在 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 有深刻的理解。