gecko-dev/devtools/server/child.js

125 строки
4.4 KiB
JavaScript
Исходник Обычный вид История

/* 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";
/* global addEventListener, addMessageListener, removeMessageListener, sendAsyncMessage */
try {
var chromeGlobal = this;
// Encapsulate in its own scope to allows loading this frame script more than once.
(function () {
const Cu = Components.utils;
const { require } = Cu.import("resource://devtools/shared/Loader.jsm", {});
const DevToolsUtils = require("devtools/shared/DevToolsUtils");
const { dumpn } = DevToolsUtils;
const { DebuggerServer, ActorPool } = require("devtools/server/main");
if (!DebuggerServer.initialized) {
DebuggerServer.init();
}
// We want a special server without any root actor and only tab actors.
// We are going to spawn a ContentActor instance in the next few lines,
// it is going to act like a root actor without being one.
DebuggerServer.registerActors({ root: false, browser: false, tab: true });
let connections = new Map();
let onConnect = DevToolsUtils.makeInfallible(function (msg) {
removeMessageListener("debug:connect", onConnect);
let mm = msg.target;
let prefix = msg.data.prefix;
Bug 1302702 - Make WebExtension Addon Debugging oop-compatible. r=ochameau This patch applies all the changes needed to the devtools actors and the toolbox-process-window, to be able to debug a webextension running in an extension child process (as well as a webextension running in the main process). The devtools actor used to debug a webextension is splitted into 3 actors: - the WebExtensionActor is the actor that is created when the "root.listTabs" RDP request is received, it provides the addon metadata (name, icon and addon id) and two RDP methods: - reload: used to reload the addon (e.g. from the "about:debugging#addons" page) - connectAddonDebuggingActor: which provides the actorID of the actor that is connected to the process where the extension is running (used by toolbox-process-window.js to connect the toolbox to the needed devtools actors, e.g. console, inspector etc.) - the WebExtensionParentActor is the actor that connects to the process where the extension is running and ensures that a WebExtensionChildActor instance is created and connected (this actor is only the entrypoint to reach the WebExtensionChildActor, and so it does not provide any RDP request on its own, it only connect itself to its child counterpart and then it returns the RDP "form" of the child actor, and the client is then connected directly to the child actor) - the WebExtensionChildActor is the actor that is running in the same process of the target extension, and it provides the same requestTypes of a tab actor. By splitting the WebExtensionActor from the WebExtensionParentActor, we are able to prevent the RemoteDebuggingServer to connect (and create instances of the WebExtensionChildActor) for every addon listed by a root.listAddons() request. MozReview-Commit-ID: L1vxhA6xQkD --HG-- extra : rebase_source : 7ed7735084d9351ff32ab1ad822e53dd0828dace
2017-03-21 17:55:35 +03:00
let addonId = msg.data.addonId;
let conn = DebuggerServer.connectToParent(prefix, mm);
conn.parentMessageManager = mm;
connections.set(prefix, conn);
Bug 1302702 - Make WebExtension Addon Debugging oop-compatible. r=ochameau This patch applies all the changes needed to the devtools actors and the toolbox-process-window, to be able to debug a webextension running in an extension child process (as well as a webextension running in the main process). The devtools actor used to debug a webextension is splitted into 3 actors: - the WebExtensionActor is the actor that is created when the "root.listTabs" RDP request is received, it provides the addon metadata (name, icon and addon id) and two RDP methods: - reload: used to reload the addon (e.g. from the "about:debugging#addons" page) - connectAddonDebuggingActor: which provides the actorID of the actor that is connected to the process where the extension is running (used by toolbox-process-window.js to connect the toolbox to the needed devtools actors, e.g. console, inspector etc.) - the WebExtensionParentActor is the actor that connects to the process where the extension is running and ensures that a WebExtensionChildActor instance is created and connected (this actor is only the entrypoint to reach the WebExtensionChildActor, and so it does not provide any RDP request on its own, it only connect itself to its child counterpart and then it returns the RDP "form" of the child actor, and the client is then connected directly to the child actor) - the WebExtensionChildActor is the actor that is running in the same process of the target extension, and it provides the same requestTypes of a tab actor. By splitting the WebExtensionActor from the WebExtensionParentActor, we are able to prevent the RemoteDebuggingServer to connect (and create instances of the WebExtensionChildActor) for every addon listed by a root.listAddons() request. MozReview-Commit-ID: L1vxhA6xQkD --HG-- extra : rebase_source : 7ed7735084d9351ff32ab1ad822e53dd0828dace
2017-03-21 17:55:35 +03:00
let actor;
if (addonId) {
const { WebExtensionChildActor } = require("devtools/server/actors/webextension");
actor = new WebExtensionChildActor(conn, chromeGlobal, prefix, addonId);
} else {
const { ContentActor } = require("devtools/server/actors/childtab");
actor = new ContentActor(conn, chromeGlobal, prefix);
}
let actorPool = new ActorPool(conn);
actorPool.addActor(actor);
conn.addActorPool(actorPool);
sendAsyncMessage("debug:actor", {actor: actor.form(), prefix: prefix});
});
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;
try {
m = require(module);
if (!(setupChild in m)) {
dumpn(`ERROR: module '${module}' does not export '${setupChild}'`);
return false;
}
m[setupChild].apply(m, args);
} catch (e) {
let errorMessage =
"Exception during actor module setup running in the child process: ";
DevToolsUtils.reportException(errorMessage + e);
dumpn(`ERROR: ${errorMessage}\n\t module: '${module}'\n\t ` +
`setupChild: '${setupChild}'\n${DevToolsUtils.safeErrorString(e)}`);
return false;
}
if (msg.data.id) {
// Send a message back to know when it is processed
sendAsyncMessage("debug:setup-in-child-response", {id: msg.data.id});
}
return true;
});
addMessageListener("debug:setup-in-child", onSetupInChild);
let onDisconnect = DevToolsUtils.makeInfallible(function (msg) {
let prefix = msg.data.prefix;
let conn = connections.get(prefix);
if (!conn) {
// Several copies of this frame script can be running for a single frame since it
// is loaded once for each DevTools connection to the frame. If this disconnect
// request doesn't match a connection known here, ignore it.
return;
}
removeMessageListener("debug:disconnect", onDisconnect);
// Call DebuggerServerConnection.close to destroy all child actors. It should end up
// calling DebuggerServerConnection.onClosed that would actually cleanup all actor
// pools.
conn.close();
connections.delete(prefix);
});
addMessageListener("debug:disconnect", onDisconnect);
// In non-e10s mode, the "debug:disconnect" message isn't always received before the
// messageManager connection goes away. Watching for "unload" here ensures we close
// any connections when the frame is unloaded.
addEventListener("unload", () => {
for (let conn of connections.values()) {
conn.close();
}
connections.clear();
});
})();
} catch (e) {
dump(`Exception in app child process: ${e}\n`);
}