基于Android 6.0的源碼剖析, 本文詳細(xì)地講解了ServiceManager啟動(dòng)流程

一. 概述
ServiceManager是Binder IPC通信過程中的守護(hù)進(jìn)程,本身也是一個(gè)Binder服務(wù),但并沒有采用libbinder中的多線程模型來與Binder驅(qū)動(dòng)通信,而是自行編寫了binder.c直接和Binder驅(qū)動(dòng)來通信,并且只有一個(gè)循環(huán)binder_loop來進(jìn)行讀取和處理事務(wù),這樣的好處是簡單而高效。
ServiceManager本身工作相對(duì)簡單,其功能:查詢和注冊(cè)服務(wù)。 對(duì)于Binder IPC通信過程中,其實(shí)更多的情形是BpBinder和BBinder之間的通信,比如ActivityManagerProxy和ActivityManagerService之間的通信等。
1.1 流程圖

啟動(dòng)過程主要以下幾個(gè)階段:
打開binder驅(qū)動(dòng):binder_open;
注冊(cè)成為binder服務(wù)的大管家:binder_become_context_manager;
進(jìn)入無限循環(huán),處理client端發(fā)來的請(qǐng)求:binder_loop;
二. 啟動(dòng)過程
ServiceManager是由init進(jìn)程通過解析init.rc文件而創(chuàng)建的,其所對(duì)應(yīng)的可執(zhí)行程序/system/bin/servicemanager,所對(duì)應(yīng)的源文件是service_manager.c,進(jìn)程名為/system/bin/servicemanager。

啟動(dòng)Service Manager的入口函數(shù)是service_manager.c中的main()方法,代碼如下:
2.1 main
[ -> service_manager.c]

2.2 binder_open
[-> servicemanager/binder.c]

打開binder驅(qū)動(dòng)相關(guān)操作:
先調(diào)用open()打開binder設(shè)備,open()方法經(jīng)過系統(tǒng)調(diào)用,進(jìn)入Binder驅(qū)動(dòng),然后調(diào)用方法binder_open(),該方法會(huì)在Binder驅(qū)動(dòng)層創(chuàng)建一個(gè)binder_proc對(duì)象,再將binder_proc對(duì)象賦值給fd->private_data,同時(shí)放入全局鏈表binder_procs。再通過ioctl()檢驗(yàn)當(dāng)前binder版本與Binder驅(qū)動(dòng)層的版本是否一致。
調(diào)用mmap()進(jìn)行內(nèi)存映射,同理mmap()方法經(jīng)過系統(tǒng)調(diào)用,對(duì)應(yīng)于Binder驅(qū)動(dòng)層的binder_mmap()方法,該方法會(huì)在Binder驅(qū)動(dòng)層創(chuàng)建Binder_buffer對(duì)象,并放入當(dāng)前binder_proc的proc->buffers鏈表。
2.2.1 binder_state
[-> servicemanager/binder.c]

2.3 binder_become_context_manager
[-> servicemanager/binder.c]

成為上下文的管理者,整個(gè)系統(tǒng)中只有一個(gè)這樣的管理者。 通過ioctl()方法經(jīng)過系統(tǒng)調(diào)用,對(duì)應(yīng)于Binder驅(qū)動(dòng)層的binder_ioctl()方法.
2.3.1 binder_ioctl
[-> kernel/drivers/android/binder.c]

根據(jù)參數(shù)BINDER_SET_CONTEXT_MGR,最終調(diào)用binder_ioctl_set_ctx_mgr()方法,這個(gè)過程會(huì)持有binder_main_lock。
2.3.2 binder_ioctl_set_ctx_mgr
[-> kernel/drivers/android/binder.c]

進(jìn)入binder驅(qū)動(dòng),在Binder驅(qū)動(dòng)中定義的靜態(tài)變量

創(chuàng)建了全局的binder_node對(duì)象binder_context_mgr_node,并將binder_context_mgr_node的強(qiáng)弱引用各加1.
2.3.3 binder_new_node
[-> kernel/drivers/android/binder.c]

在Binder驅(qū)動(dòng)層創(chuàng)建binder_node結(jié)構(gòu)體對(duì)象,并將當(dāng)前binder_proc加入到binder_node的node->proc。并創(chuàng)建binder_node的async_todo和binder_work兩個(gè)隊(duì)列。
2.4 binder_loop
[-> servicemanager/binder.c]

進(jìn)入循環(huán)讀寫操作,由main()方法傳遞過來的參數(shù)func指向svcmgr_handler。
binder_write通過ioctl()將BC_ENTER_LOOPER命令發(fā)送給binder驅(qū)動(dòng),此時(shí)bwr只有write_buffer有數(shù)據(jù),進(jìn)入binder_thread_write()方法。 接下來進(jìn)入for循環(huán),執(zhí)行ioctl(),此時(shí)bwr只有read_buffer有數(shù)據(jù),那么進(jìn)入binder_thread_read()方法。
2.4.1 binder_write
[-> servicemanager/binder.c]

根據(jù)傳遞進(jìn)來的參數(shù),初始化bwr,其中write_size大小為4,write_buffer指向緩沖區(qū)的起始地址,其內(nèi)容為BC_ENTER_LOOPER請(qǐng)求協(xié)議號(hào)。通過ioctl將bwr數(shù)據(jù)發(fā)送給binder驅(qū)動(dòng),則調(diào)用其binder_ioctl方法,如下:
2.4.2 binder_ioctl
[-> kernel/drivers/android/binder.c]

2.4.3 binder_ioctl_write_read
[-> kernel/drivers/android/binder.c]

此處將用戶空間的binder_write_read結(jié)構(gòu)體 拷貝到內(nèi)核空間.
2.4.4 binder_thread_write
[-> kernel/drivers/android/binder.c]
從bwr.write_buffer拿出cmd數(shù)據(jù),此處為BC_ENTER_LOOPER. 可見上層本次調(diào)用binder_write()方法,主要是完成設(shè)置當(dāng)前線程的looper狀態(tài)為BINDER_LOOPER_STATE_ENTERED。
2.5 binder_parse
[-> servicemanager/binder.c]
解析binder信息,此處參數(shù)ptr指向BC_ENTER_LOOPER,func指向svcmgr_handler。故有請(qǐng)求到來,則調(diào)用svcmgr_handler。
2.5.1 bio_init
[-> servicemanager/binder.c]

其中

2.5.2 bio_init_from_txn
[-> servicemanager/binder.c]

將readbuf的數(shù)據(jù)賦給bio對(duì)象的data
2.6 svcmgr_handler
[-> service_manager.c]
......
該方法的功能:查詢服務(wù),注冊(cè)服務(wù),以及列舉所有服務(wù)
2.6.1 svcinfo

每一個(gè)服務(wù)用svcinfo結(jié)構(gòu)體來表示,該handle值是在注冊(cè)服務(wù)的過程中,由服務(wù)所在進(jìn)程那一端所確定的。
三. 核心工作
servicemanager的核心工作就是注冊(cè)服務(wù)和查詢服務(wù)。
3.1 do_find_service
[-> service_manager.c]
uint32_tdo_find_service(structbinder_state *bs,

查詢到目標(biāo)服務(wù),并返回該服務(wù)所對(duì)應(yīng)的handle
3.1.1 find_svc

從svclist服務(wù)列表中,根據(jù)服務(wù)名遍歷查找是否已經(jīng)注冊(cè)。當(dāng)服務(wù)已存在svclist,則返回相應(yīng)的服務(wù)名,否則返回NULL。
當(dāng)找到服務(wù)的handle, 則調(diào)用bio_put_ref(reply, handle),將handle封裝到reply.
3.1.2 bio_put_ref

3.1.3 bio_alloc_obj

3.1.4 bio_alloc

3.2 do_add_service
[-> service_manager.c]

注冊(cè)服務(wù)的分以下3部分工作:
svc_can_register:檢查權(quán)限,檢查selinux權(quán)限是否滿足;
find_svc:服務(wù)檢索,根據(jù)服務(wù)名來查詢匹配的服務(wù);
svcinfo_death:釋放服務(wù),當(dāng)查詢到已存在同名的服務(wù),則先清理該服務(wù)信息,再將當(dāng)前的服務(wù)加入到服務(wù)列表svclist;
3.2.1 svc_can_register
[-> service_manager.c]

3.2.2 svcinfo_death
[-> service_manager.c]

3.2.3 bio_get_ref
[-> servicemanager/binder.c]

3.3 binder_link_to_death
[-> servicemanager/binder.c]

binder_write經(jīng)過跟小節(jié)2.4.1一樣的方式, 進(jìn)入Binder driver后,直接調(diào)用后進(jìn)入binder_thread_write, 處理BC_REQUEST_DEATH_NOTIFICATION命令
3.3.1 binder_ioctl_write_read
[-> kernel/drivers/android/binder.c]

3.3.2 binder_thread_write
[-> kernel/drivers/android/binder.c]
.....
此方法中的proc, thread都是指當(dāng)前servicemanager進(jìn)程的信息. 此時(shí)TODO隊(duì)列有數(shù)據(jù),則進(jìn)入binder_thread_read.
那么哪些場景會(huì)向隊(duì)列增加BINDER_WORK_DEAD_BINDER事務(wù)呢? 那就是當(dāng)binder所在進(jìn)程死亡后,會(huì)調(diào)用binder_release方法, 然后調(diào)用binder_node_release.這個(gè)過程便會(huì)發(fā)出死亡通知的回調(diào).
3.3.3 binder_thread_read
將命令BR_DEAD_BINDER寫到用戶空間, 此處的cookie是前面?zhèn)鬟f的svcinfo_death. 當(dāng)binder_loop下一次 執(zhí)行binder_parse的過程便會(huì)處理該消息。
3.3.4 binder_parse
[-> servicemanager/binder.c]
由小節(jié)3.2的 si->death.func = (void*) svcinfo_death; 可知此處 death->func便是執(zhí)行svcinfo_death()方法.
3.3.5 svcinfo_death
[-> service_manager.c]

3.3.6 binder_release
[-> service_manager.c]

向Binder Driver寫入BC_RELEASE命令, 最終進(jìn)入Binder Driver后執(zhí)行binder_dec_ref(ref, 1)來減少binder node的引用.
3.4 binder_send_reply
[-> servicemanager/binder.c]
當(dāng)小節(jié)2.5執(zhí)行binder_parse方法,先調(diào)用svcmgr_handler(),再然后執(zhí)行binder_send_reply過程。該方法會(huì)調(diào)用 [小節(jié)2.4.1] binder_write進(jìn)入binder驅(qū)動(dòng)后,將BC_FREE_BUFFER和BC_REPLY命令協(xié)議發(fā)送給Binder驅(qū)動(dòng),向client端發(fā)送reply. 其中data的數(shù)據(jù)區(qū)中保存的是TYPE為HANDLE.
四. 總結(jié)
ServiceManger集中管理系統(tǒng)內(nèi)的所有服務(wù),通過權(quán)限控制進(jìn)程是否有權(quán)注冊(cè)服務(wù),通過字符串名稱來查找對(duì)應(yīng)的Service; 由于ServiceManger進(jìn)程建立跟所有向其注冊(cè)服務(wù)的死亡通知, 那么當(dāng)服務(wù)所在進(jìn)程死亡后, 會(huì)只需告知ServiceManager. 每個(gè)Client通過查詢ServiceManager可獲取Server進(jìn)程的情況,降低所有Client進(jìn)程直接檢測(cè)會(huì)導(dǎo)致負(fù)載過重。
ServiceManager啟動(dòng)流程:
打開binder驅(qū)動(dòng),并調(diào)用mmap()方法分配128k的內(nèi)存映射空間:binder_open();
通知binder驅(qū)動(dòng)使其成為守護(hù)進(jìn)程:binder_become_context_manager();
驗(yàn)證selinux權(quán)限,判斷進(jìn)程是否有權(quán)注冊(cè)或查看指定服務(wù);
進(jìn)入循環(huán)狀態(tài),等待Client端的請(qǐng)求:binder_loop()。
注冊(cè)服務(wù)的過程,根據(jù)服務(wù)名稱,但同一個(gè)服務(wù)已注冊(cè),重新注冊(cè)前會(huì)先移除之前的注冊(cè)信息;
死亡通知: 當(dāng)binder所在進(jìn)程死亡后,會(huì)調(diào)用binder_release方法,然后調(diào)用binder_node_release.這個(gè)過程便會(huì)發(fā)出死亡通知的回調(diào).
ServiceManager最核心的兩個(gè)功能為查詢和注冊(cè)服務(wù):
注冊(cè)服務(wù):記錄服務(wù)名和handle信息,保存到svclist列表;
查詢服務(wù):根據(jù)服務(wù)名查詢相應(yīng)的的handle信息。