Gérer plusieurs utilisateurs

Ce guide du développeur explique comment votre outil de contrôle des règles relatives aux appareils (DPC) peut gérer plusieurs utilisateurs Android sur des appareils dédiés.

Présentation

Votre DPC peut aider plusieurs personnes à partager un même appareil dédié. Votre DPC exécutés sur un appareil entièrement géré peuvent créer et gérer deux types d'utilisateurs:

  • Les utilisateurs secondaires sont les utilisateurs Android dont les applications et les données sont enregistrées séparément. entre les sessions. Vous gérez les utilisateurs à l'aide d'un composant d'administration. Ces utilisateurs sont utile dans les cas où un appareil est repris au début d'une journée de travail, par exemple les chauffeurs-livreurs ou les agents de sécurité.
  • Les utilisateurs éphémères sont les utilisateurs secondaires que le système supprime lorsqu'ils s'arrête, s'éteint ou redémarre. Ces utilisateurs sont utiles pour les cas où les données peuvent être supprimées une fois la session terminée, telles que l'accès public des kiosques Internet.

Vous utilisez votre DPC existant pour gérer l'appareil dédié et l'appareil secondaire utilisateurs. Un composant d'administration de votre DPC se définit comme l'administrateur de la nouvelle utilisateurs lorsque vous les créez.

Utilisateur principal et deux utilisateurs secondaires.
Figure 1. Les utilisateurs principaux et secondaires gérés par les administrateurs depuis le même DPC

Les administrateurs d'un utilisateur secondaire doivent appartenir au même package que l'administrateur du un appareil entièrement géré. Pour simplifier le développement, nous vous recommandons de partager entre l'appareil et les utilisateurs secondaires.

La gestion de plusieurs utilisateurs sur des appareils dédiés nécessite généralement Android 9.0, Cependant, certaines des méthodes utilisées dans ce guide du développeur sont disponibles versions antérieures d'Android.

Utilisateurs secondaires

Les utilisateurs secondaires peuvent se connecter au Wi-Fi et configurer de nouveaux réseaux. Cependant, ils ne peuvent pas modifier ni supprimer des réseaux, pas même les réseaux qu’ils ont créés.

Créer des utilisateurs

Votre DPC peut créer des utilisateurs supplémentaires en arrière-plan, puis les basculer au premier plan. Le processus est presque le même pour les instances secondaires les utilisateurs éphémères. Procédez comme suit dans les administrateurs appareil géré et utilisateur secondaire:

  1. Appelez DevicePolicyManager.createAndManageUser(). Pour créer un utilisateur éphémère, incluez MAKE_USER_EPHEMERAL dans l'argument "flags".
  2. Appeler DevicePolicyManager.startUserInBackground() jusqu'à démarrer l'utilisateur en arrière-plan. L'utilisateur commence à courir, mais vous voudrez pour terminer la configuration avant de placer l'utilisateur au premier plan la personne qui utilise l'appareil.
  3. Dans l'administrateur de l'utilisateur secondaire, appelez DevicePolicyManager.setAffiliationIds() jusqu'à associer le nouvel utilisateur à l'utilisateur principal. Voir Coordination DPC ci-dessous.
  4. De retour dans l'administrateur de l'appareil entièrement géré, appelez DevicePolicyManager.switchUser() pour basculer l'utilisateur vers au premier plan.

L'exemple suivant montre comment ajouter l'étape 1 à votre DPC:

Kotlin

val dpm = getContext().getSystemService(Context.DEVICE_POLICY_SERVICE)
        as DevicePolicyManager

// If possible, reuse an existing affiliation ID across the
// primary user and (later) the ephemeral user.
val identifiers = dpm.getAffiliationIds(adminName)
if (identifiers.isEmpty()) {
    identifiers.add(UUID.randomUUID().toString())
    dpm.setAffiliationIds(adminName, identifiers)
}

// Pass an affiliation ID to the ephemeral user in the admin extras.
val adminExtras = PersistableBundle()
adminExtras.putString(AFFILIATION_ID_KEY, identifiers.first())
// Include any other config for the new user here ...

// Create the ephemeral user, using this component as the admin.
try {
    val ephemeralUser = dpm.createAndManageUser(
            adminName,
            "tmp_user",
            adminName,
            adminExtras,
            DevicePolicyManager.MAKE_USER_EPHEMERAL or
                    DevicePolicyManager.SKIP_SETUP_WIZARD)

} catch (e: UserManager.UserOperationException) {
    if (e.userOperationResult ==
            UserManager.USER_OPERATION_ERROR_MAX_USERS) {
        // Find a way to free up users...
    }
}

Java

DevicePolicyManager dpm = (DevicePolicyManager)
    getContext().getSystemService(Context.DEVICE_POLICY_SERVICE);

// If possible, reuse an existing affiliation ID across the
// primary user and (later) the ephemeral user.
Set<String> identifiers = dpm.getAffiliationIds(adminName);
if (identifiers.isEmpty()) {
  identifiers.add(UUID.randomUUID().toString());
  dpm.setAffiliationIds(adminName, identifiers);
}

// Pass an affiliation ID to the ephemeral user in the admin extras.
PersistableBundle adminExtras = new PersistableBundle();
adminExtras.putString(AFFILIATION_ID_KEY, identifiers.iterator().next());
// Include any other config for the new user here ...

// Create the ephemeral user, using this component as the admin.
try {
  UserHandle ephemeralUser = dpm.createAndManageUser(
      adminName,
      "tmp_user",
      adminName,
      adminExtras,
      DevicePolicyManager.MAKE_USER_EPHEMERAL |
          DevicePolicyManager.SKIP_SETUP_WIZARD);

} catch (UserManager.UserOperationException e) {
  if (e.getUserOperationResult() ==
      UserManager.USER_OPERATION_ERROR_MAX_USERS) {
    // Find a way to free up users...
  }
}

Lorsque vous créez ou démarrez un nouvel utilisateur, vous pouvez vérifier la raison des échecs en interceptant l'exception UserOperationException et en appelant getUserOperationResult() Dépassement du nombre d'utilisateurs sont des raisons courantes d'échec:

La création d'un utilisateur peut prendre un certain temps. Si vous créez fréquemment des utilisateurs, vous pouvez améliorer l'expérience utilisateur en préparant un utilisateur prêt à l'emploi en arrière-plan. Vous devrez peut-être concilier les avantages d'un utilisateur prêt à l'emploi et d'utilisateurs autorisés sur un appareil.

Identification

Après avoir créé un utilisateur, vous devez faire référence à celui-ci avec un numéro de série persistant numéro. Ne conservez pas les UserHandle, car le système les recycle à mesure que vous créer et supprimer des utilisateurs. Pour obtenir le numéro de série, appelez UserManager.getSerialNumberForUser():

Kotlin

// After calling createAndManageUser() use a device-unique serial number
// (that isn’t recycled) to identify the new user.
secondaryUser?.let {
    val userManager = getContext().getSystemService(UserManager::class.java)
    val ephemeralUserId = userManager!!.getSerialNumberForUser(it)
    // Save the serial number to storage  ...
}

Java

// After calling createAndManageUser() use a device-unique serial number
// (that isn’t recycled) to identify the new user.
if (secondaryUser != null) {
  UserManager userManager = getContext().getSystemService(UserManager.class);
  long ephemeralUserId = userManager.getSerialNumberForUser(secondaryUser);
  // Save the serial number to storage  ...
}

Configuration utilisateur

Selon les besoins de vos utilisateurs, vous pouvez personnaliser la configuration utilisateurs. Vous pouvez inclure les options suivantes lorsque vous appelez createAndManageUser():

SKIP_SETUP_WIZARD
Ignore l'exécution de l'assistant de configuration destiné aux nouveaux utilisateurs, qui recherche et installe des mises à jour. invite l'utilisateur à ajouter un compte Google ainsi que les services Google, et définit le verrouillage de l’écran. Cela peut prendre un certain temps et ne pas s'appliquer à tous les cas (des kiosques Internet publics, par exemple).
LEAVE_ALL_SYSTEM_APPS_ENABLED
Laisse toutes les applications système activées pour le nouvel utilisateur. Si vous ne le définissez pas, le nouvel utilisateur ne contient que l'ensemble minimal d'applications dont le téléphone a besoin généralement un explorateur de fichiers, un clavier téléphonique, des contacts et des SMS.

Suivre le cycle de vie des utilisateurs

Votre DPC (s'il s'agit d'un administrateur de l'appareil entièrement géré) pourrait trouver utile de lorsque les utilisateurs secondaires changent. Pour exécuter des tâches de suivi après des modifications, remplacez ces méthodes de rappel dans la sous-classe DeviceAdminReceiver de votre DPC:

onUserStarted()
Appelée après le démarrage d'un utilisateur par le système. Cet utilisateur est peut-être encore en train de configurer ou s'exécuter en arrière-plan. Vous pouvez récupérer l'utilisateur à partir de startedUser .
onUserSwitched()
Appelée après que le système est passé à un autre utilisateur. Vous pouvez obtenir le nouvel utilisateur qui s'exécute désormais au premier plan à partir de l'argument switchedUser.
onUserStopped()
Appelée après que le système a arrêté un utilisateur, car celui-ci s'est déconnecté, est passé à nouvel utilisateur (s'il s'agit d'un utilisateur éphémère) ou votre DPC a arrêté l'utilisateur. Vous pouvez obtenir l'utilisateur à partir de l'argument stoppedUser.
onUserAdded()
Appelée lorsque le système ajoute un utilisateur. En général, les utilisateurs secondaires ne sont pas entièrement configuré lorsque votre DPC reçoit le rappel. Vous pouvez obtenir l'utilisateur à partir du l'argument newUser.
onUserRemoved()
Appelée après la suppression d'un utilisateur par le système. Comme cet utilisateur a déjà été supprimé, vous ne pouvez pas accéder à l'utilisateur représenté par l'argument removedUser.

Pour savoir quand le système place un utilisateur au premier plan ou renvoie un utilisateur vers la en arrière-plan, les applications peuvent enregistrer un récepteur ACTION_USER_FOREGROUND et Annonces ACTION_USER_BACKGROUND.

Découvrir les utilisateurs

L'administrateur d'un appareil entièrement géré peut appeler tous les utilisateurs secondaires DevicePolicyManager.getSecondaryUsers() Résultats inclure tous les utilisateurs secondaires ou éphémères créés par l'administrateur. Les résultats ont également tout utilisateur secondaire (ou invité) qu'une personne utilisant l'appareil pourrait que vous avez créés. Les résultats n'incluent pas les profils professionnels, car ils ne le sont pas les utilisateurs secondaires. L'exemple suivant montre comment utiliser cette méthode:

Kotlin

// The device is stored for the night. Stop all running secondary users.
dpm.getSecondaryUsers(adminName).forEach {
    dpm.stopUser(adminName, it)
}

Java

// The device is stored for the night. Stop all running secondary users.
for (UserHandle user : dpm.getSecondaryUsers(adminName)) {
  dpm.stopUser(adminName, user);
}

Voici d'autres méthodes que vous pouvez appeler pour connaître l'état des utilisateurs secondaires:

DevicePolicyManager.isEphemeralUser()
Appelez cette méthode depuis l'administrateur d'un utilisateur secondaire pour savoir s'il s'agit d'un utilisateur éphémère.
DevicePolicyManager.isAffiliatedUser()
Appelez cette méthode depuis l'administrateur d'un utilisateur secondaire pour savoir si cet utilisateur est affilié à l'utilisateur principal. Pour en savoir plus sur l'affiliation, consultez la page DPC. coordination ci-dessous.

Gestion des utilisateurs

Si vous souhaitez gérer entièrement le cycle de vie des utilisateurs, vous pouvez appeler des API de contrôler précisément quand et comment l'appareil change d'utilisateur. Par exemple : supprimer un compte utilisateur lorsqu'un appareil n'a pas été utilisé pendant un certain temps ou vous pouvez envoyer les commandes non envoyées à un serveur avant la fin de la journée de travail d'une personne.

Se déconnecter

Android 9.0 a ajouté un bouton de déconnexion à l'écran de verrouillage afin qu'une personne utilisant le l'appareil peut mettre fin à sa session. Lorsque vous appuyez sur le bouton, le système arrête l'utilisateur secondaire, supprime l'utilisateur s'il est éphémère, tandis que l'utilisateur principal revient au premier plan. Android masque le bouton lorsque l'utilisateur principal se trouve dans le au premier plan, car l'utilisateur principal ne peut pas se déconnecter.

Android n'affiche pas le bouton "Terminer la session" par défaut, mais votre administrateur (d'un entièrement géré) peuvent l'activer en appelant DevicePolicyManager.setLogoutEnabled() Si vous avez besoin de confirmer l'état actuel du bouton, appeler DevicePolicyManager.isLogoutEnabled()

L'administrateur d'un utilisateur secondaire peut déconnecter l'utilisateur et renvoyer à l'utilisateur principal. Vérifiez tout d'abord que l'utilisateur secondaire et l'utilisateur principal puis appelez DevicePolicyManager.logoutUser(). Si si l'utilisateur déconnecté est un utilisateur éphémère, le système s'arrête, puis supprime utilisateur.

Changer d'utilisateur

Pour passer à un autre utilisateur secondaire, l'administrateur d'un appareil entièrement géré peut appelez DevicePolicyManager.switchUser(). Pour plus de commodité, peut transmettre null pour passer à l'utilisateur principal.

Arrêter un utilisateur

Pour arrêter un utilisateur secondaire, un DPC qui possède un appareil entièrement géré peut appeler DevicePolicyManager.stopUser() Si l'utilisateur arrêté est un utilisateur éphémère, l'utilisateur est arrêté, puis supprimé.

Dans la mesure du possible, nous vous recommandons d'arrêter les utilisateurs afin de rester en dessous de la le nombre maximal d'utilisateurs en cours d'exécution.

Supprimer un espace utilisateur

Pour supprimer définitivement un utilisateur secondaire, un DPC peut appeler l'un des éléments suivants Méthodes DevicePolicyManager:

  • Un administrateur d'un appareil entièrement géré peut appeler removeUser().
  • Un administrateur de l'utilisateur secondaire peut appeler wipeData().

Le système supprime les utilisateurs éphémères lorsqu'ils sont déconnectés, arrêtés ou basculent à l'écart.

Désactiver l'interface utilisateur par défaut

Si votre DPC fournit une interface utilisateur pour gérer les utilisateurs, vous pouvez désactiver l'application intégrée d'Android une interface multi-utilisateur. Pour ce faire, appelez DevicePolicyManager.setLogoutEnabled() et en ajoutant la Restriction DISALLOW_USER_SWITCH telle qu'indiquée dans les l'exemple suivant:

Kotlin

// Explicitly disallow logging out using Android UI (disabled by default).
dpm.setLogoutEnabled(adminName, false)

// Disallow switching users in Android's UI. This DPC can still
// call switchUser() to manage users.
dpm.addUserRestriction(adminName, UserManager.DISALLOW_USER_SWITCH)

Java

// Explicitly disallow logging out using Android UI (disabled by default).
dpm.setLogoutEnabled(adminName, false);

// Disallow switching users in Android's UI. This DPC can still
// call switchUser() to manage users.
dpm.addUserRestriction(adminName, UserManager.DISALLOW_USER_SWITCH);

La personne qui utilise l'appareil ne peut pas ajouter d'utilisateurs secondaires avec l'interface utilisateur intégrée d'Android car les administrateurs d'appareils entièrement gérés ajoutent automatiquement Restriction utilisateur DISALLOW_ADD_USER.

Messages de session

Lorsque la personne qui utilise un appareil passe à un nouvel utilisateur, Android affiche un panneau pour mettez l'interrupteur en surbrillance. Android affiche les messages suivants:

  • Message "Start-user-session" qui s'affiche lorsque l'appareil passe à un appareil secondaire de l'utilisateur principal.
  • Message de session utilisateur final affiché lorsque l'appareil revient à l'utilisateur principal d'un utilisateur secondaire.

Le système n'affiche pas ces messages lorsqu'il passe d'un compte utilisateur secondaire à un autre.

Étant donné que les messages peuvent ne pas convenir à toutes les situations, vous pouvez modifier le texte de ces messages. Par exemple, si votre solution utilise des clés de chiffrement session, vous pouvez le refléter dans des messages de type: Arrêt du navigateur session et suppression des données personnelles...

Le système affiche le message pendant quelques secondes seulement, de sorte que chaque message doit être une phrase courte et claire. Pour personnaliser les messages, votre administrateur peut appeler les méthodes DevicePolicyManager. setStartUserSessionMessage() et setEndUserSessionMessage(), comme indiqué dans l'exemple suivant:

Kotlin

// Short, easy-to-read messages shown at the start and end of a session.
// In your app, store these strings in a localizable resource.
internal val START_USER_SESSION_MESSAGE = "Starting guest session…"
internal val END_USER_SESSION_MESSAGE = "Stopping & clearing data…"

// ...
dpm.setStartUserSessionMessage(adminName, START_USER_SESSION_MESSAGE)
dpm.setEndUserSessionMessage(adminName, END_USER_SESSION_MESSAGE)

Java

// Short, easy-to-read messages shown at the start and end of a session.
// In your app, store these strings in a localizable resource.
private static final String START_USER_SESSION_MESSAGE = "Starting guest session…";
private static final String END_USER_SESSION_MESSAGE = "Stopping & clearing data…";

// ...
dpm.setStartUserSessionMessage(adminName, START_USER_SESSION_MESSAGE);
dpm.setEndUserSessionMessage(adminName, END_USER_SESSION_MESSAGE);

Transmettez null pour supprimer vos messages personnalisés et revenir aux paramètres par défaut d'Android messages. Pour vérifier le texte du message actuel, appelez getStartUserSessionMessage() ou getEndUserSessionMessage()

Votre DPC doit définir des messages localisés. pour les paramètres régionaux actuels de l'utilisateur. Vous devez également modifier les messages modifications des paramètres régionaux de l'utilisateur:

Kotlin

override fun onReceive(context: Context?, intent: Intent?) {
    // Added the <action android:name="android.intent.action.LOCALE_CHANGED" />
    // intent filter for our DeviceAdminReceiver subclass in the app manifest file.
    if (intent?.action === ACTION_LOCALE_CHANGED) {

        // Android's resources return a string suitable for the new locale.
        getManager(context).setStartUserSessionMessage(
                getWho(context),
                context?.getString(R.string.start_user_session_message))

        getManager(context).setEndUserSessionMessage(
                getWho(context),
                context?.getString(R.string.end_user_session_message))
    }
    super.onReceive(context, intent)
}

Java

public void onReceive(Context context, Intent intent) {
  // Added the <action android:name="android.intent.action.LOCALE_CHANGED" />
  // intent filter for our DeviceAdminReceiver subclass in the app manifest file.
  if (intent.getAction().equals(ACTION_LOCALE_CHANGED)) {

    // Android's resources return a string suitable for the new locale.
    getManager(context).setStartUserSessionMessage(
        getWho(context),
        context.getString(R.string.start_user_session_message));

    getManager(context).setEndUserSessionMessage(
        getWho(context),
        context.getString(R.string.end_user_session_message));
  }
  super.onReceive(context, intent);
}

Coordination DPC

La gestion des utilisateurs secondaires a généralement besoin de deux instances de votre DPC, une qui possède l'appareil entièrement géré, tandis que l'autre possède l'utilisateur secondaire. Lors de la création d'un nouvel utilisateur, l'administrateur de l'appareil entièrement géré définit une autre instance en tant qu'administrateur du nouvel utilisateur.

Utilisateurs affiliés

Certaines des API présentées dans ce guide du développeur ne fonctionnent que lorsque les utilisateurs secondaires sont affiliés ; Comme Android désactive certaines fonctionnalités, (journalisation réseau, par exemple) lorsque vous ajoutez des utilisateurs secondaires non affiliés à l'appareil, vous devez affilier les utilisateurs dès que possible. Consultez l'exemple dans Configuration ci-dessous.

Configuration

Configurez de nouveaux utilisateurs secondaires (à partir du DPC qui possède l'utilisateur secondaire) avant permettant aux gens de les utiliser. Vous pouvez effectuer cette configuration depuis la Rappel DeviceAdminReceiver.onEnabled(). Si vous aviez déjà définir des extras d'administrateur dans l'appel à createAndManageUser(), vous pouvez obtenir de l'argument intent. L'exemple suivant montre une affiliation DPC un nouvel utilisateur secondaire dans le rappel:

Kotlin

override fun onEnabled(context: Context?, intent: Intent?) {
    super.onEnabled(context, intent)

    // Get the affiliation ID (our DPC previously put in the extras) and
    // set the ID for this new secondary user.
    intent?.getStringExtra(AFFILIATION_ID_KEY)?.let {
        val dpm = getManager(context)
        dpm.setAffiliationIds(getWho(context), setOf(it))
    }
    // Continue setup of the new secondary user ...
}

Java

public void onEnabled(Context context, Intent intent) {
  // Get the affiliation ID (our DPC previously put in the extras) and
  // set the ID for this new secondary user.
  String affiliationId = intent.getStringExtra(AFFILIATION_ID_KEY);
  if (affiliationId != null) {
    DevicePolicyManager dpm = getManager(context);
    dpm.setAffiliationIds(getWho(context),
        new HashSet<String>(Arrays.asList(affiliationId)));
  }
  // Continue setup of the new secondary user ...
}

RPC entre les DPC

Même si les deux instances DPC s'exécutent sous des utilisateurs distincts, les DPC qui possèdent l’appareil et les utilisateurs secondaires peuvent communiquer entre eux. Étant donné que l'appel d'un autre service DPC dépasse les limites de l'utilisateur, votre DPC ne peut pas appelez bindService() comme vous le feriez normalement Android. Pour s'associer à un service exécuté dans un autre utilisateur, appeler DevicePolicyManager.bindDeviceAdminServiceAsUser()

Utilisateur principal et deux utilisateurs secondaires affiliés qui appellent des RPC.
Figure 2. Administrateurs d'utilisateurs principaux et secondaires affiliés appelant des méthodes de service

Votre DPC ne peut être lié qu'à des services exécutés dans les utilisateurs renvoyés par DevicePolicyManager.getBindDeviceAdminTargetUsers() L'exemple suivant montre comment l'administrateur d'une liaison d'utilisateur secondaire est lié à l'administrateur de l'appareil entièrement géré:

Kotlin

// From a secondary user, the list contains just the primary user.
dpm.getBindDeviceAdminTargetUsers(adminName).forEach {

    // Set up the callbacks for the service connection.
    val intent = Intent(mContext, FullyManagedDeviceService::class.java)
    val serviceconnection = object : ServiceConnection {
        override fun onServiceConnected(componentName: ComponentName,
                                        iBinder: IBinder) {
            // Call methods on service ...
        }
        override fun onServiceDisconnected(componentName: ComponentName) {
            // Clean up or reconnect if needed ...
        }
    }

    // Bind to the service as the primary user [it].
    val bindSuccessful = dpm.bindDeviceAdminServiceAsUser(adminName,
            intent,
            serviceconnection,
            Context.BIND_AUTO_CREATE,
            it)
}

Java

// From a secondary user, the list contains just the primary user.
List<UserHandle> targetUsers = dpm.getBindDeviceAdminTargetUsers(adminName);
if (targetUsers.isEmpty()) {
  // If the users aren't affiliated, the list doesn't contain any users.
  return;
}

// Set up the callbacks for the service connection.
Intent intent = new Intent(mContext, FullyManagedDeviceService.class);
ServiceConnection serviceconnection = new ServiceConnection() {
  @Override
  public void onServiceConnected(
      ComponentName componentName, IBinder iBinder) {
    // Call methods on service ...
  }

  @Override
  public void onServiceDisconnected(ComponentName componentName) {
    // Clean up or reconnect if needed ...
  }
};

// Bind to the service as the primary user.
UserHandle primaryUser = targetUsers.get(0);
boolean bindSuccessful = dpm.bindDeviceAdminServiceAsUser(
    adminName,
    intent,
    serviceconnection,
    Context.BIND_AUTO_CREATE,
    primaryUser);

Ressources supplémentaires

Pour en savoir plus sur les appareils dédiés, consultez les documents suivants: