先上一張Binder 的工作流程圖。(如果不清晰知押,可以 復(fù)制圖片鏈接到瀏覽器 或 保存到本地 查看淤刃,我經(jīng)常都是這樣看圖的哈)
一開始上手砸逊,陌生的東西比較多,But,其實并不復(fù)雜立镶。喔壁袄,流程圖是用 ProcessOn 畫的。很棒的在線畫圖工具媚媒。
出發(fā)前預(yù)備子彈
我們知道進程之間嗜逻,虛擬地址不同,是不能直接通信的缭召,這是一種保護機制栈顷。打開任務(wù)管理器,查看一下N多的進程恼琼,試想一下如果這些進程直接通信會帶來什么后果妨蛹?
而用戶空間可以通過System calls(系統(tǒng)回調(diào))與內(nèi)核空間通信的,如果在內(nèi)核空間中有一個模塊晴竞,能夠完成數(shù)據(jù)的轉(zhuǎn)發(fā)蛙卤,那么是不是兩個進程就可以通信了呢?如下圖:
上面提到一些用戶空間噩死、內(nèi)核空間的概念颤难,用戶空間也能大概猜到是什么東西,而內(nèi)核空間已维,就知道它是很底層的東西好了行嗤。而模塊呢,可以簡單的理解為實現(xiàn)一個功能的程序或一個硬件電路等垛耳,比如玩單片機的時候栅屏,會有紅外線模塊,藍(lán)牙模塊堂鲜,wifi模塊等栈雳。這些概念的東西搜索一下百科知道就好。
Binder驅(qū)動
Binder驅(qū)動運行在內(nèi)核空間缔莲,它就是那個內(nèi)核模塊了哥纫。Binder驅(qū)動很重要,承擔(dān)了進程間通信的數(shù)據(jù)轉(zhuǎn)發(fā)等痴奏。一提到驅(qū)動蛀骇,也是比較熟悉,你插個U盤读拆,需要驅(qū)動吧擅憔。而Binder驅(qū)動也差不多,雖然名字取得很好建椰,功能還很強大雕欺。但也不是什么神奇的東西。
Binder跨進程通信模型
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憔儿。
先上一張圖來描述上面的那個情景:
可以看到,ServiceManager放可、Binder Client谒臼、Binder Server處于不同的進程,他們?nèi)齻€都在用戶空間耀里,而Binder驅(qū)動在內(nèi)核空間屋休。(我是特意把Binder驅(qū)動畫的比較大的,因為Binder驅(qū)動的作用最大)
那先來簡述一下這個通信模型:
首先是有一個ServiceManager备韧,剛開始這個通訊錄是空白的,然后Server進程向ServiceManager注冊一個映射關(guān)系表痪枫,比如徐同學(xué)把自己的地址廣東省廣州市xx區(qū)寫進通訊錄织堂,那么就形成了一張表:
徐同學(xué) —> 廣東省廣州市xx區(qū)
之后Client進程想要和Server進程通信,首先向ServiceManager查詢地址奶陈,ServiceManager收到查詢的請求之后易阳,返回查詢結(jié)果給Client。
注意到這里不管是Server進程注冊吃粒,還是Client查詢潦俺,都是經(jīng)過Binder驅(qū)動的,這也真是Binder驅(qū)動的作用所在,先不急事示,下面的原理會分析到早像。
這時候我就拿著地址就開始寄明信片咯。當(dāng)我把明信片放扔進郵筒肖爵,之后的工作就是由郵局去完成了卢鹦,也就是Binder驅(qū)動去完成通信的轉(zhuǎn)發(fā)。
Binder通信原理
從寄明信片的例子中劝堪,郵遞員從郵筒取出明信片冀自,然后跨越千山萬水將明信片送達(dá)。從這點我們也能想到秒啦,其實Binder驅(qū)動完成的工作是很重要的熬粗。
我們來還原一個Binder跨進程通信的過程。 案例:Client進程調(diào)用Server進程的computer對象的add方法余境。
接下來的內(nèi)容你可能需要知道代理模式才能更好的理解驻呐,不過沒學(xué)習(xí)過代理模式也沒關(guān)系,可以先讀下去葛超,然后在去補一下代理模式暴氏,再回來看這篇文章。思路會清晰很多绣张。
1. Server進程向ServiceManager注冊答渔,告訴ServiceManager我是誰,我有什么侥涵,我能做什么沼撕。就好比徐同學(xué)(Server進程)有一臺筆記本(computer對象),這臺筆記本有個add方法芜飘。這時映射關(guān)系表就生成了务豺。
2. Client進程向ServiceManager查詢,我要調(diào)用Server進程的computer對象的add方法嗦明,可以看到這個過程經(jīng)過Binder驅(qū)動笼沥,這時候Binder驅(qū)動就開始發(fā)揮他的作用了。
當(dāng)向ServiceManager查詢完畢娶牌,是返回一個computer對象給Client進程嗎奔浅?其實不然,Binder驅(qū)動將computer對象轉(zhuǎn)換成了computerProxy對象诗良,并轉(zhuǎn)發(fā)給了Client進程汹桦,
因此,Client進程拿到的并不是真實的computer對象鉴裹,而是一個代理對象舞骆,即computerProxy對象钥弯。很容易理解這個computerProxy對象也是有add方法,(如果連add方法都沒有督禽,豈不是欺騙了Client脆霎?),但是這個add方法只是對參數(shù)進行一些包裝而已赂蠢。
3. 當(dāng)Client進程調(diào)用add方法绪穆,這個消息發(fā)送給Binder驅(qū)動,這時驅(qū)動發(fā)現(xiàn)虱岂,原來是computerProxy玖院,那么Client進程應(yīng)該是需要調(diào)用computer對象的add方法的,這時驅(qū)動通知Server進程第岖,調(diào)用你的computer對象的add方法难菌,將結(jié)果給我。
然后Server進程就將計算結(jié)果發(fā)送給驅(qū)動蔑滓,驅(qū)動再轉(zhuǎn)發(fā)給Client進程郊酒,這時Client進程還蒙在了鼓里,他以為自己調(diào)用的是真實的computer對象的add方法键袱,其實他只是調(diào)用了代理而已燎窘。不過Client最終還是拿到了計算結(jié)果。
好了蹄咖,一個通信過程就完成了褐健。我們發(fā)現(xiàn),其實Binder驅(qū)動就是一個中轉(zhuǎn)澜汤。
總結(jié)
再來梳理總結(jié)一下:當(dāng)Client進程向ServiceManager查詢Server進程(我要調(diào)用你的某個對象的某個方法了)蚜迅,這個過程也是一個跨進程通信的過程,也經(jīng)過了Binder驅(qū)動俊抵,這時Binder驅(qū)動發(fā)揮它的作用谁不,來了個貍貓換太子,將Server進程中的真實對象轉(zhuǎn)換成代理對象徽诲,返回這個代理對象給Client進程刹帕。
Client進程拿到了這個代理對象,然后調(diào)用這個代理對象的方法谎替,Binder驅(qū)動繼續(xù)發(fā)揮他的使命轩拨,它會通知Server進程執(zhí)行計算工作,將Server進程中的真實對象執(zhí)行的結(jié)果返回給了Client進程院喜,這樣Client進程還是如愿的得到了自己想要≡未洌跨進程通信完畢喷舀!
這篇文章寫的主要是我學(xué)習(xí)Binder時的痛點砍濒,我看過好多篇講Binder的文章,發(fā)現(xiàn)好多都是不講Binder驅(qū)動的硫麻,我很懵逼為什么那么重要的東西就略過爸邢,但還是有大神寫的很好,比如:
Binder學(xué)習(xí)指南
Android Binder設(shè)計與實現(xiàn)
關(guān)于用戶空間和內(nèi)核空間拿愧,可以閱讀阮一峰老師的文章:User space 與 Kernel space
全文完畢杠河!