Mobile/Fennec/Extensions/Electrolysis
Introduction
Fennec 2.0 will move the Electrolysis platform. This means that chrome windows (the main application window) and content windows (web content in browser tabs) will be in separate processes. This impacts application and add-on code in a few ways:
- Code in one process will not be able to directly access code in the other process.
- Inter process communication will use a message based system to communicate.
An example will help illustrate the affect of the changes. First, let's look at how code in the application (or add-on overlay) would access the DOM of a web page:
alert(gBrowser.contentDocument.title); // in Firefox alert(Browser.selectedBrowser.contentDocument.title); // in Fennec
This code will break because contentDocument will always return null (or perhaps it will throw an exception). In any case, it just won't work. Other properties of <browser> will also fail, such as contentWindow, ...(add more)...
Another common use-case is listening for DOM event bubble up from the web content:
gBrowser.addEventListener("DOMLinkAdded", myHandler, true); // in Firefox
Browser.selectedBrowser.addEventListener("DOMLinkAdded", myHandler, true); // in Fennec
This will no longer work. DOM events do not pass across the process boundary.
Glossary
Before diving into more details about how multi-process works in Mozilla, let's create a glossary of terms:
- chrome: Any JS code that runs at a high level of privilege. This code has access to the Mozilla platform.
- content: A web page, including the HTML, JS and CSS. Code in this scope is sandboxed and has limited capabilities.
- process: An instance of a computer program that executed independently from other processes. Direct communication between processes is not allowed, but indirect communication, via messages is allowed.
- in-process: content is running in the same process as the main application.
- out-of-process: content is running in a separate process. This process does have chrome script, but does not have direct access to the main application.
- messaging system: A system built into all Mozilla processes that enables sending and receiving messages.
- browser: A XUL element that provides a surface for browsing web and chrome content. A browser can be set to allow multi-process support (
<browser remote="true"/>) or traditional, in-process support (<browser />). - message manager: See messaging system
Overview
You might be wondering how in the world any application code or add-on code is supposed to work in the world of multi-process. Mozilla has implemented a few different ways to help get your code working. The most powerful system is the IPC Messaging System. The Messaging System is used to pass messages and JSON data back and forth across the process boundary. The way to access the system is by using the MessageManager object.
MessageManager object is available to the chrome script in both processes. See the MXR link for a full description of the interfaces. The API is slightly different though:
Main (application) Process
void addMessageListener(in AString aMessage, in nsIFrameMessageListener aListener); void removeMessageListener(in AString aMessage, in nsIFrameMessageListener aListener); void sendAsyncMessage(in messageName, in JSON); void loadFrameScript(in AString aURL, in boolean aAllowDelayedLoad);
In the main process, window.messageManager is how you access the MessageManager. This manager can communicate to all browser child processes in the window's scope. You can also access an individual child process by using the browser.messageManager.
Child (content) Process
void addMessageListener(in AString aMessage, in nsIFrameMessageListener aListener); void removeMessageListener(in AString aMessage, in nsIFrameMessageListener aListener); void sendAsyncMessage(in messageName, in JSON); void sendSyncMessage(in messageName, in JSON); readonly attribute nsIDOMWindow content; readonly attribute nsIDocShell docShell; void dump(in DOMString aStr);
In the child process, MessageManager is the root JS object, so you have direct access to all the members.
Message Listeners
/**
* receiveMessage is called with one parameter, which has the following
* properties:
* {
* name: %message name%,
* sync: %true or false%,
* target: %browser%,
* json: %json object or null%
* }
*
* if the message is synchronous, possible return value is sent back
* as JSON.
*
* When the listener is called, 'this' value is the target of the message.
*/
void receiveMessage(in Object aMessage);
Sending and receiving messages across processes is a lot like the window.postMessage system. Instead of events, the code deals with messages. Just like event listeners, message listeners can be implemented as JS objects or JS functions.
The key to starting the whole system is loading a chrome script in the content process. The is done using the loadFrameScript method in the main process.
