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