从MediaServer看Binder的使用方式(二)

语言: CN / TW / HK

theme: channing-cyan

android源码分析目录

一 概述

```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(); } ```

上一篇我们说完了步骤 1 到步骤 3,并且到了 IPCThreadState 在和 Binder 交互时,会调用 waitForResponse,然后在 waitForResponse 中调用 talkWithDriver 和 Binder 进行交互,读出 mIn 中的数据,然后通过 executeCommand 执行,接下来,我们再看看具体的细节

源码目录

frameworks/native/libs/binder/IPCThreadState.cpp frameworks/native/libs/binder/ProcessState.cpp frameworks/native/libs/binder/IPCThreadState.cpp

二 talkWithDriver

```cpp [IPCThreadState.cpp]

status_t IPCThreadState::talkWithDriver(bool doReceive) { //这个就是我们在open_device时拿到的fd if (mProcess->mDriverFD <= 0) { return -EBADF; }

//binder_write_read是用来和binder设备交换数据的结构
binder_write_read bwr;

// 读
const bool needRead = mIn.dataPosition() >= mIn.dataSize();

//如果还需要读,就先读,不写
const size_t outAvail = (!doReceive || needRead) ? mOut.dataSize() : 0;

bwr.write_size = outAvail;
bwr.write_buffer = (uintptr_t)mOut.data();

//我们将读到的数据
if (doReceive && needRead) {
    bwr.read_size = mIn.dataCapacity();
    bwr.read_buffer = (uintptr_t)mIn.data();
} else {
    bwr.read_size = 0;
    bwr.read_buffer = 0;
}

//日志
...

// 读和写都结束了
if ((bwr.write_size == 0) && (bwr.read_size == 0)) return NO_ERROR;

bwr.write_consumed = 0;
bwr.read_consumed = 0;
status_t err;
do {
    IF_LOG_COMMANDS() {
        alog << "About to read/write, write size = " << mOut.dataSize() << endl;
    }

if defined(ANDROID)

    //通过ioctl的方式交互
    if (ioctl(mProcess->mDriverFD, BINDER_WRITE_READ, &bwr) >= 0)
        err = NO_ERROR;
    else
        err = -errno;

else

    err = INVALID_OPERATION;

endif

    if (mProcess->mDriverFD <= 0) {
        err = -EBADF;
    }
    IF_LOG_COMMANDS() {
        alog << "Finished read/write, write size = " << mOut.dataSize() << endl;
    }
} while (err == -EINTR);

//日志
...

if (err >= NO_ERROR) {
    if (bwr.write_consumed > 0) {
        if (bwr.write_consumed < mOut.dataSize())
            mOut.remove(0, bwr.write_consumed);
        else {
            mOut.setDataSize(0);
            processPostWriteDerefs();
        }
    }
    if (bwr.read_consumed > 0) {
        mIn.setDataSize(bwr.read_consumed);
        mIn.setDataPosition(0);
    }
    //日志
    ...
    return NO_ERROR;
}

return err;

} ```

三 startThreadPool

因为 registerExtensions 默认为空,所以我们接下来看 startThreadPool 的相关逻辑,相比于之前的逻辑,这个简单很多

```cpp [ProcessState.cpp]

void ProcessState::startThreadPool() { AutoMutex _l(mLock); if (!mThreadPoolStarted) { mThreadPoolStarted = true; spawnPooledThread(true); } }

void ProcessState::spawnPooledThread(bool isMain) { if (mThreadPoolStarted) { String8 name = makeBinderThreadName(); ALOGV("Spawning new pooled thread, name=%s\n", name.string()); //传入的参数是true sp t = new PoolThread(isMain); t->run(name.string()); } }

class PoolThread : public Thread { public: explicit PoolThread(bool isMain) : mIsMain(isMain) { }

protected: virtual bool threadLoop() { IPCThreadState::self()->joinThreadPool(mIsMain); return false; }

const bool mIsMain;

}; ```

四 joinThreadPool

接下来就是最后一步 joinThreadPool 了,它是定义在 IPCThreadState.cpp 中的函数

```cpp [IPCThreadState.cpp]

void IPCThreadState::joinThreadPool(bool isMain) {

//如果isMain是true,则需要写入一个BC_ENTER_LOOPER
mOut.writeInt32(isMain ? BC_ENTER_LOOPER : BC_REGISTER_LOOPER);

status_t result;
do {
    //处理已经死亡的BBinder对象
    processPendingDerefs();
    // 获取下一条命令
    result = getAndExecuteCommand();

    if (result < NO_ERROR && result != TIMED_OUT && result != -ECONNREFUSED && result != -EBADF) {
        LOG_ALWAYS_FATAL("getAndExecuteCommand(fd=%d) returned unexpected error %d, aborting",
              mProcess->mDriverFD, result);
    }

    // 不是主线程就不需要一直循环
    if(result == TIMED_OUT && !isMain) {
        break;
    }
} while (result != -ECONNREFUSED && result != -EBADF);


//退出Looper
mOut.writeInt32(BC_EXIT_LOOPER);
talkWithDriver(false);

} ```

4.1 getAndExecuteCommand

在 joinThreadPool 也有一个和之前很像的函数 getAndExecuteCommand,它也是 talkWithDriver 和 executeCommand,因为之前已经说过,所以这里就不重复了

```cpp [IPCThreadState.cpp]

status_t IPCThreadState::getAndExecuteCommand() { status_t result; int32_t cmd; //和Binder驱动交互 result = talkWithDriver(); if (result >= NO_ERROR) { //取出数据 size_t IN = mIn.dataAvail(); if (IN < sizeof(int32_t)) return result; cmd = mIn.readInt32();

    pthread_mutex_lock(&mProcess->mThreadCountLock);
    mProcess->mExecutingThreadsCount++;
    if (mProcess->mExecutingThreadsCount >= mProcess->mMaxThreads &&
            mProcess->mStarvationStartTimeMs == 0) {
        mProcess->mStarvationStartTimeMs = uptimeMillis();
    }
    pthread_mutex_unlock(&mProcess->mThreadCountLock);

    //执行cmd
    result = executeCommand(cmd);

    pthread_mutex_lock(&mProcess->mThreadCountLock);
    mProcess->mExecutingThreadsCount--;
    if (mProcess->mExecutingThreadsCount < mProcess->mMaxThreads &&
            mProcess->mStarvationStartTimeMs != 0) {
        int64_t starvationTimeMs = uptimeMillis() - mProcess->mStarvationStartTimeMs;
        if (starvationTimeMs > 100) {
            ALOGE("binder thread pool (%zu threads) starved for %" PRId64 " ms",
                  mProcess->mMaxThreads, starvationTimeMs);
        }
        mProcess->mStarvationStartTimeMs = 0;
    }
    pthread_cond_broadcast(&mProcess->mThreadCountDecrement);
    pthread_mutex_unlock(&mProcess->mThreadCountLock);
}

return result;

} ```

五 总结

终于,一个关于 MediaServer 系统 Server 使用 Binder 的过程,就让我们整理完毕了

  1. 在使用 Binder 之前,需要获得一个 ProcessState 实例,这个对象是一个单例
  2. 然后需要拿到一个 defaultServiceManager 对象,这是一个 IServiceManager,它是一个 IBinder 对象,其实就是 BpBinder
  3. 我们如果想要给其他进程提供 Binder 服务,那么我们需要将自己的服务注册到 ServiceManager 中,这个注册流程就是一个 Binder 通信的过程
  4. 注册完毕后通过 ProcessState::self()->startThreadPool 启动一个线程进行 Binder 事件的接收处理,这个线程不会退出
  5. 将 MediaServer 的主线程,通过 IPCThreadState::self()->joinThreadPool 也加入 loop 循环,接收 Binder 事件

当然,这两篇关于 Binder 的介绍,也只是很简单的说明了 Binder 通信时,native 层参与的类以及这些通信的流程,对于更细节的东西,这里并没有提到,接下来我们就看看 Java 层的 Binder 机制,以及这些操作中的细节