From 5b0e5053897f15a6e6f5bccc8f4274e060bad631 Mon Sep 17 00:00:00 2001 From: Rob Wu Date: Fri, 25 Mar 2022 22:24:11 +0000 Subject: [PATCH] Bug 1761072 - Replace use of ExtensionParent in devtools' ExtensionsBackgroundScriptStatusWatcher r=rpl,jdescottes ExtensionParent.jsm cannot be loaded without a profile, as explained at https://bugzilla.mozilla.org/show_bug.cgi?id=1761072#c5. But ExtensionsBackgroundScriptStatusWatcher would try to (lazily) load the module before a profile was ready, in order to subscribe to future changes. To avoid loading this whole ExtensionParent.jsm module, I have replaced the event propagation mechanism with observers. Differential Revision: https://phabricator.services.mozilla.com/D142065 --- .../extensions-backgroundscript-status.js | 34 ++++++++++-------- .../components/extensions/ExtensionParent.jsm | 11 ------ .../extensions/parent/ext-backgroundPage.js | 35 ++++++------------- 3 files changed, 30 insertions(+), 50 deletions(-) diff --git a/devtools/server/actors/resources/extensions-backgroundscript-status.js b/devtools/server/actors/resources/extensions-backgroundscript-status.js index a1c748985b98..2da0f88e2675 100644 --- a/devtools/server/actors/resources/extensions-backgroundscript-status.js +++ b/devtools/server/actors/resources/extensions-backgroundscript-status.js @@ -4,11 +4,7 @@ "use strict"; -loader.lazyImporter( - this, - "ExtensionParent", - "resource://gre/modules/ExtensionParent.jsm" -); +const Services = require("Services"); const { TYPES: { EXTENSIONS_BGSCRIPT_STATUS }, @@ -33,20 +29,25 @@ class ExtensionsBackgroundScriptStatusWatcher { * Dictionary object with following attributes: * - onAvailable: mandatory function * This will be called for each resource. - * - onUpdated: optional function - * This would be called multiple times for each resource. */ - async watch(rootActor, { onAvailable, onUpdated }) { + async watch(rootActor, { onAvailable }) { this.rootActor = rootActor; this.onAvailable = onAvailable; - this.onUpdated = onUpdated; - this.unwatchBackgroundStatusUpdates = ExtensionParent.DebugUtils.watchBackgroundScriptStatusUpdates( - this.onBackgroundScriptStatus - ); + Services.obs.addObserver(this, "extension:background-script-status"); } - onBackgroundScriptStatus = (addonId, isRunning) => { + observe(subject, topic, data) { + switch (topic) { + case "extension:background-script-status": { + const { addonId, isRunning } = subject.wrappedJSObject; + this.onBackgroundScriptStatus(addonId, isRunning); + break; + } + } + } + + onBackgroundScriptStatus(addonId, isRunning) { this.onAvailable([ { resourceType: EXTENSIONS_BGSCRIPT_STATUS, @@ -56,10 +57,13 @@ class ExtensionsBackgroundScriptStatusWatcher { }, }, ]); - }; + } destroy() { - this.unwatchBackgroundStatusUpdates?.(); + if (this.onAvailable) { + this.onAvailable = null; + Services.obs.removeObserver(this, "extension:background-script-status"); + } } } diff --git a/toolkit/components/extensions/ExtensionParent.jsm b/toolkit/components/extensions/ExtensionParent.jsm index de3282ae8ebf..44c081275445 100644 --- a/toolkit/components/extensions/ExtensionParent.jsm +++ b/toolkit/components/extensions/ExtensionParent.jsm @@ -1503,17 +1503,6 @@ const DebugUtils = { throw Error(`Unable to terminate background script for ${addonId}`); }, - watchBackgroundScriptStatusUpdates(callback) { - const listener = (_evtName, addonId, isRunning) => { - callback(addonId, isRunning); - }; - apiManager.on(`devtools:background-script-status`, listener); - - return () => { - apiManager.off(`devtools:background-script-status`, listener); - }; - }, - /** * Retrieve a XUL browser element which has been configured to be able to connect * the devtools actor with the process where the extension is running. diff --git a/toolkit/components/extensions/parent/ext-backgroundPage.js b/toolkit/components/extensions/parent/ext-backgroundPage.js index aa91f4636f35..31b444911348 100644 --- a/toolkit/components/extensions/parent/ext-backgroundPage.js +++ b/toolkit/components/extensions/parent/ext-backgroundPage.js @@ -40,6 +40,13 @@ XPCOMUtils.defineLazyPreferenceGetter( delay => Math.min(Math.max(delay, 100), 5 * 60 * 1000) ); +function notifyBackgroundScriptStatus(addonId, isRunning) { + // Notify devtools when the background scripts is started or stopped + // (used to show the current status in about:debugging). + const subject = { addonId, isRunning }; + Services.obs.notifyObservers(subject, "extension:background-script-status"); +} + // Responsible for the background_page section of the manifest. class BackgroundPage extends HiddenExtensionPage { constructor(extension, options) { @@ -100,20 +107,10 @@ class BackgroundPage extends HiddenExtensionPage { await Promise.all(context.listenerPromises); context.listenerPromises = null; - // Notify devtools when the background scripts is started or stopped - // (used to show the current status in about:debugging). - extensions.emit( - `devtools:background-script-status`, - extension.id, - true /* isRunning */ - ); + notifyBackgroundScriptStatus(extension.id, true); context.callOnClose({ close() { - extensions.emit( - `devtools:background-script-status`, - extension.id, - false /* isRunning */ - ); + notifyBackgroundScriptStatus(extension.id, false); }, }); } @@ -211,20 +208,10 @@ class BackgroundWorker { await Promise.all(context.listenerPromises); context.listenerPromises = null; - // Notify devtools when the background scripts is started or stopped - // (used to show the current status in about:debugging). - extensions.emit( - `devtools:background-script-status`, - extension.id, - true /* isRunning */ - ); + notifyBackgroundScriptStatus(extension.id, true); context.callOnClose({ close() { - extensions.emit( - `devtools:background-script-status`, - extension.id, - false /* isRunning */ - ); + notifyBackgroundScriptStatus(extension.id, false); }, }); }