Android中的IPC方式——Binder(一)

本文主要是參考一些資料講述一些基本概念,有基礎的能夠直接從下一篇看起。 只要有個基本的瞭解就能夠了沒必要深究。windows

概述

簡單來講,Binder是Android中使用最普遍的IPC(進程間通訊)機制。Linux中自己已經擁有了經典的進程間的通訊方式,如信號量、管道、消息隊列、貢獻內存、scoket等。那麼Android仍是創造了新的IPC方式,主要是基於性能、穩定性和安全性方面考慮。緩存

  • 性能安全

    性能上的優點。Socket 做爲一款通用接口,其傳輸效率低,開銷大,主要用在跨網絡的進程間通訊和本機上進程間的低速通訊。消息隊列和管道採用存儲-轉發方式,即數據先從發送方緩存區拷貝到內核開闢的緩存區中,而後再從內核緩存區拷貝到接收方緩存區,至少有兩次拷貝過程。共享內存雖然無需拷貝,但控制複雜,難以使用。Binder 只須要一次數據拷貝,性能上僅次於共享內存。服務器

    IPC方式 數據拷貝次數
    共享內存 0
    Binder 1
    Socket/管道/消息隊列 2
  • 安全性網絡

    傳統的 IPC 沒有任何安全措施,徹底依賴上層協議來確保。Android 做爲一個開放性的平臺,市場上有各種海量的應用供用戶選擇安裝,因此Android 爲每一個安裝好的 APP 分配了本身的 UID,故而進程的 UID 是鑑別進程身份的重要標誌來鑑別身份。架構

  • 穩定性函數

    基於C/S架構,客戶端有什麼需求丟給服務端來處理,架構清晰、職責明確又相互獨立,天然穩定性更好。雖然貢獻內存無需拷貝,可是控制複雜難以使用。性能

Linux進程間通訊

基本概念介紹

Linux

上圖展現了 Liunx 中跨進程通訊涉及到的一些基本概念:操作系統

  • 進程隔離
    進程與進程間內存是不共享的。兩個進程就像兩個平行的世界,A 進程無法直接訪問 B 進程的數據,這就是進程隔離的通俗解釋。A 進程和 B 進程之間要進行數據交互就得采用特殊的通訊機制:進程間通訊(IPC)。code

  • 進程空間劃分
    操做系統的核心是內核,獨立於普通的應用程序,能夠訪問受保護的內存空間,也能夠訪問底層硬件設備的權限。爲了保護用戶進程不能直接操做內核,保證內核的安全,操做系統從邏輯上將虛擬空間劃分爲用戶空間(User Space)和內核空間(Kernel Space)。

  • 系統調用

    從邏輯上進行了用戶空間和內核空間的劃分,但不可避免的用戶空間須要訪問內核資源,好比文件操做、訪問網絡等等。就須要藉助系統調用來實現,這樣保證了全部的資源訪問都是在內核的控制下進行的,避免了用戶程序對系統資源的越權訪問,提高了系統安全性和穩定性。

Linux 下的傳統 IPC 通訊原理

消息發送方將要發送的數據存放在內存緩存區中,經過系統調用進入內核態。而後內核程序在內核空間分配內存,開闢一塊內核緩存區,調用 copy_from_user()函數將數據從用戶空間的內存緩存區拷貝到內核空間的內核緩存區中。

一樣的,接收方進程在接收數據時在本身的用戶空間開闢一塊內存緩存區,而後內核程序調用copy_to_user()函數將數據從內核緩存區拷貝到接收進程的內存緩存區。

傳統 IPC 通訊原理

傳統的 IPC 通訊方式有兩個問題:

  • 性能低下,一次數據傳遞須要經歷:內存緩存區 --> 內核緩存區 --> 內存緩存區,須要 2 次數據拷貝
  • 接收數據的緩存區由數據接收進程提供,可是接收進程並不知道須要多大的空間來存放將要傳遞過來的數據,所以只能開闢儘量大的內存空間或者先調用 API 接收消息頭來獲取消息體的大小,這兩種作法不是浪費空間就是浪費時間。

Binder 跨進程通訊原理

從上面看出傳統的跨進程通訊是須要內核空間作支持的,可是Binder並非Linux 系統內核的一部分,這樣怎麼辦呢? Linux 有動態內核可加載模塊(Loadable Kernel Module,LKM)的機制,模塊是具備獨立功能的程序,它能夠被單獨編譯,可是不能獨立運行。它在運行時被連接到內核做爲內核的一部分運行。這樣,Android 系統就能夠經過動態添加一個內核模塊運行在內核空間,用戶進程之間經過這個內核模塊做爲橋樑來實現通訊。

在 Android 系統中,這個運行在內核空間,負責各個用戶進程經過 Binder 實現通訊的內核模塊就叫 Binder 驅動(Binder Dirver)。

Binder IPC 方式主要是經過內存映射mmap() 來實現,mmap() 是操做系統中一種內存映射的方法。內存映射簡單的講就是將用戶空間的一塊內存區域映射到內核空間。

內存映射能減小數據拷貝次數,實現用戶空間和內核空間的高效互動。兩個空間各自的修改能直接反映在映射的內存區域,從而被對方空間及時感知。也正由於如此,內存映射可以提供對進程間通訊的支持。

一次完整的Binder IPC過程:

  • 首先 Binder 驅動在內核空間建立一個數據接收緩存區;
  • 接着在內核空間開闢一塊內核緩存區,創建內核緩存區內核中數據接收緩存區之間的映射關係,以及內核中數據接收緩存區接收進程用戶空間地址的映射關係;
  • 發送方進程經過系統調用 copy_from_user() 將數據 copy 到內核中的內核緩存區,因爲內核緩存區和接收進程的用戶空間存在內存映射,所以也就至關於把數據發送到了接收進程的用戶空間,這樣便完成了一次進程間的通訊。

BinderIPC原理

Binder 通訊模型

Binder通訊採用C/S架構,從組件視角來講,包含Client、Server、ServiceManager以及Binder驅動,其中ServiceManager用於管理系統中的各類服務。其中 Client、Server、Service Manager 運行在用戶空間(存疑),Binder 驅動運行在內核空間。

統觀Binder中的各個組成元素,發現它和TCP/IP網絡又不少相同之處。

  • Binder驅動——路由器;
  • Service Manager ——DNS;
  • Binder Client ——客戶端;
  • Binder Server —— 服務端;

TCP/IP一個典型的鏈接過程

TCP/IP一個典型的鏈接過程

client和server創建鏈接一般有如下幾個步驟:

  • Client向DNS查詢Google.com的IP地址。

    首先Client要知道DNS的IP地址才能夠,這個是在Client接入網絡以前就完成的。

    若是Client已經知道了Server的IP天然能夠跳過這一個步驟直接與Server鏈接。好比windows下提供了一個hosts文件用於查詢經常使用域名與IP的對應關係。

  • DNS將查詢到的結果返回給Client。

  • Client得知Googlde.com的IP後,向Google服務器發起鏈接。

  • 在這一系列流程中沒有談到Router,由於它的做用就是將數據包投遞給目標IP。

在以上整個TCP/IP的模型中,IP地址是彼此間溝通的惟一憑證。其次Router是構建一個通訊網絡的基礎,它根據用戶的目標IP來把數據包正確的送達。最後DNS不是必須的。

類比下 Binder的流程:

進程1(客戶端)想要和進程2(服務端)進行訪問,由於他們之間是 跨進程的(跨網絡)因此須要Binder驅動(Router)來把請求正確的投遞到對方所在的進程(服務端)中,而參與通訊的進程都須要持有Binder"頒發"的惟一標誌(IP地址)。一樣的Binder中的ServiceManager(DNS)也不是必須的,前提是Client能記住進程的Binder標誌(IP地址)。特別注意的是這個Binder標誌是」動態IP「,意味這每次訪問都須要從新獲取,而DNS能夠完美的解決這個問題,用於管理Binder標誌和域名之間的對應關係。

DNS有本身的IP地址,那麼ServiceManager在Binder的通訊過程的惟一標誌永遠是0。

相關文章
相關標籤/搜索