Android Binder跨進程通訊原理分析

先上一張Binder 的工做流程圖。(若是不清晰,能夠 複製圖片連接到瀏覽器 或 保存到本地 查看,我常常都是這樣看圖的哈)瀏覽器

一開始上手,陌生的東西比較多,But,其實並不複雜。喔,流程圖是用 ProcessOn 畫的。很棒的在線畫圖工具。工具

出發前預備子彈
咱們知道進程之間,虛擬地址不一樣,是不能直接通訊的,這是一種保護機制。打開任務管理器,查看一下N多的進程,試想一下若是這些進程直接通訊會帶來什麼後果?學習

而用戶空間能夠經過System calls(系統回調)與內核空間通訊的,若是在內核空間中有一個模塊,可以完成數據的轉發,那麼是否是兩個進程就能夠通訊了呢?以下圖:動畫

上面提到一些用戶空間、內核空間的概念,用戶空間也能大概猜到是什麼東西,而內核空間,就知道它是很底層的東西好了。而模塊呢,能夠簡單的理解爲實現一個功能的程序或一個硬件電路等,好比玩單片機的時候,會有紅外線模塊,藍牙模塊,wifi模塊等。這些概念的東西搜索一下百科知道就好。spa

Binder驅動
Binder驅動運行在內核空間,它就是那個內核模塊了。Binder驅動很重要,承擔了進程間通訊的數據轉發等。一提到驅動,也是比較熟悉,你插個U盤,須要驅動吧。而Binder驅動也差很少,雖然名字取得很好,功能還很強大。但也不是什麼神奇的東西。設計

Binder跨進程通訊模型
Binder的通訊模型有4個角色:Binder Client、Binder Server、Binder Driver(Binder驅動)、ServiceManager。代理

想象一個情景:我到北京旅行,要給高中同窗寄一張明信片,明信片確定要寫上地址吧,否則怎麼寄給對方呢?那麼我怎麼拿到這個地址呢,很簡單,翻一下畢業相冊就行了。而這個記錄着同窗們通訊地址的畢業相冊,就至關與一個通信錄。在Binder的通訊模型中扮演的是ServiceManager的角色。好,如今已經有了通訊地址了,那麼就找到郵局寄出去就行了。過幾天同窗就高高興興的收到了明信片。那麼這個郵局在Binder通訊模型中扮演的是Binder驅動的角色,而做爲寄信人的我就是Binder Client,收信人同窗就是Binder Server。對象

先上一張圖來描述上面的那個情景:blog

能夠看到,ServiceManager、Binder Client、Binder Server處於不一樣的進程,他們三個都在用戶空間,而Binder驅動在內核空間。(我是特地把Binder驅動畫的比較大的,由於Binder驅動的做用最大)進程

那先來簡述一下這個通訊模型:

首先是有一個ServiceManager,剛開始這個通信錄是空白的,而後Server進程向ServiceManager註冊一個映射關係表,好比徐同窗把本身的地址廣東省廣州市xx區寫進通信錄,那麼就造成了一張表:

徐同窗 —> 廣東省廣州市xx區

以後Client進程想要和Server進程通訊,首先向ServiceManager查詢地址,ServiceManager收到查詢的請求以後,返回查詢結果給Client。

注意到這裏不論是Server進程註冊,仍是Client查詢,都是通過Binder驅動的,這也真是Binder驅動的做用所在,先不急,下面的原理會分析到。

這時候我就拿着地址就開始寄明信片咯。當我把明信片放扔進郵筒,以後的工做就是由郵局去完成了,也就是Binder驅動去完成通訊的轉發。

Binder通訊原理
從寄明信片的例子中,郵遞員從郵筒取出明信片,而後跨越千山萬水將明信片送達。從這點咱們也能想到,其實Binder驅動完成的工做是很重要的。

咱們來還原一個Binder跨進程通訊的過程。
案例:Client進程調用Server進程的computer對象的add方法。

接下來的內容你可能須要知道代理模式才能更好的理解,不過沒學習過代理模式也不要緊,能夠先讀下去,而後在去補一下代理模式,再回來看這篇文章。思路會清晰不少。

1. Server進程向ServiceManager註冊,告訴ServiceManager我是誰,我有什麼,我能作什麼。就比如徐同窗(Server進程)有一臺筆記本(computer對象),這檯筆記本有個add方法。這時映射關係表就生成了。
2. Client進程向ServiceManager查詢,我要調用Server進程的computer對象的add方法,能夠看到這個過程通過Binder驅動,這時候Binder驅動就開始發揮他的做用了。當向ServiceManager查詢完畢,是返回一個computer對象給Client進程嗎?其實否則,Binder驅動將computer對象轉換成了computerProxy對象,並轉發給了Client進程,所以,Client進程拿到的並非真實的computer對象,而是一個代理對象,即computerProxy對象。很容易理解這個computerProxy對象也是有add方法,(若是連add方法都沒有,豈不是欺騙了Client?),可是這個add方法只是對參數進行一些包裝而已。
3. 當Client進程調用add方法,這個消息發送給Binder驅動,這時驅動發現,原來是computerProxy,那麼Client進程應該是須要調用computer對象的add方法的,這時驅動通知Server進程,調用你的computer對象的add方法,將結果給我。而後Server進程就將計算結果發送給驅動,驅動再轉發給Client進程,這時Client進程還蒙在了鼓裏,他覺得本身調用的是真實的computer對象的add方法,其實他只是調用了代理而已。不過Client最終仍是拿到了計算結果。

好了,一個通訊過程就完成了。咱們發現,其實Binder驅動就是一箇中轉。

總結
再來梳理總結一下:當Client進程向ServiceManager查詢Server進程(我要調用你的某個對象的某個方法了),這個過程也是一個跨進程通訊的過程,也通過了Binder驅動,這時Binder驅動發揮它的做用,來了個狸貓換太子,將Server進程中的真實對象轉換成代理對象,返回這個代理對象給Client進程。
Client進程拿到了這個代理對象,而後調用這個代理對象的方法,Binder驅動繼續發揮他的使命,它會通知Server進程執行計算工做,將Server進程中的真實對象執行的結果返回給了Client進程,這樣Client進程仍是如願的獲得了本身想要。跨進程通訊完畢!

這篇文章寫的主要是我學習Binder時的痛點,我看過好多篇講Binder的文章,發現好多都是不講Binder驅動的,我很懵逼爲何那麼重要的東西就略過,但仍是有大神寫的很好,好比:

Binder學習指南

Android Binder設計與實現

關於用戶空間和內核空間,能夠閱讀阮一峯老師的文章:User space 與 Kernel space

全文完畢!  

相關文章
相關標籤/搜索