引言

跨进程通信(IPC)和远程过程调用(RPC)是实现不同进程间数据交换的关键技术。在现代操作系统中,每个进程都有自己的独立内存空间,这导致进程之间无法直接访问彼此的资源。为了解决这一问题,IPC和RPC应运而生,它们分别使用Binder和软总线驱动来促进通信,前者适用于设备内部的不同进程,后者则扩展至跨设备通信。

IPC与RPC原理
  • 客户端-服务器模型:通信遵循客户端-服务器模式,其中客户端创建服务器端的代理,通过代理读写数据以实现通信。
  • 代理机制:客户端与服务器端交互时,通过代理对象进行,代理对象能够模拟服务器端的行为,将请求转发给真实的服务器,并将结果返回给客户端。
  • SAMgr的作用:服务提供方在启动时会向系统能力管理者(SAMgr)注册其系统能力,而客户端则通过SAMgr获取服务的代理对象,从而进行通信。

HarmonyOS入门之跨进程通信_IPC

约束与限制
  • 数据传输量限制:在单个设备上的IPC通信中,数据量不宜超过1MB,对于大量数据的传输推荐使用匿名共享内存。
  • 不支持匿名Stub的死亡通知订阅。
  • Proxy对象不可在本设备内进行二次跨进程传递。
使用建议
  • 接口定义:定义一个接口类,继承IRemoteBroker,包含消息码和未实现的方法,这些方法在继承该接口的客户端和服务器端中实现。
  • 服务端实现:编写Stub类,继承IRemoteStubRemoteObject,重写AsObjectOnRemoteRequest方法。
  • 客户端实现:编写Proxy类,继承IRemoteProxyRemoteProxy,实现AsObject方法,并封装调用SendRequest的方法。
  • 注册与获取SA:在服务端进程注册SA到SAMgr,客户端通过SAMgr获取SA的Proxy。
场景示例:ITestAbility

以下是一个基于C++的IPC/RPC场景示例,展示了如何实现ITestAbility接口以及相应的StubProxy

#include "iremote_broker.h"

const int TRANS_ID_PING_ABILITIES = 5;
const std::string DESCRIPTOR = "test.ITestAbility";

class ITestAbility : public IRemoteBroker {
public:
    DECLARE_INTERFACE_DESCRIPTOR(to_utf16(DESCRIPTOR));
    virtual int TestPingAbility(const std::u16string &dummy) = 0;
};

class TestAbilityStub : public IRemoteStub<ITestAbility> {
public:
    int OnRemoteRequest(uint32_t code, MessageParcel &data, MessageParcel &reply, MessageOption &option) override;
    int TestPingAbility(const std::u16string &dummy) override;
};

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

class TestAbilityProxy : public IRemoteProxy<ITestAbility> {
public:
    explicit TestAbilityProxy(const sptr<IRemoteObject> &impl);
    int TestPingAbility(const std::u16string &dummy) override;
};
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
注册与获取

服务端注册:

auto samgr = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager();
samgr->AddSystemAbility(saId, new TestAbility());
  • 1.
  • 2.

客户端获取:

sptr<IRemoteObject> remoteObject = samgr->GetSystemAbility(saId);
sptr<ITestAbility> testAbility = iface_cast<ITestAbility>(remoteObject);
  • 1.
  • 2.
JS侧开发

在JavaScript侧,使用HarmonyOS的RPC模块进行Ability的绑定和通信处理。

import rpc from "@ohos.rpc";
import featureAbility from "@ohos.ability.featureAbility";

let proxy = null;
let connectId = null;

let want = {
    "bundleName": "ohos.rpc.test.server",
    "abilityName": "ohos.rpc.test.server.ServiceAbility",
};

let connect = {
    onConnect: function(elementName, remote) {
        proxy = remote;
    },
    onDisconnect: function(elementName) {},
    onFailed: function() {
        proxy = null;
    }
};

connectId = featureAbility.connectAbility(want, connect);

// 使用期约
proxy.sendRequestAsync(1, data, reply, option)
    .then(function(result) {
        if (result.errCode != 0) {
            console.error("send request failed, errCode: " + result.errCode);
            return;
        }
        // 从result.reply里读取结果
    })
    .catch(function(e) {
        console.error("send request got exception: " + e);
    });
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.

以上代码片段详细地展示了如何在HarmonyOS环境下实现IPC和RPC通信,从接口定义到服务端和客户端的具体实现,再到注册和获取系统能力的步骤,以及在JavaScript侧进行绑定和通信处理的流程。