Virtual A/B — основной механизм обновления Android. Virtual A/B работает поверх устаревших обновлений A/B (см. Обновления системы A/B ) и не-A/B, который устарел в версии 15, чтобы уменьшить объём занимаемого обновлениями места.
В Virtual A/B фактически нет отдельного слота для динамических разделов (см. раздел «Динамические разделы») . Вместо этого дельта-данные записываются в снимок, а затем объединяются с базовым разделом после подтверждения успешной загрузки. Virtual A/B использует специальный формат снимков Android. См. формат COW для сжатых снимков , который позволяет сжимать снимки и минимизировать использование дискового пространства. При полной загрузке OTA размер снимка уменьшается примерно на 45% благодаря сжатию, а размер инкрементального снимка OTA — примерно на 55%.
В Android 12 доступна функция сжатия Virtual A/B для сжатия разделов, созданных с помощью снимков. Virtual A/B предлагает следующие возможности:
- Виртуальные обновления A/B происходят незаметно (обновление происходит полностью в фоновом режиме, пока устройство работает), как и обновления A/B. Виртуальные обновления A/B минимизируют время, в течение которого устройство находится в автономном режиме и не может быть использовано.
- Обновления Virtual A/B можно откатить . Если новая ОС не загружается, устройства автоматически откатываются к предыдущей версии.
- Обновления Virtual A/B занимают минимум места, дублируя только разделы, используемые загрузчиком. Остальные обновляемые разделы сохраняются в моментальных снимках .
Предыстория и терминология
В этом разделе определяется терминология и описывается технология, поддерживающая виртуальный A/B. Во время беспроводного обновления (OTA) данные новой операционной системы записываются либо в новый слот для физических разделов, либо на специальное устройство Android COW. После перезагрузки устройства данные динамических разделов объединяются с базовым устройством с помощью демонов dm-user и snapuserd. Этот процесс полностью происходит в пользовательском пространстве.
Устройство-картограф
Device-mapper — это виртуальный блочный слой Linux, часто используемый в Android. При использовании динамических разделов , такие как /system
представляют собой стек многоуровневых устройств:
- Внизу стека находится физический суперраздел (например,
/dev/block/by-name/super
). - В середине находится устройство
dm-linear
, определяющее, какие блоки в суперразделе образуют данный динамический раздел. Оно отображается как/dev/block/mapper/system_[a|b]
на устройстве A/B или/dev/block/mapper/system
на устройстве, отличном от A/B. - Вверху находится устройство
dm-verity
, созданное для проверенных разделов. Это устройство проверяет правильность подписи блоков на устройствеdm-linear
. Оно отображается как/dev/block/mapper/system-verity
и является источником точки монтирования/system
.
На рисунке 1 показано, как выглядит стек под точкой монтирования /system
.
Рисунок 1. Стек под точкой монтирования /system
Сжатые снимки
В Android 12 и более поздних версиях, поскольку требования к пространству в разделе /data
могут быть высокими, вы можете включить сжатые моментальные снимки в своей сборке, чтобы удовлетворить более высокие требования к пространству в разделе /data
.
Виртуальные сжатые снимки A/B создаются на основе следующих компонентов, доступных в Android 12 и выше:
-
dm-user
— модуль ядра, аналогичный FUSE, который позволяет пользовательскому пространству реализовывать блочные устройства. -
snapuserd
— демон пользовательского пространства для реализации нового формата моментальных снимков.
Эти компоненты обеспечивают сжатие. Другие необходимые изменения для реализации возможностей сжатых снимков описаны в следующих разделах: Формат COW для сжатых снимков , dm-user и snapuserd .
Формат COW для сжатых снимков
В Android 12 и более поздних версиях сжатые снимки используют специальный формат COW для Android. Формат COW содержит метаданные об OTA и имеет отдельные буферы, содержащие операции COW и новые данные операционной системы. По сравнению с форматом снимков ядра, который допускал только операции замены (замена блока X в базовом образе содержимым блока Y в снимке), формат COW для сжатых снимков Android более выразителен и поддерживает следующие операции:
- Копировать : Блок X в базовом устройстве следует заменить блоком Y в базовом устройстве.
- Заменить : блок X в базовом устройстве следует заменить содержимым блока Y в снимке. Каждый из этих блоков сжат с помощью gz.
- Ноль : Блок X в базовом устройстве следует заменить всеми нулями.
- XOR : Устройство COW хранит сжатые XOR байты между блоком X и блоком Y. (Доступно в Android 13 и выше.)
Полные OTA-обновления состоят только из операций замены и обнуления . Инкрементальные OTA-обновления могут дополнительно включать операции копирования .
Полная структура снимка на диске выглядит так:
Рисунок 2. Формат Android COW на диске
dm-пользователь
Модуль ядра dm-user позволяет реализовать блочные устройства Device-Mapper userspace
. Запись в таблице dm-user создаёт различные устройства в каталоге /dev/dm-user/<control-name>
. Процесс userspace
может опрашивать устройство для получения запросов на чтение и запись от ядра. Каждый запрос имеет связанный буфер, который пользовательское пространство может либо заполнить (для чтения), либо распространить (для записи).
Модуль ядра dm-user
предоставляет новый пользовательский интерфейс для ядра, который не является частью кодовой базы kernel.org. До тех пор, пока это не будет сделано, Google оставляет за собой право изменять интерфейс dm-user
в Android.
snapuserd
Компонент пользовательского пространства snapuserd
для dm-user
реализует сжатие Virtual A/B. Snapuserd — это демон пользовательского пространства, отвечающий за запись и чтение данных устройств Android COW. Все операции ввода-вывода в моментальный снимок должны проходить через эту службу. Во время беспроводного обновления (OTA) новые данные операционной системы записываются в моментальный снимок с помощью snapuserd (со сжатием). Здесь также выполняется разбор метаданных и распаковка новых данных блока.
сжатие XOR
На устройствах с Android 13 и выше функция сжатия XOR, включённая по умолчанию, позволяет сохранять снимки пользовательского пространства, сжатые с помощью XOR, между старыми и новыми блоками. Когда при обновлении Virtual A/B изменяется всего несколько байтов в блоке, схема хранения со сжатием XOR использует меньше места, чем схема хранения по умолчанию, поскольку снимки не хранят полные 4 КБ. Такое уменьшение размера снимка возможно благодаря тому, что данные XOR содержат много нулей и их легче сжимать, чем необработанные данные блока. На устройствах Pixel сжатие XOR уменьшает размер снимка на 25–40%.
Для устройств, обновляемых до Android 13 и выше, необходимо включить сжатие XOR. Подробнее см. в разделе Сжатие XOR .
Слияние снимков
На устройствах с Android 13 и более поздними версиями процессы создания и слияния снимков в сжатии Virtual A/B выполняются компонентом пользовательского пространства snapuserd
. Для устройств, обновляющихся до Android 13 и более поздних версий, эта функция должна быть включена. Подробнее см. в разделе «Слияние пользовательского пространства» .
Ниже описывается процесс сжатия Virtual A/B:
- Фреймворк монтирует раздел
/system
к устройствуdm-verity
, которое размещается поверх устройстваdm-user
. Это означает, что все операции ввода-вывода из корневой файловой системы направляются наdm-user
. -
dm-user
направляет ввод-вывод демонуsnapuserd
пользовательского пространства, который обрабатывает запросы ввода-вывода. - После завершения операции слияния фреймворк сворачивает
dm-verity
поверхdm-linear
(system_base
) и удаляетdm-user
.
Рисунок 3. Процесс виртуального сжатия A/B
Процесс слияния снимков может быть прерван. Если устройство перезагрузится во время процесса слияния, процесс возобновится после перезагрузки.
Инициализирующие переходы
При загрузке со сжатыми снимками процесс инициализации первого этапа должен запустить snapuserd
для монтирования разделов. Это создаёт проблему: при загрузке и принудительном применении sepolicy
snapuserd
попадает в неправильный контекст, и его запросы на чтение завершаются ошибкой, вызывая отказы selinux.
Чтобы решить эту проблему, snapuserd
переходит в синхронном режиме с init
следующим образом:
- На первом этапе
init
запускаетsnapuserd
с ramdisk и сохраняет открытый файловый дескриптор в переменной среды. - На первом этапе
init
переключает корневую файловую систему на системный раздел, а затем выполняет системную копиюinit
. - Системная копия
init
считывает объединенную sepolicy в строку. -
Init
вызываетmlock()
на всех страницах, хранящихся в ext4. Затем он деактивирует все таблицы сопоставления устройств для устройств-снимков и останавливаетsnapuserd
. После этого чтение из разделов запрещено, так как это приводит к взаимоблокировке. - Используя открытый дескриптор копии
snapuserd
на RAM-диске,init
перезапускает демон с корректным контекстом selinux. Таблицы сопоставления устройств для устройств-снимков повторно активируются. - Init вызывает
munlockall()
— можно безопасно снова выполнить ввод-вывод.
Использование пространства
В следующей таблице представлено сравнение использования пространства для различных механизмов OTA с использованием ОС Pixel и размеров OTA.
Размер воздействия | не-A/B | А/Б | Виртуальный А/Б | Виртуальный A/B (сжатый) |
---|---|---|---|---|
Оригинальное заводское изображение | 4,5 ГБ супер (3,8 ГБ образа + 700 МБ зарезервировано) 1 | 9 ГБ супер (3,8 ГБ + 700 МБ зарезервировано, для двух слотов) | 4,5 ГБ супер (3,8 ГБ образа + 700 МБ зарезервировано) | 4,5 ГБ супер (3,8 ГБ образа + 700 МБ зарезервировано) |
Другие статические разделы | /кэш | Никто | Никто | Никто |
Дополнительное хранилище во время OTA (пространство возвращается после применения OTA) | 1,4 ГБ на /data | 0 | 3,8 ГБ 2 на /data | 2,1 ГБ 2 на /data |
Общий объем хранилища, необходимый для применения OTA | 5,9 ГБ 3 (супер и данные) | 9 ГБ (супер) | 8,3 ГБ 3 (супер и данные) | 6,6 ГБ 3 (супер и данные) |
1 Указывает предполагаемую компоновку на основе пиксельного отображения.
2 Предполагается, что новый образ системы имеет тот же размер, что и исходный.
3 Требуемое пространство временно и не подлежит перезагрузке.
Android 11 Virtual A/B
В версии 11 для Android Virtual A/B запись в динамический раздел осуществлялась с использованием формата Kernel COW. В конечном итоге этот формат был упразднён, поскольку Kernel COW не поддерживает сжатие.
Android 12 Virtual A/B
В Android 12 сжатие поддерживается в формате COW, специфичном для Android. Эта версия Virtual A/B требовала преобразования COW, специфичного для Android, в формат COW ядра. В конечном итоге это было заменено в Android 13, что устранило зависимость от формата COW ядра и dm-snapshot
.
Чтобы реализовать Virtual A/B или использовать возможности сжатых снимков, см. раздел Реализация Virtual A/B.