B2G/Architecture

From MozillaWiki
< B2G
Revision as of 11:06, 13 February 2012 by Cgj (talk | contribs)
Jump to navigation Jump to search

This document describes at a high level how Gaia and B2G work in the port of Gecko to Gonk. If you don't know what these things are yet, don't worry, they'll be introduced below.

Gaia/B2G/Gecko are under heavy development, so some items below discuss how the code will work, instead of how it currently works. This will be noted.

Terminology

Gaia : The user interface of b2g. Everything drawn to screen after b2g starts up is some part of Gaia. Gaia implements a lock screen, home screen, telephone dialer, text-messaging application, camera app, ... and many more. Gaia is written entirely in HTML, CSS, and JavaScript. Its only interface to the underlying operating system is through Open Web APIs, which are implemented by Gecko. Gaia works well when run on top of b2g; however, since it only uses standard web APIs, it works on other OSes and in other web browsers (albeit with degraded functionality). Third-party applications can be installed alongside Gaia.

Gecko : The "application runtime" of b2g. At a high level, Gecko implements the open standards for HTML, CSS, and JS and makes those interfaces run well on all the OSes that Gecko supports. This means that Gecko consists of, among other things, a networking stack, graphics stack, layout engine, virtual machine (for JS), and porting layers.

Gonk : The lower-level "operating system" of b2g. Gonk consists of a linux kernel and userspace hardware abstraction layer (HAL). The kernel and several userspace libraries are common open-source projects: linux, libusb, bluez, etc. Some other parts of the HAL are shared with the android project: GPS, camera, among others. You could say that Gonk is an extremely simple linux distribution. Gonk is a porting target of Gecko; there is a port of Gecko to Gonk, just like there is a port of Gecko to OS X, and a port of Gecko to Android. Since the b2g project has full control over Gonk, we can expose interfaces to Gecko that aren't possible to expose on other OSes. For example, Gecko has direct access to the full telephony stack and display framebuffer on Gonk, but doesn't have this access on any other OS.

Booting

After turning on a b2g phone, execution starts in the primary bootloader. From there, the process of loading the main OS kernel happens in the usual way: a succession of higher-level bootloaders bootstrap the next loader in the chain. At the end of the process, execution is handed off to the linux kernel.

There's not a lot to say about the boot process, but there are a few things worth knowing

  • The bootloaders usually show the first "splash screen" seen during device boot, which usually displays a vendor logo.
  • The bootloaders implement flashing an image onto the device. Different devices use different protocols. Most phones use the fastboot protocol, but the Galaxy S II uses the "odin" protocol.
  • By the end of the bootstrapping process, the modem image is usually loaded and running on the modem firmware. How this happens is highly device-specific and possibly proprietary.

Kernel (Linux)

The linux kernel(s) in Gonk is reasonably close to upstream linux. There are a few modifications made by AOSP that are not in upstream yet. Vendors also modify the linux kernel and upstream those modifications on their own schedule. But in general, the linux kernel is close to stock.

The startup process for linux is well documented elsewhere on the internet, so it's not covered here. At the end of kernel startup, a userspace "init" process is launched, like in most other UNIX-like OSes. At this point in execution, only a ramdisk is mounted. The ramdisk is built during the b2g build process, and consists of critical utilities (like init), other startup scripts, and loadable kernel modules.

After launching the init process, the linux kernel services system calls from userspace and interrupts etc. from hardware devices. Many devices are exposed to userspace through sysfs (documented elsewhere on the internet). For example, here's some code that reads the battery state in Gecko (link to original code)

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

init

The init process in Gonk mounts necessary file systems, spawns system services, and acts a process manager after that. This is very similar to init on other UNIX-like OSes. init "interprets" scripts (init*.rc), that consist of commands. Here's the main init script for the Galaxy S II

Main init script for the Galaxy S II

In particular, init is responsible for launching the b2g process, described below. Here's the snippet of code that launches b2g

service b2g /system/b2g/b2g
    onrestart restart media

Userspace process architecture

At this point, it's best to step back a bit and look at how the various components of b2g fit together, at a very high level.

B2G processes

This diagram shows the main userspace processes in b2g. (NOTE: this diagram is subject to change, and not guaranteed to be 100% accurate.) The dotted lines show processes that are spawned by init. The solid lines show other communication channels.

The b2g process is the main system process. It runs with high privileges: it has access to most hardware devices. b2g communicates with the modem, draws to the display framebuffer, and talks to GPS, cameras, and other devices. Internally, b2g runs Gecko code (libxul.so). The details of how it communicates with hardware are discussed below.

The b2g process may spawn a number of low-rights "content processes". These are where web applications and other web content are loaded. These process communicate with the main Gecko server process through IPDL, a message-passing system.

The rild process is the interface to the modem processor. "RIL" is the "radio interface layer", "rild" is the "RIL daemon". It's a proprietary "blob" of code implemented by hardware vendors. rild allows a client to connect to a UNIX-domain socket it binds to.

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

In b2g, the rild client is the rilproxy process. It just acts as a dumb forwarding proxy between rild and b2g. The reason we need this proxy is an implementation detail, not important. The code lives here.

The mediaserver process controls audio and video playback. Gecko talks to it through an android RPC mechanism. The code for mediaserver lives here. Some of the media that Gecko can play (OGG Vorbis audio, OGG Theora video, and WebM video) are decoded by Gecko and sent directly to the mediaserver. Other media files are decoded by libstagefright, which is capable of accessing proprietary codecs and hardware decoders. (NOTE: B2G will not use the mediaserver process, in its current incarnation, in the long run.)

The netd process is used to configure network interfaces. wpa_supplicant is the standard UNIX-ish daemon that connects to WiFi access points. TODO: document other processes

Gecko: Processing input events

Most action inside of Gecko is triggered by input events (button presses, touch-screen touches, and so forth). Input events enter Gecko through the Gonk "app shell" (on b2g). For example

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

These input events originate from the standard linux input_event system, dispatched by input-device drivers. We use a light abstraction over that which provides some nice features like filtering of events. Here's where input events originate

            if (pfd.revents & POLLIN) {
                int32_t readSize = read(pfd.fd, mInputBufferData,
                        sizeof(struct input_event) * INPUT_BUFFER_SIZE);
                if (readSize < 0) {
                    if (errno != EAGAIN && errno != EINTR) {
                        LOGW("could not get event (errno=%d)", errno);
                    }
                } else if ((readSize % sizeof(struct input_event)) != 0) {
                    LOGE("could not get event (wrong size: %d)", readSize);
                } else {
                    mInputBufferCount = readSize / sizeof(struct input_event);
                    mInputBufferIndex = 0;
                }
            }
        }

After being read by Gecko, inputs are dispatched into the DOM from here

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

From here on, the events are either consumed by Gecko internally, or dispatched to web applications as DOM events.

Gecko: Graphics

At the very lowest level, Gecko uses OpenGL ES 2.0 to draw to a glcontext that wraps the hardware framebuffers. Gecko sets up its graphics context here

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

The FramebufferNativeWindow is implemented here. It uses the "gralloc" hardware interface to the graphics driver to map buffers from the framebuffer device.

Gecko uses its Layers system to composite drawn content to the screen. A full description of layers is beyond the scope of this document, but what approximately happens is

  • Gecko draws separate regions of pages into memory buffers. Sometimes, these buffers are system memory. Other times, they're textures mapped into Gecko's address space, meaning Gecko draws directly to VRAM. Drawing happens here, in the common case.
  • Gecko composites these textures to screen using GL commands. Composition of the pixels painted above would happen here.

The details of how Gecko actually draws web content are beyond the scope of this document.