AIDL全名Android Interface Definition Language,是一种接口定义语言,也是Android系统的一种跨进程通信机制。从AIDL的名字就可以看出来,AIDL做的就是在服务提供进程和服务使用进程之间的协商好的接口,双方通过该接口进行通信。本文将以一个例子来讲述AIDL的使用方式和流程,在下一篇文章中我将从代码层面对AIDL进行分析。
AIDL实例
文章中所涉及的例子来源于android开发之AIDL用法_进程间通信原理详解 一文。首先我们创建一个AIDL文件,并创建了一个接口方法:
interface forService {
void registerTestCall(forActivity cb);
void invokCallBack();
}
这里多说一句,在AIDL文件中并不是所有的数据都可以使用,能够使用的数据类型包括如下几种:
* 基本数据类型(int, long, char, boolean, double等)
* String和CharSequence
* List:只支持ArrayList,并且里面的元素都能被AIDL支持
* Map:只支持HashMap,里面的每个元素能被AIDL支持
* Parcelable:所有实现Parcelable接口的对象
* AIDL: 所有AIDL接口本身也能在AIDL文件中使用
另外AIDL中除了基本数据类型意外,其他数据类型必须标上方向:in、out或者inout。其实AIDL文件和interface很像,其作用本质也是定义了一个接口,就像双方制定的一个协议一样,在通信时必须遵守该协定才能正常通信。
远程服务端Service实现
package com.styleflying.AIDL;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.os.RemoteCallbackList;
import android.os.RemoteException;
import android.util.Log;
public class mAIDLService extends Service {
....
@Override
public void onCreate() {
Log("service create");
}
@Override
public IBinder onBind(Intent t) {
Log("service on bind");
return mBinder;
}
@Override
public boolean onUnbind(Intent intent) {
Log("service on unbind");
return super.onUnbind(intent);
}
public void onRebind(Intent intent) {
Log("service on rebind");
super.onRebind(intent);
}
private final forService.Stub mBinder = new forService.Stub() {
@Override
public void invokCallBack() throws RemoteException
{
callback.performAction();
}
@Override
public void registerTestCall(forActivity cb) throws RemoteException
{
callback = cb;
}
};
}
这里注意一下onBind()
函数,该函数返回了一个IBinder
类型,IBinder
说明AIDL底层是基于Android Binder机制实现的,Binder机制的具体实现细节放到下一篇博客再做详细介绍。onBind
函数实际返回的是mBinder
类型,而该类型实际是声明了一个forService.stub
类型,并在声明中对AIDL文件定义的接口方法做了具体的实现。所以这里的mBinder
可以理解为一个包含了AIDL所定义接口具体实现的类,而这个类最终将传递给客户端,供其调用。
客户端代码
package com.styleflying.AIDL;
....
public class mAIDLActivity extends Activity {
private static final String TAG = "AIDLActivity";
forService mService;
private ServiceConnection mConnection = new ServiceConnection() {
public void onServiceConnected(ComponentName className,
IBinder service) {
mService = forService.Stub.asInterface(service);
try {
mService.registerTestCall(mCallback);}
catch (RemoteException e) {
}
}
public void onServiceDisconnected(ComponentName className) {
Log("disconnect service");
mService = null;
}
};
}
ServiceConnection
是客户端发起的一个指向服务端的连接,而在连接成功时(onServiceConnected
被调用时),通过mService =forService.Stub.asInterface(service)
获取到了服务端传递过来的包含有AIDL规定接口具体实现的AIDL对象(即service端onBind
返回的对象,该对象原本是一个forService.stub
对象通过调用asInterface
接口获取到了对应的AIDL对象),接下来就可以利用mService
调用对应的方法了。然后在连接断开时再释放即可。
AIDL源码解析
上文即是一个AIDL的使用实例,利用AIDL可以轻松的实现在Android端的跨应用通信。但知其然还要知其所以然,这样简单的使用显然无法透彻的了解AIDL通信的原理。上文我们已经提到了AIDL实际底层利用的是Android Binder机制进行通信,在本文中我们将从代码层面继续剖析AIDL机制,而在下一篇博客中讲解Binder机制的原理。虽然我们定义的AIDL文件只有寥寥数行,但是真正的运行起来的AIDL代码却远远不止这点,实际上大部分的工作IDE都帮我们完成了,以上文中的forService
为例,在我们编写完AIDL文件后,IDE会生成其对应的java文件forService.java
:
package ...;
import java.lang.String;
import android.os.RemoteException;
import android.os.IBinder;
import android.os.IInterface;
import android.os.Binder;
import android.os.Parcel;
public interface forService extends android.os.IInterface
{
/** Local-side IPC implementation stub class. */
public static abstract class Stub extends android.os.Binder implements com.styleflying.AIDL.forService
{
private static final java.lang.String DESCRIPTOR = "com.styleflying.AIDL.forService";
/** Construct the stub at attach it to the interface. */
public Stub()
{
this.attachInterface(this, DESCRIPTOR);
}
/**
* Cast an IBinder object into an forService interface,
* generating a proxy if needed.
*/
public static com.styleflying.AIDL.forService asInterface(android.os.IBinder obj)
{
if ((obj==null)) {
return null;
}
android.os.IInterface iin = (android.os.IInterface)obj.queryLocalInterface(DESCRIPTOR);
if (((iin!=null)&&(iin instanceof com.styleflying.AIDL.forService))) {
return ((com.styleflying.AIDL.forService)iin);
}
return new com.styleflying.AIDL.forService.Stub.Proxy(obj);
}
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_registerTestCall:
{
data.enforceInterface(DESCRIPTOR);
com.styleflying.AIDL.forActivity _arg0;
_arg0 = com.styleflying.AIDL.forActivity.Stub.asInterface(data.readStrongBinder());
this.registerTestCall(_arg0);
reply.writeNoException();
return true;
}
case TRANSACTION_invokCallBack:
{
data.enforceInterface(DESCRIPTOR);
this.invokCallBack();
reply.writeNoException();
return true;
}
}
return super.onTransact(code, data, reply, flags);
}
private static class Proxy implements com.styleflying.AIDL.forService
{
private android.os.IBinder mRemote;
Proxy(android.os.IBinder remote)
{
mRemote = remote;
}
public android.os.IBinder asBinder()
{
return mRemote;
}
public java.lang.String getInterfaceDescriptor()
{
return DESCRIPTOR;
}
public void registerTestCall(com.styleflying.AIDL.forActivity cb) 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.writeStrongBinder((((cb!=null))?(cb.asBinder()):(null)));
mRemote.transact(Stub.TRANSACTION_registerTestCall, _data, _reply, 0);
_reply.readException();
}
finally {
_reply.recycle();
_data.recycle();
}
}
public void invokCallBack() throws android.os.RemoteException
{
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
try {
_data.writeInterfaceToken(DESCRIPTOR);
mRemote.transact(Stub.TRANSACTION_invokCallBack, _data, _reply, 0);
_reply.readException();
}
finally {
_reply.recycle();
_data.recycle();
}
}
}
static final int TRANSACTION_registerTestCall = (IBinder.FIRST_CALL_TRANSACTION + 0);
static final int TRANSACTION_invokCallBack = (IBinder.FIRST_CALL_TRANSACTION + 1);
}
public void registerTestCall(com.styleflying.AIDL.forActivity cb) throws android.os.RemoteException;
public void invokCallBack() throws android.os.RemoteException;
}
代码比较复杂,而且一看就是系统自动生成的,看起来很不规范。不用着急,我们一点一点来啃。首先这个类在内部实现了一个抽象类Stub,这个词看起来是不是很熟悉,对了,它就是在Service端出现的那个stub。stub直译过来是存根,也就是Service保留在本地的一个凭证。forService
类中所有的逻辑都在stub中实现。而在stub中又有一个子类称为proxy(代理),这个类名更好理解,他是service的代理,需要用到代理的地方只有远程的调用者,即客户端。所以proxy就是从服务端传递到客户端的对象,客户端正是通过这个代理来执行AIDL中的接口方法的。
Stub
接下来我们深入两个类来看其代码,首先stub通过android.os.IInterface
的attachInterface
方法来完成自我构造。接下来是asInterface
方法,客户端正是利用这个方法来获取到远程服务对象的。在该方法中,首先是在本地查询是否有DESCRIPTOR
所描述的类,如果存在直接返回;如果不存在就返回proxy。这说明当客户端在调用该方法获取远程服务时,实际上服务端首先是会检查服务端是否和客户端在同一个进程中,如果在则直接返回自身,如果不是则返回proxy代理。onTransact
是指令的执行的函数,也即执行AIDL接口定义的函数实际上最终都会执行到这里。data是传入数据,reply是返回数据,两个数据都是Parcel类说明在AIDL的通信过程中数据必须经过序列化操作。不同的指令执行不同的switch分支:1)读取数据;2)执行指令;3)返回数据。
Proxy
读懂了Stub的源码,Proxy的源码就更加简单了,Proxy类中有一个mRemote属性,该属性就是远端的服务端stub。当客户端利用proxy代理执行对应的方法时,proxy的执行逻辑都是:1)声明传入数据和返回结果两个序列化对象;2)写入传入数据;3)执行方法,执行的逻辑就是调用mRemote的onTransact方法在远端执行方法;4)执行完成后读取返回结果
以上就是从代码层面来解析AIDL机制的实现原理,其实如果读懂了代码,AIDL的实现原理也不难,stub-proxy模式也是一个常用的设计模式。但是数据和指令究竟是怎么在两个进程之间进行传递的,源码中却没有体现,这就需要了解AIDL的底层实现机制Binder了。