Google is committed to advancing racial equity for Black communities. See how.
Cette page a été traduite par l'API Cloud Translation.
Switch to English

Mises à jour du système A / B (sans couture)

Les mises à jour système A / B, également appelées mises à jour transparentes, garantissent qu'un système de démarrage fonctionnel reste sur le disque pendant une mise à jour OTA (over-the-air) . Cette approche réduit la probabilité d'un appareil inactif après une mise à jour, ce qui signifie moins de remplacements d'appareils et de reflets d'appareils dans les centres de réparation et de garantie. D'autres systèmes d'exploitation de qualité commerciale tels que ChromeOS utilisent également les mises à jour A / B avec succès.

Pour plus d'informations sur les mises à jour du système A / B et leur fonctionnement, voir Sélection de partition (emplacements) .

Les mises à jour du système A / B offrent les avantages suivants:

  • Les mises à jour OTA peuvent se produire pendant l'exécution du système, sans interrompre l'utilisateur. Les utilisateurs peuvent continuer à utiliser leurs périphériques pendant une OTA - le seul temps d'arrêt pendant une mise à jour est lorsque le périphérique redémarre dans la partition de disque mise à jour.
  • Après une mise à jour, le redémarrage ne prend pas plus de temps qu'un redémarrage normal.
  • Si un OTA ne s'applique pas (par exemple, en raison d'un mauvais flash), l'utilisateur ne sera pas affecté. L'utilisateur continuera à exécuter l'ancien système d'exploitation et le client est libre de réessayer la mise à jour.
  • Si une mise à jour OTA est appliquée mais ne parvient pas à démarrer, le périphérique redémarrera dans l'ancienne partition et restera utilisable. Le client est libre de réessayer la mise à jour.
  • Toutes les erreurs (telles que les erreurs d'E / S) affectent uniquement le jeu de partitions inutilisé et peuvent être retentées. De telles erreurs deviennent également moins probables car la charge d'E / S est délibérément faible pour éviter de dégrader l'expérience utilisateur.
  • Les mises à jour peuvent être diffusées sur les appareils A / B, ce qui évite de télécharger le package avant de l'installer. Le streaming signifie qu'il n'est pas nécessaire que l'utilisateur dispose de suffisamment d'espace libre pour stocker le package de mise à jour sur /data ou /cache .
  • La partition de cache n'est plus utilisée pour stocker les packages de mise à jour OTA, il n'est donc pas nécessaire de s'assurer que la partition de cache est suffisamment grande pour les futures mises à jour.
  • dm-verity garantit qu'un périphérique démarrera une image non corrompue. Si un appareil ne démarre pas en raison d'un problème OTA ou dm-verity défectueux, l'appareil peut redémarrer dans une ancienne image. (Android Verified Boot ne nécessite pas de mises à jour A / B.)

À propos des mises à jour du système A / B

Les mises à jour A / B nécessitent des modifications à la fois du client et du système. Le serveur de packages OTA, cependant, ne devrait pas nécessiter de modifications: les packages de mise à jour sont toujours servis via HTTPS. Pour les appareils utilisant l'infrastructure OTA de Google, les modifications du système sont toutes dans AOSP et le code client est fourni par les services Google Play. Les OEM n'utilisant pas l'infrastructure OTA de Google pourront réutiliser le code système AOSP mais devront fournir leur propre client.

Pour les équipementiers fournissant leur propre client, le client doit:

  • Décidez quand effectuer une mise à jour. Les mises à jour A / B ayant lieu en arrière-plan, elles ne sont plus initiées par l'utilisateur. Pour éviter de perturber les utilisateurs, il est recommandé de planifier les mises à jour lorsque l'appareil est en mode de maintenance inactif, par exemple pendant la nuit, et en Wi-Fi. Cependant, votre client peut utiliser toutes les heuristiques souhaitées.
  • Vérifiez auprès de vos serveurs de packages OTA et déterminez si une mise à jour est disponible. Cela devrait être essentiellement le même que votre code client existant, sauf que vous voudrez signaler que l'appareil prend en charge A / B. (Le client de Google comprend également un bouton Vérifier maintenant permettant aux utilisateurs de vérifier la dernière mise à jour.)
  • Appelez update_engine avec l'URL HTTPS de votre package de mise à jour, en supposant qu'il en existe un. update_engine mettra à jour les blocs bruts sur la partition actuellement inutilisée au fur et à mesure qu'il diffuse le package de mise à jour.
  • Signalez les réussites ou échecs d'installation à vos serveurs, en fonction du code de résultat update_engine . Si la mise à jour est appliquée avec succès, update_engine indiquera au bootloader de démarrer dans le nouveau système d'exploitation au prochain redémarrage. Le chargeur de démarrage reviendra sur l'ancien système d'exploitation si le nouveau système d'exploitation ne démarre pas, donc aucun travail n'est requis de la part du client. Si la mise à jour échoue, le client doit décider quand (et s'il faut) réessayer, en fonction du code d'erreur détaillé. Par exemple, un bon client pourrait reconnaître qu'un package OTA partiel ("diff") échoue et essayer un package OTA complet à la place.

En option, le client peut:

  • Afficher une notification demandant à l'utilisateur de redémarrer. Si vous souhaitez mettre en œuvre une politique dans laquelle l'utilisateur est encouragé à se mettre régulièrement à jour, cette notification peut être ajoutée à votre client. Si le client n'invite pas les utilisateurs, les utilisateurs recevront la mise à jour la prochaine fois qu'ils redémarreront de toute façon. (Le client de Google a un délai configurable par mise à jour.)
  • Afficher une notification indiquant aux utilisateurs s'ils ont démarré avec une nouvelle version du système d'exploitation ou s'ils étaient censés le faire, mais sont revenus à l'ancienne version du système d'exploitation. (Le client de Google ne fait généralement ni l'un ni l'autre.)

Du côté du système, les mises à jour du système A / B affectent les éléments suivants:

  • Sélection de partition (emplacements), le démon update_engine et les interactions du chargeur de démarrage (décrites ci-dessous)
  • Processus de construction et génération de packages de mise à jour OTA (décrits dans Implémentation des mises à jour A / B )

Sélection de partition (slots)

Les mises à jour du système A / B utilisent deux ensembles de partitions appelés slots (normalement slot A et slot B). Le système fonctionne à partir de l'emplacement actuel tandis que les partitions de l'emplacement inutilisé ne sont pas accessibles par le système en cours d'exécution pendant le fonctionnement normal. Cette approche rend les mises à jour résistantes aux pannes en conservant l'emplacement inutilisé comme solution de secours: si une erreur se produit pendant ou immédiatement après une mise à jour, le système peut revenir à l'ancien emplacement et continuer à avoir un système opérationnel. Pour atteindre cet objectif, aucune partition utilisée par l'emplacement actuel ne doit être mise à jour dans le cadre de la mise à jour OTA (y compris les partitions pour lesquelles il n'y a qu'une seule copie).

Chaque emplacement a un attribut amorçable qui indique si l'emplacement contient un système correct à partir duquel le périphérique peut démarrer. L'emplacement actuel est amorçable lorsque le système est en cours d'exécution, mais l'autre emplacement peut avoir une ancienne version (toujours correcte) du système, une version plus récente ou des données non valides. Indépendamment de l'emplacement actuel , il existe un emplacement qui est l'emplacement actif (celui que le chargeur de démarrage démarrera au prochain démarrage) ou l'emplacement préféré .

Chaque emplacement a également un attribut de réussite défini par l'espace utilisateur, qui n'est pertinent que si l'emplacement est également amorçable. Un emplacement réussi doit pouvoir démarrer, s'exécuter et se mettre à jour. Un emplacement amorçable qui n'a pas été marqué comme réussi (après plusieurs tentatives de démarrage à partir de celui-ci) doit être marqué comme non amorçable par le chargeur de démarrage, y compris le changement de l'emplacement actif vers un autre emplacement amorçable (normalement vers l'emplacement en cours d'exécution immédiatement avant la tentative de démarrage dans le nouveau, actif). Les détails spécifiques de l'interface sont définis dans boot_control.h .

Démon du moteur de mise à jour

Les mises à jour système A / B utilisent un démon d'arrière-plan appelé update_engine pour préparer le système à démarrer dans une nouvelle version mise à jour. Ce démon peut effectuer les actions suivantes:

  • Lisez les partitions de l'emplacement A / B en cours et écrivez toutes les données dans les partitions de l'emplacement A / B inutilisées comme indiqué par le package OTA.
  • Appelez l'interface boot_control dans un flux de travail prédéfini.
  • Exécutez un programme de post-installation à partir de la nouvelle partition après avoir écrit toutes les partitions d'emplacement inutilisées, comme indiqué par le package OTA. (Pour plus de détails, voir Post-installation ).

Comme le démon update_engine n'est pas impliqué dans le processus de démarrage lui-même, il est limité dans ce qu'il peut faire pendant une mise à jour par les politiques et fonctionnalités SELinux dans l'emplacement actuel (ces politiques et fonctionnalités ne peuvent pas être mises à jour tant que le système ne démarre pas dans un nouvelle version). Pour maintenir un système robuste, le processus de mise à jour ne doit pas modifier la table de partition, le contenu des partitions dans l'emplacement actuel ou le contenu des partitions non A / B qui ne peuvent pas être effacées avec une réinitialisation d'usine.

Mettre à jour la source du moteur

La source update_engine se trouve dans system/update_engine . Les fichiers dexopt A / B OTA sont répartis entre installd et un gestionnaire de packages:

Pour un exemple fonctionnel, reportez-vous à /device/google/marlin/device-common.mk .

Mettre à jour les journaux du moteur

Pour les versions Android 8.x et antérieures, les journaux update_engine se trouvent dans logcat et dans le rapport de bogue. Pour rendre les journaux update_engine disponibles dans le système de fichiers, appliquez les modifications suivantes à votre build:

Ces modifications enregistrent une copie du journal update_engine le plus récent dans /data/misc/update_engine_log/update_engine. YEAR - TIME . En plus du journal actuel, les cinq journaux les plus récents sont enregistrés sous /data/misc/update_engine_log/ . Les utilisateurs avec l'ID de groupe de journaux pourront accéder aux journaux du système de fichiers.

Interactions avec le chargeur de démarrage

Le boot_control HAL est utilisé par update_engine (et éventuellement d'autres démons) pour indiquer au bootloader de quoi démarrer. Les exemples de scénarios courants et leurs états associés sont les suivants:

  • Cas normal : le système fonctionne à partir de son emplacement actuel, soit l'emplacement A ou B. Aucune mise à jour n'a été appliquée jusqu'à présent. L'emplacement actuel du système est amorçable, réussi et l'emplacement actif.
  • Mise à jour en cours : le système fonctionne à partir de l'emplacement B, l'emplacement B est donc l'emplacement amorçable, réussi et actif. L'emplacement A a été marqué comme non amorçable car le contenu de l'emplacement A est en cours de mise à jour mais pas encore terminé. Un redémarrage dans cet état devrait continuer à démarrer à partir de l'emplacement B.
  • Mise à jour appliquée, redémarrage en attente : le système fonctionne à partir de l'emplacement B, l'emplacement B est amorçable et réussi, mais l'emplacement A a été marqué comme actif (et est donc marqué comme amorçable). L'emplacement A n'est pas encore marqué comme réussi et un certain nombre de tentatives de démarrage à partir de l'emplacement A doivent être effectuées par le chargeur de démarrage.
  • Système redémarré dans une nouvelle mise à jour : le système fonctionne à partir de l'emplacement A pour la première fois, l'emplacement B est toujours amorçable et réussi, tandis que l'emplacement A est uniquement amorçable et toujours actif mais pas réussi. Un démon de l'espace utilisateur, update_verifier , doit marquer l'emplacement A comme réussi après certaines vérifications.

Prise en charge des mises à jour en streaming

Les appareils utilisateur n'ont pas toujours assez d'espace sur /data pour télécharger le package de mise à jour. Comme ni les OEM ni les utilisateurs ne souhaitent gaspiller de l'espace sur une partition /cache , certains utilisateurs se passent de mises à jour car l'appareil n'a nulle part où stocker le package de mise à jour. Pour résoudre ce problème, Android 8.0 a ajouté la prise en charge de la diffusion en continu des mises à jour A / B qui écrivent des blocs directement sur la partition B au fur et à mesure de leur téléchargement, sans avoir à stocker les blocs sur /data . Les mises à jour A / B en streaming ne nécessitent pratiquement pas de stockage temporaire et nécessitent juste assez de stockage pour environ 100 Ko de métadonnées.

Pour activer les mises à jour en continu dans Android 7.1, sélectionnez les correctifs suivants:

Ces correctifs sont nécessaires pour prendre en charge les mises à jour A / B en continu dans Android 7.1 et versions ultérieures, que ce soit en utilisant Google Mobile Services (GMS) ou tout autre client de mise à jour.

Vie d'une mise à jour A / B

Le processus de mise à jour démarre lorsqu'un package OTA (appelé dans le code une charge utile ) est disponible pour téléchargement. Les politiques de l'appareil peuvent différer le téléchargement de la charge utile et l'application en fonction du niveau de la batterie, de l'activité de l'utilisateur, de l'état de charge ou d'autres politiques. De plus, comme la mise à jour s'exécute en arrière-plan, les utilisateurs peuvent ne pas savoir qu'une mise à jour est en cours. Tout cela signifie que le processus de mise à jour peut être interrompu à tout moment en raison de politiques, de redémarrages inattendus ou d'actions de l'utilisateur.

Facultativement, les métadonnées du package OTA lui-même indiquent que la mise à jour peut être diffusée en continu; le même package peut également être utilisé pour une installation sans diffusion en continu. Le serveur peut utiliser les métadonnées pour indiquer au client qu'il est diffusé en continu afin que le client update_engine correctement l'OTA à update_engine . Les fabricants d'appareils disposant de leur propre serveur et client peuvent activer les mises à jour en continu en s'assurant que le serveur identifie que la mise à jour est en streaming (ou suppose que toutes les mises à jour sont en streaming) et que le client appelle correctement update_engine pour le streaming. Les fabricants peuvent utiliser le fait que le package est de la variante de diffusion en continu pour envoyer un indicateur au client afin de déclencher le transfert vers le côté du framework en tant que streaming.

Une fois qu'une charge utile est disponible, le processus de mise à jour est le suivant:

Étape Activités
1 L'emplacement actuel (ou «emplacement source») est marqué comme réussi (s'il n'est pas déjà marqué) avec markBootSuccessful() .
2 Le slot inutilisé (ou "slot cible") est marqué comme non amorçable en appelant la fonction setSlotAsUnbootable() . L'emplacement actuel est toujours marqué comme réussi au début de la mise à jour pour empêcher le chargeur de démarrage de retomber dans l'emplacement inutilisé, qui contiendra bientôt des données invalides. Si le système a atteint le point où il peut commencer à appliquer une mise à jour, l'emplacement actuel est marqué comme réussi même si d'autres composants majeurs sont cassés (comme l'interface utilisateur dans une boucle de crash) car il est possible de pousser un nouveau logiciel pour les corriger. problèmes.

La charge utile de mise à jour est un objet blob opaque avec les instructions de mise à jour vers la nouvelle version. La charge utile de mise à jour comprend les éléments suivants:
  • Métadonnées . Une partie relativement petite de la charge utile de mise à jour, les métadonnées contiennent une liste d'opérations pour produire et vérifier la nouvelle version sur l'emplacement cible. Par exemple, une opération peut décompresser un certain blob et l'écrire dans des blocs spécifiques d'une partition cible, ou lire à partir d'une partition source, appliquer un correctif binaire et écrire dans certains blocs d'une partition cible.
  • Données supplémentaires . En tant que gros de la charge utile de mise à jour, les données supplémentaires associées aux opérations se composent de l'objet blob compressé ou du correctif binaire dans ces exemples.
3 Les métadonnées de la charge utile sont téléchargées.
4 Pour chaque opération définie dans les métadonnées, dans l'ordre, les données associées (le cas échéant) sont téléchargées dans la mémoire, l'opération est appliquée et la mémoire associée est supprimée.
5 Les partitions entières sont relues et vérifiées par rapport au hachage attendu.
6 L'étape de post-installation (le cas échéant) est exécutée. En cas d'erreur lors de l'exécution d'une étape, la mise à jour échoue et est réessayée avec éventuellement une charge utile différente. Si toutes les étapes jusqu'à présent ont réussi, la mise à jour réussit et la dernière étape est exécutée.
sept L' emplacement inutilisé est marqué comme actif en appelant setActiveBootSlot() . Marquer le slot inutilisé comme actif ne signifie pas qu'il finira de démarrer. Le chargeur de démarrage (ou le système lui-même) peut basculer le slot actif s'il ne lit pas un état de réussite.
8 La post-installation (décrite ci-dessous) consiste à exécuter un programme à partir de la version "nouvelle mise à jour" tout en fonctionnant toujours dans l'ancienne version. Si elle est définie dans le package OTA, cette étape est obligatoire et le programme doit retourner avec le code de sortie 0 ; sinon, la mise à jour échoue.
9 Une fois que le système a réussi à démarrer suffisamment loin dans le nouvel emplacement et a terminé les vérifications post-redémarrage, l'emplacement actuel (anciennement «l'emplacement cible») est marqué comme réussi en appelant markBootSuccessful() .

Post-installation

Pour chaque partition où une étape de post-installation est définie, update_engine monte la nouvelle partition dans un emplacement spécifique et exécute le programme spécifié dans l'OTA par rapport à la partition montée. Par exemple, si le programme de post-installation est défini comme usr/bin/postinstall dans la partition système, cette partition de l'emplacement inutilisé sera montée dans un emplacement fixe (tel que /postinstall_mount ) et le /postinstall_mount/usr/bin/postinstall commande /postinstall_mount/usr/bin/postinstall est exécutée.

Pour que la post-installation réussisse, l'ancien noyau doit être capable de:

  • Montez le nouveau format de système de fichiers . Le type de système de fichiers ne peut pas changer à moins qu'il ne soit pris en charge dans l'ancien noyau, y compris des détails tels que l'algorithme de compression utilisé si vous utilisez un système de fichiers compressé (par exemple SquashFS).
  • Comprenez le format du programme de post-installation de la nouvelle partition . Si vous utilisez un binaire ELF (Executable and Linkable Format), il doit être compatible avec l'ancien noyau (par exemple, un nouveau programme 64 bits fonctionnant sur un ancien noyau 32 bits si l'architecture est passée de versions 32 à 64 bits). À moins que le chargeur ( ld ) ne soit invité à utiliser d'autres chemins ou à créer un binaire statique, les bibliothèques seront chargées à partir de l'ancienne image système et non de la nouvelle.

Par exemple, vous pouvez utiliser un script shell comme programme de post-installation interprété par le binaire shell de l'ancien système avec un #! marqueur en haut), puis configurez les chemins de bibliothèque à partir du nouvel environnement pour exécuter un programme de post-installation binaire plus complexe. Vous pouvez également exécuter l'étape de post-installation à partir d'une partition plus petite dédiée pour permettre la mise à jour du format du système de fichiers dans la partition principale du système sans entraîner de problèmes de compatibilité descendante ou de mises à jour de tremplin; cela permettrait aux utilisateurs de mettre à jour directement vers la dernière version à partir d'une image d'usine.

Le nouveau programme de post-installation est limité par les politiques SELinux définies dans l'ancien système. En tant que telle, l'étape de post-installation convient à l'exécution des tâches requises par la conception sur un périphérique donné ou à d'autres tâches au mieux (par exemple, mettre à jour le micrologiciel ou le chargeur de démarrage compatible A / B, préparer des copies de bases de données pour la nouvelle version, etc. ). L'étape de post-installation ne convient pas aux corrections de bogues ponctuelles avant le redémarrage qui nécessitent des autorisations imprévues.

Le programme fonctionne postinstall sélectionnés dans le postinstall contexte SELinux. Tous les fichiers de la nouvelle partition montée seront marqués avec postinstall_file , quels que soient leurs attributs après le redémarrage dans ce nouveau système. Les modifications apportées aux attributs SELinux dans le nouveau système n'auront aucun impact sur l'étape de post-installation. Si le programme de post-installation nécessite des autorisations supplémentaires, celles-ci doivent être ajoutées au contexte de post-installation.

Après le redémarrage

Après le redémarrage, update_verifier déclenche la vérification d'intégrité à l'aide de dm-verity. Cette vérification commence avant zygote pour éviter que les services Java apportent des modifications irréversibles qui empêcheraient une restauration en toute sécurité. Au cours de ce processus, le chargeur de démarrage et le noyau peuvent également déclencher un redémarrage si le démarrage vérifié ou dm-verity détecte une corruption. Une fois la vérification terminée, update_verifier marque le démarrage réussi.

update_verifier lira uniquement les blocs répertoriés dans /data/ota_package/care_map.txt , qui est inclus dans un package A / B OTA lors de l'utilisation du code AOSP. Le client de mise à jour du système Java, tel que GmsCore, extrait care_map.txt , configure l'autorisation d'accès avant de redémarrer l'appareil et supprime le fichier extrait une fois que le système a démarré avec succès dans la nouvelle version.