Merge b2g-inbound to m-c.
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)