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