À partir d'Android 13, de nouveaux framebuffers, utilisés lors de la composition client, sont alloués chaque fois que la résolution de l'écran change. Cette allocation est effectuée par SurfaceFlinger lors du prochain cycle invalidate après un changement de résolution.
Gestion du framebuffer lors des changements de résolution
Les changements de résolution se produisent dans l'un des deux scénarios suivants :
Un événement de branchement à chaud, initié par Hardware Composer (HWC), qui se produit lors du passage d'un écran externe à un autre écran externe dont la résolution par défaut est différente.
Lors d'un événement de branchement à chaud, les handles des anciens tampons de frame sont libérés lorsque les anciennes données d'affichage sont désallouées.
Il s'agit d'un changement de mode d'affichage initié par SurfaceFlinger, qui se produit lorsque l'utilisateur modifie la résolution avec les paramètres utilisateur ou lorsqu'une application modifie la résolution avec
preferredDisplayModeId
.Lors d'un changement de mode d'affichage, les handles des framebuffers client existants sont libérés par SurfaceFlinger avant d'appeler
setActiveConfig
ousetActiveConfigWithConstraints
.
Pour éviter des problèmes catastrophiques, tels que la fragmentation de la mémoire, sur les appareils qui ne réservent pas suffisamment de mémoire pour les anciens et les nouveaux framebuffers, il est essentiel que HWC cesse d'utiliser les anciens framebuffers et libère tous les handles de ces framebuffers, comme indiqué dans les cas suivants :
Pour les événements de branchement à chaud, immédiatement avant d'appeler
onHotplug
.Pour les changements de mode, immédiatement après l'appel à
setActiveConfig
ousetActiveConfigWithConstraints
.
La libération des handles permet de désallouer complètement la mémoire du framebuffer avant l'allocation de nouveaux framebuffers que SurfaceFlinger effectue lors du prochain cycle invalidate.
Recommandations pour la gestion des framebuffers
Si HWC ne libère pas les handles des anciens framebuffers à temps, la nouvelle allocation de framebuffer a lieu avant la désallocation de l'ancien framebuffer. Cela peut entraîner des problèmes catastrophiques lorsque la nouvelle allocation échoue en raison d'une fragmentation ou d'autres problèmes. Pire encore, si HWC ne libère pas du tout ces handles, une fuite de mémoire peut se produire.
Pour éviter les échecs d'allocation catastrophiques, suivez ces recommandations :
Si HWC doit continuer à utiliser les anciens framebuffers client jusqu'à ce que les nouveaux soient fournis, il est essentiel de réserver suffisamment de mémoire pour les anciens et les nouveaux framebuffers, et éventuellement d'exécuter des algorithmes de défragmentation sur l'espace mémoire des framebuffers.
Allouez un pool de mémoire dédié aux tampons de frame, distinct du reste de la mémoire tampon graphique. C'est important, car entre la libération et la réattribution des framebuffers, un processus tiers peut tenter d'allouer de la mémoire graphique. Si le même pool de mémoire graphique est utilisé par le tampon de trame et si la mémoire graphique est pleine, le processus tiers peut occuper la mémoire graphique précédemment allouée par un tampon de trame, laissant ainsi une mémoire insuffisante pour la réallocation du tampon de trame ou, éventuellement, fragmentant l'espace mémoire.
Tester la gestion du framebuffer
Nous conseillons aux OEM de tester la bonne gestion de la mémoire du framebuffer client lors des changements de résolution de leur appareil, comme décrit ci-dessous :
Pour les événements de branchement à chaud, il vous suffit de débrancher et de rebrancher deux écrans différents avec des résolutions différentes.
Pour les changements de mode, utilisez le test
ModeSwitchingTestActivity
CTS Verifier pour lancer un changement de mode afin de tester le comportement de la mémoire du framebuffer. Ce test peut identifier visuellement les problèmes difficiles à détecter par programmation.