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

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

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

Предварительные требования

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

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

Интеграция с 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 .
  • Для этой службы необходимо установить параметр android:exported в true
  • Параметр 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 . Если ваше приложение зависит от управляемых конфигураций для загрузки, см. раздел «Настройка управляемых конфигураций», чтобы узнать, как читать и прослушивать изменения.

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

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

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

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

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

{
  "applications": [

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

Перед назначением ролей в соответствии с политикой система проверит, совпадает ли отпечаток сертификата ключа подписи приложения на устройстве с отпечатком из Play Store. Если отпечаток отличается, роли приложению не будут назначены, и в 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 Bucket, а не системного списка разрешенного энергопотребления.

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

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