一篇文章瞭解相見恨晚的 Android Binder 進程間通信

概述

最近在學習 Binder 機制,在網上查閱了大量的資料,也看了老羅的 Binder 系列的博客和 Innost 的深刻理解 Binder 系列的博客,都是從底層開始講的,全是 C 代碼,雖然以前學過 C 和 C++,然而各類函數之間花式跳轉,看的我都懷疑人生。絕不誇張的講每看一遍都是新的內容,跟沒看過同樣。後來又看到了 Gityuan 的博客看到了一些圖解彷彿發現了新大陸。
2019秋招必備面試題彙總+阿里P6P7安卓進階資料分享
下面就以圖解的方式介紹下 Binder 機制,相信你看這篇文章,必定有所收穫。node

Binder進程間通訊原理 視頻詳解 須要密碼私聊我便可
連接: https://share.weiyun.com/5GOZsQF

什麼是 Binder?

Binder 是 Android 系統中進程間通信(IPC)的一種方式,也是 Android 系統中最重要的特性之一。Android 中的四大組件 Activity,Service,Broadcast,ContentProvider,不一樣的 App 等都運行在不一樣的進程中,它是這些進程間通信的橋樑。正如其名「粘合劑」同樣,它把系統中各個組件粘合到了一塊兒,是各個組件的橋樑。面試

理解 Binder 對於理解整個 Android 系統有着很是重要的做用,若是對 Binder 不瞭解,就很難對 Android 系統機制有更深刻的理解。緩存

1. Binder 架構

  • Binder 通訊採用 C/S 架構,從組件視角來講,包含 Client、 Server、 ServiceManager 以及 Binder 驅動,其中 ServiceManager 用於管理系統中的各類服務。
  • Binder 在 framework 層進行了封裝,經過 JNI 技術調用 Native(C/C++)層的 Binder 架構。
  • Binder 在 Native 層以 ioctl 的方式與 Binder 驅動通信。

2. Binder 機制

  • 首先須要註冊服務端,只有註冊了服務端,客戶端纔有通信的目標,服務端經過 ServiceManager 註冊服務,註冊的過程就是向 Binder 驅動的全局鏈表 binder_procs 中插入服務端的信息(binder_proc 結構體,每一個 binder_proc 結構體中都有 todo 任務隊列),而後向 ServiceManager 的 svcinfo 列表中緩存一下注冊的服務。
  • 有了服務端,客戶端就能夠跟服務端通信了,通信以前須要先獲取到服務,拿到服務的代理,也能夠理解爲引用。好比下面的代碼:安全

    //獲取WindowManager服務引用WindowManager wm = (WindowManager)getSystemService(getApplication().WINDOW_SERVICE);

    獲取服務端的方式就是經過 ServiceManager 向 svcinfo 列表中查詢一下返回服務端的代理,svcinfo 列表就是全部已註冊服務的通信錄,保存了全部註冊的服務信息。網絡

  • 有了服務端的引用咱們就能夠向服務端發送請求了,經過 BinderProxy 將咱們的請求參數發送給 ServiceManager,經過共享內存的方式使用內核方法 copy_from_user() 將咱們的參數先拷貝到內核空間,這時咱們的客戶端進入等待狀態,而後 Binder 驅動向服務端的 todo 隊列裏面插入一條事務,執行完以後把執行結果經過 copy_to_user() 將內核的結果拷貝到用戶空間(這裏只是執行了拷貝命令,並無拷貝數據,binder只進行一次拷貝),喚醒等待的客戶端並把結果響應回來,這樣就完成了一次通信。

怎麼樣是否是很簡單,以上就是 Binder 機制的主要通信方式,下面咱們來看看具體實現。架構

3. 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 鏈表保存了服務端的進程信息。

4. Binder 進程與線程

對於底層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 線程來處理的。

5. ServiceManager 啓動

瞭解了 Binder 驅動,怎麼與 Binder 驅動進行通信呢?那就是經過 ServiceManager,好多文章稱 ServiceManager 是 Binder 驅動的守護進程,大管家,其實 ServiceManager 的做用很簡單就是提供了查詢服務和註冊服務的功能。下面咱們來看一下 ServiceManager 啓動的過程。

  • ServiceManager 分爲 framework 層和 native 層,framework 層只是對 native 層進行了封裝方便調用,圖上展現的是 native 層的 ServiceManager 啓動過程。
  • ServiceManager 的啓動是系統在開機時,init 進程解析 init.rc 文件調用 service_manager.c 中的 main() 方法入口啓動的。native 層有一個 binder.c 封裝了一些與 Binder 驅動交互的方法。
  • ServiceManager 的啓動分爲三步,首先打開驅動建立全局鏈表 binder_procs,而後將本身當前進程信息保存到 binder_procs 鏈表,最後開啓 loop 不斷的處理共享內存中的數據,並處理 BR_xxx 命令(ioctl 的命令,BR 能夠理解爲 binder reply 驅動處理完的響應)。

6. ServiceManager 註冊服務

  • 註冊 MediaPlayerService 服務端,咱們經過 ServiceManager 的 addService() 方法來註冊服務。
  • 首先 ServiceManager 向 Binder 驅動發送 BC_TRANSACTION 命令(ioctl 的命令,BC 能夠理解爲 binder client 客戶端發過來的請求命令)攜帶 ADD_SERVICE_TRANSACTION 命令,同時註冊服務的線程進入等待狀態 waitForResponse()。Binder 驅動收到請求命令向 ServiceManager 的 todo 隊列裏面添加一條註冊服務的事務。事務的任務就是建立服務端進程 binder_node 信息並插入到 binder_procs 鏈表中。
  • 事務處理完以後發送 BR_TRANSACTION 命令,ServiceManager 收到命令後向 svcinfo 列表中添加已經註冊的服務。最後發送 BR_REPLY 命令喚醒等待的線程,通知註冊成功。

7. ServiceManager 獲取服務

  • 獲取服務的過程與註冊相似,相反的過程。經過 ServiceManager 的 getService() 方法來註冊服務。
  • 首先 ServiceManager 向 Binder 驅動發送 BC_TRANSACTION 命令攜帶 CHECK_SERVICE_TRANSACTION 命令,同時獲取服務的線程進入等待狀態 waitForResponse()。
  • Binder 驅動收到請求命令向 ServiceManager 的發送 BC_TRANSACTION 查詢已註冊的服務,查詢到直接響應 BR_REPLY 喚醒等待的線程。若查詢不到將與 binder_procs 鏈表中的服務進行一次通信再響應。

8. 進行一次完整通信

  • 咱們在使用 Binder 時基本都是調用 framework 層封裝好的方法,AIDL 就是 framework 層提供的傻瓜式是使用方式。假設服務已經註冊完,咱們來看看客戶端怎麼執行服務端的方法。
  • 首先咱們經過 ServiceManager 獲取到服務端的 BinderProxy 代理對象,經過調用 BinderProxy 將參數,方法標識(例如:TRANSACTION_test,AIDL中自動生成)傳給  ServiceManager,同時客戶端線程進入等待狀態。
  • ServiceManager 將用戶空間的參數等請求數據複製到內核空間,並向服務端插入一條執行執行方法的事務。事務執行完通知 ServiceManager 將執行結果從內核空間複製到用戶空間,並喚醒等待的線程,響應結果,通信結束。

總結

好了,這裏只是從實現邏輯上簡單介紹了下 Binder 機制的工做原理,想要深刻理解 Binder 機制,還得本身下功夫,看源碼,儘管這個過程很痛苦。一遍看不懂就再來一遍,說實話本人理解能力比較差,跟着博客思路看了不下十遍。努力總會有收穫,好好欣賞 native 層各方法之間花式跳轉的魅力吧。最後你將發現新世界的大門在向你敞開。

網上資料不少,我的以爲比較好的以下:

  1. Bander設計與實現
  2. 老羅的 Android進程間通訊(IPC)機制Binder簡要介紹和學習計劃 系列
  3. Innost的 深刻理解Binder 系列
  4. Gityuan的 Binder系列 (基於 Android 6.0)
  5. Binder學習指南
Binder進程間通訊原理 視頻詳解 須要密碼私聊我便可
連接: https://share.weiyun.com/5GOZsQF

2019秋招必備面試題彙總+阿里P6P7安卓進階資料分享

相關文章
相關標籤/搜索