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