AIDL 的理解&源碼分析

aidl通訊試所有的對象都得實現Parcelable 接口

onTransact() Binder 驅動執行完畢時需要回調的方法

Proxy 移動端IPC通訊的時候,消息都是通過Binder 進行傳遞的。
這個代理可以理解爲:IPC機制中,Android代碼 跟底層對應IPC的Binder驅動 之間進行通訊時的代理

asInterface() 查詢本地所有的aidl 接口,判斷該Binder對象是否爲一個本地的 Binder引用

然後bindService的時候,需要傳遞一個 ServiceConnection的內部類實現,在ServiceConnection內部類實現中
bindService(intent, conn, BIND_AUTO_CREATE);


    ServiceConnection conn=new ServiceConnection() {    
        //aidl鏈接失敗回調
        @Override
        public void onServiceDisconnected(ComponentName name) {
        }
        //aidl連接成功回調
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            //在系統內部將執行一下邏輯行爲
            /*public static com.aidl.lxcay.MyAidlInterface asInterface(android.os.IBinder obj) {
            * if ((obj == null)) {
            *   return null;
            * }
            * 查詢本地所有的aidl 的描述,判斷該Binder對象是否爲一個本地的 Binder引用
            * android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
            * if (((iin != null) && (iin instanceof com.aidl.lxcay.MyAidlInterface))) {
            * 返回定義好的代理接口
            * return ((com.aidl.lxcay.MyAidlInterface) iin);
            * }
            * 返回默認代理
            * return new com.aidl.lxcay.MyAidlInterface.Stub.Proxy(obj);
            * }
            */
            //這個localInterface 就是aidl裏面規定好的接口引用,即Binder 引用
            localInterface = Stub.asInterface(service);
            //在客戶端可以通過點擊事件執行這個引用裏對應的函數,如果執行成功,會在相應的Service裏面執行相應的 函數;
            //下面給出一個demo
        }
    };
    eg:
    //客戶端
    public void click(View v) throws RemoteException{
        Log.i(TAG, localInterface.login("24", 24)+"");

        Log.i(TAG, localInterface.sayHello(new Person("lxcay", 24))+"");
    }
    //服務端
    public class MyServices extends Service {
        @Override
        public IBinder onBind(Intent intent) {

            return new MyBind();
        }
        // class MyBind 繼承 Stub接口,爲什麼會重寫一下2個回調方法,是因爲在aidl文件對應的java代碼裏面有這句代碼
        /*
         * public static abstract class Stub extends android.os.Binder implements com.aidl.lxcay.MyAidlInterface {}
         * 在我自己定義的接口描述文件裏面就有 
         * interface MyAidlInterface {
         *      boolean login(String name,int age);
         *      String sayHello(in Person p);
         * }
         */
        class MyBind extends Stub{

            @Override
            public boolean login(String name, int age) throws RemoteException {

                return !name.equals(age);
            }

            @Override
            public String sayHello(Person p) throws RemoteException {
                return "lxcay hello world, hello aidl~";
            }
        }
    }

然後在客戶端跟服務端交互的時候,我們可以通過看 aidl對應系統生成的java類中的描述,來擼清楚來龍去脈

/*
 * This file is auto-generated.  DO NOT MODIFY.
 * Original file: D:\\SCode\\SogouGameSDKSample\\src\\com\\intfs\\MyAidlInterface.aidl
 */
package com.aidl.lxcay;

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

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

        /**
         * Cast an IBinder object into an com.aidl.lxcay.MyAidlInterface interface,
         * generating a proxy if needed.
         */
        public static com.aidl.lxcay.MyAidlInterface asInterface(android.os.IBinder obj) {
            if ((obj == null)) {
                return null;
            }
            android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
            if (((iin != null) && (iin instanceof com.aidl.lxcay.MyAidlInterface))) {
                return ((com.aidl.lxcay.MyAidlInterface) iin);
            }
            return new com.aidl.lxcay.MyAidlInterface.Stub.Proxy(obj);
        }
        //這個被重寫是因爲,咱們的com.aidl.lxcay.MyAidlInterface類extends android.os.IInterface 所以需要提供一個 asBinder 對象
        @Override
        public android.os.IBinder asBinder() {
            return this;
        }
        //這個是提供給Binder驅動在接受到消息的時候,回調的方法。裏面對應的就是aidl接口描述文件裏面的固定格式
        @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_login: {
                data.enforceInterface(DESCRIPTOR);
                java.lang.String _arg0;
                _arg0 = data.readString();
                int _arg1;
                _arg1 = data.readInt();
                //---------------->>
                boolean _result = this.login(_arg0, _arg1);
                reply.writeNoException();
                reply.writeInt(((_result) ? (1) : (0)));
                return true;
            }
            case TRANSACTION_sayHello: {
                data.enforceInterface(DESCRIPTOR);
                com.aidl.lxcay.Person _arg0;
                if ((0 != data.readInt())) {
                    _arg0 = com.aidl.lxcay.Person.CREATOR.createFromParcel(data);
                } else {
                    _arg0 = null;
                }
                ////------------------------>>
                java.lang.String _result = this.sayHello(_arg0);
                reply.writeNoException();
                reply.writeString(_result);
                return true;
            }
            }
            return super.onTransact(code, data, reply, flags);
        }
        //這個代理類,是客戶端跟服務端之間的一個橋樑,通過閱讀以下代碼 ①方法 跟②方法,我們可以大致知道他們之間是怎麼通訊的。
        private static class Proxy implements com.aidl.lxcay.MyAidlInterface {
            //mRemote 爲 Binder的引用
            private android.os.IBinder mRemote;

            Proxy(android.os.IBinder remote) {
                //在Binder 的驅動中 mRemote 也重載了transact() 函數
                mRemote = remote;
            }

            @Override
            public android.os.IBinder asBinder() {
                return mRemote;
            }

            public java.lang.String getInterfaceDescriptor() {
                return DESCRIPTOR;
            }
            //①方法
            @Override
            public boolean login(java.lang.String name, int age) throws android.os.RemoteException {
                android.os.Parcel _data = android.os.Parcel.obtain();
                android.os.Parcel _reply = android.os.Parcel.obtain();
                boolean _result;
                try {
                    _data.writeInterfaceToken(DESCRIPTOR);
                    _data.writeString(name);
                    _data.writeInt(age);

                    //在向Binder通訊的時候,執行以下一句代碼,驅動執行完畢之後成功,最後會回調 上面的
                    //public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags)方法
                    mRemote.transact(Stub.TRANSACTION_login, _data, _reply, 0);

                    _reply.readException();
                    _result = (0 != _reply.readInt());
                } finally {
                    _reply.recycle();
                    _data.recycle();
                }
                return _result;
            }
            //②方法
            @Override
            public java.lang.String sayHello(com.aidl.lxcay.Person p) throws android.os.RemoteException {
                android.os.Parcel _data = android.os.Parcel.obtain();
                android.os.Parcel _reply = android.os.Parcel.obtain();
                java.lang.String _result;
                try {
                    _data.writeInterfaceToken(DESCRIPTOR);
                    if ((p != null)) {
                        _data.writeInt(1);
                        p.writeToParcel(_data, 0);
                    } else {
                        _data.writeInt(0);
                    }
                    mRemote.transact(Stub.TRANSACTION_sayHello, _data, _reply, 0);
                    _reply.readException();
                    _result = _reply.readString();
                } finally {
                    _reply.recycle();
                    _data.recycle();
                }
                return _result;
            }
        }

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

    public boolean login(java.lang.String name, int age) throws android.os.RemoteException;

    public java.lang.String sayHello(com.aidl.lxcay.Person p) throws android.os.RemoteException;
}

ServiceManager 可以得到android系統的各個 ServiceManger對象,而每一個ServiceManger對象,又持有着各自對應的Binder 引用。
所以說,ServiceManager是Binder 驅動的一個引子,在IPC中 是客戶端和服務端進行通信的媒介

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