AIDL:Android Interface Definition Language,即Android接口定义语言。Android系统中的进程之间不能共享内存,因此,需要提供一些机制在不同进程之间进行数据通信。
为了使其他的应用程序也可以访问本应用程序提供的服务,Android系统采用了远程过程调用(Remote Procedure Call,RPC)方式来实现。与很多其他的基于RPC的解决方案一样,Android使用一种接口定义语言(Interface Definition Language,IDL)来公开服务的接口。我们知道4个Android应用程序组件中的3个(Activity、BroadcastReceiver和ContentProvider)都可以进行跨进程访问,另外一个Android应用程序组件Service同样可以。因此,可以将这种可以跨进程访问的服务称为AIDL(Android Interface Definition Language)服务。
1.使用
1.1实现parcelable接口
跨进程通信的类必要实现Parcelable接口
Book.java
package com.example.zhouk.testproject.aidl;
import android.os.Parcel;
import android.os.Parcelable;
public class Book implements Parcelable {
public String bookName;
protected Book(Parcel in) {
bookName = in.readString();
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(bookName);
}
@Override
public int describeContents() {
return 0;
}
public static final Creator<Book> CREATOR = new Creator<Book>() {
@Override
public Book createFromParcel(Parcel in) {
return new Book(in);
}
@Override
public Book[] newArray(int size) {
return new Book[size];
}
};
}
1.2对传递的类创建aidl文件
Book.aidl,且该文件必须位于com.example.zhouk.testproject.aidl目录下
package com.example.zhouk.testproject.aidl;
parcelable Book;
1.3创建接口aidl文件
IBookManager.aidl
package com.example.zhouk.testproject.aidl;
import com.example.zhouk.testproject.aidl.Book;
interface IBookManager {
List<Book> getBookList();
void addBook(in Book book);
}
上文代码中的接口一共有了两个函数接口,且必须引入parcelable类的路径,因为aidl与java文件不同,即使在同包下也必须手动导入。
1.4 build 项目
点击Build Project 会在build目录下生成IBookManager.java接口,在代码中继承这个接口就可以实现AIDL进程间通信了。
1.5 server实现接口
package com.example.zhouk.testproject.aidl;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.os.RemoteException;
import java.util.ArrayList;
import java.util.List;
public class BookService extends Service {
private final String TAG = "BookService";
private List<Book> bookList;
public BookService() {}
@Override
public void onCreate() {
super.onCreate();
bookList = new ArrayList<>();
bookList.add(new Book("TestBook"));
}
private final IBookManager.Stub binder = new IBookManager.Stub() {
@Override
public List<Book> getBookList() throws RemoteException {
synchronized (bookList) {
return bookList;
}
}
@Override
public void addBook(Book book) throws RemoteException {
if(book != null) {
synchronized (bookList) {
bookList.add(book);
}
}
}
};
@Override
public IBinder onBind(Intent intent) {
return binder;
}
}
1.6 client调用接口
IBookManager bookManager;
Boolean connected = false;
private ServiceConnection serviceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
bookManager = IBookManager.Stub.asInterface(service);
connected = true;
}
@Override
public void onServiceDisconnected(ComponentName name) {
connected = false;
}
};
client可以通过bindService方法,在ServiceConnection中获取到Binder,调用Stub.asInterface接口获取到接口,实现RPC 远程过程调用
2.分析
2.1总体分析
系统生成的IBookManager接口,核心功能实现主要在内部抽象类Stub里,Stub实现了IBookManager接口但未实现具体业务,且继承了android.os.Binder,故Stub就是服务端要实现的Binder接口,Stub内部有个Proxy类也实现了IBookManager接口,采用代理模式和Parcelable实现了跨进程通信,即跨进程中client调用的就是该Proxy类。
2.2 IBookManager接口分析
public interface IBookManager extends android.os.IInterface
{
public java.util.List<com.example.zhouk.testproject.aidl.Book> getBookList() throws android.os.RemoteException;
public void addBook(com.example.zhouk.testproject.aidl.Book book) throws android.os.RemoteException;
}
IBookManager接口的代码比较简单,只有之前在aidl文件中定义的两个函数接口
2.3 Stub抽象类
Stub是IBookManager接口的内部抽象类,继承了android.os.Binder,是Binder的扩展类,在服务端的Service中,通过onBind函数返回,这里采用了里氏替换原则,而Stub的具体业务接口实现也是在Service中完成的。
- Stub内部定义了一个DESCRIPTOR用作当前Binder的唯一标识。
- asInterface函数
public static com.example.zhouk.testproject.aidl.IBookManager asInterface(android.os.IBinder obj)
{
if ((obj==null)) {
return null;
}
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin!=null)&&(iin instanceof com.example.zhouk.testproject.aidl.IBookManager))) {
return ((com.example.zhouk.testproject.aidl.IBookManager)iin);
}
return new com.example.zhouk.testproject.aidl.IBookManager.Stub.Proxy(obj);
}
传递binder参数到函数内,调用该Binder变量的queryLocalInterface,判断当前进程是否是服务端进程,如果是就没有跨进程,直接返回改Binder,若跨进程则返回代理类Proxy,采用RPC方式处理。
- asBinder函数
@Override
public android.os.IBinder asBinder()
{
return this;
}
返回当前binder类
- onTransact函数
@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_getBookList:
{
data.enforceInterface(descriptor);
java.util.List<com.example.zhouk.testproject.aidl.Book> _result = this.getBookList();
reply.writeNoException();
reply.writeTypedList(_result);
return true;
}
case TRANSACTION_addBook:
{
data.enforceInterface(descriptor);
com.example.zhouk.testproject.aidl.Book _arg0;
if ((0!=data.readInt())) {
_arg0 = com.example.zhouk.testproject.aidl.Book.CREATOR.createFromParcel(data);
}
else {
_arg0 = null;
}
this.addBook(_arg0);
reply.writeNoException();
return true;
}
default:
{
return super.onTransact(code, data, reply, flags);
}
}
}
RPC的核心传输代码,该函数运行在服务端中的Binder线池中,当客户端发起跨进程请求时,远程请求会通过系统底层封装后交由此方法处理。code确定目标方法,data为写入参数,reply为返回值。
2.4 Proxy类
Proxy实现了IBookManager接口,对两接口实现了RPC数据封装,
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
初始化信息传递的载体
_data.writeInterfaceToken(DESCRIPTOR);
if ((book!=null)) {
_data.writeInt(1);
book.writeToParcel(_data, 0);
}
addBook中,book参数的传入
mRemote.transact(Stub.TRANSACTION_getBookList, _data, _reply, 0);
发起传输
_reply.readException();
_result = _reply.createTypedArrayList(com.example.zhouk.testproject.aidl.Book.CREATOR);
读取返回值
完整代码
/*
* This file is auto-generated. DO NOT MODIFY.
* Original file: C:\\Users\\zhouk\\AndroidStudioProjects\\testProject\\app\\src\\main\\aidl\\com\\example\\zhouk\\testproject\\aidl\\IBookManager.aidl
*/
package com.example.zhouk.testproject.aidl;
public interface IBookManager extends android.os.IInterface
{
/** Local-side IPC implementation stub class. */
public static abstract class Stub extends android.os.Binder implements com.example.zhouk.testproject.aidl.IBookManager
{
private static final java.lang.String DESCRIPTOR = "com.example.zhouk.testproject.aidl.IBookManager";
/** Construct the stub at attach it to the interface. */
public Stub()
{
this.attachInterface(this, DESCRIPTOR);
}
/**
* Cast an IBinder object into an com.example.zhouk.testproject.aidl.IBookManager interface,
* generating a proxy if needed.
*/
public static com.example.zhouk.testproject.aidl.IBookManager asInterface(android.os.IBinder obj)
{
if ((obj==null)) {
return null;
}
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin!=null)&&(iin instanceof com.example.zhouk.testproject.aidl.IBookManager))) {
return ((com.example.zhouk.testproject.aidl.IBookManager)iin);
}
return new com.example.zhouk.testproject.aidl.IBookManager.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_getBookList:
{
data.enforceInterface(descriptor);
java.util.List<com.example.zhouk.testproject.aidl.Book> _result = this.getBookList();
reply.writeNoException();
reply.writeTypedList(_result);
return true;
}
case TRANSACTION_addBook:
{
data.enforceInterface(descriptor);
com.example.zhouk.testproject.aidl.Book _arg0;
if ((0!=data.readInt())) {
_arg0 = com.example.zhouk.testproject.aidl.Book.CREATOR.createFromParcel(data);
}
else {
_arg0 = null;
}
this.addBook(_arg0);
reply.writeNoException();
return true;
}
default:
{
return super.onTransact(code, data, reply, flags);
}
}
}
private static class Proxy implements com.example.zhouk.testproject.aidl.IBookManager
{
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 java.util.List<com.example.zhouk.testproject.aidl.Book> getBookList() throws android.os.RemoteException
{
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
java.util.List<com.example.zhouk.testproject.aidl.Book> _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
mRemote.transact(Stub.TRANSACTION_getBookList, _data, _reply, 0);
_reply.readException();
_result = _reply.createTypedArrayList(com.example.zhouk.testproject.aidl.Book.CREATOR);
}
finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
@Override public void addBook(com.example.zhouk.testproject.aidl.Book book) throws android.os.RemoteException
{
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
try {
_data.writeInterfaceToken(DESCRIPTOR);
if ((book!=null)) {
_data.writeInt(1);
book.writeToParcel(_data, 0);
}
else {
_data.writeInt(0);
}
mRemote.transact(Stub.TRANSACTION_addBook, _data, _reply, 0);
_reply.readException();
}
finally {
_reply.recycle();
_data.recycle();
}
}
}
static final int TRANSACTION_getBookList = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
static final int TRANSACTION_addBook = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
}
public java.util.List<com.example.zhouk.testproject.aidl.Book> getBookList() throws android.os.RemoteException;
public void addBook(com.example.zhouk.testproject.aidl.Book book) throws android.os.RemoteException;
}