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