Binder總結篇1-Binder原理

黎偉傑發表於2018-08-13

Binder總結篇1-Binder原理

需要學會Binder的基本使用和原理,需要的知識點有:

  1. Linux程式和空間的概念

  2. 虛擬地址概念

  3. 常用IPC,他們的基本流程和Binder的區別

  4. C/S架構基本思路,也就是Binder驅動,ServerManager,Client和Server這四個概念。

  5. AIDL以及支援的資料型別,包括Parcelable等,以及編寫

  6. Service(Android的四大元件之一),Binder等幾個具體的java類使用。

以下是自己的一些Binder學習總結,如有侵權請聯絡刪除。

Linux的程式和空間的概念

在Linux系統中,程式是分配給應用程式執行的最小描述,即一個應用程式最少有一個程式,而一個程式之間又最少有一個執行緒,程式給應用程式分配記憶體空間。

空間:在Linux中,為了保持系統的穩定性,分為核心空間和使用者空間,核心空間的許可權最高,使用者空間的許可權最低。比如讀寫檔案,網路請求就是在核心空間中進行的。

在Linux中,存在著程式隔離,也就是程式A無法直接訪問程式B的資料,他們之間各自具有獨立的記憶體。假如他們需要進行通訊,就必須通過IPC來實現,主要是通過兩個方法:copy_from_usercopy_to_user

虛擬地址

在給應用程式分配記憶體的時候,對於應用程式來說,他是一片連續的記憶體空間,但是實際上,這些記憶體空間對映到具體的實體記憶體中是碎片化的不連續的,這個在應用程式看來是連續的空間就是通過虛擬地址實現的。通過虛擬地址,讓應用程式看似擁有連續的記憶體空間,從而對映到具體的實體記憶體中。

比如,在32位系統中,可以定址的空間長度是2的32次方,也就是4GB。

傳統IPC

包括:

  1. 共享記憶體

  2. 訊息管道

  3. Socket

  4. 訊號量

這些是常用的IPC方法,一般而言,他們會經歷兩次的資料copy,共享記憶體除外。

第一次是傳送方將資料通過copy_from_user拷貝到核心空間中,這是第一次。然後,接收方在自己的記憶體空間中,分配快取區,通過copy_to_user方法把核心空間的資料複製到自己進行讀取。

如下圖:

Binder總結篇1-Binder原理

對於Android系統而言,上面的幾種方式都不太適合,首先對於兩次的資料拷貝,存在的問題是:

  1. copy次數多耗費時間

  2. 接收方不知道需要分配多大的記憶體接受資料,或者是需要提前通知接受方分配而耗費時間。

對於共享記憶體,雖然它無需copy但是較為難以控制,安全性方面較差。

那麼Binder在這方面具有什麼優勢呢?

  1. Binder是隻需要一次資料copy,僅低於共享記憶體。

  2. 他基於C/S架構,職責分離又相互獨立,穩定性更好。

  3. 在安全性方面,傳統的IPC接收方無法獲取對方可靠的程式PId,從而無法鑑別對方身份。但是在Android中,他會為每一個安裝好的App分配一個自己的UID,從而做到可以鑑別身份。

所以Binder是Android系統進行IPC採用的手段。那麼Binder為什麼只是可以一次資料拷貝就行了呢?

這個就是利用虛擬記憶體了。Binder藉助記憶體對映,在核心空間和接收方的使用者空間的資料快取區做了一層記憶體對映。也就是說,在傳送方將資料拷貝到記憶體空間的時候,核心空間的這部分地址同時也會被對映到接收方的記憶體快取中,這樣子,就少了一次從內和空間拷貝到使用者空間。

如下圖:

Binder總結篇1-Binder原理

Binder 的通訊原理

在Binder中,有四個概念,Binder驅動,ServerManager,Client以及Server,這四個部分組成了BinderC/S架構。

他跟一次網路請求很相似:Client通過域名發起請求,通過DNS域名解析器解析具體的ip地址,然後再通過路由轉發到具體的Server,再然後Server將請求結果通過路由轉發回Client。

在Binder的IPC中,有如下幾個部分:

  1. Binder驅動

Binder驅動是一種虛擬的字元裝置,註冊在/dev/bindr中,其中定義了一套Binder通訊協議,負責建立程式間Binder通訊,提供了資料包在程式之間傳遞的底層支援。

他的角色類似路由,他是提供程式間通訊的底層支援。負責將Client端的請求轉發到Server,並將Server的資料返回給Client。

2 ServerManager

他的作用類似DNS伺服器,負責將Client請求的Server的Binder描述轉化為具體的Server地址,以便Binder驅動將Client的請求轉達到Server。當Server需要提供服務的時候,他必須先向ServerManager註冊,這樣子,ServerManager中,就存有一份類似key-value的資料,儲存了一份Server的Binder字元名稱和Binder引用的對映以便Client可以找到。

  1. Client

Client的作用是發起請求,通過Binder向ServerManager發起請求獲取Server的具體地址,然後交由Binder驅動轉發。

  1. Server

Server假如需要對外提供服務,他就需要先將自己註冊到ServerManager中,以便被解析出來。Server在響應請求之後,就將資料通過Binder驅動再次將資料傳遞會Client。

這就是一次完整的IPC呼叫。

還有一個問題就是ServerManager的產生,因為Client/Server都是需要通過Binder與ServerManager進行通訊的,那麼這個ServerManager是如何產生的呢?

  1. 在Android系統啟動之後,會建立一個名詞為servermanager的程式,可以檢視ZygoteInit檔案,在裡面的main方法中,呼叫ZygoteforkSystemServer產生。它通過一個約定的命令BINDERSERVER_MGR向Binder驅動註冊,申請成為ServerManager。Binder驅動會自動為ServerManager建立一個Binder實體

  2. 這個Binder實體的引用在所有的Client中都是0,也就是說各個Client通過0這個引用就可以與ServerManager進行通訊。

Binder的代理機制

上面是我們的IPC過程,在這個過程中,Client需要獲取到Server端的Binder引用,那麼這個引用是真正的Server引用嗎,他是如何實現的呢,A程式並無法直接獲取B程式的物件。這個就是需要通過Binder的代理機制實現。

我們在Client端,向ServerManager獲取具體的Server端的Binder引用的時候,會首先進過Binder驅動,Binder驅動它並不會把真正的Server的Bind人引用返回給Client端,而是返回一個代理的java物件,該物件具有跟Server端的Binder引用相同的方法簽名,這個物件為ProxyObject,他具有跟Server的Binder例項一樣的方法,只是這些方法並沒有Server端的能力,這個ProxyObject的能力是可以通過Binder驅動,正在實現對Server的Binder進行呼叫,從而完成資料傳遞。

比如,當Binder驅動接受到Client程式的請求,就去ServerManager中查詢,在ServerManager中查詢到具體的Server具體之後,就建立一個Server端的Binder物件的ProxyObject,並且將該ProxyObject返回給Client 。然後Client就通過ProxyObject呼叫其中的方法,ProxyObject的方法再去呼叫Binder驅動,這個Binder驅動就去Server程式中,呼叫具體的Server程式的具體的Binder物件的方法,然後再通過Binder驅動返回資料給Client。

如下圖

Binder總結篇1-Binder原理

AIDL

上面我們大概梳理了Binder呼叫的整體流程,知道Binder的大概原理。在Android中,是通過AIDL這一描述性介面語言實現的。

什麼是AIDL:Android 介面定義語言 (AIDL)

關於如何使用AIDL將在下一篇文章在做詳細使用。

參考文章

關於Binder,作為應用開發者你需要知道的全部(同時也是本文的文章圖片來源)

為什麼Android要採用Binder作為IPC機制

Binder系列-開篇

Android 跨程式通訊:圖文詳解Binder機制原理

寫給 Android 應用工程師的 Binder 原理剖析

相關文章