詳細說說Binder通信原理與機制

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

詳細說說Binder通信原理與機制

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

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

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

詳細說說Binder通信原理與機制

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

Binder驅動

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

Binder跨進程通信模型

Binder的通信模型有4個角色:Binder Client、Binder Server、Binder Driver(Binder驅動)、ServiceManager。

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

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

詳細說說Binder通信原理與機制

可以看到,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進程還是如願的得到了自己想要。跨進程通信完畢


分享到:


相關文章: