从 Android 13 开始,每当屏幕分辨率发生变化时,系统都会分配在客户端合成期间使用的新的帧缓冲区。分辨率变化后,SurfaceFlinger 会对下一个“失效”周期执行此分配。invalidate
分辨率切换期间的帧缓冲区管理
分辨率会由于以下两种情况之一而发生变化:
由硬件混合渲染器 (HWC) 发起的热插拔事件,从一个外部屏幕切换到具有不同默认分辨率的另一个外部屏幕时发生。
在热插拔事件期间,旧的屏幕数据取消分配后,系统会释放旧的帧缓冲区的句柄。
由 SurfaceFlinger 发起的显示模式切换,用户使用用户设置更改分辨率时或应用使用
preferredDisplayModeId
更改分辨率时发生。在显示模式切换期间,SurfaceFlinger 会在调用
setActiveConfig
或setActiveConfigWithConstraints
之前释放现有客户端帧缓冲区的句柄。
为了避免出现灾难性问题(如内存碎片化),在没有为新旧帧缓冲区预留足够内存的设备上,HWC 必须停止使用旧帧缓冲区并释放这些帧缓冲区的所有句柄,如下所示:
对于热插拔事件,调用
onHotplug
之前立即执行上述操作。对于模式切换,调用
setActiveConfig
或setActiveConfigWithConstraints
后立即执行上述操作。
释放句柄会导致帧缓冲区内存会被完全取消分配,SurfaceFlinger 无法在下一个“失效”周期内执行新帧缓冲区分配。invalidate
帧缓冲区管理建议
如果 HWC 未及时释放旧帧缓冲区的句柄,则新的帧缓冲区分配会在旧的帧缓冲区取消分配之前发生。如果新的帧缓冲区的分配因碎片化或其他问题而失败,上述情况可能会导致灾难性问题。更糟糕的是,如果 HWC 没有释放任何句柄,还可能会发生内存泄漏。
为避免发生灾难性的分配失败问题,请遵循以下建议:
如果 HWC 需要继续使用旧的客户端帧缓冲区,直到提供了新的客户端帧缓冲区,那么为新旧帧缓冲区都预留足够的内存至关重要,并可能需要对帧缓冲区内存空间运行碎片整理算法。
为独立于其余图形内存缓冲区的帧缓冲区分配一个专属的内存池。这一点很重要,因为在取消分配和重新分配帧缓冲区期间,第三方进程可以尝试分配显存。如果帧缓冲区使用了同一显存池,而且显存已满,则第三方进程可以占用帧缓冲区先前分配的显存,从而导致没有足够的内存供帧缓冲区重新分配,或可能导致内存空间碎片化。
测试帧缓冲区管理
建议 OEM 针对其设备的分辨率切换测试客户端帧缓冲区内存管理是否正常,如下所述:
对于热插拔事件,只需拔出设备,然后重新连接具有不同分辨率的两个显示器即可。
对于模式切换,请使用
ModeSwitchingTestActivity
CTS 验证程序测试启动模式切换,以测试帧缓冲区内存行为。此测试可以直观地识别难以通过程序化方式检测的问题。