As described in an earlier blog post we’re using Firefox OS as the OS for Gonzo, our wireless camera. The big advantage is the great set of built-in APIs that we can use to leverage functionality around dialing/SMS/camera/power management. However there are a couple of things we missed from the platform.
Because the way Firefox OS is architectured all user code, like the actual code that powers Gonzo, runs in a web context. That means that the code is isolated in a sandbox and we cannot execute code outside of the sandbox or outside our privilege level. For IoT or embedded purposes that is actually quite a shame, as all the functionality that you want to use needs to be built into Gecko (the JS engine that powers Firefox & Firefox OS). For normal developers this is actually great. If I want to monitor the value of the proximity sensor it is a lot easier to write:
Rather than reading the file descriptor (or whatever, it’s device specific) that the driver for the proximity sensor opened for you. For instance, the raw reading of the proximity sensor on the Geeksphone Keon is some 200 lines of C++.
- Read and write to the GPIO pins
Disclaimer: there is a very good reason that websites cannot read arbitrary files or execute processes on your computer. But hey, it’s an embedded device that will only run your own code, and we’re all hackers here, so that’s OK.
Adding a readFile function to Gecko
First of all, make sure you have a clone of mozilla-central, and you are able to build and execute it by running
./mach build && ./mach run.
The module we’re going to build will be called OS (for Operating System, indeed) and we are going to expose it under
navigator.mozOs. You can later drop the prefix if your idea made it through W3C. The first step we need to take is define a WebIDL for the module. This is an interface file, which is also supported for other browsers, describing the API of your module. In Firefox these interfaces live in ‘dom/webidl’. In this folder, create a new file:
This file describes has three important parts:
- We want this API to be exposed through the navigator object. We can define this from the interface, and we don’t need add any additional code.
- The actual interface. We only have a single function that takes in a String, and returns a Promise. We’ll assume all files we read through this API will be human readable.
To make sure this file is picked up during build, go into
dom/webidl/moz.build and add the following line between
os and fill it with the following three files:
@mozilla.org/b2g-os;1 contract from the os.webidl file.
Helps the build system determine which files to build. Please make sure this is in alphabetical order or the build process will abort!
The last step to make is to add the new
os folder to the
/dom build script. Open
dom/moz.build and add in between of
If history thaught us anything, your code will probably break at some point. Follow the steps at MDN to enable the debugger for code that is embedded within Firefox.
Building it all…
./mach build to build a new Firefox that includes your changes. If everything goes well you should see the familiar message:
0:43.48 Your build was successful! To view resource usage of the build, run |mach resource-usage|. To take your build for a test drive, run: |mach run|
./mach run and open a normal web page. Open the console and type (replace with your own home dir of course):
And you’ll get your bash_history file visible in your console window!
My .bash_history file exposed through a normal Firefox console window.
You only need to do
./mach build when your interface changes. When you make changes to
MozOs.js you don’t need a rebuild.
Adding it to Firefox OS
When you flash this change to your Firefox OS device (by building B2G), you will presented with an error when you want to use it along the lines of
[Exception... "Factory not registered". You will need to add the files in your module to the B2G build script to fix this. Add the following lines to
Now you can use the API in Firefox OS as well.
Firefox (OS) is very extensible and when you have full control over the device, it allows you to override the default sandbox quite easily. Of course this comes with a security, so limit it to using it on an embedded platform that you control. Bad idea to browse the web with these changes.