轉(zhuǎn)載請(qǐng)注明出處:http://blog.csdn.net/wu371894545/article/details/54962860
一、Binder機(jī)制概述
在Android開發(fā)中,很多時(shí)候我們需要用到進(jìn)程間通信,所謂進(jìn)程間通信,實(shí)現(xiàn)進(jìn)程間通信的機(jī)制有很多種,比如說socket、pipe等,Android中進(jìn)程間通信的方式主要有三種:
1.標(biāo)準(zhǔn)linux Kernel IPC 接口;
2.標(biāo)準(zhǔn)D-BUS接口;
3.Binder接口。
其中,Binder機(jī)制是使用最且最被認(rèn)可的,因?yàn)锽inder機(jī)制有以下優(yōu)點(diǎn):
1.相對(duì)于其它IPC機(jī)制,Binder機(jī)制更加簡(jiǎn)潔和快速;
2.消耗的內(nèi)存相對(duì)更少;
3.傳統(tǒng)的IPC機(jī)制可能會(huì)增加進(jìn)程的開銷,以及出現(xiàn)進(jìn)程過載和安全漏洞,Binder機(jī)制則有效避免和解決了這些問題。
Binder機(jī)制是Android系統(tǒng)的核心機(jī)制,幾乎貫穿于整個(gè)Android系統(tǒng),Android系統(tǒng)基本上可以看作是一個(gè)基于binder通信機(jī)制的C/S架構(gòu),Binder就像網(wǎng)絡(luò),把Android系統(tǒng)的各個(gè)部分連接到了一起。利用Binder機(jī)制,可以實(shí)現(xiàn)以下功能:
1.用驅(qū)動(dòng)程序來推進(jìn)進(jìn)程間通信;
2.通過共享內(nèi)存來提高性能;
3.為進(jìn)程請(qǐng)求分配每個(gè)進(jìn)程的線程池;
4.針對(duì)系統(tǒng)中的對(duì)象引入了引用計(jì)數(shù)和跨進(jìn)程的對(duì)象引用映射;
5.進(jìn)程間同步調(diào)用。
1. 直觀來說,Binder是Android中的一個(gè)類,它繼承了IBinder接口
2. 從IPC角度來說,Binder是Android中的一種跨進(jìn)程通信方式,Binder還可以理解為一種虛擬的物理設(shè)備,它的設(shè)備驅(qū)動(dòng)是/dev/binder,該通信方式在Linux中沒有
3. 從Android Framework角度來說,Binder是ServiceManager連接各種Manager(ActivityManager、WindowManager,etc)和相應(yīng)ManagerService的橋梁
4. 從Android應(yīng)用層來說,Binder是客戶端和服務(wù)端進(jìn)行通信的媒介,當(dāng)你bindService的時(shí)候,服務(wù)端會(huì)返回一個(gè)包含了服務(wù)端業(yè)務(wù)調(diào)用的Binder對(duì)象,通過這個(gè)Binder對(duì)象,客戶端就可以獲取服務(wù)端提供的服務(wù)或者數(shù)據(jù),這里的服務(wù)包括普通服務(wù)和基于AIDL的服務(wù)
Android中有大量的CS(Client-Server)應(yīng)用方式,這就要求Android內(nèi)部提供IPC方法,而linux所支持的進(jìn)程通信方式有兩個(gè)問題:性能和安全性。
目前l(fā)inux支持的IPC包括傳統(tǒng)的管道,System V IPC(消息隊(duì)列/共享內(nèi)存/信號(hào)量),以及socket,但只有socket支持Client-Server的通信方式,由于socket是一套通用的網(wǎng)絡(luò)通信方式,其傳輸效率低下切有很大的開銷,比如socket的連接建立過程和中斷連接過程都是有一定開銷的。消息隊(duì)列和管道采用存儲(chǔ)-轉(zhuǎn)發(fā)方式,即數(shù)據(jù)先從發(fā)送方緩存區(qū)拷貝到內(nèi)核開辟的緩存區(qū)中,然后再從內(nèi)核緩存區(qū)拷貝到接收方緩存區(qū),至少有兩次拷貝過程。共享內(nèi)存雖然無需拷貝,但控制復(fù)雜,難以使用。
在安全性方面,Android作為一個(gè)開放式,擁有眾多開發(fā)者的的平臺(tái),應(yīng)用程序的來源廣泛,確保智能終端的安全是非常重要的。終端用戶不希望從網(wǎng)上下載的程序在不知情的情況下偷窺隱私數(shù)據(jù),連接無線網(wǎng)絡(luò),長(zhǎng)期操作底層設(shè)備導(dǎo)致電池很快耗盡等等。傳統(tǒng)IPC沒有任何安全措施,完全依賴上層協(xié)議來確保。首先傳統(tǒng)IPC的接收方無法獲得對(duì)方進(jìn)程可靠的UID/PID(用戶ID/進(jìn)程ID),從而無法鑒別對(duì)方身份。Android為每個(gè)安裝好的應(yīng)用程序分配了自己的UID,故進(jìn)程的UID是鑒別進(jìn)程身份的重要標(biāo)志。使用傳統(tǒng)IPC只能由用戶在數(shù)據(jù)包里填入U(xiǎn)ID/PID,但這樣不可靠,容易被惡意程序利用。可靠的身份標(biāo)記只有由IPC機(jī)制本身在內(nèi)核中添加。其次傳統(tǒng)IPC訪問接入點(diǎn)是開放的,無法建立私有通道。比如命名管道的名稱,system V的鍵值,socket的ip地址或文件名都是開放的,只要知道這些接入點(diǎn)的程序都可以和對(duì)端建立連接,不管怎樣都無法阻止惡意程序通過猜測(cè)接收方地址獲得連接。
基于以上原因,Android需要建立一套新的IPC機(jī)制來滿足系統(tǒng)對(duì)通信方式,傳輸性能和安全性的要求,這就是Binder。Binder基于 Client-Server通信模式,傳輸過程只需一次拷貝,為發(fā)送發(fā)添加UID/PID身份,既支持實(shí)名Binder也支持匿名Binder,安全性高。
二、從自動(dòng)生成的AIDL文件中分析Binderpackage com.ryg.chapter_2.aidl;
public interface IBookManager extends android.os.IInterface {
/** Local-side IPC implementation stub class. */
public static abstract class Stub extends android.os.Binder implements
com.ryg.chapter_2.aidl.IBookManager {
PRivate static final java.lang.String DESCRIPTOR = "com.ryg.chapter_2.aidl.IBookManager";
/** Construct the stub at attach it to the interface. */
public Stub() {
this.attachInterface(this, DESCRIPTOR);
}
/**
* Cast an IBinder object into an com.ryg.chapter_2.aidl.IBookManager
* interface, generating a proxy if needed.
*/
public static com.ryg.chapter_2.aidl.IBookManager asInterface(
android.os.IBinder obj) {
if ((obj == null)) {
return null;
}
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin != null) && (iin instanceof com.ryg.chapter_2.aidl.IBookManager))) {
return ((com.ryg.chapter_2.aidl.IBookManager) iin);
}
return new com.ryg.chapter_2.aidl.IBookManager.Stub.Proxy(obj);
}
@Override
public android.os.IBinder asBinder() {
return this;
}
@Override
public boolean onTransact(int code, android.os.Parcel data,
android.os.Parcel reply, int flags)
throws android.os.RemoteException {
switch (code) {
case INTERFACE_TRANSACTION: {
reply.writeString(DESCRIPTOR);
return true;
}
case TRANSACTION_getBookList: {
data.enforceInterface(DESCRIPTOR);
java.util.List<com.ryg.chapter_2.aidl.Book> _result = this
.getBookList();
reply.writeNoException();
reply.writeTypedList(_result);
return true;
}
case TRANSACTION_addBook: {
data.enforceInterface(DESCRIPTOR);
com.ryg.chapter_2.aidl.Book _arg0;
if ((0 != data.readInt())) {
_arg0 = com.ryg.chapter_2.aidl.Book.CREATOR
.createFromParcel(data);
} else {
_arg0 = null;
}
this.addBook(_arg0);
reply.writeNoException();
return true;
}
case TRANSACTION_registerListener: {
data.enforceInterface(DESCRIPTOR);
com.ryg.chapter_2.aidl.IOnNewBookArrivedListener _arg0;
_arg0 = com.ryg.chapter_2.aidl.IOnNewBookArrivedListener.Stub
.asInterface(data.readStrongBinder());
this.registerListener(_arg0);
reply.writeNoException();
return true;
}
case TRANSACTION_unregisterListener: {
data.enforceInterface(DESCRIPTOR);
com.ryg.chapter_2.aidl.IOnNewBookArrivedListener _arg0;
_arg0 = com.ryg.chapter_2.aidl.IOnNewBookArrivedListener.Stub
.asInterface(data.readStrongBinder());
this.unregisterListener(_arg0);
reply.writeNoException();
return true;
}
}
return super.onTransact(code, data, reply, flags);
}
private static class Proxy implements
com.ryg.chapter_2.aidl.IBookManager {
private android.os.IBinder mRemote;
Proxy(android.os.IBinder remote) {
mRemote = remote;
}
@Override
public android.os.IBinder asBinder() {
return mRemote;
}
public java.lang.String getInterfaceDescriptor() {
return DESCRIPTOR;
}
@Override
public java.util.List<com.ryg.chapter_2.aidl.Book> getBookList()
throws android.os.RemoteException {
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
java.util.List<com.ryg.chapter_2.aidl.Book> _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
mRemote.transact(Stub.TRANSACTION_getBookList, _data,
_reply, 0);
_reply.readException();
_result = _reply
.createTypedArrayList(com.ryg.chapter_2.aidl.Book.CREATOR);
} finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
@Override
public void addBook(com.ryg.chapter_2.aidl.Book book)
throws android.os.RemoteException {
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
try {
_data.writeInterfaceToken(DESCRIPTOR);
if ((book != null)) {
_data.writeInt(1);
book.writeToParcel(_data, 0);
} else {
_data.writeInt(0);
}
mRemote.transact(Stub.TRANSACTION_addBook, _data, _reply, 0);
_reply.readException();
} finally {
_reply.recycle();
_data.recycle();
}
}
@Override
public void registerListener(
com.ryg.chapter_2.aidl.IOnNewBookArrivedListener listener)
throws android.os.RemoteException {
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
try {
_data.writeInterfaceToken(DESCRIPTOR);
_data.writeStrongBinder((((listener != null)) ? (listener
.asBinder()) : (null)));
mRemote.transact(Stub.TRANSACTION_registerListener, _data,
_reply, 0);
_reply.readException();
} finally {
_reply.recycle();
_data.recycle();
}
}
@Override
public void unregisterListener(
com.ryg.chapter_2.aidl.IOnNewBookArrivedListener listener)
throws android.os.RemoteException {
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
try {
_data.writeInterfaceToken(DESCRIPTOR);
_data.writeStrongBinder((((listener != null)) ? (listener
.asBinder()) : (null)));
mRemote.transact(Stub.TRANSACTION_unregisterListener,
_data, _reply, 0);
_reply.readException();
} finally {
_reply.recycle();
_data.recycle();
}
}
}
static final int TRANSACTION_getBookList = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
static final int TRANSACTION_addBook = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
static final int TRANSACTION_registerListener = (android.os.IBinder.FIRST_CALL_TRANSACTION + 2);
static final int TRANSACTION_unregisterListener = (android.os.IBinder.FIRST_CALL_TRANSACTION + 3);
}
public java.util.List<com.ryg.chapter_2.aidl.Book> getBookList()
throws android.os.RemoteException;
public void addBook(com.ryg.chapter_2.aidl.Book book)
throws android.os.RemoteException;
public void registerListener(
com.ryg.chapter_2.aidl.IOnNewBookArrivedListener listener)
throws android.os.RemoteException;
public void unregisterListener(
com.ryg.chapter_2.aidl.IOnNewBookArrivedListener listener)
throws android.os.RemoteException;
}(1):首先,它申明了倆個(gè)方法getBookList和addBook,顯然這就是我們?cè)贗bookManager.aidl中所申明的方法。同時(shí)它還倆個(gè)整形的id分別用于表示這倆個(gè)方法。(2):接著,它申明了一個(gè)內(nèi)部類Stub,這個(gè)Stub就是一個(gè)Binder類,當(dāng)客戶端和服務(wù)端都位于同一個(gè)進(jìn)程時(shí),方法調(diào)用不會(huì)走跨進(jìn)程的transact過程,而當(dāng)倆者位于不同進(jìn)程時(shí),方法調(diào)用走transact過程,這個(gè)邏輯是由于Stub的內(nèi)部代理類Proxy來完成。這么看來,IbookManager這個(gè)接口的確很簡(jiǎn)單,但是我們也應(yīng)該認(rèn)識(shí)到,這個(gè)接口的核心實(shí)現(xiàn)就是它的內(nèi)部類Stub和Stub的內(nèi)部代理類Proxy.DESCRIPTORBinder的唯一標(biāo)識(shí),一般用當(dāng)前Binder的類名表示,比如本例中的com.ryg.chapter_2.aidl.IBookManagerasInterface用于將服務(wù)端的Binder對(duì)象轉(zhuǎn)換成客戶端所需的AIDL接口對(duì)象的類型,這種轉(zhuǎn)換過程是區(qū)分進(jìn)程的,如果客戶端和服務(wù)端位于同一進(jìn)程,那么此方法返回的就是服務(wù)端的Stub對(duì)象本身,否則返回的就是系統(tǒng)封裝后的Stub.proxy對(duì)象。asBinder此方法返回當(dāng)前Binder對(duì)象onTransact這個(gè)方法運(yùn)行在服務(wù)端中的Binder線程池中,當(dāng)客戶端發(fā)起跨進(jìn)程請(qǐng)求時(shí),遠(yuǎn)程請(qǐng)求會(huì)通過底層封裝后交由此方法來處理。服務(wù)端通過code可以確定客戶端所請(qǐng)求的目標(biāo)到底是什么。當(dāng)目標(biāo)方法執(zhí)行完畢后,就向reply中寫入返回值。需要注意的是,如果此方法返回false,那么客戶端的請(qǐng)求會(huì)失敗,因此我們可以利用這個(gè)特性來進(jìn)行權(quán)限認(rèn)證,畢竟我們也不希望隨便一個(gè)進(jìn)程都能遠(yuǎn)程調(diào)用我們的服務(wù)。雖然我們知道了BInder的工作機(jī)制,但是還需要說明倆點(diǎn):1.當(dāng)客戶端發(fā)起遠(yuǎn)程請(qǐng)求時(shí),由于當(dāng)前線程會(huì)被掛起直至服務(wù)端進(jìn)程返回?cái)?shù)據(jù),所以如果一個(gè)遠(yuǎn)程方法很耗時(shí),那么不能在UI線程中發(fā)起此遠(yuǎn)程請(qǐng)求。2.由于服務(wù)器的Binder方法運(yùn)行在Binder線程池,所以Binder方法不管是否耗時(shí)都應(yīng)該采用同步的方式去實(shí)現(xiàn)。,因?yàn)樗呀?jīng)運(yùn)行在一個(gè)線程中了。四、Binder機(jī)制的工作流程
從上面我們可以知道Binder工作機(jī)制的流程:
1.客戶端獲取服務(wù)端的帶來對(duì)象(proxy)。我們需要明確的是客戶端進(jìn)程并不能直接操作服務(wù)端中的方法,如果要操作服務(wù)端中的方法,那么有一個(gè)可行的解決方法就是在客戶端建立一個(gè)服務(wù)端進(jìn)程的代理對(duì)象,這個(gè)代理對(duì)象具備和服務(wù)端進(jìn)程一樣的功能,要訪問服務(wù)端進(jìn)程中的某個(gè)方法,只需要訪問代理對(duì)象中對(duì)應(yīng)的方法即可;
2.客戶端通過調(diào)用代理對(duì)象向服務(wù)端發(fā)送請(qǐng)求。
3.代理對(duì)象將用戶請(qǐng)求通過Binder驅(qū)動(dòng)發(fā)送到服務(wù)器進(jìn)程;
4.服務(wù)端進(jìn)程處理客戶端發(fā)過來的請(qǐng)求,處理完之后通過Binder驅(qū)動(dòng)返回處理結(jié)果給客戶端的服務(wù)端代理對(duì)象;
5.代理對(duì)象將請(qǐng)求結(jié)果進(jìn)一步返回給客戶端進(jìn)程。
通過以上5個(gè)步驟,就完成了一次Binder通信。
下面我們給出一張Binder的工作機(jī)制圖
源碼下載
新聞熱點(diǎn)
疑難解答
圖片精選
網(wǎng)友關(guān)注