文档章节

Android Binder线程

WolfCS
 WolfCS
发布于 2014/03/18 22:10
字数 2046
阅读 4681
收藏 8

在android系统中,通过binder进行IPC时,服务端总是会起一些Binder线程来响应客户端的请求。如下面的这个设备上,system_process进程中就可以看到许多名为"Binder_X"的线程:

那这些Binder线程又是如何创建,如何管理的呢?而这些Binder线程本身又有些什么样的特点呢?在android的java app进程被创建起来时,它就会去建立一个线程池,来专门处理那些binder IPC事务。在frameworks/base/cmds/app_process/app_main.cpp中我们可以看到下面的这两个方法:

    virtual void onStarted()
    {
        sp<ProcessState> proc = ProcessState::self();
        ALOGV("App process: starting thread pool.\n");
        proc->startThreadPool();
        AndroidRuntime* ar = AndroidRuntime::getRuntime();
        ar->callMain(mClassName, mClass, mArgC, mArgV);
        IPCThreadState::self()->stopProcess();
    }
    virtual void onZygoteInit()
    {
        // Re-enable tracing now that we're no longer in Zygote.
        atrace_set_tracing_enabled(true);
        sp<ProcessState> proc = ProcessState::self();
        ALOGV("App process: starting thread pool.\n");
        proc->startThreadPool();
    }

app_main实际上就是android java app的java命令。这里的代码总是一个android java app执行控制的重要的枢纽。大体扫一眼这个部分的code,没错,就是上面的proc->startThreadPool()这个调用创建的Binder线程池。在android binder的设计中,ProcessState被设计来直接与binder驱动进行通信。ProcessState类被按照单例模式来设计,以确保这种类的对象可以保证在进程的全局是唯一的。它的构造函数是private,在代码中只能通过ProcessState::self()来访问ProcessState类的对象。我们顺便来看一下ProcessState::self()的实现(frameworks/native/libs/binder/ProcessState.cpp):

sp<ProcessState> ProcessState::self()
{
    Mutex::Autolock _l(gProcessMutex);
    if (gProcess != NULL) {
        return gProcess;
    }
    gProcess = new ProcessState;
    return gProcess;
}

蛮典型的一个C++单例模式的一个实现呢。那在ProcessState::startThreadPool()中又是如何创建线程池的呢?(frameworks/native/libs/binder/ProcessState.cpp)

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

这里会通过一个标记mThreadPoolStarted来表明binder线程线程池是否已经被启动过。在每次调用这个函数时都会先去检查这个标记,从而确保即使这个函数被多次调用,线程池也只会被启动一次。具体来看启动线程池的过程:设置mThreadPoolStarted为true,然后调用spawnPooledThread(true)来创建线程池中的第一个线程,也就是线程池的main线程。

那binder线程具体又是什么呢?可以看spawnPooledThread()的实现(frameworks/native/libs/binder/ProcessState.cpp)

String8 ProcessState::makeBinderThreadName() {
    int32_t s = android_atomic_add(1, &mThreadPoolSeq);
    String8 name;
    name.appendFormat("Binder_%X", 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());
    }
}
ProcessState::ProcessState()
    : mDriverFD(open_driver())
    , mVMStart(MAP_FAILED)
    , mManagesContexts(false)
    , mBinderContextCheckFunc(NULL)
    , mBinderContextUserData(NULL)
    , mThreadPoolStarted(false)
    , mThreadPoolSeq(1)
{

可以看到,所谓的binder线程,不过就是PoolThread而已。在进程全局且唯一的ProcessState对象中,有一个已经创建的binder线程的计数器mThreadPoolSeq,每创建一个新的线程,这个计数器就会加1。在ProcessState::makeBinderThreadName()函数中,会根据当前的binder线程计数器的值来构造新创建的binder线程的线程名"Binder_%X",从而可以根据线程名来识别各个不同的binder线程。

PoolThread具体又有些什么特点呢?这个还是得看PoolThread的threadLoop()方法实现(frameworks/native/libs/binder/ProcessState.cpp)

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

这个倒是简单的很,就是调用IPCThreadState::self()->joinThreadPool(mIsMain)而已。

在android binder设计中,IPCThreadState是一个binder线程的一个抽象,用于管理binder线程的具体执行。这个类被设计为,其对象在每个binder线程中唯一。为了控制这个类的对象的创建,其构造函数也被声明为private,并且只能通过IPCThreadState::self()来创建或访问IPCThreadState类的对象(frameworks/native/libs/binder/IPCThreadState.cpp):

static pthread_mutex_t gTLSMutex = PTHREAD_MUTEX_INITIALIZER;
static bool gHaveTLS = false;
static pthread_key_t gTLS = 0;
static bool gShutdown = false;
static bool gDisableBackgroundScheduling = false;

IPCThreadState* IPCThreadState::self()
{
    if (gHaveTLS) {
restart:
        const pthread_key_t k = gTLS;
        IPCThreadState* st = (IPCThreadState*)pthread_getspecific(k);
        if (st) return st;
        return new IPCThreadState;
    }
    
    if (gShutdown) return NULL;
    
    pthread_mutex_lock(&gTLSMutex);
    if (!gHaveTLS) {
        if (pthread_key_create(&gTLS, threadDestructor) != 0) {
            pthread_mutex_unlock(&gTLSMutex);
            return NULL;
        }
        gHaveTLS = true;
    }
    pthread_mutex_unlock(&gTLSMutex);
    goto restart;
}

IPCThreadState::self()函数在第一次被调到时,会先去创建一个线程局部存储的key,也就是gTLS。随后则会创建IPCThreadState对象,在IPCThreadState的构造函数中,会把this保存到线程局部存储gTLS标识的部分去(frameworks/native/libs/binder/IPCThreadState.cpp):

IPCThreadState::IPCThreadState()
    : mProcess(ProcessState::self()),
      mMyThreadId(androidGetTid()),
      mStrictModePolicy(0),
      mLastTransactionBinderFlags(0)
{
    pthread_setspecific(gTLS, this);
    clearCaller();
    mIn.setDataCapacity(256);
    mOut.setDataCapacity(256);
}

创建好了IPCThreadState对象之后就返回给调用者。因此,这个地方实际上是运用了线程局部存储机制来实现IPCThreadState对象的线程级单例的。

我们再回到IPCThreadState::joinThreadPool(),来接着看Binder线程,主执行流程所做的事情:

void IPCThreadState::joinThreadPool(bool isMain)
{
    LOG_THREADPOOL("**** THREAD %p (PID %d) IS JOINING THE THREAD POOL\n", (void*)pthread_self(), getpid());
    mOut.writeInt32(isMain ? BC_ENTER_LOOPER : BC_REGISTER_LOOPER);
    
    // This thread may have been spawned by a thread that was in the background
    // scheduling group, so first we will make sure it is in the foreground
    // one to avoid performing an initial transaction in the background.
    set_sched_policy(mMyThreadId, SP_FOREGROUND);
        
    status_t result;
    do {
        processPendingDerefs();
        // now get the next command to be processed, waiting if necessary
        result = getAndExecuteCommand();
        if (result < NO_ERROR && result != TIMED_OUT && result != -ECONNREFUSED && result != -EBADF) {
            ALOGE("getAndExecuteCommand(fd=%d) returned unexpected error %d, aborting",
                  mProcess->mDriverFD, result);
            abort();
        }
        
        // Let this thread exit the thread pool if it is no longer
        // needed and it is not the main process thread.
        if(result == TIMED_OUT && !isMain) {
            break;
        }
    } while (result != -ECONNREFUSED && result != -EBADF);
    LOG_THREADPOOL("**** THREAD %p (PID %d) IS LEAVING THE THREAD POOL err=%p\n",
        (void*)pthread_self(), getpid(), (void*)result);
    
    mOut.writeInt32(BC_EXIT_LOOPER);
    talkWithDriver(false);
}

在这个函数中,基本上就是执行一个getAndExecuteCommand()的循环。在getAndExecuteCommand()中则会不停的向binder driver拿命令执行,拿命令执行。

Binder线程池中首个线程的创建执行,大致如上所述,在android java app进程一旦被创建,也就紧跟着会被创建。那意思是说,任何一个android Java app都至少有一个Binder线程,而不管它是否有一个service组件并对其他app提供服务喽?是的,事实就是这个样子的。我们可以去查看任何一个android java app进程中的线程情况,都至少有一个以上的Binder线程,甚至是最简单的HelloWorld app也是这样的。

所谓的binder线程池,不能是只有这么一个线程吧。那Binder线程池中其它的线程又是如何创建的呢?其实是kernel发命令给某个已经在运行的binder线程来产生新的线程,如下:

    case BR_SPAWN_LOOPER:
        mProcess->spawnPooledThread(false);
        break;

大体的backtrace为:

IPCThreadState::executeCommand(int32_t cmd) 《= IPCThreadState::getAndExecuteCommand() 《= IPCThreadState::joinThreadPool(bool isMain) 《= PoolThread::threadLoop()。

binder线程真的就只有这两种创建的方式吗?所谓的binder线程,不过指的就是执行binder IPC事务处理循环的线程吧。而binder IPC事务处理循环不是被封装在了IPCThreadState::joinThreadPool()中了嘛。那是不是任何一个线程只要执行了IPCThreadState::self()->joinThreadPool(),就可以把自己变成一个binder线程了?确实是这样的。在android系统中,也确实有一些native的service,在设置好执行环境之后,甚至会让主线程去执行binder IPC事务处理循环从而把主线程变成binder线程。比如在mediaserver中(frameworks/av/media/mediaserver/main_mediaserver.cpp),就会在main()函数的最后来执行IPCThreadState::self()->joinThreadPool():

118    } else {
119        // all other services
120        if (doLog) {
121            prctl(PR_SET_PDEATHSIG, SIGKILL);   // if parent media.log dies before me, kill me also
122            setpgid(0, 0);                      // but if I die first, don't kill my parent
123        }
124        sp<ProcessState> proc(ProcessState::self());
125        sp<IServiceManager> sm = defaultServiceManager();
126        ALOGI("ServiceManager: %p", sm.get());
127        AudioFlinger::instantiate();
128        MediaPlayerService::instantiate();
129        CameraService::instantiate();
130        AudioPolicyService::instantiate();
131        registerExtensions();
132        ProcessState::self()->startThreadPool();
133        IPCThreadState::self()->joinThreadPool();
134    }

binder线程还具有一个特点。那就是binder线程线程池中线程的数量是有一个上限的,我们可以看ProcessState.cpp中open_driver()函数的实现:

343static int open_driver()
344{
345    int fd = open("/dev/binder", O_RDWR);
346    if (fd >= 0) {
347        fcntl(fd, F_SETFD, FD_CLOEXEC);
348        int vers;
349        status_t result = ioctl(fd, BINDER_VERSION, &vers);
350        if (result == -1) {
351            ALOGE("Binder ioctl to obtain version failed: %s", strerror(errno));
352            close(fd);
353            fd = -1;
354        }
355        if (result != 0 || vers != BINDER_CURRENT_PROTOCOL_VERSION) {
356            ALOGE("Binder driver protocol does not match user space protocol!");
357            close(fd);
358            fd = -1;
359        }
360        size_t maxThreads = 15;
361        result = ioctl(fd, BINDER_SET_MAX_THREADS, &maxThreads);
362        if (result == -1) {
363            ALOGE("Binder ioctl to set max threads failed: %s", strerror(errno));
364        }
365    } else {
366        ALOGW("Opening '/dev/binder' failed: %s\n", strerror(errno));
367    }
368    return fd;
369}

在这个函数中,会通过ioctl命令,告诉binder驱动,只能创建最多15个的binder线程。

Done.

© 著作权归作者所有

WolfCS
粉丝 81
博文 147
码字总数 505184
作品 4
杭州
高级程序员
私信 提问
听说你Binder机制学的不错,来面试下这几个问题(一)

Binder承担了绝大部分Android进程通信的职责,可以看做是Android的血管系统,负责不同服务模块进程间的通信。在对Binder的理解上,可大可小,日常APP开发并不怎么涉及Binder通信知识,最多就...

技术小能手
2018/07/20
0
0
android Binder 工作流程

一.Linux系统进程间通信有哪些方式? 1.socket; 2.name pipe命名管道; 3.message queue消息队列; 4.singal信号量; 5.share memory共享内存; 二.Java系统的通信方式是什么? 1.socket; ...

eric_zhang
2011/07/20
0
0
安卓framework开发的初理解

概述 其实我们写的App并不是一个完整的程序。我们写的只是一个套件组,就是一堆Activity,Service等等的组件。这个套件组给Framework框架组合在一起才是一个完整的程序。在这里先说一个概念,...

天王盖地虎626
01/11
0
0
Android Framework原理

App启动过程 点击桌面App图标,Launcher进程采用Binder IPC向system_server进程发起startActivity请求 system_server进程接收到请求后,向zygote进程发送创建进程的请求 Zygote进程fork出新的子...

天王盖地虎626
01/12
0
0
02.Android之IPC机制问题

目录介绍 2.0.0.1 什么是Binder?为什么要使用Binder?Binder中是如何进行线程管理的?总结binder讲的是什么? 2.0.0.2 Android中进程和线程的关系?什么是IPC?为何需要进行IPC?多进程通信...

潇湘剑雨
01/07
0
0

没有更多内容

加载失败,请刷新页面

加载更多

ubuntu或ubuntu kylin优麒麟中安装QQ、wechat微信、百度网盘

从中国国内的地址下载deepin wine,码云上的。这样网速比较快。然后,按照说明向下安装。 https://gitee.com/wszqkzqk/deepin-wine-for-ubuntu...

gugudu
17分钟前
1
0
基于redis分布式锁实现“秒杀”

最近在项目中遇到了类似“秒杀”的业务场景,在本篇博客中,我将用一个非常简单的demo,阐述实现所谓“秒杀”的基本思路。 业务场景 所谓秒杀,从业务角度看,是短时间内多个用户“争抢”资源...

别打我会飞
36分钟前
10
0
Zookeeper的实践指南

本章重点 1.数据存储2.基于Java API初探Zookeeper的使用3.深入分析Watcher机制的实现原理4.Curator客户端的使用,简单高效 数据存储 事务日志快照日志运行时日志 bin/zookeepe...

须臾之余
40分钟前
1
0
MySQL mybatis Point类型数据

MySQL中的point用于表示GIS中的地理坐标,在GIS中广泛使用 如何写入mysql,如下图: CREATE TABLE `test-point` ( `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '序号', `point` ......

张欢19933
51分钟前
2
0
设计模式-适配器模式

适配器模式 适配器模式(Adapter Pattern)是作为两个不兼容的接口之间的桥梁。这种类型的设计模式属于结构型模式,它结合了两个独立接口的功能。 这种模式涉及到一个单一的类,该类负责加入...

HOT_POT
今天
17
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部