diff --git a/modules/libpref/init/all.js b/modules/libpref/init/all.js index f0233cfbef6c..a0deffa91b3f 100644 --- a/modules/libpref/init/all.js +++ b/modules/libpref/init/all.js @@ -4789,6 +4789,7 @@ pref("xpinstall.signatures.required", false); pref("extensions.alwaysUnpack", false); pref("extensions.minCompatiblePlatformVersion", "2.0"); pref("extensions.webExtensionsMinPlatformVersion", "42.0a1"); +pref("extensions.allow-non-mpc-extensions", true); // Other webextensions prefs pref("extensions.webextensions.keepStorageOnUninstall", false); diff --git a/toolkit/mozapps/extensions/internal/XPIProvider.jsm b/toolkit/mozapps/extensions/internal/XPIProvider.jsm index 96684d383375..b95a8e7eae24 100644 --- a/toolkit/mozapps/extensions/internal/XPIProvider.jsm +++ b/toolkit/mozapps/extensions/internal/XPIProvider.jsm @@ -132,6 +132,7 @@ 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_E10S_HAS_NONEXEMPT_ADDON = "extensions.e10s.rollout.hasAddon"; +const PREF_ALLOW_NON_MPC = "extensions.allow-non-mpc-extensions"; const PREF_EM_MIN_COMPAT_APP_VERSION = "extensions.minCompatibleAppVersion"; const PREF_EM_MIN_COMPAT_PLATFORM_VERSION = "extensions.minCompatiblePlatformVersion"; @@ -185,6 +186,8 @@ const XPI_SIGNATURE_CHECK_PERIOD = 24 * 60 * 60; XPCOMUtils.defineConstant(this, "DB_SCHEMA", 19); +XPCOMUtils.defineLazyPreferenceGetter(this, "ALLOW_NON_MPC", PREF_ALLOW_NON_MPC); + const NOTIFICATION_TOOLBOXPROCESS_LOADED = "ToolboxProcessLoaded"; // Properties that exist in the install manifest @@ -805,6 +808,11 @@ function isUsableAddon(aAddon) { return false; } + if (!ALLOW_NON_MPC && aAddon.multiprocessCompatible !== true) { + logger.warn(`disabling ${aAddon.id} since it is not multiprocess compatible`); + return false; + } + if (AddonManager.checkCompatibility) { if (!aAddon.isCompatible) { logger.warn(`Add-on ${aAddon.id} is not compatible with application version.`); @@ -2815,6 +2823,7 @@ this.XPIProvider = { Services.prefs.addObserver(PREF_E10S_ADDON_POLICY, this); if (!REQUIRE_SIGNING) Services.prefs.addObserver(PREF_XPI_SIGNATURES_REQUIRED, this); + Services.prefs.addObserver(PREF_ALLOW_NON_MPC, this); Services.obs.addObserver(this, NOTIFICATION_FLUSH_PERMISSIONS); // Cu.isModuleLoaded can fail here for external XUL apps where there is @@ -4478,6 +4487,7 @@ this.XPIProvider = { this.updateAddonAppDisabledStates(); break; case PREF_XPI_SIGNATURES_REQUIRED: + case PREF_ALLOW_NON_MPC: this.updateAddonAppDisabledStates(); break; diff --git a/toolkit/mozapps/extensions/test/xpcshell/test_multiprocessCompatible.js b/toolkit/mozapps/extensions/test/xpcshell/test_multiprocessCompatible.js index 95dfcc02e941..485a56bb467b 100644 --- a/toolkit/mozapps/extensions/test/xpcshell/test_multiprocessCompatible.js +++ b/toolkit/mozapps/extensions/test/xpcshell/test_multiprocessCompatible.js @@ -102,6 +102,76 @@ for (let bootstrap of [false, true]) { } } +add_task(async function test_disable() { + const PREF = "extensions.allow-non-mpc-extensions"; + const ID_MPC = "mpc@tests.mozilla.org"; + const ID_NON_MPC = "non-mpc@tests.mozilla.org"; + + let addonData = { + name: "Test Add-on", + version: "1.0", + bootstrap: true, + targetApplications: [{ + id: "xpcshell@tests.mozilla.org", + minVersion: "1", + maxVersion: "1" + }] + } + + let xpi1 = createTempXPIFile(Object.assign({ + id: ID_MPC, + multiprocessCompatible: true, + }, addonData)); + let xpi2 = createTempXPIFile(Object.assign({ + id: ID_NON_MPC, + multiprocessCompatible: false, + }, addonData)); + + async function testOnce(initialAllow) { + if (initialAllow !== undefined) { + Services.prefs.setBoolPref(PREF, initialAllow); + } + + let install1 = await AddonManager.getInstallForFile(xpi1); + let install2 = await AddonManager.getInstallForFile(xpi2); + await promiseCompleteAllInstalls([install1, install2]); + + let [addon1, addon2] = await AddonManager.getAddonsByIDs([ID_MPC, ID_NON_MPC]); + do_check_neq(addon1, null); + do_check_eq(addon1.multiprocessCompatible, true); + do_check_eq(addon1.appDisabled, false); + + do_check_neq(addon2, null); + do_check_eq(addon2.multiprocessCompatible, false); + do_check_eq(addon2.appDisabled, initialAllow === false); + + // Flip the allow-non-mpc preference + let newValue = (initialAllow === true) ? false : true; + Services.prefs.setBoolPref(PREF, newValue); + + // the mpc extension should never become appDisabled + do_check_eq(addon1.appDisabled, false); + + // The non-mpc extension should become disabled if we don't allow non-mpc + do_check_eq(addon2.appDisabled, !newValue); + + // Flip the pref back and check appDisabled + Services.prefs.setBoolPref(PREF, !newValue); + + do_check_eq(addon1.appDisabled, false); + do_check_eq(addon2.appDisabled, newValue); + + addon1.uninstall(); + addon2.uninstall(); + } + + await testOnce(undefined); + await testOnce(true); + await testOnce(false); + + Services.prefs.clearUserPref(PREF); +}); + function run_test() { createAppInfo("xpcshell@tests.mozilla.org", "XPCShell", "1", "1"); startupManager();