diff options
Diffstat (limited to 'devtools/server/connectors')
10 files changed, 655 insertions, 38 deletions
diff --git a/devtools/server/connectors/content-process-connector.js b/devtools/server/connectors/content-process-connector.js index ea95a5d6ab..a2d359e4a5 100644 --- a/devtools/server/connectors/content-process-connector.js +++ b/devtools/server/connectors/content-process-connector.js @@ -109,13 +109,11 @@ function connectToContentProcess(connection, mm, onDestroy) { } } - const onMessageManagerClose = DevToolsUtils.makeInfallible( - (subject, topic, data) => { - if (subject == mm) { - onClose(); - } + const onMessageManagerClose = DevToolsUtils.makeInfallible(subject => { + if (subject == mm) { + onClose(); } - ); + }); Services.obs.addObserver(onMessageManagerClose, "message-manager-close"); EventEmitter.on(connection, "closed", onClose); diff --git a/devtools/server/connectors/frame-connector.js b/devtools/server/connectors/frame-connector.js index 789d405d90..06fbcfd1e4 100644 --- a/devtools/server/connectors/frame-connector.js +++ b/devtools/server/connectors/frame-connector.js @@ -149,7 +149,7 @@ function connectToFrame( trackMessageManager(); // Listen for app process exit - const onMessageManagerClose = function (subject, topic, data) { + const onMessageManagerClose = function (subject) { if (subject == mm) { destroy(); } diff --git a/devtools/server/connectors/js-process-actor/DevToolsProcessChild.sys.mjs b/devtools/server/connectors/js-process-actor/DevToolsProcessChild.sys.mjs new file mode 100644 index 0000000000..9e8ad64eea --- /dev/null +++ b/devtools/server/connectors/js-process-actor/DevToolsProcessChild.sys.mjs @@ -0,0 +1,362 @@ +/* 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/. */ + +import { EventEmitter } from "resource://gre/modules/EventEmitter.sys.mjs"; + +const lazy = {}; +ChromeUtils.defineESModuleGetters( + lazy, + { + releaseDistinctSystemPrincipalLoader: + "resource://devtools/shared/loader/DistinctSystemPrincipalLoader.sys.mjs", + useDistinctSystemPrincipalLoader: + "resource://devtools/shared/loader/DistinctSystemPrincipalLoader.sys.mjs", + }, + { global: "contextual" } +); + +// Name of the attribute into which we save data in `sharedData` object. +const SHARED_DATA_KEY_NAME = "DevTools:watchedPerWatcher"; + +// If true, log info about DOMProcess's being created. +const DEBUG = false; + +/** + * Print information about operation being done against each content process. + * + * @param {nsIDOMProcessChild} domProcessChild + * The process for which we should log a message. + * @param {String} message + * Message to log. + */ +function logDOMProcess(domProcessChild, message) { + if (!DEBUG) { + return; + } + dump(" [pid:" + domProcessChild + "] " + message + "\n"); +} + +export class DevToolsProcessChild extends JSProcessActorChild { + constructor() { + super(); + + // The map is indexed by the Watcher Actor ID. + // The values are objects containing the following properties: + // - connection: the DevToolsServerConnection itself + // - actor: the ContentProcessTargetActor instance + this._connections = new Map(); + + this._onConnectionChange = this._onConnectionChange.bind(this); + EventEmitter.decorate(this); + } + + instantiate() { + const { sharedData } = Services.cpmm; + const watchedDataByWatcherActor = sharedData.get(SHARED_DATA_KEY_NAME); + if (!watchedDataByWatcherActor) { + throw new Error( + "Request to instantiate the target(s) for the process, but `sharedData` is empty about watched targets" + ); + } + + // Create one Target actor for each prefix/client which listen to processes + for (const [watcherActorID, sessionData] of watchedDataByWatcherActor) { + const { connectionPrefix } = sessionData; + + if (sessionData.targets?.includes("process")) { + this._createTargetActor(watcherActorID, connectionPrefix, sessionData); + } + } + } + + /** + * Instantiate a new ProcessTarget for the given connection. + * + * @param String watcherActorID + * The ID of the WatcherActor who requested to observe and create these target actors. + * @param String parentConnectionPrefix + * The prefix of the DevToolsServerConnection of the Watcher Actor. + * This is used to compute a unique ID for the target actor. + * @param Object sessionData + * All data managed by the Watcher Actor and WatcherRegistry.sys.mjs, containing + * target types, resources types to be listened as well as breakpoints and any + * other data meant to be shared across processes and threads. + */ + _createTargetActor(watcherActorID, parentConnectionPrefix, sessionData) { + // This method will be concurrently called from `observe()` and `DevToolsProcessParent:instantiate-already-available` + // When the JSprocessActor initializes itself and when the watcher want to force instantiating existing targets. + // Simply ignore the second call as there is nothing to return, neither to wait for as this method is synchronous. + if (this._connections.has(watcherActorID)) { + return; + } + + // Compute a unique prefix, just for this DOM Process, + // which will be used to create a JSWindowActorTransport pair between content and parent processes. + // This is slightly hacky as we typicaly compute Prefix and Actor ID via `DevToolsServerConnection.allocID()`, + // but here, we can't have access to any DevTools connection as we are really early in the content process startup + // XXX: nsIDOMProcessChild's childID should be unique across processes, I think. So that should be safe? + // (this.manager == nsIDOMProcessChild interface) + // Ensure appending a final slash, otherwise the prefix may be the same between childID 1 and 10... + const forwardingPrefix = + parentConnectionPrefix + "contentProcess" + this.manager.childID + "/"; + + logDOMProcess( + this.manager, + "Instantiate ContentProcessTarget with prefix: " + forwardingPrefix + ); + + const { connection, targetActor } = this._createConnectionAndActor( + watcherActorID, + forwardingPrefix, + sessionData + ); + this._connections.set(watcherActorID, { + connection, + actor: targetActor, + }); + + // Immediately queue a message for the parent process, + // in order to ensure that the JSWindowActorTransport is instantiated + // before any packet is sent from the content process. + // As the order of messages is guaranteed to be delivered in the order they + // were queued, we don't have to wait for anything around this sendAsyncMessage call. + // In theory, the ContentProcessTargetActor may emit events in its constructor. + // If it does, such RDP packets may be lost. But in practice, no events + // are emitted during its construction. Instead the frontend will start + // the communication first. + this.sendAsyncMessage("DevToolsProcessChild:connectFromContent", { + watcherActorID, + forwardingPrefix, + actor: targetActor.form(), + }); + + // Pass initialization data to the target actor + for (const type in sessionData) { + // `sessionData` will also contain `browserId` as well as entries with empty arrays, + // which shouldn't be processed. + const entries = sessionData[type]; + if (!Array.isArray(entries) || !entries.length) { + continue; + } + targetActor.addOrSetSessionDataEntry( + type, + sessionData[type], + false, + "set" + ); + } + } + + _destroyTargetActor(watcherActorID, isModeSwitching) { + const connectionInfo = this._connections.get(watcherActorID); + // This connection has already been cleaned? + if (!connectionInfo) { + throw new Error( + `Trying to destroy a target actor that doesn't exists, or has already been destroyed. Watcher Actor ID:${watcherActorID}` + ); + } + connectionInfo.connection.close({ isModeSwitching }); + this._connections.delete(watcherActorID); + if (this._connections.size == 0) { + this.didDestroy({ isModeSwitching }); + } + } + + _createConnectionAndActor(watcherActorID, forwardingPrefix, sessionData) { + if (!this.loader) { + this.loader = lazy.useDistinctSystemPrincipalLoader(this); + } + const { DevToolsServer } = this.loader.require( + "devtools/server/devtools-server" + ); + + const { ContentProcessTargetActor } = this.loader.require( + "devtools/server/actors/targets/content-process" + ); + + DevToolsServer.init(); + + // For browser content toolbox, we do need a regular root actor and all tab + // actors, but don't need all the "browser actors" that are only useful when + // debugging the parent process via the browser toolbox. + DevToolsServer.registerActors({ target: true }); + DevToolsServer.on("connectionchange", this._onConnectionChange); + + const connection = DevToolsServer.connectToParentWindowActor( + this, + forwardingPrefix, + "DevToolsProcessChild:packet" + ); + + // Create the actual target actor. + const targetActor = new ContentProcessTargetActor(connection, { + sessionContext: sessionData.sessionContext, + }); + // There is no root actor in content processes and so + // the target actor can't be managed by it, but we do have to manage + // the actor to have it working and be registered in the DevToolsServerConnection. + // We make it manage itself and become a top level actor. + targetActor.manage(targetActor); + + const form = targetActor.form(); + targetActor.once("destroyed", options => { + // This will destroy the content process one + this._destroyTargetActor(watcherActorID, options.isModeSwitching); + // And this will destroy the parent process one + try { + this.sendAsyncMessage("DevToolsProcessChild:destroy", { + actors: [ + { + watcherActorID, + form, + }, + ], + options, + }); + } catch (e) { + // Ignore exception when the JSProcessActorChild has already been destroyed. + // We often try to emit this message while the process is being destroyed, + // but sendAsyncMessage doesn't have time to complete and throws. + if ( + !e.message.includes("JSProcessActorChild cannot send at the moment") + ) { + throw e; + } + } + }); + + return { connection, targetActor }; + } + + /** + * Destroy the server once its last connection closes. Note that multiple + * frame scripts may be running in parallel and reuse the same server. + */ + _onConnectionChange() { + if (this._destroyed) { + return; + } + this._destroyed = true; + + const { DevToolsServer } = this.loader.require( + "devtools/server/devtools-server" + ); + + // Only destroy the server if there is no more connections to it. It may be + // used to debug another tab running in the same process. + if (DevToolsServer.hasConnection() || DevToolsServer.keepAlive) { + return; + } + + DevToolsServer.off("connectionchange", this._onConnectionChange); + DevToolsServer.destroy(); + } + + /** + * Supported Queries + */ + + sendPacket(packet, prefix) { + this.sendAsyncMessage("DevToolsProcessChild:packet", { packet, prefix }); + } + + /** + * JsWindowActor API + */ + + async sendQuery(msg, args) { + try { + const res = await super.sendQuery(msg, args); + return res; + } catch (e) { + console.error("Failed to sendQuery in DevToolsProcessChild", msg); + console.error(e.toString()); + throw e; + } + } + + receiveMessage(message) { + switch (message.name) { + case "DevToolsProcessParent:instantiate-already-available": { + const { watcherActorID, connectionPrefix, sessionData } = message.data; + return this._createTargetActor( + watcherActorID, + connectionPrefix, + sessionData + ); + } + case "DevToolsProcessParent:destroy": { + const { watcherActorID, isModeSwitching } = message.data; + return this._destroyTargetActor(watcherActorID, isModeSwitching); + } + case "DevToolsProcessParent:addOrSetSessionDataEntry": { + const { watcherActorID, type, entries, updateType } = message.data; + return this._addOrSetSessionDataEntry( + watcherActorID, + type, + entries, + updateType + ); + } + case "DevToolsProcessParent:removeSessionDataEntry": { + const { watcherActorID, type, entries } = message.data; + return this._removeSessionDataEntry(watcherActorID, type, entries); + } + case "DevToolsProcessParent:packet": + return this.emit("packet-received", message); + default: + throw new Error( + "Unsupported message in DevToolsProcessParent: " + message.name + ); + } + } + + _getTargetActorForWatcherActorID(watcherActorID) { + const connectionInfo = this._connections.get(watcherActorID); + return connectionInfo?.actor; + } + + _addOrSetSessionDataEntry(watcherActorID, type, entries, updateType) { + const targetActor = this._getTargetActorForWatcherActorID(watcherActorID); + if (!targetActor) { + throw new Error( + `No target actor for this Watcher Actor ID:"${watcherActorID}"` + ); + } + return targetActor.addOrSetSessionDataEntry( + type, + entries, + false, + updateType + ); + } + + _removeSessionDataEntry(watcherActorID, type, entries) { + const targetActor = this._getTargetActorForWatcherActorID(watcherActorID); + // By the time we are calling this, the target may already have been destroyed. + if (!targetActor) { + return null; + } + return targetActor.removeSessionDataEntry(type, entries); + } + + observe(subject, topic) { + if (topic === "init-devtools-content-process-actor") { + // This is triggered by the process actor registration and some code in process-helper.js + // which defines a unique topic to be observed + this.instantiate(); + } + } + + didDestroy(options) { + for (const { connection } of this._connections.values()) { + connection.close(options); + } + this._connections.clear(); + if (this.loader) { + lazy.releaseDistinctSystemPrincipalLoader(this); + this.loader = null; + } + } +} diff --git a/devtools/server/connectors/js-process-actor/DevToolsProcessParent.sys.mjs b/devtools/server/connectors/js-process-actor/DevToolsProcessParent.sys.mjs new file mode 100644 index 0000000000..28e11def68 --- /dev/null +++ b/devtools/server/connectors/js-process-actor/DevToolsProcessParent.sys.mjs @@ -0,0 +1,256 @@ +/* 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/. */ + +import { loader } from "resource://devtools/shared/loader/Loader.sys.mjs"; +import { EventEmitter } from "resource://gre/modules/EventEmitter.sys.mjs"; + +const { WatcherRegistry } = ChromeUtils.importESModule( + "resource://devtools/server/actors/watcher/WatcherRegistry.sys.mjs", + // WatcherRegistry needs to be a true singleton and loads ActorManagerParent + // which also has to be a true singleton. + { global: "shared" } +); + +const lazy = {}; +loader.lazyRequireGetter( + lazy, + "JsWindowActorTransport", + "devtools/shared/transport/js-window-actor-transport", + true +); + +export class DevToolsProcessParent extends JSProcessActorParent { + constructor() { + super(); + + this._destroyed = false; + + // Map of DevToolsServerConnection's used to forward the messages from/to + // the client. The connections run in the parent process, as this code. We + // may have more than one when there is more than one client debugging the + // same frame. For example, a content toolbox and the browser toolbox. + // + // The map is indexed by the connection prefix. + // The values are objects containing the following properties: + // - actor: the frame target actor(as a form) + // - connection: the DevToolsServerConnection used to communicate with the + // frame target actor + // - prefix: the forwarding prefix used by the connection to know + // how to forward packets to the frame target + // - transport: the JsWindowActorTransport + // + // Reminder about prefixes: all DevToolsServerConnections have a `prefix` + // which can be considered as a kind of id. On top of this, parent process + // DevToolsServerConnections also have forwarding prefixes because they are + // responsible for forwarding messages to content process connections. + this._connections = new Map(); + + this._onConnectionClosed = this._onConnectionClosed.bind(this); + EventEmitter.decorate(this); + } + + /** + * Request the content process to create the ContentProcessTarget + */ + instantiateTarget({ + watcherActorID, + connectionPrefix, + sessionContext, + sessionData, + }) { + return this.sendQuery( + "DevToolsProcessParent:instantiate-already-available", + { + watcherActorID, + connectionPrefix, + sessionContext, + sessionData, + } + ); + } + + destroyTarget({ watcherActorID, isModeSwitching }) { + this.sendAsyncMessage("DevToolsProcessParent:destroy", { + watcherActorID, + isModeSwitching, + }); + } + + /** + * Communicate to the content process that some data have been added. + */ + addOrSetSessionDataEntry({ watcherActorID, type, entries, updateType }) { + return this.sendQuery("DevToolsProcessParent:addOrSetSessionDataEntry", { + watcherActorID, + type, + entries, + updateType, + }); + } + + /** + * Communicate to the content process that some data have been removed. + */ + removeSessionDataEntry({ watcherActorID, type, entries }) { + this.sendAsyncMessage("DevToolsProcessParent:removeSessionDataEntry", { + watcherActorID, + type, + entries, + }); + } + + connectFromContent({ watcherActorID, forwardingPrefix, actor }) { + const watcher = WatcherRegistry.getWatcher(watcherActorID); + + if (!watcher) { + throw new Error( + `Watcher Actor with ID '${watcherActorID}' can't be found.` + ); + } + const connection = watcher.conn; + + connection.on("closed", this._onConnectionClosed); + + // Create a js-window-actor based transport. + const transport = new lazy.JsWindowActorTransport( + this, + forwardingPrefix, + "DevToolsProcessParent:packet" + ); + transport.hooks = { + onPacket: connection.send.bind(connection), + onClosed() {}, + }; + transport.ready(); + + connection.setForwarding(forwardingPrefix, transport); + + this._connections.set(watcher.conn.prefix, { + watcher, + connection, + // This prefix is the prefix of the DevToolsServerConnection, running + // in the content process, for which we should forward packets to, based on its prefix. + // While `watcher.connection` is also a DevToolsServerConnection, but from this process, + // the parent process. It is the one receiving Client packets and the one, from which + // we should forward packets from. + forwardingPrefix, + transport, + actor, + }); + + watcher.notifyTargetAvailable(actor); + } + + _onConnectionClosed(status, prefix) { + if (this._connections.has(prefix)) { + const { connection } = this._connections.get(prefix); + this._cleanupConnection(connection); + } + } + + /** + * Close and unregister a given DevToolsServerConnection. + * + * @param {DevToolsServerConnection} connection + * @param {object} options + * @param {boolean} options.isModeSwitching + * true when this is called as the result of a change to the devtools.browsertoolbox.scope pref + */ + async _cleanupConnection(connection, options = {}) { + const connectionInfo = this._connections.get(connection.prefix); + if (!connectionInfo) { + return; + } + const { forwardingPrefix, transport } = connectionInfo; + + connection.off("closed", this._onConnectionClosed); + if (transport) { + // If we have a child transport, the actor has already + // been created. We need to stop using this transport. + transport.close(options); + } + + this._connections.delete(connection.prefix); + if (!this._connections.size) { + this._destroy(options); + } + + // When cancelling the forwarding, one RDP event is sent to the client to purge all requests + // and actors related to a given prefix. Do this *after* calling _destroy which will emit + // the target-destroyed RDP event. This helps the Watcher Front retrieve the related target front, + // otherwise it would be too eagerly destroyed by the purge event. + connection.cancelForwarding(forwardingPrefix); + } + + /** + * Destroy and cleanup everything for this DOM Process. + * + * @param {object} options + * @param {boolean} options.isModeSwitching + * true when this is called as the result of a change to the devtools.browsertoolbox.scope pref + */ + _destroy(options) { + if (this._destroyed) { + return; + } + this._destroyed = true; + + for (const { actor, connection, watcher } of this._connections.values()) { + watcher.notifyTargetDestroyed(actor, options); + this._cleanupConnection(connection, options); + } + } + + /** + * Supported Queries + */ + + sendPacket(packet, prefix) { + this.sendAsyncMessage("DevToolsProcessParent:packet", { packet, prefix }); + } + + /** + * JsWindowActor API + */ + + async sendQuery(msg, args) { + try { + const res = await super.sendQuery(msg, args); + return res; + } catch (e) { + console.error("Failed to sendQuery in DevToolsProcessParent", msg); + console.error(e.toString()); + throw e; + } + } + + receiveMessage(message) { + switch (message.name) { + case "DevToolsProcessChild:connectFromContent": + return this.connectFromContent(message.data); + case "DevToolsProcessChild:packet": + return this.emit("packet-received", message); + case "DevToolsProcessChild:destroy": + for (const { form, watcherActorID } of message.data.actors) { + const watcher = WatcherRegistry.getWatcher(watcherActorID); + // As we instruct to destroy all targets when the watcher is destroyed, + // we may easily receive the target destruction notification *after* + // the watcher has been removed from the registry. + if (watcher) { + watcher.notifyTargetDestroyed(form, message.data.options); + this._cleanupConnection(watcher.conn, message.data.options); + } + } + return null; + default: + throw new Error( + "Unsupported message in DevToolsProcessParent: " + message.name + ); + } + } + + didDestroy() { + this._destroy(); + } +} diff --git a/devtools/server/connectors/js-process-actor/moz.build b/devtools/server/connectors/js-process-actor/moz.build new file mode 100644 index 0000000000..e1a1f5dc9d --- /dev/null +++ b/devtools/server/connectors/js-process-actor/moz.build @@ -0,0 +1,10 @@ +# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- +# vim: set filetype=python: +# 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/. + +DevToolsModules( + "DevToolsProcessChild.sys.mjs", + "DevToolsProcessParent.sys.mjs", +) diff --git a/devtools/server/connectors/js-window-actor/DevToolsFrameChild.sys.mjs b/devtools/server/connectors/js-window-actor/DevToolsFrameChild.sys.mjs index 519cd10325..acb5e97110 100644 --- a/devtools/server/connectors/js-window-actor/DevToolsFrameChild.sys.mjs +++ b/devtools/server/connectors/js-window-actor/DevToolsFrameChild.sys.mjs @@ -173,7 +173,7 @@ export class DevToolsFrameChild extends JSWindowActorChild { * The prefix of the DevToolsServerConnection of the Watcher Actor. * This is used to compute a unique ID for the target actor. * @param Object options.sessionData - * All data managed by the Watcher Actor and WatcherRegistry.jsm, containing + * All data managed by the Watcher Actor and WatcherRegistry.sys.mjs, containing * target types, resources types to be listened as well as breakpoints and any * other data meant to be shared across processes and threads. * @param Boolean options.isDocumentCreation @@ -364,6 +364,10 @@ export class DevToolsFrameChild extends JSWindowActorChild { ignoreSubFrames: isEveryFrameTargetEnabled, sessionContext: sessionData.sessionContext, }); + // There is no root actor in content processes and so + // the target actor can't be managed by it, but we do have to manage + // the actor to have it working and be registered in the DevToolsServerConnection. + // We make it manage itself and become a top level actor. targetActor.manage(targetActor); targetActor.createdFromJsWindowActor = true; @@ -554,10 +558,10 @@ export class DevToolsFrameChild extends JSWindowActorChild { sessionContext, }); // By the time we are calling this, the target may already have been destroyed. - if (targetActor) { - return targetActor.removeSessionDataEntry(type, entries); + if (!targetActor) { + return null; } - return null; + return targetActor.removeSessionDataEntry(type, entries); } handleEvent({ type, persisted, target }) { @@ -691,8 +695,8 @@ export class DevToolsFrameChild extends JSWindowActorChild { didDestroy(options) { logWindowGlobal(this.manager, "Destroy WindowGlobalTarget"); - for (const [, connectionInfo] of this._connections) { - connectionInfo.connection.close(options); + for (const { connection } of this._connections.values()) { + connection.close(options); } this._connections.clear(); diff --git a/devtools/server/connectors/js-window-actor/DevToolsFrameParent.sys.mjs b/devtools/server/connectors/js-window-actor/DevToolsFrameParent.sys.mjs index 3c5af2a724..31750d58e4 100644 --- a/devtools/server/connectors/js-window-actor/DevToolsFrameParent.sys.mjs +++ b/devtools/server/connectors/js-window-actor/DevToolsFrameParent.sys.mjs @@ -7,11 +7,9 @@ import { EventEmitter } from "resource://gre/modules/EventEmitter.sys.mjs"; const { WatcherRegistry } = ChromeUtils.importESModule( "resource://devtools/server/actors/watcher/WatcherRegistry.sys.mjs", - { - // WatcherRegistry needs to be a true singleton and loads ActorManagerParent - // which also has to be a true singleton. - loadInDevToolsLoader: false, - } + // WatcherRegistry needs to be a true singleton and loads ActorManagerParent + // which also has to be a true singleton. + { global: "shared" } ); const lazy = {}; diff --git a/devtools/server/connectors/js-window-actor/DevToolsWorkerParent.sys.mjs b/devtools/server/connectors/js-window-actor/DevToolsWorkerParent.sys.mjs index ebe3d10ad5..cb9bffc2ca 100644 --- a/devtools/server/connectors/js-window-actor/DevToolsWorkerParent.sys.mjs +++ b/devtools/server/connectors/js-window-actor/DevToolsWorkerParent.sys.mjs @@ -7,11 +7,9 @@ import { EventEmitter } from "resource://gre/modules/EventEmitter.sys.mjs"; const { WatcherRegistry } = ChromeUtils.importESModule( "resource://devtools/server/actors/watcher/WatcherRegistry.sys.mjs", - { - // WatcherRegistry needs to be a true singleton and loads ActorManagerParent - // which also has to be a true singleton. - loadInDevToolsLoader: false, - } + // WatcherRegistry needs to be a true singleton and loads ActorManagerParent + // which also has to be a true singleton. + { global: "shared" } ); const lazy = {}; @@ -175,11 +173,7 @@ export class DevToolsWorkerParent extends JSWindowActorParent { watcher.notifyTargetAvailable(workerTargetForm); } - workerTargetDestroyed({ - watcherActorID, - forwardingPrefix, - workerTargetForm, - }) { + workerTargetDestroyed({ watcherActorID, workerTargetForm }) { const watcher = WatcherRegistry.getWatcher(watcherActorID); if (!watcher) { diff --git a/devtools/server/connectors/moz.build b/devtools/server/connectors/moz.build index a8b6fa1fea..fd4baf81ff 100644 --- a/devtools/server/connectors/moz.build +++ b/devtools/server/connectors/moz.build @@ -5,6 +5,7 @@ # file, You can obtain one at http://mozilla.org/MPL/2.0/. DIRS += [ + "js-process-actor", "js-window-actor", "process-actor", ] diff --git a/devtools/server/connectors/process-actor/DevToolsServiceWorkerParent.sys.mjs b/devtools/server/connectors/process-actor/DevToolsServiceWorkerParent.sys.mjs index 17fa89e7ac..2073f47e76 100644 --- a/devtools/server/connectors/process-actor/DevToolsServiceWorkerParent.sys.mjs +++ b/devtools/server/connectors/process-actor/DevToolsServiceWorkerParent.sys.mjs @@ -6,11 +6,9 @@ import { EventEmitter } from "resource://gre/modules/EventEmitter.sys.mjs"; const { WatcherRegistry } = ChromeUtils.importESModule( "resource://devtools/server/actors/watcher/WatcherRegistry.sys.mjs", - { - // WatcherRegistry needs to be a true singleton and loads ActorManagerParent - // which also has to be a true singleton. - loadInDevToolsLoader: false, - } + // WatcherRegistry needs to be a true singleton and loads ActorManagerParent + // which also has to be a true singleton. + { global: "shared" } ); const lazy = {}; @@ -185,11 +183,7 @@ export class DevToolsServiceWorkerParent extends JSProcessActorParent { watcher.notifyTargetAvailable(serviceWorkerTargetForm); } - serviceWorkerTargetDestroyed({ - watcherActorID, - forwardingPrefix, - serviceWorkerTargetForm, - }) { + serviceWorkerTargetDestroyed({ watcherActorID, serviceWorkerTargetForm }) { const watcher = WatcherRegistry.getWatcher(watcherActorID); if (!watcher) { |