注:下列源码均基于9.0,可通过下列方式下载本文相关源码到本地:
前言
本篇文章将根据源码解剖Android的Activity的启动流程,需注意的是下列的分析均基于Android9.0, 9.0版本相较于之前几个版本做了许多改动和重构,但是整体的流程是变化不大。根据启动Activity时机的不同,可分为根Activity的启动流程和普通Activity启动流程,根Activity启动流程又可以称为应用程序启动流程,即在桌面上点击一个应用图标到进入到应用第一个Activity的流程。而普通Activity的启动流程就是在一个应用里开启另外一个Activity的流程。由于两种启动流程是有重叠的,而根Activity的启动流程更加复杂,所以接下来我们重点分析根Activity的启动流程,而普通Activity的启动流程在涉及的地方会稍微提一下。由于考虑到篇幅较长,这里将分为两篇来介绍。
这篇将分析启动流程中的应用进程的创建:
- Launcher进程请求AMS
- AMS发送创建应用进程请求
- Zygote进程接受请求并孵化应用进程
- 应用进程启动ActivityThread
一、Launcher进程请求AMS
上面我们提到根Activity的启动流程其实就是桌面上点击一个应用图标进入到应用的第一个Activity的流程,其实桌面也可以看成一个程序,即Launcher。当系统开机后,Launcher也随之被启动,然后将已经安装的应用程序图标显示到桌面上,所以当我们点击一个应用图标其实就是相当于点击活动中的一个button,其相应事件就是Launcher进程请求AMS来启动该应用程序。
1. 时序图
2. 详细过程
请求的入口就是Launcher的startActivitySafe方法,如下:
packages/apps/Launcher3/src/com/android/launcher3/Launcher.java
1 | public boolean startActivitySafely(View v, Intent intent, ItemInfo item) { |
可以发现该方法为根Activity设置了flag,即根Activity会在新的任务栈中启动。然后会调用我们熟悉的startActivity方法,而在Launcher并没有这个方法,所以我们自然想到了应该是父类的方法,然后让我们来看看Launcher继承了哪些类?
1 | public class Launcher extends BaseDraggingActivity implements LauncherExterns, |
其实一直追踪下去,你就会发现其实Launcher调用的startActivity其实就是Activity中的startActivity。从这里也可以证明Launcher其实也是个Activity。所以在Launcher启动一个app,和我们平时在startActivity基本是一样的(基本一样,不代表完全一样,通过后文分析你就会明白!),于是我们来看看我们熟悉的Activity中的startActivity的源码是如何的:
源码:frameworks/base/core/java/android/app/Activity.java
1 |
|
从上面代码可以发现startActivity的最终实现是startActivityForResult,startActivity()第二个参数为-1表示Launcher不需要知道根Activity的启动结果,然后在startActivityForResult中由于此时根Activity还没有创建,故mParent=null,所以我们只需要关注mParent=null的情况。在这种情况中会调用Instrumentation的execStartActivity。这时候也许你就会问这个Instrumentation是什么?为什么要交给她弄呢?其实Instrumentation这个类很重要,重要体现在对Activity生命周期的调用根本离不开她。每个Activity都持有Instrumentation对象的一个引用,但是整个进程只会存在一个Instrumentation对象。回归正题,让我们瞧瞧Instrumentation的execStartActivity这个方法。
frameworks/base/core/java/android/app/Instrumentation.java
1 | public ActivityResult execStartActivity( |
在这个方法会调用ActivityManager的getService方法来得到AMS的代理对象,然后调用这个代理对象的
startActivity方法,那么这个代理对象是谁呢?让我们一探究竟
1 |
|
可以发现在Singleton中的create方法中由于b是AMS引用作为服务端处于SystemServer进程中,与当前Launcher进程作为客户端与服务端不在同一个进程,所以am返回的是IActivityManager.Stub的代理对象,此时如果要实现客户端与服务端进程间的通信,只需要在AMS继承了IActivityManager.Stub类并实现了相应的方法,而通过下面的代码可以发现AMS刚好是继承了IActivityManager.Stub类的,这样Launcher进程作为客户端就拥有了服务端AMS的代理对象,然后就可以调用AMS的方法来实现具体功能了,就这样Launcher的工作就交给AMS实现了。
1 | public class ActivityManagerService extends IActivityManager.Stub |
二、AMS发送创建应用进程请求
通过上面的分析,我们已经知道现在任务已经交给了AMS,入口是AMS的startActivity。
1. 时序图
2. 详细过程
2.1 AMS将请求任务转移给Process
首先来看看在AMS中的startActivity方法:
源码:frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
1 |
|
startActivity方法经过多个方法调用会去执行startActivityAsUser方法,在startActivityAsUser方法最后会返回mActivityStartController的一长串链式调用方法,如果AlertDialog的话,应该不难看出这链式方法肯定都是返回一个类型的对象的,我们只需要看看obtainStarter的返回类型就可以知道这个对象是什么类型了。
frameworks/base/services/core/java/com/android/server/am/ActivityStartController.java
1 | ActivityStarter obtainStarter(Intent intent, String reason) { |
可以发现这个obtainStarter返回的是ActivityStarter类型的,所以链式方法就是对ActivityStarter对象设置了要启动的活动的相关信息,最后再调用ActivityStarter对象execute方法。所以我们下一步所需要看的就是这个execute方法。
frameworks/base/services/core/java/com/android/server/am/ActivityStarter.java
1 | int execute() { |
因为在startActivityAsUser的链式方法中我们调用了setMayWait这个方法,所以这里的mRequest.mayWait为true,故会继续调用startActivityMayWait方法。
ActivityStarter#startActivityMayWait
1 |
|
startActivityMayWait方法经过调用多次的startActivity方法后会调用到startActivityUnchecked这个方法,那这个方法是干啥的呢?这个方法会根据启动标志位和Activity启动模式来决定如何启动一个Activity以及是否要调用deliverNewIntent方法通知Activity有一个Intent试图重新启动它。比如我们在一开始将活动设置了FLAG_ACTIVITY_NEW_TASK后将创建一个任务栈,其它的就自行看代码。
1 | private int startActivityUnchecked(final ActivityRecord r, ActivityRecord sourceRecord, |
然后无论以何种模式启动最终都会调用ActivityStackSupervisor.resumeFocusedStackTopActivityLocked方法。
frameworks/base/services/core/java/com/android/server/am/ActivityStackSupervisor.java
1 | boolean resumeFocusedStackTopActivityLocked( |
于是又调用了ActivityStack的resumeTopActivityUncheckedLocked
frameworks/base/services/core/java/com/android/server/am/ActivityStack.java
1 | "mService") ( |
emmmm…..,看到这估计都懵逼了,几个类跳来跳去也不知道干了些什么,不慌,让我们坚持看下ActivityStackSupervisor.startSpecificActivityLocked,因为这个方法很重要。这个方法将是普通Activity和根Activity启动流程的分岔路口。
ActivityStackSupervisor#startSpecificActivityLocked
1 | void startSpecificActivityLocked(ActivityRecord r, |
阅读上面的代码我们可以知道在方法中首先获取到了即将要启动的Activity所在的应用进程,假如是普通的Activity的启动流程的活,这个进程肯定是存在的,所以将执行realStartActivityLocked的方法。但是我们现在讨论的是根Activity的启动流程,由于应用都还未启动,意味着根Activity所在的应用进程还未创建,而mService其实就是AMS,所以这里将调用AMS的startProcessLocked。于是我们又回到了最初的起点AMS。
ActivityManagerService.java
1 | final ProcessRecord startProcessLocked(String processName, |
是不是又惊呆了,好吧,我也惊呆了!反正就是通过调用多个startProcessLocked方法后最终将调用startProcess方法,不过需要重点看一下上面的第四个startProcessLocked,在该方法中有个entryPoint参数为 “android.app.ActivityThread”,这个参数将在后文讲到创建应用进程后启动ActivityThread会用到。然后在startProcess方法里将调用Process.start来发送应用创建进程的请求。这样AMS就将发送请求的事交给了Process
2.2 Process向Zygote进程发送创建应用进程请求
frameworks/base/core/java/android/os/Process.java
1 | public static final ProcessStartResult start(final String processClass, |
从上面可以发现,Process中的start方法的实现是startViaZygote方法,所以我们重点观察下这个方法。
1 | private Process.ProcessStartResult startViaZygote(final String processClass, |
在startViaZygote中会创建字符串列表argsForZygote来保存将要创建的应用进程的启动参数,然后最后会调用zygoteSendArgsAndGetResult方法,而在这个方法中第一个参数会调用openZygoteSocketIfNeeded方法,第三个参数就是启动参数列表。所以我们先看看openZygoteSocketIfNeeded这个方法的实现。
1 | private ZygoteState openZygoteSocketIfNeeded(String abi) |
openZygoteSocketIfNeeded这个方法从方法名就可以推测出这个方法的作用,大概就是与Zygote建立Socket连接。而从代码中也证实了这一点,在代码中会根据Zygote进程的位数来建立相应的Socket连接,然后返回ZygoteState类型的对象。既然与Zygote建立好Socket连接后,接下来当然是发送请求啦!所以让我们来看看zygoteSendArgsAndGetResult这个方法中是如何发送请求的!
1 | //将传入的应用进程的启动参数argsForZygote写入到ZygoteState |
因为在openZygoteSocketIfNeeded中我们已经与Zygote进程建立了Socket连接,所以在这个方法中将传入的应用进程的启动参数argsForZygote写入到ZygoteState。这样AMS就完成了向Zygote进程发送创建应用进程的请求的任务。
三、Zygote进程接受请求并孵化应用进程
从上面我们知道,AMS已经与Zygote进程建立Socket连接并发送了创建应用进程的请求,那么Zygote进程是在哪里收到请求,收到请求后又是怎么处理的呢?这里可以停下来先看看刘望舒的Android系统启动流程(二)解析Zygote进程启动过程,写的很不错。不过由于我们分析的源码基于8.0,可能会稍微不同,但总体上来大致流程是一样的。通过阅读后我们知道Zygote进程是在ZygoteInit的main方法中接受请求的。所以现在的入口就是ZygoteInit的main方法。
1. 时序图
2. 详细过程
从时序图与上面的分析我们知道现在Zygote进程接受请求是在main方法,就让我们来看看这个main方法
frameworks/base/core/java/com/android/internal/os/ZygoteInit.java
1 |
|
通过main方法,我们可以知道在这个main方法首先要创建一个Server端的Socket,这个name为”zygote”的Socket用来等待ActivityManagerService来请求Zygote来创建新的应用程序进程,在上面AMS请求的分析中我们也知道客户端将根据这个name来与Zygote的Socket建立连接。接下去会启动SystemServer进程,这个进程会启动各种系统服务,比如与Activity启动息息相关的AMS。最后会调用ZygoteServer.runSelectLoop(abiList)来使创建的Socket进入无限循环,等待AMS请求。让我们来看看这个runSelectLoop
frameworks/base/core/java/com/android/internal/os/ZygoteServer.java
1 | Runnable runSelectLoop(String abiList) { |
可以发现这个方法是死循环表示不停的监听着Socket连接。acceptCommandPeer方法就是监听是否收到了请求,如果收到了请求就交给processOneCommand来实现
frameworks/base/core/java/com/android/internal/os/ZygoteConnection.java
1 | Runnable processOneCommand(ZygoteServer zygoteServer) { |
在这个方法中将对请求进行处理,首先获取到将要启动的应用进程的启动参数,然后调用forkAndSpecialize来创建应用进程。
frameworks/base/core/java/com/android/internal/os/Zygote.java
1 | public static int forkAndSpecialize(int uid, int gid, int[] gids, int runtimeFlags, |
在forkAndSpecialize中,最终将创建应用进程的任务交给nativeForkAndSpecialize,而这个方法可以看出来应该是本地方法,所以具体如何创建的我们就不深究了,在这里我们这需要知道nativeForkAndSpecialize最终是通过fork当前线程来创建一个子线程,而fork后会有返回值给pid:
- 父进程中,fork返回新创建的子进程pid;
- 子进程中,fork返回0;
- 出现错误时,fork返回负数。
于是到这里子线程也就是应用进程就被孵化出来了。你以为这样就结束了?其实还早呢!别忘了我们的最终使命是根Activity的启动,而现在只是有了根Activity所需要的应用进程,革命尚未成功,仍需要努力!
四、应用进程启动ActivityThread
1. 时序图
2. 详细过程
从上面我们知道应用进程已经被创建,那创建后呢?这就需要我们回头看上面的processOneCommand方法,细心的你肯定会发现再孵化出应用进程后,还是有返回值的。
frameworks/base/core/java/com/android/internal/os/ZygoteConnection.java
1 | Runnable processOneCommand(ZygoteServer zygoteServer) { |
在上面我们分析了当pid=0的时候,则代表了当前进程已经是子进程了,即应用进程。所以下一步将执行handleChildProc方法。
1 | private Runnable handleChildProc(ZygoteArguments parsedArgs, FileDescriptor[] descriptors, |
而handleChildProc最终又会调用ZygoteInit.zygoteInit方法。如下
frameworks/base/core/java/com/android/internal/os/ZygoteInit.java
1 | public static final Runnable zygoteInit(int targetSdkVersion, String[] argv, |
在这个方法里会创建当前进程的Binder线程池,便于后续与其它进程通信,然后调用了RuntimeInit的applicationInit方法,如下:
frameworks/base/core/java/com/android/internal/os/RuntimeInit.java
1 | protected static Runnable applicationInit(int targetSdkVersion, String[] argv, |
这个方法最终会调用findStaticMain方法,不过需注意的是方法的第一个参数args.startClass其实就是我们上文AMS将请求任务转移给Process中在最后强调的那个参数:android.app.ActivityThread。然后我们看看findStaticMain的实现
1 | protected static Runnable findStaticMain(String className, String[] argv, |
在这个方法中首先在注释1通过反射获取到android.app.ActivityThread类,然后在注释2获取到ActivityThread的main方法,最后通过main方法来构造MethodAndArgsCaller。而这个MethodAndArgsCaller是什么呢?如下:
frameworks/base/core/java/com/android/internal/os/RuntimeInit.java
1 | static class MethodAndArgsCaller implements Runnable { |
追踪下去,MethodAndArgsCaller其实是RuntimeInit的一个内部类并且继承了Runnable,然后在run方法中会通过反射调用了mMethod方法,此时mMethod是ActivityThread的main方法,即run方法中将会执行ActivityThread的main方法,在这里你可能会有疑问了,那这个run方法什么时候执行呢?让我们来看看最开始的ZygoteInit的main方法。
frameworks/base/core/java/com/android/internal/os/ZygoteInit.java
1 |
|
有没有恍然大悟呢?从分析Zygote进程接受请求并孵化应用进程的一开始,我们就是分析zygoteServer.runSelectLoop(abiList)这个方法,而分析到最后findStaticMain方法将返回MethodAndArgsCaller对象(继承Runnable),所以这时候在ZygoteInit的main方法caller会等于这个MethodAndArgsCaller对象,显然caller不等于null,故最后会执行caller.run方法,即执行ActivityThread的main方法。于是应用进程成功启动ActivityThread。
后续
分析到这,我们已经越来越接近万里长征的终点了!不过还是得歇歇,养足精力,才能走到终点。下篇博客Android之9.0Activity启动流程(二)将分析Activity启动流程的剩下部分。即:
- 应用进程绑定到AMS
- AMS发送启动Activity的请求
- ActivityThread的Handler处理启动Activity的请求
参考博客: