论Android Binder驱动在Framework中的重要性

本文转自:http://blog.csdn.net/gzzaigcnforever/article/details/20606735

这篇博文其实就是想简单的来记录下Binder驱动在Android中的重要性,早在2012年的时候就按着2.3的源码深入学习过Binder驱动的底层实现(Android之binder驱动个人学习小结),Binder驱动主要是android为了构建C/S的通信模型而量身定做的,没有过多复杂的协议,一个Parcl基本包含了所要传递的所有信息,本文就对FrameWork从运用到的Binder机制做一个模型的总结。

 

还是先把Android的Binder驱动架构提炼出来先,如下图所示是典型的CS架构,和Binder驱动密切相关的结构体包括BBinder、BpBinder、BpRefBase:

一个基于Binder的驱动架构,一般的实现过程分为如下几部:

先来看下Binder架构下涉及的一般类图布局会如下所示

基于以上Android的类,我们构建的Ixxx定义整个通信的接口函数,主要由Bpxxx来实现但主要是进行命令字与数据的打包传输,然后远程链接到本地的Bnxxx进行业务的解析与处理。一般需要构建2个文件:Ixxx.h,Ixxx.cpp.

在Ixxx.h内部申请Ixxx接口类,以及类Bnxxx的申明,一般该类只对应一个成员函数即OnTransact;在Ixxx.cpp中主要实现类Bpxxx的申明以及对Ixxx的接口函数进行实现,其核心是调用BpBinder来实现的。

理解Binder最好的方式是ServiceManager,一般以BnxxxService命名服务,都会向其进行服务的注册,而BpxxxClient是直接通过和SM在客户端的代理来获取BnxxxService在本地的代理。

其实按照我个人的理解,Bpxxx和Bnxxx更好的理解是2个进程间的通信,当然作为Service和Client是最好的使用方式。比如先前通过一个客户端的BpxxxClient发出一个请求建立一个Client处的Bpxxx接口,相应的在服务端也就存在着Bnxxx的实现函数,故而这两者之间就可以实现正常的通讯,当然Bnxxx不在是以服务的形象存在与SM中,只是简单的实现进程、线程间的通信而已。

 

下面将从一个SurfaceFlinger进程的启动到Binder驱动的操作,以及Bnxxx和Bpxxx的通信来简单介绍。

step1: Binder驱动的open和mmap过程

[html]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. int main(int argc, char** argv) {  
  2.     SurfaceFlinger::publishAndJoinThreadPool(true);  
  3.     // When SF is launched in its own process, limit the number of  
  4.     // binder threads to 4.  
  5.     ProcessState::self()->setThreadPoolMaxThreadCount(4);  
  6.     return 0;  
  7. }  
[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. sp<ProcessState> ProcessState::self()  
  2. {  
  3.     Mutex::Autolock _l(gProcessMutex);  
  4.     if (gProcess != NULL) {  
  5.         return gProcess;  
  6.     }  
  7.     gProcess = new ProcessState;  
  8.     return gProcess;  
  9. }  

ProcessState作为一个进程中唯一的变量(所谓的单列模式),他是真正和Binder驱动打交道的地方所在

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. ProcessState::ProcessState()  
  2.     : mDriverFD(open_driver())  
  3.     , mVMStart(MAP_FAILED)  
  4.     , mManagesContexts(false)  
  5.     , mBinderContextCheckFunc(NULL)  
  6.     , mBinderContextUserData(NULL)  
  7.     , mThreadPoolStarted(false)  
  8.     , mThreadPoolSeq(1)  
  9. {  
  10.     if (mDriverFD >= 0) {  
  11.         // XXX Ideally, there should be a specific define for whether we  
  12.         // have mmap (or whether we could possibly have the kernel module  
  13.         // availabla).  
  14. #if !defined(HAVE_WIN32_IPC)  
  15.         // mmap the binder, providing a chunk of virtual address space to receive transactions.  
  16.         mVMStart = mmap(0, BINDER_VM_SIZE, PROT_READ, MAP_PRIVATE | MAP_NORESERVE, mDriverFD, 0);  
  17.         if (mVMStart == MAP_FAILED) {  
  18.             // *sigh*  
  19.             ALOGE("Using /dev/binder failed: unable to mmap transaction memory.\n");  
  20.             close(mDriverFD);  
  21.             mDriverFD = -1;  
  22.         }  
  23. #else  
  24.         mDriverFD = -1;  
  25. #endif  
  26.     }  
  27.   
  28.     LOG_ALWAYS_FATAL_IF(mDriverFD < 0, "Binder driver could not be opened.  Terminating.");  
  29. }  

上述的构造函数主要完成Binder驱动的打开已经mmap的操作。

step2:Binder驱动的交互主要是接收其他的客户端请求

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. void ProcessState::startThreadPool()  
  2. {  
  3.     AutoMutex _l(mLock);  
  4.     if (!mThreadPoolStarted) {  
  5.         mThreadPoolStarted = true;  
  6.         spawnPooledThread(true);  
  7.     }  
  8. }  
[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. void IPCThreadState::joinThreadPool(bool isMain)  
  2. {  
  3. talkWithDriver();  
  4. executeCommand();  
  5. }  

在这里是通过获取和binder驱动的交互,得到待处理的信息后进行executeCommand的执行,该函数其实内部就是找到对应的本地的BBinder来执行他的transact,而通过上图的继承关系可知,一般就直接有Bnxxx的Ontransact来解析完成,如下所示;

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. status_t BBinder::transact(  
  2.     uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)  
  3. {  
  4.     data.setDataPosition(0);  
  5.   
  6.     status_t err = NO_ERROR;  
  7.     switch (code) {  
  8.         case PING_TRANSACTION:  
  9.             reply->writeInt32(pingBinder());  
  10.             break;  
  11.         default:  
  12.             err = onTransact(code, data, reply, flags);//虚函数子类被重载                                                                  break;  
  13.     }  
  14.   
  15.     if (reply != NULL) {  
  16.         reply->setDataPosition(0);  
  17.     }  
  18.   
  19.     return err;  
  20. }  


 step3: 作为客户端是如何发送相关消息的

 当你在Client有了对应的proxy后,直接操作的就是BpBinder的相关内容,我们常常见到的remote->(xxx)其实内部的实现是这样的:

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. status_t BpBinder::transact(  
  2.     uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)  
  3. {  
  4.     // Once a binder has died, it will never come back to life.  
  5.     if (mAlive) {  
  6.         status_t status = IPCThreadState::self()->transact(  
  7.             mHandle, code, data, reply, flags);  
  8.         if (status == DEAD_OBJECT) mAlive = 0;  
  9.         return status;  
  10.     }  
  11.   
  12.     return DEAD_OBJECT;  
  13. }  

可以看到是一个IPCThreadState在和帮助者你,再看他的transaction:

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. status_t IPCThreadState::transact(int32_t handle,  
  2.                                   uint32_t code, const Parcel& data,  
  3.                                   Parcel* reply, uint32_t flags)//数据的发送  
  4. {  
  5.    if (reply) {  
  6.             err = waitForResponse(reply);//等待服务端的回复  
  7. }  
[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. status_t IPCThreadState::waitForResponse(Parcel *reply, status_t *acquireResult)  
  2. {  
  3. status_t IPCThreadState::talkWithDriver(bool doReceive)//和底层走的最近的地方  
  4.   
  5. }  



其实无论是Binder的服务端还是客户端,真正的Binder在内核驱动中度会为当前的进程维护一个binder的node树,只有有新的节点产生经过内核驱动后都会记录下来,使得一旦远程的客户通过代理访问时,都是能找到对应的Binder实体,并找个该实体所示的loop服务线程,进行必要的唤醒与处理。最终反馈处理后的数据到客户端,客户端益是从线程的等待到唤醒这个过程来响应相关的处理结果,进行保存。

Binder驱动在下面要介绍的camera和SurfaceFlinger架构中会普遍的用到,所以先在这里总一个最简单的应用方式总结,以便更好的阅读代码。


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值