mozilla
Vos résultats de recherche

    Architecture de Firefox OS

    Cette traduction est en cours.

    Cet article est une vue d'ensemble de l'architecture de la plateforme Firefox OS, présentant les concepts-clés et expliquant sommairement comment les composants interagissent.

    Note: Gardez à l'esprit que Firefox OS est toujours un produit non finalisé ("Pre-release"). L'architecture décrite ici n'est pas forcément finalisée, et des changements peuvent survenir.

    Terminologie Firefox OS

    Voici quelques termes à connaître avant de lire la suite de notre documentation de Firefox OS.

    B2G
    Acronyme de Boot to Gecko.
    Boot to Gecko
    Le nom de code du système d'exploitation Firefox OS lors de sa conception. Vous trouverez souvent ce terme en référence à Firefox OS, car il a été longtemps utilisé avant que le projet ait un nom officiel.
    Firefox OS
    Firefox OS correspond aux services de support et de branding de Mozilla (et ceux de ses partenaires OEM) ajoutés au-dessus de Boot to Gecko, pour créer un produit fini.
    Gaia
    L'interface utilisateur de la plateforme Firefox OS. Tout ce qui est affiché à l'écran une fois que Firefox OS est lancé, est produit par la couche Gaia. Gaia implémente l'écran de verrouillage, l'écran d'accueil et toutes les applications standard que vous attendez sur un smartphone moderne. Gaia est implémenté entièrement à l'aide de HTML, CSS et Javascript. Les seules interfaces avec le système d'exploitation sous-jacent se font au travers d'API Web libres, elles-mêmes implémentées par la couche Gecko. Les applications tierces peuvent être installées en parallèle de la couche Gaia.
    Gecko
    C'est l'application permettant d'exécuter Firefox OS ; c'est-à-dire, la couche permettant le support des trois standards : HTML, CSS et Javascript. Il assure que chacune de ces technologies fonctionnent sur tous les systèmes d'exploitation supportés par Gecko. Cela signifie que Gecko inclut, entre autres, une pile réseau, une pile graphique, un moteur de présensation, une machine virtuelle JavaScript et des couches de portage.
    Gonk
    Gonk représente la couche la plus basse du système d'exploitation de la plateforme Firefox OS. Elle est composée d'un noyau Linux (basé sur l'Android Open Source Project (AOSP)) et une couche d'abstraction matérielle de l'espace utilisateur (HAL userspace). Le noyau et plusieurs bibliotèques en espace utilisateur font partie de projets open-source communs : Linux, libusb, bluez, et bien d'autres. D'autres parties de la HAL sont partagées avec l'AOSP : GPS, camera et d'autres. Vous pouvez considérer Gonk comme une distribution Linux basique. Gonk est une cible de portage de Gecko, il y a un port de Gecko vers Gonk, tout comme il y a un port de Gecko vers OS X, Windows et Android. Vu que le projet Firefox OS a un contrôle total sur Gonk, nous pouvons exposer des objets à Gecko, qui ne peuvent être exposés sur d'autres systèmes d'exploitation. Par exemple, Gecko a un accès direct à la pile téléphonique complète et à l'affichage frame buffer sur Gonk, mais n'a pas ce type d'accès sur les autres systèmes d'exploitation.
    Jank
    Ce terme est souvent utilisé dans l'univers du mobile, pour désigner une opération qui crée un effet de latence dans une application, qui bloque le rafraichissement de l'interface, la fait laguer ou la rend inutilisable. Nos ingénieurs Gaia utilisent des techniques d'optimisation variées pour essayer d'éradiquer cette sensation à tout prix.

    Architecture générale

    Le schéma suivant compare les architectures de plateformes propriétaires et de Firefox OS.

    on the left is a native mobile architecture stack, on the right is the Firefox OS architecture. they are similarm except that the native stack is all proprietary device functionality, and the Firefox OS stack is all done with open source and web technologies.

    Firefox OS élimine la couche native de l'API entre le système d'exploitation et les couches applicatives. Ce design intégré réduit les couches au-dessus de la plateforme et simplifie la sécurité sans sacrifier les performances ni l'expérience utilisateur.

    1. Gaia est le noyau d'application web de l'appareil, et la couche de l'interface utilisateur, en HMTL5, CSS et JavaScript, avec un certain nombre d'API exposées pour permettre le code de l'interface utilisateur d'interagir avec le matériel du téléphone et de fonctionnalité de Gecko.
    2. Gecko est le moteur Web et la couche de présentation dans Firefox OS qui relie le matériel avec le HTML, en se servant de l'interface entre le contenu Web et le périphérique sous-jacent. Gecko fournit une analyse HTML5 et  un moteur de rendu, l'accès programmatique à la fonctionnalité du matériel via des APIs Web sécurisés, une infrastructure de sécurité intelligente, la gestion de mise à jour, et d'autres services de base.
    3. Gonk est la composante au niveau du noyau dans la pile de Firefox OS qui sert d'interface entre Gecko et le matériel sous-jacent. Gonk contrôle le matériel sous-jacent et expose les capacités matérielles aux API Web mis en œuvre dans Gecko. Gonk peut être considérée comme la «boîte noire» qui fait tout le travail complexe et détaillée dans les coulisses pour contrôler l'appareil mobile en adoptant la demande au niveau du matériel.
    4. Le dispositif mobile est le matériel du téléphone fonctionnant avec Firefox OS. L'OEM est responsable de fournir l'appareil mobile.

     

    L'architecture spécifique de Firefox OS

    Firefox OS Architecture

    Déroulement du chargement de Firefox OS

    Cette section décrit le processus suivi lors de l'amorçage d'un matériel sous Firefox OS, quelles parties sont impliquées, et où. Pour visualiser rapidement, le schéma d'amorçage général du système passe par le chargeur de boot dans l'espace noyau, à l'init du code natif, au B2G puis au tour de Gecko dans l'espace utilisateur, pour terminer par le système d'applications, le gestionnaire de fenêtres, et enfin l'application d'accueil de Gecko. Toutes les autres applications vont venir s'appuyer là-dessus.

    Le processus d'amorçage

    Quand un appareil Firefox OS est allumé, l'exécution commence dans le premier chargeur d'amorçage. A partir de là, le processus de chargement du système d'exploitation principal se déroule d'une manière commune : une succession de chargeurs d'amorçage de niveaux de plus en plus hauts amorcent le chargeur suivant de la chaine. A la fin du processus, l'exécution est transférée au noyau Linux.

    Il y a plusieurs points à souligner à propos du processus d'amorçage :

    • Les chargeurs d'amorçage affichent souvent le premier écran d'accueil visualisé par l'utilisateur pendant le démarrage de l'appareil : habituellement c'est un logo marchand.
    • Les chargeurs d'amorçage implémentent la projection d'une image sur l'appareil. Des appareils différents utilisent des protocoles différents ; la plupart des téléphones utilisent le protocole fastboot, mais le Samsung Galaxy S II utilise le protocole odin.
    • Vers la fin du processus d'amorçage, l'image du modem est la plupart du temps chargée et s'exécute sur le processeur du modem. La façon dont cela se produit est très spécifique à l'appareil et peut être propriétaire.

    Le noyau Linux

    Le(s) noyau(x) Linux utilisés par Gonk est très similaire au upstream Linux duquel il dérive (basé sur un projet Android Open Source). Il y a quelques changements réalisés par l'AOSP qui n'ont pas encore été upstreamed. De plus, les marchands modifient parfois le noyau et upstream ces changements dans leur propre programme. En général, cependant, le noyau Linux et proche du stock.

    Le processus de démarrage pour Linux est bien documenté ailleurs sur Internet, cet article ne couvrira donc pas ce point.

    Le noyau Linux Kernel va soulever des appareils et exécuter des processus essentiels. Il va exécuter des processus définis dans init.rc et le successeur init.b2g.rc pour amorcer les processus essentiels comme b2g (le processus de base de FirefoxOS, qui contient Gecko) et rild (les processus relatifs à la téléphonie qui peuvent être propriétaires par différents jeux de puces) — voir ci-dessous pour plus de détails. A la fin du processus, un processus d'espace utilisateur init est lancé, comme dans la plupart des systèmes d'exploitation similaires à UNIX.

    Dès que le processus init est lancé, le noyau Linux gère les appels système de l'espace utilisateur, et interrompt, et ainsi de suite les dispositifs matériels. Beaucoup de fonctions matérielles sont exposées à l'espace utilisateur au travers de sysfs. Par exemples, voici un bout de code qui lit l'état de la batterie dans 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);
    }

    En savoir plus sur le processus init

    Le processus init dans Gonk gère le montage des fichiers système requis et engendre les services système. Après, il reste autour pour servir de gestionnaire de processus. Ceci est assez similaire au init des autres systèmes d'exploitation ressemblant à UNIX. Il interprète des scripts (c'est-à-dire, les fichiers init*.rc) qui consistent en des commandes décrivant ce qui devrait être réalisé pour démarrer des services. Le init.rc de Firefox OS est habituellement le stock init.rc d'Android pour l'appareil patché pour inclure les éléments nécessaires à la relance de Firefox OS. Il varie toutefois selon les appareils.

    Une tâche clé que gère le processus init est le démarrage du processus b2g ; c'est le coeur du système d'exploitation Firefox OS.

    Le code de init.rc qui démarre ceci ressemble à :

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

    Note : Savoir exactement à quel point init.rc diffère de la version Android varie selon les appareils ; parfois, init.b2g.rc est simplement ajouté, et parfois les patchs sont plus significatifs.

    L'architecture des processus de l'espace utilisateur

    A présent, il est utile d'avoir un regard plus haut niveau sur la manière dont les composants multiples de Firefox OS s'imbriquent et interagissent entre eux. Le diagramme montre le principal processus de l'espace utilisateur de Firefox OS.

    Userspace diagram

    Note : Gardez à l'esprit que depuis que Firefox OS est développé activement, le diagramme est susceptible de changer et pourrait ne pas être complètement exact.

    Le processus b2g est le principal processus système. Il s'exécute avec de hauts privilèges ; il a accès à la plupart des matériels de l'appareil. b2g communique avec le modem, dessine le framebuffer affiché, et échange avec les GPS, appareil photo et autres fonctions matérielles. De manière interne, b2g exécute la couche Gecko (implémentée par libxul.so). Voir Gecko pour plus de détails sur la manière dont fonctionne la couche Gecko, et comment b2g communique avec elle.

    b2g

    Le processus b2g peut à son tour déclencher un certain nombre de processus content à faibles privilèges. Ces processus sont l'endroit où les applications web et autres contenus web sont chargés. Ces processus communiquent avec le processus serveur principal Gecko avec le protocole IPDL, un système de transmission de messages.

    Le processus b2g exécute libxul, qui référence b2g/app/b2g.js pour obtenir les préférences par défaut. Avec ces préférences, il va ouvrir le ficher HTML b2g/chrome/content/shell.html, qui est complié dans le fichier omni.ja.. shell.html inclut le fichier b2g/chrome/content/shell.js, qui déclenche l'application system de Gaia.

    rild

    Le processus rild est l'interface du processeur du modem. rild est le démon qui implémente la couche de l'interface radio  (Radio Interface Layer ou RIL). C'est un morceau de code propriétaire qui est implémenté par le fournisseur de matériel pour échanger avec le modem matériel. rild permet au code client de se connecter avec un socket UNIX auquel il se lie. Il commence par le code suivant dans le script d'init :

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

    rilproxy

    Dans Firefox OS, le client rild est le processus rilproxy. Il agit comme un simple proxy de tranfert d'information entre rild et b2g. Ce proxy est nécessaire comme un détail d'implémentation ; il suffit de dire qu'il est en effet nécessaire. Le code rilproxy est accessible sur GitHub.

    mediaserver

    Le processus mediaserver contrôle la lecture de l'audio et de la vidéo. Gecko échange avec lui à travers un mécanisme Android de Remote Procedure Call (RPC). Une partie des média que Gecko peut lire (OGG Vorbis audio, OGG Theora video, et WebM video) sont décodés par Gecko et envoyé directement au processus mediaserver. Les autres fichiers média sont décodés par libstagefright, qui est capable d'accéder aux codecs propriétaires et aux encodeurs matériels.

    Note : Le processus mediaserver est un composant "temporaire" de Firefox OS ; il est là pour aider dans notre travail initial de développement, mais est prévu qu'il disparaisse éventuellement. Toutefois, cela ne devrait pas se produire avant au moins la version 2.0 de Firefox OS.

    netd

    Le processus netd est utilisé pour configurer les interfaces réseau.

    wpa_supplicant

    Le processus wpa_supplicant est le démon UNIX-style standard qui gère la connectivité avec les points d'accès WiFi.

    dbus-daemon

    Le processus dbus-daemon implémente D-Bus, un système de bus de messages que Firefox OS utilise pour la communication Bluetooth.

    Gecko

    Gecko, comme mentionné précédemment, est une exécution de standards web (HTML, CSS, et JavaScript) qui est utilisé pour implémenter tout ce que voit l'utilisateur dans Firefox OS, et contrôler les interactions avec le matériel du téléphone. Les applications Web connectent le HTML5 au matériel via des APIs Web contrôlées et sécurisées, implémentées dans Gecko. L'API Web fournit un accès informatisé aux fonctionnalités présentes dans le matériel sous-jascent de l'appareil mobile (comme la batterie ou la vibration),  ainsi que les données stockées sur, ou disponibles pour un périphérique (comme le calendrier ou les contacts). Le contenu Web appelle l'API Web accessible depuis HTML5.

    Une applicaiton consiste en une collection de contenu web connexe HTML5. Pour construire des applications web qui s'exécutent sur des périphériques mobiles Firefox OS, les développeurs simplement assemblent, emballent et distribuent ce contenu web. Lors de l'exécution, ce contenu web est interprété, compilté et rendu dans un navigateur web. Pour plus d'informations sur les applications, voir le App Center.

    Note : Pour rechercher la base de code Gecko, vous pouvez utiliser http://dxr.mozilla.org. C'est plus "fancy" et cela fournit de bonnes fonctionnalités de référence, mais avec des répertoires limités. Ou vous pouvez essayer le traditionnel http://mxr.mozilla.org, qui regroupe plus de projets de Mozilla.

    Diagramme d'architecture Gecko

    • Framework de sécurité : contient
      • Permission manager : porte d'entrée pour accéder à la fonctionnalité de l'API Web.
      • Access control list : matrice des rôles et permissions requises pour accéder à la fonctionnalité de l'API Web.
      • Credential validation : Authentification des applications/utilisateurs.
      • Permissions Store : Ensemble des privilèges requis pour accéder à la fonctionnalité de l'APIWeb.
    • Web API : Ensemble d'APIs standards qui exposent les fonctionnalités matérielles au contenu web. Founit des applications wab avec des accès sécurisés aux fonctions contenus dans le matériel de l'appareil mobile sous-jascent, avec les données stockées sur - ou disponibles pour - l'appareil.
    • I/O : Interface vers le matériel et le(s) magasin(s) de données.
    • Software Updates : Obtiennent et installent les mises à jour sur le logiciel système et les applications tierces.
    • Content Layout & Rendering : Moteur qui parse, interprète, et exécute le contenu web et, avec de l'information formatée, affiche le contenu formaté à l'utilisateur.
    • b2g process : (Gecko) exécute un processus système à hauts-privilèges qui a accès aux fonctions matérielles du téléphone. Les applications en cours d'exécution sont des processus fils de b2g.

    Fichiers Gecko en rapport avec Firefox OS

    b2g/

    Le dossier b2g contient la plupart des fonctions en lien avec Firefox OS.

    b2g/chrome/content

    Contient les fichiers Javascript exécutés sur l'application système.

    b2g/chrome/content/shell.html

    Le point d'entrée dans Gaia — le HTML pour l'application système shell.html arrive dans settings.js et shell.js:

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

    settings.js contient les paramètres par défaut de réglages du système.

    b2g/chrome/content/shell.js

    shell.js est le premier script à charger dans l'application system de Gaia.

    shell.js importe tous les modules requis, enregistre les écouteurs de touches, définit sendCustomEvent et sendChromeEvent pour communiquer avec Gaia, et fournit des aides d'installation des webapps : qutoa indexedDB, RemoteDebugger, clavier auxiliaire, et outil d'impression écran.

    Mais la fonction la plus importante de shell.js est de lancer l'application system de Gaia, puis remettre l'ensemble du travail de gestion des systèmes à l'application system de Gaia.

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

    Le script contient des paramètres prédéfinis, comme about:config dans un navigateur, et identique à pref.js de Gaia. Ces paramètres peuvent être modifiés depuis l'application Paramètres, et peuvent être écrasés avec user.js dans le script de compilation de Gaia.

    dom/{API}

    Des nouvelles implementations de l'API  (post-b2g)  seront placées dans  dom/.  Des API plus vieilles seront placées dans  dom/base,  par exemple  Navigator.cpp.

    dom/apps

    .jsm  sera chargé —  les implementations de l'API .js  comme  webapp.js  install, getSelf, etc.

    dom/apps/src/

    Toutes les autorisations sont définies dans PermissionsTable.jsm

    dom/webidl

    WebIDL est le langage utilisé pour definir les APIs web. Pour les attributs supportés, lisez WebIDL_bindings.

    hal/gonk

    Ce répertoire contient les fichiers liés à la couche de port gonk.

    Les fichiers Générés

    module/libpref/src/init/all.js

    Contient tous les fichiers de configuration.

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

    Contient le pack de styles pour les ressources de l'appareil.

    Traitement des Evénements d'entrée

    La plupart des actions à l'intérieur de Gecko sont déclenchées par les actions de l'utilisateur. Ces actions sont représentées par des événements d'entrée (tels que les pressions de bouton, touches à un appareil à écran tactile, et ainsi de suite). Ces événements entrent dans le Gecko par la source Implementation de de l'interface nsIAppShell, une interface de Gecko qui est utilisée pour représenter les points principaux d'entrée pour une application de Gecko; c'est-à-dire le pilote du dispositif d'entrée appelle des méthodes sur l'objet nsAppShell qui représente le sous-système de Gecko pour envoyer des événements à l'interface utilisateur.

    Par exemple :

    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();
    }

    Ces événements viennent du système standard input_event de Linux. Firefox OS utilise une couche d'abstraction légère, celle-ci offre quelques fonctionnalités intéressantes comme le filtrage des événements. Vous pouvez voir le code qui crée des événements d'entrée dans la méthode EventHub::getEvents() dans widget/gonk/libui/EventHub.cpp.

    Une fois que les événements sont reçus par Gecko, ils sont expédiés dans le DOM par 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);
    }
    

    Après cela, les événements sont soit consommés par Gecko lui-même ou sont expédiés à des applications Web en tant que événements DOM pour un traitement ultérieur.

    Graphisme

    Au niveau le plus bas, Gecko utilise OpenGL ES 2.0 pour dessiner un contexte GL qui enveloppe les tampon de trame de matériel. Cela se fait dans l'implementation Gonk de nsWindow par un code similaire à ceci :

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

    La class FramebufferNativeWindow est apportée directement d'Android; voir FramebufferNativeWindow.cpp. Cette dernière utilise l'API gralloc API pour accéder au pilote graphique dans l'optique de représenter les tampons du dispositif de framebuffer dans la mémoire.

    Gecko utilise son système de Couches au contenu composite élaboré  à l'écran. En résumé, voici ce qui se passe :

    1. Gecko dessine des régions distinctes de pages dans des tampons de mémoire. Parfois, ces tampons sont dans la mémoire système; d'autres fois, elles sont des textures mappées dans l'espace d'adresse de Gecko,ce qui signifie que Gecko dessine directement dans la mémoire vidéo. Cela se fait habituellement dans la méthode BasicThebesLayer::PaintThebes().
    2. Gecko regroupe alors toutes ces textures à l'écran utilisant des commandes OpenGL. Cette composition se produit dans ThebesLayerOGL::RenderTo().

    Les détails de la façon dont Gecko gère le rendu du contenu web hors du cadre de ce document.

    Couche d'Abstraction Matérielle (HAL )

    La couche d'abstraction matérielle Gecko est l'une des couches de portage de Gecko. Il gère l'accès de bas niveau aux interfaces du système à travers de multiples plates-formes utilisant une API C++ qui est accessible aux plus hauts niveaux de Gecko. Ces API sont mises en œuvre  sur une base par-plate-forme à l'intérieur du Gecko HAL(Hardware Abstraction Layer) lui-même. Cette couche d'abstraction de matériel n'est pas exposée directement au code JavaScript dans le Gecko ---  cette partie de l'interaction est assurée par les API Web.

    Regardons le processus au haut niveau. Quand un utilisateur effectue une demande d'utiliser une fonction de téléphone (comme composer un numéro, l'accès à un réseau wifi local, ou la connexion via Bluetooth), toutes les couches de la pile de technologie Firefox OS sont impliqués dans la réalisation de la demande. Les applications et le contenu web dans la couche Gaia soumet des demandes d'accès à l'appareil sous-jacente via des appels d'API Web (appelée à partir de l'intérieur de fonctions HTML5), qui sont mis en œuvre dans Gecko. Gecko à son tour soumet la demande à Link. Une seule demande de Gecko peut déclencher une série complexe d'opérations, lancés et gérés par Gonk, dans le téléphone mobile.

    Comment fonctionne le HAL

    Prenons l'API Vibration comme un exemple. Le Gecko HAL pour cette API est définie dans hal/Hal.h. En substance (simplification de la signature de la méthode pour des raisons de clarté), vous avez cette fonction :

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

    Ceci est la fonction appelée par le code Gecko pour activer le dispositif de vibration en fonction de la configuration spécifiée; une fonction correspondante existe pour annuler toute vibration continue. La mise en oeuvre de ce procédé Gonk se trouve dans hal/gonk/GonkHal.cpp:

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

    Ce code envoie la demande pour faire vibrer le dispositif à un autre fil d'execution, qui est mis en œuvre dans  VibratorRunnable::Run(). La boucle principale de ce fil ressemble à ceci :

    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() est l'API Gonk HAL (couche d'abstraction matérielle) qui tourne sur le moteur vibrant. En interne, cette méthode envoie un message au pilote du noyau en écrivant une valeur à un objet de noyau utilisant  sysfs.

    Alternatives aux implémentations de l'API HAL

    Les APIs HAL Gecko  sont pris en charge sur toutes les plateformes. Quand Gecko est compilé pour une plate-forme qui ne dispose pas d'une interface de moteurs vibrants (comme un ordinateur de bureau), alors une alternative à l'implémentation de l'API HAL est utilisé. Pour les vibrations, cela est mis en œuvre dans hal/fallback/FallbackVibration.cpp.

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

    Implémentations Sandbox

    Parce que la plupart des contenus web fonctionne dans les processus de contenu avec des privilèges faibles, nous ne pouvons pas assumer que ces processus ont les privilèges nécessaires pour être en mesure de (par exemple), allumer et éteindre le moteur de vibration. De plus, nous voulons avoir un emplacement central pour le traitement des conditions de course potentiels. Dans le Gecko HAL, cela se fait à travers une mise en œuvre «sandbox» de la HAL. Cette mise en œuvre sandbox proxie simplement des demandes formulées par des procédés de contenu et les transmet au processus du "serveur Gecko". Les demandes de proxy sont envoyés en utilisant IPDL.

    For vibration, this is handled by the Vibrate() function implemented in 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()));
    }

    This sends a message defined by the PHal interface, described by IPDL in hal/sandbox/PHal.ipdl. This method is described more or less as follows:

    Vibrate(uint32_t[] pattern);

    The receiver of this message is the HalParent::RecvVibrate() method in hal/sandbox/SandboxHal.cpp, which looks like this:

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

    This omits some details that aren't relevant to this discussion; however, it shows how the message progresses from a content process through Gecko to Gonk, then to the Gonk HAL implementation of Vibrate(), and eventually to the Vibration driver.

    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 graphics 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);
    }

    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;
    }

    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 applications holding a CPU wakelock
    FOREGROUND 1 foreground applications
    FOREGROUND_KEYBOARD 1 keyboard application
    BACKGROUND_PERCEIVABLE 7 background applications playing audio
    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.

    Étiquettes et contributeurs liés au document

    Étiquettes : 
    Dernière mise à jour par : jp.jeaphil,
    Masquer la barre latérale