• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Subscribing to State Changes of a Remote Object
2<!--Kit: IPC Kit-->
3<!--Subsystem: Communication-->
4<!--Owner: @xdx19211@luodonghui0157-->
5<!--SE: @zhaopeng_gitee-->
6<!--TSE: @maxiaorong2-->
7
8IPC/RPC allows you to subscribe to the state changes of a remote stub object. When the remote stub object dies, a death notification will be sent to your local proxy. To subscribe to death notifications, you need to call the [registerDeathRecipient](../reference/apis-ipc-kit/js-apis-rpc.md#registerdeathrecipient9-1) API. To unsubscribe from death notifications, call the [unregisterDeathRecipient](../reference/apis-ipc-kit/js-apis-rpc.md#unregisterdeathrecipient9-1) API.
9
10To be specific, you need to inherit the death notification class [DeathRecipient](../reference/apis-ipc-kit/js-apis-rpc.md#deathrecipient) and implement the [onRemoteDied](../reference/apis-ipc-kit/js-apis-rpc.md#onremotedied) method to clear resources. This callback is invoked when the process accommodating the remote stub object exits or the DSoftBus connection on which RPC depends is disabled.
11
12> **NOTE**
13> - The proxy object must first subscribe to death notifications of the stub object. If the stub object is in the normal state, the proxy object can cancel the subscription as required.
14> - If the process of the stub object exits or the DSoftBus connection on which RPC depends is disabled, the [onRemoteDied](../reference/apis-ipc-kit/js-apis-rpc.md#onremotedied) method customized by the proxy object will be automatically triggered.
15
16## When to Use
17
18IPC/RPC subscription is applicable to the following scenarios:<br>
191. In IPC, the proxy object needs to detect the status of the process hosting the remote stub object.
202. In RPC, the proxy object needs to detect the status of the process hosting the remote stub object, or the DSoftBus connection status on which RPC depends.
21When the proxy detects the death of the remote stub object, proxy objects and clear local resources should be cleared.
22> **NOTE**
23>
24> Subscription to death notifications of anonymous stub objects (not registered with SAMgr) is supported in IPC, but not in RPC.
25
26## **Development Using ArkTS APIs**
27
28> **NOTE**
29>
30> - The sample code in this topic implements communication between system applications across processes.
31>
32> - Application scenario constraints: The client is a third-party or system application, and the server is a system application or service.
33
34| API                                                      | Return Value Type| Description                                                    |
35| ------------------------------------------------------------ | ---------- | ------------------------------------------------------------ |
36| [registerDeathRecipient](../reference/apis-ipc-kit/js-apis-rpc.md#registerdeathrecipient9-1) | void       | Registers a callback for receiving death notifications of the remote object. This method should be called on the proxy side.|
37| [unregisterDeathRecipient](../reference/apis-ipc-kit/js-apis-rpc.md#unregisterdeathrecipient9-1) | void       | Unregisters from the callback used to receive death notifications of the remote object.                        |
38| [onRemoteDied](../reference/apis-ipc-kit/js-apis-rpc.md#onremotedied) | void       | Called when the process accommodating the remote stub object dies after the proxy successfully registers the death notification.|
39
40### Sample Code
41
42  In IPC, create the variables **want** and **connect**.
43  ```ts
44    import { Want, common } from '@kit.AbilityKit';
45    import { rpc } from '@kit.IPCKit';
46    import { hilog } from '@kit.PerformanceAnalysisKit';
47
48    let proxy: rpc.IRemoteObject | undefined;
49
50    let want: Want = {
51      // Enter the bundle name and ability name.
52      bundleName: "ohos.rpc.test.server",
53      abilityName: "ohos.rpc.test.server.ServiceAbility",
54    };
55    let connect: common.ConnectOptions = {
56      onConnect: (elementName, remoteProxy) => {
57        hilog.info(0x0000, 'testTag', 'RpcClient: js onConnect called');
58        proxy = remoteProxy;
59      },
60      onDisconnect: (elementName) => {
61        hilog.info(0x0000, 'testTag', 'RpcClient: onDisconnect');
62      },
63      onFailed: () => {
64        hilog.info(0x0000, 'testTag', 'RpcClient: onFailed');
65      }
66    };
67  ```
68
69  In RPC, create the variables **want** and **connect**.
70  ```ts
71    import { Want, common } from '@kit.AbilityKit';
72    import { rpc } from '@kit.IPCKit';
73    import { hilog } from '@kit.PerformanceAnalysisKit';
74    import { distributedDeviceManager } from '@kit.DistributedServiceKit';
75    import { BusinessError } from '@kit.BasicServicesKit';
76
77    let dmInstance: distributedDeviceManager.DeviceManager | undefined;
78    let proxy: rpc.IRemoteObject | undefined;
79
80    try{
81      dmInstance = distributedDeviceManager.createDeviceManager("ohos.rpc.test");
82    } catch(error) {
83      let err: BusinessError = error as BusinessError;
84      hilog.error(0x0000, 'testTag', 'createDeviceManager errCode:' + err.code + ', errMessage:' + err.message);
85    }
86
87    // Use distributedDeviceManager to obtain the network ID of the target device.
88    if (dmInstance != undefined) {
89      let deviceList = dmInstance.getAvailableDeviceListSync();
90      let networkId = deviceList[0].networkId;
91      let want: Want = {
92        bundleName: "ohos.rpc.test.server",
93        abilityName: "ohos.rpc.test.service.ServiceAbility",
94        deviceId: networkId,
95      };
96
97      let connect: common.ConnectOptions = {
98        onConnect: (elementName, remoteProxy) => {
99          hilog.info(0x0000, 'testTag', 'RpcClient: js onConnect called');
100          proxy = remoteProxy;
101        },
102        onDisconnect: (elementName) => {
103          hilog.info(0x0000, 'testTag', 'RpcClient: onDisconnect');
104        },
105        onFailed: () => {
106          hilog.info(0x0000, 'testTag', 'RpcClient: onFailed');
107        }
108      };
109    }
110  ```
111
112  In the FA model, the [connectAbility](../reference/apis-ability-kit/js-apis-ability-featureAbility.md#featureabilityconnectability7) API is used to connect to an ability.
113
114  <!--code_no_check_fa-->
115  ```ts
116    import { featureAbility } from '@kit.AbilityKit';
117
118    // Save the connection ID, which will be used for the subsequent service disconnection.
119    let connectId = featureAbility.connectAbility(want, connect);
120  ```
121
122  In the stage model, the [connectServiceExtensionAbility](../reference/apis-ability-kit/js-apis-inner-application-uiAbilityContext.md#connectserviceextensionability) API of **common.UIAbilityContext** is used to connect to an ability.
123  In the sample code provided in this topic, **this.context** is used to obtain **UIAbilityContext**, where **this** indicates a UIAbility instance inherited from **UIAbility**. To use **UIAbilityContext** APIs on pages, see [Obtaining the Context of UIAbility](../application-models/uiability-usage.md#obtaining-the-context-of-uiability).
124
125  <!--code_no_check-->
126  ```ts
127    let context: common.UIAbilityContext = this.getUIContext().getHostContext(); // UIAbilityContext
128    // Save the connection ID, which will be used for the subsequent service disconnection.
129    let connectId = context.connectServiceExtensionAbility(want,connect);
130   ```
131
132  After the service is successfully connected, the proxy object in the **onConnect** callback can be assigned a value You can call the [registerDeathRecipient](../reference/apis-ipc-kit/js-apis-rpc.md#registerdeathrecipient9-1) method of the proxy object to register the death callback. When the proxy object is no longer used, you can call the [unregisterDeathRecipient](../reference/apis-ipc-kit/js-apis-rpc.md#unregisterdeathrecipient9-1) method to deregister the death callback.
133
134  ```ts
135  import { rpc } from '@kit.IPCKit';
136  import { hilog } from '@kit.PerformanceAnalysisKit';
137
138  let proxy: rpc.IRemoteObject | undefined;
139
140  class MyDeathRecipient implements rpc.DeathRecipient{
141    onRemoteDied() {
142      hilog.info(0x0000, 'testTag', 'server died');
143    }
144  }
145  let deathRecipient = new MyDeathRecipient();
146  if (proxy != undefined) {
147    // The value 0 is a reserved flag for the death notification of the death listener. It has no actual meaning.
148    proxy.registerDeathRecipient(deathRecipient, 0);
149    proxy.unregisterDeathRecipient(deathRecipient, 0);
150  }
151  ```
152
153## Reverse Death Notification (Anonymous Stub)
154
155Forward dead notification is a mechanism that allows the proxy to detect death notifications of the stub. To achieve reverse dead notification, you can leverage the forward dead notification mechanism. Suppose there are two processes, A (the process hosting the original stub) and B (the process hosting the original proxy). After obtaining the proxy object of process A, process B creates an anonymous stub object (that is, a stub object not registered with SAMgr), which can be called a callback stub. Then, process B calls [sendMessageRequest](../reference/apis-ipc-kit/js-apis-rpc.md#sendmessagerequest9-2) to send the callback stub to the original stub of process A. Then, process A obtains the callback proxy of process B. As long as the death notification is registered with the callback proxy, when process B (callback stub) dies or the DSoftBus connection on which RPC depends is disabled, the callback proxy can detect the death and notify process A (original stub). In this way, the reverse death notification is implemented.
156
157> **NOTE**
158> - Reverse death notification can only be used for cross-process communication within a device.
159> - When an anonymous stub object is not referenced by any proxy, the object is automatically released.
160