1. 程式人生 > >Binder機制分析(1)——Binder結構簡介

Binder機制分析(1)——Binder結構簡介

本文是對《Android技術內幕-系統卷》第三章的摘抄和整理。

一。Binder 介紹
Binder機制實際上就是一個類似於C/S的構架:客戶端程序要想與服務端程序通訊就必須在客戶端建立一個服務端程序代理物件,然後將請求傳送到代理物件上;代理物件通過Binder驅動將請求轉發給服務端程序處理;當處理完成之後,再次通過Binder驅動傳回給代理物件,客戶端從代理物件獲取響應資訊。
client和service之間通過binder通訊,但是兩者都不會直接與Binder driver打交道,而是交給Binder Adapter來做。
Binder Adapter由ProcessState和IPCThreadState組成。
其中ProcessState類中包含了通訊細節,利用open_binder開啟

Linux裝置dev\binder。
每個程序只有一個ProcessState物件,ProcessState是一個singleton型別,其作用是維護當前程序中的所有Service代理。一個客戶端程序可能需要多個Service的服務,這樣可能會建立多個Service代理,客戶端程序中的ProcessState物件就負責維護這些Service代理。
每一個執行緒中都會有一個IPCThreadState物件,它主要負責Binder資料讀取、寫入和請求處理框架。

1. ProcessState分析
    1.1 ProcessState::self()的實現
        sp<ProcessState> ProcessState::self()  
        {  
            if (gProcess != NULL) return gProcess;  
            AutoMutex _l(gProcessMutex);  
            if (gProcess == NULL) gProcess = new ProcessState;  
            return gProcess;  
        } 
    ProcessState放置在全域性變數gProcess中,如果gProcess為NULL,則新建一個ProcessStat
    
    1.2 ProcessState::ProcessState()的實現
        ProcessState::ProcessState()  
        : mDriverFD(open_driver())//開啟Binder裝置驅動  
        , mVMStart(MAP_FAILED)//對映記憶體的起始地址  
        , mManagesContexts(false)  
        , mBinderContextCheckFunc(NULL)  
        , mBinderContextUserData(NULL)  
        , mThreadPoolStarted(false)  
        , mThreadPoolSeq(1)  
        {  
            if (mDriverFD >= 0) {  
        #if !defined(HAVE_WIN32_IPC)  
                //將fd對映為記憶體  
                mVMStart = mmap(0, BINDER_VM_SIZE, PROT_READ, MAP_PRIVATE | MAP_NORESERVE,  
                mDriverFD, 0);  
                if (mVMStart == MAP_FAILED) {  
                    close(mDriverFD);  
                    mDriverFD = -1;  
                }  
        #else  
                mDriverFD = -1;  
        #endif  
            }  
            if (mDriverFD < 0) {  
            }  
        } 
    該建構函式首先通過open_driver()開啟Binder裝置驅動(/dev/binder),然後通過ioctrl建立基本的通訊框架。
    
    1.3 getStrongProxyForHandle的實現
    sp<IBinder> ProcessState::getStrongProxyForHandle(int32_t handle)
    {
        sp<IBinder> result;
        AutoMutex _l(mLock);
        handle_entry* e = lookupHandleLocked(handle);
        if (e != NULL) {
            // We need to create a new BpBinder if there isn't currently one, OR we
            // are unable to acquire a weak reference on this current one.  See comment
            // in getWeakProxyForHandle() for more info about this.
            IBinder* b = e->binder;
            if (b == NULL || !e->refs->attemptIncWeak(this)) {
                b = new BpBinder(handle); 
                e->binder = b;
                if (b) e->refs = b->getWeakRefs();
                result = b;
            } else {
                // This little bit of nastyness is to allow us to add a primary
                // reference to the remote proxy when this team doesn't have one
                // but another team is sending the handle to us.
                result.force_set(b);
                e->refs->decWeak(this);
            }
        }
        return result;
    }
    當需要建立一個服務端代理物件時,就會呼叫getStrongProxyForHandle來實現
    該函式首先呼叫lookupHandleLocked函式,查詢當前程序維護的Service代理物件的列表,檢視要建立的Service代理物件是否已經在當前程序中建立。如果已經建立過了,則直接返回其引用就可以了;否則,將會在Service代理物件的列表中增加相應的位置,儲存將要建立的代理物件。這裡大家已經看到的所謂的服務端代理物件,其實就是BpBinder物件。
    
2. IPCThreadState分析
    2.1 在構造ProcessSate的時候,使用open_binder開啟/driver/binder,並將控制代碼記錄在mDriverFD中。但是在ProcessState中並不使用這個控制代碼,真正使用這個Binder裝置控制代碼的是IPCThreadState,所有關於Binder的操作都放置在IPCThreadState中,以下是3個重要的函式。
    talkWithDriver()  讀取/寫入
    executeCommand(...)  請求處理
    joinThreadPool()  迴圈結構
    2.2 talkWithDriver分析
        status_t IPCThreadState::talkWithDriver(bool doReceive)  
        {  
            //省略部分程式碼  
        #if defined(HAVE_Android_OS)  
                if (ioctl(mProcess->mDriverFD, BINDER_WRITE_READ, &bwr) >= 0)  
                    err = NO_ERROR;  
                else  
                    err = -errno;  
        #else  
            //省略部分程式碼  
            return err;  
        } 
        talkWithDriver負責讀取和寫入,實際上就是通過ioctl對ProcessState開啟的控制代碼進行讀寫,使用者可以不直接通過ioctl來操作Binder裝置,通過IPCThreadState物件來代理即可。
    
二。Service Manager分析
1. Android啟動時就會自動執行的一個核心程序。init.rc中的servicemanager片段:
    service servicemanager /system/bin/servicemanager  
        user system  
        critical  
        onrestart restart zygote  
        onrestart restart media 
2. Service Manager的main函式。
    int main(int argc, char **argv)  
    {  
        struct binder_state *bs;  
        void *svcmgr = BINDER_SERVICE_MANAGER;  
        bs = binder_open(128*1024);  
        if (binder_become_context_manager(bs)) {  
            LOGE("cannot become context manager (%s)\n", strerror(errno));  
            return -1;  
        }  
        svcmgr_handle = svcmgr;  
        binder_loop(bs, svcmgr_handler);  
        return 0;  
    } 
    該函式首先呼叫binder_open開啟Binder裝置(/dev/binder),其次,它呼叫了binder_become_ context_manager函式,將自己設定為Service Manager。因為Service Manager本身就是一個服務,只是它比較特殊,會管理其他所有的服務,也正是binder_become_context_manager函式將其變為服務管理器的。
3. binder_become_context_manager的實現
    int binder_become_context_manager(struct binder_state *bs)  
    {  
        return ioctl(bs->fd, BINDER_SET_CONTEXT_MGR, 0);  
    } 
4. svcmgr_handler的實現
    在main函式最後呼叫binder_loop進入迴圈狀態,並設定一個回撥函式,等待使用者的請求。
    int svcmgr_handler(struct binder_state *bs,  
                   struct binder_txn *txn,  
                   struct binder_io *msg,  
                   struct binder_io *reply)  
    {  
        //省略部分程式碼  
        switch(txn->code) {  
        //獲取服務和查詢服務  
        case SVC_MGR_GET_SERVICE:  
        case SVC_MGR_CHECK_SERVICE:  
            s = bio_get_string16(msg, &len);  
            ptr = do_find_service(bs, s, len);  
            if (!ptr)  
                break;  
            bio_put_ref(reply, ptr);  
            return 0;  
        //新增服務  
        case SVC_MGR_ADD_SERVICE:  
            s = bio_get_string16(msg, &len);  
            ptr = bio_get_ref(msg);  
            if (do_add_service(bs, s, len, ptr, txn->sender_euid))  
                return -1;  
            break;  
     
        case SVC_MGR_LIST_SERVICES: {  
         //省略部分  
        }  
        default:  
            LOGE("unknown code %d\n", txn->code);  
            return -1;  
        }  
        bio_put_uint32(reply, 0);  
        return 0;  
    }     
5. do_add_service的實現
    當有新的服務需要新增或者客戶端要獲得某個已經新增的服務時都會觸發該回調函式,新增函式(SVC_MGR_ADD_SERVICE)操作則會呼叫do_add_service來完成。
    int do_add_service(struct binder_state *bs, uint16_t *s, unsigned len,  
                   void *ptr, unsigned uid)  
    {  
        struct svcinfo *si;  
        if (!ptr || (len == 0) || (len > 127))  
            return -1;  
        if (!svc_can_register(uid, s)) {  
            return -1;  
        }  
        si = find_svc(s, len);  
        if (si) {  
            //省略部分程式碼  
            si->ptrptr = ptr;  
        } else {  
            si = malloc(sizeof(*si) + (len + 1)  
    sizeof(uint16_t));  
            //省略部分程式碼  
            si->next = svclist;  
            svclist = si;  
        }  
        binder_acquire(bs, ptr);  
        binder_link_to_death(bs, ptr, &si->death);  
        return 0;  
    }   
    新增過程為:首先,檢查是否有許可權註冊Service;然後,檢查是否已經註冊過Service,註冊過的Service將不能再次註冊;接下來構造一個svcinfo物件,並將其加入到一個全域性連結串列(svclist)中;最後,通知Binder裝置有一個Service註冊進來了。新增Binder裝置之後會為每一個服務都維護一個控制代碼,當查詢和獲得某個服務時就會使用這個控制代碼。當然,Service Manager的控制代碼在呼叫了binder_become_context_manager之後就變為0了,作為服務管理器。當客戶端需要獲得一個服務時,就會觸發SVC_MGR_GET_SERVICE命令,再呼叫do_find_service來查詢指定的服務,查詢過程就是在服務列表中查詢即可,找到之後寫入reply中返回給客戶端。

二。Binder的機制    
1. IBinder
    Android對Binder機制進行了抽象,定義了IBinder介面,該介面是對跨程序物件的抽象,在C/C++和
Java
層都有定義。IBinder定義了一套使用Binder機制來實現客戶程式與伺服器的通訊協議。
    一個普通物件只能在當前程序中被訪問,如果希望它能被其他程序訪問,就必須實現IBinder介面。IBinder介面可以指向本地物件,也可以指向遠端物件,關鍵就在於IBinder介面中的transact函式。如果IBinder指向的是一個服務端代理,那麼transact只是負責把請求傳送給伺服器;如果IBinder指向的是一個服務端,那麼transact只負責提供服務即可。因此,不管是服務端還是服務端代理物件,都必須實現該介面,這樣才能進行Binder通訊。
2. 服務端代理物件BpBinder
    BpBinder是服務端代理物件,即遠端物件在當前程序的代理。實際上,它也是Binder通訊存在於客戶端的程序,它實現了IBinder介面,它的transact函式的實現:
    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::self()的transact函式,將請求通過核心模組傳送給了服務端,服務端處理完請求之後,沿原路返回結果給呼叫者。注意transact方法是同步方法,將會掛起客戶程序的當前執行緒,直到Service把請求處理完成並返回結果。
3. 服務端BBinder
    服務端同樣需要實現IBinder介面,這裡我們以Android預設的服務端實現類(BBinder)為例進行介紹,其中transact的實現:
    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;  
    }     

    其中,PING_TRANSACTION請求用來檢查物件是否還存在,這裡簡單地把 pingBinder的返回值返回給呼叫者,其他的請求交給onTransact處理。onTransact是Bbinder中宣告的一個protected型別的虛擬函式,這個要求它的子類去實現,在下一節分析Binder的具體實現時會詳細介紹。