Android進程間通訊機制Binder應用層分析

1. 概述java

學姐今天覆習了下Android進程間通訊方式,打算從基本概念、使用緣由、基本使用、原理分析幾個方面來說講。android

想要對進程間通訊方式有個相對全面的瞭解,就先從幾個比較重要的概念IPC、AIDL、Binder提及吧。緩存

(1)IPC:Inter-Process Communication,即進程間通訊安全

(2)AIDL:Android Interface Definition Language,即Android接口定義語言。Client和Service要實現 ide

跨進程通訊,必須遵循的接口規範。須要建立.aidl文件,外在表現上和Java中的interface有點相似。性能

(3)Binder:Android進程間通訊是經過Binder來實現的。遠程Service在Client綁定服務時,會在onBind()的回調中返回一個Binder,當Client調用bindService()與遠程Service創建鏈接成功時,會拿到遠程Binder實例,從而使用遠程Service提供的服務。this

 

2. 爲何使用Binder?.net

下面內容學姐參考別人的博文,進行了總結。代理

Linux系統進程間通訊方式:code

(1)傳統機制。如管道(Pipe)、信號(Signal)和跟蹤(Trace),適用於父子進程或兄弟進程,其中命名管道(Named Pipe),支持多種類型進程

(2)System V IPC機制。如報文隊列(Message)、共享內存(Share Memory)和信號量(Semaphore)

(3)Socket通訊

然而,以上方式在性能和安全性方面存在不足:

(1)性能方面。管道和隊列採用存儲轉發方式,數據從發送方緩存區->內核緩存區->接收方緩存區,會經歷兩次拷貝過程;共享內存無拷貝但控制複雜;Socket傳輸效率低下,且鏈接的創建與中斷有必定開銷。

(2)安全性方面。傳統IPC方式沒法得到對方進程可靠的UID和PID,沒法鑑別對方身份,若採用在數據包裏填入UID/PID的方式,容易被惡意程序利用;傳統IPC方式的接入點是開放性的,沒法創建私有通道,容易被惡意程序猜想出接收方地址,得到鏈接。

而Binder是基於C/S通訊模式,傳輸過程只須要一次拷貝,且爲Client添加UID/PID身份,性能和安全性更好,所以Android進程間通訊使用了Binder。

 

3. 基本使用

假設本地Client須要使用遠程Service的計算器功能。

(1)新建Client和遠程Service兩個Android工程。

(2)在遠程Service工程中,建立ICalculator.aidl文件,並建立CalculatorService類。


(3)在Client工程中,拷貝以上.aidl文件及目錄,使用Service提供的服務。

(4)啓動Client和Service工程,便可實現進程間通訊。

 

4. 原理分析

因爲Binder機制涉及的東西不少。學姐本文並不打算深刻到內核源碼,關於Client是怎樣獲取到遠程Binder的會在後續文章再講述。下面主要是從應用層角度分析。

咱們先看看ICalculator.aidl編譯生成的ICalculator.java文件。


在基本使用部分,咱們能夠看到,Client在與Service創建鏈接成功後,會拿到遠程Binder實例(此處不能直接使用遠程Binder緣由還不是很清楚),並調用Stub的asInterface方法將其轉換成ICalculator接口。

mCalculator = ICalculator.Stub.asInterface(service);

這一步執行的操做是:根據接口描述符,從Binder中本地查找對應的接口,如有則直接返回;不然,將Binder對象傳給本地代理Stub.Proxy對象,並返回本地代理,由本地代理來接管相應的服務,Proxy也實現了ICalculator接口。

這一步以後,Client就可使用遠程Service提供的服務了。

再看看onClick()事件中的加法操做。

result = mCalculator.add(2, 1);

mCalculator即爲上面獲得的本地代理對象,其add()的實現是
 

@Override 
public int add(int a, int b) throws android.os.RemoteException
{
    android.os.Parcel _data = android.os.Parcel.obtain();
    android.os.Parcel _reply = android.os.Parcel.obtain();
    int _result;
    try {
        _data.writeInterfaceToken(DESCRIPTOR);
        _data.writeInt(a);
        _data.writeInt(b);
        mRemote.transact(Stub.TRANSACTION_add, _data, _reply, 0);
        _reply.readException();
        _result = _reply.readInt();
    }
    finally {
        _reply.recycle();
        _data.recycle();
    }
    return _result;
}

能夠看到其實是調用鏈接創建成功後的遠程Binder的transact(add)方法。再看看Binder.transact實現

public final boolean transact(int code, Parcel data, Parcel reply,
        int flags) throws RemoteException {
    if (false) Log.v("Binder", "Transact: " + code + " to " + this);
    if (data != null) {
        data.setDataPosition(0);
    }
    boolean r = onTransact(code, data, reply, flags);
    if (reply != null) {
        reply.setDataPosition(0);
    }
    return r;
}

能夠看到最後調用了遠程Binder的onTransact()方法,也就是走到了遠程Binder的Stub.onTransact()方法。這個方法實現是

@Override 
public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) 
throws android.os.RemoteException
{
    switch (code)
    {
        case TRANSACTION_add:
        {
            data.enforceInterface(DESCRIPTOR);
            int _arg0;
            _arg0 = data.readInt();
            int _arg1;
            _arg1 = data.readInt();
            int _result = this.add(_arg0, _arg1);
            reply.writeNoException();
            reply.writeInt(_result);
            return true;
        }
        ...
    }
}

這裏最終調用到了遠程Service工程建立的ICalculator.Stub實例mBinder的add()方法即a+b,所以獲得了最後的結果。

 

好了,咱們再來梳理下,Client得到並使用Service服務的過程:

(1)Client與Service創建鏈接,獲得遠程Binder(這個Binder就是Service的onBind返回的Binder,可是客戶端不能直接使用,具體緣由還不是很明確)。

(2)將遠程Binder傳給本地代理,獲得本地代理Stub.Proxy實例。

(3)經過本地代理Stub.Proxy實例間接調用遠程Binder對象的add()方法。 具體實現是:因爲遠程Binder已經傳給了本地代理Stub.Proxy。那麼經過本地代理Stub.Proxy實例間接調用遠程Binder的transact(TRANSACTION_add)操做;調用遠程Binder的onTransact()方法;調用遠程Binder的實現類ICalculator.Stub的add()方法

(4)獲得結果

 

下面再總結下ICalculator、Stub、Proxy這3個類的關係:

ICalculator:就是一個接口類。內部包括以前的接口方法和靜態Stub類。

Stub:遠程Binder實現類。繼承類Binder和ICalculator接口。

Proxy:遠程Binder代理類。實現ICalculator接口。

 

5. 總結

(1)Binder至關於不一樣進程間數據通訊的通道

(2)核心是代理模式,使用本地代理Proxy操做遠端Binder,使用相應服務

(3)如理解有誤,歡迎指正

 

6. 參考連接

http://blog.csdn.net/singwhatiwanna/article/details/19756201

http://blog.csdn.net/luoshengyang/article/details/6618363

相關文章
相關標籤/搜索