• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2022 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 #include "ability_tool_command.h"
16 
17 #include <cstdio>
18 #include <cstring>
19 #include <getopt.h>
20 #include <iostream>
21 #include <regex>
22 
23 #include "ability_manager_client.h"
24 #include "element_name.h"
25 #include "hilog_wrapper.h"
26 #include "bool_wrapper.h"
27 
28 using namespace OHOS::AppExecFwk;
29 
30 namespace OHOS {
31 namespace AAFwk {
32 namespace {
33 const std::string ABILITY_TOOL_NAME = "ability_tool";
34 const std::string ABILITY_TOOL_HELP_MSG =
35     "usage: ability_tool <command> <options>\n"
36     "ability_tool commands list:\n"
37     "  help                        list available commands\n"
38     "  start                       start ability with options\n"
39     "  stop-service                stop service with options\n"
40     "  force-stop                  force stop the process with bundle name\n"
41     "  test                        start the test framework with options\n";
42 
43 const std::string ABILITY_TOOL_HELP_MSG_START =
44     "usage: ability_tool start <options>\n"
45     "ability_tool start options list:\n"
46     "  --help                      list available options\n"
47     "  --device <device-id>        device Id\n"
48     "  --ability <ability-name>    ability name, mandatory\n"
49     "  --bundle <bundle-name>      bundle name, mandatory\n"
50     "  --options <key> <value>     start options, such as windowMode 102\n"
51     "  --flags <flag>              flags in a want\n"
52     "  -C                          cold start\n"
53     "  -D                          start with debug mode\n";
54 
55 const std::string ABILITY_TOOL_HELP_MSG_STOP_SERVICE =
56     "usage: ability_tool stop-service <options>\n"
57     "ability_tool stop-service options list:\n"
58     "  --help                      list available options\n"
59     "  --device <device-id>        device Id\n"
60     "  --ability <ability-name>    ability name, mandatory\n"
61     "  --bundle <bundle-name>      bundle name, mandatory\n";
62 
63 const std::string ABILITY_TOOL_HELP_MSG_FORCE_STOP =
64     "usage: ability_tool force-stop <options>\n"
65     "ability_tool force-stop options list:\n"
66     "  --help                      list available options\n"
67     "  <bundle-name>               bundle name, mandatory\n";
68 
69 const std::string ABILITY_TOOL_HELP_MSG_TEST =
70     "usage: ability_tool test <options>\n"
71     "ability_tool test options list:\n"
72     "  --help                              list available options\n"
73     "  --bundle <bundle-name>              bundle name, mandatory\n"
74     "  --options unittest <test-runner>    test runner need to start, mandatory\n"
75     "  --package-name <package-name>       package name, required for the FA model\n"
76     "  --module-name <module-name>         module name, required for the STAGE model\n"
77     "  --options <key> <value>             test options, such as testcase test_001\n"
78     "  --watchdog <wait-time>              max execute time for this test\n"
79     "  -D                                  test with debug mode\n";
80 
81 const std::string ABILITY_TOOL_HELP_MSG_NO_ABILITY_NAME_OPTION = "error: --ability <ability-name> is expected";
82 const std::string ABILITY_TOOL_HELP_MSG_NO_BUNDLE_NAME_OPTION = "error: --bundle <bundle-name> is expected";
83 const std::string ABILITY_TOOL_HELP_MSG_WINDOW_MODE_INVALID = "error: --options windowMode <value> with invalid param";
84 const std::string ABILITY_TOOL_HELP_MSG_LACK_VALUE = "error: lack of value of key";
85 const std::string ABILITY_TOOL_HELP_MSG_ONLY_NUM = "error: current option only support number";
86 const std::string ABILITY_TOOL_HELP_LACK_OPTIONS = "error: lack of essential args";
87 
88 const std::string SHORT_OPTIONS_FOR_TEST = "hb:o:p:m:w:D";
89 const struct option LONG_OPTIONS_FOR_TEST[] = {
90     {"help", no_argument, nullptr, 'h'},
91     {"bundle", required_argument, nullptr, 'b'},
92     {"options", required_argument, nullptr, 'o'},
93     {"package-name", required_argument, nullptr, 'p'},
94     {"module-name", required_argument, nullptr, 'm'},
95     {"watchdog", required_argument, nullptr, 'w'},
96     {"debug", no_argument, nullptr, 'D'},
97     {nullptr, 0, nullptr, 0},
98 };
99 
100 const int32_t ARG_LIST_INDEX_OFFSET = 2;
101 } // namespace
102 
AbilityToolCommand(int argc,char * argv[])103 AbilityToolCommand::AbilityToolCommand(int argc, char* argv[]) : ShellCommand(argc, argv, ABILITY_TOOL_NAME)
104 {
105     for (int i = 0; i < argc_; i++) {
106         HILOG_INFO("argv_[%{public}d]: %{public}s", i, argv_[i]);
107     }
108 
109     aaShellCmd_ = std::make_shared<AbilityManagerShellCommand>(argc, argv);
110     if (aaShellCmd_.get() == nullptr) {
111         HILOG_ERROR("Get aa command failed.");
112     }
113 }
114 
CreateCommandMap()115 ErrCode AbilityToolCommand::CreateCommandMap()
116 {
117     commandMap_ = {
118         {"help", std::bind(&AbilityToolCommand::RunAsHelpCommand, this)},
119         {"start", std::bind(&AbilityToolCommand::RunAsStartAbility, this)},
120         {"stop-service", std::bind(&AbilityToolCommand::RunAsStopService, this)},
121         {"force-stop", std::bind(&AbilityToolCommand::RunAsForceStop, this)},
122         {"test", std::bind(&AbilityToolCommand::RunAsTestCommand, this)},
123     };
124 
125     return OHOS::ERR_OK;
126 }
127 
CreateMessageMap()128 ErrCode AbilityToolCommand::CreateMessageMap()
129 {
130     if (aaShellCmd_.get() == nullptr) {
131         HILOG_ERROR("aa shell command is nullptr.");
132         return OHOS::ERR_INVALID_VALUE;
133     }
134     return aaShellCmd_.get()->CreateMessageMap();
135 }
136 
init()137 ErrCode AbilityToolCommand::init()
138 {
139     return AbilityManagerClient::GetInstance()->Connect();
140 }
141 
RunAsHelpCommand()142 ErrCode AbilityToolCommand::RunAsHelpCommand()
143 {
144     resultReceiver_.append(ABILITY_TOOL_HELP_MSG);
145     return OHOS::ERR_OK;
146 }
147 
RunAsStartAbility()148 ErrCode AbilityToolCommand::RunAsStartAbility()
149 {
150     Want want;
151     StartOptions startoptions;
152 
153     ErrCode result = ParseStartAbilityArgsFromCmd(want, startoptions);
154     if (result != OHOS::ERR_OK) {
155         resultReceiver_.append(ABILITY_TOOL_HELP_MSG_START);
156         return result;
157     }
158 
159     result = AbilityManagerClient::GetInstance()->StartAbility(want, startoptions, nullptr);
160     if (result != OHOS::ERR_OK) {
161         HILOG_ERROR("%{public}s result = %{public}d", STRING_START_ABILITY_NG.c_str(), result);
162         if (result != START_ABILITY_WAITING) {
163             resultReceiver_ = STRING_START_ABILITY_NG + "\n";
164         }
165         resultReceiver_.append(GetMessageFromCode(result));
166         return result;
167     }
168 
169     HILOG_INFO("%{public}s", STRING_START_ABILITY_OK.c_str());
170     resultReceiver_ = STRING_START_ABILITY_OK + "\n";
171     return OHOS::ERR_OK;
172 }
173 
RunAsStopService()174 ErrCode AbilityToolCommand::RunAsStopService()
175 {
176     Want want;
177 
178     ErrCode result = ParseStopServiceArgsFromCmd(want);
179     if (result != OHOS::ERR_OK) {
180         resultReceiver_.append(ABILITY_TOOL_HELP_MSG_STOP_SERVICE);
181         return OHOS::ERR_INVALID_VALUE;
182     }
183 
184     result = AbilityManagerClient::GetInstance()->StopServiceAbility(want);
185     if (result != OHOS::ERR_OK) {
186         HILOG_ERROR("%{public}s result = %{public}d", STRING_STOP_SERVICE_ABILITY_NG.c_str(), result);
187         resultReceiver_ = STRING_STOP_SERVICE_ABILITY_NG + "\n";
188         resultReceiver_.append(GetMessageFromCode(result));
189         return result;
190     }
191 
192     HILOG_INFO("%{public}s", STRING_STOP_SERVICE_ABILITY_OK.c_str());
193     resultReceiver_ = STRING_STOP_SERVICE_ABILITY_OK + "\n";
194     return OHOS::ERR_OK;
195 }
196 
RunAsForceStop()197 ErrCode AbilityToolCommand::RunAsForceStop()
198 {
199     if (argList_.empty()) {
200         resultReceiver_.append(ABILITY_TOOL_HELP_MSG_FORCE_STOP);
201         return OHOS::ERR_INVALID_VALUE;
202     }
203 
204     std::string bundleName = argList_[0];
205     ErrCode result = AbilityManagerClient::GetInstance()->KillProcess(bundleName);
206     if (result != OHOS::ERR_OK) {
207         HILOG_ERROR("%{public}s result = %{public}d", STRING_FORCE_STOP_NG.c_str(), result);
208         resultReceiver_ = STRING_FORCE_STOP_NG + "\n";
209         resultReceiver_.append(GetMessageFromCode(result));
210         return result;
211     }
212 
213     HILOG_INFO("%{public}s", STRING_FORCE_STOP_OK.c_str());
214     resultReceiver_ = STRING_FORCE_STOP_OK + "\n";
215     return OHOS::ERR_OK;
216 }
217 
RunAsTestCommand()218 ErrCode AbilityToolCommand::RunAsTestCommand()
219 {
220     std::map<std::string, std::string> params;
221 
222     ErrCode result = ParseTestArgsFromCmd(params);
223     if (result != OHOS::ERR_OK) {
224         resultReceiver_.append(ABILITY_TOOL_HELP_MSG_TEST);
225         return result;
226     }
227 
228     if (aaShellCmd_.get() == nullptr) {
229         HILOG_ERROR("aa shell command is nullptr.");
230         return OHOS::ERR_INVALID_VALUE;
231     }
232 
233     if (!aaShellCmd_.get()->IsTestCommandIntegrity(params)) {
234         HILOG_ERROR("test command lack of essential args.");
235         resultReceiver_ = ABILITY_TOOL_HELP_LACK_OPTIONS + "\n";
236         resultReceiver_.append(ABILITY_TOOL_HELP_MSG_TEST);
237         return OHOS::ERR_INVALID_VALUE;
238     }
239     return aaShellCmd_.get()->StartUserTest(params);
240 }
241 
ParseStartAbilityArgsFromCmd(Want & want,StartOptions & startoptions)242 ErrCode AbilityToolCommand::ParseStartAbilityArgsFromCmd(Want& want, StartOptions& startoptions)
243 {
244     std::string deviceId = "";
245     std::string bundleName = "";
246     std::string abilityName = "";
247     std::string paramName = "";
248     std::string paramValue = "";
249     std::smatch sm;
250     int32_t windowMode = AbilityWindowConfiguration::MULTI_WINDOW_DISPLAY_UNDEFINED;
251     int flags = 0;
252     bool isColdStart = false;
253     bool isDebugApp = false;
254     int option = -1;
255     int index = 0;
256     const std::string shortOptions = "hd:a:b:o:f:CD";
257     const struct option longOptions[] = {
258         {"help", no_argument, nullptr, 'h'},
259         {"device", required_argument, nullptr, 'd'},
260         {"ability", required_argument, nullptr, 'a'},
261         {"bundle", required_argument, nullptr, 'b'},
262         {"options", required_argument, nullptr, 'o'},
263         {"flags", required_argument, nullptr, 'f'},
264         {"cold-start", no_argument, nullptr, 'C'},
265         {"debug", no_argument, nullptr, 'D'},
266         {nullptr, 0, nullptr, 0},
267     };
268 
269     while ((option = getopt_long(argc_, argv_, shortOptions.c_str(), longOptions, &index)) != EOF) {
270         HILOG_INFO("option: %{public}d, optopt: %{public}d, optind: %{public}d", option, optopt, optind);
271         switch (option) {
272             case 'h':
273                 break;
274             case 'd':
275                 deviceId = optarg;
276                 break;
277             case 'a':
278                 abilityName = optarg;
279                 break;
280             case 'b':
281                 bundleName = optarg;
282                 break;
283             case 'o':
284                 if (!GetKeyAndValueByOpt(optind, paramName, paramValue)) {
285                     return OHOS::ERR_INVALID_VALUE;
286                 }
287                 HILOG_DEBUG("paramName: %{public}s, paramValue: %{public}s", paramName.c_str(), paramValue.c_str());
288                 if (paramName == "windowMode" &&
289                     std::regex_match(paramValue, sm, std::regex(STRING_TEST_REGEX_INTEGER_NUMBERS))) {
290                     windowMode = std::stoi(paramValue);
291                 }
292                 break;
293             case 'f':
294                 paramValue = optarg;
295                 if (std::regex_match(paramValue, sm, std::regex(STRING_TEST_REGEX_INTEGER_NUMBERS))) {
296                     flags = std::stoi(paramValue);
297                 }
298                 break;
299             case 'C':
300                 isColdStart = true;
301                 break;
302             case 'D':
303                 isDebugApp = true;
304                 break;
305             default:
306                 break;
307         }
308     }
309 
310     // Parameter check
311     if (abilityName.size() == 0 || bundleName.size() == 0) {
312         HILOG_DEBUG("'ability_tool %{public}s' without enough options.", cmd_.c_str());
313         if (abilityName.size() == 0) {
314             resultReceiver_.append(ABILITY_TOOL_HELP_MSG_NO_ABILITY_NAME_OPTION + "\n");
315         }
316 
317         if (bundleName.size() == 0) {
318             resultReceiver_.append(ABILITY_TOOL_HELP_MSG_NO_BUNDLE_NAME_OPTION + "\n");
319         }
320 
321         return OHOS::ERR_INVALID_VALUE;
322     }
323 
324     // Get Want
325     ElementName element(deviceId, bundleName, abilityName);
326     want.SetElement(element);
327 
328     WantParams wantParams;
329     if (isColdStart) {
330         wantParams.SetParam("coldStart", Boolean::Box(isColdStart));
331     }
332     if (isDebugApp) {
333         wantParams.SetParam("debugApp", Boolean::Box(isDebugApp));
334     }
335     want.SetParams(wantParams);
336 
337     if (flags != 0) {
338         want.AddFlags(flags);
339     }
340 
341     // Get StartOptions
342     if (windowMode != AbilityWindowConfiguration::MULTI_WINDOW_DISPLAY_UNDEFINED) {
343         if (windowMode != AbilityWindowConfiguration::MULTI_WINDOW_DISPLAY_FULLSCREEN &&
344             windowMode != AbilityWindowConfiguration::MULTI_WINDOW_DISPLAY_PRIMARY &&
345             windowMode != AbilityWindowConfiguration::MULTI_WINDOW_DISPLAY_SECONDARY &&
346             windowMode != AbilityWindowConfiguration::MULTI_WINDOW_DISPLAY_FLOATING) {
347             HILOG_DEBUG("'ability_tool %{public}s' %{public}s", cmd_.c_str(),
348                 ABILITY_TOOL_HELP_MSG_WINDOW_MODE_INVALID.c_str());
349             resultReceiver_.append(ABILITY_TOOL_HELP_MSG_WINDOW_MODE_INVALID + "\n");
350             return OHOS::ERR_INVALID_VALUE;
351         }
352         startoptions.SetWindowMode(windowMode);
353     }
354 
355     return OHOS::ERR_OK;
356 }
357 
ParseStopServiceArgsFromCmd(Want & want)358 ErrCode AbilityToolCommand::ParseStopServiceArgsFromCmd(Want& want)
359 {
360     std::string deviceId = "";
361     std::string abilityName = "";
362     std::string bundleName = "";
363     int option = -1;
364     int index = 0;
365     const std::string shortOptions = "hd:a:b:";
366     const struct option longOptions[] = {
367         {"help", no_argument, nullptr, 'h'},
368         {"device", required_argument, nullptr, 'd'},
369         {"ability", required_argument, nullptr, 'a'},
370         {"bundle", required_argument, nullptr, 'b'},
371         {nullptr, 0, nullptr, 0},
372     };
373 
374     while ((option = getopt_long(argc_, argv_, shortOptions.c_str(), longOptions, &index)) != EOF) {
375         HILOG_INFO("option: %{public}d, optopt: %{public}d, optind: %{public}d", option, optopt, optind);
376         switch (option) {
377             case 'h':
378                 break;
379             case 'd':
380                 deviceId = optarg;
381                 break;
382             case 'a':
383                 abilityName = optarg;
384                 break;
385             case 'b':
386                 bundleName = optarg;
387                 break;
388             default:
389                 break;
390         }
391     }
392 
393     if (abilityName.size() == 0 || bundleName.size() == 0) {
394         HILOG_INFO("'ability_tool %{public}s' without enough options.", cmd_.c_str());
395         if (abilityName.size() == 0) {
396             resultReceiver_.append(ABILITY_TOOL_HELP_MSG_NO_ABILITY_NAME_OPTION + "\n");
397         }
398 
399         if (bundleName.size() == 0) {
400             resultReceiver_.append(ABILITY_TOOL_HELP_MSG_NO_BUNDLE_NAME_OPTION + "\n");
401         }
402 
403         return OHOS::ERR_INVALID_VALUE;
404     }
405 
406     ElementName element(deviceId, bundleName, abilityName);
407     want.SetElement(element);
408     return OHOS::ERR_OK;
409 }
410 
ParseTestArgsFromCmd(std::map<std::string,std::string> & params)411 ErrCode AbilityToolCommand::ParseTestArgsFromCmd(std::map<std::string, std::string>& params)
412 {
413     std::string tempKey;
414     std::string paramKey;
415     std::string paramValue;
416     std::smatch sm;
417     int option = -1;
418     int index = 0;
419 
420     // Parameter parse with conversion
421     while ((option = getopt_long(argc_, argv_, SHORT_OPTIONS_FOR_TEST.c_str(), LONG_OPTIONS_FOR_TEST, &index)) != EOF) {
422         HILOG_INFO("option: %{public}d, optopt: %{public}d, optind: %{public}d", option, optopt, optind);
423         switch (option) {
424             case 'h':
425                 break;
426             case 'b':
427                 params["-b"] = optarg;
428                 break;
429             case 'o':
430                 if (!GetKeyAndValueByOpt(optind, tempKey, paramValue)) {
431                     return OHOS::ERR_INVALID_VALUE;
432                 }
433                 HILOG_DEBUG("tempKey: %{public}s, paramValue: %{public}s", tempKey.c_str(), paramValue.c_str());
434                 paramKey = "-s ";
435                 paramKey.append(tempKey);
436                 params[paramKey] = paramValue;
437                 break;
438             case 'p':
439                 params["-p"] = optarg;
440                 break;
441             case 'm':
442                 params["-m"] = optarg;
443                 break;
444             case 'w':
445                 paramValue = optarg;
446                 if (!(std::regex_match(paramValue, sm, std::regex(STRING_TEST_REGEX_INTEGER_NUMBERS)))) {
447                     HILOG_DEBUG("'ability_tool test --watchdog %{public}s", ABILITY_TOOL_HELP_MSG_ONLY_NUM.c_str());
448                     resultReceiver_.append(ABILITY_TOOL_HELP_MSG_ONLY_NUM + "\n");
449                     return OHOS::ERR_INVALID_VALUE;
450                 }
451                 params["-w"] = paramValue;
452                 break;
453             case 'D':
454                 params["-D"] = "true";
455                 break;
456             default:
457                 break;
458         }
459     }
460 
461     return OHOS::ERR_OK;
462 }
463 
GetKeyAndValueByOpt(int optind,std::string & key,std::string & value)464 bool AbilityToolCommand::GetKeyAndValueByOpt(int optind, std::string& key, std::string& value)
465 {
466     int argListIndex = optind - ARG_LIST_INDEX_OFFSET;
467     if (argListIndex < 1) {
468         return false;
469     }
470 
471     bool isOption = (argList_[argListIndex - 1] == "-o" || argList_[argListIndex - 1] == "--options") ? true : false;
472     int keyIndex = isOption ? argListIndex : argListIndex - 1;
473     int valueIndex = isOption ? argListIndex + 1 : argListIndex;
474     if (keyIndex >= static_cast<int>(argList_.size()) || keyIndex < 0 ||
475         valueIndex >= static_cast<int>(argList_.size()) || valueIndex < 0) {
476         HILOG_DEBUG("'ability_tool %{public}s' %{public}s", cmd_.c_str(),
477             ABILITY_TOOL_HELP_MSG_LACK_VALUE.c_str());
478         resultReceiver_.append(ABILITY_TOOL_HELP_MSG_LACK_VALUE + "\n");
479         return false;
480     }
481 
482     key = argList_[keyIndex];
483     value = argList_[valueIndex];
484     return true;
485 }
486 } // namespace AAFwk
487 } // namespace OHOS
488