Bug 1509047 - Part 2: Add an API for measuring the number of unique origins visited in the past 24 hours; r=johannh
authorEhsan Akhgari <ehsan@mozilla.com>
Sat, 24 Nov 2018 17:21:34 -0500
changeset 507890 33e74171331abbd3feb26d26d27bbd9f762215ab
parent 507889 1a669c064a396860699bf8a194b70198a095858f
child 507891 913a77710ba88e0a7e946dbf740fbd225b5c0c52
push id1905
push userffxbld-merge
push dateMon, 21 Jan 2019 12:33:13 +0000
treeherdermozilla-release@c2fca1944d8c [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjohannh
bugs1509047
milestone65.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 1509047 - Part 2: Add an API for measuring the number of unique origins visited in the past 24 hours; r=johannh Differential Revision: https://phabricator.services.mozilla.com/D12863
browser/app/profile/firefox.js
browser/modules/BrowserUsageTelemetry.jsm
browser/modules/test/browser/browser.ini
browser/modules/test/browser/browser_UsageTelemetry_uniqueOriginsVisitedInPast24Hours.js
--- a/browser/app/profile/firefox.js
+++ b/browser/app/profile/firefox.js
@@ -1791,8 +1791,10 @@ pref("toolkit.coverage.endpoint.base", "
 #if defined(NIGHTLY_BUILD) && defined(MOZ_LIBPRIO)
 pref("prio.enabled", true);
 #endif
 
 // Discovery prefs
 pref("browser.discovery.enabled", false);
 pref("browser.discovery.containers.enabled", true);
 pref("browser.discovery.sites", "addons.mozilla.org");
+
+pref("browser.engagement.recent_visited_origins.expiry", 86400); // 24 * 60 * 60 (24 hours in seconds)
--- a/browser/modules/BrowserUsageTelemetry.jsm
+++ b/browser/modules/BrowserUsageTelemetry.jsm
@@ -2,29 +2,36 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
 var EXPORTED_SYMBOLS = [
   "BrowserUsageTelemetry",
+  "URICountListener",
   "URLBAR_SELECTED_RESULT_TYPES",
   "URLBAR_SELECTED_RESULT_METHODS",
   "MINIMUM_TAB_COUNT_INTERVAL_MS",
  ];
 
 const {XPCOMUtils} = ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm", null);
 
 XPCOMUtils.defineLazyModuleGetters(this, {
   PrivateBrowsingUtils: "resource://gre/modules/PrivateBrowsingUtils.jsm",
   SearchTelemetry: "resource:///modules/SearchTelemetry.jsm",
   Services: "resource://gre/modules/Services.jsm",
+  setTimeout: "resource://gre/modules/Timer.jsm",
 });
 
+// This pref is in seconds!
+XPCOMUtils.defineLazyPreferenceGetter(this,
+  "gRecentVisitedOriginsExpiry",
+  "browser.engagement.recent_visited_origins.expiry");
+
 // The upper bound for the count of the visited unique domain names.
 const MAX_UNIQUE_VISITED_DOMAINS = 100;
 
 // Observed topic names.
 const TAB_RESTORING_TOPIC = "SSTabRestoring";
 const TELEMETRY_SUBSESSIONSPLIT_TOPIC = "internal-telemetry-after-subsession-split";
 const DOMWINDOW_OPENED_TOPIC = "domwindowopened";
 const AUTOCOMPLETE_ENTER_TEXT_TOPIC = "autocomplete-did-enter-text";
@@ -123,16 +130,18 @@ function getSearchEngineId(engine) {
 function shouldRecordSearchCount(tabbrowser) {
   return !PrivateBrowsingUtils.isWindowPrivate(tabbrowser.ownerGlobal) ||
          !Services.prefs.getBoolPref("browser.engagement.search_counts.pbm", false);
 }
 
 let URICountListener = {
   // A set containing the visited domains, see bug 1271310.
   _domainSet: new Set(),
+  // A set containing the visited origins during the last 24 hours (similar to domains, but not quite the same)
+  _origin24hrSet: new Set(),
   // A map to keep track of the URIs loaded from the restored tabs.
   _restoredURIsMap: new WeakMap(),
 
   isHttpURI(uri) {
     // Only consider http(s) schemas.
     return uri.schemeIs("http") || uri.schemeIs("https");
   },
 
@@ -225,35 +234,63 @@ let URICountListener = {
 
     // We only want to count the unique domains up to MAX_UNIQUE_VISITED_DOMAINS.
     if (this._domainSet.size == MAX_UNIQUE_VISITED_DOMAINS) {
       return;
     }
 
     // Unique domains should be aggregated by (eTLD + 1): x.test.com and y.test.com
     // are counted once as test.com.
+    let baseDomain;
     try {
       // Even if only considering http(s) URIs, |getBaseDomain| could still throw
       // due to the URI containing invalid characters or the domain actually being
       // an ipv4 or ipv6 address.
-      this._domainSet.add(Services.eTLD.getBaseDomain(uri));
+      baseDomain = Services.eTLD.getBaseDomain(uri);
+      this._domainSet.add(baseDomain);
     } catch (e) {
-      return;
+      baseDomain = uri.host;
+    }
+
+    // Record the origin, but with the base domain (eTLD + 1).
+    let baseDomainURI = uri.mutate()
+                           .setHost(baseDomain)
+                           .finalize();
+    this._origin24hrSet.add(baseDomainURI.prePath);
+    if (gRecentVisitedOriginsExpiry) {
+      setTimeout(() => {
+        this._origin24hrSet.delete(baseDomainURI.prePath);
+      }, gRecentVisitedOriginsExpiry * 1000);
     }
 
     Services.telemetry.scalarSet(UNIQUE_DOMAINS_COUNT_SCALAR_NAME, this._domainSet.size);
   },
 
   /**
    * Reset the counts. This should be called when breaking a session in Telemetry.
    */
   reset() {
     this._domainSet.clear();
   },
 
+  /**
+   * Returns the number of unique origins visited in this session during the
+   * last 24 hours.
+   */
+  get uniqueOriginsVisitedInPast24Hours() {
+    return this._origin24hrSet.size;
+  },
+
+  /**
+   * Resets the number of unique origins visited in this session.
+   */
+  resetUniqueOriginsVisitedInPast24Hours() {
+    this._origin24hrSet.clear();
+  },
+
   QueryInterface: ChromeUtils.generateQI([Ci.nsIWebProgressListener,
                                           Ci.nsISupportsWeakReference]),
 };
 
 let urlbarListener = {
 
   // This is needed for recordUrlbarSelectedResultMethod().
   selectedIndex: -1,
--- a/browser/modules/test/browser/browser.ini
+++ b/browser/modules/test/browser/browser.ini
@@ -34,16 +34,17 @@ skip-if = !e10s
 skip-if = os != win || (os == win && bits == 64) # bug 1456807
 [browser_UnsubmittedCrashHandler.js]
 run-if = crashreporter
 [browser_urlBar_zoom.js]
 [browser_UsageTelemetry.js]
 [browser_UsageTelemetry_domains.js]
 [browser_UsageTelemetry_private_and_restore.js]
 skip-if = verify && debug
+[browser_UsageTelemetry_uniqueOriginsVisitedInPast24Hours.js]
 [browser_UsageTelemetry_urlbar.js]
 support-files =
   usageTelemetrySearchSuggestions.sjs
   usageTelemetrySearchSuggestions.xml
 [browser_UsageTelemetry_searchbar.js]
 support-files =
   usageTelemetrySearchSuggestions.sjs
   usageTelemetrySearchSuggestions.xml
new file mode 100644
--- /dev/null
+++ b/browser/modules/test/browser/browser_UsageTelemetry_uniqueOriginsVisitedInPast24Hours.js
@@ -0,0 +1,56 @@
+/* eslint-disable mozilla/no-arbitrary-setTimeout */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+"use strict";
+
+ChromeUtils.defineModuleGetter(this, "URICountListener",
+                               "resource:///modules/BrowserUsageTelemetry.jsm");
+
+add_task(async function test_uniqueOriginsVisitedInPast24Hours() {
+  registerCleanupFunction(async () => {
+    info("Cleaning up");
+    URICountListener.resetUniqueOriginsVisitedInPast24Hours();
+  });
+
+  URICountListener.resetUniqueOriginsVisitedInPast24Hours();
+  let startingCount = URICountListener.uniqueOriginsVisitedInPast24Hours;
+  is(startingCount, 0, "We should have no origins recorded in the history right after resetting");
+
+  // Add a new window and then some tabs in it.
+  let win = await BrowserTestUtils.openNewBrowserWindow();
+  await BrowserTestUtils.openNewForegroundTab(win.gBrowser, "http://example.com");
+
+  await BrowserTestUtils.openNewForegroundTab(win.gBrowser, "http://test1.example.com");
+  is(URICountListener.uniqueOriginsVisitedInPast24Hours, startingCount + 1,
+     "test1.example.com should only count as a unique visit if example.com wasn't visited before");
+
+  // http://www.exämple.test
+  await BrowserTestUtils.openNewForegroundTab(win.gBrowser, "http://xn--exmple-cua.test");
+  is(URICountListener.uniqueOriginsVisitedInPast24Hours, startingCount + 2,
+     "www.exämple.test should count as a unique visit");
+
+  // Set the expiry time to 1 second
+  await SpecialPowers.pushPrefEnv({set: [["browser.engagement.recent_visited_origins.expiry", 1]]});
+
+  await BrowserTestUtils.openNewForegroundTab(win.gBrowser, "http://127.0.0.1");
+  is(URICountListener.uniqueOriginsVisitedInPast24Hours, startingCount + 3,
+     "127.0.0.1 should count as a unique visit");
+
+  let countBefore = URICountListener.uniqueOriginsVisitedInPast24Hours;
+
+  await new Promise(resolve => {
+    setTimeout(_ => {
+      let countAfter = URICountListener.uniqueOriginsVisitedInPast24Hours;
+      is(countAfter, countBefore - 1,
+         "The expiry should work correctly");
+      resolve();
+    }, 1100);
+  });
+
+  BrowserTestUtils.removeTab(win.gBrowser.selectedTab);
+  BrowserTestUtils.removeTab(win.gBrowser.selectedTab);
+  await BrowserTestUtils.closeWindow(win);
+});
+