Intel Learning Series para desarrolladores para Android*, n.º 6: Depuración en Android* OS

Las dificultades y las estrategias para identificar problemas de tiempo de ejecución y posibles códigos problemáticos en aplicaciones dirigidas al sistema operativo Android* o en la pila de software del sistema Android* van a ser notablemente similares independientemente de si la arquitectura de la plataforma subyacente está basada en la arquitectura Intel® y el procesador Intel® Atom™ más reciente o en la arquitectura ARM*. En este capítulo ofreceremos una descripción general de las metodologías disponibles para depurar software dirigido a Android* en la arquitectura Intel. También hablaremos de la instalación y la configuración de entornos de depuración para software de sistema y aplicaciones dirigidas a Android y la arquitectura Intel. Mientras hagamos esto, también señalaremos dónde se encuentran las diferencias cuando se desarrolla para la arquitectura ARM.

1. Prerrequisitos

En este capítulo cubriremos el controlador USB Intel® necesario para habilitar la depuración remota de aplicaciones en dispositivos con procesador Intel® Atom™ que funcionen con el sistema operativo Android*.

También analizaremos la Imagen de Sistema Intel® Atom™ x86 para el emulador de Android. Si no hay ningún destino de depuración física disponible, la mejor opción posible es tener un dispositivo con procesador Intel® Atom™ emulado dentro de la capa de emulación de dispositivos del SDK de Android*.

Estos dos prerrequisitos son, junto con el SDK de Android*, la base para el desarrollo cruzado dirigido a tabletas o smartphones con procesador Intel® Atom™.

1.1. Controlador USB Intel® para dispositivos Android

Echemos un vistazo primero al paquete del controlador USB Intel® para Android, que permite conectar la máquina host de desarrollo al dispositivo Android que contiene un procesador Intel Atom™. En este primer ejemplo, se va a suponer que el host tiene sistema operativo Windows*. Los principios para sistemas host con Linux* o OS X* son similares.

  • Descargue el paquete de instalación desde http://www.intel.com/software/android
  • Ejecute el instalador y acepte el pedido de confirmación de Windows User Account Control (UAC), si corresponde.
  • Verá la siguiente pantalla (Figura 1). Haga clic en Next para continuar (si el instalador detecta una versión anterior del controlador, acepte para desinstalarla).

    Figura 1. Pantalla de inicio para la instalación del controlador de dispositivos USB
  • Lea y acepe el acuerdo de licencia para el usuario final (EULA) del controlador.
  • Se le pedirá que seleccione componentes. Haga clic en el botón Next para continuar.
  • Elija la ruta de instalación y haga clic en Install.
  • El instalador comenzará a instalar los controladores USB para Android. Puede que este proceso tome algunos minutos (Figura 2).

    Figura 2. Pantalla de progreso de la instalación del controlador de dispositivos USB
  1. Cuando haya terminado la instalación, haga clic en OK en la nota emergente y luego haga clic en Finish para cerrar el programa de instalación.

1.2. Instalación de la Imagen de Sistema Intel® Atom™ x86 para el emulador de Android

Para la alternativa de depurar en el host con Android* Virtual Device Manager, el primer prerrequisito es que esté disponible la imagen de sistema apropiada. Mover o Proteger o Indicar

Cerrar

El complemento Intel Android x86 System Image requiere que esté instalado el SDK de Android. En el sitio web para desarrolladores de Android (http://developer.android.com/sdk/installing.html) encontrará instrucciones para instalar este kit. El Android SDK Manager le permitirá descargar e instalar el complemento Intel Atom Processor Android x86 Emulator Image.

Siga estos pasos:

  1. Inicie el programa Android SDK Manager.
  2. En Packages → Android 4.x.x (API 1x), marque la casilla para seleccionar Intel Atom x86 System Image by Intel Corporation.
  3. Una vez seleccionado, haga clic en el botón Install Package, como se muestra en la Figura 3.
    (Nota: es posible que deba instalar más de un paquete; esto depende de los otros paquetes que preseleccionen usted o el programa Android SDK Manager).

    Figura 3. Selección de Android SDK Manager para la Imagen de Sistema x86
  4. Lea el acuerdo de licencia de Intel Corporation. Si acepta los términos, seleccione la opción Accept y haga clic en el botón Install, como se muestra en la Figura 4.

    Figura 4. Aceptación de los términos de licencia de Android SDK Manager
  5. En este momento, el Android SDK Manager descargará e instalará el complemento en la carpeta de complementos del SDK de Android (<sdk>/add-ons/). La descarga y la instalación llevan varios minutos, tiempo que depende de la velocidad de la conexión.
  6. Seleccione Manage AVDs en el menú Tools (Figura 5).

    Figura 5. Android SDK Manager – Administración de dispositivos virtuales de Android
  7. Debería aparecer la ventana de Android Virtual Device Manager. Haga clic en New (Figura 6).

    Figura 6. Paso para agregar un dispositivo virtual de Android*
  8. Ingrese un nombre para el dispositivo virtual en el campo Name. Nota: no se permite usar espacios en el nombre.
  9. Seleccione Intel Atomx86 System Image (Intel Corporation) – API Level 10 de la lista desplegable del campo Target (Figura 7).

    Figura 7. La imagen de sistema Intel Atom x86 como destino de dispositivo virtual
  10. Cuando haya seleccionado los valores de la configuración, haga clic en el botón Create AVD:
  11. El nuevo dispositivo virtual debería aparecer en el Android Virtual Device Manager. Seleccione el nuevo dispositivo y haga clic en el botón Start, como se muestra en la Figura 8.

    Figura 8. Inicio del dispositivo virtual de Android*
  12. Debe aparecer la ventana Launch Options. Seleccione el tamaño de la pantalla (Screen Size) y la resolución (Monitor dpi) de su sistema. Si no lo hace, el emulador podría ser de dimensiones más grandes que la pantalla de visualización. Haga clic en el botón Launch (Figura 9).

    Figura 9. Opciones de inicio del dispositivo virtual
  13. Después de un momento, el emulador se iniciará y mostrará la pantalla de la Figura 10.

    Figura 10. Emulación de AVD* para dispositivo Android* con Arquitectura Intel®

1.3. Depuración de aplicaciones con Android Debug Bridge

Android Debug Bridge (ADB) es una herramienta de línea de comandos que maneja la comunicación de depuración entre un depurador en el host (por lo general GDB* o DDMS* [Dalvik* Debug Monitor Server] o también ADT) y una imagen de Android que se ejecuta en el destino. La imagen de destino se podría estar ejecutando como emulación de dispositivo o en un dispositivo físico de desarrollo, con el cual usted se comunique mediante USB-OTG (On-The-Go) o llave USB a Ethernet. En pocas palabras, ADB es el “pegamento unificador” que hace posible la depuración de aplicaciones en Android.

Hay una amplia variedad de factores de forma a los que puede pertenecer el dispositivo al que se está conectando o que está emulando. Lo habitual es que sea un smartphone o una tableta. Sin embargo podría ser una tableta para controles médicos o un dispositivo integrado para la industria, para el manejo energético en el hogar, para depósitos o cualquier otro uso de sistemas inteligentes.

Configurar Android Debug Bridge para que permita la depuración remota de una plataforma basada en el procesador Intel Atom no es muy diferente de depurar en otras arquitecturas.

1.4. Configuración de ADB

Primero es necesario que tenga instalado en el host de desarrollo el SDK de Android con ADB incluido. Las instrucciones para este procedimiento se pueden encontrar en http://developer.android.com/sdk/installing.html.

Si su imagen de destino se está ejecutando en un dispositivo físico, lo primero que debe hacerse es incluir la compatibilidad con USB-OTG o USB a Ethernet. Para que se admita USB a Ethernet, se requiere un cambio de configuración de kernel y una recompilación. El fabricante OEM le proporcionará la información necesaria.

El método estándar para depurar aplicaciones en forma remota es usar la interfaz USB-OTG existente en la mayoría de los dispositivos Android. La configuración se describe en bastante detalle en el sitio web para desarrolladores de Android: http://developer.android.com/guide/developing/device.html:

Los pasos fundamentales que se describen allí son los siguientes:

  1. Declare su aplicación como "depurable" en su manifiesto de Android.
  2. Encienda “Depuración USB” ("USB Debugging") en su dispositivo.
  3. En el dispositivo, vaya a Settings > Applications > Development y habilite USB debugging (en dispositivos con Android 4.x.x, debe ir a Settings > Developer options).
  4. Configure el sistema para que detecte su dispositivo.
  • Si está desarrollando en Windows, necesita instalar un controlador USB para ADB (ver los prerrequisitos).
  • Si está desarrollando en Linux Ubuntu*, necesita agregar un archivo de reglas udev que contenga una configuración USB para cada tipo de dispositivo que quiera usar para desarrollar. En el archivo de reglas, cada fabricante de dispositivos está identificado con un identificador único de vendedor, tal como se especifica en la propiedad ATTR{idVendor}. Puede encontrar una lista de identificadores de vendedor en http://developer.android.com/tools/device.html#VendorIds.
  • Para configurar la detección de dispositivos en Linux Ubuntu, inicie sesión como root y cree este archivo:
    /etc/udev/rules.d/51-android.rules
  • Use este formato para agregar al archivo cada uno de los vendedores:
    SUBSYSTEM=="usb", ATTR{idVendor}=="????", MODE="0666", GROUP="plugdev"
    La asignación MODE especifica permisos de escritura/lectura, y GROUP define a qué grupo de Unix pertenece el nodo del dispositivo.
  • Ejecute:
    chmod a+r /etc/udev/rules.d/51-android.rules
  • Cuando enchufe el dispositivo por USB, si desea verificar que esté conectado, ejecute ADB devices desde el directorio platform-tools/ del SDK. Si está conectado, aparecerá el nombre como “device”.

Con Android OS iniciado en el CDK, conecte un cable USB-OTG al puerto (USB mini b) del CDK y conecte el otro extremo del cable (USB A) a su host de desarrollo.

Si todo está funcionando bien, debería poder ejecutar el comando siguiente para ver el dispositivo conectado:

$ adb devices

* daemon not running. starting it now *

* daemon started successfully *

List of devices attached

0123456789ABCDEF device

Nota: para ver qué nombre de dispositivo se asignó a esta conexión en el dev de Linux, puede mirar dmesg para buscar la dirección de "usb-storage: device found at <num>" y luego hacer un "ls -l /dev/bus/usb/*" para buscar el número.

1.5. ADB en Windows

Descargue e instale Eclipse Classic desde http://www.eclipse.org/downloads/.

Descargue el paquete del SDK de Android para Windows desde http://developer.android.com/sdk/index.html (android-sdk_r18-windows.zip o installer_r18-windows.exe).

Después de instalar el SDK de Android, adb.exe quedará ubicado en <install-dir>\android-sdk\platform-tools.

1.6. Comunicación host-cliente de ADB

Hasta ahora, nos hemos dedicado a instalar ADB en el host de desarrollo. En realidad, es un programa cliente-servidor que incluye tres componentes:

  • Un cliente, que se ejecuta en la máquina de desarrollo. Puede invocar un cliente desde un shell con un comando de ADB. Otras herramientas de Android tales como el complemento ADT y DDMS también crean clientes de ADB.
  • Un servidor, que se ejecuta como proceso en segundo plano en la máquina de desarrollo. El servidor administra la comunicación entre el cliente y el daemon de ADB que se ejecuta en un emulador o un dispositivo.
  • Un daemon, que se ejecuta como proceso en segundo plano en cada instancia de emulador o dispositivo.

Cuando se inicia un cliente de ADB, el cliente primero comprueba si hay un proceso de servidor de ADB ya ejecutándose. Si no lo hay, inicia el proceso de servidor. Cuando el servidor se inicia, se enlaza con el puerto TCP local 5037 y queda a la escucha de comandos enviados desde clientes de ADB (todos los clientes de ADB usan el puerto 5037 para comunicarse con el servidor de ADB).

Luego, el servidor establece conexiones con todas las instancias emulador/dispositivo en ejecución. Para localizar las instancias emulador/dispositivo, explora los puertos de número impar entre el 5555 y el 5585, el rango que usan los emuladores/dispositivos. Cuando el servidor encuentra un daemon de ADB, establece una conexión con ese puerto. Obsérvese que cada instancia emulador/dispositivo adquiere un par de puertos consecutivos (uno de número par para las conexiones de consola y uno impar para las conexiones de ADB). Por ejemplo:

Emulador 1, consola: 5554

Emulador 1, adb: 5555

Emulador 2, consola: 5556

Emulador 2, adb: 5557 (...)

Como se muestra, la instancia de emulador conectada a ADB en el puerto 5555 es la misma instancia cuya consola escucha en el puerto 5554.

Una vez que el servidor ha establecido conexiones con todas las instancias de emulador, puede usar los comandos de ADB para controlar esas instancias y acceder a ellas. Como el servidor administra las conexiones a instancias emulador/dispositivo y maneja comandos desde múltiples clientes de ADB, usted puede controlar cualquier instancia emulador/dispositivo desde cualquier cliente (o desde un script).

1.7. Inicio de ADB

Escriba "adb shell". Verá el signo #, indicador de que la conexión ha sido exitosa.

$ adb shell

1.8. Comandos clave para dispositivos ADB

Los comandos de la lista siguiente ayudan a transferir la aplicación depurada a la emulación o el dispositivo de destino desde la línea de comandos. Pueden ser muy útiles, en especial si no se dispone de una conexión de terminal ssh.

  adb push <local> <remote>    - copiar archivo/dir a dispositivo
  adb pull <remote> [<local>]  - copiar archivo/dir desde dispositivo
  adb sync [ <directory> ]     - copiar host->dispositivo sólo si ha cambiado
                                 (-l significa mostrar en lista, pero no copiar)
                                 (ver “adb help all”)
  adb shell                    - ejecutar shell remoto interactivamente
  adb shell <command>          - ejecutar comando de shell remoto
  adb emu <command>            - ejecutar comando de consola de emulador
  adb logcat [ <filter-spec> ] – Ver registro de dispositivo
  adb forward <local> <remote> - desviar conexiones de software
                                 las especificaciones de desvío son una de las siguientes:
                                   tcp:<port>
                                   localabstract:<unix domain socket
     name>
                                   localreserved:<unix domain socket
     name>
localfilesystem:<unix domain socket name>
                                   dev:<character device name>
                                   jdwp:<process pid> (remote only)
  adb jdwp                     - muestra los identificadores de procesos que son host de un 
     transporte de JDWP
  adb install [-l] [-r] [-s] <file> - inserta este archivo de paquete en el 
     dispositivo y lo instala
                                 ('-l' significa bloquear desvíos en la aplicación)
                                 ('-r' significa reinstalar la aplicación, pero 
     conservar sus datos)
                                 ('-s' significa instalar en la tarjeta SD en lugar del 
     almacenamiento interno)
  adb uninstall [-k] <package> - eliminar este paquete de aplicaciones del dispositivo
                                 ('-k' significa conservar los directorios  
     de datos y caché)

Se pueden encontrar más detalles sobre la configuración y el uso de ADB en http://developer.android.com/guide/developing/tools/adb.html.

1.9. Uso del complemento Android Debug Tools para Eclipse

Para dispositivos basados en la arquitectura Intel, el proceso de instalación no varía mucho del descrito en http://developer.android.com/sdk/eclipse-adt.html#installing.

El complemento Android Debug Tools (ADT) proporciona depuración integrada completa de aplicaciones del entorno de desarrollo integrado (Integrated Development Environment, IDE) de Eclipse para dispositivos de destino y emuladores basados en la arquitectura Intel. Ofrece dos perspectivas de depuración diferentes con distintos conjuntos de prestaciones

Es posible cambiar entre una y otra según sea necesario, ya que ambas proporcionan diferentes ventajas para depurar aplicaciones.

1.10. La perspectiva de depuración de Eclipse

La perspectiva de depuración de Eclipse le brinda acceso a las siguientes pestañas:

  • Debug: muestra las aplicaciones de Android depuradas antes y actualmente, y sus hilos en ejecución.
  • Variables: cuando se establecen puntos de interrupción, muestra valores de variables durante la ejecución de código.
  • Puntos de interrupción: muestra una lista con los puntos de interrupción del código de su aplicación.
  • LogCat: le permite ver mensajes de registro del sistema en tiempo real. La pestaña LogCat también está disponible en la perspectiva DDMS.

Para acceder a la perspectiva de depuración, haga clic en Window > Open Perspective > Debug. Encontrará más información en la documentación correspondiente del depurador de Eclipse.

1.11. La perspectiva DDMS

 

La perspectiva DDMS en Eclipse permite acceder a todas las prestaciones de DDMS desde dentro del IDE de Eclipse. Se puede acceder a las siguientes secciones de DDMS:

Devices - Muestra la lista de dispositivos y AVD conectados a ADB.

Emulator Control - Permite llevar a cabo funciones de dispositivo.

LogCat - Permite ver mensajes de registro del sistema en tiempo real.

Threads - Muestra los hilos en ejecución dentro de una máquina virtual.

Heap - Muestra el uso de montón (heap) para una máquina virtual.

Allocation Tracker – Muestra la asignación de memoria de objetos.

File Explorer - Permite explorar el sistema de archivos del dispositivo.

1.12. Entorno de ejecución de aplicaciones para depuración

La diferencia al depurar una aplicación de Android dirigida a un dispositivo basado en la arquitectura Intel aparece cuando se configura el dispositivo de destino para la depuración.

Se selecciona el dispositivo de destino con el Android Virtual Device Manager, que forma parte del SDK de Android, y se va a Window > AVD Manager en el menú desplegable del IDE de Eclipse. Allí hay que asegurarse de seleccionar Intel Atom (x86) como destino de la interfaz binaria de aplicaciones integrada (EABI) para la emulación del dispositivo y la imagen del sistema operativo (Figura 11).


Figura 11. Selección de un dispositivo basado en el procesador Intel® Atom™ en Android Virtual Device Manager

Si siguió los pasos descritos al comienzo del capítulo para instalar ADB y establecer un puente de depuración a un dispositivo físico, verá una entrada de selector de dispositivo en el IDE de Eclipse, desde la cual podrá escoger el destino para el desarrollo y la depuración de la aplicación.

En caso contrario, depurar una aplicación de Android destinada a la arquitectura Intel no es diferente de depurar una aplicación de Android destinada a la arquitectura ARM.

2. Supervisor de Ejecución Acelerada por Hardware Intel®

El Supervisor de Ejecución Acelerada por Hardware Intel® (Intel HAXM) es un motor de virtualización asistido por hardware (hipervisor) que usa Intel Virtualization Technology (Intel® VT) para acelerar la emulación de aplicaciones Android en máquinas host. En combinación con las imágenes de emulador Android x86 que suministra Intel y el Android SDK Manager oficial, Intel HAXM posibilita emular Android a mayor velocidad en sistemas con Intel VT habilitada.

La imagen de sistema del emulador x86 de Android* 4.0.4 (Ice Cream Sandwich) permite ejecutar una emulación de Android en la máquina de desarrollo. En combinación con el SDK de Android, puede probar sus aplicaciones de Android en un dispositivo virtual de Android basado en la arquitectura Intel y aprovechar la arquitectura y la tecnología de virtualización subyacentes de Intel.

Para instalar la imagen de sistema del emulador, puede usar el Android SDK Manager.

Intel HAXM se puede instalar por medio del Android SDK Manager (Figura 12). Exige que esté instalado el SDK de Android (versión 17 o superior). Hay más información disponible en el sitio web para desarrolladores de Android (http://developer.android.com/sdk/).


Figura 12. Descarga del Supervisor de Ejecución Acelerada por Hardware Intel®

Intel HAXM está disponible para hosts Linux, Windows e iOS. Como ejemplo, describimos más abajo la instalación en Ubuntu OS de 64 bits, ya que esta es la principal plataforma validada y admitida por Google para compilaciones de Android.

A continuación encontrará los pasos rápidos para instalar y habilitar la KVM en una plataforma host Ubuntu, e iniciar el emulador Android x86 de Intel con la virtualización asistida por hardware (hipervisor) de Intel. Cuando AVD aprovecha Intel HAXM, funciona de manera considerablemente más rápida y fluida que sin hipervisor.

2.1. Instalación de la KVM

 

  1. Para ver si su procesador admite la virtualización por hardware, observe el resultado de este comando:
    $ egrep -c '(vmx|svm)' /proc/cpuinfo
    Si devuelve el valor 0, su CPU no admite la virtualización por hardware.
  2. A continuación, instale el comprobador de CPU:
    $ sudo apt-get install cpu-checker
  3. Ahora puede comprobar si su CPU admite KVM:
    $kvm-ok
    1. Si ve:
      "INFO: Your CPU supports KVM extensions
      INFO: /dev/kvm exists
      KVM acceleration can be used"
      puede ejecutar su máquina virtual más rápido con las extensiones de KVM.
    2. Si ve:
      "INFO: KVM is disabled by your BIOS
      HINT: Enter your BIOS setup and enable Virtualization Technology (VT),
      and then hard poweroff/poweron your system
      KVM acceleration can NOT be used"
      debe ir a la configuración del BIOS y habilitar Intel VT.

2.2. Uso de un kernel de 64 bits

Se recomienda ejecutar un kernel de 64 bits en el sistema operativo del host, pero no es indispensable. Si se usarán más de 2 GB de RAM para las máquinas virtuales, es necesario utilizar un kernel de 64 bits. Con una instalación de kernel de 32 bits, habrá una limitación de 2 GB de RAM por máquina virtual. Además, los sistemas de 64 bits pueden ser hosts de huéspedes de 32 y 64 bits. Los sistemas de 32 bits sólo pueden ser hosts de huéspedes de 32 bits.

  1. Para ver si el procesador es de 64 bits, ejecute este comando:
    $ egrep -c ' lm ' /proc/cpuinfo
    Si se imprime el valor 0, significa que su CPU no es de 64 bits. Si el valor es 1 o superior, su CPU es de 64 bits. Nota: lm significa Long Mode (modo largo), que equivale a una CPU de 64 bits.
  2. Para ver si el kernel en ejecución es de 64 bits, use el siguiente comando:
    $ uname -m
    Si el valor devuelto es x86_64, el kernel que se está ejecutando es de 64 bits. Si ve i386, i486, i586 o i686, es de 32 bits.

2.3. Cómo instalar la KVM

Para instalar la KVM, siga estos pasos:

  1. Para Ubuntu 10.04 o superior:
    $ sudo apt-get install qemu-kvm libvirt-bin ubuntu-vm-builder bridge-utils
    Puede ignorar la solicitud de Postfix Configuration (configuración de postfijo) que se muestra en la Figura 13; para eso seleccione "No Configuration".

    Figura 13. Configuración de postfijo en la instalación de la KVM
  2. A continuación, agregue su cuenta <username> a los grupos kvm y libvirtd:
    $ sudo adduser your_user_name kvm
    $ sudo adduser your_user_name libvirtd
    Después de la instalación, es necesario que vuelva a iniciar sesión para que su cuenta de usuario pase a ser miembro activo de los grupos de usuario kvm y libvirtd. Estos miembros pueden ejecutar máquinas virtuales.
  3. Para verificar si la instalación ha sido exitosa, puede usar el siguiente comando:
    $ sudo virsh -c qemu:///system list

2.4. Cómo iniciar el dispositivo virtual de Android

El emulador Android para x86 de (Figura 14) se puede iniciar con este comando:

$ /tools/emulator-x86 -avd Your_AVD_Name -qemu -m 2047 -enable-kvm

donde Your_AVD_Name es un nombre elegido por usted; “-qemu” proporciona las opciones para qemu, y “-m” especifica la cantidad de memoria para el Android emulado (es decir, el huésped). Si usa un valor muy bajo para la memoria, es posible que el rendimiento se vea afectado debido a las actividades frecuentes de intercambio.


Figura 14. AVD ejecutando Android en capa de emulación de arquitectura Intel®

2.5. Uso del AVD Manager en Eclipse para iniciar un dispositivo virtual

Los siguientes pasos son los que recomienda Google para comenzar a depurar una aplicación mediante el uso de AVD desde dentro del IDE de Eclipse:

  1. En Eclipse, haga clic en la carpeta de su proyecto Android y seleccione Run > Run Configurations.
  2. En el panel izquierdo del cuadro de diálogo Run Configurations, seleccione la configuración de ejecución de su proyecto Android o cree una configuración nueva.
  3. Haga clic en la pestaña Target.
  4. Seleccione el AVD basado en arquitectura Intel que creó anteriormente.
  5. En el campo Additional Emulator Command Line Options, escriba:
    -qemu -m 2047 -enable-kvm
  6. Ejecute su proyecto Android con esta configuración de ejecución.

2.6. Cómo ejecutar Android dentro de Oracle* VirtualBox*

Ejecutar una imagen completa de Android OS en una PC de escritorio dentro de una máquina virtual Oracle VirtualBox es una buena alternativa a la KVM y QEMU en sistemas host Windows, en especial para aquellos que busquen desarrollar y depurar código nativo en Android.

En esta parte compartiremos algunos detalles acerca de:

  • compilar el instalador de Android 4.0.x VirtualBox para x86 a partir del destino de VirtualBox x86 vbox-x86-eng que ofrece Google en forma oficial (incluido en el árbol de código fuente de Android 4.0.1);
  • usar un kernel Linux 2.6 proporcionado por Intel para agregar prestaciones específicas a VirtualBox; y
  • cómo usar installer.vdi para instalar Android ICS 4.0 en VirtualBox.

Además del emulador de AVD de Google compatible con la tecnología Intel HAXM, Android para VirtualBox x86 se ejecuta en un verdadero entorno virtualizado basado en la arquitectura Intel. Así se cuenta con otra herramienta rápida y de alto rendimiento para desarrolladores y colaboradores dirigida a desarrollar y probar aplicaciones rápidamente. Iniciar Android 4.0.x en VirtualBox en un sistema host típico Intel® Core™ i5 lleva unos 20 segundos. La rapidez, el alto rendimiento y la experiencia satisfactoria del usuario explican la popularidad de que goza VirtualBox entre desarrolladores de Android, en especial cuando las plataformas de destino están basadas en la arquitectura Intel. La disponibilidad de tabletas y smartphones Android basados en la arquitectura Intel todavía es algo limitada en el mercado, por lo que podría convenir comenzar a usar un entorno virtual en el sistema host de desarrollo en lugar de depender de la comunicación de depuración por USB. Esta alternativa es en especial válida e interesante cuando tanto el host de desarrollo como el dispositivo de destino Android están basados en la arquitectura Intel.

2.7. Destinos de compilación de VirtualBox x86 de Google para Android 4.x

Si ha estado usando antes el repositorio de origen de Android 4.0.x que ofrece Google, quizá haya notado que Google proporciona una versión x86 del destino de VirtualBox vbox_x86-eng. Si se usa el comando lunch antes de iniciar la compilación, los tres primeros destinos que proporciona Google para Android 4.0.x son:

$ lunch

  1. full-eng
  2. full_x86-eng
  3. vbox_x86-eng

Con el destino vbox_x86-eng (#3), tanto los desarrolladores de aplicaciones como los de sistemas pueden crear paquetes de android_disk.vdi y android installer.vdi. Estos paquetes se pueden usar para ejecutar Android 4.x dentro de VirtualBox para desarrollar aplicaciones e integrar sistemas en Windows, Linux y en la plataforma OS X*.

2.7.1. Descarga del árbol de código fuente e instalación del repositorio

Para instalar, inicializar y configurar el repositorio, siga estos pasos (se pueden encontrar más detalles en http://source.android.com/source/downloading.html):

$ mkdir ~/bin
$ PATH=~/bin:$PATH
$ curl https://dl-ssl.google.com/dl/googlesource/git-repo/repo > ~/bin/repo
$ chmod a+x ~/bin/repo
$ mkdir ANDROID_TOP_PATH
$ cd ANDROID_TOP_PATH

Con este comando se obtiene una lista de ramas disponibles (del root de descarga de su repositorio de Android):

$ git --git-dir .repo/manifests/.git/ branch -a

Ejecute repo init para obtener una lista actual de las subramas de repositorio disponibles con todas las actualizaciones más recientes:

$ repo init -u https://android.googlesource.com/platform/manifest -b android-4.0.1_r1

Para usar la herramienta de revisión de código Gerrit*, necesitará una dirección de correo electrónico conectada con una cuenta de Google registrada. Asegúrese de que sea una dirección activa en la que pueda recibir mensajes. Se asignará a su compilación la versión de kernel y el número de compilación, y se mostrará la información en la página Android/settings/about phone/.

Si la inicialización es exitosa, aparecerá al final un mensaje de que Repo se inicializó en su directorio de trabajo. Su directorio de cliente debería contener ahora un directorio .repo donde se guardarán archivos tales como el manifiesto.

Para llevar archivos a su directorio de trabajo desde los repositorios como se especifica en el manifiesto predeterminado, ejecute

$ repo sync

En forma predefinida, el acceso al código fuente de Android es anónimo. Para proteger los servidores contra el uso excesivo, a cada dirección IP se le asigna una cuota.

2.7.2. Creación de un kernel personalizado que admita mouse

Como Android está dirigido a dispositivos con pantalla táctil, no admite puntero de mouse en forma predeterminada. Además, es posible que no incluya un controlador para conexión Ethernet por cable, ya que la mayoría de los dispositivos Android usan exclusivamente radios inalámbricas para la comunicación de red. Para agregar estas funcionalidades, deberá reconstruir el kernel para que admita mouse y todas las prestaciones que usted pueda necesitar. Estos pasos le permitirán hacerlo:

  1. Descargue el complemento Android x86 Emulator Image por medio del Android SDK Manager.
  2. Cree una nueva carpeta y descomprima kernel_sdk_x86.tar.gz en ella para que contenga el árbol de código fuente del kernel.
  3. Cambie al directorio que contiene los archivos del kernel.

Ahora que tenemos la fuente del kernel, es necesario modificar la configuración para que coincida con el hardware que se usa como sistema host de VirtualBox y recompilar. La interfaz gráfica menuconfig que proporcionan las fuentes del kernel permitirá hacer esto cómodamente:

$ cp ANDROID_TOP_PATH/your_kernel_path/arch/x86/configs/vbox_defconfig .config

$ make CC=gcc-4.4 CXX=g++-4.4 ARCH=x86 menuconfig

La compilación y la carga llevarán unos segundos.

Una vez completadas, use

  • las flechas arriba/abajo para navegar;
  • la tecla de entrada para seleccionar (expandir);
  • “y” (o la barra espaciadora) para incluir.

Para habilitar la compatibilidad con mouse, navegue a: Device Driver > Input Device Support > Mice.

Nota: menuconfig es la aplicación que se puede usar para revisar y asegurarse de que estén disponibles todas las características necesarias para que se admita la integración de su aplicación o sistema. En el caso de los desarrolladores de aplicaciones, es igual de importante que también prueben y validen la aplicación en compilaciones de Android predeterminadas. Sólo entonces será posible garantizar la compatibilidad máxima con dispositivos Android de diferentes fabricantes.

Ya hechos los cambios necesarios en la configuración del kernel, ahora podemos compilarlo. No lleva demasiado tiempo, así que elegí un valor ‘j’ bajo. Es importante observar que si se omiten los parámetros CC y CCX, la compilación terminará prematuramente (con esta configuración), sin un error explícito, ya que usará la versión 4.6.

$ make CC=gcc-4.4 CXX=g++-4.4 ARCH=x86 –j8

Donde el parámetro –j indica la cantidad de núcleos disponibles para la compilación. En el ejemplo anterior se supone que el sistema es de cuatro núcleos con tecnología Intel® Hyper-Threading habilitada.

Después de que la compilación se complete con éxito, la última línea del registro de compilación será

Kernel: arch/x86/boot/bzImage is ready

2.7.1. Cómo agregar el kernel con parche

Es necesario cambiar el nombre de la imagen de kernel bzImage a kernel-vbox y copiarla a /ANDROID_TOP_PATH/prebuilt/android-x86/kernel/kernel-vbox:

$ cp /ANDROID_TOP_PATH/kernel/arch/x86/boot/bzImage /ANDROID_TOP_PATH/prebuilt/android-x86/kernel/kernel-vbox

2.7.2. Reducción del tiempo de compilación con el uso de CCACHE

Se puede reducir mucho el tiempo necesario para las compilaciones posteriores si se usa el caché de compilación. Para establecer un caché de 50 GB, haga lo siguiente:

  1. Instale el programa CCcache y cree un directorio para su ccache
    $ sudo apt-get install ccache
    $ sudo mkdir /ANDROID_TOP_PATH/ccache
    $ sudo chown $LOGNAME /ANDROID_TOP_PATH/ccache
  2. Configure las variables de su entorno para que sean compatibles con ccache; para ello modifique ~/.bashrc
    $ sudo gedit ~/.bashrc
  3. Agregue:
    export CCACHE_DIR=/ANDROID_TOP_PATH/ccache
    export USE_CCACHE=1
  4. Establezca los tamaños de ccache.
    $ ccache -F 100000
    $ ccache -M 50G

2.7.3. Cómo compilar Android 4.0.x con nuevo kernel

Configuración del entorno:

$ /ANDROID_TOP_PATH/> source build/envsetup.sh
Para ICS 4.0.1, verá:
including device/samsung/maguro/vendorsetup.sh
including device/samsung/tuna/vendorsetup.sh
including device/ti/panda/vendorsetup.sh
including sdk/bash_completion/adb.bash

Para asegurarse de elegir un destino válido cuando use el comando lunch, conviene hacer lo siguiente:

$ lunch

y elegir el destino deseado de la lista:
1. full-eng
2. full_x86-eng
3. vbox_x86-eng
4. full_maguro-userdebug
5. full_tuna-userdebug
6. full_panda-eng

¿Cuál preferiría? [full-eng]

Nota: asegúrese de seleccionar 3. vbox_x86-eng.

PLATFORM_VERSION_CODENAME=REL
PLATFORM_VERSION=4.0.1
TARGET_PRODUCT=vbox_x86
TARGET_BUILD_VARIANT=eng
TARGET_BUILD_TYPE=release
TARGET_BUILD_APPS=
TARGET_ARCH=x86
TARGET_ARCH_VARIANT=x86
HOST_ARCH=x86 HOST_OS=linux
HOST_BUILD_TYPE=release
BUILD_ID=ITL41D

Ejecute make

$ make -j8

2.8. Cómo compilar el disco de VirtualBox y el instalador de Android

Por último, compile Android_disk.vdi e installer_vdi juntos:

$ make android_disk_vdi installer_vdi -j8

Si la compilación es exitosa, verá lo siguiente en el registro de compilación:

Done with VirtualBox bootable disk image -[ out/target/product/vbox_x86/android_disk.vdi ]-
Done with VirtualBox bootable installer image -[ out/target/product/vbox_x86/installer.vdi ]-

Con el android_disk.vdi así creado, ahora puede seleccionar New > Create New Virtual Machine en VirtualBox y usar android_disk.vdi como imagen de disco existente que sirva de base para la máquina virtual, que ahora iniciará automáticamente Android 4.0.x.

La configuración de los parámetros de inicio de VirtualBox* es directa. Vaya a Settings > About this phone para ver la información de su compilación (Figura 15):
Figura 15. Información de compilación de Android 4.0.x dentro de Oracle VirtualBox

2.9. Como usar un disco de instalación de Android para crear una partición virtual grande

Aunque se expanda el tamaño de archivo en VirtualBox a ~550 MB, sigue siendo demasiado pequeño si se quiere cargar aplicaciones para probarlas. Se necesita un disco de instalación para instalar Android en una partición mucho más grande (de preferencia, mayor que 4 GB).

Primero seleccione Machine > New de la barra de menú de VirtualBox y use el asistente Create New Virtual Machine Wizard para crear un disco más grande bajo la entrada de configuración del controlador IDE.

Luego en Settings > Storage de su máquina virtual, agregue installer.vdi como esclavo IDE primario (Primary IDE Slave), como se muestra en la Figura 16. Ahora puede comenzar a instalar Android en el disco más grande, de 4 GB, que recién ha creado.


Figura 16. Configuración de almacenamiento para máquina virtual

  1. Inicie el emulador.
  2. Use F12 para ir al menú de inicio del BIOS. Inicie con la unidad secundaria,
  3. Use grub para seleccionar la opción de instalación: 2. Boot from Primary Slave, para iniciar desde la unidad esclava primaria (Figura 17).


Figura 17. Cómo iniciar la imagen del instalador dentro de VirtualBox

Cuando vea el mensaje “Done processing installer config” que indica que la configuración del instalador ha sido procesada, escriba “reboot”.

Nota: la primera vez que intente instalar en el disco virtual objetivo, es posible que la instalación fracase. Aparecerá un mensaje que le pedirá volver a ejecutar el instalador. Hágalo con el siguiente comando:

$ installer

Después del reinicio, verá que su Android se está ejecutando desde el disco de mayor tamaño que ha creado y podrá quitar sin riesgos installer.vdi de Storage bajo la configuración del controlador IDE de VirtualBox.

2.10. Puerto serie

En la máquina virtual, la compatibilidad con puerto serie está habilitada de manera predeterminada. Sin embargo, es necesario inicializar y configurar el puerto serie COM1 antes de poder usarlo. Las siguientes instrucciones harán que VirtualBox cree una named pipe llamada .vbox_pipe en su directorio home. En la línea de comandos, ingrese:

$ VBoxManage modifyvm Android --uart1 0x03f8 4

$ VBoxManage modifyvm Android --uartmode1 server /home/user/.vbox_pipe

Como alternativa, desde la interfaz gráfica de usuario de VirtualBox, use la pestaña Serial Ports del menú de configuración “Virtual Machine Settings” para habilitar COM1 como "Host Pipe" y seleccione Create Pipe para que se cree como /home/user/.vbox_pipe.

Para conectarse a esta named pipe, use:

$ socat unix-client:$HOME/.vbox_pipe stdout

Nota: es posible que VirtualBox no entienda las variables de entorno (como $HOME), así que deberá especificar la ruta completa específica, como por ejemplo /home/user/.vbox_pipe.

2.11. Ethernet

El puerto Ethernet (eth0) está habilitado para DHCP en la imagen. Para conectarse a él por ADB, deberá buscar la dirección DHCP que se le ha asignado.

Si está usando Ethernet en puente, puede obtener esta dirección a partir de una petición del shell, ya sea desde el puerto serie o desde Developer Tools > Terminal Emulator mediante el uso del comando:

$ netcfg

Si está usando un adaptador sólo Host, “vboxnet0”, debería usar la dirección 192.168.56.101.

2.12. Notas finales

Ahora ya tiene una imagen de VirtualBox ejecutándose en Android 4.0.x compilada por completo a partir del destino vbox-x86 oficial de Google (Figura 18).


Figura 18. Android OS iniciado por completo dentro de la máquina virtual VirtualBox

3. Depuración con GDB, el depurador de GNU Project

El NDK de Android incluye GDB, el depurador de GNU, que permite iniciar, pausar, examinar y modificar programas. En dispositivos Android, y más generalmente en dispositivos integrados, GDB está configurado en modo cliente/servidor. El programa se ejecuta en el dispositivo como servidor y cliente remoto. La estación de trabajo del desarrollador se conecta a él y envía comandos de depuración de manera similar a una aplicación local. GDB en sí es una utilidad de línea de comandos. Veamos primero su modelo básico de uso antes de echar un vistazo también a la integración con Eclipse CDT.

Al depurar con GDB, se usa gdbserver, que se ejecuta en el dispositivo, para manejar la comunicación de depuración, pero puede seguir usándose un controlador de llave subyacente USB a Ethernet con ADB para manejar la capa de transporte de comunicación en la cual gdbserver se comunica mediante TCP/IP con GDB ejecutándose en el host de desarrollo.

Hay una aplicación gdbclient que establece el entorno de comunicación de depuración e inicia gdbserver en el dispositivo depurado.

uso: gdbclient EXECUTABLE :PORT [PROG_PATH]

EXECUTABLE nombre del ejecutable (el predeterminado es app_process)

PORT puerto de conexión (predeterminado :1234)

PROG_PATH ruta completa del ejecutable en el destino (ej. /system/bin/mediaserver)

Si PROG_PATH está establecido, gdclient intenta iniciar gdbserver y asociarlo al

PROG_PATH actual.

Para iniciar gdbserver explícitamente, se puede usar el comando siguiente:

# gdbserver :1234 --attach 269

Attached; pid = 269

Listening on port 1234

Las instrucciones paso a paso de inicio de sesión de depuración que se incluyen más abajo ilustran cómo ADB todavía es subyacente a la comunicación de depuración, pese a que se usa GDB para depurar, no ADT o DDMS. Supongamos que se está usando el

puerto 1234.

Proceso de inicio:

gdbserver :1234 /system/bin/executable

o asociar a un proceso existente.

gdbserver :1234 --attach pid

En su estación de trabajo, redireccione el puerto 1234 al dispositivo con adb:

adb forward tcp:1234 tcp:1234

Inicie una versión especial de gdb que esté en el área “prebuilt” del árbol de código fuente:

prebuilt/Linux/toolchain-eabi-4.x.x/bin/i686-android-linux-gdb (para Linux)

prebuilt/darwin-x86/toolchain-eabi-4.x.x/bin/i686-android-linux-gdb (para Darwin)

Si no encuentra ninguna de las dos versiones especiales de GDB, ejecute find prebuilt –name i686-android-linux-gdbin en su árbol de código fuente para buscar y ejecutar la versión más reciente. Asegúrese de usar la copia del ejecutable que se encuentra en el directorio de símbolos, no en el directorio principal de Android, porque a la de este último directorio se le ha quitado la información de símbolos.

En GDB, dígale a GDB dónde encontrar las bibliotecas compartidas que se cargarán:

set solib-absolute-prefix /absolute-source-path/out/target/product/product-name/symbols

set solib-search-path /absolute-source-path/out/target/product/product-name/symbols/system/lib

La ruta al árbol de código fuente es absolute-source-path. Asegúrese de que los directorios especificados sean los correctos, Es posible que si comete un error, GDB no se lo diga. Use este comando para conectarse con el dispositivo:

(gdb) target remote :1234

El :1234 le dice a GDB que se conecte con el puerto 1234 de localhost, que está en puente con el dispositivo mediante ADB.

Ahora puede comenzar a depurar con GDB código C/C++ nativo ejecutado en Android, de la misma manera que está acostumbrado a hacerlo. Si además tiene instalado Eclipse, lo cual es muy probable si está usando el SDK de Android SDK para desarrollo de aplicaciones basadas en Dalvik*/Java*, se puede usar directamente Eclipse y su integración con GDB para agregar puntos de interrupción e inspeccionar programas.

Por cierto, Eclipse puede insertar puntos de interrupción con facilidad en Java y archivos fuente de C/C++; sólo hay que hacer clic en el margen izquierdo del editor de texto. Los puntos de interrupción de Java funcionan de forma predeterminada gracias al complemento ADT, que administra la depuración mediante Android Debug Bridge. Esto no es así para CDT, que, por supuesto, no está preparado para funcionar con Android. Por lo tanto, insertar un punto de interrupción no tendrá efecto a menos que configuremos CDT para usar el GDB del NDK, el cual a su vez necesita estar enlazado a la aplicación nativa de Android para depurarla. Primero, se debe habilitar el modo de depuración en su aplicación. Deben seguirse estos pasos:

  1. Algo muy importante que se debe hacer, y muy fácil de olvidar, es activar el indicador de depuración en su proyecto de Android. Esto se hace en el manifiesto de la aplicación AndroidManifest.xml. No se olvide de usar la versión apropiada del SDK para el código nativo:
    <?xml version="1.0" encoding="utf-8"?> <manifest ...> <uses-sdk android:minSdkVersion="10"/> <application ... android:debuggable="true"> ...
  2. Al habilitarse el indicador de depuración en el manifiesto, se activa automáticamente el modo de depuración en el código nativo. Sin embargo, el indicador APP_OPTIM también controla el modo de depuración. Si se lo ha establecido de forma manual en Android.mk, entonces compruebe que su valor sea debug (y no release) o simplemente elimínelo:
    APP_OPTIM := debug
  3. Ahora configuremos el cliente de GDB que se conectará con el dispositivo. Vuelva a compilar el proyecto y enchufe el dispositivo o inicie el emulador. Ejecute su aplicación y salga de ella. Asegúrese de que se encuentre cargada y su PID esté disponible. Para comprobarlo, puede usar el siguiente comando que mostrará la lista de procesos (en Windows, use Cygwin):
    $ adb shell ps |grep gl2jni
    Debe devolver una línea:
    app_75 13178 1378 201108 68672 ffffffff 80118883 S com.android.gl2jni
  4. Abra una ventana de terminal y vaya al directorio de su proyecto. Ejecute el comando ndk-gdb (situado en la carpeta Android NDK, por ejemplo android-ndk-r8\):
    $ ndk-gdb
    Este comando no debe devolver un mensaje, sino crear tres archivos en el directorio obj\local\x86:
    • gdb.setup: este es un archivo de configuración generado por el cliente de GDB.
    • app_process: este archivo se toma directamente de su dispositivo. Es un archivo ejecutable de sistema, que se inicia cuando arranca el sistema y se desdobla para iniciar una nueva aplicación. GBD necesita este archivo de referencia para encontrar sus marcas. En cierto modo, es el punto de entrada binario a su aplicación.
    • libc.so: este archivo también se toma directamente de su dispositivo. Es la biblioteca C estándar de Android (conocida como biónica) que usa GDB realizar el seguimiento de todos los hilos nativos creados durante el tiempo de ejecución.

    En el directorio de su proyecto, copie obj\local\x86\gdb.setup y cámbiele el nombre a gdb2.setup. Ábralo y elimine la línea siguiente que solicita al cliente de GDB que se conecte con el servidor de GDB que se ejecuta en el dispositivo (esto lo hará el propio Eclipse):
    (gdb) target remote :1234
  5. En el menú principal de Eclipse, vaya a Run | Debug Configurations... y cree una nueva configuración de depuración en el elemento de la aplicación C/C++ llamado GL2JNIActivityDefault. Esta configuración iniciará el cliente de GDB en su computadora y se conectará con el servidor de GDB que se ejecuta en el dispositivo.
  6. En la pestaña Main (Figura 19), escriba en Project el directorio de su propio proyecto y use el botón Browse para que C/C++ Application apunte a obj\local\ x86\app_process (puede usar una ruta absoluta o relativa).

    Figura 19. Configuración de depuración para aplicación C/C++
  7. Cambie el tipo de iniciador a Standard Create Process Launcher (Figura 20); para ello use el vínculo Select other... que encontrará en la parte inferior derecha de la ventana.

    Figura 20. Selección del iniciador preferido
  8. Vaya al archivo de depuración, establezca el tipo de depurador como gdbserver y el depurador de GDB como android-ndk-r8\toolchains\x86-4.4.3\prebuilt\windows\bin\i686-android-linux-gdb.exe. Es necesario que el archivo de comandos de GDB (Figura 21) apunte al archivo gdb2.setup situado en \obj\local\x86 (puede usar una ruta absoluta o relativa).

    Figura 21. Panel de configuración del depurador
  9. Vaya a la pestaña Connection (Figure 22) y elija TCP en Type. Conserve los valores predeterminados para Host name or IP address y Port number (localhost, 5039).

    Figura 22. Configuración de la conexión en el panel de configuración del depurador
  10. Ahora configuremos Eclipse para ejecutar el servidor de GDB en el dispositivo. Haga una copia de android-ndk-r8\ndk-gdb y ábrala con un editor de texto. Busque la línea siguiente:
    $GDBCLIENT -x `native_path $GDBSETUP`
    Conviértala en comentario porque el cliente de GDB va a ser ejecutado por Eclipse mismo:
    #$GDBCLIENT -x `native_path $GDBSETUP`
  11. En el menú principal de Eclipse, vaya a Run | External Tools | External Tools | Configurations... (Figure 23) y cree una nueva configuración GL2JNIActivity_GDB. Esta configuración iniciará el servidor de GDB en el dispositivo.
  12. En la pestaña Main, haga que Location apunte a su ndk-gdb modificado en android-ndk-r8. Establezca como directorio de trabajo (Working Directory) el directorio en el que se encuentra la aplicación. Como opción, puede configurar el cuadro de texto Arguments:
    • verbose: para ver en detalle que sucede en la consola de Eclipse.
    • force: para anular automáticamente toda sesión anterior.
    • start: para dejar que el servidor de GDB inicie la aplicación en lugar de asociarse a la aplicación después de que se la ha iniciado. Esta opción es interesante si depura sólo código nativo y no Java.

    Figura 23. Configuración de herramientas externas
  13. Ahora, inicie su aplicación de la manera habitual.
  14. Una vez que se inicie la aplicación, puede iniciar ndk-gdb directamente por la consola o iniciar la configuración de herramienta externa GL2JNIActivity_GDB, que va a iniciar el servidor de GDB en el dispositivo. El servidor de GDB recibe comandos de depuración que envía el cliente de GDB remoto y depura su aplicación localmente.
  15. Abra jni\gl_code.cpp y establezca un punto de interrupción (Figura 24) en setupGraphics; para hacerlo, haga doble clic en el margen izquierdo del editor de texto (o haga clic con el botón derecho y seleccione Toggle breakpoint [alternar punto de interrupción]).

    Figura 24. Establecimiento de puntos de interrupción
  16. Por último, inicie la configuración de aplicación C/C++ predeterminada GL2JNIActivity para iniciar el cliente de GDB. Retransmite comandos de depuración de Eclipse CDT al servidor de GDB por una conexión de socket. Desde el punto de vista del desarrollador, esto es casi como depurar una aplicación local.

3. Analizadores de Rendimiento de Gráficos Intel® (Intel GPA)

Existen también herramientas específicas para depurar el rendimiento de gráficos. El Analizador de Sistemas GPA de Intel® (Intel® GPA System Analyzer) es uno de los Analizadores de Rendimiento de Gráficos Intel® (Intel® GPA) con nueva compatibilidad para dispositivos Android basados en Intel y su finalidad es que los ingenieros de aplicaciones y controladores optimicen sus cargas de trabajo de OpenGL* ES.

En esta sección se brindan instrucciones para configurar y usar Intel GPA con su dispositivo Android mediante una conexión USB. Cuando el Analizador de Sistemas GPA de Intel está conectado a un dispositivo Android, proporciona métricas de rendimiento de OpenGL ES API, CPU y GPU, y también proporciona múltiples reemplazos de estado de pipelines de gráficos para ayudarlo a analizar el rendimiento de la aplicación OpenGL ES.

Para usar el Analizador de Sistemas GPA de Intel en dispositivos Android basados en x86, es necesario que compruebe la máquina de destino y la versión del firmware desde el documento.

Para comenzar a recopilar métricas, necesita instalar el Analizador de Sistemas GPA de Intel en el sistema cliente y conectarlo al dispositivo de destino:

  1. Instale Intel GPA 2012 en la máquina cliente Windows/Linux.
  2. Inicie el Analizador de Sistemas GPA de Intel.
  3. Asegúrese de que los dispositivos Android estén conectados al sistema cliente por cable USB.
  4. Espere hasta 10 segundos mientras su sistema cliente detecta los dispositivos de destino. Los dispositivos encontrados aparecen en la ventana de diálogo. La lista de dispositivos de destino se actualiza cada 5 o 6 segundos.
  5. Busque el dispositivo que quiera conectar y haga clic en Connect (Figura 25). El Analizador de Sistemas GPA de Intel copiará los componentes necesarios al dispositivo de destino y generará una lista de aplicaciones instaladas. Si desea interrumpir el proceso de conexión, haga clic en Stop.

    Figura 25. Selección del dispositivo conectado
  6. Seleccione la aplicación deseada de la lista de aplicaciones disponibles. La pantalla Application List (Lista de aplicaciones, Figura 26) muestra todas las aplicaciones de usuario y de sistema instaladas en el dispositivo Android.

    Figura 26. Lista de aplicaciones
  7. La aplicación se iniciará y usted verá sus datos en la ventana del Analizador de Sistemas GPA de Intel.
  8. Para cambiar a otra aplicación, haga clic en Back. Tenga en cuenta que se forzará el cierre de la aplicación que se está ejecutando.
  9. Para cambiar a otro dispositivo de destino, haga clic en Back. La arquitectura de gráficos PowerVR consiste en los siguientes módulos principales que convierten los datos enviados de aplicaciones 3D en una imagen representada: Tile Accelerator (TA), Image Synthesis Processor (ISP) y Texture &s; Shading Processor (TSP). Las métricas de Intel GPA que están en el grupo “GPU” corresponden a uno de estos módulos, y el orden de las métricas en la lista de métricas (Metrics List) depende del orden de los módulos en el pipeline de gráficos (Figura 27).

    Figura 27. Ventana del Analizador de Sistemas GPA de Intel®

4. Depuración de sistema de Android OS ejecutándose en un procesador Intel® Atom™

Hasta ahora nos hemos ocupado del desarrollo y la depuración de aplicaciones, ya sea que sólo usen el Java* Runtime de Android o se ejecuten en forma nativa como objetos compartidos y binarios de la Arquitectura Intel® x86.

Sin embargo, es posible que el integrador de sistemas y el fabricante de dispositivos necesiten trabajar en la capa de la pila de software del sistema y los controladores del dispositivo. Esto es en especial así cuando es necesario implementar la compatibilidad con dispositivos periféricos para una plataforma específica o si se realiza la primera portación del sistema operativo a un nuevo dispositivo basado en procesador Intel® Atom™.

En los siguientes capítulos veremos las soluciones de depuración para este fin basadas en la norma IEEE 1149.1 (JTAG) y las diferencias entre la arquitectura ARM* y la Arquitectura Intel® que pueden incidir en la depuración a nivel de sistema.

4.1. Depuración JTAG

Para la depuración de controladores de dispositivos y de sistema a nivel de sistema operativo y firmware, el método más común en el mundo de los sistemas inteligentes integrados es usar una interfaz JTAG. La norma IEEE 1149.1 de Joint Test Action Group (JTAG) define un “Puerto de acceso de prueba estándar y una arquitectura de exploración de límites para puertos de acceso de prueba utilizados con el fin de evaluar placas de circuito impreso”. A esta norma se la llama habitualmente interfaz de depuración JTAG. Desde sus comienzos como norma para pruebas de placas de circuito, se ha convertido en la norma de interfaz de facto para depuración de plataformas a nivel de sistema operativo o independiente del sistema operativo.

Encontrará más información sobre JTAG y su uso en la depuración de pila de software de sistemas modernos en el artículo “JTAG 101; IEEE 1149.x and Software Debug” (“JTAG 101; IEEE 1149.x y depuración de software”) escrito por Randy Johnson y Stewart Christie (http://download.intel.com/design/intarch/papers/321095.pdf).

Desde la perspectiva del OEM y la de sus socios desarrolladores de aplicaciones y controladores, entender la interacción entre el controlador y los componentes de la pila de software que se ejecutan en diferentes partes del sistema inteligente integrado system-on-chip (SoC) o en dispositivos con diferentes factores de forma es crucial para determinar la estabilidad de la plataforma. Desde la perspectiva del validador de silicio, la pila de software de bajo nivel proporciona el entorno de prueba que expone la clase de factores de estrés a los que se expondrá la plataforma durante el uso en el mundo real. En pocas palabras, los SoCs modernos requieren que se comprenda el conjunto en forma integral y sus complejas interacciones con el mundo real, no que sólo se preste atención a resultados unitarios positivos de componentes individuales de hardware. Este es el nivel de entendimiento que puede proporcionar el enfoque de depuración de software de sistema basado en JTAG. Para que esto sea así, se deben combinar los conocimientos profundos que proporciona inherentemente la interfaz JTAG acerca del software con la capacidad de exportar información de estado del sistema operativo Android que se ejecuta en el destino.

Es importante, en especial para depurar controladores de dispositivos, comprender tanto el estado exacto del dispositivo periférico en el chipset como la interacción del controlador de dispositivo con la capa del sistema operativo y el resto de la pila de software.

Si se mira a Android desde la perspectiva de la depuración del sistema, con la atención dirigida a los controladores y el kernel del OS, en realidad no es sino una rama especializada de Linux. Por lo tanto, se puede tratar como cualquier Linux 2.6.3x o superior.

El procesador Intel® Atom™ Z2460 admite Boundary Scan y MPI Parallel Trace Interface (PTI) de IEEE-1149.1 y IEEE-1149.7 (JTAG), como así también rastreo de instrucciones basados en Branch Trace Storage (BTS), Last Branch Record (LBR) y Architectural Event Trace (AET) por medio del eXtended Debug Port (XDP) de Intel compatible con JTAG.

Hay diversos proveedores de JTAG que ofrecen soluciones de depuración de sistemas compatibles con Android, incluidos:

4.2. Depuración en Android OS

Lo que complica depurar plataformas basadas en Android es que este sistema operativo por lo general aprovecha agresivamente los estados de inactividad con poco uso de energía y los de suspensión para optimizar el consumo de energía. Por lo tanto, la verdadera dificultad consiste en depurar en estados de bajo consumo de energía y

  • o bien mantener la funcionalidad de JTAG durante algunos de los estados de bajo consumo;
  • o, cuando esto no sea posible, volver a asociar JTAG ni bien se vuelva a habilitar el dominio de consumo de energía del chipset para JTAG.

Muchos problemas a nivel de sistema operativo de estos tipos de plataforma tienen a centrarse en los cambios de modo de consumo de energía y el orden de las secuencias de suspensión/reactivación.

El depurador de sistema, ya sea basado en un agente de depuración o que use una interfaz de dispositivo JTAG, es una herramienta muy útil para ayudar a cumplir varios de los objetivos clave de desarrollo en el sistema operativo.

El depurador se puede usar para validar el proceso de inicio y analizar y corregir problemas de estabilidad tales como errores de tiempo de ejecución, errores de segmentación o servicios que no se inician correctamente durante el arranque.

Además se puede usar para identificar y corregir problemas de configuración del sistema operativo, ya que proporciona accesos detallados y representaciones de tablas de páginas, tablas de descriptor y también rastreo de instrucciones. La combinación de rastreo de instrucciones y acceso a tablas de memoria puede ser una herramienta muy potente para determinar las causas originales de desbordamientos de pila, pérdidas de memoria e incluso situaciones de anulación de datos.

La Figura 28 muestra la traducción de la tabla de páginas de direcciones físicas a direcciones de memoria virtual. Con la gran flexibilidad que ofrece x86 para definir la profundidad de las tablas de traducción y la granularidad de los bloques de memoria direccionados, este nivel de facilidad de acceso y visibilidad de la distribución de la memoria se vuelve más importante para el desarrollo de sistemas a nivel de sistema operativo.


Figura 28. Traducción de dirección lógica a dirección lineal

Para traducir una dirección lógica a una dirección lineal, el procesador hace lo siguiente:

  1. Usa el desplazamiento del selector de segmento para localizar el descriptor del segmento del GDT o LDT y lo lee al procesador (este paso sólo es necesario cuando se carga un nuevo segmento al registro de segmentos).
  2. Examina el descriptor del segmento para comprobar los derechos de acceso y el rango del segmento con el fin de garantizar que el segmento sea accesible y que el desplazamiento se encuentre dentro de sus límites.
  3. Agrega la dirección base del segmento desde el descriptor hasta el desplazamiento para formar una dirección lineal.
  4. Si no se utiliza paginación, el procesador mapea la dirección lineal directamente a la dirección física (es decir, la dirección lineal sale en el bus de dirección del procesador). Si se pagina el espacio de direcciones lineales, se usa un segundo nivel de traducción de direcciones para traducir la dirección lineal a la dirección física.

Cuando funciona en modo protegido, la Arquitectura Intel permite que el espacio de direcciones lineales se mapee directamente a una memoria física grande (por ejemplo, 4 GB de RAM) o indirectamente (con el uso de paginación) a una memoria física y un espacio almacenamiento de disco más pequeños. A este último método de mapeo del espacio de direcciones lineales es común que se lo llame de memoria virtual o de memoria virtual paginada por demanda.

Cuando se utiliza paginación, el procesador divide el espacio de direcciones lineales en páginas de tamaño fijo (por lo general, de 4 KB de longitud) que se pueden mapear a la memoria física o al espacio de almacenamiento del disco. Cuando un programa (o una tarea) hace referencia a una dirección lógica de la memoria, el procesador traduce la dirección a una dirección lineal y luego usa su mecanismo de paginación para traducir la dirección lineal a una dirección física correspondiente. Si la página que contiene la dirección lineal no está en ese momento en la memoria física, el procesador genera una excepción de error de página (#PF). El controlador de excepciones de la excepción de error de página normalmente indica al sistema operativo o ejecutivo que cargue la página desde el espacio de almacenamiento del disco a la memoria física (y quizá a la vez escriba una página diferente de la memoria física al disco). Cuando se ha cargado la página en la memoria física, un valor devuelto por el controlador de excepciones hace que se reinicie la instrucción que generó la excepción. La información que usa el procesador para mapear direcciones lineales al espacio de direcciones lineales y para general excepciones de error de página (cuando es necesario) está contenida en los directorios de páginas y las tablas de páginas almacenados en la memoria.

La paginación es diferente de la segmentación, porque usa páginas de tamaño fijo. A diferencia de los segmentos, que por lo general son del mismo tamaño que las estructuras de datos o código que contienen, las páginas tienen un tamaño fijo. Si la única forma de traducción de direcciones que se utiliza es la segmentación, las estructuras de datos presentes en la memoria física tendrán todas sus partes en la memoria. Si se utiliza la paginación, las estructuras de datos pueden estar en parte en la memoria y en parte en el espacio de almacenamiento del disco.

Para reducir al mínimo la cantidad de ciclos de bus necesarios para traducir direcciones, las entradas de directorio de páginas y tablas de páginas a las que se accedió más recientemente se guardan en el caché del procesador, en dispositivos llamados búferes de traducción de direcciones (TLB). Los TLB satisfacen la mayoría de los requisitos de lectura de directorio de páginas y tablas de páginas actuales sin necesidad de un ciclo de bus. Sólo se producen ciclos de bus adicionales cuando los TLB no contienen una entrada de tabla de páginas, lo que normalmente ocurre cuando no se ha accedido a una página durante mucho tiempo.

Esto pone de relieve dos diferencias esenciales entre desarrollar y configurar la pila de software de Android OS en la arquitectura Intel y en muchas otras arquitecturas. El modelo de direccionamiento de desplazamiento y base del selector, combinado con la tabla de descriptores locales (LDT) y la tabla de descriptores globales (GDT), permite hacer una traducción profunda y multicapa de direcciones desde la memoria física hasta la virtual con granularidad variable del fragmento de direcciones. Esta es una funcionalidad potente para configurar la memoria de manera personalizada en un entorno compartimentalizado con espacios de memoria aislados que están protegidos. Sin embargo, si se la usa de manera incorrecta, también puede incrementar los tiempos de acceso a la memoria. Por lo tanto, la buena visibilidad de la traducción de páginas de memoria es una característica deseable.

Otra diferencia entre la arquitectura Intel y otras es el manejo de las interrupciones del sistema. Por ejemplo, en ARM, se tiene un conjunto predefinido de interrupciones de hardware en el espacio de direcciones reservadas de 0x0 a 0x20. Estas ubicaciones contienen a su vez instrucciones de saltos al controlador de interrupciones. En la arquitectura Intel, se emplea un controlador de interrupción de hardware dedicado. A las interrupciones de hardware no se accede directamente por el espacio de memoria, sino mediante el acceso al controlador de interrupciones Intel® 8529. La ventaja de este enfoque es que el controlador de interrupciones permite controlar en forma directa las interrupciones de E/S para los dispositivos conectados. En las arquitecturas que no usan un controlador de interrupciones dedicado, por lo general se ha sobrecargado el interruptor IRQ con una rutina controladora de interrupciones más compleja para lograr esto.

5.1. Depuración de controladores de dispositivos

Una buena solución de depuración JTAG para nivel de sistema operativo debería proporcionar además visibilidad de los hilos de kernel y los módulos activos de kernel, junto con otra información exportada por el kernel. Para permitir la depuración de controladores de dispositivos y servicios cargados dinámicamente, se puede usar un parche de kernel o un módulo de kernel que exporte la ubicación de la memoria del método de inicialización y el método de destrucción del controlador.

También es importante, en especial para depurar controladores de dispositivos y la configuración del sistema, poder acceder y revisar en forma directa el contenido de los registros de configuración de los dispositivos. Estos registros y su contenido se pueden listar simplemente con sus valores hexadecimales de registro o visualizar como campos de bits, tal como se muestra en la Figura 29. La visualización bit a bit hace más fácil detectar y comprender cambios realizados al estado de un dispositivo durante la depuración, mientras el controlador asociado está interactuando con él.


Figura 29. Vista de campo de bits del registro de dispositivo

Es posible analizar el código después de que se ha desempaquetado en la memoria la imagen de kernel zImage comprimida simplemente mediante la liberación del control de ejecución en el depurador hasta alcanzar start_kernel. Esto implica, por supuesto, que se ha cargado el archivo vmlinux que contiene la información de símbolos del kernel. En este punto, es posible usar puntos de interrupción de software. Antes de este punto en el proceso de inicio, sólo se deben usar puntos de interrupción de hardware basados en el registro de puntos de interrupción, para evitar que el depurador intente escribir instrucciones de punto de interrupción en la memoria no inicializada. Luego, se inicia el sistema operativo exitosamente una vez que se ha alcanzado el bucle inactivo mwait_idle.

Además, si su solución de depuración brinda acceso a rastreo de instrucciones basado en Last Branch Storage (LBR), esta funcionalidad se puede usar, en conjunto con todas las prestaciones de control de ejecución regulares de un depurador JTAG, para forzar la detención de la ejecución en una excepción y analizar el flujo de ejecución en sentido inverso con el fin de identificar la causa original de los problemas de tiempo de ejecución.

Last Branch Records se puede usar para rastrear la ejecución de código desde el restablecimiento del destino. Como las discontinuidades en la ejecución del código se guardan en estos MSR, los depuradores pueden reconstruir el código ejecutado mediante la lectura de las direcciones de origen y destino, el acceso a la memoria entre ubicaciones específicas y el desensamblaje del código. El desensamblaje se muestra por lo general en una interfaz gráfica de rastreo en la interfaz del depurador. Esto podría ser útil para ver qué código se ejecutó antes de una interrupción de administración del sistema (SMI) o alguna otra excepción si el punto de interrupción está establecido en la interrupción.

5.2. Puntos de interrupción de hardware

Tal como ocurre con la arquitectura ARM, los procesadores basados en la arquitectura Intel admiten instrucciones de punto de interrupción para puntos de interrupción tanto de software como de hardware, para datos y código. En la arquitectura ARM, por lo general se tiene un conjunto de registros dedicados para puntos de interrupción y punto de interrupción de datos (watchpoints). La implementación común tiende a proporcionar dos de cada uno. Cuando estos registros contienen un valor, el procesador los compara con accesos a la dirección de memoria por parte del registro contador del programa o una lectura/escritura de memoria. Ni bien se produce el acceso, la ejecución se detiene. Esta es una forma diferente de puntos de interrupción de software, en el sentido de que la ejecución se detiene de inmediato cuando se encuentra una instrucción de punto de interrupción. Como la instrucción de punto de interrupción reemplaza a la instrucción de ensamblaje que se encontraría normalmente en una dirección de memoria determinada, la ejecución se detiene efectivamente antes de que se ejecute la instrucción que se hallaría normalmente en la ubicación del punto de interrupción.

La implementación de puntos de interrupción de hardware en la arquitectura Intel es muy similar a como se implementa en la arquitectura ARM, aunque es un poco más flexible.

En todos los núcleos de procesadores Intel Atom, hay cuatro registros DR que almacenan direcciones, las cuales se comparan con la dirección obtenida que se encuentra en el bus de memoria, antes (a veces después) de una búsqueda en la memoria (memory fetch).

Puede usar los cuatro registros para proporcionar direcciones que desencadenen cualquiera de los siguientes eventos de control de ejecución de depuración:

  • 00 – interrupción en ejecución de instrucción
  • 01 – interrupción en escritura de datos solamente
  • 10 – interrupción “OR” indefinida (si la arquitectura lo permite) en lecturas o escrituras de E/S
  • 11 – interrupción en lecturas o escrituras de datos, pero no en búsqueda de instrucciones (instruction fetch)

Por lo tanto, los cuatro puntos de interrupción de hardware se pueden usar tanto como puntos de interrupción o como watchpoints. Los watchpoints pueden ser de sólo lectura o de sólo escritura (o de E/S).

5.2. Depuración cruzada: procesador Intel® Atom™ y arquitectura ARM

Muchos desarrolladores que toman como procesador de destino el Intel Atom puede que tengan experiencia más que nada en desarrollo para arquitecturas RISC con longitud fija de instrucciones. MIPS y ARM son ejemplos arquetípicos de ISA con longitud fija. En general el modelo de uso de depuración cruzada entre un procesador Intel Atom y un procesador de arquitectura ARM es muy similar. Muchos de los métodos y problemas conceptuales de depuración son los mismos.

Sin embargo, desarrollar en un host basado en la arquitectura Intel para un procesador de destino Intel Atom ofrece muchas ventajas, en especial cuando el sistema operativo incrustado que se elige se deriva de alguno de los sistemas operativos estándares comunes, como Linux o Windows. La primera ventaja es el rico ecosistema de herramientas de rendimiento, análisis de consumo de energía y depuración disponibles para el mercado de desarrollo de software para la arquitectura Intel, que es un mercado más amplio. La segunda ventaja es que la depuración de la corrección funcional y el comportamiento multithreading de la aplicación se puede hacer localmente. Esta ventaja se analizará más adelante es este mismo capítulo.

Hay varias diferencias entre los procesadores Intel Atom y los procesadores ARM que los desarrolladores deben conocer. En las siguientes dos apartados se presentará un resumen de estas diferencias.

5.3. Instrucciones de longitud variable

Los conjuntos de instrucciones de IA-32 e Intel 64 tienen longitud variable de las instrucciones. La repercusión de esto en el depurador es que no puede simplemente inspeccionar el código a intervalos fijos de 32 bits, sino que debe interpretar y desensamblar las instrucciones de máquina de la aplicación sobre la base del contexto de estas instrucciones; la ubicación de la instrucción siguiente depende de la ubicación, el tamaño y la correcta decodificación de la anterior. En contraste, en la arquitectura ARM lo único que necesita monitorizar el depurador es la secuencia de código que cambia del modo ARM al modo Thumb o al modo Thumb mejorado, y en el sentido inverso. Una vez que se está en un modo específico, todas las instrucciones y direcciones de memoria tienen un tamaño de 32 o 16 bits. Los desarrolladores de firmware y los desarrolladores de controladores de dispositivos que necesitan alinear con precisión llamadas a registros específicos de dispositivos y quieren depender de la comprensión de la impresión de salida de la ventana de memoria del depurador deben entender el impacto que pueden llegar a tener las instrucciones de longitud variable.

5.4. Interrupciones de hardware

Otra diferencia de arquitectura que puede ser relevante cuando se depura código de sistema es cómo se manejan las interrupciones de hardware. En la arquitectura ARM, los vectores de excepción

  • 0 Restablecer
  • 1 Anular
  • 2 Anular datos
  • 3 Anular captura previa
  • 4 Instrucción sin definir
  • 5 Interrupción (IRQ)
  • 6 Interrupción rápida (FIRQ)

se mapean de la dirección 0x0 a la dirección 0x20. Esta área de memoria está protegida y normalmente no se la puede remapear. Lo común es que todas las ubicaciones de los vectores de 0x0 a 0x20 contengan saltos a la dirección de memoria donde reside el código real del controlador de excepciones. Para el vector de restablecimiento, eso implica que en 0x0 habrá un salto a la ubicación del código de inicio de la plataforma o el firmware. Este enfoque hace menos flexible la implementación de interrupciones de hardware y controladores de señal de sistema operativo en la arquitectura ARM, pero la estandariza más. Es fácil capturar una interrupción en el depurador simplemente mediante el establecimiento de un punto de interrupción de hardware en la ubicación del vector en el rango de direcciones de 0x0 a 0x20.

En la arquitectura Intel, se emplea un controlador de interrupción de hardware dedicado. No se puede acceder a las interrupciones

  • 0 Temporizador de sistema
  • 1 Teclado
  • 2 Segundo controlador de interrupciones en cascada
  • 3 COM2 – interfaz serie
  • 4 COM1 – interfaz serie
  • 5 LPT – interfaz paralela
  • 6 Controlador de disco flexible
  • 7 Disponible
  • 8 Reloj en tiempo real CMOS
  • 9 Tarjeta de sonido
  • 10 Adaptador de red
  • 11 Disponible
  • 12 Disponible
  • 13 Procesador numérico
  • 14 IDE – Interfaz de disco rígido
  • 15 IDE – Interfaz de disco rígido

directamente por el espacio de direcciones de la memoria del procesador, sino que para controlarlas se accede al controlador de interrupciones Intel 8259. Como se puede ver en la primera lista de interrupciones, el controlador ya permite el control directo de interrupciones de E/S de hardware de dispositivos conectados, las cuales se manejan por medio de interrupción IRQ o interrupción rápida en la plataforma ARM. Esta prestación hace más fácil la implementación de un control de interrupciones apropiado a nivel de sistema operativo en la arquitectura Intel, en especial para E/S de dispositivo. El mapeo de excepciones de software, como anulaciones de datos o errores de segmentación, también es más flexible en la arquitectura Intel y corresponde a un puerto del controlador de interrupciones que es llamado mediante la tabla de descriptores de interrupción (IDT). El mapeo de la IDT a las interrupciones de hardware es definible por medio de la pila de software. Además, la captura de estas excepciones no se puede hacer fácilmente desde la implementación de una depuración que ignore la pila de software. A fin de capturar eventos de software que desencadenen interrupciones de hardware en la arquitectura Intel, es fundamental tener cierto conocimiento de la capa de sistema operativo. Es necesario saber cómo las señales del sistema operativo para estas excepciones mapean al controlador de interrupciones subyacente. Lo más habitual, incluso en depuradores a nivel de sistema, es que a las excepciones las capture una tabla de señales mapeadas a la memoria del sistema operativo, en lugar de intentar capturarlas directamente a nivel de hardware.

5.5. Paso único

La arquitectura ARM no tiene una instrucción explícita de un solo paso. En la arquitectura Intel, es común que se implementen pasos únicos a nivel de ensamblaje directamente en el depurador mediante una instrucción de ese tipo. En ARM, los pasos de instrucción únicos se implementan como comando “ejecutar hasta la interrupción”. El depurador debe inspeccionar el código para garantizar que se cubran todas las rutas de código posibles (en especial si se sale de una instrucción de ramificación o similar). Desde la perspectiva de la implementación del depurador, esto genera un ligero overhead, pero no excesivo, ya que, de todos modos, esta implementación “ejecutar hasta la interrupción” se necesitará con frecuencia para las ejecuciones paso a paso de lenguaje de alto nivel. Los desarrolladores de software en general deberían tener presente esta diferencia, ya que podría conducir a un comportamiento levemente diferente en la ejecución paso a paso.

5.6. Mapeo de memoria virtual

La implementación de traducción de páginas y tablas de descriptores para el mapeo de memoria virtual es sorprendentemente similar, al menos en cuanto al concepto. En la arquitectura Intel, la tabla de descriptores globales (GDT) y la tabla de descriptores locales (LDT) permiten hacer ajustes de dispersión anidados a páginas de memoria que se mapean el espacio de direcciones virtuales. La Figura 30 ilustra la traducción de dirección física a lineal en la arquitectura Intel.


Figura 30. Traducción de páginas en la arquitectura Intel®

En ARM, las tablas de páginas de primer y segundo nivel definen una búsqueda de páginas más directa, y como máximo de uno o dos niveles de profundidad, para la memoria virtual. La Figura 31 muestra un ejemplo de traducción de dirección lineal a física.


Figura 31. Traducción de páginas en ARM

La arquitectura Intel ofrece múltiples niveles de dispersión para las tablas de descriptores, las tablas de páginas, el acceso al espacio de direcciones de 32 bits en modo real y el direccionamiento de 64 bits en modo protegido que depende del modelo base:desplazamiento del selector. ARM no emplea base:desplazamiento en sus diversos modos. En la arquitectura Intel, la búsqueda de tablas de páginas puede ser implícitamente más profunda. En ARM, el conjunto definido es de dos tablas de páginas. En la arquitectura Intel, las tablas de descriptores pueden enmascarar tablas anidadas y, por lo tanto, la verdadera profundidad de las ejecuciones de tablas de páginas puede llegar fácilmente a ser el doble o el triple que en ARM.

El mecanismo de traducción de páginas en la arquitectura Intel ofrece mayor flexibilidad en la distribución de la memoria del sistema y los mecanismos que usa la capa de sistema operativo para asignar fragmentos de memoria específicos como bloques protegidos para la ejecución de aplicaciones. Sin embargo, es cierto que le dificulta al desarrollador contar con un resumen completo de la virtualización de memoria para de ese modo evitar pérdidas de memoria e infracciones de acceso a la memoria (errores de segmentación). En sistemas operativos con todas las prestaciones y mucha memoria, este no es un problema importante. Los sistemas operativos en tiempo real con más visibilidad hacia el manejo de la memoria pueden estar más expuestos a esta dificultad.

6 Consideraciones respecto de la tecnología Intel® Hyper-Threading

Desde la perspectiva de la depuración, prácticamente no hay diferencia entre un núcleo de procesador físico y un núcleo lógico que haya sido habilitado mediante la tecnología Intel Hyper-Threading. El hyper-threading se habilita como parte del proceso de inicialización de la plataforma en el BIOS. Por lo tanto, no hay una diferencia perceptible, desde la perspectiva de la aplicación, entre un núcleo de procesador físico verdadero y un núcleo de procesador lógico adicional. Como esta tecnología posibilita la ejecución simultánea de múltiples hilos, las dificultades de depuración son similares a las que presenta la depuración multinúcleo real.

7 SoC e interacción de multinúcleo heterogéneo

Que haya docenas de componentes de software y hardware interactuando en SoC incrementan el tiempo que lleva determinar problemas de origen durante la depuración. Las interacciones entre los diferentes componentes de software son con frecuencia sensibles al tiempo. Cuando se intenta depurar una base de código con muchas interacciones entre componentes, la ejecución paso a paso en un componente específico no suele ser una opción viable. La depuración printf tradicional tampoco es eficaz en este contexto porque los cambios de depuración pueden afectar de manera negativa el comportamiento respecto del tiempo y causar problemas aún peores (lo que se conoce como “Heisenbugs”).

7.1. Depuración por rastreo de eventos

Hay una amplia variedad de tecnologías de rastreo de eventos de datos basadas en la instrumentación de software estático que ayudan a resolver este problema. El principio común es que utilizan una pequeña cantidad de memoria de búfer DRAM para capturar datos de eventos mientras se crean y luego usa un mecanismo de registro para escribir el resultado del rastreo en un archivo de registro. La monitorización del rastreo de datos puede ser en tiempo real mediante la interconexión directa con la API de registro de rastreo, o se puede hacer fuera de línea por medio del uso de una gran variedad de visualizadores para analizar interacciones más complejas de componentes de la pila de software.

Tres de las implementaciones de ese tipo más comunes son LTTng*, Ftrace* y SVEN*.

A continuación se incluye una tabla comparativa de estas implementaciones en la que se priorizan los sistemas operativos tipo Linux*, y por lo tanto se puede aplicar también a Android*.


Figura 31. Diferentes soluciones de rastreo de eventos de datos

Encontrará más información en los sitios web respectivos de cada producto:

7. Resumen

En este artículo vimos los detalles de configuración y evaluación de las herramientas de depuración y los controladores necesarios. Además, pusimos de relieve algunas diferencias de arquitectura que pueden influir en la depuración, pero por lo general sólo en el caso de los desarrolladores interesados en trabajar muy cerca de la capa de sistema.

Como hemos visto en la descripción general de soluciones de depuración disponibles y configuraciones de depuración para Android en sistemas basados en la arquitectura Intel, existe todo un conjunto de entornos de depuración que cubren las necesidades del desarrollador de aplicaciones Java, del de código C/C++ nativo y del de pila de software del sistema.

La depuración en la arquitectura Intel es compatible con el SDK de Android estándar y los conjuntos de herramientas del NDK de Android ofrecidas por Google. Además el ecosistema de Intel, al igual que otros, proporciona soluciones de depuración que amplían estas herramientas disponibles y ofrece soluciones para depuración de pilas de software de sistema y de rendimiento de gráficos.

Si está familiarizado con la depuración y el desarrollo para Android en la arquitectura ARM, los mismos métodos de depuración sirven para la arquitectura Intel. La infraestructura disponible de herramientas de depuración y desarrollo está basada en el SDK de Android* SDK y se extiende mediante soluciones de Intel y de colaboradores de ecosistema que a menudo también resultan familiares de ARM*. Por lo tanto, no debería haber muchas sorpresas al depurar software en dispositivos Android basados en procesadores Intel® Atom™ en lugar de depurar en dispositivos basados en ARM*.

8. Referencias

Pour de plus amples informations sur les optimisations de compilation, consultez notre Avertissement concernant les optimisations.