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 "IpcProxy.h"
17 #include <cstdlib>
18 #include <cstring>
19 #include <hilog/log.h>
20 #include <fcntl.h>
21 #include <future>
22 #include <unistd.h>
23 #include "napi/native_api.h"
24 #include "AbilityKit/native_child_process.h"
25 #include "ChildProcess.h"
26 #include "loghelper.h"
27
28 #undef LOG_DOMAIN
29 #undef LOG_TAG
30 #define LOG_DOMAIN 0x3200
31 #define LOG_TAG "CHILD_TAG"
32
33 static ChildProcess g_childProcess;
34 static IpcProxy *g_ipcProxyPnt = nullptr;
35 static std::vector<IpcProxy*> g_ipcProxyPntObjects;
36 static std::promise<int> *g_promiseStartProcess = nullptr;
37
38 extern "C" {
39
NativeChildProcess_OnConnect()40 OHIPCRemoteStub* NativeChildProcess_OnConnect()
41 {
42 OH_LOG_INFO(LOG_APP, "Child process - OnConnect");
43 return g_childProcess.GetIpcStub();
44 }
45
NativeChildProcess_MainProc()46 void NativeChildProcess_MainProc()
47 {
48 OH_LOG_INFO(LOG_APP, "Child process - MainProc started");
49 g_childProcess.MainProc();
50 OH_LOG_INFO(LOG_APP, "Child process - MainProc end");
51 }
52
53 } // extern "C"
54
OnNativeChildProcessStarted(int errCode,OHIPCRemoteProxy * remoteProxy)55 static void OnNativeChildProcessStarted(int errCode, OHIPCRemoteProxy *remoteProxy)
56 {
57 OH_LOG_INFO(LOG_APP, "Main process - OnNativeChildProcessStarted %{public}d", errCode);
58 g_ipcProxyPnt = new (std::nothrow) IpcProxy(remoteProxy);
59 if (g_ipcProxyPnt == nullptr) {
60 OH_LOG_ERROR(LOG_APP, "Main process - Alloc ipc proxy object failed!");
61 OH_IPCRemoteProxy_Destroy(remoteProxy);
62 } else {
63 g_ipcProxyPntObjects.push_back(g_ipcProxyPnt);
64 }
65
66 if (g_promiseStartProcess != nullptr) {
67 g_promiseStartProcess->set_value(errCode);
68 }
69 }
70
ChildProcessAdd(napi_env env,napi_callback_info info)71 static napi_value ChildProcessAdd(napi_env env, napi_callback_info info)
72 {
73 int32_t result = INT32_MIN;
74 if (g_ipcProxyPnt != nullptr) {
75 size_t argc = 2;
76 napi_value args[2] = { nullptr };
77 napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
78 int32_t value0;
79 napi_get_value_int32(env, args[0], &value0);
80 int32_t value1;
81 napi_get_value_int32(env, args[1], &value1);
82
83 result = g_ipcProxyPnt->Add(value0, value1);
84 OH_LOG_INFO(LOG_APP, "Main process - ChildProcessAdd %{public}d+%{public}d=%{public}d",
85 value0, value1, result);
86 } else {
87 OH_LOG_ERROR(LOG_APP, "Main process - Child process not started");
88 }
89
90 napi_value sumNapi;
91 napi_create_int32(env, result, &sumNapi);
92 return sumNapi;
93 }
94
StartNativeChildProcess(napi_env env,napi_callback_info info)95 static napi_value StartNativeChildProcess(napi_env env, napi_callback_info info)
96 {
97 std::promise<int> promise;
98 g_promiseStartProcess = &promise;
99
100 size_t argc = 1;
101 napi_value args[1] = { nullptr };
102 napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
103
104 char libName[64];
105 size_t nameLen;
106 napi_get_value_string_utf8(env, args[0], libName, sizeof(libName), &nameLen);
107
108 int32_t ret = OH_Ability_CreateNativeChildProcess(libName, OnNativeChildProcessStarted);
109 OH_LOG_INFO(LOG_APP, "Main process - StartNativeChildProcess Lib:%{public}s ret:%{public}d", libName, ret);
110
111 if (ret == NCP_NO_ERROR) {
112 auto future = promise.get_future();
113 OH_LOG_INFO(LOG_APP, "Main process - Wait for call back");
114 ret = future.get();
115 }
116
117 g_promiseStartProcess = nullptr;
118 napi_value napiRet;
119 napi_create_int32(env, ret, &napiRet);
120 return napiRet;
121 }
122
RequestExitChildProcess(napi_env env,napi_callback_info info)123 static napi_value RequestExitChildProcess(napi_env env, napi_callback_info info)
124 {
125 int32_t ret = 0;
126 if (g_ipcProxyPnt != nullptr && g_ipcProxyPnt->RequestExitChildProcess()) {
127 ret = 1;
128 delete g_ipcProxyPnt;
129 g_ipcProxyPnt = nullptr;
130 OH_LOG_INFO(LOG_APP, "Main process - RequestExitChildProcess successed");
131
132 g_ipcProxyPntObjects.pop_back();
133 if (!g_ipcProxyPntObjects.empty()) {
134 OH_LOG_INFO(LOG_APP, "Main process - RequestExitChildProcess get g_ipcProxyPnt");
135 g_ipcProxyPnt = g_ipcProxyPntObjects.back();
136 }
137 }
138
139 napi_value napiRet;
140 napi_create_int32(env, ret, &napiRet);
141 return napiRet;
142 }
143
CallApiWithNullCallback(napi_env env,napi_callback_info info)144 static napi_value CallApiWithNullCallback(napi_env env, napi_callback_info info)
145 {
146 int32_t ret = OH_Ability_CreateNativeChildProcess("libentry.so", nullptr);
147 napi_value napiRet;
148 napi_create_int32(env, ret, &napiRet);
149 return napiRet;
150 }
151
CallApiWithNullLibName(napi_env env,napi_callback_info info)152 static napi_value CallApiWithNullLibName(napi_env env, napi_callback_info info)
153 {
154 int32_t ret = OH_Ability_CreateNativeChildProcess(nullptr, OnNativeChildProcessStarted);
155 napi_value napiRet;
156 napi_create_int32(env, ret, &napiRet);
157 return napiRet;
158 }
159
CallApiWithNull(napi_env env,napi_callback_info info)160 static napi_value CallApiWithNull(napi_env env, napi_callback_info info)
161 {
162 int32_t ret = OH_Ability_CreateNativeChildProcess(nullptr, nullptr);
163 napi_value napiRet;
164 napi_create_int32(env, ret, &napiRet);
165 return napiRet;
166 }
167
ChildProcessStartNewProcess(napi_env env,napi_callback_info info)168 static napi_value ChildProcessStartNewProcess(napi_env env, napi_callback_info info)
169 {
170 int32_t ret = INT32_MIN;
171 if (g_ipcProxyPnt != nullptr) {
172 ret = g_ipcProxyPnt->StartNativeChildProcess();
173 OH_LOG_INFO(LOG_APP, "Main process - StartNativeChildProcess ret:%{public}d", ret);
174 }
175
176 napi_value napiRet;
177 napi_create_int32(env, ret, &napiRet);
178 return napiRet;
179 }
180
BusyTest(napi_env env,napi_callback_info info)181 static napi_value BusyTest(napi_env env, napi_callback_info info)
182 {
183 napi_value napiRet;
184 std::promise<int> promise;
185 g_promiseStartProcess = &promise;
186 int32_t ret = OH_Ability_CreateNativeChildProcess("libbusytest.so", OnNativeChildProcessStarted);
187 if (ret != NCP_NO_ERROR) {
188 OH_LOG_INFO(LOG_APP, "Main process - StartNativeChildProcess for busy test failed! ret:%{public}d", ret);
189 napi_create_int32(env, ret, &napiRet);
190 return napiRet;
191 }
192
193 ret = OH_Ability_CreateNativeChildProcess("libentry.so", OnNativeChildProcessStarted);
194
195 auto future = promise.get_future();
196 OH_LOG_INFO(LOG_APP, "Main process - Wait for busy test call back");
197 future.wait();
198
199 g_promiseStartProcess = nullptr;
200 napi_create_int32(env, ret, &napiRet);
201 return napiRet;
202 }
203
StartChildWithArgs(NativeChildProcess_IsolationMode mode)204 static Ability_NativeChildProcess_ErrCode StartChildWithArgs(NativeChildProcess_IsolationMode mode)
205 {
206 int32_t pid = -1;
207 NativeChildProcess_Args args;
208 auto testParam = "testEntryParams";
209 args.entryParams = (char*)malloc(sizeof(char) * strlen(testParam) + 1);
210 (void)strcpy(args.entryParams, testParam);
211
212 auto fd1Name = "fd1";
213 args.fdList.head = (NativeChildProcess_Fd*)malloc(sizeof(NativeChildProcess_Fd));
214 args.fdList.head->fdName = (char*)malloc(sizeof(char) * strlen(fd1Name) + 1);
215 (void)strcpy(args.fdList.head->fdName, fd1Name);
216
217 auto path = "data/storage/el2/base/files/test.txt";
218 int32_t fd = open(path, O_RDWR | O_CREAT | O_TRUNC, 0644);
219 auto testString = "test";
220 write(fd, testString, strlen(testString));
221 close(fd);
222 fd = open(path, O_RDWR | O_TRUNC, 0644);
223 args.fdList.head->fd = fd;
224 args.fdList.head->next = NULL;
225
226 NativeChildProcess_Options options = {
227 .isolationMode = mode
228 };
229 OH_LOG_INFO(LOG_APP, "===================Ability_NativeChildProcess before");
230 Ability_NativeChildProcess_ErrCode ret = OH_Ability_StartNativeChildProcess(
231 "libentry.so:Main", args, options, &pid);
232 OH_LOG_INFO(LOG_APP, "===================Ability_NativeChildProcess_ErrCode: %{public}d", ret);
233 close(fd);
234 return ret;
235 }
236
StartChildWithNoArgs()237 static Ability_NativeChildProcess_ErrCode StartChildWithNoArgs()
238 {
239 int32_t pid = -1;
240 NativeChildProcess_Args args;
241 args.entryParams = NULL;
242 args.fdList.head = NULL;
243
244 NativeChildProcess_Options options = {
245 .isolationMode = NCP_ISOLATION_MODE_ISOLATED
246 };
247 OH_LOG_INFO(LOG_APP, "===================Ability_NativeChildProcess before");
248 Ability_NativeChildProcess_ErrCode ret = OH_Ability_StartNativeChildProcess(
249 "libentry.so:Main", args, options, &pid);
250 OH_LOG_INFO(LOG_APP, "===================Ability_NativeChildProcess_ErrCode: %{public}d", ret);
251 return ret;
252 }
253
StartChildIsolated(napi_env env,napi_callback_info info)254 static napi_value StartChildIsolated(napi_env env, napi_callback_info info)
255 {
256 OH_LOG_INFO(LOG_APP, "===================StartChildIsolated");
257 int32_t ret = static_cast<int32_t>(StartChildWithArgs(NCP_ISOLATION_MODE_ISOLATED));
258 napi_value napiRet;
259 napi_create_int32(env, ret, &napiRet);
260 return napiRet;
261 }
262
StartChildNormal(napi_env env,napi_callback_info info)263 static napi_value StartChildNormal(napi_env env, napi_callback_info info)
264 {
265 OH_LOG_INFO(LOG_APP, "===================StartChildNormal");
266 int32_t ret = static_cast<int32_t>(StartChildWithArgs(NCP_ISOLATION_MODE_NORMAL));
267 napi_value napiRet;
268 napi_create_int32(env, ret, &napiRet);
269 return napiRet;
270 }
271
272
StartChildNoArgs(napi_env env,napi_callback_info info)273 static napi_value StartChildNoArgs(napi_env env, napi_callback_info info)
274 {
275 OH_LOG_INFO(LOG_APP, "===================StartChildWithNoArgs");
276 int32_t ret = static_cast<int32_t>(StartChildWithNoArgs());
277 napi_value napiRet;
278 napi_create_int32(env, ret, &napiRet);
279 return napiRet;
280 }
281
282 EXTERN_C_START
Init(napi_env env,napi_value exports)283 static napi_value Init(napi_env env, napi_value exports)
284 {
285 napi_property_descriptor desc[] = {
286 { "childProcessAdd", nullptr, ChildProcessAdd, nullptr, nullptr, nullptr, napi_default, nullptr },
287 { "startNativeChildProcess", nullptr, StartNativeChildProcess,
288 nullptr, nullptr, nullptr, napi_default, nullptr },
289 { "requestExitChildProcess", nullptr, RequestExitChildProcess,
290 nullptr, nullptr, nullptr, napi_default, nullptr },
291 { "callApiWithNullCallback", nullptr, CallApiWithNullCallback,
292 nullptr, nullptr, nullptr, napi_default, nullptr },
293 { "callApiWithNullLibName", nullptr, CallApiWithNullLibName,
294 nullptr, nullptr, nullptr, napi_default, nullptr },
295 { "callApiWithNull", nullptr, CallApiWithNull,
296 nullptr, nullptr, nullptr, napi_default, nullptr },
297 { "childProcessStartNewProcess", nullptr, ChildProcessStartNewProcess,
298 nullptr, nullptr, nullptr, napi_default, nullptr },
299 { "busyTest", nullptr, BusyTest,
300 nullptr, nullptr, nullptr, napi_default, nullptr },
301 { "startChildIsolated", nullptr, StartChildIsolated,
302 nullptr, nullptr, nullptr, napi_default, nullptr },
303 { "startChildNormal", nullptr, StartChildNormal,
304 nullptr, nullptr, nullptr, napi_default, nullptr },
305 { "startChildNoArgs", nullptr, StartChildNoArgs,
306 nullptr, nullptr, nullptr, napi_default, nullptr }
307 };
308 napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc);
309 return exports;
310 }
311 EXTERN_C_END
312
313 static napi_module demoModule = {
314 .nm_version = 1,
315 .nm_flags = 0,
316 .nm_filename = nullptr,
317 .nm_register_func = Init,
318 .nm_modname = "entry",
319 .nm_priv = ((void*)0),
320 .reserved = { 0 },
321 };
322
RegisterEntryModule(void)323 extern "C" __attribute__((constructor)) void RegisterEntryModule(void)
324 {
325 napi_module_register(&demoModule);
326 }
327