https://www.cnblogs.com/dirt2/p/5537288.html
多線程部分
BR_SPAWN_LOOPER
首先要管理線程池就要知道池子有多大,應用程序通過INDER_SET_MAX_THREADS告訴驅動最多可以創建幾個線程。以后每個線程在創建,進入主循環,退出主循環時都要分別使用BC_REGISTER_LOOP,BC_ENTER_LOOP,BC_EXIT_LOOP告知驅動,以便驅動收集和記錄當前線程池的狀態。每當驅動接收完數據包返回讀Binder的線程時,都要檢查一下是不是已經沒有閑置線程了。如果是,而且線程總數不會超出線程池最大線程數,就會在當前讀出的數據包后面再追加一條BR_SPAWN_LOOPER消息,告訴用戶線程即將不夠用了,請再啟動一些,否則下一個請求可能不能及時響應。新線程一啟動又會通過BC_xxx_LOOP告知驅動更新狀態。這樣只要線程沒有耗盡,總是有空閑線程在等待隊列中隨時待命,及時處理請求。
關於工作線程的啟動,Binder驅動還做了一點小小的優化。當進程P1的線程T1向進程P2發送請求時,驅動會先查看一下線程T1是否也正在處理來自P2某個線程請求但尚未完成(沒有發送回復)。這種情況通常發生在兩個進程都有Binder實體並互相對發時請求時。假如驅動在進程P2中發現了這樣的線程,比如說T2,就會要求T2來處理T1的這次請求。因為T2既然向T1發送了請求尚未得到返回包,說明T2肯定(或將會)阻塞在讀取返回包的狀態。這時候可以讓T2順便做點事情,總比等在那里閑着好。而且如果T2不是線程池中的線程還可以為線程池分擔部分工作,減少線程池使用率。
8 數據包接收隊列與(線程)等待隊列管理
通常數據傳輸的接收端有兩個隊列:數據包接收隊列和(線程)等待隊列,用以緩解供需矛盾。當超市里的進貨(數據包)太多,貨物會堆積在倉庫里;購物的人(線程)太多,會排隊等待在收銀台,道理是一樣的。在驅動中,每個進程有一個全局的接收隊列,也叫to-do隊列,存放不是發往特定線程的數據包;相應地有一個全局等待隊列,所有等待從全局接收隊列里收數據的線程在該隊列里排隊。每個線程有自己私有的to-do隊列,存放發送給該線程的數據包;相應的每個線程都有各自私有等待隊列,專門用於本線程等待接收自己to-do隊列里的數據。雖然名叫隊列,其實線程私有等待隊列中最多只有一個線程,即它自己。
由於發送時沒有特別標記,驅動怎么判斷哪些數據包該送入全局to-do隊列,哪些數據包該送入特定線程的to-do隊列呢?這里有兩條規則。規則1:Client發給Server的請求數據包都提交到Server進程的全局to-do隊列。不過有個特例,就是上節談到的Binder對工作線程啟動的優化。經過優化,來自T1的請求不是提交給P2的全局to-do隊列,而是送入了T2的私有to-do隊列。規則2:對同步請求的返回數據包(由BC_REPLY發送的包)都發送到發起請求的線程的私有to-do隊列中。如上面的例子,如果進程P1的線程T1發給進程P2的線程T2的是同步請求,那么T2返回的數據包將送進T1的私有to-do隊列而不會提交到P1的全局to-do隊列。