成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

關(guān)于Binder,作為應(yīng)用開(kāi)發(fā)者你需要知道的全部

移動(dòng)開(kāi)發(fā) Android
這篇文章主要從宏觀的層面去理解Binder中的各種概念和基本通信過(guò)程,只關(guān)注Java層的實(shí)現(xiàn),底層實(shí)現(xiàn)不做介紹。對(duì)于應(yīng)用開(kāi)發(fā)者而言,理解Binder的基本設(shè)計(jì)原理和通信過(guò)程已經(jīng)夠了,想要深入理解Binder需要自行閱讀源碼。

為什么要理解Binder?

一般Android應(yīng)用開(kāi)發(fā)很少直接用到跨進(jìn)程信通信(IPC),但如果你想知道:

  • App是如何啟動(dòng)并初始化的?
  • Activity的啟動(dòng)過(guò)程是怎樣的?
  • 進(jìn)程間是如何通信的?
  • AIDL的具體原理是什么?
  • 眾多插件化框架的設(shè)計(jì)原理 等等

就必須對(duì)Binder有所了解,無(wú)論是四大組件,還是各種系統(tǒng)Service,比如ActivityManagerService、PackageManagerService,它們的實(shí)現(xiàn)都依賴(lài)Binder的通信機(jī)制,可見(jiàn)Binder在Android系統(tǒng)中的重要性,可以說(shuō)Binder是邁入高級(jí)工程師的***步。

[[245146]]

Binder機(jī)制很復(fù)雜,想要徹底弄懂比較難,除了需要了解操作系統(tǒng)中的各種知識(shí)外,還需要看懂Binder驅(qū)動(dòng)層的代碼實(shí)現(xiàn)。最近看了很多關(guān)于Binder的文章,大部分過(guò)于抽象或者過(guò)于深入源碼細(xì)節(jié),真正淺顯易懂的文章很少。

這篇文章主要從宏觀的層面去理解Binder中的各種概念和基本通信過(guò)程,只關(guān)注Java層的實(shí)現(xiàn),底層實(shí)現(xiàn)不做介紹。對(duì)于應(yīng)用開(kāi)發(fā)者而言,理解Binder的基本設(shè)計(jì)原理和通信過(guò)程已經(jīng)夠了,想要深入理解Binder需要自行閱讀源碼。

本文主要從三個(gè)方面來(lái)做分析:

1、為什么是Binder?

  • 傳統(tǒng)Linux IPC機(jī)制的缺點(diǎn)
  • Linux的一些基本知識(shí)
  • 傳統(tǒng)Linux IPC機(jī)制的通信原理

2、Binder的基本原理

  • Binder的底層原理
  • Binder的通信模型
  • Binder的代理機(jī)制
  • 對(duì)Binder概念的重新理解

3、通過(guò)代碼來(lái)理解Binder

  • 通過(guò)AIDL實(shí)例來(lái)了解Binder的用法
  • 通過(guò)手動(dòng)編碼實(shí)現(xiàn)ActivityManagerService

1、為什么是Binder?

1.1 傳統(tǒng)IPC機(jī)制的缺點(diǎn)

大家都知道Android系統(tǒng)是基于Linux內(nèi)核實(shí)現(xiàn)的,Linux已經(jīng)提供了多種進(jìn)程間通信機(jī)制,比如:管道、消息隊(duì)列、共享內(nèi)存和套接字(Socket)等等,為什么還要再實(shí)現(xiàn)一套IPC機(jī)制呢?主要是基于兩方面的原因:

1.1.1 性能角度

管道、消息隊(duì)列、Socket實(shí)現(xiàn)一次進(jìn)程通信都需要2次內(nèi)存拷貝,效率太低;共享內(nèi)存雖然不需要拷貝內(nèi)存,但管理復(fù)雜;Binder只需要一次內(nèi)存拷貝,從性能角度來(lái)看,低于共享內(nèi)存方式,優(yōu)于其它方式。

關(guān)于Binder,作為應(yīng)用開(kāi)發(fā)者你需要知道的全部

1.1.2 安全性考慮

傳統(tǒng)的IPC機(jī)制沒(méi)有安全措施,接收方無(wú)法獲得對(duì)方可靠的進(jìn)程ID或用戶ID,完全靠上層的協(xié)議來(lái)保護(hù),比如Socket通信的IP地址是客戶端填入的,很可能被惡意程序篡改。Android作為面向終端用戶的開(kāi)源平臺(tái),應(yīng)用市場(chǎng)中有海量的應(yīng)用供用戶選擇,因此安全性極為重要。Android系統(tǒng)為每個(gè)已安裝的App都分配了用戶ID(UID),UID是鑒別進(jìn)程身份的重要標(biāo)識(shí),通過(guò)UID可以進(jìn)行一系列的權(quán)限校驗(yàn)。另一方面 ,傳統(tǒng)IPC的接入點(diǎn)是開(kāi)放的,任何程序都可以根據(jù)協(xié)議進(jìn)行訪問(wèn),無(wú)法阻止惡意程序的訪問(wèn),Android需要一種基于C/S架構(gòu)的IPC機(jī)制,Server端需要能夠?qū)lient的請(qǐng)求進(jìn)行身份校驗(yàn),來(lái)保證數(shù)據(jù)的安全性。

1.2 Linux的一些基本知識(shí)

要知道Binder是如何只用一次內(nèi)存拷貝即實(shí)現(xiàn)跨進(jìn)程通信的,首先需要弄清楚為什么傳統(tǒng)IPC機(jī)制為什么需要兩次內(nèi)存拷貝,這就需要先了解一些操作系統(tǒng)的基礎(chǔ)知識(shí)。

1.2.1 進(jìn)程隔離

先來(lái)看一下維基百科對(duì)“進(jìn)程隔離”的定義:

進(jìn)程隔離是為保護(hù)操作系統(tǒng)中進(jìn)程互不干擾而設(shè)計(jì)的一組不同硬件和軟件的技術(shù)。這個(gè)技術(shù)是為了避免進(jìn)程A寫(xiě)入進(jìn)程B的情況發(fā)生。 進(jìn)程的隔離實(shí)現(xiàn),使用了虛擬地址空間。進(jìn)程A的虛擬地址和進(jìn)程B的虛擬地址不同,這樣就防止進(jìn)程A將數(shù)據(jù)信息寫(xiě)入進(jìn)程B。

也就是說(shuō),進(jìn)程之間的數(shù)據(jù)是不共享的,A進(jìn)程無(wú)法直接訪問(wèn)B進(jìn)程的數(shù)據(jù),以此來(lái)保證數(shù)據(jù)的安全性。在進(jìn)程隔離的操作系統(tǒng)中,進(jìn)程之間的交互必須通過(guò)IPC機(jī)制。

進(jìn)程隔離的實(shí)現(xiàn)使用了虛擬地址空間,什么是虛擬地址空間呢?首先需要了解操作系統(tǒng)中的虛擬內(nèi)存概念,它是一種提高編程效率和提高物理內(nèi)存利用效率的一種技術(shù)。簡(jiǎn)單來(lái)說(shuō),就是應(yīng)用程序看到了都一片連續(xù)完整的內(nèi)存地址空間,而實(shí)際上這些地壇空間是映射到碎片化的物理內(nèi)存中的,這個(gè)映射的過(guò)程對(duì)應(yīng)用程序來(lái)說(shuō)是透明的。這個(gè)概念很重要,對(duì)于虛擬內(nèi)存更深入的理解可以參考這篇文章:Linux 虛擬內(nèi)存和物理內(nèi)存的理解

1.2.2 進(jìn)程空間:用戶空間/內(nèi)核空間

現(xiàn)在的操作系統(tǒng)都采用虛擬內(nèi)存,對(duì)32位的操作系統(tǒng)而言,尋址空間是2的32次方,即4G。操作系統(tǒng)的核心是內(nèi)核,內(nèi)核擁有對(duì)底層設(shè)備的所有訪問(wèn)權(quán)限,因此需要和普通的應(yīng)用程序獨(dú)立開(kāi)來(lái),用戶進(jìn)程不能直接訪問(wèn)內(nèi)核進(jìn)程。操作系統(tǒng)從邏輯上把虛擬地址空間劃分為用戶空間(User Space)和內(nèi)核空間(Kernel Space)。在32位的Linux操作系統(tǒng)中,將高位的1GB字節(jié)供內(nèi)核使用,稱(chēng)之為內(nèi)核空間;剩下的3GB字節(jié)供用戶進(jìn)程使用,稱(chēng)之為用戶空間。

1.2.3 系統(tǒng)調(diào)用:用戶態(tài)/內(nèi)核態(tài)

因?yàn)橛脩艨臻g的權(quán)限低于內(nèi)核空間,不可避免用戶空間需要訪問(wèn)內(nèi)核空間的資源,比如讀寫(xiě)文件和網(wǎng)絡(luò)訪問(wèn),如何實(shí)現(xiàn)呢?唯一的方式就是通過(guò)操作系統(tǒng)提供的系統(tǒng)調(diào)用接口,通過(guò)系統(tǒng)調(diào)用接口,用戶程序可以在內(nèi)核的控制下實(shí)現(xiàn)對(duì)內(nèi)核資源的有限訪問(wèn),這樣既能滿足應(yīng)用程序的資源請(qǐng)求,也能保障系統(tǒng)安全和穩(wěn)定。

當(dāng)用戶進(jìn)程執(zhí)行自己的代碼時(shí),進(jìn)程當(dāng)前就處于用戶運(yùn)行態(tài)(用戶態(tài)),此時(shí)處理器執(zhí)行用戶代碼,權(quán)限較低;當(dāng)用戶進(jìn)程通過(guò)系統(tǒng)調(diào)用執(zhí)行內(nèi)核代碼時(shí),進(jìn)程就暫時(shí)進(jìn)入了內(nèi)核運(yùn)行態(tài)(內(nèi)核態(tài)),此時(shí)處理器權(quán)限***,可以執(zhí)行特權(quán)指令。

1.2.4 內(nèi)核模塊/驅(qū)動(dòng)

前面說(shuō)了用戶空間可以通過(guò)系統(tǒng)調(diào)用訪問(wèn)內(nèi)核空間,那用戶空間之間(進(jìn)程間)怎么通信呢?傳統(tǒng)的IPC機(jī)制都是通過(guò)內(nèi)核來(lái)支持的,Binder也一樣,有一個(gè)運(yùn)行在內(nèi)核中的Binder驅(qū)動(dòng)程序負(fù)責(zé)進(jìn)程之間Binder的通信。

驅(qū)動(dòng)程序一般指的是設(shè)備驅(qū)動(dòng)程序(Device Driver),是一種可以使計(jì)算機(jī)和設(shè)備通信的特殊程序。相當(dāng)于硬件的接口,操作系統(tǒng)只有通過(guò)這個(gè)接口。

Binder驅(qū)動(dòng)是一種虛擬的字符設(shè)備,注冊(cè)在/dev/binder中,其定義了一套Binder通信協(xié)議,負(fù)責(zé)建立進(jìn)程間的Binder通信,提供了數(shù)據(jù)包在進(jìn)程之間傳遞的一系列底層支持。應(yīng)用進(jìn)程訪問(wèn)Binder驅(qū)動(dòng)也是通過(guò)系統(tǒng)調(diào)用實(shí)現(xiàn)的。

1.3 傳統(tǒng)IPC機(jī)制的通信原理

了解了上面的基礎(chǔ)知識(shí)后,我們來(lái)看看傳統(tǒng)IPC機(jī)制是如何實(shí)現(xiàn),通常是下面兩個(gè)步驟(共享內(nèi)存機(jī)制除外):

  1. 發(fā)送方進(jìn)程通過(guò)系統(tǒng)調(diào)用(copy_from_user)將要發(fā)送的數(shù)據(jù)存拷貝到內(nèi)核緩存區(qū)中。
  2. 接收方開(kāi)辟一段內(nèi)存空間,內(nèi)核通過(guò)系統(tǒng)調(diào)用(copy_to_user)將內(nèi)核緩存區(qū)中的數(shù)據(jù)拷貝到接收方的內(nèi)存緩存區(qū)。

關(guān)于Binder,作為應(yīng)用開(kāi)發(fā)者你需要知道的全部

這種傳統(tǒng)IPC機(jī)制存在2個(gè)問(wèn)題:

  1. 需要進(jìn)行2次數(shù)據(jù)拷貝,第1次是從發(fā)送方用戶空間拷貝到內(nèi)核緩存區(qū),第2次是從內(nèi)核緩存區(qū)拷貝到接收方用戶空間。
  2. 接收方進(jìn)程不知道事先要分配多大的空間來(lái)接收數(shù)據(jù),可能存在空間上的浪費(fèi)。

2、Binder的基本原理

2.1 Binder底層原理

傳統(tǒng)IPC機(jī)制需要拷貝2次內(nèi)存,Binder是如何只用1次內(nèi)存拷貝就實(shí)現(xiàn)進(jìn)程間通信的呢?前面我們已經(jīng)了解到,Linux是使用的是虛擬內(nèi)存尋址方式,用戶空間的虛擬內(nèi)存地址是映射到物理內(nèi)存中的,對(duì)虛擬內(nèi)存的讀寫(xiě)實(shí)際上是對(duì)物理內(nèi)存的讀寫(xiě),這個(gè)過(guò)程就是內(nèi)存映射,這個(gè)內(nèi)存映射過(guò)程是通過(guò)系統(tǒng)調(diào)用mmap()來(lái)實(shí)現(xiàn)的。

Binder借助了內(nèi)存映射的方法,在內(nèi)核空間和接收方用戶空間的數(shù)據(jù)緩存區(qū)之間做了一層內(nèi)存映射。這樣一來(lái),從發(fā)送方用戶空間拷貝到內(nèi)核空間緩存區(qū)的數(shù)據(jù),就相當(dāng)于直接拷貝到了接收方用戶空間的數(shù)據(jù)緩存區(qū),從而減少了一次數(shù)據(jù)拷貝。

關(guān)于Binder,作為應(yīng)用開(kāi)發(fā)者你需要知道的全部

2.2 Binder通信模型

Binder是基于C/S架構(gòu)的,對(duì)于通信雙方來(lái)說(shuō),發(fā)起請(qǐng)求的進(jìn)程屬于Client,接收請(qǐng)求的進(jìn)程屬于Server,由于存在進(jìn)程隔離,雙方不能直接通信,Binder是如何實(shí)現(xiàn)的呢?

寫(xiě)給 Android 應(yīng)用工程師的 Binder 原理剖析中舉的網(wǎng)絡(luò)通信例子很貼切,Binder的通信過(guò)程與網(wǎng)絡(luò)請(qǐng)求類(lèi)似,網(wǎng)絡(luò)通信過(guò)程可以簡(jiǎn)化為4個(gè)角色:Client、Server、DNS服務(wù)器和路由器。一次完整的網(wǎng)絡(luò)通信大體過(guò)程如下:

a、Client輸入Server的域名

b、DNS解析域名

通過(guò)域名是無(wú)法直接找到相應(yīng)Server的,必須先通過(guò)DNS服務(wù)器將Server的域名轉(zhuǎn)化為具體的IP地址。

c、通過(guò)路由器將請(qǐng)求發(fā)送至Server

Client通過(guò)DNS服務(wù)器解析到Server的IP地址后,也還不能直接向Server發(fā)起請(qǐng)求,需要經(jīng)過(guò)路由器的層層中轉(zhuǎn)才還到達(dá)Server。

d、Server返回?cái)?shù)據(jù)

Server接收到請(qǐng)求并處理后,再通過(guò)路由器將數(shù)據(jù)返回給Client。

在Binder機(jī)制中,也定義了4個(gè)角色:Client、Server、Binder驅(qū)動(dòng)和ServiceManager。

Binder驅(qū)動(dòng):類(lèi)似網(wǎng)絡(luò)通信中的路由器,負(fù)責(zé)將Client的請(qǐng)求轉(zhuǎn)發(fā)到具體的Server中執(zhí)行,并將Server返回的數(shù)據(jù)傳回給Client。

ServiceManager:類(lèi)似網(wǎng)絡(luò)通信中的DNS服務(wù)器,負(fù)責(zé)將Client請(qǐng)求的Binder描述符轉(zhuǎn)化為具體的Server地址,以便Binder驅(qū)動(dòng)能夠轉(zhuǎn)發(fā)給具體的Server。Server如需提供Binder服務(wù),需要向ServiceManager注冊(cè)。

關(guān)于Binder,作為應(yīng)用開(kāi)發(fā)者你需要知道的全部

具體的通信過(guò)程是這樣的:

a、Server向ServiceManager注冊(cè)

Server通過(guò)Binder驅(qū)動(dòng)向ServiceManager注冊(cè),聲明可以對(duì)外提供服務(wù)。ServiceManager中會(huì)保留一份映射表:名字為zhangsan的Server對(duì)應(yīng)的Binder引用是0x12345。

b、Client向ServiceManager請(qǐng)求Server的Binder引用

Client想要請(qǐng)求Server的數(shù)據(jù)時(shí),需要先通過(guò)Binder驅(qū)動(dòng)向ServiceManager請(qǐng)求Server的Binder引用:我要向名字為zhangsan的Server通信,請(qǐng)告訴我Server的Binder引用。

c、向具體的Server發(fā)送請(qǐng)求

Client拿到這個(gè)Binder引用后,就可以通過(guò)Binder驅(qū)動(dòng)和Server進(jìn)行通信了。

d、Server返回結(jié)果

Server響應(yīng)請(qǐng)求后,需要再次通過(guò)Binder驅(qū)動(dòng)將結(jié)果返回給Client。

可以看到,Client、Server、ServiceManager之間的通信都是通過(guò)Binder驅(qū)動(dòng)作為橋梁的,可見(jiàn)Binder驅(qū)動(dòng)的重要性。也許你還有一點(diǎn)疑問(wèn),ServiceManager和Binder驅(qū)動(dòng)屬于兩個(gè)不同的進(jìn)程,它們是為Client和Server之間的進(jìn)程間通信服務(wù)的,也就是說(shuō)Client和Server之間的進(jìn)程間通信依賴(lài)ServiceManager和Binder驅(qū)動(dòng)之間的進(jìn)程間通信,這就像是:“蛋生雞,雞生蛋,但***個(gè)蛋得通過(guò)一只雞孵出來(lái)”。Binder機(jī)制是如何創(chuàng)造***只下蛋的雞呢?

  1. 當(dāng)Android系統(tǒng)啟動(dòng)后,會(huì)創(chuàng)建一個(gè)名稱(chēng)為servicemanager的進(jìn)程,這個(gè)進(jìn)程通過(guò)一個(gè)約定的命令BINDERSETCONTEXT_MGR向Binder驅(qū)動(dòng)注冊(cè),申請(qǐng)成為為ServiceManager,Binder驅(qū)動(dòng)會(huì)自動(dòng)為ServiceManager創(chuàng)建一個(gè)Binder實(shí)體(***只下蛋的雞);
  2. 并且這個(gè)Binder實(shí)體的引用在所有的Client中都為0,也就說(shuō)各個(gè)Client通過(guò)這個(gè)0號(hào)引用就可以和ServiceManager進(jìn)行通信。Server通過(guò)0號(hào)引用向ServiceManager進(jìn)行注冊(cè),Client通過(guò)0號(hào)引用就可以獲取到要通信的Server的Binder引用。

Android Binder設(shè)計(jì)與實(shí)現(xiàn) - 設(shè)計(jì)篇中對(duì)Client、Server、Binder驅(qū)動(dòng)和ServiceManager有更詳細(xì)的介紹。

2.3 Binder的代理機(jī)制

通過(guò)上面的分析,我們已經(jīng)知道了Binder的基本通信過(guò)程:Client向SerivceManger獲取到Server的Binder引用,Client通過(guò)Binder引用向Server發(fā)起具體請(qǐng)求。Client通過(guò)這個(gè)Binder引用具體是如何調(diào)用Server方法的呢?

關(guān)于Binder,作為應(yīng)用開(kāi)發(fā)者你需要知道的全部

比如一個(gè)Server提供add方法,Client實(shí)際請(qǐng)求add的流程是這樣的:Client先通過(guò)Binder驅(qū)動(dòng)向ServiceManager獲取Server的Binder引用,這個(gè)引用就是一個(gè)Java Object,這個(gè)Object有一個(gè)add方法;Cient拿到這個(gè)Object后就可以直接請(qǐng)求add方法了。

實(shí)際上Client拿到的Object并不是Server真正的Binder實(shí)體,Binder驅(qū)動(dòng)做了一層對(duì)象轉(zhuǎn)換,將這個(gè)Object包裝成了一個(gè)代理對(duì)象ProxyObject,這個(gè)ProxyObject和真正的Binder實(shí)體有相同的方法簽名,Client通過(guò)這個(gè)ProxyObject請(qǐng)求add方法時(shí),Binder驅(qū)動(dòng)會(huì)自動(dòng)將請(qǐng)求轉(zhuǎn)發(fā)到具體的Binder實(shí)體中執(zhí)行,這就是Binder的代理機(jī)制。由于ProxyObject和真正的Binder實(shí)體有相同的方法簽名,其實(shí)Client并不需要關(guān)心是ProxyObject還是真實(shí)的Object。

為了方便描述,下面將Server真正的Binder實(shí)體稱(chēng)為Binder本地對(duì)象;將Client中的Binder引用,即ProxyObject,稱(chēng)之為Binder代理對(duì)象。

2.4 對(duì)Binder概念的重新理解

經(jīng)過(guò)上面的分析,我們已經(jīng)大體清楚了Binder機(jī)制的基本通信原理,現(xiàn)在回過(guò)頭來(lái)重新梳理下對(duì)Binder機(jī)制的認(rèn)識(shí):

總體來(lái)說(shuō),Binder是基于C/S結(jié)構(gòu)的一種面向?qū)ο蟮腎PC機(jī)制。包含:Client、Server、Binder驅(qū)動(dòng)和ServiceManager四大組成部分。各組成部分中的Binder含義都有所有不同:

  • 對(duì)于Client

Binder是Server本地對(duì)象的一個(gè)引用,這個(gè)引用實(shí)際上是一個(gè)代理對(duì)象,Client通過(guò)這個(gè)代理對(duì)象來(lái)間接訪問(wèn)Server的本地對(duì)象;

  • 對(duì)于Server

Binder是提供具體實(shí)現(xiàn)的本地對(duì)象,需向ServiceManager注冊(cè);

  • 對(duì)于Binder驅(qū)動(dòng)

它是連接Client來(lái)Server的橋梁,負(fù)責(zé)將代理對(duì)象轉(zhuǎn)化為本地對(duì)象,并將Server的執(zhí)行結(jié)果返回給Client。

  • 對(duì)于ServiceManager

它保存了Server Binder字符名稱(chēng)和Binder引用的映射,Client通過(guò)它來(lái)找到Server的Binder引用。

Binder驅(qū)動(dòng)中保留了Binder代理對(duì)象和Binder本地對(duì)象的具體結(jié)構(gòu),由于我們只關(guān)心Binder的基本通信機(jī)制,底層實(shí)現(xiàn)不做過(guò)多介紹,想具體了解的同學(xué)可以參考Android Binder設(shè)計(jì)與實(shí)現(xiàn) - 設(shè)計(jì)篇。

3、通過(guò)代碼來(lái)理解Binder

上面的介紹比較抽象,現(xiàn)在我們通過(guò)具體實(shí)例來(lái)理解Binder。

  • 通過(guò)AIDL實(shí)例來(lái)了解Binder的用法
  • 通過(guò)手動(dòng)編碼實(shí)現(xiàn)ActivityManagerService

3.1 通過(guò)AIDL實(shí)例來(lái)了解Binder的用法

實(shí)現(xiàn)Binder通信的最常用方法就是通過(guò)aidl,aidl接口定義了Client和Server進(jìn)行通信的接口,對(duì)aidl不了解的同學(xué)請(qǐng)參考官方文檔Android 接口定義語(yǔ)言 (AIDL)。

3.1.1 與Binder相關(guān)的幾個(gè)類(lèi)的職責(zé)

在具體分析之前,我們需要先了解與Binder相關(guān)的幾個(gè)類(lèi)的職責(zé):

  • IBinder

跨進(jìn)程通信的Base接口,它聲明了跨進(jìn)程通信需要實(shí)現(xiàn)的一系列抽象方法,實(shí)現(xiàn)了這個(gè)接口就說(shuō)明可以進(jìn)行跨進(jìn)程通信,Client和Server都要實(shí)現(xiàn)此接口。

  • IInterface

這也是一個(gè)Base接口,用來(lái)表示Server提供了哪些能力,是Client和Server通信的協(xié)議。

  • Binder

提供Binder服務(wù)的本地對(duì)象的基類(lèi),它實(shí)現(xiàn)了IBinder接口,所有本地對(duì)象都要繼承這個(gè)類(lèi)。

  • BinderProxy

在Binder.java這個(gè)文件中還定義了一個(gè)BinderProxy類(lèi),這個(gè)類(lèi)表示Binder代理對(duì)象它同樣實(shí)現(xiàn)了IBinder接口,不過(guò)它的很多實(shí)現(xiàn)都交由native層處理。Client中拿到的實(shí)際上是這個(gè)代理對(duì)象。

  • Stub

這個(gè)類(lèi)在編譯aidl文件后自動(dòng)生成,它繼承自Binder,表示它是一個(gè)Binder本地對(duì)象;它是一個(gè)抽象類(lèi),實(shí)現(xiàn)了IInterface接口,表明它的子類(lèi)需要實(shí)現(xiàn)Server將要提供的具體能力(即aidl文件中聲明的方法)。

  • Proxy

它實(shí)現(xiàn)了IInterface接口,說(shuō)明它是Binder通信過(guò)程的一部分;它實(shí)現(xiàn)了aidl中聲明的方法,但最終還是交由其中的mRemote成員來(lái)處理,說(shuō)明它是一個(gè)代理對(duì)象,mRemote成員實(shí)際上就是BinderProxy。

3.1.2 AIDL實(shí)例

首先定義一個(gè)aidl文件,這個(gè)接口中聲明了一個(gè)getPid方法:

  1. // IRemoteService.aidl 
  2. package com.rush.demo.aidltest; 
  3.  
  4. interface IRemoteService { 
  5.     int getPid(); 

下面是編譯IRemoteService.aild后生成的java類(lèi):

  1. // IRemoteService.java 
  2. package com.rush.demo.aidltest; 
  3.  
  4. public interface IRemoteService extends android.os.IInterface { 
  5.     public static abstract class Stub extends android.os.Binder implements com.rush.demo.aidltest.IRemoteService { 
  6.         //Binder描述符 
  7.         private static final java.lang.String DESCRIPTOR = "com.rush.demo.aidltest.IRemoteService"
  8.  
  9.         public Stub() { 
  10.             this.attachInterface(this, DESCRIPTOR); 
  11.         } 
  12.  
  13.         public static com.rush.demo.aidltest.IRemoteService asInterface(android.os.IBinder obj) { 
  14.             if ((obj == null)) { 
  15.                 return null
  16.             } 
  17.             android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR); 
  18.             if (((iin != null) && (iin instanceof com.rush.demo.aidltest.IRemoteService))) { 
  19.                 return ((com.rush.demo.aidltest.IRemoteService) iin); 
  20.             } 
  21.             return new com.rush.demo.aidltest.IRemoteService.Stub.Proxy(obj); 
  22.         } 
  23.  
  24.         @Override 
  25.         public android.os.IBinder asBinder() { 
  26.             return this; 
  27.         } 
  28.  
  29.         @Override 
  30.         public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException { 
  31.             switch (code) { 
  32.                 case INTERFACE_TRANSACTION: { 
  33.                     reply.writeString(DESCRIPTOR); 
  34.                     return true
  35.                 } 
  36.                 case TRANSACTION_getPid: { 
  37.                     data.enforceInterface(DESCRIPTOR); 
  38.                     java.lang.String _arg0; 
  39.                     _arg0 = data.readString(); 
  40.                     int _result = this.getPid(_arg0); 
  41.                     reply.writeNoException(); 
  42.                     reply.writeInt(_result); 
  43.                     return true
  44.                 } 
  45.             } 
  46.             return super.onTransact(code, data, reply, flags); 
  47.         } 
  48.  
  49.         private static class Proxy implements com.rush.demo.aidltest.IRemoteService { 
  50.             private android.os.IBinder mRemote; 
  51.  
  52.             Proxy(android.os.IBinder remote) { 
  53.                 mRemote = remote; 
  54.             } 
  55.  
  56.             @Override 
  57.             public android.os.IBinder asBinder() { 
  58.                 return mRemote; 
  59.             } 
  60.  
  61.             public java.lang.String getInterfaceDescriptor() { 
  62.                 return DESCRIPTOR; 
  63.             } 
  64.  
  65.             @Override 
  66.             public int getPid(java.lang.String name) throws android.os.RemoteException { 
  67.                 android.os.Parcel _data = android.os.Parcel.obtain(); 
  68.                 android.os.Parcel _reply = android.os.Parcel.obtain(); 
  69.                 int _result; 
  70.                 try { 
  71.                     _data.writeInterfaceToken(DESCRIPTOR); 
  72.                     _data.writeString(name); 
  73.                     mRemote.transact(Stub.TRANSACTION_getPid, _data, _reply, 0); 
  74.                     _reply.readException(); 
  75.                     _result = _reply.readInt(); 
  76.                 } finally { 
  77.                     _reply.recycle(); 
  78.                     _data.recycle(); 
  79.                 } 
  80.                 return _result; 
  81.             } 
  82.  
  83.         static final int TRANSACTION_getPid = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0); 
  84.     } 
  85.  
  86.     public int getPid(java.lang.String name) throws android.os.RemoteException; 

這個(gè)文件中有3個(gè)類(lèi):

a、IRemoteService

繼承至IInterface接口,聲明了IRemoteService.aidl中聲明的getPid方法,它是Client和Service通信的接口。

b、IRemoteService.Stub

IRemoteService的靜態(tài)抽象內(nèi)部類(lèi),繼承自Binder,其子類(lèi)需要實(shí)現(xiàn)IRemoteService接口,表明它是Server的Binder本地對(duì)象,需要實(shí)現(xiàn)getPid接口。

c、IRemoteService.Stub.Proxy

IRemoteService.Stub的靜態(tài)內(nèi)部類(lèi),它并沒(méi)有繼承自Binder,而是包含了一個(gè)IBinder對(duì)象,這個(gè)對(duì)象其實(shí)是BinderProxy,說(shuō)明它是Server在Client中的本地代理對(duì)象。Proxy實(shí)現(xiàn)了getPid接口,將參數(shù)序列化后交由mRemote(BinderProxy)處理,實(shí)際上就是交給Binder驅(qū)動(dòng)來(lái)完成與遠(yuǎn)程Stub的通信。

先來(lái)看Stub中的asInterface方法,這個(gè)方法通常是Client在bindService成功后,由Client來(lái)調(diào)用的,作用是將綁定成功后返回的IBinder對(duì)象轉(zhuǎn)換為具體的IInterface接口,Client拿到這個(gè)IInterface接口后就可以和自由的調(diào)用Server提供的方法了。

  1. public static com.rush.demo.aidltest.IRemoteService asInterface(android.os.IBinder obj) { 
  2.     if ((obj == null)) { 
  3.         return null
  4.     } 
  5.     android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR); 
  6.     if (((iin != null) && (iin instanceof com.rush.demo.aidltest.IRemoteService))) { 
  7.         return ((com.rush.demo.aidltest.IRemoteService) iin); 
  8.     } 
  9.     return new com.rush.demo.aidltest.IRemoteService.Stub.Proxy(obj); 

asInterface方法中既可能返回Stub本身的IRemoteService對(duì)象,也可能創(chuàng)建一個(gè)Proxy對(duì)象,這是為什么呢?因?yàn)锽inder雖然是跨進(jìn)程通信機(jī)制,但也可以為本進(jìn)程服務(wù),也就是說(shuō)Client和Server可能在同一個(gè)進(jìn)程,在同一個(gè)進(jìn)程就沒(méi)必要通過(guò)Binder驅(qū)動(dòng)來(lái)中轉(zhuǎn)了,直接訪問(wèn)就可以了;如果Client和Server在不同的進(jìn)程,就需要通過(guò)Binder代理對(duì)象來(lái)中轉(zhuǎn)。也就是說(shuō):

  1. Client和Server在同一個(gè)進(jìn)程,obj是Binder本地對(duì)象(Stub的子類(lèi)),asInterface方法返回的就是Binder本地對(duì)象;
  2. Client和Server在不同的進(jìn)程,obj實(shí)際上是Binder代理對(duì)象,asInterface返回一個(gè)Proxy對(duì)象。
  1. //Binder.java 
  2. /** 
  3.  * obj.queryLocalInterface是怎樣去查找是否有本地的IInterface呢,從Binder的代碼中可以看到,只是簡(jiǎn)單的比較Binder的描述符和要查找的描述符是否匹配,匹配的話直接返回mOwner,這個(gè)mOwner就是Stub構(gòu)造方法中調(diào)用attachInterface方法傳入的this參數(shù)。 
  4.  */ 
  5. public IInterface queryLocalInterface(String descriptor) { 
  6.     if (mDescriptor.equals(descriptor)) { 
  7.         return mOwner; 
  8.     } 
  9.     return null
  10.  
  11. final class BinderProxy implements IBinder { 
  12.     public IInterface queryLocalInterface(String descriptor) { 
  13.         return null
  14.     } 
  15.  
  16. public static abstract class Stub extends android.os.Binder implements com.rush.demo.aidltest.IRemoteService { 
  17.     // Binder描述符,值為接口類(lèi)名全稱(chēng) 
  18.     private static final java.lang.String DESCRIPTOR = "com.rush.demo.aidltest.IRemoteService"
  19.  
  20.     public Stub() { 
  21.         //向Binder中綁定owner和descriptor 
  22.         this.attachInterface(this, DESCRIPTOR); 
  23.     } 

obj.queryLocalInterface是怎樣去查找是否有本地的IInterface呢,從Binder的代碼中可以看到,只是簡(jiǎn)單的比較Binder的描述符和要查找的描述符是否匹配,匹配的話直接返回mOwner,這個(gè)mOwner就是Stub構(gòu)造方法中調(diào)用attachInterface方法傳入的this參數(shù)。而B(niǎo)inderProxy的queryLocalInterface方法直接返回null。

Client中通過(guò)Binder調(diào)用Server方法有兩種場(chǎng)景:

1、Client和Server在同一個(gè)進(jìn)程

Stub.asInterface方法返回的是Stub對(duì)象,即Binder本地對(duì)象。也就是說(shuō)和Binder跨進(jìn)程通信無(wú)關(guān),直接調(diào)用即可,此時(shí)Client調(diào)用方和Server響應(yīng)方在同一個(gè)線程中。

2、Client和Server在不同的進(jìn)程

Stub.asInterface方法返回的是Binder代理對(duì)象,需要通過(guò)Binder驅(qū)動(dòng)完成跨進(jìn)程通信。這種場(chǎng)景下,Client調(diào)用方線程會(huì)被掛起(Binder也提供了異步的方式,這里不討論),等待Server響應(yīng)后返回?cái)?shù)據(jù)。這里要注意的是,Server的響應(yīng)是在Server進(jìn)程的Binder線程池中處理的,并不是主線程。

接下來(lái)分析跨進(jìn)程場(chǎng)景下,Client調(diào)用getPid方法的具體流程:

1、Client調(diào)用Binder代理對(duì)象,Client線程掛起

Client中拿到的IRemoteService引用實(shí)際上是Proxy,調(diào)用getPid方法實(shí)際上是調(diào)用Proxy的getPid方法,這個(gè)方法只是將參數(shù)序列化后,調(diào)用了mRemote成員的transact方法。Stub類(lèi)中為IRemoteService中的每個(gè)方法定義了方法編號(hào),transact方法中傳入getPid方法的編號(hào)。此時(shí)Client調(diào)用方線程掛起,等待Server響應(yīng)數(shù)據(jù)。

  1. // Stub.Proxy 
  2. public int getPid(java.lang.String name) throws android.os.RemoteException { 
  3.     ... 
  4.     _data.writeInterfaceToken(DESCRIPTOR); 
  5.     _data.writeString(name); 
  6.     mRemote.transact(Stub.TRANSACTION_getPid, _data, _reply, 0); 
  7.     _reply.readException(); 
  8.     _result = _reply.readInt(); 
  9.     ... 
  10.     return _result; 

2、Binder代理對(duì)象將請(qǐng)求派發(fā)給Binder驅(qū)動(dòng)

Proxy中的mRemote成員實(shí)際上是BinderProxy,而B(niǎo)inderProxy中的transact方法最終調(diào)用于transactNative方法,也就是說(shuō)Client的請(qǐng)求派發(fā)給了Binder驅(qū)動(dòng)來(lái)處理。

3、Binder驅(qū)動(dòng)將請(qǐng)求派發(fā)給Server

Binder驅(qū)動(dòng)經(jīng)過(guò)一系列的處理后,將請(qǐng)求派發(fā)給了Server,即調(diào)用Server本地Binder對(duì)象(Stub)的onTransact方法最終在此方法中完成getPid方法的具體調(diào)用。在onTransact方法中,根據(jù)Proxy中調(diào)用transact時(shí)傳入的方法編號(hào)來(lái)區(qū)別具體要處理的方法。

  1. // Stub 
  2. public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException { 
  3.     switch (code) { 
  4.         ... 
  5.         case TRANSACTION_getPid: { 
  6.             data.enforceInterface(DESCRIPTOR); 
  7.             //獲取方法參數(shù) 
  8.             java.lang.String _arg0 = data.readString(); 
  9.             //調(diào)用getPid方法,這個(gè)方法在Stub的子類(lèi),即Server中實(shí)現(xiàn) 
  10.             int _result = this.getPid(_arg0); 
  11.             reply.writeNoException(); 
  12.             reply.writeInt(_result); 
  13.             return true
  14.         } 
  15.     } 
  16.     return super.onTransact(code, data, reply, flags); 

4、喚醒Client線程,返回結(jié)果

onTransact處理結(jié)束后,將結(jié)果寫(xiě)入reply并返回至Binder驅(qū)動(dòng),驅(qū)動(dòng)喚醒掛起的Client線程,并將結(jié)果返回。至此,一次跨進(jìn)程通信完成。

3.2 手動(dòng)編碼來(lái)實(shí)現(xiàn)ActivityManagerService

通過(guò)前面的示例我們已經(jīng)知道,aidl文件只是用來(lái)定義C/S交互的接口,Android在編譯時(shí)會(huì)自動(dòng)生成相應(yīng)的Java類(lèi),生成的類(lèi)中包含了Stub和Proxy靜態(tài)內(nèi)部類(lèi),用來(lái)封裝數(shù)據(jù)轉(zhuǎn)換的過(guò)程,實(shí)際使用時(shí)只關(guān)心具體的Java接口類(lèi)即可。為什么Stub和Proxy是靜態(tài)內(nèi)部類(lèi)呢?這其實(shí)只是為了將三個(gè)類(lèi)放在一個(gè)文件中,提高代碼的聚合性。通過(guò)上面的分析,我們其實(shí)完全可以不通過(guò)aidl,手動(dòng)編碼來(lái)實(shí)現(xiàn)Binder的通信,下面我們通過(guò)編碼來(lái)實(shí)現(xiàn)ActivityManagerService。

首先定義IActivityManager接口:

  1. public interface IActivityManager extends IInterface { 
  2.     //binder描述符 
  3.     String DESCRIPTOR = "android.app.IActivityManager"
  4.     //方法編號(hào) 
  5.     int TRANSACTION_startActivity = IBinder.FIRST_CALL_TRANSACTION + 0; 
  6.     //聲明一個(gè)啟動(dòng)activity的方法,為了簡(jiǎn)化,這里只傳入intent參數(shù) 
  7.     int startActivity(Intent intent) throws RemoteException; 

其次,實(shí)現(xiàn)ActivityManagerService側(cè)的本地Binder對(duì)象基類(lèi):

  1. // 名稱(chēng)隨意,不一致叫Stub 
  2. public abstract class ActivityManagerNative extends Binder implements IActivityManager { 
  3.  
  4.     public static IActivityManager asInterface(IBinder obj) { 
  5.         if (obj == null) { 
  6.             return null
  7.         } 
  8.         IActivityManager in = (IActivityManager) obj.queryLocalInterface(IActivityManager.DESCRIPTOR); 
  9.         if (in != null) { 
  10.             return in
  11.         } 
  12.         //代理對(duì)象,見(jiàn)下面的代碼 
  13.         return new ActivityManagerProxy(obj); 
  14.     } 
  15.  
  16.     @Override 
  17.     public IBinder asBinder() { 
  18.         return this; 
  19.     } 
  20.  
  21.     @Override 
  22.     protected boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException { 
  23.         switch (code) { 
  24.             // 獲取binder描述符 
  25.             case INTERFACE_TRANSACTION: 
  26.                 reply.writeString(IActivityManager.DESCRIPTOR); 
  27.                 return true
  28.             // 啟動(dòng)activity,從data中反序列化出intent參數(shù)后,直接調(diào)用子類(lèi)startActivity方法啟動(dòng)activity。 
  29.             case IActivityManager.TRANSACTION_startActivity: 
  30.                 data.enforceInterface(IActivityManager.DESCRIPTOR); 
  31.                 Intent intent = Intent.CREATOR.createFromParcel(data); 
  32.                 int result = this.startActivity(intent); 
  33.                 reply.writeNoException(); 
  34.                 reply.writeInt(result); 
  35.                 return true
  36.         } 
  37.         return super.onTransact(code, data, reply, flags); 
  38.     } 

再次,實(shí)現(xiàn)Client側(cè)的代理對(duì)象:

  1. public class ActivityManagerProxy implements IActivityManager { 
  2.     private IBinder mRemote; 
  3.  
  4.     public ActivityManagerProxy(IBinder remote) { 
  5.         mRemote = remote; 
  6.     } 
  7.  
  8.     @Override 
  9.     public IBinder asBinder() { 
  10.         return mRemote; 
  11.     } 
  12.  
  13.     @Override 
  14.     public int startActivity(Intent intent) throws RemoteException { 
  15.         Parcel data = Parcel.obtain(); 
  16.         Parcel reply = Parcel.obtain(); 
  17.         int result; 
  18.         try { 
  19.             // 將intent參數(shù)序列化,寫(xiě)入data中 
  20.             intent.writeToParcel(data, 0); 
  21.             // 調(diào)用BinderProxy對(duì)象的transact方法,交由Binder驅(qū)動(dòng)處理。 
  22.             mRemote.transact(IActivityManager.TRANSACTION_startActivity, data, reply, 0); 
  23.             reply.readException(); 
  24.             // 等待server執(zhí)行結(jié)束后,讀取執(zhí)行結(jié)果 
  25.             result = reply.readInt(); 
  26.         } finally { 
  27.             data.recycle(); 
  28.             reply.recycle(); 
  29.         } 
  30.         return result; 
  31.     } 

***,實(shí)現(xiàn)Binder本地對(duì)象(IActivityManager接口):

  1. public class ActivityManagerService extends ActivityManagerNative { 
  2.     @Override 
  3.     public int startActivity(Intent intent) throws RemoteException { 
  4.         // 啟動(dòng)activity 
  5.         return 0; 
  6.     } 

簡(jiǎn)化版的ActivityManagerService到這里就已經(jīng)實(shí)現(xiàn)了,剩下就是Client需要獲取到AMS的代理對(duì)象IActivityManager就可以通信了。實(shí)際開(kāi)發(fā)過(guò)程中通過(guò)aidl文件能夠自動(dòng)編譯出中間代碼,并不需要我們手動(dòng)去實(shí)現(xiàn),不過(guò)手動(dòng)編碼能夠加深對(duì)Binder機(jī)制的理解。在開(kāi)發(fā)過(guò)程中我們也并不會(huì)直接使用到AMS,但了解AMS實(shí)現(xiàn)原理對(duì)熟悉Framework來(lái)說(shuō)必不可少,關(guān)于AMS具體實(shí)現(xiàn)原理,我會(huì)在后續(xù)的文章中分析。

至此,Binder機(jī)制的基本通信過(guò)程就介紹完了,由于Binder機(jī)制太過(guò)復(fù)雜,本人水平有限,文中難免出現(xiàn)錯(cuò)誤或不足之處,歡迎大家指正。

責(zé)任編輯:未麗燕 來(lái)源: 簡(jiǎn)書(shū)
相關(guān)推薦

2021-12-24 11:24:59

React HackReact JavaScript

2013-06-28 14:19:20

2010-07-30 16:27:06

Flex開(kāi)發(fā)

2010-03-01 10:20:27

Flex

2014-07-17 09:31:50

iOS8SDK

2011-05-26 11:13:36

Flex

2014-07-31 17:13:50

編碼程序員

2023-01-30 11:43:04

開(kāi)源代碼

2023-06-05 16:50:06

開(kāi)發(fā)TypeScriptJavaScript

2015-08-21 09:47:02

ios9sdk新特性

2016-02-22 15:09:19

Android項(xiàng)目管理技巧

2017-06-09 13:33:57

2025-02-25 08:30:00

前端開(kāi)發(fā)VSCode

2017-03-28 15:47:17

數(shù)據(jù)治理數(shù)據(jù)庫(kù)

2018-05-16 09:41:13

神經(jīng)網(wǎng)絡(luò)NN函數(shù)

2015-11-09 10:50:42

2023-02-10 08:44:05

KafkaLinkedIn模式

2015-06-30 10:59:22

MobileWeb適配

2024-04-26 13:36:01

2013-04-26 09:38:13

go
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)

主站蜘蛛池模板: 日韩中文字幕在线观看 | 99久久精品免费 | 人成在线视频 | 亚洲 欧美 日韩在线 | 成人国产精品一级毛片视频毛片 | 国产在线1 | 久久精彩视频 | 中文字幕第一页在线 | 中文字幕视频在线看5 | 成人免费大片黄在线播放 | 最新中文字幕在线 | 二区视频 | 欧美在线高清 | 久久久精品网站 | 伊人焦久影院 | 亚洲每日更新 | 精品在线一区 | 精品久久久久香蕉网 | 亚洲精品一区二区三区蜜桃久 | 久久一区二区免费视频 | 久久毛片 | 成人在线视频一区二区三区 | 国产精品精品视频一区二区三区 | 四虎影院一区二区 | 国产香蕉视频在线播放 | 国产成在线观看免费视频 | 亚洲天堂日韩精品 | 亚洲国产成人精品女人久久久 | 国产日韩欧美中文字幕 | 一区二区免费高清视频 | 有码在线 | 黄色大片视频 | 免费在线精品视频 | 色天堂视频 | 成人特级毛片 | 精品99爱视频在线观看 | 天天拍天天操 | 日本精品久久久久久久 | 99国产精品99久久久久久 | 91精品国产一区二区三区 | 蜜臀久久|