Bug 1465707 - Add addon probes for Savant Shield study; r=rhelmer
When the study preference (shield.savant.enabled) is set to true, this will record:
* When an addon begins an install
* When an addon finishes an install
* When an addon is enabled
* When an addon is disabled
* When an addon begins an uninstall
* When an addon finishes an uninstall
MozReview-Commit-ID: J8LoBZVS5iL
--- a/browser/modules/SavantShieldStudy.jsm
+++ b/browser/modules/SavantShieldStudy.jsm
@@ -4,16 +4,20 @@
"use strict";
var EXPORTED_SYMBOLS = ["SavantShieldStudy"];
ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
ChromeUtils.import("resource://gre/modules/Services.jsm");
+XPCOMUtils.defineLazyModuleGetters(this, {
+ AddonManager: "resource://gre/modules/AddonManager.jsm"
+});
+
// See LOG_LEVELS in Console.jsm. Examples: "all", "info", "warn", & "error".
const PREF_LOG_LEVEL = "shield.savant.loglevel";
// Create a new instance of the ConsoleAPI so we can control the maxLogLevel with a pref.
XPCOMUtils.defineLazyGetter(this, "log", () => {
let ConsoleAPI = ChromeUtils.import("resource://gre/modules/Console.jsm", {}).ConsoleAPI;
let consoleOptions = {
maxLogLevelPref: PREF_LOG_LEVEL,
@@ -31,16 +35,17 @@ class SavantShieldStudyClass {
this.STUDY_EXPIRATION_DATE_PREF = "shield.savant.expiration_date";
// ms = 'x' weeks * 7 days/week * 24 hours/day * 60 minutes/hour
// * 60 seconds/minute * 1000 milliseconds/second
this.DEFAULT_STUDY_DURATION_MS = 4 * 7 * 24 * 60 * 60 * 1000;
}
init() {
this.TelemetryEvents = new TelemetryEvents(this.STUDY_TELEMETRY_CATEGORY);
+ this.AddonListener = new AddonListener(this.STUDY_TELEMETRY_CATEGORY);
// check the pref in case Normandy flipped it on before we could add the pref listener
this.shouldCollect = Services.prefs.getBoolPref(this.STUDY_PREF);
if (this.shouldCollect) {
this.startupStudy();
}
Services.prefs.addObserver(this.STUDY_PREF, this);
}
@@ -68,16 +73,18 @@ class SavantShieldStudyClass {
}
this.initStudyDuration();
if (this.isStudyExpired()) {
log.debug("Study expired in between this and the previous session.");
this.endStudy("expired");
}
+
+ this.AddonListener.init();
}
isEligible() {
const isAlwaysPrivateBrowsing = Services.prefs.getBoolPref(this.ALWAYS_PRIVATE_BROWSING_PREF);
if (isAlwaysPrivateBrowsing) {
return false;
}
@@ -144,16 +151,17 @@ class SavantShieldStudyClass {
// if just shutting down, check for expiration, so the endStudy event can
// be sent along with this session's main ping.
if (!isStudyEnding && this.isStudyExpired()) {
log.debug("Study expired during this session.");
this.endStudy("expired");
return;
}
+ this.AddonListener.uninit();
Services.prefs.removeObserver(this.ALWAYS_PRIVATE_BROWSING_PREF, this);
Services.prefs.removeObserver(this.STUDY_PREF, this);
Services.prefs.removeObserver(this.STUDY_DURATION_OVERRIDE_PREF, this);
Services.prefs.clearUserPref(PREF_LOG_LEVEL);
Services.prefs.clearUserPref(this.STUDY_DURATION_OVERRIDE_PREF);
}
}
@@ -171,9 +179,73 @@ class TelemetryEvents {
}
disableCollection() {
log.debug("Study has been disabled; turning OFF data collection.");
Services.telemetry.setEventRecordingEnabled(this.STUDY_TELEMETRY_CATEGORY, false);
}
}
+class AddonListener {
+ constructor(studyCategory) {
+ this.STUDY_TELEMETRY_CATEGORY = studyCategory;
+ this.METHOD = "addon";
+ this.EXTRA_SUBCATEGORY = "customize";
+ }
+
+ init() {
+ this.listener = {
+ onInstalling: (addon, needsRestart) => {
+ const addon_id = addon.id;
+ this.recordEvent("install_start", addon_id);
+ },
+
+ onInstalled: (addon) => {
+ const addon_id = addon.id;
+ this.recordEvent("install_finish", addon_id);
+ },
+
+ onEnabled: (addon) => {
+ const addon_id = addon.id;
+ this.recordEvent("enable", addon_id);
+ },
+
+ onDisabled: (addon) => {
+ const addon_id = addon.id;
+ this.recordEvent("disable", addon_id);
+ },
+
+ onUninstalling: (addon, needsRestart) => {
+ const addon_id = addon.id;
+ this.recordEvent("remove_start", addon_id);
+ },
+
+ onUninstalled: (addon) => {
+ const addon_id = addon.id;
+ this.recordEvent("remove_finish", addon_id);
+ }
+ };
+ this.addListeners();
+ }
+
+ addListeners() {
+ AddonManager.addAddonListener(this.listener);
+ }
+
+ recordEvent(event, addon_id) {
+ log.debug(`Addon ID: ${addon_id}; event: ${ event }`);
+ Services.telemetry.recordEvent(this.STUDY_TELEMETRY_CATEGORY,
+ this.METHOD,
+ event,
+ addon_id,
+ { subcategory: this.EXTRA_SUBCATEGORY });
+ }
+
+ removeListeners() {
+ AddonManager.removeAddonListener(this.listener);
+ }
+
+ uninit() {
+ this.removeListeners();
+ }
+}
+
const SavantShieldStudy = new SavantShieldStudyClass();
--- a/toolkit/components/telemetry/Events.yaml
+++ b/toolkit/components/telemetry/Events.yaml
@@ -128,16 +128,31 @@ savant:
This is recorded any time Reader Mode is turned on or off.
bug_numbers: [1457226, 1465698]
notification_emails:
- "bdanforth@mozilla.com"
- "shong@mozilla.com"
expiry_version: "65"
extra_keys:
subcategory: The broad event category for this probe. E.g. navigation
+ addon:
+ objects: ["install_start", "install_finish", "remove_start", "remove_finish",
+ "enable", "disable" ]
+ release_channel_collection: opt-out
+ record_in_processes: ["main"]
+ description: >
+ This is recorded any time an addon event as listed in the objects field fires.
+ The value field records the addon ID for the event.
+ bug_numbers: [1457226, 1465707]
+ notification_emails:
+ - "bdanforth@mozilla.com"
+ - "shong@mozilla.com"
+ expiry_version: "65"
+ extra_keys:
+ subcategory: The broad event category for this probe. E.g. navigation
# This category contains event entries used for Telemetry tests.
# They will not be sent out with any pings.
telemetry.test:
test:
methods: ["test1", "test2"]
objects: ["object1", "object2"]
bug_numbers: [1286606]