Bug 1448221: Part 2 - Remove support for non-default legacy themes. r=aswan
authorKris Maglione <maglione.k@gmail.com>
Mon, 26 Mar 2018 16:19:04 -0700
changeset 410059 6f8118a829c47450e90ef32958287db20cb0a3b0
parent 410058 51155de79ee3e0260d22a0d6655e444fc1a9d174
child 410060 22cd4c5fcb397d80fc7f693737dc1c827ce61d74
push id101379
push usermaglione.k@gmail.com
push dateTue, 27 Mar 2018 00:46:03 +0000
treeherdermozilla-inbound@22cd4c5fcb39 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersaswan
bugs1448221
milestone61.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
Bug 1448221: Part 2 - Remove support for non-default legacy themes. r=aswan MozReview-Commit-ID: 1v0aGG3mv3U
browser/app/profile/firefox.js
browser/components/customizableui/CustomizeMode.jsm
mobile/android/app/mobile.js
toolkit/mozapps/extensions/LightweightThemeManager.jsm
toolkit/mozapps/extensions/internal/XPIInstall.jsm
toolkit/mozapps/extensions/internal/XPIProvider.jsm
toolkit/mozapps/extensions/internal/XPIProviderUtils.js
toolkit/mozapps/extensions/test/xpcshell/test_corrupt.js
toolkit/mozapps/extensions/test/xpcshell/test_legacy.js
--- a/browser/app/profile/firefox.js
+++ b/browser/app/profile/firefox.js
@@ -185,19 +185,16 @@ pref("app.update.service.enabled", true)
 //  extensions.{GUID}.update.url
 //  .. etc ..
 //
 pref("extensions.update.enabled", true);
 pref("extensions.update.url", "https://versioncheck.addons.mozilla.org/update/VersionCheck.php?reqVersion=%REQ_VERSION%&id=%ITEM_ID%&version=%ITEM_VERSION%&maxAppVersion=%ITEM_MAXAPPVERSION%&status=%ITEM_STATUS%&appID=%APP_ID%&appVersion=%APP_VERSION%&appOS=%APP_OS%&appABI=%APP_ABI%&locale=%APP_LOCALE%&currentAppVersion=%CURRENT_APP_VERSION%&updateType=%UPDATE_TYPE%&compatMode=%COMPATIBILITY_MODE%");
 pref("extensions.update.background.url", "https://versioncheck-bg.addons.mozilla.org/update/VersionCheck.php?reqVersion=%REQ_VERSION%&id=%ITEM_ID%&version=%ITEM_VERSION%&maxAppVersion=%ITEM_MAXAPPVERSION%&status=%ITEM_STATUS%&appID=%APP_ID%&appVersion=%APP_VERSION%&appOS=%APP_OS%&appABI=%APP_ABI%&locale=%APP_LOCALE%&currentAppVersion=%CURRENT_APP_VERSION%&updateType=%UPDATE_TYPE%&compatMode=%COMPATIBILITY_MODE%");
 pref("extensions.update.interval", 86400);  // Check for updates to Extensions and
                                             // Themes every day
-// Non-symmetric (not shared by extensions) extension-specific [update] preferences
-pref("extensions.dss.switchPending", false);    // Non-dynamic switch pending after next
-                                                // restart.
 
 pref("extensions.{972ce4c6-7e08-4474-a285-3208198ce6fd}.name", "chrome://browser/locale/browser.properties");
 pref("extensions.{972ce4c6-7e08-4474-a285-3208198ce6fd}.description", "chrome://browser/locale/browser.properties");
 
 pref("extensions.webextensions.themes.enabled", true);
 pref("extensions.webextensions.themes.icons.buttons", "back,forward,reload,stop,bookmark_star,bookmark_menu,downloads,home,app_menu,cut,copy,paste,new_window,new_private_window,save_page,print,history,full_screen,find,options,addons,developer,synced_tabs,open_file,sidebars,share_page,subscribe,text_encoding,email_link,forget,pocket");
 
 pref("lightweightThemes.update.enabled", true);
@@ -217,18 +214,16 @@ pref("browser.uitour.requireSecure", tru
 pref("browser.uitour.themeOrigin", "https://addons.mozilla.org/%LOCALE%/firefox/themes/");
 pref("browser.uitour.url", "https://www.mozilla.org/%LOCALE%/firefox/%VERSION%/tour/");
 // How long to show a Hearbeat survey (two hours, in seconds)
 pref("browser.uitour.surveyDuration", 7200);
 
 pref("keyword.enabled", true);
 pref("browser.fixup.domainwhitelist.localhost", true);
 
-pref("general.skins.selectedSkin", "classic/1.0");
-
 pref("general.smoothScroll", true);
 #ifdef UNIX_BUT_NOT_MAC
 pref("general.autoScroll", false);
 #else
 pref("general.autoScroll", true);
 #endif
 
 pref("browser.stopReloadAnimation.enabled", true);
--- a/browser/components/customizableui/CustomizeMode.jsm
+++ b/browser/components/customizableui/CustomizeMode.jsm
@@ -99,20 +99,16 @@ function CustomizeMode(aWindow) {
   this.areas = new Set();
 
   // There are two palettes - there's the palette that can be overlayed with
   // toolbar items in browser.xul. This is invisible, and never seen by the
   // user. Then there's the visible palette, which gets populated and displayed
   // to the user when in customizing mode.
   this.visiblePalette = this.document.getElementById(kPaletteId);
   this.pongArena = this.document.getElementById("customization-pong-arena");
-  if (Services.prefs.getCharPref("general.skins.selectedSkin") != "classic/1.0") {
-    let lwthemeButton = this.document.getElementById("customization-lwtheme-button");
-    lwthemeButton.setAttribute("hidden", "true");
-  }
   if (AppConstants.CAN_DRAW_IN_TITLEBAR) {
     this._updateTitlebarCheckbox();
     this._updateDragSpaceCheckbox();
     Services.prefs.addObserver(kDrawInTitlebarPref, this);
     Services.prefs.addObserver(kExtraDragSpacePref, this);
   }
   this.window.addEventListener("unload", this);
 }
--- a/mobile/android/app/mobile.js
+++ b/mobile/android/app/mobile.js
@@ -191,17 +191,16 @@ pref("xpinstall.whitelist.add", "https:/
 pref("xpinstall.signatures.required", true);
 
 pref("extensions.enabledScopes", 1);
 pref("extensions.autoupdate.enabled", true);
 pref("extensions.autoupdate.interval", 86400);
 pref("extensions.update.enabled", true);
 pref("extensions.update.interval", 86400);
 pref("extensions.dss.enabled", false);
-pref("extensions.dss.switchPending", false);
 pref("extensions.ignoreMTimeChanges", false);
 pref("extensions.logging.enabled", false);
 pref("extensions.hideInstallButton", true);
 pref("extensions.showMismatchUI", false);
 pref("extensions.hideUpdateButton", false);
 pref("extensions.strictCompatibility", false);
 pref("extensions.minCompatibleAppVersion", "11.0");
 
--- a/toolkit/mozapps/extensions/LightweightThemeManager.jsm
+++ b/toolkit/mozapps/extensions/LightweightThemeManager.jsm
@@ -8,18 +8,16 @@ var EXPORTED_SYMBOLS = ["LightweightThem
 
 ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
 ChromeUtils.import("resource://gre/modules/AddonManager.jsm");
 /* globals AddonManagerPrivate*/
 ChromeUtils.import("resource://gre/modules/Services.jsm");
 
 const ID_SUFFIX              = "@personas.mozilla.org";
 const PREF_LWTHEME_TO_SELECT = "extensions.lwThemeToSelect";
-const PREF_GENERAL_SKINS_SELECTEDSKIN = "general.skins.selectedSkin";
-const PREF_SKIN_TO_SELECT             = "extensions.lastSelectedSkin";
 const ADDON_TYPE             = "theme";
 const ADDON_TYPE_WEBEXT      = "webextension-theme";
 
 const URI_EXTENSION_STRINGS  = "chrome://mozapps/locale/extensions/extensions.properties";
 
 const DEFAULT_MAX_USED_THEMES_COUNT = 30;
 
 const MAX_PREVIEW_SECONDS = 30;
@@ -509,20 +507,16 @@ AddonWrapper.prototype = {
   get pendingOperations() {
     let pending = AddonManager.PENDING_NONE;
     if (this.isActive == this.userDisabled)
       pending |= this.isActive ? AddonManager.PENDING_DISABLE : AddonManager.PENDING_ENABLE;
     return pending;
   },
 
   get operationsRequiringRestart() {
-    // If a non-default theme is in use then a restart will be required to
-    // enable lightweight themes unless dynamic theme switching is enabled
-    if (Services.prefs.prefHasUserValue(PREF_GENERAL_SKINS_SELECTEDSKIN))
-      return AddonManager.OP_NEEDS_RESTART_ENABLE;
     return AddonManager.OP_NEEDS_RESTART_NONE;
   },
 
   get size() {
     // The size changes depending on whether the theme is in use or not, this is
     // probably not worth exposing.
     return null;
   },
@@ -655,19 +649,16 @@ function _getInternalID(id) {
   if (len > 0 && id.substring(len) == ID_SUFFIX)
     return id.substring(0, len);
   return null;
 }
 
 function _setCurrentTheme(aData, aLocal) {
   aData = _sanitizeTheme(aData, null, aLocal);
 
-  let needsRestart = (ADDON_TYPE == "theme") &&
-                     Services.prefs.prefHasUserValue(PREF_GENERAL_SKINS_SELECTEDSKIN);
-
   let cancel = Cc["@mozilla.org/supports-PRBool;1"].createInstance(Ci.nsISupportsPRBool);
   cancel.data = false;
   Services.obs.notifyObservers(cancel, "lightweight-theme-change-requested",
                                JSON.stringify(aData));
 
   let notify = true;
 
   if (aData) {
@@ -687,34 +678,33 @@ function _setCurrentTheme(aData, aLocal)
       AddonManagerPrivate.callAddonListeners("onInstalling", wrapper, false);
     }
 
     let current = LightweightThemeManager.currentTheme;
     let usedThemes = _usedThemesExceptId(aData.id);
     if (current && current.id != aData.id) {
       usedThemes.splice(1, 0, aData);
     } else {
-      if (current && current.id == aData.id && !needsRestart &&
-          !Services.prefs.prefHasUserValue(PREF_SKIN_TO_SELECT)) {
+      if (current && current.id == aData.id) {
         notify = false;
       }
       usedThemes.unshift(aData);
     }
     _updateUsedThemes(usedThemes);
 
     if (isInstall)
       AddonManagerPrivate.callAddonListeners("onInstalled", wrapper);
   }
 
   if (cancel.data)
     return null;
 
   if (notify) {
     AddonManagerPrivate.notifyAddonChanged(aData ? aData.id + ID_SUFFIX : null,
-                                           ADDON_TYPE, needsRestart);
+                                           ADDON_TYPE, false);
   }
 
   return LightweightThemeManager.currentTheme;
 }
 
 function _sanitizeTheme(aData, aBaseURI, aLocal) {
   if (!aData || typeof aData != "object")
     return null;
--- a/toolkit/mozapps/extensions/internal/XPIInstall.jsm
+++ b/toolkit/mozapps/extensions/internal/XPIInstall.jsm
@@ -57,16 +57,18 @@ XPCOMUtils.defineLazyServiceGetter(this,
 
 ChromeUtils.defineModuleGetter(this, "XPIInternal",
                                "resource://gre/modules/addons/XPIProvider.jsm");
 ChromeUtils.defineModuleGetter(this, "XPIProvider",
                                "resource://gre/modules/addons/XPIProvider.jsm");
 
 const PREF_ALLOW_NON_RESTARTLESS      = "extensions.legacy.non-restartless.enabled";
 
+const DEFAULT_SKIN = "classic/1.0";
+
 /* globals AddonInternal, BOOTSTRAP_REASONS, KEY_APP_SYSTEM_ADDONS, KEY_APP_SYSTEM_DEFAULTS, KEY_APP_TEMPORARY, TEMPORARY_ADDON_SUFFIX, SIGNED_TYPES, TOOLKIT_ID, XPIDatabase, XPIStates, getExternalType, isTheme, isUsableAddon, isWebExtension, mustSign, recordAddonTelemetry */
 const XPI_INTERNAL_SYMBOLS = [
   "AddonInternal",
   "BOOTSTRAP_REASONS",
   "KEY_APP_SYSTEM_ADDONS",
   "KEY_APP_SYSTEM_DEFAULTS",
   "KEY_APP_TEMPORARY",
   "SIGNED_TYPES",
@@ -660,17 +662,17 @@ async function loadManifestFromRDF(aUri,
     addon.targetPlatforms.push(platform);
   }
 
   // A theme's userDisabled value is true if the theme is not the selected skin
   // or if there is an active lightweight theme. We ignore whether softblocking
   // is in effect since it would change the active theme.
   if (isTheme(addon.type)) {
     addon.userDisabled = !!LightweightThemeManager.currentTheme ||
-                         addon.internalName != XPIProvider.selectedSkin;
+                         addon.internalName != DEFAULT_SKIN;
   } else if (addon.type == "experiment") {
     // Experiments are disabled by default. It is up to the Experiments Manager
     // to enable them (it drives installation).
     addon.userDisabled = true;
   } else {
     addon.userDisabled = false;
   }
 
--- a/toolkit/mozapps/extensions/internal/XPIProvider.jsm
+++ b/toolkit/mozapps/extensions/internal/XPIProvider.jsm
@@ -57,19 +57,16 @@ Cu.importGlobalProperties(["URL"]);
 const nsIFile = Components.Constructor("@mozilla.org/file/local;1", "nsIFile",
                                        "initWithPath");
 
 const PREF_DB_SCHEMA                  = "extensions.databaseSchema";
 const PREF_XPI_STATE                  = "extensions.xpiState";
 const PREF_BLOCKLIST_ITEM_URL         = "extensions.blocklist.itemURL";
 const PREF_BOOTSTRAP_ADDONS           = "extensions.bootstrappedAddons";
 const PREF_PENDING_OPERATIONS         = "extensions.pendingOperations";
-const PREF_SKIN_SWITCHPENDING         = "extensions.dss.switchPending";
-const PREF_SKIN_TO_SELECT             = "extensions.lastSelectedSkin";
-const PREF_GENERAL_SKINS_SELECTEDSKIN = "general.skins.selectedSkin";
 const PREF_EM_EXTENSION_FORMAT        = "extensions.";
 const PREF_EM_ENABLED_SCOPES          = "extensions.enabledScopes";
 const PREF_EM_STARTUP_SCAN_SCOPES     = "extensions.startupScanScopes";
 const PREF_EM_SHOW_MISMATCH_UI        = "extensions.showMismatchUI";
 const PREF_XPI_ENABLED                = "xpinstall.enabled";
 const PREF_XPI_WHITELIST_REQUIRED     = "xpinstall.whitelist.required";
 const PREF_XPI_DIRECT_WHITELISTED     = "xpinstall.whitelist.directRequest";
 const PREF_XPI_FILE_WHITELISTED       = "xpinstall.whitelist.fileRequest";
@@ -86,16 +83,18 @@ const PREF_SYSTEM_ADDON_SET           = 
 const PREF_SYSTEM_ADDON_UPDATE_URL    = "extensions.systemAddon.update.url";
 const PREF_ALLOW_LEGACY               = "extensions.legacy.enabled";
 
 const PREF_EM_MIN_COMPAT_APP_VERSION      = "extensions.minCompatibleAppVersion";
 const PREF_EM_MIN_COMPAT_PLATFORM_VERSION = "extensions.minCompatiblePlatformVersion";
 
 const PREF_EM_LAST_APP_BUILD_ID       = "extensions.lastAppBuildId";
 
+const DEFAULT_SKIN = "classic/1.0";
+
 // Specify a list of valid built-in add-ons to load.
 const BUILT_IN_ADDONS_URI             = "chrome://browser/content/built_in_addons.json";
 
 const OBSOLETE_PREFERENCES = [
   "extensions.bootstrappedAddons",
   "extensions.enabledAddons",
   "extensions.xpiState",
   "extensions.installCache",
@@ -105,17 +104,16 @@ const URI_EXTENSION_STRINGS           = 
 
 const DIR_EXTENSIONS                  = "extensions";
 const DIR_SYSTEM_ADDONS               = "features";
 const DIR_STAGE                       = "staged";
 const DIR_TRASH                       = "trash";
 
 const FILE_XPI_STATES                 = "addonStartup.json.lz4";
 const FILE_DATABASE                   = "extensions.json";
-const FILE_OLD_CACHE                  = "extensions.cache";
 const FILE_RDF_MANIFEST               = "install.rdf";
 const FILE_WEB_MANIFEST               = "manifest.json";
 const FILE_XPI_ADDONS_LIST            = "extensions.ini";
 
 const ADDON_ID_DEFAULT_THEME          = "{972ce4c6-7e08-4474-a285-3208198ce6fd}";
 
 const KEY_PROFILEDIR                  = "ProfD";
 const KEY_ADDON_APP_DIR               = "XREAddonAppDir";
@@ -296,16 +294,17 @@ function loadLazyObjects() {
     wantGlobalProperties: ["ChromeUtils", "TextDecoder"],
   });
 
   Object.assign(scope, {
     ADDON_SIGNING: AddonSettings.ADDON_SIGNING,
     SIGNED_TYPES,
     BOOTSTRAP_REASONS,
     DB_SCHEMA,
+    DEFAULT_SKIN,
     AddonInternal,
     XPIProvider,
     XPIStates,
     syncLoadManifestFromFile,
     isUsableAddon,
     recordAddonTelemetry,
     flushChromeCaches,
     descriptorToPath,
@@ -795,19 +794,18 @@ function isDisabledLegacy(addon) {
 /**
  * Calculates whether an add-on should be appDisabled or not.
  *
  * @param  aAddon
  *         The add-on to check
  * @return true if the add-on should not be appDisabled
  */
 function isUsableAddon(aAddon) {
-  // Hack to ensure the default theme is always usable
-  if (aAddon.type == "theme" && aAddon.internalName == XPIProvider.defaultSkin)
-    return true;
+  if (aAddon.type == "theme")
+    return aAddon.internalName == DEFAULT_SKIN;
 
   if (mustSign(aAddon.type) && !aAddon.isCorrectlySigned) {
     logger.warn(`Add-on ${aAddon.id} is not correctly signed.`);
     if (Services.prefs.getBoolPref(PREF_XPI_SIGNATURES_DEV_ROOT, false)) {
       logger.warn(`Preference ${PREF_XPI_SIGNATURES_DEV_ROOT} is set.`);
     }
     return false;
   }
@@ -1286,17 +1284,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);
 
     // We need to treat XUL themes specially here, since lightweight
     // themes require the default theme's chrome to be registered even
     // though we report it as disabled for UI purposes.
     if (aDBAddon.type == "theme") {
-      this.enabled = aDBAddon.internalName == XPIProvider.selectedSkin;
+      this.enabled = aDBAddon.internalName == DEFAULT_SKIN;
     } else {
       this.enabled = aDBAddon.visible && !aDBAddon.disabled;
     }
 
     this.version = aDBAddon.version;
     this.type = aDBAddon.type;
     this.startupData = aDBAddon.startupData;
 
@@ -1773,24 +1771,16 @@ var XPIProvider = {
   BOOTSTRAP_REASONS: Object.freeze(BOOTSTRAP_REASONS),
 
   // An array of known install locations
   installLocations: null,
   // A dictionary of known install locations by name
   installLocationsByName: null,
   // An array of currently active AddonInstalls
   installs: null,
-  // The default skin for the application
-  defaultSkin: "classic/1.0",
-  // The current skin used by the application
-  currentSkin: null,
-  // The selected skin to be used by the application when it is restarted. This
-  // will be the same as currentSkin when it is the skin to be used when the
-  // application is restarted
-  selectedSkin: null,
   // The value of the minCompatibleAppVersion preference
   minCompatibleAppVersion: null,
   // The value of the minCompatiblePlatformVersion preference
   minCompatiblePlatformVersion: null,
   // A Map of active addons to their bootstrapScope by ID
   activeAddons: new Map(),
   // True if the platform could have activated extensions
   extensionsActive: false,
@@ -2059,24 +2049,16 @@ var XPIProvider = {
                                     AddonManager.SCOPE_SYSTEM, true);
         if (hasRegistry) {
           addRegistryInstallLocation("winreg-app-global",
                                      Ci.nsIWindowsRegKey.ROOT_KEY_LOCAL_MACHINE,
                                      AddonManager.SCOPE_SYSTEM);
         }
       }
 
-      let defaultPrefs = Services.prefs.getDefaultBranch("");
-      this.defaultSkin = defaultPrefs.getStringPref(PREF_GENERAL_SKINS_SELECTEDSKIN,
-                                                    "classic/1.0");
-      this.currentSkin = Services.prefs.getStringPref(PREF_GENERAL_SKINS_SELECTEDSKIN,
-                                                      this.defaultSkin);
-      this.selectedSkin = this.currentSkin;
-      this.applyThemeChange();
-
       this.minCompatibleAppVersion = Services.prefs.getStringPref(PREF_EM_MIN_COMPAT_APP_VERSION,
                                                                   null);
       this.minCompatiblePlatformVersion = Services.prefs.getStringPref(PREF_EM_MIN_COMPAT_PLATFORM_VERSION,
                                                                        null);
 
       Services.prefs.addObserver(PREF_EM_MIN_COMPAT_APP_VERSION, this);
       Services.prefs.addObserver(PREF_EM_MIN_COMPAT_PLATFORM_VERSION, this);
       if (!AppConstants.MOZ_REQUIRE_SIGNING || Cu.isInAutomation)
@@ -2085,19 +2067,16 @@ var XPIProvider = {
       Services.prefs.addObserver(PREF_ALLOW_LEGACY, this);
       Services.obs.addObserver(this, NOTIFICATION_FLUSH_PERMISSIONS);
       Services.obs.addObserver(this, NOTIFICATION_TOOLBOX_CONNECTION_CHANGE);
 
 
       let flushCaches = this.checkForChanges(aAppChanged, aOldAppVersion,
                                              aOldPlatformVersion);
 
-      // Changes to installed extensions may have changed which theme is selected
-      this.applyThemeChange();
-
       AddonManagerPrivate.markProviderSafe(this);
 
       if (aAppChanged && !this.allAppGlobal &&
           Services.prefs.getBoolPref(PREF_EM_SHOW_MISMATCH_UI, true) &&
           AddonManager.updateEnabled) {
         let addonsToUpdate = this.shouldForceUpdateCheck(aAppChanged);
         if (addonsToUpdate) {
           this.noLegacyStartupCheck(addonsToUpdate);
@@ -2113,17 +2092,17 @@ var XPIProvider = {
         // effect
         Services.obs.notifyObservers(null, "chrome-flush-skin-caches");
         Services.obs.notifyObservers(null, "chrome-flush-caches");
       }
 
       if (AppConstants.MOZ_CRASHREPORTER) {
         // Annotate the crash report with relevant add-on information.
         try {
-          Services.appinfo.annotateCrashReport("Theme", this.currentSkin);
+          Services.appinfo.annotateCrashReport("Theme", DEFAULT_SKIN);
         } catch (e) { }
         try {
           Services.appinfo.annotateCrashReport("EMCheckCompatibility",
                                                AddonManager.checkCompatibility);
         } catch (e) { }
         this.addAddonsToCrashReporter();
       }
 
@@ -2331,37 +2310,16 @@ var XPIProvider = {
           let method = callUpdate ? "update" : "install";
           this.callBootstrapMethod(newAddon, file, method, reason, data);
         }
       }
     }
   },
 
   /**
-   * Applies any pending theme change to the preferences.
-   */
-  applyThemeChange() {
-    if (!Services.prefs.getBoolPref(PREF_SKIN_SWITCHPENDING, false))
-      return;
-
-    // Tell the Chrome Registry which Skin to select
-    try {
-      this.selectedSkin = Services.prefs.getCharPref(PREF_SKIN_TO_SELECT);
-      Services.prefs.setCharPref(PREF_GENERAL_SKINS_SELECTEDSKIN,
-                                 this.selectedSkin);
-      Services.prefs.clearUserPref(PREF_SKIN_TO_SELECT);
-      logger.debug("Changed skin to " + this.selectedSkin);
-      this.currentSkin = this.selectedSkin;
-    } catch (e) {
-      logger.error("Error applying theme change", e);
-    }
-    Services.prefs.clearUserPref(PREF_SKIN_SWITCHPENDING);
-  },
-
-  /**
    * If the application has been upgraded and there are add-ons outside the
    * application directory then we may need to synchronize compatibility
    * information but only if the mismatch UI isn't disabled.
    *
    * @returns null if no update check is needed, otherwise an array of add-on
    *          IDs to check for updates.
    */
   shouldForceUpdateCheck(aAppChanged) {
@@ -3192,36 +3150,16 @@ var XPIProvider = {
                                                                          aOldAppVersion,
                                                                          aOldPlatformVersion,
                                                                          updateReasons.includes("schemaChanged"));
         } catch (e) {
           logger.error("Failed to process extension changes at startup", e);
         }
       }
 
-      if (aAppChanged) {
-        // When upgrading the app and using a custom skin make sure it is still
-        // compatible otherwise switch back the default
-        if (this.currentSkin != this.defaultSkin) {
-          let oldSkin = XPIDatabase.getVisibleAddonForInternalName(this.currentSkin);
-          if (!oldSkin || oldSkin.disabled)
-            this.enableDefaultTheme();
-        }
-
-        // When upgrading remove the old extensions cache to force older
-        // versions to rescan the entire list of extensions
-        let oldCache = FileUtils.getFile(KEY_PROFILEDIR, [FILE_OLD_CACHE], true);
-        try {
-          if (oldCache.exists())
-            oldCache.remove(true);
-        } catch (e) {
-          logger.warn("Unable to remove old extension cache " + oldCache.path, e);
-        }
-      }
-
       if (Services.appinfo.inSafeMode) {
         aomStartup.initializeExtensions(this.getSafeModeExtensions());
         logger.debug("Initialized safe mode add-ons");
         return false;
       }
 
       // If the application crashed before completing any pending operations then
       // we should perform them now.
@@ -3757,55 +3695,24 @@ var XPIProvider = {
    * @param  aType
    *         The type of the newly enabled add-on
    */
   addonChanged(aId, aType) {
     // We only care about themes in this provider
     if (!isTheme(aType))
       return;
 
-    if (!aId) {
-      // Fallback to the default theme when no theme was enabled
-      this.enableDefaultTheme();
-      return;
-    }
-
-    // Look for the previously enabled theme and find the internalName of the
-    // currently selected theme
-    let previousTheme = null;
-    let newSkin = this.defaultSkin;
     let addons = XPIDatabase.getAddonsByType("theme", "webextension-theme");
     for (let theme of addons) {
-      if (!theme.visible)
-        return;
-      let isChangedAddon = (theme.id == aId);
-      if (isWebExtension(theme.type)) {
-        if (!isChangedAddon)
-          this.updateAddonDisabledState(theme, true, undefined);
-      } else if (isChangedAddon) {
-        newSkin = theme.internalName;
-      } else if (!theme.userDisabled && !theme.pendingUninstall) {
-        previousTheme = theme;
-      }
-    }
-
-    if (newSkin != this.currentSkin) {
-      Services.prefs.setCharPref(PREF_GENERAL_SKINS_SELECTEDSKIN, newSkin);
-      this.currentSkin = newSkin;
-    }
-    this.selectedSkin = newSkin;
-
-    // Flush the preferences to disk so they don't get out of sync with the
-    // database
-    Services.prefs.savePrefFile(null);
-
-    // Mark the previous theme as disabled. This won't cause recursion since
-    // only enabled calls notifyAddonChanged.
-    if (previousTheme)
-      this.updateAddonDisabledState(previousTheme, true, undefined);
+      if (isWebExtension(theme.type) && theme.visible && theme.id != aId)
+        this.updateAddonDisabledState(theme, true, undefined);
+    }
+
+    let defaultTheme = XPIDatabase.getVisibleAddonForInternalName(DEFAULT_SKIN);
+    this.updateAddonDisabledState(defaultTheme, aId && aId != defaultTheme.id);
   },
 
   /**
    * Update the appDisabled property for all add-ons.
    */
   updateAddonAppDisabledStates() {
     let addons = XPIDatabase.getAddons();
     for (let addon of addons) {
@@ -3842,43 +3749,16 @@ var XPIProvider = {
           }
 
           notifyComplete();
         });
       }
     });
   },
 
-  /**
-   * When the previously selected theme is removed this method will be called
-   * to enable the default theme.
-   */
-  enableDefaultTheme() {
-    logger.debug("Activating default theme");
-    let addon = XPIDatabase.getVisibleAddonForInternalName(this.defaultSkin);
-    if (addon) {
-      if (addon.userDisabled) {
-        this.updateAddonDisabledState(addon, false);
-      } else if (!this.extensionsActive) {
-        // During startup we may end up trying to enable the default theme when
-        // the database thinks it is already enabled (see f.e. bug 638847). In
-        // this case just force the theme preferences to be correct
-        Services.prefs.setCharPref(PREF_GENERAL_SKINS_SELECTEDSKIN,
-                                   addon.internalName);
-        this.currentSkin = this.selectedSkin = addon.internalName;
-        Services.prefs.clearUserPref(PREF_SKIN_TO_SELECT);
-        Services.prefs.clearUserPref(PREF_SKIN_SWITCHPENDING);
-      } else {
-        logger.warn("Attempting to activate an already active default theme");
-      }
-    } else {
-      logger.warn("Unable to activate the default theme");
-    }
-  },
-
   onDebugConnectionChange({what, connection}) {
     if (what != "opened")
       return;
 
     for (let [id, val] of this.activeAddons) {
       connection.setAddonOptions(
         id, { global: val.bootstrapScope });
     }
@@ -5034,17 +4914,17 @@ AddonWrapper.prototype = {
         icons[32] = icons[48] = this.getResourceURI("icon.png").spec;
       }
       if (this.hasResource("icon64.png")) {
         icons[64] = this.getResourceURI("icon64.png").spec;
       }
     }
 
     let canUseIconURLs = this.isActive ||
-      (addon.type == "theme" && addon.internalName == XPIProvider.defaultSkin);
+      (addon.type == "theme" && addon.internalName == DEFAULT_SKIN);
     if (canUseIconURLs && addon.iconURL) {
       icons[32] = addon.iconURL;
       icons[48] = addon.iconURL;
     }
 
     if (canUseIconURLs && addon.icon64URL) {
       icons[64] = addon.icon64URL;
     }
@@ -5203,19 +5083,21 @@ AddonWrapper.prototype = {
     let addon = addonFor(this);
     if (val == this.userDisabled) {
       return val;
     }
 
     if (addon.inDatabase) {
       let theme = isTheme(addon.type);
       if (theme && val) {
-        if (addon.internalName == XPIProvider.defaultSkin)
+        if (addon.internalName == DEFAULT_SKIN)
           throw new Error("Cannot disable the default theme");
-        XPIProvider.enableDefaultTheme();
+
+        let defaultTheme = XPIDatabase.getVisibleAddonForInternalName(DEFAULT_SKIN);
+        XPIProvider.updateAddonDisabledState(defaultTheme, false);
       }
       if (!(theme && val) || isWebExtension(addon.type)) {
         // hidden and system add-ons should not be user disasbled,
         // as there is no UI to re-enable them.
         if (this.hidden) {
           throw new Error(`Cannot disable hidden add-on ${addon.id}`);
         }
         XPIProvider.updateAddonDisabledState(addon, val);
@@ -5233,19 +5115,18 @@ AddonWrapper.prototype = {
   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 (addon.internalName == XPIProvider.defaultSkin)
+        if (addon.internalName == DEFAULT_SKIN)
           throw new Error("Cannot disable the default theme");
-        XPIProvider.enableDefaultTheme();
         if (isWebExtension(addon.type))
           XPIProvider.updateAddonDisabledState(addon, undefined, val);
       } else {
         XPIProvider.updateAddonDisabledState(addon, undefined, val);
       }
     } else if (!addon.userDisabled) {
       // Only set softDisabled if not already disabled
       addon.softDisabled = val;
--- a/toolkit/mozapps/extensions/internal/XPIProviderUtils.js
+++ b/toolkit/mozapps/extensions/internal/XPIProviderUtils.js
@@ -3,17 +3,17 @@
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
 // These are injected from XPIProvider.jsm
 /* globals ADDON_SIGNING, SIGNED_TYPES, BOOTSTRAP_REASONS, DB_SCHEMA,
           AddonInternal, XPIProvider, XPIStates, syncLoadManifestFromFile,
           isUsableAddon, recordAddonTelemetry,
-          flushChromeCaches, descriptorToPath */
+          flushChromeCaches, descriptorToPath, DEFAULT_SKIN */
 
 ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
 
 XPCOMUtils.defineLazyModuleGetters(this, {
   AddonManager: "resource://gre/modules/AddonManager.jsm",
   AddonManagerPrivate: "resource://gre/modules/AddonManager.jsm",
   AddonRepository: "resource://gre/modules/addons/AddonRepository.jsm",
   DeferredTask: "resource://gre/modules/DeferredTask.jsm",
@@ -1173,17 +1173,17 @@ this.XPIDatabaseReconcile = {
     aNewAddon.foreignInstall = isDetectedInstall &&
                                aInstallLocation.name != KEY_APP_SYSTEM_ADDONS &&
                                aInstallLocation.name != KEY_APP_SYSTEM_DEFAULTS;
 
     // appDisabled depends on whether the add-on is a foreignInstall so update
     aNewAddon.appDisabled = !isUsableAddon(aNewAddon);
 
     // The default theme is never a foreign install
-    if (aNewAddon.type == "theme" && aNewAddon.internalName == XPIProvider.defaultSkin)
+    if (aNewAddon.type == "theme" && aNewAddon.internalName == DEFAULT_SKIN)
       aNewAddon.foreignInstall = false;
 
     if (isDetectedInstall && aNewAddon.foreignInstall) {
       // If the add-on is a foreign install and is in a scope where add-ons
       // that were dropped in should default to disabled then disable it
       let disablingScopes = Services.prefs.getIntPref(PREF_EM_AUTO_DISABLED_SCOPES, 0);
       if (aInstallLocation.scope & disablingScopes) {
         logger.warn("Disabling foreign installed add-on " + aNewAddon.id + " in "
@@ -1519,17 +1519,16 @@ this.XPIDatabaseReconcile = {
     if (!systemAddonLocation.isValid(addons)) {
       // Hide the system add-on updates if any are invalid.
       logger.info("One or more updated system add-ons invalid, falling back to defaults.");
       hideLocation = KEY_APP_SYSTEM_ADDONS;
     }
 
     let previousVisible = this.getVisibleAddons(previousAddons);
     let currentVisible = this.flattenByID(currentAddons, hideLocation);
-    let sawActiveTheme = false;
 
     // Pass over the new set of visible add-ons, record any changes that occured
     // during startup and call bootstrap install/uninstall scripts as necessary
     for (let [id, currentAddon] of currentVisible) {
       let previousAddon = previousVisible.get(id);
 
       // Note if any visible add-on is not in the application install location
       if (currentAddon._installLocation.name != KEY_APP_GLOBAL)
@@ -1543,20 +1542,23 @@ this.XPIDatabaseReconcile = {
         // so wasn't something recovered from a corrupt database
         let wasStaged = !!loadedManifest(currentAddon._installLocation, id);
 
         // We might be recovering from a corrupt database, if so use the
         // list of known active add-ons to update the new add-on
         if (!wasStaged && XPIDatabase.activeBundles) {
           // For themes we know which is active by the current skin setting
           if (currentAddon.type == "theme")
-            isActive = currentAddon.internalName == XPIProvider.currentSkin;
+            isActive = currentAddon.internalName == DEFAULT_SKIN;
           else
             isActive = XPIDatabase.activeBundles.includes(currentAddon.path);
 
+          if (currentAddon.type == "webextension-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 == Blocklist.STATE_SOFTBLOCKED)
               currentAddon.softDisabled = true;
             else
               currentAddon.userDisabled = true;
@@ -1615,19 +1617,16 @@ this.XPIDatabaseReconcile = {
           let change = isActive ? AddonManager.STARTUP_CHANGE_ENABLED
                                 : AddonManager.STARTUP_CHANGE_DISABLED;
           AddonManagerPrivate.addStartupChange(change, id);
         }
       }
 
       XPIDatabase.makeAddonVisible(currentAddon);
       currentAddon.active = isActive;
-
-      if (currentAddon.active && currentAddon.internalName == XPIProvider.selectedSkin)
-        sawActiveTheme = true;
     }
 
     // Pass over the set of previously visible add-ons that have now gone away
     // and record the change.
     for (let [id, previousAddon] of previousVisible) {
       if (currentVisible.has(id))
         continue;
 
@@ -1651,23 +1650,16 @@ this.XPIDatabaseReconcile = {
     let locationAddonMap = currentAddons.get(hideLocation);
     if (locationAddonMap) {
       for (let addon of locationAddonMap.values()) {
         addon.visible = false;
         addon.active = false;
       }
     }
 
-    // If a custom theme is selected and it wasn't seen in the new list of
-    // active add-ons then enable the default theme
-    if (XPIProvider.selectedSkin != XPIProvider.defaultSkin && !sawActiveTheme) {
-      logger.info("Didn't see selected skin " + XPIProvider.selectedSkin);
-      XPIProvider.enableDefaultTheme();
-    }
-
     // Finally update XPIStates to match everything
     for (let [locationName, locationAddonMap] of currentAddons) {
       for (let [id, addon] of locationAddonMap) {
         let xpiState = XPIStates.getAddon(locationName, id);
         xpiState.syncWithDB(addon);
       }
     }
     XPIStates.save();
--- a/toolkit/mozapps/extensions/test/xpcshell/test_corrupt.js
+++ b/toolkit/mozapps/extensions/test/xpcshell/test_corrupt.js
@@ -145,43 +145,35 @@ const ADDONS = {
       pendingOperations: 0,
     },
     afterCorruption: {},
     afterSecondRestart: {},
   },
 
   // The default theme
   "theme1@tests.mozilla.org": {
-    "install.rdf": {
-      id: "theme1@tests.mozilla.org",
-      version: "1.0",
+    manifest: {
+      manifest_version: 2,
       name: "Theme 1",
-      internalName: "classic/1.0",
-      targetApplications: [{
-        id: "xpcshell@tests.mozilla.org",
-        minVersion: "2",
-        maxVersion: "2"
-      }]
+      version: "1.0",
+      theme: { images: { headerURL: "example.png" } },
+      applications: {
+        gecko: {
+          id: "theme1@tests.mozilla.org",
+        },
+      },
     },
     desiredState: {
       isActive: false,
       userDisabled: true,
       appDisabled: false,
       pendingOperations: 0,
     },
-    // Not correctly recovered, due to WebExtension themes disabling
-    // themselves on creation.
-    afterCorruption: {
-      isActive: true,
-      userDisabled: false,
-    },
-    afterSecondRestart: {
-      isActive: true,
-      userDisabled: false,
-    },
+    afterCorruption: {},
+    afterSecondRestart: {},
   },
 
   "theme2@tests.mozilla.org": {
     manifest: {
       manifest_version: 2,
       name: "Theme 2",
       version: "1.0",
       theme: { images: { headerURL: "example.png" } },
@@ -195,27 +187,18 @@ const ADDONS = {
       userDisabled: false,
     },
     desiredState: {
       isActive: true,
       userDisabled: false,
       appDisabled: false,
       pendingOperations: 0,
     },
-    // Not correctly recovered, due to WebExtension themes disabling
-    // themselves on creation.
-    afterCorruption: {
-      isActive: true,
-      userDisabled: true,
-      pendingOperations: 2,
-    },
-    afterSecondRestart: {
-      isActive: false,
-      userDisabled: true,
-    },
+    afterCorruption: {},
+    afterSecondRestart: {},
   },
 };
 
 const IDS = Object.keys(ADDONS);
 
 function promiseUpdates(addon) {
   return new Promise(resolve => {
     addon.findUpdates({onUpdateFinished: resolve},
--- a/toolkit/mozapps/extensions/test/xpcshell/test_legacy.js
+++ b/toolkit/mozapps/extensions/test/xpcshell/test_legacy.js
@@ -13,23 +13,16 @@ add_task(async function test_disable() {
       bootstrap: true,
     },
     {
       id: "apiexperiment@tests.mozilla.org",
       name: "WebExtension Experiment",
       version: "1.0",
       type: 256,
     },
-    {
-      id: "theme@tests.mozilla.org",
-      name: "Theme",
-      version: "1.0",
-      type: 4,
-      internalName: "mytheme/1.0",
-    },
   ];
 
   let nonLegacy = [
     {
       id: "webextension@tests.mozilla.org",
       manifest: {
         applications: {gecko: {id: "webextension@tests.mozilla.org"}},
       },