概览
以下内容基于 Android R 。
当 activity 到达前台时,会通过 wm 向 SurfaceFlinger 请求一块 surface ,然后 app 将 window 中所有 view 的内容渲染到这块 surface 中,SurfaceFlinger 在下一次 VSYNC 信号到达时将其合成并发送给 HWC 渲染到显示器上。如图:

具体如下:

其中涉及的主要模块的作用如下:

简而言之渲染过程如下:

下面主要介绍 java 层的几个主要步骤:构建 view 树并添加到窗口管理器、获取 surface、布局、绘图。
构建 view 树并添加到窗口管理器
以 ViewRootImpl 作为一个 window 中所有 view 的 parent ,DecorView 作为 view 树顶点构建树,再通过 WindowManager 将该 window 添加到系统的窗口管理器中。因此一个 window 的渲染由 ViewRootImpl 开始。
下图表示 ViewRootImpl 和 Window 、WindowManager 的关系:

获取 surface
android R 中 ViewRootImpl 的 Surface 通过 WM 创建的 SurfaceControl 获取。如下:

WindowManagerService 在创建 java 层的 SurfaceControl 时会请求 SurfaceFlinger 提供一个 native 层的 SurfaceControl ,而 SurfaceFlinger 实际创建了一个 layer ,并把持有 IGraphicBufferProducer 的 SurfaceControl native 对象返回给 WMS 。之后 ViewRootImpl 就通过 SurfaceControl 中的 IGraphicBufferProducer 创建一个 Surface 。
IGraphicBufferProducer 和 Surface 的关系如下:

布局 和 绘图
window 中的布局开始是在 ViewRootImpl#setView 中,如下:

其中分为布局和绘图( ViewRootImpl#performDraw )两步,其中布局又包含测量( ViewRootImpl#performMeasure )和布局( ViewRootImpl#performDraw ),如下:

测量
在测量中会用到两个关键类:LayoutParams 和 MeasureSpec,其中 LayoutParams 表示 child view 自己想要的布局方式,而 MeasureSpec 指的是布局过程中 parent view 规定自己的子 view 需要遵循的规范。

performMeasure 中的初始 DecorView 大小为 window 的大小,然后从上而下遍历以 DecorView 的 view 树,获取每个根节点的叶子节点的大小,然后确定根节点大小。

其中有两点需要注意:
- 所有 view 必须重写 onMeasure() 方法测量自己的大小,并在 onMeasure() 中调用 setMeasuredDimension(width, height) 设置自己测量过后的宽、高。
- ViewGroup 重写 onMeasure() 方法必须实现 top-down 遍历以它为 root 的树的测量,并在返回且需已完成其子 view 的测量。
布局
view 的布局就是 top-down 遍历以它为 root 的树,并根据之前的测量结果把自己放在对应位置,即设置自己所占区域的 左、上、右、下 的值。如下:

绘图
绘图分为硬件绘图和软件绘图,设置了硬件加速即为硬件绘图,而硬件加速一般默认开启。
硬件绘图简单来说就两步:
- 遍历以 view 为 root 的 view 树,记录所有需要更新的 view 的绘制命令( display list )。
- 将这个 view 及其子 view 的绘制命令发布剪裁到屏幕上最新毁坏的区域。
具体如下:

其中特别注意的是每个 view 内容的具体先后顺序好下:

即先背景,然后是自己的内容,然后是子孙,然后是滚动时淡化的边缘,然后是滚动条等装饰,最后是焦点。
硬件绘图主要是通过 ThreadedRenderer 在渲染线程中将 view 的 RenderNode 生成的场景渲染到 Surface 中。

总结
window 中的内容显示到显示器上,简单来讲就是 app 先将 xml 设置的布局信息测量布局好,然后记录需要更新的 Canvas 绘制命令,之后将 Canvas 生成的图形数据放入 SurfaceFlinger 提供的 surface 的 buffers 中,同时 WindowManager 提供这些 window 的 z-order 等信息供 SurfaceFlinger 合成时使用,SurfaceFlinger 在 VSYNC 到来时,遍历系统中所有 surface 的 layer ,并合成需要它合成的 layer ,之后把合成的 buffers 发送给 HWC ,HWC 把它们渲染到屏幕上。
原创文章,欢迎转载,但请注明出处
网友评论