最近在學習 Binder 機制,在網上查閱了大量的資料,也看了老羅的 Binder 系列的博客和 Innost 的深刻理解 Binder 系列的博客,都是從底層開始講的,全是 C 代碼,雖然以前學過 C 和 C++,然而各類函數之間花式跳轉,看的我都懷疑人生。絕不誇張的講每看一遍都是新的內容,跟沒看過同樣。後來又看到了 Gityuan 的博客看到了一些圖解彷彿發現了新大陸。
2019秋招必備面試題彙總+阿里P6P7安卓進階資料分享
下面就以圖解的方式介紹下 Binder 機制,相信你看這篇文章,必定有所收穫。node
Binder進程間通訊原理 視頻詳解 須要密碼私聊我便可
連接: https://share.weiyun.com/5GOZsQF
Binder 是 Android 系統中進程間通信(IPC)的一種方式,也是 Android 系統中最重要的特性之一。Android 中的四大組件 Activity,Service,Broadcast,ContentProvider,不一樣的 App 等都運行在不一樣的進程中,它是這些進程間通信的橋樑。正如其名「粘合劑」同樣,它把系統中各個組件粘合到了一塊兒,是各個組件的橋樑。面試
理解 Binder 對於理解整個 Android 系統有着很是重要的做用,若是對 Binder 不瞭解,就很難對 Android 系統機制有更深刻的理解。緩存
有了服務端,客戶端就能夠跟服務端通信了,通信以前須要先獲取到服務,拿到服務的代理,也能夠理解爲引用。好比下面的代碼:安全
//獲取WindowManager服務引用WindowManager wm = (WindowManager)getSystemService(getApplication().WINDOW_SERVICE);
獲取服務端的方式就是經過 ServiceManager 向 svcinfo 列表中查詢一下返回服務端的代理,svcinfo 列表就是全部已註冊服務的通信錄,保存了全部註冊的服務信息。網絡
怎麼樣是否是很簡單,以上就是 Binder 機制的主要通信方式,下面咱們來看看具體實現。架構
咱們先來了解下用戶空間與內核空間是怎麼交互的。ide
先了解一些概念函數
詳細解釋能夠參考 Kernel Space Definition;簡單理解以下:oop
Kernel space 是 Linux 內核的運行空間,User space 是用戶程序的運行空間。爲了安全,它們是隔離的,即便用戶的程序崩潰了,內核也不受影響。學習
Kernel space 能夠執行任意命令,調用系統的一切資源;User space 只能執行簡單的運算,不能直接調用系統資源,必須經過系統接口(又稱 system call),才能向內核發出指令。
雖然從邏輯上抽離出用戶空間和內核空間;可是不可避免的的是,總有那麼一些用戶空間須要訪問內核的資源;好比應用程序訪問文件,網絡是很常見的事情,怎麼辦呢?
Kernel space can be accessed by user processes only through the use of system calls.
用戶空間訪問內核空間的惟一方式就是系統調用;經過這個統一入口接口,全部的資源訪問都是在內核的控制下執行,以避免致使對用戶程序對系統資源的越權訪問,從而保障了系統的安全和穩定。用戶軟件參差不齊,要是它們亂搞把系統玩壞了怎麼辦?所以對於某些特權操做必須交給安全可靠的內核來執行。
當一個任務(進程)執行系統調用而陷入內核代碼中執行時,咱們就稱進程處於內核運行態(或簡稱爲內核態)此時處理器處於特權級最高的(0級)內核代碼中執行。當進程在執行用戶本身的代碼時,則稱其處於用戶運行態(用戶態)。即此時處理器在特權級最低的(3級)用戶代碼中運行。處理器在特權等級高的時候才能執行那些特權CPU指令。
經過系統調用,用戶空間能夠訪問內核空間,那麼若是一個用戶空間想與另一個用戶空間進行通訊怎麼辦呢?很天然想到的是讓操做系統內核添加支持;傳統的 Linux 通訊機制,好比 Socket,管道等都是內核支持的;可是 Binder 並非 Linux 內核的一部分,它是怎麼作到訪問內核空間的呢?Linux 的動態可加載內核模塊(Loadable Kernel Module,LKM)機制解決了這個問題;模塊是具備獨立功能的程序,它能夠被單獨編譯,但不能獨立運行。它在運行時被連接到內核做爲內核的一部分在內核空間運行。這樣,Android系統能夠經過添加一個內核模塊運行在內核空間,用戶進程之間的經過這個模塊做爲橋樑,就能夠完成通訊了。
在 Android 系統中,這個運行在內核空間的,負責各個用戶進程經過 Binder 通訊的內核模塊叫作 Binder 驅動;
驅動程序通常指的是設備驅動程序(Device Driver),是一種可使計算機和設備通訊的特殊程序。至關於硬件的接口,操做系統只有經過這個接口,才能控制硬件設備的工做;
驅動就是操做硬件的接口,爲了支持 Binder 通訊過程,Binder 使用了一種「硬件」,所以這個模塊被稱之爲驅動。
熟悉了上面這些概念,咱們再來看下上面的圖,用戶空間中 binder_open(), binder_mmap(), binder_ioctl() 這些方法經過 system call 來調用內核空間 Binder 驅動中的方法。內核空間與用戶空間共享內存經過 copy_from_user(), copy_to_user() 內核方法來完成用戶空間與內核空間內存的數據傳輸。Binder驅動中有一個全局的 binder_procs 鏈表保存了服務端的進程信息。
對於底層Binder驅動,經過 binder_procs 鏈表記錄全部建立的 binder_proc 結構體,binder 驅動層的每個 binder_proc 結構體都與用戶空間的一個用於 binder 通訊的進程一一對應,且每一個進程有且只有一個 ProcessState 對象,這是經過單例模式來保證的。在每一個進程中能夠有不少個線程,每一個線程對應一個 IPCThreadState 對象,IPCThreadState 對象也是單例模式,即一個線程對應一個 IPCThreadState 對象,在 Binder 驅動層也有與之相對應的結構,那就是 Binder_thread 結構體。在 binder_proc 結構體中經過成員變量 rb_root threads,來記錄當前進程內全部的 binder_thread。
Binder 線程池:每一個 Server 進程在啓動時建立一個 binder 線程池,並向其中註冊一個 Binder 線程;以後 Server 進程也能夠向 binder 線程池註冊新的線程,或者 Binder 驅動在探測到沒有空閒 binder 線程時主動向 Server 進程註冊新的的 binder 線程。對於一個 Server 進程有一個最大 Binder 線程數限制,默認爲16個 binder 線程,例如 Android 的 system_server 進程就存在16個線程。對於全部 Client 端進程的 binder 請求都是交由 Server 端進程的 binder 線程來處理的。
瞭解了 Binder 驅動,怎麼與 Binder 驅動進行通信呢?那就是經過 ServiceManager,好多文章稱 ServiceManager 是 Binder 驅動的守護進程,大管家,其實 ServiceManager 的做用很簡單就是提供了查詢服務和註冊服務的功能。下面咱們來看一下 ServiceManager 啓動的過程。
好了,這裏只是從實現邏輯上簡單介紹了下 Binder 機制的工做原理,想要深刻理解 Binder 機制,還得本身下功夫,看源碼,儘管這個過程很痛苦。一遍看不懂就再來一遍,說實話本人理解能力比較差,跟着博客思路看了不下十遍。努力總會有收穫,好好欣賞 native 層各方法之間花式跳轉的魅力吧。最後你將發現新世界的大門在向你敞開。
網上資料不少,我的以爲比較好的以下:
Binder進程間通訊原理 視頻詳解 須要密碼私聊我便可
連接: https://share.weiyun.com/5GOZsQF