Cómo implementar actualizaciones OTA

Para implementar las actualizaciones inalámbricas (OTA), el bootloader debe poder acceder a un disco RAM de recuperación durante el inicio. Si el dispositivo usa una imagen de recuperación de AOSP no modificada, el bootloader lee los primeros 32 bytes en la partición misc; si los datos coinciden con boot-recovery, el bootloader se inicia en la imagen recovery. Este método permite que cualquier trabajo de recuperación pendiente (por ejemplo, aplicar una actualización OTA o quitar datos) continúe hasta completarse.

Para obtener más información sobre el contenido de un bloque en flash que se usa para las comunicaciones por recuperación y el bootloader, consulta bootable/recovery/bootloader_message/bootloader_message.h.

Dispositivos con actualizaciones A/B

Para admitir actualizaciones inalámbricas en dispositivos que usan actualizaciones A/B, asegúrate de que el bootloader del dispositivo cumpla con los siguientes criterios.

Criterios generales

  • Todas las particiones actualizadas a través de una OTA deben poder actualizarse mientras se inicia el sistema principal (y no actualizarse en la recuperación).

  • Para iniciar la partición system, el bootloader pasa el siguiente valor en la línea de comandos del kernel: ro root=/dev/[node] rootwait init=/init.

  • Es responsabilidad del framework de Android llamar a markBootSuccessful desde la HAL. El bootloader nunca debe marcar una partición como iniciada correctamente.

Compatibilidad con la HAL de control de inicio

El bootloader debe admitir la HAL de boot_control como se define en hardware/libhardware/include/hardware/boot_control.h. El actualizador consulta el HAL de control de inicio, actualiza el espacio de inicio que no está en uso, cambia el espacio activo con el HAL y reinicia el sistema operativo actualizado. Para obtener más información, consulta Cómo implementar la HAL de control de inicio.

Compatibilidad con ranuras

El bootloader debe admitir funciones relacionadas con particiones y ranuras, como las siguientes:

  • Los nombres de las particiones deben incluir un sufijo que identifique qué particiones pertenecen a un espacio en particular en el bootloader. Para cada partición, hay una variable has-slot:partition base name correspondiente con un valor de yes. Los ranuras se nombran alfabéticamente como a, b, c, etc., que corresponden a particiones con el sufijo _a, _b, _c, etc. El bootloader debe informar al sistema operativo qué ranura se inició con la propiedad de línea de comandos androidboot.slot_suffix. Esta propiedad se establece a través de bootconfig para dispositivos que se lanzan con Android 12 o versiones posteriores.

  • El valor de slot-retry-count se restablece a un valor positivo (por lo general, 3), ya sea a través del HAL de control de inicio mediante la devolución de llamada de setActiveBootSlot o a través del comando fastboot set_active. Cuando se modifica una partición que forma parte de un espacio, el bootloader borra el mensaje "Se inició correctamente" y restablece el recuento de reintentos del espacio.

El bootloader también debe determinar qué ranura cargar. En la figura, se muestra un ejemplo de proceso de decisión.

Flujo de ranuras del bootloader
Figura 1: Flujo de ranuras del bootloader
  1. Determina qué ranura intentar. No intentes cargar un espacio marcado como slot-unbootable. Esta ranura debe ser coherente con los valores que muestra fastboot y se denomina ranura actual.

  2. Si el espacio actual no está marcado como slot-successful y tiene un slot-retry-count = 0, márcalo como slot-unbootable. Luego, selecciona un espacio diferente que no esté marcado como unbootable, sino como slot-successful. Este espacio ahora es el seleccionado. Si no hay ninguna ranura disponible, inicia el proceso de recuperación o muestra un mensaje de error significativo al usuario.

  3. Selecciona el boot.img adecuado y, luego, incluye la ruta de acceso para corregir la partición del sistema en la línea de comandos del kernel.

  4. Completa el parámetro slot_suffix de la línea de comandos del kernel.

  5. Inicio. Si no está marcado como slot-successful, disminuye slot-retry-count.

La utilidad fastboot determina qué partición se debe actualizar cuando se ejecutan comandos de actualización. Por ejemplo, ejecutar el comando fastboot flash system system.img primero consulta la variable current-slot y, luego, concatena el resultado al sistema para generar el nombre de la partición que se debe escribir en la memoria flash (system_a, system_b, etc.).

Cuando configuras la ranura actual con el comando set_active de fastboot o el comando setActiveBootSlot de la HAL del control de inicio, el bootloader debe actualizar la ranura actual, borrar slot-unbootable y slot-successful, y restablecer el recuento de reintentos (esta es la única forma de borrar slot-unbootable).

Dispositivos sin actualizaciones A/B

Para admitir actualizaciones inalámbricas en dispositivos que no usan actualizaciones A/B (consulta Dispositivos actualizables que no son A/B), asegúrate de que el bootloader del dispositivo cumpla con los siguientes criterios.

  • La partición recovery debe contener una imagen que pueda leer una imagen del sistema desde alguna partición compatible (cache, userdata) y escribirla en la partición system.

  • El bootloader debería admitir el inicio directo en el modo de recuperación.

  • Si se admiten actualizaciones de imágenes de radio, la partición recovery también debería poder escribir en la radio. Esto se puede lograr de dos maneras:

    • El bootloader hace un parpadeo en la radio. En este caso, debería ser posible reiniciar desde la partición de recuperación al bootloader para completar la actualización.

    • La imagen de recuperación hace parpadear la radio. Esta funcionalidad se puede proporcionar como una biblioteca o utilidad binaria.