Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> Android開發 >> 關於android開發 >> Android Binder機制介紹,androidbinder機制

Android Binder機制介紹,androidbinder機制

編輯:關於android開發

Android Binder機制介紹,androidbinder機制


做過Android開發的同學可能有些體會,入門初期,工作內容主要是實現各式各樣的UI界面,以及實現應用的業務邏輯。在這個階段,我們會逐漸熟悉View系統,逐漸學會實現各種各樣的界面以及動畫效果。再往後,當我們想更深入的學習android系統,比如學習android四大組件的啟動過程、AMS、PMS等等時,都會遇到一個叫做Binder的東西。結合筆者的經驗,Binder可以說是深入理解Android系統的重要基礎。binder作為android系統進程間通信的機制,貫穿在方方面面。我們平時使用最多的startActivity、startService都是通過binder機制與AMS所在進程進行通信。本文主要對Binder機制的體系結構作簡要介紹,相信讀者看完後,會對binder有一個總體上的理解與把握。

 

注:筆者初學binder時,曾經看過一些binder介紹的文章,並且過早的糾結於一些文章中的binder代碼細節,感覺非常吃力。本文僅從宏觀上對binder機制進行介紹。相信讀者先理解了binder的總體結構後,再去深入細節,學習效果會更好。

 

Binder是什麼、能做什麼?

Binder是android系統裡面的進程間通信機制。androd系統中,不同的app運行在不同的進程中,同一個app的不同組件也可能運行在不同的進程中(androidManifest文件中android:process)。當一個進程想為其它進程提供服務時,就需要通過進程間通信的方式來提供服務。打個比方:我們有一個APP1,裡面有個service組件可以提供計算器的服務。當另外一個APP2也想使用APP1裡面的service的計算器的服務時,由於不同的APP運行在不同的進程中,所以,APP2是無法直接使用APP1裡面的service。由於跨越了進程,只能通過進程間通信機制來完成。

再說的形象點,APP1所在進程有一個對象object1,其中有一個方法method1。 APP2所在的另外一個進程,想使用object1的method1方法。binder可能幫助我們在APP2所在進程拿到一個object1對象的引用,使我們能夠像調用本地對象一樣,通過object1.method1()直接調用。利用binder,我們可以突破進程的限制,將對象傳給其它進程,讓其它進程方便調用對象的方法。

 

為什麼用Binder?

理解了binder是什麼、能做什麼後,大家可能會有疑問:android系統基於Linux,linux本身具有很多的進程間通信方式可供選擇,為什麼android不使用linux自帶的一個進程間通信方式,而新創造了一個binder?是重復造輪子嗎?

Linux自帶的進程間通信方式有:文件、signal、socket、Pipe、共享內存...,  為什麼使用Binder?筆者總結原因有兩大方面:

1 歷史原因。Binder最早並不是為Android系統而設計的,最開始有一個OpenBinder的東西,用在一個叫做Palm Cobaltw的為內核操作系統上。後來,Palm Cobaltw移植到了Linux系統上,OpenBinder也跟著移植了過來。Google在組建Android開發團隊的時候,聘請了一位叫做Dianne Hackborn的工程師,而他就是OpenBinder的核心人員。後面在做android進程間通信時,發現binder很合適,就理所當然的在android系統上使用了Binder。

2 binder自身的一些特點和優勢。Binder實現進程間通信時,在安全性和效率方面,都很合適用在android系統中。關於這點,先有個印象即可。

 

Binder有哪些組成部分?

一個Binder系統由四部分組成:Binder客戶端、Binder服務端、Binder驅動、服務登記查詢模塊

Binder客戶端:想要使用服務的進程

Binder服務端:實際提供服務的進程

Binder驅動:我們在客戶端先通過Binder拿到一個服務端進程中的一個對象的引用,通過這個引用,直接調用對象的方法獲取結果。在這個引用對象執行方法時,它是先將方法調用的請求傳給binder驅動;然後binder驅動再將請求傳給服務端進程;服務端進程收到請求後,調用服務端“真正”的對象來執行所調用的方法;得出結果後,將結果發給binder驅動;binder驅動再將結果發給我們的客戶端;最終,我們在客戶端進程的調用就有了返回值。Binder驅動,相當於一個中轉者的角色。通過這個中轉者的幫忙,我們就可以調用其它進程中的對象。

服務登記查詢模塊:我們調用其它進程裡面的對象時,首先要獲取這個對象。這個對象其實代表了另外一個進程能給我們提供什麼樣的服務(再直接一點,就是:對象中有哪些方法可以讓客戶端進程調用)。首先服務端進程要在某個地方注冊登記一下,告訴系統我有個對象可以公開給其它進程來提供服務。當客戶端進程需要這個服務時,就去這個登記的地方通過查詢來找到這個對象。

 

Binder各部分是如何工作的?

下面從客戶端進程的角度來看看binder的工作機制

作為客戶端進程,僅僅是想使用服務端進程提供的服務而已:   但是由於進程的隔離性,Client所在的ProcessA是不能讀寫Service所在的ProcessB中的內容,但系統內核可以,而Binder驅動就是運行在內核態。Binder驅動幫我們中轉請求即可:   有了Binder驅動後,對於Client端和Service端,需要額外專門與Binder驅動打交道,為了幫Client和Service端屏蔽掉與Binder驅動打交道這件很low的工作,我們可以分別為Client和Service設計一個代理,讓他們只與代理打交道即可,將與Binder驅動打交道的任務放在代理裡面: 讀者可能要問,如果要自己實現Client端和Service端,通過上面的方式,雖然邏輯上獨立出來了兩個代理(客戶端代理的Proxy、服務端的代理Stub),這兩個代理還不是要自己實現?如果還是要自己實現,那分出來又有實際的意義? AndroidSDK為我們提供了一個AIDL工具。我們只要新建一個AIDL文件,像創建普通interface一樣(略有不同)在裡面定義接口方法。定義好之後,androidSDK會根據aidl裡面的接口定義,自動為我們生成一個java文件,其中就包括客戶端代理Proxy和服務端代理Stub,並且自動生成了與Binder驅動通信的代碼,是不是很爽。上面的圖片中,之所以將客戶端代理叫做Proxy,服務端代理叫做Stub,就是因為aidl自動生成的代理中,兩個代理的類名就是Proxy和Stub。我們在做的實際工作就只有真正的服務功能邏輯了。   再更近一步的想想,對於客戶端而言,更理想的狀態是,客戶端完全不用知道調用的對象是一個本地對象,還是一個服務端進程中的對象。按照上面的圖片,客戶端顯然知道自己調用的是遠程對象,所以通過一個Proxy來調。我們在開發android應用程序的過程中,都會用到一些系統提供的XXXManager(ActivityManager、PackageManager、WifiManager、PowerManager等等),而這些manager所要實現的目的之一,正是幫Client屏蔽掉Binder的實現細節。有了這些Manager,Client在使用時,首先通過getServiceManager(xxx)獲取一個manager對象,後面就直接調用manager中封裝好的服務方法即可。這樣以來,manager內部實際上還是通過客戶端代理,通過binder驅動來跟運行在另外一個進程中的xxxService來通信,但對於Client來說,完全不用知道。如下圖: 對於一些系統服務,ActivityManager、PackagerManager等等,不光為Client屏幕了Binder相關細節,還可以對真正的服務端對象提供的服務API進行過濾和控制,可以只為Client暴露一個服務API的子集。   最後一個疑問:到上面的圖片所講的內容為止,前提條件是Client先獲取到了一個Proxy或者Manager,然後才完成後面的進程間通信。那到底Client是如何獲取到Manager或者Proxy呢? 首先以一些系統服務為例: 前面提到,Binder機制的四個組成部分中,有一個是“服務登記查詢模塊”,對應上圖中的Context Manager,在Android系統中運行時的進程名為:servicemanager。在所有服務進程中,servicemanager第一個啟動,原因也不難理解,如果其它服務進程先於servicemanager啟動,到哪裡去注冊?   如上圖所示,假設Service所在的進程ProcessB在servicemanager進程啟動後啟動,ProcessB需要向servicemanager注冊。“注冊”這個動作,本質也是要跨進程通信,從ProcessB到servicemanager,這時,Service成為了本次跨進程通信的客戶端,ContextManager成為了服務端。客戶端到服務端的通信,按前面講到的內容,需要一個Proxy或者Manager。這個Proxy或者Manager從哪裡獲取呢?問題好像陷入了循環死鎖?因為ContextManager的特殊地位,讀者可以理解為系統對它有點特殊待遇,Service可以從一個全局固定的地方直接去拿Proxy或者Manager,而不用像Client那樣通過查詢來獲取Proxy/Manager。拿到了客戶端代理,具體注冊的通信過程如上文所講,不再重復。到這裡為止,Service就成功注冊到了ContextManager中。   客戶端Client初始化Manager時,manager也像剛才的Service,直接從某個固定的地方拿到ContextManager的代理,通過代理,去查詢ContextManager,獲取一個“提供所要服務的代理對象”。manager有了這個對象,Client就可以通過manager來使用服務了,調用邏輯如圖:   當自己來實現Client和Service時,Client如何獲取Proxy代理對象? 先講一下實現方式:一般我們會在App中通過Service組件的方式來創建一個服務。其它App通過BindService的方式連接到Service,通過onServiceConnected回調就能獲取Proxy代理對象。具體實現可參考:http://blog.csdn.net/singwhatiwanna/article/details/17041691  

總結

本文簡要介紹了Binder跨進程通信機制的邏輯,希望能幫助初學Binder的同學快速入門,提交學習效率。文中使用的圖片以及講解思路,來自於這個文檔:

http://events.linuxfoundation.org/images/stories/slides/abs2013_gargentas.pdf,加進去一些筆者自己的思考和總結。一些地方如果有錯誤,歡迎指正交流。

另外推薦一篇binder入門的文章:http://weishu.me/2016/01/12/binder-index-for-newer/

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved