從MediaServer看Binder的使用方式(一)

語言: CN / TW / HK

theme: channing-cyan

android原始碼分析目錄

一 概述

Binder是Android中的一種IPC機制,在Binder中,Binder是基於C/S架構的,但是除了C/S架構中的Client和Server,Android中還有一個ServiceManager,它的作用就是管理各種服務,我們在Service的啟動中已經見識過它了。

接下來,在我們深入學習Binder之前,我們先通過Android系統自己對於Binder的使用,來了解Binder,在這裡,我們選擇的目標是MediaServer

原始碼目錄

```

frameworks/av/media/mediaserver/main_mediaserver.cpp frameworks/native/libs/binder/ProcessState.cpp frameworks/native/libs/binder/IServiceManager.cpp frameworks/native/libs/binder/BpBinder.cpp frameworks/native/libs/binder/include/binder/IInterface.h frameworks/native/libs/binder/IServiceManager.cpp frameworks/native/libs/binder/Binder.cpp frameworks/av/media/libmediaplayerservice/MediaPlayerService.cpp frameworks/native/libs/binder/BpBinder.cpp frameworks/native/libs/binder/IPCThreadState.cpp ```

二 MediaServer的入口

MediaServer的入口函式如下,這是一個非常標準的Binder使用流程

```cpp [main_mediaserver.cpp]

int main(int argc __unused, char **argv __unused) { signal(SIGPIPE, SIG_IGN); //1 獲得一個ProcessState的例項 sp proc(ProcessState::self()); //2 獲得一個IServiceManager物件 sp sm(defaultServiceManager()); ALOGI("ServiceManager: %p", sm.get()); AIcu_initializeIcuOrDie(); //3 註冊服務 MediaPlayerService::instantiate(); ResourceManagerService::instantiate(); //4 註冊其他,預設為空 registerExtensions(); //5 ProcessState有關執行緒池 ProcessState::self()->startThreadPool(); //6 IPCThreadState有關執行緒池 IPCThreadState::self()->joinThreadPool(); } ```

在上述程式碼中,我們看到了大致6個步驟,接下來,我們就對這6個步驟進行一一分析

三 ProcessState

看步驟1的程式碼,我們也能大致猜測出來,它是一個單例,這個self方法具體如下

```cpp [ProcessState.cpp]

sp ProcessState::self() { Mutex::Autolock _l(gProcessMutex); if (gProcess != nullptr) { return gProcess; } //第一次執行一定為空,需要建立物件,所以會執行建構函式 gProcess = new ProcessState(kDefaultDriver); return gProcess; } ```

3.1 ProcessState的建構函式

```cpp [ProcessState.cpp]

ProcessState::ProcessState(const char *driver) : mDriverName(String8(driver)) //這裡是關鍵點 , mDriverFD(open_driver(driver)) , ... { if (mDriverFD >= 0) { //呼叫一個mmap,拿到起始地址 mVMStart = mmap(nullptr, BINDER_VM_SIZE, PROT_READ, MAP_PRIVATE | MAP_NORESERVE, mDriverFD, 0); if (mVMStart == MAP_FAILED) { // 如果mmap對映失敗,一般不會執行 ALOGE("Using %s failed: unable to mmap transaction memory.\n", mDriverName.c_str()); close(mDriverFD); mDriverFD = -1; mDriverName.clear(); } }

LOG_ALWAYS_FATAL_IF(mDriverFD < 0, "Binder driver could not be opened.  Terminating.");

} ```

3.2 open_driver

```cpp [ProcessState.cpp]

static int open_driver(const char *driver) {
//開啟binder驅動 int fd = open(driver, O_RDWR | O_CLOEXEC); if (fd >= 0) { int vers = 0; //通過ioctl的方式與binder驅動進行互動 //版本 status_t result = ioctl(fd, BINDER_VERSION, &vers); if (result == -1) { ALOGE("Binder ioctl to obtain version failed: %s", strerror(errno)); close(fd); fd = -1; } if (result != 0 || vers != BINDER_CURRENT_PROTOCOL_VERSION) { ALOGE("Binder driver protocol(%d) does not match user space protocol(%d)! ioctl() return value: %d", vers, BINDER_CURRENT_PROTOCOL_VERSION, result); close(fd); fd = -1; } size_t maxThreads = DEFAULT_MAX_BINDER_THREADS; //最大執行緒數,預設是15 result = ioctl(fd, BINDER_SET_MAX_THREADS, &maxThreads); if (result == -1) { ALOGE("Binder ioctl to set max threads failed: %s", strerror(errno)); } } else { ALOGW("Opening '%s' failed: %s\n", driver, strerror(errno)); } return fd; } ```

到這裡,Process的建構函式就算是結束了,它主要的工作如下

  1. 開啟binder驅動(預設是/dev/binder),獲得一個fd
  2. 對於返回的fd使用mmap,這樣Binder驅動就會分配一塊記憶體來接收資料
  3. Process是單例的

四 defaultServiceManager

defaultServiceManager是IServiceManager中的一個函式,它返回了一個IServiceManager物件,它也是一個單例

```cpp [IServiceManager.cpp ]

sp defaultServiceManager() { if (gDefaultServiceManager != nullptr) return gDefaultServiceManager;

{
    AutoMutex _l(gDefaultServiceManagerLock);
    while (gDefaultServiceManager == nullptr) {
        //建立一個gDefaultServiceManager物件
        gDefaultServiceManager = interface_cast<IServiceManager>(
            ProcessState::self()->getContextObject(nullptr));
        //如果為空,就迴圈等待
        if (gDefaultServiceManager == nullptr)
            sleep(1);
    }
}

return gDefaultServiceManager;

} ```

在defaultServiceManager中,首先會通過getContextObject來獲取一個gDefaultServiceManager物件,如果沒有獲取到,那麼就會迴圈等待,這裡我們有兩個問題

  1. getContextObject是如何獲取的gDefaultServiceManager
  2. 什麼情況下會獲取不到

首先我們思考第一個問題,getContextObject做了什麼

4.1 getContextObject

getContextObject是ProcessState中的函式,具體如下

```cpp [ProcessState.cpp]

sp ProcessState::getContextObject(const sp& /caller/) { return getStrongProxyForHandle(0); }

[ProcessState.cpp]

//通過一個int的handle值,來獲得一個IBinder sp ProcessState::getStrongProxyForHandle(int32_t handle) { sp result;

AutoMutex _l(mLock);

//根據handle值來查詢
handle_entry* e = lookupHandleLocked(handle);

if (e != nullptr) {
    //拿到查詢物件中的IBinder
    IBinder* b = e->binder;
    if (b == nullptr || !e->refs->attemptIncWeak(this)) {
        //如果IBinder為空
        if (handle == 0) {
            //handle值為0
            Parcel data;
            status_t status = IPCThreadState::self()->transact(
                    0, IBinder::PING_TRANSACTION, data, nullptr, 0);
            if (status == DEAD_OBJECT)
               return nullptr;
        }
        //根據handle值建立一個BpBinder
        b = BpBinder::create(handle);
        //填充entry
        e->binder = b;
        if (b) e->refs = b->getWeakRefs();
        result = b;
    } else {
        result.force_set(b);
        e->refs->decWeak(this);
    }
}

return result;

} ```

4.2 BpBinder

在getStrongProxyForHandle函式中,我們看到了一個物件叫BpBinder,關於BpBinder,這裡簡單說明一下

  • 在Android中,使用BInder通訊時,一般都會有兩個物件BpBinder和BBinder
  • 它們都是繼承自IBinder而來的,BpBinder代表客戶端,BBinder代表服務端
  • 這裡建立時傳入的handle值0就是它們用來對應的標識

關於BpBinder的建構函式如下

```cpp [BpBinder.cpp]

BpBinder::BpBinder(int32_t handle, int32_t trackedUid) : mHandle(handle) , mAlive(1) , mObitsSent(0) , mObituaries(nullptr) , mTrackedUid(trackedUid) { ALOGV("Creating BpBinder %p handle %d\n", this, mHandle);

extendObjectLifetime(OBJECT_LIFETIME_WEAK);
IPCThreadState::self()->incWeakHandle(handle, this);

} ```

這個建構函式很簡單,接下來我們再看拿到了這個BpBInder物件之後又做了什麼

4.3

經過BpBInder物件的構造,我們可以將之前程式碼簡化

```cpp gDefaultServiceManager = interface_cast( ProcessState::self()->getContextObject(nullptr)); //因為ProcessState::self()->getContextObject(nullptr)獲得的是一個BpBInder //所以如上程式碼如下 gDefaultServiceManager = interface_cast(new BpBInder(0));

然後通過interface_cast將這個物件轉化成IServiceManager,關於interface_cast,它是模板函式

[IInterface.h]

//模板函式 template inline sp interface_cast(const sp& obj) { return INTERFACE::asInterface(obj); }

//巨集定義如下 #define DECLARE_META_INTERFACE(INTERFACE) \ public: \ static const ::android::String16 descriptor; \ static ::android::sp asInterface( \ const ::android::sp<::android::IBinder>& obj); \ ...

#define IMPLEMENT_META_INTERFACE(INTERFACE, NAME) \ ...
::android::sp I##INTERFACE::asInterface( \ const ::android::sp<::android::IBinder>& obj) \ { \ ::android::sp intr; \ if (obj != nullptr) { \ intr = static_cast( \ obj->queryLocalInterface( \ I##INTERFACE::descriptor).get()); \ if (intr == nullptr) { \ intr = new Bp##INTERFACE(obj); \ } \ } \ return intr; \ }
```

然後通過兩個巨集定義DECLARE_META_INTERFACE和IMPLEMENT_META_INTERFACE,就將它們關聯起來了

```cpp [IServiceManager.h]

class IServiceManager : public IInterface { public: DECLARE_META_INTERFACE(ServiceManager) ... } ```

並且在IServiceManager.cpp中,有一行IMPLEMENT_META_INTERFACE(ServiceManager, "android.os.IServiceManager")

所以上述的interface_cast(new BpBInder(0));最後其實是建立了一個BpServiceManager

4.3 BpServiceManager

接下來,我們看看這個建立過程發生了哪些事情,首先我們先看BpServiceManager的繼承關係

ServiceManager繼承關係.png 首先是BpServiceManager的建構函式,它是IServiceManager.cpp的一個內部類

```cpp [IServiceManager.cpp]

class BpServiceManager : public BpInterface { public: explicit BpServiceManager(const sp& impl) : BpInterface(impl) ... ```

然後是BpInterface,它是IInterface.h的一個內部類

```cpp [IInterface.h]

template inline BpInterface::BpInterface(const sp& remote) : BpRefBase(remote) ... ```

接下來是BpRefBase,它是Binder.cpp的一個內部類

```cpp [Binder.cpp]

BpRefBase::BpRefBase(const sp& o) : mRemote(o.get()), mRefs(nullptr), mState(0) ... ```

通過 BpServiceManager -> BpInterface -> BpRefBase,最後將我們傳入的一個BpBinder和一個mRemote關聯了起來,到這裡,我們的準備工作就算是完成了

五 IPCThreadState

5.1 服務的註冊

在main_mediaserver.cpp的第三步MediaPlayerService::instantiate();,就是服務的註冊

```cpp [MediaPlayerService.cpp]

void MediaPlayerService::instantiate() { defaultServiceManager()->addService( String16("media.player"), new MediaPlayerService()); } ```

如果看過SystemServer的原始碼,就會發現裡面有很多這樣addService註冊服務的邏輯,這裡的defaultServiceManager在前面我們已經說了,它是一個BpServiceManager物件,它繼承自IServiceManager,它的addService方法如下

```cpp [IServiceManager::BpServiceManager]

virtual status_t addService(const String16& name, const sp& service, bool allowIsolated, int dumpsysPriority) { //這裡有一個Parcel,這個物件是Android中跨程序通訊的重要物件,資料就儲存在這裡面 Parcel data, reply; data.writeInterfaceToken(IServiceManager::getInterfaceDescriptor()); data.writeString16(name); data.writeStrongBinder(service); data.writeInt32(allowIsolated ? 1 : 0); data.writeInt32(dumpsysPriority); //這個remote()就是我們建立時候傳入的BpBinder status_t err = remote()->transact(ADD_SERVICE_TRANSACTION, data, &reply); return err == NO_ERROR ? reply.readExceptionCode() : err; } ```

這裡我們看到了一個transact,這個方法我們以後會經常看見,它就是和Binder互動的重要函式

5.2 IPCThreadState的建立

剛才我們說到了Binder的具體互動函式transact,它是定義在BpBinder中的,接下來我們就看看BpBinder中的具體邏輯

``` [BpBinder.cpp]

status_t BpBinder::transact( uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) { // Once a binder has died, it will never come back to life. if (mAlive) { //關鍵點,IPCThreadState status_t status = IPCThreadState::self()->transact( mHandle, code, data, reply, flags); if (status == DEAD_OBJECT) mAlive = 0; return status; }

return DEAD_OBJECT;

} ```

這裡我們看到了一個IPCThreadState,這個類也是Binder通訊中非常重要的類,我們先看它的self方法

```cpp [IPCThreadState.cpp]

IPCThreadState IPCThreadState::self() { //第一次是false if (gHaveTLS) { restart: //在restart中建立IPCThreadState物件 const pthread_key_t k = gTLS; IPCThreadState st = (IPCThreadState*)pthread_getspecific(k); if (st) return st; return new IPCThreadState; }

//第一次是false
if (gShutdown) {
    ALOGW("Calling IPCThreadState::self() during shutdown is dangerous, expect a crash.\n");
    return nullptr;
}

//執行緒鎖
pthread_mutex_lock(&gTLSMutex);
if (!gHaveTLS) {
    int key_create_value = pthread_key_create(&gTLS, threadDestructor);
    if (key_create_value != 0) {
        pthread_mutex_unlock(&gTLSMutex);
        ALOGW("IPCThreadState::self() unable to create TLS key, expect a crash: %s\n",
                strerror(key_create_value));
        return nullptr;
    }
    gHaveTLS = true;
}
pthread_mutex_unlock(&gTLSMutex);
//跳轉到restart
goto restart;

} ```

可以看出這個是一個和執行緒相關的單例,在同一個執行緒下它只有一個物件,接下來我們再看它的建構函式

```cpp [IPCThreadState.cpp]

IPCThreadState::IPCThreadState() : mProcess(ProcessState::self()), mWorkSource(kUnsetWorkSource), mPropagateWorkSource(false), mStrictModePolicy(0), mLastTransactionBinderFlags(0), mCallRestriction(mProcess->mCallRestriction) { //和執行緒相關聯 pthread_setspecific(gTLS, this); clearCaller(); //和Binder驅動互動的兩個緩衝區 mIn.setDataCapacity(256); mOut.setDataCapacity(256); mIPCThreadStateBase = IPCThreadStateBase::self(); } ```

然後在建構函式中,初始化了兩個緩衝區mIn和mOut,這個mIn是從Binder裝置讀資料的,而mOut則是向Binder裝置寫資料的

5.3 transact

接下來我們就要看最關鍵的transact

```cpp [IPCThreadState.cpp]

status_t IPCThreadState::transact(int32_t handle, uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) { ... err = writeTransactionData(BC_TRANSACTION, flags, handle, code, data, nullptr); ... if ((flags & TF_ONE_WAY) == 0) {
... if (reply) { err = waitForResponse(reply); } else { Parcel fakeReply; err = waitForResponse(&fakeReply); } ... } else { err = waitForResponse(nullptr, nullptr); } return err; } ```

transact中的邏輯非常長,並且裡面還有很多判斷,不過這裡不論是哪個分支,都會呼叫到兩個方法,分別是writeTransactionData和waitForResponse,接下來我們就看看這個waitForResponse裡面具體做了什麼事

5.4 writeTransactionData

```cpp [IPCThreadState.cpp]

status_t IPCThreadState::writeTransactionData(int32_t cmd, uint32_t binderFlags, int32_t handle, uint32_t code, const Parcel& data, status_t* statusBuffer) { binder_transaction_data tr;

tr.target.ptr = 0;
tr.target.handle = handle;
tr.code = code;
tr.flags = binderFlags;
tr.cookie = 0;
tr.sender_pid = 0;
tr.sender_euid = 0;

//將資料用tr進行封裝
...

//將資料寫到mOut
mOut.writeInt32(cmd);
mOut.write(&tr, sizeof(tr));

return NO_ERROR;

} ```

顯然,writeTransactionData主要的作用就是將要傳遞的引數寫到mOut中去

5.5 waitForResponse

```cpp [IPCThreadState.cpp]

status_t IPCThreadState::waitForResponse(Parcel reply, status_t acquireResult) { uint32_t cmd; int32_t err;

while (1) {
    if ((err=talkWithDriver()) < NO_ERROR) break;
    ...
    //從Binder中讀出資料
    cmd = (uint32_t)mIn.readInt32();

    //死迴圈加上switch,說明一次Binder互動會讀出多次資料
    switch (cmd) {
    ...


    default:
        //執行拿到的cmd
        err = executeCommand(cmd);
        if (err != NO_ERROR) goto finish;
        break;
    }
}

finish: if (err != NO_ERROR) { if (acquireResult) *acquireResult = err; if (reply) reply->setError(err); mLastError = err; }

return err;

} ```

在waitForResponse中,會不斷的從mIn中讀出資料,然後根據這個讀出的資料,執行不同的邏輯

六 總結

到此,我們基本知道了,MediaServer在使用Binder時,是如何註冊的,不過對於IPCThreadState的細節,本篇還沒完全說明白,關於後續的部分在下一篇說明