1# 远端状态订阅开发实例 2 3IPC/RPC提供对远端Stub对象状态的订阅机制, 在远端Stub对象消亡时,可触发消亡通知告诉本地Proxy对象。这种状态通知订阅需要调用特定接口完成,当不再需要订阅时也需要调用特定接口取消。使用这种订阅机制的用户,需要实现消亡通知接口DeathRecipient并实现onRemoteDied方法清理资源。该方法会在远端Stub对象所在进程消亡或所在设备离开组网时被回调。值得注意的是,调用这些接口有一定的顺序。首先,需要Proxy订阅Stub消亡通知,若在订阅期间Stub状态正常,则在不再需要时取消订阅;若在订阅期间Stub所在进程退出或者所在设备退出组网,则会自动触发Proxy自定义的后续操作。 4 5## 使用场景 6 7这种订阅机制适用于本地Proxy对象需要感知远端Stub对象所在进程消亡,或所在设备离开组网的场景。当Proxy感知到Stub端消亡后,可适当清理本地资源。此外,RPC目前不提供匿名Stub对象的消亡通知,即只有向SAMgr注册过的服务才能被订阅消亡通知,IPC则支持匿名对象的消亡通知。 8 9 10## Native侧接口 11 12| 接口名 | 返回值类型 | 功能描述 | 13| -------- | -------- | -------- | 14| AddDeathRecipient(const sptr\<DeathRecipient> &recipient); | bool | 订阅远端Stub对象状态。 | 15| RemoveDeathRecipient(const sptr\<DeathRecipient> &recipient); | bool | 取消订阅远端Stub对象状态。 | 16| OnRemoteDied(const wptr\<IRemoteObject> &object); | void | 当远端Stub对象死亡时回调。 | 17 18### 参考代码 19 20```C++ 21#include "iremote_broker.h" 22#include "iremote_stub.h" 23 24 25//定义消息码 26enum { 27 TRANS_ID_PING_ABILITY = 5, 28 TRANS_ID_REVERSED_MONITOR 29}; 30 31const std::string DESCRIPTOR = "test.ITestAbility"; 32 33class ITestService : public IRemoteBroker { 34public: 35 // DECLARE_INTERFACE_DESCRIPTOR是必需的,入参需使用std::u16string; 36 DECLARE_INTERFACE_DESCRIPTOR(to_utf16(DESCRIPTOR)); 37 virtual int TestPingAbility(const std::u16string &dummy) = 0; // 定义业务函数 38}; 39 40class TestServiceProxy : public IRemoteProxy<ITestAbility> { 41public: 42 explicit TestAbilityProxy(const sptr<IRemoteObject> &impl); 43 virtual int TestPingAbility(const std::u16string &dummy) override; 44 int TestAnonymousStub(); 45private: 46 static inline BrokerDelegator<TestAbilityProxy> delegator_; // 方便后续使用iface_cast宏 47}; 48 49TestServiceProxy::TestServiceProxy(const sptr<IRemoteObject> &impl) 50 : IRemoteProxy<ITestAbility>(impl) 51{ 52} 53 54int TestServiceProxy::TestPingAbility(const std::u16string &dummy){ 55 MessageOption option; 56 MessageParcel dataParcel, replyParcel; 57 dataParcel.WriteString16(dummy); 58 int error = PeerHolder::Remote()->SendRequest(TRANS_ID_PING_ABILITY, dataParcel, replyParcel, option); 59 int result = (error == ERR_NONE) ? replyParcel.ReadInt32() : -1; 60 return result; 61} 62``` 63 64 65 66 67```c++ 68#include "iremote_object.h" 69 70class TestDeathRecipient : public IRemoteObject::DeathRecipient { 71public: 72 virtual void OnRemoteDied(const wptr<IRemoteObject>& remoteObject); 73} 74 75void TestDeathRecipient::OnRemoteDied(const wptr<IRemoteObject>& remoteObject) 76{ 77} 78``` 79 80```c++ 81sptr<IPCObjectProxy> object = new IPCObjectProxy(1, to_utf16(DESCRIPTOR)); 82sptr<IRemoteObject::DeathRecipient> deathRecipient (new TestDeathRecipient());// 构造一个消亡通知对象 83bool result = object->AddDeathRecipient(deathRecipient); // 注册消亡通知 84result = object->RemoveDeathRecipient(deathRecipient); // 移除消亡通知 85``` 86 87## JS侧接口 88 89| 接口名 | 返回值类型 | 功能描述 | 90| -------------------- | ---------- | ------------------------------------------------------------ | 91| addDeathRecippient | boolean | 注册用于接收远程对象消亡通知的回调,增加proxy对象上的消亡通知。 | 92| removeDeathRecipient | boolean | 注销用于接收远程对象消亡通知的回调。 | 93| onRemoteDied | void | 在成功添加死亡通知订阅后,当远端对象死亡时,将自动调用本方法。 | 94 95### 参考代码 96 97```ts 98import FA from "@ohos.ability.featureAbility"; 99let proxy; 100let connect = { 101 onConnect: function(elementName, remoteProxy) { 102 console.log("RpcClient: js onConnect called."); 103 proxy = remoteProxy; 104 }, 105 onDisconnect: function(elementName) { 106 console.log("RpcClient: onDisconnect"); 107 }, 108 onFailed: function() { 109 console.log("RpcClient: onFailed"); 110 } 111}; 112let want = { 113 "bundleName": "com.ohos.server", 114 "abilityName": "com.ohos.server.MainAbility", 115}; 116FA.connectAbility(want, connect); 117class MyDeathRecipient { 118 onRemoteDied() { 119 console.log("server died"); 120 } 121} 122let deathRecipient = new MyDeathRecipient(); 123proxy.addDeathRecippient(deathRecipient, 0); 124proxy.removeDeathRecipient(deathRecipient, 0); 125``` 126 127## Stub感知Proxy消亡(匿名Stub的使用) 128 129正向的消亡通知是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,便实现了反向消亡通知。 130 131注意: 132 133> 反向死亡通知仅限设备内跨进程通信使用,不可用于跨设备。 134 135> 当匿名Stub对象没有被任何一个Proxy指向的时候,内核会自动回收。 136 137### 参考代码 138 139```c++ 140//Proxy 141int TestAbilityProxy::TestAnonymousStub() 142{ 143 MessageOption option; 144 MessageParcel dataParcel, replyParcel; 145 dataParcel.UpdateDataVersion(Remote()); 146 dataParcel.WriteRemoteObject(new TestAbilityStub()); 147 int error = Remote()->SendRequest(TRANS_ID_REVERSED_MONITOR,dataParcel, replyParcel, option); 148 int result = (error == ERR_NONE) ? replyParcel.ReadInt32() : -1; 149 return result; 150} 151 152//Stub 153 154int TestAbilityStub::OnRemoteRequest(uint32_t code, MessageParcel &data, MessageParcel &reply, MessageOption &option) 155{ 156 switch (code) { 157 case TRANS_ID_REVERSED_MONITOR: { 158 sptr<IRemoteObject> obj = data.ReadRemoteObject(); 159 if (obj == nullptr) { 160 reply.WriteInt32(ERR_NULL_OBJECT); 161 return ERR_NULL_OBJECT; 162 } 163 bool result = obj->AddDeathRecipient(new TestDeathRecipient()); 164 result ? reply.WriteInt32(ERR_NONE) : reply.WriteInt32(-1); 165 break; 166 } 167 default: 168 break; 169 } 170 return ERR_NONE; 171} 172``` 173 174