2 * Copyright (c) 2016 Samsung Electronics Co., Ltd All Rights Reserved
4 * Licensed under the Apache License, Version 2.0 (the License);
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an AS IS BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
17 #include <pkgmgr-info.h>
18 #include <pkgmgr_installer_info.h>
20 #include <tzplatform_config.h>
24 #include "pkgmgr_parser_plugin_interface.h"
43 #include "ni_common.h"
44 #include "db_manager.h"
45 #include "tac_common.h"
46 #include "path_manager.h"
47 #include "plugin_manager.h"
48 #include "r2r_checker.h"
53 #define LOG_TAG "DOTNET_INSTALLER_PLUGIN"
56 #error "CROSSGEN_PATH is missed"
60 #define __STR(x) __XSTR(x)
61 #if defined(__arm__) || defined(__aarch64__)
62 static const char* __NATIVE_LIB_DIR = __STR(NATIVE_LIB_DIR);
64 static const char* __CROSSGEN_PATH = __STR(CROSSGEN_PATH);
65 static const char* __DOTNET_DIR = __STR(DOTNET_DIR);
66 static const char* __READ_ONLY_APP_UPDATE_DIR = __STR(READ_ONLY_APP_UPDATE_DIR);
68 #ifdef UNIQUE_DEFAULT_BASE_ADDR_SUPPORT
69 static const char* __SYSTEM_BASE_FILE = __STR(SYSTEM_BASE_FILE);
75 static const char* CORERUN_CMD = "/usr/share/dotnet.tizen/netcoreapp/corerun";
76 static const char* CROSSGEN2_PATH = "/usr/share/dotnet.tizen/netcoreapp/crossgen2/crossgen2.dll";
77 static const char* CLRJIT_PATH = "/usr/share/dotnet.tizen/netcoreapp/libclrjit.so";
78 static const char* CROSSGEN_OPT_JITPATH = "--jitpath";
79 static const char* CROSSGEN_OPT_TARGET_ARCH = "--targetarch";
80 static const char* CROSSGEN_OPT_OUT_NEAR_INPUT = "--out-near-input";
81 static const char* CROSSGEN_OPT_SINGLE_FILE_COMPILATION = "--single-file-compilation";
82 //static const char* CROSSGEN_OPT_PARALLELISM = "--parallelism";
83 //static const char* CROSSGEN_OPT_PARALLELISM_COUNT = "5";
84 static const char* CROSSGEN_OPT_RESILIENT = "--resilient";
85 static const char* CROSSGEN_OPT_OPTIMIZE = "-O";
86 static const char* CROSSGEN_OPT_INPUTBUBBLE = "--inputbubble";
87 static const char* CROSSGEN_OPT_COMPILE_BUBBLE_GENERICS = "--compilebubblegenerics";
88 static const char* CROSSGEN_OPT_VERBOSE = "--verbose";
89 static const char* CROSSGEN_OPT_TUNING = "--tuning";
90 static std::vector<std::string> REF_VECTOR;
92 static int __interval = 0;
93 static PathManager* __pm = nullptr;
95 static bool isCoreLibPrepared(DWORD flags)
97 if (flags & NI_FLAGS_ENABLER2R) {
101 std::string coreLibBackup = concatPath(__pm->getRuntimePath(), "System.Private.CoreLib.dll.Backup");
102 if (isFile(coreLibBackup)) {
105 _SERR("The native image of System.Private.CoreLib does not exist\n"
106 "Run the command to create the native image\n"
107 "# dotnettool --ni-dll /usr/share/dotnet.tizen/netcoreapp/System.Private.CoreLib.dll\n");
112 static bool hasCoreLibNI()
114 std::string ildasm = concatPath(__pm->getRuntimePath(), "ildasm");
115 std::string coreLib = concatPath(__pm->getRuntimePath(), "System.Private.CoreLib.dll");
116 std::string cmd = ildasm + " " + coreLib + " -noil -stats | grep '.rsrc'";
119 fp = popen(cmd.c_str(), "r");
122 if (fgets(buff, sizeof(buff), fp) != NULL) {
131 static void waitInterval()
133 // by the recommand, ignore small value for performance.
134 if (__interval > 10000) {
135 _SOUT("sleep %d usec", __interval);
140 static std::string getNIFilePath(const std::string& dllPath)
142 size_t index = dllPath.find_last_of(".");
143 if (index == std::string::npos) {
144 _SERR("File doesnot contain extension. fail to get NI file name");
147 std::string fName = dllPath.substr(0, index);
148 std::string fExt = dllPath.substr(index, dllPath.length());
150 // crossgen generate file with lower case extension only
151 std::transform(fExt.begin(), fExt.end(), fExt.begin(), ::tolower);
152 std::string niPath = fName + ".ni" + fExt;
158 * @brief create the directory including parents directory, and
159 * copy ownership and smack labels to the created directory.
160 * @param[in] target directory path
161 * @param[in] source directory path to get ownership and smack label
162 * @return if directory created successfully, return true otherwise false
164 static bool createDirsAndCopyOwnerShip(std::string& target_path, const std::string& source)
167 mode_t mode = S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH;
169 for (std::string::iterator iter = target_path.begin(); iter != target_path.end();) {
170 std::string::iterator newIter = std::find(iter, target_path.end(), '/');
171 std::string newPath = std::string(target_path.begin(), newIter);
173 if (!newPath.empty()) {
174 if (stat(newPath.c_str(), &st) != 0) {
175 if (mkdir(newPath.c_str(), mode) != 0 && errno != EEXIST) {
176 _SERR("Fail to create app ni directory (%s)", newPath.c_str());
179 if (!source.empty()) {
180 copySmackAndOwnership(source, newPath);
183 if (!S_ISDIR(st.st_mode)) {
184 _SERR("Fail. path is not a dir (%s)", newPath.c_str());
190 if(newIter != target_path.end()) {
198 static std::string getAppNIFilePath(const std::string& absDllPath, DWORD flags)
200 std::string niDirPath;
201 std::string prevPath;
203 prevPath = getBaseName(absDllPath);
204 niDirPath = concatPath(prevPath, APP_NI_SUB_DIR);
206 if (flags & NI_FLAGS_APP_UNDER_RO_AREA) {
207 niDirPath = replaceAll(niDirPath, getBaseName(__pm->getAppRootPath()), __READ_ONLY_APP_UPDATE_DIR);
208 _SERR("App is installed in RO area. Change NI path to RW area(%s).", niDirPath.c_str());
209 _ERR("App is installed in RO area. Change NI path to RW area(%s).", niDirPath.c_str());
212 if (!isDirectory(niDirPath)) {
213 if (!createDirsAndCopyOwnerShip(niDirPath, prevPath)) {
214 niDirPath = prevPath;
215 _SERR("fail to create dir (%s)", niDirPath.c_str());
219 return getNIFilePath(concatPath(niDirPath, getFileName(absDllPath)));
222 static bool checkNIExistence(const std::string& absDllPath)
224 std::string absNIPath = getNIFilePath(absDllPath);
225 if (absNIPath.empty()) {
229 if (isFile(absNIPath)) {
233 // native image of System.Private.CoreLib.dll should have to overwrite
234 // original file to support new coreclr
235 if (absDllPath.find("System.Private.CoreLib.dll") != std::string::npos) {
236 if (hasCoreLibNI()) {
244 static bool checkDllExistInDir(const std::string& path)
247 auto func = [&ret](const std::string& f_path, const std::string& f_name) {
248 if (isManagedAssembly(f_name) || isNativeImage(f_name)) {
253 scanFilesInDirectory(path, func, 0);
259 * Get the list of managed files in the specific directory
260 * Absolute paths of managed files are stored at the result list.
261 * If native image already exist in the same directory, managed file is ignored.
263 * Note: System.Private.CoreLib is excluded from the result list.
265 static ni_error_e getTargetDllList(const std::string& path, std::vector<std::string>& fileList)
267 if (!isDirectory(path)) {
268 return NI_ERROR_INVALID_PARAMETER;
271 auto func = [&fileList](const std::string& f_path, const std::string& f_name) {
272 if (isManagedAssembly(f_path) && !checkNIExistence(f_path)) {
273 if (f_path.find("System.Private.CoreLib") == std::string::npos) {
274 fileList.push_back(getAbsolutePath(f_path));
279 scanFilesInDirectory(path, func, 0);
281 return NI_ERROR_NONE;
284 #ifdef UNIQUE_DEFAULT_BASE_ADDR_SUPPORT
285 static uintptr_t getFileSize(const std::string& path)
289 if (stat(path.c_str(), &sb) == 0) {
296 // Get next base address to be used for system ni image from file
297 // __SYSTEM_BASE_FILE should be checked for existance before calling this function
298 static uintptr_t getNextBaseAddrFromFile()
300 FILE *pFile = fopen(__SYSTEM_BASE_FILE, "r");
302 _SERR("Failed to open %s", __SYSTEM_BASE_FILE);
309 while (fscanf(pFile, "%" SCNxPTR " %" SCNuPTR "", &addr, &size) != EOF) {
317 // Get next base address to be used for system ni image
318 static uintptr_t getNextBaseAddr()
320 uintptr_t baseAddr = 0;
322 if (!isFile(__SYSTEM_BASE_FILE)) {
323 // This is the starting address for all default base addresses
324 baseAddr = DEFAULT_BASE_ADDR_START;
326 baseAddr = getNextBaseAddrFromFile();
328 // Round to a multple of 64K (see ZapImage::CalculateZapBaseAddress in CoreCLR)
329 uintptr_t BASE_ADDRESS_ALIGNMENT = 0xffff;
330 baseAddr = (baseAddr + BASE_ADDRESS_ALIGNMENT) & ~BASE_ADDRESS_ALIGNMENT;
336 // Save base address of system ni image to file
337 static void updateBaseAddrFile(const std::string& absNIPath, uintptr_t baseAddr)
339 uintptr_t niSize = getFileSize(absNIPath);
341 _SERR("File %s doesn't exist", absNIPath.c_str());
345 // Write new entry to the file
346 FILE *pFile = fopen(__SYSTEM_BASE_FILE, "a");
348 _SERR("Failed to open %s", __SYSTEM_BASE_FILE);
352 fprintf(pFile, "%" PRIxPTR " %" PRIuPTR "\n", baseAddr, niSize);
356 // check if dll is listed in TPA
357 static bool isTPADll(const std::string& dllPath)
359 std::string absPath = getBaseName(getAbsolutePath(dllPath));
361 std::vector<std::string> paths = __pm->getPlatformAssembliesPaths();
362 for (unsigned int i = 0; i < paths.size(); i++) {
363 if (paths[i].find(getBaseName(absPath)) != std::string::npos) {
372 // baseAddr should be checked in file before getting here
373 static ni_error_e crossgen(const std::string& dllPath, const std::string& appPath, DWORD flags)
375 std::string absDllPath = getAbsolutePath(dllPath);
376 std::string absNIPath;
378 bool isAppNI = flags & NI_FLAGS_APPNI;
379 if (isAppNI && strstr(absDllPath.c_str(), __DOTNET_DIR) == NULL) {
380 absNIPath = getAppNIFilePath(absDllPath, flags);
381 if (exist(absNIPath)) {
382 return NI_ERROR_ALREADY_EXIST;
385 absNIPath = getNIFilePath(absDllPath);
386 if (checkNIExistence(absDllPath)) {
387 return NI_ERROR_ALREADY_EXIST;
391 if (absNIPath.empty()) {
392 _SERR("Fail to get ni file name");
393 return NI_ERROR_UNKNOWN;
396 #ifdef UNIQUE_DEFAULT_BASE_ADDR_SUPPORT
397 uintptr_t baseAddr = 0;
399 if (isTPADll(dllPath)) {
400 baseAddr = getNextBaseAddr();
406 return NI_ERROR_UNKNOWN;
410 waitpid(pid, &status, 0);
411 if (WIFEXITED(status)) {
412 // Do not use checkNIExistence() function to check whether ni file created or not.
413 // checkNIExistence() return false for System.Private.Corelib.dll
414 if (isFile(absNIPath)) {
415 copySmackAndOwnership(absDllPath, absNIPath);
416 std::string absPdbPath = replaceAll(absDllPath, ".dll", ".pdb");
417 std::string pdbFilePath = replaceAll(absNIPath, ".ni.dll", ".pdb");
418 if (isFile(absPdbPath) && (absPdbPath != pdbFilePath)) {
419 if (!copyFile(absPdbPath, pdbFilePath)) {
420 _SERR("Failed to copy a .pdb file");
422 copySmackAndOwnership(absPdbPath, pdbFilePath);
425 #ifdef UNIQUE_DEFAULT_BASE_ADDR_SUPPORT
427 updateBaseAddrFile(absNIPath, baseAddr);
430 return NI_ERROR_NONE;
432 _SERR("Fail to create native image for %s", dllPath.c_str());
433 return NI_ERROR_NO_SUCH_FILE;
437 std::string jitPath = __pm->getRuntimePath() + "/libclrjit.so";
438 std::vector<const char*> argv = {
441 "/JITPath", jitPath.c_str()
444 bool compat = flags & NI_FLAGS_COMPATIBILITY;
445 argv.push_back(compat ? "/Platform_Assemblies_Pathes" : "/p");
446 std::vector<std::string> paths = __pm->getPlatformAssembliesPaths();
447 std::string platformAssembliesPaths;
448 for (const auto &path : paths) {
449 if (!platformAssembliesPaths.empty()) {
450 platformAssembliesPaths += ":";
452 platformAssembliesPaths += path;
454 argv.push_back(platformAssembliesPaths.c_str());
456 bool enableR2R = flags & NI_FLAGS_ENABLER2R;
458 argv.push_back("/FragileNonVersionable");
461 if (flags & NI_FLAGS_VERBOSE) {
462 argv.push_back("/verbose");
465 if (flags & NI_FLAGS_INSTRUMENT) {
466 argv.push_back("/Tuning");
469 #ifdef UNIQUE_DEFAULT_BASE_ADDR_SUPPORT
470 std::string baseAddrString;
472 argv.push_back("/BaseAddress");
473 std::stringstream ss;
474 ss << "0x" << std::hex << baseAddr;
475 baseAddrString = ss.str();
476 argv.push_back(baseAddrString.c_str());
480 argv.push_back("/App_Paths");
481 std::string absAppPath;
482 if (!appPath.empty()) {
483 absAppPath = appPath;
485 absAppPath = getBaseName(absDllPath);
487 argv.push_back(absAppPath.c_str());
489 argv.push_back("/out");
490 argv.push_back(absNIPath.c_str());
492 argv.push_back(absDllPath.c_str());
493 argv.push_back(nullptr);
495 _SOUT("+ %s (%s)", absDllPath.c_str(), enableR2R ? "R2R" : "FNV");
497 execv(__CROSSGEN_PATH, const_cast<char* const*>(argv.data()));
501 return NI_ERROR_NONE;
504 static void makeArgs(std::vector<const char*>& args, const std::vector<std::string>& refPaths, DWORD flags)
506 args.push_back(CORERUN_CMD);
507 args.push_back(CROSSGEN2_PATH);
508 args.push_back(CROSSGEN_OPT_JITPATH);
509 args.push_back(CLRJIT_PATH);
510 args.push_back(CROSSGEN_OPT_TARGET_ARCH);
511 args.push_back(ARCHITECTURE_IDENTIFIER);
512 if (!(flags & NI_FLAGS_NO_PIPELINE)) {
513 args.push_back(CROSSGEN_OPT_OUT_NEAR_INPUT);
514 args.push_back(CROSSGEN_OPT_SINGLE_FILE_COMPILATION);
516 //args.push_back(OPT_PARALLELISM);
517 //args.push_back(OPT_PARALLELISM_COUNT);
518 args.push_back(CROSSGEN_OPT_RESILIENT);
520 args.push_back(CROSSGEN_OPT_OPTIMIZE);
522 if (flags & NI_FLAGS_INPUT_BUBBLE) {
523 args.push_back(CROSSGEN_OPT_INPUTBUBBLE);
524 args.push_back(CROSSGEN_OPT_COMPILE_BUBBLE_GENERICS);
527 if (flags & NI_FLAGS_VERBOSE) {
528 args.push_back(CROSSGEN_OPT_VERBOSE);
531 if (flags & NI_FLAGS_INSTRUMENT) {
532 args.push_back(CROSSGEN_OPT_TUNING);
537 // set reference path
538 std::vector<std::string> paths = __pm->getPlatformAssembliesPaths();
539 for (const auto &path : paths) {
540 REF_VECTOR.push_back("-r:" + path + "/*.dll");
543 for (const auto &path : refPaths) {
544 if (checkDllExistInDir(path)) {
545 REF_VECTOR.push_back("-r:" + path + "/*.dll");
549 for (const auto &path : REF_VECTOR) {
550 args.push_back(path.c_str());
554 static void clearArgs(std::vector<const char*>& args)
560 static ni_error_e makePdbSymlinkForNI(std::string dllPath, std::string niPath)
562 std::string pdbPath = changeExtension(dllPath, ".dll", ".pdb");
564 if (exist(pdbPath)) {
565 std::string targetPDBPath = changeExtension(niPath, ".ni.dll", ".pdb");
566 if (!exist(targetPDBPath)) {
567 bf::create_symlink(pdbPath, targetPDBPath);
568 copySmackAndOwnership(pdbPath, targetPDBPath, true);
571 } catch (const bf::filesystem_error& error) {
572 _SERR("Fail to create symlink for %s", pdbPath.c_str());
573 return NI_ERROR_UNKNOWN;
576 return NI_ERROR_NONE;
579 static ni_error_e crossgen2PipeLine(const std::vector<std::string>& dllList, const std::vector<std::string>& refPaths, DWORD flags)
584 return NI_ERROR_UNKNOWN;
588 waitpid(pid, &status, 0);
589 if (WIFEXITED(status)) {
590 for (auto& dllPath: dllList) {
591 std::string niPath = changeExtension(dllPath, ".dll", ".ni.dll");
593 if (!exist(niPath)) {
594 _SERR("Fail to create native image for %s", dllPath.c_str());
595 return NI_ERROR_NO_SUCH_FILE;
598 copySmackAndOwnership(dllPath, niPath);
599 // if AppNI then move ni.dll file to .native_image and copy pdb to .native_image
600 if (flags & NI_FLAGS_APPNI) {
601 std::string appNIPath = getAppNIFilePath(dllPath, flags);
602 moveFile(niPath, appNIPath);
603 makePdbSymlinkForNI(dllPath, appNIPath);
606 _SOUT("Native image %s generated successfully.", niPath.c_str());
610 std::vector<const char*> argv;
612 makeArgs(argv, refPaths, flags);
614 // add input files at the end of parameter
615 for (const auto &input : dllList) {
616 argv.push_back(input.c_str());
617 _SOUT("+ %s", input.c_str());
620 argv.push_back(nullptr);
623 //for (auto &arg: argv) _SOUT("+ %s", arg);
625 execv(CORERUN_CMD, const_cast<char* const*>(argv.data()));
631 return NI_ERROR_NONE;
634 static ni_error_e crossgen2NoPipeLine(const std::vector<std::string>& dllList, const std::vector<std::string>& refPaths, DWORD flags)
636 for (auto& dllPath : dllList) {
638 if (flags & NI_FLAGS_APPNI) {
639 niPath = getAppNIFilePath(dllPath, flags);
641 niPath = getNIFilePath(dllPath);
647 return NI_ERROR_UNKNOWN;
651 waitpid(pid, &status, 0);
652 if (WIFEXITED(status)) {
653 if (!exist(niPath)) {
654 _SERR("Fail to create native image for %s", dllPath.c_str());
655 return NI_ERROR_NO_SUCH_FILE;
658 copySmackAndOwnership(dllPath, niPath);
659 if (flags & NI_FLAGS_APPNI) {
660 makePdbSymlinkForNI(dllPath, niPath);
662 _SOUT("Native image %s generated successfully.", niPath.c_str());
665 std::vector<const char*> argv;
666 makeArgs(argv, refPaths, flags);
668 argv.push_back("-o");
669 argv.push_back(niPath.c_str());
671 argv.push_back(dllPath.c_str());
672 _SOUT("+ %s", dllPath.c_str());
675 argv.push_back(nullptr);
678 //for (auto &arg: argv) _SOUT("+ %s", arg);
680 execv(CORERUN_CMD, const_cast<char* const*>(argv.data()));
689 return NI_ERROR_NONE;
693 static ni_error_e doAOTList(std::vector<std::string>& dllList, const std::string& refPaths, DWORD flags)
695 if (dllList.empty()) {
696 return NI_ERROR_INVALID_PARAMETER;
698 // When performing AOT for one Dll, an error is returned when an error occurs.
699 // However, when processing multiple dlls at once, only the log for errors is output and skipped.
701 for (auto it = dllList.begin(); it != dllList.end(); it++) {
704 _SERR("dll file is not exist : %s", f.c_str());
707 if (!isManagedAssembly(f)) {
708 _SERR("Input file is not a dll file : %s", f.c_str());
713 if (!isFile(concatPath(__pm->getRuntimePath(), "crossgen"))) {
714 _SERR("crossgen1 doesnot supported. use crossgen2 forcibily");
715 flags |= NI_FLAGS_USE_CROSSGEN2;
718 if (flags & NI_FLAGS_USE_CROSSGEN2) { // crossgen2
719 std::vector<std::string> paths;
720 splitPath(refPaths, paths);
722 if (flags & NI_FLAGS_NO_PIPELINE) {
723 crossgen2NoPipeLine(dllList, paths, flags);
725 crossgen2PipeLine(dllList, paths, flags);
727 } else { // crossgen1
728 for (auto& dll : dllList) {
729 crossgen(dll, refPaths, flags);
734 return NI_ERROR_NONE;
737 static ni_error_e doAOTFile(const std::string& dllFile, const std::string& refPaths, DWORD flags)
739 if (!isFile(dllFile)) {
740 _SERR("dll file is not exist : %s", dllFile.c_str());
741 return NI_ERROR_NO_SUCH_FILE;
744 if (!isManagedAssembly(dllFile)) {
745 _SERR("Failed. Input parameter is not managed dll (%s)\n", dllFile.c_str());
746 return NI_ERROR_INVALID_PARAMETER;
749 std::vector<std::string> dllList;
750 dllList.push_back(getAbsolutePath(dllFile));
751 return doAOTList(dllList, refPaths, flags);
754 // callback function of "pkgmgrinfo_appinfo_metadata_filter_foreach"
755 static int appAotCb(pkgmgrinfo_appinfo_h handle, void *userData)
759 DWORD *pFlags = (DWORD*)userData;
761 ret = pkgmgrinfo_appinfo_get_pkgid(handle, &pkgId);
762 if (ret != PMINFO_R_OK) {
763 _SERR("Failed to get pkgid");
767 if (removeNIUnderPkgRoot(pkgId) != NI_ERROR_NONE) {
768 _SERR("Failed to remove previous dlls from [%s]", pkgId);
772 if (createNIUnderPkgRoot(pkgId, *pFlags) != NI_ERROR_NONE) {
773 _SERR("Failed to generate NI file [%s]", pkgId);
776 _SOUT("Complete make application to native image");
782 static ni_error_e createCoreLibNI(DWORD flags)
784 std::string coreLib = concatPath(__pm->getRuntimePath(), "System.Private.CoreLib.dll");
785 std::string niCoreLib = concatPath(__pm->getRuntimePath(), "System.Private.CoreLib.ni.dll");
786 std::string coreLibBackup = concatPath(__pm->getRuntimePath(), "System.Private.CoreLib.dll.Backup");
788 if (!isFile(coreLibBackup) && !hasCoreLibNI()) {
789 if (doAOTFile(coreLib, std::string(), flags) == NI_ERROR_NONE) {
790 if (rename(coreLib.c_str(), coreLibBackup.c_str())) {
791 _SERR("Failed to rename System.Private.CoreLib.dll");
792 return NI_ERROR_CORE_NI_FILE;
794 if (rename(niCoreLib.c_str(), coreLib.c_str())) {
795 _SERR("Failed to rename System.Private.CoreLib.ni.dll");
796 return NI_ERROR_CORE_NI_FILE;
799 _SERR("Failed to create native image for %s", coreLib.c_str());
800 return NI_ERROR_CORE_NI_FILE;
803 return NI_ERROR_NONE;
806 ni_error_e initNICommon()
808 #if defined(__arm__) || defined(__aarch64__)
809 // get interval value
810 const static std::string intervalFile = concatPath(__NATIVE_LIB_DIR, "crossgen_interval.txt");
811 std::ifstream inFile(intervalFile);
813 _SOUT("crossgen_interval.txt is found");
814 inFile >> __interval;
817 if (initializePluginManager("normal")) {
818 _SERR("Fail to initialize PluginManager");
819 return NI_ERROR_UNKNOWN;
823 __pm = new PathManager();
824 } catch (const std::exception& e) {
825 _SERR("Failed to create PathManager");
826 return NI_ERROR_UNKNOWN;
829 char* pluginDllPaths = pluginGetDllPath();
830 if (pluginDllPaths && pluginDllPaths[0] != '\0') {
831 __pm->addPlatformAssembliesPaths(pluginDllPaths, true);
834 char* pluginNativePaths = pluginGetNativeDllSearchingPath();
835 if (pluginNativePaths && pluginNativePaths[0] != '\0') {
836 __pm->addNativeDllSearchingPaths(pluginNativePaths, true);
839 return NI_ERROR_NONE;
841 _SERR("crossgen supports arm/arm64 architecture only. skip ni file generation");
842 return NI_ERROR_NOT_SUPPORTED;
846 void finalizeNICommon()
850 finalizePluginManager();
856 ni_error_e createNIPlatform(DWORD flags)
858 ni_error_e ret = createCoreLibNI(flags);
859 if (ret != NI_ERROR_NONE) {
863 return createNIUnderDirs(__pm->getRuntimePath() + ":" + __pm->getTizenFXPath(), flags);
866 ni_error_e createNIDll(const std::string& dllPath, DWORD flags)
868 if (dllPath.find("System.Private.CoreLib.dll") != std::string::npos) {
869 return createCoreLibNI(flags);
872 if (!isCoreLibPrepared(flags)) {
873 return NI_ERROR_CORE_NI_FILE;
876 return doAOTFile(dllPath, std::string(), flags);
879 ni_error_e createNIUnderTAC(const std::string& targetPath, const std::string& refPaths, DWORD flags)
883 // get managed file list from targetPath
884 std::vector<std::string> dllList;
885 ret = getTargetDllList(targetPath, dllList);
886 if (ret != NI_ERROR_NONE) {
890 std::vector<std::string> needNIList;
891 std::vector<std::string> niList;
893 for (auto &dll : dllList) {
894 if (!checkNIExistence(dll)) {
895 needNIList.push_back(dll);
897 niList.push_back(getNIFilePath(dll));
900 if (!needNIList.empty()) {
901 // NI fils of TAC-related dlls under /opt/usr/dotnet should not be created under .native_image directory.
902 // So, unset NI_FLAGS_APPNI temporally and restore it after running AOT.
903 flags &= ~NI_FLAGS_APPNI;
904 ret = doAOTList(needNIList, refPaths, flags);
905 flags |= NI_FLAGS_APPNI;
906 if (ret != NI_ERROR_NONE) {
911 for (auto &niPath : niList) {
913 std::string symNIPath = concatPath(targetPath, getFileName(niPath));
914 if (!exist(symNIPath)) {
915 bf::create_symlink(niPath, symNIPath);
916 copySmackAndOwnership(targetPath.c_str(), symNIPath.c_str(), true);
917 _SOUT("%s symbolic link file generated successfully.", symNIPath.c_str());
918 _INFO("%s symbolic link file generated successfully.", symNIPath.c_str());
923 return NI_ERROR_NONE;
927 ni_error_e createNIUnderDirs(const std::string& rootPaths, DWORD flags)
929 ni_error_e ret = NI_ERROR_NONE;
930 if (!isCoreLibPrepared(flags)) {
931 return NI_ERROR_CORE_NI_FILE;
934 std::vector<std::string> fileList;
935 std::vector<std::string> paths;
936 splitPath(rootPaths, paths);
938 for (const auto &path : paths) {
943 if (path.find(TAC_SYMLINK_SUB_DIR) != std::string::npos) {
944 ret = createNIUnderTAC(path, rootPaths, flags);
945 if (ret != NI_ERROR_NONE) {
949 ret = getTargetDllList(path, fileList);
950 if (ret != NI_ERROR_NONE) {
956 if (fileList.empty()) {
957 return NI_ERROR_NONE;
960 return doAOTList(fileList, rootPaths, flags);
963 ni_error_e createNIUnderPkgRoot(const std::string& pkgId, DWORD flags)
965 std::string rootPath = getRootPath(pkgId);
966 if (rootPath.empty()) {
967 _SERR("Failed to get root path from [%s]", pkgId.c_str());
968 return NI_ERROR_INVALID_PACKAGE;
971 __pm->setAppRootPath(rootPath);
973 flags |= NI_FLAGS_APPNI;
975 if (isReadOnlyArea(rootPath)) {
976 flags |= NI_FLAGS_APP_UNDER_RO_AREA;
977 flags |= NI_FLAGS_NO_PIPELINE;
978 _SERR("Only no-pipeline mode supported for RO app. Set no-pipeline option forcibly");
980 flags &= ~NI_FLAGS_APP_UNDER_RO_AREA;
983 // create native image under bin and lib directory
984 // tac directory is skipped in the createNIUnderDirs.
985 return createNIUnderDirs(__pm->getAppPaths(), flags);
988 void removeNIPlatform()
990 std::string coreLib = concatPath(__pm->getRuntimePath(), "System.Private.CoreLib.dll");
991 std::string coreLibBackup = concatPath(__pm->getRuntimePath(), "System.Private.CoreLib.dll.Backup");
993 if (hasCoreLibNI()) {
994 if (!isFile(coreLibBackup)) {
998 if (remove(coreLib.c_str())) {
999 _SERR("Failed to remove System.Private.CoreLib native image file");
1001 if (rename(coreLibBackup.c_str(), coreLib.c_str())) {
1002 _SERR("Failed to rename System.Private.CoreLib.Backup to origin");
1006 #ifdef UNIQUE_DEFAULT_BASE_ADDR_SUPPORT
1007 if (isFile(__SYSTEM_BASE_FILE)) {
1008 if (remove(__SYSTEM_BASE_FILE)) {
1009 _SERR("Failed to remove %s", __SYSTEM_BASE_FILE);
1014 removeNIUnderDirs(__pm->getRuntimePath() + ":" + __pm->getTizenFXPath());
1017 void removeNIUnderDirs(const std::string& rootPaths)
1019 auto convert = [](const std::string& path, const std::string& filename) {
1020 if (isNativeImage(path)) {
1021 if (remove(path.c_str())) {
1022 _SERR("Failed to remove %s", path.c_str());
1027 std::vector<std::string> paths;
1028 splitPath(rootPaths, paths);
1029 for (const auto &path : paths) {
1030 scanFilesInDirectory(path, convert, -1);
1034 ni_error_e removeNIUnderPkgRoot(const std::string& pkgId)
1036 std::string rootPath = getRootPath(pkgId);
1037 if (rootPath.empty()) {
1038 _SERR("Failed to get root path from [%s]", pkgId.c_str());
1039 return NI_ERROR_INVALID_PACKAGE;
1042 __pm->setAppRootPath(rootPath);
1044 // getAppNIPaths returns bin/.native_image, lib/.native_image and .tac_symlink.
1045 std::string appNIPaths = __pm->getAppNIPaths();
1046 std::vector<std::string> paths;
1047 splitPath(appNIPaths, paths);
1048 for (const auto &path : paths) {
1049 if (!isReadOnlyArea(path)) {
1050 // Only the native image inside the TAC should be removed.
1051 if (strstr(path.c_str(), TAC_SYMLINK_SUB_DIR) != NULL) {
1052 removeNIUnderDirs(path);
1054 if (isDirectory(path)) {
1055 if (!removeAll(path.c_str())) {
1056 _SERR("Failed to remove app ni dir [%s]", path.c_str());
1063 // In special cases, the ni file may exist in the dll location.
1064 // The code below is to avoid this exceptional case.
1065 std::string appPaths = __pm->getAppPaths();
1066 splitPath(appPaths, paths);
1067 for (const auto &path : paths) {
1068 if (isDirectory(path)) {
1069 removeNIUnderDirs(path);
1073 return NI_ERROR_NONE;
1076 ni_error_e regenerateAppNI(DWORD flags)
1078 if (!isCoreLibPrepared(flags)) {
1079 return NI_ERROR_CORE_NI_FILE;
1083 pkgmgrinfo_appinfo_metadata_filter_h handle;
1085 ret = pkgmgrinfo_appinfo_metadata_filter_create(&handle);
1086 if (ret != PMINFO_R_OK)
1087 return NI_ERROR_UNKNOWN;
1089 ret = pkgmgrinfo_appinfo_metadata_filter_add(handle, AOT_METADATA_KEY, METADATA_VALUE);
1090 if (ret != PMINFO_R_OK) {
1091 pkgmgrinfo_appinfo_metadata_filter_destroy(handle);
1092 return NI_ERROR_UNKNOWN;
1095 ret = pkgmgrMDFilterForeach(handle, appAotCb, &flags);
1097 pkgmgrinfo_appinfo_metadata_filter_destroy(handle);
1098 return NI_ERROR_UNKNOWN;
1101 pkgmgrinfo_appinfo_metadata_filter_destroy(handle);
1102 return NI_ERROR_NONE;
1105 // callback function of "pkgmgrinfo_appinfo_metadata_filter_foreach"
1106 static int regenTacCb(pkgmgrinfo_appinfo_h handle, void *userData)
1109 DWORD *pFlags = (DWORD*)userData;
1111 int ret = pkgmgrinfo_appinfo_get_pkgid(handle, &pkgId);
1112 if (ret != PMINFO_R_OK || pkgId == NULL) {
1113 _SERR("Failed to get pkgid");
1117 sqlite3 *tac_db = openDB(TAC_APP_LIST_DB);
1119 _SERR("Sqlite open error");
1122 sqlite3_exec(tac_db, "BEGIN;", NULL, NULL, NULL);
1124 char *sql = sqlite3_mprintf("SELECT * FROM TAC WHERE PKGID = %Q;", pkgId);
1125 std::vector<std::string> nugets = selectDB(tac_db, sql);
1133 std::string nugetPaths;
1134 for (const auto &nuget : nugets) {
1135 if (!nugetPaths.empty()) {
1138 nugetPaths += concatPath(__DOTNET_DIR, nuget);
1141 for (auto& nuget : nugets) {
1142 createNIUnderTAC(concatPath(__DOTNET_DIR, nuget), nugetPaths, *pFlags);
1148 ni_error_e regenerateTACNI(DWORD flags)
1150 if (!isCoreLibPrepared(flags)) {
1151 return NI_ERROR_CORE_NI_FILE;
1154 removeNIUnderDirs(__DOTNET_DIR);
1156 pkgmgrinfo_appinfo_metadata_filter_h handle;
1157 int ret = pkgmgrinfo_appinfo_metadata_filter_create(&handle);
1158 if (ret != PMINFO_R_OK) {
1159 return NI_ERROR_UNKNOWN;
1162 ret = pkgmgrinfo_appinfo_metadata_filter_add(handle, TAC_METADATA_KEY, METADATA_VALUE);
1163 if (ret != PMINFO_R_OK) {
1164 pkgmgrinfo_appinfo_metadata_filter_destroy(handle);
1165 return NI_ERROR_UNKNOWN;
1168 ret = pkgmgrMDFilterForeach(handle, regenTacCb, &flags);
1170 pkgmgrinfo_appinfo_metadata_filter_destroy(handle);
1171 return NI_ERROR_UNKNOWN;
1174 pkgmgrinfo_appinfo_metadata_filter_destroy(handle);
1176 return NI_ERROR_NONE;
1179 static std::vector<uid_t> getUserIds()
1181 std::vector<uid_t> list;
1184 errno = 0; // so we can distinguish errors from no more entries
1185 passwd* entry = getpwent();
1188 _SERR("Error while getting userIDs");
1194 list.push_back(entry->pw_uid);
1201 static std::string getAppDataPath(const std::string& pkgId, uid_t uid)
1203 std::string pDataFile;
1205 tzplatform_set_user(uid);
1207 const char* tzUserApp = tzplatform_getenv(TZ_USER_APP);
1208 if (tzUserApp != NULL) {
1209 pDataFile = std::string(tzUserApp) + "/" + pkgId + "/data/";
1212 tzplatform_reset_user();
1217 ni_error_e removeAppProfileData(const std::string& pkgId)
1219 if (pkgId.empty()) {
1220 return NI_ERROR_INVALID_PARAMETER;
1223 std::vector<uid_t> uidList = getUserIds();
1224 for (auto& uid : uidList) {
1225 // get data path from pkgid
1226 std::string dataPath = getAppDataPath(pkgId, uid);
1227 if (!dataPath.empty() && exist(dataPath)) {
1228 std::string pDataFile = dataPath + PROFILE_BASENAME;
1230 if (exist(pDataFile)) {
1231 if (!removeFile(pDataFile)) {
1232 _SERR("Fail to remove profile data file (%s).", pDataFile.c_str());
1233 return NI_ERROR_UNKNOWN;
1235 _SOUT("Profile data (%s) is removed successfully", pDataFile.c_str());
1240 return NI_ERROR_NONE;
1243 static int appTypeListCb(pkgmgrinfo_appinfo_h handle, void *user_data)
1246 int ret = pkgmgrinfo_appinfo_get_pkgid(handle, &pkgId);
1247 if (ret != PMINFO_R_OK || pkgId == NULL) {
1248 _SERR("Fail to get pkgid");
1252 if (removeAppProfileData(pkgId) != NI_ERROR_NONE) {
1253 _SERR("Fail to remove profile data for (%s)", pkgId);
1259 static ni_error_e removeAppProfileByAppType(const char* type)
1263 pkgmgrinfo_appinfo_filter_h filter;
1265 ret = pkgmgrinfo_appinfo_filter_create(&filter);
1266 if (ret != PMINFO_R_OK) {
1267 _SERR("Fail to create appinfo filter");
1268 return NI_ERROR_UNKNOWN;
1271 ret = pkgmgrinfo_appinfo_filter_add_string(filter, PMINFO_APPINFO_PROP_APP_TYPE, type);
1272 if (ret != PMINFO_R_OK) {
1273 pkgmgrinfo_appinfo_filter_destroy(filter);
1274 _SERR("Fail to add appinfo filter (%s)", type);
1275 return NI_ERROR_UNKNOWN;
1278 ret = pkgmgrinfo_appinfo_filter_foreach_appinfo(filter, appTypeListCb, NULL);
1279 if (ret != PMINFO_R_OK) {
1280 _SERR("Fail to pkgmgrinfo_pkginfo_filter_foreach_pkginfo");
1281 pkgmgrinfo_appinfo_filter_destroy(filter);
1282 return NI_ERROR_UNKNOWN;
1285 pkgmgrinfo_appinfo_filter_destroy(filter);
1287 return NI_ERROR_NONE;
1290 void removeAllAppProfileData()
1292 std::vector<const char*> appTypeList = {"dotnet", "dotnet-nui", "dotnet-inhouse"};
1294 for (auto& type : appTypeList) {
1295 if (removeAppProfileByAppType(type) != NI_ERROR_NONE) {
1296 _SERR("Fail to removeAppProfileByAppType for type (%s)", type);