Binder概述
Linux的進(jìn)程間通信機(jī)制
Android系統(tǒng)中,每一個(gè)應(yīng)用程序都是由一些Activity和Service組成的,這些Activity和Service有可能運(yùn)行在同一個(gè)進(jìn)程中,也有可能運(yùn)行在不同的進(jìn)程中。那么,不在同一個(gè)進(jìn)程的Activity或者Service是如何通信的呢?這就是本文中要介紹的Binder進(jìn)程間通信機(jī)制了。
我們知道,Android系統(tǒng)是基于Linux內(nèi)核的,而Linux內(nèi)核繼承和兼容了豐富的Unix系統(tǒng)進(jìn)程間通信(IPC)機(jī)制。有傳統(tǒng)的管道(Pipe)、信號(hào)(Signal)和跟蹤(Trace),這三項(xiàng)通信手段只能用于父進(jìn)程與子進(jìn)程之間,或者兄弟進(jìn)程之間;后來(lái)又增加了命令管道(Named Pipe),使得進(jìn)程間通信不再局限于父子進(jìn)程或者兄弟進(jìn)程之間;為了更好地支持商業(yè)應(yīng)用中的事務(wù)處理,在AT&T的Unix系統(tǒng)V中,又增加了三種稱為“System V IPC”的進(jìn)程間通信機(jī)制,分別是報(bào)文隊(duì)列(Message)、共享內(nèi)存(Share Memory)和信號(hào)量(Semaphore);后來(lái)BSD Unix對(duì)“System V IPC”機(jī)制進(jìn)行了重要的擴(kuò)充,提供了一種稱為插口(Socket)的進(jìn)程間通信機(jī)制。若想進(jìn)一步詳細(xì)了解這些進(jìn)程間通信機(jī)制,建議參考羅升陽(yáng)老師的Android學(xué)習(xí)啟動(dòng)篇一文中提到《Linux內(nèi)核源代碼情景分析》一書。
各個(gè)進(jìn)程間通信方式比較:
- 管道:在創(chuàng)建時(shí)分配一個(gè)page大小的內(nèi)存,緩存區(qū)大小比較有限;
- 消息隊(duì)列:信息復(fù)制兩次,額外的CPU消耗;不合適頻繁或信息量大的通信;
- 共享內(nèi)存:無(wú)須復(fù)制,共享緩沖區(qū)直接付附加到進(jìn)程虛擬地址空間,速度快;但進(jìn)程間的同步問題操作系統(tǒng)無(wú)法實(shí)現(xiàn),必須各進(jìn)程利用同步工具解決;
- 套接字:作為更通用的接口,傳輸效率低,主要用于不同機(jī)器或跨網(wǎng)絡(luò)的通信;
- 信號(hào)量:常作為一種鎖機(jī)制,防止某進(jìn)程正在訪問共享資源時(shí),其他進(jìn)程也訪問該資源。因此,主要作為進(jìn)程間以及同一進(jìn)程內(nèi)不同線程之間的同步手段。
- 信號(hào): 不適用于信息交換,更適用于進(jìn)程中斷控制,比如非法內(nèi)存訪問,殺死某個(gè)進(jìn)程等;
Binder的優(yōu)勢(shì)
- 從性能的角度
數(shù)據(jù)拷貝次數(shù):Binder數(shù)據(jù)拷貝只需要一次,而管道、消息隊(duì)列、Socket都需要2次,但共享內(nèi)存方式一次內(nèi)存拷貝都不需要;從性能角度看,Binder性能僅次于共享內(nèi)存。
- 從穩(wěn)定性的角度
Binder是基于C/S架構(gòu)的,C/S架構(gòu)是指客戶端(Client)和服務(wù)端(Server)組成的架構(gòu),Client端有什么需求,直接發(fā)送給Server端去完成,架構(gòu)清晰明朗,Server端與Client端相對(duì)獨(dú)立,穩(wěn)定性較好;而共享內(nèi)存實(shí)現(xiàn)方式復(fù)雜,沒有客戶與服務(wù)端之別, 需要充分考慮到訪問臨界資源的并發(fā)同步問題,否則可能會(huì)出現(xiàn)死鎖等問題;從這穩(wěn)定性角度看,Binder架構(gòu)優(yōu)越于共享內(nèi)存。
- 從安全的角度
傳統(tǒng)Linux IPC的接收方無(wú)法獲得對(duì)方進(jìn)程可靠的UID/PID,從而無(wú)法鑒別對(duì)方身份;而Android作為一個(gè)開放的開源體系,擁有非常多的開發(fā)平臺(tái),App來(lái)源甚廣,因此手機(jī)的安全顯得額外重要;對(duì)于普通用戶,絕不希望從App商店下載偷窺隱射數(shù)據(jù)、后臺(tái)造成手機(jī)耗電等等問題,傳統(tǒng)Linux IPC無(wú)任何保護(hù)措施,完全由上層協(xié)議來(lái)確保。Android為每個(gè)安裝好的應(yīng)用程序分配了自己的UID,故進(jìn)程的UID是鑒別進(jìn)程身份的重要標(biāo)志,前面提到C/S架構(gòu),Android系統(tǒng)中對(duì)外只暴露Client端,Client端將任務(wù)發(fā)送給Server端,Server端會(huì)根據(jù)權(quán)限控制策略,判斷UID/PID是否滿足訪問權(quán)限,目前權(quán)限控制很多時(shí)候是通過(guò)彈出權(quán)限詢問對(duì)話框,讓用戶選擇是否運(yùn)行。Android 6.0,也稱為Android M,在6.0之前的系統(tǒng)是在App第一次安裝時(shí),會(huì)將整個(gè)App所涉及的所有權(quán)限一次詢問,只要留意看會(huì)發(fā)現(xiàn)很多App根本用不上通信錄和短信,但在這一次性權(quán)限權(quán)限時(shí)會(huì)包含進(jìn)去,讓用戶拒絕不得,因?yàn)榫芙^后App無(wú)法正常使用,而一旦授權(quán)后,應(yīng)用便可以胡作非為。針對(duì)這個(gè)問題,google在Android M做了調(diào)整,不再是安裝時(shí)一并詢問所有權(quán)限,而是在App運(yùn)行過(guò)程中,需要哪個(gè)權(quán)限再?gòu)椏蛟儐栍脩羰欠窠o相應(yīng)的權(quán)限,對(duì)權(quán)限做了更細(xì)地控制,讓用戶有了更多的可控性,但同時(shí)也帶來(lái)了另一個(gè)用戶詬病的地方,那也就是權(quán)限詢問的彈框的次數(shù)大幅度增多。對(duì)于Android M平臺(tái)上,有些App開發(fā)者可能會(huì)寫出讓手機(jī)異常頻繁彈框的App,企圖直到用戶授權(quán)為止,這對(duì)用戶來(lái)說(shuō)是不能忍的,用戶最后吐槽的可不光是App,還有Android系統(tǒng)以及手機(jī)廠商,有些用戶可能就跳果粉了,這還需要廣大Android開發(fā)者以及手機(jī)廠商共同努力,共同打造安全與體驗(yàn)俱佳的Android手機(jī)。
傳統(tǒng)IPC只能由用戶在數(shù)據(jù)包里填入U(xiǎn)ID/PID;另外,可靠的身份標(biāo)記只有由IPC機(jī)制本身在內(nèi)核中添加。其次傳統(tǒng)IPC訪問接入點(diǎn)是開放的,無(wú)法建立私有通道。從安全角度,Binder的安全性更高。
- 從語(yǔ)言層面的角度
大家多知道Linux是基于C語(yǔ)言(面向過(guò)程的語(yǔ)言),而Android是基于Java語(yǔ)言(面向?qū)ο蟮恼Z(yǔ)句),而對(duì)于Binder恰恰也符合面向?qū)ο蟮乃枷?,將進(jìn)程間通信轉(zhuǎn)化為通過(guò)對(duì)某個(gè)Binder對(duì)象的引用調(diào)用該對(duì)象的方法,而其獨(dú)特之處在于Binder對(duì)象是一個(gè)可以跨進(jìn)程引用的對(duì)象,它的實(shí)體位于一個(gè)進(jìn)程中,而它的引用卻遍布于系統(tǒng)的各個(gè)進(jìn)程之中??梢詮囊粋€(gè)進(jìn)程傳給其它進(jìn)程,讓大家都能訪問同一Server,就像將一個(gè)對(duì)象或引用賦值給另一個(gè)引用一樣。Binder模糊了進(jìn)程邊界,淡化了進(jìn)程間通信過(guò)程,整個(gè)系統(tǒng)仿佛運(yùn)行于同一個(gè)面向?qū)ο蟮某绦蛑小?/p>
從語(yǔ)言層面,Binder更適合基于面向?qū)ο笳Z(yǔ)言的Android系統(tǒng),對(duì)于Linux系統(tǒng)可能會(huì)有點(diǎn)“水土不服”。另外,Binder是為Android這類系統(tǒng)而生,而并非Linux社區(qū)沒有想到Binder IPC機(jī)制的存在。也并非Linux現(xiàn)有的IPC機(jī)制不夠好,相反地,經(jīng)過(guò)這么多優(yōu)秀工程師的不斷打磨,依然非常優(yōu)秀,每種Linux的IPC機(jī)制都有存在的價(jià)值,同時(shí)在Android系統(tǒng)中也依然采用了大量Linux現(xiàn)有的IPC機(jī)制,根據(jù)每類IPC的原理特性,因時(shí)制宜,不同場(chǎng)景特性往往會(huì)采用其下最適宜的。比如在Android OS中的Zygote進(jìn)程的IPC采用的是Socket(套接字)機(jī)制,Android中的Kill Process采用的signal(信號(hào))機(jī)制等等。而Binder更多則用在system_server進(jìn)程與上層App層的IPC交互。
Binder的缺點(diǎn)
Binder對(duì)CPU和內(nèi)存的需求比較低,效率比較高,從而進(jìn)一步說(shuō)明Binder適合于移動(dòng)系統(tǒng)Android,但是,也有一定缺點(diǎn),就是不同利用Binder輸出大數(shù)據(jù),比如利用Binder傳輸幾M大小的圖片,便會(huì)出現(xiàn)異常,雖然有廠商會(huì)增加Binder內(nèi)存,但是也不可能比系統(tǒng)默認(rèn)內(nèi)存大很多,否則整個(gè)系統(tǒng)的可用內(nèi)存大幅度降低。
講了Binder的這么多好處,就來(lái)看看Binder是如何運(yùn)行起來(lái)的吧!
學(xué)習(xí)計(jì)劃

完成一次Client到Server通信的流轉(zhuǎn)還是比較復(fù)雜的,從應(yīng)用層到Framework層、從UserSpace到KernelSpace、從Java層到Jni層都涉及到了。Binder學(xué)習(xí)的這個(gè)過(guò)程也可以對(duì)Android、Linux系統(tǒng)有更深入的了解。
廢話就不多說(shuō)了,回到正題。個(gè)人先簡(jiǎn)單總結(jié)了幾大主要步驟:
- ServiceManager啟動(dòng),注冊(cè)成為Binder通信的上下文管理者
- 如何獲取Service Manager
- Server啟動(dòng)并向Service Manager注冊(cè)
- Client通過(guò)ServiceManager獲取Service信息
- Client根據(jù)得到的Service信息建立與Service所在的Server進(jìn)程通信的通路,然后直接與Service交互。
這個(gè)順序是由底層向上層排的,但為了方便學(xué)習(xí),我會(huì)從上層入手,逐步深入的學(xué)習(xí)。
學(xué)習(xí)過(guò)程中大量參考了羅升陽(yáng)老師及Gityuan的博文,在此表示感謝!