Bug 1465694 - Add tab event telemetry for Savant Shield study; r=dao
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
--- a/browser/base/content/tabbrowser.js
+++ b/browser/base/content/tabbrowser.js
@@ -1035,16 +1035,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) {
@@ -2455,16 +2456,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);
@@ -2842,16 +2844,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]