一. 引言--女媧造人的故事
成都創(chuàng)新互聯(lián)公司-專業(yè)網(wǎng)站定制、快速模板網(wǎng)站建設(shè)、高性價比德城網(wǎng)站開發(fā)、企業(yè)建站全套包干低至880元,成熟完善的模板庫,直接使用。一站式德城網(wǎng)站制作公司更省心,省錢,快速模板網(wǎng)站建設(shè)找我們,業(yè)務(wù)覆蓋德城地區(qū)。費用合理售后完善,10多年實體公司更值得信賴。
在天地混沌之際,上神女媧因為覺得自己太孤單,沒人跟它一起嗨,決定按照自己的模樣添加一些生物;于是呢,捏泥為人,并賦予了人生育的能力,所以女媧被稱為了人類的母親;
神話故事很美好,解釋了人類的來源,但是這個邏輯中其實有個缺陷,就是女媧從哪里來的?
那有些同學(xué)就會問了,這里說Binder設(shè)計,為什么要提到女媧造人的故事呢?這是因為二者在源頭這個問題的處理上有異曲同工之妙,嗯,后面會再做說明。
二. Android Binder簡介
Andoid Binder從Open Binder發(fā)展而來,提供了跨進(jìn)程通信機(jī)制;其實linux已經(jīng)提供很多的跨進(jìn)程機(jī)制,比如管道,共享內(nèi)存等等,那為什么google要使用binder呢?
其實,大家也可以思考下,針對于移動設(shè)備這種低配置的設(shè)備(相對于服務(wù)器),新的進(jìn)程間通信機(jī)制需要具備什么新的優(yōu)點呢?
1.內(nèi)存節(jié)省,因為移動設(shè)備的低配置,所以需要新的通信機(jī)制盡可能的節(jié)省資源,binder在跨進(jìn)程數(shù)據(jù)拷貝時只進(jìn)行一次;
2.高效性,比如對于手機(jī)這種東西,大家肯定希望它反應(yīng)迅速,界面流暢;
3. 安全性,手機(jī)涉及了大量的用戶隱私,比如支付寶賬號,電話本聯(lián)系人號碼,短信記錄,通話記錄等等;
在linux系統(tǒng)中對于權(quán)限安全性管理,UID是一個很重要的東西,所以對于安全性,binder就在binder driver里面負(fù)責(zé)填寫調(diào)用進(jìn)程的UID和PID;相比一些在應(yīng)用程序填寫UID和PID的進(jìn)程間通信機(jī)制,安全性得到了極大提高。
總體來說,Binder肯定是一個不錯的進(jìn)程間通信機(jī)制,否則android經(jīng)過這么多年的發(fā)展,如果Binder不是足夠優(yōu)秀的話,以google的技術(shù)實力,早就被google替換了吧!
三.Binder通信關(guān)系總圖
Binder作為Android里面進(jìn)程間通信機(jī)制,主要有4個模塊參與這個過程,分別是
client
service
ServiceManager
Binder Driver
client和service作為通信的模塊很容易理解,因為client需要和service通信,所以它們兩個必然會成為通信的一部分。
那service manager和Binder driver起的作用是什么呢?
service manager提供service的注冊,查詢等服務(wù),那說的再明白一點,就是service Binder本地對象把自己和一個名字添加到service manager注冊;
這樣,client就可以向service manager通過指定的名字去查詢之前注冊的service,從而找到對應(yīng)的Binder實體對象,再繼而生成屬于自己進(jìn)程的Binder 引用對象。
最后把這個屬于自己進(jìn)程的Binder引用對象和自己進(jìn)程內(nèi)的一個Binder代理對象對應(yīng)起來;這樣client就間接的擁有了service Binder本地對象的引用,進(jìn)而可以和service通信。
那Binder driver是做什么用的呢?
Binder driver提供的是橋梁的作用,比如從service注冊是service manager,抑或從client到service mangager查詢service,以及從client到service的通信,都需要通過Binder driver。
所以Binder driver提供了一個橋梁,同時在通信的過程中記錄了一些數(shù)據(jù)。
為了更好的說明,先上一張整體Binder的關(guān)系圖。
這張圖已經(jīng)基本包括了binder通信過程中的所有對象,我們可以用言語來簡略的描述下這個過程和各個對象的含義,至于更詳細(xì)的我們后面再講。
過程簡短描述:
1.首先這張圖有兩個空間,用戶空間和內(nèi)核空間;client, service,service manager運行在用戶空間;而binder driver運行在內(nèi)核空間。
2.service manager首先注冊為binder driver的服務(wù)管理者,注冊的過程中,service manager會調(diào)用open和mmap方法來通知binder driver為它分配一塊最大不超過4MB的內(nèi)存,當(dāng)然這個大小可以由service manager來指定,service manager指定的是128KB。這塊內(nèi)存同時被兩個虛擬地址應(yīng)用,一個binder driver的一個是service manager的。
換句話就是說binder driver為service manager分配了一塊同時被內(nèi)核空間和用戶空間映射的內(nèi)存。
這也是binder驅(qū)動的精華,通過這種虛擬內(nèi)存雙重映射,減少了binder driver和service manager之間的數(shù)據(jù)拷貝。
3.這樣,binder driver就記錄下了與service manager 對應(yīng)的binder實體對象(也就是圖中的sm binder實體)。
并且強(qiáng)制規(guī)定sm binder實體對象對應(yīng)的是句柄值是0。也就是其他進(jìn)程來訪問service,只要它傳到binder driver的句柄值是0,那就意味著目標(biāo)service就是service manager。
然后service manager進(jìn)程進(jìn)入等待狀態(tài),等待別的進(jìn)程來喚醒。比如別的進(jìn)程要注冊service或者查詢service。
4.service進(jìn)程啟動后,同樣會通過open和mmap方法通知binder driver為service進(jìn)程分配一塊不超過4MB的內(nèi)存,一般應(yīng)用程序的是1MB左右(1mb - 8kb)。
同第2點一樣,這塊內(nèi)存也被binder driver內(nèi)核空間和service進(jìn)程用戶空間的虛擬地址同時映射。
然后向service manager注冊service;正如第2點所言,binder driver強(qiáng)制規(guī)定了0號句柄對應(yīng)的是service manager實體對象,所以service進(jìn)程只要傳入0號句柄,然后把想注冊的service一起傳入過來就可以了。
5.binder driver接到service的ioctl調(diào)用后,找到第2點描述的sm binder實體,然后通過這個sm binder實體找到service manager對應(yīng)的進(jìn)程。
此時,service manager的進(jìn)程正在睡眠等待狀態(tài),于是binder driver把要處理的工作封裝成一個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.此時,service進(jìn)程會返回service進(jìn)程用戶空間,然后會再次進(jìn)入binder driver,并且進(jìn)入等待狀態(tài);它需要等待service manager注冊service的返回結(jié)果。
7.service manager進(jìn)程被喚醒后,回到service manager用戶空間,同時把binder driver拷貝過來的數(shù)據(jù)讀取出來,把名稱和從binder driver傳入的句柄值保存起來,再次執(zhí)行結(jié)果通過ioctl指令通知binder driver。
8.service manager進(jìn)程回到binder driver之后,通過之前第5步產(chǎn)生的binder_transaction找到之前調(diào)用的binder driver的service進(jìn)程和線程,把第7點從service manager返回的結(jié)果讀出來,然后拷貝到binder driver為service分配的內(nèi)存,再喚醒service線程。
9.service manager在binder driver完成之后,會再次進(jìn)程等待狀態(tài)。
10.service進(jìn)程被service manager進(jìn)程喚醒之后,會回到service進(jìn)程的用戶空間,然后把第8步binder driver拷貝service進(jìn)程內(nèi)存的數(shù)據(jù)讀取出來(這塊內(nèi)存在binder driver中,被service進(jìn)程和binder driver同時映射),再完成最后的邏輯。
11.client進(jìn)程啟動后,也會像service和service manager一樣通過open和mmap方法請求binder driver為client進(jìn)程分配一塊內(nèi)存用戶進(jìn)程間通信。
12.client進(jìn)程向service manager發(fā)起查詢service請求,同時傳入要查詢service的名稱,傳入的binder句柄值是0,也就是對應(yīng)著service manager。
13.binder driver接受到client的查詢請求后,根據(jù)句柄值0找到service manager的binder實體對象(sm binder實體),然后通過sm binder實體對象找到service manager進(jìn)程。此時,service manager進(jìn)程正處于等待狀態(tài)。
14.binder driver把從client傳入的數(shù)據(jù)拷貝到為service manager分配的那塊內(nèi)存,生成一個binder_transaction,然后喚醒service manager進(jìn)程。
15.client進(jìn)程經(jīng)過一些處理后進(jìn)入等待狀態(tài),等待service manager來喚醒。
16.service manager被喚醒后,把binder driver拷貝給它的數(shù)據(jù)讀取出來,當(dāng)然最重要的是從client進(jìn)程傳入的service 名稱。通過查找,找到名稱對應(yīng)的句柄值。也就是第7點那個名稱和句柄值。然后通過ioctl再次回到binder driver。
17.binder driver通過binder_transaction找到第15點的client進(jìn)程和線程,通過從service manager返回的句柄值找到binder driver里面對應(yīng)的service 實體對象。然后喚醒client線程。
18.在binder driver里面,client線程根據(jù)service 實體對象,生成屬于client進(jìn)程的binder引用對象,也就是一個句柄值,再返回client進(jìn)程用戶空間。
19.在client進(jìn)程用戶空間,把句柄值拷貝出來,封裝成一個BpBinder對象,BpBinder對象里面mHandle值就保存了這個句柄值。
20.client和service通信,client使用第19步獲取到的mHandle句柄值,發(fā)送給binder driver。
21.binder driver根據(jù)mHandle句柄值找到client進(jìn)程內(nèi)對應(yīng)的binder引用對象,再根據(jù)binder引用對象找到它對應(yīng)的binder實體對象,再根據(jù)binder實體對象找到其所在的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實體對象有個cookie值指向用戶空間service進(jìn)程的的service地址,所以service在被喚醒后,它可以找到是由哪個service組件來響應(yīng)此次服務(wù)(service進(jìn)程內(nèi)可能不止一個service組件)。
24.service完成自己的邏輯后,再次通過binder_ioctl通知binder driver,告訴binder driver處理結(jié)果,然后再喚醒client進(jìn)程。這個過程就和service manager通知service是一樣的了。
這樣,整個通信過程就基本結(jié)束了。
ps:
1. 這里說的service和android應(yīng)用里面說的4大組件service并不是一個概念,這里的service指的是提供Binder服務(wù)的Binder本地對象。
2. 上面說的Binder代理對象,Binder引用對象,Binder實體對象,Binder本地對象是按照從client到service的順序的,可以按個解釋下這幾個對象的含義。
a. Binder代理對象,運行在client用戶空間,對應(yīng)的類是BpBinder,實現(xiàn)的關(guān)鍵在于它有個句柄mHandle變量,通過這個變量可以在Binder driver內(nèi)核空間里面找到對應(yīng)的Binder引用對象。
b. Binder引用對象,運行在Binder driver內(nèi)核空間,對應(yīng)的數(shù)據(jù)是binder_ref結(jié)構(gòu)體。
c. Binder實體對象,運行在Binder driver內(nèi)核空間,對應(yīng)的數(shù)據(jù)是binder_node結(jié)構(gòu)體。
d.Binder本地對象,運行在service用戶空間,對應(yīng)的數(shù)據(jù)是BBinder,其實就是一個提供服務(wù)的Binder service。
3. 可能大家看到看到對于service manager在binder driver中, client和并沒有binder引用對象,而其他service在client進(jìn)程中卻有binder 引用對象,這是為什么呢?
這個問題就回到文章開始的第一點,里面在描述女媧造人關(guān)于源頭這個問題上的時候,我們說神話故事里面假設(shè)女媧是事先存在的,從而彌補(bǔ)了這個故事里面的漏洞。
那在binder機(jī)制里面,也有這個問題:就是client通過service manager拿到service的binder句柄值,那么service怎么拿到service manager的句柄值呢?
就好比說人是女媧造的,那女媧又是哪里來的呢?
好吧,跟神話故事一樣,我們也是假設(shè)service manager是事先存在的,并且規(guī)定它的句柄值就是0。
那么client和service只要傳入句柄0就可以找到service manager在binder driver中的binder實體對象,自然也不需要binder 引用對象了。
而且service manager進(jìn)程也不會像其他service進(jìn)程一樣,可能存在多個service服務(wù)。
4. service manager請求binder driver為它分配的內(nèi)存是128kb,一般應(yīng)用程序(client, service)請求binder driver為它分配的內(nèi)存是1MB - 8KB。
這是我們要求使用binder時不能傳輸大于1MB數(shù)據(jù)的原因,比如通過intent傳輸圖片,很有可能會超過binder傳輸上限。當(dāng)然這個我們在后面分析代碼的時候會看到。
詳見:
android_proj/framework/base/libs/binder/ProcessState.cpp
#define BINDER_VM_SIZE ((1*1024*1024) - (4096 *2))
5. 在上圖中大家看到有些service進(jìn)程中可能存在多個service組件,比如service2進(jìn)程。它們都通過binder driver注冊到了service manager,但是它們有不同的名稱對應(yīng)以及不同的service組件地址,這兩個區(qū)別分別會被service manager和binder driver(通過binder_node結(jié)構(gòu)體的cookie數(shù)據(jù))所記住。
所以可以區(qū)分。
6. binder線程池,用戶空間的程序有個線程池來響應(yīng)binder driver,但是有個上限,一般是15個線程,詳見
android_proj/framework/base/libs/binder/ProcessState.cpp
open_driver(){
...
size_t maxThreads = 15;
result = ioctl(fd, BINDER_SET_MAX_THREADS, &maxThreads);
...
}
但是需要說明的是這15個線程指的是binder driver請求用戶空間程序創(chuàng)建的最大線程數(shù)(當(dāng)應(yīng)用程序線程數(shù)不足以響應(yīng)binder請求時,binder driver會請求應(yīng)用程序分配線程),并不包括用戶空間程序主動注冊到binder driver的。
四. binder機(jī)制中的數(shù)據(jù)結(jié)構(gòu)
在初步了解binder機(jī)制的通信過程后,我們需要更深一步的了解binder通信,所以需要簡單講解下binder通信過程中的數(shù)據(jù)結(jié)構(gòu)。
用戶空間數(shù)據(jù) | binder driver內(nèi)核空間數(shù)據(jù) | 描述 |
flat_binder_object | binder_node | binder service對象描述,每個添加到binder driver的service都會對應(yīng)一個binder_node,包括service manager也是 。 flat_binder_object顧名思義就是壓扁了的binder_object,為什么要壓扁呢?是為了傳輸?shù)男枨?,所以把binder對象從用戶空間傳輸?shù)絙inder driver內(nèi)核空間的時候,就需要用到這個數(shù)據(jù)結(jié)構(gòu),比如addService的時候。 |
client,service進(jìn)程 | binder_proc | 對應(yīng)一個進(jìn)程,當(dāng)進(jìn)程調(diào)用open方法打開binder driver的時候,binder driver會保存這個進(jìn)程的相關(guān)信息,就是用binder_proc這個數(shù)據(jù)結(jié)構(gòu)。 在上面我們說起過,一個進(jìn)程中可能有多個service組件,比如service2進(jìn)程,那在binder driver里面也是這種關(guān)系。 binder_proc和binder_node是一對多的關(guān)系。 binder_proc使用了紅黑樹的數(shù)據(jù)結(jié)構(gòu)來描述了它里面binder_node。 紅黑樹的數(shù)據(jù)結(jié)構(gòu)大家有不清楚可以百度下。 |
線程 | binder_thread | binder_thread是線程在binder driver中的描述,所以binder_proc和binder_thread的對應(yīng)關(guān)系也是1對多,也是用紅黑樹來組織的。 |
binder_transaction_data | binder_transaction | binder_transaction用來描述binder driver里面的一個事務(wù)。事務(wù)在數(shù)據(jù)庫里面用的比較多,binder driver也借用了這個概念。 那binder_transaction_data就剛好是用來描述從用戶空間到內(nèi)核空間傳輸binder_transaction數(shù)據(jù)的。 |
- | binder_buffer | 在前面描述過,binder driver會為每個進(jìn)程分配一個不超過4MB的內(nèi)存,用來傳輸數(shù)據(jù)。 那怎么來管理這塊內(nèi)存呢? binder driver把這塊內(nèi)存劃成一頁一頁來管理,那一個binder_buffer就表示一頁。 |
- | binder_ref | binder driver里面的binder引用對象。 binder_ref主要的作用就是擁有一個句柄值,同時指向一個binder_node binder實體對象。 句柄值對應(yīng)client里面的binder代理對象BpBinder里面的mHandle,所以client可以根據(jù)mHandle找到內(nèi)核對應(yīng)的binder_ref數(shù)據(jù)。 binder_ref關(guān)聯(lián)的binder_node對象,這樣,找到binder_ref后,就可以進(jìn)一步找到binder_node。 binder_node上面講過,關(guān)聯(lián)了binder_proc,以及service進(jìn)程里面的service組件,也就是binder本地對象。 所以,通過這一層層的關(guān)聯(lián),都連接起來了。 |
- | binder_ref_death | 跟binder本地對象死亡通知有關(guān)。 我們知道binder機(jī)制是這樣的引用的。 BpBinder(mHandle)->binder_ref->binder_node->BBinder binder本地對象。 那如果binder本地對象意外的掛了呢?比如service所在進(jìn)程由于程序邏輯錯誤異常退出了,調(diào)用它的client怎么辦呢? 所以為了部分解決這個問題,binder因為死亡通知這個功能,當(dāng)binder本地對象消亡之后,需要通知正在監(jiān)聽它的binder_ref client。 |
- | binder_work | binder driver的工作項描述,后面再具體描述。 |
binder_write_read | binder_write_read | ioctl指令BINDER_WRITE_READ的數(shù)據(jù)結(jié)構(gòu)。 |
五. 實名binder對象和匿名binder對象
所謂的實名和匿名是針對service manager而言的,就是service manager知不知道這個binder對象的存在,并且給它一個名字相對應(yīng)。
正如第一步里面所描述的女媧造人的故事,女媧可以造人,但是人也可以造人。如果把女媧比喻成service manager,那么第一代人就是實名binder對象,第一代人以及后面的人造的人就是匿名binder對象;
因為它對于女媧這個service manager而言,女媧并不知道它們的存在和名字。
這個比喻如果難以理解的話,那再舉個更加現(xiàn)實的栗子:
如果一個人想進(jìn)入火車候車室,那么他需要火車票或者站臺票,那我們現(xiàn)在來做如下比喻:
例子 | binder | |
進(jìn)入候車室 | 實現(xiàn)binder通信功能 | |
火車票 | 實名binder對象 | |
站臺票 | 匿名binder對象 | |
鐵道部 | service manager | |
檢票口 | binder driver |
1.假如把進(jìn)入候車室這個功能比喻成實現(xiàn)binder通信這個功能,那么:
2.火車票和站臺票都可以進(jìn)入候車室,也就是說實名binder和匿名binder都可以完成進(jìn)程間通信功能,這點并沒有什么區(qū)別。
3.由于火車票是實名制的,所以鐵道部能知道賣出的票和購買人的***一一對應(yīng);但是對于站臺票,鐵道部并不能知道這種對應(yīng)關(guān)系;
那對于service manager和實名binder,匿名binder也是這種關(guān)系 -- service mangager清楚的知道所有實名binder的名稱,binder服務(wù)所在的進(jìn)程等等信息,但是對于匿名binder卻一無所知,它甚至不知道匿名binder的存在。
4.購買站臺票不是想買就可以買的,需要持有火車票吃可以購買站臺票;
那對于實名binder和匿名binder也是如此,匿名binder不是想創(chuàng)建就能創(chuàng)建的,首先需要得到一個實名binder,通過實名binder得到匿名binder,具體例子可以參考bindService得到一個匿名binder的實現(xiàn)。
5.對于檢票口,不管是火車票還是站臺票都會從檢票口通過,所以檢票口可以記錄一些信息;同樣,對于binder driver,不管是實名binder還是匿名binder都會通過binder driver,binder driver也會記錄它們的信息。
六. binder ioctl指令
ioctl指令名稱 | 含義 | 注釋 |
BINDER_WRITE_READ | 最重要的ioctl指令,后面可以執(zhí)行很多binder命令操作。 | 獨特的先寫后讀的設(shè)計,給予了用戶空間程序更多的便利。 |
BINDER_SET_IDLE_TIMEOUT | 暫未使用 | |
BINDER_SET_MAX_THREADS | 設(shè)置binder driver可以請求用戶空間進(jìn)程最大線程數(shù)。 | 不包括用戶空間進(jìn)程主動注冊到binder driver的線程。 |
BINDER_SET_IDLE_PRIORITY | 暫未使用 | |
BINDER_SET_CONTEXT_MGR | 通知binder driver,當(dāng)前進(jìn)程成為binder機(jī)制上下文,也就是service mangager | binder driver里面只能存在一個service manager,多次調(diào)用會出錯。 |
BINDER_THREAD_EXIT | 通知binder driver線程退出 | |
BINDER_VERSION | 返回當(dāng)前binder driver版本號 |
七. binder命令
binder命令按照命令的流向性分為兩大類:
1.BC_XXX
2.BR_XXX
從用戶空間流向binder driver的命令被稱為BC_XXX,也就是binder command的簡稱;相應(yīng)的從binder driver流向用戶空間進(jìn)程的稱為BR_XXX,也就是binder return的簡稱。如下圖:
對于所有的binder 命令,可以用下面兩張表來描述:
具體可以參考./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命令之一,一般通過ioctl--BINDER_WRITE_READ來和binder driver交互。 |
BC_REPLY | 回復(fù)binder driver | 比如addService的時候,service manager在處理完自己的邏輯后會發(fā)送此命令到binder driver,告訴binder driver自己處理結(jié)果。 |
BC_ACQUIRE_RESULT | 暫不支持 | |
BC_FREE_BUFFER | 通知binder driver去釋放一個binder_buff的內(nèi)存,參數(shù)int表示此binder_buff在用戶空間進(jìn)程的虛擬映射地址。 | 一般是在處理完一個事務(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ā)出。 | 因為binder driver在請求service進(jìn)程增加一個service組件的強(qiáng)引用之后,它需要等待service組件增加強(qiáng)引用計數(shù)的結(jié)果,它需要根據(jù)這個結(jié)果修改自己的一些狀態(tài)。 |
BC_ATTEMPT_ACQUIRE | 暫不支持 | |
BC_REGISTER_LOOPER | 通知binder driver此進(jìn)程進(jìn)入BINDER_LOOPER_STATE_REGISTERED狀態(tài),再經(jīng)過一些處理就會進(jìn)入就緒狀態(tài),可以處理進(jìn)程的事務(wù)。 此命令是binder driver通知用戶空間進(jìn)程創(chuàng)建線程后,用戶空間進(jìn)程創(chuàng)建線程后會調(diào)用此命令,通知binder driver此線程已經(jīng)準(zhǔn)備好。 | |
BC_ENTER_LOOPER | 用戶空間進(jìn)程主動請求binder driver通知此線程可以處理進(jìn)程間binder 通信請求,一般如果沒有事情做的話,會進(jìn)入等待狀態(tài)。 | 此命令和BC_REGISTER_LOOPER的區(qū)別就是 BC_ENTER_LOOPER是用戶空間進(jìn)程主動通知binder driver的, BC_REGISTER_LOOPER是binder driver發(fā)現(xiàn)此用戶空間進(jìn)程的線程池?zé)o法響應(yīng)binder通信,需要創(chuàng)建新線程;然后向目標(biāo)用戶空間進(jìn)程發(fā)出請求創(chuàng)建線程命令 用戶空間進(jìn)程創(chuàng)建線程完畢后,會調(diào)用BC_REGISTER_LOOPER通知binder driver。 |
BC_EXIT_LOOPER | 通知binder driver此線程退出 | |
BC_REQUEST_DEATH_NOTIFICATION | client請求binder driver注冊目標(biāo)service組件的死亡通知 | 以便在目標(biāo)serive組件死亡的時候得到通知,然后client可以處理自己的邏輯。 |
BC_CLEAR_DEATH_NOTIFICATION | client通知binder driver取消注冊對某個service binder本地對象的死亡通知監(jiān)聽 | |
BC_DEAD_BINDER_DONE | client通知binder driver對某個service進(jìn)程的binder本地對象死亡通知處理完畢。 |
4.BR_XXX
命令名稱 | 含義 | 注釋 |
BR_ERROR | 通知用戶空間進(jìn)程,binder driver處理出現(xiàn)異常 | |
BR_OK | 通知用戶空間進(jìn)程,binder driver處理成功 | |
BR_TRANSACTION | binder driver請求用戶空間進(jìn)程處理一個事務(wù),事務(wù)的數(shù)據(jù)方法binder_transaction_data結(jié)構(gòu)體中, | 比如addService的時候,binder driver請求service manager去注冊一個service。 |
BR_REPLY | binder driver通知用戶空間進(jìn)程處理完畢 | 比如用戶空間進(jìn)程發(fā)起的BC_TRANSACTION 處理完畢后,binder driver就會反饋BR_REPLY |
BR_ACQUIRE_RESULT | 暫不支持 | |
BR_DEAD_REPLY | binder driver反饋目標(biāo)binder對象已經(jīng)死亡,返回錯誤。 | |
BR_TRANSACTION_COMPLETE | binder driver反饋事務(wù)處理完成 | |
BR_INCREFS | binder driver請求用戶空間進(jìn)程增加指定binder本地對象的弱引用 | |
BR_ACQUIRE | binder driver請求用戶空間進(jìn)程增加指定binder本地對象的強(qiáng)引用 | |
BR_RELEASE | binder driver請求用戶空間進(jìn)程減少指定binder本地對象的強(qiáng)引用 | |
BR_DECREFS | binder driver請求用戶空間進(jìn)程減少指定binder本地對象的弱引用 | |
BR_ATTEMPT_ACQUIRE | 暫不支持 | |
BR_NOOP | 沒有什么操作 | |
BR_SPAWN_LOOPER | binder driver請求用戶空間進(jìn)程分配一個線程;這種情況一般是在用戶空間進(jìn)程線程池?zé)o法處理binder driver間通信請求的情況下。 | |
BR_FINISHED | 暫不支持 | |
BR_DEAD_BINDER | 通知用戶空間進(jìn)程所監(jiān)聽的binder本地對象已經(jīng)銷毀 | |
BR_CLEAR_DEATH_NOTIFICATION_DONE | 在用戶空間進(jìn)程請求BC_CLEAR_DEATH_NOTIFICATION命令后,binder driver返回這個命令通知用戶空間進(jìn)程 | |
BR_FAILED_REPLY | binder driver返回失敗 | |
八. 引用計數(shù)
在第七點的表中,我們提到了所有的Binder協(xié)議命令,其中包括類似BC_INCREFS,BC_ACQUIRE,BC_RELEASE,BC_DECREFS之類的命令,表中解釋是維護(hù)binder對象的引用計數(shù);那為什么要進(jìn)行這樣的設(shè)計呢?
那我們可以來做這樣一種假設(shè):
client進(jìn)程引用service進(jìn)程的一個binder本地對象正在通信,如果這個時候service進(jìn)程把這個binder本地對象回收了怎么辦?
為了解決這個問題,binder機(jī)制使用了引用的概念:
在Java里面,我們知道維護(hù)一個對象的生命周期可以通過強(qiáng)引用,軟引用,弱引用和虛引用來實現(xiàn)(具體的區(qū)別大家可以百度,里面一些區(qū)別和技巧還是很有用的,特別是軟引用用來實現(xiàn)圖片的緩存),只要一個對象被從垃圾回收的根節(jié)點強(qiáng)引用所關(guān)聯(lián),那么它是不會被回收的。
所以,類似的,binder機(jī)制里面也采用這個概念。
那,binder driver為什么不直接引用binder 本地對象呢?
這是因為binder driver是在內(nèi)核空間,binder本地對象在service進(jìn)程的用戶空間,不能直接引用。
所以,binder 機(jī)制才通過這種通過命令調(diào)用的方式,通知service進(jìn)程為指定的binder本地對象增加/減少引用,從而達(dá)到維護(hù)用戶空間service進(jìn)程binder本地對象生命周期的目的。
九. 死亡通知機(jī)制
通過上面幾點介紹,一到七點保證了binder間進(jìn)程通信,第八點保證了生命周期管理,一切看起來都那么完美。
但是,還是有意外情況發(fā)生,那就是:
提供服務(wù)的service進(jìn)程死亡了怎么辦?
對應(yīng)這個問題,client和binder driver都愛莫能助,因為它們也無法控制service進(jìn)程的生命周期。又回到了第八點闡述的那個問題:
client進(jìn)程引用service進(jìn)程的一個binder本地對象正在通信,如果service進(jìn)程的binder本地對象不存在了怎么辦?
對于service進(jìn)程死亡,一般可以分為兩種情況:
1.正常死亡,比如程序自己退出
2.異常退出,比如因為程序里面的一個邏輯錯誤導(dǎo)致進(jìn)程退出
如果是第1種情形,程序會自己主動close掉自己進(jìn)程打開的binder driver;從而調(diào)用到binder driver的binder_release函數(shù)。
如果是第2種情形,操作系統(tǒng)會幫我們close,從而也可以調(diào)用binder driver的binder_release函數(shù)。
所以,上面兩種可能都可以在binder driver的binder_release函數(shù)中去解決。
binder 機(jī)制死亡通知的過程是這樣的:
a.client進(jìn)程拿到指向service進(jìn)程binder本地對象的引用后,它可以向這個service進(jìn)程binder本地對象請求注冊一個死亡通知(其實就是BpBinder,因為它實現(xiàn)了死亡通知的接口)。
b.binder driver記錄下了這層對應(yīng)關(guān)系。
c.當(dāng)binder driver檢測到目標(biāo)service進(jìn)程已經(jīng)死亡時,它找到這個進(jìn)程所有binder本地對象在binder driver里面對應(yīng)的binder實體對象。
d.然后根據(jù)binder實體對象找到所有引用它的binder引用對象,如果發(fā)現(xiàn)binder引用對象有注冊死亡通知,那么就封裝一個binder_work項給binder引用對象所在的進(jìn)程,然后喚醒它;讓那個進(jìn)程去完成自己的邏輯。
至此,binder設(shè)計篇內(nèi)容全部提供完畢,下面會寫一些binder實現(xiàn)篇的東西,也就是從代碼的角度來分析這些內(nèi)容。
當(dāng)前文章:3.Androidbinder設(shè)計篇
當(dāng)前地址:http://jinyejixie.com/article40/ipjdho.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供靜態(tài)網(wǎng)站、網(wǎng)站改版、軟件開發(fā)、網(wǎng)站導(dǎo)航、做網(wǎng)站、響應(yīng)式網(wǎng)站
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)