Binder學習(三)經過AIDL分析Binder通訊流程

概述

AIDL (Android Interface Definition Language) 是一種接口定義語言,用於生成能夠在Android設備上兩個進程之間進行PC的代碼。若是在一個進程中(例如Activity)要調用另外一個進程中(例如Service)對象的操做,就可使用AIDL生成可序列化的參數,來完成進程間通訊,也就是說,爲了簡化應用層進行IPC操做,Android提供了AIDL這門語言,在學習AIDL這門語言以前,咱們來看一下Android中IPC的具體流程。java

IPC具體的實際過程
IPC具體的實際過程

  • Client發起一個請求,阻塞
  • Client拿到服務端的Proxy,調用Proxy的相應方法
  • Proxy去跟Server進行交互,請求相應的結果
  • Proxy拿到結果返回給客戶端

Client跟Proxy進行交互的數據不須要進行序列化,可是Proxy跟Server進行交互的時候必須進行序列化跟反序列化android

其實咱們在實際進行IPC的時候並不須要關注Proxy以及Binder Driver,上述模型能夠再次進行抽象bash

Binder抽象模型
Binder抽象模型

client端:BpBinder.transact()來發送事務請求;
server端:BBinder.onTransact()會接收到相應事務。app

正文

數據類型

AIDL默認支持以下數據類型:ide

  • 基本數據類型
  • List集合
  • Map集合
  • String類型
  • CharSequence類型

若是定義的類型不是AIDL默認支持的類型,則須要使用Parcelable進行序列化。一類是用來定義parcelable對象,以供其餘AIDL文件使用AIDL中非默認支持的數據類型的。學習

文件類型

AIDL的文件後綴名爲.aidl,並非以前的.java,不過在使用AIDL進行通訊的過程當中,
aidl文件只是用來定義數據類型跟接口。ui

使用方法

建立一個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的核心,這個類是一個接口,下面先看一下這個接口的結構圖:this

PeopleManager
PeopleManager

PeopleManager內部實現了PeopleManager.aidl的兩個方法,而且在內部建立了一個叫Stub的內部類,同時Stub也本身維護了一個叫作Proxy的內部類,經過前面對Binder機制的原理分析,咱們其實能夠很明確的知道,Proxy就是服務端的代理類,他做爲一個 中間代理,承載了Client與Server之間的轉化,而Stub類的onTransact方法就是用來接收Proxy的輸入而且把請求結果返回,從而達到代理的做用,因此分析AIDL實際上只須要注重分析一下asInterface,onTransact這兩個方法以及Proxy代理類便可。 spa

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機制。

BInder工做機制
BInder工做機制

經過觀察這張圖,咱們能夠AIDL底層對Binder機制進行了封裝,讓Android中的IPC通訊機制更加簡單方便,固然,咱們也能夠本身動手寫,固然Android中還有別的不少IPC通訊方式,例如Messenger等,。若是想實現Binder機制進行通訊,只須要Server(在Android裏面大多數使用Service來建立一個Server)端返回一個Binder對象,而後將調用asInterface將Binder對象傳遞過來便可。

參考資料

Android開發藝術探索

相關文章
相關標籤/搜索