1.Binder簡(jiǎn)介
我們知道舔涎,在Android操作系統(tǒng)中乱凿,每個(gè)進(jìn)程都擁有屬于自己的獨(dú)立虛擬地址空間(用戶(hù)空間+內(nèi)核空間)。一般情況下粱胜,進(jìn)程的用戶(hù)空間是各自獨(dú)立的,無(wú)法進(jìn)行數(shù)據(jù)共享狐树;而內(nèi)核空間卻是所有進(jìn)程都可以共同訪(fǎng)問(wèn)的焙压。
對(duì)于Android系統(tǒng)來(lái)說(shuō),其特有的IPC機(jī)制是Binder抑钟。正如其名字所喻(粘粘劑)涯曲,通過(guò)Binder作為橋梁,將系統(tǒng)各個(gè)進(jìn)程組件進(jìn)行連接在塔。
2.Binder優(yōu)點(diǎn)
1.Binder更加簡(jiǎn)潔和快速幻件,消耗的內(nèi)存資源更小。
2.傳統(tǒng)的進(jìn)程間通信可能會(huì)增加進(jìn)程的開(kāi)銷(xiāo)蛔溃,而且有進(jìn)程過(guò)載和安全漏洞等方面的風(fēng)險(xiǎn)绰沥,Binder正好能解決和避免這些問(wèn)題篱蝇。
3.用驅(qū)動(dòng)程序來(lái)推進(jìn)進(jìn)程間的通信。
4.通過(guò)共享內(nèi)存來(lái)提高性能徽曲。
5.為進(jìn)程請(qǐng)求分配每個(gè)進(jìn)程的線(xiàn)程池零截。
6.針對(duì)系統(tǒng)中的對(duì)象引入了引用計(jì)數(shù)和跨進(jìn)程的對(duì)象引用映射。
7.進(jìn)程間同步調(diào)用秃臣。
3.Binder實(shí)現(xiàn)IPC通訊原理
3.1 Binder IPC基礎(chǔ)組件
Binder通訊采用C/S架構(gòu)涧衙,其進(jìn)行IPC涉及到的組件主要包含Client,Server,ServerManager和binder驅(qū)動(dòng)。
Client:客戶(hù)端
Server:服務(wù)端
ServerManager:用于管理系統(tǒng)中的各種服務(wù)甜刻。提供服務(wù)注冊(cè)功能和查詢(xún)服務(wù)功能绍撞。(此處的ServerManager是Native層的ServiceManager(c++),不是framework層的ServerManager(java))。
binder驅(qū)動(dòng):位于內(nèi)核空間得院,提供Client傻铣,Server,ServerManager跨進(jìn)程通訊功能祥绞。
3.2實(shí)例講解
我們知道非洲,Android提供的AIDL通訊底層采用的就是Binder機(jī)制。現(xiàn)在我們采用AIDL方式創(chuàng)建2個(gè)應(yīng)用進(jìn)行進(jìn)程間通訊蜕径。
(1)首先定義aidl接口:
// IMath.aidl
package com.yn.bindertest.aidl;
// Declare any non-default types here with import statements
interface IMath {
int add(in int a,in int b);
void result(in int justTestWithoutReturnValue);
}
(2)服務(wù)端代碼編寫(xiě):
public class Server extends Service {
private static final String TAG = "ynServer";
@Nullable
@Override
public IBinder onBind(Intent intent) {
return new IMath.Stub(){
@Override
public int add(int a, int b) throws RemoteException {
Log.d(TAG, "add: "+Thread.currentThread().getName());
return a+b;
}
@Override
public void result(int justTestWithoutReturnValue) throws RemoteException {
Log.d(TAG, "result: "+Thread.currentThread().getName());
}
};
}
}
(3)客戶(hù)端代碼編寫(xiě):
public class MainActivity extends AppCompatActivity {
private static final String TAG = "ynClient";
private TextView tvShow;
private IMath mServer;
private ServiceConnection mServiceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
Log.d(TAG, "onServiceConnected: "+Thread.currentThread().getName());
mServer = IMath.Stub.asInterface(service);
try {
mServer.asBinder().linkToDeath(mDeathRecipient,0);
} catch (RemoteException e) {
e.printStackTrace();
}
}
@Override
public void onServiceDisconnected(ComponentName name) {
Log.d(TAG, "onServiceDisconnected: "+Thread.currentThread().getName());
}
};
private IBinder.DeathRecipient mDeathRecipient = new IBinder.DeathRecipient(){
@Override
public void binderDied() {
Log.d(TAG, "binderDied: "+Thread.currentThread().getName());
bindService(new Intent(MainActivity.this, Server.class),mServiceConnection , Context.BIND_AUTO_CREATE);
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
tvShow = (TextView)findViewById(R.id.tvShow);
bindService(new Intent(this, Server.class),mServiceConnection , Context.BIND_AUTO_CREATE);
}
public void onClick(View view)
{
try {
int sum = mServer.add(10,30);
Log.d(TAG, "onClick: sum="+sum);
tvShow.setText(sum+"");
} catch (RemoteException e) {
e.printStackTrace();
}
}
}
(4)記得在AndroidManifest.xml中將Service設(shè)置到另一個(gè)進(jìn)程中两踏。
<service
android:name=".Server"
android:process="com.yn.bindertest.server" />
通過(guò)以上步驟,我們就實(shí)現(xiàn)了使用AIDL進(jìn)行跨進(jìn)程通訊功能兜喻,結(jié)果如下:
當(dāng)程序啟動(dòng)時(shí)梦染,bindService()成功時(shí)就會(huì)回調(diào)onServiceConnected,然后手動(dòng)調(diào)用add可以看到add過(guò)程是運(yùn)行在Server端的binder線(xiàn)程池中的朴皆;由于為Server設(shè)置了死亡代理帕识,當(dāng)服務(wù)端異常被kill時(shí),會(huì)回調(diào)死亡代理IBinder.DeathRecipient.binderDied和ServiceConnection.onServiceDisconnected遂铡,兩者的區(qū)別就是binderDied是運(yùn)行在客戶(hù)端的binder線(xiàn)程池中的肮疗,而onServiceDisconnected是運(yùn)行在主線(xiàn)程中的。
更關(guān)鍵的一點(diǎn)是:當(dāng)客戶(hù)端調(diào)用遠(yuǎn)程函數(shù)時(shí)扒接,客戶(hù)端進(jìn)程會(huì)被掛起伪货,等待遠(yuǎn)程服務(wù)端執(zhí)行完成后才重新運(yùn)行客戶(hù)端進(jìn)程,因此钾怔,這是一個(gè)同步調(diào)用碱呼,應(yīng)小心因?yàn)榉?wù)端的耗時(shí)方法導(dǎo)致客戶(hù)端發(fā)生ANR。
3.3 aidl的binder機(jī)制講解
當(dāng)我們創(chuàng)建完成IMath.aidl文件后宗侦,rebuild一下巍举,可以看到IDE為我們生成了一個(gè).java文件,路徑為:app\build\generated\source\aidl\debug\com\yn\bindertest\aidl\IMath.java
該IMath.java的具體內(nèi)容如下:
可以看到凝垛,IDE為我們自動(dòng)生成的其實(shí)就是一個(gè)繼承了IInterface的接口懊悯,生成的接口類(lèi)名和方法與我們aidl中聲明的完全一致蜓谋,只是另外增加了一個(gè)Stub內(nèi)部抽象靜態(tài)類(lèi),而這個(gè)Stub類(lèi)繼承了Binder并且實(shí)現(xiàn)了我們這個(gè)IMath(由于IMath繼承了IInterface,而IInterface只有一個(gè)接口方法asBinder),所以這個(gè)Stub類(lèi)就是一個(gè)Binder炭分,并且必須實(shí)現(xiàn)我們自己定義的IMath中的接口方法桃焕,并提供asBinder方法給到系統(tǒng)調(diào)用。
所以這個(gè)Stub類(lèi)才是我們要著重進(jìn)行研究的捧毛,那么這個(gè)Stub類(lèi)的具體如下所示:
/**
* Local-side IPC implementation stub class.
*/
public static abstract class Stub extends android.os.Binder implements com.yn.bindertest.aidl.IMath {
private static final java.lang.String DESCRIPTOR = "com.yn.bindertest.aidl.IMath";
/**
* Construct the stub at attach it to the interface.
*/
public Stub() {
this.attachInterface(this, DESCRIPTOR);
}
/**
* Cast an IBinder object into an com.yn.bindertest.aidl.IMath interface,
* generating a proxy if needed.
*/
public static com.yn.bindertest.aidl.IMath asInterface(android.os.IBinder obj) {
if ((obj == null)) {
return null;
}
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin != null) && (iin instanceof com.yn.bindertest.aidl.IMath))) {
return ((com.yn.bindertest.aidl.IMath) iin);
}
return new com.yn.bindertest.aidl.IMath.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_add: {
data.enforceInterface(DESCRIPTOR);
int _arg0;
_arg0 = data.readInt();
int _arg1;
_arg1 = data.readInt();
int _result = this.add(_arg0, _arg1);
reply.writeNoException();
reply.writeInt(_result);
return true;
}
case TRANSACTION_result: {
data.enforceInterface(DESCRIPTOR);
int _arg0;
_arg0 = data.readInt();
this.result(_arg0);
reply.writeNoException();
return true;
}
}
return super.onTransact(code, data, reply, flags);
}
private static class Proxy implements com.yn.bindertest.aidl.IMath {
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 int add(int a, int b) throws android.os.RemoteException {
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
int _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
_data.writeInt(a);
_data.writeInt(b);
mRemote.transact(Stub.TRANSACTION_add, _data, _reply, 0);
_reply.readException();
_result = _reply.readInt();
} finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
@Override
public void result(int justTestWithoutReturnValue) 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.writeInt(justTestWithoutReturnValue);
mRemote.transact(Stub.TRANSACTION_result, _data, _reply, 0);
_reply.readException();
} finally {
_reply.recycle();
_data.recycle();
}
}
}
static final int TRANSACTION_add = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
static final int TRANSACTION_result = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
}
看一下asInterface()內(nèi)容:
可以看出观堂,通過(guò)DESCRIPTOR(即包名+類(lèi)名:"com.yn.bindertest.aidl.IMath")先進(jìn)行本地查找,如果找到呀忧,那么返回本地binder類(lèi)對(duì)象(即onBind返回的那個(gè)binder對(duì)象)师痕,如果找不到,那么返回一個(gè)binder代理類(lèi)而账,這個(gè)代理類(lèi)具體內(nèi)容如下:
private static class Proxy implements com.yn.bindertest.aidl.IMath {
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 int add(int a, int b) throws android.os.RemoteException {
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
int _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
_data.writeInt(a);
_data.writeInt(b);
mRemote.transact(Stub.TRANSACTION_add, _data, _reply, 0);
_reply.readException();
_result = _reply.readInt();
} finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
@Override
public void result(int justTestWithoutReturnValue) 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.writeInt(justTestWithoutReturnValue);
mRemote.transact(Stub.TRANSACTION_result, _data, _reply, 0);
_reply.readException();
} finally {
_reply.recycle();
_data.recycle();
}
}
}
可以看到胰坟,這個(gè)Proxy也實(shí)現(xiàn)了IMath接口,并且持有一個(gè)遠(yuǎn)程服務(wù)的IBinder對(duì)象(其實(shí)這個(gè)IBinder是一個(gè)BinderProxy對(duì)象泞辐,是bindservice時(shí)笔横,向ServiceManager獲取得到的)。所以咐吼,當(dāng)處于不同的進(jìn)程時(shí)吹缔,客戶(hù)端得到的是一個(gè)Proxy代理類(lèi),然后由于該代理類(lèi)實(shí)現(xiàn)了aidl定義的接口锯茄,并且持有一個(gè)遠(yuǎn)程IBinder接口厢塘,所以在調(diào)用aidl接口方法時(shí),可以看到肌幽,它通過(guò)將函數(shù)參數(shù)放入到一個(gè)Parcel(_data)中晚碾,提供一個(gè)Parcel(_reply)存儲(chǔ)返回結(jié)果(如果有返回的話(huà)),然后通過(guò)持有的遠(yuǎn)程IBinder對(duì)象的transact將函數(shù)標(biāo)識(shí)牍颈,參數(shù)Parcel和返回結(jié)果Parcel發(fā)送給遠(yuǎn)程服務(wù),客戶(hù)端調(diào)用transact時(shí)琅关,客戶(hù)端進(jìn)程被掛起煮岁,然后通過(guò)binder驅(qū)動(dòng)調(diào)用到遠(yuǎn)程服務(wù)的onTransact函數(shù),通過(guò)傳遞過(guò)來(lái)的函數(shù)標(biāo)識(shí)涣易,就可以知道要執(zhí)行哪個(gè)函數(shù)画机,然后取出對(duì)應(yīng)的函數(shù)參數(shù),運(yùn)行完成后新症,將返回結(jié)果存儲(chǔ)到_reply中步氏,通過(guò)binder驅(qū)動(dòng)返回給客戶(hù)端,客戶(hù)端只要讀取_reply就可以獲取到結(jié)果徒爹。這樣荚醒,就完成了一次IPC通訊芋类。
綜上所述,通過(guò)aidl實(shí)現(xiàn)IPC的原理如下:
1.IDE根據(jù)我們定義的aidl生成一個(gè)同名接口界阁,并繼承IInterface,目的是為了客戶(hù)端可以通過(guò)asBinder獲取到binder對(duì)象(同個(gè)進(jìn)程則獲取的是同一個(gè)binder侯繁,不同進(jìn)程獲取到的是一個(gè)BinderProxy代理對(duì)象)。
2.當(dāng)Server(Service)啟動(dòng)時(shí)泡躯,它會(huì)通過(guò)binder驅(qū)動(dòng)向ServiceManager進(jìn)行注冊(cè)(binder標(biāo)識(shí)+binder引用)贮竟;當(dāng)Client要獲取遠(yuǎn)程服務(wù)(bindservice)時(shí),它首先要通過(guò)binder驅(qū)動(dòng)向ServiceManger獲取特定遠(yuǎn)程服務(wù)的binder引用较剃,獲取成功后咕别,就可以對(duì)遠(yuǎn)程服務(wù)進(jìn)行IPC通訊(也是通過(guò)binder驅(qū)動(dòng))。
總結(jié)
應(yīng)用間通過(guò)Binder實(shí)現(xiàn)IPC的整體過(guò)程如下圖所示:
1.當(dāng)Server啟動(dòng)時(shí)写穴,它會(huì)通過(guò)進(jìn)程內(nèi)的0號(hào)binder引用惰拱,將服務(wù)名和binder傳遞給內(nèi)核0號(hào)binder引用,再依次傳給ServiceManager內(nèi)核binder實(shí)體确垫,最后傳入ServiceManager的進(jìn)程binder中弓颈。經(jīng)過(guò)這個(gè)過(guò)程后,ServiceManager內(nèi)部就記錄了Server相應(yīng)的信息删掀,該過(guò)程即是Server向ServiceManager的注冊(cè)過(guò)程翔冀。
2.當(dāng)Client要進(jìn)行遠(yuǎn)程服務(wù)通訊時(shí),它首先會(huì)經(jīng)由進(jìn)程內(nèi)0號(hào)binder引用通知到內(nèi)核0號(hào)binder引用披泪,然后經(jīng)由ServiceManager內(nèi)核binder實(shí)體纤子,最后將所需的服務(wù)信息傳入到ServiceManager進(jìn)程的binder實(shí)體中,那么ServiceManager通過(guò)查詢(xún)相關(guān)服務(wù)信息款票,如果存在對(duì)應(yīng)服務(wù)控硼,就會(huì)通過(guò)binder驅(qū)動(dòng)傳遞一個(gè)擁有訪(fǎng)問(wèn)遠(yuǎn)程服務(wù)能力的BinderProxy給到Client(即bindservice時(shí),onServiceConnection中的onConnected中的IBinder參數(shù))艾少。這個(gè)過(guò)程就是Client的獲取遠(yuǎn)程服務(wù)過(guò)程卡乾。
3.Client獲取遠(yuǎn)程服務(wù)成功后嫩舟,就可以通過(guò)ServiceManager傳遞過(guò)來(lái)的BinderProxy對(duì)象創(chuàng)建出一個(gè)遠(yuǎn)程服務(wù)Binder的代理類(lèi)對(duì)象(asInterface)筷弦,通過(guò)這個(gè)代理類(lèi)對(duì)象,Client就可以執(zhí)行遠(yuǎn)程服務(wù)相關(guān)方法了傍菇,從而實(shí)現(xiàn)跨進(jìn)程IPC通訊谍椅。
4.當(dāng)Client調(diào)用遠(yuǎn)程方法時(shí)误堡,本地遠(yuǎn)程binder的代理類(lèi)對(duì)象會(huì)調(diào)用其持有的BinderProxy對(duì)象的transact方法,這個(gè)方法會(huì)將要調(diào)用的函數(shù)標(biāo)識(shí)雏吭,參數(shù)和返回值(如果有的話(huà))放入到Client的共享內(nèi)存中锁施,然后經(jīng)由內(nèi)核binder驅(qū)動(dòng)運(yùn)輸?shù)较鄳?yīng)遠(yuǎn)程服務(wù)的共享內(nèi)存中,然后遠(yuǎn)程服務(wù)的進(jìn)程binder實(shí)體的onTransact函數(shù)會(huì)被調(diào)用,這個(gè)函數(shù)的功能就是從共享內(nèi)存中獲取傳遞過(guò)來(lái)的相關(guān)信息悉抵,通過(guò)函數(shù)標(biāo)識(shí)就知道要運(yùn)行哪個(gè)函數(shù)肩狂,然后再將相關(guān)的參數(shù)提取出來(lái)(如果有的話(huà)),執(zhí)行完畢后基跑,就將返回結(jié)果存入之前傳遞過(guò)來(lái)的容器(Parcel)內(nèi)婚温,最后經(jīng)由內(nèi)核binder驅(qū)動(dòng)傳遞回給到Client中。這樣媳否,一次完整的binder IPC通訊就完成了栅螟。