• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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