Building B2G (FirefoxOS) for a Nexus 5

firefox_logo-wordmark-vert_RGB

So recently I’ve been working on porting B2G to a Huawei Softbank 201HW/U9201L phone. While doing so, however, I had the minor setback of bricking the phone. This is a brick in the sense that the device goes into an infinite boot loop, right after starting up — as soon as it starts up, it determines it needs to restart.

As that project might actually take a long time to complete (I’m currently at the point of trying to manufacture a ClockWorkMod-compatible image that would fix what is broken on th phone, which currently seems to be a bunch of missing symlinks), I recently bought myself a Nexus 5. The Nexus 5 is defined as a target for the B2G project, so there should be no porting involved, and the process should be straight forward. In this post I will try and detail my efforts (and hopefully ultimate success) in flashing a new, unlocked Nexus 5 with FirefoxOS.

Through out the article, I made notes in almost-real-time, so a lot of this article is me stumbling around the build process for B2G. For completeness, I’ll leave those parts in, but apply a highlight and bold the steps that actually worked.

To clear the any previous B2G work:

./build.sh clean

To generate a new configuration for the Nexus 5:

./config.sh nexus-5

In doing this however, I came across some errors syncing, and found this trace in my configure output:

Fetching projects:   2% (3/137)  Fetching project platform/external/elfutils
error: Cannot fetch platform/external/elfutils (GitError: --force-sync not enabled; cannot overwrite a local work tree. If you're comfortable with the possibility of losing the work tree's git metadata, use `repo sync --force-sync external/elfutils` to proceed.)
Fetching project platform/hardware/libhardware
Exception in thread Thread-7:
Traceback (most recent call last):
  File "/usr/lib/python2.7/threading.py", line 810, in __bootstrap_inner
    self.run()
  File "/usr/lib/python2.7/threading.py", line 763, in run
    self.__target(*self.__args, **self.__kwargs)
  File "/path/to/B2G/.repo/repo/subcmds/sync.py", line 265, in _FetchProjectList
    success = self._FetchHelper(opt, project, *args, **kwargs)
  File "/path/to/B2G/.repo/repo/subcmds/sync.py", line 308, in _FetchHelper
    optimized_fetch=opt.optimized_fetch)
  File "/path/to/B2G/.repo/repo/project.py", line 1147, in Sync_NetworkHalf
    self._InitGitDir(force_sync=force_sync)
  File "/path/to/B2G/.repo/repo/project.py", line 2171, in _InitGitDir
    raise e
GitError: --force-sync not enabled; cannot overwrite a local work tree. If you're comfortable with the possibility of losing the work tree's git metadata, use `repo sync --force-sync external/elfutils` to proceed.

I fixed this by enabling force-sync on config.sh (I actually fixed these problems one-by-one at first, then found the --force-sync switch in ./config.sh usage. In the end, my config.sh command looked like:

./config.sh --force-sync nexus-5

Despite trying to force-sync the nexus-5 repos/fetching, I forced me to start with a fresh clone of B2G

After re-cloning B2G in another folder (luckily I had ~30GB to spare), I ran into another issue. Towards the end (I think) of the process, build.sh attempts to build the system image and fails. the error looks something like this:

make_ext4fs -s -S out/target/product/hammerhead/root/file_contexts -l 1073741824 -a system out/target/product/hammerhead/obj/PACKAGING/systemimage_intermediates/system.img out/target/product/hammerhead/system
+ make_ext4fs -s -S out/target/product/hammerhead/root/file_contexts -l 1073741824 -a system out/target/product/hammerhead/obj/PACKAGING/systemimage_intermediates/system.img out/target/product/hammerhead/system
can't set android permissions - built without android support
make_ext4fs [ -l <len> ] [ -j <journal size> ] [ -b <block_size> ]
    [ -g <blocks per group> ] [ -i <inodes> ] [ -I <inode size> ]
    [ -L <label> ] [ -f ] [ -a <android mountpoint> ]
    [ -S file_contexts ]
    [ -z | -s ] [ -w ] [ -c ] [ -J ] [ -v ]
    <filename> [<directory>]
+ '[' 1 -ne 0 ']'
+ exit 4
error: failed to build out/target/product/hammerhead/obj/PACKAGING/systemimage_intermediates/system.img from out/target/product/hammerhead/system
make: *** [out/target/product/hammerhead/obj/PACKAGING/systemimage_intermediates/system.img] Error 1

The gist of the issue I encountered here seemed to be that make_ext4fs

After some searching, I came upon a XDG thread that mentions a repo which makes building make_ext4fs easier (for people who are trying to build system images). I cloned the repo, checked out the branch that corresponded to the version of Android that was currently on the phone. Thinking about it, maybe this should have been for the version of the android that B2G was building, but I imagine stock Hammerhead (which is the codename for the phone) android image was probably the same version (or not too many versions removed) anyway.

As make_ext4fs was the only binary that I wanted to override (or felt I should override), I created a folder with a symlink to the file, and added that to my PATH, then restarted build.sh.

This still failed, and that resulted in me realizing that a local version of make_ext4fs was overriding/obstructing B2G and build.sh from using it’s own. I noticed that /usr/bin was at the beginning of the PATH that mksystemimg.sh was building, and copied that PATH over to a shell, and realized that without /usr/bin, a completely different version of make_ext4fs was picked up — namely one from the out directory inside B2G.

Now, I needed to set about building a multi-locale version of FirefoxOS (since I would love to have both Japanese and English keyboards/menus on demand).

To do this, I followed the official B2G multi-locale build guide.

Essentially the steps I followed were to

  • cd gaia/locales (from B2G root)
  • Download tar.gz versions of en-US and ja translation code from Mozilla’s l10n Hg repository
  • Create the languages_own.json file, which contained on “en” and “ja” entries (basically I cut pieces out of the language_* files that were already there to minimize chance of error — don’t forget to make sure the appropriate commas are there/not there, I assume it has to be valid JSON)
  • Set ENV variables as instructed in the build guide

The guide noted the following commands to run to build gaia:

make clean && make production LOCALES_FILE=locales/languages-own.json

Unfortunately, the guide is not quite clear on where exactly to run those commands from. I assumed they were supposed to be run from inside the “gaia” folder, and tried them, though they didn’t really work. After trying this, I realized that the guide was out of date — the newest (at the time of this post) gaia l10n files were located at https://hg.mozilla.org/releases/gaia-l10n/v2_5. Download and trying to use the “ja” and “en-US” locales from this release actually lead to a discrepancy (it seems the JA translations were missing ~20 “chunks” of translation). At that point, I decided to just give up on multi-locale for now, mostly because I still wanted to tackle writing a japanese keyboard app myself. :)

It also might be the case that I just picked a bad version of the two… If I had used v2_2, which is considered stable, instead of v2_5, en-US and ja locales might have been in sync.

After giving up on multi-locale FFOS (for now), I ran build.sh (from B2G root) with the ENV still set, and this command:

VARIANT=eng MOZILLA_OFFICIAL=0 B2G_SYSTEM_APPS=1 GAIA_OPTIMIZE=1 B2G_UPDATER=1 B2G_UPDATE_CHANNEL=default MOZ_TELEMETRY_REPORTING=1 MOZ_CRASHREPORTER_NO_REPORT=1 LOCALES_FILE=locales/languages_own.json GAIA_KEYBOARD_LAYOUTS=en ./build.sh

(note that languages_own.json had to be created before this was run)

After running that, the build went off without a hitch, and gave the expected/usual output, instructing me to flash the device.

With a tiny bit of apprehension, a pinch of uncertainty, and a dash of how-many-phones-will-I-brick-this-year, I set ./flash.sh off to do it’s dirty work.

After some waiting, I was greeted by the sound of the accessibility notice in the newer FFOS version, alerting me on how to have the contents of the screen read to me (which is awesome, quite possible one of the only devices that handle accessibility issues so early on, and seem to get it right). I was also greeted with this screen:

nexus-running-ffos

Great success