Android-Binder 简析
前言
對(duì)于Android來說,Binder的重要性怎么說都不為過。不管是我們的四大組件Activity、Service、BroadcastReceiver、ContentProvider,還是經(jīng)常在應(yīng)用中使用到的各種ServiceManager,其背后都是Binder在支撐。然而Binder機(jī)制又不是三言兩語能夠描述得清楚的,因此本文通過對(duì)一個(gè)簡(jiǎn)單的AIDL Demo進(jìn)行分析,讓讀者對(duì)Binder有個(gè)初步的認(rèn)識(shí),要想深入了解Binder背后的原理,可以參考最后的延伸閱讀。
Demo
首先我們通過AIDL新建一個(gè)跨進(jìn)程通信的Demo,然后在代碼中簡(jiǎn)單分析Binder的運(yùn)行過程。
Server Module
我們先新建一個(gè)提供接口的AIDL服務(wù)端module,服務(wù)端主要提供AddBook和getBookList兩個(gè)功能,其目錄如下:
p2.png
IBookManager.AIDL
Book.java
Book.AIDL
BookManagerService
Client Module
把Server module的代碼拷貝一份(AIDL包名不能變),然后新建一個(gè)MainActivity即可
MainActivity
分析
把代碼寫好后,build一下,就能看到自動(dòng)生成了一個(gè)IBookManager.Java文件
IBookManager.Java
p3.png package com.nancyyihao.aidlserver; // Declare any non-default types here with import statementspublic interface IBookManager extends android.os.IInterface {/*** Local-side IPC implementation stub class.*/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"; // Binder Indentifierpublic Stub() {this.attachInterface(this, DESCRIPTOR);}/*** Cast an IBinder object into an com.nancyyihao.aidlserver.IBookManager interface,* generating a proxy if needed.*/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); // local Binder}return new com.nancyyihao.aidlserver.IBookManager.Stub.Proxy(obj); // remote Binder}@Overridepublic android.os.IBinder asBinder() {return this;}@Overridepublic 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;}@Overridepublic android.os.IBinder asBinder() {return mRemote;}public java.lang.String getInterfaceDescriptor() {return DESCRIPTOR;}@Overridepublic 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;}@Overridepublic 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先調(diào)用bindService啟動(dòng)服務(wù),會(huì)調(diào)用BookManagerService的onCreate方法,接著調(diào)用onBind方法,該方法會(huì)返回遠(yuǎn)程的Binder---mBinder,該Binder包含getBookList和AddBook兩個(gè)方法的具體實(shí)現(xiàn)。
@Overridepublic IBinder onBind(Intent intent) {return mBinder;}private Binder mBinder = new IBookManager.Stub() {@Overridepublic List<Book> getBookList() throws RemoteException {return mBookList;}@Overridepublic void addBook(Book book) throws RemoteException {mBookList.add(book);}} ;當(dāng)Client和server成功建立連接時(shí),就會(huì)調(diào)用Client的onServiceConnected(name, service)方法把遠(yuǎn)程的mBinder回調(diào)給Client,此時(shí)的service就是遠(yuǎn)程的mBinder對(duì)象
private ServiceConnection mConnection = new ServiceConnection() {@Overridepublic 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轉(zhuǎn)成AIDL接口,如果是本進(jìn)程內(nèi)的Binder就直接返回,否則返回內(nèi)部代理類proxy
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); // local Binder}return new com.nancyyihao.aidlserver.IBookManager.Stub.Proxy(obj); // remote Binder}接著執(zhí)行
try {List<Book> bookList = bookManager.getBookList();} catch (Exception e) {e.printStackTrace();}此時(shí)的bookManager通過asInterface方法轉(zhuǎn)換后,返回的實(shí)際上是本地的proxy類
private static class Proxy implements com.nancyyihao.aidlserver.IBookManager {private android.os.IBinder mRemote;Proxy(android.os.IBinder remote) {mRemote = remote;}@Overridepublic android.os.IBinder asBinder() {return mRemote;}public java.lang.String getInterfaceDescriptor() {return DESCRIPTOR;}@Overridepublic 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;}@Overridepublic 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類其實(shí)也是一個(gè)IBookManager接口,調(diào)用bookManager.getBookList()其實(shí)是調(diào)用Proxy.getBookList。
@Overridepublic 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方法中調(diào)用了mRemote.trasact()
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進(jìn)行遠(yuǎn)程通信的!把需要的參數(shù)放data中,服務(wù)端執(zhí)行完后把接口寫到result里。從代碼中可以看到transact方法中調(diào)用了onTransact方法。我們?cè)倏纯磑nTransact方法有啥東西。
@Overridepublic 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;}......}直接調(diào)用了this.getBookList方法返回結(jié)果,這個(gè)this到底是哪個(gè)對(duì)象?前面提到mRemote其實(shí)是遠(yuǎn)程中的Binder對(duì)象,其代碼如下
private Binder mBinder = new IBookManager.Stub() {@Overridepublic List<Book> getBookList() throws RemoteException {return mBookList;}@Overridepublic void addBook(Book book) throws RemoteException {mBookList.add(book);}} ;this.getBookList其實(shí)就是mRemote.getBookList,就是上面代碼中的mBinder.getBookList!然后把返回結(jié)果放到result中即可。至此,整個(gè)通信過程分析完畢。
總結(jié)
Client是通過本地的Proxy類像Server發(fā)起通信
Client通過ServerConnection接口回調(diào)收到Server遠(yuǎn)程Binder對(duì)象
IPC過程發(fā)生在transact方法中,該方法會(huì)掛起直到服務(wù)端返回結(jié)果,因此不能在主線程調(diào)用遠(yuǎn)程服務(wù)。
p1.jpg
圖片和文中Demo來自《Android開發(fā)技術(shù)探索》
源碼下載
Android-AIDL-Demo
延伸閱讀
Binder學(xué)習(xí)指南
Android Bander設(shè)計(jì)與實(shí)現(xiàn) - 設(shè)計(jì)篇
Android進(jìn)程間通信(IPC)機(jī)制Binder簡(jiǎn)要介紹和學(xué)習(xí)計(jì)劃
轉(zhuǎn)載于:https://www.cnblogs.com/jasonkent27/p/5860680.html
總結(jié)
以上是生活随笔為你收集整理的Android-Binder 简析的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: java8-4 多态的练习以及题目
- 下一篇: Android官方培训课程中文版(v0.