HarmonyOS遠端狀態訂閱開發例項

HarmonyOS開發者社群發表於2023-10-12

IPC/RPC提供對遠端Stub物件狀態的訂閱機制, 在遠端Stub物件消亡時,可觸發消亡通知告訴本地Proxy物件。這種狀態通知訂閱需要呼叫特定介面完成,當不再需要訂閱時也需要呼叫特定介面取消。使用這種訂閱機制的使用者,需要實現消亡通知介面DeathRecipient並實現onRemoteDied方法清理資源。該方法會在遠端Stub物件所在程式消亡或所在裝置離開組網時被回撥。值得注意的是,呼叫這些介面有一定的順序。首先,需要Proxy訂閱Stub消亡通知,若在訂閱期間Stub狀態正常,則在不再需要時取消訂閱;若在訂閱期間Stub所在程式退出或者所在裝置退出組網,則會自動觸發Proxy自定義的後續操作。

使用場景

這種訂閱機制適用於本地Proxy物件需要感知遠端Stub物件所在程式消亡,或所在裝置離開組網的場景。當Proxy感知到Stub端消亡後,可適當清理本地資源。此外,RPC目前不提供匿名Stub物件的消亡通知,即只有向SAMgr註冊過的服務才能被訂閱消亡通知,IPC則支援匿名物件的消亡通知。

Native側介面

介面名

返回值型別

功能描述

AddDeathRecipient(const sptr<DeathRecipient> &recipient);

bool

訂閱遠端Stub物件狀態。

RemoveDeathRecipient(const sptr<DeathRecipient> &recipient);

bool

取消訂閱遠端Stub物件狀態。

OnRemoteDied(const wptr<IRemoteObject> &object);

void

當遠端Stub物件死亡時回撥。

參考程式碼

#include "iremote_broker.h"
#include "iremote_stub.h"
//定義訊息碼
enum {
    TRANS_ID_PING_ABILITY = 5,
    TRANS_ID_REVERSED_MONITOR
};
const std::string DESCRIPTOR = "test.ITestAbility";
class ITestService : public IRemoteBroker {
public:
    // DECLARE_INTERFACE_DESCRIPTOR是必需的,入參需使用std::u16string;
    DECLARE_INTERFACE_DESCRIPTOR(to_utf16(DESCRIPTOR));
    virtual int TestPingAbility(const std::u16string &dummy) = 0; // 定義業務函式
};
class TestServiceProxy : public IRemoteProxy<ITestAbility> {
public:
    explicit TestAbilityProxy(const sptr<IRemoteObject> &impl);
    virtual int TestPingAbility(const std::u16string &dummy) override;
    int TestAnonymousStub();
private:
    static inline BrokerDelegator<TestAbilityProxy> delegator_; // 方便後續使用iface_cast宏
};
TestServiceProxy::TestServiceProxy(const sptr<IRemoteObject> &impl)
    : IRemoteProxy<ITestAbility>(impl)
{
}
int TestServiceProxy::TestPingAbility(const std::u16string &dummy){
    MessageOption option;
    MessageParcel dataParcel, replyParcel;
    dataParcel.WriteString16(dummy);
    int error = PeerHolder::Remote()->SendRequest(TRANS_ID_PING_ABILITY, dataParcel, replyParcel, option);
    int result = (error == ERR_NONE) ? replyParcel.ReadInt32() : -1;
    return result;
}
#include "iremote_object.h"
class TestDeathRecipient : public IRemoteObject::DeathRecipient {
public:
    virtual void OnRemoteDied(const wptr<IRemoteObject>& remoteObject);
}
void TestDeathRecipient::OnRemoteDied(const wptr<IRemoteObject>& remoteObject)
{
}
sptr<IPCObjectProxy> object = new IPCObjectProxy(1, to_utf16(DESCRIPTOR));
sptr<IRemoteObject::DeathRecipient> deathRecipient (new TestDeathRecipient());// 構造一個消亡通知物件
bool result = object->AddDeathRecipient(deathRecipient); // 註冊消亡通知
result = object->RemoveDeathRecipient(deathRecipient); // 移除消亡通知

JS側介面

介面名

返回值型別

功能描述

addDeathRecipient

boolean

註冊用於接收遠端物件消亡通知的回撥,增加proxy物件上的消亡通知。

removeDeathRecipient

boolean

登出用於接收遠端物件消亡通知的回撥。

onRemoteDied

void

在成功新增死亡通知訂閱後,當遠端物件死亡時,將自動呼叫本方法。

參考程式碼

import FA from "@ohos.ability.featureAbility";
let proxy;
let connect = {
    onConnect: function(elementName, remoteProxy) {
        console.log("RpcClient: js onConnect called.");
        proxy = remoteProxy;
    },
    onDisconnect: function(elementName) {
        console.log("RpcClient: onDisconnect");
    },
    onFailed: function() {
        console.log("RpcClient: onFailed");
    }
};
let want = {
    "bundleName": "com.ohos.server",
    "abilityName": "com.ohos.server.MainAbility",
};
FA.connectAbility(want, connect);
class MyDeathRecipient {
    onRemoteDied() {
        console.log("server died");
    }
}
let deathRecipient = new MyDeathRecipient();
proxy.addDeathRecipient(deathRecipient, 0);
proxy.removeDeathRecipient(deathRecipient, 0);

Stub感知Proxy消亡(匿名Stub的使用)

正向的消亡通知是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,便實現了反向消亡通知。

注意:

反向死亡通知僅限裝置內跨程式通訊使用,不可用於跨裝置。

當匿名Stub物件沒有被任何一個Proxy指向的時候,核心會自動回收。

參考程式碼

//Proxy
int TestAbilityProxy::TestAnonymousStub()
{
    MessageOption option;
    MessageParcel dataParcel, replyParcel;
    dataParcel.UpdateDataVersion(Remote());
    dataParcel.WriteRemoteObject(new TestAbilityStub());
    int error = Remote()->SendRequest(TRANS_ID_REVERSED_MONITOR,dataParcel, replyParcel, option);
    int result = (error == ERR_NONE) ? replyParcel.ReadInt32() : -1;
    return result;
}
//Stub
int TestAbilityStub::OnRemoteRequest(uint32_t code, MessageParcel &data, MessageParcel &reply, MessageOption &option)
{
    switch (code) {
        case TRANS_ID_REVERSED_MONITOR: {
            sptr<IRemoteObject> obj = data.ReadRemoteObject();
            if (obj == nullptr) {
                reply.WriteInt32(ERR_NULL_OBJECT);
                return ERR_NULL_OBJECT;
            }
            bool result = obj->AddDeathRecipient(new TestDeathRecipient());
            result ? reply.WriteInt32(ERR_NONE) : reply.WriteInt32(-1);
            break;
        }
        default:
            break;
    }
    return ERR_NONE;
}


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/70009402/viewspace-2988536/,如需轉載,請註明出處,否則將追究法律責任。

相關文章