Динамическое разбиение на разделы реализовано с помощью модуля 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 показан пример таблицы разделов до и после преобразования в динамические разделы.

Поддерживаются следующие динамические разделы:
- Система
- Продавец
- Продукт
- Системный экст
- ОДМ
Для устройств, запускаемых с 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
- Для устройств с виртуальным запуском A/B сумма максимальных размеров всех групп должна быть не более:
BOARD_SUPER_PARTITION_SIZE- накладные расходы
См. раздел «Реализация виртуального A/B-тестирования» . - Для пусковых устройств типа A/B сумма максимальных размеров всех групп должна быть равна:
BOARD_SUPER_PARTITION_SIZE/ 2 - overhead - Для устройств, не относящихся к классу 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 МиБ неиспользованного пространства.
Изменения, идущие от корня системы
На устройствах, запускаемых с Android 10, нельзя использовать права root в системе.
Устройства с динамическими разделами (независимо от того, запускаются ли они с динамическими разделами или добавляются к ним позже) не должны использовать system-as-root. Ядро Linux не может интерпретировать super и, следовательно, не может смонтировать сам system . Теперь system монтируется на первом этапе init , который находится в оперативной памяти (ramdisk).
Не устанавливайте флаг BOARD_BUILD_SYSTEM_ROOT_IMAGE . В Android 10 флаг BOARD_BUILD_SYSTEM_ROOT_IMAGE используется только для различения того, монтируется ли система ядром или init первого этапа в ramdisk.
Если параметр PRODUCT_USE_DYNAMIC_PARTITIONS также имеет true , установка BOARD_BUILD_SYSTEM_ROOT_IMAGE в значение true приводит к ошибке сборки.
Когда параметр BOARD_USES_RECOVERY_AS_BOOT установлен в значение true, образ восстановления создается как boot.img, содержащий образ восстановления в оперативной памяти. Ранее загрузчик использовал параметр командной строки ядра 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
В файлах `device tree` и `device tree overlays` не должно быть записей в `fstab`. Используйте файл `fstab`, который будет частью виртуального диска в оперативной памяти.
Для логических разделов необходимо внести изменения в файл fstab:
- Поле флагов fs_mgr должно содержать
logicalфлаг и флагfirst_stage_mount, введенный в Android 10, который указывает на то, что раздел должен быть смонтирован на первом этапе. - В качестве флага
fs_mgrдля раздела можно указатьavb= vbmeta partition name, после чего указанный разделvbmetaинициализируется на первом этапеinitперед попыткой монтирования каких-либо устройств. - В поле
devдолжно быть указано имя раздела.
Следующие записи в файле fstab устанавливают system, vendor и product в качестве логических разделов в соответствии с вышеуказанными правилами.
#<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 remount
Для разработчиков, использующих сборки 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 без динамических разделов» .
Изображения завода
Для устройств с поддержкой динамических разделов следует избегать использования fastboot в пользовательском пространстве для прошивки заводских образов, поскольку загрузка в пользовательское пространство происходит медленнее, чем при использовании других методов прошивки.
Для решения этой проблемы make dist теперь создает дополнительный образ super.img , который можно напрямую прошить в суперраздел. Он автоматически объединяет содержимое логических разделов, то есть содержит system.img , vendor.img и так далее, в дополнение к метаданным super . Этот образ можно напрямую прошить в super без каких-либо дополнительных инструментов или использования `fastbootd`. После сборки super.img помещается в ${ANDROID_PRODUCT_OUT} .
Для устройств A/B, запускающихся с динамическими разделами, super.img содержит образы в слоте A. После прямой прошивки образа super.img, перед перезагрузкой устройства отметьте слот A как загрузочный.
Для устройств, требующих модернизации, make dist собирает набор образов super_*.img , которые можно напрямую прошить на соответствующие физические разделы. Например, make dist собирает super_system.img и super_vendor.img когда BOARD_SUPER_PARTITION_BLOCK_DEVICES является поставщиком системы. Эти образы помещаются в папку OTA в архиве target_files.zip .
Настройка устройства сопоставления устройств хранения
Динамическое разбиение диска на разделы поддерживает ряд непредсказуемых объектов Device-Mapper. Не все из них могут создаваться должным образом, поэтому необходимо отслеживать все точки монтирования и обновлять свойства 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 , и значения начинают обновляться. Однако, поскольку триггеры свойств активируются только на поздней 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}