• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021-2022 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 
20 #include <fcntl.h>
21 #include <sys/signalfd.h>
22 #include <sys/socket.h>
23 #include <sys/stat.h>
24 #include <sys/wait.h>
25 #include <unistd.h>
26 #include <sched.h>
27 
28 #include "init_hashmap.h"
29 #include "init_socket.h"
30 #include "init_utils.h"
31 #include "parameter.h"
32 #include "securec.h"
33 
34 #ifdef REPORT_EVENT
35 #include "event_reporter.h"
36 #endif
37 
38 static AppSpawnContentExt *g_appSpawnContent = NULL;
39 
40 #ifdef APPSPAWN_TEST
41 static const int TV_SEC = 1;
42 #else
43 static const int TV_SEC = 60;
44 #endif
45 
AppInfoHashNodeCompare(const HashNode * node1,const HashNode * node2)46 static int AppInfoHashNodeCompare(const HashNode *node1, const HashNode *node2)
47 {
48     AppInfo *testNode1 = HASHMAP_ENTRY(node1, AppInfo, node);
49     AppInfo *testNode2 = HASHMAP_ENTRY(node2, AppInfo, node);
50     return testNode1->pid - testNode2->pid;
51 }
52 
TestHashKeyCompare(const HashNode * node1,const void * key)53 static int TestHashKeyCompare(const HashNode *node1, const void *key)
54 {
55     AppInfo *testNode1 = HASHMAP_ENTRY(node1, AppInfo, node);
56     return testNode1->pid - *(pid_t *)key;
57 }
58 
AppInfoHashNodeFunction(const HashNode * node)59 static int AppInfoHashNodeFunction(const HashNode *node)
60 {
61     AppInfo *testNode = HASHMAP_ENTRY(node, AppInfo, node);
62     if (testNode == NULL) {
63         return -1;
64     }
65     return testNode->pid % APP_HASH_BUTT;
66 }
67 
AppInfoHashKeyFunction(const void * key)68 static int AppInfoHashKeyFunction(const void *key)
69 {
70     pid_t code = *(pid_t *)key;
71     return code % APP_HASH_BUTT;
72 }
73 
AppInfoHashNodeFree(const HashNode * node)74 static void AppInfoHashNodeFree(const HashNode *node)
75 {
76     AppInfo *testNode = HASHMAP_ENTRY(node, AppInfo, node);
77     APPSPAWN_LOGI("AppInfoHashNodeFree %s\n", testNode->name);
78     free(testNode);
79 }
80 
AddAppInfo(pid_t pid,const char * processName)81 APPSPAWN_STATIC void AddAppInfo(pid_t pid, const char *processName)
82 {
83     size_t len = strlen(processName) + 1;
84     AppInfo *node = (AppInfo *)malloc(sizeof(AppInfo) + len + 1);
85     APPSPAWN_CHECK(node != NULL, return, "Failed to malloc for appinfo");
86 
87     node->pid = pid;
88     int ret = strcpy_s(node->name, len, processName);
89     APPSPAWN_CHECK(ret == 0, free(node);
90         return, "Failed to strcpy process name");
91     HASHMAPInitNode(&node->node);
92     ret = OH_HashMapAdd(g_appSpawnContent->appMap, &node->node);
93     APPSPAWN_CHECK(ret == 0, free(node);
94         return, "Failed to add appinfo to hash");
95     APPSPAWN_LOGI("Add %s, pid=%d success", processName, pid);
96 }
97 
ProcessTimer(const TimerHandle taskHandle,void * context)98 APPSPAWN_STATIC void ProcessTimer(const TimerHandle taskHandle, void *context)
99 {
100     UNUSED(context);
101     APPSPAWN_LOGI("timeout stop appspawn");
102     LE_StopLoop(LE_GetDefaultLoop());
103 }
104 
RemoveAppInfo(pid_t pid)105 static void RemoveAppInfo(pid_t pid)
106 {
107     HashNode *node = OH_HashMapGet(g_appSpawnContent->appMap, (const void *)&pid);
108     APPSPAWN_CHECK(node != NULL, return, "Invalid node %d", pid);
109     AppInfo *appInfo = HASHMAP_ENTRY(node, AppInfo, node);
110     APPSPAWN_CHECK(appInfo != NULL, return, "Invalid node %d", pid);
111     OH_HashMapRemove(g_appSpawnContent->appMap, (const void *)&pid);
112     free(appInfo);
113     if ((g_appSpawnContent->flags & FLAGS_ON_DEMAND) != FLAGS_ON_DEMAND) {
114         return;
115     }
116 
117     if (g_appSpawnContent->timer == NULL && OH_HashMapIsEmpty(g_appSpawnContent->appMap) != 0) {
118         APPSPAWN_LOGI("Start time for appspawn");
119         int ret = LE_CreateTimer(LE_GetDefaultLoop(), &g_appSpawnContent->timer, ProcessTimer, NULL);
120         APPSPAWN_CHECK(ret == 0, return, "Failed to create time");
121         LE_StartTimer(LE_GetDefaultLoop(), g_appSpawnContent->timer, 60000, 1);  // 60000 60s
122     }
123 }
124 
KillProcess(const HashNode * node,const void * context)125 static void KillProcess(const HashNode *node, const void *context)
126 {
127     AppInfo *hashNode = (AppInfo *)node;
128     kill(hashNode->pid, SIGKILL);
129     APPSPAWN_LOGI("kill app, pid = %d, processName = %s", hashNode->pid, hashNode->name);
130 }
131 
OnClose(const TaskHandle taskHandle)132 static void OnClose(const TaskHandle taskHandle)
133 {
134     AppSpawnClientExt *client = (AppSpawnClientExt *)LE_GetUserData(taskHandle);
135     APPSPAWN_CHECK(client != NULL, return, "Failed to get client");
136 }
137 
SendMessageComplete(const TaskHandle taskHandle,BufferHandle handle)138 APPSPAWN_STATIC void SendMessageComplete(const TaskHandle taskHandle, BufferHandle handle)
139 {
140     AppSpawnClientExt *client = (AppSpawnClientExt *)LE_GetUserData(taskHandle);
141     APPSPAWN_CHECK(client != NULL, return, "Failed to get client");
142     APPSPAWN_LOGI("SendMessageComplete client.id %d result %d pid %d",
143         client->client.id, LE_GetSendResult(handle), client->pid);
144     if (LE_GetSendResult(handle) != 0 && client->pid > 0) {
145         kill(client->pid, SIGKILL);
146         APPSPAWN_LOGI("Send message fail err:%d kill app [ %d %s]",
147             LE_GetSendResult(handle), client->pid, client->property.bundleName);
148     }
149 }
150 
SendResponse(AppSpawnClientExt * client,const char * buff,size_t buffSize)151 static int SendResponse(AppSpawnClientExt *client, const char *buff, size_t buffSize)
152 {
153     APPSPAWN_CHECK(buff != NULL, return -1, "Invalid content buff");
154     uint32_t bufferSize = buffSize;
155     BufferHandle handle = LE_CreateBuffer(LE_GetDefaultLoop(), bufferSize);
156     char *buffer = (char *)LE_GetBufferInfo(handle, NULL, &bufferSize);
157     int ret = memcpy_s(buffer, bufferSize, buff, buffSize);
158     APPSPAWN_CHECK(ret == 0, return -1, "Failed to memcpy_s bufferSize");
159     return LE_Send(LE_GetDefaultLoop(), client->stream, handle, buffSize);
160 }
161 
162 #ifdef REPORT_EVENT
PrintProcessExitInfo(pid_t pid,uid_t uid,int status)163 static void PrintProcessExitInfo(pid_t pid, uid_t uid, int status)
164 {
165     HashNode *node = OH_HashMapGet(g_appSpawnContent->appMap, (const void *)&pid);
166     APPSPAWN_CHECK(node != NULL, return, "Handle SIGCHLD from pid:%d status:%d", pid, status);
167     AppInfo *appInfo = HASHMAP_ENTRY(node, AppInfo, node);
168     APPSPAWN_CHECK(appInfo != NULL, return, "Handle SIGCHLD from pid:%d status:%d", pid, status);
169 
170     if (WIFSIGNALED(status)) {
171         APPSPAWN_LOGW("%s with pid %d exit with signal:%d", appInfo->name, pid, WTERMSIG(status));
172     }
173     if (WIFEXITED(status)) {
174         APPSPAWN_LOGW("%s with pid %d exit with code:%d", appInfo->name, pid, WEXITSTATUS(status));
175     }
176 
177     ReportProcessExitInfo(appInfo->name, pid, uid, status);
178 }
179 #endif
180 
HandleDiedPid(pid_t pid,uid_t uid,int status)181 static void HandleDiedPid(pid_t pid, uid_t uid, int status)
182 {
183     APPSPAWN_LOGI("SignalHandler pid %d status %d", pid, status);
184 #ifdef REPORT_EVENT
185     PrintProcessExitInfo(pid, uid, status);
186 #endif
187 #ifdef NWEB_SPAWN
188     // nwebspawn will invoke waitpid and remove appinfo at GetProcessTerminationStatusInner when
189     // GetProcessTerminationStatusInner is called before the parent process receives the SIGCHLD signal.
190     RecordRenderProcessExitedStatus(pid, status);
191 #endif
192     RemoveAppInfo(pid);
193 }
194 
SignalHandler(const struct signalfd_siginfo * siginfo)195 APPSPAWN_STATIC void SignalHandler(const struct signalfd_siginfo *siginfo)
196 {
197     APPSPAWN_LOGI("SignalHandler signum %d", siginfo->ssi_signo);
198     switch (siginfo->ssi_signo) {
199         case SIGCHLD: {  // delete pid from app map
200 #ifndef APPSPAWN_TEST
201             pid_t pid;
202             int status;
203             while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
204                 HandleDiedPid(pid, siginfo->ssi_uid, status);
205             }
206 #else
207             HandleDiedPid(siginfo->ssi_pid, siginfo->ssi_uid, 0);
208 #endif
209             break;
210         }
211         case SIGTERM: {  // appswapn killed, use kill without parameter
212             OH_HashMapTraverse(g_appSpawnContent->appMap, KillProcess, NULL);
213 #ifndef APPSPAWN_TEST
214             LE_StopLoop(LE_GetDefaultLoop());
215 #endif
216             break;
217         }
218         default:
219             APPSPAWN_LOGI("SigHandler, unsupported signal %d.", siginfo->ssi_signo);
220             break;
221     }
222 }
223 
HandleSpecial(AppSpawnClientExt * appProperty)224 static void HandleSpecial(AppSpawnClientExt *appProperty)
225 {
226     const char *fileExtensionHapBundleName = "com.ohos.UserFile.ExternalFileManager";
227     if (strcmp(appProperty->property.bundleName, fileExtensionHapBundleName) == 0) {
228         if (appProperty->property.gidCount < APP_MAX_GIDS) {
229             appProperty->property.gidTable[appProperty->property.gidCount] = GID_FILE_ACCESS;
230             appProperty->property.gidCount++;
231         }
232     }
233 
234     // special handle bundle name medialibrary and scanner
235     const char *specialBundleNames[] = {
236         "com.ohos.medialibrary.medialibrarydata"
237     };
238 
239     for (size_t i = 0; i < sizeof(specialBundleNames) / sizeof(specialBundleNames[0]); i++) {
240         if (strcmp(appProperty->property.bundleName, specialBundleNames[i]) == 0) {
241             if (appProperty->property.gidCount < APP_MAX_GIDS) {
242                 appProperty->property.gidTable[appProperty->property.gidCount] = GID_USER_DATA_RW;
243                 appProperty->property.gidCount++;
244             } else {
245                 APPSPAWN_LOGE("gidCount out of bounds !");
246             }
247             break;
248         }
249     }
250 }
251 
WaitChild(int fd,int pid,const AppSpawnClientExt * appProperty)252 static int WaitChild(int fd, int pid, const AppSpawnClientExt *appProperty)
253 {
254     int result = 0;
255     fd_set rd;
256     struct timeval tv;
257     FD_ZERO(&rd);
258     FD_SET(fd, &rd);
259     tv.tv_sec = TV_SEC;
260     tv.tv_usec = 0;
261 
262     int ret = select(fd + 1, &rd, NULL, NULL, &tv);
263     if (ret == 0) {  // timeout
264         APPSPAWN_LOGI("Time out for child %s %d fd %d", appProperty->property.processName, pid, fd);
265         result = 0;
266     } else if (ret == -1) {
267         APPSPAWN_LOGI("Error for child %s %d", appProperty->property.processName, pid);
268         result = 0;
269     } else {
270         (void)read(fd, &result, sizeof(result));
271     }
272 
273     return result;
274 }
275 
CheckColdAppEnabled(AppSpawnClientExt * appProperty)276 static void CheckColdAppEnabled(AppSpawnClientExt *appProperty)
277 {
278     if (appProperty == NULL) {
279         return;
280     }
281 
282     if ((appProperty->property.flags & 0x01) != 0) {
283         char cold[10] = {0};  // 10 cold
284         int ret = GetParameter("startup.appspawn.cold.boot", "0", cold, sizeof(cold));
285         APPSPAWN_LOGV("appspawn.cold.boot %s %d ", cold, ret);
286         if (ret > 0 && strcmp(cold, "1") == 0) {
287             appProperty->client.flags |= APP_COLD_START;
288         }
289     }
290 }
291 
292 #ifdef NWEB_SPAWN
GetProcessTerminationStatusInner(int32_t pid,int * status)293 static int GetProcessTerminationStatusInner(int32_t pid, int *status)
294 {
295     if (status == NULL) {
296         return -1;
297     }
298 
299     if (GetRenderProcessTerminationStatus(pid, status) == 0) {
300         // this shows that the parent process has received SIGCHLD signal.
301         return 0;
302     }
303 
304     if (kill(pid, SIGKILL) != 0) {
305         APPSPAWN_LOGE("unable to kill render process, pid: %d", pid);
306     }
307 
308     pid_t exitPid = waitpid(pid, status, WNOHANG);
309     if (exitPid != pid) {
310         APPSPAWN_LOGE("waitpid failed, return : %d, pid: %d, status: %d", exitPid, pid, *status);
311         return -1;
312     }
313 
314     RemoveAppInfo(pid);
315     return 0;
316 }
317 
GetProcessTerminationStatus(AppSpawnClientExt * appProperty)318 static void GetProcessTerminationStatus(AppSpawnClientExt *appProperty)
319 {
320     int exitStatus = 0;
321     int ret = GetProcessTerminationStatusInner(appProperty->property.pid, &exitStatus);
322     if (ret) {
323         SendResponse(appProperty, (char *)&ret, sizeof(ret));
324     } else {
325         SendResponse(appProperty, (char *)&exitStatus, sizeof(exitStatus));
326     }
327     APPSPAWN_LOGI("AppSpawnServer::get render process termination status, status = %d pid = %d uid %d %s %s",
328         exitStatus, appProperty->property.pid, appProperty->property.uid,
329         appProperty->property.processName, appProperty->property.bundleName);
330 }
331 #endif
332 
SetInternetPermission(AppSpawnClientExt * appProperty)333 APPSPAWN_STATIC void SetInternetPermission(AppSpawnClientExt *appProperty)
334 {
335 #ifndef APPSPAWN_TEST
336     if (appProperty->property.setAllowInternet == 1 && appProperty->property.allowInternet == 0) {
337         appProperty->client.setAllowInternet = 1;
338         appProperty->client.allowInternet = 0;
339     }
340 #endif
341 }
342 
OnReceiveRequest(const TaskHandle taskHandle,const uint8_t * buffer,uint32_t buffLen)343 APPSPAWN_STATIC void OnReceiveRequest(const TaskHandle taskHandle, const uint8_t *buffer, uint32_t buffLen)
344 {
345     APPSPAWN_CHECK(buffer != NULL && buffLen >= sizeof(AppParameter), LE_CloseTask(LE_GetDefaultLoop(), taskHandle);
346         return, "Invalid buffLen %u", buffLen);
347     AppSpawnClientExt *appProperty = (AppSpawnClientExt *)LE_GetUserData(taskHandle);
348     APPSPAWN_CHECK(appProperty != NULL, LE_CloseTask(LE_GetDefaultLoop(), taskHandle);
349         return, "alloc client Failed");
350 
351     int ret = memcpy_s(&appProperty->property, sizeof(appProperty->property), buffer, buffLen);
352     APPSPAWN_CHECK(ret == 0, LE_CloseTask(LE_GetDefaultLoop(), taskHandle); return, "Invalid buffLen %u", buffLen);
353 
354 #ifdef NWEB_SPAWN
355     // get render process termination status, only nwebspawn need this logic.
356     if (appProperty->property.code == GET_RENDER_TERMINATION_STATUS) {
357         GetProcessTerminationStatus(appProperty);
358         return;
359     }
360 #endif
361 
362     APPSPAWN_CHECK(appProperty->property.gidCount <= APP_MAX_GIDS && strlen(appProperty->property.processName) > 0,
363         LE_CloseTask(LE_GetDefaultLoop(), taskHandle);
364         return, "Invalid property %u", appProperty->property.gidCount);
365     // special handle bundle name medialibrary and scanner
366     HandleSpecial(appProperty);
367     SetInternetPermission(appProperty);
368     if (g_appSpawnContent->timer != NULL) {
369         LE_StopTimer(LE_GetDefaultLoop(), g_appSpawnContent->timer);
370         g_appSpawnContent->timer = NULL;
371     }
372     appProperty->pid = 0;
373     CheckColdAppEnabled(appProperty);
374     // create pipe for commication from child
375     if (pipe(appProperty->fd) == -1) {
376         APPSPAWN_LOGE("create pipe fail, errno = %d", errno);
377         LE_CloseTask(LE_GetDefaultLoop(), taskHandle);
378         return;
379     }
380 
381     APPSPAWN_LOGI("OnReceiveRequest client.id %d appProperty %d processname %s buffLen %d flags 0x%x",
382         appProperty->client.id, appProperty->property.uid, appProperty->property.processName,
383         buffLen, appProperty->property.flags);
384     fcntl(appProperty->fd[0], F_SETFL, O_NONBLOCK);
385 
386     /* Clone support only one parameter, so need to package application parameters */
387     AppSandboxArg *sandboxArg = (AppSandboxArg *)malloc(sizeof(AppSandboxArg));
388     if (sandboxArg == NULL) {
389         close(appProperty->fd[0]);
390         close(appProperty->fd[1]);
391         LE_CloseTask(LE_GetDefaultLoop(), taskHandle);
392         return;
393     }
394     (void)memset_s(sandboxArg, sizeof(AppSandboxArg), 0, sizeof(AppSandboxArg));
395 
396     sandboxArg->content = &g_appSpawnContent->content;
397     sandboxArg->client = &appProperty->client;
398     sandboxArg->client->cloneFlags = 0;
399     sandboxArg->client->cloneFlags = GetAppNamespaceFlags(appProperty->property.bundleName);
400     int result = AppSpawnProcessMsg(sandboxArg, &appProperty->pid);
401     if (result == 0) {  // wait child process result
402         result = WaitChild(appProperty->fd[0], appProperty->pid, appProperty);
403     }
404     close(appProperty->fd[0]);
405     close(appProperty->fd[1]);
406     free(sandboxArg);
407     APPSPAWN_LOGI("child process %s %s pid %d",
408         appProperty->property.processName, (result == 0) ? "success" : "fail", appProperty->pid);
409     if (result == 0) {
410         AddAppInfo(appProperty->pid, appProperty->property.processName);
411         SendResponse(appProperty, (char *)&appProperty->pid, sizeof(appProperty->pid));
412     } else {
413         SendResponse(appProperty, (char *)&result, sizeof(result));
414     }
415 }
416 
417 #ifdef APPSPAWN_TEST
418 TaskHandle g_testClientHandle = NULL;
GetTestClientHandle()419 TaskHandle GetTestClientHandle()
420 {
421     return g_testClientHandle;
422 }
423 #endif
OnConnection(const LoopHandle loopHandle,const TaskHandle server)424 APPSPAWN_STATIC int OnConnection(const LoopHandle loopHandle, const TaskHandle server)
425 {
426     static uint32_t clientId = 0;
427     APPSPAWN_CHECK(server != NULL, return -1, "Error server");
428 
429     TaskHandle stream;
430     LE_StreamInfo info = {};
431     info.baseInfo.flags = TASK_STREAM | TASK_PIPE | TASK_CONNECT;
432 #ifdef APPSPAWN_TEST
433     info.baseInfo.flags |= TASK_TEST;
434 #endif
435     info.baseInfo.close = OnClose;
436     info.baseInfo.userDataSize = sizeof(AppSpawnClientExt);
437     info.disConnectComplete = NULL;
438     info.sendMessageComplete = SendMessageComplete;
439     info.recvMessage = OnReceiveRequest;
440 
441     LE_STATUS ret = LE_AcceptStreamClient(LE_GetDefaultLoop(), server, &stream, &info);
442     APPSPAWN_CHECK(ret == 0, return -1, "Failed to alloc stream");
443     AppSpawnClientExt *client = (AppSpawnClientExt *)LE_GetUserData(stream);
444     APPSPAWN_CHECK(client != NULL, return -1, "Failed to alloc stream");
445 #ifndef APPSPAWN_CHECK_GID_UID
446 #ifndef APPSPAWN_TEST
447     struct ucred cred = {-1, -1, -1};
448     socklen_t credSize  = sizeof(struct ucred);
449     if (getsockopt(LE_GetSocketFd(stream), SOL_SOCKET, SO_PEERCRED, &cred, &credSize) < 0) {
450         APPSPAWN_LOGE("get cred failed!");
451         LE_CloseStreamTask(LE_GetDefaultLoop(), stream);
452         return -1;
453     }
454 
455     if (cred.uid != DecodeUid("foundation")  && cred.uid != DecodeUid("root")) {
456         APPSPAWN_LOGE("OnConnection client fd %d is nerverallow!", LE_GetSocketFd(stream));
457         LE_CloseStreamTask(LE_GetDefaultLoop(), stream);
458         return -1;
459     }
460 #endif
461 #endif
462 
463     client->stream = stream;
464     client->client.id = ++clientId;
465     client->client.flags = 0;
466 #ifndef APPSPAWN_TEST
467     client->client.setAllowInternet = 0;
468     client->client.allowInternet = 1;
469 #endif
470     APPSPAWN_LOGI("OnConnection client fd %d Id %d", LE_GetSocketFd(stream), client->client.id);
471 #ifdef APPSPAWN_TEST
472     g_testClientHandle = stream;
473 #endif
474     return 0;
475 }
476 
NotifyResToParent(struct AppSpawnContent_ * content,AppSpawnClient * client,int result)477 static void NotifyResToParent(struct AppSpawnContent_ *content, AppSpawnClient *client, int result)
478 {
479     AppSpawnClientExt *appProperty = (AppSpawnClientExt *)client;
480     int fd = appProperty->fd[1];
481     APPSPAWN_LOGI("NotifyResToParent %s fd %d result %d", appProperty->property.processName, fd, result);
482     write(appProperty->fd[1], &result, sizeof(result));
483     // close write
484     close(fd);
485 }
486 
AppSpawnInit(AppSpawnContent * content)487 static void AppSpawnInit(AppSpawnContent *content)
488 {
489     AppSpawnContentExt *appSpawnContent = (AppSpawnContentExt *)content;
490     APPSPAWN_CHECK(appSpawnContent != NULL, return, "Invalid appspawn content");
491 
492     APPSPAWN_LOGI("AppSpawnInit");
493     if (content->loadExtendLib) {
494         content->loadExtendLib(content);
495     }
496 
497     content->notifyResToParent = NotifyResToParent;
498     // set private function
499     SetContentFunction(content);
500 
501     // set uid gid filetr
502     if (content->setUidGidFilter) {
503         content->setUidGidFilter(content);
504     }
505 
506     // load app sandbox config
507     LoadAppSandboxConfig();
508 }
509 
AppSpawnColdRun(AppSpawnContent * content,int argc,char * const argv[])510 void AppSpawnColdRun(AppSpawnContent *content, int argc, char *const argv[])
511 {
512     AppSpawnContentExt *appSpawnContent = (AppSpawnContentExt *)content;
513     APPSPAWN_CHECK(appSpawnContent != NULL, return, "Invalid appspawn content");
514 
515     AppSpawnClientExt *client = (AppSpawnClientExt *)malloc(sizeof(AppSpawnClientExt));
516     APPSPAWN_CHECK(client != NULL, return, "Failed to alloc memory for client");
517     (void)memset_s(client, sizeof(AppSpawnClientExt), 0, sizeof(AppSpawnClientExt));
518     int ret = GetAppSpawnClientFromArg(argc, argv, client);
519     APPSPAWN_CHECK(ret == 0, free(client);
520         return, "Failed to get client from arg");
521     APPSPAWN_LOGI("Cold running %d processName %s %u ", getpid(), client->property.processName,
522         content->longProcNameLen);
523 
524     ret = DoStartApp(content, &client->client, content->longProcName, content->longProcNameLen);
525     if (ret == 0 && content->runChildProcessor != NULL) {
526         content->runChildProcessor(content, &client->client);
527     }
528 
529     APPSPAWN_LOGI("App exit %d.", getpid());
530     free(client);
531     free(appSpawnContent);
532     g_appSpawnContent = NULL;
533 }
534 
AppSpawnRun(AppSpawnContent * content,int argc,char * const argv[])535 static void AppSpawnRun(AppSpawnContent *content, int argc, char *const argv[])
536 {
537     APPSPAWN_LOGI("AppSpawnRun");
538     AppSpawnContentExt *appSpawnContent = (AppSpawnContentExt *)content;
539     APPSPAWN_CHECK(appSpawnContent != NULL, return, "Invalid appspawn content");
540 
541     LE_STATUS status = LE_CreateSignalTask(LE_GetDefaultLoop(), &appSpawnContent->sigHandler, SignalHandler);
542     if (status == 0) {
543         (void)LE_AddSignal(LE_GetDefaultLoop(), appSpawnContent->sigHandler, SIGCHLD);
544         status = LE_AddSignal(LE_GetDefaultLoop(), appSpawnContent->sigHandler, SIGTERM);
545     }
546     if (status != 0) {
547         APPSPAWN_LOGE("Failed to add signal %d", status);
548     }
549 #ifndef APPSPAWN_TEST
550     LE_RunLoop(LE_GetDefaultLoop());
551 #endif
552     APPSPAWN_LOGI("AppSpawnRun exit ");
553     LE_CloseSignalTask(LE_GetDefaultLoop(), appSpawnContent->sigHandler);
554     // release resource
555     OH_HashMapDestory(appSpawnContent->appMap);
556     LE_CloseSignalTask(LE_GetDefaultLoop(), appSpawnContent->server);
557     LE_CloseLoop(LE_GetDefaultLoop());
558     free(content);
559     g_appSpawnContent = NULL;
560 #ifndef APPSPAWN_TEST
561     quick_exit(0);
562 #endif
563 }
564 
CreateHashForApp(AppSpawnContentExt * appSpawnContent)565 static int CreateHashForApp(AppSpawnContentExt *appSpawnContent)
566 {
567     HashInfo hashInfo = {
568         AppInfoHashNodeCompare,
569         TestHashKeyCompare,
570         AppInfoHashNodeFunction,
571         AppInfoHashKeyFunction,
572         AppInfoHashNodeFree,
573         APP_HASH_BUTT
574     };
575     int ret = OH_HashMapCreate(&appSpawnContent->appMap, &hashInfo);
576     APPSPAWN_CHECK(ret == 0, free(appSpawnContent); return -1, "Failed to create hash for app");
577     return 0;
578 }
579 
AppSpawnCreateContent(const char * socketName,char * longProcName,uint32_t longProcNameLen,int mode)580 AppSpawnContent *AppSpawnCreateContent(const char *socketName, char *longProcName, uint32_t longProcNameLen, int mode)
581 {
582     APPSPAWN_CHECK(LE_GetDefaultLoop() != NULL, return NULL, "Invalid default loop");
583     APPSPAWN_CHECK(socketName != NULL && longProcName != NULL, return NULL, "Invalid name");
584     APPSPAWN_LOGI("AppSpawnCreateContent %s %u mode %d", socketName, longProcNameLen, mode);
585 
586     AppSpawnContentExt *appSpawnContent = (AppSpawnContentExt *)malloc(sizeof(AppSpawnContentExt));
587     APPSPAWN_CHECK(appSpawnContent != NULL, return NULL, "Failed to alloc memory for appspawn");
588     (void)memset_s(&appSpawnContent->content, sizeof(appSpawnContent->content), 0, sizeof(appSpawnContent->content));
589     appSpawnContent->content.longProcName = longProcName;
590     appSpawnContent->content.longProcNameLen = longProcNameLen;
591     appSpawnContent->timer = NULL;
592     appSpawnContent->flags = 0;
593     appSpawnContent->server = NULL;
594     appSpawnContent->sigHandler = NULL;
595     appSpawnContent->content.initAppSpawn = AppSpawnInit;
596 
597     if (mode) {
598         appSpawnContent->flags |= FLAGS_MODE_COLD;
599         appSpawnContent->content.runAppSpawn = AppSpawnColdRun;
600     } else {
601         appSpawnContent->content.runAppSpawn = AppSpawnRun;
602 
603         // create hash for app
604         APPSPAWN_CHECK(CreateHashForApp(appSpawnContent) == 0, return NULL, "Failed to create hash for app");
605 
606         char path[128] = {0};  // 128 max path
607         int ret = snprintf_s(path, sizeof(path), sizeof(path) - 1, "%s%s", SOCKET_DIR, socketName);
608         APPSPAWN_CHECK(ret >= 0, free(appSpawnContent); return NULL, "Failed to snprintf_s %d", ret);
609         int socketId = GetControlSocket(socketName);
610         APPSPAWN_LOGI("get socket form env %s socketId %d", socketName, socketId);
611         APPSPAWN_CHECK_ONLY_EXPER(socketId <= 0, appSpawnContent->flags |= FLAGS_ON_DEMAND);
612 
613         LE_StreamServerInfo info = {};
614         info.baseInfo.flags = TASK_STREAM | TASK_PIPE | TASK_SERVER;
615         info.socketId = socketId;
616         info.server = path;
617         info.baseInfo.close = NULL;
618         info.incommingConnect = OnConnection;
619 
620         ret = LE_CreateStreamServer(LE_GetDefaultLoop(), &appSpawnContent->server, &info);
621         APPSPAWN_CHECK(ret == 0, free(appSpawnContent); return NULL, "Failed to create socket for %s", path);
622         // create socket
623         ret = chmod(path, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
624         APPSPAWN_CHECK(ret == 0, free(appSpawnContent); return NULL, "Failed to chmod %s, err %d. ", path, errno);
625 #ifndef APPSPAWN_CHECK_GID_UID
626         ret = lchown(path, 0, 4000); // 4000 is appspawn gid
627         APPSPAWN_CHECK(ret == 0, free(appSpawnContent); return NULL, "Failed to lchown %s, err %d. ", path, errno);
628 #endif
629         APPSPAWN_LOGI("AppSpawnCreateContent path %s fd %d", path, LE_GetSocketFd(appSpawnContent->server));
630     }
631     g_appSpawnContent = appSpawnContent;
632     return &g_appSpawnContent->content;
633 }
634