WindowManagerService 核心数据结构(2)
简述
在开始看代码之前,我们先来了解一下WMS的核心数据结构,后续WMS很多的操作都是基于这些数据结构的,了解完这些类之后可以更加便于我们看具体流程代码。
WMS用一个树结构来记录所有的窗口,其中里面有许多不同类型的节点,用来代表不同的业务。
WindowContainer
在WMS树结构里,所有的节点类都继承了WindowContainer,WindowContainer里面处理了一些树结构相关的操作,例如记录了父节点和子节点,提供了一些树的操作方法
例如reparent,setParent,addChild。同时支持了一些树节点变化的监听,例如onParentChanged。
这个基类WindowContainer主要就是实现了一个树结构,提供了一些结构变化的监听回调。(一定程度上可以理解为我门自己实现的树结构的TreeNode)
每个WindowContainer里面都有一个SurfaceControl,对应SurfaceFlinger里面有一个layer,SurfaceFlinger里面也有一个layer树结构,这样WMS父窗口的变化就能同样影响到SurfaceFlinger里面父layer,从而影响子layer。
WindowContainer继承了ConfigurationContainer,这个ConfigurationContainer主要是用来记录Configuration的,我们在开发app的时候应该会接触Configuration,里面有一些系统相关的配置,比如亮暗色,横竖屏等。
class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<E>
implements Comparable<WindowContainer>, Animatable, SurfaceFreezer.Freezable,
InsetsControlTarget {
...
private WindowContainer<WindowContainer> mParent = null;
// WindowList是一个ArrayList的子类,可以看出来这里的泛型就是子节点的类型。
protected final WindowList<E> mChildren = new WindowList<E>();
}
RootWindowContainer
RootWindowContainer是WMS树的根节点,它继承了WindowContainer,所以根节点下面只能是DisplayContent。
RootWindowContainer只有一个,DisplayContent代表屏幕,几个屏幕就有几个DisplayContent
class RootWindowContainer extends WindowContainer<DisplayContent>
implements DisplayManager.DisplayListener {
...
}
DisplayContent
DisplayContent代表一个屏幕,正常情况我们设备如果只有一个屏幕的话就只有一个DisplayContent,但是很多时候会有一些虚拟屏,比如说屏幕录制就是通过虚拟屏实现的,录制屏幕的时候WMS会创建一个虚拟盘,然后调用SurfaceFlinger构建出一个mirror屏,然后将mirror Surface渲染出来的图像编码写到文件中。
现在由于新能源车的兴起,很多厂在做车手互联,那些手机在车机上异源投屏就是通过创建虚拟屏实现的。
DisplayContent继承关系如下,可以看出来DisplayContent的子节点是DisplayArea。
class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.DisplayContentInfo {
...
}
class RootDisplayArea extends DisplayArea.Dimmable {
...
}
static class Dimmable extends DisplayArea<DisplayArea> {
...
}
public class DisplayArea<T extends WindowContainer> extends WindowContainer<T> {
}
DisplayArea
DisplayArea有几个子类,除了上面的RootDisplayArea以外还有TaskDisplayArea和DisplayArea.Tokens。
而DisplayArea.Tokens有一个子类ImeContainer。
TaskDisplayArea是用于管理Task的,我们平时应用开发接触到的页面几乎都是在这个节点下面的,这个我们后面介绍。
DisplayArea.Tokens的子节点类型是WindowToken,WindowToken是用于管理窗口的集合,它也有一个很重要的子类ActivityRecord,我们也在后面介绍。另外它还有一个子类WallpaperWindowToken是用于管理壁纸的。
ImeContainer是输入法的容器。
final class TaskDisplayArea extends DisplayArea<WindowContainer> {
...
}
public static class Tokens extends DisplayArea<WindowToken> {
...
}
private static class ImeContainer extends DisplayArea.Tokens {
...
}
TaskDisplayArea
这个是用于管理所有Task的集合,Task的概念在app开发的过程中应该也会有所接触,最近任务中显示的一个一个的app其实就是一个个Task。
Task
Task继承子TaskFragment,而TaskFragment继承了WindowContainer。
这里的Task节点就是最近任务中的那个Task,它会包含ActivityRecord。
这里的TaskFragment是最近几个版本更新出来的,个人的理解是它只是剥离了一些逻辑(主要是跟AMS相关的生命周期一类的逻辑),让Task里面的逻辑解耦(个人理解不一定正确)
class Task extends TaskFragment {
...
}
class TaskFragment extends WindowContainer<WindowContainer> {
...
}
ActivityRecord和WindowState
这两个结构是最重要的两个结构。
ActivityRecord对应app的Acitvity,在app启动activity的时候system_server创建,由此可见AMS的逻辑和WMS是有耦合的。
ActivityRecord是的子节点是WindowState,WindowState就是代表最终的窗口,我们屏幕上所有显示的app窗口几乎都是WindowState,同时WindowState可以有子节点,仍然是WindowState,这就是父子窗口。Activity自己本来的窗口会作为ActivityRecord的子节点(一个WindowState),如果我们使用activity的context来创建dialog,就会在这个WindowState下面再创建一个WindowState。所以对话框就是一个子窗口,本质也是通过WindowManager.addView接口实现的,我们后面会讲。
这里顺带提一个点,可以帮大家更好的理解窗口,做app开发的同学们应该会接触过,有时候弹窗不会直接创建Dialog,而是使用DialogFragment,这个很不一样,DialogFrament不是一个单独的窗口,而是app侧view在Z轴叠加效果实现的,也就是说创建并且显示一个DialogFragment不需要通过binder通知到SystemServer,是在app进程中就可以完成的,而想要创建一个Dialog,是需要SystemServer一起来完成的。
final class ActivityRecord extends WindowToken implements WindowManagerService.AppFreezeListener {
...
}
class WindowState extends WindowContainer<WindowState> implements WindowManagerPolicy.WindowState,
InsetsControlTarget, InputTarget {
...
}
小结
我们这一节只介绍了一些数据结构,WMS就是通过这些数据结构构建的窗口树,通过这个树来管理所有app的窗口。
所有的节点都继承自WindowContainer,这个窗口树的根节点是RootWindowContainer。而RootWindowContainer下面是DisplayContent,代表屏幕,包括虚拟屏。
下一节会介绍这个树结构初始化的过程。