Cómo administrar varios usuarios

En esta guía para desarrolladores, se explica cómo el controlador de política de dispositivo (DPC) puede Administrar varios usuarios de Android con dispositivos exclusivos

Descripción general

Tu DPC puede ayudar a varias personas a compartir un solo dispositivo dedicado. Tu DPC que se ejecutan en un dispositivo completamente administrado pueden crear y administrar dos tipos de usuarios:

  • Los usuarios secundarios son usuarios de Android con apps y datos independientes guardados entre sesiones. Administras al usuario con un componente de administrador. Estos usuarios son útil para los casos en que se retira un dispositivo al inicio de un turno, como repartidores o trabajadores de seguridad.
  • Los usuarios efímeros son usuarios secundarios que el sistema borra cuando el usuario se detenga, cambie o el dispositivo se reinicie. Estos usuarios son útiles para casos que permiten borrar los datos luego de que finaliza la sesión, como las políticas quioscos de Internet.

Usas tu DPC existente para administrar el dispositivo de uso específico y el dispositivo usuarios. Un componente de administrador de tu DPC se establece como administrador de los nuevos controladores usuarios cuando los creas.

Usuario principal y dos usuarios secundarios
Figura 1: Usuarios principales y secundarios gestionados por administradores desde el mismo DPC

Los administradores de un usuario secundario deben pertenecer al mismo paquete que el administrador del completamente administrado. Para simplificar el desarrollo, recomendamos compartir un administrador entre el dispositivo y los usuarios secundarios.

Para administrar varios usuarios en dispositivos exclusivos, por lo general, se requiere Android 9.0, Sin embargo, algunos de los métodos que se usan en esta guía para desarrolladores están disponibles en versiones anteriores de Android.

Usuarios secundarios

Los usuarios secundarios pueden conectarse a Wi-Fi y configurar nuevas redes. Sin embargo, no pueden editar ni eliminar redes, ni siquiera las que crearon.

Crea usuarios

Tu DPC puede crear usuarios adicionales en segundo plano y, luego, cambiarlos a primer plano. El proceso es casi el mismo para las políticas de usuarios efímeros. Implementa los siguientes pasos en los administradores de dispositivo administrado y usuario secundario:

  1. Llama a DevicePolicyManager.createAndManageUser(). Para crear un usuario efímero, incluye MAKE_USER_EPHEMERAL en el argumento de marcas
  2. Llamada DevicePolicyManager.startUserInBackground() a iniciar el usuario en segundo plano. El usuario comienza a correr, pero querrás para finalizar la configuración antes de llevar al usuario al primer plano y mostrarlo al la persona que usa el dispositivo.
  3. En el administrador del usuario secundario, llama DevicePolicyManager.setAffiliationIds() a afiliar el usuario nuevo al usuario principal. Consulta Coordinación del DPC a continuación.
  4. De vuelta en el administrador del dispositivo completamente administrado, llama DevicePolicyManager.switchUser() para cambiar el usuario a en primer plano.

En el siguiente ejemplo, se muestra cómo agregar el paso 1 a tu 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...
  }
}

Cuando creas o inicias un usuario nuevo, puedes verificar el motivo de las fallas captando la excepción UserOperationException y llamando getUserOperationResult() Superar al usuario límites son motivos de falla comunes:

Crear un usuario puede llevar un tiempo. Si creas usuarios con frecuencia, puedes mejorar la experiencia del usuario preparando en segundo plano a un usuario listo para usar. Tal vez debas equilibrar las ventajas de un usuario listo para usar con la máxima la cantidad de usuarios permitidos en un dispositivo.

Identificación

Después de crear un usuario nuevo, debes referirte al usuario con un número de serie persistente de la fila. No conserves el UserHandle, ya que el sistema los recicla a medida que crear y borrar usuarios. Llama para obtener el número de serie 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  ...
}

Configuración del usuario

Según las necesidades de tus usuarios, puedes personalizar la configuración de usuarios. Puedes incluir las siguientes marcas cuando llames a createAndManageUser():

SKIP_SETUP_WIZARD
Omite la ejecución del asistente de configuración de usuarios nuevos que busca actualizaciones y las instala. le solicita al usuario que agregue una Cuenta de Google junto con los servicios de Google un bloqueo de pantalla. Este proceso puede demorar un tiempo y es posible que no se aplique a todos los casos. usuarios, como los kioscos de Internet públicos.
LEAVE_ALL_SYSTEM_APPS_ENABLED
Permite todas las apps del sistema habilitadas para el usuario nuevo. Si no estableces esta marca, el usuario nuevo contenga solo el conjunto mínimo de aplicaciones que el teléfono necesita normalmente, a través de un navegador de archivos, un marcador de teléfono, contactos y mensajes SMS.

Sigue el ciclo de vida del usuario

Tu DPC (si es un administrador de un dispositivo completamente administrado) podría resultarle útil sepa cuándo cambian los usuarios secundarios. Para ejecutar tareas de seguimiento después de los cambios, anula estos métodos de devolución de llamada en la subclase DeviceAdminReceiver de tu DPC:

onUserStarted()
Se llama después de que el sistema inicia un usuario. Es posible que este usuario aún esté configurando se esté ejecutando en segundo plano. Puedes obtener el usuario desde startedUser .
onUserSwitched()
Se llama después de que el sistema cambia a un usuario diferente. Puedes obtener el usuario nuevo que ahora se ejecuta en primer plano desde el argumento switchedUser.
onUserStopped()
Se llama después de que el sistema detiene a un usuario porque salió de la cuenta, cambia a un usuario nuevo (si el usuario es efímero) o tu DPC detuvo al usuario. Puedes obtener usuario a partir del argumento stoppedUser.
onUserAdded()
Se llama cuando el sistema agrega un usuario nuevo. Por lo general, los usuarios secundarios no son completamente configurada cuando tu DPC reciba la devolución de llamada. Puedes obtener el usuario del newUser.
onUserRemoved()
Se llama después de que el sistema borra un usuario. Como el usuario ya se borró, No puedes acceder al usuario representado por el argumento removedUser.

Para saber cuándo el sistema lleva a un usuario al primer plano o lo envía a la en segundo plano, las apps pueden registrar un receptor para la ACTION_USER_FOREGROUND y ACTION_USER_BACKGROUND transmisiones.

Descubre usuarios

Para obtener todos los usuarios secundarios, un administrador de un dispositivo completamente administrado puede llamar DevicePolicyManager.getSecondaryUsers() Resultados incluir a los usuarios secundarios o efímeros que haya creado el administrador. Los resultados también incluir a los usuarios secundarios (o usuarios invitados) que una persona que usa el dispositivo pueda que creaste. Los resultados no incluyen perfiles de trabajo porque no están usuarios secundarios. En el siguiente ejemplo, se muestra cómo puedes usar este método:

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

Estos son otros métodos que puedes llamar para averiguar el estado de los usuarios secundarios:

DevicePolicyManager.isEphemeralUser()
Llama a este método desde el administrador de un usuario secundario para averiguar si se trata de un como un usuario efímero.
DevicePolicyManager.isAffiliatedUser()
Llama a este método desde el administrador de un usuario secundario para averiguar si este usuario están afiliadas al usuario principal. Para obtener más información sobre la afiliación, consulta DPC coordinación a continuación.

Administración de usuarios

Si deseas administrar completamente el ciclo de vida del usuario, puedes llamar a las APIs para control detallado del momento y la manera en que el dispositivo cambia de usuario. Por ejemplo, puedes borrar un usuario cuando no se usó el dispositivo durante un tiempo enviar los pedidos no enviados a un servidor antes de que termine el turno de una persona.

Salir

Android 9.0 agregó un botón para salir a la pantalla de bloqueo para que una persona que use dispositivo puede finalizar su sesión. Después de presionar el botón, el sistema detiene la usuario secundario, borra el usuario si es efímero y el usuario principal vuelve a primer plano. Android oculta el botón cuando el usuario principal está en el en primer plano porque el usuario principal no puede salir.

Android no muestra el botón de finalización de sesión de forma predeterminada, pero el administrador completamente administrado) pueden habilitarla llamando DevicePolicyManager.setLogoutEnabled() Si necesitas confirmar el estado actual del botón, llamar DevicePolicyManager.isLogoutEnabled()

El administrador de un usuario secundario puede salir de la sesión del usuario de manera programática y volver al usuario principal. Primero, confirma que el usuario secundario y el principal estén afiliado y, luego, llama a DevicePolicyManager.logoutUser(). Si usuario que no accedió a su cuenta es un usuario efímero, el sistema se detiene y borra usuario.

Cambiar usuarios

Para cambiar a otro usuario secundario, el administrador de un dispositivo completamente administrado puede llamar a DevicePolicyManager.switchUser() Para tu conveniencia, Puedes pasar null para cambiar al usuario principal.

Cómo detener a un usuario

Para detener a un usuario secundario, un DPC que posea un dispositivo completamente administrado puede llamar DevicePolicyManager.stopUser() Si el usuario detenido es un efímero, el usuario se detiene y, luego, se borra.

Recomendamos detener a los usuarios siempre que sea posible para mantenerse por debajo del nivel de la cantidad máxima de usuarios en ejecución.

Eliminar un usuario

Para borrar de forma permanente un usuario secundario, un DPC puede llamar a una de las siguientes opciones: Métodos DevicePolicyManager:

  • Un administrador de un dispositivo completamente administrado puede llamar a removeUser().
  • Un administrador del usuario secundario puede llamar a wipeData().

El sistema borra a los usuarios efímeros cuando salen de sus cuentas, si se detienen o cambian te.

Inhabilita la IU predeterminada

Si tu DPC proporciona una IU para administrar usuarios, puedes inhabilitar la interfaz multiusuario. Para hacerlo, llama a DevicePolicyManager.setLogoutEnabled() y agrega restricción DISALLOW_USER_SWITCH, como se muestra en el siguiente ejemplo:

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 que usa el dispositivo no puede agregar usuarios secundarios con la IU integrada de Android. ya que los administradores de dispositivos completamente administrados agregan automáticamente Restricción de usuario de DISALLOW_ADD_USER.

Mensajes de sesión

Cuando la persona que usa un dispositivo cambia a un usuario nuevo, Android muestra un panel para y destacar el interruptor. Android muestra los siguientes mensajes:

  • Mensaje de inicio de sesión del usuario que se muestra cuando el dispositivo cambia a un modo secundario usuario del usuario principal.
  • Mensaje de la sesión de usuario final que se muestra cuando el dispositivo regresa al usuario principal de un usuario secundario.

El sistema no muestra los mensajes cuando se alterna entre dos usuarios secundarios.

Debido a que los mensajes podrían no ser adecuados para todas las situaciones, puedes cambiar el texto de estos mensajes. Por ejemplo, si tu solución usa cuentas de usuario sesiones, puedes reflejarlo en los mensajes, por ejemplo: Deteniendo el navegador sesión y borrando los datos personales...

El sistema muestra el mensaje solo unos segundos, así que cada mensaje debe ser una frase corta y clara. Para personalizar los mensajes, tu administrador puede llamar los métodos DevicePolicyManager setStartUserSessionMessage() y setEndUserSessionMessage(), como se muestra en el siguiente ejemplo:

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

Pasa null para borrar tus mensajes personalizados y volver a la configuración predeterminada de Android mensajes nuevos. Si necesitas revisar el texto del mensaje actual, llama getStartUserSessionMessage() o getEndUserSessionMessage()

Tu DPC debería establecer mensajes localizados para la configuración regional actual del usuario. También debes actualizar los mensajes cuando cambios regionales del usuario:

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

Coordinación del DPC

Para administrar usuarios secundarios, por lo general, se necesitan dos instancias de tu DPC: una a la que el dispositivo completamente administrado, mientras que la otra es propietaria del usuario secundario. Al crear un usuario nuevo, el administrador del dispositivo completamente administrado establece otra instancia de como administrador del usuario nuevo.

Usuarios afiliados

Algunas de las APIs de esta guía para desarrolladores solo funcionan cuando los usuarios secundarios están afiliados. Porque Android inhabilita algunas funciones (registros de red, por ejemplo) cuando agrega nuevos usuarios secundarios no afiliados a el dispositivo, debes afiliar a los usuarios lo antes posible. Consulta el ejemplo en Configuración a continuación.

Configuración

Configura nuevos usuarios secundarios (desde el DPC que posee el usuario secundario) antes de y dejar que las personas los usen. Puedes realizar esta configuración desde la Devolución de llamada DeviceAdminReceiver.onEnabled(). Si anteriormente configura los elementos adicionales de administrador en la llamada a createAndManageUser(), puedes obtener del argumento intent. En el siguiente ejemplo, se muestra una afiliación a un DPC un nuevo usuario secundario en la devolución de llamada:

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 DPC

Aunque las dos instancias de DPC se ejecutan con usuarios diferentes, los DPC que poseen el dispositivo y los usuarios secundarios pueden comunicarse entre sí. Como llamar al servicio de otro DPC excede los límites del usuario, tu DPC no puede llamar a bindService() como lo normalmente lo haría en Android Para vincularse a un servicio que se ejecuta en otro usuario, llama DevicePolicyManager.bindDeviceAdminServiceAsUser()

Usuario principal y dos usuarios secundarios afiliados que llaman a RPCs.
Figura 2: Los administradores de los usuarios principales y secundarios afiliados métodos de servicio de llamadas

Tu DPC solo puede vincularse a servicios que se ejecuten en los usuarios devueltos por DevicePolicyManager.getBindDeviceAdminTargetUsers() En el siguiente ejemplo, se muestra cómo el administrador de una vinculación de usuario secundaria con el administrador del dispositivo completamente administrado:

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

Recursos adicionales

Para obtener más información sobre los dispositivos exclusivos, lee los siguientes documentos: