Bug 1462516: Move more XPI database code out of XPIProvider.jsm. r=aswan

MozReview-Commit-ID: IIoP5GPa4Cu

--HG--
extra : rebase_source : 4993834aa10f1a763ce12c72db44aa0af0f1395e
This commit is contained in:
Kris Maglione 2018-05-17 18:44:01 -07:00
parent f6471189bd
commit 10b1f3e064
14 changed files with 266 additions and 415 deletions

View File

@ -738,16 +738,7 @@ class AddonValidator extends CollectionValidator {
}
async getClientItems() {
const installed = await AddonManager.getAllAddons();
const addonsWithPendingOperation = await AddonManager.getAddonsWithOperationsByTypes(["extension", "theme"]);
// Addons pending install won't be in the first list, but addons pending
// uninstall/enable/disable will be in both lists.
let all = new Map(installed.map(addon => [addon.id, addon]));
for (let addon of addonsWithPendingOperation) {
all.set(addon.id, addon);
}
// Convert to an array since Map.prototype.values returns an iterable
return [...all.values()];
return AddonManager.getAllAddons();
}
normalizeClientItem(item) {

View File

@ -2331,37 +2331,6 @@ var AddonManagerInternal = {
return this.getAddonsByTypes(null);
},
/**
* Asynchronously gets add-ons that have operations waiting for an application
* restart to complete.
*
* @param aTypes
* An optional array of types to retrieve. Each type is a string name
*/
getAddonsWithOperationsByTypes(aTypes) {
if (!gStarted)
throw Components.Exception("AddonManager is not initialized",
Cr.NS_ERROR_NOT_INITIALIZED);
if (aTypes && !Array.isArray(aTypes))
throw Components.Exception("aTypes must be an array or null",
Cr.NS_ERROR_INVALID_ARG);
return (async () => {
let addons = [];
for (let provider of this.providers) {
let providerAddons = await promiseCallProvider(
provider, "getAddonsWithOperationsByTypes", aTypes);
if (providerAddons)
addons.push(...providerAddons);
}
return addons;
})();
},
/**
* Adds a new AddonManagerListener if the listener is not already registered.
*
@ -3389,10 +3358,6 @@ var AddonManager = {
return AddonManagerInternal.getAddonsByIDs(aIDs);
},
getAddonsWithOperationsByTypes(aTypes) {
return AddonManagerInternal.getAddonsWithOperationsByTypes(aTypes);
},
getAddonsByTypes(aTypes) {
return AddonManagerInternal.getAddonsByTypes(aTypes);
},

View File

@ -122,16 +122,6 @@ var PluginProvider = {
id => this.getAddonByID(id)));
},
/**
* Called to get Addons that have pending operations.
*
* @param aTypes
* An array of types to fetch. Can be null to get all types
*/
async getAddonsWithOperationsByTypes(aTypes) {
return [];
},
/**
* Called to get the current AddonInstalls, optionally restricting by type.
*

View File

@ -28,6 +28,7 @@ XPCOMUtils.defineLazyModuleGetters(this, {
ExtensionUtils: "resource://gre/modules/ExtensionUtils.jsm",
FileUtils: "resource://gre/modules/FileUtils.jsm",
OS: "resource://gre/modules/osfile.jsm",
PermissionsUtils: "resource://gre/modules/PermissionsUtils.jsm",
Services: "resource://gre/modules/Services.jsm",
Blocklist: "resource://gre/modules/Blocklist.jsm",
@ -35,6 +36,7 @@ XPCOMUtils.defineLazyModuleGetters(this, {
UpdateChecker: "resource://gre/modules/addons/XPIInstall.jsm",
XPIInstall: "resource://gre/modules/addons/XPIInstall.jsm",
XPIInternal: "resource://gre/modules/addons/XPIProvider.jsm",
XPIProvider: "resource://gre/modules/addons/XPIProvider.jsm",
verifyBundleSignedState: "resource://gre/modules/addons/XPIInstall.jsm",
});
@ -44,23 +46,15 @@ const {nsIBlocklistService} = Ci;
/* globals
* BOOTSTRAP_REASONS,
* DB_SCHEMA,
* SIGNED_TYPES,
* XPIProvider,
* XPIStates,
* isTheme,
* isWebExtension,
* recordAddonTelemetry,
*/
for (let sym of [
"BOOTSTRAP_REASONS",
"DB_SCHEMA",
"SIGNED_TYPES",
"XPIProvider",
"XPIStates",
"isTheme",
"isWebExtension",
"recordAddonTelemetry",
]) {
XPCOMUtils.defineLazyGetter(this, sym, () => XPIInternal[sym]);
}
@ -88,6 +82,7 @@ const PREF_DB_SCHEMA = "extensions.databaseSchema";
const PREF_EM_AUTO_DISABLED_SCOPES = "extensions.autoDisableScopes";
const PREF_EM_EXTENSION_FORMAT = "extensions.";
const PREF_PENDING_OPERATIONS = "extensions.pendingOperations";
const PREF_XPI_PERMISSIONS_BRANCH = "xpinstall.";
const PREF_XPI_SIGNATURES_DEV_ROOT = "xpinstall.signatures.dev-root";
const TOOLKIT_ID = "toolkit@mozilla.org";
@ -137,6 +132,22 @@ const LEGACY_TYPES = new Set([
"extension",
]);
// Some add-on types that we track internally are presented as other types
// externally
const TYPE_ALIASES = {
"webextension": "extension",
"webextension-dictionary": "dictionary",
"webextension-langpack": "locale",
"webextension-theme": "theme",
};
const SIGNED_TYPES = new Set([
"extension",
"webextension",
"webextension-langpack",
"webextension-theme",
]);
// Time to wait before async save of XPI JSON database, in milliseconds
const ASYNC_SAVE_DELAY_MS = 20;
@ -195,6 +206,46 @@ async function getRepositoryAddon(aAddon) {
return aAddon;
}
/**
* Helper function that determines whether an addon of a certain type is a
* theme.
*
* @param {string} type
* The add-on type to check.
* @returns {boolean}
*/
function isTheme(type) {
return type == "theme" || TYPE_ALIASES[type] == "theme";
}
/**
* Converts a list of API types to a list of API types and any aliases for those
* types.
*
* @param {Array<string>?} aTypes
* An array of types or null for all types
* @returns {Set<string>?}
* An set of types or null for all types
*/
function getAllAliasesForTypes(aTypes) {
if (!aTypes)
return null;
let types = new Set(aTypes);
for (let [alias, type] of Object.entries(TYPE_ALIASES)) {
// Add any alias for the internal type
if (types.has(type)) {
types.add(alias);
} else {
// If this internal type was explicitly requested and its external
// type wasn't, ignore it.
types.delete(alias);
}
}
return types;
}
/**
* Copies properties from one object to another. If no target object is passed
* a new object will be created and returned.
@ -667,7 +718,7 @@ AddonWrapper = class {
}
get type() {
return XPIInternal.getExternalType(addonFor(this).type);
return XPIDatabase.getExternalType(addonFor(this).type);
}
get isWebExtension() {
@ -1676,6 +1727,15 @@ this.XPIDatabase = {
}
},
/**
* Imports the xpinstall permissions from preferences into the permissions
* manager for the user to change later.
*/
importPermissions() {
PermissionsUtils.importFromPrefs(PREF_XPI_PERMISSIONS_BRANCH,
XPIInternal.XPI_PERMISSION);
},
/**
* Called when a new add-on has been enabled when only one add-on of that type
* can be enabled.
@ -1707,6 +1767,23 @@ this.XPIDatabase = {
}
},
/**
* Converts an internal add-on type to the type presented through the API.
*
* @param {string} aType
* The internal add-on type
* @returns {string}
* An external add-on type
*/
getExternalType(aType) {
if (aType in TYPE_ALIASES)
return TYPE_ALIASES[aType];
return aType;
},
isTheme,
SIGNED_TYPES,
/**
* Asynchronously list all addons that match the filter function
*
@ -1795,14 +1872,13 @@ this.XPIDatabase = {
/**
* Asynchronously gets the visible add-ons, optionally restricting by type.
*
* @param {Array<string>?} aTypes
* @param {Set<string>?} aTypes
* An array of types to include or null to include all types
* @returns {Promise<Array<AddonInternal>>}
*/
getVisibleAddons(aTypes) {
return this.getAddonList(aAddon => (aAddon.visible &&
(!aTypes || (aTypes.length == 0) ||
(aTypes.indexOf(aAddon.type) > -1))));
(!aTypes || aTypes.has(aAddon.type))));
},
/**
@ -1830,7 +1906,7 @@ this.XPIDatabase = {
/**
* Asynchronously gets all add-ons with pending operations.
*
* @param {Array<string>?} aTypes
* @param {Set<string>?} aTypes
* The types of add-ons to retrieve or null to get all types
* @returns {Promise<Array<AddonInternal>>}
*/
@ -1838,18 +1914,7 @@ this.XPIDatabase = {
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 {string} aGUID
* Sync GUID of add-on to fetch
* @returns {Promise<AddonInternal?>}
*/
getAddonBySyncGUID(aGUID) {
return this.getAddon(aAddon => aAddon.syncGUID == aGUID);
(!aTypes || aTypes.has(aAddon.type))));
},
/**
@ -1867,6 +1932,61 @@ this.XPIDatabase = {
return _filterDB(this.addonDB, aAddon => true);
},
/**
* Called to get an Addon with a particular ID.
*
* @param {string} aId
* The ID of the add-on to retrieve
* @returns {Addon?}
*/
async getAddonByID(aId) {
let aAddon = await this.getVisibleAddonForID(aId);
return aAddon ? aAddon.wrapper : null;
},
/**
* Synchronously returns the Addon object for the add-on with the
* given ID.
*
* *DO NOT USE THIS IF YOU CAN AT ALL AVOID IT*
*
* This will always return null if the add-on database has not been
* loaded, and the resulting Addon object may not yet include a
* reference to its corresponding repository add-on object.
*
* @param {string} aId
* The ID of the add-on to return.
* @returns {DBAddonInternal?}
* The Addon object, if available.
*/
syncGetAddonByID(aId) {
let aAddon = this.syncGetVisibleAddonForID(aId);
return aAddon ? aAddon.wrapper : null;
},
/**
* Obtain an Addon having the specified Sync GUID.
*
* @param {string} aGUID
* String GUID of add-on to retrieve
* @returns {Addon?}
*/
async getAddonBySyncGUID(aGUID) {
let addon = await this.getAddon(aAddon => aAddon.syncGUID == aGUID);
return addon ? addon.wrapper : null;
},
/**
* Called to get Addons of a particular type.
*
* @param {Array<string>?} aTypes
* An array of types to fetch. Can be null to get all types.
* @returns {Addon[]}
*/
async getAddonsByTypes(aTypes) {
let addons = await this.getVisibleAddons(getAllAliasesForTypes(aTypes));
return addons.map(a => a.wrapper);
},
/**
* Returns true if signing is required for the given add-on type.
@ -2173,6 +2293,7 @@ this.XPIDatabase = {
XPIProvider.runPhase);
this.syncLoadDB(true);
}
logger.debug("Updating add-on states");
for (let [, addon] of this.addonDB) {
let newActive = (addon.visible && !addon.disabled && !addon.pendingUninstall);
@ -2181,6 +2302,8 @@ this.XPIDatabase = {
this.saveChanges();
}
}
Services.prefs.setBoolPref(PREF_PENDING_OPERATIONS, false);
},
/**
@ -2300,6 +2423,32 @@ this.XPIDatabase = {
return isDisabled;
},
/**
* Update the appDisabled property for all add-ons.
*/
updateAddonAppDisabledStates() {
for (let addon of this.getAddons()) {
this.updateAddonDisabledState(addon);
}
},
/**
* Update the repositoryAddon property for all add-ons.
*/
async updateAddonRepositoryData() {
let addons = await this.getVisibleAddons(null);
logger.debug("updateAddonRepositoryData found " + addons.length + " visible add-ons");
await Promise.all(addons.map(addon =>
AddonRepository.getCachedAddonByID(addon.id).then(aRepoAddon => {
if (aRepoAddon || AddonRepository.getCompatibilityOverridesSync(addon.id)) {
logger.debug("updateAddonRepositoryData got info for " + addon.id);
addon._repositoryAddon = aRepoAddon;
this.updateAddonDisabledState(addon);
}
})));
},
/**
* Record a bit of per-addon telemetry.
*

View File

@ -47,7 +47,6 @@ XPCOMUtils.defineLazyModuleGetters(this, {
InstallRDF: "resource://gre/modules/addons/RDFManifestConverter.jsm",
XPIDatabase: "resource://gre/modules/addons/XPIDatabase.jsm",
XPIInternal: "resource://gre/modules/addons/XPIProvider.jsm",
XPIProvider: "resource://gre/modules/addons/XPIProvider.jsm",
});
XPCOMUtils.defineLazyServiceGetter(this, "uuidGen",
@ -88,20 +87,18 @@ const PREF_XPI_DIRECT_WHITELISTED = "xpinstall.whitelist.directRequest";
const PREF_XPI_FILE_WHITELISTED = "xpinstall.whitelist.fileRequest";
const PREF_XPI_WHITELIST_REQUIRED = "xpinstall.whitelist.required";
/* globals BOOTSTRAP_REASONS, KEY_APP_SYSTEM_ADDONS, KEY_APP_SYSTEM_DEFAULTS, PREF_BRANCH_INSTALLED_ADDON, PREF_SYSTEM_ADDON_SET, TEMPORARY_ADDON_SUFFIX, SIGNED_TYPES, TOOLKIT_ID, XPI_PERMISSION, XPIStates, getExternalType, isTheme, isWebExtension, iterDirectory */
const TOOLKIT_ID = "toolkit@mozilla.org";
/* globals BOOTSTRAP_REASONS, KEY_APP_SYSTEM_ADDONS, KEY_APP_SYSTEM_DEFAULTS, PREF_BRANCH_INSTALLED_ADDON, PREF_SYSTEM_ADDON_SET, TEMPORARY_ADDON_SUFFIX, XPI_PERMISSION, XPIStates, isWebExtension, iterDirectory */
const XPI_INTERNAL_SYMBOLS = [
"BOOTSTRAP_REASONS",
"KEY_APP_SYSTEM_ADDONS",
"KEY_APP_SYSTEM_DEFAULTS",
"PREF_BRANCH_INSTALLED_ADDON",
"PREF_SYSTEM_ADDON_SET",
"SIGNED_TYPES",
"TEMPORARY_ADDON_SUFFIX",
"TOOLKIT_ID",
"XPI_PERMISSION",
"XPIStates",
"getExternalType",
"isTheme",
"isWebExtension",
"iterDirectory",
];
@ -110,6 +107,10 @@ for (let name of XPI_INTERNAL_SYMBOLS) {
XPCOMUtils.defineLazyGetter(this, name, () => XPIInternal[name]);
}
function isTheme(type) {
return XPIDatabase.isTheme(type);
}
/**
* Returns a nsIFile instance for the given path, relative to the given
* base file, if provided.
@ -960,7 +961,7 @@ function shouldVerifySignedState(aAddon) {
// Otherwise only check signatures if signing is enabled and the add-on is one
// of the signed types.
return AddonSettings.ADDON_SIGNING && SIGNED_TYPES.has(aAddon.type);
return AddonSettings.ADDON_SIGNING && XPIDatabase.SIGNED_TYPES.has(aAddon.type);
}
/**
@ -2447,7 +2448,7 @@ AddonInstallWrapper.prototype = {
},
get type() {
return getExternalType(installFor(this).type);
return XPIDatabase.getExternalType(installFor(this).type);
},
get iconURL() {
@ -2522,7 +2523,7 @@ var UpdateChecker = function(aAddon, aListener, aReason, aAppVersion, aPlatformV
this.addon = aAddon;
aAddon._updateCheck = this;
XPIProvider.doing(this);
XPIInstall.doing(this);
this.listener = aListener;
this.appVersion = aAppVersion;
this.platformVersion = aPlatformVersion;
@ -2583,7 +2584,7 @@ UpdateChecker.prototype = {
* The list of update details for the add-on
*/
async onUpdateCheckComplete(aUpdates) {
XPIProvider.done(this.addon._updateCheck);
XPIInstall.done(this.addon._updateCheck);
this.addon._updateCheck = null;
let AUC = AddonUpdateChecker;
@ -2680,7 +2681,7 @@ UpdateChecker.prototype = {
* An error status
*/
onUpdateCheckError(aError) {
XPIProvider.done(this.addon._updateCheck);
XPIInstall.done(this.addon._updateCheck);
this.addon._updateCheck = null;
this.callListener("onNoCompatibilityUpdateAvailable", this.addon.wrapper);
this.callListener("onNoUpdateAvailable", this.addon.wrapper);
@ -3376,6 +3377,34 @@ var XPIInstall = {
recursiveRemove,
syncLoadManifestFromFile,
// Keep track of in-progress operations that support cancel()
_inProgress: [],
doing(aCancellable) {
this._inProgress.push(aCancellable);
},
done(aCancellable) {
let i = this._inProgress.indexOf(aCancellable);
if (i != -1) {
this._inProgress.splice(i, 1);
return true;
}
return false;
},
cancelAll() {
// Cancelling one may alter _inProgress, so don't use a simple iterator
while (this._inProgress.length > 0) {
let c = this._inProgress.shift();
try {
c.cancel();
} catch (e) {
logger.warn("Cancel failed", e);
}
}
},
/**
* @param {string} id
* The expected ID of the add-on.
@ -3677,7 +3706,7 @@ var XPIInstall = {
(uri.schemeIs("chrome") || uri.schemeIs("file")))
return true;
XPIProvider.importPermissions();
XPIDatabase.importPermissions();
let permission = Services.perms.testPermissionFromPrincipal(aInstallingPrincipal, XPI_PERMISSION);
if (permission == Ci.nsIPermissionManager.DENY_ACTION)
@ -3758,7 +3787,7 @@ var XPIInstall = {
let results = [...this.installs];
if (aTypes) {
results = results.filter(install => {
return aTypes.includes(getExternalType(install.type));
return aTypes.includes(XPIDatabase.getExternalType(install.type));
});
}

View File

@ -26,14 +26,12 @@ ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
ChromeUtils.import("resource://gre/modules/AddonManager.jsm");
XPCOMUtils.defineLazyModuleGetters(this, {
AddonRepository: "resource://gre/modules/addons/AddonRepository.jsm",
AppConstants: "resource://gre/modules/AppConstants.jsm",
AsyncShutdown: "resource://gre/modules/AsyncShutdown.jsm",
Dictionary: "resource://gre/modules/Extension.jsm",
Extension: "resource://gre/modules/Extension.jsm",
Langpack: "resource://gre/modules/Extension.jsm",
FileUtils: "resource://gre/modules/FileUtils.jsm",
PermissionsUtils: "resource://gre/modules/PermissionsUtils.jsm",
OS: "resource://gre/modules/osfile.jsm",
ConsoleAPI: "resource://gre/modules/Console.jsm",
JSONFile: "resource://gre/modules/JSONFile.jsm",
@ -62,7 +60,6 @@ const PREF_EM_STARTUP_SCAN_SCOPES = "extensions.startupScanScopes";
// xpinstall.signatures.required only supported in dev builds
const PREF_XPI_SIGNATURES_REQUIRED = "xpinstall.signatures.required";
const PREF_LANGPACK_SIGNATURES = "extensions.langpacks.signatures.required";
const PREF_XPI_PERMISSIONS_BRANCH = "xpinstall.";
const PREF_INSTALL_DISTRO_ADDONS = "extensions.installDistroAddons";
const PREF_BRANCH_INSTALLED_ADDON = "extensions.installedDistroAddon.";
const PREF_SYSTEM_ADDON_SET = "extensions.systemAddonSet";
@ -81,7 +78,6 @@ const DIR_STAGE = "staged";
const DIR_TRASH = "trash";
const FILE_XPI_STATES = "addonStartup.json.lz4";
const FILE_DATABASE = "extensions.json";
const KEY_PROFILEDIR = "ProfD";
const KEY_ADDON_APP_DIR = "XREAddonAppDir";
@ -107,11 +103,9 @@ const STARTUP_MTIME_SCOPES = [KEY_APP_GLOBAL,
const NOTIFICATION_FLUSH_PERMISSIONS = "flush-pending-permissions";
const XPI_PERMISSION = "install";
const TOOLKIT_ID = "toolkit@mozilla.org";
const XPI_SIGNATURE_CHECK_PERIOD = 24 * 60 * 60;
XPCOMUtils.defineConstant(this, "DB_SCHEMA", 26);
const DB_SCHEMA = 26;
const NOTIFICATION_TOOLBOX_CONNECTION_CHANGE = "toolbox-connection-change";
@ -138,22 +132,6 @@ const BOOTSTRAP_REASONS = {
ADDON_DOWNGRADE: 8
};
// Some add-on types that we track internally are presented as other types
// externally
const TYPE_ALIASES = {
"webextension": "extension",
"webextension-dictionary": "dictionary",
"webextension-langpack": "locale",
"webextension-theme": "theme",
};
const SIGNED_TYPES = new Set([
"extension",
"webextension",
"webextension-langpack",
"webextension-theme",
]);
const ALL_EXTERNAL_TYPES = new Set([
"dictionary",
"extension",
@ -265,18 +243,6 @@ function isWebExtension(type) {
return type == "webextension" || type == "webextension-theme";
}
/**
* Helper function that determines whether an addon of a certain type is a
* theme.
*
* @param {string} type
* The add-on type to check.
* @returns {boolean}
*/
function isTheme(type) {
return type == "theme" || TYPE_ALIASES[type] == "theme";
}
/**
* Returns true if the given file, based on its name, should be treated
* as an XPI. If the file does not have an appropriate extension, it is
@ -326,62 +292,20 @@ function getExpectedID(file) {
* True if the add-on should run in safe mode
*/
function canRunInSafeMode(aAddon) {
let location = aAddon.location || null;
if (!location) {
return false;
}
// Even though the updated system add-ons aren't generally run in safe mode we
// include them here so their uninstall functions get called when switching
// back to the default set.
// TODO product should make the call about temporary add-ons running
// in safe mode. assuming for now that they are.
let location = aAddon.location || null;
if (!location) {
return false;
}
return location.isTemporary || location.isSystem;
}
/**
* Converts an internal add-on type to the type presented through the API.
*
* @param {string} aType
* The internal add-on type
* @returns {string}
* An external add-on type
*/
function getExternalType(aType) {
if (aType in TYPE_ALIASES)
return TYPE_ALIASES[aType];
return aType;
}
/**
* Converts a list of API types to a list of API types and any aliases for those
* types.
*
* @param {Array<string>?} aTypes
* An array of types or null for all types
* @returns {Array<string>?}
* An array of types or null for all types
*/
function getAllAliasesForTypes(aTypes) {
if (!aTypes)
return null;
// Build a set of all requested types and their aliases
let typeset = new Set(aTypes);
for (let alias of Object.keys(TYPE_ALIASES)) {
// Ignore any requested internal types
typeset.delete(alias);
// Add any alias for the internal type
if (typeset.has(TYPE_ALIASES[alias]))
typeset.add(alias);
}
return [...typeset];
}
/**
* Gets an nsIURI for a file within another file, either a directory or an XPI
* file. If aFile is a directory then this will return a file: URI, if it is an
@ -2026,34 +1950,6 @@ var XPIProvider = {
this._telemetryDetails[aId][aName] = aValue;
},
// Keep track of in-progress operations that support cancel()
_inProgress: [],
doing(aCancellable) {
this._inProgress.push(aCancellable);
},
done(aCancellable) {
let i = this._inProgress.indexOf(aCancellable);
if (i != -1) {
this._inProgress.splice(i, 1);
return true;
}
return false;
},
cancelAll() {
// Cancelling one may alter _inProgress, so don't use a simple iterator
while (this._inProgress.length > 0) {
let c = this._inProgress.shift();
try {
c.cancel();
} catch (e) {
logger.warn("Cancel failed", e);
}
}
},
setupInstallLocations(aAppChanged) {
function DirectoryLoc(aName, aScope, aKey, aPaths, aLocked) {
try {
@ -2321,12 +2217,12 @@ var XPIProvider = {
async shutdown() {
logger.debug("shutdown");
// Stop anything we were doing asynchronously
this.cancelAll();
this.activeAddons.clear();
this.allAppGlobal = true;
// Stop anything we were doing asynchronously
XPIInstall.cancelAll();
for (let install of XPIInstall.installs) {
if (install.onShutdown()) {
install.onShutdown();
@ -2389,13 +2285,7 @@ var XPIProvider = {
*/
addAddonsToCrashReporter() {
if (!(Services.appinfo instanceof Ci.nsICrashReporter) ||
!AppConstants.MOZ_CRASHREPORTER) {
return;
}
// In safe mode no add-ons are loaded so we should not include them in the
// crash report
if (Services.appinfo.inSafeMode) {
Services.appinfo.inSafeMode) {
return;
}
@ -2532,15 +2422,6 @@ var XPIProvider = {
return addons;
},
/**
* Imports the xpinstall permissions from preferences into the permissions
* manager for the user to change later.
*/
importPermissions() {
PermissionsUtils.importFromPrefs(PREF_XPI_PERMISSIONS_BRANCH,
XPI_PERMISSION);
},
getDependentAddons(aAddon) {
return Array.from(XPIDatabase.getAddons())
.filter(addon => addon.dependencies.includes(aAddon.id));
@ -2605,13 +2486,11 @@ var XPIProvider = {
}
}
let haveAnyAddons = (XPIStates.size > 0);
// If the schema appears to have changed then we should update the database
if (DB_SCHEMA != Services.prefs.getIntPref(PREF_DB_SCHEMA, 0)) {
// If we don't have any add-ons, just update the pref, since we don't need to
// write the database
if (!haveAnyAddons) {
if (!XPIStates.size) {
logger.debug("Empty XPI database, setting schema version preference to " + DB_SCHEMA);
Services.prefs.setIntPref(PREF_DB_SCHEMA, DB_SCHEMA);
} else {
@ -2619,14 +2498,6 @@ var XPIProvider = {
}
}
// If the database doesn't exist and there are add-ons installed then we
// must update the database however if there are no add-ons then there is
// no need to update the database.
let dbFile = FileUtils.getFile(KEY_PROFILEDIR, [FILE_DATABASE], true);
if (!dbFile.exists() && haveAnyAddons) {
updateReasons.push("needNewDatabase");
}
// Catch and log any errors during the main startup
try {
let extensionListChanged = false;
@ -2649,7 +2520,7 @@ var XPIProvider = {
// If the application crashed before completing any pending operations then
// we should perform them now.
if (extensionListChanged || hasPendingChanges) {
this._updateActiveAddons();
XPIDatabase.updateActiveAddons();
return true;
}
@ -2661,12 +2532,6 @@ var XPIProvider = {
return false;
},
_updateActiveAddons() {
logger.debug("Updating database with changes to installed add-ons");
XPIDatabase.updateActiveAddons();
Services.prefs.setBoolPref(PREF_PENDING_OPERATIONS, false);
},
/**
* Gets an array of add-ons which were placed in a known install location
* prior to startup of the current session, were detected by a directory scan
@ -2679,7 +2544,7 @@ var XPIProvider = {
// We detected changes. Update the database to account for them.
await XPIDatabase.asyncLoadDB(false);
XPIDatabaseReconcile.processFileChanges({}, false);
this._updateActiveAddons();
XPIDatabase.updateActiveAddons();
}
let addons = await Promise.all(
@ -2738,7 +2603,7 @@ var XPIProvider = {
getAddonByInstanceID(aInstanceID) {
let id = this.getAddonIDByInstanceID(aInstanceID);
if (id) {
return this.syncGetAddonByID(id);
return XPIDatabase.syncGetAddonByID(id);
}
return null;
@ -2758,53 +2623,11 @@ var XPIProvider = {
return null;
},
/**
* Called to get an Addon with a particular ID.
*
* @param {string} aId
* The ID of the add-on to retrieve
* @returns {Addon?}
*/
async getAddonByID(aId) {
let aAddon = await XPIDatabase.getVisibleAddonForID(aId);
return aAddon ? aAddon.wrapper : null;
},
/**
* Synchronously returns the Addon object for the add-on with the
* given ID.
*
* *DO NOT USE THIS IF YOU CAN AT ALL AVOID IT*
*
* This will always return null if the add-on database has not been
* loaded, and the resulting Addon object may not yet include a
* reference to its corresponding repository add-on object.
*
* @param {string} aId
* The ID of the add-on to return.
* @returns {DBAddonInternal?}
* The Addon object, if available.
*/
syncGetAddonByID(aId) {
let aAddon = XPIDatabase.syncGetVisibleAddonForID(aId);
return aAddon ? aAddon.wrapper : null;
},
/**
* Called to get Addons of a particular type.
*
* @param {Array<string>?} aTypes
* An array of types to fetch. Can be null to get all types.
* @returns {Addon[]}
*/
async getAddonsByTypes(aTypes) {
let typesToGet = getAllAliasesForTypes(aTypes);
if (typesToGet && !typesToGet.some(type => ALL_EXTERNAL_TYPES.has(type))) {
if (aTypes && !aTypes.some(type => ALL_EXTERNAL_TYPES.has(type))) {
return [];
}
let addons = await XPIDatabase.getVisibleAddons(typesToGet);
return addons.map(a => a.wrapper);
return XPIDatabase.getAddonsByTypes(aTypes);
},
/**
@ -2817,7 +2640,7 @@ var XPIProvider = {
async getActiveAddons(aTypes) {
// If we already have the database loaded, returning full info is fast.
if (this.isDBLoaded) {
let addons = await this.getAddonsByTypes(aTypes);
let addons = await XPIProvider.getAddonsByTypes(aTypes);
return {
addons: addons.filter(addon => addon.isActive),
fullData: true,
@ -2854,70 +2677,6 @@ var XPIProvider = {
return {addons: result, fullData: false};
},
/**
* Obtain an Addon having the specified Sync GUID.
*
* @param {string} aGUID
* String GUID of add-on to retrieve
* @returns {Addon?}
*/
async getAddonBySyncGUID(aGUID) {
let addon = await XPIDatabase.getAddonBySyncGUID(aGUID);
return addon ? addon.wrapper : null;
},
/**
* Called to get Addons that have pending operations.
*
* @param {Array<string>?} aTypes
* An array of types to fetch. Can be null to get all types
* @returns {Addon[]}
*/
async getAddonsWithOperationsByTypes(aTypes) {
let typesToGet = getAllAliasesForTypes(aTypes);
let aAddons = await XPIDatabase.getVisibleAddonsWithPendingOperations(typesToGet);
let results = aAddons.map(a => a.wrapper);
for (let install of XPIInstall.installs) {
if (install.state == AddonManager.STATE_INSTALLED &&
!(install.addon.inDatabase))
results.push(install.addon.wrapper);
}
return results;
},
addonChanged(id, type) {
XPIDatabase.addonChanged(id, type);
},
/**
* Update the appDisabled property for all add-ons.
*/
updateAddonAppDisabledStates() {
let addons = XPIDatabase.getAddons();
for (let addon of addons) {
XPIDatabase.updateAddonDisabledState(addon);
}
},
/**
* Update the repositoryAddon property for all add-ons.
*/
async updateAddonRepositoryData() {
let addons = await XPIDatabase.getVisibleAddons(null);
logger.debug("updateAddonRepositoryData found " + addons.length + " visible add-ons");
await Promise.all(addons.map(addon =>
AddonRepository.getCachedAddonByID(addon.id).then(aRepoAddon => {
if (aRepoAddon || AddonRepository.getCompatibilityOverridesSync(addon.id)) {
logger.debug("updateAddonRepositoryData got info for " + addon.id);
addon._repositoryAddon = aRepoAddon;
XPIDatabase.updateAddonDisabledState(addon);
}
})));
},
onDebugConnectionChange({what, connection}) {
if (what != "opened")
return;
@ -2934,22 +2693,23 @@ var XPIProvider = {
* @see nsIObserver
*/
observe(aSubject, aTopic, aData) {
if (aTopic == NOTIFICATION_FLUSH_PERMISSIONS) {
switch (aTopic) {
case NOTIFICATION_FLUSH_PERMISSIONS:
if (!aData || aData == XPI_PERMISSION) {
this.importPermissions();
XPIDatabase.importPermissions();
}
return;
} else if (aTopic == NOTIFICATION_TOOLBOX_CONNECTION_CHANGE) {
this.onDebugConnectionChange(aSubject.wrappedJSObject);
return;
}
break;
if (aTopic == "nsPref:changed") {
case NOTIFICATION_TOOLBOX_CONNECTION_CHANGE:
this.onDebugConnectionChange(aSubject.wrappedJSObject);
break;
case "nsPref:changed":
switch (aData) {
case PREF_XPI_SIGNATURES_REQUIRED:
case PREF_LANGPACK_SIGNATURES:
case PREF_ALLOW_LEGACY:
this.updateAddonAppDisabledStates();
XPIDatabase.updateAddonAppDisabledStates();
break;
}
}
@ -2964,6 +2724,13 @@ for (let meth of ["getInstallForFile", "getInstallForURL", "getInstallsByTypes",
};
}
for (let meth of ["addonChanged", "getAddonByID", "getAddonBySyncGUID",
"updateAddonRepositoryData", "updateAddonAppDisabledStates"]) {
XPIProvider[meth] = function() {
return XPIDatabase[meth](...arguments);
};
}
var XPIInternal = {
BOOTSTRAP_REASONS,
BootstrapScope,
@ -2972,19 +2739,14 @@ var XPIInternal = {
KEY_APP_SYSTEM_DEFAULTS,
PREF_BRANCH_INSTALLED_ADDON,
PREF_SYSTEM_ADDON_SET,
SIGNED_TYPES,
SystemAddonLocation,
TEMPORARY_ADDON_SUFFIX,
TOOLKIT_ID,
TemporaryInstallLocation,
XPIProvider,
XPIStates,
XPI_PERMISSION,
awaitPromise,
canRunInSafeMode,
getExternalType,
getURIForResourceInFile,
isTheme,
isWebExtension,
isXPI,
iterDirectory,

View File

@ -908,21 +908,6 @@ MockProvider.prototype = {
return addons;
},
/**
* Called to get Addons that have pending operations.
*
* @param aTypes
* An array of types to fetch. Can be null to get all types
*/
async getAddonsWithOperationsByTypes(aTypes, aCallback) {
var addons = this.addons.filter(function(aAddon) {
if (aTypes && aTypes.length > 0 && !aTypes.includes(aAddon.type))
return false;
return aAddon.pendingOperations != 0;
});
return addons;
},
/**
* Called to get the current AddonInstalls, optionally restricting by type.
*

View File

@ -157,7 +157,6 @@ var { AddonManager, AddonManagerInternal, AddonManagerPrivate } = AMscope;
const promiseAddonByID = AddonManager.getAddonByID;
const promiseAddonsByIDs = AddonManager.getAddonsByIDs;
const promiseAddonsWithOperationsByTypes = AddonManager.getAddonsWithOperationsByTypes;
var gPort = null;
var gUrlToFileMap = {};

View File

@ -4,12 +4,11 @@
// Test the cancellable doing/done/cancelAll API in XPIProvider
var scope = ChromeUtils.import("resource://gre/modules/addons/XPIProvider.jsm", {});
var XPIProvider = scope.XPIProvider;
ChromeUtils.import("resource://gre/modules/addons/XPIInstall.jsm");
function run_test() {
// Check that cancelling with nothing in progress doesn't blow up
XPIProvider.cancelAll();
XPIInstall.cancelAll();
// Check that a basic object gets cancelled
let getsCancelled = {
@ -20,17 +19,17 @@ function run_test() {
this.isCancelled = true;
}
};
XPIProvider.doing(getsCancelled);
XPIProvider.cancelAll();
XPIInstall.doing(getsCancelled);
XPIInstall.cancelAll();
Assert.ok(getsCancelled.isCancelled);
// Check that if we complete a cancellable, it doesn't get cancelled
let doesntGetCancelled = {
cancel: () => do_throw("This should not have been cancelled")
};
XPIProvider.doing(doesntGetCancelled);
Assert.ok(XPIProvider.done(doesntGetCancelled));
XPIProvider.cancelAll();
XPIInstall.doing(doesntGetCancelled);
Assert.ok(XPIInstall.done(doesntGetCancelled));
XPIInstall.cancelAll();
// A cancellable that adds a cancellable
getsCancelled.isCancelled = false;
@ -40,11 +39,11 @@ function run_test() {
if (this.isCancelled)
do_throw("Already cancelled");
this.isCancelled = true;
XPIProvider.doing(getsCancelled);
XPIInstall.doing(getsCancelled);
}
};
XPIProvider.doing(addsAnother);
XPIProvider.cancelAll();
XPIInstall.doing(addsAnother);
XPIInstall.cancelAll();
Assert.ok(addsAnother.isCancelled);
Assert.ok(getsCancelled.isCancelled);
@ -56,11 +55,11 @@ function run_test() {
if (this.isCancelled)
do_throw("Already cancelled");
this.isCancelled = true;
XPIProvider.done(doesntGetCancelled);
XPIInstall.done(doesntGetCancelled);
}
};
XPIProvider.doing(removesAnother);
XPIProvider.doing(doesntGetCancelled);
XPIProvider.cancelAll();
XPIInstall.doing(removesAnother);
XPIInstall.doing(doesntGetCancelled);
XPIInstall.cancelAll();
Assert.ok(removesAnother.isCancelled);
}

View File

@ -274,9 +274,6 @@ add_task(async function test_1() {
let dir = do_get_addon_root_uri(profileDir, ID1);
equal(b1.getResourceURI("bootstrap.js").spec, dir + "bootstrap.js");
let list = await AddonManager.getAddonsWithOperationsByTypes(null);
equal(list.length, 0);
});
// Tests that disabling doesn't require a restart
@ -1192,9 +1189,6 @@ add_task(async function test_23() {
let dir = do_get_addon_root_uri(profileDir, ID1);
equal(b1.getResourceURI("bootstrap.js").spec, dir + "bootstrap.js");
let list = await AddonManager.getAddonsWithOperationsByTypes(null);
equal(list.length, 0);
await promiseRestartManager();
let b1_2 = await AddonManager.getAddonByID(ID1);

View File

@ -183,9 +183,6 @@ add_task(async function test_1() {
} catch (e) {
// Expected the chrome url to not be registered
}
let list = await AddonManager.getAddonsWithOperationsByTypes(null);
equal(list.length, 0);
});
// Tests that disabling doesn't require a restart
@ -480,9 +477,6 @@ add_task(async function test_23() {
ok(!addon.hasResource("bootstrap.js"));
do_check_in_crash_annotation(ID_DICT, "1.0");
let list = await AddonManager.getAddonsWithOperationsByTypes(null);
equal(list.length, 0);
await promiseRestartManager();
addon = await AddonManager.getAddonByID(ID_DICT);

View File

@ -26,9 +26,6 @@ async function run_test_1() {
let addons = await AddonManager.getAddonsByTypes(null);
Assert.equal(gCount, addons.length);
let pendingAddons = await AddonManager.getAddonsWithOperationsByTypes(null);
Assert.equal(0, pendingAddons.length);
executeSoon(run_test_2);
}

View File

@ -203,9 +203,6 @@ add_task(async function test_1() {
addon = await AddonManager.getAddonByID("addon1@tests.mozilla.org");
ok(addon);
let pendingAddons = await AddonManager.getAddonsWithOperationsByTypes(null);
equal(pendingAddons.length, 0);
uri = NetUtil.newURI(addon.iconURL);
if (uri instanceof Ci.nsIJARURI) {
let {file} = uri.JARFile.QueryInterface(Ci.nsIFileURL);

View File

@ -8,7 +8,7 @@
// Load XPI Provider to get schema version ID
var XPIScope = ChromeUtils.import("resource://gre/modules/addons/XPIProvider.jsm", {});
const DB_SCHEMA = XPIScope.DB_SCHEMA;
const {DB_SCHEMA} = XPIScope.XPIInternal;
createAppInfo("xpcshell@tests.mozilla.org", "XPCShell", "1", "1.9.2");