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了。

相关文章
|
22天前
|
消息中间件 存储 Java
Android消息处理机制(Handler+Looper+Message+MessageQueue)
Android消息处理机制(Handler+Looper+Message+MessageQueue)
35 2
|
6天前
|
消息中间件 存储 Java
Android面试高频知识点(2) 详解Android消息处理机制(Handler)
Android面试高频知识点(2) 详解Android消息处理机制(Handler)
|
9天前
|
消息中间件 存储 Java
Android面试高频知识点(2) 详解Android消息处理机制(Handler)
Android面试高频知识点(2) 详解Android消息处理机制(Handler)
30 1
|
10天前
|
存储 安全 数据安全/隐私保护
探索安卓与iOS的隐私保护机制####
【10月更文挑战第15天】 本文深入剖析了安卓和iOS两大操作系统在隐私保护方面的策略与技术实现,旨在揭示两者如何通过不同的技术手段来保障用户数据的安全与隐私。文章将逐一探讨各自的隐私控制功能、加密措施以及用户权限管理,为读者提供一个全面而深入的理解。 ####
26 1
|
13天前
|
消息中间件 存储 Java
Android消息处理机制(Handler+Looper+Message+MessageQueue)
Android消息处理机制(Handler+Looper+Message+MessageQueue)
42 2
|
2月前
|
存储 缓存 Android开发
Android RecyclerView 缓存机制深度解析与面试题
本文首发于公众号“AntDream”,详细解析了 `RecyclerView` 的缓存机制,包括多级缓存的原理与流程,并提供了常见面试题及答案。通过本文,你将深入了解 `RecyclerView` 的高性能秘诀,提升列表和网格的开发技能。
64 8
|
3月前
|
消息中间件 存储 Java
Android面试高频知识点(2) 详解Android消息处理机制(Handler)
Android 消息处理机制估计都被写烂了,但是依然还是要写一下,因为Android应用程序是通过消息来驱动的,Android某种意义上也可以说成是一个以消息驱动的系统,UI、事件、生命周期都和消息处理机制息息相关,并且消息处理机制在整个Android知识体系中也是尤其重要,在太多的源码分析的文章讲得比较繁琐,很多人对整个消息处理机制依然是懵懵懂懂,这篇文章通过一些问答的模式结合Android主线程(UI线程)的工作原理来讲解,源码注释很全,还有结合流程图,如果你对Android 消息处理机制还不是很理解,我相信只要你静下心来耐心的看,肯定会有不少的收获的。
182 3
Android面试高频知识点(2) 详解Android消息处理机制(Handler)
|
5月前
|
安全 算法 数据安全/隐私保护
探索iOS与Android的隐私保护机制
【6月更文挑战第5天】在数字时代,隐私保护已成为用户最关心的问题之一。iOS和Android作为两大主流操作系统,各自发展出了独特的隐私保护技术。本文将深入探讨这两个平台在隐私保护方面的策略、技术和挑战。
126 3
|
5月前
|
Android开发
38. 【Android教程】Handler 消息传递机制
38. 【Android教程】Handler 消息传递机制
52 2
|
5月前
|
大数据 Android开发
Android使用AIDL+MemoryFile传递大数据
Android使用AIDL+MemoryFile传递大数据
63 0