淺談Binder通訊原理與機制

Binder是Android提供的一種進程間通訊(IPC,Inter-Process Communication)機制。android

Android是基於Linux的操做系統,Linux自帶多種進程通訊方式,爲何還要引入Binder。因此在講解Binder以前,先來分析Linux自帶的七種通訊方式。git

1、Linux系統的進程間通訊

進程是一個獨立的資源分配單元,不一樣進程(一般指用戶進程)之間的資源是獨立的,一個進程不能直接訪問另外一個進程的資源,可是,進程不是孤立的,不一樣的進程須要進行信息的交互和狀態的傳遞等,所以須要進程間通訊。github

進程間通訊的目的:緩存

  • 數據傳輸:一個進程須要將它的數據發送給另外一個進程。
  • 通知事件:一個進程須要向另外一個或一組進程發送消息,通知它(它們)發生了某種事件(如進程終止時要通知父進程)。
  • 資源共享:多個進程之間共享一樣的資源。爲了作到這一點,須要內核提供互斥和同步機制。
  • 進程控制:有些進程但願徹底控制另外一個進程的執行(如 Debug 進程),此時控制進程但願可以攔截另外一個進程的全部陷入和異常,並可以及時知道它的狀態改變。

Linux只要支持的七種進程間通訊方式以下:安全

(1)管道(pipe)網絡

管道是由內核管理的一個緩衝區,至關於咱們放入內存中的一個紙條。管道的一端鏈接一個進程的輸出,這個進程會向管道中放入信息。管道的另外一端鏈接一個進程的輸入,這個進程取出被放入管道的信息。一個緩衝區不須要很大,它被設計成 環形的數據結構,以即可循環利用。當管道中沒有信息的話,從管道中讀取的進程會等待,直到另外一端的進程放入信息。當管道被放滿信息的時候,嘗試放入信息的進程會等待,直到另外一端的進程取出信息。當兩個進程都終結的時候,管道也自動消失。數據結構

管道容許一個進程和另外一個與它有共同祖先的進程之間進行通訊。架構

(2)命名管道(FIFO)併發

相似於管道,可是它能夠用於任何兩個進程之間的通訊,命名管道在文件系統中有對應的文件名。命名管道經過命令mkfifo或系統調用mkfifo來建立。app

缺點(管道和命名管道):在建立時分配一個管道時,緩存區大小比較有限,數據以無格式字節流傳輸;並不適合Android大量的進程通訊。

(3)消息隊列(message queue)

消息隊列提供了一種從一個進程向另外一個進程發送一個數據塊的方法。 每一個數據塊都被認爲含有一個類型,接收進程能夠獨立地接收含有不一樣類型的數據結構。咱們能夠經過發送消息來避免命名管道的同步和阻塞問題。可是消息隊列與命名管道同樣,每一個數據塊都有一個最大長度的限制。

缺點: 信息複製兩次,額外的CPU消耗;不合適頻繁或信息量大的通訊;

(4)共享內存(shared memory)

共享內存就是容許兩個不相關的進程訪問同一個邏輯內存,是最快的可用IPC形式。不一樣進程之間共享的內存一般安排爲同一段物理內存,進程能夠將同一段共享內存鏈接到它們本身的地址空間中,全部進程均可以訪問共享內存中的地址。同時,爲了安全性考慮,它每每與其餘通訊機制,如信號量結合使用,以達到進程間的同步及互斥。無須複製,共享緩衝區直接付附加到進程虛擬地址空間,速度快

缺點: 通訊須要設計複雜的機制保證各進程通信有效性。進程間的同步問題操做系統沒法實現,必須各進程利用同步工具解決; 安全問題比較突出,若是Android採用Binder 無異於將每一個App放在一個內存中,這樣是很是不安全的。

(5)套接字(Socket)

套接字做爲更通用的接口,傳輸效率低,主要用於不通機器或跨網絡的通訊。

(6)信號量(semaphore)

常做爲一種鎖機制,防止某進程正在訪問共享資源時,其餘進程也訪問該資源。所以,主要做爲進程間以及同一進程內不一樣線程之間的同步手段。

(7)信號(signal)

不適用於信息交換,更適用於進程中斷控制,好比非法內存訪問,殺死某個進程等;

2、爲何Android引入Binder通訊?

下面咱們從5個角度來展開對Binder的分析:

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

(2) 從穩定性的角度 Binder是基於C/S架構的,簡單解釋下C/S架構,是指客戶端(Client)和服務端(Server)組成的架構,Client端有什麼需求,直接發送給Server端去完成,架構清晰明朗,Server端與Client端相對獨立,穩定性較好;而共享內存實現方式複雜,沒有客戶與服務端之別, 須要充分考慮到訪問臨界資源的併發同步問題,不然可能會出現死鎖等問題;從這穩定性角度看,Binder架構優越於共享內存。

僅僅從以上兩點,各有優劣,還不足以支撐google去採用binder的IPC機制,那麼更重要的緣由是:

(3) 從安全的角度 傳統Linux IPC的接收方沒法得到對方進程可靠的UID/PID,從而沒法鑑別對方身份;而Android做爲一個開放的開源體系,擁有很是多的開發平臺,App來源甚廣,所以手機的安全顯得額外重要;對於普通用戶,毫不但願從App商店下載偷窺隱射數據、後臺形成手機耗電等等問題,傳統Linux IPC無任何保護措施,徹底由上層協議來確保。

Android爲每一個安裝好的應用程序分配了本身的UID,故進程的UID是鑑別進程身份的重要標誌,前面提到C/S架構,Android系統中對外只暴露Client端,Client端將任務發送給Server端,Server端會根據權限控制策略,判斷UID/PID是否知足訪問權限,目前權限控制不少時候是經過彈出權限詢問對話框,讓用戶選擇是否運行。Android 6.0,也稱爲Android M,在6.0以前的系統是在App第一次安裝時,會將整個App所涉及的全部權限一次詢問,只要留意看會發現不少App根本用不上通訊錄和短信,但在這一次性權限權限時會包含進去,讓用戶拒毫不得,由於拒絕後App沒法正常使用,而一旦受權後,應用即可以胡做非爲。

針對這個問題,google在Android M作了調整,再也不是安裝時一併詢問全部權限,而是在App運行過程當中,須要哪一個權限再彈框詢問用戶是否給相應的權限,對權限作了更細地控制,讓用戶有了更多的可控性,但**同時也帶來了另外一個用戶詬病的地方,那也就是權限詢問的彈框的次數大幅度增多。**對於Android M平臺上,有些App開發者可能會寫出讓手機異常頻繁彈框的App,企圖直到用戶受權爲止,這對用戶來講是不能忍的,用戶最後吐槽的可不光是App,還有Android系統以及手機廠商,有些用戶可能就跳果粉了,這還須要廣大Android開發者以及手機廠商共同努力,共同打造安全與體驗俱佳的Android手機。

傳統IPC只能由用戶在數據包裏填入UID/PID;另外,可靠的身份標記只有由IPC機制自己在內核中添加。其次傳統IPC訪問接入點是開放的,沒法創建私有通道。從安全角度,Binder的安全性更高。

說到這,可能有人要反駁,Android就算用了Binder架構,而現現在Android手機的各類流氓軟件,不就是幹着這種偷窺隱射,後臺偷偷跑流量的事嗎?沒錯,確實存在,但這不能說Binder的安全性很差,由於Android系統仍然是掌握主控權,能夠控制這類App的流氓行爲,只是對於該採用何種策略來控制,在這方面android的確存在不少有待進步的空間,這也是google以及各大手機廠商一直努力改善的地方之一。在Android 6.0,google對於app的權限問題做爲較多的努力,大大收緊的應用權限;另外,在Google舉辦的Android Bootcamp 2016大會中,google也表示在Android 7.0 (也叫Android N)的權限隱私方面會進一步增強加固,好比SELinux,Memory safe language(還在research中)等等,在今年的5月18日至5月20日,google將推出Android N。

話題扯遠了,繼續說Binder。

(4)從語言層面的角度 你們多知道Linux是基於C語言(面向過程的語言),而Android是基於Java語言(面向對象的語句),而對於Binder偏偏也符合面向對象的思想,將進程間通訊轉化爲經過對某個Binder對象的引用調用該對象的方法,而其獨特之處在於Binder對象是一個能夠跨進程引用的對象,它的實體位於一個進程中,而它的引用卻遍及於系統的各個進程之中。能夠從一個進程傳給其它進程,讓你們都能訪問同一Server,就像將一個對象或引用賦值給另外一個引用同樣。Binder模糊了進程邊界,淡化了進程間通訊過程,整個系統彷彿運行於同一個面向對象的程序之中。從語言層面,Binder更適合基於面嚮對象語言的Android系統,對於Linux系統可能會有點「水土不服」。

另外,Binder是爲Android這類系統而生,而並不是Linux社區沒有想到Binder IPC機制的存在,對於Linux社區的廣大開發人員,我仍是表示深深佩服,讓世界有了如此精湛而美妙的開源系統。也並不是Linux現有的IPC機制不夠好,相反地,通過這麼多優秀工程師的不斷打磨,依然很是優秀,每種Linux的IPC機制都有存在的價值,同時在Android系統中也依然採用了大量Linux現有的IPC機制,根據每類IPC的原理特性,因時制宜,不一樣場景特性每每會採用其下最適宜的。好比在Android OS中的Zygote進程的IPC採用的是Socket(套接字)機制,Android中的Kill Process採用的signal(信號)機制等等。而Binder更多則用在system_server進程與上層App層的IPC交互

(5) 從公司戰略的角度

總所周知,Linux內核是開源的系統,所開放源代碼許可協議GPL保護,該協議具備「病毒式感染」的能力,怎麼理解這句話呢?受GPL保護的Linux Kernel是運行在內核空間,對於上層的任何類庫、服務、應用等運行在用戶空間,一旦進行SysCall(系統調用),調用到底層Kernel,那麼也必須遵循GPL協議。

而Android 之父 Andy Rubin對於GPL顯然是不能接受的,爲此,Google巧妙地將GPL協議控制在內核空間,將用戶空間的協議採用Apache-2.0協議(容許基於Android的開發商不向社區反饋源碼),同時在GPL協議與Apache-2.0之間的Lib庫中採用BSD證受權方法,有效隔斷了GPL的傳染性,仍有較大爭議,但至少目前緩解Android,讓GPL止步於內核空間,這是Google在GPL Linux下 開源與商業化共存的一個成功典範。

綜合上述5點,可知Binder是Android系統上層進程間通訊的不二選擇。

3、Binder通訊原理與機制

 Linux將空間分爲內核空間和用戶空間,Linux 操做系統和驅動程序運行在內核空間,用戶運用程序(用戶進程)運行在用戶空間。兩個不一樣的用戶進程之間不能夠直接訪問,而用戶空間能夠經過System calls(系統回調)與內核空間通訊的,若是在內核空間中有一個模塊,可以完成數據的轉發,那麼兩個進程就能夠通訊了。Binder是基於C/S架構的,即指客戶端(Client)和服務端(Server)組成的架構,Client端有什麼需求,直接發送給Server端去完成,以下圖所示:

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

Binder Client是請求服務的進程;Binder Server是提供服務的進程;Binder驅動承載進程間通訊的數據轉發;ServiceManager維護映射關係表,都有哪些服務,每一個都是什麼、有什麼方法可調用。ServiceManager、Binder Client、Binder Server處於不一樣的進程,他們三個都在用戶空間,而Binder驅動在內核空間。

下面咱們以一個案例來大體說明Binder的通訊過程,案例:Client A進程調用Server B進程的computer對象的add方法。

1,Server進程向ServiceManager註冊,告訴ServiceManager我是誰,我有什麼,我能作什麼。就比如Server B進程有一個computer對象,這個computer對象有個add方法,這時映射關係表就生成了。

2,Client A進程向ServiceManager查詢,我要調用Server B進程的computer對象的add方法,因爲Binder Client和ServiceManager處於不一樣的進程,因此這個過程也要通過Binder驅動,這時候Binder驅動就開始發揮他的做用了。當向ServiceManager查詢完畢,Binder驅動將computer對象轉換成了computerProxy對象,並轉發給了Client A進程,所以,Client A進程拿到的並非真實的computer對象,而是一個代理對象,即computerProxy對象。

3,當Client A進程調用add方法,這個消息發送給Binder驅動,這時驅動發現,原來是computerProxy,那麼Client A進程應該是須要調用computer對象的add方法的,這時驅動通知Server B進程,調用你的computer對象的add方法,將結果給我。而後Server B進程就將計算結果發送給驅動,驅動再轉發給Client A進程,這時Client進程還蒙在了鼓裏,他覺得本身調用的是真實的computer對象的add方法,其實他只是調用了代理而已,不過Client最終仍是拿到了計算結果。這裏能夠發現,Binder驅動起到了中轉的做用。

Binder的架構圖以下圖所示:

 

 

參考連接:

http://blog.csdn.net/lianghe_work/article/details/47707667

https://blog.csdn.net/zhu2695/article/details/51148249

https://github.com/interviewandroid/AndroidInterView

相關文章
相關標籤/搜索