原先准备在binder阅读(3)中记录ServiceManager的使用,但是写着写着发现,如果不了解和binder相关的类,那么阅读起来将会由很多困惑,所以就先来记录binder相关的类了。记录完发现特别凌乱…先就这样吧。
1 UML类图
从 binder阅读(1)一开始的图中可以看到,getService获得的是一个handle,要怎样才能用这个handle完成RPC呢?Android为我们提供了一套框架,以下是框架相关类的UML类图。
我们设计的service需要遵循这套框架才能注册到binder驱动中,client也要遵循这套框架才能实现对service的调用。
接下来我们将会一起了解下面这张图中的内容。
binder框架代码位置: frameworks/native/libs/binder/
我将以MediaServer为例,代码位置:frameworks/av/media/libmedia/
2 IBinder
IBinder
声明于IBinder.h,实现于Binder.cpp。
想要让一个类对象能够通过binder驱动进行跨进程传输,那么这个class必须要继承自IBinder
接口。
IBinder
为服务本体和远程代理提供了基本接口,并提供了一些基础实现,本体和代理均需要实现这些接口。
2 BBinder
BBinder
声明于Binder.h,实现于Binder.cpp。
BBinder
是服务本体对IBinder
的实现。BBinder
覆写了localBinder方法,使其可以返回服务本体,调用BBinder
对象的remoteBinder方法将会返回null。
BBinder* BBinder::localBinder()
{
return this;
}
transact方法用于执行远程代理的调用,根据不同的code执行不同的方法,transact已经实现了一些基本的调用,服务自定义的调用需要在onTransact做实现,该工作由子类完成。
virtual status_t transact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags = 0) final;
virtual status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags = 0);
3 BpBinder
BpBinder
声明于BpBinder.h,实现于BpBinder.cpp。
BpBinder
是远程代理对IBinder
的实现。BpBinder
覆写了remoteBinder方法,使其可以返回远程代理,调用BpBinder
对象的localBinder方法将会返回null。
BpBinder
中封装有从ServiceManager那里获取到的Handle。BpBinder
提供有私有的create方法,可以很方便的帮助我们用Handle创建一个BpBinder
对象。
BpBinder
同样有transact方法,该方法用于和binder驱动通信,利用handle调用服务提供的方法,而BBinder
的transact用于执行我们的远程调用。
有这样一种情况,我们在使用远程代理进行RPC调用,但是这时候service挂了,如果我们不及时处理程序就很容易出错了。为了解决这个问题,BpBinder
提供了一个linkToDeath方法,当远程服务死亡时可以通知到使用者。这个不是我们的重点,所以这里只要会用就行。
virtual status_t linkToDeath(const sp<DeathRecipient>& recipient, void* cookie = nullptr, uint32_t flags = 0);
4 IInterface
IInterface
声明于IInterface.h,实现于IInterface.cpp。
我们定义的binder服务接口需要继承自IInterface
。IInterface
可以理解是服务本体和远程代理的一层封装,封装的是IBinder
对象,提供更高层的接口,方便我们使用。
IInterface
为我们提供了asBinder方法,这个方法的实现需要依赖子类对onAsBinder的实现,从名字上可以猜到它用来获取IInterface
中封装的IBinder
对象。
我们以 IMediaPlayerService为例看看binder服务接口要如何声明。IMediaPlayerService
继承自IInterface
,除了声明虚函数接口外,还调用了一个宏 DECLARE_META_INTERFACE,这个宏为我们提供了多个方法和类成员。
class IMediaPlayerService: public IInterface
{
public:
DECLARE_META_INTERFACE(MediaPlayerService);
}
DECLARE_META_INTERFACE 定义在 IInterface.h,将宏参数做替换后的代码如下:
public:
static const ::android::String16 descriptor;
static ::android::sp<IMediaPlayerService> asInterface(const ::android::sp<::android::IBinder>& obj);
virtual const ::android::String16& getInterfaceDescriptor() const;
IMediaPlayerService();
virtual ~IMediaPlayerService();
static bool setDefaultImpl(::android::sp<IMediaPlayerService> impl);
static const ::android::sp<IMediaPlayerService>& getDefaultImpl();
private:
static ::android::sp<IMediaPlayerService> default_impl;
实现同样也在 IInterface.h,这里我们不做展开,后面用到了我们再看。
5 BnInterface
BnInterface
声明于IInterface.h,实现于IInterface.cpp。
BnInterface
是服务本体对IInterface
接口的实现:
template<typename INTERFACE>
inline sp<IInterface> BnInterface<INTERFACE>::queryLocalInterface(
const String16& _descriptor)
{
if (_descriptor == INTERFACE::descriptor) return sp<IInterface>::fromExisting(this);
return nullptr;
}
template<typename INTERFACE>
inline const String16& BnInterface<INTERFACE>::getInterfaceDescriptor() const
{
return INTERFACE::getInterfaceDescriptor();
}
template<typename INTERFACE>
IBinder* BnInterface<INTERFACE>::onAsBinder()
{
return this;
}
覆写了IBinder
接口queryLocalInterface用于返回服务本体(BnInterface);
覆写了IInterface
接口onAsBinder,用于返回服务本体(IBinder)。
我们在这里看下上面的宏定义实现展开:
const ::android::String16& IMediaPlayerService::getInterfaceDescriptor() const { return IMediaPlayerService::descriptor;}
::android::sp<IMediaPlayerService> IMediaPlayerService::asInterface(const ::android::sp<::android::IBinder>& obj) {
::android::sp<IMediaPlayerService> intr;
if (obj != nullptr) {
// 尝试将IBinder对象转换为BnMediaPlayerService对象
intr = ::android::sp<IMediaPlayerService>::cast(obj->queryLocalInterface(IMediaPlayerService::descriptor));
if (intr == nullptr) {
// 如果为null,则将IBinder对象转换为BpMediaPlayerService对象
intr = ::android::sp<BpMediaPlayerService>::make(obj);
}
}
return intr;
}
template<typename INTERFACE>
inline sp<INTERFACE> interface_cast(const sp<IBinder>& obj)
{
return INTERFACE::asInterface(obj);
}
我们从ServiceManager获取到的服务其实是一个IBinder
对象,有了它我们还不能执行RPC,需要将它转换为BpInterface
对象或者是说代理实现,该对象内完成了参数的封装以及对Handle的调用。那我们应该如何转换呢?用这里的两个方法asInterface 和 interface_cast 就可以了。
6 BpInterface
BpInterface
声明于IInterface.h,实现于IInterface.cpp。
BpInterface
指的是远程代理,除了实现了IInterface
接口外,还继承了BpRefBase
。
BpRefBase
声明于Binder.h,实现于Binder.cpp。BpRefBase
用于管理远程代理的生命周期,用handle创建的BpBinder
对象就存储于BpRefBase
。BpRefBase
的remote方法返回的就是BpBinder
。
template<typename INTERFACE>
inline BpInterface<INTERFACE>::BpInterface(const sp<IBinder>& remote)
: BpRefBase(remote)
{}
template<typename INTERFACE>
inline IBinder* BpInterface<INTERFACE>::onAsBinder()
{
return remote();
}
inline IBinder* remote() const { return mRemote; }
说到生命周期,BpRefBase
的用法我没太看懂什么意思。
BpRefBase::BpRefBase(const sp<IBinder>& o)
: mRemote(o.get()), mRefs(nullptr), mState(0)
{
extendObjectLifetime(OBJECT_LIFETIME_WEAK);
if (mRemote) {
mRemote->incStrong(this); // Removed on first IncStrong().
mRefs = mRemote->createWeak(this); // Held for our entire lifetime.
}
}
不过我猜是将BpRefBase
和 IBinder
的生命周期绑定,因为BpRefBase
和IBinder
需要相互依赖,IBinder
释放了BpRefBase
也就无法工作了,BpRefBase
释放了IBinder
同样也没有意义了。
7 Parcel
RPC调用时少不了要传输数据,server端如何才能够识别client端写过去的数据呢?这就需要他们做一个约定,按照既定的数据格式传输数据。
Parcel
就是用于帮我们做数据格式化的工作的,包括输入数据的封装与输出数据的解压。我们按什么顺序写入数据,就要按照什么顺序读取数据。
Parcel
声明于Parcel.h,实现于Parcel.cpp。
现在我们可以使用aidl生成binder接口,但是aidl文件中我们只能使用Parcel
中已经定义的基础数据类型,而不能使用任意类型,这是因为Parcel
并不知道要按照什么规则写入我们想要使用的数据。
8 IPCThreadState / ProcessState
我们的老朋友了,ProcessState
用于打开关闭binder驱动程序,IPCThreadState
用于与操作binder驱动,与之沟通。
写在最后:这一篇笔记记录了一些零零碎碎的内容,主要了解了一些类的接口含义与使用。写到这我有点凌乱了,因为这篇仅仅是流水账式的记录,并没有什么章法可言,我应该也没有理解为什么binder框架这么设计。文章来源:https://www.toymoban.com/news/detail-508397.html
现在回过头又想了一些,不知是对是错,就先记录在这里:文章来源地址https://www.toymoban.com/news/detail-508397.html
- binder驱动中传输的对象之所以要继承自
IBinder
,是因为传输的对象有可能是代理,也有可能是服务实体,我们得区分他们,IBinder
为我们提供了区分他们的方法; - 远端代理 和 本地服务 实际的执行者不同,所以又区分了
BBinder
和BpBinder
,BBinder
中是一个实例化的提供服务的对象,而BpBinder
存储的是服务的引用handle; - 为了保证远端代理 和 本地服务的接口保持一致,所以他们都继承了
IInterface
; - 远端的接口和本地的服务接口实际完成的工作不一样,所以区分出了
BnInterface
和BpInterface
,BpInterface
需要组织数据并且向handle发送数据,BnInterface
需要根据发来的数据做真正的函数调用。
到了这里,关于Android 13(T) - binder阅读(3)- binder相关的类的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!