1 /*
2 * Copyright (c) 2021 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 <getopt.h>
16 #include <unistd.h>
17 #include <cinttypes>
18
19 #include "appexecfwk_errors.h"
20 #include "app_log_wrapper.h"
21 #include "fms_command.h"
22 #include "if_system_ability_manager.h"
23 #include "ipc_skeleton.h"
24 #include "iservice_registry.h"
25 #include "string_ex.h"
26 #include "system_ability_definition.h"
27
28 using namespace OHOS::AAFwk;
29
30 namespace OHOS {
31 namespace AppExecFwk {
32 namespace {
33 const int COMMAND_QUERY_INVALID = -1;
34 const int COMMAND_QUERY_STORAGE = 0;
35 const int COMMAND_QUERY_NAME = 1;
36 const int COMMAND_QUERY_ID = 2;
37
38 // const std::string BUNDLE_NAME_EMPTY = "";
39
40 const std::string SHORT_OPTIONS = "hsn:i:";
41 const struct option LONG_OPTIONS[] = {
42 {"help", no_argument, nullptr, 'h'},
43 {"storage", no_argument, nullptr, 's'},
44 {"bundle-name", required_argument, nullptr, 'n'},
45 {"form-id", required_argument, nullptr, 'i'},
46 {0, 0, 0, 0},
47 };
48 } // namespace
49
FormMgrShellCommand(int argc,char * argv[])50 FormMgrShellCommand::FormMgrShellCommand(int argc, char *argv[]) : ShellCommand(argc, argv, FM_TOOL_NAME)
51 {
52 }
init()53 ErrCode FormMgrShellCommand::init()
54 {
55 return ERR_OK;
56 }
57 /**
58 * @brief Create command map.
59 */
CreateCommandMap()60 ErrCode FormMgrShellCommand::CreateCommandMap()
61 {
62 commandMap_ = {
63 {"help", std::bind(&FormMgrShellCommand::RunAsHelpCommand, this)},
64 {"query", std::bind(&FormMgrShellCommand::RunAsQueryCommand, this)},
65 // {"dump", std::bind(&FormMgrShellCommand::RunAsDumpCommand, this)},
66 };
67
68 return OHOS::ERR_OK;
69 }
70 /**
71 * @brief Create message map.
72 */
CreateMessageMap()73 ErrCode FormMgrShellCommand::CreateMessageMap()
74 {
75 messageMap_ = {
76 // error + message
77 {
78 ERR_APPEXECFWK_INSTALL_INTERNAL_ERROR,
79 "error: fm query internal error.",
80 },
81 {
82 ERR_APPEXECFWK_FORM_INVALID_PARAM,
83 "error: fm query param error.",
84 },
85 {
86 ERR_APPEXECFWK_FORM_PERMISSION_DENY,
87 "error: fm query permission denied.",
88 },
89 {
90 ERR_APPEXECFWK_FORM_NOT_EXIST_ID,
91 "warning: fm query no form info.",
92 },
93 {
94 ERR_APPEXECFWK_FORM_COMMON_CODE,
95 "error: unknown.",
96 },
97 };
98
99 return OHOS::ERR_OK;
100 }
101 /**
102 * @brief Run help command.
103 */
RunAsHelpCommand()104 ErrCode FormMgrShellCommand::RunAsHelpCommand()
105 {
106 resultReceiver_.append(FM_HELP_MSG);
107
108 return OHOS::ERR_OK;
109 }
110 /**
111 * @brief Run query form info command.
112 */
RunAsQueryCommand()113 ErrCode FormMgrShellCommand::RunAsQueryCommand()
114 {
115 int32_t result = OHOS::ERR_OK;
116 int32_t cmdFlag = COMMAND_QUERY_INVALID;
117 int option = -1;
118 int counter = 0;
119 std::string bundleName = "";
120 int64_t formId = 0;
121
122 while (true) {
123 counter++;
124 option = getopt_long(argc_, argv_, SHORT_OPTIONS.c_str(), LONG_OPTIONS, nullptr);
125 APP_LOGI("option: %{public}d, optopt: %{public}d, optind: %{public}d", option, optopt, optind);
126 if (optind < 0 || optind > argc_) {
127 return OHOS::ERR_INVALID_VALUE;
128 }
129
130 for (int i = 0; i < argc_; i++) {
131 APP_LOGI("argv_[%{public}d]: %{public}s", i, argv_[i]);
132 }
133
134 if (option == -1) {
135 if (counter == 1) {
136 // When scanning the first argument
137 if (strcmp(argv_[optind], cmd_.c_str()) == 0) {
138 // 'fm query' with no option: fm query
139 // 'fm query' with a wrong argument: fm query xxx
140 APP_LOGE("'fm query' with no option.");
141 resultReceiver_.append(HELP_MSG_NO_OPTION + "\n");
142 result = OHOS::ERR_INVALID_VALUE;
143 }
144 }
145 break;
146 }
147
148 if (option == '?') {
149 result = HandleUnknownOption(optopt);
150 break;
151 }
152
153 result = HandleNormalOption(option, bundleName, formId, cmdFlag);
154 // if(result == OHOS::ERR_OK) {
155 // break;
156 // }
157 }
158
159 if (result == OHOS::ERR_OK) {
160 result = ExecuteQuery(bundleName, formId, cmdFlag);
161 } else {
162 resultReceiver_.append(HELP_MSG_QUERY);
163 }
164
165 return result;
166 }
167 /**
168 * @brief Handle command args.
169 * @param optopt Command optopt.
170 * @return Returns ERR_OK on success, others on failure.
171 */
HandleUnknownOption(const char optopt)172 int32_t FormMgrShellCommand::HandleUnknownOption(const char optopt)
173 {
174 int32_t result = OHOS::ERR_OK;
175 switch (optopt) {
176 case 'n':
177 case 'i': {
178 // 'fm query -n' with no argument: fm query -n
179 // 'fm query --bundle-name' with no argument: fm query --bundle-name
180 // 'fm query -i' with no argument: fm query -i
181 // 'fm query --form-id' with no argument: fm query --form-id
182 APP_LOGE("'fm query' %{public}s with no argument.", argv_[optind - 1]);
183 resultReceiver_.append("error: option '");
184 resultReceiver_.append(argv_[optind - 1]);
185 resultReceiver_.append("' requires a value.\n");
186 result = OHOS::ERR_INVALID_VALUE;
187 break;
188 }
189 case 0: {
190 // 'fm query' with a unknown option: fm query --x
191 // 'fm query' with a unknown option: fm query --xxx
192 std::string unknownOption = "";
193 std::string unknownOptionMsg = GetUnknownOptionMsg(unknownOption);
194 APP_LOGE("'fm query' with a unknown option: %{public}s", unknownOption.c_str());
195 resultReceiver_.append(unknownOptionMsg);
196 result = OHOS::ERR_INVALID_VALUE;
197 break;
198 }
199 default: {
200 // 'fm query' with a unknown option: fm query -x
201 // 'fm query' with a unknown option: fm query -xxx
202 std::string unknownOption = "";
203 std::string unknownOptionMsg = GetUnknownOptionMsg(unknownOption);
204 APP_LOGE("'fm query' with a unknown option: %{public}s", unknownOption.c_str());
205 resultReceiver_.append(unknownOptionMsg);
206 result = OHOS::ERR_INVALID_VALUE;
207 break;
208 }
209 }
210
211 return result;
212 }
213 /**
214 * @brief Handle command args.
215 * @param option Command option.
216 * @param bundleName BundleName.
217 * @param formId The id of the form.
218 * @param cmdFlag Command Flag.
219 * @return Returns ERR_OK on success, others on failure.
220 */
HandleNormalOption(const int option,std::string & bundleName,int64_t & formId,int32_t & cmdFlag)221 int32_t FormMgrShellCommand::HandleNormalOption(const int option, std::string &bundleName, int64_t &formId, int32_t &cmdFlag)
222 {
223 APP_LOGI("%{public}s start, option: %{public}d", __func__, option);
224 int32_t result = OHOS::ERR_OK;
225 switch (option) {
226 case 'h': {
227 // 'fm query -h'
228 // 'fm query --help'
229 APP_LOGI("'fm query' %{public}s", argv_[optind - 1]);
230 result = OHOS::ERR_INVALID_VALUE;
231 break;
232 }
233 case 's': {
234 // 'fm query -s'
235 // 'fm query --storage'
236 cmdFlag = COMMAND_QUERY_STORAGE;
237 break;
238 }
239 case 'n': {
240 // 'fm query -n <bundle-name>'
241 // 'fm query --bundle-name <bundle-name>'
242 if(optarg == nullptr) {
243 resultReceiver_.append("error: option ");
244 resultReceiver_.append("'-n'");
245 resultReceiver_.append(" requires a value.\n");
246 result = OHOS::ERR_INVALID_VALUE;
247 break;
248 }
249 cmdFlag = COMMAND_QUERY_NAME;
250 bundleName = optarg;
251 break;
252 }
253 case 'i': {
254 // 'fm query -i <form-id> '
255 // 'fm query --form-id <form-id> '
256 if(optarg == nullptr) {
257 resultReceiver_.append("error: option ");
258 resultReceiver_.append("'-i'");
259 resultReceiver_.append(" requires a value.\n");
260 result = OHOS::ERR_INVALID_VALUE;
261 break;
262 }
263 cmdFlag = COMMAND_QUERY_ID;
264 formId = std::stoll(optarg);
265 break;
266 }
267 default: {
268 result = OHOS::ERR_INVALID_VALUE;
269 APP_LOGI("'fm query' invalid option.");
270 break;
271 }
272 }
273 APP_LOGI("%{public}s end, result: %{public}d", __func__, result);
274 return result;
275 }
276 /**
277 * @brief Execute query form info command.
278 * @param bundleName BundleName.
279 * @param formId The id of the form.
280 * @param cmdFlag Command Flag.
281 * @return Returns ERR_OK on success, others on failure.
282 */
ExecuteQuery(const std::string & bundleName,const int64_t formId,const int32_t cmdFlag)283 int32_t FormMgrShellCommand::ExecuteQuery(const std::string &bundleName, const int64_t formId, const int32_t cmdFlag)
284 {
285 APP_LOGI("%{public}s start, bundleName: %{public}s, formId:%{public}" PRId64 "", __func__, bundleName.c_str(), formId);
286 int32_t result = OHOS::ERR_OK;
287 switch (cmdFlag) {
288 case COMMAND_QUERY_STORAGE: {
289 result = QueryStorageFormInfos();
290 break;
291 }
292 case COMMAND_QUERY_NAME: {
293 result = QueryFormInfoByBundleName(bundleName);
294 break;
295 }
296 case COMMAND_QUERY_ID: {
297 result = QueryFormInfoByFormId(formId);
298 break;
299 }
300 default: {
301 APP_LOGI("'fm query' invalid command.");
302 break;
303 }
304 APP_LOGI("%{public}s end, cmdFlag: %{public}d", __func__, cmdFlag);
305 }
306
307 if (result == OHOS::ERR_OK) {
308 resultReceiver_ = STRING_QUERY_FORM_INFO_OK + "\n" + resultReceiver_;
309 } else if(result == OHOS::ERR_APPEXECFWK_FORM_NOT_EXIST_ID){
310 resultReceiver_ = STRING_QUERY_FORM_INFO_OK + "\n";
311 resultReceiver_.append(GetMessageFromCode(result));
312 } else {
313 resultReceiver_ = STRING_QUERY_FORM_INFO_NG + "\n";
314 resultReceiver_.append(GetMessageFromCode(result));
315 }
316
317 return result;
318 }
319 /**
320 * @brief Query all of form storage infos.
321 * @return Returns ERR_OK on success, others on failure.
322 */
QueryStorageFormInfos()323 int32_t FormMgrShellCommand::QueryStorageFormInfos()
324 {
325 APP_LOGI("%{public}s start", __func__);
326
327 int errCode = ConnectFms();
328 if(errCode != OHOS::ERR_OK) {
329 return errCode;
330 }
331
332 std::string formInfos;
333 MessageParcel data;
334 if (!WriteInterfaceToken(data)) {
335 APP_LOGE("%{public}s, failed to write interface token", __func__);
336 return ERR_APPEXECFWK_PARCEL_ERROR;
337 }
338
339 int result = GetStringInfo(IFormMgr::Message::FORM_MGR_STORAGE_FORM_INFOS, data, formInfos);
340 if (result == ERR_OK) {
341 resultReceiver_= formInfos;
342 } else {
343 APP_LOGE("'fm query' failed to query form info.");
344 }
345 APP_LOGI("%{public}s end, formInfo: %{public}s", __func__, resultReceiver_.c_str());
346
347 return result;
348 }
349 /**
350 * @brief Query form infos by bundleName.
351 * @param bundleName BundleName.
352 * @return Returns ERR_OK on success, others on failure.
353 */
QueryFormInfoByBundleName(const std::string & bundleName)354 int32_t FormMgrShellCommand::QueryFormInfoByBundleName(const std::string& bundleName)
355 {
356 APP_LOGI("%{public}s start, bundleName: %{public}s", __func__, bundleName.c_str());
357
358 int errCode = ConnectFms();
359 if(errCode != OHOS::ERR_OK) {
360 return errCode;
361 }
362
363 std::string formInfos;
364 MessageParcel data;
365 if (!WriteInterfaceToken(data)) {
366 APP_LOGE("%{public}s, failed to write interface token", __func__);
367 return ERR_APPEXECFWK_PARCEL_ERROR;
368 }
369
370 if (!data.WriteString(bundleName)) {
371 APP_LOGE("%{public}s, failed to write bundleName", __func__);
372 return ERR_APPEXECFWK_PARCEL_ERROR;
373 }
374
375 int result = GetStringInfo(IFormMgr::Message::FORM_MGR_FORM_INFOS_BY_NAME, data, formInfos);
376 if (result == ERR_OK) {
377 APP_LOGI("%{public}s, DumpFormInfoByBundleName success", __func__);
378 resultReceiver_ = formInfos;
379 } else {
380 APP_LOGE("'fm query' failed to query form info.");
381 }
382 APP_LOGI("%{public}s end, formInfo: %{public}s", __func__, resultReceiver_.c_str());
383
384 return result;
385 }
386 /**
387 * @brief Query form infos by form id.
388 * @param formId The id of the form.
389 * @return Returns ERR_OK on success, others on failure.
390 */
QueryFormInfoByFormId(const std::int64_t formId)391 int32_t FormMgrShellCommand::QueryFormInfoByFormId(const std::int64_t formId)
392 {
393 APP_LOGI("%{public}s start, formId: %{public}" PRId64 "", __func__, formId);
394
395 int errCode = ConnectFms();
396 if(errCode != OHOS::ERR_OK) {
397 return errCode;
398 }
399
400 std::string formInfo;
401 MessageParcel data;
402 if (!WriteInterfaceToken(data)) {
403 APP_LOGE("%{public}s, failed to write interface token", __func__);
404 return ERR_APPEXECFWK_PARCEL_ERROR;
405 }
406 if (!data.WriteInt64(formId)) {
407 APP_LOGE("%{public}s, failed to write formId", __func__);
408 return ERR_APPEXECFWK_PARCEL_ERROR;
409 }
410
411 int result = GetStringInfo(IFormMgr::Message::FORM_MGR_FORM_INFOS_BY_ID, data, formInfo);
412 if (result == ERR_OK) {
413 resultReceiver_ = formInfo;
414 } else if(result == OHOS::ERR_APPEXECFWK_FORM_NOT_EXIST_ID) {
415 APP_LOGW("'fm query' no form info.");
416 } else {
417 APP_LOGE("'fm query' failed to query form info.");
418 }
419 APP_LOGI("%{public}s end, formInfo: %{public}s", __func__, resultReceiver_.c_str());
420
421 return result;
422 }
WriteInterfaceToken(MessageParcel & data)423 bool FormMgrShellCommand::WriteInterfaceToken(MessageParcel &data)
424 {
425 if (!data.WriteInterfaceToken(IFormMgr::GetDescriptor())) {
426 APP_LOGE("%{public}s, failed to write interface token", __func__);
427 return false;
428 }
429 return true;
430 }
GetStringInfo(IFormMgr::Message code,MessageParcel & data,std::string & stringInfo)431 int FormMgrShellCommand::GetStringInfo(IFormMgr::Message code, MessageParcel &data, std::string &stringInfo)
432 {
433 int error;
434 MessageParcel reply;
435 error = SendTransactCmd(code, data, reply);
436 if (error != ERR_OK) {
437 return error;
438 }
439
440 error = reply.ReadInt32();
441 if (error != ERR_OK) {
442 APP_LOGE("%{public}s, failed to read reply result: %{public}d", __func__, error);
443 return error;
444 }
445 std::vector<std::string> stringInfoList;
446 if (!reply.ReadStringVector(&stringInfoList)) {
447 APP_LOGE("%{public}s, failed to read string vector from reply", __func__);
448 return false;
449 }
450 if (stringInfoList.empty()) {
451 APP_LOGI("%{public}s, No string info", __func__);
452 return ERR_APPEXECFWK_FORM_NOT_EXIST_ID;
453 }
454 for (auto &info : stringInfoList) {
455 stringInfo += info;
456 }
457 APP_LOGD("%{public}s, get string info success", __func__);
458 return ERR_OK;
459 }
SendTransactCmd(IFormMgr::Message code,MessageParcel & data,MessageParcel & reply)460 int FormMgrShellCommand::SendTransactCmd(IFormMgr::Message code, MessageParcel &data, MessageParcel &reply)
461 {
462 MessageOption option(MessageOption::TF_SYNC);
463
464 if (!remoteObject_) {
465 APP_LOGE("%{public}s, failed to get remote object, cmd: %{public}d", __func__, code);
466 return ERR_APPEXECFWK_SERVICE_NOT_CONNECTED;
467 }
468 int32_t result = remoteObject_->SendRequest(static_cast<uint32_t>(code), data, reply, option);
469 if (result != ERR_OK) {
470 APP_LOGE("%{public}s, failed to SendRequest: %{public}d, cmd: %{public}d", __func__, result, code);
471 return result;
472 }
473 return ERR_OK;
474 }
475 /**
476 * @brief Connect form manager service.
477 * @return Returns ERR_OK on success, others on failure.
478 */
ConnectFms()479 int32_t FormMgrShellCommand::ConnectFms()
480 {
481 if(remoteObject_ != nullptr) {
482 return OHOS::ERR_OK;
483 }
484 sptr<ISystemAbilityManager> systemManager = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager();
485 if (systemManager == nullptr) {
486 APP_LOGE("%{private}s:fail to get system ability manager", __func__);
487 return ERR_APPEXECFWK_FORM_GET_FMS_FAILED;
488 }
489 remoteObject_ = systemManager->GetSystemAbility(FORM_MGR_SERVICE_ID);
490 if (remoteObject_ == nullptr) {
491 APP_LOGE("%{private}s:fail to connect FormMgrService", __func__);
492 return ERR_APPEXECFWK_FORM_GET_FMS_FAILED;
493 }
494
495 APP_LOGI("%{public}s end, get fms proxy success", __func__);
496 return OHOS::ERR_OK;
497 }
498 } // namespace AppExecFwk
499 } // namespace OHOS