El sistema compila el binario del actualizador desde bootable/recovery/updater
y lo usa en un paquete OTA.
ota_update.zip
, incremental_ota_update.zip
) que contiene el ejecutable binario META-INF/com/google/android/update-binary
.
Updater contiene varias funciones integradas y un intérprete para un lenguaje de secuencias de comandos extensible (edify) que admite comandos para tareas típicas relacionadas con las actualizaciones. El actualizador busca una secuencia de comandos en el archivo .zip del paquete en el archivo META-INF/com/google/android/updater-script
.
Nota: El uso de la secuencia de comandos de edify o las funciones integradas no es una actividad común, pero puede ser útil si necesitas depurar el archivo de actualización.
Sintaxis de Edify
Una secuencia de comandos de edify es una sola expresión en la que todos los valores son cadenas. Las cadenas vacías son false en un contexto booleano y todas las demás cadenas son true. Edify admite los siguientes operadores (con los significados habituales):
(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
Cualquier cadena de los caracteres a-z, A-Z, 0-9, _, :, /, . que no sea una palabra reservada se considera un literal de cadena. (Las palabras reservadas son if else y endif.). Las cadenas literales también pueden aparecer entre comillas dobles. Esta es la forma de crear valores con espacios en blanco y otros caracteres que no están en el conjunto anterior. \n, \t, \" y \\ sirven como escapes dentro de cadenas con comillas, al igual que \x##.
Los operadores && y || hacen cortocircuito. El lado derecho no se evalúa si el resultado lógico lo determina el lado izquierdo. Los siguientes son equivalentes:
e1 && e2 if e1 then e2 endif
El operador ; es un punto de secuencia, lo que significa que primero se evalúa el lado izquierdo y, luego, el derecho. Su valor es el valor de la expresión del lado derecho. También puede aparecer un punto y coma después de una expresión, de modo que el efecto simule sentencias de estilo C:
prepare(); do_other_thing("argument"); finish_up();
Funciones integradas
La mayor parte de la funcionalidad de actualización se encuentra en las funciones disponibles para que las ejecuten las secuencias de comandos.
(Estrictamente hablando, estas son macros en lugar de funciones en el sentido de Lisp, ya que no es necesario que evalúen todos sus argumentos). A menos que se indique lo contrario, las funciones muestran true cuando se realizan correctamente y false cuando se producen errores. Si deseas que los errores aborten la ejecución de la secuencia de comandos, usa las funciones abort()
o assert()
. El conjunto de funciones disponibles en el actualizador también se puede extender para proporcionar funciones específicas del dispositivo.
abort([msg])
- Aborta la ejecución de la secuencia de comandos de inmediato, con el msg opcional. Si el usuario activó la visualización de texto, msg aparecerá en el registro de recuperación y en la pantalla.
-
assert(expr[, expr, ...])
- Evalúa cada expr a su vez. Si alguno es falso, aborta de inmediato la ejecución con el mensaje "assert failed" y el texto fuente de la expresión que falló.
-
apply_patch(src_file, tgt_file, tgt_sha1, tgt_size, patch1_sha1, patch1_blob, [...])
-
Aplica un parche binario al src_file para producir el tgt_file . Si el objetivo deseado es el mismo que la fuente, pasa “-” para tgt_file . tgt_sha1 y tgt_size son el hash SHA1 final y el tamaño esperados del archivo de destino. Los argumentos restantes deben venir en pares: un hash SHA1 (una cadena hexadecimal de 40 caracteres) y un blob. El blob es el parche que se aplicará cuando el contenido actual del archivo de origen tenga el SHA1 determinado.
Las correcciones se realizan de forma segura, lo que garantiza que el archivo de destino tenga el hash y el tamaño de SHA1 deseados o que no se modifique, y no se dejará en un estado intermedio irrecuperable. Si el proceso se interrumpe durante la aplicación de parches, es posible que el archivo de destino esté en un estado intermedio. Existe una copia en la partición de caché, por lo que reiniciar la actualización puede actualizar el archivo correctamente.
Se admite una sintaxis especial para tratar el contenido de las particiones del dispositivo de tecnología de memoria (MTD) como archivos, lo que permite aplicar parches a particiones sin procesar, como el inicio. Para leer una partición de MTD, debes saber cuántos datos deseas leer, ya que la partición no tiene un concepto de fin de archivo. Puedes usar la cadena "MTD:partition:size_1:sha1_1:size_2: sha1_2" como nombre de archivo para leer la partición determinada. Debes especificar al menos un par (size, sha-1). Puedes especificar más de uno si hay varias posibilidades para lo que esperas leer.
-
apply_patch_check(filename, sha1[, sha1, ...])
-
Muestra verdadero si el contenido de filename o la copia temporal en la partición de caché
(si está presente) tiene una suma de comprobación SHA1 igual a uno de los valores de sha1 dados.
Los valores de sha1 se especifican como 40 dígitos hexadecimales. Esta función difiere de
sha1_check(read_file(filename), sha1 [, ...])
en que sabe verificar la copia de la partición de caché, por lo queapply_patch_check()
se realizará correctamente, incluso si el archivo se dañó debido a unaapply_patch() update
interrumpida. apply_patch_space(bytes)
- Muestra verdadero si hay al menos bytes de espacio en el búfer de intercambio disponibles para aplicar parches binarios.
-
concat(expr[, expr, ...])
- Evalúa cada expresión y las concatena. El operador + es azúcar sintáctico para esta función en el caso especial de dos argumentos (pero el formato de la función puede tomar cualquier cantidad de expresiones). Las expresiones deben ser cadenas; no se pueden concatenar objetos blob.
-
file_getprop(filename, key)
-
Lee el nombre de archivo determinado, lo interpreta como un archivo de propiedades (p.ej.,
/system/build.prop
) y muestra el valor de la clave determinada , o la cadena vacía si no está presente la clave. -
format(fs_type, partition_type, location, fs_size, mount_point)
-
Vuelve a formatear una partición determinada. Tipos de particiones admitidos:
- fs_type="yaffs2" y partition_type="MTD". La ubicación debe ser el nombre de la partición de MTD. Allí se construye un sistema de archivos yaffs2 vacío. Los argumentos restantes no se usan.
- fs_type="ext4" y partition_type="EMMC". La ubicación debe ser el archivo del dispositivo para la partición. Allí se construye un sistema de archivos ext4 vacío. Si fs_size es cero, el sistema de archivos ocupa toda la partición. Si fs_size es un número positivo, el sistema de archivos toma los primeros fs_size bytes de la partición. Si fs_size es un número negativo, el sistema de archivos toma todo, excepto los últimos |fs_size| bytes de la partición.
- fs_type="f2fs" y partition_type="EMMC". La ubicación debe ser el archivo del dispositivo para la partición. fs_size debe ser un número no negativo. Si fs_size es cero, el sistema de archivos ocupa toda la partición. Si fs_size es un número positivo, el sistema de archivos toma los primeros fs_size bytes de la partición.
- mount_point debe ser el punto de activación futuro para el sistema de archivos.
getprop(key)
- Muestra el valor de la propiedad del sistema clave (o la cadena vacía, si no está definida). Los valores de las propiedades del sistema que define la partición de recuperación no son necesariamente los mismos que los del sistema principal. Esta función muestra el valor en recuperación.
-
greater_than_int(a, b)
- Muestra verdadero si y solo si (iff) a (interpretado como un número entero) es mayor que b (interpretado como un número entero).
-
ifelse(cond, e1[, e2])
- Evalúa cond y, si es verdadero, evalúa y muestra el valor de e1. De lo contrario, evalúa y muestra e2 (si está presente). La construcción "if ... else ... then ... endif" es solo azúcar sintáctico para esta función.
is_mounted(mount_point)
- Muestra verdadero si hay un sistema de archivos activado en mount_point.
-
is_substring(needle, haystack)
- Devuelve verdadero si y solo si aguja es una subcadena de pajarero.
-
less_than_int(a, b)
- Muestra verdadero si a (interpretado como un número entero) es menor que b (interpretado como un número entero).
-
mount(fs_type, partition_type, name, mount_point)
- Activa un sistema de archivos de fs_type en mount_point. partition_type debe ser uno de los siguientes:
-
MTD. Name es el nombre de una partición MTD (p.ej., system, userdata; consulta
/proc/mtd
en el dispositivo para obtener una lista completa). - EMMC:
La recuperación no activa ningún sistema de archivos de forma predeterminada (excepto la tarjeta SD si el usuario realiza una instalación manual de un paquete desde la tarjeta SD). Tu secuencia de comandos debe activar las particiones que necesite modificar.
-
MTD. Name es el nombre de una partición MTD (p.ej., system, userdata; consulta
-
package_extract_dir(package_dir, dest_dir)
- Extrae todos los archivos del paquete debajo de package_dir y los escribe en el árbol correspondiente debajo de dest_dir. Se reemplazarán los archivos existentes.
-
package_extract_file(package_file[, dest_file])
- Extrae un solo package_file del paquete de actualización y lo escribe en dest_file, reemplazando los archivos existentes si es necesario. Sin el argumento dest_file, muestra el contenido del archivo del paquete como un blob binario.
read_file(filename)
- Lee filename y muestra su contenido como un blob binario.
-
run_program(path[, arg, ...])
- Ejecuta el objeto binario en path y pasa los arg. Muestra el estado de salida del programa.
set_progress(frac)
-
Establece la posición del medidor de progreso dentro del fragmento definido por la llamada a
show_progress()
más reciente. frac debe estar en el rango [0.0, 1.0]. El medidor de progreso nunca retrocede; se ignoran los intentos de hacerlo. -
sha1_check(blob[, sha1])
-
El argumento blob es un blob del tipo que muestra
read_file()
o la forma de un argumento depackage_extract_file()
. Sin argumentos sha1, esta función muestra el hash SHA1 del blob (como una cadena hexadecimal de 40 dígitos). Con uno o más argumentos sha1, esta función muestra el hash SHA1 si es igual a uno de los argumentos o la cadena vacía si no es igual a ninguno de ellos. -
show_progress(frac, secs)
-
Avanza el medidor de progreso en la siguiente frac de su longitud durante los
secs segundos (debe ser un número entero). secs puede ser 0, en cuyo caso el medidor
no avanza automáticamente, sino con la función
set_progress()
definida anteriormente. sleep(secs)
- Suspende la unidad durante secs segundos (debe ser un número entero).
-
stdout(expr[, expr, ...])
- Evalúa cada expresión y vuelca su valor en stdout. Es útil para depurar.
-
tune2fs(device[, arg, …])
- Ajusta los parámetros ajustables args en el dispositivo.
ui_print([text, ...])
- Concatena todos los argumentos text y los imprime en la IU (donde será visible si el usuario activó la visualización de texto).
unmount(mount_point)
- Desactiva el sistema de archivos activado en mount_point.
-
wipe_block_device(block_dev, len)
- Limpia los len bytes del dispositivo de almacenamiento en bloque determinado block_dev.
wipe_cache()
- Hace que se borre la partición de caché al final de una instalación correcta.
-
write_raw_image(filename_or_blob, partition)
-
Escribe la imagen en filename_or_blob en la partición de MTD.
filename_or_blob puede ser una cadena que nombre un archivo local o un argumento con valor de BLOB que contenga los datos que se escribirán. Para copiar un archivo del paquete OTA a una partición, usa lo siguiente:
write_raw_image(package_extract_file("zip_filename"), "partition_name");
Nota: Antes de Android 4.1, solo se aceptaban nombres de archivo, por lo que, para lograrlo, primero se debían descomprimir los datos en un archivo local temporal.