Change update size for PBA (#419)
[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 #include <tzplatform_config.h>
21
22 #include "log.h"
23 #include "utils.h"
24 #include "pkgmgr_parser_plugin_interface.h"
25
26 #include <wait.h>
27 #include <dirent.h>
28 #include <sys/stat.h>
29
30 #include <algorithm>
31 #include <string>
32 #include <fstream>
33 #include <sstream>
34
35 #include <pwd.h>
36 #include <grp.h>
37 #include <unistd.h>
38 #include <string.h>
39 #include <sqlite3.h>
40 #include <inttypes.h>
41 #include <errno.h>
42
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"
49
50 #ifdef  LOG_TAG
51 #undef  LOG_TAG
52 #endif
53 #define LOG_TAG "DOTNET_INSTALLER_PLUGIN"
54
55 #define __XSTR(x) #x
56 #define __STR(x) __XSTR(x)
57 #if defined(__arm__) || defined(__aarch64__)
58 static const char* __NATIVE_LIB_DIR = __STR(NATIVE_LIB_DIR);
59 #endif
60 static const char* __DOTNET_DIR = __STR(DOTNET_DIR);
61 static const char* __READ_ONLY_APP_UPDATE_DIR = __STR(READ_ONLY_APP_UPDATE_DIR);
62
63 #ifdef UNIQUE_DEFAULT_BASE_ADDR_SUPPORT
64 static const char* __SYSTEM_BASE_FILE = __STR(SYSTEM_BASE_FILE);
65 #endif
66
67 #undef __STR
68 #undef __XSTR
69
70 static std::string CORERUN_CMD = "/usr/share/dotnet.tizen/netcoreapp/corerun";
71 static std::string CROSSGEN2_PATH = "/usr/share/dotnet.tizen/netcoreapp/crossgen2/crossgen2.dll";
72 static std::string CLRJIT_PATH = "/usr/share/dotnet.tizen/netcoreapp/libclrjit.so";
73 static const char* CROSSGEN_OPT_JITPATH = "--jitpath";
74 static const char* CROSSGEN_OPT_TARGET_ARCH = "--targetarch";
75 static const char* CROSSGEN_OPT_OUT_NEAR_INPUT = "--out-near-input";
76 static const char* CROSSGEN_OPT_SINGLE_FILE_COMPILATION = "--single-file-compilation";
77 //static const char* CROSSGEN_OPT_PARALLELISM = "--parallelism";
78 //static const char* CROSSGEN_OPT_PARALLELISM_COUNT = "5";
79 static const char* CROSSGEN_OPT_RESILIENT = "--resilient";
80 static const char* CROSSGEN_OPT_OPTIMIZE = "-O";
81 static const char* CROSSGEN_OPT_OPTIMIZE_TIME = "--Ot";
82 static const char* CROSSGEN_OPT_INPUTBUBBLE = "--inputbubble";
83 static const char* CROSSGEN_OPT_COMPILE_BUBBLE_GENERICS = "--compilebubblegenerics";
84 static const char* CROSSGEN_OPT_VERBOSE = "--verbose";
85 static std::vector<std::string> REF_VECTOR;
86 static std::vector<std::string> INPUTBUBBLE_REF_VECTOR;
87 static std::vector<std::string> MIBC_VECTOR;
88
89 static int __interval = 0;
90 static PathManager* __pm = nullptr;
91
92 static NIOption* __ni_option = nullptr;
93
94 // singleton
95 NIOption* getNIOption()
96 {
97         if (__ni_option == nullptr) {
98                 __ni_option = (NIOption*)calloc(sizeof(NIOption), 1);
99                 if (__ni_option == nullptr) {
100                         _SERR("Fail to create NIOption");
101                 }
102         }
103         return __ni_option;
104 }
105
106 static void waitInterval()
107 {
108         // by the recommand, ignore small value for performance.
109         if (__interval > 10000) {
110                 _SOUT("sleep %d usec", __interval);
111                 usleep(__interval);
112         }
113 }
114
115 #ifdef UNIQUE_DEFAULT_BASE_ADDR_SUPPORT
116 static uintptr_t getFileSize(const std::string& path)
117 {
118         struct stat sb;
119
120         if (stat(path.c_str(), &sb) == 0) {
121                 return sb.st_size;
122         }
123
124         return 0;
125 }
126
127 // Get next base address to be used for system ni image from file
128 // __SYSTEM_BASE_FILE should be checked for existance before calling this function
129 static uintptr_t getNextBaseAddrFromFile()
130 {
131         FILE *pFile = fopen(__SYSTEM_BASE_FILE, "r");
132         if (pFile == NULL) {
133                 _SERR("Failed to open %s", __SYSTEM_BASE_FILE);
134                 return 0;
135         }
136
137         uintptr_t addr = 0;
138         uintptr_t size = 0;
139
140         while (fscanf(pFile, "%" SCNxPTR " %" SCNuPTR "", &addr, &size) != EOF) {
141         }
142
143         fclose(pFile);
144
145         return addr + size;
146 }
147
148 // Get next base address to be used for system ni image
149 static uintptr_t getNextBaseAddr()
150 {
151         uintptr_t baseAddr = 0;
152
153         if (!isFile(__SYSTEM_BASE_FILE)) {
154                 // This is the starting address for all default base addresses
155                 baseAddr = DEFAULT_BASE_ADDR_START;
156         } else {
157                 baseAddr = getNextBaseAddrFromFile();
158
159                 // Round to a multple of 64K (see ZapImage::CalculateZapBaseAddress in CoreCLR)
160                 uintptr_t BASE_ADDRESS_ALIGNMENT = 0xffff;
161                 baseAddr = (baseAddr + BASE_ADDRESS_ALIGNMENT) & ~BASE_ADDRESS_ALIGNMENT;
162         }
163
164         return baseAddr;
165 }
166
167 // Save base address of system ni image to file
168 static void updateBaseAddrFile(const std::string& absNIPath, uintptr_t baseAddr)
169 {
170         uintptr_t niSize = getSizeOfImage(absNIPath);
171         if (niSize == 0) {
172                 _SERR("File %s doesn't exist", absNIPath.c_str());
173                 return;
174         }
175
176         // Write new entry to the file
177         FILE *pFile = fopen(__SYSTEM_BASE_FILE, "a");
178         if (pFile == NULL) {
179                 _SERR("Failed to open %s", __SYSTEM_BASE_FILE);
180                 return;
181         }
182
183         fprintf(pFile, "%" PRIxPTR " %" PRIuPTR "\n", baseAddr, niSize);
184         fclose(pFile);
185 }
186
187 // check if dll is listed in TPA
188 static bool isTPADll(const std::string& dllPath)
189 {
190         std::string absPath = getBaseName(getAbsolutePath(dllPath));
191
192         std::vector<std::string> paths = __pm->getPlatformAssembliesPaths();
193         for (unsigned int i = 0; i < paths.size(); i++) {
194                 if (paths[i].find(getBaseName(absPath)) != std::string::npos) {
195                         return true;
196                 }
197         }
198
199         return false;
200 }
201 #endif
202
203 /**
204  * @brief create the directory including parents directory, and
205  *        copy ownership and smack labels to the created directory.
206  * @param[in] target directory path
207  * @param[in] source directory path to get ownership and smack label
208  * @return if directory created successfully, return true otherwise false
209  */
210 static bool createDirsAndCopyOwnerShip(std::string& target_path, const std::string& source)
211 {
212         struct stat st;
213         mode_t mode = S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH;
214
215         for (std::string::iterator iter = target_path.begin(); iter != target_path.end();) {
216                 std::string::iterator newIter = std::find(iter, target_path.end(), '/');
217                 std::string newPath = std::string(target_path.begin(), newIter);
218
219                 if (!newPath.empty()) {
220                         if (stat(newPath.c_str(), &st) != 0) {
221                                 if (mkdir(newPath.c_str(), mode) != 0 && errno != EEXIST) {
222                                         _SERR("Fail to create app ni directory (%s)", newPath.c_str());
223                                         return false;
224                                 }
225                                 if (!source.empty()) {
226                                         copySmackAndOwnership(source, newPath);
227                                 }
228                         } else {
229                                 if (!S_ISDIR(st.st_mode)) {
230                                         _SERR("Fail. path is not a dir (%s)", newPath.c_str());
231                                         return false;
232                                 }
233                         }
234                 }
235                 iter = newIter;
236                 if(newIter != target_path.end()) {
237                         ++iter;
238                 }
239         }
240
241         return true;
242 }
243
244 static std::string getNIFilePath(const std::string& dllPath)
245 {
246         size_t index = dllPath.find_last_of(".");
247         if (index == std::string::npos) {
248                 _SERR("File doesnot contain extension. fail to get NI file name");
249                 return "";
250         }
251         std::string fName = dllPath.substr(0, index);
252         std::string fExt = dllPath.substr(index, dllPath.length());
253
254         // crossgen generate file with lower case extension only
255         std::transform(fExt.begin(), fExt.end(), fExt.begin(), ::tolower);
256         std::string niPath = fName + ".ni" + fExt;
257
258         return niPath;
259 }
260
261 static std::string getAppNIFilePath(const std::string& absDllPath, NIOption* opt)
262 {
263         std::string niDirPath;
264         std::string prevPath;
265
266         prevPath = getBaseName(absDllPath);
267         niDirPath = concatPath(prevPath, APP_NI_SUB_DIR);
268
269         if (opt->flags & NI_FLAGS_APP_UNDER_RO_AREA) {
270                 niDirPath = replaceAll(niDirPath, getBaseName(__pm->getAppRootPath()), __READ_ONLY_APP_UPDATE_DIR);
271                 _SERR("App is installed in RO area. Change NI path to RW area(%s).", niDirPath.c_str());
272                 _ERR("App is installed in RO area. Change NI path to RW area(%s).", niDirPath.c_str());
273         }
274
275         if (!isDirectory(niDirPath)) {
276                 if (!createDirsAndCopyOwnerShip(niDirPath, prevPath)) {
277                         niDirPath = prevPath;
278                         _SERR("fail to create dir (%s)", niDirPath.c_str());
279                 }
280         }
281
282         return getNIFilePath(concatPath(niDirPath, getFileName(absDllPath)));
283 }
284
285 static bool checkNIExistence(const std::string& absDllPath)
286 {
287         std::string absNIPath = getNIFilePath(absDllPath);
288         if (absNIPath.empty()) {
289                 return false;
290         }
291
292         if (isFile(absNIPath)) {
293                 return true;
294         }
295
296         // native image of System.Private.CoreLib.dll should have to overwrite
297         // original file to support new coreclr
298         if (absDllPath.find("System.Private.CoreLib.dll") != std::string::npos) {
299                 return isR2RImage(absDllPath);
300         }
301
302         return false;
303 }
304
305 static bool checkAppNIExistence(const std::string& absDllPath, NIOption* opt)
306 {
307         std::string absNIPath = getAppNIFilePath(absDllPath, opt);
308         if (absNIPath.empty()) {
309                 return false;
310         }
311
312         if (isFile(absNIPath)) {
313                 return true;
314         }
315
316         return false;
317 }
318
319 static bool checkDllExistInDir(const std::string& path)
320 {
321         bool ret = false;
322         auto func = [&ret](const std::string& f_path, const std::string& f_name) {
323                 if (isManagedAssembly(f_name) || isNativeImage(f_name)) {
324                         ret = true;
325                 }
326         };
327
328         scanFilesInDirectory(path, func, 0);
329
330         return ret;
331 }
332
333 /*
334  * Get the list of managed files in the specific directory
335  * Absolute paths of managed files are stored at the result list.
336  * If native image already exist in the same directory, managed file is ignored.
337  */
338 static ni_error_e getTargetDllList(const std::string& path, std::vector<std::string>& fileList)
339 {
340         if (!isDirectory(path)) {
341                 return NI_ERROR_INVALID_PARAMETER;
342         }
343
344         auto func = [&fileList](const std::string& f_path, const std::string& f_name) {
345                 if (isManagedAssembly(f_path) && !checkNIExistence(f_path)) {
346                         fileList.push_back(getAbsolutePath(f_path));
347                 }
348         };
349
350         scanFilesInDirectory(path, func, 0);
351
352         return NI_ERROR_NONE;
353 }
354
355 /*
356  * Get the list of managed files in the specific directory of Application
357  * Absolute paths of managed files are stored at the result list.
358  * If native image already exist in the .native_image directory, managed file is ignored.
359  *
360  */
361 static ni_error_e getAppTargetDllList(const std::string& path, std::vector<std::string>& fileList, NIOption *opt)
362 {
363         if (!isDirectory(path)) {
364                 return NI_ERROR_INVALID_PARAMETER;
365         }
366
367         auto func = [&fileList, opt](const std::string& f_path, const std::string& f_name) {
368                 if (isManagedAssembly(f_path) && !checkAppNIExistence(f_path, opt)) {
369                         fileList.push_back(getAbsolutePath(f_path));
370                 }
371         };
372
373         scanFilesInDirectory(path, func, 0);
374
375         return NI_ERROR_NONE;
376 }
377
378 static void makeArgs(std::vector<const char*>& args, const std::vector<std::string>& refPaths, NIOption* opt)
379 {
380         args.push_back(CORERUN_CMD.c_str());
381         if (CROSSGEN2_PATH != "") {
382                 args.push_back(CROSSGEN2_PATH.c_str());
383         }
384         args.push_back(CROSSGEN_OPT_JITPATH);
385         args.push_back(CLRJIT_PATH.c_str());
386         args.push_back(CROSSGEN_OPT_TARGET_ARCH);
387         args.push_back(ARCHITECTURE_IDENTIFIER);
388         if (!(opt->flags & NI_FLAGS_NO_PIPELINE)) {
389                 args.push_back(CROSSGEN_OPT_OUT_NEAR_INPUT);
390                 args.push_back(CROSSGEN_OPT_SINGLE_FILE_COMPILATION);
391         }
392         //args.push_back(OPT_PARALLELISM);
393         //args.push_back(OPT_PARALLELISM_COUNT);
394         args.push_back(CROSSGEN_OPT_RESILIENT);
395
396         args.push_back(CROSSGEN_OPT_OPTIMIZE_TIME);
397
398         if (opt->flags & NI_FLAGS_INPUT_BUBBLE) {
399                 args.push_back(CROSSGEN_OPT_INPUTBUBBLE);
400                 args.push_back(CROSSGEN_OPT_COMPILE_BUBBLE_GENERICS);
401
402                 if (opt->flags & NI_FLAGS_INPUT_BUBBLE_REF) {
403                         INPUTBUBBLE_REF_VECTOR.clear();
404                         // check inputbubbleref format.
405                         for (const auto &path : opt->inputBubbleRefPath) {
406                                 if (checkDllExistInDir(path)) {
407                                         INPUTBUBBLE_REF_VECTOR.push_back("--inputbubbleref:" + path + "/*.dll");
408                                 }
409                         }
410                         // add ref path to inputbubble ref
411                         for (const auto &path : refPaths) {
412                                 if (checkDllExistInDir(path)) {
413                                         INPUTBUBBLE_REF_VECTOR.push_back("--inputbubbleref:" + path + "/*.dll");
414                                 }
415                         }
416                         for (const auto &path : INPUTBUBBLE_REF_VECTOR) {
417                                 args.push_back(path.c_str());
418                         }
419                 }
420         }
421
422         if (opt->flags & NI_FLAGS_MIBC) {
423                 MIBC_VECTOR.clear();
424                 for (const auto &path : opt->mibcPath) {
425                         MIBC_VECTOR.push_back("--mibc:" + path);
426                 }
427                 for (const auto &path : MIBC_VECTOR) {
428                         args.push_back(path.c_str());
429                 }
430         }
431
432         if (opt->flags & NI_FLAGS_VERBOSE) {
433                 args.push_back(CROSSGEN_OPT_VERBOSE);
434         }
435
436         REF_VECTOR.clear();
437
438         // set reference path
439         if (opt->flags & NI_FLAGS_REF) {
440                 for (const auto &path : opt->refPath) {
441                         REF_VECTOR.push_back("-r:" + path + "/*.dll");
442                 }
443         } else {
444                 std::vector<std::string> paths = __pm->getPlatformAssembliesPaths();
445                 for (const auto &path : paths) {
446                         if (checkDllExistInDir(path)) {
447                                 REF_VECTOR.push_back("-r:" + path + "/*.dll");
448                         }
449                 }
450         }
451
452         if (opt->flags & NI_FLAGS_EXTRA_REF) {
453                 for (const auto &erPath : opt->extraRefPath) {
454                         std::string path = getAbsolutePath(erPath);
455                         if (checkDllExistInDir(path)) {
456                                 REF_VECTOR.push_back("-r:" + path + "/*.dll");
457                         }
458                 }
459         }
460
461         for (const auto &path : refPaths) {
462                 if (checkDllExistInDir(path)) {
463                         REF_VECTOR.push_back("-r:" + path + "/*.dll");
464                 }
465         }
466
467         for (const auto &path : REF_VECTOR) {
468                 args.push_back(path.c_str());
469         }
470 }
471
472 static void clearArgs(std::vector<const char*>& args)
473 {
474         REF_VECTOR.clear();
475         args.clear();
476 }
477
478 static ni_error_e makePdbSymlinkForNI(std::string dllPath, std::string niPath)
479 {
480         std::string pdbPath = changeExtension(dllPath, ".dll", ".pdb");
481         try {
482                 if (exist(pdbPath)) {
483                         std::string targetPDBPath = changeExtension(niPath, ".ni.dll", ".pdb");
484                         if (!exist(targetPDBPath)) {
485                                 bf::create_symlink(pdbPath, targetPDBPath);
486                                 copySmackAndOwnership(pdbPath, targetPDBPath, true);
487                         }
488                 }
489         } catch (const bf::filesystem_error& error) {
490                 _SERR("Fail to create symlink for %s", pdbPath.c_str());
491                 return NI_ERROR_UNKNOWN;
492         }
493
494         return NI_ERROR_NONE;
495 }
496
497 static ni_error_e crossgen2PostAction(const std::string& dllPath, const std::string& niPath, NIOption* opt) {
498         if (!exist(niPath)) {
499                 removeFile(changeExtension(niPath, ".ni.dll", ".ni.dll.tmp"));
500                 _SERR("Fail to create native image for %s", dllPath.c_str());
501                 return NI_ERROR_NO_SUCH_FILE;
502         }
503         copySmackAndOwnership(dllPath, niPath);
504         // if AppNI then move ni.dll file to .native_image and copy pdb to .native_image
505         if (opt->flags & NI_FLAGS_APPNI) {
506                 std::string appNIPath = getAppNIFilePath(dllPath, opt);
507                 moveFile(niPath, appNIPath);
508                 makePdbSymlinkForNI(dllPath, appNIPath);
509                 _SOUT("Native image %s generated successfully.", appNIPath.c_str());
510         } else {
511                 _SOUT("Native image %s generated successfully.", niPath.c_str());
512         }
513         return NI_ERROR_NONE;
514 }
515
516 static ni_error_e crossgen2PipeLine(const std::vector<std::string>& dllList, const std::vector<std::string>& refPaths, NIOption* opt)
517 {
518         // fork crossgen2
519         pid_t pid = fork();
520         if (pid == -1)
521                 return NI_ERROR_UNKNOWN;
522
523         if (pid > 0) {
524                 int status;
525                 waitpid(pid, &status, 0);
526                 if (WIFEXITED(status)) {
527                         for (auto& dllPath: dllList) {
528                                 ni_error_e ret = crossgen2PostAction(dllPath, changeExtension(dllPath, ".dll", ".ni.dll"), opt);
529                                 if (ret != NI_ERROR_NONE) {
530                                         return ret;
531                                 }
532                         }
533                 } else {
534                         _SERR("Failed. Forked process terminated abnormally");
535                         return NI_ERROR_ABNORMAL_PROCESS_TERMINATION;
536                 }
537         } else {
538                 std::vector<const char*> argv;
539                 makeArgs(argv, refPaths, opt);
540
541                 // add input files at the end of parameter
542                 for (const auto &input : dllList) {
543                         argv.push_back(input.c_str());
544                         _SOUT("+ %s", input.c_str());
545                 }
546
547                 // end param
548                 argv.push_back(nullptr);
549
550                 // print cmd
551                 if (opt->flags & NI_FLAGS_PRINT_CMD) {
552                         _SOUT("==================== NI Commands =========================");
553                         for (auto &arg: argv) _SOUT("+ %s", arg);
554                 }
555
556                 execv(CORERUN_CMD.c_str(), const_cast<char* const*>(argv.data()));
557
558                 clearArgs(argv);
559                 exit(0);
560         }
561
562         return NI_ERROR_NONE;
563 }
564
565 static ni_error_e crossgen2NoPipeLine(const std::vector<std::string>& dllList, const std::vector<std::string>& refPaths, NIOption* opt)
566 {
567         for (auto& dllPath : dllList) {
568                 std::string niPath;
569                 if (opt->flags & NI_FLAGS_APPNI) {
570                         niPath = getAppNIFilePath(dllPath, opt);
571                 } else {
572                         niPath = getNIFilePath(dllPath);
573                 }
574
575 #ifdef UNIQUE_DEFAULT_BASE_ADDR_SUPPORT
576                 uintptr_t baseAddr = 0;
577                 if (isTPADll(dllPath)) {
578                         baseAddr = getNextBaseAddr();
579                 }
580 #endif
581
582                 // fork crossgen2
583                 pid_t pid = fork();
584                 if (pid == -1)
585                         return NI_ERROR_UNKNOWN;
586
587                 if (pid > 0) {
588                         int status;
589                         waitpid(pid, &status, 0);
590                         if (WIFEXITED(status)) {
591                                 ni_error_e ret = crossgen2PostAction(dllPath, niPath, opt);
592                                 if (ret != NI_ERROR_NONE) {
593                                         return ret;
594                                 }
595 #ifdef UNIQUE_DEFAULT_BASE_ADDR_SUPPORT
596                                 if (baseAddr != 0) {
597                                         updateBaseAddrFile(niPath, baseAddr);
598                                 }
599 #endif
600                         } else {
601                                 _SERR("Failed. Forked process terminated abnormally");
602                                 _SERR("Crossgen2 was terminated by the OOM killer. Please check the system.");
603                                 removeFile(changeExtension(niPath, ".ni.dll", ".ni.dll.tmp"));
604                                 return NI_ERROR_ABNORMAL_PROCESS_TERMINATION;
605                         }
606                 } else {
607                         std::vector<const char*> argv;
608                         makeArgs(argv, refPaths, opt);
609
610 #ifdef UNIQUE_DEFAULT_BASE_ADDR_SUPPORT
611                         std::string baseAddrString;
612                         if (baseAddr != 0) {
613                                 argv.push_back("--imagebase");
614                                 std::stringstream ss;
615                                 ss << "0x" << std::hex << baseAddr;
616                                 baseAddrString = ss.str();
617                                 argv.push_back(baseAddrString.c_str());
618                         }
619 #endif
620                         argv.push_back("-o");
621                         argv.push_back(niPath.c_str());
622
623                         argv.push_back(dllPath.c_str());
624                         _SOUT("+ %s", dllPath.c_str());
625
626                         // end param
627                         argv.push_back(nullptr);
628
629                         // print cmd
630                         if (opt->flags & NI_FLAGS_PRINT_CMD) {
631                                 _SOUT("==================== NI Commands =========================");
632                                 for (auto &arg: argv) _SOUT("+ %s", arg);
633                         }
634
635                         execv(CORERUN_CMD.c_str(), const_cast<char* const*>(argv.data()));
636
637                         clearArgs(argv);
638                         exit(0);
639                 }
640
641                 waitInterval();
642         }
643
644         return NI_ERROR_NONE;
645 }
646
647 static ni_error_e createCoreLibNI(NIOption* opt)
648 {
649         std::string coreLib = concatPath(__pm->getRuntimePath(), "System.Private.CoreLib.dll");
650         std::string niCoreLib = concatPath(__pm->getRuntimePath(), "System.Private.CoreLib.ni.dll");
651         std::string coreLibBackup = concatPath(__pm->getRuntimePath(), "System.Private.CoreLib.dll.Backup");
652
653         std::vector<std::string> dllList;
654         std::vector<std::string> refPaths;
655         dllList.push_back(getAbsolutePath(coreLib));
656
657         if (!isFile(coreLibBackup) && !isR2RImage(coreLib)) {
658                 if (crossgen2NoPipeLine(dllList, refPaths, opt) == NI_ERROR_NONE && exist(niCoreLib)) {
659                         if (rename(coreLib.c_str(), coreLibBackup.c_str())) {
660                                 _SERR("Failed to rename System.Private.CoreLib.dll");
661                                 return NI_ERROR_CORE_NI_FILE;
662                         }
663                         if (rename(niCoreLib.c_str(), coreLib.c_str())) {
664                                 _SERR("Failed to rename System.Private.CoreLib.ni.dll");
665                                 return NI_ERROR_CORE_NI_FILE;
666                         }
667                 } else {
668                         _SERR("Failed to create native image for %s", coreLib.c_str());
669                         return NI_ERROR_CORE_NI_FILE;
670                 }
671         }
672         return NI_ERROR_NONE;
673 }
674
675 static ni_error_e doAOTList(std::vector<std::string>& dllList, const std::string& refPaths, NIOption* opt)
676 {
677         ni_error_e ret = NI_ERROR_NONE;
678
679         if (dllList.empty()) {
680                 return NI_ERROR_INVALID_PARAMETER;
681         }
682         // When performing AOT for one Dll, an error is returned when an error occurs.
683         // However, when processing multiple dlls at once, only the log for errors is output and skipped.
684
685         std::string coreLib = concatPath(__pm->getRuntimePath(), "System.Private.CoreLib.dll");
686         bool hasSPC = false;
687
688         std::vector<std::string> niList;
689         for (auto it = dllList.begin(); it != dllList.end(); it++) {
690                 std::string f = *it;
691                 if (!isFile(f)) {
692                         _SERR("dll file is not exist : %s", f.c_str());
693                         dllList.erase(it--);
694                 }
695                 if (!isManagedAssembly(f)) {
696                         _SERR("Input file is not a dll file : %s", f.c_str());
697                         dllList.erase(it--);
698                 }
699                 // handle System.Private.CoreLib.dll separately.
700                 // dllList and path manager contain absolute path. So, there is no need to change path to absolute path
701                 if (f == coreLib) {
702                         hasSPC = true;
703                         dllList.erase(it--);
704                 } else {
705                         niList.push_back(changeExtension(f, ".dll", ".ni.dll"));
706                 }
707         }
708
709         // In the case of SPC, post-processing is required to change the name of the native image.
710         // In order to avoid repeatedly checking whether the generated native image is an SPC,
711         // the SPC native image generation is performed separately.
712         if (hasSPC) {
713                 ret = createCoreLibNI(opt);
714                 if (ret != NI_ERROR_NONE) {
715                         return ret;
716                 }
717         }
718
719         // if there is no proper input after processing dll list
720         if (dllList.empty()) {
721                 if (hasSPC) {
722                         return ret;
723                 } else {
724                         return NI_ERROR_INVALID_PARAMETER;
725                 }
726         }
727
728         std::vector<std::string> paths;
729         splitPath(refPaths, paths);
730
731         if (opt->flags & NI_FLAGS_NO_PIPELINE) {
732                 ret = crossgen2NoPipeLine(dllList, paths, opt);
733         } else {
734                 // When the forked process in the pipeline state is terminated(WIFSIGNALED(status)),
735                 // retry the generation of the native image
736                 // if the number of .dll files and the number of .ni.dll files are different.
737                 for (int callCnt = 0; callCnt < 2; callCnt++) {
738                         // If an error occurs, perform it twice with the same option.
739                         ret = crossgen2PipeLine(dllList, paths, opt);
740                         if (ret != NI_ERROR_NONE) {
741                                 _SERR("Crossgen2 is abnormally terminated. Regenerate native images that failed while running crossgen2.");
742                                 dllList.clear();
743                                 for (auto it = niList.begin(); it != niList.end(); it++) {
744                                         std::string niPath = *it;
745                                         std::string dllPath = changeExtension(niPath, ".ni.dll", ".dll");
746                                         if (crossgen2PostAction(dllPath, niPath, opt) != NI_ERROR_NONE) {
747                                                 dllList.push_back(dllPath);
748                                         } else {
749                                                 niList.erase(it--);
750                                         }
751                                 }
752                         } else {
753                                 break;
754                         }
755                 }
756                 // If an error occurs after two crossgen2PipeLine() attempts,
757                 // try crossgen2NoPipeLine() for the last time.
758                 if (ret != NI_ERROR_NONE) {
759                         _SERR("Retry running crossgen2 with --no-pipeline mode to avoid termination by OOM.");
760                         ret = crossgen2NoPipeLine(dllList, paths, opt);
761                 }
762         }
763
764         return ret;
765 }
766
767 static ni_error_e doAOTFile(const std::string& dllFile, const std::string& refPaths, NIOption* opt)
768 {
769         if (!isFile(dllFile)) {
770                 _SERR("dll file is not exist : %s", dllFile.c_str());
771                 return NI_ERROR_NO_SUCH_FILE;
772         }
773
774         if (!isManagedAssembly(dllFile)) {
775                 _SERR("Failed. Input parameter is not managed dll (%s)\n", dllFile.c_str());
776                 return NI_ERROR_INVALID_PARAMETER;
777         }
778
779         if (checkNIExistence(dllFile)) {
780                 _SERR("Native image file is already exist : %s", dllFile.c_str());
781                 return NI_ERROR_ALREADY_EXIST;
782         }
783
784         std::vector<std::string> dllList;
785         dllList.push_back(getAbsolutePath(dllFile));
786         return doAOTList(dllList, refPaths, opt);
787 }
788
789 // callback function of "pkgmgrinfo_appinfo_metadata_filter_foreach"
790 static int appAotCb(pkgmgrinfo_appinfo_h handle, void *userData)
791 {
792         char *pkgId = NULL;
793         int ret = 0;
794         NIOption **pOptions = (NIOption**)userData;
795
796         if ((*pOptions)->flags & NI_FLAGS_SKIP_RO_APP) {
797                 bool isSystem = false;
798                 int ret = pkgmgrinfo_appinfo_is_system(handle, &isSystem);
799                 if (ret != PMINFO_R_OK) {
800                         _SERR("Failed to check that app is System or not\n");
801                         return -1;
802                 }
803                 if (isSystem) {
804                         return 0;
805                 }
806         }
807
808         ret = pkgmgrinfo_appinfo_get_pkgid(handle, &pkgId);
809         if (ret != PMINFO_R_OK) {
810                 _SERR("Failed to get pkgid");
811                 return -1;
812         }
813
814         if (removeNIUnderPkgRoot(pkgId) != NI_ERROR_NONE) {
815                 _SERR("Failed to remove previous dlls from [%s]", pkgId);
816                 return -1;
817         }
818
819         if (createNIUnderPkgRoot(pkgId, *pOptions) != NI_ERROR_NONE) {
820                 _SERR("Failed to generate NI file [%s]", pkgId);
821                 return -1;
822         } else {
823                 _SOUT("Complete make application to native image");
824         }
825
826         return 0;
827 }
828
829 ni_error_e initNICommon()
830 {
831 #if defined(__arm__) || defined(__aarch64__)
832
833         char *env = nullptr;
834         env = getenv("MIC_CROSSGEN2_ENABLED");
835         if (env != nullptr && !strcmp(env, "1")) {
836                 CORERUN_CMD = std::string("/opt/usr/dotnet/mic/crossgen2");
837                 CROSSGEN2_PATH = "";
838                 CLRJIT_PATH = std::string("/opt/usr/dotnet/mic/libclrjit_unix_") + ARCHITECTURE_IDENTIFIER + std::string("_x64.so");
839         }
840
841         // get interval value
842         const static std::string intervalFile = concatPath(__NATIVE_LIB_DIR, "crossgen_interval.txt");
843         std::ifstream inFile(intervalFile);
844         if (inFile) {
845                 _SOUT("crossgen_interval.txt is found");
846                 inFile >> __interval;
847         }
848
849         if (initializePluginManager("normal")) {
850                 _SERR("Fail to initialize PluginManager");
851                 return NI_ERROR_UNKNOWN;
852         }
853
854         try {
855                 __pm = new PathManager();
856         } catch (const std::exception& e) {
857                 _SERR("Failed to create PathManager");
858                 return NI_ERROR_UNKNOWN;
859         }
860
861         char* pluginDllPaths = pluginGetDllPath();
862         if (pluginDllPaths && pluginDllPaths[0] != '\0') {
863                 __pm->addPlatformAssembliesPaths(pluginDllPaths, true);
864         }
865
866         char* pluginNativePaths = pluginGetNativeDllSearchingPath();
867         if (pluginNativePaths && pluginNativePaths[0] != '\0') {
868                 __pm->addNativeDllSearchingPaths(pluginNativePaths, true);
869         }
870
871         return NI_ERROR_NONE;
872 #else
873         _SERR("crossgen supports arm/arm64 architecture only. skip ni file generation");
874         return NI_ERROR_NOT_SUPPORTED;
875 #endif
876 }
877
878 void finalizeNICommon()
879 {
880         __interval = 0;
881
882         finalizePluginManager();
883
884         delete(__pm);
885         __pm = nullptr;
886
887         if (__ni_option) {
888                 free(__ni_option);
889                 __ni_option = nullptr;
890         }
891 }
892
893 ni_error_e createNIPlatform(NIOption* opt)
894 {
895         ni_error_e ret = createNIUnderDirs(__pm->getRuntimePath(), opt);
896         if (ret != NI_ERROR_NONE) {
897                 return ret;
898         }
899
900         return createNIUnderDirs(__pm->getTizenFXPath(), opt);
901 }
902
903 ni_error_e createNIDll(const std::string& dllPath, NIOption* opt)
904 {
905         return doAOTFile(dllPath, std::string(), opt);
906 }
907
908 ni_error_e createNIUnderTAC(const std::string& targetPath, const std::string& refPaths, NIOption* opt)
909 {
910         ni_error_e ret;
911
912         // get managed file list from targetPath
913         std::vector<std::string> dllList;
914         ret = getTargetDllList(targetPath, dllList);
915         if (ret != NI_ERROR_NONE) {
916                 return ret;
917         }
918
919         std::vector<std::string> needNIList;
920         std::vector<std::string> niList;
921
922         for (auto &dll : dllList) {
923                 if (!checkNIExistence(dll)) {
924                         needNIList.push_back(dll);
925                 }
926                 niList.push_back(getNIFilePath(dll));
927         }
928
929         if (!needNIList.empty()) {
930                 // NI fils of TAC-related dlls under /opt/usr/dotnet should not be created under .native_image directory.
931                 // So, unset NI_FLAGS_APPNI temporally and restore it after running AOT.
932                 opt->flags &= ~NI_FLAGS_APPNI;
933                 ret = doAOTList(needNIList, refPaths, opt);
934                 opt->flags |= NI_FLAGS_APPNI;
935                 if (ret != NI_ERROR_NONE) {
936                         return ret;
937                 }
938         }
939
940         for (auto &niPath : niList) {
941                 if (exist(niPath)) {
942                         std::string symNIPath = concatPath(targetPath, getFileName(niPath));
943                         if (!exist(symNIPath)) {
944                                 bf::create_symlink(niPath, symNIPath);
945                                 copySmackAndOwnership(targetPath.c_str(), symNIPath.c_str(), true);
946                                 _SOUT("%s symbolic link file generated successfully.", symNIPath.c_str());
947                                 _INFO("%s symbolic link file generated successfully.", symNIPath.c_str());
948                         }
949                 }
950         }
951
952         return NI_ERROR_NONE;
953 }
954
955
956 ni_error_e createNIUnderDirs(const std::string& rootPaths, NIOption* opt)
957 {
958         ni_error_e ret = NI_ERROR_NONE;
959
960         std::vector<std::string> fileList;
961         std::vector<std::string> paths;
962         splitPath(rootPaths, paths);
963
964         for (const auto &path : paths) {
965                 if (!exist(path)) {
966                         continue;
967                 }
968
969                 if (path.find(TAC_SYMLINK_SUB_DIR) != std::string::npos) {
970                         ret = createNIUnderTAC(path, rootPaths, opt);
971                         if (ret != NI_ERROR_NONE) {
972                                 return ret;
973                         }
974                 } else if (opt->flags & NI_FLAGS_APPNI) {
975                         ret = getAppTargetDllList(path, fileList, opt);
976                         if (ret != NI_ERROR_NONE) {
977                                 return ret;
978                         }
979                 } else {
980                         ret = getTargetDllList(path, fileList);
981                         if (ret != NI_ERROR_NONE) {
982                                 return ret;
983                         }
984                 }
985         }
986
987         if (fileList.empty()) {
988                 return NI_ERROR_NONE;
989         }
990
991         return doAOTList(fileList, rootPaths, opt);
992 }
993
994 ni_error_e createNIUnderPkgRoot(const std::string& pkgId, NIOption* opt)
995 {
996         if (!isR2RImage(concatPath(__pm->getRuntimePath(), "System.Private.CoreLib.dll"))) {
997                 _SERR("The native image of System.Private.CoreLib does not exist.\n"
998                                 "Run the command to create the native image\n"
999                                 "# dotnettool --ni-dll /usr/share/dotnet.tizen/netcoreapp/System.Private.CoreLib.dll");
1000                 return NI_ERROR_CORE_NI_FILE;
1001         }
1002
1003         std::string rootPath = getRootPath(pkgId);
1004         if (rootPath.empty()) {
1005                 _SERR("Failed to get root path from [%s]", pkgId.c_str());
1006                 return NI_ERROR_INVALID_PACKAGE;
1007         }
1008
1009         __pm->setAppRootPath(rootPath);
1010
1011         char* extraDllPaths = pluginGetExtraDllPath();
1012         if (extraDllPaths && extraDllPaths[0] != '\0') {
1013                 opt->flags |= NI_FLAGS_EXTRA_REF;
1014                 splitPath(extraDllPaths, opt->extraRefPath);
1015         }
1016
1017         opt->flags |= NI_FLAGS_APPNI;
1018
1019         if (isReadOnlyArea(rootPath)) {
1020                 opt->flags |= NI_FLAGS_APP_UNDER_RO_AREA;
1021                 opt->flags |= NI_FLAGS_NO_PIPELINE;
1022                 _SERR("Only no-pipeline mode supported for RO app. Set no-pipeline option forcibly");
1023         } else {
1024                 opt->flags &= ~NI_FLAGS_APP_UNDER_RO_AREA;
1025         }
1026
1027         // create native image under bin and lib directory
1028         // tac directory is skipped in the createNIUnderDirs.
1029         return createNIUnderDirs(__pm->getAppPaths(), opt);
1030 }
1031
1032 void removeNIPlatform()
1033 {
1034         std::string coreLib = concatPath(__pm->getRuntimePath(), "System.Private.CoreLib.dll");
1035         std::string coreLibBackup = concatPath(__pm->getRuntimePath(), "System.Private.CoreLib.dll.Backup");
1036
1037         if (isR2RImage(coreLib)) {
1038                 if (!isFile(coreLibBackup)) {
1039                         return;
1040                 }
1041
1042                 if (remove(coreLib.c_str())) {
1043                         _SERR("Failed to remove System.Private.CoreLib native image file");
1044                 }
1045                 if (rename(coreLibBackup.c_str(), coreLib.c_str())) {
1046                         _SERR("Failed to rename System.Private.CoreLib.Backup to origin");
1047                 }
1048         }
1049
1050 #ifdef UNIQUE_DEFAULT_BASE_ADDR_SUPPORT
1051         if (isFile(__SYSTEM_BASE_FILE)) {
1052                 if (remove(__SYSTEM_BASE_FILE)) {
1053                         _SERR("Failed to remove %s", __SYSTEM_BASE_FILE);
1054                 }
1055         }
1056 #endif
1057
1058         removeNIUnderDirs(__pm->getRuntimePath() + ":" + __pm->getTizenFXPath());
1059 }
1060
1061 void removeNIUnderDirs(const std::string& rootPaths)
1062 {
1063         auto convert = [](const std::string& path, const std::string& filename) {
1064                 if (isNativeImage(path)) {
1065                         if (remove(path.c_str())) {
1066                                 _SERR("Failed to remove %s", path.c_str());
1067                         }
1068                 }
1069         };
1070
1071         std::vector<std::string> paths;
1072         splitPath(rootPaths, paths);
1073         for (const auto &path : paths) {
1074                 scanFilesInDirectory(path, convert, -1);
1075         }
1076 }
1077
1078 ni_error_e removeNIUnderPkgRoot(const std::string& pkgId)
1079 {
1080         std::string rootPath = getRootPath(pkgId);
1081         if (rootPath.empty()) {
1082                 _SERR("Failed to get root path from [%s]", pkgId.c_str());
1083                 return NI_ERROR_INVALID_PACKAGE;
1084         }
1085
1086         __pm->setAppRootPath(rootPath);
1087
1088         // getAppNIPaths returns bin/.native_image, lib/.native_image and .tac_symlink.
1089         std::string appNIPaths = __pm->getAppNIPaths();
1090         std::vector<std::string> paths;
1091         splitPath(appNIPaths, paths);
1092         for (const auto &path : paths) {
1093                 if (!isReadOnlyArea(path)) {
1094                         // Only the native image inside the TAC should be removed.
1095                         if (strstr(path.c_str(), TAC_SYMLINK_SUB_DIR) != NULL) {
1096                                 removeNIUnderDirs(path);
1097                         } else {
1098                                 if (isDirectory(path)) {
1099                                         if (!removeAll(path.c_str())) {
1100                                                 _SERR("Failed to remove app ni dir [%s]", path.c_str());
1101                                         }
1102                                 }
1103                         }
1104                 }
1105         }
1106
1107         // In special cases, the ni file may exist in the dll location.
1108         // The code below is to avoid this exceptional case.
1109         std::string appPaths = __pm->getAppPaths();
1110         splitPath(appPaths, paths);
1111         for (const auto &path : paths) {
1112                 if (isDirectory(path)) {
1113                         removeNIUnderDirs(path);
1114                 }
1115         }
1116
1117         return NI_ERROR_NONE;
1118 }
1119
1120 ni_error_e regenerateAppNI(NIOption* opt)
1121 {
1122         int ret = 0;
1123         pkgmgrinfo_appinfo_metadata_filter_h handle;
1124
1125         ret = pkgmgrinfo_appinfo_metadata_filter_create(&handle);
1126         if (ret != PMINFO_R_OK)
1127                 return NI_ERROR_UNKNOWN;
1128
1129         ret = pkgmgrinfo_appinfo_metadata_filter_add(handle, AOT_METADATA_KEY, METADATA_VALUE);
1130         if (ret != PMINFO_R_OK) {
1131                 pkgmgrinfo_appinfo_metadata_filter_destroy(handle);
1132                 return NI_ERROR_UNKNOWN;
1133         }
1134
1135         ret = pkgmgrMDFilterForeach(handle, appAotCb, &opt);
1136         if (ret != 0) {
1137                 pkgmgrinfo_appinfo_metadata_filter_destroy(handle);
1138                 return NI_ERROR_UNKNOWN;
1139         }
1140
1141         pkgmgrinfo_appinfo_metadata_filter_destroy(handle);
1142         return NI_ERROR_NONE;
1143 }
1144
1145 // callback function of "pkgmgrinfo_appinfo_metadata_filter_foreach"
1146 static int regenTacCb(pkgmgrinfo_appinfo_h handle, void *userData)
1147 {
1148         char *pkgId = NULL;
1149         NIOption **pOpt = (NIOption**)userData;
1150
1151         int ret = pkgmgrinfo_appinfo_get_pkgid(handle, &pkgId);
1152         if (ret != PMINFO_R_OK || pkgId == NULL) {
1153                 _SERR("Failed to get pkgid");
1154                 return -1;
1155         }
1156
1157         sqlite3 *tac_db = openDB(TAC_APP_LIST_DB);
1158         if (!tac_db) {
1159                 _SERR("Sqlite open error");
1160                 return -1;
1161         }
1162         sqlite3_exec(tac_db, "BEGIN;", NULL, NULL, NULL);
1163
1164         char *sql = sqlite3_mprintf("SELECT * FROM TAC WHERE PKGID = %Q;", pkgId);
1165         std::vector<std::string> nugets = selectDB(tac_db, sql);
1166         sqlite3_free(sql);
1167
1168         if (tac_db) {
1169                 closeDB(tac_db);
1170                 tac_db = NULL;
1171         }
1172
1173         std::string nugetPaths;
1174         for (const auto &nuget : nugets) {
1175                 if (!nugetPaths.empty()) {
1176                         nugetPaths += ":";
1177                 }
1178                 nugetPaths += concatPath(__DOTNET_DIR, nuget);
1179         }
1180
1181         for (auto& nuget : nugets) {
1182                 createNIUnderTAC(concatPath(__DOTNET_DIR, nuget), nugetPaths, *pOpt);
1183         }
1184
1185         return 0;
1186 }
1187
1188 ni_error_e regenerateTACNI(NIOption* opt)
1189 {
1190         removeNIUnderDirs(__DOTNET_DIR);
1191
1192         pkgmgrinfo_appinfo_metadata_filter_h handle;
1193         int ret = pkgmgrinfo_appinfo_metadata_filter_create(&handle);
1194         if (ret != PMINFO_R_OK) {
1195                 return NI_ERROR_UNKNOWN;
1196         }
1197
1198         ret = pkgmgrinfo_appinfo_metadata_filter_add(handle, TAC_METADATA_KEY, METADATA_VALUE);
1199         if (ret != PMINFO_R_OK) {
1200                 pkgmgrinfo_appinfo_metadata_filter_destroy(handle);
1201                 return NI_ERROR_UNKNOWN;
1202         }
1203
1204         ret = pkgmgrMDFilterForeach(handle, regenTacCb, &opt);
1205         if (ret != 0) {
1206                 pkgmgrinfo_appinfo_metadata_filter_destroy(handle);
1207                 return NI_ERROR_UNKNOWN;
1208         }
1209
1210         pkgmgrinfo_appinfo_metadata_filter_destroy(handle);
1211
1212         return NI_ERROR_NONE;
1213 }
1214
1215 static std::vector<uid_t> getUserIds()
1216 {
1217         std::vector<uid_t> list;
1218
1219         while (true) {
1220                 errno = 0; // so we can distinguish errors from no more entries
1221                 passwd* entry = getpwent();
1222                 if (!entry) {
1223                         if (errno) {
1224                                 _SERR("Error while getting userIDs");
1225                                 list.clear();
1226                                 return list;
1227                         }
1228                         break;
1229                 }
1230                 list.push_back(entry->pw_uid);
1231         }
1232         endpwent();
1233
1234         return list;
1235 }
1236
1237 static std::string getAppDataPath(const std::string& pkgId, uid_t uid)
1238 {
1239         std::string pDataFile;
1240
1241         tzplatform_set_user(uid);
1242
1243         const char* tzUserApp = tzplatform_getenv(TZ_USER_APP);
1244         if (tzUserApp != NULL) {
1245                 pDataFile = std::string(tzUserApp) + "/" + pkgId + "/data/";
1246         }
1247
1248         tzplatform_reset_user();
1249
1250         return pDataFile;
1251 }
1252
1253 ni_error_e removeAppProfileData(const std::string& pkgId)
1254 {
1255         if (pkgId.empty()) {
1256                 return NI_ERROR_INVALID_PARAMETER;
1257         }
1258
1259         std::vector<uid_t> uidList = getUserIds();
1260         for (auto& uid : uidList) {
1261                 // get data path from pkgid
1262                 std::string dataPath = getAppDataPath(pkgId, uid);
1263                 if (!dataPath.empty() && exist(dataPath)) {
1264                         std::string pDataFile = dataPath + PROFILE_BASENAME;
1265
1266                         if (exist(pDataFile)) {
1267                                 if (!removeFile(pDataFile)) {
1268                                         _SERR("Fail to remove profile data file (%s).", pDataFile.c_str());
1269                                         return NI_ERROR_UNKNOWN;
1270                                 }
1271                                 _SOUT("Profile data (%s) is removed successfully", pDataFile.c_str());
1272                         }
1273                 }
1274         }
1275
1276         return NI_ERROR_NONE;
1277 }
1278
1279 static int appTypeListCb(pkgmgrinfo_appinfo_h handle, void *user_data)
1280 {
1281         char *pkgId = NULL;
1282         int ret = pkgmgrinfo_appinfo_get_pkgid(handle, &pkgId);
1283         if (ret != PMINFO_R_OK || pkgId == NULL) {
1284                 _SERR("Fail to get pkgid");
1285                 return 0;
1286         }
1287
1288         if (removeAppProfileData(pkgId) != NI_ERROR_NONE) {
1289                 _SERR("Fail to remove profile data for (%s)", pkgId);
1290         }
1291
1292         return 0;
1293 }
1294
1295 static ni_error_e removeAppProfileByAppType(const char* type)
1296 {
1297         int ret;
1298
1299         pkgmgrinfo_appinfo_filter_h filter;
1300
1301         ret = pkgmgrinfo_appinfo_filter_create(&filter);
1302         if (ret != PMINFO_R_OK) {
1303                 _SERR("Fail to create appinfo filter");
1304                 return NI_ERROR_UNKNOWN;
1305         }
1306
1307         ret = pkgmgrinfo_appinfo_filter_add_string(filter, PMINFO_APPINFO_PROP_APP_TYPE, type);
1308         if (ret != PMINFO_R_OK) {
1309                 pkgmgrinfo_appinfo_filter_destroy(filter);
1310                 _SERR("Fail to add appinfo filter (%s)", type);
1311                 return NI_ERROR_UNKNOWN;
1312         }
1313
1314         ret = pkgmgrinfo_appinfo_filter_foreach_appinfo(filter, appTypeListCb, NULL);
1315         if (ret != PMINFO_R_OK) {
1316                 _SERR("Fail to pkgmgrinfo_pkginfo_filter_foreach_pkginfo");
1317                 pkgmgrinfo_appinfo_filter_destroy(filter);
1318                 return NI_ERROR_UNKNOWN;
1319         }
1320
1321         pkgmgrinfo_appinfo_filter_destroy(filter);
1322
1323         return NI_ERROR_NONE;
1324 }
1325
1326 void removeAllAppProfileData()
1327 {
1328         std::vector<const char*> appTypeList = {"dotnet", "dotnet-nui", "dotnet-inhouse"};
1329
1330         for (auto& type : appTypeList) {
1331                 if (removeAppProfileByAppType(type) != NI_ERROR_NONE) {
1332                         _SERR("Fail to removeAppProfileByAppType for type (%s)", type);
1333                 }
1334         }
1335 }