269 lines
7.9 KiB
JavaScript
269 lines
7.9 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 all resources in a content process of IceCat (chrome sandboxes, frame
|
|
* scripts, documents, etc.)
|
|
*
|
|
* See devtools/docs/contributor/backend/actor-hierarchy.md for more details about all the targets.
|
|
*/
|
|
|
|
const { ThreadActor } = require("resource://devtools/server/actors/thread.js");
|
|
const {
|
|
WebConsoleActor,
|
|
} = require("resource://devtools/server/actors/webconsole.js");
|
|
const makeDebugger = require("resource://devtools/server/actors/utils/make-debugger.js");
|
|
const { Pool } = require("resource://devtools/shared/protocol.js");
|
|
const { assert } = require("resource://devtools/shared/DevToolsUtils.js");
|
|
const {
|
|
SourcesManager,
|
|
} = require("resource://devtools/server/actors/utils/sources-manager.js");
|
|
const {
|
|
contentProcessTargetSpec,
|
|
} = require("resource://devtools/shared/specs/targets/content-process.js");
|
|
const Targets = require("resource://devtools/server/actors/targets/index.js");
|
|
const Resources = require("resource://devtools/server/actors/resources/index.js");
|
|
const {
|
|
BaseTargetActor,
|
|
} = require("resource://devtools/server/actors/targets/base-target-actor.js");
|
|
const { TargetActorRegistry } = ChromeUtils.importESModule(
|
|
"resource://devtools/server/actors/targets/target-actor-registry.sys.mjs",
|
|
{ global: "shared" }
|
|
);
|
|
|
|
loader.lazyRequireGetter(
|
|
this,
|
|
"WorkerDescriptorActorList",
|
|
"resource://devtools/server/actors/worker/worker-descriptor-actor-list.js",
|
|
true
|
|
);
|
|
loader.lazyRequireGetter(
|
|
this,
|
|
"MemoryActor",
|
|
"resource://devtools/server/actors/memory.js",
|
|
true
|
|
);
|
|
loader.lazyRequireGetter(
|
|
this,
|
|
"TracerActor",
|
|
"resource://devtools/server/actors/tracer.js",
|
|
true
|
|
);
|
|
|
|
class ContentProcessTargetActor extends BaseTargetActor {
|
|
constructor(conn, { isXpcShellTarget = false, sessionContext } = {}) {
|
|
super(conn, Targets.TYPES.PROCESS, contentProcessTargetSpec);
|
|
|
|
this.threadActor = null;
|
|
this.isXpcShellTarget = isXpcShellTarget;
|
|
this.sessionContext = sessionContext;
|
|
|
|
// Use a see-everything debugger
|
|
this.makeDebugger = makeDebugger.bind(null, {
|
|
findDebuggees: dbg =>
|
|
dbg.findAllGlobals().map(g => g.unsafeDereference()),
|
|
shouldAddNewGlobalAsDebuggee: () => 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");
|
|
if (this.isXpcShellTarget) {
|
|
TargetActorRegistry.registerXpcShellTargetActor(this);
|
|
}
|
|
}
|
|
|
|
get isRootActor() {
|
|
return true;
|
|
}
|
|
|
|
get url() {
|
|
return undefined;
|
|
}
|
|
|
|
get window() {
|
|
return this._consoleScope;
|
|
}
|
|
|
|
get targetGlobal() {
|
|
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() {
|
|
if (!this._consoleActor) {
|
|
this._consoleActor = new WebConsoleActor(this.conn, this);
|
|
this.manage(this._consoleActor);
|
|
}
|
|
|
|
if (!this.threadActor) {
|
|
this.threadActor = new ThreadActor(this);
|
|
this.manage(this.threadActor);
|
|
}
|
|
if (!this.memoryActor) {
|
|
this.memoryActor = new MemoryActor(this.conn, this);
|
|
this.manage(this.memoryActor);
|
|
}
|
|
if (!this.tracerActor) {
|
|
this.tracerActor = new TracerActor(this.conn, this);
|
|
this.manage(this.tracerActor);
|
|
}
|
|
|
|
return {
|
|
actor: this.actorID,
|
|
targetType: this.targetType,
|
|
|
|
isXpcShellTarget: this.isXpcShellTarget,
|
|
processID: Services.appinfo.processID,
|
|
remoteType: Services.appinfo.remoteType,
|
|
|
|
consoleActor: this._consoleActor.actorID,
|
|
memoryActor: this.memoryActor.actorID,
|
|
threadActor: this.threadActor.actorID,
|
|
tracerActor: this.tracerActor.actorID,
|
|
|
|
traits: {
|
|
networkMonitor: false,
|
|
// See trait description in browsing-context.js
|
|
supportsTopLevelTargetFlag: false,
|
|
},
|
|
};
|
|
}
|
|
|
|
ensureWorkerList() {
|
|
if (!this._workerList) {
|
|
this._workerList = new WorkerDescriptorActorList(this.conn, {});
|
|
}
|
|
return this._workerList;
|
|
}
|
|
|
|
listWorkers() {
|
|
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 { workers: actors };
|
|
});
|
|
}
|
|
|
|
_onWorkerListChanged() {
|
|
this.conn.send({ from: this.actorID, type: "workerListChanged" });
|
|
this._workerList.onListChanged = null;
|
|
}
|
|
|
|
pauseMatchingServiceWorkers(request) {
|
|
this.ensureWorkerList().workerPauser.setPauseServiceWorkers(request.origin);
|
|
}
|
|
|
|
destroy({ isModeSwitching } = {}) {
|
|
// Avoid reentrancy. We will destroy the Transport when emitting "destroyed",
|
|
// which will force destroying all actors.
|
|
if (this.destroying) {
|
|
return;
|
|
}
|
|
this.destroying = true;
|
|
|
|
// Unregistering watchers first is important
|
|
// otherwise you might have leaks reported when running browser_browser_toolbox_netmonitor.js in debug builds
|
|
Resources.unwatchAllResources(this);
|
|
|
|
this.emit("destroyed", { isModeSwitching });
|
|
|
|
super.destroy();
|
|
|
|
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");
|
|
|
|
if (this.isXpcShellTarget) {
|
|
TargetActorRegistry.unregisterXpcShellTargetActor(this);
|
|
}
|
|
}
|
|
}
|
|
|
|
exports.ContentProcessTargetActor = ContentProcessTargetActor;
|