Android 13 - binder阅读(3)- binder相关的类

原先准备在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那里获取到的HandleBpBinder提供有私有的create方法,可以很方便的帮助我们用Handle创建一个BpBinder对象。

BpBinder同样有transact方法,该方法用于和binder驱动通信,利用handle调用服务提供的方法,而BBindertransact用于执行我们的远程调用。

有这样一种情况,我们在使用远程代理进行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服务接口需要继承自IInterfaceIInterface可以理解是服务本体远程代理的一层封装,封装的是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的调用。那我们应该如何转换呢?用这里的两个方法asInterfaceinterface_cast 就可以了。


6 BpInterface

BpInterface声明于IInterface.h,实现于IInterface.cpp

BpInterface指的是远程代理,除了实现了IInterface接口外,还继承了BpRefBase

BpRefBase声明于Binder.h,实现于Binder.cppBpRefBase用于管理远程代理的生命周期,用handle创建的BpBinder对象就存储于BpRefBaseBpRefBase的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.
    }
}

不过我猜是将BpRefBaseIBinder 的生命周期绑定,因为BpRefBaseIBinder需要相互依赖,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框架这么设计。

现在回过头又想了一些,不知是对是错,就先记录在这里:

  1. binder驱动中传输的对象之所以要继承自IBinder,是因为传输的对象有可能是代理,也有可能是服务实体,我们得区分他们,IBinder为我们提供了区分他们的方法;
  2. 远端代理 和 本地服务 实际的执行者不同,所以又区分了BBinderBpBinderBBinder中是一个实例化的提供服务的对象,而BpBinder存储的是服务的引用handle;
  3. 为了保证远端代理 和 本地服务的接口保持一致,所以他们都继承了IInterface
  4. 远端的接口和本地的服务接口实际完成的工作不一样,所以区分出了BnInterfaceBpInterfaceBpInterface需要组织数据并且向handle发送数据,BnInterface需要根据发来的数据做真正的函数调用。
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

青山渺渺

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值