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