Paper 243 Android
Paper 243 Android
Paper 243 Android
{perezruiza,aldeam,mgh}@unican.es
1 Introducción
Desde que apareció el primer móvil con Android este sistema operativo ha estado en
constante evolución tanto en características como en soporte para distintas clases de
dispositivos. Debido a ello existe un gran interés en utilizar este sistema operativo en
entornos que poseen requerimientos temporales. Existen ventajas cuando utilizamos
Android para propósitos de tiempo real, ya que es un sistema adaptado y optimizado
para utilizar en dispositivos que sean eficientes energéticamente y de recursos limita-
dos, y además es un sistema extendido por un gran número de dispositivos. Lo habi-
tual es que los procesadores modernos usados con dispositivos Android tiendan a
utilizar múltiples núcleos.
Este sistema operativo se desarrolla principalmente bajo licencia Apache 2.0, aun-
que hay determinadas partes que son distribuidas con otros tipos de licencias, por
ejemplo, algunos parches del kernel tienen licencia GPLv2. Este tipo de licencias de
software libre permite a los desarrolladores y a la industria aprovechar las caracterís-
Publicado en las Actas del V Simposio de Sistemas de Tiempo Real, CEDI 2016, Colección
Aquilafuente 223, Ediciones Universidad de Salamanca, págs. 69-80, 2016
ISBN: 978-84-9012-631-8
ticas ofrecidas por Android, aplicar parches desarrollados por terceros y realizar mo-
dificaciones. Además, el kernel de Android está basado en el de Linux. Las últimas
versiones de Android que se ejecutan en los dispositivos más modernos utilizan las
versiones 3.4 o 3.10 del kernel de Linux. Este hecho permite a los desarrolladores
utilizar características avanzadas ofrecidas por Linux.
Android está orientado a la ejecución de aplicaciones desarrolladas en Java, aunque
es posible ejecutar aplicaciones escritas en cualquier lenguaje utilizando un compila-
dor adecuado. Este sistema operativo proporciona un framework que facilita el desa-
rrollo de aplicaciones Java para diferentes dominios. Para alcanzar este objetivo, An-
droid está formado por diferentes capas de componentes software (ver figura 1). La
capa más baja corresponde con el kernel de Linux, el cual proporciona el funciona-
miento básico del sistema, como por ejemplo el manejo de la memoria, los procesos y
los drivers. Encima de la capa compuesta por el kernel, hay otra capa que contiene un
conjunto de librerías nativas que están escritas en C o C++ y son compiladas para una
arquitectura hardware específica. Estas librerías incluyen una modificación de la li-
brería C de gnu glibc llamada bionic. Esta librería está diseñada específicamente para
Android pero como analizaremos más adelante presenta algunos inconvenientes
cuando es utilizada con aplicaciones de tiempo real.
Aplicaciones
Entorno de aplicación
Sistema de vistas Manejador de recursos Manejador de actividades
Kernel de Linux
Drivers Gestión de procesos Gestión de memoria Gestión de energía
2 Trabajos relacionados
Algunos trabajos [3] [4] [5] [6] han analizado la posibilidad de utilizar Android para
ejecutar aplicaciones con requisitos temporales. En ellos se llega a la conclusión de
que en primera instancia la plataforma Android es inapropiada para usarse en entor-
nos de tiempo real, a menos que apliquemos mecanismos o modificaciones al sistema
operativo. Los principales problemas encontrados en estos estudios son los siguientes:
La librería Bionic tiene más restricciones que la libc tradicional y algunas de ellas
dificultan su uso en sistemas de tiempo real.
La variabilidad en los tiempos de respuesta del kernel de Android y de la máquina
virtual Java impiden tener tiempos de respuesta acotados.
El kernel de Linux utiliza por defecto el planificador llamado “completamente
justo” (Completely Fair Scheduler, en inglés). Este planificador proporciona frac-
ciones temporales dinámicas entre las distintas tareas del sistema para intentar ser
lo más justo con todas las tareas que deben ser ejecutadas. Esto es claramente in-
compatible con los requisitos de predictibilidad de una aplicación de tiempo real.
Aplicaciones Aplicaciones
Librerías Librerías
RT
Runtime Aplicaciones Runtime RT-JVM
Linux RT Linux RT
(a) Android parcialmente de tiempo real. (b) Android de tiempo real completo.
Aplicaciones Aplicaciones
Librerías Librerías
Runtime Runtime RT
ART VM extendida Aplicaciones
Linux Kernel
Linux RT Hipervisor RT
(c) Android extendido con tiempo real. (b) Android con hipervisor de tiempo real.
Fig. 2. Soluciones teóricas para la integración de tiempo real en Android [5]. Las partes de
color azul indican cambios en la arquitectura de Android.
Otro trabajo [8] [9] ha realizado una adaptación de Android basándose en la solución
propuesta en la figura 2c. En este caso también han modificado el kernel de An-
droid/Linux con el parche RT_PREEMPT y además han añadido modificaciones en
otros componentes de Android como en el recolector de basuras de la máquina virtual
Java, en la clase Service para permitir el cambio de prioridades a nivel de aplicación
Java y en el módulo Binder para añadir herencia de prioridades en las llamadas remo-
tas a procedimientos dentro de Android.
Existe otro estudio [10] [11] que ha optado por una solución diferente a las cuatro
propuestas en la figura 2. En este caso se crea un prototipo denominado RTDroid que
pretende ser compatible con las aplicaciones escritas para la plataforma Android. Se
utiliza una máquina virtual de Java con características de tiempo real (Fiji-VM) sobre
un sistema operativo de tiempo real (Linux-RT o RTEMS). La API original de An-
droid ha sido recreada paso a paso para poder ejecutar aplicaciones Android. En cierto
modo está solución se basa en la figura 2b, pero en este caso, han construido todo el
sistema desde cero.
En las dos primeras implementaciones citadas anteriormente nos encontramos con
la alta complejidad que reside en la adaptación del kernel de Android/Linux para po-
der aplicar parches de tiempo real sobre él, ya que las últimas versiones del kernel de
Android no están integradas en la rama principal de desarrollo del kernel de Linux. Y
la solución propuesta con RTDroid requiere un fuerte proceso de adaptación con cada
nueva versión del sistema que aparezca. Debido a esto, en un estudio anterior [2]
hemos buscado una solución más portable y fácil de desarrollar y de mantener. En la
siguiente sección vamos a describir brevemente dicha solución.
Android es un sistema operativo que está en constante evolución y por ello en todas
las soluciones citadas en la sección anterior existe una fuerte dependencia con la ver-
sión Android utilizada durante su desarrollo. Además, este sistema operativo es una
plataforma muy fragmentada [12] lo que hace que todas las soluciones que requieran
modificar el kernel o la plataforma en general sean difíciles de mantener y extender a
distintas clases de dispositivos.
En nuestro estudio previo [2] hemos presentado un mecanismo para ejecutar apli-
caciones de tiempo real laxo sobre un dispositivo Android. Para ello las aplicaciones
con requisitos temporales (que estarán desarrolladas en lenguaje C) son ejecutadas
directamente sobre el kernel de Linux en un núcleo aislado de la CPU, sin necesidad
de modificar el código del kernel ni el de la plataforma. Esta solución puede ser usada
en cualquier dispositivo Android con un procesador multinúcleo y kernel de Linux
versión 2.6 o superior. Dichas aplicaciones con requisitos temporales deben ser ejecu-
tadas haciendo uso de las prioridades de tiempo real que ofrece el kernel de Li-
nux/Android (política de planificación SCHED_FIFO).
Las versiones del kernel de Linux superiores a la 2.6, por defecto tienen activada
una opción que hace que la mayor parte de este sea expulsable, por ello en cualquier
momento durante la ejecución de código perteneciente al kernel se puede producir
una expulsión, excepto en los manejadores de interrupciones y regiones protegidas
con spinlocks. Además en estas versiones del kernel también se incluyen políticas de
planificación de tiempo real (SCHED_FIFO y SCHED_RR).
A pesar de todas las características ofrecidas por el kernel de Linux/Android exis-
ten algunos inconvenientes que debemos solventar si queremos tener un grado de
predictibilidad razonable para aplicaciones con requisitos temporales:
Las tres primeras limitaciones se han resuelto en el estudio previo [2] mientras que
en el presente trabajo se resuelve la cuarta limitación relacionada con la librería bio-
nic. A continuación se procede a resumir los pasos realizados en el estudio previo [2]
para alcanzar nuestra solución que evita interferencias de otras aplicaciones de tiempo
real del sistema, elimina interrupciones, fija la frecuencia y evita el apagado de los
núcleos del procesador.
Si nos aprovechamos de las ventajas ofrecidas por los procesadores multinúcleo
podemos aislar un núcleo de la CPU utilizando mecanismos ofrecidos por Li-
nux/Android para así conseguir un entorno para las aplicaciones de tiempo real. Estas
aplicaciones se ejecutarán directamente sobre el kernel de Linux/Android y las libre-
rías nativas ofrecidas por el sistema. En la figura 3 se ilustra la arquitectura llevada a
cabo para nuestra solución aquí descrita.
CPU 1
Aislamiento
CPU 2
CPU 4
CPU 3
Aplicaciones Aplicaciones de tiempo real
Entorno de aplicaciones
Librerías nativas
Linux/Android Kernel
Fig. 3. Solución propuesta en un trabajo previo [2] para ejecutar aplicaciones de tiempo real en
Android.
Linux proporciona algunos mecanismos para aislar CPUs de la actividad general del
planificador del sistema. El más conveniente para nuestro propósito es el denominado
Cpuset. Esta funcionalidad proporcionada por el kernel no viene activada por defecto
en los dispositivos Android, lo que hace que debamos recompilar el kernel. Su objeti-
vo consiste en restringir el número de procesadores y recursos de memoria que un
conjunto de procesos pueda utilizar. Cuando el sistema operativo arranca, todos los
procesos pertenecen a un único cpuset. Si tenemos suficientes privilegios podemos
crear nuevos cpusets y mover procesos de uno a otro. De este modo podemos mover
todos los procesos del sistema a un cpuset y al mismo tiempo se puede crear otro
cpuset donde únicamente se asignen los procesos de tiempo real.
La implementación del mecanismo de los cpuset hace que por definición todos los
nuevos procesos que se creen se asignen al mismo cpuset donde está su proceso pa-
dre, a excepción de los procesos hijos de kthreadd. Este demonio se ejecuta en el
espacio del kernel y es utilizado por el sistema para crear nuevos threads del kernel.
Por consiguiente no podemos garantizar que algunos threads del kernel no se ejecuten
en un núcleo aislado. A pesar de ello en los numerosos experimentos realizados esta
situación apenas se repite y no tiene gran incidencia sobre los tiempos de ejecución.
Con el anterior mecanismo de aislamiento no conseguimos evitar que lleguen inte-
rrupciones a un núcleo aislado, pero a partir de la versión 2.4 del kernel de Linux se
ha incluido la posibilidad de asignar ciertas interrupciones a un núcleo del procesador
(o a un conjunto de núcleos). Esta funcionalidad se denomina SMP IRQ affinitiy y nos
permite controlar qué núcleos manejan las diferentes interrupciones que se producen
en el sistema. Para cada interrupción hay un directorio en el sistema donde existe un
fichero que nos permite establecer la afinidad modificando una máscara. No todas las
interrupciones son enmascarables, por ejemplo las producidas entre los núcleos del
procesador (IPI-interprocessor interrupts, en inglés). Al igual que con los threads del
kernel las numerosas pruebas realizadas muestran que el impacto de estas interrupcio-
nes es escaso.
Para alcanzar mayor grado de predictibilidad en los tiempos de ejecución es nece-
sario fijar la frecuencia de los núcleos destinados a ejecutar aplicaciones con requisi-
tos temporales. Además, algunos dispositivos Android utilizan demonios que apagan
los núcleos de la CPU que no están siendo usados para así poder ahorrar energía. Para
evitar que esto ocurra en el núcleo aislado debemos desactivar dichos demonios.
Aplicando todos los mecanismos descritos anteriormente, en el estudio previo que
hemos realizado [2] se ha determinado que se consiguen mejoras suficientemente
sustanciales en la ejecución de una tarea simple en un núcleo aislado respecto a ejecu-
tar esa misma tarea de una manera no aislada. Esta mejora es suficiente para requisi-
tos de tiempo real laxo.
El kernel de Linux utiliza una licencia GPL, pero un requisito de Android es que en él
se puedan utilizar aplicaciones de terceros que no sólo permitan ser monetizadas sino
que en estas aplicaciones se pueda utilizar código propietario. De tal modo que se
decidió utilizar una licencia BSD, que sigue siendo de código abierto pero no obliga a
que todo el código que se crea a partir de ellas herede la condición de código abierto;
por consiguiente los programadores de aplicaciones Android podrán desarrollar códi-
go propietario para este sistema operativo.
También existen otras funciones relevantes para aplicaciones de tiempo real que no
están implementadas:
Señales:
o sigwaitinfo .
o sigqueue .
o sigtimedwait .
Estas limitaciones serían más que suficientes para considerar Android un sistema
operativo inadecuado para ejecutar aplicaciones de tiempo real, por ello en la siguien-
te sección se describe la solución adoptada para solventar dichas limitaciones.
5 Glibc en Android
Lo primero que se puede considerar para poder solucionar las limitaciones de tiempo
real descritas en la sección anterior podría ser modificar el código de la librería Bionic
para dar soporte a las funciones no implementadas. Esto supondría un gran esfuerzo y
una constante adaptación a las nuevas versiones de la librería que van apareciendo.
Por ello, hemos decidido optar por una solución más portable y fácil de aplicar. Esta
consiste en utilizar la librería tradicional glibc en Android.
Para poder utilizar la librería glibc en Android, en nuestro caso1 es necesario usar
una librería compilada y adaptada para arquitecturas ARM que ejecuten un sistema
operativo Linux. La forma más directa e inmediata es utilizar un compilador cruzado
ARM/Linux con la opción static seleccionada, para así conseguir un código ejecuta-
ble que incorpore todas las funciones de las librerías de las que haga uso el programa
compilado. Esto nos limita a la ejecución exclusiva de programas enlazados estática-
mente, de tal modo que también hemos optado por conseguir ejecutar programas que
hagan uso de la librería glibc en Android de manera dinámica. Para lograr esto se
debe realizar lo siguiente:
1 Todas las pruebas se realizan en un Nexus 5 con arquitectura ARM y la versión de Android
6.0.
arm-linux-gnueabi-gcc hello_world.c -o hello_world
-Wl,--dynamic-linker=/data/local/libs/ld-linux.so.3
-Wl,-rpath=/data/local/libs -fPIE -pie
Teniendo en cuenta que el kernel que incorporan los dispositivos con Android no
sigue la rama principal de desarrollo del kernel de Linux, sería arriesgado afirmar que
la librería glibc se puede utilizar sin inconveniente alguno en este sistema operativo
sin antes realizar algunos tests. Hemos adaptado los test funcionales que están dispo-
nibles en el conjunto denominado “Open POSIX Test Suite” [14], donde se realizan
pruebas funcionales para threads, semáforos, temporizadores, variables condicionales,
colas de mensajes y protocolos de herencia de prioridad con mutexes. Todos estos
tests han sido pasados satisfactoriamente cuando se ejecutaban en Android haciendo
uso de la librería glibc, y por consiguiente podemos afirmar que es posible hacer uso
de esta librería sobre el kernel Linux/Android.
Para poder caracterizar algunas funciones POSIX utilizadas habitualmente con aplica-
ciones de tiempo real se ha utilizado un teléfono Nexus 5 con un procesador de 4
núcleos a una frecuencia de 2,2 Ghz ejecutando la versión de Android 6.0. Además se
han realizado las medidas para dos casos distintos, en el primero de ellos (test A) se
miden las funciones en un procesador sin ninguno de sus núcleos aislados; únicamen-
te todos los threads de los tests se ejecutan con prioridades de tiempo real. En el otro
caso (test B) se ha aislado uno de los núcleos del procesador aplicando los mecanis-
mos descritos en la sección 3. En ambos casos se utiliza la librería tradicional glibc y
en el sistema se ha establecido una carga de trabajo alta (ejecución de benchmarks y
descarga de paquetes por red) para tratar de simular el peor de los escenarios posibles.
En este trabajo se ha presentado una solución para poder utilizar Android con aplica-
ciones de tiempo real laxo haciendo uso de mecanismos proporcionados por el propio
sistema operativo, y aprovechando los procesadores multinúcleo cada vez más presen-
tes en dispositivos Android. Debido a que la librería bionic implementada en Android
no incorpora todas las funciones utilizadas habitualmente en aplicaciones de tiempo
real se ha optado por utilizar la librería tradicional glibc usada en los sistemas opera-
tivos Linux y se ha testado su correcto funcionamiento en Android. De este modo no
es necesaria ninguna modificación del kernel ni de ninguna librería proporcionada por
la plataforma Android. Esto supone una alta portabilidad para los distintos dispositi-
vos y versiones de Android disponibles actualmente. Algunos tests que hemos reali-
zado sobre la solución propuesta demuestran que se obtienen mejoras sustanciales con
respecto al uso de Android sin mecanismos de aislamiento.
Nuestro siguiente objetivo es medir el impacto del uso de drivers de propósito ge-
neral de Android sobre las aplicaciones de tiempo real que ejecutan en un entorno
aislado. Además también es necesario desarrollar un mecanismo de comunicación y
sincronización entre las aplicaciones de tiempo real ejecutadas en núcleo aislado y el
resto de aplicaciones de Android.