diff options
Diffstat (limited to 'devtools/server/actors/targets/parent-process.js')
-rw-r--r-- | devtools/server/actors/targets/parent-process.js | 166 |
1 files changed, 166 insertions, 0 deletions
diff --git a/devtools/server/actors/targets/parent-process.js b/devtools/server/actors/targets/parent-process.js new file mode 100644 index 0000000000..2170bd0b1e --- /dev/null +++ b/devtools/server/actors/targets/parent-process.js @@ -0,0 +1,166 @@ +/* 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(), + 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; |