Files
sousa-gecko/devtools/server/actors/descriptors/worker.js
T
Eden Chuang c7001b7dea Bug 1944240 - Derive relatedDocumentInnerWindowId from windowIDs for remote workers. r=jdescottes,devtools-reviewers
A remote worker has no window object in the process running DevTools, so
worker-connector derives the owning document's inner window id from windowIDs
(which carries it for dedicated workers) instead of dbg.window. Shared and
service workers have no single owning document, matching the previous
null-window behaviour.

Differential Revision: https://phabricator.services.mozilla.com/D306650
2026-07-07 20:20:06 +00:00

205 lines
5.1 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 any of the various kinds of workers.
*
* See devtools/docs/backend/actor-hierarchy.md for more details.
*/
// protocol.js uses objects as exceptions in order to define
// error packets.
/* eslint-disable no-throw-literal */
const { Actor } = require("resource://devtools/shared/protocol.js");
const {
workerDescriptorSpec,
} = require("resource://devtools/shared/specs/descriptors/worker.js");
const {
DevToolsServer,
} = require("resource://devtools/server/devtools-server.js");
const { XPCOMUtils } = ChromeUtils.importESModule(
"resource://gre/modules/XPCOMUtils.sys.mjs",
{ global: "contextual" }
);
const {
createWorkerSessionContext,
} = require("resource://devtools/server/actors/watcher/session-context.js");
loader.lazyRequireGetter(
this,
"connectToWorker",
"resource://devtools/server/connectors/worker-connector.js",
true
);
XPCOMUtils.defineLazyServiceGetter(
this,
"swm",
"@mozilla.org/serviceworkers/manager;1",
Ci.nsIServiceWorkerManager
);
class WorkerDescriptorActor extends Actor {
constructor(conn, dbg) {
super(conn, workerDescriptorSpec);
this._dbg = dbg;
this._threadActor = null;
this._transport = null;
this._dbgListener = {
onClose: this._onWorkerClose.bind(this),
onError: this._onWorkerError.bind(this),
};
this._dbg.addListener(this._dbgListener);
this._attached = true;
}
form() {
const form = {
actor: this.actorID,
consoleActor: this._consoleActor,
threadActor: this._threadActor,
tracerActor: this._tracerActor,
targetType: this._targetType,
id: this._dbg.id,
url: this._dbg.url,
origin: this._dbg.principal.origin,
traits: {},
type: this._dbg.type,
};
if (this._dbg.type === Ci.nsIWorkerDebugger.TYPE_SERVICE) {
/**
* The ServiceWorkerManager in content processes don't maintain
* ServiceWorkerRegistrations; record the ServiceWorker's ID, and
* this data will be merged with the corresponding registration in
* the parent process.
*/
if (!DevToolsServer.isInChildProcess) {
const registration = this._getServiceWorkerRegistrationInfo();
if (registration) {
form.scope = registration.scope;
const newestWorker =
registration.activeWorker ||
registration.waitingWorker ||
registration.installingWorker;
form.fetch = newestWorker?.handlesFetchEvents;
}
}
}
return form;
}
detach() {
if (!this._attached) {
throw { error: "wrongState" };
}
this.destroy();
}
destroy() {
if (this._attached) {
this._detach();
}
this.emit("descriptor-destroyed");
super.destroy();
}
async getTarget() {
if (!this._attached) {
return { error: "wrongState" };
}
if (this._threadActor !== null) {
return {
type: "connected",
consoleActor: this._consoleActor,
threadActor: this._threadActor,
tracerActor: this._tracerActor,
targetType: this._targetType,
};
}
try {
const { transport, workerTargetForm } = await connectToWorker(
this.conn,
this._dbg,
this.actorID,
{
sessionContext: createWorkerSessionContext(),
}
);
this._consoleActor = workerTargetForm.consoleActor;
this._threadActor = workerTargetForm.threadActor;
this._tracerActor = workerTargetForm.tracerActor;
this._targetType = workerTargetForm.targetType;
this._transport = transport;
return {
type: "connected",
consoleActor: this._consoleActor,
threadActor: this._threadActor,
tracerActor: this._tracerActor,
targetType: this._targetType,
url: this._dbg.url,
};
} catch (error) {
return { error: error.toString() };
}
}
_onWorkerClose() {
this.destroy();
}
_onWorkerError(filename, lineno, message) {
console.error("ERROR:", filename, ":", lineno, ":", message);
}
_getServiceWorkerRegistrationInfo() {
try {
return swm.getRegistrationByPrincipal(this._dbg.principal, this._dbg.url);
} catch (e) {
// getRegistrationByPrincipal throws NS_ERROR_FAILURE when there is no
// matching registration. With the parent-process worker debugger, a
// service worker debugger can be surfaced for enumeration while its
// registration is not (or no longer) available in this process, so treat a
// missing registration as "no info" rather than failing the whole
// listWorkers request.
return null;
}
}
_detach() {
if (this._threadActor !== null) {
this._transport.close();
this._transport = null;
this._threadActor = null;
}
this._dbg.removeListener(this._dbgListener);
this._attached = false;
}
}
exports.WorkerDescriptorActor = WorkerDescriptorActor;