Как уменьшить размер OTA-обновления

На этой странице описаны изменения, добавленные в AOSP, чтобы уменьшить количество ненужных изменений файлов между сборками. Производители устройств, которые поддерживают собственные системы сборки, могут использовать эту информацию в качестве руководства по уменьшению размера обновлений, передаваемых по беспроводной сети.

Беспроводные обновления Android иногда содержат измененные файлы, которые не соответствуют изменениям кода. На самом деле это артефакты системы сборки. Это может произойти, если один и тот же код, созданный в разное время, в разных каталогах или на разных компьютерах, приводит к большому количеству измененных файлов. Из-за таких лишних файлов увеличивается размер OTA-патча и становится сложно определить, какой код был изменен.

Чтобы сделать содержимое OTA более прозрачным, в AOSP внесены изменения в систему сборки, которые позволяют уменьшить размер OTA-патчей. Устранены ненужные изменения файлов между сборками, и беспроводные обновления содержат только файлы, связанные с исправлениями. В AOSP также есть инструмент для сравнения сборок, который отфильтровывает распространенные изменения файлов, связанные со сборкой, чтобы обеспечить более точное сравнение файлов сборки, и инструмент сопоставления блоков, который помогает поддерживать согласованность распределения блоков.

Система сборки может создавать слишком большие исправления несколькими способами. Чтобы решить эту проблему, в Android 8.0 и более поздних версиях были реализованы новые функции, позволяющие уменьшить размер исправлений для каждого различия в файлах. Размер пакетов беспроводных обновлений был уменьшен благодаря следующим улучшениям:

  • Использование ZSTD, алгоритма сжатия без потерь общего назначения, для полных образов при обновлении устройств без A/B-тестирования. ZSTD можно настроить для более высоких коэффициентов сжатия, увеличив уровень сжатия. Уровень сжатия задается при создании OTA-обновления с помощью флага --vabc_compression_param=zstd,$COMPRESSION_LEVEL.
  • Увеличение размера окна сжатия, используемого при обновлении по беспроводной сети. Максимальный размер окна сжатия можно задать, изменив параметр сборки в файле .mk устройства. Эта переменная задается как PRODUCT_VIRTUAL_AB_COMPRESSION_FACTOR := 262144.
  • Использование Puffin для повторного сжатия – детерминированного инструмента для исправления потоков deflate, который обрабатывает функции сжатия и разницы для создания беспроводных обновлений с помощью A/B-тестирования.
  • Изменения в использовании инструмента для создания дельт, например в том, как библиотека bsdiff используется для сжатия исправлений. В Android 9 и более поздних версий инструмент bsdiff выбирает алгоритм сжатия, который обеспечит наилучшие результаты для исправления.
  • Улучшения в update_engine привели к тому, что при применении исправлений для обновлений устройств A/B потребляется меньше памяти.

В следующих разделах рассматриваются различные проблемы, влияющие на размер беспроводных обновлений, их решения и примеры реализации в AOSP.

Порядок файлов

Проблема. Файловые системы не гарантируют порядок файлов при запросе списка файлов в каталоге, хотя обычно он одинаковый для одной и той же проверки. Такие инструменты, как ls, по умолчанию сортируют результаты, но функция подстановки, используемая командами, например find и make, не сортирует. Прежде чем использовать эти инструменты, необходимо отсортировать результаты.

Решение. При использовании таких инструментов, как find и make, с функцией подстановочного знака отсортируйте выходные данные этих команд, прежде чем использовать их. При использовании $(wildcard) или $(shell find) в файлах Android.mk также отсортируйте их. Некоторые инструменты, например Java, сортируют входные данные, поэтому перед сортировкой файлов убедитесь, что используемый вами инструмент ещё не сделал этого.

Примеры. Многие случаи были исправлены в основной системе сборки с помощью встроенного макроса all-*-files-under, который включает all-cpp-files-under (поскольку некоторые определения были распределены по другим файлам makefile). Дополнительную информацию можно найти в следующих статьях:

Создание каталога

Проблема. Изменение каталога, в котором создаются объекты, может привести к различиям в двоичных файлах. Большинство путей в сборке Android являются относительными, поэтому __FILE__ в C/C++ не является проблемой. Однако отладочные символы по умолчанию кодируют полный путь, а .note.gnu.build-id генерируется путем хеширования двоичного файла до удаления символов, поэтому он изменится, если изменятся отладочные символы.

Решение. Теперь в AOSP пути отладки относительные. Подробную информацию можно найти на странице CL: https://android.googlesource.com/platform/build/+/6a66a887baadc9eb3d0d60e26f748b8453e27a02.

Временные метки

Проблема. В выходных данных сборки временные метки приводят к ненужным изменениям в файле. Вероятнее всего, это произойдет в следующих регионах:

  • __DATE__/__TIME__/__TIMESTAMP__ макросы в коде на C или C++.
  • Временные метки, встроенные в архивы на основе ZIP.

Решения и примеры. Чтобы удалить временные метки из выходных данных сборки, следуйте инструкциям в разделах __DATE__/__TIME__/__TIMESTAMP__ в C/C++ и Встроенные временные метки в архивах.

__DATE__/__TIME__/__TIMESTAMP__ в C/C++

Эти макросы всегда дают разные результаты для разных сборок, поэтому не используйте их. Вот несколько способов удалить макросы:

Встроенные временные метки в архивах (ZIP, JAR)

В Android 7.0 проблема со встроенными временными метками в ZIP-архивах была решена путем добавления -X во все случаи использования команды zip. Это удалило UID/GID сборщика и расширенную временную метку Unix из ZIP-файла.

Новый инструмент ziptime (находится в /platform/build/+/android17-release/tools/ziptime/) сбрасывает обычные временные метки в заголовках ZIP-файлов. Подробнее о файле README…

Инструмент signapk устанавливает временные метки для APK-файлов, которые могут различаться в зависимости от часового пояса сервера. Подробнее: CL https://android.googlesource.com/platform/build/+/6c41036bcf35fe39162b50d27533f0f3bfab3028.

Инструмент signapk устанавливает временные метки для APK-файлов, которые могут различаться в зависимости от часового пояса сервера. Подробнее: CL https://android.googlesource.com/platform/build/+/6c41036bcf35fe39162b50d27533f0f3bfab3028.

Строки версий

Проблема. В строках версии APK часто добавлялся символ BUILD_NUMBER к жестко заданным версиям. Даже если в APK ничего не изменилось, кроме подписи, он будет другим.

Решение. Удалите номер сборки из строки версии APK.

Примеры

Включить вычисление verity на устройстве

Если на устройстве включена функция dm-verity, инструменты OTA автоматически выбирают конфигурацию verity и включают вычисление verity на устройстве. Это позволяет вычислять блоки verity на устройствах Android, а не хранить их в виде необработанных байтов в пакете OTA. Блоки Verity могут использовать около 16 МБ для раздела объемом 2 ГБ.

Однако проверка целостности на устройстве может занять много времени. В частности, код исправления ошибок может обрабатываться долго. На устройствах Pixel это обычно занимает до 10 минут. На устройствах более низкого класса это может занять больше времени. Если вы хотите отключить вычисление целостности на устройстве, но оставить dm-verity включенным, передайте --disable_fec_computation инструменту ota_from_target_files при создании беспроводного обновления. Этот флаг отключает проверку целостности на устройстве во время беспроводных обновлений. Это сокращает время установки OTA, но увеличивает размер пакета OTA. Если на вашем устройстве не включена функция dm-verity, этот флаг не будет иметь никакого эффекта.

Единообразные инструменты сборки

Проблема. Инструменты, создающие установленные файлы, должны работать согласованно (один и тот же входной файл всегда должен приводить к одному и тому же выходному файлу).

Решения и примеры. В следующих инструментах сборки потребовались изменения:

Как использовать инструмент сравнения сборок

Если устранить изменения файлов, связанные со сборкой, невозможно, в AOSP есть инструмент сравнения сборок target_files_diff.py, который позволяет сравнивать два пакета файлов. Этот инструмент выполняет рекурсивное сравнение двух сборок, исключая изменения файлов, связанные со сборкой, например

  • Ожидаемые изменения в выходных данных сборки (например, из-за изменения номера сборки).
  • Изменения, связанные с известными проблемами в текущей системе сборки.

Чтобы использовать инструмент сравнения сборок, выполните следующую команду:

target_files_diff.py dir1 dir2

dir1 и dir2 – это базовые каталоги, содержащие извлеченные целевые файлы для каждой сборки.

Сохраняйте постоянное распределение блоков

Содержимое файла может оставаться неизменным между двумя сборками, но блоки, в которых хранятся данные, могут быть разными. В результате программе обновления приходится выполнять ненужные операции I/O, чтобы перемещать блоки при беспроводном обновлении.

При виртуальном обновлении A/B OTA ненужные операции ввода-вывода могут значительно увеличить объем хранилища, необходимый для хранения снимка копирования при записи. При беспроводном обновлении без использования разделов A/B перемещение блоков занимает время, поскольку при этом выполняется больше операций I/O.

Чтобы решить эту проблему, в Android 7.0 Google расширила возможности инструмента make_ext4fs, который обеспечивает согласованное распределение блоков в разных сборках. Инструмент make_ext4fs принимает необязательный флаг -d base_fs, который пытается распределить файлы по одним и тем же блокам при создании изображения ext4. Вы можете извлечь файлы сопоставления блоков (например, файлы сопоставления base_fs) из ZIP-файла целевых файлов предыдущей сборки. Для каждого раздела ext4 в каталоге IMAGES есть файл .map (например, IMAGES/system.map соответствует разделу system). Затем эти файлы base_fs можно зарегистрировать и указать с помощью PRODUCT_<partition>_BASE_FS_PATH, как в этом примере:

  PRODUCT_SYSTEM_BASE_FS_PATH := path/to/base_fs_files/base_system.map
  PRODUCT_SYSTEM_EXT_BASE_FS_PATH := path/to/base_fs_files/base_system_ext.map
  PRODUCT_VENDOR_BASE_FS_PATH := path/to/base_fs_files/base_vendor.map
  PRODUCT_PRODUCT_BASE_FS_PATH := path/to/base_fs_files/base_product.map
  PRODUCT_ODM_BASE_FS_PATH := path/to/base_fs_files/base_odm.map

Это не уменьшает общий размер пакета беспроводного обновления, но повышает производительность беспроводного обновления за счет сокращения объема I/O. Для обновлений Virtual A/B это значительно сокращает объем хранилища, необходимый для применения OTA.

Не обновляйте приложения

Чтобы уменьшить размер беспроводных обновлений, можно не включать в них обновления для приложений, которые обновляются через магазины приложений. Файлы APK часто занимают значительную часть различных разделов на устройстве. Если в беспроводное обновление включить последние версии приложений, которые обновляются через магазины приложений, это может значительно увеличить размер пакета обновления и не принести пользователям особой пользы. К моменту получения пакета OTA у пользователей может быть уже установлена обновленная версия приложения или даже более новая, полученная непосредственно из магазина приложений.