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

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

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

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

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

服务概览

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

服务的一般编码模式

使用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​

责任编辑:jianghua 来源: 鸿蒙社区
相关推荐

2018-06-20 11:41:06

企业架构

2011-04-13 13:14:41

EIGRP STUB

2022-06-07 10:33:29

Camera组件鸿蒙

2014-08-19 10:30:30

Swift源码OpenStack架构

2009-09-09 15:43:15

2010-08-13 10:56:53

2016-11-25 13:14:50

Flume架构源码

2018-07-19 15:57:46

ViewStub源码方法

2010-02-04 11:06:14

2011-04-29 13:40:37

MongoDBCommand

2010-03-24 17:03:57

Python源码分析

2024-04-08 07:58:11

Python数据类型字符串

2016-11-29 09:38:06

Flume架构核心组件

2016-11-25 13:26:50

Flume架构源码

2017-11-14 12:56:31

云计算 Cloud TiDB奥秘

2017-11-15 13:11:03

云计算Cloud TiDB技术

2023-03-17 07:53:20

K8sAPIServerKubernetes

2019-10-16 16:33:41

Docker架构语言

2011-09-02 10:59:02

大数据数据分析Hadoop

2022-07-19 20:04:31

NAPI模块鸿蒙
点赞
收藏

51CTO技术栈公众号