《Android核心剖析》讀書筆記 第5章 處理序間通訊核心架構Binder

來源:互聯網
上載者:User

Binder:英文的意思是別針、回形針。我們經常用別針把兩張紙“別”在一起,在android系統中,Binder是用來完成處理序間通訊IPC的基礎架構,即把不同進程“別”在一起,便於各個進程之間可以相互傳遞訊息;如果做過Java服務端開發的話,你也可以理解成一種RPC調用,即在本地直接調用其他進程中的功能;理解該機制將有助於更好的掌握後面的android整體架構設計,因為核心模組之間的通訊都是通過Binder來完成的,這也是為什麼作者將這部分內容放在核心篇的第一章的原因;

Binder架構由三部分組成,分別為服務端、Binder驅動、用戶端,詳見:

  1. 服務端:即服務提供者,比如android就提供了很多的系統服務,比如Alarm、WIFI、INPUT、LAYOUT_INFLATER、ACTIVITY等;當然開發人員也可以實現自己的服務,然後把服務開放給其他應用使用,在代碼上服務介面必須繼承IInterface,服務具體實作類別必須繼承 Binder;
  2. Binder驅動:實際上他是一個遵從Linux裝置驅動模型的虛擬驅動,裝置節點為/dev/binder;他主要用來實現用戶端和服務端請求的中轉,其相關源碼位於./frameworks/native/libs/binder/目錄;

    具體驅動的開啟、監聽是通過守護進程servicemanager完成,在./init.rc中定義,相關源碼位於./frameworks/base/cmds/servicemanager/;

  3. 用戶端:即服務消費者,要想調用其他進程中的功能,必須在本地有一個對遠程對象的引用,且用戶端和服務端必須遵從相同的介面和資料交換協議;而這兩點就是實現IPC通訊需要解決的最核心的兩個問題;

為了簡化服務提供者和消費者之間的開發和溝通成本,android系統提供了AIDL(Android Interface Definition Language)的工具支援,該工具可以把一個用於介面聲明的aidl檔案轉換成一個Java檔案,轉換的過程就是要讓該服務在代碼層面自動符合Binder架構的設計規範,並自動解決好上面提到的2個核心問題中的第二點,產生好的Java檔案其實包括了3個類:

服務介面類IXXX extends android.os.IInterface;

本地存根類IXXX.Stub  extends android.os.Binderimplements IXXX;

遠程代理類 IXXX.Stub.Proxyimplements IXXX;

經曆過EJB時代的同學們一定對上面的代碼形式相當熟悉吧,哈哈!

以上檔案產生好之後,服務提供者就可以專註於寫具體的邏輯代碼了,直接extends IXXX.Stub 實現具體的方法即可;

那是否可以不用aidl工具來產生代碼呢?當然可以,如果你願意的話完全可以自己來寫相關的代碼,只要符合Binder代碼規範即可;

服務提供者使用的本地存根類IXXX.Stub中的核心方法

  1. public final boolean transact(int code, Parcel data, Parcel reply, int flags);
    實際上是父類Binder中的方法,因為是final的,所以子類是不能重載的,這也是Binder架構設計的一部分,因為他不允許開發人員隨意改變調用機制,該方法用於接受服務調用請求,但他自己並不直接處理這些請求,而是轉交給onTransact方法(可由子類重載)來處理,這是android系統中非常重要的一種設計思想,被廣泛用於各種情境,以後你看見onXXXX相關的方法一般都是相關的功能回調或子類重載點;
  2. protected boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply,int flags);

    根據參數code判斷該執行IXXX介面中的哪個具體業務方法,並且從data中按序取出資料作為具體業務方法的輸入參數;
    注意:從Parcel取出資料的順序必須和存入資料(具體間後面IXXX.Stub.Proxy中業務方法的描述)的順序一致,否則資料就亂套了,而這就是AIDL工具自動產生代碼要解決的核心問題;
  3. public static IXXX asInterface(android.os.IBinder obj);
    將遠程對象的引用轉換成具體的業務介面,這裡自動屏蔽了本地和遠程調用的細節,因為服務提供者不僅可以被其他進程調用,還可以被自身進程內其他功能塊調用;

服務消費者使用的遠程代理類 IXXX.Stub.Proxy中的核心方法

  1. Proxy(android.os.IBinder remote);
    建構函式,參數就是遠程服務的引用,所有的業務方法的調用都是通過該引用間接執行的;
  2. xyz(…) 各種具體的業務方法;
    這裡對服務介面的實現並不是真的商務邏輯實現,他是遠程服務在使用方本地的代理,用來中轉調用的,主要是完成輸入參數到包裹Parcel的轉換,因為IPC遠程調用對訊息的傳遞必須基於包裹Parcel,這是Binder架構設計規範的一部分;
    當輸入參數轉換完成後調用 mRemote.transact(…)將請求發送給服務提供者;

服務消費者如何擷取遠程對象的引用?

  1. 對於系統服務(系統啟動時在SystemServer進程中自動載入),android提供了統一的擷取介面,使用了原廠模式,可以通過ServiceManager.getService(.)得到遠程對象的引用IBinder,然後通過IXXX.Stub.asInterface(.)方法即可得到對具體服務介面IXXX的引用;
    注意:我們一般不會直接使用到服務介面IXXX,而是會用到對應的Manager類(可以理解為遠程服務物件的經紀人),這也是android系統的一種常見設計規範;這種設計的作用是屏蔽對遠程服務的直接存取,從而給應用程式提供靈活可控的API介面;
    也不會直接使用到ServiceManager,而是直接通過context.getSystemService(.)擷取到具體服務對應的Manager類;
    關於具體服務Service和Manager之間的關係可以參見:

  2. 對於非系統服務,可以通過執行context.startService(.)來啟動,執行bindService(Intent service, ServiceConnection conn, int flags)來擷取服務的遠程對象引用,具體是在ServiceConnection.onServiceConnected(ComponentName
    name, IBinder service);這個回呼函數中獲得;可參見:

以上內容若有轉載,請註明出處,歡迎訪問老唐的專欄http://blog.csdn.net/sfdev

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.