Binder系列3—啟動ServiceManager

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

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末沧奴,一起剝皮案震驚了整個濱河市痘括,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌滔吠,老刑警劉巖纲菌,帶你破解...
    沈念sama閱讀 222,000評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異疮绷,居然都是意外死亡翰舌,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,745評論 3 399
  • 文/潘曉璐 我一進店門冬骚,熙熙樓的掌柜王于貴愁眉苦臉地迎上來椅贱,“玉大人懂算,你說我怎么就攤上這事”勇螅” “怎么了计技?”我有些...
    開封第一講書人閱讀 168,561評論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長山橄。 經(jīng)常有香客問我垮媒,道長,這世上最難降的妖魔是什么航棱? 我笑而不...
    開封第一講書人閱讀 59,782評論 1 298
  • 正文 為了忘掉前任睡雇,我火速辦了婚禮,結(jié)果婚禮上饮醇,老公的妹妹穿的比我還像新娘它抱。我一直安慰自己,他們只是感情好驳阎,可當(dāng)我...
    茶點故事閱讀 68,798評論 6 397
  • 文/花漫 我一把揭開白布抗愁。 她就那樣靜靜地躺著,像睡著了一般呵晚。 火紅的嫁衣襯著肌膚如雪蜘腌。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,394評論 1 310
  • 那天饵隙,我揣著相機與錄音撮珠,去河邊找鬼。 笑死金矛,一個胖子當(dāng)著我的面吹牛芯急,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播驶俊,決...
    沈念sama閱讀 40,952評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼娶耍,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了饼酿?” 一聲冷哼從身側(cè)響起榕酒,我...
    開封第一講書人閱讀 39,852評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎故俐,沒想到半個月后想鹰,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,409評論 1 318
  • 正文 獨居荒郊野嶺守林人離奇死亡药版,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,483評論 3 341
  • 正文 我和宋清朗相戀三年辑舷,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片槽片。...
    茶點故事閱讀 40,615評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡何缓,死狀恐怖肢础,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情歌殃,我是刑警寧澤乔妈,帶...
    沈念sama閱讀 36,303評論 5 350
  • 正文 年R本政府宣布,位于F島的核電站氓皱,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏勃刨。R本人自食惡果不足惜波材,卻給世界環(huán)境...
    茶點故事閱讀 41,979評論 3 334
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望身隐。 院中可真熱鬧廷区,春花似錦、人聲如沸贾铝。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,470評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽垢揩。三九已至玖绿,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間叁巨,已是汗流浹背斑匪。 一陣腳步聲響...
    開封第一講書人閱讀 33,571評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留锋勺,地道東北人蚀瘸。 一個月前我還...
    沈念sama閱讀 49,041評論 3 377
  • 正文 我出身青樓,卻偏偏與公主長得像庶橱,于是被迫代替她去往敵國和親贮勃。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,630評論 2 359

推薦閱讀更多精彩內(nèi)容