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