Bug 1509047 - Part 2: Add an API for measuring the number of unique origins visited in the past 24 hours r=johannh
☠☠ backed out by 0f4be93319f6 ☠ ☠
authorEhsan Akhgari <ehsan@mozilla.com>
Wed, 28 Nov 2018 23:01:36 +0000
changeset 507865 1aa87e9e3c71eb756c446b285f098d0dc267b38e
parent 507864 da642018d1c67b613d25a17208e83a5d2ab09063
child 507866 cc9d468d6ba6a52d06f7fb03b8778e1ce6e70e69
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 Depends on D12862 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
@@ -1790,8 +1790,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,51 @@
+/* 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() {
+  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
+  SpecialPowers.setIntPref("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);
+});
+