Limites d'exécution en arrière-plan

Chaque fois qu'une application s'exécute en arrière-plan, elle consomme certaines des ressources limitées de l'appareil, comme la RAM. Cela peut nuire à l'expérience utilisateur, en particulier si l'utilisateur utilise une application gourmande en ressources, comme jouer à un jeu ou regarder une vidéo. Pour améliorer l'expérience utilisateur, Android 8.0 (niveau d'API 26) impose des limites aux fonctionnalités des applications lorsqu'elles s'exécutent en arrière-plan. Ce document décrit les modifications apportées au système d'exploitation et comment mettre à jour votre application pour qu'elle fonctionne correctement avec les nouvelles limites.

Présentation

De nombreuses applications et services Android peuvent s'exécuter simultanément. Par exemple, un utilisateur peut jouer à un jeu dans une fenêtre tout en parcourant le Web dans une autre et en utilisant une troisième application pour écouter de la musique. Plus d'applications sont exécutées en même temps, plus la charge est importante sur le système. Si des applications ou des services supplémentaires s'exécutent en arrière-plan, cela entraîne des charges supplémentaires sur le système, ce qui peut entraîner une mauvaise expérience utilisateur. Par exemple, l'application de musique peut être arrêtée soudainement.

Pour réduire le risque de ces problèmes, Android 8.0 limite les actions que les applications peuvent effectuer lorsque les utilisateurs n'interagissent pas directement avec elles. Les applications sont limitées de deux manières:

  • Limites des services en arrière-plan: lorsqu'une application est inactive, son utilisation des services en arrière-plan est limitée. Cela ne s'applique pas aux services de premier plan, qui sont plus visibles par l'utilisateur.

  • Limites de diffusion: à quelques exceptions près, les applications ne peuvent pas utiliser leur fichier manifeste pour s'inscrire aux diffusions implicites. Ils peuvent toujours s'inscrire à ces diffusions au moment de l'exécution et utiliser le fichier manifeste pour s'inscrire à des diffusions explicites et à des diffusions ciblées spécifiquement sur leur application.

Dans la plupart des cas, les applications peuvent contourner ces limites en utilisant des tâches JobScheduler. Cette approche permet à une application de s'organiser pour effectuer des tâches lorsqu'elle n'est pas en cours d'exécution, mais laisse au système la possibilité de planifier ces tâches de manière à ne pas affecter l'expérience utilisateur. Android 8.0 apporte plusieurs améliorations à JobScheduler qui facilitent le remplacement des services et des broadcast receivers par des tâches planifiées. Pour en savoir plus, consultez la section Améliorations apportées à JobScheduler.

Limites des services en arrière-plan

Les services exécutés en arrière-plan peuvent consommer les ressources de l'appareil, ce qui peut nuire à l'expérience utilisateur. Pour atténuer ce problème, le système applique un certain nombre de limites aux services.

Le système fait la distinction entre les applications de premier plan et les applications en arrière-plan. (La définition de l'arrière-plan à des fins de limitation des services est distincte de celle utilisée par la gestion de la mémoire. Une application peut être en arrière-plan en ce qui concerne la gestion de la mémoire, mais au premier plan en ce qui concerne sa capacité à lancer des services.) Une application est considérée comme étant au premier plan si l'une des conditions suivantes est remplie:

  • Elle comporte une activité visible, que l'activité soit lancée ou mise en veille.
  • Elle dispose d'un service de premier plan.
  • Une autre application de premier plan est connectée à l'application, soit en la liant à l'un de ses services, soit en utilisant l'un de ses fournisseurs de contenu. Par exemple, l'application est au premier plan si une autre application se lie à ses :
    • IME
    • Service de fond d'écran
    • Outil d'écoute des notifications
    • Service vocal ou de SMS

Si aucune de ces conditions n'est remplie, l'application est considérée comme en arrière-plan.

Lorsqu'une application est au premier plan, elle peut créer et exécuter librement des services de premier plan et d'arrière-plan. Lorsqu'une application passe en arrière-plan, elle dispose d'une période de plusieurs minutes pendant laquelle elle est toujours autorisée à créer et à utiliser des services. À la fin de cette période, l'application est considérée comme inutilisée. À ce stade, le système arrête les services en arrière-plan de l'application, comme si l'application avait appelé les méthodes Service.stopSelf() des services.

Dans certains cas, une application en arrière-plan est placée sur une liste d'autorisation temporaire pendant plusieurs minutes. Lorsqu'une application figure sur la liste d'autorisation, elle peut lancer des services sans limite et ses services en arrière-plan sont autorisés à s'exécuter. Une application est placée sur la liste d'autorisation lorsqu'elle gère une tâche visible par l'utilisateur, par exemple:

Dans de nombreux cas, votre application peut remplacer les services en arrière-plan par des tâches JobScheduler. Par exemple, CoolPhotoApp doit vérifier si l'utilisateur a reçu des photos partagées par des amis, même si l'application n'est pas en cours d'exécution au premier plan. Auparavant, l'application utilisait un service en arrière-plan qui vérifiait avec le stockage cloud de l'application. Pour migrer vers Android 8.0 (niveau d'API 26), le développeur remplace le service en arrière-plan par une tâche planifiée, qui est lancée périodiquement, interroge le serveur, puis s'arrête.

Avant Android 8.0, la méthode habituelle pour créer un service de premier plan consistait à créer un service d'arrière-plan, puis à le promouvoir au premier plan. Avec Android 8.0, il existe une complication : le système n'autorise pas une application en arrière-plan à créer un service en arrière-plan. C'est pourquoi Android 8.0 introduit la nouvelle méthode startForegroundService() pour démarrer un nouveau service au premier plan. Une fois que le système a créé le service, l'application dispose de cinq secondes pour appeler la méthode [startForeground()](/reference/android/app/Service#startForeground(int, android.app.Notification) du service pour afficher la notification visible par l'utilisateur du nouveau service. Si l'application n'appelle pas startForeground() dans le délai imparti, le système arrête le service et déclare l'application comme étant ANR.

Limites de diffusion

Si une application s'inscrit pour recevoir des diffusions, le récepteur de l'application consomme des ressources chaque fois que la diffusion est envoyée. Cela peut entraîner des problèmes si trop d'applications s'inscrivent pour recevoir des diffusions en fonction d'événements système. Un événement système qui déclenche une diffusion peut entraîner la consommation rapide de ressources par toutes ces applications, ce qui dégrade l'expérience utilisateur. Pour atténuer ce problème, Android 7.0 (niveau d'API 24) a imposé des limites aux diffusions, comme décrit dans la section Optimisation en arrière-plan. Android 8.0 (niveau d'API 26) rend ces restrictions plus strictes.

  • Les applications qui ciblent Android 8.0 ou version ultérieure ne peuvent plus enregistrer de broadcast receivers pour les diffusions implicites dans leur fichier manifeste, sauf si la diffusion est limitée à cette application en particulier. Un broadcast implicite est un broadcast qui ne cible pas de composant spécifique dans une application. Par exemple, ACTION_PACKAGE_REPLACED est envoyé à tous les écouteurs enregistrés dans toutes les applications pour leur indiquer qu'un package de l'appareil a été remplacé. Étant donné que la diffusion est implicite, elle ne sera pas envoyée aux récepteurs enregistrés dans le fichier manifeste dans les applications qui ciblent Android 8.0 ou une version ultérieure. ACTION_MY_PACKAGE_REPLACED est également une diffusion implicite, mais comme elle n'est envoyée qu'à l'application dont le package a été remplacé, elle sera transmise aux récepteurs enregistrés dans le fichier manifeste.
  • Les applications peuvent continuer à s'inscrire aux diffusions explicites dans leurs fichiers manifestes.
  • Les applications peuvent utiliser Context.registerReceiver() au moment de l'exécution pour enregistrer un récepteur pour toute diffusion, qu'elle soit implicite ou explicite.
  • Les diffusions qui nécessitent une autorisation de signature sont exemptées de cette restriction, car elles ne sont envoyées qu'aux applications signées avec le même certificat, et non à toutes les applications de l'appareil.

Dans de nombreux cas, les applications qui s'étaient précédemment enregistrées pour une diffusion implicite peuvent obtenir une fonctionnalité similaire à l'aide d'une tâche JobScheduler. Par exemple, une application de photos sur les réseaux sociaux peut être amenée à nettoyer ses données de temps en temps, et préfère le faire lorsque l'appareil est connecté à un chargeur. Auparavant, l'application enregistrait un récepteur pour ACTION_POWER_CONNECTED dans son fichier manifeste. Lorsque l'application recevait cette diffusion, elle vérifiait si un nettoyage était nécessaire. Pour migrer vers Android 8.0 ou version ultérieure, l'application supprime ce récepteur de son fichier manifeste. À la place, l'application planifie une tâche de nettoyage qui s'exécute lorsque l'appareil est inactif et en charge.

Guide de migration

Par défaut, ces modifications ne concernent que les applications qui ciblent Android 8.0 (niveau d'API 26) ou version ultérieure. Toutefois, les utilisateurs peuvent activer ces restrictions pour n'importe quelle application depuis l'écran Settings (Paramètres), même si l'application cible un niveau d'API inférieur à 26. Vous devrez peut-être mettre à jour votre application pour respecter les nouvelles limites.

Vérifiez comment votre application utilise les services. Si votre application s'appuie sur des services qui s'exécutent en arrière-plan lorsque votre application est inactive, vous devrez les remplacer. Voici quelques solutions possibles:

  • Si votre application doit créer un service de premier plan alors qu'elle est en arrière-plan, utilisez la méthode startForegroundService() au lieu de startService().
  • Si l'utilisateur peut remarquer le service, faites-en un service de premier plan. Par exemple, un service qui lit de l'audio doit toujours être un service de premier plan. Créez le service à l'aide de la méthode startForegroundService() au lieu de startService().
  • Trouvez un moyen de dupliquer la fonctionnalité du service avec une tâche planifiée. Si le service n'effectue pas une action immédiatement visible par l'utilisateur, vous devriez généralement pouvoir utiliser une tâche planifiée à la place.
  • Utilisez FCM pour réveiller sélectivement votre application lorsque des événements réseau se produisent, plutôt que d'effectuer une interrogation en arrière-plan.
  • Différez les tâches en arrière-plan jusqu'à ce que l'application soit naturellement au premier plan.

Examinez les broadcast receivers définis dans le fichier manifeste de votre application. Si votre fichier manifeste déclare un récepteur pour une diffusion implicite affectée, vous devez le remplacer. Voici quelques solutions possibles:

  • Créez le destinataire au moment de l'exécution en appelant Context.registerReceiver() au lieu de le déclarer dans le fichier manifeste.
  • Utilisez une tâche planifiée pour vérifier la condition qui aurait déclenché la diffusion implicite.