第一阶段启动中,构建了窗口层级,创建 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。
问题
在框架的分析中,其实遗留了两个问题
- ActivityRecord 和 Task 的 surface,在创建之时,是出于 hidden 状态的。那么,它们的 surface 是什么时候显示的呢?
- Task 保存到 TaskDisplayArea 时,是无法更新其 surface layer。那么,它的 surface layer 是何时更新的呢?
随着本系列文章逐渐揭开动画流程,这两个问题的答案,自然会揭晓。