|
|
Line 1: |
Line 1: |
| In order to move [[Labs/Jetpack|Jetpack]] to an out-of-process implementation, a mixture of [[Electrolysis/CPOW|CPOWs]], [[XPConnect_Chrome_Object_Wrappers|COWs]] and proxying appears to be necessary.
| | The information on this wiki page was out-of-date and has been removed; see [https://developer.mozilla.org/en/Jetpack_Processes Jetpack Processes] on MDN for the latest information. |
| | |
| == Three contexts ==
| |
| | |
| When a Jetpack is implemented in a separate process, there will be at least three kinds of JS execution contexts:
| |
| | |
| === Jetpack context ===
| |
| | |
| The jetpack JS itself will run in the jetpack process.
| |
| | |
| Predefined globals:
| |
| | |
| * <code>require()</code>
| |
| | |
| === implementation-jetpack context ===
| |
| | |
| Part of the jetpack implementation runs in the jetpack process. It uses COW-type wrappers to expose functions and properties to the jetpack context. It also has some core functions which allow it to send synchronous or asynchronous messages to the browser process.
| |
| | |
| Predefined globals:
| |
| * <code>jetpack</code> - the jetpack context global, used to create <code>jetpack.require</code>
| |
| * <code>sendMessage("messageName" [, data]);</code> - sends asynchronously, no return value
| |
| * <code>callMessage("messageName" [, data]);</code> - sends synchronously, has return value
| |
| * <code>createHandle(object[, parentHandle]);</code> - returns handle object
| |
| * other special globals as necessary, e.g. ctypes would be exposed entirely within the jetpack process and wouldn't need to communicate with chrome
| |
| * <code>registerReceiver(messageName, func)</code> - incoming messages of the specified name
| |
| * <code>wrap(object)</code> - create a COW
| |
| | |
| === implementation-chrome context ===
| |
| | |
| The rest of the jetpack implementation would live in the chrome process, primarily in a JS module. A method would exist (via XPCOM?) to bootstrap a jetpack:
| |
| | |
| <code>var ajetpack = createJetpackProcess();</code>
| |
| | |
| * <code>ajetpack.sendMessage("messageName" [, data]);</code> - only async messages are allowed
| |
| * <code>ajetpack.createHandle(object [, parentHandle]);</code>
| |
| * <code>ajetpack.loadImplementation(uri);</code> - load a script into the jetpack implementation context
| |
| * <code>ajetpack.loadUserScript(uri);</code> - load a script into the jetpack context
| |
| * <code>ajetpack.registerReceiver(messageName, func)</code>
| |
| | |
| === Messages and Handles ===
| |
| | |
| Messages that communicate between the browser and jetpack process may contain only serializable (JSON) data and "handles". A handle can be used to provide context for messages. Either the browser or the jetpack implementation may create a handle. A handle keeps its associated JS object alive, and has the following properties:
| |
| | |
| * <code>handle.object</code> - the JS object associated with the handle
| |
| * <code>handle.parent</code> - the parent handle of the object, if any
| |
| * <code>handle.destroy()</code> - destroy the handle so that is is no longer valid
| |
| * <code>handle.isValid</code> - boolean, is this handle still valid?
| |
| | |
| A handle that is created without a parent stays alive until it is explicitly destroyed.
| |
| | |
| When a handle is created, a "parent handle" may be specified: a handle becomes invalid when its parent is destroyed. This is useful for associating handles to the lifetime of a particular window, context menu, or other element, and helping ensure that they do not leak.
| |
| | |
| Either process may destroy a handle when it is no longer useful. For each handle type jetpack uses, the jetpack implementation should decide which side of the conversation is typically responsible for destroying a handle.
| |
| | |
| === Example ===
| |
| | |
| This is a barebones example of how [[Labs/Jetpack/Reboot/JEP/109|JEP 109]], the request module, could be implemented:
| |
| | |
| Jetpack:
| |
| | |
| <pre>const Request = require("request").Request;
| |
| new Request({
| |
| url: "http://example.com/",
| |
| onComplete: function() console.log(this.response.text)
| |
| }).get();</pre>
| |
| | |
| implementation-jetpack:
| |
| | |
| <pre>function jp_request(r)
| |
| {
| |
| this._onComplete = r.onComplete;
| |
| // ... set up the rest of this._stuff
| |
| }
| |
| jp_request.prototype = {
| |
| __exposedProps__ = {'__call__': 'r', 'get': 'r', 'response': 'r'},
| |
| | |
| get: function() {
| |
| // create a cross-process handle for messsages relating to this request
| |
| this._handle = createHandle(this);
| |
| // send the browser a message to kick things off
| |
| sendMessage("request_get", {url: this._url, handle: this._handle});
| |
| },
| |
| | |
| _handleResponse: function(data) {
| |
| // Firefox just sent us data. Save it in this.response and then...
| |
| this._onComplete();
| |
| },
| |
| };
| |
| registerReceiver("request_done", function(data) {
| |
| data.handle.object._handleResponse(data);
| |
| });
| |
| | |
| // Now hook up jetpack.require
| |
| jetpack.require = function(package) {
| |
| switch (package) {
| |
| "request":
| |
| return { Request: jp_request };
| |
| }
| |
| };</pre>
| |
| | |
| implementation-chrome:
| |
| | |
| <pre>var ajetpack = createJetpackProcess();
| |
| | |
| ajetpack.registerReceiver("request_get", function(data) {
| |
| // perhaps do some kind of domain validation here based on jetpack metadata?
| |
| var r = new XMLHttpRequest(data.uri, ...);
| |
| r.addEventListener("load", function() {
| |
| ajetpack.sendMessage("request_done", {
| |
| responseText: r.responseText,
| |
| handle: data.handle,
| |
| });
| |
| });
| |
| });
| |
| | |
| ajetpack.loadImplementation("chrome://jetpack/content/jetpack-implementation.js");
| |
| ajetpack.loadUserScript("resource://jetpack-repository/myjetpack.js");
| |
| </pre>
| |
| | |
| === Unresolved Issues ===
| |
| | |
| This proposal doesn't really deal with jetpack-to-content communication at all, for pagemods, etc. That's an easier question, in some ways: we can use CPOWs, and that already basically works. What we don't know is how to bootstrap it: given a jetpack and a content winow in chrome, how do we set up the machinery for jetpack/content communication?
| |
| | |
| cjones needs this for cross-process layers as well. The basic idea will be that, in the chrome process, some code will do
| |
| <code>contentProcessParent.Bridge(jetpackParent, PJetpackContent)</code>
| |
| which will asynchronously open a new channel between the content and jetpack processes. The new channel will talk <code>PJetpackContent</code> (or whatever that's called). Haven't worked out the notification bits or how the new <code>PJetpackContent</code> top-level actors will be created, but probably the content and jetpack top-levels will get an <code>OnBridge()</code> notification and perhaps that will be where the actors will be required to be created.
| |
| | |
| == External Resources ==
| |
| | |
| * [https://developer.mozilla.org/en/Multi-Process_Architecture/Jetpack Multi-process Jetpack] on MDC
| |
| * {{bug|556846}} - Investigate multi-process Jetpack
| |