圖文結合:通俗易懂的Android多進程間通信--binder機制
一丶Android多進程通信的應用場景?
?;?/p>
webview
加載圖片
push
推送與系統服務通信
部分參考,包含Framework專題:
1.騰訊Android開發(fā)筆記
2.2022年Android十一位大廠面試真題
3.60道音視頻經典面試題
二丶為什么要用binder
Android系統內核是
Linux
內核Linux
內核進程通信有:管道、內存共享、Socket
、File
;對比:

Binder
的一次拷貝發(fā)生在用戶空間拷貝到內核空間;
用戶空間:?App
進程運行的內存空間;
內核空間:?系統驅動、和硬件相關的代碼運行的內存空間,也就是進程ID為0的進程運行的空間;
程序局部性原則:?只加載少量代碼;應用沒有運行的代碼放在磁盤中,運行時高速緩沖區(qū)進行加載要運行的代碼;默認一次加載一個頁(4K),若不夠4K就用0補齊;
MMU
:內存管理單元;
給CPU
提供虛擬地址;
當對變量操作賦值時:
CPU
拿著虛擬地址和值給到MMU
MMU
用虛擬地址匹配到物理地址,MMU
去物理內存中進行賦值;
物理地址:?物理內存的實際地址,并不是磁盤;
虛擬地址:?MMU
根據物理內存的實際地址翻譯出的虛擬地址;提供給CPU
使用;


頁命中:CPU
讀取變量時,MMU
在物理內存的頁表中找到了這個地址;
頁未命中:CPU
讀取變量時,MMU
在物理內存的頁表中沒有找到了這個地址,此時會觸發(fā)MMU
去磁盤讀取變量并存到物理內存中;
普通的二次拷貝:
應用A拷貝到服務端:coay_from_user
從服務端拷貝到應用B:coay_to_user
mmap():
在物理內存中開辟一段固定大小的內存空間
將磁盤文件與物理內存進行映射(理解為綁定)
MMU
將物理內存地址轉換為虛擬地址給到CPU
(虛擬地址映射物理內存)
共享內存進程通信:
進程A調用
mmap()
函數會在內核空間中虛擬地址和一塊同樣大小的物理內存,將兩者進行映射得到一個虛擬地址
進程B調用
mmap()
函數,傳參和步驟1一樣的話,就會得到一個和步驟2相同的虛擬地址進程A和進程B都可以用同一虛擬地址對同一塊映射內存進行操作
進程A和進程B就實現了通信
沒有發(fā)生拷貝,共享一塊內存,不安全
Binder通信原理:
角色:Server端A、Client端B、Binder驅動、內核空間、物理內存
Binder驅動在物理內存中開辟一塊固定大?。?M-8K)的物理內存w,與內核空間的虛擬地址x進行映射得到
A的用戶空間的虛擬地址ax和物理內存w進行映射
此時內核空間虛擬地址x和物理內存w已經進行了映射,物理內存w和Server端A的用戶空間虛擬地址ax進行了映射:也就是 內核空間的虛擬地址x = 物理內存w = Server端A的用戶空間虛擬地址ax
B發(fā)送請求:將數據按照binder協議進行打包給到Binder驅動,Binder驅動調用
coay_from_user()
將數據拷貝到內核空間的虛擬地址x因步驟3中的三塊區(qū)域進行了映射
Server端A就得到了Client端B發(fā)送的數據
通過內存映射關系,只發(fā)生了一次拷貝

Activity
跳轉時,最多攜帶1M-8k(1兆減去8K)的數據量;
真實數據大小為:1M內存-兩頁的請求頭數據=1M-8K;
應用A直接將數據拷貝到應用B的物理內存空間中,數據量不能超過1M-8K;拷貝次數少了一次,少了從服務端拷貝到用戶;
IPC通信機制:
服務注冊
服務發(fā)現
服務調用
以下為簡單的主進程和子進程通信:
1、服務注冊: 緩存中心中有三張表(暫時理解為三個HashMap
,Binder
用的是native
的紅黑樹):
第一種:放
key
?:String - value
:類的Class
;第二種:放
key
?:Class
的類名 - value:類的方法集合;第三種:放
key
?:Class
的類名 - value:類的對象;
類的方法集合:key-value
;
key:方法簽名:“方法名” 有參數時用 “方法名-參數類型-參數類型-參數類型......”;
value
: 方法本身;
注冊后,服務若沒被調用則一直處于沉默狀態(tài),不會占用內存,這種情況只是指用戶進程里自己創(chuàng)建的服務,不適用于AMS這種;
2、服務發(fā)現: 當被查詢到時,要被初始化;
客戶端B通過發(fā)送信息到服務端A
服務端解析消息,反序列化
通過反射得到消息里的類名,方法,從注冊時的第一種、第二種表里找到Class,若對象沒初始化則初始化對象,并將對象添加到第三種的表里;
3、服務調用:
使用了動態(tài)代理
客戶端在服務發(fā)現時,拿到對象(其實是代理)
客戶端調用對象方法
代理發(fā)送序列化數據到服務端A
服務端A解析消息,反序列化,得到方法進行處理,得到序列化數據結果
將序列化結果寫入到客戶端進程的容器中;
回調給客戶端
AIDL
:?BpBinder
:數據發(fā)送角色 BbBinder:數據接收角色

編譯器生成的AIDL
的java接口.Stub.proxy.transact()
為數據發(fā)送處;
發(fā)送的數據包含:數據+方法code+方法參數等等;
發(fā)送時調用了
Linux
的驅動調用
copy_from_user()
拷貝用戶發(fā)送的數據到內核空間拷貝成功后又進行了一次請求頭的拷貝:
copy_from_user()
也就是把一次的數據分為兩次拷貝
請求頭:包含了目的進程、大小等等參數,這些參數占了8K
編譯器生成的AIDL
的java接口.Stub.onTransact()
為數據接收處;
Binder
中的IPC
機制:
每個App進程啟動時會在內核空間中映射一塊1M-8K的內存
服務端A的服務注冊到
ServiceManager
中:服務注冊客戶端B想要調用服務端A的服務,就去請求
ServiceManager
ServiceManager
去讓服務端A實例化服務:服務發(fā)現返回一個用來發(fā)送數據的對象
BpBinder
給到客戶端B客戶端B通過
BpBinder
發(fā)送數據到服務端A的內核的映射區(qū)域(傳參時客戶端會傳一個reply序列化對象,在底層會將這個地址一層一層往下傳,直至傳到回調客戶端):這里發(fā)生了一次通信copy_from_user
:服務調用服務端A通過
BBBinder
得到數據并處理數據服務端喚醒客戶端等待的線程;將返回結果寫入到客戶端發(fā)送請求時傳的一個
reply
容器地址中,調用onTransact
返回;客戶端在
onTransac
中得到數據;通信結束;
ServiceManager
維持了Binder
這套通信框架;
三丶APP多進程的優(yōu)點
擴大應用可使用的內存
手機內存6G,系統分配給虛擬機的內存一般32M、48M、64M,使用多進程時,可以使用一個進程專門加載圖片,防止OOM
。子進程崩潰,不會導致主進程崩潰
互相保活,即如果子進程被系統kill掉時,主進程拉起子進程。主進程被系統kill掉時,子進程拉起主進程。
四丶多進程通信原理

Android進程是運行在系統分配的虛擬地址空間,虛擬地址空間分為用戶空間和內核空間。多進程間,用戶空間不共享,內核空間共享,進程間通過共享的內核空間通信。
五丶多進程通信有哪些方式?
1.傳統的IPC
方式:socket
,內存共享。
2.Android特有的方式:Binder
。
六丶Binder
相對其他IPC
方式優(yōu)點/為什么使用Binder
?

1.性能:
A.Socket
傳輸數據的過程:兩次拷貝

B.Binder
傳輸數據的過程:一次拷貝

內存映射:MMAP
(memory map
)
虛擬內存和物理內存
虛擬內存映射到物理內存,物理內存存儲數據。
2.易用性
3.安全性
七丶Binder在Android系統CS通信機制中起到的作用
Android C/S
通信機制

Binder
機制的關鍵概念

Binder
在Android CS
通信機制中起到的作用




AIDL
和Binder
的關系?AIDL
封裝了Binder
,AIDL
調用Binder
部分參考,包含Framework專題:
1.騰訊Android開發(fā)筆記
2.2022年Android十一位大廠面試真題
3.60道音視頻經典面試題