зеркало из https://github.com/mozilla/gecko-dev.git
Backed out 4 changesets (bug 1192921) for b2g desktop Gu hangs
Backed out changeset 1bfa2dead61f (bug 1192921) Backed out changeset f310cab1dd4e (bug 1192921) Backed out changeset c3009691dfe6 (bug 1192921) Backed out changeset d8233b994741 (bug 1192921)
This commit is contained in:
Родитель
eaf07adf5d
Коммит
48457bc69c
|
@ -1646,7 +1646,6 @@ var AddonManagerInternal = {
|
|||
|
||||
if (gStartupComplete)
|
||||
return;
|
||||
logger.debug("Registering startup change '" + aType + "' for " + aID);
|
||||
|
||||
// Ensure that an ID is only listed in one type of change
|
||||
for (let type in this.startupChanges)
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -314,15 +314,13 @@ function DBAddonInternal(aLoaded) {
|
|||
|
||||
this._key = this.location + ":" + this.id;
|
||||
|
||||
if (aLoaded._sourceBundle) {
|
||||
this._sourceBundle = aLoaded._sourceBundle;
|
||||
try {
|
||||
this._sourceBundle = this._installLocation.getLocationForID(this.id);
|
||||
}
|
||||
else if (aLoaded.descriptor) {
|
||||
this._sourceBundle = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsIFile);
|
||||
this._sourceBundle.persistentDescriptor = aLoaded.descriptor;
|
||||
}
|
||||
else {
|
||||
throw new Error("Expected passed argument to contain a descriptor");
|
||||
catch (e) {
|
||||
// An exception will be thrown if the add-on appears in the database but
|
||||
// not on disk. In general this should only happen during startup as
|
||||
// this change is being detected.
|
||||
}
|
||||
|
||||
XPCOMUtils.defineLazyGetter(this, "pendingUpgrade",
|
||||
|
@ -787,7 +785,7 @@ this.XPIDatabase = {
|
|||
if (aRebuildOnError) {
|
||||
logger.warn("Rebuilding add-ons database from installed extensions.");
|
||||
try {
|
||||
XPIDatabaseReconcile.processFileChanges({}, false);
|
||||
XPIProvider.processFileChanges({}, false);
|
||||
}
|
||||
catch (e) {
|
||||
logger.error("Failed to rebuild XPI database from installed extensions", e);
|
||||
|
@ -1086,7 +1084,7 @@ this.XPIDatabase = {
|
|||
})
|
||||
.then(null,
|
||||
error => {
|
||||
logger.error("getAddon failed", error);
|
||||
logger.error("getAddon failed", e);
|
||||
makeSafe(aCallback)(null);
|
||||
});
|
||||
},
|
||||
|
@ -1303,7 +1301,6 @@ this.XPIDatabase = {
|
|||
if ((otherAddon.id == aAddon.id) && (otherAddon._key != aAddon._key)) {
|
||||
logger.debug("Hide addon " + otherAddon._key);
|
||||
otherAddon.visible = false;
|
||||
otherAddon.active = false;
|
||||
}
|
||||
}
|
||||
aAddon.visible = true;
|
||||
|
@ -1491,638 +1488,3 @@ this.XPIDatabase = {
|
|||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
this.XPIDatabaseReconcile = {
|
||||
/**
|
||||
* Returns a map of ID -> add-on. When the same add-on ID exists in multiple
|
||||
* install locations the highest priority location is chosen.
|
||||
*/
|
||||
flattenByID(addonMap, hideLocation) {
|
||||
let map = new Map();
|
||||
|
||||
for (let installLocation of XPIProvider.installLocations) {
|
||||
if (installLocation.name == hideLocation)
|
||||
continue;
|
||||
|
||||
let locationMap = addonMap.get(installLocation.name);
|
||||
if (!locationMap)
|
||||
continue;
|
||||
|
||||
for (let [id, addon] of locationMap) {
|
||||
if (!map.has(id))
|
||||
map.set(id, addon);
|
||||
}
|
||||
}
|
||||
|
||||
return map;
|
||||
},
|
||||
|
||||
/**
|
||||
* Finds the visible add-ons from the map.
|
||||
*/
|
||||
getVisibleAddons(addonMap) {
|
||||
let map = new Map();
|
||||
|
||||
for (let [location, addons] of addonMap) {
|
||||
for (let [id, addon] of addons) {
|
||||
if (!addon.visible)
|
||||
continue;
|
||||
|
||||
if (map.has(id)) {
|
||||
logger.warn("Previous database listed more than one visible add-on with id " + id);
|
||||
continue;
|
||||
}
|
||||
|
||||
map.set(id, addon);
|
||||
}
|
||||
}
|
||||
|
||||
return map;
|
||||
},
|
||||
|
||||
/**
|
||||
* Called to add the metadata for an add-on in one of the install locations
|
||||
* to the database. This can be called in three different cases. Either an
|
||||
* add-on has been dropped into the location from outside of Firefox, or
|
||||
* an add-on has been installed through the application, or the database
|
||||
* has been upgraded or become corrupt and add-on data has to be reloaded
|
||||
* into it.
|
||||
*
|
||||
* @param aInstallLocation
|
||||
* The install location containing the add-on
|
||||
* @param aId
|
||||
* The ID of the add-on
|
||||
* @param aAddonState
|
||||
* The new state of the add-on
|
||||
* @param aNewAddon
|
||||
* The manifest for the new add-on if it has already been loaded
|
||||
* @param aOldAppVersion
|
||||
* The version of the application last run with this profile or null
|
||||
* if it is a new profile or the version is unknown
|
||||
* @param aOldPlatformVersion
|
||||
* The version of the platform last run with this profile or null
|
||||
* if it is a new profile or the version is unknown
|
||||
* @param aMigrateData
|
||||
* If during startup the database had to be upgraded this will
|
||||
* contain data that used to be held about this add-on
|
||||
* @return a boolean indicating if flushing caches is required to complete
|
||||
* changing this add-on
|
||||
*/
|
||||
addMetadata(aInstallLocation, aId, aAddonState, aNewAddon, aOldAppVersion,
|
||||
aOldPlatformVersion, aMigrateData) {
|
||||
logger.debug("New add-on " + aId + " installed in " + aInstallLocation.name);
|
||||
|
||||
// If we had staged data for this add-on or we aren't recovering from a
|
||||
// corrupt database and we don't have migration data for this add-on then
|
||||
// this must be a new install.
|
||||
let isNewInstall = (!!aNewAddon) || (!XPIDatabase.activeBundles && !aMigrateData);
|
||||
|
||||
// If it's a new install and we haven't yet loaded the manifest then it
|
||||
// must be something dropped directly into the install location
|
||||
let isDetectedInstall = isNewInstall && !aNewAddon;
|
||||
|
||||
// Load the manifest if necessary and sanity check the add-on ID
|
||||
try {
|
||||
if (!aNewAddon) {
|
||||
// Load the manifest from the add-on.
|
||||
let file = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsIFile);
|
||||
file.persistentDescriptor = aAddonState.descriptor;
|
||||
aNewAddon = syncLoadManifestFromFile(file);
|
||||
}
|
||||
// The add-on in the manifest should match the add-on ID.
|
||||
if (aNewAddon.id != aId) {
|
||||
throw new Error("Invalid addon ID: expected addon ID " + aId +
|
||||
", found " + aNewAddon.id + " in manifest");
|
||||
}
|
||||
}
|
||||
catch (e) {
|
||||
logger.warn("addMetadata: Add-on " + aId + " is invalid", e);
|
||||
|
||||
// Remove the invalid add-on from the install location if the install
|
||||
// location isn't locked, no restart will be necessary
|
||||
if (!aInstallLocation.locked)
|
||||
aInstallLocation.uninstallAddon(aId);
|
||||
else
|
||||
logger.warn("Could not uninstall invalid item from locked install location");
|
||||
return null;
|
||||
}
|
||||
|
||||
// Update the AddonInternal properties.
|
||||
aNewAddon._installLocation = aInstallLocation;
|
||||
aNewAddon.installDate = aAddonState.mtime;
|
||||
aNewAddon.updateDate = aAddonState.mtime;
|
||||
|
||||
// Assume that add-ons in the system add-ons install location aren't
|
||||
// foreign and should default to enabled.
|
||||
aNewAddon.foreignInstall = isDetectedInstall &&
|
||||
aInstallLocation.name != KEY_APP_SYSTEM_ADDONS &&
|
||||
aInstallLocation.name != KEY_APP_SYSTEM_DEFAULTS;
|
||||
|
||||
// appDisabled depends on whether the add-on is a foreignInstall so update
|
||||
aNewAddon.appDisabled = !isUsableAddon(aNewAddon);
|
||||
|
||||
if (aMigrateData) {
|
||||
// If there is migration data then apply it.
|
||||
logger.debug("Migrating data from old database");
|
||||
|
||||
DB_MIGRATE_METADATA.forEach(function(aProp) {
|
||||
// A theme's disabled state is determined by the selected theme
|
||||
// preference which is read in loadManifestFromRDF
|
||||
if (aProp == "userDisabled" && aNewAddon.type == "theme")
|
||||
return;
|
||||
|
||||
if (aProp in aMigrateData)
|
||||
aNewAddon[aProp] = aMigrateData[aProp];
|
||||
});
|
||||
|
||||
// Force all non-profile add-ons to be foreignInstalls since they can't
|
||||
// have been installed through the API
|
||||
aNewAddon.foreignInstall |= aInstallLocation.name != KEY_APP_PROFILE;
|
||||
|
||||
// Some properties should only be migrated if the add-on hasn't changed.
|
||||
// The version property isn't a perfect check for this but covers the
|
||||
// vast majority of cases.
|
||||
if (aMigrateData.version == aNewAddon.version) {
|
||||
logger.debug("Migrating compatibility info");
|
||||
if ("targetApplications" in aMigrateData)
|
||||
aNewAddon.applyCompatibilityUpdate(aMigrateData, true);
|
||||
}
|
||||
|
||||
// Since the DB schema has changed make sure softDisabled is correct
|
||||
applyBlocklistChanges(aNewAddon, aNewAddon, aOldAppVersion,
|
||||
aOldPlatformVersion);
|
||||
}
|
||||
|
||||
// The default theme is never a foreign install
|
||||
if (aNewAddon.type == "theme" && aNewAddon.internalName == XPIProvider.defaultSkin)
|
||||
aNewAddon.foreignInstall = false;
|
||||
|
||||
if (isDetectedInstall && aNewAddon.foreignInstall) {
|
||||
// If the add-on is a foreign install and is in a scope where add-ons
|
||||
// that were dropped in should default to disabled then disable it
|
||||
let disablingScopes = Preferences.get(PREF_EM_AUTO_DISABLED_SCOPES, 0);
|
||||
if (aInstallLocation.scope & disablingScopes) {
|
||||
logger.warn("Disabling foreign installed add-on " + aNewAddon.id + " in "
|
||||
+ aInstallLocation.name);
|
||||
aNewAddon.userDisabled = true;
|
||||
}
|
||||
}
|
||||
|
||||
return XPIDatabase.addAddonMetadata(aNewAddon, aAddonState.descriptor);
|
||||
},
|
||||
|
||||
/**
|
||||
* Called when an add-on has been removed.
|
||||
*
|
||||
* @param aOldAddon
|
||||
* The AddonInternal as it appeared the last time the application
|
||||
* ran
|
||||
* @return a boolean indicating if flushing caches is required to complete
|
||||
* changing this add-on
|
||||
*/
|
||||
removeMetadata(aOldAddon) {
|
||||
// This add-on has disappeared
|
||||
logger.debug("Add-on " + aOldAddon.id + " removed from " + aOldAddon.location);
|
||||
XPIDatabase.removeAddonMetadata(aOldAddon);
|
||||
},
|
||||
|
||||
/**
|
||||
* Updates an add-on's metadata and determines if a restart of the
|
||||
* application is necessary. This is called when either the add-on's
|
||||
* install directory path or last modified time has changed.
|
||||
*
|
||||
* @param aInstallLocation
|
||||
* The install location containing the add-on
|
||||
* @param aOldAddon
|
||||
* The AddonInternal as it appeared the last time the application
|
||||
* ran
|
||||
* @param aAddonState
|
||||
* The new state of the add-on
|
||||
* @param aNewAddon
|
||||
* The manifest for the new add-on if it has already been loaded
|
||||
* @return a boolean indicating if flushing caches is required to complete
|
||||
* changing this add-on
|
||||
*/
|
||||
updateMetadata(aInstallLocation, aOldAddon, aAddonState, aNewAddon) {
|
||||
logger.debug("Add-on " + aOldAddon.id + " modified in " + aInstallLocation.name);
|
||||
|
||||
try {
|
||||
// If there isn't an updated install manifest for this add-on then load it.
|
||||
if (!aNewAddon) {
|
||||
let file = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsIFile);
|
||||
file.persistentDescriptor = aAddonState.descriptor;
|
||||
aNewAddon = syncLoadManifestFromFile(file);
|
||||
applyBlocklistChanges(aOldAddon, aNewAddon);
|
||||
|
||||
// Carry over any pendingUninstall state to add-ons modified directly
|
||||
// in the profile. This is important when the attempt to remove the
|
||||
// add-on in processPendingFileChanges failed and caused an mtime
|
||||
// change to the add-ons files.
|
||||
aNewAddon.pendingUninstall = aOldAddon.pendingUninstall;
|
||||
}
|
||||
|
||||
// The ID in the manifest that was loaded must match the ID of the old
|
||||
// add-on.
|
||||
if (aNewAddon.id != aOldAddon.id)
|
||||
throw new Error("Incorrect id in install manifest for existing add-on " + aOldAddon.id);
|
||||
}
|
||||
catch (e) {
|
||||
logger.warn("updateMetadata: Add-on " + aOldAddon.id + " is invalid", e);
|
||||
XPIDatabase.removeAddonMetadata(aOldAddon);
|
||||
XPIStates.removeAddon(aOldAddon.location, aOldAddon.id);
|
||||
if (!aInstallLocation.locked)
|
||||
aInstallLocation.uninstallAddon(aOldAddon.id);
|
||||
else
|
||||
logger.warn("Could not uninstall invalid item from locked install location");
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
// Set the additional properties on the new AddonInternal
|
||||
aNewAddon._installLocation = aInstallLocation;
|
||||
aNewAddon.updateDate = aAddonState.mtime;
|
||||
|
||||
// Update the database
|
||||
return XPIDatabase.updateAddonMetadata(aOldAddon, aNewAddon, aAddonState.descriptor);
|
||||
},
|
||||
|
||||
/**
|
||||
* Updates an add-on's descriptor for when the add-on has moved in the
|
||||
* filesystem but hasn't changed in any other way.
|
||||
*
|
||||
* @param aInstallLocation
|
||||
* The install location containing the add-on
|
||||
* @param aOldAddon
|
||||
* The AddonInternal as it appeared the last time the application
|
||||
* ran
|
||||
* @param aAddonState
|
||||
* The new state of the add-on
|
||||
* @return a boolean indicating if flushing caches is required to complete
|
||||
* changing this add-on
|
||||
*/
|
||||
updateDescriptor(aInstallLocation, aOldAddon, aAddonState) {
|
||||
logger.debug("Add-on " + aOldAddon.id + " moved to " + aAddonState.descriptor);
|
||||
aOldAddon.descriptor = aAddonState.descriptor;
|
||||
aOldAddon._sourceBundle.persistentDescriptor = aAddonState.descriptor;
|
||||
|
||||
return aOldAddon;
|
||||
},
|
||||
|
||||
/**
|
||||
* Called when no change has been detected for an add-on's metadata but the
|
||||
* application has changed so compatibility may have changed.
|
||||
*
|
||||
* @param aInstallLocation
|
||||
* The install location containing the add-on
|
||||
* @param aOldAddon
|
||||
* The AddonInternal as it appeared the last time the application
|
||||
* ran
|
||||
* @param aAddonState
|
||||
* The new state of the add-on
|
||||
* @param aOldAppVersion
|
||||
* The version of the application last run with this profile or null
|
||||
* if it is a new profile or the version is unknown
|
||||
* @param aOldPlatformVersion
|
||||
* The version of the platform last run with this profile or null
|
||||
* if it is a new profile or the version is unknown
|
||||
* @return a boolean indicating if flushing caches is required to complete
|
||||
* changing this add-on
|
||||
*/
|
||||
updateCompatibility(aInstallLocation, aOldAddon, aAddonState, aOldAppVersion, aOldPlatformVersion) {
|
||||
logger.debug("Updating compatibility for add-on " + aOldAddon.id + " in " + aInstallLocation.name);
|
||||
|
||||
// If updating from a version of the app that didn't support signedState
|
||||
// then fetch that property now
|
||||
if (aOldAddon.signedState === undefined && ADDON_SIGNING &&
|
||||
SIGNED_TYPES.has(aOldAddon.type)) {
|
||||
let file = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsIFile);
|
||||
file.persistentDescriptor = aAddonState.descriptor;
|
||||
let manifest = syncLoadManifestFromFile(file);
|
||||
aOldAddon.signedState = manifest.signedState;
|
||||
}
|
||||
// This updates the addon's JSON cached data in place
|
||||
applyBlocklistChanges(aOldAddon, aOldAddon, aOldAppVersion,
|
||||
aOldPlatformVersion);
|
||||
aOldAddon.appDisabled = !isUsableAddon(aOldAddon);
|
||||
|
||||
return aOldAddon;
|
||||
},
|
||||
|
||||
/**
|
||||
* Compares the add-ons that are currently installed to those that were
|
||||
* known to be installed when the application last ran and applies any
|
||||
* changes found to the database. Also sends "startupcache-invalidate" signal to
|
||||
* observerservice if it detects that data may have changed.
|
||||
* Always called after XPIProviderUtils.js and extensions.json have been loaded.
|
||||
*
|
||||
* @param aManifests
|
||||
* A dictionary of cached AddonInstalls for add-ons that have been
|
||||
* installed
|
||||
* @param aUpdateCompatibility
|
||||
* true to update add-ons appDisabled property when the application
|
||||
* version has changed
|
||||
* @param aOldAppVersion
|
||||
* The version of the application last run with this profile or null
|
||||
* if it is a new profile or the version is unknown
|
||||
* @param aOldPlatformVersion
|
||||
* The version of the platform last run with this profile or null
|
||||
* if it is a new profile or the version is unknown
|
||||
* @return a boolean indicating if a change requiring flushing the caches was
|
||||
* detected
|
||||
*/
|
||||
processFileChanges(aManifests, aUpdateCompatibility, aOldAppVersion, aOldPlatformVersion) {
|
||||
let loadedManifest = (aInstallLocation, aId) => {
|
||||
if (!(aInstallLocation.name in aManifests))
|
||||
return null;
|
||||
if (!(aId in aManifests[aInstallLocation.name]))
|
||||
return null;
|
||||
return aManifests[aInstallLocation.name][aId];
|
||||
};
|
||||
|
||||
// Get the previous add-ons from the database and put them into maps by location
|
||||
let previousAddons = new Map();
|
||||
for (let a of XPIDatabase.getAddons()) {
|
||||
let locationAddonMap = previousAddons.get(a.location);
|
||||
if (!locationAddonMap) {
|
||||
locationAddonMap = new Map();
|
||||
previousAddons.set(a.location, locationAddonMap);
|
||||
}
|
||||
locationAddonMap.set(a.id, a);
|
||||
}
|
||||
|
||||
// Build the list of current add-ons into similar maps. When add-ons are still
|
||||
// present we re-use the add-on objects from the database and update their
|
||||
// details directly
|
||||
let currentAddons = new Map();
|
||||
for (let installLocation of XPIProvider.installLocations) {
|
||||
let locationAddonMap = new Map();
|
||||
currentAddons.set(installLocation.name, locationAddonMap);
|
||||
|
||||
// Get all the on-disk XPI states for this location, and keep track of which
|
||||
// ones we see in the database.
|
||||
let states = XPIStates.getLocation(installLocation.name);
|
||||
|
||||
// Iterate through the add-ons installed the last time the application
|
||||
// ran
|
||||
let dbAddons = previousAddons.get(installLocation.name);
|
||||
if (dbAddons) {
|
||||
for (let [id, oldAddon] of dbAddons) {
|
||||
// Check if the add-on is still installed
|
||||
let xpiState = states && states.get(id);
|
||||
if (xpiState) {
|
||||
// Here the add-on was present in the database and on disk
|
||||
recordAddonTelemetry(oldAddon);
|
||||
|
||||
// Check if the add-on has been changed outside the XPI provider
|
||||
if (oldAddon.updateDate != xpiState.mtime) {
|
||||
// Did time change in the wrong direction?
|
||||
if (xpiState.mtime < oldAddon.updateDate) {
|
||||
XPIProvider.setTelemetry(oldAddon.id, "olderFile", {
|
||||
name: XPIProvider._mostRecentlyModifiedFile[id],
|
||||
mtime: xpiState.mtime,
|
||||
oldtime: oldAddon.updateDate
|
||||
});
|
||||
} else {
|
||||
XPIProvider.setTelemetry(oldAddon.id, "modifiedFile",
|
||||
XPIProvider._mostRecentlyModifiedFile[id]);
|
||||
}
|
||||
}
|
||||
|
||||
// The add-on has changed if the modification time has changed, or
|
||||
// we have an updated manifest for it. Also reload the metadata for
|
||||
// add-ons in the application directory when the application version
|
||||
// has changed
|
||||
let newAddon = loadedManifest(installLocation, id);
|
||||
if (newAddon || oldAddon.updateDate != xpiState.mtime ||
|
||||
(aUpdateCompatibility && (installLocation.name == KEY_APP_GLOBAL ||
|
||||
installLocation.name == KEY_APP_SYSTEM_DEFAULTS))) {
|
||||
newAddon = this.updateMetadata(installLocation, oldAddon, xpiState, newAddon);
|
||||
}
|
||||
else if (oldAddon.descriptor != xpiState.descriptor) {
|
||||
newAddon = this.updateDescriptor(installLocation, oldAddon, xpiState);
|
||||
}
|
||||
else if (aUpdateCompatibility) {
|
||||
newAddon = this.updateCompatibility(installLocation, oldAddon, xpiState,
|
||||
aOldAppVersion, aOldPlatformVersion);
|
||||
}
|
||||
else {
|
||||
// No change
|
||||
newAddon = oldAddon;
|
||||
}
|
||||
|
||||
if (newAddon)
|
||||
locationAddonMap.set(newAddon.id, newAddon);
|
||||
}
|
||||
else {
|
||||
// The add-on is in the DB, but not in xpiState (and thus not on disk).
|
||||
this.removeMetadata(oldAddon);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Any add-on in our current location that we haven't seen needs to
|
||||
// be added to the database.
|
||||
// Get the migration data for this install location so we can include that as
|
||||
// we add, in case this is a database upgrade or rebuild.
|
||||
let locMigrateData = {};
|
||||
if (XPIDatabase.migrateData && installLocation.name in XPIDatabase.migrateData)
|
||||
locMigrateData = XPIDatabase.migrateData[installLocation.name];
|
||||
|
||||
if (states) {
|
||||
for (let [id, xpiState] of states) {
|
||||
if (locationAddonMap.has(id))
|
||||
continue;
|
||||
let migrateData = id in locMigrateData ? locMigrateData[id] : null;
|
||||
let newAddon = loadedManifest(installLocation, id);
|
||||
let addon = this.addMetadata(installLocation, id, xpiState, newAddon,
|
||||
aOldAppVersion, aOldPlatformVersion, migrateData);
|
||||
if (addon)
|
||||
locationAddonMap.set(addon.id, addon);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// previousAddons may contain locations where the database contains add-ons
|
||||
// but the browser is no longer configured to use that location. The metadata
|
||||
// for those add-ons must be removed from the database.
|
||||
for (let [locationName, addons] of previousAddons) {
|
||||
if (!currentAddons.has(locationName)) {
|
||||
for (let [id, oldAddon] of addons)
|
||||
this.removeMetadata(oldAddon);
|
||||
}
|
||||
}
|
||||
|
||||
// Validate the updated system add-ons
|
||||
let systemAddonLocation = XPIProvider.installLocationsByName[KEY_APP_SYSTEM_ADDONS];
|
||||
let addons = currentAddons.get(KEY_APP_SYSTEM_ADDONS) || new Map();
|
||||
|
||||
let hideLocation;
|
||||
if (systemAddonLocation.isActive() && systemAddonLocation.isValid(addons)) {
|
||||
// Hide the system add-on defaults
|
||||
logger.info("Hiding the default system add-ons.");
|
||||
hideLocation = KEY_APP_SYSTEM_DEFAULTS;
|
||||
}
|
||||
else {
|
||||
// Hide the system add-on updates
|
||||
logger.info("Hiding the updated system add-ons.");
|
||||
hideLocation = KEY_APP_SYSTEM_ADDONS;
|
||||
}
|
||||
|
||||
let previousVisible = this.getVisibleAddons(previousAddons);
|
||||
let currentVisible = this.flattenByID(currentAddons, hideLocation);
|
||||
let sawActiveTheme = false;
|
||||
XPIProvider.bootstrappedAddons = {};
|
||||
|
||||
// Pass over the new set of visible add-ons, record any changes that occured
|
||||
// during startup and call bootstrap install/uninstall scripts as necessary
|
||||
for (let [id, currentAddon] of currentVisible) {
|
||||
let previousAddon = previousVisible.get(id);
|
||||
|
||||
// Note if any visible add-on is not in the application install location
|
||||
if (currentAddon._installLocation.name != KEY_APP_GLOBAL)
|
||||
XPIProvider.allAppGlobal = false;
|
||||
|
||||
let isActive = !currentAddon.disabled;
|
||||
let wasActive = previousAddon ? previousAddon.active : currentAddon.active
|
||||
|
||||
if (!previousAddon) {
|
||||
// If we had a manifest for this add-on it was a staged install and
|
||||
// so wasn't something recovered from a corrupt database
|
||||
let wasStaged = !!loadedManifest(currentAddon._installLocation, id);
|
||||
|
||||
// We might be recovering from a corrupt database, if so use the
|
||||
// list of known active add-ons to update the new add-on
|
||||
if (!wasStaged && XPIDatabase.activeBundles) {
|
||||
// For themes we know which is active by the current skin setting
|
||||
if (currentAddon.type == "theme")
|
||||
isActive = currentAddon.internalName == XPIProvider.currentSkin;
|
||||
else
|
||||
isActive = XPIDatabase.activeBundles.indexOf(currentAddon.descriptor) != -1;
|
||||
|
||||
// If the add-on wasn't active and it isn't already disabled in some way
|
||||
// then it was probably either softDisabled or userDisabled
|
||||
if (!isActive && !currentAddon.disabled) {
|
||||
// If the add-on is softblocked then assume it is softDisabled
|
||||
if (currentAddon.blocklistState == Blocklist.STATE_SOFTBLOCKED)
|
||||
currentAddon.softDisabled = true;
|
||||
else
|
||||
currentAddon.userDisabled = true;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// This is a new install
|
||||
if (currentAddon.foreignInstall)
|
||||
AddonManagerPrivate.addStartupChange(AddonManager.STARTUP_CHANGE_INSTALLED, id);
|
||||
|
||||
if (currentAddon.bootstrap) {
|
||||
// Visible bootstrapped add-ons need to have their install method called
|
||||
XPIProvider.callBootstrapMethod(currentAddon, currentAddon._sourceBundle,
|
||||
"install", BOOTSTRAP_REASONS.ADDON_INSTALL);
|
||||
if (!isActive)
|
||||
XPIProvider.unloadBootstrapScope(currentAddon.id);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (previousAddon !== currentAddon) {
|
||||
// This is an add-on that has changed, either the metadata was reloaded
|
||||
// or the version in a different location has become visible
|
||||
AddonManagerPrivate.addStartupChange(AddonManager.STARTUP_CHANGE_CHANGED, id);
|
||||
|
||||
let installReason = Services.vc.compare(previousAddon.version, currentAddon.version) < 0 ?
|
||||
BOOTSTRAP_REASONS.ADDON_UPGRADE :
|
||||
BOOTSTRAP_REASONS.ADDON_DOWNGRADE;
|
||||
|
||||
// If the previous add-on was in a different location, bootstrapped
|
||||
// and still exists then call its uninstall method.
|
||||
if (previousAddon.bootstrap && previousAddon._installLocation &&
|
||||
currentAddon._installLocation != previousAddon._installLocation &&
|
||||
previousAddon._sourceBundle.exists()) {
|
||||
|
||||
XPIProvider.callBootstrapMethod(previousAddon, previousAddon._sourceBundle,
|
||||
"uninstall", installReason,
|
||||
{ newVersion: currentAddon.version });
|
||||
XPIProvider.unloadBootstrapScope(previousAddon.id);
|
||||
}
|
||||
|
||||
// Make sure to flush the cache when an old add-on has gone away
|
||||
flushStartupCache();
|
||||
|
||||
if (currentAddon.bootstrap) {
|
||||
// Visible bootstrapped add-ons need to have their install method called
|
||||
let file = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsIFile);
|
||||
file.persistentDescriptor = currentAddon._sourceBundle.persistentDescriptor;
|
||||
XPIProvider.callBootstrapMethod(currentAddon, file,
|
||||
"install", installReason,
|
||||
{ oldVersion: previousAddon.version });
|
||||
if (currentAddon.disabled)
|
||||
XPIProvider.unloadBootstrapScope(currentAddon.id);
|
||||
}
|
||||
}
|
||||
|
||||
if (isActive != wasActive) {
|
||||
let change = isActive ? AddonManager.STARTUP_CHANGE_ENABLED
|
||||
: AddonManager.STARTUP_CHANGE_DISABLED;
|
||||
AddonManagerPrivate.addStartupChange(change, id);
|
||||
}
|
||||
}
|
||||
|
||||
XPIDatabase.makeAddonVisible(currentAddon);
|
||||
currentAddon.active = isActive;
|
||||
|
||||
// Make sure the bootstrap information is up to date for this ID
|
||||
if (currentAddon.bootstrap && currentAddon.active) {
|
||||
XPIProvider.bootstrappedAddons[id] = {
|
||||
version: currentAddon.version,
|
||||
type: currentAddon.type,
|
||||
descriptor: currentAddon._sourceBundle.persistentDescriptor,
|
||||
multiprocessCompatible: currentAddon.multiprocessCompatible
|
||||
};
|
||||
}
|
||||
|
||||
if (currentAddon.active && currentAddon.internalName == XPIProvider.selectedSkin)
|
||||
sawActiveTheme = true;
|
||||
}
|
||||
|
||||
// Pass over the set of previously visible add-ons that have now gone away
|
||||
// and record the change.
|
||||
for (let [id, previousAddon] of previousVisible) {
|
||||
if (currentVisible.has(id))
|
||||
continue;
|
||||
|
||||
// This add-on vanished
|
||||
AddonManagerPrivate.addStartupChange(AddonManager.STARTUP_CHANGE_UNINSTALLED, id);
|
||||
}
|
||||
|
||||
// Make sure add-ons from hidden locations are marked invisible and inactive
|
||||
let locationAddonMap = currentAddons.get(hideLocation);
|
||||
if (locationAddonMap) {
|
||||
for (let addon of locationAddonMap.values()) {
|
||||
addon.visible = false;
|
||||
addon.active = false;
|
||||
}
|
||||
}
|
||||
|
||||
// None of the active add-ons match the selected theme, enable the default.
|
||||
if (!sawActiveTheme) {
|
||||
XPIProvider.enableDefaultTheme();
|
||||
}
|
||||
|
||||
// Finally update XPIStates to match everything
|
||||
for (let [locationName, locationAddonMap] of currentAddons) {
|
||||
for (let [id, addon] of locationAddonMap) {
|
||||
let xpiState = XPIStates.getAddon(locationName, id);
|
||||
xpiState.syncWithDB(addon);
|
||||
}
|
||||
}
|
||||
XPIStates.save();
|
||||
|
||||
XPIProvider.persistBootstrappedAddons();
|
||||
|
||||
// Clear out any cached migration data.
|
||||
XPIDatabase.migrateData = null;
|
||||
XPIDatabase.saveChanges();
|
||||
|
||||
return true;
|
||||
},
|
||||
}
|
||||
|
|
Двоичный файл не отображается.
Двоичный файл не отображается.
|
@ -1,18 +0,0 @@
|
|||
Components.utils.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
const ID = "system1@tests.mozilla.org";
|
||||
const VERSION = "1.0";
|
||||
|
||||
function install(data, reason) {
|
||||
}
|
||||
|
||||
function startup(data, reason) {
|
||||
Services.prefs.setCharPref("bootstraptest." + ID + ".active_version", VERSION);
|
||||
}
|
||||
|
||||
function shutdown(data, reason) {
|
||||
Services.prefs.clearUserPref("bootstraptest." + ID + ".active_version");
|
||||
}
|
||||
|
||||
function uninstall(data, reason) {
|
||||
}
|
|
@ -1,23 +0,0 @@
|
|||
<?xml version="1.0"?>
|
||||
|
||||
<RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:em="http://www.mozilla.org/2004/em-rdf#">
|
||||
|
||||
<Description about="urn:mozilla:install-manifest">
|
||||
<em:id>system1@tests.mozilla.org</em:id>
|
||||
<em:version>1.0</em:version>
|
||||
<em:bootstrap>true</em:bootstrap>
|
||||
|
||||
<!-- Front End MetaData -->
|
||||
<em:name>System Add-on 1</em:name>
|
||||
|
||||
<em:targetApplication>
|
||||
<Description>
|
||||
<em:id>xpcshell@tests.mozilla.org</em:id>
|
||||
<em:minVersion>1</em:minVersion>
|
||||
<em:maxVersion>5</em:maxVersion>
|
||||
</Description>
|
||||
</em:targetApplication>
|
||||
|
||||
</Description>
|
||||
</RDF>
|
|
@ -1,18 +0,0 @@
|
|||
Components.utils.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
const ID = "system2@tests.mozilla.org";
|
||||
const VERSION = "1.0";
|
||||
|
||||
function install(data, reason) {
|
||||
}
|
||||
|
||||
function startup(data, reason) {
|
||||
Services.prefs.setCharPref("bootstraptest." + ID + ".active_version", VERSION);
|
||||
}
|
||||
|
||||
function shutdown(data, reason) {
|
||||
Services.prefs.clearUserPref("bootstraptest." + ID + ".active_version");
|
||||
}
|
||||
|
||||
function uninstall(data, reason) {
|
||||
}
|
|
@ -1,23 +0,0 @@
|
|||
<?xml version="1.0"?>
|
||||
|
||||
<RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:em="http://www.mozilla.org/2004/em-rdf#">
|
||||
|
||||
<Description about="urn:mozilla:install-manifest">
|
||||
<em:id>system2@tests.mozilla.org</em:id>
|
||||
<em:version>1.0</em:version>
|
||||
<em:bootstrap>true</em:bootstrap>
|
||||
|
||||
<!-- Front End MetaData -->
|
||||
<em:name>System Add-on 2</em:name>
|
||||
|
||||
<em:targetApplication>
|
||||
<Description>
|
||||
<em:id>xpcshell@tests.mozilla.org</em:id>
|
||||
<em:minVersion>1</em:minVersion>
|
||||
<em:maxVersion>5</em:maxVersion>
|
||||
</Description>
|
||||
</em:targetApplication>
|
||||
|
||||
</Description>
|
||||
</RDF>
|
Двоичный файл не отображается.
Двоичный файл не отображается.
|
@ -1,18 +0,0 @@
|
|||
Components.utils.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
const ID = "system1@tests.mozilla.org";
|
||||
const VERSION = "2.0";
|
||||
|
||||
function install(data, reason) {
|
||||
}
|
||||
|
||||
function startup(data, reason) {
|
||||
Services.prefs.setCharPref("bootstraptest." + ID + ".active_version", VERSION);
|
||||
}
|
||||
|
||||
function shutdown(data, reason) {
|
||||
Services.prefs.clearUserPref("bootstraptest." + ID + ".active_version");
|
||||
}
|
||||
|
||||
function uninstall(data, reason) {
|
||||
}
|
|
@ -1,23 +0,0 @@
|
|||
<?xml version="1.0"?>
|
||||
|
||||
<RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:em="http://www.mozilla.org/2004/em-rdf#">
|
||||
|
||||
<Description about="urn:mozilla:install-manifest">
|
||||
<em:id>system1@tests.mozilla.org</em:id>
|
||||
<em:version>2.0</em:version>
|
||||
<em:bootstrap>true</em:bootstrap>
|
||||
|
||||
<!-- Front End MetaData -->
|
||||
<em:name>System Add-on 1</em:name>
|
||||
|
||||
<em:targetApplication>
|
||||
<Description>
|
||||
<em:id>xpcshell@tests.mozilla.org</em:id>
|
||||
<em:minVersion>1</em:minVersion>
|
||||
<em:maxVersion>5</em:maxVersion>
|
||||
</Description>
|
||||
</em:targetApplication>
|
||||
|
||||
</Description>
|
||||
</RDF>
|
|
@ -1,18 +0,0 @@
|
|||
Components.utils.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
const ID = "system3@tests.mozilla.org";
|
||||
const VERSION = "1.0";
|
||||
|
||||
function install(data, reason) {
|
||||
}
|
||||
|
||||
function startup(data, reason) {
|
||||
Services.prefs.setCharPref("bootstraptest." + ID + ".active_version", VERSION);
|
||||
}
|
||||
|
||||
function shutdown(data, reason) {
|
||||
Services.prefs.clearUserPref("bootstraptest." + ID + ".active_version");
|
||||
}
|
||||
|
||||
function uninstall(data, reason) {
|
||||
}
|
|
@ -1,23 +0,0 @@
|
|||
<?xml version="1.0"?>
|
||||
|
||||
<RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:em="http://www.mozilla.org/2004/em-rdf#">
|
||||
|
||||
<Description about="urn:mozilla:install-manifest">
|
||||
<em:id>system3@tests.mozilla.org</em:id>
|
||||
<em:version>1.0</em:version>
|
||||
<em:bootstrap>true</em:bootstrap>
|
||||
|
||||
<!-- Front End MetaData -->
|
||||
<em:name>System Add-on 3</em:name>
|
||||
|
||||
<em:targetApplication>
|
||||
<Description>
|
||||
<em:id>xpcshell@tests.mozilla.org</em:id>
|
||||
<em:minVersion>1</em:minVersion>
|
||||
<em:maxVersion>5</em:maxVersion>
|
||||
</Description>
|
||||
</em:targetApplication>
|
||||
|
||||
</Description>
|
||||
</RDF>
|
|
@ -1026,7 +1026,7 @@ function getFileForAddon(aDir, aId) {
|
|||
function registerDirectory(aKey, aDir) {
|
||||
var dirProvider = {
|
||||
getFile: function(aProp, aPersistent) {
|
||||
aPersistent.value = false;
|
||||
aPersistent.value = true;
|
||||
if (aProp == aKey)
|
||||
return aDir.clone();
|
||||
return null;
|
||||
|
|
|
@ -1067,8 +1067,9 @@ function run_test_21() {
|
|||
do_check_eq(getUninstallReason(), -1);
|
||||
do_check_eq(getUninstallNewVersion(), -1);
|
||||
|
||||
do_check_eq(getInstallReason(), ADDON_DOWNGRADE);
|
||||
do_check_eq(getInstallOldVersion(), 2);
|
||||
// TODO this reason should probably be ADDON_DOWNGRADE (bug 607818)
|
||||
do_check_eq(getInstallReason(), ADDON_INSTALL);
|
||||
do_check_eq(getInstallOldVersion(), 0);
|
||||
|
||||
do_check_eq(getStartupReason(), APP_STARTUP);
|
||||
do_check_eq(getStartupOldVersion(), 0);
|
||||
|
|
|
@ -1,200 +0,0 @@
|
|||
// Tests that we reset to the default system add-ons correctly when switching
|
||||
// application versions
|
||||
const PREF_SYSTEM_ADDON_SET = "extensions.systemAddonSet";
|
||||
|
||||
const featureDir = gProfD.clone();
|
||||
featureDir.append("features");
|
||||
|
||||
const distroDir = do_get_file("data/system_addons/app0");
|
||||
registerDirectory("XREAppDist", distroDir);
|
||||
|
||||
createAppInfo("xpcshell@tests.mozilla.org", "XPCShell", "0");
|
||||
|
||||
function makeUUID() {
|
||||
let uuidGen = AM_Cc["@mozilla.org/uuid-generator;1"].
|
||||
getService(AM_Ci.nsIUUIDGenerator);
|
||||
return uuidGen.generateUUID().toString();
|
||||
}
|
||||
|
||||
function* check_installed(inProfile, ...versions) {
|
||||
let expectedDir;
|
||||
if (inProfile) {
|
||||
expectedDir = featureDir;
|
||||
}
|
||||
else {
|
||||
expectedDir = distroDir.clone();
|
||||
expectedDir.append("features");
|
||||
}
|
||||
|
||||
for (let i = 0; i < versions.length; i++) {
|
||||
let id = "system" + (i + 1) + "@tests.mozilla.org";
|
||||
let addon = yield promiseAddonByID(id);
|
||||
|
||||
if (versions[i]) {
|
||||
// Add-on should be installed
|
||||
do_check_neq(addon, null);
|
||||
do_check_eq(addon.version, versions[i]);
|
||||
do_check_true(addon.isActive);
|
||||
do_check_false(addon.foreignInstall);
|
||||
|
||||
// Verify the add-ons file is in the right place
|
||||
let file = expectedDir.clone();
|
||||
file.append(id + ".xpi");
|
||||
do_check_true(file.exists());
|
||||
do_check_true(file.isFile());
|
||||
|
||||
let uri = addon.getResourceURI(null);
|
||||
do_check_true(uri instanceof AM_Ci.nsIFileURL);
|
||||
do_check_eq(uri.file.path, file.path);
|
||||
|
||||
// Verify the add-on actually started
|
||||
let installed = Services.prefs.getCharPref("bootstraptest." + id + ".active_version");
|
||||
do_check_eq(installed, versions[i]);
|
||||
}
|
||||
else {
|
||||
// Add-on should not be installed
|
||||
do_check_eq(addon, null);
|
||||
|
||||
try {
|
||||
Services.prefs.getCharPref("bootstraptest." + id + ".active_version");
|
||||
do_throw("Expected pref to be missing");
|
||||
}
|
||||
catch (e) {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Test with a missing features directory
|
||||
add_task(function* test_missing_app_dir() {
|
||||
startupManager();
|
||||
|
||||
yield check_installed(false, null, null, null);
|
||||
|
||||
do_check_false(featureDir.exists());
|
||||
|
||||
yield promiseShutdownManager();
|
||||
});
|
||||
|
||||
// Add some features in a new version
|
||||
add_task(function* test_new_version() {
|
||||
gAppInfo.version = "1";
|
||||
distroDir.leafName = "app1";
|
||||
startupManager();
|
||||
|
||||
yield check_installed(false, "1.0", "1.0", null);
|
||||
|
||||
do_check_false(featureDir.exists());
|
||||
|
||||
yield promiseShutdownManager();
|
||||
});
|
||||
|
||||
// Another new version swaps one feature and upgrades another
|
||||
add_task(function* test_upgrade() {
|
||||
gAppInfo.version = "2";
|
||||
distroDir.leafName = "app2";
|
||||
startupManager();
|
||||
|
||||
yield check_installed(false, "2.0", null, "1.0");
|
||||
|
||||
do_check_false(featureDir.exists());
|
||||
|
||||
yield promiseShutdownManager();
|
||||
});
|
||||
|
||||
// Downgrade
|
||||
add_task(function* test_downgrade() {
|
||||
gAppInfo.version = "1";
|
||||
distroDir.leafName = "app1";
|
||||
startupManager();
|
||||
|
||||
yield check_installed(false, "1.0", "1.0", null);
|
||||
|
||||
do_check_false(featureDir.exists());
|
||||
|
||||
yield promiseShutdownManager();
|
||||
});
|
||||
|
||||
// Fake a mid-cycle install
|
||||
add_task(function* test_updated() {
|
||||
// Create a random dir to install into
|
||||
let dirname = makeUUID();
|
||||
FileUtils.getDir("ProfD", ["features", dirname], true);
|
||||
featureDir.append(dirname);
|
||||
|
||||
// Copy in the system add-ons
|
||||
let file = do_get_file("data/system_addons/app1/features/system2@tests.mozilla.org.xpi");
|
||||
file.copyTo(featureDir, file.leafName);
|
||||
file = do_get_file("data/system_addons/app2/features/system3@tests.mozilla.org.xpi");
|
||||
file.copyTo(featureDir, file.leafName);
|
||||
|
||||
// Inject it into the system set
|
||||
let addonSet = {
|
||||
schema: 1,
|
||||
directory: dirname,
|
||||
addons: {
|
||||
"system2@tests.mozilla.org": {
|
||||
version: "1.0"
|
||||
},
|
||||
"system3@tests.mozilla.org": {
|
||||
version: "1.0"
|
||||
},
|
||||
}
|
||||
};
|
||||
Services.prefs.setCharPref(PREF_SYSTEM_ADDON_SET, JSON.stringify(addonSet));
|
||||
|
||||
startupManager(false);
|
||||
|
||||
yield check_installed(true, null, "1.0", "1.0");
|
||||
|
||||
yield promiseShutdownManager();
|
||||
});
|
||||
|
||||
// An additional add-on in the directory should be ignored
|
||||
add_task(function* test_skips_additional() {
|
||||
// Copy in the system add-ons
|
||||
let file = do_get_file("data/system_addons/app1/features/system1@tests.mozilla.org.xpi");
|
||||
file.copyTo(featureDir, file.leafName);
|
||||
|
||||
startupManager(false);
|
||||
|
||||
yield check_installed(true, null, "1.0", "1.0");
|
||||
|
||||
yield promiseShutdownManager();
|
||||
});
|
||||
|
||||
// Missing add-on should revert to the default set
|
||||
add_task(function* test_revert() {
|
||||
manuallyUninstall(featureDir, "system2@tests.mozilla.org");
|
||||
|
||||
startupManager(false);
|
||||
|
||||
// With system add-on 2 gone the updated set is now invalid so it reverts to
|
||||
// the default set which is system add-ons 1 and 2.
|
||||
yield check_installed(false, "1.0", "1.0", null);
|
||||
|
||||
yield promiseShutdownManager();
|
||||
});
|
||||
|
||||
// Putting it back will make the set work again
|
||||
add_task(function* test_reuse() {
|
||||
let file = do_get_file("data/system_addons/app1/features/system2@tests.mozilla.org.xpi");
|
||||
file.copyTo(featureDir, file.leafName);
|
||||
|
||||
startupManager(false);
|
||||
|
||||
yield check_installed(true, null, "1.0", "1.0");
|
||||
|
||||
yield promiseShutdownManager();
|
||||
});
|
||||
|
||||
// Making the pref corrupt should revert to the default set
|
||||
add_task(function* test_corrupt_pref() {
|
||||
Services.prefs.setCharPref(PREF_SYSTEM_ADDON_SET, "foo");
|
||||
|
||||
startupManager(false);
|
||||
|
||||
yield check_installed(false, "1.0", "1.0", null);
|
||||
|
||||
yield promiseShutdownManager();
|
||||
});
|
|
@ -24,7 +24,6 @@ skip-if = appname != "firefox"
|
|||
[test_provider_unsafe_access_shutdown.js]
|
||||
[test_provider_unsafe_access_startup.js]
|
||||
[test_shutdown.js]
|
||||
[test_system_reset.js]
|
||||
[test_XPIcancel.js]
|
||||
[test_XPIStates.js]
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче