本文轉自: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過程
- int main(int argc, char** argv) {
- SurfaceFlinger::publishAndJoinThreadPool(true);
- // When SF is launched in its own process, limit the number of
- // binder threads to 4.
- ProcessState::self()->setThreadPoolMaxThreadCount(4);
- return 0;
- }
- sp<ProcessState> ProcessState::self()
- {
- Mutex::Autolock _l(gProcessMutex);
- if (gProcess != NULL) {
- return gProcess;
- }
- gProcess = new ProcessState;
- return gProcess;
- }
ProcessState作爲一個進程中唯一的變量(所謂的單列模式),他是真正和Binder驅動打交道的地方所在
- ProcessState::ProcessState()
- : mDriverFD(open_driver())
- , mVMStart(MAP_FAILED)
- , mManagesContexts(false)
- , mBinderContextCheckFunc(NULL)
- , mBinderContextUserData(NULL)
- , mThreadPoolStarted(false)
- , mThreadPoolSeq(1)
- {
- if (mDriverFD >= 0) {
- // XXX Ideally, there should be a specific define for whether we
- // have mmap (or whether we could possibly have the kernel module
- // availabla).
- #if !defined(HAVE_WIN32_IPC)
- // mmap the binder, providing a chunk of virtual address space to receive transactions.
- mVMStart = mmap(0, BINDER_VM_SIZE, PROT_READ, MAP_PRIVATE | MAP_NORESERVE, mDriverFD, 0);
- if (mVMStart == MAP_FAILED) {
- // *sigh*
- ALOGE("Using /dev/binder failed: unable to mmap transaction memory.\n");
- close(mDriverFD);
- mDriverFD = -1;
- }
- #else
- mDriverFD = -1;
- #endif
- }
- LOG_ALWAYS_FATAL_IF(mDriverFD < 0, "Binder driver could not be opened. Terminating.");
- }
上述的構造函數主要完成Binder驅動的打開已經mmap的操作。
step2:Binder驅動的交互主要是接收其他的客戶端請求
- void ProcessState::startThreadPool()
- {
- AutoMutex _l(mLock);
- if (!mThreadPoolStarted) {
- mThreadPoolStarted = true;
- spawnPooledThread(true);
- }
- }
- void IPCThreadState::joinThreadPool(bool isMain)
- {
- talkWithDriver();
- executeCommand();
- }
在這裏是通過獲取和binder驅動的交互,得到待處理的信息後進行executeCommand的執行,該函數其實內部就是找到對應的本地的BBinder來執行他的transact,而通過上圖的繼承關係可知,一般就直接有Bnxxx的Ontransact來解析完成,如下所示;
- status_t BBinder::transact(
- uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
- {
- data.setDataPosition(0);
- status_t err = NO_ERROR;
- switch (code) {
- case PING_TRANSACTION:
- reply->writeInt32(pingBinder());
- break;
- default:
- err = onTransact(code, data, reply, flags);//虛函數子類被重載 break;
- }
- if (reply != NULL) {
- reply->setDataPosition(0);
- }
- return err;
- }
step3: 作爲客戶端是如何發送相關消息的
當你在Client有了對應的proxy後,直接操作的就是BpBinder的相關內容,我們常常見到的remote->(xxx)其實內部的實現是這樣的:
- status_t BpBinder::transact(
- uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
- {
- // Once a binder has died, it will never come back to life.
- if (mAlive) {
- status_t status = IPCThreadState::self()->transact(
- mHandle, code, data, reply, flags);
- if (status == DEAD_OBJECT) mAlive = 0;
- return status;
- }
- return DEAD_OBJECT;
- }
可以看到是一個IPCThreadState在和幫助者你,再看他的transaction:
- status_t IPCThreadState::transact(int32_t handle,
- uint32_t code, const Parcel& data,
- Parcel* reply, uint32_t flags)//數據的發送
- {
- if (reply) {
- err = waitForResponse(reply);//等待服務端的回覆
- }
- status_t IPCThreadState::waitForResponse(Parcel *reply, status_t *acquireResult)
- {
- status_t IPCThreadState::talkWithDriver(bool doReceive)//和底層走的最近的地方
- }
其實無論是Binder的服務端還是客戶端,真正的Binder在內核驅動中度會爲當前的進程維護一個binder的node樹,只有有新的節點產生經過內核驅動後都會記錄下來,使得一旦遠程的客戶通過代理訪問時,都是能找到對應的Binder實體,並找個該實體所示的loop服務線程,進行必要的喚醒與處理。最終反饋處理後的數據到客戶端,客戶端益是從線程的等待到喚醒這個過程來響應相關的處理結果,進行保存。
Binder驅動在下面要介紹的camera和SurfaceFlinger架構中會普遍的用到,所以先在這裏總一個最簡單的應用方式總結,以便更好的閱讀代碼。