关闭

Android Binder 通信机制学习(三)

标签: Androidbinder
422人阅读 评论(0) 收藏 举报
分类:

本地Binder框架通信原理


本篇就binder机制的重要函数调用流程进行分析:

  • 1) 客户端或者服务端获得servicemananger的IBinder指针的函数调用流程
  • 2) 客户端获得IBinder指针的函数调用流程
  • 3) 客户端和服务端通信的函数调用流程,了解该调用流程可对binder通信的数据流动有一个清晰的认识

获得servicemananger的IBinder指针的函数调用流程

客户端或者服务端一般会先获得servicemananger的代理,再使用该代理来查询服务或者添加服务,获得代理之前得先获得servicemananger的IBinder指针,获得IBinder指针的函数调用流程图如下图所示:

servicemananger_ibiner

interface_cast是Binder本地框架提供的一个宏函数,这里展开后得到的代码如下所示:

inline sp<IServiceManager> interface_cast(const sp<IBinder>& obj)
  {
      return IServiceManager::asInterface(obj);
   }


在IServiceManager.cpp里使用宏IMPLEMENT_META_INTERFACE实现了IServiceManager::asInterface函数:

android::sp<IServiceManager> IServiceManager::asInterface(              
            const android::sp<android::IBinder>& obj)                 
    {                                                                  
        android::sp<IServiceManager> intr;                        
        if (obj != 0) {                                           
            intr = static_cast<IServiceManager*>(                   
                obj->queryLocalInterface(                       
                        IServiceManager::descriptor).get());     
            if (intr == 0) {                                    
                intr = new BpServiceManager(obj);               
            }                                              
        }                                                
        return intr;                                
    }

由此可知defaultServiceManager返回的IServiceManager指针指向的真实类型其实是BpServiceManager,并且封装了一个IBinder指针,这里我们主要关注IServiceManager的IBinder指针是如何获得的。

根据上图,我们可知道通过调用ProcessState::self()->getContextObject(NULL)来获得IServiceManager的IBinder指针,然后调用了getStrongProxyForHandle(0)来获得IBinder指针,由此可以知道handle为0表示servicemanager的引用。

客户端获得IBinder指针的函数调用流程

客户获得IBinder指针的函数调用流程如下所示:(如看不清请点击看大图)

client_ibinder

客户端一般会先获得IServiceManager的指针,然后通过该指针获取某个服务的IBinder指针。

示意图里的sm的真正类型其实是BpServiceManager,所以执行sm的getService方法其实是执行BpServiceManager的getService方法,BpServiceMananger的getService方法通过调用checkService方法来获得IBinder指针。

checkService方法里首先调用remote()->transact方法与servicemananger通信,获得parcel类型的返回数据。remote()的类型是IBinder指针,但指向的真实类型其实是BpBinder,它封装的handle值为0,表示servicemananger的引用。reply.readStrongBinder()的reply对象类型是parcel。

BpBinder的transact方法会转调IPCThreadState的transact方法,在IPCThreadState的transact方法里会先调用writeTransactionData填充要发送给servicemanager进程的数据,然后调用waitForResponse,waitForResponse会调用talkWithDriver将要发送的数据发给servicemananager进程,这部分数据里有要使用的service的名字,然后会收到servicemananger返回的数据,再调用parcel类型的ipcSetDataReference方法将收到的数据传给reply对象。

reply对象调用readStrongBinder以获得IBinder指针,如上图所示,会利用从servicemananger返回的handle建立BpBinder,故此客户端获得的IBinder指针指向的真实类型其实是BpBinder,客户端会将IBinder指针封装到实现了binder服务接口的BpInterface的子类里。

客户端和服务端通信的函数调用流程

客户端和服务端通信的函数调用流程如下图所示:(如看不清请点击看大图)

clientserver

客户端进程调用接口方法时,最后会都会调用remote()->transact函数提交数据到服务端进程,remote()的类型是IBinder指针,指向的实际类型其实是BpBinder(BpBinder封装了binder实体对象的句柄)。执行BpBinder的transact方法时,会调用IPCThreadState::self()->transact,先前也说到IPCThreadState负责和驱动交互数据,这里它会先调用writeTransactionData方法填充要发送给服务端进程的数据,然后调用waitForResponse方法,而waitForResponse方法会先调用talkWithDriver,talkWithDriver最终会调用ioctl方法和驱动交互,提交数据,并返回服务端进程执行的结果,然后waitForResponse方法会将收到的数据设置到reply对象里,reply为parcel类型对象。

服务端进程一般会调用joinThreadPool函数来等待客户端调用,joinThreadPool函数会先调用talkWithDriver来和驱动交互,最终调用ioctl来等待驱动提交请求,收到请求后会调用executeCommand函数,在executeCommand函数里找到BBinder对象,并执行BBinder的transact方法,BBinder的transact方法会调用它留给子类扩展的onTransact方法,BBinder子类BnInterface的子类会实现onTransact方法,根据不同的请求code转调不同的接口方法。


转自:http://www.cloudchou.com/android/post-534.html

0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:174831次
    • 积分:2609
    • 等级:
    • 排名:第13965名
    • 原创:80篇
    • 转载:63篇
    • 译文:0篇
    • 评论:18条
    文章分类
    最新评论