--- 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="0d616942c300d9fb142483210f1dda9096c9a9fc">
<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="c527178b78a5bc85b76f89d6ba7f0bb464963b79"/>
+ <project name="gaia.git" path="gaia" remote="mozillaorg" revision="25e998814ba89f30fe44cd2fdfbb44d160a04641"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="d61daef8fca7d6f335f659a8967bad423770e634"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="cd88d860656c31c7da7bb310d6a160d0011b0961"/>
<project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="227354333a185180b85471f2cc6abfb029e44718"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="dc5ca96695cab87b4c2fcd7c9f046ae3415a70a5"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="71f5a35e3bc1801847413cff1f14fc3b5cd991ca"/>
<!-- 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="3aa6abd313f965a84aa86c6b213dc154e4875139">
<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="c527178b78a5bc85b76f89d6ba7f0bb464963b79"/>
+ <project name="gaia" path="gaia" remote="mozillaorg" revision="25e998814ba89f30fe44cd2fdfbb44d160a04641"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="d61daef8fca7d6f335f659a8967bad423770e634"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="dc5ca96695cab87b4c2fcd7c9f046ae3415a70a5"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="71f5a35e3bc1801847413cff1f14fc3b5cd991ca"/>
<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"/>
@@ -126,12 +126,12 @@
<!-- Emulator specific things -->
<project name="android-development" path="development" remote="b2g" revision="dab55669da8f48b6e57df95d5af9f16b4a87b0b1"/>
<project name="device/generic/armv7-a-neon" path="device/generic/armv7-a-neon" revision="3a9a17613cc685aa232432566ad6cc607eab4ec1"/>
<project name="device_generic_goldfish" path="device/generic/goldfish" remote="b2g" revision="197cd9492b9fadaa915c5daf36ff557f8f4a8d1c"/>
<project name="platform/external/libnfc-nci" path="external/libnfc-nci" revision="7d33aaf740bbf6c7c6e9c34a92b371eda311b66b"/>
<project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="683623c76338dccd65e698bfb5c4cfee8808d799"/>
<project name="platform/external/wpa_supplicant_8" path="external/wpa_supplicant_8" revision="0e56e450367cd802241b27164a2979188242b95f"/>
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="9f28c4faea3b2f01db227b2467b08aeba96d9bec"/>
- <project name="platform_system_nfcd" path="system/nfcd" remote="b2g" revision="2cd3c7277621902b3749797eaaab618c4c80a58b"/>
+ <project name="platform_system_nfcd" path="system/nfcd" remote="b2g" revision="1adbb04024c6181f1089f3a12ee46f26663ea1db"/>
<project name="android-sdk" path="sdk" remote="b2g" revision="8b1365af38c9a653df97349ee53a3f5d64fd590a"/>
<project name="darwinstreamingserver" path="system/darwinstreamingserver" remote="b2g" revision="cf85968c7f85e0ec36e72c87ceb4837a943b8af6"/>
</manifest>
--- 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="999e945b85c578c503ad445c2285940f16aacdae">
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
- <project name="gaia" path="gaia" remote="mozillaorg" revision="c527178b78a5bc85b76f89d6ba7f0bb464963b79"/>
+ <project name="gaia" path="gaia" remote="mozillaorg" revision="25e998814ba89f30fe44cd2fdfbb44d160a04641"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="d61daef8fca7d6f335f659a8967bad423770e634"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="dc5ca96695cab87b4c2fcd7c9f046ae3415a70a5"/>
<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="71f5a35e3bc1801847413cff1f14fc3b5cd991ca"/>
--- 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="0d616942c300d9fb142483210f1dda9096c9a9fc">
<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="c527178b78a5bc85b76f89d6ba7f0bb464963b79"/>
+ <project name="gaia.git" path="gaia" remote="mozillaorg" revision="25e998814ba89f30fe44cd2fdfbb44d160a04641"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="d61daef8fca7d6f335f659a8967bad423770e634"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="cd88d860656c31c7da7bb310d6a160d0011b0961"/>
<project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="227354333a185180b85471f2cc6abfb029e44718"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="dc5ca96695cab87b4c2fcd7c9f046ae3415a70a5"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="71f5a35e3bc1801847413cff1f14fc3b5cd991ca"/>
<!-- Stock Android things -->
<project name="platform/abi/cpp" path="abi/cpp" revision="dd924f92906085b831bf1cbbc7484d3c043d613c"/>
--- a/b2g/config/flame/sources.xml
+++ b/b2g/config/flame/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="3aa6abd313f965a84aa86c6b213dc154e4875139">
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
- <project name="gaia" path="gaia" remote="mozillaorg" revision="c527178b78a5bc85b76f89d6ba7f0bb464963b79"/>
+ <project name="gaia" path="gaia" remote="mozillaorg" revision="25e998814ba89f30fe44cd2fdfbb44d160a04641"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="d61daef8fca7d6f335f659a8967bad423770e634"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="dc5ca96695cab87b4c2fcd7c9f046ae3415a70a5"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="71f5a35e3bc1801847413cff1f14fc3b5cd991ca"/>
<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="e95b4ce22c825da44d14299e1190ea39a5260bde"/>
<project groups="linux" name="platform/prebuilts/clang/linux-x86/3.2" path="prebuilts/clang/linux-x86/3.2" revision="471afab478649078ad7c75ec6b252481a59e19b8"/>
@@ -115,17 +115,17 @@
<project name="platform/system/security" path="system/security" revision="360f51f7af191316cd739f229db1c5f7233be063"/>
<project name="platform/system/vold" path="system/vold" revision="153df4d067a4149c7d78f1c92fed2ce2bd6a272e"/>
<!--original fetch url was git://github.com/t2m-foxfone/-->
<remote fetch="https://git.mozilla.org/external/t2m-foxfone" name="t2m"/>
<default remote="caf" revision="jb_3.2" sync-j="4"/>
<!-- Flame specific things -->
<project name="device/generic/armv7-a-neon" path="device/generic/armv7-a-neon" revision="e8a318f7690092e639ba88891606f4183e846d3f"/>
<project name="device/qcom/common" path="device/qcom/common" revision="34ed8345250bb97262d70a052217a92e83444ede"/>
- <project name="device-flame" path="device/t2m/flame" remote="b2g" revision="a927b19531c293dca1e80e081e0ab5715f4d1bfe"/>
+ <project name="device-flame" path="device/t2m/flame" remote="b2g" revision="d7e5ed0a081a39419932b8b9fdefc9b2d903850d"/>
<project name="codeaurora_kernel_msm" path="kernel" remote="b2g" revision="30d40a5636ff28a554f1d8e9d975bfd04c2463d3"/>
<project name="kernel_lk" path="bootable/bootloader/lk" remote="b2g" revision="2b1d8b5b7a760230f4c94c02e733e3929f44253a"/>
<project name="platform_bootable_recovery" path="bootable/recovery" remote="b2g" revision="e81502511cda303c803e63f049574634bc96f9f2"/>
<project name="platform/external/bluetooth/bluedroid" path="external/bluetooth/bluedroid" revision="81c4a859d75d413ad688067829d21b7ba9205f81"/>
<project name="platform/external/bluetooth/bluez" path="external/bluetooth/bluez" revision="f0689ac1914cdbc59e53bdc9edd9013dc157c299"/>
<project name="platform/external/bluetooth/glib" path="external/bluetooth/glib" revision="dd925f76e4f149c3d5571b80e12f7e24bbe89c59"/>
<project name="platform/external/dbus" path="external/dbus" revision="ea87119c843116340f5df1d94eaf8275e1055ae8"/>
<project name="platform_external_libnfc-nci" path="external/libnfc-nci" remote="t2m" revision="4186bdecb4dae911b39a8202252cc2310d91b0be"/>
@@ -138,13 +138,13 @@
<project name="platform/hardware/qcom/camera" path="hardware/qcom/camera" revision="5e110615212302c5d798a3c223dcee458817651c"/>
<project name="platform/hardware/qcom/display" path="hardware/qcom/display" revision="fa9ffd47948eb24466de227e48fe9c4a7c5e7711"/>
<project name="platform/hardware/qcom/gps" path="hardware/qcom/gps" revision="5dc48bd46f9589653f8bf297be5d73676f2e2867"/>
<project name="platform/hardware/qcom/media" path="hardware/qcom/media" revision="8a0d0b0d9889ef99c4c6317c810db4c09295f15a"/>
<project name="platform/hardware/qcom/wlan" path="hardware/qcom/wlan" revision="2208fa3537ace873b8f9ec2355055761c79dfd5f"/>
<project name="platform/hardware/ril" path="hardware/ril" revision="c4e2ac95907a5519a0e09f01a0d8e27fec101af0"/>
<project name="platform/system/bluetooth" path="system/bluetooth" revision="e1eb226fa3ad3874ea7b63c56a9dc7012d7ff3c2"/>
<project name="platform/system/core" path="system/core" revision="bbf7212289fc8311e43f9d11e10788e310d36a08"/>
- <project name="platform_system_nfcd" path="system/nfcd" remote="b2g" revision="2cd3c7277621902b3749797eaaab618c4c80a58b"/>
+ <project name="platform_system_nfcd" path="system/nfcd" remote="b2g" revision="1adbb04024c6181f1089f3a12ee46f26663ea1db"/>
<project name="platform/system/qcom" path="system/qcom" revision="1cdab258b15258b7f9657da70e6f06ebd5a2fc25"/>
<project name="platform/vendor/qcom/msm8610" path="device/qcom/msm8610" revision="4ae5df252123591d5b941191790e7abed1bce5a4"/>
<project name="platform/vendor/qcom-opensource/wlan/prima" path="vendor/qcom/opensource/wlan/prima" revision="ce18b47b4a4f93a581d672bbd5cb6d12fe796ca9"/>
</manifest>
--- a/b2g/config/gaia.json
+++ b/b2g/config/gaia.json
@@ -1,9 +1,9 @@
{
"git": {
"git_revision": "",
"remote": "",
"branch": ""
},
- "revision": "4024e28dbc44b11d3297378484c2474dcee425fa",
+ "revision": "549d40d59aed92eb33c912e0a8c7ea0faf0e7a18",
"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="0d616942c300d9fb142483210f1dda9096c9a9fc">
<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="c527178b78a5bc85b76f89d6ba7f0bb464963b79"/>
+ <project name="gaia.git" path="gaia" remote="mozillaorg" revision="25e998814ba89f30fe44cd2fdfbb44d160a04641"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="d61daef8fca7d6f335f659a8967bad423770e634"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="dc5ca96695cab87b4c2fcd7c9f046ae3415a70a5"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="71f5a35e3bc1801847413cff1f14fc3b5cd991ca"/>
<!-- 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="0d616942c300d9fb142483210f1dda9096c9a9fc">
<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="c527178b78a5bc85b76f89d6ba7f0bb464963b79"/>
+ <project name="gaia.git" path="gaia" remote="mozillaorg" revision="25e998814ba89f30fe44cd2fdfbb44d160a04641"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="d61daef8fca7d6f335f659a8967bad423770e634"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="dc5ca96695cab87b4c2fcd7c9f046ae3415a70a5"/>
<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/nexus-4/sources.xml
+++ b/b2g/config/nexus-4/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="3aa6abd313f965a84aa86c6b213dc154e4875139">
<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="c527178b78a5bc85b76f89d6ba7f0bb464963b79"/>
+ <project name="gaia" path="gaia" remote="mozillaorg" revision="25e998814ba89f30fe44cd2fdfbb44d160a04641"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="d61daef8fca7d6f335f659a8967bad423770e634"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="dc5ca96695cab87b4c2fcd7c9f046ae3415a70a5"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="71f5a35e3bc1801847413cff1f14fc3b5cd991ca"/>
<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"/>
@@ -122,17 +122,17 @@
<project name="platform/system/netd" path="system/netd" revision="56112dd7b811301b718d0643a82fd5cac9522073"/>
<project name="platform/system/security" path="system/security" revision="f48ff68fedbcdc12b570b7699745abb6e7574907"/>
<project name="platform/system/vold" path="system/vold" revision="8de05d4a52b5a91e7336e6baa4592f945a6ddbea"/>
<default remote="caf" revision="refs/tags/android-4.3_r2.1" sync-j="4"/>
<!-- Nexus 4 specific things -->
<project name="device-mako" path="device/lge/mako" remote="b2g" revision="78d17f0c117f0c66dd55ee8d5c5dde8ccc93ecba"/>
<project name="device/generic/armv7-a-neon" path="device/generic/armv7-a-neon" revision="3a9a17613cc685aa232432566ad6cc607eab4ec1"/>
<project name="device/lge/mako-kernel" path="device/lge/mako-kernel" revision="d1729e53d71d711c8fde25eab8728ff2b9b4df0e"/>
- <project name="platform_system_nfcd" path="system/nfcd" remote="b2g" revision="2cd3c7277621902b3749797eaaab618c4c80a58b"/>
+ <project name="platform_system_nfcd" path="system/nfcd" remote="b2g" revision="1adbb04024c6181f1089f3a12ee46f26663ea1db"/>
<project name="platform/external/libnfc-nci" path="external/libnfc-nci" revision="7d33aaf740bbf6c7c6e9c34a92b371eda311b66b"/>
<project name="platform/external/wpa_supplicant_8" path="external/wpa_supplicant_8" revision="0e56e450367cd802241b27164a2979188242b95f"/>
<project name="platform/hardware/broadcom/wlan" path="hardware/broadcom/wlan" revision="0e1929fa3aa38bf9d40e9e953d619fab8164c82e"/>
<project name="platform/hardware/qcom/audio" path="hardware/qcom/audio" revision="b0a528d839cfd9d170d092fe3743b5252b4243a6"/>
<project name="platform/hardware/qcom/bt" path="hardware/qcom/bt" revision="380945eaa249a2dbdde0daa4c8adb8ca325edba6"/>
<project name="platform/hardware/qcom/display" path="hardware/qcom/display" revision="6f3b0272cefaffeaed2a7d2bb8f633059f163ddc"/>
<project name="platform/hardware/qcom/keymaster" path="hardware/qcom/keymaster" revision="16da8262c997a5a0d797885788a64a0771b26910"/>
<project name="platform/hardware/qcom/media" path="hardware/qcom/media" revision="689b476ba3eb46c34b81343295fe144a0e81a18e"/>
--- 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="0d616942c300d9fb142483210f1dda9096c9a9fc">
<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="c527178b78a5bc85b76f89d6ba7f0bb464963b79"/>
+ <project name="gaia.git" path="gaia" remote="mozillaorg" revision="25e998814ba89f30fe44cd2fdfbb44d160a04641"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="d61daef8fca7d6f335f659a8967bad423770e634"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="dc5ca96695cab87b4c2fcd7c9f046ae3415a70a5"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="71f5a35e3bc1801847413cff1f14fc3b5cd991ca"/>
<project name="gonk-patches" path="patches" remote="b2g" revision="223a2421006e8f5da33f516f6891c87cae86b0f6"/>
<!-- Stock Android things -->
<project name="platform/abi/cpp" path="abi/cpp" revision="6426040f1be4a844082c9769171ce7f5341a5528"/>
--- a/browser/themes/linux/jar.mn
+++ b/browser/themes/linux/jar.mn
@@ -18,17 +18,17 @@ browser.jar:
#ifdef MOZ_SERVICES_SYNC
skin/classic/browser/aboutSyncTabs.css
#endif
skin/classic/browser/aboutTabCrashed.css
skin/classic/browser/actionicon-tab.png
* skin/classic/browser/browser.css
* skin/classic/browser/browser-lightweightTheme.css
skin/classic/browser/click-to-play-warning-stripes.png
-* skin/classic/browser/content-contextmenu.svg
+ skin/classic/browser/content-contextmenu.svg
* skin/classic/browser/engineManager.css
skin/classic/browser/fullscreen-darknoise.png
skin/classic/browser/Geolocation-16.png
skin/classic/browser/Geolocation-64.png
skin/classic/browser/identity.png
skin/classic/browser/identity-icons-generic.png
skin/classic/browser/identity-icons-https.png
skin/classic/browser/identity-icons-https-ev.png
--- a/browser/themes/osx/jar.mn
+++ b/browser/themes/osx/jar.mn
@@ -18,17 +18,17 @@ browser.jar:
skin/classic/browser/aboutSyncTabs.css
#endif
skin/classic/browser/aboutTabCrashed.css
skin/classic/browser/actionicon-tab.png
skin/classic/browser/actionicon-tab@2x.png
* skin/classic/browser/browser.css (browser.css)
* skin/classic/browser/browser-lightweightTheme.css
skin/classic/browser/click-to-play-warning-stripes.png
-* skin/classic/browser/content-contextmenu.svg
+ skin/classic/browser/content-contextmenu.svg
* skin/classic/browser/engineManager.css (engineManager.css)
skin/classic/browser/fullscreen-darknoise.png
skin/classic/browser/Geolocation-16.png
skin/classic/browser/Geolocation-16@2x.png
skin/classic/browser/Geolocation-64.png
skin/classic/browser/Geolocation-64@2x.png
skin/classic/browser/identity.png
skin/classic/browser/identity@2x.png
--- a/browser/themes/windows/jar.mn
+++ b/browser/themes/windows/jar.mn
@@ -20,17 +20,17 @@ browser.jar:
#ifdef MOZ_SERVICES_SYNC
skin/classic/browser/aboutSyncTabs.css
#endif
skin/classic/browser/aboutTabCrashed.css
skin/classic/browser/actionicon-tab.png
* skin/classic/browser/browser.css
* skin/classic/browser/browser-lightweightTheme.css
skin/classic/browser/click-to-play-warning-stripes.png
-* skin/classic/browser/content-contextmenu.svg
+ skin/classic/browser/content-contextmenu.svg
* skin/classic/browser/engineManager.css
skin/classic/browser/fullscreen-darknoise.png
skin/classic/browser/Geolocation-16.png
skin/classic/browser/Geolocation-64.png
skin/classic/browser/Info.png
skin/classic/browser/identity.png
skin/classic/browser/identity-icons-generic.png
skin/classic/browser/identity-icons-https.png
@@ -432,17 +432,17 @@ browser.jar:
skin/classic/aero/browser/aboutSyncTabs.css
#endif
skin/classic/aero/browser/aboutTabCrashed.css
skin/classic/aero/browser/aboutWelcomeBack.css (../shared/aboutWelcomeBack.css)
skin/classic/aero/browser/actionicon-tab.png
* skin/classic/aero/browser/browser.css (browser-aero.css)
* skin/classic/aero/browser/browser-lightweightTheme.css
skin/classic/aero/browser/click-to-play-warning-stripes.png
-* skin/classic/aero/browser/content-contextmenu.svg
+ skin/classic/aero/browser/content-contextmenu.svg
* skin/classic/aero/browser/engineManager.css
skin/classic/aero/browser/fullscreen-darknoise.png
skin/classic/aero/browser/Geolocation-16.png
skin/classic/aero/browser/Geolocation-64.png
skin/classic/aero/browser/Info.png (Info-aero.png)
skin/classic/aero/browser/identity.png (identity-aero.png)
skin/classic/aero/browser/identity-icons-generic.png
skin/classic/aero/browser/identity-icons-https.png
--- a/build/macosx/universal/mozconfig.common
+++ b/build/macosx/universal/mozconfig.common
@@ -7,17 +7,17 @@ mk_add_options MOZ_UNIFY_BDATE=1
mk_add_options MOZ_POSTFLIGHT_ALL+=build/macosx/universal/flight.mk
DARWIN_VERSION=`uname -r`
ac_add_app_options i386 --target=i386-apple-darwin$DARWIN_VERSION
ac_add_app_options x86_64 --target=x86_64-apple-darwin$DARWIN_VERSION
ac_add_app_options i386 --with-unify-dist=../x86_64/dist
ac_add_app_options x86_64 --with-unify-dist=../i386/dist
-ac_add_options --with-macos-sdk=/Developer/SDKs/MacOSX10.6.sdk
+ac_add_options --with-macos-sdk=/Developer/SDKs/MacOSX10.7.sdk
. $topsrcdir/build/macosx/mozconfig.common
# $MOZ_BUILD_APP is only defined when sourced by configure. That's not a
# problem, because the variables it affects only need to be set for
# configure.
if test -n "$MOZ_BUILD_APP" ; then
if test "$MOZ_BUILD_APP" = "i386" -o "$MOZ_BUILD_APP" = "x86_64"; then
--- a/build/mobile/remoteautomation.py
+++ b/build/mobile/remoteautomation.py
@@ -261,17 +261,17 @@ class RemoteAutomation(Automation):
return
# We only keep the last (unfinished) line in the buffer
self.logBuffer = lines[-1]
del lines[-1]
messages = []
for line in lines:
# This passes the line to the logger (to be logged or buffered)
- # and returns a list of structured messages (dict) or None, depending on the log
+ # and returns a list of structured messages (dict)
parsed_messages = self.messageLogger.write(line)
for message in parsed_messages:
if message['action'] == 'test_start':
self.lastTestSeen = message['test']
messages += parsed_messages
return messages
@property
--- a/build/mobile/robocop/FennecMochitestAssert.java
+++ b/build/mobile/robocop/FennecMochitestAssert.java
@@ -20,54 +20,63 @@ public class FennecMochitestAssert imple
private boolean mLogStarted = false;
// Used to write the test-start/test-end log lines
private String mLogTestName = "";
// Measure the time it takes to run test case
private long mStartTime = 0;
- public FennecMochitestAssert() {
- }
+ // Structured logger
+ private StructuredLogger mLogger;
/** Write information to a logfile and logcat */
public void dumpLog(String message) {
- FennecNativeDriver.log(FennecNativeDriver.LogLevel.INFO, message);
+ mLogger.info(message);
+ }
+
+ public void dumpLog(String message, Throwable t) {
+ mLogger.error(message + " - " + t.toString());
}
/** Write information to a logfile and logcat */
- public void dumpLog(String message, Throwable t) {
- FennecNativeDriver.log(FennecNativeDriver.LogLevel.INFO, message, t);
+ static class DumpLogCallback implements StructuredLogger.LoggerCallback {
+ public void call(String output) {
+ FennecNativeDriver.log(FennecNativeDriver.LogLevel.INFO, output);
+ }
+ }
+
+
+ public FennecMochitestAssert() {
+ mLogger = new StructuredLogger("robocop", new DumpLogCallback());
}
/** Set the filename used for dumpLog. */
public void setLogFile(String filename) {
FennecNativeDriver.setLogFile(filename);
String message;
if (!mLogStarted) {
- dumpLog("SimpleTest START");
+ mLogger.info("SimpleTest START");
mLogStarted = true;
}
if (mLogTestName != "") {
long diff = SystemClock.uptimeMillis() - mStartTime;
- message = "TEST-END | " + mLogTestName;
- message += " | finished in " + diff + "ms";
- dumpLog(message);
+ mLogger.testEnd(mLogTestName, "OK", "finished in " + diff + "ms");
mLogTestName = "";
}
}
public void setTestName(String testName) {
String[] nameParts = testName.split("\\.");
mLogTestName = nameParts[nameParts.length - 1];
mStartTime = SystemClock.uptimeMillis();
- dumpLog("TEST-START | " + mLogTestName);
+ mLogger.testStart(mLogTestName);
}
class testInfo {
public boolean mResult;
public String mName;
public String mDiag;
public boolean mTodo;
public boolean mInfo;
@@ -76,72 +85,68 @@ public class FennecMochitestAssert imple
mName = n;
mDiag = d;
mTodo = t;
mInfo = i;
}
}
- private void _logMochitestResult(testInfo test, String passString, String failString) {
+ /** Used to log a subtest's result.
+ * test represents the subtest (an assertion).
+ * passStatus and passExpected are the actual status and the expected status if the assertion is true.
+ * failStatus and failExpected are the actual status and the expected status otherwise.
+ */
+ private void _logMochitestResult(testInfo test, String passStatus, String passExpected, String failStatus, String failExpected) {
boolean isError = true;
- String resultString = failString;
if (test.mResult || test.mTodo) {
isError = false;
}
if (test.mResult)
{
- resultString = passString;
+ mLogger.testStatus(mLogTestName, test.mName, passStatus, passExpected, test.mDiag);
+ } else {
+ mLogger.testStatus(mLogTestName, test.mName, failStatus, failExpected, test.mDiag);
}
- String diag = test.mName;
- if (test.mDiag != null) diag += " - " + test.mDiag;
-
- String message = resultString + " | " + mLogTestName + " | " + diag;
- dumpLog(message);
if (test.mInfo) {
// do not count TEST-INFO messages
} else if (test.mTodo) {
mTodo++;
} else if (isError) {
mFailed++;
} else {
mPassed++;
}
if (isError) {
+ String message = "TEST-UNEXPECTED-" + failStatus + " | " + mLogTestName + " | "
+ + test.mName + " - " + test.mDiag;
junit.framework.Assert.fail(message);
}
}
public void endTest() {
String message;
if (mLogTestName != "") {
long diff = SystemClock.uptimeMillis() - mStartTime;
- message = "TEST-END | " + mLogTestName;
- message += " | finished in " + diff + "ms";
- dumpLog(message);
+ mLogger.testEnd(mLogTestName, "OK", "finished in " + diff + "ms");
mLogTestName = "";
}
- message = "TEST-START | Shutdown";
- dumpLog(message);
- message = "Passed: " + Integer.toString(mPassed);
- dumpLog(message);
- message = "Failed: " + Integer.toString(mFailed);
- dumpLog(message);
- message = "Todo: " + Integer.toString(mTodo);
- dumpLog(message);
- message = "SimpleTest FINISHED";
- dumpLog(message);
+ mLogger.info("TEST-START | Shutdown");
+ mLogger.info("Passed: " + Integer.toString(mPassed));
+ mLogger.info("Failed: " + Integer.toString(mFailed));
+ mLogger.info("Todo: " + Integer.toString(mTodo));
+ mLogger.info("SimpleTest FINISHED");
}
public void ok(boolean condition, String name, String diag) {
testInfo test = new testInfo(condition, name, diag, false, false);
- _logMochitestResult(test, "TEST-PASS", "TEST-UNEXPECTED-FAIL");
+ _logMochitestResult(test, "PASS", "PASS", "FAIL", "PASS");
mTestList.add(test);
}
public void is(Object actual, Object expected, String name) {
boolean pass = checkObjectsEqual(actual, expected);
ok(pass, name, getEqualString(actual, expected, pass));
}
@@ -188,17 +193,17 @@ public class FennecMochitestAssert imple
return true;
} else {
return false;
}
}
public void todo(boolean condition, String name, String diag) {
testInfo test = new testInfo(condition, name, diag, true, false);
- _logMochitestResult(test, "TEST-UNEXPECTED-PASS", "TEST-KNOWN-FAIL");
+ _logMochitestResult(test, "PASS", "FAIL", "FAIL", "FAIL");
mTestList.add(test);
}
public void todo_is(Object actual, Object expected, String name) {
boolean pass = checkObjectsEqual(actual, expected);
todo(pass, name, getEqualString(actual, expected, pass));
}
@@ -240,12 +245,11 @@ public class FennecMochitestAssert imple
private String getNotEqualString(Object a, Object b, boolean pass) {
if(pass) {
return a + " should not equal " + b;
}
return "didn't expect " + a + ", but got it";
}
public void info(String name, String message) {
- testInfo test = new testInfo(true, name, message, false, true);
- _logMochitestResult(test, "TEST-INFO", "INFO FAILED?");
+ mLogger.info(name + " | " + message);
}
}
--- a/build/mobile/robocop/StructuredLogger.java
+++ b/build/mobile/robocop/StructuredLogger.java
@@ -39,16 +39,20 @@ public class StructuredLogger {
mComponent = component;
mCallback = callback;
}
public StructuredLogger(String name, String component) {
this(name, component, new StandardLoggerCallback());
}
+ public StructuredLogger(String name, LoggerCallback callback) {
+ this(name, null, callback);
+ }
+
public StructuredLogger(String name) {
this(name, null, new StandardLoggerCallback());
}
public void suiteStart(List<String> tests, Map<String, Object> runInfo) {
HashMap<String, Object> data = new HashMap<String, Object>();
data.put("tests", tests);
if (runInfo != null) {
--- a/config/system-headers
+++ b/config/system-headers
@@ -1258,17 +1258,16 @@ X11/Xfuncproto.h
X11/X.h
X11/XKBlib.h
X11/Xlib.h
X11/Xlibint.h
X11/Xlocale.h
X11/Xos.h
X11/Xutil.h
zmouse.h
-speex/speex_resampler.h
soundtouch/SoundTouch.h
#if MOZ_NATIVE_PNG==1
png.h
#endif
#if MOZ_NATIVE_ZLIB==1
zlib.h
#endif
#ifdef MOZ_ENABLE_STARTUP_NOTIFICATION
@@ -1320,16 +1319,17 @@ vpx/vpx_codec.h
vpx/vpx_decoder.h
vpx/vpx_encoder.h
vpx/vp8cx.h
vpx/vp8dx.h
vpx_mem/vpx_mem.h
vorbis/codec.h
theora/theoradec.h
tremor/ivorbiscodec.h
+speex/speex_resampler.h
ogg/ogg.h
ogg/os_types.h
nestegg/nestegg.h
cubeb/cubeb.h
#endif
gst/gst.h
gst/app/gstappsink.h
gst/app/gstappsrc.h
--- a/configure.in
+++ b/configure.in
@@ -3839,16 +3839,17 @@ MOZ_LOCALE_SWITCHER=
MOZ_ANDROID_SEARCH_ACTIVITY=
MOZ_ANDROID_MLS_STUMBLER=
ACCESSIBILITY=1
MOZ_TIME_MANAGER=
MOZ_PAY=
MOZ_AUDIO_CHANNEL_MANAGER=
NSS_NO_LIBPKIX=
MOZ_CONTENT_SANDBOX=
+MOZ_GMP_SANDBOX=
JSGC_USE_EXACT_ROOTING=1
JSGC_GENERATIONAL=
case "$target_os" in
mingw*)
NS_ENABLE_TSF=1
AC_DEFINE(NS_ENABLE_TSF)
;;
@@ -6401,16 +6402,38 @@ MOZ_ARG_ENABLE_BOOL(content-sandbox,
if test -n "$MOZ_CONTENT_SANDBOX"; then
AC_DEFINE(MOZ_CONTENT_SANDBOX)
fi
AC_SUBST(MOZ_CONTENT_SANDBOX)
dnl ========================================================
+dnl = Gecko Media Plugin sandboxing
+dnl ========================================================
+case $OS_TARGET in
+WINNT)
+ MOZ_GMP_SANDBOX=1
+ ;;
+Linux)
+ case $CPU_ARCH in
+ x86_64|x86)
+ MOZ_GMP_SANDBOX=1
+ ;;
+ esac
+ ;;
+esac
+
+if test -n "$MOZ_GMP_SANDBOX"; then
+ AC_DEFINE(MOZ_GMP_SANDBOX)
+fi
+
+AC_SUBST(MOZ_GMP_SANDBOX)
+
+dnl ========================================================
dnl =
dnl = Module specific options
dnl =
dnl ========================================================
MOZ_ARG_HEADER(Individual module options)
dnl ========================================================
dnl = Disable feed handling components
--- a/content/base/src/Element.cpp
+++ b/content/base/src/Element.cpp
@@ -1741,17 +1741,17 @@ Element::DispatchClickEvent(nsPresContex
}
return DispatchEvent(aPresContext, &event, aTarget, aFullDispatch, aStatus);
}
nsIFrame*
Element::GetPrimaryFrame(mozFlushType aType)
{
- nsIDocument* doc = GetCurrentDoc();
+ nsIDocument* doc = GetComposedDoc();
if (!doc) {
return nullptr;
}
// Cause a flush, so we get up-to-date frame
// information
if (aType != Flush_None) {
doc->FlushPendingNotifications(aType);
--- a/content/base/src/nsDocument.cpp
+++ b/content/base/src/nsDocument.cpp
@@ -1511,17 +1511,17 @@ struct nsIDocument::FrameRequest
bool operator<(int32_t aHandle) const {
return mHandle < aHandle;
}
FrameRequestCallbackHolder mCallback;
int32_t mHandle;
};
-static already_AddRefed<mozilla::dom::NodeInfo> nullNodeInfo(nullptr);
+static already_AddRefed<mozilla::dom::NodeInfo> nullNodeInfo;
// ==================================================================
// =
// ==================================================================
nsIDocument::nsIDocument()
: nsINode(nullNodeInfo),
mCharacterSet(NS_LITERAL_CSTRING("ISO-8859-1")),
mNodeInfoManager(nullptr),
--- a/content/base/src/nsScriptLoader.cpp
+++ b/content/base/src/nsScriptLoader.cpp
@@ -322,22 +322,29 @@ nsScriptLoader::StartLoad(nsScriptLoadRe
nsCOMPtr<nsIChannel> channel;
rv = NS_NewChannel(getter_AddRefs(channel),
aRequest->mURI, nullptr, loadGroup, prompter,
nsIRequest::LOAD_NORMAL | nsIChannel::LOAD_CLASSIFY_URI,
channelPolicy);
NS_ENSURE_SUCCESS(rv, rv);
nsIScriptElement *script = aRequest->mElement;
- if (aScriptFromHead &&
- !(script && (script->GetScriptAsync() || script->GetScriptDeferred()))) {
- nsCOMPtr<nsIHttpChannelInternal>
- internalHttpChannel(do_QueryInterface(channel));
- if (internalHttpChannel)
+ nsCOMPtr<nsIHttpChannelInternal>
+ internalHttpChannel(do_QueryInterface(channel));
+
+ if (internalHttpChannel) {
+ if (aScriptFromHead &&
+ !(script && (script->GetScriptAsync() || script->GetScriptDeferred()))) {
+ // synchronous head scripts block lading of most other non js/css
+ // content such as images
internalHttpChannel->SetLoadAsBlocking(true);
+ } else if (!(script && script->GetScriptDeferred())) {
+ // other scripts are neither blocked nor prioritized unless marked deferred
+ internalHttpChannel->SetLoadUnblocked(true);
+ }
}
nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(channel));
if (httpChannel) {
// HTTP content negotation has little value in this context.
httpChannel->SetRequestHeader(NS_LITERAL_CSTRING("Accept"),
NS_LITERAL_CSTRING("*/*"),
false);
--- a/content/base/test/mochitest.ini
+++ b/content/base/test/mochitest.ini
@@ -645,8 +645,9 @@ skip-if = toolkit == 'android'
disabled = Disabled for now. Mochitest isn't reliable enough for these.
support-files = bug444546.sjs
[test_bug503473.html]
disabled = Disabled due to making the harness time out
support-files = file_bug503473-frame.sjs
[test_bug1011748.html]
skip-if = buildapp == 'b2g' || e10s
support-files = file_bug1011748_redirect.sjs file_bug1011748_OK.sjs
+[test_bug1025933.html]
--- a/content/base/test/script_bug602838.sjs
+++ b/content/base/test/script_bug602838.sjs
@@ -1,18 +1,37 @@
+function setOurState(data) {
+ x = { data: data, QueryInterface: function(iid) { return this } };
+ x.wrappedJSObject = x;
+ setObjectState("bug602838", x);
+}
+
+function getOurState() {
+ var data;
+ getObjectState("bug602838", function(x) {
+ // x can be null if no one has set any state yet
+ if (x) {
+ data = x.wrappedJSObject.data;
+ }
+ });
+ return data;
+}
+
function handleRequest(request, response)
{
if (request.queryString) {
- let blockedResponse = null;
- getObjectState("bug602838", function(x) { blockedResponse = x.wrappedJSObject.r });
- blockedResponse.finish();
- setObjectState("bug602838", null);
+ let blockedResponse = getOurState();
+ if (typeof(blockedResponse) == "object") {
+ blockedResponse.finish();
+ setOurState(null);
+ } else {
+ setOurState("unblocked");
+ }
return;
}
response.setHeader("Cache-Control", "no-cache", false);
response.setHeader("Content-Type", "text/javascript", false);
response.write("ok(asyncRan, 'Async script should have run first.'); firstRan = true;");
- response.processAsync();
-
- x = { r: response, QueryInterface: function(iid) { return this } };
- x.wrappedJSObject = x;
- setObjectState("bug602838", x);
+ if (getOurState() != "unblocked") {
+ response.processAsync();
+ setOurState(response);
+ }
}
new file mode 100644
--- /dev/null
+++ b/content/base/test/test_bug1025933.html
@@ -0,0 +1,37 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1025933
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Test for Bug 1025933</title>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+ <script type="application/javascript">
+
+ /** Test for Bug 1025933 **/
+
+ SimpleTest.waitForExplicitFinish();
+
+ function test() {
+ var s = document.getElementById("host").createShadowRoot();
+ s.innerHTML = '<div style="width:100px;height:100px;background:red"></div>';
+ var el = s.firstElementChild;
+ is(el.clientWidth, 100);
+ is(el.clientHeight, 100);
+ SimpleTest.finish();
+ }
+
+ </script>
+</head>
+<body onload="test()">
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1025933">Mozilla Bug 1025933</a>
+<p id="display"></p>
+<div id="content">
+ <div id="host"></div>
+</div>
+<pre id="test">
+</pre>
+</body>
+</html>
--- a/content/html/content/src/HTMLMediaElement.cpp
+++ b/content/html/content/src/HTMLMediaElement.cpp
@@ -2642,22 +2642,25 @@ nsresult HTMLMediaElement::FinishDecoder
mPendingEvents.Clear();
// Set mDecoder now so if methods like GetCurrentSrc get called between
// here and Load(), they work.
mDecoder = aDecoder;
// Tell the decoder about its MediaResource now so things like principals are
// available immediately.
mDecoder->SetResource(aStream);
- aDecoder->SetAudioChannel(mAudioChannel);
+ mDecoder->SetAudioChannel(mAudioChannel);
mDecoder->SetAudioCaptured(mAudioCaptured);
mDecoder->SetVolume(mMuted ? 0.0 : mVolume);
mDecoder->SetPreservesPitch(mPreservesPitch);
mDecoder->SetPlaybackRate(mPlaybackRate);
+ if (mMediaKeys) {
+ mDecoder->SetCDMProxy(mMediaKeys->GetCDMProxy());
+ }
if (mPreloadAction == HTMLMediaElement::PRELOAD_METADATA) {
mDecoder->SetMinimizePrerollUntilPlaybackStarts();
}
// Update decoder principal before we start decoding, since it
// can affect how we feed data to MediaStreams
NotifyDecoderPrincipalChanged();
@@ -3969,16 +3972,19 @@ HTMLMediaElement::SetMediaKeys(mozilla::
// TODO: Need to shutdown existing MediaKeys instance? bug 1016709.
nsRefPtr<Promise> promise = Promise::Create(global, aRv);
if (aRv.Failed()) {
return nullptr;
}
if (mMediaKeys != aMediaKeys) {
mMediaKeys = aMediaKeys;
}
+ if (mDecoder) {
+ mDecoder->SetCDMProxy(mMediaKeys->GetCDMProxy());
+ }
promise->MaybeResolve(JS::UndefinedHandleValue);
return promise.forget();
}
MediaWaitingFor
HTMLMediaElement::WaitingFor() const
{
return mWaitingFor;
--- a/content/media/AbstractMediaDecoder.h
+++ b/content/media/AbstractMediaDecoder.h
@@ -20,16 +20,17 @@ namespace layers
{
class ImageContainer;
}
class MediaResource;
class ReentrantMonitor;
class VideoFrameContainer;
class TimedMetadata;
class MediaDecoderOwner;
+class CDMProxy;
typedef nsDataHashtable<nsCStringHashKey, nsCString> MetadataTags;
static inline bool IsCurrentThread(nsIThread* aThread) {
return NS_GetCurrentThread() == aThread;
}
/**
@@ -132,16 +133,19 @@ public:
~AutoNotifyDecoded() {
mDecoder->NotifyDecodedFrames(mParsed, mDecoded);
}
private:
AbstractMediaDecoder* mDecoder;
uint32_t& mParsed;
uint32_t& mDecoded;
};
+
+ virtual nsresult SetCDMProxy(CDMProxy* aProxy) { return NS_ERROR_NOT_IMPLEMENTED; }
+ virtual CDMProxy* GetCDMProxy() { return nullptr; }
};
class MetadataEventRunner : public nsRunnable
{
private:
nsRefPtr<AbstractMediaDecoder> mDecoder;
public:
MetadataEventRunner(AbstractMediaDecoder* aDecoder, MediaInfo* aInfo, MetadataTags* aTags)
--- a/content/media/AudioNodeExternalInputStream.cpp
+++ b/content/media/AudioNodeExternalInputStream.cpp
@@ -1,17 +1,16 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-*/
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "AudioNodeEngine.h"
#include "AudioNodeExternalInputStream.h"
#include "AudioChannelFormat.h"
-#include "speex/speex_resampler.h"
#include "mozilla/dom/MediaStreamAudioSourceNode.h"
using namespace mozilla::dom;
namespace mozilla {
AudioNodeExternalInputStream::AudioNodeExternalInputStream(AudioNodeEngine* aEngine, TrackRate aSampleRate)
: AudioNodeStream(aEngine, MediaStreamGraph::INTERNAL_STREAM, aSampleRate)
--- a/content/media/AudioSegment.cpp
+++ b/content/media/AudioSegment.cpp
@@ -4,17 +4,17 @@
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "AudioSegment.h"
#include "AudioStream.h"
#include "AudioMixer.h"
#include "AudioChannelFormat.h"
#include "Latency.h"
-#include "speex/speex_resampler.h"
+#include <speex/speex_resampler.h>
namespace mozilla {
template <class SrcT, class DestT>
static void
InterleaveAndConvertBuffer(const SrcT** aSourceChannels,
int32_t aLength, float aVolume,
int32_t aChannels,
--- a/content/media/MediaDecoder.cpp
+++ b/content/media/MediaDecoder.cpp
@@ -1655,16 +1655,35 @@ bool MediaDecoder::CanPlayThrough()
// we don't suddenly discover that we need to buffer. This is particularly
// required near the start of the media, when not much data is downloaded.
int64_t readAheadMargin =
static_cast<int64_t>(stats.mPlaybackRate * CAN_PLAY_THROUGH_MARGIN);
return stats.mTotalBytes == stats.mDownloadPosition ||
stats.mDownloadPosition > stats.mPlaybackPosition + readAheadMargin;
}
+nsresult
+MediaDecoder::SetCDMProxy(CDMProxy* aProxy)
+{
+ ReentrantMonitorAutoEnter mon(GetReentrantMonitor());
+ MOZ_ASSERT(NS_IsMainThread());
+ mProxy = aProxy;
+ // Awaken any readers waiting for the proxy.
+ NotifyWaitingForResourcesStatusChanged();
+ return NS_OK;
+}
+
+CDMProxy*
+MediaDecoder::GetCDMProxy()
+{
+ GetReentrantMonitor().AssertCurrentThreadIn();
+ MOZ_ASSERT(OnDecodeThread() || NS_IsMainThread());
+ return mProxy;
+}
+
#ifdef MOZ_RAW
bool
MediaDecoder::IsRawEnabled()
{
return Preferences::GetBool("media.raw.enabled");
}
#endif
--- a/content/media/MediaDecoder.h
+++ b/content/media/MediaDecoder.h
@@ -185,16 +185,17 @@ destroying the MediaDecoder object.
#include "MediaResource.h"
#include "mozilla/dom/AudioChannelBinding.h"
#include "mozilla/gfx/Rect.h"
#include "mozilla/ReentrantMonitor.h"
#include "mozilla/TimeStamp.h"
#include "MediaStreamGraph.h"
#include "AbstractMediaDecoder.h"
#include "necko-config.h"
+#include "mozilla/CDMProxy.h"
class nsIStreamListener;
class nsIPrincipal;
class nsITimer;
namespace mozilla {
namespace dom {
class TimeRanges;
@@ -844,16 +845,22 @@ public:
// Returns true if we're logically playing, that is, if the Play() has
// been called and Pause() has not or we have not yet reached the end
// of media. This is irrespective of the seeking state; if the owner
// calls Play() and then Seek(), we still count as logically playing.
// The decoder monitor must be held.
bool IsLogicallyPlaying();
+ // This takes the decoder monitor.
+ virtual nsresult SetCDMProxy(CDMProxy* aProxy) MOZ_OVERRIDE;
+
+ // Decoder monitor must be held.
+ virtual CDMProxy* GetCDMProxy() MOZ_OVERRIDE;
+
#ifdef MOZ_RAW
static bool IsRawEnabled();
#endif
static bool IsOggEnabled();
static bool IsOpusEnabled();
#ifdef MOZ_WAVE
@@ -1094,16 +1101,18 @@ private:
}
private:
ReentrantMonitor mReentrantMonitor;
};
// The |RestrictedAccessMonitor| member object.
RestrictedAccessMonitor mReentrantMonitor;
+ nsRefPtr<CDMProxy> mProxy;
+
protected:
// Data about MediaStreams that are being fed by this decoder.
nsTArray<OutputStreamData> mOutputStreams;
// The SourceMediaStream we are using to feed the mOutputStreams. This stream
// is never exposed outside the decoder.
// Only written on the main thread while holding the monitor. Therefore it
// can be read on any thread while holding the monitor, or on the main thread
// without holding the monitor.
--- a/content/media/MediaDecoderOwner.h
+++ b/content/media/MediaDecoderOwner.h
@@ -132,14 +132,20 @@ public:
// Called by the media decoder and the video frame to get the
// ImageContainer containing the video data.
virtual VideoFrameContainer* GetVideoFrameContainer() = 0;
// Called by the media decoder object, on the main thread,
// when the connection between Rtsp server and client gets lost.
virtual void ResetConnectionState() = 0;
+
+ // Dispatches a "needkey" event to the HTMLMediaElement, with the
+ // provided init data.
+ // Main thread only.
+ virtual void DispatchNeedKey(const nsTArray<uint8_t>& aInitData,
+ const nsAString& aInitDataType) = 0;
};
}
#endif
--- a/content/media/MediaDecoderReader.h
+++ b/content/media/MediaDecoderReader.h
@@ -171,17 +171,17 @@ public:
AudioData* DecodeToFirstAudioData();
VideoData* DecodeToFirstVideoData();
MediaInfo GetMediaInfo() { return mInfo; }
// Indicates if the media is seekable.
// ReadMetada should be called before calling this method.
virtual bool IsMediaSeekable() = 0;
-
+
protected:
virtual ~MediaDecoderReader();
// Overrides of this function should decodes an unspecified amount of
// audio data, enqueuing the audio data in mAudioQueue. Returns true
// when there's more audio to decode, false if the audio is finished,
// end of file has been reached, or an un-recoverable read error has
// occured. This function blocks until the decode is complete.
--- a/content/media/MediaRecorder.cpp
+++ b/content/media/MediaRecorder.cpp
@@ -449,17 +449,18 @@ private:
return;
}
}
// In case source media stream does not notify track end, recieve
// shutdown notification and stop Read Thread.
nsContentUtils::RegisterShutdownObserver(this);
- nsRefPtr<nsIRunnable> event = new ExtractRunnable(this);
+ already_AddRefed<Session> session(this); // addref in MediaRecorder::Start
+ nsRefPtr<nsIRunnable> event = new ExtractRunnable(Move(session));
if (NS_FAILED(mReadThread->Dispatch(event, NS_DISPATCH_NORMAL))) {
NS_WARNING("Failed to dispatch ExtractRunnable at beginning");
}
}
// application should get blob and onstop event
void DoSessionEndTask(nsresult rv)
{
MOZ_ASSERT(NS_IsMainThread());
@@ -467,17 +468,18 @@ private:
mRecorder->NotifyError(rv);
}
CleanupStreams();
if (NS_FAILED(NS_DispatchToMainThread(new PushBlobRunnable(this)))) {
MOZ_ASSERT(false, "NS_DispatchToMainThread PushBlobRunnable failed");
}
// Destroy this session object in main thread.
- if (NS_FAILED(NS_DispatchToMainThread(new DestroyRunnable(this)))) {
+ already_AddRefed<Session> session(this); // addref in MediaRecorder::Start
+ if (NS_FAILED(NS_DispatchToMainThread(new DestroyRunnable(Move(session))))) {
MOZ_ASSERT(false, "NS_DispatchToMainThread DestroyRunnable failed");
}
}
void CleanupStreams()
{
if (mInputPort.get()) {
mInputPort->Destroy();
mInputPort = nullptr;
--- a/content/media/MediaStreamGraph.cpp
+++ b/content/media/MediaStreamGraph.cpp
@@ -23,17 +23,16 @@
#include "AudioChannelService.h"
#include "AudioNodeEngine.h"
#include "AudioNodeStream.h"
#include "AudioNodeExternalInputStream.h"
#include <algorithm>
#include "DOMMediaStream.h"
#include "GeckoProfiler.h"
#include "mozilla/unused.h"
-#include "speex/speex_resampler.h"
#ifdef MOZ_WEBRTC
#include "AudioOutputObserver.h"
#endif
using namespace mozilla::layers;
using namespace mozilla::dom;
using namespace mozilla::gfx;
--- a/content/media/MediaStreamGraph.h
+++ b/content/media/MediaStreamGraph.h
@@ -12,17 +12,17 @@
#include "nsTArray.h"
#include "nsIRunnable.h"
#include "StreamBuffer.h"
#include "TimeVarying.h"
#include "VideoFrameContainer.h"
#include "VideoSegment.h"
#include "MainThreadUtils.h"
#include "nsAutoRef.h"
-#include "speex/speex_resampler.h"
+#include <speex/speex_resampler.h>
#include "AudioMixer.h"
#include "mozilla/dom/AudioChannelBinding.h"
class nsIRunnable;
template <>
class nsAutoRefTraits<SpeexResamplerState> : public nsPointerRefTraits<SpeexResamplerState>
{
--- a/content/media/MediaTaskQueue.cpp
+++ b/content/media/MediaTaskQueue.cpp
@@ -43,16 +43,56 @@ MediaTaskQueue::Dispatch(TemporaryRef<ns
NS_WARNING("Failed to dispatch runnable to run MediaTaskQueue");
return rv;
}
mIsRunning = true;
return NS_OK;
}
+class MediaTaskQueueSyncRunnable : public nsRunnable {
+public:
+ MediaTaskQueueSyncRunnable(TemporaryRef<nsIRunnable> aRunnable)
+ : mRunnable(aRunnable)
+ , mMonitor("MediaTaskQueueSyncRunnable")
+ , mDone(false)
+ {
+ }
+
+ NS_IMETHOD Run() {
+ nsresult rv = mRunnable->Run();
+ {
+ MonitorAutoLock mon(mMonitor);
+ mDone = true;
+ mon.NotifyAll();
+ }
+ return rv;
+ }
+
+ nsresult WaitUntilDone() {
+ MonitorAutoLock mon(mMonitor);
+ while (!mDone) {
+ mon.Wait();
+ }
+ return NS_OK;
+ }
+private:
+ RefPtr<nsIRunnable> mRunnable;
+ Monitor mMonitor;
+ bool mDone;
+};
+
+nsresult
+MediaTaskQueue::SyncDispatch(TemporaryRef<nsIRunnable> aRunnable) {
+ RefPtr<MediaTaskQueueSyncRunnable> task(new MediaTaskQueueSyncRunnable(aRunnable));
+ nsresult rv = Dispatch(task);
+ NS_ENSURE_SUCCESS(rv, rv);
+ return task->WaitUntilDone();
+}
+
void
MediaTaskQueue::AwaitIdle()
{
MonitorAutoLock mon(mQueueMonitor);
AwaitIdleLocked();
}
void
--- a/content/media/MediaTaskQueue.h
+++ b/content/media/MediaTaskQueue.h
@@ -28,16 +28,18 @@ class MediaTaskQueue MOZ_FINAL {
public:
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(MediaTaskQueue)
MediaTaskQueue(TemporaryRef<SharedThreadPool> aPool);
nsresult Dispatch(TemporaryRef<nsIRunnable> aRunnable);
+ nsresult SyncDispatch(TemporaryRef<nsIRunnable> aRunnable);
+
// Removes all pending tasks from the task queue, and blocks until
// the currently running task (if any) finishes.
void Flush();
// Blocks until all tasks finish executing, then shuts down the task queue
// and exits.
void Shutdown();
new file mode 100644
--- /dev/null
+++ b/content/media/eme/CDMCallbackProxy.cpp
@@ -0,0 +1,284 @@
+/* -*- 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/CDMCallbackProxy.h"
+#include "mozilla/CDMProxy.h"
+#include "nsString.h"
+#include "mozilla/dom/MediaKeys.h"
+#include "mozilla/dom/MediaKeySession.h"
+#include "mozIGeckoMediaPluginService.h"
+#include "nsContentCID.h"
+#include "nsServiceManagerUtils.h"
+#include "MainThreadUtils.h"
+#include "EMELog.h"
+
+namespace mozilla {
+
+CDMCallbackProxy::CDMCallbackProxy(CDMProxy* aProxy)
+ : mProxy(aProxy)
+{
+
+}
+
+class NewSessionTask : public nsRunnable {
+public:
+ NewSessionTask(CDMProxy* aProxy,
+ uint32_t aPromiseId,
+ const nsCString& aSessionId)
+ : mProxy(aProxy)
+ , mPid(aPromiseId)
+ , mSid(NS_ConvertUTF8toUTF16(aSessionId))
+ {
+ }
+
+ NS_IMETHOD Run() {
+ mProxy->OnResolveNewSessionPromise(mPid, mSid);
+ return NS_OK;
+ }
+
+ nsRefPtr<CDMProxy> mProxy;
+ dom::PromiseId mPid;
+ nsString mSid;
+};
+
+void
+CDMCallbackProxy::ResolveNewSessionPromise(uint32_t aPromiseId,
+ const nsCString& aSessionId)
+{
+ MOZ_ASSERT(mProxy->IsOnGMPThread());
+
+ nsRefPtr<nsIRunnable> task(new NewSessionTask(mProxy,
+ aPromiseId,
+ aSessionId));
+ NS_DispatchToMainThread(task);
+}
+
+void
+CDMCallbackProxy::ResolvePromise(uint32_t aPromiseId)
+{
+ MOZ_ASSERT(mProxy->IsOnGMPThread());
+
+ // Note: CDMProxy proxies this from non-main threads to main thread.
+ mProxy->ResolvePromise(aPromiseId);
+}
+
+class RejectPromiseTask : public nsRunnable {
+public:
+ RejectPromiseTask(CDMProxy* aProxy,
+ uint32_t aPromiseId,
+ nsresult aException,
+ const nsCString& aMessage)
+ : mProxy(aProxy)
+ , mPid(aPromiseId)
+ , mException(aException)
+ , mMsg(NS_ConvertUTF8toUTF16(aMessage))
+ {
+ }
+
+ NS_IMETHOD Run() {
+ mProxy->OnRejectPromise(mPid, mException, mMsg);
+ return NS_OK;
+ }
+
+ nsRefPtr<CDMProxy> mProxy;
+ dom::PromiseId mPid;
+ nsresult mException;
+ nsString mMsg;
+};
+
+
+void
+CDMCallbackProxy::RejectPromise(uint32_t aPromiseId,
+ nsresult aException,
+ const nsCString& aMessage)
+{
+ MOZ_ASSERT(mProxy->IsOnGMPThread());
+
+ nsRefPtr<nsIRunnable> task;
+ task = new RejectPromiseTask(mProxy,
+ aPromiseId,
+ aException,
+ aMessage);
+ NS_DispatchToMainThread(task);
+}
+
+class SessionMessageTask : public nsRunnable {
+public:
+ SessionMessageTask(CDMProxy* aProxy,
+ const nsCString& aSessionId,
+ const nsTArray<uint8_t>& aMessage,
+ const nsCString& aDestinationURL)
+ : mProxy(aProxy)
+ , mSid(NS_ConvertUTF8toUTF16(aSessionId))
+ , mURL(NS_ConvertUTF8toUTF16(aDestinationURL))
+ {
+ mMsg.AppendElements(aMessage);
+ }
+
+ NS_IMETHOD Run() {
+ mProxy->OnSessionMessage(mSid, mMsg, mURL);
+ return NS_OK;
+ }
+
+ nsRefPtr<CDMProxy> mProxy;
+ dom::PromiseId mPid;
+ nsString mSid;
+ nsTArray<uint8_t> mMsg;
+ nsString mURL;
+};
+
+void
+CDMCallbackProxy::SessionMessage(const nsCString& aSessionId,
+ const nsTArray<uint8_t>& aMessage,
+ const nsCString& aDestinationURL)
+{
+ MOZ_ASSERT(mProxy->IsOnGMPThread());
+
+ nsRefPtr<nsIRunnable> task;
+ task = new SessionMessageTask(mProxy,
+ aSessionId,
+ aMessage,
+ aDestinationURL);
+ NS_DispatchToMainThread(task);
+}
+
+class ExpirationChangeTask : public nsRunnable {
+public:
+ ExpirationChangeTask(CDMProxy* aProxy,
+ const nsCString& aSessionId,
+ GMPTimestamp aExpiryTime)
+ : mProxy(aProxy)
+ , mSid(NS_ConvertUTF8toUTF16(aSessionId))
+ , mTimestamp(aExpiryTime)
+ {}
+
+ NS_IMETHOD Run() {
+ mProxy->OnExpirationChange(mSid, mTimestamp);
+ return NS_OK;
+ }
+
+ nsRefPtr<CDMProxy> mProxy;
+ nsString mSid;
+ GMPTimestamp mTimestamp;
+};
+
+void
+CDMCallbackProxy::ExpirationChange(const nsCString& aSessionId,
+ GMPTimestamp aExpiryTime)
+{
+ MOZ_ASSERT(mProxy->IsOnGMPThread());
+
+ nsRefPtr<nsIRunnable> task;
+ task = new ExpirationChangeTask(mProxy,
+ aSessionId,
+ aExpiryTime);
+ NS_DispatchToMainThread(task);
+}
+
+void
+CDMCallbackProxy::SessionClosed(const nsCString& aSessionId)
+{
+ MOZ_ASSERT(mProxy->IsOnGMPThread());
+
+ nsRefPtr<nsIRunnable> task;
+ task = NS_NewRunnableMethodWithArg<nsString>(mProxy,
+ &CDMProxy::OnSessionClosed,
+ NS_ConvertUTF8toUTF16(aSessionId));
+ NS_DispatchToMainThread(task);
+}
+
+class SessionErrorTask : public nsRunnable {
+public:
+ SessionErrorTask(CDMProxy* aProxy,
+ const nsCString& aSessionId,
+ nsresult aException,
+ uint32_t aSystemCode,
+ const nsCString& aMessage)
+ : mProxy(aProxy)
+ , mSid(NS_ConvertUTF8toUTF16(aSessionId))
+ , mException(aException)
+ , mSystemCode(aSystemCode)
+ , mMsg(NS_ConvertUTF8toUTF16(aMessage))
+ {}
+
+ NS_IMETHOD Run() {
+ mProxy->OnSessionError(mSid, mException, mSystemCode, mMsg);
+ return NS_OK;
+ }
+
+ nsRefPtr<CDMProxy> mProxy;
+ dom::PromiseId mPid;
+ nsString mSid;
+ nsresult mException;
+ uint32_t mSystemCode;
+ nsString mMsg;
+};
+
+void
+CDMCallbackProxy::SessionError(const nsCString& aSessionId,
+ nsresult aException,
+ uint32_t aSystemCode,
+ const nsCString& aMessage)
+{
+ MOZ_ASSERT(mProxy->IsOnGMPThread());
+
+ nsRefPtr<nsIRunnable> task;
+ task = new SessionErrorTask(mProxy,
+ aSessionId,
+ aException,
+ aSystemCode,
+ aMessage);
+ NS_DispatchToMainThread(task);
+}
+
+void
+CDMCallbackProxy::KeyIdUsable(const nsCString& aSessionId,
+ const nsTArray<uint8_t>& aKeyId)
+{
+ MOZ_ASSERT(mProxy->IsOnGMPThread());
+
+ CDMCaps::AutoLock caps(mProxy->Capabilites());
+ caps.SetKeyUsable(aKeyId, NS_ConvertUTF8toUTF16(aSessionId));
+}
+
+void
+CDMCallbackProxy::KeyIdNotUsable(const nsCString& aSessionId,
+ const nsTArray<uint8_t>& aKeyId)
+{
+ MOZ_ASSERT(mProxy->IsOnGMPThread());
+
+ CDMCaps::AutoLock caps(mProxy->Capabilites());
+ caps.SetKeyUnusable(aKeyId, NS_ConvertUTF8toUTF16(aSessionId));
+}
+
+void
+CDMCallbackProxy::SetCaps(uint64_t aCaps)
+{
+ MOZ_ASSERT(mProxy->IsOnGMPThread());
+
+ CDMCaps::AutoLock caps(mProxy->Capabilites());
+ caps.SetCaps(aCaps);
+}
+
+void
+CDMCallbackProxy::Decrypted(uint32_t aId,
+ GMPErr aResult,
+ const nsTArray<uint8_t>& aDecryptedData)
+{
+ MOZ_ASSERT(mProxy->IsOnGMPThread());
+
+ mProxy->gmp_Decrypted(aId, aResult, aDecryptedData);
+}
+
+void
+CDMCallbackProxy::Terminated()
+{
+ MOZ_ASSERT(mProxy->IsOnGMPThread());
+
+ mProxy->gmp_Terminated();
+}
+
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/content/media/eme/CDMCallbackProxy.h
@@ -0,0 +1,69 @@
+/* -*- 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 CDMCallbackProxy_h_
+#define CDMCallbackProxy_h_
+
+#include "mozilla/CDMProxy.h"
+#include "gmp-decryption.h"
+#include "GMPDecryptorProxy.h"
+
+namespace mozilla {
+
+// Proxies call backs from the CDM on the GMP thread back to the MediaKeys
+// object on the main thread.
+class CDMCallbackProxy : public GMPDecryptorProxyCallback {
+public:
+ virtual void ResolveNewSessionPromise(uint32_t aPromiseId,
+ const nsCString& aSessionId) MOZ_OVERRIDE;
+
+ virtual void ResolvePromise(uint32_t aPromiseId) MOZ_OVERRIDE;
+
+ virtual void RejectPromise(uint32_t aPromiseId,
+ nsresult aException,
+ const nsCString& aSessionId) MOZ_OVERRIDE;
+
+ virtual void SessionMessage(const nsCString& aSessionId,
+ const nsTArray<uint8_t>& aMessage,
+ const nsCString& aDestinationURL) MOZ_OVERRIDE;
+
+ virtual void ExpirationChange(const nsCString& aSessionId,
+ GMPTimestamp aExpiryTime) MOZ_OVERRIDE;
+
+ virtual void SessionClosed(const nsCString& aSessionId) MOZ_OVERRIDE;
+
+ virtual void SessionError(const nsCString& aSessionId,
+ nsresult aException,
+ uint32_t aSystemCode,
+ const nsCString& aMessage) MOZ_OVERRIDE;
+
+ virtual void KeyIdUsable(const nsCString& aSessionId,
+ const nsTArray<uint8_t>& aKeyId) MOZ_OVERRIDE;
+
+ virtual void KeyIdNotUsable(const nsCString& aSessionId,
+ const nsTArray<uint8_t>& aKeyId) MOZ_OVERRIDE;
+
+ virtual void SetCaps(uint64_t aCaps) MOZ_OVERRIDE;
+
+ virtual void Decrypted(uint32_t aId,
+ GMPErr aResult,
+ const nsTArray<uint8_t>& aDecryptedData) MOZ_OVERRIDE;
+
+ virtual void Terminated() MOZ_OVERRIDE;
+
+ ~CDMCallbackProxy() {}
+
+private:
+ friend class CDMProxy;
+ explicit CDMCallbackProxy(CDMProxy* aProxy);
+
+ // Warning: Weak ref.
+ CDMProxy* mProxy;
+};
+
+} // namespace mozilla
+
+#endif // CDMCallbackProxy_h_
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/content/media/eme/CDMCaps.cpp
@@ -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/. */
+
+#include "CDMCaps.h"
+#include "gmp-decryption.h"
+#include "EMELog.h"
+#include "nsThreadUtils.h"
+
+namespace mozilla {
+
+CDMCaps::CDMCaps()
+ : mMonitor("CDMCaps")
+ , mCaps(0)
+{
+}
+
+CDMCaps::~CDMCaps()
+{
+}
+
+void
+CDMCaps::Lock()
+{
+ mMonitor.Lock();
+}
+
+void
+CDMCaps::Unlock()
+{
+ mMonitor.Unlock();
+}
+
+bool
+CDMCaps::HasCap(uint64_t aCap)
+{
+ mMonitor.AssertCurrentThreadOwns();
+ return (mCaps & aCap) == aCap;
+}
+
+CDMCaps::AutoLock::AutoLock(CDMCaps& aInstance)
+ : mData(aInstance)
+{
+ mData.Lock();
+}
+
+CDMCaps::AutoLock::~AutoLock()
+{
+ mData.Unlock();
+}
+
+void
+CDMCaps::AutoLock::SetCaps(uint64_t aCaps)
+{
+ EME_LOG("SetCaps()");
+ mData.mMonitor.AssertCurrentThreadOwns();
+ mData.mCaps = aCaps;
+ for (size_t i = 0; i < mData.mWaitForCaps.Length(); i++) {
+ NS_DispatchToMainThread(mData.mWaitForCaps[i], NS_DISPATCH_NORMAL);
+ }
+ mData.mWaitForCaps.Clear();
+}
+
+void
+CDMCaps::AutoLock::CallOnMainThreadWhenCapsAvailable(nsIRunnable* aContinuation)
+{
+ mData.mMonitor.AssertCurrentThreadOwns();
+ if (mData.mCaps) {
+ NS_DispatchToMainThread(aContinuation, NS_DISPATCH_NORMAL);
+ MOZ_ASSERT(mData.mWaitForCaps.IsEmpty());
+ } else {
+ mData.mWaitForCaps.AppendElement(aContinuation);
+ }
+}
+
+bool
+CDMCaps::AutoLock::IsKeyUsable(const CencKeyId& aKeyId)
+{
+ mData.mMonitor.AssertCurrentThreadOwns();
+ const auto& keys = mData.mUsableKeyIds;
+ for (size_t i = 0; i < keys.Length(); i++) {
+ if (keys[i].mId == aKeyId) {
+ return true;
+ }
+ }
+ return false;
+}
+
+void
+CDMCaps::AutoLock::SetKeyUsable(const CencKeyId& aKeyId,
+ const nsString& aSessionId)
+{
+ mData.mMonitor.AssertCurrentThreadOwns();
+ mData.mUsableKeyIds.AppendElement(UsableKey(aKeyId, aSessionId));
+ auto& waiters = mData.mWaitForKeys;
+ size_t i = 0;
+ while (i < waiters.Length()) {
+ auto& w = waiters[i];
+ if (w.mKeyId == aKeyId) {
+ if (waiters[i].mTarget) {
+ EME_LOG("SetKeyUsable() notified waiter.");
+ w.mTarget->Dispatch(w.mContinuation, NS_DISPATCH_NORMAL);
+ } else {
+ w.mContinuation->Run();
+ }
+ waiters.RemoveElementAt(i);
+ } else {
+ i++;
+ }
+ }
+}
+
+void
+CDMCaps::AutoLock::SetKeyUnusable(const CencKeyId& aKeyId,
+ const nsString& aSessionId)
+{
+ mData.mMonitor.AssertCurrentThreadOwns();
+ auto& keys = mData.mUsableKeyIds;
+ for (size_t i = 0; i < keys.Length(); i++) {
+ if (keys[i].mId == aKeyId &&
+ keys[i].mSessionId == aSessionId) {
+ keys.RemoveElementAt(i);
+ break;
+ }
+ }
+}
+
+void
+CDMCaps::AutoLock::CallWhenKeyUsable(const CencKeyId& aKey,
+ nsIRunnable* aContinuation,
+ nsIThread* aTarget)
+{
+ mData.mMonitor.AssertCurrentThreadOwns();
+ MOZ_ASSERT(!IsKeyUsable(aKey));
+ MOZ_ASSERT(aContinuation);
+ mData.mWaitForKeys.AppendElement(WaitForKeys(aKey, aContinuation, aTarget));
+}
+
+void
+CDMCaps::AutoLock::DropKeysForSession(const nsAString& aSessionId)
+{
+ mData.mMonitor.AssertCurrentThreadOwns();
+ auto& keys = mData.mUsableKeyIds;
+ size_t i = 0;
+ while (i < keys.Length()) {
+ if (keys[i].mSessionId == aSessionId) {
+ keys.RemoveElementAt(i);
+ } else {
+ i++;
+ }
+ }
+}
+
+bool
+CDMCaps::AutoLock::AreCapsKnown()
+{
+ mData.mMonitor.AssertCurrentThreadOwns();
+ return mData.mCaps != 0;
+}
+
+bool
+CDMCaps::AutoLock::CanDecryptAndDecodeAudio()
+{
+ return mData.HasCap(GMP_EME_CAP_DECRYPT_AND_DECODE_AUDIO);
+}
+
+bool
+CDMCaps::AutoLock::CanDecryptAndDecodeVideo()
+{
+ return mData.HasCap(GMP_EME_CAP_DECRYPT_AND_DECODE_VIDEO);
+}
+
+bool
+CDMCaps::AutoLock::CanDecryptAudio()
+{
+ return mData.HasCap(GMP_EME_CAP_DECRYPT_AUDIO);
+}
+
+bool
+CDMCaps::AutoLock::CanDecryptVideo()
+{
+ return mData.HasCap(GMP_EME_CAP_DECRYPT_VIDEO);
+}
+
+} // namespace mozilla
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/content/media/eme/CDMCaps.h
@@ -0,0 +1,117 @@
+/* -*- 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 CDMCaps_h_
+#define CDMCaps_h_
+
+#include "nsString.h"
+#include "nsAutoPtr.h"
+#include "mozilla/Monitor.h"
+#include "nsIThread.h"
+#include "nsTArray.h"
+#include "mozilla/Attributes.h"
+
+namespace mozilla {
+
+typedef nsTArray<uint8_t> CencKeyId;
+
+// CDM capabilities; what keys a CDMProxy can use, and whether it can decrypt, or
+// decrypt-and-decode on a per stream basis. Must be locked to access state.
+class CDMCaps {
+public:
+ CDMCaps();
+ ~CDMCaps();
+
+ // Locks the CDMCaps. It must be locked to access its shared state.
+ // Threadsafe when locked.
+ class MOZ_STACK_CLASS AutoLock {
+ public:
+ explicit AutoLock(CDMCaps& aKeyCaps);
+ ~AutoLock();
+
+ // Returns true if the capabilities of the CDM are known, i.e. they have
+ // been reported by the CDM to Gecko.
+ bool AreCapsKnown();
+
+ bool IsKeyUsable(const CencKeyId& aKeyId);
+
+ void SetKeyUsable(const CencKeyId& aKeyId, const nsString& aSessionId);
+ void SetKeyUnusable(const CencKeyId& aKeyId, const nsString& aSessionId);
+
+ void DropKeysForSession(const nsAString& aSessionId);
+
+ // Sets the capabilities of the CDM. aCaps is the logical OR of the
+ // GMP_EME_CAP_* flags from gmp-decryption.h.
+ void SetCaps(uint64_t aCaps);
+
+ bool CanDecryptAndDecodeAudio();
+ bool CanDecryptAndDecodeVideo();
+
+ bool CanDecryptAudio();
+ bool CanDecryptVideo();
+
+ void CallOnMainThreadWhenCapsAvailable(nsIRunnable* aContinuation);
+
+ // Calls aContinuation on aTarget thread when key become usable.
+ // Pass aTarget=nullptr and runnable will be called on the GMP thread
+ // when key becomes usable.
+ void CallWhenKeyUsable(const CencKeyId& aKey,
+ nsIRunnable* aContinuation,
+ nsIThread* aTarget = nullptr);
+
+ private:
+ // Not taking a strong ref, since this should be allocated on the stack.
+ CDMCaps& mData;
+ };
+
+private:
+ void Lock();
+ void Unlock();
+ bool HasCap(uint64_t);
+
+ struct WaitForKeys {
+ WaitForKeys(const CencKeyId& aKeyId,
+ nsIRunnable* aContinuation,
+ nsIThread* aTarget)
+ : mKeyId(aKeyId)
+ , mContinuation(aContinuation)
+ , mTarget(aTarget)
+ {}
+ CencKeyId mKeyId;
+ nsRefPtr<nsIRunnable> mContinuation;
+ nsCOMPtr<nsIThread> mTarget;
+ };
+
+ Monitor mMonitor;
+
+ struct UsableKey {
+ UsableKey(const CencKeyId& aId,
+ const nsString& aSessionId)
+ : mId(aId)
+ , mSessionId(aSessionId)
+ {}
+ UsableKey(const UsableKey& aOther)
+ : mId(aOther.mId)
+ , mSessionId(aOther.mSessionId)
+ {}
+ CencKeyId mId;
+ nsString mSessionId;
+ };
+ nsTArray<UsableKey> mUsableKeyIds;
+
+ nsTArray<WaitForKeys> mWaitForKeys;
+
+ nsTArray<nsRefPtr<nsIRunnable>> mWaitForCaps;
+ uint64_t mCaps;
+
+ // It is not safe to copy this object.
+ CDMCaps(const CDMCaps&) MOZ_DELETE;
+ CDMCaps& operator=(const CDMCaps&) MOZ_DELETE;
+};
+
+} // namespace mozilla
+
+#endif
--- a/content/media/eme/CDMProxy.cpp
+++ b/content/media/eme/CDMProxy.cpp
@@ -7,158 +7,299 @@
#include "mozilla/CDMProxy.h"
#include "nsString.h"
#include "mozilla/dom/MediaKeys.h"
#include "mozilla/dom/MediaKeySession.h"
#include "mozIGeckoMediaPluginService.h"
#include "nsContentCID.h"
#include "nsServiceManagerUtils.h"
#include "MainThreadUtils.h"
-
-// TODO: Change the functions in this file to do IPC via the Gecko Media
-// Plugins API. In the meantime, the code here merely implements the
-// interface we expect will be required when the IPC is working.
+#include "mozilla/EMELog.h"
+#include "nsIConsoleService.h"
+#include "prenv.h"
+#include "mozilla/PodOperations.h"
+#include "mozilla/CDMCallbackProxy.h"
namespace mozilla {
CDMProxy::CDMProxy(dom::MediaKeys* aKeys, const nsAString& aKeySystem)
: mKeys(aKeys)
, mKeySystem(aKeySystem)
+ , mCDM(nullptr)
+ , mDecryptionJobCount(0)
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_COUNT_CTOR(CDMProxy);
}
CDMProxy::~CDMProxy()
{
MOZ_COUNT_DTOR(CDMProxy);
}
void
CDMProxy::Init(PromiseId aPromiseId)
{
MOZ_ASSERT(NS_IsMainThread());
+
+ nsresult rv = mKeys->GetOrigin(mOrigin);
+ if (NS_FAILED(rv)) {
+ RejectPromise(aPromiseId, NS_ERROR_DOM_INVALID_STATE_ERR);
+ return;
+ }
+ EME_LOG("Creating CDMProxy for origin='%s'",
+ NS_ConvertUTF16toUTF8(GetOrigin()).get());
+
if (!mGMPThread) {
nsCOMPtr<mozIGeckoMediaPluginService> mps =
do_GetService("@mozilla.org/gecko-media-plugin-service;1");
if (!mps) {
RejectPromise(aPromiseId, NS_ERROR_DOM_INVALID_STATE_ERR);
return;
}
mps->GetThread(getter_AddRefs(mGMPThread));
if (!mGMPThread) {
RejectPromise(aPromiseId, NS_ERROR_DOM_INVALID_STATE_ERR);
return;
}
}
- // TODO: Dispatch task to GMPThread to initialize CDM via IPC.
-
- mKeys->OnCDMCreated(aPromiseId);
+ nsRefPtr<nsIRunnable> task(NS_NewRunnableMethodWithArg<uint32_t>(this, &CDMProxy::gmp_Init, aPromiseId));
+ mGMPThread->Dispatch(task, NS_DISPATCH_NORMAL);
}
-static int sFakeSessionIdNum = 0;
+#ifdef DEBUG
+bool
+CDMProxy::IsOnGMPThread()
+{
+ return NS_GetCurrentThread() == mGMPThread;
+}
+#endif
+
+void
+CDMProxy::gmp_Init(uint32_t aPromiseId)
+{
+ MOZ_ASSERT(IsOnGMPThread());
+
+ nsCOMPtr<mozIGeckoMediaPluginService> mps =
+ do_GetService("@mozilla.org/gecko-media-plugin-service;1");
+ if (!mps) {
+ RejectPromise(aPromiseId, NS_ERROR_DOM_INVALID_STATE_ERR);
+ return;
+ }
+
+ nsTArray<nsCString> tags;
+ tags.AppendElement(NS_ConvertUTF16toUTF8(mKeySystem));
+ nsresult rv = mps->GetGMPDecryptor(&tags, GetOrigin(), &mCDM);
+ if (NS_FAILED(rv) || !mCDM) {
+ RejectPromise(aPromiseId, NS_ERROR_DOM_INVALID_STATE_ERR);
+ } else {
+ mCallback = new CDMCallbackProxy(this);
+ mCDM->Init(mCallback);
+ nsRefPtr<nsIRunnable> task(NS_NewRunnableMethodWithArg<uint32_t>(this, &CDMProxy::OnCDMCreated, aPromiseId));
+ NS_DispatchToMainThread(task);
+ }
+}
+
+void
+CDMProxy::OnCDMCreated(uint32_t aPromiseId)
+{
+ MOZ_ASSERT(NS_IsMainThread());
+ if (!mKeys.IsNull()) {
+ mKeys->OnCDMCreated(aPromiseId);
+ } else {
+ NS_WARNING("CDMProxy unable to reject promise!");
+ }
+}
void
CDMProxy::CreateSession(dom::SessionType aSessionType,
PromiseId aPromiseId,
const nsAString& aInitDataType,
const Uint8Array& aInitData)
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(mGMPThread);
- // TODO: Dispatch task to GMPThread to call CDM CreateSession via IPC.
+ nsAutoPtr<CreateSessionData> data(new CreateSessionData());
+ data->mSessionType = aSessionType;
+ data->mPromiseId = aPromiseId;
+ data->mInitDataType = NS_ConvertUTF16toUTF8(aInitDataType);
+ data->mInitData.AppendElements(aInitData.Data(), aInitData.Length());
+
+ nsRefPtr<nsIRunnable> task(
+ NS_NewRunnableMethodWithArg<nsAutoPtr<CreateSessionData>>(this, &CDMProxy::gmp_CreateSession, data));
+ mGMPThread->Dispatch(task, NS_DISPATCH_NORMAL);
+}
- // Make a fake session id. We'll get this from the CDM normally.
- nsAutoString id;
- id.AppendASCII("FakeSessionId_");
- id.AppendInt(sFakeSessionIdNum++);
+GMPSessionType
+ToGMPSessionType(dom::SessionType aSessionType) {
+ switch (aSessionType) {
+ case dom::SessionType::Temporary: return kGMPTemporySession;
+ case dom::SessionType::Persistent: return kGMPPersistentSession;
+ default: return kGMPTemporySession;
+ };
+};
- mKeys->OnSessionActivated(aPromiseId, id);
+void
+CDMProxy::gmp_CreateSession(nsAutoPtr<CreateSessionData> aData)
+{
+ MOZ_ASSERT(IsOnGMPThread());
+ if (!mCDM) {
+ RejectPromise(aData->mPromiseId, NS_ERROR_DOM_INVALID_STATE_ERR);
+ return;
+ }
+ mCDM->CreateSession(aData->mPromiseId,
+ aData->mInitDataType,
+ aData->mInitData,
+ ToGMPSessionType(aData->mSessionType));
}
void
CDMProxy::LoadSession(PromiseId aPromiseId,
const nsAString& aSessionId)
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(mGMPThread);
- // TODO: Dispatch task to GMPThread to call CDM LoadSession via IPC.
- // make MediaKeys::mPendingSessions CC'd
+ nsAutoPtr<SessionOpData> data(new SessionOpData());
+ data->mPromiseId = aPromiseId;
+ data->mSessionId = NS_ConvertUTF16toUTF8(aSessionId);
+ nsRefPtr<nsIRunnable> task(
+ NS_NewRunnableMethodWithArg<nsAutoPtr<SessionOpData>>(this, &CDMProxy::gmp_LoadSession, data));
+ mGMPThread->Dispatch(task, NS_DISPATCH_NORMAL);
+}
- mKeys->OnSessionActivated(aPromiseId, aSessionId);
+void
+CDMProxy::gmp_LoadSession(nsAutoPtr<SessionOpData> aData)
+{
+ MOZ_ASSERT(IsOnGMPThread());
+
+ if (!mCDM) {
+ RejectPromise(aData->mPromiseId, NS_ERROR_DOM_INVALID_STATE_ERR);
+ return;
+ }
+ mCDM->LoadSession(aData->mPromiseId, aData->mSessionId);
}
void
CDMProxy::SetServerCertificate(PromiseId aPromiseId,
- const Uint8Array& aCertData)
+ const Uint8Array& aCert)
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(mGMPThread);
- // TODO: Dispatch task to GMPThread to call CDM SetServerCertificate via IPC.
-
- ResolvePromise(aPromiseId);
+ nsAutoPtr<SetServerCertificateData> data;
+ data->mPromiseId = aPromiseId;
+ data->mCert.AppendElements(aCert.Data(), aCert.Length());
+ nsRefPtr<nsIRunnable> task(
+ NS_NewRunnableMethodWithArg<nsAutoPtr<SetServerCertificateData>>(this, &CDMProxy::gmp_SetServerCertificate, data));
+ mGMPThread->Dispatch(task, NS_DISPATCH_NORMAL);
}
-static int sUpdateCount = 0;
+void
+CDMProxy::gmp_SetServerCertificate(nsAutoPtr<SetServerCertificateData> aData)
+{
+ MOZ_ASSERT(IsOnGMPThread());
+ if (!mCDM) {
+ RejectPromise(aData->mPromiseId, NS_ERROR_DOM_INVALID_STATE_ERR);
+ return;
+ }
+ mCDM->SetServerCertificate(aData->mPromiseId, aData->mCert);
+}
void
CDMProxy::UpdateSession(const nsAString& aSessionId,
PromiseId aPromiseId,
const Uint8Array& aResponse)
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(mGMPThread);
NS_ENSURE_TRUE_VOID(!mKeys.IsNull());
- // TODO: Dispatch task to GMPThread to call CDM UpdateSession via IPC.
+ nsAutoPtr<UpdateSessionData> data(new UpdateSessionData());
+ data->mPromiseId = aPromiseId;
+ data->mSessionId = NS_ConvertUTF16toUTF8(aSessionId);
+ data->mResponse.AppendElements(aResponse.Data(), aResponse.Length());
+ nsRefPtr<nsIRunnable> task(
+ NS_NewRunnableMethodWithArg<nsAutoPtr<UpdateSessionData>>(this, &CDMProxy::gmp_UpdateSession, data));
+ mGMPThread->Dispatch(task, NS_DISPATCH_NORMAL);
+}
- nsRefPtr<dom::MediaKeySession> session(mKeys->GetSession(aSessionId));
- nsAutoCString str(NS_LITERAL_CSTRING("Update_"));
- str.AppendInt(sUpdateCount++);
- nsTArray<uint8_t> msg;
- msg.AppendElements(str.get(), str.Length());
- session->DispatchKeyMessage(msg, NS_LITERAL_STRING("http://bogus.url"));
- ResolvePromise(aPromiseId);
+void
+CDMProxy::gmp_UpdateSession(nsAutoPtr<UpdateSessionData> aData)
+{
+ MOZ_ASSERT(IsOnGMPThread());
+ if (!mCDM) {
+ RejectPromise(aData->mPromiseId, NS_ERROR_DOM_INVALID_STATE_ERR);
+ return;
+ }
+ mCDM->UpdateSession(aData->mPromiseId,
+ aData->mSessionId,
+ aData->mResponse);
}
void
CDMProxy::CloseSession(const nsAString& aSessionId,
PromiseId aPromiseId)
{
MOZ_ASSERT(NS_IsMainThread());
NS_ENSURE_TRUE_VOID(!mKeys.IsNull());
- // TODO: Dispatch task to GMPThread to call CDM CloseSession via IPC.
-
- nsRefPtr<dom::MediaKeySession> session(mKeys->GetSession(aSessionId));
+ {
+ CDMCaps::AutoLock caps(Capabilites());
+ caps.DropKeysForSession(aSessionId);
+ }
+ nsAutoPtr<SessionOpData> data(new SessionOpData());
+ data->mPromiseId = aPromiseId;
+ data->mSessionId = NS_ConvertUTF16toUTF8(aSessionId);
+ nsRefPtr<nsIRunnable> task(
+ NS_NewRunnableMethodWithArg<nsAutoPtr<SessionOpData>>(this, &CDMProxy::gmp_CloseSession, data));
+ mGMPThread->Dispatch(task, NS_DISPATCH_NORMAL);
+}
- // Pretend that the CDM actually does close the session...
- // "...the [MediaKeySession's] closed attribute promise is resolved
- // when the session is closed."
- session->OnClosed();
-
- // "The promise is resolved when the request has been processed."
- ResolvePromise(aPromiseId);
+void
+CDMProxy::gmp_CloseSession(nsAutoPtr<SessionOpData> aData)
+{
+ MOZ_ASSERT(IsOnGMPThread());
+ if (!mCDM) {
+ RejectPromise(aData->mPromiseId, NS_ERROR_DOM_INVALID_STATE_ERR);
+ return;
+ }
+ mCDM->CloseSession(aData->mPromiseId, aData->mSessionId);
}
void
CDMProxy::RemoveSession(const nsAString& aSessionId,
PromiseId aPromiseId)
{
MOZ_ASSERT(NS_IsMainThread());
-
- // TODO: Dispatch task to GMPThread to call CDM RemoveSession via IPC.
+ NS_ENSURE_TRUE_VOID(!mKeys.IsNull());
- // Assume CDM immediately removes session's data, then close the session
- // as per the spec.
- CloseSession(aSessionId, aPromiseId);
+ {
+ CDMCaps::AutoLock caps(Capabilites());
+ caps.DropKeysForSession(aSessionId);
+ }
+ nsAutoPtr<SessionOpData> data(new SessionOpData());
+ data->mPromiseId = aPromiseId;
+ data->mSessionId = NS_ConvertUTF16toUTF8(aSessionId);
+ nsRefPtr<nsIRunnable> task(
+ NS_NewRunnableMethodWithArg<nsAutoPtr<SessionOpData>>(this, &CDMProxy::gmp_RemoveSession, data));
+ mGMPThread->Dispatch(task, NS_DISPATCH_NORMAL);
+}
+
+void
+CDMProxy::gmp_RemoveSession(nsAutoPtr<SessionOpData> aData)
+{
+ MOZ_ASSERT(IsOnGMPThread());
+ if (!mCDM) {
+ RejectPromise(aData->mPromiseId, NS_ERROR_DOM_INVALID_STATE_ERR);
+ return;
+ }
+ mCDM->RemoveSession(aData->mPromiseId, aData->mSessionId);
}
void
CDMProxy::Shutdown()
{
MOZ_ASSERT(NS_IsMainThread());
mKeys.Clear();
}
@@ -191,9 +332,163 @@ CDMProxy::ResolvePromise(PromiseId aId)
nsRefPtr<nsIRunnable> task;
task = NS_NewRunnableMethodWithArg<PromiseId>(this,
&CDMProxy::ResolvePromise,
aId);
NS_DispatchToMainThread(task);
}
}
+const nsAString&
+CDMProxy::GetOrigin() const
+{
+ return mOrigin;
+}
+
+void
+CDMProxy::OnResolveNewSessionPromise(uint32_t aPromiseId,
+ const nsAString& aSessionId)
+{
+ MOZ_ASSERT(NS_IsMainThread());
+ mKeys->OnSessionCreated(aPromiseId, aSessionId);
+}
+
+void
+CDMProxy::OnSessionMessage(const nsAString& aSessionId,
+ nsTArray<uint8_t>& aMessage,
+ const nsAString& aDestinationURL)
+{
+ MOZ_ASSERT(NS_IsMainThread());
+ nsRefPtr<dom::MediaKeySession> session(mKeys->GetSession(aSessionId));
+ if (session) {
+ session->DispatchKeyMessage(aMessage, aDestinationURL);
+ }
+}
+
+void
+CDMProxy::OnExpirationChange(const nsAString& aSessionId,
+ GMPTimestamp aExpiryTime)
+{
+ MOZ_ASSERT(NS_IsMainThread());
+ NS_WARNING("CDMProxy::OnExpirationChange() not implemented");
+}
+
+void
+CDMProxy::OnSessionClosed(const nsAString& aSessionId)
+{
+ MOZ_ASSERT(NS_IsMainThread());
+ NS_WARNING("CDMProxy::OnSessionClosed() not implemented");
+}
+
+static void
+LogToConsole(const nsAString& aMsg)
+{
+ nsCOMPtr<nsIConsoleService> console(
+ do_GetService("@mozilla.org/consoleservice;1"));
+ if (!console) {
+ NS_WARNING("Failed to log message to console.");
+ return;
+ }
+ nsAutoString msg(aMsg);
+ console->LogStringMessage(msg.get());
+}
+
+void
+CDMProxy::OnSessionError(const nsAString& aSessionId,
+ nsresult aException,
+ uint32_t aSystemCode,
+ const nsAString& aMsg)
+{
+ MOZ_ASSERT(NS_IsMainThread());
+ nsRefPtr<dom::MediaKeySession> session(mKeys->GetSession(aSessionId));
+ if (session) {
+ session->DispatchKeyError(aSystemCode);
+ }
+ LogToConsole(aMsg);
+}
+
+void
+CDMProxy::OnRejectPromise(uint32_t aPromiseId,
+ nsresult aDOMException,
+ const nsAString& aMsg)
+{
+ MOZ_ASSERT(NS_IsMainThread());
+ RejectPromise(aPromiseId, aDOMException);
+ LogToConsole(aMsg);
+}
+
+const nsString&
+CDMProxy::KeySystem() const
+{
+ return mKeySystem;
+}
+
+CDMCaps&
+CDMProxy::Capabilites() {
+ return mCapabilites;
+}
+
+void
+CDMProxy::Decrypt(mp4_demuxer::MP4Sample* aSample,
+ DecryptionClient* aClient)
+{
+ nsAutoPtr<DecryptJob> job(new DecryptJob(aSample, aClient));
+ nsRefPtr<nsIRunnable> task(
+ NS_NewRunnableMethodWithArg<nsAutoPtr<DecryptJob>>(this, &CDMProxy::gmp_Decrypt, job));
+ mGMPThread->Dispatch(task, NS_DISPATCH_NORMAL);
+}
+
+void
+CDMProxy::gmp_Decrypt(nsAutoPtr<DecryptJob> aJob)
+{
+ MOZ_ASSERT(IsOnGMPThread());
+ MOZ_ASSERT(aJob->mClient);
+ MOZ_ASSERT(aJob->mSample);
+
+ if (!mCDM) {
+ aJob->mClient->Decrypted(NS_ERROR_FAILURE, nullptr);
+ return;
+ }
+
+ aJob->mId = ++mDecryptionJobCount;
+ nsTArray<uint8_t> data;
+ data.AppendElements(aJob->mSample->data, aJob->mSample->size);
+ mCDM->Decrypt(aJob->mId, aJob->mSample->crypto, data);
+ mDecryptionJobs.AppendElement(aJob.forget());
+}
+
+void
+CDMProxy::gmp_Decrypted(uint32_t aId,
+ GMPErr aResult,
+ const nsTArray<uint8_t>& aDecryptedData)
+{
+ MOZ_ASSERT(IsOnGMPThread());
+ for (size_t i = 0; i < mDecryptionJobs.Length(); i++) {
+ DecryptJob* job = mDecryptionJobs[i];
+ if (job->mId == aId) {
+ if (aDecryptedData.Length() != job->mSample->size) {
+ NS_WARNING("CDM returned incorrect number of decrypted bytes");
+ }
+ PodCopy(job->mSample->data,
+ aDecryptedData.Elements(),
+ std::min<size_t>(aDecryptedData.Length(), job->mSample->size));
+ nsresult rv = GMP_SUCCEEDED(aResult) ? NS_OK : NS_ERROR_FAILURE;
+ job->mClient->Decrypted(rv, job->mSample.forget());
+ mDecryptionJobs.RemoveElementAt(i);
+ return;
+ } else {
+ NS_WARNING("GMPDecryptorChild returned incorrect job ID");
+ }
+ }
+}
+
+void
+CDMProxy::gmp_Terminated()
+{
+ MOZ_ASSERT(IsOnGMPThread());
+ EME_LOG("CDM terminated");
+ if (mCDM) {
+ mCDM->Close();
+ mCDM = nullptr;
+ }
+}
+
} // namespace mozilla
--- a/content/media/eme/CDMProxy.h
+++ b/content/media/eme/CDMProxy.h
@@ -4,32 +4,40 @@
* 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 CDMProxy_h_
#define CDMProxy_h_
#include "nsString.h"
#include "nsAutoPtr.h"
-#include "nsProxyRelease.h"
#include "mozilla/dom/MediaKeys.h"
#include "mozilla/dom/TypedArray.h"
-
-class nsIThread;
+#include "mozilla/Monitor.h"
+#include "nsIThread.h"
+#include "GMPDecryptorProxy.h"
+#include "mozilla/CDMCaps.h"
+#include "mp4_demuxer/DecoderData.h"
namespace mozilla {
+class CDMCallbackProxy;
+
namespace dom {
class MediaKeySession;
}
-// A placeholder proxy to the CDM.
-// TODO: The functions here need to do IPC to talk to the CDM via the
-// Gecko Media Plugin API, which we'll need to extend for H.264 and EME
-// content.
+class DecryptionClient {
+public:
+ virtual ~DecryptionClient() {}
+ virtual void Decrypted(nsresult aResult,
+ mp4_demuxer::MP4Sample* aSample) = 0;
+};
+
+// Proxies calls GMP/CDM, and proxies calls back.
// Note: Promises are passed in via a PromiseId, so that the ID can be
// passed via IPC to the CDM, which can then signal when to reject or
// resolve the promise using its PromiseId.
class CDMProxy {
typedef dom::PromiseId PromiseId;
typedef dom::SessionType SessionType;
typedef dom::Uint8Array Uint8Array;
public:
@@ -90,18 +98,134 @@ public:
// Calls MediaKeys->ResolvePromise(aPromiseId) after the CDM has
// processed the request.
void RemoveSession(const nsAString& aSessionId,
PromiseId aPromiseId);
// Main thread only.
void Shutdown();
+ // Threadsafe.
+ const nsAString& GetOrigin() const;
+
+ // Main thread only.
+ void OnResolveNewSessionPromise(uint32_t aPromiseId,
+ const nsAString& aSessionId);
+
+ // Main thread only.
+ void OnSessionMessage(const nsAString& aSessionId,
+ nsTArray<uint8_t>& aMessage,
+ const nsAString& aDestinationURL);
+
+ // Main thread only.
+ void OnExpirationChange(const nsAString& aSessionId,
+ GMPTimestamp aExpiryTime);
+
+ // Main thread only.
+ void OnSessionClosed(const nsAString& aSessionId);
+
+ // Main thread only.
+ void OnSessionError(const nsAString& aSessionId,
+ nsresult aException,
+ uint32_t aSystemCode,
+ const nsAString& aMsg);
+
+ // Main thread only.
+ void OnRejectPromise(uint32_t aPromiseId,
+ nsresult aDOMException,
+ const nsAString& aMsg);
+
+ // Threadsafe.
+ void Decrypt(mp4_demuxer::MP4Sample* aSample,
+ DecryptionClient* aSink);
+
+ // Reject promise with DOMException corresponding to aExceptionCode.
+ // Can be called from any thread.
+ void RejectPromise(PromiseId aId, nsresult aExceptionCode);
+
+ // Resolves promise with "undefined".
+ // Can be called from any thread.
+ void ResolvePromise(PromiseId aId);
+
+ // Threadsafe.
+ const nsString& KeySystem() const;
+
+ // GMP thread only.
+ void gmp_Decrypted(uint32_t aId,
+ GMPErr aResult,
+ const nsTArray<uint8_t>& aDecryptedData);
+
+ // GMP thread only.
+ void gmp_Terminated();
+
+ CDMCaps& Capabilites();
+
+#ifdef DEBUG
+ bool IsOnGMPThread();
+#endif
+
private:
+ // GMP thread only.
+ void gmp_Init(uint32_t aPromiseId);
+
+ // Main thread only.
+ void OnCDMCreated(uint32_t aPromiseId);
+
+ struct CreateSessionData {
+ dom::SessionType mSessionType;
+ PromiseId mPromiseId;
+ nsAutoCString mInitDataType;
+ nsTArray<uint8_t> mInitData;
+ };
+ // GMP thread only.
+ void gmp_CreateSession(nsAutoPtr<CreateSessionData> aData);
+
+ struct SessionOpData {
+ PromiseId mPromiseId;
+ nsAutoCString mSessionId;
+ };
+ // GMP thread only.
+ void gmp_LoadSession(nsAutoPtr<SessionOpData> aData);
+
+ struct SetServerCertificateData {
+ PromiseId mPromiseId;
+ nsTArray<uint8_t> mCert;
+ };
+ // GMP thread only.
+ void gmp_SetServerCertificate(nsAutoPtr<SetServerCertificateData> aData);
+
+ struct UpdateSessionData {
+ PromiseId mPromiseId;
+ nsAutoCString mSessionId;
+ nsTArray<uint8_t> mResponse;
+ };
+ // GMP thread only.
+ void gmp_UpdateSession(nsAutoPtr<UpdateSessionData> aData);
+
+ // GMP thread only.
+ void gmp_CloseSession(nsAutoPtr<SessionOpData> aData);
+
+ // GMP thread only.
+ void gmp_RemoveSession(nsAutoPtr<SessionOpData> aData);
+
+ struct DecryptJob {
+ DecryptJob(mp4_demuxer::MP4Sample* aSample,
+ DecryptionClient* aClient)
+ : mId(0)
+ , mSample(aSample)
+ , mClient(aClient)
+ {}
+ uint32_t mId;
+ nsAutoPtr<mp4_demuxer::MP4Sample> mSample;
+ nsAutoPtr<DecryptionClient> mClient;
+ };
+ // GMP thread only.
+ void gmp_Decrypt(nsAutoPtr<DecryptJob> aJob);
+
class RejectPromiseTask : public nsRunnable {
public:
RejectPromiseTask(CDMProxy* aProxy,
PromiseId aId,
nsresult aCode)
: mProxy(aProxy)
, mId(aId)
, mCode(aCode)
@@ -112,23 +236,16 @@ private:
return NS_OK;
}
private:
nsRefPtr<CDMProxy> mProxy;
PromiseId mId;
nsresult mCode;
};
- // Reject promise with DOMException corresponding to aExceptionCode.
- // Can be called from any thread.
- void RejectPromise(PromiseId aId, nsresult aExceptionCode);
- // Resolves promise with "undefined".
- // Can be called from any thread.
- void ResolvePromise(PromiseId aId);
-
~CDMProxy();
// Helper to enforce that a raw pointer is only accessed on the main thread.
template<class Type>
class MainThreadOnlyRawPtr {
public:
MainThreadOnlyRawPtr(Type* aPtr)
: mPtr(aPtr)
@@ -159,13 +276,31 @@ private:
// destructor. only use on main thread, and always nullcheck before using!
MainThreadOnlyRawPtr<dom::MediaKeys> mKeys;
const nsAutoString mKeySystem;
// Gecko Media Plugin thread. All interactions with the out-of-process
// EME plugin must come from this thread.
nsRefPtr<nsIThread> mGMPThread;
+
+ nsAutoString mOrigin;
+
+ GMPDecryptorProxy* mCDM;
+ CDMCaps mCapabilites;
+ nsAutoPtr<CDMCallbackProxy> mCallback;
+
+ // Decryption jobs sent to CDM, awaiting result.
+ // GMP thread only.
+ nsTArray<nsAutoPtr<DecryptJob>> mDecryptionJobs;
+
+ // Number of buffers we've decrypted. Used to uniquely identify
+ // decryption jobs sent to CDM. Note we can't just use the length of
+ // mDecryptionJobs as that shrinks as jobs are completed and removed
+ // from it.
+ // GMP thread only.
+ uint32_t mDecryptionJobCount;
};
+
} // namespace mozilla
#endif // CDMProxy_h_
--- a/content/media/eme/EMELog.h
+++ b/content/media/eme/EMELog.h
@@ -1,35 +1,48 @@
/* -*- 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 EME_LOG_H_
+#define EME_LOG_H_
+
#include "prlog.h"
namespace mozilla {
#ifdef PR_LOGGING
-#ifndef EME_LOG
-PRLogModuleInfo* GetEMELog();
-#define EME_LOG(...) PR_LOG(GetEMELog(), PR_LOG_DEBUG, (__VA_ARGS__))
-#endif
+ #ifndef EME_LOG
+ PRLogModuleInfo* GetEMELog();
+ #define EME_LOG(...) PR_LOG(GetEMELog(), PR_LOG_DEBUG, (__VA_ARGS__))
+ #endif
-#ifndef EME_VERBOSE_LOG
-PRLogModuleInfo* GetEMEVerboseLog();
-#define EME_VERBOSE_LOG(...) PR_LOG(GetEMEVerboseLog(), PR_LOG_DEBUG, (__VA_ARGS__))
+ #ifndef EME_VERBOSE_LOG
+ PRLogModuleInfo* GetEMEVerboseLog();
+ #define EME_VERBOSE_LOG(...) PR_LOG(GetEMEVerboseLog(), PR_LOG_DEBUG, (__VA_ARGS__))
+ #else
+ #ifndef EME_LOG
+ #define EME_LOG(...)
+ #endif
+
+ #ifndef EME_VERBOSE_LOG
+ #define EME_VERBOSE_LOG(...)
+ #endif
+ #endif
#else
-#ifndef EME_LOG
-#define EME_LOG(...)
-#endif
+ #ifndef EME_LOG
+ #define EME_LOG(...)
+ #endif
-#ifndef EME_VERBOSE_LOG
-#define EME_VERBOSE_LOG(...)
-#endif
-
-#endif
+ #ifndef EME_VERBOSE_LOG
+ #define EME_VERBOSE_LOG(...)
+ #endif
#endif // PR_LOGGING
+
} // namespace mozilla
+
+#endif // EME_LOG_H_
--- a/content/media/eme/MediaKeyError.cpp
+++ b/content/media/eme/MediaKeyError.cpp
@@ -11,16 +11,17 @@
namespace mozilla {
namespace dom {
MediaKeyError::MediaKeyError(EventTarget* aOwner, uint32_t aSystemCode)
: Event(aOwner, nullptr, nullptr)
, mSystemCode(aSystemCode)
{
SetIsDOMBinding();
+ InitEvent(NS_LITERAL_STRING("error"), false, false);
}
MediaKeyError::~MediaKeyError()
{
}
uint32_t
MediaKeyError::SystemCode() const
--- a/content/media/eme/MediaKeySession.cpp
+++ b/content/media/eme/MediaKeySession.cpp
@@ -62,17 +62,23 @@ void
MediaKeySession::GetKeySystem(nsString& aKeySystem) const
{
aKeySystem = mKeySystem;
}
void
MediaKeySession::GetSessionId(nsString& aSessionId) const
{
- aSessionId = mSessionId;
+ aSessionId = GetSessionId();
+}
+
+const nsString&
+MediaKeySession::GetSessionId() const
+{
+ return mSessionId;
}
JSObject*
MediaKeySession::WrapObject(JSContext* aCx)
{
return MediaKeySessionBinding::Wrap(aCx, this);
}
@@ -161,17 +167,17 @@ MediaKeySession::Remove(ErrorResult& aRv
return promise.forget();
}
mKeys->GetCDMProxy()->RemoveSession(mSessionId, mKeys->StorePromise(promise));
return promise.forget();
}
void
MediaKeySession::DispatchKeyMessage(const nsTArray<uint8_t>& aMessage,
- const nsString& aURL)
+ const nsAString& aURL)
{
nsRefPtr<MediaKeyMessageEvent> event(
MediaKeyMessageEvent::Constructor(this, aURL, aMessage));
nsRefPtr<AsyncEventDispatcher> asyncDispatcher =
new AsyncEventDispatcher(this, event);
asyncDispatcher->PostDOMEvent();
}
--- a/content/media/eme/MediaKeySession.h
+++ b/content/media/eme/MediaKeySession.h
@@ -48,32 +48,34 @@ public:
// Mark this as resultNotAddRefed to return raw pointers
MediaKeyError* GetError() const;
void GetKeySystem(nsString& aRetval) const;
void GetSessionId(nsString& aRetval) const;
+ const nsString& GetSessionId() const;
+
// Number of ms since epoch at which expiration occurs, or NaN if unknown.
// TODO: The type of this attribute is still under contention.
// https://www.w3.org/Bugs/Public/show_bug.cgi?id=25902
double Expiration() const;
Promise* Closed() const;
already_AddRefed<Promise> Update(const Uint8Array& response,
ErrorResult& aRv);
already_AddRefed<Promise> Close(ErrorResult& aRv);
already_AddRefed<Promise> Remove(ErrorResult& aRv);
void DispatchKeyMessage(const nsTArray<uint8_t>& aMessage,
- const nsString& aURL);
+ const nsAString& aURL);
void DispatchKeyError(uint32_t system_code);
void OnClosed();
bool IsClosed() const;
private:
--- a/content/media/eme/MediaKeys.cpp
+++ b/content/media/eme/MediaKeys.cpp
@@ -7,18 +7,23 @@
#include "mozilla/dom/HTMLMediaElement.h"
#include "mozilla/dom/MediaKeys.h"
#include "mozilla/dom/MediaKeysBinding.h"
#include "mozilla/dom/MediaKeyMessageEvent.h"
#include "mozilla/dom/MediaKeyError.h"
#include "mozilla/dom/MediaKeySession.h"
#include "mozilla/dom/DOMException.h"
#include "mozilla/CDMProxy.h"
+#include "mozilla/EMELog.h"
#include "nsContentUtils.h"
-#include "EMELog.h"
+#include "nsIScriptObjectPrincipal.h"
+#include "mozilla/Preferences.h"
+#ifdef XP_WIN
+#include "mozilla/WindowsVersion.h"
+#endif
namespace mozilla {
namespace dom {
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(MediaKeys,
mParent,
mKeySessions,
@@ -27,18 +32,19 @@ NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(Me
NS_IMPL_CYCLE_COLLECTING_ADDREF(MediaKeys)
NS_IMPL_CYCLE_COLLECTING_RELEASE(MediaKeys)
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(MediaKeys)
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
NS_INTERFACE_MAP_ENTRY(nsISupports)
NS_INTERFACE_MAP_END
MediaKeys::MediaKeys(nsPIDOMWindow* aParent, const nsAString& aKeySystem)
- : mParent(aParent),
- mKeySystem(aKeySystem)
+ : mParent(aParent)
+ , mKeySystem(aKeySystem)
+ , mCreatePromiseId(0)
{
SetIsDOMBinding();
}
MediaKeys::~MediaKeys()
{
if (mProxy) {
mProxy->Shutdown();
@@ -71,28 +77,40 @@ MediaKeys::SetServerCertificate(const Ui
nsRefPtr<Promise> promise(MakePromise(aRv));
if (aRv.Failed()) {
return nullptr;
}
mProxy->SetServerCertificate(StorePromise(promise), aCert);
return promise.forget();
}
+static bool
+IsSupportedKeySystem(const nsAString& aKeySystem)
+{
+ return aKeySystem.EqualsASCII("org.w3.clearkey") ||
+#ifdef XP_WIN
+ (aKeySystem.EqualsASCII("com.adobe.access") &&
+ IsVistaOrLater() &&
+ Preferences::GetBool("media.eme.adobe-access.enabled", false)) ||
+#endif
+ false;
+}
+
/* static */
IsTypeSupportedResult
MediaKeys::IsTypeSupported(const GlobalObject& aGlobal,
const nsAString& aKeySystem,
const Optional<nsAString>& aInitDataType,
const Optional<nsAString>& aContentType,
const Optional<nsAString>& aCapability)
{
- // TODO: Query list of known CDMs and their supported content types.
// TODO: Should really get spec changed to this is async, so we can wait
// for user to consent to running plugin.
- return IsTypeSupportedResult::Maybe;
+ return IsSupportedKeySystem(aKeySystem) ? IsTypeSupportedResult::Maybe
+ : IsTypeSupportedResult::_empty;
}
already_AddRefed<Promise>
MediaKeys::MakePromise(ErrorResult& aRv)
{
nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(GetParentObject());
if (!global) {
NS_WARNING("Passed non-global to MediaKeys ctor!");
@@ -110,16 +128,17 @@ MediaKeys::StorePromise(Promise* aPromis
uint32_t id = sEMEPromiseCount++;
mPromises.Put(id, aPromise);
return id;
}
already_AddRefed<Promise>
MediaKeys::RetrievePromise(PromiseId aId)
{
+ MOZ_ASSERT(mPromises.Contains(aId));
nsRefPtr<Promise> promise;
mPromises.Remove(aId, getter_AddRefs(promise));
return promise.forget();
}
void
MediaKeys::RejectPromise(PromiseId aId, nsresult aExceptionCode)
{
@@ -133,30 +152,49 @@ MediaKeys::RejectPromise(PromiseId aId,
// so we might have a pending session waiting to be resolved into
// the promise on success. We've been directed to reject to promise,
// so we can throw away the corresponding session object.
mPendingSessions.Remove(aId);
}
MOZ_ASSERT(NS_FAILED(aExceptionCode));
promise->MaybeReject(aExceptionCode);
+
+ if (mCreatePromiseId == aId) {
+ // Note: This will probably destroy the MediaKeys object!
+ Release();
+ }
}
void
MediaKeys::ResolvePromise(PromiseId aId)
{
nsRefPtr<Promise> promise(RetrievePromise(aId));
if (!promise) {
NS_WARNING("MediaKeys tried to resolve a non-existent promise");
return;
}
- // We should not resolve CreateSession or LoadSession calls via this path,
- // OnSessionActivated() should be called instead.
- MOZ_ASSERT(!mPendingSessions.Contains(aId));
- promise->MaybeResolve(JS::UndefinedHandleValue);
+ if (mPendingSessions.Contains(aId)) {
+ // We should only resolve LoadSession calls via this path,
+ // not CreateSession() promises.
+ nsRefPtr<MediaKeySession> session;
+ if (!mPendingSessions.Get(aId, getter_AddRefs(session)) ||
+ !session ||
+ session->GetSessionId().IsEmpty()) {
+ NS_WARNING("Received activation for non-existent session!");
+ promise->MaybeReject(NS_ERROR_DOM_INVALID_ACCESS_ERR);
+ mPendingSessions.Remove(aId);
+ return;
+ }
+ mPendingSessions.Remove(aId);
+ mKeySessions.Put(session->GetSessionId(), session);
+ promise->MaybeResolve(session);
+ } else {
+ promise->MaybeResolve(JS::UndefinedHandleValue);
+ }
}
/* static */
already_AddRefed<Promise>
MediaKeys::Create(const GlobalObject& aGlobal,
const nsAString& aKeySystem,
ErrorResult& aRv)
{
@@ -169,37 +207,52 @@ MediaKeys::Create(const GlobalObject& aG
}
nsRefPtr<MediaKeys> keys = new MediaKeys(window, aKeySystem);
nsRefPtr<Promise> promise(keys->MakePromise(aRv));
if (aRv.Failed()) {
return nullptr;
}
- if (!aKeySystem.EqualsASCII("org.w3.clearkey")) {
+ if (!IsSupportedKeySystem(aKeySystem)) {
aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
return nullptr;
}
keys->mProxy = new CDMProxy(keys, aKeySystem);
- keys->mProxy->Init(keys->StorePromise(promise));
+
+ // The CDMProxy's initialization is asynchronous. The MediaKeys is
+ // refcounted, and its instance is returned to JS by promise once
+ // it's been initialized. No external refs exist to the MediaKeys while
+ // we're waiting for the promise to be resolved, so we must hold a
+ // reference to the new MediaKeys object until it's been created,
+ // or its creation has failed. Store the id of the promise returned
+ // here, and hold a self-reference until that promise is resolved or
+ // rejected.
+ MOZ_ASSERT(!keys->mCreatePromiseId, "Should only be created once!");
+ keys->mCreatePromiseId = keys->StorePromise(promise);
+ keys->AddRef();
+ keys->mProxy->Init(keys->mCreatePromiseId);
return promise.forget();
}
void
MediaKeys::OnCDMCreated(PromiseId aId)
{
nsRefPtr<Promise> promise(RetrievePromise(aId));
if (!promise) {
NS_WARNING("MediaKeys tried to resolve a non-existent promise");
return;
}
nsRefPtr<MediaKeys> keys(this);
promise->MaybeResolve(keys);
+ if (mCreatePromiseId == aId) {
+ Release();
+ }
}
already_AddRefed<Promise>
MediaKeys::LoadSession(const nsAString& aSessionId, ErrorResult& aRv)
{
nsRefPtr<Promise> promise(MakePromise(aRv));
if (aRv.Failed()) {
return nullptr;
@@ -219,19 +272,20 @@ MediaKeys::LoadSession(const nsAString&
// Create session.
nsRefPtr<MediaKeySession> session(
new MediaKeySession(GetParentObject(), this, mKeySystem, SessionType::Persistent, aRv));
if (aRv.Failed()) {
return nullptr;
}
- // Proxy owns session object until resolving promise.
- mProxy->LoadSession(StorePromise(promise),
- aSessionId);
+ session->Init(aSessionId);
+ auto pid = StorePromise(promise);
+ mPendingSessions.Put(pid, session);
+ mProxy->LoadSession(pid, aSessionId);
return promise.forget();
}
already_AddRefed<Promise>
MediaKeys::CreateSession(const nsAString& initDataType,
const Uint8Array& aInitData,
SessionType aSessionType,
@@ -257,36 +311,37 @@ MediaKeys::CreateSession(const nsAString
pid,
initDataType,
aInitData);
return promise.forget();
}
void
-MediaKeys::OnSessionActivated(PromiseId aId, const nsAString& aSessionId)
+MediaKeys::OnSessionCreated(PromiseId aId, const nsAString& aSessionId)
{
nsRefPtr<Promise> promise(RetrievePromise(aId));
if (!promise) {
NS_WARNING("MediaKeys tried to resolve a non-existent promise");
return;
}
MOZ_ASSERT(mPendingSessions.Contains(aId));
nsRefPtr<MediaKeySession> session;
- if (!mPendingSessions.Get(aId, getter_AddRefs(session)) || !session) {
+ bool gotSession = mPendingSessions.Get(aId, getter_AddRefs(session));
+ // Session has completed creation/loading, remove it from mPendingSessions,
+ // and resolve the promise with it. We store it in mKeySessions, so we can
+ // find it again if we need to send messages to it etc.
+ mPendingSessions.Remove(aId);
+ if (!gotSession || !session) {
NS_WARNING("Received activation for non-existent session!");
promise->MaybeReject(NS_ERROR_DOM_INVALID_ACCESS_ERR);
return;
}
- // Session has completed creation/loading, remove it from mPendingSessions,
- // and resolve the promise with it. We store it in mKeySessions, so we can
- // find it again if we need to send messages to it etc.
- mPendingSessions.Remove(aId);
session->Init(aSessionId);
mKeySessions.Put(aSessionId, session);
promise->MaybeResolve(session);
}
void
MediaKeys::OnSessionClosed(MediaKeySession* aSession)
{
@@ -298,10 +353,32 @@ MediaKeys::OnSessionClosed(MediaKeySessi
already_AddRefed<MediaKeySession>
MediaKeys::GetSession(const nsAString& aSessionId)
{
nsRefPtr<MediaKeySession> session;
mKeySessions.Get(aSessionId, getter_AddRefs(session));
return session.forget();
}
+nsresult
+MediaKeys::GetOrigin(nsString& aOutOrigin)
+{
+ MOZ_ASSERT(NS_IsMainThread());
+ // TODO: Bug 1035637, return a combination of origin and URL bar origin.
+
+ nsIPrincipal* principal = nullptr;
+ nsCOMPtr<nsPIDOMWindow> pWindow = do_QueryInterface(GetParentObject());
+ nsCOMPtr<nsIScriptObjectPrincipal> scriptPrincipal =
+ do_QueryInterface(pWindow);
+ if (scriptPrincipal) {
+ principal = scriptPrincipal->GetPrincipal();
+ }
+ NS_ENSURE_TRUE(principal, NS_ERROR_FAILURE);
+
+ nsresult res = nsContentUtils::GetUTFOrigin(principal, aOutOrigin);
+
+ EME_LOG("EME Origin = '%s'", NS_ConvertUTF16toUTF8(aOutOrigin).get());
+
+ return res;
+}
+
} // namespace dom
} // namespace mozilla
--- a/content/media/eme/MediaKeys.h
+++ b/content/media/eme/MediaKeys.h
@@ -78,17 +78,17 @@ public:
const Optional<nsAString>& aContentType,
const Optional<nsAString>& aCapability);
already_AddRefed<MediaKeySession> GetSession(const nsAString& aSessionId);
// Called once a Create() operation succeeds.
void OnCDMCreated(PromiseId aId);
// Called once a CreateSession or LoadSession succeeds.
- void OnSessionActivated(PromiseId aId, const nsAString& aSessionId);
+ void OnSessionCreated(PromiseId aId, const nsAString& aSessionId);
// Called once a session has closed.
void OnSessionClosed(MediaKeySession* aSession);
CDMProxy* GetCDMProxy() { return mProxy; }
// Makes a new promise, or nullptr on failure.
already_AddRefed<Promise> MakePromise(ErrorResult& aRv);
// Stores promise in mPromises, returning an ID that can be used to retrieve
@@ -96,28 +96,31 @@ public:
// promises to be resolved.
PromiseId StorePromise(Promise* aPromise);
// Reject promise with DOMException corresponding to aExceptionCode.
void RejectPromise(PromiseId aId, nsresult aExceptionCode);
// Resolves promise with "undefined".
void ResolvePromise(PromiseId aId);
+ nsresult GetOrigin(nsString& aOutOrigin);
+
private:
// Removes promise from mPromises, and returns it.
already_AddRefed<Promise> RetrievePromise(PromiseId aId);
// Owning ref to proxy. The proxy has a weak reference back to the MediaKeys,
// and the MediaKeys destructor clears the proxy's reference to the MediaKeys.
nsRefPtr<CDMProxy> mProxy;
nsCOMPtr<nsPIDOMWindow> mParent;
nsString mKeySystem;
KeySessionHashMap mKeySessions;
PromiseHashMap mPromises;
PendingKeySessionsHashMap mPendingSessions;
+ PromiseId mCreatePromiseId;
};
} // namespace dom
} // namespace mozilla
#endif // mozilla_dom_mediakeys_h__
--- a/content/media/eme/moz.build
+++ b/content/media/eme/moz.build
@@ -8,20 +8,25 @@ EXPORTS.mozilla.dom += [
'MediaKeyError.h',
'MediaKeyMessageEvent.h',
'MediaKeyNeededEvent.h',
'MediaKeys.h',
'MediaKeySession.h',
]
EXPORTS.mozilla += [
+ 'CDMCallbackProxy.h',
+ 'CDMCaps.h',
'CDMProxy.h',
+ 'EMELog.h'
]
UNIFIED_SOURCES += [
+ 'CDMCallbackProxy.cpp',
+ 'CDMCaps.cpp',
'CDMProxy.cpp',
'EMELog.cpp',
'MediaKeyError.cpp',
'MediaKeyMessageEvent.cpp',
'MediaKeyNeededEvent.cpp',
'MediaKeys.cpp',
'MediaKeySession.cpp',
]
--- a/content/media/fmp4/MP4Decoder.cpp
+++ b/content/media/fmp4/MP4Decoder.cpp
@@ -3,31 +3,50 @@
/* 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 "MP4Decoder.h"
#include "MP4Reader.h"
#include "MediaDecoderStateMachine.h"
#include "mozilla/Preferences.h"
+#include "mozilla/CDMProxy.h"
+#include "prlog.h"
#ifdef XP_WIN
#include "mozilla/WindowsVersion.h"
#endif
#ifdef MOZ_FFMPEG
#include "FFmpegRuntimeLinker.h"
#endif
namespace mozilla {
MediaDecoderStateMachine* MP4Decoder::CreateStateMachine()
{
return new MediaDecoderStateMachine(this, new MP4Reader(this));
}
+nsresult
+MP4Decoder::SetCDMProxy(CDMProxy* aProxy)
+{
+ nsresult rv = MediaDecoder::SetCDMProxy(aProxy);
+ NS_ENSURE_SUCCESS(rv, rv);
+ {
+ // The MP4Reader can't decrypt EME content until it has a CDMProxy,
+ // and the CDMProxy knows the capabilities of the CDM. The MP4Reader
+ // remains in "waiting for resources" state until then.
+ CDMCaps::AutoLock caps(aProxy->Capabilites());
+ nsRefPtr<nsIRunnable> task(
+ NS_NewRunnableMethod(this, &MediaDecoder::NotifyWaitingForResourcesStatusChanged));
+ caps.CallOnMainThreadWhenCapsAvailable(task);
+ }
+ return NS_OK;
+}
+
bool
MP4Decoder::GetSupportedCodecs(const nsACString& aType,
char const *const ** aCodecList)
{
if (!IsEnabled()) {
return false;
}
--- a/content/media/fmp4/MP4Decoder.h
+++ b/content/media/fmp4/MP4Decoder.h
@@ -19,16 +19,18 @@ public:
if (!IsEnabled()) {
return nullptr;
}
return new MP4Decoder();
}
virtual MediaDecoderStateMachine* CreateStateMachine();
+ virtual nsresult SetCDMProxy(CDMProxy* aProxy) MOZ_OVERRIDE;
+
// Returns true if aType is a MIME type that we can render with the
// a MP4 platform decoder backend. If aCodecList is non null,
// it is filled with a (static const) null-terminated list of strings
// denoting the codecs we'll playback.
static bool GetSupportedCodecs(const nsACString& aType,
char const *const ** aCodecList);
// Returns true if the MP4 backend is preffed on, and we're running on a
--- a/content/media/fmp4/MP4Reader.cpp
+++ b/content/media/fmp4/MP4Reader.cpp
@@ -100,16 +100,18 @@ private:
};
MP4Reader::MP4Reader(AbstractMediaDecoder* aDecoder)
: MediaDecoderReader(aDecoder)
, mAudio("MP4 audio decoder data", Preferences::GetUint("media.mp4-audio-decode-ahead", 2))
, mVideo("MP4 video decoder data", Preferences::GetUint("media.mp4-video-decode-ahead", 2))
, mLastReportedNumDecodedFrames(0)
, mLayersBackendType(layers::LayersBackend::LAYERS_NONE)
+ , mDemuxerInitialized(false)
+ , mIsEncrypted(false)
{
MOZ_ASSERT(NS_IsMainThread(), "Must be on main thread.");
MOZ_COUNT_CTOR(MP4Reader);
}
MP4Reader::~MP4Reader()
{
MOZ_ASSERT(NS_IsMainThread(), "Must be on main thread.");
@@ -163,16 +165,18 @@ MP4Reader::InitLayersBackendType()
nsRefPtr<LayerManager> layerManager =
nsContentUtils::LayerManagerForDocument(element->OwnerDoc());
NS_ENSURE_TRUE_VOID(layerManager);
mLayersBackendType = layerManager->GetCompositorBackendType();
}
+static bool sIsEMEEnabled = false;
+
nsresult
MP4Reader::Init(MediaDecoderReader* aCloneDonor)
{
MOZ_ASSERT(NS_IsMainThread(), "Must be on main thread.");
PlatformDecoderModule::Init();
mDemuxer = new MP4Demuxer(new MP4Stream(mDecoder->GetResource()));
InitLayersBackendType();
@@ -180,56 +184,171 @@ MP4Reader::Init(MediaDecoderReader* aClo
mAudio.mTaskQueue = new MediaTaskQueue(
SharedThreadPool::Get(NS_LITERAL_CSTRING("MP4 Audio Decode")));
NS_ENSURE_TRUE(mAudio.mTaskQueue, NS_ERROR_FAILURE);
mVideo.mTaskQueue = new MediaTaskQueue(
SharedThreadPool::Get(NS_LITERAL_CSTRING("MP4 Video Decode")));
NS_ENSURE_TRUE(mVideo.mTaskQueue, NS_ERROR_FAILURE);
+ static bool sSetupPrefCache = false;
+ if (!sSetupPrefCache) {
+ sSetupPrefCache = true;
+ Preferences::AddBoolVarCache(&sIsEMEEnabled, "media.eme.enabled", false);
+ }
+
return NS_OK;
}
+class DispatchKeyNeededEvent : public nsRunnable {
+public:
+ DispatchKeyNeededEvent(AbstractMediaDecoder* aDecoder,
+ nsTArray<uint8_t>& aInitData,
+ const nsString& aInitDataType)
+ : mDecoder(aDecoder)
+ , mInitData(aInitData)
+ , mInitDataType(aInitDataType)
+ {
+ }
+ NS_IMETHOD Run() {
+ // Note: Null check the owner, as the decoder could have been shutdown
+ // since this event was dispatched.
+ MediaDecoderOwner* owner = mDecoder->GetOwner();
+ if (owner) {
+ owner->DispatchNeedKey(mInitData, mInitDataType);
+ }
+ mDecoder = nullptr;
+ return NS_OK;
+ }
+private:
+ nsRefPtr<AbstractMediaDecoder> mDecoder;
+ nsTArray<uint8_t> mInitData;
+ nsString mInitDataType;
+};
+
+bool MP4Reader::IsWaitingMediaResources()
+{
+ nsRefPtr<CDMProxy> proxy;
+ {
+ ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
+ if (!mIsEncrypted) {
+ // Not encrypted, no need to wait for CDMProxy.
+ return false;
+ }
+ proxy = mDecoder->GetCDMProxy();
+ if (!proxy) {
+ // We're encrypted, we need a CDMProxy to decrypt file.
+ return true;
+ }
+ }
+ // We'll keep waiting if the CDM hasn't informed Gecko of its capabilities.
+ {
+ CDMCaps::AutoLock caps(proxy->Capabilites());
+ LOG("MP4Reader::IsWaitingMediaResources() capsKnown=%d", caps.AreCapsKnown());
+ return !caps.AreCapsKnown();
+ }
+}
+
+void
+MP4Reader::ExtractCryptoInitData(nsTArray<uint8_t>& aInitData)
+{
+ MOZ_ASSERT(mDemuxer->Crypto().valid);
+ const nsTArray<mp4_demuxer::PsshInfo>& psshs = mDemuxer->Crypto().pssh;
+ for (uint32_t i = 0; i < psshs.Length(); i++) {
+ aInitData.AppendElements(psshs[i].data);
+ }
+}
+
nsresult
MP4Reader::ReadMetadata(MediaInfo* aInfo,
MetadataTags** aTags)
{
- bool ok = mDemuxer->Init();
- NS_ENSURE_TRUE(ok, NS_ERROR_FAILURE);
+ if (!mDemuxerInitialized) {
+ bool ok = mDemuxer->Init();
+ NS_ENSURE_TRUE(ok, NS_ERROR_FAILURE);
+
+ mInfo.mAudio.mHasAudio = mAudio.mActive = mDemuxer->HasValidAudio();
+ const AudioDecoderConfig& audio = mDemuxer->AudioConfig();
+ // If we have audio, we *only* allow AAC to be decoded.
+ if (mInfo.mAudio.mHasAudio && strcmp(audio.mime_type, "audio/mp4a-latm")) {
+ return NS_ERROR_FAILURE;
+ }
+
+ mInfo.mVideo.mHasVideo = mVideo.mActive = mDemuxer->HasValidVideo();
+ const VideoDecoderConfig& video = mDemuxer->VideoConfig();
+ // If we have video, we *only* allow H.264 to be decoded.
+ if (mInfo.mVideo.mHasVideo && strcmp(video.mime_type, "video/avc")) {
+ return NS_ERROR_FAILURE;
+ }
+
+ {
+ ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
+ mIsEncrypted = mDemuxer->Crypto().valid;
+ }
- mInfo.mAudio.mHasAudio = mAudio.mActive = mDemuxer->HasValidAudio();
- const AudioDecoderConfig& audio = mDemuxer->AudioConfig();
- // If we have audio, we *only* allow AAC to be decoded.
- if (mInfo.mAudio.mHasAudio && strcmp(audio.mime_type, "audio/mp4a-latm")) {
- return NS_ERROR_FAILURE;
+ // Remember that we've initialized the demuxer, so that if we're decoding
+ // an encrypted stream and we need to wait for a CDM to be set, we don't
+ // need to reinit the demuxer.
+ mDemuxerInitialized = true;
+ }
+ if (mDemuxer->Crypto().valid) {
+ if (!sIsEMEEnabled) {
+ // TODO: Need to signal DRM/EME required somehow...
+ return NS_ERROR_FAILURE;
+ }
+
+ // We have encrypted audio or video. We'll need a CDM to decrypt and
+ // possibly decode this. Wait until we've received a CDM from the
+ // JavaScript player app.
+ nsRefPtr<CDMProxy> proxy;
+ nsTArray<uint8_t> initData;
+ ExtractCryptoInitData(initData);
+ if (initData.Length() == 0) {
+ return NS_ERROR_FAILURE;
+ }
+ if (!mInitDataEncountered.Contains(initData)) {
+ mInitDataEncountered.AppendElement(initData);
+ NS_DispatchToMainThread(new DispatchKeyNeededEvent(mDecoder, initData, NS_LITERAL_STRING("cenc")));
+ }
+ if (IsWaitingMediaResources()) {
+ return NS_OK;
+ }
+ MOZ_ASSERT(!IsWaitingMediaResources());
+
+ {
+ ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
+ proxy = mDecoder->GetCDMProxy();
+ }
+ MOZ_ASSERT(proxy);
+
+ mPlatform = PlatformDecoderModule::CreateCDMWrapper(proxy,
+ HasAudio(),
+ HasVideo(),
+ GetTaskQueue());
+ NS_ENSURE_TRUE(mPlatform, NS_ERROR_FAILURE);
+ } else {
+ mPlatform = PlatformDecoderModule::Create();
+ NS_ENSURE_TRUE(mPlatform, NS_ERROR_FAILURE);
}
- mInfo.mVideo.mHasVideo = mVideo.mActive = mDemuxer->HasValidVideo();
- const VideoDecoderConfig& video = mDemuxer->VideoConfig();
- // If we have video, we *only* allow H.264 to be decoded.
- if (mInfo.mVideo.mHasVideo && strcmp(video.mime_type, "video/avc")) {
- return NS_ERROR_FAILURE;
- }
-
- mPlatform = PlatformDecoderModule::Create();
- NS_ENSURE_TRUE(mPlatform, NS_ERROR_FAILURE);
-
if (HasAudio()) {
+ const AudioDecoderConfig& audio = mDemuxer->AudioConfig();
mInfo.mAudio.mRate = audio.samples_per_second;
mInfo.mAudio.mChannels = audio.channel_count;
mAudio.mCallback = new DecoderCallback(this, kAudio);
mAudio.mDecoder = mPlatform->CreateAACDecoder(audio,
mAudio.mTaskQueue,
mAudio.mCallback);
NS_ENSURE_TRUE(mAudio.mDecoder != nullptr, NS_ERROR_FAILURE);
nsresult rv = mAudio.mDecoder->Init();
NS_ENSURE_SUCCESS(rv, rv);
}
if (HasVideo()) {
+ const VideoDecoderConfig& video = mDemuxer->VideoConfig();
mInfo.mVideo.mDisplay =
nsIntSize(video.display_width, video.display_height);
mVideo.mCallback = new DecoderCallback(this, kVideo);
mVideo.mDecoder = mPlatform->CreateH264Decoder(video,
mLayersBackendType,
mDecoder->GetImageContainer(),
mVideo.mTaskQueue,
mVideo.mCallback);
@@ -287,19 +406,19 @@ MP4Reader::Decoder(TrackType aTrack)
MP4Sample*
MP4Reader::PopSample(TrackType aTrack)
{
switch (aTrack) {
case kAudio:
return mDemuxer->DemuxAudioSample();
case kVideo:
- if (mQueuedVideoSample)
+ if (mQueuedVideoSample) {
return mQueuedVideoSample.forget();
-
+ }
return mDemuxer->DemuxVideoSample();
default:
return nullptr;
}
}
// How async decoding works:
--- a/content/media/fmp4/MP4Reader.h
+++ b/content/media/fmp4/MP4Reader.h
@@ -7,16 +7,17 @@
#if !defined(MP4Reader_h_)
#define MP4Reader_h_
#include "MediaDecoderReader.h"
#include "nsAutoPtr.h"
#include "PlatformDecoderModule.h"
#include "mp4_demuxer/mp4_demuxer.h"
#include "MediaTaskQueue.h"
+#include "mozilla/CDMProxy.h"
#include <deque>
#include "mozilla/Monitor.h"
namespace mozilla {
namespace dom {
class TimeRanges;
@@ -50,18 +51,22 @@ public:
int64_t aEndTime,
int64_t aCurrentTime) MOZ_OVERRIDE;
virtual bool IsMediaSeekable() MOZ_OVERRIDE;
virtual nsresult GetBuffered(dom::TimeRanges* aBuffered,
int64_t aStartTime) MOZ_OVERRIDE;
+ virtual bool IsWaitingMediaResources() MOZ_OVERRIDE;
+
private:
+ void ExtractCryptoInitData(nsTArray<uint8_t>& aInitData);
+
// Destroys all decoder resources.
void Shutdown();
// Initializes mLayersBackendType if possible.
void InitLayersBackendType();
// Blocks until the demuxer produces an sample of specified type.
// Returns nullptr on error on EOS. Caller must delete sample.
@@ -136,29 +141,35 @@ private:
bool mActive;
bool mInputExhausted;
bool mError;
bool mIsFlushing;
bool mDrainComplete;
};
DecoderData mAudio;
DecoderData mVideo;
- // Queued frame extracted by the demuxer, but not yet sent to the platform
+ // Queued samples extracted by the demuxer, but not yet sent to the platform
// decoder.
nsAutoPtr<mp4_demuxer::MP4Sample> mQueuedVideoSample;
// The last number of decoded output frames that we've reported to
// MediaDecoder::NotifyDecoded(). We diff the number of output video
// frames every time that DecodeVideoData() is called, and report the
// delta there.
uint64_t mLastReportedNumDecodedFrames;
DecoderData& GetDecoderData(mp4_demuxer::TrackType aTrack);
- MP4SampleQueue& SampleQueue(mp4_demuxer::TrackType aTrack);
MediaDataDecoder* Decoder(mp4_demuxer::TrackType aTrack);
layers::LayersBackend mLayersBackendType;
+ nsTArray<nsTArray<uint8_t>> mInitDataEncountered;
+
+ // True if we've read the streams' metadata.
+ bool mDemuxerInitialized;
+
+ // Synchronized by decoder monitor.
+ bool mIsEncrypted;
};
} // namespace mozilla
#endif
--- a/content/media/fmp4/PlatformDecoderModule.cpp
+++ b/content/media/fmp4/PlatformDecoderModule.cpp
@@ -7,16 +7,20 @@
#include "PlatformDecoderModule.h"
#ifdef XP_WIN
#include "WMFDecoderModule.h"
#endif
#ifdef MOZ_FFMPEG
#include "FFmpegRuntimeLinker.h"
#endif
#include "mozilla/Preferences.h"
+#include "EMEDecoderModule.h"
+#include "mozilla/CDMProxy.h"
+#include "SharedThreadPool.h"
+#include "MediaTaskQueue.h"
namespace mozilla {
extern PlatformDecoderModule* CreateBlankDecoderModule();
bool PlatformDecoderModule::sUseBlankDecoder = false;
bool PlatformDecoderModule::sFFmpegDecoderEnabled = false;
@@ -30,22 +34,76 @@ PlatformDecoderModule::Init()
return;
}
alreadyInitialized = true;
Preferences::AddBoolVarCache(&sUseBlankDecoder,
"media.fragmented-mp4.use-blank-decoder");
Preferences::AddBoolVarCache(&sFFmpegDecoderEnabled,
"media.fragmented-mp4.ffmpeg.enabled", false);
-
#ifdef XP_WIN
WMFDecoderModule::Init();
#endif
}
+class CreateTaskQueueTask : public nsRunnable {
+public:
+ NS_IMETHOD Run() {
+ MOZ_ASSERT(NS_IsMainThread());
+ mTaskQueue = new MediaTaskQueue(GetMediaDecodeThreadPool());
+ return NS_OK;
+ }
+ nsRefPtr<MediaTaskQueue> mTaskQueue;
+};
+
+static already_AddRefed<MediaTaskQueue>
+CreateTaskQueue()
+{
+ // We must create the MediaTaskQueue/SharedThreadPool on the main thread.
+ nsRefPtr<CreateTaskQueueTask> t(new CreateTaskQueueTask());
+ nsresult rv = NS_DispatchToMainThread(t, NS_DISPATCH_SYNC);
+ NS_ENSURE_SUCCESS(rv, nullptr);
+ return t->mTaskQueue.forget();
+}
+
+/* static */
+PlatformDecoderModule*
+PlatformDecoderModule::CreateCDMWrapper(CDMProxy* aProxy,
+ bool aHasAudio,
+ bool aHasVideo,
+ MediaTaskQueue* aTaskQueue)
+{
+ bool cdmDecodesAudio;
+ bool cdmDecodesVideo;
+ {
+ CDMCaps::AutoLock caps(aProxy->Capabilites());
+ cdmDecodesAudio = caps.CanDecryptAndDecodeAudio();
+ cdmDecodesVideo = caps.CanDecryptAndDecodeVideo();
+ }
+
+ nsAutoPtr<PlatformDecoderModule> pdm;
+ if ((!cdmDecodesAudio && aHasAudio) || (!cdmDecodesVideo && aHasVideo)) {
+ // The CDM itself can't decode. We need to wrap a PDM to decode the
+ // decrypted output of the CDM.
+ pdm = Create();
+ if (!pdm) {
+ return nullptr;
+ }
+ } else {
+ NS_WARNING("CDM that decodes not yet supported!");
+ return nullptr;
+ }
+
+ return new EMEDecoderModule(aProxy,
+ pdm.forget(),
+ cdmDecodesAudio,
+ cdmDecodesVideo,
+ CreateTaskQueue());
+}
+
/* static */
PlatformDecoderModule*
PlatformDecoderModule::Create()
{
if (sUseBlankDecoder) {
return CreateBlankDecoderModule();
}
#ifdef XP_WIN
--- a/content/media/fmp4/PlatformDecoderModule.h
+++ b/content/media/fmp4/PlatformDecoderModule.h
@@ -26,16 +26,17 @@ namespace mozilla {
namespace layers {
class ImageContainer;
}
class MediaDataDecoder;
class MediaDataDecoderCallback;
class MediaInputQueue;
class MediaTaskQueue;
+class CDMProxy;
typedef int64_t Microseconds;
// The PlatformDecoderModule interface is used by the MP4Reader to abstract
// access to the H264 and AAC decoders provided by various platforms. It
// may be extended to support other codecs in future. Each platform (Windows,
// MacOSX, Linux, B2G etc) must implement a PlatformDecoderModule to provide
// access to its decoders in order to get decompressed H.264/AAC from the
// MP4Reader.
@@ -60,16 +61,25 @@ public:
// Factory method that creates the appropriate PlatformDecoderModule for
// the platform we're running on. Caller is responsible for deleting this
// instance. It's expected that there will be multiple
// PlatformDecoderModules alive at the same time. There is one
// PlatformDecoderModule created per MP4Reader.
// This is called on the decode thread.
static PlatformDecoderModule* Create();
+ // Creates a PlatformDecoderModule that uses a CDMProxy to decrypt or
+ // decrypt-and-decode EME encrypted content. If the CDM only decrypts and
+ // does not decode, we create a PDM and use that to create MediaDataDecoders
+ // that we use on on aTaskQueue to decode the decrypted stream.
+ static PlatformDecoderModule* CreateCDMWrapper(CDMProxy* aProxy,
+ bool aHasAudio,
+ bool aHasVideo,
+ MediaTaskQueue* aTaskQueue);
+
// Called to shutdown the decoder module and cleanup state. This should
// block until shutdown is complete. This is called after Shutdown() has
// been called on all MediaDataDecoders created from this
// PlatformDecoderModule.
// Called on the main thread only.
virtual nsresult Shutdown() = 0;
// Creates an H.264 decoder. The layers backend is passed in so that
new file mode 100644
--- /dev/null
+++ b/content/media/fmp4/eme/EMEDecoderModule.cpp
@@ -0,0 +1,246 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim:set ts=2 sw=2 sts=2 et cindent: */
+/* 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 "EMEDecoderModule.h"
+#include "mtransport/runnable_utils.h"
+#include "mozIGeckoMediaPluginService.h"
+#include "nsServiceManagerUtils.h"
+#include "nsThreadUtils.h"
+#include "ImageContainer.h"
+#include "prsystem.h"
+#include "mp4_demuxer/DecoderData.h"
+#include "gfx2DGlue.h"
+#include "nsContentUtils.h"
+#include "mozilla/CDMProxy.h"
+#include "mozilla/EMELog.h"
+#include "MediaTaskQueue.h"
+#include "SharedThreadPool.h"
+#include "mozilla/EMELog.h"
+#include <string>
+
+namespace mozilla {
+
+class EMEDecryptor : public MediaDataDecoder {
+ typedef mp4_demuxer::MP4Sample MP4Sample;
+
+public:
+
+ EMEDecryptor(MediaDataDecoder* aDecoder,
+ MediaDataDecoderCallback* aCallback,
+ MediaTaskQueue* aTaskQueue,
+ CDMProxy* aProxy)
+ : mDecoder(aDecoder)
+ , mCallback(aCallback)
+ , mTaskQueue(aTaskQueue)
+ , mProxy(aProxy)
+ {
+ }
+
+ virtual nsresult Init() MOZ_OVERRIDE {
+ return mTaskQueue->SyncDispatch(
+ NS_NewRunnableMethod(mDecoder,
+ &MediaDataDecoder::Init));
+ }
+
+ class RedeliverEncryptedInput : public nsRunnable {
+ public:
+ RedeliverEncryptedInput(EMEDecryptor* aDecryptor,
+ MediaTaskQueue* aTaskQueue,
+ MP4Sample* aSample)
+ : mDecryptor(aDecryptor)
+ , mTaskQueue(aTaskQueue)
+ , mSample(aSample)
+ {}
+
+ NS_IMETHOD Run() {
+ RefPtr<nsIRunnable> task;
+ task = NS_NewRunnableMethodWithArg<MP4Sample*>(mDecryptor,
+ &EMEDecryptor::Input,
+ mSample.forget());
+ mTaskQueue->Dispatch(task.forget());
+ mTaskQueue = nullptr;
+ mDecryptor = nullptr;
+ return NS_OK;
+ }
+
+ private:
+ nsRefPtr<EMEDecryptor> mDecryptor;
+ nsRefPtr<MediaTaskQueue> mTaskQueue;
+ nsAutoPtr<MP4Sample> mSample;
+ };
+
+ class DeliverDecrypted : public DecryptionClient {
+ public:
+ DeliverDecrypted(EMEDecryptor* aDecryptor, MediaTaskQueue* aTaskQueue)
+ : mDecryptor(aDecryptor)
+ , mTaskQueue(aTaskQueue)
+ {}
+ virtual void Decrypted(nsresult aResult,
+ mp4_demuxer::MP4Sample* aSample) MOZ_OVERRIDE {
+ if (NS_FAILED(aResult)) {
+ mDecryptor->mCallback->Error();
+ delete aSample;
+ } else {
+ RefPtr<nsIRunnable> task;
+ task = NS_NewRunnableMethodWithArg<MP4Sample*>(mDecryptor,
+ &EMEDecryptor::Decrypted,
+ aSample);
+ mTaskQueue->Dispatch(task.forget());
+ mTaskQueue = nullptr;
+ mDecryptor = nullptr;
+ }
+ }
+ private:
+ nsRefPtr<EMEDecryptor> mDecryptor;
+ nsRefPtr<MediaTaskQueue> mTaskQueue;
+ };
+
+ virtual nsresult Input(MP4Sample* aSample) MOZ_OVERRIDE {
+ // We run the PDM on its own task queue. We can't run it on the decode
+ // task queue, because that calls into Input() in a loop and waits until
+ // output is delivered. We need to defer some Input() calls while we wait
+ // for keys to become usable, and once they do we need to dispatch an event
+ // to run the PDM on the same task queue, but since the decode task queue
+ // is waiting in MP4Reader::Decode() for output our task would never run.
+ // So we dispatch tasks to make all calls into the wrapped decoder.
+ {
+ CDMCaps::AutoLock caps(mProxy->Capabilites());
+ if (!caps.IsKeyUsable(aSample->crypto.key)) {
+ EME_LOG("Encountered a non-usable key, waiting");
+ nsRefPtr<nsIRunnable> task(new RedeliverEncryptedInput(this,
+ mTaskQueue,
+ aSample));
+ caps.CallWhenKeyUsable(aSample->crypto.key, task);
+ return NS_OK;
+ }
+ }
+ mProxy->Decrypt(aSample, new DeliverDecrypted(this, mTaskQueue));
+ return NS_OK;
+ }
+
+ void Decrypted(mp4_demuxer::MP4Sample* aSample) {
+ mTaskQueue->Dispatch(
+ NS_NewRunnableMethodWithArg<mp4_demuxer::MP4Sample*>(
+ mDecoder,
+ &MediaDataDecoder::Input,
+ aSample));
+ }
+
+ virtual nsresult Flush() MOZ_OVERRIDE {
+ mTaskQueue->SyncDispatch(
+ NS_NewRunnableMethod(
+ mDecoder,
+ &MediaDataDecoder::Flush));
+ return NS_OK;
+ }
+
+ virtual nsresult Drain() MOZ_OVERRIDE {
+ mTaskQueue->Dispatch(
+ NS_NewRunnableMethod(
+ mDecoder,
+ &MediaDataDecoder::Drain));
+ return NS_OK;
+ }
+
+ virtual nsresult Shutdown() MOZ_OVERRIDE {
+ mTaskQueue->SyncDispatch(
+ NS_NewRunnableMethod(
+ mDecoder,
+ &MediaDataDecoder::Shutdown));
+ mDecoder = nullptr;
+ mTaskQueue->Shutdown();
+ mTaskQueue = nullptr;
+ mProxy = nullptr;
+ return NS_OK;
+ }
+
+private:
+
+ nsRefPtr<MediaDataDecoder> mDecoder;
+ MediaDataDecoderCallback* mCallback;
+ nsRefPtr<MediaTaskQueue> mTaskQueue;
+ nsRefPtr<CDMProxy> mProxy;
+};
+
+EMEDecoderModule::EMEDecoderModule(CDMProxy* aProxy,
+ PlatformDecoderModule* aPDM,
+ bool aCDMDecodesAudio,
+ bool aCDMDecodesVideo,
+ already_AddRefed<MediaTaskQueue> aTaskQueue)
+ : mProxy(aProxy)
+ , mPDM(aPDM)
+ , mTaskQueue(aTaskQueue)
+ , mCDMDecodesAudio(aCDMDecodesAudio)
+ , mCDMDecodesVideo(aCDMDecodesVideo)
+{
+}
+
+EMEDecoderModule::~EMEDecoderModule()
+{
+}
+
+nsresult
+EMEDecoderModule::Shutdown()
+{
+ MOZ_ASSERT(NS_IsMainThread(), "Must be on main thread.");
+ if (mPDM) {
+ return mPDM->Shutdown();
+ }
+ mTaskQueue->Shutdown();
+ return NS_OK;
+}
+
+MediaDataDecoder*
+EMEDecoderModule::CreateH264Decoder(const VideoDecoderConfig& aConfig,
+ layers::LayersBackend aLayersBackend,
+ layers::ImageContainer* aImageContainer,
+ MediaTaskQueue* aVideoTaskQueue,
+ MediaDataDecoderCallback* aCallback)
+{
+ if (mCDMDecodesVideo) {
+ NS_WARNING("Support for CDM that decodes video not yet supported");
+ return nullptr;
+ } else {
+ nsRefPtr<MediaDataDecoder> decoder(mPDM->CreateH264Decoder(aConfig,
+ aLayersBackend,
+ aImageContainer,
+ aVideoTaskQueue,
+ aCallback));
+ if (!decoder) {
+ return nullptr;
+ }
+
+ return new EMEDecryptor(decoder,
+ aCallback,
+ mTaskQueue,
+ mProxy);
+ }
+}
+
+MediaDataDecoder*
+EMEDecoderModule::CreateAACDecoder(const AudioDecoderConfig& aConfig,
+ MediaTaskQueue* aAudioTaskQueue,
+ MediaDataDecoderCallback* aCallback)
+{
+ if (mCDMDecodesAudio) {
+ NS_WARNING("Support for CDM that decodes audio not yet supported");
+ return nullptr;
+ } else {
+ nsRefPtr<MediaDataDecoder> decoder(mPDM->CreateAACDecoder(aConfig,
+ aAudioTaskQueue,
+ aCallback));
+ if (!decoder) {
+ return nullptr;
+ }
+
+ return new EMEDecryptor(decoder,
+ aCallback,
+ mTaskQueue,
+ mProxy);
+ }
+}
+
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/content/media/fmp4/eme/EMEDecoderModule.h
@@ -0,0 +1,62 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim:set ts=2 sw=2 sts=2 et cindent: */
+/* 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/. */
+
+#if !defined(EMEDecoderModule_h_)
+#define EMEDecoderModule_h_
+
+#include "PlatformDecoderModule.h"
+#include "gmp-decryption.h"
+
+namespace mozilla {
+
+class CDMProxy;
+class MediaTaskQueue;
+
+class EMEDecoderModule : public PlatformDecoderModule {
+private:
+ typedef mp4_demuxer::AudioDecoderConfig AudioDecoderConfig;
+ typedef mp4_demuxer::VideoDecoderConfig VideoDecoderConfig;
+
+public:
+ EMEDecoderModule(CDMProxy* aProxy,
+ PlatformDecoderModule* aPDM,
+ bool aCDMDecodesAudio,
+ bool aCDMDecodesVideo,
+ already_AddRefed<MediaTaskQueue> aDecodeTaskQueue);
+
+ virtual ~EMEDecoderModule();
+
+ // Called when the decoders have shutdown. Main thread only.
+ virtual nsresult Shutdown() MOZ_OVERRIDE;
+
+ // Decode thread.
+ virtual MediaDataDecoder*
+ CreateH264Decoder(const mp4_demuxer::VideoDecoderConfig& aConfig,
+ layers::LayersBackend aLayersBackend,
+ layers::ImageContainer* aImageContainer,
+ MediaTaskQueue* aVideoTaskQueue,
+ MediaDataDecoderCallback* aCallback) MOZ_OVERRIDE;
+
+ // Decode thread.
+ virtual MediaDataDecoder* CreateAACDecoder(
+ const mp4_demuxer::AudioDecoderConfig& aConfig,
+ MediaTaskQueue* aAudioTaskQueue,
+ MediaDataDecoderCallback* aCallback) MOZ_OVERRIDE;
+
+private:
+ nsRefPtr<CDMProxy> mProxy;
+ // Will be null if CDM has decoding capability.
+ nsAutoPtr<PlatformDecoderModule> mPDM;
+ // We run the PDM on its own task queue.
+ nsRefPtr<MediaTaskQueue> mTaskQueue;
+ bool mCDMDecodesAudio;
+ bool mCDMDecodesVideo;
+
+};
+
+} // namespace mozilla
+
+#endif // EMEDecoderModule_h_
--- a/content/media/fmp4/moz.build
+++ b/content/media/fmp4/moz.build
@@ -1,45 +1,47 @@
# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
# vim: set filetype=python:
# 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/.
EXPORTS += [
+ 'eme/EMEDecoderModule.h',
'MP4Decoder.h',
'MP4Reader.h',
'PlatformDecoderModule.h',
]
UNIFIED_SOURCES += [
'BlankDecoderModule.cpp',
+ 'eme/EMEDecoderModule.cpp',
'PlatformDecoderModule.cpp',
]
SOURCES += [
'MP4Decoder.cpp',
'MP4Reader.cpp',
]
if CONFIG['MOZ_WMF']:
- DIRS += [ 'wmf' ];
+ DIRS += [ 'wmf' ];
if CONFIG['MOZ_FFMPEG']:
- EXPORTS += [
- 'ffmpeg/FFmpegRuntimeLinker.h',
- ]
- UNIFIED_SOURCES += [
- 'ffmpeg/FFmpegLog.cpp',
- 'ffmpeg/FFmpegRuntimeLinker.cpp',
- ]
- DIRS += [
- 'ffmpeg/libav53',
- 'ffmpeg/libav54',
- 'ffmpeg/libav55',
- ]
- LOCAL_INCLUDES += [
- 'ffmpeg',
- ]
+ EXPORTS += [
+ 'ffmpeg/FFmpegRuntimeLinker.h',
+ ]
+ UNIFIED_SOURCES += [
+ 'ffmpeg/FFmpegLog.cpp',
+ 'ffmpeg/FFmpegRuntimeLinker.cpp',
+ ]
+ DIRS += [
+ 'ffmpeg/libav53',
+ 'ffmpeg/libav54',
+ 'ffmpeg/libav55',
+ ]
+ LOCAL_INCLUDES += [
+ 'ffmpeg',
+ ]
FINAL_LIBRARY = 'xul'
FAIL_ON_WARNINGS = True
--- a/content/media/gmp/GMPChild.cpp
+++ b/content/media/gmp/GMPChild.cpp
@@ -21,16 +21,18 @@ using mozilla::dom::CrashReporterChild;
#include <stdlib.h> // for _exit()
#else
#include <unistd.h> // for _exit()
#endif
#if defined(XP_WIN)
#define TARGET_SANDBOX_EXPORTS
#include "mozilla/sandboxTarget.h"
+#elif defined(XP_LINUX) && defined(MOZ_GMP_SANDBOX)
+#include "mozilla/Sandbox.h"
#endif
namespace mozilla {
namespace gmp {
GMPChild::GMPChild()
: mLib(nullptr)
, mGetAPIFunc(nullptr)
@@ -93,16 +95,23 @@ GMPChild::LoadPluginLibrary(const std::s
nsAutoString binaryName = baseName + NS_LITERAL_STRING(".dll");
#else
#error not defined
#endif
libFile->AppendRelativePath(binaryName);
nsAutoCString nativePath;
libFile->GetNativePath(nativePath);
+
+#if defined(XP_LINUX) && defined(MOZ_GMP_SANDBOX)
+ // Enable sandboxing here -- we know the plugin file's path, but
+ // this process's execution hasn't been affected by its content yet.
+ mozilla::SetMediaPluginSandbox(nativePath.get());
+#endif
+
mLib = PR_LoadLibrary(nativePath.get());
if (!mLib) {
return false;
}
GMPInitFunc initFunc = reinterpret_cast<GMPInitFunc>(PR_FindFunctionSymbol(mLib, "GMPInit"));
if (!initFunc) {
return false;
--- a/content/media/gmp/GMPDecryptorProxy.h
+++ b/content/media/gmp/GMPDecryptorProxy.h
@@ -2,16 +2,17 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef GMPDecryptorProxy_h_
#define GMPDecryptorProxy_h_
#include "GMPCallbackBase.h"
+#include "gmp-decryption.h"
namespace mp4_demuxer {
class CryptoSample;
}
class GMPDecryptorProxyCallback : public GMPCallbackBase {
public:
~GMPDecryptorProxyCallback() {}
new file mode 100644
--- /dev/null
+++ b/content/media/test/crashtests/944851.html
@@ -0,0 +1,17 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="UTF-8">
+<script>
+
+var ac = new AudioContext(1, 1354, 44100);
+var shaper = ac.createWaveShaper();
+var biquad = ac.createBiquadFilter();
+shaper.connect(biquad.frequency);
+biquad.getFrequencyResponse(new Float32Array(55785),
+ new Float32Array(62876),
+ new Float32Array(45111));
+
+</script>
+</head>
+</html>
new file mode 100644
--- /dev/null
+++ b/content/media/test/crashtests/966636.html
@@ -0,0 +1,45 @@
+<html class="reftest-wait">
+<head>
+<script>
+function boom() {
+ var Context0= new window.AudioContext();
+ var BufferSource0=Context0.createBufferSource();
+ BufferSource0.start(0);
+ BufferSource0.playbackRate.value = 1.0/128.0;
+
+ setTimeout(
+ function(){
+ BufferSource0.buffer=
+ function(){
+ var length=1;
+ var Buffer=Context0.createBuffer(1,length,Context0.sampleRate);
+ var bufferData= Buffer.getChannelData(0);
+ for (var i = 0; i < length; ++i) {
+ bufferData[i] = Math.sin(i*(626))
+ };return Buffer;
+ }();
+ setTimeout(
+ function(){
+ document.documentElement.removeAttribute("class");
+ }, 0)
+ },4)
+
+ BufferSource0.buffer=
+ function(){
+ const resample_filter_length = 64;
+ // Small enough so that resampler tail latency is triggered immediately,
+ // but large enough that skip_zeros does not consume resampler tail
+ // latency.
+ var length=resample_filter_length/2 + 1;
+ var Buffer=Context0.createBuffer(1,length,Context0.sampleRate);
+ var bufferData= Buffer.getChannelData(0);
+ for (var i = 0; i < length; ++i) {
+ bufferData[i] = Math.sin(i*(311980))
+ };
+ return Buffer;
+ }();
+}
+</script>
+</head>
+<body onload="boom();">
+</body>
new file mode 100644
--- /dev/null
+++ b/content/media/test/crashtests/990794.html
@@ -0,0 +1,22 @@
+<!DOCTYPE html>
+<script>
+var ctx = new AudioContext();
+var source = ctx.createOscillator();
+source.start(0);
+
+function appendMerger(src) {
+ const inputCount = 18;
+
+ var merger = ctx.createChannelMerger(32);
+
+ for (var i = 0; i < inputCount; ++i) {
+ src.connect(merger, 0, i);
+ }
+
+ return merger;
+}
+
+for (var i = 0; i < 6; ++i) {
+ source = appendMerger(source);
+}
+</script>
--- a/content/media/test/crashtests/crashtests.list
+++ b/content/media/test/crashtests/crashtests.list
@@ -58,18 +58,21 @@ load 907986-3.html
load 907986-4.html
load 910171-1.html
load 920987.html
load 925619-1.html
load 925619-2.html
load 926619.html
load 933151.html
load 933156.html
+load 944851.html
load 952756.html
+load 966636.html
load 986901.html
+load 990794.html
load buffer-source-ended-1.html
load offline-buffer-source-ended-1.html
HTTP load media-element-source-seek-1.html
skip-if(B2G) load oscillator-ended-1.html # intermittent B2G timeouts, bug 920338
skip-if(B2G) load oscillator-ended-2.html # intermittent B2G timeouts, bug 920338
load 1015662.html
include ../../mediasource/test/crashtests/crashtests.list
test-pref(media.navigator.permission.disabled,true) load 1028458.html
--- a/content/media/webaudio/AudioBufferSourceNode.cpp
+++ b/content/media/webaudio/AudioBufferSourceNode.cpp
@@ -7,17 +7,16 @@
#include "AudioBufferSourceNode.h"
#include "mozilla/dom/AudioBufferSourceNodeBinding.h"
#include "mozilla/dom/AudioParam.h"
#include "nsMathUtils.h"
#include "AudioNodeEngine.h"
#include "AudioNodeStream.h"
#include "AudioDestinationNode.h"
#include "AudioParamTimeline.h"
-#include "speex/speex_resampler.h"
#include <limits>
namespace mozilla {
namespace dom {
NS_IMPL_CYCLE_COLLECTION_CLASS(AudioBufferSourceNode)
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(AudioBufferSourceNode)
--- a/content/media/webaudio/WaveShaperNode.cpp
+++ b/content/media/webaudio/WaveShaperNode.cpp
@@ -5,17 +5,16 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "WaveShaperNode.h"
#include "mozilla/dom/WaveShaperNodeBinding.h"
#include "AudioNode.h"
#include "AudioNodeEngine.h"
#include "AudioNodeStream.h"
#include "mozilla/PodOperations.h"
-#include "speex/speex_resampler.h"
namespace mozilla {
namespace dom {
NS_IMPL_CYCLE_COLLECTION_CLASS(WaveShaperNode)
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(WaveShaperNode, AudioNode)
NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
--- a/content/media/webaudio/WebAudioUtils.cpp
+++ b/content/media/webaudio/WebAudioUtils.cpp
@@ -3,17 +3,16 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "WebAudioUtils.h"
#include "AudioNodeStream.h"
#include "AudioParamTimeline.h"
#include "blink/HRTFDatabaseLoader.h"
-#include "speex/speex_resampler.h"
namespace mozilla {
namespace dom {
struct ConvertTimeToTickHelper
{
AudioNodeStream* mSourceStream;
--- a/content/media/webaudio/blink/HRTFElevation.cpp
+++ b/content/media/webaudio/blink/HRTFElevation.cpp
@@ -23,17 +23,17 @@
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "HRTFElevation.h"
-#include "speex/speex_resampler.h"
+#include <speex/speex_resampler.h>
#include "mozilla/PodOperations.h"
#include "AudioSampleFormat.h"
#include "IRC_Composite_C_R0195-incl.cpp"
using namespace std;
using namespace mozilla;
--- a/content/media/webspeech/synth/pico/nsPicoService.cpp
+++ b/content/media/webspeech/synth/pico/nsPicoService.cpp
@@ -300,17 +300,17 @@ PicoCallbackRunnable::Run()
&bytes_sent);
PICO_ENSURE_SUCCESS("pico_putTextUtf8", status, NS_ERROR_FAILURE);
// XXX: End speech task on error
text_remaining -= bytes_sent;
text_offset += bytes_sent;
} else {
// If we already fed all the text to the engine, send a zero length buffer
// and quit.
- DispatchSynthDataRunnable(already_AddRefed<SharedBuffer>(nullptr), 0);
+ DispatchSynthDataRunnable(already_AddRefed<SharedBuffer>(), 0);
break;
}
do {
// Run this loop while the result of getData is STEP_BUSY, when it finishes
// synthesizing audio for the given text, it returns STEP_IDLE. We then
// break to the outer loop and feed more text, if there is any left.
if (!IsCurrentTask()) {
--- a/dom/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -4366,16 +4366,31 @@ nsGlobalWindow::GetOwnPropertyNames(JSCo
/* static */ bool
nsGlobalWindow::IsChromeWindow(JSContext* aCx, JSObject* aObj)
{
// For now, have to deal with XPConnect objects here.
return xpc::WindowOrNull(aObj)->IsChromeWindow();
}
+/* static */ bool
+nsGlobalWindow::IsShowModalDialogEnabled(JSContext*, JSObject*)
+{
+ static bool sAddedPrefCache = false;
+ static bool sIsDisabled;
+ static const char sShowModalDialogPref[] = "dom.disable_window_showModalDialog";
+
+ if (!sAddedPrefCache) {
+ Preferences::AddBoolVarCache(&sIsDisabled, sShowModalDialogPref, false);
+ sAddedPrefCache = true;
+ }
+
+ return !sIsDisabled;
+}
+
nsIDOMOfflineResourceList*
nsGlobalWindow::GetApplicationCache(ErrorResult& aError)
{
FORWARD_TO_INNER_OR_THROW(GetApplicationCache, (aError), aError, nullptr);
if (!mApplicationCache) {
nsCOMPtr<nsIWebNavigation> webNav(do_QueryInterface(GetDocShell()));
if (!webNav) {
@@ -9122,17 +9137,17 @@ nsGlobalWindow::ShowModalDialog(const ns
if (mDoc) {
mDoc->WarnOnceAbout(nsIDocument::eShowModalDialog);
}
FORWARD_TO_OUTER_OR_THROW(ShowModalDialog,
(aUrl, aArgument, aOptions, aError), aError,
nullptr);
- if (Preferences::GetBool("dom.disable_window_showModalDialog", false)) {
+ if (!IsShowModalDialogEnabled()) {
aError.Throw(NS_ERROR_NOT_AVAILABLE);
return nullptr;
}
nsRefPtr<DialogValueHolder> argHolder =
new DialogValueHolder(nsContentUtils::SubjectPrincipal(), aArgument);
// Before bringing up the window/dialog, unsuppress painting and flush
--- a/dom/base/nsGlobalWindow.h
+++ b/dom/base/nsGlobalWindow.h
@@ -507,16 +507,19 @@ public:
// WebIDL interface.
already_AddRefed<nsIDOMWindow> IndexedGetter(uint32_t aIndex, bool& aFound);
void GetSupportedNames(nsTArray<nsString>& aNames);
static bool IsChromeWindow(JSContext* /* unused */, JSObject* aObj);
+ static bool IsShowModalDialogEnabled(JSContext* /* unused */ = nullptr,
+ JSObject* /* unused */ = nullptr);
+
bool DoNewResolve(JSContext* aCx, JS::Handle<JSObject*> aObj,
JS::Handle<jsid> aId,
JS::MutableHandle<JSPropertyDescriptor> aDesc);
void GetOwnPropertyNames(JSContext* aCx, nsTArray<nsString>& aNames,
mozilla::ErrorResult& aRv);
// Object Management
--- a/dom/base/nsJSEnvironment.cpp
+++ b/dom/base/nsJSEnvironment.cpp
@@ -705,58 +705,31 @@ DumpString(const nsAString &str)
{
printf("%s\n", NS_ConvertUTF16toUTF8(str).get());
}
#endif
#define JS_OPTIONS_DOT_STR "javascript.options."
static const char js_options_dot_str[] = JS_OPTIONS_DOT_STR;
-static const char js_strict_option_str[] = JS_OPTIONS_DOT_STR "strict";
-#ifdef DEBUG
-static const char js_strict_debug_option_str[] = JS_OPTIONS_DOT_STR "strict.debug";
-#endif
#ifdef JS_GC_ZEAL
static const char js_zeal_option_str[] = JS_OPTIONS_DOT_STR "gczeal";
static const char js_zeal_frequency_str[] = JS_OPTIONS_DOT_STR "gczeal.frequency";
#endif
static const char js_memlog_option_str[] = JS_OPTIONS_DOT_STR "mem.log";
static const char js_memnotify_option_str[] = JS_OPTIONS_DOT_STR "mem.notify";
void
nsJSContext::JSOptionChangedCallback(const char *pref, void *data)
{
- nsJSContext *context = reinterpret_cast<nsJSContext *>(data);
- JSContext *cx = context->mContext;
-
sPostGCEventsToConsole = Preferences::GetBool(js_memlog_option_str);
sPostGCEventsToObserver = Preferences::GetBool(js_memnotify_option_str);
- JS::ContextOptionsRef(cx).setExtraWarnings(Preferences::GetBool(js_strict_option_str));
-
- // The vanilla GetGlobalObject returns null if a global isn't set up on
- // the context yet. We can sometimes be call midway through context init,
- // So ask for the member directly instead.
- nsIScriptGlobalObject *global = context->GetGlobalObjectRef();
-
- // XXX should we check for sysprin instead of a chrome window, to make
- // XXX components be covered by the chrome pref instead of the content one?
- nsCOMPtr<nsIDOMWindow> contentWindow(do_QueryInterface(global));
- nsCOMPtr<nsIDOMChromeWindow> chromeWindow(do_QueryInterface(global));
-
-#ifdef DEBUG
- // In debug builds, warnings are enabled in chrome context if
- // javascript.options.strict.debug is true
- if (Preferences::GetBool(js_strict_debug_option_str) &&
- (chromeWindow || !contentWindow)) {
- JS::ContextOptionsRef(cx).setExtraWarnings(true);
- }
-#endif
-
#ifdef JS_GC_ZEAL
+ nsJSContext *context = reinterpret_cast<nsJSContext *>(data);
int32_t zeal = Preferences::GetInt(js_zeal_option_str, -1);
int32_t frequency = Preferences::GetInt(js_zeal_frequency_str, JS_DEFAULT_ZEAL_FREQ);
if (zeal >= 0)
::JS_SetGCZeal(context->mContext, (uint8_t)zeal, frequency);
#endif
}
nsJSContext::nsJSContext(bool aGCOnDestruction,
--- a/dom/browser-element/mochitest/priority/test_ExpectingSystemMessage.html
+++ b/dom/browser-element/mochitest/priority/test_ExpectingSystemMessage.html
@@ -38,18 +38,18 @@ function runTest() {
// process times out.
return expectPriorityChange(childID, 'FOREGROUND');
}).then(SimpleTest.finish);
document.body.appendChild(iframe);
}
addEventListener('testready', function() {
- // Cause the CPU wake lock taken on behalf of this new process to time out
- // after 1s.
+ // Cause the grace period of priority privilege for this new process to time
+ // out after 1s.
SpecialPowers.pushPrefEnv(
{set: [["dom.ipc.systemMessageCPULockTimeoutSec", 1]]},
runTest);
});
</script>
</body>
</html>
--- a/dom/browser-element/mochitest/priority/test_ExpectingSystemMessage2.html
+++ b/dom/browser-element/mochitest/priority/test_ExpectingSystemMessage2.html
@@ -52,19 +52,19 @@ function runTest() {
iframe.setVisible(false);
return p;
}).then(SimpleTest.finish);
document.body.appendChild(iframe);
}
addEventListener('testready', function() {
- // We don't want this wake lock to time out during the test; if it did, then
- // we might see BACKGROUND priority instead of BACKGROUND_PERCEIVABLE. So
- // set the timeout to a large value.
+ // We don't want the grace period of priority privilege to time out during the
+ // test; should it really happen, we would see BACKGROUND priority instead of
+ // BACKGROUND_PERCEIVABLE. So set the timeout to a large value.
SpecialPowers.pushPrefEnv(
{set: [["dom.ipc.systemMessageCPULockTimeoutSec", 99999]]},
runTest);
});
</script>
</body>
</html>
--- a/dom/browser-element/mochitest/priority/test_HighPriorityDowngrade.html
+++ b/dom/browser-element/mochitest/priority/test_HighPriorityDowngrade.html
@@ -64,18 +64,18 @@ function runTest() {
}).then(SimpleTest.finish);
document.body.appendChild(iframe);
}
addEventListener('testready', function() {
SpecialPowers.pushPrefEnv(
{set: [
- /* Cause the CPU wake lock taken on behalf of the high-priority process
- * to time out after 1s. */
+ /* Cause the grace period of priority privilege for the high-priority
+ * process to time out after 1s. */
["dom.ipc.systemMessageCPULockTimeoutSec", 1],
["dom.wakelock.enabled", true]
]},
runTest);
});
</script>
</body>
--- a/dom/browser-element/mochitest/priority/test_HighPriorityDowngrade2.html
+++ b/dom/browser-element/mochitest/priority/test_HighPriorityDowngrade2.html
@@ -60,18 +60,18 @@ function runTest() {
document.body.removeChild(highPriorityIframe);
return p;
}).then(SimpleTest.finish);
document.body.appendChild(iframe);
}
addEventListener('testready', function() {
- // Cause the CPU wake lock taken on behalf of the high-priority process never
- // to time out during this test.
+ // Cause the grace period of priority privilege for the high-priority process
+ // never to time out during this test.
SpecialPowers.pushPrefEnv(
{set: [["dom.ipc.systemMessageCPULockTimeoutSec", 1000]]},
runTest);
});
</script>
</body>
</html>
--- a/dom/canvas/WebGLExtensionInstancedArrays.cpp
+++ b/dom/canvas/WebGLExtensionInstancedArrays.cpp
@@ -21,37 +21,37 @@ WebGLExtensionInstancedArrays::~WebGLExt
{
}
void
WebGLExtensionInstancedArrays::DrawArraysInstancedANGLE(GLenum mode, GLint first,
GLsizei count, GLsizei primcount)
{
if (mIsLost)
- return mContext->ErrorInvalidOperation("drawArraysInstancedANGLE: Extension is lost.");
+ return mContext->GenerateWarning("drawArraysInstancedANGLE: Extension is lost.");
mContext->DrawArraysInstanced(mode, first, count, primcount);
}
void
WebGLExtensionInstancedArrays::DrawElementsInstancedANGLE(GLenum mode, GLsizei count,
GLenum type, WebGLintptr offset,
GLsizei primcount)
{
if (mIsLost)
- return mContext->ErrorInvalidOperation("drawElementsInstancedANGLE: Extension is lost.");
+ return mContext->GenerateWarning("drawElementsInstancedANGLE: Extension is lost.");
mContext->DrawElementsInstanced(mode, count, type, offset, primcount);
}
void
WebGLExtensionInstancedArrays::VertexAttribDivisorANGLE(GLuint index, GLuint divisor)
{
if (mIsLost)
- return mContext->ErrorInvalidOperation("vertexAttribDivisorANGLE: Extension is lost.");
+ return mContext->GenerateWarning("vertexAttribDivisorANGLE: Extension is lost.");
mContext->VertexAttribDivisor(index, divisor);
}
bool
WebGLExtensionInstancedArrays::IsSupported(const WebGLContext* context)
{
gl::GLContext* gl = context->GL();
--- a/dom/canvas/WebGLExtensionVertexArray.cpp
+++ b/dom/canvas/WebGLExtensionVertexArray.cpp
@@ -21,45 +21,45 @@ WebGLExtensionVertexArray::WebGLExtensio
WebGLExtensionVertexArray::~WebGLExtensionVertexArray()
{
}
already_AddRefed<WebGLVertexArray> WebGLExtensionVertexArray::CreateVertexArrayOES()
{
if (mIsLost) {
- mContext->ErrorInvalidOperation("createVertexArrayOES: Extension is lost. Returning NULL.");
+ mContext->GenerateWarning("createVertexArrayOES: Extension is lost. Returning null.");
return nullptr;
}
return mContext->CreateVertexArray();
}
void WebGLExtensionVertexArray::DeleteVertexArrayOES(WebGLVertexArray* array)
{
if (mIsLost)
- return mContext->ErrorInvalidOperation("deleteVertexArrayOES: Extension is lost.");
+ return mContext->GenerateWarning("deleteVertexArrayOES: Extension is lost.");
mContext->DeleteVertexArray(array);
}
bool WebGLExtensionVertexArray::IsVertexArrayOES(WebGLVertexArray* array)
{
if (mIsLost) {
- mContext->ErrorInvalidOperation("isVertexArrayOES: Extension is lost. Returning false.");
+ mContext->GenerateWarning("isVertexArrayOES: Extension is lost. Returning false.");
return false;
}
return mContext->IsVertexArray(array);
}
void WebGLExtensionVertexArray::BindVertexArrayOES(WebGLVertexArray* array)
{
if (mIsLost)
- return mContext->ErrorInvalidOperation("bindVertexArrayOES: Extension is lost.");
+ return mContext->GenerateWarning("bindVertexArrayOES: Extension is lost.");
mContext->BindVertexArray(array);
}
bool WebGLExtensionVertexArray::IsSupported(const WebGLContext* context)
{
// If it is not supported then it's emulated, therefore it's always 'supported'
// See - WebGLVertexArrayFake.h/cpp for the emulation
--- a/dom/canvas/WebGLTexelConversions.h
+++ b/dom/canvas/WebGLTexelConversions.h
@@ -115,17 +115,17 @@ unpackFromFloat16(uint16_t v)
f32Bits |= 0x7FFFFFFF;
} else {
// this is -inf or +inf
f32Bits |= 0x7F800000;
}
return f32Value;
}
- f32Bits |= uint32_t(exp + (-15 + 127)) << 10;
+ f32Bits |= uint32_t(exp + (-15 + 127)) << 23;
f32Bits |= uint32_t(v & 0x03FF) << 13;
return f32Value;
}
MOZ_BEGIN_ENUM_CLASS(WebGLTexelPremultiplicationOp, int)
None,
Premultiply,
--- a/dom/cellbroadcast/tests/marionette/head.js
+++ b/dom/cellbroadcast/tests/marionette/head.js
@@ -53,16 +53,36 @@ const CB_DCS_LANG_GROUP_1 = [
"de", "en", "it", "fr", "es", "nl", "sv", "da", "pt", "fi",
"no", "el", "tr", "hu", "pl", null
];
const CB_DCS_LANG_GROUP_2 = [
"cs", "he", "ar", "ru", "is", null, null, null, null, null,
null, null, null, null, null, null
];
+const CB_MAX_CONTENT_PER_PAGE_7BIT = Math.floor((CB_MESSAGE_SIZE_GSM - 6) * 8 / 7);
+const CB_MAX_CONTENT_PER_PAGE_UCS2 = Math.floor((CB_MESSAGE_SIZE_GSM - 6) / 2);
+
+const DUMMY_BODY_7BITS = "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"
+ + "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"
+ + "@@@@@@@@@@@@@"; // 93 ascii chars.
+const DUMMY_BODY_7BITS_IND = DUMMY_BODY_7BITS.substr(3);
+const DUMMY_BODY_UCS2 = "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000"
+ + "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000"
+ + "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000"
+ + "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000"
+ + "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000"
+ + "\u0000"; // 41 unicode chars.
+const DUMMY_BODY_UCS2_IND = DUMMY_BODY_UCS2.substr(1);
+
+is(DUMMY_BODY_7BITS.length, CB_MAX_CONTENT_PER_PAGE_7BIT, "DUMMY_BODY_7BITS.length");
+is(DUMMY_BODY_7BITS_IND.length, CB_MAX_CONTENT_PER_PAGE_7BIT - 3, "DUMMY_BODY_7BITS_IND.length");
+is(DUMMY_BODY_UCS2.length, CB_MAX_CONTENT_PER_PAGE_UCS2, "DUMMY_BODY_UCS2.length");
+is(DUMMY_BODY_UCS2_IND.length, CB_MAX_CONTENT_PER_PAGE_UCS2 - 1, "DUMMY_BODY_UCS2_IND.length");
+
/**
* Compose input number into specified number of semi-octets.
*
* @param: aNum
* The number to be converted.
* @param: aNumSemiOctets
* Number of semi-octects to be composed to.
*
--- a/dom/cellbroadcast/tests/marionette/manifest.ini
+++ b/dom/cellbroadcast/tests/marionette/manifest.ini
@@ -1,8 +1,9 @@
[DEFAULT]
b2g = true
browser = false
qemu = true
[test_cellbroadcast_etws.js]
[test_cellbroadcast_gsm.js]
-[test_cellbroadcast_multi_sim.js]
\ No newline at end of file
+[test_cellbroadcast_multi_sim.js]
+[test_cellbroadcast_umts.js]
\ No newline at end of file
--- a/dom/cellbroadcast/tests/marionette/test_cellbroadcast_gsm.js
+++ b/dom/cellbroadcast/tests/marionette/test_cellbroadcast_gsm.js
@@ -1,34 +1,14 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
-MARIONETTE_TIMEOUT = 60000;
+MARIONETTE_TIMEOUT = 90000;
MARIONETTE_HEAD_JS = 'head.js';
-const CB_MAX_CONTENT_7BIT = Math.floor((CB_MESSAGE_SIZE_GSM - 6) * 8 / 7);
-const CB_MAX_CONTENT_UCS2 = Math.floor((CB_MESSAGE_SIZE_GSM - 6) / 2);
-
-const BODY_7BITS = "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"
- + "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"
- + "@@@@@@@@@@@@@"; // 93 ascii chars.
-const BODY_7BITS_IND = BODY_7BITS.substr(3);
-const BODY_UCS2 = "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000"
- + "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000"
- + "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000"
- + "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000"
- + "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000"
- + "\u0000"; // 41 unicode chars.
-const BODY_UCS2_IND = BODY_UCS2.substr(1);
-
-is(BODY_7BITS.length, CB_MAX_CONTENT_7BIT, "BODY_7BITS.length");
-is(BODY_7BITS_IND.length, CB_MAX_CONTENT_7BIT - 3, "BODY_7BITS_IND.length");
-is(BODY_UCS2.length, CB_MAX_CONTENT_UCS2, "BODY_UCS2.length");
-is(BODY_UCS2_IND.length, CB_MAX_CONTENT_UCS2 - 1, "BODY_UCS2_IND.length");
-
function testReceiving_GSM_MessageAttributes() {
log("Test receiving GSM Cell Broadcast - Message Attributes");
let verifyCBMessage = (aMessage) => {
// Attributes other than `language` and `body` should always be assigned.
ok(aMessage.gsmGeographicalScope != null, "aMessage.gsmGeographicalScope");
ok(aMessage.messageCode != null, "aMessage.messageCode");
ok(aMessage.messageId != null, "aMessage.messageId");
@@ -154,23 +134,23 @@ function testReceiving_GSM_Language_and_
} else if (aDcsInfo.indicator) {
is(aMessage.language, "@@", "aMessage.language");
} else {
ok(aMessage.language == null, "aMessage.language");
}
switch (aDcsInfo.encoding) {
case PDU_DCS_MSG_CODING_7BITS_ALPHABET:
- is(aMessage.body, aDcsInfo.indicator ? BODY_7BITS_IND : BODY_7BITS, "aMessage.body");
+ is(aMessage.body, aDcsInfo.indicator ? DUMMY_BODY_7BITS_IND : DUMMY_BODY_7BITS, "aMessage.body");
break;
case PDU_DCS_MSG_CODING_8BITS_ALPHABET:
ok(aMessage.body == null, "aMessage.body");
break;
case PDU_DCS_MSG_CODING_16BITS_ALPHABET:
- is(aMessage.body, aDcsInfo.indicator ? BODY_UCS2_IND : BODY_UCS2, "aMessage.body");
+ is(aMessage.body, aDcsInfo.indicator ? DUMMY_BODY_UCS2_IND : DUMMY_BODY_UCS2, "aMessage.body");
break;
}
is(aMessage.messageClass, aDcsInfo.messageClass, "aMessage.messageClass");
};
testDcs.forEach(function(aDcsInfo) {
let pdu = buildHexStr(0, 8)
@@ -291,17 +271,17 @@ function testReceiving_GSM_Multipart() {
let promise = Promise.resolve();
// According to 9.4.1.2.4 Page Parameter in TS 23.041, the maximal Number of
// pages per CB message is 15.
let numParts = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15];
let verifyCBMessage = (aMessage, aNumParts) => {
- is(aMessage.body.length, (aNumParts * CB_MAX_CONTENT_7BIT),
+ is(aMessage.body.length, (aNumParts * CB_MAX_CONTENT_PER_PAGE_7BIT),
"aMessage.body");
};
numParts.forEach(function(aNumParts) {
let pdus = [];
for (let i = 1; i <= aNumParts; i++) {
let pdu = buildHexStr(0, 10)
+ buildHexStr((i << 4) + aNumParts, 2)
--- a/dom/cellbroadcast/tests/marionette/test_cellbroadcast_multi_sim.js
+++ b/dom/cellbroadcast/tests/marionette/test_cellbroadcast_multi_sim.js
@@ -1,26 +1,22 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
MARIONETTE_TIMEOUT = 10000;
MARIONETTE_HEAD_JS = 'head.js';
-const BODY_7BITS = "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"
- + "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"
- + "@@@@@@@@@@@@@"; // 93 ascii chars.
-
function testReceiving_MultiSIM() {
log("Test receiving GSM Cell Broadcast - Multi-SIM");
let pdu = buildHexStr(0, CB_MESSAGE_SIZE_GSM * 2);
let verifyCBMessage = (aMessage, aServiceId) => {
log("Verify CB message received from serviceId: " + aServiceId);
- is(aMessage.body, BODY_7BITS, "Checking message body.");
+ is(aMessage.body, DUMMY_BODY_7BITS, "Checking message body.");
is(aMessage.serviceId, aServiceId, "Checking serviceId.");
};
return selectModem(1)
.then(() => sendMultipleRawCbsToEmulatorAndWait([pdu]))
.then((aMessage) => verifyCBMessage(aMessage, 1))
.then(() => selectModem(0))
.then(() => sendMultipleRawCbsToEmulatorAndWait([pdu]))
new file mode 100644
--- /dev/null
+++ b/dom/cellbroadcast/tests/marionette/test_cellbroadcast_umts.js
@@ -0,0 +1,450 @@
+MARIONETTE_TIMEOUT = 90000;
+MARIONETTE_HEAD_JS = 'head.js';
+
+const CB_UMTS_MESSAGE_TYPE_CBS = 1;
+const CB_UMTS_MESSAGE_PAGE_SIZE = 82;
+
+function testReceiving_UMTS_MessageAttributes() {
+ log("Test receiving UMTS Cell Broadcast - Message Attributes");
+
+ let verifyCBMessage = (aMessage) => {
+ // Attributes other than `language` , `body` and `data` should always be assigned.
+ ok(aMessage.gsmGeographicalScope != null, "aMessage.gsmGeographicalScope");
+ ok(aMessage.messageCode != null, "aMessage.messageCode");
+ ok(aMessage.messageId != null, "aMessage.messageId");
+ ok(aMessage.messageClass != null, "aMessage.messageClass");
+ ok(aMessage.timestamp != null, "aMessage.timestamp");
+ ok('etws' in aMessage, "aMessage.etws");
+ if (aMessage.etws) {
+ ok('warningType' in aMessage.etws, "aMessage.etws.warningType");
+ ok(aMessage.etws.emergencyUserAlert != null, "aMessage.etws.emergencyUserAlert");
+ ok(aMessage.etws.popup != null, "aMessage.etws.popup");
+ }
+ ok(aMessage.cdmaServiceCategory != null, "aMessage.cdmaServiceCategory");
+ };
+
+ // Here we use a single UMTS message for test.
+ let pdu = buildHexStr(CB_UMTS_MESSAGE_TYPE_CBS, 2) // msg_type
+ + buildHexStr(0, 10) // skip msg_id, sn, dcs
+ + buildHexStr(1, 2) // set num_of_pages to 1
+ + buildHexStr(0, CB_UMTS_MESSAGE_PAGE_SIZE * 2)
+ + buildHexStr(CB_UMTS_MESSAGE_PAGE_SIZE, 2); // msg_info_length
+
+ return sendMultipleRawCbsToEmulatorAndWait([pdu])
+ .then((aMessage) => verifyCBMessage(aMessage));
+}
+
+function testReceiving_UMTS_GeographicalScope() {
+ log("Test receiving UMTS Cell Broadcast - Geographical Scope");
+
+ let promise = Promise.resolve();
+
+ let verifyCBMessage = (aMessage, aGsName) => {
+ is(aMessage.gsmGeographicalScope, aGsName,
+ "aMessage.gsmGeographicalScope");
+ };
+
+ CB_GSM_GEOGRAPHICAL_SCOPE_NAMES.forEach(function(aGsName, aIndex) {
+ let pdu = buildHexStr(CB_UMTS_MESSAGE_TYPE_CBS, 2) // msg_type
+ + buildHexStr(0, 4) // skip msg_id
+ + buildHexStr(((aIndex & 0x03) << 14), 4) // set SN
+ + buildHexStr(0, 2) // skip dcs
+ + buildHexStr(1, 2) // set num_of_pages to 1
+ + buildHexStr(0, CB_UMTS_MESSAGE_PAGE_SIZE * 2)
+ + buildHexStr(CB_UMTS_MESSAGE_PAGE_SIZE, 2); // msg_info_length
+ promise = promise
+ .then(() => sendMultipleRawCbsToEmulatorAndWait([pdu]))
+ .then((aMessage) => verifyCBMessage(aMessage, aGsName));
+ });
+
+ return promise;
+}
+
+function testReceiving_UMTS_MessageCode() {
+ log("Test receiving UMTS Cell Broadcast - Message Code");
+
+ let promise = Promise.resolve();
+
+ // Message Code has 10 bits, and is ORed into a 16 bits 'serial' number. Here
+ // we test every single bit to verify the operation doesn't go wrong.
+ let messageCodes = [
+ 0x000, 0x001, 0x002, 0x004, 0x008, 0x010, 0x020, 0x040,
+ 0x080, 0x100, 0x200, 0x251
+ ];
+
+ let verifyCBMessage = (aMessage, aMsgCode) => {
+ is(aMessage.messageCode, aMsgCode, "aMessage.messageCode");
+ };
+
+ messageCodes.forEach(function(aMsgCode) {
+ let pdu = buildHexStr(CB_UMTS_MESSAGE_TYPE_CBS, 2) // msg_type
+ + buildHexStr(0, 4) // skip msg_id
+ + buildHexStr(((aMsgCode & 0x3FF) << 4), 4) // set SN
+ + buildHexStr(0, 2) // skip dcs
+ + buildHexStr(1, 2) // set num_of_pages to 1
+ + buildHexStr(0, CB_UMTS_MESSAGE_PAGE_SIZE * 2)
+ + buildHexStr(CB_UMTS_MESSAGE_PAGE_SIZE, 2); // msg_info_length
+ promise = promise
+ .then(() => sendMultipleRawCbsToEmulatorAndWait([pdu]))
+ .then((aMessage) => verifyCBMessage(aMessage, aMsgCode));
+ });
+
+ return promise;
+}
+
+function testReceiving_UMTS_MessageId() {
+ log("Test receiving UMTS Cell Broadcast - Message Identifier");
+
+ let promise = Promise.resolve();
+
+ // Message Identifier has 16 bits, but no bitwise operation is needed.
+ // Test some selected values only.
+ let messageIds = [
+ 0x0000, 0x0001, 0x0010, 0x0100, 0x1000, 0x1111, 0x8888, 0x8811,
+ ];
+
+ let verifyCBMessage = (aMessage, aMessageId) => {
+ is(aMessage.messageId, aMessageId, "aMessage.messageId");
+ ok(aMessage.etws == null, "aMessage.etws");
+ };
+
+ messageIds.forEach(function(aMessageId) {
+ let pdu = buildHexStr(CB_UMTS_MESSAGE_TYPE_CBS, 2) // msg_type
+ + buildHexStr((aMessageId & 0xFFFF), 4) // set msg_id
+ + buildHexStr(0, 4) // skip SN
+ + buildHexStr(0, 2) // skip dcs
+ + buildHexStr(1, 2) // set num_of_pages to 1
+ + buildHexStr(0, CB_UMTS_MESSAGE_PAGE_SIZE * 2)
+ + buildHexStr(CB_UMTS_MESSAGE_PAGE_SIZE, 2); // msg_info_length
+ promise = promise
+ .then(() => sendMultipleRawCbsToEmulatorAndWait([pdu]))
+ .then((aMessage) => verifyCBMessage(aMessage, aMessageId));
+ });
+
+ return promise;
+}
+
+function testReceiving_UMTS_Language_and_Body() {
+ log("Test receiving UMTS Cell Broadcast - Language & Body");
+
+ let promise = Promise.resolve();
+
+ let testDcs = [];
+ dcs = 0;
+ while (dcs <= 0xFF) {
+ try {
+ let dcsInfo = { dcs: dcs };
+ [ dcsInfo.encoding, dcsInfo.language,
+ dcsInfo.indicator, dcsInfo.messageClass ] = decodeGsmDataCodingScheme(dcs);
+ testDcs.push(dcsInfo);
+ } catch (e) {
+ // Unsupported coding group, skip.
+ let dcs = (dcs & PDU_DCS_CODING_GROUP_BITS) + 0x10;
+ }
+ dcs++;
+ }
+
+ let verifyCBMessage = (aMessage, aDcsInfo) => {
+ if (aDcsInfo.language) {
+ is(aMessage.language, aDcsInfo.language, "aMessage.language");
+ } else if (aDcsInfo.indicator) {
+ is(aMessage.language, "@@", "aMessage.language");
+ } else {
+ ok(aMessage.language == null, "aMessage.language");
+ }
+
+ switch (aDcsInfo.encoding) {
+ case PDU_DCS_MSG_CODING_7BITS_ALPHABET:
+ is(aMessage.body,
+ aDcsInfo.indicator ? DUMMY_BODY_7BITS_IND : DUMMY_BODY_7BITS,
+ "aMessage.body");
+ break;
+ case PDU_DCS_MSG_CODING_8BITS_ALPHABET:
+ ok(aMessage.body == null, "aMessage.body");
+ break;
+ case PDU_DCS_MSG_CODING_16BITS_ALPHABET:
+ is(aMessage.body,
+ aDcsInfo.indicator ? DUMMY_BODY_UCS2_IND : DUMMY_BODY_UCS2,
+ "aMessage.body");
+ break;
+ }
+
+ is(aMessage.messageClass, aDcsInfo.messageClass, "aMessage.messageClass");
+ };
+
+ testDcs.forEach(function(aDcsInfo) {
+ let pdu = buildHexStr(CB_UMTS_MESSAGE_TYPE_CBS, 2) // msg_type
+ + buildHexStr(0, 4) // skip msg_id
+ + buildHexStr(0, 4) // skip SN
+ + buildHexStr(aDcsInfo.dcs, 2) // set dcs
+ + buildHexStr(1, 2) // set num_of_pages to 1
+ + buildHexStr(0, CB_UMTS_MESSAGE_PAGE_SIZE * 2)
+ + buildHexStr(CB_UMTS_MESSAGE_PAGE_SIZE, 2); // msg_info_length
+ promise = promise
+ .then(() => sendMultipleRawCbsToEmulatorAndWait([pdu]))
+ .then((aMessage) => verifyCBMessage(aMessage, aDcsInfo));
+ });
+
+ return promise;
+}
+
+function testReceiving_UMTS_Timestamp() {
+ log("Test receiving UMTS Cell Broadcast - Timestamp");
+
+ let verifyCBMessage = (aMessage) => {
+ // Cell Broadcast messages do not contain a timestamp field (however, ETWS
+ // does). We only check the timestamp doesn't go too far (60 seconds) here.
+ let msMessage = aMessage.timestamp;
+ let msNow = Date.now();
+ ok(Math.abs(msMessage - msNow) < (1000 * 60), "aMessage.timestamp");
+ };
+
+ // Here we use a single UMTS message for test.
+ let pdu = buildHexStr(CB_UMTS_MESSAGE_TYPE_CBS, 2) // msg_type
+ + buildHexStr(0, 10) // skip msg_id, sn, dcs
+ + buildHexStr(1, 2) // set num_of_pages to 1
+ + buildHexStr(0, CB_UMTS_MESSAGE_PAGE_SIZE * 2)
+ + buildHexStr(CB_UMTS_MESSAGE_PAGE_SIZE, 2); // msg_info_length
+
+ return sendMultipleRawCbsToEmulatorAndWait([pdu])
+ .then((aMessage) => verifyCBMessage(aMessage));
+}
+
+function testReceiving_UMTS_WarningType() {
+ log("Test receiving UMTS Cell Broadcast - Warning Type");
+
+ let promise = Promise.resolve();
+
+ let messageIds = [];
+ for (let i = CB_GSM_MESSAGEID_ETWS_BEGIN; i <= CB_GSM_MESSAGEID_ETWS_END; i++) {
+ messageIds.push(i);
+ }
+
+ let verifyCBMessage = (aMessage, aMessageId) => {
+ is(aMessage.messageId, aMessageId, "aMessage.messageId");
+ ok(aMessage.etws != null, "aMessage.etws");
+
+ let offset = aMessageId - CB_GSM_MESSAGEID_ETWS_BEGIN;
+ if (offset < CB_ETWS_WARNING_TYPE_NAMES.length) {
+ is(aMessage.etws.warningType, CB_ETWS_WARNING_TYPE_NAMES[offset],
+ "aMessage.etws.warningType");
+ } else {
+ ok(aMessage.etws.warningType == null, "aMessage.etws.warningType");
+ }
+ };
+
+ messageIds.forEach(function(aMessageId) {
+ let pdu = buildHexStr(CB_UMTS_MESSAGE_TYPE_CBS, 2) // msg_type
+ + buildHexStr((aMessageId & 0xFFFF), 4) // set msg_id
+ + buildHexStr(0, 4) // skip SN
+ + buildHexStr(0, 2) // skip dcs
+ + buildHexStr(1, 2) // set num_of_pages to 1
+ + buildHexStr(0, CB_UMTS_MESSAGE_PAGE_SIZE * 2)
+ + buildHexStr(CB_UMTS_MESSAGE_PAGE_SIZE, 2); // msg_info_length
+ promise = promise
+ .then(() => sendMultipleRawCbsToEmulatorAndWait([pdu]))
+ .then((aMessage) => verifyCBMessage(aMessage, aMessageId));
+ });
+
+ return promise;
+}
+
+function testReceiving_UMTS_EmergencyUserAlert() {
+ log("Test receiving UMTS Cell Broadcast - Emergency User Alert");
+
+ let promise = Promise.resolve();
+
+ let emergencyUserAlertMasks = [0x2000, 0x0000];
+
+ let verifyCBMessage = (aMessage, aMask) => {
+ is(aMessage.messageId, CB_GSM_MESSAGEID_ETWS_BEGIN, "aMessage.messageId");
+ ok(aMessage.etws != null, "aMessage.etws");
+ is(aMessage.etws.emergencyUserAlert, aMask != 0, "aMessage.etws.emergencyUserAlert");
+ };
+
+ emergencyUserAlertMasks.forEach(function(aMask) {
+ let pdu = buildHexStr(CB_UMTS_MESSAGE_TYPE_CBS, 2) // msg_type
+ + buildHexStr(CB_GSM_MESSAGEID_ETWS_BEGIN, 4) // set msg_id
+ + buildHexStr(aMask, 4) // set SN
+ + buildHexStr(0, 2) // skip dcs
+ + buildHexStr(1, 2) // set num_of_pages to 1
+ + buildHexStr(0, CB_UMTS_MESSAGE_PAGE_SIZE * 2)
+ + buildHexStr(CB_UMTS_MESSAGE_PAGE_SIZE, 2); // msg_info_length
+ promise = promise
+ .then(() => sendMultipleRawCbsToEmulatorAndWait([pdu]))
+ .then((aMessage) => verifyCBMessage(aMessage, aMask));
+ });
+
+ return promise;
+}
+
+function testReceiving_UMTS_Popup() {
+ log("Test receiving UMTS Cell Broadcast - Popup");
+
+ let promise = Promise.resolve();
+
+ let popupMasks = [0x1000, 0x0000];
+
+ let verifyCBMessage = (aMessage, aMask) => {
+ is(aMessage.messageId, CB_GSM_MESSAGEID_ETWS_BEGIN, "aMessage.messageId");
+ ok(aMessage.etws != null, "aMessage.etws");
+ is(aMessage.etws.popup, aMask != 0, "aMessage.etws.popup");
+ };
+
+ popupMasks.forEach(function(aMask) {
+ let pdu = buildHexStr(CB_UMTS_MESSAGE_TYPE_CBS, 2) // msg_type
+ + buildHexStr(CB_GSM_MESSAGEID_ETWS_BEGIN, 4) // set msg_id
+ + buildHexStr(aMask, 4) // set SN
+ + buildHexStr(0, 2) // skip dcs
+ + buildHexStr(1, 2) // set num_of_pages to 1
+ + buildHexStr(0, CB_UMTS_MESSAGE_PAGE_SIZE * 2)
+ + buildHexStr(CB_UMTS_MESSAGE_PAGE_SIZE, 2); // msg_info_length
+ promise = promise
+ .then(() => sendMultipleRawCbsToEmulatorAndWait([pdu]))
+ .then((aMessage) => verifyCBMessage(aMessage, aMask));
+ });
+
+ return promise;
+}
+
+function testReceiving_UMTS_Multipart() {
+ log("Test receiving UMTS Cell Broadcast - Multipart Messages");
+
+ let promise = Promise.resolve();
+
+ // According to 9.4.2.2.5 CB Data in TS 23.041,
+ // Number-of-Pages is equal to or less than 15.
+ // However, the size of out_buff of android modem in emulator is fixed to 1024.
+ // The maximal number of CBS pages we can test is limited to 6.
+ // Another xpc shell test case in ril_worker will address this instead.
+ let numOfPages = [1, 2, 3, 4, 5, 6];
+
+ let verifyCBMessage = (aMessage, aNumOfPages) => {
+ is(aMessage.body.length, (aNumOfPages * CB_MAX_CONTENT_PER_PAGE_7BIT),
+ "aMessage.body");
+ };
+
+ numOfPages.forEach(function(aNumOfPages) {
+ let pdu = buildHexStr(CB_UMTS_MESSAGE_TYPE_CBS, 2) // msg_type
+ + buildHexStr(0, 4) // skip msg_id
+ + buildHexStr(0, 4) // skip SN
+ + buildHexStr(0, 2) // skip dcs
+ + buildHexStr(aNumOfPages, 2); // set num_of_pages
+ for (let i = 1; i <= aNumOfPages; i++) {
+ pdu = pdu + buildHexStr(0, CB_UMTS_MESSAGE_PAGE_SIZE * 2)
+ + buildHexStr(CB_UMTS_MESSAGE_PAGE_SIZE, 2); // msg_info_length
+ }
+ promise = promise
+ .then(() => sendMultipleRawCbsToEmulatorAndWait([pdu]))
+ .then((aMessage) => verifyCBMessage(aMessage, aNumOfPages));
+ });
+
+ return promise;
+}
+
+function testReceiving_UMTS_PaddingCharacters() {
+ log("Test receiving UMTS Cell Broadcast - Padding Characters <CR>");
+
+ let promise = Promise.resolve();
+
+ let testContents = [
+ { pdu:
+ // CB PDU with GSM 7bit encoded text of
+ // "The quick brown fox jumps over the lazy dog
+ // \r\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r
+ // \r\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r
+ // \r\r\r\r\r\r\r\r"
+ buildHexStr(CB_UMTS_MESSAGE_TYPE_CBS, 2) + // msg_type
+ buildHexStr(0, 4) + // skip msg_id
+ buildHexStr(0, 4) + // skip SN
+ buildHexStr(0, 2) + // set dcs
+ buildHexStr(1, 2) + // set num_of_pages to 1
+ "54741914AFA7C76B9058FEBEBB41E637" +
+ "1EA4AEB7E173D0DB5E9683E8E832881D" +
+ "D6E741E4F7B9D168341A8D46A3D16834" +
+ "1A8D46A3D168341A8D46A3D168341A8D" +
+ "46A3D168341A8D46A3D168341A8D46A3" +
+ "D100" +
+ buildHexStr(CB_UMTS_MESSAGE_PAGE_SIZE, 2), // msg_info_length
+ text:
+ "The quick brown fox jumps over the lazy dog"
+ },
+ { pdu:
+ // CB PDU with UCS2 encoded text of
+ // "The quick brown fox jumps over\r\r\r\r\r\r\r\r\r\r\r"
+ buildHexStr(CB_UMTS_MESSAGE_TYPE_CBS, 2) + // msg_type
+ buildHexStr(0, 4) + // skip msg_id
+ buildHexStr(0, 4) + // skip SN
+ buildHexStr(72, 2) + // set dcs
+ buildHexStr(1, 2) + // set num_of_pages to 1
+ "00540068006500200071007500690063" +
+ "006b002000620072006f0077006e0020" +
+ "0066006f00780020006a0075006d0070" +
+ "00730020006f007600650072000D000D" +
+ "000D000D000D000D000D000D000D000D" +
+ "000D" +
+ buildHexStr(CB_UMTS_MESSAGE_PAGE_SIZE, 2), // msg_info_length
+ text:
+ "The quick brown fox jumps over"
+ }
+ ];
+
+ let verifyCBMessage = (aMessage, aText) => {
+ is(aMessage.body, aText, "aMessage.body");
+ };
+
+ testContents.forEach(function(aTestContent) {
+ promise = promise
+ .then(() => sendMultipleRawCbsToEmulatorAndWait([aTestContent.pdu]))
+ .then((aMessage) => verifyCBMessage(aMessage, aTestContent.text));
+ });
+
+ return promise;
+}
+
+function testReceiving_UMTS_MessageInformationLength() {
+ log("Test receiving UMTS Cell Broadcast - Message Information Length");
+
+ let testText = "The quick brown fox jumps over the lazy dog";
+
+ let verifyCBMessage = (aMessage) => {
+ is(aMessage.body, testText, "aMessage.body");
+ };
+
+ // CB PDU with GSM 7bit encoded text of
+ // "The quick brown fox jumps over the lazy dog
+ // \r\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r
+ // \r\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r
+ // \r\r\r\r\r\r\r\r"
+ // We set msg_info_length to the number of used octets.
+ let pdu = buildHexStr(CB_UMTS_MESSAGE_TYPE_CBS, 2) // msg_type
+ + buildHexStr(0, 4) // skip msg_id
+ + buildHexStr(0, 4) // skip SN
+ + buildHexStr(0, 2) // set dcs
+ + buildHexStr(1, 2) // set num_of_pages to 1
+ + "54741914AFA7C76B9058FEBEBB41E637"
+ + "1EA4AEB7E173D0DB5E9683E8E832881D"
+ + "D6E741E4F7B9D168341A8D46A3D16834"
+ + "1A8D46A3D168341A8D46A3D168341A8D"
+ + "46A3D168341A8D46A3D168341A8D46A3"
+ + "D100"
+ + buildHexStr(Math.ceil(testText.length * 7 / 8), 2); // msg_info_length
+
+ return sendMultipleRawCbsToEmulatorAndWait([pdu])
+ .then((aMessage) => verifyCBMessage(aMessage));
+}
+
+startTestCommon(function testCaseMain() {
+ return testReceiving_UMTS_MessageAttributes()
+ .then(() => testReceiving_UMTS_GeographicalScope())
+ .then(() => testReceiving_UMTS_MessageCode())
+ .then(() => testReceiving_UMTS_MessageId())
+ .then(() => testReceiving_UMTS_Language_and_Body())
+ .then(() => testReceiving_UMTS_Timestamp())
+ .then(() => testReceiving_UMTS_WarningType())
+ .then(() => testReceiving_UMTS_EmergencyUserAlert())
+ .then(() => testReceiving_UMTS_Popup())
+ .then(() => testReceiving_UMTS_Multipart())
+ .then(() => testReceiving_UMTS_PaddingCharacters())
+ .then(() => testReceiving_UMTS_MessageInformationLength());
+});
--- a/dom/events/EventStateManager.cpp
+++ b/dom/events/EventStateManager.cpp
@@ -2490,17 +2490,17 @@ EventStateManager::DoScrollText(nsIScrol
break;
default:
MOZ_CRASH("Invalid scrollType value comes");
}
nsIntPoint overflow;
aScrollableFrame->ScrollBy(actualDevPixelScrollAmount,
nsIScrollableFrame::DEVICE_PIXELS,
- mode, &overflow, origin);
+ mode, &overflow, origin, aEvent->isMomentum);
if (!scrollFrameWeak.IsAlive()) {
// If the scroll causes changing the layout, we can think that the event
// has been completely consumed by the content. Then, users probably don't
// want additional action.
aEvent->overflowDeltaX = aEvent->overflowDeltaY = 0;
} else if (isDeltaModePixel) {
aEvent->overflowDeltaX = overflow.x;
--- a/dom/fetch/Headers.cpp
+++ b/dom/fetch/Headers.cpp
@@ -3,16 +3,18 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "mozilla/dom/Headers.h"
#include "mozilla/ErrorResult.h"
#include "mozilla/dom/UnionTypes.h"
+#include "mozilla/dom/WorkerPrivate.h"
+#include "mozilla/Preferences.h"
#include "nsCharSeparatedTokenizer.h"
#include "nsContentUtils.h"
#include "nsDOMString.h"
#include "nsNetUtil.h"
#include "nsPIDOMWindow.h"
#include "nsReadableUtils.h"
@@ -24,16 +26,42 @@ NS_IMPL_CYCLE_COLLECTING_RELEASE(Headers
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(Headers, mOwner)
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(Headers)
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
NS_INTERFACE_MAP_ENTRY(nsISupports)
NS_INTERFACE_MAP_END
// static
+bool
+Headers::PrefEnabled(JSContext* aCx, JSObject* aObj)
+{
+ using mozilla::dom::workers::WorkerPrivate;
+ using mozilla::dom::workers::GetWorkerPrivateFromContext;
+
+ if (NS_IsMainThread()) {
+ static bool sPrefCacheInit = false;
+ static bool sPrefEnabled = false;
+ if (sPrefCacheInit) {
+ return sPrefEnabled;
+ }
+ Preferences::AddBoolVarCache(&sPrefEnabled, "dom.fetch.enabled");
+ sPrefCacheInit = true;
+ return sPrefEnabled;
+ }
+
+ WorkerPrivate* workerPrivate = GetWorkerPrivateFromContext(aCx);
+ if (!workerPrivate) {
+ return false;
+ }
+
+ return workerPrivate->DOMFetchEnabled();
+}
+
+// static
already_AddRefed<Headers>
Headers::Constructor(const GlobalObject& aGlobal,
const Optional<HeadersOrByteStringSequenceSequenceOrByteStringMozMap>& aInit,
ErrorResult& aRv)
{
nsRefPtr<Headers> headers = new Headers(aGlobal.GetAsSupports());
if (!aInit.WasPassed()) {
--- a/dom/fetch/Headers.h
+++ b/dom/fetch/Headers.h
@@ -49,16 +49,18 @@ private:
public:
explicit Headers(nsISupports* aOwner, HeadersGuardEnum aGuard = HeadersGuardEnum::None)
: mOwner(aOwner)
, mGuard(aGuard)
{
SetIsDOMBinding();
}
+ static bool PrefEnabled(JSContext* cx, JSObject* obj);
+
static already_AddRefed<Headers>
Constructor(const GlobalObject& aGlobal,
const Optional<HeadersOrByteStringSequenceSequenceOrByteStringMozMap>& aInit,
ErrorResult& aRv);
void Append(const nsACString& aName, const nsACString& aValue,
ErrorResult& aRv);
void Delete(const nsACString& aName, ErrorResult& aRv);
--- a/dom/fetch/moz.build
+++ b/dom/fetch/moz.build
@@ -7,11 +7,15 @@
EXPORTS.mozilla.dom += [
'Headers.h',
]
UNIFIED_SOURCES += [
'Headers.cpp',
]
+LOCAL_INCLUDES += [
+ '../workers',
+]
+
FAIL_ON_WARNINGS = True
MSVC_ENABLE_PGO = True
FINAL_LIBRARY = 'xul'
--- a/dom/imptests/html/html/browsers/the-window-object/test_window-properties.html
+++ b/dom/imptests/html/html/browsers/the-window-object/test_window-properties.html
@@ -1,17 +1,17 @@
<!doctype html>
<meta charset=utf-8>
<title>Properties of the window object</title>
-<link rel="author" title="Ms2ger" href="ms2ger@gmail.com">
+<link rel="author" title="Ms2ger" href="mailto:Ms2ger@gmail.com">
<link rel="help" href="http://ecma-international.org/ecma-262/5.1/#sec-15.1">
-<link rel="help" href="http://dev.w3.org/2006/webapi/WebIDL/#interface-prototype-object">
-<link rel="help" href="http://dev.w3.org/2006/webapi/WebIDL/#es-attributes">
-<link rel="help" href="http://dev.w3.org/2006/webapi/WebIDL/#es-operations">
-<link rel="help" href="http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#eventtarget">
+<link rel="help" href="http://heycam.github.io/webidl/#interface-prototype-object">
+<link rel="help" href="http://heycam.github.io/webidl/#es-attributes">
+<link rel="help" href="http://heycam.github.io/webidl/#es-operations">
+<link rel="help" href="http://dom.spec.whatwg.org/#eventtarget">
<link rel="help" href="http://www.whatwg.org/html/#window">
<link rel="help" href="http://www.whatwg.org/html/#windowtimers">
<link rel="help" href="http://www.whatwg.org/html/#windowbase64">
<link rel="help" href="http://www.whatwg.org/html/#windowsessionstorage">
<link rel="help" href="http://www.whatwg.org/html/#windowlocalstorage">
<link rel="help" href="https://dvcs.w3.org/hg/editing/raw-file/tip/editing.html#dom-window-getselection">
<link rel="help" href="http://dev.w3.org/csswg/cssom/#widl-def-Window">
<link rel="help" href="http://dev.w3.org/csswg/cssom-view/#widl-def-Window">
@@ -59,17 +59,17 @@ var methods = [
"stop",
"focus",
"blur",
"open",
"alert",
"confirm",
"prompt",
"print",
- "showModalDialog",
+ // See below: "showModalDialog",
"postMessage",
// WindowBase64
"btoa",
"atob",
// WindowTimers
"setTimeout",
@@ -85,16 +85,22 @@ var methods = [
// CSSOM-View
"matchMedia",
"scroll",
"scrollTo",
"scrollBy"
];
+// We would like to remove showModalDialog from the platform,
+// see <https://www.w3.org/Bugs/Public/show_bug.cgi?id=26437>.
+if ("showModalDialog" in window) {
+ methods.push("showModalDialog");
+}
+
var readonlyAttributes = [
"history",
"parent",
"frameElement",
"navigator",
"external",
"applicationCache",
--- a/dom/ipc/ContentChild.cpp
+++ b/dom/ipc/ContentChild.cpp
@@ -913,17 +913,17 @@ ContentChild::AllocPBackgroundChild(Tran
bool
ContentChild::RecvSetProcessSandbox()
{
// We may want to move the sandbox initialization somewhere else
// at some point; see bug 880808.
#if defined(MOZ_CONTENT_SANDBOX)
#if defined(XP_LINUX)
- SetCurrentProcessSandbox();
+ SetContentProcessSandbox();
#elif defined(XP_WIN)
mozilla::SandboxTarget::Instance()->StartSandbox();
#endif
#endif
return true;
}
bool
--- a/dom/ipc/ContentParent.cpp
+++ b/dom/ipc/ContentParent.cpp
@@ -36,17 +36,16 @@
#include "mozilla/dom/asmjscache/AsmJSCache.h"
#include "mozilla/dom/Element.h"
#include "mozilla/dom/DataStoreService.h"
#include "mozilla/dom/ExternalHelperAppParent.h"
#include "mozilla/dom/PContentBridgeParent.h"
#include "mozilla/dom/PFileDescriptorSetParent.h"
#include "mozilla/dom/PCycleCollectWithLogsParent.h"
#include "mozilla/dom/PMemoryReportRequestParent.h"
-#include "mozilla/dom/power/PowerManagerService.h"
#include "mozilla/dom/DOMStorageIPC.h"
#include "mozilla/dom/bluetooth/PBluetoothParent.h"
#include "mozilla/dom/PFMRadioParent.h"
#include "mozilla/dom/devicestorage/DeviceStorageRequestParent.h"
#include "mozilla/dom/FileSystemRequestParent.h"
#include "mozilla/dom/GeolocationBinding.h"
#include "mozilla/dom/FileDescriptorSetParent.h"
#include "mozilla/dom/telephony/TelephonyParent.h"
@@ -79,17 +78,16 @@
#include "nsDOMFile.h"
#include "nsFrameMessageManager.h"
#include "nsHashPropertyBag.h"
#include "nsIAlertsService.h"
#include "nsIAppsService.h"
#include "nsIClipboard.h"
#include "nsICycleCollectorListener.h"
#include "nsIDOMGeoGeolocation.h"
-#include "mozilla/dom/WakeLock.h"
#include "nsIDOMWindow.h"
#include "nsIExternalProtocolService.h"
#include "nsIGfxInfo.h"
#include "nsIIdleService.h"
#include "nsIJSRuntimeService.h"
#include "nsIMemoryInfoDumper.h"
#include "nsIMemoryReporter.h"
#include "nsIMozBrowserFrame.h"
@@ -180,17 +178,16 @@ using namespace mozilla::system;
static NS_DEFINE_CID(kCClipboardCID, NS_CLIPBOARD_CID);
static const char* sClipboardTextFlavors[] = { kUnicodeMime };
using base::ChildPrivileges;
using base::KillProcess;
using namespace mozilla::dom::bluetooth;
using namespace mozilla::dom::devicestorage;
using namespace mozilla::dom::indexedDB;
-using namespace mozilla::dom::power;
using namespace mozilla::dom::mobilemessage;
using namespace mozilla::dom::telephony;
using namespace mozilla::hal;
using namespace mozilla::ipc;
using namespace mozilla::layers;
using namespace mozilla::net;
using namespace mozilla::jsipc;
using namespace mozilla::widget;
@@ -834,16 +831,105 @@ ContentParent::AnswerBridgeToChildProces
return PContentBridge::Bridge(this, cp);
} else {
// You can't bridge to a process you didn't open!
KillHard();
return false;
}
}
+namespace {
+
+class SystemMessageHandledListener MOZ_FINAL
+ : public nsITimerCallback
+ , public LinkedListElement<SystemMessageHandledListener>
+{
+public:
+ NS_DECL_ISUPPORTS
+
+ SystemMessageHandledListener() {}
+
+ static void OnSystemMessageHandled()
+ {
+ if (!sListeners) {
+ return;
+ }
+
+ SystemMessageHandledListener* listener = sListeners->popFirst();
+ if (!listener) {
+ return;
+ }
+
+ // Careful: ShutDown() may delete |this|.
+ listener->ShutDown();
+ }
+
+ void Init(ContentParent* aContentParent)
+ {
+ MOZ_ASSERT(!mContentParent);
+ MOZ_ASSERT(!mTimer);
+
+ // mTimer keeps a strong reference to |this|. When this object's
+ // destructor runs, it will remove itself from the LinkedList.
+
+ if (!sListeners) {
+ sListeners = new LinkedList<SystemMessageHandledListener>();
+ ClearOnShutdown(&sListeners);
+ }
+ sListeners->insertBack(this);
+
+ mContentParent = aContentParent;
+
+ mTimer = do_CreateInstance("@mozilla.org/timer;1");
+
+ uint32_t timeoutSec =
+ Preferences::GetInt("dom.ipc.systemMessageCPULockTimeoutSec", 30);
+ mTimer->InitWithCallback(this, timeoutSec * 1000,
+ nsITimer::TYPE_ONE_SHOT);
+ }
+
+ NS_IMETHOD Notify(nsITimer* aTimer)
+ {
+ // Careful: ShutDown() may delete |this|.
+ ShutDown();
+ return NS_OK;
+ }
+
+private:
+ ~SystemMessageHandledListener() {}
+
+ static StaticAutoPtr<LinkedList<SystemMessageHandledListener> > sListeners;
+
+ void ShutDown()
+ {
+ ProcessPriorityManager::ResetProcessPriority(mContentParent, false);
+
+ nsRefPtr<SystemMessageHandledListener> kungFuDeathGrip = this;
+
+ if (mContentParent) {
+ mContentParent = nullptr;
+ }
+ if (mTimer) {
+ mTimer->Cancel();
+ mTimer = nullptr;
+ }
+ }
+
+ nsRefPtr<ContentParent> mContentParent;
+ nsCOMPtr<nsITimer> mTimer;
+};
+
+StaticAutoPtr<LinkedList<SystemMessageHandledListener> >
+ SystemMessageHandledListener::sListeners;
+
+NS_IMPL_ISUPPORTS(SystemMessageHandledListener,
+ nsITimerCallback)
+
+} // anonymous namespace
+
/*static*/ TabParent*
ContentParent::CreateBrowserOrApp(const TabContext& aContext,
Element* aFrameElement,
ContentParent* aOpenerContentParent)
{
if (!sCanLaunchSubprocesses) {
return nullptr;
}
@@ -1038,17 +1124,30 @@ ContentParent::CreateBrowserOrApp(const
aFrameElement,
aOpenerContentParent);
}
// Otherwise just give up.
return nullptr;
}
- p->MaybeTakeCPUWakeLock(aFrameElement);
+ // Request a higher priority above BACKGROUND if the child process is
+ // "critical" and probably has system messages coming soon. (A CPU wake lock
+ // may already be controlled by the B2G process in SystemMessageInternal.js
+ // for message handling.) This privilege is revoked once the message is
+ // delivered, or the grace period is up, whichever comes first.
+ nsCOMPtr<nsIMozBrowserFrame> browserFrame = do_QueryInterface(aFrameElement);
+ if (browserFrame && browserFrame->GetIsExpectingSystemMessage()) {
+ ProcessPriorityManager::ResetProcessPriority(p, true);
+
+ // This object's Init() function keeps it alive.
+ nsRefPtr<SystemMessageHandledListener> listener =
+ new SystemMessageHandledListener();
+ listener->Init(p);
+ }
return static_cast<TabParent*>(browser);
}
void
ContentParent::GetAll(nsTArray<ContentParent*>& aArray)
{
aArray.Clear();
@@ -1102,127 +1201,16 @@ ContentParent::Init()
unused << SendActivateA11y();
}
#endif
DebugOnly<FileUpdateDispatcher*> observer = FileUpdateDispatcher::GetSingleton();
NS_ASSERTION(observer, "FileUpdateDispatcher is null");
}
-namespace {
-
-class SystemMessageHandledListener MOZ_FINAL
- : public nsITimerCallback
- , public LinkedListElement<SystemMessageHandledListener>
-{
-public:
- NS_DECL_ISUPPORTS
-
- SystemMessageHandledListener() {}
-
- static void OnSystemMessageHandled()
- {
- if (!sListeners) {
- return;
- }
-
- SystemMessageHandledListener* listener = sListeners->popFirst();
- if (!listener) {
- return;
- }
-
- // Careful: ShutDown() may delete |this|.
- listener->ShutDown();
- }
-
- void Init(WakeLock* aWakeLock)
- {
- MOZ_ASSERT(!mWakeLock);
- MOZ_ASSERT(!mTimer);
-
- // mTimer keeps a strong reference to |this|. When this object's
- // destructor runs, it will remove itself from the LinkedList.
-
- if (!sListeners) {
- sListeners = new LinkedList<SystemMessageHandledListener>();
- ClearOnShutdown(&sListeners);
- }
- sListeners->insertBack(this);
-
- mWakeLock = aWakeLock;
-
- mTimer = do_CreateInstance("@mozilla.org/timer;1");
-
- uint32_t timeoutSec =
- Preferences::GetInt("dom.ipc.systemMessageCPULockTimeoutSec", 30);
- mTimer->InitWithCallback(this, timeoutSec * 1000,
- nsITimer::TYPE_ONE_SHOT);
- }
-
- NS_IMETHOD Notify(nsITimer* aTimer)
- {
- // Careful: ShutDown() may delete |this|.
- ShutDown();
- return NS_OK;
- }
-
-private:
- ~SystemMessageHandledListener() {}
-
- static StaticAutoPtr<LinkedList<SystemMessageHandledListener> > sListeners;
-
- void ShutDown()
- {
- nsRefPtr<SystemMessageHandledListener> kungFuDeathGrip = this;
-
- ErrorResult rv;
- mWakeLock->Unlock(rv);
-
- if (mTimer) {
- mTimer->Cancel();
- mTimer = nullptr;
- }
- }
-
- nsRefPtr<WakeLock> mWakeLock;
- nsCOMPtr<nsITimer> mTimer;
-};
-
-StaticAutoPtr<LinkedList<SystemMessageHandledListener> >
- SystemMessageHandledListener::sListeners;
-
-NS_IMPL_ISUPPORTS(SystemMessageHandledListener,
- nsITimerCallback)
-
-} // anonymous namespace
-
-void
-ContentParent::MaybeTakeCPUWakeLock(Element* aFrameElement)
-{
- // Take the CPU wake lock on behalf of this processs if it's expecting a
- // system message. We'll release the CPU lock once the message is
- // delivered, or after some period of time, which ever comes first.
-
- nsCOMPtr<nsIMozBrowserFrame> browserFrame =
- do_QueryInterface(aFrameElement);
- if (!browserFrame ||
- !browserFrame->GetIsExpectingSystemMessage()) {
- return;
- }
-
- nsRefPtr<PowerManagerService> pms = PowerManagerService::GetInstance();
- nsRefPtr<WakeLock> lock =
- pms->NewWakeLockOnBehalfOfProcess(NS_LITERAL_STRING("cpu"), this);
-
- // This object's Init() function keeps it alive.
- nsRefPtr<SystemMessageHandledListener> listener =
- new SystemMessageHandledListener();
- listener->Init(lock);
-}
-
bool
ContentParent::SetPriorityAndCheckIsAlive(ProcessPriority aPriority)
{
ProcessPriorityManager::SetProcessPriority(this, aPriority);
// Now that we've set this process's priority, check whether the process is
// still alive. Hopefully we've set the priority to FOREGROUND*, so the
// process won't unexpectedly crash after this point!
--- a/dom/ipc/ContentParent.h
+++ b/dom/ipc/ContentParent.h
@@ -327,22 +327,16 @@ private:
void InitInternal(ProcessPriority aPriority,
bool aSetupOffMainThreadCompositing,
bool aSendRegisteredChrome);
virtual ~ContentParent();
void Init();
- // If the frame element indicates that the child process is "critical" and
- // has a pending system message, this function acquires the CPU wake lock on
- // behalf of the child. We'll release the lock when the system message is
- // handled or after a timeout, whichever comes first.
- void MaybeTakeCPUWakeLock(Element* aFrameElement);
-
// Set the child process's priority and then check whether the child is
// still alive. Returns true if the process is still alive, and false
// otherwise. If you pass a FOREGROUND* priority here, it's (hopefully)
// unlikely that the process will be killed after this point.
bool SetPriorityAndCheckIsAlive(hal::ProcessPriority aPriority);
// Transform a pre-allocated app process into a "real" app
// process, for the specified manifest URL.
--- a/dom/ipc/ProcessPriorityManager.cpp
+++ b/dom/ipc/ProcessPriorityManager.cpp
@@ -127,16 +127,22 @@ public:
/**
* This function implements ProcessPriorityManager::SetProcessPriority.
*/
void SetProcessPriority(ContentParent* aContentParent,
ProcessPriority aPriority,
uint32_t aBackgroundLRU = 0);
/**
+ * This function implements ProcessPriorityManager::ResetProcessPriority.
+ */
+ void ResetProcessPriority(ContentParent* aContentParent,
+ bool aHandleSystemMessage);
+
+ /**
* If a magic testing-only pref is set, notify the observer service on the
* given topic with the given data. This is used for testing
*/
void FireTestOnlyObserverNotification(const char* aTopic,
const nsACString& aData = EmptyCString());
/**
* Does some process, other than the one handled by aParticularManager, have
@@ -282,31 +288,34 @@ public:
uint32_t aBackgroundLRU = 0);
void SetPriorityNow(ProcessPriority aPriority,
ProcessCPUPriority aCPUPriority,
uint32_t aBackgroundLRU = 0);
void ShutDown();
+ void SetHandlesSystemMessage(bool aHandlesSystemMessage);
+
private:
void FireTestOnlyObserverNotification(
const char* aTopic,
const nsACString& aData = EmptyCString());
void FireTestOnlyObserverNotification(
const char* aTopic,
const char* aData = nullptr);
ContentParent* mContentParent;
uint64_t mChildID;
ProcessPriority mPriority;
ProcessCPUPriority mCPUPriority;
bool mHoldsCPUWakeLock;
bool mHoldsHighPriorityWakeLock;
+ bool mHandlesSystemMessage;
/**
* Used to implement NameWithComma().
*/
nsAutoCString mNameWithComma;
nsCOMPtr<nsITimer> mResetPriorityTimer;
};
@@ -492,16 +501,27 @@ ProcessPriorityManagerImpl::SetProcessPr
{
MOZ_ASSERT(aContentParent);
nsRefPtr<ParticularProcessPriorityManager> pppm =
GetParticularProcessPriorityManager(aContentParent);
pppm->SetPriorityNow(aPriority, aBackgroundLRU);
}
void
+ProcessPriorityManagerImpl::ResetProcessPriority(ContentParent* aContentParent,
+ bool aHandleSystemMessage)
+{
+ MOZ_ASSERT(aContentParent);
+ nsRefPtr<ParticularProcessPriorityManager> pppm =
+ GetParticularProcessPriorityManager(aContentParent);
+ pppm->SetHandlesSystemMessage(aHandleSystemMessage);
+ pppm->ResetPriorityNow();
+}
+
+void
ProcessPriorityManagerImpl::ObserveContentParentCreated(
nsISupports* aContentParent)
{
// Do nothing; it's sufficient to get the PPPM. But assign to nsRefPtr so we
// don't leak the already_AddRefed object.
nsCOMPtr<nsIContentParent> cp = do_QueryInterface(aContentParent);
nsRefPtr<ParticularProcessPriorityManager> pppm =
GetParticularProcessPriorityManager(cp->AsContentParent());
@@ -642,16 +662,17 @@ NS_IMPL_ISUPPORTS(ParticularProcessPrior
ParticularProcessPriorityManager::ParticularProcessPriorityManager(
ContentParent* aContentParent)
: mContentParent(aContentParent)
, mChildID(aContentParent->ChildID())
, mPriority(PROCESS_PRIORITY_UNKNOWN)
, mCPUPriority(PROCESS_CPU_PRIORITY_NORMAL)
, mHoldsCPUWakeLock(false)
, mHoldsHighPriorityWakeLock(false)
+ , mHandlesSystemMessage(false)
{
MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_Default);
LOGP("Creating ParticularProcessPriorityManager.");
}
void
ParticularProcessPriorityManager::Init()
{
@@ -964,17 +985,17 @@ ProcessPriority
ParticularProcessPriorityManager::CurrentPriority()
{
return mPriority;
}
ProcessPriority
ParticularProcessPriorityManager::ComputePriority()
{
- if ((mHoldsCPUWakeLock || mHoldsHighPriorityWakeLock) &&
+ if ((mHandlesSystemMessage || mHoldsCPUWakeLock || mHoldsHighPriorityWakeLock) &&
HasAppType("critical")) {
return PROCESS_PRIORITY_FOREGROUND_HIGH;
}
bool isVisible = false;
const InfallibleTArray<PBrowserParent*>& browsers =
mContentParent->ManagedPBrowserParent();
for (uint32_t i = 0; i < browsers.Length(); i++) {
@@ -985,17 +1006,17 @@ ParticularProcessPriorityManager::Comput
}
if (isVisible) {
return HasAppType("inputmethod") ?
PROCESS_PRIORITY_FOREGROUND_KEYBOARD :
PROCESS_PRIORITY_FOREGROUND;
}
- if ((mHoldsCPUWakeLock || mHoldsHighPriorityWakeLock) &&
+ if ((mHandlesSystemMessage || mHoldsCPUWakeLock || mHoldsHighPriorityWakeLock) &&
IsExpectingSystemMessage()) {
return PROCESS_PRIORITY_BACKGROUND_PERCEIVABLE;
}
AudioChannelService* service = AudioChannelService::GetAudioChannelService();
if (service->ProcessContentOrNormalChannelIsActive(ChildID())) {
return PROCESS_PRIORITY_BACKGROUND_PERCEIVABLE;
}
@@ -1133,16 +1154,22 @@ ParticularProcessPriorityManager::ShutDo
if (mPriority == PROCESS_PRIORITY_BACKGROUND && !IsPreallocated()) {
ProcessPriorityManager::RemoveFromBackgroundLRUPool(mContentParent);
}
mContentParent = nullptr;
}
void
+ParticularProcessPriorityManager::SetHandlesSystemMessage(bool aHandlesSystemMessage)
+{
+ mHandlesSystemMessage = aHandlesSystemMessage;
+}
+
+void
ProcessPriorityManagerImpl::FireTestOnlyObserverNotification(
const char* aTopic,
const nsACString& aData /* = EmptyCString() */)
{
if (!Preferences::GetBool("dom.ipc.processPriorityManager.testMode")) {
return;
}
@@ -1469,16 +1496,29 @@ ProcessPriorityManager::SetProcessPriori
ProcessPriorityManagerImpl* singleton =
ProcessPriorityManagerImpl::GetSingleton();
if (singleton) {
singleton->SetProcessPriority(aContentParent, aPriority);
}
}
/* static */ void
+ProcessPriorityManager::ResetProcessPriority(ContentParent* aContentParent,
+ bool aHandleSystemMessage)
+{
+ MOZ_ASSERT(aContentParent);
+
+ ProcessPriorityManagerImpl* singleton =
+ ProcessPriorityManagerImpl::GetSingleton();
+ if (singleton) {
+ singleton->ResetProcessPriority(aContentParent, aHandleSystemMessage);
+ }
+}
+
+/* static */ void
ProcessPriorityManager::RemoveFromBackgroundLRUPool(
ContentParent* aContentParent)
{
MOZ_ASSERT(aContentParent);
BackgroundProcessLRUPool* singleton =
BackgroundProcessLRUPool::Singleton();
if (singleton) {
--- a/dom/ipc/ProcessPriorityManager.h
+++ b/dom/ipc/ProcessPriorityManager.h
@@ -55,16 +55,30 @@ public:
*
* Eventually whatever priority you set here can and probably will be
* overwritten by the process priority manager.
*/
static void SetProcessPriority(dom::ContentParent* aContentParent,
hal::ProcessPriority aPriority);
/**
+ * Reset the process priority of a given ContentParent's process in
+ * consideration of system message handling.
+ *
+ * Note that because this method takes a ContentParent*, you can only set the
+ * priority of your subprocesses. In fact, because we don't support nested
+ * content processes (bug 761935), you can only call this method from the
+ * main process.
+ *
+ * The process priority manager will determine a new appropriate priority.
+ */
+ static void ResetProcessPriority(dom::ContentParent* aContentParent,
+ bool aHandleSystemMessage);
+
+ /**
* Returns true iff this process's priority is FOREGROUND*.
*
* Note that because process priorities are set in the main process, it's
* possible for this method to return a stale value. So be careful about
* what you use this for.
*/
static bool CurrentProcessIsForeground();
--- a/dom/media/tests/mochitest/mochitest.ini
+++ b/dom/media/tests/mochitest/mochitest.ini
@@ -69,18 +69,17 @@ skip-if = buildapp == 'b2g' || os == 'an
[test_peerConnection_bug825703.html]
[test_peerConnection_bug827843.html]
skip-if = toolkit == 'gonk' # b2g(Bug 960442, video support for WebRTC is disabled on b2g)
[test_peerConnection_bug834153.html]
[test_peerConnection_bug835370.html]
[test_peerConnection_bug1013809.html]
skip-if = (toolkit == 'gonk' && debug) # b2g emulator seems to be too slow (Bug 1016498 and 1008080)
[test_peerConnection_bug1042791.html]
-skip-if = true # disabled until we can resolve plugin installation issues
-#skip-if = toolkit == 'gonk' || toolkit == 'android' # no openh264 on b2g/android
+skip-if = buildapp == 'b2g' || os == 'android' # bug 1043403
[test_peerConnection_close.html]
[test_peerConnection_errorCallbacks.html]
[test_peerConnection_offerRequiresReceiveAudio.html]
skip-if = toolkit == 'gonk' # b2g(Bug 960442, video support for WebRTC is disabled on b2g)
[test_peerConnection_offerRequiresReceiveVideo.html]
skip-if = toolkit == 'gonk' # b2g(Bug 960442, video support for WebRTC is disabled on b2g)
[test_peerConnection_offerRequiresReceiveVideoAudio.html]
skip-if = toolkit == 'gonk' # b2g(Bug 960442, video support for WebRTC is disabled on b2g)
--- a/dom/media/tests/mochitest/test_peerConnection_bug1042791.html
+++ b/dom/media/tests/mochitest/test_peerConnection_bug1042791.html
@@ -23,20 +23,20 @@
options.h264 = true;
test = new PeerConnectionTest(options);
test.setMediaConstraints([{video: true}], [{video: true}]);
test.chain.removeAfter("PC_LOCAL_CREATE_OFFER");
test.chain.append([[
"PC_LOCAL_VERIFY_H264_OFFER",
function (test) {
- ok(!test.pcLocal._last_offer.sdp.contains("profile-level-id=0x42e00c"),
- "H264 offer does not contain profile-level-id=0x42e00c");
- ok(test.pcLocal._last_offer.sdp.contains("profile-level-id=42e00c"),
- "H264 offer contains profile-level-id=42e00c");
+ ok(!test.pcLocal._last_offer.sdp.toLowerCase().contains("profile-level-id=0x42e0"),
+ "H264 offer does not contain profile-level-id=0x42e0");
+ ok(test.pcLocal._last_offer.sdp.toLowerCase().contains("profile-level-id=42e0"),
+ "H264 offer contains profile-level-id=42e0");
test.next();
}
]]);
test.run();
});
</script>
</pre>
--- a/dom/messages/SystemMessageInternal.js
+++ b/dom/messages/SystemMessageInternal.js
@@ -34,16 +34,26 @@ let kMaxPendingMessages;
try {
kMaxPendingMessages =
Services.prefs.getIntPref("dom.messages.maxPendingMessages");
} catch(e) {
// getIntPref throws when the pref is not set.
kMaxPendingMessages = 5;
}
+//Limit the duration to hold the CPU wake lock.
+let kCpuWakeLockTimeoutSec;
+try {
+ kCpuWakeLockTimeoutSec =
+ Services.prefs.getIntPref("dom.ipc.systemMessageCPULockTimeoutSec");
+} catch (e) {
+ // getIntPref throws when the pref is not set.
+ kCpuWakeLockTimeoutSec = 30;
+}
+
const kMessages =["SystemMessageManager:GetPendingMessages",
"SystemMessageManager:HasPendingMessages",
"SystemMessageManager:Register",
"SystemMessageManager:Unregister",
"SystemMessageManager:Message:Return:OK",
"SystemMessageManager:AskReadyToRegister",
"SystemMessageManager:HandleMessagesDone",
"child-process-shutdown"]
@@ -144,17 +154,17 @@ SystemMessageInternal.prototype = {
// Set a watchdog to avoid locking the CPU wake lock too long,
// because it'd exhaust the battery quickly which is very bad.
// This could probably happen if the app failed to launch or
// handle the system messages due to any unexpected reasons.
cpuWakeLock.timer.initWithCallback(function timerCb() {
debug("Releasing the CPU wake lock because the system messages " +
"were not handled by its registered page before time out.");
this._cancelCpuWakeLock(aPageKey);
- }.bind(this), 30000, Ci.nsITimer.TYPE_ONE_SHOT);
+ }.bind(this), kCpuWakeLockTimeoutSec * 1000, Ci.nsITimer.TYPE_ONE_SHOT);
},
_releaseCpuWakeLock: function _releaseCpuWakeLock(aPageKey, aHandledCount) {
let cpuWakeLock = this._cpuWakeLocks[aPageKey];
if (cpuWakeLock) {
cpuWakeLock.lockCount -= aHandledCount;
if (cpuWakeLock.lockCount <= 0) {
debug("Unlocking the CPU wake lock now that the system messages " +
--- a/dom/messages/SystemMessageManager.js
+++ b/dom/messages/SystemMessageManager.js
@@ -103,20 +103,18 @@ SystemMessageManager.prototype = {
handledCount: 1 });
aDispatcher.isHandling = false;
if (aDispatcher.messages.length > 0) {
this._dispatchMessage(aType, aDispatcher, aDispatcher.messages.shift());
} else {
// No more messages that need to be handled, we can notify the
- // ContentChild to release the CPU wake lock grabbed by the ContentParent
- // (i.e. NewWakeLockOnBehalfOfProcess()) and reset the process's priority.
- //
- // TODO: Bug 874353 - Remove SystemMessageHandledListener in ContentParent
+ // ContentChild to propogate the event, so that the ContentParent can
+ // reset the process's priority.
Services.obs.notifyObservers(/* aSubject */ null,
"handle-system-messages-done",
/* aData */ null);
}
},
mozSetMessageHandler: function(aType, aHandler) {
debug("set message handler for [" + aType + "] " + aHandler);
@@ -244,21 +242,18 @@ SystemMessageManager.prototype = {
// messages.length|), so the parent can release the CPU wake lock it took
// on our behalf.
cpmm.sendAsyncMessage("SystemMessageManager:HandleMessagesDone",
{ type: msg.type,
manifestURL: this._manifestURL,
pageURL: this._pageURL,
handledCount: messages.length });
- // We also need to notify the ContentChild to release the CPU wake lock
- // grabbed by the ContentParent (i.e. NewWakeLockOnBehalfOfProcess()) and
- // reset the process's priority.
- //
- // TODO: Bug 874353 - Remove SystemMessageHandledListener in ContentParent
+ // We also need to notify the ContentChild to propogate the event, so that
+ // the ContentParent can reset the process's priority.
Services.obs.notifyObservers(/* aSubject */ null,
"handle-system-messages-done",
/* aData */ null);
}
},
// nsIDOMGlobalPropertyInitializer implementation.
init: function(aWindow) {
--- a/dom/nfc/nsNfc.js
+++ b/dom/nfc/nsNfc.js
@@ -259,17 +259,26 @@ mozNfc.prototype = {
eventType = NFC_PEER_EVENT_LOST;
break;
default:
break;
}
return eventType;
},
+ hasDeadWrapper: function hasDeadWrapper() {
+ return Cu.isDeadWrapper(this._window) || Cu.isDeadWrapper(this.__DOM_IMPL__);
+ },
+
firePeerEvent: function firePeerEvent(evt, sessionToken) {
+ if (this.hasDeadWrapper()) {
+ dump("this._window or this.__DOM_IMPL__ is a dead wrapper.");
+ return;
+ }
+
let peerEvent = (NFC_PEER_EVENT_READY === evt) ? "peerready" : "peerlost";
let detail = {
"detail":sessionToken
};
let event = new this._window.CustomEvent(peerEvent, this._wrap(detail));
this.__DOM_IMPL__.dispatchEvent(event);
},
--- a/dom/plugins/base/nsNPAPIPluginInstance.cpp
+++ b/dom/plugins/base/nsNPAPIPluginInstance.cpp
@@ -1807,17 +1807,17 @@ nsNPAPIPluginInstance::CheckJavaC2PJSObj
// Due to the Java version being specified inconsistently across platforms
// check the version via the mimetype for choosing specific Java versions
nsCString javaVersion;
if (!GetJavaVersionFromMimetype(pluginTag, javaVersion)) {
return;
}
- mozilla::Version version = javaVersion.get();
+ mozilla::Version version(javaVersion.get());
if (version >= "1.7.0.4") {
return;
}
if (!haveCodeParam && version >= "1.6.0.34" && version < "1.7") {
return;
}
--- a/dom/promise/Promise.cpp
+++ b/dom/promise/Promise.cpp
@@ -1383,18 +1383,18 @@ PromiseWorkerProxy::GetWorkerPromise() c
return mWorkerPromise;
}
void
PromiseWorkerProxy::StoreISupports(nsISupports* aSupports)
{
MOZ_ASSERT(NS_IsMainThread());
- nsMainThreadPtrHandle<nsISupports> supports =
- new nsMainThreadPtrHolder<nsISupports>(aSupports);
+ nsMainThreadPtrHandle<nsISupports> supports(
+ new nsMainThreadPtrHolder<nsISupports>(aSupports));
mSupportsArray.AppendElement(supports);
}
void
PromiseWorkerProxy::RunCallback(JSContext* aCx,
JS::Handle<JS::Value> aValue,
RunCallbackFunc aFunc)
{
--- a/dom/system/gonk/NetworkManager.js
+++ b/dom/system/gonk/NetworkManager.js
@@ -28,17 +28,16 @@ XPCOMUtils.defineLazyGetter(this, "ppmm"
XPCOMUtils.defineLazyServiceGetter(this, "gDNSService",
"@mozilla.org/network/dns-service;1",
"nsIDNSService");
XPCOMUtils.defineLazyServiceGetter(this, "gNetworkService",
"@mozilla.org/network/service;1",
"nsINetworkService");
-const TOPIC_INTERFACE_STATE_CHANGED = "network-interface-state-changed";
const TOPIC_INTERFACE_REGISTERED = "network-interface-registered";
const TOPIC_INTERFACE_UNREGISTERED = "network-interface-unregistered";
const TOPIC_ACTIVE_CHANGED = "network-active-changed";
const TOPIC_MOZSETTINGS_CHANGED = "mozsettings-changed";
const TOPIC_PREF_CHANGED = "nsPref:changed";
const TOPIC_XPCOM_SHUTDOWN = "xpcom-shutdown";
const TOPIC_CONNECTION_STATE_CHANGED = "network-connection-state-changed";
const PREF_MANAGE_OFFLINE_STATUS = "network.gonk.manage-offline-status";
@@ -131,17 +130,16 @@ function defineLazyRegExp(obj, name, pat
}
/**
* This component watches for network interfaces changing state and then
* adjusts routes etc. accordingly.
*/
function NetworkManager() {
this.networkInterfaces = {};
- Services.obs.addObserver(this, TOPIC_INTERFACE_STATE_CHANGED, true);
Services.obs.addObserver(this, TOPIC_XPCOM_SHUTDOWN, false);
Services.obs.addObserver(this, TOPIC_MOZSETTINGS_CHANGED, false);
try {
this._manageOfflineStatus =
Services.prefs.getBoolPref(PREF_MANAGE_OFFLINE_STATUS);
} catch(ex) {
// Ignore.
@@ -211,115 +209,28 @@ NetworkManager.prototype = {
Ci.nsISupportsWeakReference,
Ci.nsIObserver,
Ci.nsISettingsServiceCallback]),
// nsIObserver
observe: function(subject, topic, data) {
switch (topic) {
- case TOPIC_INTERFACE_STATE_CHANGED:
- let network = subject.QueryInterface(Ci.nsINetworkInterface);
- debug("Network " + network.type + "/" + network.name +
- " changed state to " + network.state);
- switch (network.state) {
- case Ci.nsINetworkInterface.NETWORK_STATE_CONNECTED:
-#ifdef MOZ_B2G_RIL
- // Add host route for data calls
- if (this.isNetworkTypeMobile(network.type)) {
- gNetworkService.removeHostRoutes(network.name);
- gNetworkService.addHostRoute(network);
- }
- // Dun type is a special case where we add the default route to a
- // secondary table.
- if (network.type == Ci.nsINetworkInterface.NETWORK_TYPE_MOBILE_DUN) {
- this.setSecondaryDefaultRoute(network);
- }
-#endif
- // Remove pre-created default route and let setAndConfigureActive()
- // to set default route only on preferred network
- gNetworkService.removeDefaultRoute(network);
- this.setAndConfigureActive();
-#ifdef MOZ_B2G_RIL
- // Resolve and add extra host route. For example, mms proxy or mmsc.
- // IMPORTANT: The offline state of DNSService will be set implicitly in
- // setAndConfigureActive() by modifying Services.io.offline.
- // Always setExtraHostRoute() after setAndConfigureActive().
- this.setExtraHostRoute(network);
-
- // Update data connection when Wifi connected/disconnected
- if (network.type == Ci.nsINetworkInterface.NETWORK_TYPE_WIFI) {
- for (let i = 0; i < this.mRil.numRadioInterfaces; i++) {
- this.mRil.getRadioInterface(i).updateRILNetworkInterface();
- }
- }
-#endif
-
- this.onConnectionChanged(network);
-
- // Probing the public network accessibility after routing table is ready
- CaptivePortalDetectionHelper
- .notify(CaptivePortalDetectionHelper.EVENT_CONNECT, this.active);
- break;
- case Ci.nsINetworkInterface.NETWORK_STATE_DISCONNECTED:
-#ifdef MOZ_B2G_RIL
- // Remove host route for data calls
- if (this.isNetworkTypeMobile(network.type)) {
- gNetworkService.removeHostRoute(network);
- }
- // Remove extra host route. For example, mms proxy or mmsc.
- this.removeExtraHostRoute(network);
- // Remove secondary default route for dun.
- if (network.type == Ci.nsINetworkInterface.NETWORK_TYPE_MOBILE_DUN) {
- this.removeSecondaryDefaultRoute(network);
- }
-#endif
- // Remove routing table in /proc/net/route
- if (network.type == Ci.nsINetworkInterface.NETWORK_TYPE_WIFI) {
- gNetworkService.resetRoutingTable(network);
-#ifdef MOZ_B2G_RIL
- } else if (network.type == Ci.nsINetworkInterface.NETWORK_TYPE_MOBILE) {
- gNetworkService.removeDefaultRoute(network);
-#endif
- }
-
- // Abort ongoing captive portal detection on the wifi interface
- CaptivePortalDetectionHelper
- .notify(CaptivePortalDetectionHelper.EVENT_DISCONNECT, network);
- this.setAndConfigureActive();
-#ifdef MOZ_B2G_RIL
- // Update data connection when Wifi connected/disconnected
- if (network.type == Ci.nsINetworkInterface.NETWORK_TYPE_WIFI) {
- for (let i = 0; i < this.mRil.numRadioInterfaces; i++) {
- this.mRil.getRadioInterface(i).updateRILNetworkInterface();
- }
- }
-#endif
- break;
- }
-#ifdef MOZ_B2G_RIL
- // Notify outer modules like MmsService to start the transaction after
- // the configuration of the network interface is done.
- Services.obs.notifyObservers(network, TOPIC_CONNECTION_STATE_CHANGED,
- this.convertConnectionType(network));
-#endif
- break;
case TOPIC_MOZSETTINGS_CHANGED:
let setting = JSON.parse(data);
this.handle(setting.key, setting.value);
break;
case TOPIC_PREF_CHANGED:
this._manageOfflineStatus =
Services.prefs.getBoolPref(PREF_MANAGE_OFFLINE_STATUS);
debug(PREF_MANAGE_OFFLINE_STATUS + " has changed to " + this._manageOfflineStatus);
break;
case TOPIC_XPCOM_SHUTDOWN:
Services.obs.removeObserver(this, TOPIC_XPCOM_SHUTDOWN);
Services.obs.removeObserver(this, TOPIC_MOZSETTINGS_CHANGED);
- Services.obs.removeObserver(this, TOPIC_INTERFACE_STATE_CHANGED);
#ifdef MOZ_B2G_RIL
this.dunConnectTimer.cancel();
this.dunRetryTimer.cancel();
#endif
break;
}
},
@@ -392,16 +303,111 @@ NetworkManager.prototype = {
Cr.NS_ERROR_INVALID_ARG);
}
this.networkInterfaces[networkId] = network;
Services.obs.notifyObservers(network, TOPIC_INTERFACE_REGISTERED, null);
debug("Network '" + networkId + "' registered.");
},
+ updateNetworkInterface: function(network) {
+ if (!(network instanceof Ci.nsINetworkInterface)) {
+ throw Components.Exception("Argument must be nsINetworkInterface.",
+ Cr.NS_ERROR_INVALID_ARG);
+ }
+ let networkId = this.getNetworkId(network);
+ if (!(networkId in this.networkInterfaces)) {
+ throw Components.Exception("No network with that type registered.",
+ Cr.NS_ERROR_INVALID_ARG);
+ }
+ debug("Network " + network.type + "/" + network.name +
+ " changed state to " + network.state);
+ switch (network.state) {
+ case Ci.nsINetworkInterface.NETWORK_STATE_CONNECTED:
+#ifdef MOZ_B2G_RIL
+ // Add host route for data calls
+ if (this.isNetworkTypeMobile(network.type)) {
+ gNetworkService.removeHostRoutes(network.name);
+ gNetworkService.addHostRoute(network);
+ }
+ // Dun type is a special case where we add the default route to a
+ // secondary table.
+ if (network.type == Ci.nsINetworkInterface.NETWORK_TYPE_MOBILE_DUN) {
+ this.setSecondaryDefaultRoute(network);
+ }
+#endif
+ // Remove pre-created default route and let setAndConfigureActive()
+ // to set default route only on preferred network
+ gNetworkService.removeDefaultRoute(network);
+ this.setAndConfigureActive();
+#ifdef MOZ_B2G_RIL
+ // Resolve and add extra host route. For example, mms proxy or mmsc.
+ // IMPORTANT: The offline state of DNSService will be set implicitly in
+ // setAndConfigureActive() by modifying Services.io.offline.
+ // Always setExtraHostRoute() after setAndConfigureActive().
+ this.setExtraHostRoute(network);
+
+ // Update data connection when Wifi connected/disconnected
+ if (network.type == Ci.nsINetworkInterface.NETWORK_TYPE_WIFI) {
+ for (let i = 0; i < this.mRil.numRadioInterfaces; i++) {
+ this.mRil.getRadioInterface(i).updateRILNetworkInterface();
+ }
+ }
+#endif
+
+ this.onConnectionChanged(network);
+
+ // Probing the public network accessibility after routing table is ready
+ CaptivePortalDetectionHelper
+ .notify(CaptivePortalDetectionHelper.EVENT_CONNECT, this.active);
+ break;
+ case Ci.nsINetworkInterface.NETWORK_STATE_DISCONNECTED:
+#ifdef MOZ_B2G_RIL
+ // Remove host route for data calls
+ if (this.isNetworkTypeMobile(network.type)) {
+ gNetworkService.removeHostRoute(network);
+ }
+ // Remove extra host route. For example, mms proxy or mmsc.
+ this.removeExtraHostRoute(network);
+ // Remove secondary default route for dun.
+ if (network.type == Ci.nsINetworkInterface.NETWORK_TYPE_MOBILE_DUN) {
+ this.removeSecondaryDefaultRoute(network);
+ }
+#endif
+ // Remove routing table in /proc/net/route
+ if (network.type == Ci.nsINetworkInterface.NETWORK_TYPE_WIFI) {
+ gNetworkService.resetRoutingTable(network);
+#ifdef MOZ_B2G_RIL
+ } else if (network.type == Ci.nsINetworkInterface.NETWORK_TYPE_MOBILE) {
+ gNetworkService.removeDefaultRoute(network);
+#endif
+ }
+
+ // Abort ongoing captive portal detection on the wifi interface
+ CaptivePortalDetectionHelper
+ .notify(CaptivePortalDetectionHelper.EVENT_DISCONNECT, network);
+ this.setAndConfigureActive();
+#ifdef MOZ_B2G_RIL
+ // Update data connection when Wifi connected/disconnected
+ if (network.type == Ci.nsINetworkInterface.NETWORK_TYPE_WIFI) {
+ for (let i = 0; i < this.mRil.numRadioInterfaces; i++) {
+ this.mRil.getRadioInterface(i).updateRILNetworkInterface();
+ }
+ }
+#endif
+ break;
+ }
+#ifdef MOZ_B2G_RIL
+ // Notify outer modules like MmsService to start the transaction after
+ // the configuration of the network interface is done.
+ Services.obs.notifyObservers(network, TOPIC_CONNECTION_STATE_CHANGED,
+ this.convertConnectionType(network));
+#endif
+ },
+
unregisterNetworkInterface: function(network) {
if (!(network instanceof Ci.nsINetworkInterface)) {
throw Components.Exception("Argument must be nsINetworkInterface.",
Cr.NS_ERROR_INVALID_ARG);
}
let networkId = this.getNetworkId(network);
if (!(networkId in this.networkInterfaces)) {
throw Components.Exception("No network with that type registered.",
--- a/dom/system/gonk/RadioInterfaceLayer.js
+++ b/dom/system/gonk/RadioInterfaceLayer.js
@@ -64,17 +64,16 @@ const GSMCELLINFO_CID =
const WCDMACELLINFO_CID =
Components.ID("{eeaaf307-df6e-4c98-b121-e3302b1fc468}");
const CDMACELLINFO_CID =
Components.ID("{b497d6e4-4cb8-4d6e-b673-840c7d5ddf25}");
const LTECELLINFO_CID =
Components.ID("{c7e0a78a-4e99-42f5-9251-e6172c5ed8d8}");
const NS_XPCOM_SHUTDOWN_OBSERVER_ID = "xpcom-shutdown";
-const kNetworkInterfaceStateChangedTopic = "network-interface-state-changed";
const kNetworkConnStateChangedTopic = "network-connection-state-changed";
const kNetworkActiveChangedTopic = "network-active-changed";
const kSmsReceivedObserverTopic = "sms-received";
const kSilentSmsReceivedObserverTopic = "silent-sms-received";
const kSmsSendingObserverTopic = "sms-sending";
const kSmsSentObserverTopic = "sms-sent";
const kSmsFailedObserverTopic = "sms-failed";
const kSmsDeliverySuccessObserverTopic = "sms-delivery-success";
@@ -5091,19 +5090,17 @@ RILNetworkInterface.prototype = {
},
notifyRILNetworkInterface: function() {
if (DEBUG) {
this.debug("notifyRILNetworkInterface type: " + this.type + ", state: " +
this.state);
}
- Services.obs.notifyObservers(this,
- kNetworkInterfaceStateChangedTopic,
- null);
+ gNetworkManager.updateNetworkInterface(this);
},
connect: function() {
this.enabled = true;
this.dataCall.connect(this);
},
--- a/dom/system/gonk/nsINetworkManager.idl
+++ b/dom/system/gonk/nsINetworkManager.idl
@@ -16,18 +16,18 @@ interface nsINetworkInterface : nsISuppo
const long NETWORK_STATE_CONNECTING = 0;
const long NETWORK_STATE_CONNECTED = 1;
const long NETWORK_STATE_DISCONNECTING = 2;
const long NETWORK_STATE_DISCONNECTED = 3;
/**
* Current network state, one of the NETWORK_STATE_* constants.
*
- * When this changes, network interface implementations notify the
- * 'network-interface-state-changed' observer notification.
+ * When this changes, network interface implementations notify with
+ * updateNetworkInterface() API.
*/
readonly attribute long state;
const long NETWORK_TYPE_UNKNOWN = -1;
const long NETWORK_TYPE_WIFI = 0;
const long NETWORK_TYPE_MOBILE = 1;
const long NETWORK_TYPE_MOBILE_MMS = 2;
const long NETWORK_TYPE_MOBILE_SUPL = 3;
@@ -92,33 +92,47 @@ interface nsINetworkInterface : nsISuppo
*/
void getDnses([optional] out unsigned long count,
[array, size_is(count), retval] out wstring dnses);
};
/**
* Manage network interfaces.
*/
-[scriptable, uuid(3ea50550-4b3c-11e3-8f96-0800200c9a66)]
+[scriptable, uuid(f3193805-c070-4d23-bd5c-a439eb8610c3)]
interface nsINetworkManager : nsISupports
{
/**
* Register the given network interface with the network manager.
*
* Consumers will be notified with the 'network-interface-registered'
* observer notification.
*
* Throws if there's already an interface registered with the same network id.
*
* @param network
* Network interface to register.
*/
void registerNetworkInterface(in nsINetworkInterface network);
/**
+ * Update the routes and DNSes according the state of the given network.
+ *
+ * Consumers will be notified with the 'network-connection-state-changed'
+ * observer notification.
+ *
+ * Throws an exception if the specified network interface object isn't
+ * registered.
+ *
+ * @param network
+ * Network interface to update.
+ */
+ void updateNetworkInterface(in nsINetworkInterface network);
+
+ /**
* Unregister the given network interface from the network manager.
*
* Consumers will be notified with the 'network-interface-unregistered'
* observer notification.
*
* Throws an exception if the specified network interface object isn't
* registered.
*
--- a/dom/system/gonk/ril_consts.js
+++ b/dom/system/gonk/ril_consts.js
@@ -1304,18 +1304,25 @@ this.CB_NON_MMI_SETTABLE_RANGES = [
// User Data max length in septets
this.CB_MAX_CONTENT_7BIT = 93;
// User Data max length in octets
this.CB_MAX_CONTENT_8BIT = 82;
// User Data max length in chars
this.CB_MAX_CONTENT_UCS2 = 41;
+// See 3GPP TS 23.041 v11.6.0 senction 9.3.19
+this.CB_MSG_PAGE_INFO_SIZE = 82;
+
this.CB_MESSAGE_SIZE_ETWS = 56;
this.CB_MESSAGE_SIZE_GSM = 88;
+this.CB_MESSAGE_SIZE_UMTS_MIN = 90;
+this.CB_MESSAGE_SIZE_UMTS_MAX = 1252;
+
+
// GSM Cell Broadcast Geographical Scope
// See 3GPP TS 23.041 clause 9.4.1.2.1
this.CB_GSM_GEOGRAPHICAL_SCOPE_CELL_WIDE_IMMEDIATE = 0;
this.CB_GSM_GEOGRAPHICAL_SCOPE_PLMN_WIDE = 1;
this.CB_GSM_GEOGRAPHICAL_SCOPE_LOCATION_AREA_WIDE = 2;
this.CB_GSM_GEOGRAPHICAL_SCOPE_CELL_WIDE = 3;
@@ -1338,16 +1345,22 @@ this.CB_GSM_MESSAGEID_ETWS_END = 0x110
this.CB_ETWS_WARNING_TYPE_NAMES = [
"earthquake",
"tsunami",
"earthquake-tsunami",
"test",
"other"
];
+// UMTS Message Type
+// see 3GPP TS 25.324 section 11.1
+this.CB_UMTS_MESSAGE_TYPE_CBS = 1;
+this.CB_UMTS_MESSAGE_TYPE_SCHEDULE = 2;
+this.CB_UMTS_MESSAGE_TYPE_CBS41 = 3;
+
/**
* GSM PDU constants
*/
// PDU TYPE-OF-ADDRESS
this.PDU_TOA_UNKNOWN = 0x80; // Unknown. This is used when the user or
// network has no a priori information
// about the numbering plan.
--- a/dom/system/gonk/ril_worker.js
+++ b/dom/system/gonk/ril_worker.js
@@ -6953,18 +6953,17 @@ RilObject.prototype[UNSOLICITED_RESPONSE
};
RilObject.prototype[UNSOLICITED_RESPONSE_NEW_BROADCAST_SMS] = function UNSOLICITED_RESPONSE_NEW_BROADCAST_SMS(length) {
let message;
try {
message =
this.context.GsmPDUHelper.readCbMessage(this.context.Buf.readInt32());
} catch (e) {
if (DEBUG) {
- this.context.debug("Failed to parse Cell Broadcast message: " +
- JSON.stringify(e));
+ this.context.debug("Failed to parse Cell Broadcast message: " + e);
}
return;
}
message = this._processReceivedSmsCbPage(message);
if (!message) {
return;
}
@@ -8402,17 +8401,26 @@ GsmPDUHelperObject.prototype = {
* @param msg
* message object for output.
*
* @see 3GPP TS 23.041 section 9.4.1.2.2
*/
readCbMessageIdentifier: function(msg) {
let Buf = this.context.Buf;
msg.messageId = Buf.readUint8() << 8 | Buf.readUint8();
-
+ },
+
+ /**
+ * Read ETWS information from message identifier and serial Number
+ * @param msg
+ * message object for output.
+ *
+ * @see 3GPP TS 23.041 section 9.4.1.2.1 & 9.4.1.2.2
+ */
+ readCbEtwsInfo: function(msg) {
if ((msg.format != CB_FORMAT_ETWS)
&& (msg.messageId >= CB_GSM_MESSAGEID_ETWS_BEGIN)
&& (msg.messageId <= CB_GSM_MESSAGEID_ETWS_END)) {
// `In the case of transmitting CBS message for ETWS, a part of
// Message Code can be used to command mobile terminals to activate
// emergency user alert and message popup in order to alert the users.`
msg.etws = {
emergencyUserAlert: msg.messageCode & 0x0200 ? true : false,
@@ -8539,24 +8547,22 @@ GsmPDUHelperObject.prototype = {
msg.etws = {
warningType: (word >>> 9) & 0x7F,
popup: word & 0x80 ? true : false,
emergencyUserAlert: word & 0x100 ? true : false
};
},
/**
- * Read CBS-Message-Information-Page
- *
- * @param msg
- * message object for output.
- * @param length
- * length of cell broadcast data to read in octets.
- *
- * @see 3GPP TS 23.041 section 9.3.19
+ * Read GSM CB Data
+ *
+ * This parameter is a copy of the 'CBS-Message-Information-Page' as sent
+ * from the CBC to the BSC.
+ *
+ * @see 3GPP TS 23.041 section 9.4.1.2.5
*/
readGsmCbData: function(msg, length) {
let Buf = this.context.Buf;
let bufAdapter = {
context: this.context,
readHexOctet: function() {
return Buf.readUint8();
}
@@ -8586,36 +8592,160 @@ GsmPDUHelperObject.prototype = {
PDU_NL_IDENTIFIER_DEFAULT,
PDU_NL_IDENTIFIER_DEFAULT);
length -= 2;
}
msg.body = this.readUCS2String.call(bufAdapter, length);
break;
}
+ if (msg.data || !msg.body) {
+ return;
+ }
+
// According to 9.3.19 CBS-Message-Information-Page in TS 23.041:
// "
// This parameter is of a fixed length of 82 octets and carries up to and
// including 82 octets of user information. Where the user information is
// less than 82 octets, the remaining octets must be filled with padding.
// "
// According to 6.2.1.1 GSM 7 bit Default Alphabet and 6.2.3 UCS2 in
// TS 23.038, the padding character is <CR>.
- if (!msg.body) {
- return;
- }
for (let i = msg.body.length - 1; i >= 0; i--) {
if (msg.body.charAt(i) !== '\r') {
msg.body = msg.body.substring(0, i + 1);
break;
}
}
},
/**
+ * Read UMTS CB Data
+ *
+ * Octet Number(s) Parameter
+ * 1 Number-of-Pages
+ * 2 - 83 CBS-Message-Information-Page 1
+ * 84 CBS-Message-Information-Length 1
+ * ...
+ * CBS-Message-Information-Page n
+ * CBS-Message-Information-Length n
+ *
+ * @see 3GPP TS 23.041 section 9.4.2.2.5
+ */
+ readUmtsCbData: function(msg) {
+ let Buf = this.context.Buf;
+ let numOfPages = Buf.readUint8();
+ if (numOfPages < 0 || numOfPages > 15) {
+ throw new Error("Invalid numOfPages: " + numOfPages);
+ }
+
+ let bufAdapter = {
+ context: this.context,
+ readHexOctet: function() {
+ return Buf.readUint8();
+ }
+ };
+
+ let removePaddingCharactors = function (text) {
+ for (let i = text.length - 1; i >= 0; i--) {
+ if (text.charAt(i) !== '\r') {
+ return text.substring(0, i + 1);
+ }
+ }
+ return text;
+ }
+
+ let totalLength = 0, length, pageLengths = [];
+ for (let i = 0; i < numOfPages; i++) {
+ Buf.seekIncoming(CB_MSG_PAGE_INFO_SIZE);
+ length = Buf.readUint8();
+ totalLength += length;
+ pageLengths.push(length);
+ }
+
+ // Seek back to beginning of CB Data.
+ Buf.seekIncoming(-numOfPages * (CB_MSG_PAGE_INFO_SIZE + 1));
+
+ switch (msg.encoding) {
+ case PDU_DCS_MSG_CODING_7BITS_ALPHABET: {
+ let body;
+ msg.body = "";
+ for (let i = 0; i < numOfPages; i++) {
+ body = this.readSeptetsToString.call(bufAdapter,
+ (pageLengths[i] * 8 / 7),
+ 0,
+ PDU_NL_IDENTIFIER_DEFAULT,
+ PDU_NL_IDENTIFIER_DEFAULT);
+ if (msg.hasLanguageIndicator) {
+ if (!msg.language) {
+ msg.language = body.substring(0, 2);
+ }
+ body = body.substring(3);
+ }
+
+ msg.body += removePaddingCharactors(body);
+
+ // Skip padding octets
+ Buf.seekIncoming(CB_MSG_PAGE_INFO_SIZE - pageLengths[i]);
+ // Read the octet of CBS-Message-Information-Length
+ Buf.readUint8();
+ }
+
+ break;
+ }
+
+ case PDU_DCS_MSG_CODING_8BITS_ALPHABET: {
+ msg.data = new Uint8Array(totalLength);
+ for (let i = 0, j = 0; i < numOfPages; i++) {
+ for (let pageLength = pageLengths[i]; pageLength > 0; pageLength--) {
+ msg.data[j++] = Buf.readUint8();
+ }
+
+ // Skip padding octets
+ Buf.seekIncoming(CB_MSG_PAGE_INFO_SIZE - pageLengths[i]);
+ // Read the octet of CBS-Message-Information-Length
+ Buf.readUint8();
+ }
+
+ break;
+ }
+
+ case PDU_DCS_MSG_CODING_16BITS_ALPHABET: {
+ msg.body = "";
+ for (let i = 0; i < numOfPages; i++) {
+ let pageLength = pageLengths[i];
+ if (msg.hasLanguageIndicator) {
+ if (!msg.language) {
+ msg.language = this.readSeptetsToString.call(bufAdapter,
+ 2,
+ 0,
+ PDU_NL_IDENTIFIER_DEFAULT,
+ PDU_NL_IDENTIFIER_DEFAULT);
+ } else {
+ Buf.readUint16();
+ }
+
+ pageLength -= 2;
+ }
+
+ msg.body += removePaddingCharactors(
+ this.readUCS2String.call(bufAdapter, pageLength));
+
+ // Skip padding octets
+ Buf.seekIncoming(CB_MSG_PAGE_INFO_SIZE - pageLengths[i]);
+ // Read the octet of CBS-Message-Information-Length
+ Buf.readUint8();
+ }
+
+ break;
+ }
+ }
+ },
+
+ /**
* Read Cell GSM/ETWS/UMTS Broadcast Message.
*
* @param pduLength
* total length of the incoming PDU in octets.
*/
readCbMessage: function(pduLength) {
// Validity GSM ETWS UMTS
let msg = {
@@ -8652,32 +8782,64 @@ GsmPDUHelperObject.prototype = {
return this.readEtwsCbMessage(msg);
}
if (pduLength <= CB_MESSAGE_SIZE_GSM) {
msg.format = CB_FORMAT_GSM;
return this.readGsmCbMessage(msg, pduLength);
}
- return null;
+ if (pduLength >= CB_MESSAGE_SIZE_UMTS_MIN &&
+ pduLength <= CB_MESSAGE_SIZE_UMTS_MAX) {
+ msg.format = CB_FORMAT_UMTS;
+ return this.readUmtsCbMessage(msg);
+ }
+
+ throw new Error("Invalid PDU Length: " + pduLength);
+ },
+
+ /**
+ * Read UMTS CBS Message.
+ *
+ * @param msg
+ * message object for output.
+ *
+ * @see 3GPP TS 23.041 section 9.4.2
+ * @see 3GPP TS 25.324 section 10.2
+ */
+ readUmtsCbMessage: function(msg) {
+ let Buf = this.context.Buf;
+ let type = Buf.readUint8();
+ if (type != CB_UMTS_MESSAGE_TYPE_CBS) {
+ throw new Error("Unsupported UMTS Cell Broadcast message type: " + type);
+ }
+
+ this.readCbMessageIdentifier(msg);
+ this.readCbSerialNumber(msg);
+ this.readCbEtwsInfo(msg);
+ this.readCbDataCodingScheme(msg);
+ this.readUmtsCbData(msg);
+
+ return msg;
},
/**
* Read GSM Cell Broadcast Message.
*
* @param msg
* message object for output.
* @param pduLength
* total length of the incomint PDU in octets.
*
* @see 3GPP TS 23.041 clause 9.4.1.2
*/
readGsmCbMessage: function(msg, pduLength) {
this.readCbSerialNumber(msg);
this.readCbMessageIdentifier(msg);
+ this.readCbEtwsInfo(msg);
this.readCbDataCodingScheme(msg);
this.readCbPageParameter(msg);
// GSM CB message header takes 6 octets.
this.readGsmCbData(msg, pduLength - 6);
return msg;
},
--- a/dom/system/gonk/tests/marionette/head.js
+++ b/dom/system/gonk/tests/marionette/head.js
@@ -2,17 +2,16 @@
* http://creativecommons.org/publicdomain/zero/1.0/ */
MARIONETTE_CONTEXT = "chrome";
const SETTINGS_KEY_DATA_ENABLED = "ril.data.enabled";
const SETTINGS_KEY_DATA_APN_SETTINGS = "ril.data.apnSettings";
const TOPIC_CONNECTION_STATE_CHANGED = "network-connection-state-changed";
-const TOPIC_INTERFACE_STATE_CHANGED = "network-interface-state-changed";
const TOPIC_NETWORK_ACTIVE_CHANGED = "network-active-changed";
let Promise = Cu.import("resource://gre/modules/Promise.jsm").Promise;
let ril = Cc["@mozilla.org/ril;1"].getService(Ci.nsIRadioInterfaceLayer);
ok(ril, "ril.constructor is " + ril.constructor);
let radioInterface = ril.getRadioInterface(0);
--- a/dom/system/gonk/tests/test_ril_worker_cellbroadcast.js
+++ b/dom/system/gonk/tests/test_ril_worker_cellbroadcast.js
@@ -2,16 +2,41 @@
http://creativecommons.org/publicdomain/zero/1.0/ */
subscriptLoader.loadSubScript("resource://gre/modules/ril_consts.js", this);
function run_test() {
run_next_test();
}
+function buildHexStr(aNum, aNumSemiOctets) {
+ let str = aNum.toString(16);
+ while (str.length < aNumSemiOctets) {
+ str = "0" + str;
+ }
+ return str;
+}
+
+function hexStringToParcelByteArrayData(hexString) {
+ let bytes = [];
+
+ let length = hexString.length / 2;
+
+ bytes.push(length & 0xFF);
+ bytes.push((length >> 8) & 0xFF);
+ bytes.push((length >> 16) & 0xFF);
+ bytes.push((length >> 24) & 0xFF);
+
+ for (let i = 0; i < hexString.length; i += 2) {
+ bytes.push(Number.parseInt(hexString.substr(i, 2), 16));
+ }
+
+ return bytes;
+}
+
add_test(function test_ril_consts_cellbroadcast_misc() {
// Must be 16 for indexing.
do_check_eq(CB_DCS_LANG_GROUP_1.length, 16);
do_check_eq(CB_DCS_LANG_GROUP_2.length, 16);
// Array length must be even.
do_check_eq(CB_NON_MMI_SETTABLE_RANGES.length & 0x01, 0);
for (let i = 0; i < CB_NON_MMI_SETTABLE_RANGES.length;) {
@@ -429,8 +454,97 @@ add_test(function test_ril_worker__merge
test([10, 13, 16, 19], 13, 16, [10, 19]);
test([10, 13, 16, 19], 14, 15, [10, 13, 14, 15, 16, 19]);
test([10, 13, 16, 19], 14, 16, [10, 13, 14, 19]);
test([10, 13, 16, 19], 15, 16, [10, 13, 15, 19]);
run_next_test();
});
+
+/**
+ * Verify GsmPDUHelper#readUmtsCbMessage with numOfPages from 1 to 15.
+ */
+add_test(function test_GsmPDUHelper_readUmtsCbMessage_MultiParts() {
+ let CB_UMTS_MESSAGE_PAGE_SIZE = 82;
+ let CB_MAX_CONTENT_PER_PAGE_7BIT = 93;
+ let workerHelper = newInterceptWorker(),
+ worker = workerHelper.worker,
+ context = worker.ContextPool._contexts[0],
+ GsmPDUHelper = context.GsmPDUHelper;
+
+ function test_MultiParts(aNumOfPages) {
+ let pdu = buildHexStr(CB_UMTS_MESSAGE_TYPE_CBS, 2) // msg_type
+ + buildHexStr(0, 4) // skip msg_id
+ + buildHexStr(0, 4) // skip SN
+ + buildHexStr(0, 2) // skip dcs
+ + buildHexStr(aNumOfPages, 2); // set num_of_pages
+ for (let i = 1; i <= aNumOfPages; i++) {
+ pdu = pdu + buildHexStr(0, CB_UMTS_MESSAGE_PAGE_SIZE * 2)
+ + buildHexStr(CB_UMTS_MESSAGE_PAGE_SIZE, 2); // msg_info_length
+ }
+
+ worker.onRILMessage(0, newIncomingParcel(-1,
+ RESPONSE_TYPE_UNSOLICITED,
+ UNSOLICITED_RESPONSE_NEW_BROADCAST_SMS,
+ hexStringToParcelByteArrayData(pdu)));
+
+ let postedMessage = workerHelper.postedMessage;
+ do_check_eq("cellbroadcast-received", postedMessage.rilMessageType);
+ do_check_eq(postedMessage.fullBody.length,
+ aNumOfPages * CB_MAX_CONTENT_PER_PAGE_7BIT);
+ }
+
+ [1, 5, 15].forEach(function(i) {
+ test_MultiParts(i);
+ });
+
+ run_next_test();
+});
+
+/**
+ * Verify GsmPDUHelper#readUmtsCbMessage with 8bit encoded.
+ */
+add_test(function test_GsmPDUHelper_readUmtsCbMessage_Binary() {
+ let CB_UMTS_MESSAGE_PAGE_SIZE = 82;
+ let CB_MAX_CONTENT_PER_PAGE_7BIT = 93;
+ let TEXT_BINARY = "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
+ + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
+ + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
+ + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
+ + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
+ + "FFFF";
+ let workerHelper = newInterceptWorker(),
+ worker = workerHelper.worker,
+ context = worker.ContextPool._contexts[0],
+ GsmPDUHelper = context.GsmPDUHelper;
+
+ function test_MultiPartsBinary(aNumOfPages) {
+ let pdu = buildHexStr(CB_UMTS_MESSAGE_TYPE_CBS, 2) // msg_type
+ + buildHexStr(0, 4) // skip msg_id
+ + buildHexStr(0, 4) // skip SN
+ + buildHexStr(68, 2) // set DCS to 8bit data
+ + buildHexStr(aNumOfPages, 2); // set num_of_pages
+ for (let i = 1; i <= aNumOfPages; i++) {
+ pdu = pdu + TEXT_BINARY
+ + buildHexStr(CB_UMTS_MESSAGE_PAGE_SIZE, 2); // msg_info_length
+ }
+
+ worker.onRILMessage(0, newIncomingParcel(-1,
+ RESPONSE_TYPE_UNSOLICITED,
+ UNSOLICITED_RESPONSE_NEW_BROADCAST_SMS,
+ hexStringToParcelByteArrayData(pdu)));
+
+ let postedMessage = workerHelper.postedMessage;
+ do_check_eq("cellbroadcast-received", postedMessage.rilMessageType);
+ do_check_eq(postedMessage.fullData.length,
+ aNumOfPages * CB_UMTS_MESSAGE_PAGE_SIZE);
+ for (let i = 0; i < postedMessage.fullData.length; i++) {
+ do_check_eq(postedMessage.fullData[i], 255);
+ }
+ }
+
+ [1, 5, 15].forEach(function(i) {
+ test_MultiPartsBinary(i);
+ });
+
+ run_next_test();
+});
--- a/dom/webidl/Headers.webidl
+++ b/dom/webidl/Headers.webidl
@@ -15,17 +15,17 @@ enum HeadersGuardEnum {
"request",
"request-no-cors",
"response",
"immutable"
};
[Constructor(optional HeadersInit init),
// FIXME: Exposed=Window,Worker,
- Pref="dom.fetch.enabled"]
+ Func="mozilla::dom::Headers::PrefEnabled"]
interface Headers {
[Throws] void append(ByteString name, ByteString value);
[Throws] void delete(ByteString name);
[Throws] ByteString? get(ByteString name);
[Throws] sequence<ByteString> getAll(ByteString name);
[Throws] boolean has(ByteString name);
[Throws] void set(ByteString name, ByteString value);
--- a/dom/webidl/Window.webidl
+++ b/dom/webidl/Window.webidl
@@ -74,17 +74,18 @@ typedef any Transferable;
// user prompts
[Throws] void alert();
[Throws] void alert(DOMString message);
[Throws] boolean confirm(optional DOMString message = "");
[Throws] DOMString? prompt(optional DOMString message = "", optional DOMString default = "");
[Throws] void print();
//[Throws] any showModalDialog(DOMString url, optional any argument);
- [Throws] any showModalDialog(DOMString url, optional any argument, optional DOMString options = "");
+ [Throws, Func="nsGlobalWindow::IsShowModalDialogEnabled"]
+ any showModalDialog(DOMString url, optional any argument, optional DOMString options = "");
[Throws, CrossOriginCallable] void postMessage(any message, DOMString targetOrigin, optional sequence<Transferable> transfer);
// also has obsolete members
};
Window implements GlobalEventHandlers;
Window implements WindowEventHandlers;
--- a/dom/wifi/WifiP2pManager.jsm
+++ b/dom/wifi/WifiP2pManager.jsm
@@ -16,18 +16,16 @@ Cu.import("resource://gre/modules/system
XPCOMUtils.defineLazyServiceGetter(this, "gSysMsgr",
"@mozilla.org/system-message-internal;1",
"nsISystemMessagesInternal");
XPCOMUtils.defineLazyServiceGetter(this, "gNetworkManager",
"@mozilla.org/network/manager;1",
"nsINetworkManager");
-const kNetworkInterfaceStateChangedTopic = "network-interface-state-changed";
-
this.EXPORTED_SYMBOLS = ["WifiP2pManager"];
const EVENT_IGNORED = -1;
const EVENT_UNKNOWN = -2;
// Events from supplicant for p2p.
const EVENT_P2P_DEVICE_FOUND = 0;
const EVENT_P2P_DEVICE_LOST = 1;
@@ -1471,19 +1469,17 @@ function P2pStateMachine(aP2pCommand, aN
if (_p2pNetworkInterface.registered) {
resetP2pNetworkInterface();
gNetworkManager.unregisterNetworkInterface(_p2pNetworkInterface);
_p2pNetworkInterface.registered = false;
}
}
function handleP2pNetworkInterfaceStateChanged() {
- Services.obs.notifyObservers(_p2pNetworkInterface,
- kNetworkInterfaceStateChangedTopic,
- null);
+ gNetworkManager.updateNetworkInterface(_p2pNetworkInterface);
}
// Handle 'P2P_GROUP_STARTED' event.
//
// @param aInfo information carried by "P2P_GROUP_REMOVED" event:
// .ifname
// .role: "GO" or "client".
//
--- a/dom/wifi/WifiWorker.js
+++ b/dom/wifi/WifiWorker.js
@@ -19,17 +19,16 @@ Cu.import("resource://gre/modules/WifiP2
var DEBUG = false; // set to true to show debug messages.
const WIFIWORKER_CONTRACTID = "@mozilla.org/wifi/worker;1";
const WIFIWORKER_CID = Components.ID("{a14e8977-d259-433a-a88d-58dd44657e5b}");
const WIFIWORKER_WORKER = "resource://gre/modules/wifi_worker.js";
-const kNetworkInterfaceStateChangedTopic = "network-interface-state-changed";
const kMozSettingsChangedObserverTopic = "mozsettings-changed";
const MAX_RETRIES_ON_AUTHENTICATION_FAILURE = 2;
const MAX_SUPPLICANT_LOOP_ITERATIONS = 4;
const MAX_RETRIES_ON_DHCP_FAILURE = 2;
// Settings DB path for wifi
const SETTINGS_WIFI_ENABLED = "wifi.enabled";
@@ -974,19 +973,18 @@ var WifiManager = (function() {
gNetworkManager.registerNetworkInterface(WifiNetworkInterface);
WifiNetworkInterface.registered = true;
}
WifiNetworkInterface.state = Ci.nsINetworkInterface.NETWORK_STATE_DISCONNECTED;
WifiNetworkInterface.ips = [];
WifiNetworkInterface.prefixLengths = [];
WifiNetworkInterface.gateways = [];
WifiNetworkInterface.dnses = [];
- Services.obs.notifyObservers(WifiNetworkInterface,
- kNetworkInterfaceStateChangedTopic,
- null);
+ gNetworkManager.updateNetworkInterface(WifiNetworkInterface);
+
prepareForStartup(function() {
loadDriver(function (status) {
if (status < 0) {
callback(status);
manager.state = "UNINITIALIZED";
return;
}
// This command is mandatory for Nexus 4. But some devices like
@@ -2180,19 +2178,17 @@ function WifiWorker() {
});
WifiNetworkInterface.state =
Ci.nsINetworkInterface.NETWORK_STATE_DISCONNECTED;
WifiNetworkInterface.ips = [];
WifiNetworkInterface.prefixLengths = [];
WifiNetworkInterface.gateways = [];
WifiNetworkInterface.dnses = [];
- Services.obs.notifyObservers(WifiNetworkInterface,
- kNetworkInterfaceStateChangedTopic,
- null);
+ gNetworkManager.updateNetworkInterface(WifiNetworkInterface);
break;
case "WPS_TIMEOUT":
self._fireEvent("onwpstimeout", {});
break;
case "WPS_FAIL":
self._fireEvent("onwpsfail", {});
break;
@@ -2230,19 +2226,17 @@ function WifiWorker() {
if (typeof this.info.dns1_str == "string" &&
this.info.dns1_str.length) {
WifiNetworkInterface.dnses.push(this.info.dns1_str);
}
if (typeof this.info.dns2_str == "string" &&
this.info.dns2_str.length) {
WifiNetworkInterface.dnses.push(this.info.dns2_str);
}
- Services.obs.notifyObservers(WifiNetworkInterface,
- kNetworkInterfaceStateChangedTopic,
- null);
+ gNetworkManager.updateNetworkInterface(WifiNetworkInterface);
self.ipAddress = this.info.ipaddr_str;
// We start the connection information timer when we associate, but
// don't have our IP address until here. Make sure that we fire a new
// connectionInformation event with the IP address the next time the
// timer fires.
self._lastConnectionInfo = null;
--- a/dom/workers/DataStore.cpp
+++ b/dom/workers/DataStore.cpp
@@ -411,18 +411,18 @@ public:
protected:
virtual bool
MainThreadRun() MOZ_OVERRIDE
{
AssertIsOnMainThread();
// Point WorkerDataStoreCursor to DataStoreCursor.
nsRefPtr<DataStoreCursor> cursor = mBackingStore->Sync(mRevisionId, mRv);
- nsMainThreadPtrHandle<DataStoreCursor> backingCursor =
- new nsMainThreadPtrHolder<DataStoreCursor>(cursor);
+ nsMainThreadPtrHandle<DataStoreCursor> backingCursor(
+ new nsMainThreadPtrHolder<DataStoreCursor>(cursor));
mWorkerCursor->SetBackingDataStoreCursor(backingCursor);
return true;
}
};
void
WorkerDataStore::GetName(JSContext* aCx, nsAString& aName, ErrorResult& aRv)
--- a/dom/workers/Navigator.cpp
+++ b/dom/workers/Navigator.cpp
@@ -117,17 +117,17 @@ GetDataStoresStructuredCloneCallbacksRea
return nullptr;
}
// Protect workerStoreObj from moving GC during ~nsRefPtr.
JS::Rooted<JSObject*> workerStoreObj(aCx, nullptr);
{
nsRefPtr<WorkerDataStore> workerStore =
new WorkerDataStore(workerPrivate->GlobalScope());
- nsMainThreadPtrHandle<DataStore> backingStore = dataStoreholder;
+ nsMainThreadPtrHandle<DataStore> backingStore(dataStoreholder);
// When we're on the worker thread, prepare a DataStoreChangeEventProxy.
nsRefPtr<DataStoreChangeEventProxy> eventProxy =
new DataStoreChangeEventProxy(workerPrivate, workerStore);
// Add the DataStoreChangeEventProxy as an event listener on the main thread.
nsRefPtr<DataStoreAddEventListenerRunnable> runnable =
new DataStoreAddEventListenerRunnable(workerPrivate,
--- a/dom/workers/RegisterBindings.cpp
+++ b/dom/workers/RegisterBindings.cpp
@@ -59,36 +59,32 @@ WorkerPrivate::RegisterBindings(JSContex
return false;
}
// Init other paris-bindings.
if (!ConsoleBinding::GetConstructorObject(aCx, aGlobal) ||
!DOMExceptionBinding::GetConstructorObject(aCx, aGlobal) ||
!EventBinding::GetConstructorObject(aCx, aGlobal) ||
!FileReaderSyncBinding_workers::GetConstructorObject(aCx, aGlobal) ||
+ (HeadersBinding::ConstructorEnabled(aCx, aGlobal) &&
+ !HeadersBinding::GetConstructorObject(aCx, aGlobal)) ||
!ImageDataBinding::GetConstructorObject(aCx, aGlobal) ||
!MessageEventBinding::GetConstructorObject(aCx, aGlobal) ||
!MessagePortBinding::GetConstructorObject(aCx, aGlobal) ||
!PromiseBinding::GetConstructorObject(aCx, aGlobal) ||
!TextDecoderBinding::GetConstructorObject(aCx, aGlobal) ||
!TextEncoderBinding::GetConstructorObject(aCx, aGlobal) ||
!XMLHttpRequestBinding_workers::GetConstructorObject(aCx, aGlobal) ||
!XMLHttpRequestUploadBinding_workers::GetConstructorObject(aCx, aGlobal) ||
!URLBinding_workers::GetConstructorObject(aCx, aGlobal) ||
!URLSearchParamsBinding::GetConstructorObject(aCx, aGlobal) ||
!WorkerBinding::GetConstructorObject(aCx, aGlobal) ||
!WorkerLocationBinding_workers::GetConstructorObject(aCx, aGlobal) ||
!WorkerNavigatorBinding_workers::GetConstructorObject(aCx, aGlobal)) {
return false;
}
- if (DOMFetchEnabled()) {
- if (!HeadersBinding::GetConstructorObject(aCx, aGlobal)) {
- return false;
- }
- }
-
if (!JS_DefineProfilingFunctions(aCx, aGlobal)) {
return false;
}
return true;
}
--- a/dom/workers/RuntimeService.cpp
+++ b/dom/workers/RuntimeService.cpp
@@ -79,16 +79,19 @@ USING_WORKERS_NAMESPACE
using mozilla::MutexAutoLock;
using mozilla::MutexAutoUnlock;
using mozilla::Preferences;
// The size of the worker runtime heaps in bytes. May be changed via pref.
#define WORKER_DEFAULT_RUNTIME_HEAPSIZE 32 * 1024 * 1024
+// The size of the generational GC nursery for workers, in bytes.
+#define WORKER_DEFAULT_NURSERY_SIZE 1 * 1024 * 1024
+
// The size of the worker JS allocation threshold in MB. May be changed via pref.
#define WORKER_DEFAULT_ALLOCATION_THRESHOLD 30
// The C stack size. We use the same stack size on all platforms for
// consistency.
#define WORKER_STACK_SIZE 256 * sizeof(size_t) * 1024
// Half the size of the actual C stack, to be safe.
@@ -309,17 +312,17 @@ GenerateSharedWorkerKey(const nsACString
}
}
aKey.Append('|');
aKey.Append(aScriptSpec);
}
void
-LoadRuntimeAndContextOptions(const char* aPrefName, void* /* aClosure */)
+LoadRuntimeOptions(const char* aPrefName, void* /* aClosure */)
{
AssertIsOnMainThread();
RuntimeService* rts = RuntimeService::GetService();
if (!rts && !gRuntimeServiceDuringInit) {
// May be shutting down, just bail.
return;
}
@@ -357,39 +360,24 @@ LoadRuntimeAndContextOptions(const char*
}
if (GetWorkerPref<bool>(NS_LITERAL_CSTRING("native_regexp"))) {
runtimeOptions.setNativeRegExp(true);
}
if (GetWorkerPref<bool>(NS_LITERAL_CSTRING("werror"))) {
runtimeOptions.setWerror(true);
}
- // Common options.
- JS::ContextOptions commonContextOptions = kRequiredContextOptions;
if (GetWorkerPref<bool>(NS_LITERAL_CSTRING("strict"))) {
- commonContextOptions.setExtraWarnings(true);
+ runtimeOptions.setExtraWarnings(true);
}
- // Content options.
- JS::ContextOptions contentContextOptions = commonContextOptions;
-
- // Chrome options.
- JS::ContextOptions chromeContextOptions = commonContextOptions;
-#ifdef DEBUG
- if (GetWorkerPref<bool>(NS_LITERAL_CSTRING("strict.debug"))) {
- chromeContextOptions.setExtraWarnings(true);
- }
-#endif
-
- RuntimeService::SetDefaultRuntimeAndContextOptions(runtimeOptions,
- contentContextOptions,
- chromeContextOptions);
+ RuntimeService::SetDefaultRuntimeOptions(runtimeOptions);
if (rts) {
- rts->UpdateAllWorkerRuntimeAndContextOptions();
+ rts->UpdateAllWorkerRuntimeOptions();
}
}
#ifdef JS_GC_ZEAL
void
LoadGCZealOptions(const char* /* aPrefName */, void* /* aClosure */)
{
AssertIsOnMainThread();
@@ -839,35 +827,34 @@ CreateJSContextForWorker(WorkerPrivate*
JS_SetRuntimePrivate(aRuntime, rtPrivate);
JS_SetErrorReporter(workerCx, ErrorReporter);
JS_SetInterruptCallback(aRuntime, InterruptCallback);
js::SetCTypesActivityCallback(aRuntime, CTypesActivityCallback);
- JS::ContextOptionsRef(workerCx) =
- aWorkerPrivate->IsChromeWorker() ? settings.chrome.contextOptions
- : settings.content.contextOptions;
+ JS::ContextOptionsRef(workerCx) = kRequiredContextOptions;
#ifdef JS_GC_ZEAL
JS_SetGCZeal(workerCx, settings.gcZeal, settings.gcZealFrequency);
#endif
return workerCx;
}
class WorkerJSRuntime : public mozilla::CycleCollectedJSRuntime
{
public:
// The heap size passed here doesn't matter, we will change it later in the
// call to JS_SetGCParameter inside CreateJSContextForWorker.
WorkerJSRuntime(JSRuntime* aParentRuntime, WorkerPrivate* aWorkerPrivate)
: CycleCollectedJSRuntime(aParentRuntime,
- WORKER_DEFAULT_RUNTIME_HEAPSIZE),
+ WORKER_DEFAULT_RUNTIME_HEAPSIZE,
+ WORKER_DEFAULT_NURSERY_SIZE),
mWorkerPrivate(aWorkerPrivate)
{
}
~WorkerJSRuntime()
{
auto rtPrivate = static_cast<WorkerThreadRuntimePrivate*>(JS_GetRuntimePrivate(Runtime()));
delete rtPrivate;
@@ -1690,20 +1677,18 @@ RuntimeService::Init()
{
AssertIsOnMainThread();
nsLayoutStatics::AddRef();
// Initialize JSSettings.
if (!sDefaultJSSettings.gcSettings[0].IsSet()) {
sDefaultJSSettings.runtimeOptions = JS::RuntimeOptions();
- sDefaultJSSettings.chrome.contextOptions = kRequiredContextOptions;
sDefaultJSSettings.chrome.maxScriptRuntime = -1;
sDefaultJSSettings.chrome.compartmentOptions.setVersion(JSVERSION_LATEST);
- sDefaultJSSettings.content.contextOptions = kRequiredContextOptions;
sDefaultJSSettings.content.maxScriptRuntime = MAX_SCRIPT_RUN_TIME_SEC;
#ifdef JS_GC_ZEAL
sDefaultJSSettings.gcZealFrequency = JS_DEFAULT_ZEAL_FREQ;
sDefaultJSSettings.gcZeal = 0;
#endif
SetDefaultJSGCSettings(JSGC_MAX_BYTES, WORKER_DEFAULT_RUNTIME_HEAPSIZE);
SetDefaultJSGCSettings(JSGC_ALLOCATION_THRESHOLD,
WORKER_DEFAULT_ALLOCATION_THRESHOLD);
@@ -1772,21 +1757,21 @@ RuntimeService::Init()
WorkerPrefChanged,
PREF_DOM_WINDOW_DUMP_ENABLED,
reinterpret_cast<void *>(WORKERPREF_DUMP))) ||
#endif
NS_FAILED(Preferences::RegisterCallbackAndCall(
WorkerPrefChanged,
PREF_DOM_FETCH_ENABLED,
reinterpret_cast<void *>(WORKERPREF_DOM_FETCH))) ||
- NS_FAILED(Preferences::RegisterCallback(LoadRuntimeAndContextOptions,
+ NS_FAILED(Preferences::RegisterCallback(LoadRuntimeOptions,
PREF_JS_OPTIONS_PREFIX,
nullptr)) ||
NS_FAILED(Preferences::RegisterCallbackAndCall(
- LoadRuntimeAndContextOptions,
+ LoadRuntimeOptions,
PREF_WORKERS_OPTIONS_PREFIX,
nullptr)) ||
NS_FAILED(Preferences::RegisterCallbackAndCall(
JSVersionChanged,
PREF_WORKERS_LATEST_JS_VERSION,
nullptr))) {
NS_WARNING("Failed to register pref callbacks!");
}
@@ -1925,20 +1910,20 @@ RuntimeService::Cleanup()
}
NS_ASSERTION(!mWindowMap.Count(), "All windows should have been released!");
if (mObserved) {
if (NS_FAILED(Preferences::UnregisterCallback(JSVersionChanged,
PREF_WORKERS_LATEST_JS_VERSION,
nullptr)) ||
- NS_FAILED(Preferences::UnregisterCallback(LoadRuntimeAndContextOptions,
+ NS_FAILED(Preferences::UnregisterCallback(LoadRuntimeOptions,
PREF_JS_OPTIONS_PREFIX,
nullptr)) ||
- NS_FAILED(Preferences::UnregisterCallback(LoadRuntimeAndContextOptions,
+ NS_FAILED(Preferences::UnregisterCallback(LoadRuntimeOptions,
PREF_WORKERS_OPTIONS_PREFIX,
nullptr)) ||
NS_FAILED(Preferences::UnregisterCallback(
WorkerPrefChanged,
PREF_DOM_FETCH_ENABLED,
reinterpret_cast<void *>(WORKERPREF_DOM_FETCH))) ||
#if DUMP_CONTROLLED_BY_PREF
NS_FAILED(Preferences::UnregisterCallback(
@@ -2380,22 +2365,19 @@ RuntimeService::NoteIdleThread(WorkerThr
// Schedule timer.
MOZ_ALWAYS_TRUE(NS_SUCCEEDED(mIdleThreadTimer->InitWithFuncCallback(
ShutdownIdleThreads, nullptr,
IDLE_THREAD_TIMEOUT_SEC * 1000,
nsITimer::TYPE_ONE_SHOT)));
}
void
-RuntimeService::UpdateAllWorkerRuntimeAndContextOptions()
+RuntimeService::UpdateAllWorkerRuntimeOptions()
{
- BROADCAST_ALL_WORKERS(UpdateRuntimeAndContextOptions,
- sDefaultJSSettings.runtimeOptions,
- sDefaultJSSettings.content.contextOptions,
- sDefaultJSSettings.chrome.contextOptions);
+ BROADCAST_ALL_WORKERS(UpdateRuntimeOptions, sDefaultJSSettings.runtimeOptions);
}
void
RuntimeService::UpdateAllWorkerPreference(WorkerPreference aPref, bool aValue)
{
BROADCAST_ALL_WORKERS(UpdatePreference, aPref, aValue);
}
--- a/dom/workers/RuntimeService.h
+++ b/dom/workers/RuntimeService.h
@@ -188,29 +188,24 @@ public:
static void
GetDefaultPreferences(bool aPreferences[WORKERPREF_COUNT])
{
AssertIsOnMainThread();
memcpy(aPreferences, sDefaultPreferences, WORKERPREF_COUNT * sizeof(bool));
}
static void
- SetDefaultRuntimeAndContextOptions(
- const JS::RuntimeOptions& aRuntimeOptions,
- const JS::ContextOptions& aContentCxOptions,
- const JS::ContextOptions& aChromeCxOptions)
+ SetDefaultRuntimeOptions(const JS::RuntimeOptions& aRuntimeOptions)
{
AssertIsOnMainThread();
sDefaultJSSettings.runtimeOptions = aRuntimeOptions;
- sDefaultJSSettings.content.contextOptions = aContentCxOptions;
- sDefaultJSSettings.chrome.contextOptions = aChromeCxOptions;
}
void
- UpdateAllWorkerRuntimeAndContextOptions();
+ UpdateAllWorkerRuntimeOptions();
void
UpdateAllWorkerPreference(WorkerPreference aPref, bool aValue);
static void
SetDefaultJSGCSettings(JSGCParamKey aKey, uint32_t aValue)
{
AssertIsOnMainThread();
--- a/dom/workers/ScriptLoader.cpp
+++ b/dom/workers/ScriptLoader.cpp
@@ -719,16 +719,21 @@ ScriptExecutorRunnable::WorkerRun(JSCont
// Note that we read a pref that is cached on the main thread. This is benignly
// racey.
if (xpc::ShouldDiscardSystemSource()) {
bool discard = aWorkerPrivate->UsesSystemPrincipal() ||
aWorkerPrivate->IsInPrivilegedApp();
JS::CompartmentOptionsRef(global).setDiscardSource(discard);
}
+ // Similar to the above.
+ if (xpc::ExtraWarningsForSystemJS() && aWorkerPrivate->UsesSystemPrincipal()) {
+ JS::CompartmentOptionsRef(global).extraWarningsOverride().set(true);
+ }
+
for (uint32_t index = mFirstIndex; index <= mLastIndex; index++) {
ScriptLoadInfo& loadInfo = loadInfos.ElementAt(index);
NS_ASSERTION(!loadInfo.mChannel, "Should no longer have a channel!");
NS_ASSERTION(loadInfo.mExecutionScheduled, "Should be scheduled!");
NS_ASSERTION(!loadInfo.mExecutionResult, "Should not have executed yet!");
if (NS_FAILED(loadInfo.mLoadResult)) {
--- a/dom/workers/ServiceWorkerManager.cpp
+++ b/dom/workers/ServiceWorkerManager.cpp
@@ -256,18 +256,18 @@ public:
mScriptSpec,
mRegistration->mScope,
getter_AddRefs(serviceWorker));
if (NS_WARN_IF(NS_FAILED(rv))) {
swm->RejectUpdatePromiseObservers(mRegistration, rv);
return;
}
- nsMainThreadPtrHandle<ServiceWorkerUpdateInstance> handle =
- new nsMainThreadPtrHolder<ServiceWorkerUpdateInstance>(this);
+ nsMainThreadPtrHandle<ServiceWorkerUpdateInstance> handle(
+ new nsMainThreadPtrHolder<ServiceWorkerUpdateInstance>(this));
// FIXME(nsm): Deal with error case (worker failed to download, redirect,
// parse) in error handler patch.
nsRefPtr<FinishSuccessfulFetchWorkerRunnable> r =
new FinishSuccessfulFetchWorkerRunnable(serviceWorker->GetWorkerPrivate(), handle);
AutoSafeJSContext cx;
if (!r->Dispatch(cx)) {
swm->RejectUpdatePromiseObservers(mRegistration, NS_ERROR_FAILURE);
@@ -1004,18 +1004,18 @@ ServiceWorkerManager::Install(ServiceWor
ServiceWorkerInfo* aServiceWorkerInfo)
{
AssertIsOnMainThread();
aRegistration->mInstallingWorker = aServiceWorkerInfo;
MOZ_ASSERT(aRegistration->mInstallingWorker);
InvalidateServiceWorkerContainerWorker(aRegistration,
WhichServiceWorker::INSTALLING_WORKER);
- nsMainThreadPtrHandle<ServiceWorkerRegistration> handle =
- new nsMainThreadPtrHolder<ServiceWorkerRegistration>(aRegistration);
+ nsMainThreadPtrHandle<ServiceWorkerRegistration> handle(
+ new nsMainThreadPtrHolder<ServiceWorkerRegistration>(aRegistration));
nsRefPtr<ServiceWorker> serviceWorker;
nsresult rv =
CreateServiceWorker(aServiceWorkerInfo->GetScriptSpec(),
aRegistration->mScope,
getter_AddRefs(serviceWorker));
if (NS_WARN_IF(NS_FAILED(rv))) {
@@ -1080,18 +1080,18 @@ public:
nsresult rv =
swm->CreateServiceWorker(mRegistration->mCurrentWorker->GetScriptSpec(),
mRegistration->mScope,
getter_AddRefs(serviceWorker));
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
- nsMainThreadPtrHandle<ServiceWorkerRegistration> handle =
- new nsMainThreadPtrHolder<ServiceWorkerRegistration>(mRegistration);
+ nsMainThreadPtrHandle<ServiceWorkerRegistration> handle(
+ new nsMainThreadPtrHolder<ServiceWorkerRegistration>(mRegistration));
nsRefPtr<ActivateEventRunnable> r =
new ActivateEventRunnable(serviceWorker->GetWorkerPrivate(), handle);
AutoSafeJSContext cx;
if (!r->Dispatch(cx)) {
return NS_ERROR_FAILURE;
}
--- a/dom/workers/WorkerPrivate.cpp
+++ b/dom/workers/WorkerPrivate.cpp
@@ -1542,42 +1542,33 @@ private:
mTimer->Cancel();
mTimer = nullptr;
}
return true;
}
};
-class UpdateRuntimeAndContextOptionsRunnable MOZ_FINAL : public WorkerControlRunnable
+class UpdateRuntimeOptionsRunnable MOZ_FINAL : public WorkerControlRunnable
{
JS::RuntimeOptions mRuntimeOptions;
- JS::ContextOptions mContentCxOptions;
- JS::ContextOptions mChromeCxOptions;
public:
- UpdateRuntimeAndContextOptionsRunnable(
+ UpdateRuntimeOptionsRunnable(
WorkerPrivate* aWorkerPrivate,
- const JS::RuntimeOptions& aRuntimeOptions,
- const JS::ContextOptions& aContentCxOptions,
- const JS::ContextOptions& aChromeCxOptions)
+ const JS::RuntimeOptions& aRuntimeOptions)
: WorkerControlRunnable(aWorkerPrivate, WorkerThreadUnchangedBusyCount),
- mRuntimeOptions(aRuntimeOptions),
- mContentCxOptions(aContentCxOptions),
- mChromeCxOptions(aChromeCxOptions)
+ mRuntimeOptions(aRuntimeOptions)
{ }
private:
virtual bool
WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) MOZ_OVERRIDE
{
- aWorkerPrivate->UpdateRuntimeAndContextOptionsInternal(aCx,
- mRuntimeOptions,
- mContentCxOptions,
- mChromeCxOptions);
+ aWorkerPrivate->UpdateRuntimeOptionsInternal(aCx, mRuntimeOptions);
return true;
}
};
class UpdatePreferenceRunnable MOZ_FINAL : public WorkerControlRunnable
{
WorkerPreference mPref;
bool mValue;
@@ -2876,36 +2867,29 @@ WorkerPrivateParent<Derived>::GetInnerWi
AssertIsOnMainThread();
NS_ASSERTION(!mLoadInfo.mWindow || mLoadInfo.mWindow->IsInnerWindow(),
"Outer window?");
return mLoadInfo.mWindow ? mLoadInfo.mWindow->WindowID() : 0;
}
template <class Derived>
void
-WorkerPrivateParent<Derived>::UpdateRuntimeAndContextOptions(
+WorkerPrivateParent<Derived>::UpdateRuntimeOptions(
JSContext* aCx,
- const JS::RuntimeOptions& aRuntimeOptions,
- const JS::ContextOptions& aContentCxOptions,
- const JS::ContextOptions& aChromeCxOptions)
+ const JS::RuntimeOptions& aRuntimeOptions)
{
AssertIsOnParentThread();
{
MutexAutoLock lock(mMutex);
mJSSettings.runtimeOptions = aRuntimeOptions;
- mJSSettings.content.contextOptions = aContentCxOptions;
- mJSSettings.chrome.contextOptions = aChromeCxOptions;
- }
-
- nsRefPtr<UpdateRuntimeAndContextOptionsRunnable> runnable =
- new UpdateRuntimeAndContextOptionsRunnable(ParentAsWorkerPrivate(),
- aRuntimeOptions,
- aContentCxOptions,
- aChromeCxOptions);
+ }
+
+ nsRefPtr<UpdateRuntimeOptionsRunnable> runnable =
+ new UpdateRuntimeOptionsRunnable(ParentAsWorkerPrivate(), aRuntimeOptions);
if (!runnable->Dispatch(aCx)) {
NS_WARNING("Failed to update worker context options!");
JS_ClearPendingException(aCx);
}
}
template <class Derived>
void
@@ -5529,31 +5513,26 @@ WorkerPrivate::RescheduleTimeoutTimer(JS
JS_ReportError(aCx, "Failed to start timer!");
return false;
}
return true;
}
void
-WorkerPrivate::UpdateRuntimeAndContextOptionsInternal(
+WorkerPrivate::UpdateRuntimeOptionsInternal(
JSContext* aCx,
- const JS::RuntimeOptions& aRuntimeOptions,
- const JS::ContextOptions& aContentCxOptions,
- const JS::ContextOptions& aChromeCxOptions)
+ const JS::RuntimeOptions& aRuntimeOptions)
{
AssertIsOnWorkerThread();
JS::RuntimeOptionsRef(aCx) = aRuntimeOptions;
- JS::ContextOptionsRef(aCx) = IsChromeWorker() ? aChromeCxOptions : aContentCxOptions;
for (uint32_t index = 0; index < mChildWorkers.Length(); index++) {
- mChildWorkers[index]->UpdateRuntimeAndContextOptions(aCx, aRuntimeOptions,
- aContentCxOptions,
- aChromeCxOptions);
+ mChildWorkers[index]->UpdateRuntimeOptions(aCx, aRuntimeOptions);
}
}
void
WorkerPrivate::UpdatePreferenceInternal(JSContext* aCx, WorkerPreference aPref, bool aValue)
{
AssertIsOnWorkerThread();
MOZ_ASSERT(aPref >= 0 && aPref < WORKERPREF_COUNT);
--- a/dom/workers/WorkerPrivate.h
+++ b/dom/workers/WorkerPrivate.h
@@ -388,20 +388,18 @@ public:
uint64_t aMessagePortSerial,
JSAutoStructuredCloneBuffer&& aBuffer,
nsTArray<nsCOMPtr<nsISupports>>& aClonedObjects);
uint64_t
GetInnerWindowId();
void
- UpdateRuntimeAndContextOptions(JSContext* aCx,
- const JS::RuntimeOptions& aRuntimeOptions,
- const JS::ContextOptions& aContentCxOptions,
- const JS::ContextOptions& aChromeCxOptions);
+ UpdateRuntimeOptions(JSContext* aCx,
+ const JS::RuntimeOptions& aRuntimeOptions);
void
UpdatePreference(JSContext* aCx, WorkerPreference aPref, bool aValue);
void
UpdateJSWorkerMemoryParameter(JSContext* aCx, JSGCParamKey key,
uint32_t value);
@@ -924,21 +922,17 @@ public:
void
CloseHandlerFinished()
{
AssertIsOnWorkerThread();
mCloseHandlerFinished = true;
}
void
- UpdateRuntimeAndContextOptionsInternal(
- JSContext* aCx,
- const JS::RuntimeOptions& aRuntimeOptions,
- const JS::ContextOptions& aContentCxOptions,
- const JS::ContextOptions& aChromeCxOptions);
+ UpdateRuntimeOptionsInternal(JSContext* aCx, const JS::RuntimeOptions& aRuntimeOptions);
void
UpdatePreferenceInternal(JSContext* aCx, WorkerPreference aPref, bool aValue);
void
UpdateJSWorkerMemoryParameterInternal(JSContext* aCx, JSGCParamKey key, uint32_t aValue);
enum WorkerRanOrNot {
--- a/dom/workers/Workers.h
+++ b/dom/workers/Workers.h
@@ -90,22 +90,21 @@ struct JSSettings
// There are several settings that we know we need so it makes sense to
// preallocate here.
typedef JSGCSetting JSGCSettingsArray[kGCSettingsArraySize];
// Settings that change based on chrome/content context.
struct JSContentChromeSettings
{
- JS::ContextOptions contextOptions;
JS::CompartmentOptions compartmentOptions;
int32_t maxScriptRuntime;
JSContentChromeSettings()
- : contextOptions(), compartmentOptions(), maxScriptRuntime(0)
+ : compartmentOptions(), maxScriptRuntime(0)
{ }
};
JSContentChromeSettings chrome;
JSContentChromeSettings content;
JSGCSettingsArray gcSettings;
JS::RuntimeOptions runtimeOptions;
new file mode 100644
--- /dev/null
+++ b/gfx/layers/AxisPhysicsMSDModel.cpp
@@ -0,0 +1,100 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set sw=2 ts=8 et 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 "AxisPhysicsMSDModel.h"
+#include <math.h> // for sqrt and fabs
+
+namespace mozilla {
+namespace layers {
+
+/**
+ * Constructs an AxisPhysicsMSDModel with initial values for state.
+ *
+ * @param aInitialPosition sets the initial position of the simulated spring,
+ * in AppUnits.
+ * @param aInitialDestination sets the resting position of the simulated spring,
+ * in AppUnits.
+ * @param aInitialVelocity sets the initial velocity of the simulated spring,
+ * in AppUnits / second. Critically-damped and over-damped systems are
+ * guaranteed not to overshoot aInitialDestination if this is set to 0;
+ * however, it is possible to overshoot and oscillate if not set to 0 or
+ * the system is under-damped.
+ * @param aSpringConstant sets the strength of the simulated spring. Greater
+ * values of mSpringConstant result in a stiffer / stronger spring.
+ * @param aDampingRatio controls the amount of dampening force and determines
+ * if the system is under-damped, critically-damped, or over-damped.
+ */
+AxisPhysicsMSDModel::AxisPhysicsMSDModel(double aInitialPosition,
+ double aInitialDestination,
+ double aInitialVelocity,
+ double aSpringConstant,
+ double aDampingRatio)
+ : AxisPhysicsModel(aInitialPosition, aInitialVelocity)
+ , mDestination(aInitialDestination)
+ , mSpringConstant(aSpringConstant)
+ , mSpringConstantSqrtXTwo(sqrt(mSpringConstant) * 2.0)
+ , mDampingRatio(aDampingRatio)
+{
+}
+
+AxisPhysicsMSDModel::~AxisPhysicsMSDModel()
+{
+}
+
+double
+AxisPhysicsMSDModel::Acceleration(const State &aState)
+{
+ // Simulate a Mass-Damper-Spring Model; assume a unit mass
+
+ // Hooke’s Law: http://en.wikipedia.org/wiki/Hooke%27s_law
+ double spring_force = (mDestination - aState.p) * mSpringConstant;
+ double damp_force = -aState.v * mDampingRatio * mSpringConstantSqrtXTwo;
+
+ return spring_force + damp_force;
+}
+
+
+double
+AxisPhysicsMSDModel::GetDestination()
+{
+ return mDestination;
+}
+
+void
+AxisPhysicsMSDModel::SetDestination(double aDestination)
+{
+ mDestination = aDestination;
+}
+
+bool
+AxisPhysicsMSDModel::IsFinished()
+{
+ // In order to satisfy the condition of reaching the destination, the distance
+ // between the simulation position and the destination must be less than
+ // kFinishDistance while the speed is simultaneously less than
+ // kFinishVelocity. This enables an under-damped system to overshoot the
+ // destination when desired without prematurely triggering the finished state.
+
+ // As the number of app units per css pixel is 60 and retina / HiDPI displays
+ // may display two pixels for every css pixel, setting kFinishDistance to 30.0
+ // ensures that there will be no perceptable shift in position at the end
+ // of the animation.
+ const double kFinishDistance = 30.0;
+
+ // If kFinishVelocity is set too low, the animation may end long after
+ // oscillation has finished, resulting in unnecessary processing.
+ // If set too high, the animation may prematurely terminate when expected
+ // to overshoot the destination in an under-damped system.
+ // 60.0 was selected through experimentation that revealed that a
+ // critically damped system will terminate within 100ms.
+ const double kFinishVelocity = 60.0;
+
+ return fabs(mDestination - GetPosition ()) < kFinishDistance
+ && fabs(GetVelocity()) <= kFinishVelocity;
+}
+
+}
+}
new file mode 100644
--- /dev/null
+++ b/gfx/layers/AxisPhysicsMSDModel.h
@@ -0,0 +1,86 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set sw=2 ts=8 et 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_layers_AxisPhysicsMSDModel_h
+#define mozilla_layers_AxisPhysicsMSDModel_h
+
+#include "AxisPhysicsModel.h"
+
+namespace mozilla {
+namespace layers {
+
+/**
+ * AxisPhysicsMSDModel encapsulates a 1-dimensional MSD (Mass-Spring-Damper)
+ * model. A unit mass is assumed.
+ */
+class AxisPhysicsMSDModel : public AxisPhysicsModel {
+public:
+ AxisPhysicsMSDModel(double aInitialPosition, double aInitialDestination,
+ double aInitialVelocity, double aSpringConstant,
+ double aDampingRatio);
+
+ ~AxisPhysicsMSDModel();
+
+ /**
+ * Gets the raw destination of this axis at this moment.
+ */
+ double GetDestination();
+
+ /**
+ * Sets the raw destination of this axis at this moment.
+ */
+ void SetDestination(double aDestination);
+
+ /**
+ * Returns true when the position is close to the destination and the
+ * velocity is low.
+ */
+ bool IsFinished();
+
+protected:
+ virtual double Acceleration(const State &aState);
+
+private:
+
+ /**
+ * mDestination represents the target position and the resting position of
+ * the simulated spring.
+ */
+ double mDestination;
+
+ /**
+ * Greater values of mSpringConstant result in a stiffer / stronger spring.
+ */
+ double mSpringConstant;
+
+ /**
+ * mSpringConstantSqrtTimesTwo is calculated from mSpringConstant to reduce
+ * calculations performed in the inner loop.
+ */
+ double mSpringConstantSqrtXTwo;
+
+ /**
+ * Damping Ratio: http://en.wikipedia.org/wiki/Damping_ratio
+ *
+ * When mDampingRatio < 1.0, this is an under damped system.
+ * - Overshoots destination and oscillates with the amplitude gradually
+ * decreasing to zero.
+ *
+ * When mDampingRatio == 1.0, this is a critically damped system.
+ * - Reaches destination as quickly as possible without oscillating.
+ *
+ * When mDampingRatio > 1.0, this is an over damped system.
+ * - Reaches destination (exponentially decays) without oscillating.
+ */
+ double mDampingRatio;
+
+};
+
+
+}
+}
+
+#endif
new file mode 100644
--- /dev/null
+++ b/gfx/layers/AxisPhysicsModel.cpp
@@ -0,0 +1,121 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set sw=2 ts=8 et 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 "AxisPhysicsModel.h"
+
+namespace mozilla {
+namespace layers {
+
+/**
+ * The simulation is advanced forward in time with a fixed time step to ensure
+ * that it remains deterministic given variable framerates. To determine the
+ * position at any variable time, two samples are interpolated.
+ *
+ * kFixedtimestep is set to 120hz in order to ensure that every frame in a
+ * common 60hz refresh rate display will have at least one physics simulation
+ * sample. More accuracy can be obtained by reducing kFixedTimestep to smaller
+ * intervals, such as 240hz or 1000hz, at the cost of more CPU cycles. If
+ * kFixedTimestep is increased to much longer intervals, interpolation will
+ * become less effective at reducing temporal jitter and the simulation will
+ * lose accuracy.
+ */
+const double AxisPhysicsModel::kFixedTimestep = 1.0 / 120.0; // 120hz
+
+/**
+ * Constructs an AxisPhysicsModel with initial values for state.
+ *
+ * @param aInitialPosition sets the initial position of the simulation,
+ * in AppUnits.
+ * @param aInitialVelocity sets the initial velocity of the simulation,
+ * in AppUnits / second.
+ */
+AxisPhysicsModel::AxisPhysicsModel(double aInitialPosition,
+ double aInitialVelocity)
+ : mProgress(1.0)
+ , mPrevState(aInitialPosition, aInitialVelocity)
+ , mNextState(aInitialPosition, aInitialVelocity)
+{
+
+}
+
+AxisPhysicsModel::~AxisPhysicsModel()
+{
+
+}
+
+double
+AxisPhysicsModel::GetVelocity()
+{
+ return LinearInterpolate(mPrevState.v, mNextState.v, mProgress);
+}
+
+double
+AxisPhysicsModel::GetPosition()
+{
+ return LinearInterpolate(mPrevState.p, mNextState.p, mProgress);
+}
+
+void
+AxisPhysicsModel::SetVelocity(double aVelocity)
+{
+ mNextState.v = aVelocity;
+ mNextState.p = GetPosition();
+ mProgress = 1.0;
+}
+
+void
+AxisPhysicsModel::SetPosition(double aPosition)
+{
+ mNextState.v = GetVelocity();
+ mNextState.p = aPosition;
+ mProgress = 1.0;
+}
+
+void
+AxisPhysicsModel::Simulate(const TimeDuration& aDeltaTime)
+{
+ for(mProgress += aDeltaTime.ToSeconds() / kFixedTimestep;
+ mProgress > 1.0; mProgress -= 1.0) {
+ Integrate(kFixedTimestep);
+ }
+}
+
+void
+AxisPhysicsModel::Integrate(double aDeltaTime)
+{
+ mPrevState = mNextState;
+
+ // RK4 (Runge-Kutta method) Integration
+ // http://en.wikipedia.org/wiki/Runge%E2%80%93Kutta_methods
+ Derivative a = Evaluate( mNextState, 0.0, Derivative() );
+ Derivative b = Evaluate( mNextState, aDeltaTime * 0.5, a );
+ Derivative c = Evaluate( mNextState, aDeltaTime * 0.5, b );
+ Derivative d = Evaluate( mNextState, aDeltaTime, c );
+
+ double dpdt = 1.0 / 6.0 * (a.dp + 2.0 * (b.dp + c.dp) + d.dp);
+ double dvdt = 1.0 / 6.0 * (a.dv + 2.0 * (b.dv + c.dv) + d.dv);
+
+ mNextState.p += dpdt * aDeltaTime;
+ mNextState.v += dvdt * aDeltaTime;
+}
+
+AxisPhysicsModel::Derivative
+AxisPhysicsModel::Evaluate(const State &aInitState, double aDeltaTime,
+ const Derivative &aDerivative)
+{
+ State state( aInitState.p + aDerivative.dp*aDeltaTime, aInitState.v + aDerivative.dv*aDeltaTime );
+
+ return Derivative( state.v, Acceleration(state) );
+}
+
+double
+AxisPhysicsModel::LinearInterpolate(double aV1, double aV2, double aBlend)
+{
+ return aV1 * (1.0 - aBlend) + aV2 * aBlend;
+}
+
+}
+}
new file mode 100644
--- /dev/null
+++ b/gfx/layers/AxisPhysicsModel.h
@@ -0,0 +1,131 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set sw=2 ts=8 et 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_layers_AxisPhysicsModel_h
+#define mozilla_layers_AxisPhysicsModel_h
+
+#include "AxisPhysicsModel.h"
+#include <sys/types.h> // for int32_t
+#include "mozilla/TimeStamp.h" // for TimeDuration
+
+namespace mozilla {
+namespace layers {
+
+
+/**
+ * AxisPhysicsModel encapsulates a generic 1-dimensional physically-based motion
+ * model.
+ *
+ * It performs frame-rate independent interpolation and RK4 integration for
+ * smooth animation with stable, deterministic behavior.
+ * Implementations are expected to subclass and override the Acceleration()
+ * method.
+ */
+class AxisPhysicsModel {
+public:
+ AxisPhysicsModel(double aInitialPosition, double aInitialVelocity);
+ ~AxisPhysicsModel();
+
+ /**
+ * Advance the physics simulation.
+ * |aDelta| is the time since the last sample.
+ */
+ void Simulate(const TimeDuration& aDeltaTime);
+
+ /**
+ * Gets the raw velocity of this axis at this moment.
+ */
+ double GetVelocity();
+
+ /**
+ * Sets the raw velocity of this axis at this moment.
+ */
+ void SetVelocity(double aVelocity);
+
+ /**
+ * Gets the raw position of this axis at this moment.
+ */
+ double GetPosition();
+
+ /**
+ * Sets the raw position of this axis at this moment.
+ */
+ void SetPosition(double aPosition);
+
+protected:
+
+ struct State
+ {
+ State(double ap, double av) : p(ap), v(av) {};
+ double p; // Position
+ double v; // Velocity
+ };
+
+ struct Derivative
+ {
+ Derivative() : dp(0.0), dv(0.0) {};
+ Derivative(double aDp, double aDv) : dp(aDp), dv(aDv) {};
+ double dp; // dp / delta time = Position
+ double dv; // dv / delta time = Velocity
+ };
+
+ /**
+ * Acceleration must be overridden and return the number of
+ * axis-position-units / second that should be added or removed from the
+ * velocity.
+ */
+ virtual double Acceleration(const State &aState) = 0;
+
+private:
+
+ /**
+ * Duration of fixed delta time step (seconds)
+ */
+ static const double kFixedTimestep;
+
+ /**
+ * 0.0 - 1.0 value indicating progress between current and next simulation
+ * sample. Normalized to units of kFixedTimestep duration.
+ */
+ double mProgress;
+
+ /**
+ * Sample of simulation state as it existed
+ * (1.0 - mProgress) * kFixedTimestep seconds in the past.
+ */
+ State mPrevState;
+
+ /**
+ * Sample of simulation state as it will be in mProgress * kFixedTimestep
+ * seconds in the future.
+ */
+ State mNextState;
+
+ /**
+ * Perform RK4 (Runge-Kutta method) Integration to calculate the next
+ * simulation sample.
+ */
+ void Integrate(double aDeltaTime);
+
+ /**
+ * Apply delta velocity and position represented by aDerivative over
+ * aDeltaTime seconds, calculate new acceleration, and return new deltas.
+ */
+ Derivative Evaluate(const State &aInitState, double aDeltaTime,
+ const Derivative &aDerivative);
+
+ /**
+ * Helper function for performing linear interpolation (lerp) of double's
+ */
+ static double LinearInterpolate(double aV1, double aV2, double aBlend);
+
+};
+
+
+}
+}
+
+#endif
--- a/gfx/layers/moz.build
+++ b/gfx/layers/moz.build
@@ -110,16 +110,18 @@ EXPORTS.mozilla.layers += [
'apz/src/AsyncPanZoomController.h',
'apz/src/Axis.h',
'apz/src/GestureEventListener.h',
'apz/src/TaskThrottler.h',
'apz/testutil/APZTestData.h',
'apz/util/ActiveElementManager.h',
'apz/util/APZCCallbackHelper.h',
'AtomicRefCountedWithFinalize.h',
+ 'AxisPhysicsModel.h',
+ 'AxisPhysicsMSDModel.h',
'basic/BasicCompositor.h',
'basic/MacIOSurfaceTextureHostBasic.h',
'basic/TextureHostBasic.h',
'client/CanvasClient.h',
'client/CompositableClient.h',
'client/ContentClient.h',
'client/ImageClient.h',
'client/SimpleTextureClientPool.h',
@@ -236,16 +238,18 @@ UNIFIED_SOURCES += [
'apz/src/AsyncPanZoomController.cpp',
'apz/src/Axis.cpp',
'apz/src/GestureEventListener.cpp',
'apz/src/TaskThrottler.cpp',
'apz/src/TouchBlockState.cpp',
'apz/testutil/APZTestData.cpp',
'apz/util/ActiveElementManager.cpp',
'apz/util/APZCCallbackHelper.cpp',
+ 'AxisPhysicsModel.cpp',
+ 'AxisPhysicsMSDModel.cpp',
'basic/BasicCanvasLayer.cpp',
'basic/BasicColorLayer.cpp',
'basic/BasicCompositor.cpp',
'basic/BasicContainerLayer.cpp',
'basic/BasicImages.cpp',
'basic/BasicLayerManager.cpp',
'basic/BasicLayersImpl.cpp',
'basic/BasicThebesLayer.cpp',
--- a/gfx/thebes/gfxPrefs.h
+++ b/gfx/thebes/gfxPrefs.h
@@ -245,16 +245,19 @@ private:
DECL_GFX_PREF(Once, "layers.use-image-offscreen-surfaces", UseImageOffscreenSurfaces, bool, false);
DECL_GFX_PREF(Live, "layers.orientation.sync.timeout", OrientationSyncMillis, uint32_t, (uint32_t)0);
DECL_GFX_PREF(Once, "layers.prefer-d3d9", LayersPreferD3D9, bool, false);
DECL_GFX_PREF(Once, "layers.prefer-opengl", LayersPreferOpenGL, bool, false);
DECL_GFX_PREF(Once, "layers.progressive-paint", UseProgressiveTilePainting, bool, false);
DECL_GFX_PREF(Once, "layers.scroll-graph", LayersScrollGraph, bool, false);
DECL_GFX_PREF(Once, "layers.uniformity-info", UniformityInfo, bool, false);
+ DECL_GFX_PREF(Live, "layout.css.scroll-behavior.damping-ratio", ScrollBehaviorDampingRatio, float, 1.0f);
+ DECL_GFX_PREF(Live, "layout.css.scroll-behavior.enabled", ScrollBehaviorEnabled, bool, false);
+ DECL_GFX_PREF(Live, "layout.css.scroll-behavior.spring-constant", ScrollBehaviorSpringConstant, float, 250.0f);
DECL_GFX_PREF(Once, "layout.css.touch_action.enabled", TouchActionEnabled, bool, false);
DECL_GFX_PREF(Once, "layout.frame_rate", LayoutFrameRate, int32_t, -1);
DECL_GFX_PREF(Live, "layout.display-list.dump", LayoutDumpDisplayList, bool, false);
DECL_GFX_PREF(Once, "layout.paint_rects_separately", LayoutPaintRectsSeparately, bool, true);
DECL_GFX_PREF(Live, "nglayout.debug.widget_update_flashing", WidgetUpdateFlashing, bool, false);
DECL_GFX_PREF(Live, "ui.click_hold_context_menus.delay", UiClickHoldContextMenusDelay, int32_t, 500);
--- a/js/public/HeapAPI.h
+++ b/js/public/HeapAPI.h
@@ -106,57 +106,57 @@ const uint32_t DefaultHeapMaxBytes = 32
/*
* We cannot expose the class hierarchy: the implementation is hidden. Instead
* we provide cast functions with strong debug-mode assertions.
*/
static MOZ_ALWAYS_INLINE js::gc::Cell *
AsCell(JSObject *obj)
{
js::gc::Cell *cell = reinterpret_cast<js::gc::Cell *>(obj);
- AssertGCThingHasType(cell, JSTRACE_OBJECT);
+ js::gc::AssertGCThingHasType(cell, JSTRACE_OBJECT);
return cell;
}
static MOZ_ALWAYS_INLINE js::gc::Cell *
AsCell(JSFunction *fun)
{
js::gc::Cell *cell = reinterpret_cast<js::gc::Cell *>(fun);
- AssertGCThingHasType(cell, JSTRACE_OBJECT);
+ js::gc::AssertGCThingHasType(cell, JSTRACE_OBJECT);
return cell;
}
static MOZ_ALWAYS_INLINE js::gc::Cell *
AsCell(JSString *str)
{
js::gc::Cell *cell = reinterpret_cast<js::gc::Cell *>(str);
- AssertGCThingHasType(cell, JSTRACE_STRING);
+ js::gc::AssertGCThingHasType(cell, JSTRACE_STRING);
return cell;
}
static MOZ_ALWAYS_INLINE js::gc::Cell *
AsCell(JSFlatString *flat)
{
js::gc::Cell *cell = reinterpret_cast<js::gc::Cell *>(flat);
- AssertGCThingHasType(cell, JSTRACE_STRING);
+ js::gc::AssertGCThingHasType(cell, JSTRACE_STRING);
return cell;
}
static MOZ_ALWAYS_INLINE js::gc::Cell *
AsCell(JS::Symbol *sym)
{
js::gc::Cell *cell = reinterpret_cast<js::gc::Cell *>(sym);
- AssertGCThingHasType(cell, JSTRACE_SYMBOL);
+ js::gc::AssertGCThingHasType(cell, JSTRACE_SYMBOL);
return cell;
}
static MOZ_ALWAYS_INLINE js::gc::Cell *
AsCell(JSScript *script)
{
js::gc::Cell *cell = reinterpret_cast<js::gc::Cell *>(script);
- AssertGCThingHasType(cell, JSTRACE_SCRIPT);
+ js::gc::AssertGCThingHasType(cell, JSTRACE_SCRIPT);
return cell;
}
namespace shadow {
struct ArenaHeader
{
JS::Zone *zone;
@@ -284,16 +284,17 @@ GetTenuredGCThingZone(void *thing)
}
extern JS_PUBLIC_API(Zone *)
GetObjectZone(JSObject *obj);
static MOZ_ALWAYS_INLINE bool
GCThingIsMarkedGray(void *thing)
{
+ MOZ_ASSERT(thing);
#ifdef JSGC_GENERATIONAL
/*
* GC things residing in the nursery cannot be gray: they have no mark bits.
* All live objects in the nursery are moved to tenured at the beginning of
* each GC slice, so the gray marker never sees nursery things.
*/
if (js::gc::IsInsideNursery((js::gc::Cell *)thing))
return false;
@@ -301,16 +302,20 @@ GCThingIsMarkedGray(void *thing)
uintptr_t *word, mask;
js::gc::GetGCThingMarkWordAndMask(thing, js::gc::GRAY, &word, &mask);
return *word & mask;
}
static MOZ_ALWAYS_INLINE bool
IsIncrementalBarrierNeededOnTenuredGCThing(shadow::Runtime *rt, void *thing, JSGCTraceKind kind)
{
+ MOZ_ASSERT(thing);
+#ifdef JSGC_GENERATIONAL
+ MOZ_ASSERT(!js::gc::IsInsideNursery((js::gc::Cell *)thing));
+#endif
if (!rt->needsBarrier_)
return false;
JS::Zone *zone = GetTenuredGCThingZone(thing);
return reinterpret_cast<shadow::Zone *>(zone)->needsBarrier_;
}
} /* namespace JS */
--- a/js/public/RootingAPI.h
+++ b/js/public/RootingAPI.h
@@ -98,18 +98,16 @@
* +---> MutableHandle<T>
* (via &)
*
* All of these types have an implicit conversion to raw pointers.
*/
namespace js {
-class ScriptSourceObject;
-
template <typename T>
struct GCMethods {};
template <typename T>
class RootedBase {};
template <typename T>
class HandleBase {};
--- a/js/public/Value.h
+++ b/js/public/Value.h
@@ -1335,28 +1335,16 @@ class Value
}
friend jsval_layout (::JSVAL_TO_IMPL)(Value);
friend Value JS_VALUE_CONSTEXPR (::IMPL_TO_JSVAL)(jsval_layout l);
friend Value JS_VALUE_CONSTEXPR (JS::UndefinedValue)();
};
inline bool
-IsPoisonedValue(const Value &v)
-{
- if (v.isString())
- return IsPoisonedPtr(v.toString());
- if (v.isSymbol())
- return IsPoisonedPtr(v.toSymbol());
- if (v.isObject())
- return IsPoisonedPtr(&v.toObject());
- return false;
-}
-
-inline bool
IsOptimizedPlaceholderMagicValue(const Value &v)
{
if (v.isMagic()) {
MOZ_ASSERT(v.whyMagic() == JS_OPTIMIZED_ARGUMENTS || v.whyMagic() == JS_OPTIMIZED_OUT);
return true;
}
return false;
}
@@ -1633,23 +1621,27 @@ JS_PUBLIC_API(void) HeapValueRelocate(Va
}
#endif
namespace js {
template <> struct GCMethods<const JS::Value>
{
static JS::Value initial() { return JS::UndefinedValue(); }
- static bool poisoned(const JS::Value &v) { return JS::IsPoisonedValue(v); }
+ static bool poisoned(const JS::Value &v) {
+ return v.isMarkable() && JS::IsPoisonedPtr(v.toGCThing());
+ }
};
template <> struct GCMethods<JS::Value>
{
static JS::Value initial() { return JS::UndefinedValue(); }
- static bool poisoned(const JS::Value &v) { return JS::IsPoisonedValue(v); }
+ static bool poisoned(const JS::Value &v) {
+ return v.isMarkable() && JS::IsPoisonedPtr(v.toGCThing());
+ }
static bool needsPostBarrier(const JS::Value &v) {
return v.isObject() && gc::IsInsideNursery(reinterpret_cast<gc::Cell*>(&v.toObject()));
}
#ifdef JSGC_GENERATIONAL
static void postBarrier(JS::Value *v) { JS::HeapValuePostBarrier(v); }
static void relocate(JS::Value *v) { JS::HeapValueRelocate(v); }
#endif
};
@@ -1859,16 +1851,22 @@ IMPL_TO_JSVAL(jsval_layout l)
JS::Value v;
v.data = l;
return v;
#endif
}
namespace JS {
+inline bool
+IsPoisonedValue(const Value &v)
+{
+ return js::GCMethods<Value>::poisoned(v);
+}
+
#ifndef __GNUC__
/*
* The default assignment operator for |struct C| has the signature:
*
* C& C::operator=(const C&)
*
* And in particular requires implicit conversion of |this| to type |C| for the
* return value. But |volatile C| cannot thus be converted to |C|, so just
--- a/js/src/assembler/assembler/AssemblerBuffer.h
+++ b/js/src/assembler/assembler/AssemblerBuffer.h
@@ -285,60 +285,50 @@ namespace JSC {
printer = sp;
}
void spew(const char *fmt, ...)
#ifdef __GNUC__
__attribute__ ((format (printf, 2, 3)))
#endif
{
- if (printer
-#ifdef JS_ION
- || js::jit::IonSpewEnabled(js::jit::IonSpew_Codegen)
-#endif
- )
- {
+ if (printer || js::jit::IonSpewEnabled(js::jit::IonSpew_Codegen)) {
// Buffer to hold the formatted string. Note that this may contain
// '%' characters, so do not pass it directly to printf functions.
char buf[200];
va_list va;
va_start(va, fmt);
int i = vsnprintf(buf, sizeof(buf), fmt, va);
va_end(va);
if (i > -1) {
if (printer)
printer->printf("%s\n", buf);
-
-#ifdef JS_ION
js::jit::IonSpew(js::jit::IonSpew_Codegen, "%s", buf);
-#endif
}
}
}
static void staticSpew(const char *fmt, ...)
#ifdef __GNUC__
__attribute__ ((format (printf, 1, 2)))
#endif
{
-#ifdef JS_ION
if (js::jit::IonSpewEnabled(js::jit::IonSpew_Codegen)) {
char buf[200];
va_list va;
va_start(va, fmt);
int i = vsnprintf(buf, sizeof(buf), fmt, va);
va_end(va);
if (i > -1)
js::jit::IonSpew(js::jit::IonSpew_Codegen, "%s", buf);
}
-#endif
}
};
} // namespace JSC
#endif // ENABLE(ASSEMBLER)
#endif /* assembler_assembler_AssemblerBuffer_h */
--- a/js/src/builtin/TestingFunctions.cpp
+++ b/js/src/builtin/TestingFunctions.cpp
@@ -1102,17 +1102,17 @@ DisableSPSProfiling(JSContext *cx, unsig
args.rval().setUndefined();
return true;
}
static bool
EnableOsiPointRegisterChecks(JSContext *, unsigned argc, jsval *vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
-#if defined(JS_ION) && defined(CHECK_OSIPOINT_REGISTERS)
+#ifdef CHECK_OSIPOINT_REGISTERS
jit::js_JitOptions.checkOsiPointRegisters = true;
#endif
args.rval().setUndefined();
return true;
}
static bool
DisplayName(JSContext *cx, unsigned argc, jsval *vp)
@@ -1320,19 +1320,17 @@ GetJitCompilerOptions(JSContext *cx, uns
return true;
}
static bool
SetIonCheckGraphCoherency(JSContext *cx, unsigned argc, jsval *vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
-#ifdef JS_ION
jit::js_JitOptions.checkGraphConsistency = ToBoolean(args.get(0));
-#endif
args.rval().setUndefined();
return true;
}
class CloneBufferObject : public JSObject {
static const JSPropertySpec props_[2];
static const size_t DATA_SLOT = 0;
static const size_t LENGTH_SLOT = 1;
--- a/js/src/configure.in
+++ b/js/src/configure.in
@@ -2019,18 +2019,16 @@ esac
MOZ_ARG_DISABLE_BOOL(ion,
[ --disable-ion Disable use of the IonMonkey JIT],
ENABLE_ION= )
AC_SUBST(ENABLE_METHODJIT_SPEW)
AC_SUBST(ENABLE_ION)
-AC_DEFINE(JS_ION)
-
if test -n "$COMPILE_ENVIRONMENT"; then
MOZ_COMPILER_OPTS
fi
if test -z "$SKIP_COMPILER_CHECKS"; then
dnl Checks for typedefs, structures, and compiler characteristics.
dnl ========================================================
AC_HEADER_STDC
--- a/js/src/frontend/BytecodeCompiler.h
+++ b/js/src/frontend/BytecodeCompiler.h
@@ -11,16 +11,17 @@
class JSLinearString;
namespace js {
class AutoNameVector;
class LazyScript;
class LifoAlloc;
+class ScriptSourceObject;
struct SourceCompressionTask;
namespace frontend {
JSScript *
CompileScript(ExclusiveContext *cx, LifoAlloc *alloc,
HandleObject scopeChain, HandleScript evalCaller,
const ReadOnlyCompileOptions &options, SourceBufferHolder &srcBuf,
--- a/js/src/frontend/Parser.cpp
+++ b/js/src/frontend/Parser.cpp
@@ -2539,30 +2539,28 @@ Parser<FullParseHandler>::asmJS(Node lis
// If there is no ScriptSource, then we are doing a non-compiling parse and
// so we shouldn't (and can't, without a ScriptSource) compile.
if (ss == nullptr)
return true;
pc->sc->asFunctionBox()->useAsm = true;
-#ifdef JS_ION
// Attempt to validate and compile this asm.js module. On success, the
// tokenStream has been advanced to the closing }. On failure, the
// tokenStream is in an indeterminate state and we must reparse the
// function from the beginning. Reparsing is triggered by marking that a
// new directive has been encountered and returning 'false'.
bool validated;
if (!CompileAsmJS(context, *this, list, &validated))
return false;
if (!validated) {
pc->newDirectives->setAsmJS();
return false;
}
-#endif
return true;
}
/*
* Recognize Directive Prologue members and directives. Assuming |pn| is a
* candidate for membership in a directive prologue, recognize directives and
* set |pc|'s flags accordingly. If |pn| is indeed part of a prologue, set its
--- a/js/src/gc/Barrier.h
+++ b/js/src/gc/Barrier.h
@@ -781,16 +781,17 @@ class ReadBarriered
void set(T v) { value = v; }
};
class ArrayBufferObject;
class NestedScopeObject;
class DebugScopeObject;
class GlobalObject;
+class ScriptSourceObject;
class Shape;
class BaseShape;
class UnownedBaseShape;
namespace jit {
class JitCode;
}
namespace types {
struct TypeObject;
--- a/js/src/gc/ForkJoinNursery.cpp
+++ b/js/src/gc/ForkJoinNursery.cpp
@@ -250,19 +250,17 @@ ForkJoinNursery::pjsCollection(int op)
if (!initNewspace())
CrashAtUnhandlableOOM("Cannot expand PJS nursery during GC");
// newspace must be at least as large as fromSpace
numActiveChunks_ = currentNumActiveChunks_;
}
ForkJoinNurseryCollectionTracer trc(rt, this);
forwardFromRoots(&trc);
collectToFixedPoint(&trc);
-#ifdef JS_ION
jit::UpdateJitActivationsForMinorGC<ForkJoinNursery>(TlsPerThreadData.get(), &trc);
-#endif
freeFromspace();
size_t live = movedSize_;
computeNurserySizeAfterGC(live, &msg);
sweepHugeSlots();
JS_ASSERT(hugeSlots[hugeSlotsFrom].empty());
JS_ASSERT_IF(isEvacuating_, hugeSlots[hugeSlotsNew].empty());
--- a/js/src/gc/ForkJoinNursery.h
+++ b/js/src/gc/ForkJoinNursery.h
@@ -8,19 +8,16 @@
#ifndef gc_ForkJoinNursery_h
#define gc_ForkJoinNursery_h
#ifdef JSGC_FJGENERATIONAL
#ifndef JSGC_GENERATIONAL
#error "JSGC_GENERATIONAL is required for the ForkJoinNursery"
#endif
-#ifndef JS_ION
-#error "JS_ION is required for the ForkJoinNursery"
-#endif
#include "jsalloc.h"
#include "jspubtd.h"
#include "gc/Heap.h"
#include "gc/Memory.h"
#include "gc/Nursery.h"
--- a/js/src/gc/GCRuntime.h
+++ b/js/src/gc/GCRuntime.h
@@ -99,16 +99,136 @@ struct ConservativeGCData
nativeStackTop = nullptr;
}
bool hasStackToScan() const {
return !!nativeStackTop;
}
};
+/*
+ * Encapsulates all of the GC tunables. These are effectively constant and
+ * should only be modified by setParameter.
+ */
+class GCSchedulingTunables
+{
+ /*
+ * Soft limit on the number of bytes we are allowed to allocate in the GC
+ * heap. Attempts to allocate gcthings over this limit will return null and
+ * subsequently invoke the standard OOM machinery, independent of available
+ * physical memory.
+ */
+ size_t gcMaxBytes_;
+
+ /*
+ * The base value used to compute zone->trigger.gcBytes(). When
+ * usage.gcBytes() surpasses threshold.gcBytes() for a zone, the zone may
+ * be scheduled for a GC, depending on the exact circumstances.
+ */
+ size_t gcZoneAllocThresholdBase_;
+
+ /*
+ * Totally disables |highFrequencyGC|, the HeapGrowthFactor, and other
+ * tunables that make GC non-deterministic.
+ */
+ bool dynamicHeapGrowthEnabled_;
+
+ /*
+ * We enter high-frequency mode if we GC a twice within this many
+ * microseconds. This value is stored directly in microseconds.
+ */
+ uint64_t highFrequencyThresholdUsec_;
+
+ /*
+ * When in the |highFrequencyGC| mode, these parameterize the per-zone
+ * "HeapGrowthFactor" computation.
+ */
+ uint64_t highFrequencyLowLimitBytes_;
+ uint64_t highFrequencyHighLimitBytes_;
+ double highFrequencyHeapGrowthMax_;
+ double highFrequencyHeapGrowthMin_;
+
+ /*
+ * When not in |highFrequencyGC| mode, this is the global (stored per-zone)
+ * "HeapGrowthFactor".
+ */
+ double lowFrequencyHeapGrowth_;
+
+ /*
+ * Doubles the length of IGC slices when in the |highFrequencyGC| mode.
+ */
+ bool dynamicMarkSliceEnabled_;
+
+ /*
+ * Controls the number of empty chunks reserved for future allocation.
+ */
+ unsigned minEmptyChunkCount_;
+ unsigned maxEmptyChunkCount_;
+
+ public:
+ GCSchedulingTunables()
+ : gcMaxBytes_(0),
+ gcZoneAllocThresholdBase_(30 * 1024 * 1024),
+ dynamicHeapGrowthEnabled_(false),
+ highFrequencyThresholdUsec_(1000 * 1000),
+ highFrequencyLowLimitBytes_(100 * 1024 * 1024),
+ highFrequencyHighLimitBytes_(500 * 1024 * 1024),
+ highFrequencyHeapGrowthMax_(3.0),
+ highFrequencyHeapGrowthMin_(1.5),
+ lowFrequencyHeapGrowth_(1.5),
+ dynamicMarkSliceEnabled_(false),
+ minEmptyChunkCount_(1),
+ maxEmptyChunkCount_(30)
+ {}
+
+ size_t gcMaxBytes() const { return gcMaxBytes_; }
+ size_t gcZoneAllocThresholdBase() const { return gcZoneAllocThresholdBase_; }
+ bool isDynamicHeapGrowthEnabled() const { return dynamicHeapGrowthEnabled_; }
+ uint64_t highFrequencyThresholdUsec() const { return highFrequencyThresholdUsec_; }
+ uint64_t highFrequencyLowLimitBytes() const { return highFrequencyLowLimitBytes_; }
+ uint64_t highFrequencyHighLimitBytes() const { return highFrequencyHighLimitBytes_; }
+ double highFrequencyHeapGrowthMax() const { return highFrequencyHeapGrowthMax_; }
+ double highFrequencyHeapGrowthMin() const { return highFrequencyHeapGrowthMin_; }
+ double lowFrequencyHeapGrowth() const { return lowFrequencyHeapGrowth_; }
+ bool isDynamicMarkSliceEnabled() const { return dynamicMarkSliceEnabled_; }
+ unsigned minEmptyChunkCount() const { return minEmptyChunkCount_; }
+ unsigned maxEmptyChunkCount() const { return maxEmptyChunkCount_; }
+
+ void setParameter(JSGCParamKey key, uint32_t value);
+};
+
+/*
+ * Internal values that effect GC scheduling that are not directly exposed
+ * in the GC API.
+ */
+class GCSchedulingState
+{
+ /*
+ * Influences how we schedule and run GC's in several subtle ways. The most
+ * important factor is in how it controls the "HeapGrowthFactor". The
+ * growth factor is a measure of how large (as a percentage of the last GC)
+ * the heap is allowed to grow before we try to schedule another GC.
+ */
+ bool inHighFrequencyGCMode_;
+
+ public:
+ GCSchedulingState()
+ : inHighFrequencyGCMode_(false)
+ {}
+
+ bool inHighFrequencyGCMode() const { return inHighFrequencyGCMode_; }
+
+ void updateHighFrequencyMode(uint64_t lastGCTime, uint64_t currentTime,
+ const GCSchedulingTunables &tunables) {
+ inHighFrequencyGCMode_ =
+ tunables.isDynamicHeapGrowthEnabled() && lastGCTime &&
+ lastGCTime + tunables.highFrequencyThresholdUsec() > currentTime;
+ }
+};
+
template<typename F>
struct Callback {
F op;
void *data;
Callback()
: op(nullptr), data(nullptr)
{}
@@ -177,17 +297,16 @@ class GCRuntime
void verifyPostBarriers();
void maybeVerifyPreBarriers(bool always);
void maybeVerifyPostBarriers(bool always);
bool selectForMarking(JSObject *object);
void clearSelectedForMarking();
void setDeterministic(bool enable);
#endif
- size_t maxBytesAllocated() { return maxBytes; }
size_t maxMallocBytesAllocated() { return maxMallocBytes; }
public:
// Internal public interface
js::gc::State state() { return incrementalState; }
void recordNativeStackTop();
void notifyRequestEnd() { conservativeGC.updateForRequestEnd(); }
bool isBackgroundSweeping() { return helperState.isBackgroundSweeping(); }
@@ -298,17 +417,16 @@ class GCRuntime
bool areGrayBitsValid() { return grayBitsValid; }
void setGrayBitsInvalid() { grayBitsValid = false; }
bool isGcNeeded() { return isNeeded; }
double computeHeapGrowthFactor(size_t lastBytes);
size_t computeTriggerBytes(double growthFactor, size_t lastBytes, JSGCInvocationKind gckind);
- size_t allocationThreshold() { return allocThreshold; }
JSGCMode gcMode() const { return mode; }
void setGCMode(JSGCMode m) {
mode = m;
marker.setGCMode(mode);
}
inline void updateOnFreeArenaAlloc(const ChunkInfo &info);
@@ -409,16 +527,20 @@ class GCRuntime
js::gcstats::Statistics stats;
js::GCMarker marker;
/* Track heap usage for this runtime. */
HeapUsage usage;
+ /* GC scheduling state and parameters. */
+ GCSchedulingTunables tunables;
+ GCSchedulingState schedulingState;
+
private:
/*
* Set of all GC chunks with at least one allocated thing. The
* conservative GC uses it to quickly check if a possible GC thing points
* into an allocated chunk.
*/
js::GCChunkSet chunkSet;
@@ -430,45 +552,32 @@ class GCRuntime
* removed from the list and scheduled for release.
*/
js::gc::Chunk *systemAvailableChunkListHead;
js::gc::Chunk *userAvailableChunkListHead;
js::gc::ChunkPool chunkPool;
js::RootedValueMap rootsHash;
- size_t maxBytes;
size_t maxMallocBytes;
/*
* Number of the committed arenas in all GC chunks including empty chunks.
*/
mozilla::Atomic<uint32_t, mozilla::ReleaseAcquire> numArenasFreeCommitted;
void *verifyPreData;
void *verifyPostData;
bool chunkAllocationSinceLastGC;
int64_t nextFullGCTime;
int64_t lastGCTime;
int64_t jitReleaseTime;
JSGCMode mode;
- size_t allocThreshold;
- bool highFrequencyGC;
- uint64_t highFrequencyTimeThreshold;
- uint64_t highFrequencyLowLimitBytes;
- uint64_t highFrequencyHighLimitBytes;
- double highFrequencyHeapGrowthMax;
- double highFrequencyHeapGrowthMin;
- double lowFrequencyHeapGrowth;
- bool dynamicHeapGrowth;
- bool dynamicMarkSlice;
uint64_t decommitThreshold;
- unsigned minEmptyChunkCount;
- unsigned maxEmptyChunkCount;
/* During shutdown, the GC needs to clean up every possible object. */
bool cleanUpEverything;
/*
* The gray bits can become invalid if UnmarkGray overflows the stack. A
* full GC will reset this bit, since it fills in all the gray bits.
*/
@@ -593,36 +702,36 @@ class GCRuntime
* Technically this should be #ifdef JSGC_FJGENERATIONAL but that
* affects the observed size of JSRuntime in problematic ways, see
* note in vm/ThreadPool.h.
*/
mozilla::Atomic<uint32_t, mozilla::ReleaseAcquire> fjCollectionCounter;
/*
* These options control the zealousness of the GC. The fundamental values
- * are nextScheduled and gcDebugCompartmentGC. At every allocation,
- * nextScheduled is decremented. When it reaches zero, we do either a
- * full or a compartmental GC, based on debugCompartmentGC.
+ * are nextScheduled and gcDebugCompartmentGC. At every allocation,
+ * nextScheduled is decremented. When it reaches zero, we do either a full
+ * or a compartmental GC, based on debugCompartmentGC.
*
- * At this point, if zeal_ is one of the types that trigger periodic
- * collection, then nextScheduled is reset to the value of
- * zealFrequency. Otherwise, no additional GCs take place.
+ * At this point, if zeal_ is one of the types that trigger periodic
+ * collection, then nextScheduled is reset to the value of zealFrequency.
+ * Otherwise, no additional GCs take place.
*
* You can control these values in several ways:
* - Pass the -Z flag to the shell (see the usage info for details)
* - Call zeal() or schedulegc() from inside shell-executed JS code
* (see the help for details)
*
* If gzZeal_ == 1 then we perform GCs in select places (during MaybeGC and
* whenever a GC poke happens). This option is mainly useful to embedders.
*
- * We use zeal_ == 4 to enable write barrier verification. See the comment
+ * We use zeal_ == 4 to enable write barrier verification. See the comment
* in jsgc.cpp for more information about this.
*
- * zeal_ values from 8 to 10 periodically run different types of
+ * zeal_ values from 8 to 10 periodically run different types of
* incremental GC.
*/
#ifdef JS_GC_ZEAL
int zealMode;
int zealFrequency;
int nextScheduled;
bool deterministicOnly;
int incrementalLimit;
--- a/js/src/gc/Marking.cpp
+++ b/js/src/gc/Marking.cpp
@@ -1413,19 +1413,17 @@ gc::MarkChildren(JSTracer *trc, types::T
if (type->interpretedFunction)
MarkObject(trc, &type->interpretedFunction, "type_function");
}
static void
gc::MarkChildren(JSTracer *trc, jit::JitCode *code)
{
-#ifdef JS_ION
code->trace(trc);
-#endif
}
template<typename T>
static void
PushArenaTyped(GCMarker *gcmarker, ArenaHeader *aheader)
{
for (ArenaCellIterUnderGC i(aheader); !i.done(); i.next())
PushMarkStack(gcmarker, i.get<T>());
--- a/js/src/gc/Marking.h
+++ b/js/src/gc/Marking.h
@@ -349,35 +349,31 @@ IsAboutToBeFinalized(BarrieredBase<JSObj
}
inline bool
IsAboutToBeFinalized(BarrieredBase<JSScript*> *scriptp)
{
return IsScriptAboutToBeFinalized(scriptp);
}
-#ifdef JS_ION
-/* Nonsense to get WeakCache to work with new Marking semantics. */
-
inline bool
IsAboutToBeFinalized(const js::jit::VMFunction **vmfunc)
{
/*
* Preserves entries in the WeakCache<VMFunction, JitCode>
* iff the JitCode has been marked.
*/
return false;
}
inline bool
IsAboutToBeFinalized(ReadBarrieredJitCode code)
{
return IsJitCodeAboutToBeFinalized(code.unsafeGet());
}
-#endif
inline Cell *
ToMarkable(const Value &v)
{
if (v.isMarkable())
return (Cell *)v.toGCThing();
return nullptr;
}
--- a/js/src/gc/Nursery.cpp
+++ b/js/src/gc/Nursery.cpp
@@ -4,28 +4,27 @@
* 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/. */
#ifdef JSGC_GENERATIONAL
#include "gc/Nursery-inl.h"
+#include "mozilla/IntegerPrintfMacros.h"
+
#include "jscompartment.h"
#include "jsgc.h"
#include "jsinfer.h"
#include "jsutil.h"
#include "prmjtime.h"
#include "gc/GCInternals.h"
#include "gc/Memory.h"
-#ifdef JS_ION
#include "jit/IonFrames.h"
-#endif
-#include "mozilla/IntegerPrintfMacros.h"
#include "vm/ArrayObject.h"
#include "vm/Debugger.h"
#if defined(DEBUG)
#include "vm/ScopeObject.h"
#endif
#include "vm/TypedArrayObject.h"
#include "jsgcinlines.h"
@@ -846,19 +845,17 @@ js::Nursery::collect(JSRuntime *rt, JS::
for (CompartmentsIter c(rt, SkipAtoms); !c.done(); c.next()) {
if (!c->gcLiveArrayBuffers.empty())
ArrayBufferObject::sweep(c);
}
TIME_END(sweepArrayBufferViewList);
// Update any slot or element pointers whose destination has been tenured.
TIME_START(updateJitActivations);
-#ifdef JS_ION
js::jit::UpdateJitActivationsForMinorGC<Nursery>(&rt->mainThread, &trc);
-#endif
TIME_END(updateJitActivations);
// Resize the nursery.
TIME_START(resize);
double promotionRate = trc.tenuredSize / double(allocationEnd() - start());
if (promotionRate > 0.05)
growAllocableSpace();
else if (promotionRate < 0.01)
@@ -890,17 +887,17 @@ js::Nursery::collect(JSRuntime *rt, JS::
TIME_START(clearStoreBuffer);
rt->gc.storeBuffer.clear();
TIME_END(clearStoreBuffer);
// We ignore gcMaxBytes when allocating for minor collection. However, if we
// overflowed, we disable the nursery. The next time we allocate, we'll fail
// because gcBytes >= gcMaxBytes.
- if (rt->gc.usage.gcBytes() >= rt->gc.maxBytesAllocated())
+ if (rt->gc.usage.gcBytes() >= rt->gc.tunables.gcMaxBytes())
disable();
TIME_END(total);
TraceMinorGCEnd();
#ifdef PROFILE_NURSERY
int64_t totalTime = TIME_TOTAL(total);
--- a/js/src/gc/RootMarking.cpp
+++ b/js/src/gc/RootMarking.cpp
@@ -17,19 +17,17 @@
#include "jstypes.h"
#include "jswatchpoint.h"
#include "builtin/MapObject.h"
#include "frontend/BytecodeCompiler.h"
#include "gc/ForkJoinNursery.h"
#include "gc/GCInternals.h"
#include "gc/Marking.h"
-#ifdef JS_ION
-# include "jit/IonMacroAssembler.h"
-#endif
+#include "jit/IonMacroAssembler.h"
#include "js/HashTable.h"
#include "vm/Debugger.h"
#include "vm/PropDesc.h"
#include "jsgcinlines.h"
#include "jsobjinlines.h"
using namespace js;
@@ -300,17 +298,17 @@ MarkRangeConservatively(JSTracer *trc, c
MarkWordConservatively(trc, *i);
}
static void
MarkRangeConservativelyAndSkipIon(JSTracer *trc, JSRuntime *rt, const uintptr_t *begin, const uintptr_t *end)
{
const uintptr_t *i = begin;
-#if JS_STACK_GROWTH_DIRECTION < 0 && defined(JS_ION) && !defined(JS_ARM_SIMULATOR) && !defined(JS_MIPS_SIMULATOR)
+#if JS_STACK_GROWTH_DIRECTION < 0 && !defined(JS_ARM_SIMULATOR) && !defined(JS_MIPS_SIMULATOR)
// Walk only regions in between JIT activations. Note that non-volatile
// registers are spilled to the stack before the entry frame, ensuring
// that the conservative scanner will still see them.
//
// If the ARM or MIPS simulator is enabled, JIT activations are not on
// the native stack but on the simulator stack, so we don't have to skip
// JIT regions in this case.
for (jit::JitActivationIterator iter(rt); !iter.done(); ++iter) {
@@ -533,26 +531,22 @@ AutoGCRooter::trace(JSTracer *trc)
case HASHABLEVALUE: {
AutoHashableValueRooter *rooter = static_cast<AutoHashableValueRooter *>(this);
rooter->trace(trc);
return;
}
case IONMASM: {
-#ifdef JS_ION
static_cast<js::jit::MacroAssembler::AutoRooter *>(this)->masm()->trace(trc);
-#endif
return;
}
case IONALLOC: {
-#ifdef JS_ION
static_cast<js::jit::AutoTempAllocatorRooter *>(this)->trace(trc);
-#endif
return;
}
case WRAPPER: {
/*
* We need to use MarkValueUnbarriered here because we mark wrapper
* roots in every slice. This is because of some rule-breaking in
* RemapAllWrappersForObject; see comment there.
@@ -765,19 +759,17 @@ js::gc::GCRuntime::markRuntime(JSTracer
MarkScriptRoot(trc, &vec[i].script, "scriptAndCountsVector");
}
if (!rt->isBeingDestroyed() && !trc->runtime()->isHeapMinorCollecting()) {
if (!IS_GC_MARKING_TRACER(trc) || rt->atomsCompartment()->zone()->isCollecting()) {
MarkPermanentAtoms(trc);
MarkAtoms(trc);
MarkWellKnownSymbols(trc);
-#ifdef JS_ION
jit::JitRuntime::Mark(trc);
-#endif
}
}
for (ContextIter acx(rt); !acx.done(); acx.next())
acx->mark(trc);
for (ZonesIter zone(rt, SkipAtoms); !zone.done(); zone.next()) {
if (IS_GC_MARKING_TRACER(trc) && !zone->isCollecting())
@@ -811,19 +803,17 @@ js::gc::GCRuntime::markRuntime(JSTracer
/* Mark debug scopes, if present */
if (c->debugScopes)
c->debugScopes->mark(trc);
}
MarkInterpreterActivations(&rt->mainThread, trc);
-#ifdef JS_ION
jit::MarkJitActivations(&rt->mainThread, trc);
-#endif
if (!isHeapMinorCollecting()) {
/*
* All JSCompartment::mark does is mark the globals for compartments
* which have been entered. Globals aren't nursery allocated so there's
* no need to do this for minor GCs.
*/
for (CompartmentsIter c(rt, SkipAtoms); !c.done(); c.next())
--- a/js/src/gc/Rooting.h
+++ b/js/src/gc/Rooting.h
@@ -10,34 +10,35 @@
#include "js/RootingAPI.h"
class JSAtom;
class JSLinearString;
namespace js {
class PropertyName;
+class ScriptSourceObject;
class Shape;
namespace types { struct TypeObject; }
// These are internal counterparts to the public types such as HandleObject.
typedef JS::Handle<Shape*> HandleShape;
typedef JS::Handle<types::TypeObject*> HandleTypeObject;
typedef JS::Handle<JSAtom*> HandleAtom;
typedef JS::Handle<JSLinearString*> HandleLinearString;
typedef JS::Handle<PropertyName*> HandlePropertyName;
-typedef JS::Handle<js::ScriptSourceObject*> HandleScriptSource;
+typedef JS::Handle<ScriptSourceObject*> HandleScriptSource;
typedef JS::MutableHandle<Shape*> MutableHandleShape;
typedef JS::MutableHandle<JSAtom*> MutableHandleAtom;
typedef JS::Rooted<Shape*> RootedShape;
typedef JS::Rooted<types::TypeObject*> RootedTypeObject;
typedef JS::Rooted<JSAtom*> RootedAtom;
typedef JS::Rooted<JSLinearString*> RootedLinearString;
typedef JS::Rooted<PropertyName*> RootedPropertyName;
-typedef JS::Rooted<js::ScriptSourceObject*> RootedScriptSource;
+typedef JS::Rooted<ScriptSourceObject*> RootedScriptSource;
} /* namespace js */
#endif /* gc_Rooting_h */
--- a/js/src/gc/StoreBuffer.cpp
+++ b/js/src/gc/StoreBuffer.cpp
@@ -57,22 +57,18 @@ StoreBuffer::WholeCellEdges::mark(JSTrac
JSGCTraceKind kind = GetGCThingTraceKind(edge);
if (kind <= JSTRACE_OBJECT) {
JSObject *object = static_cast<JSObject *>(edge);
if (object->is<ArgumentsObject>())
ArgumentsObject::trace(trc, object);
MarkChildren(trc, object);
return;
}
-#ifdef JS_ION
JS_ASSERT(kind == JSTRACE_JITCODE);
static_cast<jit::JitCode *>(edge)->trace(trc);
-#else
- MOZ_CRASH("Only objects can be in the wholeCellBuffer if IonMonkey is disabled.");
-#endif
}
void
StoreBuffer::CellPtrEdge::mark(JSTracer *trc)
{
if (!*edge)
return;
--- a/js/src/gc/Zone.cpp
+++ b/js/src/gc/Zone.cpp
@@ -3,84 +3,78 @@
* 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 "gc/Zone.h"
#include "jsgc.h"
-#ifdef JS_ION
#include "jit/BaselineJIT.h"
#include "jit/Ion.h"
#include "jit/JitCompartment.h"
-#endif
#include "vm/Debugger.h"
#include "vm/Runtime.h"
#include "jsgcinlines.h"
using namespace js;
using namespace js::gc;
JS::Zone::Zone(JSRuntime *rt)
: JS::shadow::Zone(rt, &rt->gc.marker),
allocator(this),
types(this),
compartments(),
gcGrayRoots(),
- gcHeapGrowthFactor(3.0),
gcMallocBytes(0),
gcMallocGCTriggered(false),
usage(&rt->gc.usage),
- gcTriggerBytes(0),
data(nullptr),
isSystem(false),
usedByExclusiveThread(false),
scheduledForDestruction(false),
maybeAlive(true),
active(false),
jitZone_(nullptr),
gcState_(NoGC),
gcScheduled_(false),
gcPreserveCode_(false),
jitUsingBarriers_(false)
{
/* Ensure that there are no vtables to mess us up here. */
JS_ASSERT(reinterpret_cast<JS::shadow::Zone *>(this) ==
static_cast<JS::shadow::Zone *>(this));
+ threshold.updateAfterGC(8192, GC_NORMAL, rt->gc.tunables, rt->gc.schedulingState);
setGCMaxMallocBytes(rt->gc.maxMallocBytesAllocated() * 0.9);
}
Zone::~Zone()
{
JSRuntime *rt = runtimeFromMainThread();
if (this == rt->gc.systemZone)
rt->gc.systemZone = nullptr;
-#ifdef JS_ION
js_delete(jitZone_);
-#endif
}
-bool Zone::init()
+bool Zone::init(bool isSystemArg)
{
+ isSystem = isSystemArg;
return gcZoneGroupEdges.init();
}
void
Zone::setNeedsBarrier(bool needs, ShouldUpdateJit updateJit)
{
-#ifdef JS_ION
if (updateJit == UpdateJit && needs != jitUsingBarriers_) {
jit::ToggleBarriers(this, needs);
jitUsingBarriers_ = needs;
}
-#endif
if (needs && runtimeFromMainThread()->isAtomsZone(this))
JS_ASSERT(!runtimeFromMainThread()->exclusiveThreadsPresent());
JS_ASSERT_IF(needs, canCollect());
needsBarrier_ = needs;
}
@@ -167,31 +161,30 @@ Zone::sweepBreakpoints(FreeOp *fop)
}
}
}
}
void
Zone::discardJitCode(FreeOp *fop)
{
-#ifdef JS_ION
if (!jitZone())
return;
if (isPreservingCode()) {
PurgeJITCaches(this);
} else {
-# ifdef DEBUG
+#ifdef DEBUG
/* Assert no baseline scripts are marked as active. */
for (ZoneCellIterUnderGC i(this, FINALIZE_SCRIPT); !i.done(); i.next()) {
JSScript *script = i.get<JSScript>();
JS_ASSERT_IF(script->hasBaselineScript(), !script->baselineScript()->active());
}
-# endif
+#endif
/* Mark baseline scripts on the stack as active. */
jit::MarkActiveBaselineScripts(this);
/* Only mark OSI points if code is being discarded. */
jit::InvalidateAll(fop, this);
for (ZoneCellIterUnderGC i(this, FINALIZE_SCRIPT); !i.done(); i.next()) {
@@ -210,40 +203,37 @@ Zone::discardJitCode(FreeOp *fop)
* need to let it warm back up to get information such as which
* opcodes are setting array holes or accessing getter properties.
*/
script->resetUseCount();
}
jitZone()->optimizedStubSpace()->free();
}
-#endif
}
uint64_t
Zone::gcNumber()
{
// Zones in use by exclusive threads are not collected, and threads using
// them cannot access the main runtime's gcNumber without racing.
return usedByExclusiveThread ? 0 : runtimeFromMainThread()->gc.gcNumber();
}
-#ifdef JS_ION
js::jit::JitZone *
Zone::createJitZone(JSContext *cx)
{
MOZ_ASSERT(!jitZone_);
if (!cx->runtime()->getJitRuntime(cx))
return nullptr;
jitZone_ = cx->new_<js::jit::JitZone>();
return jitZone_;
}
-#endif
JS::Zone *
js::ZoneOfObjectFromAnyThread(const JSObject &obj)
{
return obj.zoneFromAnyThread();
}
bool
--- a/js/src/gc/Zone.h
+++ b/js/src/gc/Zone.h
@@ -37,16 +37,50 @@ class Allocator
// Since allocators can be accessed from worker threads, the parent zone_
// should not be accessed in general. ArenaLists is allowed to actually do
// the allocation, however.
friend class gc::ArenaLists;
JS::Zone *zone_;
};
+namespace gc {
+
+// This class encapsulates the data that determines when we need to do a zone GC.
+class ZoneHeapThreshold
+{
+ // The "growth factor" for computing our next thresholds after a GC.
+ double gcHeapGrowthFactor_;
+
+ // GC trigger threshold for allocations on the GC heap.
+ size_t gcTriggerBytes_;
+
+ public:
+ ZoneHeapThreshold()
+ : gcHeapGrowthFactor_(3.0),
+ gcTriggerBytes_(0)
+ {}
+
+ double gcHeapGrowthFactor() const { return gcHeapGrowthFactor_; }
+ size_t gcTriggerBytes() const { return gcTriggerBytes_; }
+
+ void updateAfterGC(size_t lastBytes, JSGCInvocationKind gckind,
+ const GCSchedulingTunables &tunables, const GCSchedulingState &state);
+ void updateForRemovedArena(const GCSchedulingTunables &tunables);
+
+ private:
+ static double computeZoneHeapGrowthFactorForHeapSize(size_t lastBytes,
+ const GCSchedulingTunables &tunables,
+ const GCSchedulingState &state);
+ static size_t computeZoneTriggerBytes(double growthFactor, size_t lastBytes,
+ JSGCInvocationKind gckind,
+ const GCSchedulingTunables &tunables);
+};
+
+} // namespace gc
} // namespace js
namespace JS {
// A zone is a collection of compartments. Every compartment belongs to exactly
// one zone. In Firefox, there is roughly one zone per tab along with a system
// zone for everything else. Zones mainly serve as boundaries for garbage
// collection. Unlike compartments, they have no special security properties.
@@ -90,29 +124,26 @@ namespace JS {
// example, if the conservative scanner marks a string in an otherwise dead
// zone.)
struct Zone : public JS::shadow::Zone,
public js::gc::GraphNodeBase<JS::Zone>,
public js::MallocProvider<JS::Zone>
{
explicit Zone(JSRuntime *rt);
~Zone();
- bool init();
+ bool init(bool isSystem);
void findOutgoingEdges(js::gc::ComponentFinder<JS::Zone> &finder);
void discardJitCode(js::FreeOp *fop);
void addSizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf,
size_t *typePool,
size_t *baselineStubsOptimized);
- void setGCLastBytes(size_t lastBytes, js::JSGCInvocationKind gckind);
- void reduceGCTriggerBytes(size_t amount);
-
void resetGCMallocBytes();
void setGCMaxMallocBytes(size_t value);
void updateMallocCounter(size_t nbytes) {
// Note: this code may be run from worker threads. We tolerate any
// thread races when updating gcMallocBytes.
gcMallocBytes -= ptrdiff_t(nbytes);
if (MOZ_UNLIKELY(isTooMuchMalloc()))
onTooMuchMalloc();
@@ -221,19 +252,16 @@ struct Zone : public JS::shadow::Zone,
// A set of edges from this zone to other zones.
//
// This is used during GC while calculating zone groups to record edges that
// can't be determined by examining this zone by itself.
typedef js::HashSet<Zone *, js::DefaultHasher<Zone *>, js::SystemAllocPolicy> ZoneSet;
ZoneSet gcZoneGroupEdges;
- // The "growth factor" for computing our next thresholds after a GC.
- double gcHeapGrowthFactor;
-
// Malloc counter to measure memory pressure for GC scheduling. It runs from
// gcMaxMallocBytes down to zero. This counter should be used only when it's
// not possible to know the size of a free.
mozilla::Atomic<ptrdiff_t, mozilla::ReleaseAcquire> gcMallocBytes;
// GC trigger threshold for allocations on the C heap.
size_t gcMaxMallocBytes;
@@ -242,18 +270,18 @@ struct Zone : public JS::shadow::Zone,
//
// This should be a bool, but Atomic only supports 32-bit and pointer-sized
// types.
mozilla::Atomic<uint32_t, mozilla::ReleaseAcquire> gcMallocGCTriggered;
// Track heap usage under this Zone.
js::gc::HeapUsage usage;
- // GC trigger threshold for allocations on the GC heap.
- size_t gcTriggerBytes;
+ // Thresholds used to trigger GC.
+ js::gc::ZoneHeapThreshold threshold;
// Per-zone data for use by an embedder.
void *data;
bool isSystem;
bool usedByExclusiveThread;
--- a/js/src/irregexp/NativeRegExpMacroAssembler.h
+++ b/js/src/irregexp/NativeRegExpMacroAssembler.h
@@ -26,18 +26,16 @@
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef V8_NATIVE_REGEXP_MACRO_ASSEMBLER_H_
#define V8_NATIVE_REGEXP_MACRO_ASSEMBLER_H_
-#ifdef JS_ION
-
#include "irregexp/RegExpMacroAssembler.h"
namespace js {
namespace irregexp {
struct InputOutputData
{
const void *inputStart;
@@ -215,11 +213,9 @@ class MOZ_STACK_CLASS NativeRegExpMacroA
int32_t register_offset(int register_index) {
return sizeof(FrameData) + register_index * sizeof(void *);
}
};
} } // namespace js::irregexp
-#endif // JS_ION
-
#endif // V8_NATIVE_REGEXP_MACRO_ASSEMBLER_H_
--- a/js/src/irregexp/RegExpEngine.cpp
+++ b/js/src/irregexp/RegExpEngine.cpp
@@ -1646,17 +1646,16 @@ irregexp::CompilePattern(JSContext *cx,
Analysis analysis(cx, ignore_case, is_ascii);
analysis.EnsureAnalyzed(node);
if (analysis.has_failed()) {
JS_ReportError(cx, analysis.errorMessage());
return RegExpCode();
}
-#ifdef JS_ION
Maybe<jit::IonContext> ctx;
Maybe<NativeRegExpMacroAssembler> native_assembler;
Maybe<InterpretedRegExpMacroAssembler> interpreted_assembler;
RegExpMacroAssembler *assembler;
if (IsNativeRegExpEnabled(cx)) {
NativeRegExpMacroAssembler::Mode mode =
is_ascii ? NativeRegExpMacroAssembler::ASCII
@@ -1664,20 +1663,16 @@ irregexp::CompilePattern(JSContext *cx,
ctx.construct(cx, (jit::TempAllocator *) nullptr);
native_assembler.construct(&alloc, shared, cx->runtime(), mode, (data->capture_count + 1) * 2);
assembler = native_assembler.addr();
} else {
interpreted_assembler.construct(&alloc, shared, (data->capture_count + 1) * 2);
assembler = interpreted_assembler.addr();
}
-#else // JS_ION
- InterpretedRegExpMacroAssembler macro_assembler(&alloc, shared, (data->capture_count + 1) * 2);
- RegExpMacroAssembler *assembler = ¯o_assembler;
-#endif // JS_ION
// Inserted here, instead of in Assembler, because it depends on information
// in the AST that isn't replicated in the Node structure.
static const int kMaxBacksearchLimit = 1024;
if (is_end_anchored &&
!is_start_anchored &&
max_length < kMaxBacksearchLimit) {
assembler->SetCurrentPositionFromEnd(max_length);
@@ -1692,32 +1687,28 @@ irregexp::CompilePattern(JSContext *cx,
return compiler.Assemble(cx, assembler, node, data->capture_count);
}
template <typename CharT>
RegExpRunStatus
irregexp::ExecuteCode(JSContext *cx, jit::JitCode *codeBlock, const CharT *chars, size_t start,
size_t length, MatchPairs *matches)
{
-#ifdef JS_ION
typedef void (*RegExpCodeSignature)(InputOutputData *);
InputOutputData data(chars, chars + length, start, matches);
RegExpCodeSignature function = reinterpret_cast<RegExpCodeSignature>(codeBlock->raw());
{
JS::AutoSuppressGCAnalysis nogc;
CALL_GENERATED_REGEXP(function, &data);
}
return (RegExpRunStatus) data.result;
-#else
- MOZ_CRASH();
-#endif
}
template RegExpRunStatus
irregexp::ExecuteCode(JSContext *cx, jit::JitCode *codeBlock, const Latin1Char *chars, size_t start,
size_t length, MatchPairs *matches);
template RegExpRunStatus
irregexp::ExecuteCode(JSContext *cx, jit::JitCode *codeBlock, const jschar *chars, size_t start,
--- a/js/src/irregexp/RegExpEngine.h
+++ b/js/src/irregexp/RegExpEngine.h
@@ -64,46 +64,30 @@ struct RegExpCompileData
RegExpTree *tree;
bool simple;
bool contains_anchor;
int capture_count;
};
struct RegExpCode
{
-#ifdef JS_ION
jit::JitCode *jitCode;
uint8_t *byteCode;
RegExpCode()
: jitCode(nullptr), byteCode(nullptr)
{}
bool empty() {
return !jitCode && !byteCode;
}
void destroy() {
js_free(byteCode);
}
-#else
- uint8_t *byteCode;
-
- RegExpCode()
- : byteCode(nullptr)
- {}
-
- bool empty() {
- return !byteCode;
- }
-
- void destroy() {
- js_free(byteCode);
- }
-#endif
};
RegExpCode
CompilePattern(JSContext *cx, RegExpShared *shared, RegExpCompileData *data,
HandleLinearString sample, bool is_global, bool ignore_case = false,
bool is_ascii = false);
// Note: this may return RegExpRunStatus_Error if an interrupt was requested
--- a/js/src/jit/AsmJS.h
+++ b/js/src/jit/AsmJS.h
@@ -68,35 +68,21 @@ static const size_t AsmJSBufferProtected
// | waste | ObjectElements | data array | inaccessible reserved memory |
// ^ ^ ^
// | \ /
// obj->elements required to be page boundaries
//
static const size_t AsmJSMappedSize = AsmJSPageSize + AsmJSBufferProtectedSize;
#endif // JS_CODEGEN_X64
-#ifdef JS_ION
-
-// Return whether asm.js optimization is inhibitted by the platform or
+// Return whether asm.js optimization is inhibited by the platform or
// dynamically disabled:
extern bool
IsAsmJSCompilationAvailable(JSContext *cx, unsigned argc, JS::Value *vp);
-#else // JS_ION
-
-inline bool
-IsAsmJSCompilationAvailable(JSContext *cx, unsigned argc, Value *vp)
-{
- CallArgs args = CallArgsFromVp(argc, vp);
- args.rval().set(BooleanValue(false));
- return true;
-}
-
-#endif // JS_ION
-
// To succesfully link an asm.js module to an ArrayBuffer heap, the
// ArrayBuffer's byteLength must be:
// - greater or equal to 4096
// - either a power of 2 OR a multiple of 16MB
inline bool
IsValidAsmJSHeapLength(uint32_t length)
{
if (length < 4096)
--- a/js/src/jit/AsmJSLink.h
+++ b/js/src/jit/AsmJSLink.h
@@ -6,18 +6,16 @@
#ifndef jit_AsmJSLink_h
#define jit_AsmJSLink_h
#include "NamespaceImports.h"
namespace js {
-#ifdef JS_ION
-
// Create a new JSFunction to replace originalFun as the representation of the
// function defining the succesfully-validated module 'moduleObj'.
extern JSFunction *
NewAsmJSModuleFunction(ExclusiveContext *cx, JSFunction *originalFun, HandleObject moduleObj);
// Return whether this is the js::Native returned by NewAsmJSModuleFunction.
extern bool
IsAsmJSModuleNative(JSNative native);
@@ -42,69 +40,11 @@ IsAsmJSModuleLoadedFromCache(JSContext *
extern bool
IsAsmJSFunction(JSContext *cx, unsigned argc, JS::Value *vp);
extern bool
IsAsmJSFunction(HandleFunction fun);
extern JSString *
AsmJSFunctionToString(JSContext *cx, HandleFunction fun);
-#else // JS_ION
-
-inline bool
-IsAsmJSModuleNative(JSNative native)
-{
- return false;
-}
-
-inline bool
-IsAsmJSFunction(JSContext *cx, unsigned argc, Value *vp)
-{
- CallArgs args = CallArgsFromVp(argc, vp);
- args.rval().set(BooleanValue(false));
- return true;
-}
-
-inline bool
-IsAsmJSFunction(HandleFunction fun)
-{
- return false;
-}
-
-inline JSString *
-AsmJSFunctionToString(JSContext *cx, HandleFunction fun)
-{
- return nullptr;
-}
-
-inline bool
-IsAsmJSModule(JSContext *cx, unsigned argc, Value *vp)
-{
- CallArgs args = CallArgsFromVp(argc, vp);
- args.rval().set(BooleanValue(false));
- return true;
-}
-
-inline bool
-IsAsmJSModule(HandleFunction fun)
-{
- return false;
-}
-
-inline JSString*
-AsmJSModuleToString(JSContext *cx, HandleFunction fun, bool addParenToLambda)
-{
- return nullptr;
-}
-
-inline bool
-IsAsmJSModuleLoadedFromCache(JSContext *cx, unsigned argc, Value *vp)
-{
- CallArgs args = CallArgsFromVp(argc, vp);
- args.rval().set(BooleanValue(false));
- return true;
-}
-
-#endif // JS_ION
-
} // namespace js
#endif // jit_AsmJS_h
--- a/js/src/jit/AsmJSModule.h
+++ b/js/src/jit/AsmJSModule.h
@@ -2,18 +2,16 @@
* vim: set ts=8 sts=4 et sw=4 tw=99:
* 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 jit_AsmJSModule_h
#define jit_AsmJSModule_h
-#ifdef JS_ION
-
#include "mozilla/Maybe.h"
#include "mozilla/Move.h"
#include "mozilla/PodOperations.h"
#include "jsscript.h"
#include "gc/Marking.h"
#include "jit/AsmJS.h"
@@ -1220,11 +1218,9 @@ class AsmJSModuleObject : public JSObjec
module().addSizeOfMisc(mallocSizeOf, asmJSModuleCode, asmJSModuleData);
}
static const Class class_;
};
} // namespace js
-#endif // JS_ION
-
#endif /* jit_AsmJSModule_h */
--- a/js/src/jit/BaselineCompiler.h
+++ b/js/src/jit/BaselineCompiler.h
@@ -2,18 +2,16 @@
* vim: set ts=8 sts=4 et sw=4 tw=99:
* 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 jit_BaselineCompiler_h
#define jit_BaselineCompiler_h
-#ifdef JS_ION
-
#include "jit/FixedList.h"
#if defined(JS_CODEGEN_X86)
# include "jit/x86/BaselineCompiler-x86.h"
#elif defined(JS_CODEGEN_X64)
# include "jit/x64/BaselineCompiler-x64.h"
#elif defined(JS_CODEGEN_ARM)
# include "jit/arm/BaselineCompiler-arm.h"
#elif defined(JS_CODEGEN_MIPS)
@@ -272,11 +270,9 @@ class BaselineCompiler : public Baseline
void getScopeCoordinateObject(Register reg);
Address getScopeCoordinateAddressFromObject(Register objReg, Register reg);
Address getScopeCoordinateAddress(Register reg);
};
} // namespace jit
} // namespace js
-#endif // JS_ION
-
#endif /* jit_BaselineCompiler_h */
--- a/js/src/jit/BaselineDebugModeOSR.h
+++ b/js/src/jit/BaselineDebugModeOSR.h
@@ -2,18 +2,16 @@
* vim: set ts=8 sts=4 et sw=4 tw=99:
* 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 jit_BaselineDebugModeOSR_h
#define jit_BaselineDebugModeOSR_h
-#ifdef JS_ION
-
#include "jit/BaselineFrame.h"
#include "jit/BaselineIC.h"
#include "jit/BaselineJIT.h"
namespace js {
namespace jit {
// Note that this file and the corresponding .cpp implement debug mode
@@ -96,11 +94,9 @@ struct BaselineDebugModeOSRInfo
};
bool
RecompileOnStackBaselineScriptsForDebugMode(JSContext *cx, JSCompartment *comp);
} // namespace jit
} // namespace js
-#endif // JS_ION
-
#endif // jit_BaselineDebugModeOSR_h
--- a/js/src/jit/BaselineFrame-inl.h
+++ b/js/src/jit/BaselineFrame-inl.h
@@ -2,18 +2,16 @@
* vim: set ts=8 sts=4 et sw=4 tw=99:
* 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 jit_BaselineFrame_inl_h
#define jit_BaselineFrame_inl_h
-#ifdef JS_ION
-
#include "jit/BaselineFrame.h"
#include "jscntxt.h"
#include "jscompartment.h"
#include "vm/ScopeObject.h"
namespace js {
@@ -74,11 +72,9 @@ BaselineFrame::callObj() const
while (!obj->is<CallObject>())
obj = obj->enclosingScope();
return obj->as<CallObject>();
}
} // namespace jit
} // namespace js
-#endif // JS_ION
-
#endif /* jit_BaselineFrame_inl_h */
--- a/js/src/jit/BaselineFrame.h
+++ b/js/src/jit/BaselineFrame.h
@@ -2,18 +2,16 @@
* vim: set ts=8 sts=4 et sw=4 tw=99:
* 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 jit_BaselineFrame_h
#define jit_BaselineFrame_h
-#ifdef JS_ION
-
#include "jit/IonFrames.h"
#include "vm/Stack.h"
namespace js {
namespace jit {
struct BaselineDebugModeOSRInfo;
@@ -420,11 +418,9 @@ class BaselineFrame
};
// Ensure the frame is 8-byte aligned (required on ARM).
JS_STATIC_ASSERT(((sizeof(BaselineFrame) + BaselineFrame::FramePointerOffset) % 8) == 0);
} // namespace jit
} // namespace js
-#endif // JS_ION
-
#endif /* jit_BaselineFrame_h */
--- a/js/src/jit/BaselineFrameInfo.h
+++ b/js/src/jit/BaselineFrameInfo.h
@@ -2,18 +2,16 @@
* vim: set ts=8 sts=4 et sw=4 tw=99:
* 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 jit_BaselineFrameInfo_h
#define jit_BaselineFrameInfo_h
-#ifdef JS_ION
-
#include "mozilla/Alignment.h"
#include "jit/BaselineFrame.h"
#include "jit/BaselineRegisters.h"
#include "jit/FixedList.h"
#include "jit/IonMacroAssembler.h"
namespace js {
@@ -313,11 +311,9 @@ class FrameInfo
#else
inline void assertValidState(const BytecodeInfo &info) {}
#endif
};
} // namespace jit
} // namespace js
-#endif // JS_ION
-
#endif /* jit_BaselineFrameInfo_h */
--- a/js/src/jit/BaselineHelpers.h
+++ b/js/src/jit/BaselineHelpers.h
@@ -2,18 +2,16 @@
* vim: set ts=8 sts=4 et sw=4 tw=99:
* 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 jit_BaselineHelpers_h
#define jit_BaselineHelpers_h
-#ifdef JS_ION
-
#if defined(JS_CODEGEN_X86)
# include "jit/x86/BaselineHelpers-x86.h"
#elif defined(JS_CODEGEN_X64)
# include "jit/x64/BaselineHelpers-x64.h"
#elif defined(JS_CODEGEN_ARM)
# include "jit/arm/BaselineHelpers-arm.h"
#elif defined(JS_CODEGEN_MIPS)
# include "jit/mips/BaselineHelpers-mips.h"
@@ -24,11 +22,9 @@
#endif
namespace js {
namespace jit {
} // namespace jit
} // namespace js
-#endif // JS_ION
-
#endif /* jit_BaselineHelpers_h */
--- a/js/src/jit/BaselineIC.h
+++ b/js/src/jit/BaselineIC.h
@@ -2,18 +2,16 @@
* vim: set ts=8 sts=4 et sw=4 tw=99:
* 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 jit_BaselineIC_h
#define jit_BaselineIC_h
-#ifdef JS_ION
-
#include "mozilla/Assertions.h"
#include "jscntxt.h"
#include "jscompartment.h"
#include "jsgc.h"
#include "jsopcode.h"
#include "jit/BaselineJIT.h"
@@ -6466,11 +6464,9 @@ IsCacheableDOMProxy(JSObject *obj)
return false;
return true;
}
} // namespace jit
} // namespace js
-#endif // JS_ION
-
#endif /* jit_BaselineIC_h */
--- a/js/src/jit/BaselineInspector.h
+++ b/js/src/jit/BaselineInspector.h
@@ -2,18 +2,16 @@
* vim: set ts=8 sts=4 et sw=4 tw=99:
* 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 jit_BaselineInspector_h
#define jit_BaselineInspector_h
-#ifdef JS_ION
-
#include "jit/BaselineIC.h"
#include "jit/BaselineJIT.h"
#include "jit/MIR.h"
namespace js {
namespace jit {
class BaselineInspector;
@@ -119,11 +117,9 @@ class BaselineInspector
JSObject *commonGetPropFunction(jsbytecode *pc, Shape **lastProperty, JSFunction **commonGetter);
JSObject *commonSetPropFunction(jsbytecode *pc, Shape **lastProperty, JSFunction **commonSetter);
};
} // namespace jit
} // namespace js
-#endif // JS_ION
-
#endif /* jit_BaselineInspector_h */
--- a/js/src/jit/BaselineJIT.h
+++ b/js/src/jit/BaselineJIT.h
@@ -2,18 +2,16 @@
* vim: set ts=8 sts=4 et sw=4 tw=99:
* 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 jit_BaselineJIT_h
#define jit_BaselineJIT_h
-#ifdef JS_ION
-
#include "mozilla/MemoryReporting.h"
#include "jscntxt.h"
#include "jscompartment.h"
#include "ds/LifoAlloc.h"
#include "jit/Bailouts.h"
#include "jit/IonCode.h"
@@ -424,11 +422,9 @@ void
MarkActiveBaselineScripts(Zone *zone);
MethodStatus
BaselineCompile(JSContext *cx, JSScript *script);
} // namespace jit
} // namespace js
-#endif // JS_ION
-
#endif /* jit_BaselineJIT_h */
--- a/js/src/jit/BaselineRegisters.h
+++ b/js/src/jit/BaselineRegisters.h
@@ -2,18 +2,16 @@
* vim: set ts=8 sts=4 et sw=4 tw=99:
* 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 jit_BaselineRegisters_h
#define jit_BaselineRegisters_h
-#ifdef JS_ION
-
#if defined(JS_CODEGEN_X86)
# include "jit/x86/BaselineRegisters-x86.h"
#elif defined(JS_CODEGEN_X64)
# include "jit/x64/BaselineRegisters-x64.h"
#elif defined(JS_CODEGEN_ARM)
# include "jit/arm/BaselineRegisters-arm.h"
#elif defined(JS_CODEGEN_MIPS)
# include "jit/mips/BaselineRegisters-mips.h"
@@ -24,11 +22,9 @@
#endif
namespace js {
namespace jit {
} // namespace jit
} // namespace js
-#endif // JS_ION
-
#endif /* jit_BaselineRegisters_h */
--- a/js/src/jit/CompileWrappers.h
+++ b/js/src/jit/CompileWrappers.h
@@ -2,18 +2,16 @@
* vim: set ts=8 sts=4 et sw=4 tw=99:
* 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 jit_CompileWrappers_h
#define jit_CompileWrappers_h
-#ifdef JS_ION
-
#include "jscntxt.h"
namespace js {
namespace jit {
class JitRuntime;
// During Ion compilation we need access to various bits of the current
@@ -136,15 +134,12 @@ class JitCompileOptions
return spsSlowAssertionsEnabled_;
}
private:
bool cloneSingletons_;
bool spsSlowAssertionsEnabled_;
};
-
} // namespace jit
} // namespace js
-#endif // JS_ION
-
#endif // jit_CompileWrappers_h
--- a/js/src/jit/CompilerRoot.h
+++ b/js/src/jit/CompilerRoot.h
@@ -2,18 +2,16 @@
* vim: set ts=8 sts=4 et sw=4 tw=99:
* 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 jit_CompilerRoot_h
#define jit_CompilerRoot_h
-#ifdef JS_ION
-
#include "jscntxt.h"
#include "jit/Ion.h"
#include "jit/IonAllocPolicy.h"
#include "js/RootingAPI.h"
namespace js {
namespace jit {
@@ -60,11 +58,9 @@ typedef CompilerRoot<JSFunction*> Compil
typedef CompilerRoot<JSScript*> CompilerRootScript;
typedef CompilerRoot<PropertyName*> CompilerRootPropertyName;
typedef CompilerRoot<Shape*> CompilerRootShape;
typedef CompilerRoot<Value> CompilerRootValue;
} // namespace jit
} // namespace js