From 92076e16a7a177cdd73615d2ae0b87a909c849e8 Mon Sep 17 00:00:00 2001 From: Sandor Molnar Date: Tue, 8 Oct 2024 00:16:13 +0300 Subject: [PATCH] Backed out 5 changesets (bug 1920562) for causing xpc assertion failures. CLOSED TREE Backed out changeset 8f085ab589a8 (bug 1920562) Backed out changeset 4405387ae770 (bug 1920562) Backed out changeset a68fd13a33ae (bug 1920562) Backed out changeset cd3672fc08ed (bug 1920562) Backed out changeset 62ab18879eea (bug 1920562) --- .../actors/AboutPrivateBrowsingParent.sys.mjs | 4 ++ browser/app/profile/firefox.js | 3 + browser/base/content/browser-init.js | 1 + browser/base/content/browser.js | 5 ++ .../browser_aboutCertError_cca_telemetry.js | 3 + .../about/browser_aboutCertError_telemetry.js | 13 ++++ .../test/about/browser_aboutNetError.js | 1 + .../browser_aboutNetError_native_fallback.js | 1 + .../test/about/browser_aboutNetError_trr.js | 1 + .../components/BrowserContentHandler.sys.mjs | 4 ++ browser/components/BrowserGlue.sys.mjs | 43 ++++++++++++ .../aboutwelcome/tests/unit/unit-entry.js | 1 + .../asrouter/modules/ASRouter.sys.mjs | 1 + .../asrouter/tests/unit/unit-entry.js | 1 + browser/components/doh/DoHController.sys.mjs | 12 ++++ browser/components/doh/TRRPerformance.sys.mjs | 5 ++ .../migration/MigrationWizardParent.sys.mjs | 5 ++ .../newtab/lib/TelemetryFeed.sys.mjs | 5 ++ .../newtab/lib/UTEventReporting.sys.mjs | 5 ++ .../test/unit/lib/UTEventReporting.test.js | 24 +++++++ .../components/newtab/test/unit/unit-entry.js | 1 + .../test/xpcshell/test_TelemetryFeed.js | 14 ++++ browser/components/preferences/main.js | 6 ++ browser/components/preferences/preferences.js | 1 + browser/components/preferences/privacy.js | 6 ++ .../tests/browser_moreFromMozilla.js | 1 + .../browser/browser_protections_telemetry.js | 9 +++ .../screenshots/ScreenshotsUtils.sys.mjs | 1 + .../sessionstore/SessionFile.sys.mjs | 1 + .../browser_urlbar_telemetry_extension.js | 4 ++ .../browser_urlbar_telemetry_persisted.js | 4 ++ .../browser_urlbar_telemetry_places.js | 4 ++ .../browser_urlbar_telemetry_remotetab.js | 4 ++ .../browser_urlbar_telemetry_searchmode.js | 1 + .../browser_view_resultTypes_display.js | 1 + .../address/browser_address_telemetry.js | 6 ++ .../browser_iframe_layout_telemetry.js | 4 ++ .../browser_creditCard_telemetry.js | 4 ++ .../search-detection/extension/api.js | 1 + browser/modules/BrowserUsageTelemetry.sys.mjs | 1 + browser/modules/HomePage.sys.mjs | 2 + .../modules/PartnerLinkAttribution.sys.mjs | 1 + browser/modules/ProcessHangMonitor.sys.mjs | 1 + devtools/client/framework/devtools.js | 1 + devtools/client/shared/telemetry.js | 14 ++++ .../docs/contributor/frontend/telemetry.md | 3 + devtools/startup/DevToolsShim.sys.mjs | 1 + devtools/startup/DevToolsStartup.sys.mjs | 1 + dom/ipc/ContentParent.cpp | 9 +++ dom/quota/ActorsParent.cpp | 4 ++ dom/security/nsContentSecurityManager.cpp | 8 +++ dom/security/nsContentSecurityUtils.cpp | 11 ++++ .../general/browser_test_report_blocking.js | 2 + image/decoders/nsAVIFDecoder.cpp | 3 + ipc/glue/UtilityProcessHost.cpp | 17 +++++ js/xpconnect/src/XPCJSContext.cpp | 6 ++ modules/libjar/nsJARChannel.cpp | 2 + .../test/unit/test_empty_jar_telemetry.js | 2 + modules/libpref/Preferences.cpp | 21 ++++++ modules/libpref/init/StaticPrefList.yaml | 6 ++ .../browser/browser_sanitization_events.js | 1 + netwerk/dns/TRRService.cpp | 10 +++ parser/htmlparser/nsExpatDriver.cpp | 2 + .../tests/mochitest/browser_ysod_telemetry.js | 1 + services/common/uptake-telemetry.sys.mjs | 11 ++++ .../fxaccounts/FxAccountsTelemetry.sys.mjs | 1 + services/sync/modules/SyncedTabs.sys.mjs | 1 + .../cookiebanners/nsCookieBannerService.cpp | 8 +++ .../downloads/test/unit/test_DownloadList.js | 1 + .../extensions/parent/ext-telemetry.js | 8 ++- .../extensions/schemas/telemetry.json | 3 +- .../test/xpcshell/test_ext_telemetry.js | 4 ++ .../formautofill/FormAutofillParent.sys.mjs | 3 + toolkit/components/glean/docs/user/gifft.md | 9 +++ .../docs/user/glean_for_legacy_events.md | 6 ++ .../glean/tests/xpcshell/test_GIFFT.js | 2 + .../glean/tests/xpcshell/test_GIFFTIPC.js | 2 + .../targeting/Targeting.sys.mjs | 4 ++ .../components/nimbus/ExperimentAPI.sys.mjs | 2 + .../components/nimbus/lib/NimbusFeatures.cpp | 1 + .../test/unit/test_ExperimentManager_prefs.js | 7 ++ ...eSettingsExperimentLoader_updateRecipes.js | 6 ++ .../nimbus/test/unit/test_localization.js | 4 ++ .../nimbus/test/unit/test_prefFlips.js | 4 ++ toolkit/components/normandy/Normandy.sys.mjs | 7 ++ .../normandy/lib/TelemetryEvents.sys.mjs | 6 ++ .../normandy/test/browser/browser_Normandy.js | 22 +++++++ .../components/normandy/test/browser/head.js | 3 + .../normandy/test/unit/test_addon_unenroll.js | 5 ++ .../passwordmgr/LoginHelper.sys.mjs | 2 + .../test/browser/browser_relay_telemetry.js | 2 + ..._aaa_run_first_firstTimePiPToggleEvents.js | 1 + toolkit/components/reader/AboutReader.sys.mjs | 2 + toolkit/components/reader/ReaderMode.sys.mjs | 2 + .../satchel/integrations/FirefoxRelay.sys.mjs | 1 + .../components/telemetry/core/Telemetry.cpp | 11 ++++ toolkit/components/telemetry/core/Telemetry.h | 10 +++ .../telemetry/core/TelemetryEvent.cpp | 56 +++++++++++++++- .../telemetry/core/TelemetryEvent.h | 1 + .../telemetry/core/nsITelemetry.idl | 10 +++ .../telemetry/docs/collection/events.rst | 34 ++++++++-- .../docs/collection/webextension-api.rst | 9 ++- .../telemetry/tests/gtest/TestEvents.cpp | 10 ++- .../tests/integration/tests/conftest.py | 14 ++++ .../integration/tests/test_event_ping.py | 1 + .../telemetry/tests/unit/test_ChildEvents.js | 2 + .../telemetry/tests/unit/test_EventPing.js | 1 + .../test_TelemetryChildEvents_buildFaster.js | 2 + .../tests/unit/test_TelemetryEvents.js | 52 +++++++++++++++ .../unit/test_TelemetryEvents_buildFaster.js | 65 +++++++++++++++++++ toolkit/modules/JSONFile.sys.mjs | 2 + toolkit/modules/ServiceRequest.sys.mjs | 1 + .../mozapps/extensions/AddonManager.sys.mjs | 10 +++ tools/@types/lib.gecko.xpcom.d.ts | 1 + xpcom/base/AvailableMemoryWatcher.cpp | 2 + 115 files changed, 761 insertions(+), 14 deletions(-) diff --git a/browser/actors/AboutPrivateBrowsingParent.sys.mjs b/browser/actors/AboutPrivateBrowsingParent.sys.mjs index af363db95d20..5c6757b8a0ed 100644 --- a/browser/actors/AboutPrivateBrowsingParent.sys.mjs +++ b/browser/actors/AboutPrivateBrowsingParent.sys.mjs @@ -31,6 +31,10 @@ ChromeUtils.defineESModuleGetters(lazy, { let gSearchBannerShownThisSession; export class AboutPrivateBrowsingParent extends JSWindowActorParent { + constructor() { + super(); + Services.telemetry.setEventRecordingEnabled("aboutprivatebrowsing", true); + } // Used by tests static setShownThisSession(shown) { gSearchBannerShownThisSession = shown; diff --git a/browser/app/profile/firefox.js b/browser/app/profile/firefox.js index 4d8c1766ddae..b9763607cbfd 100644 --- a/browser/app/profile/firefox.js +++ b/browser/app/profile/firefox.js @@ -1453,6 +1453,7 @@ pref("app.support.baseURL", "https://support.mozilla.org/1/firefox/%VERSION%/%OS // base url for web-based feedback pages pref("app.feedback.baseURL", "https://ideas.mozilla.org/"); +pref("security.certerrors.recordEventTelemetry", true); pref("security.certerrors.permanentOverride", true); pref("security.certerrors.mitm.priming.enabled", true); pref("security.certerrors.mitm.priming.endpoint", "https://mitmdetection.services.mozilla.com/"); @@ -1999,6 +2000,8 @@ pref("browser.ml.chat.shortcuts.custom", true); pref("browser.ml.chat.shortcuts.longPress", 60000); pref("browser.ml.chat.sidebar", true); +pref("security.protectionspopup.recordEventTelemetry", true); + // Block insecure active content on https pages pref("security.mixed_content.block_active_content", true); diff --git a/browser/base/content/browser-init.js b/browser/base/content/browser-init.js index 2820086f4f2c..674b1b7515f4 100644 --- a/browser/base/content/browser-init.js +++ b/browser/base/content/browser-init.js @@ -936,6 +936,7 @@ var gBrowserInit = { "resource:///modules/DownloadsMacFinderProgress.sys.mjs" ).DownloadsMacFinderProgress.register(); } + Services.telemetry.setEventRecordingEnabled("downloads", true); } catch (ex) { console.error(ex); } diff --git a/browser/base/content/browser.js b/browser/base/content/browser.js index af89627f4677..d27580121e83 100644 --- a/browser/base/content/browser.js +++ b/browser/base/content/browser.js @@ -806,6 +806,8 @@ function updateFxaToolbarMenu(enable, isInitialUpdate = false) { fxaPanelEl.addEventListener("ViewShowing", gSync.updateSendToDeviceTitle); + Services.telemetry.setEventRecordingEnabled("fxa_app_menu", true); + if (enable && syncEnabled) { mainWindowEl.setAttribute("fxatoolbarmenu", "visible"); @@ -815,6 +817,8 @@ function updateFxaToolbarMenu(enable, isInitialUpdate = false) { if (!isInitialUpdate) { gSync.maybeUpdateUIState(); } + + Services.telemetry.setEventRecordingEnabled("fxa_avatar_menu", true); } else { mainWindowEl.removeAttribute("fxatoolbarmenu"); } @@ -7603,6 +7607,7 @@ var FirefoxViewHandler = { let viewCount = Services.prefs.getIntPref(PREF_NAME, 0); // Record telemetry + Services.telemetry.setEventRecordingEnabled("firefoxview_next", true); Glean.firefoxviewNext.tabSelectedToolbarbutton.record(); if (viewCount < MAX_VIEW_COUNT) { diff --git a/browser/base/content/test/about/browser_aboutCertError_cca_telemetry.js b/browser/base/content/test/about/browser_aboutCertError_cca_telemetry.js index 794fc40b2004..9279902fa238 100644 --- a/browser/base/content/test/about/browser_aboutCertError_cca_telemetry.js +++ b/browser/base/content/test/about/browser_aboutCertError_cca_telemetry.js @@ -6,8 +6,11 @@ const ISSUED_BY_CCA_SITE = "https://issued-by-cca.example.com"; const UNKNOWN_ISSUER_SITE = "https://untrusted.example.com"; +Services.telemetry.setEventRecordingEnabled("security.ui.certerror", true); + registerCleanupFunction(async () => { await resetTelemetry(); + Services.telemetry.setEventRecordingEnabled("security.ui.certerror", false); }); async function resetTelemetry() { diff --git a/browser/base/content/test/about/browser_aboutCertError_telemetry.js b/browser/base/content/test/about/browser_aboutCertError_telemetry.js index 5df1d1ec2536..61ec8afcbf94 100644 --- a/browser/base/content/test/about/browser_aboutCertError_telemetry.js +++ b/browser/base/content/test/about/browser_aboutCertError_telemetry.js @@ -40,6 +40,11 @@ add_task(async function checkTelemetryClickEvents() { return !events || !events.length; }); + // Now enable recording our telemetry. Even if this is disabled, content + // processes will send event telemetry to the parent, thus we needed to ensure + // we waited and cleared first. Sigh. + Services.telemetry.setEventRecordingEnabled("security.ui.certerror", true); + for (let useFrame of [false, true]) { let recordedObjects = [ "advanced_button", @@ -148,4 +153,12 @@ add_task(async function checkTelemetryClickEvents() { BrowserTestUtils.removeTab(gBrowser.selectedTab); } } + + let enableCertErrorUITelemetry = Services.prefs.getBoolPref( + "security.certerrors.recordEventTelemetry" + ); + Services.telemetry.setEventRecordingEnabled( + "security.ui.certerror", + enableCertErrorUITelemetry + ); }); diff --git a/browser/base/content/test/about/browser_aboutNetError.js b/browser/base/content/test/about/browser_aboutNetError.js index 7dfc4f4de080..e99ec9a62031 100644 --- a/browser/base/content/test/about/browser_aboutNetError.js +++ b/browser/base/content/test/about/browser_aboutNetError.js @@ -45,6 +45,7 @@ async function resetTelemetry() { ).content; return !events || !events.length; }); + Services.telemetry.setEventRecordingEnabled("security.ui.tlserror", true); } async function checkTelemetry(errorString, nssError) { diff --git a/browser/base/content/test/about/browser_aboutNetError_native_fallback.js b/browser/base/content/test/about/browser_aboutNetError_native_fallback.js index 7f6abdca65d2..d82d4d6877ba 100644 --- a/browser/base/content/test/about/browser_aboutNetError_native_fallback.js +++ b/browser/base/content/test/about/browser_aboutNetError_native_fallback.js @@ -50,6 +50,7 @@ async function verifyError(url, fallbackWarning, testName) { ).content; return !events || !events.length; }); + Services.telemetry.setEventRecordingEnabled("security.doh.neterror", true); let browser; let pageLoaded; diff --git a/browser/base/content/test/about/browser_aboutNetError_trr.js b/browser/base/content/test/about/browser_aboutNetError_trr.js index 5cc1f335b4d3..bfee686e7c11 100644 --- a/browser/base/content/test/about/browser_aboutNetError_trr.js +++ b/browser/base/content/test/about/browser_aboutNetError_trr.js @@ -89,6 +89,7 @@ add_task(async function TRROnlyExceptionButtonTelemetry() { ).content; return !events || !events.length; }); + Services.telemetry.setEventRecordingEnabled("security.doh.neterror", true); let browser = await loadErrorPage(); diff --git a/browser/components/BrowserContentHandler.sys.mjs b/browser/components/BrowserContentHandler.sys.mjs index 80e45b644493..7356e0bc7f81 100644 --- a/browser/components/BrowserContentHandler.sys.mjs +++ b/browser/components/BrowserContentHandler.sys.mjs @@ -1346,6 +1346,10 @@ nsDefaultCommandLineHandler.prototype = { } if (notificationData?.privilegedName) { + Services.telemetry.setEventRecordingEnabled( + "browser.launched_to_handle", + true + ); Glean.browserLaunchedToHandle.systemNotification.record({ name: notificationData.privilegedName, }); diff --git a/browser/components/BrowserGlue.sys.mjs b/browser/components/BrowserGlue.sys.mjs index 82847bed0dbb..f9638a7ad797 100644 --- a/browser/components/BrowserGlue.sys.mjs +++ b/browser/components/BrowserGlue.sys.mjs @@ -1361,6 +1361,10 @@ BrowserGlue.prototype = { // If we don't start with last profile, the user // likely sees the profile selector on launch. if (Services.prefs.getBoolPref(launchOnLoginPref)) { + Services.telemetry.setEventRecordingEnabled( + "launch_on_login", + true + ); Glean.launchOnLogin.lastProfileDisableStartup.record(); } Services.prefs.setBoolPref(launchOnLoginPref, false); @@ -1946,6 +1950,13 @@ BrowserGlue.prototype = { lazy.NewTabUtils.init(); + Services.telemetry.setEventRecordingEnabled( + "security.ui.protections", + true + ); + + Services.telemetry.setEventRecordingEnabled("security.doh.neterror", true); + lazy.PageActions.init(); lazy.DoHController.init(); @@ -2088,6 +2099,13 @@ BrowserGlue.prototype = { }, _recordContentBlockingTelemetry() { + Services.telemetry.setEventRecordingEnabled( + "security.ui.protectionspopup", + Services.prefs.getBoolPref( + "security.protectionspopup.recordEventTelemetry" + ) + ); + let tpEnabled = Services.prefs.getBoolPref( "privacy.trackingprotection.enabled" ); @@ -2598,6 +2616,24 @@ BrowserGlue.prototype = { }, }, + { + name: "enableCertErrorUITelemetry", + task: () => { + let enableCertErrorUITelemetry = Services.prefs.getBoolPref( + "security.certerrors.recordEventTelemetry", + true + ); + Services.telemetry.setEventRecordingEnabled( + "security.ui.certerror", + enableCertErrorUITelemetry + ); + Services.telemetry.setEventRecordingEnabled( + "security.ui.tlserror", + enableCertErrorUITelemetry + ); + }, + }, + // Load the Login Manager data from disk off the main thread, some time // after startup. If the data is required before this runs, for example // because a restored page contains a password field, it will be loaded on @@ -4711,6 +4747,7 @@ BrowserGlue.prototype = { })(); // Record why the dialog is showing or not. + Services.telemetry.setEventRecordingEnabled("upgrade_dialog", true); Glean.upgradeDialog.triggerReason.record({ value: dialogReason || "satisfied", }); @@ -5174,6 +5211,12 @@ BrowserGlue.prototype = { }, _collectTelemetryPiPEnabled() { + Services.telemetry.setEventRecordingEnabled( + "pictureinpicture.settings", + true + ); + Services.telemetry.setEventRecordingEnabled("pictureinpicture", true); + const TOGGLE_ENABLED_PREF = "media.videocontrols.picture-in-picture.video-toggle.enabled"; diff --git a/browser/components/aboutwelcome/tests/unit/unit-entry.js b/browser/components/aboutwelcome/tests/unit/unit-entry.js index ca5a5e437d80..484423d6c3f9 100644 --- a/browser/components/aboutwelcome/tests/unit/unit-entry.js +++ b/browser/components/aboutwelcome/tests/unit/unit-entry.js @@ -416,6 +416,7 @@ const TEST_GLOBAL = { notifyObservers() {}, }, telemetry: { + setEventRecordingEnabled: () => {}, recordEvent: _eventDetails => {}, scalarSet: () => {}, keyedScalarAdd: () => {}, diff --git a/browser/components/asrouter/modules/ASRouter.sys.mjs b/browser/components/asrouter/modules/ASRouter.sys.mjs index e49c3629f8a1..7b7f12ad75e0 100644 --- a/browser/components/asrouter/modules/ASRouter.sys.mjs +++ b/browser/components/asrouter/modules/ASRouter.sys.mjs @@ -689,6 +689,7 @@ export class _ASRouter { this._onExperimentEnrollmentsUpdated = this._onExperimentEnrollmentsUpdated.bind(this); this.forcePBWindow = this.forcePBWindow.bind(this); + Services.telemetry.setEventRecordingEnabled("messaging_experiments", true); this.messagesEnabledInAutomation = []; } diff --git a/browser/components/asrouter/tests/unit/unit-entry.js b/browser/components/asrouter/tests/unit/unit-entry.js index 964df01c3e87..0329e247681f 100644 --- a/browser/components/asrouter/tests/unit/unit-entry.js +++ b/browser/components/asrouter/tests/unit/unit-entry.js @@ -424,6 +424,7 @@ const TEST_GLOBAL = { notifyObservers() {}, }, telemetry: { + setEventRecordingEnabled: () => {}, scalarSet: () => {}, keyedScalarAdd: () => {}, }, diff --git a/browser/components/doh/DoHController.sys.mjs b/browser/components/doh/DoHController.sys.mjs index 97601c05f73f..d51442073d74 100644 --- a/browser/components/doh/DoHController.sys.mjs +++ b/browser/components/doh/DoHController.sys.mjs @@ -110,6 +110,9 @@ const NATIVE_FALLBACK_WARNING_PREF = "network.trr.display_fallback_warning"; const NATIVE_FALLBACK_WARNING_HEURISTIC_LIST_PREF = "network.trr.fallback_warning_heuristic_list"; +const HEURISTICS_TELEMETRY_CATEGORY = "doh"; +const TRRSELECT_TELEMETRY_CATEGORY = "security.doh.trrPerformance"; + const kLinkStatusChangedTopic = "network:link-status-changed"; const kConnectivityTopic = "network:captive-portal-connectivity-changed"; const kPrefChangedTopic = "nsPref:changed"; @@ -140,6 +143,15 @@ export const DoHController = { _heuristicsAreEnabled: false, async init() { + Services.telemetry.setEventRecordingEnabled( + HEURISTICS_TELEMETRY_CATEGORY, + true + ); + Services.telemetry.setEventRecordingEnabled( + TRRSELECT_TELEMETRY_CATEGORY, + true + ); + await lazy.DoHConfigController.initComplete; Services.obs.addObserver(this, lazy.DoHConfigController.kConfigUpdateTopic); diff --git a/browser/components/doh/TRRPerformance.sys.mjs b/browser/components/doh/TRRPerformance.sys.mjs index 370a94471bdc..aa3b01b166be 100644 --- a/browser/components/doh/TRRPerformance.sys.mjs +++ b/browser/components/doh/TRRPerformance.sys.mjs @@ -15,6 +15,11 @@ * usable network until a full set of results has been captured. We stop retrying * after 5 attempts. */ +Services.telemetry.setEventRecordingEnabled( + "security.doh.trrPerformance", + true +); + import { XPCOMUtils } from "resource://gre/modules/XPCOMUtils.sys.mjs"; const lazy = {}; diff --git a/browser/components/migration/MigrationWizardParent.sys.mjs b/browser/components/migration/MigrationWizardParent.sys.mjs index 0b9f1c46e902..1b926e333dff 100644 --- a/browser/components/migration/MigrationWizardParent.sys.mjs +++ b/browser/components/migration/MigrationWizardParent.sys.mjs @@ -43,6 +43,11 @@ let gHasOpenedBefore = false; * the associated MigrationWizardChild. */ export class MigrationWizardParent extends JSWindowActorParent { + constructor() { + super(); + Services.telemetry.setEventRecordingEnabled("browser.migration", true); + } + didDestroy() { Services.obs.notifyObservers(this, "MigrationWizard:Destroyed"); MigrationUtils.finishMigration(); diff --git a/browser/components/newtab/lib/TelemetryFeed.sys.mjs b/browser/components/newtab/lib/TelemetryFeed.sys.mjs index 25464ead64d2..e6816cfd4169 100644 --- a/browser/components/newtab/lib/TelemetryFeed.sys.mjs +++ b/browser/components/newtab/lib/TelemetryFeed.sys.mjs @@ -1499,6 +1499,11 @@ export class TelemetryFeed { // init has finished setting up the observer } + // Only uninit if the getter has initialized it + if (Object.prototype.hasOwnProperty.call(this, "utEvents")) { + this.utEvents.uninit(); + } + // TODO: Send any unfinished sessions } } diff --git a/browser/components/newtab/lib/UTEventReporting.sys.mjs b/browser/components/newtab/lib/UTEventReporting.sys.mjs index 6e07c6a2d474..11aad108435d 100644 --- a/browser/components/newtab/lib/UTEventReporting.sys.mjs +++ b/browser/components/newtab/lib/UTEventReporting.sys.mjs @@ -16,6 +16,7 @@ const EXTRAS_FIELD_NAMES = [ export class UTEventReporting { constructor() { + Services.telemetry.setEventRecordingEnabled("activity_stream", true); this.sendUserEvent = this.sendUserEvent.bind(this); this.sendSessionEndEvent = this.sendSessionEndEvent.bind(this); } @@ -47,4 +48,8 @@ export class UTEventReporting { this._createExtras(data, data.session_duration) ); } + + uninit() { + Services.telemetry.setEventRecordingEnabled("activity_stream", false); + } } diff --git a/browser/components/newtab/test/unit/lib/UTEventReporting.test.js b/browser/components/newtab/test/unit/lib/UTEventReporting.test.js index 20cdb7684a6d..77939da1360f 100644 --- a/browser/components/newtab/test/unit/lib/UTEventReporting.test.js +++ b/browser/components/newtab/test/unit/lib/UTEventReporting.test.js @@ -48,6 +48,7 @@ describe("UTEventReporting", () => { beforeEach(() => { globals = new GlobalOverrider(); sandbox = globals.sandbox; + sandbox.stub(global.Services.telemetry, "setEventRecordingEnabled"); utEvents = new UTEventReporting(); }); @@ -83,4 +84,27 @@ describe("UTEventReporting", () => { assert.validate(ping, UTSessionPing); }); }); + + describe("#uninit()", () => { + it("should call setEventRecordingEnabled with a false value", () => { + assert.equal( + global.Services.telemetry.setEventRecordingEnabled.firstCall.args[0], + "activity_stream" + ); + assert.equal( + global.Services.telemetry.setEventRecordingEnabled.firstCall.args[1], + true + ); + + utEvents.uninit(); + assert.equal( + global.Services.telemetry.setEventRecordingEnabled.secondCall.args[0], + "activity_stream" + ); + assert.equal( + global.Services.telemetry.setEventRecordingEnabled.secondCall.args[1], + false + ); + }); + }); }); diff --git a/browser/components/newtab/test/unit/unit-entry.js b/browser/components/newtab/test/unit/unit-entry.js index d6551f578fa6..35116759e35f 100644 --- a/browser/components/newtab/test/unit/unit-entry.js +++ b/browser/components/newtab/test/unit/unit-entry.js @@ -394,6 +394,7 @@ const TEST_GLOBAL = { notifyObservers() {}, }, telemetry: { + setEventRecordingEnabled: () => {}, recordEvent: _eventDetails => {}, scalarSet: () => {}, keyedScalarAdd: () => {}, diff --git a/browser/components/newtab/test/xpcshell/test_TelemetryFeed.js b/browser/components/newtab/test/xpcshell/test_TelemetryFeed.js index 41db5e7a1bf7..8bba3b57c7bc 100644 --- a/browser/components/newtab/test/xpcshell/test_TelemetryFeed.js +++ b/browser/components/newtab/test/xpcshell/test_TelemetryFeed.js @@ -1575,6 +1575,20 @@ add_task( } ); +add_task(async function test_uninit_calls_utEvents_uninit() { + info("TelemetryFeed.uninit should call .utEvents.uninit"); + let sandbox = sinon.createSandbox(); + let instance = new TelemetryFeed(); + sandbox.stub(instance.utEvents, "uninit"); + + instance.uninit(); + Assert.ok( + instance.utEvents.uninit.calledOnce, + "TelemetryFeed.utEvents.uninit should be called" + ); + sandbox.restore(); +}); + add_task(async function test_uninit_deregisters_observer() { info( "TelemetryFeed.uninit should make this.browserOpenNewtabStart() stop " + diff --git a/browser/components/preferences/main.js b/browser/components/preferences/main.js index 3ebb0164eeb8..68740bf08645 100644 --- a/browser/components/preferences/main.js +++ b/browser/components/preferences/main.js @@ -1397,6 +1397,12 @@ var gMainPane = { }, initPrimaryBrowserLanguageUI() { + // Enable telemetry. + Services.telemetry.setEventRecordingEnabled( + "intl.ui.browserLanguage", + true + ); + // This will register the "command" listener. let menulist = document.getElementById("primaryBrowserLocale"); new SelectionChangedMenulist(menulist, event => { diff --git a/browser/components/preferences/preferences.js b/browser/components/preferences/preferences.js index 78b70a99b001..bdfd45b6d5c2 100644 --- a/browser/components/preferences/preferences.js +++ b/browser/components/preferences/preferences.js @@ -191,6 +191,7 @@ function init_all() { // Asks Preferences to queue an update of the attribute values of // the entire document. Preferences.queueUpdateOfAllElements(); + Services.telemetry.setEventRecordingEnabled("aboutpreferences", true); register_module("paneGeneral", gMainPane); register_module("paneHome", gHomePane); diff --git a/browser/components/preferences/privacy.js b/browser/components/preferences/privacy.js index 0d52b8bbc916..433faf6680fb 100644 --- a/browser/components/preferences/privacy.js +++ b/browser/components/preferences/privacy.js @@ -882,6 +882,8 @@ var gPrivacyPane = { * Init DoH corresponding prefs */ initDoH() { + Services.telemetry.setEventRecordingEnabled("security.doh.settings", true); + setEventListener("dohDefaultArrow", "command", this.toggleExpansion); setEventListener("dohEnabledArrow", "command", this.toggleExpansion); setEventListener("dohStrictArrow", "command", this.toggleExpansion); @@ -990,6 +992,10 @@ var gPrivacyPane = { this._initTrackingProtectionExtensionControl(); this._initThirdPartyCertsToggle(); + Services.telemetry.setEventRecordingEnabled("privacy.ui.fpp", true); + + Services.telemetry.setEventRecordingEnabled("pwmgr", true); + Preferences.get("privacy.trackingprotection.enabled").on( "change", gPrivacyPane.trackingProtectionReadPrefs.bind(gPrivacyPane) diff --git a/browser/components/preferences/tests/browser_moreFromMozilla.js b/browser/components/preferences/tests/browser_moreFromMozilla.js index c721f8d7b0f1..6cb6d9e119f2 100644 --- a/browser/components/preferences/tests/browser_moreFromMozilla.js +++ b/browser/components/preferences/tests/browser_moreFromMozilla.js @@ -141,6 +141,7 @@ add_task(async function testwhenPrefDisabled() { add_task(async function test_aboutpreferences_event_telemetry() { Services.telemetry.clearEvents(); + Services.telemetry.setEventRecordingEnabled("aboutpreferences", true); await SpecialPowers.pushPrefEnv({ set: [["browser.preferences.moreFromMozilla", true]], diff --git a/browser/components/protections/test/browser/browser_protections_telemetry.js b/browser/components/protections/test/browser/browser_protections_telemetry.js index b889bb89bd77..2073be23e955 100644 --- a/browser/components/protections/test/browser/browser_protections_telemetry.js +++ b/browser/components/protections/test/browser/browser_protections_telemetry.js @@ -102,6 +102,8 @@ add_task(async function checkTelemetryLoadEvents() { return !events || !events.length; }); + Services.telemetry.setEventRecordingEnabled("security.ui.protections", true); + let tab = await BrowserTestUtils.openNewForegroundTab({ url: "about:protections", gBrowser, @@ -197,6 +199,8 @@ add_task(async function checkTelemetryClickEvents() { return !events || !events.length; }); + Services.telemetry.setEventRecordingEnabled("security.ui.protections", true); + let tab = await BrowserTestUtils.openNewForegroundTab({ url: "about:protections", gBrowser, @@ -800,6 +804,8 @@ add_task(async function checkTelemetryLoadEventForEntrypoint() { return !events || !events.length; }); + Services.telemetry.setEventRecordingEnabled("security.ui.protections", true); + info("Typo in 'entrypoint' should not be recorded"); let tab = await BrowserTestUtils.openNewForegroundTab({ url: "about:protections?entryPoint=newPage", @@ -882,6 +888,8 @@ add_task(async function checkTelemetryClickEventsVPN() { ).content; return !events || !events.length; }); + Services.telemetry.setEventRecordingEnabled("security.ui.protections", true); + // user is not subscribed to VPN, and is in the us AboutProtectionsParent.setTestOverride(getVPNOverrides(false, "us")); await SpecialPowers.pushPrefEnv({ @@ -1047,6 +1055,7 @@ add_task(async function checkTelemetryEventsVPNBanner() { return !events || !events.length; }); + Services.telemetry.setEventRecordingEnabled("security.ui.protections", true); // User is not subscribed to VPN AboutProtectionsParent.setTestOverride(getVPNOverrides(false, "us")); diff --git a/browser/components/screenshots/ScreenshotsUtils.sys.mjs b/browser/components/screenshots/ScreenshotsUtils.sys.mjs index 0c8c0f12bee1..8417de8a8341 100644 --- a/browser/components/screenshots/ScreenshotsUtils.sys.mjs +++ b/browser/components/screenshots/ScreenshotsUtils.sys.mjs @@ -176,6 +176,7 @@ export var ScreenshotsUtils = { return; } this.resetMethodsUsed(); + Services.telemetry.setEventRecordingEnabled("screenshots", true); Services.obs.addObserver(this, "menuitem-screenshot"); this.initialized = true; if (Cu.isInAutomation) { diff --git a/browser/components/sessionstore/SessionFile.sys.mjs b/browser/components/sessionstore/SessionFile.sys.mjs index fa6b5a978bbf..6eac2803d6bc 100644 --- a/browser/components/sessionstore/SessionFile.sys.mjs +++ b/browser/components/sessionstore/SessionFile.sys.mjs @@ -195,6 +195,7 @@ var SessionFileInternal = { }, async _readInternal(useOldExtension) { + Services.telemetry.setEventRecordingEnabled("session_restore", true); let result; let noFilesFound = true; this._usingOldExtension = useOldExtension; diff --git a/browser/components/urlbar/tests/browser/browser_urlbar_telemetry_extension.js b/browser/components/urlbar/tests/browser/browser_urlbar_telemetry_extension.js index 3591f52f3f22..e9032047222f 100644 --- a/browser/components/urlbar/tests/browser/browser_urlbar_telemetry_extension.js +++ b/browser/components/urlbar/tests/browser/browser_urlbar_telemetry_extension.js @@ -87,6 +87,9 @@ add_setup(async function () { let oldCanRecord = Services.telemetry.canRecordExtended; Services.telemetry.canRecordExtended = true; + // Enable event recording for the events tested here. + Services.telemetry.setEventRecordingEnabled("navigation", true); + // Clear history so that history added by previous tests doesn't mess up this // test when it selects results in the urlbar. await PlacesUtils.history.clear(); @@ -97,6 +100,7 @@ add_setup(async function () { Services.telemetry.canRecordExtended = oldCanRecord; await PlacesUtils.history.clear(); await PlacesUtils.bookmarks.eraseEverything(); + Services.telemetry.setEventRecordingEnabled("navigation", false); }); }); diff --git a/browser/components/urlbar/tests/browser/browser_urlbar_telemetry_persisted.js b/browser/components/urlbar/tests/browser/browser_urlbar_telemetry_persisted.js index 9264d9191b30..5a38f7d0044c 100644 --- a/browser/components/urlbar/tests/browser/browser_urlbar_telemetry_persisted.js +++ b/browser/components/urlbar/tests/browser/browser_urlbar_telemetry_persisted.js @@ -28,10 +28,14 @@ add_setup(async () => { let cleanup = await installPersistTestEngines(); testEngine = Services.search.getEngineByName("Example"); + // Enable event recording for the events. + Services.telemetry.setEventRecordingEnabled("navigation", true); + registerCleanupFunction(async function () { await PlacesUtils.history.clear(); Services.telemetry.clearScalars(); Services.telemetry.clearEvents(); + Services.telemetry.setEventRecordingEnabled("navigation", false); cleanup(); }); }); diff --git a/browser/components/urlbar/tests/browser/browser_urlbar_telemetry_places.js b/browser/components/urlbar/tests/browser/browser_urlbar_telemetry_places.js index 92f356a3c209..671ff9320b7c 100644 --- a/browser/components/urlbar/tests/browser/browser_urlbar_telemetry_places.js +++ b/browser/components/urlbar/tests/browser/browser_urlbar_telemetry_places.js @@ -102,6 +102,9 @@ add_setup(async function () { let oldCanRecord = Services.telemetry.canRecordExtended; Services.telemetry.canRecordExtended = true; + // Enable event recording for the events tested here. + Services.telemetry.setEventRecordingEnabled("navigation", true); + // Clear history so that history added by previous tests doesn't mess up this // test when it selects results in the urlbar. await PlacesUtils.history.clear(); @@ -118,6 +121,7 @@ add_setup(async function () { Services.telemetry.canRecordExtended = oldCanRecord; await PlacesUtils.history.clear(); await PlacesUtils.bookmarks.eraseEverything(); + Services.telemetry.setEventRecordingEnabled("navigation", false); }); }); diff --git a/browser/components/urlbar/tests/browser/browser_urlbar_telemetry_remotetab.js b/browser/components/urlbar/tests/browser/browser_urlbar_telemetry_remotetab.js index 14d1088c942d..baf8852736b7 100644 --- a/browser/components/urlbar/tests/browser/browser_urlbar_telemetry_remotetab.js +++ b/browser/components/urlbar/tests/browser/browser_urlbar_telemetry_remotetab.js @@ -90,6 +90,9 @@ add_setup(async function () { let oldCanRecord = Services.telemetry.canRecordExtended; Services.telemetry.canRecordExtended = true; + // Enable event recording for the events tested here. + Services.telemetry.setEventRecordingEnabled("navigation", true); + // Clear history so that history added by previous tests doesn't mess up this // test when it selects results in the urlbar. await PlacesUtils.history.clear(); @@ -146,6 +149,7 @@ add_setup(async function () { Services.telemetry.canRecordExtended = oldCanRecord; await PlacesUtils.history.clear(); await PlacesUtils.bookmarks.eraseEverything(); + Services.telemetry.setEventRecordingEnabled("navigation", false); }); }); diff --git a/browser/components/urlbar/tests/browser/browser_urlbar_telemetry_searchmode.js b/browser/components/urlbar/tests/browser/browser_urlbar_telemetry_searchmode.js index a052a342b9ae..5d20c897bfd2 100644 --- a/browser/components/urlbar/tests/browser/browser_urlbar_telemetry_searchmode.js +++ b/browser/components/urlbar/tests/browser/browser_urlbar_telemetry_searchmode.js @@ -125,6 +125,7 @@ add_setup(async function () { registerCleanupFunction(async function () { Services.telemetry.canRecordExtended = oldCanRecord; await PlacesUtils.history.clear(); + Services.telemetry.setEventRecordingEnabled("navigation", false); }); }); diff --git a/browser/components/urlbar/tests/browser/browser_view_resultTypes_display.js b/browser/components/urlbar/tests/browser/browser_view_resultTypes_display.js index ed1d67cebee2..dc8a240a4d80 100644 --- a/browser/components/urlbar/tests/browser/browser_view_resultTypes_display.js +++ b/browser/components/urlbar/tests/browser/browser_view_resultTypes_display.js @@ -292,6 +292,7 @@ add_task(async function test_remote_tab_result() { SyncedTabs._internal = originalSyncedTabsInternal; await PlacesUtils.history.clear(); await PlacesUtils.bookmarks.eraseEverything(); + Services.telemetry.setEventRecordingEnabled("navigation", false); }); await BrowserTestUtils.withNewTab({ gBrowser }, async () => { diff --git a/browser/extensions/formautofill/test/browser/address/browser_address_telemetry.js b/browser/extensions/formautofill/test/browser/address/browser_address_telemetry.js index 0991960675ca..5d2682b6b796 100644 --- a/browser/extensions/formautofill/test/browser/address/browser_address_telemetry.js +++ b/browser/extensions/formautofill/test/browser/address/browser_address_telemetry.js @@ -264,8 +264,14 @@ add_setup(async function () { ], }); + Services.telemetry.setEventRecordingEnabled(EVENT_CATEGORY, true); + Services.telemetry.clearEvents(); Services.telemetry.clearScalars(); + + registerCleanupFunction(() => { + Services.telemetry.setEventRecordingEnabled(EVENT_CATEGORY, false); + }); }); add_task(async function test_popup_opened() { diff --git a/browser/extensions/formautofill/test/browser/browser_iframe_layout_telemetry.js b/browser/extensions/formautofill/test/browser/browser_iframe_layout_telemetry.js index d0eeb0408199..563901c40871 100644 --- a/browser/extensions/formautofill/test/browser/browser_iframe_layout_telemetry.js +++ b/browser/extensions/formautofill/test/browser/browser_iframe_layout_telemetry.js @@ -37,6 +37,10 @@ function assertGleanTelemetry(events, expected_number_of_flowid = 1) { } add_setup(async function () { + Services.telemetry.setEventRecordingEnabled("creditcard", true); + registerCleanupFunction(async function () { + Services.telemetry.setEventRecordingEnabled("creditcard", false); + }); await clearGleanTelemetry(); }); diff --git a/browser/extensions/formautofill/test/browser/creditCard/browser_creditCard_telemetry.js b/browser/extensions/formautofill/test/browser/creditCard/browser_creditCard_telemetry.js index b8ebb13532fe..06332e165e0d 100644 --- a/browser/extensions/formautofill/test/browser/creditCard/browser_creditCard_telemetry.js +++ b/browser/extensions/formautofill/test/browser/creditCard/browser_creditCard_telemetry.js @@ -191,6 +191,10 @@ async function openTabAndUseCreditCard( } add_setup(async function () { + Services.telemetry.setEventRecordingEnabled("creditcard", true); + registerCleanupFunction(async function () { + Services.telemetry.setEventRecordingEnabled("creditcard", false); + }); await clearGleanTelemetry(); }); diff --git a/browser/extensions/search-detection/extension/api.js b/browser/extensions/search-detection/extension/api.js index d49d2d468027..23d093b01924 100644 --- a/browser/extensions/search-detection/extension/api.js +++ b/browser/extensions/search-detection/extension/api.js @@ -27,6 +27,7 @@ const SEARCH_TOPIC_ENGINE_MODIFIED = "browser-search-engine-modified"; this.addonsSearchDetection = class extends ExtensionAPI { getAPI(context) { + Services.telemetry.setEventRecordingEnabled("addonsSearchDetection", true); const { extension } = context; // We want to temporarily store the first monitored URLs that have been diff --git a/browser/modules/BrowserUsageTelemetry.sys.mjs b/browser/modules/BrowserUsageTelemetry.sys.mjs index 3919453b8bb4..a2338b0f8cf8 100644 --- a/browser/modules/BrowserUsageTelemetry.sys.mjs +++ b/browser/modules/BrowserUsageTelemetry.sys.mjs @@ -1567,6 +1567,7 @@ export let BrowserUsageTelemetry = { let { installer_type, extra } = data; // Record the event (mirrored to legacy telemetry using GIFFT) + Services.telemetry.setEventRecordingEnabled("installation", true); if (installer_type == "full") { Glean.installation.firstSeenFull.record(extra); } else if (installer_type == "stub") { diff --git a/browser/modules/HomePage.sys.mjs b/browser/modules/HomePage.sys.mjs index aaed778831e0..f4da51fe754b 100644 --- a/browser/modules/HomePage.sys.mjs +++ b/browser/modules/HomePage.sys.mjs @@ -76,6 +76,8 @@ export let HomePage = { return; } + Services.telemetry.setEventRecordingEnabled("homepage", true); + // Now we have the values, listen for future updates. this._ignoreListListener = this._handleIgnoreListUpdated.bind(this); diff --git a/browser/modules/PartnerLinkAttribution.sys.mjs b/browser/modules/PartnerLinkAttribution.sys.mjs index 5a18be1c3356..2f399b5ba6be 100644 --- a/browser/modules/PartnerLinkAttribution.sys.mjs +++ b/browser/modules/PartnerLinkAttribution.sys.mjs @@ -33,6 +33,7 @@ export var PartnerLinkAttribution = { async makeRequest({ targetURL, source, campaignID }) { let partner = targetURL.match(/^https?:\/\/(?:www.)?([^.]*)/)[1]; + Services.telemetry.setEventRecordingEnabled("partner_link", true); let extra = { value: partner }; if (source == "newtab") { Glean.partnerLink.clickNewtab.record(extra); diff --git a/browser/modules/ProcessHangMonitor.sys.mjs b/browser/modules/ProcessHangMonitor.sys.mjs index aa49cbf46e4a..53b70f07e34e 100644 --- a/browser/modules/ProcessHangMonitor.sys.mjs +++ b/browser/modules/ProcessHangMonitor.sys.mjs @@ -92,6 +92,7 @@ export var ProcessHangMonitor = { Services.obs.addObserver(this, "quit-application-granted"); Services.obs.addObserver(this, "xpcom-shutdown"); Services.ww.registerNotification(this); + Services.telemetry.setEventRecordingEnabled("slow_script_warning", true); }, /** diff --git a/devtools/client/framework/devtools.js b/devtools/client/framework/devtools.js index df3b874ec8d2..05e340a454cc 100644 --- a/devtools/client/framework/devtools.js +++ b/devtools/client/framework/devtools.js @@ -103,6 +103,7 @@ function DevTools() { EventEmitter.decorate(this); this._telemetry = new Telemetry(); + this._telemetry.setEventRecordingEnabled(true); // List of all commands of debugged local Web Extension. this._commandsPromiseByWebExtId = new Map(); // Map diff --git a/devtools/client/shared/telemetry.js b/devtools/client/shared/telemetry.js index b4b473def19a..cbbffecc81aa 100644 --- a/devtools/client/shared/telemetry.js +++ b/devtools/client/shared/telemetry.js @@ -19,6 +19,8 @@ const { TelemetryEnvironment } = ChromeUtils.importESModule( ); const WeakMapMap = require("resource://devtools/client/shared/WeakMapMap.js"); +const CATEGORY = "devtools.main"; + // Object to be shared among all instances. const PENDING_EVENT_PROPERTIES = new WeakMapMap(); const PENDING_EVENTS = new WeakMapMap(); @@ -48,6 +50,7 @@ class Telemetry { this.keyedScalarAdd = this.keyedScalarAdd.bind(this); this.keyedScalarSet = this.keyedScalarSet.bind(this); this.recordEvent = this.recordEvent.bind(this); + this.setEventRecordingEnabled = this.setEventRecordingEnabled.bind(this); this.preparePendingEvent = this.preparePendingEvent.bind(this); this.addEventProperty = this.addEventProperty.bind(this); this.addEventProperties = this.addEventProperties.bind(this); @@ -386,6 +389,17 @@ class Telemetry { } } + /** + * Event telemetry is disabled by default. Use this method to enable or + * disable it. + * + * @param {Boolean} enabled + * Enabled: true or false. + */ + setEventRecordingEnabled(enabled) { + return Services.telemetry.setEventRecordingEnabled(CATEGORY, enabled); + } + /** * Telemetry events often need to make use of a number of properties from * completely different codepaths. To make this possible we create a diff --git a/devtools/docs/contributor/frontend/telemetry.md b/devtools/docs/contributor/frontend/telemetry.md index 97fb0644d832..5636031f7ac3 100644 --- a/devtools/docs/contributor/frontend/telemetry.md +++ b/devtools/docs/contributor/frontend/telemetry.md @@ -239,6 +239,9 @@ this._telemetry = new Telemetry(); And use the instance to report e.g. tool opening... ```js +// Event telemetry is disabled by default so enable it for your category. +this._telemetry.setEventRecordingEnabled(true); + // If you already have all the properties for the event you can send the // telemetry event using: // this._telemetry.recordEvent(method, object, value, extra) e.g. diff --git a/devtools/startup/DevToolsShim.sys.mjs b/devtools/startup/DevToolsShim.sys.mjs index 9e6d7314cdd9..41f874a1caca 100644 --- a/devtools/startup/DevToolsShim.sys.mjs +++ b/devtools/startup/DevToolsShim.sys.mjs @@ -45,6 +45,7 @@ export const DevToolsShim = { get telemetry() { if (!this._telemetry) { this._telemetry = new lazy.Telemetry(); + this._telemetry.setEventRecordingEnabled(true); } return this._telemetry; }, diff --git a/devtools/startup/DevToolsStartup.sys.mjs b/devtools/startup/DevToolsStartup.sys.mjs index 0c9db6cb85c4..c9cd3fc39f74 100644 --- a/devtools/startup/DevToolsStartup.sys.mjs +++ b/devtools/startup/DevToolsStartup.sys.mjs @@ -330,6 +330,7 @@ DevToolsStartup.prototype = { get telemetry() { if (!this._telemetry) { this._telemetry = new lazy.Telemetry(); + this._telemetry.setEventRecordingEnabled(true); } return this._telemetry; }, diff --git a/dom/ipc/ContentParent.cpp b/dom/ipc/ContentParent.cpp index 88de9f70d968..9b9cc0ad453d 100644 --- a/dom/ipc/ContentParent.cpp +++ b/dom/ipc/ContentParent.cpp @@ -166,6 +166,7 @@ #include "mozilla/net/CookieKey.h" #include "mozilla/net/TRRService.h" #include "mozilla/TelemetryComms.h" +#include "mozilla/TelemetryEventEnums.h" #include "mozilla/RemoteLazyInputStreamParent.h" #include "mozilla/widget/RemoteLookAndFeel.h" #include "mozilla/widget/ScreenManager.h" @@ -1203,9 +1204,17 @@ IPCResult ContentParent::RecvAttributionConversion( return IPC_OK(); } +Atomic sContentParentTelemetryEventEnabled(false); + /*static*/ void ContentParent::LogAndAssertFailedPrincipalValidationInfo( nsIPrincipal* aPrincipal, const char* aMethod) { + // nsContentSecurityManager may also enable this same event, but that's okay + if (!sContentParentTelemetryEventEnabled.exchange(true)) { + sContentParentTelemetryEventEnabled = true; + Telemetry::SetEventRecordingEnabled("security"_ns, true); + } + // Send Telemetry nsAutoCString principalScheme, principalType, spec; mozilla::glean::security::FissionPrincipalsExtra extra = {}; diff --git a/dom/quota/ActorsParent.cpp b/dom/quota/ActorsParent.cpp index 54f3803aea4b..bea2f51950f9 100644 --- a/dom/quota/ActorsParent.cpp +++ b/dom/quota/ActorsParent.cpp @@ -1510,6 +1510,8 @@ QuotaManager::Observer::Observe(nsISupports* aSubject, const char* aTopic, return NS_OK; } + Telemetry::SetEventRecordingEnabled("dom.quota.try"_ns, true); + gBasePath = new nsString(); nsCOMPtr baseDir; @@ -1596,6 +1598,8 @@ QuotaManager::Observer::Observe(nsISupports* aSubject, const char* aTopic, gBuildId = nullptr; + Telemetry::SetEventRecordingEnabled("dom.quota.try"_ns, false); + return NS_OK; } diff --git a/dom/security/nsContentSecurityManager.cpp b/dom/security/nsContentSecurityManager.cpp index 313780dd40ee..7b8a291e5375 100644 --- a/dom/security/nsContentSecurityManager.cpp +++ b/dom/security/nsContentSecurityManager.cpp @@ -48,6 +48,7 @@ #include "mozilla/Preferences.h" #include "mozilla/StaticPrefs_dom.h" #include "mozilla/StaticPrefs_security.h" +#include "mozilla/Telemetry.h" #include "xpcpublic.h" #include "nsMimeTypes.h" @@ -56,6 +57,7 @@ using namespace mozilla; using namespace mozilla::dom; +using namespace mozilla::Telemetry; NS_IMPL_ISUPPORTS(nsContentSecurityManager, nsIContentSecurityManager, nsIChannelEventSink) @@ -69,6 +71,7 @@ Atomic sJSHacksChecked(false); Atomic sJSHacksPresent(false); Atomic sCSSHacksChecked(false); Atomic sCSSHacksPresent(false); +Atomic sTelemetryEventEnabled(false); /* static */ bool nsContentSecurityManager::AllowTopLevelNavigationToDataURI( @@ -835,6 +838,11 @@ void nsContentSecurityManager::MeasureUnexpectedPrivilegedLoads( MOZ_LOG(sCSMLog, LogLevel::Debug, ("- redirects: %s\n\n", loggedRedirects.get())); + // Send Telemetry + if (!sTelemetryEventEnabled.exchange(true)) { + Telemetry::SetEventRecordingEnabled("security"_ns, true); + } + glean::security::UnexpectedLoadExtra extra = { .contenttype = Some(loggedContentType), .filedetails = Some(loggedFileDetails), diff --git a/dom/security/nsContentSecurityUtils.cpp b/dom/security/nsContentSecurityUtils.cpp index 6d04fa612aee..0a88c9584b40 100644 --- a/dom/security/nsContentSecurityUtils.cpp +++ b/dom/security/nsContentSecurityUtils.cpp @@ -45,17 +45,20 @@ #include "LoadInfo.h" #include "mozilla/StaticPrefs_extensions.h" #include "mozilla/StaticPrefs_dom.h" +#include "mozilla/Telemetry.h" #include "nsIConsoleService.h" #include "nsIStringBundle.h" using namespace mozilla; using namespace mozilla::dom; +using namespace mozilla::Telemetry; extern mozilla::LazyLogModule sCSMLog; extern Atomic sJSHacksChecked; extern Atomic sJSHacksPresent; extern Atomic sCSSHacksChecked; extern Atomic sCSSHacksPresent; +extern Atomic sTelemetryEventEnabled; // Helper function for IsConsideredSameOriginForUIR which makes // Principals of scheme 'http' return Principals of scheme 'https'. @@ -741,6 +744,10 @@ void nsContentSecurityUtils::NotifyEvalUsage(bool aIsSystemPrincipal, uint32_t aColumnNumber) { FilenameTypeAndDetails fileNameTypeAndDetails = FilenameToFilenameType(aFileName, false); + if (!sTelemetryEventEnabled.exchange(true)) { + sTelemetryEventEnabled = true; + Telemetry::SetEventRecordingEnabled("security"_ns, true); + } auto fileinfo = fileNameTypeAndDetails.second; auto value = Some(fileNameTypeAndDetails.first); if (aIsSystemPrincipal) { @@ -1567,6 +1574,10 @@ bool nsContentSecurityUtils::ValidateScriptFilename(JSContext* cx, FilenameTypeAndDetails fileNameTypeAndDetails = FilenameToFilenameType(filename, true); + if (!sTelemetryEventEnabled.exchange(true)) { + sTelemetryEventEnabled = true; + Telemetry::SetEventRecordingEnabled("security"_ns, true); + } glean::security::JavascriptLoadParentProcessExtra extra = { .fileinfo = fileNameTypeAndDetails.second, .value = Some(fileNameTypeAndDetails.first), diff --git a/dom/security/test/general/browser_test_report_blocking.js b/dom/security/test/general/browser_test_report_blocking.js index 6f926f87e0d2..ab66f1d8365e 100644 --- a/dom/security/test/general/browser_test_report_blocking.js +++ b/dom/security/test/general/browser_test_report_blocking.js @@ -63,6 +63,8 @@ const TEST_CASES = [ ]; add_setup(async function () { + Services.telemetry.setEventRecordingEnabled("security.ui.xfocsperror", true); + await SpecialPowers.pushPrefEnv({ set: [ ["security.xfocsp.errorReporting.enabled", true], diff --git a/image/decoders/nsAVIFDecoder.cpp b/image/decoders/nsAVIFDecoder.cpp index b63f010a4bfd..4bef19903421 100644 --- a/image/decoders/nsAVIFDecoder.cpp +++ b/image/decoders/nsAVIFDecoder.cpp @@ -673,6 +673,9 @@ class Dav1dDecoder final : AVIFDecoderInterface { // the easiest way to see if we're getting unexpected behavior to // investigate. if (aShouldSendTelemetry && r != 0) { + // Uncomment once bug 1691156 is fixed + // mozilla::Telemetry::SetEventRecordingEnabled("avif"_ns, true); + mozilla::glean::avif::Dav1dGetPictureReturnValueExtra extra = { .value = Some(nsPrintfCString("%d", r)), }; diff --git a/ipc/glue/UtilityProcessHost.cpp b/ipc/glue/UtilityProcessHost.cpp index 1f36601c4727..df69427ba9e9 100644 --- a/ipc/glue/UtilityProcessHost.cpp +++ b/ipc/glue/UtilityProcessHost.cpp @@ -110,6 +110,10 @@ bool UtilityProcessHost::Launch(geckoargs::ChildProcessArgs aExtraOpts) { EnsureWidevineL1PathForSandbox(aExtraOpts); #endif +#if defined(MOZ_WMF_CDM) && defined(MOZ_SANDBOX) + EnanbleMFCDMTelemetryEventIfNeeded(); +#endif + mLaunchPhase = LaunchPhase::Waiting; if (!GeckoChildProcessHost::AsyncLaunch(std::move(aExtraOpts))) { @@ -410,4 +414,17 @@ void UtilityProcessHost::EnsureWidevineL1PathForSandbox( #endif +#if defined(MOZ_WMF_CDM) && defined(MOZ_SANDBOX) +void UtilityProcessHost::EnanbleMFCDMTelemetryEventIfNeeded() const { + if (mSandbox != SandboxingKind::MF_MEDIA_ENGINE_CDM) { + return; + } + static bool sTelemetryEventEnabled = false; + if (!sTelemetryEventEnabled) { + sTelemetryEventEnabled = true; + Telemetry::SetEventRecordingEnabled("mfcdm"_ns, true); + } +} +#endif + } // namespace mozilla::ipc diff --git a/js/xpconnect/src/XPCJSContext.cpp b/js/xpconnect/src/XPCJSContext.cpp index 397855b28820..d810a2acc851 100644 --- a/js/xpconnect/src/XPCJSContext.cpp +++ b/js/xpconnect/src/XPCJSContext.cpp @@ -586,6 +586,7 @@ AutoScriptActivity::~AutoScriptActivity() { } static const double sChromeSlowScriptTelemetryCutoff(10.0); +static bool sTelemetryEventEnabled(false); // static bool XPCJSContext::InterruptCallback(JSContext* cx) { @@ -1443,6 +1444,11 @@ void XPCJSContext::AfterProcessTask(uint32_t aNewRecursionDepth) { } } if (hangDuration > limit) { + if (!sTelemetryEventEnabled) { + sTelemetryEventEnabled = true; + Telemetry::SetEventRecordingEnabled("slow_script_warning"_ns, true); + } + // Use AppendFloat to avoid printf-type APIs using locale-specific // decimal separators, when we definitely want a `.`. nsCString durationStr; diff --git a/modules/libjar/nsJARChannel.cpp b/modules/libjar/nsJARChannel.cpp index c65a154d22c9..dbc111f3ef01 100644 --- a/modules/libjar/nsJARChannel.cpp +++ b/modules/libjar/nsJARChannel.cpp @@ -24,6 +24,7 @@ #include "mozilla/Preferences.h" #include "mozilla/ScopeExit.h" #include "mozilla/StaticPrefs_network.h" +#include "mozilla/Telemetry.h" #include "mozilla/glean/GleanMetrics.h" #include "private/pprio.h" #include "nsInputStreamPump.h" @@ -870,6 +871,7 @@ static void RecordZeroLengthEvent(bool aIsSync, const nsCString& aSpec, bool isTest = fileName.Find("test_empty_file.zip!") != -1; bool isOmniJa = StringBeginsWith(fileName, "omni.ja!"_ns); + Telemetry::SetEventRecordingEnabled("zero_byte_load"_ns, true); if (StringEndsWith(fileName, ".ftl"_ns)) { // FTL uses I/O to test for file presence, so we get // a high volume of events from it, but it is not erronous. diff --git a/modules/libjar/test/unit/test_empty_jar_telemetry.js b/modules/libjar/test/unit/test_empty_jar_telemetry.js index ea6a383c890d..45bf83a11319 100644 --- a/modules/libjar/test/unit/test_empty_jar_telemetry.js +++ b/modules/libjar/test/unit/test_empty_jar_telemetry.js @@ -93,6 +93,7 @@ function makeChan() { add_task(async function test_empty_jar_file_async() { var chan = makeChan(); + Services.telemetry.setEventRecordingEnabled("zero_byte_load", true); Services.telemetry.clearEvents(); await new Promise(resolve => { @@ -126,6 +127,7 @@ add_task(async function test_empty_jar_file_async() { add_task(async function test_empty_jar_file_sync() { var chan = makeChan(); + Services.telemetry.setEventRecordingEnabled("zero_byte_load", true); Services.telemetry.clearEvents(); await new Promise(resolve => { diff --git a/modules/libpref/Preferences.cpp b/modules/libpref/Preferences.cpp index 123980c45326..9b76f3b66237 100644 --- a/modules/libpref/Preferences.cpp +++ b/modules/libpref/Preferences.cpp @@ -161,6 +161,8 @@ static void ShutdownAlwaysPrefs(); // Low-level types and operations //=========================================================================== +Atomic sPrefTelemetryEventEnabled(false); + typedef nsTArray PrefSaveData; // 1 MB should be enough for everyone. @@ -661,6 +663,10 @@ class Pref { #define CHECK_SANITIZATION() \ if (IsPreferenceSanitized(this)) { \ + if (!sPrefTelemetryEventEnabled.exchange(true)) { \ + sPrefTelemetryEventEnabled = true; \ + Telemetry::SetEventRecordingEnabled("security"_ns, true); \ + } \ glean::security::pref_usage_content_process.Record( \ Some(glean::security::PrefUsageContentProcessExtra{Some(Name())})); \ if (sCrashOnBlocklistedPref) { \ @@ -1170,6 +1176,11 @@ class MOZ_STACK_CLASS PrefWrapper : public PrefWrapperBase { // This check will be performed in the above functions; but for NoneType // we need to do it explicitly, then fall-through. if (IsPreferenceSanitized(Name())) { + if (!sPrefTelemetryEventEnabled.exchange(true)) { + sPrefTelemetryEventEnabled = true; + Telemetry::SetEventRecordingEnabled("security"_ns, true); + } + glean::security::pref_usage_content_process.Record(Some( glean::security::PrefUsageContentProcessExtra{Some(Name())})); @@ -1192,6 +1203,11 @@ class MOZ_STACK_CLASS PrefWrapper : public PrefWrapperBase { // WantValueKind may short-circuit GetValue functions and cause them to // return early, before this check occurs in GetFooValue() if (this->is() && IsPreferenceSanitized(this->as())) { + if (!sPrefTelemetryEventEnabled.exchange(true)) { + sPrefTelemetryEventEnabled = true; + Telemetry::SetEventRecordingEnabled("security"_ns, true); + } + glean::security::pref_usage_content_process.Record( Some(glean::security::PrefUsageContentProcessExtra{Some(Name())})); @@ -5401,6 +5417,11 @@ int32_t Preferences::GetType(const char* aPrefName) { case PrefType::None: if (IsPreferenceSanitized(aPrefName)) { + if (!sPrefTelemetryEventEnabled.exchange(true)) { + sPrefTelemetryEventEnabled = true; + Telemetry::SetEventRecordingEnabled("security"_ns, true); + } + glean::security::pref_usage_content_process.Record(Some( glean::security::PrefUsageContentProcessExtra{Some(aPrefName)})); diff --git a/modules/libpref/init/StaticPrefList.yaml b/modules/libpref/init/StaticPrefList.yaml index 94aca8b8fe8d..3e216dd2666e 100644 --- a/modules/libpref/init/StaticPrefList.yaml +++ b/modules/libpref/init/StaticPrefList.yaml @@ -13384,6 +13384,12 @@ value: 6000 mirror: always +# The timeout of the TRR confirmation request +- name: network.trr.confirmation_telemetry_enabled + type: RelaxedAtomicBool + value: true + mirror: always + # Whether to send the Accept-Language header for TRR requests - name: network.trr.send_accept-language_headers type: RelaxedAtomicBool diff --git a/modules/libpref/test/browser/browser_sanitization_events.js b/modules/libpref/test/browser/browser_sanitization_events.js index 156bc92c3be5..537347852378 100644 --- a/modules/libpref/test/browser/browser_sanitization_events.js +++ b/modules/libpref/test/browser/browser_sanitization_events.js @@ -44,6 +44,7 @@ add_task(async function sanitized_pref_test() { ], }); + Services.telemetry.setEventRecordingEnabled("security", true); Services.telemetry.clearEvents(); TelemetryTestUtils.assertNumberOfEvents(0, { process: "content" }); diff --git a/netwerk/dns/TRRService.cpp b/netwerk/dns/TRRService.cpp index a0b3686a622e..a887930d70b3 100644 --- a/netwerk/dns/TRRService.cpp +++ b/netwerk/dns/TRRService.cpp @@ -164,6 +164,12 @@ bool TRRService::CheckCaptivePortalIsPassed() { return result; } +static void EventTelemetryPrefChanged(const char* aPref, void* aData) { + Telemetry::SetEventRecordingEnabled( + "network.dns"_ns, + StaticPrefs::network_trr_confirmation_telemetry_enabled()); +} + nsresult TRRService::Init(bool aNativeHTTPSQueryEnabled) { MOZ_ASSERT(NS_IsMainThread(), "wrong thread"); if (mInitialized) { @@ -209,6 +215,10 @@ nsresult TRRService::Init(bool aNativeHTTPSQueryEnabled) { sTRRBackgroundThread = thread; } + Preferences::RegisterCallbackAndCall( + EventTelemetryPrefChanged, + "network.trr.confirmation_telemetry_enabled"_ns); + LOG(("Initialized TRRService\n")); return NS_OK; } diff --git a/parser/htmlparser/nsExpatDriver.cpp b/parser/htmlparser/nsExpatDriver.cpp index 72f7db92963a..f522ffad5262 100644 --- a/parser/htmlparser/nsExpatDriver.cpp +++ b/parser/htmlparser/nsExpatDriver.cpp @@ -34,6 +34,7 @@ #include "mozilla/BasePrincipal.h" #include "mozilla/IntegerTypeTraits.h" #include "mozilla/NullPrincipal.h" +#include "mozilla/Telemetry.h" #include "mozilla/glean/GleanMetrics.h" #include "nsThreadUtils.h" @@ -1107,6 +1108,7 @@ nsresult nsExpatDriver::HandleError() { docShellDestroyed.Assign(destroyed ? "true"_ns : "false"_ns); } + mozilla::Telemetry::SetEventRecordingEnabled("ysod"_ns, true); mozilla::glean::ysod::ShownYsodExtra extra = { .destroyed = mozilla::Some(docShellDestroyed), .errorCode = mozilla::Some(code), diff --git a/parser/htmlparser/tests/mochitest/browser_ysod_telemetry.js b/parser/htmlparser/tests/mochitest/browser_ysod_telemetry.js index 8b7a5c05850d..d7a654cad066 100644 --- a/parser/htmlparser/tests/mochitest/browser_ysod_telemetry.js +++ b/parser/htmlparser/tests/mochitest/browser_ysod_telemetry.js @@ -6,6 +6,7 @@ const { TelemetryTestUtils } = ChromeUtils.importESModule( add_task(async function test_popup_opened() { Services.telemetry.clearEvents(); + Services.telemetry.setEventRecordingEnabled("ysod", true); const PAGE_URL = getRootDirectory(gTestPath) + "broken_xml.xhtml"; let viewSourceTab = await BrowserTestUtils.openNewForegroundTab( diff --git a/services/common/uptake-telemetry.sys.mjs b/services/common/uptake-telemetry.sys.mjs index 3eb69dce8f50..528d92c16924 100644 --- a/services/common/uptake-telemetry.sys.mjs +++ b/services/common/uptake-telemetry.sys.mjs @@ -24,6 +24,9 @@ XPCOMUtils.defineLazyPreferenceGetter( "services.common.uptake.sampleRate" ); +// Telemetry events id (see Events.yaml). +const TELEMETRY_EVENTS_ID = "uptake.remotecontent.result"; + /** * A wrapper around certain low-level operations that can be substituted for testing. */ @@ -160,6 +163,14 @@ export class UptakeTelemetry { throw new Error(`Unknown status '${status}'`); } + // Report event for real-time monitoring. See Events.yaml for registration. + // Contrary to histograms, Telemetry Events are not enabled by default. + // Enable them on first call to `report()`. + if (!this._eventsEnabled) { + Services.telemetry.setEventRecordingEnabled(TELEMETRY_EVENTS_ID, true); + this._eventsEnabled = true; + } + const hash = await UptakeTelemetry.Policy.getClientIDHash(); const channel = UptakeTelemetry.Policy.getChannel(); const shouldSendEvent = diff --git a/services/fxaccounts/FxAccountsTelemetry.sys.mjs b/services/fxaccounts/FxAccountsTelemetry.sys.mjs index 3e4bb84d62d8..a5d6c714ff9a 100644 --- a/services/fxaccounts/FxAccountsTelemetry.sys.mjs +++ b/services/fxaccounts/FxAccountsTelemetry.sys.mjs @@ -35,6 +35,7 @@ XPCOMUtils.defineLazyPreferenceGetter( export class FxAccountsTelemetry { constructor(fxai) { this._fxai = fxai; + Services.telemetry.setEventRecordingEnabled("fxa", true); } // Records an event *in the Fxa/Sync ping*. diff --git a/services/sync/modules/SyncedTabs.sys.mjs b/services/sync/modules/SyncedTabs.sys.mjs index f1d2550cb2f2..b36fe0ca0e5b 100644 --- a/services/sync/modules/SyncedTabs.sys.mjs +++ b/services/sync/modules/SyncedTabs.sys.mjs @@ -402,6 +402,7 @@ export var SyncedTabs = { }, recordSyncedTabsTelemetry(object, tabEvent, extraOptions) { + Services.telemetry.setEventRecordingEnabled("synced_tabs", true); if ( !["fxa_avatar_menu", "fxa_app_menu", "synced_tabs_sidebar"].includes( object diff --git a/toolkit/components/cookiebanners/nsCookieBannerService.cpp b/toolkit/components/cookiebanners/nsCookieBannerService.cpp index 0a01a7905ce9..9d306081a836 100644 --- a/toolkit/components/cookiebanners/nsCookieBannerService.cpp +++ b/toolkit/components/cookiebanners/nsCookieBannerService.cpp @@ -1126,6 +1126,14 @@ nsCookieBannerService::OnLocationChange(nsIWebProgress* aWebProgress, return NS_OK; } + // The static value to track if we have enabled the event telemetry for + // cookie banner. + static bool sTelemetryEventEnabled = false; + if (!sTelemetryEventEnabled) { + sTelemetryEventEnabled = true; + Telemetry::SetEventRecordingEnabled("cookie_banner"_ns, true); + } + glean::cookie_banners::ReloadExtra extra = { .hasClickRule = Some(hasClickRuleInData), .hasCookieRule = Some(hasCookieRuleInData), diff --git a/toolkit/components/downloads/test/unit/test_DownloadList.js b/toolkit/components/downloads/test/unit/test_DownloadList.js index 791faa1ab006..7045824c9cd3 100644 --- a/toolkit/components/downloads/test/unit/test_DownloadList.js +++ b/toolkit/components/downloads/test/unit/test_DownloadList.js @@ -652,6 +652,7 @@ add_task(async function test_DownloadSummary_notifications() { */ add_task(async function test_downloadAddedTelemetry() { Services.telemetry.clearEvents(); + Services.telemetry.setEventRecordingEnabled("downloads", true); let targetFile = getTempFile(TEST_TARGET_FILE_NAME); diff --git a/toolkit/components/extensions/parent/ext-telemetry.js b/toolkit/components/extensions/parent/ext-telemetry.js index b35b64efde44..eeeec5b1c34d 100644 --- a/toolkit/components/extensions/parent/ext-telemetry.js +++ b/toolkit/components/extensions/parent/ext-telemetry.js @@ -119,9 +119,13 @@ this.telemetry = class extends ExtensionAPI { throw new ExtensionUtils.ExtensionError(ex); } }, - setEventRecordingEnabled(_category, _enabled) { + setEventRecordingEnabled(category, enabled) { desktopCheck(); - // No-op since bug 1920562 (Fx133). + try { + Services.telemetry.setEventRecordingEnabled(category, enabled); + } catch (ex) { + throw new ExtensionUtils.ExtensionError(ex); + } }, registerEvents(_category, _data) { desktopCheck(); diff --git a/toolkit/components/extensions/schemas/telemetry.json b/toolkit/components/extensions/schemas/telemetry.json index 6fd9b67b1c7e..5e3c8186e44c 100644 --- a/toolkit/components/extensions/schemas/telemetry.json +++ b/toolkit/components/extensions/schemas/telemetry.json @@ -363,9 +363,8 @@ }, { "name": "setEventRecordingEnabled", - "deprecated": "`setEventRecordingEnabled` has been deprecated since Firefox 133 (see bug 1920562)", "type": "function", - "description": "Enable recording of events in a category. Events default to recording enabled. This allows to toggle recording for all events in the specified category.", + "description": "Enable recording of events in a category. Events default to recording disabled. This allows to toggle recording for all events in the specified category.", "async": true, "parameters": [ { diff --git a/toolkit/components/extensions/test/xpcshell/test_ext_telemetry.js b/toolkit/components/extensions/test/xpcshell/test_ext_telemetry.js index 8b0cbac3f436..8e3313cb7409 100644 --- a/toolkit/components/extensions/test/xpcshell/test_ext_telemetry.js +++ b/toolkit/components/extensions/test/xpcshell/test_ext_telemetry.js @@ -535,6 +535,7 @@ if (AppConstants.MOZ_BUILD_APP === "browser") { add_task(async function test_telemetry_record_event() { Services.telemetry.clearEvents(); + Services.telemetry.setEventRecordingEnabled("telemetry.test", true); ExtensionTestUtils.failOnSchemaWarnings(false); @@ -567,12 +568,14 @@ if (AppConstants.MOZ_BUILD_APP === "browser") { ExtensionTestUtils.failOnSchemaWarnings(true); + Services.telemetry.setEventRecordingEnabled("telemetry.test", false); Services.telemetry.clearEvents(); }); // Bug 1536877 add_task(async function test_telemetry_record_event_value_must_be_string() { Services.telemetry.clearEvents(); + Services.telemetry.setEventRecordingEnabled("telemetry.test", true); ExtensionTestUtils.failOnSchemaWarnings(false); @@ -616,6 +619,7 @@ if (AppConstants.MOZ_BUILD_APP === "browser") { ExtensionTestUtils.failOnSchemaWarnings(true); + Services.telemetry.setEventRecordingEnabled("telemetry.test", false); Services.telemetry.clearEvents(); }); diff --git a/toolkit/components/formautofill/FormAutofillParent.sys.mjs b/toolkit/components/formautofill/FormAutofillParent.sys.mjs index 6eab6cc6a7b4..f7bc47c8afa6 100644 --- a/toolkit/components/formautofill/FormAutofillParent.sys.mjs +++ b/toolkit/components/formautofill/FormAutofillParent.sys.mjs @@ -93,6 +93,9 @@ export let FormAutofillStatus = { if (FormAutofill.isAutofillCreditCardsAvailable) { Services.prefs.addObserver(ENABLED_AUTOFILL_CREDITCARDS_PREF, this); } + + Services.telemetry.setEventRecordingEnabled("creditcard", true); + Services.telemetry.setEventRecordingEnabled("address", true); }, /** diff --git a/toolkit/components/glean/docs/user/gifft.md b/toolkit/components/glean/docs/user/gifft.md index 6b8d25984640..5c364c53148b 100644 --- a/toolkit/components/glean/docs/user/gifft.md +++ b/toolkit/components/glean/docs/user/gifft.md @@ -156,6 +156,15 @@ Assert.equal(true, snapshot["telemetry.test.mirror_for_labeled_bool"]["1".repeat ### Telemetry Events A Glean event can be mirrored to a Telemetry Event. +Telemetry Events must be enabled before they can be recorded to via the API +`Telemetry.setEventRecordingEnabled(category, enable);`. +If the Telemetry Event isn't enabled, +recording to the Glean event will still work, +and the event will be Summarized in Telemetry as all disabled events are. + +See +[the Telemetry Event docs](/toolkit/components/telemetry/collection/events.rst) +for details on how disabled Telemetry Events behave. In order to make use of the `value` field in Telemetry Events, you must first define an event extra in the metrics.yaml file with the name "value". diff --git a/toolkit/components/glean/docs/user/glean_for_legacy_events.md b/toolkit/components/glean/docs/user/glean_for_legacy_events.md index 2854d268a877..3efec45a9acb 100644 --- a/toolkit/components/glean/docs/user/glean_for_legacy_events.md +++ b/toolkit/components/glean/docs/user/glean_for_legacy_events.md @@ -24,6 +24,12 @@ To record your new event, use [the Glean `record(...)` API][glean-event-api]. To test your new event, use [the Glean `testGetValue()` API][glean-test-api]. +```{admonition} Don't Forget! +Though you're using Glean, there's still a Legacy Telemetry event underneath. +You must call `Services.telemetry.setEventRecordingEnabled("myCategory", true);` +in order for the Legacy Telemetry event to be recorded. +``` + Your Legacy Telemetry event will appear in `about:telemetry` when your code is triggered as confirmation this is all working as you expect. diff --git a/toolkit/components/glean/tests/xpcshell/test_GIFFT.js b/toolkit/components/glean/tests/xpcshell/test_GIFFT.js index 519a0e36a18b..fe06fe7b8f5f 100644 --- a/toolkit/components/glean/tests/xpcshell/test_GIFFT.js +++ b/toolkit/components/glean/tests/xpcshell/test_GIFFT.js @@ -218,6 +218,8 @@ add_task(function test_gifft_string_list_works() { }); add_task(function test_gifft_events() { + Telemetry.setEventRecordingEnabled("telemetry.test", true); + Glean.testOnlyIpc.noExtraEvent.record(); var events = Glean.testOnlyIpc.noExtraEvent.testGetValue(); Assert.equal(1, events.length); diff --git a/toolkit/components/glean/tests/xpcshell/test_GIFFTIPC.js b/toolkit/components/glean/tests/xpcshell/test_GIFFTIPC.js index a747344a0e15..5461044ccee3 100644 --- a/toolkit/components/glean/tests/xpcshell/test_GIFFTIPC.js +++ b/toolkit/components/glean/tests/xpcshell/test_GIFFTIPC.js @@ -134,6 +134,8 @@ add_task({ skip_if: () => runningInParent }, async function run_child_stuff() { add_task( { skip_if: () => !runningInParent }, async function test_child_metrics() { + Telemetry.setEventRecordingEnabled("telemetry.test", true); + // Clear any stray Telemetry data Telemetry.clearScalars(); Telemetry.getSnapshotForHistograms("main", true); diff --git a/toolkit/components/messaging-system/targeting/Targeting.sys.mjs b/toolkit/components/messaging-system/targeting/Targeting.sys.mjs index 0f27f9e8484d..c51fc375bd20 100644 --- a/toolkit/components/messaging-system/targeting/Targeting.sys.mjs +++ b/toolkit/components/messaging-system/targeting/Targeting.sys.mjs @@ -20,6 +20,7 @@ ChromeUtils.defineESModuleGetters(lazy, { setTimeout: "resource://gre/modules/Timer.sys.mjs", }); +const TARGETING_EVENT_CATEGORY = "messaging_experiments"; const DEFAULT_TIMEOUT = 5000; const ERROR_TYPES = { ATTRIBUTE_ERROR: "AttributeError", @@ -80,6 +81,9 @@ export class TargetingContext { // Used in telemetry to report where the targeting expression is coming from this.#telemetrySource = options.source; + + // Enable event recording + Services.telemetry.setEventRecordingEnabled(TARGETING_EVENT_CATEGORY, true); } setTelemetrySource(source) { diff --git a/toolkit/components/nimbus/ExperimentAPI.sys.mjs b/toolkit/components/nimbus/ExperimentAPI.sys.mjs index e70da125a551..7ab3bce75b14 100644 --- a/toolkit/components/nimbus/ExperimentAPI.sys.mjs +++ b/toolkit/components/nimbus/ExperimentAPI.sys.mjs @@ -25,6 +25,7 @@ XPCOMUtils.defineLazyPreferenceGetter( COLLECTION_ID_PREF, COLLECTION_ID_FALLBACK ); +const EXPOSURE_EVENT_CATEGORY = "normandy"; function parseJSON(value) { if (value) { @@ -266,6 +267,7 @@ export const ExperimentAPI = { }, recordExposureEvent({ featureId, experimentSlug, branchSlug }) { + Services.telemetry.setEventRecordingEnabled(EXPOSURE_EVENT_CATEGORY, true); Glean.normandy.exposeNimbusExperiment.record({ value: experimentSlug, branchSlug, diff --git a/toolkit/components/nimbus/lib/NimbusFeatures.cpp b/toolkit/components/nimbus/lib/NimbusFeatures.cpp index 0f3a1b78358c..39140be20597 100644 --- a/toolkit/components/nimbus/lib/NimbusFeatures.cpp +++ b/toolkit/components/nimbus/lib/NimbusFeatures.cpp @@ -195,6 +195,7 @@ nsresult NimbusFeatures::RecordExposureEvent(const nsACString& aFeatureId, // this featureId return NS_ERROR_UNEXPECTED; } + Telemetry::SetEventRecordingEnabled("normandy"_ns, true); glean::normandy::expose_nimbus_experiment.Record( Some(glean::normandy::ExposeNimbusExperimentExtra{ .branchslug = Some(branchName), diff --git a/toolkit/components/nimbus/test/unit/test_ExperimentManager_prefs.js b/toolkit/components/nimbus/test/unit/test_ExperimentManager_prefs.js index 214b6212ce64..7926623aa01d 100644 --- a/toolkit/components/nimbus/test/unit/test_ExperimentManager_prefs.js +++ b/toolkit/components/nimbus/test/unit/test_ExperimentManager_prefs.js @@ -11,6 +11,9 @@ const { PrefUtils } = ChromeUtils.importESModule( const { TelemetryTestUtils } = ChromeUtils.importESModule( "resource://testing-common/TelemetryTestUtils.sys.mjs" ); +const { TelemetryEvents } = ChromeUtils.importESModule( + "resource://normandy/lib/TelemetryEvents.sys.mjs" +); /** * Pick a single entry from an object and return a new object containing only @@ -1657,6 +1660,8 @@ add_task(async function test_restorePrefs_experimentAndRollout() { }); add_task(async function test_prefChange() { + TelemetryEvents.init(); + const LEGACY_FILTER = { category: "normandy", method: "unenroll", @@ -2708,6 +2713,8 @@ add_task(async function test_prefChanged_noPrefSet() { }); add_task(async function test_restorePrefs_manifestChanged() { + TelemetryEvents.init(); + const LEGACY_FILTER = { category: "normandy", method: "unenroll", diff --git a/toolkit/components/nimbus/test/unit/test_RemoteSettingsExperimentLoader_updateRecipes.js b/toolkit/components/nimbus/test/unit/test_RemoteSettingsExperimentLoader_updateRecipes.js index 674337a1591a..80e0316af4f5 100644 --- a/toolkit/components/nimbus/test/unit/test_RemoteSettingsExperimentLoader_updateRecipes.js +++ b/toolkit/components/nimbus/test/unit/test_RemoteSettingsExperimentLoader_updateRecipes.js @@ -20,6 +20,9 @@ const { PanelTestProvider } = ChromeUtils.importESModule( const { TelemetryTestUtils } = ChromeUtils.importESModule( "resource://testing-common/TelemetryTestUtils.sys.mjs" ); +const { TelemetryEvents } = ChromeUtils.importESModule( + "resource://normandy/lib/TelemetryEvents.sys.mjs" +); add_setup(async function setup() { do_get_profile(); @@ -508,6 +511,8 @@ add_task(async function test_updateRecipes_simpleFeatureInvalidAfterUpdate() { }); add_task(async function test_updateRecipes_validationTelemetry() { + TelemetryEvents.init(); + Services.telemetry.snapshotEvents( Ci.nsITelemetry.DATASET_PRERELEASE_CHANNELS, /* clear = */ true @@ -1031,6 +1036,7 @@ add_task(async function test_updateRecipes_invalidFeature_mismatch() { }); add_task(async function test_updateRecipes_rollout_bucketing() { + TelemetryEvents.init(); Services.fog.testResetFOG(); Services.telemetry.snapshotEvents( Ci.nsITelemetry.DATASET_PRERELEASE_CHANNELS, diff --git a/toolkit/components/nimbus/test/unit/test_localization.js b/toolkit/components/nimbus/test/unit/test_localization.js index 8c1527a93250..45fb743e3b72 100644 --- a/toolkit/components/nimbus/test/unit/test_localization.js +++ b/toolkit/components/nimbus/test/unit/test_localization.js @@ -9,6 +9,9 @@ const { ExperimentFakes, ExperimentTestUtils } = ChromeUtils.importESModule( const { TelemetryTestUtils } = ChromeUtils.importESModule( "resource://testing-common/TelemetryTestUtils.sys.mjs" ); +const { TelemetryEvents } = ChromeUtils.importESModule( + "resource://normandy/lib/TelemetryEvents.sys.mjs" +); const LOCALIZATIONS = { "en-US": { @@ -119,6 +122,7 @@ add_setup(function setup() { do_get_profile(); Services.fog.initializeFOG(); + TelemetryEvents.init(); registerCleanupFunction(ExperimentTestUtils.addTestFeatures(FEATURE)); registerCleanupFunction(resetTelemetry); diff --git a/toolkit/components/nimbus/test/unit/test_prefFlips.js b/toolkit/components/nimbus/test/unit/test_prefFlips.js index e782b8a7028d..8725371c858c 100644 --- a/toolkit/components/nimbus/test/unit/test_prefFlips.js +++ b/toolkit/components/nimbus/test/unit/test_prefFlips.js @@ -12,6 +12,9 @@ const { JsonSchema } = ChromeUtils.importESModule( const { TelemetryTestUtils } = ChromeUtils.importESModule( "resource://testing-common/TelemetryTestUtils.sys.mjs" ); +const { TelemetryEvents } = ChromeUtils.importESModule( + "resource://normandy/lib/TelemetryEvents.sys.mjs" +); const USER = "user"; const DEFAULT = "default"; @@ -145,6 +148,7 @@ function checkExpectedPrefBranches(prefs) { add_setup(function setup() { do_get_profile(); Services.fog.initializeFOG(); + TelemetryEvents.init(); const cleanupFeatures = ExperimentTestUtils.addTestFeatures( PREF_FEATURES[USER], diff --git a/toolkit/components/normandy/Normandy.sys.mjs b/toolkit/components/normandy/Normandy.sys.mjs index d2cd9311a18a..ce30bb8456ee 100644 --- a/toolkit/components/normandy/Normandy.sys.mjs +++ b/toolkit/components/normandy/Normandy.sys.mjs @@ -21,6 +21,7 @@ ChromeUtils.defineESModuleGetters(lazy, { RemoteSettingsExperimentLoader: "resource://nimbus/lib/RemoteSettingsExperimentLoader.sys.mjs", ShieldPreferences: "resource://normandy/lib/ShieldPreferences.sys.mjs", + TelemetryEvents: "resource://normandy/lib/TelemetryEvents.sys.mjs", }); const UI_AVAILABLE_NOTIFICATION = "sessionstore-windows-restored"; @@ -85,6 +86,12 @@ export var Normandy = { }, async finishInit() { + try { + lazy.TelemetryEvents.init(); + } catch (err) { + log.error("Failed to initialize telemetry events:", err); + } + await lazy.PreferenceRollouts.recordOriginalValues( this.rolloutPrefsChanged ); diff --git a/toolkit/components/normandy/lib/TelemetryEvents.sys.mjs b/toolkit/components/normandy/lib/TelemetryEvents.sys.mjs index 314aecc850da..c7f7c2fa99d9 100644 --- a/toolkit/components/normandy/lib/TelemetryEvents.sys.mjs +++ b/toolkit/components/normandy/lib/TelemetryEvents.sys.mjs @@ -2,7 +2,13 @@ * 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/. */ +const TELEMETRY_CATEGORY = "normandy"; + export const TelemetryEvents = { + init() { + Services.telemetry.setEventRecordingEnabled(TELEMETRY_CATEGORY, true); + }, + sendEvent(method, object, value, extra) { for (const val of Object.values(extra)) { if (val == null) { diff --git a/toolkit/components/normandy/test/browser/browser_Normandy.js b/toolkit/components/normandy/test/browser/browser_Normandy.js index c806334b47c8..7deba94ee8f3 100644 --- a/toolkit/components/normandy/test/browser/browser_Normandy.js +++ b/toolkit/components/normandy/test/browser/browser_Normandy.js @@ -37,6 +37,7 @@ function withStubInits() { withStub(PreferenceRollouts, "init"), withStub(PreferenceExperiments, "init"), withStub(RecipeRunner, "init"), + withStub(TelemetryEvents, "init"), testFunction ); }; @@ -246,6 +247,7 @@ decorate_task(withStubInits(), async function testStartupPrefInitFail() { "startup calls PreferenceExperiments.init" ); ok(RecipeRunner.init.called, "startup calls RecipeRunner.init"); + ok(TelemetryEvents.init.called, "startup calls TelemetryEvents.init"); ok(PreferenceRollouts.init.called, "startup calls PreferenceRollouts.init"); }); @@ -262,6 +264,25 @@ decorate_task( "startup calls PreferenceExperiments.init" ); ok(RecipeRunner.init.called, "startup calls RecipeRunner.init"); + ok(TelemetryEvents.init.called, "startup calls TelemetryEvents.init"); + ok(PreferenceRollouts.init.called, "startup calls PreferenceRollouts.init"); + } +); + +decorate_task( + withStubInits(), + async function testStartupTelemetryEventsInitFail() { + TelemetryEvents.init.throws(); + + await Normandy.finishInit(); + ok(AddonStudies.init.called, "startup calls AddonStudies.init"); + ok(AddonRollouts.init.called, "startup calls AddonRollouts.init"); + ok( + PreferenceExperiments.init.called, + "startup calls PreferenceExperiments.init" + ); + ok(RecipeRunner.init.called, "startup calls RecipeRunner.init"); + ok(TelemetryEvents.init.called, "startup calls TelemetryEvents.init"); ok(PreferenceRollouts.init.called, "startup calls PreferenceRollouts.init"); } ); @@ -279,6 +300,7 @@ decorate_task( "startup calls PreferenceExperiments.init" ); ok(RecipeRunner.init.called, "startup calls RecipeRunner.init"); + ok(TelemetryEvents.init.called, "startup calls TelemetryEvents.init"); ok(PreferenceRollouts.init.called, "startup calls PreferenceRollouts.init"); } ); diff --git a/toolkit/components/normandy/test/browser/head.js b/toolkit/components/normandy/test/browser/head.js index 40c68583df9c..354c38647e37 100644 --- a/toolkit/components/normandy/test/browser/head.js +++ b/toolkit/components/normandy/test/browser/head.js @@ -51,6 +51,9 @@ sinon.assert.fail = function (message) { ok(false, message); }; +// Prep Telemetry to receive events from tests +TelemetryEvents.init(); + this.TEST_XPI_URL = (function () { const dir = getChromeDir(getResolvedURI(gTestPath)); dir.append("addons"); diff --git a/toolkit/components/normandy/test/unit/test_addon_unenroll.js b/toolkit/components/normandy/test/unit/test_addon_unenroll.js index eef301aae3d6..3dd3c12c4b8d 100644 --- a/toolkit/components/normandy/test/unit/test_addon_unenroll.js +++ b/toolkit/components/normandy/test/unit/test_addon_unenroll.js @@ -10,6 +10,9 @@ const { BranchedAddonStudyAction } = ChromeUtils.importESModule( const { BaseAction } = ChromeUtils.importESModule( "resource://normandy/actions/BaseAction.sys.mjs" ); +const { TelemetryEvents } = ChromeUtils.importESModule( + "resource://normandy/lib/TelemetryEvents.sys.mjs" +); const { AddonManager } = ChromeUtils.importESModule( "resource://gre/modules/AddonManager.sys.mjs" ); @@ -36,6 +39,8 @@ add_task(async () => { ); AddonTestUtils.overrideCertDB(); await AddonTestUtils.promiseStartupManager(); + + TelemetryEvents.init(); }); decorate_task( diff --git a/toolkit/components/passwordmgr/LoginHelper.sys.mjs b/toolkit/components/passwordmgr/LoginHelper.sys.mjs index 34beab73a58a..43e89100a4f7 100644 --- a/toolkit/components/passwordmgr/LoginHelper.sys.mjs +++ b/toolkit/components/passwordmgr/LoginHelper.sys.mjs @@ -407,6 +407,8 @@ export const LoginHelper = { // Watch for pref changes to update cached pref values. Services.prefs.addObserver("signon.", () => this.updateSignonPrefs()); this.updateSignonPrefs(); + Services.telemetry.setEventRecordingEnabled("pwmgr", true); + Services.telemetry.setEventRecordingEnabled("form_autocomplete", true); // Watch for FXA Logout to reset signon.firefoxRelay to 'available' // Using hard-coded value for FxAccountsCommon.ONLOGOUT_NOTIFICATION because diff --git a/toolkit/components/passwordmgr/test/browser/browser_relay_telemetry.js b/toolkit/components/passwordmgr/test/browser/browser_relay_telemetry.js index 35c1e69a70cc..9c7808f43125 100644 --- a/toolkit/components/passwordmgr/test/browser/browser_relay_telemetry.js +++ b/toolkit/components/passwordmgr/test/browser/browser_relay_telemetry.js @@ -170,6 +170,7 @@ add_setup(async function () { const canRecordExtendedOld = Services.telemetry.canRecordExtended; Services.telemetry.canRecordExtended = true; Services.telemetry.clearEvents(); + Services.telemetry.setEventRecordingEnabled("relay_integration", true); gRelayACOptionsTitles = await new Localization([ "browser/firefoxRelay.ftl", @@ -185,6 +186,7 @@ add_setup(async function () { resolve(); }); }); + Services.telemetry.setEventRecordingEnabled("relay_integration", false); Services.telemetry.clearEvents(); Services.telemetry.canRecordExtended = canRecordExtendedOld; sinon.restore(); diff --git a/toolkit/components/pictureinpicture/tests/browser_aaa_run_first_firstTimePiPToggleEvents.js b/toolkit/components/pictureinpicture/tests/browser_aaa_run_first_firstTimePiPToggleEvents.js index b75c79d221df..df6261584c6a 100644 --- a/toolkit/components/pictureinpicture/tests/browser_aaa_run_first_firstTimePiPToggleEvents.js +++ b/toolkit/components/pictureinpicture/tests/browser_aaa_run_first_firstTimePiPToggleEvents.js @@ -223,6 +223,7 @@ add_task(async function test_eventTelemetry() { url: TEST_PAGE, }, async browser => { + Services.telemetry.setEventRecordingEnabled("pictureinpicture", true); let videoID = "no-controls"; const PIP_PREF = diff --git a/toolkit/components/reader/AboutReader.sys.mjs b/toolkit/components/reader/AboutReader.sys.mjs index ffcd8d78e608..8e9a501844c8 100644 --- a/toolkit/components/reader/AboutReader.sys.mjs +++ b/toolkit/components/reader/AboutReader.sys.mjs @@ -85,6 +85,8 @@ const DEFAULT_COLORS = { "selection-highlight": "#FFFFCC", }; +Services.telemetry.setEventRecordingEnabled("readermode", true); + const zoomOnCtrl = Services.prefs.getIntPref("mousewheel.with_control.action", 3) == 3; const zoomOnMeta = diff --git a/toolkit/components/reader/ReaderMode.sys.mjs b/toolkit/components/reader/ReaderMode.sys.mjs index 14c378a4e2dd..07c78f8e32a7 100644 --- a/toolkit/components/reader/ReaderMode.sys.mjs +++ b/toolkit/components/reader/ReaderMode.sys.mjs @@ -42,6 +42,8 @@ ChromeUtils.defineESModuleGetters(lazy, { const gIsFirefoxDesktop = Services.appinfo.ID == "{ec8030f7-c20a-464f-9b0e-13a3a9e97384}"; +Services.telemetry.setEventRecordingEnabled("readermode", true); + export var ReaderMode = { DEBUG: 0, diff --git a/toolkit/components/satchel/integrations/FirefoxRelay.sys.mjs b/toolkit/components/satchel/integrations/FirefoxRelay.sys.mjs index 4bd8a19f6632..ebe1f8e74d0d 100644 --- a/toolkit/components/satchel/integrations/FirefoxRelay.sys.mjs +++ b/toolkit/components/satchel/integrations/FirefoxRelay.sys.mjs @@ -743,6 +743,7 @@ class RelayDisabled {} class RelayFeature extends OptInFeature { constructor() { super(RelayOffered, RelayEnabled, RelayDisabled, gConfig.relayFeaturePref); + Services.telemetry.setEventRecordingEnabled("relay_integration", true); // Update the config when the signon.firefoxRelay.base_url pref is changed. // This is added mainly for tests. Services.prefs.addObserver( diff --git a/toolkit/components/telemetry/core/Telemetry.cpp b/toolkit/components/telemetry/core/Telemetry.cpp index b0f7a83a3fbb..b3f030a55f14 100644 --- a/toolkit/components/telemetry/core/Telemetry.cpp +++ b/toolkit/components/telemetry/core/Telemetry.cpp @@ -1633,6 +1633,13 @@ TelemetryImpl::ClearEvents() { return NS_OK; } +NS_IMETHODIMP +TelemetryImpl::SetEventRecordingEnabled(const nsACString& aCategory, + bool aEnabled) { + TelemetryEvent::SetEventRecordingEnabled(aCategory, aEnabled); + return NS_OK; +} + NS_IMETHODIMP TelemetryImpl::FlushBatchedChildTelemetry() { TelemetryIPCAccumulator::IPCTimerFired(nullptr, nullptr); @@ -2005,6 +2012,10 @@ void ScalarSetMaximum(mozilla::Telemetry::ScalarID aId, const nsAString& aKey, TelemetryScalar::SetMaximum(aId, aKey, aVal); } +void SetEventRecordingEnabled(const nsACString& aCategory, bool aEnabled) { + TelemetryEvent::SetEventRecordingEnabled(aCategory, aEnabled); +} + void ShutdownTelemetry() { TelemetryImpl::ShutdownTelemetry(); } } // namespace mozilla::Telemetry diff --git a/toolkit/components/telemetry/core/Telemetry.h b/toolkit/components/telemetry/core/Telemetry.h index e7ccc1277ac9..3e087bed814c 100644 --- a/toolkit/components/telemetry/core/Telemetry.h +++ b/toolkit/components/telemetry/core/Telemetry.h @@ -549,6 +549,16 @@ class MOZ_RAII AutoScalarTimer { const nsString key; }; +/** + * Enables recording of events in a category. + * Events default to recording disabled. + * This toggles recording for all events in the specified category. + * + * @param aCategory The category name. + * @param aEnabled Whether recording should be enabled or disabled. + */ +void SetEventRecordingEnabled(const nsACString& aCategory, bool aEnabled); + } // namespace Telemetry } // namespace mozilla diff --git a/toolkit/components/telemetry/core/TelemetryEvent.cpp b/toolkit/components/telemetry/core/TelemetryEvent.cpp index 2bd52cb00fa3..b032fff5212f 100644 --- a/toolkit/components/telemetry/core/TelemetryEvent.cpp +++ b/toolkit/components/telemetry/core/TelemetryEvent.cpp @@ -334,6 +334,9 @@ nsTHashMap gEventNameIDMap(kEventCount); // The CategoryName set. nsTHashSet gCategoryNames; +// This tracks the IDs of the categories for which recording is enabled. +nsTHashSet gEnabledCategories; + // The main event storage. Events are inserted here, keyed by process id and // in recording order. typedef nsUint32HashKey ProcessIDHashKey; @@ -371,6 +374,19 @@ unsigned int GetDataset(const StaticMutexAutoLock& lock, : nsITelemetry::DATASET_PRERELEASE_CHANNELS; } +nsCString GetCategory(const StaticMutexAutoLock& lock, + const EventKey& eventKey) { + if (!eventKey.dynamic) { + return gEventInfo[eventKey.id].common_info.category(); + } + + if (!gDynamicEventInfo) { + return ""_ns; + } + + return (*gDynamicEventInfo)[eventKey.id].category; +} + bool CanRecordEvent(const StaticMutexAutoLock& lock, const EventKey& eventKey, ProcessID process) { if (!gCanRecordBase) { @@ -481,10 +497,16 @@ RecordEventResult RecordEvent(const StaticMutexAutoLock& lock, return RecordEventResult::CannotRecord; } - // Count the number of times this event has been recorded. + // Count the number of times this event has been recorded, even if its + // category does not have recording enabled. TelemetryScalar::SummarizeEvent(UniqueEventName(category, method, object), processType, dynamicNonBuiltin); + // Check whether this event's category has recording enabled + if (!gEnabledCategories.Contains(GetCategory(lock, eventKey))) { + return RecordEventResult::Ok; + } + EventRecordArray* eventRecords = GetEventRecordsForProcess(lock, processType); eventRecords->AppendElement(EventRecord(timestamp, eventKey, value, extra)); @@ -560,6 +582,12 @@ void RegisterEvents(const StaticMutexAutoLock& lock, const nsACString& category, if (aBuiltin) { gCategoryNames.Insert(category); } + + if (!aBuiltin) { + // Now after successful registration enable recording for this category + // (if not a dynamic builtin). + gEnabledCategories.Insert(category); + } } } // anonymous namespace @@ -722,6 +750,9 @@ void TelemetryEvent::InitializeGlobalState(bool aCanRecordBase, gCategoryNames.Insert(info.common_info.category()); } + // A hack until bug 1691156 is fixed + gEnabledCategories.Insert("avif"_ns); + gInitDone = true; } @@ -734,6 +765,7 @@ void TelemetryEvent::DeInitializeGlobalState() { gEventNameIDMap.Clear(); gCategoryNames.Clear(); + gEnabledCategories.Clear(); gEventRecords.Clear(); gDynamicEventInfo = nullptr; @@ -1348,6 +1380,27 @@ void TelemetryEvent::ClearEvents() { gEventRecords.Clear(); } +void TelemetryEvent::SetEventRecordingEnabled(const nsACString& category, + bool enabled) { + StaticMutexAutoLock locker(gTelemetryEventsMutex); + + if (!gCategoryNames.Contains(category)) { + LogToBrowserConsole( + nsIScriptError::warningFlag, + NS_ConvertUTF8toUTF16( + nsLiteralCString( + "Unknown category for SetEventRecordingEnabled: ") + + category)); + return; + } + + if (enabled) { + gEnabledCategories.Insert(category); + } else { + gEnabledCategories.Remove(category); + } +} + size_t TelemetryEvent::SizeOfIncludingThis( mozilla::MallocSizeOf aMallocSizeOf) { StaticMutexAutoLock locker(gTelemetryEventsMutex); @@ -1374,6 +1427,7 @@ size_t TelemetryEvent::SizeOfIncludingThis( } n += gCategoryNames.ShallowSizeOfExcludingThis(aMallocSizeOf); + n += gEnabledCategories.ShallowSizeOfExcludingThis(aMallocSizeOf); if (gDynamicEventInfo) { n += gDynamicEventInfo->ShallowSizeOfIncludingThis(aMallocSizeOf); diff --git a/toolkit/components/telemetry/core/TelemetryEvent.h b/toolkit/components/telemetry/core/TelemetryEvent.h index b01e1a39ddd0..8734df1174f9 100644 --- a/toolkit/components/telemetry/core/TelemetryEvent.h +++ b/toolkit/components/telemetry/core/TelemetryEvent.h @@ -47,6 +47,7 @@ nsresult RecordEvent(const nsACString& aCategory, const nsACString& aMethod, JS::Handle aExtra, JSContext* aCx, uint8_t optional_argc); +void SetEventRecordingEnabled(const nsACString& aCategory, bool aEnabled); nsresult RegisterEvents(const nsACString& aCategory, JS::Handle aEventData, bool aBuiltin, JSContext* cx); diff --git a/toolkit/components/telemetry/core/nsITelemetry.idl b/toolkit/components/telemetry/core/nsITelemetry.idl index c126f961ea6e..ddad0ea7d451 100644 --- a/toolkit/components/telemetry/core/nsITelemetry.idl +++ b/toolkit/components/telemetry/core/nsITelemetry.idl @@ -529,6 +529,16 @@ interface nsITelemetry : nsISupports [implicit_jscontext, optional_argc] void recordEvent(in ACString aCategory, in ACString aMethod, in ACString aObject, [optional] in jsval aValue, [optional] in jsval extra); + /** + * Enable recording of events in a category. + * Events default to recording disabled. This allows to toggle recording for all events + * in the specified category. + * + * @param aCategory The category name. + * @param aEnabled Whether recording is enabled for events in that category. + */ + void setEventRecordingEnabled(in ACString aCategory, in boolean aEnabled); + /** * Serializes the recorded events to a JSON-appropriate array and optionally resets them. * The returned structure looks like this: diff --git a/toolkit/components/telemetry/docs/collection/events.rst b/toolkit/components/telemetry/docs/collection/events.rst index ef91e7858025..773a63462bca 100644 --- a/toolkit/components/telemetry/docs/collection/events.rst +++ b/toolkit/components/telemetry/docs/collection/events.rst @@ -157,10 +157,30 @@ Since Firefox 132 (see `bug 1863031 `. +``setEventRecordingEnabled()`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. code-block:: js + + Services.telemetry.setEventRecordingEnabled(category, enabled); + +Event recording is currently disabled by default for events registered in Events.yaml. +Dynamically-registered events (those registered using ``registerEvents()``) are enabled by default, and cannot be disabled. +Privileged add-ons and Firefox code can enable & disable recording events for specific categories using this function. + +Example: + +.. code-block:: js + + Services.telemetry.setEventRecordingEnabled("ui", true); + // ... now events in the "ui" category will be recorded. + Services.telemetry.setEventRecordingEnabled("ui", false); + // ... now "ui" events will not be recorded anymore. + .. note:: - Events can be expensive to store, submit, and query. - You are responsible for ensuring that you don't submit too many events. - When your new events land in Nightly, consult with the Data Org about whether they are too "chatty". + + Even if your event category isn't enabled, counts of events that attempted to be recorded will + be :ref:`summarized `. Internal API ------------ @@ -220,12 +240,14 @@ the dynamic-process scalar ``telemetry.dynamic_event_counts`` would have a key Testing ======= -Tests involving Event Telemetry often follow this three-step form: +Tests involving Event Telemetry often follow this four-step form: 1. ``Services.telemetry.clearEvents();`` To minimize the effects of prior code and tests. -2. ``runTheCode();`` This is part of the test where you call the code that's supposed to collect +2. ``Services.telemetry.setEventRecordingEnabled(myCategory, true);`` To enable the collection of + your events. (May or may not be relevant in your case) +3. ``runTheCode();`` This is part of the test where you call the code that's supposed to collect Event Telemetry. -3. ``TelemetryTestUtils.assertEvents(expected, filter, options);`` This will check the +4. ``TelemetryTestUtils.assertEvents(expected, filter, options);`` This will check the events recorded by Event Telemetry against your provided list of expected events. If you only need to check the number of events recorded, you can use ``TelemetryTestUtils.assertNumberOfEvents(expectedNum, filter, options);``. diff --git a/toolkit/components/telemetry/docs/collection/webextension-api.rst b/toolkit/components/telemetry/docs/collection/webextension-api.rst index a525658aa006..997f2363b3bb 100644 --- a/toolkit/components/telemetry/docs/collection/webextension-api.rst +++ b/toolkit/components/telemetry/docs/collection/webextension-api.rst @@ -135,6 +135,11 @@ Instead, use :doc:`Glean event definitions <../../glean/user/glean_for_legacy_ev ``setEventRecordingEnabled`` ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Deprecated since Firefox 133 by bug 1920562. +.. code-block:: js -Instead, use :doc:`Glean event definitions <../../glean/user/glean_for_legacy_events>` for your extension's events. + browser.telemetry.setEventRecordingEnabled(category, enabled); + +Enable recording of events in a category. Events default to recording disabled. This allows to toggle recording for all events in the specified category. + +* ``category`` - *(string)* The category name. +* ``enabled`` - *(boolean)* Whether recording is enabled for events in that category. diff --git a/toolkit/components/telemetry/tests/gtest/TestEvents.cpp b/toolkit/components/telemetry/tests/gtest/TestEvents.cpp index 898441b9179e..80ba982afc1a 100644 --- a/toolkit/components/telemetry/tests/gtest/TestEvents.cpp +++ b/toolkit/components/telemetry/tests/gtest/TestEvents.cpp @@ -40,7 +40,14 @@ TEST_F(TelemetryTestFixture, RecordEventNative) { "this extra value is much too long and must be truncated to fit in the " "limit which at time of writing was 80 bytes."); - // Try recording. + // Try recording before category's enabled. + TelemetryEvent::RecordEventNative( + Telemetry::EventID::TelemetryTest_Test1_Object1, Nothing(), Nothing()); + + // Ensure "telemetry.test" is enabled + Telemetry::SetEventRecordingEnabled(category, true); + + // Try recording after it's enabled. TelemetryEvent::RecordEventNative( Telemetry::EventID::TelemetryTest_Test2_Object1, Nothing(), Nothing()); @@ -126,6 +133,7 @@ TEST_F(TelemetryTestFixture, GIFFTValue) { const nsCString category("telemetry.test"); const nsCString method("mirror_with_extra"); const nsCString object("object1"); + Telemetry::SetEventRecordingEnabled(category, true); // Record in Glean. // We include an extra extra key (extra1, here) to ensure there's always six diff --git a/toolkit/components/telemetry/tests/integration/tests/conftest.py b/toolkit/components/telemetry/tests/integration/tests/conftest.py index 411a0fc60c43..57067bedb73f 100644 --- a/toolkit/components/telemetry/tests/integration/tests/conftest.py +++ b/toolkit/components/telemetry/tests/integration/tests/conftest.py @@ -105,6 +105,20 @@ class Browser(object): ) self.marionette.set_pref("datareporting.healthreport.uploadEnabled", False) + def enable_search_events(self): + """ + Event Telemetry categories are disabled by default. + Search events are in the "navigation" category and are not enabled by + default in builds of Firefox, so we enable them here. + """ + + script = """\ + Services.telemetry.setEventRecordingEnabled("navigation", true); + """ + + with self.marionette.using_context(self.marionette.CONTEXT_CHROME): + self.marionette.execute_script(textwrap.dedent(script)) + def enable_telemetry(self): self.marionette.instance.profile.set_persistent_preferences( {"datareporting.healthreport.uploadEnabled": True} diff --git a/toolkit/components/telemetry/tests/integration/tests/test_event_ping.py b/toolkit/components/telemetry/tests/integration/tests/test_event_ping.py index fa440518f9a5..9209c562ebe2 100644 --- a/toolkit/components/telemetry/tests/integration/tests/test_event_ping.py +++ b/toolkit/components/telemetry/tests/integration/tests/test_event_ping.py @@ -10,6 +10,7 @@ def test_event_ping(browser, helpers): Barebones test for "event" ping: Search, close Firefox, check "event" ping for search events. """ + browser.enable_search_events() browser.wait_for_search_service_init() browser.search("mozilla firefox") diff --git a/toolkit/components/telemetry/tests/unit/test_ChildEvents.js b/toolkit/components/telemetry/tests/unit/test_ChildEvents.js index dc9eef1955d1..392febd5dc6f 100644 --- a/toolkit/components/telemetry/tests/unit/test_ChildEvents.js +++ b/toolkit/components/telemetry/tests/unit/test_ChildEvents.js @@ -83,6 +83,8 @@ add_task(async function () { await TelemetryController.testSetup(); // Make sure we don't generate unexpected pings due to pref changes. await setEmptyPrefWatchlist(); + // Enable recording for the test event category. + Telemetry.setEventRecordingEnabled("telemetry.test", true); // Register dynamic test events. Telemetry.registerEvents("telemetry.test.dynamic", { diff --git a/toolkit/components/telemetry/tests/unit/test_EventPing.js b/toolkit/components/telemetry/tests/unit/test_EventPing.js index 6d5ea336a691..8ff05ee2e208 100644 --- a/toolkit/components/telemetry/tests/unit/test_EventPing.js +++ b/toolkit/components/telemetry/tests/unit/test_EventPing.js @@ -56,6 +56,7 @@ add_task(async function setup() { await TelemetryController.testSetup(); TelemetryEventPing.testReset(); + Telemetry.setEventRecordingEnabled("telemetry.test", true); }); // Tests often take the form of faking policy within faked policy. diff --git a/toolkit/components/telemetry/tests/unit/test_TelemetryChildEvents_buildFaster.js b/toolkit/components/telemetry/tests/unit/test_TelemetryChildEvents_buildFaster.js index 8d46daaf087b..00a45c8b12e5 100644 --- a/toolkit/components/telemetry/tests/unit/test_TelemetryChildEvents_buildFaster.js +++ b/toolkit/components/telemetry/tests/unit/test_TelemetryChildEvents_buildFaster.js @@ -61,6 +61,8 @@ add_task(async function test_setup() { expired: true, }, }); + Telemetry.setEventRecordingEnabled(TEST_STATIC_EVENT_NAME, true); + Telemetry.setEventRecordingEnabled(TEST_EVENT_NAME, true); Telemetry.recordEvent(TEST_EVENT_NAME, "dynamic", "builtin"); Telemetry.recordEvent(TEST_STATIC_EVENT_NAME, "main_and_content", "object1"); diff --git a/toolkit/components/telemetry/tests/unit/test_TelemetryEvents.js b/toolkit/components/telemetry/tests/unit/test_TelemetryEvents.js index 3b81cb1a67fb..3d5e8269141c 100644 --- a/toolkit/components/telemetry/tests/unit/test_TelemetryEvents.js +++ b/toolkit/components/telemetry/tests/unit/test_TelemetryEvents.js @@ -161,6 +161,58 @@ add_task(async function test_event_summary_limit() { ); }); +add_task(async function test_recording_state() { + Telemetry.clearEvents(); + Telemetry.clearScalars(); + + const events = [ + ["telemetry.test", "test1", "object1"], + ["telemetry.test.second", "test", "object1"], + ]; + + // Both test categories should be off by default. + events.forEach(e => Telemetry.recordEvent(...e)); + TelemetryTestUtils.assertEvents([]); + checkEventSummary( + events.map(e => ["parent", e, 1]), + true + ); + + // Enable one test category and see that we record correctly. + Telemetry.setEventRecordingEnabled("telemetry.test", true); + events.forEach(e => Telemetry.recordEvent(...e)); + TelemetryTestUtils.assertEvents([events[0]]); + checkEventSummary( + events.map(e => ["parent", e, 1]), + true + ); + + // Also enable the other test category and see that we record correctly. + Telemetry.setEventRecordingEnabled("telemetry.test.second", true); + events.forEach(e => Telemetry.recordEvent(...e)); + TelemetryTestUtils.assertEvents(events); + checkEventSummary( + events.map(e => ["parent", e, 1]), + true + ); + + // Now turn of one category again and check that this works as expected. + Telemetry.setEventRecordingEnabled("telemetry.test", false); + events.forEach(e => Telemetry.recordEvent(...e)); + TelemetryTestUtils.assertEvents([events[1]]); + checkEventSummary( + events.map(e => ["parent", e, 1]), + true + ); +}); + +add_task(async function recording_setup() { + // Make sure both test categories are enabled for the remaining tests. + // Otherwise their event recording won't work. + Telemetry.setEventRecordingEnabled("telemetry.test", true); + Telemetry.setEventRecordingEnabled("telemetry.test.second", true); +}); + add_task(async function test_recording() { Telemetry.clearScalars(); Telemetry.clearEvents(); diff --git a/toolkit/components/telemetry/tests/unit/test_TelemetryEvents_buildFaster.js b/toolkit/components/telemetry/tests/unit/test_TelemetryEvents_buildFaster.js index 355bba9c380a..c7e9e5aaba58 100644 --- a/toolkit/components/telemetry/tests/unit/test_TelemetryEvents_buildFaster.js +++ b/toolkit/components/telemetry/tests/unit/test_TelemetryEvents_buildFaster.js @@ -102,6 +102,9 @@ add_task( const TEST_EVENT_NAME = "telemetry.test.builtin"; const DYNAMIC_EVENT_CATEGORY = "telemetry.test.expired"; const STATIC_EVENT_CATEGORY = "telemetry.test"; + Telemetry.setEventRecordingEnabled(TEST_EVENT_NAME, true); + Telemetry.setEventRecordingEnabled(DYNAMIC_EVENT_CATEGORY, true); + Telemetry.setEventRecordingEnabled(STATIC_EVENT_CATEGORY, true); Telemetry.recordEvent(TEST_EVENT_NAME, "test1", "object1"); Telemetry.recordEvent(TEST_EVENT_NAME, "test2", "object1", null, { key1: "foo", @@ -177,6 +180,7 @@ add_task(async function test_dynamicBuiltinEvents() { }); // Record some events. + Telemetry.setEventRecordingEnabled(TEST_EVENT_NAME, true); Telemetry.recordEvent(TEST_EVENT_NAME, "test1", "object1"); Telemetry.recordEvent(TEST_EVENT_NAME, "test2", "object1", null, { key1: "foo", @@ -224,6 +228,61 @@ add_task(async function test_dynamicBuiltinEvents() { } }); +add_task(async function test_dynamicBuiltinEventsDisabledByDefault() { + Telemetry.clearEvents(); + Telemetry.canRecordExtended = true; + + const TEST_EVENT_NAME = "telemetry.test.offbydefault"; + + // Register some dynamic builtin test events. + Telemetry.registerBuiltinEvents(TEST_EVENT_NAME, { + // Event with only required fields. + test1: { + methods: ["test1"], + objects: ["object1"], + }, + }); + + // Record some events. + // Explicitely _don't_ enable the category + Telemetry.recordEvent(TEST_EVENT_NAME, "test1", "object1"); + + // Now check that the snapshot contains the expected data. + let snapshot = Telemetry.snapshotEvents( + Ci.nsITelemetry.DATASET_PRERELEASE_CHANNELS, + false + ); + Assert.ok( + !("parent" in snapshot), + "Should not have parent events in the snapshot." + ); + + // Now enable the category and record again + Telemetry.setEventRecordingEnabled(TEST_EVENT_NAME, true); + Telemetry.recordEvent(TEST_EVENT_NAME, "test1", "object1"); + + snapshot = Telemetry.snapshotEvents( + Ci.nsITelemetry.DATASET_PRERELEASE_CHANNELS, + false + ); + Assert.ok("parent" in snapshot, "Should have parent events in the snapshot."); + + let expected = [[TEST_EVENT_NAME, "test1", "object1"]]; + let events = snapshot.parent; + Assert.equal( + events.length, + expected.length, + "Should have recorded the right amount of events." + ); + for (let i = 0; i < expected.length; ++i) { + Assert.deepEqual( + events[i].slice(1), + expected[i], + "Should have recorded the expected event data." + ); + } +}); + add_task(async function test_dynamicBuiltinDontOverwriteStaticData() { Telemetry.clearEvents(); Telemetry.canRecordExtended = true; @@ -239,6 +298,10 @@ add_task(async function test_dynamicBuiltinDontOverwriteStaticData() { }, }); + // First enable the categories we're using + Telemetry.setEventRecordingEnabled(TEST_STATIC_EVENT_NAME, true); + Telemetry.setEventRecordingEnabled(TEST_EVENT_NAME, true); + // Now record some dynamic-builtin and static events Telemetry.recordEvent(TEST_EVENT_NAME, "dynamic", "builtin"); Telemetry.recordEvent(TEST_STATIC_EVENT_NAME, "test1", "object1"); @@ -293,6 +356,7 @@ add_task(async function test_dynamicBuiltinEventsOverridingStatic() { }); // Record some events that should be available in the static event already . + Telemetry.setEventRecordingEnabled(TEST_EVENT_NAME, true); Telemetry.recordEvent(TEST_EVENT_NAME, "test1", "object1"); Telemetry.recordEvent(TEST_EVENT_NAME, "test2", "object1", null, { key1: "foo", @@ -358,6 +422,7 @@ add_task(async function test_realDynamicDontOverwrite() { }); // Record some events that should be available in the static event already . + Telemetry.setEventRecordingEnabled(TEST_EVENT_NAME, true); Telemetry.recordEvent(TEST_EVENT_NAME, "test1", "object1"); Telemetry.recordEvent(TEST_EVENT_NAME, "test2", "object1", null, { key1: "foo", diff --git a/toolkit/modules/JSONFile.sys.mjs b/toolkit/modules/JSONFile.sys.mjs index 6e50384ae8ee..05f54324b037 100644 --- a/toolkit/modules/JSONFile.sys.mjs +++ b/toolkit/modules/JSONFile.sys.mjs @@ -122,6 +122,8 @@ export function JSONFile(config) { this._finalizeInternalBound, () => ({ sanitizedBasename: this.sanitizedBasename }) ); + + Services.telemetry.setEventRecordingEnabled("jsonfile", true); } JSONFile.prototype = { diff --git a/toolkit/modules/ServiceRequest.sys.mjs b/toolkit/modules/ServiceRequest.sys.mjs index bfdaefbda0ce..d90cae6399b7 100644 --- a/toolkit/modules/ServiceRequest.sys.mjs +++ b/toolkit/modules/ServiceRequest.sys.mjs @@ -48,6 +48,7 @@ const PROXY_CONFIG_TYPES = [ function recordEvent(service, source = {}) { try { + Services.telemetry.setEventRecordingEnabled("service_request", true); source.value = service; Glean.serviceRequest.bypassProxyInfo.record(source); } catch (err) { diff --git a/toolkit/mozapps/extensions/AddonManager.sys.mjs b/toolkit/mozapps/extensions/AddonManager.sys.mjs index d4f65a6a5389..66769105cbfd 100644 --- a/toolkit/mozapps/extensions/AddonManager.sys.mjs +++ b/toolkit/mozapps/extensions/AddonManager.sys.mjs @@ -595,6 +595,9 @@ var AddonManagerInternal = { this.recordTimestamp("AMI_startup_begin"); + // Enable the addonsManager telemetry event category. + AMTelemetry.init(); + // Enable the AMRemoteSettings client. AMRemoteSettings.init(); @@ -4676,6 +4679,13 @@ AMRemoteSettings = { AMTelemetry = { telemetrySetupDone: false, + init() { + // Enable the addonsManager telemetry event category before the AddonManager + // has completed its startup, otherwise telemetry events recorded during the + // AddonManager/XPIProvider startup will not be recorded. + Services.telemetry.setEventRecordingEnabled("addonsManager", true); + }, + // This method is called by the AddonManager, once it has been started, so that we can // init the telemetry event category and start listening for the events related to the // addons installation and management. diff --git a/tools/@types/lib.gecko.xpcom.d.ts b/tools/@types/lib.gecko.xpcom.d.ts index a695df6dcc34..9dbc60a1f855 100644 --- a/tools/@types/lib.gecko.xpcom.d.ts +++ b/tools/@types/lib.gecko.xpcom.d.ts @@ -10500,6 +10500,7 @@ interface nsITelemetry extends nsISupports { clearScalars(): void; flushBatchedChildTelemetry(): void; recordEvent(aCategory: string, aMethod: string, aObject: string, aValue?: any, extra?: any): void; + setEventRecordingEnabled(aCategory: string, aEnabled: boolean): void; snapshotEvents(aDataset: u32, aClear?: boolean, aEventLimit?: u32): any; registerEvents(aCategory: string, aEventData: any): void; registerBuiltinEvents(aCategory: string, aEventData: any): void; diff --git a/xpcom/base/AvailableMemoryWatcher.cpp b/xpcom/base/AvailableMemoryWatcher.cpp index 73ad7242bf3b..02bc1778cefd 100644 --- a/xpcom/base/AvailableMemoryWatcher.cpp +++ b/xpcom/base/AvailableMemoryWatcher.cpp @@ -12,6 +12,7 @@ #include "mozilla/RefPtr.h" #include "mozilla/Services.h" #include "mozilla/StaticPtr.h" +#include "mozilla/Telemetry.h" #include "mozilla/glean/GleanMetrics.h" #include "nsExceptionHandler.h" #include "nsMemoryPressure.h" @@ -162,6 +163,7 @@ void nsAvailableMemoryWatcherBase::UpdateLowMemoryTimeStamp() { void nsAvailableMemoryWatcherBase::RecordTelemetryEventOnHighMemory( const MutexAutoLock&) { + Telemetry::SetEventRecordingEnabled("memory_watcher"_ns, true); glean::memory_watcher::on_high_memory_stats.Record( Some(glean::memory_watcher::OnHighMemoryStatsExtra{ Some(nsPrintfCString(