На этой странице описаны изменения, внесенные в AOSP для уменьшения количества ненужных изменений файлов между сборками. Разработчики устройств, поддерживающие собственные системы сборки, могут использовать эту информацию в качестве руководства для уменьшения размера своих беспроводных (OTA) обновлений.
Обновления Android по воздуху (OTA) иногда содержат измененные файлы, которые не соответствуют изменениям в коде. На самом деле это артефакты системы сборки. Это может произойти, когда один и тот же код, собранный в разное время, из разных каталогов или на разных машинах, создает большое количество измененных файлов. Такие лишние файлы увеличивают размер OTA-патча и затрудняют определение того, какой именно код изменился.
Для повышения прозрачности содержимого OTA-обновлений AOSP включает изменения в системе сборки, направленные на уменьшение размера OTA-патчей. Устранены ненужные изменения файлов между сборками, и OTA-обновления содержат только файлы, относящиеся к патчам. AOSP также включает инструмент сравнения сборок , который отфильтровывает общие изменения файлов, связанные со сборкой, для обеспечения более чистого сравнения файлов сборки, и инструмент сопоставления блоков , который помогает поддерживать согласованность распределения блоков.
Система сборки может создавать неоправданно большие патчи несколькими способами. Для решения этой проблемы в Android 8.0 и выше были реализованы новые функции, позволяющие уменьшить размер патча для каждого файла сравнения. Улучшения, которые уменьшили размер пакетов OTA-обновлений, включают в себя следующее:
- Использование ZSTD — универсального алгоритма сжатия без потерь для полных образов при обновлении устройств, отличных от A/B. ZSTD можно настроить для более высоких коэффициентов сжатия, увеличив уровень сжатия. Уровень сжатия устанавливается во время генерации OTA и может быть задан с помощью флага
--vabc_compression_param=zstd,$COMPRESSION_LEVEL - Увеличение размера окна сжатия, используемого во время обновления по воздуху (OTA). Максимальный размер окна сжатия можно установить, настроив параметр сборки в файле
.mkустройства. Эта переменная устанавливается какPRODUCT_VIRTUAL_AB_COMPRESSION_FACTOR := 262144 - Использование Puffin recompression, детерминированного инструмента для патчинга потоков deflate, который обрабатывает функции сжатия и сравнения для генерации A/B OTA-обновлений.
- Изменения коснулись использования инструмента генерации дельта-изменений, например, способа использования библиотеки
bsdiffдля сжатия патчей. В Android 9 и выше инструментbsdiffвыбирает алгоритм сжатия, который обеспечит наилучшие результаты сжатия для патча. - Улучшения в
update_engineпривели к снижению потребления памяти при применении патчей для обновлений устройств A/B.
В следующих разделах рассматриваются различные проблемы, влияющие на размеры обновлений OTA, способы их решения и примеры реализации в AOSP.
Порядок файлов
Проблема : файловые системы не гарантируют порядок файлов при запросе списка файлов в каталоге, хотя обычно он одинаков для одного и того же файла. Такие инструменты, как ls сортируют результаты по умолчанию, но функция подстановки, используемая командами find и make , не сортирует. Перед использованием этих инструментов необходимо отсортировать результаты.
Решение : При использовании таких инструментов, как find и make с функцией подстановки, отсортируйте вывод этих команд перед их применением. При использовании $(wildcard) или $(shell find) в файлах Android.mk также отсортируйте их. Некоторые инструменты, например Java, сортируют входные данные, поэтому перед сортировкой файлов убедитесь, что используемый вами инструмент еще этого не сделал.
Примеры: Многие ошибки были исправлены в основной системе сборки с помощью встроенного макроса all-*-files-under , который включает all-cpp-files-under (поскольку некоторые определения были разбросаны по другим make-файлам). Подробности см. в следующем:
- 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 теперь пути отладки являются относительными. Подробности см. в запросе на слияние: 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/+/android17-release/tools/ziptime/ ) сбрасывает обычные метки времени в заголовках ZIP-архивов. Подробности см. в файле README .
Инструмент signapk устанавливает метки времени для APK-файлов, которые могут различаться в зависимости от часового пояса сервера. Подробности см. в запросе на слияние https://android.googlesource.com/platform/build/+/6c41036bcf35fe39162b50d27533f0f3bfab3028 .
Инструмент signapk устанавливает метки времени для APK-файлов, которые могут различаться в зависимости от часового пояса сервера. Подробности см. в запросе на слияние 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 ГБ.
Однако вычисление достоверности на устройстве может занять много времени. В частности, код коррекции ошибок Forward Error-correction может работать долго. На устройствах Pixel это обычно занимает до 10 минут. На устройствах низкого класса это может занять больше времени. Если вы хотите отключить вычисление достоверности на устройстве, но при этом включить dm-verity, вы можете сделать это, передав флаг --disable_fec_computation инструменту ota_from_target_files при создании OTA-обновления. Этот флаг отключает вычисление достоверности на устройстве во время 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) приложения . В 64-битных системах файлы pre-dexopt (.odex) содержали неинициализированные отступы. Это было исправлено: https://android.googlesource.com/platform/art/+/34ed3afc41820c72a3c0ab9770be66b6668aa029 .
Воспользуйтесь инструментом сравнения сборок.
В случаях, когда невозможно исключить изменения файлов, связанные со сборкой, AOSP включает инструмент сравнения сборок target_files_diff.py , предназначенный для сравнения двух пакетов файлов. Этот инструмент выполняет рекурсивное сравнение двух сборок, исключая распространенные изменения файлов, связанные со сборкой, такие как
- Ожидаемые изменения в результатах сборки (например, из-за изменения номера сборки).
- Изменения внесены в связи с известными проблемами в текущей системе сборки.
Для использования инструмента сравнения версий выполните следующую команду:
target_files_diff.py dir1 dir2
dir1 и dir2 — это базовые каталоги, содержащие извлеченные целевые файлы для каждой сборки.
Обеспечьте согласованность распределения блоков.
Для заданного файла, несмотря на то, что его содержимое остается неизменным между двумя сборками, фактические блоки, содержащие данные, могут измениться. В результате, программе обновления приходится выполнять ненужные операции ввода-вывода для перемещения блоков при OTA-обновлении.
При виртуальном обновлении A/B по воздуху (OTA) ненужные операции ввода-вывода могут значительно увеличить объем памяти, необходимый для хранения снимка, созданного методом копирования при записи. При обновлении OTA без использования A/B перемещение блоков также увеличивает время обновления, поскольку из-за перемещения блоков увеличивается объем операций ввода-вывода.
Для решения этой проблемы в 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 за счет сокращения объема операций ввода-вывода. Для виртуальных обновлений A/B это значительно уменьшает объем места на диске, необходимого для применения OTA.
Избегайте обновления приложений.
Помимо минимизации различий в сборках, вы можете уменьшить размер OTA-обновлений, исключив обновления для приложений, которые получают обновления через магазины приложений. APK-файлы часто занимают значительную часть различных разделов на устройстве. Включение последних версий приложений, обновляемых через магазины приложений, в OTA-обновление может существенно повлиять на размер OTA-пакетов и принести мало пользы пользователю. К моменту получения OTA-пакета у пользователей уже может быть обновленное приложение или даже более новая версия, полученная непосредственно из магазинов приложений.