1. 簡介
Binder,中文即粘合劑,意思是粘合了兩個不同的進程。從IPC角度來說,Binder是Android中的一種跨進程通信方式。
2. 基礎概念介紹
2.1 進程隔離&跨進程通信
- 進程隔離:爲了保證安全性和獨立性,一般情況下,一個進程不能直接操作或訪問另外一個進程。即Android中的進程是相互隔離,獨立的
- 進程通信:即IPC,不同進程需要進行數據的交互和通信
2.2 內核空間&用戶空間
- 一個進程空間分爲內核空間和用戶空間,即內核空間和用戶空間相隔離
- 內核空間:即Karnel Space,是Linux內核的運行空間。可以執行任何命令, 調用系統的一切資源。與用戶空間隔離,即使用戶的程序崩潰了,內核也不會受到影響。內核空間可進行進程間,進程內的交互。內核空間的數據是共享的,故內核空間=可共享空間
- 用戶空間:即User Space,是用戶程序的運行空間。只能進行簡單的操作,在用戶空間的進程不能直接交互,可以通過內核空間來進行間接交互,但是又不能直接調用系統的資源,必須通過系統接口(System Call),向內核發出命令。用戶空間的數據不共享,給用戶空間=不可共享空間
2.3 內存映射
- 定義:關聯一個虛擬內存區域和一個磁盤上的共享對象,使兩者存在映射關係
- 實現過程:通過Linux系統調用函數:mmap(),這個函數的作用就是創建虛擬內存區域,並與共享對象建立映射關係
- 特點:減少了數據拷貝的次數,並通過映射區域實現用戶空間和內核空間的交互
傳統跨進程通信需要拷貝數據兩次,Binder機制只需要1次,主要是因爲Binder機制使用到了內存映射
3. 四大角色
- Client:使用服務的進程
- Server:提供服務的進程
- ServiceManager:管理系統的Server的註冊和查詢(將字符形式的Binder名字轉化成Client對該Binder的引用)
- Binder驅動:虛擬設備驅動,連接Client,Server,ServiceManager的橋樑
3.1 Binder驅動
Binder驅動是Binder通信的核心,它工作於內核空間,提供open,mmap,ioctl等標準文件操作。驅動負責進程間Binder通信的建立。分別管理着Server端的Binder實體核Client端的引用。
4. Binder框架
- Binder通信採用C/S模式,包括四個組件:Client,Server,ServiceManager,Binder驅動。其中Client,Server,ServiceManager運行在用戶空間,Binder驅動運行在內核空間。
- Binder在Framework層進行封裝,通過JNI技術調用Native層的Binder架構
- 在Native層的Binder以ioctl,open等操作與Binder驅動通訊。
5. Binder原理及步驟
5.1 註冊服務
- Server創建Binder實體,取一個可讀易記的名字,將Binder實體連同名字以數據包的形式通過Binder驅動發送給ServiceManager,通知ServiceManger註冊這個Binder實體。在這裏Server需要通過0號引用與ServiceManager的Binder進行通訊
- Binder驅動爲這個穿越邊界的Binder實體在內核空間創建節點和ServiceManager的引用,並將名字和引用打包傳遞給ServiceManager
- ServiceManager收到數據包後,從中取出名字和引用填入查找表中
5.2 獲取服務
-
Client利用保留的0號引用向ServiceManager請求訪問某個Binder
-
ServiceManager根據請求的數據包獲取Binder名字,在查找表中找到該名字對應的Binder引用
-
將該引用作爲回覆返回給發起請求的Client
5.2 使用服務
- Client將進程參數發送到Server進程
- Binder驅動爲跨進程通信做準備,實現內存映射
- Server根據Client的參數,執行目標方法
- Server進程將目標方法的結果返回給Client進程
6. Binder機制的優點
6.1 高效
消息隊列和管道採用的是存儲-轉發方式,至少需要兩次數據拷貝過程,效率比較低。共享內存雖然無需拷貝,但控制複雜,難以使用。而Binder由於使用了內存映射,只需進行一次數據拷貝,效率高
6.2 安全性高
Binder機制爲每個進程分配了UID/PID來鑑別身份的標識,並且在Binder通信時會根據UID/PID進行有效性檢測
6.3 使用簡單,可操作性高
Binder機制採用Client/Server的通信方式,對於管道,共享內存,消息隊列以及Socket來說只有Socket採用了Client/Server的通信方式,但是Socket主要用於跨網絡的進程通信,開銷大,效率低。另外Binder機制還實現了面向對象的調用方式。
7. Android中的IPC方式
7.1 Bundle
兩個使用場景:一是直接利用傳遞數據,在Bundle中附加信息,通過Intent發送出去。二是轉移目標跨進程通信,將需要在A進程計算的任務轉移到B進程的後臺Service中執行。
7.2 文件共享
兩個進程通過讀/寫同一個文件實現交換數據。在這裏需注意的是SharePreferences,它的底層是使用Xml文件來存儲鍵值對,當使用SharePreferences時,內存中會有一份緩存,故在多進程讀寫時,就會出現數據過期的狀況,另外在高併發讀取時,很大機率會出現數據丟失,故不建議在進程通信使用Share Preferences
7.4 Messenger
輕量級IPC,其底層的實現其實是AIDL。首先來看看其工作原理圖
根據工作原理圖來分析其實現過程:
服務進程
- 創建一個Service來處理客戶端的連接請求
- Service中創建一個Handler來接受客戶端發送過來的消息,並通過這個Handler來創建一個Messenger對象,在onBind中返回Messenger對象的底層binder
客戶進程
- 首先綁定Service,綁定成功後利用Service返回的Binder對象創建一個Messenger對象
- 通過這個Messenger對象向服務端發送消息,消息類型爲Message
服務進程回覆客戶進程
- 當服務進程收到客戶進程的消息後,進行回覆時,則客戶端需在上面的基礎上創建一個Handler來接受服務端的回覆信息,並利用這個Handler對象創建Messenger對象,並把這個對象通過message的reply參數在發送信息時傳遞給服務端。
- 服務端在接受到客戶端的信息時,利用攜帶的reply參數得到Messenger對象,然後利用這個對象就可以向客戶端發送message消息類型的消息。
7.5 AIDL
大致流程
首先創建一個Service和AIDL接口,接着創建一個類並繼承AIDL接口中Stub,重寫Stub的抽象方法,在Service中的onBind返回這個類的對象,然後客戶端綁定服務端的Service,綁定成功後將返回的Binder對象轉化成AIDL接口所屬的類型,然後就可以調用接口中的方法。
難點
- 支持的數據類型
- 基本數據類型
- String和CharSequence
- List:只支持ArrayList,裏面的元素必須能夠被AIDL支持
- map:只支持HashMap,鍵值都必須能夠被AIDL支持
- Parcelable
- AIDL
- AIDL文件中使用到自定義的Parcelable對象都要新建一個和它同名的AIDL文件,只要在文件中聲明那個類爲Parcelable即可
- 自定義的Parcelable對象和AIDL對象必須都要顯示import進來
- 除基本類型外,其他類型需標上方向,in、out、inout
- AIDL接口只支持方法,不支持聲明靜態常量
7.6 ContentProvider
ContentProvider是Android中提供的專門用於不同應用間進行數據共享的方式,故它天生就適合進程間的通訊,和Messenger一樣,它的底層實現也是Binder
7.7 Socket
又稱套接字,網絡通信中的概念。主要分爲流式套接字(TCP)和用戶數據報套接字(UDP)
7.8 Android中各種IPC方式的優缺點
名稱 | 優點 | 缺點 | 適用場景 |
---|---|---|---|
Bundle | 簡單易用 | 只能傳輸Bundle支持的數據類型 | 四大組件的進程間的通信 |
文件共享 | 簡單易用 | 不適合高併發場景,無法做到即時通信 | 無併發訪問情況,交換簡單的數據實時性不高的場景 |
AIDL | 功能強大,支持一對多併發通信,支持實時通信 | 操作較複雜,需處理好線程同步 | 一對多通信,有RPC需求 |
Messenger | 支持一對多的串行通信,支持實時通信 | 不能很好處理高併發情形,不支持RPC,數據通過Message傳遞,故只能傳輸Bundle支持的數據類型 | 低併發的一對多及時需求,無RPC需求,或者無返回結果的RPC需求 |
ContentProvider | 數據訪問功能強大,支持一對多併發數據共享 | 受約束的AIDL | 一對多的進程間的數據共享 |
Socket | 功能強大,可以通過網絡傳遞字節流,支持一對多實時通信 | 實現細節繁瑣,不支持直接的RPC | 網絡數據交換 |
參考資料
一篇文章瞭解相見恨晚的 Android Binder 進程間通訊機制
《Android開發藝術探索》