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