Implémenter des partitions dynamiques

Le partitionnement dynamique est implémenté à l'aide du module dm-linear device-mapper dans le noyau Linux. La partition super contient des métadonnées listant les noms et les plages de blocs de chaque partition dynamique dans super. Lors de la première étape de init, ces métadonnées sont analysées et validées, et des périphériques de bloc virtuel sont créés pour représenter chaque partition dynamique.

Lorsque vous appliquez une mise à jour OTA, des partitions dynamiques sont automatiquement créées, redimensionnées ou supprimées selon les besoins. Pour les appareils A/B, il existe deux copies des métadonnées, et les modifications ne sont appliquées qu'à la copie représentant l'emplacement cible.

Étant donné que les partitions dynamiques sont implémentées dans l'espace utilisateur, les partitions nécessaires au bootloader ne peuvent pas être dynamiques. Par exemple, boot, dtbo et vbmeta sont lus par le bootloader et doivent donc rester des partitions physiques.

Chaque partition dynamique peut appartenir à un groupe de mise à jour. Ces groupes limitent l'espace maximal que les partitions de ce groupe peuvent consommer. Par exemple, system et vendor peuvent appartenir à un groupe qui limite la taille totale de system et vendor.

Implémenter des partitions dynamiques sur de nouveaux appareils

Cette section explique comment implémenter des partitions dynamiques sur les nouveaux appareils lancés avec Android 10 ou version ultérieure. Pour mettre à jour les appareils existants, consultez Mettre à niveau des appareils Android.

Modifications des partitions

Pour les appareils lancés avec Android 10, créez une partition appelée super. La partition super gère les emplacements A/B en interne. Les appareils A/B n'ont donc pas besoin de partitions super_a et super_b distinctes. Toutes les partitions AOSP en lecture seule qui ne sont pas utilisées par le bootloader doivent être dynamiques et doivent être supprimées de la table de partition GUID (GPT). Les partitions spécifiques au fournisseur n'ont pas besoin d'être dynamiques et peuvent être placées dans le GPT.

Pour estimer la taille de super, ajoutez les tailles des partitions supprimées du GPT. Pour les appareils A/B, cela doit inclure la taille des deux emplacements. La figure 1 montre un exemple de table de partition avant et après la conversion en partitions dynamiques.

Mise en page de la table de partitionnement
Figure 1. Nouvelle mise en page de la table de partitions physiques lors de la conversion en partitions dynamiques

Voici les partitions dynamiques acceptées :

  • Système
  • Fournisseur
  • Produit
  • System Ext
  • ODM

Pour les appareils lancés avec Android 10, l'option de ligne de commande du noyau androidboot.super_partition doit être vide afin que la commande sysprop ro.boot.super_partition soit vide.

Alignement des partitions

Le module device-mapper peut fonctionner moins efficacement si la partition super n'est pas correctement alignée. La partition super DOIT être alignée sur la taille minimale des requêtes d'E/S, telle qu'elle est déterminée par la couche de bloc. Par défaut, le système de compilation (via lpmake, qui génère l'image de partition super) suppose qu'un alignement de 1 Mio est suffisant pour chaque partition dynamique. Toutefois, les fournisseurs doivent s'assurer que la partition super est correctement alignée.

Vous pouvez déterminer la taille de requête minimale d'un périphérique de bloc en inspectant sysfs. Exemple :

# ls -l /dev/block/by-name/super
lrwxrwxrwx 1 root root 16 1970-04-05 01:41 /dev/block/by-name/super -> /dev/block/sda17
# cat /sys/block/sda/queue/minimum_io_size
786432

Vous pouvez vérifier l'alignement de la partition super de la même manière :

# cat /sys/block/sda/sda17/alignment_offset

Le décalage d'alignement DOIT être égal à 0.

Modifications de la configuration de l'appareil

Pour activer le partitionnement dynamique, ajoutez l'indicateur suivant dans device.mk :

PRODUCT_USE_DYNAMIC_PARTITIONS := true

Modifications de la configuration du tableau

Vous devez définir la taille de la partition super :

BOARD_SUPER_PARTITION_SIZE := <size-in-bytes>

Sur les appareils A/B, le système de compilation génère une erreur si la taille totale des images de partition dynamique est supérieure à la moitié de la taille de la partition super.

Vous pouvez configurer la liste des partitions dynamiques comme suit. Pour les appareils utilisant des groupes de mise à jour, listez les groupes dans la variable BOARD_SUPER_PARTITION_GROUPS. Chaque nom de groupe possède ensuite une variable BOARD_group_SIZE et BOARD_group_PARTITION_LIST. Pour les appareils A/B, la taille maximale d'un groupe ne doit couvrir qu'un seul emplacement, car les noms de groupe sont suffixés par un emplacement en interne.

Voici un exemple d'appareil qui place toutes les partitions dans un groupe appelé example_dynamic_partitions :

BOARD_SUPER_PARTITION_GROUPS := example_dynamic_partitions
BOARD_EXAMPLE_DYNAMIC_PARTITIONS_SIZE := 6442450944
BOARD_EXAMPLE_DYNAMIC_PARTITIONS_PARTITION_LIST := system vendor product

Voici un exemple d'appareil qui place les services système et produit dans group_foo, et vendor, product et odm dans group_bar :

BOARD_SUPER_PARTITION_GROUPS := group_foo group_bar
BOARD_GROUP_FOO_SIZE := 4831838208
BOARD_GROUP_FOO_PARTITION_LIST := system product_services
BOARD_GROUP_BAR_SIZE := 1610612736
BOARD_GROUP_BAR_PARTITION_LIST := vendor product odm
  • Pour les appareils de lancement Virtual A/B, la somme des tailles maximales de tous les groupes doit être au maximum :
    BOARD_SUPER_PARTITION_SIZE - overhead
    Consultez Implémenter Virtual A/B.
  • Pour les appareils de lancement de test A/B, la somme des tailles maximales de tous les groupes doit être :
    BOARD_SUPER_PARTITION_SIZE / 2 - overhead
  • Pour les appareils non A/B et les appareils A/B de remplacement, la somme des tailles maximales de tous les groupes doit être la suivante :
    BOARD_SUPER_PARTITION_SIZE - overhead
  • Au moment de la compilation, la somme des tailles des images de chaque partition d'un groupe de mise à jour ne doit pas dépasser la taille maximale du groupe.
  • La surcharge est nécessaire dans le calcul pour tenir compte des métadonnées, des alignements, etc. Une surcharge raisonnable est de 4 Mio, mais vous pouvez choisir une surcharge plus importante si l'appareil en a besoin.

Dimensionner les partitions dynamiques

Avant les partitions dynamiques, la taille des partitions était surdimensionnée pour s'assurer qu'elles disposaient de suffisamment d'espace pour les futures mises à jour. La taille réelle a été prise telle quelle, et la plupart des partitions en lecture seule disposaient d'un certain espace libre dans leur système de fichiers. Dans les partitions dynamiques, cet espace libre est inutilisable et pourrait être utilisé pour étendre les partitions lors d'une mise à jour OTA. Il est essentiel de s'assurer que les partitions ne gaspillent pas d'espace et qu'elles sont allouées à la taille minimale possible.

Pour les images ext4 en lecture seule, le système de compilation alloue automatiquement la taille minimale si aucune taille de partition codée en dur n'est spécifiée. Le système de compilation ajuste l'image de sorte que le système de fichiers dispose du moins d'espace inutilisé possible. Cela permet de s'assurer que l'appareil ne gaspille pas d'espace qui pourrait être utilisé pour les mises à jour OTA.

De plus, les images ext4 peuvent être compressées davantage en activant la déduplication au niveau des blocs. Pour l'activer, utilisez la configuration suivante :

BOARD_EXT4_SHARE_DUP_BLOCKS := true

Si l'allocation automatique d'une taille minimale de partition n'est pas souhaitable, il existe deux façons de contrôler la taille de la partition. Vous pouvez spécifier une quantité minimale d'espace libre avec BOARD_partitionIMAGE_PARTITION_RESERVED_SIZE ou BOARD_partitionIMAGE_PARTITION_SIZE pour forcer les partitions dynamiques à une taille spécifique. Aucune de ces options n'est recommandée, sauf si cela est nécessaire.

Exemple :

BOARD_PRODUCTIMAGE_PARTITION_RESERVED_SIZE := 52428800

Cela force le système de fichiers dans product.img à disposer de 50 Mio d'espace inutilisé.

Modifications apportées au système en tant que racine

Les appareils lancés avec Android 10 ne doivent pas utiliser system-as-root.

Les appareils dotés de partitions dynamiques (qu'ils soient lancés avec des partitions dynamiques ou qu'ils en soient équipés ultérieurement) ne doivent pas utiliser system-as-root. Le noyau Linux ne peut pas interpréter la partition super et ne peut donc pas monter system lui-même. system est désormais monté par init de première étape, qui réside dans le ramdisk.

Ne définissez pas BOARD_BUILD_SYSTEM_ROOT_IMAGE. Dans Android 10, l'indicateur BOARD_BUILD_SYSTEM_ROOT_IMAGE n'est utilisé que pour déterminer si le système est monté par le noyau ou par le init de première étape dans le ramdisk.

Si vous définissez BOARD_BUILD_SYSTEM_ROOT_IMAGE sur true, une erreur de compilation se produit lorsque PRODUCT_USE_DYNAMIC_PARTITIONS est également défini sur true.

Lorsque BOARD_USES_RECOVERY_AS_BOOT est défini sur "true", l'image de récupération est créée en tant que boot.img, contenant le ramdisk de récupération. Auparavant, le bootloader utilisait le paramètre de ligne de commande du noyau skip_initramfs pour décider du mode de démarrage. Pour les appareils Android 10, le bootloader NE DOIT PAS transmettre skip_initramfs à la ligne de commande du noyau. À la place, le bootloader doit transmettre androidboot.force_normal_boot=1 pour ignorer la récupération et démarrer Android normalement. Les appareils lancés avec Android 12 ou version ultérieure doivent utiliser bootconfig pour transmettre androidboot.force_normal_boot=1.

Modifications de la configuration AVB

Lorsque vous utilisez Android Verified Boot 2.0, si l'appareil n'utilise pas de descripteurs de partition chaînés, aucune modification n'est nécessaire. Toutefois, si vous utilisez des partitions chaînées et que l'une des partitions validées est dynamique, des modifications sont nécessaires.

Voici un exemple de configuration pour un appareil qui enchaîne vbmeta pour les partitions system et vendor.

BOARD_AVB_SYSTEM_KEY_PATH := external/avb/test/data/testkey_rsa2048.pem
BOARD_AVB_SYSTEM_ALGORITHM := SHA256_RSA2048
BOARD_AVB_SYSTEM_ROLLBACK_INDEX := $(PLATFORM_SECURITY_PATCH_TIMESTAMP)
BOARD_AVB_SYSTEM_ROLLBACK_INDEX_LOCATION := 1

BOARD_AVB_VENDOR_KEY_PATH := external/avb/test/data/testkey_rsa2048.pem
BOARD_AVB_VENDOR_ALGORITHM := SHA256_RSA2048
BOARD_AVB_VENDOR_ROLLBACK_INDEX := $(PLATFORM_SECURITY_PATCH_TIMESTAMP)
BOARD_AVB_VENDOR_ROLLBACK_INDEX_LOCATION := 1

Avec cette configuration, le bootloader s'attend à trouver un pied de page vbmeta à la fin des partitions system et vendor. Étant donné que ces partitions ne sont plus visibles par le bootloader (elles résident dans super), deux modifications sont nécessaires.

  • Ajoutez les partitions vbmeta_system et vbmeta_vendor à la table de partition de l'appareil. Pour les appareils de test A/B, ajoutez vbmeta_system_a, vbmeta_system_b, vbmeta_vendor_a et vbmeta_vendor_b. Si vous ajoutez une ou plusieurs de ces partitions, elles doivent avoir la même taille que la partition vbmeta.
  • Renommez les indicateurs de configuration en ajoutant VBMETA_ et spécifiez les partitions auxquelles l'enchaînement s'étend :
    BOARD_AVB_VBMETA_SYSTEM := system
    BOARD_AVB_VBMETA_SYSTEM_KEY_PATH := external/avb/test/data/testkey_rsa2048.pem
    BOARD_AVB_VBMETA_SYSTEM_ALGORITHM := SHA256_RSA2048
    BOARD_AVB_VBMETA_SYSTEM_ROLLBACK_INDEX := $(PLATFORM_SECURITY_PATCH_TIMESTAMP)
    BOARD_AVB_VBMETA_SYSTEM_ROLLBACK_INDEX_LOCATION := 1
    
    BOARD_AVB_VBMETA_VENDOR := vendor
    BOARD_AVB_VBMETA_VENDOR_KEY_PATH := external/avb/test/data/testkey_rsa2048.pem
    BOARD_AVB_VBMETA_VENDOR_ALGORITHM := SHA256_RSA2048
    BOARD_AVB_VBMETA_VENDOR_ROLLBACK_INDEX := $(PLATFORM_SECURITY_PATCH_TIMESTAMP)
    BOARD_AVB_VBMETA_VENDOR_ROLLBACK_INDEX_LOCATION := 1

Un appareil peut utiliser l'une ou l'autre de ces partitions, ou aucune d'elles. Les modifications ne sont nécessaires que lors de l'enchaînement à une partition logique.

Modifications apportées au bootloader AVB

Si le bootloader a intégré libavb, incluez les correctifs suivants :

Si vous utilisez des partitions chaînées, incluez un correctif supplémentaire :

  • 49936b4c0109411fdd38bd4ba3a32a01c40439a9 — "libavb: Support vbmeta blobs in beginning of partition."

Modifications apportées à la ligne de commande du noyau

Un nouveau paramètre, androidboot.boot_devices, doit être ajouté à la ligne de commande du noyau. Cette option est utilisée par init pour activer les liens symboliques /dev/block/by-name. Il doit s'agir du composant de chemin d'accès à l'appareil vers le lien symbolique sous-jacent par nom créé par ueventd, c'est-à-dire /dev/block/platform/device-path/by-name/partition-name. Les appareils lancés avec Android 12 ou version ultérieure doivent utiliser bootconfig pour transmettre androidboot.boot_devices à init.

Par exemple, si le lien symbolique de la super partition par nom est /dev/block/platform/soc/100000.ufshc/by-name/super, vous pouvez ajouter le paramètre de ligne de commande dans le fichier BoardConfig.mk comme suit :

BOARD_KERNEL_CMDLINE += androidboot.boot_devices=soc/100000.ufshc
Vous pouvez ajouter le paramètre bootconfig dans le fichier BoardConfig.mk comme suit :
BOARD_BOOTCONFIG += androidboot.boot_devices=soc/100000.ufshc

Modifications apportées à fstab

L'arborescence des périphériques et les overlays de l'arborescence des périphériques ne doivent pas contenir d'entrées fstab. Utilisez un fichier fstab qui fera partie du ramdisk.

Les modifications doivent être apportées au fichier fstab pour les partitions logiques :

  • Le champ des indicateurs fs_mgr doit inclure l'indicateur logical et l'indicateur first_stage_mount, introduit dans Android 10, qui indique qu'une partition doit être montée lors de la première étape.
  • Une partition peut spécifier avb=vbmeta partition name comme indicateur fs_mgr. La partition vbmeta spécifiée est ensuite initialisée par la première étape init avant toute tentative de montage des appareils.
  • Le champ dev doit correspondre au nom de la partition.

Les entrées fstab suivantes définissent system, vendor et product comme partitions logiques en suivant les règles ci-dessus.

#<dev>  <mnt_point> <type>  <mnt_flags options> <fs_mgr_flags>
system   /system     ext4    ro,barrier=1        wait,slotselect,avb=vbmeta,logical,first_stage_mount
vendor   /vendor     ext4    ro,barrier=1        wait,slotselect,avb,logical,first_stage_mount
product  /product    ext4    ro,barrier=1        wait,slotselect,avb,logical,first_stage_mount

Copiez le fichier fstab dans le ramdisk de la première étape.

Modifications apportées à SELinux

Le périphérique de bloc de superpartition doit être marqué avec le libellé super_block_device. Par exemple, si le lien symbolique par nom de la super partition est /dev/block/platform/soc/100000.ufshc/by-name/super, ajoutez la ligne suivante à file_contexts :

/dev/block/platform/soc/10000\.ufshc/by-name/super   u:object_r:super_block_device:s0

fastbootd

Le bootloader (ou tout outil de flashage non lié à l'espace utilisateur) ne comprend pas les partitions dynamiques et ne peut donc pas les flasher. Pour résoudre ce problème, les appareils doivent utiliser une implémentation de l'espace utilisateur du protocole fastboot, appelée fastbootd.

Pour en savoir plus sur l'implémentation de fastbootd, consultez Déplacer Fastboot vers l'espace utilisateur.

adb remount

Pour les développeurs qui utilisent des versions eng ou userdebug, adb remount est extrêmement utile pour une itération rapide. Les partitions dynamiques posent un problème pour adb remount, car il n'y a plus d'espace libre dans chaque système de fichiers. Pour résoudre ce problème, les appareils peuvent activer overlayfs. Tant qu'il y a de l'espace libre dans la super partition, adb remount crée automatiquement une partition dynamique temporaire et utilise overlayfs pour les écritures. La partition temporaire est nommée scratch. N'utilisez donc pas ce nom pour d'autres partitions.

Pour savoir comment activer overlayfs, consultez le fichier README d'overlayfs dans AOSP.

Mettre à niveau les appareils Android

Si vous mettez à niveau un appareil vers Android 10 et que vous souhaitez inclure la prise en charge des partitions dynamiques dans l'OTA, vous n'avez pas besoin de modifier la table de partition intégrée. Une configuration supplémentaire est requise.

Modifications de la configuration de l'appareil

Pour adapter le partitionnement dynamique, ajoutez les indicateurs suivants dans device.mk :

PRODUCT_USE_DYNAMIC_PARTITIONS := true
PRODUCT_RETROFIT_DYNAMIC_PARTITIONS := true

Modifications de la configuration du tableau

Vous devez définir les variables de carte suivantes :

  • Définissez BOARD_SUPER_PARTITION_BLOCK_DEVICES sur la liste des périphériques de bloc utilisés pour stocker les étendues des partitions dynamiques. Il s'agit de la liste des noms des partitions physiques existantes sur l'appareil.
  • Définissez BOARD_SUPER_PARTITION_partition_DEVICE_SIZE sur les tailles de chaque périphérique de bloc dans BOARD_SUPER_PARTITION_BLOCK_DEVICES, respectivement. Il s'agit de la liste des tailles des partitions physiques existantes sur l'appareil. Cette valeur est généralement définie sur BOARD_partitionIMAGE_PARTITION_SIZE dans les configurations de carte existantes.
  • Supprimez le BOARD_partitionIMAGE_PARTITION_SIZE existant pour toutes les partitions de BOARD_SUPER_PARTITION_BLOCK_DEVICES.
  • Définissez BOARD_SUPER_PARTITION_SIZE sur la somme de BOARD_SUPER_PARTITION_partition_DEVICE_SIZE.
  • Définissez BOARD_SUPER_PARTITION_METADATA_DEVICE sur le périphérique de bloc où sont stockées les métadonnées de partition dynamique. Il doit s'agir de l'un des éléments suivants : BOARD_SUPER_PARTITION_BLOCK_DEVICES. Cette valeur est généralement définie sur system.
  • Définissez BOARD_SUPER_PARTITION_GROUPS, BOARD_group_SIZE et BOARD_group_PARTITION_LIST, respectivement. Pour en savoir plus, consultez Modifications de la configuration de la carte sur les nouveaux appareils.

Par exemple, si l'appareil dispose déjà de partitions système et fournisseur, et que vous souhaitez les convertir en partitions dynamiques et ajouter une nouvelle partition produit lors de la mise à jour, définissez cette configuration de carte :

BOARD_SUPER_PARTITION_BLOCK_DEVICES := system vendor
BOARD_SUPER_PARTITION_METADATA_DEVICE := system

# Rename BOARD_SYSTEMIMAGE_PARTITION_SIZE to BOARD_SUPER_PARTITION_SYSTEM_DEVICE_SIZE.
BOARD_SUPER_PARTITION_SYSTEM_DEVICE_SIZE := <size-in-bytes>

# Rename BOARD_VENDORIMAGE_PARTITION_SIZE to BOARD_SUPER_PARTITION_VENDOR_DEVICE_SIZE
BOARD_SUPER_PARTITION_VENDOR_DEVICE_SIZE := <size-in-bytes>

# This is BOARD_SUPER_PARTITION_SYSTEM_DEVICE_SIZE + BOARD_SUPER_PARTITION_VENDOR_DEVICE_SIZE
BOARD_SUPER_PARTITION_SIZE := <size-in-bytes>

# Configuration for dynamic partitions. For example:
BOARD_SUPER_PARTITION_GROUPS := group_foo
BOARD_GROUP_FOO_SIZE := <size-in-bytes>
BOARD_GROUP_FOO_PARTITION_LIST := system vendor product

Modifications apportées à SELinux

Les périphériques de bloc de super partition doivent être marqués avec l'attribut super_block_device_type. Par exemple, si l'appareil dispose déjà des partitions system et vendor, vous souhaitez les utiliser comme périphériques de bloc pour stocker les étendues des partitions dynamiques, et leurs liens symboliques par nom sont marqués comme system_block_device :

/dev/block/platform/soc/10000\.ufshc/by-name/system   u:object_r:system_block_device:s0
/dev/block/platform/soc/10000\.ufshc/by-name/vendor   u:object_r:system_block_device:s0

Ajoutez ensuite la ligne suivante à device.te :

typeattribute system_block_device super_block_device_type;

Pour d'autres configurations, consultez Implémenter des partitions dynamiques sur de nouveaux appareils.

Pour en savoir plus sur les mises à jour de rétrocompatibilité, consultez OTA pour les appareils A/B sans partitions dynamiques.

Images d'usine

Pour un appareil lancé avec la prise en charge des partitions dynamiques, évitez d'utiliser fastboot userspace pour flasher les images d'usine, car le démarrage dans l'espace utilisateur est plus lent que les autres méthodes de flashage.

Pour résoudre ce problème, make dist crée désormais une image super.img supplémentaire qui peut être flashée directement sur la partition super. Il regroupe automatiquement le contenu des partitions logiques, ce qui signifie qu'il contient system.img, vendor.img, etc., en plus des métadonnées de partition super. Cette image peut être flashée directement sur la partition super sans aucun outil supplémentaire ni en utilisant fastbootd. Une fois la compilation terminée, super.img est placé dans ${ANDROID_PRODUCT_OUT}.

Pour les appareils A/B lancés avec des partitions dynamiques, super.img contient des images dans l'emplacement A. Après avoir flashé l'image super directement, marquez l'emplacement A comme amorçable avant de redémarrer l'appareil.

Pour les appareils de rétrofit, make dist crée un ensemble d'images super_*.img qui peuvent être flashées directement sur les partitions physiques correspondantes. Par exemple, make dist crée super_system.img et super_vendor.img lorsque BOARD_SUPER_PARTITION_BLOCK_DEVICES est le fournisseur du système. Ces images sont placées dans le dossier OTA de target_files.zip.

Réglage du périphérique de stockage du mappeur de périphériques

Le partitionnement dynamique prend en charge un certain nombre d'objets device-mapper non déterministes. Il est possible que tous ne s'instancient pas comme prévu. Vous devez donc suivre tous les montages et mettre à jour les propriétés Android de toutes les partitions associées avec leurs périphériques de stockage sous-jacents.

Un mécanisme à l'intérieur de init suit les montages et met à jour de manière asynchrone les propriétés Android. La durée de cette opération n'est pas garantie dans une période spécifique. Vous devez donc prévoir suffisamment de temps pour que tous les déclencheurs on property réagissent. Les propriétés sont dev.mnt.blk.<partition>, où <partition> est root, system, data ou vendor, par exemple. Chaque propriété est associée au nom de l'appareil de stockage de base, comme indiqué dans ces exemples :

taimen:/ % getprop | grep dev.mnt.blk
[dev.mnt.blk.data]: [sda]
[dev.mnt.blk.firmware]: [sde]
[dev.mnt.blk.metadata]: [sde]
[dev.mnt.blk.persist]: [sda]
[dev.mnt.blk.root]: [dm-0]
[dev.mnt.blk.vendor]: [dm-1]

blueline:/ $ getprop | grep dev.mnt.blk
[dev.mnt.blk.data]: [dm-4]
[dev.mnt.blk.metadata]: [sda]
[dev.mnt.blk.mnt.scratch]: [sda]
[dev.mnt.blk.mnt.vendor.persist]: [sdf]
[dev.mnt.blk.product]: [dm-2]
[dev.mnt.blk.root]: [dm-0]
[dev.mnt.blk.system_ext]: [dm-3]
[dev.mnt.blk.vendor]: [dm-1]
[dev.mnt.blk.vendor.firmware_mnt]: [sda]

Le langage init.rc permet d'étendre les propriétés Android dans les règles, et les périphériques de stockage peuvent être ajustés par la plate-forme selon les besoins avec des commandes comme celles-ci :

write /sys/block/${dev.mnt.blk.root}/queue/read_ahead_kb 128
write /sys/block/${dev.mnt.blk.data}/queue/read_ahead_kb 128

Une fois le traitement des commandes démarré dans init de la deuxième étape, epoll loop devient actif et les valeurs commencent à se mettre à jour. Toutefois, comme les déclencheurs de propriétés ne sont actifs qu'à la fin de init, ils ne peuvent pas être utilisés lors des étapes de démarrage initiales pour gérer root, system ou vendor. Vous pouvez vous attendre à ce que la valeur par défaut du noyau read_ahead_kb soit suffisante jusqu'à ce que les scripts init.rc puissent la remplacer dans early-fs (lorsque divers démons et utilitaires démarrent). Par conséquent, Google vous recommande d'utiliser la fonctionnalité on property, associée à une propriété contrôlée par init.rc comme sys.read_ahead_kb, pour gérer le timing des opérations et éviter les conditions de course, comme dans ces exemples :

on property:dev.mnt.blk.root=* && property:sys.read_ahead_kb=*
    write /sys/block/${dev.mnt.blk.root}/queue/read_ahead_kb ${sys.read_ahead_kb:-2048}

on property:dev.mnt.blk.system=* && property:sys.read_ahead_kb=*
    write /sys/block/${dev.mnt.blk.system}/queue/read_ahead_kb ${sys.read_ahead_kb:-2048}

on property:dev.mnt.blk.vendor=* && property:sys.read_ahead_kb=*
    write /sys/block/${dev.mnt.blk.vendor}/queue/read_ahead_kb ${sys.read_ahead_kb:-2048}

on property:dev.mnt.blk.product=* && property:sys.read_ahead_kb=*
    write /sys/block/${dev.mnt.blk.system_ext}/queue/read_ahead_kb ${sys.read_ahead_kb:-2048}

on property:dev.mnt.blk.oem=* && property:sys.read_ahead_kb=*
    write /sys/block/${dev.mnt.blk.oem}/queue/read_ahead_kb ${sys.read_ahead_kb:-2048}

on property:dev.mnt.blk.data=* && property:sys.read_ahead_kb=*
    write /sys/block/${dev.mnt.blk.data}/queue/read_ahead_kb ${sys.read_ahead_kb:-2048}

on early-fs:
    setprop sys.read_ahead_kb ${ro.read_ahead_kb.boot:-2048}

on property:sys.boot_completed=1
   setprop sys.read_ahead_kb ${ro.read_ahead_kb.bootcomplete:-128}