1. 程式人生 > >Binder的工作機制淺析

Binder的工作機制淺析

實體類 聲明 工作 xmanager 失敗 pri src android 底層

在Android開發中,Binder主要用於Service中,包括AIDL和Messenger,其中Messenger的底層實現就是AIDL,所以我們這裏通過AIDL來分析一下Binder的工作機制。

一、在Android Studio中建立AIDL

首先,我們需要建立一個AIDL

1.在建立了對應的實現Parcelable接口的實體類和AIDL接口後,文件結構如下:

技術分享

2.點擊clean Project/reBuild Project,出現如下錯誤:提示無法找到Book實體類。

技術分享

3.解決方案

這個問題的出現是因為我還沒有在build.gradle中對默認的sourceSets進行修改,默認情況下他指定的源碼目錄不包括aidl。

加入下面語句後同步build.gradle,再重建工程即可。

在app下的build.gradle添加:

技術分享

系統自動生成的IBookManager

技術分享

二、Binder原理分析

通過Structure

技術分享

我們可以看到這個系統生成這個接口文件包括一個靜態抽象類Stub和兩個方法getBookList()和addBook(),這兩個方法很顯然就是我們之前在IBookManager.aidl中聲明的方法,此外它還為這兩個方法用兩個int來標示,從而在onTransact()方法中起到標示作用,如下所示:

技術分享

而內部類Stub繼承自Binder,在這個類內部又有一個代理類Proxy。接下來看這一段代碼:

技術分享

這裏判斷了客戶端和服務端是否處於同一個進程中,如果處於同一個進程中,則方法調用不會走跨進程的transact方法,而如果處於不同的進程中,則需要通過其中的代理裏proxy來完成。下面展現代理類

技術分享

在這個代理類中的getBookList和addBook方法中調用transact方法來發起RPC(遠程過程調用)請求,並將當前線程掛起,然後服務端的onTransact方法響應並執行,當RPC過程返回後,當前線程繼續執行。

  從上述描述中我們可以得出Binder的大概工作方式了,但其中有兩點需要特別說明:

1.其實剛才也已經有所提及,即當客戶端發起遠程調用時會將當前線程掛起直至服務端方法執行完畢後才繼續執行,所以如果一個遠程方法比較耗時的話,是不能在UI線程中發起遠程請求的,需要我們開啟一個子線程然後再去進行遠程調用。

2.由於服務端的Binder方法是運行在Binder的線程池中的,所以我們需要以同步的方式去實現保證線程安全。

Binder的工作機制具體如下圖所示:

技術分享

三、Binder的兩個重要方法

  上面我們提到Binder運行在服務端進程,那麽如果服務端進程由於某種原因異常終止,這個時候服務端的Binder死亡,會導致我們的遠程調用失敗,並且我們還不知道Binder連接斷裂了。所以我們需要有方法來提示我們Binder已經斷裂,然後我們就可以重新綁定遠程Service。

  為此,Binder提供了兩個配對的方法linkToDeath和unlinkToDeath,通過linkToDeath我們可以給Binder設置一個死亡代理,當其死亡時我們就能知道從而重現發起連接。

  具體如下:

private IBinder.DeathRecipient deathRecipient = new IBinder.DeathRecipient(){

        @Override
        public void binderDied() {
            if(mBookManager==null)
                return;;
            mBookManager.asBinder().unlinkToDeath(mDeathRecipient,0);
            mBookManager=null;
            //TODO:這裏重現綁定遠程Service
            
        }
    };

在客戶單綁定遠程服務成功後,給binder設置死亡代理。

 mService=IMessageBoxManager.Stub.asInterface(binder);
    binder.linkToDeath(mDeathRecipient,0);

其中linkToDeath的第二個參數是個標記位,這裏我們直接設為0,。

Binder的工作機制淺析