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

542 阅读4分钟

第一阶段启动中,构建了窗口层级,创建 Task 并保存到 TaskDisplayArea 下,创建 ActivityRecord 并保存到 Task 下。本文,透过现象看本质,来分析窗口层级构建的的框架是如何实现。

框架

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

// WindowContainer.java

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

    // parent 的数据结构 mChildren 保存 child
    mChildren.add(index, child);
    
    // child 关联 parent
    child.setParent(this);
}
// 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 层级和 native 层,而本质就是 native 层 surface 层级构建,包括创建 surface,挂载 surface,以及更新 surface layer。

创建并挂载 surface

// WindowContainer.java

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 刚创建之时,一般不涉及 surface position 更新
    updateSurfacePositionNonOrganized();
    
    // ...
}

首先通过一个 Builder 模式构建 SurfaceControl,在构建 SurfaceControl.Builder 时,还会指定 parent SurfaceControl。这样就完成了 native 层 surface 创建与挂载。

surface 刚创建的时候,应该是出于 hidden 状态。但是,除了 ActivityRecord 和 Task 以外,WMS 会让其他 WindowContainer 的 surface 在创建之时,就立即 show 出来。

WindowContainer surface 的 parent 是在构建 SurfaceControl.Builder 时指定的,一般就是 WindowContainer parent 的 surface,如下

// WindowContainer.java

Builder makeSurface() {
    final WindowContainer p = getParent();
    // 通过父WC 的 makeChildSurface() 来创建 SurfaceControl.Builder
    return p.makeChildSurface(this);
}    

Builder makeChildSurface(WindowContainer child) {

    // 继续递归调用父 WC 的 makeChildSurface() 来创建 SurfaceControl.Builder
    final WindowContainer p = getParent();
    return p.makeChildSurface(child)
            // 虽然不断递归调用,但是 child surface 的 parent 就是父 WC 的 surface
            .setParent(mSurfaceControl);
}    

而 SurfaceControl.Builder 最终是由 DisplayContent 创建的,如下

// 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);
}

更新 surface layer

窗口层级构建时,父 WindowContainer 使用一个列表 mChildren, 保存 child WindowContainer,然后会根据 child 在 mChildren 中的 index 来更新 surface layer,如下

// WindowContainer.java

void assignChildLayers() {
    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++);
    }
}

来看下 child WindowContainer 是如何更新自己 surface layer

// 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;
    }
}
// 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);
    }
}
// SurfaceFreezer.java

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

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

WindowContainer 更新 surface layer 的逻辑很简单,如果有 leash surface,那么就更新 leash surface layer,否则更新自己的 surface layer。

更新 layer 的条件

// TransitionController.java

boolean canAssignLayers(@NonNull WindowContainer wc) {

    // mBuildingFinishLayers 如果为 true,
    // 表示 finish transaction 正在对 DisplayContent 下所有 surface layer 进行更新
    // 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;
    }
    
    // Transition 处于任何状态下,都可以更新 WindowState surface layer
    // Transition 在执行中,除了 WindowState surface 以外,其他 WC 都不可以更新 surface layer
    // Transition 处于收集状态,只有 Task 不能更新 surface layer
    // 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()));
}

更新 surface layer 的条件,要分具体情况而定。

以本系列文章分析的案例来说,在第一阶段启动中,创建了 Transition 并让其进入收集状态,然后 Transition 收集了 Task 和 ActivityRecord。而 Task 保存到 TaskDisplayArea 时,无法更新 Task surface layer。

简单思考下,就可以明白其中缘由,因为执行动画时,Task surface 会被 reparent 到 leash surface 下,同时会也更新 layer。因此,没有必要在层级构建时来更新 Task layer。

问题

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

  1. ActivityRecord 和 Task 的 surface,在创建之时,是出于 hidden 状态的。那么,它们的 surface 是什么时候显示的呢?
  2. Task 保存到 TaskDisplayArea 时,是无法更新其 surface layer。那么,它的 surface layer 是何时更新的呢?

随着本系列文章逐渐揭开动画流程,这两个问题的答案,自然会揭晓。