• 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_inner_errors.h"
22 #include "nativetoken_kit.h"
23 #include "notification_bundle_option.h"
24 #include "token_setproc.h"
25 #include "singleton.h"
26 
27 namespace OHOS {
28 namespace Notification {
29 namespace {
30 constexpr char COMMAND_ACTIVE[] = "active";
31 constexpr char COMMAND_RECENT[] = "recent";
32 #ifdef DISTRIBUTED_NOTIFICATION_SUPPORTED
33 constexpr char COMMAND_DISTRIBUTED[] = "distributed";
34 constexpr char SHORT_OPTIONS[] = "hARDb:u:";
35 #else
36 constexpr char SHORT_OPTIONS[] = "hARb:u:";
37 #endif
38 constexpr char COMMAND_SET_RECENT_COUNT[] = "setRecentCount";
39 const struct option LONG_OPTIONS[] = {
40     {"help", no_argument, nullptr, 'h'},
41     {COMMAND_ACTIVE, no_argument, nullptr, 'A'},
42     {COMMAND_RECENT, no_argument, nullptr, 'R'},
43 #ifdef DISTRIBUTED_NOTIFICATION_SUPPORTED
44     {COMMAND_DISTRIBUTED, no_argument, nullptr, 'D'},
45 #endif
46     {"bundle", required_argument, nullptr, 'b'},
47     {"user-id", required_argument, nullptr, 'u'},
48 };
49 constexpr char HELP_MSG[] =
50     "usage: anm <command> [<options>]\n"
51     "These are common commands list:\n"
52     "  help                         list available commands\n"
53     "  dump                         dump the info of notification\n"
54     "  setting                      notification setting\n";
55 constexpr char DUMP_HELP_MSG[] =
56     "usage: anm dump [<options>]\n"
57     "options list:\n"
58     "  --help, -h                   help menu\n"
59 #ifdef DISTRIBUTED_NOTIFICATION_SUPPORTED
60     "  --distributed, -D            list all distributed notifications by remote device\n"
61 #endif
62     "  --active,  -A                 list all active notifications\n"
63     "  --recent,  -R                 list recent notifications\n"
64     "  --bundle,  -b  <name>         dump the info filter by the specified bundle name\n"
65     "  --user-id, -u  <userId>       dump the info filter by the specified userId\n";
66 
67 constexpr char SETTING_SHORT_OPTIONS[] = "c:e:";
68 const struct option SETTING_LONG_OPTIONS[] = {
69     {"help", no_argument, nullptr, 'h'},
70     {"recent-count", required_argument, nullptr, 'c'},
71     {"enable-notification", required_argument, nullptr, 'e'},
72 };
73 constexpr char SETTING_HELP_MSG[] =
74     "usage: anm setting [<options>]\n"
75     "options list:\n"
76     "  --help, -h                   help menu\n"
77     "  --recent-count -c <number>   set the max count of recent notifications keeping in memory\n"
78     "  --enable-notification -e <bundleName:uid:enable> set notification enabled for the bundle, eg: -e com.example:10100:1\n";
79 }  // namespace
80 
NotificationShellCommand(int argc,char * argv[])81 NotificationShellCommand::NotificationShellCommand(int argc, char *argv[]) : ShellCommand(argc, argv, "anm_dump")
82 {}
83 
CreateCommandMap()84 ErrCode NotificationShellCommand::CreateCommandMap()
85 {
86     commandMap_ = {
87         {"help", std::bind(&NotificationShellCommand::RunAsHelpCommand, this)},
88         {"dump", std::bind(&NotificationShellCommand::RunAsDumpCommand, this)},
89         {"setting", std::bind(&NotificationShellCommand::RunAsSettingCommand, this)},
90     };
91     return ERR_OK;
92 }
93 
Init()94 ErrCode NotificationShellCommand::Init()
95 {
96     SetNativeToken();
97     ErrCode result = OHOS::ERR_OK;
98     if (!ans_) {
99         ans_ = DelayedSingleton<AnsNotification>::GetInstance();
100     }
101     if (!ans_) {
102         result = OHOS::ERR_INVALID_VALUE;
103     }
104     return result;
105 }
106 
SetNativeToken()107 void NotificationShellCommand::SetNativeToken()
108 {
109     uint64_t tokenId;
110     const char **perms = new const char *[1];
111     perms[0] = "ohos.permission.NOTIFICATION_CONTROLLER";
112     NativeTokenInfoParams infoInstance = {
113         .dcapsNum = 0,
114         .permsNum = 1,
115         .aclsNum = 0,
116         .dcaps = nullptr,
117         .perms = perms,
118         .acls = nullptr,
119         .aplStr = "system_basic",
120     };
121 
122     infoInstance.processName = "anm";
123     tokenId = GetAccessTokenId(&infoInstance);
124     SetSelfTokenID(tokenId);
125     delete[] perms;
126 }
127 
RunAsHelpCommand()128 ErrCode NotificationShellCommand::RunAsHelpCommand()
129 {
130     resultReceiver_.append(HELP_MSG);
131     return ERR_OK;
132 }
133 
RunHelp()134 ErrCode NotificationShellCommand::RunHelp()
135 {
136     resultReceiver_.append(DUMP_HELP_MSG);
137     return ERR_OK;
138 }
139 
RunAsDumpCommand()140 ErrCode NotificationShellCommand::RunAsDumpCommand()
141 {
142     ErrCode ret = ERR_OK;
143     std::vector<std::string> infos;
144     std::string cmd;
145     std::string bundle;
146     int32_t userId = SUBSCRIBE_USER_INIT;
147     SetDumpCmdInfo(cmd, bundle, userId, ret);
148     if (ret != ERR_OK) {
149         return ret;
150     }
151     if (cmd.empty()) {
152         resultReceiver_.clear();
153         resultReceiver_ = "request a option 'A' or 'R' or 'D'\n";
154         resultReceiver_.append(DUMP_HELP_MSG);
155         return ERR_INVALID_VALUE;
156     }
157 
158     ret = RunDumpCmd(cmd, bundle, userId, infos);
159     int index = 0;
160     for (const auto &info : infos) {
161         resultReceiver_.append("No." + std::to_string(++index) + "\n");
162         resultReceiver_.append(info);
163     }
164     return ret;
165 }
166 
RunDumpCmd(const std::string & cmd,const std::string & bundle,int32_t userId,std::vector<std::string> & infos)167 ErrCode NotificationShellCommand::RunDumpCmd(const std::string& cmd, const std::string& bundle,
168     int32_t userId, std::vector<std::string> &infos)
169 {
170     if (ans_ != nullptr) {
171         ErrCode ret = ans_->ShellDump(cmd, bundle, userId, infos);
172         if (strncmp(cmd.c_str(), COMMAND_SET_RECENT_COUNT, strlen(COMMAND_SET_RECENT_COUNT)) == 0) {
173             if (ret == ERR_OK) {
174                 resultReceiver_.append("set recent count success\n");
175             } else {
176                 resultReceiver_.append("set recent count failed\n");
177             }
178         } else {
179             resultReceiver_.append("Total:" + std::to_string(infos.size()) + "\n");
180         }
181         return ret;
182     }
183     return ERR_ANS_SERVICE_NOT_CONNECTED;
184 }
185 
SetDumpCmdInfo(std::string & cmd,std::string & bundle,int32_t & userId,ErrCode & ret)186 void NotificationShellCommand::SetDumpCmdInfo(std::string &cmd, std::string &bundle, int32_t &userId, ErrCode &ret)
187 {
188     int option = -1;
189     bool hasOption = false;
190     while ((option = getopt_long(argc_, argv_, SHORT_OPTIONS, LONG_OPTIONS, nullptr)) != -1) {
191         if (option == '?') {
192             CheckDumpOpt();
193             resultReceiver_.append(DUMP_HELP_MSG);
194             ret = ERR_INVALID_VALUE;
195             return;
196         }
197         hasOption = true;
198         switch (option) {
199             case 'h':
200                 ret = RunHelp();
201                 break;
202             case 'A':
203                 cmd = COMMAND_ACTIVE;
204                 break;
205             case 'R':
206                 cmd = COMMAND_RECENT;
207                 break;
208 #ifdef DISTRIBUTED_NOTIFICATION_SUPPORTED
209             case 'D':
210                 cmd = COMMAND_DISTRIBUTED;
211                 break;
212 #endif
213             case 'b':
214                 bundle = optarg;
215                 break;
216             case 'u':
217                 userId = atoi(optarg);
218                 break;
219             default:
220                 resultReceiver_.append(DUMP_HELP_MSG);
221                 break;
222         }
223     }
224     if (!hasOption) {
225         resultReceiver_.append(DUMP_HELP_MSG);
226         ret = ERR_INVALID_VALUE;
227     }
228 }
229 
CheckDumpOpt()230 void NotificationShellCommand::CheckDumpOpt()
231 {
232     switch (optopt) {
233         case 'b':
234             resultReceiver_.append("error: option 'b' requires a value.\n");
235             break;
236         case 'u':
237             resultReceiver_.append("error: option 'u' requires a value.\n");
238             break;
239         default:
240             resultReceiver_.append("error: unknown option.\n");
241             break;
242     }
243 }
244 
RunAsSettingCommand()245 ErrCode NotificationShellCommand::RunAsSettingCommand()
246 {
247     int option = getopt_long(argc_, argv_, SETTING_SHORT_OPTIONS, SETTING_LONG_OPTIONS, nullptr);
248     if (option == '?') {
249         if (optopt == 'c') {
250             resultReceiver_.append("error: option 'c' requires a value.\n");
251         } else if (optopt == 'e') {
252             resultReceiver_.append("error: option 'e' requires a value.\n");
253         } else {
254             resultReceiver_.append("error: unknown option.\n");
255         }
256         resultReceiver_.append(SETTING_HELP_MSG);
257         return ERR_INVALID_VALUE;
258     }
259     if (option == 'c') {
260         int32_t count = atoi(optarg);
261         if ((count < NOTIFICATION_MIN_COUNT) || (count > NOTIFICATION_MAX_COUNT)) {
262             resultReceiver_.append("error: recent count should between 1 and 1024\n");
263             resultReceiver_.append(SETTING_HELP_MSG);
264             return ERR_INVALID_VALUE;
265         }
266         std::vector<std::string> infos;
267         std::string cmd = COMMAND_SET_RECENT_COUNT;
268         cmd.append(" ").append(std::string(optarg));
269         return RunDumpCmd(cmd, "", SUBSCRIBE_USER_INIT, infos);
270     }
271     if (option == 'e') {
272         return RunSetEnableCmd();
273     }
274 
275     resultReceiver_.append(SETTING_HELP_MSG);
276     return ERR_INVALID_VALUE;
277 }
278 
RunSetEnableCmd()279 ErrCode NotificationShellCommand::RunSetEnableCmd()
280 {
281     if (ans_ == nullptr) {
282         resultReceiver_.append("error: object is null\n");
283         return ERR_ANS_SERVICE_NOT_CONNECTED;
284     }
285 
286     NotificationBundleOption bundleOption;
287     std::string info = std::string(optarg);
288     if (std::count(info.begin(), info.end(), ':') != 2) {  // 2 (bundleName:uid:enable)
289         resultReceiver_.append("error: setting information error\n");
290         resultReceiver_.append(SETTING_HELP_MSG);
291         return ERR_INVALID_VALUE;
292     }
293 
294     size_t pos = info.find(':');
295     bundleOption.SetBundleName(info.substr(0, pos));
296     info = info.substr(pos + 1);
297     pos = info.find(':');
298     bundleOption.SetUid(atoi(info.substr(0, pos).c_str()));
299     bool enable = atoi(info.substr(pos + 1).c_str());
300 
301     ErrCode ret = ans_->SetNotificationsEnabledForSpecifiedBundle(bundleOption, "", enable);
302     if (ret == ERR_OK) {
303         resultReceiver_.append("set notification enabled success\n");
304     } else {
305         resultReceiver_.append("set notification enabled failed\n");
306     }
307     return ret;
308 }
309 }  // namespace Notification
310 }  // namespace OHOS
311