Support PBA on aarch64
[platform/core/dotnet/launcher.git] / NativeLauncher / tool / ni_common.cc
1 /*
2  * Copyright (c) 2016 Samsung Electronics Co., Ltd All Rights Reserved
3  *
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
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  */
16
17 #include <pkgmgr-info.h>
18 #include <pkgmgr_installer_info.h>
19 #include <aul.h>
20
21 #include "log.h"
22 #include "utils.h"
23 #include "pkgmgr_parser_plugin_interface.h"
24
25 #include <wait.h>
26 #include <dirent.h>
27 #include <sys/stat.h>
28
29 #include <algorithm>
30 #include <string>
31 #include <fstream>
32 #include <sstream>
33
34 #include <pwd.h>
35 #include <grp.h>
36 #include <unistd.h>
37 #include <string.h>
38 #include <sqlite3.h>
39 #include <inttypes.h>
40
41 #include "ni_common.h"
42 #include "db_manager.h"
43 #include "tac_common.h"
44 #include "path_manager.h"
45 #include "plugin_manager.h"
46
47 #ifdef  LOG_TAG
48 #undef  LOG_TAG
49 #endif
50 #define LOG_TAG "DOTNET_INSTALLER_PLUGIN"
51
52 #ifndef CROSSGEN_PATH
53 #error "CROSSGEN_PATH is missed"
54 #endif
55
56 #define __XSTR(x) #x
57 #define __STR(x) __XSTR(x)
58 static const char* __NATIVE_LIB_DIR = __STR(NATIVE_LIB_DIR);
59 static const char* __CROSSGEN_PATH = __STR(CROSSGEN_PATH);
60 static const char* __DOTNET_DIR = __STR(DOTNET_DIR);
61
62 #ifdef UNIQUE_DEFAULT_BASE_ADDR_SUPPORT
63 static const char* __SYSTEM_BASE_FILE = __STR(SYSTEM_BASE_FILE);
64 #endif
65
66 #undef __STR
67 #undef __XSTR
68
69 static int __interval = 0;
70 static PathManager* __pm = nullptr;
71
72 static void waitInterval()
73 {
74         // by the recommand, ignore small value for performance.
75         if (__interval > 10000) {
76                 fprintf(stdout, "sleep %d usec\n", __interval);
77                 usleep(__interval);
78         }
79 }
80
81 static std::string getNIFilePath(const std::string& dllPath)
82 {
83         size_t index = dllPath.find_last_of(".");
84         if (index == std::string::npos) {
85                 fprintf(stderr, "File doesnot contain extension. fail to get NI file name\n");
86                 return "";
87         }
88         std::string fName = dllPath.substr(0, index);
89         std::string fExt = dllPath.substr(index, dllPath.length());
90
91         // crossgen generate file with lower case extension only
92         std::transform(fExt.begin(), fExt.end(), fExt.begin(), ::tolower);
93         std::string niPath = fName + ".ni" + fExt;
94
95         return niPath;
96 }
97
98 static std::string getAppNIFilePath(const std::string& niPath)
99 {
100         std::string fileName;
101         std::string niDirPath;
102         std::string prevPath;
103
104         size_t index = niPath.find_last_of("/");
105         if (index != std::string::npos) {
106                 prevPath = niPath.substr(0, index);
107                 fileName = niPath.substr(index + 1, niPath.length());
108         } else {
109                 prevPath = ".";
110                 fileName = niPath;
111         }
112
113         niDirPath = concatPath(prevPath, APP_NI_SUB_DIR);
114
115         if (!isFile(niDirPath)) {
116                 if (mkdir(niDirPath.c_str(), 0755) == 0) {
117                         copySmackAndOwnership(prevPath, niDirPath);
118                 } else {
119                         fprintf(stderr, "Fail to create app ni directory (%s)\n", niDirPath.c_str());
120                 }
121         }
122
123         return concatPath(niDirPath, fileName);
124 }
125
126 static bool checkNIExistence(const std::string& path)
127 {
128         std::string f = getNIFilePath(path);
129         if (f.empty()) {
130                 return false;
131         }
132
133         if (isFile(f)) {
134                 return true;
135         }
136
137         // native image of System.Private.CoreLib.dll should have to overwrite
138         // original file to support new coreclr
139         if (path.find("System.Private.CoreLib.dll") != std::string::npos) {
140                 std::string coreLibBackup = path + ".Backup";
141                 if (isFile(coreLibBackup)) {
142                         return true;
143                 }
144         }
145
146         return false;
147 }
148
149 #ifdef UNIQUE_DEFAULT_BASE_ADDR_SUPPORT
150 static uintptr_t getFileSize(const std::string& path)
151 {
152         struct stat sb;
153
154         if (stat(path.c_str(), &sb) == 0) {
155                 return sb.st_size;
156         }
157
158         return 0;
159 }
160
161 // Get next base address to be used for system ni image from file
162 // __SYSTEM_BASE_FILE should be checked for existance before calling this function
163 static uintptr_t getNextBaseAddrFromFile()
164 {
165         FILE *pFile = fopen(__SYSTEM_BASE_FILE, "r");
166         if (pFile == NULL) {
167                 fprintf(stderr, "Failed to open %s\n", __SYSTEM_BASE_FILE);
168                 return 0;
169         }
170
171         uintptr_t addr = 0;
172         uintptr_t size = 0;
173
174         while (fscanf(pFile, "%" SCNxPTR " %" SCNuPTR "", &addr, &size) != EOF) {
175         }
176
177         fclose(pFile);
178
179         return addr + size;
180 }
181
182 // Get next base address to be used for system ni image
183 static uintptr_t getNextBaseAddr()
184 {
185         uintptr_t baseAddr = 0;
186
187         if (!isFile(__SYSTEM_BASE_FILE)) {
188                 // This is the starting address for all default base addresses
189                 baseAddr = DEFAULT_BASE_ADDR_START;
190         } else {
191                 baseAddr = getNextBaseAddrFromFile();
192
193                 // Round to a multple of 64K (see ZapImage::CalculateZapBaseAddress in CoreCLR)
194                 uintptr_t BASE_ADDRESS_ALIGNMENT = 0xffff;
195                 baseAddr = (baseAddr + BASE_ADDRESS_ALIGNMENT) & ~BASE_ADDRESS_ALIGNMENT;
196         }
197
198         return baseAddr;
199 }
200
201 // Save base address of system ni image to file
202 static void updateBaseAddrFile(const std::string& absNIPath, uintptr_t baseAddr)
203 {
204         uintptr_t niSize = getFileSize(absNIPath);
205         if (niSize == 0) {
206                 fprintf(stderr, "File %s doesn't exist\n", absNIPath.c_str());
207                 return;
208         }
209
210         // Write new entry to the file
211         FILE *pFile = fopen(__SYSTEM_BASE_FILE, "a");
212         if (pFile == NULL) {
213                 fprintf(stderr, "Failed to open %s\n", __SYSTEM_BASE_FILE);
214                 return;
215         }
216
217         fprintf(pFile, "%" PRIxPTR " %" PRIuPTR "\n", baseAddr, niSize);
218         fclose(pFile);
219 }
220
221 // check if dll is listed in TPA
222 static bool isTPADll(const std::string& dllPath)
223 {
224         std::string absPath = getBaseName(getAbsolutePath(dllPath));
225
226         std::vector<std::string> paths = __pm->getPlatformAssembliesPaths();
227         for (unsigned int i = 0; i < paths.size(); i++) {
228                 if (paths[i].find(getBaseName(absPath)) != std::string::npos) {
229                         return true;
230                 }
231         }
232
233         return false;
234 }
235 #endif
236
237 // baseAddr should be checked in file before getting here
238 static ni_error_e crossgen(const std::string& dllPath, const std::string& appPath, DWORD flags)
239 {
240         if (!isFile(dllPath)) {
241                 fprintf(stderr, "dll file is not exist : %s\n", dllPath.c_str());
242                 return NI_ERROR_NO_SUCH_FILE;
243         }
244
245         if (!isManagedAssembly(dllPath)) {
246                 //fprintf(stderr, "Input file is not a dll file : %s\n", dllPath.c_str());
247                 return NI_ERROR_INVALID_PARAMETER;
248         }
249
250         if (checkNIExistence(dllPath)) {
251                 //fprintf(stderr, "Already ni file is exist for %s\n", dllPath.c_str());
252                 return NI_ERROR_ALREADY_EXIST;
253         }
254
255         std::string absDllPath = getAbsolutePath(dllPath);
256         std::string absNIPath = getNIFilePath(dllPath);
257
258         if (absNIPath.empty()) {
259                 fprintf(stderr, "Fail to get ni file name\n");
260                 return NI_ERROR_UNKNOWN;
261         }
262
263         bool isAppNI = flags & NI_FLAGS_APPNI;
264         if (isAppNI && strstr(absNIPath.c_str(), __DOTNET_DIR) == NULL) {
265                 absNIPath = getAppNIFilePath(absNIPath);
266         }
267
268 #ifdef UNIQUE_DEFAULT_BASE_ADDR_SUPPORT
269         uintptr_t baseAddr = 0;
270
271         if (isTPADll(dllPath)) {
272                 baseAddr = getNextBaseAddr();
273         }
274 #endif
275
276         pid_t pid = fork();
277         if (pid == -1)
278                 return NI_ERROR_UNKNOWN;
279
280         if (pid > 0) {
281                 int status;
282                 waitpid(pid, &status, 0);
283                 if (WIFEXITED(status)) {
284                         // Do not use checkNIExistence() function to check whether ni file created or not.
285                         // checkNIExistence() return false for System.Private.Corelib.dll
286                         if (isFile(absNIPath)) {
287                                 copySmackAndOwnership(absDllPath, absNIPath);
288                                 std::string absPdbPath = replaceAll(absDllPath, ".dll", ".pdb");
289                                 std::string pdbFilePath = replaceAll(absNIPath, ".ni.dll", ".pdb");
290                                 if (isFile(absPdbPath) && (absPdbPath != pdbFilePath)) {
291                                         if (!copyFile(absPdbPath, pdbFilePath)) {
292                                                 fprintf(stderr, "Failed to copy a .pdb file\n");
293                                         } else {
294                                                 copySmackAndOwnership(absPdbPath, pdbFilePath);
295                                         }
296                                 }
297 #ifdef UNIQUE_DEFAULT_BASE_ADDR_SUPPORT
298                                 if (baseAddr != 0) {
299                                         updateBaseAddrFile(absNIPath, baseAddr);
300                                 }
301 #endif
302                                 return NI_ERROR_NONE;
303                         } else {
304                                 fprintf(stderr, "Fail to create native image for %s\n", dllPath.c_str());
305                                 return NI_ERROR_NO_SUCH_FILE;
306                         }
307                 }
308         } else {
309                 std::string jitPath = __pm->getRuntimePath() + "/libclrjit.so";
310                 std::vector<const char*> argv = {
311                         __CROSSGEN_PATH,
312                         "/nologo",
313                         "/JITPath", jitPath.c_str()
314                 };
315
316                 bool compat = flags & NI_FLAGS_COMPATIBILITY;
317                 argv.push_back(compat ? "/Platform_Assemblies_Pathes" : "/p");
318                 std::vector<std::string> paths = __pm->getPlatformAssembliesPaths();
319                 std::string platformAssembliesPaths;
320                 for (const auto &path : paths) {
321                         if (!platformAssembliesPaths.empty()) {
322                                 platformAssembliesPaths += ":";
323                         }
324                         platformAssembliesPaths += path;
325                 }
326                 argv.push_back(platformAssembliesPaths.c_str());
327
328                 bool enableR2R = flags & NI_FLAGS_ENABLER2R;
329                 if (!enableR2R) {
330                         argv.push_back("/FragileNonVersionable");
331                 }
332
333                 if (flags & NI_FLAGS_VERBOSE) {
334                         argv.push_back("/verbose");
335                 }
336
337                 if (flags & NI_FLAGS_INSTRUMENT) {
338                         argv.push_back("/Tuning");
339                 }
340
341 #ifdef UNIQUE_DEFAULT_BASE_ADDR_SUPPORT
342                 std::string baseAddrString;
343                 if (baseAddr != 0) {
344                         argv.push_back("/BaseAddress");
345                         std::stringstream ss;
346                         ss << "0x" << std::hex << baseAddr;
347                         baseAddrString = ss.str();
348                         argv.push_back(baseAddrString.c_str());
349                 }
350 #endif
351
352                 argv.push_back("/App_Paths");
353                 std::string absAppPath;
354                 if (!appPath.empty()) {
355                         absAppPath = appPath;
356                 } else {
357                         absAppPath = getBaseName(absDllPath);
358                 }
359                 argv.push_back(absAppPath.c_str());
360
361                 argv.push_back("/out");
362                 argv.push_back(absNIPath.c_str());
363
364                 argv.push_back(absDllPath.c_str());
365                 argv.push_back(nullptr);
366
367                 fprintf(stdout, "+ %s (%s)\n", absDllPath.c_str(), enableR2R ? "R2R" : "FNV");
368
369                 execv(__CROSSGEN_PATH, const_cast<char* const*>(argv.data()));
370                 exit(0);
371         }
372
373         return NI_ERROR_NONE;
374 }
375
376 // callback function of "pkgmgrinfo_appinfo_metadata_filter_foreach"
377 static int appAotCb(pkgmgrinfo_appinfo_h handle, void *userData)
378 {
379         char *pkgId = NULL;
380         int ret = 0;
381         DWORD *pFlags = (DWORD*)userData;
382
383         ret = pkgmgrinfo_appinfo_get_pkgid(handle, &pkgId);
384         if (ret != PMINFO_R_OK) {
385                 fprintf(stderr, "Failed to get pkgid\n");
386                 return -1;
387         }
388
389         if (removeNIUnderPkgRoot(pkgId) != NI_ERROR_NONE) {
390                 fprintf(stderr, "Failed to remove previous dlls from [%s]\n", pkgId);
391                 return -1;
392         }
393
394         if (createNIUnderPkgRoot(pkgId, *pFlags) != NI_ERROR_NONE) {
395                 fprintf(stderr, "Failed to generate NI file [%s]\n", pkgId);
396                 return -1;
397         } else {
398                 fprintf(stdout, "Complete make application to native image\n");
399         }
400
401         return 0;
402 }
403
404 static bool isCoreLibPrepared(DWORD flags)
405 {
406         if (flags & NI_FLAGS_ENABLER2R) {
407                 return true;
408         }
409
410         std::string coreLibBackup = concatPath(__pm->getRuntimePath(), "System.Private.CoreLib.dll.Backup");
411         if (isFile(coreLibBackup)) {
412                 return true;
413         } else {
414                 fprintf(stderr, "The native image of System.Private.CoreLib does not exist\n"
415                                         "Run the command to create the native image\n"
416                                         "# dotnettool --ni-dll /usr/share/dotnet.tizen/netcoreapp/System.Private.CoreLib.dll\n\n");
417                 return false;
418         }
419 }
420
421 static bool hasCoreLibNI()
422 {
423         FILE *fp;
424         char buff[1024];
425         std::string ildasm = concatPath(__pm->getRuntimePath(), "ildasm");
426         std::string coreLib = concatPath(__pm->getRuntimePath(), "System.Private.CoreLib.dll");
427         std::string cmd = ildasm + " " + coreLib + " | grep '\\.corflags'";
428         fp = popen(cmd.c_str(), "r");
429         if (fp != NULL) {
430                 while (fgets(buff, sizeof(buff), fp) != NULL) {
431                         buff[strlen(buff) - 1] = '\0';
432                 }
433                 std::string corflag = replaceAll(buff, ".corflags", "");
434                 corflag.erase(std::remove(corflag.begin(), corflag.end(), ' '), corflag.end());
435                 // CorFlags.ILLibrary=0x00000004 (.ni.dll)
436                 if (!strcmp(corflag.substr(0, 10).c_str(), "0x00000004")) {
437                         pclose(fp);
438                         return true;
439                 }
440                 pclose(fp);
441         }
442         return false;
443 }
444
445 static ni_error_e createCoreLibNI(DWORD flags)
446 {
447         std::string coreLib = concatPath(__pm->getRuntimePath(), "System.Private.CoreLib.dll");
448         std::string niCoreLib = concatPath(__pm->getRuntimePath(), "System.Private.CoreLib.ni.dll");
449         std::string coreLibBackup = concatPath(__pm->getRuntimePath(), "System.Private.CoreLib.dll.Backup");
450
451         if (!isFile(coreLibBackup) && !hasCoreLibNI()) {
452                 if (!crossgen(coreLib, std::string(), flags)) {
453                         if (rename(coreLib.c_str(), coreLibBackup.c_str())) {
454                                 fprintf(stderr, "Failed to rename System.Private.CoreLib.dll\n");
455                                 return NI_ERROR_CORE_NI_FILE;
456                         }
457                         if (rename(niCoreLib.c_str(), coreLib.c_str())) {
458                                 fprintf(stderr, "Failed to rename System.Private.CoreLib.ni.dll\n");
459                                 return NI_ERROR_CORE_NI_FILE;
460                         }
461                 } else {
462                         fprintf(stderr, "Failed to create native image for %s\n", coreLib.c_str());
463                         return NI_ERROR_CORE_NI_FILE;
464                 }
465         }
466         return NI_ERROR_NONE;
467 }
468
469 ni_error_e initNICommon()
470 {
471 #if defined(__arm__) || defined(__aarch64__)
472         // get interval value
473         const static std::string intervalFile = concatPath(__NATIVE_LIB_DIR, "crossgen_interval.txt");
474         std::ifstream inFile(intervalFile);
475         if (inFile) {
476                 fprintf(stdout, "crossgen_interval.txt is found\n");
477                 inFile >> __interval;
478         }
479
480         if (initializePluginManager("normal")) {
481                 fprintf(stderr, "Fail to initialize PluginManager\n");
482                 return NI_ERROR_UNKNOWN;
483         }
484
485         try {
486                 __pm = new PathManager();
487         } catch (const std::exception& e) {
488                 fprintf(stderr, "Failed to create PathManager");
489                 return NI_ERROR_UNKNOWN;
490         }
491
492         char* pluginDllPaths = pluginGetDllPath();
493         if (pluginDllPaths) {
494                 __pm->addPlatformAssembliesPaths(pluginDllPaths);
495         }
496
497         return NI_ERROR_NONE;
498 #else
499         fprintf(stderr, "crossgen supports arm/arm64 architecture only. skip ni file generation\n");
500         return NI_ERROR_NOT_SUPPORTED;
501 #endif
502 }
503
504 void finalizeNICommon()
505 {
506         __interval = 0;
507
508         finalizePluginManager();
509
510         delete(__pm);
511         __pm = nullptr;
512 }
513
514 ni_error_e createNIPlatform(DWORD flags)
515 {
516         if (createCoreLibNI(flags) != NI_ERROR_NONE) {
517                 return NI_ERROR_CORE_NI_FILE;
518         }
519
520         return createNIUnderDirs(__pm->getRuntimePath() + ":" + __pm->getTizenFXPath(), flags);
521 }
522
523 ni_error_e createNIDll(const std::string& dllPath, DWORD flags)
524 {
525         if (dllPath.find("System.Private.CoreLib.dll") != std::string::npos) {
526                 return createCoreLibNI(flags);
527         }
528
529         if (!isCoreLibPrepared(flags)) {
530                 return NI_ERROR_CORE_NI_FILE;
531         }
532
533         return crossgen(dllPath, std::string(), flags);
534 }
535
536 ni_error_e createNIUnderDirs(const std::string& rootPaths, DWORD flags)
537 {
538         if (!isCoreLibPrepared(flags)) {
539                 return NI_ERROR_CORE_NI_FILE;
540         }
541
542         auto convert = [&rootPaths, flags](const std::string& path, const std::string& filename) {
543                 // if path is symlink, donot generate crossgen
544                 if (!crossgen(path, rootPaths.c_str(), flags)) {
545                         waitInterval();
546                 }
547         };
548
549         std::vector<std::string> targetPaths;
550         splitPath(rootPaths, targetPaths);
551         for (const auto &path : targetPaths) {
552                 // TAC directory should be handled specially because that contains symlink of native image file.
553                 if (strstr(path.c_str(), TAC_SYMLINK_SUB_DIR) != NULL) {
554                         if (!isDirectory(path)) {
555                                 continue;
556                         }
557                         // make native image symlink if not exist under tac directory
558                         try {
559                                 for (auto& symlinkAssembly : bf::recursive_directory_iterator(path)) {
560                                         std::string symPath = symlinkAssembly.path().string();
561                                         if (!isManagedAssembly(symPath)) {
562                                                 continue;
563                                         }
564
565                                         // if there is symlink and original file for native image, skip generation
566                                         std::string symNIPath = symPath.substr(0, symPath.rfind(".dll")) + ".ni.dll";
567                                         if (isFile(symNIPath)) {
568                                                 continue;
569                                         }
570
571                                         // if original native image not exist, generate native image
572                                         std::string originPath = bf::read_symlink(symPath).string();
573                                         std::string originNIPath = originPath.substr(0, originPath.rfind(".dll")) + ".ni.dll";
574                                         if (!isFile(originNIPath)) {
575                                                 if (!crossgen(originPath, path.c_str(), flags)) {
576                                                         waitInterval();
577                                                 }
578                                         }
579
580                                         // if no symlink file exist, create symlink
581                                         if (!isFile(symNIPath)) {
582                                                 bf::create_symlink(originNIPath, symNIPath);
583                                                 copySmackAndOwnership(symPath.c_str(), symNIPath.c_str(), true);
584                                                 fprintf(stdout, "%s symbolic link file generated successfully.\n", symNIPath.c_str());
585                                                 _INFO("%s symbolic link file generated successfully.", symNIPath.c_str());
586                                         }
587                                 }
588                         } catch (const bf::filesystem_error& error) {
589                                 fprintf(stderr, "Failed to recursive directory: %s\n", error.what());
590                                 return NI_ERROR_UNKNOWN;
591                         }
592                 } else {
593                         scanFilesInDirectory(path, convert, 0);
594                 }
595         }
596
597         return NI_ERROR_NONE;
598 }
599
600 ni_error_e createNIUnderPkgRoot(const std::string& pkgId, DWORD flags)
601 {
602         std::string rootPath = getRootPath(pkgId);
603         if (rootPath.empty()) {
604                 fprintf(stderr, "Failed to get root path from [%s]\n", pkgId.c_str());
605                 return NI_ERROR_INVALID_PACKAGE;
606         }
607
608         __pm->setAppRootPath(rootPath);
609
610         flags |= NI_FLAGS_APPNI;
611
612         // create native image under bin and lib directory
613         // tac directory is skipped in the createNIUnderDirs.
614         return createNIUnderDirs(__pm->getAppPaths(), flags);
615 }
616
617 void removeNIPlatform()
618 {
619         std::string coreLib = concatPath(__pm->getRuntimePath(), "System.Private.CoreLib.dll");
620         std::string coreLibBackup = concatPath(__pm->getRuntimePath(), "System.Private.CoreLib.dll.Backup");
621
622         if (hasCoreLibNI()) {
623                 if (!isFile(coreLibBackup)) {
624                         return;
625                 }
626
627                 if (remove(coreLib.c_str())) {
628                         fprintf(stderr, "Failed to remove System.Private.CoreLib native image file\n");
629                 }
630                 if (rename(coreLibBackup.c_str(), coreLib.c_str())) {
631                         fprintf(stderr, "Failed to rename System.Private.CoreLib.Backup to origin\n");
632                 }
633         }
634
635 #ifdef UNIQUE_DEFAULT_BASE_ADDR_SUPPORT
636         if (isFile(__SYSTEM_BASE_FILE)) {
637                 if (remove(__SYSTEM_BASE_FILE)) {
638                         fprintf(stderr, "Failed to remove %s\n", __SYSTEM_BASE_FILE);
639                 }
640         }
641 #endif
642
643         removeNIUnderDirs(__pm->getRuntimePath() + ":" + __pm->getTizenFXPath());
644 }
645
646 void removeNIUnderDirs(const std::string& rootPaths)
647 {
648         auto convert = [](const std::string& path, const std::string& filename) {
649                 if (isNativeImage(path)) {
650                         if (remove(path.c_str())) {
651                                 fprintf(stderr, "Failed to remove %s\n", path.c_str());
652                         }
653                 }
654         };
655
656         std::vector<std::string> paths;
657         splitPath(rootPaths, paths);
658         for (const auto &path : paths) {
659                 scanFilesInDirectory(path, convert, -1);
660         }
661 }
662
663 ni_error_e removeNIUnderPkgRoot(const std::string& pkgId)
664 {
665         std::string rootPath = getRootPath(pkgId);
666         if (rootPath.empty()) {
667                 fprintf(stderr, "Failed to get root path from [%s]\n", pkgId.c_str());
668                 return NI_ERROR_INVALID_PACKAGE;
669         }
670
671         __pm->setAppRootPath(rootPath);
672
673         // getAppNIPaths returns bin/.native_image, lib/.native_image and .tac_symlink.
674         std::string appNIPaths = __pm->getAppNIPaths();
675         std::vector<std::string> paths;
676         splitPath(appNIPaths, paths);
677         for (const auto &path : paths) {
678                 // Only the native image inside the TAC should be removed.
679                 if (strstr(path.c_str(), TAC_SYMLINK_SUB_DIR) != NULL) {
680                         removeNIUnderDirs(path);
681                 } else {
682                         if (isDirectory(path)) {
683                                 if (!removeAll(path.c_str())) {
684                                         fprintf(stderr, "Failed to remove app ni dir [%s]\n", path.c_str());
685                                 }
686                         }
687                 }
688         }
689
690         return NI_ERROR_NONE;
691 }
692
693 ni_error_e regenerateAppNI(DWORD flags)
694 {
695         if (!isCoreLibPrepared(flags)) {
696                 return NI_ERROR_CORE_NI_FILE;
697         }
698
699         int ret = 0;
700         pkgmgrinfo_appinfo_metadata_filter_h handle;
701
702         ret = pkgmgrinfo_appinfo_metadata_filter_create(&handle);
703         if (ret != PMINFO_R_OK)
704                 return NI_ERROR_UNKNOWN;
705
706         ret = pkgmgrinfo_appinfo_metadata_filter_add(handle, AOT_METADATA_KEY, METADATA_VALUE);
707         if (ret != PMINFO_R_OK) {
708                 pkgmgrinfo_appinfo_metadata_filter_destroy(handle);
709                 return NI_ERROR_UNKNOWN;
710         }
711
712         ret = pkgmgrinfo_appinfo_metadata_filter_foreach(handle, appAotCb, &flags);
713         if (ret != PMINFO_R_OK) {
714                 fprintf(stderr, "Failed pkgmgrinfo_appinfo_metadata_filter_foreach\n");
715                 pkgmgrinfo_appinfo_metadata_filter_destroy(handle);
716                 return NI_ERROR_UNKNOWN;
717         }
718
719         fprintf(stdout, "Success pkgmgrinfo_appinfo_metadata_filter_foreach\n");
720
721         pkgmgrinfo_appinfo_metadata_filter_destroy(handle);
722         return NI_ERROR_NONE;
723 }
724
725 // callback function of "pkgmgrinfo_appinfo_metadata_filter_foreach"
726 static int regenTacCb(pkgmgrinfo_appinfo_h handle, void *userData)
727 {
728         char *pkgId = NULL;
729         DWORD *pFlags = (DWORD*)userData;
730
731         int ret = pkgmgrinfo_appinfo_get_pkgid(handle, &pkgId);
732         if (ret != PMINFO_R_OK || pkgId == NULL) {
733                 fprintf(stderr, "Failed to get pkgid\n");
734                 return -1;
735         }
736
737         sqlite3 *tac_db = openDB(TAC_APP_LIST_DB);
738         if (!tac_db) {
739                 fprintf(stderr, "Sqlite open error\n");
740                 return -1;
741         }
742         sqlite3_exec(tac_db, "BEGIN;", NULL, NULL, NULL);
743
744         char *sql = sqlite3_mprintf("SELECT * FROM TAC WHERE PKGID = %Q;", pkgId);
745         std::vector<std::string> nugets = selectDB(tac_db, sql);
746         sqlite3_free(sql);
747
748         if (tac_db) {
749                 closeDB(tac_db);
750                 tac_db = NULL;
751         }
752
753         std::string nugetPaths;
754         for (const auto &nuget : nugets) {
755                 if (!nugetPaths.empty()) {
756                         nugetPaths += ":";
757                 }
758                 nugetPaths += concatPath(__DOTNET_DIR, nuget);
759         }
760
761         auto convert = [&nugetPaths, pFlags](const std::string& path, const std::string& filename) {
762                 if (strstr(path.c_str(), TAC_SHA_256_INFO) != NULL)
763                         return;
764                 if (!crossgen(path, nugetPaths.c_str(), *pFlags)) {
765                         waitInterval();
766                 }
767         };
768
769         for (auto& nuget : nugets) {
770                 scanFilesInDirectory(concatPath(__DOTNET_DIR, nuget), convert, -1);
771         }
772
773         return 0;
774 }
775
776 ni_error_e regenerateTACNI(DWORD flags)
777 {
778         if (!isCoreLibPrepared(flags)) {
779                 return NI_ERROR_CORE_NI_FILE;
780         }
781
782         removeNIUnderDirs(__DOTNET_DIR);
783
784         pkgmgrinfo_appinfo_metadata_filter_h handle;
785         int ret = pkgmgrinfo_appinfo_metadata_filter_create(&handle);
786         if (ret != PMINFO_R_OK) {
787                 return NI_ERROR_UNKNOWN;
788         }
789
790         ret = pkgmgrinfo_appinfo_metadata_filter_add(handle, TAC_METADATA_KEY, METADATA_VALUE);
791         if (ret != PMINFO_R_OK) {
792                 pkgmgrinfo_appinfo_metadata_filter_destroy(handle);
793                 return NI_ERROR_UNKNOWN;
794         }
795
796         ret = pkgmgrinfo_appinfo_metadata_filter_foreach(handle, regenTacCb, &flags);
797         if (ret != PMINFO_R_OK) {
798                 fprintf(stderr, "Failed pkgmgrinfo_appinfo_metadata_filter_foreach\n");
799                 pkgmgrinfo_appinfo_metadata_filter_destroy(handle);
800                 return NI_ERROR_UNKNOWN;
801         }
802         fprintf(stdout, "Success pkgmgrinfo_appinfo_metadata_filter_foreach\n");
803
804         pkgmgrinfo_appinfo_metadata_filter_destroy(handle);
805
806         return NI_ERROR_NONE;
807 }