Backed out 11 changesets (bug 1059079, bug 1015518, bug 900551, bug 846200) for Gaia UI test failures on a CLOSED TREE.
authorRyan VanderMeulen <ryanvm@gmail.com>
Thu, 28 Aug 2014 12:49:49 -0400
changeset 223806 7c97c5f7a05e229ef8210c2e2766e4e212218b91
parent 223805 c498b3767ae7eb578e914676bc41019cd3a7728f
child 223807 76b26a3f9392e26dd5ce744c4962329267bc1060
push id3979
push userraliiev@mozilla.com
push dateMon, 13 Oct 2014 16:35:44 +0000
treeherdermozilla-beta@30f2cc610691 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs1059079, 1015518, 900551, 846200
milestone34.0a1
backs outd85b4e48b3b46233418d9f260a7277cbbf719c44
663b73ba69ec7a522635c879f61ebf3fae2df788
5cf1cb5fa02281b979cab1d8a5693726921e195b
b953dd5bfdaabcad3f639ef5411fd836f10fcab7
a2b6d7c84100055c0063e06f288db7d57a875092
ceb79fe83d15ffea7abda042a73b453e9cac93aa
f6acf344fbf0ba8f118a31bacfbb89cb20a5565c
fa269ea539376efc5d4494233a82d41cd7ad9950
b89c84a850f936bf4436030162c68d2860dca74b
b7a7dfbe4e3faba12323a7350b11eb635541dcd0
c6f54d821c11ee5b2d71281cb8a37d680a32618e
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
Backed out 11 changesets (bug 1059079, bug 1015518, bug 900551, bug 846200) for Gaia UI test failures on a CLOSED TREE. Backed out changeset d85b4e48b3b4 (bug 1015518) Backed out changeset 663b73ba69ec (bug 1015518) Backed out changeset 5cf1cb5fa022 (bug 900551) Backed out changeset b953dd5bfdaa (bug 900551) Backed out changeset a2b6d7c84100 (bug 900551) Backed out changeset ceb79fe83d15 (bug 900551) Backed out changeset f6acf344fbf0 (bug 900551) Backed out changeset fa269ea53937 (bug 846200) Backed out changeset b89c84a850f9 (bug 846200) Backed out changeset b7a7dfbe4e3f (bug 846200) Backed out changeset c6f54d821c11 (bug 1059079)
b2g/chrome/content/shell.js
dom/apps/src/PermissionsInstaller.jsm
dom/apps/src/PermissionsTable.jsm
dom/base/Navigator.cpp
dom/bluetooth/tests/marionette/head.js
dom/bluetooth/tests/marionette/manifest.ini
dom/bluetooth/tests/marionette/test_dom_BluetoothManager_enabled.js
dom/bluetooth2/tests/marionette/test_dom_BluetoothManager_API2.js
dom/events/test/test_all_synthetic_events.html
dom/fmradio/test/marionette/test_bug876597.js
dom/ipc/preload.js
dom/mobileconnection/tests/marionette/test_dsds_mobile_data_connection.js
dom/mobileconnection/tests/marionette/test_mobile_data_connection.js
dom/mobileconnection/tests/marionette/test_mobile_data_ipv6.js
dom/mobileconnection/tests/marionette/test_mobile_set_radio.js
dom/permission/tests/unit/test_bug808734.js
dom/settings/SettingsChangeNotifier.jsm
dom/settings/SettingsManager.js
dom/settings/SettingsRequestManager.jsm
dom/settings/SettingsService.js
dom/settings/moz.build
dom/settings/tests/mochitest.ini
dom/settings/tests/test_settings_basics.html
dom/settings/tests/test_settings_blobs.html
dom/settings/tests/test_settings_data_uris.html
dom/settings/tests/test_settings_events.html
dom/settings/tests/test_settings_navigator_object.html
dom/settings/tests/test_settings_onsettingchange.html
dom/settings/tests/test_settings_permissions.html
dom/settings/tests/test_settings_service.js
dom/system/gonk/tests/marionette/head.js
dom/tests/mochitest/general/test_interfaces.html
dom/tests/mochitest/geolocation/test_mozsettings.html
dom/tests/mochitest/geolocation/test_mozsettingsWatch.html
dom/tethering/tests/marionette/head.js
dom/tethering/tests/marionette/manifest.ini
dom/webidl/MozSettingsTransactionEvent.webidl
dom/webidl/SettingsManager.webidl
dom/webidl/moz.build
dom/wifi/test/marionette/head.js
testing/mozbase/mozrunner/mozrunner/devices/emulator.py
--- a/b2g/chrome/content/shell.js
+++ b/b2g/chrome/content/shell.js
@@ -1,16 +1,16 @@
 /* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- /
 /* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 Cu.import('resource://gre/modules/ContactService.jsm');
-Cu.import('resource://gre/modules/SettingsRequestManager.jsm');
+Cu.import('resource://gre/modules/SettingsChangeNotifier.jsm');
 Cu.import('resource://gre/modules/DataStoreChangeNotifier.jsm');
 Cu.import('resource://gre/modules/AlarmService.jsm');
 Cu.import('resource://gre/modules/ActivitiesService.jsm');
 Cu.import('resource://gre/modules/NotificationDB.jsm');
 Cu.import('resource://gre/modules/Payment.jsm');
 Cu.import("resource://gre/modules/AppsUtils.jsm");
 Cu.import('resource://gre/modules/UserAgentOverrides.jsm');
 Cu.import('resource://gre/modules/Keyboard.jsm');
--- a/dom/apps/src/PermissionsInstaller.jsm
+++ b/dom/apps/src/PermissionsInstaller.jsm
@@ -25,16 +25,30 @@ const READCREATE = "readcreate";
 const READWRITE = "readwrite";
 
 const PERM_TO_STRING = ["unknown", "allow", "deny", "prompt"];
 
 function debug(aMsg) {
   //dump("-*-*- PermissionsInstaller.jsm : " + aMsg + "\n");
 }
 
+// An array carring all the possible (expanded) permission names.
+let AllPossiblePermissions = [];
+for (let permName in PermissionsTable) {
+  let expandedPermNames = [];
+  if (PermissionsTable[permName].access) {
+    expandedPermNames = expandPermissions(permName, READWRITE);
+  } else {
+    expandedPermNames = expandPermissions(permName);
+  }
+  AllPossiblePermissions = AllPossiblePermissions.concat(expandedPermNames);
+  AllPossiblePermissions =
+    AllPossiblePermissions.concat(["offline-app", "pin-app"]);
+}
+
 this.PermissionsInstaller = {
   /**
    * Install permissisions or remove deprecated permissions upon re-install.
    * @param object aApp
    *        The just-installed app configuration.
    *        The properties used are manifestURL, origin and manifest.
    * @param boolean aIsReinstall
    *        Indicates the app was just re-installed
--- a/dom/apps/src/PermissionsTable.jsm
+++ b/dom/apps/src/PermissionsTable.jsm
@@ -7,18 +7,17 @@
 const Ci = Components.interfaces;
 const Cu = Components.utils;
 
 this.EXPORTED_SYMBOLS = [
   "PermissionsTable",
   "PermissionsReverseTable",
   "expandPermissions",
   "appendAccessToPermName",
-  "isExplicitInPermissionsTable",
-  "AllPossiblePermissions"
+  "isExplicitInPermissionsTable"
 ];
 
 // Permission access flags
 const READONLY = "readonly";
 const CREATEONLY = "createonly";
 const READCREATE = "readcreate";
 const READWRITE = "readwrite";
 
@@ -145,26 +144,17 @@ this.PermissionsTable =  { geolocation: 
                             privileged: ALLOW_ACTION,
                             certified: ALLOW_ACTION
                            },
                            settings: {
                              app: DENY_ACTION,
                              privileged: DENY_ACTION,
                              certified: ALLOW_ACTION,
                              access: ["read", "write"],
-                             additional: ["indexedDB-chrome-settings", "settings-api"]
-                           },
-                           // This exists purely for tests, no app
-                           // should ever use it. It can only be
-                           // handed out by SpecialPowers.
-                           "settings-clear": {
-                             app: DENY_ACTION,
-                             privileged: DENY_ACTION,
-                             certified: DENY_ACTION,
-                             additional: ["indexedDB-chrome-settings", "settings-api"]
+                             additional: ["indexedDB-chrome-settings"]
                            },
                            permissions: {
                              app: DENY_ACTION,
                              privileged: DENY_ACTION,
                              certified: ALLOW_ACTION
                            },
                            phonenumberservice: {
                              app: DENY_ACTION,
@@ -398,23 +388,16 @@ this.PermissionsTable =  { geolocation: 
                              privileged: DENY_ACTION,
                              certified: ALLOW_ACTION
                            },
                            "moz-firefox-accounts": {
                              app: DENY_ACTION,
                              privileged: PROMPT_ACTION,
                              certified: ALLOW_ACTION,
                              substitute: ["firefox-accounts"]
-                           },
-                           "settings:wallpaper.image": {
-                             app: DENY_ACTION,
-                             privileged: PROMPT_ACTION,
-                             certified: ALLOW_ACTION,
-                             access: ["read", "write"],
-                             additional: ["settings-api"]
                            }
                          };
 
 /**
  * Append access modes to the permission name as suffixes.
  *   e.g. permission name 'contacts' with ['read', 'write'] =
  *   ['contacts-read', contacts-write']
  * @param string aPermName
@@ -513,44 +496,40 @@ this.expandPermissions = function expand
     if (tableEntry.additional) {
       expandedPermNames = expandedPermNames.concat(tableEntry.additional);
     }
   }
 
   return expandedPermNames;
 };
 
-this.PermissionsReverseTable = {};
-this.AllPossiblePermissions = [];
-
-(function () {
+this.PermissionsReverseTable = (function () {
   // PermissionsTable as it is works well for direct searches, but not
   // so well for reverse ones (that is, if I get something like
   // device-storage:music-read or indexedDB-chrome-settings-read how
   // do I know which permission it really is? Hence this table is
   // born. The idea is that
   // reverseTable[device-storage:music-read] should return
   // device-storage:music
-  //
-  // We also need a list of all the possible permissions for things like the
-  // settingsmanager, so construct that while we're at it.
+  let reverseTable = {};
+
   for (let permName in PermissionsTable) {
     let permAliases;
     if (PermissionsTable[permName].access) {
       permAliases = expandPermissions(permName, "readwrite");
     } else {
       permAliases = expandPermissions(permName);
     }
     for (let i = 0; i < permAliases.length; i++) {
-      PermissionsReverseTable[permAliases[i]] = permName;
-      AllPossiblePermissions.push(permAliases[i]);
+      reverseTable[permAliases[i]] = permName;
     }
   }
-  AllPossiblePermissions =
-    AllPossiblePermissions.concat(["offline-app", "pin-app"]);
+
+  return reverseTable;
+
 })();
 
 this.isExplicitInPermissionsTable = function(aPermName, aIntStatus) {
 
   // Check to see if the 'webapp' is app/privileged/certified.
   let appStatus;
   switch (aIntStatus) {
     case Ci.nsIPrincipal.APP_STATUS_CERTIFIED:
--- a/dom/base/Navigator.cpp
+++ b/dom/base/Navigator.cpp
@@ -2104,18 +2104,18 @@ Navigator::DoNewResolve(JSContext* aCx, 
       // we don't want to define an interface on the Xray if it's disabled in
       // the target global, even if it's enabled in the Xray's global.
       if (name_struct->mConstructorEnabled &&
           !(*name_struct->mConstructorEnabled)(aCx, naviObj)) {
         return true;
       }
 
       if (name.EqualsLiteral("mozSettings")) {
-        bool hasPermission = CheckPermission("settings-api-read") ||
-          CheckPermission("settings-api-write");
+        bool hasPermission = CheckPermission("settings-read") ||
+                             CheckPermission("settings-write");
         if (!hasPermission) {
           FillPropertyDescriptor(aDesc, aObject, JS::NullValue(), false);
           return true;
         }
       }
 
       if (name.EqualsLiteral("mozDownloadManager")) {
         if (!CheckPermission("downloads")) {
--- a/dom/bluetooth/tests/marionette/head.js
+++ b/dom/bluetooth/tests/marionette/head.js
@@ -721,17 +721,17 @@ function startBluetoothTestBase(aPermiss
     .then(aTestCaseMain)
     .then(cleanUp, function() {
       ok(false, "Unhandled rejected promise.");
       cleanUp();
     });
 }
 
 function startBluetoothTest(aReenable, aTestCaseMain) {
-  startBluetoothTestBase(["settings-read", "settings-write", "settings-api-read", "settings-api-write"], function() {
+  startBluetoothTestBase(["settings-read", "settings-write"], function() {
     let origEnabled, needEnable;
 
     return getBluetoothEnabled()
       .then(function(aEnabled) {
         origEnabled = aEnabled;
         needEnable = !aEnabled;
         log("Original 'bluetooth.enabled' is " + origEnabled);
 
--- a/dom/bluetooth/tests/marionette/manifest.ini
+++ b/dom/bluetooth/tests/marionette/manifest.ini
@@ -1,16 +1,12 @@
 [DEFAULT]
 b2g = true
 browser = false
 qemu = true
 
 [test_navigate_to_default_url.py]
-disabled = https://bugzilla.mozilla.org/show_bug.cgi?id=1058158
-
 [test_dom_BluetoothManager_enabled.js]
 [test_dom_BluetoothManager_adapteradded.js]
 [test_dom_BluetoothAdapter_setters.js]
 [test_dom_BluetoothAdapter_getters.js]
 [test_dom_BluetoothAdapter_discovery.js]
-
 [test_dom_BluetoothAdapter_pair.js]
-disabled = https://bugzilla.mozilla.org/show_bug.cgi?id=1058158
\ No newline at end of file
--- a/dom/bluetooth/tests/marionette/test_dom_BluetoothManager_enabled.js
+++ b/dom/bluetooth/tests/marionette/test_dom_BluetoothManager_enabled.js
@@ -53,17 +53,17 @@ function test(aEnabled) {
       } else {
         deferred.reject();
       }
     });
 
   return deferred.promise;
 }
 
-startBluetoothTestBase(["settings-read", "settings-write", "settings-api-read", "settings-api-write"],
+startBluetoothTestBase(["settings-read", "settings-write"],
                        function testCaseMain() {
   return getBluetoothEnabled()
     .then(function(aEnabled) {
       log("Original 'bluetooth.enabled' is " + aEnabled);
       // Set to !aEnabled and reset back to aEnabled.
       return test(!aEnabled).then(test.bind(null, aEnabled));
     });
 });
--- a/dom/bluetooth2/tests/marionette/test_dom_BluetoothManager_API2.js
+++ b/dom/bluetooth2/tests/marionette/test_dom_BluetoothManager_API2.js
@@ -34,15 +34,15 @@ function waitForManagerAttributeChanged(
       ok(true, "BluetoothManager event 'onattributechanged' got.");
       deferred.resolve(aEvent);
     }
   };
 
   return deferred.promise;
 }
 
-startBluetoothTestBase(["settings-read", "settings-write", "settings-api-read", "settings-api-write"],
+startBluetoothTestBase(["settings-read", "settings-write"],
                        function testCaseMain() {
   let adapters = bluetoothManager.getAdapters();
   ok(Array.isArray(adapters), "Can not got the array of adapters");
   ok(adapters.length, "The number of adapters should not be zero");
   ok(bluetoothManager.defaultAdapter, "defaultAdapter should not be null.");
 });
--- a/dom/events/test/test_all_synthetic_events.html
+++ b/dom/events/test/test_all_synthetic_events.html
@@ -272,20 +272,16 @@ const kEventConstructors = {
   MozOtaStatusEvent:                         { create: function (aName, aProps) {
                                                           return new MozOtaStatusEvent(aName, aProps);
                                                        },
                                              },
   MozSettingsEvent:                          { create: function (aName, aProps) {
                                                          return new MozSettingsEvent(aName, aProps);
                                                        },
                                              },
-  MozSettingsTransactionEvent:               { create: function (aName, aProps) {
-                                                         return new MozSettingsTransactionEvent(aName, aProps);
-                                                       },
-                                             },
   MozSmsEvent:                               { create: function (aName, aProps) {
                                                          return new MozSmsEvent(aName, aProps);
                                                        },
                                              },
   MozStkCommandEvent:                        { create: function (aName, aProps) {
                                                           return new MozStkCommandEvent(aName, aProps);
                                                        },
                                              },
--- a/dom/fmradio/test/marionette/test_bug876597.js
+++ b/dom/fmradio/test/marionette/test_bug876597.js
@@ -1,18 +1,16 @@
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/ */
 
 MARIONETTE_TIMEOUT = 10000;
 
 SpecialPowers.addPermission("fmradio", true, document);
 SpecialPowers.addPermission("settings-read", true, document);
 SpecialPowers.addPermission("settings-write", true, document);
-SpecialPowers.addPermission("settings-api-read", true, document);
-SpecialPowers.addPermission("settings-api-write", true, document);
 
 let FMRadio = window.navigator.mozFMRadio;
 let mozSettings = window.navigator.mozSettings;
 let KEY = "airplaneMode.enabled";
 
 function verifyInitialState() {
   log("Verifying initial state.");
   ok(FMRadio);
--- a/dom/ipc/preload.js
+++ b/dom/ipc/preload.js
@@ -21,16 +21,17 @@ const BrowserElementIsPreloaded = true;
   Cu.import("resource://gre/modules/BrowserElementPromptService.jsm");
   Cu.import("resource://gre/modules/DOMRequestHelper.jsm");
   Cu.import("resource://gre/modules/FileUtils.jsm");
   Cu.import("resource://gre/modules/Geometry.jsm");
   Cu.import("resource://gre/modules/IndexedDBHelper.jsm");
   Cu.import("resource://gre/modules/NetUtil.jsm");
   Cu.import("resource://gre/modules/Services.jsm");
   Cu.import("resource://gre/modules/SettingsDB.jsm");
+  Cu.import("resource://gre/modules/SettingsQueue.jsm");
   Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 
   Cc["@mozilla.org/appshell/appShellService;1"].getService(Ci["nsIAppShellService"]);
   Cc["@mozilla.org/appshell/window-mediator;1"].getService(Ci["nsIWindowMediator"]);
   Cc["@mozilla.org/AppsService;1"].getService(Ci["nsIAppsService"]);
   Cc["@mozilla.org/base/telemetry;1"].getService(Ci["nsITelemetry"]);
   Cc["@mozilla.org/categorymanager;1"].getService(Ci["nsICategoryManager"]);
   Cc["@mozilla.org/childprocessmessagemanager;1"].getService(Ci["nsIMessageSender"]);
--- a/dom/mobileconnection/tests/marionette/test_dsds_mobile_data_connection.js
+++ b/dom/mobileconnection/tests/marionette/test_dsds_mobile_data_connection.js
@@ -146,9 +146,9 @@ startDSDSTestCommon(function() {
   numOfRadioInterfaces = getNumOfRadioInterfaces();
 
   return testEnableData()
     .then(testSwitchDefaultDataToSimTwo)
     .then(testDisableDataRoamingWhileRoaming)
     .then(testEnableDataRoamingWhileRoaming)
     .then(testDisableData)
     .then(restoreTestEnvironment);
-}, ["settings-read", "settings-write", "settings-api-read", "settings-api-write"]);
+}, ["settings-read", "settings-write"]);
--- a/dom/mobileconnection/tests/marionette/test_mobile_data_connection.js
+++ b/dom/mobileconnection/tests/marionette/test_mobile_data_connection.js
@@ -103,9 +103,9 @@ startTestCommon(function() {
     .then(() => {
       if (origApnSettings) {
         return setDataApnSettings(origApnSettings);
       }
     })
     .then(() => setEmulatorRoamingAndWait(false))
     .then(() => setDataRoamingEnabled(false));
 
-}, ["settings-read", "settings-write", "settings-api-read", "settings-api-write"]);
\ No newline at end of file
+}, ["settings-read", "settings-write"]);
\ No newline at end of file
--- a/dom/mobileconnection/tests/marionette/test_mobile_data_ipv6.js
+++ b/dom/mobileconnection/tests/marionette/test_mobile_data_ipv6.js
@@ -120,9 +120,9 @@ startTestCommon(function() {
     })
 
     .then(() => setDataRoamingEnabled(false))
     .then(function() {
       if (origApnSettings) {
         return setDataApnSettings(origApnSettings);
       }
     });
-}, ["settings-read", "settings-write", "settings-api-read", "settings-api-write"]);
+}, ["settings-read", "settings-write"]);
--- a/dom/mobileconnection/tests/marionette/test_mobile_set_radio.js
+++ b/dom/mobileconnection/tests/marionette/test_mobile_set_radio.js
@@ -33,9 +33,9 @@ startTestCommon(function() {
       is(mobileConnection.data.connected, false);
     })
 
     // Restore test environment.
     .then(() => setDataApnSettings(origApnSettings))
     .then(() => setDataEnabled(false))
     .then(() => setRadioEnabledAndWait(true));
 
-}, ["settings-read", "settings-write", "settings-api-read", "settings-api-write"]);
+}, ["settings-read", "settings-write"]);
--- a/dom/permission/tests/unit/test_bug808734.js
+++ b/dom/permission/tests/unit/test_bug808734.js
@@ -10,17 +10,16 @@ var gData = [
   expected: ["contacts-read", "contacts-create",
              "contacts-write"]
 },
 // test additional expansion and access not having read+create+write
 {
   permission: "settings",
   access: READWRITE,
   expected: ["settings-read", "settings-write",
-             "settings-api-read", "settings-api-write",
              "indexedDB-chrome-settings-read",
              "indexedDB-chrome-settings-write"]
 },
 // test substitute
 {
   permission: "storage",
   expected: ["indexedDB-unlimited",
              "default-persistent-storage"]
new file mode 100644
--- /dev/null
+++ b/dom/settings/SettingsChangeNotifier.jsm
@@ -0,0 +1,126 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+"use strict"
+
+const DEBUG = false;
+function debug(s) {
+  if (DEBUG) dump("-*- SettingsChangeNotifier: " + s + "\n");
+}
+
+const Cu = Components.utils;
+const Cc = Components.classes;
+const Ci = Components.interfaces;
+
+this.EXPORTED_SYMBOLS = ["SettingsChangeNotifier"];
+
+Cu.import("resource://gre/modules/XPCOMUtils.jsm");
+Cu.import("resource://gre/modules/Services.jsm");
+
+const kXpcomShutdownObserverTopic      = "xpcom-shutdown";
+const kMozSettingsChangedObserverTopic = "mozsettings-changed";
+const kFromSettingsChangeNotifier      = "fromSettingsChangeNotifier";
+
+XPCOMUtils.defineLazyServiceGetter(this, "ppmm",
+                                   "@mozilla.org/parentprocessmessagemanager;1",
+                                   "nsIMessageBroadcaster");
+
+this.SettingsChangeNotifier = {
+  init: function() {
+    if (DEBUG) debug("init");
+    this.children = [];
+    this._messages = ["Settings:Changed", "Settings:RegisterForMessages", "child-process-shutdown"];
+    this._messages.forEach((function(msgName) {
+      ppmm.addMessageListener(msgName, this);
+    }).bind(this));
+
+    Services.obs.addObserver(this, kXpcomShutdownObserverTopic, false);
+    Services.obs.addObserver(this, kMozSettingsChangedObserverTopic, false);
+
+    // Broadcast when SettingChangeNotifier finishes init process.
+    ppmm.broadcastAsyncMessage("Settings:Notifier:Init:OK");
+  },
+
+  observe: function(aSubject, aTopic, aData) {
+    if (DEBUG) debug("observe");
+    switch (aTopic) {
+      case kXpcomShutdownObserverTopic:
+        this._messages.forEach((function(msgName) {
+          ppmm.removeMessageListener(msgName, this);
+        }).bind(this));
+        Services.obs.removeObserver(this, kXpcomShutdownObserverTopic);
+        Services.obs.removeObserver(this, kMozSettingsChangedObserverTopic);
+        ppmm = null;
+        break;
+      case kMozSettingsChangedObserverTopic:
+      {
+        let setting = JSON.parse(aData);
+        // To avoid redundantly broadcasting settings-changed events that are
+        // just requested from content processes themselves, skip the observer
+        // messages that are notified from the internal SettingsChangeNotifier.
+        if (setting.message && setting.message === kFromSettingsChangeNotifier)
+          return;
+        this.broadcastMessage("Settings:Change:Return:OK",
+          { key: setting.key, value: setting.value });
+        break;
+      }
+      default:
+        if (DEBUG) debug("Wrong observer topic: " + aTopic);
+        break;
+    }
+  },
+
+  broadcastMessage: function broadcastMessage(aMsgName, aContent) {
+    if (DEBUG) debug("Broadast");
+    this.children.forEach(function(msgMgr) {
+      msgMgr.sendAsyncMessage(aMsgName, aContent);
+    });
+  },
+
+  receiveMessage: function(aMessage) {
+    if (DEBUG) debug("receiveMessage");
+    let msg = aMessage.data;
+    let mm = aMessage.target;
+    switch (aMessage.name) {
+      case "Settings:Changed":
+        if (!aMessage.target.assertPermission("settings-write")) {
+          Cu.reportError("Settings message " + msg.name +
+                         " from a content process with no 'settings-write' privileges.");
+          return null;
+        }
+        this.broadcastMessage("Settings:Change:Return:OK",
+          { key: msg.key, value: msg.value });
+        Services.obs.notifyObservers(this, kMozSettingsChangedObserverTopic,
+          JSON.stringify({
+            key: msg.key,
+            value: msg.value,
+            message: kFromSettingsChangeNotifier
+          }));
+        break;
+      case "Settings:RegisterForMessages":
+        if (!aMessage.target.assertPermission("settings-read")) {
+          Cu.reportError("Settings message " + msg.name +
+                         " from a content process with no 'settings-read' privileges.");
+          return null;
+        }
+        if (DEBUG) debug("Register!");
+        if (this.children.indexOf(mm) == -1) {
+          this.children.push(mm);
+        }
+        break;
+      case "child-process-shutdown":
+        if (DEBUG) debug("Unregister");
+        let index;
+        if ((index = this.children.indexOf(mm)) != -1) {
+          if (DEBUG) debug("Unregister index: " + index);
+          this.children.splice(index, 1);
+        }
+        break;
+      default:
+        if (DEBUG) debug("Wrong message: " + aMessage.name);
+    }
+  }
+}
+
+SettingsChangeNotifier.init();
--- a/dom/settings/SettingsManager.js
+++ b/dom/settings/SettingsManager.js
@@ -1,252 +1,303 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
 const DEBUG = false;
-function debug(s) { dump("-*- SettingsManager: " + s + "\n"); }
+function debug(s) {
+  if (DEBUG) dump("-*- SettingsManager: " + s + "\n");
+}
 
 const Cc = Components.classes;
 const Ci = Components.interfaces;
 const Cu = Components.utils;
 
+Cu.import("resource://gre/modules/SettingsQueue.jsm");
+Cu.import("resource://gre/modules/SettingsDB.jsm");
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 Cu.import("resource://gre/modules/Services.jsm");
-Cu.import("resource://gre/modules/DOMRequestHelper.jsm");
 
-XPCOMUtils.defineLazyServiceGetter(Services, "DOMRequest",
-                                   "@mozilla.org/dom/dom-request-service;1",
-                                   "nsIDOMRequestService");
 XPCOMUtils.defineLazyServiceGetter(this, "cpmm",
                                    "@mozilla.org/childprocessmessagemanager;1",
                                    "nsIMessageSender");
 XPCOMUtils.defineLazyServiceGetter(this, "mrm",
                                    "@mozilla.org/memory-reporter-manager;1",
                                    "nsIMemoryReporterManager");
-XPCOMUtils.defineLazyServiceGetter(this, "uuidgen",
-                                   "@mozilla.org/uuid-generator;1",
-                                   "nsIUUIDGenerator");
-
-/**
- * In order to make SettingsManager work with Privileged Apps, we need the lock
- * to be OOP. However, the lock state needs to be managed on the child process,
- * while the IDB functions now happen on the parent process so we don't have to
- * expose IDB permissions at the child process level. We use the
- * DOMRequestHelper mechanism to deal with DOMRequests/promises across the
- * processes.
- *
- * However, due to the nature of the IDBTransaction lifetime, we need to relay
- * to the parent when to finalize the transaction once the child is done with the
- * lock. We keep a list of all open requests for a lock, and once the lock
- * reaches the end of its receiveMessage function with no more queued requests,
- * we consider it dead. At that point, we send a message to the parent to notify
- * it to finalize the transaction.
- */
 
 function SettingsLock(aSettingsManager) {
-  if (DEBUG) debug("settings lock init");
   this._open = true;
+  this._isBusy = false;
+  this._requests = new Queue();
   this._settingsManager = aSettingsManager;
-  this._id = uuidgen.generateUUID().toString();
+  this._transaction = null;
 
   let closeHelper = function() {
-    if (DEBUG) debug("closing lock " + this._id);
+    if (DEBUG) debug("closing lock");
     this._open = false;
-    this.runOrFinalizeQueries();
   }.bind(this);
 
-  // DOMRequestIpcHelper.initHelper sets this._window
-  this.initDOMRequestHelper(this._settingsManager._window, ["Settings:Get:OK", "Settings:Get:KO",
-                                                            "Settings:Clear:OK", "Settings:Clear:KO",
-                                                            "Settings:Set:OK", "Settings:Set:KO",
-                                                            "Settings:Finalize:OK", "Settings:Finalize:KO"]);
-  this.sendMessage("Settings:CreateLock", {lockID: this._id, isInternalLock: false});
   Services.tm.currentThread.dispatch(closeHelper, Ci.nsIThread.DISPATCH_NORMAL);
 }
 
 SettingsLock.prototype = {
-  __proto__: DOMRequestIpcHelper.prototype,
-  set onsettingstransactionsuccess(aHandler) {
-    this.__DOM_IMPL__.setEventHandler("onsettingstransactionsuccess", aHandler);
-  },
-
-  get onsettingstransactionsuccess() {
-    return this.__DOM_IMPL__.getEventHandler("onsettingstransactionsuccess");
-  },
-
-  set onsettingstransactionfailure(aHandler) {
-    this.__DOM_IMPL__.setEventHandler("onsettingstransactionfailure", aHandler);
-  },
-
-  get onsettingstransactionfailure() {
-    return this.__DOM_IMPL__.getEventHandler("onsettingstransactionfailure");
-  },
-
   get closed() {
     return !this._open;
   },
 
   _wrap: function _wrap(obj) {
     return Cu.cloneInto(obj, this._settingsManager._window);
   },
 
-  sendMessage: function(aMessageName, aData) {
-    cpmm.sendAsyncMessage(aMessageName,
-                          aData,
-                          undefined,
-                          this._settingsManager._window.document.nodePrincipal);
-  },
+  process: function process() {
+    let lock = this;
+    let store = lock._transaction.objectStore(SETTINGSSTORE_NAME);
+
+    while (!lock._requests.isEmpty()) {
+      let info = lock._requests.dequeue();
+      if (DEBUG) debug("info: " + info.intent);
+      let request = info.request;
+      switch (info.intent) {
+        case "clear":
+          let clearReq = store.clear();
+          clearReq.onsuccess = function() {
+            this._open = true;
+            Services.DOMRequest.fireSuccess(request, 0);
+            this._open = false;
+          }.bind(lock);
+          clearReq.onerror = function() {
+            Services.DOMRequest.fireError(request, 0)
+          };
+          break;
+        case "set":
+          let keys = Object.getOwnPropertyNames(info.settings);
+          if (keys.length) {
+            lock._isBusy = true;
+          }
+          for (let i = 0; i < keys.length; i++) {
+            let key = keys[i];
+            let last = i === keys.length - 1;
+            if (DEBUG) debug("key: " + key + ", val: " + JSON.stringify(info.settings[key]) + ", type: " + typeof(info.settings[key]));
+            let checkKeyRequest = store.get(key);
+
+            checkKeyRequest.onsuccess = function (event) {
+              let defaultValue;
+              let userValue = info.settings[key];
+              if (event.target.result) {
+                defaultValue = event.target.result.defaultValue;
+              } else {
+                defaultValue = null;
+                if (DEBUG) debug("MOZSETTINGS-SET-WARNING: " + key + " is not in the database.\n");
+              }
+
+              let obj = {settingName: key, defaultValue: defaultValue, userValue: userValue};
+              if (DEBUG) debug("store1: " + JSON.stringify(obj));
+              let setReq = store.put(obj);
+
+              setReq.onsuccess = function() {
+                cpmm.sendAsyncMessage("Settings:Changed", { key: key, value: userValue });
+                if (last && !request.error) {
+                  lock._open = true;
+                  Services.DOMRequest.fireSuccess(request, 0);
+                  lock._open = false;
+                }
+              };
 
-  runOrFinalizeQueries: function() {
-    if (!this._requests || Object.keys(this._requests).length == 0) {
-      this.sendMessage("Settings:Finalize", {lockID: this._id});
-              } else {
-      this.sendMessage("Settings:Run", {lockID: this._id});
+              setReq.onerror = function() {
+                if (!request.error) {
+                  Services.DOMRequest.fireError(request, setReq.error.name)
+                }
+              };
+
+              if (last) {
+                lock._isBusy = false;
+                if (!lock._requests.isEmpty()) {
+                  lock.process();
+                }
+              }
+            };
+            checkKeyRequest.onerror = function(event) {
+              if (!request.error) {
+                Services.DOMRequest.fireError(request, checkKeyRequest.error.name)
+              }
+            };
+          }
+          // Don't break here, instead return. Once the previous requests have
+          // finished this loop will start again.
+          return;
+        case "get":
+          let getReq = (info.name === "*") ? store.mozGetAll()
+                                           : store.mozGetAll(info.name);
+
+          getReq.onsuccess = function(event) {
+            if (DEBUG) debug("Request for '" + info.name + "' successful. " +
+                             "Record count: " + event.target.result.length);
+
+            if (event.target.result.length == 0) {
+              if (DEBUG) debug("MOZSETTINGS-GET-WARNING: " + info.name + " is not in the database.\n");
+            }
+
+            let results = {};
+
+            for (var i in event.target.result) {
+              let result = event.target.result[i];
+              var name = result.settingName;
+              if (DEBUG) debug("VAL: " + result.userValue +", " + result.defaultValue + "\n");
+              results[name] = result.userValue !== undefined ? result.userValue : result.defaultValue;
+            }
+
+            this._open = true;
+            Services.DOMRequest.fireSuccess(request, this._wrap(results));
+            this._open = false;
+          }.bind(lock);
+
+          getReq.onerror = function() {
+            Services.DOMRequest.fireError(request, 0)
+          };
+          break;
+      }
     }
   },
 
-  receiveMessage: function(aMessage) {
-    let msg = aMessage.data;
-    // SettingsRequestManager broadcasts changes to all locks in the child. If
-    // our lock isn't being addressed, just return.
-    if (msg.lockID != this._id) {
-      return;
-    }
-    if (DEBUG) debug("receiveMessage (" + this._id + "): " + aMessage.name);
-    // Finalizing a transaction does not return a request ID since we are
-    // supposed to fire callbacks.
-    if (!msg.requestID) {
-      let event;
-      switch (aMessage.name) {
-        case "Settings:Finalize:OK":
-          if (DEBUG) debug("Lock finalize ok!");
-          event = new this._window.MozSettingsTransactionEvent("settingstransactionsuccess", {});
-          this.__DOM_IMPL__.dispatchEvent(event);
-          break;
-        case "Settings:Finalize:KO":
-          if (DEBUG) debug("Lock finalize failed!");
-          event = new this._window.MozSettingsTransactionEvent("settingstransactionfailure", {
-            error: msg.errorMsg
-          });
-          this.__DOM_IMPL__.dispatchEvent(event);
-          break;
-        default:
-          if (DEBUG) debug("Message type " + aMessage.name + " is missing a requestID");
-      }
-      return;
-    }
+  createTransactionAndProcess: function() {
+    if (DEBUG) debug("database opened, creating transaction");
 
+    let manager = this._settingsManager;
+    let transactionType = manager.hasWritePrivileges ? "readwrite" : "readonly";
 
-    let req = this.getRequest(msg.requestID);
-    if (!req) {
-      if (DEBUG) debug("Matching request not found.");
-      return;
+    this._transaction =
+      manager._settingsDB._db.transaction(SETTINGSSTORE_NAME, transactionType);
+
+    this.process();
+  },
+
+  maybeProcess: function() {
+    if (this._transaction && !this._isBusy) {
+      this.process();
     }
-    this.removeRequest(msg.requestID);
-    if (DEBUG) debug("receiveMessage: " + aMessage.name);
-    switch (aMessage.name) {
-      case "Settings:Get:OK":
-        for (let i in msg.settings) {
-          msg.settings[i] = this._wrap(msg.settings[i]);
-        }
-        this._open = true;
-        Services.DOMRequest.fireSuccess(req.request, this._wrap(msg.settings));
-        this._open = false;
-        break;
-      case "Settings:Set:OK":
-      case "Settings:Clear:OK":
-        this._open = true;
-        Services.DOMRequest.fireSuccess(req.request, 0);
-        this._open = false;
-        break;
-      case "Settings:Get:KO":
-      case "Settings:Set:KO":
-      case "Settings:Clear:KO":
-        if (DEBUG) debug("error:" + msg.errorMsg);
-        Services.DOMRequest.fireError(req.request, msg.errorMsg);
-        break;
-      default:
-        if (DEBUG) debug("Wrong message: " + aMessage.name);
-    }
-    this.runOrFinalizeQueries();
   },
 
   get: function get(aName) {
-    if (DEBUG) debug("get (" + this._id + "): " + aName);
     if (!this._open) {
       dump("Settings lock not open!\n");
       throw Components.results.NS_ERROR_ABORT;
     }
-    let req = this.createRequest();
-    let reqID = this.getRequestId({request: req});
-    this.sendMessage("Settings:Get", {requestID: reqID,
-                                      lockID: this._id,
-                                      name: aName});
+
+    if (this._settingsManager.hasReadPrivileges) {
+      let req = Services.DOMRequest.createRequest(this._settingsManager._window);
+      this._requests.enqueue({ request: req, intent:"get", name: aName });
+      this.maybeProcess();
       return req;
+    } else {
+      if (DEBUG) debug("get not allowed");
+      throw Components.results.NS_ERROR_NOT_IMPLEMENTED;
+    }
+  },
+
+  _serializePreservingBinaries: function _serializePreservingBinaries(aObject) {
+    function needsUUID(aValue) {
+      if (!aValue || !aValue.constructor) {
+        return false;
+      }
+      return (aValue.constructor.name == "Date") || (aValue instanceof Ci.nsIDOMFile) ||
+             (aValue instanceof Ci.nsIDOMBlob);
+    }
+    // We need to serialize settings objects, otherwise they can change between
+    // the set() call and the enqueued request being processed. We can't simply
+    // parse(stringify(obj)) because that breaks things like Blobs, Files and
+    // Dates, so we use stringify's replacer and parse's reviver parameters to
+    // preserve binaries.
+    let manager = this._settingsManager;
+    let binaries = Object.create(null);
+    let stringified = JSON.stringify(aObject, function(key, value) {
+      value = manager._settingsDB.prepareValue(value);
+      if (needsUUID(value)) {
+        let uuid = Cc["@mozilla.org/uuid-generator;1"].getService(Ci.nsIUUIDGenerator)
+                                                      .generateUUID().toString();
+        binaries[uuid] = value;
+        return uuid;
+      }
+      return value;
+    });
+    return JSON.parse(stringified, function(key, value) {
+      if (value in binaries) {
+        return binaries[value];
+      }
+      return value;
+    });
   },
 
   set: function set(aSettings) {
-    if (DEBUG) debug("send: " + JSON.stringify(aSettings));
     if (!this._open) {
       throw "Settings lock not open";
     }
-    let req = this.createRequest();
-    let reqID = this.getRequestId({request: req});
-    this.sendMessage("Settings:Set", {requestID: reqID,
-                                      lockID: this._id,
-                                      settings: aSettings});
+
+    if (this._settingsManager.hasWritePrivileges) {
+      let req = Services.DOMRequest.createRequest(this._settingsManager._window);
+      if (DEBUG) debug("send: " + JSON.stringify(aSettings));
+      let settings = this._serializePreservingBinaries(aSettings);
+      this._requests.enqueue({request: req, intent: "set", settings: settings});
+      this.maybeProcess();
       return req;
+    } else {
+      if (DEBUG) debug("set not allowed");
+      throw "No permission to call set";
+    }
   },
 
   clear: function clear() {
-    if (DEBUG) if (DEBUG) debug("clear");
     if (!this._open) {
       throw "Settings lock not open";
     }
-    let req = this.createRequest();
-    let reqID = this.getRequestId({request: req});
-    this.sendMessage("Settings:Clear", {requestID: reqID,
-                                        lockID: this._id});
+
+    if (this._settingsManager.hasWritePrivileges) {
+      let req = Services.DOMRequest.createRequest(this._settingsManager._window);
+      this._requests.enqueue({ request: req, intent: "clear"});
+      this.maybeProcess();
       return req;
+    } else {
+      if (DEBUG) debug("clear not allowed");
+      throw "No permission to call clear";
+    }
   },
 
   classID: Components.ID("{60c9357c-3ae0-4222-8f55-da01428470d5}"),
   contractID: "@mozilla.org/settingsLock;1",
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsISupports,
-                                         Ci.nsIObserver,
-                                         Ci.nsISupportsWeakReference])
+  QueryInterface: XPCOMUtils.generateQI([Ci.nsISupports]),
 };
 
 function SettingsManager() {
+  this._settingsDB = new SettingsDB();
+  this._settingsDB.init();
 }
 
 SettingsManager.prototype = {
   _callbacks: null,
-  _isRegistered: false,
-  _perms: [],
 
   _wrap: function _wrap(obj) {
     return Cu.cloneInto(obj, this._window);
   },
 
   set onsettingchange(aHandler) {
     this.__DOM_IMPL__.setEventHandler("onsettingchange", aHandler);
-    this.checkMessageRegistration();
   },
 
   get onsettingchange() {
     return this.__DOM_IMPL__.getEventHandler("onsettingchange");
   },
 
   createLock: function() {
-    if (DEBUG) debug("creating lock");
-    let lock = new SettingsLock(this);
+    if (DEBUG) debug("get lock!");
+    var lock = new SettingsLock(this);
+    this._settingsDB.ensureDB(
+      function() { lock.createTransactionAndProcess(); },
+      function() { dump("Cannot open Settings DB. Trying to open an old version?\n"); }
+    );
     return lock;
   },
 
   receiveMessage: function(aMessage) {
     if (DEBUG) debug("Settings::receiveMessage: " + aMessage.name);
     let msg = aMessage.json;
 
     switch (aMessage.name) {
@@ -263,100 +314,91 @@ SettingsManager.prototype = {
           if (DEBUG) debug("observe callback called! " + msg.key + " " + this._callbacks[msg.key].length);
           this._callbacks[msg.key].forEach(function(cb) {
             cb(this._wrap({settingName: msg.key, settingValue: msg.value}));
           }.bind(this));
         } else {
           if (DEBUG) debug("no observers stored!");
         }
         break;
+      case "Settings:Notifier:Init:OK":
+        // If SettingManager receives this message means SettingChangeNotifier
+        // might not receive the Settings:RegisterForMessage message. We should
+        // send it again after SettingChangeNotifier is ready.
+        if (this.hasReadPrivileges) {
+          cpmm.sendAsyncMessage("Settings:RegisterForMessages");
+        }
+        break;
       default:
         if (DEBUG) debug("Wrong message: " + aMessage.name);
     }
   },
 
-  // If we have either observer callbacks or an event handler,
-  // register for messages from the main thread. Otherwise, if no one
-  // is listening, unregister to reduce parent load.
-  checkMessageRegistration: function checkRegistration() {
-    let handler = this.__DOM_IMPL__.getEventHandler("onsettingchange");
-    if (!this._isRegistered) {
-      if (DEBUG) debug("Registering for messages");
-      cpmm.sendAsyncMessage("Settings:RegisterForMessages",
-                            undefined,
-                            undefined,
-                            this._window.document.nodePrincipal);
-      this._isRegistered = true;
-    } else {
-      if ((!this._callbacks || Object.keys(this._callbacks).length == 0)  &&
-          !handler) {
-        if (DEBUG) debug("Unregistering for messages");
-        cpmm.sendAsyncMessage("Settings:UnregisterForMessages",
-                              undefined,
-                              undefined,
-                              this._window.document.nodePrincipal);
-        this._isRegistered = false;
-        this._callbacks = null;
-      }
-    }
-  },
-  
   addObserver: function addObserver(aName, aCallback) {
     if (DEBUG) debug("addObserver " + aName);
     if (!this._callbacks) {
       this._callbacks = {};
     }
     if (!this._callbacks[aName]) {
       this._callbacks[aName] = [aCallback];
     } else {
       this._callbacks[aName].push(aCallback);
     }
-    this.checkMessageRegistration();
   },
 
   removeObserver: function removeObserver(aName, aCallback) {
     if (DEBUG) debug("deleteObserver " + aName);
     if (this._callbacks && this._callbacks[aName]) {
-      let index = this._callbacks[aName].indexOf(aCallback);
+      let index = this._callbacks[aName].indexOf(aCallback)
       if (index != -1) {
-        this._callbacks[aName].splice(index, 1);
-        if (this._callbacks[aName].length == 0) {
-          delete this._callbacks[aName];
-        }
+        this._callbacks[aName].splice(index, 1)
       } else {
         if (DEBUG) debug("Callback not found for: " + aName);
       }
     } else {
       if (DEBUG) debug("No observers stored for " + aName);
     }
-    this.checkMessageRegistration();
   },
 
   init: function(aWindow) {
-    if (DEBUG) debug("SettingsManager init");
     mrm.registerStrongReporter(this);
     cpmm.addMessageListener("Settings:Change:Return:OK", this);
+    cpmm.addMessageListener("Settings:Notifier:Init:OK", this);
     this._window = aWindow;
     Services.obs.addObserver(this, "inner-window-destroyed", false);
     let util = aWindow.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindowUtils);
     this.innerWindowID = util.currentInnerWindowID;
+
+    let readPerm = Services.perms.testExactPermissionFromPrincipal(aWindow.document.nodePrincipal, "settings-read");
+    let writePerm = Services.perms.testExactPermissionFromPrincipal(aWindow.document.nodePrincipal, "settings-write");
+    this.hasReadPrivileges = readPerm == Ci.nsIPermissionManager.ALLOW_ACTION;
+    this.hasWritePrivileges = writePerm == Ci.nsIPermissionManager.ALLOW_ACTION;
+
+    if (this.hasReadPrivileges) {
+      cpmm.sendAsyncMessage("Settings:RegisterForMessages");
+    }
+
+    if (!this.hasReadPrivileges && !this.hasWritePrivileges) {
+      dump("No settings permission for: " + aWindow.document.nodePrincipal.origin + "\n");
+      Cu.reportError("No settings permission for: " + aWindow.document.nodePrincipal.origin);
+    }
   },
 
   observe: function(aSubject, aTopic, aData) {
     if (DEBUG) debug("Topic: " + aTopic);
     if (aTopic == "inner-window-destroyed") {
       let wId = aSubject.QueryInterface(Ci.nsISupportsPRUint64).data;
       if (wId == this.innerWindowID) {
         this.cleanup();
       }
     }
   },
 
   collectReports: function(aCallback, aData, aAnonymize) {
-    for (let topic in this._callbacks) {
+    for (var topic in this._callbacks) {
       let length = this._callbacks[topic].length;
       if (length == 0) {
         continue;
       }
 
       let path;
       if (length < 20) {
         path = "settings-observers";
@@ -372,23 +414,25 @@ SettingsManager.prototype = {
                          "The number of settings observers for this topic.",
                          aData);
     }
   },
 
   cleanup: function() {
     Services.obs.removeObserver(this, "inner-window-destroyed");
     cpmm.removeMessageListener("Settings:Change:Return:OK", this);
+    cpmm.removeMessageListener("Settings:Notifier:Init:OK", this);
     mrm.unregisterStrongReporter(this);
     this._requests = null;
     this._window = null;
     this._innerWindowID = null;
+    this._settingsDB.close();
   },
 
   classID: Components.ID("{c40b1c70-00fb-11e2-a21f-0800200c9a66}"),
   contractID: "@mozilla.org/settingsManager;1",
   QueryInterface: XPCOMUtils.generateQI([Ci.nsISupports,
                                          Ci.nsIDOMGlobalPropertyInitializer,
                                          Ci.nsIObserver,
                                          Ci.nsIMemoryReporter]),
 };
 
-this.NSGetFactory = XPCOMUtils.generateNSGetFactory([SettingsManager, SettingsLock]);
+this.NSGetFactory = XPCOMUtils.generateNSGetFactory([SettingsManager, SettingsLock])
deleted file mode 100644
--- a/dom/settings/SettingsRequestManager.jsm
+++ /dev/null
@@ -1,920 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this file,
- * You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-"use strict";
-
-const DEBUG = false;
-function debug(s) { dump("-*- SettingsRequestManager: " + s + "\n"); }
-const Cc = Components.classes;
-const Ci = Components.interfaces;
-const Cu = Components.utils;
-
-this.EXPORTED_SYMBOLS = ["SettingsRequestManager"];
-
-Cu.import("resource://gre/modules/SettingsDB.jsm");
-Cu.import("resource://gre/modules/XPCOMUtils.jsm");
-Cu.import("resource://gre/modules/Services.jsm");
-Cu.import("resource://gre/modules/PermissionsTable.jsm");
-
-const kXpcomShutdownObserverTopic      = "xpcom-shutdown";
-const kMozSettingsChangedObserverTopic = "mozsettings-changed";
-const kSettingsReadSuffix              = "-read";
-const kSettingsWriteSuffix             = "-write";
-const kSettingsClearPermission         = "settings-clear";
-const kAllSettingsReadPermission       = "settings" + kSettingsReadSuffix;
-const kAllSettingsWritePermission      = "settings" + kSettingsWriteSuffix;
-// Any application with settings permissions, be it for all settings
-// or a single one, will need to be able to access the settings API.
-// The settings-api permission allows an app to see the mozSettings
-// API in order to create locks and queue tasks. Whether these tasks
-// will be allowed depends on the exact permissions the app has.
-const kSomeSettingsReadPermission      = "settings-api" + kSettingsReadSuffix;
-const kSomeSettingsWritePermission     = "settings-api" + kSettingsWriteSuffix;
-
-XPCOMUtils.defineLazyServiceGetter(this, "ppmm",
-                                   "@mozilla.org/parentprocessmessagemanager;1",
-                                   "nsIMessageBroadcaster");
-XPCOMUtils.defineLazyServiceGetter(this, "uuidgen",
-                                   "@mozilla.org/uuid-generator;1",
-                                   "nsIUUIDGenerator");
-
-let SettingsPermissions = {
-  _mmPermissions: {},
-  addManager: function(aMessage) {
-    if (DEBUG) debug("Adding message manager permissions");
-    let mm = aMessage.target;
-    // In order for mochitests to work, we have to update permissions on every
-    // lock creation or observer addition. This still means we can cache
-    // permissions.
-    if (this._mmPermissions[mm]) {
-      if (DEBUG) debug("Manager already added, updating permissions");
-    }
-    let perms = [];
-    let principal;
-    let isSystemPrincipal = false;
-    if (aMessage.principal.origin == "[System Principal]") {
-      isSystemPrincipal = true;
-    } else {
-      let uri = Services.io.newURI(aMessage.principal.origin, null, null);
-      principal = Services.scriptSecurityManager.getAppCodebasePrincipal(uri,
-                                                                         aMessage.principal.appId,
-                                                                         aMessage.principal.isInBrowserElement);
-    }
-    for (let i in AllPossiblePermissions) {
-      let permName = AllPossiblePermissions[i];
-      // We only care about permissions starting with the word "settings"
-      if (permName.indexOf("settings") != 0) {
-        continue;
-      }
-      if (isSystemPrincipal || Services.perms.testExactPermissionFromPrincipal(principal, permName) == Ci.nsIPermissionManager.ALLOW_ACTION) {
-        perms.push(permName);
-      }
-    }
-    this._mmPermissions[mm] = perms;
-  },
-  removeManager: function(aMsgMgr) {
-    if (DEBUG) debug("Removing message manager permissions for " + aMsgMgr);
-    if (!this._mmPermissions[aMsgMgr]) {
-      if (DEBUG) debug("Manager not added!");
-      return;
-    }
-    delete this._mmPermissions[aMsgMgr];
-  },
-  checkPermission: function(aMsgMgr, aPerm) {
-    if (!this._mmPermissions[aMsgMgr]) {
-      if (DEBUG) debug("Manager not added!");
-      return false;
-    }
-    return (this._mmPermissions[aMsgMgr].indexOf(aPerm) != -1);
-  },
-  hasAllReadPermission: function(aMsgMgr) {
-    return this.checkPermission(aMsgMgr, kAllSettingsReadPermission);
-  },
-  hasAllWritePermission: function(aMsgMgr) {
-    return this.checkPermission(aMsgMgr, kAllSettingsWritePermission);
-  },
-  hasSomeReadPermission: function(aMsgMgr) {
-    return this.checkPermission(aMsgMgr, kSomeSettingsReadPermission);
-  },
-  hasSomeWritePermission: function(aMsgMgr) {
-    return this.checkPermission(aMsgMgr, kSomeSettingsWritePermission);
-  },
-  hasClearPermission: function(aMsgMgr) {
-    return this.checkPermission(aMsgMgr, kSettingsClearPermission);
-  },
-  assertSomeReadPermission: function(aMsgMgr) {
-    aMsgMgr.assertPermission(kSomeSettingsReadPermission);
-  },
-  hasReadPermission: function(aMsgMgr, aSettingsName) {
-    return this.hasAllReadPermission(aMsgMgr) || this.checkPermission(aMsgMgr, "settings:" + aSettingsName + kSettingsReadSuffix);
-  },
-  hasWritePermission: function(aMsgMgr, aSettingsName) {
-    return this.hasAllWritePermission(aMsgMgr) || this.checkPermission(aMsgMgr, "settings:" + aSettingsName + kSettingsWriteSuffix);
-  }
-};
-
-
-function SettingsLockInfo(aDB, aMsgMgr, aLockID, aIsServiceLock) {
-  return {
-    // ID Shared with the object on the child side
-    lockID: aLockID,
-    // Is this a content lock or a settings service lock?
-    isServiceLock: aIsServiceLock,
-    // Tasks to be run once the lock is at the head of the queue
-    tasks: [],
-    // This is set to true once a transaction is ready to run, but is not at the
-    // head of the lock queue.
-    consumable: false,
-    // Holds values that are requested to be set until the lock lifetime ends,
-    // then commits them to the DB.
-    queuedSets: {},
-    // Internal transaction object
-    _transaction: undefined,
-    // Message manager that controls the lock
-    _mm: aMsgMgr,
-    // If true, it means a permissions check failed, so just fail everything now
-    _failed: false,
-    // If we're slated to run finalize, set this to make sure we don't
-    // somehow run other events afterward.
-    finalizing: false,
-    // Lets us know if we can use this lock for a clear command
-    canClear: true,
-    // Lets us know if this lock has been used to clear at any point.
-    hasCleared: false,
-    getObjectStore: function() {
-      if (DEBUG) debug("Getting transaction for " + this.lockID);
-      let store;
-      // Test for transaction validity via trying to get the
-      // datastore. If it doesn't work, assume the transaction is
-      // closed, create a new transaction and try again.
-      if (this._transaction) {
-        try {
-          store = this._transaction.objectStore(SETTINGSSTORE_NAME);
-        } catch (e) {
-          if (e.name == "InvalidStateError") {
-            if (DEBUG) debug("Current transaction for " + this.lockID + " closed, trying to create new one.");
-          } else {
-            throw e;
-          }
-        }
-      }
-      // Create one transaction with a global permission. This may be
-      // slightly slower on apps with full settings permissions, but
-      // it means we don't have to do our own transaction order
-      // bookkeeping.
-      if (!SettingsPermissions.hasSomeWritePermission(this._mm)) {
-        this._transaction = aDB._db.transaction(SETTINGSSTORE_NAME, "readonly");
-      } else {
-        this._transaction = aDB._db.transaction(SETTINGSSTORE_NAME, "readwrite");
-      }
-      this._transaction.oncomplete = function() {
-        if (DEBUG) debug("Transaction for lock " + this.lockID + " closed");
-      }.bind(this);
-      this._transaction.onabort = function () {
-        if (DEBUG) debug("Transaction for lock " + this.lockID + " aborted");
-        this._failed = true;
-      }.bind(this);
-      try {
-        store = this._transaction.objectStore(SETTINGSSTORE_NAME);
-      } catch (e) {
-          if (e.name == "InvalidStateError") {
-            if (DEBUG) debug("Cannot create objectstore on transaction for " + this.lockID);
-            return null;
-          } else {
-            throw e;
-          }
-      }
-      return store;
-    },
-    get objectStore() {
-      return this.getObjectStore();
-    }
-  };
-}
-
-let SettingsRequestManager = {
-  // Access to the settings DB
-  settingsDB: new SettingsDB(),
-  // Remote messages to listen for from child
-  messages: ["child-process-shutdown", "Settings:Get", "Settings:Set",
-             "Settings:Clear", "Settings:Run", "Settings:Finalize",
-             "Settings:CreateLock", "Settings:RegisterForMessages"],
-  // Map of LockID to SettingsLockInfo objects
-  lockInfo: {},
-  // Queue of LockIDs. The LockID on the front of the queue is the only lock
-  // that will have requests processed, all other locks will queue requests
-  // until they hit the front of the queue.
-  settingsLockQueue: [],
-  children: [],
-  init: function() {
-    if (DEBUG) debug("init");
-    this.settingsDB.init();
-    this.messages.forEach((function(msgName) {
-      ppmm.addMessageListener(msgName, this);
-    }).bind(this));
-    Services.obs.addObserver(this, kXpcomShutdownObserverTopic, false);
-  },
-
-  _serializePreservingBinaries: function _serializePreservingBinaries(aObject) {
-    function needsUUID(aValue) {
-      if (!aValue || !aValue.constructor) {
-        return false;
-      }
-      return (aValue.constructor.name == "Date") || (aValue instanceof Ci.nsIDOMFile) ||
-             (aValue instanceof Ci.nsIDOMBlob);
-    }
-    // We need to serialize settings objects, otherwise they can change between
-    // the set() call and the enqueued request being processed. We can't simply
-    // parse(stringify(obj)) because that breaks things like Blobs, Files and
-    // Dates, so we use stringify's replacer and parse's reviver parameters to
-    // preserve binaries.
-    let binaries = Object.create(null);
-    let stringified = JSON.stringify(aObject, function(key, value) {
-      value = this.settingsDB.prepareValue(value);
-      if (needsUUID(value)) {
-        let uuid = uuidgen.generateUUID().toString();
-        binaries[uuid] = value;
-        return uuid;
-      }
-      return value;
-    }.bind(this));
-    return JSON.parse(stringified, function(key, value) {
-      if (value in binaries) {
-        return binaries[value];
-      }
-      return value;
-    });
-  },
-
-  queueTask: function(aOperation, aData) {
-    if (DEBUG) debug("Queueing task: " + aOperation);
-
-    let defer = {};
-
-    if (aOperation == "set") {
-      aData.settings = this._serializePreservingBinaries(aData.settings);
-    }
-
-    this.lockInfo[aData.lockID].tasks.push({
-      operation: aOperation,
-      data: aData,
-      defer: defer
-    });
-
-    let promise = new Promise(function(resolve, reject) {
-      defer.resolve = resolve;
-      defer.reject = reject;
-    });
-
-    return promise;
-  },
-
-  // Due to the fact that we're skipping the database in some places
-  // by keeping a local "set" value cache, resolving some calls
-  // without a call to the database would mean we could potentially
-  // receive promise responses out of expected order if a get is
-  // called before a set. Therefore, we wrap our resolve in a null
-  // get, which means it will resolves afer the rest of the calls
-  // queued to the DB.
-  queueTaskReturn: function(aTask, aReturnValue) {
-    if (DEBUG) debug("Making task queuing transaction request.");
-    let data = aTask.data;
-    let lock = this.lockInfo[data.lockID];
-    let store = lock.objectStore;
-    if (!store) {
-      if (DEBUG) debug("Rejecting task queue on lock " + aTask.data.lockID);
-      return Promise.reject({task: aTask, error: "Cannot get object store"});
-    }
-    // Due to the fact that we're skipping the database, resolving
-    // this without a call to the database would mean we could
-    // potentially receive promise responses out of expected order if
-    // a get is called before a set. Therefore, we wrap our resolve in
-    // a null get, which means it will resolves afer the rest of the
-    // calls queued to the DB.
-    let getReq = store.get(0);
-
-    let defer = {};
-    let promiseWrapper = new Promise(function(resolve, reject) {
-      defer.resolve = resolve;
-      defer.reject = reject;
-    });
-
-    getReq.onsuccess = function(event) {
-      return defer.resolve(aReturnValue);
-    };
-    getReq.onerror = function() {
-      return defer.reject({task: aTask, error: getReq.error.name});
-    };
-    return promiseWrapper;
-  },
-  
-  taskGet: function(aTask) {
-    if (DEBUG) debug("Running Get task on lock " + aTask.data.lockID);
-
-    // Check that we have permissions for getting the value
-    let data = aTask.data;
-    let lock = this.lockInfo[data.lockID];
-
-    if (lock._failed) {
-      if (DEBUG) debug("Lock failed. All subsequent requests will fail.");
-      return Promise.reject({task: aTask, error: "Lock failed, all requests now failing."});
-    }
-
-    if (lock.hasCleared) {
-      if (DEBUG) debug("Lock was used for a clear command. All subsequent requests will fail.");
-      return Promise.reject({task: aTask, error: "Lock was used for a clear command. All subsequent requests will fail."});
-    }
-
-    lock.canClear = false;
-    
-    if (!SettingsPermissions.hasReadPermission(lock._mm, data.name)) {
-      if (DEBUG) debug("get not allowed for " + data.name);
-      lock._failed = true;
-      return Promise.reject({task: aTask, error: "No permission to get " + data.name});
-    }
-
-    // If the value was set during this transaction, use the cached value
-    if (data.name in lock.queuedSets) {
-      if (DEBUG) debug("Returning cached set value " + lock.queuedSets[data.name] + " for " + data.name);
-      let local_results = {};
-      local_results[data.name] = lock.queuedSets[data.name];
-      return this.queueTaskReturn(aTask, {task: aTask, results: local_results});
-    }
-
-    // Create/Get transaction and make request
-    if (DEBUG) debug("Making get transaction request for " + data.name);
-    let store = lock.objectStore;
-    if (!store) {
-      if (DEBUG) debug("Rejecting Get task on lock " + aTask.data.lockID);
-      return Promise.reject({task: aTask, error: "Cannot get object store"});
-    }
-
-    if (DEBUG) debug("Making get request for " + data.name);
-    let getReq = (data.name === "*") ? store.mozGetAll() : store.mozGetAll(data.name);
-
-    let defer = {};
-    let promiseWrapper = new Promise(function(resolve, reject) {
-      defer.resolve = resolve;
-      defer.reject = reject;
-    });
-
-    getReq.onsuccess = function(event) {
-      if (DEBUG) debug("Request for '" + data.name + "' successful. " +
-            "Record count: " + event.target.result.length);
-
-      if (event.target.result.length == 0) {
-        if (DEBUG) debug("MOZSETTINGS-GET-WARNING: " + data.name + " is not in the database.\n");
-      }
-
-      let results = {};
-
-      for (let i in event.target.result) {
-        let result = event.target.result[i];
-        let name = result.settingName;
-        if (DEBUG) debug(name + ": " + result.userValue +", " + result.defaultValue);
-        let value = result.userValue !== undefined ? result.userValue : result.defaultValue;
-        results[name] = value;
-      }
-      return defer.resolve({task: aTask, results: results});
-    };
-    getReq.onerror = function() {
-      return defer.reject({task: aTask, error: getReq.error.name});
-    };
-    return promiseWrapper;
-  },
-
-  taskSet: function(aTask) {
-    let data = aTask.data;
-    let lock = this.lockInfo[data.lockID];
-    let keys = Object.getOwnPropertyNames(data.settings);
-
-    if (lock._failed) {
-      if (DEBUG) debug("Lock failed. All subsequent requests will fail.");
-      return Promise.reject({task: aTask, error: "Lock failed a permissions check, all requests now failing."});
-    }
-
-    if (lock.hasCleared) {
-      if (DEBUG) debug("Lock was used for a clear command. All subsequent requests will fail.");
-      return Promise.reject({task: aTask, error: "Lock was used for a clear command. All other requests will fail."});
-    }
-
-    lock.canClear = false;
-
-    // If we have no keys, resolve
-    if (keys.length === 0) {
-      if (DEBUG) debug("No keys to change entered!");
-      return Promise.resolve({task: aTask});
-    }
-
-    for (let i = 0; i < keys.length; i++) {
-      if (!SettingsPermissions.hasWritePermission(lock._mm, keys[i])) {
-        if (DEBUG) debug("set not allowed on " + keys[i]);
-        lock._failed = true;
-        return Promise.reject({task: aTask, error: "No permission to set " + keys[i]});
-      }
-    }
-
-    for (let i = 0; i < keys.length; i++) {
-      let key = keys[i];
-      if (DEBUG) debug("key: " + key + ", val: " + JSON.stringify(data.settings[key]) + ", type: " + typeof(data.settings[key]));
-      lock.queuedSets[key] = data.settings[key];
-    }
-
-    return this.queueTaskReturn(aTask, {task: aTask});
-  },
-
-  queueConsume: function() {
-    if (this.settingsLockQueue.length > 0 && this.lockInfo[this.settingsLockQueue[0]].consumable) {
-      Services.tm.currentThread.dispatch(SettingsRequestManager.consumeTasks.bind(this), Ci.nsIThread.DISPATCH_NORMAL);
-    }
-  },
-
-  // Removes the current lock from the queue, and starts transactions for the
-  // next lock, assuming there is one.
-  removeCurrentLock: function() {
-    let lock = this.settingsLockQueue.shift();
-    delete this.lockInfo[lock.lockID];
-    this.queueConsume();
-  },
-
-  finalizeSets: function(aTask) {
-    let data = aTask.data;
-    if (DEBUG) debug("Finalizing tasks for lock " + data.lockID);
-    let lock = this.lockInfo[data.lockID];
-    lock.finalizing = true;
-    if (lock._failed) {
-      this.removeCurrentLock();
-      return Promise.reject({task: aTask, error: "Lock failed a permissions check, all requests now failing."});
-    }
-    // If we have cleared, there is no reason to continue finalizing
-    // this lock. Just resolve promise with task and move on.
-    if (lock.hasCleared) {
-      if (DEBUG) debug("Clear was called on lock, skipping finalize");
-      this.removeCurrentLock();
-      return Promise.resolve({task: aTask});
-    }
-    let keys = Object.getOwnPropertyNames(lock.queuedSets);
-    if (keys.length === 0) {
-      if (DEBUG) debug("Nothing to finalize. Exiting.");
-      this.removeCurrentLock();
-      return Promise.resolve({task: aTask});
-    }
-
-    let store = lock.objectStore;
-    if (!store) {
-      if (DEBUG) debug("Rejecting Set task on lock " + aTask.data.lockID);
-      return Promise.reject({task: aTask, error: "Cannot get object store"});
-    }
-
-    // Due to the fact there may have multiple set operations to clear, and
-    // they're all async, callbacks are gathered into promises, and the promises
-    // are processed with Promises.all().
-    let checkPromises = [];
-    let finalValues = {};
-    for (let i = 0; i < keys.length; i++) {
-      let key = keys[i];
-      if (DEBUG) debug("key: " + key + ", val: " + lock.queuedSets[key] + ", type: " + typeof(lock.queuedSets[key]));
-      let checkDefer = {};
-      let checkPromise = new Promise(function(resolve, reject) {
-        checkDefer.resolve = resolve;
-        checkDefer.reject = reject;
-      });
-
-      // Get operation is used to fill in the default value, assuming there is
-      // one. For the moment, if a value doesn't exist in the settings DB, we
-      // allow the user to add it, and just pass back a null default value.
-      let checkKeyRequest = store.get(key);
-      checkKeyRequest.onsuccess = function (event) {
-        let userValue = lock.queuedSets[key];
-        let defaultValue;
-        if (!event.target.result) {
-          defaultValue = null;
-          if (DEBUG) debug("MOZSETTINGS-GET-WARNING: " + key + " is not in the database.\n");
-        } else {
-          defaultValue = event.target.result.defaultValue;
-        }
-        let obj = {settingName: key, defaultValue: defaultValue, userValue: userValue};
-        finalValues[key] = {defaultValue: defaultValue, userValue: userValue};
-        let setReq = store.put(obj);
-        setReq.onsuccess = function() {
-          if (DEBUG) debug("Set successful!");
-          if (DEBUG) debug("key: " + key + ", val: " + finalValues[key] + ", type: " + typeof(finalValues[key]));
-          return checkDefer.resolve({task: aTask});
-        };
-        setReq.onerror = function() {
-          return checkDefer.reject({task: aTask, error: setReq.error.name});
-        };
-      }.bind(this);
-      checkKeyRequest.onerror = function(event) {
-        return checkDefer.reject({task: aTask, error: checkKeyRequest.error.name});
-      };
-      checkPromises.push(checkPromise);
-    }
-
-    let defer = {};
-    let promiseWrapper = new Promise(function(resolve, reject) {
-      defer.resolve = resolve;
-      defer.reject = reject;
-    });
-
-    // Once all transactions are done, or any have failed, remove the lock and
-    // start processing the tasks from the next lock in the queue.
-    Promise.all(checkPromises).then(function() {
-      // If all commits were successful, notify observers
-      for (let i = 0; i < keys.length; i++) {
-        this.sendSettingsChange(keys[i], finalValues[keys[i]].userValue, lock.isServiceLock);
-      }
-      this.removeCurrentLock();
-      defer.resolve({task: aTask});
-    }.bind(this), function(ret) {
-      this.removeCurrentLock();
-      defer.reject({task: aTask, error: "Set transaction failure"});
-    }.bind(this));
-    return promiseWrapper;
-  },
-
-  // Clear is only expected to be called via tests, and if a lock
-  // calls clear, it should be the only thing the lock does. This
-  // allows us to not have to deal with the possibility of query
-  // integrity checking. Clear should never be called in the wild,
-  // even by certified apps, which is why it has its own permission
-  // (settings-clear).
-  taskClear: function(aTask) {
-    if (DEBUG) debug("Clearing");
-    let data = aTask.data;
-    let lock = this.lockInfo[data.lockID];
-
-    if (lock._failed) {
-      if (DEBUG) debug("Lock failed, all requests now failing.");
-      return Promise.reject({task: aTask, error: "Lock failed, all requests now failing."});
-    }
-
-    if (!lock.canClear) {
-      if (DEBUG) debug("Lock tried to clear after queuing other tasks. Failing.");
-      lock._failed = true;
-      return Promise.reject({task: aTask, error: "Cannot call clear after queuing other tasks, all requests now failing."});
-    }
-
-    if (!SettingsPermissions.hasClearPermission(lock._mm)) {
-      if (DEBUG) debug("clear not allowed");
-      lock._failed = true;
-      return Promise.reject({task: aTask, error: "No permission to clear DB"});
-    }
-
-    lock.hasCleared = true;
-
-    let store = lock.objectStore;
-    if (!store) {
-      if (DEBUG) debug("Rejecting Clear task on lock " + aTask.data.lockID);
-      return Promise.reject({task: aTask, error: "Cannot get object store"});
-    }
-    let defer = {};
-    let promiseWrapper = new Promise(function(resolve, reject) {
-      defer.resolve = resolve;
-      defer.reject = reject;
-    });
-
-    let clearReq = store.clear();
-    clearReq.onsuccess = function() {
-      return defer.resolve({task: aTask});
-    };
-    clearReq.onerror = function() {
-      return defer.reject({task: aTask});
-    };
-    return promiseWrapper;
-  },
-
-  ensureConnection : function() {
-    if (DEBUG) debug("Ensuring Connection");
-    let defer = {};
-    let promiseWrapper = new Promise(function(resolve, reject) {
-      defer.resolve = resolve;
-      defer.reject = reject;
-    });
-    this.settingsDB.ensureDB(
-      function() { defer.resolve(); },
-      function(error) {
-        if (DEBUG) debug("Cannot open Settings DB. Trying to open an old version?\n");
-        defer.reject(error);
-      }
-    );
-    return promiseWrapper;
-  },
-
-  runTasks: function(aLockID) {
-    if (DEBUG) debug("Running tasks for " + aLockID);
-    let lock = this.lockInfo[aLockID];
-    if (lock.finalizing) {
-      debug("TASK TRYING TO QUEUE AFTER FINALIZE CALLED. THIS IS BAD. Lock: " + aLockID);
-      return;
-    }
-    let currentTask = lock.tasks.shift();
-    let promises = [];
-    while (currentTask) {
-      if (DEBUG) debug("Running Operation " + currentTask.operation);
-      let p;
-      switch (currentTask.operation) {
-        case "get":
-          p = this.taskGet(currentTask);
-          break;
-        case "set":
-          p = this.taskSet(currentTask);
-          break;
-        case "clear":
-          p = this.taskClear(currentTask);
-          break;
-        case "finalize":
-          p = this.finalizeSets(currentTask);
-          break;
-        default:
-          if (DEBUG) debug("Invalid operation: " + currentTask.operation);
-          p.reject("Invalid operation: " + currentTask.operation);
-      }
-      p.then(function(ret) {
-        ret.task.defer.resolve(ret.results);
-      }.bind(currentTask), function(ret) {
-        ret.task.defer.reject(ret.error);
-      });
-      promises.push(p);
-      currentTask = lock.tasks.shift();
-    }
-  },
-
-  consumeTasks: function() {
-    if (this.settingsLockQueue.length == 0) {
-      if (DEBUG) debug("Nothing to run!");
-      return;
-    }
-
-    let lockID = this.settingsLockQueue[0];
-    if (DEBUG) debug("Consuming tasks for " + lockID);
-    let lock = this.lockInfo[lockID];
-
-    // If a process dies, we should clean up after it via the
-    // child-process-shutdown event. But just in case we don't, we want to make
-    // sure we never block on consuming.
-    if (!lock) {
-      if (DEBUG) debug("Lock not found");
-      this.queueConsume();
-      return;
-    }
-
-    if (!lock.consumable || lock.tasks.length === 0) {
-      if (DEBUG) debug("No more tasks to run or not yet consuamble.");
-      return;
-    }
-
-    lock.consumable = false;
-    this.ensureConnection().then(
-      function(task) {
-        this.runTasks(lockID);
-      }.bind(this), function(ret) {
-        dump("-*- SettingsRequestManager: SETTINGS DATABASE ERROR: Cannot make DB connection!\n");
-    });
-  },
-
-  observe: function(aSubject, aTopic, aData) {
-    if (DEBUG) debug("observe");
-    switch (aTopic) {
-      case kXpcomShutdownObserverTopic:
-        this.messages.forEach((function(msgName) {
-          ppmm.removeMessageListener(msgName, this);
-        }).bind(this));
-        Services.obs.removeObserver(this, kXpcomShutdownObserverTopic);
-        ppmm = null;
-        break;
-      default:
-        if (DEBUG) debug("Wrong observer topic: " + aTopic);
-        break;
-    }
-  },
-
-  sendSettingsChange: function(aKey, aValue, aIsServiceLock) {
-    this.broadcastMessage("Settings:Change:Return:OK",
-      { key: aKey, value: aValue });
-    Services.obs.notifyObservers(this, kMozSettingsChangedObserverTopic,
-      JSON.stringify({
-        key: aKey,
-        value: aValue,
-        isInternalChange: aIsServiceLock
-      }));
-  },
-
-  broadcastMessage: function broadcastMessage(aMsgName, aContent) {
-    if (DEBUG) debug("Broadcast");
-    this.children.forEach(function(msgMgr) {
-      if (SettingsPermissions.hasReadPermission(msgMgr, aContent.key)) {
-        msgMgr.sendAsyncMessage(aMsgName, aContent);
-      }
-    });
-    if (DEBUG) debug("Finished Broadcasting");
-  },
-
-  addObserver: function(aMsgMgr) {
-    if (DEBUG) debug("Add observer for" + aMsgMgr);
-    if (this.children.indexOf(aMsgMgr) == -1) {
-      this.children.push(aMsgMgr);
-    }
-  },
-
-  removeObserver: function(aMsgMgr) {
-    if (DEBUG) debug("Remove observer for" + aMsgMgr);
-    let index = this.children.indexOf(aMsgMgr);
-    if (index != -1) {
-      this.children.splice(index, 1);
-    }
-  },
-
-  removeMessageManager: function(aMsgMgr){
-    if (DEBUG) debug("Removing message manager " + aMsgMgr);
-    this.removeObserver(aMsgMgr);
-    SettingsPermissions.removeManager(aMsgMgr);
-    let closedLockIDs = [];
-    let lockIDs = Object.keys(this.lockInfo);
-    for (let i in lockIDs) {
-      if (this.lockInfo[lockIDs[i]]._mm == aMsgMgr) {
-      	if (DEBUG) debug("Removing lock " + lockIDs[i] + " due to process close/crash");
-        closedLockIDs.push(lockIDs[i]);
-      }
-    }
-    for (let i in closedLockIDs) {
-      let transaction = this.lockInfo[closedLockIDs[i]]._transaction;
-      if (transaction) {
-        try {
-          transaction.abort();
-        } catch (e) {
-          if (e.name == "InvalidStateError") {
-            if (DEBUG) debug("Current transaction for " + this.lockID + " closed, trying to create new one.");
-          } else {
-            throw e;
-          }
-        }
-      }
-      delete this.lockInfo[closedLockIDs[i]];
-      let index = this.settingsLockQueue.indexOf(closedLockIDs[i]);
-      if (index > -1) {
-        this.settingsLockQueue.splice(index, 1);
-      }
-      // If index is 0, the lock we just removed was at the head of
-      // the queue, so possibly queue the next lock if it's
-      // consumable.
-      if (index == 0) {
-        this.queueConsume();
-      }
-    }
-  },
-
-  receiveMessage: function(aMessage) {
-    if (DEBUG) debug("receiveMessage " + aMessage.name);
-
-    let msg = aMessage.data;
-    let mm = aMessage.target;
-
-    function returnMessage(name, data) {
-      try {
-        mm.sendAsyncMessage(name, data);
-      } catch (e) {
-        if (DEBUG) debug("Return message failed, " + name);
-      }
-    }
-
-    // For all message types that expect a lockID, we check to make
-    // sure that we're accessing a lock that's part of our process. If
-    // not, consider it a security violation and kill the app. Killing
-    // based on creating a colliding lock ID happens as part of
-    // CreateLock check below.
-    switch (aMessage.name) {
-      case "Settings:Get":
-      case "Settings:Set":
-      case "Settings:Clear":
-      case "Settings:Run":
-      case "Settings:Finalize":
-        if (!msg.lockID ||
-            !this.lockInfo[msg.lockID] ||
-            mm != this.lockInfo[msg.lockID]._mm) {
-          Cu.reportError("Process trying to access settings lock from another process. Killing.");
-          // Kill the app by checking for a non-existent permission
-          aMessage.target.assertPermission("message-manager-mismatch-kill");
-          return;
-        }
-      default:
-      break;
-    }
-
-    switch (aMessage.name) {
-      case "child-process-shutdown":
-        if (DEBUG) debug("Child process shutdown received.");
-        this.removeMessageManager(mm);
-        break;
-      case "Settings:RegisterForMessages":
-        SettingsPermissions.addManager(aMessage);
-        if (!SettingsPermissions.hasSomeReadPermission(mm)) {
-          Cu.reportError("Settings message " + aMessage.name +
-                         " from a content process with no 'settings-api-read' privileges.");
-          // Kill app after reporting error
-          SettingsPermissions.assertSomeReadPermission(mm);
-          return;
-        }
-        this.addObserver(mm);
-        break;
-      case "Settings:UnregisterForMessages":
-        this.removeObserver(mm);
-        break;
-      case "Settings:CreateLock":
-        if (DEBUG) debug("Received CreateLock for " + msg.lockID);
-        // If we try to create a lock ID that collides with one
-        // already in the system, consider it a security violation and
-        // kill.
-        if (msg.lockID in this.settingsLockQueue) {
-          Cu.reportError("Trying to queue a lock with the same ID as an already queued lock. Killing app.");
-          aMessage.target.assertPermission("lock-id-duplicate-kill");
-          return;
-        }
-        this.settingsLockQueue.push(msg.lockID);
-        SettingsPermissions.addManager(aMessage);
-        this.lockInfo[msg.lockID] = SettingsLockInfo(this.settingsDB, mm, msg.lockID, msg.isServiceLock);
-        break;
-      case "Settings:Get":
-        if (DEBUG) debug("Received getRequest");
-        this.queueTask("get", msg).then(function(settings) {
-            returnMessage("Settings:Get:OK", {
-              lockID: msg.lockID,
-              requestID: msg.requestID,
-              settings: settings
-            });
-          }, function(error) {
-            if (DEBUG) debug("getRequest FAILED " + msg.name);
-            returnMessage("Settings:Get:KO", {
-              lockID: msg.lockID,
-              requestID: msg.requestID,
-              errorMsg: error
-            });
-        });
-        break;
-      case "Settings:Set":
-        if (DEBUG) debug("Received Set Request");
-        this.queueTask("set", msg).then(function(settings) {
-          returnMessage("Settings:Set:OK", {
-            lockID: msg.lockID,
-            requestID: msg.requestID
-          });
-        }, function(error) {
-          returnMessage("Settings:Set:KO", {
-            lockID: msg.lockID,
-            requestID: msg.requestID,
-            errorMsg: error
-          });
-        });
-        break;
-      case "Settings:Clear":
-        if (DEBUG) debug("Received Clear Request");
-        this.queueTask("clear", msg).then(function() {
-          returnMessage("Settings:Clear:OK", {
-            lockID: msg.lockID,
-            requestID: msg.requestID
-          });
-        }, function(error) {
-          returnMessage("Settings:Clear:KO", {
-            lockID: msg.lockID,
-            requestID: msg.requestID,
-            errorMsg: error
-          });
-        });
-        break;
-      case "Settings:Finalize":
-        if (DEBUG) debug("Received Finalize");
-        this.queueTask("finalize", msg).then(function() {
-          returnMessage("Settings:Finalize:OK", {
-            lockID: msg.lockID
-          });
-        }, function(error) {
-          returnMessage("Settings:Finalize:KO", {
-            lockID: msg.lockID,
-            errorMsg: error
-          });
-        });
-      // YES THIS IS SUPPOSED TO FALL THROUGH. Finalize is considered a task
-      // running situation, but it also needs to queue a task.
-      case "Settings:Run":
-        if (DEBUG) debug("Received Run");
-        this.lockInfo[msg.lockID].consumable = true;
-        if (msg.lockID == this.settingsLockQueue[0]) {
-          // If a lock is currently at the head of the queue, run all tasks for
-          // it.
-          if (DEBUG) debug("Running tasks for " + msg.lockID);
-          this.queueConsume();
-        } else {
-          // If a lock isn't at the head of the queue, but requests to be run,
-          // simply mark it as consumable, which means it will automatically run
-          // once it comes to the head of the queue.
-          if (DEBUG) debug("Queuing tasks for " + msg.lockID + " while waiting for " + this.settingsLockQueue[0]);
-        }
-        break;
-      default:
-        if (DEBUG) debug("Wrong message: " + aMessage.name);
-    }
-  }
-};
-
-SettingsRequestManager.init();
--- a/dom/settings/SettingsService.js
+++ b/dom/settings/SettingsService.js
@@ -1,183 +1,48 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict"
 
 /* static functions */
-const DEBUG = false;
-function debug(s) {
-  dump("-*- SettingsService: " + s + "\n");
-}
+let DEBUG = 0;
+let debug;
+if (DEBUG)
+  debug = function (s) { dump("-*- SettingsService: " + s + "\n"); }
+else
+  debug = function (s) {}
 
 const Ci = Components.interfaces;
 const Cu = Components.utils;
 
+Cu.import("resource://gre/modules/SettingsQueue.jsm");
+Cu.import("resource://gre/modules/SettingsDB.jsm");
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 Cu.import("resource://gre/modules/Services.jsm");
-Cu.import('resource://gre/modules/SettingsRequestManager.jsm');
-
-XPCOMUtils.defineLazyServiceGetter(this, "uuidgen",
-                                   "@mozilla.org/uuid-generator;1",
-                                   "nsIUUIDGenerator");
-XPCOMUtils.defineLazyServiceGetter(this, "cpmm",
-                                   "@mozilla.org/childprocessmessagemanager;1",
-                                   "nsIMessageSender");
 
 const nsIClassInfo            = Ci.nsIClassInfo;
 
 const SETTINGSSERVICELOCK_CONTRACTID = "@mozilla.org/settingsServiceLock;1";
 const SETTINGSSERVICELOCK_CID        = Components.ID("{d7a395a0-e292-11e1-834e-1761d57f5f99}");
 const nsISettingsServiceLock         = Ci.nsISettingsServiceLock;
 
-function makeSettingsServiceRequest(aCallback, aName, aValue) {
-  return {
-    callback: aCallback,
-    name: aName,
-    value: aValue
-  };
-};
-
-function SettingsServiceLock(aSettingsService, aTransactionCallback) {
+function SettingsServiceLock(aSettingsService, aTransactionCallback)
+{
   if (DEBUG) debug("settingsServiceLock constr!");
   this._open = true;
+  this._busy = false;
+  this._requests = new Queue();
   this._settingsService = aSettingsService;
-  this._id = uuidgen.generateUUID().toString();
+  this._transaction = null;
   this._transactionCallback = aTransactionCallback;
-  this._requests = {};
-  let closeHelper = function() {
-    if (DEBUG) debug("closing lock " + this._id);
-    this._open = false;
-    this.runOrFinalizeQueries();
-  }.bind(this);
-
-  let msgs =   ["Settings:Get:OK", "Settings:Get:KO",
-                "Settings:Clear:OK", "Settings:Clear:KO",
-                "Settings:Set:OK", "Settings:Set:KO",
-                "Settings:Finalize:OK", "Settings:Finalize:KO"];
-
-  for (let msg in msgs) {
-    cpmm.addMessageListener(msgs[msg], this);
-  }
-
-  cpmm.sendAsyncMessage("Settings:CreateLock", {lockID: this._id, isServiceLock: true}, undefined, Services.scriptSecurityManager.getSystemPrincipal());
-  Services.tm.currentThread.dispatch(closeHelper, Ci.nsIThread.DISPATCH_NORMAL);
 }
 
 SettingsServiceLock.prototype = {
-  get closed() {
-    return !this._open;
-  },
-
-  runOrFinalizeQueries: function() {
-    if (!this._requests || Object.keys(this._requests).length == 0) {
-      cpmm.sendAsyncMessage("Settings:Finalize", {lockID: this._id}, undefined, Services.scriptSecurityManager.getSystemPrincipal());
-    } else {
-      cpmm.sendAsyncMessage("Settings:Run", {lockID: this._id}, undefined, Services.scriptSecurityManager.getSystemPrincipal());
-    }
-  },
-
-  receiveMessage: function(aMessage) {
-
-    let msg = aMessage.data;
-    // SettingsRequestManager broadcasts changes to all locks in the child. If
-    // our lock isn't being addressed, just return.
-    if(msg.lockID != this._id) {
-      return;
-    }
-    if (DEBUG) debug("receiveMessage (" + this._id + "): " + aMessage.name);
-    // Finalizing a transaction does not return a request ID since we are
-    // supposed to fire callbacks.
-    if (!msg.requestID) {
-      switch (aMessage.name) {
-        case "Settings:Finalize:OK":
-          if (DEBUG) debug("Lock finalize ok!");
-          this.callTransactionHandle();
-          break;
-        case "Settings:Finalize:KO":
-          if (DEBUG) debug("Lock finalize failed!");
-          this.callAbort();
-          break;
-        default:
-          if (DEBUG) debug("Message type " + aMessage.name + " is missing a requestID");
-      }
-      return;
-    }
-
-    let req = this._requests[msg.requestID];
-    if (!req) {
-      if (DEBUG) debug("Matching request not found.");
-      return;
-    }
-    delete this._requests[msg.requestID];
-    switch (aMessage.name) {
-      case "Settings:Get:OK":
-        this._open = true;
-        let settings_names = Object.keys(msg.settings);
-        if (settings_names.length > 0) {
-          let name = settings_names[0];        
-          if (DEBUG && settings_names.length > 1) {
-            debug("Warning: overloaded setting:" + name);
-          }
-          let result = msg.settings[name];
-          this.callHandle(req.callback, name, result);
-        } else {
-          this.callHandle(req.callback, req.name, null);
-        }
-        this._open = false;
-        break;
-      case "Settings:Set:OK":
-        this._open = true;
-        // We don't pass values back from sets in SettingsManager...
-        this.callHandle(req.callback, req.name, req.value);
-        this._open = false;
-        break;
-      case "Settings:Get:KO":
-      case "Settings:Set:KO":
-        if (DEBUG) debug("error:" + msg.errorMsg);
-        this.callError(req.callback, msg.error);
-        break;
-      default:
-        if (DEBUG) debug("Wrong message: " + aMessage.name);
-    }
-    this.runOrFinalizeQueries();
-  },
-
-  get: function get(aName, aCallback) {
-    if (DEBUG) debug("get (" + this._id + "): " + aName);
-    if (!this._open) {
-      dump("Settings lock not open!\n");
-      throw Components.results.NS_ERROR_ABORT;
-    }
-    let reqID = uuidgen.generateUUID().toString();
-    this._requests[reqID] = makeSettingsServiceRequest(aCallback, aName);
-    cpmm.sendAsyncMessage("Settings:Get", {requestID: reqID,
-                                           lockID: this._id,
-                                           name: aName},
-                                           undefined,
-                                           Services.scriptSecurityManager.getSystemPrincipal());
-  },
-
-  set: function set(aName, aValue, aCallback) {
-    if (DEBUG) debug("set: " + aName + " " + aValue);
-    if (!this._open) {
-      throw "Settings lock not open";
-    }
-    let reqID = uuidgen.generateUUID().toString();
-    this._requests[reqID] = makeSettingsServiceRequest(aCallback, aName, aValue);
-    let settings = {};
-    settings[aName] = aValue;
-    cpmm.sendAsyncMessage("Settings:Set", {requestID: reqID,
-                                           lockID: this._id,
-                                           settings: settings},
-                                           undefined,
-                                           Services.scriptSecurityManager.getSystemPrincipal());
-  },
 
   callHandle: function callHandle(aCallback, aName, aValue) {
     try {
       aCallback ? aCallback.handle(aName, aValue) : null;
     } catch (e) {
       dump("settings 'handle' callback threw an exception, dropping: " + e + "\n");
     }
   },
@@ -201,31 +66,190 @@ SettingsServiceLock.prototype = {
   callTransactionHandle: function callTransactionHandle() {
     try {
       this._transactionCallback ? this._transactionCallback.handle() : null;
     } catch (e) {
       dump("settings 'Transaction handle' callback threw an exception, dropping: " + e + "\n");
     }
   },
 
+  process: function process() {
+    debug("process!");
+    let lock = this;
+    lock._open = false;
+    let store = lock._transaction.objectStore(SETTINGSSTORE_NAME);
+
+    while (!lock._requests.isEmpty()) {
+      if (lock._isBusy) {
+        return;
+      }
+      let info = lock._requests.dequeue();
+      if (DEBUG) debug("info:" + info.intent);
+      let callback = info.callback;
+      let name = info.name;
+      switch (info.intent) {
+        case "set":
+          let value = info.value;
+          let message = info.message;
+          if(DEBUG && typeof(value) == 'object') {
+            debug("object name:" + name + ", val: " + JSON.stringify(value));
+          }
+          lock._isBusy = true;
+          let checkKeyRequest = store.get(name);
+
+          checkKeyRequest.onsuccess = function (event) {
+            let defaultValue;
+            if (event.target.result) {
+              defaultValue = event.target.result.defaultValue;
+            } else {
+              defaultValue = null;
+              if (DEBUG) debug("MOZSETTINGS-SET-WARNING: " + name + " is not in the database.\n");
+            }
+            let setReq = store.put({ settingName: name, defaultValue: defaultValue, userValue: value });
+
+            setReq.onsuccess = function() {
+              lock._isBusy = false;
+              lock._open = true;
+              lock.callHandle(callback, name, value);
+              Services.obs.notifyObservers(lock, "mozsettings-changed", JSON.stringify({
+                key: name,
+                value: value,
+                message: message
+              }));
+              lock._open = false;
+              lock.process();
+            };
+
+            setReq.onerror = function(event) {
+              lock._isBusy = false;
+              lock.callError(callback, event.target.errorMessage);
+              lock.process();
+            };
+          }
+
+          checkKeyRequest.onerror = function(event) {
+            lock._isBusy = false;
+            lock.callError(callback, event.target.errorMessage);
+            lock.process();
+          };
+          break;
+        case "get":
+          let getReq = store.mozGetAll(name);
+          getReq.onsuccess = function(event) {
+            if (DEBUG) {
+              debug("Request successful. Record count:" + event.target.result.length);
+              debug("result: " + JSON.stringify(event.target.result));
+            }
+            this._open = true;
+            if (callback) {
+              if (event.target.result[0]) {
+                if (event.target.result.length > 1) {
+                  if (DEBUG) debug("Warning: overloaded setting:" + name);
+                }
+                let result = event.target.result[0];
+                let value = result.userValue !== undefined
+                            ? result.userValue
+                            : result.defaultValue;
+                lock.callHandle(callback, name, value);
+              } else {
+                lock.callHandle(callback, name, null);
+              }
+            } else {
+              if (DEBUG) debug("no callback defined!");
+            }
+            this._open = false;
+          }.bind(lock);
+          getReq.onerror = function error(event) {
+            lock.callError(callback, event.target.errorMessage);
+          };
+          break;
+      }
+    }
+    lock._open = true;
+  },
+
+  createTransactionAndProcess: function() {
+    if (this._settingsService._settingsDB._db) {
+      let lock;
+      while (lock = this._settingsService._locks.dequeue()) {
+        if (!lock._transaction) {
+          lock._transaction = lock._settingsService._settingsDB._db.transaction(SETTINGSSTORE_NAME, "readwrite");
+          if (lock._transactionCallback) {
+            lock._transaction.oncomplete = lock.callTransactionHandle.bind(lock);
+            lock._transaction.onabort = function(event) {
+              let message = '';
+              if (event.target.error) {
+                message = event.target.error.name + ': ' + event.target.error.message;
+              }
+              this.callAbort(lock._transactionCallback.handleAbort, message);
+            };
+          }
+        }
+        if (!lock._isBusy) {
+          lock.process();
+        } else {
+          this._settingsService._locks.enqueue(lock);
+          return;
+        }
+      }
+      if (!this._requests.isEmpty() && !this._isBusy) {
+        this.process();
+      }
+    }
+  },
+
+  get: function get(aName, aCallback) {
+    if (DEBUG) debug("get: " + aName + ", " + aCallback);
+    this._requests.enqueue({ callback: aCallback, intent:"get", name: aName });
+    this.createTransactionAndProcess();
+  },
+
+  set: function set(aName, aValue, aCallback, aMessage) {
+    debug("set: " + aName + ": " + JSON.stringify(aValue));
+    if (aMessage === undefined)
+      aMessage = null;
+    this._requests.enqueue({ callback: aCallback,
+                             intent: "set", 
+                             name: aName, 
+                             value: this._settingsService._settingsDB.prepareValue(aValue),
+                             message: aMessage });
+    this.createTransactionAndProcess();
+  },
+
   classID : SETTINGSSERVICELOCK_CID,
   QueryInterface : XPCOMUtils.generateQI([nsISettingsServiceLock])
 };
 
 const SETTINGSSERVICE_CID        = Components.ID("{f656f0c0-f776-11e1-a21f-0800200c9a66}");
 
 function SettingsService()
 {
-  if (DEBUG) debug("settingsService Constructor");
+  debug("settingsService Constructor");
+  this._locks = new Queue();
+  this._settingsDB = new SettingsDB();
+  this._settingsDB.init();
 }
 
 SettingsService.prototype = {
 
+  nextTick: function nextTick(aCallback, thisObj) {
+    if (thisObj)
+      aCallback = aCallback.bind(thisObj);
+
+    Services.tm.currentThread.dispatch(aCallback, Ci.nsIThread.DISPATCH_NORMAL);
+  },
+
   createLock: function createLock(aCallback) {
     var lock = new SettingsServiceLock(this, aCallback);
+    this._locks.enqueue(lock);
+    this._settingsDB.ensureDB(
+      function() { lock.createTransactionAndProcess(); },
+      function() { dump("SettingsService failed to open DB!\n"); }
+    );
+    this.nextTick(function() { this._open = false; }, lock);
     return lock;
   },
 
   classID : SETTINGSSERVICE_CID,
   QueryInterface : XPCOMUtils.generateQI([Ci.nsISettingsService])
-};
+}
 
-this.NSGetFactory = XPCOMUtils.generateNSGetFactory([SettingsService, SettingsServiceLock]);
+this.NSGetFactory = XPCOMUtils.generateNSGetFactory([SettingsService, SettingsServiceLock])
--- a/dom/settings/moz.build
+++ b/dom/settings/moz.build
@@ -13,13 +13,14 @@ if CONFIG['MOZ_B2G']:
     EXTRA_COMPONENTS += [
         'SettingsService.js',
         'SettingsService.manifest',
     ]
 
     MOCHITEST_CHROME_MANIFESTS += ['tests/chrome.ini']
 
 EXTRA_JS_MODULES += [
+    'SettingsChangeNotifier.jsm',
     'SettingsDB.jsm',
-    'SettingsRequestManager.jsm'
+    'SettingsQueue.jsm',
 ]
 
 MOCHITEST_MANIFESTS += ['tests/mochitest.ini']
--- a/dom/settings/tests/mochitest.ini
+++ b/dom/settings/tests/mochitest.ini
@@ -1,10 +1,9 @@
 [DEFAULT]
 skip-if = (toolkit == 'gonk' && debug) || e10s #debug-only failure, bug 932878
 
 [test_settings_basics.html]
-[test_settings_permissions.html]
 [test_settings_blobs.html]
 [test_settings_data_uris.html]
 [test_settings_events.html]
 [test_settings_navigator_object.html]
 [test_settings_onsettingchange.html]
--- a/dom/settings/tests/test_settings_basics.html
+++ b/dom/settings/tests/test_settings_basics.html
@@ -17,24 +17,21 @@ https://bugzilla.mozilla.org/show_bug.cg
 
 </div>
 <pre id="test">
 <script class="testbody" type="text/javascript">
 
 "use strict";
 
 if (SpecialPowers.isMainProcess()) {
-  SpecialPowers.Cu.import("resource://gre/modules/SettingsRequestManager.jsm");
+  SpecialPowers.Cu.import("resource://gre/modules/SettingsChangeNotifier.jsm");
 }
 
-SpecialPowers.addPermission("settings-api-read", true, document);
-SpecialPowers.addPermission("settings-api-write", true, document);
 SpecialPowers.addPermission("settings-read", true, document);
 SpecialPowers.addPermission("settings-write", true, document);
-SpecialPowers.addPermission("settings-clear", true, document);
 
 function onUnwantedSuccess() {
   ok(false, "onUnwantedSuccess: shouldn't get here");
 }
 
 function onFailure() {
   ok(false, "in on Failure!");
 }
@@ -322,46 +319,43 @@ var steps = [
     req5.onerror = onFailure;
   },
   function () {
     ok(true, "Deleting database");
     var lock = mozSettings.createLock();
     req = lock.clear();
     req.onsuccess = function () {
       ok(true, "Deleted the database");
-      next();
     };
-  },
-  function () {
-    var lock = mozSettings.createLock();
+    req.onerror = onFailure;
     req2 = lock.set(wifi);
     req2.onsuccess = function () {
       ok(true, "set done");
     }
     req2.onerror = onFailure;
 
     ok(true, "Get all settings");
     var lock2 = mozSettings.createLock();
-    req3 = lock2.get("*");
-    req3.onsuccess = function () {
-      is(Object.keys(req3.result).length, 1, "length 1");
-      check(req3.result, wifi);
-      ok(true, JSON.stringify(req3.result));
+    req = lock2.get("*");
+    req.onsuccess = function () {
+      is(Object.keys(req.result).length, 1, "length 1");
+      check(wifi, req.result);
+      ok(true, JSON.stringify(req.result));
       ok(true, "Get all settings Done");
     };
-    req3.onerror = onFailure;
+    req.onerror = onFailure;
 
-    req4 = lock2.get("net3g.apn");
-    req4.onsuccess = function () {
-      is(Object.keys(req4.result).length, 1, "length 1");
-      check(wifi, req4.result);
+    req2 = lock2.get("net3g.apn");
+    req2.onsuccess = function () {
+      is(Object.keys(req2.result).length, 1, "length 1");
+      check(wifi, req2.result);
       ok(true, "Get net3g.apn Done");
       next();
     };
-    req4.onerror = onFailure;
+    req2.onerror = onFailure;
   },
   function () {
     ok(true, "Change wifi1");
     var lock = mozSettings.createLock();
     req = lock.set(wifi2);
     req.onsuccess = function () {
       ok(true, "Set Done");
     };
@@ -468,18 +462,18 @@ var steps = [
       testObj["wifi.enabled" + i] = false;
       req5.onsuccess = function () {
         check(this.request.result, this.testObj);
         ok(true, "Get2 Done");
       }.bind({testObj: testObj, request: req5});
       req5.onerror = onFailure;
     }
 
-    var lock6 = mozSettings.createLock();
-    req6 = lock6.clear();
+    var lock5 = mozSettings.createLock();
+    req6 = lock5.clear();
     req6.onsuccess = function () {
       ok(true, "Deleted the database");
       next();
     };
     req6.onerror = onFailure;
   },
   function () {
     ok(true, "reverse Test locking");
@@ -505,25 +499,23 @@ var steps = [
 
     req = lock.get("wifi.enabled");
     req.onsuccess = function() {
       check(req.result, wifiEnabled);
       ok(true, "Test2 locking result done");
     }
     req.onerror = onFailure;
 
-    var lock2 = mozSettings.createLock();
-    req2 = lock2.clear();
+    req2 = lock.clear();
     req2.onsuccess = function () {
       ok(true, "Deleted the database");
     };
     req2.onerror = onFailure;
 
-    var lock3 = mozSettings.createLock();
-    req3 = lock3.set(wifi);
+    req3 = lock.set(wifi);
     req3.onsuccess = function () {
       ok(true, "set done");
       next();
     }
     req3.onerror = onFailure;
 
   },
   function () {
@@ -765,44 +757,16 @@ var steps = [
     req = lock.clear();
     req.onsuccess = function () {
       ok(true, "Deleted the database");
       next();
     };
     req.onerror = onFailure;
   },
   function () {
-    ok(true, "Call success callback when transaction commits");
-    var lock = mozSettings.createLock();
-    lock.onsettingstransactionsuccess = function () {
-      next();
-    };
-    req = lock.set({"setting-obj": {foo: {bar: 23}}});
-    req.onsuccess = function() {
-      req2 = lock.get("setting-obj");
-      req2.onsuccess = function(event) {
-        var result = event.target.result["setting-obj"];
-        ok(result, "Got valid result");
-        ok(typeof result == "object", "Result is object");
-        ok("foo" in result && "bar" in result.foo, "Result has properties");
-        ok(result.foo.bar == 23, "Result properties are set");
-      };
-    };
-  },
-  function() {
-    ok(true, "Clear DB");
-    var lock = mozSettings.createLock();
-    req = lock.clear();
-    req.onsuccess = function () {
-      ok(true, "Deleted the database");
-      next();
-    };
-    req.onerror = onFailure;
-  },
-  function () {
     ok(true, "all done!\n");
     SimpleTest.finish();
   }
 ];
 
 function next() {
   ok(true, "Begin!");
   if (index >= steps.length) {
--- a/dom/settings/tests/test_settings_blobs.html
+++ b/dom/settings/tests/test_settings_blobs.html
@@ -17,24 +17,21 @@ https://bugzilla.mozilla.org/show_bug.cg
 
 </div>
 <pre id="test">
 <script class="testbody" type="text/javascript;version=1.7">
 
 "use strict";
 
 if (SpecialPowers.isMainProcess()) {
-  SpecialPowers.Cu.import("resource://gre/modules/SettingsRequestManager.jsm");
+  SpecialPowers.Cu.import("resource://gre/modules/SettingsChangeNotifier.jsm");
 }
 
 SpecialPowers.addPermission("settings-read", true, document);
 SpecialPowers.addPermission("settings-write", true, document);
-SpecialPowers.addPermission("settings-api-read", true, document);
-SpecialPowers.addPermission("settings-api-write", true, document);
-SpecialPowers.addPermission("settings-clear", true, document);
 
 function onUnwantedSuccess() {
   ok(false, "onUnwantedSuccess: shouldn't get here");
 }
 
 function onFailure() {
   return function(s) {
     if (s) {
--- a/dom/settings/tests/test_settings_data_uris.html
+++ b/dom/settings/tests/test_settings_data_uris.html
@@ -17,24 +17,21 @@ https://bugzilla.mozilla.org/show_bug.cg
 
 </div>
 <pre id="test">
 <script class="testbody" type="text/javascript;version=1.7">
 
 "use strict";
 
 if (SpecialPowers.isMainProcess()) {
-  SpecialPowers.Cu.import("resource://gre/modules/SettingsRequestManager.jsm");
+  SpecialPowers.Cu.import("resource://gre/modules/SettingsChangeNotifier.jsm");
 }
 
 SpecialPowers.addPermission("settings-read", true, document);
 SpecialPowers.addPermission("settings-write", true, document);
-SpecialPowers.addPermission("settings-api-read", true, document);
-SpecialPowers.addPermission("settings-api-write", true, document);
-SpecialPowers.addPermission("settings-clear", true, document);
 
 function onUnwantedSuccess() {
   ok(false, "onUnwantedSuccess: shouldn't get here");
 }
 
 function onFailure() {
   return function(s) {
     if (s) {
--- a/dom/settings/tests/test_settings_events.html
+++ b/dom/settings/tests/test_settings_events.html
@@ -27,21 +27,13 @@ is(e.settingValue, 1, "Value should be 1
 e = new MozSettingsEvent("settingchanged", {settingName: "test", settingValue: {test: "test"}});
 is(e.settingName, "test", "Name should be 'test'.");
 is(e.settingValue.test, "test", "Name should be 'test'.");
 
 e = new MozSettingsEvent("settingchanged", {settingName: "a", settingValue: true});
 is(e.settingName, "a", "Name should be a.");
 is(e.settingValue, true, "Value should be true.");
 
-var e = new MozSettingsTransactionEvent("settingtransactionsuccess", {});
-ok(e, "Should have settings event!");
-is(e.error, "", "error should be null");
-
-var e = new MozSettingsTransactionEvent("settingtransactionfailure", {error: "Test error."});
-ok(e, "Should have settings event!");
-is(e.error, "Test error.", "error should be 'Test error.'");
-
 
 </script>
 </pre>
 </body>
-</html>
+</html>
\ No newline at end of file
--- a/dom/settings/tests/test_settings_navigator_object.html
+++ b/dom/settings/tests/test_settings_navigator_object.html
@@ -27,20 +27,17 @@ function testPref() {
   }, function() {
     ise(navigator.mozSettings, undefined, "navigator.mozSettings is undefined");
     SimpleTest.finish();
   });
 }
 
 SpecialPowers.pushPermissions([
   {type: "settings-read", allow: 0, context: document},
-  {type: "settings-write", allow: 0, context: document},
-  {type: "settings-api-read", allow: 0, context: document},
-  {type: "settings-api-write", allow: 0, context: document},
-  {type: "settings-clear", allow: 0, context: document}
+  {type: "settings-write", allow: 0, context: document}
 ], function() {
   ise(frames[0].navigator.mozSettings, null, "navigator.mozSettings is null when the page doesn't have permissions");
   testPref();
 });
 </script>
 </pre>
 </body>
 </html>
--- a/dom/settings/tests/test_settings_onsettingchange.html
+++ b/dom/settings/tests/test_settings_onsettingchange.html
@@ -17,24 +17,21 @@ https://bugzilla.mozilla.org/show_bug.cg
 
 </div>
 <pre id="test">
 <script class="testbody" type="text/javascript">
 
 "use strict";
 
 if (SpecialPowers.isMainProcess()) {
-  SpecialPowers.Cu.import("resource://gre/modules/SettingsRequestManager.jsm");
+  SpecialPowers.Cu.import("resource://gre/modules/SettingsChangeNotifier.jsm");
 }
 
 SpecialPowers.addPermission("settings-write", true, document);
 SpecialPowers.addPermission("settings-read", true, document);
-SpecialPowers.addPermission("settings-api-read", true, document);
-SpecialPowers.addPermission("settings-api-write", true, document);
-SpecialPowers.addPermission("settings-clear", true, document);
 
 var screenBright = {"screen.brightness": 0.7};
 
 function onFailure() {
   ok(false, "in on Failure!");
 }
 
 function observer1(setting) {
@@ -87,22 +84,18 @@ var mozSettings = window.navigator.mozSe
 
 var steps = [
   function () {
     ok(true, "Deleting database");
     var lock = mozSettings.createLock();
     req = lock.clear();
     req.onsuccess = function () {
       ok(true, "Deleted the database");
-      next();
     };
     req.onerror = onFailure;
-  },
-  function () {
-    var lock = mozSettings.createLock();
     req2 = lock.set(screenBright);
     req2.onsuccess = function () {
       ok(true, "set done");
       navigator.mozSettings.onsettingchange = onsettingschangeWithNext;
       next();
     }
     req2.onerror = onFailure;
   },
@@ -269,29 +262,26 @@ var steps = [
     req.onerror = onFailure;
   },
   function () {
     ok(true, "Deleting database");
     var lock = mozSettings.createLock();
     req = lock.clear();
     req.onsuccess = function () {
       ok(true, "Deleted the database");
-      next();
+      navigator.mozSettings.onsettingchange = onComplexSettingschangeWithNext;
     };
     req.onerror = onFailure;
-  },
-  function () {
-    var lock = mozSettings.createLock();
-    navigator.mozSettings.onsettingchange = onComplexSettingschangeWithNext;
     req2 = navigator.mozSettings.createLock().set({'test.key': cset});
     req2.onsuccess = function () {
       ok(true, "set done");
     }
     req2.onerror = onFailure;
   },
+  
   function () {
     ok(true, "all done!\n");
     SimpleTest.finish();
   }
 ];
 
 function next() {
   ok(true, "Begin!");
deleted file mode 100644
--- a/dom/settings/tests/test_settings_permissions.html
+++ /dev/null
@@ -1,203 +0,0 @@
-<!DOCTYPE html>
-<html>
-<!--
-https://bugzilla.mozilla.org/show_bug.cgi?id={678695}
--->
-<head>
-  <title>Test for Bug {678695} Settings API</title>
-  <script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
-  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
-  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
-</head>
-<body>
-
-<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id={900551}">Mozilla Bug {900551}</a>
-<p id="display"></p>
-<div id="content" style="display: none">
-
-</div>
-<pre id="test">
-<script class="testbody" type="text/javascript">
-
-"use strict";
-
-if (SpecialPowers.isMainProcess()) {
-  SpecialPowers.Cu.import("resource://gre/modules/SettingsRequestManager.jsm");
-}
-
-SpecialPowers.removePermission("settings-read", document);
-SpecialPowers.removePermission("settings-write", document);
-SpecialPowers.addPermission("settings-api-read", true, document);
-SpecialPowers.addPermission("settings-api-write", true, document);
-SpecialPowers.addPermission("settings:wallpaper.image-read", true, document);
-SpecialPowers.addPermission("settings:wallpaper.image-write", true, document);
-SpecialPowers.addPermission("settings-clear", true, document);
-
-function onUnwantedSuccess() {
-  ok(false, "onUnwantedSuccess: shouldn't get here");
-}
-
-function onFailure() {
-  ok(false, "in on Failure!");
-}
-
-const wifi  = {"wifi.enabled": false}
-const wallpaper = {"wallpaper.image": "test-image"};
-
-var combination = {
-  "wifi.enabled": false,
-  "wallpaper.image": "test-image"
-}
-
-function equals(o1, o2) {
-  var k1 = Object.keys(o1).sort();
-  var k2 = Object.keys(o2).sort();
-  if (k1.length != k2.length) return false;
-  return k1.zip(k2, function(keyPair) {
-    if(typeof o1[keyPair[0]] == typeof o2[keyPair[1]] == "object"){
-      return equals(o1[keyPair[0]], o2[keyPair[1]])
-    } else {
-      return o1[keyPair[0]] == o2[keyPair[1]];
-    }
-  }).all();
-};
-
-function observer1(setting) {
-  is(setting.settingName, "screen.brightness", "Same settingName");
-  is(setting.settingValue, "0.7", "Same settingvalue");
-};
-
-function onsettingschangeWithNext(event) {
-  is(event.settingName, "screen.brightness", "Same settingName");
-  is(event.settingValue, "0.7", "Same settingvalue");
-  next();
-};
-
-function check(o1, o2) {
-  is(JSON.stringify(o1), JSON.stringify(o2), "same");
-}
-
-var req, req2, req3, req4, req5, req6;
-var index = 0;
-
-var mozSettings = navigator.mozSettings;
-
-var steps = [
-  // Can't delete database here since that requires permissions we don't want
-  // to give the page.
-  function () {
-    ok(true, "Setting wallpaper");
-    var lock = mozSettings.createLock();
-    req = lock.set(wallpaper);
-    req.onsuccess = function () {
-      ok(true, "set done");
-    }
-    req.onerror = onFailure;
-
-    var lock2 = mozSettings.createLock();
-    req2 = lock2.get("wallpaper.image");
-    req2.onsuccess = function () {
-      is(Object.keys(req2.result).length, 1, "length 1");
-      check(wallpaper, req2.result);
-      ok(true, "Get wallpaper Done");
-      next();
-    };
-    req2.onerror = onFailure;
-  },
-  function () {
-    ok(true, "Get Wifi");
-    var lock = mozSettings.createLock();
-    req = lock.get("wifi.enabled");
-    req.onerror = function () {
-      ok(true, "get failed (expected)");
-      next();
-    }
-    req.onsuccess = onFailure;
-  },
-  function () {
-    ok(true, "Set Wifi");
-    var lock = mozSettings.createLock();
-    req = lock.set(wifi);
-    req.onerror = function () {
-      ok(true, "set failed (expected)");
-      next();
-    }
-    req.onsuccess = onFailure;
-  },
-  function () {
-    ok(true, "Set combination (1 valid 1 not valid)");
-    var lock = mozSettings.createLock();
-    req = lock.set(combination);
-    req.onerror = function () {
-      ok(true, "set failed (expected)");
-      next();
-    }
-    req.onsuccess = onFailure;
-  },
-  function () {
-    ok(true, "All requests on a failed lock should fail");
-    var lock = mozSettings.createLock();
-    lock.onsettingstransactionfailure = function (evt) {
-      ok(evt.error == "Lock failed a permissions check, all requests now failing.", "transaction failure on permissions error message correct.");
-      ok(true, "transaction failed (expected) ");
-      next();
-    };
-    lock.onsettingstransactionsuccess = onFailure;
-
-    req = lock.set(wifi);
-    req.onerror = function () {
-      ok(true, "set failed (expected)");
-    }
-    req.onsuccess = onFailure;
-    req2 = lock.get("wallpaper.image");
-    req2.onerror = function () {
-      ok(true, "get failed (expected)");
-    }
-    req2.onsuccess = onFailure;
-  },
-  function () {
-    ok(true, "Set combination (1 valid 1 not valid)");
-    var lock = mozSettings.createLock();
-    req = lock.set(combination);
-    req.onerror = function () {
-      ok(true, "set failed (expected)");
-      next();
-    }
-    req.onsuccess = onFailure;
-  },
-  function () {
-    ok(true, "Set combination (1 valid 1 not valid)");
-    var lock = mozSettings.createLock();
-    req = lock.set(combination);
-    req.onerror = function () {
-      ok(true, "set failed (expected)");
-      next();
-    }
-    req.onsuccess = onFailure;
-  },
-  function () {
-    ok(true, "all done!\n");
-    SimpleTest.finish();
-  }
-];
-
-function next() {
-  ok(true, "Begin!");
-  if (index >= steps.length) {
-    ok(false, "Shouldn't get here!");
-    return;
-  }
-  try {
-    steps[index]();
-  } catch(ex) {
-    ok(false, "Caught exception", ex);
-  }
-  index += 1;
-}
-
-SimpleTest.waitForExplicitFinish();
-addLoadEvent(next);
-</script>
-</pre>
-</body>
-</html>
--- a/dom/settings/tests/test_settings_service.js
+++ b/dom/settings/tests/test_settings_service.js
@@ -1,18 +1,14 @@
 "use strict";
 
 const Cu = Components.utils;
 const Cc = Components.classes;
 const Ci = Components.interfaces;
 
-if (SpecialPowers.isMainProcess()) {
-  SpecialPowers.Cu.import("resource://gre/modules/SettingsRequestManager.jsm");
-}
-
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 Cu.import("resource://gre/modules/Services.jsm");
 
 SimpleTest.waitForExplicitFinish();
 
 XPCOMUtils.defineLazyServiceGetter(this, "SettingsService",
                                    "@mozilla.org/settingsService;1",
                                    "nsISettingsService");
@@ -79,42 +75,53 @@ let tests = [
 
   /* Observer tests */
   function() {
     const MOZSETTINGS_CHANGED   = "mozsettings-changed";
     const TEST_OBSERVER_KEY     = "test.observer.key";
     const TEST_OBSERVER_VALUE   = true;
     const TEST_OBSERVER_MESSAGE = "test.observer.message";
 
+    let observerCount = 2;
+
     function observer(subject, topic, data) {
 
       if (topic !== MOZSETTINGS_CHANGED) {
         ok(false, "Event is not mozsettings-changed.");
         return;
       }
 
       data = JSON.parse(data);
+
       function checkProp(name, type, value) {
         ok(name in data, "data." + name + " is present");
         is(typeof data[name], type, "data." + name + " is " + type);
         is(data[name], value, "data." + name + " is " + value);
       }
 
       checkProp("key", "string", TEST_OBSERVER_KEY);
       checkProp("value", "boolean", TEST_OBSERVER_VALUE);
-      checkProp("isInternalChange", "boolean", true);
+      if (observerCount === 2) {
+        checkProp("message", "object", null);
+      } else {
+        checkProp("message", "string", TEST_OBSERVER_MESSAGE);
+      }
+      --observerCount;
 
+      if (observerCount === 0) {
         Services.obs.removeObserver(this, MOZSETTINGS_CHANGED);
         next();
       }
+    }
 
     Services.obs.addObserver(observer, MOZSETTINGS_CHANGED, false);
 
     let lock = SettingsService.createLock();
-    lock.set(TEST_OBSERVER_KEY, TEST_OBSERVER_VALUE, null);
+    lock.set(TEST_OBSERVER_KEY, TEST_OBSERVER_VALUE, null, null);
+    lock.set(TEST_OBSERVER_KEY, TEST_OBSERVER_VALUE, null, TEST_OBSERVER_MESSAGE);
   }
 ];
 
 function next() {
   let step = tests.shift();
   if (step) {
     try {
       step();
--- a/dom/system/gonk/tests/marionette/head.js
+++ b/dom/system/gonk/tests/marionette/head.js
@@ -88,30 +88,23 @@ function getSettings(aKey, aAllowError) 
  *        A boolean value.  If set to true, an error response won't be treated
  *        as test failure.  Default: false.
  *
  * @return A deferred promise.
  */
 function setSettings(aKey, aValue, aAllowError) {
   let settings = {};
   settings[aKey] = aValue;
-  let lock = window.navigator.mozSettings.createLock();
-  let request = lock.set(settings);
-  let deferred = Promise.defer();
-  lock.onsettingstransactionsuccess = function () {
+  let request = window.navigator.mozSettings.createLock().set(settings);
+  return wrapDomRequestAsPromise(request)
+    .then(function resolve() {
       log("setSettings(" + JSON.stringify(settings) + ") - success");
-    deferred.resolve();
-  };
-  lock.onsettingstransactionfailure = function () {
+    }, function reject() {
       ok(aAllowError, "setSettings(" + JSON.stringify(settings) + ") - error");
-    // We resolve even though we've thrown an error, since the ok()
-    // will do that.
-    deferred.resolve();
-  };
-  return deferred.promise;
+    });
 }
 
 /**
  * Wait for observer event.
  *
  * Resolve if that topic event occurs.  Never reject.
  *
  * Fulfill params: the subject passed.
--- a/dom/tests/mochitest/general/test_interfaces.html
+++ b/dom/tests/mochitest/general/test_interfaces.html
@@ -696,18 +696,16 @@ var interfaceNamesInGlobalScope =
     {name: "mozRTCIceCandidate", pref: "media.peerconnection.enabled"},
 // IMPORTANT: Do not change this list without review from a DOM peer!
     {name: "mozRTCPeerConnection", pref: "media.peerconnection.enabled"},
 // IMPORTANT: Do not change this list without review from a DOM peer!
     {name: "mozRTCSessionDescription", pref: "media.peerconnection.enabled"},
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "MozSettingsEvent",
 // IMPORTANT: Do not change this list without review from a DOM peer!
-    {name: "MozSettingsTransactionEvent", permission: "settings-api-read"},
-// IMPORTANT: Do not change this list without review from a DOM peer!
     "MozSmsEvent",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "MozSmsMessage",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     {name: "MozSpeakerManager", b2g: true},
 // IMPORTANT: Do not change this list without review from a DOM peer!
     {name: "MozStkCommandEvent", b2g: true, pref: "dom.icc.enabled"},
 // IMPORTANT: Do not change this list without review from a DOM peer!
--- a/dom/tests/mochitest/geolocation/test_mozsettings.html
+++ b/dom/tests/mochitest/geolocation/test_mozsettings.html
@@ -21,26 +21,22 @@ https://bugzilla.mozilla.org/show_bug.cg
 
 SimpleTest.waitForExplicitFinish();
 
 resume_geolocationProvider(function() {
   force_prompt(true, test1);
 });
 
 if (SpecialPowers.isMainProcess()) {
-  SpecialPowers.Cu.import("resource://gre/modules/SettingsRequestManager.jsm");
+  SpecialPowers.Cu.import("resource://gre/modules/SettingsChangeNotifier.jsm");
 }
 
 function test1() {
   //This pushPermissions call is after pushPrefEnv call and pushPrefEnv calls follow after this
-  SpecialPowers.pushPermissions([{'type': 'settings-read', 'allow': true, 'context': document},
-                                 {'type': 'settings-write', 'allow': true, 'context': document},
-                                 {'type': 'settings-api-write', 'allow': true, 'context': document},
-                                 {'type': 'settings-api-read', 'allow': true, 'context': document}
-  ], test2);
+  SpecialPowers.pushPermissions([{'type': 'settings-read', 'allow': true, 'context': document}, {'type': 'settings-write', 'allow': true, 'context': document}], test2);
 }
 
 function test2() {
   ok(navigator.geolocation, "get geolocation object");
 
   toggleGeolocationSetting(false, function() {
       ok(true, "turned off geolocation via mozSettings");
       setTimeout(function() {
--- a/dom/tests/mochitest/geolocation/test_mozsettingsWatch.html
+++ b/dom/tests/mochitest/geolocation/test_mozsettingsWatch.html
@@ -21,26 +21,22 @@ https://bugzilla.mozilla.org/show_bug.cg
 
 SimpleTest.waitForExplicitFinish();
 
 resume_geolocationProvider(function() {
   force_prompt(true, test1);
 });
 
 if (SpecialPowers.isMainProcess()) {
-  SpecialPowers.Cu.import("resource://gre/modules/SettingsRequestManager.jsm");
+  SpecialPowers.Cu.import("resource://gre/modules/SettingsChangeNotifier.jsm");
 }
 
 function test1() {
   //This pushPermissions call is after pushPrefEnv call and pushPrefEnv calls follow after this
-  SpecialPowers.pushPermissions([{'type': 'settings-read', 'allow': true, 'context': document},
-                                 {'type': 'settings-write', 'allow': true, 'context': document},
-                                 {'type': 'settings-api-write', 'allow': true, 'context': document},
-                                 {'type': 'settings-api-read', 'allow': true, 'context': document}
-  ], test2);
+  SpecialPowers.pushPermissions([{'type': 'settings-read', 'allow': true, 'context': document}, {'type': 'settings-write', 'allow': true, 'context': document}], test2);
 }
 
 var watchId;
 function test2() {
   ok(navigator.geolocation, "get geolocation object");
 
   toggleGeolocationSetting(false, function() {
       ok(true, "turned off geolocation via mozSettings");
--- a/dom/tethering/tests/marionette/head.js
+++ b/dom/tethering/tests/marionette/head.js
@@ -150,29 +150,25 @@ let gTestSuite = (function() {
    * Fulfill params: (none)
    * Reject params: (none)
    *
    * @param aSettings
    *        An object of format |{key1: value1, key2: value2, ...}|.
    * @return A deferred promise.
    */
   function setSettings(aSettings) {
-    let lock = window.navigator.mozSettings.createLock();
-    let request = lock.set(aSettings);
-    let deferred = Promise.defer();
-    lock.onsettingstransactionsuccess = function () {
+    let request = navigator.mozSettings.createLock().set(aSettings);
+
+    return wrapDomRequestAsPromise(request)
+      .then(function resolve() {
         ok(true, "setSettings(" + JSON.stringify(aSettings) + ")");
-      deferred.resolve();
-    };
-    lock.onsettingstransactionfailure = function (aEvent) {
+      }, function reject(aEvent) {
         ok(false, "setSettings(" + JSON.stringify(aSettings) + ")");
-      deferred.reject();
         throw aEvent.target.error;
-    };
-    return deferred.promise;
+      });
   }
 
   /**
    * Set mozSettings value with only one key.
    *
    * Resolve if that mozSettings value is set successfully, reject otherwise.
    *
    * Fulfill params: (none)
@@ -537,18 +533,16 @@ let gTestSuite = (function() {
    * @return A deferred promise.
    */
   function acquirePermission() {
     let deferred = Promise.defer();
 
     let permissions = [{ 'type': 'wifi-manage', 'allow': 1, 'context': window.document },
                        { 'type': 'settings-write', 'allow': 1, 'context': window.document },
                        { 'type': 'settings-read', 'allow': 1, 'context': window.document },
-                       { 'type': 'settings-api-write', 'allow': 1, 'context': window.document },
-                       { 'type': 'settings-api-read', 'allow': 1, 'context': window.document },
                        { 'type': 'mobileconnection', 'allow': 1, 'context': window.document }];
 
     SpecialPowers.pushPermissions(permissions, function() {
       deferred.resolve();
     });
 
     return deferred.promise;
   }
--- a/dom/tethering/tests/marionette/manifest.ini
+++ b/dom/tethering/tests/marionette/manifest.ini
@@ -1,7 +1,6 @@
 [DEFAULT]
 b2g = true
 browser = false
 qemu = true
 
 [test_wifi_tethering_enabled.js]
-disabled = https://bugzilla.mozilla.org/show_bug.cgi?id=1058158
deleted file mode 100644
--- a/dom/webidl/MozSettingsTransactionEvent.webidl
+++ /dev/null
@@ -1,17 +0,0 @@
-/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this file,
- * You can obtain one at http://mozilla.org/MPL/2.0/.
- */
-
-[Constructor(DOMString type, optional MozSettingsTransactionEventInit eventInitDict),
- CheckPermissions="settings-api-read settings-api-write"]
-interface MozSettingsTransactionEvent : Event
-{
-  readonly attribute DOMString? error;
-};
-
-dictionary MozSettingsTransactionEventInit : EventInit
-{
-  DOMString error = "";
-};
--- a/dom/webidl/SettingsManager.webidl
+++ b/dom/webidl/SettingsManager.webidl
@@ -1,29 +1,27 @@
 /* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/.
  */
 
 [JSImplementation="@mozilla.org/settingsLock;1",
  Pref="dom.mozSettings.enabled"]
-interface SettingsLock : EventTarget {
+interface SettingsLock {
   // Whether this lock is invalid
   readonly attribute boolean closed;
 
   // Contains a JSON object with name/value pairs to be set.
   DOMRequest set(object settings);
 
   // Result contains the value of the setting.
   DOMRequest get(DOMString name);
 
   DOMRequest clear();
-  attribute EventHandler onsettingstransactionsuccess;
-  attribute EventHandler onsettingstransactionfailure;
 };
 
 dictionary SettingChange {
   DOMString settingName;
   DOMString settingValue;
 };
 
 callback SettingChangeCallback = void (SettingChange setting);
--- a/dom/webidl/moz.build
+++ b/dom/webidl/moz.build
@@ -658,17 +658,16 @@ GENERATED_EVENTS_WEBIDL_FILES = [
     'MozClirModeEvent.webidl',
     'MozContactChangeEvent.webidl',
     'MozEmergencyCbModeEvent.webidl',
     'MozInterAppMessageEvent.webidl',
     'MozMessageDeletedEvent.webidl',
     'MozMmsEvent.webidl',
     'MozOtaStatusEvent.webidl',
     'MozSettingsEvent.webidl',
-    'MozSettingsTransactionEvent.webidl',
     'MozSmsEvent.webidl',
     'MozStkCommandEvent.webidl',
     'PageTransitionEvent.webidl',
     'PopStateEvent.webidl',
     'PopupBlockedEvent.webidl',
     'ProgressEvent.webidl',
     'RecordErrorEvent.webidl',
     'RTCDataChannelEvent.webidl',
--- a/dom/wifi/test/marionette/head.js
+++ b/dom/wifi/test/marionette/head.js
@@ -204,18 +204,16 @@ let gTestSuite = (function() {
    * @return A deferred promise.
    */
   function addRequiredPermissions() {
     let deferred = Promise.defer();
 
     let permissions = [{ 'type': 'wifi-manage', 'allow': 1, 'context': window.document },
                        { 'type': 'settings-write', 'allow': 1, 'context': window.document },
                        { 'type': 'settings-read', 'allow': 1, 'context': window.document },
-                       { 'type': 'settings-api-write', 'allow': 1, 'context': window.document },
-                       { 'type': 'settings-api-read', 'allow': 1, 'context': window.document },
                        { 'type': 'mobileconnection', 'allow': 1, 'context': window.document }];
 
     SpecialPowers.pushPermissions(permissions, function() {
       deferred.resolve();
     });
 
     return deferred.promise;
   }
@@ -579,30 +577,24 @@ let gTestSuite = (function() {
    * @param aSettings
    *        An object of format |{key1: value1, key2: value2, ...}|.
    * @param aAllowError [optional]
    *        A boolean value.  If set to true, an error response won't be treated
    *        as test failure.  Default: false.
    *
    * @return A deferred promise.
    */
-  function setSettings(aSettings) {
-    let lock = window.navigator.mozSettings.createLock();
-    let request = lock.set(aSettings);
-    let deferred = Promise.defer();
-    lock.onsettingstransactionsuccess = function () {
+  function setSettings(aSettings, aAllowError) {
+    let request = window.navigator.mozSettings.createLock().set(aSettings);
+    return wrapDomRequestAsPromise(request)
+      .then(function resolve() {
         ok(true, "setSettings(" + JSON.stringify(aSettings) + ")");
-      deferred.resolve();
-    };
-    lock.onsettingstransactionfailure = function (aEvent) {
-      ok(false, "setSettings(" + JSON.stringify(aSettings) + ")");
-      deferred.reject();
-      throw aEvent.target.error;
-    };
-    return deferred.promise;
+      }, function reject() {
+        ok(aAllowError, "setSettings(" + JSON.stringify(aSettings) + ")");
+      });
   }
 
   /**
    * Set mozSettings value with only one key.
    *
    * Resolve if that mozSettings value is set successfully, reject otherwise.
    *
    * Fulfill params: (none)
--- a/testing/mozbase/mozrunner/mozrunner/devices/emulator.py
+++ b/testing/mozbase/mozrunner/mozrunner/devices/emulator.py
@@ -203,21 +203,21 @@ waitFor(
     def wait_for_homescreen(self, marionette):
         print 'waiting for homescreen...'
 
         marionette.set_context(marionette.CONTEXT_CONTENT)
         marionette.execute_async_script("""
 log('waiting for mozbrowserloadend');
 window.addEventListener('mozbrowserloadend', function loaded(aEvent) {
   log('received mozbrowserloadend for ' + aEvent.target.src);
-  if (aEvent.target.src.indexOf('ftu') != -1 || aEvent.target.src.indexOf('homescreen') != -1 || aEvent.target.src.indexOf('verticalhome') != -1) {
+  if (aEvent.target.src.indexOf('ftu') != -1 || aEvent.target.src.indexOf('homescreen') != -1) {
     window.removeEventListener('mozbrowserloadend', loaded);
     marionetteScriptFinished();
   }
-});""", script_timeout=300000)
+});""", script_timeout=120000)
         print '...done'
 
     def _get_telnet_response(self, command=None):
         output = []
         assert(self.telnet)
         if command is not None:
             self.telnet.write('%s\n' % command)
         while True: