源码分析—解析Proxy – Stub 架构的奥秘

源码分析—解析Proxy - Stub 架构的奥秘

​想了解更多内容,请访问:​

​51CTO和华为官方合作共建的鸿蒙技术社区​

​https://ost.51cto.com​

服务概览

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

服务的一般编码模式

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

  1. 设计接口类继承 IRemoteBroker,接口方法一般设计为虚方法。
  2. 设计proxy类 继承至 IRemoteProxy,并且实现sendRequest方法和自身虚方法。
  3. 设计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框架具体是如何实现的。

​想了解更多内容,请访问:​

​51CTO和华为官方合作共建的鸿蒙技术社区​

​https://ost.51cto.com​

源码分析—解析Proxy - Stub 架构的奥秘

文章版权声明

 1 原创文章作者:3013,如若转载,请注明出处: https://www.52hwl.com/94930.html

 2 温馨提示:软件侵权请联系469472785#qq.com(三天内删除相关链接)资源失效请留言反馈

 3 下载提示:如遇蓝奏云无法访问,请修改lanzous(把s修改成x)

 免责声明:本站为个人博客,所有软件信息均来自网络 修改版软件,加群广告提示为修改者自留,非本站信息,注意鉴别

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2024年1月16日 下午10:26
下一篇 2024年1月16日 下午10:26