IPC与RPC通信开发指导(C/C++)
场景介绍
IPC让运行在不同进程间的Proxy和Stub实现互相通信。IPC CAPI是IPC Kit提供的C语言接口。
IPC CAPI接口不直接提供获取通信代理对象的能力,该功能由Ability Kit提供。

进程间IPC通道的建立,请参考Native子进程开发指导(C/C++)。本文重点介绍IPC CAPI的使用。
接口说明
表1 IPC CAPI侧关键接口
| 接口名 | 描述 |
|---|---|
| typedef int (*OH_OnRemoteRequestCallback) (uint32_t code, const OHIPCParcel *data, OHIPCParcel *reply, void *userData); | Stub端用于处理远端数据请求的回调函数。 |
| OHIPCRemoteStub* OH_IPCRemoteStub_Create (const char *descriptor, OH_OnRemoteRequestCallback requestCallback, OH_OnRemoteDestroyCallback destroyCallback, void *userData); | 创建OHIPCRemoteStub对象。 |
| int OH_IPCRemoteProxy_SendRequest(const OHIPCRemoteProxy *proxy, uint32_t code, const OHIPCParcel *data, OHIPCParcel *reply, const OH_IPC_MessageOption *option); | IPC消息发送函数。 |
| struct OHIPCRemoteProxy; | 用于向远端发送请求的OHIPCRemoteProxy对象,需要依赖元能力接口返回。 |
| OHIPCDeathRecipient* OH_IPCDeathRecipient_Create (OH_OnDeathRecipientCallback deathRecipientCallback, OH_OnDeathRecipientDestroyCallback destroyCallback, void *userData); | 创建用于监听远端OHIPCRemoteStub对象死亡的通知对象(OHIPCDeathRecipient对象)。 |
| int OH_IPCRemoteProxy_AddDeathRecipient(OHIPCRemoteProxy *proxy, OHIPCDeathRecipient *recipient); | 向OHIPCRemoteProxy对象注册死亡监听,用于接收远端OHIPCRemoteStub对象死亡时的回调通知。 |
详细的接口说明请参考IPCKit。
开发步骤
先创建服务端Stub对象,通过元能力获取其客户端代理Proxy对象,然后用Proxy对象与服务端Stub对象进行IPC通信,同时再注册远端对象的死亡通知回调,用于Proxy侧感知服务端Stub对象所在进程的死亡状态。
动态库文件
CMakeLists.txt中添加以下lib。
# ipc capi
libipc_capi.so
# 元能力,ability capi
libchild_process.so
头文件
#include <IPCKit/ipc_kit.h>
#include <AbilityKit/native_child_process.h>
子进程实现
#include <IPCKit/ipc_kit.h>
// ...
#include <IPCKit/ipc_cremote_object.h>
#include <IPCKit/ipc_cparcel.h>
#include <IPCKit/ipc_error_code.h>
class IpcCapiStubTest {
public:
explicit IpcCapiStubTest();
~IpcCapiStubTest();
OHIPCRemoteStub *GetRemoteStub();
static int OnRemoteRequest(uint32_t code, const OHIPCParcel *data, OHIPCParcel *reply, void *userData);
private:
OHIPCRemoteStub *stub_{nullptr};
};
IpcCapiStubTest::IpcCapiStubTest()
{
// 创建stub对象
stub_ = OH_IPCRemoteStub_Create("testIpc", &IpcCapiStubTest::OnRemoteRequest, nullptr, this);
}
IpcCapiStubTest::~IpcCapiStubTest()
{
if (stub_ != nullptr) {
OH_IPCRemoteStub_Destroy(stub_);
}
}
OHIPCRemoteStub *IpcCapiStubTest::GetRemoteStub() { return stub_; }
int IpcCapiStubTest::OnRemoteRequest(uint32_t code, const OHIPCParcel *data, OHIPCParcel *reply, void *userData)
{
return OH_IPC_SUCCESS;
}
IpcCapiStubTest g_ipcStubObj;
extern "C" {
OHIPCRemoteStub *NativeChildProcess_OnConnect()
{
// ipcRemoteStub指向子进程实现的ipc stub对象,用于接收来自主进程的IPC消息并响应
// 子进程根据业务逻辑控制其生命周期
return g_ipcStubObj.GetRemoteStub();
}
void NativeChildProcessMainProc()
{
// 相当于子进程的Main函数,实现子进程的业务逻辑
// ...
// 函数返回后子进程随即退出
}
} // extern "C"
主进程实现
#include <IPCKit/ipc_kit.h>
#include <AbilityKit/native_child_process.h>
// ...
static void OnNativeChildProcessStarted(int errCode, OHIPCRemoteProxy *remoteProxy)
{
if (errCode != NCP_NO_ERROR) {
// 子进程未能正常启动时的异常处理
// ...
return;
}
// 保存remoteProxy对象,后续基于IPC Kit提供的API同子进程间进行IPC通信
// 耗时操作建议转移到独立线程去处理,避免长时间阻塞回调线程
// IPC对象使用完毕后,需要调用OH_IPCRemoteProxy_Destroy方法释放
// ...
}
void CreateNativeChildProcess()
{
// 第一个参数"libchildprocesssample.so"为实现了子进程必要导出方法的动态库文件名称
int32_t ret = OH_Ability_CreateNativeChildProcess("libchildprocesssample.so", OnNativeChildProcessStarted);
if (ret != NCP_NO_ERROR) {
// 子进程未能正常启动时的异常处理
// ...
}
g_result = ret;
}
Proxy侧实现
#include "IpcProxy.h"
#include <IPCKit/ipc_error_code.h>
#include "Ipchelper.h"
IpcProxy::IpcProxy(OHIPCRemoteProxy *ipcProxy)
: ipcProxy_(ipcProxy)
{
}
IpcProxy::~IpcProxy()
{
if (ipcProxy_ != nullptr) {
OH_IPCRemoteProxy_Destroy(ipcProxy_);
}
}
bool IpcProxy::RequestExitChildProcess(int32_t exitCode)
{
if (ipcProxy_ == nullptr) {
return false;
}
StdUniPtrIpcParcel data(OH_IPCParcel_Create(), OH_IPCParcel_Destroy);
StdUniPtrIpcParcel reply(OH_IPCParcel_Create(), OH_IPCParcel_Destroy);
if (data == nullptr || reply == nullptr) {
return false;
}
if (!WriteInterfaceToken(data.get()) ||
OH_IPCParcel_WriteInt32(data.get(), exitCode) != OH_IPC_SUCCESS) {
return false;
}
OH_IPC_MessageOption ipcOpt;
ipcOpt.mode = OH_IPC_REQUEST_MODE_SYNC;
ipcOpt.timeout = 0;
ipcOpt.reserved = nullptr;
int ret = OH_IPCRemoteProxy_SendRequest(ipcProxy_, IPC_ID_REQUEST_EXIT_PROCESS, data.get(), reply.get(), &ipcOpt);
if (ret != OH_IPC_SUCCESS) {
return false;
}
return true;
}
int32_t IpcProxy::Add(int32_t a, int32_t b)
{
if (ipcProxy_ == nullptr) {
return INT32_MIN;
}
int32_t result = INT32_MIN;
StdUniPtrIpcParcel data(OH_IPCParcel_Create(), OH_IPCParcel_Destroy);
StdUniPtrIpcParcel reply(OH_IPCParcel_Create(), OH_IPCParcel_Destroy);
if (data == nullptr || reply == nullptr) {
return result;
}
if (!WriteInterfaceToken(data.get()) ||
OH_IPCParcel_WriteInt32(data.get(), a) != OH_IPC_SUCCESS ||
OH_IPCParcel_WriteInt32(data.get(), b) != OH_IPC_SUCCESS) {
return result;
}
OH_IPC_MessageOption ipcOpt;
ipcOpt.mode = OH_IPC_REQUEST_MODE_SYNC;
ipcOpt.timeout = 0;
ipcOpt.reserved = nullptr;
int ret = OH_IPCRemoteProxy_SendRequest(ipcProxy_, IPC_ID_ADD, data.get(), reply.get(), &ipcOpt);
if (ret != OH_IPC_SUCCESS) {
return result;
}
OH_IPCParcel_ReadInt32(reply.get(), &result);
return result;
}
int32_t IpcProxy::StartNativeChildProcess()
{
if (ipcProxy_ == nullptr) {
return INT32_MIN;
}
int32_t result = INT32_MIN;
StdUniPtrIpcParcel data(OH_IPCParcel_Create(), OH_IPCParcel_Destroy);
StdUniPtrIpcParcel reply(OH_IPCParcel_Create(), OH_IPCParcel_Destroy);
if (data == nullptr || reply == nullptr) {
return result;
}
if (!WriteInterfaceToken(data.get())) {
return result;
}
OH_IPC_MessageOption ipcOpt;
ipcOpt.mode = OH_IPC_REQUEST_MODE_SYNC;
ipcOpt.timeout = 0;
ipcOpt.reserved = nullptr;
int ret = OH_IPCRemoteProxy_SendRequest(
ipcProxy_, IPC_ID_START_NATIVE_CHILD_PROCESS, data.get(), reply.get(), &ipcOpt);
if (ret != OH_IPC_SUCCESS) {
return result;
}
OH_IPCParcel_ReadInt32(reply.get(), &result);
return result;
}
bool IpcProxy::WriteInterfaceToken(OHIPCParcel* data)
{
return OH_IPCParcel_WriteInterfaceToken(data, interfaceToken_) == OH_IPC_SUCCESS;
}
Stub侧实现
#include "IpcStub.h"
#include <IPCKit/ipc_error_code.h>
#include <cstring>
#include <new>
IpcStub::IpcStub()
{
ipcStub_ = OH_IPCRemoteStub_Create("NativeChildIPCStubSample",
IpcStub::OnRemoteRequest, IpcStub::OnRemoteObjectDestroy, this);
}
IpcStub::~IpcStub()
{
OH_IPCRemoteStub_Destroy(ipcStub_);
}
OHIPCRemoteStub* IpcStub::GetIpcStub()
{
return ipcStub_;
}
void IpcStub::OnRemoteObjectDestroy(void *userData)
{
}
int IpcStub::OnRemoteRequest(uint32_t code, const OHIPCParcel *data, OHIPCParcel *reply, void *userData)
{
if (userData == nullptr) {
return OH_IPC_CHECK_PARAM_ERROR;
}
if (!CheckInterfaceToken(data)) {
return OH_IPC_CHECK_PARAM_ERROR;
}
int ret;
IpcStub *thiz = reinterpret_cast<IpcStub*>(userData);
switch (code) {
case IPC_ID_REQUEST_EXIT_PROCESS:
ret = thiz->HandleRequestExitChildProcess(data, reply);
break;
case IPC_ID_ADD:
ret = thiz->HandleAdd(data, reply);
break;
case IPC_ID_START_NATIVE_CHILD_PROCESS:
ret = thiz->HandleStartNativeChildProcess(data, reply);
break;
default:
ret = OH_IPC_CODE_OUT_OF_RANGE;
break;
}
return ret;
}
void* IpcStub::OnIpcMemAlloc(int32_t len)
{
// limit ipc memory alloc size to 128 bytes
if (len > 128) {
return nullptr;
}
return new (std::nothrow) char[len];
}
void IpcStub::ReleaseIpcMem(void* ipcMem)
{
delete[] reinterpret_cast<char*>(ipcMem);
}
bool IpcStub::CheckInterfaceToken(const OHIPCParcel* data)
{
char *token;
int32_t tokenLen;
int ret = OH_IPCParcel_ReadInterfaceToken(data, &token, &tokenLen, IpcStub::OnIpcMemAlloc);
if (ret != OH_IPC_SUCCESS) {
return false;
}
bool tokenCheckRes = strcmp(token, interfaceToken_) == 0;
ReleaseIpcMem(token);
return tokenCheckRes;
}
int IpcStub::HandleRequestExitChildProcess(const OHIPCParcel *data, OHIPCParcel *reply)
{
int exitCode = 0;
if (OH_IPCParcel_ReadInt32(data, &exitCode) != OH_IPC_SUCCESS) {
return OH_IPC_PARCEL_READ_ERROR;
}
int32_t ret = RequestExitChildProcess(exitCode) ? 1 : 0;
return OH_IPCParcel_WriteInt32(reply, ret);
}
int32_t IpcStub::HandleAdd(const OHIPCParcel *data, OHIPCParcel *reply)
{
int32_t a = 0;
int32_t b = 0;
if (OH_IPCParcel_ReadInt32(data, &a) != OH_IPC_SUCCESS ||
OH_IPCParcel_ReadInt32(data, &b) != OH_IPC_SUCCESS) {
return OH_IPC_PARCEL_READ_ERROR;
}
int32_t result = Add(a, b);
if (OH_IPCParcel_WriteInt32(reply, result) != OH_IPC_SUCCESS) {
return OH_IPC_PARCEL_WRITE_ERROR;
}
return OH_IPC_SUCCESS;
}
int IpcStub::HandleStartNativeChildProcess(const OHIPCParcel *data, OHIPCParcel *reply)
{
int32_t ret = StartNativeChildProcess();
return OH_IPCParcel_WriteInt32(reply, ret);
}