Gestión del Sistema Operativo Android ¿Cómo funciona ?

 

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:
  1. Privada: Propiedad de un único proceso y no compartida.
  2. 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

¿Qué es la Memoria Caché?

Memoria caché

Es una memoria rápida, cara y pequeña, formada por biestables.

Se encuentra situada entre el procesador y la memoria principal. En principio se puede considerar que funciona como un buffer de la memoria principal.

La caché se usa para almacenar una copia de aquellas palabras de la memoria principal que están siendo usadas actualmente (y que son las que se usarán con mayor probabilidad en un futuro cercano), ya que, debido a su reducido tamaño, no podemos almacenar toda la información que nuestro programa necesita.

La memoria caché trabaja almacenando los datos en sus chips, que son tomados de ella por la CPU cuando los necesita; al encontrarlos en la caché, se ahorra tener que ir a buscarlos a la RAM, redundando en un considerable ahorro de tiempo.

El procesador, cuando tiene que acceder a memoria, siempre mira antes si la información que busca se encuentra en la memoria caché. Pueden darse dos posibilidades:

  • La información solicitada se encuentra en la caché: lee la copia en caché
  • La información solicitada no se encuentra en la caché (fallo de caché): lee en la memoria principal la información buscada y guarda una copia en la caché. A la hora de escribir el nuevo dato en la caché pueden ocurrir dos cosas:
    • Hay espacio libre en la caché: se escribe el dato en las posiciones libres.
    • No hay espacio libre en la caché: hay que buscar el dato a sustituir por el que acaba de llegar. Si algún dato de los que se van a sacar ha sido modificado, se debe actualizar la copia en memoria del mismo.
  1. Niveles de caché

Los ordenadores actuales suelen montar hasta tres niveles de caché:

  • L1: caché interna asociada a los núcleos de la CPU. Es utilizada para almacenar y acceder a datos e instrucciones importantes y de uso frecuente, agilizando los procesos al ser el nivel que ofrece un tiempo de respuesta menor. Se divide en dos subniveles:
    • Nivel 1 Data Cache: se encarga de almacenar datos usados frecuentemente.
    • Nivel 1 Instruction Cache: se encarga de almacenar instrucciones usadas frecuentemente.
  • L2: caché interna al microprocesador, pero comúnmente compartida por varios núcleos al mismo tiempo.
  • L3: este nivel de caché suele ser de menor velocidad y mayor capacidad que las anteriores y frecuentemente se sitúa dentro del encapsulado del procesador, pero en su periferia, compartida por todos los núcleos del mismo.
  1. Localidad de referencia

Los programas manifiestan una propiedad que se explota en el diseño del sistema de gestión de memoria de los computadores en general y de la memoria caché en particular, la localidad de referencias: los programas tienden a reutilizar los datos e instrucciones que utilizaron recientemente. Una regla empírica que se suele cumplir en la mayoría de los programas revela que gastan el 90% de su tiempo de ejecución sobre sólo el 10% de su código. Una consecuencia de la localidad de referencia es que se puede predecir con razonable precisión las instrucciones y datos que el programa utilizará en el futuro cercano a partir del conocimiento de los accesos a memoria realizados en el pasado reciente. La localidad de referencia se manifiesta en una doble dimensión: temporal y espacial.

  1.  Localidad temporal

 las palabras de memoria accedidas recientemente tienen una alta

probabilidad de volver a ser accedidas en el futuro cercano. La localidad temporal de los programas

viene motivada principalmente por la existencia de bucles.

  1. Localidad espacial

 las palabras próximas en el espacio de memoria a las recientemente referenciadas tienen una alta probabilidad de ser también referenciadas en el futuro cercano. Es decir, que las palabras próximas en memoria tienden a ser referenciadas juntas en el tiempo. La localidad espacial viene motivada fundamentalmente por la linealidad de los programas (secuenciamiento lineal de las instrucciones) y el acceso a las estructuras de datos regulares.

  1. Diseño

En el diseño de la memoria caché se deben considerar varios factores que influyen directamente en el rendimiento de la memoria y por lo tanto en su objetivo de aumentar la velocidad de respuesta de la jerarquía de memoria. Estos factores son las políticas de ubicación, extracción, reemplazo y escritura.

  1. Política de ubicación

Decide dónde debe colocarse un bloque de memoria principal que entra en la memoria caché. Las más utilizadas son:

 

Directa: al bloque i-ésimo de memoria principal le corresponde la posición i módulo n, donde n es el número de bloques de la memoria caché. Cada bloque de la memoria principal tiene su posición en la caché y siempre en el mismo sitio. Su inconveniente es que cada bloque tiene asignada una posición fija en la memoria caché y ante continuas referencias a palabras de dos bloques con la misma localización en caché, hay continuos fallos habiendo sitio libre en la caché.

Asociativa: los bloques de la memoria principal se alojan en cualquier bloque de la memoria caché, comprobando solamente la etiqueta de todos y cada uno de los bloques para verificar acierto. Su principal inconveniente es la cantidad de comparaciones que realiza.

Asociativa por conjuntos: cada bloque de la memoria principal tiene asignado un conjunto de la caché, pero se puede ubicar en cualquiera de los bloques que pertenecen a dicho conjunto. Ello permite mayor flexibilidad que la correspondencia directa y menor cantidad de comparaciones que la totalmente asociativa.

  1. Política de extracción

La política de extracción determina cuándo y qué bloque de memoria principal hay que traer a memoria caché. Existen dos políticas muy extendidas:

 

  • Por demanda: un bloque solo se trae a memoria caché cuando ha sido referenciado y no se encuentre en memoria caché.
  • Con prebúsqueda: cuando se referencia el bloque i-ésimo de memoria principal, se trae además el bloque (i+1)-ésimo. Esta política se basa en la propiedad de localidad espacial de los programas.
    1. Política de reemplazo

Determina qué bloque de memoria caché debe abandonarla cuando no existe espacio disponible para un bloque entrante. Básicamente hay cuatro políticas:

 

  • Aleatoria: el bloque es reemplazado de forma aleatoria.
  • FIFO: se usa el algoritmo First In First Out (FIFO) (primero en entrar primero en salir) para determinar qué bloque debe abandonar la caché. Este algoritmo generalmente es poco eficiente.
  • Usado menos recientemente (LRU): sustituye el bloque que hace más tiempo que no se ha usado en la caché, traeremos a caché el bloque en cuestión y lo modificaremos ahí.
  • Usado con menor frecuencia (LFU): sustituye el bloque que ha experimentado menos referencias.

 

pasted image 0 1

¿Qué son las Topologías de Red?

Topologías de Red

La topología de una red es la configuración espacial en que se disponen sus líneas y sus nodos. Esta organización responde a los siguientes aspectos de diseño e implementación:

  • Funcionalidad
  • Escalabilidad
  • Optimización del coste

Las principales topologías de red son las siguientes o una mezcla de algunas de ellas:

Topologías cableadas

Topología en estrella

En la topología en estrella todos los equipos están conectados a un nodo central, que realiza las tareas de distribución, conmutación y control de flujo de todas las comunicaciones que circulan por la red.

En función de qué capa del modelo OSI trabaje el dispositivo que hace el papel de nodo en la estrella, se tendrá un tipo de red u otra. Puede ocupar este puesto un concentrador (hub), un conmutador (switch), un enrutador (router), un proxy, etc.

Topología en Malla

disponen conexiones entre nodos en función del tráfico, la distancia física entre ellos, etc. Mantienen la posibilidad de conectar nodos por circuitos alternativos cuando alguna de las conexiones falla. Esta estructura es la que usan, por ejemplo, las redes de conmutación de circuitos y de paquetes.

Topología en Bus

Todos los nodos se conectan a lo largo del medio físico, por ejemplo, un cable. Es una organización barata y sencilla, pero requiere medios para controlar y arbitrar el acceso al medio común.

Topología en Árbol

Utilizan una estructura de interconexión jerárquica.

Topología en Anillo

Todos los nodos están conectados a un medio físico que los une formando un círculo.

pasted image 0