安卓应用启动流程
目录
- 1 冷启动热启动
- 2 zygote和SystemServer
- 3 应用启动流程简述(记得补充)
- 4 从点击图标到通知Zygote
- 5 Zygote创建Activity进程
- 6 初始化Application实例
- 7 小结
- 8 引用
1 冷启动热启动
Activity启动过程中,一般会牵涉到应用启动的流程。应用启动又分为冷启动和热启动。
- 冷启动:点击桌面图标,手机系统不存在该应用进程,这时系统会重新fork一个子进程来加载Application并启动Activity,这个启动方式就是冷启动。
- 热启动:应用的热启动比冷启动简单得多,开销也更低。在热启动中,因为系统里已有该应用的进程,所以系统的所有工作就是将您的 Activity 带到前台。 冷启动是应用完全从0开始启动,涉及到更多的内容,所以就应用冷启动的过程展开讨论。
作者:天才木木木木
链接:https://juejin.cn/post/6844904116561379341
来源:稀土掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
2 zygote和SystemServer
在进入应用启动流程前,先简单回顾一下。
zygote是在系统启动后init进程fork出来的。
zygote有一个socket,用于接受消息,当有应用申请启动的时候,会通过socket通知zygote进程,其会fork自己来创建应用进程。- 在
init过程中,zygote会fork出SystemServer进程。
SystemServer是由zygote进程fork出来的第一个进程,其管理着很多重要服务,比如ActivityManagerService、PackageManagerService、WindowManagerService。
3 应用启动流程简述(记得补充)
从用户点击图标开始到应用创建再到第一个Activity启动

4 从点击图标到通知Zygote
4.1 Launcher
Launcher是Android系统启动后,Activity Manager Service (AMS)加载的第一个应用程序Launcher又被称为桌面程序,负责Android桌面的启动和管理- 用户使用的应用程序(App)都是通过
Launcher来启动的
源码:/packages/apps/Launcher3/src/com/android/launcher3/Launcher.java
在Launcher中有这么一段代码,创建桌面快捷方式

其中绑定了点击事件
跟进源码:/packages/apps/Launcher3/src/com/android/launcher3/touch/ItemClickHandler.java

对于App图标来说最终都是调用startAppShortcutOrInfoActivity方法。

而后最终会调用startActivitySafely,这里的launcher是Launcher类,所以回到Launcher.java代码。
其中的startActivitySafely会继续往上调用

继承关系:Launcher←StatefulActivity←BaseDraggingActivity ← BaseActivity←Activity
startActivitySafely是在BaseActivity中实现的AppLauncher的接口方法
源码:/packages/apps/Launcher3/src/com/android/launcher3/views/AppLauncher.java

于是乎流程进入到了Activity.java
4.2 Activity.java
Activity源码位于/frameworks/base/core/java/android/app/Activity.java
startActivity会调用startActivityForResult

startActivityForResult

以下是通义给出的解释:
这段代码是 startActivityForResult 方法的一部分,这个方法用于启动一个 Activity,并期望从该 Activity 获取返回的结果。当目标 Activity 完成后,它会回调当前 Activity 的 onActivityResult 方法,并附带请求码(requestCode)以及结果数据。
关键点包括:
intent参数是一个Intent对象,它包含了要启动的目标Activity的信息。requestCode是一个整型值,当目标Activity结束时会通过onActivityResult回调传递回来。这有助于识别哪个Activity返回了结果。options参数是可选的Bundle对象,可以用来指定Activity启动的一些额外选项。
如果当前 Activity 没有父 Activity (mParent == null),则会调用 Instrumentation 类的 execStartActivity 方法来启动新的 Activity。如果 requestCode 大于等于 0,则标记 mStartedActivity 为 true,这样可以避免在 Activity 初始化期间的闪烁现象,直到收到启动的 Activity 的结果为止。
如果当前 Activity 有一个父 Activity,则会调用父 Activity 的 startActivityFromChild 方法来启动新的 Activity,同时传递 requestCode 和 options。
4.3 Instrumentation.java
源码:/frameworks/base/core/java/android/app/Instrumentation.java
在Instrumentation.java中execStartActivity有两种实现。execStartActivity (带 UserHandle 参数) 方法允许开发者显式地指定用于启动 Activity 的用户。而未带UserHandle参数的方法会使用默认用户启动Activity。
1 | public ActivityResult execStartActivity( |
以execStartActivity (不带 UserHandle 参数) 为例,红框处为关键代码。

进入到了ActivityTaskManager中
4.4 ActivityTaskManager.java
源码:/frameworks/base/core/java/android/app/ActivityTaskManager.java
ActivityTaskManager.getService()能够获取到ActivityTaskManagerService的实例对象。
Singleton是单例模式的对象创建,也就是一个进程中只有一个该对象。

这里的ServiceManager应当对应的是当前进程的ServiceManager的单例,所以这里的调用是Launcher的ServiceManager单例。
当应用启动的时候AMS会将系统服务注册进进程的ServiceManager里。getService函数是直接从单例的数组中中获取的。

获取到的IBinder是对应Binder的引用信息,可以理解为所需要调用的(在这里为ActivityTaskManagerService)系统服务的引用信息。
而后返回系统服务所提供的服务接口。

为了能够流畅的理解启动流程,在这里不严谨地描述一下Binder机制的作用,具体的Binder机制会在后面的文章中学习。

之后的任务就交给了ActivityTaskManagerService
4.5 ActivityTaskManagerService.java
源码地址:/frameworks/base/services/core/java/com/android/server/wm/ActivityTaskManagerService.java


startActivityAsUser方法通过ActivityStartController的obtainStarter方法获取了ActivityStarter对象实例,并调用ActivityStarter的execute方法
4.6 ActivityStarter.java
源码位置/frameworks/base/services/core/java/com/android/server/wm/ActivityStarter.java
在ActivityStarter中最终会调用RootWindowContainer的resumeFocusedTasksTopActivities方法
1 | int execute() { |

4.7 RootWindowContainer.java
RootWindowContainer是WindowManagerService的主要组成部分之一,是一个管理窗口的容器。
resumeFocusedTasksTopActivities将会调用Task和TaskFragmentPause前台程序,为新的应用程序启动做准备。
源码位置:/frameworks/base/services/core/java/com/android/server/wm/RootWindowContainer.java

Task.java中的resumeTopActivityUncheckedLocked↓

Task.java中的resumeTopActivityInnerLocked↓

TaskFragment.java中的resumeTopActivity↓

简单总结一下如图

startProcessAsync就将交回给ActivityTaskManagerService.java
4.8 回到ActivityTaskManagerService.java
处理完窗口容器数据以后(核心工作是将前台程序Pause),再次回到了ActivityTaskManagerService
源码地址/frameworks/base/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
在startProcessAsync使用调用ActivityManagerInternal的startProcess方法

这里传入的mAmInternal变量是通过类搜索得到的。

ActivityManagerInternal的实现类是ActivityManagerService,所以这里就相当于给ActivityManagerService发消息。
这里使用的Handler机制是安卓中线程之间的通信方式,两种Service就是在同一进程下的不同进程。
4.9 ActivityManagerService.java
源码地址:/frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
startProcess

startProcessLocked

4.10 ProcessList.java
源码地址:/frameworks/base/services/core/java/com/android/server/am/ProcessList.java
由于代码实在太长,这里就摘要一下
startProcessLocked中定义了创建Activity完成后回调的入口点

最终会调用startProcess

startProcess代码主要做了以下事情
- 数据隔离:根据系统的配置,可能需要对应用的数据目录进行隔离处理。这涉及到文件系统的挂载操作。
- 选择合适的Zygote进程:根据应用的需求选择普通的
Zygote进程、Webview Zygote进程或者是App Zygote进程来启动应用。这里是启动App,所以是App Zygote - 启动应用进程:调用不同的方法来启动应用进程,这些方法会根据选择的
Zygote类型有所不同。 - 异步准备存储目录:如果需要绑定挂载应用存储目录,则异步执行目录的准备工作,以避免阻塞应用启动过程。

4.11 ZygoteProcess.java
源码地址:/frameworks/base/core/java/android/os/ZygoteProcess.java

startViaZygote全是设置参数


然后到zygoteSendArgsAndGetResult↓

再到attemptZygoteSendArgsAndGetResult,与Zygote的通信就在这里面。

5 Zygote创建Activity进程
Zygote进程是在Android系统启动过程中创建的,创建完成后会通过ZygoteServer来监听消息
5.1 ZygoteServer.java
ZygoteServer监听消息的方法是runSelectLoop
源码地址:/frameworks/base/core/java/com/android/internal/os/ZygoteServer.java

在runSelectLoop中会调用ZygoteConnection的processCommand
5.2 ZygoteConnection.java
这段代码是 Zygote 进程中的一个关键部分,用于处理来自客户端的命令,以启动新的应用程序进程。
源码地址:/frameworks/base/core/java/com/android/internal/os/ZygoteConnection.java
- **调用 ****
forkAndSpecialize****或forkSimpleApps**:调用1
2
3pid = Zygote.forkAndSpecialize(parsedArgs.mUid, parsedArgs.mGid, ..., parsedArgs.mAppDataDir);
...
Runnable result = Zygote.forkSimpleApps(argBuffer, zygoteServer.getZygoteSocketFileDescriptor(), ..., parsedArgs.mNiceName);forkAndSpecialize或forkSimpleApps方法来创建新的进程,并对其进行配置。 - 处理子进程和父进程:根据
1
2
3
4
5
6
7
8
9
10if (pid == 0) {
// 在子进程中
...
return handleChildProc (parsedArgs, childPipeFd, parsedArgs.mStartChildZygote);
} else {
// 在父进程中
...
handleParentProc(pid, serverPipeFd);
return null;
}fork()的返回值来区分父进程和子进程,并分别处理。
在handleParentProc中,会将创建好的进程pid发回给请求方(ActivityManagerService)。

handleChildProc中会调用ZygoteInit.``zygoteInit来初始化应用程序

5.3 ZygoteInit.java
Zygote进程的初始化逻辑也是在ZygoteInit中,这里fork创建的进程也是一个Zygote进程,所以也要进行ZygoteInit。
源码地址:/frameworks/base/core/java/com/android/internal/os/ZygoteInit.java

5.4 RuntimeInit.java
源码地址:/frameworks/base/core/java/com/android/internal/os/RuntimeInit.java

进入到findStaticMain,这个方法中,将通过反射找到之前传入的entryPoint(android.app.ActivityThread),然后调用其main方法。

到这里Zygote进行fork子进程的流程已经结束了,接下来将交给ActivityThread进行app的实例创建。
6 初始化Application实例
6.1 ActivityThread.java
源码地址:/frameworks/base/core/java/android/app/ActivityThread.java

attach方法如下

这里的调用栈就不深入了,接下来会调用到bindApplication方法

这里的H是ActivityThread的一个内置类


最终调用handleBindApplication,进行app实例化。

在实例化中调用的是Instrumentation的newApplication方法。
每个Activity都持有一个Instrumentation,它是由ActivityThread创建出来的一个单例。 这个类就是完成对Application和Activity初始化和生命周期的工具类,ActivityThread要创建或执行Activity生命周期方法时,都需要通过Instrumentation来进行具体的操作。
调用OnCreate函数。

至此应用启动的流程就算基本结束了。
7 小结
实际上应用启动后续还需要加载第一个Activity并将其带到前台显示,但由于都是类似的流程,就不再过多赘述了。主要从应用启动流程的学习可以对Zygote和AMS有一些更深入的了解。在启动流程中遇到了Binder、Handler、Looper等安卓重要的机制,甚至还涉及到了反射,对后面这些机制的学习也有很大的帮助。