從 Android 13 開始,每當螢幕解析度變更時,系統就會分配新的影格緩衝區,用於用戶端合成作業。解析度變更後,SurfaceFlinger 會在下一個「失效」週期執行這項配置。
解析度切換期間的 Framebuffer 管理
解析度變更的原因有下列兩種情況:
熱插拔事件,由硬體合成器 (HWC) 啟動,發生於從一個外部螢幕切換至另一個預設解析度不同的外部螢幕時。
在熱插拔事件期間,系統會釋出舊緩衝區的控制代碼,並解除分配舊螢幕資料。
SurfaceFlinger 啟動的顯示模式切換,發生於使用者透過使用者設定變更解析度,或應用程式透過
preferredDisplayModeId
變更解析度時。在切換顯示模式期間,SurfaceFlinger 會先釋出現有用戶端 Framebuffer 的控制代碼,再呼叫
setActiveConfig
或setActiveConfigWithConstraints
。
為避免在未為新舊緩衝區保留足夠記憶體的裝置上發生記憶體片段化等災難性問題,HWC 必須停止使用舊緩衝區,並釋放這些緩衝區的所有控制代碼,如以下案例所示:
如果是熱插拔事件,請在呼叫
onHotplug
之前立即執行此操作。如要切換模式,請在呼叫
setActiveConfig
或setActiveConfigWithConstraints
後立即執行此操作。
釋放控點可讓訊框緩衝區記憶體在 SurfaceFlinger 於下一個 invalidate 週期分配新訊框緩衝區之前,完全取消分配。
緩衝區管理建議
如果 HWC 未及時將控制代碼發布至舊的 Framebuffer,新的 Framebuffer 配置就會在舊的 Framebuffer 取消配置前發生。如果因片段化或其他問題導致新分配失敗,可能會造成災難性問題。更糟的是,如果 HWC 完全未釋放這些控制代碼,可能會發生記憶體洩漏。
為避免災難性的分配失敗,請參考下列建議:
如果 HWC 需要繼續使用舊的用戶端訊框緩衝區,直到提供新的用戶端訊框緩衝區為止,請務必為新舊訊框緩衝區保留足夠的記憶體,並可能在訊框緩衝區記憶體空間上執行重組演算法。
為訊框緩衝區分配專屬記憶體集區,與其餘的圖像緩衝區記憶體分開。這點很重要,因為在緩衝區解除分配和重新分配之間,第三方程序可能會嘗試分配圖形記憶體。如果訊框緩衝區使用相同的圖形記憶體集區,且圖形記憶體已滿,第三方程序可能會佔用訊框緩衝區先前分配的圖形記憶體,導致訊框緩衝區重新分配時記憶體不足,或可能造成記憶體空間片段化。
測試畫面緩衝區管理
建議 OEM 針對裝置的解析度切換測試適當的用戶端 Framebuffer 記憶體管理,如下所述:
如為熱插拔事件,只要拔除並重新連接兩個不同解析度的螢幕即可。
如要切換模式,請使用
ModeSwitchingTestActivity
CTS 驗證器測試,啟動模式切換,測試影格緩衝區記憶體行為。這項測試可以透過視覺化方式找出難以透過程式輔助偵測到的問題。