Processus et cycle de vie d'une application

Dans la plupart des cas, chaque application Android s'exécute dans son propre processus Linux. Ce processus est créé pour l'application lorsqu'une partie de son code doit s'exécuter jusqu'à ce que le système doive récupérer sa mémoire pour l'utiliser par d'autres applications et qu'elle n'est plus nécessaire.

Une fonctionnalité inhabituelle et fondamentale d'Android est que la durée de vie d'un processus d'application n'est pas directement contrôlée par l'application elle-même. Elle est déterminée par le système via une combinaison des parties de l'application dont le système sait qu'elles sont en cours d'exécution, l'importance de ces éléments pour l'utilisateur et la quantité de mémoire globale disponible dans le système.

Il est important que les développeurs d'applications comprennent l'impact des différents composants d'application (en particulier Activity, Service et BroadcastReceiver) sur la durée de vie du processus de l'application. Une utilisation incorrecte de ces composants peut entraîner l'arrêt du processus de l'application par le système pendant qu'il effectue un travail important.

Un exemple courant de bug de cycle de vie d'un processus est BroadcastReceiver qui démarre un thread lorsqu'il reçoit Intent dans sa méthode BroadcastReceiver.onReceive(), puis renvoie de la fonction. Une fois renvoyée, le système considère que le BroadcastReceiver n'est plus actif et que son processus d'hébergement n'est plus nécessaire, sauf si d'autres composants d'application y sont actifs.

Ainsi, le système peut arrêter le processus à tout moment pour récupérer de la mémoire et, ce faisant, mettre fin au thread généré qui s'exécute dans le processus. La solution à ce problème consiste généralement à programmer un JobService à partir de BroadcastReceiver afin que le système sache qu'une tâche est en cours dans le processus.

Pour déterminer les processus à arrêter en cas de mémoire insuffisante, Android place chaque processus dans une hiérarchie d'importance en fonction des composants qui y sont exécutés et de l'état de ces composants. Voici les types de processus par ordre d’importance:

  1. Un processus de premier plan est nécessaire pour ce que fait actuellement l'utilisateur. Différents composants d'application peuvent entraîner le traitement de son processus conteneur au premier plan de différentes manières. Un processus est considéré comme étant au premier plan si l'une des conditions suivantes est remplie :
  2. Il n'existe que quelques processus de ce type dans le système, et ceux-ci ne sont supprimés qu'en dernier recours si la mémoire est si faible que même ces processus ne peuvent pas continuer à s'exécuter. En règle générale, si cela se produit, l'appareil a atteint un état de pagination de mémoire. Cette action est donc nécessaire pour que l'interface utilisateur reste réactive.

  3. Un processus visible effectue une tâche dont l'utilisateur a connaissance. Sa suppression a donc un impact négatif notable sur l'expérience utilisateur. Un processus est considéré comme visible dans les conditions suivantes :
    • Elle exécute un Activity visible par l'utilisateur à l'écran, mais pas au premier plan (sa méthode onPause() a été appelée). Cela peut se produire, par exemple, si le Activity de premier plan s'affiche sous la forme d'une boîte de dialogue permettant de voir l'Activity précédent en arrière-plan.
    • Elle dispose d'un Service qui s'exécute en tant que service de premier plan via Service.startForeground() (qui demande au système de traiter le service comme un élément connu de l'utilisateur, ou essentiellement comme s'il était visible).
    • Il héberge un service que le système utilise pour une fonctionnalité particulière dont l'utilisateur a connaissance, comme un fond d'écran animé ou un service de mode de saisie.

    Le nombre de processus exécutés dans le système est moins limité que celui des processus de premier plan, tout en restant relativement contrôlé. Ces processus sont considérés comme extrêmement importants et ne sont pas arrêtés, sauf si cela est nécessaire pour que tous les processus de premier plan continuent de s'exécuter.

  4. Un processus de service est un processus contenant un Service démarré avec la méthode startService(). Bien que ces processus ne soient pas directement visibles par l'utilisateur, ils effectuent généralement des tâches qui l'intéressent (telles que l'importation ou le téléchargement de données réseau en arrière-plan). Le système continue donc toujours à s'exécuter, sauf s'il n'y a pas assez de mémoire pour conserver tous les processus visibles au premier plan.

    L'importance des services qui s'exécutent depuis longtemps (par exemple, 30 minutes ou plus) peut être rétrogradée pour permettre à leur processus d'être placé dans la liste mise en cache.

    Les processus qui doivent être exécutés sur une longue période peuvent être créés avec setForeground. S'il s'agit d'un processus périodique nécessitant une heure d'exécution stricte, il peut être planifié via AlarmManager. Pour en savoir plus, consultez Compatibilité avec les workers de longue durée. Cela permet d'éviter les situations dans lesquelles des services de longue durée qui utilisent des ressources excessives (par exemple, une fuite de mémoire) empêchent le système d'offrir une bonne expérience utilisateur.

  5. Un processus en cache n'est pas nécessaire actuellement. Le système est donc libre de le fermer si nécessaire lorsque des ressources telles que la mémoire sont nécessaires ailleurs. Dans un système au comportement normal, ce sont les seuls processus impliqués dans la gestion des ressources.

    Un système en bon état de fonctionnement dispose de plusieurs processus mis en cache toujours disponibles pour permettre un basculement efficace entre les applications, et arrête régulièrement les applications mises en cache selon les besoins. Ce n'est que dans des situations très critiques que le système atteint un point où tous les processus mis en cache sont arrêtés et qu'il doit commencer à supprimer les processus du service.

    Étant donné que les processus mis en cache peuvent être supprimés par le système à tout moment, les applications doivent cesser de fonctionner tant qu'elles sont à l'état mis en cache. Si un travail critique pour l'utilisateur doit être effectué par l'application, elle doit utiliser les API ci-dessus pour exécuter les tâches à partir d'un état de processus actif.

    Les processus mis en cache contiennent souvent une ou plusieurs instances Activity qui ne sont pas actuellement visibles par l'utilisateur (leur méthode onStop() a été appelée et renvoyée). S'ils implémentent correctement leur cycle de vie Activity lorsque le système supprime ces processus, cela n'a aucune incidence sur l'expérience de l'utilisateur lorsqu'il revient dans cette application. L'état précédemment enregistré peut être restauré lorsque l'activité associée est recréée dans un nouveau processus. Sachez qu'il n'est pas garanti que onDestroy() soit appelé si un processus est arrêté par le système. Pour en savoir plus, consultez Activity.

    À partir d'Android 13, un processus d'application peut recevoir une durée d'exécution limitée ou inexistante jusqu'à ce qu'il passe à l'un des états de cycle de vie actifs ci-dessus.

    Les processus mis en cache sont conservés dans une liste. Les règles de commande exactes de cette liste correspondent à un détail d'implémentation de la plate-forme. En règle générale, il tente de conserver des processus plus utiles, tels que ceux hébergeant l'application d'accueil de l'utilisateur ou la dernière activité qu'il a vue, avant d'autres types de processus. D'autres règles d'arrêt de processus peuvent également être appliquées, telles que la définition de limites strictes sur le nombre de processus autorisés ou la limitation de la durée pendant laquelle un processus peut rester en cache en continu.

Lorsqu'il décide de la classification d'un processus, le système base sa décision sur le niveau le plus important parmi tous les composants actuellement actifs dans le processus. Consultez la documentation Activity, Service et BroadcastReceiver pour en savoir plus sur la manière dont chacun de ces composants contribue au cycle de vie global d'un processus et de l'application.

La priorité d'un processus peut également être augmentée en fonction d'autres dépendances qu'un processus a envers lui. Par exemple, si le processus A est lié à un Service avec l'indicateur Context.BIND_AUTO_CREATE ou utilise un ContentProvider dans le processus B, la classification du processus B est toujours au moins aussi importante que celle du processus A.