简单认识Binder(基于aidl)

      下面的很多内容都是来自于《Android开发艺术探索》,这里记录一下,方便以后查看,也加强一下自己的理解。

      Binder是实现了IBinder接口的类,因为书中是在IPC部分提到Binder,所以从IPC的角度,它是IPC的一种实现方式,类似于Socket一样。从Android应用层来说的话,它是客户端和服务端通讯的媒介。标题也说到了,本篇主要基于aidl对Binder的工作机制做一个分析,而且在Android开发中,Binder用的较多的也是在基于aidl的Service中;所以,建议在读本篇博客之前,读者能对Android中Service,aidl以及IPC有一定的使用经验和了解但是对其原理很模糊为最佳

      

1,准备工作

第一步:创建一个IpayInterface.aidl文件,内容如下

// IPayInterface.aidl
package com.hfut.operationbinderpool;

// Declare any non-default types here with import statements

interface IPayInterface {
    /**
     * Demonstrates some basic types that you can use as parameters
     * and return values in AIDL.
     */
   boolean pay(int money);
}

第二步:build一下工程,生成的aidl接口内容如下

/*
 * This file is auto-generated.  DO NOT MODIFY.
 * Original file: D:\\Studysoftware\\ASCode\\androidDevelopArt\\BinderPoolTest\\app\\src\\main\\aidl\\com\\hfut\\operationbinderpool\\IPayInterface.aidl
 */
package com.hfut.operationbinderpool;
// Declare any non-default types here with import statements

public interface IPayInterface extends android.os.IInterface {
    /**
     * Local-side IPC implementation stub class.
     */
    public static abstract class Stub extends android.os.Binder implements com.hfut.operationbinderpool.IPayInterface {
        private static final java.lang.String DESCRIPTOR = "com.hfut.operationbinderpool.IPayInterface";

        /**
         * Construct the stub at attach it to the interface.
         */
        public Stub() {
            this.attachInterface(this, DESCRIPTOR);
        }

        /**
         * Cast an IBinder object into an com.hfut.operationbinderpool.IPayInterface interface,
         * generating a proxy if needed.
         */
        public static com.hfut.operationbinderpool.IPayInterface asInterface(android.os.IBinder obj) {
            if ((obj == null)) {
                return null;
            }
            android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
            if (((iin != null) && (iin instanceof com.hfut.operationbinderpool.IPayInterface))) {
                return ((com.hfut.operationbinderpool.IPayInterface) iin);
            }
            return new com.hfut.operationbinderpool.IPayInterface.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_pay: {
                    data.enforceInterface(DESCRIPTOR);
                    int _arg0;
                    _arg0 = data.readInt();
                    boolean _result = this.pay(_arg0);
                    reply.writeNoException();
                    reply.writeInt(((_result) ? (1) : (0)));
                    return true;
                }
            }
            return super.onTransact(code, data, reply, flags);
        }

        private static class Proxy implements com.hfut.operationbinderpool.IPayInterface {
            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;
            }

            /**
             * Demonstrates some basic types that you can use as parameters
             * and return values in AIDL.
             */
            @Override
            public boolean pay(int money) throws android.os.RemoteException {
                android.os.Parcel _data = android.os.Parcel.obtain();
                android.os.Parcel _reply = android.os.Parcel.obtain();
                boolean _result;
                try {
                    _data.writeInterfaceToken(DESCRIPTOR);
                    _data.writeInt(money);
                    mRemote.transact(Stub.TRANSACTION_pay, _data, _reply, 0);
                    _reply.readException();
                    _result = (0 != _reply.readInt());
                } finally {
                    _reply.recycle();
                    _data.recycle();
                }
                return _result;
            }
        }

        static final int TRANSACTION_pay = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
    }

    /**
     * Demonstrates some basic types that you can use as parameters
     * and return values in AIDL.
     */
    public boolean pay(int money) throws android.os.RemoteException;
}

准备工作到这里结束了。

2,分析生成接口

(1)所有可以在Binder上传输的接口都需要实现IInterface接口

IPayInterface extends android.os.IInterface

(2)DESCRIPTOR 是Binder的唯一标识,通常用当前Binder类名(包括包名一起)

DESCRIPTOR = "com.hfut.operationbinderpool.IPayInterface";

(3)asInterface用于将服务端的Binder对象转换成客户端aidl接口;

从下面代码的注释也很容易就可以看出这样一个作用--“把一个IBinder接口对象转换成一个名为IPayInterface的接口,在必要的情况下,返回一个代理类”;这里面是否有必要返回代理类主要取决于客户端和服务端是否在同一个进程中

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

(4)onTransact运行在服务端的Binder线程池中,客户发起跨进程通讯时,远程请求会通过底层封装后交由此方法处理

其中参数data主要用于接受客户端传来的参数(如果有),reply主要用于保存服务端返回给客户端的结果(如果有),code代表的是客户端请求的目标方法的标识;

static final int TRANSACTION_pay = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);

该方法返回的boolean代表的客户端RPC成功或者失败

@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_pay: {
            data.enforceInterface(DESCRIPTOR);
            int _arg0;
            _arg0 = data.readInt();
            boolean _result = this.pay(_arg0);
            reply.writeNoException();
            reply.writeInt(((_result) ? (1) : (0)));
            return true;
        }
    }
    return super.onTransact(code, data, reply, flags);
}

(5)public boolean pay(int money) throws android.os.RemoteException 运行在客户端

  /**
     * Demonstrates some basic types that you can use as parameters
     * and return values in AIDL.
     */
    @Override
    public boolean pay(int money) throws android.os.RemoteException {
        android.os.Parcel _data = android.os.Parcel.obtain();
        android.os.Parcel _reply = android.os.Parcel.obtain();
        boolean _result;
        try {
            _data.writeInterfaceToken(DESCRIPTOR);
            _data.writeInt(money);
            mRemote.transact(Stub.TRANSACTION_pay, _data, _reply, 0);
            _reply.readException();
            _result = (0 != _reply.readInt());
        } finally {
            _reply.recycle();
            _data.recycle();
        }
        return _result;
    }
}

首先,在客户端调用该方法的时候,会先把参数写入android.os.Parcel _data(需先创建该输入型对象)

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

_data.writeInterfaceToken(DESCRIPTOR);

_data.writeInt(money);

然后调用transact方法发起RPC请求,服务端onTransact方法会执行,同时当前线程挂起,直至RPC返回结果,当前线程恢复,读取android.os.Parcel _reply中的保存的服务端处理结果。

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

_result = (0 != _reply.readInt());

到此,Binder的内容就分析完了

3,Binder运行工作机制(书中原图)

猜你喜欢

转载自blog.csdn.net/hfut_why/article/details/81173642