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 <fcntl.h> 17#include <limits.h> 18#include <sched.h> 19#include <stdlib.h> 20#include <unistd.h> 21 22#include <sys/ipc.h> 23#include <sys/mman.h> 24#include <sys/mount.h> 25#include <sys/signalfd.h> 26#include <sys/socket.h> 27#include <sys/stat.h> 28#include <sys/wait.h> 29 30#include "appspawn_adapter.h" 31#include "appspawn_hook.h" 32#include "appspawn_msg.h" 33#include "appspawn_manager.h" 34#include "securec.h" 35 36#define SLEEP_DURATION 3000 // us 37#define EXIT_APP_TIMEOUT 1000000 // us 38 39static AppSpawnMgr *g_appSpawnMgr = NULL; 40 41AppSpawnMgr *CreateAppSpawnMgr(int mode) 42{ 43 APPSPAWN_CHECK_ONLY_EXPER(mode < MODE_INVALID, return NULL); 44 if (g_appSpawnMgr != NULL) { 45 return g_appSpawnMgr; 46 } 47 AppSpawnMgr *appMgr = (AppSpawnMgr *)calloc(1, sizeof(AppSpawnMgr)); 48 APPSPAWN_CHECK(appMgr != NULL, return NULL, "Failed to alloc memory for appspawn"); 49 appMgr->content.longProcName = NULL; 50 appMgr->content.longProcNameLen = 0; 51 appMgr->content.mode = mode; 52 appMgr->content.sandboxNsFlags = 0; 53 appMgr->content.wdgOpened = 0; 54 appMgr->servicePid = getpid(); 55 appMgr->server = NULL; 56 appMgr->sigHandler = NULL; 57 OH_ListInit(&appMgr->appQueue); 58 OH_ListInit(&appMgr->diedQueue); 59 OH_ListInit(&appMgr->appSpawnQueue); 60 appMgr->diedAppCount = 0; 61 OH_ListInit(&appMgr->extData); 62 g_appSpawnMgr = appMgr; 63 g_appSpawnMgr->spawnTime.minAppspawnTime = APPSPAWN_MAX_TIME; 64 g_appSpawnMgr->spawnTime.maxAppspawnTime = 0; 65 return appMgr; 66} 67 68AppSpawnMgr *GetAppSpawnMgr(void) 69{ 70 return g_appSpawnMgr; 71} 72 73AppSpawnContent *GetAppSpawnContent(void) 74{ 75 return g_appSpawnMgr == NULL ? NULL : &g_appSpawnMgr->content; 76} 77 78static void SpawningQueueDestroy(ListNode *node) 79{ 80 AppSpawningCtx *property = ListEntry(node, AppSpawningCtx, node); 81 DeleteAppSpawningCtx(property); 82} 83 84static void ExtDataDestroy(ListNode *node) 85{ 86 AppSpawnExtData *extData = ListEntry(node, AppSpawnExtData, node); 87 AppSpawnExtDataFree freeNode = extData->freeNode; 88 if (freeNode) { 89 freeNode(extData); 90 } 91} 92 93void DeleteAppSpawnMgr(AppSpawnMgr *mgr) 94{ 95 APPSPAWN_CHECK_ONLY_EXPER(mgr != NULL, return); 96 OH_ListRemoveAll(&mgr->appQueue, NULL); 97 OH_ListRemoveAll(&mgr->diedQueue, NULL); 98 OH_ListRemoveAll(&mgr->appSpawnQueue, SpawningQueueDestroy); 99 OH_ListRemoveAll(&mgr->extData, ExtDataDestroy); 100 101 APPSPAWN_LOGV("DeleteAppSpawnMgr %{public}d %{public}d", mgr->servicePid, getpid()); 102 free(mgr); 103 if (g_appSpawnMgr == mgr) { 104 g_appSpawnMgr = NULL; 105 } 106} 107 108void TraversalSpawnedProcess(AppTraversal traversal, void *data) 109{ 110 APPSPAWN_CHECK_ONLY_EXPER(g_appSpawnMgr != NULL && traversal != NULL, return); 111 ListNode *node = g_appSpawnMgr->appQueue.next; 112 while (node != &g_appSpawnMgr->appQueue) { 113 ListNode *next = node->next; 114 AppSpawnedProcess *appInfo = ListEntry(node, AppSpawnedProcess, node); 115 traversal(g_appSpawnMgr, appInfo, data); 116 node = next; 117 } 118} 119 120static int AppInfoPidComparePro(ListNode *node, void *data) 121{ 122 AppSpawnedProcess *node1 = ListEntry(node, AppSpawnedProcess, node); 123 pid_t pid = *(pid_t *)data; 124 return node1->pid - pid; 125} 126 127static int AppInfoNameComparePro(ListNode *node, void *data) 128{ 129 AppSpawnedProcess *node1 = ListEntry(node, AppSpawnedProcess, node); 130 return strcmp(node1->name, (char *)data); 131} 132 133static int AppInfoCompareProc(ListNode *node, ListNode *newNode) 134{ 135 AppSpawnedProcess *node1 = ListEntry(node, AppSpawnedProcess, node); 136 AppSpawnedProcess *node2 = ListEntry(newNode, AppSpawnedProcess, node); 137 return node1->pid - node2->pid; 138} 139 140AppSpawnedProcess *AddSpawnedProcess(pid_t pid, const char *processName, bool isDebuggable) 141{ 142 APPSPAWN_CHECK(g_appSpawnMgr != NULL && processName != NULL, return NULL, "Invalid mgr or process name"); 143 APPSPAWN_CHECK(pid > 0, return NULL, "Invalid pid for %{public}s", processName); 144 size_t len = strlen(processName) + 1; 145 APPSPAWN_CHECK(len > 1, return NULL, "Invalid processName for %{public}s", processName); 146 AppSpawnedProcess *node = (AppSpawnedProcess *)calloc(1, sizeof(AppSpawnedProcess) + len + 1); 147 APPSPAWN_CHECK(node != NULL, return NULL, "Failed to malloc for appinfo"); 148 149 node->pid = pid; 150 node->max = 0; 151 node->uid = 0; 152 node->exitStatus = 0; 153 node->isDebuggable = isDebuggable; 154 int ret = strcpy_s(node->name, len, processName); 155 APPSPAWN_CHECK(ret == 0, free(node); 156 return NULL, "Failed to strcpy process name"); 157 158 OH_ListInit(&node->node); 159 APPSPAWN_LOGI("Add %{public}s, pid=%{public}d success", processName, pid); 160 OH_ListAddWithOrder(&g_appSpawnMgr->appQueue, &node->node, AppInfoCompareProc); 161 return node; 162} 163 164void TerminateSpawnedProcess(AppSpawnedProcess *node) 165{ 166 APPSPAWN_CHECK_ONLY_EXPER(g_appSpawnMgr != NULL && node != NULL, return); 167 // delete node 168 OH_ListRemove(&node->node); 169 OH_ListInit(&node->node); 170 if (!IsNWebSpawnMode(g_appSpawnMgr)) { 171 free(node); 172 return; 173 } 174 if (g_appSpawnMgr->diedAppCount >= MAX_DIED_PROCESS_COUNT) { 175 AppSpawnedProcess *oldApp = ListEntry(g_appSpawnMgr->diedQueue.next, AppSpawnedProcess, node); 176 OH_ListRemove(&oldApp->node); 177 OH_ListInit(&oldApp->node); 178 free(oldApp); 179 g_appSpawnMgr->diedAppCount--; 180 } 181 APPSPAWN_LOGI("ProcessAppDied %{public}s, pid=%{public}d", node->name, node->pid); 182 OH_ListAddTail(&g_appSpawnMgr->diedQueue, &node->node); 183 g_appSpawnMgr->diedAppCount++; 184} 185 186AppSpawnedProcess *GetSpawnedProcess(pid_t pid) 187{ 188 APPSPAWN_CHECK_ONLY_EXPER(g_appSpawnMgr != NULL, return NULL); 189 ListNode *node = OH_ListFind(&g_appSpawnMgr->appQueue, &pid, AppInfoPidComparePro); 190 APPSPAWN_CHECK_ONLY_EXPER(node != NULL, return NULL); 191 return ListEntry(node, AppSpawnedProcess, node); 192} 193 194AppSpawnedProcess *GetSpawnedProcessByName(const char *name) 195{ 196 APPSPAWN_CHECK_ONLY_EXPER(g_appSpawnMgr != NULL, return NULL); 197 APPSPAWN_CHECK_ONLY_EXPER(name != NULL, return NULL); 198 199 ListNode *node = OH_ListFind(&g_appSpawnMgr->appQueue, (void *)name, AppInfoNameComparePro); 200 APPSPAWN_CHECK_ONLY_EXPER(node != NULL, return NULL); 201 return ListEntry(node, AppSpawnedProcess, node); 202} 203 204static void DumpProcessSpawnStack(pid_t pid) 205{ 206#if (!defined(CJAPP_SPAWN) && !defined(NATIVE_SPAWN)) 207 DumpSpawnStack(pid); 208 DumpSpawnStack(getpid()); 209#endif 210#ifndef APPSPAWN_TEST 211 kill(pid, SIGKILL); 212#endif 213 APPSPAWN_LOGI("Dump stack finished"); 214} 215 216int KillAndWaitStatus(pid_t pid, int sig, int *exitStatus) 217{ 218 APPSPAWN_CHECK_ONLY_EXPER(exitStatus != NULL, return 0); 219 *exitStatus = -1; 220 if (pid <= 0) { 221 return 0; 222 } 223 224 if (kill(pid, sig) != 0) { 225 APPSPAWN_LOGE("unable to kill process, pid: %{public}d ret %{public}d", pid, errno); 226 return -1; 227 } 228 pid_t exitPid = 0; 229 int retry = 0; 230 while (retry * SLEEP_DURATION < EXIT_APP_TIMEOUT) { 231 exitPid = waitpid(pid, exitStatus, WNOHANG); 232 if (exitPid == pid) { 233 return 0; 234 } 235 usleep(SLEEP_DURATION); 236 retry++; 237 } 238 239 DumpProcessSpawnStack(pid); 240 APPSPAWN_LOGE("waitpid failed, pid: %{public}d %{public}d, status: %{public}d", exitPid, pid, *exitStatus); 241 242 return -1; 243} 244 245static int GetProcessTerminationStatus(pid_t pid) 246{ 247 APPSPAWN_CHECK_ONLY_EXPER(g_appSpawnMgr != NULL, return -1); 248 APPSPAWN_LOGV("GetProcessTerminationStatus pid: %{public}d ", pid); 249 if (pid <= 0) { 250 return 0; 251 } 252 int exitStatus = 0; 253 ListNode *node = OH_ListFind(&g_appSpawnMgr->diedQueue, &pid, AppInfoPidComparePro); 254 if (node != NULL) { 255 AppSpawnedProcess *info = ListEntry(node, AppSpawnedProcess, node); 256 exitStatus = info->exitStatus; 257 OH_ListRemove(node); 258 OH_ListInit(node); 259 free(info); 260 if (g_appSpawnMgr->diedAppCount > 0) { 261 g_appSpawnMgr->diedAppCount--; 262 } 263 return exitStatus; 264 } 265 AppSpawnedProcess *app = GetSpawnedProcess(pid); 266 if (app == NULL) { 267 APPSPAWN_LOGE("unable to get process, pid: %{public}d ", pid); 268 return -1; 269 } 270 271 if (KillAndWaitStatus(pid, SIGKILL, &exitStatus) == 0) { // kill success, delete app 272 OH_ListRemove(&app->node); 273 OH_ListInit(&app->node); 274 free(app); 275 } 276 return exitStatus; 277} 278 279AppSpawningCtx *CreateAppSpawningCtx(void) 280{ 281 static uint32_t requestId = 0; 282 AppSpawningCtx *property = (AppSpawningCtx *)malloc(sizeof(AppSpawningCtx)); 283 APPSPAWN_CHECK(property != NULL, return NULL, "Failed to create AppSpawningCtx "); 284 property->client.id = ++requestId; 285 property->client.flags = 0; 286 property->forkCtx.watcherHandle = NULL; 287 property->forkCtx.pidFdWatcherHandle = NULL; 288 property->forkCtx.coldRunPath = NULL; 289 property->forkCtx.timer = NULL; 290 property->forkCtx.fd[0] = -1; 291 property->forkCtx.fd[1] = -1; 292 property->isPrefork = false; 293 property->forkCtx.childMsg = NULL; 294 property->message = NULL; 295 property->pid = 0; 296 property->state = APP_STATE_IDLE; 297 OH_ListInit(&property->node); 298 if (g_appSpawnMgr) { 299 OH_ListAddTail(&g_appSpawnMgr->appSpawnQueue, &property->node); 300 } 301 return property; 302} 303 304void DeleteAppSpawningCtx(AppSpawningCtx *property) 305{ 306 APPSPAWN_CHECK_ONLY_EXPER(property != NULL, return); 307 APPSPAWN_LOGV("DeleteAppSpawningCtx"); 308 309 DeleteAppSpawnMsg(property->message); 310 311 OH_ListRemove(&property->node); 312 if (property->forkCtx.timer) { 313 LE_StopTimer(LE_GetDefaultLoop(), property->forkCtx.timer); 314 property->forkCtx.timer = NULL; 315 } 316 if (property->forkCtx.watcherHandle) { 317 LE_RemoveWatcher(LE_GetDefaultLoop(), property->forkCtx.watcherHandle); 318 property->forkCtx.watcherHandle = NULL; 319 } 320 if (property->forkCtx.coldRunPath) { 321 free(property->forkCtx.coldRunPath); 322 property->forkCtx.coldRunPath = NULL; 323 } 324 if (property->forkCtx.fd[0] >= 0) { 325 close(property->forkCtx.fd[0]); 326 } 327 if (property->forkCtx.fd[1] >= 0) { 328 close(property->forkCtx.fd[1]); 329 } 330 331 free(property); 332} 333 334static int AppPropertyComparePid(ListNode *node, void *data) 335{ 336 AppSpawningCtx *property = ListEntry(node, AppSpawningCtx, node); 337 if (property->pid == *(pid_t *)data) { 338 return 0; 339 } 340 return 1; 341} 342 343AppSpawningCtx *GetAppSpawningCtxByPid(pid_t pid) 344{ 345 APPSPAWN_CHECK_ONLY_EXPER(g_appSpawnMgr != NULL, return NULL); 346 ListNode *node = OH_ListFind(&g_appSpawnMgr->appSpawnQueue, (void *)&pid, AppPropertyComparePid); 347 APPSPAWN_CHECK_ONLY_EXPER(node != NULL, return NULL); 348 return ListEntry(node, AppSpawningCtx, node); 349} 350 351void AppSpawningCtxTraversal(ProcessTraversal traversal, void *data) 352{ 353 APPSPAWN_CHECK_ONLY_EXPER(g_appSpawnMgr != NULL && traversal != NULL, return); 354 ListNode *node = g_appSpawnMgr->appSpawnQueue.next; 355 while (node != &g_appSpawnMgr->appSpawnQueue) { 356 ListNode *next = node->next; 357 AppSpawningCtx *ctx = ListEntry(node, AppSpawningCtx, node); 358 traversal(g_appSpawnMgr, ctx, data); 359 node = next; 360 } 361} 362 363static int DumpAppSpawnQueue(ListNode *node, void *data) 364{ 365 AppSpawningCtx *property = ListEntry(node, AppSpawningCtx, node); 366 APPSPAPWN_DUMP("app property id: %{public}u flags: %{public}x", 367 property->client.id, property->client.flags); 368 APPSPAPWN_DUMP("app property state: %{public}d", property->state); 369 370 DumpAppSpawnMsg(property->message); 371 return 0; 372} 373 374static int DumpAppQueue(ListNode *node, void *data) 375{ 376 AppSpawnedProcess *appInfo = ListEntry(node, AppSpawnedProcess, node); 377 uint64_t diff = DiffTime(&appInfo->spawnStart, &appInfo->spawnEnd); 378 APPSPAPWN_DUMP("App info uid: %{public}u pid: %{public}x", appInfo->uid, appInfo->pid); 379 APPSPAPWN_DUMP("App info name: %{public}s exitStatus: 0x%{public}x spawn time: %{public}" PRIu64 " us ", 380 appInfo->name, appInfo->exitStatus, diff); 381 return 0; 382} 383 384static int DumpExtData(ListNode *node, void *data) 385{ 386 AppSpawnExtData *extData = ListEntry(node, AppSpawnExtData, node); 387 if (extData->dumpNode) { 388 extData->dumpNode(extData); 389 } 390 return 0; 391} 392 393void ProcessAppSpawnDumpMsg(const AppSpawnMsgNode *message) 394{ 395 APPSPAWN_CHECK_ONLY_EXPER(g_appSpawnMgr != NULL && message != NULL, return); 396 FILE *stream = NULL; 397 uint32_t len = 0; 398 char *ptyName = GetAppSpawnMsgExtInfo(message, "pty-name", &len); 399 if (ptyName != NULL) { 400 APPSPAWN_LOGI("Dump info to file '%{public}s'", ptyName); 401 char canonicalPtyPath[PATH_MAX] = {0}; 402 if (realpath(ptyName, canonicalPtyPath) == NULL) { 403 return; 404 } 405 stream = fopen(canonicalPtyPath, "w"); 406 SetDumpToStream(stream); 407 } else { 408 SetDumpToStream(stdout); 409 } 410 APPSPAPWN_DUMP("Dump appspawn info start ... "); 411 APPSPAPWN_DUMP("APP spawning queue: "); 412 OH_ListTraversal((ListNode *)&g_appSpawnMgr->appSpawnQueue, NULL, DumpAppSpawnQueue, 0); 413 APPSPAPWN_DUMP("APP queue: "); 414 OH_ListTraversal((ListNode *)&g_appSpawnMgr->appQueue, "App queue", DumpAppQueue, 0); 415 APPSPAPWN_DUMP("APP died queue: "); 416 OH_ListTraversal((ListNode *)&g_appSpawnMgr->diedQueue, "App died queue", DumpAppQueue, 0); 417 APPSPAPWN_DUMP("Ext data: "); 418 OH_ListTraversal((ListNode *)&g_appSpawnMgr->extData, "Ext data", DumpExtData, 0); 419 APPSPAPWN_DUMP("Dump appspawn info finish "); 420 if (stream != NULL) { 421 (void)fflush(stream); 422 fclose(stream); 423#ifdef APPSPAWN_TEST 424 SetDumpToStream(stdout); 425#else 426 SetDumpToStream(NULL); 427#endif 428 } 429} 430 431int ProcessTerminationStatusMsg(const AppSpawnMsgNode *message, AppSpawnResult *result) 432{ 433 APPSPAWN_CHECK_ONLY_EXPER(g_appSpawnMgr != NULL && message != NULL, return -1); 434 APPSPAWN_CHECK_ONLY_EXPER(result != NULL, return -1); 435 if (!IsNWebSpawnMode(g_appSpawnMgr)) { 436 return APPSPAWN_MSG_INVALID; 437 } 438 result->result = -1; 439 result->pid = 0; 440 pid_t *pid = (pid_t *)GetAppSpawnMsgInfo(message, TLV_RENDER_TERMINATION_INFO); 441 if (pid == NULL) { 442 return -1; 443 } 444 // get render process termination status, only nwebspawn need this logic. 445 result->pid = *pid; 446 result->result = GetProcessTerminationStatus(*pid); 447 return 0; 448} 449