Merge m-c to inbound on a CLOSED TREE
authorWes Kocher <wkocher@mozilla.com>
Wed, 02 Apr 2014 19:54:15 -0700
changeset 188855 a3f6179f3e9349b9e0838a4ab11a33d611f545cf
parent 188854 8dc0eace320db3f251c09a30dae9fa31a51692fc (current diff)
parent 188827 16cf810656c7406fda903426aca909546e000ba0 (diff)
child 188856 db80411a6185b42656d937435aba05f3d03f60f0
push idunknown
push userunknown
push dateunknown
milestone31.0a1
Merge m-c to inbound on a CLOSED TREE
content/media/MediaDecoderStateMachine.cpp
content/media/MediaDecoderStateMachine.h
--- a/b2g/config/emulator-ics/sources.xml
+++ b/b2g/config/emulator-ics/sources.xml
@@ -14,17 +14,17 @@
   <!--original fetch url was git://github.com/apitrace/-->
   <remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/>
   <default remote="caf" revision="refs/tags/android-4.0.4_r2.1" sync-j="4"/>
   <!-- Gonk specific things and forks -->
   <project name="platform_build" path="build" remote="b2g" revision="1ad48c4be51b279f7f63c1a13025b52fe087d231">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
-  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="04d96dd43e2c5c673a0c73b5a65faeb115c2065f"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="f64a5aec7d8138d85de6862b8c6b999abc55acca"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="266bca6e60dad43e395f38b66edabe8bdc882334"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="d11f524d00cacf5ba0dfbf25e4aa2158b1c3a036"/>
   <project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="12408eb142739c7de87ab7ee0d0d2854d5c298f3"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="70b698c2e8d1764a1e27527a102df6452e405b9a"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="89c5816399e71bda92a8959b5b771c04d6672ea3"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="dd924f92906085b831bf1cbbc7484d3c043d613c"/>
--- a/b2g/config/emulator-jb/sources.xml
+++ b/b2g/config/emulator-jb/sources.xml
@@ -7,22 +7,22 @@
   <remote fetch="https://git.mozilla.org/b2g" name="mozilla"/>
   <!--original fetch url was git://github.com/apitrace/-->
   <remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/>
   <!--original fetch url was git://codeaurora.org/-->
   <remote fetch="https://git.mozilla.org/external/caf" name="caf"/>
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!-- B2G specific things. -->
-  <project name="platform_build" path="build" remote="b2g" revision="15d69a6789c638709911507f74d25c0425963636">
+  <project name="platform_build" path="build" remote="b2g" revision="f6a198295f65ac38f8511803654a3583a1c666af">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="04d96dd43e2c5c673a0c73b5a65faeb115c2065f"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="f64a5aec7d8138d85de6862b8c6b999abc55acca"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="266bca6e60dad43e395f38b66edabe8bdc882334"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="70b698c2e8d1764a1e27527a102df6452e405b9a"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="89c5816399e71bda92a8959b5b771c04d6672ea3"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
   <!-- Stock Android things -->
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.1" path="prebuilts/clang/linux-x86/3.1" revision="5c45f43419d5582949284eee9cef0c43d866e03b"/>
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.2" path="prebuilts/clang/linux-x86/3.2" revision="3748b4168e7bd8d46457d4b6786003bc6a5223ce"/>
--- a/b2g/config/emulator-kk/sources.xml
+++ b/b2g/config/emulator-kk/sources.xml
@@ -10,17 +10,17 @@
   <!--original fetch url was git://codeaurora.org/-->
   <remote fetch="https://git.mozilla.org/external/caf" name="caf"/>
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="a9e08b91e9cd1f0930f16cfc49ec72f63575d5fe">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="04d96dd43e2c5c673a0c73b5a65faeb115c2065f"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="f64a5aec7d8138d85de6862b8c6b999abc55acca"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="266bca6e60dad43e395f38b66edabe8bdc882334"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="70b698c2e8d1764a1e27527a102df6452e405b9a"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="89c5816399e71bda92a8959b5b771c04d6672ea3"/>
   <!-- Stock Android things -->
--- a/b2g/config/emulator/sources.xml
+++ b/b2g/config/emulator/sources.xml
@@ -14,17 +14,17 @@
   <!--original fetch url was git://github.com/apitrace/-->
   <remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/>
   <default remote="caf" revision="refs/tags/android-4.0.4_r2.1" sync-j="4"/>
   <!-- Gonk specific things and forks -->
   <project name="platform_build" path="build" remote="b2g" revision="1ad48c4be51b279f7f63c1a13025b52fe087d231">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
-  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="04d96dd43e2c5c673a0c73b5a65faeb115c2065f"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="f64a5aec7d8138d85de6862b8c6b999abc55acca"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="266bca6e60dad43e395f38b66edabe8bdc882334"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="d11f524d00cacf5ba0dfbf25e4aa2158b1c3a036"/>
   <project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="12408eb142739c7de87ab7ee0d0d2854d5c298f3"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="70b698c2e8d1764a1e27527a102df6452e405b9a"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="89c5816399e71bda92a8959b5b771c04d6672ea3"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="dd924f92906085b831bf1cbbc7484d3c043d613c"/>
--- a/b2g/config/gaia.json
+++ b/b2g/config/gaia.json
@@ -1,9 +1,9 @@
 {
     "git": {
         "git_revision": "", 
         "remote": "", 
         "branch": ""
     }, 
-    "revision": "c23b496987e1e356c1cf7cc848c69511f6db041a", 
+    "revision": "f2784b078a4b58c1f0af8238d5325d0f05dc9fc0", 
     "repo_path": "/integration/gaia-central"
 }
--- a/b2g/config/hamachi/sources.xml
+++ b/b2g/config/hamachi/sources.xml
@@ -12,17 +12,17 @@
   <!--original fetch url was git://github.com/apitrace/-->
   <remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/>
   <default remote="caf" revision="b2g/ics_strawberry" sync-j="4"/>
   <!-- Gonk specific things and forks -->
   <project name="platform_build" path="build" remote="b2g" revision="1ad48c4be51b279f7f63c1a13025b52fe087d231">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
-  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="04d96dd43e2c5c673a0c73b5a65faeb115c2065f"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="f64a5aec7d8138d85de6862b8c6b999abc55acca"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="266bca6e60dad43e395f38b66edabe8bdc882334"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="1f6a1fe07f81c5bc5e1d079c9b60f7f78ca2bf4f"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="70b698c2e8d1764a1e27527a102df6452e405b9a"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="89c5816399e71bda92a8959b5b771c04d6672ea3"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="6426040f1be4a844082c9769171ce7f5341a5528"/>
   <project name="platform/bionic" path="bionic" revision="d2eb6c7b6e1bc7643c17df2d9d9bcb1704d0b9ab"/>
--- a/b2g/config/helix/sources.xml
+++ b/b2g/config/helix/sources.xml
@@ -10,17 +10,17 @@
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <default remote="caf" revision="b2g/ics_strawberry" sync-j="4"/>
   <!-- Gonk specific things and forks -->
   <project name="platform_build" path="build" remote="b2g" revision="1ad48c4be51b279f7f63c1a13025b52fe087d231">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
-  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="04d96dd43e2c5c673a0c73b5a65faeb115c2065f"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="f64a5aec7d8138d85de6862b8c6b999abc55acca"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="266bca6e60dad43e395f38b66edabe8bdc882334"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="1f6a1fe07f81c5bc5e1d079c9b60f7f78ca2bf4f"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="70b698c2e8d1764a1e27527a102df6452e405b9a"/>
   <project name="gonk-patches" path="patches" remote="b2g" revision="223a2421006e8f5da33f516f6891c87cae86b0f6"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="6426040f1be4a844082c9769171ce7f5341a5528"/>
   <project name="platform/bionic" path="bionic" revision="d2eb6c7b6e1bc7643c17df2d9d9bcb1704d0b9ab"/>
--- a/b2g/config/inari/sources.xml
+++ b/b2g/config/inari/sources.xml
@@ -14,17 +14,17 @@
   <!--original fetch url was git://github.com/apitrace/-->
   <remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/>
   <default remote="caf" revision="ics_chocolate_rb4.2" sync-j="4"/>
   <!-- Gonk specific things and forks -->
   <project name="platform_build" path="build" remote="b2g" revision="1ad48c4be51b279f7f63c1a13025b52fe087d231">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
-  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="04d96dd43e2c5c673a0c73b5a65faeb115c2065f"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="f64a5aec7d8138d85de6862b8c6b999abc55acca"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="266bca6e60dad43e395f38b66edabe8bdc882334"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="1f6a1fe07f81c5bc5e1d079c9b60f7f78ca2bf4f"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="70b698c2e8d1764a1e27527a102df6452e405b9a"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="89c5816399e71bda92a8959b5b771c04d6672ea3"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="6426040f1be4a844082c9769171ce7f5341a5528"/>
   <project name="platform/bionic" path="bionic" revision="cd5dfce80bc3f0139a56b58aca633202ccaee7f8"/>
--- a/b2g/config/leo/sources.xml
+++ b/b2g/config/leo/sources.xml
@@ -12,17 +12,17 @@
   <!--original fetch url was git://github.com/apitrace/-->
   <remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/>
   <default remote="caf" revision="b2g/ics_strawberry" sync-j="4"/>
   <!-- Gonk specific things and forks -->
   <project name="platform_build" path="build" remote="b2g" revision="1ad48c4be51b279f7f63c1a13025b52fe087d231">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
-  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="04d96dd43e2c5c673a0c73b5a65faeb115c2065f"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="f64a5aec7d8138d85de6862b8c6b999abc55acca"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="266bca6e60dad43e395f38b66edabe8bdc882334"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="1f6a1fe07f81c5bc5e1d079c9b60f7f78ca2bf4f"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="70b698c2e8d1764a1e27527a102df6452e405b9a"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="89c5816399e71bda92a8959b5b771c04d6672ea3"/>
   <project name="gonk-patches" path="patches" remote="b2g" revision="223a2421006e8f5da33f516f6891c87cae86b0f6"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="6426040f1be4a844082c9769171ce7f5341a5528"/>
--- a/b2g/config/mako/sources.xml
+++ b/b2g/config/mako/sources.xml
@@ -7,22 +7,22 @@
   <remote fetch="https://git.mozilla.org/b2g" name="mozilla"/>
   <!--original fetch url was git://github.com/apitrace/-->
   <remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/>
   <!--original fetch url was git://codeaurora.org/-->
   <remote fetch="https://git.mozilla.org/external/caf" name="caf"/>
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!-- B2G specific things. -->
-  <project name="platform_build" path="build" remote="b2g" revision="15d69a6789c638709911507f74d25c0425963636">
+  <project name="platform_build" path="build" remote="b2g" revision="f6a198295f65ac38f8511803654a3583a1c666af">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="04d96dd43e2c5c673a0c73b5a65faeb115c2065f"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="f64a5aec7d8138d85de6862b8c6b999abc55acca"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="266bca6e60dad43e395f38b66edabe8bdc882334"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="70b698c2e8d1764a1e27527a102df6452e405b9a"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="89c5816399e71bda92a8959b5b771c04d6672ea3"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
   <!-- Stock Android things -->
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.1" path="prebuilts/clang/linux-x86/3.1" revision="5c45f43419d5582949284eee9cef0c43d866e03b"/>
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.2" path="prebuilts/clang/linux-x86/3.2" revision="3748b4168e7bd8d46457d4b6786003bc6a5223ce"/>
--- a/b2g/config/wasabi/sources.xml
+++ b/b2g/config/wasabi/sources.xml
@@ -12,17 +12,17 @@
   <!--original fetch url was git://github.com/apitrace/-->
   <remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/>
   <default remote="caf" revision="ics_chocolate_rb4.2" sync-j="4"/>
   <!-- Gonk specific things and forks -->
   <project name="platform_build" path="build" remote="b2g" revision="1ad48c4be51b279f7f63c1a13025b52fe087d231">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
-  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="04d96dd43e2c5c673a0c73b5a65faeb115c2065f"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="f64a5aec7d8138d85de6862b8c6b999abc55acca"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="266bca6e60dad43e395f38b66edabe8bdc882334"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="1f6a1fe07f81c5bc5e1d079c9b60f7f78ca2bf4f"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="70b698c2e8d1764a1e27527a102df6452e405b9a"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="89c5816399e71bda92a8959b5b771c04d6672ea3"/>
   <project name="gonk-patches" path="patches" remote="b2g" revision="223a2421006e8f5da33f516f6891c87cae86b0f6"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="6426040f1be4a844082c9769171ce7f5341a5528"/>
--- a/browser/base/content/browser-menubar.inc
+++ b/browser/base/content/browser-menubar.inc
@@ -68,20 +68,22 @@
                           accesskey="&savePageCmd.accesskey;"
                           key="key_savePage"
                           command="Browser:SavePage"/>
                 <menuitem id="menu_sendLink"
                           label="&emailPageCmd.label;"
                           accesskey="&emailPageCmd.accesskey;"
                           command="Browser:SendLink"/>
                 <menuseparator/>
+#ifndef XP_LINUX
                 <menuitem id="menu_printSetup"
                           label="&printSetupCmd.label;"
                           accesskey="&printSetupCmd.accesskey;"
                           command="cmd_pageSetup"/>
+#endif
 #ifndef XP_MACOSX
                 <menuitem id="menu_printPreview"
                           label="&printPreviewCmd.label;"
                           accesskey="&printPreviewCmd.accesskey;"
                           command="cmd_printPreview"/>
 #endif
                 <menuitem id="menu_print"
                           label="&printCmd.label;"
--- a/browser/components/sessionstore/test/head.js
+++ b/browser/components/sessionstore/test/head.js
@@ -35,17 +35,18 @@ registerCleanupFunction(() => {
     mm.removeDelayedFrameScript(script, true);
   }
   mm.removeMessageListener("SessionStore:setupSyncHandler", onSetupSyncHandler);
 });
 
 let tmp = {};
 Cu.import("resource://gre/modules/Promise.jsm", tmp);
 Cu.import("resource:///modules/sessionstore/SessionStore.jsm", tmp);
-let {Promise, SessionStore} = tmp;
+Cu.import("resource:///modules/sessionstore/SessionSaver.jsm", tmp);
+let {Promise, SessionStore, SessionSaver} = tmp;
 
 let ss = Cc["@mozilla.org/browser/sessionstore;1"].getService(Ci.nsISessionStore);
 
 // Some tests here assume that all restored tabs are loaded without waiting for
 // the user to bring them to the foreground. We ensure this by resetting the
 // related preference (see the "firefox.js" defaults file for details).
 Services.prefs.setBoolPref("browser.sessionstore.restore_on_demand", false);
 registerCleanupFunction(function () {
@@ -260,33 +261,17 @@ function promiseSaveState() {
     if (isSuccessful) {
       deferred.resolve();
     } else {
       deferred.reject(new Error("timeout"));
     }});
   return deferred.promise;
 }
 function forceSaveState() {
-  let promise = promiseSaveState();
-  const PREF = "browser.sessionstore.interval";
-  let original = Services.prefs.getIntPref(PREF);
-  // Set interval to an arbitrary non-0 duration
-  // to ensure that setting it to 0 will notify observers
-  Services.prefs.setIntPref(PREF, 1000);
-  Services.prefs.setIntPref(PREF, 0);
-  return promise.then(
-    function onSuccess(x) {
-      Services.prefs.setIntPref(PREF, original);
-      return x;
-    },
-    function onError(x) {
-      Services.prefs.setIntPref(PREF, original);
-      throw x;
-    }
-  );
+  return SessionSaver.run();
 }
 
 function promiseSaveFileContents() {
   let promise = forceSaveState();
   return promise.then(function() {
     return OS.File.read(OS.Path.join(OS.Constants.Path.profileDir, "sessionstore.js"), { encoding: "utf-8" });
   });
 }
--- a/browser/devtools/scratchpad/scratchpad.js
+++ b/browser/devtools/scratchpad/scratchpad.js
@@ -21,16 +21,20 @@ const Ci = Components.interfaces;
 const SCRATCHPAD_CONTEXT_CONTENT = 1;
 const SCRATCHPAD_CONTEXT_BROWSER = 2;
 const BUTTON_POSITION_SAVE       = 0;
 const BUTTON_POSITION_CANCEL     = 1;
 const BUTTON_POSITION_DONT_SAVE  = 2;
 const BUTTON_POSITION_REVERT     = 0;
 const EVAL_FUNCTION_TIMEOUT      = 1000; // milliseconds
 
+const MAXIMUM_FONT_SIZE = 96;
+const MINIMUM_FONT_SIZE = 6;
+const NORMAL_FONT_SIZE = 12;
+
 const SCRATCHPAD_L10N = "chrome://browser/locale/devtools/scratchpad.properties";
 const DEVTOOLS_CHROME_ENABLED = "devtools.chrome.enabled";
 const PREF_RECENT_FILES_MAX = "devtools.scratchpad.recentFilesMax";
 const SHOW_TRAILING_SPACE = "devtools.scratchpad.showTrailingSpace";
 const ENABLE_CODE_FOLDING = "devtools.scratchpad.enableCodeFolding";
 
 const VARIABLES_VIEW_URL = "chrome://browser/content/devtools/widgets/VariablesView.xul";
 
@@ -207,17 +211,35 @@ var Scratchpad = {
       "sp-cmd-webConsole": () => {
         Scratchpad.openWebConsole();
       },
       "sp-cmd-documentationLink": () => {
         Scratchpad.openDocumentationPage();
       },
       "sp-cmd-hideSidebar": () => {
         Scratchpad.sidebar.hide();
-      }
+      },
+      "sp-cmd-line-numbers": () => {
+        Scratchpad.toggleEditorOption('lineNumbers');
+      },
+      "sp-cmd-wrap-text": () => {
+        Scratchpad.toggleEditorOption('lineWrapping');
+      },
+      "sp-cmd-highlight-trailing-space": () => {
+        Scratchpad.toggleEditorOption('showTrailingSpace');
+      },
+      "sp-cmd-larger-font": () => {
+        Scratchpad.increaseFontSize();
+      },
+      "sp-cmd-smaller-font": () => {
+        Scratchpad.decreaseFontSize();
+      },
+      "sp-cmd-normal-font": () => {
+        Scratchpad.normalFontSize();
+      },
     }
 
     for (let command in commands) {
       let elem = document.getElementById(command);
       if (elem) {
         elem.addEventListener("command", commands[command]);
       }
     }
@@ -1774,16 +1796,57 @@ var Scratchpad = {
       if (aCallback) {
         aCallback(shouldClose);
       }
     });
 
     return shouldClose;
   },
 
+  /**
+   * Toggle a editor's boolean option.
+   */
+  toggleEditorOption: function SP_toggleEditorOption(optionName)
+  {
+    let newOptionValue = !this.editor.getOption(optionName);
+    this.editor.setOption(optionName, newOptionValue);
+  },
+
+  /**
+   * Increase the editor's font size by 1 px.
+   */
+  increaseFontSize: function SP_increaseFontSize()
+  {
+    let size = this.editor.getFontSize();
+
+    if (size < MAXIMUM_FONT_SIZE) {
+      this.editor.setFontSize(size + 1);
+    }
+  },
+
+  /**
+   * Decrease the editor's font size by 1 px.
+   */
+  decreaseFontSize: function SP_decreaseFontSize()
+  {
+    let size = this.editor.getFontSize();
+
+    if (size > MINIMUM_FONT_SIZE) {
+      this.editor.setFontSize(size - 1);
+    }
+  },
+
+  /**
+   * Restore the editor's original font size.
+   */
+  normalFontSize: function SP_normalFontSize()
+  {
+    this.editor.setFontSize(NORMAL_FONT_SIZE);
+  },
+
   _observers: [],
 
   /**
    * Add an observer for Scratchpad events.
    *
    * The observer implements IScratchpadObserver := {
    *   onReady:      Called when the Scratchpad and its Editor are ready.
    *                 Arguments: (Scratchpad aScratchpad)
--- a/browser/devtools/scratchpad/scratchpad.xul
+++ b/browser/devtools/scratchpad/scratchpad.xul
@@ -42,16 +42,22 @@
 <commandset id="sp-commandset">
   <command id="sp-cmd-newWindow" oncommand=";"/>
   <command id="sp-cmd-openFile" oncommand=";"/>
   <command id="sp-cmd-clearRecentFiles" oncommand=";"/>
   <command id="sp-cmd-save" oncommand=";"/>
   <command id="sp-cmd-saveas" oncommand=";"/>
   <command id="sp-cmd-revert" oncommand=";" disabled="true"/>
   <command id="sp-cmd-close" oncommand=";"/>
+  <command id="sp-cmd-line-numbers" oncommand=";"/>
+  <command id="sp-cmd-wrap-text" oncommand=";"/>
+  <command id="sp-cmd-highlight-trailing-space" oncommand=";"/>
+  <command id="sp-cmd-larger-font" oncommand=";"/>
+  <command id="sp-cmd-smaller-font" oncommand=";"/>
+  <command id="sp-cmd-normal-font" oncommand=";"/>
   <command id="sp-cmd-run" oncommand=";"/>
   <command id="sp-cmd-inspect" oncommand=";"/>
   <command id="sp-cmd-display" oncommand=";"/>
   <command id="sp-cmd-pprint" oncommand=";"/>
   <command id="sp-cmd-contentContext" oncommand=";"/>
   <command id="sp-cmd-browserContext" oncommand=";" disabled="true"/>
   <command id="sp-cmd-reloadAndRun" oncommand=";"/>
   <command id="sp-cmd-evalFunction" oncommand=";"/>
@@ -75,16 +81,28 @@
   <key id="sp-key-save"
        key="&saveFileCmd.commandkey;"
        command="sp-cmd-save"
        modifiers="accel"/>
   <key id="sp-key-close"
        key="&closeCmd.key;"
        command="sp-cmd-close"
        modifiers="accel"/>
+  <key id="sp-key-larger-font"
+       key="&largerFont.commandkey;"
+       command="sp-cmd-larger-font"
+       modifiers="accel"/>
+  <key id="sp-key-smaller-font"
+       key="&smallerFont.commandkey;"
+       command="sp-cmd-smaller-font"
+       modifiers="accel"/>
+  <key id="sp-key-normal-size-font"
+       key="&normalSize.commandkey;"
+       command="sp-cmd-normal-font"
+       modifiers="accel"/>
   <key id="sp-key-run"
        key="&run.key;"
        command="sp-cmd-run"
        modifiers="accel"/>
   <key id="sp-key-inspect"
        key="&inspect.key;"
        command="sp-cmd-inspect"
        modifiers="accel"/>
@@ -161,16 +179,53 @@
       <menuitem id="sp-menu-close"
                 label="&closeCmd.label;"
                 key="sp-key-close"
                 accesskey="&closeCmd.accesskey;"
                 command="sp-cmd-close"/>
     </menupopup>
   </menu>
 
+  <menu id="sp-view-menu" label="&viewMenu.label;" accesskey="&viewMenu.accesskey;">
+    <menupopup id="sp-menu-viewpopup">
+      <menuitem id="sp-menu-line-numbers"
+                label="&lineNumbers.label;"
+                accesskey="&lineNumbers.accesskey;"
+                type="checkbox"
+                checked="true"
+                command="sp-cmd-line-numbers"/>
+      <menuitem id="sp-menu-word-wrap"
+                label="&wordWrap.label;"
+                accesskey="&wordWrap.accesskey;"
+                type="checkbox"
+                command="sp-cmd-wrap-text"/>
+      <menuitem id="sp-menu-highlight-trailing-space"
+                label="&highlightTrailingSpace.label;"
+                accesskey="&highlightTrailingSpace.accesskey;"
+                type="checkbox"
+                command="sp-cmd-highlight-trailing-space"/>
+      <menuseparator/>
+      <menuitem id="sp-menu-larger-font"
+                label="&largerFont.label;"
+                key="sp-key-larger-font"
+                accesskey="&largerFont.accesskey;"
+                command="sp-cmd-larger-font"/>
+      <menuitem id="sp-menu-smaller-font"
+                label="&smallerFont.label;"
+                key="sp-key-smaller-font"
+                accesskey="&smallerFont.accesskey;"
+                command="sp-cmd-smaller-font"/>
+      <menuitem id="sp-menu-normal-size-font"
+                label="&normalSize.label;"
+                key="sp-menu-normal-font"
+                accesskey="&normalSize.accesskey;"
+                command="sp-cmd-normal-font"/>
+    </menupopup>
+  </menu>
+
   <menu id="sp-edit-menu" label="&editMenu.label;"
         accesskey="&editMenu.accesskey;">
     <menupopup id="sp-menu_editpopup">
       <menuitem id="menu_undo"/>
       <menuitem id="menu_redo"/>
       <menuseparator/>
       <menuitem id="menu_cut"/>
       <menuitem id="menu_copy"/>
--- a/browser/devtools/scratchpad/test/browser_scratchpad_ui.js
+++ b/browser/devtools/scratchpad/test/browser_scratchpad_ui.js
@@ -24,20 +24,26 @@ function runTests()
   let methodsAndItems = {
     "sp-menu-newscratchpad": "openScratchpad",
     "sp-menu-open": "openFile",
     "sp-menu-save": "saveFile",
     "sp-menu-saveas": "saveFileAs",
     "sp-text-run": "run",
     "sp-text-inspect": "inspect",
     "sp-text-display": "display",
-    "sp-text-reloadAndRun" : "reloadAndRun",
+    "sp-text-reloadAndRun": "reloadAndRun",
     "sp-menu-content": "setContentContext",
     "sp-menu-browser": "setBrowserContext",
-    "sp-menu-pprint":"prettyPrint",
+    "sp-menu-pprint": "prettyPrint",
+    "sp-menu-line-numbers": "toggleEditorOption",
+    "sp-menu-word-wrap": "toggleEditorOption",
+    "sp-menu-highlight-trailing-space": "toggleEditorOption",
+    "sp-menu-larger-font": "increaseFontSize",
+    "sp-menu-smaller-font": "decreaseFontSize",
+    "sp-menu-normal-size-font": "normalFontSize",
   };
 
   let lastMethodCalled = null;
 
   for (let id in methodsAndItems) {
     lastMethodCalled = null;
 
     let methodName = methodsAndItems[id];
--- a/browser/locales/en-US/chrome/browser/devtools/scratchpad.dtd
+++ b/browser/locales/en-US/chrome/browser/devtools/scratchpad.dtd
@@ -45,16 +45,40 @@
 
 <!ENTITY saveFileAsCmd.label          "Save As…">
 <!ENTITY saveFileAsCmd.accesskey      "A">
 
 <!ENTITY closeCmd.label               "Close">
 <!ENTITY closeCmd.key                 "W">
 <!ENTITY closeCmd.accesskey           "C">
 
+<!ENTITY viewMenu.label               "View">
+<!ENTITY viewMenu.accesskey           "V">
+
+<!ENTITY lineNumbers.label             "Show Line Numbers">
+<!ENTITY lineNumbers.accesskey         "L">
+
+<!ENTITY wordWrap.label                "Wrap Text">
+<!ENTITY wordWrap.accesskey            "W">
+
+<!ENTITY highlightTrailingSpace.label     "Highlight Trailing Space">
+<!ENTITY highlightTrailingSpace.accesskey "H">
+
+<!ENTITY largerFont.label             "Larger Font">
+<!ENTITY largerFont.accesskey         "a">
+<!ENTITY largerFont.commandkey        "+">
+
+<!ENTITY smallerFont.label            "Smaller Font">
+<!ENTITY smallerFont.accesskey        "M">
+<!ENTITY smallerFont.commandkey       "-">
+
+<!ENTITY normalSize.label             "Normal Size">
+<!ENTITY normalSize.accesskey         "N">
+<!ENTITY normalSize.commandkey        "0">
+
 <!ENTITY editMenu.label               "Edit">
 <!ENTITY editMenu.accesskey           "E">
 
 <!ENTITY run.label                    "Run">
 <!ENTITY run.accesskey                "R">
 <!ENTITY run.key                      "r">
 
 <!ENTITY inspect.label                "Inspect">
--- a/browser/themes/linux/browser.css
+++ b/browser/themes/linux/browser.css
@@ -49,17 +49,17 @@
 #navigator-toolbox > toolbar:not(#toolbar-menubar):not(#TabsToolbar):not(#nav-bar) {
   padding-top: 1px;
   padding-bottom: 1px;
 }
 
 #nav-bar {
   background-image: linear-gradient(@toolbarHighlight@, rgba(255,255,255,0));
   box-shadow: 0 1px 0 @toolbarHighlight@ inset;
-  margin-top: -1px; /* Move up 1px into the TabsToolbar */
+  margin-top: -@tabToolbarNavbarOverlap@; /* Move up into the TabsToolbar */
   padding-top: 2px;
   padding-bottom: 2px;
   /* Position the toolbar above the bottom of background tabs */
   position: relative;
   z-index: 1;
 }
 
 #nav-bar-overflow-button {
@@ -1725,17 +1725,17 @@ richlistitem[type~="action"][actiontype=
 }
 
 /*
  * Draw the bottom border of the tabstrip:
  */
 #TabsToolbar::after {
   content: "";
   position: absolute;
-  bottom: 1px;
+  bottom: @tabToolbarNavbarOverlap@;
   left: 0;
   right: 0;
   z-index: 0;
   border-bottom: 1px solid hsla(0,0%,0%,.3);
 }
 
 #TabsToolbar:not(:-moz-lwtheme) {
   -moz-appearance: menubar;
--- a/browser/themes/osx/browser.css
+++ b/browser/themes/osx/browser.css
@@ -93,17 +93,17 @@ toolbarseparator {
   /* Move the noise texture out of the top 1px strip because that overlaps
      with the tabbar and we don't want to repaint it when animating tabs.
      The noise image is at least 100px high, so repeating it only horizontally
      is enough. */
   background-repeat: repeat-x, no-repeat;
   background-position: 0 1px, 0 0;
 
   box-shadow: inset 0 1px 0 hsla(0,0%,100%,.4);
-  margin-top: -1px;
+  margin-top: -@tabToolbarNavbarOverlap@;
   /* Position the toolbar above the bottom of background tabs */
   position: relative;
   z-index: 1;
 }
 
 @media (min-resolution: 2dppx) {
   #nav-bar {
     background-size: 100px 100px, auto;
@@ -1612,21 +1612,22 @@ toolbarbutton[sdk-button="true"][cui-are
 #zoom-in-button:-moz-locale-dir(ltr) {
   border-top-left-radius: 0;
   border-bottom-left-radius: 0;
 }
 
 #zoom-controls[cui-areatype="toolbar"]:not([overflowedItem=true]) > #zoom-reset-button {
   min-width: 0;
   margin: 0;
+  -moz-box-orient: horizontal;
+  -moz-box-align: center;
 }
 
 #zoom-controls[cui-areatype="toolbar"]:not([overflowedItem=true]) > #zoom-reset-button > .toolbarbutton-text {
-  padding-top: 4px;
-  margin: 2px;
+  margin-top: 0;
 }
 
 /* ----- FULLSCREEN WINDOW CONTROLS ----- */
 
 #minimize-button,
 #close-button,
 #fullscreen-button ~ #window-controls > #restore-button {
   display: none;
@@ -2795,17 +2796,17 @@ toolbarbutton.chevron > .toolbarbutton-m
   content: '';
   /* Because we use placeholders for window controls etc. in the tabstrip,
    * and position those with ordinal attributes, and because our layout code
    * expects :before/:after nodes to come first/last in the frame list,
    * we have to reorder this element to come last, hence the
    * ordinal group value (see bug 853415). */
   -moz-box-ordinal-group: 1001;
   position: absolute;
-  bottom: 1px;
+  bottom: @tabToolbarNavbarOverlap@;
   left: 0;
   right: 0;
   z-index: 0;
   border-bottom: 1px solid hsla(0,0%,0%,.3);
   visibility: hidden;
 }
 
 #main-window:-moz-any([privatebrowsingmode=temporary],[sizemode="fullscreen"],[customize-entered]) #TabsToolbar::after,
--- a/browser/themes/shared/browser.inc
+++ b/browser/themes/shared/browser.inc
@@ -6,8 +6,9 @@
 
 %ifdef XP_MACOSX
 % Prior to 10.7 there wasn't a native fullscreen button so we use #restore-button to exit fullscreen
 % and want it to behave like other toolbar buttons.
 %define primaryToolbarButtons @primaryToolbarButtons@, #restore-button
 %endif
 
 %define inAnyPanel :-moz-any(:not([cui-areatype="toolbar"]), [overflowedItem=true])
+%define tabToolbarNavbarOverlap 1px
--- a/browser/themes/shared/tabs.inc.css
+++ b/browser/themes/shared/tabs.inc.css
@@ -268,35 +268,34 @@
 /* Pinned tab separators need position: absolute when positioned (during overflow). */
 #tabbrowser-tabs[positionpinnedtabs] > .tabbrowser-tab[pinned]::before {
   height: 100%;
   position: absolute;
 }
 
 .tabbrowser-tab[pinned][titlechanged]:not([selected="true"]) > .tab-stack > .tab-content {
   background-image: radial-gradient(farthest-corner at center bottom, rgb(255,255,255) 3%, rgba(186,221,251,0.75) 20%, rgba(127,179,255,0.25) 40%, rgba(127,179,255,0) 70%);
-  background-position: center bottom 1px;
+  background-position: center bottom @tabToolbarNavbarOverlap@;
   background-repeat: no-repeat;
   background-size: 85% 100%;
 }
 
 /* Background tab separators (3px wide).
    Also show separators beside the selected tab when dragging it. */
 #tabbrowser-tabs[movingtab] > .tabbrowser-tab[beforeselected]:not([last-visible-tab])::after,
 .tabbrowser-tab:not([selected]):not([afterselected-visible]):not([afterhovered]):not([first-visible-tab]):not(:hover)::before,
 #tabbrowser-tabs:not([overflow]) > .tabbrowser-tab[last-visible-tab]:not([selected]):not([beforehovered]):not(:hover)::after {
   -moz-margin-start: -1.5px;
   -moz-margin-end: -1.5px;
   background-image: url(chrome://browser/skin/tabbrowser/tab-separator.png);
-  background-position: left bottom;
+  background-position: left bottom @tabToolbarNavbarOverlap@;
   background-repeat: no-repeat;
   background-size: 3px 100%;
   content: "";
   display: -moz-box;
-  margin-bottom: 1px;
   width: 3px;
 }
 
 /* New tab button */
 
 .tabs-newtab-button {
   width: 66px;
 }
--- a/browser/themes/windows/browser.css
+++ b/browser/themes/windows/browser.css
@@ -262,17 +262,17 @@
         rgb(214, 216, 190) 2px, rgb(214, 216, 190) 3px,
         transparent 3px);
   }
 }
 
 #nav-bar {
   background-image: linear-gradient(@toolbarHighlight@, rgba(255,255,255,0));
   box-shadow: 0 1px 0 @toolbarHighlight@ inset;
-  margin-top: -1px; /* Move up 1px into the TabsToolbar */
+  margin-top: -@tabToolbarNavbarOverlap@; /* Move up into the TabsToolbar */
   /* Position the toolbar above the bottom of background tabs */
   position: relative;
   z-index: 1;
 }
 
 #personal-bookmarks {
   min-height: 24px;
 }
--- a/content/media/MediaDecoderStateMachine.cpp
+++ b/content/media/MediaDecoderStateMachine.cpp
@@ -155,16 +155,17 @@ static int64_t DurationToUsecs(TimeDurat
   return static_cast<int64_t>(aDuration.ToSeconds() * USECS_PER_S);
 }
 
 MediaDecoderStateMachine::MediaDecoderStateMachine(MediaDecoder* aDecoder,
                                                    MediaDecoderReader* aReader,
                                                    bool aRealTime) :
   mDecoder(aDecoder),
   mState(DECODER_STATE_DECODING_METADATA),
+  mInRunningStateMachine(false),
   mSyncPointInMediaStream(-1),
   mSyncPointInDecodedStream(-1),
   mResetPlayStartTime(false),
   mPlayDuration(0),
   mStartTime(-1),
   mEndTime(-1),
   mFragmentEndTime(-1),
   mReader(aReader),
@@ -186,20 +187,17 @@ MediaDecoderStateMachine::MediaDecoderSt
   mTransportSeekable(true),
   mMediaSeekable(true),
   mPositionChangeQueued(false),
   mAudioCompleted(false),
   mGotDurationFromMetaData(false),
   mDispatchedEventToDecode(false),
   mStopAudioThread(true),
   mQuickBuffering(false),
-  mIsRunning(false),
-  mRunAgain(false),
   mMinimizePreroll(false),
-  mDispatchedRunEvent(false),
   mDecodeThreadWaiting(false),
   mRealTime(aRealTime),
   mLastFrameStatus(MediaDecoderOwner::NEXT_FRAME_UNINITIALIZED)
 {
   MOZ_COUNT_CTOR(MediaDecoderStateMachine);
   NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
 
   // Only enable realtime mode when "media.realtime_decoder.enabled" is true.
@@ -1031,16 +1029,22 @@ nsresult MediaDecoderStateMachine::Init(
 
   MediaDecoderReader* cloneReader = nullptr;
   if (aCloneDonor) {
     cloneReader = static_cast<MediaDecoderStateMachine*>(aCloneDonor)->mReader;
   }
 
   mStateMachineThreadPool = stateMachinePool;
 
+  nsresult rv;
+  mTimer = do_CreateInstance("@mozilla.org/timer;1", &rv);
+  NS_ENSURE_SUCCESS(rv, rv);
+  rv = mTimer->SetTarget(GetStateMachineThread());
+  NS_ENSURE_SUCCESS(rv, rv);
+
   return mReader->Init(cloneReader);
 }
 
 void MediaDecoderStateMachine::StopPlayback()
 {
   DECODER_LOG(PR_LOG_DEBUG, ("%p StopPlayback()", mDecoder.get()));
 
   AssertCurrentThreadInMonitor();
@@ -2661,76 +2665,46 @@ nsresult MediaDecoderStateMachine::GetBu
   MediaResource* resource = mDecoder->GetResource();
   NS_ENSURE_TRUE(resource, NS_ERROR_FAILURE);
   resource->Pin();
   nsresult res = mReader->GetBuffered(aBuffered, mStartTime);
   resource->Unpin();
   return res;
 }
 
-nsresult MediaDecoderStateMachine::Run()
-{
-  ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
-  NS_ASSERTION(OnStateMachineThread(), "Should be on state machine thread.");
-
-  return CallRunStateMachine();
-}
-
 nsresult MediaDecoderStateMachine::CallRunStateMachine()
 {
   AssertCurrentThreadInMonitor();
   NS_ASSERTION(OnStateMachineThread(), "Should be on state machine thread.");
-  // This will be set to true by ScheduleStateMachine() if it's called
-  // while we're in RunStateMachine().
-  mRunAgain = false;
-
-  // Set to true whenever we dispatch an event to run this state machine.
-  // This flag prevents us from dispatching
-  mDispatchedRunEvent = false;
 
   // If audio is being captured, stop the audio thread if it's running
   if (mAudioCaptured) {
     StopAudioThread();
   }
 
+  MOZ_ASSERT(!mInRunningStateMachine, "State machine cycles must run in sequence!");
   mTimeout = TimeStamp();
-
-  mIsRunning = true;
+  mInRunningStateMachine = true;
   nsresult res = RunStateMachine();
-  mIsRunning = false;
-
-  if (mRunAgain && !mDispatchedRunEvent) {
-    mDispatchedRunEvent = true;
-    return GetStateMachineThread()->Dispatch(this, NS_DISPATCH_NORMAL);
-  }
-
+  mInRunningStateMachine = false;
   return res;
 }
 
 static void TimeoutExpired(nsITimer *aTimer, void *aClosure) {
   MediaDecoderStateMachine *machine =
     static_cast<MediaDecoderStateMachine*>(aClosure);
   NS_ASSERTION(machine, "Must have been passed state machine");
   machine->TimeoutExpired();
 }
 
 void MediaDecoderStateMachine::TimeoutExpired()
 {
   ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
   NS_ASSERTION(OnStateMachineThread(), "Must be on state machine thread");
-  if (mIsRunning) {
-    mRunAgain = true;
-  } else if (!mDispatchedRunEvent) {
-    // We don't have an event dispatched to run the state machine, so we
-    // can just run it from here.
-    CallRunStateMachine();
-  }
-  // Otherwise, an event has already been dispatched to run the state machine
-  // as soon as possible. Nothing else needed to do, the state machine is
-  // going to run anyway.
+  CallRunStateMachine();
 }
 
 void MediaDecoderStateMachine::ScheduleStateMachineWithLockAndWakeDecoder() {
   ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
   DispatchAudioDecodeTaskIfNeeded();
   DispatchVideoDecodeTaskIfNeeded();
 }
 
@@ -2740,70 +2714,35 @@ nsresult MediaDecoderStateMachine::Sched
     "Must have a state machine thread to schedule");
 
   if (mState == DECODER_STATE_SHUTDOWN) {
     return NS_ERROR_FAILURE;
   }
   aUsecs = std::max<int64_t>(aUsecs, 0);
 
   TimeStamp timeout = TimeStamp::Now() + UsecsToDuration(aUsecs);
-  if (!mTimeout.IsNull()) {
-    if (timeout >= mTimeout) {
-      // We've already scheduled a timer set to expire at or before this time,
-      // or have an event dispatched to run the state machine.
-      return NS_OK;
-    }
-    if (mTimer) {
-      // We've been asked to schedule a timer to run before an existing timer.
-      // Cancel the existing timer.
-      mTimer->Cancel();
-    }
+  if (!mTimeout.IsNull() && timeout >= mTimeout) {
+    // We've already scheduled a timer set to expire at or before this time,
+    // or have an event dispatched to run the state machine.
+    return NS_OK;
   }
 
   uint32_t ms = static_cast<uint32_t>((aUsecs / USECS_PER_MS) & 0xFFFFFFFF);
-  if (mRealTime && ms > 40)
+  if (mRealTime && ms > 40) {
     ms = 40;
-  if (ms == 0) {
-    if (mIsRunning) {
-      // We're currently running this state machine on the state machine
-      // thread. Signal it to run again once it finishes its current cycle.
-      mRunAgain = true;
-      return NS_OK;
-    } else if (!mDispatchedRunEvent) {
-      // We're not currently running this state machine on the state machine
-      // thread. Dispatch an event to run one cycle of the state machine.
-      mDispatchedRunEvent = true;
-      return GetStateMachineThread()->Dispatch(this, NS_DISPATCH_NORMAL);
-    }
-    // We're not currently running this state machine on the state machine
-    // thread, but something has already dispatched an event to run it again,
-    // so just exit; it's going to run real soon.
-    return NS_OK;
   }
-
-  // Since there is already a pending task that will run immediately,
-  // we don't need to schedule a timer task.
-  if (mRunAgain) {
-    return NS_OK;
-  }
-
   mTimeout = timeout;
-
-  nsresult res;
-  if (!mTimer) {
-    mTimer = do_CreateInstance("@mozilla.org/timer;1", &res);
-    if (NS_FAILED(res)) return res;
-    mTimer->SetTarget(GetStateMachineThread());
-  }
-
-  res = mTimer->InitWithFuncCallback(mozilla::TimeoutExpired,
-                                     this,
-                                     ms,
-                                     nsITimer::TYPE_ONE_SHOT);
-  return res;
+  // Cancel existing timer if any since we are going to schedule a new one.
+  mTimer->Cancel();
+  nsresult rv = mTimer->InitWithFuncCallback(mozilla::TimeoutExpired,
+                                             this,
+                                             ms,
+                                             nsITimer::TYPE_ONE_SHOT);
+  NS_ENSURE_SUCCESS(rv, rv);
+  return NS_OK;
 }
 
 bool MediaDecoderStateMachine::OnDecodeThread() const
 {
   return mDecodeTaskQueue->IsCurrentThreadIn();
 }
 
 bool MediaDecoderStateMachine::OnStateMachineThread() const
--- a/content/media/MediaDecoderStateMachine.h
+++ b/content/media/MediaDecoderStateMachine.h
@@ -107,18 +107,19 @@ class SharedThreadPool;
 
   All internal state is synchronised via the decoder monitor. State changes
   are either propagated by NotifyAll on the monitor (typically when state
   changes need to be propagated to non-state machine threads) or by scheduling
   the state machine to run another cycle on the shared state machine thread.
 
   See MediaDecoder.h for more details.
 */
-class MediaDecoderStateMachine : public nsRunnable
+class MediaDecoderStateMachine
 {
+  NS_INLINE_DECL_THREADSAFE_REFCOUNTING(MediaDecoderStateMachine)
 public:
   typedef MediaDecoder::DecodedStreamData DecodedStreamData;
   MediaDecoderStateMachine(MediaDecoder* aDecoder,
                                MediaDecoderReader* aReader,
                                bool aRealTime = false);
   ~MediaDecoderStateMachine();
 
   nsresult Init(MediaDecoderStateMachine* aCloneDonor);
@@ -221,19 +222,16 @@ public:
   void UpdatePlaybackPosition(int64_t aTime);
 
   // Causes the state machine to switch to buffering state, and to
   // immediately stop playback and buffer downloaded data. Must be called
   // with the decode monitor held. Called on the state machine thread and
   // the main thread.
   void StartBuffering();
 
-  // State machine thread run function. Defers to RunStateMachine().
-  NS_IMETHOD Run() MOZ_OVERRIDE;
-
   // This is called on the state machine thread and audio thread.
   // The decoder monitor must be obtained before calling this.
   bool HasAudio() const {
     AssertCurrentThreadInMonitor();
     return mInfo.HasAudio();
   }
 
   // This is called on the state machine thread and audio thread.
@@ -631,17 +629,17 @@ private:
 
   // Performs one "cycle" of the state machine. Polls the state, and may send
   // a video frame to be displayed, and generally manages the decode. Called
   // periodically via timer to ensure the video stays in sync.
   nsresult RunStateMachine();
 
   bool IsStateMachineScheduled() const {
     AssertCurrentThreadInMonitor();
-    return !mTimeout.IsNull() || mRunAgain;
+    return !mTimeout.IsNull();
   }
 
   // Returns true if we're not playing and the decode thread has filled its
   // decode buffers and is waiting. We can shut the decode thread down in this
   // case as it may not be needed again.
   bool IsPausedAndDecoderWaiting();
 
   // The decoder object that created this state machine. The state machine
@@ -667,25 +665,27 @@ private:
 
   // The task queue in which we run decode tasks. This is referred to as
   // the "decode thread", though in practise tasks can run on a different
   // thread every time they're called.
   RefPtr<MediaTaskQueue> mDecodeTaskQueue;
 
   RefPtr<SharedThreadPool> mStateMachineThreadPool;
 
-  // Timer to call the state machine Run() method. Used by
+  // Timer to run the state machine cycles. Used by
   // ScheduleStateMachine(). Access protected by decoder monitor.
   nsCOMPtr<nsITimer> mTimer;
 
-  // Timestamp at which the next state machine Run() method will be called.
-  // If this is non-null, a call to Run() is scheduled, either by a timer,
-  // or via an event. Access protected by decoder monitor.
+  // Timestamp at which the next state machine cycle will run.
+  // Access protected by decoder monitor.
   TimeStamp mTimeout;
 
+  // Used to check if there are state machine cycles are running in sequence.
+  DebugOnly<bool> mInRunningStateMachine;
+
   // The time that playback started from the system clock. This is used for
   // timing the presentation of video frames when there's no audio.
   // Accessed only via the state machine thread.
   TimeStamp mPlayStartTime;
 
   // When we start writing decoded data to a new DecodedDataStream, or we
   // restart writing due to PlaybackStarted(), we record where we are in the
   // MediaStream and what that corresponds to in the media.
@@ -905,43 +905,28 @@ private:
 
   // If this is true while we're in buffering mode, we can exit early,
   // as it's likely we may be able to playback. This happens when we enter
   // buffering mode soon after the decode starts, because the decode-ahead
   // ran fast enough to exhaust all data while the download is starting up.
   // Synchronised via decoder monitor.
   bool mQuickBuffering;
 
-  // True if the shared state machine thread is currently running this
-  // state machine.
-  bool mIsRunning;
-
-  // True if we should run the state machine again once the current
-  // state machine run has finished.
-  bool mRunAgain;
-
   // True if we should not decode/preroll unnecessary samples, unless we're
   // played. "Prerolling" in this context refers to when we decode and
   // buffer decoded samples in advance of when they're needed for playback.
   // This flag is set for preload=metadata media, and means we won't
   // decode more than the first video frame and first block of audio samples
   // for that media when we startup, or after a seek. When Play() is called,
   // we reset this flag, as we assume the user is playing the media, so
   // prerolling is appropriate then. This flag is used to reduce the overhead
   // of prerolling samples for media elements that may not play, both
   // memory and CPU overhead.
   bool mMinimizePreroll;
 
-  // True if we've dispatched an event to run the state machine. It's
-  // imperative that we don't dispatch multiple events to run the state
-  // machine at the same time, as our code assume all events are synchronous.
-  // If we dispatch multiple events, the second event can run while the
-  // first is shutting down a thread, causing inconsistent state.
-  bool mDispatchedRunEvent;
-
   // True if the decode thread has gone filled its buffers and is now
   // waiting to be awakened before it continues decoding. Synchronized
   // by the decoder monitor.
   bool mDecodeThreadWaiting;
 
   // True is we are decoding a realtime stream, like a camera stream
   bool mRealTime;
 
--- a/dom/bluetooth/tests/marionette/head.js
+++ b/dom/bluetooth/tests/marionette/head.js
@@ -30,16 +30,19 @@ const EMULATOR_NAME = "Full Android on E
 const EMULATOR_CLASS = 0x58020c;
 
 // Use same definition in QEMU for special bluetooth address,
 // which were defined at external/qemu/hw/bt.h:
 const BDADDR_ANY   = "00:00:00:00:00:00";
 const BDADDR_ALL   = "ff:ff:ff:ff:ff:ff";
 const BDADDR_LOCAL = "ff:ff:ff:00:00:00";
 
+// A user friendly name for remote BT device.
+const REMOTE_DEVICE_NAME = "Remote BT Device";
+
 let Promise =
   SpecialPowers.Cu.import("resource://gre/modules/Promise.jsm").Promise;
 
 let bluetoothManager;
 
 let pendingEmulatorCmdCount = 0;
 
 /**
@@ -73,16 +76,80 @@ function runEmulatorCmdSafe(aCommand) {
       deferred.reject(aResult);
     }
   });
 
   return deferred.promise;
 }
 
 /**
+ * Add a Bluetooth remote device to scatternet and set its properties.
+ *
+ * Use QEMU command 'bt remote add' to add a virtual Bluetooth remote
+ * and set its properties by setEmulatorDeviceProperty().
+ *
+ * Fulfill params:
+ *   result -- bluetooth address of the remote device.
+ * Reject params: (none)
+ *
+ * @param aProperies
+ *        A javascript object with zero or several properties for initializing
+ *        the remote device. By now, the properies could be 'name' or
+ *        'discoverable'. It valid to put a null object or a javascript object
+ *        which don't have any properies.
+ *
+ * @return A promise object.
+ */
+function addEmulatorRemoteDevice(aProperties) {
+  let address;
+  let promise = runEmulatorCmdSafe("bt remote add")
+    .then(function(aResults) {
+      address = aResults[0].toUpperCase();
+    });
+
+  for (let key in aProperties) {
+    let value = aProperties[key];
+    let propertyName = key;
+    promise = promise.then(function() {
+      return setEmulatorDeviceProperty(address, propertyName, value);
+    });
+  }
+
+  return promise.then(function() {
+    return address;
+  });
+}
+
+/**
+ * Remove Bluetooth remote devices in scatternet.
+ *
+ * Use QEMU command 'bt remote remove <addr>' to remove a specific virtual
+ * Bluetooth remote device in scatternet or remove them all by  QEMU command
+ * 'bt remote remove BDADDR_ALL'.
+ *
+ * @param aAddress
+ *        The string of Bluetooth address with format xx:xx:xx:xx:xx:xx.
+ *
+ * Fulfill params:
+ *   result -- an array of emulator response lines.
+ * Reject params: (none)
+ *
+ * @return A promise object.
+ */
+function removeEmulatorRemoteDevice(aAddress) {
+  let cmd = "bt remote remove " + aAddress;
+  return runEmulatorCmdSafe(cmd)
+    .then(function(aResults) {
+      // 'bt remote remove <bd_addr>' returns a list of removed device one at a line.
+      // The last item is "OK".
+      return aResults.slice(0, -1);
+    });
+}
+
+/**
  * Set a property for a Bluetooth device.
  *
  * Use QEMU command 'bt property <bd_addr> <prop_name> <value>' to set property.
  *
  * Fulfill params:
  *   result -- an array of emulator response lines.
  * Reject params:
  *   result -- an array of emulator response lines.
@@ -122,16 +189,81 @@ function getEmulatorDeviceProperty(aAddr
   let cmd = "bt property " + aAddress + " " + aPropertyName;
   return runEmulatorCmdSafe(cmd)
     .then(function(aResults) {
       return aResults[0];
     });
 }
 
 /**
+ * Start dicovering Bluetooth devices.
+ *
+ * Allows the device's adapter to start seeking for remote devices.
+ *
+ * Fulfill params: (none)
+ * Reject params: a DOMError
+ *
+ * @param aAdapter
+ *        A BluetoothAdapter which is used to interact with local BT dev
+ *
+ * @return A deferred promise.
+ */
+function startDiscovery(aAdapter) {
+  let deferred = Promise.defer();
+
+  let request = aAdapter.startDiscovery();
+  request.onsuccess = function () {
+    log("  Start discovery - Success");
+    // TODO (bug 892207): Make Bluetooth APIs available for 3rd party apps.
+    //     Currently, discovering state wouldn't change immediately here.
+    //     We would turn on this check when the redesigned API are landed.
+    // is(aAdapter.discovering, true, "BluetoothAdapter.discovering");
+    deferred.resolve();
+  }
+  request.onerror = function (aEvent) {
+    ok(false, "Start discovery - Fail");
+    deferred.reject(aEvent.target.error);
+  }
+
+  return deferred.promise;
+}
+
+/**
+ * Stop dicovering Bluetooth devices.
+ *
+ * Allows the device's adapter to stop seeking for remote devices.
+ *
+ * Fulfill params: (none)
+ * Reject params: a DOMError
+ *
+ * @param aAdapter
+ *        A BluetoothAdapter which is used to interact with local BT device.
+ *
+ * @return A deferred promise.
+ */
+function stopDiscovery(aAdapter) {
+  let deferred = Promise.defer();
+
+  let request = aAdapter.stopDiscovery();
+  request.onsuccess = function () {
+    log("  Stop discovery - Success");
+    // TODO (bug 892207): Make Bluetooth APIs available for 3rd party apps.
+    //     Currently, discovering state wouldn't change immediately here.
+    //     We would turn on this check when the redesigned API are landed.
+    // is(aAdapter.discovering, false, "BluetoothAdapter.discovering");
+    deferred.resolve();
+  }
+  request.onerror = function (aEvent) {
+    ok(false, "Stop discovery - Fail");
+    deferred.reject(aEvent.target.error);
+  }
+  return deferred.promise;
+}
+
+/**
  * Get mozSettings value specified by @aKey.
  *
  * Resolve if that mozSettings value is retrieved successfully, reject
  * otherwise.
  *
  * Fulfill params:
  *   The corresponding mozSettings value of the key.
  * Reject params: (none)
--- a/dom/bluetooth/tests/marionette/manifest.ini
+++ b/dom/bluetooth/tests/marionette/manifest.ini
@@ -2,8 +2,9 @@
 b2g = true
 browser = false
 qemu = true
 
 [test_dom_BluetoothManager_enabled.js]
 [test_dom_BluetoothManager_adapteradded.js]
 [test_dom_BluetoothAdapter_setters.js]
 [test_dom_BluetoothAdapter_getters.js]
+[test_dom_BluetoothAdapter_discovery.js]
new file mode 100644
--- /dev/null
+++ b/dom/bluetooth/tests/marionette/test_dom_BluetoothAdapter_discovery.js
@@ -0,0 +1,47 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ * vim: sw=2 ts=2 sts=2 et filetype=javascript
+ * 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/. */
+
+///////////////////////////////////////////////////////////////////////////////
+// Test Purpose:
+//   To verify that discovery process of BluetoothAdapter is correct.
+//   Use B2G emulator commands to add/remote remote devices to simulate
+//   discovering behavior.
+//
+// Test Coverage:
+//   - BluetoothAdapter.startDiscovery()
+//   - BluetoothAdapter.stopDiscovery()
+//   - BluetoothAdapter.ondevicefound()
+//   - BluetoothAdapter.discovering [Temporarily turned off until BT API update]
+//
+///////////////////////////////////////////////////////////////////////////////
+
+MARIONETTE_TIMEOUT = 60000;
+MARIONETTE_HEAD_JS = 'head.js';
+
+startBluetoothTest(true, function testCaseMain(aAdapter) {
+  log("Testing the discovery process of BluetoothAdapter ...");
+
+  // The properties of remote device.
+  let theProperties = {
+    "name": REMOTE_DEVICE_NAME,
+    "discoverable": true
+  };
+
+  return Promise.resolve()
+    .then(() => removeEmulatorRemoteDevice(BDADDR_ALL))
+    .then(() => addEmulatorRemoteDevice(/*theProperties*/ null))
+    .then(function(aRemoteAddress) {
+      let promises = [];
+      promises.push(waitForAdapterEvent(aAdapter, "devicefound"));
+      promises.push(startDiscovery(aAdapter));
+      return Promise.all(promises)
+        .then(function(aResults) {
+          is(aResults[0].device.address, aRemoteAddress, "BluetoothDevice.address");
+        });
+    })
+    .then(() => stopDiscovery(aAdapter))
+    .then(() => removeEmulatorRemoteDevice(BDADDR_ALL));
+});
--- a/dom/browser-element/BrowserElementChild.js
+++ b/dom/browser-element/BrowserElementChild.js
@@ -10,22 +10,16 @@ Cu.import("resource://gre/modules/Servic
 function debug(msg) {
   //dump("BrowserElementChild - " + msg + "\n");
 }
 
 // NB: this must happen before we process any messages from
 // mozbrowser API clients.
 docShell.isActive = true;
 
-let infos = sendSyncMessage('browser-element-api:call',
-                            { 'msg_name': 'hello' })[0];
-docShell.QueryInterface(Ci.nsIDocShellTreeItem).name = infos.name;
-docShell.setFullscreenAllowed(infos.fullscreenAllowed);
-
-
 function parentDocShell(docshell) {
   if (!docshell) {
     return null;
   }
   let treeitem = docshell.QueryInterface(Ci.nsIDocShellTreeItem);
   return treeitem.parent ? treeitem.parent.QueryInterface(Ci.nsIDocShell) : null;
 }
 
@@ -52,8 +46,13 @@ if (!('BrowserElementIsPreloaded' in thi
   ContentPanning.init();
 
   Services.scriptloader.loadSubScript("chrome://global/content/BrowserElementChildPreload.js");
 } else {
   ContentPanning.init();
 }
 
 var BrowserElementIsReady = true;
+
+let infos = sendSyncMessage('browser-element-api:call',
+                            { 'msg_name': 'hello' })[0];
+docShell.QueryInterface(Ci.nsIDocShellTreeItem).name = infos.name;
+docShell.setFullscreenAllowed(infos.fullscreenAllowed);
--- a/dom/browser-element/BrowserElementParent.jsm
+++ b/dom/browser-element/BrowserElementParent.jsm
@@ -361,33 +361,35 @@ BrowserElementParent.prototype = {
       data.msg_name = msg;
       this._mm.sendAsyncMessage('browser-element-api:call', data);
     } catch (e) {
       return false;
     }
     return true;
   },
 
-  _recvHello: function(data) {
+  _recvHello: function() {
     debug("recvHello");
 
+    this._ready = true;
+
     // Inform our child if our owner element's document is invisible.  Note
     // that we must do so here, rather than in the BrowserElementParent
     // constructor, because the BrowserElementChild may not be initialized when
     // we run our constructor.
     if (this._window.document.hidden) {
       this._ownerVisibilityChange();
     }
 
     return {
       name: this._frameElement.getAttribute('name'),
       fullscreenAllowed:
         this._frameElement.hasAttribute('allowfullscreen') ||
         this._frameElement.hasAttribute('mozallowfullscreen')
-    }
+    };
   },
 
   _fireCtxMenuEvent: function(data) {
     let detail = data.json;
     let evtName = detail.msg_name;
 
     debug('fireCtxMenuEventFromMsg: ' + evtName + ' ' + detail);
     let evt = this._createEvent(evtName, detail, /* cancellable */ true);
@@ -719,25 +721,41 @@ BrowserElementParent.prototype = {
       if (Cu.isDeadWrapper(activeInputFrame)) {
         // If the activeInputFrame is already a dead object,
         // we should simply set it to null directly.
         activeInputFrame = null;
         this._sendSetInputMethodActiveDOMRequest(req, isActive);
       } else {
         let reqOld = XPCNativeWrapper.unwrap(activeInputFrame)
                                      .setInputMethodActive(false);
-        reqOld.onsuccess = function() {
-          activeInputFrame = null;
-          this._sendSetInputMethodActiveDOMRequest(req, isActive);
+
+        // We wan't to continue regardless whether this req succeeded
+        reqOld.onsuccess = reqOld.onerror = function() {
+          let setActive = function() {
+            activeInputFrame = null;
+            this._sendSetInputMethodActiveDOMRequest(req, isActive);
+          }.bind(this);
+
+          if (this._ready) {
+            setActive();
+            return;
+          }
+
+          // Wait for the hello event from BrowserElementChild
+          let onReady = function(aMsg) {
+            if (this._isAlive() && (aMsg.data.msg_name === 'hello')) {
+              setActive();
+
+              this._mm.removeMessageListener('browser-element-api:call',
+                onReady);
+            }
+          }.bind(this);
+
+          this._mm.addMessageListener('browser-element-api:call', onReady);
         }.bind(this);
-        reqOld.onerror = function() {
-          Services.DOMRequest.fireErrorAsync(req,
-            'Failed to deactivate the old input method: ' +
-            reqOld.error + '.');
-        };
       }
     } else {
       this._sendSetInputMethodActiveDOMRequest(req, isActive);
     }
     return req;
   },
 
   _sendSetInputMethodActiveDOMRequest: function(req, isActive) {
--- a/dom/mobileconnection/tests/marionette/test_mobile_preferred_network_type.js
+++ b/dom/mobileconnection/tests/marionette/test_mobile_preferred_network_type.js
@@ -45,27 +45,42 @@ function doFailToSetPreferredNetworkType
   };
 
   request.onerror = function() {
     is(request.error.name, expectedError, "Check error message.");
     callback();
   };
 }
 
+function getSupportedNetworkTypesFromSystemProperties(clientId, callback) {
+  let key = "ro.moz.ril." + clientId + ".network_types";
+
+  runEmulatorShell(["getprop", key], function(results) {
+    let result = results[0];
+    if (!result || result === "") {
+      // Copied from GECKO_SUPPORTED_NETWORK_TYPES_DEFAULT in dom/system/gonk/ril_consts.js.
+      result = "wcdma,gsm";
+    }
+    callback(result.split(","));
+  });
+}
+
 /* Test supportedNetworkTypes */
 taskHelper.push(function testSupportedNetworkTypes() {
   let supportedNetworkTypes = mobileConnection.supportedNetworkTypes;
+  ok(Array.isArray(supportedNetworkTypes), "supportedNetworkTypes should be an array");
 
-  ok(Array.isArray(supportedNetworkTypes), "supportedNetworkTypes should be an array");
-  ok(supportedNetworkTypes.indexOf("gsm") >= 0, "Should support 'gsm'");
-  ok(supportedNetworkTypes.indexOf("wcdma") >= 0, "Should support 'wcdma'");
-  ok(supportedNetworkTypes.indexOf("cdma") >= 0, "Should support 'cdma'");
-  ok(supportedNetworkTypes.indexOf("evdo") >= 0, "Should support 'evdo'");
+  getSupportedNetworkTypesFromSystemProperties(0, function(testData) {
+    is(testData.length, supportedNetworkTypes.length);
+    for (let i = 0; i < testData.length; i++) {
+      ok(supportedNetworkTypes.indexOf(testData[i]) >= 0, "Should support '" + testData[i] + "'");
+    }
 
-  taskHelper.runNext();
+    taskHelper.runNext();
+  });
 });
 
 /* Test switching to supported preferred types */
 taskHelper.push(function testPreferredNetworkTypes() {
   let supportedTypes = [
     'gsm',
     'wcdma',
     'wcdma/gsm-auto',
--- a/dom/system/gonk/ril_consts.js
+++ b/dom/system/gonk/ril_consts.js
@@ -425,17 +425,17 @@ this.RIL_PREFERRED_NETWORK_TYPE_TO_GECKO
   GECKO_PREFERRED_NETWORK_TYPE_EVDO_ONLY,
   GECKO_PREFERRED_NETWORK_TYPE_WCDMA_GSM_CDMA_EVDO,
   GECKO_PREFERRED_NETWORK_TYPE_LTE_CDMA_EVDO,
   GECKO_PREFERRED_NETWORK_TYPE_LTE_WCDMA_GSM,
   GECKO_PREFERRED_NETWORK_TYPE_LTE_WCDMA_GSM_CDMA_EVDO,
   GECKO_PREFERRED_NETWORK_TYPE_LTE_ONLY
 ];
 
-this.GECKO_SUPPORTED_NETWORK_TYPES_DEFAULT = "gsm,wcdma,cdma,evdo";
+this.GECKO_SUPPORTED_NETWORK_TYPES_DEFAULT = "gsm,wcdma";
 this.GECKO_SUPPORTED_NETWORK_TYPES = [
   "gsm",
   "wcdma",
   "cdma",
   "evdo",
   "lte"
 ];
 
--- a/mobile/android/base/GeckoSharedPrefs.java
+++ b/mobile/android/base/GeckoSharedPrefs.java
@@ -6,16 +6,17 @@ package org.mozilla.gecko;
 
 import org.mozilla.gecko.mozglue.RobocopTarget;
 import org.mozilla.gecko.util.ThreadUtils;
 
 import android.content.Context;
 import android.content.SharedPreferences;
 import android.content.SharedPreferences.Editor;
 import android.os.Build;
+import android.os.StrictMode;
 import android.preference.PreferenceManager;
 import android.util.Log;
 
 import java.util.Arrays;
 import java.util.EnumSet;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
@@ -146,40 +147,30 @@ public final class GeckoSharedPrefs {
      * exceptions from reading/writing in the UI thread. This method will block
      * the current thread until the migration is finished.
      */
     private static synchronized void migrateIfNecessary(final Context context) {
         if (migrationDone) {
             return;
         }
 
-        if (ThreadUtils.isOnBackgroundThread()) {
-            Log.d(LOGTAG, "Already in background thread, migrating directly");
+        // We deliberatly perform the migration in the current thread (which
+        // is likely the UI thread) as this is actually cheaper than enforcing a
+        // context switch to another thread (see bug 940575).
+        if (Build.VERSION.SDK_INT < 9) {
             performMigration(context);
         } else {
-            Log.d(LOGTAG, "Not in background thread, migrating with lock");
-
-            final Object migrationLock = new Object();
-
-            ThreadUtils.getBackgroundHandler().post(new Runnable() {
-                @Override
-                public void run() {
-                    synchronized(migrationLock) {
-                        performMigration(context);
-                        migrationLock.notifyAll();
-                    }
-                }
-            });
+            // Avoid strict mode warnings.
+            final StrictMode.ThreadPolicy savedPolicy = StrictMode.allowThreadDiskReads();
+            StrictMode.allowThreadDiskWrites();
 
             try {
-                synchronized(migrationLock) {
-                    migrationLock.wait(MIGRATION_COMMIT_TIMEOUT_MSEC);
-                }
-            } catch (InterruptedException e) {
-                throw new IllegalStateException("Failed to commit migration before timeout");
+                performMigration(context);
+            } finally {
+                StrictMode.setThreadPolicy(savedPolicy);
             }
         }
 
         migrationDone = true;
     }
 
     private static void performMigration(Context context) {
         final SharedPreferences appPrefs = forApp(context, disableMigrations);
--- a/mobile/android/base/home/BrowserSearch.java
+++ b/mobile/android/base/home/BrowserSearch.java
@@ -78,17 +78,17 @@ public class BrowserSearch extends HomeF
     // The maximum number of rows deep in a search we'll dig
     // for an autocomplete result
     private static final int MAX_AUTOCOMPLETE_SEARCH = 20;
 
     // Duration for fade-in animation
     private static final int ANIMATION_DURATION = 250;
 
     // Holds the current search term to use in the query
-    private String mSearchTerm;
+    private volatile String mSearchTerm;
 
     // Adapter for the list of search results
     private SearchAdapter mAdapter;
 
     // The view shown by the fragment
     private LinearLayout mView;
 
     // The list showing search results
@@ -684,36 +684,49 @@ public class BrowserSearch extends HomeF
     private void registerEventListener(String eventName) {
         GeckoAppShell.registerEventListener(eventName, this);
     }
 
     private void unregisterEventListener(String eventName) {
         GeckoAppShell.unregisterEventListener(eventName, this);
     }
 
+    private void restartSearchLoader() {
+        SearchLoader.restart(getLoaderManager(), LOADER_ID_SEARCH, mCursorLoaderCallbacks, mSearchTerm);
+    }
+
+    private void initSearchLoader() {
+        SearchLoader.init(getLoaderManager(), LOADER_ID_SEARCH, mCursorLoaderCallbacks, mSearchTerm);
+    }
+
     public void filter(String searchTerm, AutocompleteHandler handler) {
         if (TextUtils.isEmpty(searchTerm)) {
             return;
         }
 
-        if (TextUtils.equals(mSearchTerm, searchTerm)) {
-            return;
-        }
+        final boolean isNewFilter = !TextUtils.equals(mSearchTerm, searchTerm);
 
         mSearchTerm = searchTerm;
         mAutocompleteHandler = handler;
 
         if (isVisible()) {
-            // The adapter depends on the search term to determine its number
-            // of items. Make it we notify the view about it.
-            mAdapter.notifyDataSetChanged();
+            if (isNewFilter) {
+                // The adapter depends on the search term to determine its number
+                // of items. Make it we notify the view about it.
+                mAdapter.notifyDataSetChanged();
 
-            // Restart loaders with the new search term
-            SearchLoader.restart(getLoaderManager(), LOADER_ID_SEARCH, mCursorLoaderCallbacks, mSearchTerm);
-            filterSuggestions();
+                // Restart loaders with the new search term
+                restartSearchLoader();
+                filterSuggestions();
+            } else {
+                // The search term hasn't changed, simply reuse any existing
+                // loader for the current search term. This will ensure autocompletion
+                // is consistently triggered (see bug 933739).
+                initSearchLoader();
+            }
         }
     }
 
     private static class SuggestionAsyncLoader extends AsyncTaskLoader<ArrayList<String>> {
         private final SuggestClient mSuggestClient;
         private final String mSearchTerm;
         private ArrayList<String> mSuggestions;
 
--- a/toolkit/components/osfile/modules/osfile_async_front.jsm
+++ b/toolkit/components/osfile/modules/osfile_async_front.jsm
@@ -232,29 +232,123 @@ let Scheduler = {
     messagesReceived: 0,
   },
 
   /**
    * A timer used to automatically shut down the worker after some time.
    */
   resetTimer: null,
 
+  /**
+   * Prepare to kill the OS.File worker after a few seconds.
+   */
   restartTimer: function(arg) {
     let delay;
     try {
       delay = Services.prefs.getIntPref("osfile.reset_worker_delay");
     } catch(e) {
       // Don't auto-shutdown if we don't have a delay preference set.
       return;
     }
 
     if (this.resetTimer) {
       clearTimeout(this.resetTimer);
     }
-    this.resetTimer = setTimeout(File.resetWorker, delay);
+    this.resetTimer = setTimeout(
+      () => Scheduler.kill({reset: true, shutdown: false}),
+      delay
+    );
+  },
+
+  /**
+   * Shutdown OS.File.
+   *
+   * @param {*} options
+   * - {boolean} shutdown If |true|, reject any further request. Otherwise,
+   *   further requests will resurrect the worker.
+   * - {boolean} reset If |true|, instruct the worker to shutdown if this
+   *   would not cause leaks. Otherwise, assume that the worker will be shutdown
+   *   through some other mean.
+   */
+  kill: function({shutdown, reset}) {
+    return Task.spawn(function*() {
+
+      yield this.queue;
+
+      if (!this.launched || this.shutdown || !worker) {
+        // Nothing to kill
+        this.shutdown = this.shutdown || shutdown;
+        worker = null;
+        return null;
+      }
+
+      // Deactivate the queue, to ensure that no message is sent
+      // to an obsolete worker (we reactivate it in the |finally|).
+      let deferred = Promise.defer();
+      this.queue = deferred.promise;
+
+      let message = ["Meta_shutdown", [reset]];
+
+      try {
+        Scheduler.latestReceived = [];
+        Scheduler.latestSent = [Date.now(), ...message];
+        let promise = worker.post(...message);
+
+        // Wait for result
+        let resources;
+        try {
+          resources = (yield promise).ok;
+
+          Scheduler.latestReceived = [Date.now(), message];
+        } catch (ex) {
+          LOG("Could not dispatch Meta_reset", ex);
+          // It's most likely a programmer error, but we'll assume that
+          // the worker has been shutdown, as it's less risky than the
+          // opposite stance.
+          resources = {openedFiles: [], openedDirectoryIterators: [], killed: true};
+
+          Scheduler.latestReceived = [Date.now(), message, ex];
+        }
+
+        let {openedFiles, openedDirectoryIterators, killed} = resources;
+        if (!reset
+          && (openedFiles && openedFiles.length
+            || ( openedDirectoryIterators && openedDirectoryIterators.length))) {
+          // The worker still holds resources. Report them.
+
+          let msg = "";
+          if (openedFiles.length > 0) {
+            msg += "The following files are still open:\n" +
+              openedFiles.join("\n");
+          }
+          if (openedDirectoryIterators.length > 0) {
+            msg += "The following directory iterators are still open:\n" +
+              openedDirectoryIterators.join("\n");
+          }
+
+          LOG("WARNING: File descriptors leaks detected.\n" + msg);
+        }
+
+        // Make sure that we do not leave an invalid |worker| around.
+        if (killed || shutdown) {
+          worker = null;
+        }
+
+        this.shutdown = shutdown;
+
+        return resources;
+
+      } finally {
+        // Resume accepting messages. If we have set |shutdown| to |true|,
+        // any pending/future request will be rejected. Otherwise, any
+        // pending/future request will spawn a new worker if necessary.
+        deferred.resolve();
+      }
+
+    }.bind(this));
   },
 
   /**
    * Push a task at the end of the queue.
    *
    * @param {function} code A function returning a Promise.
    * This function will be executed once all the previously
    * pushed tasks have completed.
@@ -305,16 +399,21 @@ let Scheduler = {
       options = methodArgs[methodArgs.length - 1];
     }
     Scheduler.Debugging.messagesQueued++;
     return this.push(() => Task.spawn(function*() {
       // Update debugging information. As |args| may be quite
       // expensive, we only keep a shortened version of it.
       Scheduler.Debugging.latestReceived = null;
       Scheduler.Debugging.latestSent = [Date.now(), method, summarizeObject(methodArgs)];
+
+      // Don't kill the worker just yet
+      Scheduler.restartTimer();
+
+
       let data;
       let reply;
       let isError = false;
       try {
         try {
           data = yield worker.post(method, ...args);
         } finally {
           Scheduler.Debugging.messagesReceived++;
@@ -341,21 +440,17 @@ let Scheduler = {
           Scheduler.Debugging.latestReceived = [Date.now(), reply.message, reply.fileName, reply.lineNumber];
         } else {
           Scheduler.Debugging.latestReceived = [Date.now(), summarizeObject(reply)];
         }
         if (firstLaunch) {
           Scheduler._updateTelemetry();
         }
 
-        // Don't restart the timer when reseting the worker, since that will
-        // lead to an endless "resetWorker()" loop.
-        if (method != "Meta_reset") {
-          Scheduler.restartTimer();
-        }
+        Scheduler.restartTimer();
       }
 
       // Check for duration and return result.
       if (!options) {
         return data.ok;
       }
       // Check for options.outExecutionDuration.
       if (typeof options !== "object" ||
@@ -465,64 +560,19 @@ if (SharedAll.Config.DEBUG && Scheduler.
 
 // Observer topics used for monitoring shutdown
 const WEB_WORKERS_SHUTDOWN_TOPIC = "web-workers-shutdown";
 
 // Preference used to configure test shutdown observer.
 const PREF_OSFILE_TEST_SHUTDOWN_OBSERVER =
   "toolkit.osfile.test.shutdown.observer";
 
-/**
- * A condition function meant to be used during phase
- * webWorkersShutdown, to warn about unclosed files and directories
- * and reconfigure the Scheduler to reject further requests.
- *
- * @param {bool=} shutdown If true or unspecified, reconfigure
- * the scheduler to reject further requests. Can be set to |false|
- * for testing purposes.
- * @return {promise} A promise satisfied once all pending messages
- * (including the shutdown warning message) have been answered.
- */
-function warnAboutUnclosedFiles(shutdown = true) {
-  if (!Scheduler.launched || !worker) {
-    // Don't launch the scheduler on our behalf. If no message has been
-    // sent to the worker, we can't have any leaking file/directory
-    // descriptor.
-    return null;
-  }
-  let promise = Scheduler.post("Meta_getUnclosedResources");
-
-  // Configure the worker to reject any further message.
-  if (shutdown) {
-    Scheduler.shutdown = true;
-  }
-
-  return promise.then(function onSuccess(opened) {
-    let msg = "";
-    if (opened.openedFiles.length > 0) {
-      msg += "The following files are still open:\n" +
-        opened.openedFiles.join("\n");
-    }
-    if (msg) {
-      msg += "\n";
-    }
-    if (opened.openedDirectoryIterators.length > 0) {
-      msg += "The following directory iterators are still open:\n" +
-        opened.openedDirectoryIterators.join("\n");
-    }
-    // Only log if file descriptors leaks detected.
-    if (msg) {
-      LOG("WARNING: File descriptors leaks detected.\n" + msg);
-    }
-  });
-};
-
 AsyncShutdown.webWorkersShutdown.addBlocker(
   "OS.File: flush pending requests, warn about unclosed files, shut down service.",
-  () => warnAboutUnclosedFiles(true)
+  () => Scheduler.kill({reset: false, shutdown: true})
 );
 
 
 // Attaching an observer for PREF_OSFILE_TEST_SHUTDOWN_OBSERVER to enable or
 // disable the test shutdown event observer.
 // Note: By default the PREF_OSFILE_TEST_SHUTDOWN_OBSERVER is unset.
 // Note: This is meant to be used for testing purposes only.
 Services.prefs.addObserver(PREF_OSFILE_TEST_SHUTDOWN_OBSERVER,
@@ -537,17 +587,17 @@ Services.prefs.addObserver(PREF_OSFILE_T
     }
     if (TOPIC) {
       // Generate a phase, add a blocker.
       // Note that this can work only if AsyncShutdown itself has been
       // configured for testing by the testsuite.
       let phase = AsyncShutdown._getPhase(TOPIC);
       phase.addBlocker(
         "(for testing purposes) OS.File: warn about unclosed files",
-        () => warnAboutUnclosedFiles(false)
+        () => Scheduler.kill({shutdown: false, reset: false})
       );
     }
   }, false);
 
 /**
  * Representation of a file, with asynchronous methods.
  *
  * @param {*} fdmsg The _message_ representing the platform-specific file
@@ -1361,54 +1411,25 @@ DirectoryIterator.Entry = function Entry
   return value;
 };
 DirectoryIterator.Entry.prototype = Object.create(SysAll.AbstractEntry.prototype);
 
 DirectoryIterator.Entry.fromMsg = function fromMsg(value) {
   return new DirectoryIterator.Entry(value);
 };
 
-/**
- * Flush all operations currently queued, then kill the underlying
- * worker to save memory.
- *
- * @return {Promise}
- * @reject {Error} If at least one file or directory iterator instance
- * is still open and the worker cannot be killed safely.
- */
 File.resetWorker = function() {
-  if (!Scheduler.launched || Scheduler.shutdown) {
-    // No need to reset
-    return Promise.resolve();
-  }
-  return Scheduler.post("Meta_reset").then(
-    function(wouldLeak) {
-      if (!wouldLeak) {
-        // No resource would leak, the worker was stopped.
-        worker = null;
-        return;
-      }
-      // Otherwise, resetting would be unsafe and has been canceled.
-      // Turn this into an error
-      let msg = "Cannot reset worker: ";
-      let {openedFiles, openedDirectoryIterators} = wouldLeak;
-      if (openedFiles.length > 0) {
-        msg += "The following files are still open:\n" +
-          openedFiles.join("\n");
-      }
-      if (openedDirectoryIterators.length > 0) {
-        msg += "The following directory iterators are still open:\n" +
-          openedDirectoryIterators.join("\n");
-      }
-      throw new Error(msg);
+  return Task.spawn(function*() {
+    let resources = yield Scheduler.kill({shutdown: false, reset: true});
+    if (resources && !resources.killed) {
+        throw new Error("Could not reset worker, this would leak file descriptors: " + JSON.stringify(resources));
     }
-  );
+  });
 };
 
-
 // Constants
 File.POS_START = SysAll.POS_START;
 File.POS_CURRENT = SysAll.POS_CURRENT;
 File.POS_END = SysAll.POS_END;
 
 // Exports
 File.Error = OSError;
 File.DirectoryIterator = DirectoryIterator;
--- a/toolkit/components/osfile/modules/osfile_async_worker.js
+++ b/toolkit/components/osfile/modules/osfile_async_worker.js
@@ -267,44 +267,35 @@ const EXCEPTION_NAMES = {
    SET_DEBUG: function(aDEBUG) {
      SharedAll.Config.DEBUG = aDEBUG;
    },
    // Return worker's current OS.Shared.DEBUG value to controller.
    // Note: This is used for testing purposes.
    GET_DEBUG: function() {
      return SharedAll.Config.DEBUG;
    },
-   Meta_getUnclosedResources: function() {
-     // Return information about both opened files and opened
-     // directory iterators.
-     return {
+   /**
+    * Execute shutdown sequence, returning data on leaked file descriptors.
+    *
+    * @param {bool} If |true|, kill the worker if this would not cause
+    * leaks.
+    */
+   Meta_shutdown: function(kill) {
+     let result = {
        openedFiles: OpenedFiles.listOpenedResources(),
-       openedDirectoryIterators: OpenedDirectoryIterators.listOpenedResources()
+       openedDirectoryIterators: OpenedDirectoryIterators.listOpenedResources(),
+       killed: false // Placeholder
      };
-   },
-   Meta_reset: function() {
-     // Attempt to stop the worker. This fails if at least one
-     // resource is still open. Returns the list of files and
-     // directory iterators that cannot be closed safely (or undefined
-     // if there are no such files/directory iterators).
-     let openedFiles = OpenedFiles.listOpenedResources();
-     let openedDirectoryIterators =
-       OpenedDirectoryIterators.listOpenedResources();
-     let canShutdown = openedFiles.length == 0
-                         && openedDirectoryIterators.length == 0;
-     if (canShutdown) {
-       // Succeed. Shutdown the thread, nothing to return
-       return new Meta(null, {shutdown: true});
-     } else {
-       // Fail. Don't shutdown the thread, return info on resources
-       return {
-         openedFiles: openedFiles,
-         openedDirectoryIterators: openedDirectoryIterators
-       };
-     }
+
+     // Is it safe to kill the worker?
+     let safe = result.openedFiles.length == 0
+           && result.openedDirectoryIterators.length == 0;
+     result.killed = safe && kill;
+
+     return new Meta(result, {shutdown: result.killed});
    },
    // Functions of OS.File
    stat: function stat(path, options) {
      return exports.OS.File.Info.toMsg(
        exports.OS.File.stat(Type.path.fromMsg(path), options));
    },
    setDates: function setDates(path, accessDate, modificationDate) {
      return exports.OS.File.setDates(Type.path.fromMsg(path), accessDate,
--- a/toolkit/components/osfile/tests/xpcshell/test_reset.js
+++ b/toolkit/components/osfile/tests/xpcshell/test_reset.js
@@ -32,34 +32,34 @@ add_task(function transparent_reset() {
 
 add_task(function file_open_cannot_reset() {
   let TEST_FILE = OS.Path.join(Path.profileDir, "tmp-" + Math.random());
   do_print("Leaking file descriptor " + TEST_FILE + ", we shouldn't be able to reset");
   let openedFile = yield OS.File.open(TEST_FILE, { create: true} );
   let thrown = false;
   try {
     yield OS.File.resetWorker();
-  } catch (ex if ex.message.indexOf(TEST_FILE) != -1 ) {
+  } catch (ex if ex.message.indexOf(OS.Path.basename(TEST_FILE)) != -1 ) {
     thrown = true;
   }
   do_check_true(thrown);
 
   do_print("Closing the file, we should now be able to reset");
   yield openedFile.close();
   yield OS.File.resetWorker();
 });
 
-add_task(function file_open_cannot_reset() {
+add_task(function dir_open_cannot_reset() {
   let TEST_DIR = yield OS.File.getCurrentDirectory();
   do_print("Leaking directory " + TEST_DIR + ", we shouldn't be able to reset");
   let iterator = new OS.File.DirectoryIterator(TEST_DIR);
   let thrown = false;
   try {
     yield OS.File.resetWorker();
-  } catch (ex if ex.message.indexOf(TEST_DIR) != -1 ) {
+  } catch (ex if ex.message.indexOf(OS.Path.basename(TEST_DIR)) != -1 ) {
     thrown = true;
   }
   do_check_true(thrown);
 
   do_print("Closing the directory, we should now be able to reset");
   yield iterator.close();
   yield OS.File.resetWorker();
 });
--- a/toolkit/components/osfile/tests/xpcshell/test_shutdown.js
+++ b/toolkit/components/osfile/tests/xpcshell/test_shutdown.js
@@ -84,15 +84,15 @@ add_task(function system_shutdown() {
 
   let TEST_FILE = OS.Path.join(OS.Constants.Path.profileDir, "test");
   do_print("Testing for leaks of file descriptor: " + TEST_FILE);
   let openedFile = yield OS.File.open(TEST_FILE, { create: true} );
   do_print("At this stage, we leak the file");
   do_check_true((yield testLeaksOf(TEST_FILE, "test.shutdown.file.leak")));
   yield openedFile.close();
   do_print("At this stage, we don't leak the file anymore");
-  do_check_false((yield testLeaksOf(TEST_FILE, "test.shutdown.file.leak")));
+  do_check_false((yield testLeaksOf(TEST_FILE, "test.shutdown.file.leak.2")));
 });
 
 
 function run_test() {
   run_next_test();
 }
--- a/toolkit/mozapps/extensions/AddonManager.jsm
+++ b/toolkit/mozapps/extensions/AddonManager.jsm
@@ -600,28 +600,39 @@ var AddonManagerInternal = {
         gHotfixID = Services.prefs.getCharPref(PREF_EM_HOTFIX_ID);
       } catch (e) {}
       Services.prefs.addObserver(PREF_EM_HOTFIX_ID, this, false);
 
       let defaultProvidersEnabled = true;
       try {
         defaultProvidersEnabled = Services.prefs.getBoolPref(PREF_DEFAULT_PROVIDERS_ENABLED);
       } catch (e) {}
+      AddonManagerPrivate.recordSimpleMeasure("default_providers", defaultProvidersEnabled);
 
       // Ensure all default providers have had a chance to register themselves
       if (defaultProvidersEnabled) {
-        DEFAULT_PROVIDERS.forEach(function(url) {
+        for (let url of DEFAULT_PROVIDERS) {
           try {
-            Components.utils.import(url, {});
+            let scope = {};
+            Components.utils.import(url, scope);
+            // Sanity check - make sure the provider exports a symbol that
+            // has a 'startup' method
+            let syms = Object.keys(scope);
+            if ((syms.length < 1) ||
+                (typeof scope[syms[0]].startup != "function")) {
+              logger.warn("Provider " + url + " has no startup()");
+              AddonManagerPrivate.recordException("AMI", "provider " + url, "no startup()");
+            }
+            logger.debug("Loaded provider scope for " + url + ": " + Object.keys(scope).toSource());
           }
           catch (e) {
             AddonManagerPrivate.recordException("AMI", "provider " + url + " load failed", e);
             logger.error("Exception loading default provider \"" + url + "\"", e);
           }
-        });
+        };
       }
 
       // Load any providers registered in the category manager
       let catman = Cc["@mozilla.org/categorymanager;1"].
                    getService(Ci.nsICategoryManager);
       let entries = catman.enumerateCategory(CATEGORY_PROVIDER_MODULE);
       while (entries.hasMoreElements()) {
         let entry = entries.getNext().QueryInterface(Ci.nsISupportsCString).data;
@@ -767,16 +778,17 @@ var AddonManagerInternal = {
 
     let providers = this.providers.slice(0);
     for (let provider of providers) {
       try {
         if (aMethod in provider)
           provider[aMethod].apply(provider, aArgs);
       }
       catch (e) {
+        AddonManagerPrivate.recordException("AMI", "provider " + aMethod, e);
         logger.error("Exception calling provider " + aMethod, e);
       }
     }
   },
 
   /**
    * Calls a method on all registered providers, if the provider implements
    * the method. The called method is expected to return a promise, and
--- a/toolkit/mozapps/extensions/internal/XPIProvider.jsm
+++ b/toolkit/mozapps/extensions/internal/XPIProvider.jsm
@@ -4,17 +4,17 @@
 
 "use strict";
 
 const Cc = Components.classes;
 const Ci = Components.interfaces;
 const Cr = Components.results;
 const Cu = Components.utils;
 
-this.EXPORTED_SYMBOLS = [];
+this.EXPORTED_SYMBOLS = ["XPIProvider"];
 
 Components.utils.import("resource://gre/modules/Services.jsm");
 Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
 Components.utils.import("resource://gre/modules/AddonManager.jsm");
 
 XPCOMUtils.defineLazyModuleGetter(this, "AddonRepository",
                                   "resource://gre/modules/addons/AddonRepository.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "ChromeManifestParser",
@@ -1540,17 +1540,17 @@ function makeSafe(aFunction) {
     }
     catch(ex) {
       logger.warn("XPIProvider callback failed", ex);
     }
     return undefined;
   }
 }
 
-var XPIProvider = {
+this.XPIProvider = {
   // An array of known install locations
   installLocations: null,
   // A dictionary of known install locations by name
   installLocationsByName: null,
   // An array of currently active AddonInstalls
   installs: null,
   // The default skin for the application
   defaultSkin: "classic/1.0",
@@ -1753,33 +1753,16 @@ var XPIProvider = {
    * @param  aOldAppVersion
    *         The version of the application last run with this profile or null
    *         if it is a new profile or the version is unknown
    * @param  aOldPlatformVersion
    *         The version of the platform last run with this profile or null
    *         if it is a new profile or the version is unknown
    */
   startup: function XPI_startup(aAppChanged, aOldAppVersion, aOldPlatformVersion) {
-    logger.debug("startup");
-    this.runPhase = XPI_STARTING;
-    this.installs = [];
-    this.installLocations = [];
-    this.installLocationsByName = {};
-    // Hook for tests to detect when saving database at shutdown time fails
-    this._shutdownError = null;
-    // Clear this at startup for xpcshell test restarts
-    this._telemetryDetails = {};
-    // Clear the set of enabled experiments (experiments disabled by default).
-    this._enabledExperiments = new Set();
-    // Register our details structure with AddonManager
-    AddonManagerPrivate.setTelemetryDetails("XPI", this._telemetryDetails);
-
-
-    AddonManagerPrivate.recordTimestamp("XPI_startup_begin");
-
     function addDirectoryInstallLocation(aName, aKey, aPaths, aScope, aLocked) {
       try {
         var dir = FileUtils.getDir(aKey, aPaths);
       }
       catch (e) {
         // Some directories aren't defined on some platforms, ignore them
         logger.debug("Skipping unavailable install location " + aName);
         return;
@@ -1806,16 +1789,32 @@ var XPIProvider = {
         return;
       }
 
       XPIProvider.installLocations.push(location);
       XPIProvider.installLocationsByName[location.name] = location;
     }
 
     try {
+      AddonManagerPrivate.recordTimestamp("XPI_startup_begin");
+
+      logger.debug("startup");
+      this.runPhase = XPI_STARTING;
+      this.installs = [];
+      this.installLocations = [];
+      this.installLocationsByName = {};
+      // Hook for tests to detect when saving database at shutdown time fails
+      this._shutdownError = null;
+      // Clear this at startup for xpcshell test restarts
+      this._telemetryDetails = {};
+      // Clear the set of enabled experiments (experiments disabled by default).
+      this._enabledExperiments = new Set();
+      // Register our details structure with AddonManager
+      AddonManagerPrivate.setTelemetryDetails("XPI", this._telemetryDetails);
+
       let hasRegistry = ("nsIWindowsRegKey" in Ci);
 
       let enabledScopes = Prefs.getIntPref(PREF_EM_ENABLED_SCOPES,
                                            AddonManager.SCOPE_ALL);
 
       // These must be in order of priority for processFileChanges etc. to work
       if (enabledScopes & AddonManager.SCOPE_SYSTEM) {
         if (hasRegistry) {
--- a/toolkit/themes/windows/global/inContentUI.css
+++ b/toolkit/themes/windows/global/inContentUI.css
@@ -63,20 +63,28 @@ html|html {
 /* Content */
 *|*.main-content {
   /* Needed to allow the radius to clip the inner content, see bug 595656 */
   overflow: hidden;
   background-color: rgba(255, 255, 255, 0.35);
   background-image: linear-gradient(rgba(255, 255, 255, 0),
                                     rgba(255, 255, 255, 0.75));
   border: 1px solid #C3CEDF;
-  border-radius: 5px;
 }
 
 %ifdef WINDOWS_AERO
+@media (-moz-os-version: windows-vista),
+       (-moz-os-version: windows-win7) {
+%endif
+  *|*.main-content {
+    border-radius: 5px;
+  }
+%ifdef WINDOWS_AERO
+}
+
 @media (-moz-windows-glass) {
   /* Buttons */
   *|button,
   menulist,
   colorpicker[type="button"] {
     -moz-appearance: none;
     color: black;
     padding: 0 5px;
--- a/toolkit/themes/windows/mozapps/extensions/extensions.css
+++ b/toolkit/themes/windows/mozapps/extensions/extensions.css
@@ -176,25 +176,32 @@
   padding: 10px 4px;
   border-width: 1px;
   border-style: solid;
   border-color: transparent;
   -moz-box-align: center;
   overflow: hidden;
 }
 
-.category:-moz-locale-dir(ltr) {
-  border-top-left-radius: 5px;
-  border-bottom-left-radius: 5px;
-}
+%ifdef WINDOWS_AERO
+@media (-moz-os-version: windows-vista),
+       (-moz-os-version: windows-win7) {
+%endif
+  .category:-moz-locale-dir(ltr) {
+    border-top-left-radius: 5px;
+    border-bottom-left-radius: 5px;
+  }
 
-.category:-moz-locale-dir(rtl) {
-  border-top-right-radius: 5px;
-  border-bottom-right-radius: 5px;
+  .category:-moz-locale-dir(rtl) {
+    border-top-right-radius: 5px;
+    border-bottom-right-radius: 5px;
+  }
+%ifdef WINDOWS_AERO
 }
+%endif
 
 .category[disabled] {
   border-top: 0;
   border-bottom: 0;
   height: 0;
   opacity: 0;
   transition-property: height, opacity;
   transition-duration: 1s, 0.8s;