1. 程式人生 > >android IPC機制(二)

android IPC機制(二)

Binder物件

是android中的一個類,實現了IBinder介面,是一種android中實現跨程序通訊的一種方式,可以ManagerService連線各種Manager(LayoutManager,ServiceManager,ActivityManager,SensorManager等等)和各種相應ManagerService的橋樑。

AIDL檔案之自動生成的java檔案

每次書寫aidl檔案之後,系統會自動生成相應的java檔案,比如本人自己寫的一個aidl檔案:

// IBookManager.aidl
package micro.com.chapter2.inter.aidl;

// Declare any non-default types here with import statements
import micro.com.chapter2.inter.aidl.Book ; import micro.com.chapter2.inter.aidl.Person ; import micro.com.chapter2.inter.aidl.INewBookArriveListener ; interface IBookManager { List<Book> getBooks(); void addBook(in Book book) ; void addPerson(in Person p); }

系統自動生成的IBookManager.java檔案是:

/*
 * This file is auto-generated.  DO NOT MODIFY.
 */
package micro.com.chapter2.inter.aidl;

public interface IBookManager extends android.os.IInterface {
    /**
     * Local-side IPC implementation stub class.
     */
    public static abstract class Stub extends android.os.Binder implements micro.
com.chapter2.inter.aidl.IBookManager
{ private static final java.lang.String DESCRIPTOR = "micro.com.chapter2.inter.aidl.IBookManager"; /** * Construct the stub at attach it to the interface. */ public Stub() { this.attachInterface(this, DESCRIPTOR); } /** * Cast an IBinder object into an micro.com.chapter2.inter.aidl.IBookManager interface, * generating a proxy if needed. */ public static micro.com.chapter2.inter.aidl.IBookManager asInterface(android.os.IBinder obj) { if ((obj == null)) { return null; } android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR); if (((iin != null) && (iin instanceof micro.com.chapter2.inter.aidl.IBookManager))) { return ((micro.com.chapter2.inter.aidl.IBookManager) iin); } return new micro.com.chapter2.inter.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 { switch (code) { case INTERFACE_TRANSACTION: reply.writeString(DESCRIPTOR); return true; case TRANSACTION_getBooks: { data.enforceInterface(DESCRIPTOR); java.util.List<micro.com.chapter2.inter.aidl.Book> _result = this.getBooks(); reply.writeNoException(); reply.writeTypedList(_result); return true; } case TRANSACTION_addBook: { data.enforceInterface(DESCRIPTOR); micro.com.chapter2.inter.aidl.Book _arg0; if ((0 != data.readInt())) { _arg0 = micro.com.chapter2.inter.aidl.Book.CREATOR.createFromParcel(data); } else { _arg0 = null; } this.addBook(_arg0); reply.writeNoException(); return true; } case TRANSACTION_addPerson: { data.enforceInterface(DESCRIPTOR); micro.com.chapter2.inter.aidl.Person _arg0; if ((0 != data.readInt())) { _arg0 = micro.com.chapter2.inter.aidl.Person.CREATOR.createFromParcel(data); } else { _arg0 = null; } this.addPerson(_arg0); reply.writeNoException(); return true; } } return super.onTransact(code, data, reply, flags); } private static class Proxy implements micro.com.chapter2.inter.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<micro.com.chapter2.inter.aidl.Book> getBooks() throws android.os.RemoteException { android.os.Parcel _data = android.os.Parcel.obtain(); android.os.Parcel _reply = android.os.Parcel.obtain(); java.util.List<micro.com.chapter2.inter.aidl.Book> _result; try { _data.writeInterfaceToken(DESCRIPTOR); mRemote.transact(Stub.TRANSACTION_getBooks, _data, _reply, 0); _reply.readException(); _result = _reply.createTypedArrayList(micro.com.chapter2.inter.aidl.Book.CREATOR); } finally { _reply.recycle(); _data.recycle(); } return _result; } @Override public void addBook(micro.com.chapter2.inter.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(); } } @Override public void addPerson(micro.com.chapter2.inter.aidl.Person p) 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 ((p != null)) { _data.writeInt(1); p.writeToParcel(_data, 0); } else { _data.writeInt(0); } mRemote.transact(Stub.TRANSACTION_addPerson, _data, _reply, 0); _reply.readException(); } finally { _reply.recycle(); _data.recycle(); } } } static final int TRANSACTION_getBooks = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1); static final int TRANSACTION_addBook = (android.os.IBinder.FIRST_CALL_TRANSACTION + 2); static final int TRANSACTION_addPerson = (android.os.IBinder.FIRST_CALL_TRANSACTION + 3); public java.util.List<micro.com.chapter2.inter.aidl.Book> getBooks() throws android.os.RemoteException; public void addBook(micro.com.chapter2.inter.aidl.Book book) throws android.os.RemoteException; public void addPerson(micro.com.chapter2.inter.aidl.Person p) throws android.os.RemoteException; }

其中重要屬性和方法說明如下:
1.DESCRIPTOR:
Binder中唯一的標識,自動生成時用當前Binder類名錶示。

static final int TRANSACTION_getBooks = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
static final int TRANSACTION_addBook = (android.os.IBinder.FIRST_CALL_TRANSACTION + 2);
static final int TRANSACTION_addPerson = (android.os.IBinder.FIRST_CALL_TRANSACTION + 3);

三個宣告的整型的id用於標識在transact過程中客戶端中請求的到底是哪個方法。

2.asInterface(android.os.IBinder object)
將服務端的Binder物件轉換成客戶端所需AIDL介面型別的物件,轉換是區分程序的,客戶端和伺服器在同一程序中,返回的是服務端Stub本身,否則就返回系統封裝後的Stub.proxy物件。

3.asBinder
返回當前的Binder物件

4.onTransact
本方法執行在伺服器端中Binder執行緒池中,客戶端發起跨程序請求時,遠端請求會通過系統底層封裝後交給此方法來處理:

public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException 

通過code確定客戶端方法的方法,然後從data中取得引數(如果存在引數的話),然後執行在服務端的目標方法,執行完成之後,向reply中寫入返回值(如果客戶端中需要返回值的話)。當然onTransact方法是有返回值的,如果返回false,那麼客戶端就會請求失敗。

5.Proxy#getBookList
在客戶端中執行,當客戶端遠端呼叫此方法時,內部實現方法如下:先建立所需的輸入型Parcel物件_data,輸出型Parcel物件 _replay和返回值物件List。先將需求引數寫入_data中,接著呼叫transact方法發起遠端呼叫(RPC)請求,同時當前執行緒會掛起,然後服務端的onTransact方法會被呼叫,當RPC方法結束返回後,當前執行緒從掛起狀態變成重新執行狀態,並從_reply中取出RPC過程的返回結果,最後返回 _reply中的資料。 基本圖解如下:

這裡寫圖片描述

linkToDeath & unlinkToDeath

Binder執行在服務端程序,如果服務程序由於某種原因異常終止,此時服務端的Binder連結斷裂(Binder死亡),會導致我們的遠端呼叫失敗。更為關鍵的是,不知道Binder連結斷裂,那麼客戶端的功能就會受影響。為了解決這個問題,Binder中提供了兩個配對的方法lineToDeath和unlinkToDeath,通過linktoDeath可以Binder設定死亡代理,Binder死亡時會受到死亡通知,此時可以重新發起連線請求從而恢復連結。

private IBinder.DeathRecipient mBinderPoolDeathRecipient = new IBinder.DeathRecipient() {
        @Override
        public void binderDied() {
            Log.d(TAG,"binder died...");
            //unlinkToDeath
            xxx.unlinkToDeath(mBinderPoolDeathRecipient,0);
            //restart server or rebinding ServiceConnection
        }
    } ;

在客戶端繫結遠端服務成功後,給binder設定死亡代理:

private ServiceConnection mServiceConnection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
            try {
               //linktoDeath
                xxx.linkToDeath(mBinderPoolDeathRecipient,0);
            } catch (RemoteException e) {
                e.printStackTrace();
            }
        }

        @Override
        public void onServiceDisconnected(ComponentName componentName) {}
    } ;

基本上通過以上兩個步驟,就會給我們的Binder設定死亡代理,當Binder死亡的時候就會受到相應的通知了。