Merge m-i to b-s.
authorMs2ger <ms2ger@gmail.com>
Thu, 28 Feb 2013 14:46:10 +0100
changeset 133744 831a3b6a4e07ad2624e7685147efc1013d0c4290
parent 133667 614fb1e40f6cfb10344d5d0ea6e76032cf2db017 (current diff)
parent 133743 c787a6ba6a1ccbebd1375d903ca79a2b2a07523a (diff)
child 133745 c65d59d33aa86b7e75bc420ea3beda6201e0aceb
push id2452
push userlsblakk@mozilla.com
push dateMon, 13 May 2013 16:59:38 +0000
treeherdermozilla-beta@d4b152d29d8d [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone22.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge m-i to b-s.
browser/devtools/inspector/test/browser_inspector_bug_835722_infobar_reappears.js
dom/plugins/base/Makefile.in
dom/plugins/ipc/Makefile.in
ipc/Makefile.in
mobile/android/base/Makefile.in
mobile/android/base/background/BackgroundConstants.java
mobile/android/base/resources/layout/awesomebar_tab_indicator.xml
mobile/android/base/sync/GlobalConstants.java.in
mobile/android/base/sync/Logger.java
mobile/android/base/sync/jpake/JPakeRequest.java
mobile/android/base/sync/jpake/JPakeRequestDelegate.java
mobile/android/base/sync/jpake/JPakeResponse.java
mobile/android/base/sync/log/writers/AndroidLevelCachingLogWriter.java
mobile/android/base/sync/log/writers/AndroidLogWriter.java
mobile/android/base/sync/log/writers/LevelFilteringLogWriter.java
mobile/android/base/sync/log/writers/LogWriter.java
mobile/android/base/sync/log/writers/PrintLogWriter.java
mobile/android/base/sync/log/writers/SimpleTagLogWriter.java
mobile/android/base/sync/log/writers/StringLogWriter.java
mobile/android/base/sync/log/writers/TagLogWriter.java
mobile/android/base/sync/log/writers/ThreadLocalTagLogWriter.java
mobile/android/base/sync/net/SyncResourceDelegate.java
toolkit/components/places/Makefile.in
toolkit/components/places/nsILivemarkService.idl
toolkit/components/places/tests/bookmarks/test_livemarks.js
--- a/accessible/tests/mochitest/events/test_focus_dialog.html
+++ b/accessible/tests/mochitest/events/test_focus_dialog.html
@@ -16,16 +16,20 @@
   <script type="application/javascript"
           src="../events.js"></script>
   <script type="application/javascript"
           src="../role.js"></script>
   <script type="application/javascript"
           src="../states.js"></script>
 
   <script type="application/javascript">
+    if (!navigator.platform.startsWith("Linux")) {
+      SimpleTest.expectAssertions(0, 1);
+    }
+
     function openCloseDialog(aID)
     {
       this.eventSeq = [
         new focusChecker(getNode(aID))
       ];
 
       this.invoke = function openCloseDialog_invoke()
       {
--- a/accessible/tests/mochitest/events/test_focus_general.xul
+++ b/accessible/tests/mochitest/events/test_focus_general.xul
@@ -16,16 +16,19 @@
   <script type="application/javascript"
           src="../role.js" />
   <script type="application/javascript"
           src="../states.js" />
   <script type="application/javascript"
           src="../events.js" />
 
   <script type="application/javascript">
+
+    SimpleTest.expectAssertions(0, 1);
+
     function getColorBtn(aBtnObj)
     {
       var colorpicker = aBtnObj.colorpicker;
       var container = colorpicker.firstChild;
       var btn = container.getChildAt(aBtnObj.btnIndex);
       return btn;
     }
 
--- a/accessible/tests/mochitest/focus/test_focusedChild.html
+++ b/accessible/tests/mochitest/focus/test_focusedChild.html
@@ -47,17 +47,17 @@
       }
 
       function getDialogAccessible(aInvoker)
       {
         return getAccessible(aInvoker.dialog.document);
       }
     }
 
-    //gA11yEventDumpToConsole = true;
+    gA11yEventDumpToConsole = true;
     var gQueue = null;
 
     function doTest()
     {
       gQueue = new eventQueue();
 
       gQueue.push(new openWnd());
 
--- a/accessible/tests/mochitest/states/test_frames.html
+++ b/accessible/tests/mochitest/states/test_frames.html
@@ -12,16 +12,20 @@
   <script type="application/javascript"
           src="../common.js"></script>
   <script type="application/javascript"
           src="../role.js"></script>
   <script type="application/javascript"
           src="../states.js"></script>
 
   <script type="application/javascript">
+    if (navigator.platform.startsWith("Win")) {
+      SimpleTest.expectAssertions(0, 2);
+    }
+
     function doTest()
     {
       frameDoc = document.getElementById("frame_doc").contentDocument;
       frameDocArticle = document.getElementById("frame_doc_article").contentDocument;
       frameDocCheckbox = document.getElementById("frame_doc_checkbox").contentDocument;
       frameDocTextbox = document.getElementById("frame_doc_textbox").contentDocument;
 
       testStates(frameDoc, STATE_READONLY, 0, 0, 0,
--- a/accessible/tests/mochitest/states/test_tree.xul
+++ b/accessible/tests/mochitest/states/test_tree.xul
@@ -87,22 +87,18 @@
       gQueue = new eventQueue(EVENT_REORDER);
       gQueue.push(new statesChecker("tree", new nsTreeTreeView()));
       gQueue.push(new statesChecker("treesingle", new nsTreeTreeView()));
       gQueue.push(new statesChecker("tabletree", new nsTreeTreeView()));
 
       gQueue.invoke(); // Will call SimpleTest.finish();
     }
 
-    if (!MAC) {
-      SimpleTest.waitForExplicitFinish();
-      addA11yLoadEvent(doTest);
-    } else {
-      todo(false, "Re-enable on Mac after fixing bug 845095 - intermittent orange");
-    }
+    SimpleTest.waitForExplicitFinish();
+    addA11yLoadEvent(doTest);
   ]]>
   </script>
 
   <hbox flex="1" style="overflow: auto;">
     <body xmlns="http://www.w3.org/1999/xhtml">
       <a target="_blank"
          href="https://bugzilla.mozilla.org/show_bug.cgi?id=503727"
          title="Reorganize implementation of XUL tree accessibility">
--- a/accessible/tests/mochitest/tree/test_dockids.html
+++ b/accessible/tests/mochitest/tree/test_dockids.html
@@ -11,19 +11,17 @@
   <script type="application/javascript"
           src="../common.js"></script>
   <script type="application/javascript"
           src="../role.js"></script>
   <script type="application/javascript"
           src="../states.js"></script>
 
   <script type="application/javascript">
-  if (navigator.platform.startsWith("Win")) {
-    SimpleTest.expectAssertions(0, 1);
-  }
+  SimpleTest.expectAssertions(0, 1);
 
   function doTest()
   {
     var tree =
      { DOCUMENT: [
        { PARAGRAPH: [ // head
          { PARAGRAPH: [ // link
            { STATICTEXT: [] }, // generated content
--- a/b2g/app/b2g.js
+++ b/b2g/app/b2g.js
@@ -546,27 +546,27 @@ pref("ui.showHideScrollbars", 1);
 // background.
 pref("dom.ipc.processPriorityManager.enabled", true);
 pref("dom.ipc.processPriorityManager.backgroundGracePeriodMS", 1000);
 pref("dom.ipc.processPriorityManager.temporaryPriorityLockMS", 5000);
 
 // Kernel parameters for how processes are killed on low-memory.
 pref("gonk.systemMemoryPressureRecoveryPollMS", 5000);
 pref("hal.processPriorityManager.gonk.masterOomScoreAdjust", 0);
-pref("hal.processPriorityManager.gonk.masterKillUnderMB", 1);
+pref("hal.processPriorityManager.gonk.masterKillUnderMB", 4);
 pref("hal.processPriorityManager.gonk.foregroundHighOomScoreAdjust", 67);
-pref("hal.processPriorityManager.gonk.foregroundHighKillUnderMB", 3);
+pref("hal.processPriorityManager.gonk.foregroundHighKillUnderMB", 5);
 pref("hal.processPriorityManager.gonk.foregroundOomScoreAdjust", 134);
-pref("hal.processPriorityManager.gonk.foregroundKillUnderMB", 4);
+pref("hal.processPriorityManager.gonk.foregroundKillUnderMB", 6);
 pref("hal.processPriorityManager.gonk.backgroundPerceivableOomScoreAdjust", 200);
-pref("hal.processPriorityManager.gonk.backgroundPerceivableKillUnderMB", 5);
+pref("hal.processPriorityManager.gonk.backgroundPerceivableKillUnderMB", 7);
 pref("hal.processPriorityManager.gonk.backgroundHomescreenOomScoreAdjust", 267);
-pref("hal.processPriorityManager.gonk.backgroundHomescreenKillUnderMB", 5);
+pref("hal.processPriorityManager.gonk.backgroundHomescreenKillUnderMB", 8);
 pref("hal.processPriorityManager.gonk.backgroundOomScoreAdjust", 400);
-pref("hal.processPriorityManager.gonk.backgroundKillUnderMB", 8);
+pref("hal.processPriorityManager.gonk.backgroundKillUnderMB", 20);
 pref("hal.processPriorityManager.gonk.notifyLowMemUnderMB", 10);
 
 // Niceness values (i.e., CPU priorities) for B2G processes.
 pref("hal.processPriorityManager.gonk.masterNice", 0);
 pref("hal.processPriorityManager.gonk.foregroundHighNice", 0);
 pref("hal.processPriorityManager.gonk.foregroundNice", 1);
 pref("hal.processPriorityManager.gonk.backgroundPerceivableNice", 10);
 pref("hal.processPriorityManager.gonk.backgroundHomescreenNice", 20);
--- a/browser/app/profile/firefox.js
+++ b/browser/app/profile/firefox.js
@@ -1195,15 +1195,15 @@ pref("pdfjs.previousHandler.preferredAct
 pref("pdfjs.previousHandler.alwaysAskBeforeHandling", false);
 
 // The maximum amount of decoded image data we'll willingly keep around (we
 // might keep around more than this, but we'll try to get down to this value).
 // (This is intentionally on the high side; see bug 746055.)
 pref("image.mem.max_decoded_image_kb", 256000);
 
 // Default social providers
-pref("social.manifest.facebook", "{\"origin\":\"https://www.facebook.com\",\"name\":\"Facebook Messenger\",\"workerURL\":\"https://www.facebook.com/desktop/fbdesktop2/socialfox/fbworker.js.php\",\"iconURL\":\"data:image/x-icon;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8%2F9hAAAAX0lEQVQ4jWP4%2F%2F8%2FAyUYTFhHzjgDxP9JxGeQDSBVMxgTbUBCxer%2Fr999%2BQ8DJBuArJksA9A10s8AXIBoA0B%2BR%2FY%2FjD%2BEwoBoA1yT5v3PbdmCE8MAshhID%2FUMoDgzUYIBj0Cgi7ar4coAAAAASUVORK5CYII%3D\",\"sidebarURL\":\"https://www.facebook.com/desktop/fbdesktop2/?socialfox=true\",\"icon32URL\":\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAACXBIWXMAAAsTAAALEwEAmpwYAAADbklEQVRYCc1Xv08UQRj99tctexAuCEFjRE0kGBEtLDSGqIWNxkYKbTAxNlY2JhaGWltNtNFeKgsKKxITK43/gCYW+IsoRhA4D47bH7fn9+bcvdm5JR7sefolC3Ozu9978+bNN7PayUv3HN3umdY0Y6IWBtSJ0HSTarXqTOiuTep6Lj+tdxAcA8RAgSmwdd2aCDs0clldYALb/FvgYVhjmfliVA2XpjEgWo0Attn42Z6WH1RFor5ehwo9XQIUZMoVn4qlCoVMSo62EvD8Kh0b3U2Xz43R2PBO6mUCGDlAf65V6MadZzT/rUimoccc2kYA4BfPHqJb105RzjJigKhRq9kEJUBIjgYVuXeL7SAI6eD+Abp5dTwVHOmEHxT50d8WBYJqSOdPj5BjW8gZR8UNqFR2xagx/65XFYaMH+BGWwiYpi4UkBPPLxTp9v1Z+lHc4DWvCQXWmIy6EjITgKowVd5Jjv7N3Hd6y5esigoOwpkJIAmMpZpLJGdiaaC4F0UmAj6bD84GCEwmB/qxMmRilmnwb/mpjAocHh4UEoNAt5NLZB7oy9OJo0PxqkAtePdhiSqunyC1LQUwWMPQaOr6GRre258Ajn4cP7KHcEXhsxpXbj+lT19X2TMNGTLVAcjcalS8gDwsQ2UOMhH4k8FkcrEn5E5ub2sKohxLK2VR77Hl9RUcsrgeRIEiVOT6z+tDbIeLy+vk+kGTCbXxycet6xhl//3f6bJEkdHYhA+mLtDIvoH4ieev5+juoxdk5+pjhALYEdXIpEB5w+NlSKSzqVQ/+H7IO6BLtl3fngGMiqhGJgIwlM6qpyUGFjySdk8m0Zg0ubeD7X9OIDEFajltRQgUJaUKx69tdgaQa0FMADuahZPMFtcEwNPm2hA7ZI5sK4aoE2NvYI+o8hkCIe7CwTv68zS0q9Dk5vpbm/8FXxitSzmMFHpsGj0wyLUheTwD2Y9fVgh1Ae0EPUgD9241ZEnld+v5kgnVZ/8fE0brVh5BK+1oCqKKF72Dk7HwBsssB/pklU1dfChy3S659H5+uelgIb+8WRv1/uGTV9Sdb5wJFlfW6fPCalMhwhSU1j2xKwKbP838GcOwJja4TqO0bjdmXxYTy1EYjFdCWoCEYZhseH/GDL3yJPHnuW6YmT7P1SlIA4768Hke4vOcsX8BE346lLHhDUQAAAAASUVORK5CYII=\", \"icon64URL\":\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAadEVYdFNvZnR3YXJlAFBhaW50Lk5FVCB2My41LjEwMPRyoQAACNNJREFUeNrtm3tw1NUVxz/399hHHkgCaCBGEFEEREVFYFQcSoOKdkZay4z+4dDpYIsjHWx1WoTMhFi1gzBSpVgVGbU4U1sHfPESKODwEEnRYDFAICEIeZIQshs2u/v73ds/drMsyW7YLEkl2Z6Z32yy+9v7u+fc7znne8+5KzgvAjDunzlv0M13PjDZ6c4cARj0WhEoaZ1tOn3yq9XLf/tNU0O1D5Ad7wq/OpxpaXOL1j5uZAwuaGlVgwNBhULRm0XXBG6HZrlNa9uRrzfM+3DlgjIgGMsA7rl/XDdHOnNf9vosTfVuvTsaQhdkZ4iykh2rHtqydvkxwI58BhjTfv7MmP55E9/1nLNdfU15ACkVvoAaMCRvRPa+re9+DgTaPjMAx+DrJv3M67Mz+6LybWLb4NfTHhxzx31DDhZvOtqGAgNwWbjGICV9XQJB0e/KobcOP1i8qTzaAEYgaDtNU/V5A9hSaUFLuQEt2gVQSgml+j4CUAIppYgK/m0GkCjZ9xGAUNAu0LUhgJRAAAIVzwBSqVRQH4hlAClRKZAFhOgEASoFECBR8QwgUyQGdJT/B8HzCEiBNKhUJzEgBYIgQsTJAkohe9oFZHgHKvQoHtZ9K3tewfiixXABLdoFeuSSEmkF+PH4QTz7+M3o+ENptzvGtS36uSwmjMpAYF10XCllHCYoe84FlLS555Zs5jx6J6ahY+iCl98pJiDNS1hwSZop+cm91zJmxEBefGsPlu1AxKC67V3gf5oGlZSMuz6Dp2fdhWnoAEwaN5T5hsYLb+4hKB1dcgelFDpB8ifk8thDt3DO5+fZxRvxBV0IjQR0EB3KfD1GhJS0GZnnYuGcKTgdF9ZWx4/No/BJjUUrdtJqm4iL+K5SCmSAiWMHMevhcQzNzaa6ron5SzfQ7HeiaSKx+au4m6HupcJKSYZdZVI4dypuV2yo3zoql0VP3cOiFV/Q4jdiGkGhQFqMGpbJL346kbE3DEYIQWNTC39Ysp4Gr4HQtZDyiRhA0NlmSHZbRM7pr1H0m6lckeHqdGXG3jCYoqfupeC17bT49fNRXIFSNrkDTGbNGM9dtw1D10M1DI/Xx3NLP6OqETRdDy1eglPT4rqA7K56gCIrXfHCvHwGZqUnBMtR113FS/N+xHPLtuJpDa1mVobg0emjmX7vqEjsUErhaw1Q8Mo6yk4F0A1HeOW7kIlFx/u7jworRabLpmhuPjmD+iG7YNDrrhnIS09P5cW/buOeO67lkftvJt3tDE06PE7Qsnh++QYOHPOim86wcVUS0+whJug0ghTMmcK1V2eH8m2UHP++nrwhAyIwjiXDcrN5vXAGhqGhFBeMYUvJ0re2sPfgGTTDGUZrEogVopMgmGQWUCgMEWTBE5MZPSLngnGqas/w9j92s31fJfmThvPM7HyMMKRj+qgmOiBHSsnr73/B5r1V6A53KD4k3bFS8dNgckFQoWPxu1kTGDc6N7JqzR4ff/+smE+2H8FSLkx3FluLawhaG3n2iXwcppGoV/Hemt18tK0c3UwLIfUS2nVafBeQJNUXkAF+/dht3H37cKSUBC2bTTv+w98++YazPg1dT0NoIUhruoMd+2sJrtjI7381rQM3iCVrN33N++tL0c30xFNdp0GQeFRYQhcRIO0gv5xxE/fdfSO2bfNVSTmrPtxLZW0A3XSh6VporaLG1XQHu0pOU/TaOhY8+QAuZ3w6vHnnQd74536EkZ50wOsSE0zcugolbWZOG8GM/LGUVdSw6sM97D/UgGa60QxXzMJDZAq6yb7SJgr//CkLn5pOmsvR4Z5dxUdZ9t6XoKfFjNyXkqZjuoBUCpGgCyhp8eDdQ5k++UaWrdrMlr2VSFxoZlpE8YtNWGgGXx9ppnDZpxTMfTCS8gAOlJ5g8ds7kCItTIi6j6FqMVxAC2sV2RB1ekmLCTcNpH+myeyFH7BxT1Voopoe4RKJXQqhmxw45mXh0o/xeH0opThcXs2iv2wmoFyhAnbC4yX+3PgISMDShrA5XHGa3d9UITRniIeTfHASmsGhEz7mL/mI2TPv4sU3t+KzHAnu7JKpCosOkcSIICAB5hZE0OiRCM0Iwb0b6LPQdI5W+Zn/yucoYYayRk+16eK1xqRMDAHtA0r3lep0lNAjO8kfpCpMqpTF4xZEUqA7rIlOCiKpgADVWXc4FQwgEfHPB5AiByTixIDUCYJx+wJoqdIcJV5VOAWygEZcF7BToT2upFDKtuz2BrAtf8v3mju972cBJX2exso6ok6N64BhOtM11xXXPBz6v6340PcuO+DZfaJkzWqgqY3L64Bqaaz0ZV45Mkc308dG2kd97FLSaq4v317gazr5HeCLRoACFTxbfeBw+oDhWYYj4/rw+30H+rb/VMPxXQsbKnbuABqJOi4vogyRiRB5/XNvvz3zytFTDEf61eF9b0dCKTS36c4afymTsgLeQ9Ly13X/aYnzE1Uy6PV7679trNy1xe+tKwPqAH/0Vla0qw65gH7AFeG/Y3Uy9P45o0bm3PTIaplM6lTK9jWf/OBUyQcrpdXaTIyfsXQb9QcLaAn7vJd2vxY5XxBpo8pwDmgFGsLKx1oeh8OVmUUSLXUlrWZPzbdLag9v+BjUqfDzepKAyDDcZbznGHG+1NmqSKHpVlfbadJqLW+o2LHobNX+PUB1WPkfnHwYyTmX6lI7Lehr3F576NM/+T3V3wH17f2w1xkg2ggXuSvga6p8p+bgmpVKWpXAmVh+2AsNEKogdYYAJa0GT03J4obyf60HTgKe6PTTqw0QOpcQ3wXs4LlDZyq2FXrrS4uBmjDxuCw3G5eIgA46yeC5ho11pWsWW35PWTibBC4Xf+9eBLRPg0q2+s5UvHG6bMNqJYPHw7nXutxZYvIIiMoCSgbrPVX/fv7syS+3AKfC5MOmF4iRpP6RjrId8O5vrNhS1NpUWQLUholUr6muXEoatP3emrWNR9e/avk9R8P+HuxNypPkrk93pGdnK0VtXemaN6UdOHo55vdE5b/0NKx+K4AxtAAAAABJRU5ErkJggg==\"}");
+pref("social.manifest.facebook", "{\"origin\":\"https://www.facebook.com\",\"name\":\"Facebook Messenger\",\"workerURL\":\"https://www.facebook.com/desktop/fbdesktop2/socialfox/fbworker.js.php\",\"iconURL\":\"data:image/x-icon;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8%2F9hAAAAX0lEQVQ4jWP4%2F%2F8%2FAyUYTFhHzjgDxP9JxGeQDSBVMxgTbUBCxer%2Fr999%2BQ8DJBuArJksA9A10s8AXIBoA0B%2BR%2FY%2FjD%2BEwoBoA1yT5v3PbdmCE8MAshhID%2FUMoDgzUYIBj0Cgi7ar4coAAAAASUVORK5CYII%3D\",\"sidebarURL\":\"https://www.facebook.com/desktop/fbdesktop2/?socialfox=true\",\"icon32URL\":\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAACXBIWXMAAAsTAAALEwEAmpwYAAADbklEQVRYCc1Xv08UQRj99tctexAuCEFjRE0kGBEtLDSGqIWNxkYKbTAxNlY2JhaGWltNtNFeKgsKKxITK43/gCYW+IsoRhA4D47bH7fn9+bcvdm5JR7sefolC3Ozu9978+bNN7PayUv3HN3umdY0Y6IWBtSJ0HSTarXqTOiuTep6Lj+tdxAcA8RAgSmwdd2aCDs0clldYALb/FvgYVhjmfliVA2XpjEgWo0Attn42Z6WH1RFor5ehwo9XQIUZMoVn4qlCoVMSo62EvD8Kh0b3U2Xz43R2PBO6mUCGDlAf65V6MadZzT/rUimoccc2kYA4BfPHqJb105RzjJigKhRq9kEJUBIjgYVuXeL7SAI6eD+Abp5dTwVHOmEHxT50d8WBYJqSOdPj5BjW8gZR8UNqFR2xagx/65XFYaMH+BGWwiYpi4UkBPPLxTp9v1Z+lHc4DWvCQXWmIy6EjITgKowVd5Jjv7N3Hd6y5esigoOwpkJIAmMpZpLJGdiaaC4F0UmAj6bD84GCEwmB/qxMmRilmnwb/mpjAocHh4UEoNAt5NLZB7oy9OJo0PxqkAtePdhiSqunyC1LQUwWMPQaOr6GRre258Ajn4cP7KHcEXhsxpXbj+lT19X2TMNGTLVAcjcalS8gDwsQ2UOMhH4k8FkcrEn5E5ub2sKohxLK2VR77Hl9RUcsrgeRIEiVOT6z+tDbIeLy+vk+kGTCbXxycet6xhl//3f6bJEkdHYhA+mLtDIvoH4ieev5+juoxdk5+pjhALYEdXIpEB5w+NlSKSzqVQ/+H7IO6BLtl3fngGMiqhGJgIwlM6qpyUGFjySdk8m0Zg0ubeD7X9OIDEFajltRQgUJaUKx69tdgaQa0FMADuahZPMFtcEwNPm2hA7ZI5sK4aoE2NvYI+o8hkCIe7CwTv68zS0q9Dk5vpbm/8FXxitSzmMFHpsGj0wyLUheTwD2Y9fVgh1Ae0EPUgD9241ZEnld+v5kgnVZ/8fE0brVh5BK+1oCqKKF72Dk7HwBsssB/pklU1dfChy3S659H5+uelgIb+8WRv1/uGTV9Sdb5wJFlfW6fPCalMhwhSU1j2xKwKbP838GcOwJja4TqO0bjdmXxYTy1EYjFdCWoCEYZhseH/GDL3yJPHnuW6YmT7P1SlIA4768Hke4vOcsX8BE346lLHhDUQAAAAASUVORK5CYII=\", \"icon64URL\":\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAadEVYdFNvZnR3YXJlAFBhaW50Lk5FVCB2My41LjEwMPRyoQAACNNJREFUeNrtm3tw1NUVxz/399hHHkgCaCBGEFEEREVFYFQcSoOKdkZay4z+4dDpYIsjHWx1WoTMhFi1gzBSpVgVGbU4U1sHfPESKODwEEnRYDFAICEIeZIQshs2u/v73ds/drMsyW7YLEkl2Z6Z32yy+9v7u+fc7znne8+5KzgvAjDunzlv0M13PjDZ6c4cARj0WhEoaZ1tOn3yq9XLf/tNU0O1D5Ad7wq/OpxpaXOL1j5uZAwuaGlVgwNBhULRm0XXBG6HZrlNa9uRrzfM+3DlgjIgGMsA7rl/XDdHOnNf9vosTfVuvTsaQhdkZ4iykh2rHtqydvkxwI58BhjTfv7MmP55E9/1nLNdfU15ACkVvoAaMCRvRPa+re9+DgTaPjMAx+DrJv3M67Mz+6LybWLb4NfTHhxzx31DDhZvOtqGAgNwWbjGICV9XQJB0e/KobcOP1i8qTzaAEYgaDtNU/V5A9hSaUFLuQEt2gVQSgml+j4CUAIppYgK/m0GkCjZ9xGAUNAu0LUhgJRAAAIVzwBSqVRQH4hlAClRKZAFhOgEASoFECBR8QwgUyQGdJT/B8HzCEiBNKhUJzEgBYIgQsTJAkohe9oFZHgHKvQoHtZ9K3tewfiixXABLdoFeuSSEmkF+PH4QTz7+M3o+ENptzvGtS36uSwmjMpAYF10XCllHCYoe84FlLS555Zs5jx6J6ahY+iCl98pJiDNS1hwSZop+cm91zJmxEBefGsPlu1AxKC67V3gf5oGlZSMuz6Dp2fdhWnoAEwaN5T5hsYLb+4hKB1dcgelFDpB8ifk8thDt3DO5+fZxRvxBV0IjQR0EB3KfD1GhJS0GZnnYuGcKTgdF9ZWx4/No/BJjUUrdtJqm4iL+K5SCmSAiWMHMevhcQzNzaa6ron5SzfQ7HeiaSKx+au4m6HupcJKSYZdZVI4dypuV2yo3zoql0VP3cOiFV/Q4jdiGkGhQFqMGpbJL346kbE3DEYIQWNTC39Ysp4Gr4HQtZDyiRhA0NlmSHZbRM7pr1H0m6lckeHqdGXG3jCYoqfupeC17bT49fNRXIFSNrkDTGbNGM9dtw1D10M1DI/Xx3NLP6OqETRdDy1eglPT4rqA7K56gCIrXfHCvHwGZqUnBMtR113FS/N+xHPLtuJpDa1mVobg0emjmX7vqEjsUErhaw1Q8Mo6yk4F0A1HeOW7kIlFx/u7jworRabLpmhuPjmD+iG7YNDrrhnIS09P5cW/buOeO67lkftvJt3tDE06PE7Qsnh++QYOHPOim86wcVUS0+whJug0ghTMmcK1V2eH8m2UHP++nrwhAyIwjiXDcrN5vXAGhqGhFBeMYUvJ0re2sPfgGTTDGUZrEogVopMgmGQWUCgMEWTBE5MZPSLngnGqas/w9j92s31fJfmThvPM7HyMMKRj+qgmOiBHSsnr73/B5r1V6A53KD4k3bFS8dNgckFQoWPxu1kTGDc6N7JqzR4ff/+smE+2H8FSLkx3FluLawhaG3n2iXwcppGoV/Hemt18tK0c3UwLIfUS2nVafBeQJNUXkAF+/dht3H37cKSUBC2bTTv+w98++YazPg1dT0NoIUhruoMd+2sJrtjI7381rQM3iCVrN33N++tL0c30xFNdp0GQeFRYQhcRIO0gv5xxE/fdfSO2bfNVSTmrPtxLZW0A3XSh6VporaLG1XQHu0pOU/TaOhY8+QAuZ3w6vHnnQd74536EkZ50wOsSE0zcugolbWZOG8GM/LGUVdSw6sM97D/UgGa60QxXzMJDZAq6yb7SJgr//CkLn5pOmsvR4Z5dxUdZ9t6XoKfFjNyXkqZjuoBUCpGgCyhp8eDdQ5k++UaWrdrMlr2VSFxoZlpE8YtNWGgGXx9ppnDZpxTMfTCS8gAOlJ5g8ds7kCItTIi6j6FqMVxAC2sV2RB1ekmLCTcNpH+myeyFH7BxT1Voopoe4RKJXQqhmxw45mXh0o/xeH0opThcXs2iv2wmoFyhAnbC4yX+3PgISMDShrA5XHGa3d9UITRniIeTfHASmsGhEz7mL/mI2TPv4sU3t+KzHAnu7JKpCosOkcSIICAB5hZE0OiRCM0Iwb0b6LPQdI5W+Zn/yucoYYayRk+16eK1xqRMDAHtA0r3lep0lNAjO8kfpCpMqpTF4xZEUqA7rIlOCiKpgADVWXc4FQwgEfHPB5AiByTixIDUCYJx+wJoqdIcJV5VOAWygEZcF7BToT2upFDKtuz2BrAtf8v3mju972cBJX2exso6ok6N64BhOtM11xXXPBz6v6340PcuO+DZfaJkzWqgqY3L64Bqaaz0ZV45Mkc308dG2kd97FLSaq4v317gazr5HeCLRoACFTxbfeBw+oDhWYYj4/rw+30H+rb/VMPxXQsbKnbuABqJOi4vogyRiRB5/XNvvz3zytFTDEf61eF9b0dCKTS36c4afymTsgLeQ9Ly13X/aYnzE1Uy6PV7679trNy1xe+tKwPqAH/0Vla0qw65gH7AFeG/Y3Uy9P45o0bm3PTIaplM6lTK9jWf/OBUyQcrpdXaTIyfsXQb9QcLaAn7vJd2vxY5XxBpo8pwDmgFGsLKx1oeh8OVmUUSLXUlrWZPzbdLag9v+BjUqfDzepKAyDDcZbznGHG+1NmqSKHpVlfbadJqLW+o2LHobNX+PUB1WPkfnHwYyTmX6lI7Lehr3F576NM/+T3V3wH17f2w1xkg2ggXuSvga6p8p+bgmpVKWpXAmVh+2AsNEKogdYYAJa0GT03J4obyf60HTgKe6PTTqw0QOpcQ3wXs4LlDZyq2FXrrS4uBmjDxuCw3G5eIgA46yeC5ho11pWsWW35PWTibBC4Xf+9eBLRPg0q2+s5UvHG6bMNqJYPHw7nXutxZYvIIiMoCSgbrPVX/fv7syS+3AKfC5MOmF4iRpP6RjrId8O5vrNhS1NpUWQLUholUr6muXEoatP3emrWNR9e/avk9R8P+HuxNypPkrk93pGdnK0VtXemaN6UdOHo55vdE5b/0NKx+K4AxtAAAAABJRU5ErkJggg==\", \"description\":\"Keep up with friends wherever you go on the web.\",\"author\":\"Facebook\",\"homepageURL\":\"https://www.facebook.com/about/messenger-for-firefox\"}");
 
 pref("social.sidebar.open", true);
 pref("social.sidebar.unload_timeout_ms", 10000);
 pref("social.toast-notifications.enabled", true);
 
 pref("dom.identity.enabled", false);
--- a/browser/base/content/browser-menubar.inc
+++ b/browser/base/content/browser-menubar.inc
@@ -540,17 +540,18 @@
                             label="&social.chatBar.label;"
                             accesskey="&social.chatBar.accesskey;"
                             key="focusChatBar"
                             command="Social:FocusChat"
                             class="show-only-for-keyboard"/>
                   <menuseparator class="social-statusarea-separator"/>
                   <menuseparator class="social-provider-menu" hidden="true"/>
                   <menuitem class="social-toggle-menuitem" command="Social:Toggle"/>
-                  <menuitem class="social-remove-menuitem" command="Social:Remove"/>
+                  <menuitem class="social-addons-menuitem" command="Social:Addons"
+                            label="&social.addons.label;"/>
                 </menupopup>
               </menu>
 #ifdef MOZ_SERVICES_SYNC
               <!-- only one of sync-setup or sync-menu will be showing at once -->
               <menuitem id="sync-setup"
                         label="&syncSetup.label;"
                         accesskey="&syncSetup.accesskey;"
                         observes="sync-setup-state"
--- a/browser/base/content/browser-sets.inc
+++ b/browser/base/content/browser-sets.inc
@@ -109,17 +109,17 @@
     <command id="History:UndoCloseWindow" oncommand="undoCloseWindow();"/>
     <command id="Browser:ToggleAddonBar" oncommand="toggleAddonBar();"/>
     <command id="Social:SharePage" oncommand="SocialShareButton.sharePage();" disabled="true"/>
     <command id="Social:UnsharePage" oncommand="SocialShareButton.unsharePage();"/>
     <command id="Social:ToggleSidebar" oncommand="Social.toggleSidebar();"/>
     <command id="Social:ToggleNotifications" oncommand="Social.toggleNotifications();"/>
     <command id="Social:FocusChat" oncommand="SocialChatBar.focus();" hidden="true" disabled="true"/>
     <command id="Social:Toggle" oncommand="Social.toggle();" hidden="true"/>
-    <command id="Social:Remove" oncommand="SocialUI.disableWithConfirmation();"/>
+    <command id="Social:Addons" oncommand="BrowserOpenAddonsMgr('addons://list/service');"/>
   </commandset>
 
   <commandset id="placesCommands">
     <command id="Browser:ShowAllBookmarks"
              oncommand="PlacesCommandHook.showPlacesOrganizer('AllBookmarks');"/>
     <command id="Browser:ShowAllHistory"
              oncommand="PlacesCommandHook.showPlacesOrganizer('History');"/>
   </commandset>
--- a/browser/base/content/browser-social.js
+++ b/browser/base/content/browser-social.js
@@ -737,30 +737,23 @@ var SocialMenu = {
   }
 };
 
 // XXX Need to audit that this is being initialized correctly
 var SocialToolbar = {
   // Called once, after window load, when the Social.provider object is
   // initialized.
   init: function SocialToolbar_init() {
-    let accesskey = gNavigatorBundle.getString("social.removeProvider.accesskey");
-    let removeCommand = document.getElementById("Social:Remove");
-    removeCommand.setAttribute("accesskey", accesskey);
     this._dynamicResizer = new DynamicResizeWatcher();
   },
 
   // Called when the Social.provider changes
   updateProvider: function () {
     let provider = Social.provider || Social.defaultProvider;
     if (provider) {
-      let label = gNavigatorBundle.getFormattedString("social.removeProvider.label",
-                                                      [provider.name]);
-      let removeCommand = document.getElementById("Social:Remove");
-      removeCommand.setAttribute("label", label);
       this.button.setAttribute("label", provider.name);
       this.button.setAttribute("tooltiptext", provider.name);
       this.button.style.listStyleImage = "url(" + provider.iconURL + ")";
 
       this.updateProfile();
     }
     this.updateButton();
     this.populateProviderMenus();
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -5683,16 +5683,17 @@ function SelectDetector(event, doReload)
     }
     catch (ex) {
         dump("Failed to set the intl.charset.detector preference.\n");
     }
 }
 
 function BrowserSetForcedCharacterSet(aCharset)
 {
+  gBrowser.docShell.gatherCharsetMenuTelemetry();
   gBrowser.docShell.charset = aCharset;
   // Save the forced character-set
   if (!PrivateBrowsingUtils.isWindowPrivate(window))
     PlacesUtils.history.setCharsetForURI(getWebNavigation().currentURI, aCharset);
   BrowserCharsetReload();
 }
 
 function BrowserCharsetReload()
--- a/browser/base/content/browser.xul
+++ b/browser/base/content/browser.xul
@@ -710,17 +710,18 @@
                       type="checkbox"
                       autocheck="false"
                       command="Social:ToggleNotifications"
                       label="&social.toggleNotifications.label;"
                       accesskey="&social.toggleNotifications.accesskey;"/>
             <menuseparator class="social-statusarea-separator"/>
             <menuseparator class="social-provider-menu" hidden="true"/>
             <menuitem class="social-toggle-menuitem" command="Social:Toggle"/>
-            <menuitem class="social-remove-menuitem" command="Social:Remove"/>
+            <menuitem class="social-addons-menuitem" command="Social:Addons"
+                      label="&social.addons.label;"/>
           </menupopup>
         </toolbarbutton>
       </toolbaritem>
 
       <toolbaritem id="bookmarks-menu-button-container"
                    class="chromeclass-toolbar-additional"
                    removable="true"
                    title="&bookmarksMenuButton.label;">
--- a/browser/base/content/test/social/Makefile.in
+++ b/browser/base/content/test/social/Makefile.in
@@ -7,16 +7,20 @@ topsrcdir	= @top_srcdir@
 srcdir		= @srcdir@
 VPATH		= @srcdir@
 relativesrcdir  = @relativesrcdir@
 
 include $(DEPTH)/config/autoconf.mk
 
 _BROWSER_FILES = \
                  head.js \
+		 blocklist.xml \
+		 blocklistEmpty.xml \
+		 browser_blocklist.js \
+		 browser_addons.js \
                  browser_social_perwindowPB.js \
                  browser_social_toolbar.js \
                  browser_social_shareButton.js \
                  browser_social_sidebar.js \
                  browser_social_flyout.js \
                  browser_social_mozSocial_API.js \
                  browser_social_isVisible.js \
                  browser_social_chatwindow.js \
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/social/blocklist.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0"?>
+<blocklist xmlns="http://www.mozilla.org/2006/addons-blocklist">
+  <emItems>
+    <emItem  blockID="s1" id="bad.com@services.mozilla.org"></emItem>
+  </emItems>
+</blocklist>
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/social/blocklistEmpty.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0"?>
+<blocklist xmlns="http://www.mozilla.org/2006/addons-blocklist">
+  <emItems>
+    <emItem  blockID="s2" id="nothing@services.mozilla.org"></emItem>
+  </emItems>
+</blocklist>
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/social/browser_addons.js
@@ -0,0 +1,133 @@
+
+
+let AddonManager = Cu.import("resource://gre/modules/AddonManager.jsm", {}).AddonManager;
+let SocialService = Cu.import("resource://gre/modules/SocialService.jsm", {}).SocialService;
+
+const ADDON_TYPE_SERVICE     = "service";
+const ID_SUFFIX              = "@services.mozilla.org";
+const STRING_TYPE_NAME       = "type.%ID%.name";
+
+let manifest = { // normal provider
+  name: "provider 1",
+  origin: "https://example.com",
+  sidebarURL: "https://example.com/browser/browser/base/content/test/social/social_sidebar.html",
+  workerURL: "https://example.com/browser/browser/base/content/test/social/social_worker.js",
+  iconURL: "https://example.com/browser/browser/base/content/test/moz.png"
+};
+
+function test() {
+  waitForExplicitFinish();
+
+  Services.prefs.setCharPref("social.manifest.good", JSON.stringify(manifest));
+  runSocialTests(tests, undefined, undefined, function () {
+    Services.prefs.clearUserPref("social.manifest.good");
+    finish();
+  });
+}
+
+var tests = {
+  testInstalledProviders: function(next) {
+    // tests that our builtin manfests are actually available to the addon
+    // manager.  We may have interference from the real builtin providers, so
+    // we will expect our test provider above to be in the list
+    AddonManager.getAddonsByTypes([ADDON_TYPE_SERVICE], function(addons) {
+      for (let addon of addons) {
+        if (addon.manifest.origin == manifest.origin) {
+          ok(true, "test addon is installed");
+          next();
+          return;
+        }
+      }
+      // failure state
+      ok(false, "test addon is not installed");
+      next();
+    });
+  },
+  testAddonEnableToggle: function(next) {
+    // take the first addon in the list, and toggle its enabled state via the
+    // addon interface to see that we get events. restore the enabled state at
+    // the end.
+
+    let expectEvent;
+    let listener = {
+      onEnabled: function(addon) {
+        is(expectEvent, "onEnabled", "provider onEnabled");
+        ok(!addon.userDisabled, "provider enabled");
+        executeSoon(function() {
+          // restore previous state
+          expectEvent = "onDisabling";
+          addon.userDisabled = !addon.userDisabled;
+        });
+      },
+      onEnabling: function(addon) {
+        is(expectEvent, "onEnabling", "provider onEnabling");
+        expectEvent = "onEnabled";
+      },
+      onDisabled: function(addon) {
+        is(expectEvent, "onDisabled", "provider onDisabled");
+        ok(addon.userDisabled, "provider disabled");
+        executeSoon(function() {
+          // restore previous state
+          AddonManager.removeAddonListener(listener);
+          addon.userDisabled = !addon.userDisabled;
+          next();
+        });
+      },
+      onDisabling: function(addon) {
+        is(expectEvent, "onDisabling", "provider onDisabling");
+        expectEvent = "onDisabled";
+      }
+    };
+    AddonManager.addAddonListener(listener);
+
+    AddonManager.getAddonsByTypes([ADDON_TYPE_SERVICE], function(addons) {
+      for (let addon of addons) {
+        expectEvent = addon.userDisabled ? "onEnabling" : "onDisabling";
+        addon.userDisabled = !addon.userDisabled;
+        // only test with one addon
+        return;
+      }
+      ok(false, "no addons toggled");
+      next();
+    });
+  },
+  testProviderEnableToggle: function(next) {
+    // enable and disabel a provider from the SocialService interface, check
+    // that the addon manager is updated
+
+    let expectEvent;
+
+    let listener = {
+      onEnabled: function(addon) {
+        is(expectEvent, "onEnabled", "provider onEnabled");
+        is(addon.manifest.origin, manifest.origin, "provider enabled");
+        ok(!addon.userDisabled, "provider !userDisabled");
+      },
+      onEnabling: function(addon) {
+        is(expectEvent, "onEnabling", "provider onEnabling");
+        is(addon.manifest.origin, manifest.origin, "provider about to be enabled");
+        expectEvent = "onEnabled";
+      },
+      onDisabled: function(addon) {
+        is(expectEvent, "onDisabled", "provider onDisabled");
+        is(addon.manifest.origin, manifest.origin, "provider disabled");
+        ok(addon.userDisabled, "provider userDisabled");
+      },
+      onDisabling: function(addon) {
+        is(expectEvent, "onDisabling", "provider onDisabling");
+        is(addon.manifest.origin, manifest.origin, "provider about to be disabled");
+        expectEvent = "onDisabled";
+      }
+    };
+    AddonManager.addAddonListener(listener);
+
+    expectEvent = "onEnabling";
+    SocialService.addBuiltinProvider(manifest.origin, function(provider) {
+      expectEvent = "onDisabling";
+      SocialService.removeProvider(provider.origin, function() {
+        AddonManager.removeAddonListener(listener);
+        next();
+      });
+    });
+  }
+}
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/social/browser_blocklist.js
@@ -0,0 +1,124 @@
+/* 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/. */
+
+// a place for miscellaneous social tests
+
+let SocialService = Cu.import("resource://gre/modules/SocialService.jsm", {}).SocialService;
+
+const URI_EXTENSION_BLOCKLIST_DIALOG = "chrome://mozapps/content/extensions/blocklist.xul";
+let blocklistURL = "http://test:80/browser/browser/base/content/test/social/blocklist.xml";
+let blocklistEmpty = "http://test:80/browser/browser/base/content/test/social/blocklistEmpty.xml";
+
+let manifest = { // normal provider
+  name: "provider 1",
+  origin: "https://example.com",
+  sidebarURL: "https://example.com/browser/browser/base/content/test/social/social_sidebar.html",
+  workerURL: "https://example.com/browser/browser/base/content/test/social/social_worker.js",
+  iconURL: "https://example.com/browser/browser/base/content/test/moz.png"
+};
+let manifest_bad = { // normal provider
+  name: "provider 1",
+  origin: "https://bad.com",
+  sidebarURL: "https://bad.com/browser/browser/base/content/test/social/social_sidebar.html",
+  workerURL: "https://bad.com/browser/browser/base/content/test/social/social_worker.js",
+  iconURL: "https://bad.com/browser/browser/base/content/test/moz.png"
+};
+
+function test() {
+  waitForExplicitFinish();
+
+  runSocialTests(tests, undefined, undefined, function () {
+    resetBlocklist(); //restore to original pref
+    finish();
+  });
+}
+
+var tests = {
+  testSimpleBlocklist: function(next) {
+    // this really just tests adding and clearing our blocklist for later tests
+    var blocklist = Components.classes["@mozilla.org/extensions/blocklist;1"]
+                        .getService(Components.interfaces.nsIBlocklistService);
+    setAndUpdateBlocklist(blocklistURL, function() {
+      ok(blocklist.isAddonBlocklisted("bad.com@services.mozilla.org", "0", "0", "0"), "blocking 'blocked'");
+      ok(!blocklist.isAddonBlocklisted("good.cpm@services.mozilla.org", "0", "0", "0"), "not blocking 'good'");
+      setAndUpdateBlocklist(blocklistEmpty, function() {
+        ok(!blocklist.isAddonBlocklisted("bad.com@services.mozilla.org", "0", "0", "0"), "blocklist cleared");
+        next();
+      });
+    });
+  },
+  testAddingNonBlockedProvider: function(next) {
+    function finish(isgood) {
+      ok(isgood, "adding non-blocked provider ok");
+      Services.prefs.clearUserPref("social.manifest.good");
+      setAndUpdateBlocklist(blocklistEmpty, next);
+    }
+    Services.prefs.setCharPref("social.manifest.good", JSON.stringify(manifest));
+    setAndUpdateBlocklist(blocklistURL, function() {
+      try {
+        SocialService.addProvider(manifest, function(provider) {
+          if (provider) {
+            SocialService.removeProvider(provider.origin, function() {
+              ok(true, "added and removed provider");
+              finish(true);
+            });
+          } else {
+            finish(false);
+          }
+        });
+      } catch(e) {
+        dump(e+" - "+e.stack+"\n");
+        finish(false);
+      }
+    });
+  },
+  testAddingBlockedProvider: function(next) {
+    function finish(good) {
+      ok(good, "Unable to add blocklisted provider");
+      Services.prefs.clearUserPref("social.manifest.blocked");
+      setAndUpdateBlocklist(blocklistEmpty, next);
+    }
+    Services.prefs.setCharPref("social.manifest.blocked", JSON.stringify(manifest_bad));
+    setAndUpdateBlocklist(blocklistURL, function() {
+      try {
+        SocialService.addProvider(manifest_bad, function(provider) {
+          if (provider) {
+            SocialService.removeProvider(provider.origin, function() {
+              finish(false);
+            });
+          } else {
+            finish(true);
+          }
+        });
+      } catch(e) {
+        finish(true);
+      }
+    });
+  },
+  testBlockingExistingProvider: function(next) {
+
+    addWindowListener(URI_EXTENSION_BLOCKLIST_DIALOG,  function(win) {
+      win.close();
+      ok(true, "window closed");
+    });
+
+    function finish(good) {
+      ok(good, "blocklisted provider removed");
+      Services.prefs.clearUserPref("social.manifest.blocked");
+      setAndUpdateBlocklist(blocklistEmpty, next);
+    }
+    Services.prefs.setCharPref("social.manifest.blocked", JSON.stringify(manifest_bad));
+    SocialService.addProvider(manifest_bad, function(provider) {
+      if (provider) {
+        setAndUpdateBlocklist(blocklistURL, function() {
+          SocialService.getProvider(provider.origin, function(p) {
+            finish(p==null);
+          })
+        });
+      } else {
+        finish(false);
+      }
+    });
+  }
+}
--- a/browser/base/content/test/social/browser_social_toolbar.js
+++ b/browser/base/content/test/social/browser_social_toolbar.js
@@ -152,18 +152,16 @@ var tests = {
   },
   testMenuitemsExist: function(next) {
     let toggleSidebarMenuitems = document.getElementsByClassName("social-toggle-sidebar-menuitem");
     is(toggleSidebarMenuitems.length, 2, "Toggle Sidebar menuitems exist");
     let toggleDesktopNotificationsMenuitems = document.getElementsByClassName("social-toggle-notifications-menuitem");
     is(toggleDesktopNotificationsMenuitems.length, 2, "Toggle notifications menuitems exist");
     let toggleSocialMenuitems = document.getElementsByClassName("social-toggle-menuitem");
     is(toggleSocialMenuitems.length, 2, "Toggle Social menuitems exist");
-    let removeSocialMenuitems = document.getElementsByClassName("social-remove-menuitem");
-    is(removeSocialMenuitems.length, 2, "Remove Social menuitems exist");
     next();
   },
   testToggleNotifications: function(next) {
     let enabled = Services.prefs.getBoolPref("social.toast-notifications.enabled");
     let cmd = document.getElementById("Social:ToggleNotifications");
     is(cmd.getAttribute("checked"), enabled ? "true" : "false");
     enabled = !enabled;
     Services.prefs.setBoolPref("social.toast-notifications.enabled", enabled);
--- a/browser/base/content/test/social/head.js
+++ b/browser/base/content/test/social/head.js
@@ -182,18 +182,62 @@ function checkSocialUI(win) {
   isbool(win.SocialChatBar.isAvailable, enabled && Social.haveLoggedInUser(), "chatbar available?");
   isbool(!win.SocialChatBar.chatbar.hidden, enabled && Social.haveLoggedInUser(), "chatbar visible?");
   isbool(!win.SocialShareButton.shareButton.hidden, enabled && provider.recommendInfo, "share button visible?");
   isbool(!doc.getElementById("social-toolbar-item").hidden, enabled, "toolbar items visible?");
   if (enabled)
     is(win.SocialToolbar.button.style.listStyleImage, 'url("' + provider.iconURL + '")', "toolbar button has provider icon");
 
   // and for good measure, check all the social commands.
-  // Social:Remove - never disabled directly but parent nodes are
   isbool(!doc.getElementById("Social:Toggle").hidden, enabled, "Social:Toggle visible?");
   isbool(!doc.getElementById("Social:ToggleNotifications").hidden, enabled, "Social:ToggleNotifications visible?");
   isbool(!doc.getElementById("Social:FocusChat").hidden, enabled && Social.haveLoggedInUser(), "Social:FocusChat visible?");
   isbool(doc.getElementById("Social:FocusChat").getAttribute("disabled"), enabled ? "false" : "true", "Social:FocusChat disabled?");
   is(doc.getElementById("Social:SharePage").getAttribute("disabled"), enabled && provider.recommendInfo ? "false" : "true", "Social:SharePage visible?");
 
   // broadcasters.
   isbool(!doc.getElementById("socialActiveBroadcaster").hidden, enabled, "socialActiveBroadcaster hidden?");
 }
+
+// blocklist testing
+function updateBlocklist(aCallback) {
+  var blocklistNotifier = Cc["@mozilla.org/extensions/blocklist;1"]
+                          .getService(Ci.nsITimerCallback);
+  var observer = function() {
+    Services.obs.removeObserver(observer, "blocklist-updated");
+    if (aCallback)
+      executeSoon(aCallback);
+  };
+  Services.obs.addObserver(observer, "blocklist-updated", false);
+  blocklistNotifier.notify(null);
+}
+
+var _originalTestBlocklistURL = null;
+function setAndUpdateBlocklist(aURL, aCallback) {
+  if (!_originalTestBlocklistURL)
+    _originalTestBlocklistURL = Services.prefs.getCharPref("extensions.blocklist.url");
+  Services.prefs.setCharPref("extensions.blocklist.url", aURL);
+  updateBlocklist(aCallback);
+}
+
+function resetBlocklist() {
+  Services.prefs.setCharPref("extensions.blocklist.url", _originalTestBlocklistURL);
+}
+
+function addWindowListener(aURL, aCallback) {
+  Services.wm.addListener({
+    onOpenWindow: function(aXULWindow) {
+      info("window opened, waiting for focus");
+      Services.wm.removeListener(this);
+
+      var domwindow = aXULWindow.QueryInterface(Ci.nsIInterfaceRequestor)
+                                .getInterface(Ci.nsIDOMWindow);
+      waitForFocus(function() {
+        is(domwindow.document.location.href, aURL, "window opened and focused");
+        executeSoon(function() {
+          aCallback(domwindow);
+        });
+      }, domwindow);
+    },
+    onCloseWindow: function(aXULWindow) { },
+    onWindowTitleChange: function(aXULWindow, aNewTitle) { }
+  });
+}
--- a/browser/components/sessionstore/test/browser_248970_b_perwindowpb.js
+++ b/browser/components/sessionstore/test/browser_248970_b_perwindowpb.js
@@ -1,21 +1,15 @@
 /* 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/. */
 
 function test() {
-  TestRunner.run();
-}
-
-function runTests() {
   /** Test (B) for Bug 248970 **/
-
-  // Let runTests() be a generator function.
-  yield executeSoon(next);
+  waitForExplicitFinish();
 
   let windowsToClose = [];
   let file = Services.dirsvc.get("TmpD", Ci.nsIFile);
   let filePath = file.path;
   let fieldList = {
     "//input[@name='input']":     Date.now().toString(),
     "//input[@name='spaced 1']":  Math.random().toString(),
     "//input[3]":                 "three",
@@ -158,16 +152,16 @@ function runTests() {
               for (let item in fieldList)
                 ok(compareFormValue(tab_C, item, fieldList[item]),
                   "The value for \"" + item + "\" was correctly duplicated");
 
               // private browsing session, close tab: (C) and (B)
               aWin.gBrowser.removeTab(tab_C);
               aWin.gBrowser.removeTab(tab_B);
 
-              next();
+              finish();
             });
           });
         });
       });
     });
   });
 }
--- a/browser/devtools/inspector/Highlighter.jsm
+++ b/browser/devtools/inspector/Highlighter.jsm
@@ -135,23 +135,21 @@ Highlighter.prototype = {
     this.selection.on("new-node", this.updateInfobar);
     this.selection.on("pseudoclass", this.updateInfobar);
     this.selection.on("attribute-changed", this.updateInfobar);
 
     this.onToolSelected = function(event, id) {
       if (id != "inspector") {
         this.chromeWin.clearTimeout(this.pageEventsMuter);
         this.detachMouseListeners();
-        this.disabled = true;
         this.hide();
       } else {
         if (!this.locked) {
           this.attachMouseListeners();
         }
-        this.disabled = false;
         this.show();
       }
     }.bind(this);
     this.toolbox.on("select", this.onToolSelected);
 
     this.hidden = true;
     this.highlight();
   },
@@ -203,28 +201,24 @@ Highlighter.prototype = {
       this.lock();
     }
 
     let canHighlightNode = this.selection.isNode() &&
                           this.selection.isConnected() &&
                           this.selection.isElementNode();
 
     if (canHighlightNode) {
-      if (this.selection.reason != "navigateaway") {
-        this.disabled = false;
-      }
       this.show();
       this.updateInfobar();
       this.invalidateSize();
       if (!this._highlighting &&
           this.selection.reason != "highlighter") {
         LayoutHelpers.scrollIntoViewIfNeeded(this.selection.node);
       }
     } else {
-      this.disabled = true;
       this.hide();
     }
   },
 
   /**
    * Update the highlighter size and position.
    */
   invalidateSize: function Highlighter_invalidateSize()
@@ -247,17 +241,17 @@ Highlighter.prototype = {
       this.emit("highlighting");
     }
   },
 
   /**
    * Show the highlighter if it has been hidden.
    */
   show: function() {
-    if (!this.hidden || this.disabled) return;
+    if (!this.hidden) return;
     this.showOutline();
     this.showInfobar();
     this.computeZoomFactor();
     this.attachPageListeners();
     this.invalidateSize();
     this.hidden = false;
   },
 
--- a/browser/devtools/inspector/InspectorPanel.jsm
+++ b/browser/devtools/inspector/InspectorPanel.jsm
@@ -242,17 +242,17 @@ InspectorPanel.prototype = {
     function onDOMReady() {
       newWindow.removeEventListener("DOMContentLoaded", onDOMReady, true);
 
       if (self._destroyed) {
         return;
       }
 
       if (!self.selection.node) {
-        self.selection.setNode(newWindow.document.documentElement, "navigateaway");
+        self.selection.setNode(newWindow.document.documentElement);
       }
       self._initMarkup();
     }
 
     if (newWindow.document.readyState == "loading") {
       newWindow.addEventListener("DOMContentLoaded", onDOMReady, true);
     } else {
       onDOMReady();
--- a/browser/devtools/inspector/test/Makefile.in
+++ b/browser/devtools/inspector/test/Makefile.in
@@ -34,15 +34,14 @@ include $(topsrcdir)/config/rules.mk
 		browser_inspector_cmd_inspect.html \
 		browser_inspector_highlighter_autohide.js \
 		browser_inspector_changes.js \
 		browser_inspector_bug_674871.js \
 		browser_inspector_bug_817558_delete_node.js \
 		browser_inspector_bug_650804_search.js \
 		browser_inspector_bug_650804_search.html \
 		browser_inspector_bug_840156_destroy_after_navigation.js \
-		browser_inspector_bug_835722_infobar_reappears.js \
 		head.js \
 		helpers.js \
 		$(NULL)
 
 libs::	$(_BROWSER_FILES)
 	$(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/browser/$(relativesrcdir)
deleted file mode 100644
--- a/browser/devtools/inspector/test/browser_inspector_bug_835722_infobar_reappears.js
+++ /dev/null
@@ -1,92 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
-   http://creativecommons.org/publicdomain/zero/1.0/ */
-
-function test() {
-  let inspector;
-
-  function startLocationTests() {
-    openInspector(runInspectorTests);
-  }
-
-  function runInspectorTests(aInspector) {
-    inspector = aInspector;
-
-    executeSoon(function() {
-      inspector.selection.once("new-node", onNewSelection);
-      info("selecting the DOCTYPE node");
-      inspector.selection.setNode(content.document.doctype, "test");
-    });
-  }
-
-  function onNewSelection() {
-    is(inspector.highlighter.isHidden(), true,
-       "The infobar should be hidden now on selecting a non element node.");
-    inspector.sidebar.select("ruleview");
-    let ruleView = inspector.sidebar.getTab("ruleview");
-    ruleView.addEventListener("mouseover", function onMouseOver() {
-      ruleView.removeEventListener("mouseover", onMouseOver, false);
-      is(inspector.highlighter.isHidden(), true,
-         "The infobar was hidden so mouseover on the rules view did nothing");
-      mouseOutAndContinue();
-    }, false);
-    EventUtils.synthesizeMouse(ruleView, 10, 50, {type: "mouseover"},
-                               ruleView.ownerDocument.defaultView);
-  }
-
-  function mouseOutAndContinue() {
-    let ruleView = inspector.sidebar.getTab("ruleview");
-    ruleView.addEventListener("mouseout", function onMouseOut() {
-      ruleView.removeEventListener("mouseout", onMouseOut, false);
-      is(inspector.highlighter.isHidden(), true,
-         "The infobar should not be visible after we mouseout of rules view");
-      switchToWebConsole();
-    }, false);
-    EventUtils.synthesizeMouse(ruleView, 10, 10, {type: "mousemove"},
-                               ruleView.ownerDocument.defaultView);
-    EventUtils.synthesizeMouse(ruleView, -10, -10, {type: "mouseout"},
-                               ruleView.ownerDocument.defaultView);
-  }
-
-  function switchToWebConsole() {
-    inspector.selection.once("new-node", function() {
-      is(inspector.highlighter.isHidden(), false,
-         "The infobar should be visible after we select a div.");
-      gDevTools.showToolbox(inspector.target, "webconsole").then(function() {
-        is(inspector.highlighter.isHidden(), true,
-           "The infobar should not be visible after we switched to webconsole");
-        reloadAndWait();
-      });
-    });
-    inspector.selection.setNode(content.document.querySelector("div"), "test");
-  }
-
-  function reloadAndWait() {
-    gBrowser.selectedBrowser.addEventListener("load", function onBrowserLoad() {
-      gBrowser.selectedBrowser.removeEventListener("load", onBrowserLoad, true);
-      waitForFocus(testAfterReload, content);
-    }, true);
-    content.location.reload();
-  }
-
-  function testAfterReload() {
-    is(inspector.highlighter.isHidden(), true,
-       "The infobar should not be visible after we reload with webconsole shown");
-    testEnd();
-  }
-
-  function testEnd() {
-    gBrowser.removeCurrentTab();
-    executeSoon(finish);
-  }
-
-  waitForExplicitFinish();
-
-  gBrowser.selectedTab = gBrowser.addTab();
-  gBrowser.selectedBrowser.addEventListener("load", function onBrowserLoad() {
-    gBrowser.selectedBrowser.removeEventListener("load", onBrowserLoad, true);
-    waitForFocus(startLocationTests, content);
-  }, true);
-
-  content.location = "data:text/html,<!DOCTYPE html><div>Infobar should not " +
-                     "reappear</div><p>init</p>";
-}
--- a/browser/locales/en-US/chrome/browser/browser.dtd
+++ b/browser/locales/en-US/chrome/browser/browser.dtd
@@ -607,16 +607,18 @@ just addresses the organization to follo
 <!ENTITY social.notLoggedIn.label   "Not logged in">
 
 <!ENTITY social.ok.label       "OK">
 <!ENTITY social.ok.accesskey   "O">
 
 <!ENTITY social.toggleSidebar.label "Show sidebar">
 <!ENTITY social.toggleSidebar.accesskey "s">
 
+<!ENTITY social.addons.label "Manage Services…">
+
 <!ENTITY social.toggleNotifications.label "Show desktop notifications">
 <!ENTITY social.toggleNotifications.accesskey "n">
 
 <!ENTITY social.activated.undobutton.label "Undo">
 <!ENTITY social.activated.undobutton.accesskey "U">
 
 <!ENTITY social.chatBar.commandkey "c">
 <!ENTITY social.chatBar.label "Focus chats">
--- a/browser/locales/en-US/chrome/browser/browser.properties
+++ b/browser/locales/en-US/chrome/browser/browser.properties
@@ -369,25 +369,16 @@ webapps.install.success = Application In
 # LOCALIZATION NOTE (fullscreen.entered): displayed when we enter HTML5 fullscreen mode, %S is the domain name of the focused website (e.g. mozilla.com).
 fullscreen.entered=%S is now fullscreen.
 # LOCALIZATION NOTE (fullscreen.rememberDecision): displayed when we enter HTML5 fullscreen mode, %S is the domain name of the focused website (e.g. mozilla.com).
 fullscreen.rememberDecision=Remember decision for %S
 
 # LOCALIZATION NOTE (social.activated.description): %1$S is the name of the social provider, %2$S is brandShortName (e.g. Firefox)
 social.activated.description=You've turned on %1$S for %2$S.
 
-# LOCALIZATION NOTE (social.removeProvider.label): %S is the name of the social provider
-social.removeProvider.label=Remove %S
-social.removeProvider.accesskey=R
-# LOCALIZATION NOTE (social.remove.confirmationLabel): %1$S is the name of the social provider, %2$S is brandShortName (e.g. Firefox)
-social.remove.confirmationLabel=Are you sure you want to remove %1$S for %2$S?
-# LOCALIZATION NOTE (social.remove.confirmationOK): %S is the name of the social provider
-social.remove.confirmationOK=Remove %S
-
-
 # LOCALIZATION NOTE (social.turnOff.label): %S is the name of the social provider
 social.turnOff.label=Turn off %S
 social.turnOff.accesskey=T
 # LOCALIZATION NOTE (social.turnOn.label): %S is the name of the social provider
 social.turnOn.label=Turn on %S
 social.turnOn.accesskey=T
 
 # LOCALIZATION NOTE (social.error.message): %1$S is brandShortName (e.g. Firefox), %2$S is the name of the social provider
--- a/browser/locales/en-US/chrome/browser/safebrowsing/phishing-afterload-warning-message.dtd
+++ b/browser/locales/en-US/chrome/browser/safebrowsing/phishing-afterload-warning-message.dtd
@@ -1,26 +1,14 @@
 <!-- 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/. -->
 
-<!ENTITY safeb.palm.warning.title "Suspected Web Forgery">
-
-<!ENTITY safeb.palm.message.p1 "This page has been reported as a web forgery designed to trick users into sharing personal or financial information. Entering any personal information on this page may result in identity theft or other fraud. &#160;">
-<!ENTITY safeb.palm.message.p1.linkText "Read more &#187;">
-<!ENTITY safeb.palm.p1.linkStatusText "Read more &#133;">
-
-<!ENTITY safeb.palm.message.p2.start "These types of web forgeries are used in scams known as phishing attacks, in which fraudulent web pages and emails are used to imitate sources you may trust. You can find out more about ">
-<!ENTITY safeb.palm.message.p2.linkText "how &brandShortName; protects you">
-<!ENTITY safeb.palm.message.p2.end " from phishing attacks.">
-
 <!ENTITY safeb.palm.accept.label "Get me out of here!">
-<!ENTITY safeb.palm.accept.statustext "Navigate to my home page">
 <!ENTITY safeb.palm.decline.label "Ignore this warning">
-<!ENTITY safeb.palm.decline.statustext "Close warning" >
 <!ENTITY safeb.palm.notforgery.label2 "This isn't a web forgery…">
 <!ENTITY safeb.palm.reportPage.label "Why was this page blocked?">
 
 <!ENTITY safeb.blocked.malwarePage.title "Reported Attack Page!">
 <!-- Localization note (safeb.blocked.malware.shortDesc) - Please don't translate the contents of the <span id="malware_sitename"/> tag.  It will be replaced at runtime with a domain name (e.g. www.badsite.com) -->
 <!ENTITY safeb.blocked.malwarePage.shortDesc "This web page at <span id='malware_sitename'/> has been reported as an attack page and has been blocked based on your security preferences.">
 <!ENTITY safeb.blocked.malwarePage.longDesc "<p>Attack pages try to install programs that steal private information, use your computer to attack others, or damage your system.</p><p>Some attack pages intentionally distribute harmful software, but many are compromised without the knowledge or permission of their owners.</p>">
 
--- a/browser/metro/base/content/contenthandlers/Content.js
+++ b/browser/metro/base/content/contenthandlers/Content.js
@@ -493,17 +493,17 @@ let Content = {
     
       if (ot == errorDoc.getElementById("getMeOutButton")) {
         sendAsyncMessage("Browser:BlockedSite",
                          { url: errorDoc.location.href, action: "leave" });
       } else if (ot == errorDoc.getElementById("reportButton")) {
         // This is the "Why is this site blocked" button.  For malware,
         // we can fetch a site-specific report, for phishing, we redirect
         // to the generic page describing phishing protection.
-        let action = isMalware ? "report-malware" : "report-phising";
+        let action = isMalware ? "report-malware" : "report-phishing";
         sendAsyncMessage("Browser:BlockedSite",
                          { url: errorDoc.location.href, action: action });
       } else if (ot == errorDoc.getElementById("ignoreWarningButton")) {
         // Allow users to override and continue through to the site,
         // but add a notify bar as a reminder, so that they don't lose
         // track after, e.g., tab switching.
         let webNav = docShell.QueryInterface(Ci.nsIWebNavigation);
         webNav.loadURI(content.location,
--- a/browser/metro/locales/en-US/chrome/phishing.dtd
+++ b/browser/metro/locales/en-US/chrome/phishing.dtd
@@ -1,26 +1,14 @@
 <!-- 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/. -->
 
-<!ENTITY safeb.palm.warning.title "Suspected Web Forgery">
-
-<!ENTITY safeb.palm.message.p1 "This page has been reported as a web forgery designed to trick users into sharing personal or financial information. Entering any personal information on this page may result in identity theft or other fraud. &#160;">
-<!ENTITY safeb.palm.message.p1.linkText "Read more &#187;">
-<!ENTITY safeb.palm.p1.linkStatusText "Read more &#133;">
-
-<!ENTITY safeb.palm.message.p2.start "These types of web forgeries are used in scams known as phishing attacks, in which fraudulent web pages and emails are used to imitate sources you may trust. You can find out more about ">
-<!ENTITY safeb.palm.message.p2.linkText "how &brandShortName; protects you">
-<!ENTITY safeb.palm.message.p2.end " from phishing attacks.">
-
 <!ENTITY safeb.palm.accept.label "Get me out of here!">
-<!ENTITY safeb.palm.accept.statustext "Navigate to my home page">
 <!ENTITY safeb.palm.decline.label "Ignore this warning">
-<!ENTITY safeb.palm.decline.statustext "Close warning" >
 <!ENTITY safeb.palm.notforgery.label2 "This isn't a web forgery…">
 <!ENTITY safeb.palm.reportPage.label "Why was this page blocked?">
 
 <!ENTITY safeb.blocked.malwarePage.title "Reported Attack Page!">
 <!-- Localization note (safeb.blocked.malware.shortDesc) - Please don't translate the contents of the <span id="malware_sitename"/> tag.  It will be replaced at runtime with a domain name (e.g. www.badsite.com) -->
 <!ENTITY safeb.blocked.malwarePage.shortDesc "This web page at <span id='malware_sitename'/> has been reported as an attack page and has been blocked based on your security preferences.">
 <!ENTITY safeb.blocked.malwarePage.longDesc "<p>Attack pages try to install programs that steal private information, use your computer to attack others, or damage your system.</p><p>Some attack pages intentionally distribute harmful software, but many are compromised without the knowledge or permission of their owners.</p>">
 
--- a/browser/metro/profile/metro.js
+++ b/browser/metro/profile/metro.js
@@ -575,8 +575,23 @@ pref("javascript.options.showInConsole",
 pref("browser.dom.window.dump.enabled", true);
 
 // controls if we want camera support
 pref("device.camera.enabled", true);
 pref("media.realtime_decoder.enabled", true);
 
 // Mobile manages state by autodetection
 pref("network.manage-offline-status", true);
+
+// Enable HTML fullscreen API in content.
+pref("full-screen-api.enabled", true);
+// But don't require approval when content enters fullscreen; we'll keep our
+// UI/chrome visible still, so there's no need to approve entering fullscreen.
+pref("full-screen-api.approval-required", false);
+// Don't allow fullscreen requests to percolate across content/chrome boundary,
+// so that our chrome/UI remains visible after content enters fullscreen.
+pref("full-screen-api.content-only", true);
+// Don't make top-level widgets fullscreen. This only applies when running in
+// "metrodesktop" mode, not when running in full metro mode. This prevents the
+// window from changing size when we go fullscreen; the content expands to fill
+// the window, the window size doesn't change. This pref has no effect when
+// running in actual Metro mode, as the widget will already be fullscreen then.
+pref("full-screen-api.ignore-widgets", true);
--- a/browser/metro/theme/browser.css
+++ b/browser/metro/theme/browser.css
@@ -8,17 +8,17 @@
 %define forward_transition_length 150ms
 %define forward_width 51px
 %define back_width 62px
 %define clipped_url_back_width 71px
 
 /* Sliding Toolbar/Tab Tray ------------------------------------------------- */
 
 #tray {
-  transition: transform 0.2s ease-out;
+  transition: transform @metro_animation_duration@ @metro_animation_easing@;
   transform: translateY(-@tray_slide_height@);
   width: 100%;
 }
 
 #progress-control {
   display: block;
   height: @progress_height@;
   max-height: @progress_height@;
@@ -508,17 +508,17 @@ documenttab[selected=true] .documenttab-
 /* App Bar ----------------------------------------------------------------- */
 
 appbar {
   display: block;
   position: fixed;
   height: @toolbar_height@;
   bottom: 0;
   transform: translateY(@toolbar_height@);
-  transition: transform 0.2s ease-out;
+  transition: transform @metro_animation_duration@ @metro_animation_easing@;
   width: 100%;
 }
 
 appbar toolbar {
   border-top: 1px solid @appbar_top_border@;
   border-bottom: 0px;
   height: @toolbar_height@;
   -moz-appearance: none;
--- a/browser/metro/theme/defines.inc
+++ b/browser/metro/theme/defines.inc
@@ -113,8 +113,12 @@
 %define border_radius_normal 5px
 %define border_radius_small 4px
 %define border_radius_xsmall 2px
 %define border_radius_tiny 1px
 
 %define shadow_width_xlarge 7px
 %define shadow_width_large 4px
 %define shadow_width_small 1px
+
+% easing function and duration for animations match winJS showPanel method
+%define metro_animation_duration 550ms
+%define metro_animation_easing cubic-bezier(0.1, 0.9, 0.2, 1)
--- a/browser/metro/theme/flyoutpanel.css
+++ b/browser/metro/theme/flyoutpanel.css
@@ -1,22 +1,24 @@
 /* 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/. */
 
+%filter substitution
+%include defines.inc
+
 flyoutpanel {
   height: 100%;
   border-width: 2px;
   border-color: #d7d6d6;
   background-color: #ffffff;
   -moz-border-start-style: solid;
   visibility: collapse;
   position: fixed;
-  /* bezier function and duration taken from winJS showPanel method */
-  transition: transform 550ms cubic-bezier(0.1, 0.9, 0.2, 1);
+  transition: transform @metro_animation_duration@ @metro_animation_easing@;
   transform: translateX(100%);
   font-size: 11pt;
   right: 0;
 }
 
 flyoutpanel:-moz-dir(rtl) {
   left: 0;
   right: auto;
--- a/browser/metro/theme/jar.mn
+++ b/browser/metro/theme/jar.mn
@@ -3,17 +3,17 @@
 # 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/.
 
 
 chrome.jar:
 % skin browser classic/1.0 %skin/
   skin/aboutPage.css                        (aboutPage.css)
   skin/about.css                            (about.css)
-  skin/flyoutpanel.css                      (flyoutpanel.css)
+* skin/flyoutpanel.css                      (flyoutpanel.css)
 * skin/browser.css                          (browser.css)
 * skin/content.css                          (content.css)
   skin/config.css                           (config.css)
 * skin/forms.css                            (forms.css)
 * skin/platform.css                         (platform.css)
   skin/touchcontrols.css                    (touchcontrols.css)
   skin/netError.css                         (netError.css)
 % override chrome://global/skin/about.css chrome://browser/skin/about.css
--- a/content/base/public/nsContentUtils.h
+++ b/content/base/public/nsContentUtils.h
@@ -1806,16 +1806,42 @@ public:
    * Returns true if requests for full-screen are allowed in the current
    * context. Requests are only allowed if the user initiated them (like with
    * a mouse-click or key press), unless this check has been disabled by
    * setting the pref "full-screen-api.allow-trusted-requests-only" to false.
    */
   static bool IsRequestFullScreenAllowed();
 
   /**
+   * Returns true if the DOM fullscreen API is restricted to content only.
+   * This mirrors the pref "full-screen-api.content-only". If this is true,
+   * fullscreen requests in chrome are denied, and fullscreen requests in
+   * content stop percolating upwards before they reach chrome documents.
+   * That is, when an element in content requests fullscreen, only its
+   * containing frames that are in content are also made fullscreen, not
+   * the containing frame in the chrome document.
+   *
+   * Note if the fullscreen API is running in content only mode then multiple
+   * branches of a doctree can be fullscreen at the same time, but no fullscreen
+   * document will have a common ancestor with another fullscreen document
+   * that is also fullscreen (since the only common ancestor they can have
+   * is the chrome document, and that can't be fullscreen). i.e. multiple
+   * child documents of the chrome document can be fullscreen, but the chrome
+   * document won't be fullscreen.
+   *
+   * Making the fullscreen API content only is useful on platforms where we
+   * still want chrome to be visible or accessible while content is
+   * fullscreen, like on Windows 8 in Metro mode.
+   *
+   * Note that if the fullscreen API is content only, chrome can still go
+   * fullscreen by setting the "fullScreen" attribute on its XUL window.
+   */
+  static bool IsFullscreenApiContentOnly();
+
+  /**
    * Returns true if the idle observers API is enabled.
    */
   static bool IsIdleObserverAPIEnabled() { return sIsIdleObserverAPIEnabled; }
   
   /**
    * Returns true if the doc tree branch which contains aDoc contains any
    * plugins which we don't control event dispatch for, i.e. do any plugins
    * in the same tab as this document receive key events outside of our
@@ -1827,20 +1853,22 @@ public:
    * Returns true if the content is in a document and contains a plugin
    * which we don't control event dispatch for, i.e. do any plugins in this
    * doc tree receive key events outside of our control? This always returns
    * false on MacOSX.
    */
   static bool HasPluginWithUncontrolledEventDispatch(nsIContent* aContent);
 
   /**
-   * Returns the root document in a document hierarchy. Normally this will
-   * be the chrome document.
+   * Returns the document that is the closest ancestor to aDoc that is
+   * fullscreen. If aDoc is fullscreen this returns aDoc. If aDoc is not
+   * fullscreen and none of aDoc's ancestors are fullscreen this returns
+   * nullptr.
    */
-  static nsIDocument* GetRootDocument(nsIDocument* aDoc);
+  static nsIDocument* GetFullscreenAncestor(nsIDocument* aDoc);
 
   /**
    * Returns the time limit on handling user input before
    * nsEventStateManager::IsHandlingUserInput() stops returning true.
    * This enables us to detect long running user-generated event handlers.
    */
   static TimeDuration HandlingUserInputTimeout();
 
@@ -2156,16 +2184,17 @@ private:
   static uint32_t sScriptBlockerCountWhereRunnersPrevented;
 
   static nsIInterfaceRequestor* sSameOriginChecker;
 
   static bool sIsHandlingKeyBoardEvent;
   static bool sAllowXULXBL_for_file;
   static bool sIsFullScreenApiEnabled;
   static bool sTrustedFullScreenOnly;
+  static bool sFullscreenApiIsContentOnly;
   static uint32_t sHandlingInputTimeout;
   static bool sIsIdleObserverAPIEnabled;
 
   static nsHtml5StringParser* sHTMLFragmentParser;
   static nsIParser* sXMLFragmentParser;
   static nsIFragmentContentSink* sXMLFragmentSink;
 
   /**
--- a/content/base/public/nsIDocument.h
+++ b/content/base/public/nsIDocument.h
@@ -863,20 +863,25 @@ public:
    * Returns the element which either requested DOM full-screen mode, or
    * contains the element which requested DOM full-screen mode if the
    * requestee is in a subdocument. Note this element must be *in*
    * this document.
    */
   virtual Element* GetFullScreenElement() = 0;
 
   /**
-   * Asynchronously requests that the document make aElement the full-screen
-   * element, and move into full-screen mode. The current full-screen element
-   * (if any) is pushed onto the full-screen element stack, and it can be
-   * returned to full-screen status by calling RestorePreviousFullScreenState().
+   * Asynchronously requests that the document make aElement the fullscreen
+   * element, and move into fullscreen mode. The current fullscreen element
+   * (if any) is pushed onto the fullscreen element stack, and it can be
+   * returned to fullscreen status by calling RestorePreviousFullScreenState().
+   *
+   * Note that requesting fullscreen in a document also makes the element which
+   * contains this document in this document's parent document fullscreen. i.e.
+   * the <iframe> or <browser> that contains this document is also mode
+   * fullscreen. This happens recursively in all ancestor documents.
    */
   virtual void AsyncRequestFullScreen(Element* aElement) = 0;
 
   /**
    * Called when a frame in a child process has entered fullscreen or when a
    * fullscreen frame in a child process changes to another origin.
    * aFrameElement is the frame element which contains the child-process
    * fullscreen document, and aNewOrigin is the origin of the new fullscreen
@@ -931,22 +936,35 @@ public:
    * Sets whether this document is approved for fullscreen mode.
    * Documents aren't approved for fullscreen until chrome has sent a
    * "fullscreen-approved" notification with a subject which is a pointer
    * to the approved document.
    */
   virtual void SetApprovedForFullscreen(bool aIsApproved) = 0;
 
   /**
-   * Exits documents out of DOM fullscreen mode. If aDocument is non null,
-   * only its ancestors and descendants exit fullscreen, i.e. if there are
-   * multiple windows/doctrees in fullscreen mode, only the one containing
-   * aDocument exits fullscreen mode. If aDocument is null, all windows
-   * and documents exit fullscreen. If aRunAsync is true, fullscreen is
-   * executed asynchronously.
+   * Exits documents out of DOM fullscreen mode.
+   *
+   * If aDocument is null, all fullscreen documents in all browser windows
+   * exit fullscreen.
+   *
+   * If aDocument is non null, all documents from aDocument's fullscreen root
+   * to the fullscreen leaf exit fullscreen. 
+   *
+   * Note that the fullscreen leaf is the bottom-most document which is
+   * fullscreen, it may have non-fullscreen child documents. The fullscreen
+   * root is usually the chrome document, but if fullscreen is content-only,
+   * (see the comment in nsContentUtils.h on IsFullscreenApiContentOnly())
+   * the fullscreen root will be a direct child of the chrome document, and
+   * there may be other branches of the same doctree that are fullscreen.
+   *
+   * If aRunAsync is true, fullscreen is executed asynchronously.
+   *
+   * Note if aDocument is not fullscreen this function has no effect, even if
+   * aDocument has fullscreen ancestors.
    */
   static void ExitFullscreen(nsIDocument* aDocument, bool aRunAsync);
 
   virtual void RequestPointerLock(Element* aElement) = 0;
 
   static void UnlockPointer();
 
 
--- a/content/base/src/Element.cpp
+++ b/content/base/src/Element.cpp
@@ -2570,16 +2570,23 @@ Element::AttrValueToCORSMode(const nsAtt
   }
 
   return CORSMode(aValue->GetEnumValue());
 }
 
 static const char*
 GetFullScreenError(nsIDocument* aDoc)
 {
+  // Block fullscreen requests in the chrome document when the fullscreen API
+  // is configured for content only.
+  if (nsContentUtils::IsFullscreenApiContentOnly() &&
+      nsContentUtils::IsChromeDoc(aDoc)) {
+    return "FullScreenDeniedContentOnly";
+  }
+
   nsCOMPtr<nsPIDOMWindow> win = aDoc->GetWindow();
   if (aDoc->NodePrincipal()->GetAppStatus() >= nsIPrincipal::APP_STATUS_INSTALLED) {
     // Request is in a web app and in the same origin as the web app.
     // Don't enforce as strict security checks for web apps, the user
     // is supposed to have trust in them. However documents cross-origin
     // to the web app must still confirm to the normal security checks.
     return nullptr;
   }
--- a/content/base/src/nsContentUtils.cpp
+++ b/content/base/src/nsContentUtils.cpp
@@ -227,16 +227,17 @@ nsString* nsContentUtils::sControlText =
 nsString* nsContentUtils::sMetaText = nullptr;
 nsString* nsContentUtils::sOSText = nullptr;
 nsString* nsContentUtils::sAltText = nullptr;
 nsString* nsContentUtils::sModifierSeparator = nullptr;
 
 bool nsContentUtils::sInitialized = false;
 bool nsContentUtils::sIsFullScreenApiEnabled = false;
 bool nsContentUtils::sTrustedFullScreenOnly = true;
+bool nsContentUtils::sFullscreenApiIsContentOnly = false;
 bool nsContentUtils::sIsIdleObserverAPIEnabled = false;
 
 uint32_t nsContentUtils::sHandlingInputTimeout = 1000;
 
 nsHtml5StringParser* nsContentUtils::sHTMLFragmentParser = nullptr;
 nsIParser* nsContentUtils::sXMLFragmentParser = nullptr;
 nsIFragmentContentSink* nsContentUtils::sXMLFragmentSink = nullptr;
 bool nsContentUtils::sFragmentParsingActive = false;
@@ -414,16 +415,22 @@ nsContentUtils::Init()
   sBlockedScriptRunners = new nsTArray< nsCOMPtr<nsIRunnable> >;
 
   Preferences::AddBoolVarCache(&sAllowXULXBL_for_file,
                                "dom.allow_XUL_XBL_for_file");
 
   Preferences::AddBoolVarCache(&sIsFullScreenApiEnabled,
                                "full-screen-api.enabled");
 
+  // Note: We deliberately read this pref here because this code runs
+  // before the profile loads, so users' changes to this pref in about:config
+  // won't have any effect on behaviour. We don't really want users messing
+  // with this pref, as it affects the security model of the fullscreen API.
+  sFullscreenApiIsContentOnly = Preferences::GetBool("full-screen-api.content-only", false);
+
   Preferences::AddBoolVarCache(&sTrustedFullScreenOnly,
                                "full-screen-api.allow-trusted-requests-only");
 
   sIsIdleObserverAPIEnabled = Preferences::GetBool("dom.idle-observers-api.enabled", true);
 
   Preferences::AddUintVarCache(&sHandlingInputTimeout,
                                "dom.event.handling-user-input-time-limit",
                                1000);
@@ -6515,32 +6522,41 @@ nsContentUtils::SetUpChannelOwner(nsIPri
       !IsSystemPrincipal(aLoadingPrincipal)) {
     aChannel->SetOwner(aLoadingPrincipal);
     return true;
   }
 
   return false;
 }
 
+/* static */
 bool
 nsContentUtils::IsFullScreenApiEnabled()
 {
   return sIsFullScreenApiEnabled;
 }
 
+/* static */
 bool
 nsContentUtils::IsRequestFullScreenAllowed()
 {
   return !sTrustedFullScreenOnly ||
          nsEventStateManager::IsHandlingUserInput() ||
          IsCallerChrome();
 }
 
 /* static */
 bool
+nsContentUtils::IsFullscreenApiContentOnly()
+{
+  return sFullscreenApiIsContentOnly;
+}
+
+/* static */
+bool
 nsContentUtils::HaveEqualPrincipals(nsIDocument* aDoc1, nsIDocument* aDoc2)
 {
   if (!aDoc1 || !aDoc2) {
     return false;
   }
   bool principalsEqual = false;
   aDoc1->NodePrincipal()->Equals(aDoc2->NodePrincipal(), &principalsEqual);
   return principalsEqual;
@@ -6615,26 +6631,26 @@ nsContentUtils::HasPluginWithUncontrolle
 #endif
   bool result = false;
   CheckForWindowedPlugins(aContent, &result);
   return result;
 }
 
 /* static */
 nsIDocument*
-nsContentUtils::GetRootDocument(nsIDocument* aDoc)
-{
-  if (!aDoc) {
-    return nullptr;
-  }
+nsContentUtils::GetFullscreenAncestor(nsIDocument* aDoc)
+{
   nsIDocument* doc = aDoc;
-  while (doc->GetParentDocument()) {
+  while (doc) {
+    if (doc->IsFullScreenDoc()) {
+      return doc;
+    }
     doc = doc->GetParentDocument();
   }
-  return doc;
+  return nullptr;
 }
 
 // static
 void
 nsContentUtils::ReleaseWrapper(void* aScriptObjectHolder,
                                nsWrapperCache* aCache)
 {
   if (aCache->PreservingWrapper()) {
--- a/content/base/src/nsDocument.cpp
+++ b/content/base/src/nsDocument.cpp
@@ -9250,27 +9250,45 @@ public:
     return NS_OK;
   }
 
 private:
   nsCOMPtr<nsIDocument> mDoc;
   bool mValue;
 };
 
+static nsIDocument*
+GetFullscreenRootDocument(nsIDocument* aDoc)
+{
+  if (!aDoc) {
+    return nullptr;
+  }
+  nsIDocument* doc = aDoc;
+  nsIDocument* parent;
+  while ((parent = doc->GetParentDocument()) &&
+         (!nsContentUtils::IsFullscreenApiContentOnly() ||
+          !nsContentUtils::IsChromeDoc(parent))) {
+    doc = parent;
+  }
+  return doc;
+}
+
 static void
 SetWindowFullScreen(nsIDocument* aDoc, bool aValue)
 {
   // Maintain list of fullscreen root documents.
-  nsCOMPtr<nsIDocument> root = nsContentUtils::GetRootDocument(aDoc);
+  nsCOMPtr<nsIDocument> root = GetFullscreenRootDocument(aDoc);
   if (aValue) {
     FullscreenRoots::Add(root);
   } else {
     FullscreenRoots::Remove(root);
   }
-  nsContentUtils::AddScriptRunner(new nsSetWindowFullScreen(aDoc, aValue));
+  if (!nsContentUtils::IsFullscreenApiContentOnly()) {
+    nsContentUtils::AddScriptRunner(new nsSetWindowFullScreen(aDoc, aValue));
+  }
 }
 
 class nsCallExitFullscreen : public nsRunnable {
 public:
   nsCallExitFullscreen(nsIDocument* aDoc)
     : mDoc(aDoc) {}
   NS_IMETHOD Run()
   {
@@ -9453,31 +9471,35 @@ GetFullscreenLeaf(nsIDocument* aDoc)
 {
   nsIDocument* leaf = nullptr;
   GetFullscreenLeaf(aDoc, &leaf);
   if (leaf) {
     return leaf;
   }
   // Otherwise we could be either in a non-fullscreen doc tree, or we're
   // below the fullscreen doc. Start the search from the root.
-  nsIDocument* root = nsContentUtils::GetRootDocument(aDoc);
+  nsIDocument* root = GetFullscreenRootDocument(aDoc);
   // Check that the root is actually fullscreen so we don't waste time walking
   // around its descendants.
   if (!root->IsFullScreenDoc()) {
     return nullptr;
   }
   GetFullscreenLeaf(root, &leaf);
   return leaf;
 }
 
 void
 nsDocument::RestorePreviousFullScreenState()
 {
   NS_ASSERTION(!IsFullScreenDoc() || !FullscreenRoots::IsEmpty(),
     "Should have at least 1 fullscreen root when fullscreen!");
+  NS_ASSERTION(!nsContentUtils::IsFullscreenApiContentOnly() ||
+               !nsContentUtils::IsChromeDoc(this),
+               "Should not run RestorePreviousFullScreenState() on "
+               "chrome document when fullscreen is content only");
 
   if (!IsFullScreenDoc() || !GetWindow() || FullscreenRoots::IsEmpty()) {
     return;
   }
 
   // If fullscreen mode is updated the pointer should be unlocked
   nsCOMPtr<Element> pointerLockedElement =
     do_QueryReferent(nsEventStateManager::sPointerLockedElement);
@@ -9542,29 +9564,29 @@ nsDocument::RestorePreviousFullScreenSta
       }
 
       if (!nsContentUtils::HaveEqualPrincipals(doc, fullScreenDoc)) {
         // The origin which is fullscreen changed. Send a notification to
         // the root process so that a warning or approval UI can be shown
         // as necessary.
         nsAutoString origin;
         nsContentUtils::GetUTFOrigin(doc->NodePrincipal(), origin);
-        nsIDocument* root = nsContentUtils::GetRootDocument(doc);
+        nsIDocument* root = GetFullscreenRootDocument(doc);
         nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
         os->NotifyObservers(root, "fullscreen-origin-change", origin.get());
       }
 
       break;
     }
   }
 
   if (doc == nullptr) {
     // We moved all documents in this doctree out of fullscreen mode,
     // move the top-level window out of fullscreen mode.
-    NS_ASSERTION(!nsContentUtils::GetRootDocument(this)->IsFullScreenDoc(),
+    NS_ASSERTION(!GetFullscreenRootDocument(this)->IsFullScreenDoc(),
       "Should have cleared all docs' stacks");
     SetWindowFullScreen(this, false);
   }
 }
 
 bool
 nsDocument::IsFullScreenDoc()
 {
@@ -9624,17 +9646,20 @@ LogFullScreenDenied(bool aLogFailure, co
                                   "DOM", aDoc,
                                   nsContentUtils::eDOM_PROPERTIES,
                                   aMessage);
 }
 
 nsresult
 nsDocument::AddFullscreenApprovedObserver()
 {
-  NS_ASSERTION(!mHasFullscreenApprovedObserver, "Don't add observer twice.");
+  if (mHasFullscreenApprovedObserver ||
+      !Preferences::GetBool("full-screen-api.approval-required")) {
+    return NS_OK;
+  }
 
   nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
   NS_ENSURE_TRUE(os, NS_ERROR_FAILURE);
 
   nsresult res = os->AddObserver(this, "fullscreen-approved", true);
   NS_ENSURE_SUCCESS(res, res);
 
   mHasFullscreenApprovedObserver = true;
@@ -9806,17 +9831,17 @@ nsresult nsDocument::RemoteFrameFullscre
   // Origin changed in child process, send notifiction, so that chrome can
   // update the UI to reflect the fullscreen origin change if necessary.
   // The BrowserElementChild listens on this, and forwards it over its
   // parent process, where it is redispatched. Chrome (in the root process,
   // which could be *this* process) listens for this notification so that
   // it can show a warning or approval UI.
   if (!aOrigin.IsEmpty()) {
     nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
-    os->NotifyObservers(nsContentUtils::GetRootDocument(this),
+    os->NotifyObservers(GetFullscreenRootDocument(this),
                         "fullscreen-origin-change",
                         PromiseFlatString(aOrigin).get());
   }
 
   return NS_OK;
 }
 
 nsresult nsDocument::RemoteFrameFullscreenReverted()
@@ -9842,16 +9867,23 @@ nsDocument::RequestFullScreen(Element* a
   if (aElement->OwnerDoc() != this) {
     LogFullScreenDenied(true, "FullScreenDeniedMovedDocument", this);
     return;
   }
   if (!GetWindow()) {
     LogFullScreenDenied(true, "FullScreenDeniedLostWindow", this);
     return;
   }
+  if (nsContentUtils::IsFullscreenApiContentOnly() &&
+      nsContentUtils::IsChromeDoc(this)) {
+    // Block fullscreen requests in the chrome document when the fullscreen API
+    // is configured for content only.
+    LogFullScreenDenied(true, "FullScreenDeniedContentOnly", this);
+    return;
+  }
   if (!IsFullScreenEnabled(aWasCallerChrome, true)) {
     // IsFullScreenEnabled calls LogFullScreenDenied, no need to log.
     return;
   }
   if (GetFullScreenElement() &&
       !nsContentUtils::ContentIsDescendantOf(aElement, GetFullScreenElement())) {
     // If this document is full-screen, only grant full-screen requests from
     // a descendant of the current full-screen element.
@@ -9888,17 +9920,17 @@ nsDocument::RequestFullScreen(Element* a
   // too. We're required by the spec to dispatch the events in root-to-leaf
   // order, but we traverse the doctree in a leaf-to-root order, so we save
   // references to the documents we must dispatch to so that we get the order
   // as specified.
   nsAutoTArray<nsIDocument*, 8> changed;
 
   // Remember the root document, so that if a full-screen document is hidden
   // we can reset full-screen state in the remaining visible full-screen documents.
-  nsIDocument* fullScreenRootDoc = nsContentUtils::GetRootDocument(this);
+  nsIDocument* fullScreenRootDoc = GetFullscreenRootDocument(this);
   if (fullScreenRootDoc->IsFullScreenDoc()) {
     // A document is already in fullscreen, unlock the mouse pointer
     // before setting a new document to fullscreen
     UnlockPointer();
   }
 
   // If a document is already in fullscreen, then unlock the mouse pointer
   // before setting a new document to fullscreen
@@ -9920,20 +9952,20 @@ nsDocument::RequestFullScreen(Element* a
   // appropriate css styles as well. Note we don't propagate down the
   // document hierarchy, the full-screen element (or its container) is not
   // visible there. Stop when we reach the root document.
   nsIDocument* child = this;
   while (true) {
     child->SetFullscreenRoot(fullScreenRootDoc);
     NS_ASSERTION(child->GetFullscreenRoot() == fullScreenRootDoc,
         "Fullscreen root should be set!");
+    if (child == fullScreenRootDoc) {
+      break;
+    }
     nsIDocument* parent = child->GetParentDocument();
-    if (!parent) {
-      break;
-    }
     Element* element = parent->FindContentForSubDocument(child)->AsElement();
     if (static_cast<nsDocument*>(parent)->FullScreenStackPush(element)) {
       changed.AppendElement(parent);
       child = parent;
     } else {
       // We've reached either the root, or a point in the doctree where the
       // new full-screen element container is the same as the previous
       // full-screen element's container. No more changes need to be made
@@ -9994,17 +10026,17 @@ nsDocument::RequestFullScreen(Element* a
   // root document knows the origin of the document which requested fullscreen.
   // This is used for the fullscreen approval UI. If we're in a child
   // process, the root BrowserElementChild listens for this notification,
   // and forwards it across to its BrowserElementParent, which
   // re-broadcasts the message for the root document in its process.
   if (aNotifyOnOriginChange &&
       !nsContentUtils::HaveEqualPrincipals(previousFullscreenDoc, this)) {
     nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
-    nsIDocument* root = nsContentUtils::GetRootDocument(this);
+    nsIDocument* root = GetFullscreenRootDocument(this);
     nsAutoString origin;
     nsContentUtils::GetUTFOrigin(NodePrincipal(), origin);
     os->NotifyObservers(root, "fullscreen-origin-change", origin.get());
   }
 
   // Make the window full-screen. Note we must make the state changes above
   // before making the window full-screen, as then the document reports as
   // being in full-screen mode when the chrome "fullscreen" event fires,
@@ -10041,18 +10073,19 @@ nsDocument::GetMozFullScreenElement(Erro
   }
   return nullptr;
 }
 
 Element*
 nsDocument::GetFullScreenElement()
 {
   Element* element = FullScreenStackTop();
-  NS_ASSERTION(!element || element->IsFullScreenAncestor(),
-    "Should have full-screen styles applied!");
+  NS_ASSERTION(!element ||
+               element->IsFullScreenAncestor(),
+    "Fullscreen element should have fullscreen styles applied");
   return element;
 }
 
 NS_IMETHODIMP
 nsDocument::GetMozFullScreen(bool *aFullScreen)
 {
   *aFullScreen = MozFullScreen();
   return NS_OK;
--- a/content/base/test/chrome/test_csp_bug768029.html
+++ b/content/base/test/chrome/test_csp_bug768029.html
@@ -23,16 +23,19 @@ Components.utils.import("resource://gre/
 /** Test for Bug 768029 **/
 
 // Note: we don't have to inspect all the different operations of CSP,
 // we're just looking for specific differences in behavior that indicate
 // a default CSP got applied.
 const DEFAULT_CSP_PRIV = "default-src *; script-src 'self'; style-src 'self' 'unsafe-inline'; object-src 'none'";
 const DEFAULT_CSP_CERT = "default-src *; script-src 'self'; style-src 'self'; object-src 'none'";
 
+if (navigator.platform.startsWith("Linux")) {
+  SimpleTest.expectAssertions(0, 1);
+}
 SimpleTest.waitForExplicitFinish();
 
 var gData = [
   {
     app: "https://example.com/manifest.webapp",
     appStatus: Components.interfaces.nsIPrincipal.APP_STATUS_INSTALLED,
     origin: "https://example.com",
     uri: "https://example.com/tests/content/base/test/file_csp_bug768029.html",
--- a/content/html/content/test/forms/test_progress_element.html
+++ b/content/html/content/test/forms/test_progress_element.html
@@ -18,17 +18,17 @@ and
 <div id="content" style="visibility: hidden;">
   <form id='f' method='get' target='submit_frame' action='foo'>
     <progress id='p'></progress>
   </form>
 </div>
 <pre id="test">
 <script type="application/javascript">
 
-SimpleTest.expectAssertions(1);
+SimpleTest.expectAssertions(0, 1);
 
 /** Test for progress element content and layout **/
 
 function checkFormIDLAttribute(aElement)
 {
   is("form" in aElement, false, "<progress> shouldn't have a form attribute");
 }
 
--- a/content/html/content/test/test_fullscreen-api.html
+++ b/content/html/content/test/test_fullscreen-api.html
@@ -16,22 +16,16 @@
 <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=545812">Mozilla Bug 545812</a>
 <p id="display"></p>
 <div id="content" style="display: none">
 
 </div>
 <pre id="test">
 <script type="application/javascript">
 
-if (navigator.platform.startsWith("Win")) {
-  SimpleTest.expectAssertions(0, 1); // bug 845552
-} else {
-  SimpleTest.expectAssertions(1); // bug 845552
-}
-
 /** Tests for Bug 545812 **/
 
 // Ensure the full-screen api is enabled, and will be disabled on test exit.
 SpecialPowers.setBoolPref("full-screen-api.enabled", true);
 
 // Disable the requirement for trusted contexts only, so the tests are easier
 // to write.
 SpecialPowers.setBoolPref("full-screen-api.allow-trusted-requests-only", false);
--- a/content/media/test/test_bug493187.html
+++ b/content/media/test/test_bug493187.html
@@ -11,17 +11,17 @@ https://bugzilla.mozilla.org/show_bug.cg
   <script type="text/javascript" src="use_large_cache.js"></script>
   <script type="text/javascript" src="manifest.js"></script>
 </head>
 <body>
 <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=493187">Mozilla Bug 493187</a>
 <pre id="test">
 <script class="testbody" type="text/javascript">
 
-SimpleTest.expectAssertions(0, 1);
+SimpleTest.expectAssertions(0, 2);
 
 var manager = new MediaTestManager;
 
 function start(e) {
   e.target.currentTime = e.target.duration / 4;
 }
 
 function startSeeking(e) {
--- a/content/media/test/test_bug495300.html
+++ b/content/media/test/test_bug495300.html
@@ -12,17 +12,17 @@ https://bugzilla.mozilla.org/show_bug.cg
 </head>
 <body>
 <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=495300">Mozilla Bug 495300</a>
 <pre id="test">
 <script class="testbody" type="text/javascript">
 
 if (!navigator.platform.startsWith("Mac")) {
   // not Mac
-  SimpleTest.expectAssertions(0, 1);
+  SimpleTest.expectAssertions(0, 2);
 }
 
 var manager = new MediaTestManager;
 
 function filename(uri) {
   return uri.substr(uri.lastIndexOf("/")+1);
 }
 
--- a/content/media/test/test_seek_out_of_range.html
+++ b/content/media/test/test_seek_out_of_range.html
@@ -6,17 +6,17 @@
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
   <script type="text/javascript" src="manifest.js"></script>
 </head>
 <body>
 <pre id="test">
 <script class="testbody" type="text/javascript">
 
 if (navigator.platform.startsWith("Win")) {
-  SimpleTest.expectAssertions(0, 1);
+  SimpleTest.expectAssertions(0, 8);
 }
 
 var manager = new MediaTestManager;
 
 // Test if the ended event works correctly.
 
 function startTest(e) {
   var v = e.target;
--- a/docshell/base/nsDocShell.cpp
+++ b/docshell/base/nsDocShell.cpp
@@ -1885,16 +1885,84 @@ nsDocShell::GetCharset(char** aCharset)
     if (!*aCharset) {
         return NS_ERROR_OUT_OF_MEMORY;
     }
 
     return NS_OK;
 }
 
 NS_IMETHODIMP
+nsDocShell::GatherCharsetMenuTelemetry()
+{
+  nsCOMPtr<nsIContentViewer> viewer;
+  GetContentViewer(getter_AddRefs(viewer));
+  if (!viewer) {
+    return NS_OK;
+  }
+
+  nsIDocument* doc = viewer->GetDocument();
+  if (!doc || doc->WillIgnoreCharsetOverride()) {
+    return NS_OK;
+  }
+
+  Telemetry::Accumulate(Telemetry::CHARSET_OVERRIDE_USED, true);
+
+  bool isFileURL = false;
+  nsIURI* url = doc->GetOriginalURI();
+  if (url) {
+    url->SchemeIs("file", &isFileURL);
+  }
+
+  int32_t charsetSource = doc->GetDocumentCharacterSetSource();
+  switch (charsetSource) {
+    case kCharsetFromWeakDocTypeDefault:
+    case kCharsetFromUserDefault:
+    case kCharsetFromDocTypeDefault:
+    case kCharsetFromCache:
+    case kCharsetFromParentFrame:
+    case kCharsetFromHintPrevDoc:
+      // Changing charset on an unlabeled doc.
+      if (isFileURL) {
+        Telemetry::Accumulate(Telemetry::CHARSET_OVERRIDE_SITUATION, 0);
+      } else {
+        Telemetry::Accumulate(Telemetry::CHARSET_OVERRIDE_SITUATION, 1);
+      }
+      break;
+    case kCharsetFromAutoDetection:
+      // Changing charset on unlabeled doc where chardet fired
+      if (isFileURL) {
+        Telemetry::Accumulate(Telemetry::CHARSET_OVERRIDE_SITUATION, 2);
+      } else {
+        Telemetry::Accumulate(Telemetry::CHARSET_OVERRIDE_SITUATION, 3);
+      }
+      break;
+    case kCharsetFromMetaPrescan:
+    case kCharsetFromMetaTag:
+    case kCharsetFromChannel:
+      // Changing charset on a doc that had a charset label.
+      Telemetry::Accumulate(Telemetry::CHARSET_OVERRIDE_SITUATION, 4);
+      break;
+    case kCharsetFromParentForced:
+    case kCharsetFromUserForced:
+      // Changing charset on a document that already had an override.
+      Telemetry::Accumulate(Telemetry::CHARSET_OVERRIDE_SITUATION, 5);
+      break;
+    case kCharsetFromIrreversibleAutoDetection:
+    case kCharsetFromOtherComponent:
+    case kCharsetFromByteOrderMark:
+    case kCharsetUninitialized:
+    default:
+      // Bug. This isn't supposed to happen.
+      Telemetry::Accumulate(Telemetry::CHARSET_OVERRIDE_SITUATION, 6);
+      break;
+  }
+  return NS_OK;
+}
+
+NS_IMETHODIMP
 nsDocShell::SetCharset(const char* aCharset)
 {
     // set the default charset
     nsCOMPtr<nsIContentViewer> viewer;
     GetContentViewer(getter_AddRefs(viewer));
     if (viewer) {
       nsCOMPtr<nsIMarkupDocumentViewer> muDV(do_QueryInterface(viewer));
       if (muDV) {
--- a/docshell/base/nsIDocShell.idl
+++ b/docshell/base/nsIDocShell.idl
@@ -35,17 +35,17 @@ interface nsISHEntry;
 interface nsILayoutHistoryState;
 interface nsISecureBrowserUI;
 interface nsIDOMStorage;
 interface nsIPrincipal;
 interface nsIWebBrowserPrint;
 interface nsIVariant;
 interface nsIPrivacyTransitionObserver;
 
-[scriptable, builtinclass, uuid(e8f6f3e5-8cee-4be3-8d56-5ed617305bf8)]
+[scriptable, builtinclass, uuid(4277354d-5069-4278-935a-5d596ce9bfbf)]
 interface nsIDocShell : nsIDocShellTreeItem
 {
   /**
    * Loads a given URI.  This will give priority to loading the requested URI
    * in the object implementing	this interface.  If it can't be loaded here
    * however, the URL dispatcher will go through its normal process of content
    * loading.
    *
@@ -592,16 +592,23 @@ interface nsIDocShell : nsIDocShellTreeI
    * embedding application will need to cause the data to be 
    * reparsed in order to update the DOM / display.
    *
    * A force also sets the fallback encoding for this frame.
    */
   attribute string charset;
 
   /**
+   * Called when the user chose an encoding override from the character
+   * encoding menu. Separate from the setter for the charset property to avoid
+   * extensions adding noise to the data.
+   */
+  void gatherCharsetMenuTelemetry();
+
+  /**
    * The charset forced by the user. When the charset attribute is set this
    * attribute is set to the same value.
    *
    * XXX Could this be replaced by a boolean?
    */
   attribute nsIAtom forcedCharset;
 
   /**
--- a/docshell/test/chrome/test_bug311007.xul
+++ b/docshell/test/chrome/test_bug311007.xul
@@ -26,16 +26,20 @@ https://bugzilla.mozilla.org/show_bug.cg
 </div>
 <pre id="test">
 </pre>
 </body>
 
 <script class="testbody" type="application/javascript">
 <![CDATA[
 
+if (navigator.platform.startsWith("Win")) {
+  SimpleTest.expectAssertions(0, 1);
+}
+
 /** Test for Bug 311007 **/
 
 SimpleTest.waitForExplicitFinish();
 window.open("bug311007_window.xul", "bug311007",
             "chrome,width=600,height=600");
 
 ]]>
 </script>
--- a/docshell/test/test_bug413310.html
+++ b/docshell/test/test_bug413310.html
@@ -8,16 +8,22 @@ https://bugzilla.mozilla.org/show_bug.cg
   <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=413310">Mozilla Bug 413310</a>
 <p id="display">
 <script class="testbody" type="text/javascript">
 
+if (navigator.platform.startsWith("Mac")) {
+  SimpleTest.expectAssertions(0, 2);
+} else {
+  SimpleTest.expectAssertions(0, 1);
+}
+
 /** Test for Bug 413310 **/
 
 // NOTE: If we ever make subframes do bfcache stuff, this test will need to be
 // modified accordingly!  It assumes that subframes do NOT get bfcached.
 var onloadCount = 0;
 
 var step = -1;  // One increment will come from the initial subframe onload.
                 // Note that this script should come before the subframe,
--- a/dom/base/nsFocusManager.cpp
+++ b/dom/base/nsFocusManager.cpp
@@ -1147,31 +1147,32 @@ nsFocusManager::SetFocusInner(nsIContent
   if (dsti) {
     nsCOMPtr<nsIDocShellTreeItem> root;
     dsti->GetRootTreeItem(getter_AddRefs(root));
     newRootWindow = do_GetInterface(root);
 
     isElementInActiveWindow = (mActiveWindow && newRootWindow == mActiveWindow);
   }
 
-  // Exit full-screen if we're focusing a windowed plugin on a non-MacOSX
+  // Exit fullscreen if we're focusing a windowed plugin on a non-MacOSX
   // system. We don't control event dispatch to windowed plugins on non-MacOSX,
-  // so we can't display the "Press ESC to leave full-screen mode" warning on
-  // key input if a windowed plugin is focused, so just exit full-screen
+  // so we can't display the "Press ESC to leave fullscreen mode" warning on
+  // key input if a windowed plugin is focused, so just exit fullscreen
   // to guard against phishing.
 #ifndef XP_MACOSX
+  nsIDocument* fullscreenAncestor;
   if (contentToFocus &&
-      nsContentUtils::GetRootDocument(contentToFocus->OwnerDoc())->IsFullScreenDoc() &&
+      (fullscreenAncestor = nsContentUtils::GetFullscreenAncestor(contentToFocus->OwnerDoc())) &&
       nsContentUtils::HasPluginWithUncontrolledEventDispatch(contentToFocus)) {
     nsContentUtils::ReportToConsole(nsIScriptError::warningFlag,
                                     "DOM",
                                     contentToFocus->OwnerDoc(),
                                     nsContentUtils::eDOM_PROPERTIES,
                                     "FocusedWindowedPluginWhileFullScreen");
-    nsIDocument::ExitFullscreen(contentToFocus->OwnerDoc(), /* async */ true);
+    nsIDocument::ExitFullscreen(fullscreenAncestor, /* async */ true);
   }
 #endif
 
   // if the FLAG_NOSWITCHFRAME flag is used, only allow the focus to be
   // shifted away from the current element if the new shell to focus is
   // the same or an ancestor shell of the currently focused shell.
   bool allowFrameSwitch = !(aFlags & FLAG_NOSWITCHFRAME) ||
                             IsSameOrAncestor(newWindow, mFocusedWindow);
--- a/dom/browser-element/BrowserElementPanning.js
+++ b/dom/browser-element/BrowserElementPanning.js
@@ -8,16 +8,18 @@
 "use strict";
 dump("############################### browserElementPanning.js loaded\n");
 
 let { classes: Cc, interfaces: Ci, results: Cr, utils: Cu }  = Components;
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://gre/modules/Geometry.jsm");
 
+var global = this;
+
 const ContentPanning = {
   // Are we listening to touch or mouse events?
   watchedEventsType: '',
 
   // Are mouse events being delivered to this content along with touch
   // events, in violation of spec?
   hybridEvents: false,
 
@@ -37,18 +39,26 @@ const ContentPanning = {
                            .processType == Ci.nsIXULRuntime.PROCESS_TYPE_DEFAULT;
       this.hybridEvents = isParentProcess;
 #endif
     } catch(e) {
       // Touch events aren't supported, so fall back on mouse.
       events = ['mousedown', 'mouseup', 'mousemove'];
       this.watchedEventsType = 'mouse';
     }
+
+    let els = Cc["@mozilla.org/eventlistenerservice;1"]
+                .getService(Ci.nsIEventListenerService);
+
     events.forEach(function(type) {
-      addEventListener(type, this, false);
+      // Using the system group for mouse/touch events to avoid
+      // missing events if .stopPropagation() has been called.
+      els.addSystemEventListener(global, type,
+                                 this.handleEvent.bind(this),
+                                 /* useCapture = */ false);
     }.bind(this));
 
     addMessageListener("Viewport:Change", this._recvViewportChange.bind(this));
     addMessageListener("Gesture:DoubleTap", this._recvDoubleTap.bind(this));
   },
 
   handleEvent: function cp_handleEvent(evt) {
     if (evt.defaultPrevented)
--- a/dom/browser-element/BrowserElementPromptService.jsm
+++ b/dom/browser-element/BrowserElementPromptService.jsm
@@ -452,34 +452,26 @@ AuthPromptWrapper.prototype = {
       return true;
     } catch (e) {
       return false;
     }
   }
 };
 
 function BrowserElementPromptFactory(toWrap) {
+  // this._wrapped may be null.
   this._wrapped = toWrap;
 }
 
 BrowserElementPromptFactory.prototype = {
   classID: Components.ID("{24f3d0cf-e417-4b85-9017-c9ecf8bb1299}"),
   QueryInterface: XPCOMUtils.generateQI([Ci.nsIPromptFactory]),
 
-  _mayUseNativePrompt: function() {
-    try {
-      return Services.prefs.getBoolPref("browser.prompt.allowNative");
-    } catch (e) {
-      // This properity is default to true.
-      return true;
-    }
-  },
-
   _getNativePromptIfAllowed: function(win, iid, err) {
-    if (this._mayUseNativePrompt())
+    if (this._wrapped)
       return this._wrapped.getPrompt(win, iid);
     else {
       // Not allowed, throw an exception.
       throw err;
     }
   },
 
   getPrompt: function(win, iid) {
@@ -512,17 +504,17 @@ BrowserElementPromptFactory.prototype = 
         return new BrowserElementAuthPrompt().QueryInterface(iid);
       }
 
       // Because nsIAuthPrompt2 is called in parent process. If caller
       // wants nsIAuthPrompt2 and we cannot get BrowserElementchild,
       // it doesn't mean that we should fallback. It is possible that we can
       // get the BrowserElementParent from nsIChannel that passed to
       // functions of nsIAuthPrompt2.
-      if (this._mayUseNativePrompt()) {
+      if (this._wrapped) {
         return new AuthPromptWrapper(
             this._wrapped.getPrompt(win, iid),
             new BrowserElementAuthPrompt().QueryInterface(iid))
           .QueryInterface(iid);
       } else {
         // Falling back is not allowed, so we don't need wrap the
         // BrowserElementPrompt.
         return new BrowserElementAuthPrompt().QueryInterface(iid);
@@ -542,16 +534,25 @@ BrowserElementPromptFactory.prototype = 
 };
 
 this.BrowserElementPromptService = {
   QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver,
                                          Ci.nsISupportsWeakReference]),
 
   _initialized: false,
 
+  _mayUseNativePrompt: function() {
+    try {
+      return Services.prefs.getBoolPref("browser.prompt.allowNative");
+    } catch (e) {
+      // This properity defaults to true.
+      return true;
+    }
+  },
+
   _init: function() {
     if (this._initialized) {
       return;
     }
 
     // If the pref is disabled, do nothing except wait for the pref to change.
     if (!this._browserFramesPrefEnabled()) {
       var prefs = Cc["@mozilla.org/preferences-service;1"].getService(Ci.nsIPrefBranch);
@@ -560,31 +561,37 @@ this.BrowserElementPromptService = {
     }
 
     this._initialized = true;
     this._browserElementParentMap = new WeakMap();
 
     var os = Cc["@mozilla.org/observer-service;1"].getService(Ci.nsIObserverService);
     os.addObserver(this, "outer-window-destroyed", /* ownsWeak = */ true);
 
-    // Wrap the existing @mozilla.org/prompter;1 implementation.
-    var contractID = "@mozilla.org/prompter;1";
-    var oldCID = Cm.contractIDToCID(contractID);
+    var oldPromptFactory = null;
     var newCID = BrowserElementPromptFactory.prototype.classID;
-    var oldFactory = Cm.getClassObject(Cc[contractID], Ci.nsIFactory);
+    if (this._mayUseNativePrompt()) {
+      // Wrap the existing @mozilla.org/prompter;1 implementation.  (Don't even
+      // try to get the prompter;1 if we may not use the native prompter.  We
+      // won't need it, and merely getting it is causing bug 844530.)
+      var contractID = "@mozilla.org/prompter;1";
+      var oldCID = Cm.contractIDToCID(contractID);
+      var oldFactory = Cm.getClassObject(Cc[contractID], Ci.nsIFactory);
 
-    if (oldCID == newCID) {
-      debug("WARNING: Wrapped prompt factory is already installed!");
-      return;
+      if (oldCID == newCID) {
+        debug("WARNING: Wrapped prompt factory is already installed!");
+        return;
+      }
+
+      Cm.unregisterFactory(oldCID, oldFactory);
+
+      oldPromptFactory = oldFactory.createInstance(null, Ci.nsIPromptFactory);
     }
 
-    Cm.unregisterFactory(oldCID, oldFactory);
-
-    var oldInstance = oldFactory.createInstance(null, Ci.nsIPromptFactory);
-    var newInstance = new BrowserElementPromptFactory(oldInstance);
+    var newInstance = new BrowserElementPromptFactory(oldPromptFactory);
 
     var newFactory = {
       createInstance: function(outer, iid) {
         if (outer != null) {
           throw Cr.NS_ERROR_NO_AGGREGATION;
         }
         return newInstance.QueryInterface(iid);
       }
--- a/dom/locales/en-US/chrome/dom/dom.properties
+++ b/dom/locales/en-US/chrome/dom/dom.properties
@@ -75,16 +75,17 @@ FullScreenDeniedHidden=Request for full-
 FullScreenDeniedIframeNotAllowed=Request for full-screen was denied because at least one of the document's containing iframes does not have an "allowfullscreen" attribute.
 FullScreenDeniedNotInputDriven=Request for full-screen was denied because Element.mozRequestFullScreen() was not called from inside a short running user-generated event handler.
 FullScreenDeniedNotInDocument=Request for full-screen was denied because requesting element is no longer in its document.
 FullScreenDeniedMovedDocument=Request for full-screen was denied because requesting element has moved document.
 FullScreenDeniedLostWindow=Request for full-screen was denied because we no longer have a window.
 FullScreenDeniedSubDocFullScreen=Request for full-screen was denied because a subdocument of the document requesting full-screen is already full-screen.
 FullScreenDeniedNotDescendant=Request for full-screen was denied because requesting element is not a descendant of the current full-screen element.
 FullScreenDeniedNotFocusedTab=Request for full-screen was denied because requesting element is not in the currently focused tab.
+FullScreenDeniedContentOnly=Request for full-screen was denied because requesting element is in the chrome document and the fullscreen API is configured for content only.
 RemovedFullScreenElement=Exited full-screen because full-screen element was removed from document.
 FocusedWindowedPluginWhileFullScreen=Exited full-screen because windowed plugin was focused.
 HTMLMultipartXHRWarning=HTML parsing in XMLHttpRequest is not supported for multipart responses.
 HTMLSyncXHRWarning=HTML parsing in XMLHttpRequest is not supported in the synchronous mode.
 MultipartXHRWarning=Support for multipart responses in XMLHttpRequest is going to be removed in an upcoming version. Please migrate to chunked responses or to Web Sockets.
 InvalidRedirectChannelWarning=Unable to redirect to %S because the channel doesn't implement nsIWritablePropertyBag2.
 ReportOnlyCSPIgnored=Report-only CSP policy will be ignored because there are other non-report-only CSP policies applied.
 ResponseTypeSyncXHRWarning=Use of XMLHttpRequest's responseType attribute is no longer supported in the synchronous mode in window context.
--- a/dom/locales/en-US/chrome/plugins.properties
+++ b/dom/locales/en-US/chrome/plugins.properties
@@ -4,17 +4,15 @@
 
 # LOCALIZATION NOTE (plugins.properties):
 #    Those strings are inserted into an HTML page, so you all HTML characters
 #    have to be escaped in a way that they show up correctly in HTML!
 
 title_label=About Plugins
 enabledplugins_label=Enabled plugins
 nopluginsareenabled_label=No enabled plugins found
-findmore_label=Find more information about browser plugins at
 findpluginupdates_label=Find updates for installed plugins at
-installhelp_label=Help for installing plugins is available from
 file_label=File:
 version_label=Version:
 state_label=State:
 mimetype_label=MIME Type
 description_label=Description
 suffixes_label=Suffixes
--- a/dom/media/tests/mochitest/test_peerConnection_basicAudio.html
+++ b/dom/media/tests/mochitest/test_peerConnection_basicAudio.html
@@ -16,16 +16,20 @@ https://bugzilla.mozilla.org/show_bug.cg
 <p id="display"></p>
 <div id="content" style="display: none">
   <audio id="audioPCLocal" controls></audio>
   <audio id="audioPCRemote" controls></audio>
   <audio id="audioLocal" controls></audio>
 </div>
 <pre id="test">
 <script type="application/javascript">
+  if (navigator.platform.startsWith("Win")) {
+    SimpleTest.expectAssertions(0, 1);
+  }
+
   var audioLocal;
   var audioPCLocal;
   var audioPCRemote;
 
   var pcLocal;
   var pcRemote;
 
   var test_data = {
--- a/dom/media/tests/mochitest/test_peerConnection_basicAudioVideo.html
+++ b/dom/media/tests/mochitest/test_peerConnection_basicAudioVideo.html
@@ -20,21 +20,21 @@ https://bugzilla.mozilla.org/show_bug.cg
   <video id="videoPCLocal" width="160" height="120" controls></video>
   <video id="videoPCRemote" width="160" height="120" controls></video>
   <video id="videoLocal" width="160" height="120" controls></video>
 </div>
 <pre id="test">
 <script type="application/javascript">
 
 if (navigator.platform.startsWith("Win")) {
-  SimpleTest.expectAssertions(0, 9);
+  SimpleTest.expectAssertions(0, 41);
 } else if (navigator.platform.startsWith("Mac")) {
   SimpleTest.expectAssertions(0, 2);
-} else {
-  SimpleTest.expectAssertions(0, 1);
+} else if (navigator.platform.startsWith("Linux")) {
+  SimpleTest.expectAssertions(0, 6);
 }
 
   var audioLocal;
   var audioPCLocal;
   var audioPCRemote;
 
   var videoLocal;
   var videoPCLocal;
--- a/dom/media/tests/mochitest/test_peerConnection_basicAudioVideoCombined.html
+++ b/dom/media/tests/mochitest/test_peerConnection_basicAudioVideoCombined.html
@@ -19,17 +19,17 @@ https://bugzilla.mozilla.org/show_bug.cg
 
   <video id="videoPCLocal" width="160" height="120" controls></video>
   <video id="videoPCRemote" width="160" height="120" controls></video>
   <video id="videoLocal" width="160" height="120" controls></video>
 </div>
 <pre id="test">
 <script type="application/javascript">
 
-  SimpleTest.expectAssertions(0, 1);
+  SimpleTest.expectAssertions(0, 13);
 
   var audioLocal;
   var videoLocal;
   var videoPCLocal;
   var videoPCRemote;
 
   var pcLocal;
   var pcRemote;
--- a/dom/media/tests/mochitest/test_peerConnection_bug825703.html
+++ b/dom/media/tests/mochitest/test_peerConnection_bug825703.html
@@ -13,16 +13,19 @@ https://bugzilla.mozilla.org/show_bug.cg
   </meta>
 </head>
 <body>
 <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=825703">RTCConfiguration valid/invalid permutations</a>
 <p id="display"></p>
 <pre id="test">
 <script class="testbody" type="application/javascript">
 runTest(function () {
+  if (navigator.platform.startsWith("Win")) {
+    SimpleTest.expectAssertions(0, 80);
+  }
   var pc;
   var pcs;
   var exception = null;
   try { pcs = new mozRTCPeerConnection(); } catch (e) { exception = e; }
   ok(!exception, "mozRTCPeerConnection() succeeds");
   exception = null;
   try { pc = new mozRTCPeerConnection(1); } catch (e) { exception = e; }
   ok(exception, "mozRTCPeerConnection(1) throws");
--- a/dom/media/tests/mochitest/test_peerConnection_bug827843.html
+++ b/dom/media/tests/mochitest/test_peerConnection_bug827843.html
@@ -16,16 +16,20 @@ https://bugzilla.mozilla.org/show_bug.cg
 <p id="display"></p>
 <div id="content" style="display: none">
   <audio id="audioPCLocal" controls></audio>
   <audio id="audioPCRemote" controls></audio>
   <audio id="audioLocal" controls></audio>
 </div>
 <pre id="test">
 <script type="application/javascript">
+  if (navigator.platform.startsWith("Win")) {
+    SimpleTest.expectAssertions(0, 200);
+  }
+  
   var audioLocal;
   var audioPCLocal;
   var audioPCRemote;
 
   var pcLocal;
   var pcRemote;
 
   var test_data = {
--- a/dom/media/tests/mochitest/test_peerConnection_bug834153.html
+++ b/dom/media/tests/mochitest/test_peerConnection_bug834153.html
@@ -12,16 +12,20 @@ https://bugzilla.mozilla.org/show_bug.cg
     <script type="application/javascript" src="head.js"></script>
   </meta>
 </head>
 <body>
 <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=834153">Queue CreateAnswer in PeerConnection.js</a>
 <p id="display"></p>
 <pre id="test">
 <script class="testbody" type="application/javascript">
+if (navigator.platform.startsWith("Win")) {
+  SimpleTest.expectAssertions(0, 369);
+}
+
 function croak(msg) {
   ok(0,msg);
   SimpleTest.finish();
 }
 
 runTest(function () {
   var pc1;
 
--- a/dom/media/tests/mochitest/test_peerConnection_bug835370.html
+++ b/dom/media/tests/mochitest/test_peerConnection_bug835370.html
@@ -12,16 +12,19 @@ https://bugzilla.mozilla.org/show_bug.cg
     <script type="application/javascript" src="head.js"></script>
   </meta>
 </head>
 <body>
 <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=825703">PeerConnection.createOffer constraints valid/invalid constraints permutations</a>
 <p id="display"></p>
 <pre id="test">
 <script class="testbody" type="application/javascript">
+if (navigator.platform.startsWith("Win")) {
+  SimpleTest.expectAssertions(0, 9);
+}
 runTest(function () {
   var pconnect  = new mozRTCPeerConnection();
   var pconnects = new mozRTCPeerConnection();
 
   function step1(offer) {}
   function failed(code) {}
 
   var exception = null;
--- a/dom/media/tests/mochitest/test_peerConnection_bug840344.html
+++ b/dom/media/tests/mochitest/test_peerConnection_bug840344.html
@@ -16,16 +16,22 @@ https://bugzilla.mozilla.org/show_bug.cg
 <body>
 <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=840344">
 Bug 840344</a>
 <p id="display"></p>
 <pre id="test">
 
 <script class="testbody" type="application/javascript">
 
+  if (navigator.platform.startsWith("Linux")) {
+    SimpleTest.expectAssertions(0, 1);
+  } else if (navigator.platform.startsWith("Win")) {
+    SimpleTest.expectAssertions(0, 125);
+  }
+
   runTest(function () {
     var answerCount = 0;
     var setLocalCount = 0;
 
     // SDP to stand in for an offer coming from a (theoretical) remote endpoint
     var offer = { sdp: "v=0\r\n"+
           "o=Mozilla-SIPUA 23597 0 IN IP4 0.0.0.0\r\n"+
           "s=SIP Call\r\n"+
--- a/dom/network/tests/test_network_basics.html
+++ b/dom/network/tests/test_network_basics.html
@@ -7,17 +7,21 @@
 </head>
 <body>
 <p id="display"></p>
 <div id="content" style="display: none">
 </div>
 <pre id="test">
 <script type="application/javascript">
 
-SimpleTest.expectAssertions(11);
+if (navigator.platform.startsWith("Win")) {
+  SimpleTest.expectAssertions(11, 38);
+} else {
+  SimpleTest.expectAssertions(11);
+}
 
 /** Test for Network API **/
 
 function checkInterface(aInterface) {
   ok(!(aInterface in window), aInterface + " should be prefixed");
   ok(("Moz" + aInterface) in window, aInterface + " should be prefixed");
 }
 
--- a/dom/network/tests/test_tcpsocket_default_permissions.html
+++ b/dom/network/tests/test_tcpsocket_default_permissions.html
@@ -7,16 +7,20 @@
 </head>
 <body>
 <p id="display"></p>
 <div id="content" style="display: none">
 </div>
 <pre id="test">
 <script type="application/javascript">
 
+if (navigator.platform.startsWith("Win")) {
+  SimpleTest.expectAssertions(0, 13);
+}
+
 /** Test to ensure TCPSocket permission is disabled by default **/
 
 try {
   navigator.mozTCPSocket;
   throw new Error("Error: navigator.mozTCPSocket should not exist by default");
 } catch (e) {
   ok(true, "navigator.mozTCPSocket should not exist by default");  
 }
--- a/dom/network/tests/test_tcpsocket_enabled_no_perm.html
+++ b/dom/network/tests/test_tcpsocket_enabled_no_perm.html
@@ -7,16 +7,20 @@
 </head>
 <body>
 <p id="display"></p>
 <div id="content" style="display: none">
 </div>
 <pre id="test">
 <script type="application/javascript">
 
+if (navigator.platform.startsWith("Win")) {
+  SimpleTest.expectAssertions(0, 15);
+}
+
 /** Test to ensure TCPSocket permission being turned on enables 
   navigator.mozTCPSocket, but mozTCPSocket.open does not work
   in content.
 **/
 SpecialPowers.setBoolPref("dom.mozTCPSocket.enabled", true);
 
 ok('mozTCPSocket' in navigator, "navigator.mozTCPSocket should be accessible if dom.mozTCPSocket.enabled is true");
 
--- a/dom/network/tests/test_tcpsocket_enabled_with_perm.html
+++ b/dom/network/tests/test_tcpsocket_enabled_with_perm.html
@@ -9,16 +9,18 @@
 <p id="display"></p>
 <div id="content" style="display: none">
 </div>
 <pre id="test">
 <script type="application/javascript">
 
 if (navigator.platform.startsWith("Linux")) {
   SimpleTest.expectAssertions(0, 1);
+} else if (navigator.platform.startsWith("Win")) {
+  SimpleTest.expectAssertions(0, 11);
 }
 
 /** Test to ensure TCPSocket permission being turned on enables 
   navigator.mozTCPSocket, and mozTCPSocket.open works when
   the tcp-socket permission has been granted.
 **/
 SpecialPowers.setBoolPref("dom.mozTCPSocket.enabled", true);
 SpecialPowers.addPermission("tcp-socket", true, document);
--- a/dom/permission/tests/test_permission_basics.html
+++ b/dom/permission/tests/test_permission_basics.html
@@ -16,17 +16,19 @@ https://bugzilla.mozilla.org/show_bug.cg
 <div id="content" style="display: none">
 
 </div>
 <pre id="test">
 <script class="testbody" type="text/javascript">
 
 "use strict";
 
-if (!navigator.platform.startsWith("Win")) {
+if (navigator.platform.startsWith("Win")) {
+  SimpleTest.expectAssertions(0, 34);
+} else {
   SimpleTest.expectAssertions(0, 1);
 }
 
 var testPrivApp = {
   'manifestURL' : 'https://aprivileged.com/manifest.webapp'
 };
 
 var testCertApp = {
--- a/dom/plugins/base/Makefile.in
+++ b/dom/plugins/base/Makefile.in
@@ -67,19 +67,17 @@ CPPSRCS		= \
 		$(NULL)
 
 ifeq ($(MOZ_WIDGET_TOOLKIT),android)
 LOCAL_INCLUDES += -I$(topsrcdir)/dom/plugins/base/android
 else
 # android_npapi.h extends the NPNVariable and NPPVariable enums
 # using #defines, which results in Wswitch warnings in gcc-4.6.
 # Therefore, enable FAIL_ON_WARNINGS only on non-Android platforms.
-ifndef _MSC_VER
 FAIL_ON_WARNINGS := 1
-endif # !_MSC_VER
 endif
 
 ifeq ($(OS_ARCH),WINNT)
 	CPPSRCS += nsPluginsDirWin.cpp
 	CPPSRCS += nsPluginNativeWindowWin.cpp
 	CPPSRCS += nsPluginDirServiceProvider.cpp
 	LOCAL_INCLUDES += -I$(topsrcdir)/xpcom/base
 else
--- a/dom/plugins/base/nsPluginHost.cpp
+++ b/dom/plugins/base/nsPluginHost.cpp
@@ -2638,17 +2638,20 @@ nsPluginHost::ReadPluginInfo()
   if (NS_FAILED(rv))
     return rv;
 
   int64_t fileSize;
   rv = pluginReg->GetFileSize(&fileSize);
   if (NS_FAILED(rv))
     return rv;
 
-  int32_t flen = int64_t(fileSize);
+  if (fileSize > INT32_MAX) {
+    return NS_ERROR_FAILURE;
+  }
+  int32_t flen = int32_t(fileSize);
   if (flen == 0) {
     NS_WARNING("Plugins Registry Empty!");
     return NS_OK; // ERROR CONDITION
   }
 
   nsPluginManifestLineReader reader;
   char* registry = reader.Init(flen);
   if (!registry)
--- a/dom/plugins/base/nsPluginStreamListenerPeer.cpp
+++ b/dom/plugins/base/nsPluginStreamListenerPeer.cpp
@@ -509,28 +509,28 @@ nsPluginStreamListenerPeer::OnStartReque
   if (loadGroup)
     mWeakPtrChannelLoadGroup = do_GetWeakReference(loadGroup);
 
   int64_t length;
   rv = channel->GetContentLength(&length);
 
   // it's possible for the server to not send a Content-Length.
   // we should still work in this case.
-  if (NS_FAILED(rv) || length == -1) {
+  if (NS_FAILED(rv) || length < 0 || length > UINT32_MAX) {
     // check out if this is file channel
     nsCOMPtr<nsIFileChannel> fileChannel = do_QueryInterface(channel);
     if (fileChannel) {
       // file does not exist
       mRequestFailed = true;
       return NS_ERROR_FAILURE;
     }
     mLength = 0;
   }
   else {
-    mLength = length;
+    mLength = uint32_t(length);
   }
 
   nsAutoCString aContentType; // XXX but we already got the type above!
   rv = channel->GetContentType(aContentType);
   if (NS_FAILED(rv))
     return rv;
 
   nsCOMPtr<nsIURI> aURL;
--- a/dom/plugins/ipc/BrowserStreamChild.cpp
+++ b/dom/plugins/ipc/BrowserStreamChild.cpp
@@ -25,17 +25,17 @@ BrowserStreamChild::BrowserStreamChild(P
   , mDestroyPending(NOT_DESTROYED)
   , mNotifyPending(false)
   , mStreamAsFilePending(false)
   , mInstanceDying(false)
   , mState(CONSTRUCTING)
   , mURL(url)
   , mHeaders(headers)
   , mStreamNotify(notifyData)
-  , mDeliveryTracker(this)
+  , ALLOW_THIS_IN_INITIALIZER_LIST(mDeliveryTracker(this))
 {
   PLUGIN_LOG_DEBUG(("%s (%s, %i, %i, %p, %s, %s)", FULLFUNCTION,
                     url.get(), length, lastmodified, (void*) notifyData,
                     headers.get(), mimeType.get()));
 
   AssertPluginThread();
 
   memset(&mStream, 0, sizeof(mStream));
--- a/dom/plugins/ipc/Makefile.in
+++ b/dom/plugins/ipc/Makefile.in
@@ -5,19 +5,17 @@
 DEPTH = @DEPTH@
 topsrcdir = @top_srcdir@
 srcdir = @srcdir@
 VPATH = @srcdir@
 
 include $(DEPTH)/config/autoconf.mk
 
 MODULE = dom
-ifndef _MSC_VER
 FAIL_ON_WARNINGS := 1
-endif # !_MSC_VER
 
 EXPORTS_NAMESPACES = mozilla
 
 EXPORTS_mozilla = \
   PluginLibrary.h \
   $(NULL)
 
 EXPORTS_NAMESPACES = mozilla mozilla/plugins
--- a/dom/plugins/ipc/PluginInstanceChild.cpp
+++ b/dom/plugins/ipc/PluginInstanceChild.cpp
@@ -2654,18 +2654,16 @@ PluginInstanceChild::NPN_SetCurrentAsync
                                 RemoteImageData::BGRX32 : RemoteImageData::BGRA32;
                 data->mBitmap.mStride = surface->bitmap.stride;
                 data->mWasUpdated = true;
                 break;
             }
 #ifdef XP_WIN
         case NPDrawingModelAsyncWindowsDXGISurface:
             {
-                AsyncBitmapData *bitmapData;
-              
                 CrossProcessMutexAutoLock autoLock(*mRemoteImageDataMutex);
                 data->mType = RemoteImageData::DXGI_TEXTURE_HANDLE;
                 data->mSize = gfxIntSize(surface->size.width, surface->size.height);
                 data->mFormat = surface->format == NPImageFormatBGRX32 ?
                                 RemoteImageData::BGRX32 : RemoteImageData::BGRA32;
                 data->mTextureHandle = surface->sharedHandle;
 
                 data->mWasUpdated = true;
--- a/dom/plugins/ipc/PluginModuleParent.cpp
+++ b/dom/plugins/ipc/PluginModuleParent.cpp
@@ -111,17 +111,17 @@ PluginModuleParent::LoadModule(const cha
 
 PluginModuleParent::PluginModuleParent(const char* aFilePath)
     : mSubprocess(new PluginProcessParent(aFilePath))
     , mShutdown(false)
     , mClearSiteDataSupported(false)
     , mGetSitesWithDataSupported(false)
     , mNPNIface(NULL)
     , mPlugin(NULL)
-    , mTaskFactory(this)
+    , ALLOW_THIS_IN_INITIALIZER_LIST(mTaskFactory(this))
 #ifdef XP_WIN
     , mPluginCpuUsageOnHang()
     , mHangUIParent(nullptr)
     , mHangUIEnabled(true)
     , mIsTimerReset(true)
 #endif
 #ifdef MOZ_CRASHREPORTER_INJECTOR
     , mFlashProcess1(0)
@@ -452,25 +452,28 @@ PluginModuleParent::TerminateChildProces
         NS_WARNING("failed to capture paired minidumps from hang");
     }
 #endif
 
 #ifdef XP_WIN
     // collect cpu usage for plugin processes
 
     InfallibleTArray<base::ProcessHandle> processHandles;
-    base::ProcessHandle handle;
 
     processHandles.AppendElement(OtherProcess());
+
 #ifdef MOZ_CRASHREPORTER_INJECTOR
-    if (mFlashProcess1 && base::OpenProcessHandle(mFlashProcess1, &handle)) {
-      processHandles.AppendElement(handle);
-    }
-    if (mFlashProcess2 && base::OpenProcessHandle(mFlashProcess2, &handle)) {
-      processHandles.AppendElement(handle);
+    {
+      base::ProcessHandle handle;
+      if (mFlashProcess1 && base::OpenProcessHandle(mFlashProcess1, &handle)) {
+        processHandles.AppendElement(handle);
+      }
+      if (mFlashProcess2 && base::OpenProcessHandle(mFlashProcess2, &handle)) {
+        processHandles.AppendElement(handle);
+      }
     }
 #endif
 
     if (!GetProcessCpuUsage(processHandles, mPluginCpuUsageOnHang)) {
       mPluginCpuUsageOnHang.Clear();
     }
 #endif
 
--- a/dom/plugins/ipc/hangui/PluginHangUIChild.cpp
+++ b/dom/plugins/ipc/hangui/PluginHangUIChild.cpp
@@ -7,21 +7,39 @@
 #include "PluginHangUI.h"
 
 #include "PluginHangUIChild.h"
 #include "HangUIDlg.h"
 
 #include <assert.h>
 #include <commctrl.h>
 #include <windowsx.h>
+#include <algorithm>
 #include <sstream>
+#include <vector>
 
 namespace mozilla {
 namespace plugins {
 
+struct WinInfo
+{
+  WinInfo(HWND aHwnd, POINT& aPos, SIZE& aSize)
+    :hwnd(aHwnd)
+  {
+    pos.x = aPos.x;
+    pos.y = aPos.y;
+    size.cx = aSize.cx;
+    size.cy = aSize.cy;
+  }
+  HWND  hwnd;
+  POINT pos;
+  SIZE  size;
+};
+typedef std::vector<WinInfo> WinInfoVec;
+
 PluginHangUIChild* PluginHangUIChild::sSelf = nullptr;
 const int PluginHangUIChild::kExpectedMinimumArgc = 10;
 const DWORD PluginHangUIChild::kProcessTimeout = 1200000U;
 const DWORD PluginHangUIChild::kShmTimeout = 5000U;
 
 PluginHangUIChild::PluginHangUIChild()
   : mResponseBits(0),
     mParentWindow(NULL),
@@ -119,16 +137,105 @@ PluginHangUIChild::SHangUIDlgProc(HWND a
 {
   PluginHangUIChild *self = PluginHangUIChild::sSelf;
   if (self) {
     return self->HangUIDlgProc(aDlgHandle, aMsgCode, aWParam, aLParam);
   }
   return FALSE;
 }
 
+void
+PluginHangUIChild::ResizeButtons()
+{
+  // Control IDs are specified right-to-left as they appear in the dialog
+  UINT ids[] = { IDC_STOP, IDC_CONTINUE };
+  UINT numIds = sizeof(ids)/sizeof(ids[0]);
+
+  // Pass 1: Compute the ideal size
+  bool needResizing = false;
+  SIZE idealSize = {0};
+  WinInfoVec winInfo;
+  for (UINT i = 0; i < numIds; ++i) {
+    HWND wnd = GetDlgItem(mDlgHandle, ids[i]);
+    if (!wnd) {
+      return;
+    }
+
+    // Get the button's dimensions in screen coordinates
+    RECT curRect;
+    if (!GetWindowRect(wnd, &curRect)) {
+      return;
+    }
+
+    // Get (x,y) position of the button in client coordinates
+    POINT pt;
+    pt.x = curRect.left;
+    pt.y = curRect.top;
+    if (!ScreenToClient(mDlgHandle, &pt)) {
+      return;
+    }
+
+    // Request the button's text margins
+    RECT margins;
+    if (!Button_GetTextMargin(wnd, &margins)) {
+      return;
+    }
+
+    // Compute the button's width and height
+    SIZE curSize;
+    curSize.cx = curRect.right - curRect.left;
+    curSize.cy = curRect.bottom - curRect.top;
+
+    // Request the button's ideal width and height and add in the margins
+    SIZE size = {0};
+    if (!Button_GetIdealSize(wnd, &size)) {
+      return;
+    }
+    size.cx += margins.left + margins.right;
+    size.cy += margins.top + margins.bottom;
+
+    // Size all buttons to be the same width as the longest button encountered
+    idealSize.cx = std::max(idealSize.cx, size.cx);
+    idealSize.cy = std::max(idealSize.cy, size.cy);
+
+    // We won't bother resizing unless we need extra space
+    if (idealSize.cx > curSize.cx) {
+      needResizing = true;
+    }
+
+    // Save the relevant info for the resize, if any. We do this even if 
+    // needResizing is false because another button may trigger a resize later.
+    winInfo.push_back(WinInfo(wnd, pt, curSize));
+  }
+
+  if (!needResizing) {
+    return;
+  }
+
+  // Pass 2: Resize the windows
+  int deltaX = 0;
+  HDWP hwp = BeginDeferWindowPos((int) winInfo.size());
+  if (!hwp) {
+    return;
+  }
+  for (WinInfoVec::const_iterator itr = winInfo.begin();
+       itr != winInfo.end(); ++itr) {
+    // deltaX accumulates the size changes so that each button's x coordinate 
+    // can compensate for the width increases
+    deltaX += idealSize.cx - itr->size.cx;
+    hwp = DeferWindowPos(hwp, itr->hwnd, NULL, itr->pos.x - deltaX, itr->pos.y,
+                         idealSize.cx, itr->size.cy,
+                         SWP_NOZORDER | SWP_NOACTIVATE);
+    if (!hwp) {
+      return;
+    }
+  }
+  EndDeferWindowPos(hwp);
+}
+
 INT_PTR
 PluginHangUIChild::HangUIDlgProc(HWND aDlgHandle, UINT aMsgCode, WPARAM aWParam,
                                  LPARAM aLParam)
 {
   mDlgHandle = aDlgHandle;
   switch (aMsgCode) {
     case WM_INITDIALOG: {
       // Register a wait on the Firefox process so that we will be informed
@@ -139,16 +246,17 @@ PluginHangUIChild::HangUIDlgProc(HWND aD
                                   this,
                                   INFINITE,
                                   WT_EXECUTEDEFAULT | WT_EXECUTEONLYONCE);
       SetWindowText(aDlgHandle, mWindowTitle);
       SetDlgItemText(aDlgHandle, IDC_MSG, mMessageText);
       SetDlgItemText(aDlgHandle, IDC_NOFUTURE, mNoFutureText);
       SetDlgItemText(aDlgHandle, IDC_CONTINUE, mWaitBtnText);
       SetDlgItemText(aDlgHandle, IDC_STOP, mKillBtnText);
+      ResizeButtons();
       HANDLE icon = LoadImage(NULL, IDI_QUESTION, IMAGE_ICON, 0, 0,
                               LR_DEFAULTSIZE | LR_SHARED);
       if (icon) {
         SendDlgItemMessage(aDlgHandle, IDC_DLGICON, STM_SETICON, (WPARAM)icon, 0);
       }
       EnableWindow(mParentWindow, FALSE);
       return TRUE;
     }
--- a/dom/plugins/ipc/hangui/PluginHangUIChild.h
+++ b/dom/plugins/ipc/hangui/PluginHangUIChild.h
@@ -62,16 +62,19 @@ private:
   RecvShow();
 
   bool
   RecvCancel();
 
   bool
   SetMainThread();
 
+  void
+  ResizeButtons();
+
   INT_PTR
   HangUIDlgProc(HWND aDlgHandle, UINT aMsgCode, WPARAM aWParam, LPARAM aLParam);
 
   static VOID CALLBACK
   ShowAPC(ULONG_PTR aContext);
 
   static INT_PTR CALLBACK
   SHangUIDlgProc(HWND aDlgHandle, UINT aMsgCode, WPARAM aWParam,
--- a/dom/plugins/test/mochitest/test_GCrace.html
+++ b/dom/plugins/test/mochitest/test_GCrace.html
@@ -16,17 +16,17 @@
     function start() {
       if (!SimpleTest.testPluginIsOOP()) {
         ok(true, "Skipping this test when test plugin is not OOP.");
         SimpleTest.finish();
         return;
       }
       else {
         if (navigator.platform.startsWith("Win")) {
-          SimpleTest.expectAssertions(0, 250);
+          SimpleTest.expectAssertions(0, 350);
         } else {
           SimpleTest.expectAssertions(0, 1);
         }
 
         setTimeout(checkGCRace, 1000);
       }
     }
 
--- a/dom/plugins/test/mochitest/test_twostreams.html
+++ b/dom/plugins/test/mochitest/test_twostreams.html
@@ -5,17 +5,17 @@
           src="/tests/SimpleTest/SimpleTest.js"></script>
   <link rel="stylesheet" type="text/css" 
         href="/tests/SimpleTest/test.css" />
 </head>
 <body>
   <p id="display"></p>
 
   <script type="text/javascript">
-  SimpleTest.expectAssertions(1, 2);
+  SimpleTest.expectAssertions(0, 2);
 
   SimpleTest.waitForExplicitFinish();
 
   var framesToLoad = 2;
   function frameLoaded(id) {
     var frame = document.getElementById('testframe' + id);
     if (!frame.contentDocument.body.innerHTML.length)
       return;
--- a/dom/tests/mochitest/pointerlock/test_pointerlock-api.html
+++ b/dom/tests/mochitest/pointerlock/test_pointerlock-api.html
@@ -13,20 +13,16 @@ https://bugzilla.mozilla.org/show_bug.cg
     <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=633602">
       Mozilla Bug 633602
     </a>
     <div id="content">
     </div>
     <pre id="test">
       <script type="application/javascript">
 
-        if (!navigator.platform.startsWith("Linux")) {
-          SimpleTest.expectAssertions(0, 1); // bug 845552
-        }
-
         /**
          * Pointer Lock tests for bug 633602.  These depend on the fullscreen api
          * which doesn't work when run in the mochitests' iframe, since the
          * mochitests' iframe doesn't have an allowfullscreen attribute.  To get
          * around this, all tests are run in a child window, which can go fullscreen.
          * This method is borrowed from content/html/content/test/test_fullscreen-api.html.
          **/
 
new file mode 100644
--- /dev/null
+++ b/image/test/crashtests/844403-1.html
@@ -0,0 +1,10 @@
+<color style='background-image: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZlcnNpb249IjEuMSINCiAgICAgd2lkdGg9IjEwMCIgaGVpZ2h0PSIxMDAiPg0KICA8cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSJibHVlIi8%2BDQo8L3N2Zz4NCg%3D%3D");'></color>
+<iframe contenteditable=true></iframe>
+<script>
+  document.body.innerHTML = '';
+  function onload() {
+    e = document.createElementNS("http://www.w3.org/1998/Math/MathML", "share");
+    document.body.appendChild(e);
+  }
+  document.addEventListener("DOMContentLoaded", onload, false);
+</script>
--- a/image/test/crashtests/crashtests.list
+++ b/image/test/crashtests/crashtests.list
@@ -26,8 +26,9 @@ load 256-height.ico
 
 # A 3-frame animated GIF with an inordinate delay between the second and third
 # frame.
 HTTP load delayedframe.sjs
 
 load 681190.html
 skip-if(Android&&smallScreen) load 694165-1.xhtml # nexus-s Android 2.3.6
 load 732319-1.html
+load 844403-1.html
--- a/js/src/ion/TypeOracle.cpp
+++ b/js/src/ion/TypeOracle.cpp
@@ -293,31 +293,37 @@ TypeInferenceOracle::elementReadIsDenseN
     // Check whether the object is a dense array and index is int32 or double.
     StackTypeSet *obj = script->analysis()->poppedTypes(pc, 1);
     StackTypeSet *id = script->analysis()->poppedTypes(pc, 0);
 
     JSValueType idType = id->getKnownTypeTag();
     if (idType != JSVAL_TYPE_INT32 && idType != JSVAL_TYPE_DOUBLE)
         return false;
 
+    if (obj->hasType(types::Type::StringType()))
+        return false;
+
     Class *clasp = obj->getKnownClass();
     return clasp && clasp->isNative();
 }
 
 bool
 TypeInferenceOracle::elementReadIsTypedArray(RawScript script, jsbytecode *pc, int *arrayType)
 {
     // Check whether the object is a typed array and index is int32 or double.
     StackTypeSet *obj = script->analysis()->poppedTypes(pc, 1);
     StackTypeSet *id = DropUnrooted(script)->analysis()->poppedTypes(pc, 0);
 
     JSValueType idType = id->getKnownTypeTag();
     if (idType != JSVAL_TYPE_INT32 && idType != JSVAL_TYPE_DOUBLE)
         return false;
 
+    if (obj->hasType(types::Type::StringType()))
+        return false;
+
     *arrayType = obj->getTypedArrayType();
     if (*arrayType == TypedArray::TYPE_MAX)
         return false;
 
     JS_ASSERT(*arrayType >= 0 && *arrayType < TypedArray::TYPE_MAX);
 
     // Unlike dense arrays, the types of elements in typed arrays are not
     // guaranteed to be present in the object's type, and we need to use
--- a/js/xpconnect/tests/mochitest/test_bug393269.html
+++ b/js/xpconnect/tests/mochitest/test_bug393269.html
@@ -9,21 +9,17 @@ https://bugzilla.mozilla.org/show_bug.cg
   <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=393269">Mozilla Bug 393269</a>
 <iframe id="ifr"></iframe>
 <pre id="test">
 <script class="testbody" type="text/javascript">
 
-if (navigator.platform.startsWith("Win")) {
-  SimpleTest.expectAssertions(1, 2);
-} else {
-  SimpleTest.expectAssertions(2);
-}
+SimpleTest.expectAssertions(1, 2);
 
 (function () {
     /** Test for Bug 393269 **/
     var doc = $("ifr").contentDocument;
     is("UTF-8", doc.characterSet, "control, getting a property");
     doc.open();
     try {
         is("UTF-8", doc.characterSet,
--- a/layout/base/nsDisplayList.cpp
+++ b/layout/base/nsDisplayList.cpp
@@ -1787,16 +1787,24 @@ nsDisplayBackgroundImage::TryOptimizeToI
   if (mIsThemed || !mBackgroundStyle)
     return false;
 
   nsPresContext* presContext = mFrame->PresContext();
   uint32_t flags = aBuilder->GetBackgroundPaintFlags();
   nsRect borderArea = nsRect(ToReferenceFrame(), mFrame->GetSize());
   const nsStyleBackground::Layer &layer = mBackgroundStyle->mLayers[mLayer];
 
+  if (layer.mClip != NS_STYLE_BG_CLIP_BORDER) {
+    return false;
+  }
+  nscoord radii[8];
+  if (mFrame->GetBorderRadii(radii)) {
+    return false;
+  }
+
   nsBackgroundLayerState state =
     nsCSSRendering::PrepareBackgroundLayer(presContext,
                                            mFrame,
                                            flags,
                                            borderArea,
                                            borderArea,
                                            *mBackgroundStyle,
                                            layer);
--- a/layout/base/nsPresShell.cpp
+++ b/layout/base/nsPresShell.cpp
@@ -6620,32 +6620,38 @@ PresShell::HandleEventInternal(nsEvent* 
     // XXX How about IME events and input events for plugins?
     if (aEvent->mFlags.mIsTrusted) {
       switch (aEvent->message) {
       case NS_KEY_PRESS:
       case NS_KEY_DOWN:
       case NS_KEY_UP: {
         nsIDocument *doc = mCurrentEventContent ?
                            mCurrentEventContent->OwnerDoc() : nullptr;
-        nsIDocument* root = nullptr;
+        nsIDocument* fullscreenAncestor = nullptr;
         if (static_cast<const nsKeyEvent*>(aEvent)->keyCode == NS_VK_ESCAPE &&
-            (root = nsContentUtils::GetRootDocument(doc)) &&
-            root->IsFullScreenDoc()) {
+            (fullscreenAncestor = nsContentUtils::GetFullscreenAncestor(doc))) {
           // Prevent default action on ESC key press when exiting
           // DOM fullscreen mode. This prevents the browser ESC key
           // handler from stopping all loads in the document, which
           // would cause <video> loads to stop.
           aEvent->mFlags.mDefaultPrevented = true;
           aEvent->mFlags.mOnlyChromeDispatch = true;
 
           if (aEvent->message == NS_KEY_UP) {
             // ESC key released while in DOM fullscreen mode.
-            // Fully exit all browser windows and documents from
-            // fullscreen mode.
-            nsIDocument::ExitFullscreen(nullptr, /* async */ true);
+            // If fullscreen is running in content-only mode, exit the target
+            // doctree branch from fullscreen, otherwise fully exit all
+            // browser windows and documents from fullscreen mode.
+            // Note: in the content-only fullscreen case, we pass the
+            // fullscreenAncestor since |doc| may not actually be fullscreen
+            // here, and ExitFullscreen() has no affect when passed a
+            // non-fullscreen document.
+            nsIDocument::ExitFullscreen(
+              nsContentUtils::IsFullscreenApiContentOnly() ? fullscreenAncestor : nullptr,
+              /* async */ true);
           }
         }
         // Else not full-screen mode or key code is unrestricted, fall
         // through to normal handling.
       }
       case NS_MOUSE_BUTTON_DOWN:
       case NS_MOUSE_BUTTON_UP:
         isHandlingUserInput = true;
--- a/layout/base/tests/chrome/test_transformed_scrolling_repaints_3.html
+++ b/layout/base/tests/chrome/test_transformed_scrolling_repaints_3.html
@@ -5,16 +5,22 @@
   <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
   <script type="application/javascript" src="chrome://mochikit/content/chrome-harness.js"></script>
   <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"/>
 </head>
 <!-- Need a timeout here to allow paint unsuppression before we start the test -->
 <body>
 <pre id="test">
 <script type="application/javascript">
+if (navigator.platform.startsWith("Win")) {
+  SimpleTest.expectAssertions(0, 1);
+} else if (navigator.platform.startsWith("Linux")) {
+  SimpleTest.expectAssertions(0, 3);
+}
+
 SimpleTest.waitForExplicitFinish();
 
 var root = getRootDirectory(window.location.href);
 window.open(root + "transformed_scrolling_repaints_3_window.html", "transformed_scrolling_repaints_3",
             "chrome,width=300,height=400");
 </script>
 </pre>
 </body>
--- a/layout/base/tests/test_mozPaintCount.html
+++ b/layout/base/tests/test_mozPaintCount.html
@@ -11,17 +11,17 @@
        drawmode="solid" color="FF00FF00"></embed>
 </p>
 <div id="content" style="display: none">
   
 </div>
 <pre id="test">
 <script class="testbody" type="text/javascript">
 
-if (navigator.platform.startsWith("Linux")) {
+if (!navigator.platform.startsWith("Win")) {
   SimpleTest.expectAssertions(0, 2);
 }
 
 SimpleTest.waitForExplicitFinish();
 
 var startPaintCount = window.mozPaintCount;
 ok(true, "Got to initial paint count: " + startPaintCount);
 var color = 0;
--- a/layout/forms/test/test_bug665540.html
+++ b/layout/forms/test/test_bug665540.html
@@ -13,20 +13,18 @@ https://bugzilla.mozilla.org/show_bug.cg
 <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=665540">Mozilla Bug 665540</a>
 <p id="display"></p>
 <div id="content" style="display: none">
   
 </div>
 <pre id="test">
 <script type="application/javascript">
 
-if (navigator.platform.startsWith("Linux")) {
+if (!navigator.platform.startsWith("Mac")) {
   SimpleTest.expectAssertions(0, 3);
-} else if (navigator.platform.startsWith("Win")) {
-  SimpleTest.expectAssertions(0, 1);
 }
 
 /** Test for Bug 665540 **/
 
 SimpleTest.waitForExplicitFinish();
 
 var win;
 var select;
new file mode 100644
--- /dev/null
+++ b/layout/generic/crashtests/840818.html
@@ -0,0 +1,8 @@
+<html>
+<head>
+<meta charset="UTF-8">
+</head>
+<body style="font-family: monospace;">
+<div style="-moz-column-count: 2;"><div style="-moz-column-count: 2; width: 9ch;">😎中文<span>; </span><span>!</span></div></div>
+</body>
+</html>
--- a/layout/generic/crashtests/crashtests.list
+++ b/layout/generic/crashtests/crashtests.list
@@ -433,14 +433,15 @@ test-pref(layout.css.flexbox.enabled,tru
 test-pref(layout.css.flexbox.enabled,true) load 737313-3.html
 load 762764-1.html
 load 786740-1.html
 asserts(12) test-pref(layout.css.flexbox.enabled,true) load 798020-1.html
 test-pref(layout.css.flexbox.enabled,true) load 798235-1.html
 test-pref(layout.css.flexbox.enabled,true) load 799207-1.html
 asserts(12) test-pref(layout.css.flexbox.enabled,true) load 799207-2.html
 test-pref(layout.css.flexbox.enabled,true) load 804089-1.xhtml
+load 840818.html
 test-pref(layout.css.flexbox.enabled,true) load 812822-1.html
 asserts(1) test-pref(layout.css.flexbox.enabled,true) load 824297-1.html # bug 399262
 asserts(1) test-pref(layout.css.flexbox.enabled,true) load 826532-1.html # bug 399262
 test-pref(layout.css.flexbox.enabled,true) load 827168-1.html
 load 842132-1.html
 test-pref(layout.css.flexbox.enabled,true) load 844529-1.html
--- a/layout/generic/nsBlockFrame.cpp
+++ b/layout/generic/nsBlockFrame.cpp
@@ -1787,21 +1787,20 @@ static bool LineHasClear(nsLineBox* aLin
 
 
 /**
  * Reparent a whole list of floats from aOldParent to this block.  The
  * floats might be taken from aOldParent's overflow list. They will be
  * removed from the list. They end up appended to our mFloats list.
  */
 void
-nsBlockFrame::ReparentFloats(nsIFrame* aFirstFrame,
-                             nsBlockFrame* aOldParent, bool aFromOverflow,
+nsBlockFrame::ReparentFloats(nsIFrame* aFirstFrame, nsBlockFrame* aOldParent,
                              bool aReparentSiblings) {
   nsFrameList list;
-  aOldParent->CollectFloats(aFirstFrame, list, aFromOverflow, aReparentSiblings);
+  aOldParent->CollectFloats(aFirstFrame, list, aReparentSiblings);
   if (list.NotEmpty()) {
     for (nsIFrame* f = list.FirstChild(); f; f = f->GetNextSibling()) {
       ReparentFrame(f, aOldParent, this);
     }
     mFloats.AppendFrames(nullptr, list);
   }
 }
 
@@ -2242,17 +2241,16 @@ nsBlockFrame::ReflowDirtyLines(nsBlockRe
   if (!skipPull && aState.mNextInFlow) {
     // Pull data from a next-in-flow if there's still room for more
     // content here.
     while (keepGoing && aState.mNextInFlow) {
       // Grab first line from our next-in-flow
       nsBlockFrame* nextInFlow = aState.mNextInFlow;
       nsLineBox* pulledLine;
       nsFrameList pulledFrames;
-      bool isOverflowLine = false;
       if (!nextInFlow->mLines.empty()) {
         RemoveFirstLine(nextInFlow->mLines, nextInFlow->mFrames,
                         &pulledLine, &pulledFrames);
       } else {
         // Grab an overflow line if there are any
         FrameLines* overflowLines = nextInFlow->GetOverflowLines();
         if (!overflowLines) {
           aState.mNextInFlow =
@@ -2260,17 +2258,16 @@ nsBlockFrame::ReflowDirtyLines(nsBlockRe
           continue;
         }
         bool last =
           RemoveFirstLine(overflowLines->mLines, overflowLines->mFrames,
                           &pulledLine, &pulledFrames);
         if (last) {
           nextInFlow->DestroyOverflowLines();
         }
-        isOverflowLine = true;
       }
 
       if (pulledFrames.IsEmpty()) {
         // The line is empty. Try the next one.
         NS_ASSERTION(pulledLine->GetChildCount() == 0 &&
                      !pulledLine->mFirstChild, "bad empty line");
         nextInFlow->FreeLineBox(pulledLine);
         continue;
@@ -2290,17 +2287,17 @@ nsBlockFrame::ReflowDirtyLines(nsBlockRe
       // Shift pulledLine's frames into our mFrames list.
       mFrames.AppendFrames(nullptr, pulledFrames);
 
       // Add line to our line list, and set its last child as our new prev-child
       line = mLines.before_insert(end_lines(), pulledLine);
       aState.mPrevChild = mFrames.LastChild();
 
       // Reparent floats whose placeholders are in the line.
-      ReparentFloats(pulledLine->mFirstChild, nextInFlow, isOverflowLine, true);
+      ReparentFloats(pulledLine->mFirstChild, nextInFlow, true);
 
       DumpLine(aState, pulledLine, deltaY, 0);
 #ifdef DEBUG
       AutoNoisyIndenter indent2(gNoisyReflow);
 #endif
 
       if (aState.mPresContext->HasPendingInterrupt()) {
         MarkLineDirtyForInterrupt(line);
@@ -2512,52 +2509,41 @@ nsBlockFrame::ReflowLine(nsBlockReflowSt
 }
 
 nsIFrame*
 nsBlockFrame::PullFrame(nsBlockReflowState& aState,
                         line_iterator       aLine)
 {
   // First check our remaining lines.
   if (end_lines() != aLine.next()) {
-    return PullFrameFrom(aState, aLine, this, false, mFrames, aLine.next());
+    return PullFrameFrom(aLine, this, aLine.next());
   }
 
   NS_ASSERTION(!GetOverflowLines(),
     "Our overflow lines should have been removed at the start of reflow");
 
   // Try each next-in-flow.
   nsBlockFrame* nextInFlow = aState.mNextInFlow;
   while (nextInFlow) {
-    // first normal lines, then overflow lines
+    if (nextInFlow->mLines.empty()) {
+      nextInFlow->DrainSelfOverflowList();
+    }
     if (!nextInFlow->mLines.empty()) {
-      return PullFrameFrom(aState, aLine, nextInFlow, false,
-                           nextInFlow->mFrames,
-                           nextInFlow->mLines.begin());
-    }
-
-    FrameLines* overflowLines = nextInFlow->GetOverflowLines();
-    if (overflowLines) {
-      return PullFrameFrom(aState, aLine, nextInFlow, true,
-                           overflowLines->mFrames,
-                           overflowLines->mLines.begin());
-    }
-
+      return PullFrameFrom(aLine, nextInFlow, nextInFlow->mLines.begin());
+    }
     nextInFlow = static_cast<nsBlockFrame*>(nextInFlow->GetNextInFlow());
     aState.mNextInFlow = nextInFlow;
   }
 
   return nullptr;
 }
 
 nsIFrame*
-nsBlockFrame::PullFrameFrom(nsBlockReflowState&  aState,
-                            nsLineBox*           aLine,
+nsBlockFrame::PullFrameFrom(nsLineBox*           aLine,
                             nsBlockFrame*        aFromContainer,
-                            bool                 aFromOverflowLine,
-                            nsFrameList&         aFromFrameList,
                             nsLineList::iterator aFromLine)
 {
   nsLineBox* fromLine = aFromLine;
   NS_ABORT_IF_FALSE(fromLine, "bad line to pull from");
   NS_ABORT_IF_FALSE(fromLine->GetChildCount(), "empty line");
   NS_ABORT_IF_FALSE(aLine->GetChildCount(), "empty line");
 
   NS_ASSERTION(fromLine->IsBlock() == fromLine->mFirstChild->IsBlockOutside(),
@@ -2569,72 +2555,51 @@ nsBlockFrame::PullFrameFrom(nsBlockReflo
     // we stop pulling.
     return nullptr;
   }
   // Take frame from fromLine
   nsIFrame* frame = fromLine->mFirstChild;
   nsIFrame* newFirstChild = frame->GetNextSibling();
 
   if (aFromContainer != this) {
-    NS_ASSERTION(aState.mPrevChild == aLine->LastChild(),
-      "mPrevChild should be the LastChild of the line we are adding to");
     // The frame is being pulled from a next-in-flow; therefore we
     // need to add it to our sibling list.
-    if (MOZ_LIKELY(!aFromOverflowLine)) {
-      NS_ASSERTION(&aFromFrameList == &aFromContainer->mFrames,
-                   "must be normal flow if not overflow line");
-      NS_ASSERTION(aFromLine == aFromContainer->mLines.begin(),
-                   "should only pull from first line");
-    }
-    aFromFrameList.RemoveFrame(frame);
+    MOZ_ASSERT(aLine == mLines.back());
+    MOZ_ASSERT(aFromLine == aFromContainer->mLines.begin(),
+               "should only pull from first line");
+    aFromContainer->mFrames.RemoveFrame(frame);
 
     // When pushing and pulling frames we need to check for whether any
-    // views need to be reparented
-    NS_ASSERTION(frame->GetParent() == aFromContainer, "unexpected parent frame");
-
+    // views need to be reparented.
     ReparentFrame(frame, aFromContainer, this);
-    mFrames.InsertFrame(nullptr, aState.mPrevChild, frame);
-
-    // The frame might have (or contain) floats that need to be
-    // brought over too.
-    ReparentFloats(frame, aFromContainer, aFromOverflowLine, true);
-  }
-  // when aFromContainer is 'this', then aLine->LastChild()'s next sibling
-  // is already set correctly.
+    mFrames.AppendFrame(nullptr, frame);
+
+    // The frame might have (or contain) floats that need to be brought
+    // over too. (pass 'false' since there are no siblings to check)
+    ReparentFloats(frame, aFromContainer, false);
+  } else {
+    MOZ_ASSERT(aLine == aFromLine.prev());
+  }
+
   aLine->NoteFrameAdded(frame);
   fromLine->NoteFrameRemoved(frame);
 
   if (fromLine->GetChildCount() > 0) {
     // Mark line dirty now that we pulled a child
     fromLine->MarkDirty();
     fromLine->mFirstChild = newFirstChild;
   } else {
-    // Free up the fromLine now that it's empty
+    // Free up the fromLine now that it's empty.
     // Its bounds might need to be redrawn, though.
-    FrameLines* overflowLines =
-      aFromOverflowLine ? aFromContainer->RemoveOverflowLines() : nullptr;
-    nsLineList* fromLineList =
-      aFromOverflowLine ? &overflowLines->mLines : &aFromContainer->mLines;
-    if (aFromLine.next() != fromLineList->end())
+    if (aFromLine.next() != aFromContainer->mLines.end()) {
       aFromLine.next()->MarkPreviousMarginDirty();
-
-    fromLineList->erase(aFromLine);
+    }
+    aFromContainer->mLines.erase(aFromLine);
     // aFromLine is now invalid
     aFromContainer->FreeLineBox(fromLine);
-
-    // Put any remaining overflow lines back.
-    if (aFromOverflowLine) {
-      if (!fromLineList->empty()) {
-        aFromContainer->SetOverflowLines(overflowLines);
-      } else {
-        delete overflowLines;
-        // Now any iterators into fromLineList are invalid (but
-        // aFromLine already was invalidated above)
-      }
-    }
   }
 
 #ifdef DEBUG
   VerifyLines(true);
   VerifyOverflowSituation();
 #endif
 
   return frame;
@@ -4312,17 +4277,17 @@ nsBlockFrame::PushLines(nsBlockReflowSta
   nsLineList::iterator overBegin(aLineBefore.next());
 
   // PushTruncatedPlaceholderLine sometimes pushes the first line.  Ugh.
   bool firstLine = overBegin == begin_lines();
 
   if (overBegin != end_lines()) {
     // Remove floats in the lines from mFloats
     nsFrameList floats;
-    CollectFloats(overBegin->mFirstChild, floats, false, true);
+    CollectFloats(overBegin->mFirstChild, floats, true);
 
     if (floats.NotEmpty()) {
       // Push the floats onto the front of the overflow out-of-flows list
       nsAutoOOFFrameList oofs(this);
       oofs.mList.InsertFrames(nullptr, nullptr, floats);
     }
 
     // overflow lines can already exist in some cases, in particular,
@@ -4984,42 +4949,48 @@ nsBlockFrame::AddFrames(nsFrameList& aFr
   }
 
 #ifdef DEBUG
   VerifyLines(true);
 #endif
   return NS_OK;
 }
 
-nsBlockFrame::line_iterator
-nsBlockFrame::RemoveFloat(nsIFrame* aFloat) {
+void
+nsBlockFrame::RemoveFloat(nsIFrame* aFloat)
+{
+#ifdef DEBUG
+  if (!mFloats.ContainsFrame(aFloat)) {
+    MOZ_ASSERT(GetOverflowOutOfFlows() &&
+               GetOverflowOutOfFlows()->ContainsFrame(aFloat),
+               "aFloat is not our child or on an unexpected frame list");
+  }
+#endif
+
   // Find which line contains the float, so we can update
   // the float cache.
   line_iterator line = begin_lines(), line_end = end_lines();
   for ( ; line != line_end; ++line) {
     if (line->IsInline() && line->RemoveFloat(aFloat)) {
       break;
     }
   }
 
-  // Try to destroy if it's in mFloats.
-  if (mFloats.DestroyFrameIfPresent(aFloat)) {
-    return line;
-  }
-
-  // Try our overflow list
+  if (mFloats.StartRemoveFrame(aFloat)) {
+    return;
+  }
+
   {
     nsAutoOOFFrameList oofs(this);
-    if (oofs.mList.DestroyFrameIfPresent(aFloat)) {
-      return line_end;
-    }
-  }
-
-  NS_ERROR("Destroying float without removing from a child list.");
-  return line_end;
+    if (oofs.mList.ContinueRemoveFrame(aFloat)) {
+      return;
+    }
+  }
+
+  MOZ_ASSERT(false, "float child frame not found");
 }
 
 static void MarkSameFloatManagerLinesDirty(nsBlockFrame* aBlock)
 {
   nsBlockFrame* blockWithFloatMgr = aBlock;
   while (!(blockWithFloatMgr->GetStateBits() & NS_BLOCK_FLOAT_MGR)) {
     nsBlockFrame* bf = nsLayoutUtils::GetAsBlock(blockWithFloatMgr->GetParent());
     if (!bf) {
@@ -5121,25 +5092,25 @@ nsBlockFrame::DoRemoveOutOfFlowFrame(nsI
   // Remove aFrame from the appropriate list.
   if (aFrame->IsAbsolutelyPositioned()) {
     // This also deletes the next-in-flows
     block->GetAbsoluteContainingBlock()->RemoveFrame(block,
                                                      kAbsoluteList,
                                                      aFrame);
   }
   else {
-    // First remove aFrame's next-in-flows
+    // First remove aFrame's next-in-flows.
     nsIFrame* nif = aFrame->GetNextInFlow();
     if (nif) {
       static_cast<nsContainerFrame*>(nif->GetParent())
         ->DeleteNextInFlowChild(aFrame->PresContext(), nif, false);
     }
-    // Now remove aFrame
-    // This also destroys the frame.
+    // Now remove aFrame from its child list and Destroy it.
     block->RemoveFloat(aFrame);
+    aFrame->Destroy();
   }
 }
 
 /**
  * This helps us iterate over the list of all normal + overflow lines
  */
 void
 nsBlockFrame::TryAllLines(nsLineList::iterator* aIterator,
@@ -5624,23 +5595,28 @@ nsresult
 nsBlockFrame::StealFrame(nsPresContext* aPresContext,
                          nsIFrame*      aChild,
                          bool           aForceNormal)
 {
   NS_PRECONDITION(aPresContext && aChild, "null pointer");
 
   if ((aChild->GetStateBits() & NS_FRAME_OUT_OF_FLOW) &&
       aChild->IsFloating()) {
-    bool removed = mFloats.RemoveFrameIfPresent(aChild);
+    MOZ_ASSERT(mFloats.ContainsFrame(aChild) ||
+               (GetPushedFloats() && GetPushedFloats()->ContainsFrame(aChild)),
+               "aChild is not our child");
+    bool removed = mFloats.StartRemoveFrame(aChild);
     if (!removed) {
       nsFrameList* list = GetPushedFloats();
       if (list) {
-        removed = list->RemoveFrameIfPresent(aChild);
+        removed = list->ContinueRemoveFrame(aChild);
+        // XXXmats delete the property if the list is now empty?
       }
     }
+    MOZ_ASSERT(removed, "StealFrame failed to remove the float");
     return removed ? NS_OK : NS_ERROR_UNEXPECTED;
   }
 
   if ((aChild->GetStateBits() & NS_FRAME_IS_OVERFLOW_CONTAINER)
       && !aForceNormal)
     return nsContainerFrame::StealFrame(aPresContext, aChild);
 
   // Find the line and the previous sibling that contains
@@ -5711,16 +5687,17 @@ nsBlockFrame::StealFrame(nsPresContext* 
     ++line;
     TryAllLines(&line, &line_start, &line_end, &searchingOverflowList,
                 &overflowLines);
     if (prevSibling && !prevSibling->GetNextSibling()) {
       // We just switched to the overflow list.  Null out prevSibling
       prevSibling = nullptr;
     }
   }
+  MOZ_ASSERT(false, "StealFrame failed to remove the frame");
   return NS_ERROR_UNEXPECTED;
 }
 
 void
 nsBlockFrame::DeleteNextInFlowChild(nsPresContext* aPresContext,
                                     nsIFrame*      aNextInFlow,
                                     bool           aDeletingEmptyFrames)
 {
@@ -6881,53 +6858,57 @@ nsBlockFrame::ReflowBullet(nsIFrame* aBu
 }
 
 // This is used to scan frames for any float placeholders, add their
 // floats to the list represented by aList, and remove the
 // floats from whatever list they might be in. We don't search descendants
 // that are float containing blocks.  Floats that or not children of 'this'
 // are ignored (they are not added to aList).
 void
-nsBlockFrame::CollectFloats(nsIFrame* aFrame, nsFrameList& aList,
-                            bool aFromOverflow, bool aCollectSiblings)
+nsBlockFrame::DoCollectFloats(nsIFrame* aFrame, nsFrameList& aList,
+                              bool aCollectSiblings)
 {
   while (aFrame) {
     // Don't descend into float containing blocks.
     if (!aFrame->IsFloatContainingBlock()) {
       nsIFrame *outOfFlowFrame =
         aFrame->GetType() == nsGkAtoms::placeholderFrame ?
           nsLayoutUtils::GetFloatFromPlaceholder(aFrame) : nullptr;
       if (outOfFlowFrame && outOfFlowFrame->GetParent() == this) {
-        bool removed = false;
-        if (outOfFlowFrame->GetStateBits() & NS_FRAME_IS_PUSHED_FLOAT) {
+        // Floats live in mFloats, or in the PushedFloat or OverflowOutOfFlows
+        // frame list properties.
+#ifdef DEBUG
+        if (!mFloats.ContainsFrame(outOfFlowFrame)) {
           nsFrameList* list = GetPushedFloats();
-          removed = list && list->RemoveFrameIfPresent(outOfFlowFrame);
-        }
-        if (!removed) {
-          if (aFromOverflow) {
-            nsAutoOOFFrameList oofs(this);
-            oofs.mList.RemoveFrame(outOfFlowFrame);
-          } else {
-            mFloats.RemoveFrame(outOfFlowFrame);
+          if (!list || !list->ContainsFrame(outOfFlowFrame)) {
+            list = GetOverflowOutOfFlows();
+            MOZ_ASSERT(list && list->ContainsFrame(outOfFlowFrame),
+                       "the float is not our child");
           }
         }
+#endif
+        bool removed = mFloats.StartRemoveFrame(outOfFlowFrame);
+        if (!removed) {
+          nsFrameList* list = GetPushedFloats();
+          removed = list && list->ContinueRemoveFrame(outOfFlowFrame);
+          if (!removed) {
+            nsAutoOOFFrameList oofs(this);
+            removed = oofs.mList.ContinueRemoveFrame(outOfFlowFrame);
+          }
+        }
+        MOZ_ASSERT(removed, "misplaced float child");
         aList.AppendFrame(nullptr, outOfFlowFrame);
         // FIXME: By not pulling floats whose parent is one of our
         // later siblings, are we risking the pushed floats getting
         // out-of-order?
         // XXXmats nsInlineFrame's lazy reparenting depends on NOT doing that.
       }
 
-      CollectFloats(aFrame->GetFirstPrincipalChild(), 
-                    aList, aFromOverflow, true);
-      // Note: Even though we're calling CollectFloats on aFrame's overflow
-      // list, we'll pass down aFromOverflow unchanged because we're still
-      // traversing the regular-children subtree of the 'this' frame.
-      CollectFloats(aFrame->GetFirstChild(kOverflowList), 
-                    aList, aFromOverflow, true);
+      DoCollectFloats(aFrame->GetFirstPrincipalChild(), aList, true);
+      DoCollectFloats(aFrame->GetFirstChild(kOverflowList), aList, true);
     }
     if (!aCollectSiblings)
       break;
     aFrame = aFrame->GetNextSibling();
   }
 }
 
 void
--- a/layout/generic/nsBlockFrame.h
+++ b/layout/generic/nsBlockFrame.h
@@ -452,18 +452,17 @@ public:
    * -- destroys all removed frames
    */
   enum {
     REMOVE_FIXED_CONTINUATIONS = 0x02,
     FRAMES_ARE_EMPTY           = 0x04
   };
   nsresult DoRemoveFrame(nsIFrame* aDeletedFrame, uint32_t aFlags);
 
-  void ReparentFloats(nsIFrame* aFirstFrame,
-                      nsBlockFrame* aOldParent, bool aFromOverflow,
+  void ReparentFloats(nsIFrame* aFirstFrame, nsBlockFrame* aOldParent,
                       bool aReparentSiblings);
 
   virtual bool UpdateOverflow();
 
   /** Load all of aFrame's floats into the float manager iff aFrame is not a
    *  block formatting context. Handles all necessary float manager translations;
    *  assumes float manager is in aFrame's parent's coord system.
    *  Safe to call on non-blocks (does nothing).
@@ -474,16 +473,35 @@ public:
 protected:
 
   /** grab overflow lines from this block's prevInFlow, and make them
     * part of this block's mLines list.
     * @return true if any lines were drained.
     */
   bool DrainOverflowLines();
 
+  /**
+   * @return false iff this block does not have a float on any child list.
+   * This function is O(1).
+   */
+  bool MaybeHasFloats() const {
+    if (!mFloats.IsEmpty()) {
+      return true;
+    }
+    // XXX this could be replaced with HasPushedFloats() if we enforced
+    // removing the property when the frame list becomes empty.
+    nsFrameList* list = GetPushedFloats();
+    if (list && !list->IsEmpty()) {
+      return true;
+    }
+    // For the OverflowOutOfFlowsProperty I think we do enforce that, but it's
+    // a mix of out-of-flow frames, so that's why the method name has "Maybe".
+    return GetStateBits() & NS_BLOCK_HAS_OVERFLOW_OUT_OF_FLOWS;
+  }
+
   /** grab pushed floats from this block's prevInFlow, and splice
     * them into this block's mFloats list.
     */
   void DrainPushedFloats(nsBlockReflowState& aState);
 
   /** Load all our floats into the float manager (without reflowing them).
    *  Assumes float manager is in our own coordinate system.
    */
@@ -498,20 +516,27 @@ protected:
   /** Find any trailing BR clear from the last line of the block (or its PIFs)
    */
   uint8_t FindTrailingClear();
 
   /**
     * Remove a float from our float list and also the float cache
     * for the line its placeholder is on.
     */
-  line_iterator RemoveFloat(nsIFrame* aFloat);
+  void RemoveFloat(nsIFrame* aFloat);
 
   void CollectFloats(nsIFrame* aFrame, nsFrameList& aList,
-                     bool aFromOverflow, bool aCollectFromSiblings);
+                     bool aCollectFromSiblings) {
+    if (MaybeHasFloats()) {
+      DoCollectFloats(aFrame, aList, aCollectFromSiblings);
+    }
+  }
+  void DoCollectFloats(nsIFrame* aFrame, nsFrameList& aList,
+                       bool aCollectFromSiblings);
+
   // Remove a float, abs, rel positioned frame from the appropriate block's list
   static void DoRemoveOutOfFlowFrame(nsIFrame* aFrame);
 
   /** set up the conditions necessary for an resize reflow
     * the primary task is to mark the minimumly sufficient lines dirty. 
     */
   nsresult PrepareResizeReflow(nsBlockReflowState& aState);
 
@@ -663,21 +688,18 @@ protected:
    * doesn't automatically remove the corresponding float from the
    * line's float array. This happens indirectly: either the line gets
    * emptied (and destroyed) or the line gets reflowed (because we mark
    * it dirty) and the code at the top of ReflowLine empties the
    * array. So eventually, it will be removed, just not right away.
    *
    * @return the pulled frame or nullptr
    */
-  nsIFrame* PullFrameFrom(nsBlockReflowState&  aState,
-                          nsLineBox*           aLine,
+  nsIFrame* PullFrameFrom(nsLineBox*           aLine,
                           nsBlockFrame*        aFromContainer,
-                          bool                 aFromOverflowLine,
-                          nsFrameList&         aFromFrameList,
                           nsLineList::iterator aFromLine);
 
   /**
    * Push the line after aLineBefore to the overflow line list.
    * @param aLineBefore a line in 'mLines' (or begin_lines() when
    *        pushing the first line)
    */
   void PushLines(nsBlockReflowState& aState,
--- a/layout/generic/nsContainerFrame.cpp
+++ b/layout/generic/nsContainerFrame.cpp
@@ -1210,40 +1210,73 @@ nsContainerFrame::DisplayOverflowContain
   if (overflowconts) {
     for (nsIFrame* frame = overflowconts->FirstChild(); frame;
          frame = frame->GetNextSibling()) {
       BuildDisplayListForChild(aBuilder, frame, aDirtyRect, aLists);
     }
   }
 }
 
+static bool
+TryRemoveFrame(nsIFrame* aFrame, FramePropertyTable* aPropTable,
+               const FramePropertyDescriptor* aProp, nsIFrame* aChildToRemove,
+               bool (nsFrameList::*aRemoveMethod)(nsIFrame* aFrame))
+{
+  nsFrameList* list = static_cast<nsFrameList*>(aPropTable->Get(aFrame, aProp));
+  if (list && (list->*aRemoveMethod)(aChildToRemove)) {
+    // aChildToRemove *may* have been removed from this list.
+    if (list->IsEmpty()) {
+      aPropTable->Remove(aFrame, aProp);
+      delete list;
+    }
+    return true;
+  }
+  return false;
+}
+
 nsresult
 nsContainerFrame::StealFrame(nsPresContext* aPresContext,
                              nsIFrame*      aChild,
                              bool           aForceNormal)
 {
-  bool removed = true;
+#ifdef DEBUG
+  if (!mFrames.ContainsFrame(aChild)) {
+    FramePropertyTable* propTable = aPresContext->PropertyTable();
+    nsFrameList* list = static_cast<nsFrameList*>(
+                          propTable->Get(this, OverflowContainersProperty()));
+    if (!list || !list->ContainsFrame(aChild)) {
+      list = static_cast<nsFrameList*>(
+               propTable->Get(this, ExcessOverflowContainersProperty()));
+      MOZ_ASSERT(list && list->ContainsFrame(aChild), "aChild is not our child "
+                 "or on a frame list not supported by StealFrame");
+    }
+  }
+#endif
+
+  bool removed;
   if ((aChild->GetStateBits() & NS_FRAME_IS_OVERFLOW_CONTAINER)
       && !aForceNormal) {
-    // Try removing from the overflow container list
-    if (!RemovePropTableFrame(aPresContext, aChild,
-                              OverflowContainersProperty())) {
-      // It must be in the excess overflow container list
-      removed = RemovePropTableFrame(aPresContext, aChild,
-                                     ExcessOverflowContainersProperty());
+    FramePropertyTable* propTable = aPresContext->PropertyTable();
+    // Try removing from the overflow container list.
+    removed = ::TryRemoveFrame(this, propTable, OverflowContainersProperty(),
+                               aChild, &nsFrameList::StartRemoveFrame);
+    if (!removed) {
+      // It must be in the excess overflow container list.
+      removed = ::TryRemoveFrame(this, propTable,
+                                 ExcessOverflowContainersProperty(),
+                                 aChild, &nsFrameList::ContinueRemoveFrame);
     }
-  }
-  else {
-    if (!mFrames.RemoveFrameIfPresent(aChild)) {
-      removed = false;
-      // We didn't find the child in the parent's principal child list.
+  } else {
+    removed = mFrames.StartRemoveFrame(aChild);
+    if (!removed) {
+      // We didn't find the child in our principal child list.
       // Maybe it's on the overflow list?
       nsFrameList* frameList = GetOverflowFrames();
       if (frameList) {
-        removed = frameList->RemoveFrameIfPresent(aChild);
+        removed = frameList->ContinueRemoveFrame(aChild);
         if (frameList->IsEmpty()) {
           DestroyOverflowList(aPresContext, nullptr);
         }
       }
     }
   }
 
   NS_POSTCONDITION(removed, "StealFrame: can't find aChild");
@@ -1412,43 +1445,16 @@ nsContainerFrame::GetPropTableFrames(nsP
 nsFrameList*
 nsContainerFrame::RemovePropTableFrames(nsPresContext*                 aPresContext,
                                         const FramePropertyDescriptor* aProperty)
 {
   FramePropertyTable* propTable = aPresContext->PropertyTable();
   return static_cast<nsFrameList*>(propTable->Remove(this, aProperty));
 }
 
-bool
-nsContainerFrame::RemovePropTableFrame(nsPresContext*                 aPresContext,
-                                       nsIFrame*                      aFrame,
-                                       const FramePropertyDescriptor* aProperty)
-{
-  nsFrameList* frameList = RemovePropTableFrames(aPresContext, aProperty);
-  if (!frameList) {
-    // No such list
-    return false;
-  }
-  if (!frameList->RemoveFrameIfPresent(aFrame)) {
-    // Found list, but it doesn't have the frame. Put list back.
-    SetPropTableFrames(aPresContext, frameList, aProperty);
-    return false;
-  }
-
-  if (frameList->IsEmpty()) {
-    // Removed frame and now list is empty. Delete it.
-    delete frameList;
-  }
-  else {
-    // Removed frame, but list not empty. Put it back.
-    SetPropTableFrames(aPresContext, frameList, aProperty);
-  }
-  return true;
-}
-
 nsresult
 nsContainerFrame::SetPropTableFrames(nsPresContext*                 aPresContext,
                                      nsFrameList*                   aFrameList,
                                      const FramePropertyDescriptor* aProperty)
 {
   NS_PRECONDITION(aPresContext && aProperty && aFrameList, "null ptr");
   NS_PRECONDITION(
     (aProperty != nsContainerFrame::OverflowContainersProperty() &&
--- a/layout/generic/nsContainerFrame.h
+++ b/layout/generic/nsContainerFrame.h
@@ -493,26 +493,16 @@ protected:
   /**
    * Remove and return the PresContext-stored nsFrameList named aPropID for
    * this frame. May return null.
    */
   nsFrameList* RemovePropTableFrames(nsPresContext*                 aPresContext,
                                      const FramePropertyDescriptor* aProperty);
 
   /**
-   * Remove aFrame from the PresContext-stored nsFrameList named aPropID
-   * for this frame, deleting the list if it is now empty.
-   * Return true if the aFrame was successfully removed,
-   * Return false otherwise.
-   */
-  bool RemovePropTableFrame(nsPresContext*                 aPresContext,
-                              nsIFrame*                      aFrame,
-                              const FramePropertyDescriptor* aProperty);
-
-  /**
    * Set the PresContext-stored nsFrameList named aPropID for this frame
    * to the given aFrameList, which must not be null.
    */
   nsresult SetPropTableFrames(nsPresContext*                 aPresContext,
                               nsFrameList*                   aFrameList,
                               const FramePropertyDescriptor* aProperty);
 
   /**
--- a/layout/generic/nsFrameList.cpp
+++ b/layout/generic/nsFrameList.cpp
@@ -96,30 +96,16 @@ nsFrameList::RemoveFrame(nsIFrame* aFram
     prevSibling->SetNextSibling(nextFrame);
     aFrame->SetNextSibling(nullptr);
     if (!nextFrame) {
       mLastChild = prevSibling;
     }
   }
 }
 
-bool
-nsFrameList::RemoveFrameIfPresent(nsIFrame* aFrame)
-{
-  NS_PRECONDITION(aFrame, "null ptr");
-
-  for (Enumerator e(*this); !e.AtEnd(); e.Next()) {
-    if (e.get() == aFrame) {
-      RemoveFrame(aFrame);
-      return true;
-    }
-  }
-  return false;
-}
-
 nsFrameList
 nsFrameList::RemoveFramesAfter(nsIFrame* aAfterFrame)
 {
   if (!aAfterFrame) {
     nsFrameList result;
     result.InsertFrames(nullptr, nullptr, *this);
     return result;
   }
@@ -151,28 +137,16 @@ nsFrameList::RemoveFirstChild()
 void
 nsFrameList::DestroyFrame(nsIFrame* aFrame)
 {
   NS_PRECONDITION(aFrame, "null ptr");
   RemoveFrame(aFrame);
   aFrame->Destroy();
 }
 
-bool
-nsFrameList::DestroyFrameIfPresent(nsIFrame* aFrame)
-{
-  NS_PRECONDITION(aFrame, "null ptr");
-
-  if (RemoveFrameIfPresent(aFrame)) {
-    aFrame->Destroy();
-    return true;
-  }
-  return false;
-}
-
 nsFrameList::Slice
 nsFrameList::InsertFrames(nsIFrame* aParent, nsIFrame* aPrevSibling,
                           nsFrameList& aFrameList)
 {
   NS_PRECONDITION(aFrameList.NotEmpty(), "Unexpected empty list");
 
   if (aParent) {
     aFrameList.ApplySetParent(aParent);
@@ -346,16 +320,27 @@ nsFrameList::ApplySetParent(nsIFrame* aP
 {
   NS_ASSERTION(aParent, "null ptr");
 
   for (nsIFrame* f = FirstChild(); f; f = f->GetNextSibling()) {
     f->SetParent(aParent);
   }
 }
 
+/* static */ void
+nsFrameList::UnhookFrameFromSiblings(nsIFrame* aFrame)
+{
+  MOZ_ASSERT(aFrame->GetPrevSibling() && aFrame->GetNextSibling());
+  nsIFrame* const nextSibling = aFrame->GetNextSibling();
+  nsIFrame* const prevSibling = aFrame->GetPrevSibling();
+  aFrame->SetNextSibling(nullptr);
+  prevSibling->SetNextSibling(nextSibling);
+  MOZ_ASSERT(!aFrame->GetPrevSibling() && !aFrame->GetNextSibling());
+}
+
 #ifdef DEBUG
 void
 nsFrameList::List(FILE* out) const
 {
   fputs("<\n", out);
   for (nsIFrame* frame = mFirstChild; frame;
        frame = frame->GetNextSibling()) {
     frame->List(out, 1);
--- a/layout/generic/nsFrameList.h
+++ b/layout/generic/nsFrameList.h
@@ -133,51 +133,66 @@ public:
   /**
    * Take aFrame out of the frame list. This also disconnects aFrame
    * from the sibling list. The frame must be non-null and present on
    * this list.
    */
   void RemoveFrame(nsIFrame* aFrame);
 
   /**
-   * Take aFrame out of the frame list, if present. This also disconnects
-   * aFrame from the sibling list. aFrame must be non-null but is not
-   * required to be on the list.
-   * @return true if aFrame was removed
-   */
-  bool RemoveFrameIfPresent(nsIFrame* aFrame);
-
-  /**
    * Take the frames after aAfterFrame out of the frame list.  If
    * aAfterFrame is null, removes the entire list.
    * @param aAfterFrame a frame in this list, or null
    * @return the removed frames, if any
    */
   nsFrameList RemoveFramesAfter(nsIFrame* aAfterFrame);
 
   /**
    * Take the first frame (if any) out of the frame list.
    * @return the first child, or nullptr if the list is empty
    */
   nsIFrame* RemoveFirstChild();
 
   /**
+   * The following two functions are intended to be used in concert for
+   * removing a frame from its frame list when the set of possible frame
+   * lists is known in advance, but the exact frame list is unknown.
+   * aFrame must be non-null.
+   * Example use:
+   *   bool removed = frameList1.StartRemoveFrame(aFrame) ||
+   *                  frameList2.ContinueRemoveFrame(aFrame) ||
+   *                  frameList3.ContinueRemoveFrame(aFrame);
+   *   MOZ_ASSERT(removed);
+   *
+   * @note One of the frame lists MUST contain aFrame, if it's on some other
+   *       frame list then the example above will likely lead to crashes.
+   * This function is O(1).
+   * @return true iff aFrame was removed from /some/ list, not necessarily
+   *         this one.  If it was removed from a different list then it is
+   *         guaranteed that that list is still non-empty.
+   * (this method is implemented in nsIFrame.h to be able to inline)
+   */
+  inline bool StartRemoveFrame(nsIFrame* aFrame);
+
+  /**
+   * Precondition: StartRemoveFrame MUST be called before this.
+   * This function is O(1).
+   * @see StartRemoveFrame
+   * @return true iff aFrame was removed from this list
+   * (this method is implemented in nsIFrame.h to be able to inline)
+   */
+  inline bool ContinueRemoveFrame(nsIFrame* aFrame);
+
+  /**
    * Take aFrame out of the frame list and then destroy it.
    * The frame must be non-null and present on this list.
    */
   void DestroyFrame(nsIFrame* aFrame);
 
   /**
-   * If aFrame is present on this list then take it out of the list and
-   * then destroy it. The frame must be non-null.
-   * @return true if the frame was found
-   */
-  bool DestroyFrameIfPresent(nsIFrame* aFrame);
-
-  /**
    * Insert aFrame right after aPrevSibling, or prepend it to this
    * list if aPrevSibling is null. If aParent is not null, also
    * reparents newly-added frame. Note that this method always
    * sets the frame's nextSibling pointer.
    */
   void InsertFrame(nsIFrame* aParent, nsIFrame* aPrevSibling,
                    nsIFrame* aFrame) {
     nsFrameList temp(aFrame, aFrame);
@@ -447,13 +462,21 @@ private:
   void VerifyList() const;
 #else
   void VerifyList() const {}
 #endif
 
   static const nsFrameList* sEmptyList;
 
 protected:
+  /**
+   * Disconnect aFrame from its siblings.  This must only be called if aFrame
+   * is NOT the first or last sibling, because otherwise its nsFrameList will
+   * have a stale mFirst/LastChild pointer.  This precondition is asserted.
+   * This function is O(1).
+   */
+  static void UnhookFrameFromSiblings(nsIFrame* aFrame);
+
   nsIFrame* mFirstChild;
   nsIFrame* mLastChild;
 };
 
 #endif /* nsFrameList_h___ */
--- a/layout/generic/nsIFrame.h
+++ b/layout/generic/nsIFrame.h
@@ -3242,16 +3242,54 @@ private:
     InitExternal(aFrame);
 #endif
   }
 
   nsWeakFrame*  mPrev;
   nsIFrame*     mFrame;
 };
 
+inline bool
+nsFrameList::ContinueRemoveFrame(nsIFrame* aFrame)
+{
+  MOZ_ASSERT(!aFrame->GetPrevSibling() || !aFrame->GetNextSibling(),
+             "Forgot to call StartRemoveFrame?");
+  if (aFrame == mLastChild) {
+    MOZ_ASSERT(!aFrame->GetNextSibling(), "broken frame list");
+    nsIFrame* prevSibling = aFrame->GetPrevSibling();
+    if (!prevSibling) {
+      MOZ_ASSERT(aFrame == mFirstChild, "broken frame list");
+      mFirstChild = mLastChild = nullptr;
+      return true;
+    }
+    MOZ_ASSERT(prevSibling->GetNextSibling() == aFrame, "Broken frame linkage");
+    prevSibling->SetNextSibling(nullptr);
+    mLastChild = prevSibling;
+    return true;
+  }
+  if (aFrame == mFirstChild) {
+    MOZ_ASSERT(!aFrame->GetPrevSibling(), "broken frame list");
+    mFirstChild = aFrame->GetNextSibling();
+    aFrame->SetNextSibling(nullptr);
+    MOZ_ASSERT(mFirstChild, "broken frame list");
+    return true;
+  }
+  return false;
+}
+
+inline bool
+nsFrameList::StartRemoveFrame(nsIFrame* aFrame)
+{
+  if (aFrame->GetPrevSibling() && aFrame->GetNextSibling()) {
+    UnhookFrameFromSiblings(aFrame);
+    return true;
+  }
+  return ContinueRemoveFrame(aFrame);
+}
+
 inline void
 nsFrameList::Enumerator::Next()
 {
   NS_ASSERTION(!AtEnd(), "Should have checked AtEnd()!");
   mFrame = mFrame->GetNextSibling();
 }
 
 inline
--- a/layout/generic/nsInlineFrame.cpp
+++ b/layout/generic/nsInlineFrame.cpp
@@ -238,37 +238,32 @@ nsInlineFrame::ReparentFloatsForInlineCh
                aOurLineContainer->GetPrevContinuation(),
                "Don't call this when we have no continuation, it's a waste");
   if (!aFrame) {
     NS_ASSERTION(aReparentSiblings, "Why did we get called?");
     return;
   }
 
   nsIFrame* ancestor = aFrame;
-  nsIFrame* ancestorBlockChild;
   do {
-    ancestorBlockChild = ancestor;
     ancestor = ancestor->GetParent();
     if (!ancestor)
       return;
   } while (!ancestor->IsFloatContainingBlock());
 
   if (ancestor == aOurLineContainer)
     return;
 
   nsBlockFrame* ourBlock = nsLayoutUtils::GetAsBlock(aOurLineContainer);
   NS_ASSERTION(ourBlock, "Not a block, but broke vertically?");
   nsBlockFrame* frameBlock = nsLayoutUtils::GetAsBlock(ancestor);
   NS_ASSERTION(frameBlock, "ancestor not a block");
 
-  const nsFrameList& blockChildren(ancestor->PrincipalChildList());
-  bool isOverflow = !blockChildren.ContainsFrame(ancestorBlockChild);
-
   while (true) {
-    ourBlock->ReparentFloats(aFrame, frameBlock, isOverflow, false);
+    ourBlock->ReparentFloats(aFrame, frameBlock, false);
 
     if (!aReparentSiblings)
       return;
     nsIFrame* next = aFrame->GetNextSibling();
     if (!next)
       return;
     if (next->GetParent() == aFrame->GetParent()) {
       aFrame = next;
--- a/layout/generic/test/test_bug469774.xul
+++ b/layout/generic/test/test_bug469774.xul
@@ -22,19 +22,17 @@ https://bugzilla.mozilla.org/show_bug.cg
 
   <p id="display"></p>
 <div id="content" style="display: none">
 </div>
 </body>
 
 <script class="testbody" type="application/javascript;version=1.7"><![CDATA[
 
-if (navigator.platform.startsWith("Win")) {
-  SimpleTest.expectAssertions(0, 3);
-}
+SimpleTest.expectAssertions(0, 3);
 
 /** Test for Bug 469774 **/
 
 // Test whether menu popups are blocked from being painted in their parent window.
 
 // Like snapshotWindow, but with DRAWWINDOW_DRAW_CARET
 function snapShot() {
   var canvas = document.createElementNS("http://www.w3.org/1999/xhtml", "canvas");
--- a/layout/generic/test/test_bug514732-2.xul
+++ b/layout/generic/test/test_bug514732-2.xul
@@ -25,17 +25,17 @@ https://bugzilla.mozilla.org/show_bug.cg
 </div>
 <pre id="test">
 </pre>
 </body>
 
 <script class="testbody" type="application/javascript">
 <![CDATA[
 
-if (navigator.platform.startsWith("Linux")) {
+if (!navigator.platform.startsWith("Mac")) {
   SimpleTest.expectAssertions(0, 3);
 }
 
 /** Test for Bug 514732 **/
 
 SimpleTest.waitForExplicitFinish();
 window.open("file_bug514732_window.xul", "bug514732",
             "chrome,width=600,height=600,scrollbars");
--- a/layout/generic/test/test_selection_preventDefault.html
+++ b/layout/generic/test/test_selection_preventDefault.html
@@ -28,17 +28,17 @@
 <input id="input" type="text" value="iiiiiiiii iiiiiiiii iiiiiiiii">
 <div id="fixedDiv1" class="testingDiv">
 dddddd dddddd dddddd
 </div>
 <pre id="test">
 <script class="testbody" type="text/javascript">
 
 if (navigator.platform.startsWith("Win")) {
-  SimpleTest.expectAssertions(0, 1);
+  SimpleTest.expectAssertions(0, 3);
 }
 
 var fixedDiv1 = document.getElementById("fixedDiv1");
 var input = document.getElementById("input");
 
 function test()
 {
   function getSelectionForEditor(aEditorElement)
new file mode 100644
--- /dev/null
+++ b/layout/reftests/bugs/846144-1-ref.html
@@ -0,0 +1,24 @@
+<!DOCTYPE html>
+<html><head>
+<meta http-equiv="content-type" content="text/html; charset=ISO-8859-1">
+  <title>Border radius issue demo</title>
+  <style type="text/css">
+    .testClass {
+    width: 100px;
+    height: 100px;
+    margin: 20px;
+    background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACgAAAAoCAIAAAADnC86AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAadEVYdFNvZnR3YXJlAFBhaW50Lk5FVCB2My41LjEwMPRyoQAAADdJREFUWEftzTERACAMADH8VAH+hRUXz5K77Dl39gtxRpwRZ8QZcUacEWfEGXFGnBFnxBlxZPYBKVqrOft7R9EAAAAASUVORK5CYII=);
+    border-radius: 50px;
+    /* Adding compatibility attributes for cross-browser comparison
+       Issue repros fine with just transform set. */
+    -moz-transform: translate(0,0);
+    -ms-transform: translate(0,0);
+    -webkit-transform: translate(0,0)
+    transform: translate(0,0);
+}
+
+  </style>
+</head>
+<body>
+	<div class="testClass"></div>
+</body></html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/bugs/846144-1.html
@@ -0,0 +1,24 @@
+<!DOCTYPE html>
+<html><head>
+<meta http-equiv="content-type" content="text/html; charset=ISO-8859-1">
+  <title>Border radius issue demo</title>
+  <style type="text/css">
+    .testClass {
+    width: 100px;
+    height: 100px;
+    margin: 20px;
+    background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACgAAAAoCAIAAAADnC86AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAadEVYdFNvZnR3YXJlAFBhaW50Lk5FVCB2My41LjEwMPRyoQAAADdJREFUWEftzTERACAMADH8VAH+hRUXz5K77Dl39gtxRpwRZ8QZcUacEWfEGXFGnBFnxBlxZPYBKVqrOft7R9EAAAAASUVORK5CYII=);
+    border-radius: 50px;
+    background-size: contain;
+    /* Adding compatibility attributes for cross-browser comparison
+       Issue repros fine with just transform set. */
+    -moz-transform: translate(0,0);
+    -ms-transform: translate(0,0);
+    -webkit-transform: translate(0,0)
+    transform: translate(0,0);
+}
+  </style>
+</head>
+<body>
+	<div class="testClass"></div>
+</body></html>
--- a/layout/reftests/bugs/reftest.list
+++ b/layout/reftests/bugs/reftest.list
@@ -1742,8 +1742,9 @@ skip-if(B2G) == 814952-1.html 814952-1-r
 == 816948-1.html 816948-1-ref.html
 == 817019-1.html about:blank
 skip-if(B2G) == 818276-1.html 818276-1-ref.html
 == 825999.html 825999-ref.html
 == 827577-1a.html 827577-1-ref.html
 == 827577-1b.html 827577-1-ref.html
 == 827799-1.html about:blank
 == 836844-1.html 836844-1-ref.html
+== 846144-1.html 846144-1-ref.html
--- a/layout/style/test/test_pointer-events.html
+++ b/layout/style/test/test_pointer-events.html
@@ -45,21 +45,17 @@
     iframe.contentDocument.writeln("<"+"/script>");
     iframe.contentDocument.close();
   </script>
 
 </div>
 <pre id="test">
 <script type="application/javascript;version=1.8">
 
-if (navigator.platform.startsWith("Win")) {
-  SimpleTest.expectAssertions(0, 1);
-} else {
-  SimpleTest.expectAssertions(1);
-}
+SimpleTest.expectAssertions(0, 1);
 
 SimpleTest.waitForExplicitFinish();
 
 function catches_pointer_events(element_id)
 {
     // we just assume the element is on top here.
     var element = document.getElementById(element_id);
     var bounds = element.getBoundingClientRect();
--- a/layout/svg/nsSVGMaskFrame.cpp
+++ b/layout/svg/nsSVGMaskFrame.cpp
@@ -108,48 +108,27 @@ nsSVGMaskFrame::ComputeMaskAlpha(nsRende
     if (SVGFrame) {
       SVGFrame->NotifySVGChanged(nsISVGChildFrame::TRANSFORM_CHANGED);
     }
     nsSVGUtils::PaintFrameWithEffects(&tmpCtx, nullptr, kid);
   }
 
   uint8_t *data   = image->Data();
   int32_t  stride = image->Stride();
+  nsIntRect rect(0, 0, surfaceSize.width, surfaceSize.height);
 
   if (StyleSVGReset()->mMaskType == NS_STYLE_MASK_TYPE_LUMINANCE) {
-    nsIntRect rect(0, 0, surfaceSize.width, surfaceSize.height);
-    nsSVGUtils::UnPremultiplyImageDataAlpha(data, stride, rect);
     if (StyleSVG()->mColorInterpolation ==
         NS_STYLE_COLOR_INTERPOLATION_LINEARRGB) {
-      nsSVGUtils::ConvertImageDataToLinearRGB(data, stride, rect);
-    }
-
-    for (int32_t y = 0; y < surfaceSize.height; y++) {
-      for (int32_t x = 0; x < surfaceSize.width; x++) {
-        uint8_t *pixel = data + stride * y + 4 * x;
-
-        /* linearRGB -> intensity */
-        uint8_t alpha =
-          static_cast<uint8_t>
-                     ((pixel[GFX_ARGB32_OFFSET_R] * 0.2125 +
-                          pixel[GFX_ARGB32_OFFSET_G] * 0.7154 +
-                          pixel[GFX_ARGB32_OFFSET_B] * 0.0721) *
-                         (pixel[GFX_ARGB32_OFFSET_A] / 255.0) * aOpacity);
-
-        memset(pixel, alpha, 4);
-      }
+      nsSVGUtils::ComputeLinearRGBLuminanceMask(data, stride, rect, aOpacity);
+    } else {
+      nsSVGUtils::ComputesRGBLuminanceMask(data, stride, rect, aOpacity);
     }
   } else {
-    for (int32_t y = 0; y < surfaceSize.height; y++) {
-      for (int32_t x = 0; x < surfaceSize.width; x++) {
-        uint8_t *pixel = data + stride * y + 4 * x;
-        uint8_t alpha = pixel[GFX_ARGB32_OFFSET_A] * aOpacity;
-        memset(pixel, alpha, 4);
-      }
-    }
+    nsSVGUtils::ComputeAlphaMask(data, stride, rect, aOpacity);
   }
 
   gfxPattern *retval = new gfxPattern(image);
   retval->SetMatrix(matrix);
   NS_IF_ADDREF(retval);
   return retval;
 }
 
--- a/layout/svg/nsSVGUtils.cpp
+++ b/layout/svg/nsSVGUtils.cpp
@@ -299,16 +299,102 @@ nsSVGUtils::ConvertImageDataFromLinearRG
       pixel[GFX_ARGB32_OFFSET_G] =
         glinearRGBTosRGBMap[pixel[GFX_ARGB32_OFFSET_G]];
       pixel[GFX_ARGB32_OFFSET_R] =
         glinearRGBTosRGBMap[pixel[GFX_ARGB32_OFFSET_R]];
     }
   }
 }
 
+void
+nsSVGUtils::ComputesRGBLuminanceMask(uint8_t *aData,
+                                     int32_t aStride,
+                                     const nsIntRect &aRect,
+                                     float aOpacity)
+{
+  for (int32_t y = aRect.y; y < aRect.YMost(); y++) {
+    for (int32_t x = aRect.x; x < aRect.XMost(); x++) {
+      uint8_t *pixel = aData + aStride * y + 4 * x;
+      uint8_t a = pixel[GFX_ARGB32_OFFSET_A];
+
+      uint8_t luminance;
+      if (a) {
+        /* sRGB -> intensity (unpremultiply cancels out the
+         * (a/255.0) multiplication with aOpacity */
+        luminance =
+          static_cast<uint8_t>
+                     ((pixel[GFX_ARGB32_OFFSET_R] * 0.2125 +
+                          pixel[GFX_ARGB32_OFFSET_G] * 0.7154 +
+                          pixel[GFX_ARGB32_OFFSET_B] * 0.0721) *
+                          aOpacity);
+      } else {
+        luminance = 0;
+      }
+
+      memset(pixel, luminance, 4);
+    }
+  }
+}
+
+void
+nsSVGUtils::ComputeLinearRGBLuminanceMask(uint8_t *aData,
+                                          int32_t aStride,
+                                          const nsIntRect &aRect,
+                                          float aOpacity)
+{
+  for (int32_t y = aRect.y; y < aRect.YMost(); y++) {
+    for (int32_t x = aRect.x; x < aRect.XMost(); x++) {
+      uint8_t *pixel = aData + aStride * y + 4 * x;
+      uint8_t a = pixel[GFX_ARGB32_OFFSET_A];
+
+      uint8_t luminance;
+      // unpremultiply
+      if (a) {
+        if (a != 255) {
+          pixel[GFX_ARGB32_OFFSET_B] =
+            (255 * pixel[GFX_ARGB32_OFFSET_B]) / a;
+          pixel[GFX_ARGB32_OFFSET_G] =
+            (255 * pixel[GFX_ARGB32_OFFSET_G]) / a;
+          pixel[GFX_ARGB32_OFFSET_R] =
+            (255 * pixel[GFX_ARGB32_OFFSET_R]) / a;
+        }
+
+        /* sRGB -> linearRGB -> intensity */
+        luminance =
+          static_cast<uint8_t>
+                     ((gsRGBToLinearRGBMap[pixel[GFX_ARGB32_OFFSET_R]] *
+                          0.2125 +
+                          gsRGBToLinearRGBMap[pixel[GFX_ARGB32_OFFSET_G]] *
+                          0.7154 +
+                          gsRGBToLinearRGBMap[pixel[GFX_ARGB32_OFFSET_B]] *
+                          0.0721) * (a / 255.0) * aOpacity);
+      } else {
+        luminance = 0;
+      }
+
+      memset(pixel, luminance, 4);
+    }
+  }
+}
+
+void
+nsSVGUtils::ComputeAlphaMask(uint8_t *aData,
+                             int32_t aStride,
+                             const nsIntRect &aRect,
+                             float aOpacity)
+{
+  for (int32_t y = aRect.y; y < aRect.YMost(); y++) {
+    for (int32_t x = aRect.x; x < aRect.XMost(); x++) {
+      uint8_t *pixel = aData + aStride * y + 4 * x;
+      uint8_t luminance = pixel[GFX_ARGB32_OFFSET_A] * aOpacity;
+      memset(pixel, luminance, 4);
+    }
+  }
+}
+
 float
 nsSVGUtils::CoordToFloat(nsPresContext *aPresContext,
                          nsSVGElement *aContent,
                          const nsStyleCoord &aCoord)
 {
   switch (aCoord.GetUnit()) {
   case eStyleUnit_Factor:
     // user units
--- a/layout/svg/nsSVGUtils.h
+++ b/layout/svg/nsSVGUtils.h
@@ -226,16 +226,40 @@ public:
   /*
    * Converts image data from LinearRGB to premultiplied sRGB
    */
   static void ConvertImageDataFromLinearRGB(uint8_t *data, 
                                             int32_t stride, 
                                             const nsIntRect &rect);
 
   /*
+   * Converts image data from sRGB to luminance
+   */
+  static void ComputesRGBLuminanceMask(uint8_t *aData,
+                                       int32_t aStride,
+                                       const nsIntRect &aRect,
+                                       float aOpacity);
+
+  /*
+   * Converts image data from sRGB to luminance assuming
+   * Linear RGB Interpolation
+   */
+  static void ComputeLinearRGBLuminanceMask(uint8_t *aData,
+                                            int32_t aStride,
+                                            const nsIntRect &aRect,
+                                            float aOpacity);
+  /*
+   * Converts image data to luminance using the value of alpha as luminance
+   */
+  static void ComputeAlphaMask(uint8_t *aData,
+                               int32_t aStride,
+                               const nsIntRect &aRect,
+                               float aOpacity);
+
+  /*
    * Converts a nsStyleCoord into a userspace value.  Handles units
    * Factor (straight userspace), Coord (dimensioned), and Percent (of
    * the current SVG viewport)
    */
   static float CoordToFloat(nsPresContext *aPresContext,
                             nsSVGElement *aContent,
                             const nsStyleCoord &aCoord);
 
--- a/layout/xul/base/src/nsMenuFrame.cpp
+++ b/layout/xul/base/src/nsMenuFrame.cpp
@@ -1276,17 +1276,19 @@ nsMenuFrame::PassMenuCommandEventToPopup
   mDelayedMenuCommandEvent = nullptr;
 }
 
 NS_IMETHODIMP
 nsMenuFrame::RemoveFrame(ChildListID     aListID,
                          nsIFrame*       aOldFrame)
 {
   nsFrameList* popupList = GetPopupList();
-  if (popupList && popupList->DestroyFrameIfPresent(aOldFrame)) {
+  if (popupList && popupList->FirstChild() == aOldFrame) {
+    popupList->RemoveFirstChild();
+    aOldFrame->Destroy();
     DestroyPopupList();
     PresContext()->PresShell()->
       FrameNeedsReflow(this, nsIPresShell::eTreeChange,
                        NS_FRAME_HAS_DIRTY_CHILDREN);
     return NS_OK;
   }
   return nsBoxFrame::RemoveFrame(aListID, aOldFrame);
 }
--- a/media/webrtc/signaling/src/sipcc/cpr/darwin/cpr_darwin_threads.c
+++ b/media/webrtc/signaling/src/sipcc/cpr/darwin/cpr_darwin_threads.c
@@ -51,75 +51,73 @@ cprCreateThread (const char *name,
     static uint16_t id = 0;
     cpr_thread_t *threadPtr;
     pthread_t threadId;
     pthread_attr_t attr;
 
     CPR_INFO("%s: creating '%s' thread\n", fname, name);
 
     /* Malloc memory for a new thread */
-    threadPtr = (cpr_thread_t *)cpr_malloc(sizeof(cpr_thread_t));
+    threadPtr = cpr_malloc(sizeof(cpr_thread_t));
     if (threadPtr != NULL) {
         if (pthread_attr_init(&attr) != 0) {
 
             CPR_ERROR("%s - Failed to init attribute for thread %s\n",
                       fname, name);
             cpr_free(threadPtr);
-            return (cprThread_t)NULL;
+            return NULL;
         }
 
         if (pthread_attr_setstacksize(&attr, stackSize) != 0) {
             CPR_ERROR("%s - Invalid stacksize %d specified for thread %s\n",
                       fname, stackSize, name);
             cpr_free(threadPtr);
-            return (cprThread_t)NULL;
+            return NULL;
         }
 
         if (pthread_create(&threadId, &attr, startRoutine, data) != 0) {
             CPR_ERROR("%s - Creation of thread %s failed: %d\n",
                       fname, name, errno);
             cpr_free(threadPtr);
-            return (cprThread_t)NULL;
+            return NULL;
         }
 
         /* Assign name to CPR if one was passed in */
-        if (name != NULL) {
-            threadPtr->name = name;
-        }
+        threadPtr->name = name;
 
         /*
          * TODO - It would be nice for CPR to keep a linked
          * list of running threads for debugging purposes
          * such as a show command or walking the list to ensure
          * that an application does not attempt to create
          * the same thread twice.
          */
-        threadPtr->u.handleInt = (uint64_t)threadId;
+        threadPtr->u.handlePtr = threadId;
         threadPtr->threadId = ++id;
-        return (cprThread_t)threadPtr;
+        return threadPtr;
     }
 
     /* Malloc failed */
     CPR_ERROR("%s - Malloc for thread %s failed.\n", fname, name);
     errno = ENOMEM;
-    return (cprThread_t)NULL;
+    return NULL;
 }
 
 /*
  * cprJoinThread
  *
  * wait for thread termination
  */
 void cprJoinThread(cprThread_t thread)
 {
     cpr_thread_t *cprThreadPtr;
 
     cprThreadPtr = (cpr_thread_t *) thread;
     MOZ_ASSERT(cprThreadPtr);
-    pthread_join(cprThreadPtr->u.handleInt, NULL);
+    pthread_join(cprThreadPtr->u.handlePtr, NULL);
 }
 
 /**
  * cprDestroyThread
  *
  * @brief Destroys the thread passed in.
  *
  * The cprDestroyThread function is called to destroy a thread. The thread
@@ -137,17 +135,17 @@ cprDestroyThread (cprThread_t thread)
 {
     cpr_thread_t *cprThreadPtr;
 
     cprThreadPtr = (cpr_thread_t *) thread;
     if (cprThreadPtr) {
         /*
          * Make sure thread is trying to destroy itself.
          */
-        if (cprThreadPtr->u.handlePtr == (void*) pthread_self()) {
+        if (cprThreadPtr->u.handlePtr == pthread_self()) {
             CPR_INFO("%s: Destroying Thread %d", __FUNCTION__, cprThreadPtr->threadId);
             pthread_exit(NULL);
             return CPR_SUCCESS;
         }
 
         CPR_ERROR("%s: Thread attempted to destroy another thread, not itself.",
                   __FUNCTION__);
         MOZ_ASSERT(PR_FALSE);
@@ -204,13 +202,13 @@ cprAdjustRelativeThreadPriority (int rel
  *
  * @return Thread's Id or zero(0)
  *
  */
 pthread_t
 cprGetThreadId (cprThread_t thread)
 {
     if (thread) {
-        return (pthread_t)(long) ((cpr_thread_t *)thread)->u.handleInt;
+        return ((cpr_thread_t *)thread)->u.handlePtr;
     }
     return 0;
 }
 
--- a/mobile/android/base/AboutHomeContent.java
+++ b/mobile/android/base/AboutHomeContent.java
@@ -762,39 +762,21 @@ public class AboutHomeContent extends Sc
     @Override
     public void onLightweightThemeChanged() {
         LightweightThemeDrawable drawable = mActivity.getLightweightTheme().getColorDrawable(this);
         if (drawable == null)
             return;
 
          drawable.setAlpha(255, 0);
          setBackgroundDrawable(drawable);
-
-         boolean isLight = mActivity.getLightweightTheme().isLightTheme();
-
-         if (mAddons != null) {
-             mAddons.setTheme(isLight);
-             mLastTabs.setTheme(isLight);
-             mRemoteTabs.setTheme(isLight);
-             ((GeckoImageView) findViewById(R.id.abouthome_logo)).setTheme(isLight);
-             ((GeckoTextView) findViewById(R.id.top_sites_title)).setTheme(isLight);
-         }
     }
 
     @Override
     public void onLightweightThemeReset() {
         setBackgroundColor(getContext().getResources().getColor(R.color.background_normal));
-
-        if (mAddons != null) {
-            mAddons.resetTheme();
-            mLastTabs.resetTheme();
-            mRemoteTabs.resetTheme();
-            ((GeckoImageView) findViewById(R.id.abouthome_logo)).resetTheme();
-            ((GeckoTextView) findViewById(R.id.top_sites_title)).resetTheme();
-        }
     }
 
     @Override
     protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
         super.onLayout(changed, left, top, right, bottom);
         onLightweightThemeChanged();
     }
 
--- a/mobile/android/base/AllCapsTextView.java
+++ b/mobile/android/base/AllCapsTextView.java
@@ -1,18 +1,19 @@
 /* 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/. */
 
 package org.mozilla.gecko;
 
 import android.content.Context;
 import android.util.AttributeSet;
+import android.widget.TextView;
 
-public class AllCapsTextView extends GeckoTextView {
+public class AllCapsTextView extends TextView {
 
     public AllCapsTextView(Context context, AttributeSet attrs) {
         super(context, attrs);
     }
 
     @Override
     public void setText(CharSequence text, BufferType type) {
         super.setText(text.toString().toUpperCase(), type);
--- a/mobile/android/base/AndroidManifest.xml.in
+++ b/mobile/android/base/AndroidManifest.xml.in
@@ -4,17 +4,16 @@
       package="@ANDROID_PACKAGE_NAME@"
       android:installLocation="auto"
       android:versionCode="@ANDROID_VERSION_CODE@"
       android:versionName="@MOZ_APP_VERSION@"
 #ifdef MOZ_ANDROID_SHARED_ID
       android:sharedUserId="@MOZ_ANDROID_SHARED_ID@"
 #endif
       >
-    <supports-screens android:smallScreens="false" />
     <uses-sdk android:minSdkVersion="8"
               android:targetSdkVersion="14"/>
 
 #include ../services/manifests/AnnouncementsAndroidManifest_permissions.xml.in
 #include ../services/manifests/SyncAndroidManifest_permissions.xml.in
 
     <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
     <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
--- a/mobile/android/base/AwesomeBarTabs.java
+++ b/mobile/android/base/AwesomeBarTabs.java
@@ -218,16 +218,17 @@ public class AwesomeBarTabs extends TabH
             Tab tab = Tabs.getInstance().getSelectedTab();
             if (tab != null)
                 isPrivate = tab.isPrivate();
         }
 
         for (int i = 0; i < tabWidget.getTabCount(); i++) {
             GeckoTextView view = (GeckoTextView) tabWidget.getChildTabViewAt(i);
             if (isPrivate) {
+                view.resetTheme();
                 view.setPrivateMode((i == selIndex) ? false : true);
             } else {
                 if (i == selIndex)
                     view.resetTheme();
                 else if (mActivity.getLightweightTheme().isEnabled())
                     view.setTheme(mActivity.getLightweightTheme().isLightTheme());
                 else
                     view.resetTheme();
@@ -337,47 +338,34 @@ public class AwesomeBarTabs extends TabH
         styleSelectedTab();
         if (mTarget.equals(AwesomeBar.Target.CURRENT_TAB.name())) {
             Tab tab = Tabs.getInstance().getSelectedTab();
             if (tab != null && tab.isPrivate())
                 ((BackgroundLayout) findViewById(R.id.tab_widget_container)).setPrivateMode(true);
         }
     }
 
-    public static class BackgroundLayout extends GeckoLinearLayout
-                                         implements LightweightTheme.OnChangeListener { 
+    public static class BackgroundLayout extends GeckoLinearLayout {
         private GeckoActivity mActivity;
 
         public BackgroundLayout(Context context, AttributeSet attrs) {
             super(context, attrs);
             mActivity = (GeckoActivity) context;
         }
 
         @Override
-        public void onAttachedToWindow() {
-            super.onAttachedToWindow();
-            mActivity.getLightweightTheme().addListener(this);
-        }
-
-        @Override
-        public void onDetachedFromWindow() {
-            super.onDetachedFromWindow();
-            mActivity.getLightweightTheme().removeListener(this);
-        }
-
-        @Override
         public void onLightweightThemeChanged() {
             LightweightThemeDrawable drawable = mActivity.getLightweightTheme().getColorDrawable(this);
             if (drawable == null)
                 return;
 
             drawable.setAlpha(255, 0);
 
             StateListDrawable stateList = new StateListDrawable();
-            stateList.addState(new int[] { R.attr.state_private }, new ColorDrawable(mActivity.getResources().getColor(R.color.background_normal)));
+            stateList.addState(new int[] { R.attr.state_private }, new ColorDrawable(mActivity.getResources().getColor(R.color.background_private)));
             stateList.addState(new int[] {}, drawable);
 
             int[] padding =  new int[] { getPaddingLeft(),
                                          getPaddingTop(),
                                          getPaddingRight(),
                                          getPaddingBottom()
                                        };
             setBackgroundDrawable(stateList);
@@ -389,16 +377,10 @@ public class AwesomeBarTabs extends TabH
             int[] padding =  new int[] { getPaddingLeft(),
                                          getPaddingTop(),
                                          getPaddingRight(),
                                          getPaddingBottom()
                                        };
             setBackgroundResource(R.drawable.address_bar_bg);
             setPadding(padding[0], padding[1], padding[2], padding[3]);
         }
-
-        @Override
-        protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
-            super.onLayout(changed, left, top, right, bottom);
-            onLightweightThemeChanged();
-        }
     }
 }
--- a/mobile/android/base/BrowserApp.java
+++ b/mobile/android/base/BrowserApp.java
@@ -331,17 +331,18 @@ abstract public class BrowserApp extends
 
         if (mAboutHomeContent != null)
             mAboutHomeContent.refresh();
     }
 
     @Override
     protected void onActivityResult(int requestCode, int resultCode, Intent data) {
         super.onActivityResult(requestCode, resultCode, data);
-        mBrowserToolbar.fromAwesomeBarSearch();
+        String url = resultCode == Activity.RESULT_OK ? data.getStringExtra(AwesomeBar.URL_KEY) : null;
+        mBrowserToolbar.fromAwesomeBarSearch(url);
     }
 
     public View getActionBarLayout() {
         int actionBarRes;
 
         if (!hasPermanentMenuKey() || isTablet())
            actionBarRes = R.layout.browser_toolbar_menu;
         else
--- a/mobile/android/base/BrowserToolbar.java
+++ b/mobile/android/base/BrowserToolbar.java
@@ -328,27 +328,37 @@ public class BrowserToolbar implements V
         if (mHasSoftMenuButton) {
             mMenu.setVisibility(View.VISIBLE);
             mMenu.setOnClickListener(new Button.OnClickListener() {
                 @Override
                 public void onClick(View view) {
                     mActivity.openOptionsMenu();
                 }
             });
+        }
 
+        if (!mActivity.isTablet()) {
             // Set a touch delegate to Tabs button, so the touch events on its tail
             // are passed to the menu button.
             mLayout.post(new Runnable() {
                 @Override
                 public void run() {
                     int height = mTabs.getHeight();
                     int width = mTabs.getWidth();
                     int tail = (width - height) / 2;
-                    Rect bounds = new Rect(width - tail, 0, width, height);
-                    mTabs.setTouchDelegate(new TailTouchDelegate(bounds, mMenu));
+
+                    Rect leftBounds = new Rect(0, 0, tail, height);
+                    Rect rightBounds = new Rect(width - tail, 0, width, height);
+
+                    TailTouchDelegate delegate = new TailTouchDelegate(leftBounds, mAddressBarView);
+
+                    if (mHasSoftMenuButton)
+                        delegate.add(rightBounds, mMenu);
+
+                    mTabs.setTouchDelegate(delegate);
                 }
             });
         }
 
         if (Build.VERSION.SDK_INT >= 11) {
             View panel = mActivity.getMenuPanel();
 
             // If panel is null, the app is starting up for the first time;
@@ -407,16 +417,18 @@ public class BrowserToolbar implements V
                     setReaderMode(tab.getReaderEnabled());
                 }
                 break;
             case STOP:
                 if (Tabs.getInstance().isSelectedTab(tab)) {
                     updateBackButton(tab.canDoBack());
                     updateForwardButton(tab.canDoForward());
                     setProgressVisibility(false);
+                    // Reset the title in case we haven't navigated to a new page yet.
+                    setTitle(tab.getDisplayTitle());
                 }
                 break;
             case RESTORED:
                 updateTabCount(Tabs.getInstance().getCount());
                 break;
             case SELECTED:
                 mAnimateSiteSecurity = false;
                 // fall through
@@ -531,17 +543,23 @@ public class BrowserToolbar implements V
         }
 
         // Make the right edge visible to start the animation
         mAwesomeBarRightEdge.setVisibility(View.VISIBLE);
 
         return translation;
     }
 
-    public void fromAwesomeBarSearch() {
+    public void fromAwesomeBarSearch(String url) {
+        // Update the title with the url that was just entered. Don't update the title if
+        // the AwesomeBar activity was cancelled, or if the user entered an empty string.
+        if (url != null && url.length() > 0) {
+            setTitle(url);
+        }
+
         if (mActivity.isTablet() || Build.VERSION.SDK_INT < 11) {
             return;
         }
 
         AnimatorProxy proxy = null;
 
         // If the awesomebar entry is not selected at this point, this means that
         // we had to reinflate the toolbar layout for some reason (device rotation
@@ -990,27 +1008,28 @@ public class BrowserToolbar implements V
         visible &= !(url == null || (url.startsWith("about:") && 
                      !url.equals("about:blank")));
 
         if ((mShadow.getVisibility() == View.VISIBLE) != visible) {
             mShadow.setVisibility(visible ? View.VISIBLE : View.GONE);
         }
     }
 
-    public void setTitle(CharSequence title) {
+    private void setTitle(CharSequence title) {
         Tab tab = Tabs.getInstance().getSelectedTab();
 
         // Keep the title unchanged if the tab is entering reader mode
         if (tab != null && tab.isEnteringReaderMode())
             return;
 
-        // Setting a null title will ensure we just see
-        // the "Enter Search or Address" placeholder text
-        if (tab != null && ("about:home".equals(tab.getURL()) ||
-                            "about:privatebrowsing".equals(tab.getURL())))
+        // Setting a null title will ensure we just see the "Enter Search or Address"
+        // placeholder text. Because "about:home" and "about:privatebrowsing" don't
+        // have titles, their display titles will always match their URLs.
+        if (tab != null && ("about:home".equals(title) ||
+                            "about:privatebrowsing".equals(title)))
             title = null;
 
         mTitle.setText(title);
         mAwesomeBar.setContentDescription(title != null ? title : mTitle.getHint());
     }
 
     private void setFavicon(Bitmap image) {
         if (Tabs.getInstance().getSelectedTab().getState() == Tab.STATE_LOADING)
@@ -1243,38 +1262,25 @@ public class BrowserToolbar implements V
             return false;
 
         if (mMenuPopup != null && mMenuPopup.isShowing())
             mMenuPopup.dismiss();
 
         return true;
     }
 
-    public static class RightEdge extends GeckoFrameLayout
-                                  implements LightweightTheme.OnChangeListener { 
+    public static class RightEdge extends GeckoFrameLayout {
         private BrowserApp mActivity;
 
         public RightEdge(Context context, AttributeSet attrs) {
             super(context, attrs);
             mActivity = (BrowserApp) context;
         }
 
         @Override
-        public void onAttachedToWindow() {
-            super.onAttachedToWindow();
-            mActivity.getLightweightTheme().addListener(this);
-        }
-
-        @Override
-        public void onDetachedFromWindow() {
-            super.onDetachedFromWindow();
-            mActivity.getLightweightTheme().removeListener(this);
-        }
-
-        @Override
         public void onLightweightThemeChanged() {
             Drawable drawable = mActivity.getLightweightTheme().getDrawable(this);
             if (drawable == null)
                 return;
 
             StateListDrawable stateList = new StateListDrawable();
             stateList.addState(new int[] { R.attr.state_private }, new ColorDrawable(mActivity.getResources().getColor(R.color.background_private)));
             stateList.addState(new int[] {}, drawable);
@@ -1293,16 +1299,10 @@ public class BrowserToolbar implements V
             int[] padding =  new int[] { getPaddingLeft(),
                                          getPaddingTop(),
                                          getPaddingRight(),
                                          getPaddingBottom()
                                        };
             setBackgroundResource(R.drawable.address_bar_bg);
             setPadding(padding[0], padding[1], padding[2], padding[3]);
         }
-
-        @Override
-        protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
-            super.onLayout(changed, left, top, right, bottom);
-            onLightweightThemeChanged();
-        }
     }
 }
--- a/mobile/android/base/BrowserToolbarBackground.java
+++ b/mobile/android/base/BrowserToolbarBackground.java
@@ -10,18 +10,17 @@ import android.graphics.Canvas;
 import android.graphics.Path;
 import android.graphics.PorterDuff.Mode;
 import android.graphics.drawable.ColorDrawable;
 import android.graphics.drawable.Drawable;
 import android.graphics.drawable.StateListDrawable;
 import android.util.AttributeSet;
 
 public class BrowserToolbarBackground extends GeckoLinearLayout
-                                      implements CanvasDelegate.DrawManager,
-                                                 LightweightTheme.OnChangeListener { 
+                                      implements CanvasDelegate.DrawManager {
     private GeckoActivity mActivity;
     private Path mPath;
     private CurveTowards mSide;
     private CanvasDelegate mCanvasDelegate;
 
     public enum CurveTowards { NONE, LEFT, RIGHT };
 
     public BrowserToolbarBackground(Context context, AttributeSet attrs) {
@@ -40,28 +39,16 @@ public class BrowserToolbarBackground ex
 
         // Path is clipped.
         mPath = new Path();
         mCanvasDelegate = new CanvasDelegate(this, Mode.DST_OUT);
         mActivity = (GeckoActivity) context;
     }
 
     @Override
-    public void onAttachedToWindow() {
-        super.onAttachedToWindow();
-        mActivity.getLightweightTheme().addListener(this);
-    }
-
-    @Override
-    public void onDetachedFromWindow() {
-        super.onDetachedFromWindow();
-        mActivity.getLightweightTheme().removeListener(this);
-    }
-
-    @Override
     public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
         super.onMeasure(widthMeasureSpec, heightMeasureSpec);
 
         int width = getMeasuredWidth();
         int height = getMeasuredHeight();
         int curve = (int) (height * 1.125f);
 
         mPath.reset();
@@ -118,22 +105,16 @@ public class BrowserToolbarBackground ex
                                      getPaddingTop(),
                                      getPaddingRight(),
                                      getPaddingBottom()
                                    };
         setBackgroundResource(R.drawable.address_bar_bg);
         setPadding(padding[0], padding[1], padding[2], padding[3]);
     }
 
-    @Override
-    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
-        super.onLayout(changed, left, top, right, bottom);
-        onLightweightThemeChanged();
-    }
-
     public CurveTowards getCurveTowards() {
         return mSide;
     }
 
     public void setCurveTowards(CurveTowards side) {
         if (side == mSide)
             return;
 
--- a/mobile/android/base/CustomEditText.java
+++ b/mobile/android/base/CustomEditText.java
@@ -6,19 +6,19 @@
 package org.mozilla.gecko;
 
 import android.content.Context;
 import android.util.AttributeSet;
 import android.view.KeyEvent;
 import android.view.View;
 
 public class CustomEditText extends GeckoEditText {
-    OnKeyPreImeListener mOnKeyPreImeListener;
-    OnSelectionChangedListener mOnSelectionChangedListener;
-    OnWindowFocusChangeListener mOnWindowFocusChangeListener;
+    private OnKeyPreImeListener mOnKeyPreImeListener;
+    private OnSelectionChangedListener mOnSelectionChangedListener;
+    private OnWindowFocusChangeListener mOnWindowFocusChangeListener;
 
     public CustomEditText(Context context, AttributeSet attrs) {
         super(context, attrs);
         mOnKeyPreImeListener = null;
     }
 
     public interface OnKeyPreImeListener {
         public boolean onKeyPreIme(View v, int keyCode, KeyEvent event);
--- a/mobile/android/base/GeckoView.java.frag
+++ b/mobile/android/base/GeckoView.java.frag
@@ -1,45 +1,88 @@
 /* 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/. */
 
 package org.mozilla.gecko;
 
 import android.content.Context;
+import android.content.res.TypedArray;
 import android.util.AttributeSet;
 import android.widget.@VIEWTYPE@;
 
-public class Gecko@VIEWTYPE@ extends @VIEWTYPE@ {
+public class Gecko@VIEWTYPE@ extends @VIEWTYPE@
+                             implements LightweightTheme.OnChangeListener { 
+    private GeckoActivity mActivity;
     private static final int[] STATE_PRIVATE_MODE = { R.attr.state_private };
     private static final int[] STATE_LIGHT = { R.attr.state_light };
     private static final int[] STATE_DARK = { R.attr.state_dark };
 
     private boolean mIsPrivate = false;
     private boolean mIsLight = false;
     private boolean mIsDark = false;
+    private boolean mAutoUpdateTheme = true;
 
     public Gecko@VIEWTYPE@(Context context, AttributeSet attrs) {
         super(context, attrs);
+        mActivity = (GeckoActivity) context;
+
+        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.LightweightTheme);
+        mAutoUpdateTheme = a.getBoolean(R.styleable.LightweightTheme_autoUpdateTheme, true);
+        a.recycle();
+    }
+
+    @Override
+    public void onAttachedToWindow() {
+        super.onAttachedToWindow();
+
+        if (mAutoUpdateTheme)
+            mActivity.getLightweightTheme().addListener(this);
+    }
+
+    @Override
+    public void onDetachedFromWindow() {
+        super.onDetachedFromWindow();
+
+        if (mAutoUpdateTheme)
+            mActivity.getLightweightTheme().removeListener(this);
     }
 
     @Override
     public int[] onCreateDrawableState(int extraSpace) {
         final int[] drawableState = super.onCreateDrawableState(extraSpace + 1);
 
         if (mIsPrivate)
             mergeDrawableStates(drawableState, STATE_PRIVATE_MODE);
         else if (mIsLight)
             mergeDrawableStates(drawableState, STATE_LIGHT);
         else if (mIsDark)
             mergeDrawableStates(drawableState, STATE_DARK);
 
         return drawableState;
     }
 
+    @Override
+    public void onLightweightThemeChanged() {
+        if (mAutoUpdateTheme && mActivity.getLightweightTheme().isEnabled())
+            setTheme(mActivity.getLightweightTheme().isLightTheme());
+    }
+
+    @Override
+    public void onLightweightThemeReset() {
+        if (mAutoUpdateTheme)
+            resetTheme();
+    }
+
+    @Override
+    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+        super.onLayout(changed, left, top, right, bottom);
+        onLightweightThemeChanged();
+    }
+
     public boolean isPrivateMode() {
         return mIsPrivate;
     }
 
     public void setPrivateMode(boolean isPrivate) {
         if (mIsPrivate != isPrivate) {
             mIsPrivate = isPrivate;
             refreshDrawableState();
@@ -63,10 +106,21 @@ public class Gecko@VIEWTYPE@ extends @VI
     }
 
     public void resetTheme() {
         if (mIsLight || mIsDark) {
             mIsLight = false;
             mIsDark = false;
             refreshDrawableState();
         }
-    } 
+    }
+
+    public void setAutoUpdateTheme(boolean autoUpdateTheme) {
+        if (mAutoUpdateTheme != autoUpdateTheme) {
+            mAutoUpdateTheme = autoUpdateTheme;
+
+            if (mAutoUpdateTheme)
+                mActivity.getLightweightTheme().addListener(this);
+            else
+                mActivity.getLightweightTheme().removeListener(this);
+        }
+    }
 }
--- a/mobile/android/base/Makefile.in
+++ b/mobile/android/base/Makefile.in
@@ -251,16 +251,17 @@ FENNEC_PP_XML_FILES = \
   res/drawable/address_bar_bg.xml \
   res/drawable/address_bar_nav_button.xml \
   res/drawable/address_bar_url.xml \
   res/drawable/menu_item_state.xml \
   res/drawable/menu_level.xml \
   res/layout/abouthome_content.xml \
   res/layout/awesomebar_search.xml \
   res/layout/awesomebar_suggestion_row.xml \
+  res/layout/awesomebar_tab_indicator.xml \
   res/layout/browser_toolbar.xml \
   res/layout/browser_toolbar_menu.xml \
   res/layout-land-v14/browser_toolbar.xml \
   res/layout-land-v14/browser_toolbar_menu.xml \
   res/layout-large-v11/awesomebar_search.xml \
   res/layout-large-v11/browser_toolbar_menu.xml \
   res/layout-large-land-v11/tabs_panel.xml \
   res/layout/gecko_app.xml \
@@ -396,17 +397,16 @@ RES_LAYOUT = \
   res/layout/awesomebar_expandable_list.xml \
   res/layout/awesomebar_folder_row.xml \
   res/layout/awesomebar_header_row.xml \
   res/layout/awesomebar_allpages_list.xml \
   res/layout/awesomebar_list.xml \
   res/layout/awesomebar_row.xml \
   res/layout/awesomebar_suggestion_item.xml \
   res/layout/awesomebar_suggestion_prompt.xml \
-  res/layout/awesomebar_tab_indicator.xml \
   res/layout/awesomebar_tabs.xml \
   res/layout/bookmark_edit.xml \
   res/layout/datetime_picker.xml \
   res/layout/doorhangerpopup.xml \
   res/layout/doorhanger.xml \
   res/layout/find_in_page_content.xml \
   res/layout/font_size_preference.xml \
   res/layout/gecko_appwidget.xml \
@@ -1121,17 +1121,19 @@ android-tgts = \
   $(MOZGLUE_PP_JAVA_FILES) \
   $(FENNEC_PP_JAVA_FILES) \
   $(SYNC_PP_JAVA_FILES) \
   package-name.txt \
   $(NULL)
 
 android-preqs = \
   Makefile.in \
-  $(call mkdir_deps,mozglue,db,sync/repositories/android,background/announcements) \
+  $(call mkdir_deps,$(sort $(dir $(MOZGLUE_PP_JAVA_FILES)))) \
+  $(call mkdir_deps,$(sort $(dir $(FENNEC_PP_JAVA_FILES)))) \
+  $(call mkdir_deps,$(sort $(dir $(SYNC_PP_JAVA_FILES)))) \
   $(SERVICES_MANIFEST_FRAGMENTS) \
   WebAppManifestFragment.xml.in \
   WebAppsFragments.java \
   $(NULL)
 
 $(android-tgts): % : %.in $(android-preqs)
 	$(PYTHON) $(topsrcdir)/config/Preprocessor.py \
              $(AUTOMATION_PPARGS) -DOBJDIR="`pwd`" $(DEFINES) $(ACDEFINES) $< > $@
--- a/mobile/android/base/ShapedButton.java
+++ b/mobile/android/base/ShapedButton.java
@@ -6,31 +6,25 @@ package org.mozilla.gecko;
 
 import android.content.Context;
 import android.content.res.TypedArray;
 import android.graphics.Canvas;
 import android.graphics.Path;
 import android.graphics.drawable.Drawable;
 import android.util.AttributeSet;
 
-public abstract class ShapedButton extends GeckoImageButton
-                                   implements CanvasDelegate.DrawManager,
-                                              LightweightTheme.OnChangeListener { 
+public class ShapedButton extends GeckoImageButton
+                          implements CanvasDelegate.DrawManager {
     protected GeckoActivity mActivity;
     protected Path mPath;
     protected CurveTowards mSide;
     protected CanvasDelegate mCanvasDelegate;
 
     protected enum CurveTowards { NONE, LEFT, RIGHT };
 
-    @Override
-    abstract public void onLightweightThemeChanged();
-    @Override
-    abstract public void onLightweightThemeReset();
-
     public ShapedButton(Context context, AttributeSet attrs) {
         super(context, attrs);
         mActivity = (GeckoActivity) context;
 
         TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.BrowserToolbarCurve);
         int curveTowards = a.getInt(R.styleable.BrowserToolbarCurve_curveTowards, 0x02);
         a.recycle();
 
@@ -40,28 +34,16 @@ public abstract class ShapedButton exten
             mSide = CurveTowards.LEFT;
         else
             mSide = CurveTowards.RIGHT;
 
         setWillNotDraw(false);
     }
 
     @Override
-    public void onAttachedToWindow() {
-        super.onAttachedToWindow();
-        mActivity.getLightweightTheme().addListener(this);
-    }
-
-    @Override
-    public void onDetachedFromWindow() {
-        super.onDetachedFromWindow();
-        mActivity.getLightweightTheme().removeListener(this);
-    }
-
-    @Override
     public void draw(Canvas canvas) {
         if (mCanvasDelegate != null)
             mCanvasDelegate.draw(canvas, mPath, getWidth(), getHeight());
         else
             defaultDraw(canvas);
     }
 
     @Override
@@ -91,16 +73,9 @@ public abstract class ShapedButton exten
     public void setBackgroundResource(int resId) {
         if (getBackground() == null || resId == 0) {
             super.setBackgroundResource(resId);
             return;
         }
 
         setBackgroundDrawable(getContext().getResources().getDrawable(resId));
     }
-
-    @Override
-    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
-        super.onLayout(changed, left, top, right, bottom);
-        onLightweightThemeChanged();
-    }
-
 }
--- a/mobile/android/base/TailTouchDelegate.java
+++ b/mobile/android/base/TailTouchDelegate.java
@@ -5,42 +5,70 @@
 
 package org.mozilla.gecko;
 
 import android.graphics.Rect;
 import android.view.TouchDelegate;
 import android.view.MotionEvent;
 import android.view.View;
 
+import java.util.ArrayList;
+import java.util.List;
+
 /**
  * A TouchDelegate to pass the events from one view to another.
  * Usually it's better to give half of the tail's width to the other 
  * view that is being overlapped.
  */
 public class TailTouchDelegate extends TouchDelegate {
+    // Actual delegate that got the ACTION_DOWN event.
+    private TouchDelegate mDelegate;
+
+    // List of delegates.
+    private List<TouchDelegate> mDelegates;
+
     /**
-     * Creates a TailTouchDelegate for a view.
+     * Creates an empty TailTouchDelegate for a view.
      *
      * @param bounds        The rectangular bounds on the view which should delegate events.
      * @param delegateView  The view that should get the delegated events.
      */
     public TailTouchDelegate(Rect bounds, View delegateView) {
         super(bounds, delegateView);
+        mDelegates = new ArrayList<TouchDelegate>();
+        mDelegates.add(new TouchDelegate(bounds, delegateView));
+    }
+
+    /**
+     * Adds an Android TouchDelegate for the view.
+     *
+     * @param bounds        The rectangular bounds on the view which should delegate events.
+     * @param delegateView  The view that should get the delegated events.
+     */
+    public void add(Rect bounds, View delegateView) {
+        mDelegates.add(new TouchDelegate(bounds, delegateView));
     }
 
     @Override 
     public boolean onTouchEvent(MotionEvent event) {
         switch (event.getAction()) {
             case MotionEvent.ACTION_DOWN:
                 // Android bug 36445: Touch Delegation not reset on ACTION_DOWN.
-                if (!super.onTouchEvent(event)) {
+                for (TouchDelegate delegate : mDelegates) {
+                    if (delegate.onTouchEvent(event)) {
+                        mDelegate = delegate;
+                        return true;
+                    }
+
                     MotionEvent cancelEvent = MotionEvent.obtain(event);
                     cancelEvent.setAction(MotionEvent.ACTION_CANCEL);
-                    super.onTouchEvent(cancelEvent);
+                    delegate.onTouchEvent(cancelEvent);
+                    mDelegate = null;
+                }
+                return false;
+            default:
+                if (mDelegate != null)
+                    return mDelegate.onTouchEvent(event);
+                else
                     return false;
-                 } else {
-                    return true;
-                 }
-            default:
-                return super.onTouchEvent(event);
         }
     }
 }
--- a/mobile/android/base/android-services-files.mk
+++ b/mobile/android/base/android-services-files.mk
@@ -1,31 +1,40 @@
 # 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/.
 
 # These files are managed in the android-sync repo. Do not modify directly, or your changes will be lost.
 SYNC_PP_JAVA_FILES := \
-  sync/GlobalConstants.java \
+  background/common/GlobalConstants.java \
   sync/SyncConstants.java \
   background/announcements/AnnouncementsConstants.java \
   $(NULL)
 
 SYNC_JAVA_FILES := \
   background/announcements/Announcement.java \
   background/announcements/AnnouncementPresenter.java \
   background/announcements/AnnouncementsBroadcastReceiver.java \
   background/announcements/AnnouncementsBroadcastService.java \
   background/announcements/AnnouncementsFetchDelegate.java \
   background/announcements/AnnouncementsFetcher.java \
   background/announcements/AnnouncementsFetchResourceDelegate.java \
   background/announcements/AnnouncementsService.java \
   background/announcements/AnnouncementsStartReceiver.java \
-  background/BackgroundConstants.java \
   background/BackgroundService.java \
+  background/common/log/Logger.java \
+  background/common/log/writers/AndroidLevelCachingLogWriter.java \
+  background/common/log/writers/AndroidLogWriter.java \
+  background/common/log/writers/LevelFilteringLogWriter.java \
+  background/common/log/writers/LogWriter.java \
+  background/common/log/writers/PrintLogWriter.java \
+  background/common/log/writers/SimpleTagLogWriter.java \
+  background/common/log/writers/StringLogWriter.java \
+  background/common/log/writers/TagLogWriter.java \
+  background/common/log/writers/ThreadLocalTagLogWriter.java \
   sync/AlreadySyncingException.java \
   sync/CollectionKeys.java \
   sync/CommandProcessor.java \
   sync/CommandRunner.java \
   sync/config/AccountPickler.java \
   sync/config/activities/SelectEnginesActivity.java \
   sync/config/ClientRecordTerminator.java \
   sync/config/ConfigurationMigrator.java \
@@ -74,26 +83,16 @@ SYNC_JAVA_FILES := \
   sync/jpake/stage/GetChannelStage.java \
   sync/jpake/stage/GetRequestStage.java \
   sync/jpake/stage/JPakeStage.java \
   sync/jpake/stage/PutRequestStage.java \
   sync/jpake/stage/VerifyPairingStage.java \
   sync/jpake/Zkp.java \
   sync/JSONRecordFetcher.java \
   sync/KeyBundleProvider.java \
-  sync/log/writers/AndroidLevelCachingLogWriter.java \
-  sync/log/writers/AndroidLogWriter.java \
-  sync/log/writers/LevelFilteringLogWriter.java \
-  sync/log/writers/LogWriter.java \
-  sync/log/writers/PrintLogWriter.java \
-  sync/log/writers/SimpleTagLogWriter.java \
-  sync/log/writers/StringLogWriter.java \
-  sync/log/writers/TagLogWriter.java \
-  sync/log/writers/ThreadLocalTagLogWriter.java \
-  sync/Logger.java \
   sync/MetaGlobal.java \
   sync/MetaGlobalException.java \
   sync/MetaGlobalMissingEnginesException.java \
   sync/MetaGlobalNotSetException.java \
   sync/middleware/Crypto5MiddlewareRepository.java \
   sync/middleware/Crypto5MiddlewareRepositorySession.java \
   sync/middleware/MiddlewareRepository.java \
   sync/middleware/MiddlewareRepositorySession.java \
deleted file mode 100644
--- a/mobile/android/base/background/BackgroundConstants.java
+++ /dev/null
@@ -1,20 +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/. */
-
-package org.mozilla.gecko.background;
-
-/**
- * Constants that are not specific to any individual background service.
- */
-public class BackgroundConstants {
-
-  public static final int SHARED_PREFERENCES_MODE = 0;
-  // These are used to ask Fennec (via reflection) to send
-  // us a pref notification. This avoids us having to guess
-  // Fennec's prefs branch and pref name.
-  // Eventually Fennec might listen to startup notifications and
-  // do this automatically, but this will do for now. See Bug 800244.
-  public static String GECKO_PREFERENCES_CLASS = "org.mozilla.gecko.GeckoPreferences";
-  public static String GECKO_BROADCAST_METHOD  = "broadcastAnnouncementsPref";
-}
\ No newline at end of file
--- a/mobile/android/base/background/BackgroundService.java
+++ b/mobile/android/base/background/BackgroundService.java
@@ -1,15 +1,15 @@
 /* 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/. */
 
 package org.mozilla.gecko.background;
 
-import org.mozilla.gecko.sync.Logger;
+import org.mozilla.gecko.background.common.log.Logger;
 
 import android.app.AlarmManager;
 import android.app.IntentService;
 import android.app.PendingIntent;
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
 import android.net.ConnectivityManager;
--- a/mobile/android/base/background/announcements/Announcement.java
+++ b/mobile/android/base/background/announcements/Announcement.java
@@ -2,18 +2,18 @@
  * 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/. */
 
 package org.mozilla.gecko.background.announcements;
 
 import java.net.URI;
 import java.net.URISyntaxException;
 
+import org.mozilla.gecko.background.common.log.Logger;
 import org.mozilla.gecko.sync.ExtendedJSONObject;
-import org.mozilla.gecko.sync.Logger;
 
 /**
  * Represents a retrieved product announcement.
  *
  * Instances of this class are immutable.
  */
 public class Announcement {
   private static final String LOG_TAG   = "Announcement";
--- a/mobile/android/base/background/announcements/AnnouncementPresenter.java
+++ b/mobile/android/base/background/announcements/AnnouncementPresenter.java
@@ -2,17 +2,17 @@
  * 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/. */
 
 package org.mozilla.gecko.background.announcements;
 
 import java.net.URI;
 
 import org.mozilla.gecko.R;
-import org.mozilla.gecko.sync.GlobalConstants;
+import org.mozilla.gecko.background.common.GlobalConstants;
 
 import android.app.Notification;
 import android.app.NotificationManager;
 import android.app.PendingIntent;
 import android.content.Context;
 import android.content.Intent;
 import android.net.Uri;
 
--- a/mobile/android/base/background/announcements/AnnouncementsBroadcastService.java
+++ b/mobile/android/base/background/announcements/AnnouncementsBroadcastService.java
@@ -2,20 +2,19 @@
  * 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/. */
 
 package org.mozilla.gecko.background.announcements;
 
 import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
 
-import org.mozilla.gecko.background.BackgroundConstants;
 import org.mozilla.gecko.background.BackgroundService;
-import org.mozilla.gecko.sync.GlobalConstants;
-import org.mozilla.gecko.sync.Logger;
+import org.mozilla.gecko.background.common.GlobalConstants;
+import org.mozilla.gecko.background.common.log.Logger;
 
 import android.app.AlarmManager;
 import android.app.PendingIntent;
 import android.content.Context;
 import android.content.Intent;
 import android.content.SharedPreferences;
 import android.content.SharedPreferences.Editor;
 
@@ -50,17 +49,17 @@ public class AnnouncementsBroadcastServi
    * Record the last launch time of our version of Fennec.
    *
    * @param context
    *          the <code>Context</code> to use to gain access to
    *          <code>SharedPreferences</code>.
    */
   public static void recordLastLaunch(final Context context) {
     final long now = System.currentTimeMillis();
-    final SharedPreferences preferences = context.getSharedPreferences(AnnouncementsConstants.PREFS_BRANCH, BackgroundConstants.SHARED_PREFERENCES_MODE);
+    final SharedPreferences preferences = context.getSharedPreferences(AnnouncementsConstants.PREFS_BRANCH, GlobalConstants.SHARED_PREFERENCES_MODE);
 
     // One of several things might be true, according to our logs:
     //
     // * The new current time is older than the last
     // * … or way in the future
     // * … or way in the distant past
     // * … or it's reasonable.
     //
@@ -92,22 +91,22 @@ public class AnnouncementsBroadcastServi
       Logger.debug(LOG_TAG, "Previous launch " + previous + " later than current time " +
                             now + ", but new time is sane. Accepting new time.");
     }
 
     preferences.edit().putLong(AnnouncementsConstants.PREF_LAST_LAUNCH, now).commit();
   }
 
   public static long getPollInterval(final Context context) {
-    SharedPreferences preferences = context.getSharedPreferences(AnnouncementsConstants.PREFS_BRANCH, BackgroundConstants.SHARED_PREFERENCES_MODE);
+    SharedPreferences preferences = context.getSharedPreferences(AnnouncementsConstants.PREFS_BRANCH, GlobalConstants.SHARED_PREFERENCES_MODE);
     return preferences.getLong(AnnouncementsConstants.PREF_ANNOUNCE_FETCH_INTERVAL_MSEC, AnnouncementsConstants.DEFAULT_ANNOUNCE_FETCH_INTERVAL_MSEC);
   }
 
   public static void setPollInterval(final Context context, long interval) {
-    SharedPreferences preferences = context.getSharedPreferences(AnnouncementsConstants.PREFS_BRANCH, BackgroundConstants.SHARED_PREFERENCES_MODE);
+    SharedPreferences preferences = context.getSharedPreferences(AnnouncementsConstants.PREFS_BRANCH, GlobalConstants.SHARED_PREFERENCES_MODE);
     preferences.edit().putLong(AnnouncementsConstants.PREF_ANNOUNCE_FETCH_INTERVAL_MSEC, interval).commit();
   }
 
   @Override
   protected void onHandleIntent(Intent intent) {
     Logger.setThreadLogTag(AnnouncementsConstants.GLOBAL_LOG_TAG);
     final String action = intent.getAction();
     Logger.debug(LOG_TAG, "Broadcast onReceive. Intent is " + action);
@@ -137,32 +136,32 @@ public class AnnouncementsBroadcastServi
    * notification to which we listen.
    *
    * All of this is neatly wrapped in <code>try…catch</code>, so this code
    * will run safely without a Firefox build installed.
    */
   protected void handleSystemLifetimeIntent() {
     // Ask the browser to tell us the current state of the preference.
     try {
-      Class<?> geckoPreferences = Class.forName(BackgroundConstants.GECKO_PREFERENCES_CLASS);
-      Method broadcastSnippetsPref = geckoPreferences.getMethod(BackgroundConstants.GECKO_BROADCAST_METHOD, Context.class);
+      Class<?> geckoPreferences = Class.forName(GlobalConstants.GECKO_PREFERENCES_CLASS);
+      Method broadcastSnippetsPref = geckoPreferences.getMethod(GlobalConstants.GECKO_BROADCAST_METHOD, Context.class);
       broadcastSnippetsPref.invoke(null, this);
       return;
     } catch (ClassNotFoundException e) {
-      Logger.error(LOG_TAG, "Class " + BackgroundConstants.GECKO_PREFERENCES_CLASS + " not found!");
+      Logger.error(LOG_TAG, "Class " + GlobalConstants.GECKO_PREFERENCES_CLASS + " not found!");
       return;
     } catch (NoSuchMethodException e) {
-      Logger.error(LOG_TAG, "Method " + BackgroundConstants.GECKO_PREFERENCES_CLASS + "/" + BackgroundConstants.GECKO_BROADCAST_METHOD + " not found!");
+      Logger.error(LOG_TAG, "Method " + GlobalConstants.GECKO_PREFERENCES_CLASS + "/" + GlobalConstants.GECKO_BROADCAST_METHOD + " not found!");
       return;
     } catch (IllegalArgumentException e) {
-      Logger.error(LOG_TAG, "Got exception invoking " + BackgroundConstants.GECKO_BROADCAST_METHOD + ".");
+      Logger.error(LOG_TAG, "Got exception invoking " + GlobalConstants.GECKO_BROADCAST_METHOD + ".");
     } catch (IllegalAccessException e) {
-      Logger.error(LOG_TAG, "Got exception invoking " + BackgroundConstants.GECKO_BROADCAST_METHOD + ".");
+      Logger.error(LOG_TAG, "Got exception invoking " + GlobalConstants.GECKO_BROADCAST_METHOD + ".");
     } catch (InvocationTargetException e) {
-      Logger.error(LOG_TAG, "Got exception invoking " + BackgroundConstants.GECKO_BROADCAST_METHOD + ".");
+      Logger.error(LOG_TAG, "Got exception invoking " + GlobalConstants.GECKO_BROADCAST_METHOD + ".");
     }
   }
 
   /**
    * Handle the intent sent by the browser when it wishes to notify us
    * of the value of the user preference. Look at the value and toggle the
    * alarm service accordingly.
    */
@@ -178,16 +177,16 @@ public class AnnouncementsBroadcastServi
                           (intent.hasExtra("enabled") ? enabled : ""));
 
     toggleAlarm(this, enabled);
 
     // Primarily intended for debugging and testing, but this doesn't do any harm.
     if (!enabled) {
       Logger.info(LOG_TAG, "!enabled: clearing last fetch.");
       final SharedPreferences sharedPreferences = this.getSharedPreferences(AnnouncementsConstants.PREFS_BRANCH,
-                                                                            BackgroundConstants.SHARED_PREFERENCES_MODE);
+                                                                            GlobalConstants.SHARED_PREFERENCES_MODE);
       final Editor editor = sharedPreferences.edit();
       editor.remove(AnnouncementsConstants.PREF_LAST_FETCH_LOCAL_TIME);
       editor.remove(AnnouncementsConstants.PREF_EARLIEST_NEXT_ANNOUNCE_FETCH);
       editor.commit();
     }
   }
 }
--- a/mobile/android/base/background/announcements/AnnouncementsConstants.java.in
+++ b/mobile/android/base/background/announcements/AnnouncementsConstants.java.in
@@ -1,16 +1,16 @@
 #filter substitution
 /* 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/. */
 
 package org.mozilla.gecko.background.announcements;
 
-import org.mozilla.gecko.sync.GlobalConstants;
+import org.mozilla.gecko.background.common.GlobalConstants;
 
 import android.app.AlarmManager;
 
 public class AnnouncementsConstants {
   // Not `final` so we have the option to turn this on at runtime with a magic addon.
   public static boolean DISABLED = false;
 
   public static final long MILLISECONDS_PER_DAY = 24 * 60 * 60 * 1000;
--- a/mobile/android/base/background/announcements/AnnouncementsFetchResourceDelegate.java
+++ b/mobile/android/base/background/announcements/AnnouncementsFetchResourceDelegate.java
@@ -7,18 +7,18 @@ package org.mozilla.gecko.background.ann
 import java.io.IOException;
 import java.security.GeneralSecurityException;
 import java.util.ArrayList;
 import java.util.Date;
 import java.util.List;
 
 import org.json.simple.JSONArray;
 import org.json.simple.JSONObject;
+import org.mozilla.gecko.background.common.log.Logger;
 import org.mozilla.gecko.sync.ExtendedJSONObject;
-import org.mozilla.gecko.sync.Logger;
 import org.mozilla.gecko.sync.NonArrayJSONException;
 import org.mozilla.gecko.sync.net.AuthHeaderProvider;
 import org.mozilla.gecko.sync.net.BaseResource;
 import org.mozilla.gecko.sync.net.BaseResourceDelegate;
 import org.mozilla.gecko.sync.net.Resource;
 import org.mozilla.gecko.sync.net.SyncResponse;
 
 import ch.boye.httpclientandroidlib.Header;
--- a/mobile/android/base/background/announcements/AnnouncementsFetcher.java
+++ b/mobile/android/base/background/announcements/AnnouncementsFetcher.java
@@ -4,18 +4,18 @@
 
 package org.mozilla.gecko.background.announcements;
 
 import java.io.UnsupportedEncodingException;
 import java.net.URI;
 import java.net.URISyntaxException;
 import java.net.URLEncoder;
 
-import org.mozilla.gecko.sync.GlobalConstants;
-import org.mozilla.gecko.sync.Logger;
+import org.mozilla.gecko.background.common.GlobalConstants;
+import org.mozilla.gecko.background.common.log.Logger;
 import org.mozilla.gecko.sync.net.BaseResource;
 
 public class AnnouncementsFetcher {
   private static final String LOG_TAG = "AnnounceFetch";
   private static final long MILLISECONDS_PER_DAY = 24 * 60 * 60 * 1000;
 
   public static URI getSnippetURI(String base, String channel,
                                   String version, String platform,
@@ -126,9 +126,9 @@ public class AnnouncementsFetcher {
       final URI uri = getAnnounceURI(base, lastLaunch);
       Logger.info(LOG_TAG, "Fetching announcements from " + uri.toASCIIString());
       fetchAnnouncements(uri, delegate);
     } catch (URISyntaxException e) {
       Logger.warn(LOG_TAG, "Couldn't create URL.", e);
       return;
     }
   }
-}
\ No newline at end of file
+}
--- a/mobile/android/base/background/announcements/AnnouncementsService.java
+++ b/mobile/android/base/background/announcements/AnnouncementsService.java
@@ -5,19 +5,19 @@
 package org.mozilla.gecko.background.announcements;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
 import java.net.URI;
 import java.util.List;
 import java.util.Locale;
 
-import org.mozilla.gecko.background.BackgroundConstants;
 import org.mozilla.gecko.background.BackgroundService;
-import org.mozilla.gecko.sync.Logger;
+import org.mozilla.gecko.background.common.GlobalConstants;
+import org.mozilla.gecko.background.common.log.Logger;
 
 import android.content.Intent;
 import android.content.SharedPreferences;
 import android.os.IBinder;
 
 /**
  * A Service to periodically check for new published announcements,
  * presenting them to the user if local conditions permit.
@@ -137,17 +137,17 @@ public class AnnouncementsService extend
     return null;
   }
 
   protected long getLastLaunch() {
     return getSharedPreferences().getLong(AnnouncementsConstants.PREF_LAST_LAUNCH, 0);
   }
 
   private SharedPreferences getSharedPreferences() {
-    return this.getSharedPreferences(AnnouncementsConstants.PREFS_BRANCH, BackgroundConstants.SHARED_PREFERENCES_MODE);
+    return this.getSharedPreferences(AnnouncementsConstants.PREFS_BRANCH, GlobalConstants.SHARED_PREFERENCES_MODE);
   }
 
   @Override
   protected void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
     super.dump(fd, writer, args);
 
     final long lastFetch = getLastFetch();
     final long lastLaunch = getLastLaunch();
--- a/mobile/android/base/background/announcements/AnnouncementsStartReceiver.java
+++ b/mobile/android/base/background/announcements/AnnouncementsStartReceiver.java
@@ -1,15 +1,15 @@
 /* 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/. */
 
 package org.mozilla.gecko.background.announcements;
 
-import org.mozilla.gecko.sync.Logger;
+import org.mozilla.gecko.background.common.log.Logger;
 
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
 
 /**
  * Start the announcements service when instructed by the {@link android.app.AlarmManager}.
  */
rename from mobile/android/base/sync/GlobalConstants.java.in
rename to mobile/android/base/background/common/GlobalConstants.java.in
--- a/mobile/android/base/sync/GlobalConstants.java.in
+++ b/mobile/android/base/background/common/GlobalConstants.java.in
@@ -1,36 +1,40 @@
 #filter substitution
 /* 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/. */
 
-package org.mozilla.gecko.sync;
+package org.mozilla.gecko.background.common;
 
 /**
- * Preprocessed class for storing preprocessed values.
+ * Preprocessed class for storing preprocessed values common to all
+ * Android services.
  */
 public class GlobalConstants {
   public static final String ANDROID_CPU_ARCH = "@ANDROID_CPU_ARCH@";
 
   // One of 'beta', 'aurora', 'nightly', 'default'.
   // If this is an official build, 'default' means 'release'.
   // Otherwise, it means 'dev'.
   public static final String MOZ_UPDATE_CHANNEL = "@MOZ_UPDATE_CHANNEL@";
 #ifdef MOZ_OFFICIAL_BRANDING
   public static final boolean MOZ_OFFICIAL_BRANDING = true;
 #else
   public static final boolean MOZ_OFFICIAL_BRANDING = false;
 #endif
 
   public static final long BUILD_TIMESTAMP = @MOZ_BUILD_TIMESTAMP@;
 
+  public static final String MOZ_APP_DISPLAYNAME = "@MOZ_APP_DISPLAYNAME@";
   public static final String MOZ_APP_VERSION = "@MOZ_APP_VERSION@";
   public static final String BROWSER_INTENT_PACKAGE = "@ANDROID_PACKAGE_NAME@";
   public static final String BROWSER_INTENT_CLASS = BROWSER_INTENT_PACKAGE + ".App";
 
-  /**
-   * Bug 790931: this signing-level permission protects broadcast intents that
-   * should be received only by Firefox versions sharing the same Android
-   * Account type.
-   */
-  public static final String PER_ACCOUNT_TYPE_PERMISSION = "@MOZ_ANDROID_SHARED_ACCOUNT_TYPE@.permission.PER_ACCOUNT_TYPE";
+  public static final int SHARED_PREFERENCES_MODE = 0;
+  // These are used to ask Fennec (via reflection) to send
+  // us a pref notification. This avoids us having to guess
+  // Fennec's prefs branch and pref name.
+  // Eventually Fennec might listen to startup notifications and
+  // do this automatically, but this will do for now. See Bug 800244.
+  public static String GECKO_PREFERENCES_CLASS = "org.mozilla.gecko.GeckoPreferences";
+  public static String GECKO_BROADCAST_METHOD  = "broadcastAnnouncementsPref";
 }
rename from mobile/android/base/sync/Logger.java
rename to mobile/android/base/background/common/log/Logger.java
--- a/mobile/android/base/sync/Logger.java
+++ b/mobile/android/base/background/common/log/Logger.java
@@ -1,23 +1,24 @@
 /* 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/. */
 
-package org.mozilla.gecko.sync;
+package org.mozilla.gecko.background.common.log;
 
 import java.util.Iterator;
 import java.util.LinkedHashSet;
 import java.util.Set;
 
-import org.mozilla.gecko.sync.log.writers.AndroidLevelCachingLogWriter;
-import org.mozilla.gecko.sync.log.writers.AndroidLogWriter;
-import org.mozilla.gecko.sync.log.writers.LogWriter;
-import org.mozilla.gecko.sync.log.writers.SimpleTagLogWriter;
-import org.mozilla.gecko.sync.log.writers.ThreadLocalTagLogWriter;
+import org.mozilla.gecko.background.common.GlobalConstants;
+import org.mozilla.gecko.background.common.log.writers.AndroidLevelCachingLogWriter;
+import org.mozilla.gecko.background.common.log.writers.AndroidLogWriter;
+import org.mozilla.gecko.background.common.log.writers.LogWriter;
+import org.mozilla.gecko.background.common.log.writers.SimpleTagLogWriter;
+import org.mozilla.gecko.background.common.log.writers.ThreadLocalTagLogWriter;
 
 import android.util.Log;
 
 /**
  * Logging helper class. Serializes all log operations (by synchronizing).
  */
 public class Logger {
   public static final String LOGGER_TAG = "Logger";
rename from mobile/android/base/sync/log/writers/AndroidLevelCachingLogWriter.java
rename to mobile/android/base/background/common/log/writers/AndroidLevelCachingLogWriter.java
--- a/mobile/android/base/sync/log/writers/AndroidLevelCachingLogWriter.java
+++ b/mobile/android/base/background/common/log/writers/AndroidLevelCachingLogWriter.java
@@ -1,13 +1,13 @@
 /* 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/. */
 
-package org.mozilla.gecko.sync.log.writers;
+package org.mozilla.gecko.background.common.log.writers;
 
 import java.util.IdentityHashMap;
 import java.util.Map;
 
 import android.util.Log;
 
 /**
  * Make a <code>LogWriter</code> only log when the Android log system says to.
rename from mobile/android/base/sync/log/writers/AndroidLogWriter.java
rename to mobile/android/base/background/common/log/writers/AndroidLogWriter.java
--- a/mobile/android/base/sync/log/writers/AndroidLogWriter.java
+++ b/mobile/android/base/background/common/log/writers/AndroidLogWriter.java
@@ -1,13 +1,13 @@
 /* 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/. */
 
-package org.mozilla.gecko.sync.log.writers;
+package org.mozilla.gecko.background.common.log.writers;
 
 import android.util.Log;
 
 /**
  * Log to the Android log.
  */
 public class AndroidLogWriter extends LogWriter {
   @Override
rename from mobile/android/base/sync/log/writers/LevelFilteringLogWriter.java
rename to mobile/android/base/background/common/log/writers/LevelFilteringLogWriter.java
--- a/mobile/android/base/sync/log/writers/LevelFilteringLogWriter.java
+++ b/mobile/android/base/background/common/log/writers/LevelFilteringLogWriter.java
@@ -1,13 +1,13 @@
 /* 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/. */
 
-package org.mozilla.gecko.sync.log.writers;
+package org.mozilla.gecko.background.common.log.writers;
 
 import android.util.Log;
 
 /**
  * A LogWriter that logs only if the message is as important as the specified
  * level. For example, if the specified level is <code>Log.WARN</code>, only
  * <code>warn</code> and <code>error</code> will log.
  */
rename from mobile/android/base/sync/log/writers/LogWriter.java
rename to mobile/android/base/background/common/log/writers/LogWriter.java
--- a/mobile/android/base/sync/log/writers/LogWriter.java
+++ b/mobile/android/base/background/common/log/writers/LogWriter.java
@@ -1,13 +1,13 @@
 /* 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/. */
 
-package org.mozilla.gecko.sync.log.writers;
+package org.mozilla.gecko.background.common.log.writers;
 
 /**
  * An abstract object that logs information in some way.
  * <p>
  * Intended to be composed with other log writers, for example a log
  * writer could make all log entries have the same single log tag, or
  * could ignore certain log levels, before delegating to an inner log
  * writer.
rename from mobile/android/base/sync/log/writers/PrintLogWriter.java
rename to mobile/android/base/background/common/log/writers/PrintLogWriter.java
--- a/mobile/android/base/sync/log/writers/PrintLogWriter.java
+++ b/mobile/android/base/background/common/log/writers/PrintLogWriter.java
@@ -1,13 +1,13 @@
 /* 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/. */
 
-package org.mozilla.gecko.sync.log.writers;
+package org.mozilla.gecko.background.common.log.writers;
 
 import java.io.PrintWriter;
 
 /**
  * Log to a <code>PrintWriter</code>.
  */
 public class PrintLogWriter extends LogWriter {
   protected final PrintWriter pw;
rename from mobile/android/base/sync/log/writers/SimpleTagLogWriter.java
rename to mobile/android/base/background/common/log/writers/SimpleTagLogWriter.java
--- a/mobile/android/base/sync/log/writers/SimpleTagLogWriter.java
+++ b/mobile/android/base/background/common/log/writers/SimpleTagLogWriter.java
@@ -1,13 +1,13 @@
 /* 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/. */
 
-package org.mozilla.gecko.sync.log.writers;
+package org.mozilla.gecko.background.common.log.writers;
 
 /**
  * Make a <code>LogWriter</code> only log with a single string tag.
  */
 public class SimpleTagLogWriter extends TagLogWriter {
   final String tag;
   public SimpleTagLogWriter(String tag, LogWriter inner) {
     super(inner);
rename from mobile/android/base/sync/log/writers/StringLogWriter.java
rename to mobile/android/base/background/common/log/writers/StringLogWriter.java
--- a/mobile/android/base/sync/log/writers/StringLogWriter.java
+++ b/mobile/android/base/background/common/log/writers/StringLogWriter.java
@@ -1,13 +1,13 @@
 /* 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/. */
 
-package org.mozilla.gecko.sync.log.writers;
+package org.mozilla.gecko.background.common.log.writers;
 
 import java.io.PrintWriter;
 import java.io.StringWriter;
 
 public class StringLogWriter extends LogWriter {
   protected final StringWriter sw;
   protected final PrintLogWriter inner;
 
rename from mobile/android/base/sync/log/writers/TagLogWriter.java
rename to mobile/android/base/background/common/log/writers/TagLogWriter.java
--- a/mobile/android/base/sync/log/writers/TagLogWriter.java
+++ b/mobile/android/base/background/common/log/writers/TagLogWriter.java
@@ -1,13 +1,13 @@
 /* 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/. */
 
-package org.mozilla.gecko.sync.log.writers;
+package org.mozilla.gecko.background.common.log.writers;
 
 /**
  * A @link{LogWriter} that logs each message under a parent tag.
  */
 public abstract class TagLogWriter extends LogWriter {
 
   protected final LogWriter inner;
 
rename from mobile/android/base/sync/log/writers/ThreadLocalTagLogWriter.java
rename to mobile/android/base/background/common/log/writers/ThreadLocalTagLogWriter.java
--- a/mobile/android/base/sync/log/writers/ThreadLocalTagLogWriter.java
+++ b/mobile/android/base/background/common/log/writers/ThreadLocalTagLogWriter.java
@@ -1,13 +1,13 @@
 /* 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/. */
 
-package org.mozilla.gecko.sync.log.writers;
+package org.mozilla.gecko.background.common.log.writers;
 
 /**
  * Log with a single global tag… but that tag can be different for each thread.
  *
  * Takes a @link{ThreadLocal} as a constructor parameter.
  */
 public class ThreadLocalTagLogWriter extends TagLogWriter {
 
--- a/mobile/android/base/resources/layout-land-v14/browser_toolbar.xml.in
+++ b/mobile/android/base/resources/layout-land-v14/browser_toolbar.xml.in
@@ -104,17 +104,18 @@
                                 android:layout_height="fill_parent"
                                 android:layout_weight="1.0"
                                 android:singleLine="true"
                                 android:paddingRight="8dp"
                                 android:textColor="@color/awesome_bar_title"
                                 android:textColorHint="@color/awesome_bar_title_hint"
                                 android:gravity="center_vertical|left"
                                 android:hint="@string/awesomebar_default_text"
-                                android:layout_gravity="center_vertical"/>
+                                android:layout_gravity="center_vertical"
+                                gecko:autoUpdateTheme="false"/>
 
                 <ImageButton android:id="@+id/reader"
                              style="@style/AddressBar.ImageButton.Icon"
                              android:src="@drawable/reader"
                              android:contentDescription="@string/reader"
                              android:visibility="gone"/>
 
                 <ImageButton android:id="@+id/stop"
--- a/mobile/android/base/resources/layout-land-v14/browser_toolbar_menu.xml.in
+++ b/mobile/android/base/resources/layout-land-v14/browser_toolbar_menu.xml.in
@@ -104,17 +104,18 @@
                                 android:layout_height="fill_parent"
                                 android:layout_weight="1.0"
                                 android:singleLine="true"
                                 android:paddingRight="8dp"
                                 android:textColor="@color/awesome_bar_title"
                                 android:textColorHint="@color/awesome_bar_title_hint"
                                 android:gravity="center_vertical|left"
                                 android:hint="@string/awesomebar_default_text"
-                                android:layout_gravity="center_vertical"/>
+                                android:layout_gravity="center_vertical"
+                                gecko:autoUpdateTheme="false"/>
 
                 <ImageButton android:id="@+id/reader"
                              style="@style/AddressBar.ImageButton.Icon"
                              android:src="@drawable/reader"
                              android:contentDescription="@string/reader"
                              android:visibility="gone"/>
 
                 <ImageButton android:id="@+id/stop"
--- a/mobile/android/base/resources/layout-large-v11/awesomebar_search.xml.in
+++ b/mobile/android/base/resources/layout-large-v11/awesomebar_search.xml.in
@@ -31,17 +31,18 @@
           android:hint="@string/awesomebar_default_text"
           android:textColor="@color/awesome_bar_title"
           android:textColorHint="@color/awesome_bar_title_hint"
           android:textColorHighlight="@color/url_bar_text_highlight"
           android:inputType="textUri|textNoSuggestions"
           android:imeOptions="actionSearch|flagNoExtractUi|flagNoFullscreen"
           android:selectAllOnFocus="true"
           android:singleLine="true"
-          android:gravity="center_vertical|left">
+          android:gravity="center_vertical|left"
+          gecko:autoUpdateTheme="false">
               <requestFocus/>
     </view>
 
     <LinearLayout android:layout_width="4dp"
                   android:layout_height="fill_parent"
                   android:orientation="vertical"
                   android:layout_alignParentRight="true"/>
 
--- a/mobile/android/base/resources/layout-large-v11/browser_toolbar_menu.xml.in
+++ b/mobile/android/base/resources/layout-large-v11/browser_toolbar_menu.xml.in
@@ -146,17 +146,18 @@
                                 android:layout_height="fill_parent"
                                 android:layout_weight="1.0"
                                 android:singleLine="true"
                                 android:paddingRight="8dp"
                                 android:textColor="@color/awesome_bar_title"
                                 android:textColorHint="@color/awesome_bar_title_hint"
                                 android:gravity="center_vertical|left"
                                 android:hint="@string/awesomebar_default_text"
-                                android:layout_gravity="center_vertical"/>
+                                android:layout_gravity="center_vertical"
+                                gecko:autoUpdateTheme="false"/>
 
                 <ImageButton android:id="@+id/reader"
                              style="@style/AddressBar.ImageButton.Icon"
                              android:src="@drawable/reader"
                              android:contentDescription="@string/reader"
                              android:visibility="gone"/>
 
                 <ImageButton android:id="@+id/stop"
--- a/mobile/android/base/resources/layout/awesomebar_search.xml.in
+++ b/mobile/android/base/resources/layout/awesomebar_search.xml.in
@@ -31,17 +31,18 @@
           android:hint="@string/awesomebar_default_text"
           android:textColor="@color/awesome_bar_title"
           android:textColorHint="@color/awesome_bar_title_hint"
           android:textColorHighlight="@color/url_bar_text_highlight"
           android:inputType="textUri|textNoSuggestions"
           android:imeOptions="actionSearch|flagNoExtractUi|flagNoFullscreen"
           android:selectAllOnFocus="true"
           android:singleLine="true"
-          android:gravity="center_vertical|left">
+          android:gravity="center_vertical|left"
+          gecko:autoUpdateTheme="false">
               <requestFocus/>
     </view>
 
     <LinearLayout android:layout_width="4dp"
                   android:layout_height="fill_parent"
                   android:orientation="vertical"
                   android:layout_alignParentRight="true"/>
 
rename from mobile/android/base/resources/layout/awesomebar_tab_indicator.xml
rename to mobile/android/base/resources/layout/awesomebar_tab_indicator.xml.in
--- a/mobile/android/base/resources/layout/awesomebar_tab_indicator.xml
+++ b/mobile/android/base/resources/layout/awesomebar_tab_indicator.xml.in
@@ -1,16 +1,19 @@
+#filter substitution
 <?xml version="1.0" encoding="utf-8"?>
 <!-- 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/. -->
 
 <Gecko.TextView xmlns:android="http://schemas.android.com/apk/res/android"
+                xmlns:gecko="http://schemas.android.com/apk/res/@ANDROID_PACKAGE_NAME@"
                 android:layout_width="wrap_content"
                 android:layout_height="fill_parent"
                 android:layout_weight="1.0"
                 android:gravity="center"
                 android:background="@drawable/awesomebar_tab_indicator"
                 android:padding="10dp"
                 android:singleLine="true"
                 android:ellipsize="marquee"
                 android:textSize="13sp"
-                android:textColor="@color/awesome_bar_title"/>
+                android:textColor="@color/awesome_bar_title"
+                gecko:autoUpdateTheme="false"/>
--- a/mobile/android/base/resources/layout/browser_toolbar.xml.in
+++ b/mobile/android/base/resources/layout/browser_toolbar.xml.in
@@ -102,17 +102,18 @@
                                 android:layout_height="fill_parent"
                                 android:layout_weight="1.0"
                                 android:singleLine="true"
                                 android:paddingRight="8dp"
                                 android:textColor="@color/awesome_bar_title"
                                 android:textColorHint="@color/awesome_bar_title_hint"
                                 android:gravity="center_vertical|left"
                                 android:hint="@string/awesomebar_default_text"
-                                android:layout_gravity="center_vertical"/>
+                                android:layout_gravity="center_vertical"
+                                gecko:autoUpdateTheme="false"/>
 
                 <ImageButton android:id="@+id/reader"
                              style="@style/AddressBar.ImageButton.Icon"
                              android:src="@drawable/reader"
                              android:contentDescription="@string/reader"
                              android:visibility="gone"/>
 
                 <ImageButton android:id="@+id/stop"
--- a/mobile/android/base/resources/layout/browser_toolbar_menu.xml.in
+++ b/mobile/android/base/resources/layout/browser_toolbar_menu.xml.in
@@ -102,17 +102,18 @@
                                 android:layout_height="fill_parent"
                                 android:layout_weight="1.0"
                                 android:singleLine="true"
                                 android:paddingRight="8dp"
                                 android:textColor="@color/awesome_bar_title"
                                 android:textColorHint="@color/awesome_bar_title_hint"
                                 android:gravity="center_vertical|left"
                                 android:hint="@string/awesomebar_default_text"
-                                android:layout_gravity="center_vertical"/>
+                                android:layout_gravity="center_vertical"
+                                gecko:autoUpdateTheme="false"/>
 
                 <ImageButton android:id="@+id/reader"
                              style="@style/AddressBar.ImageButton.Icon"
                              android:src="@drawable/reader"
                              android:contentDescription="@string/reader"
                              android:visibility="gone"/>
 
                 <ImageButton android:id="@+id/stop"
--- a/mobile/android/base/resources/values/attrs.xml
+++ b/mobile/android/base/resources/values/attrs.xml
@@ -66,16 +66,17 @@
 
     <declare-styleable name="PrivateBrowsing">
         <attr name="state_private" format="boolean"/>
     </declare-styleable>
 
     <declare-styleable name="LightweightTheme">
         <attr name="state_light" format="boolean"/>
         <attr name="state_dark" format="boolean"/>
+        <attr name="autoUpdateTheme" format="boolean"/>
     </declare-styleable>
 
     <declare-styleable name="TwoWayView">
 
         <attr name="android:orientation"/>
 
         <attr name="android:choiceMode"/>
 
--- a/mobile/android/base/sync/CommandProcessor.java
+++ b/mobile/android/base/sync/CommandProcessor.java
@@ -8,16 +8,17 @@ import java.util.ArrayList;
 import java.util.List;
 import java.util.Map;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.atomic.AtomicInteger;
 
 import org.json.simple.JSONArray;
 import org.json.simple.JSONObject;
 import org.mozilla.gecko.R;
+import org.mozilla.gecko.background.common.log.Logger;
 import org.mozilla.gecko.sync.repositories.NullCursorException;
 import org.mozilla.gecko.sync.repositories.android.ClientsDatabaseAccessor;
 import org.mozilla.gecko.sync.repositories.domain.ClientRecord;
 
 import android.app.Notification;
 import android.app.NotificationManager;
 import android.app.PendingIntent;
 import android.content.Context;
--- a/mobile/android/base/sync/DelayedWorkTracker.java
+++ b/mobile/android/base/sync/DelayedWorkTracker.java
@@ -1,14 +1,16 @@
 /* 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/. */
 
 package org.mozilla.gecko.sync;
 
+import org.mozilla.gecko.background.common.log.Logger;
+
 /**
  * A little class to allow us to maintain a count of extant
  * things (in our case, callbacks that need to fire), and
  * some work that we want done when that count hits 0.
  *
  * @author rnewman
  *
  */
--- a/mobile/android/base/sync/GlobalSession.java
+++ b/mobile/android/base/sync/GlobalSession.java
@@ -14,16 +14,17 @@ import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.Map.Entry;
 import java.util.Set;
 import java.util.concurrent.atomic.AtomicLong;
 
 import org.json.simple.parser.ParseException;
+import org.mozilla.gecko.background.common.log.Logger;
 import org.mozilla.gecko.sync.crypto.CryptoException;
 import org.mozilla.gecko.sync.crypto.KeyBundle;
 import org.mozilla.gecko.sync.delegates.ClientsDataDelegate;
 import org.mozilla.gecko.sync.delegates.FreshStartDelegate;
 import org.mozilla.gecko.sync.delegates.GlobalSessionCallback;
 import org.mozilla.gecko.sync.delegates.JSONRecordFetchDelegate;
 import org.mozilla.gecko.sync.delegates.KeyUploadDelegate;
 import org.mozilla.gecko.sync.delegates.MetaGlobalDelegate;
--- a/mobile/android/base/sync/InfoCollections.java
+++ b/mobile/android/base/sync/InfoCollections.java
@@ -5,16 +5,18 @@
 package org.mozilla.gecko.sync;
 
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.Map;
 import java.util.Map.Entry;
 import java.util.Set;
 
+import org.mozilla.gecko.background.common.log.Logger;
+
 /**
  * Fetches the timestamp information in <code>info/collections</code> on the
  * Sync server. Provides access to those timestamps, along with logic to check
  * for whether a collection requires an update.
  */
 public class InfoCollections {
   private static final String LOG_TAG = "InfoCollections";
 
--- a/mobile/android/base/sync/InfoCounts.java
+++ b/mobile/android/base/sync/InfoCounts.java
@@ -5,16 +5,18 @@
 package org.mozilla.gecko.sync;
 
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.Map;
 import java.util.Map.Entry;
 import java.util.Set;
 
+import org.mozilla.gecko.background.common.log.Logger;
+
 public class InfoCounts {
   static final String LOG_TAG = "InfoCounts";
 
   /**
    * Counts fetched from the server, or <code>null</code> if not yet fetched.
    */
   private Map<String, Integer> counts = null;
 
--- a/mobile/android/base/sync/JSONRecordFetcher.java
+++ b/mobile/android/base/sync/JSONRecordFetcher.java
@@ -1,13 +1,18 @@
+/* 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/. */
+
 package org.mozilla.gecko.sync;
 
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
 
+import org.mozilla.gecko.background.common.log.Logger;
 import org.mozilla.gecko.sync.delegates.JSONRecordFetchDelegate;
 import org.mozilla.gecko.sync.net.SyncStorageRecordRequest;
 import org.mozilla.gecko.sync.net.SyncStorageRequestDelegate;
 import org.mozilla.gecko.sync.net.SyncStorageResponse;
 
 /**
  * An object which fetches a chunk of JSON from a URI, using certain credentials,
  * and informs its delegate of the result.
--- a/mobile/android/base/sync/MetaGlobal.java
+++ b/mobile/android/base/sync/MetaGlobal.java
@@ -7,16 +7,17 @@ package org.mozilla.gecko.sync;
 import java.io.IOException;
 import java.net.URISyntaxException;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Map;
 import java.util.Set;
 
 import org.json.simple.parser.ParseException;
+import org.mozilla.gecko.background.common.log.Logger;
 import org.mozilla.gecko.sync.MetaGlobalException.MetaGlobalMalformedSyncIDException;
 import org.mozilla.gecko.sync.MetaGlobalException.MetaGlobalMalformedVersionException;
 import org.mozilla.gecko.sync.delegates.MetaGlobalDelegate;
 import org.mozilla.gecko.sync.net.SyncStorageRecordRequest;
 import org.mozilla.gecko.sync.net.SyncStorageRequestDelegate;
 import org.mozilla.gecko.sync.net.SyncStorageResponse;
 
 public class MetaGlobal implements SyncStorageRequestDelegate {
--- a/mobile/android/base/sync/PersistedMetaGlobal.java
+++ b/mobile/android/base/sync/PersistedMetaGlobal.java
@@ -1,16 +1,16 @@
 /* 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/. */
 
 package org.mozilla.gecko.sync;
 
+import org.mozilla.gecko.background.common.log.Logger;
 import org.mozilla.gecko.sync.CryptoRecord;
-import org.mozilla.gecko.sync.Logger;
 
 import android.content.SharedPreferences;
 
 public class PersistedMetaGlobal {
   public static final String LOG_TAG = "PersistedMetaGlobal";
 
   public static final String META_GLOBAL_SERVER_RESPONSE_BODY = "metaGlobalServerResponseBody";
   public static final String META_GLOBAL_LAST_MODIFIED        = "metaGlobalLastModified";
--- a/mobile/android/base/sync/SyncConfiguration.java
+++ b/mobile/android/base/sync/SyncConfiguration.java
@@ -8,16 +8,17 @@ import java.net.URI;
 import java.net.URISyntaxException;
 import java.util.Collection;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Map;
 import java.util.Map.Entry;
 import java.util.Set;
 
+import org.mozilla.gecko.background.common.log.Logger;
 import org.mozilla.gecko.sync.crypto.KeyBundle;
 import org.mozilla.gecko.sync.crypto.PersistedCrypto5Keys;
 import org.mozilla.gecko.sync.stage.GlobalSyncStage.Stage;
 
 import android.content.SharedPreferences;
 import android.content.SharedPreferences.Editor;
 
 public class SyncConfiguration implements CredentialsSource {
--- a/mobile/android/base/sync/SyncConstants.java.in
+++ b/mobile/android/base/sync/SyncConstants.java.in
@@ -1,48 +1,56 @@
 #filter substitution
 /* 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/. */
 
 package org.mozilla.gecko.sync;
 
+import org.mozilla.gecko.background.common.GlobalConstants;
+
 /**
- * Preprocessed class for storing preprocessed values.
+ * Preprocessed class for storing preprocessed values specific to Android Sync.
  */
 public class SyncConstants {
-  public static final String PRODUCT_NAME = "@MOZ_APP_DISPLAYNAME@";
   public static final String GLOBAL_LOG_TAG = "FxSync";
   public static final String SYNC_MAJOR_VERSION  = "1";
   public static final String SYNC_MINOR_VERSION  = "0";
   public static final String SYNC_VERSION_STRING = SYNC_MAJOR_VERSION + "." +
                                                    GlobalConstants.MOZ_APP_VERSION + "." +
                                                    SYNC_MINOR_VERSION;
 
   public static final String SYNC_USER_AGENT = "Firefox AndroidSync " +
                                                SYNC_VERSION_STRING + " (" +
-                                               PRODUCT_NAME + ")";
+                                               GlobalConstants.MOZ_APP_DISPLAYNAME + ")";
 
-
-  public static final String ACCOUNTTYPE_SYNC     = "@MOZ_ANDROID_SHARED_ACCOUNT_TYPE@";
+  public static final String ACCOUNTTYPE_SYNC = "@MOZ_ANDROID_SHARED_ACCOUNT_TYPE@";
 
   /**
-   * Bug 790931: this action is broadcast when an Android Account is deleted.
-   * This allows each installed Firefox to delete any pickle file and to (try
-   * to) wipe its client record from the server.
+   * Bug 790931: this action is broadcast when an Android Sync Account is
+   * deleted.  This allows each installed Firefox to delete any Sync Account
+   * pickle file and to (try to) wipe its client record from the Sync server.
    * <p>
    * It is protected by signing-level permission PER_ACCOUNT_TYPE_PERMISSION and
-   * can be received only by Firefox versions sharing the same Android Account
-   * type.
+   * can be received only by Firefox versions sharing the same Android Sync
+   * Account type.
    * <p>
    * See {@link org.mozilla.gecko.sync.setup.SyncAccounts#makeSyncAccountDeletedIntent(android.content.Context, android.accounts.AccountManager, android.accounts.Account)}
    * for contents of the intent.
    */
   public static final String SYNC_ACCOUNT_DELETED_ACTION = "@MOZ_ANDROID_SHARED_ACCOUNT_TYPE@.accounts.SYNC_ACCOUNT_DELETED_ACTION";
 
   /**
-   * Bug 790931: version number of contents of SYNC_ACCOUNT_DELETED_ACTION intent.
+   * Bug 790931: version number of contents of SYNC_ACCOUNT_DELETED_ACTION
+   * intent.
    * <p>
    * See {@link org.mozilla.gecko.sync.setup.SyncAccounts#makeSyncAccountDeletedIntent(android.content.Context, android.accounts.AccountManager, android.accounts.Account)}
    * for contents of the intent.
    */
   public static final long SYNC_ACCOUNT_DELETED_INTENT_VERSION = 1;
+
+  /**
+   * Bug 790931: this signing-level permission protects broadcast intents that
+   * should be received only by Firefox versions sharing the same Android Sync
+   * Account type.
+   */
+  public static final String PER_ACCOUNT_TYPE_PERMISSION = "@MOZ_ANDROID_SHARED_ACCOUNT_TYPE@.permission.PER_ACCOUNT_TYPE";
 }
--- a/mobile/android/base/sync/SynchronizerConfiguration.java
+++ b/mobile/android/base/sync/SynchronizerConfiguration.java
@@ -2,16 +2,17 @@
  * 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/. */
 
 package org.mozilla.gecko.sync;
 
 import java.io.IOException;
 
 import org.json.simple.parser.ParseException;
+import org.mozilla.gecko.background.common.log.Logger;
 import org.mozilla.gecko.sync.SyncConfiguration.ConfigurationBranch;
 import org.mozilla.gecko.sync.repositories.RepositorySessionBundle;
 
 import android.content.SharedPreferences.Editor;
 
 public class SynchronizerConfiguration {
   private static final String LOG_TAG = "SynczrConfiguration";
 
--- a/mobile/android/base/sync/Utils.java
+++ b/mobile/android/base/sync/Utils.java
@@ -22,16 +22,17 @@ import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Locale;
 import java.util.Map;
 import java.util.TreeMap;
 
 import org.json.simple.JSONArray;
 import org.mozilla.apache.commons.codec.binary.Base32;
 import org.mozilla.apache.commons.codec.binary.Base64;
+import org.mozilla.gecko.background.common.log.Logger;
 import org.mozilla.gecko.sync.setup.Constants;
 
 import android.content.Context;
 import android.content.SharedPreferences;
 import android.os.Bundle;
 
 public class Utils {
 
--- a/mobile/android/base/sync/config/AccountPickler.java
+++ b/mobile/android/base/sync/config/AccountPickler.java
@@ -2,18 +2,18 @@
  * 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/. */
 
 package org.mozilla.gecko.sync.config;
 
 import java.io.FileOutputStream;
 import java.io.PrintStream;
 
+import org.mozilla.gecko.background.common.log.Logger;
 import org.mozilla.gecko.sync.ExtendedJSONObject;
-import org.mozilla.gecko.sync.Logger;
 import org.mozilla.gecko.sync.Utils;
 import org.mozilla.gecko.sync.setup.Constants;
 import org.mozilla.gecko.sync.setup.SyncAccounts;
 import org.mozilla.gecko.sync.setup.SyncAccounts.SyncAccountParameters;
 
 import android.accounts.Account;
 import android.content.Context;
 
--- a/mobile/android/base/sync/config/ClientRecordTerminator.java
+++ b/mobile/android/base/sync/config/ClientRecordTerminator.java
@@ -1,18 +1,18 @@
 /* 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/. */
 
 package org.mozilla.gecko.sync.config;
 
 import java.net.URI;
 
+import org.mozilla.gecko.background.common.log.Logger;
 import org.mozilla.gecko.sync.GlobalSession;
-import org.mozilla.gecko.sync.Logger;
 import org.mozilla.gecko.sync.net.BaseResource;
 import org.mozilla.gecko.sync.net.SyncStorageRecordRequest;
 import org.mozilla.gecko.sync.net.SyncStorageRequestDelegate;
 import org.mozilla.gecko.sync.net.SyncStorageResponse;
 
 /**
  * Bug 770785: when an Android Account is deleted, we need to (try to) delete
  * the associated client GUID from the server's clients table.
--- a/mobile/android/base/sync/config/ConfigurationMigrator.java
+++ b/mobile/android/base/sync/config/ConfigurationMigrator.java
@@ -3,17 +3,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 package org.mozilla.gecko.sync.config;
 
 import java.util.HashMap;
 import java.util.Map;
 import java.util.Map.Entry;
 
-import org.mozilla.gecko.sync.Logger;
+import org.mozilla.gecko.background.common.log.Logger;
 import org.mozilla.gecko.sync.SyncConfiguration;
 import org.mozilla.gecko.sync.Utils;
 
 import android.accounts.Account;
 import android.accounts.AccountManager;
 import android.content.Context;
 import android.content.SharedPreferences;
 import android.content.SharedPreferences.Editor;
--- a/mobile/android/base/sync/config/activities/SelectEnginesActivity.java
+++ b/mobile/android/base/sync/config/activities/SelectEnginesActivity.java
@@ -5,17 +5,17 @@
 package org.mozilla.gecko.sync.config.activities;
 
 import java.util.HashMap;
 import java.util.Map;
 import java.util.Map.Entry;
 import java.util.Set;
 
 import org.mozilla.gecko.R;
-import org.mozilla.gecko.sync.Logger;
+import org.mozilla.gecko.background.common.log.Logger;
 import org.mozilla.gecko.sync.SyncConfiguration;
 import org.mozilla.gecko.sync.ThreadPool;
 import org.mozilla.gecko.sync.setup.SyncAccounts;
 import org.mozilla.gecko.sync.syncadapter.SyncAdapter;
 
 import android.accounts.Account;
 import android.accounts.AccountManager;
 import android.app.Activity;
--- a/mobile/android/base/sync/crypto/PersistedCrypto5Keys.java
+++ b/mobile/android/base/sync/crypto/PersistedCrypto5Keys.java
@@ -1,17 +1,17 @@
 /* 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/. */
 
 package org.mozilla.gecko.sync.crypto;
 
+import org.mozilla.gecko.background.common.log.Logger;
 import org.mozilla.gecko.sync.CollectionKeys;
 import org.mozilla.gecko.sync.CryptoRecord;
-import org.mozilla.gecko.sync.Logger;
 
 import android.content.SharedPreferences;
 
 public class PersistedCrypto5Keys {
   public static final String LOG_TAG = "PersistedC5Keys";
 
   public static final String CRYPTO5_KEYS_SERVER_RESPONSE_BODY = "crypto5KeysServerResponseBody";
   public static final String CRYPTO5_KEYS_LAST_MODIFIED        = "crypto5KeysLastModified";
--- a/mobile/android/base/sync/jpake/JPakeClient.java
+++ b/mobile/android/base/sync/jpake/JPakeClient.java
@@ -6,18 +6,18 @@ package org.mozilla.gecko.sync.jpake;
 
 import java.io.UnsupportedEncodingException;
 import java.math.BigInteger;
 import java.util.LinkedList;
 import java.util.Queue;
 
 import org.json.simple.JSONObject;
 import org.mozilla.apache.commons.codec.binary.Base64;
+import org.mozilla.gecko.background.common.log.Logger;
 import org.mozilla.gecko.sync.ExtendedJSONObject;
-import org.mozilla.gecko.sync.Logger;
 import org.mozilla.gecko.sync.ThreadPool;
 import org.mozilla.gecko.sync.Utils;
 import org.mozilla.gecko.sync.crypto.CryptoException;
 import org.mozilla.gecko.sync.crypto.CryptoInfo;
 import org.mozilla.gecko.sync.crypto.KeyBundle;
 import org.mozilla.gecko.sync.crypto.NoKeyBundleException;
 import org.mozilla.gecko.sync.jpake.stage.CompleteStage;
 import org.mozilla.gecko.sync.jpake.stage.ComputeFinalStage;
--- a/mobile/android/base/sync/jpake/JPakeCrypto.java
+++ b/mobile/android/base/sync/jpake/JPakeCrypto.java
@@ -9,17 +9,17 @@ import java.math.BigInteger;
 import java.security.GeneralSecurityException;
 import java.security.InvalidKeyException;
 import java.security.MessageDigest;
 import java.security.NoSuchAlgorithmException;
 
 import javax.crypto.Mac;
 import javax.crypto.spec.SecretKeySpec;
 
-import org.mozilla.gecko.sync.Logger;
+import org.mozilla.gecko.background.common.log.Logger;
 import org.mozilla.gecko.sync.crypto.HKDF;
 import org.mozilla.gecko.sync.crypto.KeyBundle;
 
 public class JPakeCrypto {
   private static final String LOG_TAG = "JPakeCrypto";
 
   /*
    * Primes P and Q, and generator G - from original Mozilla J-PAKE
deleted file mode 100644
--- a/mobile/android/base/sync/jpake/JPakeRequest.java
+++ /dev/null
@@ -1,48 +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/. */
-
-package org.mozilla.gecko.sync.jpake;
-
-import java.net.URI;
-import java.net.URISyntaxException;
-
-import org.mozilla.gecko.sync.net.BaseResource;
-import org.mozilla.gecko.sync.net.Resource;
-import org.mozilla.gecko.sync.net.ResourceDelegate;
-
-import ch.boye.httpclientandroidlib.HttpEntity;
-
-public class JPakeRequest implements Resource {
-  private BaseResource resource;
-  public JPakeRequestDelegate delegate;
-
-  public JPakeRequest(String uri, ResourceDelegate delegate) throws URISyntaxException {
-    this(new URI(uri), delegate);
-  }
-
-  public JPakeRequest(URI uri, ResourceDelegate delegate) {
-    this.resource = new BaseResource(uri);
-    this.resource.delegate = delegate;
-  }
-
-  @Override
-  public void get() {
-    this.resource.get();
-  }
-
-  @Override
-  public void delete() {
-    this.resource.delete();
-  }
-
-  @Override
-  public void post(HttpEntity body) {
-    this.resource.post(body);
-  }
-
-  @Override
-  public void put(HttpEntity body) {
-    this.resource.put(body);
-  }
-}
deleted file mode 100644
--- a/mobile/android/base/sync/jpake/JPakeRequestDelegate.java
+++ /dev/null
@@ -1,14 +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/. */
-
-package org.mozilla.gecko.sync.jpake;
-
-import ch.boye.httpclientandroidlib.HttpResponse;
-
-public interface JPakeRequestDelegate {
-
-  public void onRequestFailure(HttpResponse response);
-  public void onRequestSuccess(HttpResponse response);
-  public void onRequestError(Exception e);
-}
deleted file mode 100644
--- a/mobile/android/base/sync/jpake/JPakeResponse.java
+++ /dev/null
@@ -1,16 +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/. */
-
-package org.mozilla.gecko.sync.jpake;
-
-import org.mozilla.gecko.sync.net.SyncResponse;
-
-import ch.boye.httpclientandroidlib.HttpResponse;
-
-public class JPakeResponse extends SyncResponse {
-
-  public JPakeResponse(HttpResponse res) {
-    super(res);
-  }
-}
--- a/mobile/android/base/sync/jpake/stage/CompleteStage.java
+++ b/mobile/android/base/sync/jpake/stage/CompleteStage.java
@@ -1,15 +1,15 @@
 /* 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/. */
 
 package org.mozilla.gecko.sync.jpake.stage;
 
-import org.mozilla.gecko.sync.Logger;
+import org.mozilla.gecko.background.common.log.Logger;
 import org.mozilla.gecko.sync.jpake.JPakeClient;
 
 public class CompleteStage extends JPakeStage {
 
   @Override
   public void execute(JPakeClient jClient) {
     Logger.debug(LOG_TAG, "Exchange complete.");
     jClient.finished = true;
--- a/mobile/android/base/sync/jpake/stage/ComputeFinalStage.java
+++ b/mobile/android/base/sync/jpake/stage/ComputeFinalStage.java
@@ -4,18 +4,18 @@
 
 package org.mozilla.gecko.sync.jpake.stage;
 
 import java.io.UnsupportedEncodingException;
 import java.math.BigInteger;
 import java.security.InvalidKeyException;
 import java.security.NoSuchAlgorithmException;
 
+import org.mozilla.gecko.background.common.log.Logger;
 import org.mozilla.gecko.sync.ExtendedJSONObject;
-import org.mozilla.gecko.sync.Logger;
 import org.mozilla.gecko.sync.NonObjectJSONException;
 import org.mozilla.gecko.sync.jpake.IncorrectZkpException;
 import org.mozilla.gecko.sync.jpake.JPakeClient;
 import org.mozilla.gecko.sync.jpake.JPakeCrypto;
 import org.mozilla.gecko.sync.jpake.Zkp;
 import org.mozilla.gecko.sync.setup.Constants;
 
 public class ComputeFinalStage extends JPakeStage {
--- a/mobile/android/base/sync/jpake/stage/ComputeKeyVerificationStage.java
+++ b/mobile/android/base/sync/jpake/stage/ComputeKeyVerificationStage.java
@@ -1,18 +1,18 @@
 /* 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/. */
 
 package org.mozilla.gecko.sync.jpake.stage;
 
 import java.io.UnsupportedEncodingException;
 
+import org.mozilla.gecko.background.common.log.Logger;
 import org.mozilla.gecko.sync.ExtendedJSONObject;
-import org.mozilla.gecko.sync.Logger;
 import org.mozilla.gecko.sync.crypto.CryptoException;
 import org.mozilla.gecko.sync.crypto.KeyBundle;
 import org.mozilla.gecko.sync.jpake.JPakeClient;
 import org.mozilla.gecko.sync.setup.Constants;
 
 public class ComputeKeyVerificationStage extends JPakeStage {
 
   @Override
--- a/mobile/android/base/sync/jpake/stage/ComputeStepOneStage.java
+++ b/mobile/android/base/sync/jpake/stage/ComputeStepOneStage.java
@@ -2,18 +2,18 @@
  * 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/. */
 
 package org.mozilla.gecko.sync.jpake.stage;
 
 import java.io.UnsupportedEncodingException;
 import java.security.NoSuchAlgorithmException;
 
+import org.mozilla.gecko.background.common.log.Logger;
 import org.mozilla.gecko.sync.ExtendedJSONObject;
-import org.mozilla.gecko.sync.Logger;
 import org.mozilla.gecko.sync.jpake.BigIntegerHelper;
 import org.mozilla.gecko.sync.jpake.JPakeClient;
 import org.mozilla.gecko.sync.jpake.JPakeCrypto;
 import org.mozilla.gecko.sync.jpake.JPakeJson;
 import org.mozilla.gecko.sync.jpake.JPakeParty;
 import org.mozilla.gecko.sync.jpake.Zkp;
 import org.mozilla.gecko.sync.setup.Constants;
 
--- a/mobile/android/base/sync/jpake/stage/ComputeStepTwoStage.java
+++ b/mobile/android/base/sync/jpake/stage/ComputeStepTwoStage.java
@@ -3,18 +3,18 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 package org.mozilla.gecko.sync.jpake.stage;
 
 import java.io.UnsupportedEncodingException;
 import java.math.BigInteger;
 import java.security.NoSuchAlgorithmException;
 
+import org.mozilla.gecko.background.common.log.Logger;
 import org.mozilla.gecko.sync.ExtendedJSONObject;
-import org.mozilla.gecko.sync.Logger;
 import org.mozilla.gecko.sync.NonObjectJSONException;
 import org.mozilla.gecko.sync.jpake.BigIntegerHelper;
 import org.mozilla.gecko.sync.jpake.Gx3OrGx4IsZeroOrOneException;
 import org.mozilla.gecko.sync.jpake.IncorrectZkpException;
 import org.mozilla.gecko.sync.jpake.JPakeClient;
 import org.mozilla.gecko.sync.jpake.JPakeCrypto;
 import org.mozilla.gecko.sync.jpake.JPakeJson;
 import org.mozilla.gecko.sync.jpake.Zkp;
--- a/mobile/android/base/sync/jpake/stage/DecryptDataStage.java
+++ b/mobile/android/base/sync/jpake/stage/DecryptDataStage.java
@@ -4,18 +4,18 @@
 
 package org.mozilla.gecko.sync.jpake.stage;
 
 import java.io.IOException;
 import java.io.UnsupportedEncodingException;
 
 import org.json.simple.JSONObject;
 import org.json.simple.parser.ParseException;
+import org.mozilla.gecko.background.common.log.Logger;
 import org.mozilla.gecko.sync.ExtendedJSONObject;
-import org.mozilla.gecko.sync.Logger;
 import org.mozilla.gecko.sync.NonObjectJSONException;
 import org.mozilla.gecko.sync.Utils;
 import org.mozilla.gecko.sync.crypto.CryptoException;
 import org.mozilla.gecko.sync.crypto.CryptoInfo;
 import org.mozilla.gecko.sync.crypto.KeyBundle;
 import org.mozilla.gecko.sync.jpake.JPakeClient;
 import org.mozilla.gecko.sync.setup.Constants;
 
--- a/mobile/android/base/sync/jpake/stage/DeleteChannel.java
+++ b/mobile/android/base/sync/jpake/stage/DeleteChannel.java
@@ -3,17 +3,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 package org.mozilla.gecko.sync.jpake.stage;
 
 import java.io.IOException;
 import java.net.URISyntaxException;
 import java.security.GeneralSecurityException;
 
-import org.mozilla.gecko.sync.Logger;
+import org.mozilla.gecko.background.common.log.Logger;
 import org.mozilla.gecko.sync.jpake.JPakeClient;
 import org.mozilla.gecko.sync.net.BaseResource;
 import org.mozilla.gecko.sync.net.BaseResourceDelegate;
 import org.mozilla.gecko.sync.setup.auth.AccountAuthenticator;
 
 import ch.boye.httpclientandroidlib.HttpResponse;
 import ch.boye.httpclientandroidlib.client.ClientProtocolException;
 import ch.boye.httpclientandroidlib.client.methods.HttpRequestBase;
--- a/mobile/android/base/sync/jpake/stage/GetChannelStage.java
+++ b/mobile/android/base/sync/jpake/stage/GetChannelStage.java
@@ -4,17 +4,17 @@
 
 package org.mozilla.gecko.sync.jpake.stage;
 
 import java.io.IOException;
 import java.net.URISyntaxException;
 import java.security.GeneralSecurityException;
 
 import org.json.simple.parser.JSONParser;
-import org.mozilla.gecko.sync.Logger;
+import org.mozilla.gecko.background.common.log.Logger;
 import org.mozilla.gecko.sync.jpake.JPakeClient;
 import org.mozilla.gecko.sync.net.BaseResource;
 import org.mozilla.gecko.sync.net.BaseResourceDelegate;
 import org.mozilla.gecko.sync.net.SyncResponse;
 import org.mozilla.gecko.sync.setup.Constants;
 
 import ch.boye.httpclientandroidlib.HttpResponse;
 import ch.boye.httpclientandroidlib.client.ClientProtocolException;
--- a/mobile/android/base/sync/jpake/stage/GetRequestStage.java
+++ b/mobile/android/base/sync/jpake/stage/GetRequestStage.java
@@ -5,17 +5,17 @@
 package org.mozilla.gecko.sync.jpake.stage;
 
 import java.io.IOException;
 import java.net.URISyntaxException;
 import java.security.GeneralSecurityException;
 import java.util.Timer;
 import java.util.TimerTask;
 
-import org.mozilla.gecko.sync.Logger;
+import org.mozilla.gecko.background.common.log.Logger;
 import org.mozilla.gecko.sync.jpake.JPakeClient;
 import org.mozilla.gecko.sync.net.BaseResource;
 import org.mozilla.gecko.sync.net.BaseResourceDelegate;
 import org.mozilla.gecko.sync.net.Resource;
 import org.mozilla.gecko.sync.net.SyncResponse;
 import org.mozilla.gecko.sync.setup.Constants;
 
 import ch.boye.httpclientandroidlib.Header;
--- a/mobile/android/base/sync/jpake/stage/PutRequestStage.java
+++ b/mobile/android/base/sync/jpake/stage/PutRequestStage.java
@@ -6,17 +6,17 @@ package org.mozilla.gecko.sync.jpake.sta
 
 import java.io.IOException;
 import java.io.UnsupportedEncodingException;
 import java.net.URISyntaxException;
 import java.security.GeneralSecurityException;
 import java.util.Timer;
 import java.util.TimerTask;
 
-import org.mozilla.gecko.sync.Logger;
+import org.mozilla.gecko.background.common.log.Logger;
 import org.mozilla.gecko.sync.jpake.JPakeClient;
 import org.mozilla.gecko.sync.net.BaseResource;
 import org.mozilla.gecko.sync.net.Resource;
 import org.mozilla.gecko.sync.net.BaseResourceDelegate;
 import org.mozilla.gecko.sync.setup.Constants;
 
 import ch.boye.httpclientandroidlib.Header;
 import ch.boye.httpclientandroidlib.HttpResponse;
--- a/mobile/android/base/sync/jpake/stage/VerifyPairingStage.java
+++ b/mobile/android/base/sync/jpake/stage/VerifyPairingStage.java
@@ -2,18 +2,18 @@
  * 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/. */
 
 package org.mozilla.gecko.sync.jpake.stage;
 
 import java.io.UnsupportedEncodingException;
 
 import org.mozilla.apache.commons.codec.binary.Base64;
+import org.mozilla.gecko.background.common.log.Logger;
 import org.mozilla.gecko.sync.ExtendedJSONObject;
-import org.mozilla.gecko.sync.Logger;
 import org.mozilla.gecko.sync.NonObjectJSONException;
 import org.mozilla.gecko.sync.crypto.CryptoException;
 import org.mozilla.gecko.sync.crypto.CryptoInfo;
 import org.mozilla.gecko.sync.crypto.KeyBundle;
 import org.mozilla.gecko.sync.jpake.JPakeClient;
 import org.mozilla.gecko.sync.setup.Constants;
 
 public class VerifyPairingStage extends JPakeStage {
--- a/mobile/android/base/sync/middleware/MiddlewareRepositorySession.java
+++ b/mobile/android/base/sync/middleware/MiddlewareRepositorySession.java
@@ -1,17 +1,17 @@
 /* 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/. */
 
 package org.mozilla.gecko.sync.middleware;
 
 import java.util.concurrent.ExecutorService;
 
-import org.mozilla.gecko.sync.Logger;
+import org.mozilla.gecko.background.common.log.Logger;
 import org.mozilla.gecko.sync.repositories.InactiveSessionException;
 import org.mozilla.gecko.sync.repositories.InvalidSessionTransitionException;
 import org.mozilla.gecko.sync.repositories.RepositorySession;
 import org.mozilla.gecko.sync.repositories.RepositorySessionBundle;
 import org.mozilla.gecko.sync.repositories.delegates.RepositorySessionBeginDelegate;
 import org.mozilla.gecko.sync.repositories.delegates.RepositorySessionFinishDelegate;
 import org.mozilla.gecko.sync.repositories.delegates.RepositorySessionGuidsSinceDelegate;
 import org.mozilla.gecko.sync.repositories.delegates.RepositorySessionWipeDelegate;
--- a/mobile/android/base/sync/net/BaseResource.java
+++ b/mobile/android/base/sync/net/BaseResource.java
@@ -14,18 +14,18 @@ import java.security.GeneralSecurityExce
 import java.security.KeyManagementException;
 import java.security.NoSuchAlgorithmException;
 import java.security.SecureRandom;
 
 import javax.net.ssl.SSLContext;
 
 import org.json.simple.JSONArray;
 import org.json.simple.JSONObject;
+import org.mozilla.gecko.background.common.log.Logger;
 import org.mozilla.gecko.sync.ExtendedJSONObject;
-import org.mozilla.gecko.sync.Logger;
 
 import ch.boye.httpclientandroidlib.Header;
 import ch.boye.httpclientandroidlib.HttpEntity;
 import ch.boye.httpclientandroidlib.HttpResponse;
 import ch.boye.httpclientandroidlib.HttpVersion;
 import ch.boye.httpclientandroidlib.client.AuthCache;
 import ch.boye.httpclientandroidlib.client.ClientProtocolException;
 import ch.boye.httpclientandroidlib.client.methods.HttpDelete;
--- a/mobile/android/base/sync/net/ConnectionMonitorThread.java
+++ b/mobile/android/base/sync/net/ConnectionMonitorThread.java
@@ -1,15 +1,15 @@
 /* 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/. */
 
 package org.mozilla.gecko.sync.net;
 
-import org.mozilla.gecko.sync.Logger;
+import org.mozilla.gecko.background.common.log.Logger;
 
 /**
  * Every <code>REAP_INTERVAL</code> milliseconds, wake up
  * and expire any connections that need cleaning up.
  *
  * When we're told to shut down, take the connection manager
  * with us.
  */
--- a/mobile/android/base/sync/net/HMACAuthHeaderProvider.java
+++ b/mobile/android/base/sync/net/HMACAuthHeaderProvider.java
@@ -9,17 +9,17 @@ import java.net.URI;
 import java.security.GeneralSecurityException;
 import java.security.InvalidKeyException;
 import java.security.NoSuchAlgorithmException;
 
 import javax.crypto.Mac;
 import javax.crypto.spec.SecretKeySpec;
 
 import org.mozilla.apache.commons.codec.binary.Base64;
-import org.mozilla.gecko.sync.Logger;
+import org.mozilla.gecko.background.common.log.Logger;
 import org.mozilla.gecko.sync.Utils;
 
 import ch.boye.httpclientandroidlib.Header;
 import ch.boye.httpclientandroidlib.client.methods.HttpRequestBase;
 import ch.boye.httpclientandroidlib.client.methods.HttpUriRequest;
 import ch.boye.httpclientandroidlib.impl.client.DefaultHttpClient;
 import ch.boye.httpclientandroidlib.message.BasicHeader;
 import ch.boye.httpclientandroidlib.protocol.BasicHttpContext;
deleted file mode 100644
--- a/mobile/android/base/sync/net/SyncResourceDelegate.java
+++ /dev/null
@@ -1,44 +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/. */
-
-package org.mozilla.gecko.sync.net;
-
-import ch.boye.httpclientandroidlib.client.methods.HttpRequestBase;
-import ch.boye.httpclientandroidlib.impl.client.DefaultHttpClient;
-
-/**
- * Shared abstract class for resource delegate that use the same timeouts
- * and no credentials.
- *
- * @author rnewman
- *
- */
-public abstract class SyncResourceDelegate implements ResourceDelegate {
-  public static int connectionTimeoutInMillis = 1000 * 30;     // Wait 30s for a connection to open.
-  public static int socketTimeoutInMillis     = 1000 * 2 * 60; // Wait 2 minutes for data.
-
-  protected Resource resource;
-  public SyncResourceDelegate(Resource resource) {
-    this.resource = resource;
-  }
-
-  @Override
-  public int connectionTimeout() {
-    return connectionTimeoutInMillis;
-  }
-
-  @Override
-  public int socketTimeout() {
-    return socketTimeoutInMillis;
-  }
-
-  @Override
-  public String getCredentials() {
-    return null;
-  }
-
-  @Override
-  public void addHeaders(HttpRequestBase request, DefaultHttpClient client) {
-  }
-}
--- a/mobile/android/base/sync/net/SyncResponse.java
+++ b/mobile/android/base/sync/net/SyncResponse.java
@@ -7,18 +7,18 @@ package org.mozilla.gecko.sync.net;
 import java.io.BufferedReader;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.InputStreamReader;
 import java.io.Reader;
 import java.util.Scanner;
 
 import org.json.simple.parser.ParseException;
+import org.mozilla.gecko.background.common.log.Logger;
 import org.mozilla.gecko.sync.ExtendedJSONObject;
-import org.mozilla.gecko.sync.Logger;
 import org.mozilla.gecko.sync.NonObjectJSONException;
 import org.mozilla.gecko.sync.Utils;
 
 import ch.boye.httpclientandroidlib.Header;
 import ch.boye.httpclientandroidlib.HttpEntity;
 import ch.boye.httpclientandroidlib.HttpResponse;
 import ch.boye.httpclientandroidlib.impl.cookie.DateParseException;
 import ch.boye.httpclientandroidlib.impl.cookie.DateUtils;
--- a/mobile/android/base/sync/net/SyncStorageCollectionRequest.java
+++ b/mobile/android/base/sync/net/SyncStorageCollectionRequest.java
@@ -5,17 +5,17 @@
 package org.mozilla.gecko.sync.net;
 
 import java.io.BufferedReader;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.InputStreamReader;
 import java.net.URI;
 
-import org.mozilla.gecko.sync.Logger;
+import org.mozilla.gecko.background.common.log.Logger;
 
 import ch.boye.httpclientandroidlib.Header;
 import ch.boye.httpclientandroidlib.HttpEntity;
 import ch.boye.httpclientandroidlib.HttpResponse;
 import ch.boye.httpclientandroidlib.client.methods.HttpRequestBase;
 import ch.boye.httpclientandroidlib.impl.client.DefaultHttpClient;
 
 /**
--- a/mobile/android/base/sync/net/SyncStorageRequest.java
+++ b/mobile/android/base/sync/net/SyncStorageRequest.java
@@ -5,18 +5,18 @@
 package org.mozilla.gecko.sync.net;
 
 import java.io.IOException;
 import java.net.URI;
 import java.net.URISyntaxException;
 import java.security.GeneralSecurityException;
 import java.util.HashMap;
 
+import org.mozilla.gecko.background.common.log.Logger;
 import org.mozilla.gecko.sync.SyncConstants;
-import org.mozilla.gecko.sync.Logger;
 
 import ch.boye.httpclientandroidlib.HttpEntity;
 import ch.boye.httpclientandroidlib.HttpResponse;
 import ch.boye.httpclientandroidlib.client.ClientProtocolException;
 import ch.boye.httpclientandroidlib.client.methods.HttpRequestBase;
 import ch.boye.httpclientandroidlib.impl.client.DefaultHttpClient;
 import ch.boye.httpclientandroidlib.params.CoreProtocolPNames;
 
--- a/mobile/android/base/sync/net/SyncStorageResponse.java
+++ b/mobile/android/base/sync/net/SyncStorageResponse.java
@@ -2,17 +2,17 @@
  * 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/. */
 
 package org.mozilla.gecko.sync.net;
 
 import java.io.IOException;
 import java.util.HashMap;
 
-import org.mozilla.gecko.sync.Logger;
+import org.mozilla.gecko.background.common.log.Logger;
 
 import ch.boye.httpclientandroidlib.HttpResponse;
 
 public class SyncStorageResponse extends SyncResponse {
 
   // Responses that are actionable get constant status codes.
   public static final String RESPONSE_CLIENT_UPGRADE_REQUIRED = "16";
 
--- a/mobile/android/base/sync/net/TLSSocketFactory.java
+++ b/mobile/android/base/sync/net/TLSSocketFactory.java
@@ -5,17 +5,17 @@
 package org.mozilla.gecko.sync.net;
 
 import java.io.IOException;
 import java.net.Socket;
 
 import javax.net.ssl.SSLContext;
 import javax.net.ssl.SSLSocket;
 
-import org.mozilla.gecko.sync.Logger;
+import org.mozilla.gecko.background.common.log.Logger;
 
 import ch.boye.httpclientandroidlib.conn.ssl.SSLSocketFactory;
 import ch.boye.httpclientandroidlib.params.HttpParams;
 
 public class TLSSocketFactory extends SSLSocketFactory {
   private static final String LOG_TAG = "TLSSocketFactory";
   private static final String[] DEFAULT_CIPHER_SUITES = new String[] {
     "SSL_RSA_WITH_RC4_128_SHA",        // "RC4_SHA"
--- a/mobile/android/base/sync/receivers/SyncAccountDeletedReceiver.java
+++ b/mobile/android/base/sync/receivers/SyncAccountDeletedReceiver.java
@@ -1,15 +1,15 @@
 /* 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/. */
 
 package org.mozilla.gecko.sync.receivers;
 
-import org.mozilla.gecko.sync.Logger;
+import org.mozilla.gecko.background.common.log.Logger;
 
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
 
 public class SyncAccountDeletedReceiver extends BroadcastReceiver {
   public static final String LOG_TAG = "SyncAccountDeletedReceiver";
 
--- a/mobile/android/base/sync/receivers/SyncAccountDeletedService.java
+++ b/mobile/android/base/sync/receivers/SyncAccountDeletedService.java
@@ -1,18 +1,18 @@
 /* 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/. */
 
 package org.mozilla.gecko.sync.receivers;
 
 import org.mozilla.gecko.sync.ExtendedJSONObject;
-import org.mozilla.gecko.sync.GlobalConstants;
+import org.mozilla.gecko.background.common.GlobalConstants;
+import org.mozilla.gecko.background.common.log.Logger;
 import org.mozilla.gecko.sync.SyncConstants;
-import org.mozilla.gecko.sync.Logger;
 import org.mozilla.gecko.sync.SyncConfiguration;
 import org.mozilla.gecko.sync.Utils;
 import org.mozilla.gecko.sync.config.AccountPickler;
 import org.mozilla.gecko.sync.config.ClientRecordTerminator;
 import org.mozilla.gecko.sync.setup.Constants;
 import org.mozilla.gecko.sync.setup.SyncAccounts.SyncAccountParameters;
 
 import android.accounts.AccountManager;
--- a/mobile/android/base/sync/receivers/UpgradeReceiver.java
+++ b/mobile/android/base/sync/receivers/UpgradeReceiver.java
@@ -1,17 +1,17 @@
 /* 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/. */
 
 package org.mozilla.gecko.sync.receivers;
 
 import org.mozilla.gecko.sync.CredentialException;
-import org.mozilla.gecko.sync.GlobalConstants;
-import org.mozilla.gecko.sync.Logger;
+import org.mozilla.gecko.background.common.GlobalConstants;
+import org.mozilla.gecko.background.common.log.Logger;
 import org.mozilla.gecko.sync.SyncConfiguration;
 import org.mozilla.gecko.sync.ThreadPool;
 import org.mozilla.gecko.sync.config.ConfigurationMigrator;
 import org.mozilla.gecko.sync.setup.Constants;
 import org.mozilla.gecko.sync.setup.SyncAccounts;
 import org.mozilla.gecko.sync.setup.SyncAccounts.SyncAccountParameters;
 
 import android.accounts.Account;
--- a/mobile/android/base/sync/repositories/RepositorySession.java
+++ b/mobile/android/base/sync/repositories/RepositorySession.java
@@ -5,17 +5,17 @@
 package org.mozilla.gecko.sync.repositories;
 
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Iterator;
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Executors;
 
-import org.mozilla.gecko.sync.Logger;
+import org.mozilla.gecko.background.common.log.Logger;
 import org.mozilla.gecko.sync.repositories.delegates.RepositorySessionBeginDelegate;
 import org.mozilla.gecko.sync.repositories.delegates.RepositorySessionFetchRecordsDelegate;
 import org.mozilla.gecko.sync.repositories.delegates.RepositorySessionFinishDelegate;
 import org.mozilla.gecko.sync.repositories.delegates.RepositorySessionGuidsSinceDelegate;
 import org.mozilla.gecko.sync.repositories.delegates.RepositorySessionStoreDelegate;
 import org.mozilla.gecko.sync.repositories.delegates.RepositorySessionWipeDelegate;
 import org.mozilla.gecko.sync.repositories.domain.Record;
 
--- a/mobile/android/base/sync/repositories/RepositorySessionBundle.java
+++ b/mobile/android/base/sync/repositories/RepositorySessionBundle.java
@@ -2,18 +2,18 @@
  * 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/. */
 
 package org.mozilla.gecko.sync.repositories;
 
 import java.io.IOException;
 
 import org.json.simple.parser.ParseException;
+import org.mozilla.gecko.background.common.log.Logger;
 import org.mozilla.gecko.sync.ExtendedJSONObject;
-import org.mozilla.gecko.sync.Logger;
 import org.mozilla.gecko.sync.NonObjectJSONException;
 
 public class RepositorySessionBundle {
   public static final String LOG_TAG = RepositorySessionBundle.class.getSimpleName();
 
   protected static final String JSON_KEY_TIMESTAMP = "timestamp";
 
   protected final ExtendedJSONObject object;
--- a/mobile/android/base/sync/repositories/Server11RepositorySession.java
+++ b/mobile/android/base/sync/repositories/Server11RepositorySession.java
@@ -11,21 +11,21 @@ import java.net.URI;
 import java.net.URISyntaxException;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.HashSet;
 import java.util.Set;
 import java.util.concurrent.atomic.AtomicLong;
 
 import org.json.simple.JSONArray;
+import org.mozilla.gecko.background.common.log.Logger;
 import org.mozilla.gecko.sync.CryptoRecord;
 import org.mozilla.gecko.sync.DelayedWorkTracker;
 import org.mozilla.gecko.sync.ExtendedJSONObject;
 import org.mozilla.gecko.sync.HTTPFailureException;
-import org.mozilla.gecko.sync.Logger;
 import org.mozilla.gecko.sync.Server11PreviousPostFailedException;
 import org.mozilla.gecko.sync.Server11RecordPostFailedException;
 import org.mozilla.gecko.sync.UnexpectedJSONException;
 import org.mozilla.gecko.sync.crypto.KeyBundle;
 import org.mozilla.gecko.sync.net.SyncStorageCollectionRequest;
 import org.mozilla.gecko.sync.net.SyncStorageRequest;
 import org.mozilla.gecko.sync.net.SyncStorageRequestDelegate;
 import org.mozilla.gecko.sync.net.SyncStorageResponse;
--- a/mobile/android/base/sync/repositories/StoreTrackingRepositorySession.java
+++ b/mobile/android/base/sync/repositories/StoreTrackingRepositorySession.java
@@ -2,17 +2,17 @@
  * 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/. */
 
 package org.mozilla.gecko.sync.repositories;
 
 import java.util.Collection;
 import java.util.Iterator;
 
-import org.mozilla.gecko.sync.Logger;
+import org.mozilla.gecko.background.common.log.Logger;
 import org.mozilla.gecko.sync.repositories.delegates.RepositorySessionBeginDelegate;
 import org.mozilla.gecko.sync.repositories.delegates.RepositorySessionFinishDelegate;
 import org.mozilla.gecko.sync.repositories.domain.Record;
 
 public abstract class StoreTrackingRepositorySession extends RepositorySession {
   private static final String LOG_TAG = "StoreTrackSession";
   protected StoreTracker storeTracker;
 
--- a/mobile/android/base/sync/repositories/android/AndroidBrowserBookmarksDataAccessor.java
+++ b/mobile/android/base/sync/repositories/android/AndroidBrowserBookmarksDataAccessor.java
@@ -5,18 +5,18 @@
 package org.mozilla.gecko.sync.repositories.android;
 
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.HashMap;
 import java.util.Map;
 
 import org.json.simple.JSONArray;
+import org.mozilla.gecko.background.common.log.Logger;
 import org.mozilla.gecko.db.BrowserContract;
-import org.mozilla.gecko.sync.Logger;
 import org.mozilla.gecko.sync.repositories.NullCursorException;
 import org.mozilla.gecko.sync.repositories.domain.BookmarkRecord;
 import org.mozilla.gecko.sync.repositories.domain.Record;
 
 import android.content.ContentUris;
 import android.content.ContentValues;
 import android.content.Context;
 import android.database.Cursor;
--- a/mobile/android/base/sync/repositories/android/AndroidBrowserBookmarksRepositorySession.java
+++ b/mobile/android/base/sync/repositories/android/AndroidBrowserBookmarksRepositorySession.java
@@ -9,18 +9,18 @@ import java.util.Collection;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.Map;
 import java.util.Map.Entry;
 import java.util.TreeMap;
 
 import org.json.simple.JSONArray;
 import org.mozilla.gecko.R;
+import org.mozilla.gecko.background.common.log.Logger;
 import org.mozilla.gecko.db.BrowserContract;
-import org.mozilla.gecko.sync.Logger;
 import org.mozilla.gecko.sync.Utils;
 import org.mozilla.gecko.sync.repositories.InactiveSessionException;
 import org.mozilla.gecko.sync.repositories.InvalidSessionTransitionException;
 import org.mozilla.gecko.sync.repositories.NoGuidForIdException;
 import org.mozilla.gecko.sync.repositories.NullCursorException;
 import org.mozilla.gecko.sync.repositories.ParentNotFoundException;
 import org.mozilla.gecko.sync.repositories.Repository;
 import org.mozilla.gecko.sync.repositories.delegates.RepositorySessionBeginDelegate;
--- a/mobile/android/base/sync/repositories/android/AndroidBrowserHistoryDataAccessor.java
+++ b/mobile/android/base/sync/repositories/android/AndroidBrowserHistoryDataAccessor.java
@@ -5,18 +5,18 @@
 package org.mozilla.gecko.sync.repositories.android;
 
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.Map;
 
 import org.json.simple.JSONArray;
 import org.json.simple.JSONObject;
+import org.mozilla.gecko.background.common.log.Logger;
 import org.mozilla.gecko.db.BrowserContract;
-import org.mozilla.gecko.sync.Logger;
 import org.mozilla.gecko.sync.repositories.NullCursorException;
 import org.mozilla.gecko.sync.repositories.domain.HistoryRecord;
 import org.mozilla.gecko.sync.repositories.domain.Record;
 
 import android.content.ContentValues;
 import android.content.Context;
 import android.net.Uri;
 
--- a/mobile/android/base/sync/repositories/android/AndroidBrowserHistoryDataExtender.java
+++ b/mobile/android/base/sync/repositories/android/AndroidBrowserHistoryDataExtender.java
@@ -2,17 +2,17 @@
  * 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/. */
 
 package org.mozilla.gecko.sync.repositories.android;
 
 import java.util.ArrayList;
 
 import org.json.simple.JSONArray;
-import org.mozilla.gecko.sync.Logger;
+import org.mozilla.gecko.background.common.log.Logger;
 import org.mozilla.gecko.sync.repositories.NullCursorException;
 import org.mozilla.gecko.sync.repositories.domain.HistoryRecord;
 
 import android.content.ContentValues;
 import android.content.Context;
 import android.database.Cursor;
 import android.database.SQLException;
 import android.database.sqlite.SQLiteDatabase;
--- a/mobile/android/base/sync/repositories/android/AndroidBrowserHistoryRepositorySession.java
+++ b/mobile/android/base/sync/repositories/android/AndroidBrowserHistoryRepositorySession.java
@@ -3,18 +3,18 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 package org.mozilla.gecko.sync.repositories.android;
 
 import java.util.ArrayList;
 
 import org.json.simple.JSONArray;
 import org.json.simple.JSONObject;
+import org.mozilla.gecko.background.common.log.Logger;
 import org.mozilla.gecko.db.BrowserContract;
-import org.mozilla.gecko.sync.Logger;
 import org.mozilla.gecko.sync.repositories.InactiveSessionException;
 import org.mozilla.gecko.sync.repositories.InvalidSessionTransitionException;
 import org.mozilla.gecko.sync.repositories.NoGuidForIdException;
 import org.mozilla.gecko.sync.repositories.NullCursorException;
 import org.mozilla.gecko.sync.repositories.ParentNotFoundException;
 import org.mozilla.gecko.sync.repositories.Repository;
 import org.mozilla.gecko.sync.repositories.delegates.RepositorySessionBeginDelegate;
 import org.mozilla.gecko.sync.repositories.delegates.RepositorySessionFinishDelegate;
--- a/mobile/android/base/sync/repositories/android/AndroidBrowserRepositoryDataAccessor.java
+++ b/mobile/android/base/sync/repositories/android/AndroidBrowserRepositoryDataAccessor.java
@@ -1,18 +1,18 @@
 /* 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/. */
 
 package org.mozilla.gecko.sync.repositories.android;
 
 import java.util.List;
 
+import org.mozilla.gecko.background.common.log.Logger;
 import org.mozilla.gecko.db.BrowserContract;
-import org.mozilla.gecko.sync.Logger;
 import org.mozilla.gecko.sync.repositories.NullCursorException;
 import org.mozilla.gecko.sync.repositories.domain.Record;
 
 import android.content.ContentValues;
 import android.content.Context;
 import android.database.Cursor;
 import android.net.Uri;
 
--- a/mobile/android/base/sync/repositories/android/AndroidBrowserRepositorySession.java
+++ b/mobile/android/base/sync/repositories/android/AndroidBrowserRepositorySession.java
@@ -2,17 +2,17 @@
  * 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/. */
 
 package org.mozilla.gecko.sync.repositories.android;
 
 import java.util.ArrayList;
 import java.util.HashMap;
 
-import org.mozilla.gecko.sync.Logger;
+import org.mozilla.gecko.background.common.log.Logger;
 import org.mozilla.gecko.sync.repositories.InactiveSessionException;
 import org.mozilla.gecko.sync.repositories.InvalidRequestException;
 import org.mozilla.gecko.sync.repositories.InvalidSessionTransitionException;
 import org.mozilla.gecko.sync.repositories.MultipleRecordsForGuidException;
 import org.mozilla.gecko.sync.repositories.NoGuidForIdException;
 import org.mozilla.gecko.sync.repositories.NoStoreDelegateException;
 import org.mozilla.gecko.sync.repositories.NullCursorException;
 import org.mozilla.gecko.sync.repositories.ParentNotFoundException;
--- a/mobile/android/base/sync/repositories/android/BookmarksDeletionManager.java
+++ b/mobile/android/base/sync/repositories/android/BookmarksDeletionManager.java
@@ -3,18 +3,18 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 package org.mozilla.gecko.sync.repositories.android;
 
 import java.util.HashSet;
 import java.util.Map;
 import java.util.Set;
 
+import org.mozilla.gecko.background.common.log.Logger;
 import org.mozilla.gecko.db.BrowserContract;
-import org.mozilla.gecko.sync.Logger;
 import org.mozilla.gecko.sync.repositories.NullCursorException;
 import org.mozilla.gecko.sync.repositories.delegates.RepositorySessionStoreDelegate;
 
 /**
  * Queue up deletions. Process them at the end.
  *
  * Algorithm:
  *
--- a/mobile/android/base/sync/repositories/android/BookmarksInsertionManager.java
+++ b/mobile/android/base/sync/repositories/android/BookmarksInsertionManager.java
@@ -7,17 +7,17 @@ package org.mozilla.gecko.sync.repositor
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.LinkedHashSet;
 import java.util.Map;
 import java.util.Set;
 
-import org.mozilla.gecko.sync.Logger;
+import org.mozilla.gecko.background.common.log.Logger;
 import org.mozilla.gecko.sync.Utils;
 import org.mozilla.gecko.sync.repositories.domain.BookmarkRecord;
 
 /**
  * Queue up insertions:
  * <ul>
  * <li>Folder inserts where the parent is known. Do these immediately, because
  * they allow other records to be inserted. Requires bookkeeping updates. On
--- a/mobile/android/base/sync/repositories/android/ClientsDatabase.java
+++ b/mobile/android/base/sync/repositories/android/ClientsDatabase.java
@@ -1,15 +1,15 @@
 /* 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/. */
 
 package org.mozilla.gecko.sync.repositories.android;
 
-import org.mozilla.gecko.sync.Logger;
+import org.mozilla.gecko.background.common.log.Logger;
 import org.mozilla.gecko.sync.repositories.NullCursorException;
 import org.mozilla.gecko.sync.repositories.domain.ClientRecord;
 
 import android.content.ContentValues;
 import android.content.Context;
 import android.database.Cursor;
 import android.database.sqlite.SQLiteDatabase;
 
--- a/mobile/android/base/sync/repositories/android/FennecControlHelper.java
+++ b/mobile/android/base/sync/repositories/android/FennecControlHelper.java
@@ -1,16 +1,16 @@
 /* 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/. */
 
 package org.mozilla.gecko.sync.repositories.android;
 
+import org.mozilla.gecko.background.common.log.Logger;
 import org.mozilla.gecko.db.BrowserContract.Control;
-import org.mozilla.gecko.sync.Logger;
 import org.mozilla.gecko.sync.repositories.NoContentProviderException;
 
 import android.content.ContentProviderClient;
 import android.content.Context;
 import android.database.Cursor;
 import android.net.Uri;
 
 /**
--- a/mobile/android/base/sync/repositories/android/FennecTabsRepository.java
+++ b/mobile/android/base/sync/repositories/android/FennecTabsRepository.java
@@ -2,19 +2,19 @@
  * 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/. */
 
 package org.mozilla.gecko.sync.repositories.android;
 
 import java.util.ArrayList;
 
 import org.json.simple.JSONArray;
+import org.mozilla.gecko.background.common.log.Logger;
 import org.mozilla.gecko.db.BrowserContract;
 import org.mozilla.gecko.db.BrowserContract.Tabs;
-import org.mozilla.gecko.sync.Logger;
 import org.mozilla.gecko.sync.repositories.InactiveSessionException;
 import org.mozilla.gecko.sync.repositories.NoContentProviderException;
 import org.mozilla.gecko.sync.repositories.NoStoreDelegateException;
 import org.mozilla.gecko.sync.repositories.Repository;
 import org.mozilla.gecko.sync.repositories.RepositorySession;
 import org.mozilla.gecko.sync.repositories.delegates.RepositorySessionCreationDelegate;
 import org.mozilla.gecko.sync.repositories.delegates.RepositorySessionFetchRecordsDelegate;
 import org.mozilla.gecko.sync.repositories.delegates.RepositorySessionFinishDelegate;
--- a/mobile/android/base/sync/repositories/android/FormHistoryRepositorySession.java
+++ b/mobile/android/base/sync/repositories/android/FormHistoryRepositorySession.java
@@ -3,19 +3,19 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 package org.mozilla.gecko.sync.repositories.android;
 
 import java.util.ArrayList;
 import java.util.List;
 import java.util.concurrent.Callable;
 
+import org.mozilla.gecko.background.common.log.Logger;
 import org.mozilla.gecko.db.BrowserContract.DeletedFormHistory;
 import org.mozilla.gecko.db.BrowserContract.FormHistory;
-import org.mozilla.gecko.sync.Logger;
 import org.mozilla.gecko.sync.repositories.InactiveSessionException;
 import org.mozilla.gecko.sync.repositories.NoContentProviderException;
 import org.mozilla.gecko.sync.repositories.NoStoreDelegateException;
 import org.mozilla.gecko.sync.repositories.NullCursorException;
 import org.mozilla.gecko.sync.repositories.RecordFilter;
 import org.mozilla.gecko.sync.repositories.Repository;
 import org.mozilla.gecko.sync.repositories.StoreTrackingRepositorySession;
 import org.mozilla.gecko.sync.repositories.delegates.RepositorySessionCreationDelegate;
--- a/mobile/android/base/sync/repositories/android/PasswordsRepositorySession.java
+++ b/mobile/android/base/sync/repositories/android/PasswordsRepositorySession.java
@@ -2,21 +2,21 @@
  * 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/. */
 
 package org.mozilla.gecko.sync.repositories.android;
 
 import java.util.ArrayList;
 import java.util.List;
 
+import org.mozilla.gecko.background.common.log.Logger;
 import org.mozilla.gecko.db.BrowserContract;
 import org.mozilla.gecko.db.BrowserContract.DeletedColumns;
 import org.mozilla.gecko.db.BrowserContract.DeletedPasswords;
 import org.mozilla.gecko.db.BrowserContract.Passwords;
-import org.mozilla.gecko.sync.Logger;
 import org.mozilla.gecko.sync.repositories.InactiveSessionException;
 import org.mozilla.gecko.sync.repositories.NoStoreDelegateException;
 import org.mozilla.gecko.sync.repositories.NullCursorException;
 import org.mozilla.gecko.sync.repositories.RecordFilter;
 import org.mozilla.gecko.sync.repositories.Repository;
 import org.mozilla.gecko.sync.repositories.StoreTrackingRepositorySession;
 import org.mozilla.gecko.sync.repositories.android.RepoUtils.QueryHelper;
 import org.mozilla.gecko.sync.repositories.delegates.RepositorySessionCreationDelegate;
--- a/mobile/android/base/sync/repositories/android/RepoUtils.java
+++ b/mobile/android/base/sync/repositories/android/RepoUtils.java
@@ -3,19 +3,19 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 package org.mozilla.gecko.sync.repositories.android;
 
 import java.io.IOException;
 
 import org.json.simple.JSONArray;
 import org.json.simple.parser.ParseException;
+import org.mozilla.gecko.background.common.log.Logger;
 import org.mozilla.gecko.db.BrowserContract;
 import org.mozilla.gecko.sync.ExtendedJSONObject;
-import org.mozilla.gecko.sync.Logger;
 import org.mozilla.gecko.sync.NonArrayJSONException;
 import org.mozilla.gecko.sync.repositories.NullCursorException;
 import org.mozilla.gecko.sync.repositories.domain.ClientRecord;
 import org.mozilla.gecko.sync.repositories.domain.HistoryRecord;
 
 import android.content.ContentProviderClient;
 import android.content.Context;
 import android.database.Cursor;
--- a/mobile/android/base/sync/repositories/domain/BookmarkRecord.java
+++ b/mobile/android/base/sync/repositories/domain/BookmarkRecord.java
@@ -4,18 +4,18 @@
 
 package org.mozilla.gecko.sync.repositories.domain;
 
 import java.io.UnsupportedEncodingException;
 import java.net.URLEncoder;
 import java.util.Map;
 
 import org.json.simple.JSONArray;
+import org.mozilla.gecko.background.common.log.Logger;
 import org.mozilla.gecko.sync.ExtendedJSONObject;
-import org.mozilla.gecko.sync.Logger;
 import org.mozilla.gecko.sync.NonArrayJSONException;
 import org.mozilla.gecko.sync.Utils;
 import org.mozilla.gecko.sync.repositories.android.RepoUtils;
 
 /**
  * Covers the fields used by all bookmark objects.
  * @author rnewman
  *
--- a/mobile/android/base/sync/repositories/domain/ClientRecord.java
+++ b/mobile/android/base/sync/repositories/domain/ClientRecord.java
@@ -1,17 +1,17 @@
 /* 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/. */
 
 package org.mozilla.gecko.sync.repositories.domain;
 
 import org.json.simple.JSONArray;
+import org.mozilla.gecko.background.common.log.Logger;
 import org.mozilla.gecko.sync.ExtendedJSONObject;
-import org.mozilla.gecko.sync.Logger;
 import org.mozilla.gecko.sync.NonArrayJSONException;
 import org.mozilla.gecko.sync.Utils;
 import org.mozilla.gecko.sync.repositories.android.RepoUtils;
 
 public class ClientRecord extends Record {
   private static final String LOG_TAG = "ClientRecord";
 
   public static final String CLIENT_TYPE         = "mobile";
--- a/mobile/android/base/sync/repositories/domain/FormHistoryRecord.java
+++ b/mobile/android/base/sync/repositories/domain/FormHistoryRecord.java
@@ -1,16 +1,16 @@
 /* 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/. */
 
 package org.mozilla.gecko.sync.repositories.domain;
 
+import org.mozilla.gecko.background.common.log.Logger;
 import org.mozilla.gecko.sync.ExtendedJSONObject;
-import org.mozilla.gecko.sync.Logger;
 import org.mozilla.gecko.sync.Utils;
 import org.mozilla.gecko.sync.repositories.android.RepoUtils;
 
 /**
  * A FormHistoryRecord represents a saved form element.
  *
  * I map a <code>fieldName</code> string to a <code>value</code> string.
  *
--- a/mobile/android/base/sync/repositories/domain/HistoryRecord.java
+++ b/mobile/android/base/sync/repositories/domain/HistoryRecord.java
@@ -3,18 +3,18 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 package org.mozilla.gecko.sync.repositories.domain;
 
 import java.util.HashMap;
 
 import org.json.simple.JSONArray;
 import org.json.simple.JSONObject;
+import org.mozilla.gecko.background.common.log.Logger;
 import org.mozilla.gecko.sync.ExtendedJSONObject;
-import org.mozilla.gecko.sync.Logger;
 import org.mozilla.gecko.sync.NonArrayJSONException;
 import org.mozilla.gecko.sync.Utils;
 import org.mozilla.gecko.sync.repositories.android.RepoUtils;
 
 /**
  * Visits are in microsecond precision.
  *
  * @author rnewman
--- a/mobile/android/base/sync/repositories/domain/PasswordRecord.java
+++ b/mobile/android/base/sync/repositories/domain/PasswordRecord.java
@@ -1,16 +1,16 @@
 /* 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/. */
 
 package org.mozilla.gecko.sync.repositories.domain;
 
+import org.mozilla.gecko.background.common.log.Logger;
 import org.mozilla.gecko.sync.ExtendedJSONObject;
-import org.mozilla.gecko.sync.Logger;
 import org.mozilla.gecko.sync.Utils;
 import org.mozilla.gecko.sync.repositories.android.RepoUtils;
 
 public class PasswordRecord extends Record {
   private static final String LOG_TAG = "PasswordRecord";
 
   public static final String COLLECTION_NAME = "passwords";
   public static long PASSWORDS_TTL = -1; // Never expire passwords.
--- a/mobile/android/base/sync/repositories/domain/TabsRecord.java
+++ b/mobile/android/base/sync/repositories/domain/TabsRecord.java
@@ -3,19 +3,19 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 package org.mozilla.gecko.sync.repositories.domain;
 
 import java.util.ArrayList;
 
 import org.json.simple.JSONArray;
 import org.json.simple.JSONObject;
+import org.mozilla.gecko.background.common.log.Logger;
 import org.mozilla.gecko.db.BrowserContract;
 import org.mozilla.gecko.sync.ExtendedJSONObject;
-import org.mozilla.gecko.sync.Logger;
 import org.mozilla.gecko.sync.NonArrayJSONException;
 import org.mozilla.gecko.sync.Utils;
 import org.mozilla.gecko.sync.repositories.android.RepoUtils;
 
 import android.content.ContentValues;
 
 /**
  * Represents a client's collection of tabs.
--- a/mobile/android/base/sync/setup/SyncAccounts.java
+++ b/mobile/android/base/sync/setup/SyncAccounts.java
@@ -6,19 +6,19 @@ package org.mozilla.gecko.sync.setup;
 
 import java.io.File;
 import java.io.UnsupportedEncodingException;
 import java.security.NoSuchAlgorithmException;
 
 import org.mozilla.gecko.db.BrowserContract;
 import org.mozilla.gecko.sync.CredentialException;
 import org.mozilla.gecko.sync.ExtendedJSONObject;
-import org.mozilla.gecko.sync.GlobalConstants;
+import org.mozilla.gecko.background.common.GlobalConstants;
+import org.mozilla.gecko.background.common.log.Logger;
 import org.mozilla.gecko.sync.SyncConstants;
-import org.mozilla.gecko.sync.Logger;
 import org.mozilla.gecko.sync.SyncConfiguration;
 import org.mozilla.gecko.sync.ThreadPool;
 import org.mozilla.gecko.sync.Utils;
 import org.mozilla.gecko.sync.config.AccountPickler;
 import org.mozilla.gecko.sync.repositories.android.RepoUtils;
 
 import android.accounts.Account;
 import android.accounts.AccountManager;
--- a/mobile/android/base/sync/setup/SyncAuthenticatorService.java
+++ b/mobile/android/base/sync/setup/SyncAuthenticatorService.java
@@ -2,19 +2,18 @@
  * 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/. */
 
 package org.mozilla.gecko.sync.setup;
 
 import java.io.UnsupportedEncodingException;
 import java.security.NoSuchAlgorithmException;
 
-import org.mozilla.gecko.sync.GlobalConstants;
+import org.mozilla.gecko.background.common.log.Logger;
 import org.mozilla.gecko.sync.SyncConstants;
-import org.mozilla.gecko.sync.Logger;
 import org.mozilla.gecko.sync.Utils;
 import org.mozilla.gecko.sync.setup.activities.SetupSyncActivity;
 
 import android.accounts.AbstractAccountAuthenticator;
 import android.accounts.Account;
 import android.accounts.AccountAuthenticatorResponse;
 import android.accounts.AccountManager;
 import android.accounts.NetworkErrorException;
@@ -245,14 +244,14 @@ public class SyncAuthenticatorService ex
       // correctly identify whether a Sync account has been removed (when some
       // Firefox versions are installed on the SD card).
       //
       // Broadcast intents protected with permissions are secure, so it's okay
       // to include password and sync key, etc.
       final Intent intent = SyncAccounts.makeSyncAccountDeletedIntent(mContext, AccountManager.get(mContext), account);
       Logger.info(LOG_TAG, "Account named " + account.name + " being removed; " +
           "broadcasting secure intent " + intent.getAction() + ".");
-      mContext.sendBroadcast(intent, GlobalConstants.PER_ACCOUNT_TYPE_PERMISSION);
+      mContext.sendBroadcast(intent, SyncConstants.PER_ACCOUNT_TYPE_PERMISSION);
 
       return result;
     }
   }
 }
--- a/mobile/android/base/sync/setup/activities/AccountActivity.java
+++ b/mobile/android/base/sync/setup/activities/AccountActivity.java
@@ -2,18 +2,18 @@
  * 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/. */
 
 package org.mozilla.gecko.sync.setup.activities;
 
 import java.util.Locale;
 
 import org.mozilla.gecko.R;
+import org.mozilla.gecko.background.common.log.Logger;
 import org.mozilla.gecko.sync.SyncConstants;
-import org.mozilla.gecko.sync.Logger;
 import org.mozilla.gecko.sync.ThreadPool;
 import org.mozilla.gecko.sync.setup.Constants;
 import org.mozilla.gecko.sync.setup.InvalidSyncKeyException;
 import org.mozilla.gecko.sync.setup.SyncAccounts;
 import org.mozilla.gecko.sync.setup.SyncAccounts.SyncAccountParameters;
 import org.mozilla.gecko.sync.setup.auth.AccountAuthenticator;
 import org.mozilla.gecko.sync.setup.auth.AuthenticationResult;
 
--- a/mobile/android/base/sync/setup/activities/ActivityUtils.java
+++ b/mobile/android/base/sync/setup/activities/ActivityUtils.java
@@ -1,15 +1,15 @@
 /* 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/. */
 
 package org.mozilla.gecko.sync.setup.activities;
 
-import org.mozilla.gecko.sync.Logger;
+import org.mozilla.gecko.background.common.log.Logger;
 import org.mozilla.gecko.sync.SyncConstants;
 import org.mozilla.gecko.sync.setup.InvalidSyncKeyException;
 
 public class ActivityUtils {
   public static void prepareLogging() {
     Logger.setThreadLogTag(SyncConstants.GLOBAL_LOG_TAG);
   }
 
--- a/mobile/android/base/sync/setup/activities/RedirectToSetupActivity.java
+++ b/mobile/android/base/sync/setup/activities/RedirectToSetupActivity.java
@@ -1,12 +1,16 @@
+/* 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/. */
+
 package org.mozilla.gecko.sync.setup.activities;
 
 import org.mozilla.gecko.R;
-import org.mozilla.gecko.sync.Logger;
+import org.mozilla.gecko.background.common.log.Logger;
 import org.mozilla.gecko.sync.setup.Constants;
 
 import android.content.Intent;
 import android.os.Bundle;
 import android.view.View;
 
 public class RedirectToSetupActivity extends SyncActivity {
   public static final String LOG_TAG = "RedirectToSetupActivity";
--- a/mobile/android/base/sync/setup/activities/SendTabActivity.java
+++ b/mobile/android/base/sync/setup/activities/SendTabActivity.java
@@ -6,20 +6,20 @@ package org.mozilla.gecko.sync.setup.act
 
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.List;
 import java.util.Map;
 import java.util.Map.Entry;
 
 import org.mozilla.gecko.R;
+import org.mozilla.gecko.background.common.log.Logger;
 import org.mozilla.gecko.sync.CommandProcessor;
 import org.mozilla.gecko.sync.CommandRunner;
 import org.mozilla.gecko.sync.GlobalSession;
-import org.mozilla.gecko.sync.Logger;
 import org.mozilla.gecko.sync.SyncConfiguration;
 import org.mozilla.gecko.sync.SyncConstants;
 import org.mozilla.gecko.sync.repositories.NullCursorException;
 import org.mozilla.gecko.sync.repositories.android.ClientsDatabaseAccessor;
 import org.mozilla.gecko.sync.repositories.domain.ClientRecord;
 import org.mozilla.gecko.sync.setup.Constants;
 import org.mozilla.gecko.sync.setup.SyncAccounts;
 import org.mozilla.gecko.sync.stage.SyncClientsEngineStage;
--- a/mobile/android/base/sync/setup/activities/SetupSuccessActivity.java
+++ b/mobile/android/base/sync/setup/activities/SetupSuccessActivity.java
@@ -1,16 +1,16 @@
 /* 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/. */
 
 package org.mozilla.gecko.sync.setup.activities;
 
 import org.mozilla.gecko.R;
-import org.mozilla.gecko.sync.GlobalConstants;
+import org.mozilla.gecko.background.common.GlobalConstants;
 import org.mozilla.gecko.sync.setup.Constants;
 import org.mozilla.gecko.sync.setup.SyncAccounts;
 
 import android.content.Intent;
 import android.os.Bundle;
 import android.view.View;
 import android.widget.TextView;
 
--- a/mobile/android/base/sync/setup/activities/SetupSyncActivity.java
+++ b/mobile/android/base/sync/setup/activities/SetupSyncActivity.java
@@ -4,17 +4,17 @@
 
 package org.mozilla.gecko.sync.setup.activities;
 
 import java.io.UnsupportedEncodingException;
 import java.util.HashMap;
 
 import org.json.simple.JSONObject;
 import org.mozilla.gecko.R;
-import org.mozilla.gecko.sync.Logger;
+import org.mozilla.gecko.background.common.log.Logger;
 import org.mozilla.gecko.sync.SyncConstants;
 import org.mozilla.gecko.sync.ThreadPool;
 import org.mozilla.gecko.sync.Utils;
 import org.mozilla.gecko.sync.jpake.JPakeClient;
 import org.mozilla.gecko.sync.jpake.JPakeNoActivePairingException;
 import org.mozilla.gecko.sync.setup.Constants;
 import org.mozilla.gecko.sync.setup.SyncAccounts;
 import org.mozilla.gecko.sync.setup.SyncAccounts.SyncAccountParameters;
--- a/mobile/android/base/sync/setup/activities/WebViewActivity.java
+++ b/mobile/android/base/sync/setup/activities/WebViewActivity.java
@@ -1,16 +1,16 @@
 /* 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/. */
 
 package org.mozilla.gecko.sync.setup.activities;
 
 import org.mozilla.gecko.R;
-import org.mozilla.gecko.sync.Logger;
+import org.mozilla.gecko.background.common.log.Logger;
 
 import android.app.Activity;
 import android.net.Uri;
 import android.os.Bundle;
 import android.view.Window;
 import android.webkit.WebChromeClient;
 import android.webkit.WebView;
 import android.webkit.WebViewClient;
--- a/mobile/android/base/sync/setup/auth/AccountAuthenticator.java
+++ b/mobile/android/base/sync/setup/auth/AccountAuthenticator.java
@@ -2,17 +2,17 @@
  * 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/. */
 
 package org.mozilla.gecko.sync.setup.auth;
 
 import java.util.LinkedList;
 import java.util.Queue;
 
-import org.mozilla.gecko.sync.Logger;
+import org.mozilla.gecko.background.common.log.Logger;
 import org.mozilla.gecko.sync.ThreadPool;
 import org.mozilla.gecko.sync.Utils;
 import org.mozilla.gecko.sync.setup.activities.AccountActivity;
 
 public class AccountAuthenticator {
   private final String LOG_TAG = "AccountAuthenticator";
 
   private AccountActivity activityCallback;
--- a/mobile/android/base/sync/setup/auth/AuthenticateAccountStage.java
+++ b/mobile/android/base/sync/setup/auth/AuthenticateAccountStage.java
@@ -8,18 +8,18 @@ import java.io.BufferedReader;
 import java.io.IOException;
 import java.io.InputStreamReader;
 import java.io.UnsupportedEncodingException;
 import java.net.URI;
 import java.net.URISyntaxException;
 import java.security.GeneralSecurityException;
 
 import org.mozilla.apache.commons.codec.binary.Base64;
+import org.mozilla.gecko.background.common.log.Logger;
 import org.mozilla.gecko.sync.SyncConstants;
-import org.mozilla.gecko.sync.Logger;
 import org.mozilla.gecko.sync.net.BaseResource;
 import org.mozilla.gecko.sync.net.BaseResourceDelegate;
 import org.mozilla.gecko.sync.setup.Constants;
 
 import ch.boye.httpclientandroidlib.HttpResponse;
 import ch.boye.httpclientandroidlib.client.ClientProtocolException;
 import ch.boye.httpclientandroidlib.client.methods.HttpRequestBase;
 import ch.boye.httpclientandroidlib.impl.client.DefaultHttpClient;
--- a/mobile/android/base/sync/setup/auth/EnsureUserExistenceStage.java
+++ b/mobile/android/base/sync/setup/auth/EnsureUserExistenceStage.java
@@ -7,17 +7,17 @@ package org.mozilla.gecko.sync.setup.aut
 import java.io.BufferedReader;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.InputStreamReader;
 import java.io.UnsupportedEncodingException;
 import java.net.URISyntaxException;
 import java.security.GeneralSecurityException;
 
-import org.mozilla.gecko.sync.Logger;
+import org.mozilla.gecko.background.common.log.Logger;
 import org.mozilla.gecko.sync.net.BaseResource;
 import org.mozilla.gecko.sync.net.BaseResourceDelegate;
 import org.mozilla.gecko.sync.setup.Constants;
 
 import ch.boye.httpclientandroidlib.HttpResponse;
 import ch.boye.httpclientandroidlib.client.ClientProtocolException;
 
 public class EnsureUserExistenceStage implements AuthenticatorStage {
--- a/mobile/android/base/sync/setup/auth/FetchUserNodeStage.java
+++ b/mobile/android/base/sync/setup/auth/FetchUserNodeStage.java
@@ -6,17 +6,17 @@ package org.mozilla.gecko.sync.setup.aut
 
 import java.io.BufferedReader;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.InputStreamReader;
 import java.net.URISyntaxException;
 import java.security.GeneralSecurityException;
 
-import org.mozilla.gecko.sync.Logger;
+import org.mozilla.gecko.background.common.log.Logger;
 import org.mozilla.gecko.sync.net.BaseResource;
 import org.mozilla.gecko.sync.net.BaseResourceDelegate;
 import org.mozilla.gecko.sync.setup.Constants;
 
 import ch.boye.httpclientandroidlib.HttpResponse;
 import ch.boye.httpclientandroidlib.client.ClientProtocolException;
 
 public class FetchUserNodeStage implements AuthenticatorStage {
--- a/mobile/android/base/sync/stage/AndroidBrowserBookmarksServerSyncStage.java
+++ b/mobile/android/base/sync/stage/AndroidBrowserBookmarksServerSyncStage.java
@@ -1,18 +1,18 @@
 /* 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/. */
 
 package org.mozilla.gecko.sync.stage;
 
 import java.net.URISyntaxException;
 
+import org.mozilla.gecko.background.common.log.Logger;
 import org.mozilla.gecko.sync.JSONRecordFetcher;
-import org.mozilla.gecko.sync.Logger;
 import org.mozilla.gecko.sync.MetaGlobalException;
 import org.mozilla.gecko.sync.repositories.RecordFactory;
 import org.mozilla.gecko.sync.repositories.Repository;
 import org.mozilla.gecko.sync.repositories.android.AndroidBrowserBookmarksRepository;
 import org.mozilla.gecko.sync.repositories.android.FennecControlHelper;
 import org.mozilla.gecko.sync.repositories.domain.BookmarkRecordFactory;
 import org.mozilla.gecko.sync.repositories.domain.VersionConstants;
 
--- a/mobile/android/base/sync/stage/AndroidBrowserHistoryServerSyncStage.java
+++ b/mobile/android/base/sync/stage/AndroidBrowserHistoryServerSyncStage.java
@@ -1,17 +1,17 @@
 /* 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/. */
 
 package org.mozilla.gecko.sync.stage;
 
 import java.net.URISyntaxException;
 
-import org.mozilla.gecko.sync.Logger;
+import org.mozilla.gecko.background.common.log.Logger;
 import org.mozilla.gecko.sync.MetaGlobalException;
 import org.mozilla.gecko.sync.repositories.ConstrainedServer11Repository;
 import org.mozilla.gecko.sync.repositories.RecordFactory;
 import org.mozilla.gecko.sync.repositories.Repository;
 import org.mozilla.gecko.sync.repositories.android.AndroidBrowserHistoryRepository;
 import org.mozilla.gecko.sync.repositories.android.FennecControlHelper;
 import org.mozilla.gecko.sync.repositories.domain.HistoryRecordFactory;
 import org.mozilla.gecko.sync.repositories.domain.VersionConstants;
--- a/mobile/android/base/sync/stage/EnsureClusterURLStage.java
+++ b/mobile/android/base/sync/stage/EnsureClusterURLStage.java
@@ -7,17 +7,17 @@ package org.mozilla.gecko.sync.stage;
 import java.io.BufferedReader;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.InputStreamReader;
 import java.net.URI;
 import java.net.URISyntaxException;
 import java.security.GeneralSecurityException;
 
-import org.mozilla.gecko.sync.Logger;
+import org.mozilla.gecko.background.common.log.Logger;
 import org.mozilla.gecko.sync.NodeAuthenticationException;
 import org.mozilla.gecko.sync.NullClusterURLException;
 import org.mozilla.gecko.sync.ThreadPool;
 import org.mozilla.gecko.sync.net.BaseResource;
 import org.mozilla.gecko.sync.net.BaseResourceDelegate;
 
 import ch.boye.httpclientandroidlib.HttpEntity;
 import ch.boye.httpclientandroidlib.HttpResponse;
--- a/mobile/android/base/sync/stage/EnsureCrypto5KeysStage.java
+++ b/mobile/android/base/sync/stage/EnsureCrypto5KeysStage.java
@@ -5,21 +5,21 @@
 package org.mozilla.gecko.sync.stage;
 
 import java.io.IOException;
 import java.net.URISyntaxException;
 import java.util.HashSet;
 import java.util.Set;
 
 import org.json.simple.parser.ParseException;
+import org.mozilla.gecko.background.common.log.Logger;
 import org.mozilla.gecko.sync.CollectionKeys;
 import org.mozilla.gecko.sync.CryptoRecord;
 import org.mozilla.gecko.sync.ExtendedJSONObject;
 import org.mozilla.gecko.sync.InfoCollections;
-import org.mozilla.gecko.sync.Logger;
 import org.mozilla.gecko.sync.NoCollectionKeysSetException;
 import org.mozilla.gecko.sync.NonObjectJSONException;
 import org.mozilla.gecko.sync.crypto.CryptoException;
 import org.mozilla.gecko.sync.crypto.KeyBundle;
 import org.mozilla.gecko.sync.crypto.PersistedCrypto5Keys;
 import org.mozilla.gecko.sync.net.SyncStorageRecordRequest;
 import org.mozilla.gecko.sync.net.SyncStorageRequestDelegate;
 import org.mozilla.gecko.sync.net.SyncStorageResponse;
--- a/mobile/android/base/sync/stage/FetchMetaGlobalStage.java
+++ b/mobile/android/base/sync/stage/FetchMetaGlobalStage.java
@@ -1,17 +1,17 @@
 /* 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/. */
 
 package org.mozilla.gecko.sync.stage;
 
+import org.mozilla.gecko.background.common.log.Logger;
 import org.mozilla.gecko.sync.GlobalSession;
 import org.mozilla.gecko.sync.InfoCollections;
-import org.mozilla.gecko.sync.Logger;
 import org.mozilla.gecko.sync.MetaGlobal;
 import org.mozilla.gecko.sync.PersistedMetaGlobal;
 import org.mozilla.gecko.sync.delegates.MetaGlobalDelegate;
 import org.mozilla.gecko.sync.net.SyncStorageResponse;
 
 public class FetchMetaGlobalStage extends AbstractNonRepositorySyncStage {
   private static final String LOG_TAG = "FetchMetaGlobalStage";
   private static final String META_COLLECTION = "meta";
--- a/mobile/android/base/sync/stage/SafeConstrainedServer11Repository.java
+++ b/mobile/android/base/sync/stage/SafeConstrainedServer11Repository.java
@@ -1,20 +1,20 @@
 /* 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/. */
 
 package org.mozilla.gecko.sync.stage;
 
 import java.net.URISyntaxException;
 
+import org.mozilla.gecko.background.common.log.Logger;
 import org.mozilla.gecko.sync.CredentialsSource;
 import org.mozilla.gecko.sync.InfoCounts;
 import org.mozilla.gecko.sync.JSONRecordFetcher;
-import org.mozilla.gecko.sync.Logger;
 import org.mozilla.gecko.sync.repositories.ConstrainedServer11Repository;
 import org.mozilla.gecko.sync.repositories.Repository;
 import org.mozilla.gecko.sync.repositories.Server11RepositorySession;
 import org.mozilla.gecko.sync.repositories.delegates.RepositorySessionCreationDelegate;
 
 import android.content.Context;
 
 /**
--- a/mobile/android/base/sync/stage/ServerSyncStage.java
+++ b/mobile/android/base/sync/stage/ServerSyncStage.java
@@ -5,21 +5,21 @@
 package org.mozilla.gecko.sync.stage;
 
 import java.io.IOException;
 import java.net.URISyntaxException;
 import java.util.Map;
 import java.util.concurrent.ExecutorService;
 
 import org.json.simple.parser.ParseException;
+import org.mozilla.gecko.background.common.log.Logger;
 import org.mozilla.gecko.sync.CredentialsSource;
 import org.mozilla.gecko.sync.EngineSettings;
 import org.mozilla.gecko.sync.GlobalSession;
 import org.mozilla.gecko.sync.HTTPFailureException;
-import org.mozilla.gecko.sync.Logger;
 import org.mozilla.gecko.sync.MetaGlobalException;
 import org.mozilla.gecko.sync.NoCollectionKeysSetException;
 import org.mozilla.gecko.sync.NonObjectJSONException;
 import org.mozilla.gecko.sync.SynchronizerConfiguration;
 import org.mozilla.gecko.sync.Utils;
 import org.mozilla.gecko.sync.crypto.KeyBundle;
 import org.mozilla.gecko.sync.delegates.WipeServerDelegate;
 import org.mozilla.gecko.sync.middleware.Crypto5MiddlewareRepository;
--- a/mobile/android/base/sync/stage/SyncClientsEngineStage.java
+++ b/mobile/android/base/sync/stage/SyncClientsEngineStage.java
@@ -8,22 +8,22 @@ import java.io.UnsupportedEncodingExcept
 import java.net.URI;
 import java.net.URISyntaxException;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.concurrent.atomic.AtomicInteger;
 
 import org.json.simple.JSONArray;
 import org.json.simple.JSONObject;
+import org.mozilla.gecko.background.common.log.Logger;
 import org.mozilla.gecko.sync.CommandProcessor;
 import org.mozilla.gecko.sync.CommandProcessor.Command;
 import org.mozilla.gecko.sync.CryptoRecord;
 import org.mozilla.gecko.sync.ExtendedJSONObject;
 import org.mozilla.gecko.sync.HTTPFailureException;
-import org.mozilla.gecko.sync.Logger;
 import org.mozilla.gecko.sync.NoCollectionKeysSetException;
 import org.mozilla.gecko.sync.Utils;
 import org.mozilla.gecko.sync.crypto.CryptoException;
 import org.mozilla.gecko.sync.crypto.KeyBundle;
 import org.mozilla.gecko.sync.delegates.ClientsDataDelegate;
 import org.mozilla.gecko.sync.net.BaseResource;
 import org.mozilla.gecko.sync.net.SyncStorageCollectionRequest;
 import org.mozilla.gecko.sync.net.SyncStorageRecordRequest;
--- a/mobile/android/base/sync/syncadapter/SyncAdapter.java
+++ b/mobile/android/base/sync/syncadapter/SyncAdapter.java
@@ -8,20 +8,20 @@ import java.io.IOException;
 import java.net.URI;
 import java.security.NoSuchAlgorithmException;
 import java.util.concurrent.atomic.AtomicBoolean;
 
 import org.json.simple.parser.ParseException;
 import org.mozilla.gecko.db.BrowserContract;
 import org.mozilla.gecko.sync.AlreadySyncingException;
 import org.mozilla.gecko.sync.CredentialException;
-import org.mozilla.gecko.sync.GlobalConstants;
+import org.mozilla.gecko.background.common.GlobalConstants;
+import org.mozilla.gecko.background.common.log.Logger;
 import org.mozilla.gecko.sync.SyncConstants;
 import org.mozilla.gecko.sync.GlobalSession;
-import org.mozilla.gecko.sync.Logger;
 import org.mozilla.gecko.sync.NonObjectJSONException;
 import org.mozilla.gecko.sync.SyncConfiguration;
 import org.mozilla.gecko.sync.SyncConfigurationException;
 import org.mozilla.gecko.sync.SyncException;
 import org.mozilla.gecko.sync.ThreadPool;
 import org.mozilla.gecko.sync.Utils;
 import org.mozilla.gecko.sync.config.AccountPickler;
 import org.mozilla.gecko.sync.crypto.CryptoException;
@@ -547,17 +547,17 @@ public class SyncAdapter extends Abstrac
     }
     return accountGUID;
   }
 
   @Override
   public synchronized String getClientName() {
     String clientName = accountSharedPreferences.getString(SyncConfiguration.PREF_CLIENT_NAME, null);
     if (clientName == null) {
-      clientName = SyncConstants.PRODUCT_NAME + " on " + android.os.Build.MODEL;
+      clientName = GlobalConstants.MOZ_APP_DISPLAYNAME + " on " + android.os.Build.MODEL;
       accountSharedPreferences.edit().putString(SyncConfiguration.PREF_CLIENT_NAME, clientName).commit();
     }
     return clientName;
   }
 
   @Override
   public synchronized void setClientsCount(int clientsCount) {
     accountSharedPreferences.edit().putLong(SyncConfiguration.PREF_NUM_CLIENTS, (long) clientsCount).commit();
--- a/mobile/android/base/sync/synchronizer/ConcurrentRecordConsumer.java
+++ b/mobile/android/base/sync/synchronizer/ConcurrentRecordConsumer.java
@@ -1,15 +1,15 @@
 /* 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/. */
 
 package org.mozilla.gecko.sync.synchronizer;
 
-import org.mozilla.gecko.sync.Logger;
+import org.mozilla.gecko.background.common.log.Logger;
 import org.mozilla.gecko.sync.repositories.domain.Record;
 
 /**
  * Consume records from a queue inside a RecordsChannel, as fast as we can.
  * TODO: rewrite this in terms of an ExecutorService and a CompletionService.
  * See Bug 713483.
  *
  * @author rnewman
--- a/mobile/android/base/sync/synchronizer/RecordsChannel.java
+++ b/mobile/android/base/sync/synchronizer/RecordsChannel.java
@@ -3,17 +3,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 package org.mozilla.gecko.sync.synchronizer;
 
 import java.util.concurrent.ConcurrentLinkedQueue;
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.atomic.AtomicInteger;
 
-import org.mozilla.gecko.sync.Logger;
+import org.mozilla.gecko.background.common.log.Logger;
 import org.mozilla.gecko.sync.ThreadPool;
 import org.mozilla.gecko.sync.repositories.InvalidSessionTransitionException;
 import org.mozilla.gecko.sync.repositories.NoStoreDelegateException;
 import org.mozilla.gecko.sync.repositories.RepositorySession;
 import org.mozilla.gecko.sync.repositories.delegates.DeferredRepositorySessionBeginDelegate;
 import org.mozilla.gecko.sync.repositories.delegates.DeferredRepositorySessionStoreDelegate;
 import org.mozilla.gecko.sync.repositories.delegates.RepositorySessionBeginDelegate;
 import org.mozilla.gecko.sync.repositories.delegates.RepositorySessionFetchRecordsDelegate;
--- a/mobile/android/base/sync/synchronizer/SerialRecordConsumer.java
+++ b/mobile/android/base/sync/synchronizer/SerialRecordConsumer.java
@@ -1,15 +1,15 @@
 /* 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/. */
 
 package org.mozilla.gecko.sync.synchronizer;
 
-import org.mozilla.gecko.sync.Logger;
+import org.mozilla.gecko.background.common.log.Logger;
 import org.mozilla.gecko.sync.repositories.domain.Record;
 
 /**
  * Consume records from a queue inside a RecordsChannel, storing them serially.
  * @author rnewman
  *
  */
 class SerialRecordConsumer extends RecordConsumer {
--- a/mobile/android/base/sync/synchronizer/ServerLocalSynchronizerSession.java
+++ b/mobile/android/base/sync/synchronizer/ServerLocalSynchronizerSession.java
@@ -1,15 +1,15 @@
 /* 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/. */
 
 package org.mozilla.gecko.sync.synchronizer;
 
-import org.mozilla.gecko.sync.Logger;
+import org.mozilla.gecko.background.common.log.Logger;
 import org.mozilla.gecko.sync.repositories.FetchFailedException;
 import org.mozilla.gecko.sync.repositories.StoreFailedException;
 
 /**
  * A <code>SynchronizerSession</code> designed to be used between a remote
  * server and a local repository.
  * <p>
  * Handles failure cases as follows (in the order they will occur during a sync):
--- a/mobile/android/base/sync/synchronizer/Synchronizer.java
+++ b/mobile/android/base/sync/synchronizer/Synchronizer.java
@@ -1,15 +1,15 @@
 /* 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/. */
 
 package org.mozilla.gecko.sync.synchronizer;
 
-import org.mozilla.gecko.sync.Logger;
+import org.mozilla.gecko.background.common.log.Logger;
 import org.mozilla.gecko.sync.SynchronizerConfiguration;
 import org.mozilla.gecko.sync.repositories.Repository;
 import org.mozilla.gecko.sync.repositories.RepositorySessionBundle;
 
 import android.content.Context;
 
 /**
  * I perform a sync.
--- a/mobile/android/base/sync/synchronizer/SynchronizerSession.java
+++ b/mobile/android/base/sync/synchronizer/SynchronizerSession.java
@@ -3,17 +3,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 package org.mozilla.gecko.sync.synchronizer;
 
 
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.atomic.AtomicInteger;
 
-import org.mozilla.gecko.sync.Logger;
+import org.mozilla.gecko.background.common.log.Logger;
 import org.mozilla.gecko.sync.repositories.InactiveSessionException;
 import org.mozilla.gecko.sync.repositories.InvalidSessionTransitionException;
 import org.mozilla.gecko.sync.repositories.RepositorySession;
 import org.mozilla.gecko.sync.repositories.RepositorySessionBundle;
 import org.mozilla.gecko.sync.repositories.delegates.DeferrableRepositorySessionCreationDelegate;
 import org.mozilla.gecko.sync.repositories.delegates.DeferredRepositorySessionFinishDelegate;
 import org.mozilla.gecko.sync.repositories.delegates.RepositorySessionFinishDelegate;
 
--- a/mobile/android/locales/en-US/chrome/phishing.dtd
+++ b/mobile/android/locales/en-US/chrome/phishing.dtd
@@ -1,26 +1,14 @@
 <!-- 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/. -->
 
-<!ENTITY safeb.palm.warning.title "Suspected Web Forgery">
-
-<!ENTITY safeb.palm.message.p1 "This page has been reported as a web forgery designed to trick users into sharing personal or financial information. Entering any personal information on this page may result in identity theft or other fraud. &#160;">
-<!ENTITY safeb.palm.message.p1.linkText "Read more &#187;">
-<!ENTITY safeb.palm.p1.linkStatusText "Read more &#133;">
-
-<!ENTITY safeb.palm.message.p2.start "These types of web forgeries are used in scams known as phishing attacks, in which fraudulent web pages and emails are used to imitate sources you may trust. You can find out more about ">
-<!ENTITY safeb.palm.message.p2.linkText "how &brandShortName; protects you">
-<!ENTITY safeb.palm.message.p2.end " from phishing attacks.">
-
 <!ENTITY safeb.palm.accept.label "Get me out of here!">
-<!ENTITY safeb.palm.accept.statustext "Navigate to my home page">
 <!ENTITY safeb.palm.decline.label "Ignore this warning">
-<!ENTITY safeb.palm.decline.statustext "Close warning" >
 <!ENTITY safeb.palm.notforgery.label2 "This isn't a web forgery…">
 <!ENTITY safeb.palm.reportPage.label "Why was this page blocked?">
 
 <!ENTITY safeb.blocked.malwarePage.title "Reported Attack Page!">
 <!-- Localization note (safeb.blocked.malware.shortDesc) - Please don't translate the contents of the <span id="malware_sitename"/> tag.  It will be replaced at runtime with a domain name (e.g. www.badsite.com) -->
 <!ENTITY safeb.blocked.malwarePage.shortDesc "This web page at <span id='malware_sitename'/> has been reported as an attack page and has been blocked based on your security preferences.">
 <!ENTITY safeb.blocked.malwarePage.longDesc "<p>Attack pages try to install programs that steal private information, use your computer to attack others, or damage your system.</p><p>Some attack pages intentionally distribute harmful software, but many are compromised without the knowledge or permission of their owners.</p>">
 
--- a/mobile/android/services/java-sources.mn
+++ b/mobile/android/services/java-sources.mn
@@ -2,18 +2,27 @@ background/announcements/Announcement.ja
 background/announcements/AnnouncementPresenter.java
 background/announcements/AnnouncementsBroadcastReceiver.java
 background/announcements/AnnouncementsBroadcastService.java
 background/announcements/AnnouncementsFetchDelegate.java
 background/announcements/AnnouncementsFetcher.java
 background/announcements/AnnouncementsFetchResourceDelegate.java
 background/announcements/AnnouncementsService.java
 background/announcements/AnnouncementsStartReceiver.java
-background/BackgroundConstants.java
 background/BackgroundService.java
+background/common/log/Logger.java
+background/common/log/writers/AndroidLevelCachingLogWriter.java
+background/common/log/writers/AndroidLogWriter.java
+background/common/log/writers/LevelFilteringLogWriter.java
+background/common/log/writers/LogWriter.java
+background/common/log/writers/PrintLogWriter.java
+background/common/log/writers/SimpleTagLogWriter.java
+background/common/log/writers/StringLogWriter.java
+background/common/log/writers/TagLogWriter.java
+background/common/log/writers/ThreadLocalTagLogWriter.java
 sync/AlreadySyncingException.java
 sync/CollectionKeys.java
 sync/CommandProcessor.java
 sync/CommandRunner.java
 sync/config/AccountPickler.java
 sync/config/activities/SelectEnginesActivity.java
 sync/config/ClientRecordTerminator.java
 sync/config/ConfigurationMigrator.java
@@ -62,26 +71,16 @@ sync/jpake/stage/DeleteChannel.java
 sync/jpake/stage/GetChannelStage.java
 sync/jpake/stage/GetRequestStage.java
 sync/jpake/stage/JPakeStage.java
 sync/jpake/stage/PutRequestStage.java
 sync/jpake/stage/VerifyPairingStage.java
 sync/jpake/Zkp.java
 sync/JSONRecordFetcher.java
 sync/KeyBundleProvider.java
-sync/log/writers/AndroidLevelCachingLogWriter.java
-sync/log/writers/AndroidLogWriter.java
-sync/log/writers/LevelFilteringLogWriter.java
-sync/log/writers/LogWriter.java
-sync/log/writers/PrintLogWriter.java
-sync/log/writers/SimpleTagLogWriter.java
-sync/log/writers/StringLogWriter.java
-sync/log/writers/TagLogWriter.java
-sync/log/writers/ThreadLocalTagLogWriter.java
-sync/Logger.java
 sync/MetaGlobal.java
 sync/MetaGlobalException.java
 sync/MetaGlobalMissingEnginesException.java
 sync/MetaGlobalNotSetException.java
 sync/middleware/Crypto5MiddlewareRepository.java
 sync/middleware/Crypto5MiddlewareRepositorySession.java
 sync/middleware/MiddlewareRepository.java
 sync/middleware/MiddlewareRepositorySession.java
--- a/mobile/android/services/preprocess-sources.mn
+++ b/mobile/android/services/preprocess-sources.mn
@@ -1,3 +1,3 @@
-sync/GlobalConstants.java
+background/common/GlobalConstants.java
 sync/SyncConstants.java
 background/announcements/AnnouncementsConstants.java
--- a/mobile/xul/locales/en-US/chrome/phishing.dtd
+++ b/mobile/xul/locales/en-US/chrome/phishing.dtd
@@ -1,26 +1,14 @@
 <!-- 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/. -->
 
-<!ENTITY safeb.palm.warning.title "Suspected Web Forgery">
-
-<!ENTITY safeb.palm.message.p1 "This page has been reported as a web forgery designed to trick users into sharing personal or financial information. Entering any personal information on this page may result in identity theft or other fraud. &#160;">
-<!ENTITY safeb.palm.message.p1.linkText "Read more &#187;">
-<!ENTITY safeb.palm.p1.linkStatusText "Read more &#133;">
-
-<!ENTITY safeb.palm.message.p2.start "These types of web forgeries are used in scams known as phishing attacks, in which fraudulent web pages and emails are used to imitate sources you may trust. You can find out more about ">
-<!ENTITY safeb.palm.message.p2.linkText "how &brandShortName; protects you">
-<!ENTITY safeb.palm.message.p2.end " from phishing attacks.">
-
 <!ENTITY safeb.palm.accept.label "Get me out of here!">
-<!ENTITY safeb.palm.accept.statustext "Navigate to my home page">
 <!ENTITY safeb.palm.decline.label "Ignore this warning">
-<!ENTITY safeb.palm.decline.statustext "Close warning" >
 <!ENTITY safeb.palm.notforgery.label2 "This isn't a web forgery…">
 <!ENTITY safeb.palm.reportPage.label "Why was this page blocked?">
 
 <!ENTITY safeb.blocked.malwarePage.title "Reported Attack Page!">
 <!-- Localization note (safeb.blocked.malware.shortDesc) - Please don't translate the contents of the <span id="malware_sitename"/> tag.  It will be replaced at runtime with a domain name (e.g. www.badsite.com) -->
 <!ENTITY safeb.blocked.malwarePage.shortDesc "This web page at <span id='malware_sitename'/> has been reported as an attack page and has been blocked based on your security preferences.">
 <!ENTITY safeb.blocked.malwarePage.longDesc "<p>Attack pages try to install programs that steal private information, use your computer to attack others, or damage your system.</p><p>Some attack pages intentionally distribute harmful software, but many are compromised without the knowledge or permission of their owners.</p>">
 
--- a/modules/libpref/src/init/all.js
+++ b/modules/libpref/src/init/all.js
@@ -3977,16 +3977,17 @@ pref("network.buffer.cache.size",  32768
 pref("notification.feature.enabled", false);
 
 // Alert animation effect, name is disableSlidingEffect for backwards-compat.
 pref("alerts.disableSlidingEffect", false);
 
 // DOM full-screen API.
 pref("full-screen-api.enabled", false);
 pref("full-screen-api.allow-trusted-requests-only", true);
+pref("full-screen-api.content-only", false);
 pref("full-screen-api.pointer-lock.enabled", true);
 
 // DOM idle observers API
 pref("dom.idle-observers-api.enabled", true);
 
 // Time limit, in milliseconds, for nsEventStateManager::IsHandlingUserInput().
 // Used to detect long running handlers of user-generated events.
 pref("dom.event.handling-user-input-time-limit", 1000);
--- a/parser/expat/lib/xmlparse.c
+++ b/parser/expat/lib/xmlparse.c
@@ -1507,17 +1507,19 @@ XML_Parse(XML_Parser parser, const char 
     eventEndPtr = eventPtr;
     processor = errorProcessor;
     return XML_STATUS_ERROR;
   }
 #ifndef XML_CONTEXT_BYTES
   else if (bufferPtr == bufferEnd) {
     const char *end;
     int nLeftOver;
-    enum XML_Error result;
+/* BEGIN MOZILLA CHANGE (|result| has type XML_Status, not XML_Error) */
+    enum XML_Status result;
+/* END MOZILLA CHANGE */
     parseEndByteIndex += len;
     positionPtr = s;
     ps_finalBuffer = (XML_Bool)isFinal;
 
     errorCode = processor(parser, s, parseEndPtr = s + len, &end);
 
     if (errorCode != XML_ERROR_NONE) {
       eventEndPtr = eventPtr;
--- a/security/manager/ssl/tests/mochitest/mixedcontent/test_bug472986.html
+++ b/security/manager/ssl/tests/mochitest/mixedcontent/test_bug472986.html
@@ -7,21 +7,17 @@
   <script type="text/javascript" src="/MochiKit/Style.js"></script>
   <script type="text/javascript" src="/MochiKit/Signal.js"></script>
   <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
   <script type="text/javascript" src="mixedContentTest.js"></script>
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
 
   <script class="testbody" type="text/javascript">
 
-  if (navigator.platform.startsWith("Win")) {
-    SimpleTest.expectAssertions(0, 3);
-  } else {
-    SimpleTest.expectAssertions(3);
-  }
+  SimpleTest.expectAssertions(0, 3);
 
   // Clear the default onload assigned to test start because we must
   // wait for replaced image to load and only after that test the security state
   var onLoadFunction = window.onload;
   window.onload = function()
   {
     var img1 = document.getElementById("img1");
     img1.addEventListener("load", onLoadFunction, false);
--- a/services/healthreport/healthreporter.jsm
+++ b/services/healthreport/healthreporter.jsm
@@ -83,16 +83,18 @@ function AbstractHealthReporter(branch, 
   this._initialized = false;
   this._initializeHadError = false;
   this._initializedDeferred = Promise.defer();
   this._shutdownRequested = false;
   this._shutdownInitiated = false;
   this._shutdownComplete = false;
   this._shutdownCompleteCallback = null;
 
+  this._errors = [];
+
   this._pullOnlyProviders = {};
   this._pullOnlyProvidersRegistered = false;
   this._lastDailyDate = null;
 
   // Yes, this will probably run concurrently with remaining constructor work.
   let hasFirstRun = this._prefs.get("service.firstRun", false);
   this._initHistogram = hasFirstRun ? TELEMETRY_INIT : TELEMETRY_INIT_FIRSTRUN;
   this._dbOpenHistogram = hasFirstRun ? TELEMETRY_DB_OPEN : TELEMETRY_DB_OPEN_FIRSTRUN;
@@ -123,18 +125,17 @@ AbstractHealthReporter.prototype = Objec
   //----------------------------------------------------
 
   _onInitError: function (error) {
     TelemetryStopwatch.cancel(this._initHistogram, this);
     TelemetryStopwatch.cancel(this._dbOpenHistogram, this);
     delete this._initHistogram;
     delete this._dbOpenHistogram;
 
-    this._log.error("Error during initialization: " +
-                    CommonUtils.exceptionStr(error));
+    this._recordError("Error during initialization", error);
     this._initializeHadError = true;
     this._initiateShutdown();
     this._initializedDeferred.reject(error);
 
     // FUTURE consider poisoning prototype's functions so calls fail with a
     // useful error message.
   },
 
@@ -170,16 +171,17 @@ AbstractHealthReporter.prototype = Objec
 
   _initializeCollector: function () {
     if (this._collector) {
       throw new Error("Collector has already been initialized.");
     }
 
     this._log.info("Initializing collector.");
     this._collector = new Metrics.Collector(this._storage);
+    this._collector.onProviderError = this._errors.push.bind(this._errors);
     this._collectorInProgress = true;
 
     let catString = this._prefs.get("service.providerCategories") || "";
     if (catString.length) {
       for (let category of catString.split(",")) {
         yield this.registerProvidersFromCategoryManager(category);
       }
     }
@@ -231,27 +233,31 @@ AbstractHealthReporter.prototype = Objec
       return;
     }
 
     this._log.info("Request to shut down.");
 
     this._initialized = false;
     this._shutdownRequested = true;
 
-    if (this._collectorInProgress) {
-      this._log.warn("Collector is in progress of initializing. Waiting to finish.");
-      return;
-    }
+    if (this._initializeHadError) {
+      this._log.warn("Initialization had error. Shutting down immediately.");
+    } else {
+      if (this._collectorInProgress) {
+        this._log.warn("Collector is in progress of initializing. Waiting to finish.");
+        return;
+      }
 
-    // If storage is in the process of initializing, we need to wait for it
-    // to finish before continuing. The initialization process will call us
-    // again once storage has initialized.
-    if (this._storageInProgress) {
-      this._log.warn("Storage is in progress of initializing. Waiting to finish.");
-      return;
+      // If storage is in the process of initializing, we need to wait for it
+      // to finish before continuing. The initialization process will call us
+      // again once storage has initialized.
+      if (this._storageInProgress) {
+        this._log.warn("Storage is in progress of initializing. Waiting to finish.");
+        return;
+      }
     }
 
     this._log.warn("Initiating main shutdown procedure.");
 
     // Everything from here must only be performed once or else race conditions
     // could occur.
 
     TelemetryStopwatch.start(TELEMETRY_SHUTDOWN, this);
@@ -479,18 +485,18 @@ AbstractHealthReporter.prototype = Objec
         let ns = {};
         Cu.import(uri, ns);
 
         let promise = this.registerProviderFromType(ns[entry]);
         if (promise) {
           promises.push(promise);
         }
       } catch (ex) {
-        this._log.warn("Error registering provider from category manager: " +
-                       entry + "; " + CommonUtils.exceptionStr(ex));
+        this._recordError("Error registering provider from category manager : " +
+                          entry + ": ", ex);
         continue;
       }
     }
 
     return Task.spawn(function wait() {
       for (let promise of promises) {
         yield promise;
       }
@@ -520,18 +526,17 @@ AbstractHealthReporter.prototype = Objec
     }.bind(this);
 
     return Task.spawn(function registerPullProviders() {
       for each (let providerType in this._pullOnlyProviders) {
         try {
           let provider = this.initProviderFromType(providerType);
           yield this.registerProvider(provider);
         } catch (ex) {
-          this._log.warn("Error registering pull-only provider: " +
-                         CommonUtils.exceptionStr(ex));
+          this._recordError("Error registering pull-only provider", ex);
         }
       }
     }.bind(this)).then(onFinished, onFinished);
   },
 
   ensurePullOnlyProvidersUnregistered: function () {
     if (!this._pullOnlyProvidersRegistered) {
       return Promise.resolve();
@@ -550,26 +555,55 @@ AbstractHealthReporter.prototype = Objec
         }
 
         this._log.info("Shutting down pull-only provider: " +
                        provider.name);
 
         try {
           yield provider.shutdown();
         } catch (ex) {
-          this._log.warn("Error when shutting down provider: " +
-                         CommonUtils.exceptionStr(ex));
+          this._recordError("Error when shutting down provider: " +
+                            provider.name, ex);
         } finally {
           this._collector.unregisterProvider(provider.name);
         }
       }
     }.bind(this)).then(onFinished, onFinished);
   },
 
   /**
+   * Record an exception for reporting in the payload.
+   *
+   * A side effect is the exception is logged.
+   *
+   * Note that callers need to be extra sensitive about ensuring personal
+   * or otherwise private details do not leak into this. All of the user data
+   * on the stack in FHR code should be limited to data we were collecting with
+   * the intent to submit. So, it is covered under the user's consent to use
+   * the feature.
+   *
+   * @param message
+   *        (string) Human readable message describing error.
+   * @param ex
+   *        (Error) The error that should be captured.
+   */
+  _recordError: function (message, ex) {
+    let recordMessage = message;
+    let logMessage = message;
+
+    if (ex) {
+      recordMessage += ": " + ex.message;
+      logMessage += ": " + CommonUtils.exceptionStr(ex);
+    }
+
+    this._log.warn(logMessage);
+    this._errors.push(recordMessage);
+  },
+
+  /**
    * Collect all measurements for all registered providers.
    */
   collectMeasurements: function () {
     return Task.spawn(function doCollection() {
       try {
         TelemetryStopwatch.start(TELEMETRY_COLLECT_CONSTANT, this);
         yield this._collector.collectConstantData();
         TelemetryStopwatch.finish(TELEMETRY_COLLECT_CONSTANT, this);
@@ -623,18 +657,18 @@ AbstractHealthReporter.prototype = Objec
       let payload;
       let error;
 
       try {
         yield this.collectMeasurements();
         payload = yield this.getJSONPayload(asObject);
       } catch (ex) {
         error = ex;
-        this._log.warn("Error collecting and/or retrieving JSON payload: " +
-                       CommonUtils.exceptionStr(ex));
+        this._collectException("Error collecting and/or retrieving JSON payload",
+                               ex);
       } finally {
         yield this.ensurePullOnlyProvidersUnregistered();
 
         if (error) {
           throw error;
         }
       }
 
@@ -684,21 +718,16 @@ AbstractHealthReporter.prototype = Objec
     let o = {
       version: 1,
       thisPingDate: pingDateString,
       data: {last: {}, days: {}},
     };
 
     let outputDataDays = o.data.days;
 
-    // We need to be careful that data in errors does not leak potentially
-    // private information.
-    // FUTURE ask Privacy if we can put exception stacks in here.
-    let errors = [];
-
     // Guard here in case we don't track this (e.g., on Android).
     let lastPingDate = this.lastPingDate;
     if (lastPingDate && lastPingDate.getTime() > 0) {
       o.lastPingDate = this._formatDate(lastPingDate);
     }
 
     for (let provider of this._collector.providers) {
       let providerName = provider.name;
@@ -711,38 +740,36 @@ AbstractHealthReporter.prototype = Objec
         let name = providerName + "." + measurement.name;
 
         let serializer;
         try {
           // The measurement is responsible for returning a serializer which
           // is aware of the measurement version.
           serializer = measurement.serializer(measurement.SERIALIZE_JSON);
         } catch (ex) {
-          this._log.warn("Error obtaining serializer for measurement: " + name +
-                         ": " + CommonUtils.exceptionStr(ex));
-          errors.push("Could not obtain serializer: " + name);
+          this._recordError("Error obtaining serializer for measurement: " +
+                            name, ex);
           continue;
         }
 
         let data;
         try {
           data = yield measurement.getValues();
         } catch (ex) {
-          this._log.warn("Error obtaining data for measurement: " +
-                         name + ": " + CommonUtils.exceptionStr(ex));
-          errors.push("Could not obtain data: " + name);
+          this._recordError("Error obtaining data for measurement: " + name,
+                            ex);
           continue;
         }
 
         if (data.singular.size) {
           try {
             o.data.last[name] = serializer.singular(data.singular);
           } catch (ex) {
-            this._log.warn("Error serializing data: " + CommonUtils.exceptionStr(ex));
-            errors.push("Error serializing singular: " + name);
+            this._recordError("Error serializing singular data: " + name,
+                              ex);
             continue;
           }
         }
 
         let dataDays = data.days;
         for (let i = 0; i < DAYS_IN_PAYLOAD; i++) {
           let date = new Date(now.getTime() - i * MILLISECONDS_PER_DAY);
           if (!dataDays.hasDay(date)) {
@@ -757,28 +784,25 @@ AbstractHealthReporter.prototype = Objec
             }
 
             if (!(dateFormatted in outputDataDays)) {
               outputDataDays[dateFormatted] = {};
             }
 
             outputDataDays[dateFormatted][name] = serialized;
           } catch (ex) {
-            this._log.warn("Error populating data for day: " +
-                           CommonUtils.exceptionStr(ex));
-            errors.push("Could not serialize day: " + name +
-                        " ( " + dateFormatted + ")");
+            this._recordError("Error populating data for day: " + name, ex);
             continue;
           }
         }
       }
     }
 
-    if (errors.length) {
-      o.errors = errors;
+    if (this._errors.length) {
+      o.errors = this._errors.slice(0, 20);
     }
 
     this._storage.compact();
 
     if (!asObject) {
       TelemetryStopwatch.start(TELEMETRY_JSON_PAYLOAD_SERIALIZE, this);
       o = JSON.stringify(o);
       TelemetryStopwatch.finish(TELEMETRY_JSON_PAYLOAD_SERIALIZE, this);
--- a/services/healthreport/modules-testing/utils.jsm
+++ b/services/healthreport/modules-testing/utils.jsm
@@ -231,16 +231,26 @@ InspectedHealthReporter.prototype = {
   _onStorageCreated: function (storage) {
     if (this.onStorageCreated) {
       this.onStorageCreated(storage);
     }
 
     return HealthReporter.prototype._onStorageCreated.call(this, storage);
   },
 
+  _initializeCollector: function () {
+    for (let result of HealthReporter.prototype._initializeCollector.call(this)) {
+      yield result;
+    }
+
+    if (this.onInitializeCollectorFinished) {
+      this.onInitializeCollectorFinished();
+    }
+  },
+
   _onCollectorInitialized: function () {
     if (this.onCollectorInitialized) {
       this.onCollectorInitialized();
     }
 
     return HealthReporter.prototype._onCollectorInitialized.call(this);
   },
 
--- a/services/healthreport/tests/xpcshell/test_healthreporter.js
+++ b/services/healthreport/tests/xpcshell/test_healthreporter.js
@@ -149,16 +149,31 @@ add_task(function test_shutdown_collecto
   };
 
   // This will hang if shutdown logic is busted.
   reporter._waitForShutdown();
   do_check_eq(reporter.collectorShutdownCount, 1);
   do_check_eq(reporter.storageCloseCount, 1);
 });
 
+// Simulates an error during collector initialization and verifies we shut down.
+add_task(function test_shutdown_when_collector_errors() {
+  let reporter = yield getJustReporter("shutdown_when_collector_errors", SERVER_URI, true);
+
+  reporter.onInitializeCollectorFinished = function () {
+    print("Throwing fake error.");
+    throw new Error("Fake error during collector initialization.");
+  };
+
+  // This will hang if shutdown logic is busted.
+  reporter._waitForShutdown();
+  do_check_eq(reporter.collectorShutdownCount, 1);
+  do_check_eq(reporter.storageCloseCount, 1);
+});
+
 add_task(function test_register_providers_from_category_manager() {
   const category = "healthreporter-js-modules";
 
   let cm = Cc["@mozilla.org/categorymanager;1"]
              .getService(Ci.nsICategoryManager);
   cm.addCategoryEntry(category, "DummyProvider",
                       "resource://testing-common/services/metrics/mocks.jsm",
                       false, true);
--- a/services/metrics/collector.jsm
+++ b/services/metrics/collector.jsm
@@ -27,17 +27,16 @@ Cu.import("resource://services-common/ut
 this.Collector = function (storage) {
   this._log = Log4Moz.repository.getLogger("Services.Metrics.Collector");
 
   this._providers = new Map();
   this._storage = storage;
 
   this._providerInitQueue = [];
   this._providerInitializing = false;
-  this.providerErrors = new Map();
 }
 
 Collector.prototype = Object.freeze({
   get providers() {
     let providers = [];
     for (let [name, entry] of this._providers) {
       providers.push(entry.provider);
     }
@@ -119,22 +118,19 @@ Collector.prototype = Object.freeze({
         let result = yield provider.init(this._storage);
         this._log.info("Provider successfully initialized: " + provider.name);
 
         this._providers.set(provider.name, {
           provider: provider,
           constantsCollected: false,
         });
 
-        this.providerErrors.set(provider.name, []);
-
         deferred.resolve(result);
       } catch (ex) {
-        this._log.warn("Provider failed to initialize: " + provider.name +
-                       ": " + CommonUtils.exceptionStr(ex));
+        this._recordProviderError(provider.name, "Failed to initialize", ex);
         deferred.reject(ex);
       } finally {
         this._providerInitializing = false;
         this._popAndInitProvider();
       }
     }.bind(this));
   },
 
@@ -179,25 +175,24 @@ Collector.prototype = Object.freeze({
     let promises = [];
 
     for (let entry of entries) {
       let provider = entry.provider;
       let collectPromise;
       try {
         collectPromise = provider[fnProperty].call(provider);
       } catch (ex) {
-        this._log.warn("Exception when calling " + provider.name + "." +
-                       fnProperty + ": " + CommonUtils.exceptionStr(ex));
-        this.providerErrors.get(provider.name).push(ex);
+        this._recordProviderError(provider.name, "Exception when calling " +
+                                  "collect function: " + fnProperty, ex);
         continue;
       }
 
       if (!collectPromise) {
-        this._log.warn("Provider does not return a promise from " +
-                       fnProperty + "(): " + provider.name);
+        this._recordProviderError(provider.name, "Does not return a promise " +
+                                  "from " + fnProperty + "()");
         continue;
       }
 
       let promise = collectPromise.then(function onCollected(result) {
         if (onCollect) {
           try {
             onCollect(entry, result);
           } catch (ex) {
@@ -226,24 +221,37 @@ Collector.prototype = Object.freeze({
    */
   _handleCollectionPromises: function (promises) {
     return Task.spawn(function waitForPromises() {
       for (let [name, promise] of promises) {
         try {
           yield promise;
           this._log.debug("Provider collected successfully: " + name);
         } catch (ex) {
-          this._log.warn("Provider failed to collect: " + name + ": " +
-                         CommonUtils.exceptionStr(ex));
-          try {
-            this.providerErrors.get(name).push(ex);
-          } catch (ex2) {
-            this._log.error("Error updating provider errors. This should " +
-                            "never happen: " + CommonUtils.exceptionStr(ex2));
-          }
+          this._recordProviderError(name, "Failed to collect", ex);
         }
       }
 
       throw new Task.Result(this);
     }.bind(this));
   },
+
+  /**
+   * Record an error that occurred operating on a provider.
+   */
+  _recordProviderError: function (name, msg, ex) {
+    let msg = "Provider error: " + name + ": " + msg;
+    if (ex) {
+      msg += ": " + ex.message;
+    }
+    this._log.warn(msg);
+
+    if (this.onProviderError) {
+      try {
+        this.onProviderError(msg);
+      } catch (callError) {
+        this._log.warn("Exception when calling onProviderError callback: " +
+                       CommonUtils.exceptionStr(callError));
+      }
+    }
+  },
 });
 
--- a/services/metrics/tests/xpcshell/test_metrics_collector.js
+++ b/services/metrics/tests/xpcshell/test_metrics_collector.js
@@ -24,17 +24,16 @@ add_task(function test_register_provider
 
   let collector = new Metrics.Collector(storage);
   let dummy = new DummyProvider();
 
   yield collector.registerProvider(dummy);
   do_check_eq(collector._providers.size, 1);
   yield collector.registerProvider(dummy);
   do_check_eq(collector._providers.size, 1);
-  do_check_eq(collector.providerErrors.size, 1);
   do_check_eq(collector.getProvider(dummy.name), dummy);
 
   let failed = false;
   try {
     collector.registerProvider({});
   } catch (ex) {
     do_check_true(ex.message.startsWith("Argument must be a Provider"));
     failed = true;
@@ -47,59 +46,64 @@ add_task(function test_register_provider
   do_check_eq(collector._providers.size, 0);
   do_check_null(collector.getProvider(dummy.name));
 
   yield storage.close();
 });
 
 add_task(function test_collect_constant_data() {
   let storage = yield Metrics.Storage("collect_constant_data");
+  let errorCount = 0;
   let collector = new Metrics.Collector(storage);
+  collector.onProviderError = function () { errorCount++; }
   let provider = new DummyProvider();
   yield collector.registerProvider(provider);
 
   do_check_eq(provider.collectConstantCount, 0);
 
   yield collector.collectConstantData();
   do_check_eq(provider.collectConstantCount, 1);
 
   do_check_true(collector._providers.get("DummyProvider").constantsCollected);
-  do_check_eq(collector.providerErrors.get("DummyProvider").length, 0);
 
   yield storage.close();
+  do_check_eq(errorCount, 0);
 });
 
 add_task(function test_collect_constant_throws() {
   let storage = yield Metrics.Storage("collect_constant_throws");
   let collector = new Metrics.Collector(storage);
+  let errors = [];
+  collector.onProviderError = function (error) { errors.push(error); };
+
   let provider = new DummyProvider();
   provider.throwDuringCollectConstantData = "Fake error during collect";
   yield collector.registerProvider(provider);
 
   yield collector.collectConstantData();
-  do_check_true(collector.providerErrors.has(provider.name));
-  let errors = collector.providerErrors.get(provider.name);
   do_check_eq(errors.length, 1);
-  do_check_eq(errors[0].message, provider.throwDuringCollectConstantData);
+  do_check_true(errors[0].contains(provider.throwDuringCollectConstantData));
 
   yield storage.close();
 });
 
 add_task(function test_collect_constant_populate_throws() {
   let storage = yield Metrics.Storage("collect_constant_populate_throws");
   let collector = new Metrics.Collector(storage);
+  let errors = [];
+  collector.onProviderError = function (error) { errors.push(error); };
+
   let provider = new DummyProvider();
   provider.throwDuringConstantPopulate = "Fake error during constant populate";
   yield collector.registerProvider(provider);
 
   yield collector.collectConstantData();
 
-  let errors = collector.providerErrors.get(provider.name);
   do_check_eq(errors.length, 1);
-  do_check_eq(errors[0].message, provider.throwDuringConstantPopulate);
+  do_check_true(errors[0].contains(provider.throwDuringConstantPopulate));
   do_check_false(collector._providers.get(provider.name).constantsCollected);
 
   yield storage.close();
 });
 
 add_task(function test_collect_constant_onetime() {
   let storage = yield Metrics.Storage("collect_constant_onetime");
   let collector = new Metrics.Collector(storage);
--- a/testing/marionette/client/marionette/venv_mochitest.sh
+++ b/testing/marionette/client/marionette/venv_mochitest.sh
@@ -1,14 +1,14 @@
 #!/bin/bash
 # 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/.
 
-VIRTUAL_ENV_VERSION="1.8.2"
+VIRTUAL_ENV_VERSION="49f40128a9ca3824ebf253eca408596e135cf893"
 
 PYTHON=$1
 
 # Store the current working directory so we can change back into it after
 # preparing the Marionette virtualenv
 CWD=$(pwd)
 
 if [ -z "${PYTHON}" ]
--- a/testing/mochitest/tests/SimpleTest/TestRunner.js
+++ b/testing/mochitest/tests/SimpleTest/TestRunner.js
@@ -420,16 +420,17 @@ TestRunner.expectChildProcessCrash = fun
 **/
 TestRunner.testFinished = function(tests) {
     // Prevent a test from calling finish() multiple times before we
     // have a chance to unload it.
     if (TestRunner._currentTest == TestRunner._lastTestFinished) {
         TestRunner.error("TEST-UNEXPECTED-FAIL | " +
                          TestRunner.currentTestURL +
                          " | called finish() multiple times");
+        TestRunner.updateUI([{ result: false }]);
         return;
     }
     TestRunner._lastTestFinished = TestRunner._currentTest;
 
     function cleanUpCrashDumpFiles() {
         if (!SpecialPowers.removeExpectedCrashDumpFiles(TestRunner._expectingProcessCrash)) {
             TestRunner.error("TEST-UNEXPECTED-FAIL | " +
                              TestRunner.currentTestURL +
@@ -489,23 +490,21 @@ TestRunner.testUnloaded = function() {
         var newAssertionCount = SpecialPowers.assertionCount();
         var numAsserts = newAssertionCount - TestRunner._lastAssertionCount;
         TestRunner._lastAssertionCount = newAssertionCount;
 
         var url = TestRunner._urls[TestRunner._currentTest];
         var max = TestRunner._expectedMaxAsserts;
         var min = TestRunner._expectedMinAsserts;
         if (numAsserts > max) {
-            // WHEN ENABLING, change "log" to "error" and "DETCEPXENU"
-            // to "UNEXPECTED".
-            TestRunner.log("TEST-DETCEPXENU-FAIL | " + url + " | Assertion count " + numAsserts + " is greater than expected range " + min + "-" + max + " assertions.");
+            TestRunner.error("TEST-UNEXPECTED-FAIL | " + url + " | Assertion count " + numAsserts + " is greater than expected range " + min + "-" + max + " assertions.");
+            TestRunner.updateUI([{ result: false }]);
         } else if (numAsserts < min) {
-            // WHEN ENABLING, change "log" to "error" and "DETCEPXENU"
-            // to "UNEXPECTED".
-            TestRunner.log("TEST-DETCEPXENU-PASS | " + url + " | Assertion count " + numAsserts + " is less than expected range " + min + "-" + max + " assertions.");
+            TestRunner.error("TEST-UNEXPECTED-PASS | " + url + " | Assertion count " + numAsserts + " is less than expected range " + min + "-" + max + " assertions.");
+            TestRunner.updateUI([{ result: false }]);
         } else if (numAsserts > 0) {
             TestRunner.log("TEST-KNOWN-FAIL | " + url + " | Assertion count " + numAsserts + " within expected range " + min + "-" + max + " assertions.");
         }
     }
     TestRunner._currentTest++;
     if (TestRunner.runSlower) {
         setTimeout(TestRunner.runNextTest, 1000);
     } else {
--- a/toolkit/components/places/Makefile.in
+++ b/toolkit/components/places/Makefile.in
@@ -26,17 +26,16 @@ XPIDLSRCS += \
   mozIAsyncHistory.idl \
   mozIAsyncFavicons.idl \
   mozIAsyncLivemarks.idl \
   mozIPlacesAutoComplete.idl \
   mozIColorAnalyzer.idl \
   nsIAnnotationService.idl \
   nsIBrowserHistory.idl \
   nsIFaviconService.idl \
-  nsILivemarkService.idl \
   nsINavBookmarksService.idl \
   nsITaggingService.idl  \
   nsPIPlacesDatabase.idl \
   nsPIPlacesHistoryListenersNotifier.idl \
   $(NULL)
 
 EXPORTS_NAMESPACES = mozilla/places
 
--- a/toolkit/components/places/PlacesUtils.jsm
+++ b/toolkit/components/places/PlacesUtils.jsm
@@ -439,59 +439,16 @@ this.PlacesUtils = {
               Ci.nsINavHistoryQueryOptions.RESULTS_AS_DATE_SITE_QUERY ||
             resultType == Ci.nsINavHistoryQueryOptions.RESULTS_AS_DATE_QUERY ||
             resultType == Ci.nsINavHistoryQueryOptions.RESULTS_AS_SITE_QUERY ||
             this.nodeIsDay(aNode) ||
             this.nodeIsHost(aNode));
   },
 
   /**
-   * Determines if a container item id is a livemark.
-   * @param aItemId
-   *        The id of the potential livemark.
-   * @returns true if the item is a livemark.
-   * @deprecated see the new API in mozIAsyncLivemarks.
-   */
-  itemIsLivemark: function PU_itemIsLivemark(aItemId) {
-    Cu.reportError("Synchronous livemarks methods and PlacesUtils livemarks " +
-                   "utils (itemIsLivemark, nodeIsLivemarkContainer, " +
-                   "nodeIsLivemarkItem) are deprecated and will be removed " +
-                   "in a future release.");
-    // If the Livemark service hasn't yet been initialized then
-    // use the annotations service directly to avoid instanciating
-    // it on startup. (bug 398300)
-    if (Object.getOwnPropertyDescriptor(this, "livemarks").value === undefined)
-      return this.annotations.itemHasAnnotation(aItemId, this.LMANNO_FEEDURI);
-    // If the livemark service has already been instanciated, use it.
-    return this.livemarks.isLivemark(aItemId);
-  },
-
-  /**
-   * Determines whether a result node is a livemark container.
-   * @param aNode
-   *        A result Node
-   * @returns true if the node is a livemark container item
-   * @deprecated see the new API in mozIAsyncLivemarks.
-   */
-  nodeIsLivemarkContainer: function PU_nodeIsLivemarkContainer(aNode) {
-    return this.nodeIsFolder(aNode) && this.itemIsLivemark(aNode.itemId);
-  },
-
- /**
-  * Determines whether a result node is a livemark item
-  * @param aNode
-  *        A result node
-  * @returns true if the node is a livemark container item
-   * @deprecated see the new API in mozIAsyncLivemarks.
-  */
-  nodeIsLivemarkItem: function PU_nodeIsLivemarkItem(aNode) {
-    return aNode.parent && this.nodeIsLivemarkContainer(aNode.parent);
-  },
-
-  /**
    * Determines whether or not a node is a readonly folder.
    * @param   aNode
    *          The node to test.
    * @returns true if the node is a readonly folder.
   */
   isReadonlyFolder: function(aNode) {
     return this.nodeIsFolder(aNode) &&
            this._readOnly.indexOf(asQuery(aNode).folderItemId) != -1;
@@ -2186,18 +2143,17 @@ XPCOMUtils.defineLazyServiceGetter(Place
                                    "nsIAnnotationService");
 
 XPCOMUtils.defineLazyServiceGetter(PlacesUtils, "tagging",
                                    "@mozilla.org/browser/tagging-service;1",
                                    "nsITaggingService");
 
 XPCOMUtils.defineLazyGetter(PlacesUtils, "livemarks", function() {
   return Cc["@mozilla.org/browser/livemark-service;2"].
-         getService(Ci.nsILivemarkService).
-         QueryInterface(Ci.mozIAsyncLivemarks);
+         getService(Ci.mozIAsyncLivemarks);
 });
 
 XPCOMUtils.defineLazyGetter(PlacesUtils, "transactionManager", function() {
   let tm = Cc["@mozilla.org/transactionmanager;1"].
            createInstance(Ci.nsITransactionManager);
   tm.AddListener(PlacesUtils);
   this.registerShutdownFunction(function () {
     // Clear all references to local transactions in the transaction manager,
deleted file mode 100644
--- a/toolkit/components/places/nsILivemarkService.idl
+++ /dev/null
@@ -1,185 +0,0 @@
-/* -*- Mode: C++; 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/. */
-
-#include "nsISupports.idl"
-
-/**
- * WARNING:
- *
- * This interface is deprecated and will be removed in a future release.
- * Use the mozIAsyncLivemarks interface instead.
- */
-
-interface nsIURI;
-interface nsINavBookmarksService;
-
-[scriptable, uuid(62a5fe00-d85c-4a63-aef7-176d8f1b189d)]
-interface nsILivemarkService : nsISupports
-{
-  /**
-   * Starts the livemark refresh timer.
-   * Being able to manually control this allows activity such
-   * as bookmarks import to occur without kicking off HTTP traffic.
-   *
-   * @note This is a no-op and exists just as a compatibility shim.
-   *
-   * @deprecated use the mozIAsyncLivemarks interface instead.
-   */
-  void start();
-
-  /**
-   * Stop the livemark refresh timer.
-   *
-   * @note This is a no-op and exists just as a compatibility shim.
-   *
-   * @deprecated use the mozIAsyncLivemarks interface instead.
-   */
-  void stopUpdateLivemarks();
-
-  /**
-   * Creates a new livemark
-   * @param folder      The id of the parent folder
-   * @param name        The name to show when displaying the livemark
-   * @param siteURI     The URI of the site the livemark was created from
-   * @param feedURI     The URI of the actual RSS feed
-   * @param index       The index to insert at, or
-   *                    nsINavBookmarksService.DEFAULT_INDEX to append.
-   * @returns the ID of the folder for the livemark
-   *
-   * @deprecated use the mozIAsyncLivemarks interface instead.
-   */
-  long long createLivemark(in long long folder,
-                           in AString name,
-                           in nsIURI siteURI,
-                           in nsIURI feedURI,
-                           in long index);
-
-  /**
-   * Same as above, use during startup to avoid HTTP traffic
-   */
-  long long createLivemarkFolderOnly(in long long folder,
-                                     in AString name,
-                                     in nsIURI siteURI,
-                                     in nsIURI feedURI,
-                                     in long index);
-
-  /**
-   * Determines whether the folder with the given folder ID identifies
-   * a livemark container.
-   *
-   * @param folder    A folder ID
-   *
-   * @returns true if the given folder is a livemark folder, or
-   *          false otherwise
-   *
-   * @throws NS_ERROR_INVALID_ARG if the folder ID isn't known
-   *
-   * @deprecated use the mozIAsyncLivemarks interface instead.
-   */
-  boolean isLivemark(in long long folder);
-
-  /**
-   * Determines whether the feed URI is a currently registered livemark.
-   *
-   * @param aFeedURI
-   *        Feed URI to look for.
-   *
-   * @returns the found livemark folder id, or -1 if nothing was found.
-   *
-   * @deprecated use the mozIAsyncLivemarks interface instead.
-   */
-  long long getLivemarkIdForFeedURI(in nsIURI aFeedURI);
-
-  /**
-   * Gets the URI of the website associated with a livemark container.
-   *
-   * @param container  The folder ID of a livemark container
-   *
-   * @returns nsIURI representing the URI of the website; if the livemark
-   *          container doesn't have a valid site URI, null will be returned
-   *
-   * @throws NS_ERROR_INVALID_ARG if the folder ID isn't known or identifies
-   *         a folder that isn't a livemark container
-   * @throws NS_ERROR_MALFORMED_URI if the site URI annotation has
-   *         somehow been corrupted (and can't be turned into an nsIURI)
-   *
-   * @deprecated use the mozIAsyncLivemarks interface instead.
-   */
-  nsIURI getSiteURI(in long long container);
-
-  /**
-   * Sets the URI of the website associated with a livemark container.
-   *
-   * @param container  The folder ID of a livemark container
-   * @param siteURI    nsIURI object representing the site URI, or null
-   *                   to clear the site URI for this livemark container
-   *
-   * @throws NS_ERROR_INVALID_ARG if the folder ID isn't known or identifies
-   *         a folder that isn't a livemark container; also if the siteURI
-   *         argument isn't a valid nsIURI object (or null)
-   *
-   * @note This is a no-op and exists just as a compatibility shim.
-   *
-   * @deprecated use the mozIAsyncLivemarks interface instead.
-   */
-  void setSiteURI(in long long container, in nsIURI siteURI);
-
-  /**
-   * Gets the URI of the syndication feed associated with a livemark container.
-   *
-   * @param container  The folder ID of a livemark container
-   *
-   * @returns nsIURI representing the URI of the feed; if the livemark
-   *          container doesn't have a valid feed URI, null will be returned
-   *          of the nsIURI object returned will be the empty string.
-   *
-   * @throws NS_ERROR_INVALID_ARG if the folder ID isn't known or identifies
-   *         a folder that isn't a livemark container
-   * @throws NS_ERROR_MALFORMED_URI if the site URI annotation has
-   *         somehow been corrupted (and can't be turned into an nsIURI)
-   *
-   * @deprecated use the mozIAsyncLivemarks interface instead.
-   */
-  nsIURI getFeedURI(in long long container);
-
-  /**
-   * Sets the URI of the feed associated with a livemark container.
-   *
-   * NOTE: The caller is responsible for reloading the livemark after
-   *       changing its feed URI (since the contents are likely to be different
-   *       given a different feed).
-   *
-   * @param container  The folder ID of a livemark container
-   * @param feedURI    nsIURI object representing the syndication feed URI
-   *
-   * @throws NS_ERROR_INVALID_ARG if the folder ID isn't known or identifies
-   *         a folder that isn't a livemark container; also if the feedURI
-   *         argument isn't a valid nsIURI object
-   *
-   * @note This is a no-op and exists just as a compatibility shim.
-   *
-   * @deprecated use the mozIAsyncLivemarks interface instead.
-   */
-  void setFeedURI(in long long container, in nsIURI feedURI);
-
-  /**
-   * Reloads all livemark subscriptions, whether or not they've expired.
-   *
-   * @deprecated use the mozIAsyncLivemarks interface instead.
-   */
-  void reloadAllLivemarks();
-
-  /**
-   * Reloads the livemark with this folder ID, whether or not it's expired.
-   * @param folderID The ID of the folder to be reloaded
-   *
-   * @deprecated use the mozIAsyncLivemarks interface instead.
-   */
-  void reloadLivemarkFolder(in long long folderID);
-};
-
-%{C++
-#define LMANNO_FEEDURI "livemark/feedURI"
-%}
--- a/toolkit/components/places/nsLivemarkService.js
+++ b/toolkit/components/places/nsLivemarkService.js
@@ -190,191 +190,16 @@ LivemarkService.prototype = {
       for each (let livemark in this._livemarks) {
         livemark.terminate();
       }
       this._livemarks = {};
     }
   },
 
   //////////////////////////////////////////////////////////////////////////////
-  //// Deprecated nsILivemarkService methods
-
-  _reportDeprecatedMethod: function DEPRECATED_LS__reportDeprecatedMethod()
-  {
-    let oldFuncName = arguments.callee.caller.name.slice(14);
-    Cu.reportError(oldFuncName + " is deprecated and will be removed in a " +
-                   "future release.  Check the nsILivemarkService interface.");
-  },
-
-  _ensureSynchronousCache: function DEPRECATED_LS__ensureSynchronousCache()
-  {
-    if (!this._pendingStmt) {
-      return;
-    }
-    this._pendingStmt.cancel();
-    this._pendingStmt = null;
-
-    let db = PlacesUtils.history.QueryInterface(Ci.nsPIPlacesDatabase)
-                                .DBConnection;
-    let stmt = db.createStatement(this._populateCacheSQL);
-    stmt.params.folder_type = Ci.nsINavBookmarksService.TYPE_FOLDER;
-    stmt.params.feedURI_anno = PlacesUtils.LMANNO_FEEDURI;
-    stmt.params.siteURI_anno = PlacesUtils.LMANNO_SITEURI;
-
-    while (stmt.executeStep()) {
-      let id = stmt.row.id;
-      let siteURL = stmt.row.siteURI;
-      let guid = stmt.row.guid;
-      this._livemarks[id] =
-        new Livemark({ id: id,
-                       guid: guid,
-                       title: stmt.row.title,
-                       parentId: stmt.row.parent,
-                       index: stmt.row.position,
-                       lastModified: stmt.row.lastModified,
-                       feedURI: NetUtil.newURI(stmt.row.feedURI),
-                       siteURI: siteURL ? NetUtil.newURI(siteURL) : null,
-        });
-      this._guids[guid] = id;
-    }
-    stmt.finalize();
-  },
-
-  start: function DEPRECATED_LS_start()
-  {
-    this._reportDeprecatedMethod();
-  },
-
-  stopUpdateLivemarks: function DEPRECATED_LS_stopUpdateLivemarks()
-  {
-    this._reportDeprecatedMethod();
-  },
-
-  createLivemark: function DEPRECATED_LS_createLivemark(aParentId, aTitle, aSiteURI,
-                                                        aFeedURI, aIndex)
-  {
-    this._reportDeprecatedMethod();
-    this._ensureSynchronousCache();
-
-    if (!aParentId || aParentId < 1 ||
-        aIndex < -1 ||
-        !aFeedURI || !(aFeedURI instanceof Ci.nsIURI) ||
-        (aSiteURI && !(aSiteURI instanceof Ci.nsIURI)) ||
-         aParentId in this._livemarks) {
-      throw Cr.NS_ERROR_INVALID_ARG;
-    }
-
-    let livemark = new Livemark({ title:    aTitle
-                                , parentId: aParentId
-                                , index:    aIndex
-                                , feedURI:  aFeedURI
-                                , siteURI:  aSiteURI
-                                });
-    if (this._itemAdded && this._itemAdded.id == livemark.id) {
-      livemark.guid = this._itemAdded.guid;
-      livemark.index = this._itemAdded.index;
-      livemark.lastModified = this._itemAdded.lastModified;
-    }
-
-    this._livemarks[livemark.id] = livemark;
-    this._guids[livemark.guid] = livemark.id;
-    return livemark.id;
-  },
-
-  createLivemarkFolderOnly: function DEPRECATED_LS_(aParentId, aTitle, aSiteURI,
-                                                    aFeedURI, aIndex)
-  {
-    return this.createLivemark(aParentId, aTitle, aSiteURI, aFeedURI, aIndex);
-  },
-
-  isLivemark: function DEPRECATED_LS_isLivemark(aId)
-  {
-    this._reportDeprecatedMethod();