• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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