(2) Android中Binder調用流程 --- Binder環境的初始化

       我們知道,在Android裏Binder是進程間通信的基礎,而且,Android的應用程序天生就支持Binder通信,爲什麼?沒了Binder,Android裏的四大組件將沒法運轉,比如Activity的啓動其實是通過AMS來管理的,Activity裏的那個token成員變量其實就是Activity在AMS中一條記錄的引用,而這些都是跨進程的。
       既然Binder是Android裏跨進程交換數據的基礎,像查詢系統服務這些操作也是通過IServiceManager這個IBinder來完成的,那麼問題來了,Android世界裏的第一個IBinder是什麼?在那裏實現的?
       這就是說我們要找到最先孵化出蛋的小雞在那裏,要不這麼多小雞那裏來的:)嗯,這就是關鍵,還記得上節我們說過的ServiceManager進程的初始化嗎?對,就是它,上節我們說這個進程實際上就是IServiceManager這個IBinder的具體實現,到這裏可能有點暈了,一個進程怎麼是接口的實現呢,準確說是ServiceManager進程的svcmgr_handler函數實現了IServiceManager接口功能的,還是暈,這不符合面向對象編程,但事實就是這樣,ServiceManager是藉助Binder驅動來完成這些功能,而我們獲取的IServiceManager接口實際是通過BpBinder(這個後面會講)來代理的,其handle爲0,下面給出ServiceManager進程啓動初始化流程圖。

       根據上圖,我們講下具體的流程,分爲兩個部分:IServiceManager初始化和使用。
       

IServiceManager初始化

    1)ServiceManager進程啓動;
    2)初始化Binder驅動設備;
    3)向Binder驅動申請成爲Binder的管理者;
    4)Binder驅動內部生成一個全局的binder_node節點,並設置其handle爲0;
    5)ServiceManager進程進入死循環,不斷從Binder驅動讀取客戶端請求;
    6) ServiceManager收到客戶端請求,解析請求,根據解析出的命令分別處理;
    7) 把處理結果通過Binder驅動發送給請求的客戶端,完成一次命令處理。

客戶端使用請求

       我們這裏以註冊Service爲例進行說明。
       1)通過ServiceManagerNative獲取IServiceManager代理接口;
       2)獲取的IServiceManager接口遠程代理對象在JAVA層對應的是BinderProxy,在Native層對應的是BpBinder;
       3)BinderProxy是通過BinderInternal.getContextObject()獲取的;
       4)BinderInternal.getContextObject()是一個native方法,其內部就是通過handle爲0來生成一個BpBinder對象,然後把這個本地對象保存在BinderProxy的mObject成員變量裏(在native層通過這個成員變量得到native層的BpBinder)。
       5)因此最終IBinder實際調用的是BpBinder的transact()函數;
       6)在BpBinder的transact()函數內部,實際調用的是IPCThreadState的transact來處理的,數據經過層層封裝,最終調用ioctl(mProcess->mDriverFD,BINDER_WRITE_READ, &bwr)把請求發送到Binder驅動層;
       7)Binder驅動層收到請求後,解析發現handle爲0,然後找到handle爲0對應的進程ServiceManager,最後把請求放到ServiceManager的處理隊列並喚醒ServiceManager;
       8)ServiceManager收到客戶端請求後,根據請求碼進行處理,這裏是註冊Service,因此在列表中插入註冊的Service信息,這裏要注意,新註冊的Service就是個IBinder,其對應handle由Binder驅動生成了,因此,這裏會根據handle查詢列表是否存在,不存在插入一條Service信息。

通過上面流程的描述,有幾個關鍵點

       1)我們實際獲取的IServiceManager僅僅是一個代理,其本地對象實現是BpBinder;
       2)IServiceManager的handle固定是0,其沒有名稱,也不需要;
       3)IServiceManager的具體實現是ServiceManager結合Binder驅動完成的;
       4)每個IBinder對象都和一個32位的整型handle一一對應,並且這個handle是由Binder驅動層生成的。

       到這裏大家應該明白了Android世界裏的第一個IBinder是誰了,沒錯,就是ServiceManager,其實現了IServiceManager的接口功能,這也是Android設計的巧妙之處。
       知道了第一個IBinder之後,接下來我們看下應用進程怎麼初始化Binder環境並使用的。其實,在ServiceManager裏我們已經知道怎麼樣使用Binder了,就是通過ioctl系統調用完成的,並使用命令BINDER_WRITE_READ完成一次讀寫操作。
       Binder驅動裏定義很多命令,用來控制讀寫、環境參數設置等。回到主題,看下應用進程怎麼初始化Binder環境的。
       我們知道應用程序進程是由Zygote進程fork出來的,而這最終會調用ZygoteInit.zygoteInit這個方法。

       frameworks/base/core/java/com/android/internal/os/ZygoteInit.java

public static final void zygoteInit(int targetSdkVersion, String[] argv,
830            ClassLoader classLoader) throws Zygote.MethodAndArgsCaller {
......
837
838        RuntimeInit.commonInit();
839        ZygoteInit.nativeZygoteInit();
840        RuntimeInit.applicationInit(targetSdkVersion, argv, classLoader);
841    }

       我們看到調用了本地方法ZygoteInit.nativeZygoteInit();
       frameworks/base/core/jni/AndroidRuntime.cpp

static void com_android_internal_os_ZygoteInit_nativeZygoteInit(JNIEnv* env,
jobject clazz)
222{
223    gCurRuntime->onZygoteInit();
224}

       gCurRuntime就是一個AppRuntime類型的對象:

       frameworks/base/cmds/app_process/app_main.cpp

virtual void onZygoteInit()
92    {
93        sp<ProcessState> proc = ProcessState::self();
94        ALOGV("App process: starting thread pool.\n");
95        proc->startThreadPool();
96    }

       sp<ProcessState> proc = ProcessState::self();這句代碼初始化了Binder驅動設備並調用mmap分配了1M的緩存;接下來proc->startThreadPool();這句代碼則把新建一個線程作爲Binder線程(處理Binder的請求等等)。
       所以,一開始應用進程僅僅啓動一個Binder線程,而SystemService開始啓動兩個binder線程來處理請求(SystemServer主線程是一個,通過ProcessState啓動一個)。

       本系列文章均爲原創,主要總結作者多年在軟件行業的一些經驗,和大家共同學習、進步,轉載請註明出處,謝謝!

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