зеркало из https://github.com/mozilla/pjs.git
Bug 555349: Finalize the restartless add-on format. r=robstrong
This commit is contained in:
Родитель
7746c1c7e5
Коммит
ab93423703
|
@ -107,12 +107,22 @@ const PROP_LOCALE_SINGLE = ["name", "description", "creator", "homepageURL"];
|
|||
const PROP_LOCALE_MULTI = ["developers", "translators", "contributors"];
|
||||
const PROP_TARGETAPP = ["id", "minVersion", "maxVersion"];
|
||||
|
||||
const BOOTSTRAP_REASONS = {
|
||||
APP_STARTUP : 1,
|
||||
APP_SHUTDOWN : 2,
|
||||
ADDON_ENABLE : 3,
|
||||
ADDON_DISABLE : 4,
|
||||
ADDON_INSTALL : 5,
|
||||
ADDON_UNINSTALL : 6,
|
||||
ADDON_UPGRADE : 7,
|
||||
ADDON_DOWNGRADE : 8
|
||||
};
|
||||
|
||||
// Map new string type identifiers to old style nsIUpdateItem types
|
||||
const TYPES = {
|
||||
extension: 2,
|
||||
theme: 4,
|
||||
locale: 8,
|
||||
bootstrapped: 64
|
||||
locale: 8
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -393,6 +403,10 @@ function loadManifestFromRDF(aUri, aStream) {
|
|||
addon.aboutURL = null;
|
||||
}
|
||||
|
||||
// Only read the bootstrapped property for extensions
|
||||
if (addon.type == "extension")
|
||||
addon.bootstrap = getRDFProperty(ds, root, "bootstrap") == "true";
|
||||
|
||||
addon.defaultLocale = readLocale(ds, root, true);
|
||||
|
||||
addon.locales = [];
|
||||
|
@ -1191,7 +1205,7 @@ var XPIProvider = {
|
|||
WARN("Could not uninstall invalid item from locked install location");
|
||||
// If this was an active add-on then we must force a restart
|
||||
if (aOldAddon.active) {
|
||||
if (aOldAddon.type == "bootstrapped")
|
||||
if (aOldAddon.bootstrap)
|
||||
delete XPIProvider.bootstrappedAddons[aOldAddon.id];
|
||||
else
|
||||
return true;
|
||||
|
@ -1212,8 +1226,8 @@ var XPIProvider = {
|
|||
// If the old version was active and wasn't bootstrapped or the new
|
||||
// version will be active and isn't bootstrapped then we must force a
|
||||
// restart
|
||||
if ((aOldAddon.active && aOldAddon.type != "bootstrapped") ||
|
||||
(newAddon.active && newAddon.type != "bootstrapped")) {
|
||||
if ((aOldAddon.active && !aOldAddon.bootstrap) ||
|
||||
(newAddon.active && !newAddon.bootstrap)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -1250,7 +1264,7 @@ var XPIProvider = {
|
|||
|
||||
// If the add-on is bootstrappable and it should be active then
|
||||
// mark it as active and add it to the list to be activated.
|
||||
if (aOldAddon.type == "bootstrapped" && !aOldAddon.appDisabled &&
|
||||
if (aOldAddon.bootstrap && !aOldAddon.appDisabled &&
|
||||
!aOldAddon.userDisabled) {
|
||||
aOldAddon.active = true;
|
||||
XPIDatabase.updateAddonActive(aOldAddon);
|
||||
|
@ -1281,7 +1295,7 @@ var XPIProvider = {
|
|||
// If this is a visible add-on and it isn't userDisabled then we
|
||||
// may need a restart or to update the bootstrap list.
|
||||
if (aOldAddon.visible && !aOldAddon.userDisabled) {
|
||||
if (aOldAddon.type == "bootstrapped") {
|
||||
if (aOldAddon.bootstrap) {
|
||||
// When visible and not userDisabled, active is the opposite of
|
||||
// appDisabled.
|
||||
aOldAddon.active = !aOldAddon.appDisabled;
|
||||
|
@ -1330,10 +1344,10 @@ var XPIProvider = {
|
|||
|
||||
// If this was an active add-on and bootstrapped we must remove it from
|
||||
// the bootstrapped list, otherwise we need to force a restart.
|
||||
if (aOldAddon.type != "bootstrapped")
|
||||
if (!aOldAddon.bootstrap)
|
||||
return true;
|
||||
|
||||
delete XPIProvider.bootstrappedAddons[aOldAddon.id];
|
||||
XPIProvider.unloadBootstrapScope(aOldAddon.id);
|
||||
}
|
||||
|
||||
return false;
|
||||
|
@ -1398,16 +1412,17 @@ var XPIProvider = {
|
|||
// Update the database.
|
||||
XPIDatabase.addAddonMetadata(newAddon, aAddonState.descriptor);
|
||||
|
||||
// Visible bootstrapped add-ons need to be added to the bootstrap list.
|
||||
// Visible bootstrapped add-ons need to have their install method called
|
||||
if (newAddon.visible) {
|
||||
visibleAddons[newAddon.id] = newAddon;
|
||||
if (newAddon.type != "bootstrapped")
|
||||
if (!newAddon.bootstrap)
|
||||
return true;
|
||||
|
||||
XPIProvider.bootstrappedAddons[newAddon.id] = {
|
||||
version: newAddon.version,
|
||||
descriptor: aAddonState.descriptor
|
||||
};
|
||||
let dir = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsILocalFile);
|
||||
dir.persistentDescriptor = aAddonState.descriptor;
|
||||
XPIProvider.callBootstrapMethod(newAddon.id, newAddon.version, dir,
|
||||
"install",
|
||||
BOOTSTRAP_REASONS.ADDON_INSTALL);
|
||||
}
|
||||
|
||||
return false;
|
||||
|
@ -1566,12 +1581,11 @@ var XPIProvider = {
|
|||
return true;
|
||||
}
|
||||
|
||||
let bootstrappedAddons = this.bootstrappedAddons;
|
||||
this.bootstrappedAddons = {};
|
||||
for (let id in bootstrappedAddons) {
|
||||
for (let id in this.bootstrappedAddons) {
|
||||
let dir = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsILocalFile);
|
||||
dir.persistentDescriptor = bootstrappedAddons[id].descriptor;
|
||||
this.activateAddon(id, bootstrappedAddons[id].version, dir, true, false);
|
||||
dir.persistentDescriptor = this.bootstrappedAddons[id].descriptor;
|
||||
this.callBootstrapMethod(id, this.bootstrappedAddons[id].version, dir,
|
||||
"startup", BOOTSTRAP_REASONS.APP_STARTUP);
|
||||
}
|
||||
|
||||
// Let these shutdown a little earlier when they still have access to most
|
||||
|
@ -1580,8 +1594,13 @@ var XPIProvider = {
|
|||
observe: function(aSubject, aTopic, aData) {
|
||||
Services.prefs.setCharPref(PREF_BOOTSTRAP_ADDONS,
|
||||
JSON.stringify(XPIProvider.bootstrappedAddons));
|
||||
for (let id in XPIProvider.bootstrappedAddons)
|
||||
XPIProvider.deactivateAddon(id, true, false);
|
||||
for (let id in XPIProvider.bootstrappedAddons) {
|
||||
let dir = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsILocalFile);
|
||||
dir.persistentDescriptor = XPIProvider.bootstrappedAddons[id].descriptor;
|
||||
XPIProvider.callBootstrapMethod(id, XPIProvider.bootstrappedAddons[id].version,
|
||||
dir, "shutdown",
|
||||
BOOTSTRAP_REASONS.APP_SHUTDOWN);
|
||||
}
|
||||
Services.obs.removeObserver(this, "quit-application-granted");
|
||||
}
|
||||
}, "quit-application-granted", false);
|
||||
|
@ -1872,7 +1891,7 @@ var XPIProvider = {
|
|||
return aAddon.internalName !=
|
||||
Prefs.getCharPref(PREF_GENERAL_SKINS_SELECTEDSKIN);
|
||||
|
||||
return aAddon.type != "bootstrapped";
|
||||
return !aAddon.bootstrap;
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -1891,7 +1910,7 @@ var XPIProvider = {
|
|||
return this.selectedSkin !=
|
||||
Prefs.getCharPref(PREF_GENERAL_SKINS_SELECTEDSKIN);
|
||||
|
||||
return aAddon.type != "bootstrapped";
|
||||
return !aAddon.bootstrap;
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -1907,7 +1926,7 @@ var XPIProvider = {
|
|||
return aAddon.internalName ==
|
||||
Prefs.getCharPref(PREF_GENERAL_SKINS_SELECTEDSKIN);
|
||||
|
||||
return aAddon.type != "bootstrapped";
|
||||
return !aAddon.bootstrap;
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -1923,85 +1942,53 @@ var XPIProvider = {
|
|||
return aAddon.internalName ==
|
||||
Prefs.getCharPref(PREF_GENERAL_SKINS_SELECTEDSKIN);
|
||||
|
||||
return aAddon.type != "bootstrapped";
|
||||
return !aAddon.bootstrap;
|
||||
},
|
||||
|
||||
/**
|
||||
* Calls a method in a bootstrap.js loaded scope logging any exceptions thrown.
|
||||
* Loads a bootstrapped add-on's bootstrap.js into a sandbox and the reason
|
||||
* values as constants in the scope. This will also add information about the
|
||||
* add-on to the bootstrappedAddons dictionary and notify the crash reporter
|
||||
* that new add-ons have been loaded.
|
||||
*
|
||||
* @param aId
|
||||
* The ID of the add-on being bootstrapped
|
||||
* @param aScope
|
||||
* The loaded JS scope to call into
|
||||
* @param aMethods
|
||||
* An array of methods. The first method in the array that exists in
|
||||
* the scope will be called
|
||||
*/
|
||||
callBootstrapMethod: function XPI_callBootstrapMethod(aId, aScope, aMethods) {
|
||||
for (let i = 0; i < aMethods.length; i++) {
|
||||
if (aMethods[i] in aScope) {
|
||||
LOG("Calling bootstrap method " + aMethods[i] + " on " + aId);
|
||||
|
||||
try {
|
||||
aScope[aMethods[i]](aId);
|
||||
}
|
||||
catch (e) {
|
||||
WARN("Exception running bootstrap method " + aMethods[i] + " on " +
|
||||
aId + ": " + e);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Activates a bootstrapped add-on by loading its JS scope and calling the
|
||||
* appropriate method on it. Adds the add-on and its scope to the
|
||||
* bootstrapScopes and bootstrappedAddons dictionaries.
|
||||
*
|
||||
* @param aId
|
||||
* The ID of the add-on being activated
|
||||
* @param aVersion
|
||||
* The version of the add-on being activated
|
||||
* The add-on's ID
|
||||
* @param aDir
|
||||
* The directory containing the add-on
|
||||
* @param aStartup
|
||||
* true if the add-on is being activated during startup
|
||||
* @param aInstall
|
||||
* true if the add-on is being activated during installation
|
||||
* The nsILocalFile for the directory containing the add-on
|
||||
* @param aVersion
|
||||
* The add-on's version
|
||||
* @return a JavaScript scope
|
||||
*/
|
||||
activateAddon: function XPI_activateAddon(aId, aVersion, aDir, aStartup, aInstall) {
|
||||
let methods = ["enable"];
|
||||
if (aStartup)
|
||||
methods.unshift("startup");
|
||||
if (aInstall)
|
||||
methods.unshift("install");
|
||||
let bootstrap = aDir.clone();
|
||||
bootstrap.append("bootstrap.js");
|
||||
if (bootstrap.exists()) {
|
||||
let uri = Services.io.newFileURI(bootstrap);
|
||||
let principal = Cc["@mozilla.org/systemprincipal;1"].
|
||||
createInstance(Ci.nsIPrincipal);
|
||||
let scope = new Components.utils.Sandbox(principal);
|
||||
let loader = Cc["@mozilla.org/moz/jssubscript-loader;1"].
|
||||
createInstance(Ci.mozIJSSubScriptLoader);
|
||||
|
||||
loadBootstrapScope: function XPI_loadBootstrapScope(aId, aDir, aVersion) {
|
||||
LOG("Loading bootstrap scope from " + aDir.path);
|
||||
// Mark the add-on as active for the crash reporter before loading
|
||||
this.bootstrappedAddons[aId] = {
|
||||
version: aVersion,
|
||||
descriptor: aDir.persistentDescriptor
|
||||
};
|
||||
this.bootstrapScopes[aId] = scope;
|
||||
this.addAddonsToCrashReporter();
|
||||
|
||||
let principal = Cc["@mozilla.org/systemprincipal;1"].
|
||||
createInstance(Ci.nsIPrincipal);
|
||||
this.bootstrapScopes[aId] = new Components.utils.Sandbox(principal);
|
||||
|
||||
let bootstrap = aDir.clone();
|
||||
bootstrap.append("bootstrap.js");
|
||||
if (bootstrap.exists()) {
|
||||
let uri = Services.io.newFileURI(bootstrap);
|
||||
let loader = Cc["@mozilla.org/moz/jssubscript-loader;1"].
|
||||
createInstance(Ci.mozIJSSubScriptLoader);
|
||||
|
||||
try {
|
||||
loader.loadSubScript(uri.spec, scope);
|
||||
loader.loadSubScript(uri.spec, this.bootstrapScopes[aId]);
|
||||
}
|
||||
catch (e) {
|
||||
WARN("Error loading bootstrap.js for " + aId + ": " + e);
|
||||
}
|
||||
|
||||
this.callBootstrapMethod(aId, scope, methods);
|
||||
// Copy the reason values from the global object into the bootstrap scope.
|
||||
for (let name in BOOTSTRAP_REASONS)
|
||||
this.bootstrapScopes[aId][name] = BOOTSTRAP_REASONS[name];
|
||||
}
|
||||
else {
|
||||
WARN("Bootstrap missing for " + aId);
|
||||
|
@ -2009,34 +1996,58 @@ var XPIProvider = {
|
|||
},
|
||||
|
||||
/**
|
||||
* Dectivates a bootstrapped add-on by by calling the appropriate method on
|
||||
* the cached JS scope. Removes the add-on and its scope from the
|
||||
* bootstrapScopes and bootstrappedAddons dictionaries.
|
||||
* Unloads a bootstrap scope by dropping all references to it and then
|
||||
* updating the list of active add-ons with the crash reporter.
|
||||
*
|
||||
* @param aId
|
||||
* The ID of the add-on being deactivated
|
||||
* @param aShutdown
|
||||
* true if the add-on is being deactivated during shutdown
|
||||
* @param aUninstall
|
||||
* true if the add-on is being deactivated during uninstallation
|
||||
* The add-on's ID
|
||||
*/
|
||||
deactivateAddon: function XPI_deactivateAddon(aId, aShutdown, aUninstall) {
|
||||
if (!(aId in this.bootstrappedAddons)) {
|
||||
ERROR("Attempted to deactivate an add-on that was never activated");
|
||||
unloadBootstrapScope: function XPI_unloadBootstrapScope(aId) {
|
||||
delete this.bootstrapScopes[aId];
|
||||
delete this.bootstrappedAddons[aId];
|
||||
this.addAddonsToCrashReporter();
|
||||
},
|
||||
|
||||
/**
|
||||
* Calls a bootstrap method for an add-on.
|
||||
*
|
||||
* @param aId
|
||||
* The ID of the add-on
|
||||
* @param aVersion
|
||||
* The version of the add-on
|
||||
* @param aDir
|
||||
* The nsILocalFile for the directory containing the add-on
|
||||
* @param aMethod
|
||||
* The name of the bootstrap method to call
|
||||
* @param aReason
|
||||
* The reason flag to pass to the bootstrap's startup method
|
||||
*/
|
||||
callBootstrapMethod: function XPI_callBootstrapMethod(aId, aVersion, aDir,
|
||||
aMethod, aReason) {
|
||||
// Load the scope if it hasn't already been loaded
|
||||
if (!(aId in this.bootstrapScopes))
|
||||
this.loadBootstrapScope(aId, aDir, aVersion);
|
||||
|
||||
if (!(aMethod in this.bootstrapScopes[aId])) {
|
||||
WARN("Add-on " + aId + " is missing bootstrap method " + aMethod);
|
||||
return;
|
||||
}
|
||||
let scope = this.bootstrapScopes[aId];
|
||||
delete this.bootstrappedAddons[aId];
|
||||
delete this.bootstrapScopes[aId];
|
||||
|
||||
let methods = ["disable"];
|
||||
if (aShutdown)
|
||||
methods.unshift("shutdown");
|
||||
if (aUninstall)
|
||||
methods.unshift("uninstall");
|
||||
this.callBootstrapMethod(aId, scope, methods);
|
||||
let params = {
|
||||
id: aId,
|
||||
version: aVersion,
|
||||
installPath: aDir.clone()
|
||||
};
|
||||
|
||||
this.addAddonsToCrashReporter();
|
||||
LOG("Calling bootstrap method " + aMethod + " on " + aId + " version " +
|
||||
aVersion);
|
||||
try {
|
||||
this.bootstrapScopes[aId][aMethod](params, aReason);
|
||||
}
|
||||
catch (e) {
|
||||
WARN("Exception running bootstrap method " + aMethods + " on " +
|
||||
aId + ": " + e);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -2113,14 +2124,19 @@ var XPIProvider = {
|
|||
aAddon.active = !isDisabled;
|
||||
XPIDatabase.updateAddonActive(aAddon);
|
||||
if (isDisabled) {
|
||||
if (aAddon.type == "bootstrapped")
|
||||
this.deactivateAddon(aAddon.id, false, false);
|
||||
if (aAddon.bootstrap) {
|
||||
let dir = aAddon._installLocation.getLocationForID(aAddon.id);
|
||||
this.callBootstrapMethod(aAddon.id, aAddon.version, dir, "shutdown",
|
||||
BOOTSTRAP_REASONS.ADDON_DISABLE);
|
||||
this.unloadBootstrapScope(aAddon.id);
|
||||
}
|
||||
AddonManagerPrivate.callAddonListeners("onDisabled", wrapper);
|
||||
}
|
||||
else {
|
||||
if (aAddon.type == "bootstrapped") {
|
||||
if (aAddon.bootstrap) {
|
||||
let dir = aAddon._installLocation.getLocationForID(aAddon.id);
|
||||
this.activateAddon(aAddon.id, aAddon.version, dir, false, false);
|
||||
this.callBootstrapMethod(aAddon.id, aAddon.version, dir, "startup",
|
||||
BOOTSTRAP_REASONS.ADDON_ENABLE);
|
||||
}
|
||||
AddonManagerPrivate.callAddonListeners("onEnabled", wrapper);
|
||||
}
|
||||
|
@ -2174,8 +2190,16 @@ var XPIProvider = {
|
|||
requiresRestart);
|
||||
|
||||
if (!requiresRestart) {
|
||||
if (aAddon.type == "bootstrapped")
|
||||
this.deactivateAddon(aAddon.id, false, true);
|
||||
if (aAddon.bootstrap) {
|
||||
let dir = aAddon._installLocation.getLocationForID(aAddon.id);
|
||||
if (aAddon.active) {
|
||||
this.callBootstrapMethod(aAddon.id, aAddon.version, dir, "shutdown",
|
||||
BOOTSTRAP_REASONS.ADDON_UNINSTALL);
|
||||
}
|
||||
this.callBootstrapMethod(aAddon.id, aAddon.version, dir, "uninstall",
|
||||
BOOTSTRAP_REASONS.ADDON_UNINSTALL);
|
||||
this.unloadBootstrapScope(aAddon.id);
|
||||
}
|
||||
aAddon._installLocation.uninstallAddon(aAddon.id);
|
||||
XPIDatabase.removeAddonMetadata(aAddon);
|
||||
AddonManagerPrivate.callAddonListeners("onUninstalled", wrapper);
|
||||
|
@ -2225,7 +2249,7 @@ const FIELDS_ADDON = "internal_id, id, location, version, type, internalName, "
|
|||
"updateURL, updateKey, optionsURL, aboutURL, iconURL, " +
|
||||
"defaultLocale, visible, active, userDisabled, appDisabled, " +
|
||||
"pendingUninstall, descriptor, installDate, updateDate, " +
|
||||
"applyBackgroundUpdates";
|
||||
"applyBackgroundUpdates, bootstrap";
|
||||
|
||||
// A helper function to simply log any errors that occur during async statements.
|
||||
function asyncErrorLogger(aError) {
|
||||
|
@ -2261,7 +2285,7 @@ var XPIDatabase = {
|
|||
":updateKey, :optionsURL, :aboutURL, :iconURL, " +
|
||||
":locale, :visible, :active, :userDisabled," +
|
||||
" :appDisabled, 0, :descriptor, :installDate, " +
|
||||
":updateDate, :applyBackgroundUpdates)",
|
||||
":updateDate, :applyBackgroundUpdates, :bootstrap)",
|
||||
addAddonMetadata_addon_locale: "INSERT INTO addon_locale VALUES " +
|
||||
"(:internal_id, :name, :locale)",
|
||||
addAddonMetadata_locale: "INSERT INTO locale (name, description, creator, " +
|
||||
|
@ -2278,7 +2302,7 @@ var XPIDatabase = {
|
|||
"internal_id=:internal_id",
|
||||
|
||||
getActiveAddons: "SELECT " + FIELDS_ADDON + " FROM addon WHERE active=1 AND " +
|
||||
"type<>'theme' AND type<>'bootstrapped'",
|
||||
"type<>'theme' AND bootstrap=0",
|
||||
getActiveTheme: "SELECT " + FIELDS_ADDON + " FROM addon WHERE " +
|
||||
"internalName=:internalName AND type='theme'",
|
||||
|
||||
|
@ -2299,7 +2323,8 @@ var XPIDatabase = {
|
|||
|
||||
makeAddonVisible: "UPDATE addon SET visible=1 WHERE internal_id=:internal_id",
|
||||
removeAddonMetadata: "DELETE FROM addon WHERE internal_id=:internal_id",
|
||||
// Equates to active = visible && !userDisabled && !appDisabled && !pendingUninstall
|
||||
// Equates to active = visible && !userDisabled && !appDisabled &&
|
||||
// !pendingUninstall
|
||||
setActiveAddons: "UPDATE addon SET active=MIN(visible, 1 - userDisabled, " +
|
||||
"1 - appDisabled, 1 - pendingUninstall)",
|
||||
setAddonProperties: "UPDATE addon SET userDisabled=:userDisabled, " +
|
||||
|
@ -2369,9 +2394,11 @@ var XPIDatabase = {
|
|||
if (disabled == "true" || disabled == "needs-disable")
|
||||
migrateData[location][id].userDisabled = true;
|
||||
|
||||
let targetApps = ds.GetTargets(source, EM_R("targetApplication"), true);
|
||||
let targetApps = ds.GetTargets(source, EM_R("targetApplication"),
|
||||
true);
|
||||
while (targetApps.hasMoreElements()) {
|
||||
let targetApp = targetApps.getNext().QueryInterface(Ci.nsIRDFResource);
|
||||
let targetApp = targetApps.getNext()
|
||||
.QueryInterface(Ci.nsIRDFResource);
|
||||
let appInfo = {
|
||||
id: getRDFProperty(ds, targetApp, "id"),
|
||||
minVersion: getRDFProperty(ds, targetApp, "minVersion"),
|
||||
|
@ -2482,7 +2509,7 @@ var XPIDatabase = {
|
|||
"pendingUninstall INTEGER, descriptor TEXT, " +
|
||||
"installDate INTEGER, updateDate INTEGER, " +
|
||||
"applyBackgroundUpdates INTEGER, " +
|
||||
"UNIQUE (id, location)");
|
||||
"bootstrap INTEGER, UNIQUE (id, location)");
|
||||
this.connection.createTable("targetApplication",
|
||||
"addon_internal_id INTEGER, " +
|
||||
"id TEXT, minVersion TEXT, maxVersion TEXT, " +
|
||||
|
@ -2618,7 +2645,8 @@ var XPIDatabase = {
|
|||
addon.installDate = aRow.installDate;
|
||||
addon.updateDate = aRow.updateDate;
|
||||
["visible", "active", "userDisabled", "appDisabled",
|
||||
"pendingUninstall", "applyBackgroundUpdates"].forEach(function(aProp) {
|
||||
"pendingUninstall", "applyBackgroundUpdates",
|
||||
"bootstrap"].forEach(function(aProp) {
|
||||
addon[aProp] = aRow[aProp] != 0;
|
||||
});
|
||||
this.addonCache[aRow.internal_id] = Components.utils.getWeakReference(addon);
|
||||
|
@ -2768,7 +2796,8 @@ var XPIDatabase = {
|
|||
addon.installDate = aRow.getResultByName("installDate");
|
||||
addon.updateDate = aRow.getResultByName("updateDate");
|
||||
["visible", "active", "userDisabled", "appDisabled",
|
||||
"pendingUninstall", "applyBackgroundUpdates"].forEach(function(aProp) {
|
||||
"pendingUninstall", "applyBackgroundUpdates",
|
||||
"bootstrap"].forEach(function(aProp) {
|
||||
addon[aProp] = aRow.getResultByName(aProp) != 0;
|
||||
});
|
||||
this.addonCache[internal_id] = Components.utils.getWeakReference(addon);
|
||||
|
@ -3042,8 +3071,8 @@ var XPIDatabase = {
|
|||
stmt.params.installDate = aAddon.installDate;
|
||||
stmt.params.updateDate = aAddon.updateDate;
|
||||
copyProperties(aAddon, PROP_METADATA, stmt.params);
|
||||
["visible", "userDisabled", "appDisabled",
|
||||
"applyBackgroundUpdates"].forEach(function(aProp) {
|
||||
["visible", "userDisabled", "appDisabled", "applyBackgroundUpdates",
|
||||
"bootstrap"].forEach(function(aProp) {
|
||||
stmt.params[aProp] = aAddon[aProp] ? 1 : 0;
|
||||
});
|
||||
stmt.params.active = (aAddon.visible && !aAddon.userDisabled &&
|
||||
|
@ -3842,20 +3871,35 @@ AddonInstall.prototype = {
|
|||
// See bug 553015.
|
||||
|
||||
// Deactivate and remove the old add-on as necessary
|
||||
let reason = BOOTSTRAP_REASONS.ADDON_INSTALL;
|
||||
if (this.existingAddon) {
|
||||
if (Services.vc.compare(this.existingAddon.version, this.addon.version) < 0)
|
||||
reason = BOOTSTRAP_REASONS.ADDON_UPGRADE;
|
||||
else
|
||||
reason = BOOTSTRAP_REASONS.ADDON_DOWNGRADE;
|
||||
|
||||
if (this.existingAddon.bootstrap) {
|
||||
let dir = this.existingAddon._installLocation
|
||||
.getLocationForID(this.existingAddon.id);
|
||||
if (this.existingAddon.active) {
|
||||
if (this.existingAddon.type == "bootstrapped")
|
||||
XPIProvider.deactivateAddon(this.existingAddon.id, false,
|
||||
isUpgrade);
|
||||
// If this is an upgrade its metadata will be removed below
|
||||
if (!isUpgrade) {
|
||||
XPIProvider.callBootstrapMethod(this.existingAddon.id,
|
||||
this.existingAddon.version,
|
||||
dir, "shutdown", reason);
|
||||
}
|
||||
XPIProvider.callBootstrapMethod(this.existingAddon.id,
|
||||
this.existingAddon.version,
|
||||
dir, "uninstall", reason);
|
||||
XPIProvider.unloadBootstrapScope(this.existingAddon.id);
|
||||
}
|
||||
|
||||
if (isUpgrade) {
|
||||
this.installLocation.uninstallAddon(this.existingAddon.id);
|
||||
}
|
||||
else if (this.existingAddon.active) {
|
||||
this.existingAddon.active = false;
|
||||
XPIDatabase.updateAddonActive(this.existingAddon);
|
||||
}
|
||||
}
|
||||
if (isUpgrade)
|
||||
this.installLocation.uninstallAddon(this.existingAddon.id);
|
||||
}
|
||||
|
||||
// Install the new add-on into its final directory
|
||||
let dir = this.installLocation.installAddon(this.addon.id, stagedAddon);
|
||||
|
@ -3878,8 +3922,17 @@ AddonInstall.prototype = {
|
|||
XPIDatabase.getAddonInLocation(this.addon.id, this.installLocation.name,
|
||||
function(a) {
|
||||
self.addon = a;
|
||||
if (self.addon.active && self.addon.type == "bootstrapped")
|
||||
XPIProvider.activateAddon(self.addon.id, self.addon.version, dir, false, true);
|
||||
if (self.addon.bootstrap) {
|
||||
XPIProvider.callBootstrapMethod(self.addon.id, self.addon.version,
|
||||
dir, "install", reason);
|
||||
if (self.addon.active) {
|
||||
XPIProvider.callBootstrapMethod(self.addon.id, self.addon.version,
|
||||
dir, "startup", reason);
|
||||
}
|
||||
else {
|
||||
this.unloadBootstrapScope(self.addon.id);
|
||||
}
|
||||
}
|
||||
AddonManagerPrivate.callAddonListeners("onInstalled",
|
||||
createWrapper(self.addon));
|
||||
|
||||
|
|
|
@ -1,9 +1,19 @@
|
|||
Components.utils.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
function enable() {
|
||||
Services.prefs.setIntPref("bootstraptest.version", 1);
|
||||
function install(data, reason) {
|
||||
Services.prefs.setIntPref("bootstraptest.installed_version", 1);
|
||||
}
|
||||
|
||||
function disable() {
|
||||
Services.prefs.setIntPref("bootstraptest.version", 0);
|
||||
function startup(data, reason) {
|
||||
Services.prefs.setIntPref("bootstraptest.active_version", 1);
|
||||
Services.prefs.setIntPref("bootstraptest.startup_reason", reason);
|
||||
}
|
||||
|
||||
function shutdown(data, reason) {
|
||||
Services.prefs.setIntPref("bootstraptest.active_version", 0);
|
||||
Services.prefs.setIntPref("bootstraptest.shutdown_reason", reason);
|
||||
}
|
||||
|
||||
function uninstall(data, reason) {
|
||||
Services.prefs.setIntPref("bootstraptest.installed_version", 0);
|
||||
}
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
<Description about="urn:mozilla:install-manifest">
|
||||
<em:id>bootstrap1@tests.mozilla.org</em:id>
|
||||
<em:version>1.0</em:version>
|
||||
<em:type>64</em:type>
|
||||
<em:bootstrap>true</em:bootstrap>
|
||||
|
||||
<!-- Front End MetaData -->
|
||||
<em:name>Test Bootstrap 1</em:name>
|
||||
|
|
|
@ -1,9 +1,19 @@
|
|||
Components.utils.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
function enable() {
|
||||
Services.prefs.setIntPref("bootstraptest.version", 2);
|
||||
function install(data, reason) {
|
||||
Services.prefs.setIntPref("bootstraptest.installed_version", 2);
|
||||
}
|
||||
|
||||
function disable() {
|
||||
Services.prefs.setIntPref("bootstraptest.version", 0);
|
||||
function startup(data, reason) {
|
||||
Services.prefs.setIntPref("bootstraptest.active_version", 2);
|
||||
Services.prefs.setIntPref("bootstraptest.startup_reason", reason);
|
||||
}
|
||||
|
||||
function shutdown(data, reason) {
|
||||
Services.prefs.setIntPref("bootstraptest.active_version", 0);
|
||||
Services.prefs.setIntPref("bootstraptest.shutdown_reason", reason);
|
||||
}
|
||||
|
||||
function uninstall(data, reason) {
|
||||
Services.prefs.setIntPref("bootstraptest.installed_version", 0);
|
||||
}
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
<Description about="urn:mozilla:install-manifest">
|
||||
<em:id>bootstrap1@tests.mozilla.org</em:id>
|
||||
<em:version>2.0</em:version>
|
||||
<em:type>64</em:type>
|
||||
<em:bootstrap>true</em:bootstrap>
|
||||
|
||||
<!-- Front End MetaData -->
|
||||
<em:name>Test Bootstrap 1</em:name>
|
||||
|
|
|
@ -2,6 +2,15 @@
|
|||
* http://creativecommons.org/publicdomain/zero/1.0/
|
||||
*/
|
||||
|
||||
const APP_STARTUP = 1;
|
||||
const APP_SHUTDOWN = 2;
|
||||
const ADDON_ENABLE = 3;
|
||||
const ADDON_DISABLE = 4;
|
||||
const ADDON_INSTALL = 5;
|
||||
const ADDON_UNINSTALL = 6;
|
||||
const ADDON_UPGRADE = 7;
|
||||
const ADDON_DOWNGRADE = 8;
|
||||
|
||||
// This verifies that bootstrappable add-ons can be used with restarts.
|
||||
Components.utils.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
|
@ -10,8 +19,20 @@ Services.prefs.setIntPref("bootstraptest.version", 0);
|
|||
const profileDir = gProfD.clone();
|
||||
profileDir.append("extensions");
|
||||
|
||||
function getActivatedVersion() {
|
||||
return Services.prefs.getIntPref("bootstraptest.version");
|
||||
function getActiveVersion() {
|
||||
return Services.prefs.getIntPref("bootstraptest.active_version");
|
||||
}
|
||||
|
||||
function getInstalledVersion() {
|
||||
return Services.prefs.getIntPref("bootstraptest.installed_version");
|
||||
}
|
||||
|
||||
function getStartupReason() {
|
||||
return Services.prefs.getIntPref("bootstraptest.startup_reason");
|
||||
}
|
||||
|
||||
function getShutdownReason() {
|
||||
return Services.prefs.getIntPref("bootstraptest.shutdown_reason");
|
||||
}
|
||||
|
||||
function run_test() {
|
||||
|
@ -33,7 +54,7 @@ function run_test_1() {
|
|||
ensure_test_completed();
|
||||
|
||||
do_check_neq(install, null);
|
||||
do_check_eq(install.type, "bootstrapped");
|
||||
do_check_eq(install.type, "extension");
|
||||
do_check_eq(install.version, "1.0");
|
||||
do_check_eq(install.name, "Test Bootstrap 1");
|
||||
do_check_eq(install.state, AddonManager.STATE_DOWNLOADED);
|
||||
|
@ -62,7 +83,9 @@ function check_test_1() {
|
|||
do_check_false(b1.appDisabled);
|
||||
do_check_false(b1.userDisabled);
|
||||
do_check_true(b1.isActive);
|
||||
do_check_eq(getActivatedVersion(), 1);
|
||||
do_check_eq(getInstalledVersion(), 1);
|
||||
do_check_eq(getActiveVersion(), 1);
|
||||
do_check_eq(getStartupReason(), ADDON_INSTALL);
|
||||
do_check_true(b1.hasResource("install.rdf"));
|
||||
do_check_true(b1.hasResource("bootstrap.js"));
|
||||
do_check_false(b1.hasResource("foo.bar"));
|
||||
|
@ -100,7 +123,9 @@ function run_test_2() {
|
|||
do_check_false(b1.appDisabled);
|
||||
do_check_true(b1.userDisabled);
|
||||
do_check_false(b1.isActive);
|
||||
do_check_eq(getActivatedVersion(), 0);
|
||||
do_check_eq(getInstalledVersion(), 1);
|
||||
do_check_eq(getActiveVersion(), 0);
|
||||
do_check_eq(getShutdownReason(), ADDON_DISABLE);
|
||||
do_check_not_in_crash_annotation("bootstrap1@tests.mozilla.org", "1.0");
|
||||
|
||||
AddonManager.getAddonByID("bootstrap1@tests.mozilla.org", function(newb1) {
|
||||
|
@ -118,9 +143,13 @@ function run_test_2() {
|
|||
// Test that restarting doesn't accidentally re-enable
|
||||
function run_test_3() {
|
||||
shutdownManager();
|
||||
do_check_eq(getActivatedVersion(), 0);
|
||||
do_check_eq(getInstalledVersion(), 1);
|
||||
do_check_eq(getActiveVersion(), 0);
|
||||
do_check_eq(getShutdownReason(), ADDON_DISABLE);
|
||||
startupManager(0, false);
|
||||
do_check_eq(getActivatedVersion(), 0);
|
||||
do_check_eq(getInstalledVersion(), 1);
|
||||
do_check_eq(getActiveVersion(), 0);
|
||||
do_check_eq(getShutdownReason(), ADDON_DISABLE);
|
||||
do_check_not_in_crash_annotation("bootstrap1@tests.mozilla.org", "1.0");
|
||||
|
||||
AddonManager.getAddonByID("bootstrap1@tests.mozilla.org", function(b1) {
|
||||
|
@ -152,7 +181,9 @@ function run_test_4() {
|
|||
do_check_false(b1.appDisabled);
|
||||
do_check_false(b1.userDisabled);
|
||||
do_check_true(b1.isActive);
|
||||
do_check_eq(getActivatedVersion(), 1);
|
||||
do_check_eq(getInstalledVersion(), 1);
|
||||
do_check_eq(getActiveVersion(), 1);
|
||||
do_check_eq(getStartupReason(), ADDON_ENABLE);
|
||||
do_check_in_crash_annotation("bootstrap1@tests.mozilla.org", "1.0");
|
||||
|
||||
AddonManager.getAddonByID("bootstrap1@tests.mozilla.org", function(newb1) {
|
||||
|
@ -170,10 +201,14 @@ function run_test_4() {
|
|||
// Tests that a restart shuts down and restarts the add-on
|
||||
function run_test_5() {
|
||||
shutdownManager();
|
||||
do_check_eq(getActivatedVersion(), 0);
|
||||
do_check_eq(getInstalledVersion(), 1);
|
||||
do_check_eq(getActiveVersion(), 0);
|
||||
do_check_eq(getShutdownReason(), APP_SHUTDOWN);
|
||||
do_check_not_in_crash_annotation("bootstrap1@tests.mozilla.org", "1.0");
|
||||
startupManager(0, false);
|
||||
do_check_eq(getActivatedVersion(), 1);
|
||||
do_check_eq(getInstalledVersion(), 1);
|
||||
do_check_eq(getActiveVersion(), 1);
|
||||
do_check_eq(getStartupReason(), APP_STARTUP);
|
||||
do_check_in_crash_annotation("bootstrap1@tests.mozilla.org", "1.0");
|
||||
|
||||
AddonManager.getAddonByID("bootstrap1@tests.mozilla.org", function(b1) {
|
||||
|
@ -198,7 +233,7 @@ function run_test_6() {
|
|||
ensure_test_completed();
|
||||
|
||||
do_check_neq(install, null);
|
||||
do_check_eq(install.type, "bootstrapped");
|
||||
do_check_eq(install.type, "extension");
|
||||
do_check_eq(install.version, "2.0");
|
||||
do_check_eq(install.name, "Test Bootstrap 1");
|
||||
do_check_eq(install.state, AddonManager.STATE_DOWNLOADED);
|
||||
|
@ -223,7 +258,10 @@ function check_test_6() {
|
|||
do_check_false(b1.appDisabled);
|
||||
do_check_false(b1.userDisabled);
|
||||
do_check_true(b1.isActive);
|
||||
do_check_eq(getActivatedVersion(), 2);
|
||||
do_check_eq(getInstalledVersion(), 2);
|
||||
do_check_eq(getActiveVersion(), 2);
|
||||
do_check_eq(getStartupReason(), ADDON_UPGRADE);
|
||||
do_check_eq(getShutdownReason(), ADDON_UPGRADE);
|
||||
do_check_not_in_crash_annotation("bootstrap1@tests.mozilla.org", "1.0");
|
||||
do_check_in_crash_annotation("bootstrap1@tests.mozilla.org", "2.0");
|
||||
|
||||
|
@ -249,7 +287,9 @@ function run_test_7() {
|
|||
|
||||
function check_test_7() {
|
||||
ensure_test_completed();
|
||||
do_check_eq(getActivatedVersion(), 0);
|
||||
do_check_eq(getInstalledVersion(), 0);
|
||||
do_check_eq(getActiveVersion(), 0);
|
||||
do_check_eq(getShutdownReason(), ADDON_UNINSTALL);
|
||||
do_check_not_in_crash_annotation("bootstrap1@tests.mozilla.org", "2.0");
|
||||
|
||||
AddonManager.getAddonByID("bootstrap1@tests.mozilla.org", function(b1) {
|
||||
|
@ -291,7 +331,9 @@ function run_test_8() {
|
|||
do_check_false(b1.appDisabled);
|
||||
do_check_false(b1.userDisabled);
|
||||
do_check_true(b1.isActive);
|
||||
do_check_eq(getActivatedVersion(), 1);
|
||||
do_check_eq(getInstalledVersion(), 1);
|
||||
do_check_eq(getActiveVersion(), 1);
|
||||
do_check_eq(getStartupReason(), APP_STARTUP);
|
||||
do_check_in_crash_annotation("bootstrap1@tests.mozilla.org", "1.0");
|
||||
|
||||
run_test_9();
|
||||
|
@ -311,6 +353,133 @@ function run_test_9() {
|
|||
do_check_eq(b1, null);
|
||||
do_check_not_in_crash_annotation("bootstrap1@tests.mozilla.org", "1.0");
|
||||
|
||||
do_test_finished();
|
||||
run_test_10();
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
// Tests that installing a downgrade sends the right reason
|
||||
function run_test_10() {
|
||||
prepare_test({ }, [
|
||||
"onNewInstall"
|
||||
]);
|
||||
|
||||
AddonManager.getInstallForFile(do_get_addon("test_bootstrap1_2"), function(install) {
|
||||
ensure_test_completed();
|
||||
|
||||
do_check_neq(install, null);
|
||||
do_check_eq(install.type, "extension");
|
||||
do_check_eq(install.version, "2.0");
|
||||
do_check_eq(install.name, "Test Bootstrap 1");
|
||||
do_check_eq(install.state, AddonManager.STATE_DOWNLOADED);
|
||||
do_check_true(install.addon.hasResource("install.rdf"));
|
||||
do_check_true(install.addon.hasResource("bootstrap.js"));
|
||||
do_check_false(install.addon.hasResource("foo.bar"));
|
||||
do_check_not_in_crash_annotation("bootstrap1@tests.mozilla.org", "2.0");
|
||||
|
||||
prepare_test({
|
||||
"bootstrap1@tests.mozilla.org": [
|
||||
["onInstalling", false],
|
||||
"onInstalled"
|
||||
]
|
||||
}, [
|
||||
"onInstallStarted",
|
||||
"onInstallEnded",
|
||||
], check_test_10_pt1);
|
||||
install.install();
|
||||
});
|
||||
}
|
||||
|
||||
function check_test_10_pt1() {
|
||||
AddonManager.getAddonByID("bootstrap1@tests.mozilla.org", function(b1) {
|
||||
do_check_neq(b1, null);
|
||||
do_check_eq(b1.version, "2.0");
|
||||
do_check_false(b1.appDisabled);
|
||||
do_check_false(b1.userDisabled);
|
||||
do_check_true(b1.isActive);
|
||||
do_check_eq(getInstalledVersion(), 2);
|
||||
do_check_eq(getActiveVersion(), 2);
|
||||
do_check_eq(getStartupReason(), ADDON_INSTALL);
|
||||
do_check_true(b1.hasResource("install.rdf"));
|
||||
do_check_true(b1.hasResource("bootstrap.js"));
|
||||
do_check_false(b1.hasResource("foo.bar"));
|
||||
do_check_in_crash_annotation("bootstrap1@tests.mozilla.org", "2.0");
|
||||
|
||||
prepare_test({ }, [
|
||||
"onNewInstall"
|
||||
]);
|
||||
|
||||
AddonManager.getInstallForFile(do_get_addon("test_bootstrap1_1"), function(install) {
|
||||
ensure_test_completed();
|
||||
|
||||
do_check_neq(install, null);
|
||||
do_check_eq(install.type, "extension");
|
||||
do_check_eq(install.version, "1.0");
|
||||
do_check_eq(install.name, "Test Bootstrap 1");
|
||||
do_check_eq(install.state, AddonManager.STATE_DOWNLOADED);
|
||||
|
||||
prepare_test({
|
||||
"bootstrap1@tests.mozilla.org": [
|
||||
["onInstalling", false],
|
||||
"onInstalled"
|
||||
]
|
||||
}, [
|
||||
"onInstallStarted",
|
||||
"onInstallEnded",
|
||||
], check_test_10_pt2);
|
||||
install.install();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function check_test_10_pt2() {
|
||||
AddonManager.getAddonByID("bootstrap1@tests.mozilla.org", function(b1) {
|
||||
do_check_neq(b1, null);
|
||||
do_check_eq(b1.version, "1.0");
|
||||
do_check_false(b1.appDisabled);
|
||||
do_check_false(b1.userDisabled);
|
||||
do_check_true(b1.isActive);
|
||||
do_check_eq(getInstalledVersion(), 1);
|
||||
do_check_eq(getActiveVersion(), 1);
|
||||
do_check_eq(getStartupReason(), ADDON_DOWNGRADE);
|
||||
do_check_eq(getShutdownReason(), ADDON_DOWNGRADE);
|
||||
do_check_in_crash_annotation("bootstrap1@tests.mozilla.org", "1.0");
|
||||
do_check_not_in_crash_annotation("bootstrap1@tests.mozilla.org", "2.0");
|
||||
|
||||
run_test_11();
|
||||
});
|
||||
}
|
||||
|
||||
// Tests that uninstalling a disabled add-on still calls the uninstall method
|
||||
function run_test_11() {
|
||||
AddonManager.getAddonByID("bootstrap1@tests.mozilla.org", function(b1) {
|
||||
prepare_test({
|
||||
"bootstrap1@tests.mozilla.org": [
|
||||
["onDisabling", false],
|
||||
"onDisabled",
|
||||
["onUninstalling", false],
|
||||
"onUninstalled"
|
||||
]
|
||||
});
|
||||
|
||||
b1.userDisabled = true;
|
||||
|
||||
do_check_eq(getInstalledVersion(), 1);
|
||||
do_check_eq(getActiveVersion(), 0);
|
||||
do_check_eq(getShutdownReason(), ADDON_DISABLE);
|
||||
do_check_not_in_crash_annotation("bootstrap1@tests.mozilla.org", "1.0");
|
||||
|
||||
b1.uninstall();
|
||||
|
||||
check_test_11();
|
||||
});
|
||||
}
|
||||
|
||||
function check_test_11() {
|
||||
ensure_test_completed();
|
||||
do_check_eq(getInstalledVersion(), 0);
|
||||
do_check_eq(getActiveVersion(), 0);
|
||||
do_check_not_in_crash_annotation("bootstrap1@tests.mozilla.org", "1.0");
|
||||
|
||||
do_test_finished();
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче