【Android】進程間通信IPC——Binder

Binder是Android中的跨進程通信方式,bindService的時候,服務端返回Binder對象,通過該對象客戶端可以從服務端獲取數據。
進程間通信IPC——AIDL中創建了ICustomAidlInterface.aidl。
以下是根據ICustomAidlInterface.aidl生成的ICustomAidlInterface.Java接口類。

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

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

        /**
         * Cast an IBinder object into an com.sjl.exercise.ICustomAidlInterface interface,
         * generating a proxy if needed.
         */
        public static com.sjl.exercise.ICustomAidlInterface asInterface(android.os.IBinder obj) {
            if ((obj == null)) {
                return null;
            }
            //④
            android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
            if (((iin != null) && (iin instanceof com.sjl.exercise.ICustomAidlInterface))) {
                return ((com.sjl.exercise.ICustomAidlInterface) iin);
            }
            return new com.sjl.exercise.ICustomAidlInterface.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 {
            //③
            java.lang.String descriptor = DESCRIPTOR;
            switch (code) {
                case INTERFACE_TRANSACTION: {
                    reply.writeString(descriptor);
                    return true;
                }
                case TRANSACTION_getCurrentTime: {
                    data.enforceInterface(descriptor);
                    java.lang.String _result = this.getCurrentTime();
                    reply.writeNoException();
                    reply.writeString(_result);
                    return true;
                }
                case TRANSACTION_insertUser: {
                    data.enforceInterface(descriptor);
                    com.sjl.exercise.bean.UserBean _arg0;
                    if ((0 != data.readInt())) {
                        _arg0 = com.sjl.exercise.bean.UserBean.CREATOR.createFromParcel(data);
                    } else {
                        _arg0 = null;
                    }
                    this.insertUser(_arg0);
                    reply.writeNoException();
                    return true;
                }
                case TRANSACTION_getUsers: {
                    data.enforceInterface(descriptor);
                    java.util.List<com.sjl.exercise.bean.UserBean> _result = this.getUsers();
                    reply.writeNoException();
                    reply.writeTypedList(_result);
                    return true;
                }
                case TRANSACTION_clearUser: {
                    data.enforceInterface(descriptor);
                    this.clearUser();
                    reply.writeNoException();
                    return true;
                }
                default: {
                    return super.onTransact(code, data, reply, flags);
                }
            }
        }

        private static class Proxy implements com.sjl.exercise.ICustomAidlInterface {
            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 java.lang.String getCurrentTime() 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);
                    //⑤
                    mRemote.transact(Stub.TRANSACTION_getCurrentTime, _data, _reply, 0);
                    _reply.readException();
                    _result = _reply.readString();
                } finally {
                    _reply.recycle();
                    _data.recycle();
                }
                return _result;
            }

            @Override
            public void insertUser(com.sjl.exercise.bean.UserBean userBean) 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 ((userBean != null)) {
                        _data.writeInt(1);
                        userBean.writeToParcel(_data, 0);
                    } else {
                        _data.writeInt(0);
                    }
                    mRemote.transact(Stub.TRANSACTION_insertUser, _data, _reply, 0);
                    _reply.readException();
                } finally {
                    _reply.recycle();
                    _data.recycle();
                }
            }

            @Override
            public java.util.List<com.sjl.exercise.bean.UserBean> getUsers() throws android.os.RemoteException {
                android.os.Parcel _data = android.os.Parcel.obtain();
                android.os.Parcel _reply = android.os.Parcel.obtain();
                java.util.List<com.sjl.exercise.bean.UserBean> _result;
                try {
                    _data.writeInterfaceToken(DESCRIPTOR);
                    mRemote.transact(Stub.TRANSACTION_getUsers, _data, _reply, 0);
                    _reply.readException();
                    _result = _reply.createTypedArrayList(com.sjl.exercise.bean.UserBean.CREATOR);
                } finally {
                    _reply.recycle();
                    _data.recycle();
                }
                return _result;
            }

            @Override
            public void clearUser() throws android.os.RemoteException {
                android.os.Parcel _data = android.os.Parcel.obtain();
                android.os.Parcel _reply = android.os.Parcel.obtain();
                try {
                    _data.writeInterfaceToken(DESCRIPTOR);
                    mRemote.transact(Stub.TRANSACTION_clearUser, _data, _reply, 0);
                    _reply.readException();
                } finally {
                    _reply.recycle();
                    _data.recycle();
                }
            }
        }
        //②
        static final int TRANSACTION_getCurrentTime = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
        static final int TRANSACTION_insertUser = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
        static final int TRANSACTION_getUsers = (android.os.IBinder.FIRST_CALL_TRANSACTION + 2);
        static final int TRANSACTION_clearUser = (android.os.IBinder.FIRST_CALL_TRANSACTION + 3);
    }
    //①
    public java.lang.String getCurrentTime() throws android.os.RemoteException;

    public void insertUser(com.sjl.exercise.bean.UserBean userBean) throws android.os.RemoteException;

    public java.util.List<com.sjl.exercise.bean.UserBean> getUsers() throws android.os.RemoteException;

    public void clearUser() throws android.os.RemoteException;
}

ICustomAidlInterface類最下面的①就是對應aidl文件裏聲明的幾個方法,②所在聲明瞭對應方法的int值,在抽象方法Stub#onTransact方法中可以看到③處正是用②中聲明的int值區分調用的對應方法的。

public interface ICustomAidlInterface extends android.os.IInterface {

    public static abstract class Stub extends android.os.Binder implements com.sjl.exercise.ICustomAidlInterface {
        private static final java.lang.String DESCRIPTOR = "com.sjl.exercise.ICustomAidlInterface";

        ...
        @Override
        public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException {
            //③
            java.lang.String descriptor = DESCRIPTOR;
            switch (code) {
                case INTERFACE_TRANSACTION: {
                    reply.writeString(descriptor);
                    return true;
                }
                case TRANSACTION_getCurrentTime: {
                    data.enforceInterface(descriptor);
                    java.lang.String _result = this.getCurrentTime();
                    reply.writeNoException();
                    reply.writeString(_result);
                    return true;
                }
                case TRANSACTION_insertUser: {
                    data.enforceInterface(descriptor);
                    com.sjl.exercise.bean.UserBean _arg0;
                    if ((0 != data.readInt())) {
                        _arg0 = com.sjl.exercise.bean.UserBean.CREATOR.createFromParcel(data);
                    } else {
                        _arg0 = null;
                    }
                    this.insertUser(_arg0);
                    reply.writeNoException();
                    return true;
                }
                case TRANSACTION_getUsers: {
                    data.enforceInterface(descriptor);
                    java.util.List<com.sjl.exercise.bean.UserBean> _result = this.getUsers();
                    reply.writeNoException();
                    reply.writeTypedList(_result);
                    return true;
                }
                case TRANSACTION_clearUser: {
                    data.enforceInterface(descriptor);
                    this.clearUser();
                    reply.writeNoException();
                    return true;
                }
                default: {
                    return super.onTransact(code, data, reply, flags);
                }
            }
        }

        private static class Proxy implements com.sjl.exercise.ICustomAidlInterface {
            ...
        //②
        static final int TRANSACTION_getCurrentTime = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
        static final int TRANSACTION_insertUser = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
        static final int TRANSACTION_getUsers = (android.os.IBinder.FIRST_CALL_TRANSACTION + 2);
        static final int TRANSACTION_clearUser = (android.os.IBinder.FIRST_CALL_TRANSACTION + 3);
    }
    //①
    public java.lang.String getCurrentTime() throws android.os.RemoteException;

    public void insertUser(com.sjl.exercise.bean.UserBean userBean) throws android.os.RemoteException;

    public java.util.List<com.sjl.exercise.bean.UserBean> getUsers() throws android.os.RemoteException;

    public void clearUser() throws android.os.RemoteException;
}

Stub構造函數裏傳入IInterface和DESCRIPTOR,客戶端通過綁定服務獲取到aidl接口時使用了ICustomAidlInterface.Stub.asInterface(service)方法,在靜態抽象類Stub中④處Stub#asInterface方法中可以看到使用Binder#queryLocalInterface方法獲取本地aidl接口,如果有則返回本地找到的aidl接口,如果沒有就返回定義的Proxy代理類(queryLocalInterface方法就是比對DESCRIPTOR來確認是否返回對應的IInterface,在不同進程時無法找到對應的IInterface,只能通過代理類Proxy來進行aidl方法調用)。

public interface ICustomAidlInterface extends android.os.IInterface {
    /**
     * Local-side IPC implementation stub class.
     */
    public static abstract class Stub extends android.os.Binder implements com.sjl.exercise.ICustomAidlInterface {
        private static final java.lang.String DESCRIPTOR = "com.sjl.exercise.ICustomAidlInterface";
        ...
        public static com.sjl.exercise.ICustomAidlInterface asInterface(android.os.IBinder obj) {
            if ((obj == null)) {
                return null;
            }
            //④
            android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
            if (((iin != null) && (iin instanceof com.sjl.exercise.ICustomAidlInterface))) {
                return ((com.sjl.exercise.ICustomAidlInterface) iin);
            }
            return new com.sjl.exercise.ICustomAidlInterface.Stub.Proxy(obj);
        }

        private static class Proxy implements com.sjl.exercise.ICustomAidlInterface {
            ...    
        }
    }
}

查看Proxy類可以看到它的IPC都是mRemote實現的,而在對應的方法中都使用了mRemote.transact方法,傳入方法對應的int值、客戶端傳入參數data和服務端返回結果reply

        private static class Proxy implements com.sjl.exercise.ICustomAidlInterface {
            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 java.lang.String getCurrentTime() 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);
                    //⑤
                    mRemote.transact(Stub.TRANSACTION_getCurrentTime, _data, _reply, 0);
                    _reply.readException();
                    _result = _reply.readString();
                } finally {
                    _reply.recycle();
                    _data.recycle();
                }
                return _result;
            }

        }

    }

Binder#transact代碼如下,最終調用了Binder#onTransact,也就是Binder#onTransact

    /**
     * Default implementation rewinds the parcels and calls onTransact.  On
     * the remote side, transact calls into the binder to do the IPC.
     */
    public final boolean transact(int code, @NonNull Parcel data, @Nullable Parcel reply,
            int flags) throws RemoteException {
        if (false) Log.v("Binder", "Transact: " + code + " to " + this);

        if (data != null) {
            data.setDataPosition(0);
        }
        boolean r = onTransact(code, data, reply, flags);
        if (reply != null) {
            reply.setDataPosition(0);
        }
        return r;
    }

Binder#onTransact方法如下,通過code確定調用的對應方法,data獲取傳入參數,reply設置返回值

    @Override
    public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException {
        java.lang.String descriptor = DESCRIPTOR;
        switch (code) {
            case TRANSACTION_insertUser: {
                data.enforceInterface(descriptor);
                com.sjl.exercise.bean.UserBean _arg0;
                if ((0 != data.readInt())) {
                    _arg0 = com.sjl.exercise.bean.UserBean.CREATOR.createFromParcel(data);
                } else {
                    _arg0 = null;
                }
                this.insertUser(_arg0);
                reply.writeNoException();
                return true;
            }
            case TRANSACTION_getUsers: {
                data.enforceInterface(descriptor);
                java.util.List<com.sjl.exercise.bean.UserBean> _result = this.getUsers();
                reply.writeNoException();
                reply.writeTypedList(_result);
                return true;
            }
        }
    }

總結:

服務端:服務端返回實現IBinder接口的對象;
客戶端:客戶端如果在本地找到aidl實例直接轉換使用,否則通過Proxy代理調用;
通訊:本地客戶端強制轉換可調用調用方法,其他進程客戶端需要通過Proxy代理調用方法;

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