前言
启动一个应用的前提就是这个应用所需的进程已经启动,所以AMS在启动应用是会首先检查这个应用的进程是否存在,如果不存在就会请求Zygote进程fork一个新的进程并启动起来。
在前面的文章里我们知道Zygote会创建一个Socket,这个Socket用来等待AMS的请求,当收到请求会fork自身创建应用进程,这样就会获得进程中自带的虚拟机实例。
进程创建过程中除了获取虚拟机实例,还会创建Binder线程池和消息循环,这样运作在进程中的应用就可以进行进程间通信了。
AMS发送启动进程请求
首先AMS通过调用startProcessLocked向Zygote进行发送请求,这个过程大致如下:
先重点来看看ZygoteProcess的openZygoteSocketIfNeeded这个方法,部分代码如下:
private ZygoteState openZygoteSocketIfNeeded(String abi) throws ZygoteStartFailedEx {
...
if (primaryZygoteState == null || primaryZygoteState.isClosed()) {
try {
primaryZygoteState = ZygoteState.connect(mSocket);
} catch (IOException ioe) {
throw new ZygoteStartFailedEx("Error connecting to primary zygote", ioe);
}
...
}
if (primaryZygoteState.matches(abi)) {
return primaryZygoteState;
}
// The primary zygote didn't match. Try the secondary.
if (secondaryZygoteState == null || secondaryZygoteState.isClosed()) {
try {
secondaryZygoteState = ZygoteState.connect(mSecondarySocket);
} catch (IOException ioe) {
throw new ZygoteStartFailedEx("Error connecting to secondary zygote", ioe);
}
...
}
if (secondaryZygoteState.matches(abi)) {
return secondaryZygoteState;
}
throw new ZygoteStartFailedEx("Unsupported zygote ABI: " + abi);
}
之前文章讲到过在Zygote的main方法中会创建名为"zygote"的Socket。在openZygoteSocketIfNeeded方法中可以看到会调用ZygoteState的connect方法与mSocket建立连接,mSocket就是名为“zygote”的Socket,并返回ZygoteState类型的对象primaryZygoteState。然后可以看到检查primaryZygoteState与应用程序进程所需的ABI是否匹配,如果不匹配则会继续通过connect连接mSecondarySocket,这个则是名为“zygote_secondary”的Socket。
在之前文章中说过Zygote分32位和64位,再组合成主模式+辅模式可以有4种脚本,名为“zygote”的就是主模式,名为“zygote_secondary”就是辅模式。
所以上面的代码简单来说就是先连接主模式的Zygote,然后判断是否匹配ABI,如果不匹配就连接辅模式。
这个ZygoteState对象会返回给zygoteSendArgsAndGetResult方法,然后将应用进程的启动参数写入ZygoteState,这样就将启动进程的请求发送到Zygote了。
Zygote接受请求并创建进程
先来看看这个过程的大致流程:
回到Zygote的main方法中,这部分前面文章讲过了,这里简单回顾一下。这里会创建一个name为"zygote"的Socket来等待AMS请求,然后预加载类和资源,接下来启动SystemServer进程,SystemServer进程也会启动系统服务,最后会调用ZygoteServer的runSelectLoop来等待AMS发送创建新应用进程的请求。
runSelectLoop会调用runOnce函数来处理请求,这个函数代码如下:
boolean runOnce() throws ZygoteInit.MethodAndArgsCaller {
...
pid = Zygote.forkAndSpecialize(parsedArgs.uid, parsedArgs.gid, parsedArgs.gids, parsedArgs.debugFlags, rlimits, parsedArgs.mountExternal, parsedArgs.seInfo, parsedArgs.niceName, fdsToClose, parsedArgs.instructionSet,parsedArgs.appDataDir);
} catch(){
}
try {
if (pid == 0) {
...
IoUtils.closeQuietly(serverPipeFd);
serverPipeFd = null;
handleChildProc(parsedArgs, descriptors, childPipeFd, newStderr);
return true;
} else {
IoUtils.closeQuietly(childPipeFd);
childPipeFd = null;
return handleParentProc(pid, descriptors, serverPipeFd, parsedArgs);
}
} finally {
IoUtils.closeQuietly(childPipeFd);
IoUtils.closeQuietly(serverPipeFd);
}
}
在这个函数中会调用readArgumentList方法来获取应用进程的启动参数,也就是之前写入ZygoteState对象的。然后可以看到执行了forkAndSpecialize方法用这些参数来fork一个应用程序进程,返回pid。如果pid是0说明代码运行在新创建的应用进程中,就会执行handleChildProc。
在handleChildProc方法中调用了ZygoteInit的zygoteInit方法,代码如下:
public static final Runnable zygoteInit(int targetSdkVersion, String[] argv, ClassLoader classLoader) {
...
RuntimeInit.redirectLogStreams();
RuntimeInit.commonInit();
ZygoteInit.nativeZygoteInit();
return RuntimeInit.applicationInit(targetSdkVersion, argv, classLoader);
}
注意ZygoteInit.nativeZygoteInit()
这一步会创建Binder线程池,这个我们后续再说。然后调用了RuntimeInit的applicationInit函数。这个函数中会调用invokeStaticMain方法,代码如下:
private static void invokeStaticMain(String className, String[] argv, ClassLoader classLoader)
throws Zygote.MethodAndArgsCaller {
Class<?> cl;
try {
cl = Class.forName(className, true, classLoader);
} catch (ClassNotFoundException ex) {
throw new RuntimeException(
"Missing class when invoking static main " + className,
ex);
}
Method m;
try {
m = cl.getMethod("main", new Class[] { String[].class });
} catch (NoSuchMethodException ex) {
throw new RuntimeException(
"Missing static main on " + className, ex);
} catch (SecurityException ex) {
throw new RuntimeException(
"Problem getting static main on " + className, ex);
}
...
throw new Zygote.MethodAndArgsCaller(m, argv);
}
这里通过反射获得了ActivityThread类,并获得了它的main方法,然后将main方法传入MethodAndArgsCaller类,这个类是一个异常类,最后抛出这个异常。在Zygote的main方法中会捕获这个异常并获取main方法执行。
这里为什么不直接执行main而是抛出异常呢?和之前文章中Zygote处理SystemServer进程一样,抛出异常会清除所有以上过程的堆栈帧,这样ActivityThread的main方法就是最初的,看起来像是应用程序进程的入口方法一样。
Binder线程池
上面说到在Zygote处理创建应用进程的请求过程中会在zygoteInit方法中通过ZygoteInit.nativeZygoteInit()
这一步来创建Binder线程池。
很明显nativeZygoteInit是JNI方法,对应的是AndroidRuntime.cpp中的con_android_internal_os_ZygoteInit_nativeZygoteInit函数,这个函数只有一行代码
gCurRuntime->onZygoteInit()
gCurRuntime是AndroidRuntime类型的指针,在这里实际上是AppRuntime,因为AppRuntime继承自AndroidRuntime,它创建的时候就会创建这个指针。
而onZygoteInit函数的真正实现则是在app_main.app中,代码如下
virtual void onZygoteInit(){
sp<ProcessState> proc = ProcessState::self();
if(proc->supportsProcesses()){
proc->startThreadPool();
}
}
最后一步调用ProcessState的startThreadPool函数来启动Binder线程池,这个函数如下:
void ProcessState::startThreadPool()
{
AutoMutex _l(mLock);
if (!mThreadPoolStarted) {
mThreadPoolStarted = true;
spawnPooledThread(true);
}
}
其中mThreadPoolStarted用来标识Binder线程池是否启动过,这样确保Binder线程池只启动一次。如果未启动则调用spawnPooledThread来创建线程池中的第一个线程——主线程。
void ProcessState::spawnPooledThread(bool isMain)
{
if (mThreadPoolStarted) {
String8 name = makeBinderThreadName();
sp<Thread> t = new PoolThread(isMain);
t->run(name.string());
}
}
Binder线程都是PoolThread对象,然后执行run函数启动线程。PoolThread代码如下:
class PoolThread : public Thread
{
...
protected:
virtual bool threadLoop()
{
IPCThreadState::self()->joinThreadPool(mIsMain);
return false;
}
const bool mIsMain;
};
在PoolThread中调用IPCThreadState的joinThreadPool函数,可以将当前线程注册到Binder驱动中,这样就加入了Binder线程池,新创建的应用进程就支持Binder进程通信了。我们只需要创建当前进程的Binder对象,将它注册到ServiceManager中就可以实现Binder进程间通信,不必关系进程间是如何通过Binder通信。
消息循环创建
在上面的进程中,还有一个过程没有提到,就是应用程序进程启动后会创建消息循环。
上面我们提到Zygote处理创建应用进程请求的最后是通过抛出异常,然后在ZygoteInit的main方法中捕获,从异常中获取ActivityThread的main方法并执行的。这个main方法的代码如下:
public static void main(String[] args) {
Looper.prepareMainLooper();
ActivityThread thread = new ActivityThread();
thread.attach(false, startSeq);
if (sMainThreadHandler == null) {
sMainThreadHandler = thread.getHandler();
}
Looper.loop();
throw new RuntimeException("Main thread loop unexpectedly exited");
}
ActivityThread类用于管理当前应用进程的主线程,在这里可以看到创建了主线程的消息循环looper;然后创建了ActivityThread;接下来赋值sMainThreadHandler,这个handler就用于处理主线程的消息;最后通过loop()函数将消息循环启动起来。
这样主线程中就启动了消息循环了,就可以通过Handler进行消息通信。
总结
上面我们总结了应用进程的创建和启动过程,其实主要就是两个部分:
- AMS发送创建应用程序进程的请求到Zygote
- Zygote接收创建应用程序进程的请求,fork出新的进程并启动
当然在这个过程中有很多细节,最重要就是Binder线程池和消息循环的创建和启动。
最后
如果想要成为架构师或想突破20~30K薪资范畴,那就不要局限在编码,业务,要会选型、扩展,提升编程思维。此外,良好的职业规划也很重要,学习的习惯很重要,但是最重要的还是要能持之以恒,任何不能坚持落实的计划都是空谈。
如果你没有方向,这里给大家分享一套由阿里高级架构师编写的《Android八大模块进阶笔记》,帮大家将杂乱、零散、碎片化的知识进行体系化的整理,让大家系统而高效地掌握Android开发的各个知识点。
相对于我们平时看的碎片化内容,这份笔记的知识点更系统化,更容易理解和记忆,是严格按照知识体系编排的。
欢迎大家一键三连支持,若需要文中资料,直接扫描文末优快云官方认证微信卡片免费领取↓↓↓(文末还有ChatGPT机器人小福利哦,大家千万不要错过)

PS:群里还设有ChatGPT机器人,可以解答大家在工作上或者是技术上的问题
