千里马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