【SUBJECT技术】OpenHarmony 在一台设备从本端监听远端消亡的实现方法
背景双方模块进行交互,如果一方挂掉了,另一方还如痴如醉地一直为它工作,显然是有悖常理的。一旦对方不幸结束了,我们如何感知到并且正常开展后续工作?本文综合了Sensors,msdp模块进行了详实的介绍,希望对小伙们的此类工作有所帮助。
以下实例全部基于"client,proxy→stub,service"架构。
目录
1.原理介绍2.几种情况的重点说明
2.1 例1:服务侧监听客户侧消亡2.2 例2:客户端监听服务端消亡2.3 例3:服务端监听客户端消亡2.4 例4:服务端监听底层HDI侧消亡
3. 传感器服务端监听不同客户端消亡的处理实例4.小结
一、原理介绍
1. HarmonyOS远端状态订阅开发实例
IPC/RPC提供对远端Stub对象状态的订阅机制, 在远端Stub对象消亡时,可触发消亡通知告诉本地Proxy对象。这种状态通知订阅需要调用特定接口完成,当不再需要订阅时也需要调用特定接口取消。使用这种订阅机制的用户,需要实现消亡通知接口DeathRecipient并实现onRemoteDied方法清理资源。该方法会在远端Stub对象所在进程消亡时被回调。值得注意的是,调用这些接口有一定的顺序。首先,需要Proxy订阅Stub消亡通知,若在订阅期间Stub状态正常,则在不再需要时取消订阅;若在订阅期间Stub所在进程退出,则会自动触发Proxy自定义的后续操作。
2. 使用场景
这种订阅机制适用于本地Proxy对象需要感知远端Stub对象所在进程消亡。当Proxy感知到Stub端消亡后,可适当清理本地资源。此外,RPC目前不提供匿名Stub对象的消亡通知,即只有向SAMgr注册过的服务才能被订阅消亡通知,IPC则支持匿名对象的消亡通知。
3. Native侧接口
接口名返回值类型功能描述AddDeathRecipient(const sptr &recipient);bool订阅远端Stub对象状态。RemoveDeathRecipient(const sptr &recipient);bool取消订阅远端Stub对象状态。OnRemoteDied(const wptr &object);void当远端Stub对象消亡时回调。4. 调用序列图
https://forums.openharmony.cn/./figures/SequenceDeathRecipient.png
二、几种情况的重点说明
为了方便阅读和理解,名称有所修改,无关的代码被删除。远端(被监听)是消亡的一侧,本端是处理消亡的一侧。本端既可以在客户侧,也可以在服务侧。一般本端在客户侧是用来监听服务侧消亡情况,在服务侧是用来监听客户侧消亡的情况,或者底层提供服务侧的消亡情况。
只要出现 OnRemoteDied() 的地方就是本端,它是用来处理消亡的地方。
例1:服务侧监听客户侧消亡
在服务侧创建消亡信息接收者对象,添加、删除监听,以及消亡响应处理忽略,着重看一下客户侧如何将被监听的对象一路传递到服务侧的。
在远端要做的事情
步骤1. 定义被监听者类 ClientStubObject
class IRemoteClientObject : public IRemoteBroker {
public:
DECLARE_INTERFACE_DESCRIPTOR(u"ohos.xxx.IRemoteClientObject");// 必须存在,不然找不到该对象
};
class ClientStubObject :public IRemoteStub {
public:
explicit ClientStubObject(napi_env env) : env_(env) {}
virtual ~ClientStubObject() {};
int32_t OnRemoteRequest(uint32_t code, MessageParcel &data, MessageParcel &reply, MessageOption &option) override;
};步骤2. 创建被监听者类对象
sptr object = new (std::nothrow) ClientStubObject(env);步骤3. 把 object 一路传递给服务侧
void DeviceStatusSrvProxy::Subscribe(sptr object)
{
sptr remote = Remote();
MessageParcel data;
WRITEREMOTEOBJECT(data, object->AsObject());
MessageParcel reply;
MessageOption option;
int32_t ret = remote->SendRequest(static_cast(DeviceInterfaceCode::DEVICESTATUS_SUBSCRIBE),
data, reply, option);
}
int32_t DeviceStatusSrvStub::SubscribeStub(MessageParcel &data, MessageParcel &reply)
{
sptr obj = data.ReadRemoteObject();
sptr object = iface_cast(obj);
return RET_OK;
}例2:客户端监听服务端消亡
此种情况处理较为简单, 全部代码在客户侧(本端)实现。
步骤1. 定义消亡信息接收者类
class DeviceStatusDeathRecipient : public IRemoteObject::DeathRecipient {
public:
DeviceStatusDeathRecipient() = default;
~DeviceStatusDeathRecipient() = default;
void OnRemoteDied(const wptr &remote);
private:
DISALLOW_COPY_AND_MOVE(DeviceStatusDeathRecipient);
};步骤2. 消亡信息接收到的处理
void DeviceStatusClient::DeviceStatusDeathRecipient::OnRemoteDied(const wptr &remote)
{
DeviceStatusClient::GetInstance().ResetProxy(remote);
LOGD("Recv death notice");
}步骤3. 客户端定义消亡信息接收者对象
class DeviceStatusClient final : public DelayedRefSingleton {
DECLARE_DELAYED_REF_SINGLETON(DeviceStatusClient)
public:
~DeviceStatusClient();
ErrCode Connect();
sptr deathRecipient_ { nullptr };
};步骤4. 创建消亡信息接收者对象,并获取服务端(远端)对象
客户端首次Connect()时,通过服务端 MSDP_DEVICESTATUS_SERVICE_ID 获取被监听者的对象,然后将接收者添加给它。
ErrCode DeviceStatusClient::Connect()
{
sptr sa = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager();
sptr remoteObject = sa->CheckSystemAbility(MSDP_DEVICESTATUS_SERVICE_ID);
deathRecipient_ = sptr(new (std::nothrow) DeviceStatusDeathRecipient());
if (remoteObject->IsProxyObject()) {
remoteObject->AddDeathRecipient(deathRecipient_);
}
proxy_ = iface_cast(remoteObject);
return RET_OK;
}步骤5. 客户端析构时,删除消亡信息接收者
DeviceStatusClient::~DeviceStatusClient()
{
if (proxy_ != nullptr) {
auto remoteObject = proxy_->AsObject();
if (remoteObject != nullptr) {
remoteObject->RemoveDeathRecipient(deathRecipient_);
}
}
}例3:服务端监听客户端消亡
在本端要做的事情
定义接收者对象、添加接收者、删除接收者、处理消亡事件
步骤1. 在服务侧(本端)定义一个消亡信息接收者对象
class SensorService : public SystemAbility, public StreamServer, public SensorServiceStub {
DECLARE_SYSTEM_ABILITY(SensorService)
SENSOR_DECLARE_DELAYED_SP_SINGLETON(SensorService);
public:
void ProcessDeathObserver(const wptr &object);
private:
DISALLOW_COPY_AND_MOVE(SensorService);
void RegisterClientDeathRecipient(sptr sensorClient, int32_t pid);
void UnregisterClientDeathRecipient(sptr sensorClient);
// death recipient of sensor client
sptr deathRecipient_ = nullptr; // 定义消亡信息接收者对象
};步骤2. 在服务侧(本端),首先构建接收者,然后将接收者添加给传入的远端(客户侧)对象
void SensorService::RegisterClientDeathRecipient(sptr sensorClient, int32_t pid)
{
if (deathRecipient_ == nullptr) {
deathRecipient_ = new (std::nothrow) DeathRecipientTemplate(*const_cast(this));
CHKPV(deathRecipient_);
}
sensorClient->AddDeathRecipient(deathRecipient_);
clientInfo_.SaveClientPid(sensorClient, pid);
}消亡信息接收者的模板类如下定义,构造时将类对象传入,放在privateData_。
#include "iremote_object.h"
template
class DeathRecipientTemplate : public IRemoteObject::DeathRecipient {
public:
explicit DeathRecipientTemplate(T &privateData) : privateData_(privateData) {};
virtual ~DeathRecipientTemplate() = default;
// 被监听者消亡后被调起
virtual void OnRemoteDied(const wptr &object)
{
privateData_.ProcessDeathObserver(object);
};
private:
T &privateData_;// 构造时传入
};步骤3. 在服务侧(本端),将接收者从远端(客户侧)对象中删除
void SensorService::UnregisterClientDeathRecipient(sptr sensorClient)
{
sensorClient->RemoveDeathRecipient(deathRecipient_);
}步骤4. 在服务侧(本端),处理消亡事件
void SensorService::ProcessDeathObserver(const wptr &object)
{
sptr client = object.promote();
int32_t pid = clientInfo_.FindClientPid(client);
if (pid == INVALID_PID) {
LOGE("pid is invalid");
return;
}
LOGI("pid is %{public}d", pid);
}在远端要做的事情
步骤1. 在客户侧(远端被监听),创建对象并且一路传递给服务侧
int32_t SensorServiceClient::TransferDataChannel(sptr sensorDataChannel)
{
if (sensorClientStub_ == nullptr) {
sensorClientStub_ = new (std::nothrow) SensorClientStub(); // 创建被监听者对象
}
auto sm = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager();
auto object = sm->GetSystemAbility(SENSOR_SERVICE_ABILITY_ID);
proxy_ = iface_cast(object);
auto remoteObject = sensorClientStub_->AsObject();
ret = proxy_->TransferDataChannel(sensorDataChannel, remoteObject);
return ret;
}
ErrCode SensorService::TransferDataChannel(const sptr &sensorBasicDataChannel,
const sptr &sensorClient)
{
RegisterClientDeathRecipient(sensorClient, pid);
return ERR_OK;
}步骤2. 在客户侧(远端被监听),被监听者对象是如何被构建出来是关键的一环
首先,创建一个ISensorClient类,必须从IRemoteBroker继承;其次,创建一个SensorClientStub类,必须从IRemoteStub继承;最后,重写 OnRemoteRequest()函数,函数内什么有用的事情也没做。
其实,客户端Client为自己构建一个Stub作为自己的“影子”,然后将他传递给服务端(本端)作为被监听对象。
#include "iremote_broker.h"
class ISensorClient : public IRemoteBroker {
public:
ISensorClient() = default;
virtual ~ISensorClient() = default;
DECLARE_INTERFACE_DESCRIPTOR(u"ISensorClient");
};
class SensorClientStub : public IRemoteStub {
public:
SensorClientStub() = default;
virtual ~SensorClientStub() = default;
virtual int32_t OnRemoteRequest(uint32_t code, MessageParcel &data, MessageParcel &reply,
MessageOption &option) override;
};
int32_t SensorClientStub::OnRemoteRequest(uint32_t code, MessageParcel &data, MessageParcel &reply,
MessageOption &option)
{
std::u16string descriptor = SensorClientStub::GetDescriptor();
std::u16string remoteDescriptor = data.ReadInterfaceToken();
if (descriptor != remoteDescriptor) {
return OBJECT_NULL;
}
LOGD("Begin, cmd:%{public}u", code);
return NO_ERROR;
}
例4:服务端监听底层HDI侧消亡
此种情况处理较为简单, 全部代码在服务侧(本端)实现,通过Get()函数直接获取了远端对象。
步骤1. 生成一个消亡信息接收者的模板类
构造时将类对象传入,放在privateData_。
#include "iremote_object.h"
template
class DeathRecipientTemplate : public IRemoteObject::DeathRecipient {
public:
explicit DeathRecipientTemplate(T &privateData) : privateData_(privateData) {};
virtual ~DeathRecipientTemplate() = default;
// 被监听者消亡后被调起
virtual void OnRemoteDied(const wptr &object)
{
privateData_.ProcessDeathObserver(object);
};
private:
T &privateData_;// 构造时传入
};步骤2. 定义消亡信息接收者对象
class HdiLightConnection : public ILightHdiConnection {
public:
HdiLightConnection() = default;
virtual ~HdiLightConnection() {};
int32_t ConnectHdi() override;
int32_t DestroyHdiConnection() override;
void ProcessDeathObserver(const wptr &object);// 由消亡信息接收者类调起
private:
DISALLOW_COPY_AND_MOVE(HdiLightConnection);
sptr hdiDeathObserver_ = nullptr; // 定义接收者对象
sptr lightInterface_ = nullptr;
void RegisterHdiDeathRecipient();
void UnregisterHdiDeathRecipient();
};步骤3. 首次链接底层硬件服务时,获取底层远端对象(被监听者)lightInterface_
int32_t HdiLightConnection::ConnectHdi()
{
lightInterface_ = ILightInterface::Get();
if (lightInterface_ != nullptr) {
RegisterHdiDeathRecipient();
return ERR_OK;
}
return ERR_INVALID_VALUE;
}步骤4. 构建消亡信息接收者对象 hdiDeathObserver_
顺便将接收者添加至远端被监听者 lightInterface_
void HdiLightConnection::RegisterHdiDeathRecipient()
{
if (hdiDeathObserver_ == nullptr) {
hdiDeathObserver_ = new (std::nothrow) DeathRecipientTemplate(*const_cast(this));
}
OHOS::HDI::hdi_objcast(lightInterface_)->AddDeathRecipient(hdiDeathObserver_);
}步骤5. 本端不再监听远端时,将消亡信息接收者从远端(被监听者)移除
void HdiLightConnection::UnregisterHdiDeathRecipient()
{
OHOS::HDI::hdi_objcast(lightInterface_)->RemoveDeathRecipient(hdiDeathObserver_);
}步骤6. 远端(被监听者)消亡,将消亡信息接收者从远端(被监听者)移除
void HdiLightConnection::ProcessDeathObserver(const wptr &object)
{
sptr hdiService = object.promote();
hdiService->RemoveDeathRecipient(hdiDeathObserver_);
}三、传感器服务端监听不同客户端消亡的处理实例
参考链接:https://gitee.com/openharmony/sensors_miscdevice/pulls/314
https://forums.openharmony.cn/./figures/deathRecipient_pr.png
四、结论
本文全面描述了本端监听远端消亡,接收到消亡信息的后续处理实现。
定义消亡信息接收者,向远端添加、移除接收者以及处理消亡事件都比较简单明了。但是,如何获取被监听的远端对象差异较大,尤其是服务端获取客户端(远端)消亡对象较为复杂。客户端Client为自己构建一个Stub作为自己的“影子”,然后将他传递给服务端(本端)作为被监听对象。
各个示例如何获取远端对象汇总如下,以资参考:
场景扼要结论如何获取远端对象例1:服务侧监听客户侧消亡客户端再构造一个远端Stub对象,较为复杂class IRemoteClientObject : public IRemoteBroker {};class ClientStubObject :public IRemoteStub {};sptr object = new (std::nothrow) ClientStubObject(env);例2:客户端监听服务端消亡IPC 天然支持client监听server,做法简单sptr sa = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager();sptr remoteObject = sa->CheckSystemAbility(MSDP_DEVICESTATUS_SERVICE_ID);例3:服务端监听客户端消亡客户端再构造一个远端Stub对象,较为复杂class SensorClientStub : public IRemoteStub {};object = new (std::nothrow) SensorClientStub(); // 创建被监听者对象例4:服务端监听底层HDI侧消亡底层HDI侧封装的很好,做法简单object = ILightInterface::Get(); 受教了
页:
[1]