3e43773a8a92cae74c6fb19ac118f872c4cf3d65
[platform/core/dotnet/launcher.git] / NativeLauncher / tool / dotnettool.cc
1 /*
2  * Copyright (c) 2019 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 "utils.h"
18 #include "ni_common.h"
19 #include "tac_common.h"
20 #include "profile_common.h"
21 #include "privilege_common.h"
22 #include "multi_target_resolver.h"
23 #include "log.h"
24
25 #include <vector>
26 #include <cstring>
27 #include <string.h>
28 #include <stdlib.h>
29 #include <sys/time.h>
30 #include <app_common.h>
31
32 void DisplayUsage() {
33         _SOUT(
34                 "\n"
35                 "Dotnet Tool Version: 1.0\n"
36                 "\n"
37                 "Commands:\n"
38                 "       -h, --help                - Show this help message\n"
39                 "       --ni-system               - Create NI under System DLLs\n"
40                 "       --ni-dll                  - Create NI for DLL\n"
41                 "       --ni-pkg                  - Create NI for package\n"
42                 "                                   (If package is installed under RO area, NI files are generated under RW area)\n"
43                 "       --ni-dir                  - Create NI for directory\n"
44                 "       --ni-reset-system         - Remove System NI files\n"
45                 "       --ni-reset-pkg            - Remove App NI files\n"
46                 "       --ni-reset-dir            - Remove NI for directory\n"
47                 "       --ni-regen-all-app        - Re-generate All App NI files\n"
48                 "       --tac-regen-all           - Re-generate All TAC files\n"
49                 "       --tac-restore-db          - Restore TAC Database\n"
50                 "       --tac-disable-pkg         - Disable TAC for package\n"
51                 "       --tac-enable-pkg          - Enable TAC for package\n"
52                 "       --resolve-all-app         - Remove unused multi-targeting files of all apps\n"
53                 "                                   (this option is used for FOTA script or test)\n"
54                 "       --rm-app-profile          - Remove application profile of given packages for all users\n"
55                 "                                   (this option should be run as root)\n"
56                 "       --rm-all-app-profile      - Remove application profile of all packages for all users\n"
57                 "                                   (this option should be run as root)\n"
58                 "       --check-all-app-privilege - Chcek application privilege of all package\n"
59                 "                                   (this option should be run as root)\n"
60                 "\n"
61                 "Options:\n"
62                 "       --mibc                    - Specify Mibc files. Sepatated with ':'.\n"
63                 "       --verbose                 - Display verbose information\n"
64                 "       --inputbubble             - Compile input assemblies into one bubble with the assemblies described at --inputbubbleref option\n"
65                 "                                   Note!: If you do not have an accurate understanding of Bubble, do not use this option.\n"
66                 "                                          All assemblies in the bubble must be guaranteed to be compiled to the native image before execution.\n"
67                 "                                          If an uncompiled assembly is included in the bubble during execution, an unknown error may occur.\n"
68                 "                                          If --inputbubbleref option doesnot be set, only input files are included to bubble. \n"
69                 "       --inputbubbleref          - Input bubble reference file(s) to be added to bubble (used with --inputbubble option)\n"
70                 "       --ref                     - Reference file(s) for compilation\n"
71                 "                                   (system paths are set automatically.)\n"
72                 "       --no-pipeline             - Compile the dlls individually\n"
73                 "       --print-cmd               - Print command and options\n"
74                 "       --skip-ro-app             - Skip re-generate NI for apps installed RO area\n"
75                 "                                   (This option works with --ni-regen-all-app only)\n"
76                 "       --rm-origin-after-ni      - Remove original dll after creating native image\n"
77                 "                                   Note!: App ATOC options(--ni-pkg, --ni-regen-all-app, --tac-regen-all) cannot be used with --rm-origin-after-ni option.\n"
78                 "                                   (Use only for assemblies that will not be AOTed again afterward.)\n"
79                 "       --set-priority            - Sets the priority of the process to the specified values from -20(highest priority) to 19(lowest priority).(default : 0)\n"
80
81                 "\n"
82                 "Usage: dotnettool [options] [command] [arguments]\n"
83                 "\n"
84                 "Example:\n"
85                 "1. Create native image for dlls and exes under platform directories\n"
86                 "   # dotnettool --ni-system\n"
87                 "2. Create native image for dll\n"
88                 "   # dotnettool --ni-dll /usr/bin/Tizen.Runtime.dll\n"
89                 "3. Create native image under the package's bin and lib directory\n"
90                 "   # dotnettool --ni-pkg org.tizen.FormsGallery\n"
91                 "4. Regenerate native images for all installed .net packages\n"
92                 "   # dotnettool --ni-regen-all-app\n"
93                 "5. Create native image for dll based on the Mibc data\n"
94                 "   # dotnettool --mibc /tmp/ibcdata/in.mibc --ni-dll /usr/bin/Tizen.Runtime.dll\n"
95                 "6. Remove profile for package\n"
96                 "   # dotnettool --rm-app-profile org.tizen.FormsGallery\n"
97                 "\n");
98 }
99
100 int main(int argc, char* argv[])
101 {
102         argc--;
103         argv++;
104
105         long starttime;
106         long endtime;
107         struct timeval tv;
108         gettimeofday(&tv, NULL);
109         starttime = tv.tv_sec * 1000l + tv.tv_usec / 1000l;
110
111         if (argc <= 0) {
112                 DisplayUsage();
113                 return -1;
114         }
115
116         NIOption* opt = getNIOption();
117         if (opt == nullptr) {
118                 _SERR("Fail to create option structure.");
119                 return -1;
120         }
121
122         std::vector<std::string> args;
123         for (int i = 0; i < argc; ++i) {
124                 std::string arg = argv[i];
125
126                 if ((arg == "-?") || (arg == "-h") || (arg == "--h")) {
127                         DisplayUsage();
128                         return 0;
129                 } else if (arg == "--verbose") {
130                         opt->flags |= NI_FLAGS_VERBOSE;
131                 } else if (arg == "--inputbubble") {
132                         opt->flags |= NI_FLAGS_INPUT_BUBBLE;
133                 } else if (arg == "--no-pipeline") {
134                         opt->flags |= NI_FLAGS_NO_PIPELINE;
135                 } else if (arg == "--print-cmd") {
136                         opt->flags |= NI_FLAGS_PRINT_CMD;
137                 } else if (arg == "--skip-ro-app") {
138                         opt->flags |= NI_FLAGS_SKIP_RO_APP;
139                 }  else if (arg == "--rm-origin-after-ni") {
140                         opt->flags |= NI_FLAGS_RM_ORIGIN_AFTER_NI;
141                 } else if (arg == "--set-priority") {
142                         ++i;
143                         if (i >= argc) {
144                                 _SOUT("Priority value(-20 ~ 19) should be followed for --set-priority option");
145                                 DisplayUsage();
146                                 return 0;
147                         }
148
149                         opt->flags |= NI_FLAGS_SET_PRIORITY;
150                         try {
151                                 opt->priority = std::stoi(argv[i]);
152                                 setPriority(opt);
153                         } catch (...) {
154                                 _SERR("Invalid argument: %s", argv[i]);
155                                 DisplayUsage();
156                                 return 0;
157                         }
158                 } else if (arg == "--mibc") {
159                         ++i;
160                         if (i >= argc) {
161                                 _SOUT("File path containing Mibc files should be followed for --mibc option");
162                                 DisplayUsage();
163                                 return 0;
164                         }
165
166                         opt->flags |= NI_FLAGS_MIBC;
167
168                         std::vector<std::string> paths;
169                         splitPath(std::string(argv[i]), paths);
170                         for (const auto &path : paths) {
171                                 if (!isFile(path) || isDirectory(path)) {
172                                         _SERR("Mibc file path is missing or does not exist");
173                                         return -1;
174                                 }
175                                 opt->mibcPath.push_back(path);
176                         }
177                 } else if (arg == "--inputbubbleref") {
178                         ++i;
179                         if (i >= argc) {
180                                 _SOUT("Path for references should be followed for --inputbubbleref option");
181                                 DisplayUsage();
182                                 return 0;
183                         }
184
185                         opt->flags |= NI_FLAGS_INPUT_BUBBLE_REF;
186
187                         std::vector<std::string> files;
188                         splitPath(std::string(argv[i]), files);
189                         for (const auto &f : files) {
190                                 opt->inputBubbleRefFiles.push_back(f);
191                         }
192                 } else if (arg == "--ref") {
193                         ++i;
194                         if (i >= argc) {
195                                 _SOUT("Path for references should be followed for --ref option");
196                                 DisplayUsage();
197                                 return 0;
198                         }
199
200                         std::vector<std::string> files;
201                         splitPath(std::string(argv[i]), files);
202                         for (const auto &f : files) {
203                                 opt->refFiles.push_back(f);
204                         }
205                 } else {
206                         args.push_back(arg);
207                 }
208         }
209
210         if (args.size() == 0) {
211                 _SERR("The command is missing");
212                 DisplayUsage();
213                 return -1;
214         }
215
216         if (opt->flags & NI_FLAGS_INPUT_BUBBLE_REF && !(opt->flags & NI_FLAGS_INPUT_BUBBLE)) {
217                 _SERR("--inputbubbleref option should be used with --inputbubble option");
218                 DisplayUsage();
219                 return -1;
220         }
221
222         if (initNICommon() != NI_ERROR_NONE) {
223                 return -1;
224         }
225
226         std::vector<std::string>::iterator it = args.begin();
227         std::string cmd = std::string(*it);
228         it = args.erase(it);
229
230         //sh-3.2# dotnettool --ni-system [AssemblyDirectory] [AssemblyDirectory] ...
231         if (cmd == "--ni-system") {
232                 std::string inputs;
233                 while (it != args.end()) {
234                         const std::string dir = std::string(*it);
235                         inputs = inputs + ":" + dir;
236                         it = args.erase(it);
237                 }
238                 int ret = createNIPlatform(inputs, opt);
239                 if (ret != NI_ERROR_NONE) {
240                         _SERR("Failed to generate system NI");
241                 }
242         }
243         //sh-3.2# dotnettool --ni-dll [assemblyPath] [assemblyPath] ...
244         else if (cmd == "--ni-dll") {
245                 if (args.size() < 1) {
246                         _SERR("DLL path is missing");
247                 }
248                 std::vector<std::string> inputs;
249                 while (it != args.end()) {
250                         std::string dll = std::string(*it);
251                         inputs.push_back(dll);
252                         opt->refFiles.push_back(dll);
253                         if (opt->flags & NI_FLAGS_INPUT_BUBBLE) {
254                                 opt->inputBubbleRefFiles.push_back(dll);
255                         }
256                         it = args.erase(it);
257                 }
258
259                 for (auto &dll : inputs) {
260                         int ret = createNIDll(dll, opt);
261                         if (ret != NI_ERROR_NONE && ret != NI_ERROR_ALREADY_EXIST) {
262                                 _SERR("Failed to generate NI file [%s]", dll.c_str());
263                                 break;
264                         }
265                 }
266         }
267         //sh-3.2# dotnettool --ni-pkg [pkgId] [pkgId] ...
268         else if (cmd == "--ni-pkg") {
269                 if (opt->flags & NI_FLAGS_RM_ORIGIN_AFTER_NI) {
270                         _SERR("App AOTC options cannot be used with --rm-origin-after-ni option");
271                         DisplayUsage();
272                         return -1;
273                 }
274
275                 if (args.size() < 1) {
276                         _SERR("Package name is missing");
277                 }
278                 while (it != args.end()) {
279                         std::string pkg = std::string(*it);
280                         int ret = createNIUnderPkgRoot(pkg, opt);
281                         if (ret != NI_ERROR_NONE) {
282                                 _SERR("Failed to generate app NI [%s]", pkg.c_str());
283                                 break;
284                         }
285                         it = args.erase(it);
286                 }
287         }
288         //sh-3.2# dotnettool --ni-dir [AssemblyDirectory] [AssemblyDirectory] ...
289         else if (cmd == "--ni-dir") {
290                 if (args.size() < 1) {
291                         _SERR("Directory path is missing");
292                 }
293                 std::string dir;
294                 while (it != args.end()) {
295                         if (!dir.empty()) {
296                                 dir += std::string(":");
297                         }
298                         dir += std::string(*it);
299                         it = args.erase(it);
300                 }
301                 if (createNIUnderDirs(dir, opt) != NI_ERROR_NONE) {
302                         _SERR("Failed to generate NI directory");
303                 }
304         }
305         //sh-3.2# dotnettool --ni-reset-system
306         else if (cmd == "--ni-reset-system") {
307                 removeNIPlatform();
308         }
309         //sh-3.2# dotnettool --ni-reset-pkg [pkgId] [pkgId] ...
310         else if (cmd == "--ni-reset-pkg") {
311                 if (args.size() < 1) {
312                         _SERR("Package name is missing");
313                 }
314                 while (it != args.end()) {
315                         std::string pkg = std::string(*it);
316                         int ret = removeNIUnderPkgRoot(pkg);
317                         if (ret != NI_ERROR_NONE) {
318                                 _SERR("Failed to remove dlls for given package [%s]", pkg.c_str());
319                                 break;
320                         }
321                         it = args.erase(it);
322                 }
323         }
324         //sh-3.2# dotnettool --ni-reset-dir [AssemblyDirectory] [AssemblyDirectory] ...
325         else if (cmd == "--ni-reset-dir") {
326                 if (args.size() < 1) {
327                         _SERR("Directory path is missing");
328                 }
329                 while (it != args.end()) {
330                         const std::string dir = std::string(*it);
331                         removeNIUnderDirs(dir);
332                         it = args.erase(it);
333                 }
334         }
335         //sh-3.2# dotnettool --ni-regen-all-app
336         else if (cmd == "--ni-regen-all-app") {
337                 if (opt->flags & NI_FLAGS_RM_ORIGIN_AFTER_NI) {
338                         _SERR("App AOTC options cannot be used with --rm-origin-after-ni option");
339                         DisplayUsage();
340                         return -1;
341                 }
342
343                 int ret = regeneratePkgNI(opt);
344                 if (ret != NI_ERROR_NONE) {
345                         _SERR("Failed to regenerate all app NI");
346                 }
347         }
348         //sh-3.2# dotnettool --tac-regen-all
349         else if (cmd == "--tac-regen-all") {
350                 if (opt->flags & NI_FLAGS_RM_ORIGIN_AFTER_NI) {
351                         _SERR("App AOTC options cannot be used with --rm-origin-after-ni option");
352                         DisplayUsage();
353                         return -1;
354                 }
355
356                 int ret = regenerateTACNI(opt);
357                 if (ret != NI_ERROR_NONE) {
358                         _SERR("Failed to regenerate all TAC");
359                 }
360         }
361         //sh-3.2# dotnettool --tac-restore-db
362         else if (cmd == "--tac-restore-db") {
363                 int ret = tac_restoreDB();
364                 if (ret != TAC_ERROR_NONE) {
365                         _SERR("Failed to restore TAC db");
366                 }
367                 ret = tlc_restoreDB();
368                 if (ret != TAC_ERROR_NONE) {
369                         _SERR("Failed to restore TLC db");
370                 }
371         }
372         //sh-3.2# dotnettool --tac-enable-pkg [pkgId] [pkgId] ...
373         else if (cmd == "--tac-enable-pkg") {
374                 if (args.size() < 1) {
375                         _SERR("Package name is missing");
376                 }
377                 while (it != args.end()) {
378                         std::string pkg = std::string(*it);
379                         int ret = enableTACPackage(pkg);
380                         if (ret != TAC_ERROR_NONE) {
381                                 _SERR("Failed to enable tac [%s]", pkg.c_str());
382                                 break;
383                         }
384                         it = args.erase(it);
385                 }
386         }
387         //sh-3.2# dotnettool --tac-disable-pkg [pkgId] [pkgId] ...
388         else if (cmd == "--tac-disable-pkg") {
389                 if (args.size() < 1) {
390                         _SERR("Package name is missing");
391                 }
392                 while (it != args.end()) {
393                         std::string pkg = std::string(*it);
394                         int ret = disableTACPackage(pkg);
395                         if (ret != TAC_ERROR_NONE) {
396                                 _SERR("Failed to disable tac [%s]", pkg.c_str());
397                                 break;
398                         }
399                         it = args.erase(it);
400                 }
401         }
402         //sh-3.2# dotnettool --resolve-all-app
403         else if (cmd == "--resolve-all-app") {
404                 resolveAllApps();
405         }
406         //sh-3.2# dotnettool --rm-app-profile [pkgId] [pkgId] ...
407         else if (cmd == "--rm-app-profile") {
408                 if (args.size() < 1) {
409                         _SERR("Package name is missing");
410                 }
411                 while (it != args.end()) {
412                         std::string pkg = std::string(*it);
413                         if (removeAppProfileData(pkg) != PROFILE_ERROR_NONE) {
414                                 _SERR("Failed to remove [%s] profile data", pkg.c_str());
415                         }
416                         it = args.erase(it);
417                 }
418         }
419         //sh-3.2# dotnettool --rm-all-app-profile
420         else if (cmd == "--rm-all-app-profile") {
421                 removeAllAppProfileData();
422         }
423         //sh-3.2# dotnettool --check-all-app-privilege
424         else if (cmd == "--check-all-app-privilege") {
425                 checkAllAppPrivilege();
426         }
427         else {
428                 _SERR("Unknown option [%s]", cmd.c_str());
429                 DisplayUsage();
430         }
431
432         finalizeNICommon();
433
434         gettimeofday(&tv, NULL);
435         endtime = tv.tv_sec * 1000l + tv.tv_usec / 1000l;
436         int ms = (int)(endtime - starttime);
437         float sec = (float)(ms/1000);
438         _SOUT("\nSpend time for dotnettool is [%d]ms, [%.3f]sec", ms, sec);
439
440         return 0;
441 }