基于Android 6.0的源碼剖析, 本文詳細地講解了ServiceManager啟動流程
一. 概述
ServiceManager是Binder IPC通信過程中的守護進程饶碘,本身也是一個Binder服務(wù)酣栈,但并沒有采用libbinder中的多線程模型來與Binder驅(qū)動通信宵呛,而是自行編寫了binder.c直接和Binder驅(qū)動來通信跛十,并且只有一個循環(huán)binder_loop來進行讀取和處理事務(wù)靶剑,這樣的好處是簡單而高效剩辟。
ServiceManager本身工作相對簡單,其功能:查詢和注冊服務(wù)躯保。 對于Binder IPC通信過程中旋膳,其實更多的情形是BpBinder和BBinder之間的通信,比如ActivityManagerProxy和ActivityManagerService之間的通信等途事。
1.1 流程圖
啟動過程主要以下幾個階段:
打開binder驅(qū)動:binder_open验懊;
注冊成為binder服務(wù)的大管家:binder_become_context_manager;
進入無限循環(huán)尸变,處理client端發(fā)來的請求:binder_loop义图;
二. 啟動過程
ServiceManager是由init進程通過解析init.rc文件而創(chuàng)建的,其所對應(yīng)的可執(zhí)行程序/system/bin/servicemanager召烂,所對應(yīng)的源文件是service_manager.c碱工,進程名為/system/bin/servicemanager。
啟動Service Manager的入口函數(shù)是service_manager.c中的main()方法奏夫,代碼如下:
2.1 main
[ -> service_manager.c]
2.2 binder_open
[-> servicemanager/binder.c]
打開binder驅(qū)動相關(guān)操作:
先調(diào)用open()打開binder設(shè)備怕篷,open()方法經(jīng)過系統(tǒng)調(diào)用,進入Binder驅(qū)動桶蛔,然后調(diào)用方法binder_open()匙头,該方法會在Binder驅(qū)動層創(chuàng)建一個binder_proc對象,再將binder_proc對象賦值給fd->private_data仔雷,同時放入全局鏈表binder_procs蹂析。再通過ioctl()檢驗當(dāng)前binder版本與Binder驅(qū)動層的版本是否一致。
調(diào)用mmap()進行內(nèi)存映射碟婆,同理mmap()方法經(jīng)過系統(tǒng)調(diào)用电抚,對應(yīng)于Binder驅(qū)動層的binder_mmap()方法,該方法會在Binder驅(qū)動層創(chuàng)建Binder_buffer對象竖共,并放入當(dāng)前binder_proc的proc->buffers鏈表蝙叛。
2.2.1 binder_state
[-> servicemanager/binder.c]
2.3 binder_become_context_manager
[-> servicemanager/binder.c]
成為上下文的管理者,整個系統(tǒng)中只有一個這樣的管理者公给。 通過ioctl()方法經(jīng)過系統(tǒng)調(diào)用借帘,對應(yīng)于Binder驅(qū)動層的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()方法淌铐,這個過程會持有binder_main_lock肺然。
2.3.2 binder_ioctl_set_ctx_mgr
[-> kernel/drivers/android/binder.c]
進入binder驅(qū)動,在Binder驅(qū)動中定義的靜態(tài)變量
創(chuàng)建了全局的binder_node對象binder_context_mgr_node腿准,并將binder_context_mgr_node的強弱引用各加1.
2.3.3 binder_new_node
[-> kernel/drivers/android/binder.c]
在Binder驅(qū)動層創(chuàng)建binder_node結(jié)構(gòu)體對象际起,并將當(dāng)前binder_proc加入到binder_node的node->proc。并創(chuàng)建binder_node的async_todo和binder_work兩個隊列。
2.4 binder_loop
[-> servicemanager/binder.c]
進入循環(huán)讀寫操作街望,由main()方法傳遞過來的參數(shù)func指向svcmgr_handler校翔。
binder_write通過ioctl()將BC_ENTER_LOOPER命令發(fā)送給binder驅(qū)動,此時bwr只有write_buffer有數(shù)據(jù)灾前,進入binder_thread_write()方法防症。 接下來進入for循環(huán),執(zhí)行ioctl()豫柬,此時bwr只有read_buffer有數(shù)據(jù)告希,那么進入binder_thread_read()方法。
2.4.1 binder_write
[-> servicemanager/binder.c]
根據(jù)傳遞進來的參數(shù)烧给,初始化bwr燕偶,其中write_size大小為4,write_buffer指向緩沖區(qū)的起始地址础嫡,其內(nèi)容為BC_ENTER_LOOPER請求協(xié)議號指么。通過ioctl將bwr數(shù)據(jù)發(fā)送給binder驅(qū)動,則調(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。故有請求到來平项,則調(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對象的data
2.6 svcmgr_handler
[-> service_manager.c]
......
該方法的功能:查詢服務(wù),注冊服務(wù)闽瓢,以及列舉所有服務(wù)
2.6.1 svcinfo
每一個服務(wù)用svcinfo結(jié)構(gòu)體來表示接癌,該handle值是在注冊服務(wù)的過程中,由服務(wù)所在進程那一端所確定的扣讼。
三. 核心工作
servicemanager的核心工作就是注冊服務(wù)和查詢服務(wù)缺猛。
3.1 do_find_service
[-> service_manager.c]
uint32_tdo_find_service(structbinder_state *bs,
查詢到目標(biāo)服務(wù),并返回該服務(wù)所對應(yīng)的handle
3.1.1 find_svc
從svclist服務(wù)列表中椭符,根據(jù)服務(wù)名遍歷查找是否已經(jīng)注冊荔燎。當(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]
注冊服務(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一樣的方式, 進入Binder driver后,直接調(diào)用后進入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進程的信息. 此時TODO隊列有數(shù)據(jù),則進入binder_thread_read.
那么哪些場景會向隊列增加BINDER_WORK_DEAD_BINDER事務(wù)呢? 那就是當(dāng)binder所在進程死亡后,會調(diào)用binder_release方法, 然后調(diào)用binder_node_release.這個過程便會發(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的過程便會處理該消息。
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命令, 最終進入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過程。該方法會調(diào)用 [小節(jié)2.4.1] binder_write進入binder驅(qū)動后瓶籽,將BC_FREE_BUFFER和BC_REPLY命令協(xié)議發(fā)送給Binder驅(qū)動匠童,向client端發(fā)送reply. 其中data的數(shù)據(jù)區(qū)中保存的是TYPE為HANDLE.
四. 總結(jié)
ServiceManger集中管理系統(tǒng)內(nèi)的所有服務(wù),通過權(quán)限控制進程是否有權(quán)注冊服務(wù),通過字符串名稱來查找對應(yīng)的Service; 由于ServiceManger進程建立跟所有向其注冊服務(wù)的死亡通知, 那么當(dāng)服務(wù)所在進程死亡后, 會只需告知ServiceManager. 每個Client通過查詢ServiceManager可獲取Server進程的情況塑顺,降低所有Client進程直接檢測會導(dǎo)致負載過重汤求。
ServiceManager啟動流程:
打開binder驅(qū)動,并調(diào)用mmap()方法分配128k的內(nèi)存映射空間:binder_open();
通知binder驅(qū)動使其成為守護進程:binder_become_context_manager()严拒;
驗證selinux權(quán)限扬绪,判斷進程是否有權(quán)注冊或查看指定服務(wù);
進入循環(huán)狀態(tài)裤唠,等待Client端的請求:binder_loop()挤牛。
注冊服務(wù)的過程,根據(jù)服務(wù)名稱种蘸,但同一個服務(wù)已注冊墓赴,重新注冊前會先移除之前的注冊信息;
死亡通知: 當(dāng)binder所在進程死亡后,會調(diào)用binder_release方法,然后調(diào)用binder_node_release.這個過程便會發(fā)出死亡通知的回調(diào).
ServiceManager最核心的兩個功能為查詢和注冊服務(wù):
注冊服務(wù):記錄服務(wù)名和handle信息劈彪,保存到svclist列表竣蹦;
查詢服務(wù):根據(jù)服務(wù)名查詢相應(yīng)的的handle信息。