詳細(xì)說說Binder 通信原理與機(jī)制

先上一張Binder 的工作流程圖。(如果不清晰,可以復(fù)制圖片鏈接到瀏覽器或
保存到本地查看,我經(jīng)常都是這樣看圖的哈)

image.png

一開始上手,陌生的東西比較多,But,其實并不復(fù)雜。喔,流程圖是用ProcessOn
畫的。很棒的在線畫圖工具。
出發(fā)前預(yù)備子彈我們知道進(jìn)程之間,虛擬地址不同,是不能直接通信的,這是
一種保護(hù)機(jī)制。打開任務(wù)管理器,查看一下N 多的進(jìn)程,試想一下如果這些進(jìn)
程直接通信會帶來什么后果?
而用戶空間可以通過System calls(系統(tǒng)回調(diào))與內(nèi)核空間通信的,如果在內(nèi)核
空間中有一個模塊,能夠完成數(shù)據(jù)的轉(zhuǎn)發(fā),那么是不是兩個進(jìn)程就可以通信了
呢?如下圖:

image.png

上面提到一些用戶空間、內(nèi)核空間的概念,用戶空間也能大概猜到是什么東西,
而內(nèi)核空間,就知道它是很底層的東西好了。而模塊呢,可以簡單的理解為實現(xiàn)
一個功能的程序或一個硬件電路等,比如玩單片機(jī)的時候,會有紅外線模塊,藍(lán)
牙模塊,wifi 模塊等。這些概念的東西搜索一下百科知道就好。
Binder 驅(qū)動
Binder 驅(qū)動運(yùn)行在內(nèi)核空間,它就是那個內(nèi)核模塊了。Binder 驅(qū)動很重要,承
擔(dān)了進(jìn)程間通信的數(shù)據(jù)轉(zhuǎn)發(fā)等。一提到驅(qū)動,也是比較熟悉,你插個U 盤,需
要驅(qū)動吧。而Binder 驅(qū)動也差不多,雖然名字取得很好,功能還很強(qiáng)大。但也
不是什么神奇的東西。

Binder 跨進(jìn)程通信模型
Binder 的通信模型有4 個角色:Binder Client、Binder Server、Binder Driver
(Binder 驅(qū)動)、ServiceManager。

想象一個情景:我到北京旅行,要給高中同學(xué)寄一張明信片,明信片肯定要寫上
地址吧,不然怎么寄給對方呢?那么我怎么拿到這個地址呢,很簡單,翻一下畢
業(yè)相冊就好了。而這個記錄著同學(xué)們通信地址的畢業(yè)相冊,就相當(dāng)與一個通訊錄。
在Binder 的通信模型中扮演的是ServiceManager 的角色。好,現(xiàn)在已經(jīng)有了通
信地址了,那么就找到郵局寄出去就好了。過幾天同學(xué)就高高興興的收到了明信
片。那么這個郵局在Binder 通信模型中扮演的是Binder 驅(qū)動的角色,而作為寄
信人的我就是Binder Client,收信人同學(xué)就是Binder Server。
先上一張圖來描述上面的那個情景:

image.png

可以看到,ServiceManager、Binder Client、Binder Server 處于不同的進(jìn)程,他
們?nèi)齻€都在用戶空間,而Binder 驅(qū)動在內(nèi)核空間。(我是特意把Binder 驅(qū)動畫
的比較大的,因為Binder 驅(qū)動的作用最大)
那先來簡述一下這個通信模型:
首先是有一個ServiceManager,剛開始這個通訊錄是空白的,然后Server 進(jìn)程
向ServiceManager 注冊一個映射關(guān)系表,比如徐同學(xué)把自己的地址廣東省廣州
市xx 區(qū)寫進(jìn)通訊錄,那么就形成了一張表:


image.png

之后Client 進(jìn)程想要和Server 進(jìn)程通信,首先向ServiceManager 查詢地址,
ServiceManager 收到查詢的請求之后,返回查詢結(jié)果給Client。
注意到這里不管是Server 進(jìn)程注冊,還是Client 查詢,都是經(jīng)過Binder 驅(qū)動的,
這也真是Binder 驅(qū)動的作用所在,先不急,下面的原理會分析到。
這時候我就拿著地址就開始寄明信片咯。當(dāng)我把明信片放扔進(jìn)郵筒,之后的工作
就是由郵局去完成了,也就是Binder 驅(qū)動去完成通信的轉(zhuǎn)發(fā)。

Binder 通信原理
從寄明信片的例子中,郵遞員從郵筒取出明信片,然后跨越千山萬水將明信片送
達(dá)。從這點(diǎn)我們也能想到,其實Binder 驅(qū)動完成的工作是很重要的。
我們來還原一個Binder 跨進(jìn)程通信的過程。案例:Client 進(jìn)程調(diào)用Server 進(jìn)程
的computer 對象的add 方法。
接下來的內(nèi)容你可能需要知道代理模式才能更好的理解,不過沒學(xué)習(xí)過代理模式
也沒關(guān)系,可以先讀下去,然后在去補(bǔ)一下代理模式,再回來看這篇文章。思路
會清晰很多。

1. Server 進(jìn)程向ServiceManager 注冊,告訴ServiceManager
我是誰,我有什么,我能做什么。就好比徐同學(xué)(Server 進(jìn)程)有
一臺筆記本(computer 對象),這臺筆記本有個add 方法。這時
映射關(guān)系表就生成了。

2. Client 進(jìn)程向ServiceManager 查詢,我要調(diào)用Server 進(jìn)程的
computer 對象的add 方法,可以看到這個過程經(jīng)過Binder 驅(qū)動,
這時候Binder 驅(qū)動就開始發(fā)揮他的作用了。當(dāng)向ServiceManager
查詢完畢,是返回一個computer 對象給Client 進(jìn)程嗎?其實不然,
Binder 驅(qū)動將computer 對象轉(zhuǎn)換成了computerProxy 對象,并轉(zhuǎn)
發(fā)給了Client 進(jìn)程,因此,Client 進(jìn)程拿到的并不是真實的
computer 對象,而是一個代理對象,即computerProxy 對象。很
容易理解這個computerProxy 對象也是有add 方法,(如果連add
方法都沒有,豈不是欺騙了Client?),但是這個add 方法只是對
參數(shù)進(jìn)行一些包裝而已。

3. 當(dāng)Client 進(jìn)程調(diào)用add 方法,這個消息發(fā)送給Binder 驅(qū)動,
這時驅(qū)動發(fā)現(xiàn),原來是computerProxy,那么Client 進(jìn)程應(yīng)該是需
要調(diào)用computer 對象的add 方法的,這時驅(qū)動通知Server 進(jìn)程,
調(diào)用你的computer 對象的add 方法,將結(jié)果給我。然后Server
進(jìn)程就將計算結(jié)果發(fā)送給驅(qū)動,驅(qū)動再轉(zhuǎn)發(fā)給Client 進(jìn)程,這時
Client 進(jìn)程還蒙在了鼓里,他以為自己調(diào)用的是真實的computer
對象的add 方法,其實他只是調(diào)用了代理而已。不過Client 最終
還是拿到了計算結(jié)果。
好了,一個通信過程就完成了。我們發(fā)現(xiàn),其實Binder 驅(qū)動就是一個中轉(zhuǎn)。

總結(jié)

再來梳理總結(jié)一下:當(dāng)Client 進(jìn)程向ServiceManager 查詢Server 進(jìn)程(我要調(diào)
用你的某個對象的某個方法了),這個過程也是一個跨進(jìn)程通信的過程,也經(jīng)過
了Binder 驅(qū)動,這時Binder 驅(qū)動發(fā)揮它的作用,來了個貍貓換太子,將Server
進(jìn)程中的真實對象轉(zhuǎn)換成代理對象,返回這個代理對象給Client 進(jìn)程。Client
進(jìn)程拿到了這個代理對象,然后調(diào)用這個代理對象的方法,Binder 驅(qū)動繼續(xù)發(fā)揮
他的使命,它會通知Server 進(jìn)程執(zhí)行計算工作,將Server 進(jìn)程中的真實對象執(zhí)行的結(jié)果返回給了Client 進(jìn)程,這樣Client 進(jìn)程還是如愿的得到了自己想要???br> 進(jìn)程通信完畢

Linux 自帶多種進(jìn)程通信方式, 為什么Android 都沒采用二偏偏使用Binder 通信

面試官: Linux 自帶多種進(jìn)程通信方式,為什么Android 都沒采用
而偏偏使用Binder 通信
心理分析:面試官絕對不會現(xiàn)場讓你分析binder 的源碼,源碼又
深又廣,沒有面試官會傻到讓你分析binder 所有的機(jī)制。他會問
你為什么不采用linux。從這個地方會看出你對binder 有多深。
這道題往往是面試Android 高級的必考題。所以小伙伴們需要格外
的注意
求職者:應(yīng)該從linux 自帶的進(jìn)程通信說起。然后各個擊破指
出在Android 這種特殊系統(tǒng)上的不足。最后引入binder 的優(yōu)勢

Linux 現(xiàn)有的所有進(jìn)程間IPC 方式:
1.管道:
什么是管道:
管道可用于具有親緣關(guān)系進(jìn)程間的通信,管道是由內(nèi)核管理的一個緩沖
區(qū),
相當(dāng)于我們放入內(nèi)存中的一個紙條。管道的一端連接一個進(jìn)程的輸出。這
個進(jìn)程會向管道中放入信息。
管道的另一端連接一個進(jìn)程的輸入,這個進(jìn)程取出被放入管道的信息。一
個緩沖區(qū)不需要很大,它被設(shè)計成為環(huán)形的數(shù)據(jù)結(jié)構(gòu),


image.png

以便管道可以被循環(huán)利用。當(dāng)管道中沒有信息的話,從管道中讀取的進(jìn)程
會等待,直到另一端的進(jìn)程放入信息。當(dāng)管道被放滿信息的時候,嘗試放
入信息的進(jìn)程會等待,直到另一端的進(jìn)程取出信息。當(dāng)兩個進(jìn)程都終結(jié)的
時候,管道也自動消失。
缺點(diǎn): 在創(chuàng)建時分配一個管道時,緩存區(qū)大小比較有限;并不適合Android
大量的進(jìn)程通信

2.消息隊列:
消息隊列提供了一種從一個進(jìn)程向另一個進(jìn)程發(fā)送一個數(shù)據(jù)塊的方
法。每個數(shù)據(jù)塊都被認(rèn)為含有一個類型,接收進(jìn)程可以獨(dú)立地接收含有
不同類型的數(shù)據(jù)結(jié)構(gòu)。我們可以通過發(fā)送消息來避免命名管道的同步和阻
塞問題。但是消息隊列與命名管道一樣,每個數(shù)據(jù)塊都有一個最大長度的
限制。
缺點(diǎn): 信息復(fù)制兩次,額外的CPU 消耗;不合適頻繁或信息量大的通信;

3.共享內(nèi)存:

什么是共享內(nèi)存:
顧名思義,共享內(nèi)存就是允許兩個不相關(guān)的進(jìn)程訪問同一個邏輯內(nèi)存。
共享內(nèi)存是在兩個正在運(yùn)行的進(jìn)程之間共享和傳遞數(shù)據(jù)的一種非常有效
的方式。不同進(jìn)程之間共享的內(nèi)存通常安排為同一段物理內(nèi)存。進(jìn)程可以
將同一段共享內(nèi)存連接到它們自己的地址空間中,所有進(jìn)程都可以訪問共
享內(nèi)存中的地址無須復(fù)制,共享緩沖區(qū)直接付附加到進(jìn)程虛擬地址空間,速度快;

缺點(diǎn): 通信需要設(shè)計復(fù)雜的機(jī)制保證各個進(jìn)程通訊有效性。進(jìn)程間的同步
問題操作系統(tǒng)無法實現(xiàn),必須各進(jìn)程利用同步工具解決; 安全問題比較
突出,如果Android 采用Binder 無異于將每個App 放在一個內(nèi)存中,這
樣是非常不安全的

4.套接字:作為更通用的接口,傳輸效率低,主要用于不通機(jī)器或跨網(wǎng)絡(luò)的通信;
5.信號量:常作為一種鎖機(jī)制,防止某進(jìn)程正在訪問共享資源時,其他進(jìn)程也訪
問該資源。因此,主要作為進(jìn)程間以及同一進(jìn)程內(nèi)不同線程之間的同步手段。
6.信號: 不適用于信息交換,更適用于進(jìn)程中斷控制,比如非法內(nèi)存訪問,殺死
某個進(jìn)程等;
接下來正面回答這個問題,從5 個角度來展開對Binder 的分析:

(1) 從性能的角度數(shù)據(jù)拷貝次數(shù):Binder 數(shù)據(jù)拷貝只需要一次,而管道、消息
隊列、Socket 都需要2 次,但共享內(nèi)存方式一次內(nèi)存拷貝都不需要;從性能角
度看,Binder 性能僅次于共享內(nèi)存。

(2) 從穩(wěn)定性的角度Binder 是基于C/S 架構(gòu)的,簡單解釋下C/S 架構(gòu),是指客
戶端(Client)和服務(wù)端(Server)組成的架構(gòu),Client 端有什么需求,直接發(fā)送給
Server 端去完成,架構(gòu)清晰明朗,Server 端與Client 端相對獨(dú)立,穩(wěn)定性較好;
而共享內(nèi)存實現(xiàn)方式復(fù)雜,沒有客戶與服務(wù)端之別, 需要充分考慮到訪問臨界
資源的并發(fā)同步問題,否則可能會出現(xiàn)死鎖等問題;從這穩(wěn)定性角度看,Binder
架構(gòu)優(yōu)越于共享內(nèi)存。
僅僅從以上兩點(diǎn),各有優(yōu)劣,還不足以支撐google 去采用binder 的IPC 機(jī)制,
那么更重要的原因是:

(3) 從安全的角度傳統(tǒng)Linux IPC 的接收方無法獲得對方進(jìn)程可靠的UID/PID,
從而無法鑒別對方身份;而Android 作為一個開放的開源體系,擁有非常多的開
發(fā)平臺,App 來源甚廣,因此手機(jī)的安全顯得額外重要;對于普通用戶,絕不希
望從App 商店下載偷窺隱射數(shù)據(jù)、后臺造成手機(jī)耗電等等問題,傳統(tǒng)Linux IPC
無任何保護(hù)措施,完全由上層協(xié)議來確保。
Android 為每個安裝好的應(yīng)用程序分配了自己的UID,故進(jìn)程的UID 是鑒別進(jìn)程
身份的重要標(biāo)志,前面提到C/S 架構(gòu),Android 系統(tǒng)中對外只暴露Client 端,
Client 端將任務(wù)發(fā)送給Server 端,Server 端會根據(jù)權(quán)限控制策略,判斷UID/PID
是否滿足訪問權(quán)限,目前權(quán)限控制很多時候是通過彈出權(quán)限詢問對話框,讓用
戶選擇是否運(yùn)行。Android 6.0,也稱為Android M,在6.0 之前的系統(tǒng)是在App
第一次安裝時,會將整個App 所涉及的所有權(quán)限一次詢問,只要留意看會發(fā)現(xiàn)
很多App 根本用不上通信錄和短信,但在這一次性權(quán)限權(quán)限時會包含進(jìn)去,讓
用戶拒絕不得,因為拒絕后App 無法正常使用,而一旦授權(quán)后,應(yīng)用便可以胡
作非為。
針對這個問題,google 在Android M 做了調(diào)整,不再是安裝時一并詢問所有權(quán)
限,而是在App 運(yùn)行過程中,需要哪個權(quán)限再彈框詢問用戶是否給相應(yīng)的權(quán)限,
對權(quán)限做了更細(xì)地控制,讓用戶有了更多的可控性,但同時也帶來了另一個用
戶詬病的地方,那也就是權(quán)限詢問的彈框的次數(shù)大幅度增多。
對于Android M
平臺上,有些App 開發(fā)者可能會寫出讓手機(jī)異常頻繁彈框的App,企圖直到用
戶授權(quán)為止,這對用戶來說是不能忍的,用戶最后吐槽的可不光是App,還有
Android 系統(tǒng)以及手機(jī)廠商,有些用戶可能就跳果粉了,這還需要廣大Android
開發(fā)者以及手機(jī)廠商共同努力,共同打造安全與體驗俱佳的Android 手機(jī)。
傳統(tǒng)IPC 只能由用戶在數(shù)據(jù)包里填入UID/PID;另外,可靠的身份標(biāo)記只有由IPC
機(jī)制本身在內(nèi)核中添加。其次傳統(tǒng)IPC 訪問接入點(diǎn)是開放的,無法建立私有通道。
從安全角度,Binder 的安全性更高。
說到這,可能有人要反駁,Android 就算用了Binder 架構(gòu),而現(xiàn)如今Android
手機(jī)的各種流氓軟件,不就是干著這種偷窺隱射,后臺偷偷跑流量的事嗎?沒錯,
確實存在,但這不能說Binder 的安全性不好,因為Android 系統(tǒng)仍然是掌握主
控權(quán),可以控制這類App 的流氓行為,只是對于該采用何種策略來控制,在這
方面android 的確存在很多有待進(jìn)步的空間,這也是google 以及各大手機(jī)廠商
一直努力改善的地方之一。在Android 6.0,google 對于app 的權(quán)限問題作為較
多的努力,大大收緊的應(yīng)用權(quán)限;另外,在Google 舉辦的Android Bootcamp
2016 大會中,google 也表示在Android 7.0 (也叫Android N)的權(quán)限隱私方
面會進(jìn)一步加強(qiáng)加固,比如SELinux,Memory safe language(還在research 中)
等等,在今年的5 月18 日至5 月20 日,google 將推出Android N。
話題扯遠(yuǎn)了,繼續(xù)說Binder。

(4)從語言層面的角度大家多知道Linux 是基于C 語言(面向過程的語言),而
Android 是基于Java 語言(面向?qū)ο蟮恼Z句),而對于Binder 恰恰也符合面向?qū)?br> 象的思想,將進(jìn)程間通信轉(zhuǎn)化為通過對某個Binder 對象的引用調(diào)用該對象的方
法,而其獨(dú)特之處在于Binder 對象是一個可以跨進(jìn)程引用的對象,它的實體位
于一個進(jìn)程中,而它的引用卻遍布于系統(tǒng)的各個進(jìn)程之中??梢詮囊粋€進(jìn)程傳給
其它進(jìn)程,讓大家都能訪問同一Server,就像將一個對象或引用賦值給另一個引
用一樣。Binder 模糊了進(jìn)程邊界,淡化了進(jìn)程間通信過程,整個系統(tǒng)仿佛運(yùn)行于
同一個面向?qū)ο蟮某绦蛑小恼Z言層面,Binder 更適合基于面向?qū)ο笳Z言的
Android 系統(tǒng),對于Linux 系統(tǒng)可能會有點(diǎn)“水土不服”。

另外,Binder 是為Android 這類系統(tǒng)而生,而并非Linux 社區(qū)沒有想到Binder
IPC 機(jī)制的存在,對于Linux 社區(qū)的廣大開發(fā)人員,我還是表示深深佩服,讓世
界有了如此精湛而美妙的開源系統(tǒng)。也并非Linux 現(xiàn)有的IPC 機(jī)制不夠好,相
反地,經(jīng)過這么多優(yōu)秀工程師的不斷打磨,依然非常優(yōu)秀,每種Linux 的IPC
機(jī)制都有存在的價值,同時在Android 系統(tǒng)中也依然采用了大量Linux 現(xiàn)有的
IPC 機(jī)制,根據(jù)每類IPC 的原理特性,因時制宜,不同場景特性往往會采用其下
最適宜的。比如在Android OS 中的Zygote 進(jìn)程的IPC 采用的是Socket(套
接字)機(jī)制,Android 中的Kill Process 采用的 signa(l 信號)機(jī)制等等。而 Binder
更多則用在system_server 進(jìn)程與上層App 層的IPC 交互。

(5) 從公司戰(zhàn)略的角度
總所周知,Linux 內(nèi)核是開源的系統(tǒng),所開放源代碼許可協(xié)議GPL 保護(hù),該協(xié)議
具有“病毒式感染”的能力,怎么理解這句話呢?受GPL 保護(hù)的Linux Kernel 是運(yùn)
行在內(nèi)核空間,對于上層的任何類庫、服務(wù)、應(yīng)用等運(yùn)行在用戶空間,一旦進(jìn)行
SysCall(系統(tǒng)調(diào)用),調(diào)用到底層Kernel,那么也必須遵循GPL 協(xié)議。
而Android 之父Andy Rubin 對于GPL 顯然是不能接受的,為此,Google 巧妙
地將GPL 協(xié)議控制在內(nèi)核空間,將用戶空間的協(xié)議采用Apache-2.0 協(xié)議(允許
基于Android 的開發(fā)商不向社區(qū)反饋源碼),同時在GPL 協(xié)議與Apache-2.0 之
間的Lib 庫中采用BSD 證授權(quán)方法,有效隔斷了GPL 的傳染性,仍有較大爭議,
但至少目前緩解Android,讓GPL 止步于內(nèi)核空間,這是Google 在GPL Linux
下開源與商業(yè)化共存的一個成功典范。
有了這些鋪墊,我們再說說Binder 的今世前緣
Binder 是基于開源的OpenBinder 實現(xiàn)的,OpenBinder 是一個開源的系統(tǒng)IPC
機(jī)制,最初是由Be Inc.開發(fā),接著由Palm, Inc.公司負(fù)責(zé)開發(fā),現(xiàn)在OpenBinder
的作者在Google 工作,既然作者在Google 公司,在用戶空間采用Binder 作為
核心的IPC 機(jī)制,再用Apache-2.0 協(xié)議保護(hù),自然而然是沒什么問題,減少法
律風(fēng)險,以及對開發(fā)成本也大有裨益的,那么從公司戰(zhàn)略角度,Binder 也是不錯
的選擇。
另外,再說一點(diǎn)關(guān)于OpenBinder,在2015 年OpenBinder 以及合入到Linux
Kernel 主線3.19 版本,這也算是Google 對Linux 的一點(diǎn)回饋吧。
綜合上述5 點(diǎn),可知Binder 是Android 系統(tǒng)上層進(jìn)程間通信的不二選擇。

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

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

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