169570cc8Sopenharmony_ci/*
269570cc8Sopenharmony_ci * Copyright (c) 2024 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 <signal.h>
1769570cc8Sopenharmony_ci#include <stdbool.h>
1869570cc8Sopenharmony_ci#include <stdlib.h>
1969570cc8Sopenharmony_ci
2069570cc8Sopenharmony_ci#include "appspawn_hook.h"
2169570cc8Sopenharmony_ci#include "appspawn_modulemgr.h"
2269570cc8Sopenharmony_ci#include "appspawn_manager.h"
2369570cc8Sopenharmony_ci#include "appspawn_service.h"
2469570cc8Sopenharmony_ci#include "appspawn_kickdog.h"
2569570cc8Sopenharmony_ci#include "parameter.h"
2669570cc8Sopenharmony_ci#include "securec.h"
2769570cc8Sopenharmony_ci
2869570cc8Sopenharmony_ci#define APPSPAWN_PRELOAD "libappspawn_helper.z.so"
2969570cc8Sopenharmony_ci
3069570cc8Sopenharmony_ci#ifndef CJAPP_SPAWN
3169570cc8Sopenharmony_cistatic AppSpawnStartArgTemplate g_appSpawnStartArgTemplate[PROCESS_INVALID] = {
3269570cc8Sopenharmony_ci    {APPSPAWN_SERVER_NAME, {MODE_FOR_APP_SPAWN, MODULE_APPSPAWN, APPSPAWN_SOCKET_NAME, APPSPAWN_SERVER_NAME, 1}},
3369570cc8Sopenharmony_ci    {NWEBSPAWN_SERVER_NAME, {MODE_FOR_NWEB_SPAWN, MODULE_NWEBSPAWN, NWEBSPAWN_SOCKET_NAME, NWEBSPAWN_SERVER_NAME, 1}},
3469570cc8Sopenharmony_ci    {"app_cold", {MODE_FOR_APP_COLD_RUN, MODULE_APPSPAWN, APPSPAWN_SOCKET_NAME, APPSPAWN_SERVER_NAME, 0}},
3569570cc8Sopenharmony_ci    {"nweb_cold", {MODE_FOR_NWEB_COLD_RUN, MODULE_NWEBSPAWN, APPSPAWN_SOCKET_NAME, NWEBSPAWN_SERVER_NAME, 0}},
3669570cc8Sopenharmony_ci    {NATIVESPAWN_SERVER_NAME, {MODE_FOR_NATIVE_SPAWN, MODULE_NATIVESPAWN, NATIVESPAWN_SOCKET_NAME,
3769570cc8Sopenharmony_ci        NATIVESPAWN_SERVER_NAME, 1}},
3869570cc8Sopenharmony_ci    {NWEBSPAWN_RESTART, {MODE_FOR_NWEB_SPAWN, MODULE_NWEBSPAWN, NWEBSPAWN_SOCKET_NAME, NWEBSPAWN_SERVER_NAME, 1}},
3969570cc8Sopenharmony_ci};
4069570cc8Sopenharmony_ci#else
4169570cc8Sopenharmony_cistatic AppSpawnStartArgTemplate g_appCJSpawnStartArgTemplate[CJPROCESS_INVALID] = {
4269570cc8Sopenharmony_ci    {CJAPPSPAWN_SERVER_NAME, {MODE_FOR_CJAPP_SPAWN, MODULE_APPSPAWN, CJAPPSPAWN_SOCKET_NAME, CJAPPSPAWN_SERVER_NAME,
4369570cc8Sopenharmony_ci        1}},
4469570cc8Sopenharmony_ci    {"app_cold", {MODE_FOR_APP_COLD_RUN, MODULE_APPSPAWN, CJAPPSPAWN_SOCKET_NAME, CJAPPSPAWN_SERVER_NAME, 0}},
4569570cc8Sopenharmony_ci};
4669570cc8Sopenharmony_ci#endif
4769570cc8Sopenharmony_ci
4869570cc8Sopenharmony_cistatic void CheckPreload(char *const argv[])
4969570cc8Sopenharmony_ci{
5069570cc8Sopenharmony_ci    char buf[256] = APPSPAWN_PRELOAD;  // 256 is enough in most cases
5169570cc8Sopenharmony_ci    char *preload = getenv("LD_PRELOAD");
5269570cc8Sopenharmony_ci    char *pos = preload ? strstr(preload, APPSPAWN_PRELOAD) : NULL;
5369570cc8Sopenharmony_ci    if (pos) {
5469570cc8Sopenharmony_ci        int len = pos - preload;
5569570cc8Sopenharmony_ci        len = sprintf_s(buf, sizeof(buf), "%.*s%s", len, preload, pos + strlen(APPSPAWN_PRELOAD));
5669570cc8Sopenharmony_ci        APPSPAWN_CHECK(len >= 0, return, "preload too long?: %{public}s", preload);
5769570cc8Sopenharmony_ci        if (len == 0) {
5869570cc8Sopenharmony_ci            int ret = unsetenv("LD_PRELOAD");
5969570cc8Sopenharmony_ci            APPSPAWN_CHECK(ret == 0, return, "unsetenv fail(%{public}d)", errno);
6069570cc8Sopenharmony_ci        } else {
6169570cc8Sopenharmony_ci            int ret = setenv("LD_PRELOAD", buf, true);
6269570cc8Sopenharmony_ci            APPSPAWN_CHECK(ret == 0, return, "setenv fail(%{public}d): %{public}s", errno, buf);
6369570cc8Sopenharmony_ci        }
6469570cc8Sopenharmony_ci        return;
6569570cc8Sopenharmony_ci    }
6669570cc8Sopenharmony_ci    if (preload && preload[0]) {
6769570cc8Sopenharmony_ci        int len = sprintf_s(buf, sizeof(buf), "%s:" APPSPAWN_PRELOAD, preload);
6869570cc8Sopenharmony_ci        APPSPAWN_CHECK(len > 0, return, "preload too long: %{public}s", preload);
6969570cc8Sopenharmony_ci    }
7069570cc8Sopenharmony_ci    int ret = setenv("LD_PRELOAD", buf, true);
7169570cc8Sopenharmony_ci    APPSPAWN_CHECK(ret == 0, return, "setenv fail(%{public}d): %{public}s", errno, buf);
7269570cc8Sopenharmony_ci    ssize_t nread = readlink("/proc/self/exe", buf, sizeof(buf) - 1);
7369570cc8Sopenharmony_ci    APPSPAWN_CHECK(nread != -1, return, "readlink fail: /proc/self/exe: %{public}d", errno);
7469570cc8Sopenharmony_ci    buf[nread] = 0;
7569570cc8Sopenharmony_ci    ret = execv(buf, argv);
7669570cc8Sopenharmony_ci    APPSPAWN_LOGE("execv fail: %{public}s: %{public}d: %{public}d", buf, errno, ret);
7769570cc8Sopenharmony_ci}
7869570cc8Sopenharmony_ci
7969570cc8Sopenharmony_ci#ifndef NATIVE_SPAWN
8069570cc8Sopenharmony_cistatic AppSpawnStartArgTemplate *GetAppSpawnStartArg(const char *serverName, AppSpawnStartArgTemplate *argTemplate,
8169570cc8Sopenharmony_ci    int count)
8269570cc8Sopenharmony_ci{
8369570cc8Sopenharmony_ci    for (int i = 0; i < count; i++) {
8469570cc8Sopenharmony_ci        if (strcmp(serverName, argTemplate[i].serverName) == 0) {
8569570cc8Sopenharmony_ci            return &argTemplate[i];
8669570cc8Sopenharmony_ci        }
8769570cc8Sopenharmony_ci    }
8869570cc8Sopenharmony_ci
8969570cc8Sopenharmony_ci    return argTemplate;
9069570cc8Sopenharmony_ci}
9169570cc8Sopenharmony_ci#endif
9269570cc8Sopenharmony_ci
9369570cc8Sopenharmony_ci// appspawn -mode appspawn | cold | nwebspawn -param app_property -fd clientFd
9469570cc8Sopenharmony_ciint main(int argc, char *const argv[])
9569570cc8Sopenharmony_ci{
9669570cc8Sopenharmony_ci    APPSPAWN_LOGE("main argc: %{public}d", argc);
9769570cc8Sopenharmony_ci    if (argc <= 0) {
9869570cc8Sopenharmony_ci        return 0;
9969570cc8Sopenharmony_ci    }
10069570cc8Sopenharmony_ci    uintptr_t start = (uintptr_t)argv[0];
10169570cc8Sopenharmony_ci    uintptr_t end = (uintptr_t)strchr(argv[argc - 1], 0);
10269570cc8Sopenharmony_ci    if (end == 0) {
10369570cc8Sopenharmony_ci        return 0;
10469570cc8Sopenharmony_ci    }
10569570cc8Sopenharmony_ci    InitCommonEnv();
10669570cc8Sopenharmony_ci    CheckPreload(argv);
10769570cc8Sopenharmony_ci    (void)signal(SIGPIPE, SIG_IGN);
10869570cc8Sopenharmony_ci    uint32_t argvSize = end - start;
10969570cc8Sopenharmony_ci    AppSpawnStartArg *arg;
11069570cc8Sopenharmony_ci    AppSpawnStartArgTemplate *argTemp = NULL;
11169570cc8Sopenharmony_ci
11269570cc8Sopenharmony_ci#ifdef CJAPP_SPAWN
11369570cc8Sopenharmony_ci    argTemp = &g_appCJSpawnStartArgTemplate[CJPROCESS_FOR_APP_SPAWN];
11469570cc8Sopenharmony_ci    if (argc > MODE_VALUE_INDEX) {
11569570cc8Sopenharmony_ci        argTemp = GetAppSpawnStartArg(argv[MODE_VALUE_INDEX], g_appCJSpawnStartArgTemplate,
11669570cc8Sopenharmony_ci            ARRAY_LENGTH(g_appCJSpawnStartArgTemplate));
11769570cc8Sopenharmony_ci    }
11869570cc8Sopenharmony_ci#elif NATIVE_SPAWN
11969570cc8Sopenharmony_ci    argTemp = &g_appSpawnStartArgTemplate[PROCESS_FOR_NATIVE_SPAWN];
12069570cc8Sopenharmony_ci#else
12169570cc8Sopenharmony_ci    argTemp = &g_appSpawnStartArgTemplate[PROCESS_FOR_APP_SPAWN];
12269570cc8Sopenharmony_ci    if (argc > MODE_VALUE_INDEX) {
12369570cc8Sopenharmony_ci        argTemp = GetAppSpawnStartArg(argv[MODE_VALUE_INDEX], g_appSpawnStartArgTemplate,
12469570cc8Sopenharmony_ci            ARRAY_LENGTH(g_appSpawnStartArgTemplate));
12569570cc8Sopenharmony_ci    }
12669570cc8Sopenharmony_ci#endif
12769570cc8Sopenharmony_ci    arg = &argTemp->arg;
12869570cc8Sopenharmony_ci    if (arg->initArg == 0) {
12969570cc8Sopenharmony_ci        APPSPAWN_CHECK(argc >= ARG_NULL, return 0, "Invalid arg for cold start %{public}d", argc);
13069570cc8Sopenharmony_ci    } else {
13169570cc8Sopenharmony_ci        if (strcmp(argTemp->serverName, NWEBSPAWN_RESTART) == 0) {  // nweb spawn restart
13269570cc8Sopenharmony_ci            APPSPAWN_CHECK_ONLY_EXPER(argvSize >= APP_LEN_PROC_NAME, argvSize = APP_LEN_PROC_NAME);
13369570cc8Sopenharmony_ci        } else {
13469570cc8Sopenharmony_ci            APPSPAWN_CHECK(argvSize >= APP_LEN_PROC_NAME, return 0, "Invalid arg size for service %{public}s",
13569570cc8Sopenharmony_ci                arg->serviceName);
13669570cc8Sopenharmony_ci        }
13769570cc8Sopenharmony_ci    }
13869570cc8Sopenharmony_ci    AppSpawnContent *content = StartSpawnService(arg, argvSize, argc, argv);
13969570cc8Sopenharmony_ci    if (content != NULL) {
14069570cc8Sopenharmony_ci        if ((arg->moduleType == MODULE_APPSPAWN) && (arg->mode != MODE_FOR_APP_COLD_RUN)) {
14169570cc8Sopenharmony_ci            AppSpawnKickDogStart(content);
14269570cc8Sopenharmony_ci        }
14369570cc8Sopenharmony_ci        content->runAppSpawn(content, argc, argv);
14469570cc8Sopenharmony_ci    }
14569570cc8Sopenharmony_ci    return 0;
14669570cc8Sopenharmony_ci}
147