「安卓framework基础篇7」从WMS到BufferQueue第一篇 - WMS层级树的初始化过程(基于AOSP13)
上一篇文章分析了Vsync的基本工作过程,最终Vsync信号会派发给订阅Vsync信号的APP进程,那APP进程收到Vsync信号后,会做哪些事情呢?本篇咱们先以画图的形式将构造WMS层级树的算法执行过程直观得向大家解释清楚,因为收到Vsync信号后,都是基于WMS的层级树来操作SurfaceFlinger中的窗口图层的,如果有空,看本篇前强烈建议先了解一下什么是有序多叉树和有序多叉树的前序遍历算法,WMS层级树就是一棵有序多叉树。
学习aosp源码的小伙伴对WMS应该不会陌生,WMS全称WindowManagerService,是安卓系统中用来统一管理系统窗口的重要服务,下面我们从WMS的初始化开始一直分析到SurfaceFlinger消费BufferQueue里的帧数据元素。
WMS的初始化源码分析(重点在构造WMS层级树)
系统开机时会调用 frameworks/base/services/java/com/android/server/SystemServer.java 的startOtherServices方法:
/*** Starts a miscellaneous grab bag of stuff that has yet to be refactored and organized.*/private void startOtherServices(@NonNullTimingsTraceAndSlog t) {//省略// 初始化WMS服务wm = WindowManagerService.main(context, inputManager, !mFirstBoot, mOnlyCore,new PhoneWindowManager(), mActivityManagerService.mActivityTaskManager);//省略// 将WMS对象传递给AMS服务mActivityManagerService.setWindowManager(wm);//省略}
ActivityManagerService.java的setWindowManager方法:
publicvoidsetWindowManager(WindowManagerService wm) {synchronized (this) {// 将wms对象保存到自身的成员变量中mWindowManager = wm;mWmInternal = LocalServices.getService(WindowManagerInternal.class);// 将wms对象传递给ATMS服务mActivityTaskManager.setWindowManager(wm);}}
ActivityTaskManagerService.java 的 setWindowManager 方法:
public void setWindowManager(WindowManagerService wm) {synchronized (mGlobalLock) {//省略// 将wms对象传递给根容器mRootWindowContainer.setWindowManager(wm);//省略}}
frameworks/base/services/core/java/com/android/server/wm/RootWindowContainer.java的setWindowManager方法
void setWindowManager(WindowManagerService wm) {//省略for (int displayNdx = 0; displayNdx < displays.length; ++displayNdx) {final Display display = displays[displayNdx];// 开始初始化WMS层级树final DisplayContent displayContent = new DisplayContent(display, this);//省略}//省略}
frameworks/base/services/core/java/com/android/server/wm/DisplayContent.java 的 DisplayContent 构造方法:
DisplayContent(Display display, RootWindowContainer root) {//省略configureSurfaces(pendingTransaction);//省略}
frameworks/base/services/core/java/com/android/server/wm/DisplayContent.java 的 configureSurfaces 方法:
private void configureSurfaces(Transaction transaction) {//省略// 开始构造WMS层级树mDisplayAreaPolicy = mWmService.getDisplayAreaPolicyProvider().instantiate(mWmService, this /* content */, this /* root */,mImeWindowsContainer);//省略}
frameworks/base/services/core/java/com/android/server/wm/DisplayContent.java 的 instantiate 方法:
static final class DefaultProvider implements DisplayAreaPolicy.Provider {@Overridepublic DisplayAreaPolicy instantiate(WindowManagerService wmService,DisplayContent content, RootDisplayArea root,DisplayArea.Tokens imeContainer) {//省略final HierarchyBuilder rootHierarchy = new HierarchyBuilder(root);//省略if (content.isTrusted()) {//省略// 设置每个层级的Feature(特性)configureTrustedHierarchyBuilder(rootHierarchy, wmService, content);}//省略// 正式开始构造wms层级树结构return new DisplayAreaPolicyBuilder().setRootHierarchy(rootHierarchy).build(wmService);}
WMS初始化层级树的代码,有两处难点,第一处是设置每个层级的Feature(特性),第二处是创建层级树对象
设置每个层级的Feature(特性)难点分析
private void configureTrustedHierarchyBuilder(HierarchyBuilder rootHierarchy,WindowManagerService wmService, DisplayContent content) {// 创建Feature对象并放入rootHierarchy中,后面会依据Feature来构造WMS层级树// WindowedMagnification 代表具有局部放大功能的层级特性rootHierarchy.addFeature(new Feature.Builder(wmService.mPolicy, "WindowedMagnification",FEATURE_WINDOWED_MAGNIFICATION).upTo(TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY).except(TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY)// Make the DA dimmable so that the magnify window also mirrors the dim layer..setNewDisplayAreaSupplier(DisplayArea.Dimmable::new).build());// 省略}
DisplayAreaPolicyBuilder.Feature.Builder的构造函数:
Builder(WindowManagerPolicy policy, String name, int id) {// 省略// 构造 mLayers 这个布尔类型的数组,数组容量为层级树的最大层数+1// 这个数组表示当前的 Feature 会应用到那些层级上,// 这个数组的下标代表层级编号,数组元素值为true代表对应的层级应当应用当前这个FeaturemLayers = new boolean[mPolicy.getMaxWindowLayer() + 1];}
new Feature.Builder.except :设置需要应用本特性的层级时,要排除指定的层级
new Feature.Builder.all :所有层级都需要应用本特性
new Feature.Builder.and :设置需要应用本特性的层级时,要把指定的层级也包含进来
new Feature.Builder.upTo :应用了指定层级和其以下的层级,都要应用当前特性
这时候遇到个小疑问,为什么表示具体特性类型的常量值要定义成 “2000 + xxx” 呢?这是安卓系统诞生之初就定义好的,为的是预留足够多的冗余值来为未来要添加的新特性做准备。
创建层级树对象难点分析
DisplayAreaPolicyBuilder.buid 方法:
Result build(WindowManagerService wmService) {// 省略// 调用DisplayAreaPolicyBuilder.HierarchyBuilder.build 方法开始构建层级树mRootHierarchyBuilder.build(mDisplayAreaGroupHierarchyBuilders);// 省略}
DisplayAreaPolicyBuilder.HierarchyBuilder.build 方法:
private void build(@Nullable List<HierarchyBuilder> displayAreaGroupHierarchyBuilders) {// 省略PendingArea[] areaForLayer = new PendingArea[maxWindowLayerCount];final PendingArea root = new PendingArea(null, 0, null);Arrays.fill(areaForLayer, root);// 省略final int size = mFeatures.size();// 第一个for循环开始,把Feature挂载到各自对应的Layer元素上for (int i = 0; i < size; i++) {// 省略final Feature feature = mFeatures.get(i);PendingArea featureArea = null;for (int layer = 0; layer < maxWindowLayerCount; layer++) {if (feature.mWindowLayers[layer]) {// 省略if (featureArea == null || featureArea.mParent != areaForLayer[layer]) {// 省略featureArea = new PendingArea(feature, layer, areaForLayer[layer]);areaForLayer[layer].mChildren.add(featureArea);}areaForLayer[layer] = featureArea;} else {// 省略featureArea = null;}}}// 省略PendingArea leafArea = null;int leafType = LEAF_TYPE_TOKENS;// 第二个for循环开始,for (int layer = 0; layer < maxWindowLayerCount; layer++) {int type = typeOfLayer(policy, layer);// 省略if (leafArea == null || leafArea.mParent != areaForLayer[layer]|| type != leafType) {// 省略leafArea = new PendingArea(null /* feature */, layer, areaForLayer[layer]);areaForLayer[layer].mChildren.add(leafArea);leafType = type;if (leafType == LEAF_TYPE_TASK_CONTAINERS) {// 省略addTaskDisplayAreasToApplicationLayer(areaForLayer[layer]);addDisplayAreaGroupsToApplicationLayer(areaForLayer[layer],displayAreaGroupHierarchyBuilders);leafArea.mSkipTokens = true;} else if (leafType == LEAF_TYPE_IME_CONTAINERS) {// 省略leafArea.mExisting = mImeContainer;leafArea.mSkipTokens = true;}}leafArea.mMaxLayer = layer;}root.computeMaxLayer();// 将临时层级树数据结构转换成最终的WMS对象结构root.instantiateChildren(mRoot, displayAreaForLayer, 0, featureAreas);// 省略mRoot.onHierarchyBuilt(mFeatures, displayAreaForLayer, featureAreas);}
第一个for循环过程演示图(假设有3个Feature + 7个层级)

简单描述就是:
将Feature挂到对应的层级上,相邻的层级如果共享同一个Feature会合并成一个对象来表示,最终构造出一个有序多叉树。将这棵树称之为层级树的特性树更为贴切,因为这个树中的每个节点表示的是特性而不是具体的层级。举个例子:

上图中红框部分层级6和7共享第二个Feature、层级6拥有第三个Feature。
第二个for循环
第二个for循环比较好理解,就是为挂载app的layer和输入法的layer再挂上叶子节点。
将临时层级树数据结构转换成最终的WMS对象结构
void instantiateChildren(DisplayArea<DisplayArea> parent, DisplayArea.Tokens[] areaForLayer,int level, Map<Feature, List<DisplayArea<WindowContainer>>> areas) {// 为当前节点的所有直接子节点按mMinLaye字段值排序(升序排序)mChildren.sort(Comparator.comparingInt(pendingArea -> pendingArea.mMinLayer));// 遍历每个直接子节点for (int i = 0; i < mChildren.size(); i++) {final PendingArea child = mChildren.get(i);// 创建每个直接子节点对应的正式WMS节点final DisplayArea area = child.createArea(parent, areaForLayer);if (area == null) {// TaskDisplayArea and ImeContainer can be set at different hierarchy, so it can// be null.continue;}//将创建的正式WMS节点挂载到正式的wms树上parent.addChild(area, WindowContainer.POSITION_TOP);if (child.mFeature != null) {areas.get(child.mFeature).add(area);}// 递归调用本方法,为当前子节点再做相同的事,直到完成前序遍历child.instantiateChildren(area, areaForLayer, level + 1, areas);}}
这个方法就是将之前的临时层级树用递归的方式前序遍历,生成一棵排过序的、与临时层级树的结构几乎相同的正式层级树,每个节点用DisplayArea对象代替。
夜雨聆风