How many hacks does it take to make your extension install without a restart? · 2010-09-10 15:50 by Wladimir Palant
Dave Townsend did some really great work on the add-on manager recently, he managed to completely rewrite the old crappy backend code and replace it with something far more sane. Along the way a new feature was added: starting with Firefox 4 some add-ons should be able to opt-in and install/uninstall without requiring a browser restart. This feature was primarily meant for JetPack-built extensions but is generally open to all other extensions as well. I tried enabling this feature for Adblock Plus and found that there is an awful number of catches attached to it. I wrote these down, might save somebody else’s time:
registerFactory()the required number of times.
- Catch 2: You are responsible for shutting down any code you are running. If your extension is uninstalled or disabled you will be notified, the rest (unregistering components, removing observers and cleaning out any other traces your extension left in the application) is up to you. Solution: write more code, test carefully.
Components.utils.import()will not work because modules are cached by canonical file name rather then their URL. Solution: adapt your build scripts to ensure that the modules directory gets a different name for each build.
- Catch 4: No default preferences (bug 564675). Solution: do not use default preferences. Just assume that any preference value might be missing and fall back to a hardcoded default value then.
- Catch 5: You cannot use the chrome:// protocol for your extension because your chrome.manifest will be ignored. And there isn’t a way to add new chrome “domains” dynamically either (bug 564667). Which makes opening custom dialogs rather hard, in particular XUL can now only be used if its source is associated with the system principal. Solution: create your own protocol similar to chrome:// and make sure to assign the system principal to all channels (luckily,
nsIScriptSecurityManager.getSystemPrincipal()became scriptable a few days ago — but you can also create an instance of the “@mozilla.org/systemprincipal;1” component).
- Catch 6: You cannot load DTD files from your custom protocol because the XML parser only accepts the chrome:// protocol. Yes, it is hardcoded and there is absolutely nothing you can do about it. Solution: modify your protocol implementation to inline any external DTD files, this will work.
- Catch 6.5 (Added: 2010-09-11): The new add-on manager (the one coming for Firefox 4, not the one in Firefox 3.6) doesn’t like non-chrome protocols all too much. Extension icons will not display at all. Options and About dialogs will open yet not as real dialogs but as pages inside a new browser window. Of course it looks ugly then and things like automatic window sizing won’t work. For this one, there are even two solutions. First: forget about it, let’s hope that users will find your extension’s preferences even without add-on manager integration. Second: find the hardcoded check for “chrome” in add-on manager code and replace it by checking URI_IS_LOCAL_RESOURCE protocol flag. Shouldn’t be too hard, might even make it into Firefox 4 still.
- Catch 7: Opening a new dialog works now but you still need to overlay the browser window somehow. Overlay definitions in chrome.manifest are ignored and manipulating the overlays table dynamically isn’t possible. Solution: register an observer with
nsIWindowWatcher.registerNotification()to get notified whenever a new window opens, use
document.loadOverlay()to apply overlays dynamically.
- Catch 8:
document.loadOverlay()will not work if a previous overlay load didn’t finish yet (bug 330458). So if a different extension also tries to apply its overlays dynamically and gets there first you are out of luck. No, you cannot detect this condition — only the one who called
document.loadOverlay()has an observer. Solution: according to the bug report there is an exception, so if that exception is thrown you can wait a little and start another attempt. Might be however that the exception is asynchronous — then you will always have to wait a little, then check whether your overlay got applied. If not — start another attempt.
- Catch 9: You won’t know when your own overlay finished loading (bug 496320). So if you have to initialize things, when are you going to do this? Solution: do not use overlays, just go there and insert the elements you need.
At this point my hack-o-meter exploded and, as you all well know, programming without a functional hack-o-meter isn’t safe. So I decided to give up on this whole idea, I probably spent too much time on it already. I’m pretty certain that there are more catches that I just didn’t find yet. And — sure, if your extension is very simple (in particular: minimal user interface) things might work out for you. After all, it works for JetPack and they only use a few of the hacks I mentioned.
Commenting is closed for this article.