From 802ff278409c55809b65b9e0c817181073be7ce4 Mon Sep 17 00:00:00 2001 From: Marco Castelluccio Date: Tue, 16 Jan 2024 00:40:30 +0000 Subject: [PATCH] Bug 1861445 - Add the runtime.onPerformanceWarning WebExtension event r=zombie When an extension's content script is very slow and causes a webpage to hang noticeably, a warning banner is displayed to the user. It would be useful to also notify the extension developer when that happens, so that they can address the issue. Let's add a new event runtime.onPerformanceWarning that can be dispatched when the browser needs to warn an extension of runtime performance issues. For now, let's just dispatch that event when the slow extension warning banner is displayed to the user. See also https://github.com/w3c/webextensions/issues/456 Differential Revision: https://phabricator.services.mozilla.com/D194708 UltraBlame original commit: 199b3c24b8b43b8053831d7c287bbe83e43037c4 --- .../extensions/test/browser/browser.toml | 7 + ...rowser_ext_runtime_onPerformanceWarning.js | 724 ++++++++++++++++++ .../extensions/parent/ext-runtime.js | 256 +++++++ .../extensions/schemas/runtime.json | 315 ++++++++ .../test/mochitest/test_ext_all_apis.js | 15 + 5 files changed, 1317 insertions(+) create mode 100644 browser/components/extensions/test/browser/browser_ext_runtime_onPerformanceWarning.js diff --git a/browser/components/extensions/test/browser/browser.toml b/browser/components/extensions/test/browser/browser.toml index 13dba2e334c4b..4cf81c94cf45e 100644 --- a/browser/components/extensions/test/browser/browser.toml +++ b/browser/components/extensions/test/browser/browser.toml @@ -2025,6 +2025,13 @@ js ] [ " +browser_ext_runtime_onPerformanceWarning +. +js +" +] +[ +" browser_ext_runtime_openOptionsPage . js diff --git a/browser/components/extensions/test/browser/browser_ext_runtime_onPerformanceWarning.js b/browser/components/extensions/test/browser/browser_ext_runtime_onPerformanceWarning.js new file mode 100644 index 0000000000000..d3182fd9cf924 --- /dev/null +++ b/browser/components/extensions/test/browser/browser_ext_runtime_onPerformanceWarning.js @@ -0,0 +1,724 @@ +/ +* +- +* +- +Mode +: +indent +- +tabs +- +mode +: +nil +; +js +- +indent +- +level +: +2 +- +* +- +* +/ +/ +* +vim +: +set +sts += +2 +sw += +2 +et +tw += +80 +: +* +/ +" +use +strict +" +; +const +{ +Management +: +{ +global +: +{ +tabTracker +} +} +} += +ChromeUtils +. +importESModule +( +" +resource +: +/ +/ +gre +/ +modules +/ +Extension +. +sys +. +mjs +" +) +; +const +{ +ExtensionUtils +: +{ +promiseObserved +} +} += +ChromeUtils +. +importESModule +( +" +resource +: +/ +/ +gre +/ +modules +/ +ExtensionUtils +. +sys +. +mjs +" +) +; +class +TestHangReport +{ +constructor +( +addonId +scriptBrowser +) +{ +this +. +addonId += +addonId +; +this +. +scriptBrowser += +scriptBrowser +; +this +. +QueryInterface += +ChromeUtils +. +generateQI +( +[ +" +nsIHangReport +" +] +) +; +} +} +function +dispatchHangReport +( +extensionId +scriptBrowser +) +{ +const +hangObserved += +promiseObserved +( +" +process +- +hang +- +report +" +) +; +Services +. +obs +. +notifyObservers +( +new +TestHangReport +( +extensionId +scriptBrowser +) +" +process +- +hang +- +report +" +) +; +return +hangObserved +; +} +function +background +( +) +{ +let +onPerformanceWarningDetails += +null +; +browser +. +runtime +. +onPerformanceWarning +. +addListener +( +details += +> +{ +onPerformanceWarningDetails += +details +; +} +) +; +browser +. +test +. +onMessage +. +addListener +( +message += +> +{ +if +( +message += += += +" +get +- +on +- +performance +- +warning +- +details +" +) +{ +browser +. +test +. +sendMessage +( +" +on +- +performance +- +warning +- +details +" +onPerformanceWarningDetails +) +; +onPerformanceWarningDetails += +null +; +} +} +) +; +} +async +function +expectOnPerformanceWarningDetails +( +extension +expectedOnPerformanceWarningDetails +) +{ +extension +. +sendMessage +( +" +get +- +on +- +performance +- +warning +- +details +" +) +; +let +actualOnPerformanceWarningDetails += +await +extension +. +awaitMessage +( +" +on +- +performance +- +warning +- +details +" +) +; +Assert +. +deepEqual +( +actualOnPerformanceWarningDetails +expectedOnPerformanceWarningDetails +expectedOnPerformanceWarningDetails +? +" +runtime +. +onPerformanceWarning +fired +with +correct +details +" +: +" +runtime +. +onPerformanceWarning +didn +' +t +fire +" +) +; +} +add_task +( +async +function +test_should_fire_on_process_hang_report +( +) +{ +const +description += +" +Slow +extension +content +script +caused +a +page +hang +user +was +warned +. +" +; +const +extension += +ExtensionTestUtils +. +loadExtension +( +{ +background +} +) +; +await +extension +. +startup +( +) +; +const +tabs += +await +Promise +. +all +( +[ +BrowserTestUtils +. +openNewForegroundTab +( +gBrowser +) +BrowserTestUtils +. +openNewForegroundTab +( +gBrowser +) +] +) +; +/ +/ +Warning +event +shouldn +' +t +have +fired +initially +. +await +expectOnPerformanceWarningDetails +( +extension +null +) +; +/ +/ +Hang +report +fired +for +the +extension +and +first +tab +. +Warning +event +with +first +/ +/ +tab +ID +expected +. +await +dispatchHangReport +( +extension +. +id +tabs +[ +0 +] +. +linkedBrowser +) +; +await +expectOnPerformanceWarningDetails +( +extension +{ +category +: +" +content_script +" +severity +: +" +high +" +description +tabId +: +tabTracker +. +getId +( +tabs +[ +0 +] +) +} +) +; +/ +/ +Hang +report +fired +for +different +extension +no +warning +event +expected +. +await +dispatchHangReport +( +" +wrong +- +addon +- +id +" +tabs +[ +0 +] +. +linkedBrowser +) +; +await +expectOnPerformanceWarningDetails +( +extension +null +) +; +/ +/ +Non +- +extension +hang +report +fired +no +warning +event +expected +. +await +dispatchHangReport +( +null +tabs +[ +0 +] +. +linkedBrowser +) +; +await +expectOnPerformanceWarningDetails +( +extension +null +) +; +/ +/ +Hang +report +fired +for +the +extension +and +second +tab +. +Warning +event +with +/ +/ +second +tab +ID +expected +. +await +dispatchHangReport +( +extension +. +id +tabs +[ +1 +] +. +linkedBrowser +) +; +await +expectOnPerformanceWarningDetails +( +extension +{ +category +: +" +content_script +" +severity +: +" +high +" +description +tabId +: +tabTracker +. +getId +( +tabs +[ +1 +] +) +} +) +; +/ +/ +Hang +report +fired +for +the +extension +with +no +associated +tab +. +Warning +event +/ +/ +with +no +tab +ID +expected +. +await +dispatchHangReport +( +extension +. +id +null +) +; +await +expectOnPerformanceWarningDetails +( +extension +{ +category +: +" +content_script +" +severity +: +" +high +" +description +} +) +; +await +Promise +. +all +( +tabs +. +map +( +BrowserTestUtils +. +removeTab +) +) +; +await +extension +. +unload +( +) +; +} +) +; diff --git a/toolkit/components/extensions/parent/ext-runtime.js b/toolkit/components/extensions/parent/ext-runtime.js index ab5ac7a4e7289..a413d5fe4c2c9 100644 --- a/toolkit/components/extensions/parent/ext-runtime.js +++ b/toolkit/components/extensions/parent/ext-runtime.js @@ -61,6 +61,46 @@ use strict " ; +/ +/ +This +file +expects +tabTracker +to +be +defined +in +the +global +scope +( +e +. +g +. +/ +/ +by +ext +- +browser +. +js +or +ext +- +android +. +js +) +. +/ +* +global +tabTracker +* +/ var { ExtensionParent @@ -498,6 +538,196 @@ _fire } ; } +onPerformanceWarning +( +{ +fire +} +) +{ +let +{ +extension +} += +this +; +let +observer += +( +subject +topic +) += +> +{ +let +report += +subject +. +QueryInterface +( +Ci +. +nsIHangReport +) +; +if +( +report +? +. +addonId +! += += +extension +. +id +) +{ +return +; +} +const +performanceWarningEventDetails += +{ +category +: +" +content_script +" +severity +: +" +high +" +description +: +" +Slow +extension +content +script +caused +a +page +hang +user +was +warned +. +" +} +; +let +scriptBrowser += +report +. +scriptBrowser +; +let +nativeTab += +scriptBrowser +? +. +ownerGlobal +. +gBrowser +? +. +getTabForBrowser +( +scriptBrowser +) +; +if +( +nativeTab +) +{ +performanceWarningEventDetails +. +tabId += +tabTracker +. +getId +( +nativeTab +) +; +} +fire +. +async +( +performanceWarningEventDetails +) +; +} +; +Services +. +obs +. +addObserver +( +observer +" +process +- +hang +- +report +" +) +; +return +{ +unregister +: +( +) += +> +{ +Services +. +obs +. +removeObserver +( +observer +" +process +- +hang +- +report +" +) +; +} +convert +( +_fire +context +) +{ +fire += +_fire +; +} +} +; +} } ; getAPI @@ -963,6 +1193,32 @@ listener api ( ) +onPerformanceWarning +: +new +EventManager +( +{ +context +module +: +" +runtime +" +event +: +" +onPerformanceWarning +" +extensionApi +: +this +} +) +. +api +( +) reload : async diff --git a/toolkit/components/extensions/schemas/runtime.json b/toolkit/components/extensions/schemas/runtime.json index 4014aed3f2b77..4bc5ff55f48b0 100644 --- a/toolkit/components/extensions/schemas/runtime.json +++ b/toolkit/components/extensions/schemas/runtime.json @@ -1400,6 +1400,106 @@ periodic " ] } +{ +" +id +" +: +" +OnPerformanceWarningCategory +" +" +type +" +: +" +string +" +" +enum +" +: +[ +" +content_script +" +] +" +description +" +: +" +The +performance +warning +event +category +e +. +g +. +' +content_script +' +. +" +} +{ +" +id +" +: +" +OnPerformanceWarningSeverity +" +" +type +" +: +" +string +" +" +enum +" +: +[ +" +low +" +" +medium +" +" +high +" +] +" +description +" +: +" +The +performance +warning +event +severity +. +Will +be +' +high +' +for +serious +and +user +- +visible +issues +. +" +} ] " properties @@ -5691,6 +5791,221 @@ dispatched } ] } +{ +" +name +" +: +" +onPerformanceWarning +" +" +type +" +: +" +function +" +" +description +" +: +" +Fired +when +a +runtime +performance +issue +is +detected +with +the +extension +. +Observe +this +event +to +be +proactively +notified +of +runtime +performance +problems +with +the +extension +. +" +" +parameters +" +: +[ +{ +" +type +" +: +" +object +" +" +name +" +: +" +details +" +" +properties +" +: +{ +" +category +" +: +{ +" +ref +" +: +" +OnPerformanceWarningCategory +" +" +description +" +: +" +The +performance +warning +event +category +e +. +g +. +' +content_script +' +. +" +} +" +severity +" +: +{ +" +ref +" +: +" +OnPerformanceWarningSeverity +" +" +description +" +: +" +The +performance +warning +event +severity +e +. +g +. +' +high +' +. +" +} +" +tabId +" +: +{ +" +type +" +: +" +integer +" +" +optional +" +: +true +" +description +" +: +" +The +( +ref +: +tabs +. +Tab +) +that +the +performance +warning +relates +to +if +any +. +" +} +" +description +" +: +{ +" +type +" +: +" +string +" +" +description +" +: +" +An +explanation +of +what +the +warning +means +and +hopefully +how +to +address +it +. +" +} +} +} +] +} ] } ] diff --git a/toolkit/components/extensions/test/mochitest/test_ext_all_apis.js b/toolkit/components/extensions/test/mochitest/test_ext_all_apis.js index b5cfa21cda0c5..a4d73ea99d235 100644 --- a/toolkit/components/extensions/test/mochitest/test_ext_all_apis.js +++ b/toolkit/components/extensions/test/mochitest/test_ext_all_apis.js @@ -545,6 +545,11 @@ onMessageExternal " runtime . +onPerformanceWarning +" +" +runtime +. onStartup " " @@ -578,6 +583,16 @@ runtime setUninstallURL " " +runtime +. +OnPerformanceWarningCategory +" +" +runtime +. +OnPerformanceWarningSeverity +" +" theme . getCurrent