简介
最近重温了下开发艺术探索里面的IPC机制,对于AIDL做下笔记
使用时,客户端定义AIDL接口方法
package com.lpc.aidltest;
// Declare any non-default types here with import statements
import com.lpc.aidltest.Book;
interface IBookInterface {
List<Book> getBookList();
void addBook(in Book book);
}
以及Parcelable数据类:
public class Book implements Parcelable {
int bookId ;
String bookName;
protected Book(Parcel in) {
bookId = in.readInt();
bookName = in.readString();
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(bookId);
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];
}
};
}
编译后,系统生成AIDL实现的android.os.IInterface
Java类—-IBookInterface
,里面asBinder返回一个IBinder对象:
这个接口实现类,里面定义了2个空方法和一个Binder类型的Stub类,Stub类实现了外部类IBookInterface,原本需要重写getBookList和addBook方法,但是由于它是abstract类型的,所以实际上这个两个方法都是放在Stub的私有静态类Proxy里重写的,故而Proxy也实现了IBookInterface接口。
asInterface里面,根据客户端和服务器是否在同一进程,分别返回服务端的IBinder ,也就是Stub本身和客户端使用的IBinder–Proxy:
public static com.lpc.aidltest.IBookInterface asInterface(android.os.IBinder obj)
{
if ((obj==null)) {
return null;
}
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin!=null)&&(iin instanceof com.lpc.aidltest.IBookInterface))) {
return ((com.lpc.aidltest.IBookInterface)iin);
}
return new com.lpc.aidltest.IBookInterface.Stub.Proxy(obj);
}
Proxy里面存有一个服务端的IBinder对象mRemote
1、不在同一进程时
调用的时Proxy里面的getBookList和addBook方法,都会使用服务端的IBinder实例mRemote的transact方法:
@Override public java.util.List<com.lpc.aidltest.Book> getBookList() throws android.os.RemoteException
{
//输入对象_data
android.os.Parcel _data = android.os.Parcel.obtain();
//输出结果_reply
android.os.Parcel _reply = android.os.Parcel.obtain();
java.util.List<com.lpc.aidltest.Book> _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
//调用服务端,也就是Stub的onTransact,传入_data,返回_reply
mRemote.transact(Stub.TRANSACTION_getBookList, _data, _reply, 0);
_reply.readException();
_result = _reply.createTypedArrayList(com.lpc.aidltest.Book.CREATOR);
}
finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
通过transact的源码可以知道,实际上就是调用了Stub的onTransact方法。
2、在同一进程时
asInterface直接返回服务端的IBinder,也就是Stub,虽然Stub也实现了IBookInterface接口,但是由于它是abstract类型的,所以没有重写getBookList和addBook方法,而是直接通过onTransact来实现。
@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_getBookList:
{
data.enforceInterface(DESCRIPTOR);
java.util.List<com.lpc.aidltest.Book> _result = this.getBookList();
reply.writeNoException();
reply.writeTypedList(_result);
return true;
}
case TRANSACTION_addBook:
{
data.enforceInterface(DESCRIPTOR);
com.lpc.aidltest.Book _arg0;
if ((0!=data.readInt())) {
_arg0 = com.lpc.aidltest.Book.CREATOR.createFromParcel(data);
}
else {
_arg0 = null;
}
this.addBook(_arg0);
reply.writeNoException();
return true;
}
}
return super.onTransact(code, data, reply, flags);
}
在onTransact里面通过方法对于的Flag来分别实现getBookList和addBook方法,在客户端请求transact方法时,线程回挂起,然后服务端onTransact执行,返回结果后,线程继续执行,从reply里面拿到结果。
最后看一段使用代码:
IBookManager bookManager = IBookManager.Stub.asInterface(service);
mRemoteBookManager.asBinder().linkToDeath(mDeathRecipient, 0);
List<Book> list = bookManager.getBookList();
Book newBook = new Book(3, "Android进阶");
bookManager.addBook(newBook);
上面的代码,总结下来就是:客户端定义AIDL方法(IBookManager.aidl),然后系统生成IBinder类(IBookManager.java),里面有服务端Stub和客户端Proxy,客户端通过IBinder类的Stub里面的asInterface拿到Proxy代理接口,调用接口里的getBookList方法,唤起服务端的onTransact方法,进行数据的操作,然后将结果放入reply中,返回给Proxy