android 進(jìn)程間通信原理

前言

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

進(jìn)程通信架構(gòu)

1、android的IPC和RPC

RPC指的是跨進(jìn)程遠(yuǎn)程調(diào)用,強調(diào)了調(diào)用的功能,即一個進(jìn)程之間調(diào)用另外一個進(jìn)程的方法。

IPC指的是進(jìn)程間通信,android使用Binder機制來進(jìn)行進(jìn)程間的通信,沒有調(diào)用的功能。

Android系統(tǒng)的RPC = Binder進(jìn)程間通信+在Binder基礎(chǔ)上建立起來的進(jìn)程間函數(shù)調(diào)用機制。

2、android系統(tǒng)的RPC實現(xiàn)

RPC架構(gòu)圖

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

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

Binder整體架構(gòu)


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

Server啟動后會開啟一個線程不停的讀取Binder驅(qū)動的讀接口,這是一個阻塞調(diào)用;在需要響應(yīng)客戶端的時候,會調(diào)用Binder驅(qū)動的寫接口進(jìn)行數(shù)據(jù)返回。

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

所有的通信都是通過底層的Binder驅(qū)動實現(xiàn)的。

3、RPC機制java層代碼分析

類圖


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

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

getSystemService時序

客戶端通過Context.getSystemService獲取遠(yuǎn)程服務(wù)時,會轉(zhuǎn)到ContextImpl中調(diào)用,ContextImpl有一個ServiceFetcher內(nèi)部類,通過名字知道該類用于獲取Service;ContextImpl里面有個static的WALLPAPER_FETCHER,在APK啟動時會加載里面的函數(shù),如下所示,其中registerService會將每個Service對應(yīng)的構(gòu)造器ServiceFetcher放入SYSTEM_SERVICE_MAP中。

創(chuàng)建ServiceFetcher

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

SeviceFetcher.getService

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

registerService

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

BinderInternal.getContextObject

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

接下來就是調(diào)用ServiceManagerNative的asInterface函數(shù)了.

ServiceManagerNative.asInterface()

這里的參數(shù)obj是一個BinderProxy對象,ServiceManagerProxy提供了addService、getService的實現(xiàn),也就是ServiceManager最終關(guān)聯(lián)到了ServiceManagerProxy上。到這里,在java層我們已經(jīng)擁有了ServiceManager的遠(yuǎn)程接口ServiceManagerProxy,對ServiceManager的所有操作將轉(zhuǎn)接到ServiceManagerProxy中。

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

SystemServer.init2()

ServerThread的run方法會完成所有系統(tǒng)Service的創(chuàng)建,并添加到ServiceManager中去,如下所示:

添加所有的系統(tǒng)Service

其中addService也是調(diào)用的ServiceManagerProxy的addService,這樣在系統(tǒng)啟動后,相當(dāng)于在OS層維護(hù)了一群系統(tǒng)Service的list。

4、幾個概念

IBinder是一個接口,它代表了一種跨進(jìn)程傳輸?shù)哪芰?/b>;只要實現(xiàn)了這個接口,就能將這個對象進(jìn)行跨進(jìn)程傳遞;這是驅(qū)動底層支持的;在跨進(jìn)程數(shù)據(jù)流經(jīng)驅(qū)動的時候,驅(qū)動會識別IBinder類型的數(shù)據(jù),從而自動完成不同進(jìn)程Binder本地對象(Server端)以及Binder代理對象(Client獲取的Proxy)的轉(zhuǎn)換。

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

Java層的Binder類,代表的其實就是Binder本地對象。BinderProxy類是Binder類的一個內(nèi)部類,它代表遠(yuǎn)程進(jìn)程的Binder對象的本地代理;這兩個類都繼承自IBinder,因而都具有跨進(jìn)程傳輸?shù)哪芰?;實際上,在跨越進(jìn)程的時候,Binder驅(qū)動會自動完成這兩個對象的轉(zhuǎn)換。

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

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容