Gestire più utenti

Questa guida per gli sviluppatori spiega in che modo il controller dei criteri dei dispositivi (DPC) può gestire più utenti Android su dispositivi dedicati.

Panoramica

Il tuo DPC può aiutare più persone a condividere un singolo dispositivo dedicato. Il tuo DPC (controller criteri dispositivi) in esecuzione su un dispositivo completamente gestito può creare e gestire due tipi di utenti:

  • Gli utenti secondari sono utenti Android che hanno salvato app e dati separati. tra una sessione e l'altra. Per gestire l'utente devi utilizzare un componente di amministrazione. Questi utenti sono utile nei casi in cui un dispositivo viene rilevato all'inizio di un turno, come addetti alle consegne o addetti alla sicurezza.
  • Gli utenti temporanei sono utenti secondari che il sistema elimina quando l'utente. si arresta, si allontana o il dispositivo si riavvia. Questi utenti sono utili per i casi in cui i dati possono essere eliminati al termine della sessione, ad esempio l'accesso pubblico kiosk internet.
di Gemini Advanced.

Utilizzi il DPC esistente per gestire il dispositivo dedicato e utenti. Un componente amministratore nel DPC si imposta come amministratore per il nuovo gli utenti quando li crei.

Utente principale e due utenti secondari.
Figura 1. Utenti principali e secondari gestiti dagli amministratori da lo stesso DPC
.

Gli amministratori di un utente secondario devono appartenere allo stesso pacchetto dell'amministratore di dispositivo completamente gestito. Per semplificare lo sviluppo, ti consigliamo di condividere un amministratore tra il dispositivo e gli utenti secondari.

Per gestire più utenti su dispositivi dedicati, in genere è richiesto Android 9.0, tuttavia alcuni dei metodi utilizzati in questa guida per gli sviluppatori sono disponibili in con le versioni precedenti di Android.

Utenti secondari

Gli utenti secondari possono connettersi al Wi-Fi e configurare nuove reti. Tuttavia, non possono modificare o eliminare le reti, neanche quelle che hanno creato.

Creare utenti

Il DPC può creare utenti aggiuntivi in background e poi può cambiarli in primo piano. Il processo è quasi lo stesso sia per gli ambienti secondari per gli utenti temporanei. Implementa i seguenti passaggi negli amministratori del servizio dispositivo gestito e utente secondario:

  1. Chiama il numero DevicePolicyManager.createAndManageUser(). Per creare un utente temporaneo, includi MAKE_USER_EPHEMERAL nell'argomento flags.
  2. Chiama Da DevicePolicyManager.startUserInBackground() a avviare l'utente in background. L'utente inizia a correre, ma vuoi per completare la configurazione prima di portare l'utente in primo piano e mostrarlo a la persona che utilizza il dispositivo.
  3. Nell'amministratore dell'utente secondario, chiama Da DevicePolicyManager.setAffiliationIds() a abbinare il nuovo utente all'utente principale. Consulta Coordinazione DPC di seguito.
  4. Torna all'amministratore del dispositivo completamente gestito, chiama DevicePolicyManager.switchUser() per consentire all'utente di passare in primo piano.

Il seguente esempio mostra come aggiungere il passaggio 1 al 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...
  }
}

Quando crei o avvii un nuovo utente, puoi verificare il motivo degli eventuali errori rilevando l'eccezione UserOperationException e chiamando getUserOperationResult(). Numero di utenti in eccesso sono motivi comuni di errore:

di Gemini Advanced.

La creazione di un utente può richiedere del tempo. Se crei spesso utenti, puoi migliorare l'esperienza utente preparando un utente pronto all'uso in background. Potrebbe essere necessario bilanciare i vantaggi di un utente pronto all'uso con il massimo di utenti consentiti su un dispositivo.

Identificazione

Dopo aver creato un nuovo utente, devi indirizzare a quest'ultimo con un numero seriale permanente. numero. Non rendere permanente UserHandle perché il sistema ricicla questi elementi mentre creare ed eliminare utenti. Recupera il numero di serie chiamando 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  ...
}

Configurazione utente

A seconda delle esigenze degli utenti, puoi personalizzare la configurazione di utenti. Puoi includere i seguenti flag quando chiami createAndManageUser():

SKIP_SETUP_WIZARD
Salta l'esecuzione della configurazione guidata per i nuovi utenti, che verifica la presenza di aggiornamenti e li installa, chiede all'utente di aggiungere un Account Google insieme ai servizi Google e imposta un blocco schermo. Questa operazione può richiedere del tempo e potrebbe non essere applicabile a tutti ad esempio i kiosk internet pubblici.
LEAVE_ALL_SYSTEM_APPS_ENABLED
Lascia tutte le app di sistema attivate nel nuovo utente. Se non imposti questo flag, il nuovo utente contiene solo l'insieme minimo di app di cui il telefono ha bisogno funzionano, in genere un browser di file, un tastierino telefonico, contatti e SMS.

Segui il ciclo di vita dell'utente

Il tuo DPC (se è un amministratore del dispositivo completamente gestito) potrebbe trovare utile sapere quando cambiano utenti secondari. Per eseguire attività successive dopo le modifiche, sostituisci questi metodi di callback nella sottoclasse DeviceAdminReceiver del tuo DPC:

onUserStarted()
Chiamato dopo che il sistema ha avviato un utente. L'utente potrebbe ancora configurare o in esecuzione in background. Puoi recuperare l'utente da startedUser .
onUserSwitched()
Chiamato dopo che il sistema è passato a un altro utente. Puoi far arrivare il nuovo utente attualmente in esecuzione in primo piano dall'argomento switchedUser.
onUserStopped()
Chiamata dopo che il sistema ha interrotto un utente perché è disconnesso, è passato a un nuovo utente (se l'utente è temporaneo) o il tuo DPC ha arrestato l'utente. Puoi ottenere l'utente dall'argomento stoppedUser.
onUserAdded()
Chiamato quando il sistema aggiunge un nuovo utente. In genere, gli utenti secondari non completamente configurato quando il DPC riceve la richiamata. Puoi far accedere l'utente newUser argomento.
onUserRemoved()
Chiamato dopo l'eliminazione di un utente da parte del sistema. Poiché l'utente è già stato eliminato, Non puoi accedere all'utente rappresentato dall'argomento removedUser.

Per sapere quando il sistema mette un utente in primo piano o lo reindirizza allo le app possono registrare un ricevitore ACTION_USER_FOREGROUND e ACTION_USER_BACKGROUND annunci.

Scopri gli utenti

Per recuperare tutti gli utenti secondari, un amministratore di un dispositivo completamente gestito può chiamare DevicePolicyManager.getSecondaryUsers() I risultati include gli utenti secondari o temporanei creati dall'amministratore. Anche i risultati Includono eventuali utenti secondari (o utenti ospiti) che una persona che utilizza il dispositivo potrebbe che hai creato. I risultati non includono profili di lavoro perché non sono utenti secondari. Il seguente esempio mostra come utilizzare questo metodo:

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);
}

Di seguito sono riportati altri metodi che puoi chiamare per scoprire lo stato degli utenti secondari:

DevicePolicyManager.isEphemeralUser()
Chiama questo metodo dall'amministratore di un utente secondario per scoprire se si tratta di un utente temporaneo.
DevicePolicyManager.isAffiliatedUser()
Chiama questo metodo dall'amministratore di un utente secondario per sapere se questo utente affiliato all'utente principale. Per scoprire di più sull'affiliazione, consulta la sezione DPC (controller criteri dispositivi) di coordinamento di seguito.

Gestione utenti

Se vuoi gestire completamente il ciclo di vita dell'utente, puoi chiamare le API per un controllo granulare di quando e come il dispositivo cambia utente. Ad esempio, puoi eliminare un utente quando un dispositivo non è stato utilizzato per un certo periodo di tempo inviare ordini non inviati a un server prima che finisca il turno di una persona.

Esci

Android 9.0 ha aggiunto un pulsante di disconnessione alla schermata di blocco in modo che una persona che utilizza dispositivo può terminare la sessione. Dopo aver toccato il pulsante, il sistema interrompe la utente secondario, elimina l'utente se è temporaneo e l'utente principale torna in primo piano. Android nasconde il pulsante quando l'utente principale è in primo piano perché l'utente principale non riesce a uscire.

Android non mostra il pulsante di fine sessione per impostazione predefinita, ma l'amministratore (di un completamente gestito) può abilitarlo chiamando DevicePolicyManager.setLogoutEnabled() Per conferma lo stato attuale del pulsante, richiama DevicePolicyManager.isLogoutEnabled()

L'amministratore di un utente secondario può disconnettere in modo programmatico l'utente e tornare per l'utente principale. Innanzitutto, verifica che gli utenti secondari e principali siano affiliato, quindi chiama DevicePolicyManager.logoutUser(). Se l'utente disconnesso è un utente temporaneo, il sistema arresta ed elimina utente.

Cambia utente

Per passare a un altro utente secondario, l'amministratore di un dispositivo completamente gestito può chiama DevicePolicyManager.switchUser(). Per praticità, puoi può passare null per passare all'utente principale.

Interrompere un utente

Per interrompere un utente secondario, un DPC che possiede un dispositivo completamente gestito può chiamare DevicePolicyManager.stopUser() Se l'utente bloccato è utente temporaneo, l'utente viene interrotto e poi eliminato.

Ti consigliamo di fermare gli utenti quando possibile per evitare di rimanere al di sotto della soglia il numero massimo di utenti in esecuzione.

Eliminazione di un utente

Per eliminare definitivamente un utente secondario, un DPC può chiamare uno dei seguenti DevicePolicyManager metodi:

  • L'amministratore di un dispositivo completamente gestito può chiamare removeUser().
  • Un amministratore dell'utente secondario può chiamare wipeData().

Il sistema elimina gli utenti temporanei quando sono disconnessi, arrestati o trasferiti. di distanza.

Disattiva l'interfaccia utente predefinita

Se il DPC fornisce un'interfaccia utente per gestire gli utenti, puoi disattivare un'interfaccia multiutente. Puoi farlo chiamando DevicePolicyManager.setLogoutEnabled() e l'aggiunta del parametro DISALLOW_USER_SWITCH come mostrato in nell'esempio seguente:

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 persona che utilizza il dispositivo non può aggiungere utenti secondari con l'UI integrata di Android poiché gli amministratori dei dispositivi completamente gestiti aggiungono automaticamente Limitazione utente DISALLOW_ADD_USER.

Messaggi di sessione

Quando la persona che utilizza un dispositivo passa a un nuovo utente, Android mostra un riquadro per evidenzia l'opzione. Android mostra i seguenti messaggi:

  • Messaggio di avvio della sessione utente mostrato quando il dispositivo passa a una sessione secondaria dell'utente principale.
  • Messaggio di sessione utente finale mostrato quando il dispositivo torna all'utente principale. di un utente secondario.

Il sistema non mostra i messaggi quando si passa da un utente secondario all'altro.

Poiché i messaggi potrebbero non essere adatti a tutte le situazioni, puoi cambiare il testo di questi messaggi. Ad esempio, se la tua soluzione utilizza un utente temporaneo sessioni, puoi segnalarlo nei messaggi, come: Arrestare il browser sessione e eliminazione dei dati personali in corso...

Il sistema mostra il messaggio solo per un paio di secondi, quindi ogni messaggio deve essere una frase breve e chiara. Per personalizzare i messaggi, l'amministratore può chiamare i metodi DevicePolicyManager setStartUserSessionMessage() e setEndUserSessionMessage() come mostrato in nell'esempio seguente:

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);

Passa null per eliminare i tuoi messaggi personalizzati e tornare alle impostazioni predefinite di Android messaggi. Per controllare il testo attuale del messaggio, chiama getStartUserSessionMessage() oppure getEndUserSessionMessage().

Il DPC deve impostare messaggi localizzati per le impostazioni internazionali correnti dell'utente. Devi anche aggiornare i messaggi quando modifiche alle impostazioni internazionali dell'utente:

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);
}

Coordinamento DPC (controller criteri dispositivi)

Per la gestione degli utenti secondari, in genere sono necessarie due istanze del DPC (controller criteri dispositivi), una delle quali il dispositivo completamente gestito, mentre l'altro è proprietario dell'utente secondario. Durante la creazione un nuovo utente, l'amministratore del dispositivo completamente gestito imposta un'altra istanza come amministratore del nuovo utente.

Utenti affiliati

Alcune API in questa guida per gli sviluppatori funzionano solo quando gli utenti secondari sono affiliati. Perché Android disattiva alcune funzionalità (ad esempio il logging di rete) quando aggiungi nuovi utenti secondari non affiliati il dispositivo, dovresti affiliare gli utenti appena possibile. Vedi l'esempio in Configurazione qui sotto.

Configura

Configura i nuovi utenti secondari (dal DPC proprietario dell'utente secondario) prima per consentire agli utenti di utilizzarli. Puoi eseguire questa configurazione DeviceAdminReceiver.onEnabled(). Se in precedenza imposta gli eventuali extra amministrativi della chiamata su createAndManageUser(), puoi ottenere dall'argomento intent. L'esempio seguente mostra un'affiliazione DPC (controller criteri dispositivi) un nuovo utente secondario nel callback:

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 tra DPC (controller criteri dispositivi)

Anche se le due istanze DPC vengono eseguite su utenti separati, proprietari del dispositivo e gli utenti secondari possono comunicare tra loro. Poiché la chiamata a un servizio di un altro DPC supera i confini dell'utente, il DPC non può chiama bindService() come normalmente Android. Per l'associazione a un servizio in esecuzione in un altro utente, richiama DevicePolicyManager.bindDeviceAdminServiceAsUser()

Utente principale e due utenti secondari affiliati che chiamano RPC.
Figura 2. Amministratori di utenti principali e secondari affiliati chiamata ai metodi di servizio
.

Il DPC può essere associato solo ai servizi in esecuzione negli utenti restituiti DevicePolicyManager.getBindDeviceAdminTargetUsers() L'esempio seguente mostra l'amministratore di un'associazione utente secondaria all'amministratore del dispositivo completamente gestito:

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);

Risorse aggiuntive

Per scoprire di più sui dispositivi dedicati, leggi i seguenti documenti: