В Android 10 корневая файловая система больше не включается в ramdisk.img, а объединяется с system.img (то есть system.img всегда создается так, как если бы было задано значение BOARD_BUILD_SYSTEM_ROOT_IMAGE). Устройства, выпущенные с Android 10:
- Используйте схему разделов system-as-root (применяется автоматически при сборке, изменить это нельзя).
- Необходимо использовать ramdisk, который требуется для dm-linear.
- Необходимо задать для параметра
BOARD_BUILD_SYSTEM_ROOT_IMAGEзначениеfalse. Этот параметр используется только для того, чтобы различать устройства, которые используют ramdisk, и устройства, которые не используют ramdisk (и вместо этого монтируютsystem.imgнапрямую).
Значение конфигурации system-as-root различается в Android 9 и Android 10. В конфигурации Android 9 system-as-root для параметра BOARD_BUILD_SYSTEM_ROOT_IMAGE задано значение true, которое заставляет сборку объединить корневую файловую систему в system.img, а затем смонтировать system.img как корневую файловую систему (rootfs). Эта конфигурация обязательна для устройств с Android 9, но необязательна для устройств, на которых Android 9 был установлен в качестве обновления, и для устройств с более ранними версиями Android. В конфигурации Android 10 с системным разделом в корневом каталоге сборка всегда объединяет $TARGET_SYSTEM_OUT и $TARGET_ROOT_OUT в system.img. Эта конфигурация является режимом работы по умолчанию для всех устройств с Android 10.
В Android 10 также внесены изменения для поддержки динамических разделов – системы разделов пользовательского пространства, которая позволяет создавать, изменять размер и удалять разделы при обновлении по беспроводной сети. В рамках этого изменения ядро Linux больше не может монтировать логический системный раздел на устройствах с Android 10, поэтому эта операция обрабатывается на первом этапе инициализации.
В следующих разделах описаны требования к системному корневому разделу для OTA-обновлений только системы, а также приведены рекомендации по обновлению устройств для использования системного корневого раздела (включая изменения макета разделов и требования к ядру dm-verity). Подробнее об изменениях в ramdisk можно узнать в статье Разделы ramdisk.
О беспроводных обновлениях только системы
OTA-обновления только системы, которые позволяют обновлять выпуски Android system.img и product.img без изменения других разделов, требуют макета раздела "система как корень". Все устройства с Android 10 должны использовать системный раздел в качестве корневого, чтобы можно было выполнять OTA-обновления только системы.
- Устройства с разделами A/B, в которых раздел
systemмонтируется как rootfs, уже используют систему как корневую файловую систему и не требуют изменений для поддержки OTA-обновлений системы. - Устройства без A/B-обновлений, которые монтируют раздел
systemв/system, должны быть обновлены для использования макета раздела system-as-root, чтобы поддерживать беспроводные обновления системы.
Подробнее об устройствах с разделами A/B и без них можно узнать в статье Системные обновления A/B (бесшовные).
Использовать оверлей поставщика (<=AOSP 14)
Оверлей поставщика позволяет накладывать изменения на раздел vendor при загрузке устройства. Наложение поставщика – это набор модулей поставщика в разделе product, которые накладываются на раздел vendor при загрузке устройства, заменяя и дополняя существующие модули.
Когда устройство загружается, процесс init завершает монтирование на первом этапе и считывает свойства по умолчанию. Затем он ищет /product/vendor_overlay/<target_vendor_version> и монтирует каждый подкаталог в соответствующий каталог раздела vendor, если выполняются следующие условия:
/vendor/<overlay_dir>./product/vendor_overlay/<target_vendor_version>/<overlay_dir>имеет тот же контекст файла, что и/vendor/<overlay_dir>.initможет быть смонтирован в контексте файла/vendor/<overlay_dir>.
Как реализовать оверлей поставщика
Установите файлы наложения поставщика в /product/vendor_overlay/<target_vendor_version>. Эти файлы перекрывают раздел vendor при загрузке устройства, заменяя файлы с тем же именем и добавляя новые файлы. Оверлей поставщика не может удалять файлы из раздела vendor.
Файлы оверлея поставщика должны иметь тот же контекст, что и целевые файлы, которые они заменяют в разделе vendor. По умолчанию файлы в каталоге /product/vendor_overlay/<target_vendor_version> имеют контекст vendor_file. Если контекст файлов поставщика не совпадает с контекстом файлов, которые они заменяют, укажите это в файле sepolicy для устройства. Контекст файла задается на уровне каталога. Если контекст файла каталога наложения поставщика не совпадает с целевым каталогом и правильный контекст файла не указан в sepolicy для устройства, каталог наложения поставщика не будет наложен на целевой каталог.
Чтобы использовать наложение поставщика, ядро должно включить OverlayFS, задав значение CONFIG_OVERLAY_FS=y. Кроме того, ядро должно быть объединено с общим ядром версии 4.4 или более поздней или исправлено с помощью "overlayfs:
override_creds=off option bypass creator_cred".
Пример реализации оверлея поставщика
В этой процедуре показано, как реализовать наложение поставщика, которое перекрывает каталоги /vendor/lib/*, /vendor/etc/* и /vendor/app/*.
-
Добавьте готовые файлы поставщиков в папку
device/<vendor>/<target>/vendor_overlay/<target_vendor_version>/:device/google/device/vendor_overlay/28/lib/libfoo.so device/google/device/vendor_overlay/28/lib/libbar.so device/google/device/vendor_overlay/28/etc/baz.xml device/google/device/vendor_overlay/28/app/qux.apk
-
Установите готовые файлы поставщика в
product/vendor_overlayвdevice/google/device/device.mk:PRODUCT_COPY_FILES += \ $(call find-copy-subdir-files,*,device/google/device/vendor_overlay,$(TARGET_COPY_OUT_PRODUCT)/vendor_overlay)
-
Определите контексты файлов, если целевые файлы раздела
vendorимеют контексты, отличные отvendor_file. Поскольку в примере/vendor/lib/*используется контекстvendor_file, этот каталог не включен.Добавьте в чат-группу "
device/google/device-sepolicy/private/file_contexts" следующее:/(product|system/product)/vendor_overlay/[0-9]+/etc(/.*)? u:object_r:vendor_configs_file:s0 /(product|system/product)/vendor_overlay/[0-9]+/app(/.*)? u:object_r:vendor_app_file:s0
-
Разрешить процессу
initмонтировать наложение поставщика в контекстах файлов, отличных отvendor_file. Поскольку у процессаinitуже есть разрешение на монтирование в контекстеvendor_file, в этом примере не определяются правила дляvendor_file.Добавьте в
device/google/device-sepolicy/public/init.teследующее:allow init vendor_configs_file:dir mounton; allow init vendor_app_file:dir mounton;
Проверка наложения поставщика
Чтобы проверить конфигурацию наложения поставщика, добавьте файлы в
/product/vendor_overlay/<target_vendor_version>/<overlay_dir>
и убедитесь, что они накладываются на файлы в
/vendor/<overlay_dir>.
Для сборок userdebug существует тестовый модуль для Atest:
$ atest -v fs_mgr_vendor_overlay_test
Обновление до system-as-root
Чтобы обновить устройства, не поддерживающие A/B-обновления, и использовать system-as-root, необходимо обновить схему разбиения для boot.img и system.img, настроить dm-verity и удалить все зависимости загрузки от корневых папок, относящихся к устройству.
Как обновить разделы
В отличие от устройств с A/B-разделами, где /boot используется как раздел recovery, на устройствах без A/B-разделов раздел /recovery должен быть отдельным, поскольку на них нет резервного раздела (например, с boot_a на boot_b). Если на устройстве без A/B-разделов удалить раздел /recovery и сделать его похожим на схему с A/B-разделами, режим восстановления может перестать работать при сбое обновления раздела /boot. По этой причине раздел /recovery должен быть отдельным от раздела /boot на устройствах, не поддерживающих A/B-обновления. Это означает, что образ восстановления по-прежнему будет обновляться с задержкой (как на устройствах с Android 8.1.0 или более ранней версии).
В таблице ниже перечислены различия в разделах образов для устройств без поддержки A/B-обновлений до и после Android 9.
| Изображение | Ramdisk (до Android 9) | System-as-root (после Android 9) |
|---|---|---|
boot.img |
Содержит ядро и ramdisk.img:
ramdisk.img
-/
- init.rc
- init
- etc -> /system/etc
- system/ (mount point)
- vendor/ (mount point)
- odm/ (mount point)
... |
Содержит только обычное загрузочное ядро. |
recovery.img |
Содержит ядро и ramdisk.img восстановления. |
|
system.img |
Содержит следующие данные:
system.img
-/
- bin/
- etc
- vendor -> /vendor
- ... |
Содержит объединенный контент исходных файлов system.img и ramdisk.img:
system.img
-/
- init.rc
- init
- etc -> /system/etc
- system/
- bin/
- etc/
- vendor -> /vendor
- ...
- vendor/ (mount point)
- odm/ (mount point)
... |
Сами разделы не меняются. В обоих случаях используется следующая схема:
/boot/system/system/recovery/vendorи т. д.
Как настроить dm-verity
В системе с корневым разделом на устройстве ядро должно смонтировать system.img в / (точку монтирования) с помощью dm-verity. В AOSP поддерживаются следующие реализации dm-verity для system.img:
vboot 1.0
Для vboot 1.0 ядро должно анализировать метаданные, относящиеся к Android, на /system, а затем преобразовывать их в параметры dm-verity, чтобы настроить dm-verity (требуются эти исправления ядра).
В следующем примере показаны настройки dm-verity для system-as-root в командной строке ядра:
ro root=/dev/dm-0 rootwait skip_initramfs init=/init dm="system none ro,0 1 android-verity /dev/sda34" veritykeyid=id:7e4333f9bba00adfe0ede979e28ed1920492b40f
vboot 2.0
Для vboot 2.0 (AVB) загрузчик должен интегрировать external/avb/libavb, который затем анализирует дескриптор дерева хешей для /system, преобразует его в параметры dm-verity и передает их ядру через командную строку ядра. (Дескрипторы хеш-дерева /system
могут быть в /vbmeta или в самом /system.)
Для vboot 2.0 требуются следующие исправления ядра:
- https://android-review.googlesource.com/#/c/kernel/common/+/158491/
- исправления для ядра 4.4, исправления для ядра 4.9 и т. д.
В следующем примере показаны настройки dm-verity для system-as-root в командной строке ядра:
ro root=/dev/dm-0 rootwait skip_initramfs init=/init dm="1 vroot none ro 1,0 5159992 verity 1 PARTUUID=00000016-0000-0000-0000-000000000000 PARTUUID=00000016-0000-0000-0000-000000000000 4096 4096 644999 644999 sha1 d80b4a8be3b58a8ab86fad1b498640892d4843a2 8d08feed2f55c418fb63447fec0d32b1b107e42c 10 restart_on_corruption ignore_zero_blocks use_fec_from_device PARTUUID=00000016-0000-0000-0000-000000000000 fec_roots 2 fec_blocks 650080 fec_start 650080"
Используйте корневые папки для разных устройств
При использовании системного раздела в качестве корневого после того, как на устройство будет записан стандартный системный образ (GSI) (и до запуска тестов набора для тестирования поставщика), все корневые папки, добавленные с помощью команды BOARD_ROOT_EXTRA_FOLDERS, будут удалены, поскольку все содержимое корневого каталога будет заменено на GSI с системным разделом в качестве корневого. Удаление этих папок может привести к тому, что устройство не сможет загрузиться, если оно зависит от корневых папок устройства (например, они используются в качестве точек подключения).
Чтобы избежать этой проблемы, не используйте BOARD_ROOT_EXTRA_FOLDERS для добавления корневых папок, относящихся к определенному устройству. Если вам нужно указать точки монтирования для определенных устройств, используйте /mnt/vendor/<mount point> (добавлено в этих списках изменений). Точки монтирования, относящиеся к определенному поставщику, можно указать непосредственно в дереве устройств fstab (для монтирования на первом этапе) и в файле /vendor/etc/fstab.{ro.hardware} без дополнительной настройки (поскольку fs_mgr создает их в каталоге /mnt/vendor/* автоматически).