最近在重新看<Android開發(fā)藝術(shù)探索>準(zhǔn)備將閱讀的記錄下來,加深理解
Binder
從來類的角度來說,Binder就是Android的一個(gè)類,它繼承了IBinder接口
從IPC的角度來說,Binder是Android中的一個(gè)中的一種跨進(jìn)程通信方式,Binder還可以理解為一種虛擬的物理設(shè)備,它的設(shè)備驅(qū)動(dòng)是/dev/binder,該通信方式在Linux中沒有(由于耦合性太強(qiáng),而Linux沒有接納)
從Android Framework角度來說,Binder是ServiceManager連接各種Manager(ActivityManager、WindowManager等)和相應(yīng)的ManagerService的橋梁
從Android應(yīng)用層的角度來說,Binder是客戶端和服務(wù)端進(jìn)行通信的媒介,當(dāng)你bindService的時(shí)候,服務(wù)端會(huì)返回一個(gè)包含了服務(wù)端業(yè)務(wù)調(diào)用的Binder對象,通過這個(gè)Binder對象,客戶端就可以獲取服務(wù)端提供的服務(wù)或者數(shù)據(jù),這里的服務(wù)包括普通服務(wù)和基于AIDL的服務(wù)
Android開發(fā)中,Binder主要是用于Service中,包括了Aidl和Messenger,Messenger的底層實(shí)現(xiàn)其實(shí)就是AIDL.
我們新建一個(gè)aidl文件,build之后系統(tǒng)會(huì)自動(dòng)根據(jù)創(chuàng)建的aidl文件生成一個(gè)同名的java文件,他本質(zhì)是一個(gè)繼承了android.os.IInterface的接口,所有可以在Binder中傳輸?shù)慕涌诙夹枰^承IInterface這個(gè)接口.
系統(tǒng)生成的代碼中,會(huì)有之前在aidl中聲明的方法 同時(shí)有一個(gè)抽象的Stub類,這個(gè)Stub其實(shí)就是一個(gè)Binder類,同時(shí)在Stub中還有一個(gè)內(nèi)部Proxy類。
這里我繞了很久才明白為什么在Proxy內(nèi)的方法是運(yùn)行在客戶端的,onTransact的方法是運(yùn)行于服務(wù)端的,我們這里可以先看一下概念,后續(xù)會(huì)通過代碼進(jìn)行分析
首先可以查看一下Stub內(nèi)部的元素:
- DESCRIPTOR:唯一標(biāo)識(shí)符
- Stub():構(gòu)造函數(shù)
- asInterface(android.os.IBinder obj) :用于將遠(yuǎn)程的Binder對象轉(zhuǎn)換為客戶端所需要的AIDL對象.在此函數(shù)中,如果服務(wù)端和客戶端是處于同一進(jìn)程,返回的就是服務(wù)端的Stub對象,如果不是則會(huì)返回封裝的Stub.Proxy對象
- asBinder:返回當(dāng)前的Binder對象
-
onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags):該方法運(yùn)行與服務(wù)端的Binder線程池中,當(dāng)客戶端發(fā)起了跨進(jìn)程的請求時(shí),遠(yuǎn)程請求會(huì)通過系統(tǒng)底層封裝后交給該函數(shù)進(jìn)行處理,服務(wù)端可以通過code知道遠(yuǎn)程調(diào)用的是哪一個(gè)方法,將傳入的data中取出方法需要的參數(shù)(如果方法需要的話),然后執(zhí)行目標(biāo)方法.執(zhí)行完畢后將返回值放入到reply中,返回false的話客戶端的調(diào)用會(huì)失敗
Proxy類:代理類
內(nèi)部有一個(gè)android.os.IBinder的內(nèi)部變量mRemote,代表了遠(yuǎn)程的Ibinder對象,構(gòu)造函數(shù)為
Proxy(android.os.IBinder remote) {
mRemote = remote;
}
Proxy#聲明的方法:
這個(gè)方法會(huì)運(yùn)行在客戶端,當(dāng)客戶端進(jìn)行調(diào)用時(shí),首先會(huì)獲取到兩個(gè)Parcel對象,一個(gè)為傳入的數(shù)據(jù),一個(gè)為返回的數(shù)據(jù). 通過函數(shù)_data.writeInterfaceToken(DESCRIPTOR);將當(dāng)前遠(yuǎn)程的唯一描述符寫入,接著通過函數(shù)transact調(diào)用相應(yīng)的函數(shù)方法, 接著函數(shù)掛起,等待執(zhí)行完畢后會(huì)讀取返回到的數(shù)據(jù)然后返回.接著我們通過代碼來查看一下這個(gè)過程.
@Override
public java.util.List<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<Book> _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
mRemote.transact(Stub.TRANSACTION_getBookList, _data, _reply, 0);
_reply.readException();
_result = _reply.createTypedArrayList(com.hy.bindertest.Book.CREATOR);
}finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
接著我們進(jìn)入mRemote.transact()這個(gè)函數(shù)中.
/**
* Default implementation rewinds the parcels and calls onTransact. On
* the remote side, transact calls into the binder to do the IPC.
*/
public final boolean transact(int code, @NonNull Parcel data, @Nullable Parcel reply,
int flags)throws RemoteException {
if (false) Log.v("Binder", "Transact: " + code +" to " +this);
if (data !=null) {
data.setDataPosition(0);
}
boolean r = onTransact(code, data, reply, flags);//這里代用了onTransact方法
if (reply !=null) {
reply.setDataPosition(0);
}
return r;
}
會(huì)發(fā)現(xiàn)他最后調(diào)用的就是mRemote中的onTransact函數(shù),而mRemote這個(gè)遠(yuǎn)程Binder對象,是運(yùn)行于服務(wù)端的BInder線程中,所以這里也就是所說的onTransact方法運(yùn)行于服務(wù)端的Binder線程池中的原因,這時(shí)候當(dāng)前線程會(huì)被掛起,等待RPC過程結(jié)束后,當(dāng)前線程繼續(xù)進(jìn)行,然后從_replay中獲取到RPC過程返回的結(jié)果,最后返回_replay中的數(shù)據(jù).
所以,我們就知道,當(dāng)客戶端發(fā)起一次遠(yuǎn)程的調(diào)用時(shí),當(dāng)前的線程會(huì)被掛起知道服務(wù)端返回?cái)?shù)據(jù),所以一個(gè)遠(yuǎn)程函數(shù)是很耗時(shí)的,我們不能在UI線程中進(jìn)行調(diào)用,而服務(wù)器端的Binder方法是運(yùn)行于Binder的線程池中的,所以Binder中的方法我們不需要再開線程進(jìn)行執(zhí)行.
所以整個(gè)過程就比較清晰了:
首先客戶端發(fā)起一個(gè)遠(yuǎn)程的請求->Binder收到之后,將參數(shù)寫入到data中,調(diào)用transact方法執(zhí)行,遠(yuǎn)程的Service中的OnTransact函數(shù)指定函數(shù)被調(diào)用,將結(jié)果寫入到reply返回到Binder中,Binder獲取到結(jié)果,返回給Client;