前言
每個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的相關實作需要我們手動完成,這裡使用了政策模式。