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進行詳細的學習:

1.Android Bander設計與實現 - 設計篇

2.淺談Service Manager成爲Android進程間通信(IPC)機制Binder守護進程之路


在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文件

          aidl文件書寫規則參考Android Interface Definition Language (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的細節參考如下兩個例子:

         一個簡單的demo學習Android遠程Service(AIDL的使用)

         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




   



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章