概述
AIDL (Android Interface Definition Language) 是一種介面定義語言,用於生成可以在Android裝置上兩個程式之間進行PC的程式碼。如果在一個程式中(例如Activity)要呼叫另一個程式中(例如Service)物件的操作,就可以使用AIDL生成可序列化的引數,來完成程式間通訊,也就是說,為了簡化應用層進行IPC操作,Android提供了AIDL這門語言,在學習AIDL這門語言之前,我們來看一下Android中IPC的具體流程。
- Client發起一個請求,阻塞
- Client拿到服務端的Proxy,呼叫Proxy的相應方法
- Proxy去跟Server進行互動,請求相應的結果
- Proxy拿到結果返回給客戶端
Client跟Proxy進行互動的資料不需要進行序列化,但是Proxy跟Server進行互動的時候必須進行序列化跟反序列化
其實我們在實際進行IPC的時候並不需要關注Proxy以及Binder Driver,上述模型可以再次進行抽象
client端:BpBinder.transact()來傳送事務請求;
server端:BBinder.onTransact()會接收到相應事務。
正文
資料型別
AIDL預設支援如下資料型別:
- 基本資料型別
- List集合
- Map集合
- String型別
- CharSequence型別
如果定義的型別不是AIDL預設支援的型別,則需要使用Parcelable進行序列化。一類是用來定義parcelable物件,以供其他AIDL檔案使用AIDL中非預設支援的資料型別的。
檔案型別
AIDL的檔案字尾名為.aidl,並不是之前的.java,不過在使用AIDL進行通訊的過程中,
aidl檔案只是用來定義資料型別跟介面。
使用方法
建立一個Parcelable 物件
public class People implements Parcelable {
private int age;
private String gender;
private String hobby;
//此處省略若干行程式碼
}複製程式碼
建立一個AIDL的類
package com.wustor.aidl;
// Declare any non-default types here with import statements
parcelable People;複製程式碼
建立一個AIDL的介面
package com.wustor.aidl;
// Declare any non-default types here with import statements
import com.wustor.aidl.People;
interface PeopleManager {
List<People> getPeople();
void addPeople(in People people);
}複製程式碼
檢視PeopleManager.java
Android系統會在".\app\build\generated\source\aidl\debug\com\wustor\aidl"的目錄下生成一個PeopleManager.java檔案,這個類就是AIDL的核心,這個類是一個介面,下面先看一下這個介面的結構圖:
PeopleManager內部實現了PeopleManager.aidl的兩個方法,並且在內部建立了一個叫Stub的內部類,同時Stub也自己維護了一個叫做Proxy的內部類,通過前面對Binder機制的原理分析,我們其實可以很明確的知道,Proxy就是服務端的代理類,他作為一個 中間代理,承載了Client與Server之間的轉化,而Stub類的onTransact方法就是用來接收Proxy的輸入並且把請求結果返回,從而達到代理的作用,所以分析AIDL實際上只需要注重分析一下asInterface,onTransact這兩個方法以及Proxy代理類即可。
asBinder
@Override
public android.os.IBinder asBinder() {
return this;
}複製程式碼
返回當前Binder物件
asInterface
此方法位於Client端
/**
* Cast an IBinder object into an com.wustor.aidl.PeopleManager interface,
* generating a proxy if needed.
*/
public static com.wustor.aidl.PeopleManager asInterface(android.os.IBinder obj) {
if ((obj == null)) {
return null;
}
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
//檢視本地是否存在這個類,不存在的話就重新建立
if (((iin != null) && (iin instanceof com.wustor.aidl.PeopleManager))) {
return ((com.wustor.aidl.PeopleManager) iin);
}
return new com.wustor.aidl.PeopleManager.Stub.Proxy(obj);
}複製程式碼
queryLocalInterface
public IInterface queryLocalInterface(String descriptor) {
if (mDescriptor.equals(descriptor)) {
return mOwner;
}
return null;
}
public void attachInterface(IInterface owner, String descriptor) {
mOwner = owner;
mDescriptor = descriptor;
}複製程式碼
首先會呼叫queryLocalInterface來判斷descriptor跟mDescriptor是否相等,我們通過檢視Binder的原始碼可以看到descriptor就是當前PeopleManager的類名,那麼通過傳遞過來的Binder物件查詢這個類名,實際上就是判斷Server端的BookManager跟Client是不是相同,如果相同就說明Client跟Server是在同一個程式,如果在同一個程式,那麼就直接返回當前的IInterface ,否則返回null,那麼Client端就會自己建立一個Proxy的代理類。
Proxy
getPeople()
static final int TRANSACTION_getPeople = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
static final int TRANSACTION_addPeople = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
@Override
public java.util.List<com.wustor.aidl.People> getPeople() throws android.os.RemoteException {
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
java.util.List<com.wustor.aidl.People> _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
//呼叫transact方法,傳遞引數
mRemote.transact(Stub.TRANSACTION_getPeople, _data, _reply, 0);
_reply.readException();
//拿到返回結果
_result = _reply.createTypedArrayList(com.wustor.aidl.People.CREATOR);
} finally {
_reply.recycle();
_data.recycle();
}
//返回引數給Client
return _result;
}複製程式碼
在Client呼叫,執行Transact方法,當前執行緒阻塞,服務端的onTransact方法會被呼叫,從reply中拿到返回值後,執行緒繼續執行。
addPeoplet
@Override
public void addPeople(com.wustor.aidl.People people) 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 ((people != null)) {
_data.writeInt(1);
people.writeToParcel(_data, 0);
} else {
_data.writeInt(0);
}
mRemote.transact(Stub.TRANSACTION_addPeople, _data, _reply, 0);
_reply.readException();
} finally {
_reply.recycle();
_data.recycle();
}
}複製程式碼
在Client執行,跟getPeople()方法基本一致,唯一的區別是此方法沒有返回值,所以不需要回寫Client
onTransact
@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_getPeople: {
data.enforceInterface(DESCRIPTOR);
java.util.List<com.wustor.aidl.People> _result = this.getPeople();
reply.writeNoException();
reply.writeTypedList(_result);
return true;
}
case TRANSACTION_addPeople: {
data.enforceInterface(DESCRIPTOR);
com.wustor.aidl.People _arg0;
if ((0 != data.readInt())) {
_arg0 = com.wustor.aidl.People.CREATOR.createFromParcel(data);
} else {
_arg0 = null;
}
this.addPeople(_arg0);
reply.writeNoException();
return true;
}
}
return super.onTransact(code, data, reply, flags);
}複製程式碼
執行在Server端,當Client端發起跨程式請求的時候,系統底層會返回Proxy代理,然後通過代理執行Client的方法,就會呼叫此方法。注意這個方法會從data取傳遞過來的引數,然後通過code判斷需要執行哪一個方法,執行完畢後,就返回值寫入reply中,此方法的返回值表明IPC請求是否成功。
總結
通過分析AIDL的原理,從而可以進一步理解Binder機制,總結一下,Android中利用Binder機制。
通過觀察這張圖,我們可以AIDL底層對Binder機制進行了封裝,讓Android中的IPC通訊機制更加簡單方便,當然,我們也可以自己動手寫,當然Android中還有別的很多IPC通訊方式,例如Messenger等,。如果想實現Binder機制進行通訊,只需要Server(在Android裡面大多數使用Service來建立一個Server)端返回一個Binder物件,然後將呼叫asInterface將Binder物件傳遞過來即可。