Binder總結篇1-Binder原理
需要學會Binder的基本使用和原理,需要的知識點有:
-
Linux程式和空間的概念
-
虛擬地址概念
-
常用IPC,他們的基本流程和Binder的區別
-
C/S架構基本思路,也就是Binder驅動,ServerManager,Client和Server這四個概念。
-
AIDL以及支援的資料型別,包括Parcelable等,以及編寫
-
Service(Android的四大元件之一),Binder等幾個具體的java類使用。
以下是自己的一些Binder學習總結,如有侵權請聯絡刪除。
Linux的程式和空間的概念
在Linux系統中,程式是分配給應用程式執行的最小描述,即一個應用程式最少有一個程式,而一個程式之間又最少有一個執行緒,程式給應用程式分配記憶體空間。
空間:在Linux中,為了保持系統的穩定性,分為核心空間和使用者空間,核心空間的許可權最高,使用者空間的許可權最低。比如讀寫檔案,網路請求就是在核心空間中進行的。
在Linux中,存在著程式隔離,也就是程式A無法直接訪問程式B的資料,他們之間各自具有獨立的記憶體。假如他們需要進行通訊,就必須通過IPC來實現,主要是通過兩個方法:copy_from_user
和copy_to_user
。
虛擬地址
在給應用程式分配記憶體的時候,對於應用程式來說,他是一片連續的記憶體空間,但是實際上,這些記憶體空間對映到具體的實體記憶體中是碎片化的不連續的,這個在應用程式看來是連續的空間就是通過虛擬地址實現的。通過虛擬地址,讓應用程式看似擁有連續的記憶體空間,從而對映到具體的實體記憶體中。
比如,在32位系統中,可以定址的空間長度是2的32次方,也就是4GB。
傳統IPC
包括:
-
共享記憶體
-
訊息管道
-
Socket
-
訊號量
這些是常用的IPC方法,一般而言,他們會經歷兩次的資料copy,共享記憶體除外。
第一次是傳送方將資料通過copy_from_user
拷貝到核心空間中,這是第一次。然後,接收方在自己的記憶體空間中,分配快取區,通過copy_to_user
方法把核心空間的資料複製到自己進行讀取。
如下圖:
對於Android系統而言,上面的幾種方式都不太適合,首先對於兩次的資料拷貝,存在的問題是:
-
copy次數多耗費時間
-
接收方不知道需要分配多大的記憶體接受資料,或者是需要提前通知接受方分配而耗費時間。
對於共享記憶體,雖然它無需copy但是較為難以控制,安全性方面較差。
那麼Binder在這方面具有什麼優勢呢?
-
Binder是隻需要一次資料copy,僅低於共享記憶體。
-
他基於C/S架構,職責分離又相互獨立,穩定性更好。
-
在安全性方面,傳統的IPC接收方無法獲取對方可靠的程式PId,從而無法鑑別對方身份。但是在Android中,他會為每一個安裝好的App分配一個自己的UID,從而做到可以鑑別身份。
所以Binder是Android系統進行IPC採用的手段。那麼Binder為什麼只是可以一次資料拷貝就行了呢?
這個就是利用虛擬記憶體了。Binder藉助記憶體對映,在核心空間
和接收方的使用者空間
的資料快取區做了一層記憶體對映。也就是說,在傳送方將資料拷貝到記憶體空間的時候,核心空間的這部分地址同時也會被對映到接收方的記憶體快取中,這樣子,就少了一次從內和空間拷貝到使用者空間。
如下圖:
Binder 的通訊原理
在Binder中,有四個概念,Binder驅動,ServerManager,Client以及Server,這四個部分組成了BinderC/S架構。
他跟一次網路請求很相似:Client通過域名發起請求,通過DNS域名解析器解析具體的ip地址,然後再通過路由轉發到具體的Server,再然後Server將請求結果通過路由轉發回Client。
在Binder的IPC中,有如下幾個部分:
- Binder驅動
Binder驅動是一種虛擬的字元裝置,註冊在/dev/bindr中,其中定義了一套Binder通訊協議,負責建立程式間Binder通訊,提供了資料包在程式之間傳遞的底層支援。
他的角色類似路由,他是提供程式間通訊的底層支援。負責將Client端的請求轉發到Server,並將Server的資料返回給Client。
2 ServerManager
他的作用類似DNS伺服器,負責將Client請求的Server的Binder描述轉化為具體的Server地址,以便Binder驅動將Client的請求轉達到Server。當Server需要提供服務的時候,他必須先向ServerManager註冊,這樣子,ServerManager中,就存有一份類似key-value的資料,儲存了一份Server的Binder字元名稱和Binder引用的對映以便Client可以找到。
- Client
Client的作用是發起請求,通過Binder向ServerManager發起請求獲取Server的具體地址,然後交由Binder驅動轉發。
- Server
Server假如需要對外提供服務,他就需要先將自己註冊到ServerManager中,以便被解析出來。Server在響應請求之後,就將資料通過Binder驅動再次將資料傳遞會Client。
這就是一次完整的IPC呼叫。
還有一個問題就是ServerManager的產生,因為Client/Server都是需要通過Binder與ServerManager進行通訊的,那麼這個ServerManager是如何產生的呢?
-
在Android系統啟動之後,會建立一個名詞為servermanager的程式,可以檢視
ZygoteInit
檔案,在裡面的main方法中,呼叫Zygote
的forkSystemServer
產生。它通過一個約定的命令BINDERSERVER_MGR向Binder驅動註冊,申請成為ServerManager。Binder驅動會自動為ServerManager建立一個Binder實體 -
這個Binder實體的引用在所有的Client中都是0,也就是說各個Client通過0這個引用就可以與ServerManager進行通訊。
Binder的代理機制
上面是我們的IPC過程,在這個過程中,Client需要獲取到Server端的Binder引用,那麼這個引用是真正的Server引用嗎,他是如何實現的呢,A程式並無法直接獲取B程式的物件。這個就是需要通過Binder的代理機制實現。
我們在Client端,向ServerManager獲取具體的Server端的Binder引用的時候,會首先進過Binder驅動,Binder驅動它並不會把真正的Server的Bind人引用返回給Client端,而是返回一個代理的java物件,該物件具有跟Server端的Binder引用相同的方法簽名,這個物件為ProxyObject,他具有跟Server的Binder例項一樣的方法,只是這些方法並沒有Server端的能力,這個ProxyObject的能力是可以通過Binder驅動,正在實現對Server的Binder進行呼叫,從而完成資料傳遞。
比如,當Binder驅動接受到Client程式的請求,就去ServerManager中查詢,在ServerManager中查詢到具體的Server具體之後,就建立一個Server端的Binder物件的ProxyObject,並且將該ProxyObject返回給Client 。然後Client就通過ProxyObject呼叫其中的方法,ProxyObject的方法再去呼叫Binder驅動,這個Binder驅動就去Server程式中,呼叫具體的Server程式的具體的Binder物件的方法,然後再通過Binder驅動返回資料給Client。
如下圖
AIDL
上面我們大概梳理了Binder呼叫的整體流程,知道Binder的大概原理。在Android中,是通過AIDL這一描述性介面語言實現的。
什麼是AIDL:Android 介面定義語言 (AIDL)
關於如何使用AIDL將在下一篇文章在做詳細使用。
參考文章
關於Binder,作為應用開發者你需要知道的全部(同時也是本文的文章圖片來源)