在Android应用程序启动过程(一)——进程创建中,我们已经讲述了一个app进程的创建过程。一个app进程刚被fork出来时,它还不具备与AMS“沟通”的能力。它需要进行一些初始化,以开启这种能力。
Android中提供了Binder进程间通信机制,两个进程通过Binder Driver来实现数据跨进程交换。Binder Driver为用户空间提供了/dev/binder节点,我们可以使用open、mmap和ioctl来操作它。
因此一个app进程要想访问AMS(AMS在systemserver进程),它也需要先打开Binder Driver,建立好内存映射后,再执行IPC操作,执行完后关闭。但如果每次要和AMS通信都要重复打开Binder Driver和建立内存映射,这样很浪费资源,也会降低效率。一个好的方式就是,app进程只在一开始打开Binder Driver、建立内存映射,之后就一直使用直到进程被关闭。
围绕这个思路,我们再来看下,app进程被创建后,执行到RuntimeInit.zygoteInit()时所进行的初始化操作。
// frameworks/base/core/java/com/android/internal/os/RuntimeInit.java
public static final void zygoteInit(int targetSdkVersion, String[] argv)
throws ZygoteInit.MethodAndArgsCaller {
...
// 这里调用了一个native方法
zygoteInitNative();
applicationInit(targetSdkVersion, argv);
}
public static final native void zygoteInitNative();
// frameworks/base/core/jni/AndroidRuntime.cpp
static JNINativeMethod gMethods[] = {
{ "finishInit", "()V",
(void*) com_android_internal_os_RuntimeInit_finishInit },
{ "zygoteInitNative", "()V",
(void*) com_android_internal_os_RuntimeInit_zygoteInit },
{ "isComputerOn", "()I",
(void*) com_android_internal_os_RuntimeInit_isComputerOn },
{ "turnComputerOn", "()V",
(void*) com_android_internal_os_RuntimeInit_turnComputerOn },
{ "getQwertyKeyboard", "()I",
(void*) com_android_internal_os_RuntimeInit_getQwertyKeyboard },
};
static AndroidRuntime* gCurRuntime = NULL;
static void com_android_internal_os_RuntimeInit_zygoteInit(JNIEnv* env, jobject clazz)
{
// gCurRuntime在AndroidRuntime类的构造函数中被赋值的
// 创建的位置是Zygote进程的main()方法,实际类型是AppRuntime
gCurRuntime->onZygoteInit();
}
// frameworks/base/cmds/app_process/app_main.cpp
virtual void onZygoteInit()
{
// 打开/dev/binder,建立内存映射
sp proc = ProcessState::self();
LOGV("App process: starting thread pool.\n");
proc->startThreadPool();
}
1. ProcessState
ProcessState::self()是返回一个单例对象,保证进程内只有一个实例,再看看它的构造函数:
// frameworks/base/libs/binder/ProcessState.cpp
ProcessState::ProcessState()
: mDriverFD(open_driver()) // 打开/dev/binder
, mVMStart(MAP_FAILED)
, mManagesContexts(false)
, mBinderContextCheckFunc(NULL)
, mBinderContextUserData(NULL)
, mThreadPoolStarted(false)
, mThreadPoolSeq(1) {
if (mDriverFD >= 0) {
// 使用mmap进行内存映射
mVMStart = mmap(0, BINDER_VM_SIZE, PROT_READ, MAP_PRIVATE | MAP_NORESERVE, mDriverFD, 0);
}
}
static int open_driver() {
int fd = open("/dev/binder", O_RDWR);
if (fd >= 0) {
...
// 设置支持的最大线程数
size_t maxThreads = 15;
result = ioctl(fd, BINDER_SET_MAX_THREADS, &maxThreads);
...
}
return fd;
}
2. Binder线程池
Binder是支持并发执行IPC的,通过Binder线程池来执行。线程池的大小上限是1+15=16个。1是我们下面要说的Binder主线程,15正是上面我们打开Binder Driver后设置的值。 在app进程创建后一开始只会创建一个Binder主线程,Binder Driver会根据需要向用户空间发送创建线程的命令。
// frameworks/base/cmds/app_process/app_main.cpp
virtual void onZygoteInit()
{
sp proc = ProcessState::self();
LOGV("App process: starting thread pool.\n");
// 创建一个Binder主线程 (主线程不会退出)
proc->startThreadPool();
}
void ProcessState::startThreadPool()
{
AutoMutex _l(mLock);
if (!mThreadPoolStarted) {
mThreadPoolStarted = true;
// true表示是创建Binder主线程
spawnPooledThread(true);
}
}
void ProcessState::spawnPooledThread(bool isMain)
{
...
// 启动Binder主线程
sp t = new PoolThread(isMain);
t->run(buf);
}
class PoolThread : public Thread
{
public:
PoolThread(bool isMain)
: mIsMain(isMain)
{
}
protected:
virtual bool threadLoop()
{
IPCThreadState::self()->joinThreadPool(mIsMain);
return false;
}
const bool mIsMain;
};
参考:
《深入理解Android内核设计思想 第2版》
Binder通信过程中的用户空间线程池的管理