Android Binder與服務註冊過程

紀伯倫說:「你沒法同時擁有青春和關於青春的知識;由於青春忙於生計,沒有餘暇去求知;而知識忙於尋求自我,沒法享受生活。」android

序言

跑去圖書館自習了一天,看了一天Binder,效率仍是蠻高的。特別推薦,同時想在之後每篇博文寫幾句文藝或者雞湯或者高逼格的話,提升各種姿式水平吧。回到正題,講講Binder,我將從爲何要有Binder,Binder的底層實現,而後經過一個客戶端調用服務進程的整個過程來進一步闡述其做用。git

Binder用來幹什麼

進程間通訊,嗯?而後你就想知道這些??進程間通訊爲何要藉助一箇中間件,直接不能夠嗎?
來看下Linux內核空間和用戶空間,再慢慢的談談爲何?這裏要先從Linux下的內存空間劃分來說起了。github

圖片描述

Linux中,給每一個用戶進程的空間是4個G,內核一個G,固然這是虛擬的內存,也就是不足的地方是藉助於硬盤來實現虛擬,對於用戶進程,用戶進程空間是不能夠共享的,可是對於內核空間彼此之間是能夠共享的,用戶空間不能夠共享,所以兩個進程之間進行通訊就會有問題了,因此在通訊上要藉助於內核空間來進行通訊。引出來內核了,經過內核進行通訊,具體如何進行呢?若是讓你來設計你會怎麼設計呢?
跟每個進程劃分一塊區域,而後每一個進程對其內存進行loop,有消息後做出反饋將內容發送至對方的內存中,而後。。。感受優雅嗎?可是對於中間部分怎麼尋找,如何定位,內存不多是事先劃分好,動態劃分了,進程間如何知道彼此的內存中的地址,這是一個問題,中間的數據如何進行傳遞,等等問題。算法

再考慮一個問題,什麼樣的進程間須要通訊,不難發現,須要進行通訊的進程通常是可見或不可見進程和服務進程之間進行的通訊,因此咱們須要去找服務進程,而後和它通訊,先看一個例子,當咱們在手機中經過進度條調節手機音量的時候。函數

圖片描述
如今你能夠對Binder有一個這樣的認識,經過它能夠進行進程間通訊,固然Binder是Android在基於Linux上進行一個IPC的新方式,雖爲新方式,也不過是在基於共享內存上進行了更進一步的封裝和優化,並且其不只僅是進行IPC,還能夠RPC,即爲遠程調用,在進程A中能夠像調用本身的函數同樣,調用進程B的函數。oop

Binder的實現機制

既然是藉助於內核空間的一塊內存,既然要進行通訊,彼此之間有數據交流,有哪些數據呢?要找到該進程,而後要讓該進程知道本身調用的方法,而後還要將結果傳遞回來,
IPC數據
圖片描述
Handle即爲所要尋找的服務的編號,RPC數據,即爲咱們在調用函數的時候所要傳遞的參數,RPC代碼即爲咱們的調用代碼,Binder協議,也就是咱們在和內存進行交互的時候,告知其咱們是要接收仍是要發送,而後內核空間給對於Binder管理的這塊區域起了個什麼名字呢?Binder Driver,經過其對Binder進行管理。如今咱們對於進程間通訊有了更進一步的理解。Binder Driver的生成則是在init進程中建立。
圖片描述
如今咱們要更深刻一步來了解這個過程的具體細節了,由於本篇主要是對這個機制進行一個概述,因此不許備經過代碼細節來對該過程進行一個細節化的描述。只講述整個流程。優化

前面提到了,進程間的通訊通常是在和服務進程進行通訊,如今個人一個進程和某個服務進程進行通訊,那麼我給出服務名便可,而後系統如何根據這個服務名找到服務,而後調用服務的相關方法,而後再將結果返回呢?來看看Android中是如何實現的。
回顧上一篇文章中講述的Android啓動流程中,講到的一個Context Manager進程,這個進程在全部的Service啓動以前啓動,而後全部的服務進程須要向其進行註冊,那麼又牽扯到一個問題,既然Context Manager也是一個進程,其它進程向其進行註冊時候不是也須要進程間通訊了,先從Context Manager來看。spa

Context Manager

Context Manager和其它的Android服務不一樣,採用C語言編寫,爲了方便和Binder進行緊密銜接,Context Manager,首先打開Binder Driver,而後在內存中建立一塊內存,用來接收一寫IPC數據,在內存中建立一個Binder節點,將本身置爲0號節點,而後對本身的內存區域進行輪詢,當接收到數據的時候,對其中的數據進行解析,而後根據相應的協議執行相應的操做。Context Manager的主要做用是服務註冊和服務檢索。它給每個服務分配了一個稱爲Handle的編號。這個過程講的比較粗了。設計

從服務註冊和使用流程看Binder

再談Context Manager

Context Manager在mediaserver和system_server以前運行,每當有service server來註冊服務的時候,Context Manager會把服務的名稱和該服務在Binder Driver 中分配的Binder節點編號註冊到自身服務目錄中。Service程序以IPC應答數據的形式結束Context Manager服務目錄中的服務名稱,而後輸出咱們所看到的一系列的服務。server

  • 調用binder_open函數,引發open和mmap的調用,調用open打開Binder Driver,而調用mmap則生成結束IPC數據的Buffer,系統給予其128k的大小用來接收IPC數據。其具體代碼實現,則是經過一個結構體來記錄,而後存放了該塊內存的引用。

  • Context Manager在訪問Binder Driver,將自身的Binder節點設置爲0號節點。

  • 調用loop函數,來輪詢檢測Binder,接收IPC數據,當出現IPC數據後,調用binder_parse,來解析IPC數據。

  • 由於Context Manager的兩個主要做用是服務的檢索和服務的註冊,因此接收到的IPC數據也就是用來作這兩件事情的。

    • 服務檢索:經過RPC數據中傳遞的服務名稱,從do_find_service()函數自身的服務列表中獲取帶有指定名稱的服務編號,然後經過bio_put_ref()函數來生成binder_object結構體,該結構體被包含到IPC引導數據的RPC數據中,而後調用binder_send_reply()函數,將數據傳遞給Binder Driver.

    • 服務註冊:當解析出爲服務註冊的時候,調用do_add_service()函數,將IPC數據的RPC數據包含的服務名稱和Binder節點編號註冊到自身的服務目錄中,而後調用binder_send_reply,將IPC應答數據傳遞給Binder Driver。

咱們對於服務的註冊和檢索,又有了更進一步的瞭解了,如今咱們要更深刻一些。跟具體一些。

服務向Context Manager註冊

當Service Server向Context Manager註冊自身的服務時,Binder Driver會進行Binder Addressing。Binder Driver會首先找到Handle值爲0的Binder節點,Handle值爲0的Binder節點爲Context Manager,而後Binder Driver會生成一個Binder節點,用來表示前來註冊的服務,接下來生成Binder引用數據,以便Context Manager識別所生成的Binder節點,並將其關聯起來,根據生成順序,引用數據會被編號,而後將編號插入到IPC數據,傳遞給Context Manager,Context Manager會根據服務名稱將Binder節點進行關聯,這樣咱們服務註冊過程便完成了。

調用服務

首先是Handle值爲0的IPC數據通過Binder Driver傳遞至Context Manager,Context Manager根據服務編號查找對應的引用數據,而後在服務客戶端生成引用數據,並將其和ConText Manager的引用數據所指向的Binder節點鏈接起來,鏈接後的Binder節點和Service Server自身服務的Binder節點相對應,Binder Driver將根據生成順序爲引用數據編號,並傳遞給服務客戶端,服務端將引用數據編號保存到Handle中,把與服務相關的RPC代碼,RPC函數包含進IPC數據中,發送給Service Sever。而後Service server在和其進行數據交互。

經過上述兩個步驟咱們實現了本地客戶端經過Binder對於服務的調用。經過上述,你對Binder會有了一個初步的瞭解和大致上對整個過程有了一個面貌。接下來將寫一篇關於android 生成apk過程和apk安裝過程。

本人如今每日一道算法題的Github地址。
https://github.com/Jensenczx/CodeEveryday附帶OJ地址和本人的代碼

相關文章
相關標籤/搜索