Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Creating a restartless extension

22 views
Skip to first unread message

Alfonso Martínez de Lizarrondo

unread,
Aug 1, 2010, 5:06:19 AM8/1/10
to
Hi all.

I think that one of the most interesting parts for extension developers
in Firefox 4 is the ability to run our extesions without requesting a
restart of Firefox, so I guess that I'm not the only one that would like
to add that feature to his code.

The problem for me is that there's very little documentation about that.
In https://wiki.mozilla.org/Extension_Manager:Bootstrapped_Extensions we
can read the steps to declare an extension as bootstrapped, I've tested
them and it really works, so nice!

this is a copied example:

function startup(data, reason) {

Components.classes["@mozilla.org/embedcomp/prompt-service;1"].getService(Components.interfaces.nsIPromptService).alert(null,
"Bootstrapped", "Ohai!");
}

function shutdown(data, reason) {

Components.classes["@mozilla.org/embedcomp/prompt-service;1"].getService(Components.interfaces.nsIPromptService).alert(null,
"Bootstrapped", "Bye for now!");

}

Ok, now we must load the rest of our code into Firefox.

To map the resource://myextension code I've found that it can be done
this way:
old line in chrome.registry
resource myextension modules/

New code:
var ios = Cc['@mozilla.org/network/io-service;1']
.getService(Ci.nsIIOService);

function startup(data, reason) {

var installPath = data.installPath;

var modulePath = installPath.clone();
modulePath.append("modules");

var aliasFile = Cc["@mozilla.org/file/local;1"]
.createInstance(Ci.nsILocalFile);

aliasFile.initWithPath( modulePath.path );

var aliasURI = ios.newFileURI(aliasFile);

var resProt = ios.getProtocolHandler("resource")
.QueryInterface(Ci.nsIResProtocolHandler);
resProt.setSubstitution("myextension", aliasURI);

...
}

function shutdown(data, reason) {

var resProt = ios.getProtocolHandler("resource")
.QueryInterface(Ci.nsIResProtocolHandler);
resProt.setSubstitution("myextension", null);

}

/* end*/


That allows to load our js modules on request:
Components.utils.import("resource://myextension/module.js");
(note that for the moment such modules can't be unloaded on shutdown:
https://bugzilla.mozilla.org/show_bug.cgi?id=564674 )

But I'm at a lost trying to find out the rest of pieces.
I guess that the next "easy" step would be to register the chrome://
pieces, but I haven't found a sample to do it.
When the extension manager is open it shows in the error console:
No chrome package registered for chrome://myextension/skin/icon.png

So, how do I convert these two lines from chrome.manifest?
content myextension chrome/content/
skin myextension classic/1.0 chrome/skin/

Of course there are more questions after this step, but I would rather
do it little by little.

Thanks for any hint.

Nils Maier

unread,
Aug 1, 2010, 12:10:49 PM8/1/10
to
Am 01.08.2010 11:06, schrieb Alfonso Martínez de Lizarrondo:
> But I'm at a lost trying to find out the rest of pieces.
> I guess that the next "easy" step would be to register the chrome://
> pieces, but I haven't found a sample to do it.

I tried and actually you cannot do this, as you'd have to implement
nsIDirectoryServiceProvider for ChromeML allowing aggregates, what you
cannot do right now, as aggregation mode requires returning a special
success code; and you cannot return special success codes from JS for
all I know (just error codes).
This means, that while you can register your provider, you will override
all others.

Here is the code in question:
http://mxr.mozilla.org/mozilla-central/source/xpcom/io/nsDirectoryService.cpp#427

Cheers
Nils

Gijs Kruitbosch

unread,
Aug 2, 2010, 1:10:52 AM8/2/10
to

I hacked around that by just retrieving the current list and have my nsIDSP
return the concatenation of that and my own items, but I'm not sure that's
possible in this context... try and see?

~ Gijs

Nils Maier

unread,
Aug 2, 2010, 11:34:40 AM8/2/10
to

That won't work really well, as you don't drop packages once
unregistered again... think multiple extensions using this idea.

Nils

Dave Townsend

unread,
Aug 2, 2010, 11:53:25 AM8/2/10
to

Note that I'd very much like to just support loading chrome from
restartless extensions (probably restricted to the package
registrations) and then remove it afterwards. We have a bug on file to
do it (https://bugzilla.mozilla.org/show_bug.cgi?id=564667) but it
probably won't block the release which makes it hard for me to find the
time to do it. If someone had a chance to work on it then that would be
awesome.

Gijs Kruitbosch

unread,
Aug 2, 2010, 5:55:20 PM8/2/10
to Nils Maier

That assumes that multiple add-ons actually use this *and* drop the packages
*and* expect this change to be applied in the same browser session (because IIRC
you can turn caching off, and the list your nsIDSP gets is regenerated on next
startup). I don't really know why you would want to do that. As it is, there is
(or was?) no way to remove an overlay, so you couldn't really 'remove' an add-on
completely without extensive reloading of the browser chrome, etc., in which
case you might as well do a full restart.

That said, I haven't read up on Fx 4 facilities, and therefore don't fully
understand what the OP wants to achieve. What I'm saying is based on code I
wrote about a year ago, and never finished nor released, to install regular
add-ons without restarts. So you'd install one add-on (I named it
'quickinstall') and it overrode some behaviour when installing add-ons. It could
basically work even then, if not for the reason you cited above (although
obviously, if there is only one add-on taking care of this for everybody else,
we're good) and the overlays (although I never implemented anything about
loading components, both the OP and several people I questioned about it at the
time seem(ed) to believe it possible to deal with that).

Anyhow! Let me know if anyone comes up with good solutions...

Cheers,
Gijs

Nils Maier

unread,
Aug 2, 2010, 10:26:27 PM8/2/10
to


My assessment was correct at the time I tried, but things have changed.
You can now actually load full manifests and by that register any
chrome, style and so on by using
nsIComponentRegistrar.autoRegister(manifestFile)/XRE_AddManifestLocation.
Even explicit component registration works.
There is no facility yet to actually unload stuff again (which would be
required for live deactivate/uninstall). There is some unit test stuff
doing some trickery[1] to temp. register chrome, but I'm not sure if
that will work for things like overlays.
At least some kind of foundation is there, which might be used build
something sane.

There are however far too many roadblocks for porting complex addons to
be really restartless. For example:
* cannot really load styles into active windows and unload them again
(work-around would be to have all styles as inline styles attached to
any added DOM elements)
* fastload caches may interfere with new versions, I guess (wonder what
jetpack does in this regard)
* cannot fully unload components/modules (jetpack?)
* loading/unloading of default preferences
* hardcoded stuff (window icon paths, default preferences again)

Cheers
Nils

[1]
http://mxr.mozilla.org/mozilla-central/source/toolkit/content/tests/chrome/RegisterUnregisterChrome.js

johnjbarton

unread,
Aug 2, 2010, 11:39:13 PM8/2/10
to
On 8/2/2010 7:26 PM, Nils Maier wrote:
> Am 02.08.2010 23:55, schrieb Gijs Kruitbosch:
...

>
> There are however far too many roadblocks for porting complex addons to
> be really restartless. For example:
> * cannot really load styles into active windows and unload them again
> (work-around would be to have all styles as inline styles attached to
> any added DOM elements)

Therefore you need to implement undo for ever change you make. This
maybe less than you think, since you won't need to undo changes to
things you add to the UI (and consequently remove).

> * fastload caches may interfere with new versions, I guess (wonder what
> jetpack does in this regard)

I can't see how. You won't get cached.

> * cannot fully unload components/modules (jetpack?)

Therefore you need to implement you own module solution which does
support undo. Or attach everything to one or a few objects you delete.

> * loading/unloading of default preferences

Yes, you guessed my next claim: therefore you need to do you own.

> * hardcoded stuff (window icon paths, default preferences again)

Yup.

0 new messages