Android通信方式篇(七)-Binder機(jī)制(Native層(下))

本篇文章針對向ServiceManager注冊服務(wù) 和 獲取服務(wù)兩個流程來做總結(jié)。在這兩個過程中,ServiceManager都扮演的是服務(wù)端,與客戶端之間的通信也是通過Binder IPC误窖。

在此之前先了解下Binder的進(jìn)程與線程的關(guān)系:

用戶空間:ProcessState描述一個進(jìn)程涮阔,IPCThreadState對應(yīng)一個進(jìn)程中的一個線程猜绣。
內(nèi)核空間:binder_proc描述一個進(jìn)程,統(tǒng)一由binder_procs全局鏈表保存敬特,binder_thread對應(yīng)進(jìn)程的一個線程掰邢。
ProcessState與binder_proc是一一對應(yīng)的。

Binder線程池:每個Server進(jìn)程在啟動時會創(chuàng)建一個binder線程池伟阔,并向其中注冊一個Binder線程辣之;之后Server進(jìn)程也可以向binder線程池注冊新的線程,或者Binder驅(qū)動在探測到?jīng)]有空閑binder線程時會主動向Server進(jìn)程注冊新的的binder線程皱炉。對于一個Server進(jìn)程有一個最大Binder線程數(shù)限制15怀估,(#define DEFAULT_MAX_BINDER_THREADS 15)。對于所有Client端進(jìn)程的binder請求都是交由Server端進(jìn)程的binder線程來處理的合搅。我的理解是:binder線程是進(jìn)程進(jìn)行binder ipc時的一條數(shù)據(jù)處理路徑多搀。

一、 Server通過addService向ServiceManager注冊服務(wù)

MediaPlayerService向ServiceManager注冊過程如下:

相關(guān)類:

framework/native/libs/binder/
- Binder.cpp
- BpBinder.cpp
- IPCThreadState.cpp
- ProcessState.cpp
- IServiceManager.cpp
- IInterface.cpp
- Parcel.cpp
frameworks/native/include/binder/
- IInterface.h (包括BnInterface, BpInterface)

整個過程總結(jié)如下:
1 獲取BpServiceManager 與 BpBinder
由defaultServiceManager()返回的是BpServiceManager灾部,同時會創(chuàng)建ProcessState對象和BpBinder對象康铭。然后通過BpBinder執(zhí)行transact,把真正工作交給IPCThreadState來處理赌髓。

2 BpBinder transact
Binder代理類調(diào)用transact()方法从藤,真正工作還是交給IPCThreadState來進(jìn)行transact工作催跪。

3 通過IPCThreadState 包裝并轉(zhuǎn)換數(shù)據(jù)并進(jìn)行transact事務(wù)處理
每個線程都有一個IPCThreadState,每個IPCThreadState中都有一對Parcel變量:mIn呛哟、mOut叠荠。相當(dāng)于兩根數(shù)據(jù)管道:

  • mIn 用來接收來自Binder設(shè)備的數(shù)據(jù),默認(rèn)大小為256字節(jié)扫责;
  • mOut用來存儲發(fā)往Binder設(shè)備的數(shù)據(jù)榛鼎,默認(rèn)大小為256字節(jié)。
    另外鳖孤,IPCThreadState進(jìn)行transact事務(wù)處理分3部分:
  • errorCheck() //數(shù)據(jù)錯誤檢查
  • writeTransactionData() // 傳輸數(shù)據(jù)
  • waitForResponse() //f等待響應(yīng)

最后執(zhí)行talkWithDriver者娱。

writeTransactionData:將BC Protocol + binder_transaction_data結(jié)構(gòu)體 寫入mOut, 然后執(zhí)行waitForResponse:

由talkWithDriver將數(shù)據(jù)進(jìn)一步封裝到binder_write_read結(jié)構(gòu)體苏揣,通過ioctl(BINDER_WRITE_READ)與驅(qū)動通信黄鳍。同時等待驅(qū)動返回的接收BR命令,從mIn取出返回的數(shù)據(jù)平匈。

mIn包裝的數(shù)據(jù)結(jié)構(gòu)(注冊服務(wù)handle = 0 框沟,code 為ADD_SERVICE_TRANSACTION):

4 Binder Driver
把binder_write_read結(jié)構(gòu)體write_buffer里數(shù)據(jù)取出來,分別得到BC命令和封裝好數(shù)據(jù)的事務(wù)binder_transaction_data, 然后根據(jù)handler增炭,在當(dāng)前binder_proc中忍燥,找到相應(yīng)的binder_ref,由binder_ref再找到目標(biāo)binder_node實(shí)體隙姿,由目標(biāo)binder_node再找到目標(biāo)進(jìn)程binder_proc梅垄。然后就是插入數(shù)據(jù):當(dāng)binder驅(qū)動可以找到合適的線程,就會把binder_transaction節(jié)點(diǎn)插入到servciemanager的線程的todo隊(duì)列中输玷,如果找不到合適的線程队丝,就把節(jié)點(diǎn)之間插入servciemanager的binder_proc的todo隊(duì)列。

5 ServiceManager
經(jīng)過Binder Driver的處理欲鹏,數(shù)據(jù)已經(jīng)到了ServiceManager進(jìn)程机久,在BR_TRANSACTION的引導(dǎo)下,在binder_loop()中執(zhí)行binder_parser()取出數(shù)據(jù)赔嚎,執(zhí)行do_add_service()操作吞加,最終向 svcinfo 列表中添加已經(jīng)注冊的服務(wù)(沒有數(shù)據(jù)的返回)。最后發(fā)送 BR_REPLY 命令喚醒等待的線程尽狠,通知注冊成功。結(jié)束MediaPlayerService進(jìn)程 waitForResponse()的狀態(tài)叶圃,整個注冊過程結(jié)束袄膏。

二、Client通過getService向ServiceManager獲取Server的服務(wù)

獲取服務(wù)的過程與注冊類似掺冠,首先 ServiceManager 向 Binder 驅(qū)動發(fā)送 BC_TRANSACTION 命令攜帶 CHECK_SERVICE_TRANSACTION 命令沉馆,同時獲取服務(wù)的線程進(jìn)入等待狀態(tài) waitForResponse()码党。Binder 驅(qū)動收到請求命令向 ServiceManager 的發(fā)送 BC_TRANSACTION 查詢已注冊的服務(wù),會區(qū)分請求服務(wù)所屬進(jìn)程情況斥黑。

  • 當(dāng)請求服務(wù)的進(jìn)程與服務(wù)屬于不同進(jìn)程揖盘,則為請求服務(wù)所在進(jìn)程創(chuàng)建binder_ref對象,指向服務(wù)進(jìn)程中的binder_node;最終readStrongBinder()锌奴,返回的是BpBinder對象兽狭;

  • 當(dāng)請求服務(wù)的進(jìn)程與服務(wù)屬于同一進(jìn)程,則不再創(chuàng)建新對象鹿蜀,只是引用計(jì)數(shù)加1箕慧,并且修改type為BINDER_TYPE_BINDER或BINDER_TYPE_WEAK_BINDER。最終readStrongBinder()茴恰,返回的是BBinder對象的真實(shí)子類颠焦。

查詢到直接響應(yīng) BR_REPLY 喚醒等待的線程。若查詢不到將與 binder_procs 鏈表中的服務(wù)進(jìn)行一次通訊再響應(yīng)往枣。

三伐庭、Client與Server的一次完整通信

以startService為例來簡單總結(jié)下執(zhí)行流程:

3.1 從方法執(zhí)行流程來看:

Client :

1 AMP.startService 標(biāo)記方法以及通過Parcel包裝數(shù)據(jù);

2 BinderProxy.transact 實(shí)際調(diào)用native的 android_os_BinderProxy_transact 傳遞數(shù)據(jù)分冈;

3 獲取BpServiceManager 與 BpBinder 同時會創(chuàng)建ProcessState圾另。然后通過BpBinder執(zhí)行transact,把真正工作交給IPCThreadState來處理丈秩;

4 IPC.transact 主要執(zhí)行writeTransactionData盯捌,將上層傳來的數(shù)據(jù)重新包裝成binder_transaction_data,并將BC Protocol + binder_transaction_data結(jié)構(gòu)體 寫入mOut蘑秽;

5 IPC waitForResponse talkWithDriver + 等待返回?cái)?shù)據(jù)饺著;

6 talkWithDriver 將數(shù)據(jù)進(jìn)一步封裝成binder_write_read,通過ioctl(BINDER_WRITE_READ)與驅(qū)動通信肠牲;

Kernel :

7 binder ioctl 接收BINDER_WRITE_READ ioctl命令幼衰;

8 binder_ioctl_write_read 把用戶空間數(shù)據(jù)ubuf拷貝到內(nèi)核空間bwr;

9 binder_thread_write 當(dāng)bwr寫緩存有數(shù)據(jù)缀雳,則執(zhí)行binder_thread_write渡嚣;當(dāng)寫失敗則將bwr數(shù)據(jù)寫回用戶空間并退出;

10 binder_transaction 找到目標(biāo)進(jìn)程binder_proc并插入數(shù)據(jù)到目標(biāo)進(jìn)程的線程todo隊(duì)列肥印,最終執(zhí)行到它
時识椰,將發(fā)起端數(shù)據(jù)拷貝到接收端進(jìn)程的buffer結(jié)構(gòu)體;

11 binder_thread_read 根據(jù)binder_transaction結(jié)構(gòu)體和binder_buffer結(jié)構(gòu)體數(shù)據(jù)生成新的binder_transaction_data結(jié)構(gòu)體深碱,寫入bwr的read_buffer腹鹉,當(dāng)bwr讀緩存有數(shù)據(jù),則執(zhí)行binder_thread_read敷硅;當(dāng)讀失敗則再將bwr數(shù)據(jù)寫回用戶空間并退出功咒;最后愉阎,把內(nèi)核數(shù)據(jù)bwr拷貝到用戶空間ubuf。

12 binder_thread_write + binder_ioctl BR命令和數(shù)據(jù)傳遞

Server:

13 IPC.executeCommand 解析kernel傳過來的binder_transaction_data數(shù)據(jù)力奋,找到目標(biāo)BBinder并調(diào)用其transact()方法;

14 IPC.joinThreadPool 采用循環(huán)不斷地執(zhí)行g(shù)etAndExecuteCommand()方法, 處理事務(wù)榜旦。當(dāng)bwr的讀寫buffer都沒有數(shù)據(jù)時,則阻塞在binder_thread_read的wait_event過程. 另外,正常情況下binder線程一旦創(chuàng)建則不會退出.

15 BBinder.transact 到Binder.exeTransact 調(diào)用 AMN.onTransact

16 AMN.onTransact 把數(shù)據(jù)傳遞到AMS.starService去執(zhí)行

17 AMS.starService Server處理了Client的請求了

然后原路replay回去,talkWithDriver 到Kernel 景殷,然后找到Client進(jìn)程溅呢,把數(shù)據(jù)拷貝到read_buffer里,最終喚醒IPC滨彻,把反饋傳遞回AMP.startService藕届。完成啟動服務(wù)。

3.2 從通信協(xié)議流程來看:

非oneWay:

  • Binder客戶端或者服務(wù)端向Binder Driver發(fā)送的命令都是以BC_開頭,例如BC_TRANSACTION和BC_REPLY, 所有Binder Driver向Binder客戶端或者服務(wù)端發(fā)送的命令則都是以BR_開頭, 例如BR_TRANSACTION和BR_REPLY.

  • 只有當(dāng)BC_TRANSACTION或者BC_REPLY時, 才調(diào)用binder_transaction()來處理事務(wù). 并且都會回應(yīng)調(diào)用者一個BINDER_WORK_TRANSACTION_COMPLETE事務(wù), 經(jīng)過binder_thread_read()會轉(zhuǎn)變成BR_TRANSACTION_COMPLETE.

oneway:

oneway與非oneway區(qū)別: 都是需要等待Binder Driver的回應(yīng)消息BR_TRANSACTION_COMPLETE. 主要區(qū)別在于oneway的通信收到BR_TRANSACTION_COMPLETE則返回,而不會再等待BR_REPLY消息的到來. 另外亭饵,oneway的binder IPC則接收端無法獲取對方的pid.

3.3 從數(shù)據(jù)流來看

從用戶空間開始:

  • AMP.startService:組裝flat_binder_object對象等組成的Parcel data休偶;

  • IPC.writeTransactionData:組裝BC_TRANSACTION和binder_transaction_data結(jié)構(gòu)體,寫入mOut;

  • IPC.talkWithDriver: 組裝BINDER_WRITE_READ和binder_write_read結(jié)構(gòu)體辜羊,通過ioctl傳輸?shù)津?qū)動層踏兜。

進(jìn)入驅(qū)動后:

  • binder_thread_write: 處理binder_write_read.write_buffer數(shù)據(jù)

  • binder_transaction: 處理write_buffer.binder_transaction_data數(shù)據(jù);創(chuàng)建binder_transaction結(jié)構(gòu)體八秃,記錄事務(wù)通信的線程來源以及事務(wù)鏈條等相關(guān)信息碱妆;分配binder_buffer結(jié)構(gòu)體,拷貝當(dāng)前線程binder_transaction_data的data數(shù)據(jù)到binder_buffer->data昔驱;

  • binder_thread_read: 處理binder_transaction結(jié)構(gòu)體數(shù)據(jù)疹尾。組裝cmd=BR_TRANSACTION和binder_transaction_data結(jié)構(gòu)體,寫入binder_write_read.read_buffer數(shù)據(jù)骤肛。

回到用戶空間:

  • IPC.executeCommand:處理BR_TRANSACTION命令, 將binder_transaction_data數(shù)據(jù)解析成BBinder.transact()所需的參數(shù)

  • AMN.onTransact: 層層回調(diào)纳本,進(jìn)入該方法,反序列化數(shù)據(jù)后腋颠,調(diào)用startService()方法繁成。

參考:
http://gityuan.com/2016/09/04/binder-start-service/
http://gityuan.com/2015/11/28/binder-summary/
http://gityuan.com/2015/11/14/binder-add-service/
http://gityuan.com/2015/11/15/binder-get-service/

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
禁止轉(zhuǎn)載,如需轉(zhuǎn)載請通過簡信或評論聯(lián)系作者淑玫。
  • 序言:七十年代末巾腕,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子絮蒿,更是在濱河造成了極大的恐慌尊搬,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,372評論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件土涝,死亡現(xiàn)場離奇詭異毁嗦,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)回铛,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,368評論 3 392
  • 文/潘曉璐 我一進(jìn)店門狗准,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人茵肃,你說我怎么就攤上這事腔长。” “怎么了验残?”我有些...
    開封第一講書人閱讀 162,415評論 0 353
  • 文/不壞的土叔 我叫張陵捞附,是天一觀的道長。 經(jīng)常有香客問我您没,道長鸟召,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,157評論 1 292
  • 正文 為了忘掉前任氨鹏,我火速辦了婚禮欧募,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘仆抵。我一直安慰自己跟继,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,171評論 6 388
  • 文/花漫 我一把揭開白布镣丑。 她就那樣靜靜地躺著舔糖,像睡著了一般。 火紅的嫁衣襯著肌膚如雪莺匠。 梳的紋絲不亂的頭發(fā)上金吗,一...
    開封第一講書人閱讀 51,125評論 1 297
  • 那天,我揣著相機(jī)與錄音趣竣,去河邊找鬼摇庙。 笑死,一個胖子當(dāng)著我的面吹牛期贫,可吹牛的內(nèi)容都是我干的跟匆。 我是一名探鬼主播,決...
    沈念sama閱讀 40,028評論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼通砍,長吁一口氣:“原來是場噩夢啊……” “哼玛臂!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起封孙,我...
    開封第一講書人閱讀 38,887評論 0 274
  • 序言:老撾萬榮一對情侶失蹤迹冤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后虎忌,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體泡徙,經(jīng)...
    沈念sama閱讀 45,310評論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,533評論 2 332
  • 正文 我和宋清朗相戀三年膜蠢,在試婚紗的時候發(fā)現(xiàn)自己被綠了堪藐。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片莉兰。...
    茶點(diǎn)故事閱讀 39,690評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖礁竞,靈堂內(nèi)的尸體忽然破棺而出糖荒,到底是詐尸還是另有隱情,我是刑警寧澤模捂,帶...
    沈念sama閱讀 35,411評論 5 343
  • 正文 年R本政府宣布捶朵,位于F島的核電站,受9級特大地震影響狂男,放射性物質(zhì)發(fā)生泄漏综看。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,004評論 3 325
  • 文/蒙蒙 一岖食、第九天 我趴在偏房一處隱蔽的房頂上張望红碑。 院中可真熱鬧,春花似錦县耽、人聲如沸句喷。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽唾琼。三九已至,卻和暖如春澎剥,著一層夾襖步出監(jiān)牢的瞬間锡溯,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,812評論 1 268
  • 我被黑心中介騙來泰國打工哑姚, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留祭饭,地道東北人。 一個月前我還...
    沈念sama閱讀 47,693評論 2 368
  • 正文 我出身青樓叙量,卻偏偏與公主長得像倡蝙,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子绞佩,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,577評論 2 353

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