前言
每個Android進程只能運行在自己擁有的虛擬地址空間,對于用戶空間。不同進程之間彼此是不能共享的,而內核空間是可以共享的。Client和Server進程通信就是利用進程間可以共享內核內存空間來完成底層通信工作的,Client和Server通過ioctl等和內核空間進行交互。
1、android的IPC和RPC
RPC指的是跨進程遠程調用,強調了調用的功能,即一個進程之間調用另外一個進程的方法。
IPC指的是進程間通信,android使用Binder機制來進行進程間的通信,沒有調用的功能。
Android系統的RPC = Binder進程間通信+在Binder基礎上建立起來的進程間函數調用機制。
2、android系統的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:
圖中紅色部分代表整個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);該代碼的運行時序如下所示:
客戶端通過Context.getSystemService獲取遠程服務時,會轉到ContextImpl中調用,ContextImpl有一個ServiceFetcher內部類,通過名字知道該類用于獲取Service;ContextImpl里面有個static的WALLPAPER_FETCHER,在APK啟動時會加載里面的函數,如下所示,其中registerService會將每個Service對應的構造器ServiceFetcher放入SYSTEM_SERVICE_MAP中。
在調用ContextImpl.getSystemService()時,會調用SYSTEM_SERVICE_MAP對應ServiceFetcher的getService()方法,如下所示。ContextImpl有個全局mServiceCache用于緩存用戶創建的Service緩存,這樣用戶再次獲取的時候可以直接從緩存取出,避免再次創建。
如果mServiceCache沒有需要的Service緩存,則調用ServiceFetcher的createService進行創建,這里就開始和ServiceManager打交道了,以AlarmManager為例,首先調用ServiceManager.getService()獲取IBinder,然后調用IAlarmManager.stub.asInterface將該binder轉化成客戶端可以直接調用的接口,最后將該接口封裝成AlarmManager給客戶端使用。
我們看到這里調用了ServiceManagerNative.asInterface獲取應IServiceManager實例,傳入了BinderInternal.getContextObject(),如下所示:
getContextObject方法是一個JNI方法,其實sServiceManager?=?ServiceManagerNative.asInterface(BinderInternal.getContextObject());就相當于:sServiceManager?=?ServiceManagerNative.asInterface(new?BinderProxy());
接下來就是調用ServiceManagerNative的asInterface函數了.
這里的參數obj是一個BinderProxy對象,ServiceManagerProxy提供了addService、getService的實現,也就是ServiceManager最終關聯到了ServiceManagerProxy上。到這里,在java層我們已經擁有了ServiceManager的遠程接口ServiceManagerProxy,對ServiceManager的所有操作將轉接到ServiceManagerProxy中。
如此就實現了對android系統的ServiceManager的RPC調用。那么android系統中提供的那些Service是怎樣添加到ServiceManager中去的呢?答案就在SystemServer.java類中,SystemServer伴隨系統一起啟動,之后會運行ServerThread線程。
ServerThread的run方法會完成所有系統Service的創建,并添加到ServiceManager中去,如下所示:
其中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的相關實現需要我們手動完成,這里使用了策略模式。