На этой странице описаны изменения, добавленные в 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).
Дополнительную информацию можно найти в следующих статьях:
- 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++ и Встроенные временные метки в архивах.
__DATE__/__TIME__/__TIMESTAMP__ в 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-файлов, которые могут различаться в зависимости от часового пояса сервера. Подробнее: CL
https://android.googlesource.com/platform/build/+/6c41036bcf35fe39162b50d27533f0f3bfab3028.
Инструмент signapk устанавливает временные метки для APK-файлов, которые могут различаться в зависимости от часового пояса сервера. Подробнее: CL https://android.googlesource.com/platform/build/+/6c41036bcf35fe39162b50d27533f0f3bfab3028.
Строки версий
Проблема. В строках версии APK часто добавлялся символ BUILD_NUMBER к жестко заданным версиям. Даже если в APK ничего не изменилось, кроме подписи, он будет другим.
Решение. Удалите номер сборки из строки версии APK.
Примеры
- https://android.googlesource.com/platform/packages/apps/Camera2/+/5e0f4cf699a4c7c95e2c38ae3babe6f20c258d27
- https://android.googlesource.com/platform/build/+/d75d893da8f97a5c7781142aaa7a16cf1dbb669c
Включить вычисление 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, этот флаг не будет иметь никакого эффекта.
Единообразные инструменты сборки
Проблема. Инструменты, создающие установленные файлы, должны работать согласованно (один и тот же входной файл всегда должен приводить к одному и тому же выходному файлу).
Решения и примеры. В следующих инструментах сборки потребовались изменения:
- Создатель файла 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. - Файлы предварительной оптимизации приложений (.odex). Файлы pre-dexopt (.odex) содержали неинициализированные отступы в 64-разрядных системах. Исправление: https://android.googlesource.com/platform/art/+/34ed3afc41820c72a3c0ab9770be66b6668aa029.
Как использовать инструмент сравнения сборок
Если устранить изменения файлов, связанные со сборкой, невозможно, в 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 у пользователей может быть уже установлена обновленная версия приложения или даже более новая, полученная непосредственно из магазина приложений.