Explorer les processus Android

Il y a quelques semaines, je corrigeais un bug dans Android Studio et je suis tombé sur la balise « android:process ». (Je travaille chez Google dans l’équipe Android Studio.) Je savais que la balise vous permet de spécifier le processus sur lequel le composant android va s’exécuter. Cependant, je ne connaissais pas tous les détails et le raisonnement derrière les processus Android. J’ai donc lu à ce sujet et écrit cet article pour partager ce que j’ai appris.

Comme toujours, je suis heureux d’être corrigé sur tout ce sur quoi je suis mal informé.

Un aperçu des processus Android

Android est basé sur linux donc « le système Android démarre un nouveau processus Linux pour l’application avec un seul thread d’exécution. Par défaut, tous les composants d’une même application s’exécutent dans le même processus et le même thread (appelé le thread « principal »). » (extrait de : Vue d’ensemble des processus et des threads)

Généralement, le thread « principal » est aussi le thread « UI » ou le thread « événement », car toute modification de l’UI ou traitement des événements se produit sur ce thread. (exception : y̵o̵u̵ ̵c̵a̵n̵ ̵c̵h̵a̵n̵g̵e̵ ̵t̵h̵i̵s̵ ̵b̵y̵ ̵u̵s̵i̵n̵g̵ ̵T̵h̵r̵e̵a̵d̵ ̵A̵n̵n̵o̵t̵a̵t̵i̵o̵n̵s̵.̵ Je me suis trompé, il est seulement possible pour les applications systèmes d’avoir un MainThread et un UIThread différents : « Les outils de construction traitent les annotations @MainThread et @UiThread comme interchangeables, de sorte que vous pouvez appeler des méthodes @UiThread à partir de méthodes @MainThread, et vice versa. Cependant, il est possible qu’un thread UI soit différent du thread principal dans le cas d’apps système avec plusieurs vues sur différents threads. »)

Par défaut, le processus principal (et le thread principal qu’il démarre) s’exécute avec un nom de processus qui est le même que l’applicationId de l’application (déclaré dans le build.gradle de votre app). Ainsi, si vous deviez créer un projet par défaut avec Android Studio, vous obtiendriez une application Android qui s’exécutera sur le thread : com.example.<nom d’utilisateur>.myapplication et le package par défaut correspondant pour votre code.

Ce que fait la balise « android:process »

Par défaut, une application Android n’aura qu’un seul processus. Tous les composants seront exécutés sur le même processus. Lorsque vous déclarez de nouveaux composants dans le manifeste de votre application, vous pouvez utiliser la balise « android:process » pour déclarer un nouveau processus pour ce composant. Comme ceci:

<activity
android:name=".SettingsActivity"
android:process=":setting"
android:label="@string/title_activity_settings">
</activity>

Dans le snippet ci-dessus, je déclare une SettingActivity qui sera exécutée sur le processus local com.example.kelvinma.myapplication:setting. (plus sur local vs global plus tard dans cet article)

Le tag « android:process » peut être appliqué sur les 4 composants android:

  • Activity
  • Service
  • Receiver
  • Provider

et aussi sur le tag Application. Lorsqu’il est appliqué sur le tag Application, tout composant de l’application hérite également de l’android:process à moins qu’il ne soit surchargé par son propre tag android:process.

Je ne suis pas sûr du cas d’utilisation de ce tag sur votre déclaration d’application quand vous pouvez simplement changer votre applicationId à la place. Si vous en connaissez un, dites-le moi.

Un court exemple visuel

Pour illustrer une application multi-processus, supposons que je démarre l’activité par défaut sur mon application Pomodoro puis en utilisant le snippet ci-dessus, je change mon SettingsActivity pour qu’elle s’exécute sur un autre processus. Alors après le démarrage de mon application et le démarrage de SettingsActivity, mon application aura 2 processus:

$ ./adb shell ps | grep kelvin
u0_a61 32175 1669 1292180 47600 SyS_epoll_ b738f2b5 S com.example.kelvinhanma.pomodoro
u0_a61 32223 1669 1284796 43736 SyS_epoll_ b738f2b5 S com.example.kelvinhanma.pomodoro:setting

Cependant, tous les composants s’exécutent implicitement sur le processus par défaut sauf indication contraire par la balise process. Donc, si vous ajoutez android:process=":setting"à votre activité par défaut et que vous démarrez ensuite une autre activité, votre application aura 2 processus:

com.example.kelvinhanma.pomodoro:setting
com.example.kelvinhanma.pomodoro

Parce que l’activité démarrée démarrera sur le processus par défaut car elle n’a pas de balise process définie.

Quand dois-je rendre mon application multi-processus ?

Il y a 2 raisons que je connais pour créer une app multi-processus :

  1. Votre app a des actions distinctes qui doivent être exécutées indépendamment, l’exemple commun est une app de lecture de musique aurait le processus par défaut gérer l’interface utilisateur et un autre processus pour gérer la lecture de la musique.
  2. Votre app frappe des contraintes de mémoire. Android limite l’utilisation de la mémoire vive sur une base par processus. Vous pouvez donc augmenter la limite totale de RAM de votre application en exécutant plusieurs processus. Cependant, puisque les processus ne partagent pas la mémoire, vous ne pouvez pas partager les Singleton entre les processus.

Processus local vs global

Le type de processus dépend de la valeur que vous entrez dans la balise process. Si vous commencez par un deux-points ( » : »), alors le processus est un processus local qui est privé à votre application (le nom complet du processus serait applicationId:processName). Si vous commencez par une lettre minuscule alors c’est un processus global.

Un processus global peut être partagé entre des applications. Souvent, une bibliothèque s’exécutera sur un processus global, de sorte que plusieurs applications peuvent partager le processus pour réduire l’utilisation de la mémoire.

android:process quiz

Finissons avec quelques scénarios, voyez si vous pouvez prédire la réponse.

Q : Que se passe-t-il si vous utilisez un processus global pour définir votre processus à votre id de paquet ? android:process="com.example.kelvinhanma.pomodoro"

A : Votre processus reste inchangé et cela est autorisé. Bien que ce soit une chose inutile et stupide à faire.

Q : Que se passe-t-il si vous l’utilisez pour définir votre processus sur le paquet d’une autre application ? Supposons que j’ai une com.example.kelvinhanma.pomodoro en cours d’exécution sur mon appareil. Je fixe le processus global d’une autre app au même nom et le déploie.

Je me retrouverais avec 2 processus avec le même nom !

./adb shell ps | grep kelvin
u0_a181 28008 630 4324212 66060 SyS_epoll_wait 0 S com.example.kelvinhanma.pomodoro
u0_a179 28287 630 4327384 66200 SyS_epoll_wait 0 S com.example.kelvinhanma.pomodoro

Mais c’est très bien. Les noms de processus n’ont pas besoin d’être uniques. Remarquez que les utilisateurs sont différents (u0_a181, u0_a179) et que les ids des processus sont uniques.

J’espère que vous avez apprécié cet article et que vous avez appris quelque chose. N’hésitez pas à me faire savoir si quelque chose est incorrect!