Эта статья рассказывает о ряде технологий, которые были интегрированы в Android в последние несколько лет и приблизили решение проблемы фрагментации, отсутствия обновлений и существенно упростили создание кастомных прошивок.
A/B-разметка
Большой проблемой с обновлениями является отказ пользователей. Как показывает практика, многие владельцы смартфонов не хотят обновлять свои устройства, потому что: а) это отнимает время, в течение которого смартфон будет недоступен для использования; б) после обновления смартфон может работать некорректно или не включится вообще.
В свое время разработчики Chrome OS также столкнулись с этой проблемой и создали надежную и незаметную пользователю систему бесшовного обновления (Seamless updates). Суть ее состоит в том, что вместо одного системного раздела, поверх которого накладывались бы обновления системы, Chrome OS использует два идентичных системных раздела, каждый из которых содержит свою копию операционной системы.
Обновление в Chrome OS происходит следующим образом: когда ОС обнаруживает наличие обновления, она скачивает его в фоне, устанавливает на второй (неактивный) системный раздел и помечает этот раздел как активный. После перезагрузки (не обязательно сразу после обновления) ОС запускается уже с этого раздела.
РЕКОМЕНДУЕМ:
Инструменты для анализа Android-приложений на Android
Благодаря такой схеме пользователь даже не подозревает, что система обновилась, он просто попадает в обновленную ОС после перезагрузки или включения ноутбука. При этом Chrome OS способна гарантировать, что после обновления пользователь не получит кирпич: если во время загрузки с обновленного раздела произойдет сбой — система пометит текущий раздел флагом unbootable, сделает активным «старый» системный раздел и загрузит заведомо рабочую версию ОС.
Начиная с седьмой версии Android также поддерживает бесшовные обновления и так называемую A/B-разметку разделов. Однако, так как системных разделов в устройствах с Android намного больше, чем в хромбуках, сама раскладка разделов получается более запутанной. Вот только часть разделов, которые пришлось дублировать:
- boot — содержит ядро и RAM-диск, на устройствах с A/B-разметкой также консоль восстановления (recovery);
- system — содержит Android, системные библиотеки, системные приложения, стандартные рингтоны, обои и так далее;
- vendor — драйверы и все необходимые прослойки для работы с железом (Project Treble);
- userdata — настройки, приложения и данные пользователя;
- radio — прошивка радиомодуля (поддержка сотовых сетей);
- vbmeta — раздел Android Verified Boot 2.0 (механизм доверенной загрузки), содержащий контрольные суммы компонентов системы.
Всего дублированных разделов может быть несколько десятков. Например, на OnePlus 6 с A/B-разметкой общее количество разделов — 72 и несколько десятков из них используются только загрузчиком.
От других разделов, наоборот, стало возможным отказаться. Устройства с A/B-разметкой не включают в себя отдельный раздел recovery (консоль восстановления, нужна для установки обновления и сброса до заводских настроек) и раздел cache, который использовался для хранения файлов обновлений (теперь обновление скачивается напрямую в неактивный раздел).
A/B-разметка также позволила вдвое сократить размер раздела system, что вкупе с удалением разделов recovery и cache сделало переход на новую схему разметки менее болезненным. Например, на смартфонах Pixel потеря пространства составила всего несколько сотен мегабайт.
Раздел | Размер A/B | Размер A-only |
---|---|---|
Bootloader | 50 Мбайт × 2 | 50 Мбайт |
Boot | 32 Мбайт × 2 | 32 Мбайт |
Recovery | 0 | 32 Мбайт |
Cache | 0 | 100 Мбайт |
Radio | 70 Мбайт × 2 | 70 Мбайт |
Vendor | 300 Мбайт × 2 | 300 Мбайт |
System | 2048 Мбайт × 2 | 4096 Мбайт |
Всего | 5000 Мбайт | 4680 Мбайт |
Еще одно достоинство A/B-разметки — отсутствие экрана «Android is upgrading…» после обновления. Система просто загружается как обычно. Также A/B-разметка упрощает тестирование кастомных прошивок: кастом можно поставить второй системой и откатиться на первую, если что-то пойдет не так.
В целом одни плюсы и никаких минусов. Проблема только в том, что A/B-разметка до сих пор остается опциональной, а перешли на нее далеко не все производители смартфонов. Даже Samsung — крупнейший производитель устройств на Android — до сих пор использует старую разметку. И связано это, скорее всего, с нежеланием тратить средства и время на перепрофилирование уже работающей и отлаженной системы обновления.
Проверить, поддерживает ли твой смартфон A/B-разметку, можно с помощью все того же приложения Treble Check из предыдущего раздела или прочитав переменную ro.build.ab_update с помощью ADB:
1 |
$ adb shell getprop ro.build.ab_update |
Шпаргалка по управлению A/B-разделами с помощью fastboot
Узнать, какой слот (группа разделов) теперь активен:
1 |
$ fastboot getvar all | grep “current-slot” |
Сделать неактивный в данный момент слот активным:
1 |
$ fastboot set_active other |
Сделать активным указанный слот (a или b):
1 |
$ fastboot set_active СЛОТ |
Прошить указанный раздел:
1 2 |
$ fastboot flash имя_раздела_a partition.img $ fastboot flash имя_раздела_b partition.img |
Динамические обновления
Project Treble открыл дорогу для еще одной весьма полезной функции — Dynamic System Updates (DSU). Этот механизм появился в Android 10 специально для пользователей и разработчиков, которые хотят протестировать новую (бета) версию Android, но не желают жертвовать для этого установленной системой и своими данными.
DSU базируется на технологии Dynamic Partitions, которая должна быть реализована во всех устройствах, выпущенных на рынок с Android 10. При использовании Dynamic Partitions в смартфоне, по сути, есть только один суперраздел, в котором система может создавать динамические разделы, удалять их и менять размеры (такое возможно благодаря модулю ядра Linux dm-linear).
Все системные разделы в таком смартфоне тоже динамические (кроме загрузочных разделов: boot, dtbo и vbmeta). Поэтому при необходимости система может сдвинуть их, чтобы освободить место для дополнительных разделов. Именно так делает функция DSU. Она уменьшает размер системных разделов, создает в освободившемся пространстве еще один набор системных разделов и устанавливает в него образ GSI. Далее смартфон перезагружается в эту свежеустановленную систему, а следующая перезагрузка выполняется вновь со стандартных разделов.
Чтобы установить образ GSI, используя DSU, для начала необходимо разблокировать загрузчик смартфона. Затем активировать DSU с помощью ADB:
1 |
$ adb shell setprop persist.sys.fflag.override.settings_dynamic_system true |
Затем нужно скачать сам образ, распаковать и закинуть его на внутреннюю карту памяти смартфона:
1 2 |
$ gzip -c system_raw.img > system_raw.gz $ adb push system_raw.gz /storage/emulated/0/Download/ |
Затем можно запустить установку:
1 2 3 4 5 6 |
$ adb shell am start-activity \ -n com.android.dynsystem/com.android.dynsystem.VerificationActivity \ -a android.os.image.action.START_INSTALL \ -d file:///storage/emulated/0/Download/system_raw.gz \ --el KEY_SYSTEM_SIZE $(du -b system_raw.img|cut -f1) \ --el KEY_USERDATA_SIZE 8589934592 |
После окончания установки в шторке появится уведомление с предложением перезагрузиться.
Сложно, не правда ли? Именно поэтому в Android 11 появилась функция под названием DSU Loader. Она позволяет автоматически загрузить и установить образ GSI в пару кликов.
В текущих сборках Android 11 DSU Loader требует разблокированный загрузчик. Однако к релизу стабильной версии Google планирует убрать это ограничение.
Виртуальная A/B-разметка
Кроме возможности временной установки официальных сборок GSI, механизм DSU также позволил реализовать еще одну весьма интересную функцию — Virtual A/B.
Мы уже рассматривали преимущества новой A/B-разметки и то, какие проблемы она может решить. Однако ввиду потери пространства, которое может принести с собой A/B-разметка на устройствах с ограниченным объемом NAND-памяти, а также проблем с миграцией Google не спешит заставлять производителей смартфонов использовать новую разметку.
РЕКОМЕНДУЕМ:
Как устроена операционная система Андроид
Вместо этого они создали виртуальную A/B-разметку. Работает она примерно так же, как динамические обновления, только без отката на ранее установленную прошивку: когда смартфон обнаруживает новое OTA-обновление, он создает несколько дополнительных системных разделов для новой прошивки, скачивает в них обновление, а затем делает эти разделы активными (как и в случае с A/B-разметкой). После следующей перезагрузки смартфон загружается уже с новых разделов; если загрузка проходит успешно, то старые разделы удаляются, а освобожденное ими место отдается разделу userdata.
Виртуальная A/B-разметка будет обязательной для всех устройств, вышедших на рынок с Android 11.
Модульные обновления
Еще один шаг в решении проблемы с обновлениями — Project Mainline. Это внедренная в Android 10 подсистема, позволяющая обновлять куски Android в обход производителя устройства.
В центре новой подсистемы — пакетный менеджер APEX, очень похожий на тот, что используется в дистрибутивах Linux и новой операционке Google Fuchsia. Работает он примерно так: допустим, по очередному указу правительства в России вновь меняют часовые пояса. Команда разработчиков Android формирует новую версию пакета с часовыми поясами и выкладывает ее в Google Play. Пользователи получают обновление — все счастливы.
Таким же образом могут быть обновлены библиотеки и целые подсистемы. Уже сейчас в AOSP доступны пакеты с рантаймом ART («виртуальная машина», ответственная за запуск приложений), библиотека криптографических алгоритмов Conscrypt, набор мультимедийных кодеков, мультимедийный фреймворк, DNS-резолвер, интерфейс Documents UI, Permission Controller, ExtServices, данные часовых поясов, ANGLE (прослойка для трансляции вызовов OpenGL ES в OpenGL, Direct3D 9/11, Desktop GL и Vulkan) и Captive Portal Login. В теории в пакет APEX можно упаковать практически любой компонент системы, и пользователи смогут обновить его независимо от производителя смартфона.
Интересно, что APEX не производит обновление «на живую», когда старый компонент заменяется новым. Раздел /system в Android недоступен для записи, поэтому APEX использует трюк с монтированием. Все обновляемые файлы внутри пакета APEX находятся в образе файловой системы ext4. Когда пакет «устанавливается», система монтирует этот образ поверх раздела /system в режиме bind. В результате файлы пакета как бы заменяют оригинальные файлы Android, хотя в реальности все остается на своих местах.
Такой же трюк использует Magisk для установки модификаций Android без изменения раздела /system. И его автор уже сказал, что APEX станет проблемой для Magisk.
Трюк с сохранением пространства
Внимательно прочитав раздел «A/B-разметка», ты мог заметить, что экономия пространства при такой разметке в основном достигается за счет сокращения размера раздела system в два раза. И дело здесь вовсе не в том, что при A/B-разметке используется какая-то специализированная сборка Android, а в отказе от «лишних» файлов.
В классическом варианте разметки системный раздел содержит в себе не только саму операционную систему, но и так называемые файлы odex. Они представляют собой оптимизированные (пропущенные через AOT-компилятор) версии dex-файлов, которые, в свою очередь, содержат код приложения.
Файлы odex позволяют сократить время старта приложения и повысить его производительность. Они могут быть созданы тремя путями:
- преинсталлированы на устройство (в классическом варианте разметки — в раздел system);
- сгенерированы динамически во время использования приложения или простоя устройства;
- загружены из Google Play вместе с самим приложением.
Отсутствие файлов odex может серьезно испортить пользовательский экспириенс от первого запуска смартфона (время загрузки может составить несколько минут вместо десятков секунд), поэтому они необходимы сразу. С другой стороны, они занимают примерно половину всего пространства раздела system, а если этот раздел продублировать, то потеря пространства станет существенной.
Именно поэтому разработчики отказались от предустановки файлов odex в активный системный раздел, а вместо этого залили их в неактивный системный раздел вместо копии операционной системы. Так что жизненный цикл смартфона с A/B-разметкой выглядит так:
- При выпуске с конвейера раздел system_a активный, содержит файлы операционной системы, раздел system_b неактивный, содержит файлы odex.
- Во время первого запуска система копирует файлы odex в раздел userdata.
- После получения первого OTA-обновления система записывает обновление в раздел system_b, далее запускает генерацию файлов odex (инструмент dex2oat) для новой версии ОС (они также записываются в userdata) и после ее завершения помечает раздел system_b (все разделы слота B) как активный.
- После перезагрузки смартфон загружает операционную систему с раздела system_b, используя сгенерированные на третьем этапе файлы odex.
Выводы
A/B-разметка и динамические разделы — одни из самых интересных и полезных технологий, появившихся в Android в последние пять лет. В теории с их помощью можно реализовать мультизагрузку, создавать разделы для любых подсобных задач и полностью менять таблицу разделов устройства, выкинув все лишнее. Проблема только в том, что без разлочки загрузчика и кастомной прошивки все это будет недоступно.
РЕКОМЕНДУЕМ:
12 советов разработчику Андроид приложений
APEX, с другой стороны, в теории может решить большинство проблем с обновлением смартфонов. Однако, в отличие от дистрибутивов Linux и ОС Fuchsia, пакеты APEX больше напоминают костыль, чем уместное инженерное решение. С другой стороны — лучше так, чем никак.