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 kill(pid, SIGKILL);
211 APPSPAWN_LOGI("Dump stack finished");
212 }
213
KillAndWaitStatus(pid_t pid,int sig,int * exitStatus)214 int KillAndWaitStatus(pid_t pid, int sig, int *exitStatus)
215 {
216 APPSPAWN_CHECK_ONLY_EXPER(exitStatus != NULL, return 0);
217 *exitStatus = -1;
218 if (pid <= 0) {
219 return 0;
220 }
221
222 if (kill(pid, sig) != 0) {
223 APPSPAWN_LOGE("unable to kill process, pid: %{public}d ret %{public}d", pid, errno);
224 return -1;
225 }
226
227 int retry = 0;
228 pid_t exitPid = 0;
229 while (retry * SLEEP_DURATION < EXIT_APP_TIMEOUT) {
230 exitPid = waitpid(pid, exitStatus, WNOHANG);
231 if (exitPid == pid) {
232 return 0;
233 }
234 usleep(SLEEP_DURATION);
235 retry++;
236 }
237
238 DumpProcessSpawnStack(pid);
239 APPSPAWN_LOGE("waitpid failed, pid: %{public}d %{public}d, status: %{public}d", exitPid, pid, *exitStatus);
240
241 return -1;
242 }
243
GetProcessTerminationStatus(pid_t pid)244 static int GetProcessTerminationStatus(pid_t pid)
245 {
246 APPSPAWN_CHECK_ONLY_EXPER(g_appSpawnMgr != NULL, return -1);
247 APPSPAWN_LOGV("GetProcessTerminationStatus pid: %{public}d ", pid);
248 if (pid <= 0) {
249 return 0;
250 }
251 int exitStatus = 0;
252 ListNode *node = OH_ListFind(&g_appSpawnMgr->diedQueue, &pid, AppInfoPidComparePro);
253 if (node != NULL) {
254 AppSpawnedProcess *info = ListEntry(node, AppSpawnedProcess, node);
255 exitStatus = info->exitStatus;
256 OH_ListRemove(node);
257 OH_ListInit(node);
258 free(info);
259 if (g_appSpawnMgr->diedAppCount > 0) {
260 g_appSpawnMgr->diedAppCount--;
261 }
262 return exitStatus;
263 }
264 AppSpawnedProcess *app = GetSpawnedProcess(pid);
265 if (app == NULL) {
266 APPSPAWN_LOGE("unable to get process, pid: %{public}d ", pid);
267 return -1;
268 }
269
270 if (KillAndWaitStatus(pid, SIGKILL, &exitStatus) == 0) { // kill success, delete app
271 OH_ListRemove(&app->node);
272 OH_ListInit(&app->node);
273 free(app);
274 }
275 return exitStatus;
276 }
277
CreateAppSpawningCtx(void)278 AppSpawningCtx *CreateAppSpawningCtx(void)
279 {
280 static uint32_t requestId = 0;
281 AppSpawningCtx *property = (AppSpawningCtx *)malloc(sizeof(AppSpawningCtx));
282 APPSPAWN_CHECK(property != NULL, return NULL, "Failed to create AppSpawningCtx ");
283 property->client.id = ++requestId;
284 property->client.flags = 0;
285 property->forkCtx.watcherHandle = NULL;
286 property->forkCtx.pidFdWatcherHandle = NULL;
287 property->forkCtx.coldRunPath = NULL;
288 property->forkCtx.timer = NULL;
289 property->forkCtx.fd[0] = -1;
290 property->forkCtx.fd[1] = -1;
291 property->isPrefork = false;
292 property->forkCtx.childMsg = NULL;
293 property->message = NULL;
294 property->pid = 0;
295 property->state = APP_STATE_IDLE;
296 OH_ListInit(&property->node);
297 if (g_appSpawnMgr) {
298 OH_ListAddTail(&g_appSpawnMgr->appSpawnQueue, &property->node);
299 }
300 return property;
301 }
302
DeleteAppSpawningCtx(AppSpawningCtx * property)303 void DeleteAppSpawningCtx(AppSpawningCtx *property)
304 {
305 APPSPAWN_CHECK_ONLY_EXPER(property != NULL, return);
306 APPSPAWN_LOGV("DeleteAppSpawningCtx");
307
308 DeleteAppSpawnMsg(property->message);
309
310 OH_ListRemove(&property->node);
311 if (property->forkCtx.timer) {
312 LE_StopTimer(LE_GetDefaultLoop(), property->forkCtx.timer);
313 property->forkCtx.timer = NULL;
314 }
315 if (property->forkCtx.watcherHandle) {
316 LE_RemoveWatcher(LE_GetDefaultLoop(), property->forkCtx.watcherHandle);
317 property->forkCtx.watcherHandle = NULL;
318 }
319 if (property->forkCtx.coldRunPath) {
320 free(property->forkCtx.coldRunPath);
321 property->forkCtx.coldRunPath = NULL;
322 }
323 if (property->forkCtx.fd[0] >= 0) {
324 close(property->forkCtx.fd[0]);
325 }
326 if (property->forkCtx.fd[1] >= 0) {
327 close(property->forkCtx.fd[1]);
328 }
329
330 free(property);
331 }
332
AppPropertyComparePid(ListNode * node,void * data)333 static int AppPropertyComparePid(ListNode *node, void *data)
334 {
335 AppSpawningCtx *property = ListEntry(node, AppSpawningCtx, node);
336 if (property->pid == *(pid_t *)data) {
337 return 0;
338 }
339 return 1;
340 }
341
GetAppSpawningCtxByPid(pid_t pid)342 AppSpawningCtx *GetAppSpawningCtxByPid(pid_t pid)
343 {
344 APPSPAWN_CHECK_ONLY_EXPER(g_appSpawnMgr != NULL, return NULL);
345 ListNode *node = OH_ListFind(&g_appSpawnMgr->appSpawnQueue, (void *)&pid, AppPropertyComparePid);
346 APPSPAWN_CHECK_ONLY_EXPER(node != NULL, return NULL);
347 return ListEntry(node, AppSpawningCtx, node);
348 }
349
AppSpawningCtxTraversal(ProcessTraversal traversal,void * data)350 void AppSpawningCtxTraversal(ProcessTraversal traversal, void *data)
351 {
352 APPSPAWN_CHECK_ONLY_EXPER(g_appSpawnMgr != NULL && traversal != NULL, return);
353 ListNode *node = g_appSpawnMgr->appSpawnQueue.next;
354 while (node != &g_appSpawnMgr->appSpawnQueue) {
355 ListNode *next = node->next;
356 AppSpawningCtx *ctx = ListEntry(node, AppSpawningCtx, node);
357 traversal(g_appSpawnMgr, ctx, data);
358 node = next;
359 }
360 }
361
DumpAppSpawnQueue(ListNode * node,void * data)362 static int DumpAppSpawnQueue(ListNode *node, void *data)
363 {
364 AppSpawningCtx *property = ListEntry(node, AppSpawningCtx, node);
365 APPSPAPWN_DUMP("app property id: %{public}u flags: %{public}x",
366 property->client.id, property->client.flags);
367 APPSPAPWN_DUMP("app property state: %{public}d", property->state);
368
369 DumpAppSpawnMsg(property->message);
370 return 0;
371 }
372
DumpAppQueue(ListNode * node,void * data)373 static int DumpAppQueue(ListNode *node, void *data)
374 {
375 AppSpawnedProcess *appInfo = ListEntry(node, AppSpawnedProcess, node);
376 uint64_t diff = DiffTime(&appInfo->spawnStart, &appInfo->spawnEnd);
377 APPSPAPWN_DUMP("App info uid: %{public}u pid: %{public}x", appInfo->uid, appInfo->pid);
378 APPSPAPWN_DUMP("App info name: %{public}s exitStatus: 0x%{public}x spawn time: %{public}" PRIu64 " us ",
379 appInfo->name, appInfo->exitStatus, diff);
380 return 0;
381 }
382
DumpExtData(ListNode * node,void * data)383 static int DumpExtData(ListNode *node, void *data)
384 {
385 AppSpawnExtData *extData = ListEntry(node, AppSpawnExtData, node);
386 if (extData->dumpNode) {
387 extData->dumpNode(extData);
388 }
389 return 0;
390 }
391
ProcessAppSpawnDumpMsg(const AppSpawnMsgNode * message)392 void ProcessAppSpawnDumpMsg(const AppSpawnMsgNode *message)
393 {
394 APPSPAWN_CHECK_ONLY_EXPER(g_appSpawnMgr != NULL && message != NULL, return);
395 FILE *stream = NULL;
396 uint32_t len = 0;
397 char *ptyName = GetAppSpawnMsgExtInfo(message, "pty-name", &len);
398 if (ptyName != NULL) {
399 APPSPAWN_LOGI("Dump info to file '%{public}s'", ptyName);
400 char canonicalPtyPath[PATH_MAX] = { 0 };
401 if (realpath(ptyName, canonicalPtyPath) == NULL) {
402 return;
403 }
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