24d5e48080de39ff1d4bbbfe4e800ee3577c957a
[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.)"
79                 "\n"
80                 "Usage: dotnettool [options] [command] [arguments]\n"
81                 "\n"
82                 "Example:\n"
83                 "1. Create native image for dlls and exes under platform directories\n"
84                 "   # dotnettool --ni-system\n"
85                 "2. Create native image for dll\n"
86                 "   # dotnettool --ni-dll /usr/bin/Tizen.Runtime.dll\n"
87                 "3. Create native image under the package's bin and lib directory\n"
88                 "   # dotnettool --ni-pkg org.tizen.FormsGallery\n"
89                 "4. Regenerate native images for all installed .net packages\n"
90                 "   # dotnettool --ni-regen-all-app\n"
91                 "5. Create native image for dll based on the Mibc data\n"
92                 "   # dotnettool --mibc /tmp/ibcdata/in.mibc --ni-dll /usr/bin/Tizen.Runtime.dll\n"
93                 "6. Remove profile for package\n"
94                 "   # dotnettool --rm-app-profile org.tizen.FormsGallery\n"
95                 "\n");
96 }
97
98 int main(int argc, char* argv[])
99 {
100         argc--;
101         argv++;
102
103         long starttime;
104         long endtime;
105         struct timeval tv;
106         gettimeofday(&tv, NULL);
107         starttime = tv.tv_sec * 1000l + tv.tv_usec / 1000l;
108
109         if (argc <= 0) {
110                 DisplayUsage();
111                 return -1;
112         }
113
114         NIOption* opt = getNIOption();
115         if (opt == nullptr) {
116                 _SERR("Fail to create option structure.");
117                 return -1;
118         }
119
120         std::vector<std::string> args;
121         for (int i = 0; i < argc; ++i) {
122                 std::string arg = argv[i];
123
124                 if ((arg == "-?") || (arg == "-h") || (arg == "--h")) {
125                         DisplayUsage();
126                         return 0;
127                 } else if (arg == "--verbose") {
128                         opt->flags |= NI_FLAGS_VERBOSE;
129                 } else if (arg == "--inputbubble") {
130                         opt->flags |= NI_FLAGS_INPUT_BUBBLE;
131                 } else if (arg == "--no-pipeline") {
132                         opt->flags |= NI_FLAGS_NO_PIPELINE;
133                 } else if (arg == "--print-cmd") {
134                         opt->flags |= NI_FLAGS_PRINT_CMD;
135                 } else if (arg == "--skip-ro-app") {
136                         opt->flags |= NI_FLAGS_SKIP_RO_APP;
137                 }  else if (arg == "--rm-origin-after-ni") {
138                         opt->flags |= NI_FLAGS_RM_ORIGIN_AFTER_NI;
139                 } else if (arg == "--mibc") {
140                         ++i;
141                         if (i >= argc) {
142                                 _SOUT("File path containing Mibc files should be followed for --mibc option");
143                                 DisplayUsage();
144                                 return 0;
145                         }
146
147                         opt->flags |= NI_FLAGS_MIBC;
148
149                         std::vector<std::string> paths;
150                         splitPath(std::string(argv[i]), paths);
151                         for (const auto &path : paths) {
152                                 if (!isFile(path) || isDirectory(path)) {
153                                         _SERR("Mibc file path is missing or does not exist");
154                                         return -1;
155                                 }
156                                 opt->mibcPath.push_back(path);
157                         }
158                 } else if (arg == "--inputbubbleref") {
159                         ++i;
160                         if (i >= argc) {
161                                 _SOUT("Path for references should be followed for --inputbubbleref option");
162                                 DisplayUsage();
163                                 return 0;
164                         }
165
166                         opt->flags |= NI_FLAGS_INPUT_BUBBLE_REF;
167
168                         std::vector<std::string> files;
169                         splitPath(std::string(argv[i]), files);
170                         for (const auto &f : files) {
171                                 opt->inputBubbleRefFiles.push_back(f);
172                         }
173                 } else if (arg == "--ref") {
174                         ++i;
175                         if (i >= argc) {
176                                 _SOUT("Path for references should be followed for --ref option");
177                                 DisplayUsage();
178                                 return 0;
179                         }
180
181                         std::vector<std::string> files;
182                         splitPath(std::string(argv[i]), files);
183                         for (const auto &f : files) {
184                                 opt->refFiles.push_back(f);
185                         }
186                 } else {
187                         args.push_back(arg);
188                 }
189         }
190
191         if (opt->flags & NI_FLAGS_INPUT_BUBBLE_REF && !(opt->flags & NI_FLAGS_INPUT_BUBBLE)) {
192                 _SERR("--inputbubbleref option should be used with --inputbubble option");
193                 DisplayUsage();
194                 return -1;
195         }
196
197         if (initNICommon() != NI_ERROR_NONE) {
198                 return -1;
199         }
200
201         std::vector<std::string>::iterator it = args.begin();
202         std::string cmd = std::string(*it);
203         it = args.erase(it);
204
205         //sh-3.2# dotnettool --ni-system [AssemblyDirectory] [AssemblyDirectory] ...
206         if (cmd == "--ni-system") {
207                 std::string inputs;
208                 while (it != args.end()) {
209                         const std::string dir = std::string(*it);
210                         inputs = inputs + ":" + dir;
211                         it = args.erase(it);
212                 }
213                 int ret = createNIPlatform(inputs, opt);
214                 if (ret != NI_ERROR_NONE) {
215                         _SERR("Failed to generate system NI");
216                 }
217         }
218         //sh-3.2# dotnettool --ni-dll [assemblyPath] [assemblyPath] ...
219         else if (cmd == "--ni-dll") {
220                 if (args.size() < 1) {
221                         _SERR("DLL path is missing");
222                 }
223                 std::vector<std::string> inputs;
224                 while (it != args.end()) {
225                         std::string dll = std::string(*it);
226                         inputs.push_back(dll);
227                         opt->refFiles.push_back(dll);
228                         if (opt->flags & NI_FLAGS_INPUT_BUBBLE) {
229                                 opt->inputBubbleRefFiles.push_back(dll);
230                         }
231                         it = args.erase(it);
232                 }
233
234                 for (auto &dll : inputs) {
235                         int ret = createNIDll(dll, opt);
236                         if (ret != NI_ERROR_NONE && ret != NI_ERROR_ALREADY_EXIST) {
237                                 _SERR("Failed to generate NI file [%s]", dll.c_str());
238                                 break;
239                         }
240                 }
241         }
242         //sh-3.2# dotnettool --ni-pkg [pkgId] [pkgId] ...
243         else if (cmd == "--ni-pkg") {
244                 if (opt->flags & NI_FLAGS_RM_ORIGIN_AFTER_NI) {
245                         _SERR("App AOTC options cannot be used with --rm-origin-after-ni option");
246                         DisplayUsage();
247                         return -1;
248                 }
249
250                 if (args.size() < 1) {
251                         _SERR("Package name is missing");
252                 }
253                 while (it != args.end()) {
254                         std::string pkg = std::string(*it);
255                         int ret = createNIUnderPkgRoot(pkg, opt);
256                         if (ret != NI_ERROR_NONE) {
257                                 _SERR("Failed to generate app NI [%s]", pkg.c_str());
258                                 break;
259                         }
260                         it = args.erase(it);
261                 }
262         }
263         //sh-3.2# dotnettool --ni-dir [AssemblyDirectory] [AssemblyDirectory] ...
264         else if (cmd == "--ni-dir") {
265                 if (args.size() < 1) {
266                         _SERR("Directory path is missing");
267                 }
268                 std::string dir;
269                 while (it != args.end()) {
270                         if (!dir.empty()) {
271                                 dir += std::string(":");
272                         }
273                         dir += std::string(*it);
274                         it = args.erase(it);
275                 }
276                 if (createNIUnderDirs(dir, opt) != NI_ERROR_NONE) {
277                         _SERR("Failed to generate NI directory");
278                 }
279         }
280         //sh-3.2# dotnettool --ni-reset-system
281         else if (cmd == "--ni-reset-system") {
282                 removeNIPlatform();
283         }
284         //sh-3.2# dotnettool --ni-reset-pkg [pkgId] [pkgId] ...
285         else if (cmd == "--ni-reset-pkg") {
286                 if (args.size() < 1) {
287                         _SERR("Package name is missing");
288                 }
289                 while (it != args.end()) {
290                         std::string pkg = std::string(*it);
291                         int ret = removeNIUnderPkgRoot(pkg);
292                         if (ret != NI_ERROR_NONE) {
293                                 _SERR("Failed to remove dlls for given package [%s]", pkg.c_str());
294                                 break;
295                         }
296                         it = args.erase(it);
297                 }
298         }
299         //sh-3.2# dotnettool --ni-reset-dir [AssemblyDirectory] [AssemblyDirectory] ...
300         else if (cmd == "--ni-reset-dir") {
301                 if (args.size() < 1) {
302                         _SERR("Directory path is missing");
303                 }
304                 while (it != args.end()) {
305                         const std::string dir = std::string(*it);
306                         removeNIUnderDirs(dir);
307                         it = args.erase(it);
308                 }
309         }
310         //sh-3.2# dotnettool --ni-regen-all-app
311         else if (cmd == "--ni-regen-all-app") {
312                 if (opt->flags & NI_FLAGS_RM_ORIGIN_AFTER_NI) {
313                         _SERR("App AOTC options cannot be used with --rm-origin-after-ni option");
314                         DisplayUsage();
315                         return -1;
316                 }
317
318                 int ret = regenerateAppNI(opt);
319                 if (ret != NI_ERROR_NONE) {
320                         _SERR("Failed to regenerate all app NI");
321                 }
322         }
323         //sh-3.2# dotnettool --tac-regen-all
324         else if (cmd == "--tac-regen-all") {
325                 if (opt->flags & NI_FLAGS_RM_ORIGIN_AFTER_NI) {
326                         _SERR("App AOTC options cannot be used with --rm-origin-after-ni option");
327                         DisplayUsage();
328                         return -1;
329                 }
330
331                 int ret = regenerateTACNI(opt);
332                 if (ret != NI_ERROR_NONE) {
333                         _SERR("Failed to regenerate all TAC");
334                 }
335         }
336         //sh-3.2# dotnettool --tac-restore-db
337         else if (cmd == "--tac-restore-db") {
338                 int ret = tac_restoreDB();
339                 if (ret != TAC_ERROR_NONE) {
340                         _SERR("Failed to restore TAC db");
341                 }
342                 ret = tlc_restoreDB();
343                 if (ret != TAC_ERROR_NONE) {
344                         _SERR("Failed to restore TLC db");
345                 }
346         }
347         //sh-3.2# dotnettool --tac-enable-pkg [pkgId] [pkgId] ...
348         else if (cmd == "--tac-enable-pkg") {
349                 if (args.size() < 1) {
350                         _SERR("Package name is missing");
351                 }
352                 while (it != args.end()) {
353                         std::string pkg = std::string(*it);
354                         int ret = enableTACPackage(pkg);
355                         if (ret != TAC_ERROR_NONE) {
356                                 _SERR("Failed to enable tac [%s]", pkg.c_str());
357                                 break;
358                         }
359                         it = args.erase(it);
360                 }
361         }
362         //sh-3.2# dotnettool --tac-disable-pkg [pkgId] [pkgId] ...
363         else if (cmd == "--tac-disable-pkg") {
364                 if (args.size() < 1) {
365                         _SERR("Package name is missing");
366                 }
367                 while (it != args.end()) {
368                         std::string pkg = std::string(*it);
369                         int ret = disableTACPackage(pkg);
370                         if (ret != TAC_ERROR_NONE) {
371                                 _SERR("Failed to disable tac [%s]", pkg.c_str());
372                                 break;
373                         }
374                         it = args.erase(it);
375                 }
376         }
377         //sh-3.2# dotnettool --resolve-all-app
378         else if (cmd == "--resolve-all-app") {
379                 int ret = resolveAllApps();
380                 if (ret != 0) {
381                         _SERR("Failed to remove unused multi-targeting files");
382                 }
383         }
384         //sh-3.2# dotnettool --rm-app-profile [pkgId] [pkgId] ...
385         else if (cmd == "--rm-app-profile") {
386                 if (args.size() < 1) {
387                         _SERR("Package name is missing");
388                 }
389                 while (it != args.end()) {
390                         std::string pkg = std::string(*it);
391                         if (removeAppProfileData(pkg) != PROFILE_ERROR_NONE) {
392                                 _SERR("Failed to remove [%s] profile data", pkg.c_str());
393                         }
394                         it = args.erase(it);
395                 }
396         }
397         //sh-3.2# dotnettool --rm-all-app-profile
398         else if (cmd == "--rm-all-app-profile") {
399                 removeAllAppProfileData();
400         }
401         //sh-3.2# dotnettool --check-all-app-privilege
402         else if (cmd == "--check-all-app-privilege") {
403                 checkAllAppPrivilege();
404         }
405         else {
406                 _SERR("Unknown option [%s]", cmd.c_str());
407                 DisplayUsage();
408         }
409
410         finalizeNICommon();
411
412         gettimeofday(&tv, NULL);
413         endtime = tv.tv_sec * 1000l + tv.tv_usec / 1000l;
414         _SOUT("\nSpend time for dotnettool is [%d]ms", (int)(endtime - starttime));
415
416         return 0;
417 }