Binder中 Service与Binder之间的转换

来源:互联网 发布:清华大学覃征讲大数据 编辑:程序博客网 时间:2024/05/29 15:06

这几天一直在看binder的结构,感叹这样天才的设计。
现在只研究到binder的native框架,在IPCThreadState以下,真正的driver和数据交换还需要进一步研究。在此记录一些目前的体会。

1.IInterface的作用
个人感觉,这个IInterface严格上讲,并不是Binder这个框架的一部分。

基类 IInterface为 server 端提供接口,它的子类声明了 service 能够实现的所有的方法。
它的作用是提供了一个common的方式,可以将IBinder与Service进行显示的转换。

因为在进行IPC时,实际的service IXXXService要转换成IBinder,才能传递给ServiceManager进行注册检索,或者传递给Client进行调用。
而且Client拿到ServiceManager回传的IBinder以后,又要转换回IXXXService进行功能调用,所以IInterface产生了,提供了IXXXService与IBinder互相转换的功能。

(1)IXXXService转换IBinder实现:
IXXXService继承自IInterface,所以IInterface中的asBinder()方法,会将自身,也就是IXXXService转换成一个IBinder对象。
sp<IBinder> IInterface::asBinder()
{
    return this ? onAsBinder() : NULL;
}
这个onAsBinder()是一个虚拟方法,实际上是有IInterface的两个子类BpInterface和BnInterface实现的。
BpInterface的实现:
inline IBinder* BpInterface<INTERFACE>::onAsBinder()
{
    return remote(); //调用它的父类BpRefBase的remote()方法,返回IBinder,其实就是一个BpBinder
}
BnInterface的实现:
IBinder* BnInterface<INTERFACE>::onAsBinder()
{
    return this; //就是返回自身,因为BnInterface就是从BBinder继承的,BBinder又是继承自IBinder
}

(2)IBinder转换IXXXService实现:
当一个Client拿到ServiceManager返回的IBinder时,需要转换为IXXXService接口,才能调用它的功能。
这个转换,是由IInterface中定义的宏DECLARE_META_INTERFACE来声明的asInterface完成的,并由宏IMPLEMENT_META_INTERFACE实现的。
将宏代码IMPLEMENT_META_INTERFACE展开后得到:
android::sp<IXXXService> I##INTERFACE::asInterface(                
            const android::sp<android::IBinder>& obj)                   
{                                                                   
    android::sp<IXXXService> intr;                                 
    if (obj != NULL) {                                              
        intr = static_cast<IXXXService*>(                          
            obj->queryLocalInterface( //先调用queryLocalInterface,这个方法是IBinder定义的,默认实现是返回NULL,而在BBinder的子类BnInterface中,重载了该方法,返回this,而
                                      //BpInterface并没有重载,使用IBinder的默认实现,返回NULL。                             
                    IXXXService::descriptor).get());               
        if (intr == NULL)

{                                                  intr = new BpXXXService(obj); //如果queryLocalInterface返回NULL,就构造一个BpXXXService返回,Client得到的正是这个BpXXXService        }

                                                           
    }                                                               
    return intr;                                                    
}
总结一下,如果传进来的obj参数,是一个BBinder,就返回自身(这种情况应该是service和client在同一进程),如果是一个BpBinder,就new一个代理对象返回(这种情况应该是service和client在不同进程)。                                   

2.IBinder, BBinder和BpBinder
这3个类,是对Android Binder框架的抽象,其实这个BBinder,改成BnBinder可能更形象一些。
但是要注意的是,一个IXXXService的继承图中,BpBinder并不在这个继承关系之中,也就是说BpBinder并没有子类。但是BBinder是在这个继承关系当中的,它的子类就是BnInterface。
换句话说,BBinder和BpBinder的功能并不是对称的,以前就是没有理解到这一点,才会一直很糊涂。

BpBinder的是存在于BpRefBase中的mRemote的成员变量中。从Client调用Service的过程中分析,就更清楚了。
假设有一个IXXXService接口:
class IXXXService : public IInterface {
    ....
    public void helloWorld(const char* str);
    ....
}
1)client调用service
    client得到一个BpXXXService以后
    (a)会调用BpXXXService实现的helloWorld,它会将str参数打包到Parcel中。然后调用remote()->transact(xxx)
    (b)remote()是在BpXXXService的父类BpRefBase中实现的,返回的就是一个BpBinder.实际上调用的就是BpBinder的transact
    (c)BpBinder的transact实现,就是直接调用IPCThreadState::self()->transact()发送数据。
(2)service接收client请求:
    (a)通过IPCThreadState接收到client的请求后,首先会调用BBinder的transact方法。
    (b)BBinder的transact方法又会调用子类实现的虚拟方法onTransact。这个虚拟方法是在BnXXXService中实现的。
    (c)onTransact方法,会通过传递进来的参数来判断,需要调用IXXXService中的那个方法,示例中只有一个helloWorld方法。
    (d)直接调用helloWorld,就会找到它的真正实现,也就是BnXXXService的子类XXXService中的helloWorld方法。

Comments:

1. client得到的BpXXXService是Server返回的一个远程代理接口,例如BpMediaPlayer;

2. BpXXXService会将参数打包成parcel,然后调用remote()->transact(xxx)。其中remote()是调用BpRefBase的remote()方法得到BpBinder实例,remote()->transact(parcel) 也就是BpBinder 实例通过调用 IPCThreadState 的 transact ()来向 ProcessState实例的mOut 中写入数据,然后将mOut中的数据发送给Binder Driver。

 例如BpMediaPlayer类中的 setDataSource() 会调用remote()->transact(SET_DATA_SOURCE_STREAM, data, &reply);

3. BBinder的transact方法会调用子类实现的虚拟方法onTransact。如BnMediaPlayer是BBinder的子类,BnMediaPlayer的onTransact() 函数中有switch,针对传递过来的SET_DATA_SOURCE_STREAM这个命令,执行 reply->writeInt32(setDataSource(url, numHeaders > 0 ? &headers : NULL));


Q:上面comments 3里头的 reply->writeInt32(setDataSource(url, numHeaders > 0 ? &headers : NULL)); 是调用到哪里的setDataSource?

A:调用的是MediaPlayerService中的setDataSource,但不明白BnMediaPlayer是如何跟MediaPlayerService扯上关系的

Q:IXXXService 和 XXXService 之间的关系是什么?例如IMediaPlayer.cpp 与 MediaPlayer.cpp的关系

Q:前面所讲的server与binder之间的转换在这个实例中是如何体现的?

 
总结一下,从上面的流程当中就可以看出前文说的,BpBinder并不在继承关系当中,它只是一个打包数据,并通过IPCThreadState::self()->transact()方法发送出去。
而BBinder和BnXXXService的作用,就是接收IPCThreadState传递过来的信息,解包数据,并调用XXXService真正的实现。


0 0
原创粉丝点击