Implementazione di partizioni dinamiche

Il partizionamento dinamico viene implementato utilizzando il modulo dm-linear device-mapper nel kernel Linux. La partizione super contiene metadati che elencano i nomi e gli intervalli di blocchi di ogni partizione dinamica all'interno di super. Durante la prima fase init, questi metadati vengono analizzati e convalidati e vengono creati dispositivi virtuali a blocchi per rappresentare ogni partizione dinamica.

Quando viene applicato un aggiornamento OTA, le partizioni dinamiche vengono create, ridimensionate o eliminate automaticamente in base alle esigenze. Per i dispositivi A/B, esistono due copie dei metadati e le modifiche vengono applicate solo alla copia che rappresenta lo slot target.

Poiché le partizioni dinamiche sono implementate nello spazio utente, le partizioni necessarie dall'avvio non possono essere rese dinamiche. Ad esempio, boot, dtbo e vbmeta vengono letti dal bootloader e quindi devono rimanere come partizioni fisiche.

Ogni partizione dinamica può appartenere a un gruppo di aggiornamento. Questi gruppi limitano lo spazio massimo che le partizioni di quel gruppo possono utilizzare. Ad esempio, system e vendor possono appartenere a un gruppo che limita le dimensioni totali di system e vendor.

Implementare partizioni dinamiche sui nuovi dispositivi

Questa sezione descrive come implementare le partizioni dinamiche sui nuovi dispositivi che vengono lanciati con Android 10 e versioni successive. Per aggiornare i dispositivi esistenti, vedi Eseguire l'upgrade dei dispositivi Android.

Modifiche alla partizione

Per i dispositivi lanciati con Android 10, crea una partizione denominata super. La partizione super gestisce gli slot A/B internamente, quindi i dispositivi A/B non hanno bisogno di partizioni super_a e super_b separate. Tutte le partizioni AOSP di sola lettura non utilizzate dal bootloader devono essere dinamiche e devono essere rimosse dalla tabella delle partizioni GUID (GPT). Le partizioni specifiche del fornitore non devono essere dinamiche e possono essere inserite nel GPT.

Per stimare le dimensioni di super, aggiungi le dimensioni delle partizioni eliminate dal GPT. Per i dispositivi A/B, deve essere inclusa la dimensione di entrambi gli slot. La Figura 1 mostra una tabella di partizione di esempio prima e dopo la conversione in partizioni dinamiche.

Layout della tabella delle partizioni
Figura 1. Nuovo layout della tabella delle partizioni fisiche durante la conversione alle partizioni dinamiche

Le partizioni dinamiche supportate sono:

  • Sistema
  • Fornitore
  • Prodotto
  • Estensione di sistema
  • ODM

Per i dispositivi lanciati con Android 10, l'opzione della riga di comando del kernel androidboot.super_partition deve essere vuota in modo che il comando syspropro.boot.super_partition sia vuoto.

Allineamento della partizione

Il modulo device-mapper potrebbe funzionare in modo meno efficiente se la partizione super non è allineata correttamente. La partizione super DEVE essere allineata alla dimensione minima della richiesta I/O, come determinata dal livello di blocco. Per impostazione predefinita, il sistema di compilazione (tramite lpmake, che genera l'immagine della partizione super) presuppone che un allineamento di 1 MiB sia sufficiente per ogni partizione dinamica. Tuttavia, i fornitori devono assicurarsi che la partizione super sia allineata correttamente.

Puoi determinare le dimensioni minime della richiesta di un dispositivo di blocco esaminando sysfs. Ad esempio:

# 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

Puoi verificare l'allineamento della partizione super in modo simile:

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

L'offset di allineamento DEVE essere 0.

Modifiche alla configurazione del dispositivo

Per attivare la suddivisione dinamica, aggiungi il seguente flag in device.mk:

PRODUCT_USE_DYNAMIC_PARTITIONS := true

Modifiche alla configurazione della lavagna

Devi impostare la dimensione della partizione super:

BOARD_SUPER_PARTITION_SIZE := <size-in-bytes>

Sui dispositivi A/B, il sistema di compilazione restituisce un errore se la dimensione totale delle immagini delle partizioni dinamiche è superiore alla metà di quelle super.

Puoi configurare l'elenco delle partizioni dinamiche nel seguente modo. Per i dispositivi che utilizzano i gruppi di aggiornamento, elenca i gruppi nella variabile BOARD_SUPER_PARTITION_GROUPS. Ogni nome di gruppo ha quindi una variabile BOARD_group_SIZE e BOARD_group_PARTITION_LIST. Per i dispositivi A/B, la dimensione massima di un gruppo deve coprire un solo slot, poiché i nomi dei gruppi sono dotati di suffisso interno per lo slot.

Ecco un esempio di dispositivo che inserisce tutte le partizioni in un gruppo chiamato 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

Ecco un esempio di dispositivo che inserisce i servizi di sistema e di prodotto in group_foo e vendor, product e odm in 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
  • Per i dispositivi di lancio di Virtual A/B, la somma delle dimensioni massime di tutti i gruppi deve essere al massimo:
    BOARD_SUPER_PARTITION_SIZE - overhead
    Consulta Implementazione di Virtual A/B.
  • Per i dispositivi di lancio A/B, la somma delle dimensioni massime di tutti i gruppi deve essere:
    BOARD_SUPER_PARTITION_SIZE / 2 - overhead
  • Per i dispositivi non A/B e i dispositivi A/B di retrofit, la somma delle dimensioni massime di tutti i gruppi deve essere:
    BOARD_SUPER_PARTITION_SIZE - overhead
  • Al momento della compilazione, la somma delle dimensioni delle immagini di ogni partizione in un gruppo di aggiornamento non deve superare la dimensione massima del gruppo.
  • L'overhead è necessario nel calcolo per tenere conto di metadati, allineamenti e così via. Un overhead ragionevole è 4 MiB, ma puoi scegliere un overhead maggiore in base alle esigenze del dispositivo.

Dimensioni delle partizioni dinamiche

Prima delle partizioni dinamiche, le dimensioni delle partizioni erano sovraallocate per assicurarsi che avessero spazio sufficiente per gli aggiornamenti futuri. Le dimensioni effettive sono state prese così come sono e la maggior parte delle partizioni di sola lettura aveva un po' di spazio libero nel file system. Nelle partizioni dinamiche, lo spazio libero è inutilizzabile e potrebbe essere utilizzato per aumentare le partizioni durante un OTA. È fondamentale assicurarsi che le partizioni non sprechino spazio e che vengano allocate a una dimensione minima possibile.

Per le immagini ext4 di sola lettura, il sistema di compilazione alloca automaticamente la dimensione minima se non viene specificata una dimensione della partizione hardcoded. Il sistema di compilazione adatta l'immagine in modo che il file system abbia il minor spazio inutilizzato possibile. In questo modo, il dispositivo non spreca spazio che può essere utilizzato per le OTA.

Inoltre, le immagini ext4 possono essere compresse ulteriormente attivando la deduplica a livello di blocco. Per attivare questa opzione, utilizza la seguente configurazione:

BOARD_EXT4_SHARE_DUP_BLOCKS := true

Se l'allocazione automatica di una dimensione minima della partizione non è auspicabile, esistono due modi per controllarne le dimensioni. Puoi specificare una quantità minima di spazio libero con BOARD_partitionIMAGE_PARTITION_RESERVED_SIZE oppure puoi specificare BOARD_partitionIMAGE_PARTITION_SIZE per forzare le partizioni dinamiche a una dimensione specifica. Nessuna di queste opzioni è consigliata, a meno che non sia necessaria.

Ad esempio:

BOARD_PRODUCTIMAGE_PARTITION_RESERVED_SIZE := 52428800

In questo modo, il file system in product.img deve avere 50 MiB di spazio inutilizzato.

Modifiche system as-root

I dispositivi lanciati con Android 10 non devono utilizzare system-as-root.

I dispositivi con partizioni dinamiche (che vengono avviate con o riadattate partizioni dinamiche) non devono utilizzare il sistema come utente root. Il kernel Linux non può interpretare la partizione super e quindi non può montare system. system è ora montato dalla prima fase init, che risiede nel ramdisk.

Non impostare BOARD_BUILD_SYSTEM_ROOT_IMAGE. In Android 10, il flag BOARD_BUILD_SYSTEM_ROOT_IMAGE viene utilizzato solo per distinguere se il sistema è montato dal kernel o dal primo livello init in ramdisk.

L'impostazione di BOARD_BUILD_SYSTEM_ROOT_IMAGE su true causa un errore di compilazione quando anche PRODUCT_USE_DYNAMIC_PARTITIONS è true.

Quando BOARD_USES_RECOVERY_AS_BOOT è impostato su true, l'immagine di recupero viene creata come boot.img, contenente il ramdisk del recupero. In precedenza, il bootloader utilizzava il parametro della riga di comando skip_initramfs kernel per decidere in quale modalità avviare il sistema. Per i dispositivi Android 10, il bootloader NON DEVE passare skip_initramfs alla riga di comando del kernel. Invece, il bootloader dovrebbe passare androidboot.force_normal_boot=1 per saltare il recupero e avviare il normale Android. I dispositivi lanciati con Android 12 o versioni successive devono utilizzare bootconfig per passare androidboot.force_normal_boot=1.

Modifiche alla configurazione AVB

Quando utilizzi Avvio verificato 2.0 di Android, se il dispositivo non utilizza descrittori di partizione concatenati, non è necessaria alcuna modifica. Tuttavia, se utilizzi partizioni concatenate e una delle partizioni verificate è dinamica, sono necessarie modifiche.

Ecco un esempio di configurazione per un dispositivo che concatena vbmeta per le partizioni system e 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

Con questa configurazione, il bootloader si aspetta di trovare un footer vbmeta alla fine delle partizioni system e vendor. Poiché queste partizioni non sono più visibili al bootloader (risiedono in super), sono necessarie due modifiche.

  • Aggiungi le partizioni vbmeta_system e vbmeta_vendor alla tabella delle partizioni del dispositivo. Per i dispositivi A/B, aggiungi vbmeta_system_a, vbmeta_system_b, vbmeta_vendor_a e vbmeta_vendor_b. Se aggiungi una o più di queste partizioni, devono avere le stesse dimensioni della partizione vbmeta.
  • Rinomina i flag di configurazione aggiungendo VBMETA_ e specifica le partizioni a cui si estende la catena:
    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 dispositivo potrebbe utilizzare una, entrambe o nessuna di queste partizioni. Le modifiche sono necessarie solo quando si esegue il collegamento a una partizione logica.

Modifiche al bootloader AVB

Se il bootloader ha incorporato libavb, includi le seguenti patch:

Se utilizzi partizioni in catena, includi un patch aggiuntivo:

  • 49936b4c0109411fdd38bd4ba3a32a01c40439a9 - "libavb: supporta i blob vbmeta all'inizio della partizione".

Modifiche alla riga di comando kernel

È necessario aggiungere un nuovo parametro, androidboot.boot_devices, alla riga di comando del kernel. Viene utilizzato da init per attivare i link simbolici /dev/block/by-name. Dovrebbe essere il componente del percorso del dispositivo del collegamento simbolico sottostante creato da ueventd, ovvero /dev/block/platform/device-path/by-name/partition-name. I dispositivi lanciati con Android 12 o versioni successive devono utilizzare bootconfig per passare androidboot.boot_devices a init.

Ad esempio, se il link simbolico della super partizione per nome è /dev/block/platform/soc/100000.ufshc/by-name/super, puoi aggiungere il parametro della riga di comando nel file BoardConfig.mk come segue:

BOARD_KERNEL_CMDLINE += androidboot.boot_devices=soc/100000.ufshc
Puoi aggiungere il parametro bootconfig nel file BoardConfig.mk come segue:
BOARD_BOOTCONFIG += androidboot.boot_devices=soc/100000.ufshc

Modifiche a fstab

La struttura ad albero del dispositivo e le relative sovrapposizioni non devono contenere voci fstab. Utilizza un file fstab che farà parte della ramdisk.

È necessario apportare modifiche al file fstab per le partizioni logiche:

  • Il campo fs_mgr flags deve includere il flag logical e il flag first_stage_mount, introdotto in Android 10, che indica che una partizione deve essere montée nella prima fase.
  • Una partizione può specificare avb=vbmeta partition name come un fs_mgr flag e la partizione vbmeta specificata viene inizializzata dal primo livello init prima di tentare di montare i dispositivi.
  • Il campo dev deve essere il nome della partizione.

Le seguenti voci fstab impostano system, vendor e product come partizioni logiche seguendo le regole riportate sopra.

#<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

Copia il file fstab nel ramdisk della prima fase.

Modifiche a SELinux

Il dispositivo del blocco della partizione super deve essere contrassegnato con l'etichetta super_block_device. Ad esempio, se il link simbolico della super partizione per nome è /dev/block/platform/soc/100000.ufshc/by-name/super, aggiungi la seguente riga a file_contexts:

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

fastbootd

Il bootloader (o qualsiasi strumento di flashing non nello spazio utente) non comprende le partizioni dinamiche, quindi non può eseguirne il flashing. Per risolvere questo problema, i dispositivi devono utilizzare un'implementazione nello spazio utente del protocollo fastboot, chiamata fastbootd.

Per ulteriori informazioni su come implementare fastbootd, consulta Spostare Fastboot nello spazio utente.

adb remount

Per gli sviluppatori che utilizzano build eng o userdebug, adb remount è estremamente utile per l'iterazione rapida. Le partizioni dinamiche rappresentano un problema per adb remount perché non è più disponibile spazio libero all'interno di ogni file system. Per risolvere il problema, i dispositivi possono attivare overlayfs. Se all'interno della super partizione è presente spazio libero, adb remount crea automaticamente una partizione dinamica provvisoria e utilizza overlayfs per le scritture. La partizione temporanea è scratch, quindi non utilizzare questo nome per altre partizioni.

Per ulteriori informazioni su come attivare overlayfs, consulta il file README di overlayfs in AOSP.

Eseguire l'upgrade dei dispositivi Android

Se esegui l'upgrade di un dispositivo ad Android 10 e vuoi includere il supporto delle partizioni dinamiche nell'OTA, non è necessario modificare la tabella delle partizioni integrata. È necessaria qualche configurazione aggiuntiva.

Modifiche alla configurazione del dispositivo

Per eseguire il retrofit del partizionamento dinamico, aggiungi i seguenti flag in device.mk:

PRODUCT_USE_DYNAMIC_PARTITIONS := true
PRODUCT_RETROFIT_DYNAMIC_PARTITIONS := true

Modifiche alla configurazione della lavagna

Devi impostare le seguenti variabili della scheda:

  • Imposta BOARD_SUPER_PARTITION_BLOCK_DEVICES sull'elenco dei dispositivi di blocco utilizzati per memorizzare le estensioni delle partizioni dinamiche. Questo è l'elenco dei nomi delle partizioni fisiche esistenti sul dispositivo.
  • Imposta BOARD_SUPER_PARTITION_partition_DEVICE_SIZE, rispettivamente, sulle dimensioni di ogni dispositivo di blocco in BOARD_SUPER_PARTITION_BLOCK_DEVICES. Questo è l'elenco delle dimensioni delle partizioni fisiche esistenti sul dispositivo. In genere, è BOARD_partitionIMAGE_PARTITION_SIZE nelle configurazioni della scheda esistenti.
  • Annulla l'impostazione di BOARD_partitionIMAGE_PARTITION_SIZE esistente per tutte le partizioni in BOARD_SUPER_PARTITION_BLOCK_DEVICES.
  • Imposta BOARD_SUPER_PARTITION_SIZE sulla somma di BOARD_SUPER_PARTITION_partition_DEVICE_SIZE.
  • Imposta BOARD_SUPER_PARTITION_METADATA_DEVICE sul dispositivo di blocco in cui sono archiviati i metadati della partizione dinamica. Deve essere uno dei seguenti: BOARD_SUPER_PARTITION_BLOCK_DEVICES. In genere, questo valore è impostato su system.
  • Imposta BOARD_SUPER_PARTITION_GROUPS, BOARD_group_SIZE e BOARD_group_PARTITION_LIST, rispettivamente. Per maggiori dettagli, consulta Modifiche alla configurazione della scheda sui nuovi dispositivi.

Ad esempio, se il dispositivo ha già partizioni di sistema e del fornitore e vuoi convertirle in partizioni dinamiche e aggiungere una nuova partizione del prodotto durante l'aggiornamento, imposta questa configurazione della scheda:

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

Modifiche a SELinux

I dispositivi a blocchi della super partizione devono essere contrassegnati con l'attributo super_block_device_type. Ad esempio, se il dispositivo ha già le partizioni system e vendor, vuoi utilizzarle come dispositivi di blocco per memorizzare le estensioni delle partizioni dinamiche e i relativi link simbolici per nome sono contrassegnati come 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

Poi, aggiungi la seguente riga a device.te:

typeattribute system_block_device super_block_device_type;

Per altre configurazioni, consulta Implementazione di partizioni dinamiche su nuovi dispositivi.

Per ulteriori informazioni sugli aggiornamenti di retrofit, consulta Aggiornamento over-the-air per i dispositivi A/B senza partizioni dinamiche.

Immagini del produttore

Per un dispositivo lanciato con il supporto delle partizioni dinamiche, evita di utilizzare il fastboot nello spazio utente per eseguire il flashing delle immagini di fabbrica, poiché l'avvio nello spazio utente è più lento rispetto ad altri metodi di flashing.

Per risolvere questo problema, make dist ora crea un'immagine super.img aggiuntiva che può essere sottoposta a flashing direttamente nella super partizione. Raggruppa automaticamente i contenuti delle partizioni logiche, ovvero contiene system.img, vendor.img e così via, oltre ai metadati della partizione super. Questa immagine può essere sottoposta a flashing direttamente nella partizione super senza strumenti aggiuntivi o senza utilizzare fastbootd. Dopo la compilazione, super.img viene inserito in ${ANDROID_PRODUCT_OUT}.

Per i dispositivi A/B che vengono avviati con partizioni dinamiche, super.img contiene immagini nello slot A. Dopo aver eseguito direttamente il flashing della super immagine, contrassegna lo slot A come avviabile prima di riavviare il dispositivo.

Per i dispositivi di retrofit, make dist crea un insieme di immagini super_*.img che possono essere inviate tramite flashing direttamente alle partizioni fisiche corrispondenti. Ad esempio, make dist compila super_system.img e super_vendor.img quando BOARD_SUPER_PARTITION_BLOCK_DEVICES è il fornitore del sistema. Queste immagini vengono posizionate nella cartella OTA in target_files.zip.

Ottimizzazione dello spazio di archiviazione del dispositivo mapper

Il partizionamento dinamico supporta una serie di oggetti device-mapper non determisti. Potrebbero non essere tutte create come previsto, quindi devi tenere traccia di tutti i montaggi e aggiornare le proprietà Android di tutte le partizioni associate con i relativi dispositivi di archiviazione sottostanti.

Un meccanismo all'interno di init monitora i mount e aggiorna in modo asincrono le proprietà Android. Non è garantito che il tempo richiesto sia compreso in un periodo specifico, quindi devi concedere tempo sufficiente affinché tutti gli attivatori di on property reagiscano. Le proprietà sono dev.mnt.blk.<partition> dove <partition> è root, system, data o vendor, ad esempio. Ogni proprietà è associata al nome del dispositivo di archiviazione di base, come mostrato in questi esempi:

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]

Il linguaggio init.rc consente di espandere le proprietà Android nell'ambito delle regole e i dispositivi di archiviazione possono essere ottimizzati dalla piattaforma in base alle esigenze con comandi come:

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

Quando l'elaborazione dei comandi inizia nella seconda fase init, il epoll loop diventa attivo e i valori iniziano ad aggiornarsi. Tuttavia, poiché gli attivatori delle proprietà non sono attivi fino alla fine del init, non possono essere utilizzati nelle fasi di avvio iniziali per gestire root, system o vendor. È possibile che il valore predefinito del kernel read_ahead_kb sia sufficiente finché gli script init.rc non possono eseguire l'override in early-fs (all'avvio di vari demoni e servizi). Pertanto, Google consiglia di utilizzare la funzionalità on property, abbinata a una proprietà controllata da init.rc come sys.read_ahead_kb, per gestire la temporizzazione delle operazioni e per evitare condizioni di gara, come in questi esempi:

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}