由于Android系統(tǒng)保護(hù)機(jī)制(沙箱機(jī)制)雄驹,兩個(gè)進(jìn)程是各自運(yùn)行在自己的進(jìn)程空間之中的,相互之間進(jìn)行隔離并不能夠直接進(jìn)行通訊(確保一個(gè)進(jìn)程掛掉了职抡,不會影響另外一個(gè)進(jìn)程的運(yùn)行)鹃锈。
一、為什么使用Binder機(jī)制
Android系統(tǒng)是基于Linux系統(tǒng)的宪萄,我們知道Linux 系統(tǒng)之中常見的進(jìn)程之間的通訊就有共享內(nèi)存艺谆、消息隊(duì)列、管道拜英、Socket等静汤。那為什么Android 系統(tǒng)不直接采用Linux 的進(jìn)程之間的通訊方式,而是采用Binder機(jī)制,C/S模式來實(shí)現(xiàn)進(jìn)程之間的通訊呢虫给?
我想主要有以下三個(gè)方面的原因藤抡。
- C/S架構(gòu)模式,Binder能夠很好的支持Client-Server模式抹估,相比只有Socket能夠提供C/S模式缠黍,但是Socket主要是用于網(wǎng)絡(luò)之間的通訊以及本地進(jìn)程之間的低速通訊,效率太低药蜻。
- 安全考慮瓷式, Android 系統(tǒng)為每一個(gè)應(yīng)用程序都分配了唯一的一個(gè)UID,且Android系統(tǒng)安全權(quán)限管理很嚴(yán)格语泽,Server端會根據(jù)權(quán)限控制策略贸典,判斷UID/PID是否滿足訪問權(quán)限。
- 性能考慮踱卵, 傳統(tǒng)的消息隊(duì)列廊驼、管道、Socke都需要通過2次拷貝操作惋砂,才能實(shí)現(xiàn)從用戶態(tài)空間到內(nèi)核空間的數(shù)據(jù)拷貝妒挎。而共享內(nèi)存實(shí)現(xiàn)方式復(fù)雜,沒有客戶與服務(wù)端之別西饵, 需要充分考慮到訪問臨界資源的并發(fā)同步問題饥漫,否則可能會出現(xiàn)死鎖等問題。而Binder只需要一次拷貝操作就可以(從發(fā)送方的緩存區(qū)拷貝到內(nèi)核的緩存區(qū)罗标,而接收方的緩存區(qū)與內(nèi)核的緩存區(qū)是映射到同一塊物理地址的,因此只需要1次拷貝即可)积蜻。
二闯割、幾個(gè)重要的概念
- Binder實(shí)體,其實(shí)就是Server在內(nèi)核中的binder_node結(jié)構(gòu)體的對象竿拆,保存著Server對象在用戶空間的地址信息宙拉。通過Binder實(shí)體可以找到用戶空間的Server的對象。
- Binder引用丙笋,其實(shí)就是是內(nèi)核中binder_ref結(jié)構(gòu)體的對象谢澈,它的作用是在表示"Binder實(shí)體"的引用。簡單說是每一個(gè)Binder引用都是某一個(gè)Binder實(shí)體的引用御板,通過Binder引用可以在內(nèi)核中找到它對應(yīng)的Binder實(shí)體锥忿。
- 遠(yuǎn)程服務(wù),Server都是以服務(wù)的形式注冊到ServiceManager中進(jìn)行管理的怠肋,可以理解就是Server提供的服務(wù)敬鬓。
- ServiceManager,是用戶空間的守護(hù)進(jìn)程,由init進(jìn)程負(fù)責(zé)啟動(dòng)钉答,之后會打開/dev/binder設(shè)備础芍,建立128K虛擬內(nèi)存映射Binder 驅(qū)動(dòng),下發(fā)BINDER_SET_CONTEXT_MGR的command数尿,聲明自己成為上下文管理者仑性,進(jìn)入binder消息輪詢,等待client消息到來右蹦。
- Server注冊服務(wù)诊杆,Server首先會向Binder驅(qū)動(dòng)發(fā)起注冊服務(wù)請求,Binder驅(qū)動(dòng)會新建與該Server對應(yīng)的Binder實(shí)體嫩实,在ServiceManager的保存Binder引用的紅黑樹中查找Server的Binder引用如果不存在則會新建一個(gè)與該Server對應(yīng)的Binder引用刽辙。并將其添加到ServiceManager的保存Binder引用的紅黑樹之中。
- Client獲取遠(yuǎn)程服務(wù)甲献,Client攜帶Server的服務(wù)名向Binder驅(qū)動(dòng)獲取遠(yuǎn)程服務(wù)宰缤,Binder驅(qū)動(dòng)會轉(zhuǎn)發(fā)會給ServiceManager進(jìn)程,且有ServiceManager返回Server對應(yīng)的Binder實(shí)體的Binder引用信息晃洒,Client根據(jù)這個(gè)信息創(chuàng)建Server的遠(yuǎn)程服務(wù)慨灭,該遠(yuǎn)程服務(wù)會對應(yīng)的通過Binder驅(qū)動(dòng)和真正的Server進(jìn)行交互,從而執(zhí)行相應(yīng)的動(dòng)作球及。
三氧骤、AIDL 示例
在Android開發(fā)過程中,我們一般是采用編寫AIDL文件的形式來描述服務(wù)器提供哪些接口吃引。
IDataManager.aidl 文件
// 無論應(yīng)用的類是否和aidl文件在同一包下筹陵,都需要顯示import
import org.github.lion.aidl_demo.Data;
interface IDataManager {
/** AIDL 支持的數(shù)據(jù)類型劃分為四類
* 第一類是 Java 編程語言中的基本類型
* 第二類包括 String、List镊尺、Map 和 CharSequence
* 第三類是其他 AIDL 生成的 interface
* 第四類是實(shí)現(xiàn)了 Parcelable protocol 的自定義類
*/
void basicTypes(int anInt, long aLong, boolean aBoolean
, float aFloat, double aDouble, String aString);
int getDataTypeCount();
List<Data> getData();
String getUrlContent(String url);
}
自定義實(shí)現(xiàn)Parcelable接口類型
/** 必須實(shí)現(xiàn)Parcelable接口
* 1. 定義CREATOR對象
*/
public class Data implements Parcelable {
...
protected Data(Parcel in) {
...
}
public static final Creator<Data> CREATOR = new Creator<Data>() {
@Override
public Data createFromParcel(Parcel in) {
return new Data(in);
}
@Override
public Data[] newArray(int size) {
return new Data[size];
}
};
}
服務(wù)端的實(shí)現(xiàn)
private static final IDataManager.Stub mBinder = new IDataManager.Stub() {
@Override
public void basicTypes(int anInt, long aLong, boolean aBoolean
, float aFloat, double aDouble, String aString)
throws RemoteException {
}
@Override
public int getDataTypeCount() throws RemoteException {
// todo return some data
return 0;
}
@Override
public List<Data> getData() throws RemoteException {
// todo return some data
return null;
}
@Override
public String getUrlContent(String url) throws RemoteException {
// todo return some data
return null;
}
};
@Override
public IBinder onBind(Intent intent) {
return mBinder;
}
客戶端實(shí)現(xiàn)
private IDataManager dataManagerService = null;
@Override
protected void onCreate(Bundle savedInstanceState) {
...
// 綁定服務(wù)
bindService(new Intent(this, DataManagerService.class), dataServiceConnection,
Context.BIND_AUTO_CREATE);
}
private ServiceConnection dataServiceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
// 返回IBinder 對象朦佩,封裝為代理類
dataManagerService = IDataManager.Stub.asInterface(service);
}
@Override
public void onServiceDisconnected(ComponentName name) {
dataManagerService = null;
}
};
接下來我們看看Android Studio幫我們自動(dòng)生成的Java文件里面的內(nèi)容。
// IDataManager2 直接繼承了IInterface
public interface IDataManager2 extends IInterface {
// 返回值為基本數(shù)據(jù)類型庐氮,定義接口時(shí)不需要做特殊處理
int getDataCount() throws RemoteException;
// 自定義的返回?cái)?shù)據(jù)類型需要實(shí)現(xiàn)Parcelable接口语稠,進(jìn)程間通信不能直接共享內(nèi)存,需要將對象持久化弄砍。
// 所以自定義的類需要實(shí)現(xiàn)Parcelable接口
List<Data2> getData() throws RemoteException;
}
//內(nèi)部抽象類集成Binder實(shí)現(xiàn)了IDataManager2(Stub)接口
public abstract class DataManagerNative extends Binder implements IDataManager2 {
// Binder描述符仙畦,唯一標(biāo)識符
private static final String DESCRIPTOR = "com.github.onlynight.aidl_demo2.aidl.IDataManager2";
// 每個(gè)方法對應(yīng)的ID
private static final int TRANSACTION_getDataCount = IBinder.FIRST_CALL_TRANSACTION;
private static final int TRANSACTION_getData = IBinder.FIRST_CALL_TRANSACTION + 1;
public DataManagerNative() {
attachInterface(this, DESCRIPTOR);
}
/**
* 將Binder轉(zhuǎn)化為IInterface接口
*
* @param binder
* @return
*/
public static IDataManager2 asInterface(IBinder binder) {
if (binder == null) {
return null;
}
//同一進(jìn)程內(nèi)直接返回
IInterface iin = binder.queryLocalInterface(DESCRIPTOR);
if ((iin != null) && (iin instanceof IDataManager2)) {
return (IDataManager2) iin;
}
//不在同一進(jìn)程使用代理獲取遠(yuǎn)程服務(wù)
return new Proxy(binder);
}
@Override
public IBinder asBinder() {
return this;
}
/**
* 我們查看Binder的源碼就可以看出實(shí)際上transact方法真正的執(zhí)行體
* 是這個(gè)onTransact方法。
*
* @param code 服務(wù)器回掉的方法ID音婶,每一個(gè)方法都有一個(gè)唯一id慨畸,
* 這樣方法回調(diào)時(shí)可通過id判斷回調(diào)的方法。
* @param data 輸入的參數(shù)衣式,傳遞給服務(wù)端的參數(shù)
* @param reply 輸出的參數(shù)先口,服務(wù)器返回的數(shù)據(jù)
* @param flags 默認(rèn)傳入0
* @return
* @throws RemoteException 遠(yuǎn)端服務(wù)器無響應(yīng)拋出該錯(cuò)誤型奥。
*/
@Override
protected boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {
switch (code) {
case TRANSACTION_getDataCount: {
data.enforceInterface(DESCRIPTOR);
int _result = this.getDataCount();
reply.writeNoException();
reply.writeInt(_result);
return true;
}
case TRANSACTION_getData: {
data.enforceInterface(DESCRIPTOR);
List<Data2> _result = this.getData();
reply.writeNoException();
reply.writeTypedList(_result);
return true;
}
}
return super.onTransact(code, data, reply, flags);
}
/**
* 代理類,調(diào)用transact方法碉京。
*/
private static class Proxy implements IDataManager2 {
private IBinder remote;
Proxy(IBinder remote) {
this.remote = remote;
}
public String getInterfaceDescriptor() {
return DESCRIPTOR;
}
@Override
public int getDataCount() throws RemoteException {
// 輸入?yún)?shù)
Parcel _data = Parcel.obtain();
//輸出參數(shù)
Parcel _reply = Parcel.obtain();
int _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
remote.transact(TRANSACTION_getDataCount, _data, _reply, 0);
_reply.readException();
_result = _reply.readInt();
} finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
@Override
public List<Data2> getData() throws RemoteException {
Parcel _data = Parcel.obtain();
Parcel _reply = Parcel.obtain();
List<Data2> _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
remote.transact(TRANSACTION_getData, _data, _reply, 0);
_reply.readException();
_result = _reply.createTypedArrayList(Data2.CREATOR);
} finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
@Override
public IBinder asBinder() {
return remote;
}
}
}
參考博客:
1. binder守護(hù)進(jìn)程servicemanager簡介
2. Android Binder機(jī)制(一) Binder的設(shè)計(jì)和框架
3. 一篇文章了解相見恨晚的 Android Binder 進(jìn)程間通訊機(jī)制