安卓AIDL分析

AIDL分析(Binder跨进程通信分析)

文件格式

package com.ckkj.router.aidl;

interface IRouterInterface {

    void stepIn(int steps);

    void stepOut(int steps);
}

可以看到,aidl的内容书写格式和正常的接口一模一样,只是文件后缀为aidl,而且具有包名和import语句
需要注意的是:由于不是普通的java文件,在aidl引用关系中,即使是位于同一个package下的文件,也需要通过import将引用的类导入到aidl中

文件描述

创建完aidl文件后,rebuild该项目,会在gen目录下生成aidl文件对应的java文件,上图中的aidl文件对应生成的java文件如下:

	<!--对应接口的标识符-->
	private static final java.lang.String DESCRIPTOR = "com.github.lotty.IMyAidlInterface";
	<!--对应接口中的方法标识符-->
 	static final int TRANSACTION_stepIn =(android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
    static final int TRANSACTION_stepOut = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
	<!--对应接口中的stepIn方法-->
	public void stepIn(int steps) throws android.os.RemoteException;
	<!--对应接口中的stepOut方法-->
	public void stepOut(int steps) throws android.os.RemoteException;
  1. TRANSACTION 方法标识符,有限定范围,必须介于FIRST_CALL_TRANSACTIONLAST_CALL_TRANSACTION之间
 /**
     * The first transaction code available for user commands.
     */
    int FIRST_CALL_TRANSACTION  = 0x00000001;
    /**
     * The last transaction code available for user commands.
     */
    int LAST_CALL_TRANSACTION   = 0x00ffffff;
  1. DESCRIPTOR Biner标识符,确认是有哪个客户端发起的请求,一般是类的全路径名称
  2. 类关系说明
/**创建的aidl文件对应的java接口文件
*/
interface IRouterInterface extends android.os.IInterface

/**本地客户端stub,处理通信,可能是进程内,也可能是进程间,当引起进程间通信时,会交给代理类Proxy
*/
abstract class Stub extends android.os.Binder implements com.ckkj.router.aidl.IRouterInterface

/**处理进程间通信的代理类
*/
class Proxy implements com.ckkj.router.aidl.IRouterInterface

方法分析

  1. onTransact
/**该方法会由服务端执行,运行在服务端的binder线程池中,主要是将结果写到返回结果对象中
* 需要注意该方法的最好是同步的,因为已经是在线程池中
*/
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_stepIn: {
                data.enforceInterface(descriptor);
                int _arg0;
                _arg0 = data.readInt();
                this.stepIn(_arg0);
                reply.writeNoException();
                return true;
             }
        case TRANSACTION_stepOut: {
                data.enforceInterface(descriptor);
                int _arg0;
                _arg0 = data.readInt();
                this.stepOut(_arg0);
                reply.writeNoException();
                return true;
             }
        default: {
                return super.onTransact(code, data, reply, flags);
             }
        }
}


 2. stepIn接口方法

/**该方法会由服务端在代理类Proxy中执行,主要是将参数写到请求参数对象中,并调用服务端的transact方法
*/
public void stepIn(int steps) throws android.os.RemoteException {
    android.os.Parcel _data = android.os.Parcel.obtain();
    android.os.Parcel _reply = android.os.Parcel.obtain();
    try {
            _data.writeInterfaceToken(DESCRIPTOR);
            _data.writeInt(steps);
            mRemote.transact(Stub.TRANSACTION_stepIn, _data, _reply, 0);
            _reply.readException();
    } finally {
            _reply.recycle();
            _data.recycle();
    }
}

总体流程

  1. 客户端发起调用,通过asInterface获取远端Binder在本地的对象(或者代理)
  2. 查询本地是否已有服务对象queryLocalInterface(本地调用)
  3. 出发跨进程调用时,通过Stub.Proxy对象将调用交给服务端
  4. 在Proxy中对应的方法调用会调用Binder.transact方法,并将参数序列化写入到data中,调用对象为服务端的Binder对象,此时调用进入服务端
  5. transact的方法会调用自身的onTransact方法,进行真实的调用,同时将返回数据序列化写入到reply中
  6. 本地从reply中获取数据,流程结束
发布了36 篇原创文章 · 获赞 9 · 访问量 4890

猜你喜欢

转载自blog.csdn.net/lotty_wh/article/details/103599323