详解proxy-stub结构的设计模式

描述

  OpenHarmony 中存在很多的服务,一般来说可以使得 A 应用调用 B 服务的方法,就像在自己进程中调用一样,这里具体的实现实际通过 binder 驱动实现。

  binder 驱动通过 mmap 将内核态代码映射到用户态,直接读写数据这样就完成了跨进程的调用。不过这不是该篇内容的重点,本片主要讲一下 proxy - stub 的设计模式。

  服务的一般编码模式

  使用 proxy - stub 架构编程,大致可以分为以下三个步骤:

  设计接口类,继承至 IRemoteBroker,接口方法一般设计为虚方法。

  设计 proxy 类,继承至 IRemoteProxy,并且实现 sendRequest 方法和自身虚方法。

  设计 stub 类,继承至 IRemoteStub ,并且实现 OnRemote 方法和自身虚方法。

  这样我们就可以在调用是调用 proxy 类的接口方法就像调用 stub 类的接口方法一样了。

  源码剖析

  我们通过阅读源码,解开其神秘的面纱。我们现在关注几个重点的类。

  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 &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 &recipient) 0;

    virtual bool RemoveDeathRecipient(const sptr &recipient) 0;

    virtual bool Marshalling(Parcel &parcel) const override;

    static IRemoteObject *Unmarshalling(Parcel &parcel);

    static bool Marshalling(Parcel &parcel, const sptr &object);

    virtual sptr 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 驱动中数据传输的类,继承自 Parcelable 。而继承RefBase 可以理解为智能指针的控制块。

  OpenHarmony 中这里并没有直接使用 C++ 标准库中的智能指针,而是使用 sptr 和 refbase 两个类共同构建,也就是裸指针和控制块相关信息。使用后者的方式,更加解耦。符合复杂架构设计理念。

  IRemoteBroker:


class IRemoteBroker : public virtual RefBase {
public:
    IRemoteBroker() = default;
    virtual ~IRemoteBroker() override = default;
    virtual sptr AsObject() = 0;
    static inline sptr AsImplement(const sptr &object)
    {
        return nullptr;
    }
};

#define DECLARE_INTERFACE_DESCRIPTOR(DESCRIPTOR)                         
    static inline const std::u16string metaDescriptor_ = { DESCRIPTOR }; 
    static inline const std::u16string &GetDescriptor()                  
    {                                                                    
        return metaDescriptor_;                                          
    }

 

  一般的接口类,通过 metaDescriptor_ 作为表示区分标识。

  IRemoteProxy:

 

namespace OHOS {
template <typename INTERFACE> class IRemoteProxy : public PeerHolder, public INTERFACE {
public:
    explicit IRemoteProxy(const sptr &object);
    ~IRemoteProxy() override = default;

protected:
    sptr AsObject() override;
};

template <typename INTERFACE>
IRemoteProxy::IRemoteProxy(const sptr &object) : PeerHolder(object)
{
}

template <typename INTERFACE> sptr IRemoteProxy::AsObject()
{
    return Remote();
}
} // namespace OHOS

 

  IRemoteProxy 使用 c++ 的 crtp (奇特重现模板模式)编程,使得父类可以调用子类的方法。继承自 peerhold (其实就是包括一个 IRemoteObject 对象)。

  IRemoteStub:



namespace OHOS {
template <typename INTERFACE> class IRemoteStub : public IPCObjectStub, public INTERFACE {
public:
    IRemoteStub();
    virtual ~IRemoteStub() = default;
    sptr AsObject() override;
    sptr AsInterface() override;
};

template <typename INTERFACE> IRemoteStub::IRemoteStub() : IPCObjectStub(INTERFACE::GetDescriptor()) {}

template <typename INTERFACE> sptr IRemoteStub::AsInterface()
{
    return this;
}

template <typename INTERFACE> sptr IRemoteStub::AsObject()
{
    return this;
}
} // namespace OHOS

 

  stub 对象较于 proxy 对象复杂一些,也使用 crtp 编程。会继承 IPCObjectStub(也是 iremoteObject 对象)。

  看到这里,可能有人疑惑,为什么 proxy 调用,会直接调用到 stub 这端呢?

  其实奥秘就在于 stub 继承的 IPCObjectStub(继承 iremoteObject)对象,就是这个 iremoteObject 对象。

  proxy 的构造继承 peerhold,peerhold 类中的iremoteObject 对象和 IPCObjectStub 这个是什么关系呢?

  其实 peerhold 是 IPCObjectStub 的引用对象,实际类型是 IPCObjectProxy。

  这两者在 ipc 框架中,IPCObjectProxy 实际使用 sendrequest,IPCObjectStub 便会调用 OnremoteRequest。如果有兴趣,我们下次可以分析 IPC 框架具体是如何实现的。

  原文标题:剖析鸿蒙经典的proxy - stub架构

  文章出处:【微信公众号:HarmonyOS技术社区】欢迎添加关注!文章转载请注明出处。

  审核编辑:汤梓红


打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分