Андроид обновление базы данных

Полный список

— меняем версию и обновляем структуру БД в onUpgrade

С развитием приложения может возникнуть необходимость изменения структуры БД, которую оно использует. На одном из прошлых уроков я упоминал, что для этого используется метод onUpgrade класса SQLiteOpenHelper. Этот метод вызывается, если существующая версия БД отличается от той, к которой мы пытаемся подключиться. Версию мы обычно указывали при вызове конструктора супер-класса SQLiteOpenHelper в конструкторе DBHelper.

Попробуем воспользоваться методом onUpgrade и посмотреть, как происходит переход на новую версию БД. Для этого напишем небольшое приложение, аналогичное одному из приложений с прошлых уроков – про сотрудников и должности.

Первая версия БД будет содержать только таблицу people с именем сотрудника и его должностью. Но такая таблица будет не совсем корректна. Если вдруг у нас изменится название должности, придется обновлять все соответствующие записи в people. Поэтому мы решаем изменить БД и организовать данные немного по-другому.

Во второй версии добавим таблицу position с названием должности и зарплатой. И в таблице people вместо названия должности пропишем соответствующий ID из position.

Project name: P0391_SQLiteOnUpgradeDB
Build Target: Android 2.3.3
Application name: SQLiteOnUpgradeDB
Package name: ru.startandroid.develop.p0391sqliteonupgradedb
Create Activity: MainActivity

Экран снова не используем, будем выводить все в лог.

Открываем MainActivity.java и кодим:

Код несложен. Я сгруппировал операции по выводу в лог данных из Cursor – метод logCursor. Метод writeStaff – выбирает данные из таблицы people и вызывает метод для вывода данных в лог. В методе Activity onCreate мы создаем объект DBHelper, подключаемся к БД, выводим в лог версию БД, вызываем writeStaff и отключаемся.

В DBHelper все как обычно. В конструкторе вызываем конструктор супер-класса. Обратите внимание, DB_VERSION = 1 – мы будем подключаться к базе версии 1. В методе onCreate создаем таблицу и заполняем ее.

Все сохраним и запустим приложение. Смотрим лог:

— onCreate database —
— Staff db v.1 —
Table people. 8 rows
name = Иван; position = Программер;
name = Марья; position = Бухгалтер;
name = Петр; position = Программер;
name = Антон; position = Программер;
name = Даша; position = Бухгалтер;
name = Борис; position = Директор;
name = Костя; position = Программер;
name = Игорь; position = Охранник;

БД создалась, версия = 1 и данные из таблицы вывелись в лог. Приложение работает, все ок. Но тут мы (внезапно!) понимаем, что при проектировании структуры БД была допущена ошибка. Записывать название должности в поле таблицы people – неправильно. К тому же у нас еще добавляются данные по зарплатам. Надо создать таблицу должностей — position, и использовать из нее id в таблице people. Тем самым структура нашей БД меняется и мы присваиваем ей версию – 2.

Но наше приложение уже установлено у пользователей. Оно уже создало БД версии 1, и в этой БД уже есть данные. Мы не можем просто удалить существующие таблицы и создать новые, т.к. возможно пользователь уже хранит там свои данные. Нам надо будет написать скрипты для обновления без потери данных.

План обновления такой:

— создаем и заполняем данными таблицу position
— добавляем в таблицу people столбец – posid для хранения id из position
— заполняем people.posid данными из position в зависимости от значения people.position
— удаляем столбец people.position

Давайте менять MainActivity.java. Наше приложение теперь будет ориентировано на БД версии 2. Укажем это, изменив значение константы DB_VERSION на 2:

Метод writeStaff перепишем таким образом:

Будем выводить в лог данные из таблиц people, position и их объединения.

Реализуем метод обновления — onUpgrade в DBHelper:

Все в соответствии с планом обновления, который я приводил выше. Есть пара нюансов.

Во-первых, используем БД-транзакцию. Т.е. нам надо чтобы на БД накатились все наши обновления. А в случае ошибки в процессе обновления — все изменения должны быть отменены и БД должна остаться прежней. Тут транзакции очень выручают.

Во-вторых, в SQLite нельзя просто так удалить столбец, приходится создавать временную таблицу, перекидывать туда данные, удалять оригинал, создавать его снова с нужной структурой, скидывать в него данные из временной таблицы и удалять временную таблицу. Подробнее об этом можно почитать тут — How do I add or delete columns from an existing table in SQLite.

Наше приложение обновилось. И теперь, при запуске, оно попытается подключиться к БД версии 2, но увидит, что существующая версия = 1 и вызовет метод onUpgrade, дав нам возможность внести необходимые изменения в структуру БД. Но это произойдет в случае обновления приложения. А что будет если пользователь поставит наше новое приложение на свежий смартфон первый раз?

В этом случае приложение также попытается подключиться к БД версии 2. Но т.к. приложение только что установлено, то БД еще не существует. Приложение создаст БД и присвоит ей версию номер 2, т.к. оно умеет работать именно с такой версией. При создании будет вызван метод onCreate в DBHelper. Значит, в нем мы должны прописать код, который будет создавать нам БД версии 2 – т.е. обновленную таблицу people и новую таблицу position.

Пишем onCreate в DBHelper:

Создание и заполнение данными двух таблиц. Все понятно.

Теперь можно все сохранить и запустить приложение.

— onUpgrade database from 1 to 2 version —
— Staff db v.2 —
Table people. 8 rows
name = Иван; posid = 2;
name = Марья; posid = 3;
name = Петр; posid = 2;
name = Антон; posid = 2;
name = Даша; posid = 3;
name = Борис; posid = 1;
name = Костя; posid = 2;
name = Игорь; posid = 4;
Table position. 4 rows
name = Директор; salary = 15000;
name = Программер; salary = 13000;
name = Бухгалтер; salary = 10000;
name = Охранник; salary = 8000;
inner join. 8 rows
Name = Иван; Position = Программер; Salary = 13000;
Name = Марья; Position = Бухгалтер; Salary = 10000;
Name = Петр; Position = Программер; Salary = 13000;
Name = Антон; Position = Программер; Salary = 13000;
Name = Даша; Position = Бухгалтер; Salary = 10000;
Name = Борис; Position = Директор; Salary = 15000;
Name = Костя; Position = Программер; Salary = 13000;
Name = Игорь; Position = Охранник; Salary = 8000;

Видим, что вызывался onUpgrade и обновил нам БД с версии 1 на 2. Далее выводим все данные, чтобы убедиться, что обновление прошло корректно.

Можно также убедиться, что новый onCreate в DBHelper корректно отработает. Для этого надо удалить файл БД и запустить приложение. Приложение не найдет БД и создаст ее сразу в новом формате и с версией 2.

Сценарий выдуманный, есть к чему придраться и о чем поспорить, но смысл не в этом. Смысл в том, что мы увидели, как происходит обновление БД, если приложение запросило новую версию. Поначалу, возможно, покажется запутанным этот механизм создания и обновления. Но сложного реально ничего нет. С опытом придет полное понимание.

Читайте также:  Exo player для андроид тв

Еще хочу отметить, что у объекта Cursor есть метод close(), который освобождает занимаемые им ресурсы. Не забывайте про него.

Думаю, теперь можно смело сказать, что работу с SQLite в Android мы изучили достаточно основательно. И в дальнейших уроках сможем свободно использовать эти знания.

Полный код MainActivity.java:

На следующем уроке:

— разбираем как можно использовать LayoutInflater

Присоединяйтесь к нам в Telegram:

— в канале StartAndroid публикуются ссылки на новые статьи с сайта startandroid.ru и интересные материалы с хабра, medium.com и т.п.

— в чатах решаем возникающие вопросы и проблемы по различным темам: Android, Kotlin, RxJava, Dagger, Тестирование

— ну и если просто хочется поговорить с коллегами по разработке, то есть чат Флудильня

— новый чат Performance для обсуждения проблем производительности и для ваших пожеланий по содержанию курса по этой теме

Источник

Android: обновление версии БД и добавление новой таблицы

Я уже создал таблицы sqlite для своего приложения, но теперь я хочу добавить новую таблицу в базу данных.

Я изменил версию DB, как показано ниже

и добавлена строка для создания таблицы

onCreate и onUpgrade как показано ниже:

но по какой-то причине новая таблица не создается. Что я делаю не так?

5 ответов

1. О onCreate () и onUpgrade ()

onCreate(..) вызывается, когда приложение свежеустановленная. onUpgrade вызывается всякий раз, когда приложение обновляется и запускается и версия базы данных — это не то же самое.

2. Увеличение версии БД

важно: увеличение только версии приложения недостаточно для onUpgrade будет звонил!

3. Не забывайте своих новых пользователей!

не забудьте добавить

к вашему методу onCreate (), а также или вновь установленным приложениям будет не хватать таблицы.

4. Как справиться с несколькими изменениями базы данных с течением времени

когда у вас есть последовательные обновления приложений, некоторые из которых имеют обновления базы данных, вы хотите быть уверены, чтобы проверить oldVersion :

таким образом, когда обновления пользователей с версии 1 до версии 3, они получают оба обновления. Когда пользователь обновляется с версии 2 до 3, они просто получают обновление версии 3. В конце концов, вы не можете рассчитывать на 100% вашей пользовательской базы для обновления каждый раз, когда вы выпускаете обновление. Иногда они пропускают обновление или 12:)

5. Сохранение номеров версий под контролем при разработке

полностью удаляет приложение. Когда вы установите снова, вы гарантированно нажмете onCreate что удерживает вас от необходимости продолжать увеличивать версию базы данных в стратосферу по мере развития.

ваш код выглядит правильно. Мое предложение заключается в том, что база данных уже думает, что она обновлена. Если вы выполнили проект после увеличения номера версии, но перед добавлением execSQL вызов, база данных на вашем тестовом устройстве / эмуляторе может уже поверить, что она находится в версии 2.

быстрый способ проверить это-изменить номер версии на 3 — если он обновится после этого, вы знаете, что это было только потому, что ваше устройство считало, что оно уже обновлено.

можно использовать метод. В методе onUpgrade вы получаете oldVersion в качестве одного из параметров.

на onUpgrade использовать switch и в каждом из case s используйте номер версии для отслеживания текущей версии базы данных.

лучше всего, что вы петля от oldVersion to newVersion , incrementing version по 1 за раз, а затем обновить базы данных шаг за шагом. Это очень полезно, когда кто-то с базой данных версии 1 обновляет приложение через долгое время до версии с использованием базы данных версии 7, и приложение начинает сбой из-за некоторых несовместимых изменений.

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

@jkschneider прямо. Однако есть лучший подход.

запишите необходимые изменения в файл sql для каждого обновления, как описано в ссылке https://riggaroo.co.za/android-sqlite-database-use-onupgrade-correctly/

эти .файлы sql будут выполняться в методе onUpgrade() в соответствии с версией база данных.

работа с версиями базы данных является очень важной частью разработки приложений. Я предполагаю, что у вас уже есть расширение класса AppDbHelper SQLiteOpenHelper . Когда вы расширяете его, вам нужно будет реализовать onCreate и onUpgrade метод.

, когда onCreate и onUpgrade методы, называемые

  • onCreate вызывается при новой установке приложения.
  • onUpgrade вызывается при обновлении приложения.

организация Версия базы данных Я управляю версиями в методах класса. Создание реализации миграции интерфейса. Например. Для первой версии create MigrationV1 класс, вторая версия create MigrationV1ToV2 (это мое соглашение об именах)

  1. использование классов миграции

onCreate : С onCreate будет вызываться, когда приложение только что установлено, нам также нужно выполнить все миграции (база данных обновление версии.) Так что onCreate будет выглядеть так:

onUpgrade : этот метод будет вызываться, когда приложение уже установлено и обновлено до новой версии приложения. Если приложение содержит какие-либо изменения базы данных, поместите все изменения базы данных в новый класс миграции и увеличьте версию базы данных.

например, допустим, пользователь установил приложение с базой данных версии 1, и теперь версия базы данных обновляется до 2(все обновления схемы держали в MigrationV1ToV2 ). Теперь, когда приложение обновлено, нам нужно обновить базу данных, применив изменения схемы базы данных в MigrationV1ToV2 такой:

Примечание: все обновления (упомянутые в onUpgrade ) в схеме базы данных должно быть выполнено в onCreate

Источник

Эволюция системы обновления Android

В этой статье мы рассмотрим все возможные варианты обновления прошивки на устройствах под управлением Fuchsia Android. Особое внимание уделим самому популярному способу — обновлению по воздуху или OTA (over-the-air) — и расскажем об этапах его развития.

Итак, как можно обновить Android на мобильных устройствах? Занимаясь разработкой ТВ-приставок под управлением этой ОС, мы определили для себя 4 способа, отбросив совсем уж экзотические варианты:

перепрошивка flash-памяти через аппаратный интерфейс JTAG (если есть);

перепрошивка flash-памяти с использованием загрузчика (bootloader);

обновление через Recovery Mode;

Рассмотрим подробнее каждый из вариантов.

1. Обновление Android через JTAG-интерфейс

Вариант с JTAG позволяет обновлять устройство только локально и требует подключения девайса с Android к хосту, например, по USB-интерфейсу. Так как перепрошивается flash-память, новую версию Android можно поставить на прошивку с другими ключами безопасности, да и в целом не сильно стесняться в выборе версий самой Android, версии собранной прошивки или переконфигурации разделов flash-памяти.

Однако обычно JTAG-интерфейс присутствует только на отладочных платах, что сильно сужает область применения этого варианта обновиться.

Читайте также:  Лучший радар детектор для андроид 2021

2. Обновление Android через Recovery Mode

Обычно загрузчик является проприетарным, его разрабатывает производитель чипа. Именно bootloader инициализирует доверенную среду выполнения (TEE, trusted execution environment) и проверяет целостность разделов boot и recovery перед переносом выполнения в ядро Linux. Сам загрузчик часто является составным, часть его уровней может быть открытой (например, на базе U-boot), а часть — проприетарной.

Bootloader Android позволяет перепрошивать flash-память устройства подготовленными образами разделов. Для этого используется протокол fastboot либо его аналог (в случае Amlogic это будет протокол WorldCup Device). Fastboot, как и его аналог WorldCup Device, — это протокол взаимодействия с bootloader через USB-интерфейс или локальную сеть Ethernet.

Для перепрошивки необходимо подключить устройство через USB к хосту (есть вариант использовать LAN Ethernet), перевести загрузчик (bootloader) в специальный update-режим и в этом режиме перепрошить flash-память устройства.

Плюсы и минусы данного метода всё те же, что и для JTAG: так как обновление проходит без участия самой системы Android, при перепрошивке нет ограничений, связанных с версией системы/сборки или ключами безопасности.

Но, как всегда, есть одно НО. 🙂 Bootloader должен быть разблокирован, а это значит, что мы можем перепрошить сам загрузчик или разделы устройства. Блокировка/разблокировка производится командой fastboot flashing lock/unlock, но для выполнения этой команды может понадобится пароль, установленный тем, кто добрался до этого устройства раньше вас (обычно это производитель).

3. Обновление Android через Recovery Mode и OTA

Если первые два варианта обновления оставались неизменными на протяжении всего времени развития Android, то следующие два варианта — обновление через Recovery Mode и OTA — реализуются средствами самой Android и эволюционировали вместе со всей ОС.

Стоит упомянуть, что Recovery Mode и OTA — это два различных варианта вызова движка обновления Android.

Recovery или non-A/B System Updates

Recovery и движок обновления updater (bootable/recovery/updater) — это как раз то, с чего началась система обновления Android (располагается в bootable/recovery в дереве исходников AOSP).

Схема обновления Recovery (или non-A/B System Updates) задействует специальный раздел восстановления (Recovery), где содержится специальная ОС на основе ядра Linux. Эта ОС на базе Linux содержит программное обеспечение для распаковки загруженного образа обновления и его применения к другим разделам. Так и проходит обновление Android.

Пример разметки flash-памяти на устройстве с Android 6.0:

Карта разделов Android 6.0.1

[mmcblk0p01] bootloader offset 0x000000000000, size 0x000000400000

[mmcblk0p02] reserved offset 0x000002400000, size 0x000004000000

[mmcblk0p03] cache offset 0x000006c00000, size 0x000020000000

[mmcblk0p04] env offset 0x000027400000, size 0x000000800000

[mmcblk0p05] logo offset 0x000028400000, size 0x000002000000

[mmcblk0p06] recovery offset 0x00002ac00000, size 0x000002000000

[mmcblk0p07] rsv offset 0x00002d400000, size 0x000000800000

[mmcblk0p08] tee offset 0x00002e400000, size 0x000000800000

[mmcblk0p09] crypt offset 0x00002f400000, size 0x000002000000

[mmcblk0p10] misc offset 0x000031c00000, size 0x000002000000

[mmcblk0p11] instaboot offset 0x000034400000, size 0x000020000000

[mmcblk0p12] boot offset 0x000054c00000, size 0x000002000000

[mmcblk0p13] system offset 0x000057400000, size 0x000060000000

[mmcblk0p14] data offset 0x0000b7c00000, size 0x0002ec200000

Сам процесс обновления происходит в два этапа:

После загрузки с раздела Recovery происходит обновление всех остальных разделов Android.

И уже после перезагрузки и запуска новой версии Android происходит обновление раздела Recovery.

При обновлении с использованием движка updater на первом этапе проверяется версия и цифровая подпись образа, поэтому откатить на старую версию ОС уже не получится.

Обновиться по схеме Recovery можно как локально, выбрав в bootloader режим Recovery Mode и запустив движок обновления updater через меню Recovery Mode, либо удаленно, через OTA, когда приложение, работающее в Android, вызывает тот же updater из Java. И как раз при таком удаленном запуске можно организовать массовое обновление целой серии устройств. Этот вариант используют операторы цифрового ТВ при обновлении своих абонентских ТВ-приставок.

Сам раздел Recovery при non-A/B-схеме обновления является физическим разделом во flash-памяти. С появлением A/B-схемы раздел Recovery переместился на RAM-диск в оперативной памяти устройства, но возможность сделать его отдельным физическим разделом также осталась.

Нужно сказать, что в системе Android нет четкого разделения на «старое» и «новое», скорее добавляются дополнительные возможности в конфигурации сборки Android с сохранением по возможности совместимости со старыми решениями. Однако не все варианты конфигураций работают.

Одним из важных недостатков схемы Recovery или non-A/B System Updates является то, что при любом сбое во время обновления или битой прошивке мы получаем пусть и не «кирпич» (с раздела Recovery всё еще можно запустить устройство в Recovery Mode), но всё же не полнофункциональное и требующее восстановления устройство.

С этим, видимо, решено было что-то делать, потому что следующим этапом эволюции системы обновления стало бесшовное обновление (seamless updates) или A/B-схема обновления.

Бесшовное обновление или A/B-схема

Эта возможность появилась в Android 7.0, она реализована в новом движке update_engine, который располагается в system/update_engine в дереве исходников AOSP.

Главной особенностью A/B-схемы стало то, что в случае сбоев при обновлении можно загрузиться с предыдущей рабочей версии системы Android. Flash-память устройства содержит дублирующиеся системные разделы или слоты (slot A и B), отсюда и название — A/B system updates (вечная проблема с выбором названий). За выбор слота для загрузки (A или B) отвечает bootloader, анализируя состояние слотов.

Принцип бесшовного обновления Android по A/B-схеме (активный раздел отмечен птичкой)

Итак, как же происходит обновление:

1) Загружая систему, например, со слотов A, мы скачиваем и прошиваем обновления на слоты B.

2) После перезагрузки со слотов B мы проверяем работоспособность системы, и, если все ОК, сообщаем bootloader, что обновление прошло успешно.

В случае проблем с обновлением bootloader вернется на старую версию прошивки после нескольких неудачных попыток загрузиться с новой системы.

На официальном сайте для разработчиков — Android Source — этот процесс расписан более детально в 9 шагах, также там объясняется, как все работает после перезагрузки.

Особенность бесшовной A/B-схемы обновление — это «съедение» большего объема flash-памяти. Насколько большего? Это можно оценить по приведенным ниже схемам разделов для Android 9.0. Как уже упоминалось ранее, разработчик может выбирать, какую из схем — A/B или non-A/B — применять в конфигурации системы.

Карта разделов Android P (recovery)

[mmcblk0p01] bootloader offset 0x000000000000, size 0x000000400000

[mmcblk0p02] reserved offset 0x000002400000, size 0x000004000000

[mmcblk0p03] cache offset 0x000006c00000, size 0x000046000000

[mmcblk0p04] env offset 0x00004d400000, size 0x000000800000

[mmcblk0p05] logo offset 0x00004e400000, size 0x000000800000

[mmcblk0p06] recovery offset 0x00004f400000, size 0x000001800000

[mmcblk0p07] misc offset 0x000051400000, size 0x000000800000

[mmcblk0p08] dtbo offset 0x000052400000, size 0x000000800000

[mmcblk0p09] cri_data offset 0x000053400000, size 0x000000800000

[mmcblk0p10] param offset 0x000054400000, size 0x000001000000

[mmcblk0p11] boot offset 0x000055c00000, size 0x000001000000

[mmcblk0p12] rsv offset 0x000057400000, size 0x000001000000

[mmcblk0p13] metadata offset 0x000058c00000, size 0x000001000000

[mmcblk0p14] vbmeta offset 0x00005a400000, size 0x000000200000

[mmcblk0p15] tee offset 0x00005ae00000, size 0x000002000000

Читайте также:  Hdmi cec для android

[mmcblk0p16] vendor offset 0x00005d600000, size 0x000040000000

[mmcblk0p17] odm offset 0x00009de00000, size 0x000008000000

[mmcblk0p18] system offset 0x0000a6600000, size 0x000050000000

[mmcblk0p19] product offset 0x0000f6e00000, size 0x00000800000

[mmcblk0p01] bootloader offset 0x000000000000, size 0x000000400000

[mmcblk0p02] reserved offset 0x000002400000, size 0x000004000000

[mmcblk0p03] cache offset 0x000006c00000, size 0x000000000000

[mmcblk0p04] env offset 0x000007400000, size 0x000000800000

[mmcblk0p05] logo offset 0x000008400000, size 0x000000800000

[mmcblk0p06] boot_a offset 0x000009400000, size 0x000001000000

[mmcblk0p07] misc offset 0x00000ac00000, size 0x000000800000

[mmcblk0p08] dtbo_a offset 0x00000bc00000, size 0x000000800000

[mmcblk0p09] dtbo_b offset 0x00000cc00000, size 0x000000800000

[mmcblk0p10] cri_data offset 0x00000dc00000, size 0x000000800000

[mmcblk0p11] param offset 0x00000ec00000, size 0x000001000000

[mmcblk0p12] boot_b offset 0x000010400000, size 0x000001000000

[mmcblk0p13] rsv offset 0x000011c00000, size 0x000001000000

[mmcblk0p14] metadata_a offset 0x000013400000, size 0x000001000000

[mmcblk0p15] metadata_b offset 0x000014c00000, size 0x000001000000

[mmcblk0p16] vbmeta_a offset 0x000016400000, size 0x000000200000

[mmcblk0p17] vbmeta_b offset 0x000016e00000, size 0x000000200000

[mmcblk0p18] tee offset 0x000017800000, size 0x000002000000

[mmcblk0p19] vendor_a offset 0x00001a000000, size 0x000040000000

[mmcblk0p20] vendor_b offset 0x00005a800000, size 0x000040000000

[mmcblk0p21] odm_a offset 0x00009b000000, size 0x000008000000

[mmcblk0p22] odm_b offset 0x0000a3800000, size 0x000008000000

[mmcblk0p23] system_a offset 0x0000ac000000, size 0x000050000000

[mmcblk0p24] system_b offset 0x0000fc800000, size 0x000050000000

[mmcblk0p25] product_a offset 0x00014d000000, size 0x000008000000

[mmcblk0p26] product_b offset 0x000155800000, size 0x000008000000

[mmcblk0p27] data offset 0x00015e000000, size 0x000245e00000

Если сравнить эти две конфигурации, то можно заметить, что раздел data при A/B-схеме меньше на 1,6 ГБ, и это цена дублирующихся системных разделов. Много это или мало — каждый решает сам, ориентируясь на характеристики своего устройства/проекта.

Проект Treble

Следующие изменения в системе обновления произошли в Android 8.0. Начиная с Android O (8.0) и продолжая в Android P (9.0), Google реализует свой проект Treble. Идея проекта состоит в том, чтобы упростить технологический процесс создания обновления для Android-устройства. Google предложил разделить с помощью неизменных интерфейсов части прошивки, созданием которых занимаются разные компании. Процесс разработки прошивки для конкретного девайса можно упрощенно разделить на следующие шаги:

Команда Android создает новую версию своей OC.

Разработчик чипа или системы на кристалле (Silicon Manufacturer) создает аппаратно-зависимые патчи для запуска этой версии Android на своих платах.

И уже разработчики конечного устройства (Vendors) делают свою часть для реализации всех функций конкретного продукта для рынка электроники.

Проект Treble разделяет ОС Android с дополнениями от производителей чипов/СнК и код разработчика конечного устройства, так что теперь операционная система может получать обновления без реализации изменений от производителя устройства.

Разделение происходит как с помощью программного интерфейса (переход с Hardware Abstraction Layer 1.0 на HAL2.0), так и за счет выделения отдельных разделов на flash-памяти для Silicon Manufacturer и Vendor (выше в карте разделов Android 9.0 можно увидеть разделы odm, vendor, product).

Переход с HAL1.0 на HAL2.0 заключается в отказе от прямого связывания с системными библиотеками. Вместо этого, используя IPC Binder, можно подключаться к системным сервисам.

И еще одно небольшое, но полезное изменение: начиная с Android 8.0, в update_engine добавлена поддержка потоковых обновлений по A/B-схеме, в ходе которых идет прямая запись в слот B без необходимости промежуточного хранения данных в /data. Для таких потоковых обновлений практически не требуется временное хранилище, достаточно всего лишь 100 килобайт для сохранения метаданных.

При этом необходимо, чтобы http-сервер, используемый для скачивания обновления, поддерживал HTTP range requests или другими словами докачку.

Проект Mainline

Следующим серьезным этапом в развитии системы обновления Android стал проект Mainline. Реализация этого проекта началась с Android 10.0 и продолжилась в текущем Android 11.0.

Проект Mainline позволяет обновлять отдельные системные компоненты без обновления ОС целиком. Нужные данные загружаются через Google Play отдельно от OTA-обновления прошивки от производителя. Предполагается, что прямая доставка обновлений, не привязанных к оборудованию частей Android, позволит существенно сократить время получения обновлений, увеличить оперативность исправления уязвимостей и снизить зависимость от производителей устройств в поддержке безопасности ОС.

Для реализации проекта Mainline выбранные компоненты системы Android преобразуются в модули. Часть этих модулей имеет старый формат APK, а часть конвертируется в новый APEX-формат, который отличается от APK возможностью применения на раннем этапе загрузки системы. На случай возможных сбоев предусмотрен режим отката изменений.

С APEX-пакетами работает системный сервис APEX manager (apexd). Это нативный сервис, который после проверки распаковывает APEX-пакет в пользовательское пространство на диске и добавляет запись о нем в свою базу данных. При следующей загрузке системы APEX manager проверяет все пакеты из базы данных, создает loop-устройство для ext4-образа каждого APEX-пакета и монтирует его по пути /apex/name@ver.

Модули с обновлениями изначально будут поставляться с открытым кодом, они будут сразу доступны в репозиториях AOSP (Android Open Source Project) и смогут включать улучшения и исправления, подготовленные сторонними участниками.

В рамках проекта Mainline в Android 10 было добавлено 13 обновляемых модулей, а в Android 11 в дополнение к уже существующим прибавилось еще 11 модулей.

Схема Virtual A/B

Также в Android 11 к схемам non-A/B и A/B была добавлена схема Virtual A/B. Этот новый механизм обновления сочетает преимущества обоих предшественников, он обеспечивает устойчивое к сбоям обновление устройства, задействуя при этом минимальный объем flash-памяти. Это стало возможным благодаря созданию снимков файловой системы (snapshot) с использованием технологии Device-mapper (подсистема ядра Linux, позволяющая создавать виртуальные блочные устройства) и Dynamic Partitions.

Dynamic Partitions — это система организации динамических разделов для Android. С ее помощью можно создавать, изменять размер или уничтожать разделы прямо в процессе обновления по воздуху (OTA). При использовании динамических разделов разработчикам больше не нужно беспокоиться о размере отдельных разделов, таких как system, vendor и product. Вместо них на устройстве выделяется суперраздел, внутри которого можно динамически изменять размер подразделов. Больше нет необходимости оставлять свободное пространство для будущих OTA-обновлений внутри отдельных образов разделов. Оставшееся свободное место в суперразделе теперь доступно для всех динамических подразделов.

И в заключении последние слухи конца 2020 года — вишенка на торте. Google конвертирует Android Runtime в модуль Mainline. Android Runtime или ART — это среда выполнения Android-приложений, включающая компиляцию байт-кода приложения в машинные инструкции. Так что есть вероятность, что уже в Android 12 можно будет обновить ART через GooglePlay, установив APEX-пакет.

Также, вероятно, система обновления Android мигрирует в Fuchsia, новую ОС Google, которая сейчас находится в процессе разработки. Они традиционно копируют удачные решения в своих программных продуктах. Так, например, update_engine для A/B-схемы, который применяется сейчас в Android, используется в еще одной ОC Google — Chrome OS. Или еще один пример: в Fuchsia предлагается библиотека Machina, которая позволяет запускать Linux-программы в специальной изолированной виртуальной машине по аналогии с тем, как организован запуск Linux-приложений в той же Chrome OS.

Источник

Оцените статью