Bug 1363925: Part 8d - Move updateAddonDisabledState to XPIDatabase. r=aswan

This code is large and complex, and can only be called when we have an
AddonInternal object from XPIDatabase.jsm. It should live with that code.

MozReview-Commit-ID: 3ssV5aH9NUJ

--HG--
extra : rebase_source : d54474f67213420678706f04291b246ceee154de
extra : histedit_source : d1a3ca6fd05856a6675380717351e2e1d1568cf1
This commit is contained in:
Kris Maglione 2018-04-22 15:00:08 -07:00
Родитель 4f17dc56da
Коммит 294399b3fb
3 изменённых файлов: 170 добавлений и 148 удалений

Просмотреть файл

@ -4,6 +4,14 @@
"use strict"; "use strict";
/**
* This file contains most of the logic required to maintain the
* extensions database, including querying and modifying extension
* metadata. In general, we try to avoid loading it during startup when
* at all possible. Please keep that in mind when deciding whether to
* add code here or elsewhere.
*/
/* eslint "valid-jsdoc": [2, {requireReturn: false, requireReturnDescription: false, prefer: {return: "returns"}}] */ /* eslint "valid-jsdoc": [2, {requireReturn: false, requireReturnDescription: false, prefer: {return: "returns"}}] */
var EXPORTED_SYMBOLS = ["AddonInternal", "XPIDatabase", "XPIDatabaseReconcile"]; var EXPORTED_SYMBOLS = ["AddonInternal", "XPIDatabase", "XPIDatabaseReconcile"];
@ -472,7 +480,7 @@ AddonInternal.prototype = {
} }
if (this.inDatabase && updateDatabase) { if (this.inDatabase && updateDatabase) {
XPIProvider.updateAddonDisabledState(this, userDisabled, softDisabled); XPIDatabase.updateAddonDisabledState(this, userDisabled, softDisabled);
XPIDatabase.saveChanges(); XPIDatabase.saveChanges();
} else { } else {
this.appDisabled = !XPIDatabase.isUsableAddon(this); this.appDisabled = !XPIDatabase.isUsableAddon(this);
@ -888,7 +896,7 @@ AddonWrapper.prototype = {
if (this.hidden) { if (this.hidden) {
throw new Error(`Cannot disable hidden add-on ${addon.id}`); throw new Error(`Cannot disable hidden add-on ${addon.id}`);
} }
XPIProvider.updateAddonDisabledState(addon, val); XPIDatabase.updateAddonDisabledState(addon, val);
} else { } else {
addon.userDisabled = val; addon.userDisabled = val;
// When enabling remove the softDisabled flag // When enabling remove the softDisabled flag
@ -908,9 +916,9 @@ AddonWrapper.prototype = {
// When softDisabling a theme just enable the active theme // When softDisabling a theme just enable the active theme
if (isTheme(addon.type) && val && !addon.userDisabled) { if (isTheme(addon.type) && val && !addon.userDisabled) {
if (isWebExtension(addon.type)) if (isWebExtension(addon.type))
XPIProvider.updateAddonDisabledState(addon, undefined, val); XPIDatabase.updateAddonDisabledState(addon, undefined, val);
} else { } else {
XPIProvider.updateAddonDisabledState(addon, undefined, val); XPIDatabase.updateAddonDisabledState(addon, undefined, val);
} }
} else if (!addon.userDisabled) { } else if (!addon.userDisabled) {
// Only set softDisabled if not already disabled // Only set softDisabled if not already disabled
@ -1028,9 +1036,9 @@ AddonWrapper.prototype = {
if (!this.temporarilyInstalled) { if (!this.temporarilyInstalled) {
let addonFile = addon.getResourceURI; let addonFile = addon.getResourceURI;
XPIProvider.updateAddonDisabledState(addon, true); XPIDatabase.updateAddonDisabledState(addon, true);
Services.obs.notifyObservers(addonFile, "flush-cache-entry"); Services.obs.notifyObservers(addonFile, "flush-cache-entry");
XPIProvider.updateAddonDisabledState(addon, false); XPIDatabase.updateAddonDisabledState(addon, false);
resolve(); resolve();
} else { } else {
// This function supports re-installing an existing add-on. // This function supports re-installing an existing add-on.
@ -1253,7 +1261,7 @@ Object.assign(DBAddonInternal.prototype, {
}); });
if (wasCompatible != this.isCompatible) if (wasCompatible != this.isCompatible)
XPIProvider.updateAddonDisabledState(this); XPIDatabase.updateAddonDisabledState(this);
}, },
toJSON() { toJSON() {
@ -2211,6 +2219,141 @@ this.XPIDatabase = {
} }
}, },
/**
* Updates the disabled state for an add-on. Its appDisabled property will be
* calculated and if the add-on is changed the database will be saved and
* appropriate notifications will be sent out to the registered AddonListeners.
*
* @param {DBAddonInternal} aAddon
* The DBAddonInternal to update
* @param {boolean?} [aUserDisabled]
* Value for the userDisabled property. If undefined the value will
* not change
* @param {boolean?} [aSoftDisabled]
* Value for the softDisabled property. If undefined the value will
* not change. If true this will force userDisabled to be true
* @param {boolean?} [aBecauseSelecting]
* True if we're disabling this add-on because we're selecting
* another.
* @returns {boolean?}
* A tri-state indicating the action taken for the add-on:
* - undefined: The add-on did not change state
* - true: The add-on because disabled
* - false: The add-on became enabled
* @throws if addon is not a DBAddonInternal
*/
updateAddonDisabledState(aAddon, aUserDisabled, aSoftDisabled, aBecauseSelecting) {
if (!(aAddon.inDatabase))
throw new Error("Can only update addon states for installed addons.");
if (aUserDisabled !== undefined && aSoftDisabled !== undefined) {
throw new Error("Cannot change userDisabled and softDisabled at the " +
"same time");
}
if (aUserDisabled === undefined) {
aUserDisabled = aAddon.userDisabled;
} else if (!aUserDisabled) {
// If enabling the add-on then remove softDisabled
aSoftDisabled = false;
}
// If not changing softDisabled or the add-on is already userDisabled then
// use the existing value for softDisabled
if (aSoftDisabled === undefined || aUserDisabled)
aSoftDisabled = aAddon.softDisabled;
let appDisabled = !this.isUsableAddon(aAddon);
// No change means nothing to do here
if (aAddon.userDisabled == aUserDisabled &&
aAddon.appDisabled == appDisabled &&
aAddon.softDisabled == aSoftDisabled)
return undefined;
let wasDisabled = aAddon.disabled;
let isDisabled = aUserDisabled || aSoftDisabled || appDisabled;
// If appDisabled changes but addon.disabled doesn't,
// no onDisabling/onEnabling is sent - so send a onPropertyChanged.
let appDisabledChanged = aAddon.appDisabled != appDisabled;
// Update the properties in the database.
this.setAddonProperties(aAddon, {
userDisabled: aUserDisabled,
appDisabled,
softDisabled: aSoftDisabled
});
let wrapper = aAddon.wrapper;
if (appDisabledChanged) {
AddonManagerPrivate.callAddonListeners("onPropertyChanged",
wrapper,
["appDisabled"]);
}
// If the add-on is not visible or the add-on is not changing state then
// there is no need to do anything else
if (!aAddon.visible || (wasDisabled == isDisabled))
return undefined;
// Flag that active states in the database need to be updated on shutdown
Services.prefs.setBoolPref(PREF_PENDING_OPERATIONS, true);
// Sync with XPIStates.
let xpiState = XPIStates.getAddon(aAddon.location, aAddon.id);
if (xpiState) {
xpiState.syncWithDB(aAddon);
XPIStates.save();
} else {
// There should always be an xpiState
logger.warn("No XPIState for ${id} in ${location}", aAddon);
}
// Have we just gone back to the current state?
if (isDisabled != aAddon.active) {
AddonManagerPrivate.callAddonListeners("onOperationCancelled", wrapper);
} else {
if (isDisabled) {
AddonManagerPrivate.callAddonListeners("onDisabling", wrapper, false);
} else {
AddonManagerPrivate.callAddonListeners("onEnabling", wrapper, false);
}
this.updateAddonActive(aAddon, !isDisabled);
if (isDisabled) {
if (aAddon.bootstrap && XPIProvider.activeAddons.has(aAddon.id)) {
XPIProvider.callBootstrapMethod(aAddon, aAddon._sourceBundle, "shutdown",
BOOTSTRAP_REASONS.ADDON_DISABLE);
XPIProvider.unloadBootstrapScope(aAddon.id);
}
AddonManagerPrivate.callAddonListeners("onDisabled", wrapper);
} else {
if (aAddon.bootstrap) {
XPIProvider.callBootstrapMethod(aAddon, aAddon._sourceBundle, "startup",
BOOTSTRAP_REASONS.ADDON_ENABLE);
}
AddonManagerPrivate.callAddonListeners("onEnabled", wrapper);
}
}
// Notify any other providers that a new theme has been enabled
if (isTheme(aAddon.type)) {
if (!isDisabled) {
AddonManagerPrivate.notifyAddonChanged(aAddon.id, aAddon.type);
if (xpiState) {
xpiState.syncWithDB(aAddon);
XPIStates.save();
}
} else if (isDisabled && !aBecauseSelecting) {
AddonManagerPrivate.notifyAddonChanged(null, "theme");
}
}
return isDisabled;
},
/** /**
* Record a bit of per-addon telemetry. * Record a bit of per-addon telemetry.
* *

Просмотреть файл

@ -4,6 +4,13 @@
"use strict"; "use strict";
/**
* This file contains most of the logic required to install extensions.
* In general, we try to avoid loading it until extension installation
* or update is required. Please keep that in mind when deciding whether
* to add code here or elsewhere.
*/
/* eslint "valid-jsdoc": [2, {requireReturn: false, requireReturnDescription: false, prefer: {return: "returns"}}] */ /* eslint "valid-jsdoc": [2, {requireReturn: false, requireReturnDescription: false, prefer: {return: "returns"}}] */
var EXPORTED_SYMBOLS = [ var EXPORTED_SYMBOLS = [

Просмотреть файл

@ -4,6 +4,13 @@
"use strict"; "use strict";
/**
* This file contains most of the logic required to load and run
* extensions at startup. Anything which is not required immediately at
* startup should go in XPIInstall.jsm or XPIDatabase.jsm if at all
* possible, in order to minimize the impact on startup performance.
*/
/* eslint "valid-jsdoc": [2, {requireReturn: false, requireReturnDescription: false, prefer: {return: "returns"}}] */ /* eslint "valid-jsdoc": [2, {requireReturn: false, requireReturnDescription: false, prefer: {return: "returns"}}] */
var EXPORTED_SYMBOLS = ["XPIProvider", "XPIInternal"]; var EXPORTED_SYMBOLS = ["XPIProvider", "XPIInternal"];
@ -1977,7 +1984,7 @@ var XPIProvider = {
["signedState"]); ["signedState"]);
} }
let disabled = XPIProvider.updateAddonDisabledState(addon); let disabled = XPIDatabase.updateAddonDisabledState(addon);
if (disabled !== undefined) if (disabled !== undefined)
changes[disabled ? "disabled" : "enabled"].push(addon.id); changes[disabled ? "disabled" : "enabled"].push(addon.id);
} }
@ -2567,7 +2574,7 @@ var XPIProvider = {
let addons = XPIDatabase.getAddonsByType("webextension-theme"); let addons = XPIDatabase.getAddonsByType("webextension-theme");
for (let theme of addons) { for (let theme of addons) {
if (theme.visible && theme.id != aId) if (theme.visible && theme.id != aId)
this.updateAddonDisabledState(theme, true, undefined, true); XPIDatabase.updateAddonDisabledState(theme, true, undefined, true);
} }
if (!aId && (!LightweightThemeManager.currentTheme || if (!aId && (!LightweightThemeManager.currentTheme ||
@ -2587,7 +2594,7 @@ var XPIProvider = {
updateAddonAppDisabledStates() { updateAddonAppDisabledStates() {
let addons = XPIDatabase.getAddons(); let addons = XPIDatabase.getAddons();
for (let addon of addons) { for (let addon of addons) {
this.updateAddonDisabledState(addon); XPIDatabase.updateAddonDisabledState(addon);
} }
}, },
@ -2603,7 +2610,7 @@ var XPIProvider = {
if (aRepoAddon || AddonRepository.getCompatibilityOverridesSync(addon.id)) { if (aRepoAddon || AddonRepository.getCompatibilityOverridesSync(addon.id)) {
logger.debug("updateAddonRepositoryData got info for " + addon.id); logger.debug("updateAddonRepositoryData got info for " + addon.id);
addon._repositoryAddon = aRepoAddon; addon._repositoryAddon = aRepoAddon;
this.updateAddonDisabledState(addon); XPIDatabase.updateAddonDisabledState(addon);
} }
}))); })));
}, },
@ -2828,7 +2835,7 @@ var XPIProvider = {
activeAddon.disable = true; activeAddon.disable = true;
for (let addon of this.getDependentAddons(aAddon)) { for (let addon of this.getDependentAddons(aAddon)) {
if (addon.active) if (addon.active)
this.updateAddonDisabledState(addon); XPIDatabase.updateAddonDisabledState(addon);
} }
} }
} }
@ -2890,7 +2897,7 @@ var XPIProvider = {
// Extensions are automatically initialized in the correct order at startup. // Extensions are automatically initialized in the correct order at startup.
if (aMethod == "startup" && aReason != BOOTSTRAP_REASONS.APP_STARTUP) { if (aMethod == "startup" && aReason != BOOTSTRAP_REASONS.APP_STARTUP) {
for (let addon of this.getDependentAddons(aAddon)) for (let addon of this.getDependentAddons(aAddon))
this.updateAddonDisabledState(addon); XPIDatabase.updateAddonDisabledState(addon);
} }
if (CHROME_TYPES.has(aAddon.type) && aMethod == "shutdown" && aReason != BOOTSTRAP_REASONS.APP_SHUTDOWN) { if (CHROME_TYPES.has(aAddon.type) && aMethod == "shutdown" && aReason != BOOTSTRAP_REASONS.APP_SHUTDOWN) {
@ -2900,141 +2907,6 @@ var XPIProvider = {
this.setTelemetry(aAddon.id, aMethod + "_MS", new Date() - timeStart); this.setTelemetry(aAddon.id, aMethod + "_MS", new Date() - timeStart);
} }
}, },
/**
* Updates the disabled state for an add-on. Its appDisabled property will be
* calculated and if the add-on is changed the database will be saved and
* appropriate notifications will be sent out to the registered AddonListeners.
*
* @param {DBAddonInternal} aAddon
* The DBAddonInternal to update
* @param {boolean?} [aUserDisabled]
* Value for the userDisabled property. If undefined the value will
* not change
* @param {boolean?} [aSoftDisabled]
* Value for the softDisabled property. If undefined the value will
* not change. If true this will force userDisabled to be true
* @param {boolean?} [aBecauseSelecting]
* True if we're disabling this add-on because we're selecting
* another.
* @returns {boolean?}
* A tri-state indicating the action taken for the add-on:
* - undefined: The add-on did not change state
* - true: The add-on because disabled
* - false: The add-on became enabled
* @throws if addon is not a DBAddonInternal
*/
updateAddonDisabledState(aAddon, aUserDisabled, aSoftDisabled, aBecauseSelecting) {
if (!(aAddon.inDatabase))
throw new Error("Can only update addon states for installed addons.");
if (aUserDisabled !== undefined && aSoftDisabled !== undefined) {
throw new Error("Cannot change userDisabled and softDisabled at the " +
"same time");
}
if (aUserDisabled === undefined) {
aUserDisabled = aAddon.userDisabled;
} else if (!aUserDisabled) {
// If enabling the add-on then remove softDisabled
aSoftDisabled = false;
}
// If not changing softDisabled or the add-on is already userDisabled then
// use the existing value for softDisabled
if (aSoftDisabled === undefined || aUserDisabled)
aSoftDisabled = aAddon.softDisabled;
let appDisabled = !XPIDatabase.isUsableAddon(aAddon);
// No change means nothing to do here
if (aAddon.userDisabled == aUserDisabled &&
aAddon.appDisabled == appDisabled &&
aAddon.softDisabled == aSoftDisabled)
return undefined;
let wasDisabled = aAddon.disabled;
let isDisabled = aUserDisabled || aSoftDisabled || appDisabled;
// If appDisabled changes but addon.disabled doesn't,
// no onDisabling/onEnabling is sent - so send a onPropertyChanged.
let appDisabledChanged = aAddon.appDisabled != appDisabled;
// Update the properties in the database.
XPIDatabase.setAddonProperties(aAddon, {
userDisabled: aUserDisabled,
appDisabled,
softDisabled: aSoftDisabled
});
let wrapper = aAddon.wrapper;
if (appDisabledChanged) {
AddonManagerPrivate.callAddonListeners("onPropertyChanged",
wrapper,
["appDisabled"]);
}
// If the add-on is not visible or the add-on is not changing state then
// there is no need to do anything else
if (!aAddon.visible || (wasDisabled == isDisabled))
return undefined;
// Flag that active states in the database need to be updated on shutdown
Services.prefs.setBoolPref(PREF_PENDING_OPERATIONS, true);
// Sync with XPIStates.
let xpiState = XPIStates.getAddon(aAddon.location, aAddon.id);
if (xpiState) {
xpiState.syncWithDB(aAddon);
XPIStates.save();
} else {
// There should always be an xpiState
logger.warn("No XPIState for ${id} in ${location}", aAddon);
}
// Have we just gone back to the current state?
if (isDisabled != aAddon.active) {
AddonManagerPrivate.callAddonListeners("onOperationCancelled", wrapper);
} else {
if (isDisabled) {
AddonManagerPrivate.callAddonListeners("onDisabling", wrapper, false);
} else {
AddonManagerPrivate.callAddonListeners("onEnabling", wrapper, false);
}
XPIDatabase.updateAddonActive(aAddon, !isDisabled);
if (isDisabled) {
if (aAddon.bootstrap && this.activeAddons.has(aAddon.id)) {
this.callBootstrapMethod(aAddon, aAddon._sourceBundle, "shutdown",
BOOTSTRAP_REASONS.ADDON_DISABLE);
this.unloadBootstrapScope(aAddon.id);
}
AddonManagerPrivate.callAddonListeners("onDisabled", wrapper);
} else {
if (aAddon.bootstrap) {
this.callBootstrapMethod(aAddon, aAddon._sourceBundle, "startup",
BOOTSTRAP_REASONS.ADDON_ENABLE);
}
AddonManagerPrivate.callAddonListeners("onEnabled", wrapper);
}
}
// Notify any other providers that a new theme has been enabled
if (isTheme(aAddon.type)) {
if (!isDisabled) {
AddonManagerPrivate.notifyAddonChanged(aAddon.id, aAddon.type);
if (xpiState) {
xpiState.syncWithDB(aAddon);
XPIStates.save();
}
} else if (isDisabled && !aBecauseSelecting) {
AddonManagerPrivate.notifyAddonChanged(null, "theme");
}
}
return isDisabled;
},
}; };
for (let meth of ["cancelUninstallAddon", "getInstallForFile", for (let meth of ["cancelUninstallAddon", "getInstallForFile",