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