Arquitectura Android – ART vs Dalvik


Para hablar de ART vs DALVIK primero tenemos que remontarnos un poco más abajo en la arquitectura de Android.

La arquitectura de Android no deja de ser como la de cualquier otro sistema operativo funcionando en un ordenador (como Windows, Mac o Linux). Un usario poco ducho en las profundidades de Android vería la arquitectura como la siguiente pila:

Arquitectura Android según un usuario - www.Jarroba.com

El usuario medio tiene en su mano un rectángulo -que bien sabe llamar SmartPhone- y entiende que ejecuta Apps, el resto es «Magia» (es una broma de informáticos 😛 ). El usuario obvia el resto de la arquitectura y es normal pues se abstrae del funcionamiento interno, solo quiere que funcione y punto. Es un usuario que no quiere saber más sobre el funcionamiento, para eso lo ha comprado y lo utiliza como lo tiene que utilizar.

Para alguien que quiera conocer los entresijos de Android la pila de arquitectura anterior se nos queda muy escasa y todo lo que entra dentro de la «Magia» se estiede; es donde millones de personas han trabajado durante decenas de años -pudieramos hablar de casi un siglo- para llevar este rectángulo mágico -Smartphone- al usuario.

Android es un sistema operativo peculiar, pues trabaja sobre un núcreo Linux y todas sus aplicaciones compilan en Java (pero con compilación propia de Android). Igualmente su arquitectura sigue la de cualquier otro ordenador en el mundo:

422px-Computer_abstraction_layers-es.svg

Imagen de arquitectura típica de computadores obtenida de la Wikipedia, del artículo Arquitectura de computadores

Para que comprendas la magnitud que hay por debajo al trabajar con cualquier lenguaje de programación (y al usar las aplicaciones), un dispositivo Android sigue las mismas pautas. Desde lo físico, el Hardware, que es el dispositivo en sí, al Smartphone o Tablet que sueles tener en la mano. Lejos del Hardware, como usuario y desarrollador de aplicaciones Android tan solo trabajaremos con la capa más superficial de la arquitectura de ordenadores, la de “S.O. y aplicaciones”.

Pila de arquitectura Android - www.Jarroba.com

Voy a explicar en detalle la arquitectura Android y cada una de sus partes (la siguiente imagen representa la pila de la arquitectura Android desde la cima que es el nivel de las aplicaciones, hasta la base del Hardware):

  • Aplicaciones: cualquier tipo de aplicación Android. Es la capa que utiliza el usuario.
  • Framework de Android: Acceso al API de Android para reutilizar componentes o modificarlos. Es la capa en la que trabajaremos como desarrolladores Android (trabajaremos con SDK; veremos cómo se utiliza). Todo en esta capa será una representación exacta de la capa HAL.
  • Bibliotecas nativas en C/C++: el desarrollador puede usarlas a través del Framework. Es la capa en la que podremos trabajar como desarrolladores Android a bajo nivel (se trabaja con el NDK y se programa en C/C++).
  • Runtime de Android: bibliotecas del lenguaje Java que se ejecutan sobre:

-Una única instancia en la máquina virtual Dalvik (antigua)

-Sobre el entorno de ejecución Android Runtime (o conocido por sus siglas ART)

  • Comunicación ligada entre procesos (Binder IPC, Inter-Procces Communication): Mecanismo que permite al Framework ir más allá de un proceso y llamar a los servicios del sistema operativo Android. Lo que permite a las APIs interactuar con los servicios del sistema operativo Android. Estas comunicaciones están ocultas para el desarrollador en la capa de Framework (hablaremos más de esto en el capítulo de Services).
  • Servicios del Sistema Android: Casi todas las funcionalidades en el API del Framework se comunicarán con algún servicio (Service) del sistema para acceder a hardware implicado. Cada servicio se divide en componentes enfocados en funcionalidades. Los servicios se agrupan en:

-System: Incluye gestores de ventanas, de notificaciones, etc

-Media: Incluye aquellos involucrados en la reproducción y la grabación multimedia (imágenes, audio, video, etc)

  • Capa de abstracción del Hardware (HAL, Hardware Abstraction Layer): Interfaz que permite al sistema operativo Android llamar a la capa de drivers (controladores) del dispositivo.
  • Kernel (núcleo) Linux: Capa de abstracción del hardware y servicios de seguridad, gestión de memoria, de procesos, pila de red, modelo de los controladores, etc.
  • Ensamblador: lenguaje de bajo nivel para circuitos integrados programables. Es una representación mnemotécnica del código máquina en binario y varias constantes para programar de una manera más sencilla que utilizar directamente el binario (más información en http://es.wikipedia.org/wiki/Lenguaje_ensamblador).
  • Firmware: Instrucciones máquina grabadas en un chip para propósitos específicos (más información en http://es.wikipedia.org/wiki/Firmware)
  • Hardware: Son las partes físicas y los componentes (más información en http://es.wikipedia.org/wiki/Hardware)

Diferencia entre Dalvik y ART. ART vs DALVIK

No nos importa a la hora de desarrollar aplicaciones Android, ya que nosotros trabajaremos con la capa de Framework (y si acaso con la capa de bibliotecas C/C++ si utilizamos el NDK). El resto es automático y transparente para los desarrolladores de aplicaciones Android.

Es decir, que cuando ejecutemos una aplicación desarrollada para ART también funcionará para Dalvik, por retrocompatibilidad.

Dalvik estuvo vigente desde el nacimiento de Android, siendo sustituido por ART a partir de la versión 5.0 (en la versión 4.4 era opcional su uso).

Dalvik o ART se encuentra en todo dispositivo o emulador que ejecute Android (dependiendo de la versión de Android es Dalvik o ART).

Bytecode

En programación en general, el bytecode es el resultado de realizar el pesado trabajo de procesar el código fuente (el código que has programado) y optimizarlo. Se obtiene como resultado el fichero llamado bytecode. Fichero que es portable entre arquitecturas. Será la máquina virtual la encargada compilar (traducir) en tiempo de ejecución a código máquina del sistema donde se despliega. Lo que resulta mucho más rápido que realizar todo el trabajo desde el código fuente, pues se ha realizado de antemano el trabajo.

En Android los programas están escritos normalmente en Java y compilados a bytecode por la máquina virtual de Java. Luego es traducido a ficheros bytecode para Dalvik o para ART:

  • DEX (Dalvik Executable Format, Formato Ejetucable para máquinas virtuales Dalvik): Archivo de bytecode que siempre será llamado “classes.dex” comprimido dentro del fichero APK. Este fichero es general y no está preparado para un Hardware en específico, por lo que tiene que ser traducido al código máquina en cada dispositivo (para no tener que traducirlo cada vez que se ejecute la aplicación se creará o un fichero ODEX o un ELF). Es necesario tanto para la máquina virtual Dalvik, como para ART.
  • ODEX (Optimized DEX, fichero DEX Optimizado): Este fichero contiene el conjunto de instrucciones utilizado por la máquina virtual Dalvik. Cada vez que la aplicación se ejecuta en el dispositivo la máquina virtual Dalvik traduce las partes utilizadas del fichero DEX dinámicamente y lo guarda en el fichero ODEX; a medida que se va traduciendo más, se va guardando en el fichero ODEX. Se genera mediante la herramienta “dexopt” a partir de un fichero DEX. Es necesario para la máquina virtual Dalvik.
  • ELF (Executable and Linkable Format, Formato Ejecutable y Enlazable): El fichero ELF es un ejecutable para Linux; es un formato de archivo para ejecutables, código objeto, bibliotecas compartidas y volcados de memoria. Es decir, el fichero bytecode DEX se traduce al fichero fichero ELF siendo éste la tradución a código máquina del Hardware donde se va a ejecutar; de ahí que se compile en el mismo dispositivo en el momento de la instalación (a diferencia de ODEX, ELF es la traducción completa de todo el fichero DEX en una sola vez durante la instalación; ODEX es la suma de las partes que ha ido traduciendo la máquina virtual Dalvik cada vez que se ejecutó la aplicación). Se genera mediante la herramienta “dex2oat” a partir de un fichero DEX. Es necesario para ART (sustituye al fichero ODEX de la antigua máquinva virtual Dalvik).

 

Empaquetar en APK un programa Android

El Sistema de Construcción (Build System) combina el JDK de Java y las herramientas del SDK de Android. Las tareas de pruebas (testing) se realizan como comprobación final, asegurando que la aplicación funciona como se espera en condiciones reales. Con Gradle en Android Studio se compilará, firmará, optimizará la aplicación a la vez. Cuando se termine de preparar, se obtendrá una aplicación APK firmada que se puede distribuir a los usuarios directamente o través de la tienda de aplicaciones “Google Play”. El fichero APK resultante contendrá: código fuente compilado, recursos, el fichero de manifiesto (AndroidManifest.xml), entre otros.

A continuación describo los pasos que se siguien para crear un paquete APK (ver siguiente imagen). Va desde la zona más alta de la imagen, donde tendremos el código que estamos programando con Android Studio y todos los recursos que añadamos a nuestra aplicación; hasta la zona de abajo, donde obtendremos el fichero APK firmado.

Diagrama de cómo se empaqueta un programa en un fichero APK de Android - www.Jarroba.com

Explico los pasos vistos en la imagen anterior, por herramienta utilizada (la mayoría de estas herramientas las podemos encontrar como ejecutables dentro de la carpeta del SDK de Android, o el compilador de Java se usa el propio de Java. Recalcar que todo este proceso es automático y no tiene que preocuparnos):

  • aapt (Herramienta de empaquetado de activos Android, The Android Asset Packaging Tool): Compila el fichero “AndroidManiest.xml” y los ficheros XML de las Activities. Además, genera el fichero “R.java” para referenciar los recursos desde el código Java (Más información en capítulos posteriores).
  • aidl (Lenguaje para definir interfaces Android, Android Interface Definition Language): Convierte los interfaces “.aidl” (interfaces para comunicar servicios mediante la comunicación entre procesos, IPC; entraremos en detalle en capítulos futuros) en interfaces Java.
  • Compilador Java: toma todo el código Java, incluidos los ficheros “R.java”, los interfaces de“.aidl”, y los compila en ficheros “.class”.
  • dex: Convierte los ficheros “.class” en ficheros bytecode DEX. Además, cualquier biblioteca importada, así como otros ficheros “.class” que hayas incluido serán convertidos a ficheros DEX, incluyendo todas las clases de nuestro código en un único fichero DEX. Para optimizar el espacio, los Strings duplicados y otras constantes repetidas se introducen una única vez en el fichero DEX.
  • dexopt: Solo se aplica si se ejecuta en el emulador desde Android Studio. Convierte el fichero DEX al fichero compilado ODEX mediante una compilación AOT (Ahead Of Time, Antes de Tiempo) para que funcione única y exclusivamente en el emulador (más información en preguntas posteriores). En este caso el ODEX no se empaqueta dentro del APK, sino que se pone al junto al APK.
  • apkbuilder: imágenes, vídeos, y otros que no se pueden compilar, junto con los ficheros DEX son empaquetados en el fichero APK.
  • Jarsigner: Firmamos el ficheros APK con una clave de desarrollo (debug) o de lanzamiento (release). El fichero APK resultante ya se puede instalar en cualquier dispositivo Android.
  • Zipalign: Si el fichero APK se ha firmado con la clave de lanzamiento (release), el fichero se debe alinear (la alineación de la estructura de datos consiste en desplazar los bits un múltiplo del tamaño de la palabra que pueda controlar el procesador, y rellenar lo que falte; en Android normalmente son 4 bytes). El fichero APK alineado resultante aumenta el rendimiento del sistema de memoria debido a la forma en que el procesador gestiona la memoria en un dispositivo.

Fichero APK

Se puede deducir que va a contener el fichero APK resultante del anterior proceso. Los ficheros son:

  • DEX: contiene todos los ficheros Java, como nuestros ficheros Java o el R.java
  • Recursos compilados: ficheros XML, como el AndroidManifest.xml, o los Layouts
  • Recursos No compilados: vídeos, imágenes, audios, etc

Contenido de un fichero APK de Android - www.Jarroba.com

También recordar que el APK está firmado y alineado.

Falta el fichero ELF para ART, que no se ha obtenido en el anterior proceso. Para convertir de un archivo DEX a un archivo ELF se realiza mediante la herramienta “dex2oat”. Ésta herramienta se encuentra dentro del sistema operativo Android. En cuanto instalemos el fichero APK en el sistema operativo Android, la herramienta “dex2oat” toma el fichero DEX y crea el fichero ELF.

En Dalvik se aplicaca la herramienta “dexopt” sobre las partes del fichero DEX que se estén usando, para generar el fichero ODEX en el momento de la ejecución por la máquina virtual Dalvik.

Instalación del APK en el dispositivo

El archivo DEX en su estado original se dice que está en el estado Pre-dexopt.

En el momento de la instalación de la aplicación en el dispositivo, el fichero DEX es modificado:

  • Se optimiza
  • Se intercambia el orden de los bits según el formato Endianness, de cómo se almacenan los datos y la arquitectura con la que funciona el procesador (es decir, de cómo se almacenen los datos en big-endian que es el orden natural, little-endian que es del menos relevante al más relevante, y middle-endian que es el soporte para los dos formatos anteriores)
  • Se crean estructuras de datos simples
  • Se enlazan las funciones de las bibliotecas inline (se insertan una copia del código fuente de la función en la sección del código donde sea llamada)
  • Los objetos de clases vacías serán cortocircuitadas (short-circuited en inglés, referido en programación a que no se evaluará si no es necesario).

Si trabajamos con ART, cuando se instala la aplicación se generará el fichero ELF desde el DEX.

Si trabajamos con Dalvik, puede crearse el fichero ODEX al instalarse, aunque no será completo.

Una curiosidad que seguro que has notado cuando se actualiza tu dispositivo Android. Es que al terminar la actualización se tienen que actualizar todas las aplicaciones instaladas. Esta actualización de todas las aplicaciones instaladas es la compilación de los bytecodes DEX dentro de tu dispositivo.

Máquina virtual Dalvik

Es una máquina virtual desarrollada por Google para Android.

Aunque es muy parecida a la máquina virtual de Java, la maquina virtual Dalvik se diferencia en:

  • Ocupa menos
  • Es capaz de ejecutar 16 bits conjuntos de instrucciones, en vez de los 8 bits de la máquina virtual de Java
  • La tabla de constantes (constant pool) se ha modificado para utilizar solo índices de 32 bits para simplificar.

La máquina virtual Dalvik se caracteriza por realizar compilaciones “justo a tiempo” (JIT, Just-In-Time). En resumen, cada vez que se ejecuta una aplicación, el compilador de la máquina virtual Dalvik traduce el bytecode de dicha aplicación con la herramienta “dexopt” en tiempo de ejecución a código máquina, y lo ejecuta (JIT, Just-In-Time. Más información en sucesivas preguntas).

Cabe mencionar que cada aplicación corre sobre su propia instancia de la máquina virtual (habrá tantas máquinas virtuales instanciadas como aplicaciones en ejecución). De este modo, si se produce cualquier problema con la aplicación, no afectaría al resto de aplicaciones en ejecución.

La máquina virtual Dalvik abre el fichero APK y descomprime el fichero DEX del interior. Luego creará en caché o actualizará el fichero ODEX si los permisos lo permiten, y luego lo ejecutará.

Compilación JIT (Just-In-Time, Justo a tiempo)

La compilación JIT es compilar el bytecode del programa en tiempo de ejecución.

Para aclararlo pongamos un ejemplo para el caso que nos ocupa. Supongamos que tienes un móvil con una aplicación. De esta aplicación solo está el bytecode DEX dentro del fichero APK. Cuando pulsas el icono para acceder ejecutar la aplicación por primera vez, en ese momento se realiza la compilación se realiza la compilación de la aplicación en tu dispositivo por la máquina virtual Dalvik, lo que convierte el bytecode a código máquina que es el fichier ODEX. Luego este código ya es entendido por el Hardware. Es el momento en el que podemos decir que la aplicación funciona de verdad.

Evidentemente este proceso de compilación JIT consume tiempo y sería un poco estúpido repetirlo varias veces para el mismo código de la misma aplicación; por lo que no se compila cada vez que se ejecuta el mismo programa. Sino que se compila el bytecode DEX y se cachea el código máquina resultante en el fichero fichero ODEX. En siguientes ejecuciones de la misma aplicación se reutiliza el código ya cacheado del fichero ODEX.

Las razones para realizar una compilación JIT son:

  • Compilar el bytecode a código máquina optimizado para la CPU y el sistema operativo donde se va a ejecutar.
  • El sistema puede recoger estadísticas de la ejecución de la aplicación en una máquina. De este modo, puede decidir recompilarla de otra manera para optimizar el rendimiento.
  • El sistema puede realizar optimizaciones globales sin perder las ventajas del enlazamiento dinámico (el sistema operativo carga las bibliotecas compartidas a memoria RAM, y vincula las que necesite a la aplicación; por ejemplo, si desarrollamos una aplicación con la cámara de fotos, Android nos cargará la biblioteca de Camera a RAM y la vinculará a nuestra aplicación para que la pueda utilizar).

Herramienta «dexopt»

Se verificarán y optimizarán todas las clases del fichero DEX cargando todas las clases en la máquina virtual y ejecutándolas. En caso de que algo falle, no se verificará ni optimizará.

La herramienta “dexopt” efectuará una inicialización abreviada de la máquina virtual, cargando cero o más ficheros DEX desde la ruta de la clase de arranque (bootstrap class path), y luego verificar y optimizar todo lo posible del fichero DEX objetivo. Al terminar, el proceso finaliza, liberando todos los recursos.

La herramienta “dexopt” puede generar ficheros ODEX desde ficheros DEX con uno de los siguientes casos (La letra precedente a la descripción corresponde en la imagen con la letra de cada aplicación):

A) Aplicación de producción (para Google Play): El instalador de aplicaciones del sistema lo genera cuando la aplicación se instala por primera vez. Esta aplicación tiene privilegios para escribir en el directorio “dalvik-cache”. Si no se ha convertido todo el código DEX a ODEX, se generará cuando se ejecute la aplicación.

B) Aplicación de desarrollo para el emulador: El Sistema de Contrucción (Build System) realiza una compilación AOT (Ahead Of Time, Antes de Tiempo) en el momento en que el SDK de Android empaqueta el APK. Se extrae el fichero DEX y se elimina (el APK resultante no tendrá fichero DEX). El ODEX se almacena al lado del fichero comprimido original (no en el directorio “dalvik-cache”), formando parte de la imagen del sistema. Este caso requiere utilizar el emulador, forzar una compilación JIT del fichero DEX, para extraer el fichero ODEX resultante al directorio “dalvik-cache”.

C) Aplicación de desarrollo para dispositivo físico: La máquina virtual Dalvik realiza una compilación JIT. La salida va a un directorio especial llamado “dalvik-cache”. Este método solo está permitido para desarrollo, donde los permisos del directorio “dalvik-cache” no están restringidos. En producción no está permitido.

Máquina Virtual Dalvik de Android - www.Jarroba.comEl directorio “dalvik-cache” se localiza exactamente en la ruta “$ANDROID_DATA/data/dalvik-cache”.

Los archivos ODEX tendrán un nombre derivado de la ruta donde se encuentra el fichero DEX. Solo se tiene permiso para leer –pero no modificar o eliminar- los ficheros DEX tanto de nuestra aplicación como de otras. Las aplicaciones solo tienen permisos para acceder a su fichero ODEX.

La creación ODEX desde DEX, en los casos donde “Dalvik compila con JIT el fichero ODEX” y “el instalador de aplicaciones genera el fichero ODEX”, sigue los siguientes pasos:

1º Si no existe se crea el directorio “dalvik-cache”.

2º El fichero DEX se descomprime del fichero APK. Y se reserva una pequeña cantidad de espacio al inicio del fichero DEX para la cabecera del archivo ODEX.

3º El fichero se asigna a memoria para acceder a esta fácilmente y se ajusta para el sistema en el que está. Incluye el intercambio de bytes, la reordenación de bytes, comprobaciones estructurales básicas (como asegurar que los offsets y los índices de los ficheros estén dentro de rangos válidos), sin cambiar nada significativo del archivo DEX.

El proceso de verificación del bytecode implica el escaneo de todas las instrucciones de cada método en cada clase de un fichero DEX. El objetivo consiste en identificar las secuencias de instrucciones ilegales (un ejemplo de algo ilegal es: realizar una llamada desde un paquete a un método de una clase de otro paquete diferente) para no tener que realizar las comprobaciones en tiempo de ejecución. Muchos de los cálculos son necesarios para la exacta recolección de basura.

Por razones de rendimiento, la optimización asumirá que la verificación se haya ejecutado correctamente. Por defecto, Dalvik verifica todas las clases, y solo optimiza las clases que han sido verificadas.

Una vez pasada la verificación exitosamente, se pondrá un flag en el ODEX. De esta manera no se volverá a verificar cuando se recargue.

La optimización de Dalvik consta de lo siguiente:

  • Para llamadas a métodos virtuales, remplaza el índice de método por una índice de vtable.
  • Para instancias de campos get/put, remplaza el índice del campo por un byte offset. También, fusiona las variante boolean / byte / char / short en una sola forma de 32 bits
  • Remplaza las llamadas de alto volumen, como String.length(), con con remplazos en línea (inline). Se salta habitual llamada a métodos sobrecargados, directamente se intercambia desde el intérprete a la implementación nativa.
  • Poda los métodos vacíos.
  • Añade datos previamente calculados.

Con respecto a la optimización pueden darse los siguientes problemas:

  • Los índices vtable y los byte offset están sujetos a cambios si se actualiza la máquina virtual.
  • Si la superclase (en herencia es la clase padre, de la que se hereda) pertenece a un fichero DEX diferente, y ese otro DEX con la clase padre se actualiza, habrá que asegurar que nuestros índices y offsets se actualicen también.

Entorno de ejecución ART

ART (Android Runtime, Entorno de ejecución Android), realiza una compilación AOT en el momento de la instalación para obtener el ejecutable ELF (sustituye al fichero ODEX de Dalvik).

Entorno de Ejecución ART de Android - www.Jarroba.comART mejora respecto a la máquina virtual Dalvik:

  • Mejora el rendimiento del recolector de basura
  • Mejora la depuración de aplicaciones
  • Mejora los análisis de ayuda al desarrollo
  • Consume menos energía
  • Mejora el rendimiento general del sistema
  • No hay caché de código en tiempo de ejecución
  • Al utilizar solo memoria RAM se puede paginar (Dalvik utilizaban memoria Caché que no era paginable)
  • Pre-inicializa el conjunto de clases en tiempo de compilación lo que mejora el rendimiento de la memoria RAM
  • Compilar con la herramienta “dex2oat” desde un fichero DEX a un ELF consume casi tres veces más de tiempo que, compilar con la herramienta “dexopt” de DEX a ODEX. Pese a esto, el resultado es una compilación completa en los fichero ELF, al contrario que en los ODEX que solo se compilaba una parte

Como añadido en ART, se mantiene la retro-compatibilidad con Dalvik al utilizar sus mismos bytecode “.dex”. Pero ART no utiliza “.odex”, sino que los sustituye por los ejecutables “ELF”.

compilación AOT (Ahead-Of-Time, Antes de tiempo)

La compilación AOT es compilar el bytecode en código máquina antes de que se ejecute el programa.

En Android se compila el bytecode DEX en el momento en el que se instala la aplicación en el dispositivo, convirtiéndose en el fichero ejecutable ELF.

Las razones para realizar una compilación AOT son:

  • La ejecución se produce muy rápido al tener ya compilados los programas y bibliotecas. Ahorra espacio en disco duro, en memoria RAM, y se reduce el tiempo en iniciarse. Al utilizar AOT se reduce el número de compilaciones, se utiliza menos el procesador, por lo que se ahorra más batería; por esto es muy útil en dispositivos móviles.
  • En contraposición. Compilar “justo a tiempo” (JIT) es demasiado lento –por compilar mientras se ejecuta- cuando hay código complejo y provoca latencia, cosa que no ocurre al compilar con AOT. Aunque con AOT no se permite realizar ciertas optimizaciones que sí se pueden hacer con JIT.

Odex y Deodex (u Odexing y Deodexing)

Posiblemente hayas escuchado estas palabras si has utilizado o visto algo de ROMs (ROM viene de “Read Only Memory”, es una memoria de solo lectura que guarda el sistema operativo; si te acuerdas de la época del CD-ROM, una ROM de Android es como el CD-ROM en el que viene el sistema operativo para instalarlo en un dispositivo). Es más, seguramente hayas escuchado estas palabras si te suena ROM cocinada o modificada (Una “ROM cocinada” quiere decir que el sistema operativo se ha modificado con apliciones, animaciones, temas, procesos internos, configuraciones, etc elegidos por su creador; y cuando la instalemos en nuestro dispositivo, se verá como lo han modificado desde el principio).

Seguro que has caído en que las palabras “Odex” y “Deodex” se parecen al archivo ODEX. Como vimos anteriormente, ODEX es el bytecode que optimiza el inicio de las aplicaciones para cada dispositivo (es el DEX optimizado para la máquina virtual Dalvik).

La problemática de los cocineros de ROMs, es que si modifican un fichero APK ya instalado en el dispositivo, y no refrescan el fichero ODEX, provoca errores. Por lo que tienen que “deodexar” el fichero APK antes de trabajar con éste, para facilitar su tarea.

He utilizado “Deodex” como verbo, pues es la acción. Tenemos tipos de acciones con la conversión de los bytecode:

  • Odex (Odexar): Es lo que ya vimos (lo “normal”), lo que se hace al crear desde el archivo DEX el fichero ODEX mediante la herramienta “dexopt”.
  • Deodex (Deodexar): Implica elegir un fichero APK que queramos y buscar su fichero ODEX en la memoría caché, para introducirlo dentro de dicho APK. Con esto se consigue agilizar la programación, al poder modificar los ficheros APK sin preocuparse de que el ODEX no esté actualizado por estar en la memoria caché; asegurando la integridad de la aplicación. Puede “deodexarse” toda una ROM entera, lo que implica la “deodexación” de todos sus ficheros APK instalados.

Por tanto, para trabajar con ROMs cocinadas es mejor que hayan sido “Deodexadas”.

Otras dificultades son:

  • El fichero ODEX tiene dependencias en cada fichero BOOTCLASSPATH que se carga cuando se genera. El fichero ODEX solo es válido cuando se utiliza exactamente ese fichero BOOTCLASSPATH. Dalvik fuerza esto al almacenar un checksum (suma de control) de cada fichero que el fichero ODEX. Lo que hace que sea dependiente de su checksum, asegurando que el checksum de cada fichero coincida con el fichero ODEX que sea cargado. El fichero BOOTCLASSPATH es un listado de APKs o JARs (los cuales son “core.jar”, “ext.jar”, “framework.jar”, “android.policy.jar” y “services.jar”, y pueden ser encontrados en el directorio “/system/framework”) desde donde las clases pueden ser cargadas. Sin embargo, algunas APKs tienen dependencias extras a otros APKs o JARs (además de los 5 anteriores). Las dependencias de los ficheros ODEX complican la modficación de aplicaciones ya instaladas. Esto se debe a que no se puede coger una APK con su fichero ODEX de una imagen del sistema, e intentar ejecutarla en otra imagen del sistema (a menos que utilicen exactamente los mismos ficheros del Framework, cosa casi imposible).
  • Si se hace cualquier cambio en el fichero BOOTCLASSPATH, invalidará todas las dependencias de los ficheros ODEX (lo que implica la invalidación de todos los APKs y JARs del dispositivo).
  • Los ficheros ODEX son difíciles de convertir a ficheros DEX.
  • La primera vez que una aplicación “deodexada” sea ejecutada por la máquina virtual Dalvik, requerirá un tiempo superior de inicio. El resto de ejecuciones la aplicación no tardará más, pues ya habrá movido el fichero ODEX a la carpeta de caché.

Nota del autor

Este artículo -tanto texto como gráficos- ha sido un trabajo de recopilación de información por diferentes medios durante varios meses, y una adaptación propia de los mismos. Que si bien he intentado ser lo más fiel y preciso a nivel teórico, de estar documentado por los diferentes medios que aportan la información más directa (fiable) y por el conocimiento del que dispongo. Es mi deber indicar que debido a incoherencias y contradiciones en la documentación oficial, además debido a la evolución propia de las arquitectura, pudiran no ajustarse con la realidad.

Con mis mejores deseos espero aclarar un montón de dudas, que sea un buen artículo y que la información sea la más completa posible; para que no tengas que gastar tanto tiempo como yo en recopilarla, desgranarla y entenderla.

Cualquier cosa me lo pueden sugerir en los comentarios.

Y si nunca has programado en Android y te ha picado el gusanillo, puedes aprender a programar en Android de una manera muy sencilla con nuestro libro gratuito en la siguiente dirección: https://jarroba.com/libro-android-100-gratis/

Bibliografía

Comparte esta entrada en:
Safe Creative #1401310112503
Arquitectura Android – ART vs Dalvik por "www.jarroba.com" esta bajo una licencia Creative Commons
Reconocimiento-NoComercial-CompartirIgual 3.0 Unported License.
Creado a partir de la obra en www.jarroba.com

10 thoughts on “Arquitectura Android – ART vs Dalvik”

  1. Hola, quería hacer un comentario-pregunta, cito:

    «Evidentemente este proceso de compilación JIT consume tiempo y sería un poco estúpido repetirlo varias veces para el mismo código de la misma aplicación; por lo que no se compila cada vez que se ejecuta el mismo programa. Sino que se compila el bytecode DEX y se cachea el código máquina resultante en el fichero fichero ODEX. En siguientes ejecuciones de la misma aplicación se reutiliza el código ya cacheado del fichero ODEX.»

    Me parece que la parte que dice «cada vez que se ejecuta el mismo programa» debería ser «cada vez que se ejecuta el mismo trozo de código durante una ejecución determinada». Tengo entendido que cuando cerramos la aplicacioón y la volvemos a abrir (ejecutar), el JIT comienza desde cero.

    1. Buena observación Jose y gracias por la sugerencia.
      Aunque para lo que comentas, si bien pudiera ser en algunos casos, realmente no comienza de cero la compilación JIT en Android como se indica en:
      * https://source.android.com/devices/tech/dalvik/jit-compiler: en el apartado «JIT compilation» se indica que si hay un fichero OAT (que está contenido en el ODEX) disponible se usará (aunque se generará regularmente).
      * https://source.android.com/devices/tech/dalvik/configure: en «How ART works» en el punto 3 se indica que al reiniciar la aplicación se evitará usar JIT para métodos ya compilados.
      De cualquier manera me apunto una revisión para el artículo.

  2. Cambié mi tablet de dalvic a art automáticamente se apagó y me dice optimizando aplicaciones 1 de 2 y nunca más prendió lo deje días así y nada

    1. Buenas Alan, esta web es técnica de programación. Si tienes problemas con algún dispositivo contacte con su fabricante o con quien se lo vendió.

    1. Hola Carlos. La verdad es que lo que más trabajo hubo al realizar este artículo fue que no poner a lo que poner, para que fuera claro, con una explicación clara y fluida. Tomo nota de lo que nos comentas para una futura revisión del artículo; de cualquier manera ahí queda tu comentario para ayudar a quien lo necesite 🙂

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

Este sitio usa Akismet para reducir el spam. Aprende cómo se procesan los datos de tus comentarios.

Uso de cookies

Este sitio web utiliza cookies para que usted tenga la mejor experiencia de usuario. Si continúa navegando está dando su consentimiento para la aceptación de las mencionadas cookies y la aceptación de nuestra política de cookies

ACEPTAR
Aviso de cookies