Динамическое секционирование реализовано с помощью модуля 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
была пустой.
Выравнивание разделов
Модуль сопоставления устройств может работать менее эффективно, если 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
— накладные расходы
См. Реализация Virtual 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
первого этапа, который находится на виртуальном диске.
Не устанавливайте BOARD_BUILD_SYSTEM_ROOT_IMAGE
. В Android 10 флаг BOARD_BUILD_SYSTEM_ROOT_IMAGE
используется только для того, чтобы различать, монтируется ли система ядром или init
первого этапа на виртуальном диске.
Установка BOARD_BUILD_SYSTEM_ROOT_IMAGE
значения true
приводит к ошибке сборки, если PRODUCT_USE_DYNAMIC_PARTITIONS
также имеет 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
. Это должен быть компонент пути устройства к базовой символической ссылке по имени, созданной 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, который будет частью виртуального диска.
Изменения необходимо внести в файл fstab для логических разделов:
- Поле fs_mgr flags должно включать
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
фастбутд
Загрузчик (или любой другой инструмент для прошивки, не относящийся к пользовательскому пространству) не понимает динамические разделы, поэтому не может их прошить. Чтобы решить эту проблему, устройства должны использовать реализацию протокола 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. После прошивки суперобраза напрямую отметьте слот А как загрузочный перед перезагрузкой устройства.
Для модифицированных устройств 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
становится активным, и значения начинают обновляться. Однако, поскольку триггеры свойств не активны до поздней 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}
Динамическое секционирование реализовано с помощью модуля 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
была пустой.
Выравнивание разделов
Модуль сопоставления устройств может работать менее эффективно, если 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
— накладные расходы
См. Реализация Virtual 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
первого этапа, который находится на виртуальном диске.
Не устанавливайте BOARD_BUILD_SYSTEM_ROOT_IMAGE
. В Android 10 флаг BOARD_BUILD_SYSTEM_ROOT_IMAGE
используется только для того, чтобы различать, монтируется ли система ядром или init
первого этапа на виртуальном диске.
Установка BOARD_BUILD_SYSTEM_ROOT_IMAGE
значения true
приводит к ошибке сборки, если PRODUCT_USE_DYNAMIC_PARTITIONS
также имеет 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
. Это должен быть компонент пути устройства к базовой символической ссылке по имени, созданной 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, который будет частью виртуального диска.
Изменения необходимо внести в файл fstab для логических разделов:
- Поле fs_mgr flags должно включать
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
фастбутд
Загрузчик (или любой другой инструмент для прошивки, не относящийся к пользовательскому пространству) не понимает динамические разделы, поэтому не может их прошить. Чтобы решить эту проблему, устройства должны использовать реализацию протокола 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
. - SET
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 Partition Block должны быть помечены атрибутом 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 для Flash Factory Images, поскольку загрузка на пользовательское пространство медленнее, чем другие методы мигания.
Чтобы решить эту проблему, make dist
Now создавать дополнительное изображение super.img
, которое можно вспыхнуть непосредственно в супер разделение. Он автоматически объединяет содержимое логических разделов, то есть он содержит system.img
, vendor.img
и т. Д., В дополнение к метаданным super
разделения. Это изображение может быть прошит непосредственно в super
-раздел без какого -либо дополнительного инструмента или использования FastBootd. После сборки super.img
помещается в ${ANDROID_PRODUCT_OUT}
.
Для устройств A/B, которые запускаются с динамическими разделами, super.img
содержит изображения в слоте. После перезагрузки устройства непосредственно отметьте Super Image, отметьте слот A как загрузка.
Для модернизированных устройств, make dist
создавать набор super_*.img
-изображений, которые можно вспыхнуть непосредственно на соответствующие физические разделы. Например, make dist
Builds super_system.img
и super_vendor.img
, когда BOARD_SUPER_PARTITION_BLOCK_DEVICES
является поставщиком системы. Эти изображения размещены в папке OTA в target_files.zip
.
Настройка хранилища устройства 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}
Динамическое разделение реализуется с использованием модуля DM-линейного устройства в ядре 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
. Все разделы AOST, только для чтения, которые не используются загрузчиком, должны быть динамическими и должны быть удалены из таблицы раздела Guid (GPT). Разделы, специфичные для поставщика, не должны быть динамичными и могут быть размещены в GPT.
Чтобы оценить размер super
, добавьте размеры разделов, удаленных из GPT. Для устройств A/B это должно включать размер обоих слотов. На рисунке 1 показан пример таблицы раздела до и после преобразования в динамические разделы.

Поддерживаемые динамические перегородки:
- Система
- Продавец
- Продукт
- Система Ext
- ОДМ
Для запуска устройств с Android 10 параметр командной строки Kernel androidboot.super_partition
должна быть пустой, чтобы командная Sysprop ro.boot.super_partition
пуста.
Выравнивание раздела
Модуль устройства-маппер может работать менее эффективно, если super
раздел не выровнен должным образом. super
раздел должен быть выровнен с минимальным размером запроса ввода/вывода , как определяется слоем блока. По умолчанию система сборки (через lpmake
, которая генерирует изображение super
Partition), предполагает, что выравнивание 1 MIB достаточно для каждого динамического разделения. Тем не менее, продавцы должны убедиться, что 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
Partition аналогичным образом:
# 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 - накладные расходы - Для устройств, не являющихся A/B и устройствами Modorion A/B, сумма максимальных размеров всех групп должна быть:
BOARD_SUPER_PARTITION_SIZE
- накладные расходы - Во время сборки сумма размеров изображений каждого раздела в группе обновлений не должна превышать максимальный размер группы.
- Накладные расходы требуются в вычислении для учета метаданных, выравниваний и т. Д. Разумные накладные расходы - это 4 MIB, но вы можете выбрать большие накладные расходы по мере необходимости устройству.
Размер динамических перегородков
Перед динамическими перегородками размеры раздела были чрезмерно раскрыты, чтобы убедиться, что у них было достаточно места для будущих обновлений. Фактический размер был взят как есть, и большинство разделов только для чтения имели некоторое свободное пространство в их файловой системе. В динамических перегородках это свободное пространство является непригодным для использования и может использоваться для выращивания перегородков во время 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, не должны использовать системную коррекцию.
Устройства с динамическими разделами (независимо от того, запускается ли он с или модернизированными динамическими разделами) не должны использовать системную корн. Ядро Linux не может интерпретировать super
разделение, и поэтому не может установить саму system
. system
теперь монтируется первой стадией init
, которая находится в Ramdisk.
Не устанавливайте BOARD_BUILD_SYSTEM_ROOT_IMAGE
. В Android 10 флаг BOARD_BUILD_SYSTEM_ROOT_IMAGE
используется только для дифференциации, монтируется ли система ядром или первой init
в Ramdisk.
Установка BOARD_BUILD_SYSTEM_ROOT_IMAGE
TO true
приводит к ошибке сборки, когда PRODUCT_USE_DYNAMIC_PARTITIONS
также true
.
Когда BOARD_USES_RECOVERY_AS_BOOT
устанавливается на true, изображение восстановления создается как boot.img, содержащий рамдиск восстановления. Ранее Bootloader использовал параметр командной строки skip_initramfs
Command Line, чтобы решить, в какой режим загрузиться. Для устройств Android 10 загрузчик не должен передавать skip_initramfs
в командную строку ядра. Вместо этого загрузчик должен передать androidboot.force_normal_boot=1
чтобы пропустить восстановление и загрузку нормального Android. Устройства androidboot.force_normal_boot=1
запущенные с Android 12 или более
AVB Configuration Change
При использовании 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 Bootloader изменяется
Если загрузчик встроен Libavb , включите следующие патчи:
- 818CF567407754446285466EDA984Acedd4baeac0 - «Libavb: только Guids для раздела запроса, когда CMDLine нуждается в них».
- 5ABD6BC2578968D24406D834471ADFD995A0C2E9 - «Разрешить системное разделение отсутствовать»
- 9BA3B6613B4E5130FA01A11D984C6B5F0EB3AF05- «Исправить AVBSLOTVERIFYDATA-> CMDLINE может быть нулевым»
При использовании цепных разделов включите дополнительный патч:
- 49936B4C0109411FDD38BD4BA3A32A01C40439A9 - «Libavb: поддержка Blobs vbmeta в начале раздела».
Изменения командной строки ядра
Новый параметр, androidboot.boot_devices
, должен быть добавлен в командную строку ядра. Это используется init
, чтобы включить /dev/block/by-name
symlinks. Это должен быть компонент пути устройства для базового побочного символа, созданного ueventd
, то есть /dev/block/platform/ device-path /by-name/ partition-name
. Устройства, запущенные с init
12 или androidboot.boot_devices
Например, если Symlink Symlink Super Partition IS /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, который будет частью RamDisk.
Изменения должны быть внесены в файл FSTAB для логических разделов:
- Поле FS_MGR Flags должно включать
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 на первом этапе RamDisk.
Selinux меняется
Устройство Super Partition Block должно быть помечено меткой super_block_device
. Например, если Symlink Super Priation Symlink IS /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
Bootloader (или любой инструмент для мигания, не являющегося USERSPACE) не понимает динамические разделы, поэтому он не может их мигать. Чтобы решить это, устройства должны использовать внедрение пользовательского пространства протокола FastBoot под названием FastBootd.
Для получения дополнительной информации о том, как реализовать FastBootd, см. Перемещение FastBoot в пространство для пользователя .
adb перемонтировать
Для разработчиков, использующих сборки ENG или UserDeBug, adb remount
чрезвычайно полезен для быстрой итерации. Динамические разделы создают проблему для adb remount
, поскольку в каждой файловой системе больше нет свободного пространства. Чтобы решить эту проблему, устройства могут включать OplayFS. До тех пор, пока в супер -разделе существует свободное пространство, adb remount
автоматически создает временный динамический раздел и использует OplayFS для записей. Временное разделение называется scratch
, поэтому не используйте это имя для других разделов.
Для получения дополнительной информации о том, как включить overlayfs, см. Alplayfs readme в AOSP.
Обновите устройства Android
Если вы обновите устройство до Android 10 и хотите включить поддержку динамических разделов в OTA, вам не нужно менять встроенную таблицу разделов. Требуется некоторая дополнительная конфигурация.
Изменения конфигурации устройства
Чтобы модернизировать динамическое разделение, добавьте следующие флаги в device.mk
:
PRODUCT_USE_DYNAMIC_PARTITIONS := true PRODUCT_RETROFIT_DYNAMIC_PARTITIONS := true
Изменения конфигурации платы
Вам нужно установить следующие переменные платы:
- SET
BOARD_SUPER_PARTITION_BLOCK_DEVICES
В список блочных устройств, используемых для хранения экстентов динамических разделов. Это список имен существующих физических разделов на устройстве. - SET
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
. - SET
BOARD_SUPER_PARTITION_SIZE
в суммеBOARD_SUPER_PARTITION_ partition _DEVICE_SIZE
. - SET
BOARD_SUPER_PARTITION_METADATA_DEVICE
в устройство блока, где хранятся динамические метаданные разделения. Это должен быть один изBOARD_SUPER_PARTITION_BLOCK_DEVICES
. Обычно это установлено наsystem
. - SET
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 Partition Block должны быть помечены атрибутом 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 для Flash Factory Images, поскольку загрузка на пользовательское пространство медленнее, чем другие методы мигания.
Чтобы решить эту проблему, make dist
Now создавать дополнительное изображение super.img
, которое можно вспыхнуть непосредственно в супер разделение. Он автоматически объединяет содержимое логических разделов, то есть он содержит system.img
, vendor.img
и т. Д., В дополнение к метаданным super
разделения. Это изображение может быть прошит непосредственно в super
-раздел без какого -либо дополнительного инструмента или использования FastBootd. После сборки super.img
помещается в ${ANDROID_PRODUCT_OUT}
.
Для устройств A/B, которые запускаются с динамическими разделами, super.img
содержит изображения в слоте. После перезагрузки устройства непосредственно отметьте Super Image, отметьте слот A как загрузка.
Для модернизированных устройств, make dist
создавать набор super_*.img
-изображений, которые можно вспыхнуть непосредственно на соответствующие физические разделы. Например, make dist
Builds super_system.img
и super_vendor.img
, когда BOARD_SUPER_PARTITION_BLOCK_DEVICES
является поставщиком системы. Эти изображения размещены в папке OTA в target_files.zip
.
Настройка хранилища устройства 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}
Динамическое разделение реализуется с использованием модуля DM-линейного устройства в ядре 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
. Все разделы AOST, только для чтения, которые не используются загрузчиком, должны быть динамическими и должны быть удалены из таблицы раздела Guid (GPT). Разделы, специфичные для поставщика, не должны быть динамичными и могут быть размещены в GPT.
Чтобы оценить размер super
, добавьте размеры разделов, удаленных из GPT. Для устройств A/B это должно включать размер обоих слотов. На рисунке 1 показан пример таблицы раздела до и после преобразования в динамические разделы.

Поддерживаемые динамические перегородки:
- Система
- Продавец
- Продукт
- Система Ext
- ОДМ
Для запуска устройств с Android 10 параметр командной строки Kernel androidboot.super_partition
должна быть пустой, чтобы командная Sysprop ro.boot.super_partition
пуста.
Выравнивание раздела
Модуль устройства-маппер может работать менее эффективно, если super
раздел не выровнен должным образом. super
раздел должен быть выровнен с минимальным размером запроса ввода/вывода , как определяется слоем блока. По умолчанию система сборки (через lpmake
, которая генерирует изображение super
Partition), предполагает, что выравнивание 1 MIB достаточно для каждого динамического разделения. Тем не менее, продавцы должны убедиться, что 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
Partition аналогичным образом:
# 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 - накладные расходы - Для устройств, не являющихся A/B и устройствами Modorion A/B, сумма максимальных размеров всех групп должна быть:
BOARD_SUPER_PARTITION_SIZE
- накладные расходы - Во время сборки сумма размеров изображений каждого раздела в группе обновлений не должна превышать максимальный размер группы.
- Накладные расходы требуются в вычислении для учета метаданных, выравниваний и т. Д. Разумные накладные расходы - это 4 MIB, но вы можете выбрать большие накладные расходы по мере необходимости устройству.
Размер динамических перегородков
Перед динамическими перегородками размеры раздела были чрезмерно раскрыты, чтобы убедиться, что у них было достаточно места для будущих обновлений. Фактический размер был взят как есть, и большинство разделов только для чтения имели некоторое свободное пространство в их файловой системе. В динамических перегородках это свободное пространство является непригодным для использования и может использоваться для выращивания перегородков во время 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, не должны использовать системную коррекцию.
Устройства с динамическими разделами (независимо от того, запускается ли он с или модернизированными динамическими разделами) не должны использовать системную корн. Ядро Linux не может интерпретировать super
разделение, и поэтому не может установить саму system
. system
теперь монтируется первой стадией init
, которая находится в Ramdisk.
Не устанавливайте BOARD_BUILD_SYSTEM_ROOT_IMAGE
. В Android 10 флаг BOARD_BUILD_SYSTEM_ROOT_IMAGE
используется только для дифференциации, монтируется ли система ядром или первой init
в Ramdisk.
Установка BOARD_BUILD_SYSTEM_ROOT_IMAGE
TO true
приводит к ошибке сборки, когда PRODUCT_USE_DYNAMIC_PARTITIONS
также true
.
Когда BOARD_USES_RECOVERY_AS_BOOT
устанавливается на true, изображение восстановления создается как boot.img, содержащий рамдиск восстановления. Ранее Bootloader использовал параметр командной строки skip_initramfs
Command Line, чтобы решить, в какой режим загрузиться. Для устройств Android 10 загрузчик не должен передавать skip_initramfs
в командную строку ядра. Вместо этого загрузчик должен передать androidboot.force_normal_boot=1
чтобы пропустить восстановление и загрузку нормального Android. Устройства androidboot.force_normal_boot=1
запущенные с Android 12 или более
AVB Configuration Change
При использовании 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 Bootloader изменяется
Если загрузчик встроен Libavb , включите следующие патчи:
- 818CF567407754446285466EDA984Acedd4baeac0 - «Libavb: только Guids для раздела запроса, когда CMDLine нуждается в них».
- 5ABD6BC2578968D24406D834471ADFD995A0C2E9 - «Разрешить системное разделение отсутствовать»
- 9BA3B6613B4E5130FA01A11D984C6B5F0EB3AF05- «Исправить AVBSLOTVERIFYDATA-> CMDLINE может быть нулевым»
При использовании цепных разделов включите дополнительный патч:
- 49936B4C0109411FDD38BD4BA3A32A01C40439A9 - «Libavb: поддержка Blobs vbmeta в начале раздела».
Изменения командной строки ядра
Новый параметр, androidboot.boot_devices
, должен быть добавлен в командную строку ядра. Это используется init
, чтобы включить /dev/block/by-name
symlinks. It should be the device path component to the underlying by-name symlink created by ueventd
, that is, /dev/block/platform/ device-path /by-name/ partition-name
. Devices launching with Android 12 or later must use bootconfig to pass androidboot.boot_devices
to init
.
For example, if the super partition by-name symlink is /dev/block/platform/ soc/100000.ufshc /by-name/super
, you can add the command line parameter in the BoardConfig.mk file as follows:
BOARD_KERNEL_CMDLINE += androidboot.boot_devices=soc/100000.ufshc
BOARD_BOOTCONFIG += androidboot.boot_devices=soc/100000.ufshc
fstab changes
The device tree and device tree overlays must not contain fstab entries. Use an fstab file that will be part of the ramdisk.
Changes must be made to the fstab file for logical partitions:
- The fs_mgr flags field must include the
logical
flag and thefirst_stage_mount
flag, introduced in Android 10, which indicates that a partition is to be mounted in the first stage. - A partition may specify
avb= vbmeta partition name
as anfs_mgr
flag and then the specifiedvbmeta
partition is initialized by first stageinit
before attempting to mount any devices. - The
dev
field must be the partition name.
The following fstab entries set system, vendor, and product as logical partitions following the above rules.
#<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
Copy the fstab file into the first stage ramdisk.
SELinux changes
The super partition block device must be marked with the label super_block_device
. For example, if the super partition by-name symlink is /dev/block/platform/ soc/100000.ufshc /by-name/super
, add the following line to file_contexts
:
/dev/block/platform/soc/10000\.ufshc/by-name/super u:object_r:super_block_device:s0
fastbootd
The bootloader (or any non-userspace flashing tool) doesn't understand dynamic partitions, so it can't flash them. To address this, devices must use a user-space implementation of the fastboot protocol, called fastbootd.
For more information on how to implement fastbootd, see Moving Fastboot to User Space .
adb перемонтировать
For developers using eng or userdebug builds, adb remount
is extremely useful for fast iteration. Dynamic partitions pose a problem for adb remount
because there is no longer free space within each file system. To address this, devices can enable overlayfs. As long as there is free space within the super partition, adb remount
automatically creates a temporary dynamic partition and uses overlayfs for writes. The temporary partition is named scratch
, so don't use this name for other partitions.
For more information on how to enable overlayfs, see the overlayfs README in AOSP.
Upgrade Android devices
If you upgrade a device to Android 10, and want to include dynamic partitions support in the OTA, you don't need to change the built-in partition table. Some extra configuration is required.
Device configuration changes
To retrofit dynamic partitioning, add the following flags in device.mk
:
PRODUCT_USE_DYNAMIC_PARTITIONS := true PRODUCT_RETROFIT_DYNAMIC_PARTITIONS := true
Board configuration changes
You're required to set the following board variables:
- Set
BOARD_SUPER_PARTITION_BLOCK_DEVICES
to the list of block devices used to store extents of dynamic partitions. This is the list of names of existing physical partitions on the device. - Set
BOARD_SUPER_PARTITION_ partition _DEVICE_SIZE
to the sizes of each block device inBOARD_SUPER_PARTITION_BLOCK_DEVICES
, respectively. This is the list of sizes of existing physical partitions on the device. This is usuallyBOARD_ partition IMAGE_PARTITION_SIZE
in existing board configurations. - Unset existing
BOARD_ partition IMAGE_PARTITION_SIZE
for all partitions inBOARD_SUPER_PARTITION_BLOCK_DEVICES
. - Set
BOARD_SUPER_PARTITION_SIZE
to the sum ofBOARD_SUPER_PARTITION_ partition _DEVICE_SIZE
. - Set
BOARD_SUPER_PARTITION_METADATA_DEVICE
to the block device where dynamic partition metadata is stored. It must be one ofBOARD_SUPER_PARTITION_BLOCK_DEVICES
. Usually, this is set tosystem
. - Set
BOARD_SUPER_PARTITION_GROUPS
,BOARD_ group _SIZE
, andBOARD_ group _PARTITION_LIST
, respectively. See Board configuration changes on new devices for details.
For example, if the device already has system and vendor partitions, and you want to convert them to dynamic partitions and add a new product partition during the update, set this board configuration:
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 changes
The super partition block devices must be marked with the attribute super_block_device_type
. For example, if the device already has system
and vendor
partitions, you want to use them as block devices to store extents of dynamic partitions, and their by-name symlinks are marked as 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
Then, add the following line to device.te
:
typeattribute system_block_device super_block_device_type;
For other configurations, see Implementing dynamic partitions on new devices .
For more information about retrofit updates, see OTA for A/B Devices without Dynamic Partitions .
Заводские изображения
For a device launching with dynamic partitions support, avoid using userspace fastboot to flash factory images, as booting to userspace is slower than other flashing methods.
To address this, make dist
now builds an additional super.img
image that can be flashed directly to the super partition. It automatically bundles the contents of logical partitions, meaning it contains system.img
, vendor.img
, and so on, in addition to the super
partition metadata. This image can be flashed directly to the super
partition without any additional tooling or using fastbootd. After the build, super.img
is placed in ${ANDROID_PRODUCT_OUT}
.
For A/B devices that launch with dynamic partitions, super.img
contains images in the A slot. After flashing the super image directly, mark slot A as bootable before rebooting the device.
For retrofit devices, make dist
builds a set of super_*.img
images that can be flashed directly to corresponding physical partitions. For example, make dist
builds super_system.img
and super_vendor.img
when BOARD_SUPER_PARTITION_BLOCK_DEVICES
is the system vendor. These images are placed in the OTA folder in target_files.zip
.
Device mapper storage-device tuning
Dynamic partitioning accommodates a number of nondeterministic device-mapper objects. These may not all instantiate as expected, so you must track all mounts, and update the Android properties of all the associated partitions with their underlying storage devices.
A mechanism inside init
tracks the mounts and asynchronously updates the Android properties. The amount of time this takes isn't guaranteed to be within a specific period, so you must provide enough time for all on property
triggers to react. The properties are dev.mnt.blk. <partition>
where <partition>
is root
, system
, data
, or vendor
, for example. Each property is associated with the base storage-device name, as shown in these examples:
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]
The init.rc
language allows the Android properties to be expanded as part of the rules, and storage devices can be tuned by the platform as needed with commands like these:
write /sys/block/${dev.mnt.blk.root}/queue/read_ahead_kb 128 write /sys/block/${dev.mnt.blk.data}/queue/read_ahead_kb 128
Once command processing starts in second-stage init
, the epoll loop
becomes active, and the values start to update. However, because property triggers aren't active until late- init
, they can't be used in the initial boot stages to handle root
, system
, or vendor
. You may expect the kernel default read_ahead_kb
to be sufficient until the init.rc
scripts can override in early-fs
(when various daemons and facilities start). Therefore, Google recommends that you use the on property
feature, coupled with an init.rc
-controlled property like sys.read_ahead_kb
, to deal with timing the operations and to prevent race conditions, as in these examples:
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}