Android V app 冷启动(2) 窗口层级的构建

根据 Android V app 冷启动 (1) Activity生命周期 分析,在第一阶段启动中,会构建窗口层级。但是,我打算以授人以渔的方式来讲解,即分析框架,而不是分析具体的流程。

框架

在窗口层级构建时,parent 都是通过基类的 WindowContainer#addChild() 来保存 child

java 复制代码
// WindowContainer.java

// parent 保存 child
void addChild(E child, int index) {
    // ...

    // parent 的数据结构 mChildren 保存 child
    mChildren.add(index, child);
    
    // child 关联 parent
    child.setParent(this);
}
java 复制代码
// WindowContainer.java

// child 关联 parent
final protected void setParent(WindowContainer<WindowContainer> parent) {
    final WindowContainer oldParent = mParent;

    // 1. child 保存 parent
    mParent = parent;

    // ...

    if (!mReparenting) {

        // 处理 sync state
        onSyncReparent(oldParent, mParent);

        if (mParent != null && mParent.mDisplayContent != null
                && mDisplayContent != mParent.mDisplayContent) {
            // 保存 DisplayContent
            onDisplayChanged(mParent.mDisplayContent);
        }

        // 2. child 处理 parent 改变
        onParentChanged(mParent, oldParent);
    }
}    


void onParentChanged(ConfigurationContainer newParent, ConfigurationContainer oldParent) {
    // 利用新 parent 的 full config,更新 child 的 config
    super.onParentChanged(newParent, oldParent);

    if (mParent == null) {
        return;
    }

    if (mSurfaceControl == null) {
        // 3. 既然有了 parent,那么就创建 child 的 surface,并挂在 parent surface 之下
        createSurfaceControl(false /*force*/);
    } else {
        // ...
    }

    // 4. 通过 parent 重新调整 children layer
    mParent.assignChildLayers();
}

从这里可以看出,窗口层级构建,包括 WMS 层和 surface 层。在 WMS 层,是通过数据结构相互关联,而在 surface 层,需要 child 窗口 surface,并挂载到 parent 之下。最后,还通过 parent 重新调整 children 窗口的 layer。

创建并挂载 child surface

java 复制代码
// WindowContainer.java

// child 创建 surface

void createSurfaceControl(boolean force) {
    // makeSurface() 是创建一个 SurfaceControl.Builder
    setInitialSurfaceControlProperties(makeSurface());
}

void setInitialSurfaceControlProperties(Builder b) {
    // 用 mSurfaceControl 保存创建的 surface
    setSurfaceControl(b.setCallsite("WindowContainer.setInitialSurfaceControlProperties").build());
    
    // 只有 ActivityRecord 和 Task 的 surface,不需要在创建时立即 show 出来
    if (showSurfaceOnCreation()) { 
        getSyncTransaction().show(mSurfaceControl);
    }
    
    // 更新 surface position
    updateSurfacePositionNonOrganized();
    
    // ...
}

child surface 在创建完成后,除了 ActivityRecord 和 Task 以外,都是立即通过 sync transaction/pending transaction show 出来。

也就是说,ActivityRecord 和 Task 的 surface 在刚创建时,是不可见的。这与 Transition 动画有关,这里暂时不表。

makeSurface() 在创建 SurfaceControl.Builder 的同时,还会为 child surface 设置 parent surface,如下

java 复制代码
// WindowContainer.java

Builder makeSurface() {
    final WindowContainer p = getParent();
    // 通过 parent 来构建 SurfaceControl.Builder
    return p.makeChildSurface(this);
}    

Builder makeChildSurface(WindowContainer child) {

    // parent 也递归调用自己 parent 来构建 Builder
    final WindowContainer p = getParent();
    return p.makeChildSurface(child)
            // 注意,这里指定了 child surface 的 parent surface
            // 其实就是 child 的 parent 的 surface
            .setParent(mSurfaceControl);
}    

child 的 SurfaceControl.Builder 是通过 parent 进行构建,并且还把 parent surface 指定为 child surface 的 parent。

经过层层递归,最终由 DisplayContent 来创建 child 的 SurfaceControl.Builder

java 复制代码
// DisplayContent.java

SurfaceControl.Builder makeChildSurface(WindowContainer child) {
    SurfaceSession s = child != null ? child.getSession() : getSession();

    final SurfaceControl.Builder b = mWmService.makeSurfaceBuilder(s)
                                                .setContainerLayer();
    if (child == null) {
        return b;
    }
    return b.setName(child.getName())
            .setParent(mSurfaceControl);
}

parent 调整 children layer

当窗口层级构建完成后,parent 会调整所有 children layer,包括 WMS layer 以及 surface layer

java 复制代码
// WindowContainer.java

void assignChildLayers() {
    // 注意,layer 的调整,是通过 sync transaction 或 pending transaction 执行的
    assignChildLayers(getSyncTransaction());
    scheduleAnimation();
}

void assignChildLayers(Transaction t) {
    int layer = 0;

    
    for (int j = 0; j < mChildren.size(); ++j) {
        final WindowContainer wc = mChildren.get(j);
        // 递归调用,让 child 更新自己 children layer
        wc.assignChildLayers(t);
        
        // 1.优先给不需要提升z-order的 child 更新 layer
        if (!wc.needsZBoost()) {
            wc.assignLayer(t, layer++);
        }
    }
    
    
    for (int j = 0; j < mChildren.size(); ++j) {
        final WindowContainer wc = mChildren.get(j);
        // 2.然后在给需要提升z-order的 child 更新 layer
        if (wc.needsZBoost()) {
            wc.assignLayer(t, layer++);
        }
    }
    if (mOverlayHost != null) {
        mOverlayHost.setLayer(t, layer++);
    }
}

parent 调整 children layer 的原理是,遍历 mChildren,依次给 child 更新 layer(从 0 开始)。

来看下具体更新 layer 是如何实现的

java 复制代码
// WindowContainer.java

void assignLayer(Transaction t, int layer) {

    // 排除不能更新 layer 的情况
    // 例如,动画在执行的时候,不能更新 Task / ActivityRecord 的 layer,
    // 因为它们的 surface 可能正在被动画操纵
    if (!mTransitionController.canAssignLayers(this)) return;
    
    // layer 有改变
    final boolean changed = layer != mLastLayer || mLastRelativeToLayer != null;
    
    if (mSurfaceControl != null && changed) {
        // 设置 layer
        setLayer(t, layer);
        
        // 保存最新 layer
        mLastLayer = layer;
        mLastRelativeToLayer = null;
    }
}

这里先不谈不能更新 layer 的情况,只要 layer 改变,就需要重新设置 layer

java 复制代码
// WindowContainer.java

protected void setLayer(Transaction t, int layer) {
    if (mSurfaceFreezer.hasLeash()) {
        // When the freezer has created animation leash parent for the window, set the layer
        // there instead.
        mSurfaceFreezer.setLayer(t, layer);
    } else {
        // Route through surface animator to accommodate that our surface control might be
        // attached to the leash, and leash is attached to parent container.
        mSurfaceAnimator.setLayer(t, layer);
    }
}
java 复制代码
// SurfaceFreezer.java

void setLayer(SurfaceControl.Transaction t, int layer) {
    if (mLeash != null) {
        // 给 leash 设置 layer
        t.setLayer(mLeash, layer);
    }
}
java 复制代码
// SurfaceAnimator.java

void setLayer(Transaction t, int layer) {
    // 有 leash,就给 leash 设置 layer,否则就给自己 surface 设置 layer
    t.setLayer(mLeash != null ? mLeash : mAnimatable.getSurfaceControl(), layer);
}

这里的代码,我个人认为比较晦涩,它的意思其实很简单,如果 WindowContainer 有动画在执行,就给动画的 leash 设置 layer,否则就给 WindowContainer 自己的 surface 设置 layer。

更新 layer 的条件

这里,针对 app 冷启动的情况,来看下窗口层级构建时,检测是否能设置 layer 的方法

java 复制代码
// TransitionController.java

boolean canAssignLayers(@NonNull WindowContainer wc) {
    // Don't build window state into finish transaction in case another window is added or
    // removed during transition playing.
    if (mBuildingFinishLayers) {
        return wc.asWindowState() == null;
    }
    
    // Always allow WindowState to assign layers since it won't affect transition.
    return wc.asWindowState() != null || (!isPlaying()
            // Don't assign task while collecting.
            && !(wc.asTask() != null && isCollecting()));
}

根据 Android V app 冷启动 (1) Activity生命周期 分析,在第一阶段启动中,首先创建不 Transition 并进入收集状态,然后收集了要启动的 ActivityRecord。

那么,系统当前有一个处于收集状态的 Transition。因此,窗口层级构建中,把 Task 保存到 TaskDisplayArea 时,是不能为 Task 更新 layer 的。而把 ActivityRecord 保存到 Task 时,是可以为 ActivityRecord 更新 layer 的。

问题

在框架的分析中,其实遗留了两个问题

  1. ActivityRecord 和 Task 的 surface,在创建的时候,是隐藏的。那么,它们的 surface 是什么时候显示的呢?
  2. 窗口层级构建时的 layer 更新,没有为 Task 更新 layer。那么 Task 的 layer 是何时更新的呢?

然而,此时还不能回答这两个问题,因此它们与窗口的刷新,以及 Transition 动画紧密相关。在后续的文章中,我会分析到这两个问题。

相关推荐
张小潇38 分钟前
AOSP15 Input专题InputDispatcher源码分析
android
TT_Close40 分钟前
【Flutter×鸿蒙】debug 包也要签名,这点和 Android 差远了
android·flutter·harmonyos
Kapaseker2 小时前
2026年,我们还该不该学编程?
android·kotlin
雨白18 小时前
Android 快捷方式实战指南:静态、动态与固定快捷方式详解
android
hqk18 小时前
鸿蒙项目实战:手把手带你实现 WanAndroid 布局与交互
android·前端·harmonyos
LING19 小时前
RN容器启动优化实践
android·react native
恋猫de小郭21 小时前
Flutter 发布官方 Skills ,Flutter 在 AI 领域再添一助力
android·前端·flutter
Kapaseker1 天前
一杯美式搞懂 Any、Unit、Nothing
android·kotlin
黄林晴1 天前
你的 Android App 还没接 AI?Gemini API 接入全攻略
android
恋猫de小郭2 天前
2026 Flutter VS React Native ,同时在 AI 时代 VS Native 开发,你没见过的版本
android·前端·flutter