• 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 "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