文档管理中心
我的
您当前正在浏览新版开发者文档中心,目录分类和层级有所调整。点击左侧当前文档分类名称前的“☰”图标,可切换文档分类。 了解新版目录
指南与API参考指南应用框架Ability Kit(程序框架服务)应用模型进程模型扩展进程开发指导子进程开发指导(C/C++)

子进程开发指导(C/C++)

概述

在Native层多进程编程场景中,开发者常面临父子进程通信复杂、参数传递困难等问题。Native子进程机制允许应用通过C API创建子进程,支持IPC通信和参数传递,适用于需要高性能进程隔离和跨进程通信的场景。本模块提供了创建Native子进程、获取启动参数、终止子进程、获取子进程退出信息等能力,两种创建方式的接口选型和能力差异请参见子进程创建方式选择。

说明
  • 创建的子进程会随着父进程的退出而退出,无法脱离父进程独立运行。
  • 创建子进程前,可调用OH_Ability_IsNativeChildProcessSupported查询当前设备是否支持创建Native子进程。

子进程创建方式选择

展开
对比项 创建支持IPC通信的Native子进程 创建支持参数传递的Native子进程
涉及接口 OH_Ability_CreateNativeChildProcessWithConfigs20+ OH_Ability_StartNativeChildProcessWithConfigs20+
适用场景 适用于父子进程需要建立IPC通道通信的场景,如将高风险操作或独立业务逻辑隔离到子进程并通过IPC交互。 适用于需要向子进程传递参数(字符串、文件描述符)并由子进程执行计算任务的场景,如音视频编解码、数据处理等。
父子进程通信方式 IPC通道(子进程通过NativeChildProcess_OnConnect返回IPC Stub,主进程通过OHIPCRemoteProxy通信) 参数传递(通过NativeChildProcess_Args传入entryParams和fd列表,单向传参)
子进程入口函数 需实现并导出NativeChildProcess_OnConnect和NativeChildProcess_MainProc两个函数 需实现并导出以NativeChildProcess_Args为参数的入口函数(函数名可自定义)
启动结果获取 异步,通过onProcessStarted回调通知启动结果和IPC Proxy对象 同步,通过输出参数pid返回子进程号
是否依赖IPC Kit 是 否
子进程销毁方式 NativeChildProcess_MainProc返回后子进程退出 入口函数返回后子进程退出

创建支持IPC通信的Native子进程

通过OH_Ability_CreateNativeChildProcessWithConfigs接口异步创建Native子进程,子进程需实现并导出NativeChildProcess_OnConnect和NativeChildProcess_MainProc两个函数。子进程启动后先调用NativeChildProcess_OnConnect获取IPC Stub对象,再调用NativeChildProcess_MainProc移交主线程控制权,该函数返回后子进程随即退出。该方式对IPC Kit存在依赖。

  1. 添加动态库文件和头文件引用。

    在CMakeLists.txt文件中添加动态库文件。

    收起
    自动换行
    深色代码主题
    复制
    1. libipc_capi.so
    2. libchild_process.so

    在源文件中引入头文件。

    收起
    自动换行
    深色代码主题
    复制
    1. #include <IPCKit/ipc_kit.h>
    2. #include <AbilityKit/native_child_process.h>
  2. 在子进程中实现必要的导出方法。

    在子进程中,实现必要的两个函数NativeChildProcess_OnConnect及NativeChildProcess_MainProc并导出(假设代码所在的文件名为ChildProcessSample.cpp)。其中NativeChildProcess_OnConnect方法返回的OHIPCRemoteStub对象负责与主进程进行IPC通信,具体实现方法请参考IPC通信开发指导(C/C++),本文不再赘述。

    子进程启动后会先调用NativeChildProcess_OnConnect获取IPC Stub对象,之后再调用NativeChildProcess_MainProc移交主线程控制权,该函数返回后子进程随即退出。

    收起
    自动换行
    深色代码主题
    复制
    1. #include <IPCKit/ipc_kit.h>
    2. // ...
    3. #include <IPCKit/ipc_cremote_object.h>
    4. #include <IPCKit/ipc_cparcel.h>
    5. #include <IPCKit/ipc_error_code.h>
    6. class IpcCapiStubTest {
    7. public:
    8. explicit IpcCapiStubTest();
    9. ~IpcCapiStubTest();
    10. OHIPCRemoteStub *GetRemoteStub();
    11. static int OnRemoteRequest(uint32_t code, const OHIPCParcel *data, OHIPCParcel *reply, void *userData);
    12. private:
    13. OHIPCRemoteStub *stub_{nullptr};
    14. };
    15. IpcCapiStubTest::IpcCapiStubTest()
    16. {
    17. // 创建stub对象
    18. stub_ = OH_IPCRemoteStub_Create("testIpc", &IpcCapiStubTest::OnRemoteRequest, nullptr, this);
    19. }
    20. IpcCapiStubTest::~IpcCapiStubTest()
    21. {
    22. if (stub_ != nullptr) {
    23. OH_IPCRemoteStub_Destroy(stub_);
    24. }
    25. }
    26. OHIPCRemoteStub *IpcCapiStubTest::GetRemoteStub() { return stub_; }
    27. int IpcCapiStubTest::OnRemoteRequest(uint32_t code, const OHIPCParcel *data, OHIPCParcel *reply, void *userData)
    28. {
    29. return OH_IPC_SUCCESS;
    30. }
    31. IpcCapiStubTest g_ipcStubObj;
    32. extern "C" {
    33. OHIPCRemoteStub *NativeChildProcess_OnConnect()
    34. {
    35. // ipcRemoteStub指向子进程实现的ipc stub对象,用于接收来自主进程的IPC消息并响应
    36. // 子进程根据业务逻辑控制其生命周期
    37. return g_ipcStubObj.GetRemoteStub();
    38. }
    39. void NativeChildProcess_MainProc()
    40. {
    41. // 相当于子进程的Main函数,实现子进程的业务逻辑
    42. // ...
    43. // 函数返回后子进程随即退出
    44. }
    45. } // extern "C"
  3. 编译动态链接库。

    修改CMakeLists.txt文件,编译动态链接库(假设需要编译出的库文件名称为libchildprocesssample.so),并添加IPC动态库依赖。

    收起
    自动换行
    深色代码主题
    复制
    1. add_library(childprocesssample SHARED
    2. # 实现必要导出方法的源文件
    3. ChildProcessSample.cpp
    4. # 其它代码源文件
    5. # ...
    6. )
    7. target_link_libraries(childprocesssample PUBLIC
    8. # 添加依赖的IPC动态库
    9. libipc_capi.so
    10. # 其它所依赖的动态库
    11. # ...
    12. )
  4. 在主进程中实现子进程启动结果回调函数。

    收起
    自动换行
    深色代码主题
    复制
    1. #include <IPCKit/ipc_kit.h>
    2. #include <AbilityKit/native_child_process.h>
    3. // ···
    4. static void OnNativeChildProcessStarted(int errCode, OHIPCRemoteProxy *remoteProxy)
    5. {
    6. if (errCode != NCP_NO_ERROR) {
    7. // 子进程未能正常启动时的异常处理
    8. // ...
    9. return;
    10. }
    11. // 保存remoteProxy对象,后续基于IPC Kit提供的API同子进程间进行IPC通信
    12. // 耗时操作建议转移到独立线程去处理,避免长时间阻塞回调线程
    13. // IPC对象使用完毕后,需要调用OH_IPCRemoteProxy_Destroy方法释放
    14. // ···
    15. }

    回调函数传递的第二个参数OHIPCRemoteProxy对象,会与子进程实现的NativeChildProcess_OnConnect方法返回的OHIPCRemoteStub对象间建立IPC通道,具体使用方法参考IPC通信开发指导(C/C++),本文不再赘述;OHIPCRemoteProxy对象使用完毕后,需要调用OH_IPCRemoteProxy_Destroy函数释放。

  5. 在主进程中启动Native子进程。

    调用OH_Ability_CreateNativeChildProcessWithConfigs接口启动Native子进程,可通过OH_Ability_CreateChildProcessConfigs创建子进程配置信息对象,并按需设置进程名、隔离模式和uid隔离等。需注意返回值为NCP_NO_ERROR仅代表成功调用Native子进程启动逻辑,实际的启动结果通过回调函数异步通知。需注意仅允许在主进程中创建子进程。

    收起
    自动换行
    深色代码主题
    复制
    1. #include <IPCKit/ipc_kit.h>
    2. #include <AbilityKit/native_child_process.h>
    3. // ...
    4. int32_t g_result = -1;
    5. // ...
    6. static void OnNativeChildProcessStarted(int errCode, OHIPCRemoteProxy *remoteProxy)
    7. {
    8. if (errCode != NCP_NO_ERROR) {
    9. // 子进程未能正常启动时的异常处理
    10. // ...
    11. return;
    12. }
    13. // 保存remoteProxy对象,后续基于IPC Kit提供的API同子进程间进行IPC通信
    14. // 耗时操作建议转移到独立线程去处理,避免长时间阻塞回调线程
    15. // IPC对象使用完毕后,需要调用OH_IPCRemoteProxy_Destroy方法释放
    16. // ...
    17. }
    18. void CreateNativeChildProcess()
    19. {
    20. // 创建子进程配置信息对象
    21. Ability_ChildProcessConfigs *configs = OH_Ability_CreateChildProcessConfigs();
    22. // 设置子进程的进程名
    23. OH_Ability_ChildProcessConfigs_SetProcessName(configs, "childprocess_ipc");
    24. // 第一个参数"libchildprocesssample.so"为实现了子进程必要导出方法的动态库文件名称
    25. Ability_NativeChildProcess_ErrCode ret = OH_Ability_CreateNativeChildProcessWithConfigs("libchildprocesssample.so",
    26. configs, OnNativeChildProcessStarted);
    27. // configs对象使用完毕后需要销毁,避免内存泄漏
    28. OH_Ability_DestroyChildProcessConfigs(configs);
    29. if (ret != NCP_NO_ERROR) {
    30. // 子进程未能正常启动时的异常处理
    31. // ...
    32. }
    33. g_result = ret;
    34. }
  6. 为主进程添加编译依赖项。

    修改CMakeLists.txt添加必要的依赖库,假设主进程所在的so名称为libmainprocesssample.so(主进程和子进程的实现也可以选择编译到同一个动态库文件)。

    收起
    自动换行
    深色代码主题
    复制
    1. target_link_libraries(mainprocesssample PUBLIC
    2. # 添加依赖的IPC及元能力动态库
    3. libipc_capi.so
    4. libchild_process.so
    5. # 其它依赖的动态库
    6. # ...
    7. )

创建支持参数传递的Native子进程

通过OH_Ability_StartNativeChildProcessWithConfigs接口同步创建Native子进程,子进程需实现以NativeChildProcess_Args为参数的入口函数。通过NativeChildProcess_Args传入entryParams字符串和fd列表,入口函数返回后子进程自动退出。

  1. 添加动态库文件和头文件引用。

    在CMakeLists.txt文件中添加动态库文件。

    收起
    自动换行
    深色代码主题
    复制
    1. libchild_process.so

    在源文件中引入头文件。

    收起
    自动换行
    深色代码主题
    复制
    1. #include <AbilityKit/native_child_process.h>
  2. 在子进程中实现必要的导出方法。

    在子进程中,实现参数为NativeChildProcess_Args的入口函数并导出(假设代码所在的文件名为ChildProcessSample.cpp)。子进程启动后会调用该入口函数,该函数返回后子进程随即退出。

    收起
    自动换行
    深色代码主题
    复制
    1. #include <AbilityKit/native_child_process.h>
    2. #include <hilog/log.h>
    3. #include "loghelper.h"
    4. extern "C" {
    5. /**
    6. * 子进程的入口函数,实现子进程的业务逻辑
    7. * 函数名称可以自定义,在主进程调用OH_Ability_StartNativeChildProcessWithConfigs方法时指定,此示例中为Main
    8. * 函数返回后子进程退出
    9. */
    10. void Main(NativeChildProcess_Args args)
    11. {
    12. OH_LOG_INFO(LOG_APP, "Main started");
    13. // 获取传入的entryParams
    14. char *entryParams = args.entryParams;
    15. // 获取传入的fd列表
    16. NativeChildProcess_Fd *current = args.fdList.head;
    17. while (current != nullptr) {
    18. char *fdName = current->fdName;
    19. int32_t fd = current->fd;
    20. current = current->next;
    21. // 实现业务逻辑
    22. }
    23. }
    24. } // extern "C"
  3. 编译动态链接库。

    修改CMakeLists.txt文件,编译为动态链接库(假设需要编译出的库文件名称为libchildprocesssample.so),并添加元能力动态库依赖。

    收起
    自动换行
    深色代码主题
    复制
    1. add_library(childprocesssample SHARED
    2. # 实现必要导出方法的源文件
    3. ChildProcessSample.cpp
    4. # 其它代码源文件
    5. # ...
    6. )
    7. target_link_libraries(childprocesssample PUBLIC
    8. # 添加依赖的元能力动态库
    9. libchild_process.so
    10. # 其它所依赖的动态库
    11. # ...
    12. )
  4. 在主进程中启动Native子进程。

    调用OH_Ability_StartNativeChildProcessWithConfigs接口启动Native子进程,可通过OH_Ability_CreateChildProcessConfigs创建子进程配置信息对象,并按需设置进程名、隔离模式和uid隔离等。返回值为NCP_NO_ERROR代表成功启动Native子进程。

    收起
    自动换行
    深色代码主题
    复制
    1. #include <AbilityKit/native_child_process.h>
    2. #include <cstdlib>
    3. #include <cstring>
    4. #include <fcntl.h>
    5. // ...
    6. int32_t g_fdNameMaxLength = 20;
    7. void StartNativeChildProcess()
    8. {
    9. NativeChildProcess_Args args;
    10. // 设置entryParams
    11. const size_t entryParamsSize = 10;
    12. args.entryParams = (char *)malloc(sizeof(char) * entryParamsSize);
    13. if (args.entryParams != nullptr) {
    14. (void)strlcpy(args.entryParams, "testParam", entryParamsSize);
    15. }
    16. // 插入节点到链表头节点中
    17. args.fdList.head = (NativeChildProcess_Fd *)malloc(sizeof(NativeChildProcess_Fd));
    18. // fd关键字,最多不超过20个字符
    19. args.fdList.head->fdName = (char *)malloc(sizeof(char) * g_fdNameMaxLength);
    20. if (args.fdList.head->fdName != nullptr) {
    21. (void)strlcpy(args.fdList.head->fdName, "fd1", g_fdNameMaxLength);
    22. }
    23. // 获取fd逻辑
    24. int32_t fd = open("/data/storage/el2/base/haps/entry/files/test.txt", O_RDWR | O_CREAT, 0644);
    25. args.fdList.head->fd = fd;
    26. // 此处只插入一个fd记录,根据需求可以插入更多fd记录到链表中,最多不超过16个
    27. args.fdList.head->next = NULL;
    28. // 创建子进程配置信息对象
    29. Ability_ChildProcessConfigs *configs = OH_Ability_CreateChildProcessConfigs();
    30. // 设置子进程的进程名
    31. OH_Ability_ChildProcessConfigs_SetProcessName(configs, "child");
    32. // 第一个参数"libchildprocesssample.so:Main"为实现了子进程Main方法的动态库文件名称和入口方法名
    33. int32_t pid = -1;
    34. Ability_NativeChildProcess_ErrCode ret =
    35. OH_Ability_StartNativeChildProcessWithConfigs("libchildprocesssample.so:Main", args, configs, &pid);
    36. // configs对象使用完毕后需要销毁,避免内存泄漏
    37. OH_Ability_DestroyChildProcessConfigs(configs);
    38. if (ret != NCP_NO_ERROR) {
    39. // 释放NativeChildProcess_Args中的内存空间防止内存泄漏
    40. // 子进程未能正常启动时的异常处理
    41. // ...
    42. }
    43. // ...
    44. // 释放NativeChildProcess_Args中的内存空间防止内存泄漏
    45. }
  5. 为主进程添加编译依赖项。

    修改CMakeLists.txt添加必要的依赖库,假设主进程所在的so名称为libmainprocesssample.so(主进程和子进程的实现也可以选择编译到同一个动态库文件)。

    收起
    自动换行
    深色代码主题
    复制
    1. target_link_libraries(mainprocesssample PUBLIC
    2. # 添加依赖的元能力动态库
    3. libchild_process.so
    4. # 其它依赖的动态库
    5. # ...
    6. )

子进程获取启动参数

从API version 17开始,支持子进程获取启动参数。

  1. 添加动态库文件和头文件引用。

    在CMakeLists.txt文件中添加动态库文件。

    收起
    自动换行
    深色代码主题
    复制
    1. libchild_process.so

    在源文件中引入头文件。

    收起
    自动换行
    深色代码主题
    复制
    1. #include <AbilityKit/native_child_process.h>
  2. 在子进程中获取启动参数。

    OH_Ability_StartNativeChildProcessWithConfigs创建子进程后,子进程内的任意so和任意子线程可以通过调用OH_Ability_GetCurrentChildProcessArgs()获取到子进程的启动参数NativeChildProcess_Args,便于操作相关的文件描述符。

    收起
    自动换行
    深色代码主题
    复制
    1. #include <AbilityKit/native_child_process.h>
    2. #include <thread>
    3. extern "C" {
    4. void ThreadFunc()
    5. {
    6. // 获取子进程的启动参数
    7. NativeChildProcess_Args *args = OH_Ability_GetCurrentChildProcessArgs();
    8. // 获取启动参数失败时返回nullptr
    9. if (args == nullptr) {
    10. return;
    11. }
    12. // 获取启动参数中的entryParams
    13. char *entryParams = args->entryParams;
    14. // 获取fd列表
    15. NativeChildProcess_Fd *current = args->fdList.head;
    16. while (current != nullptr) {
    17. char *fdName = current->fdName;
    18. int32_t fd = current->fd;
    19. current = current->next;
    20. // 实现业务逻辑
    21. }
    22. }
    23. /**
    24. * 子进程的入口函数,实现子进程的业务逻辑
    25. * args是子进程的启动参数
    26. */
    27. void Main(NativeChildProcess_Args args)
    28. {
    29. // 实现业务逻辑
    30. // 创建线程
    31. std::thread tObj(ThreadFunc);
    32. }
    33. } // extern "C"

终止子进程

从API version 22开始,支持根据传入的pid终止当前进程创建的Native子进程或ArkTS子进程。

  1. 添加动态库文件和头文件引用。

    在CMakeLists.txt文件中添加动态库文件。

    收起
    自动换行
    深色代码主题
    复制
    1. libchild_process.so

    在源文件中引入头文件。

    收起
    自动换行
    深色代码主题
    复制
    1. #include <AbilityKit/native_child_process.h>
  2. 实现终止子进程。

    通过native_child_process和childProcessManager(非SELF_FORK模式)中的接口创建子进程后,主进程可以调用OH_Ability_KillChildProcess(int32_t pid)根据传入的pid终止相应的子进程。

    收起
    自动换行
    深色代码主题
    复制
    1. #include <AbilityKit/native_child_process.h>
    2. // ...
    3. void KillChildProcess(int32_t pid)
    4. {
    5. Ability_NativeChildProcess_ErrCode ret = OH_Ability_KillChildProcess(pid);
    6. if (ret != NCP_NO_ERROR) {
    7. // 子进程未成功杀死的异常处理
    8. }
    9. // ...
    10. }

获取Native子进程退出信息

从API version 20开始,支持父进程通过注册回调函数监听子进程,获取子进程异常退出信息,以便父进程做后续优化处理。这里支持监听的子进程必须为OH_Ability_StartNativeChildProcess、OH_Ability_StartNativeChildProcessWithConfigs或startNativeChildProcess接口创建的子进程。

  1. 添加动态库文件和头文件引用。

    在CMakeLists.txt文件中添加动态库文件。

    收起
    自动换行
    深色代码主题
    复制
    1. libchild_process.so

    在源文件中引入头文件。

    收起
    自动换行
    深色代码主题
    复制
    1. #include <AbilityKit/native_child_process.h>
  2. 注册和解注册Native子进程异常退出回调。

    调用OH_Ability_RegisterNativeChildProcessExitCallback注册Native子进程,如果返回值为NCP_NO_ERROR表示注册成功。

    调用OH_Ability_UnregisterNativeChildProcessExitCallback解注册Native子进程,如果返回值为NCP_NO_ERROR表示解注册成功。

    收起
    自动换行
    深色代码主题
    复制
    1. #include <AbilityKit/native_child_process.h>
    2. #include <hilog/log.h>
    3. // ...
    4. void OnNativeChildProcessExit(int32_t pid, int32_t signal)
    5. {
    6. OH_LOG_INFO(LOG_APP, "pid: %{public}d, signal: %{public}d", pid, signal);
    7. }
    8. void RegisterNativeChildProcessExitCallback()
    9. {
    10. Ability_NativeChildProcess_ErrCode ret =
    11. OH_Ability_RegisterNativeChildProcessExitCallback(OnNativeChildProcessExit);
    12. if (ret != NCP_NO_ERROR) {
    13. OH_LOG_ERROR(LOG_APP, "register failed.");
    14. }
    15. // ...
    16. }
    17. void UnregisterNativeChildProcessExitCallback()
    18. {
    19. Ability_NativeChildProcess_ErrCode ret =
    20. OH_Ability_UnregisterNativeChildProcessExitCallback(OnNativeChildProcessExit);
    21. if (ret != NCP_NO_ERROR) {
    22. OH_LOG_ERROR(LOG_APP, "unregister failed.");
    23. }
    24. // ...
    25. }
  3. 添加编译依赖项。

    修改CMakeLists.txt添加必要的依赖库,假设主进程所在的so名称为libmainprocesssample.so(主进程和子进程的实现也可以选择编译到同一个动态库文件)。

    收起
    自动换行
    深色代码主题
    复制
    1. target_link_libraries(mainprocesssample PUBLIC
    2. # 添加依赖的元能力动态库
    3. libchild_process.so
    4. # 其它依赖的动态库
    5. # ...
    6. )