安卓应用启动流程

目录

1 冷启动热启动

Activity启动过程中,一般会牵涉到应用启动的流程。应用启动又分为冷启动热启动

  1. 冷启动:点击桌面图标,手机系统不存在该应用进程,这时系统会重新fork一个子进程来加载Application并启动Activity,这个启动方式就是冷启动。
  2. 热启动:应用的热启动比冷启动简单得多,开销也更低。在热启动中,因为系统里已有该应用的进程,所以系统的所有工作就是将您的 Activity 带到前台。 冷启动是应用完全从0开始启动,涉及到更多的内容,所以就应用冷启动的过程展开讨论。

作者:天才木木木木
链接:https://juejin.cn/post/6844904116561379341
来源:稀土掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

2 zygote和SystemServer

在进入应用启动流程前,先简单回顾一下。

zygote是在系统启动后init进程fork出来的。

  • zygote有一个socket,用于接受消息,当有应用申请启动的时候,会通过socket通知zygote进程,其会fork自己来创建应用进程。
  • init过程中,zygoteforkSystemServer进程。

SystemServer是由zygote进程fork出来的第一个进程,其管理着很多重要服务,比如ActivityManagerServicePackageManagerServiceWindowManagerService

3 应用启动流程简述(记得补充)

从用户点击图标开始到应用创建再到第一个Activity启动

来源 https://www.cnblogs.com/anywherego/p/18233682

4 从点击图标到通知Zygote

4.1 Launcher

  • LauncherAndroid系统启动后,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,这里的launcherLauncher类,所以回到Launcher.java代码。

其中的startActivitySafely会继续往上调用

继承关系:LauncherStatefulActivityBaseDraggingActivityBaseActivityActivity

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 完成后,它会回调当前 ActivityonActivityResult 方法,并附带请求码(requestCode)以及结果数据。

关键点包括:

  • intent 参数是一个 Intent 对象,它包含了要启动的目标 Activity 的信息。
  • requestCode 是一个整型值,当目标 Activity 结束时会通过 onActivityResult 回调传递回来。这有助于识别哪个 Activity 返回了结果。
  • options 参数是可选的 Bundle 对象,可以用来指定 Activity 启动的一些额外选项。

如果当前 Activity 没有父 Activity (mParent == null),则会调用 Instrumentation 类的 execStartActivity 方法来启动新的 Activity。如果 requestCode 大于等于 0,则标记 mStartedActivitytrue,这样可以避免在 Activity 初始化期间的闪烁现象,直到收到启动的 Activity 的结果为止。

如果当前 Activity 有一个父 Activity,则会调用父 Activity 的 startActivityFromChild 方法来启动新的 Activity,同时传递 requestCodeoptions

4.3 Instrumentation.java

源码:/frameworks/base/core/java/android/app/Instrumentation.java

Instrumentation.javaexecStartActivity有两种实现。execStartActivity (带 UserHandle 参数) 方法允许开发者显式地指定用于启动 Activity 的用户。而未带UserHandle参数的方法会使用默认用户启动Activity

1
2
3
4
5
6
7
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的单例,所以这里的调用是LauncherServiceManager单例。

当应用启动的时候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方法通过ActivityStartControllerobtainStarter方法获取了ActivityStarter对象实例,并调用ActivityStarterexecute方法

4.6 ActivityStarter.java

源码位置/frameworks/base/services/core/java/com/android/server/wm/ActivityStarter.java

ActivityStarter中最终会调用RootWindowContainerresumeFocusedTasksTopActivities方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
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

RootWindowContainerWindowManagerService的主要组成部分之一,是一个管理窗口的容器。

resumeFocusedTasksTopActivities将会调用TaskTaskFragmentPause前台程序,为新的应用程序启动做准备。

源码位置:/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使用调用ActivityManagerInternalstartProcess方法

这里传入的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代码主要做了以下事情

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

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中会调用ZygoteConnectionprocessCommand

5.2 ZygoteConnection.java

这段代码是 Zygote 进程中的一个关键部分,用于处理来自客户端的命令,以启动新的应用程序进程。

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

  1. **调用 ****forkAndSpecialize****或forkSimpleApps**:
    1
    2
    3
    pid = Zygote.forkAndSpecialize(parsedArgs.mUid, parsedArgs.mGid, ..., parsedArgs.mAppDataDir);
    ...
    Runnable result = Zygote.forkSimpleApps(argBuffer, zygoteServer.getZygoteSocketFileDescriptor(), ..., parsedArgs.mNiceName);
    调用 forkAndSpecializeforkSimpleApps 方法来创建新的进程,并对其进行配置。
  2. 处理子进程和父进程
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    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方法

这里的HActivityThread的一个内置类

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

在实例化中调用的是InstrumentationnewApplication方法。

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

调用OnCreate函数。

至此应用启动的流程就算基本结束了。

7 小结

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