【轉(zhuǎn)載地址:http://www.reibang.com/p/4ee3fd07da14】
【建議去原文地址查看,本轉(zhuǎn)載只是記錄本人學(xué)習(xí)歷程】
前言
如果你接觸過 跨進(jìn)程通信 (
IPC
)震桶,那么你對Binder
一定不陌生雖然 網(wǎng)上有很多介紹
Binder
的文章煤伟,可是存在一些問題:淺顯的討論Binder
機(jī)制 或 一味講解Binder
源碼缅叠、邏輯不清楚贰镣,最終導(dǎo)致的是讀者們還是無法形成一個(gè)完整的Binder
概念-
本文采用 清晰的圖文講解方式困檩,按照 大角度 -> 小角度 去分析
Binder
绳锅,即:先從 機(jī)制、模型的角度 去分析 整個(gè)
Binder
跨進(jìn)程通信機(jī)制的模型再 從源碼實(shí)現(xiàn)角度典奉,分析
Binder
在Android
中的具體實(shí)現(xiàn)
從而全方位地介紹 Binder
,希望你們會喜歡丧叽。
請盡量在PC端而不要在移動端看卫玖,否則圖片可能看不清。
目錄
1. Binder到底是什么踊淳?
中文即 粘合劑假瞬,意思為粘合了兩個(gè)不同的進(jìn)程
網(wǎng)上有很多對
Binder
的定義,但都說不清楚:Binder
是跨進(jìn)程通信方式迂尝、它實(shí)現(xiàn)了IBinder
接口脱茉,是連接ServiceManager
的橋梁blabla,估計(jì)大家都看暈了垄开,沒法很好的理解我認(rèn)為:對于
Binder
的定義琴许,在不同場景下其定義不同
在本文的講解中,按照 大角度 -> 小角度 去分析Binder
溉躲,即:
- 先從 機(jī)制榜田、模型的角度 去分析 整個(gè)
Binder
跨進(jìn)程通信機(jī)制的模型
其中益兄,會詳細(xì)分析模型組成中的
Binder
驅(qū)動
- 再 從源碼實(shí)現(xiàn)角度,分析
Binder
在Android
中的具體實(shí)現(xiàn)
從而全方位地介紹 Binder
箭券,希望你們會喜歡净捅。
2. 知識儲備
在講解Binder
前,我們先了解一些基礎(chǔ)知識
2.1 進(jìn)程空間分配
一個(gè)進(jìn)程空間分為 用戶空間 & 內(nèi)核空間(
Kernel
)辩块,即把進(jìn)程內(nèi) 用戶 & 內(nèi)核 隔離開來-
二者區(qū)別:
進(jìn)程間蛔六,用戶空間的數(shù)據(jù)不可共享,所以用戶空間 = 不可共享空間
進(jìn)程間废亭,內(nèi)核空間的數(shù)據(jù)可共享国章,所以內(nèi)核空間 = 可共享空間
進(jìn)程內(nèi) 用戶 與 內(nèi)核 進(jìn)行交互 稱為系統(tǒng)調(diào)用
2.2 進(jìn)程隔離
為了保證 安全性 & 獨(dú)立性,一個(gè)進(jìn)程 不能直接操作或者訪問另一個(gè)進(jìn)程滔以,即Android
的進(jìn)程是相互獨(dú)立捉腥、隔離的
2.3 跨進(jìn)程通信( IPC
)
隔離后,由于某些需求你画,進(jìn)程間 需要合作 / 交互
-
跨進(jìn)程間通信的原理
先通過 進(jìn)程間 的內(nèi)核空間進(jìn)行 數(shù)據(jù)交互
再通過 進(jìn)程內(nèi) 的用戶空間 & 內(nèi)核空間進(jìn)行 數(shù)據(jù)交互抵碟,從而實(shí)現(xiàn) 進(jìn)程間的用戶空間 的數(shù)據(jù)交互
而Binder
,就是充當(dāng) 連接 兩個(gè)進(jìn)程(內(nèi)核空間)的通道坏匪。
3. Binder 跨進(jìn)程通信機(jī)制 模型
3.1 模型原理
Binder
跨進(jìn)程通信機(jī)制 模型 基于 Client - Server
模式
- 模型原理圖
- 模型組成角色說明
- 模型原理步驟說明
3.2 額外說明
說明1:Client
進(jìn)程拟逮、Server
進(jìn)程 & Service Manager
進(jìn)程之間的交互 都必須通過Binder
驅(qū)動(使用 open
和 ioctl
文件操作函數(shù)),而非直接交互
原因:
Client
進(jìn)程适滓、Server
進(jìn)程 &Service Manager
進(jìn)程屬于進(jìn)程空間的用戶空間敦迄,不可進(jìn)行進(jìn)程間交互Binder
驅(qū)動 屬于 進(jìn)程空間的 內(nèi)核空間,可進(jìn)行進(jìn)程間 & 進(jìn)程內(nèi)交互
所以凭迹,原理圖可表示為以下:
虛線表示并非直接交互
說明2: Binder
驅(qū)動 & Service Manager
進(jìn)程 屬于 Android
基礎(chǔ)架構(gòu)(即系統(tǒng)已經(jīng)實(shí)現(xiàn)好了)罚屋;而Client
進(jìn)程 和 Server
進(jìn)程 屬于Android
應(yīng)用層(需要開發(fā)者自己實(shí)現(xiàn))
所以,在進(jìn)行跨進(jìn)程通信時(shí)嗅绸,開發(fā)者只需自定義Client
& Server
進(jìn)程 并 顯式使用上述3個(gè)步驟脾猛,最終借助 Android
的基本架構(gòu)功能就可完成進(jìn)程間通信
說明3:Binder請求的線程管理
Server
進(jìn)程會創(chuàng)建很多線程來處理Binder
請求Binder
模型的線程管理 采用Binder
驅(qū)動的線程池,并由Binder
驅(qū)動自身進(jìn)行管理
而不是由
Server
進(jìn)程來管理的
- 一個(gè)進(jìn)程的
Binder
線程數(shù)默認(rèn)最大是16鱼鸠,超過的請求會被阻塞等待空閑的Binder線程猛拴。
所以,在進(jìn)程間通信時(shí)處理并發(fā)問題時(shí)蚀狰,如使用
ContentProvider
時(shí)愉昆,它的CRUD
(創(chuàng)建、檢索麻蹋、更新和刪除)方法只能同時(shí)有16個(gè)線程同時(shí)工作
至此跛溉,我相信大家對
Binder
跨進(jìn)程通信機(jī)制 模型 已經(jīng)有了一個(gè)非常清晰的定性認(rèn)識下面,我將通過一個(gè)實(shí)例,分析
Binder
跨進(jìn)程通信機(jī)制 模型在Android
中的具體代碼實(shí)現(xiàn)方式
即分析 上述步驟在
Android
中具體是用代碼如何實(shí)現(xiàn)的
4. Binder機(jī)制 在Android中的具體實(shí)現(xiàn)原理
-
Binder
機(jī)制在Android
中的實(shí)現(xiàn)主要依靠Binder
類倒谷,其實(shí)現(xiàn)了IBinder
接口
下面會詳細(xì)說明
- 實(shí)例說明:
Client
進(jìn)程 需要調(diào)用Server
進(jìn)程的加法函數(shù)(將整數(shù)a和b相加)
即:
Client
進(jìn)程 需要傳兩個(gè)整數(shù)給Server
進(jìn)程
Server
進(jìn)程 需要把相加后的結(jié)果 返回給Client
進(jìn)程
-
具體步驟
下面蛛蒙,我會根據(jù)
Binder
跨進(jìn)程通信機(jī)制 模型的步驟進(jìn)行分析
步驟1:注冊服務(wù)
-
過程描述
Server
進(jìn)程 通過Binder
驅(qū)動 向Service Manager
進(jìn)程 注冊服務(wù) -
代碼實(shí)現(xiàn)
Server
進(jìn)程 創(chuàng)建 一個(gè)Binder
對象
Binder
實(shí)體是Server
進(jìn)程 在Binder
驅(qū)動中的存在形式該對象保存
Server
和ServiceManager
的信息(保存在內(nèi)核空間中)
Binder
驅(qū)動通過 內(nèi)核空間的Binder
實(shí)體 找到用戶空間的Server
對象
- 代碼分析
Binder binder = new Stub();
// 步驟1:創(chuàng)建Binder對象 ->>分析1
// 步驟2:創(chuàng)建 IInterface 接口類 的匿名類
// 創(chuàng)建前,需要預(yù)先定義 繼承了IInterface 接口的接口 -->分析3
IInterface plus = new IPlus(){
// 確定Client進(jìn)程需要調(diào)用的方法
public int add(int a,int b) {
return a+b;
}
// 實(shí)現(xiàn)IInterface接口中唯一的方法
public IBinder asBinder(){
return null ;
}
};
// 步驟3
binder.attachInterface(plus渤愁,"add two int");
// 1\. 將(add two int牵祟,plus)作為(key,value)對存入到Binder對象中的一個(gè)Map<String,IInterface>對象中
// 2\. 之后,Binder對象 可根據(jù)add two int通過queryLocalIInterface()獲得對應(yīng)IInterface對象(即plus)的引用抖格,可依靠該引用完成對請求方法的調(diào)用
// 分析完畢诺苹,跳出
<-- 分析1:Stub類 -->
public class Stub extends Binder {
// 繼承自Binder類 ->>分析2
// 復(fù)寫onTransact()
@Override
boolean onTransact(int code, Parcel data, Parcel reply, int flags){
// 具體邏輯等到步驟3再具體講解,此處先跳過
switch (code) {
case Stub.add: {
data.enforceInterface("add two int");
int arg0 = data.readInt();
int arg1 = data.readInt();
int result = this.queryLocalIInterface("add two int") .add( arg0, arg1);
reply.writeInt(result);
return true;
}
}
return super.onTransact(code, data, reply, flags);
}
// 回到上面的步驟1雹拄,繼續(xù)看步驟2
<-- 分析2:Binder 類 -->
public class Binder implement IBinder{
// Binder機(jī)制在Android中的實(shí)現(xiàn)主要依靠的是Binder類收奔,其實(shí)現(xiàn)了IBinder接口
// IBinder接口:定義了遠(yuǎn)程操作對象的基本接口,代表了一種跨進(jìn)程傳輸?shù)哪芰? // 系統(tǒng)會為每個(gè)實(shí)現(xiàn)了IBinder接口的對象提供跨進(jìn)程傳輸能力
// 即Binder類對象具備了跨進(jìn)程傳輸?shù)哪芰?
void attachInterface(IInterface plus, String descriptor)滓玖;
// 作用:
// 1\. 將(descriptor坪哄,plus)作為(key,value)對存入到Binder對象中的一個(gè)Map<String,IInterface>對象中
// 2\. 之后,Binder對象 可根據(jù)descriptor通過queryLocalIInterface()獲得對應(yīng)IInterface對象(即plus)的引用势篡,可依靠該引用完成對請求方法的調(diào)用
IInterface queryLocalInterface(Stringdescriptor) 翩肌;
// 作用:根據(jù) 參數(shù) descriptor 查找相應(yīng)的IInterface對象(即plus引用)
boolean onTransact(int code, Parcel data, Parcel reply, int flags);
// 定義:繼承自IBinder接口的
// 作用:執(zhí)行Client進(jìn)程所請求的目標(biāo)方法(子類需要復(fù)寫)
// 參數(shù)說明:
// code:Client進(jìn)程請求方法標(biāo)識符禁悠。即Server進(jìn)程根據(jù)該標(biāo)識確定所請求的目標(biāo)方法
// data:目標(biāo)方法的參數(shù)念祭。(Client進(jìn)程傳進(jìn)來的,此處就是整數(shù)a和b)
// reply:目標(biāo)方法執(zhí)行后的結(jié)果(返回給Client進(jìn)程)
// 注:運(yùn)行在Server進(jìn)程的Binder線程池中碍侦;當(dāng)Client進(jìn)程發(fā)起遠(yuǎn)程請求時(shí)粱坤,遠(yuǎn)程請求會要求系統(tǒng)底層執(zhí)行回調(diào)該方法
final class BinderProxy implements IBinder {
// 即Server進(jìn)程創(chuàng)建的Binder對象的代理對象類
// 該類屬于Binder的內(nèi)部類
}
// 回到分析1原處
}
<-- 分析3:IInterface接口實(shí)現(xiàn)類 -->
public interface IPlus extends IInterface {
// 繼承自IInterface接口->>分析4
// 定義需要實(shí)現(xiàn)的接口方法,即Client進(jìn)程需要調(diào)用的方法
public int add(int a,int b);
// 返回步驟2
}
<-- 分析4:IInterface接口類 -->
// 進(jìn)程間通信定義的通用接口
// 通過定義接口瓷产,然后再服務(wù)端實(shí)現(xiàn)接口站玄、客戶端調(diào)用接口,就可實(shí)現(xiàn)跨進(jìn)程通信濒旦。
public interface IInterface
{
// 只有一個(gè)方法:返回當(dāng)前接口關(guān)聯(lián)的 Binder 對象蜒什。
public IBinder asBinder();
}
// 回到分析3原處
注冊服務(wù)后,Binder
驅(qū)動持有 Server
進(jìn)程創(chuàng)建的Binder
實(shí)體
步驟2:獲取服務(wù)
Client
進(jìn)程 使用 某個(gè)service
前(此處是 相加函數(shù))疤估,須 通過Binder
驅(qū)動 向ServiceManager
進(jìn)程 獲取相應(yīng)的Service
信息具體代碼實(shí)現(xiàn)過程如下:
此時(shí),Client
進(jìn)程與 Server
進(jìn)程已經(jīng)建立了連接
步驟3:使用服務(wù)
Client
進(jìn)程 根據(jù)獲取到的 Service
信息(Binder
代理對象)霎冯,通過Binder
驅(qū)動 建立與 該Service
所在Server
進(jìn)程通信的鏈路铃拇,并開始使用服務(wù)
-
過程描述
Client
進(jìn)程 將參數(shù)(整數(shù)a和b)發(fā)送到Server
進(jìn)程Server
進(jìn)程 根據(jù)Client
進(jìn)程要求調(diào)用 目標(biāo)方法(即加法函數(shù))Server
進(jìn)程 將目標(biāo)方法的結(jié)果(即加法后的結(jié)果)返回給Client
進(jìn)程
代碼實(shí)現(xiàn)過程
步驟1: Client
進(jìn)程 將參數(shù)(整數(shù)a和b)發(fā)送到Server
進(jìn)程
// 1\. Client進(jìn)程 將需要傳送的數(shù)據(jù)寫入到Parcel對象中
// data = 數(shù)據(jù) = 目標(biāo)方法的參數(shù)(Client進(jìn)程傳進(jìn)來的,此處就是整數(shù)a和b) + IInterface接口對象的標(biāo)識符descriptor
android.os.Parcel data = android.os.Parcel.obtain();
data.writeInt(a);
data.writeInt(b);
data.writeInterfaceToken("add two int");沈撞;
// 方法對象標(biāo)識符讓Server進(jìn)程在Binder對象中根據(jù)"add two int"通過queryLocalIInterface()查找相應(yīng)的IInterface對象(即Server創(chuàng)建的plus)慷荔,Client進(jìn)程需要調(diào)用的相加方法就在該對象中
android.os.Parcel reply = android.os.Parcel.obtain();
// reply:目標(biāo)方法執(zhí)行后的結(jié)果(此處是相加后的結(jié)果)
// 2\. 通過 調(diào)用代理對象的transact() 將 上述數(shù)據(jù)發(fā)送到Binder驅(qū)動
binderproxy.transact(Stub.add, data, reply, 0)
// 參數(shù)說明:
// 1\. Stub.add:目標(biāo)方法的標(biāo)識符(Client進(jìn)程 和 Server進(jìn)程 自身約定,可為任意)
// 2\. data :上述的Parcel對象
// 3\. reply:返回結(jié)果
// 0:可不管
// 注:在發(fā)送數(shù)據(jù)后缠俺,Client進(jìn)程的該線程會暫時(shí)被掛起
// 所以显晶,若Server進(jìn)程執(zhí)行的耗時(shí)操作贷岸,請不要使用主線程,以防止ANR
// 3\. Binder驅(qū)動根據(jù) 代理對象 找到對應(yīng)的真身Binder對象所在的Server 進(jìn)程(系統(tǒng)自動執(zhí)行)
// 4\. Binder驅(qū)動把 數(shù)據(jù) 發(fā)送到Server 進(jìn)程中磷雇,并通知Server 進(jìn)程執(zhí)行解包(系統(tǒng)自動執(zhí)行)
步驟2:Server
進(jìn)程根據(jù)Client
進(jìn)要求 調(diào)用 目標(biāo)方法(即加法函數(shù))
// 1\. 收到Binder驅(qū)動通知后偿警,Server 進(jìn)程通過回調(diào)Binder對象onTransact()進(jìn)行數(shù)據(jù)解包 & 調(diào)用目標(biāo)方法
public class Stub extends Binder {
// 復(fù)寫onTransact()
@Override
boolean onTransact(int code, Parcel data, Parcel reply, int flags){
// code即在transact()中約定的目標(biāo)方法的標(biāo)識符
switch (code) {
case Stub.add: {
// a. 解包Parcel中的數(shù)據(jù)
data.enforceInterface("add two int");
// a1\. 解析目標(biāo)方法對象的標(biāo)識符
int arg0 = data.readInt();
int arg1 = data.readInt();
// a2\. 獲得目標(biāo)方法的參數(shù)
// b. 根據(jù)"add two int"通過queryLocalIInterface()獲取相應(yīng)的IInterface對象(即Server創(chuàng)建的plus)的引用,通過該對象引用調(diào)用方法
int result = this.queryLocalIInterface("add two int") .add( arg0, arg1);
// c. 將計(jì)算結(jié)果寫入到reply
reply.writeInt(result);
return true;
}
}
return super.onTransact(code, data, reply, flags);
// 2\. 將結(jié)算結(jié)果返回 到Binder驅(qū)動
** 步驟3:Server
進(jìn)程 將目標(biāo)方法的結(jié)果(即加法后的結(jié)果)返回給Client
進(jìn)程**
// 1\. Binder驅(qū)動根據(jù) 代理對象 沿原路 將結(jié)果返回 并通知Client進(jìn)程獲取返回結(jié)果
// 2\. 通過代理對象 接收結(jié)果(之前被掛起的線程被喚醒)
binderproxy.transact(Stub.ADD, data, reply, 0)唯笙;
reply.readException();螟蒸;
result = reply.readInt();
}
}
-
總結(jié)
下面崩掘,我用一個(gè)原理圖 & 流程圖來總結(jié)步驟3的內(nèi)容
5. 優(yōu)點(diǎn)
對比 Linux
(Android
基于Linux
)上的其他進(jìn)程通信方式(管道七嫌、消息隊(duì)列、共享內(nèi)存苞慢、
信號量诵原、Socket
)砚蓬,Binder
機(jī)制的優(yōu)點(diǎn)有:
6. 總結(jié)
- 本文主要詳細(xì)講解 跨進(jìn)程通信模型
Binder
機(jī)制 肮砾,總結(jié)如下:
看完本文的
Binder
機(jī)制原理疮装,繼續(xù)閱讀AIDL
的內(nèi)容會更加好誉碴,具體請看我的文章Android:遠(yuǎn)程服務(wù)Service(含AIDL & IPC講解)下面我將繼續(xù)對
Android
中的知識進(jìn)行講解 叛薯,有興趣可以繼續(xù)關(guān)注Carson_Ho的安卓開發(fā)筆記
請點(diǎn)贊稀轨!因?yàn)槟愕墓膭钍俏覍懽鞯淖畲髣恿Γ?/h1>
相關(guān)文章閱讀
Android開發(fā):最全面撮慨、最易懂的Android屏幕適配解決方案
Android事件分發(fā)機(jī)制詳解:史上最全面毛萌、最易懂
Android開發(fā):史上最全的Android消息推送解決方案
Android開發(fā):最全面航闺、最易懂的Webview詳解
歡迎關(guān)注Carson_Ho的簡書褪测!
相關(guān)文章閱讀
Android開發(fā):最全面撮慨、最易懂的Android屏幕適配解決方案
Android事件分發(fā)機(jī)制詳解:史上最全面毛萌、最易懂
Android開發(fā):史上最全的Android消息推送解決方案
Android開發(fā):最全面航闺、最易懂的Webview詳解
作者:Carson_Ho
鏈接:http://www.reibang.com/p/4ee3fd07da14
來源:簡書
著作權(quán)歸作者所有。商業(yè)轉(zhuǎn)載請聯(lián)系作者獲得授權(quán)潦刃,非商業(yè)轉(zhuǎn)載請注明出處侮措。</pre>