Android Binder入门指南之Binder服务的消息循环


   在前面的三篇文章中,我们以MediaPlayerService为例,介绍了在Binder的C-S架构中的Server服务是如何通过addService请求添加到ServiceManager中进行管理的。但是在Android Binder机制(八) addService详解之请求的反馈的结尾处,我们有留下一个悬念就是MediaPlayerService仅仅只是将自己注册到了ServiceManager中,它还没有进入消息循环等待Client的请求。那么本文继续以MediaPlayerService为例来说明Binder服务是如何进行消息循环的。
注意:本文是基于Android 7.xx版本进行介绍的!


1.MediaPlayerService的main()函数

int main(int argc __unused, char **argv __unused){...    sp<ProcessState> proc(ProcessState::self());    sp<IServiceManager> sm(defaultServiceManager());...    MediaPlayerService::instantiate();    ResourceManagerService::instantiate();...    ProcessState::self()->startThreadPool();    IPCThreadState::self()->joinThreadPool();}

该代码在frameworks/av/media/mediaserver/main_mediaserver.cpp中。对于MediaPlayerService::instantiate(),在前面的篇章中已经详细介绍过了;它的作用是将MediaPlayerService已经注册到ServiceManager中。下面让我们接着分析startThreadPool()的流程。


2.ProcessState::startThreadPool()

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

该代码定义在该代码定义在frameworks/native/libs/binder/ProcessState.cpp中,逻辑比较简单。此时mThreadPoolStarted的初始值为false,因此这里设置mThreadPoolStarted=true之后,接着调用spawnPooledThread(true),这里 的ture非常重要,这里先备注一下。让我们继续分析。


3.ProcessState::spawnPooledThread

String8 ProcessState::makeBinderThreadName() {    int32_t s = android_atomic_add(1, &mThreadPoolSeq);    pid_t pid = getpid();    String8 name;    name.appendFormat("Binder:%d_%X", pid, s);    return name;}void ProcessState::spawnPooledThread(bool isMain){    if (mThreadPoolStarted) {    //为线程取一个名称        String8 name = makeBinderThreadName();        ALOGV("Spawning new pooled thread, name=%s\n", name.string());        sp<Thread> t = new PoolThread(isMain);        t->run(name.string());    }}

此时的mThreadPoolStarted为false,所以会继续往下走。
(1) 调用mThreadPoolStarted为Binder线程取一个名称,它的代码比较简单,这里就不详细分析了,线程的名称是"Binder:%d_%X"(d就是当前进程,其实X是16进制数),每新建一个线程X的值都会+1。这个会在分析一些日志的时候经常看到。
(2) 然后新建PoolThread线程,并运行。这个线程非常重要,下面我们会详细分析。


4.PoolThread

class PoolThread : public Thread{public:    PoolThread(bool isMain)        : mIsMain(isMain)    {    }    protected:    virtual bool threadLoop()    {        IPCThreadState::self()->joinThreadPool(mIsMain);        return false;    }        const bool mIsMain;};

该代码依然定义在frameworks/native/libs/binder/ProcessState.cpp中。可以从代码看到PoolThread继承于Thread,在线程启动之后会调用threadLoop()进入消息循环中。好,到此我们先打住一下。此时的读者应该会有人提出一个疑问,为什么PoolThread线程启动之后就会调用threadLoop()进入消息循环中呢,那么下面我们分析分析当PoolThread启动之后,是如何调用到threadLoop()的。这里的关键就在于PoolThread继承于Thread类,先看看Thread的构造函数,然后再看看run()的代码,我们就能找到原因了。


4.Thread类

class Thread : virtual public RefBase{public:                        Thread(bool canCallJava = true);    virtual             ~Thread();    virtual status_t    run(    const char* name,                                int32_t priority = PRIORITY_DEFAULT,                                size_t stack = 0);    virtual void        requestExit();    virtual status_t    readyToRun();               status_t    requestExitAndWait();            status_t    join();            ...    private:    virtual bool        threadLoop() = 0;private:...    static  int             _threadLoop(void* user);...};Thread::Thread(bool canCallJava)    :   mCanCallJava(canCallJava),        mThread(thread_id_t(-1)),        mLock("Thread::mLock"),        mStatus(NO_ERROR),        mExitPending(false), mRunning(false)        , mTid(-1){}

该代码分别定义在system/core/include/utils/Thread.h和system/core/libutils/Threads.cpp中。当新建PoolThread对象时,会调用到Thread的构造函数,进行一些列初始化。这里传入的参数canCallJava为true,所以设置mCanCallJava=true。然后让我们继续分析PoolThread调用run的流程,由于PoolThread有没有覆盖run会调用父类Thread的run。


5.Thread::run

status_t Thread::run(const char* name, int32_t priority, size_t stack){//初始化锁    Mutex::Autolock _l(mLock);    if (mRunning) {        return INVALID_OPERATION;    }...//初始化    mStatus = NO_ERROR;    mExitPending = false;    mThread = thread_id_t(-1);    mHoldSelf = this;    mRunning = true;    bool res;    if (mCanCallJava) {//会走该分支    //则调用createThreadEtc函数,线程函数是_threadLoop。 //_threadLoop是Thread.cpp中定义的一个函数。        res = createThreadEtc(_threadLoop,                this, name, priority, stack, &mThread);    } else {        res = androidCreateRawThreadEtc(_threadLoop,                this, name, priority, stack, &mThread);    }...    return NO_ERROR;}

该代码定义在system/core/libutils/Threads.cpp中,且此时mCanCallJava为true,所以会在mCanCallJava分支。下面来分步骤详细分析一下:
(1) 先看看函数参数。name是spawnPooledThread()中创建的Binder线程名称,形式是"Binder_X"。priority是优先级(默认值为PRIORITY_DEFAULT),stack是线程栈数量(默认是0);它们都是使用默认值,在system/core/include/utils/Thread.h中定义。
(2) 先进行初始化;mCanCallJava的值在构造函数中被初始化为true。因此,会调用createThreadEtc()。


6. createThreadEtc

// Create thread with lots of parametersinline bool createThreadEtc(thread_func_t entryFunction,                            void *userData,                            const char* threadName = "android:unnamed_thread",                            int32_t threadPriority = PRIORITY_DEFAULT,                            size_t threadStackSize = 0,                            thread_id_t *threadId = 0){    return androidCreateThreadEtc(entryFunction, userData, threadName,        threadPriority, threadStackSize, threadId) ? true : false;}

该代码定义在system/core/include/utils/AndroidThreads.h中。它会接着调用androidCreateThreadEtc()。

6.1 androidCreateThreadEtc

static android_create_thread_fn gCreateThreadFn = androidCreateRawThreadEtc;int androidCreateThreadEtc(android_thread_func_t entryFunction,                            void *userData,                            const char* threadName,                            int32_t threadPriority,                            size_t threadStackSize,                            android_thread_id_t *threadId){    return gCreateThreadFn(entryFunction, userData, threadName,        threadPriority, threadStackSize, threadId);}

该代码定义在system/core/libutils/Threads.cpp中。 androidCreateThreadEtc()会调用gCreateThreadFn()。gCreateThreadFn()是个函数指针,它的值是androidCreateRawThreadEtc。

6.2 androidCreateRawThreadEtc

int androidCreateRawThreadEtc(android_thread_func_t entryFunction,                               void *userData,                               const char* threadName __android_unused,                               int32_t threadPriority,                               size_t threadStackSize,                               android_thread_id_t *threadId){...    int result = pthread_create(&thread, &attr,                    (android_pthread_entry)entryFunction, userData);...    return 1;}

该代码定义在system/core/libutils/Threads.cpp中。 该函数会调用pthread_create(),而pthread_create()则是我们非常熟悉的Linux的标准接口,它的作用就是创建线程。线程创建成功之后运行时,会以执行entryFunction对应的函数。而entryFunction这个函数指针的值是_threadLoop。因此,当线程启动之后,会执行_threadLoop。让我们接着分析_threadLoop函数。


7._threadLoop

int Thread::_threadLoop(void* user){...    bool first = true;    do {        bool result;        if (first) {            first = false;            self->mStatus = self->readyToRun();            result = (self->mStatus == NO_ERROR);            if (result && !self->exitPending()) {...                result = self->threadLoop();            }        } else {            ...        }...    } while(strong != 0);    return 0;}   

该代码定义在system/core/libutils/Threads.cpp中。first的初始值为true,因此进入到if(first)中。 readyToRun()的实现在Threads.cpp中,返回NO_ERROR。因此result为true,而mExitPending的默认值为false,即self0>exitPending()返回false。因此会执行self->threadLoop()。由于PoolThread重载了threadLoop(),因此,这里的self->threadLoop()会调用PoolThread中的threadLoop()。分析到这里终于解开了前面章节4.PoolThread 的疑问了。


8.PoolThread::threadLoop()

class PoolThread : public Thread{public:    PoolThread(bool isMain)        : mIsMain(isMain)    {    }    protected:    virtual bool threadLoop()    {        IPCThreadState::self()->joinThreadPool(mIsMain);        return false;    }        const bool mIsMain;};

上面的代码就是PoolThread中实现的threadLoop()的函数,它会先通过IPCThreadState::self()获取IPCThreadState对象,然后调用IPCThreadState::joinThreadPool(mIsMain),其中mIsMain为true。然后直接返回false,只会调用threadLoop一次,如果是返回ture会循环执行。


9. IPCThreadState::joinThreadPool()

void IPCThreadState::joinThreadPool(bool isMain){...    mOut.writeInt32(isMain ? BC_ENTER_LOOPER : BC_REGISTER_LOOPER);    ...    do {...        result = getAndExecuteCommand();        if (result < NO_ERROR && result != TIMED_OUT && result != -ECONNREFUSED && result != -EBADF) {...            abort();        }...        if(result == TIMED_OUT && !isMain) {            break;        }    } while (result != -ECONNREFUSED && result != -EBADF);...        mOut.writeInt32(BC_EXIT_LOOPER);    talkWithDriver(false);}

该代码定义在frameworks/native/libs/binder/IPCThreadState.cpp中.。在该函数中,会进入了Binder的Server服务的消息循环中。下面详细讲解一下:
(1) 此时的isMain为ture,因此因此会先将BC_ENTER_LOOPER指令写入到mOut中。BC_ENTER_LOOPER是不是有种似曾相识的感觉,对了在前面介绍ServiceManager里面有介绍过。
(2) 接着调用getAndExecuteCommand()。


10. IPCThreadState::getAndExecuteCommand()

status_t IPCThreadState::getAndExecuteCommand(){    status_t result;    int32_t cmd;    // 和Binder驱动交互    result = talkWithDriver();    if (result >= NO_ERROR) {        ...        // 读取mIn中的数据        cmd = mIn.readInt32();        ...        // 调用executeCommand()对数据进行处理。        result = executeCommand(cmd);        ...    }    return result;}

该函数会调用talkWithDriver()和Binder驱动进行交互。对于talkWithDriver(),前面已经多次提到。在此,talkWithDriver()会将BC_ENTER_LOOPER指令发送给Binder驱动,告诉Binder驱动,MediaPlayerService进入了消息循环状态。BC_ENTER_LOOPER的流程在Android Binder机制(四) servicemanager守护进程中已经介绍过了。
当BC_ENTER_LOOPER处理完毕,MediaPlayerService再次调用ioctl()和Binder驱动通信时,由于MediaPlayerService对应的待处理事务列表为空,因此MediaPlayerService线程会进入中断等待状态。当有Client向MediaPlayerService发送请求时,MediaPlayerService就会被唤醒。

更多相关文章

  1. 箭头函数的基础使用
  2. Python技巧匿名函数、回调函数和高阶函数
  3. Android(安卓)数据存储
  4. Android(安卓)系统Gsensor系统架构
  5. Android(安卓)Recovery Ui 分析
  6. android中wifi原理及流程分析
  7. Android异步处理三:Handler+Looper+MessageQueue深入详解
  8. Android异步消息处理机制Handler完全解析
  9. android 退出应用程序

随机推荐

  1. Android(安卓)动画效果 --Animation 动画
  2. 系出名门Android(4) - 活动(Activity),
  3. Android(安卓)P按键静音流程
  4. android开发中@+id/和android:id用法的区
  5. Android几种FrameWork(Manager)的用法
  6. Android之SharedPreferences详解与原理分
  7. Android百度地图(一):百度地图定位sdk 类
  8. Android的全屏问题
  9. android 仿QQ登陆界面实现
  10. Android(安卓)NDK开发