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