Bug 1107888 - e10s support for dynamic actor registration. r=ochameau

This commit is contained in:
Jan Odvarko 2014-12-05 15:40:10 -08:00
parent a35012eae2
commit 536ea800d3
6 changed files with 143 additions and 32 deletions

View File

@ -11,8 +11,10 @@ const { Cu, CC, components } = require("chrome");
const { Promise: promise } = Cu.import("resource://gre/modules/Promise.jsm", {});
const Services = require("Services");
const { DebuggerServer } = require("devtools/server/main");
const { XPCOMUtils } = require("resource://gre/modules/XPCOMUtils.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "NetUtil", "resource://gre/modules/NetUtil.jsm");
const ActorRegistryUtils = require("devtools/server/actors/utils/actor-registry-utils");
const { registerActor, unregisterActor } = ActorRegistryUtils;
loader.lazyImporter(this, "NetUtil", "resource://gre/modules/NetUtil.jsm");
/**
* The ActorActor gives you a handle to an actor you've dynamically
@ -28,13 +30,7 @@ const ActorActor = protocol.ActorClass({
},
unregister: method(function () {
if (this.options.tab) {
DebuggerServer.removeTabActor(this.options);
}
if (this.options.global) {
DebuggerServer.removeGlobalActor(this.options);
}
unregisterActor(this.options);
}, {
request: {},
response: {}
@ -61,28 +57,9 @@ const ActorRegistryActor = protocol.ActorClass({
},
registerActor: method(function (sourceText, fileName, options) {
const principal = CC("@mozilla.org/systemprincipal;1", "nsIPrincipal")();
const sandbox = Cu.Sandbox(principal);
const exports = sandbox.exports = {};
sandbox.require = require;
registerActor(sourceText, fileName, options);
Cu.evalInSandbox(sourceText, sandbox, "1.8", fileName, 1);
let { prefix, constructor, type } = options;
if (type.global) {
DebuggerServer.addGlobalActor({
constructorName: constructor,
constructorFun: sandbox[constructor]
}, prefix);
}
if (type.tab) {
DebuggerServer.addTabActor({
constructorName: constructor,
constructorFun: sandbox[constructor]
}, prefix);
}
let { constructor, type } = options;
return ActorActor(this.conn, {
name: constructor,

View File

@ -0,0 +1,74 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
let { Cu, CC, Ci, Cc } = require("chrome");
const { DebuggerServer } = require("devtools/server/main");
/**
* Support for actor registration. Main used by ActorRegistryActor
* for dynamic registration of new actors.
*
* @param sourceText {String} Source of the actor implementation
* @param fileName {String} URL of the actor module (for proper stack traces)
* @param options {Object} Configuration object
*/
exports.registerActor = function(sourceText, fileName, options) {
const principal = CC("@mozilla.org/systemprincipal;1", "nsIPrincipal")();
const sandbox = Cu.Sandbox(principal);
const exports = sandbox.exports = {};
sandbox.require = require;
Cu.evalInSandbox(sourceText, sandbox, "1.8", fileName, 1);
let { prefix, constructor, type } = options;
if (type.global && !DebuggerServer.globalActorFactories.hasOwnProperty(prefix)) {
DebuggerServer.addGlobalActor({
constructorName: constructor,
constructorFun: sandbox[constructor]
}, prefix);
}
if (type.tab && !DebuggerServer.tabActorFactories.hasOwnProperty(prefix)) {
DebuggerServer.addTabActor({
constructorName: constructor,
constructorFun: sandbox[constructor]
}, prefix);
}
// Also register in all child processes in case the current scope
// is chrome parent process.
if (!DebuggerServer.isInChildProcess) {
DebuggerServer.setupInChild({
module: "devtools/server/actors/utils/actor-registry-utils",
setupChild: "registerActor",
args: [sourceText, fileName, options]
});
}
}
exports.unregisterActor = function(options) {
if (options.tab) {
DebuggerServer.removeTabActor(options);
}
if (options.global) {
DebuggerServer.removeGlobalActor(options);
}
// Also unregister it from all child processes in case the current
// scope is chrome parent process.
if (!DebuggerServer.isInChildProcess) {
DebuggerServer.setupInChild({
module: "devtools/server/actors/utils/actor-registry-utils",
setupChild: "unregisterActor",
args: [options]
});
}
}

View File

@ -14,7 +14,9 @@ let chromeGlobal = this;
let Cu = Components.utils;
let { devtools } = Cu.import("resource://gre/modules/devtools/Loader.jsm", {});
const DevToolsUtils = devtools.require("devtools/toolkit/DevToolsUtils.js");
const {DebuggerServer, ActorPool} = Cu.import("resource://gre/modules/devtools/dbg-server.jsm", {});
const { dumpn } = DevToolsUtils;
const { DebuggerServer, ActorPool } = Cu.import("resource://gre/modules/devtools/dbg-server.jsm", {});
if (!DebuggerServer.childID) {
DebuggerServer.childID = 1;
}
@ -57,6 +59,36 @@ let chromeGlobal = this;
addMessageListener("debug:connect", onConnect);
// Allows executing module setup helper from the parent process.
// See also: DebuggerServer.setupInChild()
let onSetupInChild = DevToolsUtils.makeInfallible(msg => {
let { module, setupChild, args } = msg.data;
let m, fn;
try {
m = devtools.require(module);
if (!setupChild in m) {
dumpn("ERROR: module '" + module + "' does not export '" +
setupChild + "'");
return false;
}
m[setupChild].apply(m, args);
return true;
} catch(e) {
let error_msg = "exception during actor module setup running in the child process: ";
DevToolsUtils.reportException(error_msg + e);
dumpn("ERROR: " + error_msg + " \n\t module: '" + module +
"' \n\t setupChild: '" + setupChild + "'\n" +
DevToolsUtils.safeErrorString(e));
return false;
}
});
addMessageListener("debug:setup-in-child", onSetupInChild);
let onDisconnect = DevToolsUtils.makeInfallible(function (msg) {
removeMessageListener("debug:disconnect", onDisconnect);

View File

@ -730,6 +730,31 @@ var DebuggerServer = {
*/
get isInChildProcess() !!this.parentMessageManager,
/**
* In a chrome parent process, ask all content child processes
* to execute a given module setup helper.
*
* @param module
* The module to be required
* @param setupChild
* The name of the setup helper exported by the above module
* (setup helper signature: function ({mm}) { ... })
*/
setupInChild: function({ module, setupChild, args }) {
if (this.isInChildProcess) {
return;
}
const gMessageManager = Cc["@mozilla.org/globalmessagemanager;1"].
getService(Ci.nsIMessageListenerManager);
gMessageManager.broadcastAsyncMessage("debug:setup-in-child", {
module: module,
setupChild: setupChild,
args: args,
});
},
/**
* In a content child process, ask the DebuggerServer in the parent process
* to execute a given module setup helper.
@ -829,6 +854,8 @@ var DebuggerServer = {
let { NetworkMonitorManager } = require("devtools/toolkit/webconsole/network-monitor");
netMonitor = new NetworkMonitorManager(aFrame, actor.actor);
events.emit(DebuggerServer, "new-child-process", { mm: mm });
deferred.resolve(actor);
}).bind(this);
mm.addMessageListener("debug:actor", onActorCreated);

View File

@ -70,6 +70,7 @@ EXTRA_JS_MODULES.devtools.server.actors += [
]
EXTRA_JS_MODULES.devtools.server.actors.utils += [
'actors/utils/actor-registry-utils.js',
'actors/utils/automation-timeline.js',
'actors/utils/make-debugger.js',
'actors/utils/map-uri-to-addon-id.js',

View File

@ -65,7 +65,7 @@ function unregisterNewActor() {
.unregister()
.then(testActorIsUnregistered)
.then(null, e => {
DevToolsUtils.reportException("registerNewActor", e)
DevToolsUtils.reportException("unregisterNewActor", e)
do_check_true(false);
});
}