Часто задаваемые вопросы

Использовал ли Google A/B OTA на каких-либо устройствах?

Да. Маркетинговое название A/B-обновлений — «бесшовные обновления» . Телефоны Pixel и Pixel XL с октября 2016 года поставлялись с A/B, а все Chromebook используют одинаковую реализацию update_engine для A/B. Необходимая реализация кода платформы доступна в Android 7.1 и более поздних версиях.

Почему A/B OTA лучше?

A/B-обновления OTA обеспечивают более удобный пользовательский интерфейс при установке обновлений. Данные ежемесячных обновлений безопасности показывают, что эта функция уже доказала свою эффективность: по состоянию на май 2017 года 95% владельцев Pixel устанавливают последнее обновление безопасности через месяц по сравнению с 87% пользователей Nexus, при этом пользователи Pixel обновляются быстрее, чем пользователи Nexus. Сбои в блоках обновления во время OTA-обновления больше не приводят к тому, что устройство не загружается; до тех пор, пока новый образ системы не будет успешно загружен, Android сохраняет возможность отката к предыдущему рабочему образу системы.

Что такое system_other?

Приложения хранятся в файлах .apk, которые на самом деле являются архивами ZIP. Каждый файл .apk содержит внутри один или несколько файлов .dex, содержащих переносимый байт-код Dalvik. Файл .odex (оптимизированный .dex) существует отдельно от файла .apk и может содержать машинный код, специфичный для устройства. Если файл .odex доступен, Android может запускать приложения с предварительно скомпилированной скоростью, не дожидаясь компиляции кода каждый раз при запуске приложения. Файл .odex не является строго необходимым: Android может фактически запускать код .dex напрямую через интерпретацию или компиляцию Just-In-Time (JIT), но файл .odex обеспечивает наилучшее сочетание скорости запуска и скорости выполнения, если есть свободное место.

Пример: для файла installed-files.txt из Nexus 6P под управлением Android 7.1 с общим размером образа системы 2628 МБ (2755792836 байт) распределение наибольших вкладов в общий размер образа системы по типу файла выглядит следующим образом:

.odex 1391770312 байт 50,5%
.apk 846878259 байт 30,7%
.so (нативный код C/C++) 202162479 байт 7,3%
файлы .oat/изображения .art 163892188 байт 5,9%
Шрифты 38952361 байт 1,4%
данные локали icu 27468687 байт 0,9%

Эти показатели схожи и для других устройств, поэтому на устройствах Nexus/Pixel файлы .odex занимают примерно половину системного раздела. Это означало, что мы могли продолжать использовать ext4, но записывать файлы .odex в раздел B на заводе, а затем копировать их в /data при первой загрузке. Фактический объём хранилища, используемый ext4 A/B, идентичен объёму хранилища SquashFS A/B, поскольку при использовании SquashFS мы бы разместили предустановленные файлы .odex в system_a, а не в system_b.

Не означает ли копирование файлов .odex в /data, что сэкономленное в /system место будет потеряно в /data?

Не совсем. На Pixel большая часть места, занимаемого файлами .odex, предназначена для приложений, которые обычно находятся в каталоге /data . Эти приложения используют обновления Google Play, поэтому файлы .apk и .odex в образе системы не используются большую часть срока службы устройства. Такие файлы можно полностью исключить и заменить небольшими файлами .odex, привязанными к профилю, когда пользователь фактически использует каждое приложение (таким образом, не занимая место для приложений, которые пользователь не использует). Подробнее см. в докладе на конференции Google I/O 2016 «Эволюция искусства» .

Сравнение затруднено по нескольким основным причинам:

  • Приложения, обновленные через Google Play, всегда помещают свои файлы .odex в /data сразу после получения первого обновления.
  • Приложения, которые пользователь не запускает, вообще не нуждаются в файле .odex.
  • Компиляция на основе профилей создает файлы .odex меньшего размера, чем предварительная компиляция (поскольку первая оптимизирует только критически важный для производительности код).

Подробную информацию о возможностях настройки, доступных OEM-производителям, см. в разделе Настройка ART .

Разве в каталоге /data нет двух копий файлов .odex?

Всё немного сложнее... После записи образа новой системы новая версия dex2oat запускается на основе новых dex-файлов для генерации новых .odex-файлов. Это происходит, пока старая система ещё работает, поэтому и старый, и новый .odex-файлы находятся в каталоге /data одновременно.

Код в OtaDexoptService ( frameworks/base/+/android16-release/services/core/java/com/android/server/pm/OtaDexoptService.java ) вызывает getAvailableSpace перед оптимизацией каждого пакета, чтобы избежать переполнения /data . Обратите внимание, что available здесь по-прежнему консервативен: это объем оставшегося места до достижения обычного системного порога низкого пространства (измеряемого как в процентах, так и в байтах). Таким образом, если /data заполнен, не будет двух копий каждого файла .odex. В этом же коде также есть BULK_DELETE_THRESHOLD: если устройство приближается к заполнению доступного пространства (как только что описано), файлы .odex, принадлежащие неиспользуемым приложениям, удаляются. Это еще один случай без двух копий каждого файла .odex.

В худшем случае, когда /data полностью заполнен, обновление ожидает перезагрузки устройства в новую систему, после чего файлы .odex старой системы больше не понадобятся. Этим занимается PackageManager: ( frameworks/base/+/android16-release/services/core/java/com/android/server/pm/PackageManagerService.java#7215 ). После успешной загрузки новой системы installd ( frameworks/native/+/android16-release/cmds/installd/dexopt.cpp#2422 ) может удалить файлы .odex, использовавшиеся старой системой, вернув устройство в стабильное состояние с одной копией.

Итак, хотя возможно, что /data содержит две копии всех файлов .odex, (а) это временно и (б) происходит только при наличии достаточного свободного места в каталоге /data . За исключением периодов обновления, существует только одна копия. Кроме того, в рамках общих функций обеспечения надёжности ART никогда не заполнит /data файлами .odex (поскольку это также создаст проблемы в системе, отличной от A/B).

Разве все эти записи/копирования не приводят к износу вспышки?

Переписывается лишь небольшая часть флеш-памяти: полное обновление системы Pixel записывает около 2,3 ГБ. (Приложения также перекомпилируются, но это касается и не-A/B-приложений.) Традиционно блочные полноценные OTA-приложения записывали схожий объем данных, поэтому показатели износа флеш-памяти должны быть схожими.

Увеличивает ли время заводской прошивки перепрошивка двух системных разделов?

Нет. Pixel не увеличил размер образа системы (он просто разделил пространство на два раздела).

Не замедляет ли сохранение файлов .odex на диске B перезагрузку после сброса настроек к заводским?

Да. Если вы уже пользовались устройством, получили OTA-обновление и выполнили сброс настроек до заводских, первая перезагрузка будет медленнее, чем обычно (1 мин 40 с против 40 с на Pixel XL), поскольку файлы .odex будут утеряны из папки B после первого OTA-обновления и не смогут быть скопированы в /data . Вот в чём компромисс.

Сброс к заводским настройкам должен быть редкой операцией по сравнению с обычной загрузкой, поэтому затрачиваемое время не так важно. (Это не повлияет на пользователей или рецензентов, которые получают свои устройства с завода, поскольку в этом случае раздел B доступен.) Использование JIT-компилятора означает, что нам не нужно перекомпилировать всё , так что это не так плохо, как может показаться. Также можно пометить приложения как требующие предварительной компиляции, используя coreApp="true" в манифесте: ( frameworks/base/+/android16-release/packages/SystemUI/AndroidManifest.xml#23 ). В настоящее время это используется system_server , поскольку JIT-компиляция ему не разрешена по соображениям безопасности.

Разве хранение файлов .odex в каталоге /data, а не /system не замедляет перезагрузку после OTA?

Нет. Как объяснялось выше, новый dex2oat запускается во время работы образа старой системы для создания файлов, необходимых для новой системы. Обновление не считается доступным до завершения этой работы.

Можем ли (нужно ли) мы поставлять A/B-устройство объёмом 32 ГБ? 16 ГБ? 8 ГБ?

32 ГиБ работают хорошо, как и было доказано на Pixel, а 320 МБ из 16 ГиБ означает сокращение на 2%. Аналогично, 320 МБ из 8 ГиБ означает сокращение на 4%. Очевидно, что A/B не рекомендуется использовать на устройствах с 4 ГиБ, поскольку 320 МБ занимают почти 10% от общего доступного пространства.

Требуются ли для AVB2.0 A/B OTA?

Нет. Для Android Verified Boot всегда требовались блочные обновления, но не обязательно обновления A/B.

Требуется ли AVB2.0 для A/B OTA?

Нет.

Нарушают ли A/B OTA защиту от отката AVB2.0?

Нет. Здесь возникает некоторая путаница: если системе A/B не удаётся загрузить новый образ системы, она (после определённого загрузчиком количества попыток) автоматически вернётся к «предыдущему» образу системы. Однако ключевой момент заключается в том, что «предыдущий» в смысле A/B — это фактически «текущий» образ системы. Как только устройство успешно загружает новый образ, срабатывает защита от отката, которая гарантирует невозможность отката. Но пока новый образ не будет успешно загружен, защита от отката не считает его текущим образом системы.

Если вы устанавливаете обновление во время работы системы, разве это не медленно?

При обновлениях, отличных от A/B, цель состоит в том, чтобы установить обновление как можно быстрее, поскольку пользователь ждёт и не может пользоваться своим устройством, пока обновление применяется. При обновлениях A/B всё наоборот: поскольку пользователь всё ещё использует своё устройство, целью является минимальное воздействие на него, поэтому обновление намеренно замедлено. Благодаря логике клиента обновления системы Java (которым для Google является GmsCore, основной пакет, предоставляемый GMS), Android также пытается выбрать время, когда пользователи вообще не используют свои устройства. Платформа поддерживает приостановку/возобновление обновления, и клиент может использовать это, чтобы приостановить обновление, если пользователь начинает использовать устройство, и возобновить его, когда устройство снова становится неактивным.

Процесс выполнения OTA-загрузки состоит из двух этапов, которые в пользовательском интерфейсе наглядно отображаются как «Шаг 1 из 2» и «Шаг 2 из 2» под индикатором выполнения. Шаг 1 соответствует записи блоков данных, а шаг 2 — предварительной компиляции dex-файлов. Эти два этапа существенно различаются по влиянию на производительность. Первый этап — это простой ввод-вывод. Он требует небольших ресурсов (ОЗУ, ЦП, ввод-вывод), поскольку просто медленно копирует блоки.

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

Этот процесс похож на тот, когда Google Play устанавливает обновление приложения в фоновом режиме, прежде чем отобразить уведомление об обновлении 5 приложений , как это делалось на протяжении многих лет.

А что, если пользователь действительно ждет обновления?

Текущая реализация GmsCore не различает фоновые обновления и обновления, инициированные пользователем, но, возможно, в будущем это будет реализовано. Если пользователь явно запросил установку обновления или наблюдает за ходом обновления, мы отдадим приоритет обновлению, предполагая, что он активно ожидает его завершения.

Что произойдет, если не удастся применить обновление?

При не-A/B-обновлениях, если обновление не применялось, пользователь обычно оставался с неработоспособным устройством. Единственным исключением были случаи, когда сбой происходил ещё до запуска приложения (например, из-за того, что пакет не прошёл проверку). При A/B-обновлениях сбой в применении обновления не влияет на текущую работающую систему. Обновление можно просто повторить позже.