引言
跨进程通信(IPC)和远程过程调用(RPC)是实现不同进程间数据交换的关键技术。在现代操作系统中,每个进程都有自己的独立内存空间,这导致进程之间无法直接访问彼此的资源。为了解决这一问题,IPC和RPC应运而生,它们分别使用Binder和软总线驱动来促进通信,前者适用于设备内部的不同进程,后者则扩展至跨设备通信。
IPC与RPC原理
- 客户端-服务器模型:通信遵循客户端-服务器模式,其中客户端创建服务器端的代理,通过代理读写数据以实现通信。
- 代理机制:客户端与服务器端交互时,通过代理对象进行,代理对象能够模拟服务器端的行为,将请求转发给真实的服务器,并将结果返回给客户端。
- SAMgr的作用:服务提供方在启动时会向系统能力管理者(SAMgr)注册其系统能力,而客户端则通过SAMgr获取服务的代理对象,从而进行通信。
约束与限制
- 数据传输量限制:在单个设备上的IPC通信中,数据量不宜超过1MB,对于大量数据的传输推荐使用匿名共享内存。
- 不支持匿名Stub的死亡通知订阅。
- Proxy对象不可在本设备内进行二次跨进程传递。
使用建议
- 接口定义:定义一个接口类,继承
IRemoteBroker
,包含消息码和未实现的方法,这些方法在继承该接口的客户端和服务器端中实现。 - 服务端实现:编写
Stub
类,继承IRemoteStub
或RemoteObject
,重写AsObject
和OnRemoteRequest
方法。 - 客户端实现:编写
Proxy
类,继承IRemoteProxy
或RemoteProxy
,实现AsObject
方法,并封装调用SendRequest
的方法。 - 注册与获取SA:在服务端进程注册SA到SAMgr,客户端通过SAMgr获取SA的Proxy。
场景示例:ITestAbility
以下是一个基于C++的IPC/RPC场景示例,展示了如何实现ITestAbility
接口以及相应的Stub
和Proxy
。
#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;
};
注册与获取
服务端注册:
auto samgr = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager();
samgr->AddSystemAbility(saId, new TestAbility());
客户端获取:
sptr<IRemoteObject> remoteObject = samgr->GetSystemAbility(saId);
sptr<ITestAbility> testAbility = iface_cast<ITestAbility>(remoteObject);
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);
});
以上代码片段详细地展示了如何在HarmonyOS环境下实现IPC和RPC通信,从接口定义到服务端和客户端的具体实现,再到注册和获取系统能力的步骤,以及在JavaScript侧进行绑定和通信处理的流程。