从AIDL一窥Android Binder机制

Binder机制在Android系统中地位毋庸置疑,system_server就经过Binder来实现进程间的通讯,从而达到管理、调用一系列系统服务的能力。本文就AIDL来解读一下Binder机制的。 先了解一下以下几个概念:java

IBinder 、 Binder 、 BinderProxy 、 IInterface

  1. IBinder : 根据官方的说明文档IBinder定义的是一种使对象具有远程通讯能力的接口,他的子类是Binder。IBinder内部预先定义了一些IPC须要用到的接口,实现IBinder的对象能够被Binder Drivder在IPC过程当中传递;
  2. Binder : 实现了IBinder,具有IPC通讯的能力。在IPC通讯过程当中,Binder表明的是Server的本地对象;
  3. BinderProxy : BinderProxy是Binder的内部类,一样实现了IBinder,不一样于Binder的是,BinderProxy是Binder对象在Client端的一个代理,Client经过BinderProxy间接跟Server进行通讯;
  4. IInterface : 表明的是Server所具有的接口;

还有一点须要说明一下:当一个Service向AMS进行注册时,传递的过去的以及保存在AMS中的是一个Binder对象。当Client须要跟Service进行通讯,经过AMS查询到实际上是一个BinderProxy,由于能够有多个Client同时跟Service进行通讯。固然若是Service和Client在同一进程,AMS返回的仍是一个Binder对象,毕竟没有必要进行IPC。在进行IPC时,Binder Drivder会在中间帮忙转换Binder和BinderProxy。android

AIDL

仍是按照Android Service详解(二)的例子来解释app

如今咱们来看一下系统自动生成的aidl文件具体有些什么:ide

/* * This file is auto-generated. DO NOT MODIFY. * Original file: /Users/lebens/Development/WorkSpace/jxx_workspace/Server/app/src/main/aidl/jxx/com/server/aidl/IServerServiceInfo.aidl */
package jxx.com.server.aidl;
public interface IServerServiceInfo extends android.os.IInterface {
    /** Local-side IPC implementation stub class. */
    public static abstract class Stub extends android.os.Binder implements jxx.com.server.aidl.IServerServiceInfo {
        private static final java.lang.String DESCRIPTOR = "jxx.com.server.aidl.IServerServiceInfo";
        /** Construct the stub at attach it to the interface. */
        public Stub() {
            this.attachInterface(this, DESCRIPTOR);
        }
        /** * Cast an IBinder object into an jxx.com.server.aidl.IServerServiceInfo interface, * generating a proxy if needed. */
        public static jxx.com.server.aidl.IServerServiceInfo asInterface(android.os.IBinder obj) {
            if ((obj==null)) {
                return null;
            }
            android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
            if (((iin!=null)&&(iin instanceof jxx.com.server.aidl.IServerServiceInfo))) {
                return ((jxx.com.server.aidl.IServerServiceInfo)iin);
            }
            return new jxx.com.server.aidl.IServerServiceInfo.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_getServerInfo:
                {
                    data.enforceInterface(descriptor);
                    jxx.com.server.aidl.ServerInfo _result = this.getServerInfo();
                    reply.writeNoException();
                    if ((_result!=null)) {
                        reply.writeInt(1);
                        _result.writeToParcel(reply, android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
                    }
                    else {
                        reply.writeInt(0);
                    }
                    return true;
                }
                case TRANSACTION_setServerInfo:
                {
                    data.enforceInterface(descriptor);
                    jxx.com.server.aidl.ServerInfo _arg0;
                    if ((0!=data.readInt())) {
                        _arg0 = jxx.com.server.aidl.ServerInfo.CREATOR.createFromParcel(data);
                    }
                    else {
                        _arg0 = null;
                    }
                    this.setServerInfo(_arg0);
                    reply.writeNoException();
                    if ((_arg0!=null)) {
                        reply.writeInt(1);
                        _arg0.writeToParcel(reply, android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
                    }
                    else {
                        reply.writeInt(0);
                    }
                    return true;
                }
                default:
                {
                    return super.onTransact(code, data, reply, flags);
                }
            }
        }
        private static class Proxy implements jxx.com.server.aidl.IServerServiceInfo {
            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 jxx.com.server.aidl.ServerInfo getServerInfo() throws android.os.RemoteException {
                android.os.Parcel _data = android.os.Parcel.obtain();
                android.os.Parcel _reply = android.os.Parcel.obtain();
                jxx.com.server.aidl.ServerInfo _result;
                try {
                    _data.writeInterfaceToken(DESCRIPTOR);
                    mRemote.transact(Stub.TRANSACTION_getServerInfo, _data, _reply, 0);
                    _reply.readException();
                    if ((0!=_reply.readInt())) {
                        _result = jxx.com.server.aidl.ServerInfo.CREATOR.createFromParcel(_reply);
                    }
                    else {
                        _result = null;
                    }
                }
                finally {
                    _reply.recycle();
                    _data.recycle();
                }
                return _result;
            }
            @Override public void setServerInfo(jxx.com.server.aidl.ServerInfo serverinfo) 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 ((serverinfo!=null)) {
                        _data.writeInt(1);
                        serverinfo.writeToParcel(_data, 0);
                    }
                    else {
                        _data.writeInt(0);
                    }
                    mRemote.transact(Stub.TRANSACTION_setServerInfo, _data, _reply, 0);
                    _reply.readException();
                    if ((0!=_reply.readInt())) {
                        serverinfo.readFromParcel(_reply);
                    }
                }
                finally {
                    _reply.recycle();
                    _data.recycle();
                }
            }
        }
        static final int TRANSACTION_getServerInfo = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
        static final int TRANSACTION_setServerInfo = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
    }
    public jxx.com.server.aidl.ServerInfo getServerInfo() throws android.os.RemoteException;
    public void setServerInfo(jxx.com.server.aidl.ServerInfo serverinfo) throws android.os.RemoteException;
}
复制代码
  1. 这个文件中,咱们看到IServerServiceInfo实现了IInterface,说明IServerServiceInfo具有了IPC通讯须要的接口,最底下咱们也能够看到定义的getServerInfo()、setServerInfo()两个方法;
  2. 接着来看Stub这个对象,它是IServerServiceInfo的静态内部类,继承了Binder同时实现了IServerServiceInfo。这意味着Stub能够经过Binder Driver进行进程间传递,同时又具有了IPC所须要的接口,实际咱们在Service中asBinder()返回的就是这个对象;
  3. Proxy对象,这又是一个代理对象,不过代理的是BinderProxy。这个对象存在的意思就是代理BinderProxy,将Client的操做转化成BinderProxy去跟Server通讯。
  4. Proxy 和 Stub 的区别在于,Stud自己就是一个Binder对象,能够直接被Binder Driver传递,而Proxy只是表明Service提供的IPC接口,实际使用内部的被代理的mRemote来实现IPC。

Stub

关于Stub再来看几点:post

  1. DESCRIPTOR : 这是用来惟一表示Stub的,当Stub被实例化时会经过DESCRIPTOR来保存owner对象,也就是Stub所表明的IInterface,同时在queryLocalInterface若是是在同一进程查询的话就是返回的Stub;
  2. TRANSACTION_getServerInfo 、 TRANSACTION_setServerInfo : 这两个用来标识Client操做的接口方法。
  3. asInterface : 这个方法就是将Binder,转换成Client须要的接口对象,若是Binder Driver返回的是一个BinderProxy对象,则建立一个Proxy返回给Client。
  4. onTransact : 这个方法跟下面的Proxy对象一同分析。

Proxy

  1. mRemote : 这是一个BinderProxy对象,由Binder Driver传递而来。Proxy的IPC都是经过mRemote来实现的;
  2. 这里咱们还看到的了咱们定义的接口方法,这些方法都是提供给Client使用的,用于跟Server通讯;
  3. mRemote的transact() : 在Binder Driver的帮助下,最终会调用到Stub的onTransact()中。

onTransact()

以getServerInfo()为例来分析一下onTransact传递过程。 首先咱们在Proxy的实现是这样的this

@Override public jxx.com.server.aidl.ServerInfo getServerInfo() throws android.os.RemoteException {
        android.os.Parcel _data = android.os.Parcel.obtain();
        android.os.Parcel _reply = android.os.Parcel.obtain();
        jxx.com.server.aidl.ServerInfo _result;
        try {
            _data.writeInterfaceToken(DESCRIPTOR);
            mRemote.transact(IServerServiceInfo.Stub.TRANSACTION_getServerInfo, _data, _reply, 0);
            _reply.readException();
            if ((0!=_reply.readInt())) {
                _result = jxx.com.server.aidl.ServerInfo.CREATOR.createFromParcel(_reply);
            }
            else {
                _result = null;
            }
        }
        finally {
            _reply.recycle();
            _data.recycle();
        }
        return _result;
    }
复制代码
  1. _data 、 _reply 分别用于Client向Server传递参数和Server向Client返回结果,这2个内的参数都是要序列化的,毕竟IPC;
  2. 经过mRemote.transact开始调用Server的方法;
  3. 经过_reply读取Server返回的数据,并反序列化结果,将之返回;

从上面的分析能够知道,这里的mRemote实际上是一个BinderProxy对象,咱们去看一下这个方法spa

/** * 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(),也就是Stub的onTransact(),咱们来看一下线程

@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_getServerInfo:
                {
                    data.enforceInterface(descriptor);
                    jxx.com.server.aidl.ServerInfo _result = this.getServerInfo();
                    reply.writeNoException();
                    if ((_result!=null)) {
                        reply.writeInt(1);
                        _result.writeToParcel(reply, android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
                    }
                    else {
                        reply.writeInt(0);
                    }
                    return true;
                }
                case TRANSACTION_setServerInfo:
                {
                    data.enforceInterface(descriptor);
                    jxx.com.server.aidl.ServerInfo _arg0;
                    if ((0!=data.readInt())) {
                        _arg0 = jxx.com.server.aidl.ServerInfo.CREATOR.createFromParcel(data);
                    }
                    else {
                        _arg0 = null;
                    }
                    this.setServerInfo(_arg0);
                    reply.writeNoException();
                    if ((_arg0!=null)) {
                        reply.writeInt(1);
                        _arg0.writeToParcel(reply, android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
                    }
                    else {
                        reply.writeInt(0);
                    }
                    return true;
                }
                default:
                {
                    return super.onTransact(code, data, reply, flags);
                }
            }
复制代码

在内部能够看到case TRANSACTION_getServerInfo 下的操做其实也是很简单,就是把Client须要的结果经过reply传递回Client代理

总结

经过上面的代码分析,AIDL咱们能够快速实现IPC,咱们来总结一下:code

  1. Server须要定义提供给Client的接口,也即实现IInterface,同时还要提供一个Binder用来供Binder Driver找到Server,经过DESCRIPTOR肯定;
  2. Client在跟Server通讯以前须要得到一个Binder或者BinderProxy对象,经过Binder Driver跟Server创建联系;
  3. Binder Driver在通讯过程当中自动转换了BinderProxy 和 Binder;

经过这个例子的分析,其实系统的AMS管理各类系统服务也是一样的套路,经过2个Binder创建通讯。

还有一点须要注意: Binder或者BinderProxy都是运行在他们本身的Binder池中的,也就是直接经过Binder通讯的话,须要注意线程切换

相关文章
相关标签/搜索