Merge b2g-inbound to m-c.
authorRyan VanderMeulen <ryanvm@gmail.com>
Wed, 26 Mar 2014 20:46:47 -0400
changeset 175406 e4423b6f3ca82a6e802891bc40410ee39703b061
parent 175326 1b761f92d159b2baf7bbccfde27c0c87207fe71a (current diff)
parent 175405 5953c846bb5aba0650a67400be524fde32097901 (diff)
child 175462 da3198b95e6b9948133865375c393a0c72444efa
push id1
push userroot
push dateMon, 20 Oct 2014 17:29:22 +0000
milestone31.0a1
Merge b2g-inbound to m-c.
--- a/addon-sdk/Makefile.in
+++ b/addon-sdk/Makefile.in
@@ -1,16 +1,22 @@
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 include $(topsrcdir)/config/config.mk
 
+ifeq (gonk,$(MOZ_WIDGET_TOOLKIT))
+MOZ_B2G=1
+else
+MOZ_B2G=0
+endif
+
 libs::
-	$(PYTHON) $(srcdir)/copy_source.py $(topsrcdir) $(srcdir)/source/lib $(FINAL_TARGET)/modules/commonjs >copy_source.mk
+	$(PYTHON) $(srcdir)/copy_source.py $(topsrcdir) $(srcdir)/source/lib $(FINAL_TARGET)/modules/commonjs $(MOZ_B2G) >copy_source.mk
 	$(MAKE) -f copy_source.mk libs
 
 include $(topsrcdir)/config/rules.mk
 
 TEST_FILES = \
   source/app-extension \
   source/bin \
   source/python-lib \
--- a/addon-sdk/copy_source.py
+++ b/addon-sdk/copy_source.py
@@ -1,23 +1,24 @@
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 import os
 import sys
 
-if len(sys.argv) != 4:
+if len(sys.argv) != 5:
     print >> sys.stderr, "Usage: copy_source.py " \
-                         "<topsrcdir> <source directory> <target directory>"
+                         "<topsrcdir> <source directory> <target directory> <isb2g>"
     sys.exit(1)
 
 topsrcdir = sys.argv[1]
 source_dir = sys.argv[2]
 target_dir = sys.argv[3]
+isB2G = int(sys.argv[4])
 
 print """
 DEPTH     = ..
 topsrcdir = %(topsrcdir)s
 srcdir    = %(topsrcdir)s/addon-sdk
 VPATH     = %(topsrcdir)s/addon-sdk
 
 include $(topsrcdir)/config/config.mk
@@ -30,16 +31,32 @@ if not os.path.exists(real_source):
 elif not os.path.isdir(real_source):
     print >> sys.stderr, "Error: Source %s is not a directory" % real_source
     sys.exit(1)
 for dirpath, dirnames, filenames in os.walk(real_source):
     if not filenames:
         continue
     dirpath = dirpath.replace(os.sep, '/')
     relative = dirpath[len(source_dir):]
+    if isB2G and relative in [
+        '/method/test',
+        '/sdk/ui',
+        '/sdk/ui/button',
+        '/sdk/ui/sidebar',
+        '/sdk/places',
+        '/sdk/places/host',
+        '/sdk/tabs',
+        '/sdk/panel',
+        '/sdk/frame',
+        '/sdk/test',
+        '/sdk/window',
+        '/sdk/windows',
+        '/sdk/deprecated',
+        ]:
+        continue
     varname = "COMMONJS%s" % relative.replace('/', '_')
     print "%s_FILES = \\" % varname
     for name in filenames:
         print "  %s/%s \\" % (dirpath, name)
     print "  $(NULL)"
     print "%s_DEST = %s%s" % (varname, target_dir, relative)
     print "INSTALL_TARGETS += %s\n" % varname
 
--- a/b2g/app/b2g.js
+++ b/b2g/app/b2g.js
@@ -698,16 +698,18 @@ pref("gonk.systemMemoryPressureRecoveryP
 #ifndef DEBUG
 // Enable pre-launching content processes for improved startup time
 // (hiding latency).
 pref("dom.ipc.processPrelaunch.enabled", true);
 // Wait this long before pre-launching a new subprocess.
 pref("dom.ipc.processPrelaunch.delayMs", 5000);
 #endif
 
+pref("dom.ipc.reuse_parent_app", false);
+
 // When a process receives a system message, we hold a CPU wake lock on its
 // behalf for this many seconds, or until it handles the system message,
 // whichever comes first.
 pref("dom.ipc.systemMessageCPULockTimeoutSec", 30);
 
 // Ignore the "dialog=1" feature in window.open.
 pref("dom.disable_window_open_dialog_feature", true);
 
--- 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="9da1b9c11bf518bce882be305ae121c44c5d1e05"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="e909a131d5ae702b2befdbc165996f9930653171"/>
   <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="cb16958e41105d7c551d9941f522db97b8312538"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="485846b2a40d8ac7d6c1c5f8af6d15b0c10af19d"/>
   <!-- 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
@@ -12,17 +12,17 @@
   <!--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">
     <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="9da1b9c11bf518bce882be305ae121c44c5d1e05"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="e909a131d5ae702b2befdbc165996f9930653171"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="266bca6e60dad43e395f38b66edabe8bdc882334"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="cb16958e41105d7c551d9941f522db97b8312538"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="485846b2a40d8ac7d6c1c5f8af6d15b0c10af19d"/>
   <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="9da1b9c11bf518bce882be305ae121c44c5d1e05"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="e909a131d5ae702b2befdbc165996f9930653171"/>
   <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="cb16958e41105d7c551d9941f522db97b8312538"/>
   <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="485846b2a40d8ac7d6c1c5f8af6d15b0c10af19d"/>
   <!-- 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="9da1b9c11bf518bce882be305ae121c44c5d1e05"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="e909a131d5ae702b2befdbc165996f9930653171"/>
   <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="cb16958e41105d7c551d9941f522db97b8312538"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="485846b2a40d8ac7d6c1c5f8af6d15b0c10af19d"/>
   <!-- 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": ""
+        "branch": ""
     }, 
-    "revision": "1bd0f38add918047002f67c22ca407ca3844be4f", 
+    "revision": "5aec7ae12f4adb8518fb6d409fa1ea2dc7ea0c06", 
     "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="9da1b9c11bf518bce882be305ae121c44c5d1e05"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="e909a131d5ae702b2befdbc165996f9930653171"/>
   <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="cb16958e41105d7c551d9941f522db97b8312538"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="485846b2a40d8ac7d6c1c5f8af6d15b0c10af19d"/>
   <!-- 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="9da1b9c11bf518bce882be305ae121c44c5d1e05"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="e909a131d5ae702b2befdbc165996f9930653171"/>
   <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="cb16958e41105d7c551d9941f522db97b8312538"/>
   <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="9da1b9c11bf518bce882be305ae121c44c5d1e05"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="e909a131d5ae702b2befdbc165996f9930653171"/>
   <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="cb16958e41105d7c551d9941f522db97b8312538"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="485846b2a40d8ac7d6c1c5f8af6d15b0c10af19d"/>
   <!-- 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="9da1b9c11bf518bce882be305ae121c44c5d1e05"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="e909a131d5ae702b2befdbc165996f9930653171"/>
   <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="cb16958e41105d7c551d9941f522db97b8312538"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="485846b2a40d8ac7d6c1c5f8af6d15b0c10af19d"/>
   <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
@@ -12,17 +12,17 @@
   <!--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">
     <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="9da1b9c11bf518bce882be305ae121c44c5d1e05"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="e909a131d5ae702b2befdbc165996f9930653171"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="266bca6e60dad43e395f38b66edabe8bdc882334"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="cb16958e41105d7c551d9941f522db97b8312538"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="485846b2a40d8ac7d6c1c5f8af6d15b0c10af19d"/>
   <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="9da1b9c11bf518bce882be305ae121c44c5d1e05"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="e909a131d5ae702b2befdbc165996f9930653171"/>
   <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="cb16958e41105d7c551d9941f522db97b8312538"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="485846b2a40d8ac7d6c1c5f8af6d15b0c10af19d"/>
   <project name="gonk-patches" path="patches" remote="b2g" revision="223a2421006e8f5da33f516f6891c87cae86b0f6"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="6426040f1be4a844082c9769171ce7f5341a5528"/>
--- a/content/base/src/nsGkAtomList.h
+++ b/content/base/src/nsGkAtomList.h
@@ -850,16 +850,17 @@ GK_ATOM(pageincrement, "pageincrement")
 GK_ATOM(pagex, "pagex")
 GK_ATOM(pagey, "pagey")
 GK_ATOM(paint_order, "paint-order")
 GK_ATOM(palettename, "palettename")
 GK_ATOM(panel, "panel")
 GK_ATOM(param, "param")
 GK_ATOM(parameter, "parameter")
 GK_ATOM(parent, "parent")
+GK_ATOM(parentapp, "parentapp")
 GK_ATOM(parentfocused, "parentfocused")
 GK_ATOM(parsetype, "parsetype")
 GK_ATOM(pattern, "pattern")
 GK_ATOM(patternSeparator, "pattern-separator")
 GK_ATOM(perMille, "per-mille")
 GK_ATOM(percent, "percent")
 GK_ATOM(persist, "persist")
 GK_ATOM(phase, "phase")
--- a/dom/browser-element/BrowserElementParent.cpp
+++ b/dom/browser-element/BrowserElementParent.cpp
@@ -53,16 +53,25 @@ CreateIframe(Element* aOpenerFrameElemen
   // Copy the opener frame's mozapp attribute to the popup frame.
   if (aOpenerFrameElement->HasAttr(kNameSpaceID_None, nsGkAtoms::mozapp)) {
     nsAutoString mozapp;
     aOpenerFrameElement->GetAttr(kNameSpaceID_None, nsGkAtoms::mozapp, mozapp);
     popupFrameElement->SetAttr(kNameSpaceID_None, nsGkAtoms::mozapp,
                                mozapp, /* aNotify = */ false);
   }
 
+  // Copy the opener frame's parentApp attribute to the popup frame.
+  if (aOpenerFrameElement->HasAttr(kNameSpaceID_None, nsGkAtoms::parentapp)) {
+    nsAutoString parentApp;
+    aOpenerFrameElement->GetAttr(kNameSpaceID_None, nsGkAtoms::parentapp,
+                                 parentApp);
+    popupFrameElement->SetAttr(kNameSpaceID_None, nsGkAtoms::parentapp,
+                               parentApp, /* aNotify = */ false);
+  }
+
   // Copy the window name onto the iframe.
   popupFrameElement->SetAttr(kNameSpaceID_None, nsGkAtoms::name,
                              aName, /* aNotify = */ false);
 
   // Indicate whether the iframe is should be remote.
   popupFrameElement->SetAttr(kNameSpaceID_None, nsGkAtoms::Remote,
                              aRemote ? NS_LITERAL_STRING("true") :
                                        NS_LITERAL_STRING("false"),
--- a/dom/ipc/AppProcessChecker.cpp
+++ b/dom/ipc/AppProcessChecker.cpp
@@ -70,22 +70,16 @@ AssertAppProcess(PBrowserParent* aActor,
           aValid = true;
         }
         break;
       }
       default:
         break;
     }
   }
-
-  if (!aValid) {
-    printf_stderr("Security problem: Content process does not have `%s'.  It will be killed.\n", aCapability);
-    ContentParent* process = tab->Manager();
-    process->KillHard();
-  }
   return aValid;
 }
 
 bool
 AssertAppStatus(PBrowserParent* aActor,
                 unsigned short aStatus)
 {
   if (!aActor) {
@@ -100,51 +94,53 @@ AssertAppStatus(PBrowserParent* aActor,
 
   if (app) {
     unsigned short appStatus = 0;
     if (NS_SUCCEEDED(app->GetAppStatus(&appStatus))) {
       valid = appStatus == aStatus;
     }
   }
 
-  if (!valid) {
-    printf_stderr("Security problem: Content process does not have `%d' status.  It will be killed.\n", aStatus);
-    ContentParent* process = tab->Manager();
-    process->KillHard();
-  }
-
   return valid;
 }
 
 bool
 AssertAppProcess(PContentParent* aActor,
                  AssertAppProcessType aType,
                  const char* aCapability)
 {
   const InfallibleTArray<PBrowserParent*>& browsers =
     aActor->ManagedPBrowserParent();
   for (uint32_t i = 0; i < browsers.Length(); ++i) {
     if (AssertAppProcess(browsers[i], aType, aCapability)) {
       return true;
     }
   }
+
+  printf_stderr("Security problem: Content process does not have `%s'.  It will be killed.\n", aCapability);
+  static_cast<ContentParent*>(aActor)->KillHard();
+
   return false;
 }
 
 bool
 AssertAppStatus(PContentParent* aActor,
                 unsigned short aStatus)
 {
   const InfallibleTArray<PBrowserParent*>& browsers =
     aActor->ManagedPBrowserParent();
   for (uint32_t i = 0; i < browsers.Length(); ++i) {
     if (AssertAppStatus(browsers[i], aStatus)) {
       return true;
     }
   }
+
+  printf_stderr("Security problem: Content process does not have `%d' status.  It will be killed.\n", aStatus);
+  static_cast<ContentParent*>(aActor)->KillHard();
+
   return false;
 }
 
 bool
 AssertAppProcess(PHalParent* aActor,
                  AssertAppProcessType aType,
                  const char* aCapability)
 {
--- a/dom/ipc/ContentChild.cpp
+++ b/dom/ipc/ContentChild.cpp
@@ -374,16 +374,17 @@ InitOnContentProcessCreated()
     mozilla::dom::time::InitializeDateCacheCleaner();
 }
 
 ContentChild::ContentChild()
  : mID(uint64_t(-1))
 #ifdef ANDROID
    ,mScreenSize(0, 0)
 #endif
+   , mCanOverrideProcessName(true)
 {
     // This process is a content process, so it's clearly running in
     // multiprocess mode!
     nsDebugImpl::SetMultiprocessMode("Child");
 }
 
 ContentChild::~ContentChild()
 {
@@ -439,32 +440,36 @@ ContentChild::Init(MessageLoop* aIOLoop,
 #endif
 
     SendGetProcessAttributes(&mID, &mIsForApp, &mIsForBrowser);
 
     GetCPOWManager();
 
 #ifdef MOZ_NUWA_PROCESS
     if (IsNuwaProcess()) {
-        SetProcessName(NS_LITERAL_STRING("(Nuwa)"));
+        SetProcessName(NS_LITERAL_STRING("(Nuwa)"), false);
         return true;
     }
 #endif
     if (mIsForApp && !mIsForBrowser) {
-        SetProcessName(NS_LITERAL_STRING("(Preallocated app)"));
+        SetProcessName(NS_LITERAL_STRING("(Preallocated app)"), false);
     } else {
-        SetProcessName(NS_LITERAL_STRING("Browser"));
+        SetProcessName(NS_LITERAL_STRING("Browser"), false);
     }
 
     return true;
 }
 
 void
-ContentChild::SetProcessName(const nsAString& aName)
+ContentChild::SetProcessName(const nsAString& aName, bool aDontOverride)
 {
+    if (!mCanOverrideProcessName) {
+        return;
+    }
+
     char* name;
     if ((name = PR_GetEnv("MOZ_DEBUG_APP_PROCESS")) &&
         aName.EqualsASCII(name)) {
 #ifdef OS_POSIX
         printf_stderr("\n\nCHILDCHILDCHILDCHILD\n  [%s] debug me @%d\n\n", name, getpid());
         sleep(30);
 #elif defined(OS_WIN)
         // Windows has a decent JIT debugging story, so NS_DebugBreak does the
@@ -472,16 +477,20 @@ ContentChild::SetProcessName(const nsASt
         NS_DebugBreak(NS_DEBUG_BREAK,
                       "Invoking NS_DebugBreak() to debug child process",
                       nullptr, __FILE__, __LINE__);
 #endif
     }
 
     mProcessName = aName;
     mozilla::ipc::SetThisProcessName(NS_LossyConvertUTF16toASCII(aName).get());
+
+    if (aDontOverride) {
+        mCanOverrideProcessName = false;
+    }
 }
 
 void
 ContentChild::GetProcessName(nsAString& aName)
 {
     aName.Assign(mProcessName);
 }
 
@@ -1700,17 +1709,17 @@ public:
     {
         NuwaSpawn();
         if (IsNuwaProcess()) {
             return NS_OK;
         }
 
         // In the new process.
         ContentChild* child = ContentChild::GetSingleton();
-        child->SetProcessName(NS_LITERAL_STRING("(Preallocated app)"));
+        child->SetProcessName(NS_LITERAL_STRING("(Preallocated app)"), false);
         mozilla::ipc::Transport* transport = child->GetTransport();
         int fd = transport->GetFileDescriptor();
         transport->ResetFileDescriptor(fd);
 
         IToplevelProtocol* toplevel = child->GetFirstOpenedActors();
         while (toplevel != nullptr) {
             transport = toplevel->GetTransport();
             fd = transport->GetFileDescriptor();
--- a/dom/ipc/ContentChild.h
+++ b/dom/ipc/ContentChild.h
@@ -70,17 +70,17 @@ public:
     static ContentChild* GetSingleton() {
         return sSingleton;
     }
 
     const AppInfo& GetAppInfo() {
         return mAppInfo;
     }
 
-    void SetProcessName(const nsAString& aName);
+    void SetProcessName(const nsAString& aName, bool aDontOverride = false);
     void GetProcessName(nsAString& aName);
     void GetProcessName(nsACString& aName);
     static void AppendProcessId(nsACString& aName);
 
     PCompositorChild*
     AllocPCompositorChild(mozilla::ipc::Transport* aTransport,
                           base::ProcessId aOtherProcess) MOZ_OVERRIDE;
     PImageBridgeChild*
@@ -309,16 +309,17 @@ private:
     AppInfo mAppInfo;
 
 #ifdef ANDROID
     gfxIntSize mScreenSize;
 #endif
 
     bool mIsForApp;
     bool mIsForBrowser;
+    bool mCanOverrideProcessName;
     nsString mProcessName;
 
     static ContentChild* sSingleton;
 
     DISALLOW_EVIL_CONSTRUCTORS(ContentChild);
 };
 
 } // namespace dom
--- a/dom/ipc/ContentParent.cpp
+++ b/dom/ipc/ContentParent.cpp
@@ -681,26 +681,60 @@ ContentParent::CreateBrowserOrApp(const 
     // !HasOwnApp() branch above.
     nsCOMPtr<mozIApplication> ownApp = aContext.GetOwnApp();
 
     if (!sAppContentParents) {
         sAppContentParents =
             new nsDataHashtable<nsStringHashKey, ContentParent*>();
     }
 
-    // Each app gets its own ContentParent instance.
+    // Each app gets its own ContentParent instance unless it shares it with
+    // a parent app.
     nsAutoString manifestURL;
     if (NS_FAILED(ownApp->GetManifestURL(manifestURL))) {
         NS_ERROR("Failed to get manifest URL");
         return nullptr;
     }
 
     ProcessPriority initialPriority = GetInitialProcessPriority(aFrameElement);
-
     nsRefPtr<ContentParent> p = sAppContentParents->Get(manifestURL);
+
+    if (!p && Preferences::GetBool("dom.ipc.reuse_parent_app")) {
+        nsAutoString parentAppURL;
+        aFrameElement->GetAttr(kNameSpaceID_None,
+                               nsGkAtoms::parentapp, parentAppURL);
+        nsAdoptingString systemAppURL =
+            Preferences::GetString("browser.homescreenURL");
+        nsCOMPtr<nsIAppsService> appsService =
+            do_GetService(APPS_SERVICE_CONTRACTID);
+        if (!parentAppURL.IsEmpty() &&
+            !parentAppURL.Equals(systemAppURL) &&
+            appsService) {
+            nsCOMPtr<mozIApplication> parentApp;
+            nsCOMPtr<mozIApplication> app;
+            appsService->GetAppByManifestURL(parentAppURL,
+                                             getter_AddRefs(parentApp));
+            appsService->GetAppByManifestURL(manifestURL,
+                                             getter_AddRefs(app));
+
+            // Only let certified apps re-use the same process.
+            unsigned short parentAppStatus = 0;
+            unsigned short appStatus = 0;
+            if (app &&
+                NS_SUCCEEDED(app->GetAppStatus(&appStatus)) &&
+                appStatus == nsIPrincipal::APP_STATUS_CERTIFIED &&
+                parentApp &&
+                NS_SUCCEEDED(parentApp->GetAppStatus(&parentAppStatus)) &&
+                parentAppStatus == nsIPrincipal::APP_STATUS_CERTIFIED) {
+                // Check if we can re-use the process of the parent app.
+                p = sAppContentParents->Get(parentAppURL);
+            }
+        }
+    }
+
     if (p) {
         // Check that the process is still alive and set its priority.
         // Hopefully the process won't die after this point, if this call
         // succeeds.
         if (!p->SetPriorityAndCheckIsAlive(initialPriority)) {
             p = nullptr;
         }
     }
--- a/dom/ipc/TabChild.cpp
+++ b/dom/ipc/TabChild.cpp
@@ -1339,17 +1339,17 @@ TabChild::SetProcessNameToAppName()
 
   nsAutoString appName;
   nsresult rv = app->GetName(appName);
   if (NS_FAILED(rv)) {
     NS_WARNING("Failed to retrieve app name");
     return;
   }
 
-  ContentChild::GetSingleton()->SetProcessName(appName);
+  ContentChild::GetSingleton()->SetProcessName(appName, true);
 }
 
 bool
 TabChild::IsRootContentDocument()
 {
     // A TabChild is a "root content document" if it's
     //
     //  - <iframe mozapp> not inside another <iframe mozapp>,
--- a/dom/messages/SystemMessageInternal.js
+++ b/dom/messages/SystemMessageInternal.js
@@ -337,17 +337,18 @@ SystemMessageInternal.prototype = {
   },
 
   receiveMessage: function receiveMessage(aMessage) {
     let msg = aMessage.json;
 
     // To prevent the hacked child process from sending commands to parent
     // to manage system messages, we need to check its manifest URL.
     if (["SystemMessageManager:Register",
-         "SystemMessageManager:Unregister",
+         // TODO: fix bug 988142 to re-enable.
+         // "SystemMessageManager:Unregister",
          "SystemMessageManager:GetPendingMessages",
          "SystemMessageManager:HasPendingMessages",
          "SystemMessageManager:Message:Return:OK",
          "SystemMessageManager:HandleMessagesDone"].indexOf(aMessage.name) != -1) {
       if (!aMessage.target.assertContainApp(msg.manifest)) {
         debug("Got message from a child process containing illegal manifest URL.");
         return null;
       }
--- a/gfx/layers/ipc/ISurfaceAllocator.h
+++ b/gfx/layers/ipc/ISurfaceAllocator.h
@@ -155,27 +155,32 @@ public:
   virtual PGrallocBufferChild* AllocGrallocBuffer(const gfx::IntSize& aSize,
                                                   uint32_t aFormat,
                                                   uint32_t aUsage,
                                                   MaybeMagicGrallocBufferHandle* aHandle)
   {
     return nullptr;
   }
 
+  virtual void DeallocGrallocBuffer(PGrallocBufferChild* aChild)
+  {
+    NS_RUNTIMEABORT("should not be called");
+  }
+
   virtual bool IPCOpen() const { return true; }
   virtual bool IsSameProcess() const = 0;
 
   // Returns true if aSurface wraps a Shmem.
   static bool IsShmem(SurfaceDescriptor* aSurface);
 
 protected:
   // this method is needed for a temporary fix, will be removed after
   // DeprecatedTextureClient/Host rework.
   virtual bool IsOnCompositorSide() const = 0;
-  static bool PlatformDestroySharedSurface(SurfaceDescriptor* aSurface);
+  bool PlatformDestroySharedSurface(SurfaceDescriptor* aSurface);
   virtual bool PlatformAllocSurfaceDescriptor(const gfx::IntSize& aSize,
                                               gfxContentType aContent,
                                               uint32_t aCaps,
                                               SurfaceDescriptor* aBuffer);
 
 
   virtual ~ISurfaceAllocator();
 
--- a/gfx/layers/ipc/ImageBridgeChild.cpp
+++ b/gfx/layers/ipc/ImageBridgeChild.cpp
@@ -931,16 +931,63 @@ ImageBridgeChild::AllocGrallocBuffer(con
                                        aUsage,
                                        aHandle);
 #else
   NS_RUNTIMEABORT("not implemented");
   return nullptr;
 #endif
 }
 
+static void ProxyDeallocGrallocBufferNow(ISurfaceAllocator* aAllocator,
+                                         PGrallocBufferChild* aChild,
+                                         ReentrantMonitor* aBarrier,
+                                         bool* aDone)
+{
+  MOZ_ASSERT(aChild);
+  MOZ_ASSERT(aDone);
+  MOZ_ASSERT(aBarrier);
+
+#ifdef MOZ_WIDGET_GONK
+  PGrallocBufferChild::Send__delete__(aChild);
+#else
+  NS_RUNTIMEABORT("not implemented");
+#endif
+
+  ReentrantMonitorAutoEnter autoMon(*aBarrier);
+  *aDone = true;
+  aBarrier->NotifyAll();
+}
+
+void
+ImageBridgeChild::DeallocGrallocBuffer(PGrallocBufferChild* aChild)
+{
+  MOZ_ASSERT(aChild);
+  if (InImageBridgeChildThread()) {
+#ifdef MOZ_WIDGET_GONK
+    PGrallocBufferChild::Send__delete__(aChild);
+#else
+    NS_RUNTIMEABORT("not implemented");
+#endif
+  } else {
+    ReentrantMonitor barrier("AllocatorProxy Dealloc");
+    ReentrantMonitorAutoEnter autoMon(barrier);
+
+    bool done = false;
+    GetMessageLoop()->PostTask(FROM_HERE,
+                               NewRunnableFunction(&ProxyDeallocGrallocBufferNow,
+                                                   this,
+                                                   aChild,
+                                                   &barrier,
+                                                   &done));
+    while (!done) {
+      barrier.Wait();
+    }
+  }
+}
+
 PTextureChild*
 ImageBridgeChild::AllocPTextureChild(const SurfaceDescriptor&,
                                      const TextureFlags&)
 {
   return TextureClient::CreateIPDLActor();
 }
 
 bool
--- a/gfx/layers/ipc/ImageBridgeChild.h
+++ b/gfx/layers/ipc/ImageBridgeChild.h
@@ -391,14 +391,16 @@ protected:
                                   bool aUnsafe);
 
   CompositableTransaction* mTxn;
 
   // ISurfaceAllocator
   virtual PGrallocBufferChild* AllocGrallocBuffer(const gfx::IntSize& aSize,
                                                   uint32_t aFormat, uint32_t aUsage,
                                                   MaybeMagicGrallocBufferHandle* aHandle) MOZ_OVERRIDE;
+
+  virtual void DeallocGrallocBuffer(PGrallocBufferChild* aChild) MOZ_OVERRIDE;
 };
 
 } // layers
 } // mozilla
 
 #endif
--- a/gfx/layers/ipc/ShadowLayerUtilsGralloc.cpp
+++ b/gfx/layers/ipc/ShadowLayerUtilsGralloc.cpp
@@ -357,17 +357,17 @@ ISurfaceAllocator::PlatformDestroyShared
   // depending on whether we're on the parent or child side.
   PGrallocBufferParent* gbp =
     aSurface->get_SurfaceDescriptorGralloc().bufferParent();
   if (gbp) {
     unused << PGrallocBufferParent::Send__delete__(gbp);
   } else {
     PGrallocBufferChild* gbc =
       aSurface->get_SurfaceDescriptorGralloc().bufferChild();
-    unused << PGrallocBufferChild::Send__delete__(gbc);
+    DeallocGrallocBuffer(gbc);
   }
 
   *aSurface = SurfaceDescriptor();
   return true;
 }
 
 //-----------------------------------------------------------------------------
 // Child process
@@ -391,16 +391,23 @@ PGrallocBufferChild*
 ShadowLayerForwarder::AllocGrallocBuffer(const gfx::IntSize& aSize,
                                          uint32_t aFormat,
                                          uint32_t aUsage,
                                          MaybeMagicGrallocBufferHandle* aHandle)
 {
   return mShadowManager->SendPGrallocBufferConstructor(aSize, aFormat, aUsage, aHandle);
 }
 
+void
+ShadowLayerForwarder::DeallocGrallocBuffer(PGrallocBufferChild* aChild)
+{
+  MOZ_ASSERT(aChild);
+  PGrallocBufferChild::Send__delete__(aChild);
+}
+
 bool
 ISurfaceAllocator::PlatformAllocSurfaceDescriptor(const gfx::IntSize& aSize,
                                                   gfxContentType aContent,
                                                   uint32_t aCaps,
                                                   SurfaceDescriptor* aBuffer)
 {
 
   // Some GL implementations fail to render gralloc textures with
--- a/gfx/layers/ipc/ShadowLayers.h
+++ b/gfx/layers/ipc/ShadowLayers.h
@@ -417,16 +417,18 @@ protected:
   RefPtr<LayerTransactionChild> mShadowManager;
 
 #ifdef MOZ_HAVE_SURFACEDESCRIPTORGRALLOC
   // from ISurfaceAllocator
   virtual PGrallocBufferChild* AllocGrallocBuffer(const gfx::IntSize& aSize,
                                                   uint32_t aFormat,
                                                   uint32_t aUsage,
                                                   MaybeMagicGrallocBufferHandle* aHandle) MOZ_OVERRIDE;
+
+  virtual void DeallocGrallocBuffer(PGrallocBufferChild* aChild) MOZ_OVERRIDE;
 #endif
 
 private:
   /**
    * Try to query the content type efficiently, but at worst map the
    * surface and return it in *aSurface.
    */
   static gfxContentType
--- a/services/fxaccounts/FxAccountsManager.jsm
+++ b/services/fxaccounts/FxAccountsManager.jsm
@@ -244,42 +244,41 @@ this.FxAccountsManager = {
       );
     }
     return this._signOut();
   },
 
   getAccount: function() {
     // We check first if we have session details cached.
     if (this._activeSession) {
-      // If our cache says that the account is not yet verified, we check that
-      // this information is correct, and update the cached data if not.
+      // If our cache says that the account is not yet verified,
+      // we kick off verification before returning what we have.
       if (this._activeSession && !this._activeSession.verified &&
           !Services.io.offline) {
-        return this.verificationStatus(this._activeSession);
+        this.verificationStatus(this._activeSession);
       }
 
       log.debug("Account " + JSON.stringify(this._user));
       return Promise.resolve(this._user);
     }
 
     // If no cached information, we try to get it from the persistent storage.
     return this._fxAccounts.getSignedInUser().then(
       user => {
         if (!user || !user.email) {
           log.debug("No signed in account");
           return Promise.resolve(null);
         }
 
         this._activeSession = user;
         // If we get a stored information of a not yet verified account,
-        // we check this information with the server, update the stored
-        // data if needed and finally return the account details.
+        // we kick off verification before returning what we have.
         if (!user.verified && !Services.io.offline) {
           log.debug("Unverified account");
-          return this.verificationStatus(user);
+          this.verificationStatus(user);
         }
 
         log.debug("Account " + JSON.stringify(this._user));
         return Promise.resolve(this._user);
       }
     );
   },
 
@@ -310,54 +309,45 @@ this.FxAccountsManager = {
       },
       reason => { this._serverError(reason); }
     );
   },
 
   verificationStatus: function() {
     log.debug("verificationStatus");
     if (!this._activeSession || !this._activeSession.sessionToken) {
-      return this._error(ERROR_NO_TOKEN_SESSION);
+      this._error(ERROR_NO_TOKEN_SESSION);
     }
 
     // There is no way to unverify an already verified account, so we just
     // return the account details of a verified account
     if (this._activeSession.verified) {
       log.debug("Account already verified");
-      return Promise.resolve(this._user);
+      return;
     }
 
     if (Services.io.offline) {
-      return this._error(ERROR_OFFLINE);
+      this._error(ERROR_OFFLINE);
     }
 
     let client = this._getFxAccountsClient();
-    return client.recoveryEmailStatus(this._activeSession.sessionToken).then(
+    client.recoveryEmailStatus(this._activeSession.sessionToken).then(
       data => {
         let error = this._getError(data);
         if (error) {
-          return this._error(error, data);
+          this._error(error, data);
         }
-
-        // If the verification status is different from the one that we have
-        // stored, we update it and return the session data. If not, we simply
-        // return the session data.
+        // If the verification status has changed, update state.
         if (this._activeSession.verified != data.verified) {
           this._activeSession.verified = data.verified;
-          return this._fxAccounts.setSignedInUser(this._activeSession).then(
-            () => {
-              log.debug(JSON.stringify(this._user));
-              return Promise.resolve(this._user);
-            }
-          );
+          this._fxAccounts.setSignedInUser(this._activeSession);
         }
         log.debug(JSON.stringify(this._user));
-        return Promise.resolve(this._user);
       },
-      reason => { return this._serverError(reason); }
+      reason => { this._serverError(reason); }
     );
   },
 
   /*
    * Try to get an assertion for the given audience.
    *
    * aOptions can include:
    *
@@ -410,17 +400,17 @@ this.FxAccountsManager = {
             }
           }
 
           return this._getAssertion(aAudience);
         }
 
         log.debug("No signed in user");
 
-        if (aOptions.silent) {
+        if (aOptions && aOptions.silent) {
           return Promise.resolve(null);
         }
 
         // If there is no currently signed in user, we trigger the signIn UI
         // flow.
         return this._uiRequest(UI_REQUEST_SIGN_IN_FLOW, aAudience);
       }
     );
--- a/services/fxaccounts/tests/xpcshell/test_manager.js
+++ b/services/fxaccounts/tests/xpcshell/test_manager.js
@@ -440,28 +440,27 @@ add_test(function(test_getAccount_existi
   );
 });
 
 add_test(function(test_getAccount_existing_unverified_session_verified_user) {
   do_print("= getAccount, existing unverified session, verified user =");
   FxAccountsManager._activeSession.verified = false;
   FxAccountsManager._fxAccounts._signedInUser.verified = false;
   FakeFxAccountsClient._verified = true;
-  FxAccountsManager.getAccount().then(
-    result => {
-      do_check_true(FakeFxAccountsClient._recoveryEmailStatusCalled);
-      do_check_true(result.verified);
-      do_check_eq(result.accountId, FxAccountsManager._user.accountId);
-      FakeFxAccountsClient._reset();
-      run_next_test();
-    },
-    error => {
-      do_throw("Unexpected error: " + error);
-    }
-  );
+  FxAccountsManager.getAccount();
+  do_execute_soon(function() {
+    do_check_true(FakeFxAccountsClient._recoveryEmailStatusCalled);
+    FxAccountsManager.getAccount().then(
+      result => {
+        do_check_true(result.verified);
+        do_check_eq(result.accountId, FxAccountsManager._user.accountId);
+        FakeFxAccountsClient._reset();
+        run_next_test();
+    });
+  });
 });
 
 add_test(function(test_signOut) {
   do_print("= signOut =");
   do_check_true(FxAccountsManager._activeSession != null);
   FxAccountsManager.signOut().then(
     result => {
       do_check_null(result);
@@ -470,30 +469,16 @@ add_test(function(test_signOut) {
       run_next_test();
     },
     error => {
       do_throw("Unexpected error: " + error);
     }
   );
 });
 
-add_test(function(test_verificationStatus_no_token_session) {
-  do_print("= verificationStatus, no token session =");
-  do_check_null(FxAccountsManager._activeSession);
-  FxAccountsManager.verificationStatus().then(
-    () => {
-      do_throw("Unexpected success");
-    },
-    error => {
-      do_check_eq(error.error, ERROR_NO_TOKEN_SESSION);
-      run_next_test();
-    }
-  );
-});
-
 add_test(function(test_signUp_no_accountId) {
   do_print("= signUp, no accountId=");
   FxAccountsManager.signUp().then(
     () => {
       do_throw("Unexpected success");
     },
     error => {
       do_check_eq(error.error, ERROR_INVALID_ACCOUNTID);
@@ -593,43 +578,37 @@ add_test(function(test_signIn_already_si
       run_next_test();
     }
   );
 });
 
 add_test(function(test_verificationStatus_unverified_session_unverified_user) {
   do_print("= verificationStatus unverified session and user =");
   FakeFxAccountsClient._verified = false;
-  FxAccountsManager.verificationStatus().then(
-    user => {
-      do_check_false(user.verified);
-      do_check_true(FakeFxAccountsClient._recoveryEmailStatusCalled);
-      do_check_false(FxAccountsManager._fxAccounts._setSignedInUserCalled);
-      run_next_test();
-    },
-    error => {
-      do_throw("Unexpected error: " + error);
-    }
-  );
+  FxAccountsManager.verificationStatus();
+  do_execute_soon(function() {
+    let user = FxAccountsManager._user;
+    do_check_false(user.verified);
+    do_check_true(FakeFxAccountsClient._recoveryEmailStatusCalled);
+    do_check_false(FxAccountsManager._fxAccounts._setSignedInUserCalled);
+    run_next_test();
+  });
 });
 
 add_test(function(test_verificationStatus_unverified_session_verified_user) {
   do_print("= verificationStatus unverified session, verified user =");
   FakeFxAccountsClient._verified = true;
-  FxAccountsManager.verificationStatus().then(
-    user => {
-      do_check_true(user.verified);
-      do_check_true(FakeFxAccountsClient._recoveryEmailStatusCalled);
-      do_check_true(FxAccountsManager._fxAccounts._setSignedInUserCalled);
-      run_next_test();
-    },
-    error => {
-      do_throw("Unexpected error: " + error);
-    }
-  );
+  FxAccountsManager.verificationStatus();
+  do_execute_soon(function() {
+    let user = FxAccountsManager._user;
+    do_check_true(user.verified);
+    do_check_true(FakeFxAccountsClient._recoveryEmailStatusCalled);
+    do_check_true(FxAccountsManager._fxAccounts._setSignedInUserCalled);
+    run_next_test();
+  });
 });
 
 add_test(function(test_queryAccount_no_exists) {
   do_print("= queryAccount, no exists =");
   FxAccountsManager.queryAccount("user@domain.org").then(
     result => {
       do_check_false(result.registered);
       run_next_test();
--- a/toolkit/devtools/apps/tests/test_webapps_actor.html
+++ b/toolkit/devtools/apps/tests/test_webapps_actor.html
@@ -79,17 +79,18 @@ var steps = [
     SpecialPowers.addPermission("embed-apps", true, document);
 
     // Required on firefox as these prefs are only set on b2g:
     SpecialPowers.pushPrefEnv({
       set: [["dom.mozBrowserFramesEnabled", true],
             ["security.apps.privileged.CSP.default",
              "default-src *; script-src 'self'; object-src 'none'; style-src 'self' 'unsafe-inline'"],
             ["devtools.debugger.unix-domain-socket", 6000],
-            ["devtools.debugger.prompt-connection", false]
+            ["devtools.debugger.prompt-connection", false],
+            ["devtools.debugger.forbid-certified-apps", true]
            ]
     }, next);
   },
   function () {
     // Load a chrome script in order to dispatch devtool debugger requests.
     // Because of wrapping issues, we can't use SpecialPowers.Cu.import to load
     // devtools jsm into mochitest scope. We end up not receiving
     // DebuggerClient.addListener callback arguments...
--- a/xpcom/base/moz.build
+++ b/xpcom/base/moz.build
@@ -17,16 +17,17 @@ XPIDL_SOURCES += [
     'nsIInterfaceRequestor.idl',
     'nsIMemory.idl',
     'nsIMemoryInfoDumper.idl',
     'nsIMemoryReporter.idl',
     'nsIMessageLoop.idl',
     'nsIMutable.idl',
     'nsIProgrammingLanguage.idl',
     'nsISecurityConsoleMessage.idl',
+    'nsIStatusReporter.idl',
     'nsISupports.idl',
     'nsIUUIDGenerator.idl',
     'nsIVersionComparator.idl',
     'nsIVisualEventTracer.idl',
     'nsIWeakReference.idl',
     'nsrootidl.idl',
 ]
 
@@ -91,24 +92,26 @@ SOURCES['nsDebugImpl.cpp'].no_pgo = True
 UNIFIED_SOURCES += [
     'AvailableMemoryTracker.cpp',
     'ClearOnShutdown.cpp',
     'CycleCollectedJSRuntime.cpp',
     'Debug.cpp',
     'nsConsoleMessage.cpp',
     'nsConsoleService.cpp',
     'nsCycleCollector.cpp',
+    'nsDumpUtils.cpp',
     'nsErrorService.cpp',
     'nsGZFileWriter.cpp',
     'nsInterfaceRequestorAgg.cpp',
     'nsMemoryImpl.cpp',
     'nsMemoryInfoDumper.cpp',
     'nsMemoryReporterManager.cpp',
     'nsMessageLoop.cpp',
     'nsSecurityConsoleMessage.cpp',
+    'nsStatusReporterManager.cpp',
     'nsSystemInfo.cpp',
     'nsTraceRefcnt.cpp',
     'nsUUIDGenerator.cpp',
     'nsVersionComparatorImpl.cpp',
     'VisualEventTracer.cpp',
 ]
 
 # On Windows, NS_StackWalk will only work correctly if we have frame pointers available.
--- a/xpcom/base/nsCycleCollector.cpp
+++ b/xpcom/base/nsCycleCollector.cpp
@@ -168,17 +168,17 @@
 #include "prenv.h"
 #include "nsPrintfCString.h"
 #include "nsTArray.h"
 #include "nsIConsoleService.h"
 #include "mozilla/Attributes.h"
 #include "nsICycleCollectorListener.h"
 #include "nsIMemoryReporter.h"
 #include "nsIFile.h"
-#include "nsMemoryInfoDumper.h"
+#include "nsDumpUtils.h"
 #include "xpcpublic.h"
 #include "GeckoProfiler.h"
 #include "js/SliceBudget.h"
 #include <stdint.h>
 #include <stdio.h>
 
 #include "mozilla/Likely.h"
 #include "mozilla/PoisonIOInterposer.h"
@@ -1722,17 +1722,24 @@ private:
         // the fallback directories in OpenTempFile.  We don't use an nsCOMPtr
         // here because OpenTempFile uses an in/out param and getter_AddRefs
         // wouldn't work.
         nsIFile* logFile = nullptr;
         if (char* env = PR_GetEnv("MOZ_CC_LOG_DIRECTORY")) {
             NS_NewNativeLocalFile(nsCString(env), /* followLinks = */ true,
                                   &logFile);
         }
-        nsresult rv = nsMemoryInfoDumper::OpenTempFile(filename, &logFile);
+
+        // In Android case, this function will open a file named aFilename under
+        // specific folder (/data/local/tmp/memory-reports). Otherwise, it will
+        // open a file named aFilename under "NS_OS_TEMP_DIR".
+        nsresult rv = nsDumpUtils::OpenTempFile(
+                                     filename,
+                                     &logFile,
+                                     NS_LITERAL_CSTRING("memory-reports"));
         if (NS_FAILED(rv)) {
           NS_IF_RELEASE(logFile);
           return nullptr;
         }
 
         return dont_AddRef(logFile);
     }
 
new file mode 100644
--- /dev/null
+++ b/xpcom/base/nsDumpUtils.cpp
@@ -0,0 +1,476 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "nsDumpUtils.h"
+#include "nsDirectoryServiceDefs.h"
+#include "nsDirectoryServiceUtils.h"
+#include "prenv.h"
+#include <errno.h>
+#include "mozilla/Services.h"
+#include "nsIObserverService.h"
+ #include "mozilla/ClearOnShutdown.h"
+
+#if defined(XP_LINUX) || defined(__FreeBSD__) // {
+#include "mozilla/Preferences.h"
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+/*
+ * The following code supports triggering a registered callback upon
+ * receiving a specific signal.
+ *
+ * Take about:memory for example, we register
+ * 1. doGCCCDump for doMemoryReport
+ * 2. doMemoryReport for sDumpAboutMemorySignum(SIGRTMIN)
+ *                       and sDumpAboutMemoryAfterMMUSignum(SIGRTMIN+1).
+ *
+ * When we receive one of these signals, we write the signal number to a pipe.
+ * The IO thread then notices that the pipe has been written to, and kicks off
+ * the appropriate task on the main thread.
+ *
+ * This scheme is similar to using signalfd(), except it's portable and it
+ * doesn't require the use of sigprocmask, which is problematic because it
+ * masks signals received by child processes.
+ *
+ * In theory, we could use Chromium's MessageLoopForIO::CatchSignal() for this.
+ * But that uses libevent, which does not handle the realtime signals (bug
+ * 794074).
+ */
+
+// This is the write-end of a pipe that we use to notice when a
+// specific signal occurs.
+static Atomic<int> sDumpPipeWriteFd(-1);
+
+static void
+DumpSignalHandler(int aSignum)
+{
+  // This is a signal handler, so everything in here needs to be
+  // async-signal-safe.  Be careful!
+
+  if (sDumpPipeWriteFd != -1) {
+    uint8_t signum = static_cast<int>(aSignum);
+    write(sDumpPipeWriteFd, &signum, sizeof(signum));
+  }
+}
+
+NS_IMPL_ISUPPORTS1(FdWatcher, nsIObserver);
+
+void FdWatcher::Init()
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  nsCOMPtr<nsIObserverService> os = services::GetObserverService();
+  os->AddObserver(this, "xpcom-shutdown", /* ownsWeak = */ false);
+
+  XRE_GetIOMessageLoop()->PostTask(
+      FROM_HERE,
+      NewRunnableMethod(this, &FdWatcher::StartWatching));
+}
+
+// Implementations may call this function multiple times if they ensure that
+// it's safe to call OpenFd() multiple times and they call StopWatching()
+// first.
+void FdWatcher::StartWatching()
+{
+  MOZ_ASSERT(XRE_GetIOMessageLoop() == MessageLoopForIO::current());
+  MOZ_ASSERT(mFd == -1);
+
+  mFd = OpenFd();
+  if (mFd == -1) {
+    LOG("FdWatcher: OpenFd failed.");
+    return;
+  }
+
+  MessageLoopForIO::current()->WatchFileDescriptor(
+    mFd, /* persistent = */ true,
+    MessageLoopForIO::WATCH_READ,
+    &mReadWatcher, this);
+}
+
+// Since implementations can call StartWatching() multiple times, they can of
+// course call StopWatching() multiple times.
+void FdWatcher::StopWatching()
+{
+  MOZ_ASSERT(XRE_GetIOMessageLoop() == MessageLoopForIO::current());
+
+  mReadWatcher.StopWatchingFileDescriptor();
+  if (mFd != -1) {
+    close(mFd);
+    mFd = -1;
+  }
+}
+
+StaticRefPtr<SignalPipeWatcher> SignalPipeWatcher::sSingleton;
+
+/* static */ SignalPipeWatcher*
+SignalPipeWatcher::GetSingleton()
+{
+  if (!sSingleton) {
+    sSingleton = new SignalPipeWatcher();
+    sSingleton->Init();
+    ClearOnShutdown(&sSingleton);
+  }
+  return sSingleton;
+}
+
+/* static */ void
+SignalPipeWatcher::RegisterCallback(const uint8_t aSignal,
+                                    PipeCallback aCallback)
+{
+  for (SignalInfoArray::index_type i = 0; 
+       i < SignalPipeWatcher::mSignalInfo.Length(); i++)
+  {
+    if (SignalPipeWatcher::mSignalInfo[i].mSignal == aSignal) {
+      LOG("Register Signal(%d) callback failed! (DUPLICATE)", aSignal);
+      return;
+    }
+  }
+  SignalInfo aSignalInfo = { aSignal, aCallback };
+  SignalPipeWatcher::mSignalInfo.AppendElement(aSignalInfo);
+  SignalPipeWatcher::RegisterSignalHandler(aSignalInfo.mSignal);
+}
+
+/* static */ void
+SignalPipeWatcher::RegisterSignalHandler(const uint8_t aSignal)
+{
+  struct sigaction action;
+  memset(&action, 0, sizeof(action));
+  sigemptyset(&action.sa_mask);
+  action.sa_handler = DumpSignalHandler;
+
+  if (aSignal) {
+    if (sigaction(aSignal, &action, nullptr)) {
+      LOG("SignalPipeWatcher failed to register sig %d.", aSignal);
+    }
+  } else {
+    for (SignalInfoArray::index_type i = 0; i < SignalPipeWatcher::mSignalInfo.Length(); i++) {
+      if (sigaction(SignalPipeWatcher::mSignalInfo[i].mSignal, &action, nullptr)) {
+        LOG("SignalPipeWatcher failed to register signal(%d) "
+            "dump signal handler.",SignalPipeWatcher::mSignalInfo[i].mSignal);
+      }
+    }
+  }
+}
+
+SignalPipeWatcher::~SignalPipeWatcher()
+{
+  if (sDumpPipeWriteFd != -1)
+    SignalPipeWatcher::StopWatching();
+}
+
+int SignalPipeWatcher::OpenFd()
+{
+  MOZ_ASSERT(XRE_GetIOMessageLoop() == MessageLoopForIO::current());
+
+  // Create a pipe.  When we receive a signal in our signal handler, we'll
+  // write the signum to the write-end of this pipe.
+  int pipeFds[2];
+  if (pipe(pipeFds)) {
+    LOG("SignalPipeWatcher failed to create pipe.");
+    return -1;
+  }
+
+  // Close this pipe on calls to exec().
+  fcntl(pipeFds[0], F_SETFD, FD_CLOEXEC);
+  fcntl(pipeFds[1], F_SETFD, FD_CLOEXEC);
+
+  int readFd = pipeFds[0];
+  sDumpPipeWriteFd = pipeFds[1];
+
+  SignalPipeWatcher::RegisterSignalHandler();
+  return readFd;
+}
+
+void SignalPipeWatcher::StopWatching()
+{
+  MOZ_ASSERT(XRE_GetIOMessageLoop() == MessageLoopForIO::current());
+
+  // Close sDumpPipeWriteFd /after/ setting the fd to -1.
+  // Otherwise we have the (admittedly far-fetched) race where we
+  //
+  //  1) close sDumpPipeWriteFd
+  //  2) open a new fd with the same number as sDumpPipeWriteFd
+  //     had.
+  //  3) receive a signal, then write to the fd.
+  int pipeWriteFd = sDumpPipeWriteFd.exchange(-1);
+  close(pipeWriteFd);
+
+  FdWatcher::StopWatching();
+}
+
+void SignalPipeWatcher::OnFileCanReadWithoutBlocking(int aFd)
+{
+  MOZ_ASSERT(XRE_GetIOMessageLoop() == MessageLoopForIO::current());
+
+  uint8_t signum;
+  ssize_t numReceived = read(aFd, &signum, sizeof(signum));
+  if (numReceived != sizeof(signum)) {
+    LOG("Error reading from buffer in "
+        "SignalPipeWatcher::OnFileCanReadWithoutBlocking.");
+    return;
+  }
+
+  for (SignalInfoArray::index_type i = 0; i < SignalPipeWatcher::mSignalInfo.Length(); i++) {
+    if(signum == SignalPipeWatcher::mSignalInfo[i].mSignal) {
+      SignalPipeWatcher::mSignalInfo[i].mCallback(signum);
+      return;
+    }
+  }
+  LOG("SignalPipeWatcher got unexpected signum.");
+}
+
+StaticRefPtr<FifoWatcher> FifoWatcher::sSingleton;
+
+/* static */ FifoWatcher*
+FifoWatcher::GetSingleton()
+{
+  if (!sSingleton) {
+    nsAutoCString dirPath;
+    Preferences::GetCString(
+      "memory_info_dumper.watch_fifo.directory", &dirPath);
+    sSingleton = new FifoWatcher(dirPath);
+    sSingleton->Init();
+    ClearOnShutdown(&sSingleton);
+  }
+  return sSingleton;
+}
+
+/* static */ bool
+FifoWatcher::MaybeCreate()
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  if (XRE_GetProcessType() != GeckoProcessType_Default) {
+    // We want this to be main-process only, since two processes can't listen
+    // to the same fifo.
+    return false;
+  }
+
+  if (!Preferences::GetBool("memory_info_dumper.watch_fifo.enabled", false)) {
+    LOG("Fifo watcher disabled via pref.");
+    return false;
+  }
+
+  // The FifoWatcher is held alive by the observer service.
+  if (!FifoWatcher::sSingleton) {
+    FifoWatcher::GetSingleton();
+  }
+  return true;
+}
+
+void
+FifoWatcher::RegisterCallback(const nsCString& aCommand,FifoCallback aCallback)
+{
+  for (FifoInfoArray::index_type i = 0;
+       i < FifoWatcher::mFifoInfo.Length(); i++)
+  {
+    if (FifoWatcher::mFifoInfo[i].mCommand.Equals(aCommand)) {
+      LOG("Register command(%s) callback failed! (DUPLICATE)", aCommand.get());
+      return;
+    }
+  }
+  FifoInfo aFifoInfo = { aCommand, aCallback };
+  FifoWatcher::mFifoInfo.AppendElement(aFifoInfo);
+}
+
+FifoWatcher::~FifoWatcher()
+{
+}
+
+int FifoWatcher::OpenFd()
+{
+  // If the memory_info_dumper.directory pref is specified, put the fifo
+  // there.  Otherwise, put it into the system's tmp directory.
+
+  nsCOMPtr<nsIFile> file;
+
+  nsresult rv;
+  if (mDirPath.Length() > 0) {
+    rv = XRE_GetFileFromPath(mDirPath.get(), getter_AddRefs(file));
+    if (NS_FAILED(rv)) {
+      LOG("FifoWatcher failed to open file \"%s\"", mDirPath.get());
+      return -1;
+    }
+  } else {
+    rv = NS_GetSpecialDirectory(NS_OS_TEMP_DIR, getter_AddRefs(file));
+    if (NS_WARN_IF(NS_FAILED(rv)))
+      return -1;
+  }
+
+  rv = file->AppendNative(NS_LITERAL_CSTRING("debug_info_trigger"));
+  if (NS_WARN_IF(NS_FAILED(rv)))
+    return -1;
+
+  nsAutoCString path;
+  rv = file->GetNativePath(path);
+  if (NS_WARN_IF(NS_FAILED(rv)))
+    return -1;
+
+  // unlink might fail because the file doesn't exist, or for other reasons.
+  // But we don't care it fails; any problems will be detected later, when we
+  // try to mkfifo or open the file.
+  if (unlink(path.get())) {
+    LOG("FifoWatcher::OpenFifo unlink failed; errno=%d.  "
+        "Continuing despite error.", errno);
+  }
+
+  if (mkfifo(path.get(), 0766)) {
+    LOG("FifoWatcher::OpenFifo mkfifo failed; errno=%d", errno);
+    return -1;
+  }
+
+#ifdef ANDROID
+    // Android runs with a umask, so we need to chmod our fifo to make it
+    // world-writable.
+    chmod(path.get(), 0666);
+#endif
+
+  int fd;
+  do {
+    // The fifo will block until someone else has written to it.  In
+    // particular, open() will block until someone else has opened it for
+    // writing!  We want open() to succeed and read() to block, so we open
+    // with NONBLOCK and then fcntl that away.
+    fd = open(path.get(), O_RDONLY | O_NONBLOCK);
+  } while (fd == -1 && errno == EINTR);
+
+  if (fd == -1) {
+    LOG("FifoWatcher::OpenFifo open failed; errno=%d", errno);
+    return -1;
+  }
+
+  // Make fd blocking now that we've opened it.
+  if (fcntl(fd, F_SETFL, 0)) {
+    close(fd);
+    return -1;
+  }
+
+  return fd;
+}
+
+void FifoWatcher::OnFileCanReadWithoutBlocking(int aFd)
+{
+  MOZ_ASSERT(XRE_GetIOMessageLoop() == MessageLoopForIO::current());
+
+  char buf[1024];
+  int nread;
+  do {
+    // sizeof(buf) - 1 to leave space for the null-terminator.
+    nread = read(aFd, buf, sizeof(buf));
+  } while(nread == -1 && errno == EINTR);
+
+  if (nread == -1) {
+    // We want to avoid getting into a situation where
+    // OnFileCanReadWithoutBlocking is called in an infinite loop, so when
+    // something goes wrong, stop watching the fifo altogether.
+    LOG("FifoWatcher hit an error (%d) and is quitting.", errno);
+    StopWatching();
+    return;
+  }
+
+  if (nread == 0) {
+    // If we get EOF, that means that the other side closed the fifo.  We need
+    // to close and re-open the fifo; if we don't,
+    // OnFileCanWriteWithoutBlocking will be called in an infinite loop.
+
+    LOG("FifoWatcher closing and re-opening fifo.");
+    StopWatching();
+    StartWatching();
+    return;
+  }
+
+  nsAutoCString inputStr;
+  inputStr.Append(buf, nread);
+
+  // Trimming whitespace is important because if you do
+  //   |echo "foo" >> debug_info_trigger|,
+  // it'll actually write "foo\n" to the fifo.
+  inputStr.Trim("\b\t\r\n");
+
+  for (FifoInfoArray::index_type i = 0; i < FifoWatcher::mFifoInfo.Length(); i++) {
+    const nsCString commandStr = FifoWatcher::mFifoInfo[i].mCommand;
+    if(inputStr == commandStr.get()) {
+      FifoWatcher::mFifoInfo[i].mCallback(inputStr);
+      return;
+    }
+  }
+  LOG("Got unexpected value from fifo; ignoring it.");
+}
+
+#endif // XP_LINUX }
+
+// In Android case, this function will open a file named aFilename under
+// /data/local/tmp/"aFoldername".
+// Otherwise, it will open a file named aFilename under "NS_OS_TEMP_DIR".
+/* static */ nsresult
+nsDumpUtils::OpenTempFile(const nsACString& aFilename, nsIFile** aFile,
+                          const nsACString& aFoldername)
+{
+#ifdef ANDROID
+  // For Android, first try the downloads directory which is world-readable
+  // rather than the temp directory which is not.
+  if (!*aFile) {
+    char *env = PR_GetEnv("DOWNLOADS_DIRECTORY");
+    if (env) {
+      NS_NewNativeLocalFile(nsCString(env), /* followLinks = */ true, aFile);
+    }
+  }
+#endif
+  nsresult rv;
+  if (!*aFile) {
+    rv = NS_GetSpecialDirectory(NS_OS_TEMP_DIR, aFile);
+    if (NS_WARN_IF(NS_FAILED(rv)))
+      return rv;
+  }
+
+#ifdef ANDROID
+  // /data/local/tmp is a true tmp directory; anyone can create a file there,
+  // but only the user which created the file can remove it.  We want non-root
+  // users to be able to remove these files, so we write them into a
+  // subdirectory of the temp directory and chmod 777 that directory.
+  if (aFoldername != EmptyCString()) {
+    rv = (*aFile)->AppendNative(aFoldername);
+    if (NS_WARN_IF(NS_FAILED(rv)))
+      return rv;
+
+    // It's OK if this fails; that probably just means that the directory already
+    // exists.
+    (*aFile)->Create(nsIFile::DIRECTORY_TYPE, 0777);
+
+    nsAutoCString dirPath;
+    rv = (*aFile)->GetNativePath(dirPath);
+    if (NS_WARN_IF(NS_FAILED(rv)))
+      return rv;
+
+    while (chmod(dirPath.get(), 0777) == -1 && errno == EINTR) {}
+  }
+#endif
+
+  nsCOMPtr<nsIFile> file(*aFile);
+
+  rv = file->AppendNative(aFilename);
+  if (NS_WARN_IF(NS_FAILED(rv)))
+    return rv;
+
+  rv = file->CreateUnique(nsIFile::NORMAL_FILE_TYPE, 0666);
+  if (NS_WARN_IF(NS_FAILED(rv)))
+    return rv;
+
+#ifdef ANDROID
+    // Make this file world-read/writable; the permissions passed to the
+    // CreateUnique call above are not sufficient on Android, which runs with a
+    // umask.
+    nsAutoCString path;
+    rv = file->GetNativePath(path);
+    if (NS_WARN_IF(NS_FAILED(rv)))
+      return rv;
+
+    while (chmod(path.get(), 0666) == -1 && errno == EINTR) {}
+#endif
+
+  return NS_OK;
+}
new file mode 100644
--- /dev/null
+++ b/xpcom/base/nsDumpUtils.h
@@ -0,0 +1,187 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* 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/. */
+
+#ifndef mozilla_nsDumpUtils_h
+#define mozilla_nsDumpUtils_h
+
+#include "nsIObserver.h"
+#include "base/message_loop.h"
+#include "nsXULAppAPI.h"
+#include "nsThreadUtils.h"
+#include "mozilla/StaticPtr.h"
+#include "nsTArray.h"
+
+#ifdef LOG
+#undef LOG
+#endif
+
+#ifdef ANDROID
+#include "android/log.h"
+#define LOG(...) __android_log_print(ANDROID_LOG_INFO, "Gecko:DumpUtils", ## __VA_ARGS__)
+#else
+#define LOG(...)
+#endif
+
+using namespace mozilla;
+
+#if defined(XP_LINUX) || defined(__FreeBSD__) // {
+
+/**
+ * Abstract base class for something which watches an fd and takes action when
+ * we can read from it without blocking.
+ */
+class FdWatcher : public MessageLoopForIO::Watcher
+                , public nsIObserver
+{
+protected:
+  MessageLoopForIO::FileDescriptorWatcher mReadWatcher;
+  int mFd;
+
+public:
+  FdWatcher()
+    : mFd(-1)
+  {
+    MOZ_ASSERT(NS_IsMainThread());
+  }
+
+  virtual ~FdWatcher()
+  {
+    // StopWatching should have run.
+    MOZ_ASSERT(mFd == -1);
+  }
+
+  /**
+   * Open the fd to watch.  If we encounter an error, return -1.
+   */
+  virtual int OpenFd() = 0;
+
+  /**
+   * Called when you can read() from the fd without blocking.  Note that this
+   * function is also called when you're at eof (read() returns 0 in this case).
+   */
+  virtual void OnFileCanReadWithoutBlocking(int aFd) = 0;
+  virtual void OnFileCanWriteWithoutBlocking(int aFd) {};
+
+  NS_DECL_THREADSAFE_ISUPPORTS
+
+  /**
+   * Initialize this object.  This should be called right after the object is
+   * constructed.  (This would go in the constructor, except we interact with
+   * XPCOM, which we can't do from a constructor because our refcount is 0 at
+   * that point.)
+   */
+  void Init();
+
+  // Implementations may call this function multiple times if they ensure that
+
+  virtual void StartWatching();
+
+  // Since implementations can call StartWatching() multiple times, they can of
+  // course call StopWatching() multiple times.
+  virtual void StopWatching();
+
+  NS_IMETHOD Observe(nsISupports* aSubject, const char* aTopic,
+                     const char16_t* aData)
+  {
+    MOZ_ASSERT(NS_IsMainThread());
+    MOZ_ASSERT(!strcmp(aTopic, "xpcom-shutdown"));
+
+    XRE_GetIOMessageLoop()->PostTask(
+        FROM_HERE,
+        NewRunnableMethod(this, &FdWatcher::StopWatching));
+
+    return NS_OK;
+  }
+};
+
+typedef void (* FifoCallback)(const nsCString& inputStr);
+struct FifoInfo {
+  nsCString mCommand;
+  FifoCallback mCallback;
+};
+typedef nsTArray<FifoInfo> FifoInfoArray;
+
+class FifoWatcher : public FdWatcher
+{
+public:
+  static FifoWatcher* GetSingleton();
+
+  static bool MaybeCreate();
+
+  void RegisterCallback(const nsCString& aCommand, FifoCallback aCallback);
+
+  virtual ~FifoWatcher();
+
+  virtual int OpenFd();
+
+  virtual void OnFileCanReadWithoutBlocking(int aFd);
+
+private:
+  nsAutoCString mDirPath;
+
+  static StaticRefPtr<FifoWatcher> sSingleton;
+
+  FifoWatcher(nsCString aPath)
+    : mDirPath(aPath)
+  {}
+
+  FifoInfoArray mFifoInfo;
+};
+
+typedef void (* PipeCallback)(const uint8_t recvSig);
+struct SignalInfo {
+  uint8_t mSignal;
+  PipeCallback mCallback;
+};
+typedef nsTArray<SignalInfo> SignalInfoArray;
+
+class SignalPipeWatcher : public FdWatcher
+{
+public:
+  static SignalPipeWatcher* GetSingleton();
+
+  void RegisterCallback(const uint8_t aSignal, PipeCallback aCallback);
+
+  void RegisterSignalHandler(const uint8_t aSignal = 0);
+
+  virtual ~SignalPipeWatcher();
+
+  virtual int OpenFd();
+
+  virtual void StopWatching();
+
+  virtual void OnFileCanReadWithoutBlocking(int aFd);
+
+private:
+  static StaticRefPtr<SignalPipeWatcher> sSingleton;
+
+  SignalPipeWatcher()
+  {
+    MOZ_ASSERT(NS_IsMainThread());
+  }
+
+  SignalInfoArray mSignalInfo;
+};
+
+#endif // XP_LINUX }
+
+
+class nsDumpUtils
+{
+public:
+  /**
+   * This function creates a new unique file based on |aFilename| in a
+   * world-readable temp directory. This is the system temp directory
+   * or, in the case of Android, the downloads directory. If |aFile| is
+   * non-null, it is assumed to point to a folder, and that folder is used
+   * instead.
+   */
+  static nsresult OpenTempFile(const nsACString& aFilename,
+                        nsIFile** aFile,
+                        const nsACString& aFoldername = EmptyCString());
+};
+
+#endif
new file mode 100644
--- /dev/null
+++ b/xpcom/base/nsIStatusReporter.idl
@@ -0,0 +1,89 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "nsISupports.idl"
+
+interface nsISimpleEnumerator;
+
+/*
+ * Status reporters show Firefox's service status.
+ */
+
+[scriptable, uuid(ffcb716c-deeb-44ea-9d9d-ab25dc6980a8)]
+interface nsIStatusReporter : nsISupports
+{
+  readonly attribute ACString name;
+  /*
+   * The name of the process containing this reporter.  Each reporter initially
+   * has "" in this field, indicating that it applies to the current process.
+   */
+  readonly attribute ACString process;
+  /*
+   * A human-readable status description.
+   */
+  readonly attribute AUTF8String description;
+};
+
+[scriptable, uuid(fd531273-3319-4fcd-90f2-9f53876c3828)]
+interface nsIStatusReporterManager : nsISupports
+{
+
+  /*
+   * Return an enumerator of nsIStatusReporters that are currently registered.
+   */
+  nsISimpleEnumerator enumerateReporters();
+
+  /*
+   * Register the given nsIStatusReporter.  After a reporter is registered,
+   * it will be available via enumerateReporters().  The Manager service
+   * will hold a strong reference to the given reporter.
+   */
+  void registerReporter(in nsIStatusReporter reporter);
+
+  /*
+   * Unregister the given status reporter.
+   */
+  void unregisterReporter(in nsIStatusReporter reporter);
+
+ /*
+  * Initialize.
+  */
+  void init();
+
+  /*
+   * Dump service status as a json file
+   */
+  void dumpReports();
+};
+
+%{C++
+
+/*
+ * Note that this defaults 'process' to "", which is usually what's desired.
+ */
+#define NS_STATUS_REPORTER_IMPLEMENT(_classname, _name, _desc_Function)       \
+    class StatusReporter_##_classname MOZ_FINAL : public nsIStatusReporter {  \
+    public:                                                                   \
+      NS_DECL_ISUPPORTS                                                       \
+      NS_IMETHOD GetName(nsACString &name)                                    \
+        { name.AssignLiteral(_name); return NS_OK; }                          \
+      NS_IMETHOD GetProcess(nsACString &process)                              \
+        { process.Truncate(); return NS_OK; }                                 \
+      NS_IMETHOD GetDescription(nsACString &desc)                             \
+        { _desc_Function(desc); return NS_OK; }                               \
+    };                                                                        \
+    NS_IMPL_ISUPPORTS1(StatusReporter_##_classname, nsIStatusReporter)
+
+#define NS_STATUS_REPORTER_NAME(_classname)  StatusReporter_##_classname
+
+nsresult NS_RegisterStatusReporter(nsIStatusReporter *reporter);
+nsresult NS_UnregisterStatusReporter(nsIStatusReporter *reporter);
+nsresult NS_DumpStatusReporter();
+
+#define NS_STATUS_REPORTER_MANAGER_CID \
+{ 0xe8eb4e7e, 0xf2cf, 0x45e5, \
+{ 0xb8, 0xa4, 0x6a, 0x0f, 0x50, 0x18, 0x84, 0x63 } }
+%}
--- a/xpcom/base/nsMemoryInfoDumper.cpp
+++ b/xpcom/base/nsMemoryInfoDumper.cpp
@@ -1,61 +1,44 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "mozilla/nsMemoryInfoDumper.h"
+#include "nsDumpUtils.h"
 
-#if defined(XP_LINUX) || defined(__FreeBSD__)
-#include "mozilla/Preferences.h"
-#endif
 #include "mozilla/unused.h"
 #include "mozilla/dom/ContentParent.h"
 #include "mozilla/dom/ContentChild.h"
 #include "nsIConsoleService.h"
 #include "nsICycleCollectorListener.h"
 #include "nsIMemoryReporter.h"
 #include "nsDirectoryServiceDefs.h"
 #include "nsGZFileWriter.h"
 #include "nsJSEnvironment.h"
 #include "nsPrintfCString.h"
 #include "nsISimpleEnumerator.h"
 #include "nsServiceManagerUtils.h"
 #include "nsIFile.h"
-#include <errno.h>
 
 #ifdef XP_WIN
 #include <process.h>
 #define getpid _getpid
 #else
 #include <unistd.h>
 #endif
 
 #if defined(XP_LINUX) || defined(__FreeBSD__)
 #include <fcntl.h>
 #include <sys/types.h>
 #include <sys/stat.h>
 #endif
 
-#ifdef ANDROID
-#include "android/log.h"
-#endif
-
-#ifdef LOG
-#undef LOG
-#endif
-
-#ifdef ANDROID
-#define LOG(...) __android_log_print(ANDROID_LOG_INFO, "Gecko:MemoryInfoDumper", ## __VA_ARGS__)
-#else
-#define LOG(...)
-#endif
-
 using namespace mozilla;
 using namespace mozilla::dom;
 
 namespace {
 
 class DumpMemoryInfoToTempDirRunnable : public nsRunnable
 {
 public:
@@ -131,419 +114,63 @@ namespace {
  *
  * In theory, we could use Chromium's MessageLoopForIO::CatchSignal() for this.
  * But that uses libevent, which does not handle the realtime signals (bug
  * 794074).
  */
 
 // It turns out that at least on some systems, SIGRTMIN is not a compile-time
 // constant, so these have to be set at runtime.
-static int sDumpAboutMemorySignum;         // SIGRTMIN
-static int sDumpAboutMemoryAfterMMUSignum; // SIGRTMIN + 1
-static int sGCAndCCDumpSignum;             // SIGRTMIN + 2
-
-// This is the write-end of a pipe that we use to notice when a
-// dump-about-memory signal occurs.
-static Atomic<int> sDumpAboutMemoryPipeWriteFd(-1);
+static uint8_t sDumpAboutMemorySignum;         // SIGRTMIN
+static uint8_t sDumpAboutMemoryAfterMMUSignum; // SIGRTMIN + 1
+static uint8_t sGCAndCCDumpSignum;             // SIGRTMIN + 2
 
-void
-DumpAboutMemorySignalHandler(int aSignum)
+void doMemoryReport(const nsCString& inputStr)
 {
-  // This is a signal handler, so everything in here needs to be
-  // async-signal-safe.  Be careful!
-
-  if (sDumpAboutMemoryPipeWriteFd != -1) {
-    uint8_t signum = static_cast<int>(aSignum);
-    write(sDumpAboutMemoryPipeWriteFd, &signum, sizeof(signum));
-  }
+  bool doMMUMemoryReport = inputStr == NS_LITERAL_CSTRING("minimize memory report");
+  LOG("FifoWatcher(command:%s) dispatching memory report runnable.", inputStr.get());
+  nsRefPtr<DumpMemoryInfoToTempDirRunnable> runnable =
+    new DumpMemoryInfoToTempDirRunnable(/* identifier = */ EmptyString(),
+                                        doMMUMemoryReport);
+  NS_DispatchToMainThread(runnable);
 }
 
-/**
- * Abstract base class for something which watches an fd and takes action when
- * we can read from it without blocking.
- */
-class FdWatcher : public MessageLoopForIO::Watcher
-                , public nsIObserver
+void doMemoryReport(const uint8_t recvSig)
 {
-protected:
-  MessageLoopForIO::FileDescriptorWatcher mReadWatcher;
-  int mFd;
-
-public:
-  FdWatcher()
-    : mFd(-1)
-  {
-    MOZ_ASSERT(NS_IsMainThread());
-  }
-
-  virtual ~FdWatcher()
-  {
-    // StopWatching should have run.
-    MOZ_ASSERT(mFd == -1);
-  }
-
-  /**
-   * Open the fd to watch.  If we encounter an error, return -1.
-   */
-  virtual int OpenFd() = 0;
-
-  /**
-   * Called when you can read() from the fd without blocking.  Note that this
-   * function is also called when you're at eof (read() returns 0 in this case).
-   */
-  virtual void OnFileCanReadWithoutBlocking(int aFd) = 0;
-  virtual void OnFileCanWriteWithoutBlocking(int aFd) {};
-
-  NS_DECL_THREADSAFE_ISUPPORTS
-
-  /**
-   * Initialize this object.  This should be called right after the object is
-   * constructed.  (This would go in the constructor, except we interact with
-   * XPCOM, which we can't do from a constructor because our refcount is 0 at
-   * that point.)
-   */
-  void Init()
-  {
-    MOZ_ASSERT(NS_IsMainThread());
-
-    nsCOMPtr<nsIObserverService> os = services::GetObserverService();
-    os->AddObserver(this, "xpcom-shutdown", /* ownsWeak = */ false);
-
-    XRE_GetIOMessageLoop()->PostTask(
-        FROM_HERE,
-        NewRunnableMethod(this, &FdWatcher::StartWatching));
-  }
-
-  // Implementations may call this function multiple times if they ensure that
-  // it's safe to call OpenFd() multiple times and they call StopWatching()
-  // first.
-  virtual void StartWatching()
-  {
-    MOZ_ASSERT(XRE_GetIOMessageLoop() == MessageLoopForIO::current());
-    MOZ_ASSERT(mFd == -1);
-
-    mFd = OpenFd();
-    if (mFd == -1) {
-      LOG("FdWatcher: OpenFd failed.");
-      return;
-    }
-
-    MessageLoopForIO::current()->WatchFileDescriptor(
-      mFd, /* persistent = */ true,
-      MessageLoopForIO::WATCH_READ,
-      &mReadWatcher, this);
-  }
-
-  // Since implementations can call StartWatching() multiple times, they can of
-  // course call StopWatching() multiple times.
-  virtual void StopWatching()
-  {
-    MOZ_ASSERT(XRE_GetIOMessageLoop() == MessageLoopForIO::current());
-
-    mReadWatcher.StopWatchingFileDescriptor();
-    if (mFd != -1) {
-      close(mFd);
-      mFd = -1;
-    }
-  }
-
-  NS_IMETHOD Observe(nsISupports* aSubject, const char* aTopic,
-                     const char16_t* aData)
-  {
-    MOZ_ASSERT(NS_IsMainThread());
-    MOZ_ASSERT(!strcmp(aTopic, "xpcom-shutdown"));
-
-    XRE_GetIOMessageLoop()->PostTask(
-        FROM_HERE,
-        NewRunnableMethod(this, &FdWatcher::StopWatching));
-
-    return NS_OK;
-  }
-};
-
-NS_IMPL_ISUPPORTS1(FdWatcher, nsIObserver);
-
-class SignalPipeWatcher : public FdWatcher
-{
-public:
-  static void Create()
-  {
-    nsRefPtr<SignalPipeWatcher> sw = new SignalPipeWatcher();
-    sw->Init();
-  }
-
-  virtual ~SignalPipeWatcher()
-  {
-    MOZ_ASSERT(sDumpAboutMemoryPipeWriteFd == -1);
-  }
-
-  virtual int OpenFd()
-  {
-    MOZ_ASSERT(XRE_GetIOMessageLoop() == MessageLoopForIO::current());
-
-    sDumpAboutMemorySignum = SIGRTMIN;
-    sDumpAboutMemoryAfterMMUSignum = SIGRTMIN + 1;
-    sGCAndCCDumpSignum = SIGRTMIN + 2;
-
-    // Create a pipe.  When we receive a signal in our signal handler, we'll
-    // write the signum to the write-end of this pipe.
-    int pipeFds[2];
-    if (pipe(pipeFds)) {
-      LOG("SignalPipeWatcher failed to create pipe.");
-      return -1;
-    }
-
-    // Close this pipe on calls to exec().
-    fcntl(pipeFds[0], F_SETFD, FD_CLOEXEC);
-    fcntl(pipeFds[1], F_SETFD, FD_CLOEXEC);
-
-    int readFd = pipeFds[0];
-    sDumpAboutMemoryPipeWriteFd = pipeFds[1];
-
-    struct sigaction action;
-    memset(&action, 0, sizeof(action));
-    sigemptyset(&action.sa_mask);
-    action.sa_handler = DumpAboutMemorySignalHandler;
-
-    if (sigaction(sDumpAboutMemorySignum, &action, nullptr)) {
-      LOG("SignalPipeWatcher failed to register about:memory "
-          "dump signal handler.");
-    }
-    if (sigaction(sDumpAboutMemoryAfterMMUSignum, &action, nullptr)) {
-      LOG("SignalPipeWatcher failed to register about:memory "
-          "dump after MMU signal handler.");
-    }
-    if (sigaction(sGCAndCCDumpSignum, &action, nullptr)) {
-      LOG("Failed to register GC+CC dump signal handler.");
-    }
-
-    return readFd;
-  }
-
-  virtual void StopWatching()
-  {
-    MOZ_ASSERT(XRE_GetIOMessageLoop() == MessageLoopForIO::current());
-
-    // Close sDumpAboutMemoryPipeWriteFd /after/ setting the fd to -1.
-    // Otherwise we have the (admittedly far-fetched) race where we
-    //
-    //  1) close sDumpAboutMemoryPipeWriteFd
-    //  2) open a new fd with the same number as sDumpAboutMemoryPipeWriteFd
-    //     had.
-    //  3) receive a signal, then write to the fd.
-    int pipeWriteFd = sDumpAboutMemoryPipeWriteFd.exchange(-1);
-    close(pipeWriteFd);
-
-    FdWatcher::StopWatching();
-  }
-
-  virtual void OnFileCanReadWithoutBlocking(int aFd)
-  {
-    MOZ_ASSERT(XRE_GetIOMessageLoop() == MessageLoopForIO::current());
-
-    uint8_t signum;
-    ssize_t numReceived = read(aFd, &signum, sizeof(signum));
-    if (numReceived != sizeof(signum)) {
-      LOG("Error reading from buffer in "
-          "SignalPipeWatcher::OnFileCanReadWithoutBlocking.");
-      return;
-    }
+  // Dump our memory reports (but run this on the main thread!).
+  bool doMMUFirst = recvSig == sDumpAboutMemoryAfterMMUSignum;
+  LOG("SignalWatcher(sig %d) dispatching memory report runnable.", recvSig);
+  nsRefPtr<DumpMemoryInfoToTempDirRunnable> runnable =
+    new DumpMemoryInfoToTempDirRunnable(/* identifier = */ EmptyString(),
+                                        doMMUFirst);
+  NS_DispatchToMainThread(runnable);
+}
 
-    if (signum == sDumpAboutMemorySignum ||
-        signum == sDumpAboutMemoryAfterMMUSignum) {
-      // Dump our memory reports (but run this on the main thread!).
-      bool doMMUFirst = signum == sDumpAboutMemoryAfterMMUSignum;
-      nsRefPtr<DumpMemoryInfoToTempDirRunnable> runnable =
-        new DumpMemoryInfoToTempDirRunnable(/* identifier = */ EmptyString(),
-                                            doMMUFirst);
-      NS_DispatchToMainThread(runnable);
-    }
-    else if (signum == sGCAndCCDumpSignum) {
-      // Dump GC and CC logs (from the main thread).
-      nsRefPtr<GCAndCCLogDumpRunnable> runnable =
-        new GCAndCCLogDumpRunnable(
-            /* identifier = */ EmptyString(),
-            /* allTraces = */ true,
-            /* dumpChildProcesses = */ true);
-      NS_DispatchToMainThread(runnable);
-    }
-    else {
-      LOG("SignalPipeWatcher got unexpected signum.");
-    }
-  }
-};
-
-class FifoWatcher : public FdWatcher
+void doGCCCDump(const nsCString& inputStr)
 {
-public:
-  FifoWatcher(nsCString aPath)
-    : mDirPath(aPath)
-    {}
-
-  static void MaybeCreate()
-  {
-    MOZ_ASSERT(NS_IsMainThread());
-
-    if (XRE_GetProcessType() != GeckoProcessType_Default) {
-      // We want this to be main-process only, since two processes can't listen
-      // to the same fifo.
-      return;
-    }
-
-    if (!Preferences::GetBool("memory_info_dumper.watch_fifo.enabled", false)) {
-      LOG("Fifo watcher disabled via pref.");
-      return;
-    }
-
-    nsAutoCString dirPath;
-    Preferences::GetCString(
-      "memory_info_dumper.watch_fifo.directory", &dirPath);
-
-    // The FifoWatcher is held alive by the observer service.
-    nsRefPtr<FifoWatcher> fw = new FifoWatcher(dirPath);
-    fw->Init();
-  }
-
-  virtual int OpenFd()
-  {
-    // If the memory_info_dumper.directory pref is specified, put the fifo
-    // there.  Otherwise, put it into the system's tmp directory.
-
-    nsCOMPtr<nsIFile> file;
-
-    nsresult rv;
-    if (mDirPath.Length() > 0) {
-      rv = XRE_GetFileFromPath(mDirPath.get(), getter_AddRefs(file));
-      if (NS_FAILED(rv)) {
-        LOG("FifoWatcher failed to open file \"%s\"", mDirPath.get());
-        return -1;
-      }
-    } else {
-      rv = NS_GetSpecialDirectory(NS_OS_TEMP_DIR, getter_AddRefs(file));
-      if (NS_WARN_IF(NS_FAILED(rv)))
-        return -1;
-    }
-
-    rv = file->AppendNative(NS_LITERAL_CSTRING("debug_info_trigger"));
-    if (NS_WARN_IF(NS_FAILED(rv)))
-      return -1;
-
-    nsAutoCString path;
-    rv = file->GetNativePath(path);
-    if (NS_WARN_IF(NS_FAILED(rv)))
-      return -1;
-
-    // unlink might fail because the file doesn't exist, or for other reasons.
-    // But we don't care it fails; any problems will be detected later, when we
-    // try to mkfifo or open the file.
-    if (unlink(path.get())) {
-      LOG("FifoWatcher::OpenFifo unlink failed; errno=%d.  "
-          "Continuing despite error.", errno);
-    }
+  bool doAllTracesGCCCDump = inputStr == NS_LITERAL_CSTRING("gc log");
+  LOG("FifoWatcher(command:%s) dispatching GC/CC log runnable.", inputStr.get());
+  nsRefPtr<GCAndCCLogDumpRunnable> runnable =
+    new GCAndCCLogDumpRunnable(/* identifier = */ EmptyString(),
+                              doAllTracesGCCCDump,
+                              /* dumpChildProcesses = */ true);
+  NS_DispatchToMainThread(runnable);
+}
 
-    if (mkfifo(path.get(), 0766)) {
-      LOG("FifoWatcher::OpenFifo mkfifo failed; errno=%d", errno);
-      return -1;
-    }
-
-#ifdef ANDROID
-    // Android runs with a umask, so we need to chmod our fifo to make it
-    // world-writable.
-    chmod(path.get(), 0666);
-#endif
-
-    int fd;
-    do {
-      // The fifo will block until someone else has written to it.  In
-      // particular, open() will block until someone else has opened it for
-      // writing!  We want open() to succeed and read() to block, so we open
-      // with NONBLOCK and then fcntl that away.
-      fd = open(path.get(), O_RDONLY | O_NONBLOCK);
-    } while (fd == -1 && errno == EINTR);
-
-    if (fd == -1) {
-      LOG("FifoWatcher::OpenFifo open failed; errno=%d", errno);
-      return -1;
-    }
-
-    // Make fd blocking now that we've opened it.
-    if (fcntl(fd, F_SETFL, 0)) {
-      close(fd);
-      return -1;
-    }
-
-    return fd;
-  }
-
-  virtual void OnFileCanReadWithoutBlocking(int aFd)
-  {
-    MOZ_ASSERT(XRE_GetIOMessageLoop() == MessageLoopForIO::current());
-
-    char buf[1024];
-    int nread;
-    do {
-      // sizeof(buf) - 1 to leave space for the null-terminator.
-      nread = read(aFd, buf, sizeof(buf));
-    } while(nread == -1 && errno == EINTR);
-
-    if (nread == -1) {
-      // We want to avoid getting into a situation where
-      // OnFileCanReadWithoutBlocking is called in an infinite loop, so when
-      // something goes wrong, stop watching the fifo altogether.
-      LOG("FifoWatcher hit an error (%d) and is quitting.", errno);
-      StopWatching();
-      return;
-    }
-
-    if (nread == 0) {
-      // If we get EOF, that means that the other side closed the fifo.  We need
-      // to close and re-open the fifo; if we don't,
-      // OnFileCanWriteWithoutBlocking will be called in an infinite loop.
-
-      LOG("FifoWatcher closing and re-opening fifo.");
-      StopWatching();
-      StartWatching();
-      return;
-    }
-
-    nsAutoCString inputStr;
-    inputStr.Append(buf, nread);
-
-    // Trimming whitespace is important because if you do
-    //   |echo "foo" >> debug_info_trigger|,
-    // it'll actually write "foo\n" to the fifo.
-    inputStr.Trim("\b\t\r\n");
-
-    bool doMemoryReport = inputStr == NS_LITERAL_CSTRING("memory report");
-    bool doMMUMemoryReport = inputStr == NS_LITERAL_CSTRING("minimize memory report");
-    bool doAllTracesGCCCDump = inputStr == NS_LITERAL_CSTRING("gc log");
-    bool doSmallGCCCDump = inputStr == NS_LITERAL_CSTRING("abbreviated gc log");
-
-    if (doMemoryReport || doMMUMemoryReport) {
-      LOG("FifoWatcher dispatching memory report runnable.");
-      nsRefPtr<DumpMemoryInfoToTempDirRunnable> runnable =
-        new DumpMemoryInfoToTempDirRunnable(/* identifier = */ EmptyString(),
-                                            doMMUMemoryReport);
-      NS_DispatchToMainThread(runnable);
-    } else if (doAllTracesGCCCDump || doSmallGCCCDump) {
-      LOG("FifoWatcher dispatching GC/CC log runnable.");
-      nsRefPtr<GCAndCCLogDumpRunnable> runnable =
-        new GCAndCCLogDumpRunnable(
-            /* identifier = */ EmptyString(),
-            doAllTracesGCCCDump,
-            /* dumpChildProcesses = */ true);
-      NS_DispatchToMainThread(runnable);
-    } else {
-      LOG("Got unexpected value from fifo; ignoring it.");
-    }
-  }
-
-private:
-  nsAutoCString mDirPath;
-};
+void doGCCCDump(const uint8_t recvSig)
+{
+  LOG("SignalWatcher(sig %d) dispatching GC/CC log runnable.", recvSig);
+  // Dump GC and CC logs (from the main thread).
+  nsRefPtr<GCAndCCLogDumpRunnable> runnable =
+    new GCAndCCLogDumpRunnable(
+        /* identifier = */ EmptyString(),
+        /* allTraces = */ true,
+        /* dumpChildProcesses = */ true);
+  NS_DispatchToMainThread(runnable);
+}
 
 } // anonymous namespace
 #endif // XP_LINUX }
 
 NS_IMPL_ISUPPORTS1(nsMemoryInfoDumper, nsIMemoryInfoDumper)
 
 nsMemoryInfoDumper::nsMemoryInfoDumper()
 {
@@ -552,18 +179,41 @@ nsMemoryInfoDumper::nsMemoryInfoDumper()
 nsMemoryInfoDumper::~nsMemoryInfoDumper()
 {
 }
 
 /* static */ void
 nsMemoryInfoDumper::Initialize()
 {
 #if defined(XP_LINUX) || defined(__FreeBSD__)
-  SignalPipeWatcher::Create();
-  FifoWatcher::MaybeCreate();
+  SignalPipeWatcher* sw = SignalPipeWatcher::GetSingleton();
+
+  // Dump memory reporters (and those of our child processes)
+  sDumpAboutMemorySignum = SIGRTMIN;
+  sw->RegisterCallback(sDumpAboutMemorySignum, doMemoryReport);
+  // Dump our memory reporters after minimizing memory usage
+  sDumpAboutMemoryAfterMMUSignum = SIGRTMIN + 1;
+  sw->RegisterCallback(sDumpAboutMemoryAfterMMUSignum, doMemoryReport);
+  // Dump the GC and CC logs in this and our child processes.
+  sGCAndCCDumpSignum = SIGRTMIN + 2;
+  sw->RegisterCallback(sGCAndCCDumpSignum, doGCCCDump);
+
+  if (FifoWatcher::MaybeCreate()) {
+    FifoWatcher* fw = FifoWatcher::GetSingleton();
+    // Dump our memory reports (but run this on the main thread!).
+    fw->RegisterCallback(NS_LITERAL_CSTRING("memory report"),
+                         doMemoryReport);
+    fw->RegisterCallback(NS_LITERAL_CSTRING("minimize memory report"),
+                         doMemoryReport);
+    // Dump GC and CC logs (from the main thread).
+    fw->RegisterCallback(NS_LITERAL_CSTRING("gc log"),
+                         doGCCCDump);
+    fw->RegisterCallback(NS_LITERAL_CSTRING("abbreviated gc log"),
+                         doGCCCDump);
+  }
 #endif
 }
 
 static void
 EnsureNonEmptyIdentifier(nsAString& aIdentifier)
 {
   if (!aIdentifier.IsEmpty()) {
     return;
@@ -709,82 +359,16 @@ MakeFilename(const char *aPrefix, const 
              const char *aSuffix, nsACString &aResult)
 {
   aResult = nsPrintfCString("%s-%s-%d.%s",
                             aPrefix,
                             NS_ConvertUTF16toUTF8(aIdentifier).get(),
                             getpid(), aSuffix);
 }
 
-/* static */ nsresult
-nsMemoryInfoDumper::OpenTempFile(const nsACString &aFilename, nsIFile* *aFile)
-{
-#ifdef ANDROID
-  // For Android, first try the downloads directory which is world-readable
-  // rather than the temp directory which is not.
-  if (!*aFile) {
-    char *env = PR_GetEnv("DOWNLOADS_DIRECTORY");
-    if (env) {
-      NS_NewNativeLocalFile(nsCString(env), /* followLinks = */ true, aFile);
-    }
-  }
-#endif
-  nsresult rv;
-  if (!*aFile) {
-    rv = NS_GetSpecialDirectory(NS_OS_TEMP_DIR, aFile);
-    if (NS_WARN_IF(NS_FAILED(rv)))
-      return rv;
-  }
-
-#ifdef ANDROID
-  // /data/local/tmp is a true tmp directory; anyone can create a file there,
-  // but only the user which created the file can remove it.  We want non-root
-  // users to be able to remove these files, so we write them into a
-  // subdirectory of the temp directory and chmod 777 that directory.
-  rv = (*aFile)->AppendNative(NS_LITERAL_CSTRING("memory-reports"));
-  if (NS_WARN_IF(NS_FAILED(rv)))
-    return rv;
-
-  // It's OK if this fails; that probably just means that the directory already
-  // exists.
-  (*aFile)->Create(nsIFile::DIRECTORY_TYPE, 0777);
-
-  nsAutoCString dirPath;
-  rv = (*aFile)->GetNativePath(dirPath);
-  if (NS_WARN_IF(NS_FAILED(rv)))
-    return rv;
-
-  while (chmod(dirPath.get(), 0777) == -1 && errno == EINTR) {}
-#endif
-
-  nsCOMPtr<nsIFile> file(*aFile);
-
-  rv = file->AppendNative(aFilename);
-  if (NS_WARN_IF(NS_FAILED(rv)))
-    return rv;
-
-  rv = file->CreateUnique(nsIFile::NORMAL_FILE_TYPE, 0666);
-  if (NS_WARN_IF(NS_FAILED(rv)))
-    return rv;
-
-#ifdef ANDROID
-    // Make this file world-read/writable; the permissions passed to the
-    // CreateUnique call above are not sufficient on Android, which runs with a
-    // umask.
-    nsAutoCString path;
-    rv = file->GetNativePath(path);
-    if (NS_WARN_IF(NS_FAILED(rv)))
-      return rv;
-
-    while (chmod(path.get(), 0666) == -1 && errno == EINTR) {}
-#endif
-
-  return NS_OK;
-}
-
 #ifdef MOZ_DMD
 struct DMDWriteState
 {
   static const size_t kBufSize = 4096;
   char mBuf[kBufSize];
   nsRefPtr<nsGZFileWriter> mGZWriter;
 
   DMDWriteState(nsGZFileWriter *aGZWriter)
@@ -890,19 +474,23 @@ nsMemoryInfoDumper::DumpMemoryInfoToTemp
   // processes and write out one file, rather than a separate file for
   // each process as was the case before bug 946407.  This is so that
   // the get_about_memory.py script in the B2G repository can
   // determine when it's done waiting for files to appear.
   MakeFilename("unified-memory-report", identifier, "json.gz", mrFilename);
 
   nsCOMPtr<nsIFile> mrTmpFile;
   nsresult rv;
-  rv = nsMemoryInfoDumper::OpenTempFile(NS_LITERAL_CSTRING("incomplete-") +
-                                        mrFilename,
-                                        getter_AddRefs(mrTmpFile));
+  // In Android case, this function will open a file named aFilename under
+  // specific folder (/data/local/tmp/memory-reports). Otherwise, it will
+  // open a file named aFilename under "NS_OS_TEMP_DIR".
+  rv = nsDumpUtils::OpenTempFile(NS_LITERAL_CSTRING("incomplete-") +
+                                 mrFilename,
+                                 getter_AddRefs(mrTmpFile),
+                                 NS_LITERAL_CSTRING("memory-reports"));
   if (NS_WARN_IF(NS_FAILED(rv)))
     return rv;
 
   nsRefPtr<nsGZFileWriter> mrWriter = new nsGZFileWriter();
   rv = mrWriter->Init(mrTmpFile);
   if (NS_WARN_IF(NS_FAILED(rv)))
     return rv;
 
@@ -936,17 +524,19 @@ nsMemoryInfoDumper::DumpDMD(const nsAStr
   MakeFilename("dmd", aIdentifier, "txt.gz", dmdFilename);
 
   // Open a new DMD file named |dmdFilename| in NS_OS_TEMP_DIR for writing,
   // and dump DMD output to it.  This must occur after the memory reporters
   // have been run (above), but before the memory-reports file has been
   // renamed (so scripts can detect the DMD file, if present).
 
   nsCOMPtr<nsIFile> dmdFile;
-  rv = nsMemoryInfoDumper::OpenTempFile(dmdFilename, getter_AddRefs(dmdFile));
+  rv = nsDumpUtils::OpenTempFile(dmdFilename,
+                                 getter_AddRefs(dmdFile),
+                                 NS_LITERAL_CSTRING("memory-reports"));
   if (NS_WARN_IF(NS_FAILED(rv)))
     return rv;
 
   nsRefPtr<nsGZFileWriter> dmdWriter = new nsGZFileWriter();
   rv = dmdWriter->Init(dmdFile);
   if (NS_WARN_IF(NS_FAILED(rv)))
     return rv;
 
--- a/xpcom/base/nsMemoryInfoDumper.h
+++ b/xpcom/base/nsMemoryInfoDumper.h
@@ -25,24 +25,16 @@ public:
   NS_DECL_NSIMEMORYINFODUMPER
 
   nsMemoryInfoDumper();
   virtual ~nsMemoryInfoDumper();
 
 public:
   static void Initialize();
 
-  /**
-   * This function creates a new unique file based on |aFilename| in a
-   * world-readable temp directory. This is the system temp directory
-   * or, in the case of Android, the downloads directory. If |aFile| is
-   * non-null, it is assumed to point to a folder, and that folder is used
-   * instead.
-   */
-  static nsresult OpenTempFile(const nsACString &aFilename, nsIFile* *aFile);
 #ifdef MOZ_DMD
   static nsresult DumpDMD(const nsAString &aIdentifier);
 #endif
 };
 
 #define NS_MEMORY_INFO_DUMPER_CID \
 { 0x00bd71fb, 0x7f09, 0x4ec3, \
 { 0x96, 0xaf, 0xa0, 0xb5, 0x22, 0xb7, 0x79, 0x69 } }
new file mode 100644
--- /dev/null
+++ b/xpcom/base/nsStatusReporterManager.cpp
@@ -0,0 +1,294 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "nsStatusReporterManager.h"
+#include "nsCOMPtr.h"
+#include "nsDirectoryServiceDefs.h"
+#include "nsArrayEnumerator.h"
+#include "nsISimpleEnumerator.h"
+#include "nsIFile.h"
+#include "nsDumpUtils.h"
+#include "nsIFileStreams.h"
+#include "nsPrintfCString.h"
+
+#ifdef XP_WIN
+#include <process.h>
+#define getpid _getpid
+#else
+#include <unistd.h>
+#endif
+
+#if defined(XP_LINUX) || defined(__FreeBSD__)
+#define DO_STATUS_REPORT 1
+#else
+#define DO_STATUS_REPORT 0
+#endif
+
+#if DO_STATUS_REPORT // {
+namespace {
+
+class DumpStatusInfoToTempDirRunnable : public nsRunnable
+{
+public:
+  DumpStatusInfoToTempDirRunnable()
+  {}
+
+  NS_IMETHOD Run()
+  {
+    nsCOMPtr<nsIStatusReporterManager> mgr =
+      do_GetService("@mozilla.org/status-reporter-manager;1");
+    mgr->DumpReports();
+    return NS_OK;
+  }
+};
+
+void doStatusReport(const nsCString& inputStr)
+{
+  LOG("FifoWatcher(%s) dispatching status report runnable.", inputStr.get());
+  nsRefPtr<DumpStatusInfoToTempDirRunnable> runnable =
+    new DumpStatusInfoToTempDirRunnable();
+  NS_DispatchToMainThread(runnable);
+}
+
+} //anonymous namespace
+#endif // DO_STATUS_REPORT }
+
+static bool gStatusReportProgress = 0;
+static int gNumReporters = 0;
+
+nsresult getStatus(nsACString& desc)
+{
+  if(!gStatusReportProgress)
+    desc.AssignLiteral("Init");
+  else {
+    desc.AssignLiteral("Running:\nThere are ");
+    desc.AppendInt(gNumReporters);
+    desc.AppendLiteral(" reporters");
+  }
+  return NS_OK;
+}
+
+NS_STATUS_REPORTER_IMPLEMENT(StatusReporter, "StatusReporter State", getStatus)
+
+#define DUMP(o, s) \
+    do { \
+        const char* s2 = (s); \
+        uint32_t dummy; \
+        nsresult rv = (o)->Write((s2), strlen(s2), &dummy); \
+        if (NS_WARN_IF(NS_FAILED(rv))) \
+          return rv; \
+    } while (0)
+
+static nsresult
+DumpReport(nsIFileOutputStream* aOStream, const nsCString& aProcess,
+           const nsCString& aName, const nsCString& aDescription)
+{
+  int pid;
+  if (aProcess.IsEmpty()) {
+    pid = getpid();
+    nsPrintfCString pidStr("PID %u", pid);
+    DUMP(aOStream, "\n    {\"Process\": \"");
+    DUMP(aOStream, pidStr.get());
+  } else {
+    pid = 0;
+    DUMP(aOStream, "\n    {\"Unknown Process\": \"");
+  }
+
+  DUMP(aOStream, "\", \"Reporter name\": \"");
+  DUMP(aOStream, aName.get());
+
+  DUMP(aOStream, "\", \"Status Description\": \"");
+  DUMP(aOStream, aDescription.get());
+  DUMP(aOStream, "\"}");
+
+  return NS_OK;
+}
+
+/**
+ ** nsStatusReporterManager implementation
+ **/
+
+NS_IMPL_ISUPPORTS1(nsStatusReporterManager, nsIStatusReporterManager)
+
+nsStatusReporterManager::nsStatusReporterManager()
+{
+}
+
+nsStatusReporterManager::~nsStatusReporterManager()
+{
+}
+
+NS_IMETHODIMP
+nsStatusReporterManager::Init()
+{
+  RegisterReporter(new NS_STATUS_REPORTER_NAME(StatusReporter));
+  gStatusReportProgress = 1;
+
+#if DO_STATUS_REPORT
+  if (FifoWatcher::MaybeCreate()) {
+    FifoWatcher* fw = FifoWatcher::GetSingleton();
+    fw->RegisterCallback(NS_LITERAL_CSTRING("status report"),doStatusReport);
+  }
+#endif
+
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsStatusReporterManager::DumpReports()
+{
+  static unsigned number = 1;
+  nsresult rv;
+
+  nsCString filename("status-reports-");
+  filename.AppendInt(getpid());
+  filename.AppendLiteral("-");
+  filename.AppendInt(number++);
+  filename.AppendLiteral(".json");
+
+  // Open a file in NS_OS_TEMP_DIR for writing.
+  // The file is initialized as "incomplete-status-reports-pid-number.json" in the
+  // begining, it will be rename as "status-reports-pid-number.json" in the end.
+  nsCOMPtr<nsIFile> tmpFile;
+  rv = nsDumpUtils::OpenTempFile(NS_LITERAL_CSTRING("incomplete-") +
+                    filename,
+                    getter_AddRefs(tmpFile),
+                    NS_LITERAL_CSTRING("status-reports"));
+  if (NS_WARN_IF(NS_FAILED(rv)))
+    return rv;
+
+  nsCOMPtr<nsIFileOutputStream> ostream =
+    do_CreateInstance("@mozilla.org/network/file-output-stream;1");
+  rv = ostream->Init(tmpFile, -1, -1, 0);
+  if (NS_WARN_IF(NS_FAILED(rv)))
+    return rv;
+
+  //Write the reports to the file
+
+  DUMP(ostream, "  [Sysdump Report Start]: ");
+
+  nsCOMPtr<nsISimpleEnumerator> e;
+  bool more;
+  EnumerateReporters(getter_AddRefs(e));
+  while (NS_SUCCEEDED(e->HasMoreElements(&more)) && more) {
+    nsCOMPtr<nsISupports> supports;
+    e->GetNext(getter_AddRefs(supports));
+    nsCOMPtr<nsIStatusReporter> r = do_QueryInterface(supports);
+
+    nsCString process;
+    rv = r->GetProcess(process);
+    if (NS_WARN_IF(NS_FAILED(rv)))
+      return rv;
+
+    nsCString name;
+    rv = r->GetName(name);
+    if (NS_WARN_IF(NS_FAILED(rv)))
+      return rv;
+
+    nsCString description;
+    rv = r->GetDescription(description);
+    if (NS_WARN_IF(NS_FAILED(rv)))
+      return rv;
+
+    rv = DumpReport(ostream, process, name, description);
+    if (NS_WARN_IF(NS_FAILED(rv)))
+      return rv;
+  }
+
+  DUMP(ostream, "\n  [Sysdump Report End] ");
+
+  rv = ostream->Close();
+  if (NS_WARN_IF(NS_FAILED(rv)))
+    return rv;
+
+  // Rename the status reports file
+  nsCOMPtr<nsIFile> srFinalFile;
+  rv = NS_GetSpecialDirectory(NS_OS_TEMP_DIR, getter_AddRefs(srFinalFile));
+  if (NS_WARN_IF(NS_FAILED(rv)))
+    return rv;
+
+#ifdef ANDROID
+  rv = srFinalFile->AppendNative(NS_LITERAL_CSTRING("status-reports"));
+  if (NS_WARN_IF(NS_FAILED(rv)))
+    return rv;
+#endif
+
+  rv = srFinalFile->AppendNative(filename);
+  if (NS_WARN_IF(NS_FAILED(rv)))
+    return rv;
+
+  rv = srFinalFile->CreateUnique(nsIFile::NORMAL_FILE_TYPE, 0600);
+  if (NS_WARN_IF(NS_FAILED(rv)))
+    return rv;
+
+  nsAutoString srActualFinalFilename;
+  rv = srFinalFile->GetLeafName(srActualFinalFilename);
+  if (NS_WARN_IF(NS_FAILED(rv)))
+    return rv;
+
+  rv = tmpFile->MoveTo(/* directory */ nullptr, srActualFinalFilename);
+
+  if (NS_WARN_IF(NS_FAILED(rv)))
+    return rv;
+
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsStatusReporterManager::EnumerateReporters(nsISimpleEnumerator** result)
+{
+  return NS_NewArrayEnumerator(result, mReporters);
+}
+
+NS_IMETHODIMP
+nsStatusReporterManager::RegisterReporter(nsIStatusReporter* reporter)
+{
+  if (mReporters.IndexOf(reporter) != -1)
+    return NS_ERROR_FAILURE;
+
+  mReporters.AppendObject(reporter);
+  gNumReporters++;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsStatusReporterManager::UnregisterReporter(nsIStatusReporter* reporter)
+{
+  if (!mReporters.RemoveObject(reporter))
+    return NS_ERROR_FAILURE;
+  gNumReporters--;
+  return NS_OK;
+}
+
+nsresult
+NS_RegisterStatusReporter (nsIStatusReporter* reporter)
+{
+  nsCOMPtr<nsIStatusReporterManager> mgr =
+    do_GetService("@mozilla.org/status-reporter-manager;1");
+  if (mgr == nullptr)
+    return NS_ERROR_FAILURE;
+  return mgr->RegisterReporter(reporter);
+}
+
+nsresult
+NS_UnregisterStatusReporter (nsIStatusReporter* reporter)
+{
+  nsCOMPtr<nsIStatusReporterManager> mgr =
+    do_GetService("@mozilla.org/status-reporter-manager;1");
+  if (mgr == nullptr)
+    return NS_ERROR_FAILURE;
+  return mgr->UnregisterReporter(reporter);
+}
+
+nsresult
+NS_DumpStatusReporter ()
+{
+  nsCOMPtr<nsIStatusReporterManager> mgr =
+    do_GetService("@mozilla.org/status-reporter-manager;1");
+  if (mgr == nullptr)
+    return NS_ERROR_FAILURE;
+  return mgr->DumpReports();
+}
new file mode 100644
--- /dev/null
+++ b/xpcom/base/nsStatusReporterManager.h
@@ -0,0 +1,41 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+
+#include "nsIStatusReporter.h"
+#include "nsCOMArray.h"
+#include "nsString.h"
+
+class nsStatusReporter MOZ_FINAL : public nsIStatusReporter
+{
+public:
+  NS_DECL_ISUPPORTS
+  NS_DECL_NSISTATUSREPORTER
+
+  nsStatusReporter(nsACString& process,
+                   nsACString& desc);
+
+  virtual ~nsStatusReporter();
+
+protected:
+  nsCString sProcess;
+  nsCString sName;
+  nsCString sDesc;
+};
+
+
+class nsStatusReporterManager : public nsIStatusReporterManager
+{
+public:
+  NS_DECL_ISUPPORTS
+  NS_DECL_NSISTATUSREPORTERMANAGER
+
+  nsStatusReporterManager();
+  virtual ~nsStatusReporterManager();
+
+private:
+  nsCOMArray<nsIStatusReporter>      mReporters;
+};
--- a/xpcom/build/XPCOMModule.inc
+++ b/xpcom/build/XPCOMModule.inc
@@ -76,8 +76,9 @@
 #endif
 
     COMPONENT(SYSTEMINFO, nsSystemInfoConstructor)
     COMPONENT(MEMORY_REPORTER_MANAGER, nsMemoryReporterManagerConstructor)
     COMPONENT(MEMORY_INFO_DUMPER, nsMemoryInfoDumperConstructor)
     COMPONENT(IOUTIL, nsIOUtilConstructor)
     COMPONENT(CYCLE_COLLECTOR_LOGGER, nsCycleCollectorLoggerConstructor)
     COMPONENT(MESSAGE_LOOP, nsMessageLoopConstructor)
+    COMPONENT(STATUS_REPORTER_MANAGER, nsStatusReporterManagerConstructor)
--- a/xpcom/build/nsXPCOMCID.h
+++ b/xpcom/build/nsXPCOMCID.h
@@ -71,16 +71,21 @@
 #define NS_MEMORY_REPORTER_MANAGER_CONTRACTID "@mozilla.org/memory-reporter-manager;1"
 
 /**
  * Memory info dumper service CID
  */
 #define NS_MEMORY_INFO_DUMPER_CONTRACTID "@mozilla.org/memory-info-dumper;1"
 
 /**
+ * Status reporter service CID
+ */
+#define NS_STATUS_REPORTER_MANAGER_CONTRACTID "@mozilla.org/status-reporter-manager;1"
+
+/**
  * Cycle collector logger contract id
  */
 #define NS_CYCLE_COLLECTOR_LOGGER_CONTRACTID "@mozilla.org/cycle-collector-logger;1"
 
 /**
  * nsMessageLoop contract id
  */
 #define NS_MESSAGE_LOOP_CONTRACTID "@mozilla.org/message-loop;1"
--- a/xpcom/build/nsXPComInit.cpp
+++ b/xpcom/build/nsXPComInit.cpp
@@ -96,16 +96,18 @@ extern nsresult nsStringInputStreamConst
 #endif
 
 #include "nsSystemInfo.h"
 #include "nsMemoryReporterManager.h"
 #include "nsMemoryInfoDumper.h"
 #include "nsSecurityConsoleMessage.h"
 #include "nsMessageLoop.h"
 
+#include "nsStatusReporterManager.h"
+
 #include <locale.h>
 #include "mozilla/Services.h"
 #include "mozilla/Omnijar.h"
 #include "mozilla/HangMonitor.h"
 #include "mozilla/Telemetry.h"
 #include "mozilla/BackgroundHangMonitor.h"
 
 #include "nsChromeRegistry.h"
@@ -211,16 +213,18 @@ NS_GENERIC_FACTORY_CONSTRUCTOR(nsMacUtil
 #endif
 
 NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsSystemInfo, Init)
 
 NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsMemoryReporterManager, Init)
 
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsMemoryInfoDumper)
 
+NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsStatusReporterManager, Init)
+
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsIOUtil)
 
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsSecurityConsoleMessage)
 
 static nsresult
 nsThreadManagerGetSingleton(nsISupports* outer,
                             const nsIID& aIID,
                             void* *aInstancePtr)