Gérer les mises à jour du système

Ce guide du développeur explique comment votre outil de contrôle des règles relatives aux appareils (DPC) peut gérer les mises à jour du système Android pour le compte de l'utilisateur de l'appareil.

Introduction

Les appareils Android peuvent recevoir et installer des mises à jour Over The Air (OTA) du logiciel système et d'application. Android avertit l'utilisateur de l'appareil qu'une mise à jour du système est disponible et qu'il peut l'installer immédiatement ou plus tard.

L'outil DPC permet à un administrateur informatique de gérer les mises à jour du système pour l'utilisateur de l'appareil. Les DPC peuvent posséder un appareil entièrement géré (appelé propriétaire de l'appareil) ou posséder un profil professionnel (appelé propriétaire de profil). Le tableau 1 montre comment les propriétaires d'appareils peuvent gérer les mises à jour du système, tandis que les propriétaires de profil peuvent uniquement communiquer des informations sur les mises à jour du système.

Tableau 1: Les tâches disponibles pour les DPC dépendent du mode Propriétaire

Tâche Propriétaire de l'appareil Propriétaire du profil
Rechercher des mises à jour du système en attente
Recevoir des rappels lorsque de nouvelles mises à jour du système sont disponibles
Définir une règle de mise à jour locale pour contrôler à quel moment Android installe les mises à jour du système
Figer la version de l'OS pour les périodes critiques

Rechercher des mises à jour en attente

Une mise à jour en attente est une mise à jour du système pour un appareil qui n'a pas encore été installé. Votre DPC peut aider les administrateurs informatiques à identifier les appareils sur lesquels des mises à jour système sont en attente et éventuellement à demander aux utilisateurs d'installer rapidement les mises à jour critiques.

Les propriétaires d'appareils et de profils équipés d'Android 8.0 (niveau d'API 26) ou version ultérieure peuvent vérifier si un appareil doit être mis à jour du système. Appelez DevicePolicyManager.getPendingSystemUpdate(), qui renvoie null si l'appareil est à jour. Si une mise à jour du système est en attente, la méthode renvoie des informations sur la mise à jour.

En savoir plus sur une mise à jour en attente

Après avoir appelé getPendingSystemUpdate(), vous pouvez inspecter la valeur SystemUpdateInfo renvoyée pour en savoir plus sur la mise à jour en attente. L'exemple suivant montre comment savoir quand une mise à jour en attente a été disponible pour la première fois pour l'appareil:

Kotlin

val firstAvailable =
        dpm.getPendingSystemUpdate(adminName)?.receivedTime
firstAvailable?.let {
    Log.i(TAG, "Update first available: ${Date(firstAvailable)}")
}

Java

SystemUpdateInfo updateInfo = dpm.getPendingSystemUpdate(adminName);
if (updateInfo != null) {
  Long firstAvailable = updateInfo.getReceivedTime();
  Log.i(TAG, "Update first available: " + new Date(firstAvailable));
}

Rappels système

Lorsqu'une mise à jour est disponible, le système Android en informe les propriétaires d'appareils. Sur Android 8.0 ou version ultérieure, le système avertit également les propriétaires de profils.

Dans votre sous-classe DeviceAdminReceiver, remplacez le rappel onSystemUpdatePending(). Vous n'avez pas besoin de vous enregistrer ni de promouvoir votre DPC pour recevoir le rappel. Le système peut appeler cette méthode plusieurs fois pour une seule mise à jour. Vous devez donc vérifier l'état de la mise à jour avant de répondre. Appelez getPendingSystemUpdate() pour en savoir plus sur la mise à jour du système via le rappel. L'exemple suivant montre comment procéder:

Kotlin

/**
 * Called when a new update is available.
 */
override fun onSystemUpdatePending(context: Context?, intent: Intent?,
                                   receivedTime: Long) {

    // System update information is supported in API level 26 or higher.
    if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
        return
    }

    val updateInfo = getManager(context)
            .getPendingSystemUpdate(getWho(context))
            ?: return
    if (updateInfo.securityPatchState ==
            SystemUpdateInfo.SECURITY_PATCH_STATE_TRUE) {
        // Perhaps install because this is a security patch.
        // ...
    }
}

Java

/**
 * Called when a new update is available.
 */
public void onSystemUpdatePending (Context context, Intent intent,
                                   long receivedTime) {

  // System update information is supported in API level 26 or higher.
  if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
    return;
  }
  SystemUpdateInfo updateInfo = getManager(context)
      .getPendingSystemUpdate(getWho(context));
  if (updateInfo == null) {
    return;
  }
  if (updateInfo.getSecurityPatchState() ==
      SystemUpdateInfo.SECURITY_PATCH_STATE_TRUE) {
    // Perhaps install because this is a security patch.
    // ...
  }
}

Lorsqu'un système comporte plusieurs DPC, par exemple des profils professionnels sur des appareils entièrement gérés, le propriétaire de l'appareil et le propriétaire du profil reçoivent tous deux le rappel.

Mettre à jour les règles

Le propriétaire d'un appareil peut contrôler le moment où les mises à jour sont installées en définissant une règle de mise à jour du système locale. Il existe trois types de règles de mise à jour du système:

Automatique
Installe les mises à jour du système dès qu'elles sont disponibles (sans intervention de l'utilisateur). Définir ce type de règle installe immédiatement toutes les mises à jour en attente susceptibles d'être reportées ou en attente d'un intervalle de maintenance.
Avec fenêtre
Installe les mises à jour du système pendant un intervalle de maintenance quotidien (sans interaction de l'utilisateur). Définissez le début et la fin de l'intervalle de maintenance quotidien en minutes de la journée lors de la création d'une règle fenêtrée.
Reportées
Reporte l'installation des mises à jour du système de 30 jours. Une fois la période de 30 jours écoulée, le système invite l'utilisateur de l'appareil à installer la mise à jour.

Périodes de report

Le système limite chaque mise à jour à un report de 30 jours. La période commence lorsque le système reporte la mise à jour pour la première fois et que la définition de nouvelles règles de report ne la prolonge pas.

Outre le report, Android peut ne pas être en mesure d'installer une mise à jour pour d'autres raisons, telles qu'une mauvaise connexion, un espace disque insuffisant ou une batterie faible.

Le système réinitialise le délai de 30 jours si une autre mise à jour devient disponible au cours de la période, ce qui permet aux administrateurs informatiques d'essayer les mises à jour système combinées. Une fois le délai de 30 jours écoulé sans nouvelle mise à jour, le système invite l'utilisateur à installer toutes les mises à jour en attente. Par la suite, lorsqu'une nouvelle mise à jour du système sera disponible, la période de 30 jours reprend.

Définir une règle

Vous pouvez définir des règles de mise à jour sous Android 8.0 (niveau d'API 26) ou version ultérieure. Pour spécifier à quel moment l'appareil doit installer les mises à jour du système, créez une instance de SystemUpdatePolicy à l'aide de l'un des trois types décrits ci-dessus. Pour définir une règle, le propriétaire de votre appareil appelle la méthode DevicePolicyManager setSystemUpdatePolicy(). L'exemple de code suivant montre comment procéder. Pour voir un exemple de règle fenêtrée, consultez la documentation de SystemUpdatePolicy.

Kotlin

// Create the system update policy to postpone installation for 30 days.
val policy = SystemUpdatePolicy.createPostponeInstallPolicy()

// Get a DevicePolicyManager instance to set the policy on the device.
val dpm = context.getSystemService(Context.DEVICE_POLICY_SERVICE)
        as DevicePolicyManager
val adminName = getComponentName(context)

// Set the policy.
dpm.setSystemUpdatePolicy(adminName, policy)

Java

// Create the system update policy to postpone installation for 30 days.
SystemUpdatePolicy policy = SystemUpdatePolicy.createPostponeInstallPolicy();

// Get a DevicePolicyManager instance to set the policy on the device.
DevicePolicyManager dpm = (DevicePolicyManager) context
    .getSystemService(Context.DEVICE_POLICY_SERVICE);
ComponentName adminName = getComponentName(context);

// Set the policy.
dpm.setSystemUpdatePolicy(adminName, policy);

Une fois créées, les instances de règle ne peuvent plus être modifiées. Pour modifier le moment où un appareil installe les mises à jour, vous pouvez créer et définir une nouvelle règle. Pour supprimer une règle d'un appareil, appelez setSystemUpdatePolicy() en transmettant null comme argument policy. Une fois que l'outil DPC supprime une règle, l'utilisateur de l'appareil voit des notifications pour toutes les mises à jour système disponibles.

Les applications peuvent appeler getSystemUpdatePolicy() pour obtenir la règle actuelle de l'appareil. Si cette méthode renvoie null, cela signifie qu'aucune règle n'est actuellement définie.

Périodes de blocage

Pour figer la version de l'OS pendant les périodes critiques, telles que les vacances ou d'autres périodes chargées, les propriétaires d'appareils peuvent suspendre les mises à jour du système pendant 90 jours maximum. Lorsqu'un appareil se trouve dans une période de blocage, il se comporte comme suit:

  • L'appareil ne reçoit aucune notification concernant les mises à jour du système en attente.
  • Les mises à jour du système de l'OS ne sont pas installées.
  • Les utilisateurs d'appareils ne peuvent pas rechercher manuellement les mises à jour du système dans les paramètres.

Le système applique une période de mise en mémoire tampon obligatoire de 60 jours après les périodes de blocage définies pour éviter de figer l'appareil indéfiniment. N'oubliez pas que le gel des mises à jour du système peut empêcher les appareils de recevoir les mises à jour critiques.

Figure 1 : Deux périodes de blocage définies pour un appareil
Calendrier affichant deux périodes de blocage dans une année avec des tampons de 60 jours.

Vous pouvez définir des périodes de blocage pour une règle de mise à jour. Vous ne pouvez pas définir de périodes de blocage sans définir de règle. Lorsque l'appareil se trouve en dehors des périodes de blocage que vous avez définies, le comportement normal de la règle (automatique, fenêtrée ou reportée) s'applique.

Définir une période de blocage

Vous pouvez définir des périodes de blocage sous Android 9 (niveau d'API 28) ou version ultérieure. Le propriétaire d'un appareil définit une période de blocage pour une règle de mise à jour du système avant de définir cette règle pour l'appareil. Voici la procédure à suivre:

  1. Créez une règle de mise à jour du système ou obtenez la règle actuelle.
  2. Définissez les périodes de blocage de la règle en appelant setFreezePeriods().
  3. Définissez la règle et les périodes de blocage pour l'appareil en appelant setSystemUpdatePolicy().

Étant donné que la période de gel se répète chaque année, les dates de début et de fin de la période sont représentées par des valeurs de jour et de mois. Le jour de début doit commencer au moins 60 jours après la fin de toute période de gel précédente. L'exemple suivant montre comment définir deux périodes de blocage pour une règle de mise à jour du système existante:

Kotlin

// Get the existing policy from the DevicePolicyController instance.
val policy = dpm.systemUpdatePolicy ?: return

try {
    // Set the two annual freeze periods on the policy for our retail
    // point-of-sale devices.
    val summerSale = FreezePeriod(
            MonthDay.of(6, 1),
            MonthDay.of(7, 31)) // Jun 1 - Jul 31 inclusive
    val winterSale = FreezePeriod(
            MonthDay.of(11, 20),
            MonthDay.of(1, 12)) // Nov 20 - Jan 12 inclusive
    policy.freezePeriods = Arrays.asList(summerSale, winterSale)

    // Set the policy again to activate the freeze periods.
    dpm.setSystemUpdatePolicy(adminName, policy)

} catch (e: SystemUpdatePolicy.ValidationFailedException) {
    // There must be previous periods recorded on the device because
    // summerSale and winterSale don’t overlap and are separated by more
    // than 60 days. Report the overlap ...
}

Java

// Get the existing policy from the DevicePolicyController instance.
SystemUpdatePolicy policy = dpm.getSystemUpdatePolicy();

try {
  // Set the two annual freeze periods on the policy for our
  // retail point-of-sale devices.
  FreezePeriod summerSale = new FreezePeriod(
      MonthDay.of(6, 1),
      MonthDay.of(7, 31)); // Jun 1 - Jul 31 inclusive
  FreezePeriod winterSale = new FreezePeriod(
      MonthDay.of(11, 20),
      MonthDay.of(1, 12)); // Nov 20 - Jan 12 inclusive
  policy.setFreezePeriods(Arrays.asList(summerSale, winterSale));

  // Don’t forget to set the policy again to activate the freeze periods.
  dpm.setSystemUpdatePolicy(adminName, policy);

} catch (SystemUpdatePolicy.ValidationFailedException e) {
  // There must be previous periods recorded on the device because summerSale
  // and winterSale don’t overlap and are separated by more than 60 days.
  // Report the overlap ...
}

Le jour de début et le jour de fin sont tous deux inclus. Si le jour de début est supérieur au jour de fin (par exemple, winterSale dans l'exemple précédent), la période de gel s'étend sur l'année suivante.

Lorsque vous définissez des périodes de blocage pour une règle de mise à jour du système, Android teste les conditions suivantes:

  • La période de blocage ne doit pas dépasser 90 jours.
  • L'intervalle entre les périodes de blocage est d'au moins 60 jours.
  • Les périodes de blocage ne se chevauchent pas.
  • Il n'y a pas de périodes de blocage en double.

Lorsque vous définissez la règle de mise à jour du système pour un appareil, Android répète ces tests et inclut toutes les périodes de blocage actuelles ou passées de l'appareil.

Android génère une exception SystemUpdatePolicy.ValidationFailedException lorsque l'un de ces tests échoue.

Pour obtenir la liste des périodes de blocage précédemment définies sur un objet de règle de mise à jour du système, toutes les applications installées peuvent appeler SystemUpdatePolicy.getFreezePeriods(). L'exemple suivant appelle cette méthode pour consigner les périodes de blocage d'un appareil:

Kotlin

// Log any freeze periods that might be set on a system update policy.
dpm.systemUpdatePolicy?.freezePeriods?.forEach {
    Log.i(TAG, "Freeze period: $it")
}

Java

// Log any freeze periods that might be set on a system update policy.
SystemUpdatePolicy currentPolicy = dpm.getSystemUpdatePolicy();
if (currentPolicy != null) { // A policy might not be set.
  for (FreezePeriod freezePeriod : currentPolicy.getFreezePeriods()) {
    Log.i(TAG, "Freeze period: " + freezePeriod.toString());
  }
}

Années bissextiles

Android utilise le calendrier ISO 8601 (également appelé calendrier grégorien) pour calculer les périodes de blocage et ignore les années bissextiles. Cela signifie que le 29 février n'est pas reconnu comme une date valide, mais est considéré comme le 28 février. Par conséquent, le 29 février n'est pas pris en compte dans le calcul de la durée d'une période de gel.

Développement et tests

Lorsque vous développez et testez la fonctionnalité de mise à jour du système de votre DPC, vous devrez peut-être créer de nombreuses périodes de blocage. Étant donné qu'Android vérifie un intervalle de 60 jours entre les périodes de gel passées, vous ne pourrez peut-être pas définir une nouvelle période de gel sans effacer au préalable l'enregistrement des périodes passées. Pour effacer l'enregistrement de la période de blocage de l'appareil, exécutez la commande suivante dans le shell Android Debug Bridge (adb) :

adb shell dpm clear-freeze-period-record

Vous pouvez vous assurer qu'un appareil se trouve dans une période de blocage en vérifiant que l'interface utilisateur pour les mises à jour du système est désactivée.

Ressources supplémentaires

Pour en savoir plus sur les mises à jour du système, consultez la documentation sur les mises à jour OTA du projet Open Source Android.