ServiceManager 是 Android 系統中重要的組成部分,咱們有必要理解它的工做原理,本文從三個方面介紹:服務器
Binder 是 Android 中使用最普遍的 IPC 機制,正由於有了 Binder,Android 系統中形形色色的進程與組件才能真正統一成有機的總體。Binder 通訊機制與 TCP/IP 有共通之處,其組成元素能夠這樣來類比:app
ServiceManager 是爲了完成 Binder Server 的 Name(域名)和 Handle(IP 地址)之間對應關係的查詢而存在的,它主要包含的功能:函數
註冊:當一個 Binder Server 建立後,應該將這個 Server 的 Name 和 Handle 對應關係記錄到 ServiceManager 中oop
查詢:其餘應用能夠根據 Server 的 Name 查詢到對應的 Service Handleui
但 ServiceManager 自身也是一個 Binder Server(服務器),怎麼找到它的 "IP 地址"呢?Binder 機制對此作了特別規定:ServiceManager 在 Binder 通訊過程當中的 Handle 永遠是 0。spa
Android 系統第一個啓動的 init 進程解析 init.rc 腳本時構建出系統的初始運行狀態,Android 系統服務大可能是在這個腳本中描述並被相繼啓動的,包括 zygote、mediaserver、surfaceflinger 以及 servicemanager 等,其中 servicemanager 描述以下:指針
#init.rc
service servicemanager /system/bin/servicemanager
class core
user system
group system
critical
onrestart restart healthd
onrestart restart zygote
onrestart restart media
onrestart restart surfaceflinger
onrestart restart drm
複製代碼
能夠看到,當 ServiceManager 發生問題重啓時,其餘 healthd、zygote、media 等服務也會被重啓。ServiceManager 服務啓動後會執行 service_manager.c 的 main 函數,關鍵代碼以下:rest
//frameworks/native/cmds/servicemanager/service_manager.c
int main(){
bs = binder_open(128*1024);
if (binder_become_context_manager(bs)) {
...
}
...
binder_loop(bs, svcmgr_handler);
return 0;
}
複製代碼
其中三個函數對應了 ServiceManager 初始化的三個關鍵工做:code
下面分別來分析這三個函數,首先來看 binder_open() 是怎麼打開 binder 驅動並映射內存的:cdn
struct binder_state *binder_open(size_t mapsize){
struct binder_state *bs;
struct binder_version vers;
bs = malloc(sizeof(*bs));
...
//打開 binder 驅動,最終調用 binder_open() 函數
bs->fd = open("/dev/binder", O_RDWR | O_CLOEXEC);
...
//獲取 Binder 版本,最終調用 binder_ioctl() 函數
ioctl(bs->fd, BINDER_VERSION, &vers)
...
//將虛擬內存映射到 Binder,最終調用 binder_mmap() 函數
bs->mapped = mmap(NULL, mapsize, PROT_READ, MAP_PRIVATE, bs->fd, 0);
...
return bs;
}
複製代碼
再來看 binder_become_context_manager() 是怎麼將本身設置爲 Binder "DNS 管理者的":
int binder_become_context_manager(struct binder_state *bs){
//發送 BINDER_SET_CONTEXT_MGR 命令,最終調用 binder_ioctl() 函數
return ioctl(bs->fd, BINDER_SET_CONTEXT_MGR, 0);
}
複製代碼
最後來看 binder_loop() 是怎麼循環等待並處理 binder 驅動發來的消息:
void binder_loop(struct binder_state *bs, binder_handler func){
int res;
//執行 BINDER_WRITE_READ 命令所需的數據格式:
struct binder_write_read bwr;
uint32_t readbuf[32]; //每次讀取數據的大小
readbuf[0] = BC_ENTER_LOOPER;
//先將 binder 驅動的進入循環命令發送給 binder 驅動:
binder_write(bs, readbuf, sizeof(uint32_t));
for (;;) { //進入循環
bwr.read_size = sizeof(readbuf);
//讀取到的消息數據存儲在 readbuf
bwr.read_buffer = (uintptr_t) readbuf;
//執行 BINDER_WRITE_READ 命令讀取消息數據
res = ioctl(bs->fd, BINDER_WRITE_READ, &bwr);
if (res < 0) {
ALOGE("binder_loop: ioctl failed (%s)\n", strerror(errno));
break;
}
//處理讀取到的消息數據
res = binder_parse(bs, 0, (uintptr_t) readbuf, bwr.read_consumed, func);
...
}
}
複製代碼
BINDER_WRITE_READ 命令既能夠用來讀取數據也能夠寫入數據,具體是寫入仍是讀取依賴 binder_write_read 結構體的 write_size 和 read_size 哪一個大於 0,上面代碼經過 bwr.read_size = sizeof(readbuf) 賦值,因此是讀取消息。
binder_parse() 方法內部處理由 binder 驅動主動發出的、一系列 BR_ 開頭的命令,包括上面提到過的 BR_TRANSACTION、BR_REPLY 等,簡化後的代碼以下:
int binder_parse(struct binder_state *bs, struct binder_io *bio,
uintptr_t ptr, size_t size, binder_handler func){
switch(cmd) {
case BR_TRANSACTION: {
...
res = func(bs, txn, &msg, &reply); //處理消息
//返回處理結果
inder_send_reply(bs, &reply, txn->data.ptr.buffer, res);
...
break;
}
case BR_REPLY: {...}
case BR_DEAD_BINDER: {...}
...
}
}
複製代碼
對於 BR_TRANSACTION 命令主要作了兩個工做,一是調用 func() 具體處理消息;二是調用 inder_send_reply() 將消息處理結果告知給 binder 驅動,注意這裏的 func 是由 service_manager.c main 函數中傳過來的方法指針,也就是 svcmgr_handler() 方法。
通過上面 ServiceManager 服務啓動的過程分析,已經知道由 binder 驅動主動發過來的 BR_TRANSACTION 命令最終在 service_manager.c 的 svcmgr_handler() 方法中處理,那服務的註冊與查詢請求想必就是在這個方法中實現的了,確實如此,簡化後的關鍵代碼以下:
int svcmgr_handler(struct binder_state *bs,
struct binder_transaction_data *txn,
struct binder_io *msg,
struct binder_io *reply){
switch(txn->code) {
case SVC_MGR_GET_SERVICE:
case SVC_MGR_CHECK_SERVICE:
//查詢服務,根據 name 查詢 Server Handle
handle = do_find_service(s, len, txn->sender_euid, txn->sender_pid);
return 0;
case SVC_MGR_ADD_SERVICE:
//註冊服務,記錄服務的 name(下面的參數 s) 與 handle
if (do_add_service(bs, s, len, handle, txn->sender_euid,
allow_isolated, txn->sender_pid))
return -1;
break;
case SVC_MGR_LIST_SERVICES: {
//查詢全部服務,返回存儲全部服務的鏈表 svclist
si = svclist;
while ((n-- > 0) && si)
si = si->next;
if (si) {
bio_put_string16(reply, si->name);
return 0;
}
return -1;
}
bio_put_uint32(reply, 0);
return 0;
}
複製代碼
註冊的服務都會存儲在 svclist 鏈表上,do_add_service() 就是將服務插入到 svclist 鏈表上記錄下來,do_find_service() 方法則遍歷 svclist 查找對應的服務。
svcmgr_handler() 方法執行完後會進一步調用 inder_send_reply() 將執行結果回覆給 binder 驅動,而後進入下一輪循環繼續等待處理消息。
ServiceManager 在 init.rc 中描述,由 init 進程啓動,運行在一個單獨的進程。
ServiceManager 啓動後主要作了三件事:1. 打開 binder 驅動並映射內存;2. 將本身設置爲 "服務大管家";3. 循環等待 binder 驅動發來的消息。
ServiceManager 經過記錄服務 Name 和 Handler 的關係,提供服務註冊與查詢功能。
對 Client 來講,ServiceManager 也是一個 Service,Client 能夠直接獲取到這個 Service,由於它的句柄值固定爲 0。