Binder实现分析

来源:互联网 发布:西安美林数据 怎么样 编辑:程序博客网 时间:2024/06/08 05:25

我在之前的一篇文章AIDL最佳实践中通过AIDL接口成功完成了进程间通信。那今天就从应用层的角度分析一下,来加深对Binder机制的了解。

首先来看AIDL最佳实践中的AIDL文件,IMyAidl.aidl:

interface IMyAidl {   int add(int num1,int num2);   List<Dog> addDog(in Dog dog);}

以及编译器根据AIDL文件生成的.java文件,IMyAidl.java:

public interface IMyAidl extends android.os.IInterface {    /**     * Local-side IPC implementation stub class.     */    public static abstract class Stub extends android.os.Binder implements com.aidl.tsnt.server.IMyAidl {        private static final java.lang.String DESCRIPTOR = "com.aidl.tsnt.server.IMyAidl";        /**         * Construct the stub at attach it to the interface.         */        public Stub() {            this.attachInterface(this, DESCRIPTOR);        }        /**         * Cast an IBinder object into an com.aidl.tsnt.server.IMyAidl interface,         * generating a proxy if needed.         */        public static com.aidl.tsnt.server.IMyAidl asInterface(android.os.IBinder obj) {            if ((obj == null)) {                return null;            }            android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);            if (((iin != null) && (iin instanceof com.aidl.tsnt.server.IMyAidl))) {                return ((com.aidl.tsnt.server.IMyAidl) iin);            }            return new com.aidl.tsnt.server.IMyAidl.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_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;                }                case TRANSACTION_addDog: {                    data.enforceInterface(DESCRIPTOR);                    com.aidl.tsnt.server.Dog _arg0;                    if ((0 != data.readInt())) {                        _arg0 = com.aidl.tsnt.server.Dog.CREATOR.createFromParcel(data);                    } else {                        _arg0 = null;                    }                    java.util.List<com.aidl.tsnt.server.Dog> _result = this.addDog(_arg0);                    reply.writeNoException();                    reply.writeTypedList(_result);                    return true;                }            }            return super.onTransact(code, data, reply, flags);        }        private static class Proxy implements com.aidl.tsnt.server.IMyAidl {            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 num1, int num2) throws android.os.RemoteException {                android.os.Parcel _data = android.os.Parcel.obtain();                android.os.Parcel _reply = android.os.Parcel.obtain();                int _result;                try {                    _data.writeInterfaceToken(DESCRIPTOR);                    _data.writeInt(num1);                    _data.writeInt(num2);                    mRemote.transact(Stub.TRANSACTION_add, _data, _reply, 0);                    _reply.readException();                    _result = _reply.readInt();                } finally {                    _reply.recycle();                    _data.recycle();                }                return _result;            }            @Override            public java.util.List<com.aidl.tsnt.server.Dog> addDog(com.aidl.tsnt.server.Dog dog) throws android.os.RemoteException {                android.os.Parcel _data = android.os.Parcel.obtain();                android.os.Parcel _reply = android.os.Parcel.obtain();                java.util.List<com.aidl.tsnt.server.Dog> _result;                try {                    _data.writeInterfaceToken(DESCRIPTOR);                    if ((dog != null)) {                        _data.writeInt(1);                        dog.writeToParcel(_data, 0);                    } else {                        _data.writeInt(0);                    }                    mRemote.transact(Stub.TRANSACTION_addDog, _data, _reply, 0);                    _reply.readException();                    _result = _reply.createTypedArrayList(com.aidl.tsnt.server.Dog.CREATOR);                } finally {                    _reply.recycle();                    _data.recycle();                }                return _result;            }        }        static final int TRANSACTION_add = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);        static final int TRANSACTION_addDog = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);    }    public int add(int num1, int num2) throws android.os.RemoteException;    public java.util.List<com.aidl.tsnt.server.Dog> addDog(com.aidl.tsnt.server.Dog dog) throws android.os.RemoteException;}

从上述自动生成的代码可以看出,IMyAidl.java继承了IInterface 接口,当然它自己也是一个接口。所有可以在Binder机制中传输的接口都需要继承IInterface 。

这个接口的结构实际上还是很清晰的,它声明了两个方法add()和addDog(),显然这是我们在IMyAidl.aidl中所声明的方法。同时它还声明了两个整型标识符TRANSACTION_add和TRANSACTION_addDog用于在onTransact()中区别客户端所请求的方法。

它还声明了一个内部类Stub,它就是一个Binder类。当客户端和服务端位于同一进程时,方法调用不会走跨进程的transact();而当客户端和服务端位于不同进程时,方法调用需要走transact(),这个逻辑由Stub的内部代理类Proxy来完成

这么来看IMyAidl这个接口很简单,这个接口的核心实现就是它的内部类Stub和Stub的内部代理类Proxy。

下面来介绍其中的方法和标识符:

DESCRIPTOR: Binder的唯一标识,一般用当前Binder的类名来表示,这里就是“com.aidl.tsnt.server.IMyAidl”。

asInterface():

        /**         * Cast an IBinder object into an com.aidl.tsnt.server.IMyAidl interface,         * generating a proxy if needed.         */        public static com.aidl.tsnt.server.IMyAidl asInterface(android.os.IBinder obj) {            if ((obj == null)) {                return null;            }            android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);            if (((iin != null) && (iin instanceof com.aidl.tsnt.server.IMyAidl))) {                return ((com.aidl.tsnt.server.IMyAidl) iin);            }            return new com.aidl.tsnt.server.IMyAidl.Stub.Proxy(obj);        }

从方法上的注释就可以看出,这个方法用来将服务端的Binder对象转化为客户端所需要的AIDL接口类型的对象。这种转换是区分进程的,如果客户端和服务端位于同一进程,那么此方法返回的就是服务端的Stub对象本身,否则返回的是系统封装后的Stub.Proxy对象

asBinder():

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

用来返回Stub(Binder)对象本身。

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_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;                }                case TRANSACTION_addDog: {                    data.enforceInterface(DESCRIPTOR);                    com.aidl.tsnt.server.Dog _arg0;                    if ((0 != data.readInt())) {                        _arg0 = com.aidl.tsnt.server.Dog.CREATOR.createFromParcel(data);                    } else {                        _arg0 = null;                    }                    java.util.List<com.aidl.tsnt.server.Dog> _result = this.addDog(_arg0);                    reply.writeNoException();                    reply.writeTypedList(_result);                    return true;                }            }            return super.onTransact(code, data, reply, flags);        }

这个方法运行在服务端中的Binder线程池中,当客户端发起跨进程请求时,远程请求会通过系统底层封装后交由此方法处理。服务端根据code可以确定客户端请求的方法是什么,接着从data中取出目标方法所需要的参数,然后执行目标方法。当目标方法执行完毕后,再向reply中写入返回值。如果此方法返回false,那么客户端请求会失败,我们可以利用这个特性来对权限进行验证。

transact():
我们在Stub.Proxy的add()和addDog()两个方法中都看到了 mRemote.transact(),可以猜测这个transact()应该最终就是调用onTransact()。然后我们看到Binder的onTransact()的注释:

    /**     * Default implementation is a stub that returns false.  You will want     * to override this to do the appropriate unmarshalling of transactions.     *     * <p>If you want to call this, call transact().     */    protected boolean onTransact(int code, Parcel data, Parcel reply,            int flags) throws RemoteException {            ……    }

果然,注释最后一行表达的意思就是如果你要调用onTransact(),请调用transact()。

通过上面的分析,我们大概从应用层了解了Binder的工作机制。

如果要从内核和framework层更深入地了解,可以看这几篇文章:
1.Binder进程间通信机制概述(Android系统源代码情景分析学习笔记)
2.Binder系统中的数据结构(Android系统源代码情景分析学习笔记)
3.Android Binder设计与实现 - 设计篇

还有两点要注意的是:

  • 当客户端发起远程请求时,由于当前线程会被挂起直至服务端进程返回数据,所以如果一个远程方法很耗时,那就不能在UI线程中发起请求。

  • 服务端的Binder方法运行在Binder线程池中,所以Binder中的方法不管是否耗时都应该采用同步的方法去实现,因为它已经运行在一个单独的线程中了。

实现分析到此完毕,当然我们也可以不借助AIDL,自己实现Binder。

原创粉丝点击