3.Androidbinder設(shè)計(jì)篇

一. 引言--女?huà)z造人的故事

成都創(chuàng)新互聯(lián)公司-專業(yè)網(wǎng)站定制、快速模板網(wǎng)站建設(shè)、高性價(jià)比德城網(wǎng)站開(kāi)發(fā)、企業(yè)建站全套包干低至880元,成熟完善的模板庫(kù),直接使用。一站式德城網(wǎng)站制作公司更省心,省錢,快速模板網(wǎng)站建設(shè)找我們,業(yè)務(wù)覆蓋德城地區(qū)。費(fèi)用合理售后完善,10多年實(shí)體公司更值得信賴。

在天地混沌之際,上神女?huà)z因?yàn)橛X(jué)得自己太孤單,沒(méi)人跟它一起嗨,決定按照自己的模樣添加一些生物;于是呢,捏泥為人,并賦予了人生育的能力,所以女?huà)z被稱為了人類的母親;

神話故事很美好,解釋了人類的來(lái)源,但是這個(gè)邏輯中其實(shí)有個(gè)缺陷,就是女?huà)z從哪里來(lái)的?

那有些同學(xué)就會(huì)問(wèn)了,這里說(shuō)Binder設(shè)計(jì),為什么要提到女?huà)z造人的故事呢?這是因?yàn)槎咴谠搭^這個(gè)問(wèn)題的處理上有異曲同工之妙,嗯,后面會(huì)再做說(shuō)明。


二. Android Binder簡(jiǎn)介

Andoid Binder從Open Binder發(fā)展而來(lái),提供了跨進(jìn)程通信機(jī)制;其實(shí)linux已經(jīng)提供很多的跨進(jìn)程機(jī)制,比如管道,共享內(nèi)存等等,那為什么google要使用binder呢?

其實(shí),大家也可以思考下,針對(duì)于移動(dòng)設(shè)備這種低配置的設(shè)備(相對(duì)于服務(wù)器),新的進(jìn)程間通信機(jī)制需要具備什么新的優(yōu)點(diǎn)呢?

1.內(nèi)存節(jié)省,因?yàn)橐苿?dòng)設(shè)備的低配置,所以需要新的通信機(jī)制盡可能的節(jié)省資源,binder在跨進(jìn)程數(shù)據(jù)拷貝時(shí)只進(jìn)行一次;

2.高效性,比如對(duì)于手機(jī)這種東西,大家肯定希望它反應(yīng)迅速,界面流暢;

3. 安全性,手機(jī)涉及了大量的用戶隱私,比如支付寶賬號(hào),電話本聯(lián)系人號(hào)碼,短信記錄,通話記錄等等;

在linux系統(tǒng)中對(duì)于權(quán)限安全性管理,UID是一個(gè)很重要的東西,所以對(duì)于安全性,binder就在binder driver里面負(fù)責(zé)填寫調(diào)用進(jìn)程的UID和PID;相比一些在應(yīng)用程序填寫UID和PID的進(jìn)程間通信機(jī)制,安全性得到了極大提高。


總體來(lái)說(shuō),Binder肯定是一個(gè)不錯(cuò)的進(jìn)程間通信機(jī)制,否則android經(jīng)過(guò)這么多年的發(fā)展,如果Binder不是足夠優(yōu)秀的話,以google的技術(shù)實(shí)力,早就被google替換了吧!

三.Binder通信關(guān)系總圖

Binder作為Android里面進(jìn)程間通信機(jī)制,主要有4個(gè)模塊參與這個(gè)過(guò)程,分別是

client

service

ServiceManager

Binder Driver

client和service作為通信的模塊很容易理解,因?yàn)閏lient需要和service通信,所以它們兩個(gè)必然會(huì)成為通信的一部分。

那service manager和Binder driver起的作用是什么呢?

service manager提供service的注冊(cè),查詢等服務(wù),那說(shuō)的再明白一點(diǎn),就是service Binder本地對(duì)象把自己和一個(gè)名字添加到service manager注冊(cè);

這樣,client就可以向service manager通過(guò)指定的名字去查詢之前注冊(cè)的service,從而找到對(duì)應(yīng)的Binder實(shí)體對(duì)象,再繼而生成屬于自己進(jìn)程的Binder 引用對(duì)象。

最后把這個(gè)屬于自己進(jìn)程的Binder引用對(duì)象和自己進(jìn)程內(nèi)的一個(gè)Binder代理對(duì)象對(duì)應(yīng)起來(lái);這樣client就間接的擁有了service Binder本地對(duì)象的引用,進(jìn)而可以和service通信。

那Binder driver是做什么用的呢?

Binder driver提供的是橋梁的作用,比如從service注冊(cè)是service manager,抑或從client到service mangager查詢service,以及從client到service的通信,都需要通過(guò)Binder driver。

所以Binder driver提供了一個(gè)橋梁,同時(shí)在通信的過(guò)程中記錄了一些數(shù)據(jù)。

為了更好的說(shuō)明,先上一張整體Binder的關(guān)系圖。

3. Android binder設(shè)計(jì)篇

這張圖已經(jīng)基本包括了binder通信過(guò)程中的所有對(duì)象,我們可以用言語(yǔ)來(lái)簡(jiǎn)略的描述下這個(gè)過(guò)程和各個(gè)對(duì)象的含義,至于更詳細(xì)的我們后面再講。

過(guò)程簡(jiǎn)短描述:

1.首先這張圖有兩個(gè)空間,用戶空間和內(nèi)核空間;client, service,service manager運(yùn)行在用戶空間;而binder driver運(yùn)行在內(nèi)核空間。

2.service manager首先注冊(cè)為binder driver的服務(wù)管理者,注冊(cè)的過(guò)程中,service manager會(huì)調(diào)用open和mmap方法來(lái)通知binder driver為它分配一塊最大不超過(guò)4MB的內(nèi)存,當(dāng)然這個(gè)大小可以由service manager來(lái)指定,service manager指定的是128KB。這塊內(nèi)存同時(shí)被兩個(gè)虛擬地址應(yīng)用,一個(gè)binder driver的一個(gè)是service manager的。

換句話就是說(shuō)binder driver為service manager分配了一塊同時(shí)被內(nèi)核空間和用戶空間映射的內(nèi)存。

這也是binder驅(qū)動(dòng)的精華,通過(guò)這種虛擬內(nèi)存雙重映射,減少了binder driver和service manager之間的數(shù)據(jù)拷貝。

3.這樣,binder driver就記錄下了與service manager 對(duì)應(yīng)的binder實(shí)體對(duì)象(也就是圖中的sm binder實(shí)體)。

并且強(qiáng)制規(guī)定sm binder實(shí)體對(duì)象對(duì)應(yīng)的是句柄值是0。也就是其他進(jìn)程來(lái)訪問(wèn)service,只要它傳到binder driver的句柄值是0,那就意味著目標(biāo)service就是service manager。

然后service manager進(jìn)程進(jìn)入等待狀態(tài),等待別的進(jìn)程來(lái)喚醒。比如別的進(jìn)程要注冊(cè)service或者查詢service。

4.service進(jìn)程啟動(dòng)后,同樣會(huì)通過(guò)open和mmap方法通知binder driver為service進(jìn)程分配一塊不超過(guò)4MB的內(nèi)存,一般應(yīng)用程序的是1MB左右(1mb - 8kb)。

同第2點(diǎn)一樣,這塊內(nèi)存也被binder driver內(nèi)核空間和service進(jìn)程用戶空間的虛擬地址同時(shí)映射。

然后向service manager注冊(cè)service;正如第2點(diǎn)所言,binder driver強(qiáng)制規(guī)定了0號(hào)句柄對(duì)應(yīng)的是service manager實(shí)體對(duì)象,所以service進(jìn)程只要傳入0號(hào)句柄,然后把想注冊(cè)的service一起傳入過(guò)來(lái)就可以了。

5.binder driver接到service的ioctl調(diào)用后,找到第2點(diǎn)描述的sm binder實(shí)體,然后通過(guò)這個(gè)sm binder實(shí)體找到service manager對(duì)應(yīng)的進(jìn)程。

此時(shí),service manager的進(jìn)程正在睡眠等待狀態(tài),于是binder driver把要處理的工作封裝成一個(gè)binder_transaction丟給service manager進(jìn)程,也就是把數(shù)據(jù)拷貝到binder driver為service manager分配的那塊內(nèi)存(也就是第2步binder driver為service manager分配的那塊內(nèi)存),這也是binder數(shù)據(jù)傳輸?shù)奈ㄒ灰淮螖?shù)據(jù)拷貝,然后喚醒它。

6.此時(shí),service進(jìn)程會(huì)返回service進(jìn)程用戶空間,然后會(huì)再次進(jìn)入binder driver,并且進(jìn)入等待狀態(tài);它需要等待service manager注冊(cè)service的返回結(jié)果。

7.service manager進(jìn)程被喚醒后,回到service manager用戶空間,同時(shí)把binder driver拷貝過(guò)來(lái)的數(shù)據(jù)讀取出來(lái),把名稱和從binder driver傳入的句柄值保存起來(lái),再次執(zhí)行結(jié)果通過(guò)ioctl指令通知binder driver。

8.service manager進(jìn)程回到binder driver之后,通過(guò)之前第5步產(chǎn)生的binder_transaction找到之前調(diào)用的binder driver的service進(jìn)程和線程,把第7點(diǎn)從service manager返回的結(jié)果讀出來(lái),然后拷貝到binder driver為service分配的內(nèi)存,再喚醒service線程。

9.service manager在binder driver完成之后,會(huì)再次進(jìn)程等待狀態(tài)。

10.service進(jìn)程被service manager進(jìn)程喚醒之后,會(huì)回到service進(jìn)程的用戶空間,然后把第8步binder driver拷貝service進(jìn)程內(nèi)存的數(shù)據(jù)讀取出來(lái)(這塊內(nèi)存在binder driver中,被service進(jìn)程和binder driver同時(shí)映射),再完成最后的邏輯。

11.client進(jìn)程啟動(dòng)后,也會(huì)像service和service manager一樣通過(guò)open和mmap方法請(qǐng)求binder driver為client進(jìn)程分配一塊內(nèi)存用戶進(jìn)程間通信。

12.client進(jìn)程向service manager發(fā)起查詢service請(qǐng)求,同時(shí)傳入要查詢service的名稱,傳入的binder句柄值是0,也就是對(duì)應(yīng)著service manager。

13.binder driver接受到client的查詢請(qǐng)求后,根據(jù)句柄值0找到service manager的binder實(shí)體對(duì)象(sm binder實(shí)體),然后通過(guò)sm binder實(shí)體對(duì)象找到service manager進(jìn)程。此時(shí),service manager進(jìn)程正處于等待狀態(tài)。

14.binder driver把從client傳入的數(shù)據(jù)拷貝到為service manager分配的那塊內(nèi)存,生成一個(gè)binder_transaction,然后喚醒service manager進(jìn)程。

15.client進(jìn)程經(jīng)過(guò)一些處理后進(jìn)入等待狀態(tài),等待service manager來(lái)喚醒。

16.service manager被喚醒后,把binder driver拷貝給它的數(shù)據(jù)讀取出來(lái),當(dāng)然最重要的是從client進(jìn)程傳入的service 名稱。通過(guò)查找,找到名稱對(duì)應(yīng)的句柄值。也就是第7點(diǎn)那個(gè)名稱和句柄值。然后通過(guò)ioctl再次回到binder driver。

17.binder driver通過(guò)binder_transaction找到第15點(diǎn)的client進(jìn)程和線程,通過(guò)從service manager返回的句柄值找到binder driver里面對(duì)應(yīng)的service 實(shí)體對(duì)象。然后喚醒client線程。

18.在binder driver里面,client線程根據(jù)service 實(shí)體對(duì)象,生成屬于client進(jìn)程的binder引用對(duì)象,也就是一個(gè)句柄值,再返回client進(jìn)程用戶空間。

19.在client進(jìn)程用戶空間,把句柄值拷貝出來(lái),封裝成一個(gè)BpBinder對(duì)象,BpBinder對(duì)象里面mHandle值就保存了這個(gè)句柄值。

20.client和service通信,client使用第19步獲取到的mHandle句柄值,發(fā)送給binder driver。

21.binder driver根據(jù)mHandle句柄值找到client進(jìn)程內(nèi)對(duì)應(yīng)的binder引用對(duì)象,再根據(jù)binder引用對(duì)象找到它對(duì)應(yīng)的binder實(shí)體對(duì)象,再根據(jù)binder實(shí)體對(duì)象找到其所在的binder進(jìn)程。然后把數(shù)據(jù)拷貝到binder driver為service進(jìn)程分配的那塊內(nèi)存,再喚醒service進(jìn)程。

22.client進(jìn)程的調(diào)用線程進(jìn)入等待狀態(tài)。

23.由于binder實(shí)體對(duì)象有個(gè)cookie值指向用戶空間service進(jìn)程的的service地址,所以service在被喚醒后,它可以找到是由哪個(gè)service組件來(lái)響應(yīng)此次服務(wù)(service進(jìn)程內(nèi)可能不止一個(gè)service組件)。

24.service完成自己的邏輯后,再次通過(guò)binder_ioctl通知binder driver,告訴binder driver處理結(jié)果,然后再喚醒client進(jìn)程。這個(gè)過(guò)程就和service manager通知service是一樣的了。

這樣,整個(gè)通信過(guò)程就基本結(jié)束了。

ps:

1. 這里說(shuō)的service和android應(yīng)用里面說(shuō)的4大組件service并不是一個(gè)概念,這里的service指的是提供Binder服務(wù)的Binder本地對(duì)象。

2. 上面說(shuō)的Binder代理對(duì)象,Binder引用對(duì)象,Binder實(shí)體對(duì)象,Binder本地對(duì)象是按照從client到service的順序的,可以按個(gè)解釋下這幾個(gè)對(duì)象的含義。

a. Binder代理對(duì)象,運(yùn)行在client用戶空間,對(duì)應(yīng)的類是BpBinder,實(shí)現(xiàn)的關(guān)鍵在于它有個(gè)句柄mHandle變量,通過(guò)這個(gè)變量可以在Binder driver內(nèi)核空間里面找到對(duì)應(yīng)的Binder引用對(duì)象。

b. Binder引用對(duì)象,運(yùn)行在Binder driver內(nèi)核空間,對(duì)應(yīng)的數(shù)據(jù)是binder_ref結(jié)構(gòu)體。

c. Binder實(shí)體對(duì)象,運(yùn)行在Binder driver內(nèi)核空間,對(duì)應(yīng)的數(shù)據(jù)是binder_node結(jié)構(gòu)體。

d.Binder本地對(duì)象,運(yùn)行在service用戶空間,對(duì)應(yīng)的數(shù)據(jù)是BBinder,其實(shí)就是一個(gè)提供服務(wù)的Binder service。

3. 可能大家看到看到對(duì)于service manager在binder driver中, client和并沒(méi)有binder引用對(duì)象,而其他service在client進(jìn)程中卻有binder 引用對(duì)象,這是為什么呢?

這個(gè)問(wèn)題就回到文章開(kāi)始的第一點(diǎn),里面在描述女?huà)z造人關(guān)于源頭這個(gè)問(wèn)題上的時(shí)候,我們說(shuō)神話故事里面假設(shè)女?huà)z是事先存在的,從而彌補(bǔ)了這個(gè)故事里面的漏洞。

那在binder機(jī)制里面,也有這個(gè)問(wèn)題:就是client通過(guò)service manager拿到service的binder句柄值,那么service怎么拿到service manager的句柄值呢?

就好比說(shuō)人是女?huà)z造的,那女?huà)z又是哪里來(lái)的呢?

好吧,跟神話故事一樣,我們也是假設(shè)service manager是事先存在的,并且規(guī)定它的句柄值就是0。

那么client和service只要傳入句柄0就可以找到service manager在binder driver中的binder實(shí)體對(duì)象,自然也不需要binder 引用對(duì)象了。

而且service manager進(jìn)程也不會(huì)像其他service進(jìn)程一樣,可能存在多個(gè)service服務(wù)。

4. service manager請(qǐng)求binder driver為它分配的內(nèi)存是128kb,一般應(yīng)用程序(client, service)請(qǐng)求binder driver為它分配的內(nèi)存是1MB - 8KB。

這是我們要求使用binder時(shí)不能傳輸大于1MB數(shù)據(jù)的原因,比如通過(guò)intent傳輸圖片,很有可能會(huì)超過(guò)binder傳輸上限。當(dāng)然這個(gè)我們?cè)诤竺娣治龃a的時(shí)候會(huì)看到。

詳見(jiàn):

android_proj/framework/base/libs/binder/ProcessState.cpp

#define BINDER_VM_SIZE ((1*1024*1024) - (4096 *2))

5. 在上圖中大家看到有些service進(jìn)程中可能存在多個(gè)service組件,比如service2進(jìn)程。它們都通過(guò)binder driver注冊(cè)到了service manager,但是它們有不同的名稱對(duì)應(yīng)以及不同的service組件地址,這兩個(gè)區(qū)別分別會(huì)被service manager和binder driver(通過(guò)binder_node結(jié)構(gòu)體的cookie數(shù)據(jù))所記住。

所以可以區(qū)分。

6. binder線程池,用戶空間的程序有個(gè)線程池來(lái)響應(yīng)binder driver,但是有個(gè)上限,一般是15個(gè)線程,詳見(jiàn)

android_proj/framework/base/libs/binder/ProcessState.cpp

open_driver(){

   ...

   size_t maxThreads = 15; 

   result = ioctl(fd, BINDER_SET_MAX_THREADS, &maxThreads);

   ...

}

但是需要說(shuō)明的是這15個(gè)線程指的是binder driver請(qǐng)求用戶空間程序創(chuàng)建的最大線程數(shù)(當(dāng)應(yīng)用程序線程數(shù)不足以響應(yīng)binder請(qǐng)求時(shí),binder driver會(huì)請(qǐng)求應(yīng)用程序分配線程),并不包括用戶空間程序主動(dòng)注冊(cè)到binder driver的。

四. binder機(jī)制中的數(shù)據(jù)結(jié)構(gòu)

在初步了解binder機(jī)制的通信過(guò)程后,我們需要更深一步的了解binder通信,所以需要簡(jiǎn)單講解下binder通信過(guò)程中的數(shù)據(jù)結(jié)構(gòu)。

用戶空間數(shù)據(jù)binder driver內(nèi)核空間數(shù)據(jù)描述
flat_binder_objectbinder_node

binder service對(duì)象描述,每個(gè)添加到binder driver的service都會(huì)對(duì)應(yīng)一個(gè)binder_node,包括service manager也是

。

flat_binder_object顧名思義就是壓扁了的binder_object,為什么要壓扁呢?是為了傳輸?shù)男枨?,所以把binder對(duì)象從用戶空間傳輸?shù)絙inder driver內(nèi)核空間的時(shí)候,就需要用到這個(gè)數(shù)據(jù)結(jié)構(gòu),比如addService的時(shí)候。

client,service進(jìn)程
binder_proc

對(duì)應(yīng)一個(gè)進(jìn)程,當(dāng)進(jìn)程調(diào)用open方法打開(kāi)binder driver的時(shí)候,binder driver會(huì)保存這個(gè)進(jìn)程的相關(guān)信息,就是用binder_proc這個(gè)數(shù)據(jù)結(jié)構(gòu)。

在上面我們說(shuō)起過(guò),一個(gè)進(jìn)程中可能有多個(gè)service組件,比如service2進(jìn)程,那在binder driver里面也是這種關(guān)系。

binder_proc和binder_node是一對(duì)多的關(guān)系。

binder_proc使用了紅黑樹(shù)的數(shù)據(jù)結(jié)構(gòu)來(lái)描述了它里面binder_node。

紅黑樹(shù)的數(shù)據(jù)結(jié)構(gòu)大家有不清楚可以百度下。

線程binder_threadbinder_thread是線程在binder driver中的描述,所以binder_proc和binder_thread的對(duì)應(yīng)關(guān)系也是1對(duì)多,也是用紅黑樹(shù)來(lái)組織的。
binder_transaction_databinder_transaction

binder_transaction用來(lái)描述binder driver里面的一個(gè)事務(wù)。事務(wù)在數(shù)據(jù)庫(kù)里面用的比較多,binder driver也借用了這個(gè)概念。

那binder_transaction_data就剛好是用來(lái)描述從用戶空間到內(nèi)核空間傳輸binder_transaction數(shù)據(jù)的。

-binder_buffer

在前面描述過(guò),binder driver會(huì)為每個(gè)進(jìn)程分配一個(gè)不超過(guò)4MB的內(nèi)存,用來(lái)傳輸數(shù)據(jù)。

那怎么來(lái)管理這塊內(nèi)存呢?

binder driver把這塊內(nèi)存劃成一頁(yè)一頁(yè)來(lái)管理,那一個(gè)binder_buffer就表示一頁(yè)。

-binder_ref

binder driver里面的binder引用對(duì)象。

binder_ref主要的作用就是擁有一個(gè)句柄值,同時(shí)指向一個(gè)binder_node binder實(shí)體對(duì)象。

句柄值對(duì)應(yīng)client里面的binder代理對(duì)象BpBinder里面的mHandle,所以client可以根據(jù)mHandle找到內(nèi)核對(duì)應(yīng)的binder_ref數(shù)據(jù)。

binder_ref關(guān)聯(lián)的binder_node對(duì)象,這樣,找到binder_ref后,就可以進(jìn)一步找到binder_node。

binder_node上面講過(guò),關(guān)聯(lián)了binder_proc,以及service進(jìn)程里面的service組件,也就是binder本地對(duì)象。

所以,通過(guò)這一層層的關(guān)聯(lián),都連接起來(lái)了。

-binder_ref_death

跟binder本地對(duì)象死亡通知有關(guān)。

我們知道binder機(jī)制是這樣的引用的。

BpBinder(mHandle)->binder_ref->binder_node->BBinder binder本地對(duì)象。

那如果binder本地對(duì)象意外的掛了呢?比如service所在進(jìn)程由于程序邏輯錯(cuò)誤異常退出了,調(diào)用它的client怎么辦呢?

所以為了部分解決這個(gè)問(wèn)題,binder因?yàn)樗劳鐾ㄖ@個(gè)功能,當(dāng)binder本地對(duì)象消亡之后,需要通知正在監(jiān)聽(tīng)它的binder_ref client。

-binder_workbinder driver的工作項(xiàng)描述,后面再具體描述。
binder_write_readbinder_write_read

ioctl指令BINDER_WRITE_READ的數(shù)據(jù)結(jié)構(gòu)。




五. 實(shí)名binder對(duì)象和匿名binder對(duì)象

所謂的實(shí)名和匿名是針對(duì)service manager而言的,就是service manager知不知道這個(gè)binder對(duì)象的存在,并且給它一個(gè)名字相對(duì)應(yīng)。

正如第一步里面所描述的女?huà)z造人的故事,女?huà)z可以造人,但是人也可以造人。如果把女?huà)z比喻成service manager,那么第一代人就是實(shí)名binder對(duì)象,第一代人以及后面的人造的人就是匿名binder對(duì)象;

因?yàn)樗鼘?duì)于女?huà)z這個(gè)service manager而言,女?huà)z并不知道它們的存在和名字。

這個(gè)比喻如果難以理解的話,那再舉個(gè)更加現(xiàn)實(shí)的栗子:

如果一個(gè)人想進(jìn)入火車候車室,那么他需要火車票或者站臺(tái)票,那我們現(xiàn)在來(lái)做如下比喻:

例子binder
進(jìn)入候車室實(shí)現(xiàn)binder通信功能
火車票實(shí)名binder對(duì)象
站臺(tái)票匿名binder對(duì)象
鐵道部
service manager

檢票口binder driver

1.假如把進(jìn)入候車室這個(gè)功能比喻成實(shí)現(xiàn)binder通信這個(gè)功能,那么:

2.火車票和站臺(tái)票都可以進(jìn)入候車室,也就是說(shuō)實(shí)名binder和匿名binder都可以完成進(jìn)程間通信功能,這點(diǎn)并沒(méi)有什么區(qū)別。

3.由于火車票是實(shí)名制的,所以鐵道部能知道賣出的票和購(gòu)買人的***一一對(duì)應(yīng);但是對(duì)于站臺(tái)票,鐵道部并不能知道這種對(duì)應(yīng)關(guān)系;

那對(duì)于service manager和實(shí)名binder,匿名binder也是這種關(guān)系 -- service mangager清楚的知道所有實(shí)名binder的名稱,binder服務(wù)所在的進(jìn)程等等信息,但是對(duì)于匿名binder卻一無(wú)所知,它甚至不知道匿名binder的存在。

4.購(gòu)買站臺(tái)票不是想買就可以買的,需要持有火車票吃可以購(gòu)買站臺(tái)票;

那對(duì)于實(shí)名binder和匿名binder也是如此,匿名binder不是想創(chuàng)建就能創(chuàng)建的,首先需要得到一個(gè)實(shí)名binder,通過(guò)實(shí)名binder得到匿名binder,具體例子可以參考bindService得到一個(gè)匿名binder的實(shí)現(xiàn)。

5.對(duì)于檢票口,不管是火車票還是站臺(tái)票都會(huì)從檢票口通過(guò),所以檢票口可以記錄一些信息;同樣,對(duì)于binder driver,不管是實(shí)名binder還是匿名binder都會(huì)通過(guò)binder driver,binder driver也會(huì)記錄它們的信息。

六. binder ioctl指令

ioctl指令名稱含義注釋
BINDER_WRITE_READ最重要的ioctl指令,后面可以執(zhí)行很多binder命令操作。獨(dú)特的先寫后讀的設(shè)計(jì),給予了用戶空間程序更多的便利。
BINDER_SET_IDLE_TIMEOUT暫未使用
BINDER_SET_MAX_THREADS設(shè)置binder driver可以請(qǐng)求用戶空間進(jìn)程最大線程數(shù)。不包括用戶空間進(jìn)程主動(dòng)注冊(cè)到binder driver的線程。
BINDER_SET_IDLE_PRIORITY暫未使用
BINDER_SET_CONTEXT_MGR通知binder driver,當(dāng)前進(jìn)程成為binder機(jī)制上下文,也就是service mangagerbinder driver里面只能存在一個(gè)service manager,多次調(diào)用會(huì)出錯(cuò)。
BINDER_THREAD_EXIT通知binder driver線程退出
BINDER_VERSION返回當(dāng)前binder driver版本號(hào)

七. binder命令

binder命令按照命令的流向性分為兩大類:

1.BC_XXX

2.BR_XXX

從用戶空間流向binder driver的命令被稱為BC_XXX,也就是binder command的簡(jiǎn)稱;相應(yīng)的從binder driver流向用戶空間進(jìn)程的稱為BR_XXX,也就是binder return的簡(jiǎn)稱。如下圖:

3. Android binder設(shè)計(jì)篇

對(duì)于所有的binder 命令,可以用下面兩張表來(lái)描述:

具體可以參考./working_directory/kernel/goldfish/driver/staging/android/binder.h

enum BinderDriverCommandProtocol {

  ...

}

enum BinderDriverReturnProtocol {

  ...

}

3.BC_XXX

命令名稱含義注釋
BC_TRANSACTION意思是進(jìn)行一次transaction,比如addService,getService,或者client跨進(jìn)程調(diào)用service方法等等。最重要的binder命令之一,一般通過(guò)ioctl--BINDER_WRITE_READ來(lái)和binder driver交互。
BC_REPLY回復(fù)binder driver比如addService的時(shí)候,service manager在處理完自己的邏輯后會(huì)發(fā)送此命令到binder driver,告訴binder driver自己處理結(jié)果。
BC_ACQUIRE_RESULT暫不支持
BC_FREE_BUFFER

通知binder driver去釋放一個(gè)binder_buff的內(nèi)存,參數(shù)int表示此binder_buff在用戶空間進(jìn)程的虛擬映射地址。

一般是在處理完一個(gè)事務(wù)之后,通知binder driver釋放先關(guān)內(nèi)存。
BC_INCREFS

通知binder driver增加目標(biāo)service 弱引用, 參數(shù)int表示目標(biāo)service的handle值,


BC_ACQUIRE

通知binder driver增加目標(biāo)service 強(qiáng)引用,參數(shù)int表示目標(biāo)service的handle值.


BC_RELEASE

通知binder driver減少目標(biāo)service強(qiáng)引用,參數(shù)int表示目標(biāo)service的handle值.


BC_DECREFS

通知binder driver減少目標(biāo)service弱引用,參數(shù)int表示目標(biāo)service的handle值.


BC_INCREFS_DONE

通知binder driver BR_INCREFS命令執(zhí)行完畢,一般由service進(jìn)程在處理完binder driver的BR_INCREFS命令后向binder driver發(fā)出。


BC_ACQUIRE_DONE通知binder driver BR_ACQUIRE命令執(zhí)行完畢,一般由service進(jìn)程在處理完binder driver的BR_ACQUIRE命令后向binder driver發(fā)出。

因?yàn)閎inder driver在請(qǐng)求service進(jìn)程增加一個(gè)service組件的強(qiáng)引用之后,它需要等待service組件增加強(qiáng)引用計(jì)數(shù)的結(jié)果,它需要根據(jù)這個(gè)結(jié)果修改自己的一些狀態(tài)。

BC_ATTEMPT_ACQUIRE暫不支持
BC_REGISTER_LOOPER

通知binder driver此進(jìn)程進(jìn)入BINDER_LOOPER_STATE_REGISTERED狀態(tài),再經(jīng)過(guò)一些處理就會(huì)進(jìn)入就緒狀態(tài),可以處理進(jìn)程的事務(wù)。

此命令是binder driver通知用戶空間進(jìn)程創(chuàng)建線程后,用戶空間進(jìn)程創(chuàng)建線程后會(huì)調(diào)用此命令,通知binder driver此線程已經(jīng)準(zhǔn)備好。


BC_ENTER_LOOPER用戶空間進(jìn)程主動(dòng)請(qǐng)求binder driver通知此線程可以處理進(jìn)程間binder 通信請(qǐng)求,一般如果沒(méi)有事情做的話,會(huì)進(jìn)入等待狀態(tài)。

此命令和BC_REGISTER_LOOPER的區(qū)別就是

BC_ENTER_LOOPER是用戶空間進(jìn)程主動(dòng)通知binder driver的,

BC_REGISTER_LOOPER是binder driver發(fā)現(xiàn)此用戶空間進(jìn)程的線程池?zé)o法響應(yīng)binder通信,需要?jiǎng)?chuàng)建新線程;然后向目標(biāo)用戶空間進(jìn)程發(fā)出請(qǐng)求創(chuàng)建線程命令

用戶空間進(jìn)程創(chuàng)建線程完畢后,會(huì)調(diào)用BC_REGISTER_LOOPER通知binder driver。

BC_EXIT_LOOPER

通知binder driver此線程退出


BC_REQUEST_DEATH_NOTIFICATION

client請(qǐng)求binder driver注冊(cè)目標(biāo)service組件的死亡通知

以便在目標(biāo)serive組件死亡的時(shí)候得到通知,然后client可以處理自己的邏輯。
BC_CLEAR_DEATH_NOTIFICATION

client通知binder driver取消注冊(cè)對(duì)某個(gè)service binder本地對(duì)象的死亡通知監(jiān)聽(tīng)


BC_DEAD_BINDER_DONE

client通知binder driver對(duì)某個(gè)service進(jìn)程的binder本地對(duì)象死亡通知處理完畢。


4.BR_XXX

命令名稱含義注釋
BR_ERROR

通知用戶空間進(jìn)程,binder driver處理出現(xiàn)異常


BR_OK

通知用戶空間進(jìn)程,binder driver處理成功


BR_TRANSACTIONbinder driver請(qǐng)求用戶空間進(jìn)程處理一個(gè)事務(wù),事務(wù)的數(shù)據(jù)方法binder_transaction_data結(jié)構(gòu)體中,

比如addService的時(shí)候,binder driver請(qǐng)求service manager去注冊(cè)一個(gè)service。

BR_REPLY
binder driver通知用戶空間進(jìn)程處理完畢比如用戶空間進(jìn)程發(fā)起的BC_TRANSACTION 處理完畢后,binder driver就會(huì)反饋BR_REPLY
BR_ACQUIRE_RESULT暫不支持
BR_DEAD_REPLY

binder driver反饋目標(biāo)binder對(duì)象已經(jīng)死亡,返回錯(cuò)誤。


BR_TRANSACTION_COMPLETEbinder driver反饋事務(wù)處理完成
BR_INCREFS

binder driver請(qǐng)求用戶空間進(jìn)程增加指定binder本地對(duì)象的弱引用


BR_ACQUIRE

binder driver請(qǐng)求用戶空間進(jìn)程增加指定binder本地對(duì)象的強(qiáng)引用


BR_RELEASE

binder driver請(qǐng)求用戶空間進(jìn)程減少指定binder本地對(duì)象的強(qiáng)引用


BR_DECREFS

binder driver請(qǐng)求用戶空間進(jìn)程減少指定binder本地對(duì)象的弱引用


BR_ATTEMPT_ACQUIRE

暫不支持


BR_NOOP

沒(méi)有什么操作


BR_SPAWN_LOOPER

binder driver請(qǐng)求用戶空間進(jìn)程分配一個(gè)線程;這種情況一般是在用戶空間進(jìn)程線程池?zé)o法處理binder driver間通信請(qǐng)求的情況下。


BR_FINISHED暫不支持
BR_DEAD_BINDER

通知用戶空間進(jìn)程所監(jiān)聽(tīng)的binder本地對(duì)象已經(jīng)銷毀


BR_CLEAR_DEATH_NOTIFICATION_DONE

在用戶空間進(jìn)程請(qǐng)求BC_CLEAR_DEATH_NOTIFICATION命令后,binder driver返回這個(gè)命令通知用戶空間進(jìn)程


BR_FAILED_REPLYbinder driver返回失敗






八. 引用計(jì)數(shù)

在第七點(diǎn)的表中,我們提到了所有的Binder協(xié)議命令,其中包括類似BC_INCREFS,BC_ACQUIRE,BC_RELEASE,BC_DECREFS之類的命令,表中解釋是維護(hù)binder對(duì)象的引用計(jì)數(shù);那為什么要進(jìn)行這樣的設(shè)計(jì)呢?

那我們可以來(lái)做這樣一種假設(shè):

client進(jìn)程引用service進(jìn)程的一個(gè)binder本地對(duì)象正在通信,如果這個(gè)時(shí)候service進(jìn)程把這個(gè)binder本地對(duì)象回收了怎么辦?

為了解決這個(gè)問(wèn)題,binder機(jī)制使用了引用的概念:

在Java里面,我們知道維護(hù)一個(gè)對(duì)象的生命周期可以通過(guò)強(qiáng)引用,軟引用,弱引用和虛引用來(lái)實(shí)現(xiàn)(具體的區(qū)別大家可以百度,里面一些區(qū)別和技巧還是很有用的,特別是軟引用用來(lái)實(shí)現(xiàn)圖片的緩存),只要一個(gè)對(duì)象被從垃圾回收的根節(jié)點(diǎn)強(qiáng)引用所關(guān)聯(lián),那么它是不會(huì)被回收的。

所以,類似的,binder機(jī)制里面也采用這個(gè)概念。

那,binder driver為什么不直接引用binder 本地對(duì)象呢?

這是因?yàn)閎inder driver是在內(nèi)核空間,binder本地對(duì)象在service進(jìn)程的用戶空間,不能直接引用。

所以,binder 機(jī)制才通過(guò)這種通過(guò)命令調(diào)用的方式,通知service進(jìn)程為指定的binder本地對(duì)象增加/減少引用,從而達(dá)到維護(hù)用戶空間service進(jìn)程binder本地對(duì)象生命周期的目的。

九. 死亡通知機(jī)制

通過(guò)上面幾點(diǎn)介紹,一到七點(diǎn)保證了binder間進(jìn)程通信,第八點(diǎn)保證了生命周期管理,一切看起來(lái)都那么完美。

但是,還是有意外情況發(fā)生,那就是:

提供服務(wù)的service進(jìn)程死亡了怎么辦?

對(duì)應(yīng)這個(gè)問(wèn)題,client和binder driver都愛(ài)莫能助,因?yàn)樗鼈円矡o(wú)法控制service進(jìn)程的生命周期。又回到了第八點(diǎn)闡述的那個(gè)問(wèn)題:

client進(jìn)程引用service進(jìn)程的一個(gè)binder本地對(duì)象正在通信,如果service進(jìn)程的binder本地對(duì)象不存在了怎么辦?

對(duì)于service進(jìn)程死亡,一般可以分為兩種情況:

1.正常死亡,比如程序自己退出

2.異常退出,比如因?yàn)槌绦蚶锩娴囊粋€(gè)邏輯錯(cuò)誤導(dǎo)致進(jìn)程退出

如果是第1種情形,程序會(huì)自己主動(dòng)close掉自己進(jìn)程打開(kāi)的binder driver;從而調(diào)用到binder driver的binder_release函數(shù)。

如果是第2種情形,操作系統(tǒng)會(huì)幫我們close,從而也可以調(diào)用binder driver的binder_release函數(shù)。

所以,上面兩種可能都可以在binder driver的binder_release函數(shù)中去解決。

binder 機(jī)制死亡通知的過(guò)程是這樣的:

a.client進(jìn)程拿到指向service進(jìn)程binder本地對(duì)象的引用后,它可以向這個(gè)service進(jìn)程binder本地對(duì)象請(qǐng)求注冊(cè)一個(gè)死亡通知(其實(shí)就是BpBinder,因?yàn)樗鼘?shí)現(xiàn)了死亡通知的接口)。

b.binder driver記錄下了這層對(duì)應(yīng)關(guān)系。

c.當(dāng)binder driver檢測(cè)到目標(biāo)service進(jìn)程已經(jīng)死亡時(shí),它找到這個(gè)進(jìn)程所有binder本地對(duì)象在binder driver里面對(duì)應(yīng)的binder實(shí)體對(duì)象。

d.然后根據(jù)binder實(shí)體對(duì)象找到所有引用它的binder引用對(duì)象,如果發(fā)現(xiàn)binder引用對(duì)象有注冊(cè)死亡通知,那么就封裝一個(gè)binder_work項(xiàng)給binder引用對(duì)象所在的進(jìn)程,然后喚醒它;讓那個(gè)進(jìn)程去完成自己的邏輯。

至此,binder設(shè)計(jì)篇內(nèi)容全部提供完畢,下面會(huì)寫一些binder實(shí)現(xiàn)篇的東西,也就是從代碼的角度來(lái)分析這些內(nèi)容。

當(dāng)前文章:3.Androidbinder設(shè)計(jì)篇
當(dāng)前地址:http://muchs.cn/article40/ipjdho.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供靜態(tài)網(wǎng)站、網(wǎng)站改版、軟件開(kāi)發(fā)網(wǎng)站導(dǎo)航、做網(wǎng)站、響應(yīng)式網(wǎng)站

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)

營(yíng)銷型網(wǎng)站建設(shè)