Android Binder實(shí)現(xiàn)淺析-Binder驅(qū)動(dòng)

簡(jiǎn)介

Android是如何實(shí)現(xiàn)跨進(jìn)程通信的,大家熟悉的Binder是什么,怎么設(shè)計(jì)的,進(jìn)程間的數(shù)據(jù)如何發(fā)送接收的。本文將以及解析,并對(duì)Binder驅(qū)動(dòng)實(shí)現(xiàn)、Native層實(shí)現(xiàn)、Java層實(shí)現(xiàn)三塊做一個(gè)總結(jié)分析。

Binder學(xué)習(xí)思路

  1. Binder與傳統(tǒng)IPC的區(qū)別
  2. Binder驅(qū)動(dòng)的內(nèi)部設(shè)計(jì)、數(shù)據(jù)結(jié)構(gòu)
  3. Binder驅(qū)動(dòng)與應(yīng)用程序進(jìn)程(C/S)之間的通信過程
  4. Android應(yīng)用程序通過Binder驅(qū)動(dòng)進(jìn)行通信的流程
  5. Android開發(fā)人員如何使用Binder通信(AIDL、Java層架構(gòu))

基礎(chǔ)知識(shí)理解

  1. Unix內(nèi)核和應(yīng)用程序進(jìn)程所使用的物理內(nèi)存是分開的,內(nèi)核使用1G的物理內(nèi)存,其他應(yīng)用程序有各自的3G物理內(nèi)存(32位操作系統(tǒng))
  2. 因?yàn)閮?nèi)核和應(yīng)用程序的物理內(nèi)存是分開的,所以兩者之間傳遞數(shù)據(jù)需要進(jìn)行數(shù)據(jù)拷貝
  3. 內(nèi)存映射(mmap)可以將兩個(gè)虛擬內(nèi)存地址空間(不同進(jìn)程)映射到同一物理內(nèi)存段上。實(shí)現(xiàn)多進(jìn)程(或者內(nèi)核與進(jìn)程)之間公用一塊內(nèi)存,減少數(shù)據(jù)拷貝次數(shù)
  4. Unix驅(qū)動(dòng)程序是一個(gè)運(yùn)行在內(nèi)核態(tài)(使用內(nèi)核對(duì)應(yīng)的物理內(nèi)存)的程序
  5. Binder也是一種IPC的實(shí)現(xiàn)方式,其與傳統(tǒng)的Unix IPC有一定的差別(使用了mmap)

理解Binder驅(qū)動(dòng)的存在

因?yàn)橐獙?shí)現(xiàn)跨進(jìn)程通信,那么,數(shù)據(jù)是如何傳輸?shù)?,怎么組織的。兩個(gè)進(jìn)程之間是如何知道對(duì)方的標(biāo)識(shí)(引用)的,這一系列問題,都由Binder驅(qū)動(dòng)解決,每個(gè)進(jìn)程需要為其他進(jìn)程提供服務(wù)(API調(diào)用),都需要向Binder驅(qū)動(dòng)注冊(cè),其他進(jìn)程才能知道自己的數(shù)據(jù)傳向哪里。這里大家先忽略ServiceManager的特殊身份。只討論Binder驅(qū)動(dòng)的覺得定位即可。

這樣看來,其實(shí)Binder驅(qū)動(dòng)就是一個(gè)多個(gè)進(jìn)程之間的中樞神經(jīng),支撐起了Android中進(jìn)程間通信,它內(nèi)部的設(shè)計(jì),與應(yīng)用程序進(jìn)程中的業(yè)務(wù),不存在任何耦合關(guān)系,只負(fù)責(zé)實(shí)現(xiàn)進(jìn)程間數(shù)據(jù)通信??梢杂萌缦聢D來理解Binder驅(qū)動(dòng)與應(yīng)用程序進(jìn)程之間的關(guān)系。

image.png

當(dāng)然,Android里的Binder架構(gòu)應(yīng)該還有ServiceManager這個(gè)系統(tǒng)服務(wù)。

ServiceManager的存在

ServiceManager下文簡(jiǎn)稱SM,是一個(gè)Android操作系統(tǒng)提供的一個(gè)系統(tǒng)進(jìn)程。那么為什么要單獨(dú)提他呢,因?yàn)檫@個(gè)進(jìn)程里,記錄了所有Binder實(shí)體(提供服務(wù)的Binder實(shí)現(xiàn)對(duì)象)的信息。

也就是說,SM是用來給應(yīng)用程序查找其他應(yīng)用程序的數(shù)據(jù)中心與校驗(yàn)中心,保障進(jìn)程間通信的安全新,合法性。

SM是系統(tǒng)服務(wù),在系統(tǒng)啟動(dòng)后,SM便啟動(dòng),并執(zhí)行以下事情:

  1. 打開Binder驅(qū)動(dòng)
  2. 將自己注冊(cè)為Binder驅(qū)動(dòng)的大管家(其他進(jìn)程根據(jù)引用編號(hào)0可以找到SM對(duì)應(yīng)的Binder實(shí)體)
  3. 進(jìn)入循環(huán),不斷從Binder驅(qū)動(dòng)中讀取消息(無消息被阻塞)
  4. 讀取到消息之后處理消息
  5. 不斷循環(huán),永不退出

SM處理的消息類型有:

  1. 注冊(cè)Binder實(shí)體對(duì)象的
  2. 查詢Binder實(shí)體對(duì)象,以引用編號(hào)的形式放回給查詢進(jìn)程

注冊(cè)Binder實(shí)體信息到SM的時(shí)候,請(qǐng)求數(shù)據(jù)中需要寫到Binder實(shí)體的描述信息,之后進(jìn)行查詢的時(shí)候就是根據(jù)描述信息來獲取到對(duì)應(yīng)的Binder應(yīng)用編號(hào)。

到這里,我們可以看出,其實(shí)整個(gè)Binder架構(gòu)就是一個(gè)Client,Server,DNS的結(jié)構(gòu),當(dāng)然Binder驅(qū)動(dòng)就扮演了一個(gè)路由器的角色。

這個(gè)結(jié)構(gòu)的前提,就是DNS需要提前注冊(cè)。也就是說SM進(jìn)程需要第一個(gè)注冊(cè)到Binder驅(qū)動(dòng)中,而且,Client和Server都知道SM的引用編號(hào)(0),能夠直接通過SM獲取其他進(jìn)程提供的Binder引用編號(hào)

Binder驅(qū)動(dòng)啟動(dòng)過程

打開

  1. 每個(gè)需要通過Binder通信的進(jìn)程都需要打開/dev/binder驅(qū)動(dòng)一次(至多一次)
  2. 打開Binder驅(qū)動(dòng)之后,內(nèi)核會(huì)調(diào)用驅(qū)動(dòng)程序的binder_open方法,該方法內(nèi)部將會(huì)創(chuàng)建binder_proc結(jié)構(gòu)體,內(nèi)存存儲(chǔ)了進(jìn)程信息以及UID信息。

內(nèi)存映射

  1. 使用mmap對(duì)/dev/binder進(jìn)行內(nèi)存映射操作
  2. 在mmap調(diào)用之后,內(nèi)核會(huì)會(huì)調(diào)用驅(qū)動(dòng)程序的binder_mmap方法,該方法內(nèi)部會(huì)為進(jìn)程創(chuàng)建binder_buffer結(jié)構(gòu)體,也就是為進(jìn)程創(chuàng)建緩沖區(qū),用于接收數(shù)據(jù)。并且這塊內(nèi)和緩沖區(qū)對(duì)應(yīng)有兩個(gè)虛擬內(nèi)存地址區(qū)間,一個(gè)是內(nèi)核的虛擬空間,一個(gè)是進(jìn)程用戶空間的虛擬空間。此塊緩沖區(qū)是一個(gè)只讀的區(qū)域,防止用戶空間對(duì)其進(jìn)行修改。

動(dòng)作執(zhí)行者

對(duì)于應(yīng)用程序進(jìn)程來說,打開驅(qū)動(dòng)和內(nèi)存映射動(dòng)作由Native類ProcessState完成,該類為單利,在構(gòu)造方法中進(jìn)行,先打開,再執(zhí)行內(nèi)存映射。

Binder與共享內(nèi)存之間的區(qū)別

為什么與共享內(nèi)存進(jìn)行對(duì)比(性能),是因?yàn)楣蚕韮?nèi)存管是unix中最快的一種IPC機(jī)制。

共享內(nèi)存為什么快,是因?yàn)楣蚕韮?nèi)存相當(dāng)于是將兩個(gè)進(jìn)程的虛擬地址空間指向了一塊物理內(nèi)存,兩個(gè)進(jìn)程對(duì)該內(nèi)存區(qū)域的修改,能夠直接反應(yīng)到對(duì)方進(jìn)程中,也就是不需要對(duì)數(shù)據(jù)進(jìn)行拷貝。

image.png

前面說到,Binder是通過mmap來實(shí)現(xiàn)的,理論上,mmap也可以讓兩個(gè)進(jìn)程映射到同一段物理內(nèi)存區(qū)域(文件)上。但是Binder沒有這樣實(shí)現(xiàn),如果這樣的話,和共享內(nèi)存就一樣了。那Binder又是如何實(shí)現(xiàn)的呢。

首先,Binder有驅(qū)動(dòng)程序,所有數(shù)據(jù)傳輸和接收,都是通過Binder驅(qū)動(dòng)來操作的。這就帶來一個(gè)問題,Binder驅(qū)動(dòng)是運(yùn)行在內(nèi)核態(tài)的,那么數(shù)據(jù)在使用Binder驅(qū)動(dòng)傳輸時(shí),是需要在內(nèi)核內(nèi)存空間與用戶內(nèi)存空間進(jìn)行拷貝操作的。

試想下,A進(jìn)程與B進(jìn)程進(jìn)行通信,A進(jìn)程給B進(jìn)程發(fā)送數(shù)據(jù)data,按照上面的分析,數(shù)據(jù)data需要先從A進(jìn)程的用戶空間拷貝到Binder驅(qū)動(dòng)的內(nèi)核空間,再通過Binder驅(qū)動(dòng)寫入到(具體實(shí)現(xiàn)后面說)B進(jìn)程的Binder驅(qū)動(dòng)內(nèi)核空間,最后從Binder驅(qū)動(dòng)再拷貝的B進(jìn)程的用戶空間。如此一來,數(shù)據(jù)進(jìn)行了兩次拷貝。

其實(shí),Binder驅(qū)動(dòng)內(nèi)部并不需要兩次數(shù)據(jù)的拷貝,原因在于Binder將內(nèi)核內(nèi)存空間與用戶內(nèi)存空間進(jìn)行了內(nèi)存映射操作,具體如下圖

image.png

首先,我們從數(shù)據(jù)接收進(jìn)程看,內(nèi)核與用戶內(nèi)存空間,通過mmap映射到了同一塊物理內(nèi)存上。也就是說對(duì)該塊物理內(nèi)存的修改,將會(huì)提現(xiàn)到數(shù)據(jù)接收進(jìn)程的用戶空間和內(nèi)核空間。

再看數(shù)據(jù)發(fā)送進(jìn)程,左邊的數(shù)據(jù)發(fā)送進(jìn)程,只是將內(nèi)核的內(nèi)存空間映射到了物理內(nèi)存上。

接著,當(dāng)數(shù)據(jù)發(fā)送進(jìn)程需要向數(shù)據(jù)接收進(jìn)程傳遞數(shù)據(jù)時(shí),數(shù)據(jù)只需要從數(shù)據(jù)發(fā)送進(jìn)程的用戶內(nèi)存空間拷貝到數(shù)據(jù)發(fā)送進(jìn)程的內(nèi)核內(nèi)存空間,此時(shí),因?yàn)閿?shù)據(jù)發(fā)送進(jìn)程的內(nèi)核內(nèi)存空間與物理內(nèi)存進(jìn)行了映射,而數(shù)據(jù)接收進(jìn)程的用戶內(nèi)存空間與內(nèi)核內(nèi)存空間同時(shí)都映射到了同一塊物理內(nèi)存上,所以此次拷貝,直接將數(shù)據(jù)發(fā)送進(jìn)程的用戶空間數(shù)據(jù),拷貝到了數(shù)據(jù)接收進(jìn)程的用戶內(nèi)存空間。

通過上面的分析,也就能理解,為什么說Binder傳輸數(shù)據(jù)時(shí)需要拷貝1次數(shù)據(jù),共享內(nèi)存不需要拷貝數(shù)據(jù)

Binder的實(shí)現(xiàn)架構(gòu)

完成對(duì)Binder跨進(jìn)程通信底層IPC實(shí)現(xiàn)分析之后,需要思考,Android如何讓兩個(gè)進(jìn)程建立聯(lián)系(如何找到通信進(jìn)程),那就需要一個(gè)系統(tǒng)進(jìn)程,所有應(yīng)用程序都知道它,并能聯(lián)系到它,從這個(gè)系統(tǒng)進(jìn)程那邊,能夠查找到(通過Service名字符串)需要通訊的進(jìn)程。

最終,Android采用了Client、Server、ServiceManager的實(shí)現(xiàn)架構(gòu),其中Client需要從ServiceManager中找到Server,然后Client與Server之間即可進(jìn)行通信

那么什么進(jìn)程能夠在ServiceManager中注冊(cè)呢,就是在Android操作系統(tǒng)中注冊(cè)過(APP清單文件中的Service)的那部分服務(wù)才能注冊(cè),到這,也就能理解Android為什么采用這種架構(gòu)模式了,在安全上又進(jìn)一步約束。

Binder驅(qū)動(dòng)

首先要知道Binder驅(qū)動(dòng)是運(yùn)行在內(nèi)核態(tài)下,內(nèi)核態(tài)的內(nèi)存是所有進(jìn)程共享的。

任務(wù)一:存儲(chǔ)所有進(jìn)程的Binder信息(引用編號(hào),Server端的虛擬內(nèi)存地址)

任務(wù)二:進(jìn)程間數(shù)據(jù)傳遞

Binder是什么

Binder是什么,需要從多方面解釋,不同環(huán)境中,其代表的是不一樣的東西。

Binder在Server中的表述

Binder在Server中代表的是具體的實(shí)現(xiàn),簡(jiǎn)稱Binder實(shí)體

Binder在Client中的表述

Binder的具體實(shí)現(xiàn)應(yīng)該是在Server進(jìn)程,也就是說Client進(jìn)程是無法拿到該實(shí)現(xiàn)對(duì)象的地址信息的。 那么Binder在Client中代表的僅僅是一個(gè)引用(驅(qū)動(dòng)給的)編號(hào),Client能夠通過該編號(hào)向遠(yuǎn)端Server發(fā)送數(shù)據(jù)。

Binder在驅(qū)動(dòng)中的表述

驅(qū)動(dòng),是Binder架構(gòu)在最核心的一部分,驅(qū)動(dòng)需要做的事情很多

  1. 所有Server端的Binder實(shí)體,需要在驅(qū)動(dòng)中注冊(cè)
  2. Client端獲取Binder時(shí),需要為Client創(chuàng)建Binder引用,并把引用編號(hào)信息記錄在驅(qū)動(dòng)中
  3. 維護(hù)各個(gè)Client中的引用于Binder實(shí)體之間的映射關(guān)系
  4. 通過引用編號(hào)找到對(duì)應(yīng)實(shí)體
  5. 創(chuàng)建Server端的Binder實(shí)體
  6. etc…

Binder實(shí)體(Server端)在驅(qū)動(dòng)中的表述 Binder實(shí)體需要在驅(qū)動(dòng)中進(jìn)行注冊(cè),注冊(cè)時(shí),驅(qū)動(dòng)需要在內(nèi)核中為Binder實(shí)體創(chuàng)建一個(gè)結(jié)構(gòu)體binder_node 該結(jié)構(gòu)體中存儲(chǔ)的主要數(shù)據(jù)為

Server端Binder實(shí)體對(duì)象的內(nèi)存地址

Server端Binder實(shí)體在所有實(shí)體鏈表中的節(jié)點(diǎn)結(jié)構(gòu)體

說明:每個(gè)Server進(jìn)程都對(duì)應(yīng)有一個(gè)鏈表,用來存儲(chǔ)所有的Binder實(shí)體節(jié)點(diǎn),以Binder實(shí)體對(duì)象的內(nèi)存地址為索引進(jìn)行查找。

Binder引用(Client端)在驅(qū)動(dòng)中的表述

Binder引用在驅(qū)動(dòng)中以binder_ref結(jié)構(gòu)體的形式存在。改結(jié)構(gòu)體中存儲(chǔ)的主要數(shù)據(jù)為:

  • Binder實(shí)體在驅(qū)動(dòng)中的結(jié)構(gòu)體引用
  • Binder實(shí)體在驅(qū)動(dòng)中的引用號(hào)(編號(hào))
  • Binder引用在進(jìn)程鏈表中的節(jié)點(diǎn)(以編號(hào)以及實(shí)體地址為索引的兩個(gè)鏈表節(jié)點(diǎn))

說明:每個(gè)Client進(jìn)程都對(duì)應(yīng)有兩個(gè)鏈表,一個(gè)是以Binder實(shí)體在驅(qū)動(dòng)中的結(jié)構(gòu)體地址為索引建立的鏈表,一個(gè)是以Binder實(shí)體在驅(qū)動(dòng)中的引用號(hào)為索引簡(jiǎn)歷的鏈表。

Binder在傳輸數(shù)據(jù)中的表述

雖然Binder實(shí)體和Binder引用都在驅(qū)動(dòng)中有不同的結(jié)構(gòu)體來標(biāo)識(shí),但是Client和Server在于Binder進(jìn)行通信時(shí),并不是通過傳遞這兩個(gè)結(jié)構(gòu)體來代表不同的Binder的,而是通過另一個(gè)統(tǒng)一的結(jié)構(gòu)體flat_binder_object來代表本次通信對(duì)應(yīng)的Binder。

既然使用的是同一個(gè)結(jié)構(gòu)體,那么這個(gè)結(jié)構(gòu)體中應(yīng)該有的內(nèi)容:

  • Binder類型(實(shí)體,引用)
  • Binder實(shí)體的內(nèi)存地址(類型為實(shí)體時(shí)用)
  • Binder應(yīng)用的編號(hào)(類型為引用時(shí)用)

其中Binder類型有以下幾種:

  • BINDER_TYPE_BINDER:表示傳遞的是Binder實(shí)體,并且指向該實(shí)體的引用都是強(qiáng)類型;
  • BINDER_TYPE_WEAK_BINDER:表示傳遞的是Binder實(shí)體,并且指向該實(shí)體的引用都是弱類型;
  • BINDER_TYPE_HANDLE:表示傳遞的是Binder強(qiáng)類型的引用
  • BINDER_TYPE_WEAK_HANDLE:表示傳遞的是Binder弱類型的引用
  • BINDER_TYPE_FD:表示傳遞的是文件形式的Binder

那么flat_binder_object里的內(nèi)容填充方式具體是怎樣的呢,比如Server將Binder傳遞給Client,Server發(fā)送的flat_binder_object,類型應(yīng)該是BINDER_TYPE_BINDER,此時(shí),驅(qū)動(dòng)將會(huì)在內(nèi)核中為Server進(jìn)程創(chuàng)建對(duì)應(yīng)的binder_node結(jié)構(gòu),并且將flat_binder_object中的Binder實(shí)體的內(nèi)存地址保存起來。接著驅(qū)動(dòng)需要在內(nèi)核中為Client進(jìn)程創(chuàng)建一個(gè)binder_ref結(jié)構(gòu),因?yàn)镾erver穿過來的Binder實(shí)體的內(nèi)存地址在Client進(jìn)程是無效的,所以驅(qū)動(dòng)需要為Client進(jìn)程創(chuàng)建一個(gè)Binder對(duì)應(yīng)的引用編號(hào),并將此編號(hào)存入binder_ref結(jié)構(gòu)中。同時(shí),需要將flat_binder_object中的類型改成BINDER_TYPE_HANDLE,以及存儲(chǔ)引用編號(hào)。

當(dāng)Client需要使用Server傳遞過來的Binder的時(shí)候,向驅(qū)動(dòng)傳遞的數(shù)據(jù)包中,就需要用到Binder的引用編號(hào),驅(qū)動(dòng)將會(huì)對(duì)引用編號(hào)進(jìn)行校驗(yàn),這樣就能在安全性上得到保障。

Binder表述總結(jié)

當(dāng)一個(gè)Server進(jìn)程創(chuàng)建了一個(gè)Binder實(shí)體,之后,這個(gè)實(shí)體在各個(gè)環(huán)境中的表述情況為

  1. Server進(jìn)程中的Binder稱為Binder實(shí)體,其應(yīng)該要繼承BBinder類(Native類)
  2. 其在Binder驅(qū)動(dòng)中,以binder_node表述
  3. 當(dāng)Server進(jìn)程的Binder服務(wù)需要被Client進(jìn)程所使用時(shí),Binder驅(qū)動(dòng)會(huì)創(chuàng)建一個(gè)binder_ref結(jié)構(gòu)體,這也就是Server中創(chuàng)建的Binder實(shí)體在Client進(jìn)程中的表述(存儲(chǔ)引用編號(hào))
  4. 在Client的用戶空間中,需要?jiǎng)?chuàng)建一個(gè)Binder代理類,該類繼承BpBinder類,Client進(jìn)程通過該代理類與Server端的Binder實(shí)體進(jìn)行通信
image.png

本文轉(zhuǎn)自 https://juejin.cn/post/7067152170474274853,如有侵權(quán),請(qǐng)聯(lián)系刪除。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容