Использовала ли Google A/B-тестирование OTA-обновлений на каких-либо устройствах?
Да. Маркетинговое название A/B-обновлений — бесшовные обновления . Телефоны Pixel и Pixel XL, выпущенные с октября 2016 года, поставлялись с A/B-обновлением, и все Chromebook используют одну и ту же реализацию A/B update_engine . Необходимая реализация кода платформы доступна в 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% |
| данные о местоположении отделения интенсивной терапии | 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 меньшего размера, чем компиляция перед выполнением кода (поскольку первая оптимизирует только критически важный с точки зрения производительности код).
Подробную информацию о доступных производителям оборудования параметрах тюнинга см. в разделе «Настройка ART» .
Разве в папке /data нет двух копий файлов .odex?
Всё немного сложнее... После записи нового образа системы новая версия dex2oat запускается для обработки новых файлов .dex с целью генерации новых файлов .odex. Это происходит, пока старая система ещё работает, поэтому старые и новые файлы .odex находятся в каталоге /data одновременно.
В коде OtaDexoptService ( frameworks/base/+/android17-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/+/android17-release/services/core/java/com/android/server/pm/PackageManagerService.java#7215 ). После успешной загрузки новой системы installd ( frameworks/native/+/android17-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/+/android17-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 по воздуху?
Нет. Для функции 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-обновлений сбой применения обновления не влияет на текущую работающую систему. Обновление можно просто повторить позже.