千里马Android Framework实战课程-应用程序app的Binder启动篇

Posted learnframework

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了千里马Android Framework实战课程-应用程序app的Binder启动篇相关的知识,希望对你有一定的参考价值。

csdn在线学习课程,课程咨询答疑和新课信息:QQ交流群:422901085进行课程讨论

android跨进程通信实战视频课程(加群获取优惠)
上一个学习专题zygote启动app进程时候,有简单讲过一下binder启动,但没有详细进行分析。这一节进行重点详细分析。

Android Framework实战视频–SystemServer启动篇
进程通过zygote进行fork后调用ZygoteInit.nativeZygoteInit(),是一个native方法,实现在androidRuntime里面,最后调到app_main.cpp的onZygoteInit,来启动binder线程池

virtual void onZygoteInit()
    {
        sp<ProcessState> proc = ProcessState::self();
        ALOGV("App process: starting thread pool.\\n");
        proc->startThreadPool();
    }

1、先主要来详细看看ProcessState的启动

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

实际是构造一个ProcessState对象

ProcessState::ProcessState(const char *driver)
    : mDriverName(String8(driver))
    , mDriverFD(open_driver(driver))//这里有调用open_driver
    , mVMStart(MAP_FAILED)
    , mThreadCountLock(PTHREAD_MUTEX_INITIALIZER)
    , mThreadCountDecrement(PTHREAD_COND_INITIALIZER)
    , mExecutingThreadsCount(0)
    , mMaxThreads(DEFAULT_MAX_BINDER_THREADS)
    , mStarvationStartTimeMs(0)
    , mManagesContexts(false)
    , mBinderContextCheckFunc(NULL)
    , mBinderContextUserData(NULL)
    , mThreadPoolStarted(false)
    , mThreadPoolSeq(1)
{
    if (mDriverFD >= 0) {
        // mmap the binder, providing a chunk of virtual address space to receive transactions.
        mVMStart = mmap(0, BINDER_VM_SIZE, PROT_READ, MAP_PRIVATE | MAP_NORESERVE, mDriverFD, 0);
        if (mVMStart == MAP_FAILED) {
            // *sigh*
            ALOGE("Using /dev/binder failed: unable to mmap transaction memory.\\n");
            close(mDriverFD);
            mDriverFD = -1;
            mDriverName.clear();
        }
    }

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

这里主要就是做了2件事:1.open了binder驱动 2.调用了binder的mmap方法申请对应的内存

注意这里的映射的内存大小是多少呢?BINDER_VM_SIZE:

#define BINDER_VM_SIZE ((1 * 1024 * 1024) - sysconf(_SC_PAGE_SIZE) * 2)
这里sysconf(_SC_PAGE_SIZE) 代表是一页内存大小一般为:4096个字节也就是4K

2、接下来在分析startThreadPool()

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

这里刚开始mThreadPoolStarted应该为false,在接下来是spawnPooledThread

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

在这里就启动了一个PoolThread线程,而且我们传递的isMain应该为true
再来看看PoolThread,这个就是在之前的专题已经讲过(native的thread篇),就不再重复了

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

IPCThreadState* IPCThreadState::self()
{
// 判断gHaveTLS是true还是false,字面意思也可以知道是用来标记有无TLS(Thread Loacal Storage)的
    if (gHaveTLS) {
restart:
        const pthread_key_t k = gTLS;
        //如果存在TLS,则根据key:gTLS去获取存储指向IPCThreadState对象的指针值,
        //这是一个一对多的关系,所有线程使用相同的key,但是其每个线程存储的值(IPCThreadState对象)
        //是线程私有的,每个线程都有一个这样的对象
        IPCThreadState* st = (IPCThreadState*)pthread_getspecific(k); 
        if (st) return st;
        //如果此线程不存在这样的key:gTLS对应的值,则创建一个IPCThreadState新对象,
        //并在其构造函数中添加进key:gTLS对应的线程局部空间中TLS(thread local storage)
        return new IPCThreadState; 
    }

    pthread_mutex_lock(&gTLSMutex);
    if (!gHaveTLS) { //gHaveTLS为false表示进程中还没有TLS,则需要创建基于key:gTLS的线程局部存储
        //创建基于key:gTLS的线程局部空间
        int key_create_value = pthread_key_create(&gTLS, threadDestructor);
        if (key_create_value != 0) {
            pthread_mutex_unlock(&gTLSMutex);
            return NULL;
        }
        gHaveTLS = true; //此时已经有TLS了,固gHaveTLS赋值为ture
    }
    pthread_mutex_unlock(&gTLSMutex);
    goto restart;
}

这里可以看出这个对象是针对每个线程独立的,进程第一次启动会pthread_key_create创建,后面线程就会看看是否已经存在,如果没有存在则对线程进行构造new IPCThreadState,在构造函数中add自己这个IPCThreadState对象

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

接下来这里又会调用IPCThreadState::self()->joinThreadPool(mIsMain);
IPCThreadState::joinThreadPool()函数的目的是让线程进入到循环中,等待命令,解析命令,给出响应,函数体如下:
这里传递是isMain为true 所以会给驱动发送一个BC_ENTER_LOOPER 进入循环命令

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);

    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=%d\\n",
        (void*)pthread_self(), getpid(), result);

    mOut.writeInt32(BC_EXIT_LOOPER);
    talkWithDriver(false);
}

IPCThreadState::joinThreadPool()函数主要是在一个do…while()循环里面不断的读取命令数据,然后解析命令数据,并给出相应的响应。

那么最后总结一下都干了什么app刚开始启动Binder时候:
1、打开binder驱动
2、binder映射对应的内存
3、启动binder线程
4、获取IPCThread对象
5、通知binder驱动已经进入循环

以上是关于千里马Android Framework实战课程-应用程序app的Binder启动篇的主要内容,如果未能解决你的问题,请参考以下文章

千里马Android Framework实战开发-native程序之间binder通信实战案例分析

千里马Android Framework实战开发-native程序之间binder通信实战案例分析

千里马Android Framework实战开发-native程序之间binder通信实战案例分析

千里马Android Framework实战开发-跨进程通信专题博客总结

千里马Android Framework实战开发-跨进程通信专题博客总结

千里马android framework实战开发-binder驱动之oneway导致的transaction failed