从零开始给 Surface 实现 SurfaceSyncGroup
背景
我的上一篇文章讲到了给 Surface 实现帧同步,作为实现帧同步的重要手段,在做动画需求,特别是跨进程同步渲染的需求中发挥了重要的作用。但还有另一种跨进程渲染的方案,在 Android13 被提了出来,这便是 SurfaceSyncGroup。SurfaceSyncGroup 是用来替代 SurfaceSyncer 的方案的,SurfaceSyncer 我没用过(Android13 发布的时候我刚工作一年),所以就不提了,不过值得注意的是,这个用来帧同步的 SurfaceSyncGroup 居然是作为开放 API 发布的,难得见到谷歌慷慨了一回啊,之前图形绘制相关的 API,不管是 BLAST 相关还是 SurfaceSyncer 都是标明了 hide 接口的。
所以我为什么老是需要用到帧同步这些东西呢,因为我在去年年末的时候接手了桌面的窗口动画业务,特别是在后续的需求中引入多个 Surface 动画之后,有些场景并不能单纯依靠事务。比如绘制的同步就不能依靠我上一篇文章中的那种方法,这就涉及到 Surface 绘制的原理了,绘制是一种隐式的事务,在绘制操作从主线程转移到 RenderThread 上帧渲染完成之后,缓冲区就会挂到一个 Transaction 上,然后这个 Transaction 被发送到 SurfaceFlinger 去进行合成。这点可以通过 Winscope 来验证,在 Windscope 的 Transcation 一栏,是可以找到带有 Buffer 的 Transaction 的。
关于 SurfaceSyncGroup 的原理,网上一搜讲解很多,我这里就不详细展开了,简单来说就是通过一个根 group,来管理所有的子 group。对于这个根 group,如果是本地进程就由本地进程管理,如果是跨进程则通过 WMS 来管理。每个子 group 在绘制完成之后需要调用 markSyncReady 来通知根 group,然后根 group 会检查是否所有的子 group 已经全部准备好,如果全部准备好了,就调用 Transaction#apply 来应用事务。那怎么做到同步帧缓冲的呢?想起我上面说的了吗,绘制也是一种隐式的事务,最终也是要转为事务来应用的,只不过对于开发者来说是个黑箱,无感知而已。