本文總結:https://www.cnblogs.com/baronzhang/p/8784458.html
Binder在android中的的使用
- 在android中涉及到跨進程的應用基本都會使用到binder機制
Binder與linux傳統IPC的性能對比
- linux IPC進程:管道,內存拷貝,消息隊列,套接字等
- 性能對比
IPC進程 | 實現方式 | 內存拷貝次數| |
---|---|---|
管道 | 數據(緩存區)->內核緩衝區-緩存區 | 至少2次 |
消息隊列 | 同上 | 同上 |
共享內存 | 讀取在一塊內存中,控制困難 | 1 |
套接字 | 通過網絡傳送,收到網絡的影響 | 至少2次 |
Binder | c/s架構 職責明確 | 1 |
linux IPC通信原理
-
什麼是IPC通信
- 進程與進程之間的內存是不共享的,如果兩個進程之間需要進行數據的交互,那就要用到特殊的通信機制:就是IPC
-
如何操作
- 在linux系統中,進程空間分爲“用戶空間”和”內核空間“,這兩個空間的隔離開來的。那麼“用戶空間‘想要訪問"內核空間”就要通過“系統調度”
- 系統調度通過一下兩個函數實現:copy_from_user: 將數據從用戶空間拷到內核空間,copy_to_user: 將數據從內核空間拷到用戶空間
- 通信過程如下:通常的做法是消息發送方將要發送的數據存放在內存緩存區中,通過系統調用進入內核態。 然後內核程序在內核空間分配內存,開闢一塊內核緩存區,調用 copy_from_user()函數將數據從用戶空間的內存緩存區拷貝到內核空間的內核緩存區中。 同樣的,接收方進程在接收數據時在自己的用戶空間開闢一塊內存緩存區, 然後內核程序調用 copy_to_user() 函數將數據從內核緩存區拷貝到接收進程的內存緩存區。 這樣數據發送方進程和數據接收方進程就完成了一次數據傳輸,我們稱完成了一次進程間通信
-
存在的不足
- 性能低下,一次數據傳遞需要經歷:內存緩存區 --> 內核緩存區 --> 內存緩存區,需要 2 次數據拷貝;
- 接收數據的緩存區由數據接收進程提供,但是接收進程並不知道需要多大的空間來存放將要傳遞過來的數據,因此只能開闢儘可能大的內存空間或者先調用 API 接收消息頭來獲取消息體的大小。
- 這兩種做法不是浪費空間就是浪費時間。
Binder機制的介紹
-
Binder驅動
在android系統中也有個內核模塊在負責android各個用戶進程的通信,這個內核模塊就叫做Binder驅動,通過Linux的內核動態加載機制,加載到內核中。
-
android通過Binder驅動也是內核模塊那跟傳統的ipc有啥區別
傳統的IPC通信是:數據從用戶空間A拷貝到內核空間,接着又從內核空間拷貝到用戶空間B,如果內核空間和用戶空間B,地址是一樣,及用戶空間B就是內核空間,那拷貝到內核空間就是拷貝用戶空間B。在linux中存在這種機制,內存映射 -
內存映射:
內存映射簡單的講就是將用戶空間的一塊內存區域映射到內核空間。映射關係建立後,用戶對這塊內存區域的修改可以直接反應到內核空間;反之內核空間對這段區域的修改也能直接反應到用戶空間 -
Binder的IPC機制原理
1.首先 Binder 驅動在內核空間創建一個數據接收緩存區
2.接着在內核空間開闢一塊內核緩存區,建立內核緩存區和內核中數據接收緩存區之間的映射關係,以及內核中數據接收緩存區和接收進程用戶空間地址的映射關係
3.發送方進程通過系統調用 copy_from_user() 將數據 copy 到內核中的內核緩存區,由於內核緩存區和接收進程的用戶空間存在內存映射,因此也就相當於把數據發送到了接收進程的用戶空間,這樣便完成了一次進程間的通信 -
Binder的通信過程
- 首先,一個進程使用 BINDER_SET_CONTEXT_MGR 命令通過 Binder 驅動將自己註冊成爲 ServiceManager;
- Server 通過驅動向 ServiceManager 中註冊 Binder(Server 中的 Binder 實體),表明可以對外提供服務。驅動爲這個 Binder 創建位於內核中的實體節點以及 ServiceManager 對實體的引用,將名字以及新建的引用打包傳給 ServiceManager,ServiceManger 將其填入查找表。
- Client 通過名字,在 Binder 驅動的幫助下從 ServiceManager 中獲取到對 Binder 實體的引用,通過這個引用就能實現和 Server 進程的通信。
-
實例-AIDL
- 參考: https://blog.csdn.net/yy1090582686/article/details/84564786