# 简介

对于 OpenHarmony 的 IPC 框架,每个部件都需要用到。本文将介绍 OpenHarmony 的进程间通信原理,并提供相应的代码示例。
IPC 和 RPC 通常采用客户端 - 服务器(Client-Server)模型,在使用时,请求服务的(Client)一端进程可获取提供服务(Server)一端所在进程的代理(Proxy),并通过此代理读写数据来实现进程间的数据通信。

# 开发步骤

# iService

定义 IPC 接口类,表示 IPC 提供的功能。
继承 IRemoteBroker ,且通过 DECLARE_INTERFACE_DESCRIPTOR 定义描述符。
提供的 IPC 业务函数写成纯虚函数。业务函数在 Proxy 端和 Stub 端都需要实现。

class ITestAbility : public IRemoteBroker {
public:
    DECLARE_INTERFACE_DESCRIPTOR(u"test.ITestAbility");
    virtual int TestPingAbility(const std::u16string &dummy) = 0; // 定义业务函数
};

# Proxy

proxy 是在 Client 侧负责与 Service 侧进行通信的中间类。主要负责将 Client 的数据进行编码发送到 Service 侧的 Stub。
proxy 需要继承 IRemoteProxy<ITestAbility> ,其中模板参数为我们上一步定义的接口类。
proxy 需要包含一个 BrokerDelegator<TestAbilityProxy> 的静态成员,自动接管我们的功能,而不需要手动注册。
proxy 通过 SendRequestIPC_CODE 和封装好的参数 发到 Service 端的 Stub。

class TestAbilityProxy : public IRemoteProxy<ITestAbility> {
public:
    explicit TestAbilityProxy(const sptr<IRemoteObject> &impl);
    int TestPingService(const std::u16string &dummy) override;
private:
    static inline BrokerDelegator<TestAbilityProxy> delegator_; // 方便后续使用 iface_cast 宏
}
TestAbilityProxy::TestAbilityProxy(const sptr<IRemoteObject> &impl)
    : IRemoteProxy<ITestAbility>(impl)
{
}
int TestAbilityProxy::TestPingService(const std::u16string &dummy){
    MessageOption option;
    MessageParcel dataParcel, replyParcel;
    dataParcel.WriteString16(dummy);
    int error = Remote()->SendRequest(TRANS_ID_PING_ABILITY, dataParcel, replyParcel, option);
    int result = (error == ERR_NONE) ? replyParcel.ReadInt32() : -1;
    return result;
}

# Stub

Stub 作为接收请求的一端,需重写 OnRemoteRequest 方法用于接收客户端调用。可以通过向 reply 写数据,直接回传数据。
可以看到 Stub 也继承了 ITestAbility,所以 Stub 也可以重写 TestPingAbility 的方法。

class TestAbilityStub : public IRemoteStub<ITestAbility> {
public:    
    virtual int OnRemoteRequest(uint32_t code, MessageParcel &data, MessageParcel &reply, MessageOption &option) override;
    int TestPingAbility(const std::u16string &dummy) override; //stub 可以不实现
};
int TestServiceStub::OnRemoteRequest(uint32_t code,
    MessageParcel &data, MessageParcel &reply, MessageOption &option)
{
    switch (code) {
    case TRANS_ID_PING_ABILITY: {
        std::u16string dummy = data.ReadString16();
        int result = TestPingAbility(dummy);
        reply.WriteInt32(result);
        return 0;
    }
    default:
        return IPCObjectStub::OnRemoteRequest(code, data, reply, option);
    }
}

# Service

本质上 Service 就是一个 Stub,只不过一般会把业务和 IPC 处理分离,业务写在 Service 里,编解码相关的 IPC 写在 Stub 中。实现业务与 IPC 解耦。
Service 会实现 接口类的所有业务函数。

class TestAbility : public TestAbilityStub, public SystemAbility {
public:
    int TestPingAbility(const std::u16string &dummy) override;
}
int TestAbility::TestPingAbility(const std::u16string &dummy) {
    return 0;
}