自 Android 13 起,每當顯示解析度變更時,系統就會分配新的框架緩衝區,用於用戶端合成作業。這項分配作業是由 SurfaceFlinger 在解析度變更後的下一個無效週期執行。
解析度切換期間的框架管理
由於下列兩種情況之一,會發生解決辦法:
熱插拔事件:由硬體合成器 (HWC) 啟動,當從一個外接螢幕切換至具有不同預設解析度的其他外接螢幕時,就會發生此事件。
在熱插事件期間,當舊顯示資料釋放時,舊框架緩衝區的句柄會釋放。
由 SurfaceFlinger 啟動的顯示模式切換,會在使用者透過使用者設定變更解析度,或應用程式透過
preferredDisplayModeId
變更解析度時發生。在切換顯示模式期間,SurfaceFlinger 會在呼叫
setActiveConfig
或setActiveConfigWithConstraints
之前釋放現有用戶端 framebuffer 的句柄。
為避免發生記憶體碎裂等嚴重問題,在未為舊版和新版 Framebuffer 保留足夠記憶體的裝置上,HWC 必須停止使用舊版 Framebuffer,並釋放這些 Framebuffer 的任何句柄,如以下情況所示:
對於熱插事件,請在呼叫
onHotplug
之前立即執行。模式切換:在呼叫
setActiveConfig
或setActiveConfigWithConstraints
後立即執行。
釋放控點後,即可在 SurfaceFlinger 在下一個失效週期中執行新影格緩衝區的分配作業前,將影格緩衝區記憶體完全取消分配。
Framebuffer 管理最佳化建議
如果 HWC 未及時釋放舊框架緩衝區的句柄,系統會在舊框架緩衝區解除配置前,先進行新框架緩衝區的配置。當新分配作業因分散或其他問題而失敗時,就可能發生嚴重問題。更糟的是,如果 HWC 完全不釋放這些句柄,就可能發生記憶體耗損。
為避免發生嚴重配置失敗,請遵循下列建議:
如果 HWC 需要繼續使用舊的用戶端 framebuffer,直到新的用戶端 framebuffer 提供為止,那麼,為舊版和新版 framebuffer 預留足夠的記憶體,並在 framebuffer 記憶體空間上執行分割作業演算法,就至關重要。
為 framebuffer 分配專屬記憶體集區,與其他圖形緩衝區記憶體分開。這一點很重要,因為在解除配置和重新配置 framebuffer 之間,第三方程序可能會嘗試配置圖形記憶體。如果 framebuffer 使用相同的圖形記憶體集區,且圖形記憶體已滿,第三方程序可能會佔用先前由 framebuffer 配置的圖形記憶體,導致 framebuffer 重新配置記憶體不足,甚至可能會使記憶體空間碎片化。
測試 framebuffer 管理
建議原始設備製造商 (OEM) 針對裝置的解析度切換,測試是否有適當的用戶端幀格緩衝區記憶體管理機制,如下所述:
針對熱插拔事件,只要拔除並重新連接兩個解析度不同的螢幕即可。
如要切換模式,請使用
ModeSwitchingTestActivity
CTS 驗證工具測試,啟動模式切換,以便測試 framebuffer 記憶體行為。這項測試可透過視覺化方式,找出難以以程式設計方式偵測到的錯誤。