這篇文章會先對比Binder機制與Linux的通訊機制的差異,瞭解爲何Android會另起爐竈,採用Binder。接着,會根據 Binder的機制,去理解什麼是Service Manager,在C/S模型中扮演什麼角色。最後,會從一次完整的通訊活動中,去理解Binder通訊的過程。 html
雖然Android繼承使用Linux的內核,但Linux與Android的通訊機制不一樣。 linux
在Linux中使用的IPC通訊機制以下: android
傳統IPC:無名pipe, signal, trace, 有名管道 緩存
AT&T Unix 系統V:共享內存,信號燈,消息隊列 安全
BSD Unix:Socket 服務器
而在Android中,並無使用這些,取而代之的是Binder機制。Binder機制是採用OpenBinder演化而來,在Android中使用它的緣由以下: 網絡
採用C/S的通訊模式。而在linux通訊機制中,目前只有socket支持C/S的通訊模式,但socket有其劣勢,具體參看第二條。 框架
有更好的傳輸性能。對比於Linux的通訊機制, socket
socket:是一個通用接口,致使其傳輸效率低,開銷大; 性能
管道和消息隊列:由於採用存儲轉發方式,因此至少須要拷貝2次數據,效率低;
共享內存:雖然在傳輸時沒有拷貝數據,但其控制機制複雜(好比跨進程通訊時,需獲取對方進程的pid,得多種機制協同操做)。
安全性更高。Linux的IPC機制在自己的實現中,並無安全措施,得依賴上層協議來進行安全控制。而Binder機制的 UID/PID是由Binder機制自己在內核空間添加身份標識,安全性高;而且Binder能夠創建私有通道,這是linux的通訊機制所沒法實現的 (Linux訪問的接入點是開放的)。
綜上所述,Android採用Binder機制是有道理的。既然Binder機制這麼多優勢,那麼咱們接下來看看它是怎樣經過C/S模型來實現的。
在android中,有不少Service都是經過binder來通訊的,好比MediaServer旗下包含了衆多service:
AudioFlinger 音頻核心服務
AudioPolicyService:音頻策略相關的重要服務
MediaPlayerService:多媒體系統中的重要服務
CameraService:有關攝像/照相的重要服務
Binder在C/S中的流程以下:
Server註冊服務。Server做爲衆多Service的擁有者,當它想向Client提供服務時,得先去Service Manager(之後縮寫成SM)那兒註冊本身的服務。Server能夠向SM註冊一個或多個服務。
Client申請服務。Client做爲Service的使用者,當它想使用服務時,得向SM申請本身所須要的服務。Client能夠申請一個或多個服務。
當Client申請服務成功後,Client就可使用服務了。
SM一方面管理Server所提供的服務,同時又響應Client的請求併爲之分配相應的服務。扮演的角色至關於月老,兩邊牽線。這種通訊方式的好處是: 一方面,service和Client請求便於管理,另外一方面在應用程序開發時,只需爲Client創建到Server的鏈接,就可花不多時間和精力去實 現Server相應功能。那麼,Binder與這個通訊模式有什麼關係呢?!其實,3者的通訊方式就是Binder機制(例如:Server向SM註冊服 務,使用Binder通訊;Client申請請求,用的是Binder通信)
上圖便是Binder的通訊模型。咱們能夠發現:
Client和Server是存在於用戶空間
Client與Server通訊的實現,是由Binder驅動在內核空間實現
SM做爲守護進程,處理客戶端請求,管理全部服務項。
爲了方便理解,咱們能夠把SM理解成DNS服務器; 那麼Binder Driver 就至關於路由的功能。這裏就涉及到Client和Server是如何通訊的問題。下面對1.2中提到的3個流程進行說明。
首先,XXXServer(XXX表明某個)在本身的進程中向Binder驅動申請建立一個XXXService的Binder的實體,
Binder驅動爲這個XXXService建立位於內核中的Binder實體節點以及Binder的引用,注意,是將名字和新建的引用打包傳遞給SM(實體沒有傳給SM),通知SM註冊一個名叫XXX的Service。
SM收到數據包後,從中取出XXXService名字和引用,填入一張查找表中。
此時,若是有Client向SM發送申請服務XXXService的請求,那麼SM就能夠在查找表中找到該Service的Binder引用,並把Binder引用(XXXBpBinder)返回給Client。
在進一步瞭解Binder通訊機制以前,咱們先弄清幾個概念。
引用和實體。這裏,對於一個用於通訊的實體(能夠理解成具備真實空間的Object),能夠有多個該實體的引用(沒有真實空間,能夠理解成實體的 一個連接,操做引用就會操做對應連接上的實體)。若是一個進程持有某個實體,其餘進程也想操做該實體,最高效的作法是去得到該實體的引用,再去操做這個引 用。
有些資料把實體稱爲本地對象,引用成爲遠程對象。能夠這麼理解:引用是從本地進程發送給其餘進程來操做實體之用,因此有本地和遠程對象之名。
若是你足夠細心,會發現這裏有一個問題:
Sm和Server都是進程,Server向SM註冊Binder須要進程間通訊,當前實現的是進程間通訊卻又用到進程間通訊。這就比如雞生蛋、蛋生雞,但至少得先有其中之一。
巧妙的Binder解決思路:
針對Binder的通訊機制,Server端擁有的是Binder的實體;Client端擁有的是Binder的引用。
若是把SM看做Server端,讓它在Binder驅動一運行起來時就有本身的Binder實體(代碼中設置ServiceManager的Binder 其handle值恆爲0)。這個Binder實體沒有名字也不須要註冊,全部的client都認爲handle值爲0的binder引用是用來與SM通訊 的(代碼中是這麼實現的),那麼這個問題就解決了。那麼,Client和Server中這麼達成協議了(handle值爲0的引用是專門與SM通訊之用 的),還不行,還須要讓SM有handle值爲0的實體纔算大功告成。怎麼實現的呢?!當一個進程調用Binder驅動時,使用 BINDER_SET_CONTEXT_MGR命令(在驅動的binder_ioctl中)將本身註冊成SM時,Binder驅動會自動爲它建立 Binder實體。這個Binder的引用對全部的Client都爲0。
Server向SM註冊了Binder實體及其名字後,Client就能夠經過Service的名字在SM的查找表中得到該Binder的引用了 (BpBinder)。Client也利用保留的handle值爲0的引用向SM請求訪問某個Service:我申請訪問XXXService的引用。 SM就會從請求數據包中得到XXXService的名字,在查找表中找到該名字對應的條目,取出Binder的引用打包回覆給client。之 後,Client就能夠利用XXXService的引用使用XXXService的服務了。
若是有更多的Client請求該Service,系統中就會有更多的Client得到這個引用。
首先要理清一個概念:client擁有本身Binder的實體,以及Server的Binder的引用;Server擁有本身Binder的實體,以及Client的Binder的引用。咱們也能夠從接收方和發送方的方式來理解:
從client向Server發數據:Client爲發送方,擁有Binder的實體;Server爲接收方,擁有Binder的引用
從server向client發數據:Server爲發送方,擁有Binder的實體;client爲接收方,擁有Binder的引用。
也就是說,咱們在創建了C/S通路後,無需考慮誰是Client誰是Server,只要理清誰是發送方誰是接收方,就能知道Binder的實體和引用在哪邊。
創建CS通路後的流程:(當接收方得到Binder的實體,發送方得到Binder的引用後)
發送方會經過Binder實體請求發送操做。
Binder驅動會處理這個操做請求,把發送方的數據放入寫緩存(binder_write_read.write_buffer) (對於接收方爲讀緩衝區),並把read_size(接收方讀數據)置爲數據大小(對於具體的實現後面會介紹);
接收方以前一直在阻塞狀態中,當寫緩存中有數據,則會讀取數據,執行命令操做
接收方執行完後,會把返回結果一樣用binder_transaction_data結構體封裝,寫入寫緩衝區(對於發送方,爲讀緩衝區)
以前在介紹Android使用Binder機制的優勢中,提到Binder能夠創建點對點的私有通道,匿名Binder就是這種方式。在 Binder通訊中,並非全部用來通訊的Binder實體都須要註冊給SM廣而告之的,Server能夠經過已創建的實體Binder鏈接將建立的 Binder實體傳給Client。而這個Binder沒有向SM註冊名字。這樣Server與Client的通訊就有很高的隱私性和安全性。
http://www.jcodecraeer.com/a/anzhuokaifa/androidkaifa/2015/0319/2619.html