Binder系列3—啟動(dòng)ServiceManager

基于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信息。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容