167 lines
5.4 KiB
JavaScript
167 lines
5.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";
|
|
|
|
/*
|
|
* Target actor for the entire parent process.
|
|
*
|
|
* This actor extends WindowGlobalTargetActor.
|
|
* This actor is extended by WebExtensionTargetActor.
|
|
*
|
|
* See devtools/docs/backend/actor-hierarchy.md for more details.
|
|
*/
|
|
|
|
const {
|
|
DevToolsServer,
|
|
} = require("resource://devtools/server/devtools-server.js");
|
|
const {
|
|
getChildDocShells,
|
|
WindowGlobalTargetActor,
|
|
} = require("resource://devtools/server/actors/targets/window-global.js");
|
|
const makeDebugger = require("resource://devtools/server/actors/utils/make-debugger.js");
|
|
|
|
const {
|
|
parentProcessTargetSpec,
|
|
} = require("resource://devtools/shared/specs/targets/parent-process.js");
|
|
|
|
class ParentProcessTargetActor extends WindowGlobalTargetActor {
|
|
/**
|
|
* Creates a target actor for debugging all the chrome content in the parent process.
|
|
* Most of the implementation is inherited from WindowGlobalTargetActor.
|
|
* ParentProcessTargetActor is a child of RootActor, it can be instantiated via
|
|
* RootActor.getProcess request. ParentProcessTargetActor exposes all target-scoped actors
|
|
* via its form() request, like WindowGlobalTargetActor.
|
|
*
|
|
* @param conn DevToolsServerConnection
|
|
* The connection to the client.
|
|
* @param {Object} options
|
|
* - isTopLevelTarget: {Boolean} flag to indicate if this is the top
|
|
* level target of the DevTools session
|
|
* - sessionContext Object
|
|
* The Session Context to help know what is debugged.
|
|
* See devtools/server/actors/watcher/session-context.js
|
|
* - customSpec Object
|
|
* WebExtensionTargetActor inherits from ParentProcessTargetActor
|
|
* and has to use its own protocol.js specification object.
|
|
*/
|
|
constructor(
|
|
conn,
|
|
{ isTopLevelTarget, sessionContext, customSpec = parentProcessTargetSpec }
|
|
) {
|
|
super(conn, {
|
|
isTopLevelTarget,
|
|
sessionContext,
|
|
customSpec,
|
|
});
|
|
|
|
// This creates a Debugger instance for chrome debugging all globals.
|
|
this.makeDebugger = makeDebugger.bind(null, {
|
|
findDebuggees: dbg =>
|
|
dbg.findAllGlobals().map(g => g.unsafeDereference()),
|
|
shouldAddNewGlobalAsDebuggee: () => true,
|
|
});
|
|
|
|
// Ensure catching the creation of any new content docshell
|
|
this.watchNewDocShells = true;
|
|
|
|
this.isRootActor = true;
|
|
|
|
// Listen for any new/destroyed chrome docshell
|
|
Services.obs.addObserver(this, "chrome-webnavigation-create");
|
|
Services.obs.addObserver(this, "chrome-webnavigation-destroy");
|
|
|
|
// If we are the parent process target actor and not a subclass
|
|
// (i.e. if we aren't the webext target actor)
|
|
// set the parent process docshell:
|
|
if (customSpec == parentProcessTargetSpec) {
|
|
this.setDocShell(this._getInitialDocShell());
|
|
}
|
|
}
|
|
|
|
// Overload setDocShell in order to observe all the docshells.
|
|
// WindowGlobalTargetActor only observes the top level one,
|
|
// but we also need to observe all of them for WebExtensionTargetActor subclass.
|
|
setDocShell(initialDocShell) {
|
|
super.setDocShell(initialDocShell);
|
|
|
|
// Iterate over all top-level windows.
|
|
for (const { docShell } of Services.ww.getWindowEnumerator()) {
|
|
if (docShell == this.docShell) {
|
|
continue;
|
|
}
|
|
this._progressListener.watch(docShell);
|
|
}
|
|
}
|
|
|
|
_getInitialDocShell() {
|
|
// Defines the default docshell selected for the target actor
|
|
let window = Services.wm.getMostRecentWindow(
|
|
DevToolsServer.chromeWindowType
|
|
);
|
|
|
|
// Default to any available top level window if there is no expected window
|
|
// eg when running ./mach run --chrome chrome://browser/content/aboutTabCrashed.xhtml --jsdebugger
|
|
if (!window) {
|
|
window = Services.wm.getMostRecentWindow(null);
|
|
}
|
|
|
|
// We really want _some_ window at least, so fallback to the hidden window if
|
|
// there's nothing else (such as during early startup).
|
|
if (!window) {
|
|
window = Services.appShell.hiddenDOMWindow;
|
|
}
|
|
return window.docShell;
|
|
}
|
|
|
|
/**
|
|
* Getter for the list of all docshells in this targetActor
|
|
* @return {Array}
|
|
*/
|
|
get docShells() {
|
|
// Iterate over all top-level windows and all their docshells.
|
|
let docShells = [];
|
|
for (const { docShell } of Services.ww.getWindowEnumerator()) {
|
|
docShells = docShells.concat(getChildDocShells(docShell));
|
|
}
|
|
|
|
return docShells;
|
|
}
|
|
|
|
observe(subject, topic, data) {
|
|
super.observe(subject, topic, data);
|
|
if (this.isDestroyed()) {
|
|
return;
|
|
}
|
|
|
|
subject.QueryInterface(Ci.nsIDocShell);
|
|
|
|
if (topic == "chrome-webnavigation-create") {
|
|
this._onDocShellCreated(subject);
|
|
} else if (topic == "chrome-webnavigation-destroy") {
|
|
this._onDocShellDestroy(subject);
|
|
}
|
|
}
|
|
|
|
_detach() {
|
|
if (this.isDestroyed()) {
|
|
return false;
|
|
}
|
|
|
|
Services.obs.removeObserver(this, "chrome-webnavigation-create");
|
|
Services.obs.removeObserver(this, "chrome-webnavigation-destroy");
|
|
|
|
// Iterate over all top-level windows.
|
|
for (const { docShell } of Services.ww.getWindowEnumerator()) {
|
|
if (docShell == this.docShell) {
|
|
continue;
|
|
}
|
|
this._progressListener.unwatch(docShell);
|
|
}
|
|
|
|
return super._detach();
|
|
}
|
|
}
|
|
|
|
exports.ParentProcessTargetActor = ParentProcessTargetActor;
|