¿Google usó actualizaciones OTA A/B en algún dispositivo?
Sí. El nombre de marketing de las actualizaciones A/B es actualizaciones sin interrupciones. 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 de código de plataforma necesaria es pública en Android 7.1 y versiones posteriores.
¿Por qué las OTA A/B son mejores?
Las actualizaciones OTA A/B proporcionan 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: a partir de mayo de 2017, el 95% de los propietarios de Pixel ejecutan 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 se actualizan antes que los de Nexus. Los errores de actualización de bloques durante una actualización inalámbrica ya no hacen que el dispositivo no se inicie. Hasta que la nueva imagen del sistema se inicie correctamente, Android retiene 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 que contienen código de bytes Dalvik portátil. Un archivo .odex (.dex optimizado) se encuentra separado del archivo .apk y puede contener código máquina específico del dispositivo. Si hay un archivo .odex disponible, Android puede ejecutar aplicaciones a velocidades compiladas con anticipación 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 (2755792836 bytes), el desglose de los elementos que más contribuyen al tamaño general de la imagen del sistema por tipo de archivo es el siguiente:
.odex | 139,177,0312 bytes | 50.5% |
.apk | 846878259 bytes | 30.7% |
.so (código C/C++ nativo) | 202162479 bytes | 7.3% |
Archivos .oat o imágenes .art | 163892188 bytes | 5.9% |
Fuentes | 38,952,361 bytes | 1.4% |
Datos de configuración regional de ICU | 274,686,87 bytes | 0.9% |
Estas cifras también son similares para otros dispositivos, por lo que, en dispositivos Nexus o 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 inicio. El almacenamiento real que se usa con ext4 A/B es idéntico al de SquashFS A/B, porque si usáramos SquashFS, habríamos enviado los archivos .odex preseleccionados en system_a en lugar de system_b.
¿No significa que copiar archivos .odex en /data implica que se pierde el espacio guardado en /system en /data?
No exactamente. En Pixel, la mayor parte del espacio que ocupan los archivos .odex es para las apps, que suelen estar 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 perfiles cuando el usuario usa cada app (por lo que no se requiere espacio para las apps que no usa). Para obtener más información, consulta la charla de Google I/O 2016 The Evolution of Art.
La comparación es difícil por varios motivos clave:
-
Las apps que actualiza Google Play siempre tuvieron sus archivos .odex en
/data
en cuanto reciben 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 solo optimiza el código crítico de rendimiento).
Para obtener detalles sobre las opciones de ajuste disponibles para los OEMs, consulta Cómo configurar ART.
¿No hay dos copias de los archivos .odex en /data?
Es un poco más complicado. Después de escribir la nueva imagen del sistema, la nueva versión de dex2oat se ejecuta 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 están en /data
al mismo tiempo.
El código en OtaDexoptService (frameworks/base/+/main/services/core/java/com/android/server/pm/OtaDexoptService.java
) llama a getAvailableSpace
antes de optimizar cada paquete para evitar el exceso de /data
. Ten en cuenta que disponible aquí sigue siendo conservador: es la cantidad de espacio que queda antes de alcanzar el umbral de espacio bajo habitual 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 está cerca de llenar el espacio disponible (como se acaba de describir), se quitan los archivos .odex que pertenecen a las apps que no se usan. Ese es otro caso sin 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 sistema nuevo y ya no necesite los archivos .odex del sistema anterior. PackageManager controla esto: (frameworks/base/+/main/services/core/java/com/android/server/pm/PackageManagerService.java#7215
). Después de que el sistema nuevo se haya iniciado correctamente, installd
(frameworks/native/+/main/cmds/installd/dexopt.cpp#2422
) puede quitar los archivos .odex que usaba el sistema anterior y devolver 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 tienes mucho espacio libre en
/data
de todos modos. Excepto durante una actualización, solo hay una copia. Y, como parte de las funciones de robustez general de ART, nunca llenará /data
con archivos .odex (porque eso también sería un problema en un sistema que no sea A/B).
¿No aumenta el desgaste de la memoria flash con toda esta escritura y copia?
Solo se vuelve a escribir una pequeña parte de la memoria flash: una actualización completa del sistema de Pixel escribe alrededor de 2.3 GiB. (Las apps también se vuelven a compilar, pero eso también es cierto para los dispositivos que no son A/B). Tradicionalmente, las actualizaciones 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 actualización de dos particiones del sistema aumenta el tiempo de actualización de fábrica?
No. Pixel no aumentó el tamaño de la imagen del sistema (solo dividió el espacio en dos particiones).
¿No hace que el reinicio después del restablecimiento de la configuración de fábrica sea lento mantener los archivos .odex en B?
Sí. Si realmente usaste un dispositivo, recibiste una actualización OTA y restableciste la configuración de fábrica, el primer reinicio será más lento de lo que sería de otra manera (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 pueden copiar en /data
. Esa es la compensación.
El restablecimiento de datos de fábrica debe ser una operación poco frecuente en comparación con el inicio normal, por lo que el tiempo que se tarda es menos importante. (Esto no afecta a los usuarios ni a los revisores que obtienen su dispositivo de la fábrica, ya que, en ese caso, la partición B está disponible). El uso del compilador JIT significa que no es necesario volver a compilar todo, por lo que no es tan malo como podrías pensar. También es posible marcar apps como necesarias para la compilación previa con coreApp="true"
en el manifiesto: (frameworks/base/+/main/packages/SystemUI/AndroidManifest.xml#23
). Actualmente, system_server
usa esto porque no se permite JIT por motivos de seguridad.
¿No hace que el reinicio después de una actualización inalámbrica sea lento mantener los archivos .odex en /data en lugar de /system?
No. Como se explicó anteriormente, el nuevo dex2oat se ejecuta mientras la imagen del sistema anterior aún se está ejecutando para generar los archivos que necesitará el sistema nuevo. La actualización no se considera disponible hasta que se realiza ese trabajo.
¿Podemos (debemos) enviar un dispositivo A/B de 32 GiB? 16 GiB? 8 GiB?
32 GiB funciona bien, como se demostró en Pixel, y 320 MiB de 16 GiB significa una reducción del 2%. Del mismo modo, 320 MiB de 8 GiB es 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 es casi el 10% del espacio total disponible.
¿AVB2.0 requiere actualizaciones OTA A/B?
No. El inicio verificado de Android siempre requirió actualizaciones basadas en bloques, pero no necesariamente actualizaciones A/B.
¿Los OTA A/B requieren AVB2.0?
No.
¿Las actualizaciones OTA A/B infringen la protección de reversión de AVB2.0?
No. Hay cierta confusión aquí porque, si un sistema A/B no se inicia en la nueva imagen del sistema, (después de una cantidad de reintentos determinados por el bootloader) volverá automáticamente a la imagen del sistema "anterior". Sin embargo, el punto clave aquí es que "anterior" en el sentido de A/B en realidad sigue siendo la imagen del sistema "actual". En cuanto el dispositivo inicia correctamente una imagen nueva, se activa la protección de reversión y se garantiza que no puedas volver atrás. Sin embargo, hasta que se inicie correctamente la imagen nueva, la protección contra la reversión no la considerará la imagen del sistema actual.
Si instalas una actualización mientras el sistema está en ejecución, ¿no es 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, ocurre lo contrario. Como el usuario sigue usando su dispositivo, el objetivo es que el impacto sea lo más bajo posible, por lo que la actualización es lenta de forma deliberada. 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 o reanudación de la actualización, y el cliente puede usarla para pausar la actualización si el usuario comienza a usar el dispositivo y reanudarla cuando el dispositivo vuelva a estar inactivo.
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 compilación previa de los archivos .dex. Estas dos fases son bastante diferentes en términos del impacto en el rendimiento. La primera fase es la E/S simple. Esto requiere pocos recursos (RAM, CPU, E/S) porque solo copia bloques lentamente.
La segunda fase ejecuta dex2oat para precompilar la nueva imagen del sistema. Esto, por supuesto, tiene límites menos claros en sus requisitos porque compila apps reales. Y, obviamente, compilar una app grande y compleja requiere mucho más trabajo que compilar una app pequeña y simple. En cambio, en la fase 1, no hay bloques de disco que sean más grandes o más complejos que otros.
El proceso es similar al que se realiza cuando Google Play instala una actualización de una 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 que inicia el usuario, pero es posible que lo haga en el futuro. En el caso de que el usuario solicite de forma explícita que se instale la actualización o esté mirando la pantalla de progreso de la actualización, priorizaremos el trabajo de actualización con la suposición de que está esperando que finalice de forma activa.
¿Qué sucede si no se puede aplicar una actualización?
Con las actualizaciones que no son A/B, si no se aplicaba una actualización, el usuario generalmente se quedaba con un dispositivo inutilizable. La única excepción era si la falla se producí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 aplica una actualización, esto no afecta al sistema que se está ejecutando. La actualización se puede volver a intentar más adelante.