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
16 #include "notification_shell_command.h"
17
18 #include <getopt.h>
19 #include <iostream>
20
21 #include "ans_const_define.h"
22 #include "ans_inner_errors.h"
23 #include "nativetoken_kit.h"
24 #include "notification_bundle_option.h"
25 #include "token_setproc.h"
26 #include "singleton.h"
27 #include "ans_convert_enum.h"
28
29 namespace OHOS {
30 namespace Notification {
31 namespace {
32 constexpr char COMMAND_ACTIVE[] = "active";
33 constexpr char COMMAND_RECENT[] = "recent";
34 #ifdef DISTRIBUTED_NOTIFICATION_SUPPORTED
35 constexpr char COMMAND_DISTRIBUTED[] = "distributed";
36 constexpr char SHORT_OPTIONS[] = "hARDb:u:r:";
37 #else
38 constexpr char SHORT_OPTIONS[] = "hARb:u:";
39 #endif
40 constexpr char COMMAND_SET_RECENT_COUNT[] = "setRecentCount";
41 const struct option LONG_OPTIONS[] = {
42 {"help", no_argument, nullptr, 'h'},
43 {COMMAND_ACTIVE, no_argument, nullptr, 'A'},
44 {COMMAND_RECENT, no_argument, nullptr, 'R'},
45 #ifdef DISTRIBUTED_NOTIFICATION_SUPPORTED
46 {COMMAND_DISTRIBUTED, no_argument, nullptr, 'D'},
47 #endif
48 {"bundle", required_argument, nullptr, 'b'},
49 {"user-id", required_argument, nullptr, 'u'},
50 {"receiver", required_argument, nullptr, 'r'},
51 };
52 constexpr char HELP_MSG[] =
53 "usage: anm <command> [<options>]\n"
54 "These are common commands list:\n"
55 " help list available commands\n"
56 " dump dump the info of notification\n"
57 " setting notification setting\n";
58 constexpr char DUMP_HELP_MSG[] =
59 "usage: anm dump [<options>]\n"
60 "options list:\n"
61 " --help, -h help menu\n"
62 #ifdef DISTRIBUTED_NOTIFICATION_SUPPORTED
63 " --distributed, -D list all distributed notifications by remote device\n"
64 #endif
65 " --active, -A list all active notifications\n"
66 " --recent, -R list recent notifications\n"
67 " --bundle, -b <name> dump the info filter by the specified bundle name\n"
68 " --user-id, -u <userId> dump the info filter by the specified userId\n"
69 " --receiver, -r <userId> dump the info filter by the specified receiver userId\n";
70
71 constexpr char SETTING_SHORT_OPTIONS[] = "c:e:d:k:b:o:g:";
72 const struct option SETTING_LONG_OPTIONS[] = {
73 {"help", no_argument, nullptr, 'h'},
74 {"recent-count", required_argument, nullptr, 'c'},
75 {"enable-notification", required_argument, nullptr, 'e'},
76 {"set-device-status", required_argument, nullptr, 'd'},
77 {"collaboration-switch", required_argument, nullptr, 'k'},
78 {"collaboration-switch-bundle", required_argument, nullptr, 'b'},
79 {"collaboration-switch-slot", required_argument, nullptr, 'o'},
80 {"get-device-status", required_argument, nullptr, 'g'},
81 };
82 constexpr char SETTING_HELP_MSG[] =
83 "usage: anm setting [<options>]\n"
84 "options list:\n"
85 " --help, -h help menu\n"
86 " --recent-count -c <number> set the max count of recent notifications keeping in memory\n"
87 " --enable-notification -e <bundleName:uid:enable> set notification enabled for the bundle, eg: -e com.example:10100:1\n"
88 " --set-device-status -d <device:status> set device status, eg: -d device:1\n"
89 " --collaboration-switch -k <device:enable> set collaboration status, eg: -k wearable:1\n"
90 " --collaboration-switch-bundle -b <device:bundleName:bundleUid:status> set bundle collaboration switch status\n"
91 " eg: -b wearable:example:10100:1\n"
92 " --collaboration-switch-slot -o <device:slotType:status> set slot collaboration switch status\n"
93 " --get-device-status -o <device> set device status\n"
94 " eg: -o wearable:0:1\n";
95 } // namespace
96
97 const int PARAM_NUM_TWO = 2;
98 const int PARAM_NUM_THREE = 3;
99
NotificationShellCommand(int argc,char * argv[])100 NotificationShellCommand::NotificationShellCommand(int argc, char *argv[]) : ShellCommand(argc, argv, "anm_dump")
101 {}
102
CreateCommandMap()103 ErrCode NotificationShellCommand::CreateCommandMap()
104 {
105 commandMap_ = {
106 {"help", std::bind(&NotificationShellCommand::RunAsHelpCommand, this)},
107 {"dump", std::bind(&NotificationShellCommand::RunAsDumpCommand, this)},
108 {"setting", std::bind(&NotificationShellCommand::RunAsSettingCommand, this)},
109 };
110 return ERR_OK;
111 }
112
Init()113 ErrCode NotificationShellCommand::Init()
114 {
115 SetNativeToken();
116 ErrCode result = OHOS::ERR_OK;
117 if (!ans_) {
118 ans_ = DelayedSingleton<AnsNotification>::GetInstance();
119 }
120 if (!ans_) {
121 result = OHOS::ERR_INVALID_VALUE;
122 }
123 return result;
124 }
125
SetNativeToken()126 void NotificationShellCommand::SetNativeToken()
127 {
128 uint64_t tokenId;
129 const char **perms = new (std::nothrow) const char *[1];
130 if (perms == nullptr) {
131 ANS_LOGE("Failed to create buffer.");
132 return;
133 }
134 perms[0] = "ohos.permission.NOTIFICATION_CONTROLLER";
135 NativeTokenInfoParams infoInstance = {
136 .dcapsNum = 0,
137 .permsNum = 1,
138 .aclsNum = 0,
139 .dcaps = nullptr,
140 .perms = perms,
141 .acls = nullptr,
142 .aplStr = "system_basic",
143 };
144
145 infoInstance.processName = "anm";
146 tokenId = GetAccessTokenId(&infoInstance);
147 SetSelfTokenID(tokenId);
148 delete[] perms;
149 }
150
RunAsHelpCommand()151 ErrCode NotificationShellCommand::RunAsHelpCommand()
152 {
153 resultReceiver_.append(HELP_MSG);
154 return ERR_OK;
155 }
156
RunHelp()157 ErrCode NotificationShellCommand::RunHelp()
158 {
159 resultReceiver_.append(DUMP_HELP_MSG);
160 return ERR_OK;
161 }
162
RunAsDumpCommand()163 ErrCode NotificationShellCommand::RunAsDumpCommand()
164 {
165 #ifdef ANM_BUILD_VARIANT_USER
166 resultReceiver_.append("error: user version cannot use dump.\n");
167 return ERR_INVALID_VALUE;
168 #endif
169 ErrCode ret = ERR_OK;
170 std::vector<std::string> infos;
171 std::string cmd;
172 std::string bundle;
173 int32_t userId = SUBSCRIBE_USER_INIT;
174 int32_t recvUserId = SUBSCRIBE_USER_INIT;
175 SetDumpCmdInfo(cmd, bundle, userId, ret, recvUserId);
176 if (ret != ERR_OK) {
177 return ret;
178 }
179 if (cmd.empty()) {
180 resultReceiver_.clear();
181 resultReceiver_ = "request a option 'A' or 'R' or 'D'\n";
182 resultReceiver_.append(DUMP_HELP_MSG);
183 return ERR_INVALID_VALUE;
184 }
185
186 ret = RunDumpCmd(cmd, bundle, userId, recvUserId, infos);
187 int index = 0;
188 for (const auto &info : infos) {
189 resultReceiver_.append("No." + std::to_string(++index) + "\n");
190 resultReceiver_.append(info);
191 }
192 return ret;
193 }
194
RunDumpCmd(const std::string & cmd,const std::string & bundle,int32_t userId,int32_t recvUserId,std::vector<std::string> & infos)195 ErrCode NotificationShellCommand::RunDumpCmd(const std::string& cmd, const std::string& bundle,
196 int32_t userId, int32_t recvUserId, std::vector<std::string> &infos)
197 {
198 if (ans_ != nullptr) {
199 ErrCode ret = ans_->ShellDump(cmd, bundle, userId, recvUserId, infos);
200 if (strncmp(cmd.c_str(), COMMAND_SET_RECENT_COUNT, strlen(COMMAND_SET_RECENT_COUNT)) == 0) {
201 if (ret == ERR_OK) {
202 resultReceiver_.append("set recent count success\n");
203 } else {
204 resultReceiver_.append("set recent count failed\n");
205 }
206 } else {
207 resultReceiver_.append("Total:" + std::to_string(infos.size()) + "\n");
208 }
209 return ret;
210 }
211 return ERR_ANS_SERVICE_NOT_CONNECTED;
212 }
213
SetDumpCmdInfo(std::string & cmd,std::string & bundle,int32_t & userId,ErrCode & ret,int32_t & recvUserId)214 void NotificationShellCommand::SetDumpCmdInfo(std::string &cmd, std::string &bundle, int32_t &userId,
215 ErrCode &ret, int32_t &recvUserId)
216 {
217 int option = -1;
218 bool hasOption = false;
219 while ((option = getopt_long(argc_, argv_, SHORT_OPTIONS, LONG_OPTIONS, nullptr)) != -1) {
220 if (option == '?') {
221 CheckDumpOpt();
222 resultReceiver_.append(DUMP_HELP_MSG);
223 ret = ERR_INVALID_VALUE;
224 return;
225 }
226 hasOption = true;
227 switch (option) {
228 case 'h':
229 ret = RunHelp();
230 break;
231 case 'A':
232 cmd = COMMAND_ACTIVE;
233 break;
234 case 'R':
235 cmd = COMMAND_RECENT;
236 break;
237 #ifdef DISTRIBUTED_NOTIFICATION_SUPPORTED
238 case 'D':
239 cmd = COMMAND_DISTRIBUTED;
240 break;
241 #endif
242 case 'b':
243 bundle = optarg;
244 break;
245 case 'u':
246 userId = atoi(optarg);
247 break;
248 case 'r':
249 recvUserId = atoi(optarg);
250 break;
251 default:
252 resultReceiver_.append(DUMP_HELP_MSG);
253 break;
254 }
255 }
256 if (!hasOption) {
257 resultReceiver_.append(DUMP_HELP_MSG);
258 ret = ERR_INVALID_VALUE;
259 }
260 }
261
CheckDumpOpt()262 void NotificationShellCommand::CheckDumpOpt()
263 {
264 switch (optopt) {
265 case 'b':
266 resultReceiver_.append("error: option 'b' requires a value.\n");
267 break;
268 case 'u':
269 resultReceiver_.append("error: option 'u' requires a value.\n");
270 break;
271 case 'r':
272 resultReceiver_.append("error: option 'r' requires a value.\n");
273 break;
274 default:
275 resultReceiver_.append("error: unknown option.\n");
276 break;
277 }
278 }
279
RunAsSettingCommand()280 ErrCode NotificationShellCommand::RunAsSettingCommand()
281 {
282 #ifdef ANM_BUILD_VARIANT_USER
283 resultReceiver_.append("error: user version cannot use setting.\n");
284 return ERR_INVALID_VALUE;
285 #endif
286 int option = getopt_long(argc_, argv_, SETTING_SHORT_OPTIONS, SETTING_LONG_OPTIONS, nullptr);
287 if (option == '?') {
288 if (optopt == 'c') {
289 resultReceiver_.append("error: option 'c' requires a value.\n");
290 } else if (optopt == 'e') {
291 resultReceiver_.append("error: option 'e' requires a value.\n");
292 } else if (optopt == 'd') {
293 resultReceiver_.append("error: option 'd' requires a value.\n");
294 } else if (optopt == 'k') {
295 resultReceiver_.append("error: option 'k' requires a value.\n");
296 } else if (optopt == 'b') {
297 resultReceiver_.append("error: option 'b' requires a value.\n");
298 } else if (optopt == 'o') {
299 resultReceiver_.append("error: option 'o' requires a value.\n");
300 } else if (optopt == 'g') {
301 resultReceiver_.append("error: option 'g' requires a value.\n");
302 } else {
303 resultReceiver_.append("error: unknown option.\n");
304 }
305 resultReceiver_.append(SETTING_HELP_MSG);
306 return ERR_INVALID_VALUE;
307 }
308 if (option == 'c') {
309 int32_t count = atoi(optarg);
310 if ((count < NOTIFICATION_MIN_COUNT) || (count > NOTIFICATION_MAX_COUNT)) {
311 resultReceiver_.append("error: recent count should between 1 and 1024\n");
312 resultReceiver_.append(SETTING_HELP_MSG);
313 return ERR_INVALID_VALUE;
314 }
315 std::vector<std::string> infos;
316 std::string cmd = COMMAND_SET_RECENT_COUNT;
317 cmd.append(" ").append(std::string(optarg));
318 return RunDumpCmd(cmd, "", SUBSCRIBE_USER_INIT, SUBSCRIBE_USER_INIT, infos);
319 }
320 if (option == 'e') {
321 return RunSetEnableCmd();
322 }
323 if (option == 'd') {
324 return RunSetDeviceStatusCmd();
325 }
326 if (option == 'k') {
327 return RunSetSmartReminderEnabledCmd();
328 }
329 if (option == 'b') {
330 return RunSetDistributedEnabledByBundleCmd();
331 }
332 if (option == 'o') {
333 return RunSetDistributedEnabledBySlotCmd();
334 }
335 if (option == 'g') {
336 return RunGetDeviceStatusCmd();
337 }
338 resultReceiver_.append(SETTING_HELP_MSG);
339 return ERR_INVALID_VALUE;
340 }
341
RunSetEnableCmd()342 ErrCode NotificationShellCommand::RunSetEnableCmd()
343 {
344 if (ans_ == nullptr) {
345 resultReceiver_.append("error: object is null\n");
346 return ERR_ANS_SERVICE_NOT_CONNECTED;
347 }
348
349 NotificationBundleOption bundleOption;
350 std::string info = std::string(optarg);
351 if (std::count(info.begin(), info.end(), ':') != 2) { // 2 (bundleName:uid:enable)
352 resultReceiver_.append("error: setting information error\n");
353 resultReceiver_.append(SETTING_HELP_MSG);
354 return ERR_INVALID_VALUE;
355 }
356
357 size_t pos = info.find(':');
358 bundleOption.SetBundleName(info.substr(0, pos));
359 info = info.substr(pos + 1);
360 pos = info.find(':');
361 bundleOption.SetUid(atoi(info.substr(0, pos).c_str()));
362 bool enable = atoi(info.substr(pos + 1).c_str());
363
364 ErrCode ret = ans_->SetNotificationsEnabledForSpecifiedBundle(bundleOption, "", enable);
365 if (ret == ERR_OK) {
366 resultReceiver_.append("set notification enabled success\n");
367 } else {
368 resultReceiver_.append("set notification enabled failed\n");
369 std::string message = GetAnsErrMessage(ErrorToExternal(ret));
370 resultReceiver_.append("failed reason is " + message + "\n");
371 }
372 return ret;
373 }
374
RunGetDeviceStatusCmd()375 ErrCode NotificationShellCommand::RunGetDeviceStatusCmd()
376 {
377 if (ans_ == nullptr) {
378 resultReceiver_.append("error: object is null\n");
379 return ERR_ANS_SERVICE_NOT_CONNECTED;
380 }
381
382 std::string info = std::string(optarg);
383 if (info.empty()) {
384 resultReceiver_.append("error: getting information error\n");
385 return ERR_INVALID_VALUE;
386 }
387
388 int32_t status = 0;
389 ErrCode ret = ans_->GetTargetDeviceStatus(info, status);
390 if (ret == ERR_OK) {
391 resultReceiver_.append("Get device status success: ");
392 resultReceiver_.append(std::to_string(status));
393 resultReceiver_.append("\n");
394 } else {
395 resultReceiver_.append("Get device status failed\n");
396 std::string message = GetAnsErrMessage(ErrorToExternal(ret));
397 resultReceiver_.append("failed reason is " + message + "\n");
398 }
399 return ret;
400 }
401
RunSetDeviceStatusCmd()402 ErrCode NotificationShellCommand::RunSetDeviceStatusCmd()
403 {
404 if (ans_ == nullptr) {
405 resultReceiver_.append("error: object is null\n");
406 return ERR_ANS_SERVICE_NOT_CONNECTED;
407 }
408
409 std::string deviceType;
410 uint32_t status = 0;
411 std::string info = std::string(optarg);
412 if (std::count(info.begin(), info.end(), ':') != 1) { // 1 (deviceType:status)
413 resultReceiver_.append("error: setting information error\n");
414 resultReceiver_.append(SETTING_HELP_MSG);
415 return ERR_INVALID_VALUE;
416 }
417
418 size_t pos = info.find(':');
419 deviceType = info.substr(0, pos);
420 status = atoi(info.substr(pos + 1).c_str());
421
422 ErrCode ret = ans_->SetTargetDeviceStatus(deviceType, status);
423 if (ret == ERR_OK) {
424 resultReceiver_.append("set device status success\n");
425 } else {
426 resultReceiver_.append("set device status failed\n");
427 std::string message = GetAnsErrMessage(ErrorToExternal(ret));
428 resultReceiver_.append("failed reason is " + message + "\n");
429 }
430 return ret;
431 }
432
RunSetSmartReminderEnabledCmd()433 ErrCode NotificationShellCommand::RunSetSmartReminderEnabledCmd()
434 {
435 if (ans_ == nullptr) {
436 resultReceiver_.append("error: object is null\n");
437 return ERR_ANS_SERVICE_NOT_CONNECTED;
438 }
439
440 std::string deviceType;
441 std::string info = std::string(optarg);
442 if (std::count(info.begin(), info.end(), ':') != 1) { // 1 (deviceType:status)
443 resultReceiver_.append("error: setting information error\n");
444 resultReceiver_.append(SETTING_HELP_MSG);
445 return ERR_INVALID_VALUE;
446 }
447
448 size_t pos = info.find(':');
449 deviceType = info.substr(0, pos);
450 bool enable = atoi(info.substr(pos + 1).c_str());
451
452 ErrCode ret = ans_->SetSmartReminderEnabled(deviceType, enable);
453 if (ret == ERR_OK) {
454 resultReceiver_.append("set collaboration switch success\n");
455 } else {
456 resultReceiver_.append("set collaboration switch failed\n");
457 std::string message = GetAnsErrMessage(ErrorToExternal(ret));
458 resultReceiver_.append("failed reason is " + message + "\n");
459 }
460 return ret;
461 }
462
RunSetDistributedEnabledByBundleCmd()463 ErrCode NotificationShellCommand::RunSetDistributedEnabledByBundleCmd()
464 {
465 if (ans_ == nullptr) {
466 resultReceiver_.append("error: object is null\n");
467 return ERR_ANS_SERVICE_NOT_CONNECTED;
468 }
469
470 std::string deviceType;
471 NotificationBundleOption bundleOption;
472 std::string info = std::string(optarg);
473 if (std::count(info.begin(), info.end(), ':') != PARAM_NUM_THREE) { // 4 (deviceType:bundleName:uid:status)
474 resultReceiver_.append("error: setting information error\n");
475 resultReceiver_.append(SETTING_HELP_MSG);
476 return ERR_INVALID_VALUE;
477 }
478
479 size_t pos = info.find(':');
480 deviceType = info.substr(0, pos);
481
482 info = info.substr(pos + 1);
483 pos = info.find(':');
484 bundleOption.SetBundleName(info.substr(0, pos));
485
486 info = info.substr(pos + 1);
487 pos = info.find(':');
488 bundleOption.SetUid(atoi(info.substr(0, pos).c_str()));
489
490 bool enable = atoi(info.substr(pos + 1).c_str());
491
492 ErrCode ret = ans_->SetDistributedEnabledByBundle(bundleOption, deviceType, enable);
493 if (ret == ERR_OK) {
494 resultReceiver_.append("set bundle collaboration switch success\n");
495 } else {
496 resultReceiver_.append("set bundle collaboration switch failed\n");
497 std::string message = GetAnsErrMessage(ErrorToExternal(ret));
498 resultReceiver_.append("failed reason is " + message + "\n");
499 }
500 return ret;
501 }
502
RunSetDistributedEnabledBySlotCmd()503 ErrCode NotificationShellCommand::RunSetDistributedEnabledBySlotCmd()
504 {
505 if (ans_ == nullptr) {
506 resultReceiver_.append("error: object is null\n");
507 return ERR_ANS_SERVICE_NOT_CONNECTED;
508 }
509
510 std::string deviceType;
511 int32_t slotType;
512 std::string info = std::string(optarg);
513 if (std::count(info.begin(), info.end(), ':') != PARAM_NUM_TWO) { //3(deviceType:slotType:status)
514 resultReceiver_.append("error: setting information error\n");
515 resultReceiver_.append(SETTING_HELP_MSG);
516 return ERR_INVALID_VALUE;
517 }
518
519 size_t pos = info.find(':');
520 deviceType = info.substr(0, pos);
521
522 info = info.substr(pos + 1);
523 pos = info.find(':');
524 slotType = atoi(info.substr(0, pos).c_str());
525 NotificationConstant::SlotType outType = NotificationConstant::SlotType::OTHER;
526 if (!NotificationNapi::AnsEnumUtil::SlotTypeJSToC(NotificationNapi::SlotType(slotType), outType)) {
527 resultReceiver_.append("error: slotType information error\n");
528 resultReceiver_.append(SETTING_HELP_MSG);
529 return ERR_INVALID_VALUE;
530 }
531 bool enable = atoi(info.substr(pos + 1).c_str());
532
533 ErrCode ret = ans_->SetDistributedEnabledBySlot(outType, deviceType, enable);
534 if (ret == ERR_OK) {
535 resultReceiver_.append("set slot collaboration switch success\n");
536 } else {
537 resultReceiver_.append("set slot collaboration switch failed\n");
538 std::string message = GetAnsErrMessage(ErrorToExternal(ret));
539 resultReceiver_.append("failed reason is " + message + "\n");
540 }
541 return ret;
542 }
543 } // namespace Notification
544 } // namespace OHOS
545