(1) Android中Binder調用流程 --- 匿名和實名Binder調用

       針對framework源碼:8.1.0

       本系列文章主要結合源碼講解Android下Binder的通訊機制,毫不誇張的說,Binder是Android下最核心的組件之一,其英文叫粘合劑,沒有它,Android下四大組件、各種組件之間的通訊失去了應有的意義。

       其實,網上介紹Binder的文章太多了,這裏我們換另外一個視角來理解下Binder,主要結合源碼和實際的使用流程來看看Binder在Android開發中扮演什麼樣的角色,具有什麼樣的功能,這一節主要從整體上了解下Android開發中用到的各種Service怎麼樣獲取、調用,以及我們自己開發的Service又是怎麼樣在多進程中完成數據交換的。

       首先,我們把Android中的Service分爲實名Service和匿名Service,那什麼是實名Service和匿名Service呢?我們先來看看實名Service,這裏所謂的實名Service主要就是系統提供的各種Service,比如ActivityManagerService、PakcageManagerService等,這些Service是系統在初始化的時候通過ServiceManager註冊到系統中的,所以,我們把這類Service叫做實名Service,下面的流程圖描述使用實名Service的整體流程。

實名Service

       從上圖看出,實名Service的使用涉及到四個進程:ServiceManager、SystemServer、Client、Binder驅動。除了Binder驅動運行在內核,其它三個進程都運行在用戶空間,爲了實現進程之間相互的數據交換,運行在內核層的Binder驅動扮演了這一角色,實現數據在用戶進程之間的交換,Binder驅動這節不講,大家只要知道,Binder驅動實現mmap和ioctl系統調用,完成內核空間和用戶空間緩存的映射以及對緩存和Service的管理。

       我們先看下Service的註冊(只有註冊了客戶端才能查詢到需要的服務),這裏涉及到兩個用戶空間的兩個進程:系統進程SystemServer和ServiceManager服務進程。

ServiceManager進程啓動

frameworks/native/cmds/servicemanager/service_manager.c

       先說說ServiceManager進程的啓動到底做了些什麼?下面是ServiceManager的main函數:

int main(int argc, char** argv)
363{
......
374    bs = binder_open(driver, 128*1024);    // (1)
375    if (!bs) {
......
385    }
386
387    if (binder_become_context_manager(bs)) {       // (2)
388        ALOGE("cannot become context manager (%s)\n", strerror(errno));
389        return -1;
390    }
391
......
415    binder_loop(bs, svcmgr_handler);       // (3)
416
417    return 0;
418}
419

       代碼(1)處的 bs = binder_open(driver, 128*1024); 作用是打開Binder設備,同時初始化緩存空間大小128KB,這裏ServiceManager就是完成Service的註冊、獲取等簡單操作,因此緩存大小爲128KB夠用了。

       代碼(2)處的 binder_become_context_manager(bs作用就是告訴Binder驅動我們這個線程是Binder的管理線程,當然ServiceManager進程自然就是Binder的管理進程,這裏要注意,這個就是Binder設計巧妙之處,因爲成爲Binder的管理線程時Binder驅動會在其內部初始化一個全局的binder_node對象,其handle爲0作爲IServiceManager的遠程代理節點信息,因此,IServiceManager是沒有具體的實現類的,它的實體Binder就是ServiceManager進程,爲什麼呢,因爲ServiceManager進程實現了IServiceManager的接口,下面代碼(3)實現的。

frameworks/native/cmds/servicemanager/binder.c

       代碼(3)是個死循環,不斷調用ioctl來讀取客戶端發來的服務查詢請求,收到客戶端請求後經過一系列的解析,最終交由svcmgr_handler處理,其實現如下:

252int svcmgr_handler(struct binder_state *bs,
253                   struct binder_transaction_data *txn,
254                   struct binder_io *msg,
255                   struct binder_io *reply)
256{
......
296
297    switch(txn->code) {
298    case SVC_MGR_GET_SERVICE:
299    case SVC_MGR_CHECK_SERVICE:
300        ......
309
310    case SVC_MGR_ADD_SERVICE:
311        ......
321
322    case SVC_MGR_LIST_SERVICES: {
323        ......
338    }
339    ......
344    bio_put_uint32(reply, 0);
345    return 0;
346}

       看到了吧,這裏就是實現IServiceManager接口的功能了,所以我們說IServiceManager接口沒有具體的實現類,而是由ServiceManager的svcmgr_handler函數完成的,這就是Binder實現的巧妙,第一個IBinder對象就是這樣實現的,接下來其它的系統提供的Service就可以通過IServiceManager來查詢獲取了。

       下面看下各種系統服務的註冊,系統服務一般是在SystemServer進程裏註冊的,我們是爲了講解Service的調用流程,這裏僅僅看看ActivityManagerService註冊即可。

ActivityManagerService服務註冊

frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java

2554    public void setSystemProcess() {
2555        try {
2556            ServiceManager.addService(Context.ACTIVITY_SERVICE, this, true);
2557            ServiceManager.addService(ProcessStats.SERVICE_NAME, mProcessStats);
2558            ServiceManager.addService("meminfo", new MemBinder(this));
2559            ServiceManager.addService("gfxinfo", new GraphicsBinder(this));
2560            ServiceManager.addService("dbinfo", new DbBinder(this));

       SystemServer啓動的時候會初始化ActivityManagerService,然後調用ActivityManagerService的setSystemProcess方法把ActivityManagerService註冊到ServiceManager中,ServiceManager.addService(Context.ACTIVITY_SERVICE, this, true);這句代碼就是。

       首先ServiceManager是一個IServiceManager的遠程代理(handler爲0),其本地實現就是BpBinder類,這裏有很多知識點,不明白先看流程就行,後面我們會說,這只是說下整體流程。

       通過ServiceManager的遠程代理,使用操作碼SVC_MGR_ADD_SERVICE通過ioctl系統調用(命令碼:BINDER_WRITE_READ)向Binder驅動發送請求,還記得之前講的嗎?ServiceManager進程在死循環裏等待讀取客戶端的請求,就是這裏了,我們向Binder驅動發送操作碼SVC_MGR_ADD_SERVICE的請求後,Binder驅動發現Binder實體的handle爲0(handle爲0對應ServiceManager進程),那麼它就知道處理的進程是ServiceManager,把請求封裝後投遞給ServiceManager進程的任務隊列,然後喚醒ServiceManager進程讓其處理這個請求。

       ServiceManager收到這個請求,開始解析並最終處理SVC_MGR_ADD_SERVICE操作碼的分支,完成Service的註冊,注意,因爲是跨進程的,ServiceManager註冊的Service僅僅是記錄實體Binder的引用、指針地址等信息,真實的IBinder實體類是在SystemServer進程中的(Binder實體類的真實宿主)。

       到這裏大家比較疑惑,那遠程調用怎麼才能調用真正的IBinder實體類來處理業務邏輯呢?答案還是在Binder驅動層,因爲Binder驅動也記錄了我們註冊的Service信息(binder_node),這些信息包括Service屬於哪個進程、其引用等,具體細節後面會講,這裏只要知道大概就行。

       到這裏Service已經註冊到ServiceManager裏了,後面就可以通過名稱來查詢系統提供的服務並使用其提供的功能了。

匿名Service

       ​匿名Service我們這裏僅僅指出其和實名Service區別,其它請參考實名Service。

       ​匿名Service和實名Service區別就在於Service的存儲方式,實名Service是存儲在ServiceManager進程裏的,其實現了key/value的方式來保存和檢索服務,因此,外部可以通過名稱來訪問指定的Service,系統的服務都是註冊在ServiceManager裏的,所以對於客戶端來說是可以通過名稱來查詢服務的。

        而匿名Service存儲的地方根據具體實現而定,比如bindService裏的IServiceConnection就是存儲在LoadApk對象的內部類ServiceDispatcher裏的,如果服務端不向外告知,外部是不知道有這個IServiceConnection對象存在的,這也是ActivityManagerService的遠程方法bindService爲什麼有IServiceConnection這個參數的原因,因爲它需要明確獲取IServiceConnection這個客戶端對象,當服務綁定成功後纔可以通過這個對象把服務傳給遠程的客戶端。

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

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