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