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