本文主要是參考一些資料講述一些基本概念鹊汛,有基礎(chǔ)的可以直接從下一篇看起续扔。
只要有個(gè)基本的了解就可以了不必深究灯帮。
概述
簡(jiǎn)單來(lái)說(shuō),Binder是Android中使用最廣泛的IPC(進(jìn)程間通信)機(jī)制司致。Linux中本身已經(jīng)擁有了經(jīng)典的進(jìn)程間的通信方式,如信號(hào)量借帘、管道歌亲、消息隊(duì)列、貢獻(xiàn)內(nèi)存疾就、scoket等澜术。那么Android還是創(chuàng)造了新的IPC方式,主要是基于性能猬腰、穩(wěn)定性和安全性方面考慮鸟废。
-
性能
性能上的優(yōu)勢(shì)。Socket 作為一款通用接口姑荷,其傳輸效率低盒延,開(kāi)銷(xiāo)大,主要用在跨網(wǎng)絡(luò)的進(jìn)程間通信和本機(jī)上進(jìn)程間的低速通信鼠冕。消息隊(duì)列和管道采用存儲(chǔ)-轉(zhuǎn)發(fā)方式添寺,即數(shù)據(jù)先從發(fā)送方緩存區(qū)拷貝到內(nèi)核開(kāi)辟的緩存區(qū)中,然后再?gòu)膬?nèi)核緩存區(qū)拷貝到接收方緩存區(qū)懈费,至少有兩次拷貝過(guò)程计露。共享內(nèi)存雖然無(wú)需拷貝,但控制復(fù)雜,難以使用薄坏。Binder 只需要一次數(shù)據(jù)拷貝趋厉,性能上僅次于共享內(nèi)存。
IPC方式 數(shù)據(jù)拷貝次數(shù) 共享內(nèi)存 0 Binder 1 Socket/管道/消息隊(duì)列 2 -
安全性
傳統(tǒng)的 IPC 沒(méi)有任何安全措施胶坠,完全依賴(lài)上層協(xié)議來(lái)確保君账。Android 作為一個(gè)開(kāi)放性的平臺(tái),市場(chǎng)上有各類(lèi)海量的應(yīng)用供用戶(hù)選擇安裝沈善,所以Android 為每個(gè)安裝好的 APP 分配了自己的 UID乡数,故而進(jìn)程的 UID 是鑒別進(jìn)程身份的重要標(biāo)志來(lái)鑒別身份。
-
穩(wěn)定性
基于C/S架構(gòu)闻牡,客戶(hù)端有什么需求丟給服務(wù)端來(lái)處理净赴,架構(gòu)清晰、職責(zé)明確又相互獨(dú)立罩润,自然穩(wěn)定性更好玖翅。雖然貢獻(xiàn)內(nèi)存無(wú)需拷貝,但是控制復(fù)雜難以使用割以。
Linux進(jìn)程間通信
基本概念介紹
上圖展示了 Liunx 中跨進(jìn)程通信涉及到的一些基本概念:
進(jìn)程隔離
進(jìn)程與進(jìn)程間內(nèi)存是不共享的金度。兩個(gè)進(jìn)程就像兩個(gè)平行的世界,A 進(jìn)程沒(méi)法直接訪問(wèn) B 進(jìn)程的數(shù)據(jù)严沥,這就是進(jìn)程隔離的通俗解釋猜极。A 進(jìn)程和 B 進(jìn)程之間要進(jìn)行數(shù)據(jù)交互就得采用特殊的通信機(jī)制:進(jìn)程間通信(IPC)。進(jìn)程空間劃分
操作系統(tǒng)的核心是內(nèi)核消玄,獨(dú)立于普通的應(yīng)用程序跟伏,可以訪問(wèn)受保護(hù)的內(nèi)存空間,也可以訪問(wèn)底層硬件設(shè)備的權(quán)限翩瓜。為了保護(hù)用戶(hù)進(jìn)程不能直接操作內(nèi)核受扳,保證內(nèi)核的安全,操作系統(tǒng)從邏輯上將虛擬空間劃分為用戶(hù)空間(User Space)和內(nèi)核空間(Kernel Space)奥溺。-
系統(tǒng)調(diào)用
從邏輯上進(jìn)行了用戶(hù)空間和內(nèi)核空間的劃分辞色,但不可避免的用戶(hù)空間需要訪問(wèn)內(nèi)核資源,比如文件操作浮定、訪問(wèn)網(wǎng)絡(luò)等等相满。就需要借助系統(tǒng)調(diào)用來(lái)實(shí)現(xiàn),這樣保證了所有的資源訪問(wèn)都是在內(nèi)核的控制下進(jìn)行的桦卒,避免了用戶(hù)程序?qū)ο到y(tǒng)資源的越權(quán)訪問(wèn)立美,提升了系統(tǒng)安全性和穩(wěn)定性。
Linux 下的傳統(tǒng) IPC 通信原理
消息發(fā)送方將要發(fā)送的數(shù)據(jù)存放在內(nèi)存緩存區(qū)中方灾,通過(guò)系統(tǒng)調(diào)用進(jìn)入內(nèi)核態(tài)建蹄。然后內(nèi)核程序在內(nèi)核空間分配內(nèi)存碌更,開(kāi)辟一塊內(nèi)核緩存區(qū),調(diào)用 copy_from_user()
函數(shù)將數(shù)據(jù)從用戶(hù)空間的內(nèi)存緩存區(qū)拷貝到內(nèi)核空間的內(nèi)核緩存區(qū)中洞慎。
同樣的痛单,接收方進(jìn)程在接收數(shù)據(jù)時(shí)在自己的用戶(hù)空間開(kāi)辟一塊內(nèi)存緩存區(qū),然后內(nèi)核程序調(diào)用copy_to_user()
函數(shù)將數(shù)據(jù)從內(nèi)核緩存區(qū)拷貝到接收進(jìn)程的內(nèi)存緩存區(qū)劲腿。
傳統(tǒng)的 IPC 通信方式有兩個(gè)問(wèn)題:
- 性能低下旭绒,一次數(shù)據(jù)傳遞需要經(jīng)歷:內(nèi)存緩存區(qū) --> 內(nèi)核緩存區(qū) --> 內(nèi)存緩存區(qū),需要 2 次數(shù)據(jù)拷貝
- 接收數(shù)據(jù)的緩存區(qū)由數(shù)據(jù)接收進(jìn)程提供焦人,但是接收進(jìn)程并不知道需要多大的空間來(lái)存放將要傳遞過(guò)來(lái)的數(shù)據(jù)挥吵,因此只能開(kāi)辟盡可能大的內(nèi)存空間或者先調(diào)用 API 接收消息頭來(lái)獲取消息體的大小,這兩種做法不是浪費(fèi)空間就是浪費(fèi)時(shí)間花椭。
Binder 跨進(jìn)程通信原理
從上面看出傳統(tǒng)的跨進(jìn)程通信是需要內(nèi)核空間做支持的忽匈,但是Binder并不是Linux 系統(tǒng)內(nèi)核的一部分,這樣怎么辦呢矿辽? Linux 有動(dòng)態(tài)內(nèi)核可加載模塊(Loadable Kernel Module丹允,LKM)的機(jī)制,模塊是具有獨(dú)立功能的程序嗦锐,它可以被單獨(dú)編譯嫌松,但是不能獨(dú)立運(yùn)行沪曙。它在運(yùn)行時(shí)被鏈接到內(nèi)核作為內(nèi)核的一部分運(yùn)行奕污。這樣,Android 系統(tǒng)就可以通過(guò)動(dòng)態(tài)添加一個(gè)內(nèi)核模塊運(yùn)行在內(nèi)核空間液走,用戶(hù)進(jìn)程之間通過(guò)這個(gè)內(nèi)核模塊作為橋梁來(lái)實(shí)現(xiàn)通信碳默。
在 Android 系統(tǒng)中,這個(gè)運(yùn)行在內(nèi)核空間缘眶,負(fù)責(zé)各個(gè)用戶(hù)進(jìn)程通過(guò) Binder 實(shí)現(xiàn)通信的內(nèi)核模塊就叫 Binder 驅(qū)動(dòng)(Binder Dirver)嘱根。
Binder IPC 方式主要是通過(guò)內(nèi)存映射mmap(
) 來(lái)實(shí)現(xiàn),mmap()
是操作系統(tǒng)中一種內(nèi)存映射的方法巷懈。內(nèi)存映射簡(jiǎn)單的講就是將用戶(hù)空間的一塊內(nèi)存區(qū)域映射到內(nèi)核空間该抒。
內(nèi)存映射能減少數(shù)據(jù)拷貝次數(shù),實(shí)現(xiàn)用戶(hù)空間和內(nèi)核空間的高效互動(dòng)顶燕。兩個(gè)空間各自的修改能直接反映在映射的內(nèi)存區(qū)域凑保,從而被對(duì)方空間及時(shí)感知。也正因?yàn)槿绱擞抗ィ瑑?nèi)存映射能夠提供對(duì)進(jìn)程間通信的支持欧引。
一次完整的Binder IPC過(guò)程:
- 首先 Binder 驅(qū)動(dòng)在內(nèi)核空間創(chuàng)建一個(gè)數(shù)據(jù)接收緩存區(qū);
- 接著在內(nèi)核空間開(kāi)辟一塊內(nèi)核緩存區(qū)恳谎,建立內(nèi)核緩存區(qū)和內(nèi)核中數(shù)據(jù)接收緩存區(qū)之間的映射關(guān)系芝此,以及內(nèi)核中數(shù)據(jù)接收緩存區(qū)和接收進(jìn)程用戶(hù)空間地址的映射關(guān)系憋肖;
- 發(fā)送方進(jìn)程通過(guò)系統(tǒng)調(diào)用 copy_from_user() 將數(shù)據(jù) copy 到內(nèi)核中的內(nèi)核緩存區(qū),由于內(nèi)核緩存區(qū)和接收進(jìn)程的用戶(hù)空間存在內(nèi)存映射婚苹,因此也就相當(dāng)于把數(shù)據(jù)發(fā)送到了接收進(jìn)程的用戶(hù)空間岸更,這樣便完成了一次進(jìn)程間的通信。
Binder 通信模型
Binder通信采用C/S架構(gòu)膊升,從組件視角來(lái)說(shuō)坐慰,包含Client、Server用僧、ServiceManager以及Binder驅(qū)動(dòng)结胀,其中ServiceManager用于管理系統(tǒng)中的各種服務(wù)。其中 Client责循、Server糟港、Service Manager 運(yùn)行在用戶(hù)空間(存疑),Binder 驅(qū)動(dòng)運(yùn)行在內(nèi)核空間院仿。
統(tǒng)觀Binder中的各個(gè)組成元素秸抚,發(fā)現(xiàn)它和TCP/IP網(wǎng)絡(luò)又很多相同之處。
- Binder驅(qū)動(dòng)——路由器歹垫;
- Service Manager ——DNS;
- Binder Client ——客戶(hù)端剥汤;
- Binder Server —— 服務(wù)端;
TCP/IP一個(gè)典型的連接過(guò)程
client和server建立連接通常有以下幾個(gè)步驟:
-
Client向DNS查詢(xún)Google.com的IP地址排惨。
首先Client要知道DNS的IP地址才可以吭敢,這個(gè)是在Client接入網(wǎng)絡(luò)之前就完成的。
如果Client已經(jīng)知道了Server的IP自然可以跳過(guò)這一個(gè)步驟直接與Server連接暮芭。比如windows下提供了一個(gè)hosts文件用于查詢(xún)常用域名與IP的對(duì)應(yīng)關(guān)系鹿驼。
DNS將查詢(xún)到的結(jié)果返回給Client。
Client得知Googlde.com的IP后辕宏,向Google服務(wù)器發(fā)起連接畜晰。
在這一系列流程中沒(méi)有談到Router,因?yàn)樗淖饔镁褪菍?shù)據(jù)包投遞給目標(biāo)IP瑞筐。
在以上整個(gè)TCP/IP的模型中凄鼻,IP地址是彼此間溝通的唯一憑證。其次Router是構(gòu)建一個(gè)通信網(wǎng)絡(luò)的基礎(chǔ)聚假,它根據(jù)用戶(hù)的目標(biāo)IP來(lái)把數(shù)據(jù)包正確的送達(dá)块蚌。最后DNS不是必須的。
類(lèi)比下 Binder的流程:
進(jìn)程1(客戶(hù)端)想要和進(jìn)程2(服務(wù)端)進(jìn)行訪問(wèn)魔策,因?yàn)樗麄冎g是 跨進(jìn)程的(跨網(wǎng)絡(luò))所以需要Binder驅(qū)動(dòng)(Router)來(lái)把請(qǐng)求正確的投遞到對(duì)方所在的進(jìn)程(服務(wù)端)中匈子,而參與通信的進(jìn)程都需要持有Binder"頒發(fā)"的唯一標(biāo)志(IP地址)。同樣的Binder中的ServiceManager(DNS)也不是必須的闯袒,前提是Client能記住進(jìn)程的Binder標(biāo)志(IP地址)虎敦。特別注意的是這個(gè)Binder標(biāo)志是”動(dòng)態(tài)IP“游岳,意味這每次訪問(wèn)都需要重新獲取,而DNS可以完美的解決這個(gè)問(wèn)題其徙,用于管理Binder標(biāo)志和域名之間的對(duì)應(yīng)關(guān)系胚迫。
DNS有自己的IP地址,那么ServiceManager在Binder的通信過(guò)程的唯一標(biāo)志永遠(yuǎn)是0唾那。