Bug 1232274: Make installing or enabling an add-on require a restart if e10s is on and a pref is set. r=rhelmer

This commit is contained in:
Dave Townsend 2016-01-14 15:21:01 -08:00
parent 1676006de9
commit c8f694bf43
4 changed files with 194 additions and 0 deletions

View File

@ -112,6 +112,7 @@ const PREF_SHOWN_SELECTION_UI = "extensions.shownSelectionUI";
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_EM_MIN_COMPAT_APP_VERSION = "extensions.minCompatibleAppVersion";
const PREF_EM_MIN_COMPAT_PLATFORM_VERSION = "extensions.minCompatiblePlatformVersion";
@ -2744,11 +2745,19 @@ this.XPIProvider = {
observe: function(aSubject, aTopic, aData) {
XPIProvider._closing = true;
for (let id in XPIProvider.bootstrappedAddons) {
// If no scope has been loaded for this add-on then there is no need
// to shut it down (should only happen when a bootstrapped add-on is
// pending enable)
if (!(id in XPIProvider.bootstrapScopes))
continue;
let file = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsIFile);
file.persistentDescriptor = XPIProvider.bootstrappedAddons[id].descriptor;
let addon = createAddonDetails(id, XPIProvider.bootstrappedAddons[id]);
XPIProvider.callBootstrapMethod(addon, file, "shutdown",
BOOTSTRAP_REASONS.APP_SHUTDOWN);
if (XPIProvider.bootstrappedAddons[id].disable)
delete XPIProvider.bootstrappedAddons[aId];
}
Services.obs.removeObserver(this, "quit-application-granted");
}
@ -4229,6 +4238,41 @@ this.XPIProvider = {
}
},
/**
* 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.
*
* @param aAddon
* The add-on to test
* @return true if enabling the add-on requires a restart
*/
e10sBlocksEnabling: function(aAddon) {
// If the preference isn't set then don't block anything
if (!Preferences.get(PREF_E10S_BLOCK_ENABLE, false))
return false;
// If e10s isn't active then don't block anything
if (!Services.appinfo.browserTabsRemoteAutostart)
return false;
// Only extensions change behaviour
if (aAddon.type != "extension")
return false;
// The hotfix is exempt
let hotfixID = Preferences.get(PREF_EM_HOTFIX_ID, undefined);
if (hotfixID && hotfixID == aAddon.id)
return false;
// System add-ons are exempt
if (aAddon._installLocation.name == KEY_APP_SYSTEM_DEFAULTS ||
aAddon._installLocation.name == KEY_APP_SYSTEM_ADDONS)
return false;
return true;
},
/**
* Tests whether enabling an add-on will require a restart.
*
@ -4263,6 +4307,9 @@ this.XPIProvider = {
return aAddon.internalName != this.currentSkin;
}
if (this.e10sBlocksEnabling(aAddon))
return true;
return !aAddon.bootstrap;
},
@ -4353,6 +4400,9 @@ this.XPIProvider = {
if (aAddon.disabled)
return false;
if (this.e10sBlocksEnabling(aAddon))
return true;
// Themes will require a restart (even if dynamic switching is enabled due
// to some caching issues) and non-bootstrapped add-ons will require a
// restart
@ -4724,6 +4774,23 @@ this.XPIProvider = {
AddonManagerPrivate.callAddonListeners("onEnabled", wrapper);
}
}
else if (aAddon.bootstrap) {
// Something blocked the restartless add-on from enabling or disabling
// make sure it happens on the next startup
if (isDisabled) {
this.bootstrappedAddons[aAddon.id].disable = true;
}
else {
this.bootstrappedAddons[aAddon.id] = {
version: aAddon.version,
type: aAddon.type,
descriptor: aAddon._sourceBundle.persistentDescriptor,
multiprocessCompatible: aAddon.multiprocessCompatible,
runInSafeMode: canRunInSafeMode(aAddon),
};
this.persistBootstrappedAddons();
}
}
}
// Sync with XPIStates.

View File

@ -262,6 +262,7 @@ function createAppInfo(id, name, version, platformVersion) {
platformBuildID: "2007010101",
// nsIXULRuntime
browserTabsRemoteAutostart: false,
inSafeMode: false,
logConsoleErrors: true,
OS: "XPCShell",

View File

@ -0,0 +1,125 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/
*/
const ID = "bootstrap1@tests.mozilla.org";
BootstrapMonitor.init();
createAppInfo("xpcshell@tests.mozilla.org", "XPCShell", "1", "1.9.2");
startupManager();
function* check_normal() {
let install = yield new Promise(resolve => AddonManager.getInstallForFile(do_get_addon("test_bootstrap1_1"), resolve));
yield promiseCompleteAllInstalls([install]);
do_check_eq(install.state, AddonManager.STATE_INSTALLED);
do_check_false(hasFlag(install.addon.pendingOperations, AddonManager.PENDING_INSTALL));
BootstrapMonitor.checkAddonInstalled(ID);
BootstrapMonitor.checkAddonStarted(ID);
let addon = yield promiseAddonByID(ID);
do_check_eq(addon, install.addon);
do_check_false(hasFlag(addon.operationsRequiringRestart, AddonManager.OP_NEEDS_RESTART_DISABLE));
addon.userDisabled = true;
BootstrapMonitor.checkAddonNotStarted(ID);
do_check_false(addon.isActive);
do_check_false(hasFlag(addon.pendingOperations, AddonManager.PENDING_DISABLE));
do_check_false(hasFlag(addon.operationsRequiringRestart, AddonManager.OP_NEEDS_RESTART_ENABLE));
addon.userDisabled = false;
BootstrapMonitor.checkAddonStarted(ID);
do_check_true(addon.isActive);
do_check_false(hasFlag(addon.pendingOperations, AddonManager.PENDING_ENABLE));
do_check_false(hasFlag(addon.operationsRequiringRestart, AddonManager.OP_NEEDS_RESTART_UNINSTALL));
addon.uninstall();
BootstrapMonitor.checkAddonNotStarted(ID);
BootstrapMonitor.checkAddonNotInstalled(ID);
restartManager();
}
// Installing the add-on normally doesn't require a restart
add_task(function*() {
gAppInfo.browserTabsRemoteAutostart = false;
Services.prefs.setBoolPref("extensions.e10sBlocksEnabling", false);
yield check_normal();
});
// Enabling the pref doesn't change anything
add_task(function*() {
gAppInfo.browserTabsRemoteAutostart = false;
Services.prefs.setBoolPref("extensions.e10sBlocksEnabling", true);
yield check_normal();
});
// Default e10s doesn't change anything
add_task(function*() {
gAppInfo.browserTabsRemoteAutostart = true;
Services.prefs.setBoolPref("extensions.e10sBlocksEnabling", false);
yield check_normal();
});
// Pref and e10s blocks install
add_task(function*() {
gAppInfo.browserTabsRemoteAutostart = true;
Services.prefs.setBoolPref("extensions.e10sBlocksEnabling", true);
let install = yield new Promise(resolve => AddonManager.getInstallForFile(do_get_addon("test_bootstrap1_1"), resolve));
yield promiseCompleteAllInstalls([install]);
do_check_eq(install.state, AddonManager.STATE_INSTALLED);
do_check_true(hasFlag(install.addon.pendingOperations, AddonManager.PENDING_INSTALL));
let addon = yield promiseAddonByID(ID);
do_check_eq(addon, null);
yield promiseRestartManager();
BootstrapMonitor.checkAddonInstalled(ID);
BootstrapMonitor.checkAddonStarted(ID);
addon = yield promiseAddonByID(ID);
do_check_neq(addon, null);
do_check_false(hasFlag(addon.operationsRequiringRestart, AddonManager.OP_NEEDS_RESTART_DISABLE));
addon.userDisabled = true;
BootstrapMonitor.checkAddonNotStarted(ID);
do_check_false(addon.isActive);
do_check_false(hasFlag(addon.pendingOperations, AddonManager.PENDING_DISABLE));
do_check_true(hasFlag(addon.operationsRequiringRestart, AddonManager.OP_NEEDS_RESTART_ENABLE));
addon.userDisabled = false;
BootstrapMonitor.checkAddonNotStarted(ID);
do_check_false(addon.isActive);
do_check_true(hasFlag(addon.pendingOperations, AddonManager.PENDING_ENABLE));
yield promiseRestartManager();
addon = yield promiseAddonByID(ID);
do_check_neq(addon, null);
do_check_true(addon.isActive);
BootstrapMonitor.checkAddonStarted(ID);
do_check_false(hasFlag(addon.operationsRequiringRestart, AddonManager.OP_NEEDS_RESTART_UNINSTALL));
addon.uninstall();
BootstrapMonitor.checkAddonNotStarted(ID);
BootstrapMonitor.checkAddonNotInstalled(ID);
restartManager();
});
// The hotfix is unaffected
add_task(function*() {
gAppInfo.browserTabsRemoteAutostart = true;
Services.prefs.setBoolPref("extensions.e10sBlocksEnabling", true);
Services.prefs.setCharPref("extensions.hotfix.id", ID);
yield check_normal();
});

View File

@ -303,3 +303,4 @@ run-sequentially = Uses global XCurProcD dir.
skip-if = os != "win"
[test_bug1180901.js]
skip-if = os != "win"
[test_e10s_restartless.js]