引子:“Android是多窗口的吗?是多个进程进行渲染的吗?具体是怎么实现的?” 以上问题一位Linux研发咨询的,虽然一直对SurfaceFlinger、三缓冲、多窗口、Z轴这些概念有所了解,但是要系统地汇总介绍出来竟然又有点陌生,而这篇文章初衷就是回答上面三个问题。
关键字:SurfaceFlinger、VSync、Choreographer、Window、Surface、Layer、三缓冲
这篇文章目的仅为了回答上述三个问题,因此内容比较精简,是面向具备一定知识储备的读者,更多详细信息大家可以参考每个模块的参考链接。
1. 多应用(进程)独立绘制,交给SurfaceFlinger合成渲染

- NativeWindows-2 面向应用,等同于应用绘制时使用的Surface(就是SurfaceView拿到的Surface一样),是ViewRootImpl通过WMS获取的
- NativeWindows-1 属于Framebuffer NativeWindowSurfaceFlinger管理,和HWC交互最终交给硬件渲染
- 当系统中存在多个需要显示UI 的应用时,一方面这种改进设计保证了它们都能获得个“本地窗口”进行绘制,另一方面这些“本地窗口”也都可以被有序地显示到终端屏幕上一一因为SurfaceFlinger 会收集所有程序的显示需求,对它们进行统一的图像混合操作,然后输出到自己的NativeWindow上。(https://blog.csdn.net/Shujie_L/article/details/137829778)
2. 从数据流向的维度来看,Apps -> BufferQueue -> SurfaceFlinger
左侧就是各应用的Render线程,是生成图形缓冲区的渲染器,比如主屏幕、状态栏和系统界面等各个应用。SurfaceFlinger 是合成器,而硬件混合渲染器是混合渲染器。
我们继续展开“生成图形缓冲区的渲染器”和“BufferQueue”看看是什么组件实现的呢?更进一步,BufferQueue的FrontBuffer-OffScreenBuffer和三缓冲机制有什么关联吗?(https://juejin.cn/post/7288963211071979578)
双缓冲:Display 独立缓冲区,CPU-GPU共用一个缓冲区
三缓冲:Display、GPU、CPU分别使用一个独立缓冲区

3. 那Surface是什么呢?

https://blog.csdn.net/xiaolong662007/article/details/8278903
AI解释:
Surface 是 Android 图形系统中的一个抽象概念,表示一个可以绘制和显示的图形缓冲区。它提供了一个接口,通过 Canvas 或 OpenGL 等 API 进行图形绘制,并与 SurfaceFlinger 协同工作,将绘制结果显示在屏幕上。文章1:我们需要一个结构来记录应用程序界面的位置,大小,以及一个buffer 来记录需要显示的内容,所以这就是我们 surface 的概念,surface 实际我们可以把它理解成一个容器,这个容器记录着应用程序界面的控制信息,比如说大小、位置,而它还有buffer 来专门存储需要显示的内容。
文章2:Android的图像系统组件 无论开发者使用什么渲染 API,一切内容都会渲染到 「Surface」 上。Surface 表示缓冲区队列中的生产方,而缓冲区队列通常会被 SurfaceFlinger 消耗。在 Android 平台上创建的每个窗口都由 Surface 提供支持。所有被渲染的可见 Surface 都被 SurfaceFlinger 合成到屏幕
4. BufferQueue是生产消费队列,但是App数据是如何跨进程发给SurfaceFlinger的?

- 在 App 进程中创建 PhoneWindow 后会创建 ViewRoot。ViewRoot 的创建会创建一个 Surface,这个 Surface 其实是空的,通过与 WindowManagerService 通信 copyFrom() 一个 NativeSurface。
- 在与 SurfaceFlinger 通信时,会创建 SharedClient 一段共享内存,里面存放的是 SharedBufferStack 对应 SurfaceFlinger 中的 SurfaceLayer 每个 Layer 其实是一个 FrameBuffer,每个 FrameBuffer 中有两个 GraphicBuffer 记作 FrontBuffer 和 BackBuffer。
- 在 SurfaceFlinger 中 SharedBufferServer 来管理 FrameBuffer。同时在 App 端 copyFrom() 出来 NativeSurface 时会创建一个 SharedBufferClient 与 SharedClient 这块共享内存关联。当客户端 addView() 或者需要更新 View 时,会通过 SharedBufferClient 写入数据到 ShareClient 中,SurfaceFlinger 中的 SharedBufferServer 接收到通知会将 FrameBuffer 中的数据传输到屏幕上。
- HWComposer 是基于硬件来产生 VSync 信号的,来通知 SurfaceFlinger 重绘控制显示的帧率。
(https://juejin.cn/post/7292428123849343039)
5. SharedClient大数据的共享内存机制

WMS的作用只是窗口管理,那么图形是怎么绘制的呢?并且这些绘制信息是如何传递给SurfaceFlinger服务的呢?每个View都有自己的onDraw回调,开发者可以在onDraw里绘制自己想要绘制的图像,很明显View的绘制是在APP端,直观上理解,View的绘制也不会交给服务端,不然也太不独立了,可是View绘制的内存是什么时候分配的呢?是谁分配的呢?我们知道每个Activity可以看做是一个图层,其对应一块绘图表面其实就是Surface,Surface绘图表面对应的内存其实是由SurfaceFlinger申请的,并且,内存是APP与SurfaceFlinger间进程共享的。实现机制是基于Linux的共享内存,其实就是MAP+tmpfs文件系统,你可以理解成SF为APP申请一块内存,然后通过binder将这块内存相关的信息传递APP端,APP端往这块内存中绘制内容,绘制完毕,通知SF图层混排,之后,SF再将数据渲染到屏幕。其实这样做也很合理,因为图像内存比较大,普通的binder与socket都无法满足需求,内存共享的示意图如上
(https://www.jianshu.com/p/e4b19fc36a0e)
(https://www.jianshu.com/p/62db83a97a5c)
6. 系统如何控制数据传递的时序以及绘制周期呢?Vsync登场

Vsync 信号可以由硬件产生,也可以用软件模拟,不过现在基本上都是硬件产生,负责产生硬件 Vsync 的是 HWC。HWC 可生成 VSYNC 事件并通过回调将事件发送到 SurfaceFlinger 再通过 DispSync 将 Vsync 生成由 Choreographer 和 SurfaceFlinger 使用的 VSYNC_APP 和 VSYNC_SF 信号。

7. Choreographer在接收到VSYNC_APP时都做了哪些动作?

工作流程:
- Choreographer 初始化
- 初始化 FrameHandler ,绑定 Looper
- 初始化 FrameDisplayEventReceiver ,与 SurfaceFlinger 建立通信用于接收和请求 Vsync
- 初始化 CallBackQueues。SurfaceFlinger 的 appEventThread 唤醒发送 Vsync ,Choreographer 回调 FrameDisplayEventReceiver.onVsync , 进入 Choreographer 的主处理函数 doFrame
- Choreographer.doFrame 计算掉帧逻辑
- Choreographer.doFrame 处理 Choreographer 的第一个 callback : input
- Choreographer.doFrame 处理 Choreographer 的第二个 callback : animation
- Choreographer.doFrame 处理 Choreographer 的第三个 callback : insets animation
- Choreographer.doFrame 处理 Choreographer 的第四个 callback : traversal,traversal-draw 中 UIThread 与 RenderThread 同步数据
- Choreographer.doFrame 处理 Choreographer 的第五个 callback : commit
- RenderThread 处理绘制命令,将处理好的绘制命令发给 GPU 处理
- 调用 swapBuffer 提交给 SurfaceFlinger 进行合成
(https://juejin.cn/post/7291604571200749609)
PS:UIThread和RenderThread的数据通信主要通过RenderNode和DisplayList,相关信息可以参考从源码updateDisplayListIfDirty开始了解
8. 总结
上述的7大主题基本解释了引子中的三个问题。如果尝试用一段话总结的话 :“Android每个应用都有自己独立的渲染区域,每个应用在独立的内存区域绘制,整个内存块是一个BufferQueue队列,按照Z轴排序。BufferQueue队列中的GraphicBuffer存储图形数据,三缓冲机制的具体实现就来源于GraphicBuffer三块内存。应用在vsync_app信号量到达时统一进行绘制工作,而vsync_sf信号量到到达时,SurfaceFlinger服务会从各应用BufferQueue队列中获取BackEnd图形数据,按照Z轴垂直排列,交给HWC处理,最终发给显示终端显示。”
当然除了主要7个步骤,还有各应用的DisplayList机制、Render线程、三缓冲机制、HWC、Skia、OpenGLES等等诸多概念没有涉及,要完整解释Android的渲染体系还有很多知识点需要掌握,最后就用一张体系大图来完成这篇完整吧。

(https://blog.csdn.net/WolfKingzyh/article/details/135625212)