Android IPC 程序間通訊實現理解
眾所周知,Android中的IPC(程序間通訊)採用了Binder機制,那麼要理解程序間通訊是如何實現的,理解Binder機制就相當關鍵了。
首先,為什麼Android的IPC要採用Binder機制呢,查閱資料,Binder機制的優點在於其少了一次拷貝過程,傳統的IPC需要將傳送端
傳送的資料從使用者空間copy到核心空間,在給到接受者時,再從核心空間copy給接受者,一次IPC請求需要兩次拷貝,而Binder機制
不同的時僅做一個copy操作,傳送IPC請求,會將Client端攜帶的資料copy到核心空間,放在共享記憶體中,通過核心與使用者空間的內
存對映到同一片物理空間,從而Server通過相關地址直接獲取到該共享記憶體中的相關資料,而不需要將其從核心空間copy到用
戶空間,這樣的機制提高了IPC的效能。
其次,Binder機制的組成:
1) 使用者空間:
Client: 發起IPC請求,通過從ServiceManager處獲取的Service程序Binder代理物件的引用,從而呼叫Service的相關方法(Service的服務介面可以通過AIDL檔案定義或者自定義介面類)
Service:需要在ServiceManager中註冊,實現AIDL中的Stub類,其中包含提供的服務介面,Publish Service的Binder物件
ServiceManager:負責管理系統中的Service,維護Service的Binder物件的引用,提供給Client以名稱方式查詢Service的服務介面以及Service
的Binder物件引用
2) 核心空間:
Binder驅動:負責程序間的資料的傳遞,通過mmap記憶體對映實現共享記憶體, 連線 Client端與Server端
其實個人覺得Binder機制的原理大致瞭解一些就ok了,因為畢竟Binder機制大多數時候不需要去修改,而關鍵的是在理解Binder機制的基礎上
如何在Binder機制基礎上實現IPC,以及能夠看懂Android系統中的IPC實現,解決程序間通訊出現的問題。
如果從Code中去詳細瞭解Binder的具體實現,可以參考如下blog進行詳細的學習:
在Android Framework中有很多需要用到IPC的地方,比如startActivity, 在APP中呼叫startActivity這其實就發起了一次IPC請求,因為APP一般跑在
自己的程序中,而ActivityManagerSerive(AMS)執行在system_server程序中,這裡啟動Activity的請求其實就是一次IPC請求,APP程序將該請求發
送到AMS所在程序中,通過請求AMS的startActivity服務將想要啟動的activity啟動起來。
在實現IPC通訊的時候,每個程序都會定義自己的Binder類,並建立Binder物件,一般Binder實體物件存在於Server程序中,而Client程序想要通過
Binder機制進行服務請求,需要通過ServiceManager獲取一個Server程序中Binder代理物件的引用。
實現Binder物件很關鍵,也比較繁瑣,所以為了方便開發者進行IPC的開發,Android提供的AIDL(Android Interface Definition Language)介面定義語言,
ADT中的aidl工具會根據用AIDL書寫的XXX.aidl檔案自動生成對應的介面類,介面類繼承android.os.IInterface,其包含Stub和Proxy兩個內部類,它
們的作用分別是:
介面類: 例如IServiceAIDL.aidl,其生成的介面類為IServiceAIDL.java,繼承自android.os.IInterface, 包含在XXX.aidl檔案中定義的所有介面
Stub類: 供Server程序用,抽象類,繼承自android.os.Binder,implements IServiceAIDL介面,Server程序中Binder物件的型別,即Server程序的Code
會去具體實現此Binder類並將其中的介面進行具體的實現,定義繼承自此類的子類或者直接匿名類實現對應的介面,此類中包含onTransact方法,這
個方法會被Binder驅動回撥,根據傳入的介面程式碼(int代號),找到需要呼叫Server程序的哪個介面。
Proxy類: 供Client程序用,implements IServiceAIDL介面類,實現該介面類中的所有方法,其為Stub類的內部類,Server程序Binder類的代理物件,Client
呼叫Proxy中的介面(即在XXX.aidl檔案中定義的服務介面),Proxy中對該介面的實現最終通過呼叫IBinder的transact方法進入到Binder驅動程式的實
現流程中,Binder驅動處理完成即回撥Stub類的onTransact方法去呼叫Server的服務實現
這裡多說一句,為什麼要提定義介面呢,程序間進行通訊無非是想要用目標程序的服務,那麼為了使得程式鬆耦合,服務定義完介面就不再修改,
Client如果想使用某個服務,直接呼叫對應的介面就可以了,不用關心Server是如何實現的,相當與在Client和Server之間抽象出一層介面,Server定
義好介面之後,具體實現可以根據具體情況進行修改,不會影響到Client介面的使用。
AIDL方便了IInterface介面類的自動生成,讓開發者專注在服務介面的定義上,不用關注IInterface的繁瑣的細節實現,當然根據自己的需求完全可以自己寫
繼承自IInterface的介面類,不需要藉助AIDL工具。AIDL只是一個IPC的工具,跟IPC實現原理沒有關係,僅幫忙將aidl定義的介面生成符合Binder機制的如上
講解的三個重要類。下面分析分析IPC中這個必備的IInterface子類的實現方式:
1)通過aidl檔案方式自動生成IInterface的子類,以一個簡單的AIDL Demo來說明
a. 僅關注介面定義服務端需要提供的介面,按照AIDL規則書寫XXX.aidl檔案
IServiceAIDL.aidl
// IServiceAIDL.aidl
package com.xm.androiddemo;
//aidl僅支援一些接本的java型別,除了那些基本型別均必須import進來
import com.xm.androiddemo.IActivityAIDL;
// Declare any non-default types here with import statements
//Server 提供給 client 的介面檔案定義
//Service(Server) 暴露給 Activity(Client) 的介面定義在 aidl檔案中
interface IServiceAIDL {
void callService();
//在 Activity 中註冊 ActivityADIL 到Service中,使得 Service 可以回撥 Activity 中的方法
void registActivityCallBack(IActivityAIDL callback);
}
b. Eclipse或者Android Studio會自動根據如上aidl檔案生成IServiceAIDL.java檔案
Eclipse生成的gen目錄下,Studio生成在$CodePath/app/build/generated/source/aidl/
debug/com/xm/androiddemo/IServiceAIDL.java
同樣你可以自己執行aidl工具來生成.aidl檔案對應的java檔案: aidl IServiceAIDL.aidl $outputPath
具體的Code我就不貼了,自行在IServiceAIDL.java中找到IServiceAIDL, Stub, Proxy三個類,
仔細看看理解一下
c. Server程序中需要提供服務的Code中實現Stub類中的介面
d.Client程序中通過建立IServiceAIDL物件來呼叫aidl檔案中定義的服務介面
Demo的細節參考如下兩個例子:
2)開發者自己寫IInterface子類,定義必要的介面,以ActivityManagerService為例來說明
IPC Binder機制涉及的三個類對應名字:
介面類:IActivityManager.java 包含所有ActivityManagerService的提供的服務介面以及介面程式碼(數字代號)
Stub類:ActivityManagerNative.java 繼承自Binder並implements IActivityManager介面類
Proxy類:ActivityManagerProxy.java ActivityManagerNative的內部類,implements IActivityManager介面類
Client與Server對以上各類的實現:
Client程序: Instrumentation類通過ActivityManagerNative.getDefault()獲取到IActivityManager介面物件,由於AMS
屬於遠端程序因此queryLocalInterface應該返回null,從而new一個ActivityManagerProxy物件,傳入AMS
程序的Binder物件引用,呼叫ActivityManagerProxy的startActivity方法,在startActivity的實現主要將IPC
需要傳輸的資料封裝成Parcel物件,然後呼叫Binder的transact方法,進入Binder驅動流程。
Server程序: ActivityManagerService繼承自ActivityManagerNative,也即ActivityManagerService本身為本程序的Binder
型別,實現IActivityManager定義的服務介面。接著上面Client的startActivity執行流程,進入Binder驅動流程
之後,底層驅動處理完畢之後回撥上層ActivityManagerNative的onTransact方法,根據傳入的介面代號呼叫
ActivityManagerService的實現的startActivity
印證如上的分析,簡單添加了幾句log,列印順序同上面分析一致
01-01 08:08:16.112 D/ipclog ( 1817): ActivityManagerProxy transact START_ACTIVITY_TRANSACTION
01-01 08:08:16.122 D/ipclog ( 596): ActivityManagerNative onTransact START_ACTIVITY_TRANSACTION
01-01 08:08:16.122 D/ipclog ( 596): ActivityManagerService startActivity
如上log資訊可以看兩個程序號1817和596,596為AMS所在Server程序,1817為應用程序
應用程序transact一個IPC請求之後,Binder驅動通過onTransact回撥到Server程序呼叫服務介面的實現。
IPC的內容暫且分析到這裡,總的來說對這個流程有了個初步的認識,深層次的東西回頭再學習補充。。。
參考
1.http://blog.csdn.net/linmiansheng/article/details/42438813