標籤:
從這篇部落格開始,將進入Binder機制的分析系列,順序是先講解Binder機制的架構,理解了整體思想後,再深入分析各層的細節實現,最後會實現一個自己的本地服務。
1.Binder的曆史
BeOS是Be公司在1991年開發的運行在BeBOX硬體上的一款作業系統,與同期的其他動作系統不同,它是一款基於GUI設計的作業系統。
George Hoffman(在LinkedIn上可以找到這哥們,簡直是活著的傳奇)當時任Be公司的工程師,他啟動了一個名為OpenBinder的項目,該項目的宗旨是研究一個高效的訊號傳遞工具,允許軟體的各個構成元素相互傳遞訊號,從而使多個軟體相互協作,共同形成一個軟體系統。在Be公司被ParmSource公司收購後,OpenBinder由Dinnie Hackborn繼續開發,後來成為管理ParmOS6 Cobalt OS的進程的基礎。在Hackborn加入Google後,他在OpenBinder的基礎上開發出了Android Binder(以下簡稱Binder),用來完成Android的進程通訊。
Binder原本是IPC(Inter Process Communication)工具,但在Android中它主要用於支援RPC(Remote Procedure Call,遠程調用),使得當前進程調用另一個進程的函數時就像調用自身的函數一樣輕鬆、簡單。
2.Linux記憶體空間與Binder Driver
Android是基於Linux核心的操作平台,Android進程與Linux進程一樣,它們只運行在進程固有的虛擬位址空間中。一個4GB的虛擬位址空間,其中3GB是使用者空間,剩餘的1G是核心空間(可通過核心設定修改).使用者代碼與相關庫分別運行在使用者空間的代碼地區、資料區域,以及堆棧地區中,而核心空間中啟動並執行代碼則運行在核心空間的各個地區中。並且,進程具有各自獨立的地址空間,單獨運行。
那麼,一個擁有獨立空間的進程如何向另一個進程傳遞資料呢?顯然要通過兩個進程共用的核心空間。雖然各個進程擁有各自獨立的使用者空間,但核心空間是共用的。從核心的角度看,進程不過是一個作業單位,雖然各進程的使用者空間相互獨立,但運行在核心空間中的任務資料、代碼都是彼此共用的。
事實上,Binder機制的架構如下所示:
下面是對各抽象層的說明:
- 服務層:該層包含一系列提供特定功能的服務函數。服務用戶端實際上調用的是代理服務物件的服務函數,而實際調用是由Service Server進行的,即Service Server實際調用服務用戶端請求的服務函數。
- RPC層:服務用戶端在該層產生用於調用服務函數的RPC代碼與RPC資料。Service Server會根據傳遞過來的RPC代碼尋找相應的函數,並將RPC資料傳遞給尋找到的函數。
- IPC層:該層將RPC層產生的RPC代碼與RPC資料封裝成Binder IPC資料,以便它們傳遞給Binder Driver;
- Binder Driver層:接收來自IPC層的Binder IPC資料,尋找包含指定服務的Service Server,並將資料傳遞給尋找到的Service Server.
3.為什麼採用Binder機制實現IPC
學過Linux的同學都知道,在Linux中,已經有管道,訊息佇列,共用記憶體,訊號量,Socket等IPC通訊機制,為什麼Google選擇了Binder,而不使用原有的IPC機制呢?
主要是以下幾方面的原因:
1) Binder的傳輸效率和可操作性很好
Socket由於傳輸效率太低,所以被排除。而訊息佇列和管道又採用儲存-轉寄的方式,使用它們進行IPC通訊時,需要經過2次記憶體拷貝,效率太低。
為什麼訊息佇列和管道的資料轉送需要經過2次記憶體拷貝呢?首先,資料先從發送方的緩衝區(即Linux中的使用者儲存空間)拷貝到記憶體開闢的緩衝區(即Linux核心儲存空間)中,是第1次拷貝。接著,再從核心緩衝區拷貝到接收方的緩衝區(也是Linux中的使用者儲存空間),這是第2次拷貝。
而採用Binder機制的話,則只需要進行1次拷貝即可,因為從發送方的緩衝區拷貝到核心的緩衝區,而接收方的緩衝區與核心的緩衝區是映射到同一塊物理地址的,因此只需要1次拷貝即可。
而共用記憶體方式,雖然使用它進行IPC通訊時進行的記憶體拷貝次數是0,但是由於操作複雜,故沒有採用。
2)Binder機制能夠很好地實現Client-Server架構
對於Android系統,Google想提供一套基於Client-Server的通訊方式。
例如,將MediaPlayer Service, Camera Service等不同的服務都由不同的Server提供,當Client需要擷取某個Server的服務時,只需要Client向Server發送相應的請求,Server收到請求之後進行處理,處理完畢後再將反饋內容發送給Client.
但是,目前Linux支援的管道,訊息佇列,共用記憶體,訊號量,Socket等IPC手段中,只有Socket是Client-Server的通訊方式 。但是Socket主要用於網路間通訊以及本機中進程間的低速通訊,它的傳輸效率太低,並不適合高速IPC通訊。
3)Binder機制的安全性高
傳統的Linux IPC機制沒有任何安全措施,完全依賴上層協議來確保。傳統IPC的接收方無法獲得對方進程可靠的UID/PID,從而無法鑒別對方身份。而Binder機制則為每個進程分配了UID/PID來作為鑒別身份的標示,並且在Binder通訊時會根據UID/PID進行有效性檢測。
4.UML圖
Binder機制涉及到代理類、Stub類,以及與Binder Driver對話的IPCThreadState類則,整體的UML圖如下所示:
IBinder、BBinder、BpBinder:IBinder類是對Android Binder的抽象,它有BBinder、BpBinder兩個子。其中BBinder類負責接收RPC代碼與資料,並在Binder Driver內部產生Binder節點。BpBinder類儲存著目標服務的Handle資訊,用於Binder Driver尋找Service Server的Binder節點的過程中;
IInterface、BnInterface、BpInterface:IInterface類提供類型變換功能,將服務或服務代理類轉換為IBinder類型。實際的類型轉換是由BnInterface、BpInterface兩個類完成,BnInterface將服務類轉換成IBinder類型,BpInterface則將服務代理類轉換成IBinder類型。在通過Binder Driver傳遞Binder對象時,必須進行類型轉換,比如在向系統註冊服務時,需要先將服務類轉換成IBinder,再將其轉遞給Context Manager.
ProcessState、IPCThreadState: ProcessState類用來管理Binder Driver,IPCThreadState類用來支援服務用戶端、Service Server與Binder Driver間的Binder IPC通訊;
Parcel: 在服務與服務代理間進行BinderIPC時,Parcel類負責儲存Binder IPC資料。Parcel類可以處理的資料有C語言的基本資料結構、基本資料結構數組、Binder對象、檔案描述符等。
Service Manager與Context Manager
在Android系統中存在著各種各樣的服務,如管理音訊裝置的Audio Flinger服務、管理幀緩衝裝置的Surface Flinger服務,還有管理相機裝置的Camera服務等。這些服務的資訊與目錄都是由Context Manager負責管理的。
而Service Manager則相當於Context Manager的服務代理。需要注意的是,Service Manager分為管理Java系統服務的Service Manager和管理本地系統服務的Service Manager.很好地表示了它們的關係:
- Java系統服務通過Java層的Service Manager註冊服務,本地系統服務通過C/C++層的Service Manager註冊服務 ;
- Java層的Service Manager通過JNI與C/C++層的Service Manager串連在一起,C/C++層的Service Manager通過Binder Driver與Context Manager進行Binder RPC;
6.核心空間的重要結構體
核心空間的Binder設計有3個非常重要的結構體:binder_proc, binder_node和binder_ref.在後面會有Blog專門分析它們,這裡只是簡要說一下它們的作用。 它們的作用如下:
- binder_proc是描述進程上下文資訊的,每一個使用者空間的進程都對應一個binder_proc結構體
- binder_node是Binder實體對應的結構體,它是Server在Binder驅動中的體現
- binder_ref是Binder引用對應的結構體,它是Client在Binder驅動中的體現
1)Binder實體紅/黑樹狀結構是儲存binder_proc對應的進程所包含的Binder實體的,而Binder實體是與Server的服務對應的。可以將Binder實體紅/黑樹狀結構理解為Server進程中包含的Server服務的紅/黑樹狀結構;
2)中有兩棵Binder引用紅/黑樹狀結構,這兩棵樹所包含的Binder引用都是一樣的。不同的是,紅/黑樹狀結構的排序基準不同,一個是以Binder實體來排序,而另一個則是以Binder引用描述(Binder引用描述實際上就是一個32位的整型數)來排序。以Binder引用描述的紅/黑樹狀結構是為了方便進行快速尋找。
是binder_node結構體的:
Android Binder機制(1):Binder架構分析