Reduce el tamaño de la actualización OTA

En esta página, se describen los cambios que se agregaron al AOSP para reducir los cambios innecesarios en los archivos entre compilaciones. Los implementadores de dispositivos que mantienen sus propios sistemas de compilación pueden usar esta información como guía para reducir el tamaño de sus actualizaciones inalámbricas (OTA).

En ocasiones, las actualizaciones OTA de Android contienen archivos modificados que no corresponden a cambios en el código. En realidad, son artefactos del sistema de compilación. Esto puede ocurrir cuando el mismo código, compilado en diferentes momentos, desde diferentes directorios o en diferentes máquinas, produce una gran cantidad de archivos modificados. Estos archivos adicionales aumentan el tamaño de un parche de OTA y dificultan la determinación de qué código cambió.

Para que el contenido de las OTA sea más transparente, el AOSP incluye cambios en el sistema de compilación diseñados para reducir el tamaño de los parches de OTA. Se eliminaron los cambios innecesarios en los archivos entre compilaciones, y solo los archivos relacionados con parches se incluyen en las actualizaciones OTA. El AOSP también incluye una herramienta de comparación de compilaciones, que filtra los cambios comunes en los archivos relacionados con la compilación para proporcionar una comparación más clara de los archivos de compilación, y una herramienta de asignación de bloques, que te ayuda a mantener la asignación de bloques de manera coherente.

Un sistema de compilación puede crear parches innecesariamente grandes de varias maneras. Para mitigar este problema, en Android 8.0 y versiones posteriores, se implementaron nuevas funciones para reducir el tamaño del parche de cada diferencia de archivo. Entre las mejoras que redujeron el tamaño de los paquetes de actualización OTA, se incluyen las siguientes:

  • Uso de ZSTD, un algoritmo de compresión sin pérdida de propósito genérico para imágenes completas en actualizaciones de dispositivos que no son A/B ZSTD se puede personalizar para obtener índices de compresión más altos si se aumenta el nivel de compresión. El nivel de compresión se establece durante el tiempo de generación de la OTA y se puede configurar pasando la marca --vabc_compression_param=zstd,$COMPRESSION_LEVEL.
  • Aumentar el tamaño de la ventana de compresión que se usa durante la OTA El tamaño máximo de la ventana de compresión se puede establecer personalizando el parámetro de compilación en el archivo .mk de un dispositivo. Esta variable se establece como PRODUCT_VIRTUAL_AB_COMPRESSION_FACTOR := 262144.
  • Uso de la recompresión de Puffin, una herramienta de aplicación de parches determinística para flujos de deflate, que controla las funciones de compresión y de diferenciación para la generación de actualizaciones OTA de pruebas A/B.
  • Cambios en el uso de la herramienta de generación de deltas, como la forma en que se usa la biblioteca bsdiff para comprimir parches. En Android 9 y versiones posteriores, la herramienta bsdiff selecciona el algoritmo de compresión que proporcionaría los mejores resultados de compresión para un parche.
  • Las mejoras en update_engine dieron como resultado un menor consumo de memoria cuando se aplican parches para las actualizaciones de dispositivos A/B.

En las siguientes secciones, se analizan varios problemas que afectan los tamaños de las actualizaciones OTA, sus soluciones y ejemplos de implementación en AOSP.

Orden de los archivos

Problema: Los sistemas de archivos no garantizan un orden de archivos cuando se solicita una lista de archivos en un directorio, aunque suele ser el mismo para la misma confirmación. Herramientas como ls ordenan los resultados de forma predeterminada, pero la función de comodín que usan comandos como find y make no los ordena. Antes de usar estas herramientas, debes ordenar los resultados.

Solución: Cuando uses herramientas como find y make con la función de comodín, ordena el resultado de estos comandos antes de usarlos. Cuando uses $(wildcard) o $(shell find) en archivos Android.mk, ordénalos también. Algunas herramientas, como Java, ordenan las entradas, por lo que, antes de ordenar los archivos, verifica que la herramienta que usas no lo haya hecho ya.

Ejemplos: Se corrigieron muchas instancias en el sistema de compilación principal con la macro all-*-files-under integrada, que incluye all-cpp-files-under (ya que varias definiciones se distribuyeron en otros archivos make). Para obtener más información, consulta los siguientes recursos:

Directorio de compilación

Problema: Cambiar el directorio en el que se compilan los elementos puede hacer que los objetos binarios sean diferentes. La mayoría de las rutas de la compilación de Android son relativas, por lo que __FILE__ en C/C++ no es un problema. Sin embargo, los símbolos de depuración codifican la ruta de acceso completa de forma predeterminada, y el .note.gnu.build-id se genera a partir del hash del archivo binario previo a la eliminación, por lo que cambiará si cambian los símbolos de depuración.

Solución: AOSP ahora hace que las rutas de depuración sean relativas. Para obtener más detalles, consulta CL: https://android.googlesource.com/platform/build/+/6a66a887baadc9eb3d0d60e26f748b8453e27a02.

Marcas de tiempo

Problema: Las marcas de tiempo en el resultado de la compilación generan cambios innecesarios en los archivos. Es probable que esto suceda en las siguientes ubicaciones:

  • Macros __DATE__/__TIME__/__TIMESTAMP__ en código C o C++
  • Marcas de tiempo incorporadas en archivos basados en ZIP

Soluciones o ejemplos: Para quitar las marcas de tiempo del resultado de la compilación, usa las instrucciones que se indican a continuación en __DATE__/__TIME__/__TIMESTAMP__ en C/C++ y en Marcas de tiempo incorporadas en archivos.

__DATE__/__TIME__/__TIMESTAMP__ en C/C++

Estas macros siempre producen resultados diferentes para diferentes compilaciones, por lo que no debes usarlas. Estas son algunas opciones para eliminar estas macros:

Marcas de tiempo incorporadas en archivos (zip, jar)

Android 7.0 solucionó el problema de las marcas de tiempo incorporadas en los archivos zip agregando -X a todos los usos del comando zip. De esta manera, se quitaron el UID/GID del compilador y la marca de tiempo extendida de Unix del archivo ZIP.

Una nueva herramienta, ziptime (ubicada en /platform/build/+/android16-release/tools/ziptime/), restablece las marcas de tiempo normales en los encabezados zip. Para obtener más información, consulta el archivo README.

La herramienta signapk establece marcas de tiempo para los archivos APK que pueden variar según la zona horaria del servidor. Para obtener más información, consulta el CL https://android.googlesource.com/platform/build/+/6c41036bcf35fe39162b50d27533f0f3bfab3028.

La herramienta signapk establece marcas de tiempo para los archivos APK que pueden variar según la zona horaria del servidor. Para obtener más detalles, consulta el CL https://android.googlesource.com/platform/build/+/6c41036bcf35fe39162b50d27533f0f3bfab3028.

Cadenas de versión

Problema: Las cadenas de versión del APK a menudo tenían el valor BUILD_NUMBER agregado a sus versiones codificadas. Incluso si no se modificara nada más en un APK, este seguiría siendo diferente.

Solución: Quita el número de compilación de la cadena de versión del APK.

Ejemplos:

Habilita el cálculo de veracidad en el dispositivo

Si dm-verity está habilitado en tu dispositivo, las herramientas de OTA seleccionan automáticamente tu configuración de verity y habilitan el cálculo de verity en el dispositivo. Esto permite que los bloques de veracidad se calculen en dispositivos Android, en lugar de almacenarse como bytes sin procesar en tu paquete OTA. Los bloques de verificación pueden usar aproximadamente 16 MB para una partición de 2 GB.

Sin embargo, calcular la veracidad en el dispositivo puede llevar mucho tiempo. Específicamente, el código de corrección de errores hacia adelante puede tardar mucho tiempo. En los dispositivos Pixel, suele tardar hasta 10 minutos. En dispositivos de gama baja, podría tardar más. Si deseas inhabilitar el cálculo de verity integrado en el dispositivo, pero habilitar dm-verity, puedes pasar --disable_fec_computation a la herramienta ota_from_target_files cuando generes una actualización OTA. Esta marca inhabilita el cálculo de la integridad en el dispositivo durante las actualizaciones inalámbricas. Disminuye el tiempo de instalación de la OTA, pero aumenta el tamaño del paquete de la OTA. Si tu dispositivo no tiene habilitado dm-verity, pasar esta marca no tendrá ningún efecto.

Herramientas de compilación coherentes

Problema: Las herramientas que generan archivos instalados deben ser coherentes (una entrada determinada siempre debe producir la misma salida).

Soluciones o ejemplos: Se requirieron cambios en las siguientes herramientas de compilación:

Cómo usar la herramienta de comparación de compilaciones

En los casos en los que no es posible eliminar los cambios en los archivos relacionados con la compilación, el AOSP incluye una herramienta de comparación de compilaciones, target_files_diff.py para comparar dos paquetes de archivos. Esta herramienta realiza una comparación recursiva entre dos compilaciones, excluyendo los cambios comunes relacionados con la compilación, como los siguientes:

  • Cambios esperados en el resultado de la compilación (por ejemplo, debido a un cambio en el número de compilación)
  • Cambios debido a problemas conocidos en el sistema de compilación actual

Para usar la herramienta de comparación de compilaciones, ejecuta el siguiente comando:

target_files_diff.py dir1 dir2

dir1 y dir2 son directorios base que contienen los archivos de destino extraídos para cada compilación.

Mantén la asignación de bloques de forma coherente

En el caso de un archivo determinado, aunque su contenido siga siendo el mismo entre dos compilaciones, es posible que hayan cambiado los bloques reales que contienen los datos. Como resultado, el actualizador debe realizar E/S innecesarias para mover los bloques en una actualización OTA.

En una actualización OTA de A/B virtual, las E/S innecesarias pueden aumentar considerablemente el espacio de almacenamiento necesario para guardar la instantánea de copia en escritura. En una actualización OTA que no es A/B, mover los bloques para una actualización OTA contribuye al tiempo de actualización, ya que hay más E/S debido a los movimientos de bloques.

Para solucionar este problema, en Android 7.0, Google extendió la herramienta make_ext4fs para mantener la asignación de bloques coherente en todas las compilaciones. La herramienta make_ext4fs acepta una marca -d base_fs opcional que intenta asignar archivos a los mismos bloques cuando se genera una imagen ext4. Puedes extraer los archivos de asignación de bloques (como los archivos de mapa base_fs) del archivo zip de los archivos de destino de una compilación anterior. Para cada partición ext4, hay un archivo .map en el directorio IMAGES (por ejemplo, IMAGES/system.map corresponde a la partición system). Luego, estos archivos base_fs se pueden registrar y especificar a través de PRODUCT_<partition>_BASE_FS_PATH, como en este ejemplo:

  PRODUCT_SYSTEM_BASE_FS_PATH := path/to/base_fs_files/base_system.map
  PRODUCT_SYSTEM_EXT_BASE_FS_PATH := path/to/base_fs_files/base_system_ext.map
  PRODUCT_VENDOR_BASE_FS_PATH := path/to/base_fs_files/base_vendor.map
  PRODUCT_PRODUCT_BASE_FS_PATH := path/to/base_fs_files/base_product.map
  PRODUCT_ODM_BASE_FS_PATH := path/to/base_fs_files/base_odm.map

Si bien esto no ayuda a reducir el tamaño general del paquete de actualización inalámbrica, sí mejora el rendimiento de la actualización inalámbrica, ya que reduce la cantidad de E/S. En el caso de las actualizaciones A/B virtuales, se reduce drásticamente la cantidad de espacio de almacenamiento necesario para aplicar la OTA.

Evita actualizar apps

Además de minimizar las diferencias de compilación, puedes reducir el tamaño de las actualizaciones OTA si excluyes las actualizaciones de las apps que se actualizan a través de las tiendas de aplicaciones. Los APKs suelen comprender una parte significativa de varias particiones en un dispositivo. Incluir las versiones más recientes de las apps que se actualizan en las tiendas de aplicaciones en una actualización OTA puede tener un gran impacto en el tamaño de los paquetes OTA y proporcionar pocos beneficios para el usuario. Cuando los usuarios reciben un paquete OTA, es posible que ya tengan la app actualizada o una versión aún más reciente que recibieron directamente de las tiendas de aplicaciones.