Binder实现分析

我在之前的一篇文章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。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值