Création d'applications multi-utilisateurs

Lorsqu'un appareil prend en charge plusieurs utilisateurs , ses applications doivent connaître ces utilisateurs distincts.

Certaines applications doivent avoir certains composants exécutés en tant que singletons et peuvent accepter les demandes de n'importe quel utilisateur. Seules les applications système peuvent actuellement utiliser cette fonctionnalité.

Cette installation :

  • Préserve les ressources
  • Arbitre une ou plusieurs ressources partagées entre les utilisateurs
  • Réduit la surcharge du réseau en utilisant une connexion à un seul serveur

Consultez le diagramme ci-dessous pour une représentation du flux d’autorisations avec plusieurs utilisateurs.

Flux d'autorisations de plusieurs utilisateurs

Figure 1. Autorisations de plusieurs utilisateurs

Activation d'un composant singleton

Pour identifier une application en tant que singleton, ajoutez android:singleUser="true" à votre service, récepteur ou fournisseur dans le manifeste Android.

Le système instanciera ce composant dans le processus exécuté en tant qu'utilisateur 0 uniquement. Toute demande de connexion à ce fournisseur ou service, ou de diffusion vers ce récepteur, émanant de n'importe quel utilisateur sera acheminée vers le processus de l'utilisateur 0. S'il s'agit du seul composant de votre application, une seule instance de votre application s'exécutera.

Les activités de votre package seront toujours lancées dans un processus distinct pour chaque utilisateur, l'UID étant dans la plage UID de cet utilisateur (par exemple 1010034).

Interagir avec les utilisateurs

Définir les autorisations

Ces autorisations sont requises

INTERACT_ACROSS_USERS (signature|system)
INTERACT_ACROSS_USERS_FULL (signature)

Utiliser des API

Utilisez les API suivantes pour rendre les applications conscientes de plusieurs utilisateurs.

  1. Extrayez le descripteur utilisateur des appels Binder entrants :
    • int userHandle = UserHandle.getCallingUserId()
  2. Utilisez de nouvelles API protégées pour démarrer des services, des activités, des diffusions sur un utilisateur spécifique :
    • Context.startActivityAsUser(Intent, UserHandle)
    • Context.bindServiceAsUser(Intent, …, UserHandle)
    • Context.sendBroadcastAsUser(Intent, … , UserHandle)
    • Context.startServiceAsUser(Intent, …, UserHandle)
    UserHandle peut être un utilisateur explicite ou l'un des handles spéciaux : UserHandle.CURRENT ou UserHandle.ALL . CURRENT indique l'utilisateur qui est actuellement au premier plan. Utilisez ALL lorsque vous souhaitez envoyer une diffusion à tous les utilisateurs.
  3. Communiquez avec des composants de votre propre application : (INTERACT_ACROSS_USERS) Ou avec des composants d'autres applications : (INTERACT_ACROSS_USERS_FULL)
  4. Vous devrez peut-être créer des composants proxy qui s'exécutent dans le processus de l'utilisateur et qui accèdent ensuite au composant singleUser de l'utilisateur 0.
  5. Interrogez les utilisateurs et leurs identifiants avec le nouveau service système UserManager :
    • UserManager.getUsers()
    • UserManager.getUserInfo()
    • UserManager.supportsMultipleUsers()
    • UserManager.getUserSerialNumber(int userHandle) - un numéro non recyclé qui correspond à un identifiant utilisateur.
    • UserManager.getUserHandle(int serialNumber)
    • UserManager.getUserProfiles() - renvoie la collection de profils autonomes et gérés, le cas échéant.
  6. Inscrivez-vous pour écouter des utilisateurs spécifiques ou tous et les rappels avec de nouvelles API sur ContentObserver, PackageMonitor, BroadcastReceiver qui fournissent des informations supplémentaires sur l'utilisateur qui a provoqué le rappel.

Services dans plusieurs utilisateurs ou profils

Tous les services n'ont pas besoin d'exécuter une instance dans un autre utilisateur ou profil professionnel. Si votre service système doit uniquement être exécuté en tant qu'utilisateur 0, désactivez les composants du service lors de son exécution sous d'autres utilisateurs pour contribuer à préserver les ressources. L'exemple suivant montre comment procéder aux points d'entrée de votre service :

// Add on all entry points such as boot_completed or other manifest-listed receivers and providers
if (!UserManager.isSystemUser()) {
    // Disable the service
    ComponentName targetServiceName = new ComponentName(this, TargetService.class);
    context.getPackageManager().setComponentEnabledSetting(
        targetServiceName, COMPONENT_ENABLED_STATE_DISABLED, 0);
}

L'exemple pourrait également utiliser PackageManager.setApplicationEnabledSetting() pour désactiver l'intégralité de l'application.