在從Android 6.0源碼的角度剖析Activity的啟動(dòng)過程一文(https://blog.csdn.net/AndrExpert/article/details/81488503)中,我們了解到Activity的啟動(dòng)過程最終由系統(tǒng)服務(wù)ActivityManagerService完成,ActivityManagerServer是繼承于Binder且運(yùn)行在系統(tǒng)進(jìn)程中,Activity的啟動(dòng)實(shí)質(zhì)是一次基于Binder機(jī)制的跨進(jìn)程通信。除此之外,Android系統(tǒng)還為應(yīng)用程序提供了各種系統(tǒng)服務(wù),比如多媒體播放、音視頻獲取、讀取傳感器數(shù)據(jù)等,它們之間的交互都是由Binder機(jī)制實(shí)現(xiàn)的。那么,所謂的Binder究竟是什么?實(shí)際上,Binder并不是一個(gè)確切的概念,它在不同的層次表述大不相同,比如通常意義下,Binder指Android系統(tǒng)中特有的一種跨進(jìn)程通信方式;從用戶空間的角度來說,對(duì)于Server進(jìn)程,Binder指Binder本地對(duì)象,而對(duì)于Client進(jìn)程,Binder指Binder代理對(duì)象;從內(nèi)核空間的角度來說,Binder指Binder驅(qū)動(dòng);從傳輸通信的角度來說,Binder是可以跨進(jìn)程傳遞的對(duì)象。
作者 | 蔣東國
責(zé)編 | 屠敏
出品 | CSDN博客
Binder基本原理
IPC與Binder簡介
進(jìn)程是程序的實(shí)體,它是程序的一次運(yùn)行活動(dòng),同時(shí)也是操作系統(tǒng)資源分配和調(diào)度的基本單位。在操作系統(tǒng)中運(yùn)行著許許多多的進(jìn)程,為了保證系統(tǒng)的有序運(yùn)行和進(jìn)程間互不干擾,操作系統(tǒng)引入了進(jìn)程隔離的概念來確保不同進(jìn)程之間相互獨(dú)立。進(jìn)程隔離使用了虛擬地址空間技術(shù),該技術(shù)通過為不同的進(jìn)程分配不同的虛擬地址,使得對(duì)于每個(gè)進(jìn)程來說都以為自己獨(dú)享了整個(gè)系統(tǒng),完全不知道其他進(jìn)程的存在,這樣就避免了進(jìn)程間錯(cuò)誤的相互寫入數(shù)據(jù)而導(dǎo)致進(jìn)程無法正常運(yùn)行。然而,雖然進(jìn)程隔離能夠確保每個(gè)進(jìn)程的數(shù)據(jù)安全,不被惡意破壞,但畢竟操作系統(tǒng)是一個(gè)有機(jī)的的統(tǒng)一整體,就像人體樣,雖然人體的各個(gè)器官也是相互獨(dú)立,但是若要完成某一個(gè)行為,就需要在大腦的控制下對(duì)相關(guān)器官進(jìn)行調(diào)配,同時(shí)器官之間也會(huì)相互傳遞信號(hào),操作系統(tǒng)亦是如此。操作系統(tǒng)是管理計(jì)算機(jī)硬件與軟件資源的計(jì)算機(jī)程序,它由內(nèi)核、驅(qū)動(dòng)程序、接口庫及外圍組成,其中,內(nèi)核是操作系統(tǒng)的核心,擁有訪問受保護(hù)的內(nèi)存空間和訪問底層硬件設(shè)備的所有權(quán)限。當(dāng)操作系統(tǒng)需要執(zhí)行某個(gè)任務(wù)時(shí),必然需要系統(tǒng)中相關(guān)進(jìn)程在內(nèi)核的控制下進(jìn)行協(xié)作,既然是相互協(xié)作,就必然牽涉到進(jìn)程間的數(shù)據(jù)交互,為了實(shí)現(xiàn)這個(gè)目的,跨進(jìn)程通信技術(shù)開始"閃亮登場"。
IPC,跨進(jìn)程通信
跨進(jìn)程通信(IPC,Interprocess Communication)是一組編程接口,它允許在一個(gè)操作系統(tǒng)中不同進(jìn)程之間傳遞或交換信息,其存儲(chǔ)-轉(zhuǎn)發(fā)方式通信過程大致為:假設(shè)有兩個(gè)運(yùn)行在用戶空間的進(jìn)程A、B,進(jìn)程A要給進(jìn)程B發(fā)送數(shù)據(jù),那么進(jìn)程A會(huì)通過系統(tǒng)調(diào)用copy_from_user將數(shù)據(jù)copy到內(nèi)核空間,然后把內(nèi)核空間通過系統(tǒng)調(diào)用copy_to_user將對(duì)應(yīng)的數(shù)據(jù)copy到進(jìn)程B即完成。下圖為IPC通信模型:
用戶空間和內(nèi)核空間是人們從邏輯上抽離出來的概念,旨在區(qū)分操作系統(tǒng)中普通的應(yīng)用程序和內(nèi)核。內(nèi)核是操作系統(tǒng)的核心,它擁有訪問受保護(hù)內(nèi)存空間和底層硬件設(shè)備的所有權(quán)限,維持著整個(gè)操作系統(tǒng)的正常運(yùn)行。為了保護(hù)內(nèi)核不受破壞,普通的應(yīng)用程序被授予有限的資源訪問權(quán)限,如果普通的應(yīng)用程序需要訪問受限的資源,就需要通過系統(tǒng)調(diào)用通過內(nèi)核來訪問這些被保護(hù)的資源。用戶空間訪問內(nèi)核空間通過系統(tǒng)調(diào)用實(shí)現(xiàn),用戶空間訪問用戶空間則需要通過內(nèi)核模塊/驅(qū)動(dòng)來實(shí)現(xiàn)。
Android系統(tǒng)是基于Linux內(nèi)核實(shí)現(xiàn)的,自然支持Linux系統(tǒng)中的IPC方式,這些方式包括管道、System V IPC(包括消息隊(duì)列/共享內(nèi)存/信號(hào)燈)和socket。其中,管道是一種半雙工的通信方式,數(shù)據(jù)只能單向流通且只能在具有父子進(jìn)程關(guān)系的進(jìn)程間使用;System V IPC是Linux系統(tǒng)為了彌補(bǔ)管道在進(jìn)程間通信的不足所引入,它包括消息隊(duì)列、信號(hào)燈和共享內(nèi)存三種進(jìn)程間通信機(jī)制,它們共享通用的認(rèn)證方式,即進(jìn)程在使用某種類型的IPC資源以前,必須通過系統(tǒng)調(diào)用傳遞一個(gè)唯一的引用標(biāo)識(shí)符到內(nèi)核來訪問這些資源;Socket套接字是一種通用的接口,用于跨網(wǎng)絡(luò)的進(jìn)程間通信和本機(jī)上進(jìn)程間的低速通信,并且支持Client-Server的通信方式。
下表為上述5種IPC方式區(qū)別:
(1) C/S結(jié)構(gòu):Client-Server結(jié)構(gòu)是一種網(wǎng)絡(luò)架構(gòu),它把客戶端與服務(wù)器區(qū)分開來。客戶端發(fā)送請(qǐng)求到服務(wù)器,服務(wù)器接收并處理請(qǐng)求,然后返回結(jié)果給客戶端。在Android系統(tǒng)中,大部分系統(tǒng)服務(wù)都是通過這種架構(gòu)為應(yīng)用程序提供服務(wù),從而讓應(yīng)用程序擁有豐富的功能。
(2) 存儲(chǔ)-轉(zhuǎn)發(fā)方式:數(shù)據(jù)先從發(fā)送方緩存區(qū)拷貝到內(nèi)核開辟的緩存區(qū)中,然后再從內(nèi)核緩存區(qū)拷貝到接收方緩存區(qū),因此整個(gè)過程需要拷貝兩次。
Binder簡介
雖然Android系統(tǒng)是基于Linux系統(tǒng)實(shí)現(xiàn)的,但它并沒有使用上述的5種方式作為系統(tǒng)的進(jìn)程間通信方式,主要是由這幾種方式要么是開銷過大,要么就是安全性低。因?yàn)锳ndroid系統(tǒng)作為一種嵌入式系統(tǒng),設(shè)備資源相對(duì)有限,因此對(duì)相關(guān)的性能要求也非常高,過大的開銷會(huì)嚴(yán)重影響系統(tǒng)的運(yùn)行性能。另外,Android系統(tǒng)是開放式的,擁有眾多的開發(fā)者平臺(tái),應(yīng)用程序的來源也非常廣泛,同時(shí)傳統(tǒng)的IPC方式無法獲得對(duì)方進(jìn)程可靠的UID/PID進(jìn)行身份校驗(yàn),這會(huì)直接影響智能設(shè)備的安全?;诖?,Android系統(tǒng)建立了一套新的IPC機(jī)制來滿足系統(tǒng)中對(duì)較高的傳輸性能和安全性通信要求,這種Android特有的IPC機(jī)制就是Binder機(jī)制。
Binder是基于OpenBinder實(shí)現(xiàn)的,OpenBinder由Google公司的Dianne Hackborn開發(fā),旨在提供一個(gè)簡單的進(jìn)程間互相通訊的途徑。Binder機(jī)制采用C/S通信模型,它使用Binder來作為Server服務(wù)對(duì)外的訪問接入點(diǎn)和Client向Server發(fā)起服務(wù)請(qǐng)求的"地址",并且在進(jìn)程間通信的過程中,數(shù)據(jù)傳輸只需拷貝一次,并且Client的身份驗(yàn)證標(biāo)志(UID/PID)只能由Binder機(jī)制在內(nèi)核中添加,因此具有安全性高、傳輸性能好等優(yōu)勢。與其他IPC機(jī)制不同,Binder使用了面向?qū)ο蟮乃枷雭砻枋鯯erver端的訪問接入點(diǎn)和Client端的服務(wù)請(qǐng)求發(fā)起地址,具體來說就是Server端的訪問接入點(diǎn)實(shí)質(zhì)是位于Server進(jìn)程中的一個(gè)Binder實(shí)體對(duì)象,該對(duì)象提供了一套方法用于向Client端提供各種服務(wù);Client端的“地址”即為Binder實(shí)體對(duì)象的引用,Client將持有該引用向Server端發(fā)起服務(wù)請(qǐng)求。下圖為Binder機(jī)制的C/S模型:
雖說Binder機(jī)制的底層代碼由C實(shí)現(xiàn),但面向?qū)ο笏枷氲囊雽⑦M(jìn)程間通信轉(zhuǎn)化為通過對(duì)某個(gè)Binder對(duì)象的引用并調(diào)用該對(duì)象的方法,而其獨(dú)特之處在于Binder對(duì)象是一個(gè)可以跨進(jìn)程引用的對(duì)象,它的實(shí)體位于一個(gè)進(jìn)程中,而它的引用卻遍布于系統(tǒng)的各個(gè)進(jìn)程之中。
Binder通信框架
基于Binder機(jī)制的進(jìn)程間通信,其通信框架主要涉及四個(gè)角色,即Server進(jìn)程、Client進(jìn)程、ServerManager進(jìn)程以及Binder驅(qū)動(dòng),其中,Server、Client和ServerManager運(yùn)行在用戶空間,Binder驅(qū)動(dòng)運(yùn)行在內(nèi)核空間。Binder驅(qū)動(dòng)是Binder通信框架的核心,它工作于內(nèi)核空間,主要負(fù)責(zé)進(jìn)程間Binder通信的建立、Binder在進(jìn)程之間的傳遞、Binder引用計(jì)數(shù)管理以及數(shù)據(jù)包在進(jìn)程之間的傳遞和交互等一系列底層支持;Server進(jìn)程用于向Client進(jìn)程提供遠(yuǎn)程服務(wù),該進(jìn)程會(huì)創(chuàng)建一個(gè)Binder實(shí)體(對(duì)象),并為其取一個(gè)字符串形式的名字,當(dāng)該Binder實(shí)體被Binder驅(qū)動(dòng)在ServerManger進(jìn)行實(shí)名注冊后,我們又稱這個(gè)Binder實(shí)體為“實(shí)名Binder”,它將擔(dān)負(fù)起向Client提供具體的遠(yuǎn)程服務(wù);Client進(jìn)程即為我們的APP,它將通過遠(yuǎn)程Binder實(shí)體的引用訪問遠(yuǎn)程Server,獲取相關(guān)的服務(wù),這里為什么不是直接通過Binder實(shí)體訪問,我們在后面的Binder機(jī)制原理再詳述;ServerManager是一個(gè)系統(tǒng)進(jìn)程,它管理著一張“查詢表”,該表記錄了Server進(jìn)程中Binder實(shí)體名字到Client中對(duì)該Binder實(shí)體引用的對(duì)應(yīng)關(guān)系,以便使Client能夠通過Binder名字獲得對(duì)Server中Binder實(shí)體的引用。Binder通信框架結(jié)構(gòu)圖如下:
在Binder機(jī)制通信模型中,Server、Client、ServerManager以及Binder驅(qū)動(dòng)的關(guān)系有點(diǎn)類似于互聯(lián)網(wǎng),它們分別對(duì)應(yīng)于互聯(lián)網(wǎng)中的服務(wù)器、客戶端、域名服務(wù)器(DNS)以及路由器,其中,服務(wù)器用于向客戶端提供服務(wù)且對(duì)外接入點(diǎn)為IP地址;客戶端用于向服務(wù)器發(fā)起請(qǐng)求服務(wù),且發(fā)起"地址"通常為域名;域名服務(wù)器提供遠(yuǎn)程服務(wù)器的IP地址與其域名映射關(guān)系,便于客戶端能夠通過域名直接訪問服務(wù)器;路由器用于網(wǎng)絡(luò)管理、數(shù)據(jù)處理等,是互聯(lián)網(wǎng)絡(luò)的樞紐。Binder通信框架流程圖如下:
大致過程為:
首先,系統(tǒng)中某個(gè)進(jìn)程向Binder驅(qū)動(dòng)發(fā)起申請(qǐng)為ServerManager進(jìn)程,該進(jìn)程將建立一張系統(tǒng)中相關(guān)Server進(jìn)程“名字”及其“地址”的映射表(查詢表); 其次,Server進(jìn)程將自己“名字”和“地址”添加到ServerManager進(jìn)程的查詢表中; 最后,Client進(jìn)程從ServerManager進(jìn)程獲取到遠(yuǎn)程Server進(jìn)程的真實(shí)“地址”,即建立Binder通信完畢。Binder機(jī)制原理
前面談?wù)摰酱蟛糠謧鹘y(tǒng)的IPC都是基于存儲(chǔ)-轉(zhuǎn)發(fā)的方式實(shí)現(xiàn)的,即進(jìn)程A通過系統(tǒng)調(diào)用copy_from_user將數(shù)據(jù)從用戶空間拷貝到內(nèi)核空間,然后再通過系統(tǒng)調(diào)用copy_to_user將數(shù)據(jù)拷貝從內(nèi)核空間拷貝到進(jìn)程B,整個(gè)通信過程數(shù)據(jù)需要拷貝2次。但是Binder機(jī)制卻不是這么做的,而是把所有的工作均交給Binder驅(qū)動(dòng)來完成,并且Binder本質(zhì)上只是一種底層通信方式和具體服務(wù)沒有關(guān)系。為了提供具體服務(wù)(或稱能力),Server必須提供一套接口函數(shù)以便Client通過遠(yuǎn)程訪問使用各種服務(wù),這里使用代理(Proxy)模式來實(shí)現(xiàn),即**將接口函數(shù)定義在一個(gè)抽象類中,Server和Client均以該抽象類為基類實(shí)現(xiàn)所有的接口函數(shù),其中Server端是真正的功能實(shí)現(xiàn)并為每個(gè)函數(shù)進(jìn)行一一編號(hào)以便Client精準(zhǔn)調(diào)用,而Client端則是對(duì)這些函數(shù)遠(yuǎn)程調(diào)用請(qǐng)求的包裝。此外,Server端還定義了一個(gè)Binder抽象類來處理來自Client的Binder請(qǐng)求數(shù)據(jù)包,其中最重要的成員函數(shù)是虛函數(shù)onTransact,該函數(shù)將用于分析收到的數(shù)據(jù)包,調(diào)用相應(yīng)的接口函數(shù)處理請(qǐng)求,并將最終的調(diào)用結(jié)果返回給Client。整個(gè)通信過程都是在Binder驅(qū)動(dòng)的控制下完成的,并且Binder在Server中的實(shí)體是通過采用繼承方式以接口類和Binder抽象類為基類構(gòu)建的。**接下來,我們借助Binder學(xué)習(xí)指南一文中的一張圖來詳細(xì)剖析下Binder機(jī)制通信過程,了解Binder驅(qū)動(dòng)、ServerManager(SM)在整個(gè)通信過程中所起的作用。
為了深入理解基于Binder機(jī)制的進(jìn)程間通信原理,這里假設(shè)Server進(jìn)程中有個(gè)Object對(duì)象(即Binder實(shí)體),它提供一個(gè)add方法供遠(yuǎn)程調(diào)用,Client進(jìn)程將通過Binder機(jī)制的方式訪問Server進(jìn)程中Object對(duì)象的add方法,具體的通信過程如下:
Server在SM中注冊實(shí)名Binder
在Server進(jìn)程中有一個(gè)Object對(duì)象(即Binder實(shí)體,下述均以Binder實(shí)體描述),它提供一個(gè)add方法,為了Client能夠找到自己并與之通信,Server進(jìn)程為Binder實(shí)體創(chuàng)建了一個(gè)字符形式的名字,然后再將Binder實(shí)體及其名字以數(shù)據(jù)包的形式通過Binder驅(qū)動(dòng)發(fā)送給ServerManager進(jìn)行注冊,其注冊過程為:
首先,Binder驅(qū)動(dòng)接收到Server發(fā)過來的數(shù)據(jù)包后,會(huì)取出數(shù)據(jù)包中的Binder實(shí)體及其名字,并為該Binder實(shí)體創(chuàng)建位于內(nèi)核中的實(shí)體節(jié)點(diǎn),并生成與其名字對(duì)應(yīng)的引用;
然后,Binder驅(qū)動(dòng)將Binder的名字和新建的引用打包傳遞給ServerManager,ServerManager收到數(shù)據(jù)包后從中取出名字和引用填入一張查找表中,這張表就像一個(gè)“通訊錄”且是系統(tǒng)唯一的,它記錄了系統(tǒng)中各種Server的名字(Binder實(shí)體字符形式名字)和地址(Binder實(shí)體的引用),而被注冊的這個(gè)Binder實(shí)體也稱為實(shí)名Binder。
Client從SM獲得實(shí)名Binder的引用
Client進(jìn)程要想訪問Server進(jìn)程的Binder實(shí)體的add方法,會(huì)將要訪問Binder實(shí)體的名字以數(shù)據(jù)包的形式發(fā)送給Binder驅(qū)動(dòng),Binder驅(qū)動(dòng)取出名字查詢ServerManager中的查詢表即可獲得Binder實(shí)體及其引用。但是Binder驅(qū)動(dòng)并沒有將真正的Binder實(shí)體返回給Client,而是“照著”Binder實(shí)體的樣子仿造一個(gè)一模一樣的對(duì)象作為代理返回給Client,這個(gè)對(duì)象又被稱之為代理對(duì)象ProxyBinder,它持有Binder實(shí)體的引用,且擁有與Binder實(shí)體完全相同能力(即方法),只是這些能力只是個(gè)“空殼”,真正的具體實(shí)現(xiàn)還是在Server進(jìn)程的Binder實(shí)體中。由于驅(qū)動(dòng)返回的代理對(duì)象(ProxyBinder)與Server進(jìn)程中的Binder實(shí)體如此相似,給人的感覺好像是直接把Server進(jìn)程Binder實(shí)體(對(duì)象)傳遞到了Client進(jìn)程,因此,我們可以說Binder對(duì)象是可以跨進(jìn)程傳遞的對(duì)象,而實(shí)際上Binder對(duì)象并沒有傳遞,傳遞的僅僅是Binder對(duì)象的引用,它將通過代理對(duì)象來承載。也就是說,Server進(jìn)程中Binder對(duì)象指Binder實(shí)體(也稱Binder本地對(duì)象),Client進(jìn)程中Binder對(duì)象指的是Binder代理對(duì)象。在Binder對(duì)象進(jìn)行跨進(jìn)程傳遞的時(shí)候,Binder驅(qū)動(dòng)會(huì)自動(dòng)完成這兩種類型的轉(zhuǎn)換。
需要注意的是,Binder驅(qū)動(dòng)返回一個(gè)Binder實(shí)體的代理對(duì)象給Client是基于Client與Server歸屬于不同進(jìn)程而言的,如果Client和Server歸屬于同一個(gè)進(jìn)程,Binder驅(qū)動(dòng)將直接將Server進(jìn)程的Binder實(shí)體返回給Client。由于本文主要是考慮Client與Server歸屬于不同進(jìn)程情況,因此待Client獲得代理對(duì)象ProxyBinder的那一刻,基于Binder機(jī)制的Client與Server遠(yuǎn)程通信鏈路建立完畢。
Client與Server跨進(jìn)程通信
在Binder驅(qū)動(dòng)返回一個(gè)Binder的代理對(duì)象給Client進(jìn)程后,Client進(jìn)程就可以通過該代理對(duì)象與遠(yuǎn)程Server進(jìn)程進(jìn)行通信。Binder代理對(duì)象繼承了Server提供的公共接口類并實(shí)現(xiàn)公共函數(shù)(注:并不是真正的實(shí)現(xiàn),真正的實(shí)現(xiàn)在Server進(jìn)程的Binder實(shí)體中),是對(duì)遠(yuǎn)程函數(shù)調(diào)用的包裝。接下來,我們分析下Client訪問Server中方法通信過程:(1) Client進(jìn)程首先會(huì)將函數(shù)參數(shù)和Binder實(shí)體的引用以數(shù)據(jù)包的形式進(jìn)行打包,然后將數(shù)據(jù)包發(fā)送給Binder驅(qū)動(dòng)向指定Server發(fā)送請(qǐng)求,此后Client進(jìn)程進(jìn)入掛起狀態(tài),以等待返回值;(2) Binder驅(qū)動(dòng)收到Client進(jìn)程發(fā)送過來的數(shù)據(jù)包后,取出Binder實(shí)體的引用,獲得目的Server并將其喚醒,再將數(shù)據(jù)包發(fā)送給它處理。這里需要提下的是,由于該引用本來就是Binder驅(qū)動(dòng)創(chuàng)建并交給ServerManager注冊用的,因此Binder驅(qū)動(dòng)自然很容易就能夠通過該引用找到能夠接收數(shù)據(jù)包的Server和獲得指向Binder實(shí)體對(duì)應(yīng)的內(nèi)存空間;(3) Server進(jìn)程收到Binder驅(qū)動(dòng)發(fā)送過來的Binder請(qǐng)求數(shù)據(jù)包后,Server進(jìn)程會(huì)利用之前開辟好線程池中的線程來處理該請(qǐng)求,通過調(diào)用Binder實(shí)體中的onTransact函數(shù),對(duì)收到的數(shù)據(jù)包進(jìn)行分析,即取出數(shù)據(jù)包中請(qǐng)求的函數(shù)接口編碼,case-by-case地解析code值,待解析成功后,再從數(shù)據(jù)包中取出函數(shù)參數(shù)并調(diào)用相應(yīng)的接口函數(shù)處理請(qǐng)求,然后Server進(jìn)程會(huì)將調(diào)用結(jié)果發(fā)送給Binder驅(qū)動(dòng);(4) Binder驅(qū)動(dòng)收到Server進(jìn)程返回的調(diào)用結(jié)果后,就會(huì)喚醒處于等待中的Client進(jìn)程,并將結(jié)果返回給它,至此,一次跨進(jìn)程通信完畢。
Java層Binder框架解析
在Android系統(tǒng)中,Binder框架由C/C++底層和Java上層構(gòu)成,其中C/C++底層提供功能實(shí)現(xiàn),Java上層為應(yīng)用進(jìn)程間的通信提供接口。由于C/C++層底層實(shí)現(xiàn)極其復(fù)雜,本文暫不涉及這部分內(nèi)容,本節(jié)將詳細(xì)剖析Java層部分。根據(jù)Binder機(jī)制原理,Binder框架Java層部分主要包含四部分,即公共接口(IIterface)、Binder接口(IBinder)、Binder實(shí)體(或稱Binder本地對(duì)象)以及Binder代理對(duì)象(BinderProxy),它們各自的作用如下:
IIterfaceIIterface是Android提供的一個(gè)接口,它表明遠(yuǎn)程Server對(duì)象具有什么樣的能力,可理解為Server和Client契約,Binder本地對(duì)象和Binder代理對(duì)象均需實(shí)現(xiàn)該接口。Interface接口中只包含一個(gè)asBinder方法,該方法用于返回與該IInterface綁定的Binder本地對(duì)象。IIterface源碼如下:
publicinterfaceIInterface
{
// 返回與該IIterface綁定的Binder實(shí)體對(duì)象
publicIBinder asBinder();
}
IBinder代表了一種跨進(jìn)程傳輸?shù)哪芰?,?shí)現(xiàn)該接口就能將這個(gè)對(duì)象進(jìn)行跨進(jìn)程傳遞,IBinder負(fù)責(zé)數(shù)據(jù)傳遞。在跨進(jìn)程數(shù)據(jù)流經(jīng)驅(qū)動(dòng)的時(shí)候,驅(qū)動(dòng)會(huì)識(shí)別IBinder類型的數(shù)據(jù),從而自動(dòng)完成不同進(jìn)程Binder本地對(duì)象以及Binder代理對(duì)象的轉(zhuǎn)換。
publicinterfaceIBinder{
// 代碼省略
...
// 返回綁定在該Binder對(duì)象的IInterface有關(guān)的描述
public@NullableString getInterfaceDeorthrowsRemoteException;
// 判斷Binder通信鏈路是否斷開
publicbooleanisBinderAlive;
// 獲取deor對(duì)應(yīng)的本地IIterface,如果返回為空,說明
// Client和Server歸屬于不同進(jìn)程
public@NullableIInterface queryLocalInterface(@NonNull String deor);
// 代碼省略
...
// 處理Binder請(qǐng)求
// code:要執(zhí)行的函數(shù)編碼
// data:函數(shù)參數(shù)
// reply:返回值
// flags:附加標(biāo)志,暫時(shí)忽略
publicbooleantransact(intcode, @NonNull Parcel data, @Nullable Parcel reply,
intflags)throwsRemoteException;
// Binder鏈接死亡(斷開)回調(diào)接口
publicinterfaceDeathRecipient{
publicvoidbinderDied;
}
// 注冊Binder鏈接斷開通知
// 即當(dāng)Binder鏈接斷開時(shí),DeathRecipient接口的binderDied方法會(huì)被回調(diào)
publicvoidlinkToDeath(@NonNull DeathRecipient recipient, intflags)
throwsRemoteException;
// 移除已注冊的Binder鏈接斷開通知
publicbooleanunlinkToDeath(@NonNull DeathRecipient recipient, intflags);
}
BinderBinder實(shí)體對(duì)象,位于Server進(jìn)程中,它繼承了IBinder,從而具有跨進(jìn)程傳輸?shù)哪芰Γ趯?shí)際通信過程中,Binder實(shí)體對(duì)象并沒有傳輸,傳輸?shù)闹皇窃搶?duì)象的引用。
Binder代理對(duì)象遠(yuǎn)程進(jìn)程Binder對(duì)象的代理,位于Client進(jìn)程中,它持有IBinder引用,也可以理解擁有跨進(jìn)程傳輸?shù)哪芰Α?/span>
AIDL工作原理
AIDL(Android Interface Definition Language),即Android接口定義語言,是Android系統(tǒng)為了便于開發(fā)具備跨進(jìn)程通信的應(yīng)用,專門提供的且用于自動(dòng)生成Java層Binder通信框架的技術(shù)。AIDL的使用比較簡單,我們只需要編寫符合AIDL開發(fā)規(guī)范的源碼文件,AS就會(huì)自動(dòng)生成用于跨進(jìn)程通信的相關(guān)文件。這里以Server端向Client提供"加法計(jì)算"服務(wù)(能力)為例,詳細(xì)剖析Java層Binder通信框架原理。
首先,我們在工程中創(chuàng)建一個(gè)以".aidl"為后綴的源文件,文件命名為IComputeInterface,并提供一個(gè)add方法;
packagecom.jiangdg.hellobinder;
interfaceIComputeInterface{
intadd(inta,intb);
}
其次,"Build->make project"工程后AS就會(huì)自動(dòng)在"app/build/generated/…/com/jiangdg/hellobuilder"目錄生成一個(gè)名為IComputeInterface.java接口文件。代碼框架大致如下:
publicinterfaceIComputeInterfaceextendsandroid.os.IInterface{
// Binder實(shí)體
publicstaticabstractclassStubextendsandroid.os.Binderimplements
com.jiangdg.hellobinder.IComputeInterface{
...
// Binder實(shí)體的代理對(duì)象
privatestaticclassProxyimplements
com.jiangdg.hellobinder.IComputeInterface{
...
}
}
// 公共方法
publicintadd(inta, intb)throwsandroid.os.RemoteException;
}
從IComputeInterface.java源碼我們可以大致看出,它主要包含三部分,即接口IComputeInterface,靜態(tài)抽象類Stub、靜態(tài)類Proxy,并由此構(gòu)成Java層的Binder通信框架。接下來,我們就來分析它們之間有何關(guān)聯(lián)以及起到的作用是什么?
(1) IComputeInterface:公共接口
IComputeInterface繼承于接口IInterface,它包含一個(gè)add方法且拋出RemoteException異常,由此可知add方法應(yīng)該是一個(gè)被遠(yuǎn)程訪問的方法。根據(jù)Binder機(jī)制原理,我們自然容易明白IComputeInterface接口就是一個(gè)“契約”接口,它表明Server端能夠像Client端提供哪些服務(wù),也是Binder機(jī)制中的代理訪問的實(shí)現(xiàn)基礎(chǔ),Server中的Binder實(shí)體和Client中的Binder實(shí)體的代理均需要實(shí)現(xiàn)它,其中,在Binder實(shí)體中為add方法真正的實(shí)現(xiàn),在Binder實(shí)體的代理對(duì)象中只是對(duì)add方法的遠(yuǎn)程調(diào)用請(qǐng)求包裝,在接下來的分析中可以驗(yàn)證這一點(diǎn)。
publicinterfaceIComputeInterfaceextendsandroid.os.IInterface{
publicintadd(inta, intb)throwsandroid.os.RemoteException;
}
(2) IComputeInterface.Stub:Binder本地對(duì)象
從 IComputeInterface的源碼可知,Stub是IComputeInterface的一個(gè)靜態(tài)抽象內(nèi)部類,但是這不是關(guān)鍵的,也僅是AIDL中的生成代碼的一種形式而已,真正重要的是Stub繼承了Binder類和IComputeInterface接口,而Binder又繼承于IBinder。根據(jù)Binder機(jī)制原理,我們就可以得出Stub就是位于Server端中的Binder實(shí)體或稱Binder本地對(duì)象,它的源碼如下:
publicstaticabstractclassStubextendsandroid.os.Binderimplements
com.jiangdg.hellobinder.IComputeInterface{
// 表明IComputeInterface是本地接口描述
privatestaticfinaljava.lang.String DEOR =
"com.jiangdg.hellobinder.IComputeInterface";
// 將Stub本身(即Binder實(shí)體對(duì)象)綁定到接口Interface
publicStub{
this.attachInterface( this, DEOR);
}
// 將Binder實(shí)體對(duì)象轉(zhuǎn)換為IInterface,即創(chuàng)建Binder實(shí)體的代理對(duì)象,如果需要的話
publicstaticcom.jiangdg.hellobinder. IComputeInterface
asInterface(android.os.IBinder obj){
if((obj== null)) {
returnnull;
}
android.os.IInterface iin = obj.queryLocalInterface(DEOR);
if(((iin!= null)&&(iin instanceofcom.jiangdg.hellobinder.IComputeInterface))){
return((com.jiangdg.hellobinder.IComputeInterface));
}
returnnewcom.jiangdg.hellobinder.IComputeInterface.Stub.Proxy(obj);
}
// 返回Binder實(shí)體對(duì)象本身
@Override
publicandroid.os. IBinder asBinder{
returnthis;
}
// 分析處理Binder請(qǐng)求數(shù)據(jù)包,根據(jù)code找到相應(yīng)的節(jié)點(diǎn)
// 調(diào)用相應(yīng)的方法處理請(qǐng)求
@Override
publicbooleanonTransact(intcode, android.os.Parcel data, android.os.Parcel reply, intflags)throwsandroid.os.RemoteException{
switch(code){
caseINTERFACE_TRANSACTION:
{
reply.writeString(DEOR);
returntrue;
}
caseTRANSACTION_add:
{
data.enforceInterface(DEOR);
int_arg0;
_arg0 = data.readInt;
int_arg1;
_arg1 = data.readInt;
int_result = this.add(_arg0, _arg1);
reply.writeNoException;
reply.writeInt(_result);
returntrue;
}
}
returnsuper.onTransact(code, data, reply, flags);
}
staticfinalintTRANSACTION_add = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
}
接下來,我們著重分析下Stub類的工作原理,這里從asInterface方法入手,該方法主要的作用是判斷Binder驅(qū)動(dòng)傳遞過來的Binder對(duì)象obj類型,來決定是否想需要返回Binder對(duì)象的代理對(duì)象Proxy,即調(diào)用obj的queryLocalInterface方法判斷傳入的DEOR(接口描述)是否與obj綁定的一致,如果一致,則表明Client與Server歸屬于同一個(gè)進(jìn)程,直接將Binder本地對(duì)象返回給Client;如果不一致,則表明Client與Server不屬于同一個(gè)進(jìn)程,就需要將obj作為參數(shù)實(shí)例化一個(gè)Binder本地對(duì)象的代理Proxy給Client。onTransact方法用于分析處理Binder驅(qū)動(dòng)發(fā)來的請(qǐng)求數(shù)據(jù)包,如果Client與Server屬于同一個(gè)進(jìn)程,當(dāng)Client要訪問Server中的add方法時(shí),onTransact就會(huì)被直接調(diào)用,不再經(jīng)歷代理調(diào)用步驟。
(3) IComputeInterface.Stub.Proxy
Proxy是Stub的一個(gè)靜態(tài)內(nèi)部類,同樣也不是關(guān)鍵的,僅是AIDL中的生成代碼的一種形式而已,真正重要的是Proxy繼承了IComputeInterface接口,并持有一個(gè)IBinder對(duì)象的引用。根據(jù)Binder機(jī)制原理,我們就可以得出Proxy就是位于Client端中的Binder本地對(duì)象的代理。從Proxy的源碼可知,它不僅持有遠(yuǎn)程Binder實(shí)體的引用,還重寫了公共方法add,該方法將Client要訪問遠(yuǎn)程方法的參數(shù)封裝在Parcel對(duì)象中,然后調(diào)用遠(yuǎn)程Binder實(shí)體的transact方法發(fā)起跨進(jìn)程調(diào)用。通過查看Android源碼可知,transact方法的實(shí)現(xiàn)位于native層,它最終調(diào)用talkwithDriver函數(shù)將請(qǐng)求參數(shù)打包交給Binder驅(qū)動(dòng),Binder驅(qū)動(dòng)識(shí)別后,最終會(huì)調(diào)用遠(yuǎn)程Server中Binder實(shí)體的onTransact方法,即Stub的onTransact方法進(jìn)行處理。需要注意的是,在實(shí)際開發(fā)中,Stub中onTransact方法所調(diào)用的add方法將由我們自己實(shí)現(xiàn),待add執(zhí)行完畢會(huì)將結(jié)果填入Parcel中以便Binder驅(qū)動(dòng)返回給Client。Proxy源碼如下:
privatestaticclassProxyimplementscom.jiangdg.hellobinder.IComputeInterface
{
// 遠(yuǎn)程Binder實(shí)體對(duì)象
privateandroid.os.IBinder mRemote;
Proxy(android.os.IBinder remote){
mRemote = remote;
}
// 返回與代理對(duì)象對(duì)應(yīng)的Binder實(shí)體
@Override
publicandroid.os. IBinder asBinder{
returnmRemote;
}
publicjava.lang. String getInterfaceDeor{
returnDEOR;
}
// 對(duì)遠(yuǎn)程調(diào)用的封裝
@Override
publicintadd(inta, intb)throwsandroid.os.RemoteException{
android.os.Parcel _data = android.os.Parcel.obtain;
android.os.Parcel _reply = android.os.Parcel.obtain;
int_result;
try{
_data.writeInterfaceToken(DEOR);
_data.writeInt(a);
_data.writeInt(b);
// 調(diào)用遠(yuǎn)程Binder實(shí)體的transact方法
// 開始處理訪問請(qǐng)求
mRemote.transact(Stub.TRANSACTION_add, _data, _reply, 0);
_reply.readException;
_result = _reply.readInt;
}
finally{
_reply.recycle;
_data.recycle;
}
return_result;
}
}
至此,關(guān)于對(duì)Binder機(jī)制的分析將告一段落,最后,我們采用Android Binder設(shè)計(jì)與實(shí)現(xiàn)中的一段原話為Binder機(jī)制作個(gè)總結(jié):Binder模糊了進(jìn)程邊界,淡化了進(jìn)程間通信過程,整個(gè)系統(tǒng)仿佛運(yùn)行于同一個(gè)面向?qū)ο蟮某绦蛑?,形形色色的Binder對(duì)象及其星羅棋布的引用仿佛粘接各個(gè)應(yīng)用程序的膠水,這也是Binder在英文的原意。
版權(quán)聲明:本文為 CSDN 博主「無名之輩FTER」的原創(chuàng)文章。
?國產(chǎn)數(shù)據(jù)庫激蕩 40 年