Android雖然構建在Linux上面,但是在IPC(進程間)機制方面,沒有利用Linux提供IPC機制,而是自己實現了一套輕量級的IPC機制
——binder機制。並且Android
Binder機制之上,Android架構提供了一套封裝,可以實現對象代理(在本地進程中代理遠程進程的對象)。本文簡單分析一下Android
Binder機制。
Binder情景分析
一個IPC通訊我們可以理解成用戶端-伺服器模式,因此我們先在這裡分析一下典型的Binder應用模式:
1、用戶端通過某種方式(後文會詳細介紹)得到伺服器端的代理對象。從用戶端角度看來代理對象和他的本機物件沒有什麼差別。它可以像其他本機物件一樣調用其方法,訪問其變數。
2、用戶端通過調用伺服器代理對象的方法向伺服器端發送請求。
3、代理對象把使用者請求通過Android核心(Linux核心)的Binder驅動發送到伺服器處理序。
4、伺服器處理序處理使用者請求,並通過Android核心(Linux核心)的Binder驅動返回處理結果給用戶端的伺服器代理對象。
5、用戶端收到伺服器端的返回結果。
如果你對COM或者Corba熟悉的話,以上的情景是否會讓你聯想到什麼呢?沒錯!都是對象代理。以上的情景,在Android中經常會被用到。如果你還沒有注意到這點兒,那麼本文非常適合你。
Binder機制的組成1、Binder驅動
binder是核心中的一個字元驅動裝置位於:/dev/binder。這個裝置是Android系統IPC的核心部分,用戶端的服務代理用來通過它向服
務器(server)發送請求,伺服器也是通過它把處理結果返回給用戶端的服務代理對象。我們只需要知道它的功能就可以了,本文我們的重點不在這裡,所以
後面不會專門介紹這部分,因為很少會有人會顯示開啟這個裝置去開發Android程式。如果想深入瞭解的話,請研究核心源碼中的binder.c。
2、Service Manager
負責管理服務。對應於第一步中,用戶端需要向Service Manager來查詢和獲得所需要服務。伺服器也需要向Service Manager註冊自己提供的服務。可以看出Service Manager是服務的大管家。
3、服務(Server)
需要強調的是這裡服務是指的是System Server,而不是SDK server,請參考《(轉)高煥堂——Android架構底層結構知多少?》關於兩種Server的介紹(其實應該是三種,丟掉了init調用的server,在init.rc中配置)。
4、用戶端
一般是指Android系統上面的應用程式。它可以請求Server中的服務。
5、對象代理
是指在用戶端應用程式中產生的Server代理(proxy)。從應用程式角度看代理對象和本機物件沒有差別,都可以調用其方法,方法都是同步的,並且返回相應的結果。
大內總管——Service Manager
Android系統Binder機制的總管是Service Manager,所有的Server(System Server)都需要向他註冊,應用程式需要向其查詢相應的服務。可見其作用是多麼的重要,所以本文首先介紹Service Manager。
通過上面介紹我們知道Service Manager非常重要,責任重大。那麼怎樣才能成為Service
Manager呢?是不是誰都可以成為Service
Manager呢?怎樣處理server的註冊和應用程式的查詢和擷取服務呢?為了回答這些問題先查看,Android中Service
Manager的源碼,其源碼位於:
frameworks\base\cmds\servicemanager\service_manager.c
我們發現了main函數,說明他自己就是一個進程,在init.rc中我們發現:
service servicemanager /system/bin/servicemanager user system critical onrestart restart zygote onrestart restart media
說明其是Android核心程式,開機就會自動運行。
下面我們在研究一下它的代碼,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函數,這個函數使他自己變為了“Server大總管”,其代碼如下:
int binder_become_context_manager(struct binder_state *bs){ return ioctl(bs->fd, BINDER_SET_CONTEXT_MGR, 0);}
也就是通過ioctl向binder裝置宣告“我就是server大總管”。
Service
Manager作為一個Server大總管,本身也是一個server。既然是一個server就要時刻準備為用戶端提供服務。最好Service
Manager調用binder_loop進入到迴圈狀態,並提供了一個回呼函數,等待使用者的請求。注意他的Service
Manager的用戶端既包括應用程式(查詢和擷取服務),也包括Server(註冊服務)。
Service
Manager的客戶怎樣才能請求其服務呢?答案是上文我們提到的情景一樣。客戶需要在自己進程中建立一個伺服器代理。現在沒有地方去查詢服務,那麼怎樣
它的客戶怎樣產生他的服務代理對象呢?答案是binder裝置(/devbinder)為每一個服務維護一個控制代碼,調用
binder_become_context_manager函數變為“Server大總管”的服務,他的控制代碼永遠是0,是一個“眾所周知”的控制代碼,這樣
每個程式都可以通過binder機制在自己的進程空間中建立一個
Service Manager代理對象了。其他的服務在binder裝置在裝置中的控制代碼是不定的,需要向“Server大總管”查詢才能知道。
現在我們需要研究Server怎樣註冊服務了,還是在其源碼中,我們可以看到在其服務處理函數中(上文提到binder_loop函數註冊給binder裝置的回呼函數)有如下代碼:
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;
有server向binder裝置寫入請求註冊Service時,Service Manager的服務處理回呼函數將會被調用。我們在仔細看看do_add_service函數的實現:
int do_add_service(struct binder_state *bs, uint16_t *s, unsigned len, void *ptr, unsigned uid){ struct svcinfo *si;// LOGI("add_service('%s',%p) uid=%d\n", str8(s), ptr, uid); if (!ptr || (len == 0) || (len > 127)) return -1; if (!svc_can_register(uid, s)) { LOGE("add_service('%s',%p) uid=%d - PERMISSION DENIED\n", str8(s), ptr, uid); return -1; } si = find_svc(s, len); if (si) { if (si->ptr) { LOGE("add_service('%s',%p) uid=%d - ALREADY REGISTERED\n", str8(s), ptr, uid); return -1; } si->ptr = ptr; } else { si = malloc(sizeof(*si) + (len + 1) * sizeof(uint16_t)); if (!si) { LOGE("add_service('%s',%p) uid=%d - OUT OF MEMORY\n", str8(s), ptr, uid); return -1; } si->ptr = ptr; si->len = len; memcpy(si->name, s, (len + 1) * sizeof(uint16_t)); si->name[len] = '\0'; si->death.func = svcinfo_death; si->death.ptr = si; si->next = svclist; svclist = si; } binder_acquire(bs, ptr); binder_link_to_death(bs, ptr, &si->death); return 0;}
我們看到首先檢查是否有許可權註冊service,沒許可權就對不起了,出錯返回;然後檢查是否已經註冊過,註冊過的
service將不能再次註冊。然後構造一個svcinfo對象,並加入一個全域鏈表中svclist中。最後通知binder裝置:有一個
service註冊進來。
我們再來看看用戶端怎樣通過Service Manager獲得Service,還是在服務處理函數中(上文提到binder_loop函數註冊給binder裝置的回呼函數)有如下代碼:
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;
我們可以看到通過do_find_service尋找Service如果尋找到的話,寫入reply中返回給用戶端。
本文我們簡單分析了一下Service Manager,後續我們會繼續分析Android binder機制的其他部分。
原文