commit 29b42d85d9c9f5166d7f264ee05ffdd0f2dd5fd2
parent afd1f9234246a29f20413c1efc1ad176c9fd4604
Author: Chris H-C <chutten@mozilla.com>
Date: Tue, 2 Dec 2025 17:14:49 +0000
Bug 1999541 - Implement Nimbus-controlled shutoff switch for "main" ping scalars r=TravisLong
Even if scalars are completely disabled, we leave the two that fuel top-line
KPIs intact. This is out of an abundance of caution, should this feature be
accidentally enabled.
Differential Revision: https://phabricator.services.mozilla.com/D274465
Diffstat:
4 files changed, 117 insertions(+), 0 deletions(-)
diff --git a/toolkit/components/nimbus/FeatureManifest.yaml b/toolkit/components/nimbus/FeatureManifest.yaml
@@ -2754,6 +2754,15 @@ legacyTelemetry:
Code that collects to and submits the ping will still operate as normal.
Cannot be used to disable the "main", "first-shutdown", "new-profile",
or "deletion-request" pings.
+ disableMainPingScalars:
+ type: boolean
+ description: |
+ If true, scalars will not be included in "main" pings.
+ Exceptions are made for two important engagement measures:
+ `browser.engagement.total_uri_count_normal_and_private_mode` and
+ `browser.engagement.active_ticks`.
+ These scalars will continue to be reported as normal, even if all
+ others are disabled by this variable.
browserLowMemoryPrefs:
description: Prefs which control the browser's behaviour under low memory.
diff --git a/toolkit/components/telemetry/pings/TelemetrySession.sys.mjs b/toolkit/components/telemetry/pings/TelemetrySession.sys.mjs
@@ -11,6 +11,7 @@ const lazy = {};
ChromeUtils.defineESModuleGetters(lazy, {
AddonManagerPrivate: "resource://gre/modules/AddonManager.sys.mjs",
+ NimbusFeatures: "resource://nimbus/ExperimentAPI.sys.mjs",
TelemetryController: "resource://gre/modules/TelemetryController.sys.mjs",
TelemetryEnvironment: "resource://gre/modules/TelemetryEnvironment.sys.mjs",
TelemetryReportingPolicy:
@@ -507,6 +508,31 @@ var Impl = {
!this._testing
);
+ if (
+ lazy.NimbusFeatures.legacyTelemetry.getVariable("disableMainPingScalars")
+ ) {
+ this._log.trace("getScalars - Main ping scalars are disabled.");
+ if (keyed) {
+ // We don't need to preserve any keyed scalars.
+ scalarsSnapshot = {};
+ } else {
+ let filteredSnapshot = {};
+ const scalarsToKeep = [
+ "browser.engagement.total_uri_count_normal_and_private_mode",
+ "browser.engagement.active_ticks",
+ ];
+ for (let scalar of scalarsToKeep) {
+ if ("parent" in scalarsSnapshot && scalar in scalarsSnapshot.parent) {
+ if (!("parent" in filteredSnapshot)) {
+ filteredSnapshot.parent = {};
+ }
+ filteredSnapshot.parent[scalar] = scalarsSnapshot.parent[scalar];
+ }
+ }
+ scalarsSnapshot = filteredSnapshot;
+ }
+ }
+
return scalarsSnapshot;
},
diff --git a/toolkit/components/telemetry/tests/unit/test_MainPingDisablement.js b/toolkit/components/telemetry/tests/unit/test_MainPingDisablement.js
@@ -0,0 +1,77 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/
+*/
+/**
+ * Tests for disabling pieces of the "main" ping.
+ */
+
+const { NimbusFeatures } = ChromeUtils.importESModule(
+ "resource://nimbus/ExperimentAPI.sys.mjs"
+);
+const { NimbusTestUtils } = ChromeUtils.importESModule(
+ "resource://testing-common/NimbusTestUtils.sys.mjs"
+);
+const { TelemetrySession } = ChromeUtils.importESModule(
+ "resource://gre/modules/TelemetrySession.sys.mjs"
+);
+
+NimbusTestUtils.init(this);
+
+add_setup(async function () {
+ // FOG needs a profile directory
+ do_get_profile();
+ Services.fog.initializeFOG();
+
+ // Make sure we don't generate unexpected pings due to pref changes.
+ await setEmptyPrefWatchlist();
+
+ Services.prefs.setBoolPref(TelemetryUtils.Preferences.FhrUploadEnabled, true);
+
+ await TelemetryController.testSetup();
+});
+
+add_task(async function test_scalarDisablement() {
+ const URI_COUNT_SCALAR =
+ "browser.engagement.total_uri_count_normal_and_private_mode";
+ const ACTIVE_TICKS_SCALAR = "browser.engagement.active_ticks";
+ const LAST_SHUTDOWN_SCALAR = "browser.timings.last_shutdown";
+
+ // Ensure there's data to be snapshotted.
+ // Both some that shouldn't be filtered...
+ Glean.browserEngagement.uriCount.add(1);
+ Glean.browserEngagement.activeTicks.add(1);
+ // ...and some that should be.
+ Glean.browserTimings.lastShutdown.set(42);
+
+ info("1. Ensure things begin by storing and reporting as expected.");
+ let payload = TelemetrySession.getPayload(
+ "reason",
+ /*clearSubsession*/ false
+ );
+
+ Assert.greater(payload.processes.parent.scalars[URI_COUNT_SCALAR], 0);
+ Assert.greater(payload.processes.parent.scalars[ACTIVE_TICKS_SCALAR], 0);
+ Assert.greater(payload.processes.parent.scalars[LAST_SHUTDOWN_SCALAR], 0);
+
+ info("2. Ensure we can disable scalars, leaving important ones intact.");
+ const { cleanup } = await NimbusTestUtils.setupTest();
+ registerCleanupFunction(cleanup);
+
+ let nimbusCleanup = await NimbusTestUtils.enrollWithFeatureConfig({
+ featureId: NimbusFeatures.legacyTelemetry.featureId,
+ value: {
+ disableMainPingScalars: true,
+ },
+ });
+
+ let filtered = TelemetrySession.getPayload(
+ "reason",
+ /*clearSubsession*/ false
+ );
+
+ Assert.greater(filtered.processes.parent.scalars[URI_COUNT_SCALAR], 0);
+ Assert.greater(filtered.processes.parent.scalars[ACTIVE_TICKS_SCALAR], 0);
+ Assert.ok(!(LAST_SHUTDOWN_SCALAR in filtered.processes.parent.scalars));
+
+ await nimbusCleanup();
+});
diff --git a/toolkit/components/telemetry/tests/unit/xpcshell.toml b/toolkit/components/telemetry/tests/unit/xpcshell.toml
@@ -40,6 +40,11 @@ skip-if = [
]
tags = "addons"
+["test_MainPingDisablement.js"]
+run-if = [
+ "os != 'android'", # Legacy telemetry is always disabled on Android
+]
+
["test_MigratePendingPings.js"]
run-if = [
"os != 'android'", # Legacy telemetry is a lways disabled on Android