summaryrefslogtreecommitdiffstats
path: root/devtools/server/actors/targets/content-process.js
diff options
context:
space:
mode:
Diffstat (limited to 'devtools/server/actors/targets/content-process.js')
-rw-r--r--devtools/server/actors/targets/content-process.js242
1 files changed, 242 insertions, 0 deletions
diff --git a/devtools/server/actors/targets/content-process.js b/devtools/server/actors/targets/content-process.js
new file mode 100644
index 0000000000..0da23e766e
--- /dev/null
+++ b/devtools/server/actors/targets/content-process.js
@@ -0,0 +1,242 @@
+/* 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 all resources in a content process of Firefox (chrome sandboxes, frame
+ * scripts, documents, etc.)
+ *
+ * See devtools/docs/backend/actor-hierarchy.md for more details.
+ */
+
+const { Cc, Ci, Cu } = require("chrome");
+const Services = require("Services");
+
+const { ThreadActor } = require("devtools/server/actors/thread");
+const { WebConsoleActor } = require("devtools/server/actors/webconsole");
+const makeDebugger = require("devtools/server/actors/utils/make-debugger");
+const { Pool } = require("devtools/shared/protocol");
+const { assert } = require("devtools/shared/DevToolsUtils");
+const {
+ SourcesManager,
+} = require("devtools/server/actors/utils/sources-manager");
+const { Actor } = require("devtools/shared/protocol");
+const {
+ contentProcessTargetSpec,
+} = require("devtools/shared/specs/targets/content-process");
+const Targets = require("devtools/server/actors/targets/index");
+const Resources = require("devtools/server/actors/resources/index");
+const TargetActorMixin = require("devtools/server/actors/targets/target-actor-mixin");
+
+loader.lazyRequireGetter(
+ this,
+ "WorkerDescriptorActorList",
+ "devtools/server/actors/worker/worker-descriptor-actor-list",
+ true
+);
+loader.lazyRequireGetter(
+ this,
+ "MemoryActor",
+ "devtools/server/actors/memory",
+ true
+);
+
+const ContentProcessTargetActor = TargetActorMixin(
+ Targets.TYPES.PROCESS,
+ contentProcessTargetSpec,
+ {
+ initialize: function(connection) {
+ Actor.prototype.initialize.call(this, connection);
+ this.conn = connection;
+ this.threadActor = null;
+
+ // Use a see-everything debugger
+ this.makeDebugger = makeDebugger.bind(null, {
+ findDebuggees: dbg => dbg.findAllGlobals(),
+ shouldAddNewGlobalAsDebuggee: global => true,
+ });
+
+ const sandboxPrototype = {
+ get tabs() {
+ return Array.from(
+ Services.ww.getWindowEnumerator(),
+ win => win.docShell.messageManager
+ );
+ },
+ };
+
+ // Scope into which the webconsole executes:
+ // A sandbox with chrome privileges with a `tabs` getter.
+ const systemPrincipal = Cc[
+ "@mozilla.org/systemprincipal;1"
+ ].createInstance(Ci.nsIPrincipal);
+ const sandbox = Cu.Sandbox(systemPrincipal, {
+ sandboxPrototype,
+ wantGlobalProperties: ["ChromeUtils"],
+ });
+ this._consoleScope = sandbox;
+
+ this._workerList = null;
+ this._workerDescriptorActorPool = null;
+ this._onWorkerListChanged = this._onWorkerListChanged.bind(this);
+
+ // Try to destroy the Content Process Target when the content process shuts down.
+ // The parent process can't communicate during shutdown as the communication channel
+ // is already down (message manager or JS Window Actor API).
+ // So that we have to observe to some event fired from this process.
+ // While such cleanup doesn't sound ultimately necessary (the process will be completely destroyed)
+ // mochitests are asserting that there is no leaks during process shutdown.
+ // Do not override destroy as Protocol.js may override it when calling destroy,
+ // and we won't be able to call removeObserver correctly.
+ this.destroyObserver = this.destroy.bind(this);
+ Services.obs.addObserver(this.destroyObserver, "xpcom-shutdown");
+ },
+
+ get isRootActor() {
+ return true;
+ },
+
+ get exited() {
+ return !this._contextPool;
+ },
+
+ get url() {
+ return undefined;
+ },
+
+ get window() {
+ return this._consoleScope;
+ },
+
+ get sourcesManager() {
+ if (!this._sourcesManager) {
+ assert(
+ this.threadActor,
+ "threadActor should exist when creating SourcesManager."
+ );
+ this._sourcesManager = new SourcesManager(this.threadActor);
+ }
+ return this._sourcesManager;
+ },
+
+ /*
+ * Return a Debugger instance or create one if there is none yet
+ */
+ get dbg() {
+ if (!this._dbg) {
+ this._dbg = this.makeDebugger();
+ }
+ return this._dbg;
+ },
+
+ form: function() {
+ if (!this._consoleActor) {
+ this._consoleActor = new WebConsoleActor(this.conn, this);
+ this.manage(this._consoleActor);
+ }
+
+ if (!this.threadActor) {
+ this.threadActor = new ThreadActor(this, null);
+ this.manage(this.threadActor);
+ }
+ if (!this.memoryActor) {
+ this.memoryActor = new MemoryActor(this.conn, this);
+ this.manage(this.memoryActor);
+ }
+
+ return {
+ actor: this.actorID,
+ consoleActor: this._consoleActor.actorID,
+ threadActor: this.threadActor.actorID,
+ memoryActor: this.memoryActor.actorID,
+ processID: Services.appinfo.processID,
+
+ traits: {
+ networkMonitor: false,
+ },
+ };
+ },
+
+ ensureWorkerList() {
+ if (!this._workerList) {
+ this._workerList = new WorkerDescriptorActorList(this.conn, {});
+ }
+ return this._workerList;
+ },
+
+ listWorkers: function() {
+ return this.ensureWorkerList()
+ .getList()
+ .then(actors => {
+ const pool = new Pool(this.conn, "workers");
+ for (const actor of actors) {
+ pool.manage(actor);
+ }
+
+ // Do not destroy the pool before transfering ownership to the newly created
+ // pool, so that we do not accidentally destroy actors that are still in use.
+ if (this._workerDescriptorActorPool) {
+ this._workerDescriptorActorPool.destroy();
+ }
+
+ this._workerDescriptorActorPool = pool;
+ this._workerList.onListChanged = this._onWorkerListChanged;
+
+ return {
+ from: this.actorID,
+ workers: actors,
+ };
+ });
+ },
+
+ _onWorkerListChanged: function() {
+ this.conn.send({ from: this.actorID, type: "workerListChanged" });
+ this._workerList.onListChanged = null;
+ },
+
+ pauseMatchingServiceWorkers(request) {
+ this.ensureWorkerList().workerPauser.setPauseServiceWorkers(
+ request.origin
+ );
+ },
+
+ destroy: function() {
+ if (this.isDestroyed()) {
+ return;
+ }
+ Resources.unwatchAllTargetResources(this);
+
+ // Notify the client that this target is being destroyed.
+ // So that we can destroy the target front and all its children.
+ this.emit("tabDetached");
+
+ Actor.prototype.destroy.call(this);
+
+ if (this.threadActor) {
+ this.threadActor = null;
+ }
+
+ // Tell the live lists we aren't watching any more.
+ if (this._workerList) {
+ this._workerList.destroy();
+ this._workerList = null;
+ }
+
+ if (this._sourcesManager) {
+ this._sourcesManager.destroy();
+ this._sourcesManager = null;
+ }
+
+ if (this._dbg) {
+ this._dbg.disable();
+ this._dbg = null;
+ }
+
+ Services.obs.removeObserver(this.destroyObserver, "xpcom-shutdown");
+ },
+ }
+);
+
+exports.ContentProcessTargetActor = ContentProcessTargetActor;