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 <regex>
20 #include "app_mgr_client.h"
21 #include "child_process_configs.h"
22 #include "hilog_tag_wrapper.h"
23 #include "native_child_callback.h"
24 #include "child_process_args_manager.h"
25 #include "child_process_manager.h"
26 #include "child_callback_manager.h"
27 #include "child_process_manager_error_utils.h"
28
29 using namespace OHOS;
30 using namespace OHOS::AbilityRuntime;
31
32 namespace {
33 constexpr size_t MAX_KEY_SIZE = 20;
34 constexpr size_t MAX_FD_SIZE = 16;
35 constexpr int32_t MAX_PROCESS_NAME_LENGTH = 64;
36 std::mutex g_callbackStubMutex;
37 std::mutex g_callbackSerialMutex;
38 sptr<OHOS::AbilityRuntime::NativeChildCallback> g_callbackStub = nullptr;
39 } // Anonymous namespace
40
OH_Ability_CreateChildProcessConfigs()41 Ability_ChildProcessConfigs* OH_Ability_CreateChildProcessConfigs()
42 {
43 std::unique_ptr<Ability_ChildProcessConfigs> configs = std::make_unique<Ability_ChildProcessConfigs>();
44 return configs.release();
45 }
46
OH_Ability_DestroyChildProcessConfigs(Ability_ChildProcessConfigs * configs)47 Ability_NativeChildProcess_ErrCode OH_Ability_DestroyChildProcessConfigs(Ability_ChildProcessConfigs* configs)
48 {
49 if(configs == nullptr){
50 TAG_LOGE(AAFwkTag::PROCESSMGR, "null Ability_ChildProcessConfigs");
51 return NCP_ERR_INVALID_PARAM;
52 }
53 delete configs;
54 configs = nullptr;
55 return NCP_NO_ERROR;
56 }
57
OH_Ability_ChildProcessConfigs_SetIsolationMode(Ability_ChildProcessConfigs * configs,NativeChildProcess_IsolationMode isolationMode)58 Ability_NativeChildProcess_ErrCode OH_Ability_ChildProcessConfigs_SetIsolationMode(
59 Ability_ChildProcessConfigs* configs, NativeChildProcess_IsolationMode isolationMode)
60 {
61 if(configs == nullptr) {
62 TAG_LOGE(AAFwkTag::APPKIT, "null Ability_ChildProcessConfigs");
63 return NCP_ERR_INVALID_PARAM;
64 }
65 configs->isolationMode = isolationMode;
66 return NCP_NO_ERROR;
67 }
68
OH_Ability_ChildProcessConfigs_SetProcessName(Ability_ChildProcessConfigs * configs,const char * processName)69 Ability_NativeChildProcess_ErrCode OH_Ability_ChildProcessConfigs_SetProcessName(Ability_ChildProcessConfigs* configs,
70 const char* processName)
71 {
72 if (configs == nullptr) {
73 TAG_LOGE(AAFwkTag::APPKIT, "null Ability_ChildProcessConfigs");
74 return NCP_ERR_INVALID_PARAM;
75 }
76 if (processName == nullptr) {
77 TAG_LOGE(AAFwkTag::APPKIT, "null processName");
78 return NCP_ERR_INVALID_PARAM;
79 }
80 int32_t processNameLen = strlen(processName);
81 if(processNameLen == 0) {
82 TAG_LOGE(AAFwkTag::APPKIT, "processName is 0");
83 return NCP_ERR_INVALID_PARAM;
84 }
85 if (processNameLen > MAX_PROCESS_NAME_LENGTH) {
86 TAG_LOGE(AAFwkTag::APPKIT, "processName is larger than 64");
87 return NCP_ERR_INVALID_PARAM;
88 }
89 try {
90 std::regex regex("^[a-zA-Z0-9_]+$");
91 if (!regex_match(processName, regex)) {
92 TAG_LOGE(AAFwkTag::APPKIT, "Wrong processName");
93 return NCP_ERR_INVALID_PARAM;
94 }
95 } catch(...) {
96 TAG_LOGE(AAFwkTag::ABILITYMGR, "regex error");
97 return NCP_ERR_INVALID_PARAM;
98 }
99 configs->processName = std::string(processName);
100 return NCP_NO_ERROR;
101 }
102
OH_Ability_CreateNativeChildProcess(const char * libName,OH_Ability_OnNativeChildProcessStarted onProcessStarted)103 int OH_Ability_CreateNativeChildProcess(const char* libName, OH_Ability_OnNativeChildProcessStarted onProcessStarted)
104 {
105 if (libName == nullptr || *libName == '\0' || onProcessStarted == nullptr) {
106 TAG_LOGE(AAFwkTag::PROCESSMGR, "null libname or callback");
107 return NCP_ERR_INVALID_PARAM;
108 }
109
110 std::string strLibName(libName);
111 if (strLibName.find("../") != std::string::npos) {
112 TAG_LOGE(AAFwkTag::PROCESSMGR, "relative path not allow");
113 return NCP_ERR_INVALID_PARAM;
114 }
115
116 sptr<IRemoteObject> callbackStub(new (std::nothrow) NativeChildCallback(onProcessStarted));
117 if (!callbackStub) {
118 TAG_LOGE(AAFwkTag::PROCESSMGR, "null callbackStub");
119 return NCP_ERR_INTERNAL;
120 }
121
122 auto cpmErr = ChildProcessManager::GetInstance().StartNativeChildProcessByAppSpawnFork(strLibName, callbackStub);
123 if (cpmErr != ChildProcessManagerErrorCode::ERR_OK) {
124 return ChildProcessManagerErrorUtil::CvtChildProcessManagerErrCode(cpmErr);
125 }
126
127 ChildCallbackManager::GetInstance().AddRemoteObject(callbackStub);
128 return NCP_NO_ERROR;
129 }
130
OH_Ability_CreateNativeChildProcessWithConfigs(const char * libName,Ability_ChildProcessConfigs * configs,OH_Ability_OnNativeChildProcessStarted onProcessStarted)131 Ability_NativeChildProcess_ErrCode OH_Ability_CreateNativeChildProcessWithConfigs(const char* libName,
132 Ability_ChildProcessConfigs* configs, OH_Ability_OnNativeChildProcessStarted onProcessStarted)
133 {
134 if (libName == nullptr || *libName == '\0' || onProcessStarted == nullptr || configs == nullptr) {
135 TAG_LOGE(AAFwkTag::PROCESSMGR, "null libname or callback or configs");
136 return NCP_ERR_INVALID_PARAM;
137 }
138
139 std::string strLibName(libName);
140 if (strLibName.find("../") != std::string::npos) {
141 TAG_LOGE(AAFwkTag::PROCESSMGR, "relative path not allow");
142 return NCP_ERR_INVALID_PARAM;
143 }
144
145 sptr<IRemoteObject> callbackStub(new (std::nothrow) NativeChildCallback(onProcessStarted));
146 if (!callbackStub) {
147 TAG_LOGE(AAFwkTag::PROCESSMGR, "null callbackStub");
148 return NCP_ERR_INTERNAL;
149 }
150
151 auto cpmErr = ChildProcessManager::GetInstance().StartNativeChildProcessByAppSpawnFork(strLibName,
152 callbackStub, configs->processName);
153 if (cpmErr != ChildProcessManagerErrorCode::ERR_OK) {
154 return ChildProcessManagerErrorUtil::CvtChildProcessManagerErrCode(cpmErr);
155 }
156
157 ChildCallbackManager::GetInstance().AddRemoteObject(callbackStub);
158 return NCP_NO_ERROR;
159 }
160
ConvertNativeChildProcessArgs(NativeChildProcess_Args & args,AppExecFwk::ChildProcessArgs & childArgs)161 Ability_NativeChildProcess_ErrCode ConvertNativeChildProcessArgs(NativeChildProcess_Args &args,
162 AppExecFwk::ChildProcessArgs &childArgs)
163 {
164 std::map<std::string, int32_t> fds;
165 NativeChildProcess_Fd* cur = args.fdList.head;
166 while (cur != nullptr) {
167 if (!cur->fdName) {
168 TAG_LOGE(AAFwkTag::PROCESSMGR, "fdName null");
169 return NCP_ERR_INVALID_PARAM;
170 }
171 std::string key(cur->fdName);
172 if (key.size() > MAX_KEY_SIZE) {
173 TAG_LOGE(AAFwkTag::PROCESSMGR, "fd name too long");
174 return NCP_ERR_INVALID_PARAM;
175 }
176 fds.emplace(key, cur->fd);
177 cur = cur->next;
178 }
179 if (fds.size() > MAX_FD_SIZE) {
180 TAG_LOGE(AAFwkTag::PROCESSMGR, "too many fds");
181 return NCP_ERR_INVALID_PARAM;
182 }
183 childArgs.fds = fds;
184 if (args.entryParams != nullptr && *(args.entryParams) != '\0') {
185 std::string entryParams(args.entryParams);
186 childArgs.entryParams = entryParams;
187 }
188 return NCP_NO_ERROR;
189 }
190
OH_Ability_StartNativeChildProcess(const char * entry,NativeChildProcess_Args args,NativeChildProcess_Options options,int32_t * pid)191 Ability_NativeChildProcess_ErrCode OH_Ability_StartNativeChildProcess(const char* entry,
192 NativeChildProcess_Args args, NativeChildProcess_Options options, int32_t *pid)
193 {
194 if (entry == nullptr || *entry == '\0') {
195 TAG_LOGE(AAFwkTag::PROCESSMGR, "Invalid entry");
196 return NCP_ERR_INVALID_PARAM;
197 }
198 std::string entryName(entry);
199 if (entryName.find(":") == std::string::npos) {
200 TAG_LOGE(AAFwkTag::PROCESSMGR, "entry point misses a colon");
201 return NCP_ERR_INVALID_PARAM;
202 }
203 if (pid == nullptr) {
204 TAG_LOGE(AAFwkTag::PROCESSMGR, "pid null");
205 return NCP_ERR_INVALID_PARAM;
206 }
207
208 AppExecFwk::ChildProcessArgs childArgs;
209 auto errCode = ConvertNativeChildProcessArgs(args, childArgs);
210 if (errCode != NCP_NO_ERROR) {
211 return errCode;
212 }
213 AppExecFwk::ChildProcessOptions childProcessOptions;
214 childProcessOptions.isolationMode = options.isolationMode == NCP_ISOLATION_MODE_ISOLATED;
215 int32_t childProcessType = AppExecFwk::CHILD_PROCESS_TYPE_NATIVE_ARGS;
216
217 auto cpmErr = ChildProcessManager::GetInstance().StartChildProcessWithArgs(entryName,
218 *pid, childProcessType, childArgs, childProcessOptions);
219 if (cpmErr != ChildProcessManagerErrorCode::ERR_OK) {
220 return ChildProcessManagerErrorUtil::CvtChildProcessManagerErrCode(cpmErr);
221 }
222 return NCP_NO_ERROR;
223 }
224
OH_Ability_StartNativeChildProcessWithConfigs(const char * entry,NativeChildProcess_Args args,Ability_ChildProcessConfigs * configs,int32_t * pid)225 Ability_NativeChildProcess_ErrCode OH_Ability_StartNativeChildProcessWithConfigs(
226 const char* entry, NativeChildProcess_Args args, Ability_ChildProcessConfigs* configs, int32_t *pid)
227 {
228 if (entry == nullptr || *entry == '\0' || configs == nullptr) {
229 TAG_LOGE(AAFwkTag::PROCESSMGR, "Invalid entry or configs");
230 return NCP_ERR_INVALID_PARAM;
231 }
232 std::string entryName(entry);
233 if (entryName.find(":") == std::string::npos) {
234 TAG_LOGE(AAFwkTag::PROCESSMGR, "entry point misses a colon");
235 return NCP_ERR_INVALID_PARAM;
236 }
237 if (pid == nullptr) {
238 TAG_LOGE(AAFwkTag::PROCESSMGR, "pid null");
239 return NCP_ERR_INVALID_PARAM;
240 }
241
242 AppExecFwk::ChildProcessArgs childArgs;
243 auto errCode = ConvertNativeChildProcessArgs(args, childArgs);
244 if (errCode != NCP_NO_ERROR) {
245 return errCode;
246 }
247 AppExecFwk::ChildProcessOptions childProcessOptions;
248 childProcessOptions.isolationMode = configs->isolationMode == NCP_ISOLATION_MODE_ISOLATED;
249 childProcessOptions.customProcessName = configs->processName;
250 int32_t childProcessType = AppExecFwk::CHILD_PROCESS_TYPE_NATIVE_ARGS;
251
252 auto cpmErr = ChildProcessManager::GetInstance().StartChildProcessWithArgs(entryName,
253 *pid, childProcessType, childArgs, childProcessOptions);
254 if (cpmErr != ChildProcessManagerErrorCode::ERR_OK) {
255 return ChildProcessManagerErrorUtil::CvtChildProcessManagerErrCode(cpmErr);
256 }
257 return NCP_NO_ERROR;
258 }
259
OH_Ability_GetCurrentChildProcessArgs()260 NativeChildProcess_Args* OH_Ability_GetCurrentChildProcessArgs()
261 {
262 NativeChildProcess_Args* result = ChildProcessArgsManager::GetInstance().GetChildProcessArgs();
263 if (result == nullptr) {
264 TAG_LOGE(AAFwkTag::PROCESSMGR, "GetChildProcessArgs null");
265 }
266 return result;
267 }
268
GetGlobalNativeChildCallbackStub()269 sptr<OHOS::AbilityRuntime::NativeChildCallback> GetGlobalNativeChildCallbackStub()
270 {
271 std::lock_guard<std::mutex> lock(g_callbackStubMutex);
272 return g_callbackStub;
273 }
274
SetGlobalNativeChildCallbackStub(sptr<OHOS::AbilityRuntime::NativeChildCallback> local)275 void SetGlobalNativeChildCallbackStub(sptr<OHOS::AbilityRuntime::NativeChildCallback> local)
276 {
277 std::lock_guard<std::mutex> lock(g_callbackStubMutex);
278 g_callbackStub = local;
279 }
280
OH_Ability_RegisterNativeChildProcessExitCallback(OH_Ability_OnNativeChildProcessExit onProcessExit)281 Ability_NativeChildProcess_ErrCode OH_Ability_RegisterNativeChildProcessExitCallback(
282 OH_Ability_OnNativeChildProcessExit onProcessExit)
283 {
284 if (onProcessExit == nullptr) {
285 TAG_LOGE(AAFwkTag::PROCESSMGR, "null callback func pointer");
286 return NCP_ERR_INVALID_PARAM;
287 }
288
289 std::lock_guard<std::mutex> lock(g_callbackSerialMutex);
290 auto localCallbackStub = GetGlobalNativeChildCallbackStub();
291 if (localCallbackStub != nullptr) {
292 localCallbackStub->AddExitCallback(onProcessExit);
293 return NCP_NO_ERROR;
294 }
295
296 localCallbackStub = sptr<NativeChildCallback>::MakeSptr(nullptr);
297 if (!localCallbackStub) {
298 TAG_LOGE(AAFwkTag::PROCESSMGR, "null callbackStub");
299 return NCP_ERR_INTERNAL;
300 }
301 SetGlobalNativeChildCallbackStub(localCallbackStub);
302 localCallbackStub->AddExitCallback(onProcessExit);
303 auto ret = DelayedSingleton<OHOS::AppExecFwk::AppMgrClient>::GetInstance()->RegisterNativeChildExitNotify(
304 localCallbackStub);
305 if (ret != NCP_NO_ERROR) {
306 TAG_LOGE(AAFwkTag::PROCESSMGR, "register native child exit notify failed, %{public}d", ret);
307 SetGlobalNativeChildCallbackStub(nullptr);
308 return NCP_ERR_INTERNAL;
309 }
310
311 return NCP_NO_ERROR;
312 }
313
OH_Ability_UnregisterNativeChildProcessExitCallback(OH_Ability_OnNativeChildProcessExit onProcessExit)314 Ability_NativeChildProcess_ErrCode OH_Ability_UnregisterNativeChildProcessExitCallback(
315 OH_Ability_OnNativeChildProcessExit onProcessExit)
316 {
317 if (onProcessExit == nullptr) {
318 TAG_LOGE(AAFwkTag::PROCESSMGR, "null callback func pointer");
319 return NCP_ERR_INVALID_PARAM;
320 }
321
322 std::lock_guard<std::mutex> lock(g_callbackSerialMutex);
323 sptr<OHOS::AbilityRuntime::NativeChildCallback> localCallbackStub = GetGlobalNativeChildCallbackStub();
324 if (localCallbackStub == nullptr) {
325 TAG_LOGE(AAFwkTag::PROCESSMGR, "null callbackStub");
326 return NCP_ERR_CALLBACK_NOT_EXIST;
327 }
328
329 auto ret = localCallbackStub->RemoveExitCallback(onProcessExit);
330 if (ret == NCP_ERR_CALLBACK_NOT_EXIST) {
331 return static_cast<Ability_NativeChildProcess_ErrCode>(ret);
332 }
333 if (localCallbackStub->IsCallbacksEmpty()) {
334 auto ret = DelayedSingleton<OHOS::AppExecFwk::AppMgrClient>::GetInstance()->UnregisterNativeChildExitNotify(
335 localCallbackStub);
336 if (ret != NCP_NO_ERROR) {
337 TAG_LOGE(AAFwkTag::PROCESSMGR, "unregister native child exit notify failed, %{public}d", ret);
338 return NCP_ERR_INTERNAL;
339 }
340 SetGlobalNativeChildCallbackStub(nullptr);
341 }
342
343 return NCP_NO_ERROR;
344 }
345