Bug 1247497 - Mechanism to control when e10s is turned on based on add-ons presence or absense. r=krizsa a=sylvestre
authorFelipe Gomes <felipc@gmail.com>
Fri, 29 Jul 2016 13:47:37 -0300
changeset 342112 d2076125a317af21aaf87cc2a3eee4351eeaaf5f
parent 342111 29dda3d9dfcb2ac4b7e84f69bb1649af99089f19
child 342113 ed1ccacac3d82e261254e853f359e399f72bd424
push id1183
push userraliiev@mozilla.com
push dateMon, 05 Sep 2016 20:01:49 +0000
treeherdermozilla-release@3148731bed45 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerskrizsa, sylvestre
bugs1247497
milestone49.0a2
Bug 1247497 - Mechanism to control when e10s is turned on based on add-ons presence or absense. r=krizsa a=sylvestre MozReview-Commit-ID: 9ZYXryIEpUf
toolkit/mozapps/extensions/internal/E10SAddonsRollout.jsm
toolkit/mozapps/extensions/internal/XPIProvider.jsm
toolkit/mozapps/extensions/internal/moz.build
new file mode 100644
--- /dev/null
+++ b/toolkit/mozapps/extensions/internal/E10SAddonsRollout.jsm
@@ -0,0 +1,107 @@
+/* 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";
+
+this.EXPORTED_SYMBOLS = [ "isAddonPartOfE10SRollout" ];
+
+const Cu = Components.utils;
+Cu.import("resource://gre/modules/Preferences.jsm");
+Cu.import("resource://gre/modules/Services.jsm");
+
+const PREF_E10S_ADDON_BLOCKLIST = "extensions.e10s.rollout.blocklist";
+const PREF_E10S_ADDON_POLICY    = "extensions.e10s.rollout.policy";
+
+const ADDONS = {
+  "Greasemonkey": { // Greasemonkey
+    id: "{e4a8a97b-f2ed-450b-b12d-ee082ba24781}", minVersion: "3.8",
+  },
+
+  "DYTV": { // Download YouTube Videos as MP4
+    id: "{b9bfaf1c-a63f-47cd-8b9a-29526ced9060}", minVersion: "1.8.7",
+  },
+
+  "VDH": { // Video Download Helper
+    id: "{b9db16a4-6edc-47ec-a1f4-b86292ed211d}", minVersion: "5.6.1",
+  },
+
+  "Lightbeam": { // Lightbeam
+    id: "jid1-F9UJ2thwoAm5gQ@jetpack", minVersion: "1.3.0.1",
+  },
+
+  "ABP": { // Adblock Plus
+    id: "{d10d0bf8-f5b5-c8b4-a8b2-2b9879e08c5d}", minVersion: "2.7.3",
+  },
+
+  "uBlockOrigin": { // uBlock Origin
+    id: "uBlock0@raymondhill.net", minVersion: "1.7.6",
+  },
+
+  "Emoji": { // Emoji Cheatsheet
+    id: "jid1-Xo5SuA6qc1DFpw@jetpack", minVersion: "1.1.1",
+  },
+
+  "ASP": { // Awesome Screenshot Plus
+    id: "jid0-GXjLLfbCoAx0LcltEdFrEkQdQPI@jetpack", minVersion: "3.0.10",
+  },
+};
+
+// NOTE: Do not modify sets or policies after they have already been
+// published to users. They must remain unchanged to provide valid data.
+const set1 = [ADDONS.Emoji,
+              ADDONS.ASP,
+              ADDONS.DYTV];
+
+const set2 = [ADDONS.Greasemonkey,
+              ADDONS.DYTV,
+              ADDONS.VDH,
+              ADDONS.Lightbeam,
+              ADDONS.ABP,
+              ADDONS.uBlockOrigin,
+              ADDONS.Emoji,
+              ADDONS.ASP];
+
+// We use these named policies to correlate the telemetry
+// data with them, in order to understand how each set
+// is behaving in the wild.
+const RolloutPolicy = {
+  "1a": { addons: set1, webextensions: true },
+  "2a": { addons: set2, webextensions: true },
+
+  "1b": { addons: set1, webextensions: false },
+  "2b": { addons: set2, webextensions: false },
+};
+
+Object.defineProperty(this, "isAddonPartOfE10SRollout", {
+  configurable: false,
+  enumerable: false,
+  writable: false,
+  value: function isAddonPartOfE10SRollout(aAddon) {
+    let blocklist = Preferences.get(PREF_E10S_ADDON_BLOCKLIST, "");
+    let policyId = Preferences.get(PREF_E10S_ADDON_POLICY, "");
+
+    if (!policyId || !RolloutPolicy.hasOwnProperty(policyId)) {
+      return false;
+    }
+
+    if (blocklist && blocklist.indexOf(aAddon.id) > -1) {
+      return false;
+    }
+
+    let policy = RolloutPolicy[policyId];
+
+    if (policy.webextensions && aAddon.type == "webextension") {
+      return true;
+    }
+
+    for (let rolloutAddon of policy.addons) {
+      if (aAddon.id == rolloutAddon.id &&
+          Services.vc.compare(aAddon.version, rolloutAddon.minVersion) >= 0) {
+        return true;
+      }
+    }
+
+    return false;
+  },
+});
--- a/toolkit/mozapps/extensions/internal/XPIProvider.jsm
+++ b/toolkit/mozapps/extensions/internal/XPIProvider.jsm
@@ -50,16 +50,18 @@ XPCOMUtils.defineLazyModuleGetter(this, 
 XPCOMUtils.defineLazyModuleGetter(this, "ConsoleAPI",
                                   "resource://gre/modules/Console.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "ProductAddonChecker",
                                   "resource://gre/modules/addons/ProductAddonChecker.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "UpdateUtils",
                                   "resource://gre/modules/UpdateUtils.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "AppConstants",
                                   "resource://gre/modules/AppConstants.jsm");
+XPCOMUtils.defineLazyModuleGetter(this, "isAddonPartOfE10SRollout",
+                                  "resource://gre/modules/addons/E10SAddonsRollout.jsm");
 
 XPCOMUtils.defineLazyServiceGetter(this, "Blocklist",
                                    "@mozilla.org/extensions/blocklist;1",
                                    Ci.nsIBlocklistService);
 XPCOMUtils.defineLazyServiceGetter(this,
                                    "ChromeRegistry",
                                    "@mozilla.org/chrome/chrome-registry;1",
                                    "nsIChromeRegistry");
@@ -112,16 +114,18 @@ const PREF_XPI_UNPACK                 = 
 const PREF_INSTALL_REQUIREBUILTINCERTS = "extensions.install.requireBuiltInCerts";
 const PREF_INSTALL_REQUIRESECUREORIGIN = "extensions.install.requireSecureOrigin";
 const PREF_INSTALL_DISTRO_ADDONS      = "extensions.installDistroAddons";
 const PREF_BRANCH_INSTALLED_ADDON     = "extensions.installedDistroAddon.";
 const PREF_INTERPOSITION_ENABLED      = "extensions.interposition.enabled";
 const PREF_SYSTEM_ADDON_SET           = "extensions.systemAddonSet";
 const PREF_SYSTEM_ADDON_UPDATE_URL    = "extensions.systemAddon.update.url";
 const PREF_E10S_BLOCK_ENABLE          = "extensions.e10sBlocksEnabling";
+const PREF_E10S_ADDON_BLOCKLIST       = "extensions.e10s.rollout.blocklist";
+const PREF_E10S_ADDON_POLICY          = "extensions.e10s.rollout.policy";
 
 const PREF_EM_MIN_COMPAT_APP_VERSION      = "extensions.minCompatibleAppVersion";
 const PREF_EM_MIN_COMPAT_PLATFORM_VERSION = "extensions.minCompatiblePlatformVersion";
 
 const PREF_CHECKCOMAT_THEMEOVERRIDE   = "extensions.checkCompatibility.temporaryThemeOverride_minAppVersion";
 
 const PREF_EM_HOTFIX_ID               = "extensions.hotfix.id";
 const PREF_EM_CERT_CHECKATTRIBUTES    = "extensions.hotfix.cert.checkAttributes";
@@ -2673,16 +2677,18 @@ this.XPIProvider = {
       this.minCompatibleAppVersion = Preferences.get(PREF_EM_MIN_COMPAT_APP_VERSION,
                                                      null);
       this.minCompatiblePlatformVersion = Preferences.get(PREF_EM_MIN_COMPAT_PLATFORM_VERSION,
                                                           null);
       this.enabledAddons = "";
 
       Services.prefs.addObserver(PREF_EM_MIN_COMPAT_APP_VERSION, this, false);
       Services.prefs.addObserver(PREF_EM_MIN_COMPAT_PLATFORM_VERSION, this, false);
+      Services.prefs.addObserver(PREF_E10S_ADDON_BLOCKLIST, this, false);
+      Services.prefs.addObserver(PREF_E10S_ADDON_POLICY, this, false);
       if (!REQUIRE_SIGNING)
         Services.prefs.addObserver(PREF_XPI_SIGNATURES_REQUIRED, this, false);
       Services.obs.addObserver(this, NOTIFICATION_FLUSH_PERMISSIONS, false);
 
       // Cu.isModuleLoaded can fail here for external XUL apps where there is
       // no chrome.manifest that defines resource://devtools.
       if (ResProtocolHandler.hasSubstitution("devtools")) {
         if (Cu.isModuleLoaded("resource://devtools/client/framework/ToolboxProcess.jsm")) {
@@ -4314,16 +4320,21 @@ this.XPIProvider = {
       case PREF_EM_MIN_COMPAT_PLATFORM_VERSION:
         this.minCompatiblePlatformVersion = Preferences.get(PREF_EM_MIN_COMPAT_PLATFORM_VERSION,
                                                             null);
         this.updateAddonAppDisabledStates();
         break;
       case PREF_XPI_SIGNATURES_REQUIRED:
         this.updateAddonAppDisabledStates();
         break;
+
+      case PREF_E10S_ADDON_BLOCKLIST:
+      case PREF_E10S_ADDON_POLICY:
+        XPIDatabase.updateAddonsBlockingE10s();
+        break;
       }
     }
   },
 
   /**
    * Determine if an add-on should be blocking e10s if enabled.
    *
    * @param  aAddon
@@ -4348,16 +4359,20 @@ this.XPIProvider = {
 
     // System add-ons are exempt
     let locName = aAddon._installLocation ? aAddon._installLocation.name
                                           : undefined;
     if (locName == KEY_APP_SYSTEM_DEFAULTS ||
         locName == KEY_APP_SYSTEM_ADDONS)
       return false;
 
+    if (isAddonPartOfE10SRollout(aAddon))
+      return false;
+
+    logger.debug("Add-on " + aAddon.id + " blocks e10s rollout.");
     return true;
   },
 
   /**
    * In some cases having add-ons active blocks e10s but turning off e10s
    * requires a restart so some add-ons that are normally restartless will
    * require a restart to install or enable.
    *
--- a/toolkit/mozapps/extensions/internal/moz.build
+++ b/toolkit/mozapps/extensions/internal/moz.build
@@ -5,16 +5,17 @@
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 EXTRA_JS_MODULES.addons += [
     'AddonLogging.jsm',
     'AddonRepository.jsm',
     'AddonRepository_SQLiteMigrator.jsm',
     'AddonUpdateChecker.jsm',
     'Content.js',
+    'E10SAddonsRollout.jsm',
     'GMPProvider.jsm',
     'LightweightThemeImageOptimizer.jsm',
     'ProductAddonChecker.jsm',
     'SpellCheckDictionaryBootstrap.js',
     'WebExtensionBootstrap.js',
     'XPIProvider.jsm',
     'XPIProviderUtils.js',
 ]