1 /*
2 * Copyright (c) 2021-2023 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 "appspawn_service.h"
17 #include "appspawn_adapter.h"
18 #include "appspawn_server.h"
19 #include "appspawn_msg.h"
20
21 #include <fcntl.h>
22 #include <stdlib.h>
23 #include <sys/signalfd.h>
24 #include <sys/socket.h>
25 #include <sys/stat.h>
26 #include <sys/wait.h>
27 #include <sys/mount.h>
28 #include <unistd.h>
29 #include <sched.h>
30 #include <linux/limits.h>
31
32 #include "init_hashmap.h"
33 #include "init_socket.h"
34 #include "init_utils.h"
35 #include "parameter.h"
36 #include "securec.h"
37 #include "nwebspawn_lancher.h"
38
39 #ifdef REPORT_EVENT
40 #include "event_reporter.h"
41 #endif
42 #ifndef APPSPAWN_TEST
43 #define TV_SEC 60
44 #define APPSPAWN_EXIT_TIME 60000
45 #else
46 #define TV_SEC 2
47 #define APPSPAWN_EXIT_TIME 500
48 #endif
49 #define DIR_MODE 0711
50 #define USER_ID_SIZE 4
51
52 static AppSpawnContentExt *g_appSpawnContent = NULL;
53 static const uint32_t EXTRAINFO_TOTAL_LENGTH_MAX = 32 * 1024;
54
AppInfoHashNodeCompare(const HashNode * node1,const HashNode * node2)55 static int AppInfoHashNodeCompare(const HashNode *node1, const HashNode *node2)
56 {
57 AppInfo *testNode1 = HASHMAP_ENTRY(node1, AppInfo, node);
58 AppInfo *testNode2 = HASHMAP_ENTRY(node2, AppInfo, node);
59 return testNode1->pid - testNode2->pid;
60 }
61
TestHashKeyCompare(const HashNode * node1,const void * key)62 static int TestHashKeyCompare(const HashNode *node1, const void *key)
63 {
64 AppInfo *testNode1 = HASHMAP_ENTRY(node1, AppInfo, node);
65 return testNode1->pid - *(pid_t *)key;
66 }
67
AppInfoHashNodeFunction(const HashNode * node)68 static int AppInfoHashNodeFunction(const HashNode *node)
69 {
70 AppInfo *testNode = HASHMAP_ENTRY(node, AppInfo, node);
71 return testNode->pid % APP_HASH_BUTT;
72 }
73
AppInfoHashKeyFunction(const void * key)74 static int AppInfoHashKeyFunction(const void *key)
75 {
76 pid_t code = *(pid_t *)key;
77 return code % APP_HASH_BUTT;
78 }
79
AppInfoHashNodeFree(const HashNode * node,void * context)80 static void AppInfoHashNodeFree(const HashNode *node, void *context)
81 {
82 (void)context;
83 AppInfo *testNode = HASHMAP_ENTRY(node, AppInfo, node);
84 APPSPAWN_LOGI("AppInfoHashNodeFree %{public}s\n", testNode->name);
85 free(testNode);
86 }
87
AddAppInfo(pid_t pid,const char * processName)88 APPSPAWN_STATIC void AddAppInfo(pid_t pid, const char *processName)
89 {
90 size_t len = strlen(processName) + 1;
91 AppInfo *node = (AppInfo *)malloc(sizeof(AppInfo) + len + 1);
92 APPSPAWN_CHECK(node != NULL, return, "Failed to malloc for appinfo");
93
94 node->pid = pid;
95 int ret = strcpy_s(node->name, len, processName);
96 APPSPAWN_CHECK(ret == 0, free(node);
97 return, "Failed to strcpy process name");
98 HASHMAPInitNode(&node->node);
99 ret = OH_HashMapAdd(g_appSpawnContent->appMap, &node->node);
100 APPSPAWN_CHECK(ret == 0, free(node);
101 return, "Failed to add appinfo to hash");
102 APPSPAWN_LOGI("Add %{public}s, pid=%{public}d success", processName, pid);
103 }
104
AddNwebInfo(pid_t pid,const char * processName)105 void AddNwebInfo(pid_t pid, const char *processName)
106 {
107 AddAppInfo(pid, processName);
108 }
109
GetAppInfo(pid_t pid)110 static AppInfo *GetAppInfo(pid_t pid)
111 {
112 HashNode *node = OH_HashMapGet(g_appSpawnContent->appMap, (const void *)&pid);
113 APPSPAWN_CHECK_ONLY_EXPER(node != NULL, return NULL);
114 return HASHMAP_ENTRY(node, AppInfo, node);
115 }
116
RemoveAppInfo(pid_t pid)117 static void RemoveAppInfo(pid_t pid)
118 {
119 AppInfo *appInfo = GetAppInfo(pid);
120 APPSPAWN_CHECK(appInfo != NULL, return, "Can not find app info for %{public}d", pid);
121 OH_HashMapRemove(g_appSpawnContent->appMap, (const void *)&pid);
122 free(appInfo);
123 if ((g_appSpawnContent->flags & FLAGS_ON_DEMAND) != FLAGS_ON_DEMAND) {
124 return;
125 }
126 }
127
KillProcess(const HashNode * node,const void * context)128 static void KillProcess(const HashNode *node, const void *context)
129 {
130 AppInfo *hashNode = (AppInfo *)node;
131 kill(hashNode->pid, SIGKILL);
132 APPSPAWN_LOGI("kill app, pid = %{public}d, processName = %{public}s", hashNode->pid, hashNode->name);
133 }
134
OnClose(const TaskHandle taskHandle)135 static void OnClose(const TaskHandle taskHandle)
136 {
137 AppSpawnClientExt *client = (AppSpawnClientExt *)LE_GetUserData(taskHandle);
138 APPSPAWN_CHECK(client != NULL, return, "Invalid client");
139 APPSPAWN_LOGI("OnClose %{public}d processName = %{public}s",
140 client->client.id, client->property.processName);
141 if (client->property.extraInfo.data != NULL) {
142 free(client->property.extraInfo.data);
143 client->property.extraInfo.totalLength = 0;
144 client->property.extraInfo.savedLength = 0;
145 client->property.extraInfo.data = NULL;
146 }
147 }
148
SendMessageComplete(const TaskHandle taskHandle,BufferHandle handle)149 static void SendMessageComplete(const TaskHandle taskHandle, BufferHandle handle)
150 {
151 AppSpawnClientExt *client = (AppSpawnClientExt *)LE_GetUserData(taskHandle);
152 APPSPAWN_CHECK(client != NULL, return, "Failed to get client");
153 APPSPAWN_LOGI("SendMessageComplete client.id %{public}d result %{public}d pid %{public}d",
154 client->client.id, LE_GetSendResult(handle), client->pid);
155 if (LE_GetSendResult(handle) != 0 && client->pid > 0) {
156 kill(client->pid, SIGKILL);
157 APPSPAWN_LOGI("Send message fail err:%{public}d kill app [ %{public}d %{public}s]",
158 LE_GetSendResult(handle), client->pid, client->property.bundleName);
159 }
160 }
161
SendResponse(AppSpawnClientExt * client,const char * buff,size_t buffSize)162 static int SendResponse(AppSpawnClientExt *client, const char *buff, size_t buffSize)
163 {
164 uint32_t bufferSize = buffSize;
165 BufferHandle handle = LE_CreateBuffer(LE_GetDefaultLoop(), bufferSize);
166 char *buffer = (char *)LE_GetBufferInfo(handle, NULL, &bufferSize);
167 int ret = memcpy_s(buffer, bufferSize, buff, buffSize);
168 APPSPAWN_CHECK(ret == 0, return -1, "Failed to memcpy_s bufferSize");
169 return LE_Send(LE_GetDefaultLoop(), client->stream, handle, buffSize);
170 }
171
KillProcessesByCGroup(uid_t uid,const AppInfo * appInfo)172 static void KillProcessesByCGroup(uid_t uid, const AppInfo *appInfo)
173 {
174 if (appInfo == NULL) {
175 return;
176 }
177
178 int userId = uid / 200000;
179 char buf[PATH_MAX];
180
181 snprintf_s(buf, sizeof(buf), sizeof(buf) - 1, "/dev/memcg/%d/%s/cgroup.procs", userId, appInfo->name);
182 FILE *file = fopen(buf, "r");
183 APPSPAWN_CHECK(file != NULL, return, "%{public}s not exists.", buf);
184 pid_t pid;
185 while (fscanf_s(file, "%d\n", &pid) == 1 && pid > 0) {
186 // If it is the app process itself, no need to kill again
187 if (pid == appInfo->pid) {
188 continue;
189 }
190
191 // If it is another process spawned by appspawn with the same package name, just ignore
192 AppInfo *newApp = GetAppInfo(pid);
193 if (newApp != NULL) {
194 APPSPAWN_LOGI("Got app %{public}s in same group for pid %{public}d.", newApp->name, pid);
195 continue;
196 }
197 APPSPAWN_LOGI("Kill app pid %{public}d now ...", pid);
198 kill(pid, SIGKILL);
199 }
200 fclose(file);
201 }
202
203
204 #ifndef APPSPAWN_TEST
IsUnlockStatus(uint32_t uid)205 static bool IsUnlockStatus(uint32_t uid)
206 {
207 const int userIdBase = 200000;
208 uid = uid / userIdBase;
209 if (uid == 0) {
210 return true;
211 }
212
213 char userId[USER_ID_SIZE] = {0};
214 size_t len = sprintf_s(userId, USER_ID_SIZE, "%u", uid);
215 APPSPAWN_CHECK(len > 0 && (len < USER_ID_SIZE), return true, "Failed to get userId");
216
217 const char rootPath[] = "/data/app/el2/";
218 const char basePath[] = "/base";
219 size_t allPathSize = strlen(rootPath) + strlen(basePath) + strlen(userId) + 1;
220 char *path = malloc(sizeof(char) * allPathSize);
221 APPSPAWN_CHECK(path != NULL, return true, "Failed to malloc path");
222 len = sprintf_s(path, allPathSize, "%s%s%s", rootPath, userId, basePath);
223 APPSPAWN_CHECK(len > 0 && (len < allPathSize), return true, "Failed to get base path");
224
225 if (access(path, F_OK) == 0) {
226 APPSPAWN_LOGI("this is unlock status");
227 free(path);
228 return true;
229 }
230 free(path);
231 APPSPAWN_LOGI("this is lock status");
232 return false;
233 }
234
MakeDirRec(const char * path)235 void MakeDirRec(const char *path)
236 {
237 if (path == NULL || *path == '\0') {
238 return;
239 }
240
241 char buffer[PATH_MAX] = {0};
242 const char slash = '/';
243 const char *p = path;
244 char *curPos = strchr(path, slash);
245 while (curPos != NULL) {
246 int len = curPos - p;
247 p = curPos + 1;
248 if (len == 0) {
249 curPos = strchr(p, slash);
250 continue;
251 }
252 if (len < 0) {
253 break;
254 }
255 APPSPAWN_CHECK(memcpy_s(buffer, PATH_MAX, path, p - path - 1) == 0,
256 return, "memcpy failed");
257 if (mkdir(buffer, DIR_MODE) == -1 && errno != EEXIST) {
258 return;
259 }
260 curPos = strchr(p, slash);
261 }
262 if (mkdir(path, DIR_MODE) == -1 && errno != EEXIST) {
263 return;
264 }
265 return;
266 }
267
MountAppEl2Dir(const AppSpawnClient * client)268 static void MountAppEl2Dir(const AppSpawnClient* client)
269 {
270 const int userIdBase = 200000;
271 const char rootPath[] = "/mnt/sandbox/";
272 const char el2Path[] = "/data/storage/el2";
273 AppParameter *appProperty = &((AppSpawnClientExt *)client)->property;
274 if (IsUnlockStatus(appProperty->uid)) {
275 return;
276 }
277
278 char userId[USER_ID_SIZE] = {0};
279 size_t len = sprintf_s(userId, USER_ID_SIZE, "%u", appProperty->uid / userIdBase);
280 APPSPAWN_CHECK(len > 0 && (len < USER_ID_SIZE), return, "Failed to get userId");
281 size_t allPathSize = strlen(rootPath) + strlen(el2Path) + strlen(appProperty->bundleName) + strlen(userId) + 2;
282 char *path = malloc(sizeof(char) * (allPathSize));
283 APPSPAWN_CHECK(path != NULL, return, "Failed to malloc path");
284 len = sprintf_s(path, allPathSize, "%s%s/%s%s", rootPath, userId,
285 appProperty->bundleName, el2Path);
286 APPSPAWN_CHECK(len > 0 && (len < allPathSize), free(path);
287 return, "Failed to get el2 path");
288
289 if (access(path, F_OK) == 0) {
290 free(path);
291 return;
292 }
293
294 MakeDirRec(path);
295 if (mount(path, path, NULL, MS_BIND | MS_REC, NULL) != 0) {
296 free(path);
297 APPSPAWN_LOGI("mount el2 path failed!");
298 return;
299 }
300 if (mount(NULL, path, NULL, MS_SHARED, NULL) != 0) {
301 free(path);
302 APPSPAWN_LOGI("mount el2 path to shared failed!");
303 return;
304 }
305 APPSPAWN_LOGI("mount el2 path to shared success!");
306 free(path);
307 return;
308 }
309 #endif
310
HandleDiedPid(pid_t pid,uid_t uid,int status)311 static void HandleDiedPid(pid_t pid, uid_t uid, int status)
312 {
313 AppInfo *appInfo = GetAppInfo(pid);
314 KillProcessesByCGroup(uid, appInfo);
315 APPSPAWN_CHECK(appInfo != NULL, return, "Can not find app info for %{public}d", pid);
316 if (WIFSIGNALED(status)) {
317 APPSPAWN_LOGW("%{public}s with pid %{public}d exit with signal:%{public}d",
318 appInfo->name, pid, WTERMSIG(status));
319 }
320 if (WIFEXITED(status)) {
321 APPSPAWN_LOGW("%{public}s with pid %{public}d exit with code:%{public}d",
322 appInfo->name, pid, WEXITSTATUS(status));
323 }
324
325 #ifdef REPORT_EVENT
326 ReportProcessExitInfo(appInfo->name, pid, uid, status);
327 #endif
328
329 // delete app info
330 RemoveAppInfo(pid);
331
332 // if current process of death is nwebspawn, restart appspawn
333 if (pid == g_nwebspawnpid) {
334 APPSPAWN_LOGW("Current process of death is nwebspawn, pid = %{public}d, restart appspawn", pid);
335 OH_HashMapTraverse(g_appSpawnContent->appMap, KillProcess, NULL);
336 LE_StopLoop(LE_GetDefaultLoop());
337 }
338 }
339
HandleDiedPidNweb(pid_t pid,uid_t uid,int status)340 static void HandleDiedPidNweb(pid_t pid, uid_t uid, int status)
341 {
342 AppInfo *appInfo = GetAppInfo(pid);
343 APPSPAWN_CHECK(appInfo != NULL, return, "Can not find app info for %{public}d", pid);
344 if (WIFSIGNALED(status)) {
345 APPSPAWN_LOGW("%{public}s with pid %{public}d exit with signal:%{public}d",
346 appInfo->name, pid, WTERMSIG(status));
347 }
348 if (WIFEXITED(status)) {
349 APPSPAWN_LOGW("%{public}s with pid %{public}d exit with code:%{public}d",
350 appInfo->name, pid, WEXITSTATUS(status));
351 }
352
353 #ifdef REPORT_EVENT
354 ReportProcessExitInfo(appInfo->name, pid, uid, status);
355 #endif
356
357 // nwebspawn will invoke waitpid and remove appinfo at GetProcessTerminationStatusInner when
358 // GetProcessTerminationStatusInner is called before the parent process receives the SIGCHLD signal.
359 RecordRenderProcessExitedStatus(pid, status);
360
361 // delete app info
362 RemoveAppInfo(pid);
363 }
364
SignalHandler(const struct signalfd_siginfo * siginfo)365 APPSPAWN_STATIC void SignalHandler(const struct signalfd_siginfo *siginfo)
366 {
367 APPSPAWN_LOGI("SignalHandler signum %{public}d", siginfo->ssi_signo);
368 switch (siginfo->ssi_signo) {
369 case SIGCHLD: { // delete pid from app map
370 pid_t pid;
371 int status;
372 while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
373 HandleDiedPid(pid, siginfo->ssi_uid, status);
374 }
375 break;
376 }
377 case SIGTERM: { // appswapn killed, use kill without parameter
378 OH_HashMapTraverse(g_appSpawnContent->appMap, KillProcess, NULL);
379 LE_StopLoop(LE_GetDefaultLoop());
380 break;
381 }
382 default:
383 APPSPAWN_LOGI("SigHandler, unsupported signal %{public}d.", siginfo->ssi_signo);
384 break;
385 }
386 }
387
SignalHandlerNweb(const struct signalfd_siginfo * siginfo)388 APPSPAWN_STATIC void SignalHandlerNweb(const struct signalfd_siginfo *siginfo)
389 {
390 APPSPAWN_LOGI("SignalHandler signum %{public}d", siginfo->ssi_signo);
391 switch (siginfo->ssi_signo) {
392 case SIGCHLD: { // delete pid from app map
393 pid_t pid;
394 int status;
395 while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
396 HandleDiedPidNweb(pid, siginfo->ssi_uid, status);
397 }
398 break;
399 }
400 case SIGTERM: { // appswapn killed, use kill without parameter
401 OH_HashMapTraverse(g_appSpawnContent->appMap, KillProcess, NULL);
402 LE_StopLoop(LE_GetDefaultLoop());
403 break;
404 }
405 default:
406 APPSPAWN_LOGI("SigHandler, unsupported signal %{public}d.", siginfo->ssi_signo);
407 break;
408 }
409 }
410
HandleSpecial(AppSpawnClientExt * appProperty)411 static void HandleSpecial(AppSpawnClientExt *appProperty)
412 {
413 // special handle bundle name medialibrary and scanner
414 const char *specialBundleNames[] = {
415 "com.ohos.medialibrary.medialibrarydata", "com.ohos.medialibrary.medialibrarydata:backup"
416 };
417
418 for (size_t i = 0; i < sizeof(specialBundleNames) / sizeof(specialBundleNames[0]); i++) {
419 if (strcmp(appProperty->property.bundleName, specialBundleNames[i]) == 0) {
420 if (appProperty->property.gidCount < APP_MAX_GIDS) {
421 appProperty->property.gidTable[appProperty->property.gidCount++] = GID_USER_DATA_RW;
422 appProperty->property.gidTable[appProperty->property.gidCount++] = GID_FILE_ACCESS;
423 }
424 break;
425 }
426 }
427 }
428
WaitChild(int fd,int pid,const AppSpawnClientExt * appProperty)429 static int WaitChild(int fd, int pid, const AppSpawnClientExt *appProperty)
430 {
431 int result = 0;
432 fd_set rd;
433 struct timeval tv;
434 FD_ZERO(&rd);
435 FD_SET(fd, &rd);
436 tv.tv_sec = TV_SEC;
437 tv.tv_usec = 0;
438
439 int ret = select(fd + 1, &rd, NULL, NULL, &tv);
440 if (ret == 0) { // timeout
441 APPSPAWN_LOGI("Time out for child %{public}s %{public}d fd %{public}d",
442 appProperty->property.processName, pid, fd);
443 result = 0;
444 } else if (ret == -1) {
445 APPSPAWN_LOGI("Error for child %{public}s %{public}d", appProperty->property.processName, pid);
446 result = 0;
447 } else {
448 (void)read(fd, &result, sizeof(result));
449 }
450
451 return result;
452 }
453
CheckColdAppEnabled(AppSpawnClientExt * appProperty)454 static void CheckColdAppEnabled(AppSpawnClientExt *appProperty)
455 {
456 if ((appProperty->property.flags & 0x01) != 0) {
457 char cold[10] = {0}; // 10 cold
458 (void)GetParameter("startup.appspawn.cold.boot", "0", cold, sizeof(cold));
459 APPSPAWN_LOGV("appspawn.cold.boot %{public}s", cold);
460 if (strcmp(cold, "1") == 0) {
461 appProperty->client.flags |= APP_COLD_START;
462 }
463 }
464 }
465
ReceiveRequestDataToExtraInfo(const TaskHandle taskHandle,AppSpawnClientExt * client,const uint8_t * buffer,uint32_t buffLen)466 static bool ReceiveRequestDataToExtraInfo(const TaskHandle taskHandle, AppSpawnClientExt *client,
467 const uint8_t *buffer, uint32_t buffLen)
468 {
469 if (client->property.extraInfo.totalLength) {
470 ExtraInfo *extraInfo = &client->property.extraInfo;
471 if (extraInfo->savedLength == 0) {
472 extraInfo->data = (char *)malloc(extraInfo->totalLength);
473 APPSPAWN_CHECK(extraInfo->data != NULL, LE_CloseTask(LE_GetDefaultLoop(), taskHandle);
474 return false, "ReceiveRequestData: malloc extraInfo failed %{public}u", extraInfo->totalLength);
475 }
476
477 uint32_t saved = extraInfo->savedLength;
478 uint32_t total = extraInfo->totalLength;
479 char *data = extraInfo->data;
480
481 APPSPAWN_LOGI("Receiving extraInfo: (%{public}u saved + %{public}u incoming) / %{public}u total",
482 saved, buffLen, total);
483
484 APPSPAWN_CHECK((total - saved) >= buffLen, LE_CloseTask(LE_GetDefaultLoop(), taskHandle);
485 return false, "ReceiveRequestData: too many data for extraInfo %{public}u ", buffLen);
486
487 int ret = memcpy_s(data + saved, buffLen, buffer, buffLen);
488 APPSPAWN_CHECK(ret == 0, LE_CloseTask(LE_GetDefaultLoop(), taskHandle);
489 return false, "ReceiveRequestData: memcpy extraInfo failed");
490
491 extraInfo->savedLength += buffLen;
492 if (extraInfo->savedLength < extraInfo->totalLength) {
493 return false;
494 }
495 extraInfo->data[extraInfo->totalLength - 1] = 0;
496 return true;
497 }
498 return true;
499 }
500
CheckRequestMsgValid(AppSpawnClientExt * client)501 static int CheckRequestMsgValid(AppSpawnClientExt *client)
502 {
503 if (client->property.extraInfo.totalLength >= EXTRAINFO_TOTAL_LENGTH_MAX) {
504 APPSPAWN_LOGE("extrainfo total length invalid,len: %{public}d", client->property.extraInfo.totalLength);
505 return -1;
506 }
507 for (int i = 0; i < APP_LEN_PROC_NAME; i++) {
508 if (client->property.processName[i] == '\0') {
509 return 0;
510 }
511 }
512
513 APPSPAWN_LOGE("processname invalid");
514 return -1;
515 }
516
ReceiveRequestData(const TaskHandle taskHandle,AppSpawnClientExt * client,const uint8_t * buffer,uint32_t buffLen)517 APPSPAWN_STATIC bool ReceiveRequestData(const TaskHandle taskHandle, AppSpawnClientExt *client,
518 const uint8_t *buffer, uint32_t buffLen)
519 {
520 APPSPAWN_CHECK(buffer != NULL && buffLen > 0, LE_CloseTask(LE_GetDefaultLoop(), taskHandle);
521 return false, "ReceiveRequestData: Invalid buff, bufferLen:%{public}d", buffLen);
522
523 // 1. receive AppParamter
524 if (client->property.extraInfo.totalLength == 0) {
525 APPSPAWN_CHECK(buffLen >= sizeof(client->property), LE_CloseTask(LE_GetDefaultLoop(), taskHandle);
526 return false, "ReceiveRequestData: Invalid buffLen %{public}u", buffLen);
527
528 int ret = memcpy_s(&client->property, sizeof(client->property), buffer, sizeof(client->property));
529 APPSPAWN_CHECK(ret == 0, LE_CloseTask(LE_GetDefaultLoop(), taskHandle);
530 return false, "ReceiveRequestData: memcpy failed %{public}d:%{public}u", ret, buffLen);
531
532 // reset extraInfo
533 client->property.extraInfo.savedLength = 0;
534 client->property.extraInfo.data = NULL;
535
536 // update buffer
537 buffer += sizeof(client->property);
538 buffLen -= sizeof(client->property);
539 ret = CheckRequestMsgValid(client);
540 APPSPAWN_CHECK(ret == 0, LE_CloseTask(LE_GetDefaultLoop(), taskHandle);
541 return false, "Invalid request msg");
542 }
543
544 // 2. check whether extraInfo exist
545 if (client->property.extraInfo.totalLength == 0) { // no extraInfo
546 APPSPAWN_LOGV("ReceiveRequestData: no extraInfo");
547 return true;
548 } else if (buffLen == 0) {
549 APPSPAWN_LOGV("ReceiveRequestData: waiting for extraInfo");
550 return false;
551 }
552 return ReceiveRequestDataToExtraInfo(taskHandle, client, buffer, buffLen);
553 }
554
HandleMessage(AppSpawnClientExt * appProperty)555 static int HandleMessage(AppSpawnClientExt *appProperty)
556 {
557 // create pipe
558 if (pipe(appProperty->fd) == -1) {
559 APPSPAWN_LOGE("create pipe fail, errno = %{public}d", errno);
560 return -1;
561 }
562 fcntl(appProperty->fd[0], F_SETFL, O_NONBLOCK);
563 /* Clone support only one parameter, so need to package application parameters */
564 AppSandboxArg sandboxArg = { 0 };
565 sandboxArg.content = &g_appSpawnContent->content;
566 sandboxArg.client = &appProperty->client;
567 sandboxArg.client->cloneFlags = sandboxArg.content->sandboxNsFlags;
568
569 SHOW_CLIENT("Receive client message ", appProperty);
570 #ifndef APPSPAWN_TEST
571 // mount el2 dir
572 MountAppEl2Dir(sandboxArg.client);
573 #endif
574 int result = AppSpawnProcessMsg(&sandboxArg, &appProperty->pid);
575 if (result == 0) { // wait child process result
576 result = WaitChild(appProperty->fd[0], appProperty->pid, appProperty);
577 }
578 close(appProperty->fd[0]);
579 close(appProperty->fd[1]);
580 APPSPAWN_LOGI("child process %{public}s %{public}s pid %{public}d",
581 appProperty->property.processName, (result == 0) ? "success" : "fail", appProperty->pid);
582 if (result == 0) {
583 AddAppInfo(appProperty->pid, appProperty->property.processName);
584 SendResponse(appProperty, (char *)&appProperty->pid, sizeof(appProperty->pid));
585 } else {
586 SendResponse(appProperty, (char *)&result, sizeof(result));
587 }
588 return 0;
589 }
590
OnReceiveRequest(const TaskHandle taskHandle,const uint8_t * buffer,uint32_t buffLen)591 static void OnReceiveRequest(const TaskHandle taskHandle, const uint8_t *buffer, uint32_t buffLen)
592 {
593 AppSpawnClientExt *appProperty = (AppSpawnClientExt *)LE_GetUserData(taskHandle);
594 APPSPAWN_CHECK(appProperty != NULL, LE_CloseTask(LE_GetDefaultLoop(), taskHandle);
595 return, "alloc client Failed");
596
597 if (!ReceiveRequestData(taskHandle, appProperty, buffer, buffLen)) {
598 return;
599 }
600
601 if (g_appSpawnContent->content.isNweb) {
602 // get render process termination status, only nwebspawn need this logic.
603 if (appProperty->property.code == GET_RENDER_TERMINATION_STATUS) {
604 int ret = GetProcessTerminationStatus(&appProperty->client);
605 RemoveAppInfo(appProperty->property.pid);
606 SendResponse(appProperty, (char *)&ret, sizeof(ret));
607 return;
608 }
609 }
610 APPSPAWN_CHECK(appProperty->property.gidCount <= APP_MAX_GIDS && strlen(appProperty->property.processName) > 0,
611 LE_CloseTask(LE_GetDefaultLoop(), taskHandle);
612 return, "Invalid property %{public}u", appProperty->property.gidCount);
613
614 // special handle bundle name medialibrary and scanner
615 HandleSpecial(appProperty);
616 if (g_appSpawnContent->timer != NULL) {
617 LE_StopTimer(LE_GetDefaultLoop(), g_appSpawnContent->timer);
618 g_appSpawnContent->timer = NULL;
619 }
620 appProperty->pid = 0;
621 CheckColdAppEnabled(appProperty);
622 int ret = HandleMessage(appProperty);
623 if (ret != 0) {
624 LE_CloseTask(LE_GetDefaultLoop(), taskHandle);
625 }
626 }
627
AcceptClient(const LoopHandle loopHandle,const TaskHandle server,uint32_t flags)628 APPSPAWN_STATIC TaskHandle AcceptClient(const LoopHandle loopHandle, const TaskHandle server, uint32_t flags)
629 {
630 static uint32_t clientId = 0;
631 TaskHandle stream;
632 LE_StreamInfo info = {};
633 info.baseInfo.flags = TASK_STREAM | TASK_PIPE | TASK_CONNECT;
634 info.baseInfo.flags |= flags;
635 info.baseInfo.close = OnClose;
636 info.baseInfo.userDataSize = sizeof(AppSpawnClientExt);
637 info.disConnectComplete = NULL;
638 info.sendMessageComplete = SendMessageComplete;
639 info.recvMessage = OnReceiveRequest;
640
641 LE_STATUS ret = LE_AcceptStreamClient(loopHandle, server, &stream, &info);
642 APPSPAWN_CHECK(ret == 0, return NULL, "Failed to alloc stream");
643 AppSpawnClientExt *client = (AppSpawnClientExt *)LE_GetUserData(stream);
644 APPSPAWN_CHECK(client != NULL, return NULL, "Failed to alloc stream");
645 struct ucred cred = {-1, -1, -1};
646 socklen_t credSize = sizeof(struct ucred);
647 if ((getsockopt(LE_GetSocketFd(stream), SOL_SOCKET, SO_PEERCRED, &cred, &credSize) < 0) ||
648 (cred.uid != DecodeUid("foundation") && cred.uid != DecodeUid("root"))) {
649 APPSPAWN_LOGE("Failed to check uid %{public}d", cred.uid);
650 LE_CloseStreamTask(LE_GetDefaultLoop(), stream);
651 return NULL;
652 }
653
654 client->stream = stream;
655 client->client.id = ++clientId;
656 client->client.flags = 0;
657 client->property.extraInfo.totalLength = 0;
658 client->property.extraInfo.savedLength = 0;
659 client->property.extraInfo.data = NULL;
660 APPSPAWN_LOGI("OnConnection client fd %{public}d Id %{public}d", LE_GetSocketFd(stream), client->client.id);
661 return stream;
662 }
663
OnConnection(const LoopHandle loopHandle,const TaskHandle server)664 static int OnConnection(const LoopHandle loopHandle, const TaskHandle server)
665 {
666 APPSPAWN_CHECK(server != NULL && loopHandle != NULL, return -1, "Error server");
667 (void)AcceptClient(loopHandle, server, 0);
668 return 0;
669 }
670
NotifyResToParent(struct AppSpawnContent_ * content,AppSpawnClient * client,int result)671 static void NotifyResToParent(struct AppSpawnContent_ *content, AppSpawnClient *client, int result)
672 {
673 AppSpawnClientExt *appProperty = (AppSpawnClientExt *)client;
674 int fd = appProperty->fd[1];
675 APPSPAWN_LOGI("NotifyResToParent %{public}s fd %{public}d result %{public}d",
676 appProperty->property.processName, fd, result);
677 write(appProperty->fd[1], &result, sizeof(result));
678 // close write
679 close(fd);
680 }
681
AppSpawnInit(AppSpawnContent * content)682 static int AppSpawnInit(AppSpawnContent *content)
683 {
684 AppSpawnContentExt *appSpawnContent = (AppSpawnContentExt *)content;
685 APPSPAWN_CHECK(appSpawnContent != NULL, return -1, "Invalid appspawn content");
686
687 APPSPAWN_LOGI("AppSpawnInit");
688 if (content->loadExtendLib) {
689 content->loadExtendLib(content);
690 }
691
692 content->notifyResToParent = NotifyResToParent;
693 // set private function
694 SetContentFunction(content);
695
696 // set uid gid filetr
697 if (content->setUidGidFilter) {
698 content->setUidGidFilter(content);
699 }
700
701 // load app sandbox config
702 LoadAppSandboxConfig(content);
703
704 // enable pid namespace
705 if (content->enablePidNs) {
706 return content->enablePidNs(content);
707 }
708 return 0;
709 }
710
AppSpawnColdRun(AppSpawnContent * content,int argc,char * const argv[])711 void AppSpawnColdRun(AppSpawnContent *content, int argc, char *const argv[])
712 {
713 AppSpawnContentExt *appSpawnContent = (AppSpawnContentExt *)content;
714 APPSPAWN_CHECK(appSpawnContent != NULL, return, "Invalid appspawn content");
715
716 AppSpawnClientExt *client = (AppSpawnClientExt *)malloc(sizeof(AppSpawnClientExt));
717 APPSPAWN_CHECK(client != NULL, return, "Failed to alloc memory for client");
718 (void)memset_s(client, sizeof(AppSpawnClientExt), 0, sizeof(AppSpawnClientExt));
719 int ret = GetAppSpawnClientFromArg(argc, argv, client);
720 APPSPAWN_CHECK(ret == 0, free(client);
721 return, "Failed to get client from arg");
722 client->client.flags &= ~ APP_COLD_START;
723 SHOW_CLIENT("Cold running", client);
724 ret = DoStartApp(content, &client->client, content->longProcName, content->longProcNameLen);
725 if (ret == 0 && content->runChildProcessor != NULL) {
726 content->runChildProcessor(content, &client->client);
727 }
728
729 APPSPAWN_LOGI("App exit %{public}d.", getpid());
730 free(client);
731 free(appSpawnContent);
732 g_appSpawnContent = NULL;
733 }
734
AppSpawnRun(AppSpawnContent * content,int argc,char * const argv[])735 static void AppSpawnRun(AppSpawnContent *content, int argc, char *const argv[])
736 {
737 APPSPAWN_LOGI("AppSpawnRun");
738 AppSpawnContentExt *appSpawnContent = (AppSpawnContentExt *)content;
739 APPSPAWN_CHECK(appSpawnContent != NULL, return, "Invalid appspawn content");
740
741 LE_STATUS status;
742
743 if (content->isNweb) {
744 status = LE_CreateSignalTask(LE_GetDefaultLoop(), &appSpawnContent->sigHandler, SignalHandlerNweb);
745 } else {
746 status = LE_CreateSignalTask(LE_GetDefaultLoop(), &appSpawnContent->sigHandler, SignalHandler);
747 }
748
749 if (status == 0) {
750 (void)LE_AddSignal(LE_GetDefaultLoop(), appSpawnContent->sigHandler, SIGCHLD);
751 (void)LE_AddSignal(LE_GetDefaultLoop(), appSpawnContent->sigHandler, SIGTERM);
752 }
753
754 LE_RunLoop(LE_GetDefaultLoop());
755 APPSPAWN_LOGI("AppSpawnRun exit ");
756 if (appSpawnContent->timer != NULL) {
757 LE_StopTimer(LE_GetDefaultLoop(), appSpawnContent->timer);
758 appSpawnContent->timer = NULL;
759 }
760 LE_CloseSignalTask(LE_GetDefaultLoop(), appSpawnContent->sigHandler);
761 // release resource
762 OH_HashMapDestory(appSpawnContent->appMap, NULL);
763 LE_CloseStreamTask(LE_GetDefaultLoop(), appSpawnContent->server);
764 LE_CloseLoop(LE_GetDefaultLoop());
765 free(content);
766 g_appSpawnContent = NULL;
767 }
768
CreateHashForApp(AppSpawnContentExt * appSpawnContent)769 static int CreateHashForApp(AppSpawnContentExt *appSpawnContent)
770 {
771 HashInfo hashInfo = {
772 AppInfoHashNodeCompare,
773 TestHashKeyCompare,
774 AppInfoHashNodeFunction,
775 AppInfoHashKeyFunction,
776 AppInfoHashNodeFree,
777 APP_HASH_BUTT
778 };
779 int ret = OH_HashMapCreate(&appSpawnContent->appMap, &hashInfo);
780 APPSPAWN_CHECK(ret == 0, free(appSpawnContent); return -1, "Failed to create hash for app");
781 return 0;
782 }
783
CreateAppSpawnServer(AppSpawnContentExt * appSpawnContent,const char * socketName)784 static int CreateAppSpawnServer(AppSpawnContentExt *appSpawnContent, const char *socketName)
785 {
786 char path[128] = {0}; // 128 max path
787 int ret = snprintf_s(path, sizeof(path), sizeof(path) - 1, "%s%s", SOCKET_DIR, socketName);
788 APPSPAWN_CHECK(ret >= 0, return -1, "Failed to snprintf_s %{public}d", ret);
789 int socketId = GetControlSocket(socketName);
790 APPSPAWN_LOGI("get socket form env %{public}s socketId %{public}d", socketName, socketId);
791 APPSPAWN_CHECK_ONLY_EXPER(socketId <= 0, appSpawnContent->flags |= FLAGS_ON_DEMAND);
792
793 LE_StreamServerInfo info = {};
794 info.baseInfo.flags = TASK_STREAM | TASK_PIPE | TASK_SERVER;
795 info.socketId = socketId;
796 info.server = path;
797 info.baseInfo.close = NULL;
798 info.incommingConnect = OnConnection;
799
800 ret = LE_CreateStreamServer(LE_GetDefaultLoop(), &appSpawnContent->server, &info);
801 APPSPAWN_CHECK(ret == 0, return -1, "Failed to create socket for %{public}s", path);
802 // create socket
803
804 APPSPAWN_CHECK(ret == 0, return -1, "Failed to lchown %{public}s, err %{public}d. ", path, errno);
805 APPSPAWN_LOGI("CreateAppSpawnServer path %{public}s fd %{public}d",
806 path, LE_GetSocketFd(appSpawnContent->server));
807 return 0;
808 }
809
AppSpawnCreateContent(const char * socketName,char * longProcName,uint32_t longProcNameLen,int mode)810 AppSpawnContent *AppSpawnCreateContent(const char *socketName, char *longProcName, uint32_t longProcNameLen, int mode)
811 {
812 APPSPAWN_CHECK(LE_GetDefaultLoop() != NULL, return NULL, "Invalid default loop");
813 APPSPAWN_CHECK(socketName != NULL && longProcName != NULL, return NULL, "Invalid name");
814 APPSPAWN_LOGI("AppSpawnCreateContent %{public}s %{public}u mode %{public}d", socketName, longProcNameLen, mode);
815
816 AppSpawnContentExt *appSpawnContent = (AppSpawnContentExt *)malloc(sizeof(AppSpawnContentExt));
817 APPSPAWN_CHECK(appSpawnContent != NULL, return NULL, "Failed to alloc memory for appspawn");
818 (void)memset_s(&appSpawnContent->content, sizeof(appSpawnContent->content), 0, sizeof(appSpawnContent->content));
819 appSpawnContent->content.longProcName = longProcName;
820 appSpawnContent->content.longProcNameLen = longProcNameLen;
821 if (strcmp(longProcName, NWEBSPAWN_SERVER_NAME) == 0) {
822 appSpawnContent->content.isNweb = true;
823 } else {
824 appSpawnContent->content.isNweb = false;
825 }
826 appSpawnContent->timer = NULL;
827 appSpawnContent->flags = 0;
828 appSpawnContent->server = NULL;
829 appSpawnContent->sigHandler = NULL;
830 appSpawnContent->content.initAppSpawn = AppSpawnInit;
831
832 if (mode) {
833 appSpawnContent->flags |= FLAGS_MODE_COLD;
834 appSpawnContent->content.runAppSpawn = AppSpawnColdRun;
835 } else {
836 appSpawnContent->content.runAppSpawn = AppSpawnRun;
837
838 // create hash for app
839 int ret = CreateHashForApp(appSpawnContent);
840 APPSPAWN_CHECK(ret == 0, free(appSpawnContent); return NULL, "Failed to create app");
841 ret = CreateAppSpawnServer(appSpawnContent, socketName);
842 APPSPAWN_CHECK(ret == 0, free(appSpawnContent); return NULL, "Failed to create server");
843 }
844 g_appSpawnContent = appSpawnContent;
845 return &g_appSpawnContent->content;
846 }
847