App 启动过程和Activity 启动过程

555 阅读7分钟

源码基于 SDK 30 ,即 Android 11

我们为什么需要阅读学习 Framework 源码?

首先阅读学习 Framework 源码能解决在编码过程中只知道要这样写,而不知道为什么要这样写的问题。知其然,不知其所以然,最容易造成的情况,就是在出现问题的时候,因为不知道编写代码背后的执行逻辑,而导致没有解决思路,只能花时间在百度中各种关键字大海捞针。

其次就是要搬出 Linux 作者那句名言了,Read the fucking code!! 学习优秀的源码,是提升编码能力的一条好路子。

还有一个问题,为什么需要了解 App 启动过程?另一个 Activity 那么重要的东西就不说了。

最直接的就是,现在许多 App 需要进行启动时间优化,导致我们需要详细的了解 App 启动流程和,知道哪些地方可以进行优化,从而才能给出优化方案。

好了,自己对自己说的废话讲了一堆可以停了。

我将 App 启动过程分为四个流程:

  1. 启动应用主 Activity 的创建流程。

  2. 应用运行所需要的进程,创建流程。

  3. 应用的初始化和 Application 对象的创建和绑定过程。

  4. 启动主 Activity 流程。

注:没有大段源码,源码可以直接 github 查看,里面包含我梳理留下的注释过程。 github.com/bukeCN/Simp…

如何启动一个 App

阅读源码,上来就是精读,不是阅读源码的好方法,应该先快速的将整个流程梳理一遍,记录问题,然后回过头来对重点、问题进行再次阅读和思考。

从 PackageManager 获取应用信息

Launch 桌面启动应用,是利用 PackageManager 获取应用上安装的应用,利用该机制可以获取到 App 的包名和启动Activity 的全限定类名,组装成 ComponentName 就可以使用 startActivity() 去启动 App 啦。都是模板代码,可以参考代码:

// 获取安装的 App 信息
Intent intent = new Intent(Intent.ACTION_MAIN, null);
intent.addCategory(Intent.CATEGORY_LAUNCHER);
List<ResolveInfo> apps = getPackageManager().queryIntentActivities(intent, 0);


ResolveInfo app = apps.get(new Random().nextInt(apps.size()-1));
// 获取该应用的包名
String packageName = app.activityInfo.packageName;
// 获取该应用的主 Activity 全限定类名
String className = app.activityInfo.name;

// 利用包名和类名启动 App
ComponentName component = new ComponentName(packageName, className);
Intent startIntent = new Intent();
startIntent.setComponent(component);
startActivity(startIntent);

通过抛出异常找到调用链入口

刚阅读代码的时候,我时常找不到源码的一个入口,后来看到别人的分享,主动抛出异常,就可以得到函数调用栈,这样就能找分析源码的入口了,App 启动的时候我就用了一下,从 Activity.startActivityForResult() 入手。

// 用
Intent startIntent = new Intent();
startActivity(startIntent);
// 异常
    android.content.ActivityNotFoundException: No Activity found to handle Intent {  }
        at android.app.Instrumentation.checkStartActivityResult(Instrumentation.java:2120)
        at android.app.Instrumentation.execStartActivity(Instrumentation.java:1746)
        at android.app.Activity.startActivityForResult(Activity.java:5368)
        at androidx.fragment.app.FragmentActivity.startActivityForResult(FragmentActivity.java:676)
        at android.app.Activity.startActivityForResult(Activity.java:5304)
        at androidx.fragment.app.FragmentActivity.startActivityForResult(FragmentActivity.java:663)
        at android.app.Activity.startActivity(Activity.java:5751)
        at android.app.Activity.startActivity(Activity.java:5719) 

应用主 Activity 的创建流程

  • Activity.startActivityForResult()

  • Instrumentation.execStartActivity() 这一步进行了 Binder IPC 调用,调用 ActivityTaskManagerService 的 startActivityAsUser() 函数。

  • ActivityTaskManagerService.startActivityAsUser() 这里会创建 ActivityStarter ,负责启动 Activity。

  • ActivityStarter.execute()

  • ActivityStarter.executeRequest() 这里有个重要的步骤,创建启动目标 App 的主 Activity 在 AMS 中的结构 ActivityRecord。

  • ActivityStarter.startActivityUnchecked()

  • ActivityStarter.startActivityInner() 这里有个重要步骤,会创建 ActivityStack,但有个问题是这里竟然使用了 RootWindowContainer 来进行 ActivityStack 的创建。

  • RootWindowContainer.resumeFocusedStacksTopActivities()

  • ActivityStack.resumeTopActivityUncheckedLocked()

  • ActivityStack.resumeTopActivityInnerLocked()** 这里会暂停 pause 上一个显示的 Activity,也就是发起启动目标 Activity 的源 Activity。**

    这里是一个分水岭,到了这一步 App 启动前Activity的准备工作已经完成,Activity 也已经添加到了对应的 ActivityStack 中,下一步将出现是创建 Activity 需要的进程,还是直接启动 Activity 的分支。

应用运行所需要的进程,创建流程

  • ActivityStackSupervisor.startSpecificActivity() 这里出现分支,如果需要启动的 Activity 的需要的进程存在,则走 Activity 启动流程,否则走创建 App 进程流程。

  • ActivityTaskManagerService.startProcessAsync()

  • ActivityManagerService.startProcess() > startProcessLocked() 这里会创建 App 进程在 AMS 中的表述实例 ProcessRecord。

  • ProcessList.startProcessLocked() > startProcessLocked()

  • ProcessList.startProcess()

  • Process.start() 这里就是发送 Soket 请求,通知 Zygote 进程 fork() 子进程,然后通过反射调用 ActivityThread.main() 函数!开始 App 进程流程啦!

应用的初始化和 Application 对象的创建和绑定过程

整个过程的逻辑是,App 进程这边现在 ActivityThread 对象中创建 ApplicationThread 这个 Bidner 对象,然后和 WMS 进行通信,调用 WMS.bindApplication() 绑定 Application 的流程,在流程中 WMS 会通过 Binder 的死亡通知机制,监听 Application 的死亡(即App 的结束),重要的是将对应 App 初始化的资源通过 Binder 传递给对应的应用进程。最后通过 Binder 调用 ActivityThread 内部类 ApplicationThread.bindApplication() 函数开始初始化流程。

  • ActivityThread.main()

  • ActivityThread.attach()

  • AMS.attachApplication()

  • ApplicationThread.bindApplication() 准备 AppBindData 对象实例,通过 Handler 给主线程发送消息,交给应用主线程处理。

    AMS 的利用 Binder IPC 调用应用进程的函数是同步调用,因此会等待应用程序进程执行完毕。

  • ActivityThread.handleBindApplication() 这里会对 Java 虚拟机进行一些设置、初始化 LoadApk 实例、创建 ApplicationContext、通过反射创建 Application 实例并会掉漆 attach() / onCreate() 生命周期函数。

在AMS.attachApplication()

应用主 Activity 启动过程

AMS 在 attachApplication() 函数中调用并等待应用进程执行完毕,然后会进行以下三个动作:

  1. 最顶层的 Activity (在启动 Activity 准备工作已完成)是否需要在该进程中运行,如果是就启动显示该 Activity。

  2. 查找需要在该进程中运行的服务。

  3. 查找需要在该进程中执行的广播。

好了,我们就看启动第一个动作。

  • ActivityTaskManager.LocalService.attachApplication() 这里会到 ATMS 中进行。

  • RootWindowContainer.attachApplication()

  • RootWindowContainer.startActivityForAttachedApplicationIfNeeded() 调用这个函数使用了动态创建 Labda 表达式的方法,首次见到,学习了。

  • ActivityStackSupervisor.realStartActivityLocked() 叮!最后调用了熟悉的函数来启动应用主 Activity!

到此,就要进入 Activity 的一个启动过程,整个 Activity 的启动过程是通过一个事务来执行的,通过给事务执行添加回调执行 Item 和生命周期状态执行 Item 来完成整个 Activity 的创建。

  • ActivityStackSupervisor.realStartActivityLocked()

    - 创建事务 ClientTransaction

    - 添加事务回调 Item > LaunchActivityItem     该 Item 中,包含 Activity 创建流程。

    - 添加生命周期执行 Iiem > ResumeActivityItem

  • ClientLifecycleManager.scheduleTransaction() 执行事务

  • ClientTransaction.schedule() 通过 Binder IPC 调用,ActivityThread 中的 ApplicationThread 对应的函数。

  • ActivityThread.ApplicationThread.scheduleTransaction()

  • ActivityThread.scheduleTransaction()

  • ClientRransactionHander.scheduleTransaction() 发送 Handler 消息 EXECUTE_TRANSACTION,转到主线程处理。代码转到 ActivityThread 的 H 中。

  • TransactionExecutor.execute() 执行事务。

  • LaunchActivityItem.execute() 这里会创建 ActivityClientRecord 实例,是 Activity 在应用端的表述,对应 AMS 中的 ActivityRecord。

    - ActivityThread.handleLaunchActivity()

    - ActivityThread.performLaunchActivity()

  • TransactionExecutor.cycleToPath() 通过前面传入的 ResumeActivityItem 表述的需要执行 Activity.onResume() 生命周期函数为终点,以上一步 LaunchActivityItem 执行过的生命周期函数为开始,计算所需要执行的生命周期路径,然后通过循环的方式调用执行。
    private void cycleToPath(ActivityClientRecord r, int finish, boolean excludeLastState,
            android.app.servertransaction.ClientTransaction transaction) {
        // 获取开始的生命周期开始
        final int start = r.getLifecycleState();
        // 计算路径
        final IntArray path = mHelper.getLifecyclePath(start, finish, excludeLastState);
        // 循环执行后续的生命周期
        performLifecycleSequence(r, path, transaction);
    }
  • TransactionExecutor.performLifecycleSequence() 按照路径执行后续生命周期
    private void performLifecycleSequence(ActivityClientRecord r, IntArray path,
            android.app.servertransaction.ClientTransaction transaction) {
        final int size = path.size();
        // 对生命周期路径进行遍历,循环执行生命周期函数
        for (int i = 0, state; i < size; i++) {
            // 获取路径上的生命周期节点
            state = path.get(i);
            // 执行对应的生命周期
            switch (state) {
                case ON_CREATE:
                    // onCreate()
                    mTransactionHandler.handleLaunchActivity(r, mPendingActions,
                            null /* customIntent */);
                    break;
                case ON_START:
                    mTransactionHandler.handleStartActivity(r.token, mPendingActions);
                    break;
                case ON_RESUME:
                    // mTransactionHandler 为 ActivityThread
                    mTransactionHandler.handleResumeActivity(r.token, false /* finalStateRequest */,
                            r.isForward, "LIFECYCLER_RESUME_ACTIVITY");
                    break;
               ...
               ...
        }
    }

小结

到此,整个 App 的启动流程也是梳理了一遍,但这个只是一个函数调用过程的大致逻辑,其中还需非常多的关键细节需要我们去了解,如:整个系统的资源加载过程?重要的 LoadApk 的实例化?

同时,整个流程中应用程序进程和系统服务 AMS / WMS 之间的跨进程通信,都是基于 Binder 机制,如果对 Binder 机制没有一个很好的理解,可能在阅读源码的过程中会出现很多疑问,造成误解。因此十分推荐在阅读 AMS 和 WMS 相关源码之前,将 Binder IPC 机制搞清楚。

在启动任务的第一阶段 Activity 的建立过程和第四阶段的启动过程,都有 RootWindowContainer 的参与,在翻看的之前版本 SDK 的源码之后,我的理解是 Google 正在一步一步的将 AMS 和 WMS 之间的管理进行优化整合。