android aidl使用方法和原理

版权声明:转载请注明出处。作者:两仪织,博客地址:http://blog.csdn.net/u013894427 https://blog.csdn.net/u013894427/article/details/84884390

AIDL设计原因

  • 跨进程通信(IPC,Inter Process Communication),以及跨进程调用(RPC,Remote Procedure Call)的一种实现方法。
  • 节省工作量

AIDL中的实现工具

为了达到这个目的引入了IInterface,IBinder以及Binder类

IInterface

是什么:IInterface是一个interface,定义了一个asBinder函数。

联想到什么:IInterface接口一定是和Binder一起使用的。

/**
 * Base class for Binder interfaces.  When defining a new interface,
 * you must derive it from IInterface.
 */
public interface IInterface
{
    /**
     * Retrieve the Binder object associated with this interface.
     * You must use this instead of a plain cast, so that proxy objects
     * can return the correct result.
     */
    public IBinder asBinder();
}

IBinder

类解读

是什么:按照官方介绍,IBinder是远程对象的基本接口,是一种高效处理进程内和跨进程调用的RPC机制核心组成部分。
这个接口用远程对象描述抽象行为协议。请不要直接使用IBinder,而是用Binder代替。

解读: 用Binder,别用IBinder。

Base interface for a remotable object, the core part of a lightweight
remote procedure call mechanism designed for high performance when
performing in-process and cross-process calls. This
interface describes the abstract protocol for interacting with a
remotable object. Do not implement this interface directly, instead
extend from {@link Binder}.

transact函数解读

对于IBinder类的描述,除了上面的介绍之外,剩下的都是对transact函数的介绍,足以说明这个函数的重要性。
那么这个函数是做什么用的呢,看下函数定义部分的注释

定义:用远程对象来执行一个通用操作。
解读:跟Handler机制中的sendMessage(Message msg)类似,code就是msg.what,data相当于添加的Bundle数据,reply是用来存储返回值的Parcel。

/**
 * Perform a generic operation with the object.
 * 
 * @param code The action to perform.  This should
 * be a number between {@link #FIRST_CALL_TRANSACTION} and
 * {@link #LAST_CALL_TRANSACTION}.
 * @param data Marshalled data to send to the target.  Must not be null.
 * If you are not sending any data, you must create an empty Parcel
 * that is given here.
 * @param reply Marshalled data to be received from the target.  May be
 * null if you are not interested in the return value.
 * @param flags Additional operation flags.  Either 0 for a normal
 * RPC, or {@link #FLAG_ONEWAY} for a one-way RPC.
 *
 * @return Returns the result from {@link Binder#onTransact}.  A successful call
 * generally returns true; false generally means the transaction code was not
 * understood.
 */
public boolean transact(int code, @NonNull Parcel data, @Nullable Parcel reply, int flags)
	throws RemoteException;

Binder类

类解读

是什么:远程对象的基本类,IBinder定义的轻量级RPC机制的核心部分。这个类实现了IBinder接口,并且提供了一种标准的本地实现。
大多数开发者不用直接实现这个类,而是使用aidl工具去秒数想要的接口,用它去生成适当的Binder子类。
不管怎样,你可以对Binder类进行拍成去继承你自己的RPC协议,或者直接简单的初始化一个原生的Binder对象作为你跨进程的令牌。

解读:Binder类是IBinder接口的实现,绝大多数情况下用aidl工具去使用就够了。

Base class for a remotable object, the core part of a lightweight
remote procedure call mechanism defined by {@link IBinder}.
This class is an implementation of IBinder that provides
standard local implementation of such an object.

Most developers will not implement this class directly, instead using the
aidl tool to describe the desired
interface, having it generate the appropriate Binder subclass. You can,
however, derive directly from Binder to implement your own custom RPC
protocol or simply instantiate a raw Binder object directly to use as a
token that can be shared across processes.

transact函数解读

这个函数是实现的IBinder接口中的一个函数,实际就是调用了Binder类中的Ontransact函数。

解读:这个函数一定不会被重载

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;
}

onTransact()解读

跟handleMessage函数根据msg.what处理不同的信息类似,根据code来响应不同接口函数,
data是序列化之后的参数集合,reply是序列化之后的返回值。

解读:这个函数一定会被重载

/**
 * Default implementation is a stub that returns false.  You will want
 * to override this to do the appropriate unmarshalling of transactions.
 *
 * <p>If you want to call this, call transact().
 *
 * <p>Implementations that are returning a result should generally use
 * {@link Parcel#writeNoException() Parcel.writeNoException} and
 * {@link Parcel#writeException(Exception) Parcel.writeException} to propagate
 * exceptions back to the caller.</p>
 *
 * @param code The action to perform.  This should
 * be a number between {@link #FIRST_CALL_TRANSACTION} and
 * {@link #LAST_CALL_TRANSACTION}.
 * @param data Marshalled data being received from the caller.
 * @param reply If the caller is expecting a result back, it should be marshalled
 * in to here.
 * @param flags Additional operation flags.  Either 0 for a normal
 * RPC, or {@link #FLAG_ONEWAY} for a one-way RPC.
 *
 * @return Return true on a successful call; returning false is generally used to
 * indicate that you did not understand the transaction code.
 */
protected boolean onTransact(int code, @NonNull Parcel data, @Nullable Parcel reply,
        int flags) throws RemoteException

AIDL的使用方法

创建一个aidl文件

文件位置:./app/src/main/aidl/IRemoteInterface.aidl

package com.xxx.validatedemo;

interface IRemoteInterface {
    int getAge(String name);
}

自动生成的java文件

创建aidl文件之后,直接使用gradle sync就会自动生成IRemoteInterface.java

文件位置:./app/build/generated/source/aidl/debug/com/xxx/validatedemo/IRemoteInterface

service中创建IRemoteInterface.Stub子类

private class MyStub extends IRemoteInterface.Stub
    {
        @Override
        public int getName(String name) throws RemoteException
        {

        }
    }

在AndroidManifest.xml中注册service为远程,也就是不同进程

<service android:name="com.xxx.xxx.validatedemo.services.RemoteService"
            android:process=":remote"
            android:exported="false"
            ></service>

在Activity中进行绑定和使用

IRemoteInterface myRemoteInterface;
Intent remoteIntent=new Intent(this,RemoteService.class);
remoteConn=new ServiceConnection()
{
	@Override
	public void onServiceConnected(ComponentName name, IBinder service)
	{
		myRemoteInterface=IRemoteInterface.Stub.asInterface(service);
	}

	@Override
	public void onServiceDisconnected(ComponentName name)
	{

	}
};
this.bindService(remoteIntent,remoteConn,BIND_AUTO_CREATE);

AIDL的原理

activity中的调用

  1. bindService传入remoteConn参数
  2. remoteConn中的OnServiceConnected函数在服务链接成功之后调用,并且返回了远程服务的service句柄
    也就是IBinder对象
  3. 通过Stub的asInterface返回调用

自动生成的IRemoteInterface.java 解读

/*
 * This file is auto-generated.  DO NOT MODIFY.
 * Original file: D:\\workspace\\android_studio\\ValidateDemo\\app\\src\\main\\aidl\\com\\xxx\\validatedemo\\IRemoteInterface.aidl
 */
package com.xxx.validatedemo;

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

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

        /**
         * Cast an IBinder object into an com.xxx.validatedemo.IRemoteInterface interface,
         * generating a proxy if needed.
         */
        public static com.xxx.validatedemo.IRemoteInterface asInterface(android.os.IBinder obj)
        {
            if ((obj == null))
            {
                return null;
            }
            android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
            if (((iin != null) && (iin instanceof com.xxx.validatedemo.IRemoteInterface)))
            {
                return ((com.xxx.validatedemo.IRemoteInterface) iin);
            }
            return new com.xxx.validatedemo.IRemoteInterface.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_getAge:
                {
                    data.enforceInterface(descriptor);
                    java.lang.String _arg0;
                    _arg0 = data.readString();
                    int _result = this.getAge(_arg0);
                    reply.writeNoException();
                    reply.writeInt(_result);
                    return true;
                }
                default:
                {
                    return super.onTransact(code, data, reply, flags);
                }
            }
        }

        private static class Proxy implements com.xxx.validatedemo.IRemoteInterface
        {
            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 int getAge(java.lang.String name) throws android.os.RemoteException
            {
                android.os.Parcel _data = android.os.Parcel.obtain();
                android.os.Parcel _reply = android.os.Parcel.obtain();
                int _result;
                try
                {
                    _data.writeInterfaceToken(DESCRIPTOR);
                    _data.writeString(name);
                    mRemote.transact(Stub.TRANSACTION_getAge, _data, _reply, 0);
                    _reply.readException();
                    _result = _reply.readInt();
                } finally
                {
                    _reply.recycle();
                    _data.recycle();
                }
                return _result;
            }
        }

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

    public int getAge(java.lang.String name) throws android.os.RemoteException;
}

文件解读:以下内容非常重要,请一个字一个字仔细阅读。

IRemoteInterface是一个接口,直接继承的是IInterface,这个接口里面有一个抽象静态类Stub,
Stub类继承Binder,实现IRemoteInterface。Stub类是抽象的,所谓抽象,就是为了继承而生
如果没有实现,就没有意义,因此,虽然在声明上说要实现IRemoteInterface类,但是实际上,
IRemoteInterface.java文件中,Stub内部类中并没有实现IRemoteInterface中定义的getAge函数,
那什么时候实现呢?当然是在Service中创建Stub的子类的时候啦。

Stub内部类中除了继承Binder类中的onTransact函数以及IInterface中的asBinder函数之外,
还写了一个asInterface函数,这个函数很重要,作用是根据传入的IBinder对象,返回接口具体实现的对象的。

来看下源码吧

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

函数做了一个简单的判空,如果传入的IBinder可以检索到当前的接口,那么直接返回这个接口
什么时候会检索到呢?答案是IBinder和接口的实现是位于同一个进程的,这就是为什么IBinder说自己支持进程内通信

如果检索不到怎么办呢,这里返回了一个匿名内部类。我们一起看一下

Stub.Proxy内部类

private static class Proxy implements com.xxx.validatedemo.IRemoteInterface
{
	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 int getAge(java.lang.String name) throws android.os.RemoteException
	{
		android.os.Parcel _data = android.os.Parcel.obtain();
		android.os.Parcel _reply = android.os.Parcel.obtain();
		int _result;
		try
		{
			_data.writeInterfaceToken(DESCRIPTOR);
			_data.writeString(name);
			mRemote.transact(Stub.TRANSACTION_getAge, _data, _reply, 0);
			_reply.readException();
			_result = _reply.readInt();
		} finally
		{
			_reply.recycle();
			_data.recycle();
		}
		return _result;
	}
}

解读:这个内部类很简单,实现了IRemoteInterface这个接口。构造函数中把传入的IBinder在getAge函数中调用transact来跨进程执行。在Binder的transact函数中可以明显的看到调用了onTransact。这样子通过以IBinder对象为媒介,完成了跨进程通信

猜你喜欢

转载自blog.csdn.net/u013894427/article/details/84884390