Android 進程間通信AIDL(二)

本文主要來分析一下AIDL實現原理,在Android進程間通信AIDL(一)學習如何使用AIDL時,在Client端用到了IRemoteService這么一個類,廢話不多說,直接貼代碼

/*
 * This file is auto-generated.  DO NOT MODIFY.
 * Original file: D:\\Android\\demo\\AIDLDemo\\app\\src\\main\\aidl\\com\\zx\\aidl\\demo\\IRemoteService.aidl
 */
package com.zx.aidl.demo;

public interface IRemoteService extends android.os.IInterface {
    /** Local-side IPC implementation stub class. */
    public static abstract class Stub extends android.os.Binder
            implements com.zx.aidl.demo.IRemoteService {
        private static final java.lang.String DESCRIPTOR = "com.zx.aidl.demo.IRemoteService";

        /** Construct the stub at attach it to the interface. */
        public Stub() {
            this.attachInterface(this, DESCRIPTOR);
        }

        /**
         * Cast an IBinder object into an com.zx.aidl.demo.IRemoteService interface,
         * generating a proxy if needed.
         */
        public static com.zx.aidl.demo.IRemoteService asInterface(android.os.IBinder obj) {
            if ((obj == null)) {
                return null;
            }
            android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
            if (((iin != null) && (iin instanceof com.zx.aidl.demo.IRemoteService))) {
                return ((com.zx.aidl.demo.IRemoteService) iin);
            }
            return new com.zx.aidl.demo.IRemoteService.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_addPerson: {
                    data.enforceInterface(DESCRIPTOR);
                    com.zx.aidl.demo.Person _arg0;
                    if ((0 != data.readInt())) {
                        _arg0 = com.zx.aidl.demo.Person.CREATOR.createFromParcel(data);
                    } else {
                        _arg0 = null;
                    }
                    this.addPerson(_arg0);
                    reply.writeNoException();
                    return true;
                }
                case TRANSACTION_getPersons: {
                    data.enforceInterface(DESCRIPTOR);
                    java.util.List<com.zx.aidl.demo.Person> _result = this.getPersons();
                    reply.writeNoException();
                    reply.writeTypedList(_result);
                    return true;
                }
            }
            return super.onTransact(code, data, reply, flags);
        }

        private static class Proxy implements com.zx.aidl.demo.IRemoteService {
            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 void addPerson(com.zx.aidl.demo.Person person)
                    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 ((person != null)) {
                        _data.writeInt(1);
                        person.writeToParcel(_data, 0);
                    } else {
                        _data.writeInt(0);
                    }
                    mRemote.transact(Stub.TRANSACTION_addPerson, _data, _reply, 0);
                    _reply.readException();
                } finally {
                    _reply.recycle();
                    _data.recycle();
                }
            }

            @Override public java.util.List<com.zx.aidl.demo.Person> getPersons()
                    throws android.os.RemoteException {
                android.os.Parcel _data = android.os.Parcel.obtain();
                android.os.Parcel _reply = android.os.Parcel.obtain();
                java.util.List<com.zx.aidl.demo.Person> _result;
                try {
                    _data.writeInterfaceToken(DESCRIPTOR);
                    mRemote.transact(Stub.TRANSACTION_getPersons, _data, _reply, 0);
                    _reply.readException();
                    _result = _reply.createTypedArrayList(com.zx.aidl.demo.Person.CREATOR);
                } finally {
                    _reply.recycle();
                    _data.recycle();
                }
                return _result;
            }
        }

        static final int TRANSACTION_addPerson = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
        static final int TRANSACTION_getPersons = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
    }

    public void addPerson(com.zx.aidl.demo.Person person) throws android.os.RemoteException;

    public java.util.List<com.zx.aidl.demo.Person> getPersons() throws android.os.RemoteException;
}

接下來我們一步一步分析上面代碼,首先看下它的注釋:

/*
 * This file is auto-generated.  DO NOT MODIFY.
 * Original file: D:\\Android\\demo\\AIDLDemo\\app\\src\\main\\aidl\\com\\zx\\aidl\\demo\\IRemoteService.aidl
 */

IRemoteService.java文件是SDK根據IRemoteService.aidl自動為我們生成的一個Java文件,并且不允許修改,那SDK為什么要為我們生成這個文件呢?首先我們知道ADIL進程間通信其實本質就是Binder機制,既然能讓客戶端訪問服務端,服務端就得公布其接口和方法供客戶端調用,IRemoteService正是充當了該角色,這里是SDK為了我們開發更簡單方便,自動生成了這么一個類,當然我們也可以自己手動去實現它。仔細查看這個接口,發現其結構其實很簡單,一個靜態內部抽象類和倆方法,我們來重點分析下內部抽象類Stub,主要來分析下它的幾個重要方法

  • asInterface(android.os.IBinder obj)
    這個方法其實是將Binder對象轉換成IRemoteService接口
 android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
            if (((iin != null) && (iin instanceof com.zx.aidl.demo.IRemoteService))) {
                return ((com.zx.aidl.demo.IRemoteService) iin);
            }
            return new com.zx.aidl.demo.IRemoteService.Stub.Proxy(obj);

首先它會通過傳入的binder對象參數去查詢本地是否有該接口,其實也是判斷是否是本地通信,如果是,直接返回該接口,查詢的時候會傳入DESCRIPTOR這么一個參數,這個參數其實是Binder的唯一標識,一般都采用類名,如果不是本地通信,會返回Proxy這么一個對象,并且將傳入了Binder對象作為參數,因為我們主要分析的是進程間通信,所以分析第二種情況,我們去看下Proxy這個類到底是什么鬼?

   private static class Proxy implements com.zx.aidl.demo.IRemoteService {
            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 void addPerson(com.zx.aidl.demo.Person person)
                    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 ((person != null)) {
                        _data.writeInt(1);
                        person.writeToParcel(_data, 0);
                    } else {
                        _data.writeInt(0);
                    }
                    mRemote.transact(Stub.TRANSACTION_addPerson, _data, _reply, 0);
                    _reply.readException();
                } finally {
                    _reply.recycle();
                    _data.recycle();
                }
            }

            @Override public java.util.List<com.zx.aidl.demo.Person> getPersons()
                    throws android.os.RemoteException {
                android.os.Parcel _data = android.os.Parcel.obtain();
                android.os.Parcel _reply = android.os.Parcel.obtain();
                java.util.List<com.zx.aidl.demo.Person> _result;
                try {
                    _data.writeInterfaceToken(DESCRIPTOR);
                    mRemote.transact(Stub.TRANSACTION_getPersons, _data, _reply, 0);
                    _reply.readException();
                    _result = _reply.createTypedArrayList(com.zx.aidl.demo.Person.CREATOR);
                } finally {
                    _reply.recycle();
                    _data.recycle();
                }
                return _result;
            }
        }

        static final int TRANSACTION_addPerson = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
        static final int TRANSACTION_getPersons = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
    }

Proxy是Stub的一個靜態內部類,從字面意思就知道它其實是一個代理類,那它到底代理的是誰?顯然Proxy內部持有了一個 Ibinder 變量,所以它其實Binder的代理,其實也就是Stub的代理對象,Proxy也實現了IRemoteService接口以及addPerson和getPersons方法,我們這里選擇getPersons這個方法來分析,看它內部到底做了那些操作,為什么不用addPerson呢,沒什么原因,因為原理都一樣,就隨便拿一個方法來分析

       @Override public java.util.List<com.zx.aidl.demo.Person> getPersons()
                    throws android.os.RemoteException {
                android.os.Parcel _data = android.os.Parcel.obtain();
                android.os.Parcel _reply = android.os.Parcel.obtain();
                java.util.List<com.zx.aidl.demo.Person> _result;
                try {
                    _data.writeInterfaceToken(DESCRIPTOR);
                    mRemote.transact(Stub.TRANSACTION_getPersons, _data, _reply, 0);
                    _reply.readException();
                    _result = _reply.createTypedArrayList(com.zx.aidl.demo.Person.CREATOR);
                } finally {
                    _reply.recycle();
                    _data.recycle();
                }
                return _result;
            }

從 asInterface(android.os.IBinder obj) 這個方法我們知道,其實在Client端拿到的是Proxy這個對象,所以它的addPerson和getPersons方法其實是運行在Client端的,首先會創建倆個Parcel參數,輸入新參數_data和_reply,同時創建了一個List返回對象_result,接下來主要分為三個步驟:

  1. 將方法參數信息寫入_data中
  2. 調用transact方法像服務端發起RPC(Remote Procedure Cal)遠程調用請求,同時掛起客戶端線程,等待服務端的onTransact方法返回結果
  3. 從_reply中拿到結果并返回然后喚醒客戶端線程
    這里說下第二步,transact方法時在底層執行的,所以我們這里不用去深究方法里到底做了什么,只需要知道該方方法向服務端的發送了一個請求,然后服務端會執行它的onTransact方法,那么onTransact到底在什么地方,其實就是Stub類里面的onTransact方法,接下來我們去看下Stub類里面的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_addPerson: {
                    data.enforceInterface(DESCRIPTOR);
                    com.zx.aidl.demo.Person _arg0;
                    if ((0 != data.readInt())) {
                        _arg0 = com.zx.aidl.demo.Person.CREATOR.createFromParcel(data);
                    } else {
                        _arg0 = null;
                    }
                    this.addPerson(_arg0);
                    reply.writeNoException();
                    return true;
                }
                case TRANSACTION_getPersons: {
                    data.enforceInterface(DESCRIPTOR);
                    java.util.List<com.zx.aidl.demo.Person> _result = this.getPersons();
                    reply.writeNoException();
                    reply.writeTypedList(_result);
                    return true;
                }
            }
            return super.onTransact(code, data, reply, flags);
        }

首先會根據code去判斷客戶端請求目標方法,這里的code就是我們在上面transact方法中傳入的Stub.TRANSACTION_getPersons,所以我們直接去看相對應的方法處理

                    data.enforceInterface(DESCRIPTOR);
                    java.util.List<com.zx.aidl.demo.Person> _result = this.getPersons();
                    reply.writeNoException();
                    reply.writeTypedList(_result);
                    return true;

首先它會去調用自身的getPersons方法,其實就是我們在Service里實現的getPersons方法

    private IRemoteService.Stub binder = new IRemoteService.Stub() {
        @Override public void addPerson(Person person) throws RemoteException {
            persons.add(person);
        }

        @Override public List<Person> getPersons() throws RemoteException {
            return persons;
        }
    };

然后將結果寫入reply中返回給我們的客戶端,需要注意的是,最后方法返回值是true,如果返回false的話,客戶端會請求失敗,到這里我們整個流程分析就已經結束,接下來我們做一個總結,先上個圖

  1. 客戶端通過asInterface(android.os.IBinder obj)得到代理對象Proxy
  2. 客戶端調用Proxy的getPersons方法,該方法內執行transact方法向服務端 發送遠程調用請求,并掛起客戶端線程
  3. 服務端得到請求后執行onTransact方法,調用自身的getPersons方法拿到結果,將結果返回給客戶端,喚醒客戶端線程
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容