我們知道,在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啓動一個)。
本系列文章均爲原創,主要總結作者多年在軟件行業的一些經驗,和大家共同學習、進步,轉載請註明出處,謝謝!