X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=NativeLauncher%2Ftool%2Fni_common.cc;h=f7b69ad7679a4e46881303c9910dadc1e0685b43;hb=4815801fb95b1cc086d4f1dc6e6b671f80767451;hp=ed24af347ef292c79f0911b295ad923fd54718aa;hpb=4ff9b3751fba4d670809ef5c73a6fc8409707c15;p=platform%2Fcore%2Fdotnet%2Flauncher.git diff --git a/NativeLauncher/tool/ni_common.cc b/NativeLauncher/tool/ni_common.cc index ed24af3..f7b69ad 100644 --- a/NativeLauncher/tool/ni_common.cc +++ b/NativeLauncher/tool/ni_common.cc @@ -17,7 +17,6 @@ #include #include #include -#include #include "log.h" #include "utils.h" @@ -26,13 +25,14 @@ #include #include #include +#include +#include #include #include #include #include -#include #include #include #include @@ -67,9 +67,9 @@ static const char* __SYSTEM_BASE_FILE = __STR(SYSTEM_BASE_FILE); #undef __STR #undef __XSTR -static const char* CORERUN_CMD = "/usr/share/dotnet.tizen/netcoreapp/corerun"; -static const char* CROSSGEN2_PATH = "/usr/share/dotnet.tizen/netcoreapp/crossgen2/crossgen2.dll"; -static const char* CLRJIT_PATH = "/usr/share/dotnet.tizen/netcoreapp/libclrjit.so"; +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"; @@ -77,7 +77,8 @@ static const char* CROSSGEN_OPT_SINGLE_FILE_COMPILATION = "--single-file-compila //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 = "-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"; @@ -102,67 +103,95 @@ NIOption* getNIOption() return __ni_option; } -static bool isCoreLibPrepared() +static void waitInterval() { - std::string coreLibBackup = concatPath(__pm->getRuntimePath(), "System.Private.CoreLib.dll.Backup"); - if (isFile(coreLibBackup)) { - return true; - } else { - _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\n"); - return false; + // by the recommand, ignore small value for performance. + if (__interval > 10000) { + _SOUT("sleep %d usec", __interval); + usleep(__interval); } } -static bool hasCoreLibNI() +#ifdef UNIQUE_DEFAULT_BASE_ADDR_SUPPORT +// 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() { - std::string ildasm = concatPath(__pm->getRuntimePath(), "ildasm"); - std::string coreLib = concatPath(__pm->getRuntimePath(), "System.Private.CoreLib.dll"); - std::string cmd = ildasm + " " + coreLib + " -noil -stats | grep '.rsrc'"; - - FILE *fp; - fp = popen(cmd.c_str(), "r"); - if (fp != NULL) { - char buff[1024]; - if (fgets(buff, sizeof(buff), fp) != NULL) { - pclose(fp); - return false; - } - pclose(fp); + FILE *pFile = fopen(__SYSTEM_BASE_FILE, "r"); + if (pFile == NULL) { + _SERR("Failed to open %s", __SYSTEM_BASE_FILE); + return 0; } - return true; + + uintptr_t addr = 0; + uintptr_t size = 0; + + while (fscanf(pFile, "%" SCNxPTR " %" SCNuPTR "", &addr, &size) != EOF) { + } + + fclose(pFile); + + return addr + size; } -static void waitInterval() +// Get next base address to be used for system ni image +static uintptr_t getNextBaseAddr() { - // by the recommand, ignore small value for performance. - if (__interval > 10000) { - _SOUT("sleep %d usec", __interval); - usleep(__interval); + uintptr_t baseAddr = 0; + + if (!isFile(__SYSTEM_BASE_FILE)) { + // This is the starting address for all default base addresses + baseAddr = DEFAULT_BASE_ADDR_START; + } else { + baseAddr = getNextBaseAddrFromFile(); + + // Round to a multple of 64K (see ZapImage::CalculateZapBaseAddress in CoreCLR) + uintptr_t BASE_ADDRESS_ALIGNMENT = 0xffff; + baseAddr = (baseAddr + BASE_ADDRESS_ALIGNMENT) & ~BASE_ADDRESS_ALIGNMENT; } + + return baseAddr; } -static std::string getNIFilePath(const std::string& dllPath) +// Save base address of system ni image to file +static void updateBaseAddrFile(const std::string& absNIPath, uintptr_t baseAddr) { - size_t index = dllPath.find_last_of("."); - if (index == std::string::npos) { - _SERR("File doesnot contain extension. fail to get NI file name"); - return ""; + uintptr_t niSize = getSizeOfImage(absNIPath); + if (niSize == 0) { + _SERR("File %s doesn't exist", absNIPath.c_str()); + 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; + // Write new entry to the file + FILE *pFile = fopen(__SYSTEM_BASE_FILE, "a"); + if (pFile == NULL) { + _SERR("Failed to open %s", __SYSTEM_BASE_FILE); + return; + } - return niPath; + fprintf(pFile, "%" PRIxPTR " %" PRIuPTR "\n", baseAddr, niSize); + fclose(pFile); } +// check if dll is listed in TPA +static bool isTPADll(const std::string& dllPath) +{ + std::string absPath = getBaseName(getAbsolutePath(dllPath)); + + std::vector paths = __pm->getPlatformAssembliesPaths(); + for (unsigned int i = 0; i < paths.size(); i++) { + if (paths[i].find(getBaseName(absPath)) != std::string::npos) { + return true; + } + } + + return false; +} +#endif + /** * @brief create the directory including parents directory, and - * copy ownership and smack labels to the created directory. + * 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 @@ -201,33 +230,57 @@ static bool createDirsAndCopyOwnerShip(std::string& target_path, const std::stri return true; } -static std::string getAppNIFilePath(const std::string& absDllPath, NIOption* opt) +static std::string getNIFilePath(const std::string& absDllPath, NIOption* opt) { - std::string niDirPath; - std::string prevPath; - - prevPath = getBaseName(absDllPath); - niDirPath = concatPath(prevPath, APP_NI_SUB_DIR); + std::string dllPath = absDllPath; + std::string fileName = getFileName(absDllPath); + if (opt->flags & NI_FLAGS_APPNI) { + std::string niDirPath; + std::string niTmpDirPath; + std::string prevPath; + + prevPath = getBaseName(absDllPath); + niDirPath = concatPath(prevPath, APP_NI_SUB_DIR); + niTmpDirPath = concatPath(prevPath, APP_NI_SUB_TMP_DIR); + + if (opt->flags & NI_FLAGS_APP_UNDER_RO_AREA) { + niTmpDirPath = replaceAll(niTmpDirPath, getBaseName(__pm->getAppRootPath()), __READ_ONLY_APP_UPDATE_DIR); + niDirPath = replaceAll(niDirPath, getBaseName(__pm->getAppRootPath()), __READ_ONLY_APP_UPDATE_DIR); + _INFO("App is installed in RO area. Change NI path to RW area(%s).", niTmpDirPath.c_str()); + } - 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(niTmpDirPath, prevPath)) { + niTmpDirPath = prevPath; + _SERR("fail to create dir (%s)", niTmpDirPath.c_str()); + } + dllPath = concatPath(niTmpDirPath, fileName); + } else { + dllPath = concatPath(niDirPath, fileName); + } + } else if (opt->flags & NI_FLAGS_RESOURCE_NI) { + std::string rpkDir = concatPath(__pm->getAppRootPath(), APP_NI_SUB_DIR); + dllPath = createDir(rpkDir) ? concatPath(rpkDir, fileName) : concatPath(__pm->getAppRootPath(), fileName); } - if (!isDirectory(niDirPath)) { - if (!createDirsAndCopyOwnerShip(niDirPath, prevPath)) { - niDirPath = prevPath; - _SERR("fail to create dir (%s)", niDirPath.c_str()); - } + 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()); - return getNIFilePath(concatPath(niDirPath, getFileName(absDllPath))); + // 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 bool checkNIExistence(const std::string& absDllPath) +static bool checkNIExistence(const std::string& absDllPath, NIOption* opt) { - std::string absNIPath = getNIFilePath(absDllPath); + std::string absNIPath = getNIFilePath(absDllPath, opt); if (absNIPath.empty()) { return false; } @@ -239,9 +292,7 @@ static bool checkNIExistence(const std::string& absDllPath) // 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) { - if (hasCoreLibNI()) { - return true; - } + return isR2RImage(absDllPath); } return false; @@ -251,7 +302,7 @@ 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)) { + if (isManagedAssembly(f_name) || isR2RImage(f_name)) { ret = true; } }; @@ -262,23 +313,19 @@ static bool checkDllExistInDir(const std::string& path) } /* - * Get the list of managed files in the specific directory + * 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 same directory, managed file is ignored. - * - * Note: System.Private.CoreLib is excluded from the result list. + * If native image already exist in the (same / .native_image) directory, managed file is ignored. */ -static ni_error_e getTargetDllList(const std::string& path, std::vector& fileList) +static ni_error_e getTargetDllList(const std::string& path, std::vector& fileList, NIOption *opt) { 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)) { - if (f_path.find("System.Private.CoreLib") == std::string::npos) { - fileList.push_back(getAbsolutePath(f_path)); - } + auto func = [&fileList, opt](const std::string& f_path, const std::string& f_name) { + if (isManagedAssembly(f_path) && !checkNIExistence(f_path, opt)) { + fileList.push_back(getAbsolutePath(f_path)); } }; @@ -289,41 +336,31 @@ static ni_error_e getTargetDllList(const std::string& path, std::vector& args, const std::vector& refPaths, NIOption* opt) { - args.push_back(CORERUN_CMD); - args.push_back(CROSSGEN2_PATH); + 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); + args.push_back(CLRJIT_PATH.c_str()); args.push_back(CROSSGEN_OPT_TARGET_ARCH); args.push_back(ARCHITECTURE_IDENTIFIER); - if (!(opt->flags & NI_FLAGS_NO_PIPELINE)) { - args.push_back(CROSSGEN_OPT_OUT_NEAR_INPUT); - args.push_back(CROSSGEN_OPT_SINGLE_FILE_COMPILATION); - } + //args.push_back(OPT_PARALLELISM); //args.push_back(OPT_PARALLELISM_COUNT); args.push_back(CROSSGEN_OPT_RESILIENT); - args.push_back(CROSSGEN_OPT_OPTIMIZE); + 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); - if (opt->flags & NI_FLAGS_INPUT_BUBBLE_REF) { - INPUTBUBBLE_REF_VECTOR.clear(); - // check inputbubbleref format. - for (const auto &path : opt->inputBubbleRefPath) { - if (checkDllExistInDir(path)) { - INPUTBUBBLE_REF_VECTOR.push_back("--inputbubbleref:" + path + "/*.dll"); - } - } - // add ref path to inputbubble ref - for (const auto &path : refPaths) { - if (checkDllExistInDir(path)) { - INPUTBUBBLE_REF_VECTOR.push_back("--inputbubbleref:" + path + "/*.dll"); - } - } - for (const auto &path : INPUTBUBBLE_REF_VECTOR) { + 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()); } } @@ -335,7 +372,9 @@ static void makeArgs(std::vector& args, const std::vector& args, const std::vectorflags & NI_FLAGS_REF) { - for (const auto &path : opt->refPath) { + 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"); } - } else { - std::vector paths = __pm->getPlatformAssembliesPaths(); - for (const auto &path : paths) { + } + + 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"); } @@ -366,7 +412,9 @@ static void makeArgs(std::vector& args, const std::vectorflags & NI_FLAGS_APPNI) { + outFile = getNIFilePath(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 (opt->flags & NI_FLAGS_RM_ORIGIN_AFTER_NI) { + if (!removeFile(dllPath)) { + _SERR("Fail to remove original file : %s", dllPath.c_str()); + } + } + + if (opt->flags & NI_FLAGS_RESOURCE_NI) { + moveFile(niPath, changeExtension(dllPath, ".dll", ".ni.dll")); + removeAll(concatPath(__pm->getAppRootPath(), APP_NI_SUB_DIR)); + } + + 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; +} + +void setPriority(NIOption* opt) +{ + pid_t pid = getpid(); + if (setpriority(PRIO_PROCESS, pid, opt->priority) == 0) { + std::string str = " "; + if (opt->priority <= -20) { + str = " highest "; + } else if (opt->priority >= 19) { + str = " lowest "; + } + _SOUT("Success to set the%spriority of the process. pid : [%d], priority : [%d]", str.c_str(), pid, getpriority(PRIO_PROCESS, pid)); + } else { + _SERR("Failed to set the priority of the process. pid : [%d], priority : [%d]", pid, getpriority(PRIO_PROCESS, pid)); + } +} + static ni_error_e crossgen2PipeLine(const std::vector& dllList, const std::vector& refPaths, NIOption* opt) { // fork crossgen2 @@ -407,29 +510,23 @@ static ni_error_e crossgen2PipeLine(const std::vector& dllList, con waitpid(pid, &status, 0); if (WIFEXITED(status)) { for (auto& dllPath: dllList) { - std::string niPath = changeExtension(dllPath, ".dll", ".ni.dll"); - - if (!exist(niPath)) { - _SERR("Fail to create native image for %s", dllPath.c_str()); - return NI_ERROR_NO_SUCH_FILE; + ni_error_e ret = crossgen2PostAction(dllPath, changeExtension(dllPath, ".dll", ".ni.dll"), opt); + if (ret != NI_ERROR_NONE) { + return ret; } - - copySmackAndOwnership(dllPath, niPath); - // if AppNI then move ni.dll file to .native_image and copy pdb to .native_image - if (opt->flags & NI_FLAGS_APPNI) { - std::string appNIPath = getAppNIFilePath(dllPath, opt); - moveFile(niPath, appNIPath); - makePdbSymlinkForNI(dllPath, appNIPath); - niPath = appNIPath; - } - - _SOUT("Native image %s generated successfully.", niPath.c_str()); } + } else { + _SERR("Failed. Forked process terminated abnormally"); + return NI_ERROR_ABNORMAL_PROCESS_TERMINATION; } } else { + if (opt->flags & NI_FLAGS_SET_PRIORITY) { + setPriority(opt); + } 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) { @@ -437,6 +534,7 @@ static ni_error_e crossgen2PipeLine(const std::vector& dllList, con _SOUT("+ %s", input.c_str()); } + // end param argv.push_back(nullptr); // print cmd @@ -445,7 +543,7 @@ static ni_error_e crossgen2PipeLine(const std::vector& dllList, con for (auto &arg: argv) _SOUT("+ %s", arg); } - execv(CORERUN_CMD, const_cast(argv.data())); + execv(CORERUN_CMD.c_str(), const_cast(argv.data())); clearArgs(argv); exit(0); @@ -458,10 +556,16 @@ static ni_error_e crossgen2NoPipeLine(const std::vector& dllList, c { for (auto& dllPath : dllList) { std::string niPath; - if (opt->flags & NI_FLAGS_APPNI) { - niPath = getAppNIFilePath(dllPath, opt); - } else { - niPath = getNIFilePath(dllPath); + niPath = getNIFilePath(dllPath, opt); + +#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 @@ -473,22 +577,38 @@ static ni_error_e crossgen2NoPipeLine(const std::vector& dllList, c int status; waitpid(pid, &status, 0); if (WIFEXITED(status)) { - if (!exist(niPath)) { - _SERR("Fail to create native image for %s", dllPath.c_str()); - return NI_ERROR_NO_SUCH_FILE; + ni_error_e ret = crossgen2PostAction(dllPath, niPath, opt); + if (ret != NI_ERROR_NONE) { + return ret; } - - copySmackAndOwnership(dllPath, niPath); - if (opt->flags & NI_FLAGS_APPNI) { - makePdbSymlinkForNI(dllPath, niPath); +#ifdef UNIQUE_DEFAULT_BASE_ADDR_SUPPORT + if (baseAddr != 0) { + updateBaseAddrFile(niPath, baseAddr); } - - _SOUT("Native image %s generated successfully.", niPath.c_str()); +#endif + } else { + _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 { + if (opt->flags & NI_FLAGS_SET_PRIORITY) { + setPriority(opt); + } 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()); @@ -504,7 +624,7 @@ static ni_error_e crossgen2NoPipeLine(const std::vector& dllList, c for (auto &arg: argv) _SOUT("+ %s", arg); } - execv(CORERUN_CMD, const_cast(argv.data())); + execv(CORERUN_CMD.c_str(), const_cast(argv.data())); clearArgs(argv); exit(0); @@ -516,36 +636,167 @@ static ni_error_e crossgen2NoPipeLine(const std::vector& dllList, c 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; + } + } + } else { + _SERR("Failed to create native image for %s", coreLib.c_str()); + return NI_ERROR_CORE_NI_FILE; + } + } + return NI_ERROR_NONE; +} + +static void renameAppNITmpPath(NIOption* opt) +{ + std::string niTmpPath = __pm->getAppRootPath() + "/bin/" + APP_NI_SUB_TMP_DIR; + std::string niPath = __pm->getAppRootPath() + "/bin/" + APP_NI_SUB_DIR; + + if (opt->flags & NI_FLAGS_APP_UNDER_RO_AREA) { + niTmpPath = replaceAll(niTmpPath, getBaseName(__pm->getAppRootPath()), __READ_ONLY_APP_UPDATE_DIR); + niPath = replaceAll(niPath, getBaseName(__pm->getAppRootPath()), __READ_ONLY_APP_UPDATE_DIR); + } + + if (isDirectory(niTmpPath)) { + if (rename(niTmpPath.c_str(), niPath.c_str())) { + _SERR("Fail to rename from .native_image_tmp to .native_image"); + } else { + _SOUT("Success to rename from %s to %s", niTmpPath.c_str(), niPath.c_str()); + } + } +} + 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; + 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--); } - if (!isManagedAssembly(f)) { + 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--); + } + } + + // Error : Multiple input files matching same simple name + // So, Remove dulicate files from dll list + std::sort(dllList.begin(), dllList.end()); + dllList.erase(unique(dllList.begin(), dllList.end()), dllList.end()); + + // 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 there is no proper input after processing dll list + if (dllList.empty()) { + if (hasSPC) { + return ret; + } else { + return NI_ERROR_INVALID_PARAMETER; + } } std::vector paths; splitPath(refPaths, paths); if (opt->flags & NI_FLAGS_NO_PIPELINE) { - crossgen2NoPipeLine(dllList, paths, opt); + ret = crossgen2NoPipeLine(dllList, paths, opt); } else { - crossgen2PipeLine(dllList, paths, opt); + 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); + } } - return NI_ERROR_NONE; + if (ret == NI_ERROR_NONE) { + if (opt->flags & NI_FLAGS_INPUT_BUBBLE) { + for (auto &dll : dllList) { + std::string tmpFile; + std::string niFile = getNIFilePath(dll, opt); + tmpFile = niFile + ".tmp"; + + if (exist(tmpFile)) { + moveFile(tmpFile, niFile); + _SOUT("Native image %s generated successfully.", niFile.c_str()); + } + } + } + if (opt->flags & NI_FLAGS_APPNI) { + renameAppNITmpPath(opt); + } + } + + return ret; } static ni_error_e doAOTFile(const std::string& dllFile, const std::string& refPaths, NIOption* opt) @@ -555,6 +806,11 @@ static ni_error_e doAOTFile(const std::string& dllFile, const std::string& refPa return NI_ERROR_NO_SUCH_FILE; } + if (checkNIExistence(dllFile, opt)) { + _SERR("Native image file is already exist : %s", dllFile.c_str()); + return NI_ERROR_ALREADY_EXIST; + } + if (!isManagedAssembly(dllFile)) { _SERR("Failed. Input parameter is not managed dll (%s)\n", dllFile.c_str()); return NI_ERROR_INVALID_PARAMETER; @@ -565,61 +821,89 @@ static ni_error_e doAOTFile(const std::string& dllFile, const std::string& refPa return doAOTList(dllList, refPaths, opt); } -// callback function of "pkgmgrinfo_appinfo_metadata_filter_foreach" -static int appAotCb(pkgmgrinfo_appinfo_h handle, void *userData) +static ni_error_e removeAndCreateNI(const char* pkgId, NIOption* pOptions) +{ + if (removeNIUnderPkgRoot(pkgId) != NI_ERROR_NONE) { + _SERR("Failed to remove previous dlls from [%s]", pkgId); + return NI_ERROR_UNKNOWN; + } + + if (createNIUnderPkgRoot(pkgId, pOptions) != NI_ERROR_NONE) { + _SERR("Failed to generate NI file [%s]", pkgId); + return NI_ERROR_UNKNOWN; + } + + _SOUT("Complete make native image for pkg (%s)", pkgId); + return NI_ERROR_NONE; +} + +static bool isReadOnlyPkg(std::string pkgId) { - char *pkgId = NULL; int ret = 0; - NIOption **pOptions = (NIOption**)userData; + bool readonly = false; + pkgmgrinfo_pkginfo_h handle; - ret = pkgmgrinfo_appinfo_get_pkgid(handle, &pkgId); + ret = pkgmgrinfo_pkginfo_get_pkginfo(pkgId.c_str(), &handle); if (ret != PMINFO_R_OK) { - _SERR("Failed to get pkgid"); - return -1; + _ERR("Fail to get pkginfo"); + return false; } - if (removeNIUnderPkgRoot(pkgId) != NI_ERROR_NONE) { - _SERR("Failed to remove previous dlls from [%s]", pkgId); - return -1; + ret = pkgmgrinfo_pkginfo_is_readonly(handle, &readonly); + if (ret != PMINFO_R_OK) { + _ERR("Fail to get is_readonly"); + pkgmgrinfo_pkginfo_destroy_pkginfo(handle); + return false; } - if (createNIUnderPkgRoot(pkgId, *pOptions) != NI_ERROR_NONE) { - _SERR("Failed to generate NI file [%s]", pkgId); + pkgmgrinfo_pkginfo_destroy_pkginfo(handle); + return readonly; +} + +// callback function of "pkgmgrinfo_appinfo_metadata_filter_foreach" +static int appAotCb(pkgmgrinfo_appinfo_h handle, void *userData) +{ + char *pkgId = NULL; + int ret = pkgmgrinfo_appinfo_get_pkgid(handle, &pkgId); + if (ret != PMINFO_R_OK) { + _SERR("Failed to get pkgid"); return -1; - } else { - _SOUT("Complete make application to native image"); } + std::vector *pkgList = (std::vector *)userData; + pkgList->push_back(pkgId); + return 0; } -static ni_error_e createCoreLibNI(NIOption* opt) +// callback function of "pkgmgrinfo_pkginfo_metadata_filter_foreach" +static int pkgAotCb(pkgmgrinfo_pkginfo_h handle, void *userData) { - 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 (!isFile(coreLibBackup) && !hasCoreLibNI()) { - if (doAOTFile(coreLib, std::string(), opt) == NI_ERROR_NONE && exist(niCoreLib)) { - if (rename(coreLib.c_str(), coreLibBackup.c_str())) { - _SERR("Failed to rename System.Private.CoreLib.dll"); - return NI_ERROR_CORE_NI_FILE; - } - if (rename(niCoreLib.c_str(), coreLib.c_str())) { - _SERR("Failed to rename System.Private.CoreLib.ni.dll"); - return NI_ERROR_CORE_NI_FILE; - } - } else { - _SERR("Failed to create native image for %s", coreLib.c_str()); - return NI_ERROR_CORE_NI_FILE; - } + char *pkgId = NULL; + int ret = pkgmgrinfo_pkginfo_get_pkgid(handle, &pkgId); + if (ret != PMINFO_R_OK) { + _SERR("Failed to get pkgid"); + return -1; } - return NI_ERROR_NONE; + + std::vector *pkgList = (std::vector *)userData; + pkgList->push_back(pkgId); + + return 0; } ni_error_e initNICommon() { #if defined(__arm__) || defined(__aarch64__) + + 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"); + } + // get interval value const static std::string intervalFile = concatPath(__NATIVE_LIB_DIR, "crossgen_interval.txt"); std::ifstream inFile(intervalFile); @@ -672,26 +956,16 @@ void finalizeNICommon() } } -ni_error_e createNIPlatform(NIOption* opt) +ni_error_e createNIPlatform(std::string& extraInputs, NIOption* opt) { - ni_error_e ret = createCoreLibNI(opt); - if (ret != NI_ERROR_NONE) { - return ret; - } + extraInputs += ":" + __pm->getRuntimePath(); + extraInputs += ":" + __pm->getTizenFXPath(); - return createNIUnderDirs(__pm->getRuntimePath() + ":" + __pm->getTizenFXPath(), opt); + return createNIUnderDirs(extraInputs, opt); } ni_error_e createNIDll(const std::string& dllPath, NIOption* opt) { - if (dllPath.find("System.Private.CoreLib.dll") != std::string::npos) { - return createCoreLibNI(opt); - } - - if (!isCoreLibPrepared()) { - return NI_ERROR_CORE_NI_FILE; - } - return doAOTFile(dllPath, std::string(), opt); } @@ -699,9 +973,27 @@ ni_error_e createNIUnderTAC(const std::string& targetPath, const std::string& re { ni_error_e ret; + // 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. + bool isAppNI = false; + if (opt->flags & NI_FLAGS_APPNI) { + opt->flags &= ~NI_FLAGS_APPNI; + isAppNI = true; + } + + 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"); + } + } + } + // get managed file list from targetPath std::vector dllList; - ret = getTargetDllList(targetPath, dllList); + ret = getTargetDllList(targetPath, dllList, opt); if (ret != NI_ERROR_NONE) { return ret; } @@ -710,31 +1002,30 @@ ni_error_e createNIUnderTAC(const std::string& targetPath, const std::string& re std::vector niList; for (auto &dll : dllList) { - if (!checkNIExistence(dll)) { + if (!checkNIExistence(dll, opt)) { needNIList.push_back(dll); } - niList.push_back(getNIFilePath(dll)); + niList.push_back(getNIFilePath(dll, opt)); } 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); - opt->flags |= NI_FLAGS_APPNI; if (ret != NI_ERROR_NONE) { return ret; } } - 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()); + if (isAppNI) { + opt->flags |= NI_FLAGS_APPNI; + 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()); + } } } } @@ -742,18 +1033,22 @@ ni_error_e createNIUnderTAC(const std::string& targetPath, const std::string& re return NI_ERROR_NONE; } - ni_error_e createNIUnderDirs(const std::string& rootPaths, NIOption* opt) { ni_error_e ret = NI_ERROR_NONE; - if (!isCoreLibPrepared()) { - return NI_ERROR_CORE_NI_FILE; - } 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; @@ -765,7 +1060,7 @@ ni_error_e createNIUnderDirs(const std::string& rootPaths, NIOption* opt) return ret; } } else { - ret = getTargetDllList(path, fileList); + ret = getTargetDllList(path, fileList, opt); if (ret != NI_ERROR_NONE) { return ret; } @@ -781,27 +1076,54 @@ ni_error_e createNIUnderDirs(const std::string& rootPaths, NIOption* opt) 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()) { _SERR("Failed to get root path from [%s]", pkgId.c_str()); return NI_ERROR_INVALID_PACKAGE; } - __pm->setAppRootPath(rootPath); - opt->flags |= NI_FLAGS_APPNI; + char* extraDllPaths = pluginGetExtraDllPath(); + if (extraDllPaths && extraDllPaths[0] != '\0') { + opt->flags |= NI_FLAGS_EXTRA_REF; + splitPath(extraDllPaths, opt->extraRefPath); + } + + std::string targetDirs; + if (isRPK(pkgId)) { + opt->flags &= ~NI_FLAGS_APPNI; // added to exclude logic of APP_NI + opt->flags |= NI_FLAGS_RESOURCE_NI; // added flag for RPK type + opt->flags |= NI_FLAGS_NO_PIPELINE; // added the flag to set the output path - 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"); + std::string paths = getResourcePaths(rootPath); + if (paths.empty()) { + _SERR("Failed to get rpk paths from [%s]", pkgId.c_str()); + return NI_ERROR_UNKNOWN; + } + targetDirs = paths; } else { - opt->flags &= ~NI_FLAGS_APP_UNDER_RO_AREA; + opt->flags |= NI_FLAGS_APPNI; + opt->flags &= ~NI_FLAGS_RESOURCE_NI; // added to exclude logic of RESOURCE_NI + + 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; + } + + targetDirs = __pm->getAppPaths(); } - // create native image under bin and lib directory - // tac directory is skipped in the createNIUnderDirs. - return createNIUnderDirs(__pm->getAppPaths(), opt); + return createNIUnderDirs(targetDirs, opt); } void removeNIPlatform() @@ -809,7 +1131,7 @@ 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; } @@ -836,9 +1158,14 @@ void removeNIPlatform() void removeNIUnderDirs(const std::string& rootPaths) { auto convert = [](const std::string& path, const std::string& filename) { - if (isNativeImage(path)) { - if (remove(path.c_str())) { - _SERR("Failed to remove %s", path.c_str()); + if (isR2RImage(path)) { + 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()); } } }; @@ -852,79 +1179,128 @@ void removeNIUnderDirs(const std::string& rootPaths) ni_error_e removeNIUnderPkgRoot(const std::string& pkgId) { + std::vector paths; + std::string rootPath = getRootPath(pkgId); if (rootPath.empty()) { _SERR("Failed to get root path from [%s]", pkgId.c_str()); return NI_ERROR_INVALID_PACKAGE; } - __pm->setAppRootPath(rootPath); - - // getAppNIPaths returns bin/.native_image, lib/.native_image and .tac_symlink. - std::string appNIPaths = __pm->getAppNIPaths(); - std::vector paths; - splitPath(appNIPaths, paths); - for (const auto &path : paths) { - if (!isReadOnlyArea(path)) { - // Only the native image inside the TAC should be removed. - if (strstr(path.c_str(), TAC_SYMLINK_SUB_DIR) != NULL) { + if (isRPK(pkgId)) { + std::string rpkPaths = getResourcePaths(rootPath); + if (rpkPaths.empty()) { + _SERR("Failed to get rpk path from [%s]", pkgId.c_str()); + return NI_ERROR_UNKNOWN; + } + splitPath(rpkPaths, paths); + for (const auto &path : paths) { + if (isDirectory(path)) { removeNIUnderDirs(path); - } else { - if (isDirectory(path)) { - if (!removeAll(path.c_str())) { - _SERR("Failed to remove app ni dir [%s]", path.c_str()); + } + } + } else { + __pm->setAppRootPath(rootPath); + + // getAppNIPaths returns bin/.native_image, lib/.native_image and .tac_symlink. + std::string appNIPaths = __pm->getAppNIPaths(); + splitPath(appNIPaths, paths); + for (const auto &path : paths) { + 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); + // 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(NIOption* opt) +ni_error_e regeneratePkgNI(NIOption* opt) { - if (!isCoreLibPrepared()) { - return NI_ERROR_CORE_NI_FILE; + std::vector pkgList; + ni_error_e ret = NI_ERROR_NONE; + + // iterates for Packages's metadata (RPK) + pkgmgrinfo_pkginfo_metadata_filter_h pkgHandle; + if (pkgmgrinfo_pkginfo_metadata_filter_create(&pkgHandle) == PMINFO_R_OK) { + if (pkgmgrinfo_pkginfo_metadata_filter_add(pkgHandle, AOT_METADATA_KEY, METADATA_VALUE_TRUE) == PMINFO_R_OK) { + if (pkgmgrPkgMDFilterForeach(pkgHandle, pkgAotCb, &pkgList) != 0) { + ret = NI_ERROR_UNKNOWN; + _ERR("pkgmgrPkgMDFilterForeach failed"); + } + } else { + ret = NI_ERROR_UNKNOWN; + _ERR("pkgmgrinfo_pkginfo_metadata_filter_add failed"); + } + pkgmgrinfo_pkginfo_metadata_filter_destroy(pkgHandle); + } else { + ret = NI_ERROR_UNKNOWN; + _ERR("pkgmgrinfo_pkginfo_metadata_filter_create failed"); } - int ret = 0; - pkgmgrinfo_appinfo_metadata_filter_h handle; + // iterate for App's metadata + pkgmgrinfo_appinfo_metadata_filter_h appHandle; + if (pkgmgrinfo_appinfo_metadata_filter_create(&appHandle) == PMINFO_R_OK) { + if (pkgmgrinfo_appinfo_metadata_filter_add(appHandle, AOT_METADATA_KEY, METADATA_VALUE_TRUE) == PMINFO_R_OK) { + if (pkgmgrAppMDFilterForeach(appHandle, appAotCb, &pkgList) != 0) { + ret = NI_ERROR_UNKNOWN; + _ERR("pkgmgrAppMDFilterForeach failed"); + } + } else { + ret = NI_ERROR_UNKNOWN; + _ERR("pkgmgrinfo_appinfo_metadata_filter_add failed"); + } + pkgmgrinfo_appinfo_metadata_filter_destroy(appHandle); + } else { + ret = NI_ERROR_UNKNOWN; + _ERR("pkgmgrinfo_appinfo_metadata_filter_create failed"); + } - ret = pkgmgrinfo_appinfo_metadata_filter_create(&handle); - if (ret != PMINFO_R_OK) - return NI_ERROR_UNKNOWN; + // remove duplicated pkg in the list. + // If one package has multiple apps, there can be duplicate values. + std::sort(pkgList.begin(), pkgList.end()); + pkgList.erase(unique(pkgList.begin(), pkgList.end()), pkgList.end()); - ret = pkgmgrinfo_appinfo_metadata_filter_add(handle, AOT_METADATA_KEY, METADATA_VALUE); - if (ret != PMINFO_R_OK) { - pkgmgrinfo_appinfo_metadata_filter_destroy(handle); - return NI_ERROR_UNKNOWN; - } + for (auto pkg : pkgList) { + if (isReadOnlyPkg(pkg) && opt->flags & NI_FLAGS_SKIP_RO_APP) { + continue; + } - ret = pkgmgrMDFilterForeach(handle, appAotCb, &opt); - if (ret != 0) { - pkgmgrinfo_appinfo_metadata_filter_destroy(handle); - return NI_ERROR_UNKNOWN; + if (removeAndCreateNI(pkg.c_str(), opt) != NI_ERROR_NONE) { + _SERR("Failed to remove previous dlls from [%s]", pkg.c_str()); + ret = NI_ERROR_UNKNOWN; + } else { + _SOUT("Complete make application to native image"); + } } - pkgmgrinfo_appinfo_metadata_filter_destroy(handle); - return NI_ERROR_NONE; + return ret; } // callback function of "pkgmgrinfo_appinfo_metadata_filter_foreach" static int regenTacCb(pkgmgrinfo_appinfo_h handle, void *userData) { char *pkgId = NULL; + char *root = NULL; NIOption **pOpt = (NIOption**)userData; int ret = pkgmgrinfo_appinfo_get_pkgid(handle, &pkgId); @@ -933,6 +1309,18 @@ static int regenTacCb(pkgmgrinfo_appinfo_h handle, void *userData) 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) { _SERR("Sqlite open error"); @@ -966,10 +1354,6 @@ static int regenTacCb(pkgmgrinfo_appinfo_h handle, void *userData) ni_error_e regenerateTACNI(NIOption* opt) { - if (!isCoreLibPrepared()) { - return NI_ERROR_CORE_NI_FILE; - } - removeNIUnderDirs(__DOTNET_DIR); pkgmgrinfo_appinfo_metadata_filter_h handle; @@ -978,13 +1362,13 @@ ni_error_e regenerateTACNI(NIOption* opt) 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 = pkgmgrMDFilterForeach(handle, regenTacCb, &opt); + ret = pkgmgrAppMDFilterForeach(handle, regenTacCb, &opt); if (ret != 0) { pkgmgrinfo_appinfo_metadata_filter_destroy(handle); return NI_ERROR_UNKNOWN; @@ -995,124 +1379,3 @@ ni_error_e regenerateTACNI(NIOption* opt) return NI_ERROR_NONE; } -static std::vector getUserIds() -{ - std::vector list; - - while (true) { - errno = 0; // so we can distinguish errors from no more entries - passwd* entry = getpwent(); - if (!entry) { - if (errno) { - _SERR("Error while getting userIDs"); - list.clear(); - return list; - } - break; - } - list.push_back(entry->pw_uid); - } - endpwent(); - - return list; -} - -static std::string getAppDataPath(const std::string& pkgId, uid_t uid) -{ - std::string pDataFile; - - tzplatform_set_user(uid); - - const char* tzUserApp = tzplatform_getenv(TZ_USER_APP); - if (tzUserApp != NULL) { - pDataFile = std::string(tzUserApp) + "/" + pkgId + "/data/"; - } - - tzplatform_reset_user(); - - return pDataFile; -} - -ni_error_e removeAppProfileData(const std::string& pkgId) -{ - if (pkgId.empty()) { - return NI_ERROR_INVALID_PARAMETER; - } - - std::vector uidList = getUserIds(); - for (auto& uid : uidList) { - // get data path from pkgid - std::string dataPath = getAppDataPath(pkgId, uid); - if (!dataPath.empty() && exist(dataPath)) { - std::string pDataFile = dataPath + PROFILE_BASENAME; - - if (exist(pDataFile)) { - if (!removeFile(pDataFile)) { - _SERR("Fail to remove profile data file (%s).", pDataFile.c_str()); - return NI_ERROR_UNKNOWN; - } - _SOUT("Profile data (%s) is removed successfully", pDataFile.c_str()); - } - } - } - - return NI_ERROR_NONE; -} - -static int appTypeListCb(pkgmgrinfo_appinfo_h handle, void *user_data) -{ - char *pkgId = NULL; - int ret = pkgmgrinfo_appinfo_get_pkgid(handle, &pkgId); - if (ret != PMINFO_R_OK || pkgId == NULL) { - _SERR("Fail to get pkgid"); - return 0; - } - - if (removeAppProfileData(pkgId) != NI_ERROR_NONE) { - _SERR("Fail to remove profile data for (%s)", pkgId); - } - - return 0; -} - -static ni_error_e removeAppProfileByAppType(const char* type) -{ - int ret; - - pkgmgrinfo_appinfo_filter_h filter; - - ret = pkgmgrinfo_appinfo_filter_create(&filter); - if (ret != PMINFO_R_OK) { - _SERR("Fail to create appinfo filter"); - return NI_ERROR_UNKNOWN; - } - - ret = pkgmgrinfo_appinfo_filter_add_string(filter, PMINFO_APPINFO_PROP_APP_TYPE, type); - if (ret != PMINFO_R_OK) { - pkgmgrinfo_appinfo_filter_destroy(filter); - _SERR("Fail to add appinfo filter (%s)", type); - return NI_ERROR_UNKNOWN; - } - - ret = pkgmgrinfo_appinfo_filter_foreach_appinfo(filter, appTypeListCb, NULL); - if (ret != PMINFO_R_OK) { - _SERR("Fail to pkgmgrinfo_pkginfo_filter_foreach_pkginfo"); - pkgmgrinfo_appinfo_filter_destroy(filter); - return NI_ERROR_UNKNOWN; - } - - pkgmgrinfo_appinfo_filter_destroy(filter); - - return NI_ERROR_NONE; -} - -void removeAllAppProfileData() -{ - std::vector appTypeList = {"dotnet", "dotnet-nui", "dotnet-inhouse"}; - - for (auto& type : appTypeList) { - if (removeAppProfileByAppType(type) != NI_ERROR_NONE) { - _SERR("Fail to removeAppProfileByAppType for type (%s)", type); - } - } -}