圖解Android – Binder 和 Service

  • 2020 年 10 月 25 日
  • 筆記

轉載://www.cnblogs.com/samchen2009/p/3316001.html

在 Zygote啟動過程 一文中我們說道,Zygote一生中最重要的一件事就是生下了 System Server 這個大兒子,System Server 擔負著提供系統 Service的重任,在深入了解這些Service 之前,我們首先要了解 什麼是Service?它的工作原理是什麼?

1. Service是什麼?

  簡單來說,Service就是提供服務的代碼,這些代碼最終體現為一個個的接口函數,所以,Service就是實現一組函數的對象,通常也稱為組件。Android 的Service 有以下一些特點:

  1. 請求Service服務的代碼(Client)  和 Service本身(Server) 不在一個線程,很多情況下不在一個進程內。跨進程的服務稱為遠端(Remote)服務,跨進程的調用稱為IPC。通常應用程序通過代理(Proxy)對象來訪問遠端的Service。
  2. Service 可以運行在native 端(C/C++),也可以運行在Java 端。同樣,Proxy 可以從native 端訪問Java Service, 也可以從Java端訪問native service, 也就是說,service的訪問與語言無關。
  3. Android里大部分的跨進程的IPC都是基於Binder實現。
  4. Proxy 通過 Interface 類定義的接口訪問Server端代碼。
  5. Service可以分為匿名和具名Service. 前者沒有註冊到ServiceManager, 應用無法通過名字獲取到訪問該服務的Proxy對象。
  6. Service通常在後台線程執行(相對於前台的Activity), 但Service不等同於Thread,Service可以運行在多個Thread上,一般這些Thread稱為 Binder Thread.

   要了解Service,我們得先從 Binder 入手。

  2.  Binder

    

    先給一張Binder相關的類圖一瞰Binder全貌,從上面的類圖(點擊看大圖)跟Binder大致有這麼幾部分:

           Native 實現:  IBinder,  BBinder, BpBinder, IPCThread, ProcessState, IInterface, etc

           Java 實現:  IBinder, Binder, BinderProxy, Stub, Proxy.

           Binder Driver: binder_proc, binder_thread, binder_node, etc.

    我們將分別對這三部分進行詳細的分析,首先從中間的Native實現開始。

    通常來說,接口是分析代碼的入口,Android中’I’ 打頭的類統統是接口類(C++里就是抽象類), 自然,分析Binder就得先從IBinder下手。先看看他的定義。

          

複製代碼
class IBinder : public virtual RefBase
{
public:
    ...
    virtual sp<IInterface>  queryLocalInterface(const String16& descriptor); //返回一個IInterface對象
    ...
    virtual const String16& getInterfaceDescriptor() const = 0; 
    virtual bool            isBinderAlive() const = 0;
    virtual status_t        pingBinder() = 0;
    virtual status_t        dump(int fd, const Vector<String16>& args) = 0;
    virtual status_t        transact(   uint32_t code,
                                        const Parcel& data,
                                        Parcel* reply,
                                        uint32_t flags = 0) = 0;
    virtual status_t        linkToDeath(const sp<DeathRecipient>& recipient,
                                        void* cookie = NULL,
                                        uint32_t flags = 0) = 0;
    virtual status_t        unlinkToDeath(  const wp<DeathRecipient>& recipient,
                                            void* cookie = NULL,
                                            uint32_t flags = 0,
                                            wp<DeathRecipient>* outRecipient = NULL) = 0;
    ...
    virtual BBinder*        localBinder();  //返回一個BBinder對象
    virtual BpBinder*       remoteBinder(); //返回一個BpBinder對象
};
複製代碼

    有接口必然有實現,從圖中可以看出,BBinder和BpBinder都是IBinder的實現類,它們幹啥用的,有啥區別?有興趣同學可以去分別去讀讀他們的代碼,分別在

  •  Bpinder: frameworks/native/lib/binder/BpBinder.cpp
  •  BBinder: frameworks/native/lib/binder/Binder.cpp

    這裡我們簡單總結一下他們的區別:

接口 BBinder BpBinder
queryLocalInterface() 沒有實現, 默認實現 IBinder 默認{reutrn NULL};   沒有實現 IBinder 默認實現 {return NULL}
getInterfaceDescriptor()   {return sEmptyDescriptor;}       (this)->transact(INTERFACE_TRANSACTION, send, &reply);
     …
    mDescriptorCache = res;  
isBinderAlive()   {return true;} {return mAlive != 0;}
pingBinder() {return NoError;} {transact(PING_TRANSACTION, send, &reply);
linkToDeath() {return INVALID_OPERATION;}   {self->requestDeathNotification(mHandle, this);}
unlinkToDeath()   {return INVALID_OPERATION;} {self->clearDeathNotification(mHandle, this);}
localBinder() {return this;} 沒有實現, IBinder默認實現 {return NULL};
remoteBinder() 沒有實現,IBinder默認實現 {return NULL;} {return this};
transact() {err = onTransact(code, data, reply, flags);} IPCThreadState::self()->transact(mHandle, code, data, reply, flags);
onTransact()

      switch (code) {
        case INTERFACE_TRANSACTION:
            reply->writeString16(getInterfaceDescriptor());
            return NO_ERROR;        …

沒有實現

 

看出來了吧,它們的差異在於它們是通信兩端的不同實現,BBinder是服務端,而BpBinder是客戶端,為什麼這麼說?

  1.  pingBinder, BBinder直接返回OK,而BpBinder需要運行一個transact函數,這個函數具體做什麼,我們後面會介紹。
  2.  linkToDeath()是用來在服務掛的時候通知客戶端的,那服務端當然不需要自己監視自己咯,所以BBinder直接返回非法,而Bpbinder需要通過requestDeathNotification()要求某人完成這個事情,究竟是誰提供這個服務?答案後面揭曉。
  3.  在Android中,remote一般代表某個遠端對象的本地代理,想像一下航空公司和機票代理,BBinder是航空公司,當然沒有remote的了,那BpBinder就是機票代理了,所以remote()自然返回自己了。
  4.  Transact的英文意思是交易,就是買賣嘛,那自然transact()就是買的操作,而onTransact()就是賣的操作,BBinder的transact()的實現就是onTransact(), 航空公司的買票當然不用通過機票代理了,直接找自己人就好了。

所以結論是,BBinder代表着服務端,而BpBinder則是它在客戶端的代理,客戶程序通過BpBinder的transact()發起請求,而服務器端的BBinder在onTranscat()里響應請求,並將結果返回。

可是交易肯定有目標的吧,回到航空公司和機票代理的例子,如果要訂去某個地方的機票,我們怎麼也得先查詢一下都有那些航班,然後才能告訴機票代理訂具體的航班號吧。這裡的查詢和預訂可以看成服務的接口函數,而航班號就是我們傳遞給機票代理的參數。客戶程序通過queryLocalInterface() 可以知道航空公司都提供哪些服務。

可是奇怪的是BBinder和BpBinder都沒有實現這個接口啊,那肯定另有他人實現這個類了,這個人就是IInterface.h, 看看代碼

複製代碼
template<typename INTERFACE>
inline sp<IInterface> BnInterface<INTERFACE>::queryLocalInterface(
        const String16& _descriptor)
{
    if (_descriptor == INTERFACE::descriptor) return this;
    return NULL;
}
複製代碼

 
BnInterface<INTERFACE> 對象將自己強制轉換成 IInterface對象返回,看看BnInterface的定義:

複製代碼
template<typename INTERFACE>
class BnInterface : public INTERFACE, public BBinder
{
public:
    virtual sp<IInterface>      queryLocalInterface(const String16& _descriptor);
    virtual const String16&     getInterfaceDescriptor() const;

protected:
    virtual IBinder*            onAsBinder();
};
複製代碼

 是一個模板類,繼承了BBinder, 還有模板 INTERFACE。我們剛才已經看過,BBinder沒有實現queryLocalInterface(), 而BnInterface 返回自己,可以他並沒有繼承IInterface, 怎麼可以強制轉換呢,唯一的解釋就是 INTERFACE模板必須繼承和實現IInterface.

複製代碼
class IInterface : public virtual RefBase
{
public:
            IInterface();
            sp<IBinder>         asBinder();
            sp<const IBinder>   asBinder() const;           
protected:
    virtual                     ~IInterface();
    virtual IBinder*            onAsBinder() = 0;
};
複製代碼

 這也太簡單了吧,只是定義了 從Interface 到 IBinder的轉換接口 asBinder, 而剛才我們研究的queryLocalInterface() 正好反過來,說明IBinder 和 IInterface 之間是可以互轉的,一個人怎麼可以變成另外一個人呢?唯一的解釋就是這個人有雙重性格,要麼他同時繼承 IInterface 和 IBinder, 要麼他體內有這兩個對象同時存在,不賣關子了,在服務端,這個雙重性格的人就是BnXXX, XXX 代表某個具體的服務,我們以圖中的BnMediaPlayer為例,看看他的定義

複製代碼
class BnMediaPlayer: public BnInterface<IMediaPlayer>
{
public:
    virtual status_t    onTransact( uint32_t code,
                                    const Parcel& data,
                                    Parcel* reply,
                                    uint32_t flags = 0);
};

class IMediaPlayer: public IInterface
{
public:
    DECLARE_META_INTERFACE(MediaPlayer);
    ...

}
複製代碼

 

這下本性都露出來了,IBinder 和 IInterface 的影子都露出來了,讓我們用圖梳理一下 (箭頭代表繼承關係)

             

歸納一下,

  1.  BBinder 實現了大部分的IBinder 接口,除了onTransact() 和 queryLocalInterface(), getInterfaceDescriptor();
  2.  BnInterface 實現了IBinder的queryLocalInterface()和getInterfaceDescriptor(), 但是其必須藉助實際的接口類。
  3.  BnMediaPlayer只是定義了onTransact(), 沒有實現。
  4.  onTransact()的具體實現在Client類。

為什麼搞得那麼複雜?Google 是希望通過這些封裝儘可能減少開發者的工作量,開發一個native的service 開發者只需要做這麼幾件事(上圖中深色部分):

  1. 定義一個接口文件, IXXXService, 繼承IInterface
  2. 定義BnXXX(), 繼承 BnInterface<IXXXService)
  3. 實現一個XXXService類,繼承BnXXX(), 並具體實現onTransact() 函數。

那客戶端呢? 我們的目標是找到一個類,它必須同時擁有IBinder 和 IIterface的特性, 先看看BpBinder 吧

   

class BpBinder : public IBinder

 

跟IInterface 沒有關係,那一定是別人,看看BpInterface 吧,

複製代碼
template<typename INTERFACE>
class BpInterface : public INTERFACE, public BpRefBase
{
public:
    BpInterface(const sp<IBinder>& remote);
protected:
    virtual IBinder*            onAsBinder();
};
複製代碼

 

我們剛才已經知道了,INTERFACE 是 IMediaPlayer, 它繼承了IInterface, IInterface 的對象找到了, 但跟IBinder 沒關係?只剩下BpRefBase 了,

複製代碼
class BpRefBase : public virtual RefBase
{
protected:
    ...
    inline  IBinder*        remote()                { return mRemote; }
    ...
private:
    ...
    IBinder* const          mRemote;
    RefBase::weakref_type*  mRefs;
    volatile int32_t        mState;
};
複製代碼

 

 有了,BpRefBase 里有IBinder 成員變量,看來在客戶端,沒有一個類同時繼承IBinder 和 IInterface, 但是有一個類繼承了其一,但包含了另外一個,這種在設計模式里成為組合(Composition).

 還是不太明白?還是用圖解釋吧,

 

看明白了?從BpInterface開始,通過BpRefBase 我們可以找到IBinder, 這個轉換就在 asBinder() 的實現里,看看代碼

複製代碼
sp<IBinder> IInterface::asBinder(){
    return this ? onAsBinder() : NULL;
}

sp<const IBinder> IInterface::asBinder() const{
    return this ? const_cast<IInterface*>(this)->onAsBinder() : NULL;
}

template<typename INTERFACE>
inline IBinder* BpInterface<INTERFACE>::onAsBinder()
{
    return remote();
}

template<typename INTERFACE>
IBinder* BnInterface<INTERFACE>::onAsBinder()
{
    return this;
}
複製代碼

這裡印證我們上面兩張圖的正確性,onAsBinder是轉換的發生的地方,服務端(BnInterface)的實現直接返回了自己,因為它繼承了兩者,而客戶端(BpInterface)則需要通過remote()(返回mRemote 成員變量)獲取,因為他自己本身不是IBinder,

那個BpRefbase的mRemote是如何被賦值的?看看以下代碼

//frameworks/native/libs/binder/binder.cpp
BpRefBase::BpRefBase(const sp<IBinder>& o)
    : mRemote(o.get()), mRefs(NULL), mState(0)
{
   ...
}

 

//frameworks/native/include/binder/iinterface.h
template<typename INTERFACE>
inline BpInterface<INTERFACE>::BpInterface(const sp<IBinder>& remote)
    : BpRefBase(remote)
{
}

 

複製代碼
//frameworks/av/media/libmedia/IMediaPlayer.cpp
class BpMediaPlayer: public BpInterface<IMediaPlayer> { public: BpMediaPlayer(const sp<IBinder>& impl) : BpInterface<IMediaPlayer>(impl) { } ... }
複製代碼

 

原來是從子類一級一級注入的,那唯一的問題就是在哪裡完成這個注入操作, 馬上搜索”new BpMediaPlayer”, 奇怪,竟然沒有,試試搜索”IMediaPlayer「,發現了一點線索

複製代碼
   //av/media/libmedia/IMediaPlayerService.cpp

   70:     virtual sp<IMediaPlayer> create(
   71:             const sp<IMediaPlayerClient>& client, int audioSessionId) {
   72          Parcel data, reply;
   73:         ...          
   77          remote()->transact(CREATE, data, &reply); 
   78:         return interface_cast<IMediaPlayer>(reply.readStrongBinder()); //reply里讀出IBinder,然後轉成IMediaPlayer接口對象
   79      }
複製代碼

 

這裡通過interface_cast 直接把IBinder 轉換成了 IMediaPlayer, interface_cast 到底有什麼魔力?

template<typename INTERFACE>
inline sp<INTERFACE> interface_cast(const sp<IBinder>& obj)
{
    return INTERFACE::asInterface(obj);
}

 

繼續跟進 asInterface, 結果發現里以下代碼

複製代碼
#define DECLARE_META_INTERFACE(INTERFACE)                               \
    static const android::String16 descriptor;                          \
    static android::sp<I##INTERFACE> asInterface(                       \
            const android::sp<android::IBinder>& obj);                  \
    virtual const android::String16& getInterfaceDescriptor() const;    \
    I##INTERFACE();                                                     \
    virtual ~I##INTERFACE();                                            \


#define IMPLEMENT_META_INTERFACE(INTERFACE, NAME)                       \
    const android::String16 I##INTERFACE::descriptor(NAME);             \
    const android::String16&                                            \
            I##INTERFACE::getInterfaceDescriptor() const {              \
        return I##INTERFACE::descriptor;                                \
    }                                                                   \
    android::sp<I##INTERFACE> I##INTERFACE::asInterface(                \
            const android::sp<android::IBinder>& obj)                   \
    {                                                                   \
        android::sp<I##INTERFACE> intr;                                 \
        if (obj != NULL) {                                              \
            intr = static_cast<I##INTERFACE*>(                          \
                obj->queryLocalInterface(                               \
                        I##INTERFACE::descriptor).get());               \
            if (intr == NULL) {                                         \
                intr = new Bp##INTERFACE(obj);                          \
            }                                                           \
        }                                                               \
        return intr;                                                    \
    }                                                                   \
複製代碼

 

恍然大悟,原來在DECLARE_META_INTERFACE 這個宏里定義了asInterface, 在IMPLEMENT_META_INTERFACE 里實現了它,這裡果然有一個new BpMediaPlayer! 然後把它轉換成父父類 IMediaPlayer。

一切都清楚了,用一張圖來表示

客戶端從遠端獲取一個IBinder對象,接着生成BpMediaPlayer, 將其轉成 IMediaPlayer 接口對象,這是用戶程序看到的對象,並通過其調用接口方法,最終調到BpBinder的transact()。

問題又來了,這個transact() 怎麼傳遞到服務端,並最終調到 onTransact()?

回想一下,onTransact() 是IBinder的接口函數吧,而且Server的IBinder實現是BBinder, 那一定有人通過某種方式得到了BBinder對象。

這個人就是Binder Driver. 為了找到真相,必須用源頭開始,那就是transact()

複製代碼
status_t BpBinder::transact(
    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
     ...
        status_t status = IPCThreadState::self()->transact(
            mHandle, code, data, reply, flags);
    ...
    return DEAD_OBJECT;
}
複製代碼

 

IPCThreadState的transact()函數相比IBinder 多了一個mHandle, 啥來歷?

BpBinder::BpBinder(int32_t handle)
    : mHandle(handle)

 

構造帶進來的,趕緊找「new BpBinder”, 結果在ProcessState.cpp 看到了

sp<IBinder> ProcessState::getStrongProxyForHandle(int32_t handle)
{
    ...
        IBinder* b = e->binder;
        if (b == NULL || !e->refs->attemptIncWeak(this)) {
            b = new BpBinder(handle); 

 

找誰call了getStrongProxyForHandle?為了快速找到調用棧,我們在BpBinder的構造函數里加了這麼幾句話:

#include <utils/CallStack.h>
...
CallStack cs;
cs.update();
cs.dump("BpBinder")

 

然後得到了下面的打印

09-29 07:11:14.363  1624  1700 D BpBinder: #00  pc 0001eb34  /system/lib/libbinder.so (android::BpBinder::BpBinder(int)+260)
09-29 07:11:14.363  1624  1700 D BpBinder: #01  pc 0003b9a2  /system/lib/libbinder.so (android::ProcessState::getStrongProxyForHandle(int)+226)
09-29 07:11:14.363  1624  1700 D BpBinder: #02  pc 00032b8c  /system/lib/libbinder.so (android::Parcel::readStrongBinder() const+316) //frameworks/native/libs/binder/Parcel.cpp:247
09-29 07:11:14.363  1624  1700 D BpBinder: #03  pc 000ad9d2  /system/lib/libandroid_runtime.so //frameworks/base/core/jni/android_os_Parcel.cpp:355
09-29 07:11:14.363  1624  1700 D BpBinder: #04  pc 00029c5b  /system/lib/libdvm.so (dvmPlatformInvoke+79) //dalvik/vm/arch/x86/Call386ABI.S:128

 

#04 dvmPlatformInvork 說明這是一個Jni調用,#03 對應的代碼是

return javaObjectForIBinder(env, parcel->readStrongBinder());

 

應該是Java傳下來一個Parcel對象,然後由本地代碼進行解析,從中讀出IBinder對象,並最終返回。也就是說,遠端有人將這個IBinder對象封在Parcel里。還是沒有頭緒?繼續順着調用棧往前看,

#02  對應於下面的代碼

複製代碼
status_t unflatten_binder(const sp<ProcessState>& proc,
    const Parcel& in, sp<IBinder>* out)
{
    const flat_binder_object* flat = in.readObject(false);
    ...case BINDER_TYPE_HANDLE:
                *out = proc->getStrongProxyForHandle(flat->handle);
                return finish_unflatten_binder(
                    static_cast<BpBinder*>(out->get()), *flat, in);
        }        
    }
    return BAD_TYPE;
}
複製代碼

 

複製代碼
#bionic/libc/kernel/common/linux/binder.h
struct flat_binder_object { unsigned long type; unsigned long flags; union { void *binder; signed long handle; }; void *cookie; };
複製代碼

 

原來mHandle就是flat_binder_object裏面的handle, 它只是一個數字!這個數據結構定義在Kernel里,是經過Kernel轉手的。越來越亂了,趕緊整理一下思路:

1.  Kernel 封裝了一個數據結構(flat_binder_object),裏面帶有一個數字(mHandle)。

2.  客戶端獲取這個數字後,生成一個BpBinder的對象。

3.  然後當客戶端需要訪問遠端服務的時候,將這個數字附上。

回到現實生活,機票代理需要向航空公司查詢或訂票的話,一定要知道是哪個航空公司,莫非這個號就是航空公司的編號?

恭喜你,就是那麼簡單,這個號就對應了服務器端的提供的某一個服務,Android 中每個Service都有一個號碼(根據創建時間遞增,0號Service 是ServiceManager,讓我用下面的圖來描述整個過程吧,

 

1. 在已知服務名的情況下,App 通過getService() 從ServiceManager 獲取該服務的信息,該信息封裝在Parcel里。

2. 應用程序收到返回的這個Parcel對象(通過Kernel), 從中讀取出flat_binder_object 對象,最終從對象中得到服務對應的服務號,mHandle.

3. 以該號碼作為參數輸入生成一個IBinder對象(實際是BpBinder)。

4. 應用獲取該對象後,通過asInterface(IBinder*) 生成服務對應的Proxy對象(BpXXX),並將其強轉為接口對象(IXXX),然後直接調用接口函數。

5. 所有的接口對象調用最終會走到BpBinder->transact()函數,這個函數調用IPCThreadState->transact()並以Service號作為參數之一。

6. 最終通過系統調用ioctrl() 進入內核空間,Binder驅動根據傳進來的Service 號尋找該Service正處於等待狀態的Binder Thread, 喚醒它並在該線程內執行相應的函數,並返回結果給APP。

強調一下:

1. 從應用程序的角度來看,他只認識IBinder 和 IMediaPlayer 這兩個類,但真正的實現在BpBinder 和 BpMediaPlayer, 這正是設計模式所推崇的「 Programs to interface, not implementations”, 可以說Android 是一個嚴格遵循設計模式思想精心設計的系統,我們將來會就這個話題進行深入的探討。

2. 客戶端應該層層的封裝,最終的目的就是獲取和傳遞這個mHandle 值,從圖中,我們看到,這個mHandle至來自與IServiceManager, 他是一個管理其他服務的服務,通過服務的名字我們可以拿到這個服務對應的Handle號,類似網絡域名服務系統。但是我們說了,IServiceManager也是服務啊,要訪問他我們也需要一個Handle號啊,對了,就如同你必須為你的機器設置DNS 服務器地址,你才能獲得DNS 服務。在Android系統里, 默認的將ServiceManger的Handler號設為0,0就是DNS服務器的地址,這樣,我們通過調用 getStrongProxyForHandle(0) 就可以拿到ServiceManager 的IBinder 對象,當然,系統提供一個 getService(char *)函數來幫助完成這個過程。

3.  Android Binder 的設計目標就是讓訪問遠端服務就像調用本地函數一樣簡單,但是遠端的對象不在本地控制之內,我們必須保證調用過程中遠端的對象不能被析構,否則本地應用程序將很有可能崩潰。同時,萬一遠端服務異常退出,如Crash, 本地對象必須知曉從而避免後續的錯誤。Android 通過 智能指針 和 DeathNotification 來支持這兩個要求,我們會有專門的章節介紹智能指針,這裡我們會在後面簡單介紹 DeathNotifycation的實現原理。

Binder的上層設計邏輯簡單介紹完畢。我們接下來看看Binder的底層設計。

3. Binder Driver

我們知道,Linux的進程空間相互獨立,兩個進程只能通過Kernel space 進行互訪,所有的IPC 機制,最底層的實現都是在Kernel space.  Binder 也是如此,通過系統調用切入內核態,內核尋找到提供服務的進程,喚醒他並進入用戶空間,然後在某個線程里調用onTransact(), 完成特定操作,並將結果返回到應用程序。那Binder Driver是如何搭起連接服務端和客戶端的這座橋樑呢?

先看看binder driver 內部的數據結構吧:

 下面一一進行解釋:

 1.  Binder node:

      我們前面說過Service 其實是一個存在於某個進程里的對象,因此,進程PID 和 對象地址可以唯一的標識一個Service 對象,除此之外,因為這個對象可能被很多應用所使用,必須有引用計數來管理他的生命周期。這些工作都必須在內核里完成,Binder node 就是這樣一個結構體來管理每個Service 對象。

     

複製代碼
struct binder_node {
    int debug_id;              //kernel內部標識node的id
    struct binder_work work;   
    union {
        struct rb_node rb_node;
        struct hlist_node dead_node;
    };
    struct binder_proc *proc;  //Service所在進程的結構體
    struct hlist_head refs;    //雙向鏈表頭,鏈表裡存放一系列指針,指向引用該Service的binder_ref對象,
    int internal_strong_refs;  //內部強引用計數
    int local_weak_refs;       //弱引用計數
    int local_strong_refs;     //強引用計數
    binder_ptr __user ptr;     //Service對象地址
    binder_ptr __user cookie;  
    unsigned has_strong_ref:1; 
    unsigned pending_strong_ref:1; 
    unsigned has_weak_ref:1;
    unsigned pending_weak_ref:1;
    unsigned has_async_transaction:1;
    unsigned accept_fds:1;
    unsigned min_priority:8;
    struct list_head async_todo;
};
複製代碼

 

 2. binder_ref

 binder_ref 描述了每個對服務對象的引用,對應與Client端。如上圖所示,每個Ref通過node指向binder_node. 一個進程所有的binder_ref通過兩個紅黑樹(RbTree)進行管理,通過binder_get_ref() 和 binder_get_ref_for_node快速查找。

複製代碼
struct binder_ref {
    /* Lookups needed: */
    /*   node + proc => ref (transaction) */
    /*   desc + proc => ref (transaction, inc/dec ref) */
    /*   node => refs + procs (proc exit) */
    int debug_id;
    struct rb_node rb_node_desc; 
    struct rb_node rb_node_node;
    struct hlist_node node_entry;   
    struct binder_proc *proc;           //應用進程
    struct binder_node *node;
    uint32_t desc;
    int strong;
    int weak;
    struct binder_ref_death *death;  //如果不為空,則client想獲知binder的死亡
};
複製代碼

 

 3. binder_proc

 一個進程既包含的Service對象,也可能包含對其他Service對象的引用. 如果作為Service對象進程,它可能會存在多個Binder_Thread。這些信息都在binder_proc結構體進行管理。

複製代碼
struct binder_proc {
    struct hlist_node proc_node; //全局鏈表 binder_procs 的node之一
    struct rb_root threads; //binder_thread紅黑樹,存放指針,指向進程所有的binder_thread, 用於Server端
    struct rb_root nodes;   //binder_node紅黑樹,存放指針,指向進程所有的binder 對象
    struct rb_root refs_by_desc; //binder_ref 紅黑樹,根據desc(service No) 查找對應的引用
    struct rb_root refs_by_node; //binder_ref 紅黑樹,根據binder_node 指針查找對應的引用
    int pid;
    struct vm_area_struct *vma;
    struct mm_struct *vma_vm_mm;
    struct task_struct *tsk;
    struct files_struct *files;
    struct hlist_node deferred_work_node;
    int deferred_work;
    void *buffer;
    ptrdiff_t user_buffer_offset;

    struct list_head buffers;
    struct rb_root free_buffers;
    struct rb_root allocated_buffers;
    size_t free_async_space;

    struct page **pages;
    size_t buffer_size;
    uint32_t buffer_free;
    struct list_head todo; //task_list, binder_work鏈表,存放指針最終指向某個binder_transaction對象
    wait_queue_head_t wait;
    struct binder_stats stats;
    struct list_head delivered_death;
    int max_threads;
    int requested_threads;
    int requested_threads_started;
    int ready_threads;
    long default_priority;
    struct dentry *debugfs_entry;
};
複製代碼

 

為了實現快速的查找,binder_proc內部維護了若干個數據結構,如圖中黃色高亮所示,

4. binder_transaction

每個transact() 調用在內核里都會生產一個binder_transaction 對象,這個對象會最終送到Service進程或線程的todo隊列里,然後喚醒他們來最終完成onTransact()調用。

複製代碼
struct binder_transaction {
    int debug_id;             //一個全局唯一的ID
    struct binder_work work; // 用於存放在todo鏈表裡
    struct binder_thread *from; //transaction 發起的線程。如果BC_TRANSACTION, 則為客戶端線程,如果是BC_REPLY, 則為服務端線程。
    struct binder_transaction *from_parent; //上一個binder_transaction. 用於client端
    struct binder_proc *to_proc; //目標進程
    struct binder_thread *to_thread; //目標線程
    struct binder_transaction *to_parent; //上一個binder_transaction, 用於server端
    unsigned need_reply:1;
    /* unsigned is_dead:1; */    /* not used at the moment */

    struct binder_buffer *buffer;
    unsigned int    code;
    unsigned int    flags;
    long    priority;
    long    saved_priority;
    kuid_t    sender_euid;
};
複製代碼

 

5. binder_thread

binder_proc里的threads 紅黑樹存放着指向binder_thread對象的指針。這裡的binder_thread 不僅僅包括service的binder thread, 也包括訪問其他service的調用thread. 也就是說所有與binder相關的線程都會在binder_proc的threads紅黑樹里留下記錄。binder_thread里最重要的兩個成員變量是 transaction_stack 和 wait.

複製代碼
struct binder_thread {
    struct binder_proc *proc;
    struct rb_node rb_node; //紅黑樹節點
    int pid;
    int looper;  //
    struct binder_transaction *transaction_stack; //transaction棧
    struct list_head todo;
    uint32_t return_error; 
    uint32_t return_error2; 
    wait_queue_head_t wait; //等待隊列,用於阻塞等待
    struct binder_stats stats;
};
複製代碼

在binder_proc裏面我們也能看到一個wait 隊列,是不是意味着線程既可以在proc->wait上等待,也可以在thread->wait上等待?binder driver 對此有明確的用法,所有的binder threads (server 端)都等待在proc->wait上。因為對於服務端來說,用哪個thread來響應遠程調用請求都是一樣的。然而所有的ref thread(client端)的返回等待都發生在調用thread的wait 隊列,因為,當某個binder thread 完成服務請求後,他必須喚醒特定的等待返回的線程。但是有一個例外,在雙向調用的情況下,某個Server端的thread將會掛在thread->wait上等待,而不是proc->wait. 舉個例子,假設兩個進程P1 和 P2,各自運行了一個Service, S1,S2, P1 在 thread T1 里調用S2提供的服務,然後在T1->wait里等待返回。S2的服務在P2的binder thread(T2)里執行,執行過程中,S2又調到S1里的某個接口,按理S1 將在P1的binder thread T3里執行, 如果P1接下來又調到了P2,那又會產生新的進程 T4, 如果這個反覆調用棧很深,需要耗費大量的線程,顯然這是非常不高效的設計。所以,binder driver 里做了特殊的處理。當T2 調用 S1的接口函數時,binder driver 會遍歷T2的transaction_stack, 如果發現這是一個雙向調用(binder_transaction->from->proc 等於P1), 便會喚醒正在等待reply的T1,T1 完成這個請求後,繼續等待S2的回復。這樣,只需要最多兩個Thread就可以完成多層的雙向調用。

binder_thread里的transaction_stack 是用鏈表實現的堆棧, 調用線程和服務線程的transaction有着不同的堆棧。下圖是上面這個例子的堆棧情形:

 

6. binder_ref_death

binder_ref 記錄了從client進程到server進程某個service的引用,binder_ref_death 是binder_ref的一個成員變量,它的不為空說明了client進程想得到這個service的死亡通知(嚴格意義上講,是service所在進程的死亡通知,因為一個進程一個/dev/binder的fd, 只有進程死亡了,driver才會知曉,通過 file_operations->release 接口)。

struct binder_ref_death {
    struct binder_work work;
    binder_ptr __user cookie;
};

 

我們可以下面一張時序圖來了解binder death notifycation 的全過程。

 

7. binder_work

從應用程序角度來看,所有的binder調用都是同步的。但在binder driver 內部,兩個進程間的交互都是異步的,一個進程產生的請求會變成一個binder_work, 並送入目標進程或線程的todo 隊列里,然後喚醒目標進程和線程來完成這個請求,並阻塞等待結果。binder_work的定義如下:

複製代碼
struct binder_work {
    struct list_head entry;
    enum {
        BINDER_WORK_TRANSACTION = 1,
        BINDER_WORK_TRANSACTION_COMPLETE,
        BINDER_WORK_NODE,
        BINDER_WORK_DEAD_BINDER,
        BINDER_WORK_DEAD_BINDER_AND_CLEAR,
        BINDER_WORK_CLEAR_DEATH_NOTIFICATION,
    } type;
};
複製代碼

 

很簡單,其實只定義了一個鏈表的節點和work的類型。

8. binder_buffer

進程間通信除了命令,還有參數和返回值的交換,要將數據從一個進程的地址空間,傳到另外一個進程的地址空間,通常需要兩次拷貝,進程A -> 內核 -> 進程B。binder_buffer 就是內核里存放交換數據的空間(這些數據是以Parcel的形式存在)。為了提高效率,Android 的 binder 只需要一次拷貝,因為binder 進程通過mmap將內核空間地址映射到用戶空間,從而可以直接訪問binder_buffer的內容而無需一次額外拷貝。binder_buffer由內核在每次發起的binder調用創建,並賦給binder_transaction->buffer. binder driver 根據binder_transaction 生產 transaction_data(包含buffer的指針而非內容), 並將其複製到用戶空間。

9. flat_binder_obj

前面我們說過,<proc, handle> 可以標識一個BpBinder 對象,而<proc, ptr> 可以標識一個BBinder對象。Binder Driver 會收到來自與BpBinder 和 BBinder的系統調用,它是如何判別它們的身份呢?答案就在flat_binder_obj里,先看看它的定義,

複製代碼
struct flat_binder_object {
 unsigned long type;  //見下面定義
 unsigned long flags;
 union {
 void *binder;            //BBinder,通過它driver可以找到對應的node
 signed long handle; //BpBinder,根據它driver可以找到對應的ref
 };
 void *cookie;
};

enum {
 BINDER_TYPE_BINDER = B_PACK_CHARS('s', 'b', '*', B_TYPE_LARGE),
 BINDER_TYPE_WEAK_BINDER = B_PACK_CHARS('w', 'b', '*', B_TYPE_LARGE),
 BINDER_TYPE_HANDLE = B_PACK_CHARS('s', 'h', '*', B_TYPE_LARGE),
 BINDER_TYPE_WEAK_HANDLE = B_PACK_CHARS('w', 'h', '*', B_TYPE_LARGE),
 BINDER_TYPE_FD = B_PACK_CHARS('f', 'd', '*', B_TYPE_LARGE),
};
複製代碼

union表明了在Server端和Client端它有着不同的解讀。type則表明了它的身份。binder driver 根據它可以找到BpBinder 和 BBinder 在內核中相對應的對象 (ref 或 node). flat_binder_obj 封裝在parcel里,詳見Parcel.cpp.

至此,binder driver裏面重要的數據結構都介紹完了,大家對binder driver的工作原理也有了大致的了解,這裡再稍作總結:

1.  當一個service向binder driver 註冊時(通過flat_binder_object), driver 會創建一個binder_node, 並掛載到該service所在進程的nodes紅黑樹。

2.  這個service的binder線程在proc->wait 隊列上進入睡眠等待。等待一個binder_work的到來。

3.  客戶端的BpBinder 創建的時候,它在driver內部也產生了一個binder_ref對象,並指向某個binder_node, 在driver內部,將client和server關聯起來。如果它需要或者Service的死亡狀態,則會生成相應的binfer_ref_death.

4.  客戶端通過transact() (對應內核命令BC_TRANSACTION)請求遠端服務,driver通過ref->node的映射,找到service所在進程,生產一個binder_bufferbinder_transaction 和 binder_work 並插入proc->todo隊列,接着喚醒某個睡在proc->wait隊列上的Binder_thread. 與此同時,該客戶端線程在其線程的wait隊列上進入睡眠,等待返回值。

5.  這個binder thread 從proc->todo 隊列中讀出一個binder_transaction, 封裝成transaction_data (命令為 BR_TRANSACTION) 並送到用戶空間。Binder用戶線程喚醒並最終執行對應的on_transact() 函數。

6.  Binder用戶線程通過transact() 向內核發送 BC_REPLY命令,driver收到後從其thread->transaction_stack中找到對應的binder_transaction, 從而知道是哪個客戶端線程正在等待這個返回。

7.  Driver 生產新的binder_transaction (命令 BR_REPLY), binder_buffer, binder_work, 將其插入應用線程的todo對立,並將該線程喚醒。

8.  客戶端的用戶線程收到回複數據,該Transaction完成。

9.  當service所在進程發生異常退出,driver 的 release函數被調到,在某位內核work_queue 線程里完成該service在內核態的清理工作(thread,buffer,node,work…), 並找到所有引用它的binder_ref, 如果某個binder_ref 有不為空的binder_ref_death, 生成新的binder_work, 送人其線程的todo 對立,喚醒它來執行剩餘工作,用戶端的DeathRecipient 會最終被調用來完成client端的清理工作。

下面這張時序圖描述了上述一個transaction完成的過程。不同的顏色代表不同的線程。注意的是,雖然Kernel和User space 線程的顏色是不一樣的,但所有的系統調用都發生在用戶進程的上下文里(所謂上下文,就是Kernel能通過某種方式找到關聯的進程(通過Kernel的current 宏),並完成進程相關的操作,比如說喚醒某個睡眠的線程,或跟用戶空間交換數據,copy_from, copy_to, 與之相對應的是中斷上下文,其完全異步觸發,因此無法做任何與進程相關的操作,比如說睡眠,鎖等)。

 

 

4. Java Binder

Binder 的學習已經接近尾聲了,我們已經研究了Binder Driver, C/C++的實現,就差最後一個部分了,Binder在Java端的實現了。Java端的實現與Native端類似,我們用下面的表格和類圖概括他們的關係

Native Java Note
IBinder IBinder  
IInterface IInterface  
IXXX IXXX aidl文件定義
BBinder Binder  通過JavaBBinder類作為橋樑
BpBinder BinderProxy  通過JNI訪問Native的實現
BnInterface N/A  
BpInterface   N/A  
BnXXX Stub aidl工具自動生成   
BpXXX     Proxy aidl工具自動生成 
     

 

 

 

 

 

 

 

 

 

 

可見,Java較Native端實現簡單很多,通過Aidl工具來實現類似功能。所以,要實現一個Java端的service,只需要做以下幾件事情:

1. 寫一個.aidl文件,裏面用AIDL語言定義一個接口類IXXX。

2.在Android.mk里加入該文件,這樣編譯系統會自動生成一個IXXX.java, 放在out/target/common/obj/JAVA_LIBRARIES/framework_intermediates/src/core 下面。

3. 在服務端,寫一個類,擴展IXXX.Stub,具體實現IXXX的接口函數。