AIDL生成的java文件分析

aidl生成的java代碼是一個接口文件,這個接口繼承了android.os.IInterface,這個接口生成的java文件中一共包括兩個部分:
1、靜態內部抽象類Stub
2、聲明瞭具體的功能的抽象方法(aidl文件中聲明的方法)
如圖:


1460594-cc1b57abbb9759a8.png
1.png

看來這個類的重點就是在Stub中了,主要來分析一下Stub類。文字不夠,圖片來湊:


1460594-e9b2b75ece86aee4.png
2.png
1460594-9a4d60a3e383899e.png
3.png

從圖中可以看到,Stub中一共分爲以下幾個部分:
一、構造方法

   /**
     * Construct the stub at attach it to the interface.
     * 構造方法
     */
    public Stub() {
        this.attachInterface(this, DESCRIPTOR);
    }
     //binder中的方法
    public void attachInterface(IInterface owner, String descriptor) {
       mOwner = owner;
       mDescriptor = descriptor;
    }

構造方法中調用了binder中的attachInterface(IInterface owner, String descriptor)方法,其中descriptor可以看做是進程的唯一標識,IInterface c參數則把Stub自己傳了進去,這個在後面asInterface()方法中會用到。

二、asInterface(android.os.IBinder obj)方法。這個方法是在綁定服務成功後客戶端調用的,用於在獲取到服務端返回的IBInder對象後,將其轉換爲對應的具有功能方法的對象,畢竟IBinder只是一個具有跨進程傳輸的接口。(類似是把一個接口轉換成它對應的實現類,可以這麼理解,但並不是這樣的)

/**
     * Cast an IBinder object into an com.example.aidldemo2.OperateInterface interface,
     * generating a proxy if needed.
     * 根據服務返回的IBinder返回所需要具有相應的功能方法的實體類
     */
    public static com.example.aidldemo2.OperateInterface asInterface(android.os.IBinder obj) {
        if ((obj == null)) {
            return null;
        }
        //檢查傳過來的binder是否和現在的進程是同一進程,如果是,返回值不爲null
        android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
        if (((iin != null) && (iin instanceof com.example.aidldemo2.OperateInterface))) {
            return ((com.example.aidldemo2.OperateInterface) iin);
        }
        //不是同一進程,返回stub的poxy
        return new com.example.aidldemo2.OperateInterface.Stub.Proxy(obj);
    }

主要做了一件事,根據 android.os.IInterface iin = queryLocalInterface (DESCRIPTOR) 得到的結果返回不同的值。如果iin不空就返回iin,否則就返回Stub的一個代理類。看一下queryLocalInterface (DESCRIPTOR) 具體做了什麼操作:

/**
 * Use information supplied to attachInterface() to return the
 * associated IInterface if it matches the requested
 * descriptor.
 */
public IInterface queryLocalInterface(String descriptor) {
    if (mDescriptor.equals(descriptor)) {
        return mOwner;
    }
    return null;
}

如果(mDescriptor.equals(descriptor)) 爲true,就返回mOwner。表示如果在同一進程中,就返回mOwner,不在同一進程中就返回null。這個mOwner是誰呢,就是在Stub類在構造方法裏面傳進來的this。
public Stub() {
this.attachInterface(this, DESCRIPTOR);
}
//binder中的方法
public void attachInterface(IInterface owner, String descriptor) {
mOwner = owner;
mDescriptor = descriptor;
}
總之,這個方法的作用就是binder和現在的進程是同一進程,就返回Stub類,否則返回Stub的代理類Proxy類。至於Proxy,下面分析。

三、Stub的內部類Proxy類。

 //Stub的代理類,代理類只有在跨進程的時候用到。實現了接口,具有了相應的功能方法
  private static class Proxy implements com.example.aidldemo2.OperateInterface {
        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 {
            //把數據放到了Parcel中存儲
            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;
        }
    }

代理類實現了功能方法的接口,這樣就保證了和Stub類具有了相同的功能,只有這樣才能代理Stub行使相同的功能。主要看裏面方法的實現,這這個例子中,實現了add方法但是並沒有真正的去做add方法的業務功能,而是把參數封裝到了Parcel 中通過binder傳遞給了遠程的服務。可以看出綁定遠程服務後,要調用遠程服務的方法是通過執行這個代理類中的對應方法,該方法再通過 mRemote.transact(Stub.TRANSACTION_add, _data, _reply, 0)把數據傳遞到遠程服務,等遠程服務執行完後再通過代理 _result = _reply.readInt();獲取到結果返回給我們的程序的。其中Stub.TRANSACTION_add是這個方法的唯一標識,是告訴遠程進程我要調用哪個方法。
總結起來這個代理類就是負責本地進程和遠程進程之間的數據封裝和傳遞(調用binder傳遞數據)以及解析結果的。

四、Stub中的onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags)方法。這個方法作爲服務端的方法,負責接收遠程客戶端通過 mRemote.transact(Stub.TRANSACTION_add, _data, _reply, 0);發送過來的數據並處理的。

//接收通過跨進程傳遞過來的數據(包括調用的方法對應的code、方法參數)
    @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;
            }
        }
        return super.onTransact(code, data, reply, flags);
    }

這個方法的參數和上面提到的代理髮送數據 mRemote.transact(Stub.TRANSACTION_add, _data, _reply, 0)的參數一一對應,code指對應的要調用的add方法的唯一標識,data裏面存放着要執行的add方法需要的參數,reply用來存儲add方法執行完後要返回的結果。

到這裏aidl生成的java文件就分析完了,總結一下就是,整個文件的核心就是靜態內部抽象類Stub。Stub中包含了一下幾項內容:
1、asInterface(android.os.IBinder obj) 用來根據不同進程返回Stub類自己還是Proxy代理類
2、代理類proxy 用來向遠程進程包裝數據、發送數據、解析返回結果
3、onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags)方法 作爲服務端進程調用,用來處理客戶端進程傳遞過來的數據
4、接口的功能方法,Stub繼承了接口,這些方法用來處理客戶端進程的具體業務。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章