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