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