Mossop Status Update: 2010-03-26

Done:

  • Met with dveditz from the security team and talked over potential issues with the current plans.
  • Addressed review comments
  • Started on reviews for the UI
  • Fixed many remaining issues
  • Re-prioritized a couple of items

Next:

  • Finish addressing review comments
  • Finish reviewing UI
  • Finish fixing everything that needs to be fixed
  • Trunk landing

How we’re breaking some extensions in the near future

You may have read some reports about how we’re re-implementing the bulk of the extension manager in Firefox. It’s been a long running project (something like a year since I first really started planning how to do it). Things are finally started to come together and all being well we are likely to look at landing the first pieces of this on the trunk nightlies in as little as a weeks time. I’ll be up front, this isn’t going to be a perfect landing. There may be some thing that are missing and other bits where the user experience isn’t as perfect as it will be finally. Of course there may also be bugs we have to rush to fix. Despite all this we feel that we’re about at the point where exposing it to the hands of thousands of nightly testers is the best way forward. Your eyes spot things that we miss, even things that may seem obvious to you and you’re vital to us getting these sorts of features polished and really just how they should be before they get released to the world at large in a Firefox release.

One thing I wanted to mention is how this will affect the extensions themselves. In many cases as you might hope there will be no change at all, the extensions will continue to work as they did on previous trunk builds. Those that do anything to the add-ons manager UI will see obvious problems since that UI has changed considerably. There is also a set of extensions that are likely to see issues because of API changes. This is pretty much normal for any feature but I thought I’d mention two common uses that extension developers are going to have to change in their code.

Accessing file and version information for extensions

The extension manager interface as it used to exist is gone with the new code. Some extensions would have used this to access their extension’s version and packaged files. There is a replacement so it mostly just means changing code to something similar to this:

Components.utils.import("resource://gre/modules/AddonManager.jsm");

AddonManager.getAddonByID("my-addon@foo.com", function(addon) {
  alert("My extension's version is " + addon.version);
  alert("Did I remember to include that file.txt file in my XPI? " +
        addon.hasResource("file.txt") ? "YES!" : "No :(");
  alert("Let's pretend I did, it's available from the URL " + addon.getResourceURL("file.txt"));
});

Hopefully to developers who used the old APIs this will look a lot nicer than it used to, I certainly prefer it. There are a couple of things to note. The old API would give you an nsIFile directly to play with. The new API gives you a URL. It is currently possible to get an nsIFile from this (as it is a file:// url), however in the future we may be no longer extracting the files out of an XPI for an extension so it is worth trying to just use the URL where you can. We might add a simple method for getting say an input stream to the files as well.

The second thing to note is that this API is asynchronous. As performance becomes more and more of an issue for the platform we have to start moving APIs to be asynchronous to allow file accesses to happen on background threads leaving the UI responsive while we wait for data. In most cases this probably won’t cause developers much of a problem, unfortunately it is difficult to make this appear to operate synchronously safely. People may know the trick of spinning an event loop while you wait for data, that is kind of unsafe since it can allow unexpected reeentrancy into code that isn’t anticipating it.

This change to an asynchronous API brings up the other main change that I am sad to have to make but cannot see a way around.

FUEL has to change

FUEL was designed to be a simple stable wrapper around the nitty gritty world of parts of XPCOM and XUL. It has I believed served fairly well in that purpose though in retrospect there are some things it might have been nice to have different about it. The problem right now though is that FUEL has wrappers around the old extension manager and they are synchronous. They simply cannot stay and work with the new extension manage, which means we have to change a part of the FUEL API slightly. This is unfortunate but I’ve tried to make the change as low impact as possible, there is in fact just a single change. Previously to get an add-ons version you might have done:

alert(Application.extensions.get("my-addon@foo.com").version);

Now you will have to do:

Application.getExtensions(function(extensions) {
  alert(extensions.get("my-addon@foo.com").version);
});

Again it switches from synchronous to asynchronous, but that is really the only change here. The extensions object passed into the callback function is basically the same as the current Application.extensions object, only a slight difference in that it is a snapshot of the list of extensions at the time of retrieval. That doesn’t make a great deal of difference for normal extensions as they cannot install or uninstall without a restart but it may have an effect if you are looking at the new restartless add-ons, in which case you can just get a new copy of the extensions object.

Mossop Status Update: 2010-03-19

Done:

Serious amounts of progress on the extension manager rewrite work this week

  • Restartless extensions implemented
  • Personas and basic plugin and search engine supported added
  • Silent background updating implemented
  • Updated the API docs to be accurate
  • Filed bugs on all known remaining issues
  • Worked out a rough schedule for trunk landing
  • Submitted the main part of the backend and API to Rob Strong for code review
  • Blogged about how this impacts extension developers

Next:

  • Fix up the remaining issues, all currently known are small or straightforward
  • Have an informal meeting with the security team to talk about potential issues
  • Fix any issues that come up from the reviews
  • Reviewing the UI side of the rewrite

Look Ma, no restarts!

An extension installed without restarting Firefox

This is a screenshot of some of my latest (and most exciting) work on my project to rewrite the extension manager. I’ve just implemented support for a special kind of extension that can install (and uninstall, and enable, disable, upgrade and anything else you can think of) without the user needing to restart Firefox. This is of course to allow add-ons developed on the Jetpack platform to install without restarts but the feature is going to be available to any extension author, there are just some restrictions to how these extensions work.

The precise spec for this isn’t final yet so I’m not going to show you precise examples but the basics are that unlike normal extensions the platform won’t load anything from the restart-less extensions except for one file. This simple JavaScript file will be called when the extension is loaded or unloaded allowing the extension to either set itself up or tear every trace of it out of the app. This may seem limited but there is actually very few things that an extension can’t do from this (and hopefully we’ll get those fixed), it just involves more manual work. Maybe we’ll simplify some of that in the future, but for now it’ll be pretty raw and ready for use. Of course the Jetpack platform basically does all the loading and unloading work for you…

Simplifying

The big project that I have been working on for quite some time now is a complete change to the architecture of the add-ons manager backend. It’s a big scary prospect since (IMHO) the code is pretty crucial to the success of Firefox and many other Mozilla based applications. Without extensions I don’t think we’d be where we are today, in fact it was because of extensions that I got involved in the project in the first place.

The current incarnation of the extension manager has served us well over the past years but for some time it has been under strain. There are always more features we want to add but certain aspects of its design make it hard to do that. Things like changing from an RDF based persistent storage to anything else are hard because the concepts are so ingrained in the code. It’s now at the point where changing anything (particularly in the startup code) is very difficult since unexpected side effects are almost sure to happen. I tried various approaches to slowly iterating the current code to something better but ultimately changing anything required changing everything so I finally bit the bullet and concluded that a rewrite was the way forward (I know, normally they aren’t the right choice but I’m, pretty confident that it is in this case).

It is that rewrite that I’ve been working on on and off for something like half a year, if not longer. Some of the nice benefits that we should see:

  • Switching from RDF to a SQLite storage model (and making it easier to switch in the future)
  • Startup and other performance improvements (probably not immediately though)
  • Less bothersome dialogs for the user
  • Vastly simpler APIs for application/extension developers including:
    • Proper separation of the backend and UI code
    • Support for pluggable add-on types

I didn’t actually mean for this post to be this long actually (after all it is about simplification), it was just this last point that I felt like demonstrating. I just wrote the basic part of the code that implements the automatic daily background update checks. It uses the new API that will be available and as well as checking for updates it also downloads and installs any it finds silently (currently, I’ll be adding the notification and controls etc. soon). It struck me just how simple it was to write this:

AddonManager.getAddonsByType(null, function(addons) {
  addons.forEach(function(addon) {
    if (addon.permissions & AddonManager.PERM_CANUPGRADE) {
      addon.findUpdates({
        onUpdateAvailable: function(addon, install) {
          install.install();
        }
      }, AddonManager.UPDATE_WHEN_PERIODIC_UPDATE);
    }
  });
});

That is some 11 lines of code to perform an update check to the add-on’s update server, retrieve information about the newest available update and start downloading and installing it.

Mossop Status Update: 2010-03-12

Done:

  • Wired up installs and blocked installs from webpages
  • Converted the xpinstall test suite to work with the new APIs
  • Started preparing the project branch for performance testing

Next:

  • Finish support for extensions that don't need restarts
  • Personas and plugins support
  • Background auto-updates
  • Convert the old EM test suite to the new APIs
  • Make sure the API docs are in sync with the code
  • Make a list of things not yet implemented for QA
  • Put together a plan for a trunk landing

Improving do_execute_soon for xpcshell tests

It struck me the other day just how much of a pain debugging asynchronous xpcshell tests is. Frequently you just see the test timeout because some code you are working on has thrown an exception, but the test harness can’t detect that and end the test, or even log the exception. Well it can now for do_execute_soon at least. I’ve landed bug 550481 which catches and logs any exceptions in the callback passed to do_execute_soon. As an added bonus I also removed the need to use do_test_pending/complete when purely using do_execute_soon, the harness does it automatically. There is no harm in you doing it yourself too though.

Mossop Status Update: 2010-03-05

Done:

  • Firefox team shenanigans
  • True async reads for the add-ons manager
  • Compatibility overrides and compatibility updates
  • Figured out how to integrate webpage triggered installs

Next:

  • Webpage installs
  • Personas and plugins support

Coordination:

Need to see if releng can get the project branch set up this week