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