Внутри пакетов OTA

Система создает двоичный файл программы обновления из bootable/recovery/updater и использует его в пакете OTA.

Сам пакет представляет собой ZIP-файл (ota_update.zip, incremental_ota_update.zip), содержащий исполняемый двоичный файл META-INF/com/google/android/update-binary .

В Updater есть несколько встроенных функций и интерпретатор для расширяемого языка сценариев (edify), который поддерживает команды для типичных задач, связанных с обновлениями. Программа обновления ищет в ZIP-файле пакета скрипт в файле META-INF/com/google/android/updater-script.

Примечание. Использование скрипта edify и/или встроенных функций – это не обычная процедура, но она может быть полезна, если вам нужно отладить файл обновления.

Синтаксис Edify

Скрипт Edify – это одно выражение, в котором все значения являются строками. Пустые строки в логическом контексте имеют значение false, а все остальные строки – true. Edify поддерживает следующие операторы (с обычными значениями):

(expr )
 expr + expr  # string concatenation, not integer addition
 expr == expr
 expr != expr
 expr && expr
 expr || expr
 ! expr
 if expr then expr endif
 if expr then expr else expr endif
 function_name(expr, expr,...)
 expr; expr

Любая строка из символов a-z, A-Z, 0-9, _, :, /, . не является зарезервированным словом, считается строковым литералом. (Зарезервированные слова: if else then endif.) Строковые литералы также могут быть заключены в двойные кавычки. Так можно создавать значения с пробелами и другими символами, не входящими в указанный выше набор. \n, \t, \" и \\ служат экранирующими символами в строках, заключенных в кавычки, как и \x##.

Операторы && и || являются сокращенными: правая часть не вычисляется, если логический результат определяется левой частью. Следующие записи эквивалентны:

e1 && e2
if e1 then e2 endif

Оператор ";" является точкой следования. Это означает, что сначала вычисляется левая часть, а затем правая. Его значение – это значение выражения справа. Точка с запятой также может стоять после выражения, имитируя операторы в стиле C:

prepare();
do_other_thing("argument");
finish_up();

Встроенные функции

Большинство функций обновления содержится в функциях, доступных для выполнения скриптами. (Строго говоря, это макросы, а не функции в смысле языка Lisp, поскольку им не обязательно вычислять все свои аргументы.) Если не указано иное, функции возвращают значение true при успешном выполнении и false при ошибке. Если вы хотите, чтобы при возникновении ошибок выполнение скрипта прекращалось, используйте функции abort() и/или assert(). Набор функций, доступных в программе обновления, также можно расширить, чтобы добавить функции, предназначенные для определенных устройств.

abort([msg])
Немедленно прерывает выполнение скрипта с необязательным сообщением msg. Если пользователь включил отображение текста, в журнале восстановления и на экране появится msg.
assert(expr[, expr, ...])
Поочередно оценивает каждое выражение. Если какое-либо из них ложно, выполнение немедленно прерывается с сообщением "assert failed" и исходным текстом выражения, которое не удалось проверить.
apply_patch(src_file, tgt_file, tgt_sha1, tgt_size, patch1_sha1, patch1_blob, [...])
Применяет двоичный патч к файлу src_file, чтобы создать файл tgt_file. Если целевой файл совпадает с исходным, укажите "-" для параметра tgt_file . tgt_sha1 и tgt_size – это ожидаемый окончательный хеш SHA1 и размер целевого файла. Остальные аргументы должны быть парными: хеш SHA1 (шестнадцатеричная строка из 40 символов) и большой двоичный объект. Блоб – это патч, который нужно применить, если текущее содержимое исходного файла имеет указанный SHA1.

Исправление выполняется безопасным способом, который гарантирует, что целевой файл либо имеет желаемый хеш SHA1 и размер, либо остается нетронутым – он не будет оставлен в невосстановимом промежуточном состоянии. Если процесс прервется во время установки исправлений, целевой файл может оказаться в промежуточном состоянии. В разделе кеша есть копия, поэтому перезапуск обновления может успешно обновить файл.

Поддерживается специальный синтаксис, позволяющий обрабатывать содержимое разделов Memory Technology Device (MTD) как файлы, что позволяет исправлять необработанные разделы, например загрузочные. Чтобы прочитать раздел MTD, нужно знать, сколько данных вы хотите прочитать, поскольку в разделе нет понятия конца файла. Вы можете использовать строку "MTD:partition:size_1:sha1_1:size_2: sha1_2" в качестве имени файла, чтобы прочитать указанный раздел. Вы должны указать хотя бы одну пару (размер, SHA-1). Если вы ожидаете получить несколько вариантов данных, можно указать несколько пар.

apply_patch_check(filename, sha1[, sha1, ...])
Возвращает значение true, если контрольная сумма SHA1 содержимого файла filename или временной копии в разделе кеша (при наличии) равна одному из заданных значений sha1. Значения sha1 указываются в виде 40 шестнадцатеричных цифр. Эта функция отличается от sha1_check(read_file(filename), sha1 [, ...]) тем, что она проверяет копию в разделе кеша, поэтому apply_patch_check() будет выполнена успешно, даже если файл был поврежден из-за прерванной операции apply_patch() update.
apply_patch_space(bytes)
Возвращает значение true, если для применения двоичных патчей доступно не менее байт временного пространства.
concat(expr[, expr, ...])
Вычисляет каждое выражение и объединяет их. Оператор + является синтаксическим сахаром для этой функции в особом случае двух аргументов (но форма функции может принимать любое количество выражений). Выражения должны быть строками, а не объектами BLOB.
file_getprop(filename, key)
Считывает указанный filename, интерпретирует его как файл свойств (например, /system/build.prop) и возвращает значение указанного key или пустую строку , если key отсутствует.
format(fs_type, partition_type, location, fs_size, mount_point)
Форматирует указанный раздел. Поддерживаемые типы разделов:
  • fs_type="yaffs2" и partition_type="MTD". В качестве местоположения необходимо указать название раздела MTD, в котором будет создана пустая файловая система yaffs2. Остальные аргументы не используются.
  • fs_type="ext4" и partition_type="EMMC". Местоположение должно быть файлом устройства для раздела. Там создается пустая файловая система ext4. Если значение fs_size равно нулю, файловая система занимает весь раздел. Если fs_size – положительное число, то файловая система занимает первые fs_size байтов раздела. Если fs_size – отрицательное число, файловая система занимает все байты раздела, кроме последних |fs_size|.
  • fs_type="f2fs" и partition_type="EMMC". Параметр "Местоположение" должен быть файлом устройства для раздела. Параметр fs_size должен быть неотрицательным числом. Если значение fs_size равно нулю, файловая система занимает весь раздел. Если fs_size – положительное число, файловая система занимает первые fs_size байт раздела.
  • mount_point должен быть будущей точкой подключения файловой системы.
getprop(key)
Возвращает значение системного свойства key (или пустую строку, если оно не определено). Значения системных свойств, заданные разделом восстановления, не обязательно совпадают со значениями основной системы. Эта функция возвращает значение в режиме восстановления.
greater_than_int(a, b)
Возвращает значение true, если и только если a (интерпретируется как целое число) больше, чем b (интерпретируется как целое число).
ifelse(cond, e1[, e2])
Проверяет условие cond и, если оно истинно, вычисляет и возвращает значение e1. В противном случае вычисляет и возвращает значение e2 (если оно указано). Конструкция "if ... else ... then ... endif" – это просто синтаксический сахар для этой функции.
is_mounted(mount_point)
Возвращает значение true, если в точке монтирования mount_point есть смонтированная файловая система.
is_substring(needle, haystack)
Возвращает значение true, если needle является подстрокой haystack.
less_than_int(a, b)
Возвращает значение true, если a (интерпретируется как целое число) меньше b (интерпретируется как целое число).
mount(fs_type, partition_type, name, mount_point)
Монтирует файловую систему типа fs_type в точке монтирования mount_point. Атрибут partition_type должен иметь одно из следующих значений:
  • MTD. Name – это название раздела MTD (например, system, userdata; полный список можно найти в файле /proc/mtd на устройстве).
  • EMMC.

По умолчанию режим восстановления не монтирует файловые системы (кроме SD-карты, если пользователь вручную устанавливает пакет с нее). Скрипт должен монтировать все разделы, которые ему нужно изменить.

package_extract_dir(package_dir, dest_dir)
Извлекает все файлы из пакета, расположенного в каталоге package_dir, и записывает их в соответствующее дерево в каталоге dest_dir. Существующие файлы будут перезаписаны.
package_extract_file(package_file[, dest_file])
Извлекает один файл package_file из пакета обновлений и записывает его в файл dest_file, при необходимости перезаписывая существующие файлы. Без аргумента dest_file возвращает содержимое файла пакета в виде двоичного объекта BLOB.
read_file(filename)
Считывает название файла и возвращает его содержимое в виде двоичного большого объекта.
run_program(path[, arg, ...])
Выполняет двоичный файл по указанному пути (path), передавая аргументы (arg). Возвращает статус выхода программы.
set_progress(frac)
Устанавливает положение индикатора выполнения в пределах фрагмента, определенного последним вызовом show_progress(). frac должно быть в диапазоне [0.0, 1.0]. Индикатор выполнения никогда не движется назад. Попытки заставить его сделать это игнорируются.
sha1_check(blob[, sha1])
Аргумент blob – это объект blob, тип которого возвращается методом read_file() или формой с одним аргументом метода package_extract_file() . Если аргументы sha1 не указаны, функция возвращает хеш SHA1 большого двоичного объекта (в виде 40-значной шестнадцатеричной строки). Если указан один или несколько аргументов sha1, функция возвращает хеш SHA1, если он равен одному из аргументов, или пустую строку, если он не равен ни одному из них.
show_progress(frac, secs)
Увеличивает значение индикатора выполнения на frac от его длины за secs секунд (должно быть целым числом). Значение secs может быть равно 0, в этом случае индикатор не будет увеличиваться автоматически, а только с помощью функции set_progress(), описанной выше.
sleep(secs)
Задержка в secs секунд (должно быть целым числом).
stdout(expr[, expr, ...])
Оценивает каждое выражение и выводит его значение в стандартный поток вывода. Полезно для отладки.
tune2fs(device[, arg, …])
Настраивает параметры args на устройстве.
ui_print([text, ...])
Объединяет все аргументы text и выводит результат в интерфейс (где он будет виден, если пользователь включил отображение текста).
unmount(mount_point)
Отключает файловую систему, смонтированную в точке монтирования.
wipe_block_device(block_dev, len)
Удаляет len байт из указанного блочного устройства block_dev.
wipe_cache()
Очищает раздел кеша после успешной установки.
write_raw_image(filename_or_blob, partition)
Записывает образ из filename_or_blob в раздел MTD. filename_or_blob может быть строкой с названием локального файла или аргументом со значением типа blob, содержащим данные для записи. Чтобы скопировать файл из пакета OTA в раздел, используйте команду: write_raw_image(package_extract_file("zip_filename"), "partition_name");

Примечание. В версиях Android ниже 4.1 принимались только имена файлов, поэтому для выполнения этой задачи данные сначала нужно было распаковать во временный локальный файл.