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