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 "native_child_process.h"
17 #include <map>
18 #include <mutex>
19 #include "hilog_tag_wrapper.h"
20 #include "native_child_callback.h"
21 #include "child_process_manager.h"
22 
23 using namespace OHOS;
24 using namespace OHOS::AbilityRuntime;
25 
26 namespace {
27 
28 std::mutex g_mutexCallBackObj;
29 sptr<IRemoteObject> g_CallbackStub;
30 OH_Ability_OnNativeChildProcessStarted g_Callback = nullptr;
31 constexpr size_t MAX_KEY_SIZE = 20;
32 constexpr size_t MAX_FD_SIZE = 16;
33 
34 const std::map<ChildProcessManagerErrorCode, Ability_NativeChildProcess_ErrCode> CPM_ERRCODE_MAP = {
35     { ChildProcessManagerErrorCode::ERR_OK, NCP_NO_ERROR },
36     { ChildProcessManagerErrorCode::ERR_MULTI_PROCESS_MODEL_DISABLED, NCP_ERR_MULTI_PROCESS_DISABLED },
37     { ChildProcessManagerErrorCode::ERR_ALREADY_IN_CHILD_PROCESS, NCP_ERR_ALREADY_IN_CHILD },
38     { ChildProcessManagerErrorCode::ERR_GET_APP_MGR_FAILED, NCP_ERR_SERVICE_ERROR },
39     { ChildProcessManagerErrorCode::ERR_APP_MGR_FAILED_INNER, NCP_ERR_SERVICE_ERROR },
40     { ChildProcessManagerErrorCode::ERR_UNSUPPORT_NATIVE_CHILD_PROCESS, NCP_ERR_NOT_SUPPORTED },
41     { ChildProcessManagerErrorCode::ERR_MAX_CHILD_PROCESSES, NCP_ERR_MAX_CHILD_PROCESSES_REACHED },
42     { ChildProcessManagerErrorCode::ERR_LIB_LOADING_FAILED, NCP_ERR_LIB_LOADING_FAILED },
43     { ChildProcessManagerErrorCode::ERR_CONNECTION_FAILED, NCP_ERR_CONNECTION_FAILED },
44     { ChildProcessManagerErrorCode::ERR_MULTI_PROCESS_MODEL_DISABLED_NEW, NCP_ERR_MULTI_PROCESS_DISABLED },
45 };
46 
CvtChildProcessManagerErrCode(ChildProcessManagerErrorCode cpmErr)47 Ability_NativeChildProcess_ErrCode CvtChildProcessManagerErrCode(ChildProcessManagerErrorCode cpmErr)
48 {
49     auto it = CPM_ERRCODE_MAP.find(cpmErr);
50     if (it == CPM_ERRCODE_MAP.end()) {
51         return NCP_ERR_INTERNAL;
52     }
53 
54     return it->second;
55 }
56 
OnNativeChildProcessStartedWapper(int errCode,OHIPCRemoteProxy * ipcProxy)57 void OnNativeChildProcessStartedWapper(int errCode, OHIPCRemoteProxy *ipcProxy)
58 {
59     std::unique_lock autoLock(g_mutexCallBackObj);
60     if (g_Callback != nullptr) {
61         g_Callback(CvtChildProcessManagerErrCode(static_cast<ChildProcessManagerErrorCode>(errCode)), ipcProxy);
62         g_Callback = nullptr;
63     } else {
64         TAG_LOGW(AAFwkTag::PROCESSMGR, "Remote call twice?");
65     }
66 
67     g_CallbackStub.clear();
68 }
69 
70 } // Anonymous namespace
71 
OH_Ability_CreateNativeChildProcess(const char * libName,OH_Ability_OnNativeChildProcessStarted onProcessStarted)72 int OH_Ability_CreateNativeChildProcess(const char* libName, OH_Ability_OnNativeChildProcessStarted onProcessStarted)
73 {
74     if (libName == nullptr || *libName == '\0' || onProcessStarted == nullptr) {
75         TAG_LOGE(AAFwkTag::PROCESSMGR, "Invalid libname or callback");
76         return NCP_ERR_INVALID_PARAM;
77     }
78 
79     std::string strLibName(libName);
80     if (strLibName.find("../") != std::string::npos) {
81         TAG_LOGE(AAFwkTag::PROCESSMGR, "relative path not allow");
82         return NCP_ERR_INVALID_PARAM;
83     }
84 
85     std::unique_lock autoLock(g_mutexCallBackObj);
86     if (g_Callback != nullptr || g_CallbackStub != nullptr) {
87         TAG_LOGW(AAFwkTag::PROCESSMGR, "Another native process starting");
88         return NCP_ERR_BUSY;
89     }
90 
91     sptr<IRemoteObject> callbackStub(new (std::nothrow) NativeChildCallback(OnNativeChildProcessStartedWapper));
92     if (!callbackStub) {
93         TAG_LOGE(AAFwkTag::PROCESSMGR, "Alloc callbackStub obj faild");
94         return NCP_ERR_INTERNAL;
95     }
96 
97     ChildProcessManager &mgr = ChildProcessManager::GetInstance();
98     auto cpmErr = mgr.StartNativeChildProcessByAppSpawnFork(strLibName, callbackStub);
99     if (cpmErr != ChildProcessManagerErrorCode::ERR_OK) {
100         return CvtChildProcessManagerErrCode(cpmErr);
101     }
102 
103     g_Callback = onProcessStarted;
104     g_CallbackStub = callbackStub;
105     return NCP_NO_ERROR;
106 }
107 
OH_Ability_StartNativeChildProcess(const char * entry,NativeChildProcess_Args args,NativeChildProcess_Options options,int32_t * pid)108 Ability_NativeChildProcess_ErrCode OH_Ability_StartNativeChildProcess(const char* entry,
109     NativeChildProcess_Args args, NativeChildProcess_Options options, int32_t *pid)
110 {
111     if (entry == nullptr || *entry == '\0') {
112         TAG_LOGE(AAFwkTag::PROCESSMGR, "Invalid entry");
113         return NCP_ERR_INVALID_PARAM;
114     }
115     std::string entryName(entry);
116     if (entryName.find(":") == std::string::npos) {
117         TAG_LOGE(AAFwkTag::PROCESSMGR, "entry point misses a colon");
118         return NCP_ERR_INVALID_PARAM;
119     }
120     if (pid == nullptr) {
121         TAG_LOGE(AAFwkTag::PROCESSMGR, "pid null");
122         return NCP_ERR_INVALID_PARAM;
123     }
124 
125     std::map<std::string, int32_t> fds;
126     NativeChildProcess_Fd* cur = args.fdList.head;
127     while (cur != nullptr) {
128         if (!cur->fdName) {
129             TAG_LOGE(AAFwkTag::PROCESSMGR, "fdName null");
130             return NCP_ERR_INVALID_PARAM;
131         }
132         std::string key(cur->fdName);
133         if (key.size() > MAX_KEY_SIZE) {
134             TAG_LOGE(AAFwkTag::PROCESSMGR, "fd name too long");
135             return NCP_ERR_INVALID_PARAM;
136         }
137         fds.emplace(key, cur->fd);
138         cur = cur->next;
139     }
140     if (fds.size() > MAX_FD_SIZE) {
141         TAG_LOGE(AAFwkTag::PROCESSMGR, "too many fds");
142         return NCP_ERR_INVALID_PARAM;
143     }
144     AppExecFwk::ChildProcessArgs childArgs;
145     childArgs.fds = fds;
146     if (args.entryParams != nullptr && *(args.entryParams) != '\0') {
147         std::string entryParams(args.entryParams);
148         childArgs.entryParams = entryParams;
149     }
150     AppExecFwk::ChildProcessOptions childProcessOptions;
151     childProcessOptions.isolationMode = options.isolationMode == NCP_ISOLATION_MODE_ISOLATED;
152     int32_t childProcessType = AppExecFwk::CHILD_PROCESS_TYPE_NATIVE_ARGS;
153 
154     ChildProcessManager &mgr = ChildProcessManager::GetInstance();
155     auto cpmErr = mgr.StartChildProcessWithArgs(entryName, *pid, childProcessType, childArgs, childProcessOptions);
156     if (cpmErr != ChildProcessManagerErrorCode::ERR_OK) {
157         return CvtChildProcessManagerErrCode(cpmErr);
158     }
159     return NCP_NO_ERROR;
160 }