tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

parent-process.js (5954B)


      1 /* This Source Code Form is subject to the terms of the Mozilla Public
      2 * License, v. 2.0. If a copy of the MPL was not distributed with this
      3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      4 
      5 "use strict";
      6 
      7 /*
      8 * Target actor for the entire parent process.
      9 *
     10 * This actor extends WindowGlobalTargetActor.
     11 *
     12 * See devtools/docs/contributor/backend/actor-hierarchy.md for more details about all the targets.
     13 */
     14 
     15 const {
     16  DevToolsServer,
     17 } = require("resource://devtools/server/devtools-server.js");
     18 const {
     19  getChildDocShells,
     20  WindowGlobalTargetActor,
     21 } = require("resource://devtools/server/actors/targets/window-global.js");
     22 const makeDebugger = require("resource://devtools/server/actors/utils/make-debugger.js");
     23 
     24 const {
     25  parentProcessTargetSpec,
     26 } = require("resource://devtools/shared/specs/targets/parent-process.js");
     27 
     28 class ParentProcessTargetActor extends WindowGlobalTargetActor {
     29  /**
     30   * Creates a target actor for debugging all the chrome content in the parent process.
     31   * Most of the implementation is inherited from WindowGlobalTargetActor.
     32   * ParentProcessTargetActor is a child of RootActor, it can be instantiated via
     33   * RootActor.getProcess request. ParentProcessTargetActor exposes all target-scoped actors
     34   * via its form() request, like WindowGlobalTargetActor.
     35   *
     36   * @param {DevToolsServerConnection} conn
     37   *        The connection to the client.
     38   * @param {boolean} options.isTopLevelTarget
     39   *        flag to indicate if this is the top
     40   *        level target of the DevTools session
     41   * @param {object} options.sessionContext
     42   *        The Session Context to help know what is debugged.
     43   *        See devtools/server/actors/watcher/session-context.js
     44   */
     45  constructor(conn, { isTopLevelTarget, sessionContext }) {
     46    super(conn, {
     47      isTopLevelTarget,
     48      sessionContext,
     49      customSpec: parentProcessTargetSpec,
     50    });
     51 
     52    // This creates a Debugger instance for chrome debugging all globals.
     53    this.makeDebugger = makeDebugger.bind(null, {
     54      findDebuggees: dbg =>
     55        dbg.findAllGlobals().map(g => g.unsafeDereference()),
     56      shouldAddNewGlobalAsDebuggee: () => true,
     57    });
     58 
     59    // Ensure catching the creation of any new content docshell
     60    this.watchNewDocShells = true;
     61 
     62    this.isRootActor = true;
     63 
     64    // Listen for any new/destroyed chrome docshell
     65    Services.obs.addObserver(this, "chrome-webnavigation-create");
     66    Services.obs.addObserver(this, "chrome-webnavigation-destroy");
     67 
     68    this.setDocShell(this._getInitialDocShell());
     69  }
     70 
     71  // Overload setDocShell in order to observe all the docshells.
     72  // WindowGlobalTargetActor only observes the top level one.
     73  setDocShell(initialDocShell) {
     74    super.setDocShell(initialDocShell);
     75 
     76    // Iterate over all top-level windows.
     77    for (const { docShell } of Services.ww.getWindowEnumerator()) {
     78      if (docShell == this.docShell) {
     79        continue;
     80      }
     81      this._progressListener.watch(docShell);
     82    }
     83  }
     84 
     85  _getInitialDocShell() {
     86    // Defines the default docshell selected for the target actor
     87    let window = Services.wm.getMostRecentWindow(
     88      DevToolsServer.chromeWindowType
     89    );
     90 
     91    // Default to any available top level window if there is no expected window
     92    // eg when running ./mach run --chrome chrome://browser/content/aboutTabCrashed.xhtml --jsdebugger
     93    if (!window) {
     94      // If DevTools is started early enough, this window will be the
     95      // early navigator:blank window created in BrowserGlue.sys.mjs
     96      window = Services.wm.getMostRecentWindow(null);
     97    }
     98 
     99    // On Fenix, we may not have any document to inspect when there is no tab
    100    // opened, so return a fake document, just to ensure the ParentProcessWindowGlobalTarget
    101    // actor has a functional document to operate with.
    102    if (!window) {
    103      const browser = Services.appShell.createWindowlessBrowser(false);
    104 
    105      // Keep a strong reference to the document to keep it alive
    106      this.headlessBrowser = browser;
    107 
    108      // Create a document in order to avoid being on the initial about:blank document
    109      // and have the document be ignored because its `isInitialDocument` attribute being true
    110      const systemPrincipal =
    111        Services.scriptSecurityManager.getSystemPrincipal();
    112      browser.docShell.createAboutBlankDocumentViewer(
    113        systemPrincipal,
    114        systemPrincipal
    115      );
    116 
    117      window = browser.docShell.domWindow;
    118 
    119      // Set some content to be shown in the inspector
    120      window.document.body.textContent =
    121        "Fake DevTools document, as there is no tab opened yet";
    122    }
    123 
    124    return window.docShell;
    125  }
    126 
    127  /**
    128   * Getter for the list of all docshells in this targetActor
    129   *
    130   * @return {Array}
    131   */
    132  get docShells() {
    133    // Iterate over all top-level windows and all their docshells.
    134    let docShells = [];
    135    for (const { docShell } of Services.ww.getWindowEnumerator()) {
    136      docShells = docShells.concat(getChildDocShells(docShell));
    137    }
    138 
    139    return docShells;
    140  }
    141 
    142  observe(subject, topic, data) {
    143    super.observe(subject, topic, data);
    144    if (this.isDestroyed()) {
    145      return;
    146    }
    147 
    148    subject.QueryInterface(Ci.nsIDocShell);
    149 
    150    if (topic == "chrome-webnavigation-create") {
    151      this._onDocShellCreated(subject);
    152    } else if (topic == "chrome-webnavigation-destroy") {
    153      this._onDocShellDestroy(subject);
    154    }
    155  }
    156 
    157  _detach() {
    158    if (this.isDestroyed()) {
    159      return false;
    160    }
    161 
    162    Services.obs.removeObserver(this, "chrome-webnavigation-create");
    163    Services.obs.removeObserver(this, "chrome-webnavigation-destroy");
    164 
    165    // Iterate over all top-level windows.
    166    for (const { docShell } of Services.ww.getWindowEnumerator()) {
    167      if (docShell == this.docShell) {
    168        continue;
    169      }
    170      this._progressListener.unwatch(docShell);
    171    }
    172 
    173    this.headlessBrowser = null;
    174 
    175    return super._detach();
    176  }
    177 }
    178 
    179 exports.ParentProcessTargetActor = ParentProcessTargetActor;