• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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