android 進程間通信原理

前言

每個Android進程只能運行在自己擁有的虛擬地址空間,對于用戶空間。不同進程之間彼此是不能共享的,而內核空間是可以共享的。Client和Server進程通信就是利用進程間可以共享內核內存空間來完成底層通信工作的,Client和Server通過ioctl等和內核空間進行交互。

進程通信架構

1、android的IPC和RPC

RPC指的是跨進程遠程調用,強調了調用的功能,即一個進程之間調用另外一個進程的方法。

IPC指的是進程間通信,android使用Binder機制來進行進程間的通信,沒有調用的功能。

Android系統的RPC = Binder進程間通信+在Binder基礎上建立起來的進程間函數調用機制。

2、android系統的RPC實現

RPC架構圖

Android的RPC主要包含Client、Server和ServiceManager。android中使用ServiceManager來管理所有的所有的Server。ServiceManger啟動后首先告訴Binder驅動,將自己標識為ServiceManager。在創建一個Server后,首先通過addService將自己交給ServiceMager管理,Client在需要調用Server時直接通過getService到ServiceManager中查找對應的Server,然后調用Server的方法。

下圖給出binder在android中的整體架構,從framework到native再到kernel:

Binder整體架構


圖中紅色部分代表整個framework層binder架構的相關組件,Binder類代碼Server端,BinderProxy代表客戶端。藍色代碼Native層的Binder架構組件。上層framewoek的binder邏輯建立在native層架構的基礎之上,核心邏輯都是交給native處理的。Framework的ServiceManager與native的ServiceManager并不完全對應,framework層的ServiceManager類的實現最終是通過BinderProcy傳遞給native層來完成的。

Server啟動后會開啟一個線程不停的讀取Binder驅動的讀接口,這是一個阻塞調用;在需要響應客戶端的時候,會調用Binder驅動的寫接口進行數據返回。

Client啟動后會不停讀取Binder驅動的讀接口并阻塞;在調用Service時會開啟線程調用Binder的寫接口;服務器端處理完后調用寫接口、喚醒阻塞中的客戶端。

所有的通信都是通過底層的Binder驅動實現的。

3、RPC機制java層代碼分析

類圖


一般我們使用如下方式來獲取系統的Service,例如AlarmManager:

AlarmManager wm = (AlarmManager)getSystemService(Context.ALARM_SERVICE);該代碼的運行時序如下所示:

getSystemService時序

客戶端通過Context.getSystemService獲取遠程服務時,會轉到ContextImpl中調用,ContextImpl有一個ServiceFetcher內部類,通過名字知道該類用于獲取Service;ContextImpl里面有個static的WALLPAPER_FETCHER,在APK啟動時會加載里面的函數,如下所示,其中registerService會將每個Service對應的構造器ServiceFetcher放入SYSTEM_SERVICE_MAP中。

創建ServiceFetcher

在調用ContextImpl.getSystemService()時,會調用SYSTEM_SERVICE_MAP對應ServiceFetcher的getService()方法,如下所示。ContextImpl有個全局mServiceCache用于緩存用戶創建的Service緩存,這樣用戶再次獲取的時候可以直接從緩存取出,避免再次創建。

SeviceFetcher.getService

如果mServiceCache沒有需要的Service緩存,則調用ServiceFetcher的createService進行創建,這里就開始和ServiceManager打交道了,以AlarmManager為例,首先調用ServiceManager.getService()獲取IBinder,然后調用IAlarmManager.stub.asInterface將該binder轉化成客戶端可以直接調用的接口,最后將該接口封裝成AlarmManager給客戶端使用。

registerService

我們看到這里調用了ServiceManagerNative.asInterface獲取應IServiceManager實例,傳入了BinderInternal.getContextObject(),如下所示:

BinderInternal.getContextObject

getContextObject方法是一個JNI方法,其實sServiceManager?=?ServiceManagerNative.asInterface(BinderInternal.getContextObject());就相當于:sServiceManager?=?ServiceManagerNative.asInterface(new?BinderProxy());

接下來就是調用ServiceManagerNative的asInterface函數了.

ServiceManagerNative.asInterface()

這里的參數obj是一個BinderProxy對象,ServiceManagerProxy提供了addService、getService的實現,也就是ServiceManager最終關聯到了ServiceManagerProxy上。到這里,在java層我們已經擁有了ServiceManager的遠程接口ServiceManagerProxy,對ServiceManager的所有操作將轉接到ServiceManagerProxy中。

如此就實現了對android系統的ServiceManager的RPC調用。那么android系統中提供的那些Service是怎樣添加到ServiceManager中去的呢?答案就在SystemServer.java類中,SystemServer伴隨系統一起啟動,之后會運行ServerThread線程。

SystemServer.init2()

ServerThread的run方法會完成所有系統Service的創建,并添加到ServiceManager中去,如下所示:

添加所有的系統Service

其中addService也是調用的ServiceManagerProxy的addService,這樣在系統啟動后,相當于在OS層維護了一群系統Service的list。

4、幾個概念

IBinder是一個接口,它代表了一種跨進程傳輸的能力;只要實現了這個接口,就能將這個對象進行跨進程傳遞;這是驅動底層支持的;在跨進程數據流經驅動的時候,驅動會識別IBinder類型的數據,從而自動完成不同進程Binder本地對象(Server端)以及Binder代理對象(Client獲取的Proxy)的轉換。

IInterface代表的就是遠程server對象具有什么能力, 表示client與server端的調用契約。具體來說,就是aidl里面的接口。

Java層的Binder類,代表的其實就是Binder本地對象。BinderProxy類是Binder類的一個內部類,它代表遠程進程的Binder對象的本地代理;這兩個類都繼承自IBinder,因而都具有跨進程傳輸的能力;實際上,在跨越進程的時候,Binder驅動會自動完成這兩個對象的轉換。

在使用AIDL的時候,編譯工具會給我們生成一個Stub的靜態內部類;這個類繼承了Binder,說明它是一個Binder本地對象,它實現了IInterface接口,表明它具有遠程Server承諾給Client的能力;Stub是一個抽象類,具體的IInterface的相關實現需要我們手動完成,這里使用了策略模式。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,401評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,011評論 3 413
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事?!?“怎么了?”我有些...
    開封第一講書人閱讀 175,263評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,543評論 1 307
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,323評論 6 404
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 54,874評論 1 321
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 42,968評論 3 439
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,095評論 0 286
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,605評論 1 331
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,551評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,720評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,242評論 5 355
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 43,961評論 3 345
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,358評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,612評論 1 280
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,330評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,690評論 2 370

推薦閱讀更多精彩內容