Android AIDL通信,及其Binder通讯原理

1.为什么试用aidl,而不是直接通信?

  • 一个进程空间分为:用户态(用户空间)和内核态(内核空间),即把进程内用户和内核隔离开来
  • 进程之间,由于Android系统为每个进程分配了一个独立的虚拟机,用户空间和内核空间的数据不可交互
  • Binder作为进程间的介质,充当了中介,使得进程间的内核态可以通过Binder进行数据交互

2.通信过程

  • 首先编写以“aidl”结尾的aidl文件,编译生成同名的java文件,在app/build/generated/source/aidl 目录下
  • 打开aidl生成的java文件查看主要类当前类实现了IInterface接口,同时生成的Stub抽象类(运行在Service端),以及Stub抽象类的内部类 Proxy代理类(运行在Client端)
  • 开始通信,通过自定义一个方法,例如 call(String msg)
private android.os.IBinder mRemote;
@Override
            public java.lang.String call(java.lang.String req) 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);
                    _data.writeString(req);
                    // 调用了IBinder 的transact
 //  第一个参数表示这一次请求执行的意图,IBinder定义了像
 //	INTERFACE_TRANSACTION、PING_TRANSACTION这样的几个通用命令。
 //	自己使用的命令的标识值需要在FIRST_CALL_TRANSACTION和LAST_CALL_TRANSACTION之间。
 //	这个参数是客户端和服务端约定好的。
//      第二个参数表示向服务端发送的数据,不能为null。
//      第三个参数表示服务端返回的数据,可以为null。
//      第四个参数flags只有0和FLAG_ONEWAY (=1)两种,默认的跨进程操作是同步的,所以transact()方法的执行会阻塞flasg=0;
//指定FLAG_ONEWAY时,表示Client的transact()是单向调用,执行后立即返回,无需等待服务端返回。
                    mRemote.transact(Stub.TRANSACTION_call, _data, _reply, 0);
                    _reply.readException();
                    _result = _reply.readString();
                } finally {
                    _reply.recycle();
                    _data.recycle();
                }
                return _result;
            }

**注意:**执行 transact 后当前线程就会被阻塞,直到服务端返回结果,如果耗时太长,需要我们在子线程开启通信
再进入查看 IBinder 的 transact是空方法,查找子类Binder

public final boolean transact(int code, Parcel data, 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抽象类,继承了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_call: {
                    data.enforceInterface(DESCRIPTOR);
                    java.lang.String _arg0;
                    _arg0 = data.readString();
                    java.lang.String _result = this.call(_arg0);
                    reply.writeNoException();
                    reply.writeString(_result);
                    return true;
                }
            }
            return super.onTransact(code, data, reply, flags);
        }

根据code不同执行不同的方法,然后将数据写入reply,最后Proxy代理类收到数据,线程继续向下执行。
binder kernel 那一块还在研究… 会更新的
最后附Binder路径: platform_frameworks_base/core/java/android/os/

猜你喜欢

转载自blog.csdn.net/guojiayuan002/article/details/82736093