1 /*
2 * Copyright (c) 2020 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 "ability_tool.h"
17
18 #include <cstdio>
19 #include <cstring>
20 #include <ohos_errno.h>
21 #include <liteipc_adapter.h>
22 #include <samgr_lite.h>
23 #include <securec.h>
24 #include <semaphore.h>
25
26 #include "ability_errors.h"
27 #include "ability_kit_command.h"
28 #include "ability_manager.h"
29 #include "ability_service_interface.h"
30 #include "adapter.h"
31 #include "want_utils.h"
32
33 namespace OHOS {
34 namespace {
35 constexpr int WAIT_TIMEOUT = 30; // 5 second
36 constexpr int MAX_BUFFER_SIZE_PER = 1024; // 1024 byte
37 constexpr char CMD_START_ABILITY[] = "start";
38 constexpr char CMD_STOP_ABILITY[] = "stopability";
39 constexpr char CMD_TERMINATE_APP[] = "terminate";
40 constexpr char CMD_DUMP_ABILITY[] = "dump";
41 } // namespace
42
43 static sem_t g_sem;
44
~AbilityTool()45 AbilityTool::~AbilityTool()
46 {
47 ClearElement(&elementName_);
48 UnregisterIpcCallback(identity_);
49 }
50
SetBundleName(const char * bundleName)51 bool AbilityTool::SetBundleName(const char *bundleName)
52 {
53 if (bundleName == nullptr || strlen(bundleName) == 0) {
54 return false;
55 }
56 SetElementBundleName(&elementName_, bundleName);
57 return true;
58 }
59
SetAbilityName(const char * abilityName)60 bool AbilityTool::SetAbilityName(const char *abilityName)
61 {
62 if (abilityName == nullptr || strlen(abilityName) == 0) {
63 return false;
64 }
65 SetElementAbilityName(&elementName_, abilityName);
66 return true;
67 }
68
SetExtra(const char * extra)69 void AbilityTool::SetExtra(const char *extra)
70 {
71 extra_ = const_cast<char *>(extra);
72 }
73
SetCommand(const char * command)74 bool AbilityTool::SetCommand(const char *command)
75 {
76 if (command == nullptr) {
77 return false;
78 }
79 if (strcmp(command, CMD_START_ABILITY) != 0 &&
80 strcmp(command, CMD_STOP_ABILITY) != 0 &&
81 strcmp(command, CMD_TERMINATE_APP) != 0 &&
82 strcmp(command, CMD_DUMP_ABILITY) != 0) {
83 return false;
84 }
85 printf("receive command: %s\n", command);
86 command_ = const_cast<char *>(command);
87 return true;
88 }
89
SetDumpAll()90 void AbilityTool::SetDumpAll()
91 {
92 dumpAll_ = true;
93 }
94
RunCommand()95 bool AbilityTool::RunCommand()
96 {
97 if (command_ == nullptr) {
98 printf("unknown command\n");
99 return false;
100 }
101 IUnknown *iUnknown = SAMGR_GetInstance()->GetFeatureApi(AMS_SERVICE, AMS_INNER_FEATURE);
102 if (iUnknown == nullptr) {
103 printf("ams inner unknown is null\n");
104 return false;
105 }
106 IClientProxy *innerProxy = nullptr;
107 (void)iUnknown->QueryInterface(iUnknown, CLIENT_PROXY_VER, (void **)&innerProxy);
108 if (innerProxy == nullptr) {
109 printf("ams inner feature is null\n");
110 return false;
111 }
112
113 if (RegisterIpcCallback(AbilityTool::AaCallback, 0, IPC_WAIT_FOREVER, &identity_, this) != 0) {
114 printf("registerIpcCallback failed\n");
115 return false;
116 }
117 bool retVal = false;
118 if (strcmp(command_, CMD_START_ABILITY) == 0) {
119 retVal = InnerStartAbility();
120 } else if (strcmp(command_, CMD_STOP_ABILITY) == 0) {
121 retVal = InnerStopAbility();
122 } else if (strcmp(command_, CMD_TERMINATE_APP) == 0) {
123 retVal = TerminateApp(innerProxy);
124 } else if (strcmp(command_, CMD_DUMP_ABILITY) == 0) {
125 retVal = Dump(innerProxy);
126 } else {
127 printf("unknown command: %s\n", command_);
128 }
129 return retVal;
130 }
131
BuildWant()132 Want* AbilityTool::BuildWant()
133 {
134 Want *want = new Want();
135 if (memset_s(want, sizeof(Want), 0, sizeof(Want)) != EOK) {
136 delete want;
137 return nullptr;
138 }
139 if (!dumpAll_) {
140 if (elementName_.abilityName == nullptr || strlen(elementName_.abilityName) == 0 ||
141 elementName_.bundleName == nullptr || strlen(elementName_.bundleName) == 0) {
142 printf("ability name or bundle name is not entered\n");
143 delete want;
144 return nullptr;
145 }
146 SetWantElement(want, elementName_);
147 }
148 if (strcmp(command_, CMD_DUMP_ABILITY) == 0) {
149 SetWantSvcIdentity(want, identity_);
150 }
151 if (extra_ != nullptr) {
152 SetWantData(want, extra_, strlen(extra_) + 1);
153 }
154 return want;
155 }
156
InnerStartAbility()157 bool AbilityTool::InnerStartAbility()
158 {
159 Want *want = BuildWant();
160 if (want == nullptr) {
161 return false;
162 }
163 int ret = StartAbility(want);
164 ClearWant(want);
165 delete want;
166 return ret == ERR_OK;
167 }
168
InnerStopAbility()169 bool AbilityTool::InnerStopAbility()
170 {
171 Want *want = BuildWant();
172 if (want == nullptr) {
173 return false;
174 }
175 int ret = StopAbility(want);
176 ClearWant(want);
177 delete want;
178 return ret == ERR_OK;
179 }
180
TerminateApp(IClientProxy * proxy) const181 bool AbilityTool::TerminateApp(IClientProxy *proxy) const
182 {
183 if (proxy == nullptr) {
184 return false;
185 }
186 if (elementName_.bundleName == nullptr || strlen(elementName_.bundleName) == 0) {
187 printf("invalid argument\n");
188 return false;
189 }
190 IpcIo req;
191 char data[IPC_IO_DATA_MAX];
192 IpcIoInit(&req, data, IPC_IO_DATA_MAX, 0);
193 IpcIoPushString(&req, elementName_.bundleName);
194 return proxy->Invoke(proxy, TERMINATE_APP, &req, nullptr, nullptr) == EC_SUCCESS;
195 }
196
Dump(IClientProxy * proxy)197 bool AbilityTool::Dump(IClientProxy *proxy)
198 {
199 if (proxy == nullptr) {
200 return false;
201 }
202 Want *want = BuildWant();
203 if (want == nullptr) {
204 return false;
205 }
206
207 IpcIo req;
208 char data[IPC_IO_DATA_MAX];
209 IpcIoInit(&req, data, IPC_IO_DATA_MAX, MAX_OBJECTS);
210 if (!SerializeWant(&req, want)) {
211 printf("SerializeWant failed\n");
212 ClearWant(want);
213 delete want;
214 return false;
215 }
216 ClearWant(want);
217 delete want;
218 if (proxy->Invoke(proxy, DUMP_ABILITY, &req, nullptr, nullptr) != EC_SUCCESS) {
219 printf("dumpAbility failed\n");
220 return false;
221 }
222 if (sem_init(&g_sem, 0, 0)) {
223 printf("sem_init failed\n");
224 return false;
225 }
226 printf("wait for callback\n");
227 struct timespec ts = { 0, 0 };
228 clock_gettime(CLOCK_REALTIME, &ts);
229 ts.tv_sec += WAIT_TIMEOUT;
230 sem_timedwait(&g_sem, &ts);
231 printf("sem exit\n");
232 return true;
233 }
234
AaCallback(const IpcContext * context,void * ipcMsg,IpcIo * data,void * arg)235 int32_t AbilityTool::AaCallback(const IpcContext* context, void *ipcMsg, IpcIo *data, void *arg)
236 {
237 printf("get ability info\n");
238 if (ipcMsg == nullptr) {
239 printf("ams call back error, ipcMsg is null\n");
240 return -1;
241 }
242 auto abilityTool = static_cast<AbilityTool *>(arg);
243 if (abilityTool == nullptr) {
244 printf("ams call back error, abilityTool is null\n");
245 FreeBuffer(nullptr, ipcMsg);
246 return -1;
247 }
248
249 uint32_t funcId = 0;
250 GetCode(ipcMsg, &funcId);
251 uint32_t flag = 0;
252 GetFlag(ipcMsg, &flag);
253 switch (funcId) {
254 case SCHEDULER_APP_INIT: {
255 ElementName element = {};
256 DeserializeElement(&element, data);
257 int ret = IpcIoPopInt32(data);
258 printf("ams call back, start %s.%s ret = %d\n", element.bundleName, element.abilityName, ret);
259 ClearElement(&element);
260 break;
261 }
262 case SCHEDULER_DUMP_ABILITY: {
263 #ifdef __LINUX__
264 size_t len = 0;
265 char *result = reinterpret_cast<char *>(IpcIoPopString(data, &len));
266 #else
267 BuffPtr *buff = IpcIoPopDataBuff(data);
268 if ((buff == nullptr) || (buff->buff == nullptr)) {
269 printf("ams call back error, buff is empty\n");
270 if (flag == LITEIPC_FLAG_ONEWAY) {
271 FreeBuffer(nullptr, ipcMsg);
272 }
273 return false;
274 }
275 char *result = static_cast<char *>(buff->buff);
276 if ((buff->buffSz > 0) && (result[buff->buffSz - 1] != '\0')) {
277 printf("Wrong message format.\n}\n");
278 FreeBuffer(nullptr, buff->buff);
279 break;
280 }
281 int len = strlen(result);
282 #endif
283 printf("dump ability info:\n");
284 if (!abilityTool->dumpAll_) {
285 printf("[%s][%s]\n", abilityTool->elementName_.bundleName, abilityTool->elementName_.abilityName);
286 }
287 printf("{\n");
288 for (int i = 0; i <= (len - 1) / MAX_BUFFER_SIZE_PER; i++) {
289 int start = MAX_BUFFER_SIZE_PER * i;
290 int size = (len - start) < MAX_BUFFER_SIZE_PER ? (len - start) : MAX_BUFFER_SIZE_PER;
291 printf("%-.*s", size, result + start);
292 }
293 printf("}\n");
294 #ifndef __LINUX__
295 FreeBuffer(nullptr, buff->buff);
296 #endif
297 break;
298 }
299 default: {
300 printf("ams call back error, funcId: %u\n", funcId);
301 break;
302 }
303 }
304 if (flag == LITEIPC_FLAG_ONEWAY) {
305 FreeBuffer(nullptr, ipcMsg);
306 }
307 sem_post(&g_sem);
308 return 0;
309 }
310 } // namespace OHOS
311