什么是AIDL
AIDL (Android Interface Definition Language),通过定义通信接口来实现进程间通信。这是Google提供的一种在安卓应用进程间通信的工具。
为什么需要AIDL
我们都知道AIDL的目的是进行进程间通信。所以需要了解AIDL原理之前先要了解一下什么叫进程间通信。
进程间通信涉及到两个名词,一个是进程间,一个是通信。
进程间就是两个或多个进程之间,所以这里先要明确一个概念,进程间通信涉及到多个实体。其次是通信,什么是通信呢?打电话,发邮件,发QQ消息都是通信,他们之间的共同点就是数据交换。所以简单来说,进程间通信就是多个多个实体间的数据交换,而且这些数据都是运行时数据,因为通信实体是运行时产生的。
那么一般情况下,我们的应用程序是怎样进行数据交换呢?
最简单的办法就是共享内存【常规的线程之间的通信机制】,即建立内存共享区,然后进程B往内存共享区里写,进程A从内存共享区里读,从而完成通信。因为进程间的资源不能共享的,所以每个系统都有自己的IPC机制,Android是基于Linux内核的移动操作系统,而且因为App是运行在自己的虚拟机进程里面,有着自己的内存映射,所以没有用内存共享实现,也并没有继承Linux的IPC机制【管道(PIPE)、消息排队、旗语、共用内存以及套接字(Socket)】,而是它自己定义了一套自己的一套IPC机制(AIDL)。
AIDL是什么,怎么实现的
1)、定义AIDL文件;——类似于后台给了一个接口文档,里面描述了各种各样的接口,而在AIDL文件中描述的是类似于JAVA接口的方法定义
2)、实现AIDL文件里面定义的接口;——类似于后台实现接口文档的接口控制器,里面定义了接口的具体实现
3)、暴露接口;——这个就像后台开发人员把接口文档给App开发人员,然后App开发人员就知道有哪些接口可以调用来实现业务了
4)、调用;——这个就是App开发人员调用后台的接口来获取过程数据了。
从上面的描述可以看出,这个AIDL实际上就是一个C/S模型,一边是客户端,一边是服务器。
首先得明白一个接口,IInterface 接口类,IInterface 接口类提供类型变换功能,将服务或服务代理类转换为 IBinder 类型,后面再详谈具体 IInterface 中asBinder()的问题。
package android.os;
//Binder接口的基类。 定义新服务接口时,必须从IInterface派生它。
public interface IInterface
{
//检索与此接口关联的Binder对象。 您必须使用此代替简单转换,以便代理对象可以返回正确的结果。
public IBinder asBinder();
}
那么首先得从服务看,看看服务是如何提供接口的
第一步:定义AIDL文件,那么看看一般手写的接口文档是什么样的,如下:
// IMyAidlInterface.aidl
package com.visualing.mk.plugins.action;
// Declare any non-default types here with import statements
//定义接口
interface IMyAidlInterface {
/**
* Demonstrates some basic types that you can use as parameters
* and return values in AIDL.
*/
//定义接口方法,描述接口信息
void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat,
double aDouble, String aString);
}
上面这个接口虽然也写的明白,但不够完善,随便看看也就罢了,工作的时候经常有工具可以把文档变得更加完善,那么可以看看Android Studio是怎么转换的,同步一下工程会发现有个根据aidl文件生成的java文件,里面定义了具体的可以暴露给客户端的接口,就完成了第三步:暴露接口
package com.visualing.mk.plugins.action;
public interface IMyAidlInterface extends android.os.IInterface
{
///////////////////////////方法定义区域///////////////////////////
public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, java.lang.String aString) throws android.os.RemoteException;
///////////////////////////方法定义区域///////////////////////////
}
那么服务端是怎么做好第二步:实现AIDL文件里面定义的接口,仔细看下内容,会发现有这样的一个抽象类,该类实现了android.os.Binder类,并且实现了com.visualing.mk.plugins.action.IMyAidlInterface接口,这个类干什么用的呢,这个就是服务端需要实现的一个类,用于对外提供服务。服务端需要实现com.visualing.mk.plugins.action.IMyAidlInterface接口中的所有内容。
public static abstract class Stub extends android.os.Binder implements com.visualing.mk.plugins.action.IMyAidlInterface
{
private static final java.lang.String DESCRIPTOR = "com.visualing.mk.plugins.action.IMyAidlInterface";
public Stub()
{
//绑定接口
this.attachInterface(this, DESCRIPTOR);
}
@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_basicTypes:
{
data.enforceInterface(DESCRIPTOR);
int _arg0;
_arg0 = data.readInt();
long _arg1;
_arg1 = data.readLong();
boolean _arg2;
_arg2 = (0!=data.readInt());
float _arg3;
_arg3 = data.readFloat();
double _arg4;
_arg4 = data.readDouble();
java.lang.String _arg5;
_arg5 = data.readString();
this.basicTypes(_arg0, _arg1, _arg2, _arg3, _arg4, _arg5);
reply.writeNoException();
return true;
}
}
return super.onTransact(code, data, reply, flags);
}
//方法对象映射的常量生命,是通过常量值来判定的
static final int TRANSACTION_basicTypes = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
}
通过实现该Stub类,则可以实现服务端的具体内容,即完成第二步:实现AIDL文件里面定义的接口
接下来从客户端来看,我们知道客户端连接服务端是通过以下方法的
IMyAidlInterface mAidlInterface;
ServiceConnection conn =new ServiceConnection(){
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
mAidlInterface = IMyAidlInterface.Stub.asInterface(service);
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
};
protected void bindService() {
bindService(intent,conn,Service.BIND_AUTO_CREATE);
}
上面我们看到一段代码IMyAidlInterface.Stub.asInterface(service),那它是怎么实现的呢
public static com.visualing.mk.plugins.action.IMyAidlInterface asInterface(android.os.IBinder obj)
{
if ((obj==null)) {
return null;
}
//尝试检索此Binder对象的本地接口实现。 如果返回null,则需要代理
//这个服务是以后台服务还是本地服务,如果是本地服务直接返回本地接口实现,否则生成远程代理对象
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
//本地服务直接返回本地接口实现判断
if (((iin!=null)&&(iin instanceof com.visualing.mk.plugins.action.IMyAidlInterface))) {
return ((com.visualing.mk.plugins.action.IMyAidlInterface)iin);
}
//生成代理对象
return new com.visualing.mk.plugins.action.IMyAidlInterface.Stub.Proxy(obj);
}
看到类的实现,知道了进行进程间通信首先连接时需要判断服务是其他进程服务还是本身进程服务,如果是本身进程服务则直接返回本地接口实现,否则生成远程代理对象Proxy,用于沟通远程进程对象。
//////////远程服务方法代理对象////////////////////////////////////////////////////////////////////////////////////////
private static class Proxy implements com.visualing.mk.plugins.action.IMyAidlInterface
{
//和远程服务绑定的对象,远程被代理的对象
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;
}
//演示一些基本类型,您可以将它们用作参数并在AIDL中返回值。
@Override
public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, java.lang.String aString) 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(anInt);
_data.writeLong(aLong);
_data.writeInt(((aBoolean)?(1):(0)));
_data.writeFloat(aFloat);
_data.writeDouble(aDouble);
_data.writeString(aString);
mRemote.transact(Stub.TRANSACTION_basicTypes, _data, _reply, 0);
_reply.readException();
}
finally {
_reply.recycle();
_data.recycle();
}
}
}
通过上面这个代理,就可以调取的远程进程的方法,从上述代码可以看到关键是mRemote.transact(Stub.TRANSACTION_basicTypes, _data, _reply, 0)这个联通远程方法调用。
同时Proxy代理类实现了com.visualing.mk.plugins.action.IMyAidlInterface接口,因此获取了该对象之后,程序就能够使用com.visualing.mk.plugins.action.IMyAidlInterface借口中的方法。
看看客户端和服务端的方法是怎么样实现映射的
static final int TRANSACTION_basicTypes = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
该常量在
public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, java.lang.String aString) throws android.os.RemoteException
{
mRemote.transact(Stub.TRANSACTION_basicTypes, _data, _reply, 0);
}
和
public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException
{
switch (code)
{
case TRANSACTION_basicTypes:
{
this.basicTypes(_arg0, _arg1, _arg2, _arg3, _arg4, _arg5);
return true;
}
}
return super.onTransact(code, data, reply, flags);
}
可以看到这两个方法transact和onTransact就是客户端与服务端通信的具体方式了。而App调用这两种方法中间过程发生的机制,那就是Android中常说的Binder机制,这个后续再看。