--- a/toolkit/mozapps/extensions/internal/XPIProviderUtils.js
+++ b/toolkit/mozapps/extensions/internal/XPIProviderUtils.js
@@ -1,14 +1,16 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
+/* eslint "valid-jsdoc": [2, {requireReturn: false, requireReturnDescription: false, prefer: {return: "returns"}}] */
+
// These are injected from XPIProvider.jsm
/* globals ADDON_SIGNING, SIGNED_TYPES, BOOTSTRAP_REASONS, DB_SCHEMA,
AddonInternal, XPIProvider, XPIStates,
isUsableAddon, recordAddonTelemetry,
descriptorToPath */
ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
@@ -62,35 +64,41 @@ const PROP_JSON_FIELDS = ["id", "syncGUI
"userPermissions", "icons", "iconURL", "icon64URL",
"blocklistState", "blocklistURL", "startupData"];
// Time to wait before async save of XPI JSON database, in milliseconds
const ASYNC_SAVE_DELAY_MS = 20;
/**
* Asynchronously fill in the _repositoryAddon field for one addon
+ *
+ * @param {AddonInternal} aAddon
+ * The add-on to annotate.
+ * @returns {AddonInternal}
+ * The annotated add-on.
*/
async function getRepositoryAddon(aAddon) {
if (aAddon) {
aAddon._repositoryAddon = await AddonRepository.getCachedAddonByID(aAddon.id);
}
return aAddon;
}
/**
* Copies properties from one object to another. If no target object is passed
* a new object will be created and returned.
*
- * @param aObject
- * An object to copy from
- * @param aProperties
- * An array of properties to be copied
- * @param aTarget
- * An optional target object to copy the properties to
- * @return the object that the properties were copied onto
+ * @param {object} aObject
+ * An object to copy from
+ * @param {string[]} aProperties
+ * An array of properties to be copied
+ * @param {object?} [aTarget]
+ * An optional target object to copy the properties to
+ * @returns {Object}
+ * The object that the properties were copied onto
*/
function copyProperties(aObject, aProperties, aTarget) {
if (!aTarget)
aTarget = {};
aProperties.forEach(function(aProp) {
if (aProp in aObject)
aTarget[aProp] = aObject[aProp];
});
@@ -98,17 +106,17 @@ function copyProperties(aObject, aProper
}
/**
* The DBAddonInternal is a special AddonInternal that has been retrieved from
* the database. The constructor will initialize the DBAddonInternal with a set
* of fields, which could come from either the JSON store or as an
* XPIProvider.AddonInternal created from an addon's manifest
* @constructor
- * @param aLoaded
+ * @param {Object} aLoaded
* Addon data fields loaded from JSON or the addon manifest.
*/
function DBAddonInternal(aLoaded) {
AddonInternal.call(this);
if (aLoaded.descriptor) {
if (!aLoaded.path) {
aLoaded.path = descriptorToPath(aLoaded.descriptor);
@@ -163,29 +171,49 @@ Object.assign(DBAddonInternal.prototype,
},
get inDatabase() {
return true;
}
});
/**
- * Internal interface: find an addon from an already loaded addonDB
+ * @typedef {Map<string, DBAddonInternal>} AddonDB
+ */
+
+/**
+ * Internal interface: find an addon from an already loaded addonDB.
+ *
+ * @param {AddonDB} addonDB
+ * The add-on database.
+ * @param {function(DBAddonInternal) : boolean} aFilter
+ * The filter predecate. The first add-on for which it returns
+ * true will be returned.
+ * @returns {DBAddonInternal?}
+ * The first matching add-on, if one is found.
*/
function _findAddon(addonDB, aFilter) {
for (let addon of addonDB.values()) {
if (aFilter(addon)) {
return addon;
}
}
return null;
}
/**
* Internal interface to get a filtered list of addons from a loaded addonDB
+ *
+ * @param {AddonDB} addonDB
+ * The add-on database.
+ * @param {function(DBAddonInternal) : boolean} aFilter
+ * The filter predecate. Add-ons which match this predicate will
+ * be returned.
+ * @returns {Array<DBAddonInternal>}
+ * The list of matching add-ons.
*/
function _filterDB(addonDB, aFilter) {
return Array.from(addonDB.values()).filter(aFilter);
}
this.XPIDatabase = {
// true if the database connection has been opened
initialized: false,
@@ -266,16 +294,18 @@ this.XPIDatabase = {
}
await this._saveTask.finalize();
},
/**
* Converts the current internal state of the XPI addon database to
* a JSON.stringify()-ready structure
+ *
+ * @returns {Object}
*/
toJSON() {
if (!this.addonDB) {
// We never loaded the database?
throw new Error("Attempt to save database without loading it first");
}
let toSave = {
@@ -294,20 +324,21 @@ this.XPIDatabase = {
* 1) Perfectly good, up to date database
* 2) Out of date JSON database needs to be upgraded => upgrade
* 3) JSON database exists but is mangled somehow => build new JSON
* 4) no JSON DB, but a usable SQLITE db we can upgrade from => upgrade
* 5) useless SQLITE DB => build new JSON
* 6) usable RDF DB => upgrade
* 7) useless RDF DB => build new JSON
* 8) Nothing at all => build new JSON
- * @param aRebuildOnError
- * A boolean indicating whether add-on information should be loaded
- * from the install locations if the database needs to be rebuilt.
- * (if false, caller is XPIProvider.checkForChanges() which will rebuild)
+ *
+ * @param {boolean} aRebuildOnError
+ * A boolean indicating whether add-on information should be loaded
+ * from the install locations if the database needs to be rebuilt.
+ * (if false, caller is XPIProvider.checkForChanges() which will rebuild)
*/
syncLoadDB(aRebuildOnError) {
this.migrateData = null;
let fstream = null;
let data = "";
try {
let readTimer = AddonManagerPrivate.simpleTimer("XPIDB_syncRead_MS");
logger.debug("Opening XPI database " + this.jsonFile.path);
@@ -353,23 +384,25 @@ this.XPIDatabase = {
AddonManagerPrivate.recordSimpleMeasure("XPIDB_overlapped_load", 1);
}
this._dbPromise = Promise.resolve(this.addonDB);
Services.obs.notifyObservers(this.addonDB, "xpi-database-loaded");
},
/**
* Parse loaded data, reconstructing the database if the loaded data is not valid
- * @param aRebuildOnError
+ *
+ * @param {string} aData
+ * The stringified add-on JSON to parse.
+ * @param {boolean} aRebuildOnError
* If true, synchronously reconstruct the database from installed add-ons
*/
parseDB(aData, aRebuildOnError) {
let parseTimer = AddonManagerPrivate.simpleTimer("XPIDB_parseDB_MS");
try {
- // dump("Loaded JSON:\n" + aData + "\n");
let inputAddons = JSON.parse(aData);
// Now do some sanity checks on our JSON db
if (!("schemaVersion" in inputAddons) || !("addons" in inputAddons)) {
parseTimer.done();
// Content of JSON file is bad, need to rebuild from scratch
logger.error("bad JSON file contents");
AddonManagerPrivate.recordSimpleMeasure("XPIDB_startupError", "badJSON");
let rebuildTimer = AddonManagerPrivate.simpleTimer("XPIDB_rebuildBadJSON_MS");
@@ -425,16 +458,19 @@ this.XPIDatabase = {
let rebuildTimer = AddonManagerPrivate.simpleTimer("XPIDB_rebuildReadFailed_MS");
this.rebuildDatabase(aRebuildOnError);
rebuildTimer.done();
}
},
/**
* Upgrade database from earlier (sqlite or RDF) version if available
+ *
+ * @param {boolean} aRebuildOnError
+ * If true, synchronously reconstruct the database from installed add-ons
*/
upgradeDB(aRebuildOnError) {
let upgradeTimer = AddonManagerPrivate.simpleTimer("XPIDB_upgradeDB_MS");
let schemaVersion = Services.prefs.getIntPref(PREF_DB_SCHEMA, 0);
if (schemaVersion > LAST_SQLITE_DB_SCHEMA) {
// we've upgraded before but the JSON file is gone, fall through
// and rebuild from scratch
@@ -443,16 +479,21 @@ this.XPIDatabase = {
this.rebuildDatabase(aRebuildOnError);
upgradeTimer.done();
},
/**
* Reconstruct when the DB file exists but is unreadable
* (for example because read permission is denied)
+ *
+ * @param {Error} aError
+ * The error that triggered the rebuild.
+ * @param {boolean} aRebuildOnError
+ * If true, synchronously reconstruct the database from installed add-ons
*/
rebuildUnreadableDB(aError, aRebuildOnError) {
let rebuildTimer = AddonManagerPrivate.simpleTimer("XPIDB_rebuildUnreadableDB_MS");
logger.warn("Extensions database " + this.jsonFile.path +
" exists but is not readable; rebuilding", aError);
// Remember the error message until we try and write at least once, so
// we know at shutdown time that there was a problem
this._loadError = aError;
@@ -461,18 +502,19 @@ this.XPIDatabase = {
rebuildTimer.done();
},
/**
* Open and read the XPI database asynchronously, upgrading if
* necessary. If any DB load operation fails, we need to
* synchronously rebuild the DB from the installed extensions.
*
- * @return Promise<Map> resolves to the Map of loaded JSON data stored
- * in this.addonDB; never rejects.
+ * @returns {Promise<AddonDB>}
+ * Resolves to the Map of loaded JSON data stored in
+ * this.addonDB; never rejects.
*/
asyncLoadDB() {
// Already started (and possibly finished) loading
if (this._dbPromise) {
return this._dbPromise;
}
logger.debug("Starting async load of XPI database " + this.jsonFile.path);
@@ -519,20 +561,21 @@ this.XPIDatabase = {
return this._dbPromise;
},
/**
* Rebuild the database from addon install directories. If this.migrateData
* is available, uses migrated information for settings on the addons found
* during rebuild
- * @param aRebuildOnError
- * A boolean indicating whether add-on information should be loaded
- * from the install locations if the database needs to be rebuilt.
- * (if false, caller is XPIProvider.checkForChanges() which will rebuild)
+ *
+ * @param {boolean} aRebuildOnError
+ * A boolean indicating whether add-on information should be loaded
+ * from the install locations if the database needs to be rebuilt.
+ * (if false, caller is XPIProvider.checkForChanges() which will rebuild)
*/
rebuildDatabase(aRebuildOnError) {
this.addonDB = new Map();
this.initialized = true;
if (XPIStates.size == 0) {
// No extensions installed, so we're done
logger.debug("Rebuilding XPI database with no extensions");
@@ -598,39 +641,44 @@ this.XPIDatabase = {
delete this._saveTask;
// re-enable the schema version setter
delete this._schemaVersionSet;
}
},
/**
* Asynchronously list all addons that match the filter function
- * @param aFilter
- * Function that takes an addon instance and returns
- * true if that addon should be included in the selected array
- * @return a Promise that resolves to the list of add-ons matching aFilter or
- * an empty array if none match
+ *
+ * @param {function(DBAddonInternal) : boolean} aFilter
+ * Function that takes an addon instance and returns
+ * true if that addon should be included in the selected array
+ *
+ * @returns {Array<DBAddonInternal>}
+ * A Promise that resolves to the list of add-ons matching
+ * aFilter or an empty array if none match
*/
async getAddonList(aFilter) {
try {
let addonDB = await this.asyncLoadDB();
let addonList = _filterDB(addonDB, aFilter);
let addons = await Promise.all(addonList.map(addon => getRepositoryAddon(addon)));
return addons;
} catch (error) {
logger.error("getAddonList failed", error);
return [];
}
},
/**
- * (Possibly asynchronously) get the first addon that matches the filter function
- * @param aFilter
- * Function that takes an addon instance and returns
- * true if that addon should be selected
+ * Get the first addon that matches the filter function
+ *
+ * @param {function(DBAddonInternal) : boolean} aFilter
+ * Function that takes an addon instance and returns
+ * true if that addon should be selected
+ * @returns {Promise<DBAddonInternal?>}
*/
getAddon(aFilter) {
return this.asyncLoadDB()
.then(addonDB => getRepositoryAddon(_findAddon(addonDB, aFilter)))
.catch(
error => {
logger.error("getAddon failed", error);
});
@@ -639,68 +687,72 @@ this.XPIDatabase = {
syncGetAddon(aFilter) {
return _findAddon(this.addonDB, aFilter);
},
/**
* Asynchronously gets an add-on with a particular ID in a particular
* install location.
*
- * @param aId
- * The ID of the add-on to retrieve
- * @param aLocation
- * The name of the install location
+ * @param {string} aId
+ * The ID of the add-on to retrieve
+ * @param {string} aLocation
+ * The name of the install location
+ * @returns {Promise<DBAddonInternal?>}
*/
getAddonInLocation(aId, aLocation) {
return this.asyncLoadDB().then(
addonDB => getRepositoryAddon(addonDB.get(aLocation + ":" + aId)));
},
/**
* Asynchronously get all the add-ons in a particular install location.
*
- * @param aLocation
- * The name of the install location
+ * @param {string} aLocation
+ * The name of the install location
+ * @returns {Promise<Array<DBAddonInternal>>}
*/
getAddonsInLocation(aLocation) {
return this.getAddonList(aAddon => aAddon._installLocation.name == aLocation);
},
/**
* Asynchronously gets the add-on with the specified ID that is visible.
*
- * @param aId
- * The ID of the add-on to retrieve
+ * @param {string} aId
+ * The ID of the add-on to retrieve
+ * @returns {Promise<DBAddonInternal?>}
*/
getVisibleAddonForID(aId) {
return this.getAddon(aAddon => ((aAddon.id == aId) && aAddon.visible));
},
syncGetVisibleAddonForID(aId) {
return this.syncGetAddon(aAddon => ((aAddon.id == aId) && aAddon.visible));
},
/**
* Asynchronously gets the visible add-ons, optionally restricting by type.
*
- * @param aTypes
- * An array of types to include or null to include all types
+ * @param {Array<string>?} aTypes
+ * An array of types to include or null to include all types
+ * @returns {Promise<Array<DBAddonInternal>>}
*/
getVisibleAddons(aTypes) {
return this.getAddonList(aAddon => (aAddon.visible &&
(!aTypes || (aTypes.length == 0) ||
(aTypes.indexOf(aAddon.type) > -1))));
},
/**
* Synchronously gets all add-ons of a particular type(s).
*
- * @param aType, aType2, ...
- * The type(s) of add-on to retrieve
- * @return an array of DBAddonInternals
+ * @param {Array<string>} aTypes
+ * The type(s) of add-on to retrieve
+ * @returns {Array<DBAddonInternal>}
*/
getAddonsByType(...aTypes) {
if (!this.addonDB) {
// jank-tastic! Must synchronously load DB if the theme switches from
// an XPI theme to a lightweight theme before the DB has loaded,
// because we're called from sync XPIProvider.addonChanged
logger.warn(`Synchronous load of XPI database due to ` +
`getAddonsByType([${aTypes.join(", ")}]) ` +
@@ -710,59 +762,62 @@ this.XPIDatabase = {
}
return _filterDB(this.addonDB, aAddon => aTypes.includes(aAddon.type));
},
/**
* Asynchronously gets all add-ons with pending operations.
*
- * @param aTypes
- * The types of add-ons to retrieve or null to get all types
+ * @param {Array<string>?} aTypes
+ * The types of add-ons to retrieve or null to get all types
+ * @returns {Promise<Array<DBAddonInternal>>}
*/
getVisibleAddonsWithPendingOperations(aTypes) {
return this.getAddonList(
aAddon => (aAddon.visible &&
aAddon.pendingUninstall &&
(!aTypes || (aTypes.length == 0) || (aTypes.indexOf(aAddon.type) > -1))));
},
/**
* Asynchronously get an add-on by its Sync GUID.
*
- * @param aGUID
- * Sync GUID of add-on to fetch
+ * @param {string} aGUID
+ * Sync GUID of add-on to fetch
+ * @returns {Promise<DBAddonInternal?>}
*/
getAddonBySyncGUID(aGUID) {
return this.getAddon(aAddon => aAddon.syncGUID == aGUID);
},
/**
* Synchronously gets all add-ons in the database.
* This is only called from the preference observer for the default
* compatibility version preference, so we can return an empty list if
* we haven't loaded the database yet.
*
- * @return an array of DBAddonInternals
+ * @returns {Array<DBAddonInternal>}
*/
getAddons() {
if (!this.addonDB) {
return [];
}
return _filterDB(this.addonDB, aAddon => true);
},
/**
* Synchronously adds an AddonInternal's metadata to the database.
*
- * @param aAddon
- * AddonInternal to add
- * @param aPath
- * The file path of the add-on
- * @return The DBAddonInternal that was added to the database
+ * @param {AddonInternal} aAddon
+ * AddonInternal to add
+ * @param {string} aPath
+ * The file path of the add-on
+ * @returns {DBAddonInternal}
+ * the DBAddonInternal that was added to the database
*/
addAddonMetadata(aAddon, aPath) {
if (!this.addonDB) {
AddonManagerPrivate.recordSimpleMeasure("XPIDB_lateOpen_addMetadata",
XPIProvider.runPhase);
this.syncLoadDB(false);
}
@@ -776,23 +831,24 @@ this.XPIDatabase = {
this.saveChanges();
return newAddon;
},
/**
* Synchronously updates an add-on's metadata in the database. Currently just
* removes and recreates.
*
- * @param aOldAddon
- * The DBAddonInternal to be replaced
- * @param aNewAddon
- * The new AddonInternal to add
- * @param aPath
- * The file path of the add-on
- * @return The DBAddonInternal that was added to the database
+ * @param {DBAddonInternal} aOldAddon
+ * The DBAddonInternal to be replaced
+ * @param {AddonInternal} aNewAddon
+ * The new AddonInternal to add
+ * @param {string} aPath
+ * The file path of the add-on
+ * @returns {DBAddonInternal}
+ * The DBAddonInternal that was added to the database
*/
updateAddonMetadata(aOldAddon, aNewAddon, aPath) {
this.removeAddonMetadata(aOldAddon);
aNewAddon.syncGUID = aOldAddon.syncGUID;
aNewAddon.installDate = aOldAddon.installDate;
aNewAddon.applyBackgroundUpdates = aOldAddon.applyBackgroundUpdates;
aNewAddon.foreignInstall = aOldAddon.foreignInstall;
aNewAddon.seen = aOldAddon.seen;
@@ -800,18 +856,18 @@ this.XPIDatabase = {
// addAddonMetadata does a saveChanges()
return this.addAddonMetadata(aNewAddon, aPath);
},
/**
* Synchronously removes an add-on from the database.
*
- * @param aAddon
- * The DBAddonInternal being removed
+ * @param {DBAddonInternal} aAddon
+ * The DBAddonInternal being removed
*/
removeAddonMetadata(aAddon) {
this.addonDB.delete(aAddon._key);
this.saveChanges();
},
updateXPIStates(addon) {
let xpiState = XPIStates.getAddon(addon.location, addon.id);
@@ -820,18 +876,18 @@ this.XPIDatabase = {
XPIStates.save();
}
},
/**
* Synchronously marks a DBAddonInternal as visible marking all other
* instances with the same ID as not visible.
*
- * @param aAddon
- * The DBAddonInternal to make visible
+ * @param {DBAddonInternal} aAddon
+ * The DBAddonInternal to make visible
*/
makeAddonVisible(aAddon) {
logger.debug("Make addon " + aAddon._key + " visible");
for (let [, otherAddon] of this.addonDB) {
if ((otherAddon.id == aAddon.id) && (otherAddon._key != aAddon._key)) {
logger.debug("Hide addon " + otherAddon._key);
otherAddon.visible = false;
otherAddon.active = false;
@@ -843,18 +899,22 @@ this.XPIDatabase = {
this.updateXPIStates(aAddon);
this.saveChanges();
},
/**
* Synchronously marks a given add-on ID visible in a given location,
* instances with the same ID as not visible.
*
- * @param aAddon
- * The DBAddonInternal to make visible
+ * @param {string} aId
+ * The ID of the add-on to make visible
+ * @param {InstallLocation} aLocation
+ * The location in which to make the add-on visible.
+ * @returns {DBAddonInternal?}
+ * The add-on instance which was marked visible, if any.
*/
makeAddonLocationVisible(aId, aLocation) {
logger.debug(`Make addon ${aId} visible in location ${aLocation}`);
let result;
for (let [, addon] of this.addonDB) {
if (addon.id != aId) {
continue;
}
@@ -873,36 +933,36 @@ this.XPIDatabase = {
}
this.saveChanges();
return result;
},
/**
* Synchronously sets properties for an add-on.
*
- * @param aAddon
- * The DBAddonInternal being updated
- * @param aProperties
- * A dictionary of properties to set
+ * @param {DBAddonInternal} aAddon
+ * The DBAddonInternal being updated
+ * @param {Object} aProperties
+ * A dictionary of properties to set
*/
setAddonProperties(aAddon, aProperties) {
for (let key in aProperties) {
aAddon[key] = aProperties[key];
}
this.saveChanges();
},
/**
* Synchronously sets the Sync GUID for an add-on.
* Only called when the database is already loaded.
*
- * @param aAddon
- * The DBAddonInternal being updated
- * @param aGUID
- * GUID string to set the value to
+ * @param {DBAddonInternal} aAddon
+ * The DBAddonInternal being updated
+ * @param {string} aGUID
+ * GUID string to set the value to
* @throws if another addon already has the specified GUID
*/
setAddonSyncGUID(aAddon, aGUID) {
// Need to make sure no other addon has this GUID
function excludeSyncGUID(otherAddon) {
return (otherAddon._key != aAddon._key) && (otherAddon.syncGUID == aGUID);
}
let otherAddon = _findAddon(this.addonDB, excludeSyncGUID);
@@ -912,18 +972,20 @@ this.XPIDatabase = {
}
aAddon.syncGUID = aGUID;
this.saveChanges();
},
/**
* Synchronously updates an add-on's active flag in the database.
*
- * @param aAddon
- * The DBAddonInternal to update
+ * @param {DBAddonInternal} aAddon
+ * The DBAddonInternal to update
+ * @param {boolean} aActive
+ * The new active state for the add-on.
*/
updateAddonActive(aAddon, aActive) {
logger.debug("Updating active state for add-on " + aAddon.id + " to " + aActive);
aAddon.active = aActive;
this.saveChanges();
},
@@ -948,16 +1010,22 @@ this.XPIDatabase = {
}
},
};
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.
+ *
+ * @param {Map<String, AddonInternal>} addonMap
+ * The add-on map to flatten.
+ * @param {string?} [hideLocation]
+ * An optional location from which to hide any add-ons.
+ * @returns {Map<string, AddonInternal>}
*/
flattenByID(addonMap, hideLocation) {
let map = new Map();
for (let installLocation of XPIProvider.installLocations) {
if (installLocation.name == hideLocation)
continue;
@@ -971,16 +1039,20 @@ this.XPIDatabaseReconcile = {
}
}
return map;
},
/**
* Finds the visible add-ons from the map.
+ *
+ * @param {Map<String, AddonInternal>} addonMap
+ * The add-on map to filter.
+ * @returns {Map<string, AddonInternal>}
*/
getVisibleAddons(addonMap) {
let map = new Map();
for (let addons of addonMap.values()) {
for (let [id, addon] of addons) {
if (!addon.visible)
continue;
@@ -1000,32 +1072,33 @@ this.XPIDatabaseReconcile = {
/**
* 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
- * @return a boolean indicating if flushing caches is required to complete
- * changing this add-on
+ * @param {InstallLocation} aInstallLocation
+ * The install location containing the add-on
+ * @param {string} aId
+ * The ID of the add-on
+ * @param {XPIState} aAddonState
+ * The new state of the add-on
+ * @param {AddonInternal?} [aNewAddon]
+ * The manifest for the new add-on if it has already been loaded
+ * @param {string?} [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 {string?} [aOldPlatformVersion]
+ * The version of the platform last run with this profile or null
+ * if it is a new profile or the version is unknown
+ * @returns {boolean}
+ * A boolean indicating if flushing caches is required to complete
+ * changing this add-on
*/
addMetadata(aInstallLocation, aId, aAddonState, aNewAddon, aOldAppVersion,
aOldPlatformVersion) {
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.
@@ -1087,43 +1160,42 @@ this.XPIDatabaseReconcile = {
}
return XPIDatabase.addAddonMetadata(aNewAddon, aAddonState.path);
},
/**
* 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
+ * @param {AddonInternal} aOldAddon
+ * The AddonInternal as it appeared the last time the application
+ * ran
*/
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. 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
+ * @param {InstallLocation} aInstallLocation
+ * The install location containing the add-on
+ * @param {AddonInternal} aOldAddon
+ * The AddonInternal as it appeared the last time the application
+ * ran
+ * @param {XPIState} aAddonState
+ * The new state of the add-on
+ * @param {AddonInternal?} [aNewAddon]
+ * The manifest for the new add-on if it has already been loaded
+ * @returns {boolean?}
+ * 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 = new nsIFile(aAddonState.path);
@@ -1152,49 +1224,49 @@ this.XPIDatabaseReconcile = {
// Update the database
return XPIDatabase.updateAddonMetadata(aOldAddon, aNewAddon, aAddonState.path);
},
/**
* Updates an add-on's path 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
+ * @param {InstallLocation} aInstallLocation
+ * The install location containing the add-on
+ * @param {AddonInternal} aOldAddon
+ * The AddonInternal as it appeared the last time the application
+ * ran
+ * @param {XPIState} aAddonState
+ * The new state of the add-on
+ * @returns {AddonInternal}
*/
updatePath(aInstallLocation, aOldAddon, aAddonState) {
logger.debug("Add-on " + aOldAddon.id + " moved to " + aAddonState.path);
aOldAddon.path = aAddonState.path;
aOldAddon._sourceBundle = new nsIFile(aAddonState.path);
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 aReloadMetadata
- * A boolean which indicates whether metadata should be reloaded from
- * the addon manifests. Default to false.
- * @return the new addon.
+ * @param {InstallLocation} aInstallLocation
+ * The install location containing the add-on
+ * @param {AddonInternal} aOldAddon
+ * The AddonInternal as it appeared the last time the application
+ * ran
+ * @param {XPIState} aAddonState
+ * The new state of the add-on
+ * @param {boolean} [aReloadMetadata = false]
+ * A boolean which indicates whether metadata should be reloaded from
+ * the addon manifests. Default to false.
+ * @returns {DBAddonInternal}
+ * The new addon.
*/
updateCompatibility(aInstallLocation, aOldAddon, aAddonState, aReloadMetadata) {
logger.debug("Updating compatibility for add-on " + aOldAddon.id + " in " + aInstallLocation.name);
let checkSigning = aOldAddon.signedState === undefined && ADDON_SIGNING &&
SIGNED_TYPES.has(aOldAddon.type);
let manifest = null;
@@ -1237,32 +1309,33 @@ this.XPIDatabaseReconcile = {
/**
* 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
- * @param aSchemaChange
- * The schema has changed and all add-on manifests should be re-read.
- * @return a boolean indicating if a change requiring flushing the caches was
- * detected
+ * @param {Object} aManifests
+ * A dictionary of cached AddonInstalls for add-ons that have been
+ * installed
+ * @param {boolean} aUpdateCompatibility
+ * true to update add-ons appDisabled property when the application
+ * version has changed
+ * @param {string?} [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 {string?} [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 {boolean} aSchemaChange
+ * The schema has changed and all add-on manifests should be re-read.
+ * @returns {boolean}
+ * A boolean indicating if a change requiring flushing the caches was
+ * detected
*/
processFileChanges(aManifests, aUpdateCompatibility, aOldAppVersion, aOldPlatformVersion,
aSchemaChange) {
let loadedManifest = (aInstallLocation, aId) => {
if (!(aInstallLocation.name in aManifests))
return null;
if (!(aId in aManifests[aInstallLocation.name]))
return null;