From 0dab5c24b89c96e5e4732f0bbe23ba197e2986c5 Mon Sep 17 00:00:00 2001 From: Luca Greco Date: Wed, 26 Oct 2022 11:39:26 +0000 Subject: [PATCH] Bug 1796586 - Fix issue related to runtime.onStartup persistent listeners wrongly cleared on idle timeout. r=mixedpuppy Differential Revision: https://phabricator.services.mozilla.com/D160119 --- .../components/extensions/ExtensionCommon.jsm | 14 +++- ...t_ext_runtime_onInstalled_and_onStartup.js | 79 +++++++++++++++++++ 2 files changed, 92 insertions(+), 1 deletion(-) diff --git a/toolkit/components/extensions/ExtensionCommon.jsm b/toolkit/components/extensions/ExtensionCommon.jsm index acd63abf7e55..4f4357e15f6e 100644 --- a/toolkit/components/extensions/ExtensionCommon.jsm +++ b/toolkit/components/extensions/ExtensionCommon.jsm @@ -2370,12 +2370,24 @@ class EventManager { // Force this listener to be cleared. listener.error = true; } + // If an attempt to prime a listener failed, ensure it is cleared now. // If a module is a startup blocking module, not all listeners may // get primed during early startup. For that reason, we don't clear // persisted listeners during early startup. At the end of background // execution any listeners that were not renewed will be cleared. - if (listener.error || (!isInStartup && !listener.primed)) { + // + // TODO(Bug 1797474): consider priming runtime.onStartup and + // avoid to special handling it here. + if ( + listener.error || + (!isInStartup && + !( + (`${module}.${event}` === "runtime.onStartup" && + listener.added) || + listener.primed + )) + ) { EventManager.clearPersistentListener(extension, module, event, key); } } diff --git a/toolkit/components/extensions/test/xpcshell/test_ext_runtime_onInstalled_and_onStartup.js b/toolkit/components/extensions/test/xpcshell/test_ext_runtime_onInstalled_and_onStartup.js index 05174e5dbca6..5caab3279b51 100644 --- a/toolkit/components/extensions/test/xpcshell/test_ext_runtime_onInstalled_and_onStartup.js +++ b/toolkit/components/extensions/test/xpcshell/test_ext_runtime_onInstalled_and_onStartup.js @@ -518,3 +518,82 @@ add_task( await promiseShutdownManager(); } ); + +// Verify we don't regress the issue related to runtime.onStartup persistent +// listener being cleared from the startup data as part of priming all listeners +// while terminating the event page on idle timeout (Bug 1796586). +add_task( + { + pref_set: [["extensions.eventPages.enabled", true]], + }, + async function test_runtime_onStartup_eventpage() { + const EXTENSION_ID = "test_eventpage_onStartup@tests.mozilla.org"; + + await promiseStartupManager(); + + let extension = ExtensionTestUtils.loadExtension({ + useAddonManager: "permanent", + manifest: { + version: "1.0", + browser_specific_settings: { + gecko: { + id: EXTENSION_ID, + }, + }, + permissions: ["browserSettings"], + background: { + persistent: false, + }, + }, + background, + }); + + await extension.startup(); + + await expectEvents(extension, { + onStartupFired: false, + onInstalledFired: true, + onInstalledReason: "install", + onInstalledTemporary: false, + }); + + info("Simulated idle timeout"); + extension.terminateBackground(); + await extension.awaitMessage("suspended"); + await promiseExtensionEvent(extension, "shutdown-background-script"); + + // onStartup remains persisted, but not primed + assertPersistentListeners(extension, "runtime", "onStartup", { + primed: false, + persisted: true, + }); + + info(`test onStartup filed after restart`); + await promiseRestartManager(); + + // onStartup is a bit special. During APP_STARTUP we do not + // prime this, we just start since it needs to. + assertPersistentListeners(extension, "runtime", "onStartup", { + primed: false, + persisted: true, + }); + await extension.awaitBackgroundStarted(); + + info("test expectEvents"); + await expectEvents(extension, { + onStartupFired: true, + onInstalledFired: false, + }); + + extension.terminateBackground(); + await extension.awaitMessage("suspended"); + await promiseExtensionEvent(extension, "shutdown-background-script"); + assertPersistentListeners(extension, "runtime", "onStartup", { + primed: false, + persisted: true, + }); + + await extension.unload(); + await promiseShutdownManager(); + } +);