1 /*
2 * Copyright (c) 2024 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 "appspawn_test_cmder.h"
17
18 #include <cerrno>
19 #include <cstdint>
20 #include <cstdio>
21 #include <cstdlib>
22 #include <fcntl.h>
23 #include <string>
24 #include <termios.h>
25 #include <unistd.h>
26
27 #include <sys/stat.h>
28
29 #include "appspawn.h"
30 #include "appspawn_msg.h"
31 #include "appspawn_utils.h"
32 #include "cJSON.h"
33 #include "command_lexer.h"
34 #include "json_utils.h"
35 #include "securec.h"
36 #include "thread_manager.h"
37
38 #define MAX_THREAD 10
39 #define MAX_SEND 200
40 #define PTY_PATH_SIZE 128
41
42 namespace OHOS {
43 namespace AppSpawnModuleTest {
44 static const std::string g_defaultAppInfo = "{ \
45 \"msg-type\": \"MSG_APP_SPAWN\", \
46 \"msg-flags\": [1, 2 ], \
47 \"process-name\" : \"com.example.myapplication\", \
48 \"dac-info\" : { \
49 \"uid\" : 20010043, \
50 \"gid\" : 20010043,\
51 \"gid-table\" : [],\
52 \"user-name\" : \"\" \
53 },\
54 \"access-token\" : {\
55 \"accessTokenIdEx\" : 537854093\
56 },\
57 \"permission\" : [\
58 \"ohos.permission.READ_IMAGEVIDEO\",\
59 \"ohos.permission.FILE_CROSS_APP\",\
60 \"ohos.permission.ACTIVATE_THEME_PACKAGE\"\
61 ],\
62 \"internet-permission\" : {\
63 \"set-allow-internet\" : 0,\
64 \"allow-internet\" : 0\
65 },\
66 \"bundle-info\" : {\
67 \"bundle-index\" : 0,\
68 \"bundle-name\" : \"com.example.myapplication\" \
69 },\
70 \"owner-id\" : \"\",\
71 \"render-cmd\" : \"1234567890\",\
72 \"domain-info\" : {\
73 \"hap-flags\" : 0,\
74 \"apl\" : \"system_core\"\
75 },\
76 \"ext-info\" : [\
77 {\
78 \"name\" : \"test\",\
79 \"value\" : \"4444444444444444444\" \
80 } \
81 ]\
82 }";
83
84 static const char *APPSPAWN_TEST_USAGE = "usage: AppSpawnTest <options> \n"
85 "options list:\n"
86 " --help list available commands\n"
87 " --file xx file path with app info\n"
88 " --thread xx use multi-thread to send message\n"
89 " --type xx send msg type \n"
90 " --pid xx render terminate pid\n"
91 " --mode nwebspawn send message to nwebspawn service\n";
92
ProcessArgs(int argc,char * const argv[])93 int AppSpawnTestCommander::ProcessArgs(int argc, char *const argv[])
94 {
95 int sendMsg = 0;
96 msgType_ = MAX_TYPE_INVALID;
97 for (int32_t i = 0; i < argc; i++) {
98 if (argv[i] == nullptr) {
99 continue;
100 }
101 if (strcmp(argv[i], "--file") == 0 && ((i + 1) < argc)) { // test file
102 i++;
103 testFileName_ = argv[i];
104 sendMsg = 1;
105 } else if (strcmp(argv[i], "--thread") == 0 && ((i + 1) < argc)) { // use thread
106 i++;
107 threadCount_ = atoi(argv[i]);
108 if (threadCount_ > MAX_THREAD) {
109 threadCount_ = MAX_THREAD;
110 }
111 sendMsg = 1;
112 } else if (strcmp(argv[i], "--mode") == 0 && ((i + 1) < argc)) {
113 i++;
114 appSpawn_ = strcmp(argv[i], "nwebspawn") == 0 ? 0 : 1;
115 sendMsg = 1;
116 } else if (strcmp(argv[i], "--type") == 0 && ((i + 1) < argc)) {
117 i++;
118 msgType_ = atoi(argv[i]);
119 sendMsg = 1;
120 } else if (strcmp(argv[i], "--pid") == 0 && ((i + 1) < argc)) {
121 i++;
122 msgType_ = MSG_GET_RENDER_TERMINATION_STATUS;
123 terminatePid_ = atoi(argv[i]);
124 sendMsg = 1;
125 } else if (strcmp(argv[i], "--help") == 0) {
126 printf("%s\n", APPSPAWN_TEST_USAGE);
127 return 1;
128 } else if (strcmp(argv[i], "--send") == 0 || strcmp(argv[i], "send") == 0) {
129 sendMsg = 1;
130 }
131 }
132 if (sendMsg == 0) {
133 printf("%s\n", APPSPAWN_TEST_USAGE);
134 return 1;
135 }
136 return 0;
137 }
138
GetUint32ArrayFromJson(const cJSON * json,const char * name,uint32_t dataArray[],uint32_t maxCount)139 uint32_t AppSpawnTestCommander::GetUint32ArrayFromJson(const cJSON *json,
140 const char *name, uint32_t dataArray[], uint32_t maxCount)
141 {
142 APPSPAWN_CHECK(json != NULL, return 0, "Invalid json");
143 APPSPAWN_CHECK(name != NULL, return 0, "Invalid name");
144 APPSPAWN_CHECK(dataArray != NULL, return 0, "Invalid dataArray");
145 APPSPAWN_CHECK(cJSON_IsObject(json), return 0, "json is not object.");
146 cJSON *array = cJSON_GetObjectItemCaseSensitive(json, name);
147 APPSPAWN_CHECK_ONLY_EXPER(array != NULL, return 0);
148 APPSPAWN_CHECK(cJSON_IsArray(array), return 0, "json is not object.");
149
150 uint32_t count = 0;
151 uint32_t arrayLen = cJSON_GetArraySize(array);
152 for (int i = 0; i < arrayLen; i++) {
153 cJSON *item = cJSON_GetArrayItem(array, i);
154 uint32_t value = (uint32_t)cJSON_GetNumberValue(item);
155 if (count < maxCount) {
156 dataArray[count++] = value;
157 }
158 }
159 return count;
160 }
161
AddBundleInfoFromJson(const cJSON * appInfoConfig,AppSpawnReqMsgHandle reqHandle)162 int AppSpawnTestCommander::AddBundleInfoFromJson(const cJSON *appInfoConfig, AppSpawnReqMsgHandle reqHandle)
163 {
164 cJSON *config = cJSON_GetObjectItemCaseSensitive(appInfoConfig, "bundle-info");
165 APPSPAWN_CHECK_ONLY_EXPER(config, return 0);
166
167 uint32_t bundleIndex = GetIntValueFromJsonObj(config, "bundle-index", 0);
168 char *bundleName = GetStringFromJsonObj(config, "bundle-name");
169 int ret = AppSpawnReqMsgSetBundleInfo(reqHandle, bundleIndex, bundleName);
170 APPSPAWN_CHECK(ret == 0, return ret, "Failed to add bundle info req %{public}s", bundleName);
171 return 0;
172 }
173
AddDacInfoFromJson(const cJSON * appInfoConfig,AppSpawnReqMsgHandle reqHandle)174 int AppSpawnTestCommander::AddDacInfoFromJson(const cJSON *appInfoConfig, AppSpawnReqMsgHandle reqHandle)
175 {
176 cJSON *config = cJSON_GetObjectItemCaseSensitive(appInfoConfig, "dac-info");
177 APPSPAWN_CHECK_ONLY_EXPER(config, return 0);
178
179 AppDacInfo info = {};
180 info.uid = GetIntValueFromJsonObj(config, "uid", 0);
181 info.gid = GetIntValueFromJsonObj(config, "gid", 0);
182 info.gidCount = GetUint32ArrayFromJson(config, "gid-table", info.gidTable, APP_MAX_GIDS);
183 char *userName = GetStringFromJsonObj(config, "user-name");
184 if (userName != nullptr) {
185 int ret = strcpy_s(info.userName, sizeof(info.userName), userName);
186 APPSPAWN_CHECK(ret == 0, return ret, "Failed to add userName info req %{public}s", userName);
187 }
188 return AppSpawnReqMsgSetAppDacInfo(reqHandle, &info);
189 }
190
AddInternetPermissionInfoFromJson(const cJSON * appInfoConfig,AppSpawnReqMsgHandle reqHandle)191 int AppSpawnTestCommander::AddInternetPermissionInfoFromJson(
192 const cJSON *appInfoConfig, AppSpawnReqMsgHandle reqHandle)
193 {
194 cJSON *config = cJSON_GetObjectItemCaseSensitive(appInfoConfig, "internet-permission");
195 APPSPAWN_CHECK_ONLY_EXPER(config, return 0);
196
197 uint8_t setAllowInternet = GetIntValueFromJsonObj(config, "set-allow-internet", 0);
198 uint8_t allowInternet = GetIntValueFromJsonObj(config, "allow-internet", 0);
199 return AppSpawnReqMsgSetAppInternetPermissionInfo(reqHandle, allowInternet, setAllowInternet);
200 }
201
AddAccessTokenFromJson(const cJSON * appInfoConfig,AppSpawnReqMsgHandle reqHandle)202 int AppSpawnTestCommander::AddAccessTokenFromJson(const cJSON *appInfoConfig, AppSpawnReqMsgHandle reqHandle)
203 {
204 cJSON *config = cJSON_GetObjectItemCaseSensitive(appInfoConfig, "access-token");
205 APPSPAWN_CHECK_ONLY_EXPER(config, return 0);
206
207 uint64_t accessTokenIdEx = GetIntValueFromJsonObj(config, "accessTokenIdEx", 0);
208 return AppSpawnReqMsgSetAppAccessToken(reqHandle, accessTokenIdEx);
209 }
210
AddDomainInfoFromJson(const cJSON * appInfoConfig,AppSpawnReqMsgHandle reqHandle)211 int AppSpawnTestCommander::AddDomainInfoFromJson(const cJSON *appInfoConfig, AppSpawnReqMsgHandle reqHandle)
212 {
213 cJSON *config = cJSON_GetObjectItemCaseSensitive(appInfoConfig, "domain-info");
214 APPSPAWN_CHECK_ONLY_EXPER(config, return 0);
215
216 uint32_t hapFlags = GetIntValueFromJsonObj(config, "hap-flags", 0);
217 char *apl = GetStringFromJsonObj(config, "apl");
218 int ret = AppSpawnReqMsgSetAppDomainInfo(reqHandle, hapFlags, apl);
219 APPSPAWN_CHECK(ret == 0, return ret, "Failed to domain info");
220 return 0;
221 }
222
AddExtTlv(const cJSON * appInfoConfig,AppSpawnReqMsgHandle reqHandle)223 int AppSpawnTestCommander::AddExtTlv(const cJSON *appInfoConfig, AppSpawnReqMsgHandle reqHandle)
224 {
225 cJSON *configs = cJSON_GetObjectItemCaseSensitive(appInfoConfig, "ext-info");
226 APPSPAWN_CHECK_ONLY_EXPER(configs != nullptr, return 0);
227
228 int ret = 0;
229 uint32_t count = cJSON_GetArraySize(configs);
230 for (unsigned int j = 0; j < count; j++) {
231 cJSON *config = cJSON_GetArrayItem(configs, j);
232
233 char *name = GetStringFromJsonObj(config, "name");
234 char *value = GetStringFromJsonObj(config, "value");
235 APPSPAWN_LOGV("ext-info %{public}s %{public}s", name, value);
236 ret = AppSpawnReqMsgAddStringInfo(reqHandle, name, value);
237 APPSPAWN_CHECK(ret == 0, return ret, "Failed to add ext name %{public}s", name);
238 }
239
240 // 添加一个二进制的扩展元素
241 AppDacInfo dacInfo{};
242 dacInfo.uid = 101; // 101 test data
243 dacInfo.gid = 101; // 101 test data
244 dacInfo.gidTable[0] = 101; // 101 test data
245 dacInfo.gidCount = 1;
246 (void)strcpy_s(dacInfo.userName, sizeof(dacInfo.userName), processName_.c_str());
247 ret = AppSpawnReqMsgAddExtInfo(reqHandle,
248 "app-dac-info", reinterpret_cast<uint8_t *>(&dacInfo), sizeof(dacInfo));
249 APPSPAWN_CHECK(ret == 0, return ret, "Failed to add ext name app-info");
250 return ret;
251 }
252
BuildMsgFromJson(const cJSON * appInfoConfig,AppSpawnReqMsgHandle reqHandle)253 int AppSpawnTestCommander::BuildMsgFromJson(const cJSON *appInfoConfig, AppSpawnReqMsgHandle reqHandle)
254 {
255 int ret = AddBundleInfoFromJson(appInfoConfig, reqHandle);
256 APPSPAWN_CHECK(ret == 0, return ret, "Failed to add dac %{public}s", processName_.c_str());
257
258 ret = AddDomainInfoFromJson(appInfoConfig, reqHandle);
259 APPSPAWN_CHECK(ret == 0, return ret, "Failed to add dac %{public}s", processName_.c_str());
260
261 ret = AddDacInfoFromJson(appInfoConfig, reqHandle);
262 APPSPAWN_CHECK(ret == 0, return ret, "Failed to add dac %{public}s", processName_.c_str());
263
264 ret = AddAccessTokenFromJson(appInfoConfig, reqHandle);
265 APPSPAWN_CHECK(ret == 0, return ret, "Failed to add access token %{public}s", processName_.c_str());
266
267 cJSON *obj = cJSON_GetObjectItemCaseSensitive(appInfoConfig, "permission");
268 if (obj != nullptr && cJSON_IsArray(obj)) {
269 int count = cJSON_GetArraySize(obj);
270 for (int i = 0; i < count; i++) {
271 char *value = cJSON_GetStringValue(cJSON_GetArrayItem(obj, i));
272 APPSPAWN_LOGV("permission %{public}s ", value);
273 ret = AppSpawnReqMsgAddPermission(reqHandle, value);
274 APPSPAWN_CHECK(ret == 0, return ret, "Failed to permission %{public}s", value);
275 }
276 }
277
278 ret = AddInternetPermissionInfoFromJson(appInfoConfig, reqHandle);
279 APPSPAWN_CHECK(ret == 0, return ret, "Failed to internet info %{public}s", processName_.c_str());
280
281 std::string ownerId = GetStringFromJsonObj(appInfoConfig, "owner-id");
282 if (!ownerId.empty()) {
283 ret = AppSpawnReqMsgSetAppOwnerId(reqHandle, ownerId.c_str());
284 APPSPAWN_CHECK(ret == 0, return ret, "Failed to ownerid %{public}s", processName_.c_str());
285 }
286
287 std::string renderCmd = GetStringFromJsonObj(appInfoConfig, "render-cmd");
288 if (!renderCmd.empty()) {
289 ret = AppSpawnReqMsgAddStringInfo(reqHandle, MSG_EXT_NAME_RENDER_CMD, renderCmd.c_str());
290 APPSPAWN_CHECK(ret == 0, return -1, "Failed to add renderCmd %{public}s", renderCmd.c_str());
291 }
292 return AddExtTlv(appInfoConfig, reqHandle);
293 }
294
CreateOtherMsg(AppSpawnReqMsgHandle & reqHandle,pid_t pid)295 int AppSpawnTestCommander::CreateOtherMsg(AppSpawnReqMsgHandle &reqHandle, pid_t pid)
296 {
297 if (msgType_ == MSG_GET_RENDER_TERMINATION_STATUS) {
298 int ret = AppSpawnTerminateMsgCreate(pid, &reqHandle);
299 APPSPAWN_CHECK(ret == 0, return ret, "Failed to termination message req %{public}s", processName_.c_str());
300 }
301 if (msgType_ == MSG_DUMP) {
302 int ret = AppSpawnReqMsgCreate(static_cast<AppSpawnMsgType>(msgType_), processName_.c_str(), &reqHandle);
303 APPSPAWN_CHECK(ret == 0, return ret, "Failed to dump req %{public}s", processName_.c_str());
304 ret = AppSpawnReqMsgAddStringInfo(reqHandle, "pty-name", ptyName_.c_str());
305 APPSPAWN_CHECK(ret == 0, return -1, "Failed to add ptyName_ %{public}s", ptyName_.c_str());
306 }
307 return 0;
308 }
309
GetMsgTypeFromJson(const cJSON * json)310 static uint32_t GetMsgTypeFromJson(const cJSON *json)
311 {
312 const char *msgType = GetStringFromJsonObj(json, "msg-type");
313 if (msgType == nullptr) {
314 return MSG_APP_SPAWN;
315 }
316 if (strcmp(msgType, "MSG_SPAWN_NATIVE_PROCESS") == 0) {
317 return MSG_SPAWN_NATIVE_PROCESS;
318 }
319 if (strcmp(msgType, "MSG_GET_RENDER_TERMINATION_STATUS") == 0) {
320 return MSG_GET_RENDER_TERMINATION_STATUS;
321 }
322 if (strcmp(msgType, "MSG_DUMP") == 0) {
323 return MSG_DUMP;
324 }
325 return MSG_APP_SPAWN;
326 }
327
CreateMsg(AppSpawnReqMsgHandle & reqHandle,const char * defaultConfig,uint32_t defMsgType)328 int AppSpawnTestCommander::CreateMsg(AppSpawnReqMsgHandle &reqHandle,
329 const char *defaultConfig, uint32_t defMsgType)
330 {
331 int ret = APPSPAWN_SYSTEM_ERROR;
332 if (clientHandle_ == NULL) {
333 ret = AppSpawnClientInit(appSpawn_ ? APPSPAWN_SERVER_NAME : NWEBSPAWN_SERVER_NAME, &clientHandle_);
334 APPSPAWN_CHECK(ret == 0, return -1, "Failed to create client %{public}d", appSpawn_);
335 }
336 reqHandle = INVALID_REQ_HANDLE;
337 if (appInfoConfig_) {
338 cJSON_Delete(appInfoConfig_);
339 appInfoConfig_ = nullptr;
340 }
341 if (!testFileName_.empty()) {
342 appInfoConfig_ = GetJsonObjFromFile(testFileName_.c_str());
343 if (appInfoConfig_ == nullptr) {
344 printf("Failed to load file %s, so use default info \n", testFileName_.c_str());
345 }
346 }
347 if (appInfoConfig_ == nullptr) {
348 appInfoConfig_ = cJSON_Parse(defaultConfig);
349 }
350 if (appInfoConfig_ == nullptr) {
351 printf("Invalid app info \n");
352 return APPSPAWN_SYSTEM_ERROR;
353 }
354 processName_ = GetStringFromJsonObj(appInfoConfig_, "process-name");
355 if (processName_.empty()) {
356 processName_ = "com.example.myapplication";
357 }
358 msgType_ = (msgType_ == MAX_TYPE_INVALID) ? GetMsgTypeFromJson(appInfoConfig_) : msgType_;
359 msgType_ = (defMsgType != MAX_TYPE_INVALID) ? defMsgType : msgType_;
360 if (msgType_ == MSG_DUMP) {
361 return CreateOtherMsg(reqHandle, 0);
362 } else if (msgType_ == MSG_GET_RENDER_TERMINATION_STATUS) {
363 pid_t pid = GetIntValueFromJsonObj(appInfoConfig_, "pid", 0);
364 return CreateOtherMsg(reqHandle, pid);
365 }
366 ret = AppSpawnReqMsgCreate(static_cast<AppSpawnMsgType>(msgType_), processName_.c_str(), &reqHandle);
367 APPSPAWN_CHECK(ret == 0, return ret, "Failed to create req %{public}s", processName_.c_str());
368
369 uint32_t msgFlags[64] = {}; // 64
370 uint32_t count = GetUint32ArrayFromJson(appInfoConfig_, "msg-flags", msgFlags, ARRAY_LENGTH(msgFlags));
371 for (uint32_t j = 0; j < count; j++) {
372 (void)AppSpawnReqMsgSetAppFlag(reqHandle, static_cast<AppFlagsIndex>(msgFlags[j]));
373 }
374 (void)AppSpawnReqMsgSetAppFlag(reqHandle, APP_FLAGS_IGNORE_SANDBOX);
375 ret = BuildMsgFromJson(appInfoConfig_, reqHandle);
376 APPSPAWN_CHECK(ret == 0, AppSpawnReqMsgFree(reqHandle);
377 return ret, "Failed to build req %{public}s", processName_.c_str());
378 return ret;
379 }
380
SendMsg()381 int AppSpawnTestCommander::SendMsg()
382 {
383 const char *server = appSpawn_ ? APPSPAWN_SERVER_NAME : NWEBSPAWN_SERVER_NAME;
384 printf("Send msg to server '%s' \n", server);
385 AppSpawnReqMsgHandle reqHandle = INVALID_REQ_HANDLE;
386 int ret = 0;
387 if (msgType_ == MSG_DUMP) {
388 while (!dumpFlags) {
389 usleep(20000); // 20000
390 }
391 ret = CreateOtherMsg(reqHandle, 0);
392 } else if (msgType_ == MSG_GET_RENDER_TERMINATION_STATUS) {
393 ret = CreateOtherMsg(reqHandle, terminatePid_);
394 } else {
395 ret = CreateMsg(reqHandle, g_defaultAppInfo.c_str());
396 }
397 AppSpawnResult result = {ret, 0};
398 if (ret == 0) {
399 ret = AppSpawnClientSendMsg(clientHandle_, reqHandle, &result);
400 }
401 switch (msgType_) {
402 case MSG_APP_SPAWN:
403 if (result.result == 0) {
404 printf("Spawn app %s success, pid %d \n", processName_.c_str(), result.pid);
405 } else {
406 printf("Spawn app %s fail, result 0x%x \n", processName_.c_str(), result.result);
407 }
408 break;
409 case MSG_SPAWN_NATIVE_PROCESS:
410 if (result.result == 0) {
411 printf("Spawn native app %s success, pid %d \n", processName_.c_str(), result.pid);
412 } else {
413 printf("Spawn native app %s fail, result 0x%x \n", processName_.c_str(), result.result);
414 }
415 break;
416 case MSG_GET_RENDER_TERMINATION_STATUS:
417 printf("Terminate app %s success, pid %d status 0x%x \n",
418 processName_.c_str(), result.pid, result.result);
419 break;
420 default:
421 printf("Dump server %s result %d \n", server, ret);
422 break;
423 }
424 msgType_ = MAX_TYPE_INVALID;
425 terminatePid_ = 0;
426 printf("Please input cmd: \n");
427 return 0;
428 }
429
StartSendMsg()430 int AppSpawnTestCommander::StartSendMsg()
431 {
432 int ret = 0;
433 printf("Start send msg thread count %d file name %s \n", threadCount_, testFileName_.c_str());
434 if (threadCount_ == 1) {
435 SendMsg();
436 } else {
437 ThreadTaskHandle taskHandle = 0;
438 ret = ThreadMgrAddTask(threadMgr_, &taskHandle);
439 APPSPAWN_CHECK(ret == 0, return 0, "Failed to add task ");
440 for (uint32_t index = 0; index < threadCount_; index++) {
441 ThreadMgrAddExecutor(threadMgr_, taskHandle, TaskExecutorProc, reinterpret_cast<ThreadContext *>(this));
442 }
443 TaskSyncExecute(threadMgr_, taskHandle);
444 }
445 return 0;
446 }
447
TaskExecutorProc(ThreadTaskHandle handle,const ThreadContext * context)448 void AppSpawnTestCommander::TaskExecutorProc(ThreadTaskHandle handle, const ThreadContext *context)
449 {
450 AppSpawnTestCommander *testCmder = AppSpawnTestCommander::ConvertTo(context);
451 testCmder->SendMsg();
452 }
453
SendTaskFinish(ThreadTaskHandle handle,const ThreadContext * context)454 void AppSpawnTestCommander::SendTaskFinish(ThreadTaskHandle handle, const ThreadContext *context)
455 {
456 APPSPAWN_LOGV("SendTaskFinish %{public}u \n", handle);
457 }
458
459 static std::vector<std::string> g_args;
HandleSplitString(const char * str,void * context)460 static int HandleSplitString(const char *str, void *context)
461 {
462 APPSPAWN_LOGV("HandleSplitString %{public}s ", str);
463 std::string value = str;
464 g_args.push_back(value);
465 return 0;
466 }
467
ProcessInputCmd(std::string & cmd)468 int AppSpawnTestCommander::ProcessInputCmd(std::string &cmd)
469 {
470 g_args.clear();
471 int ret = StringSplit(cmd.c_str(), " ", nullptr, HandleSplitString);
472 std::vector<char *> options;
473 for (const auto &arg : g_args) {
474 if (!arg.empty()) {
475 options.push_back(const_cast<char *>(arg.c_str()));
476 }
477 }
478 (void)ProcessArgs(options.size(), options.data());
479 StartSendMsg();
480 return ret;
481 }
482
InputThread(ThreadTaskHandle handle,const ThreadContext * context)483 void AppSpawnTestCommander::InputThread(ThreadTaskHandle handle, const ThreadContext *context)
484 {
485 AppSpawnTestCommander *testCmder = AppSpawnTestCommander::ConvertTo(context);
486 char buffer[1024] = {0}; // 1024 test buffer max len
487 fd_set fds;
488 printf("Please input cmd: \n");
489 while (1) {
490 FD_ZERO(&fds);
491 FD_SET(STDIN_FILENO, &fds);
492 int ret = select(STDIN_FILENO + 1, &fds, nullptr, nullptr, nullptr);
493 if (ret <= 0) {
494 if (testCmder->exit_) {
495 break;
496 }
497 continue;
498 }
499 ssize_t rlen = read(STDIN_FILENO, buffer, sizeof(buffer) - 1);
500 if (rlen <= 1) {
501 continue;
502 }
503 buffer[rlen - 1] = 0;
504 printf("Recv command: '%s' \n", buffer);
505 if (strncmp("quit", buffer, strlen("quit")) == 0) {
506 testCmder->exit_ = 1;
507 break;
508 }
509 if (strncmp("send", buffer, 4) == 0) { // 4 strlen("send")
510 std::string cmd(buffer);
511 testCmder->ProcessInputCmd(cmd);
512 printf("Please input cmd: \n");
513 }
514 }
515 }
516
DumpThread(ThreadTaskHandle handle,const ThreadContext * context)517 void AppSpawnTestCommander::DumpThread(ThreadTaskHandle handle, const ThreadContext *context)
518 {
519 AppSpawnTestCommander *testCmder = AppSpawnTestCommander::ConvertTo(context);
520 printf("Start dump thread \n");
521 char buffer[10240] = {0}; // 1024 test buffer max len
522 fd_set fds;
523 while (1) {
524 testCmder->dumpFlags = 1;
525 FD_ZERO(&fds);
526 FD_SET(testCmder->ptyFd_, &fds);
527 int ret = select(testCmder->ptyFd_ + 1, &fds, nullptr, nullptr, nullptr);
528 if (ret <= 0) {
529 if (testCmder->exit_) {
530 break;
531 }
532 continue;
533 }
534 if (!FD_ISSET(testCmder->ptyFd_, &fds)) {
535 continue;
536 }
537 ssize_t rlen = read(testCmder->ptyFd_, buffer, sizeof(buffer) - 1);
538 while (rlen > 0) {
539 buffer[rlen] = '\0';
540 printf("%s", buffer);
541 fflush(stdout);
542 rlen = read(testCmder->ptyFd_, buffer, sizeof(buffer) - 1);
543 }
544 }
545 }
546
Run()547 int AppSpawnTestCommander::Run()
548 {
549 int ret = 0;
550 const char *name = appSpawn_ ? APPSPAWN_SERVER_NAME : NWEBSPAWN_SERVER_NAME;
551 if (clientHandle_ == NULL) {
552 ret = AppSpawnClientInit(name, &clientHandle_);
553 APPSPAWN_CHECK(ret == 0, return -1, "Failed to create client %{public}s", name);
554 }
555
556 InitPtyInterface();
557
558 ret = CreateThreadMgr(5, &threadMgr_); // 5 max thread
559 APPSPAWN_CHECK(ret == 0, return -1, "Failed to create thread manager");
560
561 ret = ThreadMgrAddTask(threadMgr_, &inputHandle_);
562 APPSPAWN_CHECK(ret == 0, return 0, "Failed to add task for thread ");
563 ThreadMgrAddExecutor(threadMgr_, inputHandle_, InputThread, this);
564 TaskExecute(threadMgr_, inputHandle_, SendTaskFinish, this);
565
566 ret = ThreadMgrAddTask(threadMgr_, &dumpHandle_);
567 APPSPAWN_CHECK(ret == 0, return 0, "Failed to add task for thread ");
568 ThreadMgrAddExecutor(threadMgr_, dumpHandle_, DumpThread, this);
569 TaskExecute(threadMgr_, dumpHandle_, SendTaskFinish, this);
570
571 StartSendMsg();
572
573 APPSPAWN_LOGV("Finish send msg \n");
574 while (!exit_) {
575 usleep(200000); // 200000 200ms
576 }
577 ThreadMgrCancelTask(threadMgr_, inputHandle_);
578 ThreadMgrCancelTask(threadMgr_, dumpHandle_);
579 DestroyThreadMgr(threadMgr_);
580 threadMgr_ = nullptr;
581 inputHandle_ = 0;
582 dumpHandle_ = 0;
583 AppSpawnClientDestroy(clientHandle_);
584 clientHandle_ = nullptr;
585 return 0;
586 }
587
InitPtyInterface()588 int AppSpawnTestCommander::InitPtyInterface()
589 {
590 // open master pty and get slave pty
591 int pfd = open("/dev/ptmx", O_RDWR | O_CLOEXEC | O_NOCTTY | O_NONBLOCK);
592 APPSPAWN_CHECK(pfd >= 0, return -1, "Failed open pty err=%d", errno);
593 APPSPAWN_CHECK(grantpt(pfd) >= 0, close(pfd); return -1, "Failed to call grantpt");
594 APPSPAWN_CHECK(unlockpt(pfd) >= 0, close(pfd); return -1, "Failed to call unlockpt");
595 char ptsbuffer[PTY_PATH_SIZE] = {0};
596 int ret = ptsname_r(pfd, ptsbuffer, sizeof(ptsbuffer));
597 APPSPAWN_CHECK(ret >= 0, close(pfd);
598 return -1, "Failed to get pts name err=%d", errno);
599 APPSPAWN_LOGI("ptsbuffer is %s", ptsbuffer);
600 APPSPAWN_CHECK(chmod(ptsbuffer, S_IRWXU | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH) == 0, close(pfd);
601 return -1, "Failed to chmod %s, err=%d", ptsbuffer, errno);
602 ptyFd_ = pfd;
603 ptyName_ = std::string(ptsbuffer);
604 return 0;
605 }
606 } // namespace AppSpawnModuleTest
607 } // namespace OHOS
608