Administra los roles de la aplicación

La función de roles de la aplicación permite que un administrador de TI otorgue privilegios especiales a una aplicación administrada en un dispositivo con Android. Si se asigna un rol específico, una app puede quedar exenta de las restricciones de energía y en segundo plano, la suspensión, la hibernación (en Android 14 y versiones posteriores) y tener inhabilitados los controles del usuario (es decir, incluye acciones del usuario, como forzar detención y borrar los datos de app) (en Android 11 y versiones posteriores), lo que le permite realizar su función crítica sin interrupciones. Además, la app puede recibir notificaciones sobre sus roles asignados, lo que le permite iniciarse sin la intervención del usuario.

Para obtener una lista de los roles de aplicación disponibles y los privilegios especiales otorgados a cada rol, consulta RoleType.

Requisitos previos

El dispositivo se administra con un EMM basado en la AMAPI (no se admiten los EMM que usan un DPC personalizado).

Prepara tu app para usar la función

La integración con el SDK de AMAPI solo es necesaria si la app quiere recibir notificaciones de sus roles asignados, lo que le permite iniciarse por sí misma (es decir, iniciarse automáticamente sin interacción del usuario).

Integra el SDK de AMAPI en tu app

Puedes encontrar más información sobre el SDK de AMAPI y cómo agregarlo a tu app en la guía de integración del SDK de AMAPI.

Agrega los metadatos obligatorios al manifiesto de la app

Android Device Policy (ADP) necesita conocer el ComponentName de tu clase que implementa NotificationReceiverService para notificar a tu app sobre sus roles asignados. Debes etiquetar tu servicio en AndroidManifest.xml de forma adecuada para que ADP pueda descubrirlo automáticamente.

  • Tu app debe tener exactamente un servicio que sea enabled y tenga meta-data con android:name igual a com.google.android.managementapi.notification.NotificationReceiverService.SERVICE_APP_ROLES
  • Este servicio debe tener android:exported configurado como true
  • El android:value de meta-data debe establecerse en una cadena vacía
<service
 android:name=".MyNotificationReceiverService"
 android:exported="true">
    <meta-data android:name="com.google.android.managementapi.notification.NotificationReceiverService.SERVICE_APP_ROLES" android:value="" />
</service>

Si estás probando el rol COMPANION_APP, también debes agregar el siguiente meta-data a tu servicio para que Android Device Policy pueda enviar actualizaciones de estado de comandos locales a tu app:

<meta-data android:name="com.google.android.managementapi.notification.NotificationReceiverService.SERVICE_COMMAND_STATUS" android:value="" />

Crea un servicio que extienda NotificationReceiverService (o actualiza el existente)

Crea o actualiza tu NotificationReceiverService existente y, luego, implementa un AppRolesListener para escuchar los roles asignados a tu app. Solo se requiere getAppRolesListener() para escuchar los roles asignados a tu app. Si se le asigna un rol de COMPANION_APP a tu app, también debes implementar getCommandListener():

import android.util.Log
import com.google.android.managementapi.approles.AppRolesListener
import com.google.android.managementapi.approles.model.AppRolesSetRequest
import com.google.android.managementapi.approles.model.AppRolesSetResponse
import com.google.android.managementapi.commands.CommandListener
import com.google.android.managementapi.commands.model.Command
import com.google.android.managementapi.notification.NotificationReceiverService

class MyNotificationReceiverService : NotificationReceiverService() {

  // If your app wants to listen for roles assigned
  override fun getAppRolesListener(): AppRolesListener =
    object : AppRolesListener {
      override fun onAppRolesSet(request: AppRolesSetRequest): AppRolesSetResponse {
        val roleTypes = request.roles.map { role -> role.roleType }
        Log.i(TAG, "onAppRolesSet: $roleTypes")

        return AppRolesSetResponse.getDefaultInstance()
      }
    }

 // If your app wants to listen for local command status updates
 // Only relevant for COMPANION_APP role
 override fun getCommandListener(): CommandListener {
    return object : CommandListener {
      override fun onCommandStatusChanged(command: Command) {
         Log.i(TAG, "onCommandStatusChanged")
      }
    }
  }

  private companion object {
    const val TAG = "MyNotificationReceiverService"
  }
}

Tu app puede recibir notificaciones varias veces si sus roles cambian varias veces. Si se quitan todos los roles, tu app recibirá una notificación con una lista vacía de roles. Esta notificación sacará a tu app del estado detenido y, junto con las exenciones otorgadas para tu app, esta podrá iniciarse sin interacción del usuario. Gracias a las notificaciones y exenciones de roles de la app, esta puede escuchar las transmisiones de ACTION_BOOT_COMPLETED. Si tu app depende de sus parámetros de configuración administrados para iniciarse, consulta Cómo establecer parámetros de configuración administrados para obtener información sobre cómo leer y escuchar los cambios.

A partir del SDK de AMAPI 1.9.0, cada rol en AppRolesSetRequest también incluye el Role.ExtraCapabilities que el administrador de TI otorgó en la política. Por ejemplo, una app complementaria puede verificar si tiene permiso para emitir un comando de limpieza local:

import com.google.android.managementapi.approles.model.AppRolesSetRequest
import com.google.android.managementapi.approles.model.AppRolesSetResponse
import com.google.android.managementapi.common.model.Role
...

  override fun onAppRolesSet(request: AppRolesSetRequest): AppRolesSetResponse {
    val canWipeLocally =
      request.roles.any { role ->
        role.roleType == Role.RoleType.COMPANION_APP &&
          role.extraCapabilities.localDeviceWipeCommand ==
            Role.ExtraCapabilities.LocalDeviceWipeCommand.LOCAL_DEVICE_WIPE_COMMAND_ALLOWED
      }
    Log.i(TAG, "onAppRolesSet: canWipeLocally=$canWipeLocally")

    return AppRolesSetResponse.getDefaultInstance()
  }

Solo el administrador de TI puede otorgar funciones adicionales. Si configuras extraCapabilities en un rol que pasas a EnvironmentClient, la llamada falla con un InvalidArgumentException.

Aprovisiona el dispositivo con políticas de roles de apps

Los desarrolladores de apps pueden probar la asignación de roles de app a su aplicación con una EMM o siguiendo la guía de inicio rápido de la API de Android Management. El notebook de Colab de AMAPI te permite inscribir una empresa, crear una política y aprovisionar un dispositivo.

Establece la política para tu app con roles de app

Configura un policy con los roles de la app que se espera que tenga tu app con ApplicationPolicy.roles.

En el siguiente ejemplo, se muestra cómo configurar el rol para las apps de MTD:

{
  "applications": [

    {
      "packageName": "com.example.mtd",
      "installType": "FORCE_INSTALLED",
      "roles": [
        { "roleType": "MOBILE_THREAT_DEFENSE_ENDPOINT_DETECTION_RESPONSE" }
      ]
    }
  ]
}

Solo el rol COMPANION_APP admite extraCapabilities. Para permitir que la app complementaria borre el dispositivo o el perfil de trabajo de forma local, establece extraCapabilities.localDeviceWipeCommand en LOCAL_DEVICE_WIPE_COMMAND_ALLOWED para ese rol.

Antes de asignar los roles como se especifica en la política, el sistema verificará que la huella digital del certificado de la clave de firma de la app en el dispositivo coincida con la de Play Store. Si la huella digital es diferente, los roles no se asignarán a la app y se informará el incumplimiento de NonComplianceReason.APP_SIGNING_CERT_MISMATCH al EMM.

{
  "applications": [

    {
      "packageName": "com.example.mtd",
      "installType": "FORCE_INSTALLED",
      "signingKeyCerts": [
         { "signingKeyCertFingerprintSha256": "base64-encoded-sha256" }
       ],
      "roles": [
        { "roleType": "MOBILE_THREAT_DEFENSE_ENDPOINT_DETECTION_RESPONSE" }
      ]
    }
  ]
}

Si tu app tiene una configuración administrada, el administrador de TI puede establecer una configuración inicial para los restriction pertinentes en la política de la aplicación:

{
  "applications": [

    {
      "packageName": "com.example.mtd",
      "installType": "FORCE_INSTALLED",
      "roles": [
        { "roleType": "MOBILE_THREAT_DEFENSE_ENDPOINT_DETECTION_RESPONSE" }
      ],
      "managedConfiguration": {
        "<key>": "<value>"
      }
    }
  ]
}

Verifica el estado de la exención de batería

Las apps con el rol de defensa contra amenazas para dispositivos móviles (MTD) están exentas automáticamente de las restricciones de energía en segundo plano estándar. Sin embargo, esta exención la implementa el intervalo de App Standby, en lugar de la lista de entidades permitidas de energía del sistema.

Para verificar si la exención de la app está activa, sigue estos pasos:

import android.app.usage.UsageStatsManager
import android.content.Context

// UsageStatsManager.STANDBY_BUCKET_EXEMPTED is annotated as a @SystemApi. We can redefine it for clarity.
// Define this at the top level of your file, or inside a companion object
private const val STANDBY_BUCKET_EXEMPTED = 5

private fun isAppExemptedFromAppStandbyBucket(): Boolean =
    (getSystemService(Context.USAGE_STATS_SERVICE) as? UsageStatsManager)
        ?.appStandbyBucket == STANDBY_BUCKET_EXEMPTED