Bug 1540112 - Enable addonsManager telemetry event category before the AddonManager/XPIProvider have been started. r=aswan a=pascalc
authorLuca Greco <lgreco@mozilla.com>
Sun, 07 Apr 2019 16:57:01 +0300
changeset 526008 29a5f480accb54f1ec649e468b03c14d7c004fb6
parent 526007 963ac226a9e16ae920c25b604dfc9f0d037b9b84
child 526009 c0c2da9127f3a5112d18df9e029a3a0bc8107d1e
push id2032
push userffxbld-merge
push dateMon, 13 May 2019 09:36:57 +0000
treeherdermozilla-release@455c1065dcbe [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersaswan, pascalc
bugs1540112
milestone67.0
Bug 1540112 - Enable addonsManager telemetry event category before the AddonManager/XPIProvider have been started. r=aswan a=pascalc Reviewers: aswan, chutten Reviewed By: aswan, chutten Subscribers: chutten Bug #: 1540112 Differential Revision: https://phabricator.services.mozilla.com/D25380
browser/components/extensions/test/browser/browser_ext_browserAction_contextMenu.js
toolkit/components/extensions/test/xpcshell/test_ext_incognito.js
toolkit/mozapps/extensions/AddonManager.jsm
--- a/browser/components/extensions/test/browser/browser_ext_browserAction_contextMenu.js
+++ b/browser/components/extensions/test/browser/browser_ext_browserAction_contextMenu.js
@@ -65,16 +65,21 @@ function assertTelemetryMatches(events) 
     .filter(([timestamp, category, method]) =>
       category == TELEMETRY_CATEGORY && TELEMETRY_METHODS.has(method))
     .map(relatedEvent => relatedEvent.slice(2, 6));
 
   // Events are now [method, object, value, extra] as expected.
   Assert.deepEqual(relatedEvents, events, "The events are recorded correctly");
 }
 
+add_task(async function test_setup() {
+  // Clear any previosuly collected telemetry event.
+  Services.telemetry.snapshotEvents(Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTIN, true);
+});
+
 add_task(async function browseraction_popup_contextmenu() {
   let extension = ExtensionTestUtils.loadExtension(extData);
   await extension.startup();
 
   await clickBrowserAction(extension, window);
 
   let contentAreaContextMenu = await openContextMenuInPopup(extension);
   let item = contentAreaContextMenu.getElementsByAttribute("label", "Click me!");
--- a/toolkit/components/extensions/test/xpcshell/test_ext_incognito.js
+++ b/toolkit/components/extensions/test/xpcshell/test_ext_incognito.js
@@ -3,23 +3,30 @@
 "use strict";
 
 const {AddonManager} = ChromeUtils.import("resource://gre/modules/AddonManager.jsm");
 
 AddonTestUtils.init(this);
 AddonTestUtils.overrideCertDB();
 AddonTestUtils.createAppInfo("xpcshell@tests.mozilla.org", "XPCShell", "1", "42");
 AddonTestUtils.usePrivilegedSignatures = false;
-AddonTestUtils.hookAMTelemetryEvents();
 
 // Assert on the expected "addonsManager.action" telemetry events (and optional filter events to verify
 // by using a given actionType).
 function assertActionAMTelemetryEvent(expectedActionEvents, assertMessage, {actionType} = {}) {
-  const events = AddonTestUtils.getAMTelemetryEvents().filter(({method, extra}) => {
-    return method === "action" && (!actionType ? true : extra && extra.action === actionType);
+  const snapshot = Services.telemetry.snapshotEvents(Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTIN, true);
+
+  ok(snapshot.parent && snapshot.parent.length > 0, "Got parent telemetry events in the snapshot");
+
+  const events = snapshot.parent.filter(([timestamp, category, method, object, value, extra]) => {
+    return category === "addonsManager" && method === "action" && (
+      !actionType ? true : extra && extra.action === actionType
+    );
+  }).map(([timestamp, category, method, object, value, extra]) => {
+    return {method, object, value, extra};
   });
 
   Assert.deepEqual(events, expectedActionEvents, assertMessage);
 }
 
 async function runIncognitoTest(extensionData, privateBrowsingAllowed, allowPrivateBrowsingByDefault) {
   Services.prefs.setBoolPref("extensions.allowPrivateBrowsingByDefault", allowPrivateBrowsingByDefault);
 
@@ -67,92 +74,94 @@ add_task(async function test_extension_i
 // incognito type prior to feature being turned on.
 add_task(async function test_extension_incognito_spanning_grandfathered() {
   await AddonTestUtils.promiseStartupManager();
   Services.prefs.setBoolPref("extensions.allowPrivateBrowsingByDefault", true);
   Services.prefs.setBoolPref("extensions.incognito.migrated", false);
 
   // This extension gets disabled before the "upgrade", it should not
   // get grandfathered permissions.
+  const disabledAddonId = "disabled-ext@mozilla.com";
   let disabledWrapper = ExtensionTestUtils.loadExtension({
     manifest: {
-      applications: {gecko: {id: "@disabled"}},
+      applications: {gecko: {id: disabledAddonId}},
       incognito: "spanning",
     },
     useAddonManager: "permanent",
   });
   await disabledWrapper.startup();
-  let disabledPolicy = WebExtensionPolicy.getByID("@disabled");
+  let disabledPolicy = WebExtensionPolicy.getByID(disabledAddonId);
 
   // Verify policy settings.
   equal(disabledPolicy.permissions.includes("internal:privateBrowsingAllowed"), false,
         "privateBrowsingAllowed is not in permissions for disabled addon");
   equal(disabledPolicy.privateBrowsingAllowed, true,
         "privateBrowsingAllowed in disabled addon");
 
-  let disabledAddon = await AddonManager.getAddonByID("@disabled");
+  let disabledAddon = await AddonManager.getAddonByID(disabledAddonId);
   await disabledAddon.disable();
 
   // This extension gets grandfathered permissions for private browsing.
-  let id = "@grandfathered";
+  let addonId = "grandfathered@mozilla.com";
   let wrapper = ExtensionTestUtils.loadExtension({
     manifest: {
-      applications: {gecko: {id}},
+      applications: {gecko: {id: addonId}},
       incognito: "spanning",
     },
     useAddonManager: "permanent",
   });
   await wrapper.startup();
-  let policy = WebExtensionPolicy.getByID(id);
+  let policy = WebExtensionPolicy.getByID(addonId);
 
   // Verify policy settings.
   equal(policy.permissions.includes("internal:privateBrowsingAllowed"), false,
         "privateBrowsingAllowed is not in permissions");
   equal(policy.privateBrowsingAllowed, true,
         "privateBrowsingAllowed in extension");
 
   // Turn on incognito support and update the browser.
   Services.prefs.setBoolPref("extensions.allowPrivateBrowsingByDefault", false);
+  // Disable the addonsManager telemetry event category, to ensure that it will
+  // be enabled automatically during the AddonManager/XPIProvider startup and
+  // the telemetry event recorded (See Bug 1540112 for a rationale).
+  Services.telemetry.setEventRecordingEnabled("addonsManager", false);
   await AddonTestUtils.promiseRestartManager("2");
   await wrapper.awaitStartup();
 
   // Did it upgrade?
   ok(Services.prefs.getBoolPref("extensions.incognito.migrated", false),
      "pref marked as migrated");
 
   // Verify policy settings.
-  policy = WebExtensionPolicy.getByID(id);
+  policy = WebExtensionPolicy.getByID(addonId);
   ok(policy.permissions.includes("internal:privateBrowsingAllowed"),
      "privateBrowsingAllowed is in permissions");
   equal(policy.privateBrowsingAllowed, true,
         "privateBrowsingAllowed in extension");
 
   // Verify the disabled addon did not get permissions.
-  disabledAddon = await AddonManager.getAddonByID("@disabled");
+  disabledAddon = await AddonManager.getAddonByID(disabledAddonId);
   await disabledAddon.enable();
-  disabledPolicy = WebExtensionPolicy.getByID("@disabled");
+  disabledPolicy = WebExtensionPolicy.getByID(disabledAddonId);
 
   // Verify policy settings.
   equal(disabledPolicy.permissions.includes("internal:privateBrowsingAllowed"), false,
         "privateBrowsingAllowed is not in permissions for disabled addon");
   equal(disabledPolicy.privateBrowsingAllowed, false,
         "privateBrowsingAllowed in disabled addon");
 
   await wrapper.unload();
   await disabledWrapper.unload();
   Services.prefs.clearUserPref("extensions.allowPrivateBrowsingByDefault");
   Services.prefs.clearUserPref("extensions.incognito.migrated");
 
   const expectedEvents = [{
     method: "action",
     object: "appUpgrade",
     value: "on",
-    extra: {
-      addonId: "@grandfathered",
-      action: "privateBrowsingAllowed",
-    },
+    extra: {addonId, action: "privateBrowsingAllowed"},
   }];
 
   assertActionAMTelemetryEvent(
     expectedEvents,
     "Got the expected telemetry events for the grandfathered extensions",
     {actionType: "privateBrowsingAllowed"});
 });
--- a/toolkit/mozapps/extensions/AddonManager.jsm
+++ b/toolkit/mozapps/extensions/AddonManager.jsm
@@ -528,16 +528,18 @@ var gUpdateEnabled = true;
 var gAutoUpdateDefault = true;
 var gWebExtensionsMinPlatformVersion = "";
 var gShutdownBarrier = null;
 var gRepoShutdownState = "";
 var gShutdownInProgress = false;
 var gPluginPageListener = null;
 var gBrowserUpdated = null;
 
+var AMTelemetry;
+
 /**
  * This is the real manager, kept here rather than in AddonManager to keep its
  * contents hidden from API users.
  * @class
  * @lends AddonManager
  */
 var AddonManagerInternal = {
   managerListeners: new Set(),
@@ -696,16 +698,19 @@ var AddonManagerInternal = {
    */
   startup() {
     try {
       if (gStarted)
         return;
 
       this.recordTimestamp("AMI_startup_begin");
 
+      // Enable the addonsManager telemetry event category.
+      AMTelemetry.init();
+
       // clear this for xpcshell test restarts
       for (let provider in this.telemetryDetails)
         delete this.telemetryDetails[provider];
 
       let appChanged = undefined;
 
       let oldAppVersion = null;
       try {
@@ -3496,31 +3501,37 @@ var AddonManager = {
   get shutdown() {
     return gShutdownBarrier.client;
   },
 };
 
 /**
  * Listens to the AddonManager install and addon events and send telemetry events.
  */
-var AMTelemetry = {
+AMTelemetry = {
   telemetrySetupDone: false,
 
+  init() {
+    // Enable the addonsManager telemetry event category before the AddonManager
+    // has completed its startup, otherwise telemetry events recorded during the
+    // AddonManager/XPIProvider startup will not be recorded (e.g. the telemetry
+    // events for the extension migrated to the private browsing permission).
+    Services.telemetry.setEventRecordingEnabled("addonsManager", true);
+  },
+
   // This method is called by the AddonManager, once it has been started, so that we can
   // init the telemetry event category and start listening for the events related to the
   // addons installation and management.
   onStartup() {
     if (this.telemetrySetupDone) {
       return;
     }
 
     this.telemetrySetupDone = true;
 
-    Services.telemetry.setEventRecordingEnabled("addonsManager", true);
-
     Services.obs.addObserver(this, "addon-install-origin-blocked");
     Services.obs.addObserver(this, "addon-install-disabled");
     Services.obs.addObserver(this, "addon-install-blocked");
 
     AddonManager.addInstallListener(this);
     AddonManager.addAddonListener(this);
   },