• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Native子进程开发指导(C/C++)
2
3本模块提供了两种创建子进程的方式,开发者可根据需要进行选择。
4- [创建支持IPC回调的子进程](#创建支持ipc回调的子进程):创建子进程,并在父子进程间建立IPC通道,适用于父子进程需要IPC通信的场景。对[IPCKit](../ipc/ipc-capi-development-guideline.md)存在依赖。
5- [创建支持参数传递的子进程](#创建支持参数传递的子进程):创建子进程,并传递字符串和fd句柄参数到子进程。适用于需要传递参数到子进程的场景。
6
7
8## 创建支持IPC回调的子进程
9
10### 场景介绍
11
12本章节介绍如何在主进程中创建Native子进程,并在父子进程间建立IPC通道,方便开发者在Native层进行多进程编程。
13
14### 接口说明
15
16| 名称                                                                                                                                                                                                                                                                                                                                | 描述                                                                                    |
17| --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------- |
18| int [OH_Ability_CreateNativeChildProcess](../reference/apis-ability-kit/c-apis-ability-childprocess.md#oh_ability_createnativechildprocess) (const char *libName, [OH_Ability_OnNativeChildProcessStarted](../reference/apis-ability-kit/c-apis-ability-childprocess.md#oh_ability_onnativechildprocessstarted) onProcessStarted) | 创建子进程并加载参数中指定的动态链接库文件,进程启动结果通过回调参数异步通知,需注意回调通知为独立线程,回调函数实现需要注意线程同步,且不能执行高耗时操作避免长时间阻塞。 |
19
20> **说明:**
21>
22> 当前仅支持2in1设备。
23> 从API version 15开始,单个进程最多支持启动50个Native子进程。API version 14及之前版本,单个进程只能启动1个Native子进程。
24
25### 开发步骤
26
27基于已创建完成的Native应用开发工程,在此基础上介绍如何使用`AbilityKit`提供的C API接口,创建Native子进程,并同时在父子进程间建立IPC通道。
28
29**动态库文件**
30
31```txt
32libipc_capi.so
33libchild_process.so
34```
35
36**头文件**
37
38```c++
39#include <IPCKit/ipc_kit.h>
40#include <AbilityKit/native_child_process.h>
41```
42
431. 子进程-实现必要的导出方法。
44
45    在子进程中,实现必要的两个函数**NativeChildProcess_OnConnect**及**NativeChildProcess_MainProc**并导出(假设代码所在的文件名为ChildProcessSample.cpp)。其中NativeChildProcess_OnConnect方法返回的OHIPCRemoteStub对象负责主进程进行IPC通信,具体实现方法请参考[IPC通信开发指导(C/C++)](../ipc/ipc-capi-development-guideline.md),本文不再赘述。
46
47    子进程启动后会先调用NativeChildProcess_OnConnect获取IPC Stub对象,之后再调用NativeChildProcess_MainProc移交主线程控制权,该函数返回后子进程随即退出。
48
49    ```c++
50    #include <IPCKit/ipc_kit.h>
51
52    extern "C" {
53
54    OHIPCRemoteStub* NativeChildProcess_OnConnect()
55    {
56        // ipcRemoteStub指向子进程实现的ipc stub对象,用于接收来自主进程的IPC消息并响应
57        // 子进程根据业务逻辑控制其生命周期
58        return ipcRemoteStub;
59    }
60
61    void NativeChildProcess_MainProc()
62    {
63        // 相当于子进程的Main函数,实现子进程的业务逻辑
64        // ...
65        // 函数返回后子进程随即退出
66    }
67
68    } // extern "C"
69    ```
70
712. 子进程-编译为动态链接库。
72
73    修改CMakeList.txt文件,编译为动态链接库(假设需要编译出的库文件名称为libchildprocesssample.so),并添加IPC动态库依赖。
74
75    ```txt
76    add_library(childprocesssample SHARED
77        # 实现必要导出方法的源文件
78        ChildProcessSample.cpp
79
80        # 其它代码源文件
81        # ...
82    )
83
84    target_link_libraries(childprocesssample PUBLIC
85        # 添加依赖的IPC动态库
86        libipc_capi.so
87       
88        # 其它所依赖的动态库
89        # ...
90    )
91    ```
92
933. 主进程-实现子进程启动结果回调函数。
94
95    ```c++
96    #include <IPCKit/ipc_kit.h>
97
98    static void OnNativeChildProcessStarted(int errCode, OHIPCRemoteProxy *remoteProxy)
99    {
100        if (errCode != NCP_NO_ERROR) {
101            // 子进程未能正常启动时的异常处理
102            // ...
103            return;
104        }
105
106        // 保存remoteProxy对象,后续基于IPC Kit提供的API同子进程间进行IPC通信
107        // 耗时操作建议转移到独立线程去处理,避免长时间阻塞回调线程
108        // IPC对象使用完毕后,需要调用OH_IPCRemoteProxy_Destroy方法释放
109        // ...
110    }
111    ```
112
113    回调函数传递的第二个参数OHIPCRemoteProxy对象,会与子进程实现的**NativeChildProcess_OnConnect**方法返回的OHIPCRemoteStub对象间建立IPC通道,具体使用方法参考[IPC通信开发指导(C/C++)](../ipc/ipc-capi-development-guideline.md),本文不再赘述;OHIPCRemoteProxy对象使用完毕后,需要调用[OH_IPCRemoteProxy_Destroy](../reference/apis-ipc-kit/_o_h_i_p_c_remote_object.md#oh_ipcremoteproxy_destroy)函数释放。
114
1154. 主进程-启动Native子进程。
116
117    调用API启动Native子进程,需要注意返回值为NCP_NO_ERROR仅代表成功调用native子进程启动逻辑,实际的启动结果通过第二个参数中指定的回调函数异步通知。需注意**仅允许在主进程中创建子进程**。
118
119    ```c++
120    #include <AbilityKit/native_child_process.h>
121
122    // 第一个参数"libchildprocesssample.so"为实现了子进程必要导出方法的动态库文件名称
123    int32_t ret = OH_Ability_CreateNativeChildProcess("libchildprocesssample.so", OnNativeChildProcessStarted);
124    if (ret != NCP_NO_ERROR) {
125        // 子进程未能正常启动时的异常处理
126        // ...
127    }
128    ```
129
1305. 主进程-添加编译依赖项。
131
132    修改CMaklist.txt添加必要的依赖库,假设主进程所在的so名称为libmainprocesssample.so(主进程和子进程的实现也可以选择编译到同一个动态库文件)。
133
134    ```txt
135    target_link_libraries(mainprocesssample PUBLIC
136        # 添加依赖的IPC及元能力动态库
137        libipc_capi.so
138        libchild_process.so
139       
140        # 其它依赖的动态库
141        # ...
142    )
143    ```
144
145## 创建支持参数传递的子进程
146
147### 场景介绍
148
149本章节介绍如何创建Native子进程,并传递参数到子进程。
150
151### 接口说明
152
153| 名称                                                                                                                                                                                                                                                                                                                                | 描述                                                                                    |
154| --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------- |
155| [Ability_NativeChildProcess_ErrCode](../reference/apis-ability-kit/c-apis-ability-childprocess.md#ability_nativechildprocess_errcode) [OH_Ability_StartNativeChildProcess](../reference/apis-ability-kit/c-apis-ability-childprocess.md#oh_ability_startnativechildprocess) (const char \*entry, [NativeChildProcess_Args](../reference/apis-ability-kit/c-apis-ability-childprocess.md#nativechildprocess_args) args, [NativeChildProcess_Options](../reference/apis-ability-kit/c-apis-ability-childprocess.md#nativechildprocess_options) options, int32_t *pid) | 启动子进程并返回子进程pid。 |
156
157### 开发步骤
158
159
160**动态库文件**
161
162```txt
163libchild_process.so
164```
165
166**头文件**
167
168```c++
169#include <AbilityKit/native_child_process.h>
170```
171
1721. 子进程-实现必要的导出方法。
173
174    在子进程中,实现参数为[NativeChildProcess_Args](../reference/apis-ability-kit/c-apis-ability-childprocess.md#nativechildprocess_args)入口函数并导出(假设代码所在的文件名为ChildProcessSample.cpp)。子进程启动后会调用该入口函数,该函数返回后子进程随即退出。
175
176    ```c++
177    #include <AbilityKit/native_child_process.h>
178
179    extern "C" {
180
181    /**
182     * 子进程的入口函数,实现子进程的业务逻辑
183     * 函数名称可以自定义,在主进程调用OH_Ability_StartNativeChildProcess方法时指定,此示例中为Main
184     * 函数返回后子进程退出
185     */
186    void Main(NativeChildProcess_Args args)
187    {
188        // 获取传入的entryPrams
189        char *entryParams = args.entryParams;
190        // 获取传入的fd列表
191        NativeChildProcess_Fd *current = args.fdList.head;
192        while (current != nullptr) {
193            char *fdName = current->fdName;
194            int32_t fd = current->fd;
195            current = current->next;
196            // 业务逻辑..
197        }
198    }
199    } // extern "C"
200    ```
201
2022. 子进程-编译为动态链接库。
203
204    修改CMakeList.txt文件,编译为动态链接库(假设需要编译出的库文件名称为libchildprocesssample.so),并添加元能力动态库依赖。
205
206    ```txt
207    add_library(childprocesssample SHARED
208        # 实现必要导出方法的源文件
209        ChildProcessSample.cpp
210
211        # 其它代码源文件
212        # ...
213    )
214
215    target_link_libraries(childprocesssample PUBLIC
216        # 添加依赖的元能力动态库
217        libchild_process.so
218
219        # 其它所依赖的动态库
220        # ...
221    )
222    ```
223
2243. 主进程-启动Native子进程。
225
226    调用API启动Native子进程,返回值为NCP_NO_ERROR代表成功启动native子进程。
227
228    ```c++
229    #include <AbilityKit/native_child_process.h>
230    #include <stdlib.h>
231    #include <string.h>
232    #include <fcntl.h>
233
234    void startNativeChildProcess()
235    {
236        // ...
237        NativeChildProcess_Args args;
238        // 设置entryParams,支持传输的最大数据量为150KB
239        args.entryParams = (char*)malloc(sizeof(char) * 10);
240        (void)strcpy(args.entryParams, "testParam");
241
242        // 插入节点到链表头节点中
243        args.fdList.head = (NativeChildProcess_Fd*)malloc(sizeof(NativeChildProcess_Fd));
244        // fd关键字,最多不超过20个字符
245        args.fdList.head->fdName = (char*)malloc(sizeof(char) * 4);
246        (void)strcpy(args.fdList.head->fdName, "fd1");
247        // 获取fd逻辑
248        int32_t fd = open("/data/storage/el2/base/haps/entry/files/test.txt", O_RDWR | O_CREAT, 0644);
249        args.fdList.head->fd = fd;
250        // 此处只插入一个fd记录,根据需求可以插入更多fd记录到链表中,最多不超过16个
251        args.fdList.head->next = NULL;
252        NativeChildProcess_Options options = {
253            .isolationMode = NCP_ISOLATION_MODE_ISOLATED
254        };
255
256        // 第一个参数"libchildprocesssample.so:Main"为实现了子进程Main方法的动态库文件名称和入口方法名
257        int32_t pid = -1;
258        Ability_NativeChildProcess_ErrCode ret = OH_Ability_StartNativeChildProcess(
259            "libchildprocesssample.so:Main", args, options, &pid);
260        if (ret != NCP_NO_ERROR) {
261            // 释放NativeChildProcess_Args中的内存空间防止内存泄漏
262            // 子进程未能正常启动时的异常处理
263            // ...
264        }
265
266        // 其他逻辑
267        // ...
268
269        // 释放NativeChildProcess_Args中的内存空间防止内存泄漏
270    }
271    ```
272
2734. 主进程-添加编译依赖项。
274
275    修改CMaklist.txt添加必要的依赖库,假设主进程所在的so名称为libmainprocesssample.so(主进程和子进程的实现也可以选择编译到同一个动态库文件)。
276
277    ```txt
278    target_link_libraries(mainprocesssample PUBLIC
279        # 添加依赖的元能力动态库
280        libchild_process.so
281       
282        # 其它依赖的动态库
283        # ...
284    )
285    ```
286
287## 子进程获取启动参数
288
289### 场景介绍
290
291从API version 17开始,支持子进程获取启动参数。
292
293### 接口说明
294
295| 名称                                                                                                                                                                                                                                                                                                                                | 描述                                                                                    |
296| --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------- |
297| [NativeChildProcess_Args](../reference/apis-ability-kit/c-apis-ability-childprocess.md#nativechildprocess_args)* [OH_Ability_GetCurrentChildProcessArgs](../reference/apis-ability-kit/c-apis-ability-childprocess.md#oh_ability_startnativechildprocess)() | 返回子进程自身的启动参数。 |
298
299### 开发步骤
300
301
302**动态库文件**
303
304```txt
305libchild_process.so
306```
307
308**头文件**
309
310```c++
311#include <AbilityKit/native_child_process.h>
312```
313
314**获取启动参数**
315
316[OH_Ability_StartNativeChildProcess](../reference/apis-ability-kit/c-apis-ability-childprocess.md#oh_ability_startnativechildprocess)创建子进程后,子进程内的任意so和任意子线程可以通过调用[OH_Ability_GetCurrentChildProcessArgs](../reference/apis-ability-kit/c-apis-ability-childprocess.md#oh_ability_startnativechildprocess)()获取到子进程的启动参数[NativeChildProcess_Args](../reference/apis-ability-kit/c-apis-ability-childprocess.md#nativechildprocess_args),便于操作相关的文件描述符。
317
318```c++
319#include <AbilityKit/native_child_process.h>
320#include <thread>
321
322extern "C" {
323
324void ThreadFunc()
325{
326    // 获取子进程的启动参数
327    NativeChildProcess_Args *args = OH_Ability_GetCurrentChildProcessArgs();
328    // 获取启动参数失败时返回nullptr
329    if (args == nullptr) {
330        return;
331    }
332    // 获取启动参数中的entryPrams
333    char *entryParams = args.entryParams;
334    // 获取fd列表
335    NativeChildProcess_Fd *current = args.fdList.head;
336    while (current != nullptr) {
337        char *fdName = current->fdName;
338        int32_t fd = current->fd;
339        current = current->next;
340        // 业务逻辑..
341    }
342}
343
344/**
345 * 子进程的入口函数,实现子进程的业务逻辑
346 * args是子进程的启动参数
347 */
348void Main(NativeChildProcess_Args args)
349{
350    // 业务逻辑..
351
352    // 创建线程
353    std::thread tObj(ThreadFunc);
354}
355
356} // extern "C"
357```
358
359