178 lines
5.8 KiB
JavaScript
178 lines
5.8 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.
|
|
*
|
|
* See devtools/docs/contributor/backend/actor-hierarchy.md for more details about all the targets.
|
|
*/
|
|
|
|
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 {DevToolsServerConnection} conn
|
|
* The connection to the client.
|
|
* @param {Boolean} options.isTopLevelTarget
|
|
* flag to indicate if this is the top
|
|
* level target of the DevTools session
|
|
* @param {Object} options.sessionContext
|
|
* The Session Context to help know what is debugged.
|
|
* See devtools/server/actors/watcher/session-context.js
|
|
*/
|
|
constructor(conn, { isTopLevelTarget, sessionContext }) {
|
|
super(conn, {
|
|
isTopLevelTarget,
|
|
sessionContext,
|
|
customSpec: parentProcessTargetSpec,
|
|
});
|
|
|
|
// 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");
|
|
|
|
this.setDocShell(this._getInitialDocShell());
|
|
}
|
|
|
|
// Overload setDocShell in order to observe all the docshells.
|
|
// WindowGlobalTargetActor only observes the top level one.
|
|
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) {
|
|
// If DevTools is started early enough, this window will be the
|
|
// early navigator:blank window created in BrowserGlue.sys.mjs
|
|
window = Services.wm.getMostRecentWindow(null);
|
|
}
|
|
|
|
// On Fenix, we may not have any document to inspect when there is no tab
|
|
// opened, so return a fake document, just to ensure the ParentProcessWindowGlobalTarget
|
|
// actor has a functional document to operate with.
|
|
if (!window) {
|
|
const browser = Services.appShell.createWindowlessBrowser(false);
|
|
|
|
// Keep a strong reference to the document to keep it alive
|
|
this.headlessBrowser = browser;
|
|
|
|
// Create a document in order to avoid being on the initial about:blank document
|
|
// and have the document be ignored because its `isInitialDocument` attribute being true
|
|
const systemPrincipal =
|
|
Services.scriptSecurityManager.getSystemPrincipal();
|
|
browser.docShell.createAboutBlankDocumentViewer(
|
|
systemPrincipal,
|
|
systemPrincipal
|
|
);
|
|
|
|
window = browser.docShell.domWindow;
|
|
|
|
// Set some content to be shown in the inspector
|
|
window.document.body.textContent =
|
|
"Fake DevTools document, as there is no tab opened yet";
|
|
}
|
|
|
|
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);
|
|
}
|
|
|
|
this.headlessBrowser = null;
|
|
|
|
return super._detach();
|
|
}
|
|
}
|
|
|
|
exports.ParentProcessTargetActor = ParentProcessTargetActor;
|