На этой странице описываются изменения, добавленные в AOSP для сокращения ненужных изменений файлов между сборками. Разработчики устройств, которые поддерживают собственные системы сборки, могут использовать эту информацию в качестве руководства по уменьшению размера своих обновлений по воздуху (OTA).
Обновления Android OTA иногда содержат измененные файлы, которые не соответствуют изменениям кода. На самом деле это артефакты системы сборки. Это может произойти, когда один и тот же код, собранный в разное время, из разных каталогов или на разных машинах, создает большое количество измененных файлов. Такие избыточные файлы увеличивают размер исправления OTA и затрудняют определение того, какой код изменился.
Чтобы сделать содержимое OTA более прозрачным, AOSP включает изменения системы сборки, разработанные для уменьшения размера исправлений OTA. Ненужные изменения файлов между сборками были устранены, и только файлы, связанные с исправлениями, содержатся в обновлениях OTA. AOSP также включает инструмент сравнения сборок , который отфильтровывает общие изменения файлов, связанных со сборкой, чтобы обеспечить более чистый файл сравнения сборок, и инструмент сопоставления блоков , который помогает вам поддерживать единообразное распределение блоков.
Система сборки может создавать ненужно большие патчи несколькими способами. Чтобы смягчить это, в Android 8.0 и выше были реализованы новые функции, позволяющие уменьшить размер патча для каждого файла diff. Улучшения, которые уменьшили размеры пакетов OTA-обновлений, включают следующее:
- Использование ZSTD , универсального алгоритма сжатия без потерь для полных изображений при обновлениях устройств не-A/B. ZSTD можно настроить для более высоких коэффициентов сжатия, увеличив уровень сжатия. Уровень сжатия устанавливается во время генерации OTA и может быть установлен путем передачи флага
--vabc_compression_param=zstd,$COMPRESSION_LEVEL
- Увеличение размера окна сжатия, используемого во время OTA. Максимальный размер окна сжатия можно задать, настроив параметр сборки в файле
.mk
устройства. Эта переменная задается какPRODUCT_VIRTUAL_AB_COMPRESSION_FACTOR := 262144
- Использование рекомпрессии Puffin , детерминированного инструмента исправления для потоков Deflate, который обрабатывает функции сжатия и сравнения для генерации обновлений A/B OTA.
- Изменения в использовании инструмента дельта-генерации, например, как библиотека
bsdiff
используется для сжатия патчей. В Android 9 и выше инструментbsdiff
выбирает алгоритм сжатия, который даст наилучшие результаты сжатия для патча. - Улучшения в
update_engine
привели к уменьшению потребления памяти при применении исправлений для обновлений устройств A/B.
В следующих разделах обсуждаются различные проблемы, влияющие на размеры OTA-обновлений, их решения и примеры реализации в AOSP.
Порядок файлов
Проблема : Файловые системы не гарантируют порядок файлов при запросе списка файлов в каталоге, хотя он обычно одинаков для одного и того же извлечения. Такие инструменты, как ls
сортируют результаты по умолчанию, но функция подстановочных знаков, используемая такими командами, как find
и make
, не сортирует. Перед использованием этих инструментов необходимо отсортировать выходные данные.
Решение : При использовании таких инструментов, как find
и make
с функцией wildcard, отсортируйте вывод этих команд перед их использованием. При использовании $(wildcard)
или $(shell find)
в файлах Android.mk
также отсортируйте их. Некоторые инструменты, такие как Java, сортируют входные данные, поэтому перед сортировкой файлов убедитесь, что используемый вами инструмент еще не сделал этого.
Примеры: Многие экземпляры были исправлены в основной системе сборки с использованием встроенного макроса all-*-files-under
, который включает all-cpp-files-under
(так как несколько определений были разбросаны по другим файлам makefile). Подробности см. в следующем:
- https://android.googlesource.com/platform/build/+/4d66adfd0e6d599d8502007e4ea9aaf82e95569f
- https://android.googlesource.com/platform/build/+/379f9f9cec4fe1c66b6d60a6c19fecb81b9eb410
- https://android.googlesource.com/platform/build/+/7c3e3f8314eec2c053012dd97d2ae649ebeb5653
- https://android.googlesource.com/platform/build/+/5c64b4e81c1331cab56d8a8c201f26bb263b630c
Каталог сборки
Проблема: Изменение каталога, в котором все собрано, может привести к тому, что двоичные файлы будут отличаться. Большинство путей в сборке 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++ и Встроенные временные метки в архивах .
__ДАТА__/__ВРЕМЯ__/__МЕТКА__ в C/C++
Эти макросы всегда производят разные результаты для разных сборок, поэтому не используйте их. Вот несколько вариантов устранения этих макросов:
- Удалите их. Пример см. на https://android.googlesource.com/platform/system/core/+/30622bbb209db187f6851e4cf0cdaa147c2fca9f .
- Чтобы однозначно идентифицировать работающий двоичный файл, считайте идентификатор сборки из заголовка ELF.
- Чтобы узнать, когда была собрана ОС, прочитайте
ro.build.date
(это работает для всего, кроме инкрементальных сборок, которые могут не обновлять эту дату). Для примера обратитесь к https://android.googlesource.com/platform/external/libchrome/+/8b7977eccc94f6b3a3896cd13b4aeacbfa1e0f84 .
Встроенные временные метки в архивах (zip, jar)
Android 7.0 исправил проблему встроенных временных меток в zip-архивах, добавив -X
ко всем использованиям команды zip
. Это удалило UID/GID строителя и расширенную временную метку Unix из zip-файла.
Новый инструмент ziptime
(расположен в /platform/build/+/android16-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 все равно был бы другим.
Решение: Удалите номер сборки из строки версии APK.
Примеры:
- https://android.googlesource.com/platform/packages/apps/Camera2/+/5e0f4cf699a4c7c95e2c38ae3babe6f20c258d27
- https://android.googlesource.com/platform/build/+/d75d893da8f97a5c7781142aaa7a16cf1dbb669c
Включить вычисление верификации на устройстве
Если на вашем устройстве включен dm-verity , то инструменты OTA автоматически подхватывают вашу конфигурацию verity и включают вычисление verity на устройстве. Это позволяет вычислять блоки verity на устройствах Android, а не хранить их в виде сырых байтов в вашем пакете OTA. Блоки verity могут использовать примерно 16 МБ для раздела размером 2 ГБ.
Однако вычисление verity на устройстве может занять много времени. В частности, код Forward Error-correction может занять много времени. На пиксельных устройствах это обычно занимает до 10 минут. На бюджетных устройствах это может занять больше времени. Если вы хотите отключить вычисление verity на устройстве, но при этом включить dm-verity, вы можете сделать это, передав --disable_fec_computation
инструменту ota_from_target_files
при создании обновления OTA. Этот флаг отключает вычисление verity на устройстве во время обновлений OTA. Он сокращает время установки OTA, но увеличивает размер пакета OTA. Если на вашем устройстве не включен dm-verity, передача этого флага не имеет никакого эффекта.
Последовательные инструменты сборки
Проблема: Инструменты, генерирующие установленные файлы, должны быть единообразными (данные входные данные всегда должны давать одинаковый результат).
Решения/Примеры: Изменения потребовались в следующих инструментах сборки:
- Создатель файла NOTICE . Создатель файла NOTICE был изменен для создания воспроизводимых коллекций NOTICE. См. CL: https://android.googlesource.com/platform/build/+/8ae4984c2c8009e7a08e2a76b1762c2837ad4f64 .
- Java Android Compiler Kit (Jack) . Набор инструментов Jack требовал обновления для обработки случайных изменений в порядке сгенерированных конструкторов. В набор инструментов были добавлены детерминированные методы доступа для конструкторов: https://android.googlesource.com/toolchain/jack/+/056a5425b3ef57935206c19ecb198a89221ca64b .
- Компилятор ART AOT (dex2oat) . Двоичный файл компилятора ART получил обновление, которое добавило возможность создания детерминированного образа: https://android.googlesource.com/platform/art/+/ace0dc1dd5480ad458e622085e51583653853fb9 .
- Файл libpac.so (V8) . Каждая сборка создает другой файл
/system/lib/libpac.so
, поскольку снимок V8 меняется для каждой сборки. Решением было удалить снимок: https://android.googlesource.com/platform/external/v8/+/e537f38c36600fd0f3026adba6b3f4cbcee1fb29 . - Файлы приложений pre-dexopt (.odex) . Файлы pre-dexopt (.odex) содержали неинициализированный padding на 64-битных системах. Это было исправлено: https://android.googlesource.com/platform/art/+/34ed3afc41820c72a3c0ab9770be66b6668aa029 .
Используйте инструмент сравнения сборок
Для случаев, когда невозможно исключить изменения файлов, связанные со сборкой, AOSP включает инструмент сравнения сборок target_files_diff.py
для использования при сравнении двух пакетов файлов. Этот инструмент выполняет рекурсивное сравнение двух сборок, исключая общие изменения файлов, связанные со сборкой, такие как
- Ожидаемые изменения в результатах сборки (например, из-за изменения номера сборки).
- Изменения вызваны известными проблемами в текущей системе сборки.
Чтобы использовать инструмент сравнения сборок, выполните следующую команду:
target_files_diff.py dir1 dir2
dir1
и dir2
— это базовые каталоги, содержащие извлеченные целевые файлы для каждой сборки.
Поддерживайте единообразие распределения блоков
Для данного файла, хотя его содержимое остается неизменным между двумя сборками, фактические блоки, содержащие данные, могли измениться. В результате, обновитель должен выполнять ненужные операции ввода-вывода, чтобы перемещать блоки для обновления OTA.
В виртуальном обновлении A/B OTA ненужные операции ввода-вывода могут значительно увеличить объем хранилища, необходимый для хранения моментального снимка копирования при записи. В не-A/B OTA-обновлении перемещение блоков для обновления OTA увеличивает время обновления, поскольку из-за перемещения блоков происходит больше операций ввода-вывода.
Чтобы решить эту проблему, в Android 7.0 Google расширила инструмент make_ext4fs
для поддержания согласованного распределения блоков между сборками. Инструмент make_ext4fs
принимает необязательный флаг -d base_fs
, который пытается выделить файлы в одни и те же блоки при создании образа ext4
. Вы можете извлечь файлы сопоставления блоков (например, файлы сопоставления base_fs
) из zip-файла целевых файлов предыдущей сборки. Для каждого раздела ext4
есть файл .map
в каталоге IMAGES
(например, 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
Хотя это не помогает уменьшить общий размер пакета OTA, это улучшает производительность обновления OTA за счет сокращения количества операций ввода-вывода. Для обновлений Virtual A/B это радикально уменьшает объем дискового пространства, необходимого для применения OTA.
Избегайте обновления приложений
Помимо минимизации различий в сборках, вы можете уменьшить размеры обновлений OTA, исключив обновления для приложений, которые получают обновления через магазины приложений. APK часто составляют значительную часть различных разделов на устройстве. Включение последних версий приложений, которые обновляются магазинами приложений, в обновление OTA может оказать большое влияние на размер пакетов OTA и предоставить мало преимуществ для пользователей. К тому времени, как пользователи получат пакет OTA, они уже могут иметь обновленное приложение или даже более новую версию, полученную напрямую из магазинов приложений.