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