Join MDN and developers like you at Mozilla's View Source conference, 12-14 September in Berlin, Germany. Learn more at https://viewsourceconf.org

Cet article nécessite une relecture technique. Voici comment vous pouvez aider.

Cet article nécessite une relecture rédactionnelle. Voici comment vous pouvez aider.

Cet article est une vue d'ensemble de l'architecture de la plate-forme 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 plate-forme 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 standards 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ésentation, 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 plate-forme 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 bibliothè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, caméra 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 rafraîchissement 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 plate-formes 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 plate-forme 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é comme la «boîte noire» qui fait tout le travail complexe et détaillé 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 chaîne. 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 noyau Linux utilisé 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 et cet article ne couvrira donc pas ce point.

Le noyau Linux (ou 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 exemple, 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 cœur 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é; parfois les patchs sont plus significatifs.

L'architecture des processus de l'espace utilisateur

A présent, il est utile d'avoir un regard de plus haut niveau sur la manière dont les composants multiples de Firefox OS s'imbriquent et interagissent entre eux. Le diagramme ci-dessous 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, l'appareil photo et d'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 compilé 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 transfert 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édias que Gecko peut lire (OGG Vorbis audio, OGG Theora video, et WebM video) est décodée par Gecko et envoyée 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 nous aider dans notre travail initial de développement. Cependant, il 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 Wi-Fi.

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). Il est utilisé pour implémenter tout ce que voit l'utilisateur dans Firefox OS et pour 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-jacent 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 application consiste en une collection de contenus web connexes HTML5. Pour construire des applications web qui s'exécutent sur des périphériques mobiles Firefox OS, les développeurs assemblent, emballent et distribuent simplement ce contenu web. Lors de l'exécution, ce contenu web est interprété, compilé 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 des 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. Fournit des applications web avec des accès sécurisés aux fonctions contenues dans le matériel de l'appareil mobile sous-jacent, 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 passe, 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 : quota 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 implémentations 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 définir 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 Évé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 qu' é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 tampons de trame de matériel. Cela se fait dans l'implémentation 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 sur la façon dont Gecko gère le rendu du contenu web sortent 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 plate-formes utilisant une API C++ qui est accessible aux plus hauts niveaux de Gecko. Ces API sont mises en œuvre selon la 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 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 pour utiliser une fonction du téléphone (comme composer un numéro, accéder à un réseau Wi-Fi local, ou se connecter via Bluetooth), toutes les couches de la pile de technologie Firefox OS sont impliquées dans la réalisation de la demande. Les applications et le contenu web dans la couche Gaia soumettent des demandes d'accès à l'appareil sous-jacent via des appels d'API Web (appelées à 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ées et gérées par Gonk, dans le téléphone mobile.

Comment fonctionne le HAL

Prenons l'API Vibration comme exemple. Le Gecko HAL pour cette API est défini 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 œuvre 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'exécution, 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 prises en charge sur toutes les plate-formes. 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ée. 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, par exemple, d'allumer et éteindre le moteur de vibration. De plus, nous voulons avoir un emplacement central pour le traitement des conditions de course potentielles. 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.

Pour les vibrations, cela est géré par la fonction Vibrate() implémenté dans  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()));
}

Cela envoie un message défini par l'interface PHal, décrit par IPDL dans hal/sandbox/PHal.ipdl. Cette méthode est décrite plus ou moins comme suit :

Vibrate(uint32_t[] pattern);

Le destinataire de ce message est la méthode HalParent::RecvVibrate() dans hal/sandbox/SandboxHal.cpp, qui ressemble à ceci :

virtual bool RecvVibrate(const InfallibleTArray<unsigned int>& pattern,
            const InfallibleTArray<uint64_t> &id,
            PBrowserParent *browserParent) MOZ_OVERRIDE {

  hal::Vibrate(pattern, newID);
  return true;
}

Ceci omet certains détails qui ne sont pas appropriés à cette documentation; Cependant, il montre comment le message progresse d'un contenu de processus de Gecko à Gonk, puis à la mise en œuvre du HAL de Gonk Vibrate() et finalement au pilote de vibration.

Les API DOM

Les interfaces du DOM sont, en substance, comment le contenu Web communique avec Gecko. Ils sont plus impliqués que cela et si vous êtes intéressés par des détails supplémentaires, vous pouvez lire la documentation sur le DOM. Les interfaces du DOM sont définies en utilisant IDL, qui comprend aussi bien l'interface de fonction étrangère (FFI) que le modèle d'objet (OM) entre le JavaScript et C++.

L'API de vibration est exposée au contenu web à travers une interface IDL, qui est prévue dans nsIDOMNavigator.idl:

[implicit_jscontext] void mozVibrate(in jsval aPattern);

L'argument jsval indique que mozVibrate() (qui est notre implémentation du fournisseur préfixée de cette spécification de vibrations non-finalisé) accepte en entrée toute valeur JavaScript. Le compilateur IDL, xpidl, génère une interface C++ qui est ensuite mise en œuvre par la classe   Navigator  dans Navigator.cpp.

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

Il y a beaucoup plus de code dans cette méthode que ce que vous voyez ici, mais ce n'est pas important pour le but de cette documentation. Le fait est que l'appel à hal::Vibrate() le contrôle de transferts du DOM au HAL de Gecko. De là, nous entrons dans la mise en œuvre du HAL discutée dans la section précédente et nous frayons un chemin vers le pilote graphique. Par-dessus tout, la mise en œuvre du DOM ne se soucie pas du tout sur quelle plate-forme il est exécuté (Gonk, Windows, OS X, ou autre chose). Il ne se soucie pas non-plus si le code fonctionne dans un processus de contenu ou dans le processus serveur de Gecko. Ces détails sont tous laissés à des niveaux inférieurs du système à traiter.

L'API de vibration est une API très simple, ce qui en fait un bon exemple. L'API SMS est un exemple d'une API plus complexe qui utilise sa propre couche "d'accès distant" reliant les processus de contenu au serveur.

Couche d'Interface Radio (RIL)

La Couche d'Interface Radio, ou RIL pour Radio Interface Layer en Anglais a été mentionnée dans la section L'architecture des processus de l'espace utilisateur . Cette section examinera un peu plus de détail la manière dont les différents éléments de cette couche interagissent.

Les principaux composants impliqués dans la RIL sont :

rild
Chargé de communiquer avec le firmware modem propriétaire.
rilproxy
Qui proxie les messages entre rild et Gecko (lequel est mis en œuvre dans le processus de b2g). Ceci résout le problème d'autorisation qui se pose lorsque vous essayez de parler à rild directement, lorsque rild ne peut être communiquée à l'intérieur du groupe de radio.
b2g

Ce processus, également connu comme le procédé chrome, implémente Gecko. Les parties de celui-ci qui se rapportent à la couche d'interface radio sont dom/system/gonk/ril_worker.js qui mettent en œuvre un thread (fil) de travail qui communique avec  rild par le biais de rilproxy et implémentent la machine d'état de la radio; et l'  nsIRadioInterfaceLayer interface, qui est le service principal XPCOM du thread qui agit principalement comme un échange de messages entre le thread ril_worker.js et divers autres composants Gecko, y compris le processus contenu Gecko.

Processus du contenu de Gecko

Au sein du processus du contenu de Gecko, l' nsIRILContentHelper interface fournit un service de XPCOM qui laisse le code mettant en œuvre les parties de DOM, comme la Téléphonie et les APIs de SMS, communiquer avec l'interface de la radio, qui est dans le processus chrome., communiquer avec l'interface de la radio, qui est dans le processus chrome.

Exemple: Communication du rild au DOM

Jetons un œil à un exemple de la façon dont les parties de niveau inférieur du système communiquent avec le code DOM. Lorsque le modem reçoit un appel entrant, il notifie au rild en utilisant un mécanisme propriétaire. rild prépare alors un message pour son client selon le protocole «ouvert», qui est décrit dans ril.h. Dans le cas d'un appel entrant, un message RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED est généré et envoyé par rild à rilproxy.

rilproxy, implémenté dans le  rilproxy.c, reçoit ce message dans sa boucle principale, qui sonde sa connexion à rild en utilisant le code suivant :

ret = read(rilproxy_rw, data, 1024);

if(ret > 0) {
  writeToSocket(rild_rw, data, ret);
}

Une fois le message reçu de rild, il est ensuite expédié le long de Gecko sur la prise qui relie rilproxy Gecko. Gecko reçoit le message transmis sur son IPC thread:

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

Le consommateur de ces messages est SystemWorkerManager, qui reconditionne les messages et les envoie au ril_worker.js thread qui implémente la machine d'état RIL; ceci est fait dans la méthode  RILReceiver::MessageReceived() :

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

La tâche postée à ce thread appelle à son tour la fonction onRILMessage(), qui est implémentée en JavaScript. Ceci est fait en utilisant la fonction API JavaScript JS_CallFunctionName():

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

onRILMessage() est mis en œuvre dans dom/system/gonk/ril_worker.js, qui traite le message octets et les découpe en parcelles. Chaque colis complet est ensuite envoyé à des méthodes de gestionnaire individuelles, le cas échéant:

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

Ce code fonctionne en récupérant le type de demande de l'objet, en s'assurant qu'il soit défini comme une fonction dans le code JavaScript, appelant ensuite la méthode. Depuis ril_worker.js met en œuvre chaque type de demande dans une méthode donnée, le même nom que le type de demande, ce qui est très simple.

Dans notre exemple, RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED, le code suivant est appelé:

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

Comme vous pouvez le voir dans le code ci-dessus, quand une notification est reçue indiquant que le call state a changé, la state machine récupère le call state courant en appelant la méthode getCurrentCall():

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

Cela envoie une request back à rild pour demander l'état de tous les appels actifs à l'instant. 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. Et la communication ainsi bidirectionnelle arrive.

Le call state est alors traité et comparé au précédent état; S'il y a un changement d'état,  ril_worker.js notifie le service nsIRadioInterfaceLayer sur le thread principal:

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

nsIRadioInterfaceLayer est implémenté dans dom/system/gonk/RadioInterfaceLayer.js; le message est reçu par la méthode onmessage():

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

Tout ce qu'il fait est d'expédier le message pour le processus de contenu en utilisant le Parent Process Message Manager (PPMM):

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

Dans le processus de contenu, le message est reçu par la méthode receiveMessage() dans le service nsIRILContentHelper , depuis le 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;

Ce dernier, à son tour, appelle les méthodes nsIRILTelephonyCallback.callStateChanged() sur chaque objet telephony callback enregistré. Chaque application web qui accède à l'API window.navigator.mozTelephony a enregistré un tel objet callback que propage les événements au code JavaScript dans l'application web, either as un changement d'état d'un objet appel existant ou un nouvel événement appel entrant.

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

Les applications peuvent recevoir ces évenements et mettre à jour leur interface utilisateur etc:

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

Jetez un coup d'œil à la mise en œuvre de handleEvent(), dans l'application de demande de de composeur de numéro comme exemple étendu

3G data

Il y a un message RIL qui amorce(introduit) "un appel de données" au service cellulaire; ceci permet le mode de transfert de données dans le modem. Cet appel de données finit par créer et activer un Point-to-Point Protocol (PPP) le dispositif d'interface dans le noyau Linux qui peut être configuré utilisant les interfaces habituelles.

Note: Cette section doit être écrite.

API de DOM liées

Cette section inscrit les API de DOM qui sont relatées(liées) aux communications RIL :

  • API de téléphonie
  • API de SMS
  • API de connexion mobile

Wi-Fi

L'arrière-plan Wi-Fi pour Firefox OS utilise simplement wpa_supplicant pour faire la plupart du travail. Cela signifie que le travail principal de l'arrière-plan doit simplement gérer le suppliant et faire quelques tâches auxiliaires comme le chargement du conducteur Wi-Fi et de la permission ou la mise hors de service de l'interface de réseau. En substance, cela signifie que l'arrière-plan est une machine d'état, avec les états après l'état du suppliant.

Note: Une grande partie du truc(de la substance) intéressant qui arrive dans le Wi-Fi dépend profondément de changements possibles d'état du processus de wpa_supplicant.

La mise en œuvre du composant Wi-Fi est cassée dans deux fichiers:

dom/wifi/DOMWifiManager.js
Met en œuvre l'API qui s'est exposée au contenu Web, comme défini dans nsIWifi.idl.
dom/wifi/WifiWorker.js
Met en œuvre la machine d'état et le code qui conduit le suppliant.

Ces deux fichiers(dossiers) communiquent entre eux par l'utilisation du manager de message. L'arrière-plan écoute pour des messages demandant certaines actions, comme "l'associé" et répond par un message quand l'action demandée a été achevée.

Le côté de DOM écoute pour les méthodes de réponse aussi bien que plusieurs messages d'événement qui indiquent des changements d'état et des mises à jour de l'information.

Note: N'importe quelle API de DOM synchrones est mise en œuvre par des données mises en antémémoire sur ce côté de la conduite. Des messages synchrones sont évités quand c'est possible.

WifiWorker.js

Ce fichier met en œuvre la logique principale derrière l'interface Wi-Fi. Il fonctionne dans le processus chromé (dans le multi-processus construit) et est instancié par le SystemWorkerManager. Le fichier est généralement cassé dans deux sections : une fonction anonyme géante et WifiWorker (et son prototype). La fonction anonyme finit étant le WifiManager en fournissant une API locale, y compris des notifications pour des événements comme la connexion au suppliant et les résultats de feuilletage étant disponibles. En général, il contient peu de logique et laisse son consommateur unique contrôler ses actions tandis qu'il répond simplement par les informations demandées et contrôle les détails du rapport(de la connexion) avec le suppliant.

L'objet de WifiWorker est assis entre le WifiManager et le DOM. Il réagit aux événements et les transfert à DOM; à son tour, il reçoit des requêtes de DOM et exécute les actions appropriées sur le suppliant. Il maintient aussi des informations d'état sur le suppliant et ce qu'il doit faire ensuite.

DOMWifiManager.js

Cela met en œuvre l'API de DOM, transmettant des messages dans les deux sens entre des interlocuteurs et le travailleur Wi-Fi réel. Il y a très peu de logique impliquée.

Note: Pour éviter des messages synchrones au processus chromé, le Manager Wi-Fi a vraiment besoin du cache de l'état basé sur l'événement reçu.

Il y a un message synchrone seul, qui est envoyé à temps à l'API DOM est instanciée, pour obtenir l'état actuel du suppliant.

DHCP

DHCP et DNS sont traités par dhcpcd, la norme Linux DHCP le client. Cependant, il ne peut pas réagir quand la connexion de réseau est perdue. À cause de ceci, Firefox OS tue et reprend dhcpcd chaque fois il connecte à un réseau sans fil donné.

Dhcpcd est aussi responsable de mettre le parcours par défaut; nous appelons dans le gestionnaire de réseau pour parler au noyau de serveurs DNS.

Gestionnaire de réseau

Le Gestionnaire de réseau configure des interfaces de réseau ouvertes par le 3G des données et des composants Wi-Fi.

Note: Cela doit être écrit.

Processus et threads

Firefox OS utilise des threads POSIX pour mettre en œuvre tous les threads d'application, ceci inclut le fil conducteur de chaque travailleur d'application aussi bien que Web et des threads d'aide. Des valeurs agréables sont utilisées priorisent au processus et l'exécution de thread comptant ainsi sur le planificateur de noyau Linux standard. Selon le statut d'un processus nous l'assignons un niveau agréable et différent. Nous avons actuellement 7 niveaux :

Traitez des niveaux prioritaires
Priorité Nice Utilité
MASTER 0 Processus de b2g principal
FOREGROUND_HIGH 0 Applications tenant une UC wakelock
FOREGROUND 1 Applications de premier plan
FOREGROUND_KEYBOARD 1 Application de clavier
BACKGROUND_PERCEIVABLE 7 Applications de fond jouant audio
BACKGROUND_HOMESCREEN 18 Application d'écran d'accueil
BACKGROUND 18 Toutes les autres applications fonctionnant en arrière-plan

Quelques niveaux partagent les mêmes valeurs agréables, c'est que ces niveaux diffèrent actuellement dans la façon qu'ils sont traités par le tueur de mémoire insuffisante. Toutes les priorités peuvent être ajustées à construisent le temps via des préférences; les entrées pertinentes peuvent être trouvées dans le fichier de b2g/app/b2g.js.

Note: Pour plus d'informations sur le tueur de mémoire insuffisante et comment Firefox OS gère des situations de mémoire basses, lire Mémoire insuffisante la gestion sur Firefox OS.

Dans un processus le thread conducteur hérite la valeur agréable du processus tandis que l'on donne aux fils de travailleur Web une valeur agréable qui est un point plus haut que le thread conducteur fonctionnant ainsi à la priorité inférieure. Ceci est fait pour empêcher des travailleurs intensifs de l'UC d'excessivement ralentir le thread conducteur. Les priorités de processus sont changées quand un événement majeur arrive comme une demande est envoyée dans le contexte ou le premier plan, une nouvelle demande est mise en marche ou une application existante saisit une UC wakelock. Quand une priorité de processus est ajustée, les priorités de tous ses fils seront aussi ajustées en conséquence.

Note: Ces groupes ne sont pas actuellement utilisés pour la gestion de ressource comme ils ont prouvé incertains sur certains dispositifs et des noyaux.

Étiquettes et contributeurs liés au document

Étiquettes : 
 Dernière mise à jour par : jwhitlock,