Renew InputBubble Option (#416)
[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
389         //args.push_back(OPT_PARALLELISM);
390         //args.push_back(OPT_PARALLELISM_COUNT);
391         args.push_back(CROSSGEN_OPT_RESILIENT);
392
393         args.push_back(CROSSGEN_OPT_OPTIMIZE_TIME);
394
395         if (opt->flags & NI_FLAGS_INPUT_BUBBLE) {
396                 args.push_back(CROSSGEN_OPT_INPUTBUBBLE);
397                 args.push_back(CROSSGEN_OPT_COMPILE_BUBBLE_GENERICS);
398
399                 INPUTBUBBLE_REF_VECTOR.clear();
400                 for (const auto &path : opt->inputBubbleRefFiles) {
401                         INPUTBUBBLE_REF_VECTOR.push_back("--inputbubbleref:" + path);
402                 }
403                 for (const auto &path : INPUTBUBBLE_REF_VECTOR) {
404                         if (find(args.begin(), args.end(), path) == args.end()) {
405                                 args.push_back(path.c_str());
406                         }
407                 }
408         }
409
410         if (opt->flags & NI_FLAGS_MIBC) {
411                 MIBC_VECTOR.clear();
412                 for (const auto &path : opt->mibcPath) {
413                         MIBC_VECTOR.push_back("--mibc:" + path);
414                 }
415                 for (const auto &path : MIBC_VECTOR) {
416                         if (find(args.begin(), args.end(), path) == args.end()) {
417                                 args.push_back(path.c_str());
418                         }
419                 }
420         }
421
422         if (opt->flags & NI_FLAGS_VERBOSE) {
423                 args.push_back(CROSSGEN_OPT_VERBOSE);
424         }
425
426         REF_VECTOR.clear();
427
428         // set reference path
429         for (const auto &path : opt->refFiles) {
430                 REF_VECTOR.push_back("-r:" + path);
431         }
432
433         std::vector<std::string> paths = __pm->getPlatformAssembliesPaths();
434         for (const auto &path : paths) {
435                 if (checkDllExistInDir(path)) {
436                         REF_VECTOR.push_back("-r:" + path + "/*.dll");
437                 }
438         }
439
440         if (opt->flags & NI_FLAGS_EXTRA_REF) {
441                 for (const auto &erPath : opt->extraRefPath) {
442                         std::string path = getAbsolutePath(erPath);
443                         if (checkDllExistInDir(path)) {
444                                 REF_VECTOR.push_back("-r:" + path + "/*.dll");
445                         }
446                 }
447         }
448
449         for (const auto &path : refPaths) {
450                 if (checkDllExistInDir(path)) {
451                         REF_VECTOR.push_back("-r:" + path + "/*.dll");
452                 }
453         }
454
455         for (const auto &path : REF_VECTOR) {
456                 if (find(args.begin(), args.end(), path) == args.end()) {
457                         args.push_back(path.c_str());
458                 }
459         }
460 }
461
462 static void clearArgs(std::vector<const char*>& args)
463 {
464         REF_VECTOR.clear();
465         args.clear();
466 }
467
468 static ni_error_e makePdbSymlinkForNI(std::string dllPath, std::string niPath)
469 {
470         std::string pdbPath = changeExtension(dllPath, ".dll", ".pdb");
471         try {
472                 if (exist(pdbPath)) {
473                         std::string targetPDBPath = changeExtension(niPath, ".ni.dll", ".pdb");
474                         if (!exist(targetPDBPath)) {
475                                 bf::create_symlink(pdbPath, targetPDBPath);
476                                 copySmackAndOwnership(pdbPath, targetPDBPath, true);
477                         }
478                 }
479         } catch (const bf::filesystem_error& error) {
480                 _SERR("Fail to create symlink for %s", pdbPath.c_str());
481                 return NI_ERROR_UNKNOWN;
482         }
483
484         return NI_ERROR_NONE;
485 }
486
487 static ni_error_e crossgen2PostAction(const std::string& dllPath, const std::string& niPath, NIOption* opt) {
488         std::string outFile = niPath;
489         if (!exist(outFile)) {
490                 return NI_ERROR_NO_SUCH_FILE;
491         }
492         copySmackAndOwnership(dllPath, outFile);
493
494         // if AppNI then move ni.dll file to .native_image and copy pdb to .native_image
495         if (opt->flags & NI_FLAGS_APPNI) {
496                 outFile = getAppNIFilePath(dllPath, opt);
497                 makePdbSymlinkForNI(dllPath, outFile);
498
499                 if (opt->flags & NI_FLAGS_INPUT_BUBBLE && opt->flags & NI_FLAGS_NO_PIPELINE) {
500                         outFile = outFile + ".tmp";
501                 }
502
503                 if (niPath != outFile) {
504                         moveFile(niPath, outFile);
505                 }
506         }
507
508         if (!(opt->flags & NI_FLAGS_INPUT_BUBBLE && opt->flags & NI_FLAGS_NO_PIPELINE)) {
509                 _SOUT("Native image %s generated successfully.", outFile.c_str());
510         }
511
512         return NI_ERROR_NONE;
513 }
514
515 static ni_error_e crossgen2PipeLine(const std::vector<std::string>& dllList, const std::vector<std::string>& refPaths, NIOption* opt)
516 {
517         // fork crossgen2
518         pid_t pid = fork();
519         if (pid == -1)
520                 return NI_ERROR_UNKNOWN;
521
522         if (pid > 0) {
523                 int status;
524                 waitpid(pid, &status, 0);
525                 if (WIFEXITED(status)) {
526                         for (auto& dllPath: dllList) {
527                                 ni_error_e ret = crossgen2PostAction(dllPath, changeExtension(dllPath, ".dll", ".ni.dll"), opt);
528                                 if (ret != NI_ERROR_NONE) {
529                                         return ret;
530                                 }
531                         }
532                 } else {
533                         _SERR("Failed. Forked process terminated abnormally");
534                         return NI_ERROR_ABNORMAL_PROCESS_TERMINATION;
535                 }
536         } else {
537                 std::vector<const char*> argv;
538                 makeArgs(argv, refPaths, opt);
539                 argv.push_back(CROSSGEN_OPT_OUT_NEAR_INPUT);
540                 argv.push_back(CROSSGEN_OPT_SINGLE_FILE_COMPILATION);
541
542                 // add input files at the end of parameter
543                 for (const auto &input : dllList) {
544                         argv.push_back(input.c_str());
545                         _SOUT("+ %s", input.c_str());
546                 }
547
548                 // end param
549                 argv.push_back(nullptr);
550
551                 // print cmd
552                 if (opt->flags & NI_FLAGS_PRINT_CMD) {
553                         _SOUT("==================== NI Commands =========================");
554                         for (auto &arg: argv) _SOUT("+ %s", arg);
555                 }
556
557                 execv(CORERUN_CMD.c_str(), const_cast<char* const*>(argv.data()));
558
559                 clearArgs(argv);
560                 exit(0);
561         }
562
563         return NI_ERROR_NONE;
564 }
565
566 static ni_error_e crossgen2NoPipeLine(const std::vector<std::string>& dllList, const std::vector<std::string>& refPaths, NIOption* opt)
567 {
568         for (auto& dllPath : dllList) {
569                 std::string niPath;
570                 if (opt->flags & NI_FLAGS_APPNI) {
571                         niPath = getAppNIFilePath(dllPath, opt);
572                 } else {
573                         niPath = getNIFilePath(dllPath);
574                 }
575 #ifdef UNIQUE_DEFAULT_BASE_ADDR_SUPPORT
576                 uintptr_t baseAddr = 0;
577                 if (isTPADll(dllPath)) {
578                         baseAddr = getNextBaseAddr();
579                 }
580 #endif
581                 if (opt->flags & NI_FLAGS_INPUT_BUBBLE) {
582                         niPath += ".tmp";
583                 }
584
585                 // fork crossgen2
586                 pid_t pid = fork();
587                 if (pid == -1)
588                         return NI_ERROR_UNKNOWN;
589
590                 if (pid > 0) {
591                         int status;
592                         waitpid(pid, &status, 0);
593                         if (WIFEXITED(status)) {
594                                 ni_error_e ret = crossgen2PostAction(dllPath, niPath, opt);
595                                 if (ret != NI_ERROR_NONE) {
596                                         return ret;
597                                 }
598 #ifdef UNIQUE_DEFAULT_BASE_ADDR_SUPPORT
599                                 if (baseAddr != 0) {
600                                         updateBaseAddrFile(niPath, baseAddr);
601                                 }
602 #endif
603                         } else {
604                                 _SERR("Failed. Forked process terminated abnormally");
605                                 _SERR("Crossgen2 was terminated by the OOM killer. Please check the system.");
606                                 removeFile(changeExtension(niPath, ".ni.dll", ".ni.dll.tmp"));
607                                 return NI_ERROR_ABNORMAL_PROCESS_TERMINATION;
608                         }
609                 } else {
610                         std::vector<const char*> argv;
611                         makeArgs(argv, refPaths, opt);
612
613 #ifdef UNIQUE_DEFAULT_BASE_ADDR_SUPPORT
614                         std::string baseAddrString;
615                         if (baseAddr != 0) {
616                                 argv.push_back("--imagebase");
617                                 std::stringstream ss;
618                                 ss << "0x" << std::hex << baseAddr;
619                                 baseAddrString = ss.str();
620                                 argv.push_back(baseAddrString.c_str());
621                         }
622 #endif
623                         argv.push_back("-o");
624                         argv.push_back(niPath.c_str());
625
626                         argv.push_back(dllPath.c_str());
627                         _SOUT("+ %s", dllPath.c_str());
628
629                         // end param
630                         argv.push_back(nullptr);
631
632                         // print cmd
633                         if (opt->flags & NI_FLAGS_PRINT_CMD) {
634                                 _SOUT("==================== NI Commands =========================");
635                                 for (auto &arg: argv) _SOUT("+ %s", arg);
636                         }
637
638                         execv(CORERUN_CMD.c_str(), const_cast<char* const*>(argv.data()));
639
640                         clearArgs(argv);
641                         exit(0);
642                 }
643
644                 waitInterval();
645         }
646
647         return NI_ERROR_NONE;
648 }
649
650 static ni_error_e createCoreLibNI(NIOption* opt)
651 {
652         std::string coreLib = concatPath(__pm->getRuntimePath(), "System.Private.CoreLib.dll");
653         std::string niCoreLib = concatPath(__pm->getRuntimePath(), "System.Private.CoreLib.ni.dll");
654         std::string niTmpCoreLib = concatPath(__pm->getRuntimePath(), "System.Private.CoreLib.ni.dll.tmp");
655         std::string coreLibBackup = concatPath(__pm->getRuntimePath(), "System.Private.CoreLib.dll.Backup");
656
657         std::vector<std::string> dllList;
658         std::vector<std::string> refPaths;
659         dllList.push_back(getAbsolutePath(coreLib));
660
661         if (!isFile(coreLibBackup) && !isR2RImage(coreLib)) {
662                 if (crossgen2NoPipeLine(dllList, refPaths, opt) == NI_ERROR_NONE) {
663                         if (rename(coreLib.c_str(), coreLibBackup.c_str())) {
664                                 _SERR("Failed to rename from System.Private.CoreLib.dll to System.Private.CoreLib.dll.Backup");
665                                 return NI_ERROR_CORE_NI_FILE;
666                         }
667                         if (opt->flags & NI_FLAGS_INPUT_BUBBLE) {
668                                 if (rename(niTmpCoreLib.c_str(), coreLib.c_str())) {
669                                         _SERR("Failed to rename from System.Private.CoreLib.ni.dll.tmp to Private.CoreLib.dll");
670                                         return NI_ERROR_CORE_NI_FILE;
671                                 }                               
672                         } else {
673                                 if (rename(niCoreLib.c_str(), coreLib.c_str())) {
674                                         _SERR("Failed to rename from System.Private.CoreLib.ni.dll to Private.CoreLib.dll");
675                                         return NI_ERROR_CORE_NI_FILE;
676                                 }
677                         }
678                 } else {
679                         _SERR("Failed to create native image for %s", coreLib.c_str());
680                         return NI_ERROR_CORE_NI_FILE;
681                 }
682         }
683         return NI_ERROR_NONE;
684 }
685
686 static ni_error_e doAOTList(std::vector<std::string>& dllList, const std::string& refPaths, NIOption* opt)
687 {
688         ni_error_e ret = NI_ERROR_NONE;
689
690         if (dllList.empty()) {
691                 return NI_ERROR_INVALID_PARAMETER;
692         }
693         // When performing AOT for one Dll, an error is returned when an error occurs.
694         // However, when processing multiple dlls at once, only the log for errors is output and skipped.
695
696         std::string coreLib = concatPath(__pm->getRuntimePath(), "System.Private.CoreLib.dll");
697         bool hasSPC = false;
698
699         std::vector<std::string> niList;
700         for (auto it = dllList.begin(); it != dllList.end(); it++) {
701                 std::string f = *it;
702                 if (!isFile(f)) {
703                         _SERR("dll file is not exist : %s", f.c_str());
704                         dllList.erase(it--);
705                 }
706                 if (!isManagedAssembly(f)) {
707                         _SERR("Input file is not a dll file : %s", f.c_str());
708                         dllList.erase(it--);
709                 }
710                 // handle System.Private.CoreLib.dll separately.
711                 // dllList and path manager contain absolute path. So, there is no need to change path to absolute path
712                 if (f == coreLib) {
713                         hasSPC = true;
714                         dllList.erase(it--);
715                 } else {
716                         niList.push_back(changeExtension(f, ".dll", ".ni.dll"));
717                 }
718         }
719
720         // In the case of SPC, post-processing is required to change the name of the native image.
721         // In order to avoid repeatedly checking whether the generated native image is an SPC,
722         // the SPC native image generation is performed separately.
723         if (hasSPC) {
724                 ret = createCoreLibNI(opt);
725                 if (ret != NI_ERROR_NONE) {
726                         return ret;
727                 }
728         }
729
730         // if there is no proper input after processing dll list
731         if (dllList.empty()) {
732                 if (hasSPC) {
733                         return ret;
734                 } else {
735                         return NI_ERROR_INVALID_PARAMETER;
736                 }
737         }
738
739         std::vector<std::string> paths;
740         splitPath(refPaths, paths);
741
742         if (opt->flags & NI_FLAGS_NO_PIPELINE) {
743                 ret = crossgen2NoPipeLine(dllList, paths, opt);
744         } else {
745                 std::vector<std::string> notCompiled;
746                 ret = crossgen2PipeLine(dllList, paths, opt);
747                 if (ret != NI_ERROR_NONE) {
748                         _SERR("Crossgen2 is abnormally terminated. Regenerate native images that failed while running crossgen2.");
749                         for (auto &dll : dllList) {
750                                 std::string tFile = changeExtension(dll, ".dll", ".ni.dll");
751                                 if (opt->flags & NI_FLAGS_INPUT_BUBBLE) {
752                                         tFile += ".tmp";
753                                 }
754                                 if (!exist(tFile)) {
755                                         notCompiled.push_back(dll);
756                                 }
757                         }
758                         _SERR("Retry running crossgen2 with --no-pipeline mode to avoid termination by OOM.");
759                         ret = crossgen2NoPipeLine(notCompiled, paths, opt);
760                 }
761         }
762
763         if (ret == NI_ERROR_NONE && opt->flags & NI_FLAGS_INPUT_BUBBLE) {
764                 for (auto &dll : dllList) {
765                         std::string tmpFile;
766                         std::string niFile;
767                         if (opt->flags & NI_FLAGS_APPNI) {
768                                 niFile = getAppNIFilePath(dll, opt);
769                         } else {
770                                 niFile = getNIFilePath(dll);
771                         }
772                         tmpFile = niFile + ".tmp";
773
774                         if (exist(tmpFile)) {
775                                 moveFile(tmpFile, niFile);
776                                 _SOUT("Native image %s generated successfully.", niFile.c_str());
777                         }
778                 }
779         }
780
781         return ret;
782 }
783
784 static ni_error_e doAOTFile(const std::string& dllFile, const std::string& refPaths, NIOption* opt)
785 {
786         if (!isFile(dllFile)) {
787                 _SERR("dll file is not exist : %s", dllFile.c_str());
788                 return NI_ERROR_NO_SUCH_FILE;
789         }
790
791         if (!isManagedAssembly(dllFile)) {
792                 _SERR("Failed. Input parameter is not managed dll (%s)\n", dllFile.c_str());
793                 return NI_ERROR_INVALID_PARAMETER;
794         }
795
796         if (checkNIExistence(dllFile)) {
797                 _SERR("Native image file is already exist : %s", dllFile.c_str());
798                 return NI_ERROR_ALREADY_EXIST;
799         }
800
801         std::vector<std::string> dllList;
802         dllList.push_back(getAbsolutePath(dllFile));
803         return doAOTList(dllList, refPaths, opt);
804 }
805
806 // callback function of "pkgmgrinfo_appinfo_metadata_filter_foreach"
807 static int appAotCb(pkgmgrinfo_appinfo_h handle, void *userData)
808 {
809         char *pkgId = NULL;
810         int ret = 0;
811         NIOption **pOptions = (NIOption**)userData;
812
813         if ((*pOptions)->flags & NI_FLAGS_SKIP_RO_APP) {
814                 bool isSystem = false;
815                 int ret = pkgmgrinfo_appinfo_is_system(handle, &isSystem);
816                 if (ret != PMINFO_R_OK) {
817                         _SERR("Failed to check that app is System or not\n");
818                         return -1;
819                 }
820                 if (isSystem) {
821                         return 0;
822                 }
823         }
824
825         ret = pkgmgrinfo_appinfo_get_pkgid(handle, &pkgId);
826         if (ret != PMINFO_R_OK) {
827                 _SERR("Failed to get pkgid");
828                 return -1;
829         }
830
831         if (removeNIUnderPkgRoot(pkgId) != NI_ERROR_NONE) {
832                 _SERR("Failed to remove previous dlls from [%s]", pkgId);
833                 return -1;
834         }
835
836         if (createNIUnderPkgRoot(pkgId, *pOptions) != NI_ERROR_NONE) {
837                 _SERR("Failed to generate NI file [%s]", pkgId);
838                 return -1;
839         } else {
840                 _SOUT("Complete make application to native image");
841         }
842
843         return 0;
844 }
845
846 ni_error_e initNICommon()
847 {
848 #if defined(__arm__) || defined(__aarch64__)
849
850         char *env = nullptr;
851         env = getenv("MIC_CROSSGEN2_ENABLED");
852         if (env != nullptr && !strcmp(env, "1")) {
853                 CORERUN_CMD = std::string("/opt/usr/dotnet/mic/crossgen2");
854                 CROSSGEN2_PATH = "";
855                 CLRJIT_PATH = std::string("/opt/usr/dotnet/mic/libclrjit_unix_") + ARCHITECTURE_IDENTIFIER + std::string("_x64.so");
856         }
857
858         // get interval value
859         const static std::string intervalFile = concatPath(__NATIVE_LIB_DIR, "crossgen_interval.txt");
860         std::ifstream inFile(intervalFile);
861         if (inFile) {
862                 _SOUT("crossgen_interval.txt is found");
863                 inFile >> __interval;
864         }
865
866         if (initializePluginManager("normal")) {
867                 _SERR("Fail to initialize PluginManager");
868                 return NI_ERROR_UNKNOWN;
869         }
870
871         try {
872                 __pm = new PathManager();
873         } catch (const std::exception& e) {
874                 _SERR("Failed to create PathManager");
875                 return NI_ERROR_UNKNOWN;
876         }
877
878         char* pluginDllPaths = pluginGetDllPath();
879         if (pluginDllPaths && pluginDllPaths[0] != '\0') {
880                 __pm->addPlatformAssembliesPaths(pluginDllPaths, true);
881         }
882
883         char* pluginNativePaths = pluginGetNativeDllSearchingPath();
884         if (pluginNativePaths && pluginNativePaths[0] != '\0') {
885                 __pm->addNativeDllSearchingPaths(pluginNativePaths, true);
886         }
887
888         return NI_ERROR_NONE;
889 #else
890         _SERR("crossgen supports arm/arm64 architecture only. skip ni file generation");
891         return NI_ERROR_NOT_SUPPORTED;
892 #endif
893 }
894
895 void finalizeNICommon()
896 {
897         __interval = 0;
898
899         finalizePluginManager();
900
901         delete(__pm);
902         __pm = nullptr;
903
904         if (__ni_option) {
905                 free(__ni_option);
906                 __ni_option = nullptr;
907         }
908 }
909
910 ni_error_e createNIPlatform(std::string& extraInputs, NIOption* opt)
911 {
912         extraInputs += ":" + __pm->getRuntimePath();
913         extraInputs += ":" + __pm->getTizenFXPath();
914
915         return createNIUnderDirs(extraInputs, opt);
916 }
917
918 ni_error_e createNIDll(const std::string& dllPath, NIOption* opt)
919 {
920         return doAOTFile(dllPath, std::string(), opt);
921 }
922
923 ni_error_e createNIUnderTAC(const std::string& targetPath, const std::string& refPaths, NIOption* opt)
924 {
925         ni_error_e ret;
926
927         bool isAppNI = false;
928         if (opt->flags & NI_FLAGS_APPNI) {
929                 isAppNI = true;
930         }
931
932         if (opt->flags & NI_FLAGS_INPUT_BUBBLE) {
933                 std::vector<std::string> refs;
934                 splitPath(refPaths, refs);
935                 for (auto &p: refs) {
936                         if (isDirectory(p) && checkDllExistInDir(p)) {
937                                 opt->inputBubbleRefFiles.push_back(p + "/*.dll");
938                         }
939                 }
940         }
941
942         // get managed file list from targetPath
943         std::vector<std::string> dllList;
944         ret = getTargetDllList(targetPath, dllList);
945         if (ret != NI_ERROR_NONE) {
946                 return ret;
947         }
948
949         std::vector<std::string> needNIList;
950         std::vector<std::string> niList;
951
952         for (auto &dll : dllList) {
953                 if (!checkNIExistence(dll)) {
954                         needNIList.push_back(dll);
955                 }
956                 niList.push_back(getNIFilePath(dll));
957         }
958
959         if (!needNIList.empty()) {
960                 // NI fils of TAC-related dlls under /opt/usr/dotnet should not be created under .native_image directory.
961                 // So, unset NI_FLAGS_APPNI temporally and restore it after running AOT.
962                 opt->flags &= ~NI_FLAGS_APPNI;
963                 ret = doAOTList(needNIList, refPaths, opt);
964                 if (isAppNI) {
965                         opt->flags |= NI_FLAGS_APPNI;
966                 }
967                 if (ret != NI_ERROR_NONE) {
968                         return ret;
969                 }
970         }
971
972         if (isAppNI) {
973                 for (auto &niPath : niList) {
974                         if (exist(niPath)) {
975                                 std::string symNIPath = concatPath(targetPath, getFileName(niPath));
976                                 if (!exist(symNIPath)) {
977                                         bf::create_symlink(niPath, symNIPath);
978                                         copySmackAndOwnership(targetPath.c_str(), symNIPath.c_str(), true);
979                                         _SOUT("%s symbolic link file generated successfully.", symNIPath.c_str());
980                                         _INFO("%s symbolic link file generated successfully.", symNIPath.c_str());
981                                 }
982                         }
983                 }
984         }
985
986         return NI_ERROR_NONE;
987 }
988
989
990 ni_error_e createNIUnderDirs(const std::string& rootPaths, NIOption* opt)
991 {
992         ni_error_e ret = NI_ERROR_NONE;
993
994         std::vector<std::string> fileList;
995         std::vector<std::string> paths;
996         splitPath(rootPaths, paths);
997
998         if (opt->flags & NI_FLAGS_INPUT_BUBBLE) {
999                 for (auto &p: paths) {
1000                         if (isDirectory(p) && checkDllExistInDir(p)) {
1001                                 opt->inputBubbleRefFiles.push_back(p + "/*.dll");
1002                         }
1003                 }
1004         }
1005
1006         for (const auto &path : paths) {
1007                 if (!exist(path)) {
1008                         continue;
1009                 }
1010
1011                 if (path.find(TAC_SYMLINK_SUB_DIR) != std::string::npos) {
1012                         ret = createNIUnderTAC(path, rootPaths, opt);
1013                         if (ret != NI_ERROR_NONE) {
1014                                 return ret;
1015                         }
1016                 } else if (opt->flags & NI_FLAGS_APPNI) {
1017                         ret = getAppTargetDllList(path, fileList, opt);
1018                         if (ret != NI_ERROR_NONE) {
1019                                 return ret;
1020                         }
1021                 } else {
1022                         ret = getTargetDllList(path, fileList);
1023                         if (ret != NI_ERROR_NONE) {
1024                                 return ret;
1025                         }
1026                 }
1027         }
1028
1029         if (fileList.empty()) {
1030                 return NI_ERROR_NONE;
1031         }
1032
1033         return doAOTList(fileList, rootPaths, opt);
1034 }
1035
1036 ni_error_e createNIUnderPkgRoot(const std::string& pkgId, NIOption* opt)
1037 {
1038         if (!isR2RImage(concatPath(__pm->getRuntimePath(), "System.Private.CoreLib.dll"))) {
1039                 _SERR("The native image of System.Private.CoreLib does not exist.\n"
1040                                 "Run the command to create the native image\n"
1041                                 "# dotnettool --ni-dll /usr/share/dotnet.tizen/netcoreapp/System.Private.CoreLib.dll");
1042                 return NI_ERROR_CORE_NI_FILE;
1043         }
1044
1045         std::string rootPath = getRootPath(pkgId);
1046         if (rootPath.empty()) {
1047                 _SERR("Failed to get root path from [%s]", pkgId.c_str());
1048                 return NI_ERROR_INVALID_PACKAGE;
1049         }
1050
1051         __pm->setAppRootPath(rootPath);
1052
1053         char* extraDllPaths = pluginGetExtraDllPath();
1054         if (extraDllPaths && extraDllPaths[0] != '\0') {
1055                 opt->flags |= NI_FLAGS_EXTRA_REF;
1056                 splitPath(extraDllPaths, opt->extraRefPath);
1057         }
1058
1059         opt->flags |= NI_FLAGS_APPNI;
1060
1061         if (isReadOnlyArea(rootPath)) {
1062                 opt->flags |= NI_FLAGS_APP_UNDER_RO_AREA;
1063                 opt->flags |= NI_FLAGS_NO_PIPELINE;
1064                 _SERR("Only no-pipeline mode supported for RO app. Set no-pipeline option forcibly");
1065         } else {
1066                 opt->flags &= ~NI_FLAGS_APP_UNDER_RO_AREA;
1067         }
1068
1069         // create native image under bin and lib directory
1070         // tac directory is skipped in the createNIUnderDirs.
1071         return createNIUnderDirs(__pm->getAppPaths(), opt);
1072 }
1073
1074 void removeNIPlatform()
1075 {
1076         std::string coreLib = concatPath(__pm->getRuntimePath(), "System.Private.CoreLib.dll");
1077         std::string coreLibBackup = concatPath(__pm->getRuntimePath(), "System.Private.CoreLib.dll.Backup");
1078
1079         if (isR2RImage(coreLib)) {
1080                 if (!isFile(coreLibBackup)) {
1081                         return;
1082                 }
1083
1084                 if (remove(coreLib.c_str())) {
1085                         _SERR("Failed to remove System.Private.CoreLib native image file");
1086                 }
1087                 if (rename(coreLibBackup.c_str(), coreLib.c_str())) {
1088                         _SERR("Failed to rename System.Private.CoreLib.Backup to origin");
1089                 }
1090         }
1091
1092 #ifdef UNIQUE_DEFAULT_BASE_ADDR_SUPPORT
1093         if (isFile(__SYSTEM_BASE_FILE)) {
1094                 if (remove(__SYSTEM_BASE_FILE)) {
1095                         _SERR("Failed to remove %s", __SYSTEM_BASE_FILE);
1096                 }
1097         }
1098 #endif
1099
1100         removeNIUnderDirs(__pm->getRuntimePath() + ":" + __pm->getTizenFXPath());
1101 }
1102
1103 void removeNIUnderDirs(const std::string& rootPaths)
1104 {
1105         auto convert = [](const std::string& path, const std::string& filename) {
1106                 if (isNativeImage(path)) {
1107                         if (remove(path.c_str())) {
1108                                 _SERR("Failed to remove %s", path.c_str());
1109                         }
1110                 }
1111         };
1112
1113         std::vector<std::string> paths;
1114         splitPath(rootPaths, paths);
1115         for (const auto &path : paths) {
1116                 scanFilesInDirectory(path, convert, -1);
1117         }
1118 }
1119
1120 ni_error_e removeNIUnderPkgRoot(const std::string& pkgId)
1121 {
1122         std::string rootPath = getRootPath(pkgId);
1123         if (rootPath.empty()) {
1124                 _SERR("Failed to get root path from [%s]", pkgId.c_str());
1125                 return NI_ERROR_INVALID_PACKAGE;
1126         }
1127
1128         __pm->setAppRootPath(rootPath);
1129
1130         // getAppNIPaths returns bin/.native_image, lib/.native_image and .tac_symlink.
1131         std::string appNIPaths = __pm->getAppNIPaths();
1132         std::vector<std::string> paths;
1133         splitPath(appNIPaths, paths);
1134         for (const auto &path : paths) {
1135                 if (!isReadOnlyArea(path)) {
1136                         // Only the native image inside the TAC should be removed.
1137                         if (strstr(path.c_str(), TAC_SYMLINK_SUB_DIR) != NULL) {
1138                                 removeNIUnderDirs(path);
1139                         } else {
1140                                 if (isDirectory(path)) {
1141                                         if (!removeAll(path.c_str())) {
1142                                                 _SERR("Failed to remove app ni dir [%s]", path.c_str());
1143                                         }
1144                                 }
1145                         }
1146                 }
1147         }
1148
1149         // In special cases, the ni file may exist in the dll location.
1150         // The code below is to avoid this exceptional case.
1151         std::string appPaths = __pm->getAppPaths();
1152         splitPath(appPaths, paths);
1153         for (const auto &path : paths) {
1154                 if (isDirectory(path)) {
1155                         removeNIUnderDirs(path);
1156                 }
1157         }
1158
1159         return NI_ERROR_NONE;
1160 }
1161
1162 ni_error_e regenerateAppNI(NIOption* opt)
1163 {
1164         int ret = 0;
1165         pkgmgrinfo_appinfo_metadata_filter_h handle;
1166
1167         ret = pkgmgrinfo_appinfo_metadata_filter_create(&handle);
1168         if (ret != PMINFO_R_OK)
1169                 return NI_ERROR_UNKNOWN;
1170
1171         ret = pkgmgrinfo_appinfo_metadata_filter_add(handle, AOT_METADATA_KEY, METADATA_VALUE);
1172         if (ret != PMINFO_R_OK) {
1173                 pkgmgrinfo_appinfo_metadata_filter_destroy(handle);
1174                 return NI_ERROR_UNKNOWN;
1175         }
1176
1177         ret = pkgmgrMDFilterForeach(handle, appAotCb, &opt);
1178         if (ret != 0) {
1179                 pkgmgrinfo_appinfo_metadata_filter_destroy(handle);
1180                 return NI_ERROR_UNKNOWN;
1181         }
1182
1183         pkgmgrinfo_appinfo_metadata_filter_destroy(handle);
1184         return NI_ERROR_NONE;
1185 }
1186
1187 // callback function of "pkgmgrinfo_appinfo_metadata_filter_foreach"
1188 static int regenTacCb(pkgmgrinfo_appinfo_h handle, void *userData)
1189 {
1190         char *pkgId = NULL;
1191         NIOption **pOpt = (NIOption**)userData;
1192
1193         int ret = pkgmgrinfo_appinfo_get_pkgid(handle, &pkgId);
1194         if (ret != PMINFO_R_OK || pkgId == NULL) {
1195                 _SERR("Failed to get pkgid");
1196                 return -1;
1197         }
1198
1199         sqlite3 *tac_db = openDB(TAC_APP_LIST_DB);
1200         if (!tac_db) {
1201                 _SERR("Sqlite open error");
1202                 return -1;
1203         }
1204         sqlite3_exec(tac_db, "BEGIN;", NULL, NULL, NULL);
1205
1206         char *sql = sqlite3_mprintf("SELECT * FROM TAC WHERE PKGID = %Q;", pkgId);
1207         std::vector<std::string> nugets = selectDB(tac_db, sql);
1208         sqlite3_free(sql);
1209
1210         if (tac_db) {
1211                 closeDB(tac_db);
1212                 tac_db = NULL;
1213         }
1214
1215         std::string nugetPaths;
1216         for (const auto &nuget : nugets) {
1217                 if (!nugetPaths.empty()) {
1218                         nugetPaths += ":";
1219                 }
1220                 nugetPaths += concatPath(__DOTNET_DIR, nuget);
1221         }
1222
1223         for (auto& nuget : nugets) {
1224                 createNIUnderTAC(concatPath(__DOTNET_DIR, nuget), nugetPaths, *pOpt);
1225         }
1226
1227         return 0;
1228 }
1229
1230 ni_error_e regenerateTACNI(NIOption* opt)
1231 {
1232         removeNIUnderDirs(__DOTNET_DIR);
1233
1234         pkgmgrinfo_appinfo_metadata_filter_h handle;
1235         int ret = pkgmgrinfo_appinfo_metadata_filter_create(&handle);
1236         if (ret != PMINFO_R_OK) {
1237                 return NI_ERROR_UNKNOWN;
1238         }
1239
1240         ret = pkgmgrinfo_appinfo_metadata_filter_add(handle, TAC_METADATA_KEY, METADATA_VALUE);
1241         if (ret != PMINFO_R_OK) {
1242                 pkgmgrinfo_appinfo_metadata_filter_destroy(handle);
1243                 return NI_ERROR_UNKNOWN;
1244         }
1245
1246         ret = pkgmgrMDFilterForeach(handle, regenTacCb, &opt);
1247         if (ret != 0) {
1248                 pkgmgrinfo_appinfo_metadata_filter_destroy(handle);
1249                 return NI_ERROR_UNKNOWN;
1250         }
1251
1252         pkgmgrinfo_appinfo_metadata_filter_destroy(handle);
1253
1254         return NI_ERROR_NONE;
1255 }
1256
1257 static std::vector<uid_t> getUserIds()
1258 {
1259         std::vector<uid_t> list;
1260
1261         while (true) {
1262                 errno = 0; // so we can distinguish errors from no more entries
1263                 passwd* entry = getpwent();
1264                 if (!entry) {
1265                         if (errno) {
1266                                 _SERR("Error while getting userIDs");
1267                                 list.clear();
1268                                 return list;
1269                         }
1270                         break;
1271                 }
1272                 list.push_back(entry->pw_uid);
1273         }
1274         endpwent();
1275
1276         return list;
1277 }
1278
1279 static std::string getAppDataPath(const std::string& pkgId, uid_t uid)
1280 {
1281         std::string pDataFile;
1282
1283         tzplatform_set_user(uid);
1284
1285         const char* tzUserApp = tzplatform_getenv(TZ_USER_APP);
1286         if (tzUserApp != NULL) {
1287                 pDataFile = std::string(tzUserApp) + "/" + pkgId + "/data/";
1288         }
1289
1290         tzplatform_reset_user();
1291
1292         return pDataFile;
1293 }
1294
1295 ni_error_e removeAppProfileData(const std::string& pkgId)
1296 {
1297         if (pkgId.empty()) {
1298                 return NI_ERROR_INVALID_PARAMETER;
1299         }
1300
1301         std::vector<uid_t> uidList = getUserIds();
1302         for (auto& uid : uidList) {
1303                 // get data path from pkgid
1304                 std::string dataPath = getAppDataPath(pkgId, uid);
1305                 if (!dataPath.empty() && exist(dataPath)) {
1306                         std::string pDataFile = dataPath + PROFILE_BASENAME;
1307
1308                         if (exist(pDataFile)) {
1309                                 if (!removeFile(pDataFile)) {
1310                                         _SERR("Fail to remove profile data file (%s).", pDataFile.c_str());
1311                                         return NI_ERROR_UNKNOWN;
1312                                 }
1313                                 _SOUT("Profile data (%s) is removed successfully", pDataFile.c_str());
1314                         }
1315                 }
1316         }
1317
1318         return NI_ERROR_NONE;
1319 }
1320
1321 static int appTypeListCb(pkgmgrinfo_appinfo_h handle, void *user_data)
1322 {
1323         char *pkgId = NULL;
1324         int ret = pkgmgrinfo_appinfo_get_pkgid(handle, &pkgId);
1325         if (ret != PMINFO_R_OK || pkgId == NULL) {
1326                 _SERR("Fail to get pkgid");
1327                 return 0;
1328         }
1329
1330         if (removeAppProfileData(pkgId) != NI_ERROR_NONE) {
1331                 _SERR("Fail to remove profile data for (%s)", pkgId);
1332         }
1333
1334         return 0;
1335 }
1336
1337 static ni_error_e removeAppProfileByAppType(const char* type)
1338 {
1339         int ret;
1340
1341         pkgmgrinfo_appinfo_filter_h filter;
1342
1343         ret = pkgmgrinfo_appinfo_filter_create(&filter);
1344         if (ret != PMINFO_R_OK) {
1345                 _SERR("Fail to create appinfo filter");
1346                 return NI_ERROR_UNKNOWN;
1347         }
1348
1349         ret = pkgmgrinfo_appinfo_filter_add_string(filter, PMINFO_APPINFO_PROP_APP_TYPE, type);
1350         if (ret != PMINFO_R_OK) {
1351                 pkgmgrinfo_appinfo_filter_destroy(filter);
1352                 _SERR("Fail to add appinfo filter (%s)", type);
1353                 return NI_ERROR_UNKNOWN;
1354         }
1355
1356         ret = pkgmgrinfo_appinfo_filter_foreach_appinfo(filter, appTypeListCb, NULL);
1357         if (ret != PMINFO_R_OK) {
1358                 _SERR("Fail to pkgmgrinfo_pkginfo_filter_foreach_pkginfo");
1359                 pkgmgrinfo_appinfo_filter_destroy(filter);
1360                 return NI_ERROR_UNKNOWN;
1361         }
1362
1363         pkgmgrinfo_appinfo_filter_destroy(filter);
1364
1365         return NI_ERROR_NONE;
1366 }
1367
1368 void removeAllAppProfileData()
1369 {
1370         std::vector<const char*> appTypeList = {"dotnet", "dotnet-nui", "dotnet-inhouse"};
1371
1372         for (auto& type : appTypeList) {
1373                 if (removeAppProfileByAppType(type) != NI_ERROR_NONE) {
1374                         _SERR("Fail to removeAppProfileByAppType for type (%s)", type);
1375                 }
1376         }
1377 }