author | Andrew Swan <aswan@mozilla.com> |
Wed, 21 Nov 2018 20:01:26 -0800 | |
changeset 448838 | 51bb2e2f30d2c1486ebbc75568e09976a374fe6c |
parent 448837 | efac27a2bec4fa7e81fa3c8a6d023795aa6447dc |
child 448839 | 061b97e02ede2133f50956feba25fd8798745347 |
push id | 110255 |
push user | aswan@mozilla.com |
push date | Thu, 29 Nov 2018 21:53:45 +0000 |
treeherder | mozilla-inbound@0c715a8f0170 [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | kmag |
bugs | 857456 |
milestone | 65.0a1 |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
--- a/toolkit/mozapps/extensions/AddonManagerStartup.cpp +++ b/toolkit/mozapps/extensions/AddonManagerStartup.cpp @@ -413,17 +413,17 @@ public: nsString Type() { return GetString("type", "extension"); } bool Enabled() { return GetBool("enabled"); } double LastModifiedTime() { return GetNumber("lastModifiedTime"); } bool ShouldCheckStartupModifications() { - return Type().EqualsLiteral("webextension-langpack"); + return Type().EqualsLiteral("locale"); } Result<nsCOMPtr<nsIFile>, nsresult> FullPath(); Result<bool, nsresult> UpdateLastModifiedTime();
--- a/toolkit/mozapps/extensions/internal/XPIDatabase.jsm +++ b/toolkit/mozapps/extensions/internal/XPIDatabase.jsm @@ -42,24 +42,22 @@ XPCOMUtils.defineLazyModuleGetters(this, const {nsIBlocklistService} = Ci; // These are injected from XPIProvider.jsm /* globals * BOOTSTRAP_REASONS, * DB_SCHEMA, * XPIStates, - * isWebExtension, */ for (let sym of [ "BOOTSTRAP_REASONS", "DB_SCHEMA", "XPIStates", - "isWebExtension", ]) { XPCOMUtils.defineLazyGetter(this, sym, () => XPIInternal[sym]); } ChromeUtils.import("resource://gre/modules/Log.jsm"); const LOGGER_ID = "addons.xpi-utils"; const nsIFile = Components.Constructor("@mozilla.org/file/local;1", "nsIFile", @@ -95,22 +93,21 @@ const PENDING_INSTALL_METADATA = ["syncGUID", "targetApplications", "userDisabled", "softDisabled", "existingAddonID", "sourceURI", "releaseNotesURI", "installDate", "updateDate", "applyBackgroundUpdates", "compatibilityOverrides", "installTelemetryInfo"]; const COMPATIBLE_BY_DEFAULT_TYPES = { extension: true, dictionary: true, - "webextension-dictionary": true, }; // Properties to save in JSON file const PROP_JSON_FIELDS = ["id", "syncGUID", "version", "type", - "updateURL", "optionsURL", + "isWebExtension", "updateURL", "optionsURL", "optionsType", "optionsBrowserStyle", "aboutURL", "defaultLocale", "visible", "active", "userDisabled", "appDisabled", "pendingUninstall", "installDate", "updateDate", "applyBackgroundUpdates", "path", "skinnable", "sourceURI", "releaseNotesURI", "softDisabled", "foreignInstall", "strictCompatibility", "locales", "targetApplications", "targetPlatforms", "signedState", @@ -118,30 +115,20 @@ const PROP_JSON_FIELDS = ["id", "syncGUI "userPermissions", "icons", "iconURL", "blocklistState", "blocklistURL", "startupData", "previewImage", "hidden", "installTelemetryInfo"]; 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", + "locale", + "theme", ]); // Time to wait before async save of XPI JSON database, in milliseconds const ASYNC_SAVE_DELAY_MS = 20; /** * Schedules an idle task, and returns a promise which resolves to an * IdleDeadline when an idle slice is available. The caller should @@ -193,56 +180,16 @@ async function idleForEach(array, func, async function getRepositoryAddon(aAddon) { if (aAddon) { aAddon._repositoryAddon = await AddonRepository.getCachedAddonByID(aAddon.id); } 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. * * @param {object} aObject * An object to copy from * @param {string[]} aProperties * An array of properties to be copied * @param {object?} [aTarget] @@ -492,17 +439,17 @@ class AddonInternal { version = aPlatformVersion; // Only extensions and dictionaries can be compatible by default; themes // and language packs always use strict compatibility checking. // Dictionaries are compatible by default unless requested by the dictinary. if (this.type in COMPATIBLE_BY_DEFAULT_TYPES && !this.strictCompatibility && (!AddonManager.strictCompatibility || - this.type == "webextension-dictionary")) { + this.type == "dictionary")) { // The repository can specify compatibility overrides. // Note: For now, only blacklisting is supported by overrides. let overrides = AddonRepository.getCompatibilityOverridesSync(this.id); if (overrides) { let override = AddonRepository.findMatchingCompatOverride(this.version, overrides); if (override) { @@ -724,24 +671,16 @@ AddonWrapper = class { if (addon.location.isTemporary) { return {source: "temporary-addon"}; } } return addon.installTelemetryInfo; } - get type() { - return XPIDatabase.getExternalType(addonFor(this).type); - } - - get isWebExtension() { - return isWebExtension(addonFor(this).type); - } - get temporarilyInstalled() { return addonFor(this).location.isTemporary; } get aboutURL() { return this.isActive ? addonFor(this).aboutURL : null; } @@ -982,18 +921,18 @@ AddonWrapper = class { set softDisabled(val) { let addon = addonFor(this); if (val == addon.softDisabled) return val; if (addon.inDatabase) { // When softDisabling a theme just enable the active theme - if (isTheme(addon.type) && val && !addon.userDisabled) { - if (isWebExtension(addon.type)) + if (addon.type === "theme" && val && !addon.userDisabled) { + if (addon.isWebExtension) XPIDatabase.updateAddonDisabledState(addon, undefined, val); } else { XPIDatabase.updateAddonDisabledState(addon, undefined, val); } } else if (!addon.userDisabled) { // Only set softDisabled if not already disabled addon.softDisabled = val; } @@ -1106,17 +1045,18 @@ function chooseValue(aAddon, aObj, aProp function defineAddonWrapperProperty(name, getter) { Object.defineProperty(AddonWrapper.prototype, name, { get: getter, enumerable: true, }); } -["id", "syncGUID", "version", "isCompatible", "isPlatformCompatible", +["id", "syncGUID", "version", "type", "isWebExtension", + "isCompatible", "isPlatformCompatible", "providesUpdatesSecurely", "blocklistState", "appDisabled", "softDisabled", "skinnable", "foreignInstall", "strictCompatibility", "updateURL", "dependencies", "signedState", "isCorrectlySigned"].forEach(function(aProp) { defineAddonWrapperProperty(aProp, function() { let addon = addonFor(this); return (aProp in addon) ? addon[aProp] : undefined; }); @@ -1617,51 +1557,36 @@ this.XPIDatabase = { * * @param {string} aId * The ID of the newly enabled add-on * @param {string} aType * The type of the newly enabled add-on */ async addonChanged(aId, aType) { // We only care about themes in this provider - if (!isTheme(aType)) + if (aType !== "theme") return; - let addons = this.getAddonsByType("webextension-theme"); + let addons = this.getAddonsByType("theme"); for (let theme of addons) { if (theme.visible && theme.id != aId) await this.updateAddonDisabledState(theme, true, undefined, true); } if (!aId && (!LightweightThemeManager.currentTheme || LightweightThemeManager.currentTheme !== DEFAULT_THEME_ID)) { let theme = LightweightThemeManager.getUsedTheme(DEFAULT_THEME_ID); // This can only ever be null in tests. // This can all go away once lightweight themes are gone. if (theme) { LightweightThemeManager.currentTheme = theme; } } }, - /** - * 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 * * @param {function(AddonInternal) : boolean} aFilter * Function that takes an addon instance and returns * true if that addon should be included in the selected array @@ -1825,47 +1750,48 @@ this.XPIDatabase = { /** * 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)); + let addons = await this.getVisibleAddons(aTypes ? new Set(aTypes) : null); return addons.map(a => a.wrapper); }, /** * Returns true if signing is required for the given add-on type. * * @param {string} aType * The add-on type to check. * @returns {boolean} */ mustSign(aType) { if (!SIGNED_TYPES.has(aType)) return false; - if (aType == "webextension-langpack") { + if (aType == "locale") { return AddonSettings.LANGPACKS_REQUIRE_SIGNING; } return AddonSettings.REQUIRE_SIGNING; }, /** * Determine if this addon should be disabled due to being legacy * * @param {Addon} addon The addon to check * * @returns {boolean} Whether the addon should be disabled for being legacy */ isDisabledLegacy(addon) { return (!AddonSettings.ALLOW_LEGACY_EXTENSIONS && + !addon.isWebExtension && LEGACY_TYPES.has(addon.type) && // Legacy add-ons are allowed in the system location. !addon.location.isSystem && // Legacy extensions may be installed temporarily in // non-release builds. !(AppConstants.MOZ_ALLOW_LEGACY_EXTENSIONS && @@ -2238,17 +2164,17 @@ this.XPIDatabase = { AddonManagerPrivate.callAddonListeners("onDisabled", wrapper); } else { await bootstrap.startup(BOOTSTRAP_REASONS.ADDON_ENABLE); AddonManagerPrivate.callAddonListeners("onEnabled", wrapper); } } // Notify any other providers that a new theme has been enabled - if (isTheme(aAddon.type)) { + if (aAddon.type === "theme") { if (!isDisabled) { AddonManagerPrivate.notifyAddonChanged(aAddon.id, aAddon.type); this.updateXPIStates(aAddon); } else if (isDisabled && !aBecauseSelecting) { AddonManagerPrivate.notifyAddonChanged(null, "theme"); } } @@ -2890,17 +2816,17 @@ this.XPIDatabaseReconcile = { if (isActive != wasActive) { let change = isActive ? AddonManager.STARTUP_CHANGE_ENABLED : AddonManager.STARTUP_CHANGE_DISABLED; AddonManagerPrivate.addStartupChange(change, id); } } else if (xpiState && xpiState.wasRestored) { isActive = xpiState.enabled; - if (currentAddon.type == "webextension-theme") + if (currentAddon.isWebExtension && currentAddon.type == "theme") currentAddon.userDisabled = !isActive; // If the add-on wasn't active and it isn't already disabled in some way // then it was probably either softDisabled or userDisabled if (!isActive && !currentAddon.disabled) { // If the add-on is softblocked then assume it is softDisabled if (currentAddon.blocklistState == Services.blocklist.STATE_SOFTBLOCKED) currentAddon.softDisabled = true;
--- a/toolkit/mozapps/extensions/internal/XPIInstall.jsm +++ b/toolkit/mozapps/extensions/internal/XPIInstall.jsm @@ -82,38 +82,33 @@ const PREF_PENDING_OPERATIONS = const PREF_SYSTEM_ADDON_UPDATE_URL = "extensions.systemAddon.update.url"; const PREF_XPI_ENABLED = "xpinstall.enabled"; const PREF_XPI_DIRECT_WHITELISTED = "xpinstall.whitelist.directRequest"; const PREF_XPI_FILE_WHITELISTED = "xpinstall.whitelist.fileRequest"; const PREF_XPI_WHITELIST_REQUIRED = "xpinstall.whitelist.required"; 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 */ +/* 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, iterDirectory */ const XPI_INTERNAL_SYMBOLS = [ "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", ]; 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. * * @param {string} path * The (possibly relative) path of the file. * @param {nsIFile} [base] * An optional file to use as a base path if `path` is relative. @@ -178,17 +173,16 @@ const PROP_LOCALE_MULTI = ["developers" const TYPES = { extension: 2, dictionary: 64, }; const COMPATIBLE_BY_DEFAULT_TYPES = { extension: true, dictionary: true, - "webextension-dictionary": true, }; // This is a random number array that can be used as "salt" when generating // an automatic ID based on the directory path of an add-on. It will prevent // someone from creating an ID for a permanent add-on that could be replaced // by a temporary add-on (because that would be confusing, I guess). const TEMP_INSTALL_ID_GEN_SESSION = new Uint8Array(Float64Array.of(Math.random()).buffer); @@ -449,30 +443,30 @@ async function loadManifestFromWebManife // A * is illegal in strict_min_version if (bss.strict_min_version && bss.strict_min_version.split(".").some(part => part == "*")) { throw new Error("The use of '*' in strict_min_version is invalid"); } let addon = new AddonInternal(); addon.id = bss.id; addon.version = manifest.version; - addon.type = extension.type === "extension" ? - "webextension" : `webextension-${extension.type}`; + addon.type = extension.type === "langpack" ? "locale" : extension.type; + addon.isWebExtension = true; addon.strictCompatibility = true; addon.internalName = null; addon.updateURL = bss.update_url; addon.optionsBrowserStyle = true; addon.optionsURL = null; addon.optionsType = null; addon.aboutURL = null; addon.dependencies = Object.freeze(Array.from(extension.dependencies)); addon.startupData = extension.startupData; addon.hidden = manifest.hidden; - if (isTheme(addon.type) && await aPackage.hasResource("preview.png")) { + if (addon.type === "theme" && await aPackage.hasResource("preview.png")) { addon.previewImage = "preview.png"; } if (manifest.options_ui) { // Store just the relative path here, the AddonWrapper getURL // wrapper maps this to a full URL. addon.optionsURL = manifest.options_ui.page; if (manifest.options_ui.open_in_tab) @@ -620,16 +614,17 @@ async function loadManifestFromRDF(aUri, addon.type = null; for (let name in TYPES) { if (TYPES[name] == type) { addon.type = name; break; } } } + addon.isWebExtension = false; if (!(addon.type in TYPES)) throw new Error("Install manifest specifies unknown type: " + addon.type); if (!addon.id) throw new Error("No ID in install manifest"); if (!gIDTest.test(addon.id)) throw new Error("Illegal add-on ID " + addon.id); @@ -649,17 +644,17 @@ async function loadManifestFromRDF(aUri, addon.optionsType != AddonManager.OPTIONS_TYPE_INLINE_BROWSER && addon.optionsType != AddonManager.OPTIONS_TYPE_TAB) { throw new Error("Install manifest specifies unknown optionsType: " + addon.optionsType); } } else { // Convert legacy dictionaries into a format the WebExtension // dictionary loader can process. if (addon.type === "dictionary") { - addon.type = "webextension-dictionary"; + addon.isWebExtension = true; let dictionaries = {}; await aPackage.iterFiles(({path}) => { let match = /^dictionaries\/([^\/]+)\.dic$/.exec(path); if (match) { let lang = match[1].replace(/_/g, "-"); dictionaries[lang] = match[0]; } }); @@ -1556,17 +1551,17 @@ class AddonInstall { if (this.existingAddon) { // Check various conditions related to upgrades if (this.addon.id != this.existingAddon.id) { return Promise.reject([AddonManager.ERROR_INCORRECT_ID, `Refusing to upgrade addon ${this.existingAddon.id} to different ID ${this.addon.id}`]); } - if (isWebExtension(this.existingAddon.type) && !isWebExtension(this.addon.type)) { + if (this.existingAddon.isWebExtension && !this.addon.isWebExtension) { return Promise.reject([AddonManager.ERROR_UNEXPECTED_ADDON_TYPE, "WebExtensions may not be updated to other extension types"]); } } if (XPIDatabase.mustSign(this.addon.type)) { if (this.addon.signedState <= AddonManager.SIGNEDSTATE_MISSING) { // This add-on isn't properly signed by a signature that chains to the @@ -1785,17 +1780,17 @@ class AddonInstall { logger.debug(`Install of ${this.sourceURI.spec} completed.`); this.state = AddonManager.STATE_INSTALLED; this._callInstallListeners("onInstallEnded", this.addon.wrapper); XPIDatabase.recordAddonTelemetry(this.addon); // Notify providers that a new theme has been enabled. - if (isTheme(this.addon.type) && this.addon.active) + if (this.addon.type === "theme" && this.addon.active) AddonManagerPrivate.notifyAddonChanged(this.addon.id, this.addon.type); }; this._startupPromise = (async () => { if (this.existingAddon) { await XPIInternal.BootstrapScope.get(this.existingAddon).update( this.addon, !this.addon.disabled, install); @@ -2494,17 +2489,17 @@ function AddonInstallWrapper(aInstall) { } AddonInstallWrapper.prototype = { get __AddonInstallInternal__() { return AppConstants.DEBUG ? installFor(this) : undefined; }, get type() { - return XPIDatabase.getExternalType(installFor(this).type); + return installFor(this).type; }, get iconURL() { return installFor(this).icons[32]; }, get existingAddon() { let install = installFor(this); @@ -2648,17 +2643,17 @@ UpdateChecker.prototype = { * The list of update details for the add-on */ async onUpdateCheckComplete(aUpdates) { XPIInstall.done(this.addon._updateCheck); this.addon._updateCheck = null; let AUC = AddonUpdateChecker; let ignoreMaxVersion = false; // Ignore strict compatibility for dictionaries by default. - let ignoreStrictCompat = (this.addon.type == "webextension-dictionary"); + let ignoreStrictCompat = (this.addon.type == "dictionary"); if (!AddonManager.checkCompatibility) { ignoreMaxVersion = true; ignoreStrictCompat = true; } else if (this.addon.type in COMPATIBLE_BY_DEFAULT_TYPES && !AddonManager.strictCompatibility && !this.addon.strictCompatibility) { ignoreMaxVersion = true; } @@ -3852,17 +3847,17 @@ var XPIInstall = { * @param {Array<string>?} aTypes * An array of types or null to get all types * @returns {AddonInstall[]} */ getInstallsByTypes(aTypes) { let results = [...this.installs]; if (aTypes) { results = results.filter(install => { - return aTypes.includes(XPIDatabase.getExternalType(install.type)); + return aTypes.includes(install.type); }); } return results.map(install => install.wrapper); }, /** * Temporarily installs add-on from a local XPI file or directory. @@ -3947,17 +3942,17 @@ var XPIInstall = { AddonManagerPrivate.callInstallListeners("onExternalInstall", null, addon.wrapper, oldAddon ? oldAddon.wrapper : null, false); AddonManagerPrivate.callAddonListeners("onInstalled", addon.wrapper); // Notify providers that a new theme has been enabled. - if (isTheme(addon.type)) + if (addon.type === "theme") AddonManagerPrivate.notifyAddonChanged(addon.id, addon.type, false); return addon.wrapper; }, /** * Uninstalls an add-on, immediately if possible or marks it as pending * uninstall if not. @@ -4064,17 +4059,17 @@ var XPIInstall = { } } else if (aAddon.active) { XPIStates.disableAddon(aAddon.id); bootstrap.shutdown(BOOTSTRAP_REASONS.ADDON_UNINSTALL); XPIDatabase.updateAddonActive(aAddon, false); } // Notify any other providers that a new theme has been enabled - if (isTheme(aAddon.type) && aAddon.active) + if (aAddon.type === "theme" && aAddon.active) AddonManagerPrivate.notifyAddonChanged(null, aAddon.type); }, /** * Cancels the pending uninstall of an add-on. * * @param {DBAddonInternal} aAddon * The DBAddonInternal to cancel uninstall for @@ -4105,15 +4100,15 @@ var XPIInstall = { AddonManagerPrivate.callAddonListeners("onOperationCancelled", wrapper); if (!aAddon.disabled) { XPIInternal.BootstrapScope.get(aAddon).startup(BOOTSTRAP_REASONS.ADDON_INSTALL); XPIDatabase.updateAddonActive(aAddon, true); } // Notify any other providers that this theme is now enabled again. - if (isTheme(aAddon.type) && aAddon.active) + if (aAddon.type === "theme" && aAddon.active) AddonManagerPrivate.notifyAddonChanged(aAddon.id, aAddon.type, false); }, DirectoryInstaller, SystemAddonInstaller, };
--- a/toolkit/mozapps/extensions/internal/XPIProvider.jsm +++ b/toolkit/mozapps/extensions/internal/XPIProvider.jsm @@ -218,28 +218,16 @@ function getFile(path, base = null) { // If the path isn't absolute, we must have a base path. let file = base.clone(); file.appendRelativePath(path); return file; } /** - * Helper function that determines whether an addon of a certain type is a - * WebExtension. - * - * @param {string} type - * The add-on type to check. - * @returns {boolean} - */ -function isWebExtension(type) { - return type == "webextension" || type == "webextension-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 * assumed to be an unpacked add-on. * * @param {string} filename * The filename to check. * @param {boolean} [strict = false] * If true, this file is in a location maintained by the browser, and @@ -370,16 +358,17 @@ function* iterDirectory(aDir) { * The on-disk state of an individual XPI, created from an Object * as stored in the addonStartup.json file. */ const JSON_FIELDS = Object.freeze([ "changed", "dependencies", "enabled", "file", + "isWebExtension", "lastModifiedTime", "path", "runInSafeMode", "signedState", "startupData", "telemetryKey", "type", "version", @@ -453,16 +442,17 @@ class XPIState { * data, to be saved to addonStartup.json. * * @returns {Object} */ toJSON() { let json = { dependencies: this.dependencies, enabled: this.enabled, + isWebExtension: this.isWebExtension, lastModifiedTime: this.lastModifiedTime, path: this.relativePath, runInSafeMode: this.runInSafeMode, signedState: this.signedState, telemetryKey: this.telemetryKey, version: this.version, }; if (this.type != "extension") { @@ -526,16 +516,17 @@ class XPIState { // did a full recursive scan in that case, so we don't need to do it again. // We don't use aDBAddon.active here because it's not updated until after restart. let mustGetMod = (aDBAddon.visible && !aDBAddon.disabled && !this.enabled); this.enabled = aDBAddon.visible && !aDBAddon.disabled; this.version = aDBAddon.version; this.type = aDBAddon.type; + this.isWebExtension = aDBAddon.isWebExtension; if (aDBAddon.startupData) { this.startupData = aDBAddon.startupData; } this.telemetryKey = this.getTelemetryKey(); this.dependencies = aDBAddon.dependencies; this.runInSafeMode = canRunInSafeMode(aDBAddon); @@ -1516,17 +1507,18 @@ class BootstrapScope { * @returns {any} * The return value of the bootstrap method. */ async callBootstrapMethod(aMethod, aReason, aExtraParams = {}) { let {addon, runInSafeMode} = this; if (Services.appinfo.inSafeMode && !runInSafeMode) return null; - if (addon.type == "extension" && aMethod == "startup") { + if (!addon.isWebExtension && addon.type == "extension" && + aMethod == "startup") { logger.debug(`Registering manifest for ${this.file.path}`); Components.manager.addBootstrappedManifestLocation(this.file); } try { if (!this.scope) { this.loadBootstrapScope(aReason); } @@ -1627,22 +1619,34 @@ class BootstrapScope { // But not at app startup, since we'll already have added all of our // annotations before starting any loads. if (aReason !== BOOTSTRAP_REASONS.APP_STARTUP) { XPIProvider.addAddonsToCrashReporter(); } logger.debug(`Loading bootstrap scope from ${this.file.path}`); - if (isWebExtension(this.addon.type)) { - this.scope = Extension.getBootstrapScope(this.addon.id, this.file); - } else if (this.addon.type === "webextension-langpack") { - this.scope = Langpack.getBootstrapScope(this.addon.id, this.file); - } else if (this.addon.type === "webextension-dictionary") { - this.scope = Dictionary.getBootstrapScope(this.addon.id, this.file); + if (this.addon.isWebExtension) { + switch (this.addon.type) { + case "extension": + case "theme": + this.scope = Extension.getBootstrapScope(this.addon.id, this.file); + break; + + case "locale": + this.scope = Langpack.getBootstrapScope(this.addon.id, this.file); + break; + + case "dictionary": + this.scope = Dictionary.getBootstrapScope(this.addon.id, this.file); + break; + + default: + throw new Error(`Unknown webextension type ${this.addon.type}`); + } } else { let uri = getURIForResourceInFile(this.file, "bootstrap.js").spec; let principal = Services.scriptSecurityManager.getSystemPrincipal(); this.scope = new Cu.Sandbox(principal, { sandboxName: uri, addonId: this.addon.id, wantGlobalProperties: ["ChromeUtils"], @@ -1828,17 +1832,17 @@ class BootstrapScope { * @returns {Promise} * Resolves when all required bootstrap callbacks have * completed. */ async update(newAddon, startup = false, updateCallback) { let reason = XPIInstall.newVersionReason(this.addon.version, newAddon.version); let extraArgs = {oldVersion: this.addon.version, newVersion: newAddon.version}; - let callUpdate = isWebExtension(this.addon.type) && isWebExtension(newAddon.type); + let callUpdate = this.addon.isWebExtension && newAddon.isWebExtension; await this._uninstall(reason, callUpdate, extraArgs); if (updateCallback) { await updateCallback(); } this.addon = newAddon; @@ -2663,17 +2667,17 @@ var XPIProvider = { let {scope, isSystem} = addon.location; result.push({ id: addon.id, version: addon.version, type: addon.type, updateDate: addon.lastModifiedTime, scope, isSystem, - isWebExtension: isWebExtension(addon), + isWebExtension: addon.isWebExtension, }); } return {addons: result, fullData: false}; }, onDebugConnectionChange({what, connection}) { if (what != "opened") @@ -2740,17 +2744,16 @@ var XPIInternal = { SystemAddonLocation, TEMPORARY_ADDON_SUFFIX, TemporaryInstallLocation, XPIStates, XPI_PERMISSION, awaitPromise, canRunInSafeMode, getURIForResourceInFile, - isWebExtension, isXPI, iterDirectory, }; var addonTypes = [ new AddonManagerPrivate.AddonType("extension", URI_EXTENSION_STRINGS, "type.extension.name", AddonManager.VIEW_TYPE_LIST, 4000,