Динамическое разбиение реализовано с помощью модуля dm-linear device-mapper в ядре Linux. super
содержит метаданные, содержащие имена и диапазоны блоков каждого динамического раздела в пределах super
. На первом этапе init
эти метаданные анализируются и проверяются, после чего создаются виртуальные блочные устройства для представления каждого динамического раздела.
При применении OTA динамические разделы автоматически создаются, изменяют размер или удаляются по мере необходимости. Для устройств A/B существует две копии метаданных, и изменения применяются только к той копии, которая представляет целевой слот.
Поскольку динамические разделы реализованы в пользовательском пространстве, разделы, необходимые загрузчику, не могут быть динамическими. Например, boot
, dtbo
и vbmeta
считываются загрузчиком и поэтому должны оставаться физическими разделами.
Каждый динамический раздел может принадлежать к группе обновлений . Эти группы ограничивают максимальный объём, занимаемый разделами в этой группе. Например, system
и vendor
могут принадлежать к группе, которая ограничивает общий размер разделов system
и vendor
.
Реализуйте динамические разделы на новых устройствах
В этом разделе подробно описывается реализация динамических разделов на новых устройствах с Android 10 и более поздними версиями. Чтобы обновить существующие устройства, см . раздел Обновление устройств Android .
Изменения разделов
Для устройств с Android 10 создайте раздел с именем super
. Раздел super
управляет слотами A/B, поэтому устройствам A/B не нужны отдельные разделы super_a
и super_b
. Все разделы AOSP, доступные только для чтения и не используемые загрузчиком, должны быть динамическими и должны быть удалены из таблицы разделов GUID (GPT). Разделы, специфичные для производителя, не обязательно должны быть динамическими и могут быть размещены в GPT.
Чтобы оценить размер раздела super
, сложите размеры разделов, удаляемых из GPT. Для устройств A/B сюда следует включить размер обоих слотов. На рисунке 1 показан пример таблицы разделов до и после преобразования в динамические разделы.

Поддерживаемые динамические разделы:
- Система
- Продавец
- Продукт
- Системный Ext
- ОДМ
Для устройств, работающих под управлением Android 10, параметр командной строки ядра androidboot.super_partition
должен быть пустым, чтобы команда sysprop ro.boot.super_partition
была пустой.
Выравнивание разделов
Модуль device-mapper может работать менее эффективно, если super
не выровнен должным образом. super
ДОЛЖЕН быть выровнен по минимальному размеру запроса ввода-вывода , определяемому блочным уровнем. По умолчанию система сборки (через lpmake
, который генерирует образ super
) предполагает, что выравнивания в 1 МиБ достаточно для каждого динамического раздела. Однако поставщики должны обеспечить правильное выравнивание super
.
Вы можете определить минимальный размер запроса блочного устройства, проверив sysfs
. Например:
# 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
Проверить выравнивание super
можно аналогичным образом:
# cat /sys/block/sda/sda17/alignment_offset
Смещение выравнивания ДОЛЖНО быть равно 0.
Изменения конфигурации устройства
Чтобы включить динамическое разбиение, добавьте следующий флаг в device.mk
:
PRODUCT_USE_DYNAMIC_PARTITIONS := true
Изменения конфигурации платы
Вам необходимо задать размер super
:
BOARD_SUPER_PARTITION_SIZE := <size-in-bytes>
На устройствах A/B система сборки выдает ошибку, если общий размер образов динамических разделов превышает половину размера super
.
Список динамических разделов можно настроить следующим образом. Для устройств, использующих группы обновления, перечислите группы в переменной BOARD_SUPER_PARTITION_GROUPS
. Имя каждой группы затем будет иметь переменные BOARD_ group _SIZE
и BOARD_ group _PARTITION_LIST
. Для устройств A/B максимальный размер группы должен охватывать только один слот, поскольку имена групп имеют внутренний суффикс, обозначающий слот.
Вот пример устройства, которое помещает все разделы в группу под названием 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
Вот пример устройства, которое помещает системные и продуктовые службы в group_foo
, а vendor
, product
и odm
в 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
- Для устройств запуска Virtual A/B сумма максимальных размеров всех групп должна быть не более:
BOARD_SUPER_PARTITION_SIZE
— накладные расходы
См. раздел Реализация виртуального A/B . - Для устройств запуска A/B сумма максимальных размеров всех групп должна быть:
BOARD_SUPER_PARTITION_SIZE
/ 2 — накладные расходы - Для устройств, отличных от A/B, и модифицированных устройств A/B сумма максимальных размеров всех групп должна быть:
BOARD_SUPER_PARTITION_SIZE
— накладные расходы - Во время сборки сумма размеров образов каждого раздела в группе обновлений не должна превышать максимальный размер группы.
- При вычислениях требуются дополнительные накладные расходы для учёта метаданных, выравниваний и т. д. Разумный размер дополнительных расходов составляет 4 МБ, но вы можете выбрать больший размер, если это необходимо устройству.
Размер динамических разделов
До появления динамических разделов размеры разделов были зарезервированы, чтобы обеспечить достаточно места для будущих обновлений. Фактический размер принимался как есть, и большинство разделов, доступных только для чтения, имели некоторое количество свободного места в файловой системе. В динамических разделах это свободное пространство не используется и может быть использовано для увеличения разделов во время обновления OTA. Крайне важно гарантировать, что разделы не расходуют место впустую и выделяют минимально возможный размер.
Для образов ext4, доступных только для чтения, система сборки автоматически выделяет минимальный размер, если не указан жёстко заданный размер раздела. Система сборки подгоняет образ под размер файла так, чтобы в файловой системе оставалось как можно меньше неиспользуемого пространства. Это гарантирует, что устройство не будет тратить впустую пространство, которое можно использовать для OTA-обновлений.
Кроме того, образы ext4 можно дополнительно сжать, включив дедупликацию на уровне блоков. Для этого используйте следующую конфигурацию:
BOARD_EXT4_SHARE_DUP_BLOCKS := true
Если автоматическое выделение минимального размера раздела нежелательно, существует два способа управления размером раздела. Вы можете указать минимальный объём свободного пространства с помощью BOARD_ partition IMAGE_PARTITION_RESERVED_SIZE
или указать BOARD_ partition IMAGE_PARTITION_SIZE
, чтобы принудительно задать определённый размер динамических разделов. Ни один из этих способов не рекомендуется использовать без необходимости.
Например:
BOARD_PRODUCTIMAGE_PARTITION_RESERVED_SIZE := 52428800
Это заставит файловую систему в product.img
иметь 50 МБ неиспользуемого пространства.
Изменения в системе как root
Устройства, работающие под управлением Android 10, не должны использовать root-доступ.
Устройства с динамическими разделами (независимо от того, запускаются ли они с динамическими разделами или модернизируют их) не должны использовать систему с правами root. Ядро Linux не может интерпретировать super
и, следовательно, не может смонтировать саму system
. Теперь system
монтируется процессом init
первого этапа, который находится на RAM-диске.
Не устанавливайте BOARD_BUILD_SYSTEM_ROOT_IMAGE
. В Android 10 флаг BOARD_BUILD_SYSTEM_ROOT_IMAGE
используется только для того, чтобы различать, монтируется ли система ядром или первой стадией init
в ramdisk.
Установка BOARD_BUILD_SYSTEM_ROOT_IMAGE
в true
приводит к ошибке сборки, если PRODUCT_USE_DYNAMIC_PARTITIONS
также имеет true
.
Если параметр BOARD_USES_RECOVERY_AS_BOOT
установлен в значение true, образ восстановления создается как boot.img, содержащий RAM-диск восстановления. Ранее загрузчик использовал параметр командной строки ядра skip_initramfs
для определения режима загрузки. Для устройств с Android 10 загрузчик НЕ ДОЛЖЕН передавать skip_initramfs
в командную строку ядра. Вместо этого загрузчик должен передать androidboot.force_normal_boot=1
чтобы пропустить восстановление и загрузить обычный Android. Устройства с Android 12 и более поздними версиями должны использовать bootconfig для передачи androidboot.force_normal_boot=1
.
Изменения конфигурации AVB
При использовании Android Verified Boot 2.0 , если устройство не использует цепочечные дескрипторы разделов , изменения не требуются. Однако, если используются цепочечные разделы, и один из проверенных разделов является динамическим, изменения необходимы.
Ниже приведен пример конфигурации устройства, которое связывает vbmeta
для system
и 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
При такой конфигурации загрузчик ожидает найти нижний колонтитул vbmeta в конце разделов system
и vendor
. Поскольку эти разделы больше не видны загрузчику (они находятся в super
), необходимо внести два изменения.
- Добавьте разделы
vbmeta_system
иvbmeta_vendor
в таблицу разделов устройства. Для устройств A/B добавьтеvbmeta_system_a
,vbmeta_system_b
,vbmeta_vendor_a
иvbmeta_vendor_b
. При добавлении одного или нескольких таких разделов их размер должен совпадать с размером разделаvbmeta
. - Переименуйте флаги конфигурации, добавив
VBMETA_
, и укажите, на какие разделы распространяется цепочка: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
Устройство может использовать один, оба или ни одного из этих разделов. Изменения необходимы только при подключении к логическому разделу.
Изменения загрузчика AVB
Если загрузчик имеет встроенную библиотеку libavb , включите следующие исправления:
- 818cf56740775446285466eda984acedd4baeac0 — «libavb: запрашивать GUID разделов только тогда, когда они требуются командной строке».
- 5abd6bc2578968d24406d834471adfd995a0c2e9 — «Разрешить отсутствие системного раздела»
- 9ba3b6613b4e5130fa01a11d984c6b5f0eb3af05 — «Исправлена ошибка AvbSlotVerifyData->cmdline, которая может быть равна NULL»
При использовании связанных разделов включите дополнительный патч:
- 49936b4c0109411fdd38bd4ba3a32a01c40439a9 — «libavb: Поддержка объектов vbmeta в начале раздела».
Изменения в командной строке ядра
В командную строку ядра необходимо добавить новый параметр androidboot.boot_devices
. Он используется init
для включения символических ссылок /dev/block/by-name
. Он должен быть компонентом пути к устройству для базовой символической ссылки by-name, созданной ueventd
, то есть /dev/block/platform/ device-path /by-name/ partition-name
. Устройства, запускаемые с Android 12 и более поздними версиями, должны использовать bootconfig для передачи androidboot.boot_devices
в init
.
Например, если символическая ссылка по имени суперраздела — /dev/block/platform/ soc/100000.ufshc /by-name/super
, вы можете добавить параметр командной строки в файл BoardConfig.mk следующим образом:
BOARD_KERNEL_CMDLINE += androidboot.boot_devices=soc/100000.ufshc
BOARD_BOOTCONFIG += androidboot.boot_devices=soc/100000.ufshc
изменения fstab
Дерево устройств и оверлеи дерева устройств не должны содержать записей fstab. Используйте файл fstab, который будет частью RAM-диска.
Для логических разделов необходимо внести изменения в файл fstab:
- Поле флагов fs_mgr должно включать
logical
флаг и флагfirst_stage_mount
, представленный в Android 10, который указывает, что раздел должен быть смонтирован на первом этапе. - Раздел может указывать
avb= vbmeta partition name
как флагfs_mgr
, а затем указанный разделvbmeta
инициализируется на первом этапеinit
перед попыткой монтировать какие-либо устройства. - Поле
dev
должно содержать имя раздела.
Следующие записи fstab устанавливают систему, поставщика и продукт как логические разделы в соответствии с вышеуказанными правилами.
#<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
Скопируйте файл fstab на виртуальный диск первого этапа.
Изменения SELinux
Блочное устройство суперраздела должно быть помечено меткой super_block_device
. Например, если символическая ссылка по имени суперраздела — /dev/block/platform/ soc/100000.ufshc /by-name/super
, добавьте в file_contexts
следующую строку:
/dev/block/platform/soc/10000\.ufshc/by-name/super u:object_r:super_block_device:s0
fastbootd
Загрузчик (или любой другой инструмент прошивки, не работающий в пользовательском пространстве) не распознаёт динамические разделы, поэтому не может их прошивать. Для решения этой проблемы устройства должны использовать реализацию протокола fastboot в пользовательском пространстве, называемую fastbootd.
Дополнительную информацию о реализации fastbootd см. в разделе Перемещение Fastboot в пространство пользователя .
перемонтирование adb
Для разработчиков, использующих сборки eng или userdebug, adb remount
чрезвычайно полезен для быстрой итерации. Динамические разделы представляют собой проблему для adb remount
, поскольку в каждой файловой системе больше нет свободного места. Для решения этой проблемы устройства могут включать overlayfs. Пока в суперразделе есть свободное место, adb remount
автоматически создаёт временный динамический раздел и использует overlayfs для записи. Временный раздел называется scratch
, поэтому не используйте это имя для других разделов.
Дополнительную информацию о том, как включить overlayfs, см. в README-файле overlayfs в AOSP.
Обновление устройств Android
Если вы обновляете устройство до Android 10 и хотите включить поддержку динамических разделов в OTA-обновление, вам не нужно менять встроенную таблицу разделов. Требуется дополнительная настройка.
Изменения конфигурации устройства
Для модернизации динамического разбиения добавьте следующие флаги в device.mk
:
PRODUCT_USE_DYNAMIC_PARTITIONS := true PRODUCT_RETROFIT_DYNAMIC_PARTITIONS := true
Изменения конфигурации платы
Вам необходимо установить следующие переменные платы:
- Установите
BOARD_SUPER_PARTITION_BLOCK_DEVICES
в список блочных устройств, используемых для хранения экстентов динамических разделов. Это список имён существующих физических разделов на устройстве. - Установите
BOARD_SUPER_PARTITION_ partition _DEVICE_SIZE
равным размерам каждого блочного устройства изBOARD_SUPER_PARTITION_BLOCK_DEVICES
соответственно. Это список размеров существующих физических разделов на устройстве. В существующих конфигурациях платы это обычноBOARD_ partition IMAGE_PARTITION_SIZE
. - Отменить установку существующего
BOARD_ partition IMAGE_PARTITION_SIZE
для всех разделов вBOARD_SUPER_PARTITION_BLOCK_DEVICES
. - Установите
BOARD_SUPER_PARTITION_SIZE
равным суммеBOARD_SUPER_PARTITION_ partition _DEVICE_SIZE
. - Установите
BOARD_SUPER_PARTITION_METADATA_DEVICE
на блочное устройство, на котором хранятся метаданные динамического раздела. Это должно быть одно из следующих значений:BOARD_SUPER_PARTITION_BLOCK_DEVICES
. Обычно это значение равноsystem
. - Установите
BOARD_SUPER_PARTITION_GROUPS
,BOARD_ group _SIZE
иBOARD_ group _PARTITION_LIST
соответственно. Подробнее см. в разделе «Изменения конфигурации платы на новых устройствах» .
Например, если на устройстве уже есть системные и поставщикские разделы, и вы хотите преобразовать их в динамические разделы и добавить новый раздел продукта во время обновления, установите следующую конфигурацию платы:
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
Изменения SELinux
Блочные устройства суперразделов должны быть отмечены атрибутом super_block_device_type
. Например, если устройство уже имеет system
и vendor
разделы, вы хотите использовать их как блочные устройства для хранения экстентов динамических разделов, а их символические ссылки по имени будут отмечены как 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
Затем добавьте следующую строку в device.te
:
typeattribute system_block_device super_block_device_type;
Другие конфигурации см. в разделе Реализация динамических разделов на новых устройствах .
Дополнительную информацию об обновлениях ретрофита см. в разделе OTA для устройств A/B без динамических разделов .
Заводские изображения
Для устройств, запускаемых с поддержкой динамических разделов, избегайте использования быстрой загрузки в пользовательском пространстве для прошивки заводских образов, поскольку загрузка в пользовательском пространстве происходит медленнее, чем другие методы прошивки.
Чтобы решить эту проблему, make dist
теперь собирает дополнительный образ super.img
, который можно записать непосредственно в суперраздел. Он автоматически объединяет содержимое логических разделов, то есть содержит system.img
, vendor.img
и т.д., а также метаданные super
. Этот образ можно записать непосредственно в super
без использования дополнительных инструментов или fastbootd. После сборки super.img
помещается в ${ANDROID_PRODUCT_OUT}
.
Для устройств A/B, которые запускаются с динамическими разделами, super.img
содержит образы в слоте A. После прямой прошивки суперобраза отметьте слот A как загрузочный перед перезагрузкой устройства.
Для устройств, модернизированных с помощью make dist
, создаётся набор образов super_*.img
, которые можно напрямую записать в соответствующие физические разделы. Например, make dist
создаёт super_system.img
и super_vendor.img
если в качестве поставщика системы выбран BOARD_SUPER_PARTITION_BLOCK_DEVICES
. Эти образы размещаются в папке OTA в target_files.zip
.
Настройка устройства хранения данных с помощью картографа устройств
Динамическое разбиение поддерживает ряд недетерминированных объектов сопоставления устройств. Не все из них могут создаваться ожидаемым образом, поэтому необходимо отслеживать все монтирования и обновлять свойства Android всех связанных разделов с указанием соответствующих устройств хранения.
Механизм внутри init
отслеживает монтирование и асинхронно обновляет свойства Android. Время, необходимое для этого, не гарантируется, поэтому необходимо обеспечить достаточное время для срабатывания всех триггеров on property
. Свойства: dev.mnt.blk. <partition>
, где <partition>
— это, например, root
, system
, data
или vendor
. Каждое свойство связано с именем базового устройства хранения, как показано в следующих примерах:
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]
Язык init.rc
позволяет расширять свойства Android как часть правил, а устройства хранения могут настраиваться платформой по мере необходимости с помощью таких команд:
write /sys/block/${dev.mnt.blk.root}/queue/read_ahead_kb 128 write /sys/block/${dev.mnt.blk.data}/queue/read_ahead_kb 128
После начала обработки команды на втором этапе init
активируется epoll loop
, и значения начинают обновляться. Однако, поскольку триггеры свойств активируются только на этапе late- init
, их нельзя использовать на начальных этапах загрузки для обработки root
, system
или vendor
. Можно ожидать, что read_ahead_kb
по умолчанию в ядре будет достаточно, пока скрипты init.rc
не смогут переопределить его на early-fs
(когда запускаются различные демоны и службы). Поэтому Google рекомендует использовать свойство on property
в сочетании со свойством, управляемым init.rc
, например sys.read_ahead_kb
, для синхронизации операций и предотвращения состояний гонки, как в следующих примерах:
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}