請(qǐng)尊重原創(chuàng),轉(zhuǎn)載請(qǐng)注明出處【tianyl】的博客
前言
說到Android,有一個(gè)繞不過去的知識(shí)點(diǎn)就是IPC,也叫進(jìn)程間通信,鑒于市面上已經(jīng)很多Binder的深入解析,這里我也不說重復(fù)的話了,感覺從AIDl的角度聊聊BInder(因?yàn)槲铱春孟窈苌儆胁┛蛷倪@個(gè)角度切入)
本文概要
1 什么是Binder
2 什么Android要使用Binder作為IPC的方式?Linux現(xiàn)有的IPC方式不能用嗎
3 什么是AIDL,AIDL和BInder又是什么關(guān)系
4 AIDL的基礎(chǔ)用法
5 什么是Stub和Proxy,它們又是如何通信的?
1 什么是Binder
Binder是Android系統(tǒng)進(jìn)程間通信(IPC)方式之一,說到IPC,就要介紹一些Linux中的IPC方式
2 Linux的IPC方式
- 管道(Pipe)
- 一個(gè)線性的內(nèi)存區(qū)域,存消息時(shí)將數(shù)據(jù)寫入管道,取消息時(shí)從管道拷貝數(shù)據(jù),因?yàn)橛袃纱慰截悾ㄐ实停?/li>
- 插口(Socket)
- 是一個(gè)通用接口,導(dǎo)致其傳輸效率低,開銷大,有兩次拷貝(效率低)
- 報(bào)文隊(duì)列(Message)
- 有兩次拷貝(效率低)
- 共享內(nèi)存(Share Memory)
- 機(jī)制復(fù)雜,管理內(nèi)存機(jī)制復(fù)雜
- 信號(hào)量(Semaphore)
- 信號(hào)(Signal)
- 跟蹤(Trace)
3 Binder
3.1 Binder的優(yōu)點(diǎn)
- 安全性
- Linux的IPC機(jī)制在本身的實(shí)現(xiàn)中,并沒有安全措施,得依賴上層協(xié)議來進(jìn)行安全控制。而Binder機(jī)制的UID/PID是由Binder機(jī)制本身在內(nèi)核空間添加身份標(biāo)識(shí),安全性高
- 私有管道
- Binder可以建立私有通道,這是linux的通信機(jī)制所無法實(shí)現(xiàn)的(Linux訪問的接入點(diǎn)是開放的)
- 效率性
- LInux原有的IPC方式,要么是需要多次拷貝(2次或2次以上),要么則是機(jī)制復(fù)雜,而BInder只需要一次拷貝,在多線程時(shí)管理內(nèi)存也相對(duì)容易
所以從效率上和安全性上考慮,Google摒棄了LInux的IPC方式,重新構(gòu)建了一套屬于Android的IPC方式——BInder
4 Binder和AIDL
AIDL全稱:Android Interface Definition Language,Binder是IPC的機(jī)制,AIDL是Binder的具體規(guī)范
5 AIDL詳解
關(guān)于AIDL,它是Android Interface Definition Language,對(duì)于一個(gè).aild文件,它經(jīng)過IDE的處理后,會(huì)生成一個(gè)java文件
這個(gè)java類會(huì)實(shí)現(xiàn)android.os.IInterface接口,并且含有一個(gè)Stub的靜態(tài)抽象內(nèi)部類
public interface IAIDLTest extends android.os.IInterface
5.1 Stub
仔細(xì)查看抽象類Stub,它繼承了android.os.Binder,并實(shí)現(xiàn)了我們定義的AIDL接口
public static abstract class Stub extends android.os.Binder implements com.demo.tianyl.demo.IAIDLTest
5.2 Proxy
Proxy是抽象類Stub中的一個(gè)靜態(tài)內(nèi)部類,它也實(shí)現(xiàn)了我們定義的AIDL接口
private static class Proxy implements com.demo.tianyl.demo.IAIDLTest
5.3 Stub和Proxy
介紹完了Stub和Proxy的類的定義,下面來說說AIDL使用時(shí)它們之間的關(guān)系
1
首先要從我們定義的AIDL說起了,如果我們要使用AIDL,那么我們首先需要定義一個(gè)AIDL接口文件(IAidlTest.aidl),根據(jù)這個(gè).aidl文件自動(dòng)生成一個(gè).java文件,并且構(gòu)建一個(gè)Service實(shí)現(xiàn)我們定義的AIDL接口(AidlTestService.java),并且在manifest中注冊(cè)這個(gè)服務(wù)
2
在其他的進(jìn)程,需要使用AIDL的地方,調(diào)用bindService開啟這個(gè)服務(wù),然后在ServiceConnection中處理返回的IBinder對(duì)象
//開啟服務(wù)
bindService(service, mConnection, Context.BIND_AUTO_CREATE);
//處理IBinder對(duì)象
IAIDLTest mService = null
private ServiceConnection mConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
mService = IAIDLTest.Stub.asInterface(service)
}
@Override
public void onServiceDisconnected(ComponentName name) {
mService = null
}
};
3
說完了用法,下面來解析
首先在bindService中,獲得我們?cè)贏idlTestService.java(aidl實(shí)現(xiàn)類)中的onBind方法中返回的IBinder
實(shí)現(xiàn)類一般寫法如下
public class AidlTestService extends Service {
@Nullable
@Override
public IBinder onBind(Intent intent) {
return mBinder;
}
IAIDLTest.Stub mBinder = new IAIDLTest.Stub() {
//do something
};
}
4
然后在ServiceConnection中,處理上面返回的IBinder
mService = IAIDLTest.Stub.asInterface(service)
看內(nèi)部類Stub中的方法asInterface
public static com.demo.tianyl.demo.IAIDLTest asInterface(android.os.IBinder obj) {
if ((obj == null)) {
return null;
}
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin != null) && (iin instanceof com.demo.tianyl.demo.IAIDLTest))) {
return ((com.demo.tianyl.demo.IAIDLTest) iin);
}
return new com.demo.tianyl.demo.IAIDLTest.Stub.Proxy(obj);
}
asInterface方法會(huì)根據(jù)當(dāng)前的進(jìn)程還決定返回Stub或者Proxy
- 如果當(dāng)前進(jìn)程和AIDL定義的進(jìn)程相同,就返回Stub的實(shí)現(xiàn)類(AidlTestService.java)
- 如果當(dāng)前進(jìn)程和AIDL定義的進(jìn)程不同,就返回Proxy
所以我們可以猜到,AidlTestService.java是Stub的真實(shí)實(shí)現(xiàn)類,Proxy是Stub在其他進(jìn)程的代理實(shí)現(xiàn)類
5.4 Stub和Proxy的通信
說完了Stub和Proxy的關(guān)系,再說說它們是如何通信的
既然Proxy是Stub在其他進(jìn)程的實(shí)現(xiàn)類,那么其他進(jìn)程在調(diào)用AIDL接口中的方法時(shí),肯定是通過Proxy進(jìn)行的,例如一個(gè)求和方法add
1
Proxy中的方法如下
@Override
public int add(int x, int y) 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(x);
_data.writeInt(y);
mRemote.transact(Stub.TRANSACTION_add, _data, _reply, 0);
_reply.readException();
_result = _reply.readInt();
} finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
這個(gè)方法主要做了2件事
- 序列化參數(shù)x和y
- 調(diào)用mRemote.transact方法
其中Stub.TRANSACTION_add是定義的一個(gè)標(biāo)準(zhǔn)常量,用于確定調(diào)用的是哪個(gè)方法
static final int TRANSACTION_add = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
2
從mRemote的transact,會(huì)回調(diào)到Stub的onTransact,在這個(gè)方法中,會(huì)有
@Override
public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException {
java.lang.String descriptor = DESCRIPTOR;
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;
}
default: {
return super.onTransact(code, data, reply, flags);
}
}
}
在TRANSACTION_add分支中,會(huì)將參數(shù)反序列化,然后調(diào)用this.add(_arg0, _arg1),就是它的實(shí)現(xiàn)類,然后將結(jié)果回傳回去
6 總結(jié)
關(guān)于AIDL和Binder的相關(guān)描述,到此就結(jié)束了,因?yàn)榭紤]到已經(jīng)有不少源碼分析的博客,所以這里就較少的涉及源碼方面,想必開篇的問題,大家心中已經(jīng)有答案了吧