源碼分析—解析Proxy - Stub 架構(gòu)的奧秘
??51CTO和華為官方合作共建的鴻蒙技術(shù)社區(qū)??
服務(wù)概覽
openHarmony 中存在很多的服務(wù),一般來說可以使得A應(yīng)用調(diào)用B服務(wù)的方法,就像在自己進(jìn)程中調(diào)用一樣,這里具體的實現(xiàn)實際通過binder驅(qū)動實現(xiàn)。binder驅(qū)動通過mmap將內(nèi)核態(tài)代碼映射到用戶態(tài),直接讀寫數(shù)據(jù)這樣就完成了跨進(jìn)程的調(diào)用。不過這不是該篇內(nèi)容的重點(diǎn),本片主要講一下proxy - stub 的設(shè)計模式。
服務(wù)的一般編碼模式
使用proxy - stub 架構(gòu)編程,大致可以分為以下三個步驟:
- 設(shè)計接口類繼承 IRemoteBroker,接口方法一般設(shè)計為虛方法。
- 設(shè)計proxy類 繼承至 IRemoteProxy,并且實現(xiàn)sendRequest方法和自身虛方法。
- 設(shè)計stub類 繼承至 IRemoteStub ,并且實現(xiàn)OnRemote方法和自身虛方法。
這樣我們就可以在調(diào)用是調(diào)用proxy類的接口方法就像調(diào)用stub類的接口方法一樣了。
源碼剖析
我們通過閱讀源碼,解開其神秘的面紗。我們現(xiàn)在關(guān)注幾個重點(diǎn)的類。
IRemoteObject:
class IRemoteObject : public virtual Parcelable, public virtual RefBase {
public:
enum {
IF_PROT_DEFAULT, /* Invoker family. */
IF_PROT_BINDER = IF_PROT_DEFAULT,
IF_PROT_DATABUS,
};
enum {
DATABUS_TYPE,
};
class DeathRecipient : public RefBase {
public:
enum {
ADD_DEATH_RECIPIENT,
REMOVE_DEATH_RECIPIENT,
NOTICE_DEATH_RECIPIENT,
TEST_SERVICE_DEATH_RECIPIENT,
TEST_DEVICE_DEATH_RECIPIENT,
};
virtual void OnRemoteDied(const wptr<IRemoteObject> &object) = 0;
};
virtual int32_t GetObjectRefCount() = 0;
virtual int SendRequest(uint32_t code, MessageParcel &data, MessageParcel &reply, MessageOption &option) = 0;
virtual bool IsProxyObject() const;
virtual bool CheckObjectLegality() const;
virtual bool AddDeathRecipient(const sptr<DeathRecipient> &recipient) = 0;
virtual bool RemoveDeathRecipient(const sptr<DeathRecipient> &recipient) = 0;
virtual bool Marshalling(Parcel &parcel) const override;
static IRemoteObject *Unmarshalling(Parcel &parcel);
static bool Marshalling(Parcel &parcel, const sptr<IRemoteObject> &object);
virtual sptr<IRemoteBroker> AsInterface();
virtual int Dump(int fd, const std::vector<std::u16string> &args) = 0;
const std::u16string descriptor_;
std::u16string GetObjectDescriptor() const;
protected:
explicit IRemoteObject(std::u16string descriptor = nullptr);
};
這就是真正在binder驅(qū)動中數(shù)據(jù)傳輸?shù)念?,繼承自 Parcelable 。而繼承RefBase 可以理解為智能指針的控制塊。openharmony中這里并沒有直接使用c++標(biāo)準(zhǔn)庫中的智能指針,而是使用 sptr 和refbase兩個類共同構(gòu)建,也就是裸指針和控制塊相關(guān)信息。使用后者的方式,更加解耦。符合復(fù)雜架構(gòu)設(shè)計理念。
IRemoteBroker:
class IRemoteBroker : public virtual RefBase {
public:
IRemoteBroker() = default;
virtual ~IRemoteBroker() override = default;
virtual sptr<IRemoteObject> AsObject() = 0;
static inline sptr<IRemoteBroker> AsImplement(const sptr<IRemoteObject> &object)
{
return nullptr;
}
};
#define DECLARE_INTERFACE_DESCRIPTOR(DESCRIPTOR) \
static inline const std::u16string metaDescriptor_ = { DESCRIPTOR }; \
static inline const std::u16string &GetDescriptor() \
{ \
return metaDescriptor_; \
}
一般的接口類,通過metaDescriptor_ 作為表示區(qū)分標(biāo)識。
IRemoteProxy:
namespace OHOS {
template <typename INTERFACE> class IRemoteProxy : public PeerHolder, public INTERFACE {
public:
explicit IRemoteProxy(const sptr<IRemoteObject> &object);
~IRemoteProxy() override = default;
protected:
sptr<IRemoteObject> AsObject() override;
};
template <typename INTERFACE>
IRemoteProxy<INTERFACE>::IRemoteProxy(const sptr<IRemoteObject> &object) : PeerHolder(object)
{
}
template <typename INTERFACE> sptr<IRemoteObject> IRemoteProxy<INTERFACE>::AsObject()
{
return Remote();
}
} // namespace OHOS
IRemoteProxy 使用c++的crtp (奇特重現(xiàn)模板模式)編程,使得父類可以調(diào)用子類的方法。繼承自peerhold (其實就是包括一個IRemoteObject對象) 。
IRemoteStub:
namespace OHOS {
template <typename INTERFACE> class IRemoteStub : public IPCObjectStub, public INTERFACE {
public:
IRemoteStub();
virtual ~IRemoteStub() = default;
sptr<IRemoteObject> AsObject() override;
sptr<IRemoteBroker> AsInterface() override;
};
template <typename INTERFACE> IRemoteStub<INTERFACE>::IRemoteStub() : IPCObjectStub(INTERFACE::GetDescriptor()) {}
template <typename INTERFACE> sptr<IRemoteBroker> IRemoteStub<INTERFACE>::AsInterface()
{
return this;
}
template <typename INTERFACE> sptr<IRemoteObject> IRemoteStub<INTERFACE>::AsObject()
{
return this;
}
} // namespace OHOS
stub對象較于proxy對象復(fù)雜一些,也使用crtp編程。會繼承IPCObjectStub (也是iremoteObject對象)。
看到這里,可能有人疑惑,為什么proxy調(diào)用,會直接調(diào)用到stub這端呢?其實奧秘就在于stub 繼承的IPCObjectStub (繼承iremoteObject) 對象,就是這個iremoteObject對象。proxy的構(gòu)造繼承 peerhold ,peerhold 類中的iremoteObject 對象和 IPCObjectStub 這個是什么關(guān)系呢?其實peerhold是IPCObjectStub 的引用對象,實際類型是 IPCObjectProxy 。這兩者在ipc框架中,IPCObjectProxy 實際使用sendrequest ,IPCObjectStub便會調(diào)用OnremoteRequest。如果有興趣,我們下次可以分析IPC框架具體是如何實現(xiàn)的。
??51CTO和華為官方合作共建的鴻蒙技術(shù)社區(qū)??