# 远端状态订阅开发实例

IPC/RPC提供了订阅远端Stub对象状态的机制。当远端Stub对象死亡时，可以自动触发本端Proxy注册的死亡通知。这种死亡通知订阅需要调用指定接口registerDeathRecipient完成。不再需要订阅时，也需要调用指定接口unregisterDeathRecipient取消订阅。

使用这种订阅机制的用户需要继承死亡通知类DeathRecipient，并实现onRemoteDied方法清理资源。该方法会在远端Stub对象所在进程退出或当前RPC通信依赖的软总线连接断开时被回调。

*   首先，Proxy订阅Stub死亡通知，若在订阅期间Stub状态正常，则在不再需要时取消订阅。
*   其次，若在订阅期间，Stub所在进程退出或当前RPC通信依赖的软总线连接断开，则会自动触发执行业务已向Proxy注册的自定义的onRemoteDied方法。

#### 使用场景

IPC/RPC的订阅机制适用于以下场景：

1.  IPC通信，Proxy对象需要感知远端Stub对象所在进程的状态。
2.  RPC通信，Proxy对象需要感知远端Stub对象所在进程的状态，或者RPC通信依赖的软总线连接断开。

当Proxy感知到Stub端死亡后，应该清理本地Proxy对象以及相关资源。

RPC不支持匿名Stub对象（没有向SAMgr注册）的死亡通知，IPC支持匿名Stub对象的死亡通知。

#### ArkTS侧接口

*   此文档中的示例代码描述的是系统应用跨进程通信。
    
*   使用场景约束：客户端是第三方/系统应用，服务端是系统应用/服务
    

| 接口名 | 返回值类型 | 功能描述 |
| --- | --- | --- |
| registerDeathRecipient | void | 注册用于接收远程对象死亡通知的回调，该方法应该在proxy侧调用。 |
| unregisterDeathRecipient | void | 注销用于接收远程对象死亡通知的回调。 |
| onRemoteDied | void | Proxy侧注册死亡通知成功后，当远端Stub对象所在进程死亡时，将自动回调本方法。 |

#### 参考代码

在IPC（同设备的跨进程通信）场景中，示例代码如下：

导入相关依赖，并定义所需的变量；

```
import { BusinessError } from '@kit.BasicServicesKit';
import { Want, common } from '@kit.AbilityKit';
import { rpc } from '@kit.IPCKit';
import { hilog } from '@kit.PerformanceAnalysisKit';
import { PromptAction  } from '@kit.ArkUI';
import { JSON } from '@kit.ArkTS';

let proxy: rpc.IRemoteObject | undefined;
let connectId: number | undefined;

// 死亡通知
class MyDeathRecipient implements rpc.DeathRecipient {
  onRemoteDied() {
    hilog.info(0x0000, 'testTag', 'server is dead');
  }
}
let deathRecipient = new MyDeathRecipient();
```

连接服务，获取代理对象，然后注册死亡监听。在断开连接时，移除死亡监听。

```
// 连接服务
function connectAbility(context:common.UIAbilityContext, promptAction: PromptAction) {
  hilog.info(0x00000, 'testTag', 'begin to connect Ability');
  let want: Want = {
    bundleName: 'com.example.ipc_stub',
    abilityName: 'ServiceAbility',
  };
  let connect: common.ConnectOptions = {
    onConnect: (elementName, remoteProxy) => {
      hilog.info(0x00000, 'testTag', 'onConnect. elementName is :' + JSON.stringify(elementName));
      proxy = remoteProxy;
      // 客户端注册死亡监听
      try {
        proxy.registerDeathRecipient(deathRecipient, 0);
        hilog.info(0x00000, 'testTag', 'registerDeathRecipient success');
      } catch (err) {
        let code = (err as BusinessError).code;
        let message = (err as BusinessError).message;
        hilog.error(0x0000, 'testTag', 'register failed, code is ' + code + ', message is ' + message);
      }
      // ...
    },

    onDisconnect: (elementName) => {
      hilog.info(0x0000, 'testTag', 'onDisconnect. elementName is ' + JSON.stringify(elementName));
      // 客户端移除死亡监听
      try {
        proxy?.unregisterDeathRecipient(deathRecipient, 0);
        hilog.info(0x00000, 'testTag', 'unregisterDeathRecipient success');
      } catch (err) {
        let code = (err as BusinessError).code;
        let message = (err as BusinessError).message;
        hilog.error(0x0000, 'testTag', 'unregister failed, code is ' + code + ', message is ' + message);
      }
      proxy = undefined;
      // ...
    },

    onFailed: (code: number) => {
      hilog.info(0x0000, 'testTag', 'onFailed. code is ' + code);
      // ...
    },
  }

  try {
    connectId = context.connectServiceExtensionAbility(want, connect);
    hilog.info(0x00000, 'testTag', 'begin to connect Ability end');
  } catch (err) {
    let code = (err as BusinessError).code;
    let message = (err as BusinessError).message;
    hilog.error(0x0000, 'testTag', 'connectAbility failed, code is ' + code + ', message is ' + message);
  }
}

// 断开连接
function disconnectAbility(context: common.UIAbilityContext) {
  hilog.info(0x00000, 'testTag', 'begin to disconnect Ability. connectId is ' + connectId);
  if (connectId != undefined) {
    try {
      context.disconnectServiceExtensionAbility(connectId);
    } catch (err) {
      let code = (err as BusinessError).code;
      let message = (err as BusinessError).message;
      hilog.error(0x0000, 'testTag', 'disconnect failed, code is ' + code + ', message is ' + message);
    }
  }
}
```

在RPC（跨设备的跨进程通信）场景中，示例代码如下：

导入相关依赖，并定义所需的变量；

```
import { BusinessError } from '@kit.BasicServicesKit';
import { rpc } from '@kit.IPCKit';
import { hilog } from '@kit.PerformanceAnalysisKit';
import { distributedDeviceManager } from '@kit.DistributedServiceKit';
import { abilityAccessCtrl, PermissionRequestResult, common, Want} from '@kit.AbilityKit';
import { JSON } from '@kit.ArkTS';
import { PromptAction  } from '@kit.ArkUI';

let proxy: rpc.IRemoteObject | undefined;
let connectId: number | undefined;
let dmInstance: distributedDeviceManager.DeviceManager;
let deviceList: Array<distributedDeviceManager.DeviceBasicInfo> | undefined;
let deviceId: string| undefined;

// 死亡通知
class MyDeathRecipient implements rpc.DeathRecipient {
  onRemoteDied() {
    hilog.info(0x0000, 'testTag', 'server is dead');
  }
};
let deathRecipient = new MyDeathRecipient();
```

获取允许多设备协同的权限，在组网的情况下获取到对端的设备ID（组网场景下对应设备的唯一网络标识符，可以使用distributedDeviceManager获取目标设备的NetworkId）后连接服务，获取代理对象并注册死亡监听。当代理对象与服务端的通信结束后，在断开连接时，移除死亡监听。

```
// 获取权限
function getPermission(context:common.UIAbilityContext) {
  hilog.info(0x00000, 'testTag', 'begin to requestPermissions');
  try {
    let atManager: abilityAccessCtrl.AtManager = abilityAccessCtrl.createAtManager();
    atManager.requestPermissionsFromUser(context, ['ohos.permission.DISTRIBUTED_DATASYNC'],
      (err: BusinessError, data: PermissionRequestResult) => {
      if (err) {
        hilog.error(0x0000, 'testTag', 'requestPermissions failed, code is ' + err.code);
        hilog.error(0x0000, 'testTag', 'requestPermissions failed, message is ' + err.message);
      } else {
        hilog.info(0x0000, 'testTag', 'requestPermissions success, result is ' + JSON.stringify(data));
        hilog.info(0x0000, 'testTag', 'data permissions is ' + data.permissions);
        hilog.info(0x0000, 'testTag', 'data authResults is ' + data.authResults);
        hilog.info(0x0000, 'testTag', 'data dialogShownResults is ' + data.dialogShownResults);
      }
    });
  } catch (err) {
    let code = (err as BusinessError).code;
    let message = (err as BusinessError).message;
    hilog.error(0x0000, 'testTag', 'getPermission failed, code is ' + code + ', message is ' + message);
  }
}

// 获取对端设备信息
function getDeviceId(promptAction: PromptAction) {
  hilog.info(0x00000, 'testTag', 'begin to getDeviceId');
  try {
    dmInstance = distributedDeviceManager.createDeviceManager('com.example.rpc_client');
    hilog.info(0x0000, 'testTag', 'createDeviceManager success');
    deviceList = dmInstance.getAvailableDeviceListSync();
    hilog.info(0x0000, 'testTag', 'deviceList is ' + JSON.stringify(deviceList));
    if (deviceList.length !== 0) {
      deviceId = deviceList[0].networkId;
      hilog.info(0x0000, 'testTag', 'networkId is ' + deviceId);
      // ...
    }
  } catch (err) {
    let code = (err as BusinessError).code;
    let message = (err as BusinessError).message;
    hilog.error(0x0000, 'testTag', 'getDeviceId failed, code is ' + code + ', message is ' + message);
    // ...
  }
}

// 连接服务
function connectAbility(context:common.UIAbilityContext, promptAction: PromptAction) {
  hilog.info(0x00000, 'testTag', 'begin to connect Ability');
  let want: Want = {
    bundleName: 'com.example.rpc_stub',
    abilityName: 'ServiceAbility',
    deviceId: deviceId,
  }

  let connect: common.ConnectOptions = {
    onConnect: (elementName, remoteProxy) => {
      hilog.info(0x00000, 'testTag', 'onConnect. elementName is ' + JSON.stringify(elementName));
      proxy = remoteProxy;
      // 客户端注册死亡监听
      try {
        proxy.registerDeathRecipient(deathRecipient, 0);
        hilog.info(0x00000, 'testTag', 'registerDeathRecipient success');
      } catch (err) {
        let code = (err as BusinessError).code;
        let message = (err as BusinessError).message;
        hilog.error(0x0000, 'testTag', 'register failed, code is ' + code + ', message is ' + message);
      };
      // ...
    },
    onDisconnect: (elementName) => {
      hilog.info(0x0000, 'testTag', 'onDisconnect. elementName is ' + JSON.stringify(elementName));
      // 客户端移除死亡监听
      try {
        proxy?.unregisterDeathRecipient(deathRecipient, 0);
        hilog.info(0x00000, 'testTag', 'unregisterDeathRecipient success');
      } catch (err) {
        let code = (err as BusinessError).code;
        let message = (err as BusinessError).message;
        hilog.error(0x0000, 'testTag', 'unregister failed, code is ' + code + ', message is ' + message);
      }
      proxy = undefined;
      // ...
    },
    onFailed: (code: number) => {
      hilog.info(0x0000, 'testTag', 'onFailed. code is ' + code);
      // ...
    },
  }

  try {
    connectId = context.connectServiceExtensionAbility(want, connect);
  } catch (err) {
    let code = (err as BusinessError).code;
    let message = (err as BusinessError).message;
    hilog.error(0x0000, 'testTag', 'connectService failed, code is ' + code + ', message is ' + message);
  }
}

// 断开连接
function disconnectAbility(context: common.UIAbilityContext) {
  hilog.info(0x00000, 'testTag', 'begin to disconnect Ability');
  if (connectId != undefined) {
    try {
      context.disconnectServiceExtensionAbility(connectId);
    } catch (err) {
      let code = (err as BusinessError).code;
      let message = (err as BusinessError).message;
      hilog.error(0x0000, 'testTag', 'disconnectService failed, code is ' + code + ', message is ' + message);
    }
  }
}
```

#### Stub反向感知Proxy死亡状态（匿名Stub的特殊用法）

正向的死亡通知是Proxy感知Stub的状态，要实现反向的死亡通知（即Stub感知Proxy的状态），可以利用反向死亡通知。例如，进程A（原Stub所在进程）和进程B（原Proxy所在进程），进程B获取到进程A的原Proxy对象后，在B进程新建一个匿名Stub对象（未向SAMgr注册），称为回调Stub，通过sendMessageRequest接口将回调Stub传给进程A的原Stub，进程A就可以获取到进程B的回调Proxy。只要向回调Proxy注册了死亡通知，当进程B（回调Stub）死亡或者RPC通信依赖的软总线连接断开时，回调Proxy会感知并通知进程A（原Stub），从而实现反向死亡通知。

*   反向死亡通知仅限设备内跨进程通信使用，不可用于跨设备。
*   当匿名Stub对象没有被任何一个Proxy引用时，对象会被自动释放。