¿Google usó OTA A/B en algún dispositivo?
Sí. El nombre de marketing para las actualizaciones A/B es actualizaciones sin inconvenientes. Los teléfonos Pixel y Pixel XL de octubre de 2016 se enviaron con A/B, y todas las Chromebooks usan la misma implementación de update_engine
de A/B. La implementación del código de la plataforma necesario es pública en Android 7.1 y versiones posteriores.
¿Por qué las OTA A/B son mejores?
Las OTA A/B brindan una mejor experiencia del usuario cuando se realizan actualizaciones. Las mediciones de las actualizaciones de seguridad mensuales muestran que esta función ya demostró ser un éxito: en mayo de 2017, el 95% de los propietarios de Pixel ejecutaban la actualización de seguridad más reciente después de un mes, en comparación con el 87% de los usuarios de Nexus, y los usuarios de Pixel realizan las actualizaciones antes que los usuarios de Nexus. Las fallas en la actualización de bloques durante una OTA ya no provocan que el dispositivo no se inicie. Hasta que la nueva imagen del sistema se haya iniciado correctamente, Android conserva la capacidad de volver a la imagen del sistema anterior que funcionaba.
¿Qué es system_other?
Las aplicaciones se almacenan en archivos .apk, que en realidad son archivos ZIP. Cada archivo .apk contiene uno o más archivos .dex con código de bytes Dalvik portátil. Un archivo .odex (archivo .dex optimizado) se encuentra separado del archivo .apk y puede contener código de máquina específico para el dispositivo. Si hay un archivo .odex disponible, Android puede ejecutar aplicaciones a velocidades de compilación anticipada sin tener que esperar a que se compile el código cada vez que se inicia la aplicación. Un archivo .odex no es estrictamente necesario: Android puede ejecutar el código .dex directamente a través de la interpretación o la compilación Just-In-Time (JIT), pero un archivo .odex proporciona la mejor combinación de velocidad de inicio y velocidad de tiempo de ejecución si hay espacio disponible.
Ejemplo: Para el archivo installed-files.txt de un Nexus 6P con Android 7.1 y un tamaño total de la imagen del sistema de 2628 MiB (2,755,792,836 bytes), el desglose de los mayores contribuyentes al tamaño general de la imagen del sistema por tipo de archivo es el siguiente:
.odex | 1,391,770,312 bytes | 50.5% |
.apk | 846878259 bytes | 30.7% |
.so (código C/C++ nativo) | 202162479 bytes | 7.3% |
Imágenes .art/archivos .oat | 163892188 bytes | 5.9% |
Fuentes | 38952361 bytes | 1.4% |
Datos de configuración regional de ICU | 27468687 bytes | 0.9% |
Estas cifras son similares para otros dispositivos también, por lo que, en los dispositivos Nexus y Pixel, los archivos .odex ocupan aproximadamente la mitad de la partición del sistema. Esto significaba que podíamos seguir usando ext4, pero escribir los archivos .odex en la partición B en la fábrica y, luego, copiarlos en /data
en el primer arranque. El almacenamiento real que se usa con ext4 A/B es idéntico al de SquashFS A/B, ya que, si hubiéramos usado SquashFS, habríamos enviado los archivos .odex preoptimizados en system_a en lugar de system_b.
¿Copiar archivos .odex a /data no significa que el espacio ahorrado en /system se pierde en /data?
No exactamente. En Pixel, la mayor parte del espacio que ocupan los archivos .odex es para las apps, que suelen existir en /data
. Estas apps reciben actualizaciones de Google Play, por lo que los archivos .apk y .odex de la imagen del sistema no se usan durante la mayor parte de la vida útil del dispositivo. Estos archivos se pueden excluir por completo y reemplazar por archivos .odex pequeños basados en el perfil cuando el usuario usa cada app (por lo que no se requiere espacio para las apps que el usuario no usa). Para obtener más detalles, consulta la presentación de Google I/O 2016 The Evolution of Art.
La comparación es difícil por varios motivos clave:
-
Las apps actualizadas por Google Play siempre tuvieron sus archivos .odex en
/data
tan pronto como recibieron su primera actualización. - Las apps que el usuario no ejecuta no necesitan un archivo .odex.
- La compilación basada en perfiles genera archivos .odex más pequeños que la compilación anticipada (porque la primera optimiza solo el código crítico para el rendimiento).
Para obtener detalles sobre las opciones de ajuste disponibles para los OEM, consulta Cómo configurar ART.
¿No hay dos copias de los archivos .odex en /data?
Es un poco más complicado… Después de que se escribe la nueva imagen del sistema, se ejecuta la nueva versión de dex2oat en los nuevos archivos .dex para generar los nuevos archivos .odex. Esto ocurre mientras el sistema anterior aún se está ejecutando, por lo que los archivos .odex antiguos y nuevos se encuentran en /data
al mismo tiempo.
El código de OtaDexoptService (frameworks/base/+/android16-release/services/core/java/com/android/server/pm/OtaDexoptService.java
) llama a getAvailableSpace
antes de optimizar cada paquete para evitar el llenado excesivo de /data
. Ten en cuenta que la opción Disponible aquí sigue siendo conservadora: es la cantidad de espacio restante antes de alcanzar el umbral habitual de espacio bajo del sistema (medido como un porcentaje y un recuento de bytes). Por lo tanto, si /data
está lleno, no habrá dos copias de cada archivo .odex. El mismo código también tiene un BULK_DELETE_THRESHOLD: Si el dispositivo se acerca a llenar el espacio disponible (como se acaba de describir), se quitan los archivos .odex que pertenecen a las apps que no se usan. Este es otro caso en el que no hay dos copias de cada archivo .odex.
En el peor de los casos, cuando /data
está completamente lleno, la actualización espera hasta que el dispositivo se reinicie en el nuevo sistema y ya no necesite los archivos .odex del sistema anterior. El PackageManager se encarga de esto: (frameworks/base/+/android16-release/services/core/java/com/android/server/pm/PackageManagerService.java#7215
). Después de que el nuevo sistema se haya iniciado correctamente, installd
(frameworks/native/+/android16-release/cmds/installd/dexopt.cpp#2422
) puede quitar los archivos .odex que usaba el sistema anterior, lo que devuelve el dispositivo al estado estable en el que solo hay una copia.
Por lo tanto, si bien es posible que /data
contenga dos copias de todos los archivos .odex, (a) esto es temporal y (b) solo ocurre si de todos modos tenías mucho espacio libre en /data
. Excepto durante una actualización, solo hay una copia. Además, como parte de las funciones generales de solidez de ART, nunca llenará /data
con archivos .odex de todos modos (porque eso también sería un problema en un sistema que no es A/B).
¿Todo este proceso de escritura y copia no aumenta el desgaste de la memoria flash?
Solo se reescribe una pequeña parte de la memoria flash: una actualización completa del sistema Pixel escribe alrededor de 2.3 GiB. (Las apps también se vuelven a compilar, pero eso también sucede en los dispositivos que no son A/B). Tradicionalmente, las OTA completas basadas en bloques escribían una cantidad similar de datos, por lo que las tasas de desgaste de la memoria flash deberían ser similares.
¿El proceso de escritura en dos particiones del sistema aumenta el tiempo de escritura de fábrica?
No. El tamaño de la imagen del sistema de Pixel no aumentó (solo se dividió el espacio en dos particiones).
¿Mantener los archivos .odex en B no hace que el reinicio después de restablecer la configuración de fábrica sea lento?
Sí. Si realmente usaste un dispositivo, realizaste una actualización OTA y restableciste la configuración de fábrica, el primer reinicio será más lento de lo normal (1 minuto y 40 segundos en comparación con 40 segundos en un Pixel XL) porque los archivos .odex se habrán perdido de B después de la primera actualización OTA y, por lo tanto, no se podrán copiar en /data
. Esa es la compensación.
El restablecimiento de la configuración de fábrica debe ser una operación poco frecuente en comparación con el arranque normal, por lo que el tiempo que lleva es menos importante. (Esto no afecta a los usuarios ni a los revisores que obtienen su dispositivo de fábrica, ya que, en ese caso, la partición B está disponible). El uso del compilador JIT significa que no necesitamos recompilar todo, por lo que no es tan malo como podrías pensar. También es posible marcar las apps como si requirieran compilación anticipada con coreApp="true"
en el manifiesto: (frameworks/base/+/android16-release/packages/SystemUI/AndroidManifest.xml#23
). Actualmente, system_server
usa esta opción porque no se permite la compilación JIT por motivos de seguridad.
¿Mantener los archivos .odex en /data en lugar de /system no hace que el reinicio después de una OTA sea lento?
No. Como se explicó anteriormente, el nuevo dex2oat se ejecuta mientras la imagen del sistema anterior sigue en ejecución para generar los archivos que necesitará el nuevo sistema. La actualización no se considera disponible hasta que se complete ese trabajo.
¿Podemos (deberíamos) enviar un dispositivo A/B de 32 GiB? ¿16 GiB? ¿8 GiB?
32 GiB funciona bien, ya que se probó en Pixel, y 320 MiB de 16 GiB significan una reducción del 2%. Del mismo modo, 320 MiB de 8 GiB representan una reducción del 4%. Obviamente, A/B no sería la opción recomendada en dispositivos con 4 GiB, ya que la sobrecarga de 320 MiB representa casi el 10% del espacio total disponible.
¿AVB2.0 requiere OTA A/B?
No. El inicio verificado de Android siempre requirió actualizaciones basadas en bloques, pero no necesariamente actualizaciones A/B.
¿Las OTA A/B requieren AVB2.0?
No.
¿Las OTA A/B interrumpen la protección contra reversión de AVB2.0?
No. Hay cierta confusión aquí porque, si un sistema A/B no puede iniciar la nueva imagen del sistema, volverá automáticamente (después de una cierta cantidad de reintentos determinados por el cargador de arranque) a la imagen del sistema "anterior". Sin embargo, el punto clave aquí es que "anterior" en el sentido de la prueba A/B sigue siendo la imagen del sistema "actual". En cuanto el dispositivo inicia correctamente una imagen nueva, se activa la protección contra reversión y garantiza que no puedas volver a la versión anterior. Sin embargo, hasta que no hayas iniciado correctamente la nueva imagen, la protección contra reversión no la considerará la imagen del sistema actual.
Si instalas una actualización mientras el sistema se está ejecutando, ¿no es demasiado lento?
Con las actualizaciones que no son A/B, el objetivo es instalar la actualización lo más rápido posible, ya que el usuario está esperando y no puede usar su dispositivo mientras se aplica la actualización. Con las actualizaciones A/B, sucede lo contrario: dado que el usuario sigue usando su dispositivo, el objetivo es que el impacto sea el menor posible, por lo que la actualización es deliberadamente lenta. A través de la lógica del cliente de actualización del sistema Java (que, para Google, es GmsCore, el paquete principal que proporciona GMS), Android también intenta elegir un momento en el que los usuarios no estén usando sus dispositivos. La plataforma admite la pausa y la reanudación de la actualización, y el cliente puede usar esa función para pausar la actualización si el usuario comienza a usar el dispositivo y reanudarla cuando el dispositivo esté inactivo nuevamente.
Hay dos fases durante la actualización OTA, que se muestran claramente en la IU como Paso 1 de 2 y Paso 2 de 2 debajo de la barra de progreso. El paso 1 corresponde a la escritura de los bloques de datos, mientras que el paso 2 es la precompilación de los archivos .dex. Estas dos fases son bastante diferentes en términos de impacto en el rendimiento. La primera fase es la E/S simple. Esto requiere pocos recursos (RAM, CPU, E/S) porque solo se copian bloques lentamente.
En la segunda fase, se ejecuta dex2oat para precompilar la nueva imagen del sistema. Obviamente, esto tiene límites menos claros en sus requisitos porque compila apps reales. Obviamente, compilar una app grande y compleja requiere mucho más trabajo que compilar una app pequeña y simple, mientras que, en la fase 1, no hay bloques de disco más grandes o complejos que otros.
El proceso es similar al que se realiza cuando Google Play instala una actualización de la app en segundo plano antes de mostrar la notificación de 5 apps actualizadas, como se ha hecho durante años.
¿Qué sucede si un usuario está esperando la actualización?
La implementación actual en GmsCore no distingue entre las actualizaciones en segundo plano y las actualizaciones iniciadas por el usuario, pero es posible que lo haga en el futuro. En el caso en que el usuario haya solicitado explícitamente que se instale la actualización o esté mirando la pantalla de progreso de la actualización, priorizaremos el trabajo de actualización suponiendo que está esperando activamente a que finalice.
¿Qué sucede si no se puede aplicar una actualización?
Con las actualizaciones que no son A/B, si una actualización no se aplicaba, el usuario solía quedarse con un dispositivo inutilizable. La única excepción era si la falla ocurría antes de que se iniciara una aplicación (por ejemplo, porque no se pudo verificar el paquete). Con las actualizaciones A/B, si no se puede aplicar una actualización, no se afecta el sistema en ejecución. La actualización se puede volver a intentar más adelante.