1/*
2 * Copyright (c) 2024 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 <cerrno>
17#include <cstring>
18#include <dlfcn.h>
19#include <set>
20#include <string>
21#include <unistd.h>
22#include <utility>
23#include <vector>
24
25#include "appspawn_hook.h"
26#include "appspawn_server.h"
27#include "appspawn_service.h"
28#include "appspawn_manager.h"
29#include "appspawn_utils.h"
30#include "parameters.h"
31#ifndef APPSPAWN_TEST
32#include "main_thread.h"
33#endif
34
35APPSPAWN_STATIC int BuildFdInfoMap(const AppSpawnMsgNode *message, std::map<std::string, int> &fdMap, int isColdRun)
36{
37    APPSPAWN_CHECK_ONLY_EXPER(message != NULL && message->buffer != NULL, return -1);
38    APPSPAWN_CHECK_ONLY_EXPER(message->tlvOffset != NULL, return -1);
39    int findFdIndex = 0;
40    AppSpawnMsgReceiverCtx recvCtx;
41    if (!isColdRun) {
42        APPSPAWN_CHECK_ONLY_EXPER(message->connection != NULL, return -1);
43        recvCtx = message->connection->receiverCtx;
44        if (recvCtx.fdCount <= 0) {
45            APPSPAWN_LOGI("no need to build fd info %{public}d, %{public}d", recvCtx.fds != NULL, recvCtx.fdCount);
46            return 0;
47        }
48    }
49    for (uint32_t index = TLV_MAX; index < (TLV_MAX + message->tlvCount); index++) {
50        if (message->tlvOffset[index] == INVALID_OFFSET) {
51            return -1;
52        }
53        uint8_t *data = message->buffer + message->tlvOffset[index];
54        if (((AppSpawnTlv *)data)->tlvType != TLV_MAX) {
55            continue;
56        }
57        AppSpawnTlvExt *tlv = (AppSpawnTlvExt *)data;
58        if (strcmp(tlv->tlvName, MSG_EXT_NAME_APP_FD) != 0) {
59            continue;
60        }
61        std::string key((char *)data + sizeof(AppSpawnTlvExt));
62        if (isColdRun) {
63            std::string envKey = std::string(APP_FDENV_PREFIX) + key;
64            char *fdChar = getenv(envKey.c_str());
65            APPSPAWN_CHECK(fdChar != NULL, continue, "getfd from env failed %{public}s", envKey.c_str());
66            int fd = atoi(fdChar);
67            APPSPAWN_CHECK(fd > 0, continue, "getfd from env atoi errno %{public}s,%{public}d", envKey.c_str(), fd);
68            fdMap[key] = fd;
69        } else {
70            APPSPAWN_CHECK(findFdIndex < recvCtx.fdCount && recvCtx.fds[findFdIndex] > 0,
71                return -1, "invalid fd info  %{public}d %{public}d", findFdIndex, recvCtx.fds[findFdIndex]);
72            fdMap[key] = recvCtx.fds[findFdIndex++];
73            if (findFdIndex >= recvCtx.fdCount) {
74                break;
75            }
76        }
77    }
78    return 0;
79}
80
81static int RunChildThread(const AppSpawnMgr *content, const AppSpawningCtx *property)
82{
83    std::string checkExit;
84    if (OHOS::system::GetBoolParameter("persist.init.debug.checkexit", true)) {
85        checkExit = std::to_string(getpid());
86    }
87    setenv(APPSPAWN_CHECK_EXIT, checkExit.c_str(), true);
88    if (CheckAppMsgFlagsSet(property, APP_FLAGS_CHILDPROCESS)) {
89        std::map<std::string, int> fdMap;
90        BuildFdInfoMap(property->message, fdMap, IsColdRunMode(content));
91        AppSpawnEnvClear((AppSpawnContent *)&content->content, (AppSpawnClient *)&property->client);
92        OHOS::AppExecFwk::MainThread::StartChild(fdMap);
93    } else {
94        AppSpawnEnvClear((AppSpawnContent *)&content->content, (AppSpawnClient *)&property->client);
95        OHOS::AppExecFwk::MainThread::Start();
96    }
97    unsetenv(APPSPAWN_CHECK_EXIT);
98    return 0;
99}
100
101static int RunChildProcessor(AppSpawnContent *content, AppSpawnClient *client)
102{
103    APPSPAWN_CHECK(client != NULL && content != NULL, return -1, "Invalid client");
104    AppSpawningCtx *property = reinterpret_cast<AppSpawningCtx *>(client);
105
106    return RunChildThread(reinterpret_cast<AppSpawnMgr *>(content), property);
107}
108
109APPSPAWN_STATIC int PreLoadNativeSpawn(AppSpawnMgr *content)
110{
111    content->content.mode = MODE_FOR_NATIVE_SPAWN;
112    RegChildLooper(&content->content, RunChildProcessor);
113    return 0;
114}
115
116MODULE_CONSTRUCTOR(void)
117{
118    APPSPAWN_LOGV("Load native module ...");
119    AddPreloadHook(HOOK_PRIO_HIGHEST, PreLoadNativeSpawn);
120}