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 <ctime>
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 "ipc_skeleton.h"
32 #include "want_utils.h"
33
34 namespace OHOS {
35 namespace {
36 constexpr int WAIT_TIMEOUT = 30; // 5 second
37 constexpr int MAX_BUFFER_SIZE_PER = 1024; // 1024 byte
38 constexpr char CMD_START_ABILITY[] = "start";
39 constexpr char CMD_STOP_ABILITY[] = "stopability";
40 constexpr char CMD_TERMINATE_APP[] = "terminate";
41 constexpr char CMD_DUMP_ABILITY[] = "dump";
42 } // namespace
43
44 static sem_t g_sem;
45
~AbilityTool()46 AbilityTool::~AbilityTool()
47 {
48 ClearElement(&elementName_);
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 objectStub_.func = AbilityTool::AaCallback;
114 objectStub_.args = (void*)this;
115 objectStub_.isRemote = false;
116 identity_.handle = IPC_INVALID_HANDLE;
117 identity_.token = SERVICE_TYPE_ANONYMOUS;
118 identity_.cookie = reinterpret_cast<uintptr_t>(&objectStub_);
119
120 bool retVal = false;
121 if (strcmp(command_, CMD_START_ABILITY) == 0) {
122 retVal = InnerStartAbility();
123 } else if (strcmp(command_, CMD_STOP_ABILITY) == 0) {
124 retVal = InnerStopAbility();
125 } else if (strcmp(command_, CMD_TERMINATE_APP) == 0) {
126 retVal = TerminateApp(innerProxy);
127 } else if (strcmp(command_, CMD_DUMP_ABILITY) == 0) {
128 retVal = Dump(innerProxy);
129 } else {
130 printf("unknown command: %s\n", command_);
131 }
132 return retVal;
133 }
134
BuildWant()135 Want* AbilityTool::BuildWant()
136 {
137 Want *want = new Want();
138 if (memset_s(want, sizeof(Want), 0, sizeof(Want)) != EOK) {
139 delete want;
140 return nullptr;
141 }
142 if (!dumpAll_) {
143 if (elementName_.abilityName == nullptr || strlen(elementName_.abilityName) == 0 ||
144 elementName_.bundleName == nullptr || strlen(elementName_.bundleName) == 0) {
145 printf("ability name or bundle name is not entered\n");
146 delete want;
147 return nullptr;
148 }
149 SetWantElement(want, elementName_);
150 }
151 if (strcmp(command_, CMD_DUMP_ABILITY) == 0) {
152 SetWantSvcIdentity(want, identity_);
153 }
154 if (extra_ != nullptr) {
155 SetWantData(want, extra_, strlen(extra_) + 1);
156 }
157 return want;
158 }
159
InnerStartAbility()160 bool AbilityTool::InnerStartAbility()
161 {
162 Want *want = BuildWant();
163 if (want == nullptr) {
164 return false;
165 }
166 int ret = StartAbility(want);
167 ClearWant(want);
168 delete want;
169 return ret == ERR_OK;
170 }
171
InnerStopAbility()172 bool AbilityTool::InnerStopAbility()
173 {
174 Want *want = BuildWant();
175 if (want == nullptr) {
176 return false;
177 }
178 int ret = StopAbility(want);
179 ClearWant(want);
180 delete want;
181 return ret == ERR_OK;
182 }
183
TerminateApp(IClientProxy * proxy) const184 bool AbilityTool::TerminateApp(IClientProxy *proxy) const
185 {
186 if (proxy == nullptr) {
187 return false;
188 }
189 if (elementName_.bundleName == nullptr || strlen(elementName_.bundleName) == 0) {
190 printf("invalid argument\n");
191 return false;
192 }
193 IpcIo req;
194 char data[MAX_IO_SIZE];
195 IpcIoInit(&req, data, MAX_IO_SIZE, 0);
196 WriteString(&req, elementName_.bundleName);
197 return proxy->Invoke(proxy, TERMINATE_APP, &req, nullptr, nullptr) == EC_SUCCESS;
198 }
199
Dump(IClientProxy * proxy)200 bool AbilityTool::Dump(IClientProxy *proxy)
201 {
202 if (proxy == nullptr) {
203 return false;
204 }
205 Want *want = BuildWant();
206 if (want == nullptr) {
207 return false;
208 }
209
210 IpcIo req;
211 char data[MAX_IO_SIZE];
212 IpcIoInit(&req, data, MAX_IO_SIZE, MAX_OBJECTS);
213 if (!SerializeWant(&req, want)) {
214 printf("SerializeWant failed\n");
215 ClearWant(want);
216 delete want;
217 return false;
218 }
219 ClearWant(want);
220 delete want;
221 if (proxy->Invoke(proxy, DUMP_ABILITY, &req, nullptr, nullptr) != EC_SUCCESS) {
222 printf("dumpAbility failed\n");
223 return false;
224 }
225 if (sem_init(&g_sem, 0, 0)) {
226 printf("sem_init failed\n");
227 return false;
228 }
229 printf("wait for callback\n");
230 struct timespec ts = { 0, 0 };
231 clock_gettime(CLOCK_REALTIME, &ts);
232 ts.tv_sec += WAIT_TIMEOUT;
233 sem_timedwait(&g_sem, &ts);
234 printf("sem exit\n");
235 return true;
236 }
237
AaCallback(uint32_t code,IpcIo * data,IpcIo * reply,MessageOption option)238 int32_t AbilityTool::AaCallback(uint32_t code, IpcIo *data, IpcIo *reply, MessageOption option)
239 {
240 printf("get ability info\n");
241 auto abilityTool = static_cast<AbilityTool *>(option.args);
242 if (abilityTool == nullptr) {
243 printf("ams call back error, abilityTool is null\n");
244 return -1;
245 }
246 switch (code) {
247 case SCHEDULER_APP_INIT: {
248 ElementName element = {};
249 DeserializeElement(&element, data);
250 int32_t ret = 0;
251 ReadInt32(data, &ret);
252 printf("ams call back, start %s.%s ret = %d\n", element.bundleName, element.abilityName, ret);
253 ClearElement(&element);
254 break;
255 }
256 case SCHEDULER_DUMP_ABILITY: {
257 size_t len = 0;
258 char *result = reinterpret_cast<char *>(ReadString(data, &len));
259 printf("dump ability info:\n");
260 if (!abilityTool->dumpAll_) {
261 printf("[%s][%s]\n", abilityTool->elementName_.bundleName, abilityTool->elementName_.abilityName);
262 }
263 printf("{\n");
264 for (int i = 0; i <= (len - 1) / MAX_BUFFER_SIZE_PER; i++) {
265 int start = MAX_BUFFER_SIZE_PER * i;
266 int size = (len - start) < MAX_BUFFER_SIZE_PER ? (len - start) : MAX_BUFFER_SIZE_PER;
267 printf("%-.*s", size, result + start);
268 }
269 printf("}\n");
270 break;
271 }
272 default: {
273 printf("ams call back error, funcId: %u\n", code);
274 break;
275 }
276 }
277 sem_post(&g_sem);
278 return 0;
279 }
280 } // namespace OHOS
281