169570cc8Sopenharmony_ci/* 269570cc8Sopenharmony_ci * Copyright (c) 20214 Huawei Device Co., Ltd. 369570cc8Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License"); 469570cc8Sopenharmony_ci * you may not use this file except in compliance with the License. 569570cc8Sopenharmony_ci * You may obtain a copy of the License at 669570cc8Sopenharmony_ci * 769570cc8Sopenharmony_ci * http://www.apache.org/licenses/LICENSE-2.0 869570cc8Sopenharmony_ci * 969570cc8Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software 1069570cc8Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS, 1169570cc8Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1269570cc8Sopenharmony_ci * See the License for the specific language governing permissions and 1369570cc8Sopenharmony_ci * limitations under the License. 1469570cc8Sopenharmony_ci */ 1569570cc8Sopenharmony_ci 1669570cc8Sopenharmony_ci#include "appspawn_server.h" 1769570cc8Sopenharmony_ci 1869570cc8Sopenharmony_ci#undef _GNU_SOURCE 1969570cc8Sopenharmony_ci#define _GNU_SOURCE 2069570cc8Sopenharmony_ci#include <sched.h> 2169570cc8Sopenharmony_ci#include <signal.h> 2269570cc8Sopenharmony_ci#include <time.h> 2369570cc8Sopenharmony_ci 2469570cc8Sopenharmony_ci#include "appspawn_trace.h" 2569570cc8Sopenharmony_ci#include "appspawn_utils.h" 2669570cc8Sopenharmony_ci#ifndef OHOS_LITE 2769570cc8Sopenharmony_ci#include "appspawn_manager.h" 2869570cc8Sopenharmony_ci#endif 2969570cc8Sopenharmony_ci 3069570cc8Sopenharmony_ci#define MAX_FORK_TIME (30 * 1000) // 30ms 3169570cc8Sopenharmony_ci 3269570cc8Sopenharmony_cistatic void NotifyResToParent(struct AppSpawnContent *content, AppSpawnClient *client, int result) 3369570cc8Sopenharmony_ci{ 3469570cc8Sopenharmony_ci APPSPAWN_LOGI("NotifyResToParent: %{public}d", result); 3569570cc8Sopenharmony_ci if (content->notifyResToParent != NULL) { 3669570cc8Sopenharmony_ci content->notifyResToParent(content, client, result); 3769570cc8Sopenharmony_ci } 3869570cc8Sopenharmony_ci} 3969570cc8Sopenharmony_ci 4069570cc8Sopenharmony_civoid ProcessExit(int code) 4169570cc8Sopenharmony_ci{ 4269570cc8Sopenharmony_ci APPSPAWN_LOGI("App exit code: %{public}d", code); 4369570cc8Sopenharmony_ci#ifdef OHOS_LITE 4469570cc8Sopenharmony_ci _exit(0x7f); // 0x7f user exit 4569570cc8Sopenharmony_ci#else 4669570cc8Sopenharmony_ci quick_exit(0); 4769570cc8Sopenharmony_ci#endif 4869570cc8Sopenharmony_ci} 4969570cc8Sopenharmony_ci 5069570cc8Sopenharmony_ci#ifdef APPSPAWN_HELPER 5169570cc8Sopenharmony_ci__attribute__((visibility("default"))) 5269570cc8Sopenharmony_ci_Noreturn 5369570cc8Sopenharmony_civoid exit(int code) 5469570cc8Sopenharmony_ci{ 5569570cc8Sopenharmony_ci char *checkExit = getenv(APPSPAWN_CHECK_EXIT); 5669570cc8Sopenharmony_ci if (checkExit && atoi(checkExit) == getpid()) { 5769570cc8Sopenharmony_ci APPSPAWN_LOGF("Unexpected call: exit(%{public}d)", code); 5869570cc8Sopenharmony_ci abort(); 5969570cc8Sopenharmony_ci } 6069570cc8Sopenharmony_ci // hook `exit` to `ProcessExit` to ensure app exit in a clean way 6169570cc8Sopenharmony_ci ProcessExit(code); 6269570cc8Sopenharmony_ci // should not come here 6369570cc8Sopenharmony_ci abort(); 6469570cc8Sopenharmony_ci} 6569570cc8Sopenharmony_ci#endif 6669570cc8Sopenharmony_ci 6769570cc8Sopenharmony_ci#ifdef USE_ENCAPS 6869570cc8Sopenharmony_ci#include <sys/ioctl.h> 6969570cc8Sopenharmony_ci 7069570cc8Sopenharmony_ci#define OH_ENCAPS_PROC_TYPE_BASE 0x18 7169570cc8Sopenharmony_ci#define OH_ENCAPS_MAGIC 'E' 7269570cc8Sopenharmony_ci#define OH_PROC_APP 4 7369570cc8Sopenharmony_ci#define SET_PROC_TYPE_CMD _IOW(OH_ENCAPS_MAGIC, OH_ENCAPS_PROC_TYPE_BASE, uint32_t) 7469570cc8Sopenharmony_ci 7569570cc8Sopenharmony_cistatic void SetEncapsFlag(int fdEncaps, uint32_t flag) 7669570cc8Sopenharmony_ci{ 7769570cc8Sopenharmony_ci if (fdEncaps < -1) { 7869570cc8Sopenharmony_ci APPSPAWN_LOGE("AppSpawnChild SetEncapsFlag failed, fdEncaps < -1"); 7969570cc8Sopenharmony_ci return; 8069570cc8Sopenharmony_ci } 8169570cc8Sopenharmony_ci int ret = ioctl(fdEncaps, SET_PROC_TYPE_CMD, &flag); 8269570cc8Sopenharmony_ci if (ret != 0) { 8369570cc8Sopenharmony_ci APPSPAWN_LOGE("AppSpawnChild SetEncapsFlag failed"); 8469570cc8Sopenharmony_ci } 8569570cc8Sopenharmony_ci close(fdEncaps); 8669570cc8Sopenharmony_ci} 8769570cc8Sopenharmony_ci#endif 8869570cc8Sopenharmony_ci 8969570cc8Sopenharmony_ciint AppSpawnChild(AppSpawnContent *content, AppSpawnClient *client) 9069570cc8Sopenharmony_ci{ 9169570cc8Sopenharmony_ci APPSPAWN_CHECK(content != NULL && client != NULL, return -1, "Invalid arg for appspawn child"); 9269570cc8Sopenharmony_ci APPSPAWN_LOGI("AppSpawnChild id %{public}u flags: 0x%{public}x", client->id, client->flags); 9369570cc8Sopenharmony_ci StartAppspawnTrace("AppSpawnExecuteClearEnvHook"); 9469570cc8Sopenharmony_ci int ret = AppSpawnExecuteClearEnvHook(content, client); 9569570cc8Sopenharmony_ci FinishAppspawnTrace(); 9669570cc8Sopenharmony_ci APPSPAWN_CHECK_ONLY_EXPER(ret == 0, 9769570cc8Sopenharmony_ci NotifyResToParent(content, client, ret); 9869570cc8Sopenharmony_ci AppSpawnEnvClear(content, client); 9969570cc8Sopenharmony_ci return 0); 10069570cc8Sopenharmony_ci 10169570cc8Sopenharmony_ci if (client->flags & APP_COLD_START) { 10269570cc8Sopenharmony_ci // cold start fail, to start normal 10369570cc8Sopenharmony_ci if (content->coldStartApp != NULL && content->coldStartApp(content, client) == 0) { 10469570cc8Sopenharmony_ci return 0; 10569570cc8Sopenharmony_ci } 10669570cc8Sopenharmony_ci APPSPAWN_LOGW("AppSpawnChild cold start fail %{public}u", client->id); 10769570cc8Sopenharmony_ci } 10869570cc8Sopenharmony_ci#ifdef USE_ENCAPS 10969570cc8Sopenharmony_ci SetEncapsFlag(content->fdEncaps, OH_PROC_APP); 11069570cc8Sopenharmony_ci#endif 11169570cc8Sopenharmony_ci StartAppspawnTrace("AppSpawnExecuteSpawningHook"); 11269570cc8Sopenharmony_ci ret = AppSpawnExecuteSpawningHook(content, client); 11369570cc8Sopenharmony_ci FinishAppspawnTrace(); 11469570cc8Sopenharmony_ci APPSPAWN_CHECK_ONLY_EXPER(ret == 0, 11569570cc8Sopenharmony_ci NotifyResToParent(content, client, ret); 11669570cc8Sopenharmony_ci AppSpawnEnvClear(content, client); 11769570cc8Sopenharmony_ci return 0); 11869570cc8Sopenharmony_ci StartAppspawnTrace("AppSpawnExecutePreReplyHook"); 11969570cc8Sopenharmony_ci ret = AppSpawnExecutePreReplyHook(content, client); 12069570cc8Sopenharmony_ci FinishAppspawnTrace(); 12169570cc8Sopenharmony_ci APPSPAWN_CHECK_ONLY_EXPER(ret == 0, 12269570cc8Sopenharmony_ci NotifyResToParent(content, client, ret); 12369570cc8Sopenharmony_ci AppSpawnEnvClear(content, client); 12469570cc8Sopenharmony_ci return 0); 12569570cc8Sopenharmony_ci 12669570cc8Sopenharmony_ci // notify success to father process and start app process 12769570cc8Sopenharmony_ci StartAppspawnTrace("NotifyResToParent"); 12869570cc8Sopenharmony_ci NotifyResToParent(content, client, 0); 12969570cc8Sopenharmony_ci FinishAppspawnTrace(); 13069570cc8Sopenharmony_ci 13169570cc8Sopenharmony_ci StartAppspawnTrace("AppSpawnExecutePostReplyHook"); 13269570cc8Sopenharmony_ci (void)AppSpawnExecutePostReplyHook(content, client); 13369570cc8Sopenharmony_ci FinishAppspawnTrace(); 13469570cc8Sopenharmony_ci 13569570cc8Sopenharmony_ci if (content->runChildProcessor != NULL) { 13669570cc8Sopenharmony_ci ret = content->runChildProcessor(content, client); 13769570cc8Sopenharmony_ci } 13869570cc8Sopenharmony_ci if (ret != 0) { 13969570cc8Sopenharmony_ci AppSpawnEnvClear(content, client); 14069570cc8Sopenharmony_ci } 14169570cc8Sopenharmony_ci return 0; 14269570cc8Sopenharmony_ci} 14369570cc8Sopenharmony_ci 14469570cc8Sopenharmony_cistatic int CloneAppSpawn(void *arg) 14569570cc8Sopenharmony_ci{ 14669570cc8Sopenharmony_ci APPSPAWN_CHECK(arg != NULL, return -1, "Invalid content for appspawn"); 14769570cc8Sopenharmony_ci AppSpawnForkArg *forkArg = (AppSpawnForkArg *)arg; 14869570cc8Sopenharmony_ci ProcessExit(AppSpawnChild(forkArg->content, forkArg->client)); 14969570cc8Sopenharmony_ci return 0; 15069570cc8Sopenharmony_ci} 15169570cc8Sopenharmony_ci 15269570cc8Sopenharmony_ci#ifndef OHOS_LITE 15369570cc8Sopenharmony_cistatic void NwebSpawnCloneChildProcess(AppSpawnContent *content, AppSpawnClient *client, pid_t *pid) 15469570cc8Sopenharmony_ci{ 15569570cc8Sopenharmony_ci AppSpawnForkArg arg; 15669570cc8Sopenharmony_ci arg.client = client; 15769570cc8Sopenharmony_ci arg.content = content; 15869570cc8Sopenharmony_ci#ifndef APPSPAWN_TEST 15969570cc8Sopenharmony_ci AppSpawningCtx *property = (AppSpawningCtx *)client; 16069570cc8Sopenharmony_ci uint32_t len = 0; 16169570cc8Sopenharmony_ci char *processType = (char *)(GetAppSpawnMsgExtInfo(property->message, MSG_EXT_NAME_PROCESS_TYPE, &len)); 16269570cc8Sopenharmony_ci APPSPAWN_CHECK(processType != NULL, return, "Invalid processType data"); 16369570cc8Sopenharmony_ci 16469570cc8Sopenharmony_ci if (strcmp(processType, "gpu") == 0) { 16569570cc8Sopenharmony_ci *pid = clone(CloneAppSpawn, NULL, CLONE_NEWNET | SIGCHLD, (void *)&arg); 16669570cc8Sopenharmony_ci } else { 16769570cc8Sopenharmony_ci *pid = clone(CloneAppSpawn, NULL, content->sandboxNsFlags | SIGCHLD, (void *)&arg); 16869570cc8Sopenharmony_ci } 16969570cc8Sopenharmony_ci#else 17069570cc8Sopenharmony_ci *pid = clone(CloneAppSpawn, NULL, content->sandboxNsFlags | SIGCHLD, (void *)&arg); 17169570cc8Sopenharmony_ci#endif 17269570cc8Sopenharmony_ci} 17369570cc8Sopenharmony_ci#endif 17469570cc8Sopenharmony_ci 17569570cc8Sopenharmony_cistatic void AppSpawnForkChildProcess(AppSpawnContent *content, AppSpawnClient *client, pid_t *pid) 17669570cc8Sopenharmony_ci{ 17769570cc8Sopenharmony_ci struct timespec forkStart = {0}; 17869570cc8Sopenharmony_ci clock_gettime(CLOCK_MONOTONIC, &forkStart); 17969570cc8Sopenharmony_ci StartAppspawnTrace("AppspawnForkStart"); 18069570cc8Sopenharmony_ci *pid = fork(); 18169570cc8Sopenharmony_ci if (*pid == 0) { 18269570cc8Sopenharmony_ci struct timespec forkEnd = {0}; 18369570cc8Sopenharmony_ci clock_gettime(CLOCK_MONOTONIC, &forkEnd); 18469570cc8Sopenharmony_ci uint64_t diff = DiffTime(&forkStart, &forkEnd); 18569570cc8Sopenharmony_ci APPSPAWN_CHECK_ONLY_LOG(diff < MAX_FORK_TIME, "fork time %{public}" PRId64 " us", diff); 18669570cc8Sopenharmony_ci ProcessExit(AppSpawnChild(content, client)); 18769570cc8Sopenharmony_ci } else { 18869570cc8Sopenharmony_ci FinishAppspawnTrace(); 18969570cc8Sopenharmony_ci } 19069570cc8Sopenharmony_ci} 19169570cc8Sopenharmony_ci 19269570cc8Sopenharmony_ciint AppSpawnProcessMsg(AppSpawnContent *content, AppSpawnClient *client, pid_t *childPid) 19369570cc8Sopenharmony_ci{ 19469570cc8Sopenharmony_ci APPSPAWN_CHECK(content != NULL, return -1, "Invalid content for appspawn"); 19569570cc8Sopenharmony_ci APPSPAWN_CHECK(client != NULL && childPid != NULL, return -1, "Invalid client for appspawn"); 19669570cc8Sopenharmony_ci APPSPAWN_LOGI("AppSpawnProcessMsg id: %{public}d mode: %{public}d sandboxNsFlags: 0x%{public}x", 19769570cc8Sopenharmony_ci client->id, content->mode, content->sandboxNsFlags); 19869570cc8Sopenharmony_ci 19969570cc8Sopenharmony_ci pid_t pid = 0; 20069570cc8Sopenharmony_ci#ifndef OHOS_LITE 20169570cc8Sopenharmony_ci if (content->mode == MODE_FOR_NWEB_SPAWN) { 20269570cc8Sopenharmony_ci NwebSpawnCloneChildProcess(content, client, &pid); 20369570cc8Sopenharmony_ci } else { 20469570cc8Sopenharmony_ci#else 20569570cc8Sopenharmony_ci { 20669570cc8Sopenharmony_ci#endif 20769570cc8Sopenharmony_ci AppSpawnForkChildProcess(content, client, &pid); 20869570cc8Sopenharmony_ci } 20969570cc8Sopenharmony_ci APPSPAWN_CHECK(pid >= 0, return APPSPAWN_FORK_FAIL, "fork child process error: %{public}d", errno); 21069570cc8Sopenharmony_ci *childPid = pid; 21169570cc8Sopenharmony_ci return 0; 21269570cc8Sopenharmony_ci} 213