36
1

Índice general - RUA: Principal · 2016. 4. 28. · El emulador se divide en tres grandes bloques: Frontend, comprobación y configuración del hardware y arranque e inicialización

  • Upload
    others

  • View
    0

  • Download
    0

Embed Size (px)

Citation preview

Page 1: Índice general - RUA: Principal · 2016. 4. 28. · El emulador se divide en tres grandes bloques: Frontend, comprobación y configuración del hardware y arranque e inicialización

1

Page 2: Índice general - RUA: Principal · 2016. 4. 28. · El emulador se divide en tres grandes bloques: Frontend, comprobación y configuración del hardware y arranque e inicialización

2

Índice general

1 INTRODUCCIÓN

1.1 Motivación

1.2 Explicación del proyecto

1.3 Objetivos

2 CONTEXTUALIZACIÓN

2.1 Tecnologías disponibles

2.2 Aplicaciones similares

3 ANÁLISIS Y DISEÑO

3.1 El antes y el después en el emulador de Android: QEMU

3.2 Estructura del emulador de Android

3.3 Especificación de requisitos

3.4 Puesta en marcha: El entorno

3.5 Cómo compilar

3.6 AVD

4. EJECUTANDO EL EMULADOR

4.1 HAXM

4.1.1 Requisitos

4.2 Parámetros del emulador

Page 3: Índice general - RUA: Principal · 2016. 4. 28. · El emulador se divide en tres grandes bloques: Frontend, comprobación y configuración del hardware y arranque e inicialización

3

5 IMPLEMENTACIÓN

5.1 Modificaciones

5.2 Estructura de las modificaciones

5.3 Lista de propiedades del hardware virtual

6 LINEAS FUTURAS

7 CONCLUSIONES

8 AGRADECIMIENTOS

9 BIBLIOGRAFÍA

Page 4: Índice general - RUA: Principal · 2016. 4. 28. · El emulador se divide en tres grandes bloques: Frontend, comprobación y configuración del hardware y arranque e inicialización

4

Índice de Figuras

Figura 1: Arranque de métodos del emulador 10

Figura 2: Muestra del fichero que define el hardware soportado por defecto 12

Figura 3: Lista de opciones del fichero config.ini 13

Figura 4: Comunicación entre las distintas partes de QEMU 18

Figura 5: Conociendo el puerto RIL 23

Figura 6: Solicitud del operador de red por parte de la capa RIL 24

Figura 7: Opciones del comando radiooptions de la capa RIL 25

Page 5: Índice general - RUA: Principal · 2016. 4. 28. · El emulador se divide en tres grandes bloques: Frontend, comprobación y configuración del hardware y arranque e inicialización

5

1 Introducción

1.1 Motivación

El proyecto surge de la necesidad de validar mediante la realización de pruebas la

calidad de las mediciones y de los productos realizados en Swiss Mobility Solutions,

una compañía de Gemalto.

Estos productos se basan en recoger información, bien sea en segundo plano de

forma pasiva o mediante pruebas activas, permitiendo determinar el QoE y QoS, esto

es, la Calidad de Experiencia y Calidad de Servicio respectivamente.

Para realizar los test de calidad surgieron dos alternativas: Una era portar el código

actual a java puro dejando ciertas partes acopladas al Api de Android como es lógico;

la otra en probar en un dispositivo real la aplicación, como si de una gran caja negra

se tratase. Sabemos lo que entra y el resultado que debería de arrojar. Finalmente se

optó por esta vía dado que independientemente de estas pruebas de calidad, muchas

otras se apoyarían en dispositivos reales para, por ejemplo, testear las interfaces.

Teniendo en cuenta el ámbito del proyecto no hay nada en el mercado que realice

estas funciones y además los parámetros que Google ofrece para modificar su

emulador son a todas luces insuficientes así como la creciente necesidad de testeo

nace este proyecto con la ilusión de modificar el emulador de Android para permitir

introducir los valores necesarios para comprobar el funcionamiento de las

aplicaciones que se desarrollan en la empresa.

Por todo esto me entusiasmó la idea de tener la oportunidad de crear este proyecto,

aprendiendo Android desde lo más profundo y desarrollando una herramienta que

diera un nuevo rumbo al emulador.

Page 6: Índice general - RUA: Principal · 2016. 4. 28. · El emulador se divide en tres grandes bloques: Frontend, comprobación y configuración del hardware y arranque e inicialización

6

1.2 Explicación del proyecto

La idea principal consiste en permitir que ciertos valores que son asignados de forma

fija en el código del emulador puedan ser modificados externamente y con el

emulador funcionando mediante la introducción parámetros.

De esta forma, podemos tener la aplicación funcionando en el emulador, e ir

modificando los parámetros de entrada para comprobar el comportamiento de la

aplicación emulando así condiciones reales que difícilmente podrían ser probadas,

como por ejemplo, una captura de un valor invalido para el MCC/MNC del operador

debido a malfuncionamientos de la red.

1.3 Objetivos

Con lo dicho anteriormente los objetivos del proyecto son los siguientes:

• Conseguir modificar el valor de ciertos parámetros del emulador relativos a la clase

Telephony.

• Aprender el funcionamiento y arquitectura del emulador de Android

• Testear aplicaciones mediante test de caja negra haciendo uso del emulador

• Ampliar el parque de pruebas disponibles para las aplicaciones mediante test antes

difíciles o imposibles de realizar por requerir condiciones físicas extremas de la red.

Page 7: Índice general - RUA: Principal · 2016. 4. 28. · El emulador se divide en tres grandes bloques: Frontend, comprobación y configuración del hardware y arranque e inicialización

7

2 CONTEXTUALIZACIÓN

Existen actualmente dentro del mercado móvil muchos dispositivos para poder elegir

el que mejor se ajuste a las exigencias y necesidades de cada usuario. Pero hay un

líder indiscutible desde hace unos años, el sistema operativo Android. A lo largo de

los años hemos podido ver cómo el mercado evolucionaba y ampliaba encontrando

actualmente al sistema operativo Android en casi cualquier dispositivo y con

características muy diferentes entre sí: desde tablets y smartphones hasta relojes,

televisiones y coches.

Debido a esto y a pesar de ser una necesidad obvia cada vez es más imperativo

asegurar que nuestras aplicaciones funcionan de la manera que esperamos que

funcionen por lo tanto una herramienta como la que se va a desarrollar en este

proyecto es esencial puesto que ofrece un medio seguro, controlado y muy próximo

a la realidad en el que testear las aplicaciones.

2.1 Tecnologías disponibles

En el ámbito actual no se encuentra disponible ninguna aplicación de características

similares ni si quiera de manera profesional. Podemos sin embargo buscar ciertas

referencias a funcionamientos parecidos en otros programas como pueden ser

VMWare.

Dicho programa permite crear máquinas virtuales y configurar las características de

estas para posteriormente ejecutarlas en una maquina anfitriona. Este es el

comportamiento que sigue el emulador de Android que además hace uso de QEMU,

un emulador Open Source escrito en C que ha servido como base para multitud de

proyectos.

En nuestro caso el emulador de Android tan solo permite la ejecución de máquinas

con el sistema operativo Android pero permitiendo de igual manera que VMWare la

configuración de estas máquinas para emular de forma más fideligna el

comportamiento de los dispositivos reales. Tales configuraciones van desde la

cantidad de memoria RAM, hasta el tamaño y densidad de pantalla, espacio en disco,

emulación de la GPU, etc.

Page 8: Índice general - RUA: Principal · 2016. 4. 28. · El emulador se divide en tres grandes bloques: Frontend, comprobación y configuración del hardware y arranque e inicialización

8

2.2 Aplicaciones similares

Actualmente no hay ninguna aplicación que realice los dichos cambios en el

emulador. Sin embargo hay aplicaciones que interactúan con el emulador ampliando

con dispositivos físicos la entrada de éste, permitiendo así simular ciertos

comportamientos de una manera más próxima a la realidad. En este caso se trata de

una aplicación que parchea el código fuente del emulador para permitir que éste lea

tarjetas SIM reales a través de un dispositivo físico destinado a tal uso.

3 ANALISIS Y DISEÑO

El sino de este apartado es el de exponer el estudio previo realizado para la

comprensión, diseño e implementación de las modificaciones que queremos sobre el

emulador de Android. Así como vislumbrar los cambios futuros que se sucederán

sobre el emulador y el porqué de la disrupción en código que ha sufrido y que ha

cambiado drásticamente la manera de trabajar con éste.

3.1 El antes y el después en el emulador de Android con QEMU

Como se ha mencionado anteriormente el emulador de Android está basado en el

emulador Open Source QEMU, tras unas drásticas modificaciones sobre éste se

consiguió emular las capas necesarias para hacer correr el sistema operativo.

Históricamente y con pocos dispositivos en el mercado el emulador era lo más

parecido a un dispositivo real, funcionaba prácticamente igual y permitía una

herramienta para probar las aplicaciones de manera que los desarrolladores podían

comprobar si sus aplicaciones funcionaban correctamente en los dispositivos antes

de salir al mercado.

La forma de trabajar con el emulador, desde el punto de vista del desarrollador,

pasaba por descargar todo el árbol de fuentes del repositorio AOSP de Google y

usando una maquina Linux/Mac compilar todo el sistema operativo pues el emulador,

era una parte integrada en éste.

Posteriormente Google se dio cuenta de que el emulador se estaba convirtiendo en

una aplicación monolítica difícilmente mantenible y usable puesto que cada vez había

más dispositivos que emular con unas especificaciones muy diversas.

Cabe destacar que la herramienta, emula físicamente los dispositivos.

Page 9: Índice general - RUA: Principal · 2016. 4. 28. · El emulador se divide en tres grandes bloques: Frontend, comprobación y configuración del hardware y arranque e inicialización

9

Por esta razón se decidió crear una pequeña rama aparte donde las herramientas

fuesen utilizadas por su IDE principal, Android Studio, y en la que Google aprovecho

para romper con el diseño antiguo de su emulador para intentar paliar los problemas

mencionados.

Actualmente el emulador sigue siendo una pieza monolítica clave en las

herramientas de Google.

Page 10: Índice general - RUA: Principal · 2016. 4. 28. · El emulador se divide en tres grandes bloques: Frontend, comprobación y configuración del hardware y arranque e inicialización

10

3.2 Estructura del emulador de Android

El emulador se divide en tres grandes bloques: Frontend, comprobación y

configuración del hardware y arranque e inicialización del hardware y Kernel.

1. Frontend

En esta parte el emulador se encarga de parsear y

verificar los parámetros de entrada así como dar a

QEMU una lista limpia de parámetros para

comenzar la emulación.

Como mencionábamos anteriormente, hay un gran

chequeo de parámetros debido a los diferentes

entornos que ofrecen los dispositivos y las

necesidades de que el emulador sea compatible.

Algunas de las principales funcionalidades son las

siguientes:

Ejecución de main.c: Comienza la ejecución

parseando los parámetros mediante

Android_parse_options en una estructura que

contiene punteros listas de parámetros. Muchas de

estas opciones están definidas en cmdline-

options.h

Posteriormente se sanean estas opciones

mediante main-common.c/sanitizeOptions que

maneja todas las combinaciones de parametros

disponibles.

Tras esto se llama a main-common.c/createAVD y

se gestiona las máquinas virtuales. Estas

máquinas virtuales pueden funcionar en base a

dos casos diferentes:

Figura 1: Arranque de métodos del emulador

Page 11: Índice general - RUA: Principal · 2016. 4. 28. · El emulador se divide en tres grandes bloques: Frontend, comprobación y configuración del hardware y arranque e inicialización

11

1. El emulador es ejecutado bajo el contexto del Android Build System, esto ocurre

en las compilaciones para ramas antiguas, cuando el emulador estaba integrado

con el sistema operativo. Aquí se obtienen configuraciones como la arquitectura

elegida, directorio de salida, directorio de compilación, etc.

2. El emulador es ejecutado en modo standalone, este es el caso de la nueva rama.

En esta ejecución el emulador es encarga de comprobar los archivos requeridos,

nombre del dispositivo a emular, path hacia el sdk necesario, etc.

2. Configuración Hardware

Este será uno de los puntos de entrada para la modificación de las variables

internas del emulador. Se trata de una variable global llamada Android_hw,

internamente es del tipo AndroidHwConfig y es una estructura que está definida

bajo Android/avd/hw-config.h y sus definiciones en hw-config-defs.h. Viendo estos

ficheros podemos hacernos una idea de las características de hardware

soportadas. Aquí incluiremos nuestras variables de forma que el emulador las

considere como parte del hardware soportado.

Dentro de esta configuración también se suceden los siguientes eventos que

resultan de crucial importancia para el arranque de QEMU:

- Arranque del reloj: se usan 3 relojes en qemu-timer.c uno de tiempo real, otro

para el reloj virtual y otro reloj para el host.

- Chequeo de opciones de QEMU: se contrastan todas las opciones filtradas

anteriormente con las opciones en qemu-options.h además se realiza el

parseo de la configuración hardware dada en Android-hw y se inicializan los

sistemas de imágenes tales como system.img, data.img, sdcard.img, etc.

Page 12: Índice general - RUA: Principal · 2016. 4. 28. · El emulador se divide en tres grandes bloques: Frontend, comprobación y configuración del hardware y arranque e inicialización

12

- Entre el resto de opciones parseadas se encuentran el arranque del modem

GSM y GPS, la velocidad de red y su latencia, densidad de pantalla, etc. Para

la configuración del modem incidiré en el fichero modem.c así como en la

configuración de la tarjeta SIM mediante el fichero sim.c

Figura 2. Muestra del fichero que define el hardware soportado por defecto

Page 13: Índice general - RUA: Principal · 2016. 4. 28. · El emulador se divide en tres grandes bloques: Frontend, comprobación y configuración del hardware y arranque e inicialización

13

3. Inicialización del hardware y del Kernel

Se comienza con el arranque de los puertos ttyS0, destinado al Kernel, el ttyS1,

destinado a QEMU y los bucles principales del emulador. El bucle principal y sobre

el que habrá que incidir posteriormente está en las funciones

qemu_init_main_loop() y qemu_event_init() además en este proceso se inicializan

los dispositivos. Respecto al Kernel se trata de una CPU virtual llamada Goldfish

que ejecuta instrucciones ARM926T y que se encarga de la entrada/salida, por

ejemplo para la entrada de teclado y salida de video, que se muestra en el

emulador.

Figura 3. Comunicación entre las distintas partes de QEMU

Page 14: Índice general - RUA: Principal · 2016. 4. 28. · El emulador se divide en tres grandes bloques: Frontend, comprobación y configuración del hardware y arranque e inicialización

14

3.3 Especificación de requisitos

Aunque hay una obvia diferenciación entre los procesos de compilación según elijamos

compilar la antigua rama o la nueva, los requisitos mínimos necesarios se basan

principalmente en el espacio en disco disponible y la cantidad de RAM. Las plataformas

disponibles para realizar la compilación son Linux y Mac OS y se necesita al menos 16Gb

de RAM y un mínimo de 100Gb para compilar el código fuente. Además, si se realizan

múltiples compilaciones se recomienda unos 200Gb adicionales y entre 50-100Gb más

si usamos CCache, lo cual es harto recomendado. Como herramientas para la

compilación es obligatorio tener Python 2.6-2.7, GMake 3.82, Git y Java 7.

En lo personal recomendaría como mínimo un i7 con 16Gb de RAM combinados con

CCache, que es un compilador de caché para C/C++, una herramienta que aunque no

en la primera compilación, si en las posteriores, puede reducir los tiempos hasta dejarlo

en una hora o incluso 15minutos dependiendo de los cambios que hagamos en el código

fuente. También es recomendable usar un disco SSD.

3.4 Puesta en marcha: El entorno

Para compilar debemos seguir los siguientes pasos dependiendo de la plataforma en la

que estemos y teniendo en cuenta que estamos en la rama antigua:

1. Linux (Debian)

1. $ sudo apt-get install openjdk-7-jdk

2. $ sudo update-alternatives --config javac

3. $ sudo apt-get install bison g++-multilib git gperf libxml2-utils make python-network

zlib1g-dev:i386 zip

1. Mac

Se necesita tener el Sistema operativo instalado con la opción case-

sensitive habilitada o en su defecto crear una partición donde descargar el

código AOSP

Con el siguiente código se creará y montará una partición de 60Gb.

Además se hará uso de Brew para la instalación de paquetes externos. Por

último se aumentará el número de file descriptors simultáneos que puede

abrir el sistema operativo.

Page 15: Índice general - RUA: Principal · 2016. 4. 28. · El emulador se divide en tres grandes bloques: Frontend, comprobación y configuración del hardware y arranque e inicialización

15

1. # hdiutil create -type SPARSE -fs 'Case-sensitive Journaled HFS+'

-size 60g ~/android.dmg

2. # function mountAndroid { hdiutil attach ~/android.dmg -mountpoint /Volumes/android; }

3. # brew install gmake libsdl git gnupg

4. # ulimit –S –n 1024

Tanto si utilizamos la versión antigua como la nueva, es recomendable el

uso de la herramienta de compilación CCache. Para usarla, edita .bashrc:

1. $ export USE_CCACHE = 1

3.5 Cómo compilar

Una vez descargado el código fuente y teniendo en cuenta que estamos compilando bajo

el método antiguo debemos usar los siguientes pasos para compilar. Empezamos por

acceder al directorio donde están las fuentes y posteriormente ejecutamos:

1. $ source build/envsetup.sh 2. lunch 3. Seleccionamos la combinación deseada 4. make –j4

Destacar los siguientes sufijos a la hora de seleccionar la

plataforma/dispositivo:

1. user – Acceso limitado, versión de producción 2. userdebug – Como la anterior pero con acceso root 3. eng – Versión de desarrollo con herramientas para debug

A pesar de todo lo habitual será que compilemos la nueva rama para

disponer de las últimas versiones. Esta rama facilita y reduce enormemente

los tiempos de compilación. Dejándolos en alrededor de minuto y medio

Page 16: Índice general - RUA: Principal · 2016. 4. 28. · El emulador se divide en tres grandes bloques: Frontend, comprobación y configuración del hardware y arranque e inicialización

16

con el equipo anteriormente mencionado. Cabe destacar que deberemos

descargar dos proyectos, a saber: qemu y qemu-android.

En el proyecto qemu esta una versión antigua y fuertemente parcheada

para hacer funcionar el emulador de Android mientras que en qemu-android

están las nuevas características de QEMU 2.0+ así como las

refactorizaciones y mejoras que se van portando del proyecto antiguo.

Actualmente el proyecto qemu tiene dependencias con qemu-android.

Tanto qemu como qemu-android deben colgar del directorio external del

árbol de AOSP. Una vez hayamos clonado ambos repositorios podremos

empezar a compilar.

Como nota añadida y aunque se hablará posteriormente, si queremos

modificar la capa RIL deberemos clonarla también bajo external.

1. $ cd qemu 2. $ ./android-rebuild.sh –build-qemu-android –debug

De esta forma, compilaremos ambos proyectos desde un único comando.

Otra forma sería compilar cada proyecto por separado. Hay que tener en

cuenta que si solo vamos a modificar el antiguo QEMU solo necesitamos

compilar qemu-android la primera vez, lo cual como es lógico supone una

reducción de tiempo.

Si necesitamos compilar los proyectos por separado estos son los

comandos:

1. $ cd qemu-android 2. $ ./android/scripts/build-qemu-android.sh 3. $ cd qemu 4. $ ./android-rebuild.sh -debug

Una vez hayamos compilado los ejecutables del emulador son generados bajo

la carpeta qemu/objs/

Page 17: Índice general - RUA: Principal · 2016. 4. 28. · El emulador se divide en tres grandes bloques: Frontend, comprobación y configuración del hardware y arranque e inicialización

17

3.6 AVD (Android Virtual Device)

Las AVD son las máquinas virtuales que podemos y debemos crear y

configurar para emular los distintos dispositivos. Por ejemplo, podemos crear

una máquina virtual que emule un Nexus 5 o una tablet Samsung. Por defecto

disponemos de varios modelos por defecto, prácticamente en su totalidad de

Google salvo algunos modelos de Samsung. Por supuesto tenemos un gran

abanico de opciones para ajustarnos de la mejor forma posible a los

dispositivos que no estén en la lista por defecto. Para lanzar el emulador es

requisito indispensable utilizar una avd. He aquí los pasos a seguir para crear

una.

Lo primero que debemos hacer es obtener la lista de sistemas disponibles

instalados. De no tener ninguno, deberemos descargar el sdk correspondiente

a la versión deseada.

1. $ android list targets

Seguidamente lanzamos el siguiente comando, habiendo considerado

previamente el id deseado del listado de plataformas arrojado por el

comando anterior.

2. $ android create –n <name> -t <targetID> [-<option> <value>]

Si queremos que la máquina virtual sea compatible con HAXM deberemos

asegurarnos de que la CPU/ABI esté establecida en x86.

Page 18: Índice general - RUA: Principal · 2016. 4. 28. · El emulador se divide en tres grandes bloques: Frontend, comprobación y configuración del hardware y arranque e inicialización

18

El resto de opciones podemos ajustarlas cómodamente desde el fichero de

configuración de la máquina virtual. Para acceder a dicha configuración tan

solo tenemos que ir a la carpeta .android en los sistemas Mac/Linux. Dentro,

observaremos un listado de carpetas con el nombre de nuestras máquinas

virtuales creadas, dentro de cada una de estas carpetas hay un config.ini en el

que podremos asignar sus propiedades mediante la pareja clave=valor.

Recomiendo al menos las siguientes opciones:

Figura 4: Lista de opciones del fichero config.ini

Page 19: Índice general - RUA: Principal · 2016. 4. 28. · El emulador se divide en tres grandes bloques: Frontend, comprobación y configuración del hardware y arranque e inicialización

19

En caso de querer eliminar una máquina virtual podremos hacerlo de la

siguiente manera:

1. $ android delete avd -n <name>

Una vez creada y configurada la máquina virtual solo queda lanzarla.

4. EJECUTANDO EL EMULADOR

Si estamos con la rama con la rama antigua debemos tener en cuenta que los

ejecutables son añadidos al path automáticamente pero este es temporal. Una vez

cerremos la terminal el path se borrará y no podremos acceder a los ejecutables teniendo

que volver a compilar de nuevo. Aunque se pueden derivar a otra carpeta para

mantenerlos a salvo, las referencias que utilizan los ejecutables se perderán con lo que

no arreglaremos nada. Con la nueva rama este problema fue resuelto y los ejecutables

permanecen en el directorio aunque no son añadidos al path.

4.1 HAXM

Como se ha explicado, el emulador de Android emula un teléfono completo, con su

CPU, GPU, memoria, etc. Esto unido a las pocas mejoras dedicadas da como resultado

una lentitud considerable. Debido a las quejas recurrentes sobre este problema, Intel

decidió lanzar una herramienta que acelerase los tiempos de ejecución y en general de

respuesta del emulador. De esta forma nació HAXM.

HAXM es un driver/módulo de kernel/extensión de kernel según el sistema operativo de

turno, que concede a QEMU acceso directo al hardware en el que se ejecuta.

Page 20: Índice general - RUA: Principal · 2016. 4. 28. · El emulador se divide en tres grandes bloques: Frontend, comprobación y configuración del hardware y arranque e inicialización

20

4.1.1 Requisitos

HAXM son las siglas de Hardware Accelerated Execution Manager, una tecnología de

Intel que permite acelerar de forma notable la ejecución del emulador. Solo funciona en

combinación con las imágenes x86 del procesador Intel Atom. Teniendo esto en cuenta

los únicos requisitos son disponer de un hardware que soporte Virtualization Technology,

es decir, debe ser compatible con Intel VT-x y EM64T. Para Linux en lugar de HAXM

debe utilizarse KVM.

Puede ser necesario tener que habilitar la funcionalidad Virtualization Technology y

Execute Disable Bit en la BIOS.

Además es recomendable tener al menos 1GB de RAM.

4.1.2 Instalación

Para cualquiera dos de las tres plataformas Mac/Windows debemos abrir el Android

SDK Manager y bajo la carpeta Extras buscar: Intel x86 Emulator Acclerator (HAXM).

Tanto en Windows como en Mac deberemos buscar el ejecutable intelHAXM dmg o .exe

según proceda y seguir la instalación. Se trata de un proceso sencillo y muy guiado. Lo

único que debemos tener en cuenta es el valor de la cantidad de RAM que vamos a dejar

disponible para HAXM. Se aconseja como mínimo 1GB.

Para Linux el proceso es un poco diferente pero igualmente sencillo. Primero

instalaremos los paquetes necesarios para KVM:

Distribuciones basadas en Debian:

1. # apt-get install qemu-kvm libvirt-bin ubuntu-vm-builder bridge-

utils

Posteriormente solo hay que añadir el usuario al grupo KVM y libvirtd:

1. # adduser usuario kvm 2. # adduser usuario libvirtd

Page 21: Índice general - RUA: Principal · 2016. 4. 28. · El emulador se divide en tres grandes bloques: Frontend, comprobación y configuración del hardware y arranque e inicialización

21

Para comprobar el funcionamiento:

1. # virsh -c qemu:///system list

Según los datos de performance de Intel las mejoras observables con Intel HAXM

o KVM son de aproximadamente entre 5x y 10x.

4.2 Parámetros del emulador

Con el fin de acelerar la ejecución y rendimiento del emulador todavía más disponemos

de las siguientes opciones al lanzar el comando:

- -gpu-on: Activa la GPU de la maquina anfitriona permitiendo al

emulador hacer uso de ella. Las mejoras visuales y el arranque

mejoran notablemente.

- -no-boot-anim: Desactiva la animación de arranque de Android. Dado

que nuestros propósitos son puramente de desarrollo esto es un

detalle estético innecesario.

- -no-skin: Aunque puede ser útil dado que algunos skins ofrecen

teclado numérico el no cargar uno se consigue aligerar la carga del

emulador.

Así pues tras las mejoras instaladas, configuraciones y parámetros elegidos, la

ejecución del emulador sería así:

1. $ ./objs/emulator –avd NOMBRE –gpu on –no-boot-anim –no-skin

En la máquina mencionada los tiempos de cargar se han reducido a unos 20

segundos.

Page 22: Índice general - RUA: Principal · 2016. 4. 28. · El emulador se divide en tres grandes bloques: Frontend, comprobación y configuración del hardware y arranque e inicialización

22

5. IMPLEMENTACIÓN

Con lo visto hasta ahora somos capaces de compilar y ejecutar el resultado de nuestra

compilación con unos tiempos mínimos. Así pues vamos a dar paso a la implementación

de los cambios. Los cambios podrían dividirse en cuatro bloques: Escritura de

configuraciones, lectura de configuraciones, lectura de un fichero de estados y respuesta

basada dicho fichero.

5.1 Modificaciones

El primer cambio se basa en la ampliación del fichero de configuración que se crea para

ofrecer todas las configuraciones hardware disponible para las máquinas virtuales.

Teniendo este fichero en cuenta debemos configurar nuestra máquina virtual,

modificando el config.ini mencionado en los puntos anteriores añadiendo las opciones

que consideremos oportunas.

Una vez que el emulador arranca, carga y analiza los parámetros de este fichero. Con

esta primera modificación se abren las puertas a nuevas características del emulador de

Android permitiendo por ejemplo configurar el roaming, el estado de la conexión con el

operador y algunos datos de éste como el MCC/MNC.

Posteriormente disponemos de un fichero de texto donde con valores separados por

comas con un orden en concreto podemos asignar a estas variables, disponibles en el

fichero de configuración, diversos valores para que cambien de forma fluida sin

necesidad de reiniciar el emulador.

En el transcurso de la investigación para poder realizar estas modificaciones al emulador

una de las opciones fue conseguir comunicarse con el modem que el emulador tiene

para mandar comandos AT+ y conseguir así los cambios deseados. Llegados a este

punto hay que saber que el modem de Android filtra los comandos disponibles para no

responder a cualquier cosa que se le envíe. Los comandos disponibles son de lo más

básico, a saber: solicitar operador, cambio de tecnología, colgar llamada, descolgar

llamada, etc.

Así pues, y aunque al final no fue necesario, si se quería enviar comandos

personalizados al emulador, previamente había que diseñar esos comandos, puesto que

el modem simplemente los filtraba, pero ¿quién se comunicaba con el modem para

enviar esos comandos y que éste pudiese filtrarlos? La respuesta es la capa RIL, una

capa intermedia entre aplicaciones y hardware puro que cada fabricante implementa

siguiendo un estándar. Así que de querer modificar o agregar comandos habría que

hacerlo primero en la capa RIL.

Page 23: Índice general - RUA: Principal · 2016. 4. 28. · El emulador se divide en tres grandes bloques: Frontend, comprobación y configuración del hardware y arranque e inicialización

23

Para hacer esto hay clonar el repositorio del directorio de AOSP y hacer que cuelgue del

directorio platform/hardware/ril

Los ficheros que debemos modificar, como mínimo, para la agregación del comando son:

ril_commands.h, ril_commands.cpp y ril.cpp.

Una vez la capa RIL esta modificada y compilada solo resta añadir la librería al emulador

pusheandola al sistema.

Con estos cambios podríamos comunicarnos con el modem del emulador. Para ello

necesitaríamos arrancar el emulador, y desde una terminal abrir una shell:

1. $ adb shell

Una vez dentro solo queda mandar el comando. Pero para ello necesitamos primero el

puerto en el que está escuchando la capa RIL. Para saberlo ejecutamos el siguiente

comando:

1. # getprops rild.libargs

Esto arrojará un resultado como el que sigue:

Figura 5: Conociendo el puerto RIL

Indicándonos el puerto al que debe ser mandado el comando. Para mandar el comando

AT+ deberemos pues realizar lo siguiente:

1. $ echo AT+COMANDO > /dev/PUERTO

Page 24: Índice general - RUA: Principal · 2016. 4. 28. · El emulador se divide en tres grandes bloques: Frontend, comprobación y configuración del hardware y arranque e inicialización

24

Para saber si el modem está recibiendo dichos comandos podemos escuchar el log de

la siguiente manera:

1. $ adb logcat –v time –b radio

Con –v time indicamos que queremos ver la hora en el log y con –b radio filtramos la

radio del modem, sin este último parámetro obtendríamos toda la información que

transcurre por el emulador.

Figura 6: Solicitud del operador de red por parte de la capa RIL

Page 25: Índice general - RUA: Principal · 2016. 4. 28. · El emulador se divide en tres grandes bloques: Frontend, comprobación y configuración del hardware y arranque e inicialización

25

Llegado a este punto hay que mencionar que es posible reiniciar el modem sin reiniciar

el emulador. Aunque no existe un comando AT+ de lo que si disponemos es de la capa

RIL y una implementación de utilidades bajo la herramienta llamada radiooptions, que

permiten lanzar algunas acciones sobre la radio y la sim del emulador. Entre ellas la

posibilidad de hacer un reinicio limpio y rápido de la radio:

1. $ radiooptions 1 1 0

En el ejemplo, dicho comando seleccionad la opción RESET_MODEM para la SIM 1 y la

opción más común a la hora de elegir el estilo del modem-socket.

Figura 7: Opciones del comando radiooptions de la capa RIL

Page 26: Índice general - RUA: Principal · 2016. 4. 28. · El emulador se divide en tres grandes bloques: Frontend, comprobación y configuración del hardware y arranque e inicialización

26

La ventaja del comando radiooptions es que permite reiniciar la radio de forma

continuada. Esto había sido en principio una gran alternativa en caso de que no fuese

factible cargar los valores al emulador por código. Así podrían cargarse a través de

comandos y reiniciar la radio para comenzar otra nueva prueba, cargar otros valores, etc.

Este comando es implementado solo por algunos fabricantes, como por ejemplo

Samsung en sus Samsung Galaxy S5. Sin embargo Google ha decidido no

implementarlo en los Nexus 4.

Finalmente la opción elegida para la carga de valores fue la lectura de un fichero dentro

del modem que describiré a continuación.

5.2 Estructura de las modificaciones

El primer cambio se trata del fichero hardware-config.ini. Dicho fichero una vez

cargado en memoria es una estructura de datos interna a la que se puede acceder

de manera global desde cualquier punto del emulador. Es creada y asignada en los

primeros momentos del arranque del emulador y se mantiene en memoria mientras

éste esté funcionando.

Para que estos valores se hagan efectivos deben estar presentes primero en el

archivo de configuración config.ini de la AVD en cuestión y posteriormente deben ser

leídos y cargados en memoria.

Hay dos grandes cargas dentro de la clase Telephony.

La primera se realiza en el fichero sim.c encargado de emular el comportamiento de

la tarjeta SIM dentro del emulador. En este fichero se leen los campos de la estructura

global de configuración y son asignados los valores a las variables internas previo

checkeo de la lectura de éstas para evitar que sean asignados valores incorrectos.

En todos los casos se asigna un valor por defecto en caso de que el checkeo falle.

Los parámetros modificados dentro de este fichero son:

Número de intentos para introducir el PIN, PIN*, PUK, SIM Serial y SIM status

La siguiente carga se encuentra en android_modem.c

En este fichero se crea, configura y gestiona el comportamiento del modem del

emulador. Inicialmente se crea con la función amodem_create().

Page 27: Índice general - RUA: Principal · 2016. 4. 28. · El emulador se divide en tres grandes bloques: Frontend, comprobación y configuración del hardware y arranque e inicialización

27

La primera modificación en esta función pasa por leer un fichero de texto plano al que

separados por comas y dado un orden concreto, se le pasan ciertos valores que

mencionaré posteriormente junto al funcionamiento del fichero. Además dicha función

llama a una función personalizada amodem_reset( AModem modem) que se encarga

de leer, checkear y asignar los valores de la estructura a las variables internas del

modem.

El funcionamiento del fichero es de la siguiente manera: En la primera línea se

encuentra un comentario que indica las columnas en las que se separa cada línea.

Cada línea representa un estado del modem y puede contener diferentes valores

separados por comas que alteren uno o más parámetros del emulador. Además, la

primera columna siempre representa los instantes de tiempo que se quiere que el

emulador permanezca en ese estado.

Por ejemplo, podemos indicarle con una sola línea que permanezca 5 iteraciones en

el siguiente estado: tecnología 2g con roaming activado. Y en la siguiente línea que

permanezca una sola iteración en 3g sin roaming. Así al terminar las cinco iteraciones

pasará automáticamente a 3g y desactivará el roaming.

Al terminar de leerse el fichero vuelve a comenzar por la primera línea

automáticamente.

La lectura del fichero se realiza una única vez y permanece en memoria solo mientras

el emulador este vivo. Aunque el emulador posee dos funciones para guardar y cargar

estados que reflejen un instante exacto de su comportamiento y por lo tanto pudiera

permitirnos guardar ese estado actual y los valores del fichero ante un posible

shutdown del emulador, estas funciones no están implementadas actualmente por el

emulador de Android.

El siguiente paso necesario es controlar los tiempos en los que se cargan las líneas

del fichero y se hacen efectivas. Para ello he hecho un hook a una de las funciones

del modem que tiene un comportamiento periódico y que se encarga de controlar el

nivel de fuerza de la señal, la función handleSignalStrength.

Dicha función es en realidad un comando AT+ llamado CFQ que se encarga de

solicitar el nivel de señal periódicamente. Así pues cada vez que se realiza una

solicitud desde las capas superiores, en realidad se aprovecha para modificar, si

procede, el estado del emulador.

Para gestionar el tiempo en el que el emulador debe permanecer en un estado

concreto se utilizan dos contadores: uno maneja el número de línea actual y el otro el

número de iteraciones para esa línea. De forma que al saltar de línea el contador de

iteraciones se reinicia.

Page 28: Índice general - RUA: Principal · 2016. 4. 28. · El emulador se divide en tres grandes bloques: Frontend, comprobación y configuración del hardware y arranque e inicialización

28

Dado que la lectura del fichero se realiza por línea entera y se guardan todos los

caracteres incluidas las comas en memoria, cada vez que handleSignalStrength

solicita una nueva línea este debe encargarse de descodificarla, esto es: realizar un

split por comas y comprobar y asignar parámetros a las variables internas que

procedan. Para dicho split y dado que el emulador esta en c se ha utilizado la función

strtok.

Esta función dado un puntero a char devuelve otro puntero a char, lo cual obliga hacer

una comprobación de distinto de null para poder acceder al valor del campo del

fichero y con ello a añadir un valor especial que representa que ese campo está sin

valor. Lo cual nos obliga a que todos los campos estén rellenados y como mínimo

tendrán su valor especial. Es importante saber esto porque dentro de este fichero no

hay una clave-valor como puede ser en un json o un xml. Esta gramática así como

implementar etiquetas para controlar el comportamiento como ETIQUETA LABEL_1

y GOTO LABEL_1 están pensadas como mejoras futuras ayudando así a la

comprensión del fichero y su gestión.

Page 29: Índice general - RUA: Principal · 2016. 4. 28. · El emulador se divide en tres grandes bloques: Frontend, comprobación y configuración del hardware y arranque e inicialización

29

5.3 Lista de propiedades del hardware virtual

La forma de la lista sigue los siguientes campos:

- Name: indica la variable que debe ser añadida al fichero config.ini de

cada máquina virtual si se quiere hacer uso de esta característica.

- Type: no es relevante en el fichero config.ini pero si lo es para el

desarrollo interno.

- Default: solo valido para el desarrollo interno, contiene el valor por

defecto si no se utiliza esta variable en el config.ini

- Abstract y Description: Campos internos para describir la variable. Su

valor es informativo.

Todas estas variables son para ser añadidas en el fichero de configuración, en caso de

querer modificar el fichero interno debe seguirse la guía interna de dicho fichero y separar

los valores y solo los valores por comas. No se debe indicar el parámetro en sí dado que

están ordenados.

1. SIM card serial

name = hw.gsmModem.simSerial

type = string

default = 89014103211118510720

abstract = SIM card serial

description = Serial of the emulated SIM card, maximum 20 digits.

2. GSM IMEI number

name = hw.gsmModem.imei

type = string

default = 000000000000000

abstract = IMEI number

description = IMEI number of the GSM modem, maximum 15 digits.

3. GSM IMSI number

name = hw.gsmModem.imsi

type = string

default = 310260000000000

abstract = IMSI number

description = IMSI number of the GSM modem, maximum 15 digits.

Page 30: Índice general - RUA: Principal · 2016. 4. 28. · El emulador se divide en tres grandes bloques: Frontend, comprobación y configuración del hardware y arranque e inicialización

30

4. Operator Home Name

name = hw.gsmModem.operatorHomeName

type = string

default = Android

abstract = Operator Home Name

description = Operator Home (Network) Name, maximum 40 characters.

5. Operator Home MCC and MNC

name = hw.gsmModem.operatorHomeMccMnc

type = string

default = 310260

abstract = Operator Home MCC + MNC

description = Operator Home (Network) MCC + MNC, maximum 6 digits.

6. Operator Roaming Name

name = hw.gsmModem.operatorRoamingName

type = string

default = Android

abstract = Operator Roaming Name

description = Operator Roaming Name, maximum 40 characters.

7. Operator Roaming MCC and MNC

name = hw.gsmModem.operatorRoamingMccMnc

type = string

default = 310295

abstract = Operator Roaming MCC + MNC

description = Operator Roaming MCC + MNC, maximum 6 digits.

8. Operator Data Network

name = hw.gsmModem.operatorDataNetwork

type = string

default = 3

abstract = Operator Data Network

description = Operator Data Network technology, maximum 1 character.

Page 31: Índice general - RUA: Principal · 2016. 4. 28. · El emulador se divide en tres grandes bloques: Frontend, comprobación y configuración del hardware y arranque e inicialización

31

9. Operator Registration

name = hw.gsmModem.operatorRegistration

type = string

default = 1

abstract = Operator State

description = Operator State Network or Roaming.

10. Operator SIM State

name = hw.gsmModem.simStatus

type = string

default = 2

abstract = SIM Status

description = SIM Status, maximum 1 character.

11. Operator Operator Status Home

name = hw.gsmModem.operatorStatusHome

type = string

default = 1

abstract = Operator Status Home

description = Operator Status Home, maximum 1 character.

12. Operator Operator Status Roaming

name = hw.gsmModem.operatorStatusRoaming

type = string

default = 2

abstract = Operator Status Roaming

description = Operator Status Roaming, maximum 1 character.

13. Operator Operator Index

name = hw.gsmModem.operatorIndex

type = string

default = 0

abstract = Operator Index

description = Operator Index, maximum 1 character.

14. Operator Radio State

name = hw.gsmModem.radioState

type = string

default = 0

abstract = Radio State

description = Radio State, maximum 1 character.

Page 32: Índice general - RUA: Principal · 2016. 4. 28. · El emulador se divide en tres grandes bloques: Frontend, comprobación y configuración del hardware y arranque e inicialización

32

15. Operator RSSI

name = hw.gsmModem.rssi

type = string

default = 7

abstract = RSSI Value

description = RSSI Value, maximum 3 character.

16. Operator BER

name = hw.gsmModem.ber

type = string

default = 99

abstract = BER Value

description = BER Value, maximum 3 character.

17. Operator LAC

name = hw.gsmModem.areaCode

type = string

default = -1

abstract = Area Code

description = Location Area Code, maximum 3 character.

18. Operator Cell ID

name = hw.gsmModem.cellId

type = string

default = -1

abstract = Cell Id

description = Cell Id, maximum 3 character.

19. Operator PIN

name = hw.gsmModem.pin

type = string

default = 0000

abstract = PIN

description = PIN, maximum 4 character.

20. Operator PIN retries

name = hw.gsmModem.pinRetries

type = string

default = 3

abstract = PIN retries

description = PIN retries, maximum 1 character.

Page 33: Índice general - RUA: Principal · 2016. 4. 28. · El emulador se divide en tres grandes bloques: Frontend, comprobación y configuración del hardware y arranque e inicialización

33

21. Operator PUK

name = hw.gsmModem.puk

type = string

default = 12345678

abstract = PUK

description = PUK, maximum 8 character.

Page 34: Índice general - RUA: Principal · 2016. 4. 28. · El emulador se divide en tres grandes bloques: Frontend, comprobación y configuración del hardware y arranque e inicialización

34

6. LINEAS FUTURAS

Siendo una primera versión es obvio que habrá cosas que mejorar, y que muchas de

ellas saldrán del uso de la herramienta que puedan darle los usuarios/desarrolladores.

Creo que la base del desarrollo está bien asentada pero algunas de las mejoras que se

podrían realizar son las siguientes:

- Rehacer el fichero de lectura para que sea más fácil de leer por el usuario. La

idea sería tener una sintaxis de etiquetas y un par de instrucciones que permitiesen

manejar el comportamiento del fichero.

- Añadir parejas clave-valor al fichero como si se tratase de un json

- Mejorar la granularidad del tiempo sobrescribiendo uno de los bucles principales

del emulador para no tener que hacer el hook de la función handleSignalStrength

- Externalizar el fichero de lectura para que pueda ser cargado mediante opciones

al lanzar el emulador. Una segunda mejora sobre esta misma línea sería poder cargar el

fichero mediante telnet contra el emulador.

7. CONCLUSIONES

Como conclusión final he de decir que ha sido toda una experiencia desarrollar sobre

el emulador de Android. Me ha permitido aprender no solo sobre el emulador sino

también conocer un poco más en profundidad el lenguaje C así como el funcionamiento

de los teléfonos a bajo nivel.

Aunque ha habido momentos difíciles por la escasa documentación que hay sobre el

funcionamiento del emulador a la hora de realizar ciertas acciones o de investigar ha sido

un privilegio poder trabajar en este proyecto.

Además de mi experiencia personal considero que los objetivos han sido cumplidos y

queda asentada una buena base para continuar trabajando en ella en el futuro

mejorando el emulador con los cambios aquí propuestos y los que puedan surgir a través

de los casos de uso.

Page 35: Índice general - RUA: Principal · 2016. 4. 28. · El emulador se divide en tres grandes bloques: Frontend, comprobación y configuración del hardware y arranque e inicialización

35

8. AGRADECIMIENTOS

Me gustaría finalizar dando las gracias a todas aquellas personas que me han

ayudado a lo largo de todo el proceso dándome su apoyo e ideas en los momentos en

que no sabía cómo seguir. A mis tutores F.Javier Ferrández Pastor y José Vicente

Noguera por sus ideas sobre RIL y la lectura de ficheros entre otras muchas cosas

Así como a Luis Alberto Vivas Tajuelo por sus opiniones e ideas sobre el proyecto.

9. BIBLIOGRAFÍA

http://developer.android.com/

https://android.googlesource.com

https://wiki.diebin.at/Under_the_hood_of_Android_Emulator

https://software.intel.com/es-es/android/articles/speeding-up-the-android-

emulator-on-intel-architecture

Page 36: Índice general - RUA: Principal · 2016. 4. 28. · El emulador se divide en tres grandes bloques: Frontend, comprobación y configuración del hardware y arranque e inicialización

36