From 921027735a9e0615046e81a3d3360e6a441e6034 Mon Sep 17 00:00:00 2001 From: nianyuu Date: Mon, 21 Apr 2025 16:42:12 +0800 Subject: [PATCH] nativespawn supports sending child process exit sig to ams Signed-off-by: nianyuu --- interfaces/innerkits/client/appspawn_client.c | 94 ++++++++++++---- .../client/libappspawn_client.versionscript | 2 + interfaces/innerkits/include/appspawn.h | 19 +++- standard/appspawn_service.c | 2 +- .../app_spawn_interface_test.cpp | 29 +++++ .../app_spawn_service_test.cpp | 100 ++++++++++++++++++ 6 files changed, 221 insertions(+), 25 deletions(-) diff --git a/interfaces/innerkits/client/appspawn_client.c b/interfaces/innerkits/client/appspawn_client.c index 563b0569..da504d36 100644 --- a/interfaces/innerkits/client/appspawn_client.c +++ b/interfaces/innerkits/client/appspawn_client.c @@ -41,6 +41,9 @@ static AppSpawnReqMsgMgr *g_clientInstance[CLIENT_MAX] = {NULL}; static pthread_mutex_t g_spawnListenMutex = PTHREAD_MUTEX_INITIALIZER; static int g_spawnListenFd = 0; static bool g_spawnListenStart = false; +static pthread_mutex_t g_nativeSpawnListenMutex = PTHREAD_MUTEX_INITIALIZER; +static int g_nativeSpawnListenFd = 0; +static bool g_nativeSpawnListenStart = false; APPSPAWN_STATIC void SpawnListen(AppSpawnReqMsgMgr *reqMgr, const char *processName); @@ -271,6 +274,21 @@ APPSPAWN_STATIC void TryCreateSocket(AppSpawnReqMsgMgr *reqMgr) } } +static void SendSpawnListenMsg(AppSpawnReqMsgMgr *reqMgr, AppSpawnReqMsgNode *reqNode) +{ + if (reqMgr->type == CLIENT_FOR_APPSPAWN && reqNode->msg->msgType != MSG_OBSERVE_PROCESS_SIGNAL_STATUS) { + pthread_mutex_lock(&g_spawnListenMutex); + SpawnListen(reqMgr, reqNode->msg->processName); + pthread_mutex_unlock(&g_spawnListenMutex); + } + + if (reqMgr->type == CLIENT_FOR_NATIVESPAWN && reqNode->msg->msgType != MSG_OBSERVE_PROCESS_SIGNAL_STATUS) { + pthread_mutex_lock(&g_nativeSpawnListenMutex); + SpawnListen(reqMgr, reqNode->msg->processName); + pthread_mutex_unlock(&g_nativeSpawnListenMutex); + } +} + static int ClientSendMsg(AppSpawnReqMsgMgr *reqMgr, AppSpawnReqMsgNode *reqNode, AppSpawnResult *result) { uint32_t retryCount = 1; @@ -284,11 +302,8 @@ static int ClientSendMsg(AppSpawnReqMsgMgr *reqMgr, AppSpawnReqMsgNode *reqNode, continue; } } - if (reqNode->msg->msgType != MSG_OBSERVE_PROCESS_SIGNAL_STATUS) { - pthread_mutex_lock(&g_spawnListenMutex); - SpawnListen(reqMgr, reqNode->msg->processName); - pthread_mutex_unlock(&g_spawnListenMutex); - } + SendSpawnListenMsg(reqMgr, reqNode); + if (isColdRun && reqMgr->timeout < ASAN_TIMEOUT) { UpdateSocketTimeout(ASAN_TIMEOUT, reqMgr->socketId); } @@ -317,33 +332,48 @@ static int ClientSendMsg(AppSpawnReqMsgMgr *reqMgr, AppSpawnReqMsgNode *reqNode, return APPSPAWN_TIMEOUT; } -APPSPAWN_STATIC void SpawnListen(AppSpawnReqMsgMgr *reqMgr, const char *processName) +APPSPAWN_STATIC int SpawnListenBase(AppSpawnReqMsgMgr *reqMgr, const char *processName, int fd, bool startFlag) { - AppSpawnClientType type = reqMgr->type; - if (g_spawnListenFd <= 0 || g_spawnListenStart) { - APPSPAWN_LOGV("Spawn Listen fail,fd:%{public}d,start:%{public}d", g_spawnListenFd, g_spawnListenStart); - return; + if (fd <= 0 || startFlag) { + APPSPAWN_LOGV("Spawn Listen fail, fd:%{public}d, startFlag:%{public}d", fd, startFlag); + return -1; } - APPSPAWN_CHECK((type == CLIENT_FOR_APPSPAWN), return, "Invalid type"); - APPSPAWN_CHECK(processName != NULL, return, "Invalid process name"); - - APPSPAWN_LOGI("Spawn Listen start type:%{public}d,fd:%{public}d", type, g_spawnListenFd); + AppSpawnClientType type = reqMgr->type; + APPSPAWN_LOGI("Spawn Listen start type:%{public}d, fd:%{public}d", type, fd); AppSpawnReqMsgHandle reqHandle; int ret = AppSpawnReqMsgCreate(MSG_OBSERVE_PROCESS_SIGNAL_STATUS, processName, &reqHandle); - APPSPAWN_CHECK(ret == 0, return, "Failed to create type:%{public}d req msg, ret = %{public}d", type, ret); + APPSPAWN_CHECK(ret == 0, return ret, "Failed to create type:%{public}d req msg, ret %{public}d", type, ret); - ret = AppSpawnReqMsgAddFd(reqHandle, SPAWN_LISTEN_FD_NAME, g_spawnListenFd); + ret = AppSpawnReqMsgAddFd(reqHandle, SPAWN_LISTEN_FD_NAME, fd); APPSPAWN_CHECK(ret == 0, AppSpawnReqMsgFree(reqHandle); - return, "Failed to add info message, ret=%{public}d", ret); + return ret, "Failed to add fd info to msg, ret %{public}d", ret); AppSpawnResult result = {0}; ret = ClientSendMsg(reqMgr, (AppSpawnReqMsgNode *)reqHandle, &result); - APPSPAWN_CHECK(ret == 0, return, "Send msg to type:%{public}d failed, ret=%{public}d", type, ret); - APPSPAWN_CHECK(result.result == 0, return, "Appspawn failed to handle message, result=%{public}d", result.result); + APPSPAWN_CHECK(ret == 0, return ret, "Send msg to type:%{public}d fail, ret %{public}d", type, ret); + APPSPAWN_CHECK(result.result == 0, return result.result, + "Spawn failed to handle listen msg, result %{public}d", result.result); + + APPSPAWN_LOGI("Spawn Listen client type:%{public}d send fd:%{public}d success", type, fd); + return 0; +} + +APPSPAWN_STATIC void SpawnListen(AppSpawnReqMsgMgr *reqMgr, const char *processName) +{ + APPSPAWN_CHECK(reqMgr != NULL, return, "Invalid reqMgr"); + APPSPAWN_CHECK(processName != NULL, return, "Invalid process name"); + + int ret = 0; + if (reqMgr->type == CLIENT_FOR_APPSPAWN) { + ret = SpawnListenBase(reqMgr, processName, g_spawnListenFd, g_spawnListenStart); + APPSPAWN_ONLY_EXPER(ret == 0, g_spawnListenStart = true); + } - g_spawnListenStart = true; - APPSPAWN_LOGI("Spawn Listen client type[%{public}d] Send fd[%{public}d] success", type, g_spawnListenFd); + if (reqMgr->type == CLIENT_FOR_NATIVESPAWN) { + ret = SpawnListenBase(reqMgr, processName, g_nativeSpawnListenFd, g_nativeSpawnListenStart); + APPSPAWN_ONLY_EXPER(ret == 0, g_nativeSpawnListenStart = true); + } } int AppSpawnClientInit(const char *serviceName, AppSpawnClientHandle *handle) @@ -455,6 +485,17 @@ int SpawnListenFdSet(int fd) return 0; } +int NativeSpawnListenFdSet(int fd) +{ + if (fd <= 0) { + APPSPAWN_LOGE("NativeSpawn Listen fd set[%{public}d] failed", fd); + return APPSPAWN_ARG_INVALID; + } + g_nativeSpawnListenFd = fd; + APPSPAWN_LOGI("NativeSpawn Listen fd set[%{public}d] success", fd); + return 0; +} + int SpawnListenCloseSet(void) { pthread_mutex_lock(&g_spawnListenMutex); @@ -462,4 +503,13 @@ int SpawnListenCloseSet(void) pthread_mutex_unlock(&g_spawnListenMutex); APPSPAWN_LOGI("Spawn Listen close set success"); return 0; -} \ No newline at end of file +} + +int NativeSpawnListenCloseSet(void) +{ + pthread_mutex_lock(&g_nativeSpawnListenMutex); + g_nativeSpawnListenStart = false; + pthread_mutex_unlock(&g_nativeSpawnListenMutex); + APPSPAWN_LOGI("NativeSpawn Listen close set success"); + return 0; +} diff --git a/interfaces/innerkits/client/libappspawn_client.versionscript b/interfaces/innerkits/client/libappspawn_client.versionscript index dce211fc..9e5ec6e7 100644 --- a/interfaces/innerkits/client/libappspawn_client.versionscript +++ b/interfaces/innerkits/client/libappspawn_client.versionscript @@ -37,6 +37,8 @@ GetPermissionIndex; GetMaxPermissionIndex; GetPermissionByIndex; + NativeSpawnListenFdSet; + NativeSpawnListenCloseSet; SpawnListenFdSet; SpawnListenCloseSet; local: diff --git a/interfaces/innerkits/include/appspawn.h b/interfaces/innerkits/include/appspawn.h index f04bcf1a..3bf66bfa 100644 --- a/interfaces/innerkits/include/appspawn.h +++ b/interfaces/innerkits/include/appspawn.h @@ -346,7 +346,7 @@ int32_t GetMaxPermissionIndex(AppSpawnClientHandle handle); const char *GetPermissionByIndex(AppSpawnClientHandle handle, int32_t index); /** - * @brief set up a pipe fd to capture the exit reason of a child process + * @brief set up a pipe fd to capture the exit reason of appspawn's child process * * @param fd fd for write signal info * @return if succeed return 0,else return other value @@ -354,12 +354,27 @@ const char *GetPermissionByIndex(AppSpawnClientHandle handle, int32_t index); int SpawnListenFdSet(int fd); /** - * @brief close the listener for child process exit + * @brief close the listener for appspawn's child process exits * * @return if succeed return 0,else return other value */ int SpawnListenCloseSet(void); +/** + * @brief set up a pipe fd to capture the exit reason of nativespawn's child process + * + * @param fd fd for write signal info + * @return if succeed return 0,else return other value + */ +int NativeSpawnListenFdSet(int fd); + +/** + * @brief close the listener for nativespawn's child process exits + * + * @return if succeed return 0,else return other value + */ +int NativeSpawnListenCloseSet(void); + #ifdef __cplusplus } #endif diff --git a/standard/appspawn_service.c b/standard/appspawn_service.c index 24aa179f..e08dc1a5 100644 --- a/standard/appspawn_service.c +++ b/standard/appspawn_service.c @@ -167,7 +167,7 @@ APPSPAWN_STATIC void WriteSignalInfoToFd(AppSpawnedProcess *appInfo, AppSpawnCon APPSPAWN_LOGE("Spawn Listen failed to write signal info to fd errno %{public}d", errno); return; } - APPSPAWN_LOGV("Spawn Listen successfully write signal info[%{public}s] to fd", jsonString); + APPSPAWN_LOGV("Spawn Listen write signal info %{public}s to fd %{public}d success", jsonString, content->signalFd); free(jsonString); } diff --git a/test/unittest/app_spawn_client_test/app_spawn_interface_test.cpp b/test/unittest/app_spawn_client_test/app_spawn_interface_test.cpp index 3edef90a..755c1c3f 100644 --- a/test/unittest/app_spawn_client_test/app_spawn_interface_test.cpp +++ b/test/unittest/app_spawn_client_test/app_spawn_interface_test.cpp @@ -638,6 +638,35 @@ HWTEST_F(AppSpawnInterfaceTest, App_SpawnListenCloseSet_001, TestSize.Level0) EXPECT_EQ(ret, 0); } +/** + * @brief 测试接口:NativeSpawnListenFdSet + * + */ +HWTEST_F(AppSpawnInterfaceTest, Native_SpawnListenFdSet_001, TestSize.Level0) +{ + int ret = NativeSpawnListenFdSet(-1); + EXPECT_EQ(ret, APPSPAWN_ARG_INVALID); + + int pipefd[2]; + EXPECT_EQ(pipe(pipefd), 0); + + ret = NativeSpawnListenFdSet(pipefd[1]); + EXPECT_EQ(ret, 0); + + close(pipefd[0]); + close(pipefd[1]); +} + +/** + * @brief 测试接口:NativeSpawnListenCloseSet + * + */ +HWTEST_F(AppSpawnInterfaceTest, Native_SpawnListenCloseSet_001, TestSize.Level0) +{ + int ret = NativeSpawnListenCloseSet(); + EXPECT_EQ(ret, 0); +} + /** * @brief 测试接口:AppSpawnClientSendUserLockStatus * diff --git a/test/unittest/app_spawn_standard_test/app_spawn_service_test.cpp b/test/unittest/app_spawn_standard_test/app_spawn_service_test.cpp index 84e41d9d..9f5dfe1b 100644 --- a/test/unittest/app_spawn_standard_test/app_spawn_service_test.cpp +++ b/test/unittest/app_spawn_standard_test/app_spawn_service_test.cpp @@ -743,6 +743,106 @@ HWTEST_F(AppSpawnServiceTest, App_Spawn_Msg_012, TestSize.Level0) } while (0); } +/** + * @brief 测试子进程退出时,nativespawn通过fd中发送子进程退出状态,发送失败 + * + */ +HWTEST_F(AppSpawnServiceTest, App_Spawn_Msg_013, TestSize.Level0) +{ + int ret = 0; + AppSpawnClientHandle clientHandle = nullptr; + AppSpawnResult result = {}; + do { + int pipefd[2]; // 2 pipe fd + char buffer[1024]; // 1024 1k + APPSPAWN_CHECK(pipe(pipefd) == 0, break, "Failed to pipe fd errno:%{public}d", errno); + ret = NativeSpawnListenFdSet(pipefd[0]); + + ret = AppSpawnClientInit(NATIVESPAWN_SERVER_NAME, &clientHandle); + APPSPAWN_CHECK(ret == 0, break, "Failed to create client %{public}s", NATIVESPAWN_SERVER_NAME); + AppSpawnReqMsgHandle reqHandle = testServer->CreateMsg(clientHandle, MSG_APP_SPAWN, 0); + + ret = AppSpawnClientSendMsg(clientHandle, reqHandle, &result); + APPSPAWN_CHECK(ret == 0, break, "Failed to send msg %{public}d", ret); + AppSpawnClientDestroy(clientHandle); + sleep(1); // wait child process stand up + + AppSpawnedProcess *app = GetSpawnedProcessByName(testServer->GetDefaultTestAppBundleName()); + ASSERT_NE(app, nullptr); + char commamd[16]; // command len 16 + APPSPAWN_CHECK(sprintf_s(commamd, 16, "kill -9 %d", app->pid) > 0, break, "sprintf command unsuccess"); + system(commamd); + + bool isFind = false; + int count = 0; + while (count < 10) { + if (read(pipefd[1], buffer, sizeof(buffer)) <= 0) { + count++; + continue; + } + if (strstr(buffer, std::to_string(app->pid).c_str()) != NULL) { + isFind = true; + break; + } + count++; + } + close(pipefd[0]); + close(pipefd[1]); + ASSERT_EQ(isFind, false); + NativeSpawnListenCloseSet(); + } while (0); +} + +/** + * @brief 测试子进程退出时,nativespawn通过fd中发送子进程退出状态,发送成功 + * + */ +HWTEST_F(AppSpawnServiceTest, App_Spawn_Msg_014, TestSize.Level0) +{ + int ret = 0; + AppSpawnClientHandle clientHandle = nullptr; + AppSpawnResult result = {}; + do { + int pipefd[2]; // 2 pipe fd + char buffer[1024]; // 1024 1k + APPSPAWN_CHECK(pipe(pipefd) == 0, break, "Failed to pipe fd errno:%{public}d", errno); + ret = NativeSpawnListenFdSet(pipefd[1]); + + ret = AppSpawnClientInit(NATIVESPAWN_SERVER_NAME, &clientHandle); + APPSPAWN_CHECK(ret == 0, break, "Failed to create client %{public}s", NATIVESPAWN_SERVER_NAME); + AppSpawnReqMsgHandle reqHandle = testServer->CreateMsg(clientHandle, MSG_APP_SPAWN, 0); + + ret = AppSpawnClientSendMsg(clientHandle, reqHandle, &result); + APPSPAWN_CHECK(ret == 0, break, "Failed to send msg %{public}d", ret); + AppSpawnClientDestroy(clientHandle); + sleep(1); // wait child process stand up + + AppSpawnedProcess *app = GetSpawnedProcessByName(testServer->GetDefaultTestAppBundleName()); + ASSERT_NE(app, nullptr); + char commamd[16]; // command len 16 + APPSPAWN_CHECK(sprintf_s(commamd, 16, "kill -9 %d", app->pid) > 0, break, "sprintf command unsuccess"); + system(commamd); + + bool isFind = false; + int count = 0; + while (count < 10) { + if (read(pipefd[0], buffer, sizeof(buffer)) <= 0) { + count++; + continue; + } + if (strstr(buffer, std::to_string(app->pid).c_str()) != NULL) { + isFind = true; + break; + } + count++; + } + close(pipefd[0]); + close(pipefd[1]); + ASSERT_EQ(isFind, true); + NativeSpawnListenCloseSet(); + } while (0); +} + /** * @brief 必须最后一个,kill nwebspawn,appspawn的线程结束 * -- Gitee