3. Android binder設計篇


一. 引言--女媧造人的故事

在天地混沌之際,上神女媧因爲覺得自己太孤單,沒人跟它一起嗨,決定按照自己的模樣添加一些生物;於是呢,捏泥爲人,並賦予了人生育的能力,所以女媧被稱爲了人類的母親;

神話故事很美好,解釋了人類的來源,但是這個邏輯中其實有個缺陷,就是女媧從哪裏來的?

那有些同學就會問了,這裏說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的關係圖。

wKioL1bIXa-xulcBAAC_jRIUukA426.png


這張圖已經基本包括了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_objectbinder_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_threadbinder_thread是線程在binder driver中的描述,所以binder_proc和binder_thread的對應關係也是1對多,也是用紅黑樹來組織的。
binder_transaction_databinder_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_workbinder driver的工作項描述,後面再具體描述。
binder_write_readbinder_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 mangagerbinder 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的簡稱。如下圖:

wKioL1bPrNiiL1NRAAA9E7-cooA161.png


對於所有的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_TRANSACTIONbinder 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_COMPLETEbinder 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_REPLYbinder 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實現篇的東西,也就是從代碼的角度來分析這些內容。



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章