安卓应用启动流程
目录
- 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
。
public ActivityResult execStartActivity(
Context who, IBinder contextThread, IBinder token, String resultWho,
Intent intent, int requestCode, Bundle options, UserHandle user )
public ActivityResult execStartActivity(
Context who, IBinder contextThread, IBinder token, String target,
Intent intent, int requestCode, Bundle options)
以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
方法
int execute() {
//...
res = executeRequest(mRequest);
//...
}
private int executeRequest(Request request) {
//...
// 创建ActivityRecord对象
final ActivityRecord r = new ActivityRecord.Builder(mService)
.setCaller(callerApp)
// ...构造参数
.build();
// 调用startActivityUnchecked方法
mLastStartActivityResult = startActivityUnchecked(...);
//...
}
private int startActivityUnchecked(...) {
//...
// 调用startActivityInner
result = startActivityInner(...);
//...
}
int startActivityInner(...) {
//...
// 调用RootWindowContainer的resumeFocusedTasksTopActivities方法
mRootWindowContainer. resumeFocusedTasksTopActivities (...);
//...
}
4.7 RootWindowContainer.java
RootWindowContainer
是WindowManagerService
的主要组成部分之一,是一个管理窗口的容器。
resumeFocusedTasksTopActivities
将会调用Task
和TaskFragment
Pause前台程序,为新的应用程序启动做准备。
源码位置:/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
:
调用pid = Zygote.forkAndSpecialize(parsedArgs.mUid, parsedArgs.mGid, ..., parsedArgs.mAppDataDir); ... Runnable result = Zygote.forkSimpleApps(argBuffer, zygoteServer.getZygoteSocketFileDescriptor(), ..., parsedArgs.mNiceName);
forkAndSpecialize
或forkSimpleApps
方法来创建新的进程,并对其进行配置。 - 处理子进程和父进程:
根据if (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
等安卓重要的机制,甚至还涉及到了反射,对后面这些机制的学习也有很大的帮助。
8 引用
Android桌面Launcher源码浅析 - 博客园
Android应用启动流程分析 - 稀土掘金
Android应用程序启动源码浅析-(三万字长文慎点&Android14) - 博客园
Android Application 启动流程分析及其源码调用探究 - 稀土掘金
Android之ServiceManager服务 - 博客园