安卓应用启动流程
目录
- 1 冷启动热启动
- 2 zygote和SystemServer
- 3 应用启动流程简述(记得补充)
- 4 从点击图标到通知Zygote
- 4.1 Launcher
- 4.2 Activity.java
- 4.3 Instrumentation.java
- 4.4 ActivityTaskManager.java
- 4.5 ActivityTaskManagerService.java
- 4.6 ActivityStarter.java
- 4.7 RootWindowContainer.java
- 4.8 回到ActivityTaskManagerService.java
- 4.9 ActivityManagerService.java
- 4.10 ProcessList.java
- 4.11 ZygoteProcess.java
- 5 Zygote创建Activity进程
- 5.1 ZygoteServer.java
- 5.2 ZygoteConnection.java
- 5.3 ZygoteInit.java
- 5.4 RuntimeInit.java
- 6 初始化Application实例
- 6.1 ActivityThread.java
- 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(...) {//...// 调用startActivityInnerresult = 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服务 - 博客园