「每日一面」Binder機制你瞭解嗎?

對象中 // 2. 之後,Binder對象 可根據descriptor通過queryLocalIInterface()獲得對應IInterface對象(即plus)的引用,可依靠該引用完成對請求方法的調用IInterface queryLocalInterface(Stringdescriptor) ;// 作用:根據 參數 descriptor 查找相應的IInterface對象(即plus引用)boolean onTransact(int code, Parcel data, Parcel reply, int flags);// 定義:繼承自IBinder接口的 // 作用:執行Client進程所請求的目標方法(子類需要複寫) // 參數說明: // code:Client進程請求方法標識符。即Server進程根據該標識確定所請求的目標方法 // data:目標方法的參數。(Client進程傳進來的,此處就是整數a和b) // reply:目標方法執行後的結果(返回給Client進程) // 注:運行在Server進程的Binder線程池中;當Client進程發起遠程請求時,遠程請求會要求系統底層執行回調該方法final class BinderProxy implements IBinder {// 即Server進程創建的Binder對象的代理對象類 // 該類屬於Binder的內部類}// 回到分析1原處}public interface IPlus extends IInterface {// 繼承自IInterface接口->>分析4 // 定義需要實現的接口方法,即Client進程需要調用的方法public int add(int a,int b);// 返回步驟2}// 進程間通信定義的通用接口// 通過定義接口,然後再服務端實現接口、客戶端調用接口,就可實現跨進程通信。public interface IInterface{// 只有一個方法:返回當前接口關聯的 Binder 對象。public IBinder asBinder();}

步驟2:Server進程根據Client進要求 調用 目標方法(即加法函數)

import android.os.Binder;import android.os.Parcel;// 1. 收到Binder驅動通知後,Server 進程通過回調Binder對象onTransact()進行數據解包 & 調用目標方法public class Stub extends Binder {// 複寫onTransact()@Overrideboolean onTransact(int code, Parcel data, Parcel reply, int flags){// code即在transact()中約定的目標方法的標識符switch (code) {case Stub.add: {// a. 解包Parcel中的數據data.enforceInterface("add two int");// a1. 解析目標方法對象的標識符int arg0 = data.readInt();int arg1 = data.readInt();// a2. 獲得目標方法的參數 // b. 根據"add two int"通過queryLocalIInterface()獲取相應的IInterface對象(即Server創建的plus)的引用,通過該對象引用調用方法int result = this.queryLocalIInterface("add two int") .add( arg0, arg1);// c. 將計算結果寫入到replyreply.writeInt(result);return true;}}return super.onTransact(code, data, reply, flags);// 2. 將結算結果返回 到Binder驅動

步驟3:Server進程 將目標方法的結果(即加法後的結果)返回給Client進程

// 1. Binder驅動根據 代理對象 沿原路 將結果返回 並通知Client進程獲取返回結果

// 2. 通過代理對象 接收結果(之前被掛起的線程被喚醒)

binderproxy.transact(Stub.ADD, data, reply, 0);

reply.readException();;

result = reply.readInt();

}

}

  • 總結

    下面,我用一個原理圖 & 流程圖來總結步驟3的內容

「每日一面」Binder機制你瞭解嗎?

「每日一面」Binder機制你瞭解嗎?

Binder的線程管理

每個Binder的Server進程會創建很多線程來處理Binder請求,可以簡單的理解為創建了一個Binder的線程池吧(雖然實際上並不完全是這樣簡單的線程管理方式),而真正管理這些線程並不是由這個Server端來管理的,而是由Binder驅動進行管理的。

一個進程的Binder線程數默認最大是16,超過的請求會被阻塞等待空閒的Binder線程。理解這一點的話,你做進程間通信時處理併發問題就會有一個底,比如使用ContentProvider時(又一個使用Binder機制的組件),你就很清楚它的CRUD(創建、檢索、更新和刪除)方法只能同時有16個線程在跑。

Binder對應用開發者的用處

上面提到的線程數是一個對應用開發有用的地方,很多人之前由於不瞭解有這個線程數的限制可能會在這裡遇到過麻煩。

當然,最重要的是你瞭解了Android的進程間通信機制,知道Android的組件間是如何實現進程間通信和數據共享的,當你的應用要處理進程間通信時,你知道可能要關注哪個方面。如你的Activity組件可以設置在不同的進程中運行,那麼每個進程都是獨立的,它要使用別的進程的數據時,你就會知道用靜態變量去交互沒有意義。而且,理解了原理,再去編寫AIDL的代碼就沒有那麼難理解了。

對於一些Framework層的開發者,如自已定製ROM的團隊,需要提供自己的系統服務時,Binder機制肯定是必需要了解的,不然無從下手。

小結

多進程問題不是每個開發都會遇到的,很多應用只要在自己的進程內完成業務需求就可以了,但知道多進程的存在,並理解Android提供的Binder機制,那麼我們在選擇如何做進程間的互交時就會更明確可能存在的問題和Android的解決方案。

「每日一面」Binder機制你瞭解嗎?


分享到:


相關文章: