Implementación de particiones dinámicas

El particionamiento dinámico se implementa utilizando el módulo mapeador de dispositivos dm-linear en el kernel de Linux. La super partición contiene metadatos que enumeran los nombres y los rangos de bloques de cada partición dinámica dentro super . Durante la init de la primera etapa, estos metadatos se analizan y validan, y se crean dispositivos de bloques virtuales para representar cada partición dinámica.

Al aplicar una OTA, las particiones dinámicas se crean, redimensionan o eliminan automáticamente según sea necesario. Para los dispositivos A/B, hay dos copias de los metadatos y los cambios se aplican solo a la copia que representa la ranura de destino.

Debido a que las particiones dinámicas se implementan en el espacio de usuario, las particiones que necesita el gestor de arranque no se pueden convertir en dinámicas. Por ejemplo, boot , dtbo y vbmeta son leídos por el gestor de arranque, por lo que deben permanecer como particiones físicas.

Cada partición dinámica puede pertenecer a un grupo de actualización . Estos grupos limitan el espacio máximo que pueden consumir las particiones de ese grupo. Por ejemplo, el system y el vendor pueden pertenecer a un grupo que restringe el tamaño total del system y el vendor .

Implementación de particiones dinámicas en nuevos dispositivos

Esta sección detalla cómo implementar particiones dinámicas en nuevos dispositivos que se lanzan con Android 10 y superior. Para actualizar los dispositivos existentes, consulte Actualización de dispositivos Android .

Cambios de partición

Para dispositivos que se inicien con Android 10, cree una partición llamada super . La super partición maneja las ranuras A/B internamente, por lo que los dispositivos A/B no necesitan particiones super_a y super_b separadas. Todas las particiones AOSP de solo lectura que no utiliza el cargador de arranque deben ser dinámicas y deben eliminarse de la tabla de particiones GUID (GPT). Las particiones específicas del proveedor no tienen que ser dinámicas y se pueden colocar en el GPT.

Para estimar el tamaño de super , agregue los tamaños de las particiones que se eliminan del GPT. Para dispositivos A/B, esto debe incluir el tamaño de ambas ranuras. La Figura 1 muestra una tabla de particiones de ejemplo antes y después de convertir a particiones dinámicas.

Disposición de la tabla de particiones
Figura 1. Nuevo diseño de la tabla de particiones físicas al convertir a particiones dinámicas

Las particiones dinámicas admitidas son:

  • Sistema
  • Vendedor
  • Producto
  • Extensión del sistema
  • ODM

Para los dispositivos que se inician con Android 10, la opción de línea de comando del kernel androidboot.super_partition debe estar vacía para que el comando sysprop ro.boot.super_partition esté vacío.

Alineación de particiones

El módulo mapeador de dispositivos puede funcionar de manera menos eficiente si la super partición no está alineada correctamente. La super partición DEBE estar alineada con el tamaño mínimo de solicitud de E/S según lo determine la capa de bloque. De forma predeterminada, el sistema de compilación (a través de lpmake , que genera la imagen de super ), asume que una alineación de 1 MiB es suficiente para cada partición dinámica. Sin embargo, los proveedores deben asegurarse de que la super partición esté correctamente alineada.

Puede determinar el tamaño mínimo de solicitud de un dispositivo de bloque inspeccionando sysfs . Por ejemplo:

# 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

Puede verificar la alineación de la super partición de manera similar:

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

El desplazamiento de alineación DEBE ser 0.

Cambios en la configuración del dispositivo

Para habilitar el particionamiento dinámico, agregue el siguiente indicador en device.mk :

PRODUCT_USE_DYNAMIC_PARTITIONS := true

Cambios en la configuración de la placa

Debe establecer el tamaño de la super partición:

BOARD_SUPER_PARTITION_SIZE := <size-in-bytes>

En los dispositivos A/B, el sistema de compilación arroja un error si el tamaño total de las imágenes de partición dinámica es más de la mitad del tamaño de la super partición.

Puede configurar la lista de particiones dinámicas de la siguiente manera. Para dispositivos que usan grupos de actualización, enumere los grupos en la variable BOARD_SUPER_PARTITION_GROUPS . Cada nombre de grupo tiene una BOARD_ group _SIZE y BOARD_ group _PARTITION_LIST . Para los dispositivos A/B, el tamaño máximo de un grupo debe cubrir solo una ranura, ya que los nombres de los grupos tienen un sufijo de ranura internamente.

Aquí hay un dispositivo de ejemplo que coloca todas las particiones en un grupo llamado 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

Aquí hay un dispositivo de ejemplo que coloca los servicios del sistema y del producto en group_foo , y vendor , product y odm en 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
  • Para los dispositivos de lanzamiento Virtual A/B, la suma de los tamaños máximos de todos los grupos debe ser como máximo:
    BOARD_SUPER_PARTITION_SIZE - sobrecarga
    Consulte Implementación de Virtual A/B .
  • Para los dispositivos de lanzamiento A/B, la suma de los tamaños máximos de todos los grupos debe ser:
    BOARD_SUPER_PARTITION_SIZE / 2 - sobrecarga
  • Para dispositivos que no son A/B y dispositivos A/B reacondicionados, la suma de los tamaños máximos de todos los grupos debe ser:
    BOARD_SUPER_PARTITION_SIZE - sobrecarga
  • En el momento de la compilación, la suma de los tamaños de las imágenes de cada partición en un grupo de actualización no debe exceder el tamaño máximo del grupo.
  • Se requiere una sobrecarga en el cálculo para tener en cuenta los metadatos, las alineaciones, etc. Una sobrecarga razonable es de 4 MiB, pero puede elegir una sobrecarga mayor según lo necesite el dispositivo.

Dimensionamiento de particiones dinámicas

Antes de las particiones dinámicas, los tamaños de las particiones se asignaban en exceso para garantizar que tuvieran espacio suficiente para futuras actualizaciones. El tamaño real se tomó tal cual y la mayoría de las particiones de solo lectura tenían cierta cantidad de espacio libre en su sistema de archivos. En las particiones dinámicas, ese espacio libre no se puede usar y podría usarse para hacer crecer las particiones durante una OTA. Es fundamental asegurarse de que las particiones no desperdicien espacio y se asignen al mínimo tamaño posible.

Para imágenes ext4 de solo lectura, el sistema de compilación asigna automáticamente el tamaño mínimo si no se especifica un tamaño de partición codificado. El sistema de compilación ajusta la imagen para que el sistema de archivos tenga el menor espacio sin usar posible. Esto asegura que el dispositivo no desperdicie espacio que pueda usarse para OTA.

Además, las imágenes ext4 se pueden comprimir aún más al habilitar la deduplicación a nivel de bloque. Para habilitar esto, use la siguiente configuración:

BOARD_EXT4_SHARE_DUP_BLOCKS := true

Si no se desea la asignación automática de un tamaño mínimo de partición, hay dos formas de controlar el tamaño de la partición. Puede especificar una cantidad mínima de espacio libre con BOARD_ partition IMAGE_PARTITION_RESERVED_SIZE , o puede especificar BOARD_ partition IMAGE_PARTITION_SIZE para forzar particiones dinámicas a un tamaño específico. Ninguno de estos se recomienda a menos que sea necesario.

Por ejemplo:

BOARD_PRODUCTIMAGE_PARTITION_RESERVED_SIZE := 52428800

Esto obliga al sistema de archivos en product.img a tener 50 MiB de espacio sin usar.

Cambios del sistema como raíz

Los dispositivos que se inician con Android 10 no deben usar el sistema como raíz.

Los dispositivos con particiones dinámicas (ya sea que se inicien con particiones dinámicas o las actualicen) no deben usar el sistema como raíz. El kernel de Linux no puede interpretar la super partición y, por lo tanto, no puede montar el system en sí. El system ahora está montado por el init de primera etapa, que reside en el ramdisk.

No establezca BOARD_BUILD_SYSTEM_ROOT_IMAGE . En Android 10, el indicador BOARD_BUILD_SYSTEM_ROOT_IMAGE solo se usa para diferenciar si el sistema está montado por el kernel o por el inicio de primera etapa en init .

Establecer BOARD_BUILD_SYSTEM_ROOT_IMAGE en true provoca un error de compilación cuando PRODUCT_USE_DYNAMIC_PARTITIONS también es true .

Cuando BOARD_USES_RECOVERY_AS_BOOT se establece en verdadero, la imagen de recuperación se construye como boot.img, que contiene el ramdisk de la recuperación. Anteriormente, el cargador de arranque usaba el parámetro de línea de comando del kernel skip_initramfs para decidir en qué modo arrancar. Para dispositivos con Android 10, el gestor de arranque NO DEBE pasar skip_initramfs a la línea de comandos del kernel. En su lugar, el cargador de arranque debe pasar androidboot.force_normal_boot=1 para omitir la recuperación y arrancar Android normal. Los dispositivos que se inician con Android 12 o posterior deben usar bootconfig para pasar androidboot.force_normal_boot=1 .

Cambios en la configuración de AVB

Al usar Android Verified Boot 2.0 , si el dispositivo no usa descriptores de partición encadenados , entonces no es necesario realizar ningún cambio. Sin embargo, si usa particiones encadenadas y una de las particiones verificadas es dinámica, entonces es necesario realizar cambios.

Aquí hay una configuración de ejemplo para un dispositivo que encadena vbmeta para las particiones del system y del 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 esta configuración, el gestor de arranque espera encontrar un pie de página vbmeta al final de las particiones del system y del vendor . Debido a que estas particiones ya no son visibles para el gestor de arranque (residen en super ), se necesitan dos cambios.

  • Agregue las particiones vbmeta_system y vbmeta_vendor a la tabla de particiones del dispositivo. Para dispositivos A/B, agregue vbmeta_system_a , vbmeta_system_b , vbmeta_vendor_a y vbmeta_vendor_b . Si agrega una o más de estas particiones, deben tener el mismo tamaño que la partición vbmeta .
  • Cambie el nombre de los indicadores de configuración agregando VBMETA_ y especifique a qué particiones se extiende el encadenamiento:
    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 puede estar usando una, ambas o ninguna de estas particiones. Los cambios son necesarios solo cuando se encadena a una partición lógica.

Cambios en el cargador de arranque AVB

Si el cargador de arranque tiene libavb incorporado, incluya los siguientes parches:

Si usa particiones encadenadas, incluya un parche adicional:

  • 49936b4c0109411fdd38bd4ba3a32a01c40439a9 — "libavb: Admite blobs vbmeta al comienzo de la partición".

Cambios en la línea de comandos del kernel

Se debe agregar un nuevo parámetro, androidboot.boot_devices , a la línea de comando del kernel. Esto lo utiliza init para habilitar los enlaces simbólicos /dev/block/by-name . Debe ser el componente de ruta del dispositivo al enlace simbólico por nombre subyacente creado por ueventd , es decir, /dev/block/platform/ device-path /by-name/ partition-name . Los dispositivos que se inician con Android 12 o posterior deben usar bootconfig para pasar androidboot.boot_devices a init .

Por ejemplo, si el enlace simbólico de superpartición por nombre es /dev/block/platform/ soc/100000.ufshc /by-name/super , puede agregar el parámetro de línea de comando en el archivo BoardConfig.mk de la siguiente manera:

BOARD_KERNEL_CMDLINE += androidboot.boot_devices=soc/100000.ufshc
Puede agregar el parámetro bootconfig en el archivo BoardConfig.mk de la siguiente manera:
BOARD_BOOTCONFIG += androidboot.boot_devices=soc/100000.ufshc

cambios en fstab

El árbol de dispositivos y las superposiciones del árbol de dispositivos no deben contener entradas fstab. Utilice un archivo fstab que formará parte del ramdisk.

Se deben realizar cambios en el archivo fstab para particiones lógicas:

  • El campo fs_mgr flags debe incluir el indicador logical y el indicador first_stage_mount , introducido en Android 10, que indica que se montará una partición en la primera etapa.
  • Una partición puede especificar avb= vbmeta partition name como un indicador fs_mgr y luego la primera etapa init la partición vbmeta especificada antes de intentar montar cualquier dispositivo.
  • El dev de desarrollo debe ser el nombre de la partición.

Las siguientes entradas de fstab establecen el sistema, el proveedor y el producto como particiones lógicas siguiendo las reglas anteriores.

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

Copie el archivo fstab en el ramdisk de la primera etapa.

Cambios de SELinux

El dispositivo de súper bloque de partición debe estar marcado con la etiqueta super_block_device . Por ejemplo, si el enlace simbólico por nombre de la superpartición es /dev/block/platform/ soc/100000.ufshc /by-name/super , agregue la siguiente línea a file_contexts :

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

arranque rápido

El gestor de arranque (o cualquier herramienta de flasheo que no sea del espacio de usuario) no entiende las particiones dinámicas, por lo que no puede flashearlas. Para abordar esto, los dispositivos deben usar una implementación en el espacio de usuario del protocolo fastboot, llamada fastbootd.

Para obtener más información sobre cómo implementar fastbootd, consulte Traslado de Fastboot al espacio del usuario .

volver a montar adb

Para los desarrolladores que usan compilaciones eng o userdebug, adb remount es extremadamente útil para una iteración rápida. Las particiones dinámicas plantean un problema para el montaje de adb remount porque ya no hay espacio libre dentro de cada sistema de archivos. Para abordar esto, los dispositivos pueden habilitar overlayfs. Siempre que haya espacio libre dentro de la súper partición, adb remount crea automáticamente una partición dinámica temporal y usa overlayfs para escrituras. La partición temporal se llama scratch , así que no use este nombre para otras particiones.

Para obtener más información sobre cómo habilitar overlayfs, consulte el archivo README de overlayfs en AOSP.

Actualización de dispositivos Android

Si actualiza un dispositivo a Android 10 y desea incluir soporte de particiones dinámicas en la OTA, no necesita cambiar la tabla de particiones integrada. Se requiere alguna configuración adicional.

Cambios en la configuración del dispositivo

Para adaptar la partición dinámica, agregue las siguientes banderas en device.mk :

PRODUCT_USE_DYNAMIC_PARTITIONS := true
PRODUCT_RETROFIT_DYNAMIC_PARTITIONS := true

Cambios en la configuración de la placa

Debe configurar las siguientes variables del tablero:

  • Establezca BOARD_SUPER_PARTITION_BLOCK_DEVICES en la lista de dispositivos de bloque utilizados para almacenar extensiones de particiones dinámicas. Esta es la lista de nombres de particiones físicas existentes en el dispositivo.
  • Establezca BOARD_SUPER_PARTITION_ partition _DEVICE_SIZE en los tamaños de cada dispositivo de bloque en BOARD_SUPER_PARTITION_BLOCK_DEVICES , respectivamente. Esta es la lista de tamaños de las particiones físicas existentes en el dispositivo. Suele ser BOARD_ partition IMAGE_PARTITION_SIZE en configuraciones de placa existentes.
  • Desactive la BOARD_ partition IMAGE_PARTITION_SIZE existente para todas las particiones en BOARD_SUPER_PARTITION_BLOCK_DEVICES .
  • Establezca BOARD_SUPER_PARTITION_SIZE en la suma de BOARD_SUPER_PARTITION_ partition _DEVICE_SIZE .
  • Establezca BOARD_SUPER_PARTITION_METADATA_DEVICE en el dispositivo de bloque donde se almacenan los metadatos de la partición dinámica. Debe ser uno de BOARD_SUPER_PARTITION_BLOCK_DEVICES . Por lo general, esto se establece en system .
  • Establezca BOARD_SUPER_PARTITION_GROUPS , BOARD_ group _SIZE y BOARD_ group _PARTITION_LIST , respectivamente. Consulte Cambios en la configuración de la placa en dispositivos nuevos para obtener más detalles.

Por ejemplo, si el dispositivo ya tiene particiones de sistema y de proveedor, y desea convertirlas en particiones dinámicas y agregar una nueva partición de producto durante la actualización, establezca esta configuración de placa:

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

Cambios de SELinux

Los dispositivos de súper bloque de partición deben estar marcados con el atributo super_block_device_type . Por ejemplo, si el dispositivo ya tiene particiones de system y vendor , desea utilizarlas como dispositivos de bloque para almacenar extensiones de particiones dinámicas, y sus enlaces simbólicos por nombre están marcados como 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

Luego, agregue la siguiente línea a device.te :

typeattribute system_block_device super_block_device_type;

Para otras configuraciones, consulte Implementación de particiones dinámicas en nuevos dispositivos .

Para obtener más información sobre las actualizaciones de reacondicionamiento, consulte OTA para dispositivos A/B sin particiones dinámicas .

Imágenes de fábrica

Para un dispositivo que se inicie con soporte de particiones dinámicas, evite usar el inicio rápido del espacio de usuario para actualizar imágenes de fábrica, ya que el inicio en el espacio de usuario es más lento que otros métodos de actualización.

Para abordar esto, make dist ahora crea una imagen super.img adicional que se puede mostrar directamente en la super partición. Empaqueta automáticamente el contenido de las particiones lógicas, lo que significa que contiene system.img , vendor.img , etc., además de los metadatos de la super . Esta imagen se puede mostrar directamente en la super partición sin ninguna herramienta adicional o usando fastbootd. Después de la compilación, super.img se coloca en ${ANDROID_PRODUCT_OUT} .

Para dispositivos A/B que se inician con particiones dinámicas, super.img contiene imágenes en la ranura A. Después de mostrar la súper imagen directamente, marque la ranura A como de arranque antes de reiniciar el dispositivo.

Para dispositivos actualizados, make dist crea un conjunto de imágenes super_*.img que se pueden mostrar directamente en las particiones físicas correspondientes. Por ejemplo, crea make dist super_system.img y super_vendor.img cuando BOARD_SUPER_PARTITION_BLOCK_DEVICES es el proveedor del sistema. Estas imágenes se colocan en la carpeta OTA en target_files.zip .

Ajuste del dispositivo de almacenamiento del mapeador de dispositivos

El particionamiento dinámico se adapta a una serie de objetos mapeadores de dispositivos no deterministas. Es posible que no todos se creen instancias como se esperaba, por lo que debe realizar un seguimiento de todos los montajes y actualizar las propiedades de Android de todas las particiones asociadas con sus dispositivos de almacenamiento subyacentes.

Un mecanismo dentro de init rastrea los montajes y actualiza de forma asíncrona las propiedades de Android. No se garantiza que la cantidad de tiempo que esto tome esté dentro de un período específico, por lo que debe proporcionar suficiente tiempo para que todos los activadores on property reaccionen. Las propiedades son dev.mnt.blk. <partition> donde <partition> es root , system , data o vendor , por ejemplo. Cada propiedad está asociada con el nombre del dispositivo de almacenamiento base, como se muestra en estos ejemplos:

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]

El lenguaje init.rc permite expandir las propiedades de Android como parte de las reglas, y la plataforma puede ajustar los dispositivos de almacenamiento según sea necesario con comandos como estos:

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

Una vez que el procesamiento del comando comienza en la segunda etapa init , el epoll loop se activa y los valores comienzan a actualizarse. Sin embargo, debido a que los activadores de propiedad no están activos hasta el init tardío, no se pueden usar en las etapas iniciales de arranque para manejar root , system o vendor . Puede esperar que el kernel predeterminado read_ahead_kb sea suficiente hasta que los scripts init.rc puedan anularse en early-fs (cuando se inician varios demonios e instalaciones). Por lo tanto, Google recomienda que utilice la función on property , junto con una propiedad controlada por init.rc como sys.read_ahead_kb , para manejar el tiempo de las operaciones y evitar condiciones de carrera, como en estos ejemplos:

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}