IPC/RPC 提供对远端 Stub 对象状态的订阅机制, 在远端 Stub 对象消亡时,可触发消亡通知告诉本地 Proxy 对象。这种状态通知订阅需要调用特定接口完成,当不再需要订阅时也需要调用特定接口取消。使用这种订阅机制的用户,需要实现消亡通知接口 DeathRecipient 并实现 onRemoteDied 方法清理资源。该方法会在远端 Stub 对象所在进程消亡或所在设备离开组网时被回调。值得注意的是,调用这些接口有一定的顺序。首先,需要 Proxy 订阅 Stub 消亡通知,若在订阅期间 Stub 状态正常,则在不再需要时取消订阅;若在订阅期间 Stub 所在进程退出或者所在设备退出组网,则会自动触发 Proxy 自定义的后续操作。
使用场景
这种订阅机制适用于本地 Proxy 对象需要感知远端 Stub 对象所在进程消亡,或所在设备离开组网的场景。当 Proxy 感知到 Stub 端消亡后,可适当清理本地资源。此外,RPC 目前不提供匿名 Stub 对象的消亡通知,即只有向 SAMgr 注册过的服务才能被订阅消亡通知,IPC 则支持匿名对象的消亡通知。
Native 侧接口
参考代码
#include "iremote_broker.h"#include "iremote_stub.h"
//定义消息码enum { TRANS_ID_PING_ABILITY = 5, TRANS_ID_REVERSED_MONITOR};
const std::string DESCRIPTOR = "test.ITestAbility";
class ITestService : public IRemoteBroker {public: // DECLARE_INTERFACE_DESCRIPTOR是必需的,入参需使用std::u16string; DECLARE_INTERFACE_DESCRIPTOR(to_utf16(DESCRIPTOR)); virtual int TestPingAbility(const std::u16string &dummy) = 0; // 定义业务函数};
class TestServiceProxy : public IRemoteProxy<ITestAbility> {public: explicit TestAbilityProxy(const sptr<IRemoteObject> &impl); virtual int TestPingAbility(const std::u16string &dummy) override; int TestAnonymousStub();private: static inline BrokerDelegator<TestAbilityProxy> delegator_; // 方便后续使用iface_cast宏};
TestServiceProxy::TestServiceProxy(const sptr<IRemoteObject> &impl) : IRemoteProxy<ITestAbility>(impl){}
int TestServiceProxy::TestPingAbility(const std::u16string &dummy){ MessageOption option; MessageParcel dataParcel, replyParcel; dataParcel.WriteString16(dummy); int error = PeerHolder::Remote()->SendRequest(TRANS_ID_PING_ABILITY, dataParcel, replyParcel, option); int result = (error == ERR_NONE) ? replyParcel.ReadInt32() : -1; return result;}
复制代码
#include "iremote_object.h"
class TestDeathRecipient : public IRemoteObject::DeathRecipient {public: virtual void OnRemoteDied(const wptr<IRemoteObject>& remoteObject);}
void TestDeathRecipient::OnRemoteDied(const wptr<IRemoteObject>& remoteObject){}
复制代码
sptr<IPCObjectProxy> object = new IPCObjectProxy(1, to_utf16(DESCRIPTOR));sptr<IRemoteObject::DeathRecipient> deathRecipient (new TestDeathRecipient());// 构造一个消亡通知对象bool result = object->AddDeathRecipient(deathRecipient); // 注册消亡通知result = object->RemoveDeathRecipient(deathRecipient); // 移除消亡通知
复制代码
JS 侧接口
参考代码
import FA from "@ohos.ability.featureAbility";let proxy;let connect = { onConnect: function(elementName, remoteProxy) { console.log("RpcClient: js onConnect called."); proxy = remoteProxy; }, onDisconnect: function(elementName) { console.log("RpcClient: onDisconnect"); }, onFailed: function() { console.log("RpcClient: onFailed"); }};let want = { "bundleName": "com.ohos.server", "abilityName": "com.ohos.server.MainAbility",};FA.connectAbility(want, connect);class MyDeathRecipient { onRemoteDied() { console.log("server died"); }}let deathRecipient = new MyDeathRecipient();proxy.addDeathRecipient(deathRecipient, 0);proxy.removeDeathRecipient(deathRecipient, 0);
复制代码
Stub 感知 Proxy 消亡(匿名 Stub 的使用)
正向的消亡通知是 Proxy 感知 Stub 的状态,若想达到反向的死消亡通知,即 Stub 感知 Proxy 的状态,可以巧妙的利用正向消亡通知。如两个进程 A(原 Stub 所在进程)和 B(原 Proxy 所在进程),进程 B 在获取到进程 A 的 Proxy 对象后,在 B 进程新建一个匿名 Stub 对象(匿名指未向 SAMgr 注册),可称之为回调 Stub,再通过 SendRequest 接口将回调 Stub 传给进程 A 的原 Stub。这样一来,进程 A 便获取到了进程 B 的回调 Proxy。当进程 B 消亡或 B 所在设备离开组网时,回调 Stub 会消亡,回调 Proxy 会感知,进而通知给原 Stub,便实现了反向消亡通知。
注意:
反向死亡通知仅限设备内跨进程通信使用,不可用于跨设备。
当匿名 Stub 对象没有被任何一个 Proxy 指向的时候,内核会自动回收。
参考代码
//Proxyint TestAbilityProxy::TestAnonymousStub(){ MessageOption option; MessageParcel dataParcel, replyParcel; dataParcel.UpdateDataVersion(Remote()); dataParcel.WriteRemoteObject(new TestAbilityStub()); int error = Remote()->SendRequest(TRANS_ID_REVERSED_MONITOR,dataParcel, replyParcel, option); int result = (error == ERR_NONE) ? replyParcel.ReadInt32() : -1; return result;}
//Stub
int TestAbilityStub::OnRemoteRequest(uint32_t code, MessageParcel &data, MessageParcel &reply, MessageOption &option){ switch (code) { case TRANS_ID_REVERSED_MONITOR: { sptr<IRemoteObject> obj = data.ReadRemoteObject(); if (obj == nullptr) { reply.WriteInt32(ERR_NULL_OBJECT); return ERR_NULL_OBJECT; } bool result = obj->AddDeathRecipient(new TestDeathRecipient()); result ? reply.WriteInt32(ERR_NONE) : reply.WriteInt32(-1); break; } default: break; } return ERR_NONE;}
复制代码
评论