• 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 (std::nothrow) const char *[1];
111     if (perms == nullptr) {
112         ANS_LOGE("Failed to create buffer.");
113         return;
114     }
115     perms[0] = "ohos.permission.NOTIFICATION_CONTROLLER";
116     NativeTokenInfoParams infoInstance = {
117         .dcapsNum = 0,
118         .permsNum = 1,
119         .aclsNum = 0,
120         .dcaps = nullptr,
121         .perms = perms,
122         .acls = nullptr,
123         .aplStr = "system_basic",
124     };
125 
126     infoInstance.processName = "anm";
127     tokenId = GetAccessTokenId(&infoInstance);
128     SetSelfTokenID(tokenId);
129     delete[] perms;
130 }
131 
RunAsHelpCommand()132 ErrCode NotificationShellCommand::RunAsHelpCommand()
133 {
134     resultReceiver_.append(HELP_MSG);
135     return ERR_OK;
136 }
137 
RunHelp()138 ErrCode NotificationShellCommand::RunHelp()
139 {
140     resultReceiver_.append(DUMP_HELP_MSG);
141     return ERR_OK;
142 }
143 
RunAsDumpCommand()144 ErrCode NotificationShellCommand::RunAsDumpCommand()
145 {
146     ErrCode ret = ERR_OK;
147     std::vector<std::string> infos;
148     std::string cmd;
149     std::string bundle;
150     int32_t userId = SUBSCRIBE_USER_INIT;
151     SetDumpCmdInfo(cmd, bundle, userId, ret);
152     if (ret != ERR_OK) {
153         return ret;
154     }
155     if (cmd.empty()) {
156         resultReceiver_.clear();
157         resultReceiver_ = "request a option 'A' or 'R' or 'D'\n";
158         resultReceiver_.append(DUMP_HELP_MSG);
159         return ERR_INVALID_VALUE;
160     }
161 
162     ret = RunDumpCmd(cmd, bundle, userId, infos);
163     int index = 0;
164     for (const auto &info : infos) {
165         resultReceiver_.append("No." + std::to_string(++index) + "\n");
166         resultReceiver_.append(info);
167     }
168     return ret;
169 }
170 
RunDumpCmd(const std::string & cmd,const std::string & bundle,int32_t userId,std::vector<std::string> & infos)171 ErrCode NotificationShellCommand::RunDumpCmd(const std::string& cmd, const std::string& bundle,
172     int32_t userId, std::vector<std::string> &infos)
173 {
174     if (ans_ != nullptr) {
175         ErrCode ret = ans_->ShellDump(cmd, bundle, userId, infos);
176         if (strncmp(cmd.c_str(), COMMAND_SET_RECENT_COUNT, strlen(COMMAND_SET_RECENT_COUNT)) == 0) {
177             if (ret == ERR_OK) {
178                 resultReceiver_.append("set recent count success\n");
179             } else {
180                 resultReceiver_.append("set recent count failed\n");
181             }
182         } else {
183             resultReceiver_.append("Total:" + std::to_string(infos.size()) + "\n");
184         }
185         return ret;
186     }
187     return ERR_ANS_SERVICE_NOT_CONNECTED;
188 }
189 
SetDumpCmdInfo(std::string & cmd,std::string & bundle,int32_t & userId,ErrCode & ret)190 void NotificationShellCommand::SetDumpCmdInfo(std::string &cmd, std::string &bundle, int32_t &userId, ErrCode &ret)
191 {
192     int option = -1;
193     bool hasOption = false;
194     while ((option = getopt_long(argc_, argv_, SHORT_OPTIONS, LONG_OPTIONS, nullptr)) != -1) {
195         if (option == '?') {
196             CheckDumpOpt();
197             resultReceiver_.append(DUMP_HELP_MSG);
198             ret = ERR_INVALID_VALUE;
199             return;
200         }
201         hasOption = true;
202         switch (option) {
203             case 'h':
204                 ret = RunHelp();
205                 break;
206             case 'A':
207                 cmd = COMMAND_ACTIVE;
208                 break;
209             case 'R':
210                 cmd = COMMAND_RECENT;
211                 break;
212 #ifdef DISTRIBUTED_NOTIFICATION_SUPPORTED
213             case 'D':
214                 cmd = COMMAND_DISTRIBUTED;
215                 break;
216 #endif
217             case 'b':
218                 bundle = optarg;
219                 break;
220             case 'u':
221                 userId = atoi(optarg);
222                 break;
223             default:
224                 resultReceiver_.append(DUMP_HELP_MSG);
225                 break;
226         }
227     }
228     if (!hasOption) {
229         resultReceiver_.append(DUMP_HELP_MSG);
230         ret = ERR_INVALID_VALUE;
231     }
232 }
233 
CheckDumpOpt()234 void NotificationShellCommand::CheckDumpOpt()
235 {
236     switch (optopt) {
237         case 'b':
238             resultReceiver_.append("error: option 'b' requires a value.\n");
239             break;
240         case 'u':
241             resultReceiver_.append("error: option 'u' requires a value.\n");
242             break;
243         default:
244             resultReceiver_.append("error: unknown option.\n");
245             break;
246     }
247 }
248 
RunAsSettingCommand()249 ErrCode NotificationShellCommand::RunAsSettingCommand()
250 {
251 #ifdef ANM_BUILD_VARIANT_USER
252      resultReceiver_.append("error: user version cannot use setting.\n");
253      return ERR_INVALID_VALUE;
254 #endif
255     int option = getopt_long(argc_, argv_, SETTING_SHORT_OPTIONS, SETTING_LONG_OPTIONS, nullptr);
256     if (option == '?') {
257         if (optopt == 'c') {
258             resultReceiver_.append("error: option 'c' requires a value.\n");
259         } else if (optopt == 'e') {
260             resultReceiver_.append("error: option 'e' requires a value.\n");
261         } else {
262             resultReceiver_.append("error: unknown option.\n");
263         }
264         resultReceiver_.append(SETTING_HELP_MSG);
265         return ERR_INVALID_VALUE;
266     }
267     if (option == 'c') {
268         int32_t count = atoi(optarg);
269         if ((count < NOTIFICATION_MIN_COUNT) || (count > NOTIFICATION_MAX_COUNT)) {
270             resultReceiver_.append("error: recent count should between 1 and 1024\n");
271             resultReceiver_.append(SETTING_HELP_MSG);
272             return ERR_INVALID_VALUE;
273         }
274         std::vector<std::string> infos;
275         std::string cmd = COMMAND_SET_RECENT_COUNT;
276         cmd.append(" ").append(std::string(optarg));
277         return RunDumpCmd(cmd, "", SUBSCRIBE_USER_INIT, infos);
278     }
279     if (option == 'e') {
280         return RunSetEnableCmd();
281     }
282 
283     resultReceiver_.append(SETTING_HELP_MSG);
284     return ERR_INVALID_VALUE;
285 }
286 
RunSetEnableCmd()287 ErrCode NotificationShellCommand::RunSetEnableCmd()
288 {
289     if (ans_ == nullptr) {
290         resultReceiver_.append("error: object is null\n");
291         return ERR_ANS_SERVICE_NOT_CONNECTED;
292     }
293 
294     NotificationBundleOption bundleOption;
295     std::string info = std::string(optarg);
296     if (std::count(info.begin(), info.end(), ':') != 2) {  // 2 (bundleName:uid:enable)
297         resultReceiver_.append("error: setting information error\n");
298         resultReceiver_.append(SETTING_HELP_MSG);
299         return ERR_INVALID_VALUE;
300     }
301 
302     size_t pos = info.find(':');
303     bundleOption.SetBundleName(info.substr(0, pos));
304     info = info.substr(pos + 1);
305     pos = info.find(':');
306     bundleOption.SetUid(atoi(info.substr(0, pos).c_str()));
307     bool enable = atoi(info.substr(pos + 1).c_str());
308 
309     ErrCode ret = ans_->SetNotificationsEnabledForSpecifiedBundle(bundleOption, "", enable);
310     if (ret == ERR_OK) {
311         resultReceiver_.append("set notification enabled success\n");
312     } else {
313         resultReceiver_.append("set notification enabled failed\n");
314     }
315     return ret;
316 }
317 }  // namespace Notification
318 }  // namespace OHOS
319