• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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