Bug 1465694 - Add tab event telemetry for Savant Shield study; r=dao, a=RyanVM
authorBianca Danforth <bdanforth@mozilla.com>
Wed, 06 Jun 2018 03:44:48 -0700
changeset 473715 13af68f9e6d0b394945dfe041b4ef5108abfddb9
parent 473714 63275d610ea3f9c82e2d88b923443beaa0fbc311
child 473716 44883c246d62061847e07dcba4fd88f55eb45362
push id1728
push userjlund@mozilla.com
push dateMon, 18 Jun 2018 21:12:27 +0000
treeherdermozilla-release@c296fde26f5f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersdao, RyanVM
bugs1465694
milestone61.0
Bug 1465694 - Add tab event telemetry for Savant Shield study; r=dao, a=RyanVM These probes will register and record (for the duration of the study only): * When a tab opens. * When a tab closes. * When a tab is selected. MozReview-Commit-ID: BvknEH0ofS0
browser/base/content/tabbrowser.js
browser/modules/SavantShieldStudy.jsm
toolkit/components/telemetry/Events.yaml
--- a/browser/base/content/tabbrowser.js
+++ b/browser/base/content/tabbrowser.js
@@ -1029,16 +1029,17 @@ window._gBrowser = {
       let event = new CustomEvent("TabSelect", {
         bubbles: true,
         cancelable: false,
         detail: {
           previousTab: oldTab
         }
       });
       newTab.dispatchEvent(event);
+      Services.telemetry.recordEvent("savant", "tab", "select", null, { subcategory: "frame" });
 
       this._tabAttrModified(oldTab, ["selected"]);
       this._tabAttrModified(newTab, ["selected"]);
 
       if (oldBrowser != newBrowser &&
           oldBrowser.getInPermitUnload) {
         oldBrowser.getInPermitUnload(inPermitUnload => {
           if (!inPermitUnload) {
@@ -2401,16 +2402,17 @@ window._gBrowser = {
     }
 
     // Dispatch a new tab notification.  We do this once we're
     // entirely done, so that things are in a consistent state
     // even if the event listener opens or closes tabs.
     var detail = aEventDetail || {};
     var evt = new CustomEvent("TabOpen", { bubbles: true, detail });
     t.dispatchEvent(evt);
+    Services.telemetry.recordEvent("savant", "tab", "open", null, { subcategory: "frame" });
 
     if (!usingPreloadedContent && aOriginPrincipal && aURI) {
       let { URI_INHERITS_SECURITY_CONTEXT } = Ci.nsIProtocolHandler;
       // Unless we know for sure we're not inheriting principals,
       // force the about:blank viewer to have the right principal:
       if (!aURIObject ||
         (doGetProtocolFlags(aURIObject) & URI_INHERITS_SECURITY_CONTEXT)) {
         b.createAboutBlankContentViewer(aOriginPrincipal);
@@ -2787,16 +2789,17 @@ window._gBrowser = {
       TabBarVisibility.update();
 
     // We're committed to closing the tab now.
     // Dispatch a notification.
     // We dispatch it before any teardown so that event listeners can
     // inspect the tab that's about to close.
     var evt = new CustomEvent("TabClose", { bubbles: true, detail: { adoptedBy: aAdoptedByTab } });
     aTab.dispatchEvent(evt);
+    Services.telemetry.recordEvent("savant", "tab", "close", null, { subcategory: "frame" });
 
     if (aTab.linkedPanel) {
       if (!aAdoptedByTab && !gMultiProcessBrowser) {
         // Prevent this tab from showing further dialogs, since we're closing it
         var windowUtils = browser.contentWindow.QueryInterface(Ci.nsIInterfaceRequestor)
                                                .getInterface(Ci.nsIDOMWindowUtils);
         windowUtils.disableDialogs();
       }
--- a/browser/modules/SavantShieldStudy.jsm
+++ b/browser/modules/SavantShieldStudy.jsm
@@ -34,16 +34,19 @@ class SavantShieldStudyClass {
     this.STUDY_PREF = "shield.savant.enabled";
     this.STUDY_TELEMETRY_CATEGORY = "savant";
     this.ALWAYS_PRIVATE_BROWSING_PREF = "browser.privatebrowsing.autostart";
     this.STUDY_DURATION_OVERRIDE_PREF = "shield.savant.duration_override";
     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;
+    // If on startupStudy(), user is ineligible or study has expired,
+    // no probe listeners from this module have been added yet
+    this.shouldRemoveListeners = true;
   }
 
   init() {
     this.telemetryEvents = new TelemetryEvents(this.STUDY_TELEMETRY_CATEGORY);
     this.addonListener = new AddonListener(this.STUDY_TELEMETRY_CATEGORY);
     this.bookmarkObserver = new BookmarkObserver(this.STUDY_TELEMETRY_CATEGORY);
     this.menuListener = new MenuListener(this.STUDY_TELEMETRY_CATEGORY);
 
@@ -68,24 +71,26 @@ class SavantShieldStudyClass {
     }
   }
 
   startupStudy() {
     // enable before any possible calls to endStudy, since it sends an 'end_study' event
     this.telemetryEvents.enableCollection();
 
     if (!this.isEligible()) {
+      this.shouldRemoveListeners = false;
       this.endStudy("ineligible");
       return;
     }
 
     this.initStudyDuration();
 
     if (this.isStudyExpired()) {
       log.debug("Study expired in between this and the previous session.");
+      this.shouldRemoveListeners = false;
       this.endStudy("expired");
     }
 
     this.addonListener.init();
     this.bookmarkObserver.init();
     this.menuListener.init();
   }
 
@@ -249,17 +254,19 @@ class AddonListener {
                                   { subcategory: this.EXTRA_SUBCATEGORY });
   }
 
   removeListeners() {
     AddonManager.removeAddonListener(this.listener);
   }
 
   uninit() {
-    this.removeListeners();
+    if (SavantShieldStudy.shouldRemoveListeners) {
+      this.removeListeners();
+    }
   }
 }
 
 class BookmarkObserver {
   constructor(studyCategory) {
     this.STUDY_TELEMETRY_CATEGORY = studyCategory;
     // there are two probes: bookmark and follow_bookmark
     this.METHOD_1 = "bookmark";
@@ -275,21 +282,21 @@ class BookmarkObserver {
     this.addObservers();
   }
 
   addObservers() {
     PlacesUtils.bookmarks.addObserver(this);
   }
 
   onItemAdded(itemID, parentID, index, itemType, uri, title, dateAdded, guid, parentGUID, source) {
-    this.handleBookmarkSaveRemove(itemType, uri, source, "save");
+    this.handleItemAddRemove(itemType, uri, source, "save");
   }
 
   onItemRemoved(itemID, parentID, index, itemType, uri, guid, parentGUID, source) {
-    this.handleBookmarkSaveRemove(itemType, uri, source, "remove");
+    this.handleItemAddRemove(itemType, uri, source, "remove");
   }
 
   handleItemAddRemove(itemType, uri, source, event) {
     /*
     * "place:query" uris are used to create containers like Most Visited or
     * Recently Bookmarked. These are added as default bookmarks.
     */
     if (itemType === this.TYPE_BOOKMARK && !uri.schemeIs("place")
@@ -314,17 +321,19 @@ class BookmarkObserver {
                                   });
   }
 
   removeObservers() {
     PlacesUtils.bookmarks.removeObserver(this);
   }
 
   uninit() {
-    this.removeObservers();
+    if (SavantShieldStudy.shouldRemoveListeners) {
+      this.removeObservers();
+    }
   }
 }
 
 class MenuListener {
   constructor(studyCategory) {
     this.STUDY_TELEMETRY_CATEGORY = studyCategory;
     this.NAVIGATOR_TOOLBOX_ID = "navigator-toolbox";
     this.OVERFLOW_PANEL_ID = "widget-overflow";
@@ -413,17 +422,19 @@ class MenuListener {
       hamburgerPanel.removeEventListener("popupshown", this);
       dotdotdotPanel.removeEventListener("popupshown", this);
     } catch (err) {
       // Firefox is shutting down; elements have already been removed.
     }
   }
 
   uninit() {
-    this.windowWatcher.uninit();
+    if (SavantShieldStudy.shouldRemoveListeners) {
+      this.windowWatcher.uninit();
+    }
   }
 }
 
 /*
 * The WindowWatcher is used to add/remove listeners from MenuListener
 * to/from all windows.
 */
 class WindowWatcher {
--- a/toolkit/components/telemetry/Events.yaml
+++ b/toolkit/components/telemetry/Events.yaml
@@ -266,16 +266,29 @@ savant:
     notification_emails:
       - "bdanforth@mozilla.com"
       - "shong@mozilla.com"
     expiry_version: "65"
     extra_keys:
       subcategory: The broad event category for this probe. E.g. navigation
       flow_id: A tab identifier to associate events occuring in the same tab
       canRecordSubmit: True if a login form loads in a non-private window with Password Manager enabled.
+  tab:
+    objects: ["open", "close", "select"]
+    release_channel_collection: opt-out
+    record_in_processes: ["main"]
+    description: >
+      This is recorded any time a tab is opened, closed or selected.
+    bug_numbers: [1457226, 1465694]
+    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]