Compilación de apps con reconocimiento de multiusuario

Cuando un dispositivo admite varios usuarios, sus apps deben de estos usuarios distintos.

Ciertas apps deben tener algunos componentes ejecutarse como singleton y pueden aceptar de cualquier usuario. Solo las apps del sistema pueden usar esta función actualmente.

Este centro tiene las siguientes características:

  • Conserva los recursos
  • Arbitra uno o más recursos compartidos entre usuarios.
  • Reduce la sobrecarga de red mediante una única conexión de servidor.

Consulta el siguiente diagrama para ver una descripción del flujo de permisos con varios usuarios.

Flujo de permisos de varios usuarios

Figura 1: Permisos de varios usuarios

Cómo habilitar un componente singleton

Para identificar una app como un singleton, agrega android:singleUser="true" a tu servicio. receptor o proveedor en el manifiesto de Android.

El sistema creará una instancia de ese componente mientras se ejecuta como usuario 0. solamente. Cualquier solicitud para conectarse a ese proveedor o servicio, o para hacer transmisiones a ese receptor, desde cualquier usuario será enrutado al proceso en el usuario 0. Si este es el único componente de tu aplicación, solo se ejecutará una instancia de tu app.

Las actividades de tu paquete se seguirán iniciando en un proceso separado para por cada usuario, y el UID se encuentra en el rango de UID para ese usuario (como 1010034).

Cómo interactuar con los usuarios

Configurar permisos

Estos permisos son obligatorios

INTERACT_ACROSS_USERS (signature|system)
INTERACT_ACROSS_USERS_FULL (signature)

Usa APIs

Usa las siguientes APIs para que las apps conozcan varios usuarios.

  1. Extrae el identificador de usuario de las llamadas entrantes de Binder:
    • int userHandle = UserHandle.getCallingUserId()
  2. Usa APIs nuevas y protegidas para iniciar servicios, actividades y transmisiones en un usuario:
    • Context.startActivityAsUser(Intent, UserHandle)
    • Context.bindServiceAsUser(Intent, …, UserHandle)
    • Context.sendBroadcastAsUser(Intent, … , UserHandle)
    • Context.startServiceAsUser(Intent, …, UserHandle)
    UserHandle puede ser un usuario explícito o uno de los identificadores especiales: UserHandle.CURRENT o UserHandle.ALL. CURRENT indica el usuario que está actualmente en primer plano. Usa ALL cuando quieras enviar una transmisión a todos los usuarios.
  3. Cómo comunicarte con los componentes de tu propia app: (INTERACT_ACROSS_USERS) O con componentes de otras apps: (INTERACT_ACROSS_USERS_FULL)
  4. Puede que debas crear componentes proxy que se ejecuten en el proceso del usuario y, luego, accede al componente singleUser en el usuario 0.
  5. Consulta usuarios y sus controladores con el nuevo servicio del sistema UserManager:
    • UserManager.getUsers()
    • UserManager.getUserInfo()
    • UserManager.supportsMultipleUsers()
    • UserManager.getUserSerialNumber(int userHandle): Es un número no reciclado que corresponde a un identificador de usuario.
    • UserManager.getUserHandle(int serialNumber)
    • UserManager.getUserProfiles() : Muestra la colección de perfiles propios y administrados, si los hubiera.
  6. Regístrate para escuchar a usuarios específicos o a todos, y las devoluciones de llamada con las nuevas APIs activadas. ContentObserver, PackageMonitor y BroadcastReceiver que proporcionan acceso información sobre el usuario que causó la devolución de llamada.

Servicios en múltiples usuarios o perfiles

No todos los servicios necesitan ejecutar una instancia en otro usuario o perfil de trabajo. Si el servicio del sistema solo necesita ejecutarse como usuario 0, inhabilita los componentes del servicio cuando se ejecute bajo otros usuarios para ayudan a preservar los recursos. En el siguiente ejemplo, se muestra cómo podrías hacer esto en la entrada de tu servicio puntos:

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

En el ejemplo, también se puede usar PackageManager.setApplicationEnabledSetting() para inhabilitar toda la aplicación.