Управление ролями приложений

Функция ролей приложений позволяет системному администратору предоставлять особые права управляемому приложению на устройстве Android. Приложение с определенной ролью может быть освобождено от ограничений на энергопотребление и фоновую активность, приостановки и перевода в спящий режим (в Android 14 и более поздних версиях). Кроме того, для него могут быть отключены элементы управления пользователя, например принудительная остановка и очистка данных приложения (в Android 11 и более поздних версиях). Это позволяет приложению выполнять свои основные функции без перебоев. Кроме того, приложение может получать уведомления о назначенных ему ролях, что позволяет ему выполнять самонастройку без вмешательства пользователя.

Список доступных ролей приложения и особых прав, предоставляемых каждой роли, приведен в статье RoleType.

Требования

Устройство управляется EMM-решением на основе AMAPI (EMM-решения, использующие собственный контроллер политики устройств, не поддерживаются).

Подготовьте приложение к использованию функции

Интеграция с AMAPI SDK требуется, только если приложение должно получать уведомления о назначенных ему ролях, чтобы запускаться автоматически без участия пользователя.

Интегрируйте AMAPI SDK в свое приложение

Подробную информацию об AMAPI SDK и о том, как добавить его в приложение, можно найти в руководстве по интеграции AMAPI SDK.

Добавьте необходимые метаданные в манифест приложения

Приложению Android Device Policy (ADP) необходимо знать ComponentName вашего класса, который реализует NotificationReceiverService, чтобы уведомлять ваше приложение о назначенных ему ролях. Вам необходимо добавить в AndroidManifest.xml тег, чтобы ADP мог автоматически обнаружить ваш сервис.

  • В приложении должен быть только один сервис enabled, у которого есть meta-data с android:name, равным com.google.android.managementapi.notification.NotificationReceiverService.SERVICE_APP_ROLES.
  • Для этого сервиса необходимо задать значение true для параметра android:exported.
  • Для свойства android:value объекта meta-data должна быть задана пустая строка.
<service
 android:name=".MyNotificationReceiverService"
 android:exported="true">
    <meta-data android:name="com.google.android.managementapi.notification.NotificationReceiverService.SERVICE_APP_ROLES" android:value="" />
</service>

Если вы тестируете роль COMPANION_APP, добавьте в сервис следующий элемент meta-data, чтобы приложение Android Device Policy могло отправлять в ваше приложение обновления статуса локальных команд:

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

Создайте сервис, расширяющий NotificationReceiverService (или обновите существующий).

Создайте или обновите существующий класс NotificationReceiverService и реализуйте AppRolesListener, чтобы отслеживать роли, назначенные вашему приложению. Для этого требуется только getAppRolesListener(). Если вашему приложению назначена роль COMPANION_APP, вам также следует реализовать 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"
  }
}

Если роли приложения меняются несколько раз, оно может получить несколько уведомлений. Если все роли удалены, приложение все равно получит уведомление с пустым списком ролей. Это уведомление выведет приложение из остановленного состояния, и оно сможет запуститься без участия пользователя. Благодаря уведомлениям и исключениям для ролей приложения ваш продукт может прослушивать трансляции ACTION_BOOT_COMPLETED. Если ваше приложение зависит от управляемых конфигураций, ознакомьтесь с разделом Настройка управляемых конфигураций, чтобы узнать, как считывать и отслеживать изменения.

Начиная с AMAPI SDK 1.9.0, каждая роль в AppRolesSetRequest также включает Role.ExtraCapabilities, предоставленные системным администратором в правилах. Например, сопутствующее приложение может проверить, разрешено ли ему выполнять команду локального удаления данных:

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

Дополнительные возможности может предоставить только системный администратор. Если вы зададите extraCapabilities для роли, которую передаете в EnvironmentClient, вызов завершится ошибкой InvalidArgumentException.

Настройте устройство с помощью правил ролей приложений

Разработчики приложений могут протестировать назначение ролей своему приложению с помощью EMM или следуя краткому руководству по Android Management API. Блокнот Colab для AMAPI позволяет зарегистрировать предприятие, создать правило и настроить устройство.

Как настроить правила для приложения с помощью ролей

Настройте policy с ролями, которые должно иметь ваше приложение, используя ApplicationPolicy.roles.

В примере ниже показано, как настроить роль для приложений MTD.

{
  "applications": [

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

Только роль COMPANION_APP поддерживает extraCapabilities. Чтобы разрешить сопутствующему приложению удалять данные с устройства или из рабочего профиля, задайте для параметра extraCapabilities.localDeviceWipeCommand значение LOCAL_DEVICE_WIPE_COMMAND_ALLOWED.

Прежде чем назначить роли, указанные в правилах, система проверит, совпадает ли цифровой отпечаток сертификата ключа подписи приложения на устройстве с отпечатком из Google Play. Если цифровой отпечаток не совпадает, роли не будут назначены приложению, а в EMM будет отправлено сообщение о несоответствии NonComplianceReason.APP_SIGNING_CERT_MISMATCH.

{
  "applications": [

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

Если в вашем приложении есть управляемая конфигурация, [системный] администратор может задать начальную конфигурацию для соответствующих restriction в правилах для приложений:

{
  "applications": [

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

Проверьте статус исключения для батареи

Приложения с ролью Mobile Threat Defense (MTD) автоматически освобождаются от стандартных ограничений на энергопотребление в фоновом режиме. Однако это исключение реализуется группой App Standby, а не белым списком энергопотребления системы.

Чтобы проверить, активно ли исключение для приложения:

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