源码分析—解析proxy - stub 架构的奥秘 原创 精华

发布于 2022-3-17 11:23
浏览
6收藏

源码分析— openharmony 服务设计架构 proxy - stub

服务概览

openHarmony 中存在很多的服务,一般来说可以使得A应用调用B服务的方法,就像在自己进程中调用一样,这里具体的实现实际通过binder驱动实现。binder驱动通过mmap将内核态代码映射到用户态,直接读写数据这样就完成了跨进程的调用。不过这不是该篇内容的重点,本片主要讲一下proxy - stub 的设计模式。

服务的一般编码模式

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

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

  1. 设计proxy类 继承至 IRemoteProxy,并且实现sendRequest方法和自身虚方法。
  2. 设计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<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驱动中数据传输的类,继承自 Parcelable 。而继承RefBase 可以理解为智能指针的控制块。openharmony中这里并没有直接使用c++标准库中的智能指针,而是使用 sptr 和refbase两个类共同构建,也就是裸指针和控制块相关信息。使用后者的方式,更加解耦。符合复杂架构设计理念。

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_ 作为表示区分标识。

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 (奇特重现模板模式)编程,使得父类可以调用子类的方法。继承自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对象复杂一些,也使用crtp编程。会继承IPCObjectStub (也是iremoteObject对象)

看到这里,可能有人疑惑,为什么proxy调用,会直接调用到stub这端呢?其实奥秘就在于stub 继承的IPCObjectStub (继承iremoteObject) 对象,就是这个iremoteObject对象。proxy的构造继承 peerhold ,peerhold 类中的iremoteObject 对象和 IPCObjectStub 这个是什么关系呢?其实peerhold是IPCObjectStub 的引用对象,实际类型是 IPCObjectProxy 。这两者在ipc框架中,IPCObjectProxy 实际使用sendrequest ,IPCObjectStub便会调用OnremoteRequest。如果有兴趣,我们下次可以分析IPC框架具体是如何实现的。

©著作权归作者所有,如需转载,请注明出处,否则将追究法律责任
8
收藏 6
回复
举报
回复
添加资源
添加资源将有机会获得更多曝光,你也可以直接关联已上传资源 去关联
    相关推荐