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