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->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 
GetAppSpawnMgr(void)68 AppSpawnMgr *GetAppSpawnMgr(void)
69 {
70     return g_appSpawnMgr;
71 }
72 
GetAppSpawnContent(void)73 AppSpawnContent *GetAppSpawnContent(void)
74 {
75     return g_appSpawnMgr == NULL ? NULL : &g_appSpawnMgr->content;
76 }
77 
SpawningQueueDestroy(ListNode *node)78 static void SpawningQueueDestroy(ListNode *node)
79 {
80     AppSpawningCtx *property = ListEntry(node, AppSpawningCtx, node);
81     DeleteAppSpawningCtx(property);
82 }
83 
ExtDataDestroy(ListNode *node)84 static 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 
DeleteAppSpawnMgr(AppSpawnMgr *mgr)93 void 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 
TraversalSpawnedProcess(AppTraversal traversal, void *data)108 void 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 
AppInfoPidComparePro(ListNode *node, void *data)120 static 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 
AppInfoNameComparePro(ListNode *node, void *data)127 static int AppInfoNameComparePro(ListNode *node, void *data)
128 {
129     AppSpawnedProcess *node1 = ListEntry(node, AppSpawnedProcess, node);
130     return strcmp(node1->name, (char *)data);
131 }
132 
AppInfoCompareProc(ListNode *node, ListNode *newNode)133 static 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 
AddSpawnedProcess(pid_t pid, const char *processName, bool isDebuggable)140 AppSpawnedProcess *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 
TerminateSpawnedProcess(AppSpawnedProcess *node)164 void 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 
GetSpawnedProcess(pid_t pid)186 AppSpawnedProcess *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 
GetSpawnedProcessByName(const char *name)194 AppSpawnedProcess *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 
DumpProcessSpawnStack(pid_t pid)204 static 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 
KillAndWaitStatus(pid_t pid, int sig, int *exitStatus)216 int 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 
GetProcessTerminationStatus(pid_t pid)245 static 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 
CreateAppSpawningCtx(void)279 AppSpawningCtx *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 
DeleteAppSpawningCtx(AppSpawningCtx *property)304 void 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 
AppPropertyComparePid(ListNode *node, void *data)334 static 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 
GetAppSpawningCtxByPid(pid_t pid)343 AppSpawningCtx *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 
AppSpawningCtxTraversal(ProcessTraversal traversal, void *data)351 void 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 
DumpAppSpawnQueue(ListNode *node, void *data)363 static 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 
DumpAppQueue(ListNode *node, void *data)374 static 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 
DumpExtData(ListNode *node, void *data)384 static 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 
ProcessAppSpawnDumpMsg(const AppSpawnMsgNode *message)393 void 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 
ProcessTerminationStatusMsg(const AppSpawnMsgNode *message, AppSpawnResult *result)431 int 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