1. 程式人生 > >Android 的 Binder 機制概念介紹

Android 的 Binder 機制概念介紹

 結合了以下兩篇文章的介紹,對Android 的 Binder 機制概念開始有了一定的理解。分享給大家。

-------------------------------------分割線---------------------------------

摘要

Binder是android 中一個很重要且很複雜的概念,它在系統的整體運作中發揮著極其重要的作用,不過本文並不打算從深層次分析Binder機制,有兩點原因:1是目前網上已經 有2篇很好的文章了,2是對Binder機制進行深入底層乃至驅動的分析這一過程相當困難且相當耗時,因此並不適合重複造輪子。本文的角度是對 Android的Binder機制從整體和概念上進行分析,能夠讓大家很快明白到底什麼是Binder,Binder是幹什麼的,Binder和應用開發 的關係是什麼,總之,這篇文章還是很值得去看一看的。

什麼是Binder

1. 直觀來說,Binder是Android中的一個類,它繼承了IBinder介面

2. 從IPC角度來說,Binder是Android中的一種跨程序通訊方式,Binder還可以理解為一種虛擬的物理裝置,它的裝置驅動是/dev/binder,該通訊方式在linux中沒有

3. 從Android Framework角度來說,Binder是ServiceManager連線各種Manager(ActivityManager、WindowManager,etc)和相應ManagerService的橋樑

4. 從Android應用層來說,Binder是客戶端和服務端進行通訊的媒介,當你bindService的時候,服務端會返回一個包含了服務端業務呼叫的 Binder物件,通過這個Binder物件,客戶端就可以獲取服務端提供的服務或者資料,這裡的服務包括普通服務和基於AIDL的服務

為什麼Android核心要使用Binder

Android中有大量的CS(Client-Server)應用方式,這就要求Android內部提供IPC方法,而linux所支援的程序通訊方式有兩個問題:效能和安全性。


目 前linux支援的IPC包括傳統的管道,System V IPC(訊息佇列/共享記憶體/訊號量),以及socket,但只有socket支援Client-Server的通訊方式,由於socket是一套通用的 網路通訊方式,其傳輸效率低下切有很大的開銷,比如socket的連線建立過程和中斷連線過程都是有一定開銷的。訊息佇列和管道採用儲存-轉發方式,即數 據先從傳送方快取區拷貝到核心開闢的快取區中,然後再從核心快取區拷貝到接收方快取區,至少有兩次拷貝過程。共享記憶體雖然無需拷貝,但控制複雜,難以使 用。


在安全性方 面,Android作為一個開放式,擁有眾多開發者的的平臺,應用程式的來源廣泛,確保智慧終端的安全是非常重要的。終端使用者不希望從網上下載的程式在不 知情的情況下偷窺隱私資料,連線無線網路,長期操作底層裝置導致電池很快耗盡等等。傳統IPC沒有任何安全措施,完全依賴上層協議來確保。首先傳統IPC 的接收方無法獲得對方程序可靠的UID/PID(使用者ID/程序ID),從而無法鑑別對方身份。Android為每個安裝好的應用程式分配了自己的 UID,故程序的UID是鑑別程序身份的重要標誌。使用傳統IPC只能由使用者在資料包裡填入UID/PID,但這樣不可靠,容易被惡意程式利用。可靠的身 份標記只有由IPC機制本身在核心中新增。其次傳統IPC訪問接入點是開放的,無法建立私有通道。比如命名管道的名稱,system V的鍵值,socket的ip地址或檔名都是開放的,只要知道這些接入點的程式都可以和對端建立連線,不管怎樣都無法阻止惡意程式通過猜測接收方地址獲 得連線。


基於以上原 因,Android需要建立一套新的IPC機制來滿足系統對通訊方式,傳輸效能和安全性的要求,這就是Binder。Binder基於 Client-Server通訊模式,傳輸過程只需一次拷貝,為傳送發新增UID/PID身份,既支援實名Binder也支援匿名Binder,安全性 高。下圖為Binder通訊過程示例:

---------------------分割線----------------------------

1.Binder通訊機制介紹

這篇文章會先對比Binder機制與Linux的通訊機制的差別,瞭解為什麼Android會另起爐灶,採用Binder。接著,會根據 Binder的機制,去理解什麼是Service  Manager,在C/S模型中扮演什麼角色。最後,會從一次完整的通訊活動中,去理解Binder通訊的過程。

1.1 Android與Linux通訊機制的比較

雖然Android繼承使用Linux的核心,但Linux與Android的通訊機制不同。

在Linux中使用的IPC通訊機制如下:

  1. 傳統IPC:無名pipe, signal, trace, 有名管道

  2. AT&T Unix 系統V:共享記憶體,訊號燈,訊息佇列

  3. BSD Unix:Socket

而在Android中,並沒有使用這些,取而代之的是Binder機制。Binder機制是採用OpenBinder演化而來,在Android中使用它的原因如下:

  1. 採用C/S的通訊模式。而在linux通訊機制中,目前只有socket支援C/S的通訊模式,但socket有其劣勢,具體參看第二條。

  2. 有更好的傳輸效能。對比於Linux的通訊機制,

    • socket:是一個通用介面,導致其傳輸效率低,開銷大;

    • 管道和訊息佇列:因為採用儲存轉發方式,所以至少需要拷貝2次資料,效率低;

    • 共享記憶體:雖然在傳輸時沒有拷貝資料,但其控制機制複雜(比如跨程序通訊時,需獲取對方程序的pid,得多種機制協同操作)。

  3. 安全性更高。Linux的IPC機制在本身的實現中,並沒有安全措施,得依賴上層協議來進行安全控制。而Binder機制的 UID/PID是由Binder機制本身在核心空間新增身份標識,安全性高;並且Binder可以建立私有通道,這是linux的通訊機制所無法實現的 (Linux訪問的接入點是開放的)。

綜上所述,Android採用Binder機制是有道理的。既然Binder機制這麼多優點,那麼我們接下來看看它是怎樣通過C/S模型來實現的。

1.2Binder在Service服務中的作用

在android中,有很多Service都是通過binder來通訊的,比如MediaServer旗下包含了眾多service:

  •     AudioFlinger 音訊核心服務

  •     AudioPolicyService:音訊策略相關的重要服務

  •     MediaPlayerService:多媒體系統中的重要服務

  •     CameraService:有關攝像/照相的重要服務

Binder在C/S中的流程如下:

  1. Server註冊服務。Server作為眾多Service的擁有者,當它想向Client提供服務時,得先去Service Manager(以後縮寫成SM)那兒註冊自己的服務。Server可以向SM註冊一個或多個服務。

  2. Client申請服務。Client作為Service的使用者,當它想使用服務時,得向SM申請自己所需要的服務。Client可以申請一個或多個服務。

  3. 當Client申請服務成功後,Client就可以使用服務了。

SM一方面管理Server所提供的服務,同時又響應Client的請求併為之分配相應的服務。扮演的角色相當於月老,兩邊牽線。這種通訊方式的好處是: 一方面,service和Client請求便於管理,另一方面在應用程式開發時,只需為Client建立到Server的連線,就可花很少時間和精力去實 現Server相應功能。那麼,Binder與這個通訊模式有什麼關係呢?!其實,3者的通訊方式就是Binder機制(例如:Server向SM註冊服 務,使用Binder通訊;Client申請請求,用的是Binder通訊)

1.3Binder通訊機制流程(整體框架)

上圖即是Binder的通訊模型。我們可以發現:

  1. Client和Server是存在於使用者空間

  2. Client與Server通訊的實現,是由Binder驅動在核心空間實現

  3. SM作為守護程序,處理客戶端請求,管理所有服務項。

為了方便理解,我們可以把SM理解成DNS伺服器; 那麼Binder Driver 就相當於路由的功能。這裡就涉及到Client和Server是如何通訊的問題。下面對1.2中提到的3個流程進行說明。

1.3.1 Server向SM註冊服務

  1. 首先,XXXServer(XXX代表某個)在自己的程序中向Binder驅動申請建立一個XXXService的Binder的實體,

  2. Binder驅動為這個XXXService建立位於核心中的Binder實體節點以及Binder的引用,注意,是將名字和新建的引用打包傳遞給SM(實體沒有傳給SM),通知SM註冊一個名叫XXX的Service。

  3. SM收到資料包後,從中取出XXXService名字和引用,填入一張查詢表中。

  4. 此時,如果有Client向SM傳送申請服務XXXService的請求,那麼SM就可以在查詢表中找到該Service的Binder引用,並把Binder引用(XXXBpBinder)返回給Client。

在進一步瞭解Binder通訊機制之前,我們先弄清幾個概念。

  1. 引用和實體。這裡,對於一個用於通訊的實體(可以理解成具有真實空間的Object),可以有多個該實體的引用(沒有真實空間,可以理解成實體的 一個連結,操作引用就會操作對應連結上的實體)。如果一個程序持有某個實體,其他程序也想操作該實體,最高效的做法是去獲得該實體的引用,再去操作這個引 用。

  2. 有些資料把實體稱為本地物件,引用成為遠端物件。可以這麼理解:引用是從本地程序傳送給其他程序來操作實體之用,所以有本地和遠端物件之名。

1.3.2 一個問題-如何獲得SM的遠端介面

如果你足夠細心,會發現這裡有一個問題:

Sm和Server都是程序,Server向SM註冊Binder需要程序間通訊,當前實現的是程序間通訊卻又用到程序間通訊。這就好比雞生蛋、蛋生雞,但至少得先有其中之一。

巧妙的Binder解決思路:

針對Binder的通訊機制,Server端擁有的是Binder的實體;Client端擁有的是Binder的引用。
如果把SM看作Server端,讓它在Binder驅動一執行起來時就有自己的Binder實體(程式碼中設定ServiceManager的Binder 其handle值恆為0)。這個Binder實體沒有名字也不需要註冊,所有的client都認為handle值為0的binder引用是用來與SM通訊 的(程式碼中是這麼實現的),那麼這個問題就解決了。那麼,Client和Server中這麼達成協議了(handle值為0的引用是專門與SM通訊之用 的),還不行,還需要讓SM有handle值為0的實體才算大功告成。怎麼實現的呢?!當一個程序呼叫Binder驅動時,使用 BINDER_SET_CONTEXT_MGR命令(在驅動的binder_ioctl中)將自己註冊成SM時,Binder驅動會自動為它建立 Binder實體。這個Binder的引用對所有的Client都為0。

1.3.3 Client從SM獲得Service的遠端介面


Server向SM註冊了Binder實體及其名字後,Client就可以通過Service的名字在SM的查詢表中獲得該Binder的引用了 (BpBinder)。Client也利用保留的handle值為0的引用向SM請求訪問某個Service:我申請訪問XXXService的引用。 SM就會從請求資料包中獲得XXXService的名字,在查詢表中找到該名字對應的條目,取出Binder的引用打包回覆給client。之 後,Client就可以利用XXXService的引用使用XXXService的服務了。
如果有更多的Client請求該Service,系統中就會有更多的Client獲得這個引用。

1.3.4建立C/S通路後

首先要理清一個概念:client擁有自己Binder的實體,以及Server的Binder的引用;Server擁有自己Binder的實體,以及Client的Binder的引用。我們也可以從接收方和傳送方的方式來理解:

  • 從client向Server發資料:Client為傳送方,擁有Binder的實體;Server為接收方,擁有Binder的引用

  • 從server向client發資料:Server為傳送方,擁有Binder的實體;client為接收方,擁有Binder的引用。

也就是說,我們在建立了C/S通路後,無需考慮誰是Client誰是Server,只要理清誰是傳送方誰是接收方,就能知道Binder的實體和引用在哪邊。


建立CS通路後的流程:(當接收方獲得Binder的實體,傳送方獲得Binder的引用後)

  1. 傳送方會通過Binder實體請求傳送操作。

  2. Binder驅動會處理這個操作請求,把傳送方的資料放入寫快取(binder_write_read.write_buffer) (對於接收方為讀緩衝區),並把read_size(接收方讀資料)置為資料大小(對於具體的實現後面會介紹);

  3. 接收方之前一直在阻塞狀態中,當寫快取中有資料,則會讀取資料,執行命令操作

  4. 接收方執行完後,會把返回結果同樣用binder_transaction_data結構體封裝,寫入寫緩衝區(對於傳送方,為讀緩衝區)

1.3.5 匿名Binder

之前在介紹Android使用Binder機制的優點中,提到Binder可以建立點對點的私有通道,匿名Binder就是這種方式。在 Binder通訊中,並不是所有用來通訊的Binder實體都需要註冊給SM廣而告之的,Server可以通過已建立的實體Binder連線將建立的 Binder實體傳給Client。而這個Binder沒有向SM註冊名字。這樣Server與Client的通訊就有很高的隱私性和安全性。

轉自:https://my.oschina.net/Bruce370/blog/536946