X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=NativeLauncher%2Ftool%2Fni_common.cc;h=ecfeee20f14e871bd26374b5320f835d11f9203a;hb=fe54a0874e638069e35c77e5545090c6d2c7ebf1;hp=cabb81387f3ea007879ab52b2c2241707dbfe9b5;hpb=48f3f19802ea191f4490a98bdec5e9b10861d435;p=platform%2Fcore%2Fdotnet%2Flauncher.git diff --git a/NativeLauncher/tool/ni_common.cc b/NativeLauncher/tool/ni_common.cc index cabb813..ecfeee2 100644 --- a/NativeLauncher/tool/ni_common.cc +++ b/NativeLauncher/tool/ni_common.cc @@ -29,33 +29,34 @@ #include #include #include +#include -#include #include #include #include #include +#include +#include #include "ni_common.h" #include "db_manager.h" #include "tac_common.h" #include "path_manager.h" #include "plugin_manager.h" +#include "r2r_checker.h" #ifdef LOG_TAG #undef LOG_TAG #endif #define LOG_TAG "DOTNET_INSTALLER_PLUGIN" -#ifndef CROSSGEN_PATH -#error "CROSSGEN_PATH is missed" -#endif - #define __XSTR(x) #x #define __STR(x) __XSTR(x) +#if defined(__arm__) || defined(__aarch64__) static const char* __NATIVE_LIB_DIR = __STR(NATIVE_LIB_DIR); -static const char* __CROSSGEN_PATH = __STR(CROSSGEN_PATH); +#endif 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); @@ -64,112 +65,66 @@ static const char* __SYSTEM_BASE_FILE = __STR(SYSTEM_BASE_FILE); #undef __STR #undef __XSTR +static std::string CORERUN_CMD = "/usr/share/dotnet.tizen/netcoreapp/corerun"; +static std::string CROSSGEN2_PATH = "/usr/share/dotnet.tizen/netcoreapp/crossgen2/crossgen2.dll"; +static std::string CLRJIT_PATH = "/usr/share/dotnet.tizen/netcoreapp/libclrjit.so"; +static const char* CROSSGEN_OPT_JITPATH = "--jitpath"; +static const char* CROSSGEN_OPT_TARGET_ARCH = "--targetarch"; +static const char* CROSSGEN_OPT_OUT_NEAR_INPUT = "--out-near-input"; +static const char* CROSSGEN_OPT_SINGLE_FILE_COMPILATION = "--single-file-compilation"; +//static const char* CROSSGEN_OPT_PARALLELISM = "--parallelism"; +//static const char* CROSSGEN_OPT_PARALLELISM_COUNT = "5"; +static const char* CROSSGEN_OPT_RESILIENT = "--resilient"; +//static const char* CROSSGEN_OPT_OPTIMIZE = "-O"; +static const char* CROSSGEN_OPT_OPTIMIZE_TIME = "--Ot"; +static const char* CROSSGEN_OPT_INPUTBUBBLE = "--inputbubble"; +static const char* CROSSGEN_OPT_COMPILE_BUBBLE_GENERICS = "--compilebubblegenerics"; +static const char* CROSSGEN_OPT_VERBOSE = "--verbose"; +static std::vector REF_VECTOR; +static std::vector INPUTBUBBLE_REF_VECTOR; +static std::vector MIBC_VECTOR; + static int __interval = 0; static PathManager* __pm = nullptr; -static void waitInterval() -{ - // by the recommand, ignore small value for performance. - if (__interval > 10000) { - fprintf(stdout, "sleep %d usec\n", __interval); - usleep(__interval); - } -} - -static std::string getNIFilePath(const std::string& dllPath) -{ - 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()); - - // crossgen generate file with lower case extension only - std::transform(fExt.begin(), fExt.end(), fExt.begin(), ::tolower); - std::string niPath = fName + ".ni" + fExt; - - return niPath; -} +static NIOption* __ni_option = nullptr; -static std::string getAppNIFilePath(const std::string& niPath) +// singleton +NIOption* getNIOption() { - 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; - } - - 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 (__ni_option == nullptr) { + __ni_option = (NIOption*)calloc(sizeof(NIOption), 1); + if (__ni_option == nullptr) { + _SERR("Fail to create NIOption"); } } - - return concatPath(niDirPath, fileName); + return __ni_option; } -static bool checkNIExistence(const std::string& path) +static void waitInterval() { - std::string f = getNIFilePath(path); - if (f.empty()) { - return false; - } - - if (isFile(f)) { - return true; - } - - // native image of System.Private.CoreLib.dll should have to overwrite - // original file to support new coreclr - if (path.find("System.Private.CoreLib.dll") != std::string::npos) { - std::string coreLibBackup = path + ".Backup"; - if (isFile(coreLibBackup)) { - return true; - } + // by the recommand, ignore small value for performance. + if (__interval > 10000) { + _SOUT("sleep %d usec", __interval); + usleep(__interval); } - - return false; } #ifdef UNIQUE_DEFAULT_BASE_ADDR_SUPPORT -static uintptr_t getFileSize(const std::string& path) -{ - struct stat sb; - - if (stat(path.c_str(), &sb) == 0) { - return sb.st_size; - } - - return 0; -} - // Get next base address to be used for system ni image from file // __SYSTEM_BASE_FILE should be checked for existance before calling this function static uintptr_t getNextBaseAddrFromFile() { FILE *pFile = fopen(__SYSTEM_BASE_FILE, "r"); if (pFile == NULL) { - fprintf(stderr, "Failed to open %s\n", __SYSTEM_BASE_FILE); + _SERR("Failed to open %s", __SYSTEM_BASE_FILE); return 0; } uintptr_t addr = 0; uintptr_t size = 0; - while (fscanf(pFile, "%u %u", &addr, &size) != EOF) { + while (fscanf(pFile, "%" SCNxPTR " %" SCNuPTR "", &addr, &size) != EOF) { } fclose(pFile); @@ -199,20 +154,20 @@ static uintptr_t getNextBaseAddr() // Save base address of system ni image to file static void updateBaseAddrFile(const std::string& absNIPath, uintptr_t baseAddr) { - uintptr_t niSize = getFileSize(absNIPath); + uintptr_t niSize = getSizeOfImage(absNIPath); if (niSize == 0) { - fprintf(stderr, "File %s doesn't exist\n", absNIPath.c_str()); + _SERR("File %s doesn't exist", absNIPath.c_str()); return; } // Write new entry to the file FILE *pFile = fopen(__SYSTEM_BASE_FILE, "a"); if (pFile == NULL) { - fprintf(stderr, "Failed to open %s\n", __SYSTEM_BASE_FILE); + _SERR("Failed to open %s", __SYSTEM_BASE_FILE); return; } - fprintf(pFile, "%u %u\n", baseAddr, niSize); + fprintf(pFile, "%" PRIxPTR " %" PRIuPTR "\n", baseAddr, niSize); fclose(pFile); } @@ -232,45 +187,327 @@ static bool isTPADll(const std::string& dllPath) } #endif -// baseAddr should be checked in file before getting here -static ni_error_e crossgen(const std::string& dllPath, const std::string& appPath, DWORD flags) +/** + * @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) { - if (!isFile(dllPath)) { - fprintf(stderr, "dll file is not exist : %s\n", dllPath.c_str()); - return NI_ERROR_NO_SUCH_FILE; + 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) { + _SERR("Fail to create app ni directory (%s)", newPath.c_str()); + return false; + } + if (!source.empty()) { + copySmackAndOwnership(source, newPath); + } + } else { + if (!S_ISDIR(st.st_mode)) { + _SERR("Fail. path is not a dir (%s)", newPath.c_str()); + return false; + } + } + } + iter = newIter; + if(newIter != target_path.end()) { + ++iter; + } } - if (!isManagedAssembly(dllPath)) { - //fprintf(stderr, "Input file is not a dll file : %s\n", dllPath.c_str()); - return NI_ERROR_INVALID_PARAMETER; + return true; +} + +static std::string getNIFilePath(const std::string& dllPath) +{ + size_t index = dllPath.find_last_of("."); + if (index == std::string::npos) { + _SERR("File doesnot contain extension. fail to get NI file name"); + return ""; } + std::string fName = dllPath.substr(0, index); + std::string fExt = dllPath.substr(index, dllPath.length()); - if (checkNIExistence(dllPath)) { - //fprintf(stderr, "Already ni file is exist for %s\n", dllPath.c_str()); - return NI_ERROR_ALREADY_EXIST; + // crossgen generate file with lower case extension only + std::transform(fExt.begin(), fExt.end(), fExt.begin(), ::tolower); + std::string niPath = fName + ".ni" + fExt; + + return niPath; +} + +static std::string getAppNIFilePath(const std::string& absDllPath, NIOption* opt) +{ + std::string niDirPath; + std::string prevPath; + + prevPath = getBaseName(absDllPath); + niDirPath = concatPath(prevPath, APP_NI_SUB_DIR); + + if (opt->flags & NI_FLAGS_APP_UNDER_RO_AREA) { + niDirPath = replaceAll(niDirPath, getBaseName(__pm->getAppRootPath()), __READ_ONLY_APP_UPDATE_DIR); + _SERR("App is installed in RO area. Change NI path to RW area(%s).", niDirPath.c_str()); + _ERR("App is installed in RO area. Change NI path to RW area(%s).", niDirPath.c_str()); + } + + if (!isDirectory(niDirPath)) { + if (!createDirsAndCopyOwnerShip(niDirPath, prevPath)) { + niDirPath = prevPath; + _SERR("fail to create dir (%s)", niDirPath.c_str()); + } + } + + return getNIFilePath(concatPath(niDirPath, getFileName(absDllPath))); +} + +static bool checkNIExistence(const std::string& absDllPath) +{ + std::string absNIPath = getNIFilePath(absDllPath); + if (absNIPath.empty()) { + return false; + } + + if (isFile(absNIPath)) { + return true; } - std::string absDllPath = getAbsolutePath(dllPath); - std::string absNIPath = getNIFilePath(dllPath); + // native image of System.Private.CoreLib.dll should have to overwrite + // original file to support new coreclr + if (absDllPath.find("System.Private.CoreLib.dll") != std::string::npos) { + return isR2RImage(absDllPath); + } + + return false; +} +static bool checkAppNIExistence(const std::string& absDllPath, NIOption* opt) +{ + std::string absNIPath = getAppNIFilePath(absDllPath, opt); if (absNIPath.empty()) { - fprintf(stderr, "Fail to get ni file name\n"); + return false; + } + + if (isFile(absNIPath)) { + return true; + } + + return false; +} + +static bool checkDllExistInDir(const std::string& path) +{ + bool ret = false; + auto func = [&ret](const std::string& f_path, const std::string& f_name) { + if (isManagedAssembly(f_name) || isNativeImage(f_name)) { + ret = true; + } + }; + + scanFilesInDirectory(path, func, 0); + + return ret; +} + +/* + * Get the list of managed files in the specific directory + * Absolute paths of managed files are stored at the result list. + * If native image already exist in the same directory, managed file is ignored. + */ +static ni_error_e getTargetDllList(const std::string& path, std::vector& fileList) +{ + if (!isDirectory(path)) { + return NI_ERROR_INVALID_PARAMETER; + } + + auto func = [&fileList](const std::string& f_path, const std::string& f_name) { + if (isManagedAssembly(f_path) && !checkNIExistence(f_path)) { + fileList.push_back(getAbsolutePath(f_path)); + } + }; + + scanFilesInDirectory(path, func, 0); + + return NI_ERROR_NONE; +} + +/* + * Get the list of managed files in the specific directory of Application + * Absolute paths of managed files are stored at the result list. + * If native image already exist in the .native_image directory, managed file is ignored. + * + */ +static ni_error_e getAppTargetDllList(const std::string& path, std::vector& fileList, NIOption *opt) +{ + if (!isDirectory(path)) { + return NI_ERROR_INVALID_PARAMETER; + } + + auto func = [&fileList, opt](const std::string& f_path, const std::string& f_name) { + if (isManagedAssembly(f_path) && !checkAppNIExistence(f_path, opt)) { + fileList.push_back(getAbsolutePath(f_path)); + } + }; + + scanFilesInDirectory(path, func, 0); + + return NI_ERROR_NONE; +} + +static void makeArgs(std::vector& args, const std::vector& refPaths, NIOption* opt) +{ + args.push_back(CORERUN_CMD.c_str()); + if (CROSSGEN2_PATH != "") { + args.push_back(CROSSGEN2_PATH.c_str()); + } + args.push_back(CROSSGEN_OPT_JITPATH); + args.push_back(CLRJIT_PATH.c_str()); + args.push_back(CROSSGEN_OPT_TARGET_ARCH); + args.push_back(ARCHITECTURE_IDENTIFIER); + + //args.push_back(OPT_PARALLELISM); + //args.push_back(OPT_PARALLELISM_COUNT); + args.push_back(CROSSGEN_OPT_RESILIENT); + + args.push_back(CROSSGEN_OPT_OPTIMIZE_TIME); + + if (opt->flags & NI_FLAGS_INPUT_BUBBLE) { + args.push_back(CROSSGEN_OPT_INPUTBUBBLE); + args.push_back(CROSSGEN_OPT_COMPILE_BUBBLE_GENERICS); + + INPUTBUBBLE_REF_VECTOR.clear(); + for (const auto &path : opt->inputBubbleRefFiles) { + INPUTBUBBLE_REF_VECTOR.push_back("--inputbubbleref:" + path); + } + for (const auto &path : INPUTBUBBLE_REF_VECTOR) { + if (find(args.begin(), args.end(), path) == args.end()) { + args.push_back(path.c_str()); + } + } + } + + if (opt->flags & NI_FLAGS_MIBC) { + MIBC_VECTOR.clear(); + for (const auto &path : opt->mibcPath) { + MIBC_VECTOR.push_back("--mibc:" + path); + } + for (const auto &path : MIBC_VECTOR) { + if (find(args.begin(), args.end(), path) == args.end()) { + args.push_back(path.c_str()); + } + } + } + + if (opt->flags & NI_FLAGS_VERBOSE) { + args.push_back(CROSSGEN_OPT_VERBOSE); + } + + REF_VECTOR.clear(); + + // set reference path + for (const auto &path : opt->refFiles) { + REF_VECTOR.push_back("-r:" + path); + } + + std::vector paths = __pm->getPlatformAssembliesPaths(); + for (const auto &path : paths) { + if (checkDllExistInDir(path)) { + REF_VECTOR.push_back("-r:" + path + "/*.dll"); + } + } + + if (opt->flags & NI_FLAGS_EXTRA_REF) { + for (const auto &erPath : opt->extraRefPath) { + std::string path = getAbsolutePath(erPath); + if (checkDllExistInDir(path)) { + REF_VECTOR.push_back("-r:" + path + "/*.dll"); + } + } + } + + for (const auto &path : refPaths) { + if (checkDllExistInDir(path)) { + REF_VECTOR.push_back("-r:" + path + "/*.dll"); + } + } + + for (const auto &path : REF_VECTOR) { + if (find(args.begin(), args.end(), path) == args.end()) { + args.push_back(path.c_str()); + } + } +} + +static void clearArgs(std::vector& args) +{ + REF_VECTOR.clear(); + args.clear(); +} + +static ni_error_e makePdbSymlinkForNI(std::string dllPath, std::string niPath) +{ + std::string pdbPath = changeExtension(dllPath, ".dll", ".pdb"); + try { + if (exist(pdbPath)) { + std::string targetPDBPath = changeExtension(niPath, ".ni.dll", ".pdb"); + if (!exist(targetPDBPath)) { + bf::create_symlink(pdbPath, targetPDBPath); + copySmackAndOwnership(pdbPath, targetPDBPath, true); + } + } + } catch (const bf::filesystem_error& error) { + _SERR("Fail to create symlink for %s", pdbPath.c_str()); return NI_ERROR_UNKNOWN; } - bool isAppNI = flags & NI_FLAGS_APPNI; - if (isAppNI && strstr(absNIPath.c_str(), __DOTNET_DIR) == NULL) { - absNIPath = getAppNIFilePath(absNIPath); + return NI_ERROR_NONE; +} + +static ni_error_e crossgen2PostAction(const std::string& dllPath, const std::string& niPath, NIOption* opt) { + std::string outFile = niPath; + if (!exist(outFile)) { + return NI_ERROR_NO_SUCH_FILE; } + copySmackAndOwnership(dllPath, outFile); -#ifdef UNIQUE_DEFAULT_BASE_ADDR_SUPPORT - uintptr_t baseAddr = 0; + // if AppNI then move ni.dll file to .native_image and copy pdb to .native_image + if (opt->flags & NI_FLAGS_APPNI) { + outFile = getAppNIFilePath(dllPath, opt); + makePdbSymlinkForNI(dllPath, outFile); + + if (opt->flags & NI_FLAGS_INPUT_BUBBLE && opt->flags & NI_FLAGS_NO_PIPELINE) { + outFile = outFile + ".tmp"; + } + + if (niPath != outFile) { + moveFile(niPath, outFile); + } + } - if (isTPADll(dllPath)) { - baseAddr = getNextBaseAddr(); + if (opt->flags & NI_FLAGS_RM_ORIGIN_AFTER_NI) { + if (!removeFile(dllPath)) { + _SERR("Fail to remove original file : %s", dllPath.c_str()); + } } -#endif + if (!(opt->flags & NI_FLAGS_INPUT_BUBBLE && opt->flags & NI_FLAGS_NO_PIPELINE)) { + _SOUT("Native image %s generated successfully.", outFile.c_str()); + } + + return NI_ERROR_NONE; +} + +static ni_error_e crossgen2PipeLine(const std::vector& dllList, const std::vector& refPaths, NIOption* opt) +{ + // fork crossgen2 pid_t pid = fork(); if (pid == -1) return NI_ERROR_UNKNOWN; @@ -279,94 +516,289 @@ static ni_error_e crossgen(const std::string& dllPath, const std::string& appPat int status; waitpid(pid, &status, 0); if (WIFEXITED(status)) { - // Do not use checkNIExistence() function to check whether ni file created or not. - // checkNIExistence() return false for System.Private.Corelib.dll - if (isFile(absNIPath)) { - copySmackAndOwnership(absDllPath, absNIPath); - std::string absPdbPath = replaceAll(absDllPath, ".dll", ".pdb"); - std::string pdbFilePath = replaceAll(absNIPath, ".ni.dll", ".pdb"); - if (isFile(absPdbPath) && (absPdbPath != pdbFilePath)) { - if (!copyFile(absPdbPath, pdbFilePath)) { - fprintf(stderr, "Failed to copy a .pdb file\n"); - } else { - copySmackAndOwnership(absPdbPath, pdbFilePath); - } + for (auto& dllPath: dllList) { + ni_error_e ret = crossgen2PostAction(dllPath, changeExtension(dllPath, ".dll", ".ni.dll"), opt); + if (ret != NI_ERROR_NONE) { + return ret; + } + } + } else { + _SERR("Failed. Forked process terminated abnormally"); + return NI_ERROR_ABNORMAL_PROCESS_TERMINATION; + } + } else { + std::vector argv; + makeArgs(argv, refPaths, opt); + argv.push_back(CROSSGEN_OPT_OUT_NEAR_INPUT); + argv.push_back(CROSSGEN_OPT_SINGLE_FILE_COMPILATION); + + // add input files at the end of parameter + for (const auto &input : dllList) { + argv.push_back(input.c_str()); + _SOUT("+ %s", input.c_str()); + } + + // end param + argv.push_back(nullptr); + + // print cmd + if (opt->flags & NI_FLAGS_PRINT_CMD) { + _SOUT("==================== NI Commands ========================="); + for (auto &arg: argv) _SOUT("+ %s", arg); + } + + execv(CORERUN_CMD.c_str(), const_cast(argv.data())); + + clearArgs(argv); + exit(0); + } + + return NI_ERROR_NONE; +} + +static ni_error_e crossgen2NoPipeLine(const std::vector& dllList, const std::vector& refPaths, NIOption* opt) +{ + for (auto& dllPath : dllList) { + std::string niPath; + if (opt->flags & NI_FLAGS_APPNI) { + niPath = getAppNIFilePath(dllPath, opt); + } else { + niPath = getNIFilePath(dllPath); + } +#ifdef UNIQUE_DEFAULT_BASE_ADDR_SUPPORT + uintptr_t baseAddr = 0; + if (isTPADll(dllPath)) { + baseAddr = getNextBaseAddr(); + } +#endif + if (opt->flags & NI_FLAGS_INPUT_BUBBLE) { + niPath += ".tmp"; + } + + // fork crossgen2 + pid_t pid = fork(); + if (pid == -1) + return NI_ERROR_UNKNOWN; + + if (pid > 0) { + int status; + waitpid(pid, &status, 0); + if (WIFEXITED(status)) { + ni_error_e ret = crossgen2PostAction(dllPath, niPath, opt); + if (ret != NI_ERROR_NONE) { + return ret; } #ifdef UNIQUE_DEFAULT_BASE_ADDR_SUPPORT if (baseAddr != 0) { - updateBaseAddrFile(absNIPath, baseAddr); + updateBaseAddrFile(niPath, baseAddr); } #endif - return NI_ERROR_NONE; } else { - fprintf(stderr, "Fail to create native image for %s\n", dllPath.c_str()); - return NI_ERROR_NO_SUCH_FILE; + _SERR("Failed. Forked process terminated abnormally"); + _SERR("Crossgen2 was terminated by the OOM killer. Please check the system."); + removeFile(changeExtension(niPath, ".ni.dll", ".ni.dll.tmp")); + return NI_ERROR_ABNORMAL_PROCESS_TERMINATION; + } + } else { + std::vector argv; + makeArgs(argv, refPaths, opt); + +#ifdef UNIQUE_DEFAULT_BASE_ADDR_SUPPORT + std::string baseAddrString; + if (baseAddr != 0) { + argv.push_back("--imagebase"); + std::stringstream ss; + ss << "0x" << std::hex << baseAddr; + baseAddrString = ss.str(); + argv.push_back(baseAddrString.c_str()); + } +#endif + argv.push_back("-o"); + argv.push_back(niPath.c_str()); + + argv.push_back(dllPath.c_str()); + _SOUT("+ %s", dllPath.c_str()); + + // end param + argv.push_back(nullptr); + + // print cmd + if (opt->flags & NI_FLAGS_PRINT_CMD) { + _SOUT("==================== NI Commands ========================="); + for (auto &arg: argv) _SOUT("+ %s", arg); } + + execv(CORERUN_CMD.c_str(), const_cast(argv.data())); + + clearArgs(argv); + exit(0); } - } else { - std::string jitPath = __pm->getRuntimePath() + "/libclrjit.so"; - std::vector argv = { - __CROSSGEN_PATH, - "/nologo", - "/JITPath", jitPath.c_str() - }; - - bool compat = flags & NI_FLAGS_COMPATIBILITY; - argv.push_back(compat ? "/Platform_Assemblies_Pathes" : "/p"); - std::vector paths = __pm->getPlatformAssembliesPaths(); - std::string platformAssembliesPaths; - for (const auto &path : paths) { - if (!platformAssembliesPaths.empty()) { - platformAssembliesPaths += ":"; + + waitInterval(); + } + + return NI_ERROR_NONE; +} + +static ni_error_e createCoreLibNI(NIOption* opt) +{ + std::string coreLib = concatPath(__pm->getRuntimePath(), "System.Private.CoreLib.dll"); + std::string niCoreLib = concatPath(__pm->getRuntimePath(), "System.Private.CoreLib.ni.dll"); + std::string niTmpCoreLib = concatPath(__pm->getRuntimePath(), "System.Private.CoreLib.ni.dll.tmp"); + std::string coreLibBackup = concatPath(__pm->getRuntimePath(), "System.Private.CoreLib.dll.Backup"); + + std::vector dllList; + std::vector refPaths; + dllList.push_back(getAbsolutePath(coreLib)); + + if (!isFile(coreLibBackup) && !isR2RImage(coreLib)) { + if (crossgen2NoPipeLine(dllList, refPaths, opt) == NI_ERROR_NONE) { + if (opt->flags & NI_FLAGS_RM_ORIGIN_AFTER_NI) { + std::ofstream output(coreLibBackup); + if (!exist(coreLibBackup)) { + _SERR("Failed to create System.Private.CoreLib.dll.Backup"); + return NI_ERROR_CORE_NI_FILE; + } + copySmackAndOwnership(__pm->getRuntimePath(), coreLibBackup, false); + output.close(); + } else if (rename(coreLib.c_str(), coreLibBackup.c_str())) { + _SERR("Failed to rename from System.Private.CoreLib.dll to System.Private.CoreLib.dll.Backup"); + return NI_ERROR_CORE_NI_FILE; + } + if (opt->flags & NI_FLAGS_INPUT_BUBBLE) { + if (rename(niTmpCoreLib.c_str(), coreLib.c_str())) { + _SERR("Failed to rename from System.Private.CoreLib.ni.dll.tmp to Private.CoreLib.dll"); + return NI_ERROR_CORE_NI_FILE; + } + } else { + if (rename(niCoreLib.c_str(), coreLib.c_str())) { + _SERR("Failed to rename from System.Private.CoreLib.ni.dll to Private.CoreLib.dll"); + return NI_ERROR_CORE_NI_FILE; + } } - platformAssembliesPaths += path; + } else { + _SERR("Failed to create native image for %s", coreLib.c_str()); + return NI_ERROR_CORE_NI_FILE; } - argv.push_back(platformAssembliesPaths.c_str()); + } + return NI_ERROR_NONE; +} + +static ni_error_e doAOTList(std::vector& dllList, const std::string& refPaths, NIOption* opt) +{ + ni_error_e ret = NI_ERROR_NONE; + + if (dllList.empty()) { + return NI_ERROR_INVALID_PARAMETER; + } + // When performing AOT for one Dll, an error is returned when an error occurs. + // However, when processing multiple dlls at once, only the log for errors is output and skipped. + + std::string coreLib = concatPath(__pm->getRuntimePath(), "System.Private.CoreLib.dll"); + bool hasSPC = false; - bool enableR2R = flags & NI_FLAGS_ENABLER2R; - if (!enableR2R) { - argv.push_back("/FragileNonVersionable"); + for (auto it = dllList.begin(); it != dllList.end(); it++) { + std::string f = *it; + if (!isFile(f)) { + _SERR("dll file is not exist : %s", f.c_str()); + dllList.erase(it--); + } + else if (!isManagedAssembly(f)) { + _SERR("Input file is not a dll file : %s", f.c_str()); + dllList.erase(it--); } + // handle System.Private.CoreLib.dll separately. + // dllList and path manager contain absolute path. So, there is no need to change path to absolute path + else if (f == coreLib) { + hasSPC = true; + dllList.erase(it--); + } + } - if (flags & NI_FLAGS_VERBOSE) { - argv.push_back("/verbose"); + // In the case of SPC, post-processing is required to change the name of the native image. + // In order to avoid repeatedly checking whether the generated native image is an SPC, + // the SPC native image generation is performed separately. + if (hasSPC) { + ret = createCoreLibNI(opt); + if (ret != NI_ERROR_NONE) { + return ret; } + } - if (flags & NI_FLAGS_INSTRUMENT) { - argv.push_back("/Tuning"); + // if there is no proper input after processing dll list + if (dllList.empty()) { + if (hasSPC) { + return ret; + } else { + return NI_ERROR_INVALID_PARAMETER; } + } -#ifdef UNIQUE_DEFAULT_BASE_ADDR_SUPPORT - char baseAddrString[11] = {0}; - if (baseAddr != 0) { - argv.push_back("/BaseAddress"); - snprintf(baseAddrString, 11, "0x%08x", baseAddr); - argv.push_back(baseAddrString); + std::vector paths; + splitPath(refPaths, paths); + + if (opt->flags & NI_FLAGS_NO_PIPELINE) { + ret = crossgen2NoPipeLine(dllList, paths, opt); + } else { + std::vector notCompiled; + ret = crossgen2PipeLine(dllList, paths, opt); + if (ret != NI_ERROR_NONE) { + _SERR("Crossgen2 is abnormally terminated. Regenerate native images that failed while running crossgen2."); + for (auto &dll : dllList) { + std::string tFile = changeExtension(dll, ".dll", ".ni.dll"); + if (opt->flags & NI_FLAGS_INPUT_BUBBLE) { + tFile += ".tmp"; + } + if (!exist(tFile)) { + notCompiled.push_back(dll); + } + } + _SERR("Retry running crossgen2 with --no-pipeline mode to avoid termination by OOM."); + ret = crossgen2NoPipeLine(notCompiled, paths, opt); } -#endif + } - argv.push_back("/App_Paths"); - std::string absAppPath; - if (!appPath.empty()) { - absAppPath = appPath; - } else { - absAppPath = getBaseName(absDllPath); + if (ret == NI_ERROR_NONE && opt->flags & NI_FLAGS_INPUT_BUBBLE) { + for (auto &dll : dllList) { + std::string tmpFile; + std::string niFile; + if (opt->flags & NI_FLAGS_APPNI) { + niFile = getAppNIFilePath(dll, opt); + } else { + niFile = getNIFilePath(dll); + } + tmpFile = niFile + ".tmp"; + + if (exist(tmpFile)) { + moveFile(tmpFile, niFile); + _SOUT("Native image %s generated successfully.", niFile.c_str()); + } } - argv.push_back(absAppPath.c_str()); + } - argv.push_back("/out"); - argv.push_back(absNIPath.c_str()); + return ret; +} - argv.push_back(absDllPath.c_str()); - argv.push_back(nullptr); +static ni_error_e doAOTFile(const std::string& dllFile, const std::string& refPaths, NIOption* opt) +{ + if (!isFile(dllFile)) { + _SERR("dll file is not exist : %s", dllFile.c_str()); + return NI_ERROR_NO_SUCH_FILE; + } - fprintf(stdout, "+ %s (%s)\n", absDllPath.c_str(), enableR2R ? "R2R" : "FNV"); + if (!isManagedAssembly(dllFile)) { + _SERR("Failed. Input parameter is not managed dll (%s)\n", dllFile.c_str()); + return NI_ERROR_INVALID_PARAMETER; + } - execv(__CROSSGEN_PATH, const_cast(argv.data())); - exit(0); + if (checkNIExistence(dllFile)) { + _SERR("Native image file is already exist : %s", dllFile.c_str()); + return NI_ERROR_ALREADY_EXIST; } - return NI_ERROR_NONE; + std::vector dllList; + dllList.push_back(getAbsolutePath(dllFile)); + return doAOTList(dllList, refPaths, opt); } // callback function of "pkgmgrinfo_appinfo_metadata_filter_foreach" @@ -374,125 +806,86 @@ static int appAotCb(pkgmgrinfo_appinfo_h handle, void *userData) { char *pkgId = NULL; int ret = 0; - DWORD *pFlags = (DWORD*)userData; + NIOption **pOptions = (NIOption**)userData; + + if ((*pOptions)->flags & NI_FLAGS_SKIP_RO_APP) { + bool isSystem = false; + int ret = pkgmgrinfo_appinfo_is_system(handle, &isSystem); + if (ret != PMINFO_R_OK) { + _SERR("Failed to check that app is System or not\n"); + return -1; + } + if (isSystem) { + return 0; + } + } ret = pkgmgrinfo_appinfo_get_pkgid(handle, &pkgId); if (ret != PMINFO_R_OK) { - fprintf(stderr, "Failed to get pkgid\n"); + _SERR("Failed to get pkgid"); return -1; } if (removeNIUnderPkgRoot(pkgId) != NI_ERROR_NONE) { - fprintf(stderr, "Failed to remove previous dlls from [%s]\n", pkgId); + _SERR("Failed to remove previous dlls from [%s]", pkgId); return -1; } - if (createNIUnderPkgRoot(pkgId, *pFlags) != NI_ERROR_NONE) { - fprintf(stderr, "Failed to generate NI file [%s]\n", pkgId); + if (createNIUnderPkgRoot(pkgId, *pOptions) != NI_ERROR_NONE) { + _SERR("Failed to generate NI file [%s]", pkgId); return -1; } else { - fprintf(stdout, "Complete make application to native image\n"); + _SOUT("Complete make application to native image"); } return 0; } -static bool isCoreLibPrepared(DWORD flags) -{ - if (flags & NI_FLAGS_ENABLER2R) { - return true; - } - - std::string coreLibBackup = concatPath(__pm->getRuntimePath(), "System.Private.CoreLib.dll.Backup"); - if (isFile(coreLibBackup)) { - return true; - } else { - fprintf(stderr, "The native image of System.Private.CoreLib does not exist\n" - "Run the command to create the native image\n" - "# dotnettool --ni-dll /usr/share/dotnet.tizen/netcoreapp/System.Private.CoreLib.dll\n\n"); - return false; - } -} - -static bool hasCoreLibNI() -{ - FILE *fp; - char buff[1024]; - std::string ildasm = concatPath(__pm->getRuntimePath(), "ildasm"); - std::string coreLib = concatPath(__pm->getRuntimePath(), "System.Private.CoreLib.dll"); - std::string cmd = ildasm + " " + coreLib + " | grep '\\.corflags'"; - fp = popen(cmd.c_str(), "r"); - if (fp != NULL) { - while (fgets(buff, sizeof(buff), fp) != NULL) { - buff[strlen(buff) - 1] = '\0'; - } - std::string corflag = replaceAll(buff, ".corflags", ""); - corflag.erase(std::remove(corflag.begin(), corflag.end(), ' '), corflag.end()); - // CorFlags.ILLibrary=0x00000004 (.ni.dll) - if (!strcmp(corflag.substr(0, 10).c_str(), "0x00000004")) { - pclose(fp); - return true; - } - pclose(fp); - } - return false; -} - -static ni_error_e createCoreLibNI(DWORD flags) +ni_error_e initNICommon() { - std::string coreLib = concatPath(__pm->getRuntimePath(), "System.Private.CoreLib.dll"); - std::string niCoreLib = concatPath(__pm->getRuntimePath(), "System.Private.CoreLib.ni.dll"); - std::string coreLibBackup = concatPath(__pm->getRuntimePath(), "System.Private.CoreLib.dll.Backup"); +#if defined(__arm__) || defined(__aarch64__) - if (!isFile(coreLibBackup) && !hasCoreLibNI()) { - if (!crossgen(coreLib, std::string(), flags)) { - if (rename(coreLib.c_str(), coreLibBackup.c_str())) { - fprintf(stderr, "Failed to rename System.Private.CoreLib.dll\n"); - return NI_ERROR_CORE_NI_FILE; - } - if (rename(niCoreLib.c_str(), coreLib.c_str())) { - fprintf(stderr, "Failed to rename System.Private.CoreLib.ni.dll\n"); - return NI_ERROR_CORE_NI_FILE; - } - } else { - fprintf(stderr, "Failed to create native image for %s\n", coreLib.c_str()); - return NI_ERROR_CORE_NI_FILE; - } + char *env = nullptr; + env = getenv("MIC_CROSSGEN2_ENABLED"); + if (env != nullptr && !strcmp(env, "1")) { + CORERUN_CMD = std::string("/opt/usr/dotnet/mic/crossgen2"); + CROSSGEN2_PATH = ""; + CLRJIT_PATH = std::string("/opt/usr/dotnet/mic/libclrjit_unix_") + ARCHITECTURE_IDENTIFIER + std::string("_x64.so"); } - return NI_ERROR_NONE; -} -ni_error_e initNICommon() -{ -#if defined(__arm__) || defined(__aarch64__) // get interval value const static std::string intervalFile = concatPath(__NATIVE_LIB_DIR, "crossgen_interval.txt"); std::ifstream inFile(intervalFile); if (inFile) { - fprintf(stdout, "crossgen_interval.txt is found\n"); + _SOUT("crossgen_interval.txt is found"); inFile >> __interval; } if (initializePluginManager("normal")) { - fprintf(stderr, "Fail to initialize PluginManager\n"); + _SERR("Fail to initialize PluginManager"); return NI_ERROR_UNKNOWN; } try { __pm = new PathManager(); } catch (const std::exception& e) { - fprintf(stderr, "Failed to create PathManager"); + _SERR("Failed to create PathManager"); return NI_ERROR_UNKNOWN; } char* pluginDllPaths = pluginGetDllPath(); - if (pluginDllPaths) { - __pm->addPlatformAssembliesPaths(pluginDllPaths); + if (pluginDllPaths && pluginDllPaths[0] != '\0') { + __pm->addPlatformAssembliesPaths(pluginDllPaths, true); + } + + char* pluginNativePaths = pluginGetNativeDllSearchingPath(); + if (pluginNativePaths && pluginNativePaths[0] != '\0') { + __pm->addNativeDllSearchingPaths(pluginNativePaths, true); } return NI_ERROR_NONE; #else - fprintf(stderr, "crossgen supports arm/arm64 architecture only. skip ni file generation\n"); + _SERR("crossgen supports arm/arm64 architecture only. skip ni file generation"); return NI_ERROR_NOT_SUPPORTED; #endif } @@ -505,109 +898,175 @@ void finalizeNICommon() delete(__pm); __pm = nullptr; + + if (__ni_option) { + free(__ni_option); + __ni_option = nullptr; + } } -ni_error_e createNIPlatform(DWORD flags) +ni_error_e createNIPlatform(std::string& extraInputs, NIOption* opt) { - if (createCoreLibNI(flags) != NI_ERROR_NONE) { - return NI_ERROR_CORE_NI_FILE; - } + extraInputs += ":" + __pm->getRuntimePath(); + extraInputs += ":" + __pm->getTizenFXPath(); - return createNIUnderDirs(__pm->getRuntimePath() + ":" + __pm->getTizenFXPath(), flags); + return createNIUnderDirs(extraInputs, opt); } -ni_error_e createNIDll(const std::string& dllPath, DWORD flags) +ni_error_e createNIDll(const std::string& dllPath, NIOption* opt) { - if (dllPath.find("System.Private.CoreLib.dll") != std::string::npos) { - return createCoreLibNI(flags); + return doAOTFile(dllPath, std::string(), opt); +} + +ni_error_e createNIUnderTAC(const std::string& targetPath, const std::string& refPaths, NIOption* opt) +{ + ni_error_e ret; + + bool isAppNI = false; + if (opt->flags & NI_FLAGS_APPNI) { + isAppNI = true; } - if (!isCoreLibPrepared(flags)) { - return NI_ERROR_CORE_NI_FILE; + if (opt->flags & NI_FLAGS_INPUT_BUBBLE) { + std::vector refs; + splitPath(refPaths, refs); + for (auto &p: refs) { + if (isDirectory(p) && checkDllExistInDir(p)) { + opt->inputBubbleRefFiles.push_back(p + "/*.dll"); + } + } } - return crossgen(dllPath, std::string(), flags); -} + // get managed file list from targetPath + std::vector dllList; + ret = getTargetDllList(targetPath, dllList); + if (ret != NI_ERROR_NONE) { + return ret; + } -ni_error_e createNIUnderDirs(const std::string rootPaths, DWORD flags) -{ - if (!isCoreLibPrepared(flags)) { - return NI_ERROR_CORE_NI_FILE; + std::vector needNIList; + std::vector niList; + + for (auto &dll : dllList) { + if (!checkNIExistence(dll)) { + needNIList.push_back(dll); + } + niList.push_back(getNIFilePath(dll)); } - auto convert = [&rootPaths, flags](const std::string& path, const std::string& filename) { - // if path is symlink, donot generate crossgen - if (!crossgen(path, rootPaths.c_str(), flags)) { - waitInterval(); + if (!needNIList.empty()) { + // NI fils of TAC-related dlls under /opt/usr/dotnet should not be created under .native_image directory. + // So, unset NI_FLAGS_APPNI temporally and restore it after running AOT. + opt->flags &= ~NI_FLAGS_APPNI; + ret = doAOTList(needNIList, refPaths, opt); + if (isAppNI) { + opt->flags |= NI_FLAGS_APPNI; } - }; + if (ret != NI_ERROR_NONE) { + return ret; + } + } - std::vector targetPaths; - splitPath(rootPaths, targetPaths); - for (const auto &path : targetPaths) { - // TAC directory should be handled specially because that contains symlink of native image file. - if (strstr(path.c_str(), TAC_SYMLINK_SUB_DIR) != NULL) { - if (!isDirectory(path)) { - continue; + if (isAppNI) { + for (auto &niPath : niList) { + if (exist(niPath)) { + std::string symNIPath = concatPath(targetPath, getFileName(niPath)); + if (!exist(symNIPath)) { + bf::create_symlink(niPath, symNIPath); + copySmackAndOwnership(targetPath.c_str(), symNIPath.c_str(), true); + _SOUT("%s symbolic link file generated successfully.", symNIPath.c_str()); + _INFO("%s symbolic link file generated successfully.", symNIPath.c_str()); + } } - // make native image symlink if not exist under tac directory - try { - for (auto& symlinkAssembly : bf::recursive_directory_iterator(path)) { - std::string symPath = symlinkAssembly.path().string(); - if (!isManagedAssembly(symPath)) { - continue; - } + } + } - // if there is symlink and original file for native image, skip generation - std::string symNIPath = symPath.substr(0, symPath.rfind(".dll")) + ".ni.dll"; - if (isFile(symNIPath)) { - continue; - } + return NI_ERROR_NONE; +} - // if original native image not exist, generate native image - std::string originPath = bf::read_symlink(symPath).string(); - std::string originNIPath = originPath.substr(0, originPath.rfind(".dll")) + ".ni.dll"; - if (!isFile(originNIPath)) { - if (!crossgen(originPath, path.c_str(), flags)) { - waitInterval(); - } - } - // if no symlink file exist, create symlink - if (!isFile(symNIPath)) { - bf::create_symlink(originNIPath, symNIPath); - copySmackAndOwnership(symPath.c_str(), symNIPath.c_str(), true); - fprintf(stdout, "%s symbolic link file generated successfully.\n", symNIPath.c_str()); - _INFO("%s symbolic link file generated successfully.", symNIPath.c_str()); - } - } - } catch (const bf::filesystem_error& error) { - fprintf(stderr, "Failed to recursive directory: %s\n", error.what()); - return NI_ERROR_UNKNOWN; +ni_error_e createNIUnderDirs(const std::string& rootPaths, NIOption* opt) +{ + ni_error_e ret = NI_ERROR_NONE; + + std::vector fileList; + std::vector paths; + splitPath(rootPaths, paths); + + if (opt->flags & NI_FLAGS_INPUT_BUBBLE) { + for (auto &p: paths) { + if (isDirectory(p) && checkDllExistInDir(p)) { + opt->inputBubbleRefFiles.push_back(p + "/*.dll"); + } + } + } + + for (const auto &path : paths) { + if (!exist(path)) { + continue; + } + + if (path.find(TAC_SYMLINK_SUB_DIR) != std::string::npos) { + ret = createNIUnderTAC(path, rootPaths, opt); + if (ret != NI_ERROR_NONE) { + return ret; + } + } else if (opt->flags & NI_FLAGS_APPNI) { + ret = getAppTargetDllList(path, fileList, opt); + if (ret != NI_ERROR_NONE) { + return ret; } } else { - scanFilesInDirectory(path, convert, 0); + ret = getTargetDllList(path, fileList); + if (ret != NI_ERROR_NONE) { + return ret; + } } } - return NI_ERROR_NONE; + if (fileList.empty()) { + return NI_ERROR_NONE; + } + + return doAOTList(fileList, rootPaths, opt); } -ni_error_e createNIUnderPkgRoot(const std::string& pkgId, DWORD flags) +ni_error_e createNIUnderPkgRoot(const std::string& pkgId, NIOption* opt) { + if (!isR2RImage(concatPath(__pm->getRuntimePath(), "System.Private.CoreLib.dll"))) { + _SERR("The native image of System.Private.CoreLib does not exist.\n" + "Run the command to create the native image\n" + "# dotnettool --ni-dll /usr/share/dotnet.tizen/netcoreapp/System.Private.CoreLib.dll"); + return NI_ERROR_CORE_NI_FILE; + } + std::string rootPath = getRootPath(pkgId); if (rootPath.empty()) { - fprintf(stderr, "Failed to get root path from [%s]\n", pkgId.c_str()); + _SERR("Failed to get root path from [%s]", pkgId.c_str()); return NI_ERROR_INVALID_PACKAGE; } __pm->setAppRootPath(rootPath); - flags |= NI_FLAGS_APPNI; + char* extraDllPaths = pluginGetExtraDllPath(); + if (extraDllPaths && extraDllPaths[0] != '\0') { + opt->flags |= NI_FLAGS_EXTRA_REF; + splitPath(extraDllPaths, opt->extraRefPath); + } + + opt->flags |= NI_FLAGS_APPNI; + + if (isReadOnlyArea(rootPath)) { + opt->flags |= NI_FLAGS_APP_UNDER_RO_AREA; + opt->flags |= NI_FLAGS_NO_PIPELINE; + _SERR("Only no-pipeline mode supported for RO app. Set no-pipeline option forcibly"); + } else { + opt->flags &= ~NI_FLAGS_APP_UNDER_RO_AREA; + } // create native image under bin and lib directory // tac directory is skipped in the createNIUnderDirs. - return createNIUnderDirs(__pm->getAppPaths(), flags); + return createNIUnderDirs(__pm->getAppPaths(), opt); } void removeNIPlatform() @@ -615,23 +1074,23 @@ void removeNIPlatform() std::string coreLib = concatPath(__pm->getRuntimePath(), "System.Private.CoreLib.dll"); std::string coreLibBackup = concatPath(__pm->getRuntimePath(), "System.Private.CoreLib.dll.Backup"); - if (hasCoreLibNI()) { + if (isR2RImage(coreLib)) { if (!isFile(coreLibBackup)) { return; } if (remove(coreLib.c_str())) { - fprintf(stderr, "Failed to remove System.Private.CoreLib native image file\n"); + _SERR("Failed to remove System.Private.CoreLib native image file"); } if (rename(coreLibBackup.c_str(), coreLib.c_str())) { - fprintf(stderr, "Failed to rename System.Private.CoreLib.Backup to origin\n"); + _SERR("Failed to rename System.Private.CoreLib.Backup to origin"); } } #ifdef UNIQUE_DEFAULT_BASE_ADDR_SUPPORT if (isFile(__SYSTEM_BASE_FILE)) { if (remove(__SYSTEM_BASE_FILE)) { - fprintf(stderr, "Failed to remove %s\n", __SYSTEM_BASE_FILE); + _SERR("Failed to remove %s", __SYSTEM_BASE_FILE); } } #endif @@ -639,12 +1098,17 @@ void removeNIPlatform() removeNIUnderDirs(__pm->getRuntimePath() + ":" + __pm->getTizenFXPath()); } -void removeNIUnderDirs(const std::string rootPaths) +void removeNIUnderDirs(const std::string& rootPaths) { auto convert = [](const std::string& path, const std::string& filename) { if (isNativeImage(path)) { - if (remove(path.c_str())) { - fprintf(stderr, "Failed to remove %s\n", path.c_str()); + std::string assemblyPath = changeExtension(path, ".ni.dll", ".dll"); + if (exist(assemblyPath)) { + if (remove(path.c_str())) { + _SERR("Failed to remove %s", path.c_str()); + } + } else { + _SOUT("%s cannot be removed because there is no %s", path.c_str(), assemblyPath.c_str()); } } }; @@ -660,7 +1124,7 @@ ni_error_e removeNIUnderPkgRoot(const std::string& pkgId) { std::string rootPath = getRootPath(pkgId); if (rootPath.empty()) { - fprintf(stderr, "Failed to get root path from [%s]\n", pkgId.c_str()); + _SERR("Failed to get root path from [%s]", pkgId.c_str()); return NI_ERROR_INVALID_PACKAGE; } @@ -671,27 +1135,35 @@ ni_error_e removeNIUnderPkgRoot(const std::string& pkgId) std::vector paths; splitPath(appNIPaths, paths); for (const auto &path : paths) { - // Only the native image inside the TAC should be removed. - if (strstr(path.c_str(), TAC_SYMLINK_SUB_DIR) != NULL) { - removeNIUnderDirs(path); - } else { - if (isDirectory(path)) { - if (!removeAll(path.c_str())) { - fprintf(stderr, "Failed to remove app ni dir [%s]\n", path.c_str()); + if (!isReadOnlyArea(path)) { + // Only the native image inside the TAC should be removed. + if (strstr(path.c_str(), TAC_SYMLINK_SUB_DIR) != NULL) { + removeNIUnderDirs(path); + } else { + if (isDirectory(path)) { + if (!removeAll(path.c_str())) { + _SERR("Failed to remove app ni dir [%s]", path.c_str()); + } } } } } + // In special cases, the ni file may exist in the dll location. + // The code below is to avoid this exceptional case. + std::string appPaths = __pm->getAppPaths(); + splitPath(appPaths, paths); + for (const auto &path : paths) { + if (isDirectory(path)) { + removeNIUnderDirs(path); + } + } + return NI_ERROR_NONE; } -ni_error_e regenerateAppNI(DWORD flags) +ni_error_e regenerateAppNI(NIOption* opt) { - if (!isCoreLibPrepared(flags)) { - return NI_ERROR_CORE_NI_FILE; - } - int ret = 0; pkgmgrinfo_appinfo_metadata_filter_h handle; @@ -699,21 +1171,18 @@ ni_error_e regenerateAppNI(DWORD flags) if (ret != PMINFO_R_OK) return NI_ERROR_UNKNOWN; - ret = pkgmgrinfo_appinfo_metadata_filter_add(handle, AOT_METADATA_KEY, METADATA_VALUE); + ret = pkgmgrinfo_appinfo_metadata_filter_add(handle, AOT_METADATA_KEY, METADATA_VALUE_TRUE); if (ret != PMINFO_R_OK) { pkgmgrinfo_appinfo_metadata_filter_destroy(handle); return NI_ERROR_UNKNOWN; } - ret = pkgmgrinfo_appinfo_metadata_filter_foreach(handle, appAotCb, &flags); - if (ret != PMINFO_R_OK) { - fprintf(stderr, "Failed pkgmgrinfo_appinfo_metadata_filter_foreach\n"); + ret = pkgmgrMDFilterForeach(handle, appAotCb, &opt); + if (ret != 0) { pkgmgrinfo_appinfo_metadata_filter_destroy(handle); return NI_ERROR_UNKNOWN; } - fprintf(stdout, "Success pkgmgrinfo_appinfo_metadata_filter_foreach\n"); - pkgmgrinfo_appinfo_metadata_filter_destroy(handle); return NI_ERROR_NONE; } @@ -722,17 +1191,30 @@ ni_error_e regenerateAppNI(DWORD flags) static int regenTacCb(pkgmgrinfo_appinfo_h handle, void *userData) { char *pkgId = NULL; - DWORD *pFlags = (DWORD*)userData; + char *root = NULL; + NIOption **pOpt = (NIOption**)userData; int ret = pkgmgrinfo_appinfo_get_pkgid(handle, &pkgId); if (ret != PMINFO_R_OK || pkgId == NULL) { - fprintf(stderr, "Failed to get pkgid\n"); + _SERR("Failed to get pkgid"); return -1; } + ret = pkgmgrinfo_appinfo_get_root_path(handle, &root); + if (ret != PMINFO_R_OK) { + _SERR("Failed to get root path"); + return -1; + } + + std::string binPath = concatPath(std::string(root), "bin"); + if (exist(concatPath(binPath, PRE_COMPILED_PACKAGE_FILE))) { + _INFO("The %s is a Pre-Compiled package. So, skip the TAC", pkgId); + return 0; + } + sqlite3 *tac_db = openDB(TAC_APP_LIST_DB); if (!tac_db) { - fprintf(stderr, "Sqlite open error\n"); + _SERR("Sqlite open error"); return -1; } sqlite3_exec(tac_db, "BEGIN;", NULL, NULL, NULL); @@ -754,27 +1236,15 @@ static int regenTacCb(pkgmgrinfo_appinfo_h handle, void *userData) nugetPaths += concatPath(__DOTNET_DIR, nuget); } - auto convert = [&nugetPaths, pFlags](const std::string& path, const std::string& filename) { - if (strstr(path.c_str(), TAC_SHA_256_INFO) != NULL) - return; - if (!crossgen(path, nugetPaths.c_str(), *pFlags)) { - waitInterval(); - } - }; - for (auto& nuget : nugets) { - scanFilesInDirectory(concatPath(__DOTNET_DIR, nuget), convert, -1); + createNIUnderTAC(concatPath(__DOTNET_DIR, nuget), nugetPaths, *pOpt); } return 0; } -ni_error_e regenerateTACNI(DWORD flags) +ni_error_e regenerateTACNI(NIOption* opt) { - if (!isCoreLibPrepared(flags)) { - return NI_ERROR_CORE_NI_FILE; - } - removeNIUnderDirs(__DOTNET_DIR); pkgmgrinfo_appinfo_metadata_filter_h handle; @@ -783,21 +1253,20 @@ ni_error_e regenerateTACNI(DWORD flags) return NI_ERROR_UNKNOWN; } - ret = pkgmgrinfo_appinfo_metadata_filter_add(handle, TAC_METADATA_KEY, METADATA_VALUE); + ret = pkgmgrinfo_appinfo_metadata_filter_add(handle, TAC_METADATA_KEY, METADATA_VALUE_TRUE); if (ret != PMINFO_R_OK) { pkgmgrinfo_appinfo_metadata_filter_destroy(handle); return NI_ERROR_UNKNOWN; } - ret = pkgmgrinfo_appinfo_metadata_filter_foreach(handle, regenTacCb, &flags); - if (ret != PMINFO_R_OK) { - fprintf(stderr, "Failed pkgmgrinfo_appinfo_metadata_filter_foreach\n"); + ret = pkgmgrMDFilterForeach(handle, regenTacCb, &opt); + if (ret != 0) { pkgmgrinfo_appinfo_metadata_filter_destroy(handle); return NI_ERROR_UNKNOWN; } - fprintf(stdout, "Success pkgmgrinfo_appinfo_metadata_filter_foreach\n"); pkgmgrinfo_appinfo_metadata_filter_destroy(handle); return NI_ERROR_NONE; } +