Bug 1522919 - Add histograms to count fingerprinting and cryptomining blocking states per page load. r=johannh
☠☠ backed out by 783538d74b6a ☠ ☠
authorErica Wright <ewright@mozilla.com>
Wed, 06 Mar 2019 16:23:07 +0000
changeset 520512 39c2628de53e5a87b23737ae0364705197cef9b1
parent 520511 7f9508dc59e1de519714e91cbc105be5eae4f402
child 520513 980042eb94d3a705b7d62eff885805125bcd5303
push id10862
push userffxbld-merge
push dateMon, 11 Mar 2019 13:01:11 +0000
treeherdermozilla-beta@a2e7f5c935da [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjohannh
bugs1522919
milestone67.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1522919 - Add histograms to count fingerprinting and cryptomining blocking states per page load. r=johannh Add histograms to count fingerprinting and cryptomining blocking states per page load. Differential Revision: https://phabricator.services.mozilla.com/D20389
browser/base/content/browser-contentblocking.js
browser/base/content/browser.js
browser/base/content/test/trackingUI/browser_trackingUI_cryptominers.js
browser/base/content/test/trackingUI/browser_trackingUI_fingerprinters.js
toolkit/components/telemetry/Histograms.json
--- a/browser/base/content/browser-contentblocking.js
+++ b/browser/base/content/browser-contentblocking.js
@@ -1039,26 +1039,47 @@ var ContentBlocking = {
 
   shieldHistogramAdd(value) {
     if (PrivateBrowsingUtils.isWindowPrivate(window)) {
       return;
     }
     Services.telemetry.getHistogramById("TRACKING_PROTECTION_SHIELD").add(value);
   },
 
-  onContentBlockingEvent(event, webProgress, isSimulated) {
+  cryptominersHistogramAdd(value) {
+    Services.telemetry.getHistogramById("CRYPTOMINERS_BLOCKED_COUNT").add(value);
+  },
+
+  fingerprintersHistogramAdd(value) {
+    Services.telemetry.getHistogramById("FINGERPRINTERS_BLOCKED_COUNT").add(value);
+  },
+
+  onLocationChange() {
     let baseURI = this._baseURIForChannelClassifier;
 
     // Don't deal with about:, file: etc.
     if (!baseURI) {
       this.iconBox.removeAttribute("animate");
       this.iconBox.removeAttribute("active");
       this.iconBox.removeAttribute("hasException");
       return;
     }
+    // Add to telemetry per page load as a baseline measurement.
+    this.fingerprintersHistogramAdd("pageLoad");
+    this.cryptominersHistogramAdd("pageLoad");
+  },
+
+  onContentBlockingEvent(event, webProgress, isSimulated) {
+    let previousState = gBrowser.securityUI.contentBlockingEvent;
+    let baseURI = this._baseURIForChannelClassifier;
+
+    // Don't deal with about:, file: etc.
+    if (!baseURI) {
+      return;
+    }
 
     let anyDetected = false;
     let anyBlocking = false;
 
     for (let blocker of this.blockers) {
       // Store data on whether the blocker is activated in the current document for
       // reporting it using the "report breakage" dialog. Under normal circumstances this
       // dialog should only be able to open in the currently selected tab and onSecurityChange
@@ -1125,16 +1146,35 @@ var ContentBlocking = {
       this.shieldHistogramAdd(1);
     } else if (anyBlocking) {
       this.iconBox.setAttribute("tooltiptext", this.strings.activeTooltipText);
       this.shieldHistogramAdd(2);
     } else {
       this.iconBox.removeAttribute("tooltiptext");
       this.shieldHistogramAdd(0);
     }
+
+    // We report up to one instance of fingerprinting and cryptomining
+    // blocking and/or allowing per page load.
+    let fingerprintingBlocking = Fingerprinting.isBlocking(event) && !Fingerprinting.isBlocking(previousState);
+    let fingerprintingAllowing = Fingerprinting.isAllowing(event) && !Fingerprinting.isAllowing(previousState);
+    let cryptominingBlocking = Cryptomining.isBlocking(event) && !Cryptomining.isBlocking(previousState);
+    let cryptominingAllowing = Cryptomining.isAllowing(event) && !Cryptomining.isAllowing(previousState);
+
+    if (fingerprintingBlocking) {
+      this.fingerprintersHistogramAdd("blocked");
+    } else if (fingerprintingAllowing) {
+      this.fingerprintersHistogramAdd("allowed");
+    }
+
+    if (cryptominingBlocking) {
+      this.cryptominersHistogramAdd("blocked");
+    } else if (cryptominingAllowing) {
+      this.cryptominersHistogramAdd("allowed");
+    }
   },
 
   disableForCurrentPage() {
     let baseURI = this._baseURIForChannelClassifier;
 
     // Add the current host in the 'trackingprotection' consumer of
     // the permission manager using a normalized URI. This effectively
     // places this host on the tracking protection allowlist.
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -5442,16 +5442,18 @@ var TabsProgressListener = {
     if (tab && tab._sharingState) {
       gBrowser.setBrowserSharing(aBrowser, {});
     }
     webrtcUI.forgetStreamsFromBrowser(aBrowser);
 
     gBrowser.getNotificationBox(aBrowser).removeTransientNotifications();
 
     FullZoom.onLocationChange(aLocationURI, false, aBrowser);
+
+    ContentBlocking.onLocationChange();
   },
 
   onLinkIconAvailable(browser, dataURI, iconURI) {
     if (!iconURI) {
       return;
     }
     if (browser == gBrowser.selectedBrowser) {
       // If the "Add Search Engine" page action is in the urlbar, its image
--- a/browser/base/content/test/trackingUI/browser_trackingUI_cryptominers.js
+++ b/browser/base/content/test/trackingUI/browser_trackingUI_cryptominers.js
@@ -1,28 +1,34 @@
 /* eslint-disable mozilla/no-arbitrary-setTimeout */
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/ */
 
 "use strict";
 
 const TRACKING_PAGE = "http://example.org/browser/browser/base/content/test/trackingUI/trackingPage.html";
 const CM_PREF = "privacy.trackingprotection.cryptomining.enabled";
+let cmHistogram;
 
 add_task(async function setup() {
   await SpecialPowers.pushPrefEnv({set: [
     [ ContentBlocking.prefIntroCount, ContentBlocking.MAX_INTROS ],
     [ "urlclassifier.features.cryptomining.blacklistHosts", "cryptomining.example.com" ],
     [ "privacy.trackingprotection.enabled", false ],
     [ "privacy.trackingprotection.annotate_channels", false ],
     [ "privacy.trackingprotection.fingerprinting.enabled", false ],
   ]});
+  cmHistogram = Services.telemetry.getHistogramById("CRYPTOMINERS_BLOCKED_COUNT");
+  registerCleanupFunction(() => {
+    cmHistogram.clear();
+  });
 });
 
 async function testIdentityState(hasException) {
+  cmHistogram.clear();
   let promise = BrowserTestUtils.openNewForegroundTab({url: TRACKING_PAGE, gBrowser});
   let [tab] = await Promise.all([promise, waitForContentBlockingEvent()]);
 
   if (hasException) {
     let loaded = BrowserTestUtils.browserLoaded(tab.linkedBrowser, false, TRACKING_PAGE);
     ContentBlocking.disableForCurrentPage();
     await loaded;
   }
@@ -44,20 +50,23 @@ async function testIdentityState(hasExce
     "Shows an exception when appropriate");
 
   if (hasException) {
     let loaded = BrowserTestUtils.browserLoaded(tab.linkedBrowser, false, TRACKING_PAGE);
     ContentBlocking.enableForCurrentPage();
     await loaded;
   }
 
+  testTelemetry(1, 1, hasException);
+
   BrowserTestUtils.removeTab(tab);
 }
 
 async function testSubview(hasException) {
+  cmHistogram.clear();
   let promise = BrowserTestUtils.openNewForegroundTab({url: TRACKING_PAGE, gBrowser});
   let [tab] = await Promise.all([promise, waitForContentBlockingEvent()]);
 
   if (hasException) {
     let loaded = BrowserTestUtils.browserLoaded(tab.linkedBrowser, false, TRACKING_PAGE);
     ContentBlocking.disableForCurrentPage();
     await loaded;
   }
@@ -95,19 +104,28 @@ async function testSubview(hasException)
   ok(true, "Main view was shown");
 
   if (hasException) {
     let loaded = BrowserTestUtils.browserLoaded(tab.linkedBrowser, false, TRACKING_PAGE);
     ContentBlocking.enableForCurrentPage();
     await loaded;
   }
 
+  testTelemetry(1, 1, hasException);
+
   BrowserTestUtils.removeTab(tab);
 }
 
+function testTelemetry(pagesVisited, pagesWithBlockableContent, hasException) {
+  let results = cmHistogram.snapshot();
+  Assert.equal(results.values[0], pagesVisited, "The correct number of page loads have been recorded");
+  let expectedValue = hasException ? 2 : 1;
+  Assert.equal(results.values[expectedValue], pagesWithBlockableContent, "The correct number of cryptominers have been recorded as blocked or allowed.");
+}
+
 add_task(async function test() {
   Services.prefs.setBoolPref(CM_PREF, true);
 
   await testIdentityState(false);
   await testIdentityState(true);
 
   await testSubview(false);
   await testSubview(true);
--- a/browser/base/content/test/trackingUI/browser_trackingUI_fingerprinters.js
+++ b/browser/base/content/test/trackingUI/browser_trackingUI_fingerprinters.js
@@ -1,28 +1,34 @@
 /* eslint-disable mozilla/no-arbitrary-setTimeout */
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/ */
 
 "use strict";
 
 const TRACKING_PAGE = "http://example.org/browser/browser/base/content/test/trackingUI/trackingPage.html";
 const FP_PREF = "privacy.trackingprotection.fingerprinting.enabled";
+let fpHistogram;
 
 add_task(async function setup() {
   await SpecialPowers.pushPrefEnv({set: [
     [ ContentBlocking.prefIntroCount, ContentBlocking.MAX_INTROS ],
     [ "urlclassifier.features.fingerprinting.blacklistHosts", "fingerprinting.example.com" ],
     [ "privacy.trackingprotection.enabled", false ],
     [ "privacy.trackingprotection.annotate_channels", false ],
     [ "privacy.trackingprotection.cryptomining.enabled", false ],
   ]});
+  fpHistogram = Services.telemetry.getHistogramById("FINGERPRINTERS_BLOCKED_COUNT");
+  registerCleanupFunction(() => {
+    fpHistogram.clear();
+  });
 });
 
 async function testIdentityState(hasException) {
+  fpHistogram.clear();
   let promise = BrowserTestUtils.openNewForegroundTab({url: TRACKING_PAGE, gBrowser});
   let [tab] = await Promise.all([promise, waitForContentBlockingEvent()]);
 
   if (hasException) {
     let loaded = BrowserTestUtils.browserLoaded(tab.linkedBrowser, false, TRACKING_PAGE);
     ContentBlocking.disableForCurrentPage();
     await loaded;
   }
@@ -44,20 +50,23 @@ async function testIdentityState(hasExce
     "Shows an exception when appropriate");
 
   if (hasException) {
     let loaded = BrowserTestUtils.browserLoaded(tab.linkedBrowser, false, TRACKING_PAGE);
     ContentBlocking.enableForCurrentPage();
     await loaded;
   }
 
+  testTelemetry(1, 1, hasException);
+
   BrowserTestUtils.removeTab(tab);
 }
 
 async function testSubview(hasException) {
+  fpHistogram.clear();
   let promise = BrowserTestUtils.openNewForegroundTab({url: TRACKING_PAGE, gBrowser});
   let [tab] = await Promise.all([promise, waitForContentBlockingEvent()]);
 
   if (hasException) {
     let loaded = BrowserTestUtils.browserLoaded(tab.linkedBrowser, false, TRACKING_PAGE);
     ContentBlocking.disableForCurrentPage();
     await loaded;
   }
@@ -95,19 +104,28 @@ async function testSubview(hasException)
   ok(true, "Main view was shown");
 
   if (hasException) {
     let loaded = BrowserTestUtils.browserLoaded(tab.linkedBrowser, false, TRACKING_PAGE);
     ContentBlocking.enableForCurrentPage();
     await loaded;
   }
 
+  testTelemetry(1, 1, hasException);
+
   BrowserTestUtils.removeTab(tab);
 }
 
+function testTelemetry(pagesVisited, pagesWithBlockableContent, hasException) {
+  let results = fpHistogram.snapshot();
+  Assert.equal(results.values[0], pagesVisited, "The correct number of page loads have been recorded");
+  let expectedValue = hasException ? 2 : 1;
+  Assert.equal(results.values[expectedValue], pagesWithBlockableContent, "The correct number of fingerprinters have been recorded as blocked or allowed.");
+}
+
 add_task(async function test() {
   Services.prefs.setBoolPref(FP_PREF, true);
 
   await testIdentityState(false);
   await testIdentityState(true);
 
   await testSubview(false);
   await testSubview(true);
--- a/toolkit/components/telemetry/Histograms.json
+++ b/toolkit/components/telemetry/Histograms.json
@@ -11455,16 +11455,44 @@
     "record_in_processes": ["main"],
     "expires_in_version": "never",
     "releaseChannelCollection": "opt-out",
     "kind": "boolean",
     "description": "True if tracking protection in Private Browsing mode is disabled at startup.",
     "alert_emails": ["pdol@mozilla.com", "safebrowsing-telemetry@mozilla.org"],
     "bug_numbers": [1200944]
   },
+  "FINGERPRINTERS_BLOCKED_COUNT": {
+    "record_in_processes": ["main"],
+    "expires_in_version": "never",
+    "releaseChannelCollection": "opt-out",
+    "kind": "categorical",
+    "labels": [
+      "pageLoad",
+      "blocked",
+      "allowed"
+    ],
+    "description": "A count of the status of fingerprinter blocking per top level page load. ('pageLoad' = There was a page load, 'blocked' = at least one fingerprinter was blocked, 'allowed' = at least one fingerprinter was detected and allowed.) Note, pageLoad is used as a baseline measurement.",
+    "alert_emails": ["aedelstein@mozilla.com", "seceng-telemetry@mozilla.com"],
+    "bug_numbers": [1522919]
+  },
+  "CRYPTOMINERS_BLOCKED_COUNT": {
+    "record_in_processes": ["main"],
+    "expires_in_version": "never",
+    "releaseChannelCollection": "opt-out",
+    "kind": "categorical",
+    "labels": [
+      "pageLoad",
+      "blocked",
+      "allowed"
+    ],
+    "description": "A count of the status of cryptominer blocking per top level page load. ('pageLoad' = There was a page load, 'blocked' = at least one cryptominer was blocked, 'allowed' = at least one cryptominer was detected and allowed.) Note, pageLoad is used as a baseline measurement.",
+    "alert_emails": ["aedelstein@mozilla.com", "seceng-telemetry@mozilla.com"],
+    "bug_numbers": [1522919]
+  },
   "FENNEC_TRACKING_PROTECTION_STATE": {
     "record_in_processes": ["main", "content"],
     "expires_in_version": "never",
     "releaseChannelCollection": "opt-out",
     "kind": "enumerated",
     "n_values": 5,
     "description": "The state of the user-visible tracking protection setting (0 = Disabled, 1 = Enabled in PB, 2 = Enabled)",
     "alert_emails": ["pdol@mozilla.com", "safebrowsing-telemetry@mozilla.org"],