• 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| bool AddDeathRecipient(const sptr\<DeathRecipient> &recipient);     | 订阅远端Stub对象状态。     |
15| bool RemoveDeathRecipient(const sptr\<DeathRecipient> &recipient);  | 取消订阅远端Stub对象状态。 |
16| void OnRemoteDied(const wptr\<IRemoteObject> &object);              | 当远端Stub对象死亡时回调。 |
17
18### 参考代码
19
20```C++
21#include "iremote_broker.h"
22#include "iremote_stub.h"
23
24//定义消息码
25enum {
26    TRANS_ID_PING_ABILITY = 5,
27    TRANS_ID_REVERSED_MONITOR
28};
29
30const std::string DESCRIPTOR = "test.ITestAbility";
31
32class ITestService : public IRemoteBroker {
33public:
34    // DECLARE_INTERFACE_DESCRIPTOR是必需的,入参需使用std::u16string;
35    DECLARE_INTERFACE_DESCRIPTOR(to_utf16(DESCRIPTOR));
36    virtual int TestPingAbility(const std::u16string &dummy) = 0; // 定义业务函数
37};
38
39class TestServiceProxy : public IRemoteProxy<ITestAbility> {
40public:
41    explicit TestAbilityProxy(const sptr<IRemoteObject> &impl);
42    virtual int TestPingAbility(const std::u16string &dummy) override;
43    int TestAnonymousStub();
44private:
45    static inline BrokerDelegator<TestAbilityProxy> delegator_; // 方便后续使用iface_cast宏
46};
47
48TestServiceProxy::TestServiceProxy(const sptr<IRemoteObject> &impl)
49    : IRemoteProxy<ITestAbility>(impl)
50{
51}
52
53int TestServiceProxy::TestPingAbility(const std::u16string &dummy){
54    MessageOption option;
55    MessageParcel dataParcel, replyParcel;
56    dataParcel.WriteString16(dummy);
57    int error = PeerHolder::Remote()->SendRequest(TRANS_ID_PING_ABILITY, dataParcel, replyParcel, option);
58    int result = (error == ERR_NONE) ? replyParcel.ReadInt32() : -1;
59    return result;
60}
61```
62
63```c++
64#include "iremote_object.h"
65
66class TestDeathRecipient : public IRemoteObject::DeathRecipient {
67public:
68    virtual void OnRemoteDied(const wptr<IRemoteObject>& remoteObject);
69}
70
71void TestDeathRecipient::OnRemoteDied(const wptr<IRemoteObject>& remoteObject)
72{
73}
74```
75
76```c++
77sptr<IPCObjectProxy> object = new IPCObjectProxy(1, to_utf16(DESCRIPTOR));
78sptr<IRemoteObject::DeathRecipient> deathRecipient (new TestDeathRecipient()); // 构造一个消亡通知对象
79bool result = object->AddDeathRecipient(deathRecipient); // 注册消亡通知
80result = object->RemoveDeathRecipient(deathRecipient); // 移除消亡通知
81```
82
83## ArkTS侧接口
84
85| 接口名                                                       | 返回值类型 | 功能描述                                                     |
86| ------------------------------------------------------------ | ---------- | ------------------------------------------------------------ |
87| [registerDeathRecipient](../reference/apis/js-apis-rpc.md#registerdeathrecipient9-1) | void       | 注册用于接收远程对象消亡通知的回调,增加 proxy 对象上的消亡通知。 |
88| [unregisterDeathRecipient](../reference/apis/js-apis-rpc.md#unregisterdeathrecipient9-1) | void       | 注销用于接收远程对象消亡通知的回调。                         |
89| [onRemoteDied](../reference/apis/js-apis-rpc.md#onremotedied) | void       | 在成功添加死亡通知订阅后,当远端对象死亡时,将自动调用本方法。 |
90
91### 获取context
92
93Stage模型在连接服务前需要先获取context
94
95```ts
96import UIAbility from '@ohos.app.ability.UIAbility';
97import Want from '@ohos.app.ability.Want';
98import hilog from '@ohos.hilog';
99import AbilityConstant from '@ohos.app.ability.AbilityConstant';
100import window from '@ohos.window';
101
102export default class MainAbility extends UIAbility {
103  onCreate(want: Want, launchParam: AbilityConstant.LaunchParam) {
104    hilog.info(0x0000, 'testTag', '%{public}s', 'UIAbility onCreate');
105    let context = this.context;
106  }
107  onDestroy() {
108    hilog.info(0x0000, 'testTag', '%{public}s', 'UIAbility onDestroy');
109  }
110  onWindowStageCreate(windowStage: window.WindowStage) {
111    // Main window is created, set main page for this ability
112  	hilog.info(0x0000, 'testTag', '%{public}s', 'UIAbility onWindowStageCreate');
113  }
114  onWindowStageDestroy() {
115    // Main window is destroyed, release UI related resources
116  	hilog.info(0x0000, 'testTag', '%{public}s', 'UIAbility onWindowStageDestroy');
117  }
118  onForeground() {
119    // Ability has brought to foreground
120    hilog.info(0x0000, 'testTag', '%{public}s', 'UIAbility onForeground');
121  }
122  onBackground() {
123    // Ability has back to background
124    hilog.info(0x0000, 'testTag', '%{public}s', 'UIAbility onBackground');
125  }
126}
127```
128
129### 参考代码
130
131```ts
132// 仅FA模型需要导入@ohos.ability.featureAbility
133// import FA from "@ohos.ability.featureAbility";
134import Want from '@ohos.app.ability.Want';
135import common from '@ohos.app.ability.common';
136import rpc from '@ohos.rpc';
137import hilog from '@ohos.hilog';
138
139let proxy: rpc.IRemoteObject | undefined;
140let connect: common.ConnectOptions = {
141  onConnect: (elementName, remoteProxy) => {
142    hilog.info(0x0000, 'testTag', 'RpcClient: js onConnect called.');
143    proxy = remoteProxy;
144  },
145  onDisconnect: (elementName) => {
146    hilog.info(0x0000, 'testTag', 'RpcClient: onDisconnect');
147  },
148  onFailed: () => {
149    hilog.info(0x0000, 'testTag', 'RpcClient: onFailed');
150  }
151};
152let want: Want = {
153  bundleName: "com.ohos.server",
154  abilityName: "com.ohos.server.EntryAbility",
155};
156// FA模型通过此方法连接服务
157// FA.connectAbility(want, connect);
158
159this.context.connectServiceExtensionAbility(want, connect);
160```
161
162上述onConnect回调函数中的proxy对象需要等ability异步连接成功后才会被赋值,然后才可调用proxy对象的[unregisterDeathRecipient](../reference/apis/js-apis-rpc.md#unregisterdeathrecipient9-1)接口方法注销死亡回调
163
164```ts
165import rpc from '@ohos.rpc';
166import hilog from '@ohos.hilog';
167
168class MyDeathRecipient implements rpc.DeathRecipient{
169  onRemoteDied() {
170    hilog.info(0x0000, 'testTag', 'server died');
171  }
172}
173let deathRecipient = new MyDeathRecipient();
174if (proxy != undefined) {
175  proxy.registerDeathRecipient(deathRecipient, 0);
176  proxy.unregisterDeathRecipient(deathRecipient, 0);
177}
178```
179
180## Stub感知Proxy消亡(匿名Stub的使用)
181
182正向的消亡通知是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,便实现了反向消亡通知。
183
184注意:
185
186> 反向死亡通知仅限设备内跨进程通信使用,不可用于跨设备。
187
188> 当匿名Stub对象没有被任何一个Proxy指向的时候,内核会自动回收。
189
190### 参考代码
191
192```c++
193// Proxy
194int TestAbilityProxy::TestAnonymousStub()
195{
196    MessageOption option;
197    MessageParcel dataParcel, replyParcel;
198    dataParcel.UpdateDataVersion(Remote());
199    dataParcel.WriteRemoteObject(new TestAbilityStub());
200    int error = Remote()->SendRequest(TRANS_ID_REVERSED_MONITOR,dataParcel, replyParcel, option);
201    int result = (error == ERR_NONE) ? replyParcel.ReadInt32() : -1;
202    return result;
203}
204
205// Stub
206
207int TestAbilityStub::OnRemoteRequest(uint32_t code, MessageParcel &data, MessageParcel &reply, MessageOption &option)
208{
209    switch (code) {
210        case TRANS_ID_REVERSED_MONITOR: {
211            sptr<IRemoteObject> obj = data.ReadRemoteObject();
212            if (obj == nullptr) {
213                reply.WriteInt32(ERR_NULL_OBJECT);
214                return ERR_NULL_OBJECT;
215            }
216            bool result = obj->AddDeathRecipient(new TestDeathRecipient());
217            result ? reply.WriteInt32(ERR_NONE) : reply.WriteInt32(-1);
218            break;
219        }
220        default:
221            break;
222    }
223    return ERR_NONE;
224}
225```
226
227