Déplacer fastboot vers l'espace utilisateur

Fastboot est le nom d'un module et d'un mode de bootloader. Android 10 et versions ultérieures sont compatibles avec les partitions redimensionnables en déplaçant l'implémentation fastboot du bootloader vers l'espace utilisateur. Cette relocalisation permet de déplacer le code de clignotement vers un emplacement commun maintenable et testable, avec uniquement les parties spécifiques au fournisseur de fastboot implémentées par une couche d'abstraction matérielle (HAL). De plus, Android 12 et les versions ultérieures permettent de flasher des ramdisks à l'aide d'une commande fastboot ajoutée.

Unifier fastboot et la récupération

Étant donné que fastboot et la récupération de l'espace utilisateur sont similaires, vous pouvez les fusionner en une seule partition ou un seul binaire. Cela présente des avantages tels que l'utilisation de moins d'espace, la réduction du nombre total de partitions et le partage du noyau et des bibliothèques entre fastboot et la récupération.

Fastbootd est le nom d'un mode et d'un daemon de l'espace utilisateur. Pour prendre en charge fastbootd, le bootloader doit implémenter une nouvelle commande de bloc de contrôle du démarrage (BCB) de boot-fastboot. Pour passer en mode fastbootd, le bootloader écrit boot-fastboot dans le champ de commande du message BCB et laisse le champ recovery du BCB inchangé (pour permettre de redémarrer les tâches de récupération interrompues). Les champs status, stage et reserved restent également inchangés. Le bootloader se charge et démarre dans l'image de récupération lorsqu'il voit boot-fastboot dans le champ de commande BCB. Recovery analyse ensuite le message BCB et passe en mode fastbootd.

Commandes ADB

Cette section décrit la commande adb permettant d'intégrer fastbootd. La commande a des résultats différents selon qu'elle est exécutée par le système ou par la récupération.

Commande Description
reboot fastboot
  • Redémarre dans fastbootd (système).
  • Accède directement à fastbootd sans redémarrage (récupération).

Commandes Fastboot

Cette section décrit les commandes fastboot permettant d'intégrer fastbootd, y compris les nouvelles commandes permettant de flasher et de gérer les partitions logiques. Certaines commandes ont des résultats différents selon qu'elles ont été exécutées par le bootloader ou par fastbootd.

Commande Description
reboot recovery
  • Redémarre en mode Récupération (bootloader).
  • Accède directement à la récupération sans redémarrage (fastbootd).
reboot fastboot Redémarre sur fastbootd.
getvar is-userspace
  • Renvoie yes (fastbootd).
  • Renvoie no (bootloader).
getvar is-logical:<partition> Renvoie yes si la partition donnée est une partition logique, ou no si ce n'est pas le cas. Les partitions logiques sont compatibles avec toutes les commandes listées ci-dessous.
getvar super-partition-name Renvoie le nom de la super partition. Le nom inclut le suffixe de slot actuel si la super partition est une partition A/B (ce qui n'est généralement pas le cas).
create-logical-partition <partition> <size> Crée une partition logique avec le nom et la taille indiqués. Le nom ne doit pas déjà exister en tant que partition logique.
delete-logical-partition <partition> Supprime la partition logique donnée (efface la partition).
resize-logical-partition <partition> <size> Redimensionne la partition logique à la nouvelle taille sans modifier son contenu. Échec si l'espace disponible est insuffisant pour effectuer le redimensionnement.
flash <partition><filename> ] Écrit un fichier dans une partition flash. L'appareil doit être déverrouillé.
erase <partition> Efface une partition (l'effacement sécurisé n'est pas obligatoire). L'appareil doit être déverrouillé.
getvar <variable> | all Affiche une variable du bootloader ou toutes les variables. Si la variable n'existe pas, une erreur est renvoyée.
set_active <slot>

Définit l'emplacement de démarrage A/B donné sur active. Lors de la prochaine tentative de démarrage, le système démarre à partir de l'emplacement spécifié.

Pour la prise en charge A/B, les emplacements sont des ensembles de partitions en double qui peuvent être démarrés indépendamment. Les emplacements sont nommés a, b, etc., et sont différenciés en ajoutant les suffixes _a, _b, etc., au nom de la partition.

reboot Redémarre l'appareil normalement.
reboot-bootloader (ou reboot bootloader) Redémarre l'appareil dans le bootloader.
fastboot fetch vendor_boot <out.img>

Utilisez-le dans Android 12 et versions ultérieures pour prendre en charge le flashing des ramdisks du fournisseur.

Obtient la taille de la partition entière et la taille du segment. Récupère les données de chaque bloc, puis les assemble pour <out.img>

Pour en savoir plus, consultez fastboot fetch vendor_boot <out.img>.

fastboot flash vendor_boot:default <vendor-ramdisk.img>

Utilisez-le dans Android 12 et versions ultérieures pour prendre en charge le flashage des ramdisks du fournisseur.

Il s'agit d'une variante spéciale de la commande flash. Elle exécute une fonction d'image fetch vendor_boot, comme si fastboot fetch avait été appelée. La nouvelle image vendor_boot qu'il flashe dépend de la version de l'en-tête de démarrage (version 3 ou version 4).

Pour en savoir plus, consultez fastboot flash vendor_boot:default <vendor-ramdisk.img>.

fastboot flash vendor_boot:<foo> <vendor-ramdisk.img> Utilisez-le dans Android 12 et versions ultérieures pour prendre en charge le flashage des ramdisks du fournisseur.

Récupère l'image vendor_boot. Renvoie une erreur si l'en-tête de démarrage du fournisseur est la version 3. S'il s'agit de la version 4, il trouve le bon fragment de disque RAM du fournisseur (le cas échéant). Il remplace l'image par celle fournie, recalcule les tailles et les décalages, et affiche le nouveau vendor_boot image.

Pour en savoir plus, consultez fastboot flash vendor_boot:<foo> <vendor-ramdisk.img>.

Fastboot et bootloader

Le bootloader flashe les partitions bootloader, radio et boot/recovery, après quoi l'appareil démarre en mode fastboot (espace utilisateur) et flashe toutes les autres partitions. Le bootloader doit être compatible avec les commandes suivantes.

Commande Description
download Télécharge l'image sur la mémoire flash.
flash recovery <image>/ flash boot <image>/ flash bootloader <image>/ Flashe la partition recovery/boot et le bootloader.
reboot Redémarre l'appareil.
reboot fastboot Redémarre en mode Fastboot.
reboot recovery Redémarre en mode Recovery.
getvar Obtient une variable de bootloader requise pour le flashage de l'image de récupération/démarrage (par exemple, current-slot et max-download-size).
oem <command> Commande définie par l'OEM.

Partitions dynamiques

Le bootloader ne doit pas autoriser le flashage ni l'effacement des partitions dynamiques et doit renvoyer une erreur si ces opérations sont tentées. Pour les appareils à partition dynamique rééquipés, l'outil fastboot (et le bootloader) sont compatibles avec un mode forcé permettant de flasher directement une partition dynamique en mode bootloader. Par exemple, si system est une partition dynamique sur l'appareil rééquipé, l'utilisation de la commande fastboot --force flash system permet au bootloader (au lieu de fastbootd) de flasher la partition.

Recharge en mode désactivé

Si un appareil est compatible avec la recharge en mode éteint ou démarre automatiquement dans un mode spécial lorsque l'alimentation est appliquée, une implémentation de la commande fastboot oem off-mode-charge 0 doit contourner ces modes spéciaux, de sorte que l'appareil démarre comme si l'utilisateur avait appuyé sur le bouton d'alimentation.

HAL OEM Fastboot

Pour remplacer complètement le bootloader fastboot, fastboot doit gérer toutes les commandes fastboot existantes. Bon nombre de ces commandes proviennent d'OEM et sont documentées, mais nécessitent une implémentation personnalisée. De nombreuses commandes spécifiques aux OEM ne sont pas documentées. Pour gérer de telles commandes, le HAL fastboot spécifie les commandes OEM requises. Les OEM peuvent également implémenter leurs propres commandes.

La définition de fastboot HAL est la suivante :

import IFastbootLogger;

/**
 * IFastboot interface implements vendor specific fastboot commands.
 */
interface IFastboot {
    /**
     * Returns a bool indicating whether the bootloader is enforcing verified
     * boot.
     *
     * @return verifiedBootState True if the bootloader is enforcing verified
     * boot and False otherwise.
     */
    isVerifiedBootEnabled() generates (bool verifiedBootState);

    /**
     * Returns a bool indicating the off-mode-charge setting. If off-mode
     * charging is enabled, the device autoboots into a special mode when
     * power is applied.
     *
     * @return offModeChargeState True if the setting is enabled and False if
     * not.
     */
    isOffModeChargeEnabled() generates (bool offModeChargeState);

    /**
     * Returns the minimum battery voltage required for flashing in mV.
     *
     * @return batteryVoltage Minimum battery voltage (in mV) required for
     * flashing to be successful.
     */
    getBatteryVoltageFlashingThreshold() generates (int32_t batteryVoltage);

    /**
     * Returns the file system type of the partition. This is only required for
     * physical partitions that need to be wiped and reformatted.
     *
     * @return type Can be ext4, f2fs or raw.
     * @return result SUCCESS if the operation is successful,
     * FAILURE_UNKNOWN if the partition is invalid or does not require
     * reformatting.
     */
    getPartitionType(string partitionName) generates (FileSystemType type, Result result);

    /**
     * Executes a fastboot OEM command.
     *
     * @param oemCmd The oem command that is passed to the fastboot HAL.
     * @response result Returns the status SUCCESS if the operation is
     * successful,
     * INVALID_ARGUMENT for bad arguments,
     * FAILURE_UNKNOWN for an invalid/unsupported command.
     */
    doOemCommand(string oemCmd) generates (Result result);

};

Activer fastbootd

Pour activer fastbootd sur un appareil :

  1. Ajoute fastbootd à PRODUCT_PACKAGES dans device.mk : PRODUCT_PACKAGES += fastbootd.

  2. Assurez-vous que les HAL fastboot, boot control et health sont inclus dans l'image de récupération.

  3. Ajoutez les autorisations SEPolicy spécifiques à l'appareil requises par fastbootd. Par exemple, fastbootd nécessite un accès en écriture à une partition spécifique à l'appareil pour flasher cette partition. De plus, l'implémentation HAL fastboot peut également nécessiter des autorisations spécifiques à l'appareil.

Pour valider fastboot userspace, exécutez la Vendor Test Suite (VTS).

Ramdisques du fournisseur Flash

Android 12 et versions ultérieures permettent de flasher des ramdisks avec une commande fastboot supplémentaire qui extrait l'image vendor_boot complète d'un appareil. La commande invite l'outil fastboot côté hôte à lire l'en-tête de démarrage du fournisseur, à recréer l'image et à flasher la nouvelle image.

Pour extraire l'image vendor_boot complète, la commande fetch:vendor_boot a été ajoutée au protocole fastboot et à l'implémentation fastbootd du protocole dans Android 12. Notez que fastbootd implémente cette commande, mais que le bootloader lui-même ne le fait peut-être pas. Les OEM peuvent ajouter la commande fetch:vendor_boot à leur implémentation du bootloader du protocole. Toutefois, si la commande n'est pas reconnue en mode bootloader, le flashage de ramdisks de fournisseur individuels en mode bootloader n'est pas une option prise en charge par le fournisseur.

Modifications du bootloader

Les commandes getvar:max-fetch-size et fetch:name sont implémentées dans fastbootd. Pour prendre en charge le flashage des ramdisks du fournisseur dans le bootloader, vous devez implémenter ces deux commandes.

Modifications apportées à fastbootd

getvar:max-fetch-size est semblable à max-download-size. Elle spécifie la taille maximale que l'appareil peut envoyer dans une réponse DATA. Le pilote ne doit pas récupérer une taille supérieure à cette valeur.

fetch:name[:offset[:size]] effectue une série de vérifications sur l'appareil. La commande fetch:name[:offset[:size]] renvoie des données si toutes les conditions suivantes sont remplies :

  • L'appareil exécute une version débogable.
  • L'appareil est déverrouillé (l'état de démarrage est orange).
  • Le nom de la partition récupérée est vendor_boot.
  • La valeur size est comprise entre 0 et max-fetch-size (0 < size <= max-fetch-size).

Une fois ces éléments vérifiés, fetch:name[:offset[:size]] renvoie la taille et le décalage de la partition. Remarques :

  • fetch:name équivaut à fetch:name:0, qui équivaut à fetch:name:0:partition_size.
  • fetch:name:offset équivaut à fetch:name:offset:(partition_size - offset).

Par conséquent, fetch:name[:offset[:size]] = fetch:name:offset:(partition_size - offset).

Lorsque offset ou partition_size (ou les deux) ne sont pas spécifiés, les valeurs par défaut sont utilisées. Pour offset, il s'agit de 0, et pour size, il s'agit de la valeur calculée de partition_size - offset.

  • Décalage spécifié, taille non spécifiée : size = partition_size - offset
  • Aucune valeur spécifiée : les valeurs par défaut sont utilisées pour les deux, size = partition_size = 0.

Par exemple, fetch:foo récupère l'intégralité de la partition foo au décalage 0.

Changements de pilotes

Des commandes ont été ajoutées à l'outil fastboot pour implémenter les modifications apportées aux pilotes. Chacun est associé à sa définition complète dans le tableau des commandes Fastboot.

  • fastboot fetch vendor_boot out.img

    • Appelle getvar max-fetch-size pour déterminer la taille du segment.
    • Appelle getvar partition-size:vendor_boot[_a] pour déterminer la taille de l'ensemble de la partition.
    • Appelle fastboot fetch vendor_boot[_a]:offset:size pour chaque bloc. (La taille du bloc est supérieure à la taille vendor_boot, il n'y a donc normalement qu'un seul bloc.)
    • Assemble les données pour out.img.
  • fastboot flash vendor_boot:default vendor-ramdisk.img

    Il s'agit d'une variante spéciale de la commande flash. Elle récupère l'image vendor_boot, comme si fastboot fetch avait été appelé.

    • Si l'en-tête de démarrage du fournisseur est la version 3, il effectue les opérations suivantes :
      • Remplace le ramdisk du fournisseur par l'image donnée.
      • L'image vendor_boot clignote.
    • Si l'en-tête de démarrage du fournisseur est la version 4, il effectue les opérations suivantes :
      • Remplace l'intégralité du ramdisk du fournisseur par l'image donnée, de sorte que celle-ci devienne le seul fragment de ramdisk du fournisseur dans l'image vendor_boot.
      • Recalcule la taille et le décalage dans la table ramdisk du fournisseur.
      • L'image vendor_boot clignote.
  • fastboot flash vendor_boot:foo vendor-ramdisk.img

    Extrait vendor_boot image, comme si fastboot fetch avait été appelé.

    • Si l'en-tête de démarrage du fournisseur est la version 3, une erreur est renvoyée.
    • Si l'en-tête de démarrage du fournisseur est de version 4, il effectue les opérations suivantes :

      • Recherche le fragment ramdisk du fournisseur portant le nom ramdisk_<var>&lt;foo></var>. Si aucune correspondance n'est trouvée ou si plusieurs correspondances sont trouvées, une erreur est renvoyée.
      • Remplace le fragment de ramdisk du fournisseur par l'image donnée.
      • Recalcule chaque taille et chaque décalage dans le tableau ramdisk du fournisseur.
      • L'image vendor_boot clignote.
    • Si <foo> n'est pas spécifié, le système tente de trouver ramdisk_.

mkbootimg

Le nom default est réservé à la dénomination des fragments de ramdisk du fournisseur dans Android 12 et versions ultérieures. Bien que la sémantique fastboot flash vendor_boot:default reste la même, vous ne devez pas nommer vos fragments de disque RAM default.

Modifications apportées à SELinux

Une modification a été apportée à fastbootd.te pour permettre le flashage des ramdisks du fournisseur.