Bug 555486: Add a scope property to add-ons and allow disabling loading add-ons from certain scopes. r=robstrong
authorDave Townsend <dtownsend@oxymoronical.com>
Wed, 07 Apr 2010 11:08:32 -0700
changeset 42054 98501168f5febac77459e114834ac534c5b3e43b
parent 42053 3c29db4a650eea9e55b6915a3daa46fcd554e0c1
child 42055 9ff0a98f2ff35ab150fdca45f928e6525dab5cf7
push id1
push userroot
push dateTue, 26 Apr 2011 22:38:44 +0000
treeherdermozilla-beta@bfdb6e623a36 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersrobstrong
bugs555486
milestone1.9.3a5pre
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
Bug 555486: Add a scope property to add-ons and allow disabling loading add-ons from certain scopes. r=robstrong
build/automation.py.in
toolkit/mozapps/extensions/AddonManager.jsm
toolkit/mozapps/extensions/XPIProvider.jsm
toolkit/mozapps/extensions/test/xpcshell/head_addons.js
toolkit/mozapps/extensions/test/xpcshell/test_general.js
toolkit/mozapps/extensions/test/xpcshell/test_registry.js
toolkit/mozapps/extensions/test/xpcshell/test_startup.js
toolkit/mozapps/extensions/test/xpcshell/test_theme.js
--- a/build/automation.py.in
+++ b/build/automation.py.in
@@ -307,16 +307,17 @@ user_pref("browser.EULA.override", true)
 user_pref("javascript.options.jit.content", true);
 user_pref("gfx.color_management.force_srgb", true);
 user_pref("network.manage-offline-status", false);
 user_pref("test.mousescroll", true);
 user_pref("security.default_personal_cert", "Select Automatically"); // Need to client auth test be w/o any dialogs
 user_pref("network.http.prompt-temp-redirect", false);
 user_pref("media.cache_size", 100);
 user_pref("security.warn_viewing_mixed", false);
+user_pref("extensions.enabledScopes", 3);
 
 user_pref("geo.wifi.uri", "http://%(server)s/tests/dom/tests/mochitest/geolocation/network_geolocation.sjs");
 user_pref("geo.wifi.testing", true);
 
 user_pref("camino.warn_when_closing", false); // Camino-only, harmless to others
 
 // Make url-classifier updates so rare that they won't affect tests
 user_pref("urlclassifier.updateinterval", 172800);
--- a/toolkit/mozapps/extensions/AddonManager.jsm
+++ b/toolkit/mozapps/extensions/AddonManager.jsm
@@ -822,16 +822,28 @@ var AddonManager = {
   PERM_CAN_UNINSTALL: 1,
   // Indicates that the Addon can be enabled by the user.
   PERM_CAN_ENABLE: 2,
   // Indicates that the Addon can be disabled by the user.
   PERM_CAN_DISABLE: 4,
   // Indicates that the Addon can be upgraded.
   PERM_CAN_UPGRADE: 8,
 
+  // General descriptions of where items are installed.
+  // Installed in this profile.
+  SCOPE_PROFILE: 1,
+  // Installed for all of this user's profiles.
+  SCOPE_USER: 2,
+  // Installed and owned by the application.
+  SCOPE_APPLICATION: 4,
+  // Installed for all users of the computer.
+  SCOPE_SYSTEM: 8,
+  // The combination of all scopes.
+  SCOPE_ALL: 15,
+
   getInstallForURL: function AM_getInstallForURL(url, callback, mimetype, hash,
                                                  name, iconURL, version,
                                                  loadGroup) {
     AddonManagerInternal.getInstallForURL(url, callback, mimetype, hash, name,
                                          iconURL, version, loadGroup);
   },
 
   getInstallForFile: function AM_getInstallForFile(file, callback, mimetype) {
--- a/toolkit/mozapps/extensions/XPIProvider.jsm
+++ b/toolkit/mozapps/extensions/XPIProvider.jsm
@@ -58,16 +58,17 @@ const PREF_EM_DSS_ENABLED             = 
 const PREF_DSS_SWITCHPENDING          = "extensions.dss.switchPending";
 const PREF_DSS_SKIN_TO_SELECT         = "extensions.lastSelectedSkin";
 const PREF_GENERAL_SKINS_SELECTEDSKIN = "general.skins.selectedSkin";
 const PREF_EM_CHECK_COMPATIBILITY     = "extensions.checkCompatibility";
 const PREF_EM_CHECK_UPDATE_SECURITY   = "extensions.checkUpdateSecurity";
 const PREF_EM_UPDATE_URL              = "extensions.update.url";
 const PREF_EM_ENABLED_ADDONS          = "extensions.enabledAddons";
 const PREF_EM_EXTENSION_FORMAT        = "extensions.";
+const PREF_EM_ENABLED_SCOPES          = "extensions.enabledScopes";
 const PREF_XPI_ENABLED                = "xpinstall.enabled";
 const PREF_XPI_WHITELIST_REQUIRED     = "xpinstall.whitelist.required";
 
 const DIR_EXTENSIONS                  = "extensions";
 const DIR_STAGE                       = "staged";
 
 const FILE_OLD_DATABASE               = "extensions.rdf";
 const FILE_DATABASE                   = "extensions.sqlite";
@@ -777,63 +778,92 @@ var XPIProvider = {
    * Starts the XPI provider initializes the install locations and prefs.
    */
   startup: function XPI_startup() {
     LOG("startup");
     this.installs = [];
     this.installLocations = [];
     this.installLocationsByName = {};
 
-    function addDirectoryInstallLocation(name, key, paths, locked) {
+    function addDirectoryInstallLocation(name, key, paths, scope, locked) {
       try {
         var dir = FileUtils.getDir(key, paths);
       }
       catch (e) {
         // Some directories aren't defined on some platforms, ignore them
         LOG("Skipping unavailable install location " + name);
         return;
       }
 
       try {
-        var location = new DirectoryInstallLocation(name, dir, locked);
+        var location = new DirectoryInstallLocation(name, dir, scope, locked);
       }
       catch (e) {
         WARN("Failed to add directory install location " + name + " " + e);
         return;
       }
 
       XPIProvider.installLocations.push(location);
       XPIProvider.installLocationsByName[location.name] = location;
     }
 
-    function addRegistryInstallLocation(name, rootkey) {
+    function addRegistryInstallLocation(name, rootkey, scope) {
       try {
-        var location = new WinRegInstallLocation(name, rootkey);
+        var location = new WinRegInstallLocation(name, rootkey, scope);
       }
       catch (e) {
         WARN("Failed to add registry install location " + name + " " + e);
         return;
       }
 
       XPIProvider.installLocations.push(location);
       XPIProvider.installLocationsByName[location.name] = location;
     }
 
     let hasRegistry = ("nsIWindowsRegKey" in Ci);
 
+    let enabledScopes = Prefs.getIntPref(PREF_EM_ENABLED_SCOPES,
+                                         AddonManager.SCOPE_ALL);
+
     // These must be in order of priority for processFileChanges etc. to work
-    if (hasRegistry)
-      addRegistryInstallLocation("winreg-app-global", Ci.nsIWindowsRegKey.ROOT_KEY_LOCAL_MACHINE);
-    addDirectoryInstallLocation(KEY_APP_SYSTEM_LOCAL, "XRESysLExtPD", [Services.appinfo.ID], true);
-    addDirectoryInstallLocation(KEY_APP_SYSTEM_SHARE, "XRESysSExtPD", [Services.appinfo.ID], true);
-    addDirectoryInstallLocation(KEY_APP_GLOBAL,       KEY_APPDIR,     [DIR_EXTENSIONS], true);
-    if (hasRegistry)
-      addRegistryInstallLocation("winreg-app-user", Ci.nsIWindowsRegKey.ROOT_KEY_CURRENT_USER);
-    addDirectoryInstallLocation(KEY_APP_SYSTEM_USER,  "XREUSysExt",   [Services.appinfo.ID], true);
-    addDirectoryInstallLocation(KEY_APP_PROFILE,      KEY_PROFILEDIR, [DIR_EXTENSIONS], false);
+    if (enabledScopes & AddonManager.SCOPE_SYSTEM) {
+      if (hasRegistry) {
+        addRegistryInstallLocation("winreg-app-global",
+                                   Ci.nsIWindowsRegKey.ROOT_KEY_LOCAL_MACHINE,
+                                   AddonManager.SCOPE_SYSTEM);
+      }
+      addDirectoryInstallLocation(KEY_APP_SYSTEM_LOCAL, "XRESysLExtPD",
+                                  [Services.appinfo.ID],
+                                  AddonManager.SCOPE_SYSTEM, true);
+      addDirectoryInstallLocation(KEY_APP_SYSTEM_SHARE, "XRESysSExtPD",
+                                  [Services.appinfo.ID],
+                                  AddonManager.SCOPE_SYSTEM, true);
+    }
+
+    if (enabledScopes & AddonManager.SCOPE_APPLICATION) {
+      addDirectoryInstallLocation(KEY_APP_GLOBAL, KEY_APPDIR,
+                                  [DIR_EXTENSIONS],
+                                  AddonManager.SCOPE_APPLICATION, true);
+    }
+
+    if (enabledScopes & AddonManager.SCOPE_USER) {
+      if (hasRegistry) {
+        addRegistryInstallLocation("winreg-app-user",
+                                   Ci.nsIWindowsRegKey.ROOT_KEY_CURRENT_USER,
+                                   AddonManager.SCOPE_USER);
+      }
+      addDirectoryInstallLocation(KEY_APP_SYSTEM_USER, "XREUSysExt",
+                                  [Services.appinfo.ID],
+                                  AddonManager.SCOPE_USER, true);
+    }
+
+    // The profile location is always enabled
+    addDirectoryInstallLocation(KEY_APP_PROFILE, KEY_PROFILEDIR,
+                                [DIR_EXTENSIONS],
+                                AddonManager.SCOPE_PROFILE, false);
 
     this.defaultSkin = Prefs.getDefaultCharPref(PREF_GENERAL_SKINS_SELECTEDSKIN,
                                                 "classic/1.0");
     this.selectedSkin = Prefs.getCharPref(PREF_GENERAL_SKINS_SELECTEDSKIN,
                                           this.defaultSkin);
 
     // Tell the Chrome Registry which Skin to select
     if (Prefs.getBoolPref(PREF_DSS_SWITCHPENDING, false)) {
@@ -4242,16 +4272,23 @@ function AddonWrapper(addon) {
       return null;
     return addon._install.wrapper;
   });
 
   this.__defineGetter__("pendingUpgrade", function() {
     return createWrapper(addon.pendingUpgrade);
   });
 
+  this.__defineGetter__("scope", function() {
+    if (addon._installLocation)
+      return addon._installLocation.scope;
+
+    return AddonManager.SCOPE_PROFILE;
+  });
+
   this.__defineGetter__("pendingOperations", function() {
     let pending = 0;
     if (!(addon instanceof DBAddonInternal))
       pending |= AddonManager.PENDING_INSTALL;
     else if (addon.pendingUninstall)
       pending |= AddonManager.PENDING_UNINSTALL;
 
     if (addon.active && (addon.userDisabled || addon.appDisabled))
@@ -4377,24 +4414,27 @@ AddonWrapper.prototype = {
  * then it means the add-on will be uninstalled from this location during the
  * next startup. If the directory contains the add-on's files then they will be
  * installed during the next startup.
  *
  * @param   name
  *          The string identifier for the install location
  * @param   directory
  *          The nsIFile directory for the install location
+ * @param   scope
+ *          The scope of add-ons installed in this location
  * @param   locked
  *          true if add-ons cannot be installed, uninstalled or upgraded in the
  *          install location
  */
-function DirectoryInstallLocation(name, directory, locked) {
+function DirectoryInstallLocation(name, directory, scope, locked) {
   this._name = name;
   this.locked = locked;
   this._directory = directory;
+  this._scope = scope
   this._IDToDirMap = {};
   this._DirToIDMap = {};
 
   if (!directory.exists())
     return;
   if (!directory.isDirectory())
     throw new Error("Location must be a directory.");
 
@@ -4492,16 +4532,23 @@ DirectoryInstallLocation.prototype = {
   /**
    * Gets the name of this install location.
    */
   get name() {
     return this._name;
   },
 
   /**
+   * Gets the scope of this install location.
+   */
+  get scope() {
+    return this._scope;
+  },
+
+  /**
    * Gets an array of nsIFiles for add-ons installed in this location.
    */
   get addonLocations() {
     let locations = [];
     for (let id in this._IDToDirMap) {
       locations.push(this._IDToDirMap[id].clone()
                          .QueryInterface(Ci.nsILocalFile));
     }
@@ -4597,22 +4644,24 @@ DirectoryInstallLocation.prototype = {
  * An object that identifies a registry install location for add-ons. The location
  * consists of a registry key which contains string values mapping ID to the
  * directory where an add-on is installed
  *
  * @param   name
  *          The string identifier of this Install Location.
  * @param   rootKey
  *          The root key (one of the ROOT_KEY_ values from nsIWindowsRegKey).
- * @constructor
+ * @param   scope
+ *          The scope of add-ons installed in this location
  */
-function WinRegInstallLocation(name, rootKey) {
+function WinRegInstallLocation(name, rootKey, scope) {
   this.locked = true;
   this._name = name;
   this._rootKey = rootKey;
+  this._scope = scope;
   this._IDToDirMap = {};
   this._DirToIDMap = {};
 
   let path = this._appKeyPath + "\\Extensions";
   let key = Cc["@mozilla.org/windows-registry-key;1"].
             createInstance(Ci.nsIWindowsRegKey);
 
   // Reading the registry may throw an exception, and that's ok.  In error
@@ -4626,16 +4675,17 @@ function WinRegInstallLocation(name, roo
 
   this._readAddons(key);
   key.close();
 }
 
 WinRegInstallLocation.prototype = {
   _name       : "",
   _rootKey    : null,
+  _scope      : null,
   _IDToDirMap : null,  // mapping from ID to directory object
   _DirToIDMap : null,  // mapping from directory path to ID
 
   /**
    * Retrieves the path of this Application's data key in the registry.
    */
   get _appKeyPath() {
     let appVendor = Services.appinfo.vendor;
@@ -4683,16 +4733,23 @@ WinRegInstallLocation.prototype = {
   /**
    * Gets the name of this install location.
    */
   get name() {
     return this._name;
   },
 
   /**
+   * Gets the scope of this install location.
+   */
+  get scope() {
+    return this._scope;
+  },
+
+  /**
    * Gets an array of nsIFiles for add-ons installed in this location.
    */
   get addonLocations() {
     let locations = [];
     for (let id in this._IDToDirMap) {
       locations.push(this._IDToDirMap[id].clone()
                          .QueryInterface(Ci.nsILocalFile));
     }
--- a/toolkit/mozapps/extensions/test/xpcshell/head_addons.js
+++ b/toolkit/mozapps/extensions/test/xpcshell/head_addons.js
@@ -639,9 +639,12 @@ if ("nsIWindowsRegKey" in AM_Ci) {
 }
 
 // Get the profile directory for tests to use.
 const gProfD = do_get_profile().QueryInterface(AM_Ci.nsILocalFile);
 
 // Enable more extensive EM logging
 Services.prefs.setBoolPref("extensions.logging.enabled", true);
 
+// By default only load extensions from the profile install location
+Services.prefs.setIntPref("extensions.enabledScopes", AddonManager.SCOPE_PROFILE);
+
 do_register_cleanup(shutdownManager);
--- a/toolkit/mozapps/extensions/test/xpcshell/test_general.js
+++ b/toolkit/mozapps/extensions/test/xpcshell/test_general.js
@@ -1,17 +1,17 @@
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/
  */
 
 // This just verifies that the EM can actually startup and shutdown a few times
 // without any errors
 
-// We have to look up how many add-ons are present in case apps like SeaMonkey
-// try to use this test with their built-in add-ons.
+// We have to look up how many add-ons are present since there will be plugins
+// etc. detected
 var gCount;
 
 function run_test() {
   do_test_pending();
   createAppInfo("xpcshell@tests.mozilla.org", "XPCShell", "1", "1.9.2");
 
   var count = 0;
   startupManager(1);
--- a/toolkit/mozapps/extensions/test/xpcshell/test_registry.js
+++ b/toolkit/mozapps/extensions/test/xpcshell/test_registry.js
@@ -1,15 +1,20 @@
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/
  */
 
 // Tests that extensions installed through the registry work as expected
 createAppInfo("xpcshell@tests.mozilla.org", "XPCShell", "1", "1.9.2");
 
+// 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",
     maxVersion: "1"
@@ -55,19 +60,22 @@ function run_test_1() {
 
   startupManager(1);
 
   AddonManager.getAddons(["addon1@tests.mozilla.org",
                           "addon2@tests.mozilla.org"], function([a1, a2]) {
     do_check_neq(a1, null);
     do_check_true(a1.isActive);
     do_check_false(hasFlag(a1.permissions, AddonManager.PERM_CAN_UNINSTALL));
+    do_check_eq(a1.scope, AddonManager.SCOPE_SYSTEM);
+
     do_check_neq(a2, null);
     do_check_true(a2.isActive);
     do_check_false(hasFlag(a2.permissions, AddonManager.PERM_CAN_UNINSTALL));
+    do_check_eq(a2.scope, AddonManager.SCOPE_USER);
 
     run_test_2();
   });
 }
 
 // Tests whether uninstalling from the registry works
 function run_test_2() {
   MockRegistry.setValue(AM_Ci.nsIWindowsRegKey.ROOT_KEY_LOCAL_MACHINE,
--- a/toolkit/mozapps/extensions/test/xpcshell/test_startup.js
+++ b/toolkit/mozapps/extensions/test/xpcshell/test_startup.js
@@ -1,18 +1,19 @@
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/
  */
 
 // This verifies startup detection of added/removed/changed items and install
 // location priorities
 
-// We try to count the non-test extensions the add-on manager detects like the
-// built-in extensions in seamonkey.
-var additionalAddons, additionalExtensions;
+// 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",
@@ -77,39 +78,33 @@ registerDirectory("XREUSysExt", userDir.
 const profileDir = gProfD.clone();
 profileDir.append("extensions");
 
 // Set up the profile
 function run_test() {
   do_test_pending();
   startupManager(1);
 
-  AddonManager.getAddonsByTypes(null, function(allAddons) {
-    additionalAddons = allAddons.length;
-    AddonManager.getAddonsByTypes(["extension"], function(allExtensions) {
-      additionalExtensions = allExtensions.length;
-      AddonManager.getAddons(["addon1@tests.mozilla.org",
-                              "addon2@tests.mozilla.org",
-                              "addon3@tests.mozilla.org",
-                              "addon4@tests.mozilla.org",
-                              "addon5@tests.mozilla.org"],
-                              function([a1, a2, a3, a4, a5]) {
+  AddonManager.getAddons(["addon1@tests.mozilla.org",
+                          "addon2@tests.mozilla.org",
+                          "addon3@tests.mozilla.org",
+                          "addon4@tests.mozilla.org",
+                          "addon5@tests.mozilla.org"],
+                          function([a1, a2, a3, a4, a5]) {
 
-        do_check_eq(a1, null);
-        do_check_not_in_crash_annotation(addon1.id, addon1.version);
-        do_check_eq(a2, null);
-        do_check_not_in_crash_annotation(addon2.id, addon2.version);
-        do_check_eq(a3, null);
-        do_check_not_in_crash_annotation(addon3.id, addon3.version);
-        do_check_eq(a4, null);
-        do_check_eq(a5, null);
+    do_check_eq(a1, null);
+    do_check_not_in_crash_annotation(addon1.id, addon1.version);
+    do_check_eq(a2, null);
+    do_check_not_in_crash_annotation(addon2.id, addon2.version);
+    do_check_eq(a3, null);
+    do_check_not_in_crash_annotation(addon3.id, addon3.version);
+    do_check_eq(a4, null);
+    do_check_eq(a5, null);
 
-        run_test_1();
-      });
-    });
+    run_test_1();
   });
 }
 
 function end_test() {
   do_test_finished();
 }
 
 // Try to install all the items into the profile
@@ -144,53 +139,53 @@ function run_test_1() {
     do_check_neq(a1, null);
     do_check_eq(a1.id, "addon1@tests.mozilla.org");
     do_check_eq(a1.version, "1.0");
     do_check_eq(a1.name, "Test 1");
     do_check_true(isExtensionInAddonsList(profileDir, a1.id));
     do_check_true(hasFlag(a1.permissions, AddonManager.PERM_CAN_UNINSTALL));
     do_check_true(hasFlag(a1.permissions, AddonManager.PERM_CAN_UPGRADE));
     do_check_in_crash_annotation(addon1.id, addon1.version);
+    do_check_eq(a1.scope, AddonManager.SCOPE_PROFILE);
 
     do_check_neq(a2, null);
     do_check_eq(a2.id, "addon2@tests.mozilla.org");
     do_check_eq(a2.version, "2.0");
     do_check_eq(a2.name, "Test 2");
     do_check_true(isExtensionInAddonsList(profileDir, a2.id));
     do_check_true(hasFlag(a2.permissions, AddonManager.PERM_CAN_UNINSTALL));
     do_check_true(hasFlag(a2.permissions, AddonManager.PERM_CAN_UPGRADE));
     do_check_in_crash_annotation(addon2.id, addon2.version);
+    do_check_eq(a2.scope, AddonManager.SCOPE_PROFILE);
 
     do_check_neq(a3, null);
     do_check_eq(a3.id, "addon3@tests.mozilla.org");
     do_check_eq(a3.version, "3.0");
     do_check_eq(a3.name, "Test 3");
     do_check_true(isExtensionInAddonsList(profileDir, a3.id));
     do_check_true(hasFlag(a3.permissions, AddonManager.PERM_CAN_UNINSTALL));
     do_check_true(hasFlag(a3.permissions, AddonManager.PERM_CAN_UPGRADE));
     do_check_in_crash_annotation(addon3.id, addon3.version);
+    do_check_eq(a3.scope, AddonManager.SCOPE_PROFILE);
 
     do_check_eq(a4, null);
     do_check_false(isExtensionInAddonsList(profileDir, "addon4@tests.mozilla.org"));
     dest = profileDir.clone();
     dest.append("addon4@tests.mozilla.org");
     do_check_false(dest.exists());
 
     do_check_eq(a5, null);
     do_check_false(isExtensionInAddonsList(profileDir, "addon5@tests.mozilla.org"));
     dest = profileDir.clone();
     dest.append("addon5@tests.mozilla.org");
     do_check_false(dest.exists());
 
-    AddonManager.getAddonsByTypes(null, function(addons) {
-      do_check_eq(addons.length, 3 + additionalAddons);
-      AddonManager.getAddonsByTypes(["extension"], function(extensionAddons) {
-        do_check_eq(extensionAddons.length, 3 + additionalExtensions);
-        run_test_2();
-      });
+    AddonManager.getAddonsByTypes(["extension"], function(extensionAddons) {
+      do_check_eq(extensionAddons.length, 3);
+      run_test_2();
     });
   });
 }
 
 // Test that modified items are detected and items in other install locations
 // are ignored
 function run_test_2() {
   var dest = userDir.clone();
@@ -225,26 +220,28 @@ function run_test_2() {
     do_check_neq(a1, null);
     do_check_eq(a1.id, "addon1@tests.mozilla.org");
     do_check_eq(a1.version, "1.0");
     do_check_true(isExtensionInAddonsList(profileDir, a1.id));
     do_check_false(isExtensionInAddonsList(userDir, a1.id));
     do_check_true(hasFlag(a1.permissions, AddonManager.PERM_CAN_UNINSTALL));
     do_check_true(hasFlag(a1.permissions, AddonManager.PERM_CAN_UPGRADE));
     do_check_in_crash_annotation(addon1.id, a1.version);
+    do_check_eq(a1.scope, AddonManager.SCOPE_PROFILE);
 
     do_check_neq(a2, null);
     do_check_eq(a2.id, "addon2@tests.mozilla.org");
     do_check_eq(a2.version, "2.1");
     do_check_true(isExtensionInAddonsList(profileDir, a2.id));
     do_check_false(isExtensionInAddonsList(userDir, a2.id));
     do_check_false(isExtensionInAddonsList(globalDir, a2.id));
     do_check_true(hasFlag(a2.permissions, AddonManager.PERM_CAN_UNINSTALL));
     do_check_true(hasFlag(a2.permissions, AddonManager.PERM_CAN_UPGRADE));
     do_check_in_crash_annotation(addon2.id, a2.version);
+    do_check_eq(a2.scope, AddonManager.SCOPE_PROFILE);
 
     do_check_eq(a3, null);
     do_check_false(isExtensionInAddonsList(profileDir, "addon3@tests.mozilla.org"));
     do_check_not_in_crash_annotation(addon3.id, addon3.version);
 
     do_check_eq(a4, null);
     do_check_false(isExtensionInAddonsList(profileDir, "addon4@tests.mozilla.org"));
 
@@ -279,26 +276,28 @@ function run_test_3() {
     do_check_neq(a1, null);
     do_check_eq(a1.id, "addon1@tests.mozilla.org");
     do_check_eq(a1.version, "1.1");
     do_check_false(isExtensionInAddonsList(profileDir, a1.id));
     do_check_true(isExtensionInAddonsList(userDir, a1.id));
     do_check_false(hasFlag(a1.permissions, AddonManager.PERM_CAN_UNINSTALL));
     do_check_false(hasFlag(a1.permissions, AddonManager.PERM_CAN_UPGRADE));
     do_check_in_crash_annotation(addon1.id, a1.version);
+    do_check_eq(a1.scope, AddonManager.SCOPE_USER);
 
     do_check_neq(a2, null);
     do_check_eq(a2.id, "addon2@tests.mozilla.org");
     do_check_eq(a2.version, "2.3");
     do_check_false(isExtensionInAddonsList(profileDir, a2.id));
     do_check_true(isExtensionInAddonsList(userDir, a2.id));
     do_check_false(isExtensionInAddonsList(globalDir, a2.id));
     do_check_false(hasFlag(a2.permissions, AddonManager.PERM_CAN_UNINSTALL));
     do_check_false(hasFlag(a2.permissions, AddonManager.PERM_CAN_UPGRADE));
     do_check_in_crash_annotation(addon2.id, a2.version);
+    do_check_eq(a2.scope, AddonManager.SCOPE_USER);
 
     do_check_eq(a3, null);
     do_check_false(isExtensionInAddonsList(profileDir, "addon3@tests.mozilla.org"));
 
     do_check_eq(a4, null);
     do_check_false(isExtensionInAddonsList(profileDir, "addon4@tests.mozilla.org"));
 
     do_check_eq(a5, null);
@@ -307,18 +306,126 @@ function run_test_3() {
     dest = profileDir.clone();
     dest.append("addon4@tests.mozilla.org");
     do_check_false(dest.exists());
 
     run_test_4();
   });
 }
 
+// Test that disabling an install location works
+function run_test_4() {
+  Services.prefs.setIntPref("extensions.enabledScopes", AddonManager.SCOPE_SYSTEM);
+
+  restartManager(1);
+
+  AddonManager.getAddons(["addon1@tests.mozilla.org",
+                          "addon2@tests.mozilla.org",
+                          "addon3@tests.mozilla.org",
+                          "addon4@tests.mozilla.org",
+                          "addon5@tests.mozilla.org"],
+                          function([a1, a2, a3, a4, a5]) {
+
+    do_check_eq(a1, null);
+    do_check_false(isExtensionInAddonsList(profileDir, "addon1@tests.mozilla.org"));
+    do_check_false(isExtensionInAddonsList(userDir, "addon1@tests.mozilla.org"));
+
+    do_check_neq(a2, null);
+    do_check_eq(a2.id, "addon2@tests.mozilla.org");
+    do_check_eq(a2.version, "2.2");
+    do_check_false(isExtensionInAddonsList(profileDir, a2.id));
+    do_check_false(isExtensionInAddonsList(userDir, a2.id));
+    do_check_true(isExtensionInAddonsList(globalDir, a2.id));
+    do_check_false(hasFlag(a2.permissions, AddonManager.PERM_CAN_UNINSTALL));
+    do_check_false(hasFlag(a2.permissions, AddonManager.PERM_CAN_UPGRADE));
+    do_check_in_crash_annotation(addon2.id, a2.version);
+    do_check_eq(a2.scope, AddonManager.SCOPE_SYSTEM);
+
+    run_test_5();
+  });
+}
+
+// Switching disabled locations works
+function run_test_5() {
+  Services.prefs.setIntPref("extensions.enabledScopes", AddonManager.SCOPE_USER);
+
+  restartManager(1);
+
+  AddonManager.getAddons(["addon1@tests.mozilla.org",
+                          "addon2@tests.mozilla.org",
+                          "addon3@tests.mozilla.org",
+                          "addon4@tests.mozilla.org",
+                          "addon5@tests.mozilla.org"],
+                          function([a1, a2, a3, a4, a5]) {
+
+    do_check_neq(a1, null);
+    do_check_eq(a1.id, "addon1@tests.mozilla.org");
+    do_check_eq(a1.version, "1.1");
+    do_check_false(isExtensionInAddonsList(profileDir, a1.id));
+    do_check_true(isExtensionInAddonsList(userDir, a1.id));
+    do_check_false(hasFlag(a1.permissions, AddonManager.PERM_CAN_UNINSTALL));
+    do_check_false(hasFlag(a1.permissions, AddonManager.PERM_CAN_UPGRADE));
+    do_check_in_crash_annotation(addon1.id, a1.version);
+    do_check_eq(a1.scope, AddonManager.SCOPE_USER);
+
+    do_check_neq(a2, null);
+    do_check_eq(a2.id, "addon2@tests.mozilla.org");
+    do_check_eq(a2.version, "2.3");
+    do_check_false(isExtensionInAddonsList(profileDir, a2.id));
+    do_check_true(isExtensionInAddonsList(userDir, a2.id));
+    do_check_false(isExtensionInAddonsList(globalDir, a2.id));
+    do_check_false(hasFlag(a2.permissions, AddonManager.PERM_CAN_UNINSTALL));
+    do_check_false(hasFlag(a2.permissions, AddonManager.PERM_CAN_UPGRADE));
+    do_check_in_crash_annotation(addon2.id, a2.version);
+    do_check_eq(a2.scope, AddonManager.SCOPE_USER);
+
+    run_test_6();
+  });
+}
+
+// Resetting the pref makes everything visible again
+function run_test_6() {
+  Services.prefs.clearUserPref("extensions.enabledScopes");
+
+  restartManager(1);
+
+  AddonManager.getAddons(["addon1@tests.mozilla.org",
+                          "addon2@tests.mozilla.org",
+                          "addon3@tests.mozilla.org",
+                          "addon4@tests.mozilla.org",
+                          "addon5@tests.mozilla.org"],
+                          function([a1, a2, a3, a4, a5]) {
+
+    do_check_neq(a1, null);
+    do_check_eq(a1.id, "addon1@tests.mozilla.org");
+    do_check_eq(a1.version, "1.1");
+    do_check_false(isExtensionInAddonsList(profileDir, a1.id));
+    do_check_true(isExtensionInAddonsList(userDir, a1.id));
+    do_check_false(hasFlag(a1.permissions, AddonManager.PERM_CAN_UNINSTALL));
+    do_check_false(hasFlag(a1.permissions, AddonManager.PERM_CAN_UPGRADE));
+    do_check_in_crash_annotation(addon1.id, a1.version);
+    do_check_eq(a1.scope, AddonManager.SCOPE_USER);
+
+    do_check_neq(a2, null);
+    do_check_eq(a2.id, "addon2@tests.mozilla.org");
+    do_check_eq(a2.version, "2.3");
+    do_check_false(isExtensionInAddonsList(profileDir, a2.id));
+    do_check_true(isExtensionInAddonsList(userDir, a2.id));
+    do_check_false(isExtensionInAddonsList(globalDir, a2.id));
+    do_check_false(hasFlag(a2.permissions, AddonManager.PERM_CAN_UNINSTALL));
+    do_check_false(hasFlag(a2.permissions, AddonManager.PERM_CAN_UPGRADE));
+    do_check_in_crash_annotation(addon2.id, a2.version);
+    do_check_eq(a2.scope, AddonManager.SCOPE_USER);
+
+    run_test_7();
+  });
+}
+
 // Check that items in the profile hide the others again.
-function run_test_4() {
+function run_test_7() {
   var dest = profileDir.clone();
   dest.append("addon1@tests.mozilla.org");
   addon1.version = "1.2";
   writeInstallRDFToDir(addon1, dest);
   dest = userDir.clone();
   dest.append("addon2@tests.mozilla.org");
   dest.remove(true);
 
@@ -334,42 +441,78 @@ function run_test_4() {
     do_check_neq(a1, null);
     do_check_eq(a1.id, "addon1@tests.mozilla.org");
     do_check_eq(a1.version, "1.2");
     do_check_true(isExtensionInAddonsList(profileDir, a1.id));
     do_check_false(isExtensionInAddonsList(userDir, a1.id));
     do_check_true(hasFlag(a1.permissions, AddonManager.PERM_CAN_UNINSTALL));
     do_check_true(hasFlag(a1.permissions, AddonManager.PERM_CAN_UPGRADE));
     do_check_in_crash_annotation(addon1.id, a1.version);
+    do_check_eq(a1.scope, AddonManager.SCOPE_PROFILE);
 
     do_check_neq(a2, null);
     do_check_eq(a2.id, "addon2@tests.mozilla.org");
     do_check_eq(a2.version, "2.2");
     do_check_false(isExtensionInAddonsList(profileDir, a2.id));
     do_check_false(isExtensionInAddonsList(userDir, a2.id));
     do_check_true(isExtensionInAddonsList(globalDir, a2.id));
     do_check_false(hasFlag(a2.permissions, AddonManager.PERM_CAN_UNINSTALL));
     do_check_false(hasFlag(a2.permissions, AddonManager.PERM_CAN_UPGRADE));
     do_check_in_crash_annotation(addon2.id, a2.version);
+    do_check_eq(a2.scope, AddonManager.SCOPE_SYSTEM);
 
     do_check_eq(a3, null);
     do_check_false(isExtensionInAddonsList(profileDir, "addon3@tests.mozilla.org"));
 
     do_check_eq(a4, null);
     do_check_false(isExtensionInAddonsList(profileDir, "addon4@tests.mozilla.org"));
 
     do_check_eq(a5, null);
     do_check_false(isExtensionInAddonsList(profileDir, "addon5@tests.mozilla.org"));
 
-    run_test_5();
+    run_test_8();
+  });
+}
+
+// Disabling all locations still leaves the profile working
+function run_test_8() {
+  Services.prefs.setIntPref("extensions.enabledScopes", 0);
+
+  restartManager(1);
+
+  AddonManager.getAddons(["addon1@tests.mozilla.org",
+                          "addon2@tests.mozilla.org",
+                          "addon3@tests.mozilla.org",
+                          "addon4@tests.mozilla.org",
+                          "addon5@tests.mozilla.org"],
+                          function([a1, a2, a3, a4, a5]) {
+
+    do_check_neq(a1, null);
+    do_check_eq(a1.id, "addon1@tests.mozilla.org");
+    do_check_eq(a1.version, "1.2");
+    do_check_true(isExtensionInAddonsList(profileDir, a1.id));
+    do_check_false(isExtensionInAddonsList(userDir, a1.id));
+    do_check_true(hasFlag(a1.permissions, AddonManager.PERM_CAN_UNINSTALL));
+    do_check_true(hasFlag(a1.permissions, AddonManager.PERM_CAN_UPGRADE));
+    do_check_in_crash_annotation(addon1.id, a1.version);
+    do_check_eq(a1.scope, AddonManager.SCOPE_PROFILE);
+
+    do_check_eq(a2, null);
+    do_check_false(isExtensionInAddonsList(profileDir, "addon2@tests.mozilla.org"));
+    do_check_false(isExtensionInAddonsList(userDir, "addon2@tests.mozilla.org"));
+    do_check_false(isExtensionInAddonsList(globalDir, "addon2@tests.mozilla.org"));
+
+    run_test_9();
   });
 }
 
 // More hiding and revealing
-function run_test_5() {
+function run_test_9() {
+  Services.prefs.clearUserPref("extensions.enabledScopes", 0);
+
   var dest = userDir.clone();
   dest.append("addon1@tests.mozilla.org");
   dest.remove(true);
   dest = globalDir.clone();
   dest.append("addon2@tests.mozilla.org");
   dest.remove(true);
   dest = profileDir.clone();
   dest.append("addon2@tests.mozilla.org");
@@ -387,42 +530,44 @@ function run_test_5() {
 
     do_check_neq(a1, null);
     do_check_eq(a1.id, "addon1@tests.mozilla.org");
     do_check_eq(a1.version, "1.2");
     do_check_true(isExtensionInAddonsList(profileDir, a1.id));
     do_check_false(isExtensionInAddonsList(userDir, a1.id));
     do_check_true(hasFlag(a1.permissions, AddonManager.PERM_CAN_UNINSTALL));
     do_check_true(hasFlag(a1.permissions, AddonManager.PERM_CAN_UPGRADE));
+    do_check_eq(a1.scope, AddonManager.SCOPE_PROFILE);
 
     do_check_neq(a2, null);
     do_check_eq(a2.id, "addon2@tests.mozilla.org");
     do_check_eq(a2.version, "2.4");
     do_check_true(isExtensionInAddonsList(profileDir, a2.id));
     do_check_false(isExtensionInAddonsList(userDir, a2.id));
     do_check_false(isExtensionInAddonsList(globalDir, a2.id));
     do_check_true(hasFlag(a2.permissions, AddonManager.PERM_CAN_UNINSTALL));
     do_check_true(hasFlag(a2.permissions, AddonManager.PERM_CAN_UPGRADE));
+    do_check_eq(a2.scope, AddonManager.SCOPE_PROFILE);
 
     do_check_eq(a3, null);
     do_check_false(isExtensionInAddonsList(profileDir, "addon3@tests.mozilla.org"));
 
     do_check_eq(a4, null);
     do_check_false(isExtensionInAddonsList(profileDir, "addon4@tests.mozilla.org"));
 
     do_check_eq(a5, null);
     do_check_false(isExtensionInAddonsList(profileDir, "addon5@tests.mozilla.org"));
 
-    run_test_6();
+    run_test_10();
   });
 }
 
 // Checks that a removal from one location and an addition in another location
 // for the same item is handled
-function run_test_6() {
+function run_test_10() {
   var dest = profileDir.clone();
   dest.append("addon1@tests.mozilla.org");
   dest.remove(true);
   dest = userDir.clone();
   dest.append("addon1@tests.mozilla.org");
   addon1.version = "1.3";
   writeInstallRDFToDir(addon1, dest);
 
@@ -437,41 +582,43 @@ function run_test_6() {
 
     do_check_neq(a1, null);
     do_check_eq(a1.id, "addon1@tests.mozilla.org");
     do_check_eq(a1.version, "1.3");
     do_check_false(isExtensionInAddonsList(profileDir, a1.id));
     do_check_true(isExtensionInAddonsList(userDir, a1.id));
     do_check_false(hasFlag(a1.permissions, AddonManager.PERM_CAN_UNINSTALL));
     do_check_false(hasFlag(a1.permissions, AddonManager.PERM_CAN_UPGRADE));
+    do_check_eq(a1.scope, AddonManager.SCOPE_USER);
 
     do_check_neq(a2, null);
     do_check_eq(a2.id, "addon2@tests.mozilla.org");
     do_check_eq(a2.version, "2.4");
     do_check_true(isExtensionInAddonsList(profileDir, a2.id));
     do_check_false(isExtensionInAddonsList(userDir, a2.id));
     do_check_false(isExtensionInAddonsList(globalDir, a2.id));
     do_check_true(hasFlag(a2.permissions, AddonManager.PERM_CAN_UNINSTALL));
     do_check_true(hasFlag(a2.permissions, AddonManager.PERM_CAN_UPGRADE));
+    do_check_eq(a2.scope, AddonManager.SCOPE_PROFILE);
 
     do_check_eq(a3, null);
     do_check_false(isExtensionInAddonsList(profileDir, "addon3@tests.mozilla.org"));
 
     do_check_eq(a4, null);
     do_check_false(isExtensionInAddonsList(profileDir, "addon4@tests.mozilla.org"));
 
     do_check_eq(a5, null);
     do_check_false(isExtensionInAddonsList(profileDir, "addon5@tests.mozilla.org"));
 
-    run_test_7();
+    run_test_11();
   });
 }
 
 // This should remove any remaining items
-function run_test_7() {
+function run_test_11() {
   var dest = userDir.clone();
   dest.append("addon1@tests.mozilla.org");
   dest.remove(true);
   dest = profileDir.clone();
   dest.append("addon2@tests.mozilla.org");
   dest.remove(true);
 
   restartManager(1);
--- a/toolkit/mozapps/extensions/test/xpcshell/test_theme.js
+++ b/toolkit/mozapps/extensions/test/xpcshell/test_theme.js
@@ -27,30 +27,47 @@ function run_test() {
     type: 4,
     internalName: "theme1/1.0",
     targetApplications: [{
       id: "xpcshell@tests.mozilla.org",
       minVersion: "1",
       maxVersion: "2"
     }]
   }, dest);
+
   dest = profileDir.clone();
   dest.append("theme2@tests.mozilla.org");
   writeInstallRDFToDir({
     id: "theme2@tests.mozilla.org",
     version: "1.0",
     name: "Test 1",
     internalName: "theme2/1.0",
     targetApplications: [{
       id: "xpcshell@tests.mozilla.org",
       minVersion: "1",
       maxVersion: "2"
     }]
   }, dest);
 
+  // We need a default theme for some of these things to work but we have hidden
+  // the one in the application directory.
+  dest = profileDir.clone();
+  dest.append("default@tests.mozilla.org");
+  writeInstallRDFToDir({
+    id: "default@tests.mozilla.org",
+    version: "1.0",
+    name: "Default",
+    internalName: "classic/1.0",
+    targetApplications: [{
+      id: "xpcshell@tests.mozilla.org",
+      minVersion: "1",
+      maxVersion: "2"
+    }]
+  }, dest);
+
   startupManager(1);
   // Make sure we only register once despite multiple calls
   AddonManager.addInstallListener(InstallListener);
   AddonManager.addAddonListener(AddonListener);
   AddonManager.addInstallListener(InstallListener);
   AddonManager.addAddonListener(AddonListener);
   AddonManager.addInstallListener(InstallListener);
 
@@ -174,17 +191,17 @@ function run_test_3() {
 
   prepare_test({
     "1@personas.mozilla.org": [
       ["onInstalling", false],
       "onInstalled",
       ["onEnabling", false],
       "onEnabled"
     ],
-    "{972ce4c6-7e08-4474-a285-3208198ce6fd}": [
+    "default@tests.mozilla.org": [
       ["onDisabling", false],
       "onDisabled",
     ]
   }, [
     "onExternalInstall"
   ]);
 
   LightweightThemeManager.currentTheme = {
@@ -466,23 +483,22 @@ function run_test_7() {
 
     run_test_8();
   });
 }
 
 // Uninstalling a lightweight theme in use should not require a restart and it
 // should reactivate the default theme
 function run_test_8() {
-  // TODO stop this depending on the default theme being present
   prepare_test({
     "2@personas.mozilla.org": [
       ["onUninstalling", false],
       "onUninstalled"
     ],
-    "{972ce4c6-7e08-4474-a285-3208198ce6fd}": [
+    "default@tests.mozilla.org": [
       ["onEnabling", false],
       "onEnabled"
     ]
   });
 
   AddonManager.getAddon("2@personas.mozilla.org", function(p2) {
     p2.uninstall();
 
@@ -517,41 +533,41 @@ function run_test_9() {
 
 // Uninstalling a custom theme in use should require a restart
 function run_test_10() {
   AddonManager.getAddon("theme2@tests.mozilla.org", function(oldt2) {
     prepare_test({
       "theme2@tests.mozilla.org": [
         "onEnabling",
       ],
-      "{972ce4c6-7e08-4474-a285-3208198ce6fd}": [
+      "default@tests.mozilla.org": [
         "onDisabling"
       ]
     });
 
     oldt2.userDisabled = false;
 
     ensure_test_completed();
 
     restartManager(0);
 
-    AddonManager.getAddons(["{972ce4c6-7e08-4474-a285-3208198ce6fd}",
+    AddonManager.getAddons(["default@tests.mozilla.org",
                             "theme2@tests.mozilla.org"], function([d, t2]) {
       do_check_true(t2.isActive);
       do_check_false(t2.userDisabled);
       do_check_false(t2.appDisabled);
       do_check_false(d.isActive);
       do_check_true(d.userDisabled);
       do_check_false(d.appDisabled);
 
       prepare_test({
         "theme2@tests.mozilla.org": [
           "onUninstalling",
         ],
-        "{972ce4c6-7e08-4474-a285-3208198ce6fd}": [
+        "default@tests.mozilla.org": [
           "onEnabling"
         ]
       });
 
       t2.uninstall();
 
       ensure_test_completed();
 
@@ -636,17 +652,17 @@ function check_test_12() {
 
 // Updating a custom theme in use should require a restart
 function run_test_13() {
   AddonManager.getAddon("theme1@tests.mozilla.org", function(t1) {
     prepare_test({
       "theme1@tests.mozilla.org": [
         "onEnabling",
       ],
-      "{972ce4c6-7e08-4474-a285-3208198ce6fd}": [
+      "default@tests.mozilla.org": [
         "onDisabling"
       ]
     });
 
     t1.userDisabled = false;
     ensure_test_completed();
     restartManager(0);