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 #ifdef APPSPAWN_HISYSEVENT
58 appMgr->hisyseventInfo = NULL;
59 #endif
60 OH_ListInit(&appMgr->appQueue);
61 OH_ListInit(&appMgr->diedQueue);
62 OH_ListInit(&appMgr->appSpawnQueue);
63 #ifndef APPSPAWN_SANDBOX_NEW
64 OH_ListInit(&appMgr->dataGroupCtxQueue);
65 #endif
66 appMgr->diedAppCount = 0;
67 OH_ListInit(&appMgr->extData);
68 g_appSpawnMgr = appMgr;
69 g_appSpawnMgr->spawnTime.minAppspawnTime = APPSPAWN_MAX_TIME;
70 g_appSpawnMgr->spawnTime.maxAppspawnTime = 0;
71 return appMgr;
72 }
73
GetAppSpawnMgr(void)74 AppSpawnMgr *GetAppSpawnMgr(void)
75 {
76 return g_appSpawnMgr;
77 }
78
GetAppSpawnContent(void)79 AppSpawnContent *GetAppSpawnContent(void)
80 {
81 return g_appSpawnMgr == NULL ? NULL : &g_appSpawnMgr->content;
82 }
83
SpawningQueueDestroy(ListNode * node)84 static void SpawningQueueDestroy(ListNode *node)
85 {
86 AppSpawningCtx *property = ListEntry(node, AppSpawningCtx, node);
87 DeleteAppSpawningCtx(property);
88 }
89
ExtDataDestroy(ListNode * node)90 static void ExtDataDestroy(ListNode *node)
91 {
92 AppSpawnExtData *extData = ListEntry(node, AppSpawnExtData, node);
93 AppSpawnExtDataFree freeNode = extData->freeNode;
94 if (freeNode) {
95 freeNode(extData);
96 }
97 }
98
DeleteAppSpawnMgr(AppSpawnMgr * mgr)99 void DeleteAppSpawnMgr(AppSpawnMgr *mgr)
100 {
101 APPSPAWN_CHECK_ONLY_EXPER(mgr != NULL, return);
102 OH_ListRemoveAll(&mgr->appQueue, NULL);
103 OH_ListRemoveAll(&mgr->diedQueue, NULL);
104 OH_ListRemoveAll(&mgr->appSpawnQueue, SpawningQueueDestroy);
105 OH_ListRemoveAll(&mgr->extData, ExtDataDestroy);
106 #ifndef APPSPAWN_SANDBOX_NEW
107 OH_ListRemoveAll(&mgr->dataGroupCtxQueue, NULL);
108 #endif
109 #ifdef APPSPAWN_HISYSEVENT
110 DeleteHisyseventInfo(mgr->hisyseventInfo);
111 #endif
112
113 APPSPAWN_LOGV("DeleteAppSpawnMgr %{public}d %{public}d", mgr->servicePid, getpid());
114 free(mgr);
115 if (g_appSpawnMgr == mgr) {
116 g_appSpawnMgr = NULL;
117 }
118 }
119
TraversalSpawnedProcess(AppTraversal traversal,void * data)120 void TraversalSpawnedProcess(AppTraversal traversal, void *data)
121 {
122 APPSPAWN_CHECK_ONLY_EXPER(g_appSpawnMgr != NULL && traversal != NULL, return);
123 ListNode *node = g_appSpawnMgr->appQueue.next;
124 while (node != &g_appSpawnMgr->appQueue) {
125 ListNode *next = node->next;
126 AppSpawnedProcess *appInfo = ListEntry(node, AppSpawnedProcess, node);
127 traversal(g_appSpawnMgr, appInfo, data);
128 node = next;
129 }
130 }
131
AppInfoPidComparePro(ListNode * node,void * data)132 static int AppInfoPidComparePro(ListNode *node, void *data)
133 {
134 AppSpawnedProcess *node1 = ListEntry(node, AppSpawnedProcess, node);
135 pid_t pid = *(pid_t *)data;
136 return node1->pid - pid;
137 }
138
AppInfoNameComparePro(ListNode * node,void * data)139 static int AppInfoNameComparePro(ListNode *node, void *data)
140 {
141 AppSpawnedProcess *node1 = ListEntry(node, AppSpawnedProcess, node);
142 return strcmp(node1->name, (char *)data);
143 }
144
AppInfoCompareProc(ListNode * node,ListNode * newNode)145 static int AppInfoCompareProc(ListNode *node, ListNode *newNode)
146 {
147 AppSpawnedProcess *node1 = ListEntry(node, AppSpawnedProcess, node);
148 AppSpawnedProcess *node2 = ListEntry(newNode, AppSpawnedProcess, node);
149 return node1->pid - node2->pid;
150 }
151
AddSpawnedProcess(pid_t pid,const char * processName,bool isDebuggable)152 AppSpawnedProcess *AddSpawnedProcess(pid_t pid, const char *processName, bool isDebuggable)
153 {
154 APPSPAWN_CHECK(g_appSpawnMgr != NULL && processName != NULL, return NULL, "Invalid mgr or process name");
155 APPSPAWN_CHECK(pid > 0, return NULL, "Invalid pid for %{public}s", processName);
156 size_t len = strlen(processName) + 1;
157 APPSPAWN_CHECK(len > 1, return NULL, "Invalid processName for %{public}s", processName);
158 AppSpawnedProcess *node = (AppSpawnedProcess *)calloc(1, sizeof(AppSpawnedProcess) + len + 1);
159 APPSPAWN_CHECK(node != NULL, return NULL, "Failed to malloc for appinfo");
160
161 node->pid = pid;
162 node->max = 0;
163 node->uid = 0;
164 node->exitStatus = 0;
165 node->isDebuggable = isDebuggable;
166 int ret = strcpy_s(node->name, len, processName);
167 APPSPAWN_CHECK(ret == 0, free(node);
168 return NULL, "Failed to strcpy process name");
169
170 OH_ListInit(&node->node);
171 APPSPAWN_LOGI("Add %{public}s, pid=%{public}d success", processName, pid);
172 OH_ListAddWithOrder(&g_appSpawnMgr->appQueue, &node->node, AppInfoCompareProc);
173 return node;
174 }
175
TerminateSpawnedProcess(AppSpawnedProcess * node)176 void TerminateSpawnedProcess(AppSpawnedProcess *node)
177 {
178 APPSPAWN_CHECK_ONLY_EXPER(g_appSpawnMgr != NULL && node != NULL, return);
179 // delete node
180 OH_ListRemove(&node->node);
181 OH_ListInit(&node->node);
182 if (!IsNWebSpawnMode(g_appSpawnMgr)) {
183 free(node);
184 return;
185 }
186 if (g_appSpawnMgr->diedAppCount >= MAX_DIED_PROCESS_COUNT) {
187 AppSpawnedProcess *oldApp = ListEntry(g_appSpawnMgr->diedQueue.next, AppSpawnedProcess, node);
188 OH_ListRemove(&oldApp->node);
189 OH_ListInit(&oldApp->node);
190 free(oldApp);
191 g_appSpawnMgr->diedAppCount--;
192 }
193 APPSPAWN_LOGI("ProcessAppDied %{public}s, pid=%{public}d", node->name, node->pid);
194 OH_ListAddTail(&g_appSpawnMgr->diedQueue, &node->node);
195 g_appSpawnMgr->diedAppCount++;
196 }
197
GetSpawnedProcess(pid_t pid)198 AppSpawnedProcess *GetSpawnedProcess(pid_t pid)
199 {
200 APPSPAWN_CHECK_ONLY_EXPER(g_appSpawnMgr != NULL, return NULL);
201 ListNode *node = OH_ListFind(&g_appSpawnMgr->appQueue, &pid, AppInfoPidComparePro);
202 APPSPAWN_CHECK_ONLY_EXPER(node != NULL, return NULL);
203 return ListEntry(node, AppSpawnedProcess, node);
204 }
205
GetSpawnedProcessByName(const char * name)206 AppSpawnedProcess *GetSpawnedProcessByName(const char *name)
207 {
208 APPSPAWN_CHECK_ONLY_EXPER(g_appSpawnMgr != NULL, return NULL);
209 APPSPAWN_CHECK_ONLY_EXPER(name != NULL, return NULL);
210
211 ListNode *node = OH_ListFind(&g_appSpawnMgr->appQueue, (void *)name, AppInfoNameComparePro);
212 APPSPAWN_CHECK_ONLY_EXPER(node != NULL, return NULL);
213 return ListEntry(node, AppSpawnedProcess, node);
214 }
215
DumpProcessSpawnStack(pid_t pid)216 static void DumpProcessSpawnStack(pid_t pid)
217 {
218 #if (!defined(CJAPP_SPAWN) && !defined(NATIVE_SPAWN))
219 DumpSpawnStack(pid);
220 DumpSpawnStack(getpid());
221 #endif
222 kill(pid, SIGKILL);
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 LE_RemoveWatcher(LE_GetDefaultLoop(), property->forkCtx.watcherHandle);
329 property->forkCtx.watcherHandle = NULL;
330 }
331 if (property->forkCtx.coldRunPath) {
332 free(property->forkCtx.coldRunPath);
333 property->forkCtx.coldRunPath = NULL;
334 }
335 if (property->forkCtx.fd[0] >= 0) {
336 close(property->forkCtx.fd[0]);
337 }
338 if (property->forkCtx.fd[1] >= 0) {
339 close(property->forkCtx.fd[1]);
340 }
341
342 free(property);
343 }
344
AppPropertyComparePid(ListNode * node,void * data)345 static int AppPropertyComparePid(ListNode *node, void *data)
346 {
347 AppSpawningCtx *property = ListEntry(node, AppSpawningCtx, node);
348 if (property->pid == *(pid_t *)data) {
349 return 0;
350 }
351 return 1;
352 }
353
GetAppSpawningCtxByPid(pid_t pid)354 AppSpawningCtx *GetAppSpawningCtxByPid(pid_t pid)
355 {
356 APPSPAWN_CHECK_ONLY_EXPER(g_appSpawnMgr != NULL, return NULL);
357 ListNode *node = OH_ListFind(&g_appSpawnMgr->appSpawnQueue, (void *)&pid, AppPropertyComparePid);
358 APPSPAWN_CHECK_ONLY_EXPER(node != NULL, return NULL);
359 return ListEntry(node, AppSpawningCtx, node);
360 }
361
AppSpawningCtxTraversal(ProcessTraversal traversal,void * data)362 void AppSpawningCtxTraversal(ProcessTraversal traversal, void *data)
363 {
364 APPSPAWN_CHECK_ONLY_EXPER(g_appSpawnMgr != NULL && traversal != NULL, return);
365 ListNode *node = g_appSpawnMgr->appSpawnQueue.next;
366 while (node != &g_appSpawnMgr->appSpawnQueue) {
367 ListNode *next = node->next;
368 AppSpawningCtx *ctx = ListEntry(node, AppSpawningCtx, node);
369 traversal(g_appSpawnMgr, ctx, data);
370 node = next;
371 }
372 }
373
DumpAppSpawnQueue(ListNode * node,void * data)374 static int DumpAppSpawnQueue(ListNode *node, void *data)
375 {
376 AppSpawningCtx *property = ListEntry(node, AppSpawningCtx, node);
377 APPSPAWN_DUMP("app property id: %{public}u flags: %{public}x",
378 property->client.id, property->client.flags);
379 APPSPAWN_DUMP("app property state: %{public}d", property->state);
380
381 DumpAppSpawnMsg(property->message);
382 return 0;
383 }
384
DumpAppQueue(ListNode * node,void * data)385 static int DumpAppQueue(ListNode *node, void *data)
386 {
387 AppSpawnedProcess *appInfo = ListEntry(node, AppSpawnedProcess, node);
388 uint64_t diff = DiffTime(&appInfo->spawnStart, &appInfo->spawnEnd);
389 APPSPAWN_DUMP("App info uid: %{public}u pid: %{public}x", appInfo->uid, appInfo->pid);
390 APPSPAWN_DUMP("App info name: %{public}s exitStatus: 0x%{public}x spawn time: %{public}" PRIu64 " us ",
391 appInfo->name, appInfo->exitStatus, diff);
392 return 0;
393 }
394
DumpExtData(ListNode * node,void * data)395 static int DumpExtData(ListNode *node, void *data)
396 {
397 AppSpawnExtData *extData = ListEntry(node, AppSpawnExtData, node);
398 if (extData->dumpNode) {
399 extData->dumpNode(extData);
400 }
401 return 0;
402 }
403
ProcessAppSpawnDumpMsg(const AppSpawnMsgNode * message)404 void ProcessAppSpawnDumpMsg(const AppSpawnMsgNode *message)
405 {
406 APPSPAWN_CHECK_ONLY_EXPER(g_appSpawnMgr != NULL && message != NULL, return);
407 FILE *stream = NULL;
408 uint32_t len = 0;
409 char *ptyName = GetAppSpawnMsgExtInfo(message, "pty-name", &len);
410 if (ptyName != NULL) {
411 APPSPAWN_LOGI("Dump info to file '%{public}s'", ptyName);
412 char canonicalPtyPath[PATH_MAX] = { 0 };
413 if (realpath(ptyName, canonicalPtyPath) == NULL) {
414 return;
415 }
416
417 stream = fopen(canonicalPtyPath, "w");
418 SetDumpToStream(stream);
419 } else {
420 SetDumpToStream(stdout);
421 }
422 APPSPAWN_DUMP("Dump appspawn info start ... ");
423 APPSPAWN_DUMP("APP spawning queue: ");
424 OH_ListTraversal((ListNode *)&g_appSpawnMgr->appSpawnQueue, NULL, DumpAppSpawnQueue, 0);
425 APPSPAWN_DUMP("APP queue: ");
426 OH_ListTraversal((ListNode *)&g_appSpawnMgr->appQueue, "App queue", DumpAppQueue, 0);
427 APPSPAWN_DUMP("APP died queue: ");
428 OH_ListTraversal((ListNode *)&g_appSpawnMgr->diedQueue, "App died queue", DumpAppQueue, 0);
429 APPSPAWN_DUMP("Ext data: ");
430 OH_ListTraversal((ListNode *)&g_appSpawnMgr->extData, "Ext data", DumpExtData, 0);
431 APPSPAWN_DUMP("Dump appspawn info finish ");
432 if (stream != NULL) {
433 (void)fflush(stream);
434 fclose(stream);
435 #ifdef APPSPAWN_TEST
436 SetDumpToStream(stdout);
437 #else
438 SetDumpToStream(NULL);
439 #endif
440 }
441 }
442
ProcessTerminationStatusMsg(const AppSpawnMsgNode * message,AppSpawnResult * result)443 int ProcessTerminationStatusMsg(const AppSpawnMsgNode *message, AppSpawnResult *result)
444 {
445 APPSPAWN_CHECK_ONLY_EXPER(g_appSpawnMgr != NULL && message != NULL, return -1);
446 APPSPAWN_CHECK_ONLY_EXPER(result != NULL, return -1);
447 if (!IsNWebSpawnMode(g_appSpawnMgr)) {
448 return APPSPAWN_MSG_INVALID;
449 }
450 result->result = -1;
451 result->pid = 0;
452 pid_t *pid = (pid_t *)GetAppSpawnMsgInfo(message, TLV_RENDER_TERMINATION_INFO);
453 if (pid == NULL) {
454 return -1;
455 }
456 // get render process termination status, only nwebspawn need this logic.
457 result->pid = *pid;
458 result->result = GetProcessTerminationStatus(*pid);
459 return 0;
460 }
461