論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 plaincopy在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. }  
  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驅動打交道的地方所在

  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驅動的交互主要是接收其他的客戶端請求

  1. void ProcessState::startThreadPool()  
  2. {  
  3.     AutoMutex _l(mLock);  
  4.     if (!mThreadPoolStarted) {  
  5.         mThreadPoolStarted = true;  
  6.         spawnPooledThread(true);  
  7.     }  
  8. }  
  1. void IPCThreadState::joinThreadPool(bool isMain)  
  2. {  
  3. talkWithDriver();  
  4. executeCommand();  
  5. }  

在這裏是通過獲取和binder驅動的交互,得到待處理的信息後進行executeCommand的執行,該函數其實內部就是找到對應的本地的BBinder來執行他的transact,而通過上圖的繼承關係可知,一般就直接有Bnxxx的Ontransact來解析完成,如下所示;

  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)其實內部的實現是這樣的:

  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:

  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. }  
  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架構中會普遍的用到,所以先在這裏總一個最簡單的應用方式總結,以便更好的閱讀代碼。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章