進程的Binder線程池工做過程

基於Android 6.0源碼剖析,分析Binder線程池以及binder線程啓動過程。
git

一. 概述架構

Android系統啓動完成後,ActivityManager, PackageManager等各大服務都運行在system_server進程,app應用須要使用系統服務都是經過binder來完成進程之間的通訊,那對於binder線程是如何管理的呢,又是如何建立的呢?其實不管是system_server進程,仍是app進程,都是在進程fork完成後,便會在新進程中執行onZygoteInit()的過程當中,啓動binder線程池。接下來,就以此爲起點展開從線程的視角來看看binder的世界。app

二. Binder線程建立

Binder線程建立與其所在進程的建立中產生,Java層進程的建立都是經過Process.start()方法,向Zygote進程發出建立進程的socket消息,Zygote收到消息後會調用Zygote.forkAndSpecialize()來fork出新進程,在新進程中會調用到RuntimeInit.nativeZygoteInit方法,該方法通過jni映射,最終會調用到app_main.cpp中的onZygoteInit,那麼接下來從這個方法提及。socket

2.1 onZygoteInit

[-> app_main.cpp]async

ProcessState::self()是單例模式,主要工做是調用open()打開/dev/binder驅動設備,再利用mmap()映射內核的地址空間,將Binder驅動的fd賦值ProcessState對象中的變量mDriverFD,用於交互操做。startThreadPool()是建立一個新的binder線程,不斷進行talkWithDriver()。函數

 

2.2 PS.startThreadPooloop

[-> ProcessState.cpp]編碼

啓動Binder線程池後, 則設置mThreadPoolStarted=true. 經過變量mThreadPoolStarted來保證每一個應用進程只容許啓動一個binder線程池, 且本次建立的是binder主線程(isMain=true). 其他binder線程池中的線程都是由Binder驅動來控制建立的。spa

 

2.3 PS.spawnPooledThread

[-> ProcessState.cpp]線程

2.3.1 makeBinderThreadName

[-> ProcessState.cpp]

獲取Binder線程名,格式爲Binder_x, 其中x爲整數。每一個進程中的binder編碼是從1開始,依次遞增; 只有經過spawnPooledThread方法來建立的線程才符合這個格式,對於直接將當前線程經過joinThreadPool加入線程池的線程名則不符合這個命名規則。 另外,目前Android N中Binder命令已改成Binder:_x格式, 則對於分析問題頗有幫忙.

 

2.3.2 PoolThread.run

[-> ProcessState.cpp]

從函數名看起來是建立線程池,其實就只是建立一個線程,該PoolThread繼承Thread類。t->run()方法最終調用 PoolThread的threadLoop()方法。

2.4 IPC.joinThreadPool

[-> IPCThreadState.cpp]

  • 對於isMain=true的狀況下, command爲BC_ENTER_LOOPER,表明的是Binder主線程,不會退出的線程;
  • 對於isMain=false的狀況下,command爲BC_REGISTER_LOOPER,表示是由binder驅動建立的線程。

2.5 processPendingDerefs

[-> IPCThreadState.cpp]

2.6 getAndExecuteCommand

[-> IPCThreadState.cpp]

2.7 talkWithDriver

在這裏調用的isMain=true,也就是向mOut例如寫入的即是BC_ENTER_LOOPER. 通過talkWithDriver(), 接下來程序往哪進行呢?從binder_thread_write()往下說BC_ENTER_LOOPER的處理過程。
2.7.1 binder_thread_write

[-> binder.c]

當發生如下3種狀況之一,便會進入done:

  • 當前線程的return_error發生錯誤的狀況;
  • 當Binder驅動向客戶端發送死亡通知的狀況;
  • 當類型爲BINDER_WORK_TRANSACTION(即收到命令是BC_TRANSACTION或BC_REPLY)的狀況;

任何一個Binder線程當同時知足如下條件,則會生成用於建立新線程的BR_SPAWN_LOOPER命令:

  1. 當前進程中沒有請求建立binder線程,即requested_threads = 0;
  2. 當前進程沒有空閒可用的binder線程,即ready_threads = 0;(線程進入休眠狀態的個數就是空閒線程數)
  3. 當前進程已啓動線程個數小於最大上限(默認15);
  4. 當前線程已接收到BC_ENTER_LOOPER或者BC_REGISTER_LOOPER命令,即當前處於BINDER_LOOPER_STATE_REGISTERED或者BINDER_LOOPER_STATE_ENTERED狀態。【小節2.6】已設置狀態爲BINDER_LOOPER_STATE_ENTERED,顯然這條件是知足的。

從system_server的binder線程一直的執行流:IPC.joinThreadPool - > IPC.getAndExecuteCommand() - > IPC.talkWithDriver(),但talkWithDriver收到事務以後,便進入IPC.executeCommand(),接下來,從executeCommand提及。

2.8 IPC.executeCommand

Binder主線程的建立是在其所在的進程建立的過程一塊兒建立的,後面再建立的普通binder線程是由spawnPooledThread(false)方法所建立的。

 

2.9思考

默認地,每一個進程的binder線程池的線程個數上限爲15,該上限不統計經過BC_ENTER_LOOPER命令建立的binder主線程,只計算BC_REGISTER_LOOPER命令建立的線程對此,或者不少人不理解,例栗子:某個進程的主線程執行以下方法,那麼該進程可建立的binder線程個數上限是多少呢?

首先線程池的binder線程個數上限爲6個,經過startThreadPool()建立的主線程不在最大線程上限,最後一句是將當前線程成爲binder線程,因此說可建立的binder線程個數上限爲8 ,若是還不理解,建議再多看看這幾個方案的源碼,多思考整個binder架構。

 

三。總結

Binder設計架構中,只有第一個Binder主線程(也就是Binder_1線程)是由應用程序主動建立,Binder線程池的普通線程都是由Binder驅動根據IPC通訊需求建立,Binder線程的建立流程圖:

每次由Zygote fork出新進程的過程當中,伴隨着建立binder線程池,調用spawnPooledThread來建立binder主線程。當線程執行binder_thread_read的過程當中,發現當前沒有空閒線程,沒有請求建立線程,且沒有達到上限,則建立新的binder線程。

Binder的交易有3種類型:

  1. 調用:發起進程的線程不必定是在Binder線程,大多數狀況下,接收者只指向進程,並不肯定會有哪一個線程來處理,因此不指定線程;
  2. 答覆:發起者必定是binder線程,而且接收者線程即是上次call時的發起線程(該線程不必定是binder線程,能夠是任意線程)。
  3. async:與調用類型差很少,惟一不一樣的是async是oneway方式不須要回復,發起進程的線程不必定是在Binder線程,接收者只指向進程,而且不肯定會有哪一個線程來處理,因此不指定線程。

Binder系統中可分爲3類binder線程:

  • Binder主線程:進程建立過程會調用startThreadPool()過程當中再進入spawnPooledThread(true),來建立Binder主線程。編號從1開始,也就是意味着binder主線程名爲binder_1,而且主線程是不會退出的。
  • Binder普通線程:是由Binder Driver來根據是否有空閒的binder線程來決定是否建立binder線程,回調spawnPooledThread(false),isMain = false,該線程名格式爲binder_x。
  • Binder其餘線程其餘線程是指並無調用spawnPooledThread方法,而是直接調用IPC.joinThreadPool(),將當前線程直接加入binder線程隊列。例如:mediaserver和servicemanager的主線程都是binder線程,但system_server的主線程並不是binder線程。

 

 

 

做者:MIUI資深工程師-袁輝輝

我的博客:gityuan.com

 

更多內容能夠關注小米開放平臺訂閱號:

官方QQ交流羣:398616987
想要了解更多?
那就關注咱們吧!

相關文章
相關標籤/搜索