tor-browser

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

content-process.js (8077B)


      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 all resources in a content process of Firefox (chrome sandboxes, frame
      9 * scripts, documents, etc.)
     10 *
     11 * See devtools/docs/contributor/backend/actor-hierarchy.md for more details about all the targets.
     12 */
     13 
     14 const { ThreadActor } = require("resource://devtools/server/actors/thread.js");
     15 const {
     16  WebConsoleActor,
     17 } = require("resource://devtools/server/actors/webconsole.js");
     18 const makeDebugger = require("resource://devtools/server/actors/utils/make-debugger.js");
     19 const { Pool } = require("resource://devtools/shared/protocol.js");
     20 const { assert } = require("resource://devtools/shared/DevToolsUtils.js");
     21 const {
     22  SourcesManager,
     23 } = require("resource://devtools/server/actors/utils/sources-manager.js");
     24 const {
     25  contentProcessTargetSpec,
     26 } = require("resource://devtools/shared/specs/targets/content-process.js");
     27 const Targets = require("resource://devtools/server/actors/targets/index.js");
     28 const Resources = require("resource://devtools/server/actors/resources/index.js");
     29 const {
     30  BaseTargetActor,
     31 } = require("resource://devtools/server/actors/targets/base-target-actor.js");
     32 const { TargetActorRegistry } = ChromeUtils.importESModule(
     33  "resource://devtools/server/actors/targets/target-actor-registry.sys.mjs",
     34  { global: "shared" }
     35 );
     36 
     37 loader.lazyRequireGetter(
     38  this,
     39  "WorkerDescriptorActorList",
     40  "resource://devtools/server/actors/worker/worker-descriptor-actor-list.js",
     41  true
     42 );
     43 loader.lazyRequireGetter(
     44  this,
     45  "MemoryActor",
     46  "resource://devtools/server/actors/memory.js",
     47  true
     48 );
     49 loader.lazyRequireGetter(
     50  this,
     51  "TracerActor",
     52  "resource://devtools/server/actors/tracer.js",
     53  true
     54 );
     55 
     56 class ContentProcessTargetActor extends BaseTargetActor {
     57  constructor(conn, { isXpcShellTarget = false, sessionContext } = {}) {
     58    super(conn, Targets.TYPES.PROCESS, contentProcessTargetSpec);
     59 
     60    this.threadActor = null;
     61    this.isXpcShellTarget = isXpcShellTarget;
     62    this.sessionContext = sessionContext;
     63 
     64    // Use a see-everything debugger
     65    this.makeDebugger = makeDebugger.bind(null, {
     66      findDebuggees: dbg =>
     67        dbg.findAllGlobals().map(g => g.unsafeDereference()),
     68      shouldAddNewGlobalAsDebuggee: () => true,
     69    });
     70 
     71    const sandboxPrototype = {
     72      get tabs() {
     73        return Array.from(
     74          Services.ww.getWindowEnumerator(),
     75          win => win.docShell.messageManager
     76        );
     77      },
     78    };
     79 
     80    // Scope into which the webconsole executes:
     81    // A sandbox with chrome privileges with a `tabs` getter.
     82    const systemPrincipal = Cc["@mozilla.org/systemprincipal;1"].createInstance(
     83      Ci.nsIPrincipal
     84    );
     85    const sandbox = Cu.Sandbox(systemPrincipal, {
     86      sandboxPrototype,
     87      wantGlobalProperties: ["ChromeUtils"],
     88    });
     89    this._consoleScope = sandbox;
     90 
     91    this._workerList = null;
     92    this._workerDescriptorActorPool = null;
     93    this._onWorkerListChanged = this._onWorkerListChanged.bind(this);
     94 
     95    // Try to destroy the Content Process Target when the content process shuts down.
     96    // The parent process can't communicate during shutdown as the communication channel
     97    // is already down (message manager or JS Window Actor API).
     98    // So that we have to observe to some event fired from this process.
     99    // While such cleanup doesn't sound ultimately necessary (the process will be completely destroyed)
    100    // mochitests are asserting that there is no leaks during process shutdown.
    101    // Do not override destroy as Protocol.js may override it when calling destroy,
    102    // and we won't be able to call removeObserver correctly.
    103    this.destroyObserver = this.destroy.bind(this);
    104    Services.obs.addObserver(this.destroyObserver, "xpcom-shutdown");
    105    if (this.isXpcShellTarget) {
    106      TargetActorRegistry.registerXpcShellTargetActor(this);
    107    }
    108  }
    109 
    110  get isRootActor() {
    111    return true;
    112  }
    113 
    114  get url() {
    115    return undefined;
    116  }
    117 
    118  get window() {
    119    return this._consoleScope;
    120  }
    121 
    122  get targetGlobal() {
    123    return this._consoleScope;
    124  }
    125 
    126  get sourcesManager() {
    127    if (!this._sourcesManager) {
    128      assert(
    129        this.threadActor,
    130        "threadActor should exist when creating SourcesManager."
    131      );
    132      this._sourcesManager = new SourcesManager(this.threadActor);
    133    }
    134    return this._sourcesManager;
    135  }
    136 
    137  /*
    138   * Return a Debugger instance or create one if there is none yet
    139   */
    140  get dbg() {
    141    if (!this._dbg) {
    142      this._dbg = this.makeDebugger();
    143    }
    144    return this._dbg;
    145  }
    146 
    147  form() {
    148    if (!this._consoleActor) {
    149      this._consoleActor = new WebConsoleActor(this.conn, this);
    150      this.manage(this._consoleActor);
    151    }
    152 
    153    if (!this.threadActor) {
    154      this.threadActor = new ThreadActor(this);
    155      this.manage(this.threadActor);
    156    }
    157    if (!this.memoryActor) {
    158      this.memoryActor = new MemoryActor(this.conn, this);
    159      this.manage(this.memoryActor);
    160    }
    161    if (!this.tracerActor) {
    162      this.tracerActor = new TracerActor(this.conn, this);
    163      this.manage(this.tracerActor);
    164    }
    165 
    166    return {
    167      actor: this.actorID,
    168      targetType: this.targetType,
    169 
    170      isXpcShellTarget: this.isXpcShellTarget,
    171      processID: Services.appinfo.processID,
    172      remoteType: Services.appinfo.remoteType,
    173 
    174      consoleActor: this._consoleActor.actorID,
    175      memoryActor: this.memoryActor.actorID,
    176      threadActor: this.threadActor.actorID,
    177      tracerActor: this.tracerActor.actorID,
    178 
    179      traits: {
    180        networkMonitor: false,
    181        // See trait description in browsing-context.js
    182        supportsTopLevelTargetFlag: false,
    183      },
    184    };
    185  }
    186 
    187  ensureWorkerList() {
    188    if (!this._workerList) {
    189      this._workerList = new WorkerDescriptorActorList(this.conn, {});
    190    }
    191    return this._workerList;
    192  }
    193 
    194  listWorkers() {
    195    return this.ensureWorkerList()
    196      .getList()
    197      .then(actors => {
    198        const pool = new Pool(this.conn, "workers");
    199        for (const actor of actors) {
    200          pool.manage(actor);
    201        }
    202 
    203        // Do not destroy the pool before transfering ownership to the newly created
    204        // pool, so that we do not accidentally destroy actors that are still in use.
    205        if (this._workerDescriptorActorPool) {
    206          this._workerDescriptorActorPool.destroy();
    207        }
    208 
    209        this._workerDescriptorActorPool = pool;
    210        this._workerList.onListChanged = this._onWorkerListChanged;
    211 
    212        return { workers: actors };
    213      });
    214  }
    215 
    216  _onWorkerListChanged() {
    217    this.conn.send({ from: this.actorID, type: "workerListChanged" });
    218    this._workerList.onListChanged = null;
    219  }
    220 
    221  pauseMatchingServiceWorkers(request) {
    222    this.ensureWorkerList().workerPauser.setPauseServiceWorkers(request.origin);
    223  }
    224 
    225  destroy({ isModeSwitching } = {}) {
    226    // Avoid reentrancy. We will destroy the Transport when emitting "destroyed",
    227    // which will force destroying all actors.
    228    if (this.destroying) {
    229      return;
    230    }
    231    this.destroying = true;
    232 
    233    // Unregistering watchers first is important
    234    // otherwise you might have leaks reported when running browser_browser_toolbox_netmonitor.js in debug builds
    235    Resources.unwatchAllResources(this);
    236 
    237    this.emit("destroyed", { isModeSwitching });
    238 
    239    super.destroy();
    240 
    241    if (this.threadActor) {
    242      this.threadActor = null;
    243    }
    244 
    245    // Tell the live lists we aren't watching any more.
    246    if (this._workerList) {
    247      this._workerList.destroy();
    248      this._workerList = null;
    249    }
    250 
    251    if (this._sourcesManager) {
    252      this._sourcesManager.destroy();
    253      this._sourcesManager = null;
    254    }
    255 
    256    if (this._dbg) {
    257      this._dbg.disable();
    258      this._dbg = null;
    259    }
    260 
    261    Services.obs.removeObserver(this.destroyObserver, "xpcom-shutdown");
    262 
    263    if (this.isXpcShellTarget) {
    264      TargetActorRegistry.unregisterXpcShellTargetActor(this);
    265    }
    266  }
    267 }
    268 
    269 exports.ContentProcessTargetActor = ContentProcessTargetActor;