前言
对于Android来说,Binder的重要性怎么说都不为过。不管是我们的四大组件Activity、Service、BroadcastReceiver、ContentProvider,还是经常在应用中使用到的各种ServiceManager,其背后都是Binder在支撑。然而Binder机制又不是三言两语能够描述得清楚的,因此本文通过对一个简单的AIDL Demo进行分析,让读者对Binder有个初步的认识,要想深入了解Binder背后的原理,可以参考最后的延伸阅读。
Demo
首先我们通过AIDL新建一个跨进程通信的Demo,然后在代码中简单分析Binder的运行过程。
Server Module
我们先新建一个提供接口的AIDL服务端module,服务端主要提供AddBook和getBookList两个功能,其目录如下:
- IBookManager.AIDL
1 2 3 4 5 6 7 8
| package com.nancyyihao.aidlserver; import com.nancyyihao.aidlserver.Book;
interface IBookManager { List<Book> getBookList(); void addBook(in Book book); }
|
- Book.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
| package com.nancyyihao.aidlserver; import android.os.Parcel; import android.os.Parcelable;
public class Book implements Parcelable { private String bookName; private int bookId; public Book(){} public Book(int bookId, String bookName){ this.bookId = bookId ; this.bookName = bookName ; } public Book(Parcel parcel){ bookName = parcel.readString(); bookId = parcel.readInt(); } public String getBookName() { return bookName; } public void setBookName(String bookName) { this.bookName = bookName; } public int getBookId() { return bookId; } public void setBookId(int bookId) { this.bookId = bookId; } @Override public int describeContents() { return 0; } @Override public void writeToParcel(Parcel dest, int flags) { dest.writeString(bookName); dest.writeInt(bookId); } public static final Parcelable.Creator<Book> CREATOR = new Creator<Book>(){ @Override public Book createFromParcel(Parcel source) { return new Book(source); } @Override public Book[] newArray(int size) { return new Book[size]; } }; }
|
- Book.AIDL
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
| package com.nancyyihao.aidlserver; parcelable Book; BookManagerService
package com.nancyyihao.aidlserver; import android.app.Service; import android.content.Intent; import android.os.Binder; import android.os.IBinder; import android.os.RemoteException; import java.util.List; import java.util.concurrent.CopyOnWriteArrayList;
public class BookManagerService extends Service { private static final String TAG = "BMS"; private CopyOnWriteArrayList<Book> mBookList = new CopyOnWriteArrayList<>(); @Override public IBinder onBind(Intent intent) { return mBinder; } @Override public void onCreate() { super.onCreate(); mBookList.add(new Book(3,"Android")); mBookList.add(new Book(4,"iOS")); } private Binder mBinder = new IBookManager.Stub() { @Override public List<Book> getBookList() throws RemoteException { return mBookList; } @Override public void addBook(Book book) throws RemoteException { mBookList.add(book); } } ; }
|
Client Module
把Server module的代码拷贝一份(AIDL包名不能变),然后新建一个MainActivity即可
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
| MainActivity package com.nancyyihao.aidlserver; import android.content.ComponentName; import android.content.Intent; import android.content.ServiceConnection; import android.os.Bundle; import android.os.IBinder; import android.support.v7.app.AppCompatActivity; import android.util.Log; import com.nancyyihao.R; import java.util.List; public class MainActivity extends AppCompatActivity { private static final String TAG = "MainActivity"; private ServiceConnection mConnection = new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder service) { IBookManager bookManager = IBookManager.Stub.asInterface(service); Log.e("trace", "onServiceConnected"); try { List<Book> bookList = bookManager.getBookList(); Log.e(TAG, "query book list, list type:" + bookList.getClass().getCanonicalName()); Log.e(TAG, "query book list:" + bookList.toString()); } catch (Exception e) { e.printStackTrace(); } } @Override public void onServiceDisconnected(ComponentName name) { } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); final Intent intent = new Intent(); intent.setAction("com.nancyyihao.startservice"); intent.setPackage("com.nancyyihao.aidlserver"); Log.e("trace", "bindService"); bindService(intent, mConnection, BIND_AUTO_CREATE); } @Override protected void onDestroy() { super.onDestroy(); unbindService(mConnection); } }
|
分析
把代码写好后,build一下,就能看到自动生成了一个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 112
| package com.nancyyihao.aidlserver;
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); } @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 { 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; } @Override public android.os.IBinder asBinder() { return mRemote; } public java.lang.String getInterfaceDescriptor() { return DESCRIPTOR; } @Override 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; } @Override 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; }
|
Client先调用bindService启动服务,会调用BookManagerService的onCreate方法,接着调用onBind方法,该方法会返回远程的Binder—mBinder,该Binder包含getBookList和AddBook两个方法的具体实现。
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| @Override public IBinder onBind(Intent intent) { return mBinder; } private Binder mBinder = new IBookManager.Stub() { @Override public List<Book> getBookList() throws RemoteException { return mBookList; } @Override public void addBook(Book book) throws RemoteException { mBookList.add(book); } } ;
|
当Client和server成功建立连接时,就会调用Client的onServiceConnected(name, service)方法把远程的mBinder回调给Client,此时的service就是远程的mBinder对象
1 2 3 4 5 6 7 8 9 10 11
| private ServiceConnection mConnection = new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder service) { IBookManager bookManager = IBookManager.Stub.asInterface(service); Log.e("trace", "onServiceConnected"); try { List<Book> bookList = bookManager.getBookList(); } catch (Exception e) { e.printStackTrace(); } }
|
Client端通过asInterface方法把mBinder转成AIDL接口,如果是本进程内的Binder就直接返回,否则返回内部代理类proxy
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
| 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); } 接着执行
try { List<Book> bookList = bookManager.getBookList(); } catch (Exception e) { e.printStackTrace(); } 此时的bookManager通过asInterface方法转换后,返回的实际上是本地的proxy类
private static class Proxy implements com.nancyyihao.aidlserver.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.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; } @Override 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); }
|
通过代码我们可以看到proxy类其实也是一个IBookManager接口,调用bookManager.getBookList()其实是调用Proxy.getBookList。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| @Override 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; }
|
在Proxy.getBookList方法中调用了mRemote.trasact()
1 2 3 4 5 6 7 8 9 10 11 12
| public final boolean transact(int code, Parcel data, Parcel reply, int flags) throws RemoteException { if (false) Log.v("Binder", "Transact: " + code + " to " + this); if (data != null) { data.setDataPosition(0); } boolean r = onTransact(code, data, reply, flags); if (reply != null) { reply.setDataPosition(0); } return r; }
|
Client就是在这里和Server进行远程通信的!把需要的参数放data中,服务端执行完后把接口写到result里。从代码中可以看到transact方法中调用了onTransact方法。我们再看看onTransact方法有啥东西。
1 2 3 4 5 6 7 8 9 10 11 12
| @Override public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException { ...... case TRANSACTION_getBookList: { data.enforceInterface(DESCRIPTOR); java.util.List<com.nancyyihao.aidlserver.Book> _result = this.getBookList(); reply.writeNoException(); reply.writeTypedList(_result); return true; } ...... }
|
直接调用了this.getBookList方法返回结果,这个this到底是哪个对象?前面提到mRemote其实是远程中的Binder对象,其代码如下
1 2 3 4 5 6 7 8 9 10
| private Binder mBinder = new IBookManager.Stub() { @Override public List<Book> getBookList() throws RemoteException { return mBookList; } @Override public void addBook(Book book) throws RemoteException { mBookList.add(book); } } ;
|
this.getBookList其实就是mRemote.getBookList,就是上面代码中的mBinder.getBookList!然后把返回结果放到result中即可。至此,整个通信过程分析完毕。
总结
- Client是通过本地的Proxy类像Server发起通信
- Client通过ServerConnection接口回调收到Server远程Binder对象
- IPC过程发生在transact方法中,该方法会挂起直到服务端返回结果,因此不能在主线程调用远程服务。
图片和文中Demo来自《Android开发技术探索》
源码下载
Android-AIDL-Demo
延伸阅读