国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 系統 > Android > 正文

# 讀 Android 開發藝術探索 &3

2019-11-09 17:57:44
字體:
來源:轉載
供稿:網友

關鍵詞:Binder / 跨進程通信機制 / AIDL /

Binder 是系統各個組件的橋梁,是一種極其方便的跨進程通信機制。Android 的四大組件、AMS、PMS 等系統服務都與 Binder 有關系。

這篇筆記是看《Android 開發藝術探索》之后,對 Binder 的進一步學習,對 Binder 知識的梳理參考了以下幾篇非常優秀的文章(感謝存在那么多大神對知識的無私傳播):(1)Weishu’s Notes - Binder 學習指南 (2)Android Binder 設計與實現 - 設計篇 (3)Android 進程間通信(ipC)機制 Binder 簡要介紹和學習計劃 (4)Android 跨進程通信之使用 AIDL 等等不一一列舉。

1. AIDL #

AIDL (Android Interface Definition Language,安卓接口定義語言) 是一種 IDL 語言,用于生成可以在 Android 設備上兩個進程之間進行進程間通信(interPRocess communication, IPC)的代碼。如果在一個進程中(例如 Activity)要調用另一個進程中(例如 Service)對象的操作,就可以使用 AIDL 生成可序列化的參數。AIDL IPC 機制是面向接口的,像 COM 或 Corba 一樣,但是更加輕量級。它是使用代理類在客戶端和實現端傳遞數據。

[ 關于 AIDL 需要知道的幾點 ]

使用 AIDL 之前需要理解如何使用 bindService;在 Android 上,一個進程不能正常訪問另一個進程的內存,需要將它們的對象分解成操作系統所理解的基本單位,按次序跨越進程邊界,AIDL 就起到這個作用;AIDL 允許你定義客戶端與服務端達成一致的程序接口,使用進程間通信來相互交流;什么時候使用 AIDL: 如果不需要執行不同應用之間的 IPC 并發,應該使用 Binder 建立接口;如果想執行 IPC,但是不需要處理多線程,應該使用 Messenger 實現接口;而使用 AIDL 的必要情況是:允許來自不同應用的客戶端跨進程通信來訪問你的 Service,而且想要在你的 Service 中處理多線程;AIDL 的原理:實際上就是通過我們寫的 aidl 文件,幫助我們生成了一個接口,一個 Stub 類用于服務端,一個 Proxy 類用于客戶端調用。

我們使用AIDL接口的時候,經常會接觸到 IBinder / IInterface / Binder / BinderProxy / Stub 這些類,那么這每個類代表的是什么呢?

IBinder 是一個接口,它代表了一種跨進程傳輸的能力;只要實現了這個接口,就能將這個對象進行跨進程傳遞;這是驅動底層支持的;在跨進程數據流經驅動的時候,驅動會識別 IBinder 類型的數據,從而自動完成不同進程的 Binder 本地對象以及 Binder 代理對象的轉換。IBinder 負責數據傳輸。這里的 IInterface 代表的就是遠程 server 對象具有什么能力。具體來說,就是 aidl 里面的接口。java 層的 Binder 類,代表的其實就是 Binder 本地對象。BinderProxy 類是 Binder 類的一個內部類,它代表遠程進程的 Binder 對象的本地代理;這兩個類都繼承自 IBinder, 因而都具有跨進程傳輸的能力;實際上,在跨越進程的時候,Binder 驅動會自動完成這兩個對象的轉換。在使用 AIDL 的時候,編譯工具會給我們生成一個 Stub 的靜態內部類;這個類繼承了 Binder, 說明它是一個 Binder 本地對象,它實現了 IInterface 接口,表明它具有遠程 Server 承諾給 Client 的能力;Stub 是一個抽象類,具體的 IInterface 的相關實現需要我們手動完成,這里使用了策略模式。

它總是那么一種固定的模式:一個需要跨進程傳遞的對象一定繼承自 IBinder,如果是 Binder 本地對象,那么一定繼承 Binder 實現 IInterface,如果是代理對象,那么就實現了 IInterface 并持有了 IBinder 引用;

Proxy 與 Stub 不一樣,雖然他們都既是 Binder 又是 IInterface,不同的是 Stub 采用的是繼承(is 關系),Proxy 采用的是組合(has 關系)。

2. 內核模塊 / 驅動 #

用戶空間訪問內核空間的唯一方式是系統調用。當一個進程執行系統調用而陷入內核代碼中執行,該進程便處于內核運行態(內核態)。當進程只是在執行用戶自己的代碼時,是處于用戶運行態(用戶態)。傳統的 linux 通信機制比如 Socket、管道等都是內核支持的,但 Binder 不是 Linux 內核的一部分,需要依靠 Linux 的 動態可加載內核模塊 (Loadable Kernel Module, LKM)機制來解決這個問題。模塊具有獨立功能,可以被單獨的編譯,但是不能獨立運行,需要在運行的時候被鏈接到內核作為內核的一部分在內核空間運行。Android 系統通過 Binder 通信的內核模塊,即 Binder 驅動,運行在內核空間,用戶進程之間通過這個模塊作為橋梁完成需要的通信。(驅動就是操作硬件的接口)

3. Binder 通信模型 #

Android 特別使用 Binder 的原因:性能 + 安全。移動設備廣泛地使用跨進程通信,需要對通信機制本身有更嚴格的要求。傳統的進程通信方式對于通信雙方的身份沒有嚴格的驗證,僅僅是在上層協議進行架設,比如 Socket 通信 ip 地址是客戶端手動填入的,可以被偽造。Binder 機制從協議本身就支持對通信雙方作身份校驗,提升安全性。(PS:這也是 Android 權限模型的基礎)進程的隔離實現,使用了虛擬地址空間。由于進程隔離機制的存在,所以跨進程通信的雙方(Server 進程,Client 進程)無法通過簡單的方式進行通信,需要 Binder 機制。兩個運行在用戶空間的進程要完成通信,必須借助內核的幫助,運行在內核里面的程序叫做 Binder驅動,類似于一次打電話過程中的基站的作用;而還有一個很重要的東西叫做 ServiceManager,相當于通信錄的作用。

Binder 通信模型有四個角色(Client / Server / ServiceManager / Driver),通信步驟大致如下:

有一個進程向驅動申請為 ServiceManager,驅動同意之后,它便可以負責對 Service 的管理;Server 向 ServiceManager 注冊,每一個 Service 端的進程啟動之后要向 ServiceManager 報告,ServiceManager 建立一張表,對應著各個 Server 的名字和地址;Client 詢問 ServiceManager 如何聯系到想要聯系的 Server,ServiceManager 返回一個消息,Client 根據這個消息就可以開始建立與 Server 的通信; 這里 Client 與 ServiceManager 的通信,Client 與 Server 的通信都會經過驅動,驅動是整個過程的核心;

兩個運行在用戶空間的進程 A 和進程 B 如何完成通信?有一種方案: 內核可以訪問 A 和 B 的所有數據;所以,可以通過內核做中轉;假設進程 A 要給進程 B 發送數據,那么就先把 A 的數據 copy 到內核空間,然后把內核空間對應的數據 copy 到 B 就完成了;用戶空間要操作內核空間,需要通過系統調用;剛好,這里就有兩個系統調用:copy_from_user, copy_to_user。 但是但是但是,Binder 機制并不是這么做的!!!看圖(該圖來自Binder 學習指南)

Binder 機制跨進程原理

首先,Server 進程要向 ServiceManager 注冊,告訴 ServiceManager 一個標識之類的信息,于是 ServiceManager 建立了一張表:這個標識對應進程這個 Server;然后,Client 向 ServiceManager 查詢,告訴 ServiceManager 它需要這個標識信息對應的某個內容,驅動在數據流過的時候返回 Client 所需要的對象(這其實不是原本真正的對象,而是一個一模一樣的代理對象,而且這個對象的內容什么也不做,只是直接把參數做了一些包裝直接轉發給了 Binder 驅動)對于驅動而言,通過查表發現用的是什么代理對象替換了原本的對象給 Client,然后去正真的訪問真對象,并且告訴 Server 把調用的結果發送給驅動,驅動把結果返回給 Client 進程。

由于驅動返回的 objectProxy 與 Server 里的原始的 object 近乎一樣,給人感覺是直接 “ 把 Server 進程里面的對象 Object 傳遞給了 Client 進程 ”,我們因此說是 “ Binder 對象是可以進行跨進程傳遞的一種對象 ”。 其實不然,Binder 跨進程傳輸并不是真的把一個對象傳輸給了另一個進程;傳輸過程好像是 Binder 跨進程穿越的時候玩了一個魔術,它在一個進程留下了一個真身,在另一個進程幻化出一個影子(這個影子可以有多個);所以說!!! Client 進程的操作實際上是對于影子的操作,影子利用 Binder 驅動最終讓真身完成操作。 Android 系統實現這種機制使用的是 代理模式, 對于 Binder 的訪問,如果是在同一個進程(不需要跨進程),那么直接返回原始的 Binder 實體;如果在不同進程,那么就給他一個代理對象(影子);我們在系統源碼以及 AIDL 的生成代碼里面可以看到很多這種實現。

PS:Server 進程向 ServiceManager 注冊的過程也是跨進程通信,驅動也會對這個過程進行暗箱操作:ServiceManager 中存在的 Server 端的對象實際上也是代理對象,后面 Client 向 ServiceManager 查詢的時候,驅動會給 Client 返回另外一個代理對象。Server 進程的本地對象僅有一個,其他進程所擁有的全部都是它的代理。

一句話總結就是:Client 進程只不過是持有了 Server 端的代理;代理對象協助驅動完成了跨進程通信。

4. 關于 Binder 所需要知道的 #

Binder 的設計采用了抽象的面向對象的思想,對于 Binder 通信的使用者而言, Server 里面的 Binder 和 Client 里面的 Binder 沒有什么不同,一個 Binder 代表了所有,不用關心實現的細節,甚至不用關心驅動以及 ServiceManager 的存在;Binder 指的是一種通信機制,IPC 機制;對于 Server 進程來說,Binder 指的是 Binder 本地對象;對于 Client 來說,Binder 指的是 Binder 代理對象,只是 Binder 對象的一個遠程代理,需要明白的是,對這個 Binder 代理對象的操作,會通過驅動最終轉發到 Binder 本地對象上去完成。而對于使用者來說,并不需要關心到底是 Binder 的代理對象還是本地對象,對兩者的操作沒有任何區別;Binder 是可以進行跨進程傳遞的對象,Binder 驅動會對具有跨進程傳遞能力的對象做特殊處理:自動完成代理對象和本地對象的轉換;Binder 的實體(本地對象)位于一個進程中,而它的引用(代理對象)卻遍布于系統的各個進程之中。Binder 模糊了進程邊界,淡化了進程間通信過程,整個系統仿佛運行于同一個面向對象的程序之中。形形色色的 Binder 對象以及星羅棋布的引用仿佛粘接各個應用程序的膠水,這也是 Binder 在英文里的原意。

End.

Note by HF. Learn from Internet & 《Android 開發藝術探索》



發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 新余市| 滁州市| 虹口区| 延寿县| 虞城县| 石泉县| 新乐市| 南通市| 冀州市| 南江县| 吴忠市| 聂拉木县| 肃北| 黄陵县| 乌什县| 甘肃省| 禹州市| 武汉市| 陆川县| 六安市| 泰宁县| 富锦市| 北流市| 卓尼县| 玉田县| 邵东县| 武鸣县| 太谷县| 天台县| 汤阴县| 保康县| 菏泽市| 长乐市| 砀山县| 和田县| 浦江县| 桐柏县| 沙坪坝区| 南京市| 宕昌县| 彰化县|