зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1192921: Add an install location for system add-ons. r=rhelmer
This adds two new directory install locations. One contains the default system add-ons that ship with the application, the other contains system add-on that will eventually be updatable at runtime. The updatable location tracks the expected list of add-ons in a pref. and only returns add-ons from that list when asked for its list of add-ons. After processFileChanges has scanned all add-ons and updated the database it checks if the updated system add-ons match the expected set. If not we ignore those add-ons when working out which add-ons should be visible. If they do match then we ignore the app-shipped system add-ons when working out which are visible. --HG-- extra : commitid : H1px7lWsLNj extra : rebase_source : 6b70fd6c88608169e2974e19acd37bf63243c1cd
This commit is contained in:
Родитель
72d129f6ff
Коммит
a486e9c783
|
@ -99,6 +99,7 @@ const PREF_INSTALL_DISTRO_ADDONS = "extensions.installDistroAddons";
|
|||
const PREF_BRANCH_INSTALLED_ADDON = "extensions.installedDistroAddon.";
|
||||
const PREF_SHOWN_SELECTION_UI = "extensions.shownSelectionUI";
|
||||
const PREF_INTERPOSITION_ENABLED = "extensions.interposition.enabled";
|
||||
const PREF_SYSTEM_ADDON_SET = "extensions.systemAddonSet";
|
||||
|
||||
const PREF_EM_MIN_COMPAT_APP_VERSION = "extensions.minCompatibleAppVersion";
|
||||
const PREF_EM_MIN_COMPAT_PLATFORM_VERSION = "extensions.minCompatiblePlatformVersion";
|
||||
|
@ -116,6 +117,7 @@ const URI_EXTENSION_STRINGS = "chrome://mozapps/locale/extensions/exte
|
|||
const STRING_TYPE_NAME = "type.%ID%.name";
|
||||
|
||||
const DIR_EXTENSIONS = "extensions";
|
||||
const DIR_SYSTEM_ADDONS = "features";
|
||||
const DIR_STAGE = "staged";
|
||||
const DIR_TRASH = "trash";
|
||||
|
||||
|
@ -131,6 +133,8 @@ const KEY_TEMPDIR = "TmpD";
|
|||
const KEY_APP_DISTRIBUTION = "XREAppDist";
|
||||
|
||||
const KEY_APP_PROFILE = "app-profile";
|
||||
const KEY_APP_SYSTEM_ADDONS = "app-system-addons";
|
||||
const KEY_APP_SYSTEM_DEFAULTS = "app-system-defaults";
|
||||
const KEY_APP_GLOBAL = "app-global";
|
||||
const KEY_APP_SYSTEM_LOCAL = "app-system-local";
|
||||
const KEY_APP_SYSTEM_SHARE = "app-system-share";
|
||||
|
@ -1957,7 +1961,7 @@ this.XPIStates = {
|
|||
|
||||
for (let location of XPIProvider.installLocations) {
|
||||
// The list of add-on like file/directory names in the install location.
|
||||
let addons = location.addonLocations;
|
||||
let addons = location.getAddonLocations();
|
||||
// The results of scanning this location.
|
||||
let foundAddons = new SerializableMap();
|
||||
|
||||
|
@ -2313,6 +2317,28 @@ this.XPIProvider = {
|
|||
XPIProvider.installLocationsByName[location.name] = location;
|
||||
}
|
||||
|
||||
function addSystemAddonInstallLocation(aName, aKey, aPaths, aScope) {
|
||||
try {
|
||||
var dir = FileUtils.getDir(aKey, aPaths);
|
||||
}
|
||||
catch (e) {
|
||||
// Some directories aren't defined on some platforms, ignore them
|
||||
logger.debug("Skipping unavailable install location " + aName);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
var location = new SystemAddonInstallLocation(aName, dir, aScope, aAppChanged !== false);
|
||||
}
|
||||
catch (e) {
|
||||
logger.warn("Failed to add system add-on install location " + aName, e);
|
||||
return;
|
||||
}
|
||||
|
||||
XPIProvider.installLocations.push(location);
|
||||
XPIProvider.installLocationsByName[location.name] = location;
|
||||
}
|
||||
|
||||
function addRegistryInstallLocation(aName, aRootkey, aScope) {
|
||||
try {
|
||||
var location = new WinRegInstallLocation(aName, aRootkey, aScope);
|
||||
|
@ -2355,6 +2381,14 @@ this.XPIProvider = {
|
|||
[DIR_EXTENSIONS],
|
||||
AddonManager.SCOPE_PROFILE, false);
|
||||
|
||||
addSystemAddonInstallLocation(KEY_APP_SYSTEM_ADDONS, KEY_PROFILEDIR,
|
||||
[DIR_SYSTEM_ADDONS],
|
||||
AddonManager.SCOPE_PROFILE);
|
||||
|
||||
addDirectoryInstallLocation(KEY_APP_SYSTEM_DEFAULTS, KEY_APP_DISTRIBUTION,
|
||||
[DIR_SYSTEM_ADDONS],
|
||||
AddonManager.SCOPE_PROFILE, true);
|
||||
|
||||
if (enabledScopes & AddonManager.SCOPE_USER) {
|
||||
addDirectoryInstallLocation(KEY_APP_SYSTEM_USER, "XREUSysExt",
|
||||
[Services.appinfo.ID],
|
||||
|
@ -6757,7 +6791,7 @@ function DirectoryInstallLocation(aName, aDirectory, aScope) {
|
|||
this._IDToFileMap = {};
|
||||
this._linkedAddons = [];
|
||||
|
||||
if (!aDirectory.exists())
|
||||
if (!aDirectory || !aDirectory.exists())
|
||||
return;
|
||||
if (!aDirectory.isDirectory())
|
||||
throw new Error("Location must be a directory.");
|
||||
|
@ -6882,7 +6916,7 @@ DirectoryInstallLocation.prototype = {
|
|||
/**
|
||||
* Gets an array of nsIFiles for add-ons installed in this location.
|
||||
*/
|
||||
get addonLocations() {
|
||||
getAddonLocations: function() {
|
||||
let locations = new Map();
|
||||
for (let id in this._IDToFileMap) {
|
||||
locations.set(id, this._IDToFileMap[id].clone());
|
||||
|
@ -7201,6 +7235,128 @@ Object.assign(MutableDirectoryInstallLocation.prototype, {
|
|||
},
|
||||
});
|
||||
|
||||
/**
|
||||
* An object which identifies a directory install location for system add-ons.
|
||||
* The location consists of a directory which contains the add-ons installed in
|
||||
* the location.
|
||||
*
|
||||
* @param aName
|
||||
* The string identifier for the install location
|
||||
* @param aDirectory
|
||||
* The nsIFile directory for the install location
|
||||
* @param aScope
|
||||
* The scope of add-ons installed in this location
|
||||
* @param aResetSet
|
||||
* True to throw away the current add-on set
|
||||
*/
|
||||
function SystemAddonInstallLocation(aName, aDirectory, aScope, aResetSet) {
|
||||
this._baseDir = aDirectory;
|
||||
|
||||
if (aResetSet) {
|
||||
this._addonSet = { schema: 1, addons: {} };
|
||||
this._saveAddonSet(this._addonSet);
|
||||
}
|
||||
else {
|
||||
this._addonSet = this._loadAddonSet();
|
||||
}
|
||||
|
||||
this._directory = null;
|
||||
if (this._addonSet.directory) {
|
||||
this._directory = aDirectory.clone();
|
||||
this._directory.append(this._addonSet.directory);
|
||||
logger.info("SystemAddonInstallLocation scanning directory " + this._directory.path);
|
||||
}
|
||||
else {
|
||||
logger.info("SystemAddonInstallLocation directory is missing");
|
||||
}
|
||||
|
||||
DirectoryInstallLocation.call(this, aName, this._directory, aScope);
|
||||
this.locked = true;
|
||||
}
|
||||
|
||||
SystemAddonInstallLocation.prototype = Object.create(DirectoryInstallLocation.prototype);
|
||||
Object.assign(SystemAddonInstallLocation.prototype, {
|
||||
/**
|
||||
* Reads the current set of system add-ons
|
||||
*/
|
||||
_loadAddonSet: function() {
|
||||
try {
|
||||
let setStr = Preferences.get(PREF_SYSTEM_ADDON_SET, null);
|
||||
if (setStr) {
|
||||
let addonSet = JSON.parse(setStr);
|
||||
if ((typeof addonSet == "object") && addonSet.schema == 1)
|
||||
return addonSet;
|
||||
}
|
||||
}
|
||||
catch (e) {
|
||||
logger.error("Malformed system add-on set, resetting.");
|
||||
}
|
||||
|
||||
return { schema: 1, addons: {} };
|
||||
},
|
||||
|
||||
/**
|
||||
* Saves the current set of system add-ons
|
||||
*/
|
||||
_saveAddonSet: function(aAddonSet) {
|
||||
Preferences.set(PREF_SYSTEM_ADDON_SET, JSON.stringify(aAddonSet));
|
||||
},
|
||||
|
||||
getAddonLocations: function() {
|
||||
let addons = DirectoryInstallLocation.prototype.getAddonLocations.call(this);
|
||||
|
||||
// Strip out any unexpected add-ons from the list
|
||||
for (let id of addons.keys()) {
|
||||
if (!(id in this._addonSet.addons))
|
||||
addons.delete(id);
|
||||
}
|
||||
|
||||
return addons;
|
||||
},
|
||||
|
||||
/**
|
||||
* Tests whether updated system add-ons are expected.
|
||||
*/
|
||||
isActive: function() {
|
||||
return this._directory != null;
|
||||
},
|
||||
|
||||
/**
|
||||
* Tests whether the loaded add-on information matches what is expected.
|
||||
*/
|
||||
isValid: function(aAddons) {
|
||||
for (let id of Object.keys(this._addonSet.addons)) {
|
||||
if (!aAddons.has(id)) {
|
||||
logger.warn("Expected add-on " + id + " is missing from the system add-on location.");
|
||||
return false;
|
||||
}
|
||||
|
||||
let addon = aAddons.get(id);
|
||||
if (addon.appDisabled) {
|
||||
logger.warn("System add-on " + id + " isn't compatible with the application.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (addon.unpack) {
|
||||
logger.warn("System add-on " + id + " isn't a packed add-on.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!addon.bootstrap) {
|
||||
logger.warn("System add-on " + id + " isn't restartless.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (addon.version != this._addonSet.addons[id].version) {
|
||||
logger.warn("System add-on " + id + " wasn't the correct version.");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
},
|
||||
});
|
||||
|
||||
#ifdef XP_WIN
|
||||
/**
|
||||
* An object that identifies a registry install location for add-ons. The location
|
||||
|
@ -7307,7 +7463,7 @@ WinRegInstallLocation.prototype = {
|
|||
/**
|
||||
* Gets an array of nsIFiles for add-ons installed in this location.
|
||||
*/
|
||||
get addonLocations() {
|
||||
getAddonLocations: function() {
|
||||
let locations = new Map();
|
||||
for (let id in this._IDToFileMap) {
|
||||
locations.set(id, this._IDToFileMap[id].clone());
|
||||
|
|
|
@ -1497,10 +1497,13 @@ 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) {
|
||||
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;
|
||||
|
@ -1608,7 +1611,12 @@ this.XPIDatabaseReconcile = {
|
|||
aNewAddon._installLocation = aInstallLocation;
|
||||
aNewAddon.installDate = aAddonState.mtime;
|
||||
aNewAddon.updateDate = aAddonState.mtime;
|
||||
aNewAddon.foreignInstall = isDetectedInstall;
|
||||
|
||||
// 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);
|
||||
|
@ -1886,7 +1894,8 @@ this.XPIDatabaseReconcile = {
|
|||
// has changed
|
||||
let newAddon = loadedManifest(installLocation, id);
|
||||
if (newAddon || oldAddon.updateDate != xpiState.mtime ||
|
||||
(aUpdateCompatibility && installLocation.name == KEY_APP_GLOBAL)) {
|
||||
(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) {
|
||||
|
@ -1943,8 +1952,24 @@ this.XPIDatabaseReconcile = {
|
|||
}
|
||||
}
|
||||
|
||||
// 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);
|
||||
let currentVisible = this.flattenByID(currentAddons, hideLocation);
|
||||
let sawActiveTheme = false;
|
||||
XPIProvider.bootstrappedAddons = {};
|
||||
|
||||
|
@ -2012,11 +2037,9 @@ this.XPIDatabaseReconcile = {
|
|||
// and still exists then call its uninstall method.
|
||||
if (previousAddon.bootstrap && previousAddon._installLocation &&
|
||||
currentAddon._installLocation != previousAddon._installLocation &&
|
||||
currentAddons.get(previousAddon._installLocation.name).has(id)) {
|
||||
previousAddon._sourceBundle.exists()) {
|
||||
|
||||
let file = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsIFile);
|
||||
file.persistentDescriptor = previousAddon._sourceBundle.persistentDescriptor;
|
||||
XPIProvider.callBootstrapMethod(previousAddon, file,
|
||||
XPIProvider.callBootstrapMethod(previousAddon, previousAddon._sourceBundle,
|
||||
"uninstall", installReason,
|
||||
{ newVersion: currentAddon.version });
|
||||
XPIProvider.unloadBootstrapScope(previousAddon.id);
|
||||
|
@ -2071,6 +2094,15 @@ this.XPIDatabaseReconcile = {
|
|||
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();
|
||||
|
|
Двоичные данные
toolkit/mozapps/extensions/test/xpcshell/data/system_addons/app1/features/system1@tests.mozilla.org.xpi
Normal file
Двоичные данные
toolkit/mozapps/extensions/test/xpcshell/data/system_addons/app1/features/system1@tests.mozilla.org.xpi
Normal file
Двоичный файл не отображается.
Двоичные данные
toolkit/mozapps/extensions/test/xpcshell/data/system_addons/app1/features/system2@tests.mozilla.org.xpi
Normal file
Двоичные данные
toolkit/mozapps/extensions/test/xpcshell/data/system_addons/app1/features/system2@tests.mozilla.org.xpi
Normal file
Двоичный файл не отображается.
18
toolkit/mozapps/extensions/test/xpcshell/data/system_addons/app1/features/system_1_1/bootstrap.js
поставляемый
Normal file
18
toolkit/mozapps/extensions/test/xpcshell/data/system_addons/app1/features/system_1_1/bootstrap.js
поставляемый
Normal file
|
@ -0,0 +1,18 @@
|
|||
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) {
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
<?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>
|
18
toolkit/mozapps/extensions/test/xpcshell/data/system_addons/app1/features/system_2_1/bootstrap.js
поставляемый
Normal file
18
toolkit/mozapps/extensions/test/xpcshell/data/system_addons/app1/features/system_2_1/bootstrap.js
поставляемый
Normal file
|
@ -0,0 +1,18 @@
|
|||
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) {
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
<?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>
|
Двоичные данные
toolkit/mozapps/extensions/test/xpcshell/data/system_addons/app2/features/system1@tests.mozilla.org.xpi
Normal file
Двоичные данные
toolkit/mozapps/extensions/test/xpcshell/data/system_addons/app2/features/system1@tests.mozilla.org.xpi
Normal file
Двоичный файл не отображается.
Двоичные данные
toolkit/mozapps/extensions/test/xpcshell/data/system_addons/app2/features/system3@tests.mozilla.org.xpi
Normal file
Двоичные данные
toolkit/mozapps/extensions/test/xpcshell/data/system_addons/app2/features/system3@tests.mozilla.org.xpi
Normal file
Двоичный файл не отображается.
18
toolkit/mozapps/extensions/test/xpcshell/data/system_addons/app2/features/system_1_2/bootstrap.js
поставляемый
Normal file
18
toolkit/mozapps/extensions/test/xpcshell/data/system_addons/app2/features/system_1_2/bootstrap.js
поставляемый
Normal file
|
@ -0,0 +1,18 @@
|
|||
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) {
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
<?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>
|
18
toolkit/mozapps/extensions/test/xpcshell/data/system_addons/app2/features/system_3_1/bootstrap.js
поставляемый
Normal file
18
toolkit/mozapps/extensions/test/xpcshell/data/system_addons/app2/features/system_3_1/bootstrap.js
поставляемый
Normal file
|
@ -0,0 +1,18 @@
|
|||
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) {
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
<?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 = true;
|
||||
aPersistent.value = false;
|
||||
if (aProp == aKey)
|
||||
return aDir.clone();
|
||||
return null;
|
||||
|
|
|
@ -0,0 +1,200 @@
|
|||
// 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,6 +24,7 @@ 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]
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче