Android V app 冷启动(2) 构建窗口层级树 & layer层级树

618 阅读4分钟

在 Activity 启动的第一阶段中,创建了 Task 并保存到 TaskDisplayArea 下,然后创建了 ActivityRecord 并保存到 Task 下。

这一过程,不仅构建了 WMS 的窗口层级树,还构建了 SF 的 Layer 层级树。本文来分析其实现原理,因为它并不是你看起来的那么简单。

构建 WMS 窗口层级树

WMS 窗口层级树构建,是通过 WindowContainer#addChild() 父容器保存子容器来实现的

// WindowContainer.java

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

    // WindowContainer#mChildren 类型为ArrayList
    // 它用于保存所有的子容器
    mChildren.add(index, child);
    
    // 子容器使用 WindowContainer#mParent 保存父容器
    child.setParent(this);
}

在 WMS 层面,分别使用 WindowContainer 的成员变量 mChildren 和 parent ,保存子容器和父容器。

但是,此时并没有构建 SF Layer 层级树。而这一过程,其实是在子容器保存父容器的时候实现的,如下

// WindowContainer.java

final protected void setParent(WindowContainer<WindowContainer> parent) {
    final WindowContainer oldParent = mParent;

    // 保存父容器
    mParent = parent;

    // ...

    if (!mReparenting) {

        // ...

        // 处理父容器改变
        onParentChanged(mParent, oldParent);
    }
}    


void onParentChanged(ConfigurationContainer newParent, ConfigurationContainer oldParent) {
    // ...
    
    if (mSurfaceControl == null) {
        // 1.创建 surface,即 SF Layer,并挂载到父容器 surface 之下
        createSurfaceControl(false /*force*/);
    } else {
        // ...
    }

    // 2. 利用父容器更新子容器的层级,也更新 SF Layer 层级
    mParent.assignChildLayers();
}

构建 SF Layer 层级树

构建 SF Layer 层级树时,首先是子容器创建自己 Surface

// WindowContainer.java

void createSurfaceControl(boolean force) {
    setInitialSurfaceControlProperties(makeSurface());
}

makeSurface() 创建的是一个 Surface.Builder 对象,它用于构建 Surface,如下

// WindowContainer.java

Builder makeSurface() {
    final WindowContainer p = getParent();
    return p.makeChildSurface(this);
}    

Builder makeChildSurface(WindowContainer child) {

    final WindowContainer p = getParent();
    // 1.递归调用,通过父容器创建 Surface.Builder
    return p.makeChildSurface(child)
            // 2. 指定子容器 Surface 需要挂载到父容器 Surface 之下
            .setParent(mSurfaceControl);
}    

Surface.Builder 是通过递归调用父容器来创建的,最终会通过 DisplayContent 来创建

// DisplayContent.java

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

    // 通过工厂创建一个 SurfaceControl.Builder 
    final SurfaceControl.Builder b = mWmService.makeSurfaceBuilder(s)
                                                // surface 为容器类型
                                                .setContainerLayer();
    // ...
    
    return b.setName(child.getName())
            .setParent(mSurfaceControl);
}

SurfaceControl.Builder 构建完成后,就要利用它来创建真正的 SF Layer,如下

// WindowContainer.java

void setInitialSurfaceControlProperties(Builder b) {
    // 通过 Surface.Builder.build() 创建 surface
    // WMS 窗口容器使用  WindowContainer#mSurfaceControl 保存surface
    setSurfaceControl(b.setCallsite("WindowContainer.setInitialSurfaceControlProperties").build());
    
    // 出了 ActivityRecord 和 Task 以外,
    // 其他容器的 surface,在创建时就立即 show 出来
    if (showSurfaceOnCreation()) { 
        getSyncTransaction().show(mSurfaceControl);
    }
    
    // ...
}

SurfaceControl.Builder 的 build() 方法,会创建一个与 SF Layer 关联的 SurfaceControl 对象,如下

// SurfaceControl.java

public SurfaceControl build() {
    // ...

    return new SurfaceControl(
            mSession, mName, mWidth, mHeight, mFormat, mFlags, mParent, mMetadata,
            mLocalOwnerView, mCallsite);
}


private SurfaceControl(SurfaceSession session, String name, int w, int h, int format, int flags,
        SurfaceControl parent, SparseIntArray metadata, WeakReference<View> localOwnerView,
        String callsite)
                throws OutOfResourcesException, IllegalArgumentException {
    
    // ...
    
    try {
        // ...
        
        // 通过 JNI 层创建一个 SurfaceFlinger Layer
        nativeObject = nativeCreate(session, name, w, h, format, flags,
                parent != null ? parent.mNativeObject : 0, metaParcel);
    } // ...
    
    // 通过 mNativeObject 保存底层 Layer
    assignNativeObject(nativeObject, callsite);
}

更新容器和Layer层级

在 WMS 中,当子容器有了父容器后,会通过父容器来更新所有子容器的层级,如下

// WindowContainer.java

// 子容器处理父容器改变
void onParentChanged(ConfigurationContainer newParent, ConfigurationContainer oldParent) {
    // ...
    
    if (mSurfaceControl == null) {
        // 1.创建 surface,即 SF Layer,并挂载到父容器 surface 之下
        createSurfaceControl(false /*force*/);
    } else {
        // ...
    }

    // 2. 利用父容器更新子容器的层级,也更新 SF Layer 层级
    mParent.assignChildLayers();
}

// 父容器更新子容器层级
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);
        // 1. 递归调用,更新所有子容器的层级
        wc.assignChildLayers(t);
        
        if (!wc.needsZBoost()) {
            // 2. 更新直系子容器层级
            wc.assignLayer(t, layer++);
        }
    }
    
    
    // ...
}

父容器是根据子容器在 ArrayList mChildren 中的 index,递归更新所有子节点容器的层级

// WindowContainer.java

void assignLayer(Transaction t, int layer) {

    // 排除不能更新层级的情况
    if (!mTransitionController.canAssignLayers(this)) return;
    
    // 层级有改变
    final boolean changed = layer != mLastLayer || mLastRelativeToLayer != null;
    
    if (mSurfaceControl != null && changed) {
        // 更新 SF layer 层级
        setLayer(t, layer);
        
        // 保存容器层级
        mLastLayer = layer;
        mLastRelativeToLayer = null;
    }
}
// WindowContainer.java

protected void setLayer(Transaction t, int layer) {
    // 这里虽然分两种情况,其实原理就是有 leash 更新 leash 层级,否则更新容器层级
    if (mSurfaceFreezer.hasLeash()) {
        mSurfaceFreezer.setLayer(t, layer);
    } else { // 本文分析这里这里为例
        mSurfaceAnimator.setLayer(t, layer);
    }
}
// SurfaceAnimator.java

void setLayer(Transaction t, int layer) {
    // 通过 Tranasction 更新 SF Layer 层级
    t.setLayer(mLeash != null ? mLeash : mAnimatable.getSurfaceControl(), layer);
}

更新层级的条件

到目前为止,我只是以一种最简单易懂的方式,讲述了层级树的构建与层级更新原理。但是,在实际中,远远没有这里描述的这么简单。

首先,构建 SF layer 树的时候,Task 和 ActivityRecord 的 surface 在创建的时候,是不能立即显示的,那么它们什么时候显示出来呢?

然后,更新层级树节点层级时,也是有条件限制的,如下

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

这里的条件,其实都与窗口动画 Transition 有关。以我们分析的案例来说,当创建 Task,并保存到 TaskDisplayArea 下时,Task 是不能更新层级的,那么 Task 对应的 SF layer 自然也不能更新层级。而创建 AcivityRecord 并保存到 Task 下时,Task 却能更新 ActivityRecord 及其 SF layer 的层级。

想要明白其中的道理,需要对窗口动画 Transition 有深刻的理解。