diff --git a/adapter/appspawn_adapter.h b/adapter/appspawn_adapter.h index a1df6de0f180d9e0d348faebfd958ec4eaa8f287..22168570d45020df85daafaee8cc279f0930ac04 100644 --- a/adapter/appspawn_adapter.h +++ b/adapter/appspawn_adapter.h @@ -29,6 +29,8 @@ void SetAppAccessToken(struct AppSpawnContent_ *content, AppSpawnClient *client) void LoadExtendLib(AppSpawnContent *content); void RunChildProcessor(AppSpawnContent *content, AppSpawnClient *client); void RegisterAppSandbox(struct AppSpawnContent_ *content, AppSpawnClient *client); +int GetRenderProcessTerminationStatus(int32_t pid, int *status); +void RecordRenderProcessExitedStatus(pid_t pid, int status); void LoadAppSandboxConfig(void); #ifdef __cplusplus } diff --git a/adapter/appspawn_nweb.cpp b/adapter/appspawn_nweb.cpp index b46ccee5d4116db5f98d41f21d12869ea8aaabf0..926ac939bbc856efad8b17a706d8122724381b9d 100644 --- a/adapter/appspawn_nweb.cpp +++ b/adapter/appspawn_nweb.cpp @@ -15,10 +15,23 @@ #include "appspawn_adapter.h" +#include +#include #include +#include #include +struct RenderProcessNode { + RenderProcessNode(time_t now, int exit):recordTime_(now), exitStatus_(exit) {} + time_t recordTime_; + int exitStatus_; +}; + +namespace { +constexpr int32_t RENDER_PROCESS_MAX_NUM = 16; +std::map g_renderProcessMap; void *g_nwebHandle = nullptr; +} void LoadExtendLib(AppSpawnContent *content) { @@ -61,3 +74,49 @@ void RunChildProcessor(AppSpawnContent *content, AppSpawnClient *client) } funcNWebRenderMain(appProperty->property.renderCmd); } + +static void DumpRenderProcessExitedMap() +{ + APPSPAWN_LOGI("dump render process exited array:"); + for (auto& it : g_renderProcessMap) { + APPSPAWN_LOGV("[pid, time, exitedStatus] = [%d, %ld, %d]", + it.first, it.second.recordTime_, it.second.exitStatus_); + } +} + +void RecordRenderProcessExitedStatus(pid_t pid, int status) +{ + if (g_renderProcessMap.size() < RENDER_PROCESS_MAX_NUM) { + RenderProcessNode node(time(nullptr), status); + g_renderProcessMap.insert({pid, node}); + return; + } + + APPSPAWN_LOGV("render process map size reach max, need to erase oldest data."); + DumpRenderProcessExitedMap(); + auto oldestData = std::min_element(g_renderProcessMap.begin(), g_renderProcessMap.end(), + [](const std::pair& left, const std::pair& right) { + return left.second.recordTime_ < right.second.recordTime_; + }); + g_renderProcessMap.erase(oldestData); + RenderProcessNode node(time(nullptr), status); + g_renderProcessMap.insert({pid, node}); + DumpRenderProcessExitedMap(); +} + +int GetRenderProcessTerminationStatus(int32_t pid, int *status) +{ + if (status == nullptr) { + return -1; + } + + auto it = g_renderProcessMap.find(pid); + if (it != g_renderProcessMap.end()) { + *status = it->second.exitStatus_; + g_renderProcessMap.erase(it); + return 0; + } + APPSPAWN_LOGE("not find pid[%d] in render process exited map", pid); + DumpRenderProcessExitedMap(); + return -1; +} \ No newline at end of file diff --git a/standard/appspawn_service.c b/standard/appspawn_service.c index 1e2ec020cd66cc0dec4cbadd2c956bd74443b1d6..7b6fd53bac84aaa6eea6121d61e2346b107cf2cb 100644 --- a/standard/appspawn_service.c +++ b/standard/appspawn_service.c @@ -158,13 +158,17 @@ static void SignalHandler(const struct signalfd_siginfo *siginfo) APPSPAWN_LOGI("SignalHandler signum %d", siginfo->ssi_signo); switch (siginfo->ssi_signo) { case SIGCHLD: { // delete pid from app map - // nwebspawn will invoke waitpid and remove appinfo at GetRenderProcessTerminationStatus. pid_t pid; int status; while ((pid = waitpid(-1, &status, WNOHANG)) > 0) { APPSPAWN_LOGI("SignalHandler pid %d status %d", pid, status); #ifdef REPORT_EVENT PrintProcessExitInfo(pid, siginfo->ssi_uid, status); +#endif +#ifdef NWEB_SPAWN + // nwebspawn will invoke waitpid and remove appinfo at GetProcessTerminationStatusInner when + // GetProcessTerminationStatusInner is called before the parent process receives the SIGCHLD signal. + RecordRenderProcessExitedStatus(pid, status); #endif RemoveAppInfo(pid); } @@ -245,12 +249,17 @@ static void StartColdApp(AppSpawnClientExt *appProperty) } #ifdef NWEB_SPAWN -static int GetRenderProcessTerminationStatus(int32_t pid, int *status) +static int GetProcessTerminationStatusInner(int32_t pid, int *status) { if (status == NULL) { return -1; } + if (GetRenderProcessTerminationStatus(pid, status) == 0) { + // this shows that the parent process has recived SIGCHLD signal. + return 0; + } + if (kill(pid, SIGKILL) != 0) { APPSPAWN_LOGE("unable to kill render process, pid: %d", pid); } @@ -267,7 +276,7 @@ static int GetRenderProcessTerminationStatus(int32_t pid, int *status) static void GetProcessTerminationStatus(AppSpawnClientExt *appProperty) { int exitStatus = 0; - int ret = GetRenderProcessTerminationStatus(appProperty->property.pid, &exitStatus); + int ret = GetProcessTerminationStatusInner(appProperty->property.pid, &exitStatus); if (ret) { SendResponse(appProperty, (char *)&ret, sizeof(ret)); } else {