Reducción del tamaño de OTA

Esta página describe los cambios agregados a AOSP para reducir los cambios de archivos innecesarios 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).

Las actualizaciones OTA de Android ocasionalmente contienen archivos modificados que no corresponden a cambios de código. En realidad, son artefactos del sistema de compilación. Esto puede ocurrir cuando el mismo código, creado en diferentes momentos, desde diferentes directorios o en diferentes máquinas, produce una gran cantidad de archivos modificados. Dicho exceso de archivos aumenta el tamaño de un parche OTA y dificulta determinar qué código cambió.

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

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

  • Uso de Brotli , un algoritmo de compresión sin pérdida de propósito genérico para imágenes completas en actualizaciones de dispositivos no A/B. Brotli se puede personalizar para optimizar la compresión. En actualizaciones más grandes compuestas de dos o más bloques en el sistema de archivos (por ejemplo, system.img ), los fabricantes de dispositivos o socios pueden agregar sus propios algoritmos de compresión y pueden usar diferentes algoritmos de compresión en diferentes bloques de la misma actualización.
  • Uso de la recompresión de Puffin , una herramienta de aplicación de parches determinista para deflate streams, que maneja las funciones de compresión y diferenciación para la generación de actualizaciones A/B OTA.
  • Cambios en el uso de la herramienta de generación delta, 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 ofrecería los mejores resultados de compresión para un parche.
  • Las mejoras en update_engine dieron como resultado que se consumiera menos memoria cuando se aplicaron parches para actualizaciones de dispositivos A/B.
  • Mejoras en la división de archivos zip grandes para actualizaciones OTA basadas en bloques. Un modo en imgdiff divide archivos APK de gran tamaño, según los nombres de las entradas. Esto produce un parche más pequeño en comparación con la división lineal de archivos y el uso de la herramienta bsdiff para comprimirlos.

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

orden de archivo

Problema : los sistemas de archivos no garantizan un orden de archivos cuando se les solicita una lista de archivos en un directorio, aunque normalmente es lo mismo para el mismo pago. Herramientas como ls ordenan los resultados de forma predeterminada, pero la función comodín utilizada por comandos como find y make no ordena. Antes de utilizar estas herramientas, debe ordenar las salidas.

Solución : cuando utilice herramientas como find y make con la función comodín, ordene la salida de estos comandos antes de utilizarlos. Cuando use $(wildcard) o $(shell find) en archivos Android.mk , ordénelos también. Algunas herramientas, como Java, ordenan las entradas, así que antes de ordenar los archivos, verifique que la herramienta que está utilizando no lo haya hecho ya.

Ejemplos: muchas instancias se corrigieron en el sistema de compilación central utilizando la macro incorporada all-*-files-under , que incluye all-cpp-files-under (ya que varias definiciones se distribuyeron en otros makefiles). Para obtener más información, consulte lo siguiente:

Directorio de compilación

Problema: cambiar el directorio en el que se construyen las cosas puede hacer que los archivos binarios sean diferentes. La mayoría de las rutas en la compilación de Android son rutas 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 binario previamente eliminado, 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 información, consulte CL: https://android.googlesource.com/platform/build/+/6a66a887baadc9eb3d0d60e26f748b8453e27a02 .

Marcas de tiempo

Problema: las marcas de tiempo en la salida de compilación generan cambios de archivo innecesarios. Es probable que esto suceda en los siguientes lugares:

  • __DATE__/__TIME__/__TIMESTAMP__ macros en código C o C++.
  • Marcas de tiempo incrustadas en archivos comprimidos.

Soluciones/Ejemplos: para eliminar las marcas de tiempo de la salida de compilación, use las instrucciones que se proporcionan a continuación en __DATE__/__TIME__/__TIMESTAMP__ en C/C++. y Marcas de tiempo incrustadas en archivos .

__FECHA__/__HORA__/__TIMESTAMP__ en C/C++

Estas macros siempre producen diferentes salidas para diferentes compilaciones, así que no las use. Aquí hay algunas opciones para eliminar estas macros:

Marcas de tiempo incrustadas en archivos (zip, jar)

Android 7.0 solucionó el problema de las marcas de tiempo incrustadas en los archivos zip al agregar -X a todos los usos del comando zip . Esto eliminó el UID/GID del constructor y la marca de tiempo extendida de Unix del archivo zip.

Una nueva herramienta, ziptime (ubicada en /platform/build/+/master/tools/ziptime/ ) restablece las marcas de tiempo normales en los encabezados zip. Para obtener más información, consulte el archivo LÉAME .

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, consulte CL https://android.googlesource.com/platform/build/+/6c41036bcf35fe39162b50d27533f0f3bfab3028 .

Cadenas de versión

Problema: las cadenas de versión de APK a menudo tenían el BUILD_NUMBER agregado a sus versiones codificadas. Incluso si nada más cambiara en un APK, como resultado, el APK seguiría siendo diferente.

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

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

Ejemplos:

Habilitar el cálculo de la veracidad en el dispositivo

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

Sin embargo, calcular la verdad en el dispositivo puede llevar mucho tiempo. Específicamente, el código de corrección de errores de reenvío puede tardar mucho tiempo. En dispositivos de píxeles, suele tardar hasta 10 minutos. En dispositivos de gama baja, podría llevar más tiempo. Si desea deshabilitar el cálculo de verity en el dispositivo, pero aún habilitar dm-verity, puede hacerlo pasando --disable_fec_computation a la herramienta ota_from_target_files al generar una actualización OTA. Este indicador deshabilita el cálculo de la veracidad en el dispositivo durante las actualizaciones OTA. Disminuye el tiempo de instalación de OTA, pero aumenta el tamaño del paquete de OTA. Si su dispositivo no tiene habilitado dm-verity, pasar este indicador no tiene efecto.

Herramientas de construcción consistentes

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

Soluciones/Ejemplos: Se requirieron cambios en las siguientes herramientas de compilación:

Uso de la herramienta de compilación de diferencias

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

  • 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 build diff, ejecute 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.

Mantener la asignación de bloques consistente

Para un archivo determinado, aunque su contenido sigue siendo el mismo entre dos compilaciones, los bloques reales que contienen los datos pueden haber cambiado. Como resultado, el actualizador debe realizar E/S innecesarias para mover los bloques para una actualización OTA.

En una actualización OTA Virtual A/B, la E/S innecesaria puede aumentar considerablemente el espacio de almacenamiento necesario para almacenar la instantánea de copia en escritura. En una actualización OTA no 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 abordar este problema, en Android 7.0, Google amplió la herramienta make_ext4fs para mantener la asignación de bloques consistente en todas las compilaciones. La herramienta make_ext4fs acepta un indicador opcional -d base_fs que intenta asignar archivos a los mismos bloques al generar una imagen ext4 . Puede extraer los archivos de asignación de bloques (como los archivos de asignación 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 del system ). 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 OTA, sí mejora el rendimiento de la actualización OTA al reducir la cantidad de E/S. Para las actualizaciones Virtual A/B, reduce drásticamente la cantidad de espacio de almacenamiento necesario para aplicar la OTA.

Evita actualizar aplicaciones

Además de minimizar las diferencias de compilación, puede reducir el tamaño de las actualizaciones OTA al excluir las actualizaciones de las aplicaciones que obtienen actualizaciones a través de las tiendas de aplicaciones. Los APK a menudo comprenden una parte importante de varias particiones en un dispositivo. Incluir las últimas versiones de las aplicaciones que actualizan las tiendas de aplicaciones en una actualización OTA puede tener un gran impacto en los paquetes OTA y brindar pocos beneficios al usuario. Cuando los usuarios reciben un paquete OTA, es posible que ya tengan la aplicación actualizada, o incluso una versión más nueva, recibida directamente de las tiendas de aplicaciones.