【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 _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 getUsers() throws android.os.RemoteException {
                android.os.Parcel _data = android.os.Parcel.obtain();
                android.os.Parcel _reply = android.os.Parcel.obtain();
                java.util.List _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 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 _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 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 _result = this.getUsers();
                reply.writeNoException();
                reply.writeTypedList(_result);
                return true;
            }
        }
    }

总结:

服务端:服务端返回实现IBinder接口的对象;
客户端:客户端如果在本地找到aidl实例直接转换使用,否则通过Proxy代理调用;
通讯:本地客户端强制转换可调用调用方法,其他进程客户端需要通过Proxy代理调用方法;

你可能感兴趣的:(Android,知识体系)