Wednesday, January 22, 2014

Editing files from omni.ja in Firefox 20 onwards

This post focuses on Ubuntu, however when I get time I will update it with instructions for Windows.

So I've been working on a small side project recently and I found that editing the live code on Firefox is not as easy as it used to be. I had to do a fair amount of digging (and sifting out of outdated information) to get all the information on how to modify omni.ja files from live Firefox installs, so I'll just collect what I learned in this post.

Firefox is a browser written in C/C++, JavaScript, CSS, and XML. The C++ bits are compiled (by a very lengthy build process), but the Javascript is simply zipped up and loaded at runtime. There are binary versions of the JS files (which probably load faster), but these are not necessary.

Previously, the JS was uncompressed and just lying around in directories, and one could simply edit these files to change some functionality. While the core APIs are in C, most of the behavior of the Firefox UI is in JS/XML and thus a lot of tweaking can be done through these files. Of course, making an addon may be a viable option, but you may not always want to do that.

However to improve performance the files were gradually bundled in jars, finally resulting in the monstrosity known as omni.ja. This is a rather quirky jar file that contains the JS and JS "binaries".

Fortunately, the files in this jar can still be edited, with some more effort.

Firstly, let me note that on Ubuntu, there are two  omni.jas. The first in in /usr/lib/firefox, and the second is in /usr/lib/firefox/browser. These contain different code, so you may have to find out which one holds your JS.

Extracting the files from omni.ja is pretty simple. Copy omni.ja to a temporary directory, and run unzip omni.ja on it. (sudo apt-get install unzip may be necessary. Alternatively, use Ubuntu's Archive manager after renaming it to a .zip)

If you wish to modify a file from omni.ja, be sure that you delete its corresponding binary in the jsloader/resources/gre subtree or under the jssubloader tree. Then modify the javascript file as usual.

Try to keep a backup of the old omni.ja just in case, syntax errors may stop Firefox from loading.

To repack, you have to run zip -qr9XD omni.ja * in the same temporary directory. Be sure to delete the old omni.ja file before zipping, otherwise you may end up with a nested omni.ja. While I was playing with the file, after an initial smooth period where everything worked, I started getting segfaults even when simply unpacking, repacking, and loading omni.ja because I was neglecting to delete the old omni.ja, which created a jar that was nested in around 25 levels, which was too large for Firefox.

Now copy the new omni.ja from the temporary directory to where you got it from. Give everyone read permissions (chmod a+r /usr/lib/firefox)

This still does not ensure that the new jar file will be loaded. What you need to do to force this reload is open Firefox, disable or enable an addon (this only works if the addon is one that requires restart after being disabled or enabled — if this is the case you will be prompted to restart), and restart Firefox from the prompt. Other ways to do this (credit: Neil Rashbrook)

  • Use the --purgecaches command line parameter
  • Set the MOZ_PURGE_CACHES environment variable to 1
  • Use the .purgecaches file

Once you force reload omni.ja, Firefox should run on your new code.