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