Gecko:Chrome Registration
The registration of chrome files in the chrome: protocol is currently a fairly complex process involving multiple layers of manifests and configuration files. I (bsmedberg) intend to significantly reduce the complexity of chrome registration, while at the same time fixing a series of filed and unfiled bugs with uninstalling chrome packages.
Contents
The Current Registration Process
The first part of the chrome registration process identifies a list of locations to register. For chrome installed as part of the application, this is handled by a manifest file called "installed-chrome.txt". This file lists locations of chrome packages. In toolkit applications, this is also handled by the extension manager. The EM keeps a list of enabled extensions, and provides a list of chrome package locations to the chrome registry.
The manifest/registrations are not read at every startup. Instead, the chrome registry keeps a cache of the package information (extensions.cache). It updates this cache when the modification-time of installed-chrome.txt changes, or when the EM determines that the set of installed extensions has changed.
The second part of chrome registration looks at each chrome package for an RDF file (contents.rdf) describing the package. This RDF file describes the package name and any overlays or style-overlays that the package provides. In seamonkey, this RDF file also defines version numbers for content, locale, and skin packages, so that only properly-versioned locale and skin packages are applied to a content package. In toolkit applications, this is not necessary, because the EM handles all version-checking before the chrome registry sees any chrome packages.
Problems
The main problems with this architecture stem from the way the chrome registry caches the package information. It essentially builds a giant aggregation of the individual package RDF files and saves that to disk. Not only does that loading eat a lot of cycles during startup (RDF/XML parsing is notoriously slow), but it means that the chrome registry doesn't have a way to identify which parts of the aggregated whole came from which source package. When it comes time to uninstall or disable a package, it uses a series of hacks which separate parts of the RDF graph, but do not remove them. This can become a serious issue later, when seemingly similar packages are installed and re-add RDF arcs, but do not provide the same package set. See bug 258878.
Solution
The easiest solution avoids RDF altogether. Now that we have moved all version-checking into the EM, there is not much left in the RDF vocabulary. All the parts of the RDF package manifest can easily be described in a simple plaintext format, as follows:
package packagename URI [the URI would normally be a relative to the manifest] locale packagename localename URI skin packagename skinname URI overlay URIToBeOverlaid OverlayURI style URIToBeStyled CSSURI
These manifest files would be read at startup directly. I envision there would be one "main" app.manifest file generated at build-time for the major portions of the app, similar to the way installed-chrome.txt is generated today. The toolkit/app/extensions can all use their own manifest file. Uninstall/disabling an extension simply involves removing that extension's manifest from the list to read at startup.
Bug 278534 which was tracking this has now been resolved.
Migration
In order for the flat chrome manifests to provide all the benefits that are promised here, we need to actually use them in our build system. I have taught the make-jars.pl a new syntax that can be used to construct the flat manifests:
toolkit.jar: % content global %content/global/ % overlay chrome://communicator/content/contentAreaContextOverlay.xul chrome://communicator/content/permissions/imageContextOverlay.xul
classic.jar: % skin global classic/1.0 %skin/classic/global/
To migrate to the new manifests, remove the "contents.rdf" lines from jar.mn and replace them with these registration lines beginning with %. If you are migrating a contents.rdf that registers a content package, you need to look in the contents.rdf and see whether it registers any overlays. For instance, when migrating this contents.rdf, you need the following jar.mn lines:
browser.jar: % content browser %content/browser/ #ifdef XP_MACOSX % overlay chrome://mozapps/content/downloads/downloads.xul chrome://browser/content/downloadManagerOverlay.xul % overlay chrome://mozapps/content/extensions/extensions.xul?type=extensions chrome://browser/content/extensionsManagerOverlay.xul % overlay chrome://mozapps/content/extensions/extensions.xul?type=themes chrome://browser/content/extensionsManagerOverlay.xul % overlay chrome://global/content/console.xul chrome://browser/content/jsConsoleOverlay.xul #endif
Compatibility
Because we don't want to arbitrarily break current extension authors, this system reads existing contents.rdf files and parses them into manifest files when extensions are first installed, making this system transparent to existing extensions/themes.
Comments Gecko:Axel Hecht
How does this play together with update? When update bounces up the version number, shouldn't old extensions get a cross check on their version numbers to see if they should be at least disabled?
Answer Gecko:Benjamin Smedberg
If the extension manager finds that an extension/theme is incompatible, it removes that chrome manifest from the list that the chrome registry reads. That is in fact one of the hard cases that this proposal is solving.