前言
AIDL是Android提供的方便应用层进行进程间通信的描述语言,同时也提供了AIDL语言转成Java语言的工具,方便客户端开发,下面我们通过一个简单的例子来说明AIDL是怎么使用的,以及这样设计背后的意义。
DEMO
定义aidl
1 2 3 4
| interface IBookManager { List<Book> getBookList(); void addBook(Book book); }
|
针对这样一个AIDL文件,编译之后,生成一个IBookManager.java文件,代码如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111
| public interface IBookManager extends android.os.IInterface {
public static abstract class Stub extends android.os.Binder implements com.nancyyihao.aidlserver.IBookManager { private static final java.lang.String DESCRIPTOR = "com.nancyyihao.aidlserver.IBookManager"; public Stub() { this.attachInterface(this, DESCRIPTOR); }
public static com.nancyyihao.aidlserver.IBookManager asInterface(android.os.IBinder obj) { if ((obj == null)) { return null; } android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR); if (((iin != null) && (iin instanceof com.nancyyihao.aidlserver.IBookManager))) { return ((com.nancyyihao.aidlserver.IBookManager) iin); } return new com.nancyyihao.aidlserver.IBookManager.Stub.Proxy(obj); } public android.os.IBinder asBinder() { return this; } 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.nancyyihao.aidlserver.Book> _result = this.getBookList(); reply.writeNoException(); reply.writeTypedList(_result); return true; } case TRANSACTION_addBook: { data.enforceInterface(DESCRIPTOR); com.nancyyihao.aidlserver.Book _arg0; if ((0 != data.readInt())) { _arg0 = com.nancyyihao.aidlserver.Book.CREATOR.createFromParcel(data); } else { _arg0 = null; } this.addBook(_arg0); reply.writeNoException(); return true; } } return super.onTransact(code, data, reply, flags); } private static class Proxy implements com.nancyyihao.aidlserver.IBookManager { 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 java.util.List<com.nancyyihao.aidlserver.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.nancyyihao.aidlserver.Book> _result; try { _data.writeInterfaceToken(DESCRIPTOR); mRemote.transact(Stub.TRANSACTION_getBookList, _data, _reply, 0); _reply.readException(); _result = _reply.createTypedArrayList(com.nancyyihao.aidlserver.Book.CREATOR); } finally { _reply.recycle(); _data.recycle(); } return _result; } public void addBook(com.nancyyihao.aidlserver.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.nancyyihao.aidlserver.Book> getBookList() throws android.os.RemoteException; public void addBook(com.nancyyihao.aidlserver.Book book) throws android.os.RemoteException; }
|
代码分析
生成的代码主要有三部分,如下图所示
- 第一部分:IBookManager的Java接口,其实就是把AIDL语言转成了Java语言
- 第二部分:Stub抽象类,留给服务端实现,主要包含两个方法,一个是asInterface方法,该方法会返回一个实现了IBookManager的一个实例;另外一个onTransact方法,该方法会根据不同的transact code调用执行相应的业务逻辑,这个业务逻辑由Stub子类去实现
- 第三部分:Proxy类,工作在客户端侧,实现了对Binder数据请求的封装,会调用mRemote.transact方法进行binder请求。
对于服务端,只需要写一个类实现具体的业务了逻辑就可以了;比如BookManagerService,而对于客户端
1 2
| IBookManager manager = IBookManager.Stub.asInterface(IBinder); manager.getBookList();
|
也只需要调用Stub.asInterface()拿到相应的实例,然后就直接调用相应的方法即可。这样设计的好处首先是完全屏蔽了底层的Binder通信,IPC就相当于一个普通的方法调用,其次是服务端也不用关心数据接收和组装(当然服务端要做好同步),只需要实现好对应的业务逻辑,不得不说这样的设计思路值得我们学习。
通过上面的例子我们也可以知道,想要使用Binder通信,当然也可以不用AIDL,完全可以自己写对应的Stub/Proxy/IBookManager接口类,核心是要根据接口封装出对应的数据接口,然后调用mRemote.transact方法就可以和服务端进行通信,不过既然有工具帮你做好,干嘛不用呢?
总结
通过查看Android源码之后,我们可以看到Framework层绝大部分系统服务都遵循这样的设计模式,先定义一个接口(服务),然后实现对应的Stub/Proxy/Service(Service驻留在system_server进程,Proxy都是给app侧使用的),最后客户端就可以通过ServiceManager.getService拿到系统提供的服务,IPC就相当于一个简单方法调用,下一篇文章我们会以ActivityManager为例,分析系统调用过程,敬请期待。