Implementa particiones dinámicas

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

Cuando se aplica una actualización OTA, las particiones dinámicas se crean, cambian de tamaño o borran automáticamente según sea necesario. En el caso de los dispositivos A/B, hay dos copias de los metadatos, y los cambios solo se aplican a la copia que representa la ranura de destino.

Dado que las particiones dinámicas se implementan en el espacio de usuario, las particiones que necesita el bootloader no pueden ser dinámicas. Por ejemplo, el cargador de arranque lee boot, dtbo y vbmeta, 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, system y vendor pueden pertenecer a un grupo que restringe el tamaño total de system y vendor.

Implementa particiones dinámicas en dispositivos nuevos

En esta sección, se detalla cómo implementar particiones dinámicas en dispositivos nuevos que se lanzan con Android 10 y versiones posteriores. Para actualizar dispositivos existentes, consulta Cómo actualizar dispositivos Android.

Cambios en las particiones

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

Para estimar el tamaño de super, suma los tamaños de las particiones que se borran del GPT. En el caso de los dispositivos A/B, esto debe incluir el tamaño de ambos espacios. En la Figura 1, se muestra un ejemplo de una tabla de particiones antes y después de la conversión a particiones dinámicas.

Diseño de la tabla de particiones
Figura 1: Nuevo diseño de la tabla de particiones físicas cuando se realiza la conversión a particiones dinámicas

Las particiones dinámicas admitidas son las siguientes:

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

En el caso de los dispositivos que se lanzan con Android 10, la opción de línea de comandos 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 device-mapper puede funcionar con menor eficiencia si la partición super no está alineada correctamente. La partición super DEBE estar alineada con el tamaño mínimo de solicitud de E/S según lo determina la capa de bloques. De forma predeterminada, el sistema de compilación (a través de lpmake, que genera la imagen de la partición super) supone que una alineación de 1 MiB es suficiente para cada partición dinámica. Sin embargo, los proveedores deben asegurarse de que la partición super esté alineada correctamente.

Puedes 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

Puedes verificar la alineación de la partición super de una 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 particionado dinámico, agrega la siguiente marca en device.mk:

PRODUCT_USE_DYNAMIC_PARTITIONS := true

Cambios en la configuración de la placa

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

BOARD_SUPER_PARTITION_SIZE := <size-in-bytes>

En los dispositivos A/B, el sistema de compilación genera 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 partición super.

Puedes configurar la lista de particiones dinámicas de la siguiente manera. Para los dispositivos que usan grupos de actualización, enumera los grupos en la variable BOARD_SUPER_PARTITION_GROUPS. Cada nombre de grupo tiene una variable BOARD_group_SIZE y BOARD_group_PARTITION_LIST. En el caso de los dispositivos A/B, el tamaño máximo de un grupo solo debe abarcar una ranura, ya que los nombres de los grupos tienen un sufijo interno de ranura.

Este es un ejemplo de un dispositivo 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

Este es un ejemplo de un dispositivo 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
  • En el caso de los dispositivos de lanzamiento de A/B virtual, la suma de los tamaños máximos de todos los grupos debe ser, como máximo, la siguiente:
    BOARD_SUPER_PARTITION_SIZE - overhead
    Consulta Implementación de A/B virtual.
  • En el caso de los dispositivos de lanzamiento de la prueba A/B, la suma de los tamaños máximos de todos los grupos debe ser la siguiente:
    BOARD_SUPER_PARTITION_SIZE / 2 - overhead
  • En el caso de los dispositivos que no son A/B y los dispositivos A/B actualizados, la suma de los tamaños máximos de todos los grupos debe ser la siguiente:
    BOARD_SUPER_PARTITION_SIZE - overhead
  • En el momento de la compilación, la suma de los tamaños de las imágenes de cada partición de un grupo de actualización no debe superar el tamaño máximo del grupo.
  • La sobrecarga es necesaria en el cálculo para tener en cuenta los metadatos, las alineaciones, etcétera. Una sobrecarga razonable es de 4 MiB, pero puedes elegir una sobrecarga mayor según lo necesite el dispositivo.

Cómo dimensionar particiones dinámicas

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

En el caso de las 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 la menor cantidad posible de espacio sin usar. Esto garantiza que el dispositivo no desperdicie espacio que se puede usar para las OTA.

Además, las imágenes ext4 se pueden comprimir aún más si se habilita la deduplicación a nivel de bloques. Para habilitar esta opción, usa la siguiente configuración:

BOARD_EXT4_SHARE_DUP_BLOCKS := true

Si no deseas la asignación automática de un tamaño mínimo de partición, existen dos formas de controlar el tamaño de la partición. Puedes especificar una cantidad mínima de espacio libre con BOARD_partitionIMAGE_PARTITION_RESERVED_SIZE o BOARD_partitionIMAGE_PARTITION_SIZE para forzar las particiones dinámicas a un tamaño específico. No se recomienda ninguna de estas opciones, 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 en System-as-root

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

Los dispositivos con particiones dinámicas (ya sea que se lancen con particiones dinámicas o que se adapten a ellas) no deben usar system-as-root. El kernel de Linux no puede interpretar la partición super y, por lo tanto, no puede activar system. system ahora se activa con init de la primera etapa, que reside en el disco RAM.

No establezcas BOARD_BUILD_SYSTEM_ROOT_IMAGE. En Android 10, la marca BOARD_BUILD_SYSTEM_ROOT_IMAGE solo se usa para diferenciar si el kernel activó el sistema o si lo hizo el init de la primera etapa en el disco RAM.

Si configuras BOARD_BUILD_SYSTEM_ROOT_IMAGE como true, se produce un error de compilación cuando PRODUCT_USE_DYNAMIC_PARTITIONS también es true.

Cuando BOARD_USES_RECOVERY_AS_BOOT se establece como verdadero, la imagen de recuperación se compila como boot.img, que contiene el ramdisk de recuperación. Anteriormente, el cargador de arranque usaba el parámetro de línea de comandos del kernel skip_initramfs para decidir en qué modo arrancar. En el caso de los dispositivos con Android 10, el bootloader NO DEBE pasar skip_initramfs a la línea de comandos del kernel. En su lugar, el cargador de arranque debería pasar androidboot.force_normal_boot=1 para omitir la recuperación y arrancar Android normalmente. Los dispositivos que se lanzan con Android 12 o versiones posteriores deben usar bootconfig para pasar androidboot.force_normal_boot=1.

Cambios en la configuración de AVB

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

Este es un ejemplo de configuración para un dispositivo que encadena vbmeta para las particiones system y 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 cargador de arranque espera encontrar un pie de vbmeta al final de las particiones system y vendor. Debido a que estas particiones ya no son visibles para el cargador de arranque (residen en super), se necesitan dos cambios.

  • Agrega las particiones vbmeta_system y vbmeta_vendor a la tabla de particiones del dispositivo. Para los dispositivos A/B, agrega vbmeta_system_a, vbmeta_system_b, vbmeta_vendor_a y vbmeta_vendor_b. Si se agregan una o más de estas particiones, deben tener el mismo tamaño que la partición vbmeta.
  • Cambia el nombre de los parámetros de configuración agregando VBMETA_ y especifica 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 usar una, ambas o ninguna de estas particiones. Los cambios solo son necesarios cuando se encadenan a una partición lógica.

Cambios en el bootloader de AVB

Si el cargador de arranque tiene incorporada la biblioteca libavb, incluye los siguientes parches:

Si usas particiones encadenadas, incluye un parche adicional:

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

Cambios en la línea de comandos del kernel

Se debe agregar un nuevo parámetro, androidboot.boot_devices, a la línea de comandos del kernel. init usa este parámetro para habilitar vínculos simbólicos de /dev/block/by-name. Debe ser el componente de ruta de acceso del dispositivo al symlink subyacente por nombre creado por ueventd, es decir, /dev/block/platform/device-path/by-name/partition-name. Los dispositivos que se lanzan con Android 12 o versiones posteriores deben usar bootconfig para pasar androidboot.boot_devices a init.

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

BOARD_KERNEL_CMDLINE += androidboot.boot_devices=soc/100000.ufshc
Puedes 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 de fstab. Usa un archivo fstab que formará parte del ramdisk.

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

  • El campo de marcas de fs_mgr debe incluir la marca logical y la marca first_stage_mount, que se introdujo en Android 10 y que indica que una partición se debe activar en la primera etapa.
  • Una partición puede especificar avb=vbmeta partition name como una marca fs_mgr y, luego, la partición vbmeta especificada se inicializa con la primera etapa init antes de intentar montar cualquier dispositivo.
  • El campo dev 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 según 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

Copia el archivo fstab en el disco RAM de la primera etapa.

Cambios en SELinux

El dispositivo de bloqueo de la superpartición debe estar marcado con la etiqueta super_block_device. Por ejemplo, si el vínculo simbólico de la superpartición por nombre es /dev/block/platform/soc/100000.ufshc/by-name/super, agrega la siguiente línea a file_contexts:

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

fastbootd

El bootloader (o cualquier herramienta de escritura que no sea de espacio de usuario) no comprende las particiones dinámicas, por lo que no puede escribirlas. Para abordar este problema, los dispositivos deben usar una implementación del protocolo fastboot en el espacio del usuario, llamada fastbootd.

Para obtener más información sobre cómo implementar fastbootd, consulta Cómo mover fastboot al espacio del usuario.

adb remount

Para los desarrolladores que usan compilaciones de eng o userdebug, adb remount es extremadamente útil para una iteración rápida. Las particiones dinámicas representan un problema para adb remount, ya que ya no hay espacio libre en cada sistema de archivos. Para solucionar este problema, los dispositivos pueden habilitar overlayfs. Siempre que haya espacio libre dentro de la superpartición, adb remount creará automáticamente una partición dinámica temporal y usará overlayfs para las escrituras. La partición temporal se llama scratch, por lo que no debes usar este nombre para otras particiones.

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

Cómo actualizar dispositivos Android

Si actualizas un dispositivo a Android 10 y quieres incluir la compatibilidad con particiones dinámicas en la actualización inalámbrica, no es necesario que cambies la tabla de particiones integrada. Se requiere una configuración adicional.

Cambios en la configuración del dispositivo

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

PRODUCT_USE_DYNAMIC_PARTITIONS := true
PRODUCT_RETROFIT_DYNAMIC_PARTITIONS := true

Cambios en la configuración de la placa

Debes establecer las siguientes variables de la placa:

  • Establece BOARD_SUPER_PARTITION_BLOCK_DEVICES en la lista de dispositivos de bloque que se usan para almacenar extensiones de particiones dinámicas. Es la lista de nombres de las particiones físicas existentes en el dispositivo.
  • Establece BOARD_SUPER_PARTITION_partition_DEVICE_SIZE en los tamaños de cada dispositivo de bloqueo en BOARD_SUPER_PARTITION_BLOCK_DEVICES, respectivamente. Es la lista de tamaños de las particiones físicas existentes en el dispositivo. Por lo general, es BOARD_partitionIMAGE_PARTITION_SIZE en las configuraciones de la placa existentes.
  • Anula la configuración de BOARD_partitionIMAGE_PARTITION_SIZE existente para todas las particiones en BOARD_SUPER_PARTITION_BLOCK_DEVICES.
  • Establece BOARD_SUPER_PARTITION_SIZE como la suma de BOARD_SUPER_PARTITION_partition_DEVICE_SIZE.
  • Establece BOARD_SUPER_PARTITION_METADATA_DEVICE en el dispositivo de almacenamiento en bloques en el que se almacenan los metadatos de la partición dinámica. Debe ser uno de los siguientes: BOARD_SUPER_PARTITION_BLOCK_DEVICES. Por lo general, se establece en system.
  • Establece BOARD_SUPER_PARTITION_GROUPS, BOARD_group_SIZE y BOARD_group_PARTITION_LIST, respectivamente. Consulta Cambios en la configuración de la placa en dispositivos nuevos para obtener más detalles.

Por ejemplo, si el dispositivo ya tiene particiones del sistema y del proveedor, y deseas convertirlas en particiones dinámicas y agregar una nueva partición del producto durante la actualización, establece esta configuración de la 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 en SELinux

Los dispositivos de bloque de la superpartición deben marcarse con el atributo super_block_device_type. Por ejemplo, si el dispositivo ya tiene particiones system y vendor, quieres usarlas como dispositivos de bloque para almacenar extensiones de particiones dinámicas, y sus vínculos 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, agrega la siguiente línea a device.te:

typeattribute system_block_device super_block_device_type;

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

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

Imágenes de fábrica

En el caso de un dispositivo que se lanza con compatibilidad con particiones dinámicas, evita usar fastboot en el espacio del usuario para escribir imágenes de fábrica, ya que el arranque en el espacio del usuario es más lento que otros métodos de escritura.

Para abordar este problema, make dist ahora compila una imagen super.img adicional que se puede escribir directamente en la partición super. Agrupa automáticamente el contenido de las particiones lógicas, lo que significa que contiene system.img, vendor.img, etcétera, además de los metadatos de partición super. Esta imagen se puede escribir directamente en la partición super sin herramientas adicionales ni fastbootd. Después de la compilación, super.img se coloca en ${ANDROID_PRODUCT_OUT}.

En el caso de los dispositivos A/B que se lanzan con particiones dinámicas, super.img contiene imágenes en la ranura A. Después de instalar la imagen super directamente, marca la ranura A como de arranque antes de reiniciar el dispositivo.

En el caso de los dispositivos de actualización, make dist compila un conjunto de imágenes de super_*.img que se pueden instalar directamente en las particiones físicas correspondientes. Por ejemplo, make dist compila 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 asignador de dispositivos

El particionamiento dinámico admite varios objetos de asignador de dispositivos no determinísticos. Es posible que no todos se creen instancias según lo esperado, por lo que debes hacer 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 hace un seguimiento de las vinculaciones y actualiza de forma asíncrona las propiedades de Android. El tiempo que lleva este proceso no está garantizado para que se complete dentro de un período específico, por lo que debes proporcionar suficiente tiempo para que reaccionen todos los activadores de on property. Las propiedades son dev.mnt.blk.<partition>, donde <partition> es root, system, data o vendor, por ejemplo. Cada propiedad está asociada con el nombre base del dispositivo de almacenamiento, 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 que las propiedades de Android se expandan como parte de las reglas, y los dispositivos de almacenamiento se pueden ajustar según sea necesario con comandos como los siguientes:

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 comienza el procesamiento de comandos en init de segunda etapa, epoll loop se activa y los valores comienzan a actualizarse. Sin embargo, debido a que los activadores de propiedades no están activos hasta la etapa tardía de init, no se pueden usar en las etapas iniciales de inicio para controlar root, system o vendor. Puedes esperar que el valor predeterminado del kernel read_ahead_kb sea suficiente hasta que las secuencias de comandos init.rc puedan anularlo en early-fs (cuando se inician varios daemons y utilidades). Por lo tanto, Google recomienda que uses la función on property, junto con una propiedad controlada por init.rc, como sys.read_ahead_kb, para controlar 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}