Cómo implementar actualizaciones OTA

Para implementar las actualizaciones inalámbricas, 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 inalámbrica 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 que se actualicen a través de una OTA deben poder actualizarse mientras se inicia el sistema principal (y no se actualiza 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 que se inició de forma correcta.

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 la HAL de control de inicio, actualiza la ranura de inicio que no está en uso, cambia la ranura activa con la HAL y se reinicia en 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, incluidas las siguientes:

  • Los nombres de las particiones deben incluir un sufijo que identifique qué particiones pertenecen a una ranura en particular en el bootloader. Para cada partición, hay una variable has-slot:partition base name correspondiente con un valor de yes. Las ranuras se nombran alfabéticamente como a, b, c, etc., que corresponden a las 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.

  • La HAL del control de inicio restablece el valor de slot-retry-count a un valor positivo (generalmente 3), mediante la devolución de llamada setActiveBootSlot o el comando fastboot set_active. Cuando se modifica una partición que forma parte de una ranura, el bootloader borra el mensaje “se inició con éxito” y restablece el recuento de reintentos de la ranura.

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

Flujo de ranuras del bootloader
Figura 1: Flujo de ranuras del bootloader
  1. Determina qué ranura intentar. No intentes cargar una ranura marcada 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 horario disponible diferente que no esté marcado como unbootable y esté marcado 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 e incluye la ruta para la partición del sistema correcta en la línea de comandos del kernel.

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

  5. Arranque. Si no está marcada como slot-successful, disminuye la cantidad de slot-retry-count.

La utilidad fastboot determina qué partición escribir en la memoria flash cuando se ejecuta cualquier comando de escritura en la memoria flash. 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 manera de borrar slot-unbootable).

Dispositivos sin actualizaciones A/B

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

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

  • El bootloader debe 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 la radio en la memoria flash. Esto se puede lograr de dos maneras:

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

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