Bug 699175: The current theme is not active when updating Firefox and the add-ons database schema changes. r=Unfocused
authorDave Townsend <dtownsend@oxymoronical.com>
Tue, 22 Nov 2011 18:28:27 -0800
changeset 82304 47c587d6524296b4b3610e3335afacafb4ef46f9
parent 82303 3edc79afc84277486afad1fb76d007ba37e72894
child 82305 1bca914c339e10a37aa05829c9a03f4c3dbbc33d
push id519
push userakeybl@mozilla.com
push dateWed, 01 Feb 2012 00:38:35 +0000
treeherdermozilla-beta@788ea1ef610b [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersUnfocused
bugs699175
milestone11.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 699175: The current theme is not active when updating Firefox and the add-ons database schema changes. r=Unfocused
toolkit/mozapps/extensions/XPIProvider.jsm
toolkit/mozapps/extensions/test/addons/test_migrate9/install.rdf
toolkit/mozapps/extensions/test/xpcshell/test_migrate2.js
toolkit/mozapps/extensions/test/xpcshell/test_migrate4.js
--- a/toolkit/mozapps/extensions/XPIProvider.jsm
+++ b/toolkit/mozapps/extensions/XPIProvider.jsm
@@ -122,17 +122,17 @@ const PREFIX_ITEM_URI                 = 
 const RDFURI_ITEM_ROOT                = "urn:mozilla:item:root"
 const RDFURI_INSTALL_MANIFEST_ROOT    = "urn:mozilla:install-manifest";
 const PREFIX_NS_EM                    = "http://www.mozilla.org/2004/em-rdf#";
 
 const TOOLKIT_ID                      = "toolkit@mozilla.org";
 
 const BRANCH_REGEXP                   = /^([^\.]+\.[0-9]+[a-z]*).*/gi;
 
-const DB_SCHEMA                       = 9;
+const DB_SCHEMA                       = 12;
 const REQ_VERSION                     = 2;
 
 #ifdef MOZ_COMPATIBILITY_NIGHTLY
 const PREF_EM_CHECK_COMPATIBILITY = PREF_EM_CHECK_COMPATIBILITY_BASE +
                                     ".nightly";
 #else
 const PREF_EM_CHECK_COMPATIBILITY = PREF_EM_CHECK_COMPATIBILITY_BASE + "." +
                                     Services.appinfo.version.replace(BRANCH_REGEXP, "$1");
@@ -151,25 +151,25 @@ const DB_METADATA        = ["syncGUID",
                             "installDate",
                             "updateDate",
                             "size",
                             "sourceURI",
                             "releaseNotesURI",
                             "applyBackgroundUpdates"];
 const DB_BOOL_METADATA   = ["visible", "active", "userDisabled", "appDisabled",
                             "pendingUninstall", "bootstrap", "skinnable",
-                            "softDisabled", "foreignInstall",
+                            "softDisabled", "isForeignInstall",
                             "hasBinaryComponents", "strictCompatibility"];
 
 // Properties that should be migrated where possible from an old database. These
 // shouldn't include properties that can be read directly from install.rdf files
 // or calculated
 const DB_MIGRATE_METADATA= ["installDate", "userDisabled", "softDisabled",
                             "sourceURI", "applyBackgroundUpdates",
-                            "releaseNotesURI", "foreignInstall", "syncGUID"];
+                            "releaseNotesURI", "isForeignInstall", "syncGUID"];
 
 const BOOTSTRAP_REASONS = {
   APP_STARTUP     : 1,
   APP_SHUTDOWN    : 2,
   ADDON_ENABLE    : 3,
   ADDON_DISABLE   : 4,
   ADDON_INSTALL   : 5,
   ADDON_UNINSTALL : 6,
@@ -2578,17 +2578,22 @@ var XPIProvider = {
 
         return true;
       }
 
       return false;
     }
 
     /**
-     * Called when a new add-on has been detected.
+     * Called to add the metadata for an add-on in one of the install locations
+     * to the database. This can be called in three different cases. Either an
+     * add-on has been dropped into the location from outside of Firefox, or
+     * an add-on has been installed through the application, or the database
+     * has been upgraded or become corrupt and add-on data has to be reloaded
+     * into it.
      *
      * @param  aInstallLocation
      *         The install location containing the add-on
      * @param  aId
      *         The ID of the add-on
      * @param  aAddonState
      *         The new state of the add-on
      * @param  aMigrateData
@@ -2602,27 +2607,30 @@ var XPIProvider = {
 
       let newAddon = null;
       let sameVersion = false;
       // Check the updated manifests lists for the install location, If there
       // is no manifest for the add-on ID then newAddon will be undefined
       if (aInstallLocation.name in aManifests)
         newAddon = aManifests[aInstallLocation.name][aId];
 
+      // If we aren't recovering from a corrupt database or we don't have
+      // migration data for this add-on then this must be a new install.
+      let isNewInstall = !aActiveBundles && !aMigrateData;
+ 
+      // If it's a new install and we haven't yet loaded the manifest then it
+      // must be something dropped directly into the install location
+      let isDetectedInstall = isNewInstall && !newAddon;
+
+      // Load the manifest if necessary and sanity check the add-on ID
       try {
-        // Otherwise the add-on has appeared in the install location.
         if (!newAddon) {
           // Load the manifest from the add-on.
           let file = aInstallLocation.getLocationForID(aId);
           newAddon = loadManifestFromFile(file);
-
-          // The default theme is never a foreign install
-          if (newAddon.type != "theme" || newAddon.internalName != XPIProvider.defaultSkin)
-            newAddon.foreignInstall = true;
-
         }
         // The add-on in the manifest should match the add-on ID.
         if (newAddon.id != aId)
           throw new Error("Incorrect id in install manifest");
       }
       catch (e) {
         WARN("Add-on is invalid", e);
 
@@ -2635,52 +2643,63 @@ var XPIProvider = {
         return false;
       }
 
       // Update the AddonInternal properties.
       newAddon._installLocation = aInstallLocation;
       newAddon.visible = !(newAddon.id in visibleAddons);
       newAddon.installDate = aAddonState.mtime;
       newAddon.updateDate = aAddonState.mtime;
-
-      // Check if the add-on is a foreign install and is in a scope where
-      // add-ons that were dropped in should default to disabled.
-      let disablingScopes = Prefs.getIntPref(PREF_EM_AUTO_DISABLED_SCOPES, 0);
-      if (newAddon.foreignInstall && aInstallLocation.scope & disablingScopes)
-        newAddon.userDisabled = true;
-
-      // If there is migration data then apply it.
+      newAddon.foreignInstall = isDetectedInstall;
+
       if (aMigrateData) {
+        // If there is migration data then apply it.
         LOG("Migrating data from old database");
 
         DB_MIGRATE_METADATA.forEach(function(aProp) {
           // A theme's disabled state is determined by the selected theme
           // preference which is read in loadManifestFromRDF
           if (aProp == "userDisabled" && newAddon.type == "theme")
             return;
 
           if (aProp in aMigrateData)
             newAddon[aProp] = aMigrateData[aProp];
         });
 
+        // Force all non-profile add-ons to be foreignInstalls since they can't
+        // have been installed through the API
+        newAddon.foreignInstall |= aInstallLocation.name != KEY_APP_PROFILE;
+
         // Some properties should only be migrated if the add-on hasn't changed.
         // The version property isn't a perfect check for this but covers the
         // vast majority of cases.
         if (aMigrateData.version == newAddon.version) {
           LOG("Migrating compatibility info");
           sameVersion = true;
           if ("targetApplications" in aMigrateData)
             newAddon.applyCompatibilityUpdate(aMigrateData, true);
         }
 
         // Since the DB schema has changed make sure softDisabled is correct
         applyBlocklistChanges(newAddon, newAddon, aOldAppVersion,
                               aOldPlatformVersion);
       }
 
+      // The default theme is never a foreign install
+      if (newAddon.type == "theme" && newAddon.internalName == XPIProvider.defaultSkin)
+        newAddon.foreignInstall = false;
+
+      if (isDetectedInstall && newAddon.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 = Prefs.getIntPref(PREF_EM_AUTO_DISABLED_SCOPES, 0);
+        if (aInstallLocation.scope & disablingScopes)
+          newAddon.userDisabled = true;
+      }
+
       if (aActiveBundles) {
         // If we have a list of what add-ons should be marked as active then use
         // it to guess at migration data
         // For themes we know which is active by the current skin setting
         if (newAddon.type == "theme")
           newAddon.active = newAddon.internalName == XPIProvider.currentSkin;
         else
           newAddon.active = aActiveBundles.indexOf(aAddonState.descriptor) != -1;
@@ -2708,21 +2727,18 @@ var XPIProvider = {
         // add-on will just be unavailable until we try again in a subsequent
         // startup
         ERROR("Failed to add add-on " + aId + " in " + aInstallLocation.name +
               " to database", e);
         return false;
       }
 
       if (newAddon.visible) {
-        // Remember add-ons that were installed during startup. If there was a
-        // cached manifest or migration data then this install is already
-        // expected
-        if (!aMigrateData && (!(aInstallLocation.name in aManifests) ||
-                              !(aId in aManifests[aInstallLocation.name]))) {
+        // Remember add-ons that were first detected during startup.
+        if (isDetectedInstall) {
           // If a copy from a higher priority location was removed then this
           // add-on has changed
           if (AddonManager.getStartupChanges(AddonManager.STARTUP_CHANGE_UNINSTALLED)
                           .indexOf(newAddon.id) != -1) {
             AddonManagerPrivate.addStartupChange(AddonManager.STARTUP_CHANGE_CHANGED,
                                                  newAddon.id);
           }
           else {
@@ -3943,17 +3959,17 @@ var XPIProvider = {
 
 const FIELDS_ADDON = "internal_id, id, syncGUID, location, version, type, " +
                      "internalName, updateURL, updateKey, optionsURL, " +
                      "optionsType, aboutURL, iconURL, icon64URL, " +
                      "defaultLocale, visible, active, userDisabled, " +
                      "appDisabled, pendingUninstall, descriptor, " +
                      "installDate, updateDate, applyBackgroundUpdates, bootstrap, " +
                      "skinnable, size, sourceURI, releaseNotesURI, softDisabled, " +
-                     "foreignInstall, hasBinaryComponents, strictCompatibility";
+                     "isForeignInstall, hasBinaryComponents, strictCompatibility";
 
 /**
  * A helper function to log an SQL error.
  *
  * @param  aError
  *         The storage error code associated with the error
  * @param  aErrorString
  *         An error message
@@ -4092,17 +4108,17 @@ var XPIDatabase = {
                             ":location, :version, :type, :internalName, " +
                             ":updateURL, :updateKey, :optionsURL, " +
                             ":optionsType, :aboutURL, " +
                             ":iconURL, :icon64URL, :locale, :visible, :active, " +
                             ":userDisabled, :appDisabled, :pendingUninstall, " +
                             ":descriptor, :installDate, :updateDate, " +
                             ":applyBackgroundUpdates, :bootstrap, :skinnable, " +
                             ":size, :sourceURI, :releaseNotesURI, :softDisabled, " +
-                            ":foreignInstall, :hasBinaryComponents, " +
+                            ":isForeignInstall, :hasBinaryComponents, " +
                             ":strictCompatibility)",
     addAddonMetadata_addon_locale: "INSERT INTO addon_locale VALUES " +
                                    "(:internal_id, :name, :locale)",
     addAddonMetadata_locale: "INSERT INTO locale (name, description, creator, " +
                              "homepageURL) VALUES (:name, :description, " +
                              ":creator, :homepageURL)",
     addAddonMetadata_strings: "INSERT INTO locale_strings VALUES (:locale, " +
                               ":type, :value)",
@@ -4632,17 +4648,17 @@ var XPIDatabase = {
                                   "visible INTEGER, active INTEGER, " +
                                   "userDisabled INTEGER, appDisabled INTEGER, " +
                                   "pendingUninstall INTEGER, descriptor TEXT, " +
                                   "installDate INTEGER, updateDate INTEGER, " +
                                   "applyBackgroundUpdates INTEGER, " +
                                   "bootstrap INTEGER, skinnable INTEGER, " +
                                   "size INTEGER, sourceURI TEXT, " +
                                   "releaseNotesURI TEXT, softDisabled INTEGER, " +
-                                  "foreignInstall INTEGER, " +
+                                  "isForeignInstall INTEGER, " +
                                   "hasBinaryComponents INTEGER, " +
                                   "strictCompatibility INTEGER, " +
                                   "UNIQUE (id, location), " +
                                   "UNIQUE (syncGUID)");
       this.connection.createTable("targetApplication",
                                   "addon_internal_id INTEGER, " +
                                   "id TEXT, minVersion TEXT, maxVersion TEXT, " +
                                   "UNIQUE (addon_internal_id, id)");
@@ -7049,16 +7065,23 @@ AddonInternal.prototype = {
   visible: false,
   userDisabled: false,
   appDisabled: false,
   softDisabled: false,
   sourceURI: null,
   releaseNotesURI: null,
   foreignInstall: false,
 
+  get isForeignInstall() {
+    return this.foreignInstall;
+  },
+  set isForeignInstall(aVal) {
+    this.foreignInstall = aVal;
+  },
+
   get selectedLocale() {
     if (this._selectedLocale)
       return this._selectedLocale;
     let locale = findClosestLocale(this.locales);
     this._selectedLocale = locale ? locale : this.defaultLocale;
     return this._selectedLocale;
   },
 
new file mode 100644
--- /dev/null
+++ b/toolkit/mozapps/extensions/test/addons/test_migrate9/install.rdf
@@ -0,0 +1,26 @@
+<?xml version="1.0"?>
+
+<RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+     xmlns:em="http://www.mozilla.org/2004/em-rdf#">
+
+  <Description about="urn:mozilla:install-manifest">
+    <em:id>addon9@tests.mozilla.org</em:id>
+    <em:version>1.0</em:version>
+    <em:internalName>theme1/1.0</em:internalName>
+
+    <!-- Front End MetaData -->
+    <em:name>Test Theme 1</em:name>
+    <em:description>Test Description</em:description>
+
+    <em:targetApplication>
+      <Description>
+        <em:id>xpcshell@tests.mozilla.org</em:id>
+        <em:minVersion>1</em:minVersion>
+        <em:maxVersion>2</em:maxVersion>
+      </Description>
+    </em:targetApplication>
+
+    <em:skinnable>true</em:skinnable>
+
+  </Description>
+</RDF>
--- a/toolkit/mozapps/extensions/test/xpcshell/test_migrate2.js
+++ b/toolkit/mozapps/extensions/test/xpcshell/test_migrate2.js
@@ -1,13 +1,20 @@
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/
  */
 
 // Checks that we migrate data from future versions of the database
+// Note that since the database doesn't contain the foreignInstall field we
+// should just assume that no add-ons  in the user profile were foreignInstalls
+
+// Enable loading extensions from the user and system scopes
+Services.prefs.setIntPref("extensions.enabledScopes",
+                          AddonManager.SCOPE_PROFILE + AddonManager.SCOPE_USER +
+                          AddonManager.SCOPE_SYSTEM);
 
 var addon1 = {
   id: "addon1@tests.mozilla.org",
   version: "1.0",
   name: "Test 1",
   targetApplications: [{
     id: "xpcshell@tests.mozilla.org",
     minVersion: "1",
@@ -66,29 +73,61 @@ var addon6 = {
   name: "Test 6",
   targetApplications: [{
     id: "xpcshell@tests.mozilla.org",
     minVersion: "0",
     maxVersion: "0"
   }]
 };
 
+var addon7 = {
+  id: "addon7@tests.mozilla.org",
+  version: "2.0",
+  name: "Test 7",
+  targetApplications: [{
+    id: "xpcshell@tests.mozilla.org",
+    minVersion: "1",
+    maxVersion: "1"
+  }]
+};
+
+var addon8 = {
+  id: "addon8@tests.mozilla.org",
+  version: "2.0",
+  name: "Test 8",
+  targetApplications: [{
+    id: "xpcshell@tests.mozilla.org",
+    minVersion: "1",
+    maxVersion: "1"
+  }]
+};
+
+createAppInfo("xpcshell@tests.mozilla.org", "XPCShell", "1", "1.9.2");
 const profileDir = gProfD.clone();
 profileDir.append("extensions");
+const globalDir = gProfD.clone();
+globalDir.append("extensions2");
+globalDir.append(gAppInfo.ID);
+registerDirectory("XRESysSExtPD", globalDir.parent);
+const userDir = gProfD.clone();
+userDir.append("extensions3");
+userDir.append(gAppInfo.ID);
+registerDirectory("XREUSysExt", userDir.parent);
 
 function run_test() {
   do_test_pending();
-  createAppInfo("xpcshell@tests.mozilla.org", "XPCShell", "1", "1.9.2");
 
   writeInstallRDFForExtension(addon1, profileDir);
   writeInstallRDFForExtension(addon2, profileDir);
   writeInstallRDFForExtension(addon3, profileDir);
   writeInstallRDFForExtension(addon4, profileDir);
   writeInstallRDFForExtension(addon5, profileDir);
   writeInstallRDFForExtension(addon6, profileDir);
+  writeInstallRDFForExtension(addon7, globalDir);
+  writeInstallRDFForExtension(addon8, userDir);
 
   // Write out a minimal database
   let dbfile = gProfD.clone();
   dbfile.append("extensions.sqlite");
   let db = AM_Cc["@mozilla.org/storage/service;1"].
            getService(AM_Ci.mozIStorageService).
            openDatabase(dbfile);
   db.createTable("addon", "internal_id INTEGER PRIMARY KEY AUTOINCREMENT, " +
@@ -101,17 +140,19 @@ function run_test() {
 
   let internal_ids = {};
 
   [["addon1@tests.mozilla.org", "app-profile", "1.0", "1", "0", "0"],
    ["addon2@tests.mozilla.org", "app-profile", "2.0", "0", "1", "0"],
    ["addon3@tests.mozilla.org", "app-profile", "2.0", "1", "1", "0"],
    ["addon4@tests.mozilla.org", "app-profile", "2.0", "0", "0", "0"],
    ["addon5@tests.mozilla.org", "app-profile", "2.0", "1", "0", "0"],
-   ["addon6@tests.mozilla.org", "app-profile", "1.0", "0", "1", "0"]].forEach(function(a) {
+   ["addon6@tests.mozilla.org", "app-profile", "1.0", "0", "1", "0"],
+   ["addon7@tests.mozilla.org", "app-system-share", "1.0", "1", "0", "0"],
+   ["addon8@tests.mozilla.org", "app-system-user", "1.0", "1", "0", "0"]].forEach(function(a) {
     stmt.params.id = a[0];
     stmt.params.location = a[1];
     stmt.params.version = a[2];
     stmt.params.active = a[3];
     stmt.params.userDisabled = a[4];
     stmt.params.installDate = a[5];
     stmt.execute();
     internal_ids[a[0]] = db.lastInsertRowID;
@@ -146,50 +187,73 @@ function run_test() {
   check_startup_changes("disabled", []);
   check_startup_changes("enabled", []);
 
   AddonManager.getAddonsByIDs(["addon1@tests.mozilla.org",
                                "addon2@tests.mozilla.org",
                                "addon3@tests.mozilla.org",
                                "addon4@tests.mozilla.org",
                                "addon5@tests.mozilla.org",
-                               "addon6@tests.mozilla.org"],
-                               function([a1, a2, a3, a4, a5, a6]) {
+                               "addon6@tests.mozilla.org",
+                               "addon7@tests.mozilla.org",
+                               "addon8@tests.mozilla.org"],
+                               function([a1, a2, a3, a4, a5, a6, a7, a8]) {
     // addon1 was enabled in the database
     do_check_neq(a1, null);
     do_check_false(a1.userDisabled);
     do_check_false(a1.appDisabled);
     do_check_true(a1.isActive);
     do_check_false(a1.strictCompatibility);
+    do_check_false(a1.foreignInstall);
     // addon2 was disabled in the database
     do_check_neq(a2, null);
     do_check_true(a2.userDisabled);
     do_check_false(a2.appDisabled);
     do_check_false(a2.isActive);
     do_check_false(a2.strictCompatibility);
+    do_check_false(a2.foreignInstall);
     // addon3 was pending-disable in the database
     do_check_neq(a3, null);
     do_check_true(a3.userDisabled);
     do_check_false(a3.appDisabled);
     do_check_false(a3.isActive);
     do_check_false(a3.strictCompatibility);
+    do_check_false(a3.foreignInstall);
     // addon4 was pending-enable in the database
     do_check_neq(a4, null);
     do_check_false(a4.userDisabled);
     do_check_false(a4.appDisabled);
     do_check_true(a4.isActive);
     do_check_true(a4.strictCompatibility);
+    do_check_false(a4.foreignInstall);
     // addon5 was enabled in the database but needed a compatibiltiy update
     do_check_neq(a5, null);
     do_check_false(a5.userDisabled);
     do_check_false(a5.appDisabled);
     do_check_true(a5.isActive);
     do_check_false(a5.strictCompatibility);
+    do_check_false(a5.foreignInstall);
     // addon6 was disabled and compatible but a new version has been installed
     // since, it should still be disabled but should be incompatible
     do_check_neq(a6, null);
     do_check_true(a6.userDisabled);
     do_check_true(a6.appDisabled);
     do_check_false(a6.isActive);
     do_check_false(a6.strictCompatibility);
+    do_check_false(a6.foreignInstall);
+    // addon7 is in the global install location so should be a foreignInstall
+    do_check_neq(a7, null);
+    do_check_false(a7.userDisabled);
+    do_check_false(a7.appDisabled);
+    do_check_true(a7.isActive);
+    do_check_false(a7.strictCompatibility);
+    do_check_true(a7.foreignInstall);
+    // addon8 is in the user install location so should be a foreignInstall
+    do_check_neq(a8, null);
+    do_check_false(a8.userDisabled);
+    do_check_false(a8.appDisabled);
+    do_check_true(a8.isActive);
+    do_check_false(a8.strictCompatibility);
+    do_check_true(a8.foreignInstall);
+
     do_test_finished();
   });
 }
--- a/toolkit/mozapps/extensions/test/xpcshell/test_migrate4.js
+++ b/toolkit/mozapps/extensions/test/xpcshell/test_migrate4.js
@@ -71,16 +71,28 @@ var addon6 = {
   updateURL: "http://localhost:4444/data/test_migrate4.rdf",
   targetApplications: [{
     id: "xpcshell@tests.mozilla.org",
     minVersion: "0",
     maxVersion: "1"
   }]
 };
 
+var defaultTheme = {
+  id: "default@tests.mozilla.org",
+  version: "1.0",
+  name: "Default",
+  internalName: "classic/1.0",
+  targetApplications: [{
+    id: "xpcshell@tests.mozilla.org",
+    minVersion: "1",
+    maxVersion: "2"
+  }]
+};
+
 const profileDir = gProfD.clone();
 profileDir.append("extensions");
 
 do_load_httpd_js();
 var testserver;
 
 let oldSyncGUIDs = {};
 
@@ -94,33 +106,36 @@ function prepare_profile() {
   testserver.start(4444);
 
   writeInstallRDFForExtension(addon1, profileDir);
   writeInstallRDFForExtension(addon2, profileDir);
   writeInstallRDFForExtension(addon3, profileDir);
   writeInstallRDFForExtension(addon4, profileDir);
   writeInstallRDFForExtension(addon5, profileDir);
   writeInstallRDFForExtension(addon6, profileDir);
+  writeInstallRDFForExtension(defaultTheme, profileDir);
 
   startupManager();
-  installAllFiles([do_get_addon("test_migrate8")],
+  installAllFiles([do_get_addon("test_migrate8"), do_get_addon("test_migrate9")],
                   function() {
     restartManager();
 
     AddonManager.getAddonsByIDs(["addon1@tests.mozilla.org",
                                  "addon2@tests.mozilla.org",
                                  "addon3@tests.mozilla.org",
                                  "addon4@tests.mozilla.org",
                                  "addon5@tests.mozilla.org",
-                                 "addon6@tests.mozilla.org"],
-                                 function([a1, a2, a3, a4, a5, a6]) {
+                                 "addon6@tests.mozilla.org",
+                                 "addon9@tests.mozilla.org"],
+                                 function([a1, a2, a3, a4, a5, a6, a9]) {
       a2.userDisabled = true;
       a2.applyBackgroundUpdates = false;
       a4.userDisabled = true;
       a6.userDisabled = true;
+      a9.userDisabled = false;
 
       for each (let addon in [a1, a2, a3, a4, a5, a6]) {
         oldSyncGUIDs[addon.id] = addon.syncGUID;
       }
 
       a6.findUpdates({
         onUpdateAvailable: function(aAddon, aInstall6) {
           AddonManager.getInstallForURL("http://localhost:4444/addons/test_migrate4_7.xpi", function(aInstall7) {
@@ -149,16 +164,19 @@ function prepare_profile() {
           }, "application/x-xpinstall");
         }
       }, AddonManager.UPDATE_WHEN_USER_REQUESTED);
     });
   });
 }
 
 function perform_migration() {
+  // Turn on disabling for all scopes
+  Services.prefs.setIntPref("extensions.autoDisableScopes", 15);
+
   let dbfile = gProfD.clone();
   dbfile.append("extensions.sqlite");
   let db = AM_Cc["@mozilla.org/storage/service;1"].
            getService(AM_Ci.mozIStorageService).
            openDatabase(dbfile);
   db.schemaVersion = 1;
   Services.prefs.setIntPref("extensions.databaseSchema", 1);
   db.close();
@@ -177,18 +195,19 @@ function test_results() {
 
   AddonManager.getAddonsByIDs(["addon1@tests.mozilla.org",
                                "addon2@tests.mozilla.org",
                                "addon3@tests.mozilla.org",
                                "addon4@tests.mozilla.org",
                                "addon5@tests.mozilla.org",
                                "addon6@tests.mozilla.org",
                                "addon7@tests.mozilla.org",
-                               "addon8@tests.mozilla.org"],
-                               function([a1, a2, a3, a4, a5, a6, a7, a8]) {
+                               "addon8@tests.mozilla.org",
+                               "addon9@tests.mozilla.org"],
+                               function([a1, a2, a3, a4, a5, a6, a7, a8, a9]) {
     // addon1 was enabled
     do_check_neq(a1, null);
     do_check_eq(a1.syncGUID, oldSyncGUIDs[a1.id]);
     do_check_false(a1.userDisabled);
     do_check_false(a1.appDisabled);
     do_check_true(a1.isActive);
     do_check_true(a1.applyBackgroundUpdates);
     do_check_true(a1.foreignInstall);
@@ -265,19 +284,29 @@ function test_results() {
     do_check_false(a7.hasBinaryComponents);
     do_check_false(a7.strictCompatibility);
 
     // addon8 was enabled and has binary components
     do_check_neq(a8, null);
     do_check_false(a8.userDisabled);
     do_check_false(a8.appDisabled);
     do_check_true(a8.isActive);
+    do_check_false(a8.foreignInstall);
     do_check_true(a8.hasBinaryComponents);
     do_check_false(a8.strictCompatibility);
 
+    // addon9 is the active theme
+    do_check_neq(a9, null);
+    do_check_false(a9.userDisabled);
+    do_check_false(a9.appDisabled);
+    do_check_true(a9.isActive);
+    do_check_false(a9.foreignInstall);
+    do_check_false(a9.hasBinaryComponents);
+    do_check_true(a9.strictCompatibility);
+
     testserver.stop(do_test_finished);
   });
 }
 
 function run_test() {
   do_test_pending();
 
   prepare_profile();