Android 11 (niveau d'API 30) ou version ultérieure est compatible avec le congélateur d'applications mises en cache. Cette fonctionnalité arrête l'exécution des processus mis en cache et réduit l'utilisation des ressources par les applications au comportement anormal qui pourraient tenter de fonctionner lorsqu'elles sont mises en cache.
Le congélateur d'applications mises en cache maintient les applications dans la RAM tout en les gardant hors du processeur. Si Android détermine qu'une application ne doit pas fonctionner, mais qu'elle peut être nécessaire à l'avenir, il gèle le processus de l'application au lieu de l'arrêter. Cela évite un démarrage à froid lorsque l'application est à nouveau nécessaire.
Android gèle les applications mises en cache en migrant leurs processus vers un cgroup gelé. Cela réduit la consommation active et inactive du processeur en présence d'applications actives mises en cache. Vous pouvez activer le congélateur d'applications à l'aide d'un indicateur de configuration système ou d'une option pour les développeurs.
Dans Android 14 (niveau d'API 34) et versions ultérieures, le congélateur d'applications mises en cache inclut les comportements robustes suivants :
- Les processus d'application à l'état mis en cache sont figés 10 secondes après leur passage à cet état.
- Le système dégèle immédiatement un processus d'application figé lors d'un événement de cycle de vie. Ces événements incluent la réception d'un intent, le démarrage d'un service de job ou la reprise d'une activité par l'utilisateur.
ActivityManagerService gère tous les processus d'application et prend des décisions concernant le cycle de vie des applications. CachedAppOptimizer est responsable du gel du processus de l'application.
Lorsqu'un processus d'application est figé, tous ses threads sont suspendus et ne peuvent pas effectuer de travail de processeur tant qu'ils ne sont pas dégelés. Par conséquent, l'application ne peut pas effectuer de récupération de mémoire (GC) ni répondre aux événements de réduction de mémoire. Pour plus d'informations, consultez ComponentCallbacks2.onTrimMemory(int). Pour ce faire, à partir d'Android 14 :
- Les applications avec une instance
Activityvisible sont averties deTRIM_MEMORY_UI_HIDDENdès qu'elles passent en arrière-plan. Les applications qui restent dans un cycle de vie sans UI, comme les applications avec un service de premier plan, peuvent recevoirTRIM_MEMORY_BACKGROUND. Les autres événements de suppression ne sont pas transmis, car lorsque les applications sont éligibles à ces événements, elles sont censées être figées. - Peu de temps après le passage à l'état mis en cache, le système peut demander au runtime de l'application d'effectuer un GC en prévision d'un éventuel gel.
- Lorsqu'un processus d'application est figé, des étapes de compaction de mémoire supplémentaires peuvent se produire, comme l'écriture de pages modifiées dans la mémoire de stockage et l'échange de pages anonymes vers la ZRAM.
- Si tous les processus d'une application particulière sont figés, le système met fin à tous les sockets TCP actifs gérés par l'application. Cela empêche le côté serveur du socket d'envoyer des pings TCP keepalive qui réveilleraient le modem de l'appareil.
Les processus d'application mis en cache sont dégelés lorsque leur état de processus passe de "mis en cache" à un état d'importance supérieure. Pour réduire les événements de dégel dans Android 14 et versions ultérieures, le système met en file d'attente les diffusions enregistrées en contexte lorsque l'application est à l'état mis en cache. Les diffusions enregistrées en contexte sont des récepteurs qu'une application enregistre de manière dynamique en appelant Context.registerReceiver. Le système ne diffuse ces diffusions en file d'attente qu'une fois l'application dégelée. En revanche, le système ne met pas en file d'attente les diffusions déclarées dans le fichier manifeste.
Les diffusions déclarées par le fichier manifeste sont des récepteurs déclarés de manière statique dans AndroidManifest.xml à l'aide de l'élément <receiver>. Le système dégèle immédiatement l'application mise en cache pour diffuser les diffusions déclarées par le fichier manifeste.
Impact sur l'état du système
Android met fin au processus d'application mis en cache le moins récemment utilisé s'il existe plus de MAX_CACHED_PROCESSES processus d'application mis en cache. Sur les appareils compatibles équipés d'Android 14 ou version ultérieure, MAX_CACHED_PROCESSES est considérablement augmenté, ce qui permet aux appareils de conserver beaucoup plus de processus d'application mis en cache dans la RAM.
Le fait de conserver davantage d'applications en cache dans la RAM permet de réduire jusqu'à 30% les démarrages à froid, avec des réductions qui évoluent en fonction de la RAM totale de l'appareil. Dans le même temps, la consommation du processeur par les applications mises en cache est minimisée, ce qui permet de réaliser d'importantes économies de batterie.
Exemptions pour les congélateurs
Dans certaines conditions, un processus d'application peut passer à l'état mis en cache, mais rester non figé. Ces exemptions sont des détails d'implémentation et peuvent changer dans les futures versions d'Android :
- Verrouillage de fichiers : si un processus mis en cache détient un verrouillage de fichier qui bloque d'autres processus non mis en cache, le processus qui détient le verrouillage n'est pas figé.
- Liaisons
BIND_WAIVE_PRIORITY: les processus d'application avec des liaisons entrantes créées à l'aide deContext.BIND_WAIVE_PRIORITYpeuvent passer à l'état mis en cache, mais rester non figés jusqu'à ce que tous les processus client connectés soient également mis en cache. Cette exemption s'applique aux applications multiprocessus, telles que les navigateurs Web utilisant des onglets personnalisés.
Implémenter le congélateur d'applications
Le congélateur d'applications mises en cache utilise le congélateur cgroup v2 du noyau. Les appareils livrés avec un noyau compatible peuvent l'activer. Activez l'option pour les développeurs Suspend execution for cached apps (Suspendre l'exécution pour les applications mises en cache) ou définissez l'indicateur de configuration de l'appareil activity_manager_native_boot use_freezer sur true. Exemple :
adb shell device_config put activity_manager_native_boot use_freezer true && adb rebootLe congélateur est désactivé lorsque vous définissez l'indicateur use_freezer sur false ou que vous désactivez l'option pour les développeurs. Exemple :
adb shell device_config put activity_manager_native_boot use_freezer false && adb rebootVous pouvez activer ou désactiver ce paramètre en modifiant la configuration d'un appareil dans une version ou une mise à jour logicielle.
Pour remplacer MAX_CACHED_PROCESSES, par exemple pour définir la valeur sur 1024 à des fins de test :
adb shell device_config put activity_manager max_cached_processes 1024
adb shell device_config set_sync_disabled_for_tests persistentPour annuler le forçage de MAX_CACHED_PROCESSES :
adb shell device_config delete activity_manager max_cached_processes
adb shell device_config set_sync_disabled_for_tests noneLe congélateur d'applications n'expose pas d'API officielles et ne dispose pas d'un client d'implémentation de référence, mais il utilise les API système masquées setProcessFrozen pour geler un processus individuel et enableFreezer pour activer ou désactiver le gel globalement.
Gérer les fonctionnalités personnalisées
Les processus d'application ne sont pas censés effectuer de tâches lorsqu'ils sont mis en cache, mais certaines applications peuvent avoir des fonctionnalités personnalisées prises en charge par des processus qui sont censés s'exécuter lorsqu'ils sont mis en cache. Lorsque le congélateur d'applications est activé sur un appareil exécutant de telles applications, les processus mis en cache sont figés et peuvent empêcher le fonctionnement des fonctionnalités personnalisées.
Pour contourner ce problème, vous pouvez définir l'état du processus sur "Non mis en cache" avant que le processus n'ait besoin d'effectuer une tâche. Cette modification permet aux applications de rester actives. Par exemple, un service de premier plan lié ou un état de premier plan sont des exemples d'états actifs.
Modes de défaillance courants
Lorsque les processus d'application sont figés, une communication inter-processus (IPC) ou une planification des tâches inappropriées peuvent entraîner l'arrêt de l'application ou un comportement inattendu.
Transactions de liaisons synchrones vers des processus figés
Lorsqu'un processus d'application cliente envoie une transaction Binder synchrone à un processus d'application serveur figé, le système met immédiatement fin au processus d'application serveur. Cela empêche le thread client de se bloquer indéfiniment en attendant une réponse du serveur figé. Le thread client reçoit ensuite RemoteException et tous les écouteurs enregistrés sont déclenchés. Pour plus d'informations, consultez IBinder.linkToDeath.
Cause première : cet échec est généralement dû à un bug dans l'application cliente.
Lorsqu'un client se lie à un service, le processus du serveur est lié au client et
est empêché d'entrer dans l'état mis en cache avant le client. Pour en savoir plus, consultez Context.bindService. Toutefois, une fois que le client appelle Context.unbindService, le processus serveur peut être mis en cache et figé. Si le client continue d'utiliser la référence IBinder mise en cache après la dissociation, il risque de communiquer avec un processus figé.
Pour éviter ce problème, assurez-vous que les applications clientes suppriment les références IBinder immédiatement après l'appel de Context.unbindService.
Dépassement de mémoire tampon de transaction de liaison asynchrone
Lorsqu'un processus d'application serveur reçoit des transactions Binder asynchrones (oneway) pendant qu'il est figé, les transactions sont mises en mémoire tampon dans une mémoire tampon par processus. Si le serveur reçoit trop de transactions asynchrones lorsqu'il est figé, le tampon déborde et le système met fin au processus de l'application serveur.
Pour éviter ce dépassement de tampon, évitez d'envoyer un nombre excessif de transactions Binder asynchrones à des processus susceptibles d'être mis en cache ou figés.
Exécution répétée des tâches planifiées lors de la réactivation
Si une application exécute des tâches répétitives, elle est suspendue pendant que le processus est figé. Pour en savoir plus, consultez ScheduledThreadPoolExecutor.scheduleAtFixedRate ou Timer.scheduleAtFixedRate. Lorsque le processus se débloque, les exécutions manquées accumulées peuvent s'exécuter rapidement, les unes après les autres, pratiquement sans délai.
Pour éviter une vague d'exécutions lorsque l'application se débloque, utilisez scheduleWithFixedDelay au lieu de scheduleAtFixedRate pour les tâches en arrière-plan. Vous pouvez également utiliser WorkManager.
Tester et dépanner le congélateur d'applications
Pour vérifier que le congélateur d'applications fonctionne comme prévu ou pour résoudre les problèmes liés au congélateur, utilisez les outils et commandes de diagnostic suivants :
Commandes du gestionnaire d'activités
Vous pouvez utiliser les commandes adb shell am pour contrôler manuellement le gel et la compression d'un processus spécifique :
Forcer un processus à se figer :
adb shell am freeze <process>Forcer un processus à se débloquer :
adb shell am unfreeze <process>Forcez une compaction complète de la mémoire sur un processus :
adb shell am compact full <process>
Examen de Logcat
Consultez logcat pour afficher les entrées figées et dégelées chaque fois qu'un processus migre vers ou hors du congélateur :
adb logcat | grep -i "\(freezing\|froze\)"Les journaux de motifs de déblocage génèrent des valeurs énumérées à partir de l'énumération du tampon de protocole UnfreezeReason.
Inspection Dumpsys
Pour obtenir la liste des processus figés, utilisez dumpsys activity :
adb shell dumpsys activity | grep -A 20 "Apps frozen:"Vérifiez la présence du fichier /sys/fs/cgroup/uid_0/cgroup.freeze.
ApplicationExitInfo
Pour interroger le motif de l'arrêt d'un processus précédent, consultez ActivityManager.getHistoricalProcessExitReasons.
Si un processus d'application a été arrêté en raison d'un problème lié au congélateur, par exemple la réception d'une transaction de binder synchrone pendant la période de gel, le motif de sortie est défini sur ApplicationExitInfo.REASON_FREEZER.
Traçage Perfetto
Les événements liés au congélateur sont émis sur une piste nommée Freezer sous le processus system_server dans les traces Perfetto :
- Les tranches
FreezeetUnfreezeindiquent quand un processus change d'état. - Les événements
updateAppFreezeStateLSPindiquent quand le serveur système réexamine les attributs du processus pour décider de le geler ou de le dégeler.
Vous pouvez inspecter ces événements directement dans l'UI Perfetto ou les analyser à l'aide de PerfettoSQL :
INCLUDE PERFETTO MODULE slices.with_context;
SELECT *
FROM process_slice
WHERE process_name = "system_server"
AND track_name = "Freezer"
AND (name LIKE "Freeze %" OR name LIKE "Unfreeze %");
Dans la bibliothèque standard PerfettoSQL, les événements de blocage sont également récapitulés dans le tableau android_freezer_events.