Support regen-app-ni for read-only app (#301)
author조웅석/Common Platform Lab(SR)/Principal Engineer/삼성전자 <ws77.cho@samsung.com>
Thu, 24 Dec 2020 00:52:44 +0000 (09:52 +0900)
committerGitHub Enterprise <noreply-CODE@samsung.com>
Thu, 24 Dec 2020 00:52:44 +0000 (09:52 +0900)
When a partial update of tizenfx occurs, native image files of application created with FNV option  must be regenerated.
However, it is not possible with the current implementation to replace the native-image files of the app installed in the read-only area like the preload app.
To solve this problem, add a functionality that creates new native images under /opt/usr/dotnet/apps, when creating a new native image files of read-only app.

12 files changed:
NativeLauncher/CMakeLists.txt
NativeLauncher/inc/ni_common.h
NativeLauncher/inc/path_manager.h
NativeLauncher/inc/tac_common.h
NativeLauncher/inc/utils.h
NativeLauncher/tool/dotnettool.cc
NativeLauncher/tool/ni_common.cc
NativeLauncher/tool/tac_common.cc
NativeLauncher/util/path_manager.cc
NativeLauncher/util/utils.cc
dotnet-launcher.manifest
packaging/dotnet-launcher.spec

index c344aab..fc67894 100644 (file)
@@ -51,6 +51,10 @@ IF(DEFINED DOTNET_DIR)
     SET(EXTRA_CFLAGS_COMMON "${EXTRA_CFLAGS_COMMON} -DDOTNET_DIR=${DOTNET_DIR}")
 ENDIF(DEFINED DOTNET_DIR)
 
+IF(DEFINED READ_ONLY_APP_UPDATE_DIR)
+    SET(EXTRA_CFLAGS_COMMON "${EXTRA_CFLAGS_COMMON} -DREAD_ONLY_APP_UPDATE_DIR=${READ_ONLY_APP_UPDATE_DIR}")
+ENDIF(DEFINED READ_ONLY_APP_UPDATE_DIR)
+
 IF(DEFINED USE_DEFAULT_BASE_ADDR)
     SET(EXTRA_CFLAGS_COMMON "${EXTRA_CFLAGS_COMMON} -DUSE_DEFAULT_BASE_ADDR")
 ENDIF(DEFINED USE_DEFAULT_BASE_ADDR)
index bdaba44..944448a 100644 (file)
@@ -30,6 +30,7 @@
 #define NI_FLAGS_APPNI                  0x0002
 #define NI_FLAGS_COMPATIBILITY          0x0004
 #define NI_FLAGS_VERBOSE                0x0008
+#define NI_FLAGS_READONLY_APP           0x0010
 #define NI_FLAGS_INSTRUMENT             0x1000
 
 typedef std::function<void (std::string)> afterCreate;
@@ -59,15 +60,15 @@ void finalizeNICommon();
 
 /**
  * @brief create native images for platform DLLs (.NETCore + TizenFX)
- * @param[i] flags additional flags for the image generator
+ * @param[in] flags additional flags for the image generator
  * @return ni_error_e
  */
 ni_error_e createNIPlatform(DWORD flags);
 
 /**
  * @brief create a native image for a single DLL
- * @param[i] dllPath path to input DLL
- * @param[i] flags additional flags for the image generator
+ * @param[in] dllPath path to input DLL
+ * @param[in] flags additional flags for the image generator
  * @return ni_error_e
  */
 ni_error_e createNIDll(const std::string& dllPath, DWORD flags);
@@ -75,16 +76,16 @@ ni_error_e createNIDll(const std::string& dllPath, DWORD flags);
 
 /**
  * @brief create native images for all DLLs under directories
- * @param[i] rootPaths paths to directories
- * @param[i] flags additional flags for the image generator
+ * @param[in] rootPaths paths to directories
+ * @param[in] flags additional flags for the image generator
  * @return ni_error_e
  */
 ni_error_e createNIUnderDirs(const std::string& rootPaths, DWORD flags);
 
 /**
  * @brief create native images for all DLLs in a package
- * @param[i] pkgId package ID
- * @param[i] flags additional flags for the image generator
+ * @param[in] pkgId package ID
+ * @param[in] flags additional flags for the image generator
  * @return ni_error_e
  */
 ni_error_e createNIUnderPkgRoot(const std::string& pkgId, DWORD flags);
@@ -96,27 +97,27 @@ void removeNIPlatform();
 
 /**
  * @brief remove native images under directories
- * @param[i] rootPaths paths to directories
+ * @param[in] rootPaths paths to directories
  */
 void removeNIUnderDirs(const std::string& rootPaths);
 
 /**
  * @brief remove native images of a package
- * @param[i] pkgId package ID
+ * @param[in] pkgId package ID
  * @return ni_error_e
  */
 ni_error_e removeNIUnderPkgRoot(const std::string& pkgId);
 
 /**
  * @brief regenerate native images of all installed applications
- * @param[i] flags additional flags for the image generator
+ * @param[in] flags additional flags for the image generator
  * @return ni_error_e
  */
 ni_error_e regenerateAppNI(DWORD flags);
 
 /**
  * @brief regenerate native image of TAC for all shared assembly.
- * @param[i] flags additional flags for the image generator
+ * @param[in] flags additional flags for the image generator
  * @return ni_error_e
  */
 ni_error_e regenerateTACNI(DWORD flags);
index 3de0d7b..38ca327 100644 (file)
@@ -69,8 +69,8 @@ public:
 
        /**
         * @brief Add platform assemblies paths. The TPA(Trusted-Platform-Assembly) is generated based on this paths
-        * @param[i] paths the paths to be added
-        * @param[i] isHighPriority if true, paths are added in front of the current list, otherwise added at the end of the list
+        * @param[in] paths the paths to be added
+        * @param[in] isHighPriority if true, paths are added in front of the current list, otherwise added at the end of the list
         */
        void addPlatformAssembliesPaths(const std::string& paths, bool isHighPriority = false);
 
@@ -78,67 +78,74 @@ public:
         * @brief Set application root path.
         *        All application related paths ("bin", "lib", ".tac_symlink", ".native_image") are generated based on it.
         *        A temporary path (/proc/self/fd/[fd]) is used if this function is never called.
-        * @param[i] rootPath application root path
+        * @param[in] rootPath application root path
         */
        void setAppRootPath(const std::string& rootPath);
 
        /**
         * @brief Get runtime path which contains coreclr and corefx
-        * @return[i] runtime path
+        * @return runtime path
         */
        const std::string& getRuntimePath();
 
        /**
         * @brief Get tizenfx path which contains tizenfx
-        * @return[i] runtime path
+        * @return runtime path
         */
        const std::string& getTizenFXPath();
 
        /**
         * @brief Get platform assemblies paths
-        * @return[i] return path vector
+        * @return return path vector
         */
        const std::vector<std::string>& getPlatformAssembliesPaths();
 
        /**
         * @brief Get application root path
         * @see setAppRootPath()
-        * @return[i] system paths
+        * @return system paths
         */
        const std::string& getAppRootPath();
 
        /**
         * @brief Get the path of .tac_symlink of application
-        * @return[i] .tac_symlink path
+        * @return .tac_symlink path
         */
        const std::string& getAppTacPath();
 
        /**
         * @brief Get the list of directories where the assemlies of this application exist
-        * @return[i] the list(":" seperated) of paths to probe in for an assembly
+        * @return the list(":" seperated) of paths to probe in for an assembly
         */
        const std::string& getAppPaths();
 
        /**
         * @brief Get the list of directories where the native image of this application exist
-        * @return[i] the list(":" seperated) of paths to probe in for an native image
+        * @return the list(":" seperated) of paths to probe in for an native image
         */
        const std::string& getAppNIPaths();
 
        /**
         * @brief Get the list of directories where the native libraries of this application exist
-        * @return[i] the list(":" seperated) of paths the loader should probe when looking for native libraries
+        * @return the list(":" seperated) of paths the loader should probe when looking for native libraries
         */
        const std::string& getNativeDllSearchingPaths();
 
 private:
-       // update application related path (bin, lib, tac_symlink, native_image)
-       void updateAppRelatedPath(const std::string& appRootPath);
+       /**
+        * @brief Update application related path (bin, lib, tac_symlink, native_image)
+        *        In most cases, appRootPath and appNIRootPath are the same.
+        *        Apps installed in read-only storage may have a different appNIRootPath.
+        * @param[in] root path of application. (APP_PATH is geneated based on root path)
+        * @param[in] root path for native image (APP_NI_PATH is generated based on on ni root path )
+        */
+       void updateAppRelatedPath(const std::string& appRootPath, const std::string& appNIRootPath);
 
 private:
        std::vector<std::string> platformAssembliesPaths;
        std::string systemPaths;
        std::string appRootPath;
+       std::string appNIRootPath;
        std::string runtimePath;
        std::string tizenfxPath;
        std::string appPaths;
@@ -146,6 +153,7 @@ private:
        std::string nativeDllSearchingPaths;
        std::string appTacPath;
        int rootFD;
+       int niRootFD;
 };
 
 #endif /* __DLL_PATH_MANAGER_H__ */
index a97eb70..17e2441 100644 (file)
@@ -37,14 +37,14 @@ tac_error_e tac_restoreDB();
 
 /**
  * @brief disable tac feature.
- * @param[i] pkgId package ID
+ * @param[in] pkgId package ID
  * @return tac_error_e
  */
 tac_error_e disableTACPackage(const std::string& pkgId);
 
 /**
  * @brief enable tac feature.
- * @param[i] pkgId package ID
+ * @param[in] pkgId package ID
  * @return tac_error_e
  */
 tac_error_e enableTACPackage(const std::string& pkgId);
index dc4d6c4..505fba9 100644 (file)
@@ -44,21 +44,21 @@ enum FSFlag : int {
  * @brief concat path with PATH_SEPARATOR
  * @param[in] destination path
  * @param[in] source path
- * return std::string result path
+ * @return std::string result path
  */
 std::string concatPath(const std::string& path1, const std::string& path2);
 
 /**
  * @brief get canonicalized absolute Path
  * @param[in] source path
- * return std::string result path
+ * @return std::string result path
  */
 std::string getAbsolutePath(const std::string& path);
 
 /**
  * @brief get the directory of file
  * @param[in] source path
- * return std::string result path
+ * @return std::string result path
  */
 std::string getBaseName(const std::string& path);
 
@@ -67,28 +67,28 @@ std::string getBaseName(const std::string& path);
  * @param[in] original string
  * @param[in] pattern to match
  * @param[in] replacement string
- * return std::string the modified string
+ * @return std::string the modified string
  */
 std::string replaceAll(const std::string& str, const std::string& pattern, const std::string& replace);
 
 /**
  * @brief get root path
  * @param[in] package id
- * return std::string root path
+ * @return std::string root path
  */
 std::string getRootPath(const std::string& pkgId);
 
 /**
  * @brief get exec name
  * @param[in] package id
- * return std::string exec name
+ * @return std::string exec name
  */
 std::string getExecName(const std::string& pkgId);
 
 /**
  * @brief get app type
  * @param[in] package id
- * return std::string app type
+ * @return std::string app type
  */
 std::string getAppType(const std::string& pkgId);
 
@@ -96,11 +96,18 @@ std::string getAppType(const std::string& pkgId);
  * @brief get metadata value
  * @param[in] package id
  * @param[in] metadata key
- * return std::string metadata value
+ * @return std::string metadata value
  */
 std::string getMetadataValue(const std::string& pkgId, const std::string& key);
 
 /**
+ * @brief check the package is 'readonly' or not
+ * @param[in] package id
+ * @return bool package readonly value
+ */
+bool isReadOnlyApp(const std::string& pkgId);
+
+/**
  * @brief split path with ":" delimiter and put that in the vector
  * @param[in] source path
  * @param[out] string vector
index c5d5af2..83f0b6a 100644 (file)
@@ -40,6 +40,7 @@ void DisplayUsage() {
                "       --ni-reset-pkg            - Remove App NI files\n"
                "       --ni-reset-dir            - Remove NI for directory\n"
                "       --ni-regen-all-app        - Re-generate All App NI files\n"
+               "       --ni-regen-all-ro-app     - Re-generate All read-only type App NI files\n"
                "       --tac-regen-all           - Re-generate All TAC files\n"
                "       --tac-restore-db          - Restore TAC Database\n"
                "       --tac-disable-pkg         - Disable TAC for package\n"
@@ -224,6 +225,14 @@ int main(int argc, char* argv[])
                        fprintf(stderr, "Failed to regenerate all app NI\n");
                }
        }
+       //sh-3.2# dotnettool --ni-regen-readonly-app
+       else if (cmd == "--ni-regen-all-ro-app") {
+               flags |= NI_FLAGS_READONLY_APP;
+               int ret = regenerateAppNI(flags);
+               if (ret != NI_ERROR_NONE) {
+                       fprintf(stderr, "Failed to regenerate read-only app NI\n");
+               }               
+       }
        //sh-3.2# dotnettool --tac-regen-all
        else if (cmd == "--tac-regen-all") {
                int ret = regenerateTACNI(flags);
index db1eab6..1a8f894 100644 (file)
@@ -37,6 +37,7 @@
 #include <string.h>
 #include <sqlite3.h>
 #include <inttypes.h>
+#include <errno.h>
 
 #include "ni_common.h"
 #include "db_manager.h"
@@ -60,6 +61,7 @@ static const char* __NATIVE_LIB_DIR = __STR(NATIVE_LIB_DIR);
 #endif
 static const char* __CROSSGEN_PATH = __STR(CROSSGEN_PATH);
 static const char* __DOTNET_DIR = __STR(DOTNET_DIR);
+static const char* __READ_ONLY_APP_UPDATE_DIR = __STR(READ_ONLY_APP_UPDATE_DIR);
 
 #ifdef UNIQUE_DEFAULT_BASE_ADDR_SUPPORT
 static const char* __SYSTEM_BASE_FILE = __STR(SYSTEM_BASE_FILE);
@@ -97,32 +99,67 @@ static std::string getNIFilePath(const std::string& dllPath)
        return niPath;
 }
 
-static std::string getAppNIFilePath(const std::string& niPath)
+/**
+ * @brief create the directory including parents directory, and
+ *        copy ownership and smack labels to the created directory.
+ * @param[in] target directory path
+ * @param[in] source directory path to get ownership and smack label
+ * @return if directory created successfully, return true otherwise false
+ */
+static bool createDirsAndCopyOwnerShip(std::string& target_path, const std::string& source)
+{
+       struct stat st;
+       mode_t mode = S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH;
+
+       for (std::string::iterator iter = target_path.begin(); iter != target_path.end();) {
+               std::string::iterator newIter = std::find(iter, target_path.end(), '/');
+               std::string newPath = std::string(target_path.begin(), newIter);
+
+               if (!newPath.empty()) {
+                       if (stat(newPath.c_str(), &st) != 0) {
+                               if (mkdir(newPath.c_str(), mode) != 0 && errno != EEXIST) {
+                                       fprintf(stderr, "Fail to create app ni directory (%s)\n", newPath.c_str());
+                                       return false;
+                               }
+                               if (!source.empty()) {
+                                       copySmackAndOwnership(source, newPath);
+                               }
+                       } else {
+                               if (!S_ISDIR(st.st_mode)) {
+                                       fprintf(stderr, "Fail. path is not a dir (%s)\n", newPath.c_str());
+                                       return false;
+                               }
+                       }
+               }
+               iter = newIter;
+               if(newIter != target_path.end()) {
+                       ++iter;
+               }
+       }
+
+       return true;
+}
+
+static std::string getAppNIFilePath(const std::string& absDllPath, DWORD flags)
 {
-       std::string fileName;
        std::string niDirPath;
        std::string prevPath;
 
-       size_t index = niPath.find_last_of("/");
-       if (index != std::string::npos) {
-               prevPath = niPath.substr(0, index);
-               fileName = niPath.substr(index + 1, niPath.length());
-       } else {
-               prevPath = ".";
-               fileName = niPath;
-       }
-
+       prevPath = getBaseName(absDllPath);
        niDirPath = concatPath(prevPath, APP_NI_SUB_DIR);
 
-       if (!isFile(niDirPath)) {
-               if (mkdir(niDirPath.c_str(), 0755) == 0) {
-                       copySmackAndOwnership(prevPath, niDirPath);
-               } else {
-                       fprintf(stderr, "Fail to create app ni directory (%s)\n", niDirPath.c_str());
+       if (flags & NI_FLAGS_READONLY_APP) {
+               niDirPath = replaceAll(niDirPath, getBaseName(__pm->getAppRootPath()), __READ_ONLY_APP_UPDATE_DIR);
+       }
+
+       if (!isDirectory(niDirPath)) {
+               if (!createDirsAndCopyOwnerShip(niDirPath, prevPath)) {
+                       niDirPath = prevPath;
+                       fprintf(stderr, "fail to create dir (%s)\n", niDirPath.c_str());
                }
        }
 
-       return concatPath(niDirPath, fileName);
+       return getNIFilePath(concatPath(niDirPath, getFileName(absDllPath)));
 }
 
 static bool checkNIExistence(const std::string& path)
@@ -255,18 +292,20 @@ static ni_error_e crossgen(const std::string& dllPath, const std::string& appPat
        }
 
        std::string absDllPath = getAbsolutePath(dllPath);
-       std::string absNIPath = getNIFilePath(dllPath);
+       std::string absNIPath;
+
+       bool isAppNI = flags & NI_FLAGS_APPNI;
+       if (isAppNI && strstr(absDllPath.c_str(), __DOTNET_DIR) == NULL) {
+               absNIPath = getAppNIFilePath(absDllPath, flags);
+       } else {
+               absNIPath = getNIFilePath(absDllPath);
+       }
 
        if (absNIPath.empty()) {
                fprintf(stderr, "Fail to get ni file name\n");
                return NI_ERROR_UNKNOWN;
        }
 
-       bool isAppNI = flags & NI_FLAGS_APPNI;
-       if (isAppNI && strstr(absNIPath.c_str(), __DOTNET_DIR) == NULL) {
-               absNIPath = getAppNIFilePath(absNIPath);
-       }
-
 #ifdef UNIQUE_DEFAULT_BASE_ADDR_SUPPORT
        uintptr_t baseAddr = 0;
 
@@ -388,9 +427,23 @@ static int appAotCb(pkgmgrinfo_appinfo_h handle, void *userData)
                return -1;
        }
 
-       if (removeNIUnderPkgRoot(pkgId) != NI_ERROR_NONE) {
-               fprintf(stderr, "Failed to remove previous dlls from [%s]\n", pkgId);
-               return -1;
+       bool readOnlyApp = isReadOnlyApp(pkgId);
+
+       // read-only and readonly flag set
+       if (readOnlyApp && (*pFlags & NI_FLAGS_READONLY_APP)) {
+               fprintf(stderr, "try to regenerate read-only pkg [%s]\n", pkgId);
+       } 
+       // not rad-only and readonly flag doesnot set
+       else if (!readOnlyApp && !(*pFlags & NI_FLAGS_READONLY_APP)) {
+               if (removeNIUnderPkgRoot(pkgId) != NI_ERROR_NONE) {
+                       fprintf(stderr, "Failed to remove previous dlls from [%s]\n", pkgId);
+                       return -1;
+               }                       
+       }
+       // skip regeneration
+       else {
+               fprintf(stderr, "skip regeneration. pkg-type(read-only) doesnot match the configuration [%s]\n", pkgId);
+               return 0;
        }
 
        if (createNIUnderPkgRoot(pkgId, *pFlags) != NI_ERROR_NONE) {
index eed13a2..9335325 100644 (file)
@@ -32,6 +32,7 @@
 #define __XSTR(x) #x
 #define __STR(x) __XSTR(x)
 static const char* __DOTNET_DIR = __STR(DOTNET_DIR);
+static const char* __READ_ONLY_APP_UPDATE_DIR = __STR(READ_ONLY_APP_UPDATE_DIR);
 #undef __STR
 #undef __XSTR
 
@@ -45,15 +46,16 @@ static void cleanupDirectory()
        std::vector<std::string> removeNuget;
        try {
                for (auto& nuget : bf::recursive_directory_iterator(__DOTNET_DIR)) {
-                       bool isExist = false;
                        std::string nugetPath = nuget.path().string();
+                       if (!bf::is_directory(nugetPath) ||
+                               nugetPath.find(TLC_LIBRARIES_DIR) != std::string::npos ||
+                               nugetPath.find(__READ_ONLY_APP_UPDATE_DIR) != std::string::npos) {
+                               continue;
+                       }
+
+                       bool isExist = false;
                        for (auto& restore : restore_nuget) {
-                               if (!bf::is_directory(nugetPath) || nugetPath.find(TLC_LIBRARIES_DIR) != std::string::npos) {
-                                       isExist = true;
-                                       break;
-                               }
-                               if (!strcmp(nugetPath.c_str(), restore.c_str()) ||
-                                       !strcmp(nugetPath.c_str(), restore.substr(0, restore.rfind('/')).c_str())) {
+                               if (nugetPath == restore || nugetPath == getBaseName(restore)) {
                                        isExist = true;
                                        break;
                                }
index ee456f3..ae89ca2 100644 (file)
@@ -36,6 +36,8 @@ static const char* __TIZEN_API_PATH_KEY = "db/dotnet/tizen_api_path";
 static const char* __DEVICE_API_DIR = __STR(DEVICE_API_DIR);
 static const char* __RUNTIME_DIR = __STR(RUNTIME_DIR);
 static const char* __NATIVE_LIB_DIR = __STR(NATIVE_LIB_DIR);
+static const char* __READ_ONLY_APP_UPDATE_DIR = __STR(READ_ONLY_APP_UPDATE_DIR);
+
 #undef __STR
 #undef __XSTR
 
@@ -52,19 +54,23 @@ static std::string getExtraNativeLibDirs(const std::string& appRoot)
        return candidate;
 }
 
-void PathManager::updateAppRelatedPath(const std::string& appRootPath)
+void PathManager::updateAppRelatedPath(const std::string& appRootPath, const std::string& appNIRootPath)
 {
        std::string appBinPath = concatPath(appRootPath, "bin");
        std::string appLibPath = concatPath(appRootPath, "lib");
 
+       std::string appNIBinPath = concatPath(concatPath(appNIRootPath, "bin"), APP_NI_SUB_DIR);
+       std::string appNILibPath = concatPath(concatPath(appNIRootPath, "lib"), APP_NI_SUB_DIR);
+
        appTacPath = concatPath(appBinPath, TAC_SYMLINK_SUB_DIR);
        appPaths = appRootPath + ":" + appBinPath + ":" + appLibPath + ":" + appTacPath;
-       appNIPaths = concatPath(appBinPath, APP_NI_SUB_DIR) + ":" + concatPath(appLibPath, APP_NI_SUB_DIR) + ":"+ appTacPath;
-       nativeDllSearchingPaths = runtimePath + ":" + __NATIVE_LIB_DIR  + ":" + appBinPath + ":" + appLibPath + ":" + getExtraNativeLibDirs(appRootPath);
+       appNIPaths = appNIBinPath + ":" + appNILibPath + ":"+ appTacPath;
+       nativeDllSearchingPaths = runtimePath + ":" + __NATIVE_LIB_DIR + ":" + appBinPath + ":" + appLibPath + ":" + getExtraNativeLibDirs(appRootPath);
 }
 
 PathManager::PathManager() :
-       rootFD(-1)
+       rootFD(-1),
+       niRootFD(-1)
 {
        // set runtime path
        runtimePath = getAbsolutePath(__RUNTIME_DIR);
@@ -89,8 +95,16 @@ PathManager::PathManager() :
                throw std::ios_base::failure("Fail to open /proc/self");
        }
 
+       // set temporal application root path for native image
+       niRootFD = open("/proc/self", O_DIRECTORY);
+       if (niRootFD < 0) {
+               _ERR("Failed to open /proc/self");
+               throw std::ios_base::failure("Fail to open /proc/self");
+       }
+
        appRootPath = std::string("/proc/self/fd/") + std::to_string(rootFD);
-       updateAppRelatedPath(appRootPath);
+       appNIRootPath = std::string("/proc/self/fd/") + std::to_string(niRootFD);
+       updateAppRelatedPath(appRootPath, appNIRootPath);
 
        _INFO("Path manager created successfully");
 }
@@ -122,16 +136,33 @@ void PathManager::addPlatformAssembliesPaths(const std::string& paths, bool isHi
 
 void PathManager::setAppRootPath(const std::string& rootPath)
 {
+       appRootPath = getAbsolutePath(rootPath);
+
+       // check readonly update directory eixst or not
+       std::string niRootPath = replaceAll(appRootPath, getBaseName(appRootPath), __READ_ONLY_APP_UPDATE_DIR);
+       if (isDirectory(niRootPath)) {
+               appNIRootPath = getAbsolutePath(niRootPath);
+       } else {
+               appNIRootPath = appRootPath;
+       }
+
        // override root path for application launch mode (candidate / standalone mode)
        if (rootFD >= 0) {
-               int tmpFD = open(rootPath.c_str(), O_DIRECTORY);
+               int tmpFD = open(appRootPath.c_str(), O_DIRECTORY);
                dup3(tmpFD, rootFD, O_CLOEXEC);
                if (tmpFD >= 0)
                        close(tmpFD);
        }
 
-       appRootPath = getAbsolutePath(rootPath);
-       updateAppRelatedPath(appRootPath);
+       // override ni root path
+       if (niRootFD >= 0) {
+               int tmpFD = open(appNIRootPath.c_str(), O_DIRECTORY);
+               dup3(tmpFD, niRootFD, O_CLOEXEC);
+               if (tmpFD >= 0)
+                       close(tmpFD);
+       }
+
+       updateAppRelatedPath(appRootPath, appNIRootPath);
 }
 
 const std::string& PathManager::getRuntimePath()
index 0dd7777..00cb0c8 100644 (file)
@@ -236,6 +236,39 @@ std::string getMetadataValue(const std::string& pkgId, const std::string& key)
        return metadataValue;
 }
 
+bool isReadOnlyApp(const std::string& pkgId)
+{
+       bool readOnly = false;
+       int ret = 0;
+       uid_t uid = 0;
+
+       if (pkgmgr_installer_info_get_target_uid(&uid) < 0) {
+               _ERR("Failed to get UID");
+               return readOnly;
+       }
+
+       pkgmgrinfo_pkginfo_h handle;
+       if (uid == 0) {
+               ret = pkgmgrinfo_pkginfo_get_pkginfo(pkgId.c_str(), &handle);
+       } else {
+               ret = pkgmgrinfo_pkginfo_get_usr_pkginfo(pkgId.c_str(), uid, &handle);
+       }
+
+       if (ret != PMINFO_R_OK) {
+               return readOnly;
+       }
+
+       ret = pkgmgrinfo_pkginfo_is_readonly(handle, &readOnly);
+       if (ret != PMINFO_R_OK) {
+               pkgmgrinfo_pkginfo_destroy_pkginfo(handle);
+               return readOnly;
+       }
+
+       pkgmgrinfo_pkginfo_destroy_pkginfo(handle);
+
+       return readOnly;
+}
+
 std::string getBaseName(const std::string& path)
 {
        auto pos = path.find_last_of(PATH_SEPARATOR);
index e14cc1f..71d0ad6 100644 (file)
@@ -4,6 +4,7 @@
     </request>
     <assign>
         <filesystem path="/opt/usr/dotnet" label="System::Shared" type="transmutable" />
+        <filesystem path="/opt/usr/dotnet/apps" label="User::Home"/>
         <filesystem path="/usr/bin/dotnet-loader" label="User" exec_label="User" />
         <filesystem path="/usr/bin/dotnet" label="System::Tools" exec_label="User" />
     </assign>
index 80685dc..1db30cd 100644 (file)
@@ -58,6 +58,7 @@ Requires(preun): /usr/bin/systemctl
 %define _install_plugin_dir /etc/package-manager/parserlib
 %define _native_lib_dir /usr/share/dotnet.tizen/lib
 %define _dotnet_dir /opt/usr/dotnet
+%define _readonly_app_update_dir /opt/usr/dotnet/apps
 %define _system_base_addr_file /opt/usr/dotnet.system.base.addr
 
 %define _ibc_data_dir /usr/share/dotnet.tizen/ibcdata
@@ -127,6 +128,7 @@ cmake \
        -DINSTALL_MDPLUGIN_DIR=%{_install_mdplugin_dir} \
        -DINSTALL_PLUGIN_DIR=%{_install_plugin_dir} \
        -DDOTNET_DIR=%{_dotnet_dir} \
+       -DREAD_ONLY_APP_UPDATE_DIR=%{_readonly_app_update_dir} \
        -DVERSION=%{version} \
        -DNATIVE_LIB_DIR=%{_native_lib_dir} \
 %ifarch %{arm} aarch64
@@ -149,6 +151,7 @@ mv Managed/Tizen.Runtime/bin/Release/Tizen.Runtime.dll %{buildroot}%{_framework_
 mv Managed/Tizen.Runtime/bin/Release/Tizen.Runtime.pdb %{buildroot}%{_framework_dir}
 
 mkdir -p %{buildroot}%{_dotnet_dir}
+mkdir -p %{buildroot}%{_readonly_app_update_dir}
 mkdir -p %{buildroot}%{_native_lib_dir}
 ln -sf %{_libdir}/libsqlite3.so.0 %{buildroot}%{_native_lib_dir}/libsqlite3.so
 
@@ -201,6 +204,7 @@ chsmack -a User /usr/bin/dotnet-nui-loader
 /usr/share/parser-plugins/dotnet-launcher.info
 %{_framework_dir}/Tizen.Runtime.dll
 %{_dotnet_dir}
+%{_readonly_app_update_dir}
 %{_ibc_data_dir}
 %{_tizen_preload_dir}
 %{_rw_update_scripts_dir}/%{_rw_dotnet_update_script}