Este contenido se puede encuadrar en los temas:
TEMA 20 PES: Explotación y administración de Sistemas Operativos Monousuario y Multiusuario
TEMA 20 SAI: Explotación y administración de un Sistema Operativo Monousuario
¿Qué es Android?
Android es un sistema operativo monousuario desarrollado por Google, basado en el Kernel 2.5 de Linux y otro software de código abierto. Está orientado a la plataforma ARM aunque existe una rama de desarrollo independiente orientada a la arquitectura x86 (Chrome OS).
Android es software libre bajo licencia Apache y actualmente (año 2020) es el sistema operativo móvil más utilizado en el mundo.
Su nombre proviene de la famosa novela de Philip K. Dick Do Androids Dream of Electric Sheep? (¿sueñan los androides con ovejas eléctricas?) que fue adaptada en la película Blade Runner de Ridley Scott.
La compañía que lo desarrolló fue Android Inc, apoyada económicamente por Google y comprada por este en 2005, pero no fue presentado hasta el año 2007 tras la fundación del Open Handset Alliance que engloba numerosos fabricantes de hardware relacionados con la telefonía móvil.
La estructura del sistema operativo Android se compone de aplicaciones que se ejecutan sobre un Middleware que las abstrae de la complejidad de las comunicaciones del sistema y de la máquina en particular, mediante un framework Java.
Bajo esta máquina virtual Java, se encuentra el núcleo del sistema escrito en lenguaje C y que incorpora una potente biblioteca que incluye un administrador de interfaz gráfica (surface manager), un framework OpenCore, una base de datos relacional SQLite, una API gráfica OpenGL, un motor de renderizado WebKit (Safari), un motor gráfico SGL – SSL y una biblioteca estándar de C (Bionic).
MÁQUINA VIRTUAL JAVA
Uno de los elementos clave de Android es la máquina virtual Java. En lugar de utilizar una tradicional máquina virtual Java (VM), tales como Java ME (Java Mobile Edition), Android utiliza su propia máquina virtual personalizada diseñada para asegurar que la multitarea se ejecuta de manera eficiente en un único dispositivo.
Inicialmente se utilizó la máquina virtual Dalvik con la librería de ejecución JIT (Just In Time) que traducía a bytecode Java cualquier aplicación en el momento de su ejecución.
En la versión 4.4 de Android se introdujo la máquina ART (Android RunTime) que compila la aplicación a Java bytecode en el momento de su instalación; a partir de la versión 5 ART reemplazó por completo a Dalvik.
Las aplicaciones (Apps) en Android se distribuyen por tanto en archivos .APK (Android Application PacKage, similar al JAR del Java de Oracle) y son compiladas en el momento de su instalación por ART a Java bytecode.
La máquina virtual Java de Android no gestiona directamente la memoria o los procesos, sino que utiliza el núcleo de Linux subyacente para manejar la planificación de procesos y la gestión de la memoria.
Android funciona en modo multitarea ejecutando múltiples instancias de la máquina virtual java, una por cada proceso, lo que crea un entorno muy confiable, similar a un sandbox.
Gestión de Memoria en Android.
La plataforma de Android se basa en la premisa de que la memoria libre es memoria desperdiciada, de modo que intenta aprovechar la memoria disponible en todo momento.
Android Runtime (ART) y la máquina virtual Dalvik usan las funciones de paginación y mapeo de memoria (mmapping) para administrar la memoria.
Jerarquía de Memoria
La jerarquía de Memoria en Android se basa en la gestión de tres niveles: RAM, zRAM y ROM.
- La memoria RAM es la memoria principal del dispositivo y se gestiona mediante paginación.
- La zona libre de RAM se utiliza como una memoria de intercambio SWAP en la que se almacenan datos y programas de forma comprimida, aumentando así su aprovechamiento en término de capacidad, de ahí el nombre de zRAM, para diferenciarla.
- La memoria ROM está compuesta por memoria EEPROM Flash Integrada (eMMC/embedded Multimedia Card) y opcionalmente una tarjeta SD.
- Existe un nivel cero en esta jerarquía compuesto por la memoria caché y registros del microprocesador, pero Android no los gestiona directamente, sino que lo hace el microprocesador.
Paginación de la memoria.
La memoria RAM está dividida en páginas. Por lo general, cada página tiene 4 KB de memoria.
Las páginas se consideran libres o usadas. Las páginas libres son memoria RAM sin usar. Las páginas usadas son memoria RAM que el sistema está utilizando de manera activa y se agrupan en las siguientes categorías:
- Almacenamiento en caché: Memoria con copia en un archivo del almacenamiento (por ejemplo, código o archivos asignados a la memoria). Hay dos tipos de esta memoria:
- Privada: Propiedad de un único proceso y no compartida.
- Compartida: Es utilizada conjuntamente por varios procesos.
- Anónima: Memoria no respaldada por un archivo en almacenamiento, por ejemplo bloques de datos temporales.
Las páginas a su vez pueden ser Limpias o Sucias: Las páginas limpias contienen una copia exacta de un archivo (o parte de un archivo) respaldado en ROM. Una página limpia se «ensucia» cuando es modificada y por tanto ya no contiene una copia fidedigna en el soporte de almacenamiento.
Es posible liberar memoria descartando las páginas limpias porque están respaldadas, pero no se deben eliminar en ningún caso las páginas sucias, ya que se perdería información.
Algoritmo de Reemplazo de página.
El algoritmo de reemplazo de página es el mismo que utiliza el núcleo Linux 2.6 y que se denomina PFRA (Page Frame Reclamation Algorithm). Es una modificación del algoritmo LRU pero basado en listas y con prioridad para los procesos activos.
Las páginas de memoria en uso se dividen en dos listas por cada zona de memoria, una para aplicaciones en uso y otra para aplicaciones inactivas. Las páginas de memoria de la lista de inactivas pueden además ser marcadas como swappables o descartables dependiendo del tiempo de inactividad y previsión de uso.
El algoritmo PFRA sólo se ejecuta cuando la memoria empieza a escasear, momento en el cual selecciona todas las páginas marcadas como “descartables/limpias” y a continuación se seleccionan las páginas menos usadas recientemente (LRU) de la lista de aplicaciones inactivas.
Este algoritmo se ejecuta de forma incremental, intentando liberar el máximo de memoria pero cargando en zRAM páginas inactivas sucias, volcando a memoria masiva (limpiando) solo en las últimas iteraciones si no se alcanza liberar la memoria deseada.
La implementación en Android de este algoritmo la realiza el daemon kswapd que se ejecutará automáticamente al alcanzarse un umbral mínimo de memoria disponible y buscará alcanzar un umbral máximo determinado también de antemano.
Si tras la ejecución de kswapd aún no hay suficiente memoria para la carga de una determinada aplicación en memoria, se ejecutará un asistente de limpieza LMK (Low Memory Killer) que sacará de memoria procesos activos, según un nivel de prioridad asignado, comenzando con los procesos en segundo plano menos usados, y siguiendo incluso con la app de inicio, servicos, apps en primer plano, procesos del sistema, etc. siguiendo la jerarquía de procesos de Android.
Gestión de Procesos en Android.
Procesos:
Con frecuencia la documentación de Android se refiere a la gestión de procesos como ciclo de vida de Android.
Android implementa la multitarea mediante la ejecución de múltiples hilos para cada proceso; el proceso más simple consta de un sólo hilo principal que sólo es lanzado en el caso de que no exista ninguna instancia del proceso en ejecución.
De igual forma un proceso puede utilizar múltiples hilos, uno por cada subproceso. También se da la situación en que un proceso comparte subprocesos con otros, lanzando para ello el sistema los hilos necesarios.
Tipos de procesos en Android.
El tipo de proceso en Android determina el comportamiento del planificador respecto a este: no es lo mismo un proceso “activo” y “visible” cuya finalización por parte del sistema tendría una experiencia muy negativa para el usuario, que por ejemplo un servicio del sistema.
Android por tanto, clasifica los procesos como:
- Activos: Se están ejecutando y además son requeridos para la interacción con el usuario, bien sean procesos en primer plano o servicios dando soporte a éstos.
- Visibles: Un nivel por debajo de Activo, ya que un proceso visible estaría en segundo plano.
- Servicio: Procesos que no son visibles de forma directa pero dan un servicio importante al usuario, por ejemplo mantener una conexión a Internet. Estos procesos no deben ser finalizados a no ser que su mantenimiento suponga una merma para un proceso activo.
- Segundo Plano: Procesos en ejecución, pero no visibles, a los que el sistema intentará dotar de recursos siempre que haya disponibles.
- Vacíos: Es una forma rápida de inicialización: por ejemplo un proceso que intenta ser lanzado pero el liberador de memoria está ocupado haciéndole hueco.
Planificación de procesos
La planificación en Android es expropiativa lo cual debe ser tenido en cuenta por el programador, ya que si no se definen bien los diferentes componentes de la aplicación esta puede ser finalizada mientras está efectuando una tarea relevante para el sistema o para el usuario.
El algoritmo utilizado por el planificador es Round-Robin con prioridad basada en una jerarquía de importancia según el tipo de proceso (visto anteriormente) y otros factores:
El sistema mantiene una lista pseudo-LRU (Last Recently Used) para evitar que los procesos se apropien de los recursos, pero ordenada según prioridades. La prioridad de un proceso se puede incrementar si este es un subproceso de mayor prioridad, es decir, la prioridad de un conjunto de procesos interdependientes se iguala a la prioridad del componente más prioritario del conjunto.
Cuando un proceso pasa al estado de espera o de finalización, este se almacena en caché (zRAM). El sentido de almacenar también los procesos finalizados es acelerar su carga en RAM si se vuelven a solicitar.
Android asegura la respuesta de cualquier app lanzada por el usuario, deteniendo y matando a los procesos que impiden la fluidez y liberando recursos para las aplicaciones más prioritarias.
Comunicación entre procesos
Los procesos en Android se comunican mediante paso de mensajes de tipo objeto. Esto se hace a través de llamadas al IPC Binder, que es la implementación en Android de su propio InterProcess Caller y que permite a los procesos en ejecución, comunicarse con otros procesos independientes del sistema para sincronizar su ejecución u obtener información necesaria.
Gestión de Usuarios en Android
Android sólo puede ser accedido por un usuario en un momento dado, es decir por el usuario principal.
En algunos sistemas (Samsung, Xiaomi) es posible mantener usuarios adicionales mediante la adicción de capas de software sobre el sistema operativo que emule el uso por varios usuarios, por ejemplo para control parental o para tener un doble uso del teléfono en casa y en el trabajo.
Sin embargo en el sistema sólo hay en realidad un único usuario, al que se le añaden o restringen permisos y visores sobre aplicaciones.
Este usuario al que se le ligan las distintas cuentas de proveedores (Google, Xiaomi, Amazon, etc) viene con los permisos restringidos por defecto.
Si es necesario dar mayores niveles de prioridad al usuario debemos acceder a la configuración del teléfono para activar los permisos completos. A este proceso se le suele llamar ruteo del teléfono, porque al hacerlo activamos los permisos completos del usuario root en el kernel Linux. Con frecuencia esta escalada de privilegios está restringida y apareja la pérdida de la garantía y de otras ventajas de la marca.
Fuentes del artículo:
https://es.wikipedia.org/wiki/Android
https://androidos.readthedocs.io/
https://developer.android.com/topic/performance/memory-management?hl=es