应用冷启动流程一:桌面 Activity 调用到系统进程

308 阅读4分钟

本文已参与[新人创作礼]活动,一起开启掘金之路。

之前也写过一些应用冷启动的内容,对着源码走了一遍流程(Activity 启动流程和 UML 时序图)。但总感觉效果不好,源码扯的有点多,对理解 AMS 却没有太大帮助,所以想再梳理一下,源码少点,流程也粗略些,在个别细节处多停留,记录一下自己当时的困惑。 本来想一篇文章说完的,最后发现东西还是有点多了,自身实力搞不定,所以还是拆开,这一篇就当作系列一:主要看看桌面 Activity 是怎么调用到系统进程的

聊应用冷启动,还是以从桌面点击应用图标冷启动为例。主要过程包括:

  • 桌面进程向系统发起启动另一个应用中的 Activity 的请求;
  • 系统对发送过来的 intent 参数进行解析,选择启动模式,并校验启动权限、参数合法性。如果校验通过,就通知桌面 pause 当前的 Activity;
  • 桌面收到系统暂停当前 Activity 的要求,执行相关过程,并告知系统已暂停;
  • 继续执行目标 Activity 启动的过程,首先进行任务栈相关的处理。因为是冷启动,目标 Activity 所在进程不存在,所以首先要通过 AMS 创建 app2 进程,绑定资源和上下文环境;
  • 创建并启动目标 Activity。

大概流程就是 Activity--->Instrumentation-->ATMS,我们分步看看。

1 Activity 组合了一个 Instrumentation 对象

Activity.java 中,有一个 Instrumentation 的类对象。这个东西翻译为仪表盘,作用是监视 app 进程与系统间的交互。每个 Activity 都持有一个 Instrumentation 对象的引用,但一个应用进程只有一个 Instrumentation 对象,这个特性是如何做到的我们暂时不深入研究。下图第一行的注释说到 mInstrumentation 的初始化时机是在构造完成但 onCreate 方法回调之前。

image.png

我们在启动 Activity 的过程中会在 startActivityForResult() 方法中执行 mInstrumentation.execStartActivity,很自然的到了 Instrumentation.java 中。

5399      public void startActivityForResult(@RequiresPermission Intent intent, int requestCode,
5400              @Nullable Bundle options) {
5401          if (mParent == null) {
5402              options = transferSpringboardActivityOptions(options);
5403              Instrumentation.ActivityResult ar =
5404                  mInstrumentation.execStartActivity(
5405                      this, mMainThread.getApplicationThread(), mToken, this,
5406                      intent, requestCode, options);

留意一下:Instrumentation.ActivityResult,ActivityResult是 Instrumentation 的静态内部类,用来描述 Activity 的执行结果,返回给原 Activity。

1629      /**
1630       * Description of a Activity execution result to return to the original
1631       * activity.
1632       */

2 Instrumentation 通过 AIDL 调用到 ATMS

下面就一起看看这个工具类Instrumentation.java,官方对这个类作用的介绍:监视应用与系统间的所有交互

image.png 接着上文的分析,看看 execStartActivity 方法。


1709      @UnsupportedAppUsage
1710      public ActivityResult execStartActivity(
1711              Context who, IBinder contextThread, IBinder token, Activity target,
1712              Intent intent, int requestCode, Bundle options) {

1743              int result = ActivityTaskManager.getService().startActivity(whoThread,
1744                      who.getOpPackageName(), who.getAttributionTag(), intent,
1745                      intent.resolveTypeIfNeeded(who.getContentResolver()), token,
1746                      target != null ? target.mEmbeddedID : null, requestCode, 0, null, options);

显然重点在 ActivityTaskManager.getService()上了,一起看看吧。

image.png

这是一个获取 binder 服务的标准动作啊,现在我们看看 ACTIVITY_TASK_SERVICE 对应哪个类,通过搜索确定到了 ActivityTaskManagerService.java。其实代码跟到这,我们只需要明白一件事:Instrumentation 是通过 AIDL 获取到了 ActivityTaskManagerService 的对象,实现了跨进程调用 startActivity,而 ActivityTaskManager 封装了 binder 服务的获取。至于 AIDL 服务获取的流程,有兴趣的可以看下这篇文章。AIDL 服务的发布 publishBinderService 和 获取 getService

image.png

桌面 Activity 请求启动 Activity 的关键流程说的差不多了。最后再简单看下 execStartActivity 的参数。

1685       * @param who The Context from which the activity is being started.
1686       * @param contextThread The main thread of the Context from which the activity
1687       *                      is being started.
1688       * @param token Internal token identifying to the system who is starting
1689       *              the activity; may be null.
1690       * @param target Which activity is performing the start (and thus receiving
1691       *               any result); may be null if this call is not being made
1692       *               from an activity.
1693       * @param intent The actual Intent to start.
1694       * @param requestCode Identifier for this request's result; less than zero
1695       *                    if the caller is not expecting a result.
1696       * @param options Addition options.

这是 Activity.java 调用时的传参,和上面的参数对照着理解。

image.png

  • who:发起请求时的 Context,对应 Activity.java 中的 this
  • contextThread:who 对应的主线程,mMainThread.getApplication() 获得,mMainThread 是 ActivityThread 的对象
  • token:一个 IBinder 类型对象
  • target:当前发起请求的 Activity,这里也对应 this。当不是从 Activity 发起启动请求时,这个参数是 null。 后面会接着当前流程,看一下应用冷启动过程中,ATMS 中的流程