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