Android Binder框架实现之Binder服务的消息循环

   Android Binder框架实现之Binder服务的消息循环


Android Binder框架实现目录:

Android Binder框架实现之Binder的设计思想
Android Binder框架实现之何为匿名/实名Binder
Android Binder框架实现之Binder中的数据结构
Android Binder框架实现之Binder相关的接口和类
Android Binder框架实现之Parcel详解之基本数据的读写
Android Binder框架实现之Parcel read/writeStrongBinder实现
Android Binder框架实现之servicemanager守护进程
Android Binder框架实现之defaultServiceManager()的实现
Android Binder框架实现之Native层addService详解之请求的发送
Android Binder框架实现之Native层addService详解之请求的处理
Android Binder框架实现之Native层addService详解之请求的反馈
Android Binder框架实现之Binder服务的消息循环
Android Binder框架实现之Native层getService详解之请求的发送
Android Binder框架实现之Native层getService详解之请求的处理
Android Binder框架实现之Native层getService详解之请求的反馈
Android Binder框架实现之Binder Native Service的Java调用流程
Android Binder框架实现之Java层Binder整体框架设计
Android Binder框架实现之Framework层Binder服务注册过程源码分析
Android Binder框架实现之Java层Binder服务跨进程调用源码分析
Android Binder框架实现之Java层获取Binder服务源码分析



引言

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

frameworks/native/libs/binder/IServiceManager.cpp
frameworks/native/libs/binder/Static.cpp
frameworks/native/libs/binder/ProcessState.cpp
kernel/drivers/staging/android/binder.c
kernel/include/linux/list.h
kernel/drivers/staging/android/uapi/binder.h
external/kernel-headers/original/uapi/linux/android/binder.h
frameworks/native/include/binder/ProcessState.h
frameworks/native/include/binder/BpBinder.h
frameworks/native/libs/binder/BpBinder.cpp
frameworks/native/include/binder/IPCThreadState.h
frameworks/native/libs/binder/IPCThreadState.cpp
frameworks/native/include/binder/IInterface.h
frameworks/native/libs/binder/IInterface.cpp
frameworks/native/include/binder/IBinder.h
frameworks/native/libs/binder/Binder.cpp
frameworks/av/media/mediaserver/main_mediaserver.cpp
frameworks/native/cmds/servicemanager/service_manager.c


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 parameters
inline 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就会被唤醒。

评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值