电子设备知识网-中国电子设备,国内最专业电子设备平台
电子设备知识网-中国电子设备,国内最专业电子设备平台

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

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

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

服务的一般编码模式

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

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

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

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

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

源码剖析

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

IRemoteObject:

 classIRemoteObject:publicvirtualParcelable,publicvirtualRefBase{ public: enum{ IF_PROT_DEFAULT,/*Invokerfamily.*/ IF_PROT_BINDER=IF_PROT_DEFAULT, IF_PROT_DATABUS, }; enum{ DATABUS_TYPE, }; classDeathRecipient:publicRefBase{ public: enum{ ADD_DEATH_RECIPIENT, REMOVE_DEATH_RECIPIENT, NOTICE_DEATH_RECIPIENT, TEST_SERVICE_DEATH_RECIPIENT, TEST_DEVICE_DEATH_RECIPIENT, }; virtualvoidOnRemoteDied(constwptr&object)=0; };  virtualint32_tGetObjectRefCount()=0;  virtualintSendRequest(uint32_tcode,MessageParcel&data,MessageParcel&reply,MessageOption&option)=0;  virtualboolIsProxyObject()const;  virtualboolCheckObjectLegality()const;  virtualboolAddDeathRecipient(constsptr&recipient)=0;  virtualboolRemoveDeathRecipient(constsptr&recipient)=0;  virtualboolMarshalling(Parcel&parcel)constoverride;  staticIRemoteObject*Unmarshalling(Parcel&parcel);  staticboolMarshalling(Parcel&parcel,constsptr&object);  virtualsptrAsInterface();  virtualintDump(intfd,conststd::vector<std::u16string>&args)=0;  conststd::u16stringdescriptor_;  std::u16stringGetObjectDescriptor()const;  protected: explicitIRemoteObject(std::u16stringdescriptor=nullptr); }; 

这就是真正在 binder 驱动中数据传输的类,继承自 Parcelable 。而继承RefBase 可以理解为智能指针的控制块。

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

IRemoteBroker:

 classIRemoteBroker:publicvirtualRefBase{ public: IRemoteBroker()=default; virtual~IRemoteBroker()override=default; virtualsptrAsObject()=0; staticinlinesptrAsImplement(constsptr&object) { returnnullptr; } };  #defineDECLARE_INTERFACE_DESCRIPTOR(DESCRIPTOR) staticinlineconststd::u16stringmetaDescriptor_={DESCRIPTOR}; staticinlineconststd::u16string&GetDescriptor() { returnmetaDescriptor_; } 

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

IRemoteProxy:

 namespaceOHOS{ template<typenameINTERFACE>classIRemoteProxy:publicPeerHolder,publicINTERFACE{ public: explicitIRemoteProxy(constsptr&object); ~IRemoteProxy()override=default;  protected: sptrAsObject()override; };  template<typenameINTERFACE> IRemoteProxy::IRemoteProxy(constsptr&object):PeerHolder(object) { }  template<typenameINTERFACE>sptrIRemoteProxy::AsObject() { returnRemote(); } }//namespaceOHOS 

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

IRemoteStub:

 namespaceOHOS{ template<typenameINTERFACE>classIRemoteStub:publicIPCObjectStub,publicINTERFACE{ public: IRemoteStub(); virtual~IRemoteStub()=default; sptrAsObject()override; sptrAsInterface()override; };  template<typenameINTERFACE>IRemoteStub::IRemoteStub():IPCObjectStub(INTERFACE::GetDescriptor()){}  template<typenameINTERFACE>sptrIRemoteStub::AsInterface() { returnthis; }  template<typenameINTERFACE>sptrIRemoteStub::AsObject() { returnthis; } }//namespaceOHOS 

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技术社区】欢迎添加关注!文章转载请注明出处。

审核编辑:汤梓红

未经允许不得转载:电子设备知识网 » 详解proxy-stub结构的设计模式

分享到: 生成海报