diff options
Diffstat (limited to 'browser/extensions/e10srollout/bootstrap.js')
-rw-r--r-- | browser/extensions/e10srollout/bootstrap.js | 197 |
1 files changed, 197 insertions, 0 deletions
diff --git a/browser/extensions/e10srollout/bootstrap.js b/browser/extensions/e10srollout/bootstrap.js new file mode 100644 index 000000000..0da7ac225 --- /dev/null +++ b/browser/extensions/e10srollout/bootstrap.js @@ -0,0 +1,197 @@ +/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */ +/* 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"; + +const {classes: Cc, interfaces: Ci, utils: Cu} = Components; + +Cu.import("resource://gre/modules/Preferences.jsm"); +Cu.import("resource://gre/modules/Services.jsm"); +Cu.import("resource://gre/modules/UpdateUtils.jsm"); +Cu.import("resource://gre/modules/AppConstants.jsm"); + + // The amount of people to be part of e10s +const TEST_THRESHOLD = { + "beta" : 0.5, // 50% + "release" : 1.0, // 100% + "esr" : 1.0, // 100% +}; + +const ADDON_ROLLOUT_POLICY = { + "beta" : "51alladdons", // Any WebExtension or addon except with mpc = false + "release" : "51set1", + "esr" : "esrA", // WebExtensions and Addons with mpc=true +}; + +if (AppConstants.RELEASE_OR_BETA) { + // Bug 1348576 - e10s is never enabled for non-official release builds + // This is hacky, but the problem it solves is the following: + // the e10s rollout is controlled by the channel name, which + // is the only way to distinguish between Beta and Release. + // However, non-official release builds (like the ones done by distros + // to ship Firefox on their package managers) do not set a value + // for the release channel, which gets them to the default value + // of.. (drumroll) "default". + // But we can't just always configure the same settings for the + // "default" channel because that's also the name that a locally + // built Firefox gets, and e10s is managed in a different way + // there (directly by prefs, on Nightly and Aurora). + TEST_THRESHOLD.default = TEST_THRESHOLD.release; + ADDON_ROLLOUT_POLICY.default = ADDON_ROLLOUT_POLICY.release; +} + + +const PREF_COHORT_SAMPLE = "e10s.rollout.cohortSample"; +const PREF_COHORT_NAME = "e10s.rollout.cohort"; +const PREF_E10S_OPTED_IN = "browser.tabs.remote.autostart"; +const PREF_E10S_FORCE_ENABLED = "browser.tabs.remote.force-enable"; +const PREF_E10S_FORCE_DISABLED = "browser.tabs.remote.force-disable"; +const PREF_TOGGLE_E10S = "browser.tabs.remote.autostart.2"; +const PREF_E10S_ADDON_POLICY = "extensions.e10s.rollout.policy"; +const PREF_E10S_ADDON_BLOCKLIST = "extensions.e10s.rollout.blocklist"; +const PREF_E10S_HAS_NONEXEMPT_ADDON = "extensions.e10s.rollout.hasAddon"; + +function startup() { + // In theory we only need to run this once (on install()), but + // it's better to also run it on every startup. If the user has + // made manual changes to the prefs, this will keep the data + // reported more accurate. + // It's also fine (and preferred) to just do it here on startup + // (instead of observing prefs), because e10s takes a restart + // to take effect, so we keep the data based on how it was when + // the session started. + defineCohort(); +} + +function install() { + defineCohort(); +} + +let cohortDefinedOnThisSession = false; + +function defineCohort() { + // Avoid running twice when it was called by install() first + if (cohortDefinedOnThisSession) { + return; + } + cohortDefinedOnThisSession = true; + + let updateChannel = UpdateUtils.getUpdateChannel(false); + if (!(updateChannel in TEST_THRESHOLD)) { + setCohort("unsupportedChannel"); + return; + } + + let addonPolicy = "unknown"; + if (updateChannel in ADDON_ROLLOUT_POLICY) { + addonPolicy = ADDON_ROLLOUT_POLICY[updateChannel]; + Preferences.set(PREF_E10S_ADDON_POLICY, addonPolicy); + // This is also the proper place to set the blocklist pref + // in case it is necessary. + + Preferences.set(PREF_E10S_ADDON_BLOCKLIST, + // bug 1185672 - Tab Mix Plus + "{dc572301-7619-498c-a57d-39143191b318};" + + // bug 1332692 - LastPass + "support@lastpass.com;"); + } else { + Preferences.reset(PREF_E10S_ADDON_POLICY); + } + + let userOptedOut = optedOut(); + let userOptedIn = optedIn(); + let disqualified = (Services.appinfo.multiprocessBlockPolicy != 0); + let testGroup = (getUserSample() < TEST_THRESHOLD[updateChannel]); + let hasNonExemptAddon = Preferences.get(PREF_E10S_HAS_NONEXEMPT_ADDON, false); + let temporaryDisqualification = getTemporaryDisqualification(); + + let cohortPrefix = ""; + if (disqualified) { + cohortPrefix = "disqualified-"; + } else if (hasNonExemptAddon) { + cohortPrefix = `addons-set${addonPolicy}-`; + } + + if (userOptedOut) { + setCohort("optedOut"); + } else if (userOptedIn) { + setCohort("optedIn"); + } else if (temporaryDisqualification != "") { + // Users who are disqualified by the backend (from multiprocessBlockPolicy) + // can be put into either the test or control groups, because e10s will + // still be denied by the backend, which is useful so that the E10S_STATUS + // telemetry probe can be correctly set. + + // For these volatile disqualification reasons, however, we must not try + // to activate e10s because the backend doesn't know about it. E10S_STATUS + // here will be accumulated as "2 - Disabled", which is fine too. + setCohort(`temp-disqualified-${temporaryDisqualification}`); + Preferences.reset(PREF_TOGGLE_E10S); + } else if (testGroup) { + setCohort(`${cohortPrefix}test`); + Preferences.set(PREF_TOGGLE_E10S, true); + } else { + setCohort(`${cohortPrefix}control`); + Preferences.reset(PREF_TOGGLE_E10S); + } +} + +function shutdown(data, reason) { +} + +function uninstall() { +} + +function getUserSample() { + let prefValue = Preferences.get(PREF_COHORT_SAMPLE, undefined); + let value = 0.0; + + if (typeof(prefValue) == "string") { + value = parseFloat(prefValue, 10); + return value; + } + + if (typeof(prefValue) == "number") { + // convert old integer value + value = prefValue / 100; + } else { + value = Math.random(); + } + + Preferences.set(PREF_COHORT_SAMPLE, value.toString().substr(0, 8)); + return value; +} + +function setCohort(cohortName) { + Preferences.set(PREF_COHORT_NAME, cohortName); + try { + if (Ci.nsICrashReporter) { + Services.appinfo.QueryInterface(Ci.nsICrashReporter).annotateCrashReport("E10SCohort", cohortName); + } + } catch (e) {} +} + +function optedIn() { + return Preferences.get(PREF_E10S_OPTED_IN, false) || + Preferences.get(PREF_E10S_FORCE_ENABLED, false); +} + +function optedOut() { + // Users can also opt-out by toggling back the pref to false. + // If they reset the pref instead they might be re-enabled if + // they are still part of the threshold. + return Preferences.get(PREF_E10S_FORCE_DISABLED, false) || + (Preferences.isSet(PREF_TOGGLE_E10S) && + Preferences.get(PREF_TOGGLE_E10S) == false); +} + +/* If this function returns a non-empty string, it + * means that this particular user should be temporarily + * disqualified due to some particular reason. + * If a user shouldn't be disqualified, then an empty + * string must be returned. + */ +function getTemporaryDisqualification() { + return ""; +} |