mozilla
Los resultados de tu búsqueda

    Arquitectura del Sistema Operativo Firefox OS

    This translation is incomplete. Please help translate this article from English.

    Este artículo es un panorama de alto nivel de la arquitectura de la plataforma Firefox OS, que introduce conceptos fundamentales y explica cómo sus componentes interactúan a un nivel básico.

    Nota: recuerda que Firefox OS todavía se encuentra en estado de pre-lanzamiento. La arquitectura descrita aquí no necesariamente es la final y que otros elementos todavía pueden estar sujetos a cambios.

    Terminología de Firefox OS

    Existen algunos términos que debes entender antes de continuar leyendo nuestra documentación sobre Firefox OS.

    B2G
    Sigla de Boot to Gecko.
    Boot to Gecko
    El nombre código de ingeniería para el sistema operativo Firefox OS.
    Firefox OS
    Es básicamente la marca y  servicios de soporte de Mozilla (y sus socios de OEM) aplicados sobre Boot to Gecko para crear el producto final de lanzamiento.
    Gaia
    La interfaz de usuario de la plataforma Firefox OS. Cualquier cosa dibujada en la pantalla una vez que Firefox OS ha sido iniciado es un producto de la capa Gaia. La misma implementa la pantalla de seguridad (lock screen), pantalla principal (home screen) y todas las aplicaciones estándares de cualquier teléfono inteligente moderno. Gaia se implementa en su totalidad empleando HTML, CSS y JavaScript. Las interfaces subyacentes al sistema operativo son Web APIs de código abierto, que se implementan por medio de la capa Gecko. Las aplicaciones de terceros se pueden instalar en paralelo con la capa Gaia.
    Gecko
    Este es el runtime de aplicaciones de Firefox OS, es decir, la capa que provee todo el soporte para el trío de estándares de código abierto: HTML, CSS y JavaScript. Es responsable de que esas APIs funcionen bien en cualquier sistema operativo soportado por Gecko. Esto implica que Gecko incluya, además de otras cosas, paquetes de redes y de gráficos, un motor de diagramación, una máquina virtual de JavaScript y capas de adaptación (porting).
    Gonk
    Gonk es el sistema operativo de bajo nivel de la plataforma Firefox OS que consiste un núcleo/kernel Linux (basado sobre el Android Open Source Project (AOSP)) y una capa de abstracción de hardware de espacio de usuario (HAL por su sigla en inglés). El kernel y varias de las librerías de espacio de usuario son proyectos comunes de código abierto: Linux, libusb, bluez, y sucesivos. Algunas de las otras partes de la HAL se comparten con la AOSP: GPS, cámara y otros. Se podría decir que Gonk es una distribución de Linux muy sencilla. Gonk es una capa de adaptación (port) de dispositivos: un adaptador entre el hardware y Gecko. Gonk es una distribución de Linux bastante sencilla que puede ser tratada como un adaptador Gecko empardado con capas de adaptación Gecko —entonces Gonk es un objetivo para adaptar Gecko a Firefox OS así como también hay adaptadores de Gecko para OS X, Windows y Android. Como el Proyecto Firefox OS goza de control total sobre Gonk, podemos exponer interfaces a Gecko que no podrían ser expuestas en otros sistemas operativos. Por ejemplo, Gecko posee a través de Gonk acceso directo al conjunto completo de telefonía y al buffer de pantalla pero no tiene este acceso en otros sistemas operativos.
    Jank
    Este término, generalmente empleado en el área de las aplicaciones móviles, se refiere al efecto causado por código lento o ineficiente en una aplicación, que podría blquear la actualización de la interfaz de usuario y provocar su lentitud o que no responda. Nuestros ingenieros de Gaia se valen de numerosas técnicas de optimización para evitar esto lo mejor posible.

    Diagrama estructural

    Firefox OS Architecture

    Procedimiento de arranque de Firefox OS

    Esta sección describe el proceso por el que los dipositivos con Firefox OS arrancan (butean), cuáles partes están involucradas en el proceso y dónde. A modo de referencia rápida, el flujo del arranque general del sistema va desde los cargadores de arranque (bootloaders) en el espacio del núcleo/kernel al init en el código nativo, a B2G y después a Geko en el espacio de usuario y después finalmente a la aplicación de sistema, gestor de ventanas y posteriormente a la pantalla de inicio de la aplicación en Gecko. Sobre ese conjunto se ejecutan todas las otras aplicaciones.

    El proceso de arranque encadenado (bootstrapping)

    Cuando un dispositivo con FirefoxOS se enciende,  la ejecución se inicia en el cargador del arranque primario (bootloader). Desde allí, el proceso de la carga del SO principal procede normalmene; una sucesión de arranques de jerarquías crecientes inicia el siguiennte arranque en la cadena. Al final del proceso, se delega la ejecución al núcleo/kernel Linux.

    Hay algunos puntos destcables sobre el proceso de arranque:

    • Los arrancadores generalmente muestran la primera pantalla de sistema que ve el usuario durante el inicio; generalmente es un logo del fabricante/vendedor.
    • Los arrancadores cargan por flash una imagen [virtual] en el dispositivo. Diferentes dispositivos emplean difierentes protocolos; la mayoría de los teléfonos emplean el fastboot protocol (protocolo de carga rápida), pero el Samsung Galaxy S II usa el protocolo Odin.
    • Hacia el final del proceso de arranque encadenado, suele cargarse la imagen virtual del módem y se ejecuta en el procesador del módem. Cómo ocurre esto es específico de cada dispositivo y puede tambien serlo del fabricante.

    El kernel Linux

    El núcleo Linux empleado por Gonk es muy similar a la versión de Linux difundida (upstreamed) de la que deriva (basada sobre el Android Open Source Project). Existen cambios hehos por el AOSP que todavía no han sido difundidos. Además, los fabricantes y vendedores a veces modifican el núcleo y cargan esos cambios a la versión de difusión de acuerdo con su intinerario. En términos generales, el núcleo Linux es muy parecido al original.

    El proceso de arranque de Linux se encuentra bien documentado en la internet por lo tanto este artículo no lo cubrirá.

    El núcleo Linux activará dispositivos y ejecutará procesos esenciales definidos en init.rc y su sucesor init.b2g.rc para arrancar procesos esenciales como b2g [procesos básicos de Firefox OS, contenedores de Gecko] y rild [un proceso relacionado con la telefonía que puede ser específico de cada chip] —vaya más abajo para ver más detalles. Al final del proceso, un proceso init de espacio de usuario (userspace) se lanza, como ocurre en la mayoría de los sistemas operativos del tipo UNIX.

    Una vez que el proceso init se ha lanzado, el núcleo Linux administra las llamadas del sistema desde el espacio de usuario, las interrupciones y semejantes desde los dispositivos de hardware. Algunas de las características de hardware se exponen al espacio de usuario a través de sysfs. Por ejemplo, aquí hay un fragmento de código que lee el estado de la batería en Gecko:

    FILE *capacityFile = fopen("/sys/class/power_supply/battery/capacity", "r");
    double capacity = dom::battery::kDefaultLevel * 100;
    if (capacityFile) {
      fscanf(capacityFile, "%lf", &capacity);
      fclose(capacityFile);
    }

    Más sobre el proceso init

    El proceso init en Gonk gestiona el montaje de los archivos de sistema requeridos y activa los procesos de systema. Después de eso, se mantiene activo como gestor de procesos. Esto es muy similar al init en otros sistemas operativos similares a UNIX. Interpreta scripts [los archivos init.rc] que consisten de  comandos que describen lo que debería ser hecho para iniciar servicios varios. El init.rc  de FirefoxOS suele ser el init.rc original de Android para ese dispositivo, parchado para incluir los requisitos de arranque de FirefoxOS, y varía de dispositivo a dispositivo.

    Una de las tareas fundamentales que maneja el proceso init es el inicio del proceso b2g; éste es el núcleo del sistema operativo FirefoxOS.

    El código para tal init.rc es el siguiente:

    service b2g /system/bin/b2g.sh
        class main
        onrestart restart media

    Nota: las variaciones de init.rc dependerán de dispositivo a dispositivo; a veces init.b2g.rc sólo es anexadoo, y a veces los parches son más significativos.

    Estructura del proceso del espacio de usuario (userspace)

    Resulta muy útil echar un vistazo de alto nivel a cómo varios componentes del Fir3fox OS se articulan e interactúan entre sí. Este diagrama muestra los procesos primarios de espacio de usuario en Firefox OS.

    Userspace diagram

    Nota: recuerda que como Firefox OS se encuentra en desarrollo activo, este diagrama puede estar sujeto a cambios y puede ser impreciso parcialmente.

    El proceso b2g es el proceso primario de sistema. Se ejecuta con privilegios altos; tiene acceso a la mayoría del hardware. b2g se comunica con el módem, almacena en el buffer de pantalla e interactúa con el GPS, cámaras y otros dispositivos. Internamemte, se ejecuta cen una capa de Gecko (implementada por libxul.so). Ver Gecko para más detalles sobre cómo funciona la capa Gecko y cómo b2g se comunica con ella.

    b2g

    El proceso b2g puede dar lugar a un número de procesos de contenido de baja categoría. Estos procesos albergan la carga de aplicaciones web y otros contenidos. Estos procesos se comunican con el proceso principal del servidor Gecko a través de IPDL, un sistema de envio de mensajes.

    El proceso b2g  ejecuta lixbul, lo que hace referencia a b2g/app/b2g.js para obtener las preferencias de fábrica. De las preferencias se abrirá el archivo HTML descripto b2g/chrome/content/shell.html, que se compila en un archivo omni.ja. El shell.html incluye el archivo b2g/chrome/content/shell.js , que activa la aplicación system  de Gaia.

    rild

    El proceso rild  es la interfaz del proceso del módem. rild es el daemon que implementa La capa de Inerfaz de la Radio [Radio Interface Layer (RIL)]. Es una pieza propia del código que está implementada por el fabricante/vendedor de hardware para comunicarse con el hardware del módem. rild hace posible que el código cliente se comunique con un empalme de dominio-UNIX al que se enlaza Se inicia con un código como este en el init script:

    service ril-daemon /system/bin/rild
        socket rild stream 660 root radio

    rilproxy

    En Firefox OS, el cliente rild client es el proceso rilproxy. Esto actúa como un proxi inerte de envio (dumb proxy) entre rild y b2g. Este proxi es necesario  como un detalle de implementación; es de hecho necesario. El rilproxycódigo se encuentra en GitHub.

    mediaserver

    El  proceso mediaserver controla la reproducción de audio y video. Gecko se comunica con él a través de un mecanismo de Llamada de Procedimiento Remota de Android [Android Remote Procedure Call (RPC)]. Algunos de los contenidos multimedia que Gecko puede reproducir (OGG Vorbis audio, OGG Theora video, y WebM video) son decodificados por Gecko y enviados directamente al proceso mediaserver. Otros archivos multimedia son decodificados por libstagefright, que puede acceder códecs del fabricante y codificadores del hardware.

    Nota: El proceso mediaserver es un compponente "provisional" de Firefox OS; existe sólo para ayudar en el trabajo de desarrollo inicial pero se espera que se descarte con el tiempo; lo que seguramente no ocurrirá antes de la version 2.0 de Firefox OS.

    netd

    El proceso netd se usa para configurar interfaces de red.

    wpa_supplicant

    El proceso wpa_supplicant process es un daemon estándar de estilo UNIX que maneja la conectividad con los puntos de acceso WiFi.

    dbus-daemon

    El dbus-daemon implementa el D-Bus, un sistema de mensajes de bus que Firefox OS emplea para las comunicaciones por Bluetooth.

    Gecko

    Gecko, como se lo mencionó previamente, es la implementación de estándares web (HTML, CSS, y JavaScript) que se usa para implementar todos lo que el usuario ve en Firefox OS.

    Note: Para buscar en la base de código de Gecko, se puede usar http://dxr.mozilla.org. Es más elegantw y ofrece buenas características de referemcias. pero con repositorios limitados. También podría usar el tradicional http://mxr.mozilla.org, que contiene más proyectos de Mozilla.

    Archivos de Gecko relacionados con Firefox OS

    b2g/

    La carpeta b2g contiene es su mayoría funciones relacionadas con Firefox OS.

    b2g/chrome/content

    Contiene archivos de Javascript ejecutados sobre la aplicación de sistema.

    b2g/chrome/content/shell.html

    El punto de entrada a Gaia — el HTML para la aplicación de sistema. shell.html toma de settings.js and shell.js:

    <script src="chrome://browser/content/settings.js" type="application/javascript;version=1.8"> </script>
    <script src="chrome://browser/content/shell.js" type="application/javascript;version=1.8"> </script>

    settings.js contiene parámetros de configuración básicos (default) de sistema.

    b2g/chrome/content/shell.js

    shell.js es el primer script que se carga en la aplicación de sistema de Gaia.

    shell.js importa todos los módulos requeridos, registra los detectores de clave (key listeners), define sendCustomEvent y sendChromeEvent para que se cominiquen con Gaia, y provee ayudantes de instalación de aplicaciones web: indexedDB quota, RemoteDebugger, ayudante de teclado, y la herramienta para captura de pantalla.

    Pero la función más importante de shell.js es lanzar la aplicación de sistema de Gaia, después entregarle todo el trabajo general de administración del sistema.

    let systemAppFrame =
      document.createElementNS('http://www.w3.org/1999/xhtml', 'html:iframe');
        ...
      container.appendChild(systemAppFrame);
    b2g/app/b2g.js

    Este script contiene configuraciones predefinidas, como about:config en el navegador, y la misma que Gaia's pref.js. Estas configuraciones se pueden cambiar desde la aplicación de congifuraciones y se pueden sobreescribir con user.js en el script de construcción Gaia.

    dom/{API}

    Nuevas implementaciones de la API (post-b2g) se localizarán en dom/. Las APIs anteiores se localizarán en dom/base, for example Navigator.cpp.

    dom/apps

    .jsm se cargarán implementaciones de API — .js API tales como webapp.js install, getSelf, etc.

    dom/apps/PermissionsTable.jsm

    Se definen todos los permisos en PermissionsTable.jsm

    dom/webidl

    WebIDL es el lenguaje empleado para definir web APIs. La información sobre los atributos soportados se encuentra en WebIDL_bindings.

    hal/gonk

    Este directorio contiene archivos sobre la capa  de adaptación gonk..

    Archivos generados

    module/libpref/src/init/all.js

    Contiene todos los archivos de configuración.

    /system/b2g/ omni.ja and omni.js

    Contiene el paquete de estilos para los recursos en el dispositivo.

    Proceso de eventos de ingreso

    La mayor parte de las acciones en Gecko se activas por acciones de usuario. Estas acciones se representan por eventos de ingreso (tales como presionar botones, tocar la pantalla y así). Estos eventos entran a Gecko a través de Gonk implementation perteneciente a nsIAppShell, que es una interfaz de Gecko empleada para representar los puntos de entrada primaria de una aplicación de Gecko, es decir, el controlador del dispositivo de ingreso llama métodos en el objeto nsAppShell que representa el subsistema de Gecko para así enviar eventos a la interfaz de usuario.

     

    Por ejemplo:

     

    void GeckoInputDispatcher::notifyKey(nsecs_t eventTime,
                                         int32_t deviceId,
                                         int32_t source,
                                         uint32_t policyFlags,
                                         int32_t action,
                                         int32_t flags,
                                         int32_t keyCode,
                                         int32_t scanCode,
                                         int32_t metaState,
                                         nsecs_t downTime) {
      UserInputData data;
      data.timeMs = nanosecsToMillisecs(eventTime);
      data.type = UserInputData::KEY_DATA;
      data.action = action;
      data.flags = flags;
      data.metaState = metaState;
      data.key.keyCode = keyCode;
      data.key.scanCode = scanCode;
      {
        MutexAutoLock lock(mQueueLock);
        mEventQueue.push(data);
      }
      gAppShell->NotifyNativeEvent();
    }

    Estos eventos provienen del sistema estándar Linux input_event. Firefox OS emplea light abstraction layer sobre eso; lo que provee algunas características útiles como filtrar los eventos. Se puede ver el código que crea eventos de ingreso en el método EventHub::getEvents() que se encuentra en widget/gonk/libui/EventHub.cpp.

    Un vez que Gecko recivió los eventos, se envían a DOM DOM por nsAppShell:

    static nsEventStatus sendKeyEventWithMsg(uint32_t keyCode,
                                             uint32_t msg,
                                             uint64_t timeMs,
                                             uint32_t flags) {
        nsKeyEvent event(true, msg, NULL);
        event.keyCode = keyCode;
        event.location = nsIDOMKeyEvent::DOM_KEY_LOCATION_MOBILE;
        event.time = timeMs;
        event.flags |= flags;
        return nsWindow::DispatchInputEvent(event);
    }
    

    Después de lo anterior, los eventtos son consumidos por Gecko o enviados a aplicaciones web como Eventos DOM para ser procesados posteriormente.

    Graficos

    En si nivel más inferior, Gecko emplea OpenGL ES 2.0 para establecer un contexto GL que envuelva los buffers del hardwaret. Se realiza dentro de la implementación de Gonk en nsWindow por medio de un código similar:

    gNativeWindow = new android::FramebufferNativeWindow();
    sGLContext = GLContextProvider::CreateForWindow(this);

    La clase FramebufferNativeWindow es obtiene directamente desde Android; ver FramebufferNativeWindow.cpp.Esto emplea la API gralloc API para acceder al controlador de gráficos con el fin de mapear los buffers  del dispositivo framebuffer a la memorio del dispositivo.

    Gecko emplea su sistema (de) Layers para componer contenido dibujado en la pantalla. En resumen, ocurre lo siguiente:

    1. Gecko dibuja regiones distintas de las páginas en los buffers de memoria, A veces, estos buffers están en la memoria del sistema; otras veces, son texturas mapeadas en el espacio de direcciones de Gecko, lo que siginifica que Gecko está dibujando directamente en la memoria de video. Esto se realiza generalmente en el método BasicThebesLayer::PaintThebes().
    2. Entonces, Gecko, compone todas estas texturas en la pantalla empleando comandos OpenGL. Esta composición tiene lugar en ThebesLayerOGL::RenderTo().

    Los detalles de cómo Gecko maneja el muestreo (rendenring) de contenido web se encuentra fuera del alcance de este documento.

    Capa de Absrtacción de Hardware (HAL)


    La capa de abstracción de hardware de Gecko es una de sus capas de adaptación (porting). Gestionla los accesos de bajo nivel a las interfaces del sistema a lo largo de múltiples plataformas que emplean una API de C++ a la que se accede en los niveles superiores de Gecko. Estas APIs se implementan de plataforma a plataforma dentro de la HAL de Gecko. Esta capa de abstracción de hardware no se expone directamente a código javaScript dentro de Gecko.

    Cómo funciona HAL

    Tomemos la API Vibration como ejemplo. la HAL para esta API se define en hal/Hal.h. Resumiendo (simplificando el método de firma para hacerlo más claro), tienes esta función:

    void Vibrate(const nsTArray<uint32> &pattern);</uint32>

    Esta es la función que el código de Gecko llama par activar la vibración del dispositivo de acuerdo con un patrón específico; una función correspondiente existe para cancelar la vibración activa. La implementación de GONK para este método está en hal/gonk/GonkHal.cpp:

    void Vibrate(const nsTArray<uint32_t> &pattern) {
      EnsureVibratorThreadInitialized();
      sVibratorRunnable->Vibrate(pattern);
    }
    </uint32_t>

    Este código envía la petición para el inicio de la vibración a otro conjunto de procesos, que se implementa en VibratorRunnable::Run(). El bucle principal de este conjunto se ve así:

    while (!mShuttingDown) {
      if (mIndex < mPattern.Length()) {
        uint32_t duration = mPattern[mIndex];
        if (mIndex % 2 == 0) {
          vibrator_on(duration);
        }
        mIndex++;
        mMonitor.Wait(PR_MillisecondsToInterval(duration));
      }
      else {
        mMonitor.Wait();
      }
    }
    

    vibrator_on() es la API HAL de GONK que enciende el motor de vibración. Internamente, este método envía un mensaje al controlador de núcleo (kernel driver) al escribir un valor en un objeto de kernel empleando sysfs.

    Implementaciones de la Fallback HAL API


    Las APIs HAL de Gecko tienen soporte en todas las plataformas. Cuando se construye Gecko para una plataforma que no expone una interfaz a los motores de vibración (como una computadora de escritorio) entonces se vale de una implemenación de fallback de la API de HAL. Para la vibración, se emplea en hal/fallback/FallbackVibration.cpp.

    void Vibrate(const nsTArray<uint32_t> &pattern) {
    }</uint32_t>

    Implementaciones de Sandbox (entorno cerrado)

    Debido a que la mayoría del contenido de la red se ejecuta en procesos de contenido con privilegios bajos, no podemos suponer que esos procesos tienen los privilegios necesarios para poder (por ejemplo) activar o desactivar el motor de vibración. Además, queremos tener una ubicación central para controlar las posibles condiciones de carrera (race conditions). En la HAL de Gecko, esto se realiza por medio de la implementación de una sandbox de la HAL. Esta sandbox simplemente funciona como un proxy para la peticiones realizadas por los procesos de contenido y las reenvía al proceso del "servidor Gecko". Las peticiones de proxy se envían empleando IPDL.

    Para la vibración, la función Vibrate() se encarga de la gestión y se la implementa en hal/sandbox/SandboxHal.cpp:

    void Vibrate(const nsTArray<uint32_t>& pattern, const WindowIdentifier &id) {
      AutoInfallibleTArray<uint32_t, 8=""> p(pattern);
    
      WindowIdentifier newID(id);
      newID.AppendProcessID();
      Hal()->SendVibrate(p, newID.AsArray(), GetTabChildFrom(newID.GetWindow()));
    }</uint32_t,></uint32_t>

    Esto envía un mensaje definido por la interfaz PHal, descripta por IPDL en hal/sandbox/PHal.ipdl. El método se describe aproximadamente de la siguiente manera:

    Vibrate(uint32_t[] pattern);

    El receptor de este mensaje es la  HalParent::RecvVibrate() method in hal/sandbox/SandboxHal.cpp, la que se ve así:

    virtual bool RecvVibrate(const InfallibleTArray<unsigned int="">& pattern,
                const InfallibleTArray<uint64_t> &id,
                PBrowserParent *browserParent) MOZ_OVERRIDE {
    
      hal::Vibrate(pattern, newID);
      return true;
    }</uint64_t></unsigned>

    Así se omiten algunos detalles que no son relevantes a este punto sin embargo demuestra cómo el mensaje progresa de un proceso de contenido a través de Gecko hasta Gonk, luego a la implementación de la HAL de Gonk Vibrate(), y finalmente al controlador de vibración.

    DOM APIs

    DOM interfaces are, in essence, how web content communicates with Gecko. There's more involved than that, and if you're interested in added details, you can read about the DOM. DOM interfaces are defined using IDL, which comprises both a foreign function interface (FFI) and object model (OM) between JavaScript and C++.

    The vibration API is exposed to web content through an IDL interface, which is provided in nsIDOMNavigator.idl:

    [implicit_jscontext] void mozVibrate(in jsval aPattern);

    The jsval argument indicates that mozVibrate() (which is our vendor-prefixed implementation of this non-finalized vibration specification) accepts as input any JavaScript value. The IDL compiler, xpidl, generates a C++ interface that's then implemented by the Navigator class in Navigator.cpp.

    NS_IMETHODIMP Navigator::MozVibrate(const jsval& aPattern, JSContext* cx) {
      // ...
      hal::Vibrate(pattern);
      return NS_OK;
    }

    There's a lot more code in this method than what you see here, but it's not important for the purposes of this discussion. The point is that the call to hal::Vibrate() transfers control from the DOM to the Gecko HAL. From there, we enter the HAL implementation discussed in the previous section and work our way down toward the driver. On top of that, the DOM implementation doesn't care at all what platform it's running on (Gonk, Windows, OS X, or anything else). It also doesn't care whether the code is running in a content process or in the Gecko server process. Those details are all left to lower levels of the system to deal with.

    The vibration API is a very simple API, which makes it a good example. The SMS API is an example of a more complex API which uses its own "remoting" layer connecting content processes to the server.

    Radio Interface Layer (RIL)

    The RIL was mentioned in the section The userspace process architecture. This section will examine how the various pieces of this layer interact in a bit more detail.

    The main components involved in the RIL are:

    rild
    The daemon that talks to the proprietary modem firmware.
    rilproxy
    The daemon that proxies messages between rild and Gecko (which is implemented in the b2g process). This overcomes the permission problem that arises when trying to talk to rild directly, since rild can only be communicated with from within the radio group.
    b2g
    This process, also known as the chrome process, implements Gecko. The portions of it that relate to the Radio Interface Layer are dom/system/gonk/ril_worker.js, which implements a worker thread that talks to rild through rilproxy and implements the radio state machine; and the nsIRadioInterfaceLayer interface, which is the main thread's XPCOM service that acts primarily as a message exchange between the ril_worker.js thread and various other Gecko components, including the Gecko content process.
    Gecko's content process
    Within Gecko's content process, the nsIRILContentHelper interface provides an XPCOM service that lets code implementing parts of the DOM, such as the Telephony and SMS APIs talk to the radio interface, which is in the chrome process.

    Example: Communicating from rild to the DOM

    Let's take a look at an example of how the lower level parts of the system communicate with DOM code. When the modem receives an incoming call, it notifies rild using a proprietary mechanism. rild then prepares a message for its client according to the "open" protocol, which is described in ril.h. In the case of an incoming call, a RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED message is generated and sent by rild to rilproxy.

    rilproxy, implemented in rilproxy.c, receives this message in its main loop, which polls its connection to rild using code like this:

    ret = read(rilproxy_rw, data, 1024);
    
    if(ret > 0) {
      writeToSocket(rild_rw, data, ret);
    }

    Once the message is received from rild, it's then forwarded along to Gecko on the socket that connects rilproxy to Gecko. Gecko receives the forwarded message on its IPC thread:

    int ret = read(fd, mIncoming->Data, 1024);
    // ... handle errors ...
    mIncoming->mSize = ret;
    sConsumer->MessageReceived(mIncoming.forget());
    

    The consumer of these messages is SystemWorkerManager, which repackages the messages and dispatches them to the ril_worker.js thread that implements the RIL state machine; this is done in the RILReceiver::MessageReceived() method:

    virtual void MessageReceived(RilRawData *aMessage) {
      nsRefPtr<dispatchrilevent> dre(new DispatchRILEvent(aMessage));
      mDispatcher->PostTask(dre);
    }</dispatchrilevent>

    The task posted to that thread in turn calls the onRILMessage() function, which is implemented in JavaScript. This is done using the JavaScript API function JS_CallFunctionName():

    return JS_CallFunctionName(aCx, obj, "onRILMessage", NS_ARRAY_LENGTH(argv),
                               argv, argv);

    onRILMessage() is implemented in dom/system/gonk/ril_worker.js, which processes the message bytes and chops them into parcels. Each complete parcel is then dispatched to individual handler methods as appropriate:

    handleParcel: function handleParcel(request_type, length) {
      let method = this[request_type];
      if (typeof method == "function") {
        if (DEBUG) debug("Handling parcel as " + method.name);
        method.call(this, length);
      }
    }
    

    This code works by getting the request type from the object, making sure it's defined as a function in the JavaScript code, then calling the method. Since ril_worker.js implements each request type in a method given the same name as the request type, this is very simple.

    In our example, RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED, the following handler is called:

    RIL[UNSOLICITED_RESPONSE_CALL_STATE_CHANGED] = function UNSOLICITED_RESPONSE_CALL_STATE_CHANGED() {
      this.getCurrentCalls();
    };

    As you see in the code above, when notification is received that the call state has changed, the state machine simply fetches the current call state by calling the getCurrentCall() method:

    getCurrentCalls: function getCurrentCalls() {
      Buf.simpleRequest(REQUEST_GET_CURRENT_CALLS);
    }

    This sends a request back to rild to request the state of all currently active calls. The request flows back along a similar path the RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED message followed, but in the opposite direction (that is, from ril_worker.js to SystemWorkerManager to Ril.cpp, then rilproxy and finally to the rild socket). rild then responds in kind, back along the same path, eventually arriving in ril_worker.js's handler for the REQUEST_GET_CURRENT_CALLS message. And thus bidirectional communication occurs.

    The call state is then processed and compared to the previous state; if there's a change of state, ril_worker.js notifies the nsIRadioInterfaceLayer service on the main thread:

    _handleChangedCallState: function _handleChangedCallState(changedCall) {
      let message = {type: "callStateChange",
                     call: changedCall};
      this.sendDOMMessage(message);
    }

    nsIRadioInterfaceLayer is implemented in dom/system/gonk/RadioInterfaceLayer.js; the message is received by its onmessage() method:

     onmessage: function onmessage(event) {
       let message = event.data;
       debug("Received message from worker: " + JSON.stringify(message));
       switch (message.type) {
         case "callStateChange":
           // This one will handle its own notifications.
           this.handleCallStateChange(message.call);
           break;
       ...
    

    All this really does is dispatch the message to the content process using the Parent Process Message Manager (PPMM):

    handleCallStateChange: function handleCallStateChange(call) {
      [some internal state updating]
      ppmm.sendAsyncMessage("RIL:CallStateChanged", call);
    }

    In the content process, the message is received by receiveMessage() method in the nsIRILContentHelper service, from the Child Process Message Manager (CPMM):

    receiveMessage: function receiveMessage(msg) {
      let request;
      debug("Received message '" + msg.name + "': " + JSON.stringify(msg.json));
      switch (msg.name) {
        case "RIL:CallStateChanged":
          this._deliverTelephonyCallback("callStateChanged",
                                         [msg.json.callIndex, msg.json.state,
                                         msg.json.number, msg.json.isActive]);
          break;

    This, in turn, calls the nsIRILTelephonyCallback.callStateChanged() methods on every registered telephony callback object. Every web application that accesses the window.navigator.mozTelephony API has registered one such callback object that dispatches events to the JavaScript code in the web application, either as a state change of an existing call object or a new incoming call event.

    NS_IMETHODIMP Telephony::CallStateChanged(PRUint32 aCallIndex, PRUint16 aCallState,
                                              const nsAString& aNumber, bool aIsActive) {
      [...]
    
      if (modifiedCall) {
        // Change state.
        modifiedCall->ChangeState(aCallState);
    
        // See if this should replace our current active call.
        if (aIsActive) {
          mActiveCall = modifiedCall;
        }
    
        return NS_OK;
      }
    
      nsRefPtr<telephonycall> call =
              TelephonyCall::Create(this, aNumber, aCallState, aCallIndex);
      nsRefPtr<callevent> event = CallEvent::Create(call);
      nsresult rv = event->Dispatch(ToIDOMEventTarget(), NS_LITERAL_STRING("incoming"));
      NS_ENSURE_SUCCESS(rv, rv);
      return NS_OK;
    }</callevent></telephonycall>

    Applications can receive these events and update their user interface and so forth:

    handleEvent: function fm_handleEvent(evt) {
      switch (evt.call.state) {
        case 'connected':
          this.connected();
          break;
        case 'disconnected':
          this.disconnected();
          break;
        default:
          break;
      }
    }

    Take a look at the implementation of handleEvent() in the Dialer application as an extended example.

    3G data

    There is a RIL message that initiates a "data call" to the cellular service; this enables data transfer mode in the modem. This data call ends up creating and activating a Point-to-Point Protocol (PPP) interface device in the Linux kernel that can be configured using the usual interfaces.

    Note: This section needs to be written.

    This section lists DOM APIs that are related to RIL communications:

    WiFi

    The WiFi backend for Firefox OS simply uses wpa_supplicant to do most of the work. That means that the backend's primary job is to simply manage the supplicant, and to do some auxiliary tasks such as loading the WiFi driver and enabling or disabling the network interface. In essence, this means that the backend is a state machine, with the states following the state of the supplicant.

    Note: Much of the interesting stuff that happens in WiFi depends deeply on possible state changes in the wpa_supplicant process.

    The implementation of the WiFi component is broken up into two files:

    dom/wifi/DOMWifiManager.js
    Implements the API that's exposed to web content, as defined in nsIWifi.idl.
    dom/wifi/WifiWorker.js
    Implements the state machine and the code that drives the supplicant.

    These two files communicate with one another using the message manager. The backend listens for messages requesting certain actions, such as "associate", and responds with a message when the requested action has been completed.

    The DOM side listens for the response methods as well as several event messages that indicate state changes and information updates.

    Note: Any synchromous DOM APIs are implemented by caching data on that side of the pipe. Synchronous messages are avoided whenever possible.

    WifiWorker.js

    This file implements the main logic behind the WiFi interface. It runs in the chrome process (in multi-process builds) and is instantiated by the SystemWorkerManager. The file is generally broken into two sections: a giant anonymous function and WifiWorker (and its prototype). The anonymous function ends up being the WifiManager by providing a local API, including notifications for events such as connection to the supplicant and scan results being available. In general, it contains little logic and lets its sole consumer control its actions while it simply responds with the requested information and controls the details of the connection with the supplicant.

    The WifiWorker object sits between the WifiManager and the DOM. It reacts to events and forwards them to the DOM; in turn, it receives requests from the DOM and performs the appropriate actions on the supplicant. It also maintains state information about the supplicant and what it needs to do next.

    DOMWifiManager.js

    This implements the DOM API, transmitting messages back and forth between callers and the actual WiFi worker. There's very little logic involved.

    Note: In order to avoid synchronous messages to the chrome process, the WiFi Manager does need to cache the state based on the received event.

    There's a single synchronous message, which is sent at the time the DOM API is instantiated, in order to get the current state of the supplicant.

    DHCP

    DHCP and DNS are handled by dhcpcd, the standard Linux DHCP client. However, it's not able to react when the network connection is lost. Because of this, Firefox OS kills and restarts dhcpcd each time it connects to a given wireless network.

    dhcpcd is also responsible for setting the default route; we call into the network manager to tell the kernel about DNS servers.

    Network Manager

    The Network Manager configures network interfaces opened by the 3G data and WiFi components.

    Note: This needs to be written.

    Processes and threads

    Firefox OS uses POSIX threads to implement all application threads, this includes the main thread of each application as well as Web workers and helper threads. Nice values are used prioritize process and thread execution thus relying on the standard Linux kernel scheduler. Depending on the status of a process we assign it a different nice level. We've currently got 7 levels:

    Process priority levels
    Priority Nice Used for
    MASTER 0 main b2g process
    FOREGROUND_HIGH 0 critical applications holding the cpu or highpriority wakelock, this is currently reserved for the clock and communications applications
    FOREGROUND 1 foreground applications
    FOREGROUND_KEYBOARD 1 keyboard application
    BACKGROUND_PERCEIVABLE 7 background applications playing audio or holding the holding the cpu or highpriority wakelock and having at least a system message handler registered
    BACKGROUND_HOMESCREEN 18 homescreen application
    BACKGROUND 18 all other applications running in the background

    Some levels share the same nice values, that's because those levels currently differ in the way they're treated by the out of memory killer. All priorities can be adjusted at build time via preferences; the relevant entries can be found in the b2g/app/b2g.js file.

    Note: for more information on the out-of-memory killer, and how Firefox OS manages low memory situations, read Out of memory management on Firefox OS.

    Within a process the main thread inherits the nice value of the process whilst web worker threads are given a nice value that is one point higher than the main thread thus running at lower priority. This is done in order to prevent CPU-intensive workers from excessively slowing down the main thread. Processes priorities are changed whenever a major event happens such as an application is sent into the background or foreground, a new application is started up or an existing application grabs a CPU wakelock. Whenever a process priority is adjusted all its threads' priorities will also be adjusted accordingly.

    Note: cgroups are not currently used for resource management as they've proven unreliable on certain devices and kernels.

     

    Etiquetas y colaboradores del documento

    Contributors to this page: Tribamell, palfrei, cortega, pablocubico, ZeroBlazer, ccarruitero, maedca
    Última actualización por: palfrei,
    Ocultar la barra lateral