Activity冷启动

498 阅读5分钟

基于Android R版本分析

参考:

Android11 WMS 之 AppTransition

android R版本AppTransition动效源码分析

Activity Transit Type

TRANSIT Typevaluedesc
TRANSIT_UNSET-1初始值,未设置过渡动画
TRANSIT_NONE0没有过渡动画
TRANSIT_ACTIVITY_OPEN6新Activity的窗口正在同一任务中的现有窗口之上打开
TRANSIT_ACTIVITY_CLOSE7最顶层Activity的窗口正在关闭以显示同一任务中的前一个Activity
TRANSIT_TASK_OPEN8新Activity的窗口正在另一个Activity所属的Task的现有窗口之上打开
TRANSIT_TASK_CLOSE9最顶层Activity的一个窗口正在关闭,以显示不同任务中的前一个Activity
TRANSIT_TASK_TO_FRONT10将Task移至最顶端,即现有Task的窗口显示在另一个Activity所属Task的顶部
TRANSIT_TASK_TO_BACK11将Task移至最低端,即现有Task的窗口被放置在所有其他Task下方
TRANSIT_WALLPAPER_CLOSE12新Activity没有Wallpaper的窗口会在有Wallpaper的窗口之上打开,从而有效地关闭Wallpaper
TRANSIT_WALLPAPER_OPEN13新Activity带有Wallpaper的窗口会在没有Wallpaper的窗口上打开,从而有效地打开Wallpaper
TRANSIT_WALLPAPER_INTRA_OPEN14新Activity的一个窗口在现有Activity的顶部打开,并且两者都在Wallpaper的顶部
TRANSIT_WALLPAPER_INTRA_CLOSE15最顶部Activity的窗口正在关闭以显示之前的Activity,并且两者都位于Wallpaper的顶部
TRANSIT_TASK_OPEN_BEHIND16新Task中的一个窗口在另一个Activity的Task中的现有窗口后面打开 新窗口将短暂显示,然后消失
TRANSIT_ACTIVITY_RELAUNCH18正在重新启动Activity(例如,由于配置更改)
TRANSIT_DOCK_TASK_FROM_RECENTS19正在对接最近的Task
TRANSIT_KEYGUARD_GOING_AWAY20Keyguard 即将消失
TRANSIT_KEYGUARD_GOING_AWAY_ON_WALLPAPER21Keyguard 将消失,显示背后请求Wallpaper的Activity
TRANSIT_KEYGUARD_OCCLUDE22Keyguard 被遮挡
TRANSIT_KEYGUARD_UNOCCLUDE23Keyguard 未被遮挡
TRANSIT_TRANSLUCENT_ACTIVITY_OPEN24正在打开一个半透明的Activity
TRANSIT_TRANSLUCENT_ACTIVITY_CLOSE25一个半透明的Activity正在关闭
TRANSIT_CRASHING_ACTIVITY_CLOSE26正在关闭崩溃的Activity
TRANSIT_TASK_CHANGE_WINDOWING_MODE27一项Task正在改变窗口模式
TRANSIT_SHOW_SINGLE_TASK_DISPLAY28由于第一个Activity已启动或正在打开,因此正在显示只能包含一个Task的显示

APP 冷启动

App冷启动.png

我们知道,在launcher界面冷启动一个应用程序,需要涉及三个进程:

  • launcher进程:负责与SystemServer进程通信,通知拉起目标app进程,同时处理Pause逻辑;
  • systemserver进程:负责fork目标进程,同时需要等待launcher进程和目标app进程的执行结果,待都准备就绪之后,真正启动目标进程;
  • 目标app进程:接收System进程的启动通知,进行初始化,等待SystemServer通知可以正式启动;

Launcher冷启动Task.png

该图中包含了热启动的逻辑,我们只需要关注冷启动逻辑即可,但其实也是类同的,在一部分逻辑上,冷启动和热启动的执行逻辑相同

上述的时序图,对应的就是整体的目标app冷启动的调用栈逻辑;

我们针对两个调用逻辑进行分析:

  • TargetStack:startActivityLocked

    在这个过程中,会对Starting Activity的Task准备AppTransition,在后续目标进程启动的过程中,会执行execute AppTransition;

  • RootWindowContainer:resumeFocusedStackTopActivities

    • 将之前的Activity进行PAUSED;
    • 将目标Activity(即将需要显示的Activity)设置为resume状态;

TargetStack # startActivityLocked

TargetStack&startActivityLocked.png

在这个过程中,其实核心逻辑有两部分:

  • prepareAppTransition:这个过程本质就是调用AppTransition的setAppTransition()方法,将对应计算出来的tranist和flag保存到AppTransition以供后续使用;
  • startingWindow:这个是Android R引入的一个新的概念,是用于处理在应用进程刚启动时,大概率会出现的1-2s的空白界面的优化,使用特定的画面遮挡这一块显示区域,对应的概念为Splash Screen

activityPaused

同理,也包含热启动的逻辑

在调用完目前TargetTask执行prepareAppTransition()方法之后,就会继续对原Activity进行Pause操作;

核心逻辑其实就是ActivityStack的completePausedLocked(),其中包含了两个部分:

  • Pausing Activity的处理
  • Resume Activity的处理

我们分析一下Pausing Activity处理逻辑;

Pausing Activity

activityPaused.png

基本上针对PausingActivity的处理,在launcher冷启动的场景下,其实就是将mPausingActivity的state设置为PAUSED,然后将mPausingActivity置空即可;

resumeNext # resumeFocusedStacksTopActivities

resumeFocusedStacksTopActivities.png

我们关注冷启动的流程,我们可以看到,在 !next.attachedToProcess的分支中,我们会调用ActivityStackSupervisor的startSpecificActivity()方法,在这个方法中,有一个核心逻辑:

void startSpecificActivity(ActivityRecord r, boolean andResume, boolean checkConfig) {
    // Is this activity's application already running?
    final WindowProcessController wpc =
            mService.getProcessController(r.processName, r.info.applicationInfo.uid);
​
    boolean knownToBeDead = false;
    // 这个过程会判断wpc是否为空,即判断目标进程的ProcessRecord实例是否为空
    // 如果为空,这不会进入该分支执行realStartActivityLocked()方法
    if (wpc != null && wpc.hasThread()) {
        try {
            realStartActivityLocked(r, wpc, andResume, checkConfig);
            return;
        } catch (RemoteException e) {
            Slog.w(TAG, "Exception when starting activity "
                    + r.intent.getComponent().flattenToShortString(), e);
        }
​
        // If a dead object exception was thrown -- fall through to
        // restart the application.
        knownToBeDead = true;
    }
​
    r.notifyUnknownVisibilityLaunchedForKeyguardTransition();
​
    final boolean isTop = andResume && r.isTopRunningActivity();
    mService.startProcessAsync(r, knownToBeDead, isTop, isTop ? "top-activity" : "activity");
}

attachApplication

attachApplication.png

在这个过程中,会获取目标进程的ProcessRecord实例,然后从中获取对应的ProcessRecord的WindowProcessController实例;

WindowProcessController用于和AMS中的ProcessRecord进行通讯,当ProcessRecord中对应用进程作出调整后,通过WindowProcessController和WM进行通信;

ATMS会获取到目标ProcessRecord的WindowProcessController实例,传给对应的WindowContainer,即对应的ActivityRecord,推动ActivityRecord执行对应的逻辑,最终就是调用RootWindowContainer的realStartActivityLocked()进行真正的Activity启动;

我们需要注意的是,Application的启动和Activity的启动,不是同一时刻,可见简单的理解为Application为进程,只有当进程启动之后,Activity才能基于该基础之上机型启动和创建;

realStartActivityLocked

realStartActivityLocked.png

这个过程,针对冷启动,比较简单,会在realStartActivityLocked()方法中执行minimalResumeActivityLocked()方法,这个过程中就会调用ActivityRecord的completeResumeLocked,进而执行executeAppTransition()方法;

performSurfacePlacement

performSurfacePlacement.png

真正进行动画绘制的逻辑,在goodTogo()模块;

这个模块中,会判断startingWindow(Splash Screen)和对应的目标ActivityRecord的窗口动画是否绘制完成,完成之后,就可以进行show显示;

而这一块的动画本质,其实还是ValueAnimator的使用,但是这个里面涉及到了远程动画和本地动画的区别;