Android下AIDL机制详解

简介: AIDL全名Android Interface Definition Language,是一种接口定义语言,也是Android系统的一种跨进程通信机制。从AIDL的名字就可以看出来,AIDL做的就是在服务提供进程和服务使用进程之间的协商好的接口,双方通过该接口进行通信。本文将以一个例子来讲述AIDL的使用方式和流程,在下一篇文章中我将从代码层面对AIDL进行分析。 ### AIDL实例 文

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.IInterfaceattachInterface方法来完成自我构造。接下来是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了。

相关文章
|
2月前
|
Java Android开发
[Android AIDL] --- AIDL工程搭建
[Android AIDL] --- AIDL工程搭建
18 0
|
2月前
|
Java 开发工具 Android开发
[Android AIDL] --- AIDL原理简析
[Android AIDL] --- AIDL原理简析
33 0
|
4月前
|
Android开发 容器
[Android]View的事件分发机制(源码解析)
[Android]View的事件分发机制(源码解析)
36 0
|
4月前
|
消息中间件 缓存 安全
android开发,使用kotlin学习消息机制Handler
android开发,使用kotlin学习消息机制Handler
81 0
|
4月前
|
安全 Android开发 Kotlin
android开发,使用kotlin学习Android权限机制
android开发,使用kotlin学习Android权限机制
38 0
|
8月前
|
Android开发
Android 使用Alarm机制创建长时间在后台运行的定时任务
Android 使用Alarm机制创建长时间在后台运行的定时任务
158 0
|
8月前
|
Java API Android开发
Android 权限机制详解
Android 权限机制详解
74 0
|
8月前
|
XML 消息中间件 API
Android 中handler消息机制的理解
Android 中handler消息机制的理解
48 0