Bug 1465707 - Add addon probes for Savant Shield study; r=rhelmer draft
authorBianca Danforth <bdanforth@mozilla.com>
Wed, 06 Jun 2018 03:34:13 -0700
changeset 805552 da9715876a9f19c8655a74bd0558cb074788ada5
parent 805551 ea21bf3e665d10066b6dce39873de9b353a12e57
push id112687
push userbdanforth@mozilla.com
push dateThu, 07 Jun 2018 22:45:04 +0000
reviewersrhelmer
bugs1465707
milestone62.0a1
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
browser/modules/SavantShieldStudy.jsm
toolkit/components/telemetry/Events.yaml
--- 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]