Merge pull request #62 from dotnet/generate_coreLib_ni_when_install
[platform/core/dotnet/launcher.git] / NativeLauncher / installer-plugin / ni_common.cc
index f9e81b8..cf3e85e 100644 (file)
@@ -69,22 +69,32 @@ static void waitInterval()
        }
 }
 
-static bool niExist(const std::string& path, std::string& ni)
+static std::string getNiFileName(const std::string& dllPath)
 {
-       static std::string possibleExts[] = {
-               ".ni.dll", ".NI.dll", ".NI.DLL", ".ni.DLL",
-               ".ni.exe", ".NI.exe", ".NI.EXE", ".ni.EXE"
-       };
-       std::string fName = path.substr(0, path.size() - 4);
+       size_t index = dllPath.find_last_of(".");
+       if (index == std::string::npos) {
+               fprintf(stderr, "File doesnot contain extension. fail to get NI file name\n");
+               return "";
+       }
+       std::string fName = dllPath.substr(0, index);
+       std::string fExt = dllPath.substr(index, dllPath.length());
 
-       struct stat sb;
+       // crossgen generate file with lower case extension only
+       std::transform(fExt.begin(), fExt.end(), fExt.begin(), ::tolower);
+       std::string niPath = fName + ".ni" + fExt;
 
-       for (std::string ext : possibleExts) {
-               std::string f = fName + ext;
-               if (stat(f.c_str(), &sb) == 0) {
-                       ni = f;
-                       return true;
-               }
+       return niPath;
+}
+
+static bool niExist(const std::string& path)
+{
+       std::string f = getNiFileName(path);
+       if (f.empty()) {
+               return false;
+       }
+
+       if (isFileExist(f)) {
+               return true;
        }
 
        // native image of System.Private.CoreLib.dll should have to overwrite
@@ -92,7 +102,6 @@ static bool niExist(const std::string& path, std::string& ni)
        if (path.find("System.Private.CoreLib.dll") != std::string::npos) {
                std::string coreLibBackup = path + ".Backup";
                if (isFileExist(coreLibBackup)) {
-                       ni = path;
                        return true;
                }
        }
@@ -100,43 +109,67 @@ static bool niExist(const std::string& path, std::string& ni)
        return false;
 }
 
-static void updateNiFileInfo(const std::string& path)
+static void updateNiFileInfo(const std::string& dllPath, const std::string& niPath)
 {
        char* label = NULL;
-       std::string niPath;
 
-       if (niExist(path, niPath)) {
-               // change smack label
-               if (smack_getlabel(path.c_str(), &label, SMACK_LABEL_ACCESS) == 0) {
-                       if (smack_setlabel(niPath.c_str(), label, SMACK_LABEL_ACCESS) < 0) {
-                               fprintf(stderr, "Fail to set smack label\n");
-                       }
-                       free(label);
+       // change smack label
+       if (smack_getlabel(dllPath.c_str(), &label, SMACK_LABEL_ACCESS) == 0) {
+               if (smack_setlabel(niPath.c_str(), label, SMACK_LABEL_ACCESS) < 0) {
+                       fprintf(stderr, "Fail to set smack label\n");
                }
+               free(label);
+       }
 
-               // change owner and groups for generated ni file.
-               struct stat info;
-               if (!stat(path.c_str(), &info)) {
-                       if (chown(niPath.c_str(), info.st_uid, info.st_gid) == -1)
-                               fprintf(stderr, "Failed to change owner and group name\n");
-               }
+       // change owner and groups for generated ni file.
+       struct stat info;
+       if (!stat(dllPath.c_str(), &info)) {
+               if (chown(niPath.c_str(), info.st_uid, info.st_gid) == -1)
+                       fprintf(stderr, "Failed to change owner and group name\n");
        }
 }
 
-static void crossgen(const std::string& dllPath, const std::string& appPath, bool enableR2R)
+static ni_error_e crossgen(const std::string& dllPath, const std::string& appPath, bool enableR2R)
 {
+       if (!isFileExist(dllPath)) {
+               fprintf(stderr, "dll file is not exist : %s\n", dllPath.c_str());
+               return NI_ERROR_NO_SUCH_FILE;
+       }
+
+       if (!isManagedAssembly(dllPath)) {
+               fprintf(stderr, "Input file is not a dll file : %s\n", dllPath.c_str());
+               return NI_ERROR_INVALID_PARAMETER;
+       }
+
+       if (niExist(dllPath)) {
+               fprintf(stderr, "Already ni file is exist for %s\n", dllPath.c_str());
+               return NI_ERROR_ALREADY_EXIST;
+       }
+
        std::string absDllPath = absolutePath(dllPath);
+       std::string absNiPath = getNiFileName(dllPath);
+       if (absNiPath.empty()) {
+               fprintf(stderr, "Fail to get ni file name\n");
+               return NI_ERROR_UNKNOWN;
+       }
 
        pid_t pid = fork();
        if (pid == -1)
-               return;
+               return NI_ERROR_UNKNOWN;
 
        if (pid > 0) {
                int status;
                waitpid(pid, &status, 0);
                if (WIFEXITED(status)) {
-                       updateNiFileInfo(absDllPath);
-                       return;
+                       // Do not use niExist() function to check whether ni file created or not.
+                       // niEixst() return false for System.Private.Corelib.dll
+                       if (isFileExist(absNiPath)) {
+                               updateNiFileInfo(absDllPath, absNiPath);
+                               return NI_ERROR_NONE;
+                       } else {
+                               fprintf(stderr, "Fail to create native image for %s\n", dllPath.c_str());
+                               return NI_ERROR_NO_SUCH_FILE;
+                       }
                }
        } else {
                std::string jitPath = getRuntimeDir() + "/libclrjit.so";
@@ -160,6 +193,9 @@ static void crossgen(const std::string& dllPath, const std::string& appPath, boo
                }
                argv.push_back(absAppPath.c_str());
 
+               argv.push_back("/out");
+               argv.push_back(absNiPath.c_str());
+
                argv.push_back(absDllPath.c_str());
                argv.push_back(nullptr);
 
@@ -168,9 +204,11 @@ static void crossgen(const std::string& dllPath, const std::string& appPath, boo
                execv(__CROSSGEN_PATH, const_cast<char* const*>(argv.data()));
                exit(0);
        }
+
+       return NI_ERROR_NONE;
 }
 
-static int getRootPath(std::string pkgId, std::string& rootPath)
+static ni_error_e getRootPath(std::string pkgId, std::string& rootPath)
 {
        int ret = 0;
        char *path = 0;
@@ -179,36 +217,37 @@ static int getRootPath(std::string pkgId, std::string& rootPath)
 
        if (pkgmgr_installer_info_get_target_uid(&uid) < 0) {
                _ERR("Failed to get UID");
-               return -1;
+               return NI_ERROR_UNKNOWN;
        }
 
        pkgmgrinfo_pkginfo_h handle;
        if (uid == 0) {
                ret = pkgmgrinfo_pkginfo_get_pkginfo(pkgId.c_str(), &handle);
                if (ret != PMINFO_R_OK)
-                       return -1;
+                       return NI_ERROR_UNKNOWN;
        } else {
                ret = pkgmgrinfo_pkginfo_get_usr_pkginfo(pkgId.c_str(), uid, &handle);
                if (ret != PMINFO_R_OK)
-                       return -1;
+                       return NI_ERROR_UNKNOWN;
        }
 
        ret = pkgmgrinfo_pkginfo_get_root_path(handle, &path);
        if (ret != PMINFO_R_OK) {
                pkgmgrinfo_pkginfo_destroy_pkginfo(handle);
-               return -1;
+               return NI_ERROR_UNKNOWN;
        }
        rootPath = path;
        pkgmgrinfo_pkginfo_destroy_pkginfo(handle);
 
-       return 0;
+       return NI_ERROR_NONE;
 }
 
-
+// callback function of "pkgmgrinfo_appinfo_metadata_filter_foreach"
 static int appAotCb(pkgmgrinfo_appinfo_h handle, void *userData)
 {
        char *pkgId = NULL;
        int ret = 0;
+       bool* enableR2R = (bool*)userData;
 
        ret = pkgmgrinfo_appinfo_get_pkgid(handle, &pkgId);
        if (ret != PMINFO_R_OK) {
@@ -222,7 +261,7 @@ static int appAotCb(pkgmgrinfo_appinfo_h handle, void *userData)
        }
 
        // Regenerate ni files with R2R mode forcibiliy. (there is no way to now which option is used)
-       if (createNiUnderPkgRoot(pkgId, true) != 0) {
+       if (createNiUnderPkgRoot(pkgId, *enableR2R) != 0) {
                fprintf(stderr, "Failed to get root path from [%s]\n", pkgId);
                return -1;
        } else {
@@ -238,9 +277,8 @@ static void createCoreLibNI(bool enableR2R)
        std::string niCoreLib = concatPath(getRuntimeDir(), "System.Private.CoreLib.ni.dll");
        std::string coreLibBackup = concatPath(getRuntimeDir(), "System.Private.CoreLib.dll.Backup");
 
-       if (!niExist(coreLib, niCoreLib)) {
-               crossgen(coreLib, std::string(), enableR2R);
-               if (isFileExist(niCoreLib)) {
+       if (!isFileExist(coreLibBackup)) {
+               if (!crossgen(coreLib, std::string(), enableR2R)) {
                        if (rename(coreLib.c_str(), coreLibBackup.c_str())) {
                                fprintf(stderr, "Failed to rename System.Private.CoreLib.dll\n");
                        }
@@ -253,8 +291,9 @@ static void createCoreLibNI(bool enableR2R)
        }
 }
 
-int initNICommon(NiCommonOption* option)
+ni_error_e initNICommon(NiCommonOption* option)
 {
+#if defined(__arm__)
        // get interval value
        const char* intervalFile = "/usr/share/dotnet.tizen/lib/crossgen_interval.txt";
        std::ifstream inFile(intervalFile);
@@ -265,16 +304,20 @@ int initNICommon(NiCommonOption* option)
 
        if (initializePluginManager("normal")) {
                fprintf(stderr, "Fail to initialize plugin manager\n");
-               return -1;
+               return NI_ERROR_UNKNOWN;
        }
        if (initializePathManager(option->runtimeDir, option->tizenFXDir, option->extraDirs)) {
                fprintf(stderr, "Fail to initialize path manager\n");
-               return -1;
+               return NI_ERROR_UNKNOWN;
        }
 
        __tpa = getTPA();
 
-       return 0;
+       return NI_ERROR_NONE;
+#else
+       fprintf(stderr, "crossgen supports arm architecture only. skip ni file generation\n");
+       return NI_ERROR_NOT_SUPPORTED;
+#endif
 }
 
 void finalizeNICommon()
@@ -291,32 +334,22 @@ void finalizeNICommon()
 void createNiPlatform(bool enableR2R)
 {
        const std::string platformDirs[] = {getRuntimeDir(), getTizenFXDir()};
-
        createNiUnderDirs(platformDirs, 2, enableR2R);
 }
 
-void createNiDll(const std::string& dllPath, bool enableR2R)
+ni_error_e createNiDll(const std::string& dllPath, bool enableR2R)
 {
        createCoreLibNI(enableR2R);
-
-       if (!isFileExist(dllPath)) {
-               fprintf(stderr, "Failed to find dll : %s\n", dllPath.c_str());
-               return;
-       }
-
-       std::string niPath;
-       if (niExist(dllPath, niPath)) {
-               fprintf(stderr, "Already [%s] file is exist\n", niPath.c_str());
-               return;
+       // System.Private.CoreLib.dll is generated in the createCoreLibNI function.
+       // Skip if input dll is System.Private.CoreLib.dll
+       if (dllPath.find("System.Private.CoreLib.dll") != std::string::npos) {
+               return NI_ERROR_NONE;
        }
 
-       crossgen(dllPath, std::string(), enableR2R);
-       if (!niExist(dllPath, niPath)) {
-               fprintf(stderr, "Failed to create native image for %s\n", dllPath.c_str());
-       }
+       return crossgen(dllPath, std::string(), enableR2R);
 }
 
-void createNiUnderDirs(const std::string rootPaths[], int count, const std::string ignores[], int igcount, afterCreate cb, bool enableR2R)
+void createNiUnderDirs(const std::string rootPaths[], int count, bool enableR2R)
 {
        createCoreLibNI(enableR2R);
 
@@ -329,45 +362,24 @@ void createNiUnderDirs(const std::string rootPaths[], int count, const std::stri
        if (appPaths.back() == ':')
                appPaths.pop_back();
 
-       auto convert = [&appPaths, ignores, igcount, &cb, enableR2R](const std::string& path, const char* name) {
-               for (int i = 0; i < igcount; i++) {
-                       if (path == ignores[i])
-                               return;
-               }
-               std::string niPath;
-               if (isManagedAssembly(path)) {
-                       if (niExist(path, niPath)) {
-                               fprintf(stderr, "Already [%s] file is exist\n", niPath.c_str());
-                               return;
-                       }
-                       crossgen(path, appPaths.c_str(), enableR2R);
-                       if (niExist(path, niPath)) {
-                               if (cb != nullptr)
-                                       cb(niPath.c_str());
-                       } else {
-                               fprintf(stderr, "Failed to create native image for %s\n", path.c_str());
-                       }
+       auto convert = [&appPaths, enableR2R](const std::string& path, const char* name) {
+               if (!crossgen(path, appPaths.c_str(), enableR2R)) {
                        waitInterval();
                }
        };
 
-       for (int i = 0; i < count; i++)
+       for (int i = 0; i < count; i++) {
                scanFilesInDir(rootPaths[i], convert, 1);
-}
-void createNiUnderDirs(const std::string rootPaths[], int count, afterCreate cb, bool enableR2R)
-{
-       createNiUnderDirs(rootPaths, count, nullptr, 0, cb, enableR2R);
-}
-void createNiUnderDirs(const std::string rootPaths[], int count, bool enableR2R)
-{
-       createNiUnderDirs(rootPaths, count, nullptr, enableR2R);
+       }
 }
 
-int createNiUnderPkgRoot(const std::string& pkgName, bool enableR2R)
+ni_error_e createNiUnderPkgRoot(const std::string& pkgName, bool enableR2R)
 {
        std::string pkgRoot;
-       if (getRootPath(pkgName, pkgRoot) < 0)
-               return -1;
+       if (getRootPath(pkgName, pkgRoot) != NI_ERROR_NONE) {
+               fprintf(stderr, "Failed to get root path from [%s]\n", pkgName.c_str());
+               return NI_ERROR_INVALID_PACKAGE;
+       }
 
        std::string binDir = concatPath(pkgRoot, "bin");
        std::string libDir = concatPath(pkgRoot, "lib");
@@ -375,37 +387,22 @@ int createNiUnderPkgRoot(const std::string& pkgName, bool enableR2R)
 
        createNiUnderDirs(paths, 2, enableR2R);
 
-       return 0;
+       return NI_ERROR_NONE;
 }
 
-int createNiDllUnderPkgRoot(const std::string& pkgName, const std::string& dllPath, bool enableR2R)
+ni_error_e createNiDllUnderPkgRoot(const std::string& pkgName, const std::string& dllPath, bool enableR2R)
 {
        std::string pkgRoot;
-       if (getRootPath(pkgName, pkgRoot) < 0)
-               return -1;
+       if (getRootPath(pkgName, pkgRoot) < 0) {
+               fprintf(stderr, "Failed to get root path from [%s]\n", pkgName.c_str());
+               return NI_ERROR_INVALID_PACKAGE;
+       }
 
        std::string binDir = concatPath(pkgRoot, "bin");
        std::string libDir = concatPath(pkgRoot, "lib");
-       std::string appPaths = binDir + ":" + libDir;
-
-       if (!isFileExist(dllPath)) {
-               fprintf(stderr, "Failed to find dll : %s\n", dllPath.c_str());
-               return -1;
-       }
+       std::string paths = binDir + ":" + libDir;
 
-       std::string niPath;
-       if (niExist(dllPath, niPath)) {
-               fprintf(stderr, "Already [%s] file is exist\n", niPath.c_str());
-               return -1;
-       }
-
-       crossgen(dllPath, appPaths, enableR2R);
-       if (!niExist(dllPath, niPath)) {
-               fprintf(stderr, "Failed to create native image for %s\n", dllPath.c_str());
-               return -1;
-       }
-
-       return 0;
+       return crossgen(dllPath, paths, enableR2R);
 }
 
 void removeNiPlatform()
@@ -445,11 +442,13 @@ void removeNiUnderDirs(const std::string rootPaths[], int count)
                scanFilesInDir(rootPaths[i], convert, -1);
 }
 
-int removeNiUnderPkgRoot(const std::string& pkgName)
+ni_error_e removeNiUnderPkgRoot(const std::string& pkgName)
 {
        std::string pkgRoot;
-       if (getRootPath(pkgName, pkgRoot) < 0)
-               return -1;
+       if (getRootPath(pkgName, pkgRoot) < 0) {
+               fprintf(stderr, "Failed to get root path from [%s]\n", pkgName.c_str());
+               return NI_ERROR_INVALID_PACKAGE;
+       }
 
        std::string binDir = concatPath(pkgRoot, "bin");
        std::string libDir = concatPath(pkgRoot, "lib");
@@ -457,34 +456,34 @@ int removeNiUnderPkgRoot(const std::string& pkgName)
 
        removeNiUnderDirs(paths, 2);
 
-       return 0;
+       return NI_ERROR_NONE;
 }
 
-int regenerateAppNI()
+ni_error_e regenerateAppNI(bool enableR2R)
 {
        int ret = 0;
        pkgmgrinfo_appinfo_metadata_filter_h handle;
 
        ret = pkgmgrinfo_appinfo_metadata_filter_create(&handle);
        if (ret != PMINFO_R_OK)
-               return -1;
+               return NI_ERROR_UNKNOWN;
 
        ret = pkgmgrinfo_appinfo_metadata_filter_add(handle, "http://tizen.org/metadata/prefer_dotnet_aot", "true");
        if (ret != PMINFO_R_OK) {
                pkgmgrinfo_appinfo_metadata_filter_destroy(handle);
-               return -1;
+               return NI_ERROR_UNKNOWN;
        }
 
-       ret = pkgmgrinfo_appinfo_metadata_filter_foreach(handle, appAotCb, NULL);
+       ret = pkgmgrinfo_appinfo_metadata_filter_foreach(handle, appAotCb, &enableR2R);
        if (ret != PMINFO_R_OK) {
                fprintf(stderr, "Failed pkgmgrinfo_appinfo_metadata_filter_foreach\n");
                pkgmgrinfo_appinfo_metadata_filter_destroy(handle);
-               return -1;
+               return NI_ERROR_UNKNOWN;
        }
 
        fprintf(stderr, "Success pkgmgrinfo_appinfo_metadata_filter_foreach\n");
 
        pkgmgrinfo_appinfo_metadata_filter_destroy(handle);
-       return 0;
+       return NI_ERROR_NONE;
 }