AIDL下Binder的工作机制

之前有一篇是讲到AIDL的使用,其实在系统那里已经为aidl生产了一个Binder类,那么我们现在就来逐一分析一下:

首先,在这个IMyAIDL接口中继承了android.os.IInterface这个接口,所有可以在Binder中传输的接口都要继承IInterface这个接口。

public interface IMyAIDL extends android.os.IInterface {}

在这个接口里面,声明了我们在aidl里面定义的方法

public java.util.List<com.example.xing.aidldemo.Person> add(com.example.xing.aidldemo.Person person) throws android.os.RemoteException;

还有就是定义了一个Stub的静态内部类,这个内部类也继承了Binder,还实现了本身的接口IMyAIDL,所以这个Stub相当于就是一个Binder。在服务器端new一个Binder的时候,new IMyAIDL.Stub(),获得的就是这个Stub。

public static abstract class Stub extends android.os.Binder implements com.example.xing.aidldemo.IMyAIDL {}

在里面定义了两个静态变量

private static final java.lang.String DESCRIPTOR = "com.example.xing.aidldemo.IMyAIDL";
static final int TRANSACTION_add = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
名称 说明
DESCRIPTOR 通常就是Binder的包名
TRANSACTION_add 是我们在接口里面定义的add()方法的ID标志

在这个Stub类接着看下去,发现这样一个方法:

public static com.example.xing.aidldemo.IMyAIDL asInterface(android.os.IBinder obj)
        {
            if ((obj==null)) {
                return null;
            }
            android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
            if (((iin!=null)&&(iin instanceof com.example.xing.aidldemo.IMyAIDL))) {
                return ((com.example.xing.aidldemo.IMyAIDL)iin);
            }
            return new com.example.xing.aidldemo.IMyAIDL.Stub.Proxy(obj);
        }

是不是感觉似曾相识,没错就是在客户端的时候拿到远程服务的时候调用了这个方法。

iMyAidl = IMyAIDL.Stub.asInterface(iBinder);

这个方法就是为了将服务器端的Binder对象转化为客户端的可以使用的aidl对象。通常这里需要进行判断,如果客户端和服务器端是处于同一个进程里面,返回的就是服务器的Binder,如果不是同一个进程的话,就返回new com.example.xing.aidldemo.IMyAIDL.Stub.Proxy(obj)。这里出现了Proxy,这个究竟是什么呢?不过从字面上理解应该就是代理,那我们找找Proxy在哪里出现?

private static class Proxy implements com.example.xing.aidldemo.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 java.util.List<com.example.xing.aidldemo.Person> add(com.example.xing.aidldemo.Person person) throws android.os.RemoteException {
                android.os.Parcel _data = android.os.Parcel.obtain();
                android.os.Parcel _reply = android.os.Parcel.obtain();
                java.util.List<com.example.xing.aidldemo.Person> _result;
                try {
                    _data.writeInterfaceToken(DESCRIPTOR);
                    if ((person != null)) {
                        _data.writeInt(1);
                        person.writeToParcel(_data, 0);
                    } else {
                        _data.writeInt(0);
                    }
                    mRemote.transact(Stub.TRANSACTION_add, _data, _reply, 0);
                    _reply.readException();
                    _result = _reply.createTypedArrayList(com.example.xing.aidldemo.Person.CREATOR);
                } finally {
                    _reply.recycle();
                    _data.recycle();
                }
                return _result;
            }
        }

原来这个类是Stub的静态内部类,也是实现了IMyAIDL这个接口,所以同样实现了add()这个方法。就是说我们在客户端拿到的并非真正的远程服务IBinder,而只是代理而已。
那么直接看到我们的add()方法中,这里定义两个parcel

android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();

_data用于写入参数(如果有的话),_reply用于数据的返回。
接着往下看

try {
    _data.writeInterfaceToken(DESCRIPTOR);
    if ((person != null)) {
        _data.writeInt(1);
        person.writeToParcel(_data, 0);
    } else {
        _data.writeInt(0);
    }
    mRemote.transact(Stub.TRANSACTION_add, _data, _reply, 0);
    _reply.readException();
    _result = _reply.createTypedArrayList(com.example.xing.aidldemo.Person.CREATOR);
} finally {
    _reply.recycle();
    _data.recycle();
}
return _result;

这时候看到调用的mRemote.transact(),这个mRemote是Stub的实例,相当于就是调用IBinder底层的onTransact()方法,将从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);
            com.example.xing.aidldemo.Person _arg0;
            if ((0 != data.readInt())) {
                _arg0 = com.example.xing.aidldemo.Person.CREATOR.createFromParcel(data);
            } else {
                _arg0 = null;
            }
            java.util.List<com.example.xing.aidldemo.Person> _result = this.add(_arg0);
            reply.writeNoException();
            reply.writeTypedList(_result);
            return true;
        }
    }
    return super.onTransact(code, data, reply, flags);
}

onTransact里面有4个参数:

参数 说明
code 用于区分执行哪个方法,客户端会传递此参数,告诉服务端执行哪个方法
data 客户端传递过来的参数
replay 服务器返回回去的值
flags 标明是否有返回值,0为有(双向),1为没有(单向)

当通过code判断执行哪个方法的时候,首先会从data中获取传进来的参数,接着执行目标方法,具体的实现就是在我们服务端编写的,this.add(_arg0),执行完毕之后,就将返回的数据写进reply中

reply.writeNoException();
reply.writeTypedList(_result);

基本上执行的过程就是这样了。
其实Android 下的Binder机制主要就是有3部分:服务端接口,Binder驱动和客户端接口。
服务端的接口:实际上就是一个Binder实例,当它被创建的时候,会自动创建一个线程,接收Binder驱动传来的消息执行onTransact()方法,根据参数的不同,执行不同的方法,在AIDL中相当于Stub。
Binder驱动:也是一个Binder的实例,客户端通过这个远程访问服务端。就是客户端和服务器端之间的桥梁。
客户端接口:获得Binder实例,调用Transact()。在AIDL中,相当于就是Proxy。
注意:

  • 当客户端发起远程调用的时候,当前线程会被挂起,直到数据返回,所以远程方法如果是一个很耗时的,就不要在主线程发起请求
  • 服务端的Binder方法是在一个线程池里面运行的

这里写图片描述

猜你喜欢

转载自blog.csdn.net/lihuanxing/article/details/52470266