Binder之簡單實例

Binder簡介

Binder是Android中使用的進程間通訊機制(IPC)。在Android系統中,應用程序是由Activity、Service、Broadcast Receiver和Content Provider四種類型的組件構成的,它們有可能運行在同一進程中,也有可能運行在不一樣的進程中。此外,各類系統組件也運行在獨立的進程中。這些運行在不一樣進程中的應用程序組件和系統組件之間的通訊機制就是Binder。
Android雖然構建在Linux上面,可是在IPC機制方面,沒有利用Linux提供IPC機制,而是使用了一套輕量級的IPC機制—Binder機制。Binder是基於OpenBinder來實現的。OpenBinder最早是由Be Inc.開發的,接着Palm Inc.也跟着使用。Binder是一種進程間通訊機制,它是一種相似於COM和CORBA分佈式組件架構,通俗一點,實際上是提供遠程過程調用(RPC)功能。android

Binder具備如下特色編程

  • 具備分佈式的架構。
  • 面向系統級的開發。面向系統層的,而不是面向應用層的。目標是進程和IPC,而不是面向跨網絡通信。
  • 自己使用C++語言實現。
  • 多線程編程的支持。支持多線程編程的各類線程模型。不強制使用特定的線程模型。
  • 可支持多操做系統平臺。從BeOS開始,到Windows和Palm OS Cobalt,再到Android。Binder都是能夠在這些不一樣平臺實現和使用的。Binder使用一些組件和對象來呈現一些基本的系統服務,好比進程和共享內存。它沒有試圖取代和隱藏操做系統中那些傳統的概念,而是擁抱和超越它們。這使得binder能夠支持大多數的傳統操做系統平臺。
  • 良好的硬件伸縮性。對硬件要求很低,這正好符合android的實際狀況,android的產品線普遍,芯片主頻各個層次的都有,要在低端的機器上跑的順暢,軟件自己的性能要求仍是很重要。
  • 用戶可定製性高。做爲IPC的機制實現,串聯了系統裏的大部分組件,而且將各個組件之間的耦合行降到最低。各個組件的能夠自由修改和替換,提升了用戶的可定製性。

Binder應用模型
一個IPC通信咱們能夠簡單理解成Client-Server模式,Client請求Service,Server接收到Client請求後處理相應,或可能帶回結果返回給Client。
圖片描述服務器

Binder機制在Android系統的進程間通信模型總結以下:網絡

  1. Client經過Service Manager獲得Server的Proxy。從Client角度看來Proxy和他的本地對象沒有什麼差異。它能夠像其餘本地對象同樣調用其方法,訪問其變量。
  2. Client經過調用Proxy的方法向Server發送請求信息。
  3. Proxy經過Binder設備節點(/dev/binder),把用戶請求信息發送到Linux內核空間(其實是內存共享),由Binder驅動獲取併發送到Server。
  4. Server處理用戶請求,並經過Linux內核的Binder驅動返回處理結果給Client的Proxy。
  5. Client收到Server的返回結果。

Binder機制的組成多線程

  • Binder Driver: Binder是內核中的一個字符驅動設備位於/dev/binder。這個設備是Android系統IPC的核心部分,客戶端(Client)的服務代理用來經過它向服務器(Server)發送請求,服務器也是經過它把處理結果返回給客戶端的服務代理對象。這部份內容,在Android中經過一個IPCThreadState對象封裝了對Binder驅動的操做。
  • Service Manager: 這個東西主要用來負責管理服務。Android中提供的系統服務都要經過Service Manager註冊本身,將本身添加進服務管理鏈表中,爲客戶端提供服務。而客戶端若是要和特定的系統服務端通信,就須要向Service Manager來查詢和得到所須要服務。能夠看出Service Manager是系統服務對象的管理中心。
  • Server: 須要強調的是這裏服務是指的是System Server,而不是SDK server,向客戶端提供服務。
  • Client: 通常是指Android系統上面的應用程序。它能夠請求Server中的服務。
  • Proxy: 是指在客戶端應用程序中獲取生成的Server代理(proxy)類對象。從應用程序角度看代理對象和本地對象沒有差異,均可以調用其方法,方法都是同步的,而且返回相應的結果。

一個最簡單的Binder傳輸

下面以一個簡單實例來分析Binder傳輸。該測試程序由client端調用add()函數,在server端完成加法操做,並返回結果。測試程序的目錄結構以下,
圖片描述架構

類圖以下所示。左側爲server端,右側爲client端。
圖片描述併發

Client端代碼解析

圖片描述
從Client端的代碼看起。Client若是想和Server進行通訊,必須先得到Server的遠程接口,這個過程經過Service Manager來實現。Service Manager用來管理Server而且向Client提供查詢Server遠程接口的功能。分佈式

1.---> BinderClientRun.cpp
2.
3.int main(int argc, char** argv)
4.{
5.    int sum = 0;
6.    sp<IBinderServiceTest> mBinderServiceTest;
7.
8.    if (mBinderServiceTest.get() == 0) {
9.        // 經過defaultServiceManager函數來得到Service Manager的遠程接口
10.        sp<IServiceManager> sm = defaultServiceManager(); 
11.        sp<IBinder> binder;
12. 
13.        // 在循環中使用sm->getService不斷嘗試得到名稱爲「my.binder.test」的Service,返回binder
14.        do {
15.            binder = sm->getService(String16("my.binder.test"));
16.            if (binder != 0)
17.                break;
18.                ALOGI("getService fail");
19.            usleep(500000); // 0.5 s
20.        } while (true);
21. 
22.        // 獲得Service的binder後,經過interface_cast,將這個binder轉化成BpBinderServiceTest
23.        mBinderServiceTest = interface_cast<IBinderServiceTest> (binder);
24.        ALOGE_IF(mBinderServiceTest == 0, "no IBinderServiceTest!?");
25.    }
26. 
27.    // BpBinderServiceTest,就能夠調用遠程server的接口了
28.    sum = mBinderServiceTest->add(3, 4);
29.    ALOGI("sum = %d", sum);
30.    return 0;
31.}

代碼中的interface_cast是如何將binder轉化爲BpBinderServiceTest的呢?Android有意隱藏了這一轉換,讓應用很輕鬆的完成這一轉換。看一下interface_cast的定義ide

1.---> IInterface.h
2. 
3.template<typename INTERFACE>
4.inline sp<INTERFACE> interface_cast(const sp<IBinder>& obj)
5.{
6.    return INTERFACE::asInterface(obj);
7.}

interface_cast是一個模板,它返回的是 IBinderServiceTest::asInterface。但在咱們的源碼中並無直接實現 asInterface,那它是在哪裏實現的呢?讓咱們先看一下兩個宏定義函數

1.---> IInterface.h
2. 
3.#define DECLARE_META_INTERFACE(INTERFACE)                               \
4.    static const android::String16 descriptor;                          \
5.    static android::sp<I##INTERFACE> asInterface(                       \
6.            const android::sp<android::IBinder>& obj);                  \
7.    virtual const android::String16& getInterfaceDescriptor() const;    \
8.    I##INTERFACE();                                                     \
9.    virtual ~I##INTERFACE();                                            \
10.
11.
12.#define IMPLEMENT_META_INTERFACE(INTERFACE, NAME)                       \
13.    const android::String16 I##INTERFACE::descriptor(NAME);             \
14.    const android::String16&                                            \
15.            I##INTERFACE::getInterfaceDescriptor() const {              \
16.        return I##INTERFACE::descriptor;                                \
17.    }                                                                   \
18.    android::sp<I##INTERFACE> I##INTERFACE::asInterface(                \
19.            const android::sp<android::IBinder>& obj)                   \
20.    {                                                                   \
21.        android::sp<I##INTERFACE> intr;                                 \
22.        if (obj != NULL) {                                              \
23.            intr = static_cast<I##INTERFACE*>(                          \
24.                obj->queryLocalInterface(                               \
25.                        I##INTERFACE::descriptor).get());               \
26.            if (intr == NULL) {                                         \
27.                intr = new Bp##INTERFACE(obj);                          \
28.            }                                                           \
29.        }                                                               \
30.        return intr;                                                    \
31.    }                                                                   \
32.    I##INTERFACE::I##INTERFACE() { }                                    \
33.    I##INTERFACE::~I##INTERFACE() { }

這兩個宏會在程序中被使用

1.---> IBinderServiceTest.h
2. 
3.class IBinderServiceTest: public IInterface {
4.public:                                            
5.    DECLARE_META_INTERFACE(BinderServiceTest);
6.
7.    virtual int add(int a, int b) = 0;             
8.};
9.
10. 
11.---> IBinderServiceTest.cpp
12. 
13.IMPLEMENT_META_INTERFACE(BinderServiceTest, "android.test.IBinderServiceTest");

將這兩個宏展開會等到

1.---> IBinderServiceTest.h
2. 
3.class IBinderServiceTest: public IInterface {
4.public:                                            
5.    static const android::String16 descriptor; 
6.    static android::sp<IBinderServiceTest > asInterface
7.                     (const android::sp<android::IBinder>& obj);
8.    virtual const android::String16& getInterfaceDescriptor() const; 
9.    IBinderServiceTest (); 
10.    virtual ~IBinderServiceTest (); 
11.    virtual int add(int a, int b) = 0;             
12.};
1.---> IBinderServiceTest.cpp
2.
3.    const android::String16 IBinderServiceTest ::descriptor("android.test.IBinderServiceTest"); 
4.    const android::String16& IBinderServiceTest ::getInterfaceDescriptor() const { 
5.        return IBinderServiceTest ::descriptor;
6.    }
7.    android::sp<IBinderServiceTest > IBinderServiceTest ::asInterface
8.                              (const android::sp<android::IBinder>& obj)
9.    {
10.        android::sp<IBinderServiceTest > intr;
11.        if (obj != NULL) {
12.            intr = static_cast<IBinderServiceTest *>
13.                         (obj->queryLocalInterface(IBinderServiceTest ::descriptor).get());
14.            if (intr == NULL) {
15.                intr = new BpBinderServiceTest (obj);
16.            }
17.        }
18.        return intr;
19.    }
20.    IBinderServiceTest ::IBinderServiceTest () { }
21.    IBinderServiceTest ::~IBinderServiceTest () { }

展開的宏裏,咱們找到了asInterface,這裏new了一個 BpBinderServiceTest,而後將其返回。Client端獲得Server端的代理BpBinderServiceTest後,就能夠像本地調用同樣來使用Server端的接口。示例程序中調用了add()函數,看一下它早Proxy中的實現。

1.---> IBinderServiceTest.cpp 
2. 
3.class BpBinderServiceTest: public BpInterface<IBinderServiceTest>
4.{
5.public:
6.    BpBinderServiceTest(const sp<IBinder>& impl) :
7.        BpInterface<IBinderServiceTest> (impl) {
8.    }
9.
10.    int add(int a, int b) {
11.        // Parcel類用來於序列化進程間通訊數據。
12.        Parcel data, reply;
13.        ALOGI("BpBinderServiceTest add, a = %d, b = %d", a, b);
14. 
15.        // 寫入Binder傳輸數據的頭,這裏寫入Service描述符「android.test.IBinderServiceTest」。
16.        data.writeInterfaceToken(IBinderServiceTest::getInterfaceDescriptor());
17.        // 以後向Binder中寫入要發送給Server的數據。
18.        data.writeInt32(a);
19.        data.writeInt32(b);
20.        // 開始進行遠端的傳輸調用。
21.        remote()->transact(TEST_ADD, data, &reply);
22.        // 讀取Server返回的數據。
23.        int sum = reply.readInt32();
24.
25.        ALOGI("BpBinderServiceTest sum = %d", sum);
26.        return sum;
27.    }
28.};

代碼中,remote()來自於BpRefBase類,它返回一個BpBinder指針,所以這將調用BpBinder::transact。TEST_ADD是Binder執行的命令編碼,Server會根據這個值來執行相應的命令。實際的Binder傳輸是在IPCThreadState中完成的,傳輸時同步的,調用返回表示Server端已經執行結束。這裏不作詳解。

Server端代碼解析

圖片描述
Client端發送命令TEST_ADD,看看Server端是如何執行這個命令的。

1.---> IBinderServiceTest.cpp 
2. 
3.status_t BnBinderServiceTest::onTransact(uint32_t code, const Parcel& data,
4.        Parcel* reply, uint32_t flags) {
5.    switch (code) {
6.        // 接收到Client端的命令TEST_ADD。
7.        case TEST_ADD: {
8.            // 檢查數據頭是否爲Service描述符。
9.            CHECK_INTERFACE(IBinderServiceTest, data, reply);
10.            
11.            // 讀取輸入的數據。
12.            int a = data.readInt32();
13.            int b = data.readInt32();
14.            ALOGI("BnBinderServiceTest add, a = %d  b = %d", a, b);
15.            
16.            int sum = 0;
17.            // 調用Server對應的函數
18.            sum  = add(a, b);
19.            ALOGI("BnBinderServiceTest sum = %d", sum);
20.            // 寫入返回數據到Binder。
21.            reply->writeInt32(sum);
22.            return sum;
23.        }   
24.    default:
25.        return BBinder::onTransact(code, data, reply, flags);
26.    }   
27.}

Server端的源頭也是在IPCThreadState中。IPCThreadState藉助ProcessState類來與Binder驅動程序交互,接收Client處的請求。以後調用BBinder類的transact函數,並傳入相關參數。BBinder類的transact函數最終調用BnBinderServiceTest類的onTransact函數。
下面從Server端啓動開始分析。

1.---> BinderServerRun.cpp 
2. 
3.int main(int argc, char** argv)
4. {
5.    // 建立一個ProcessState實例。
6.    sp<ProcessState> proc(ProcessState::self());
7.    // 獲得Service Manager的遠程接口。
8.    sp<IServiceManager> sm = defaultServiceManager();
9. 
10.    // 增長Service "my.binder.test"到Service Manager中。
11.    BinderServiceTest::instantiate();
12.    ProcessState::self()->startThreadPool();
13.    IPCThreadState::self()->joinThreadPool();
14.    return 0;
15.}
16. 
17. 
18.---> BinderTestServer.cpp 
19. 
20.void BinderServiceTest::instantiate() {
21.    ALOGI("Enter instantiate");
22.
23.    status_t st = defaultServiceManager()->addService(
24.            String16("my.binder.test"), new BinderServiceTest());
25.    ALOGD("addService ret=%d", st);
26.}
27.
28.BinderServiceTest::BinderServiceTest() {
29.    ALOGD("Constructor");
30.}
31.
32.BinderServiceTest::~BinderServiceTest() {
33.    ALOGD("Destructor");
34.}
35.
36.int BinderServiceTest::add(int a, int b) {
37.    ALOGI("add a = %d, b = %d.", a, b);
38.    return a+b;
39.}

Server端首先要經過ProcessState::self()調用建立一個ProcessState實例。ProcessState::self()是ProcessState類的一個靜態成員變量,這個函數返回一個全局惟一的ProcessState實例gProcess。代碼以下

1.---> ProcessState.cpp 
2. 
3.sp<ProcessState> ProcessState::self()
4.{
5.    Mutex::Autolock _l(gProcessMutex);
6.    if (gProcess != NULL) {
7.        return gProcess;
8.    }
9.    gProcess = new ProcessState;
10.    return gProcess;
11.}

ProcessState實例化的過程當中主要完成兩個工做。一是會經過open_driver函數打開Binder設備文件/dev/binder,並將打開設備文件描述符保存在成員變量mDriverFD中;二是經過mmap來把設備文件/dev/binder映射到內存中。這裏不作詳解。
接下來分析startThreadPool()和joinThreadPool()到底作了什麼。startThreadPool() 的實現以下面的代碼所示:

1.---> ProcessState.cpp 
2.  
3.void ProcessState::startThreadPool()
4.{
5.    AutoMutex _l(mLock);
6.    if (!mThreadPoolStarted) {
7.        mThreadPoolStarted = true;
8.        spawnPooledThread(true);
9.    }
10.}
11....... 
12.void ProcessState::spawnPooledThread(bool isMain)
13.{
14.    if (mThreadPoolStarted) {
15.        String8 name = makeBinderThreadName();
16.        ALOGV("Spawning new pooled thread, name=%s\n", name.string());
17.        sp<Thread> t = new PoolThread(isMain);
18.        t->run(name.string());
19.    }
20.}

PoolThread 是在 IPCThreadState 中定義的一個 Thread 子類,它的實現以下所示:

1.---> ProcessState.cpp 
2.  
3.class PoolThread : public Thread
4.{
5.public:
6.    PoolThread(bool isMain)
7.        : mIsMain(isMain)
8.    {
9.    }
10.    
11.protected:
12.    virtual bool threadLoop()
13.    {
14.        IPCThreadState::self()->joinThreadPool(mIsMain);
15.        return false;
16.    }
17.    
18.    const bool mIsMain;
19.};

PoolThread繼承Thread類,其run函數調用Thread::run()建立一個線程,最終調用子類的threadLoop函數。threadLoop()也是調用joinThreadPool()完成工做。joinThreadPool()的代碼以下。

1.---> IPCThreadState.cpp 
2.  
3.status_t IPCThreadState::getAndExecuteCommand()
4.{
5.    status_t result;
6.    int32_t cmd;
7.
8.    result = talkWithDriver();
9.    if (result >= NO_ERROR) {
10.        size_t IN = mIn.dataAvail();
11.        if (IN < sizeof(int32_t)) return result;
12.        cmd = mIn.readInt32();
13.        IF_LOG_COMMANDS() {
14.            alog << "Processing top-level Command: "
15.                 << getReturnString(cmd) << endl;
16.        }
17.
18.        result = executeCommand(cmd);
19.
20.        // After executing the command, ensure that the thread is returned to the
21.        // foreground cgroup before rejoining the pool.  The driver takes care of
22.        // restoring the priority, but doesn't do anything with cgroups so we
23.        // need to take care of that here in userspace.  Note that we do make
24.        // sure to go in the foreground after executing a transaction, but
25.        // there are other callbacks into user code that could have changed
26.        // our group so we want to make absolutely sure it is put back.
27.        set_sched_policy(mMyThreadId, SP_FOREGROUND);
28.    }
29.
30.    return result;
31.}
32.......
33.void IPCThreadState::joinThreadPool(bool isMain)
34.{
35.    LOG_THREADPOOL("**** THREAD %p (PID %d) IS JOINING THE THREAD POOL\n", (void*)pthread_self(), getpid());
36.
37.    mOut.writeInt32(isMain ? BC_ENTER_LOOPER : BC_REGISTER_LOOPER);
38.    
39.    // This thread may have been spawned by a thread that was in the background
40.    // scheduling group, so first we will make sure it is in the foreground
41.    // one to avoid performing an initial transaction in the background.
42.    set_sched_policy(mMyThreadId, SP_FOREGROUND);
43.        
44.    status_t result;
45.    do {
46.        processPendingDerefs();
47.        // now get the next command to be processed, waiting if necessary
48.        result = getAndExecuteCommand();
49.
50.        if (result < NO_ERROR && result != TIMED_OUT && result != -ECONNREFUSED && result != -EBADF) {
51.            ALOGE("getAndExecuteCommand(fd=%d) returned unexpected error %d, aborting",
52.                  mProcess->mDriverFD, result);
53.            abort();
54.        }
55.        
56.        // Let this thread exit the thread pool if it is no longer
57.        // needed and it is not the main process thread.
58.        if(result == TIMED_OUT && !isMain) {
59.            break;
60.        }
61.    } while (result != -ECONNREFUSED && result != -EBADF);
62.
63.    LOG_THREADPOOL("**** THREAD %p (PID %d) IS LEAVING THE THREAD POOL err=%p\n",
64.        (void*)pthread_self(), getpid(), (void*)result);
65.    
66.    mOut.writeInt32(BC_EXIT_LOOPER);
67.    talkWithDriver(false);
68.}

這個函數最終是在一個無窮循環中,經過調用talkWithDriver函數來和Binder驅動程序進行交互,實際上就是調用talkWithDriver來等待Client的請求,而後再調用executeCommand來處理請求,而在executeCommand函數中,最終會調用BBinder::transact來真正處理Client的請求。而BBinder::transact最終會調用onTransact函數來處理,也就實際調用了示例中的BnBinderServiceTest::onTransact。

相關文章
相關標籤/搜索