1 /*
2 * Copyright (c) 2020 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "command_parser.h"
17
18 #include <climits>
19 #include <cstdint>
20 #include <getopt.h>
21 #include <iostream>
22 #include <pthread.h>
23 #include <semaphore.h>
24
25 #include "adapter.h"
26 #include "appexecfwk_errors.h"
27 #include "bundle_info.h"
28 #include "bundle_inner_interface.h"
29 #include "bundle_manager.h"
30 #include "convert_utils.h"
31 #include "iproxy_client.h"
32 #include "ipc_skeleton.h"
33 #include "parameter.h"
34 #include "samgr_lite.h"
35 #include "securec.h"
36 #include "rpc_errno.h"
37
38 using namespace std;
39
40 namespace OHOS {
41 namespace {
42 const int32_t MIN_ARGUMENT_NUMBER = 2;
43 const int32_t MAX_ARGUMENT_NUMBER = 4;
44 const int32_t MAX_LOG_LEN = 1024;
45 const int32_t MAX_DUMP_LIST_NUMBER = 3;
46 const int32_t UDID_STRING_LEN = 64;
47 const uint32_t INITIAL_CBID = 1;
48
49 static sem_t g_sem;
50 static IClientProxy *g_bmsInnerClient = nullptr;
51 static InstallParam g_installParam = { .installLocation = 1, .keepData = false };
52
53 const std::string CMD_INSTALL = "install";
54 const std::string CMD_UNINSTALL = "uninstall";
55 const std::string CMD_DUMP = "dump";
56 const std::string CMD_ENABLE = "set";
57 const std::string CMD_GET_UDID = "getudid";
58
59 const std::string INSTALL_HELP_MESSAGE = "Usage: install hap-path [options]\n"
60 "Description:\n"
61 "\t--help|-h help menu\n"
62 "\t--happath|-p location of the hap to install\n";
63 const std::string UNINSTALL_HELP_MESSAGE = "Usage: uninstall bundle-name [options]\n"
64 "Description:\n"
65 "\t--help|-h help menu\n"
66 "\t--bundlename|-n name of the bundle to uninstall\n";
67 const std::string DUMP_HELP_MESSAGE = "Usage: dump [options]\n"
68 "Option Description:\n"
69 "\t--help|-h help menu\n"
70 "\t--list|-l app list\n"
71 "\t--bundlename|-n dump installed hap's info\n"
72 "\t--metadatakey|-m dump bundleNames match metaData key\n";
73 const std::string ENABLE_HELP_MESSAGE = "Usage: set [options]\n"
74 "Option Description:\n"
75 "\t--externalmode|-e status enable externalmode\n"
76 "\t--debugmode|-d status enable debugmode\n"
77 "\t--signmode|-s status enable signmode\n";
78
79 const std::string HELP_MESSAGE = INSTALL_HELP_MESSAGE + UNINSTALL_HELP_MESSAGE + DUMP_HELP_MESSAGE +
80 ENABLE_HELP_MESSAGE;
81 const std::string ERROR_COMMAND = "error command!\n";
82 const std::string ERROR_OPTION = "error option!\n";
83 const std::string ERROR_INSTALL_PATH = "invalid path!\n";
84 const std::string ERROR_EXTRA_PARAMETER = "extra parameter!\n";
85 const std::string ERROR_SEM_ERROR = "sem init failed!\n";
86 const std::string ERROR_DUMP_FAIL = "no bundle info!\n";
87 const std::string ERROR_DUMP_ERROR = "dump info error!\n";
88
89 const std::string SHORT_OPTIONS = "n:hlp:m:";
90 const struct option LONG_OPTIONS[] = {
91 {"help", no_argument, nullptr, 'h'},
92 {"list", no_argument, nullptr, 'l'},
93 {"bundlename", required_argument, nullptr, 'n'},
94 {"happath", required_argument, nullptr, 'p'},
95 {"metadatakey", required_argument, nullptr, 'm'},
96 {nullptr, 0, nullptr, 0}
97 };
98
99 #ifdef OHOS_DEBUG
100 const std::string ENABLE_SHORT_OPTIONS = "he:d:s:";
101 const struct option ENABLE_LONG_OPTIONS[] = {
102 {"help", no_argument, nullptr, 'h'},
103 {"externalmode", required_argument, nullptr, 'e'},
104 {"debugmode", required_argument, nullptr, 'd'},
105 {"signmode", required_argument, nullptr, 's'},
106 {nullptr, 0, nullptr, 0}
107 };
108 #endif
109
GetBmsInnerClient()110 IClientProxy *GetBmsInnerClient()
111 {
112 IUnknown *iUnknown = SAMGR_GetInstance()->GetFeatureApi(BMS_SERVICE, BMS_INNER_FEATURE);
113 if (iUnknown == nullptr) {
114 printf("get feature api fail!\n");
115 return nullptr;
116 }
117 IClientProxy *bmsClient = nullptr;
118 int result = iUnknown->QueryInterface(iUnknown, CLIENT_PROXY_VER, reinterpret_cast<void **>(&bmsClient));
119 if (result != 0) {
120 printf("query interface fail!\n");
121 return nullptr;
122 }
123 return bmsClient;
124 }
125 } // namespace
126
HandleCommands(int32_t argc,char * argv[]) const127 void CommandParser::HandleCommands(int32_t argc, char *argv[]) const
128 {
129 if (argc < MIN_ARGUMENT_NUMBER) {
130 printf("%s\n", HELP_MESSAGE.c_str());
131 return;
132 }
133 g_bmsInnerClient = GetBmsInnerClient();
134 std::string cmd = argv[1];
135 if (cmd == CMD_INSTALL) {
136 RunAsInstallCommand(argc, argv);
137 } else if (cmd == CMD_UNINSTALL) {
138 RunAsUninstallCommand(argc, argv);
139 } else if (cmd == CMD_DUMP) {
140 RunAsDumpCommand(argc, argv);
141 } else if (cmd == CMD_GET_UDID) {
142 RunAsGetUdidCommand(argc, argv);
143 #ifdef OHOS_DEBUG
144 } else if (cmd == CMD_ENABLE) {
145 RunAsEnableCommand(argc, argv);
146 #endif
147 } else {
148 printf("%s\n", (ERROR_COMMAND + HELP_MESSAGE).c_str());
149 }
150 }
151
ReceiveCallback(const uint8_t resultCode,const void * resultMessage)152 static void ReceiveCallback(const uint8_t resultCode, const void *resultMessage)
153 {
154 std::string strMessage = reinterpret_cast<const char *>(resultMessage);
155 if (!strMessage.empty()) {
156 printf("resultMessage is %s\n", strMessage.c_str());
157 }
158 sem_post(&g_sem);
159 }
160
BmToolDeathNotify(void * arg)161 static void BmToolDeathNotify(void *arg)
162 {
163 printf("error message: %s\n", "Bundle Manager Service is dead");
164 exit(-1);
165 }
166
RunAsInstallCommand(int32_t argc,char * argv[]) const167 void CommandParser::RunAsInstallCommand(int32_t argc, char *argv[]) const
168 {
169 if (argc > MAX_ARGUMENT_NUMBER) {
170 printf("%s\n", (ERROR_EXTRA_PARAMETER + INSTALL_HELP_MESSAGE).c_str());
171 return;
172 }
173
174 int32_t option;
175 char realPath[PATH_MAX + 1] = { 0 };
176 uint32_t cbId = INITIAL_CBID;
177 SvcIdentity sid = SAMGR_GetRemoteIdentity(BMS_SERVICE, BMS_INNER_FEATURE);
178 while ((option = getopt_long_only(argc, argv, SHORT_OPTIONS.c_str(), LONG_OPTIONS, nullptr)) != -1) {
179 switch (option) {
180 case 'h':
181 printf("%s\n", INSTALL_HELP_MESSAGE.c_str());
182 break;
183 case 'p':
184 if (sem_init(&g_sem, 0, 0)) {
185 printf("error message: %s\n", ERROR_SEM_ERROR.c_str());
186 return;
187 }
188 if (optarg == nullptr || strlen(optarg) > PATH_MAX) {
189 printf("error message: %s\n", ERROR_INSTALL_PATH.c_str());
190 return;
191 }
192 if (realpath(optarg, realPath) == nullptr) {
193 printf("error message: %s\n", ERROR_INSTALL_PATH.c_str());
194 return;
195 }
196 if (AddDeathRecipient(sid, BmToolDeathNotify, nullptr, &cbId) != ERR_NONE) {
197 printf("error message: %s\n", "death callback is registered unsuccessfully");
198 return;
199 }
200 Install(realPath, &g_installParam, ReceiveCallback);
201 sem_wait(&g_sem);
202 break;
203 default:
204 printf("%s\n", (ERROR_OPTION + INSTALL_HELP_MESSAGE).c_str());
205 break;
206 }
207 }
208 }
209
RunAsUninstallCommand(int32_t argc,char * argv[]) const210 void CommandParser::RunAsUninstallCommand(int32_t argc, char *argv[]) const
211 {
212 if (argc > MAX_ARGUMENT_NUMBER) {
213 printf("%s\n", (ERROR_EXTRA_PARAMETER + UNINSTALL_HELP_MESSAGE).c_str());
214 return;
215 }
216
217 int32_t option;
218 uint32_t cbId = INITIAL_CBID;
219 SvcIdentity sid = SAMGR_GetRemoteIdentity(BMS_SERVICE, BMS_INNER_FEATURE);
220 while ((option = getopt_long_only(argc, argv, SHORT_OPTIONS.c_str(), LONG_OPTIONS, nullptr)) != -1) {
221 switch (option) {
222 case 'h':
223 printf("%s\n", UNINSTALL_HELP_MESSAGE.c_str());
224 break;
225 case 'n':
226 if (sem_init(&g_sem, 0, 0)) {
227 printf("error message: %s\n", ERROR_SEM_ERROR.c_str());
228 return;
229 }
230 if (AddDeathRecipient(sid, BmToolDeathNotify, nullptr, &cbId) != ERR_NONE) {
231 printf("error message: %s\n", "death callback is registered unsuccessfully");
232 return;
233 }
234 Uninstall(optarg, &g_installParam, ReceiveCallback);
235 sem_wait(&g_sem);
236 break;
237 default:
238 printf("%s\n", (ERROR_OPTION + UNINSTALL_HELP_MESSAGE).c_str());
239 break;
240 }
241 }
242 }
243
RunAsDumpCommand(int32_t argc,char * argv[]) const244 void CommandParser::RunAsDumpCommand(int32_t argc, char *argv[]) const
245 {
246 if (argc > MAX_ARGUMENT_NUMBER) {
247 printf("%s\n", (ERROR_EXTRA_PARAMETER + DUMP_HELP_MESSAGE).c_str());
248 return;
249 }
250
251 int32_t option = getopt_long_only(argc, argv, SHORT_OPTIONS.c_str(), LONG_OPTIONS, nullptr);
252 switch (option) {
253 case 'h':
254 printf("%s\n", DUMP_HELP_MESSAGE.c_str());
255 break;
256 case 'n':
257 GetInstallBundleInfo(optarg);
258 break;
259 case 'l':
260 GetInstallBundleInfos(argc);
261 break;
262 case 'm':
263 GetBundleInfosByMetaDataKey(optarg);
264 break;
265 default:
266 printf("%s\n", (ERROR_OPTION + DUMP_HELP_MESSAGE).c_str());
267 break;
268 }
269 }
270
RunAsGetUdidCommand(int32_t argc,char * argv[]) const271 void CommandParser::RunAsGetUdidCommand(int32_t argc, char *argv[]) const
272 {
273 if (argc > MAX_ARGUMENT_NUMBER) {
274 printf("%s\n", (ERROR_EXTRA_PARAMETER + DUMP_HELP_MESSAGE).c_str());
275 return;
276 }
277
278 char udid[UDID_STRING_LEN + 1] = {0};
279 if (memset_s(udid, sizeof(udid), 0, sizeof(udid)) != EOK) {
280 printf("GetUdid error memset\n");
281 return;
282 }
283 char *devUdid = udid;
284 int ret = GetDevUdid(devUdid, sizeof(udid));
285 if (ret == EOK) {
286 cout << devUdid << endl;
287 } else {
288 cout << "Get Udid error ret = " << ret << endl;
289 }
290 }
291
292 #ifdef OHOS_DEBUG
RunAsEnableCommand(int32_t argc,char * argv[]) const293 void CommandParser::RunAsEnableCommand(int32_t argc, char *argv[]) const
294 {
295 if (argc > MAX_ARGUMENT_NUMBER) {
296 printf("%s\n", (ERROR_EXTRA_PARAMETER + ENABLE_HELP_MESSAGE).c_str());
297 return;
298 }
299
300 int32_t option = getopt_long_only(argc, argv, ENABLE_SHORT_OPTIONS.c_str(), ENABLE_LONG_OPTIONS, nullptr);
301 switch (option) {
302 case 'h':
303 printf("%s\n", ENABLE_HELP_MESSAGE.c_str());
304 break;
305 case 'd':
306 SetDebugMode(optarg, SET_SIGN_DEBUG_MODE);
307 break;
308 case 'e':
309 SetDebugMode(optarg, SET_EXTERNAL_INSTALL_MODE);
310 break;
311 case 's':
312 SetDebugMode(optarg, SET_SIGN_MODE);
313 break;
314 default:
315 printf("%s\n", (ERROR_OPTION + ENABLE_HELP_MESSAGE).c_str());
316 break;
317 }
318 }
319 #endif
320
GetInstallBundleInfo(const std::string & bundleName) const321 void CommandParser::GetInstallBundleInfo(const std::string &bundleName) const
322 {
323 BundleInfo bundleInfo;
324 if (memset_s(&bundleInfo, sizeof(BundleInfo), 0, sizeof(BundleInfo)) != EOK) {
325 printf("error message: %s\n", ERROR_DUMP_ERROR.c_str());
326 return;
327 }
328 if (GetBundleInfo(bundleName.c_str(), 1, &bundleInfo) != OHOS_SUCCESS) {
329 printf("error message: %s\n", ERROR_DUMP_FAIL.c_str());
330 return;
331 }
332
333 cJSON *root = ConvertUtils::GetJsonBundleInfo(&bundleInfo);
334 if (root == nullptr) {
335 ClearBundleInfo(&bundleInfo);
336 printf("error message: %s\n", ERROR_DUMP_ERROR.c_str());
337 return;
338 }
339
340 char *str = cJSON_PrintUnformatted(root);
341 cJSON_Delete(root);
342 ClearBundleInfo(&bundleInfo);
343 if (str != nullptr) {
344 InfoPrint(str);
345 cJSON_free(str);
346 str = nullptr;
347 } else {
348 printf("error message: %s\n", ERROR_DUMP_ERROR.c_str());
349 }
350 }
351
InfoPrint(const std::string & str) const352 void CommandParser::InfoPrint(const std::string &str) const
353 {
354 int32_t len = str.size();
355 if (len == 0) {
356 return;
357 }
358 int32_t times = len / MAX_LOG_LEN;
359 int32_t remains = len % MAX_LOG_LEN;
360 for (int32_t i = 0; i < times; i++) {
361 printf("%s\n", str.substr(i * MAX_LOG_LEN, MAX_LOG_LEN).c_str());
362 }
363 printf("%s\n", str.substr(times * MAX_LOG_LEN, remains).c_str());
364 }
365
GetInstallBundleInfos(int32_t argc) const366 void CommandParser::GetInstallBundleInfos(int32_t argc) const
367 {
368 if (argc > MAX_DUMP_LIST_NUMBER) {
369 printf("error message: %s\n", ERROR_OPTION.c_str());
370 return;
371 }
372
373 BundleInfo *bundleInfo = nullptr;
374 int32_t len = 0;
375 if (GetBundleInfos(1, &bundleInfo, &len) != OHOS_SUCCESS) {
376 printf("error message: %s\n", ERROR_DUMP_FAIL.c_str());
377 return;
378 }
379
380 cJSON *root = ConvertUtils::GetJsonBundleInfos(&bundleInfo, len);
381 if (root == nullptr) {
382 printf("error message: %s\n", ERROR_DUMP_ERROR.c_str());
383 BundleInfoUtils::FreeBundleInfos(bundleInfo, len);
384 return;
385 }
386
387 char *str = cJSON_PrintUnformatted(root);
388 cJSON_Delete(root);
389 BundleInfoUtils::FreeBundleInfos(bundleInfo, len);
390 if (str != nullptr) {
391 InfoPrint(str);
392 cJSON_free(str);
393 str = nullptr;
394 } else {
395 printf("error message: %s\n", ERROR_DUMP_ERROR.c_str());
396 }
397 }
398
GetBundleInfosByMetaDataKey(const std::string & metaDataKey) const399 void CommandParser::GetBundleInfosByMetaDataKey(const std::string &metaDataKey) const
400 {
401 int32_t len = 0;
402 BundleInfo *bundleInfos = nullptr;
403
404 if (metaDataKey.empty()) {
405 printf("query param is invalid!\n");
406 return;
407 }
408 if (GetBundleInfosByMetaData(metaDataKey.c_str(), &bundleInfos, &len) != OHOS_SUCCESS) {
409 printf("error message: %s\n", ERROR_DUMP_FAIL.c_str());
410 return;
411 }
412
413 printf("bundleNames match metaData key, len: %d\n", len);
414 for (int32_t i = 0; i < len; ++i) {
415 printf("bundleName: %s", bundleInfos[i].bundleName);
416 if (i != len - 1) {
417 printf("%s\n", "; ");
418 } else {
419 printf("%s\n", "\n");
420 }
421 }
422 BundleInfoUtils::FreeBundleInfos(bundleInfos, len);
423 }
424
425 #ifdef OHOS_DEBUG
BmsToolNotify(IOwner owner,int code,IpcIo * reply)426 static int BmsToolNotify(IOwner owner, int code, IpcIo *reply)
427 {
428 if ((reply == nullptr) || (owner == nullptr)) {
429 printf("%s\n", "Bm tool Notify ipc is nullptr");
430 return OHOS_FAILURE;
431 }
432 uint8_t readCode;
433 ReadUint8(reply, &readCode);
434 switch (readCode) {
435 case SET_EXTERNAL_INSTALL_MODE:
436 case SET_SIGN_DEBUG_MODE:
437 case SET_SIGN_MODE: {
438 uint8_t *ret = reinterpret_cast<uint8_t *>(owner);
439 ReadUint8(reply, ret);
440 break;
441 }
442 default: {
443 break;
444 }
445 }
446 return ERR_OK;
447 }
448
SetMode(int32_t mode,bool enable)449 uint8_t SetMode(int32_t mode, bool enable)
450 {
451 if (g_bmsInnerClient == nullptr) {
452 printf("%s\n", "Bm tool client is nullptr");
453 return ERR_APPEXECFWK_OBJECT_NULL;
454 }
455 IpcIo ipcIo;
456 char data[MAX_IO_SIZE];
457 IpcIoInit(&ipcIo, data, MAX_IO_SIZE, 0);
458 WriteBool(&ipcIo, enable);
459 uint8_t setModeResult = 0;
460 int32_t ret = g_bmsInnerClient->Invoke(g_bmsInnerClient, mode, &ipcIo, &setModeResult, BmsToolNotify);
461 if (ret != ERR_OK) {
462 printf("Bm tool invoke failed: %d\n", ret);
463 return ERR_APPEXECFWK_INVOKE_ERROR;
464 }
465 return setModeResult;
466 }
467
SetDebugMode(const std::string & enable,int32_t mode) const468 void CommandParser::SetDebugMode(const std::string &enable, int32_t mode) const
469 {
470 bool isEnable = false;
471 if (enable == "enable") {
472 isEnable = true;
473 } else if (enable == "disable") {
474 isEnable = false;
475 } else {
476 printf("%s\n", "wrong param");
477 return;
478 }
479 uint8_t ret = SetMode(mode, isEnable);
480 if (ret == 0) {
481 printf("%s\n", "success");
482 } else {
483 printf("%s\n", "fail");
484 }
485 }
486 #endif
487 } // namespace OHOS
488