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 }