--- a/b2g/config/emulator-ics/sources.xml
+++ b/b2g/config/emulator-ics/sources.xml
@@ -14,23 +14,23 @@
<!--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="15c84c943e41ad834640a45e1e1c2ac804168af7"/>
+ <project name="gaia.git" path="gaia" remote="mozillaorg" revision="5458f73e319759543fddf7e96d7ece4d78318e32"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="7f792d756385bb894fba7645da59c67fe2c804bf"/>
<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="04ffbed6a18a2085a27bc113034fe71b8d10c10e"/>
+ <project name="apitrace" path="external/apitrace" remote="apitrace" revision="11f01789444d4ebe97581c31d8756d773e18356f"/>
<!-- Stock Android things -->
<project name="platform/abi/cpp" path="abi/cpp" revision="dd924f92906085b831bf1cbbc7484d3c043d613c"/>
<project name="platform/bionic" path="bionic" revision="c72b8f6359de7ed17c11ddc9dfdde3f615d188a9"/>
<project name="platform/bootable/recovery" path="bootable/recovery" revision="425f8b5fadf5889834c5acd27d23c9e0b2129c28"/>
<project name="device/common" path="device/common" revision="42b808b7e93d0619286ae8e59110b176b7732389"/>
<project name="device/sample" path="device/sample" revision="237bd668d0f114d801a8d6455ef5e02cc3577587"/>
<project name="platform_external_apriori" path="external/apriori" remote="b2g" revision="11816ad0406744f963537b23d68ed9c2afb412bd"/>
<project name="platform/external/bluetooth/bluez" path="external/bluetooth/bluez" revision="52a1a862a8bac319652b8f82d9541ba40bfa45ce"/>
--- a/b2g/config/emulator-jb/sources.xml
+++ b/b2g/config/emulator-jb/sources.xml
@@ -12,20 +12,20 @@
<!--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="15c84c943e41ad834640a45e1e1c2ac804168af7"/>
+ <project name="gaia" path="gaia" remote="mozillaorg" revision="5458f73e319759543fddf7e96d7ece4d78318e32"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="7f792d756385bb894fba7645da59c67fe2c804bf"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="dc5ca96695cab87b4c2fcd7c9f046ae3415a70a5"/>
- <project name="apitrace" path="external/apitrace" remote="apitrace" revision="04ffbed6a18a2085a27bc113034fe71b8d10c10e"/>
+ <project name="apitrace" path="external/apitrace" remote="apitrace" revision="11f01789444d4ebe97581c31d8756d773e18356f"/>
<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"/>
<project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" revision="9025e50b9d29b3cabbbb21e1dd94d0d13121a17e"/>
<project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" revision="b89fda71fcd0fa0cf969310e75be3ea33e048b44"/>
<project groups="linux,arm" name="platform/prebuilts/gcc/linux-x86/arm/arm-eabi-4.7" path="prebuilts/gcc/linux-x86/arm/arm-eabi-4.7" revision="2e7d5348f35575870b3c7e567a9a9f6d66f8d6c5"/>
--- a/b2g/config/emulator-kk/sources.xml
+++ b/b2g/config/emulator-kk/sources.xml
@@ -10,25 +10,25 @@
<!--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="15c84c943e41ad834640a45e1e1c2ac804168af7"/>
+ <project name="gaia" path="gaia" remote="mozillaorg" revision="5458f73e319759543fddf7e96d7ece4d78318e32"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="7f792d756385bb894fba7645da59c67fe2c804bf"/>
<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="04ffbed6a18a2085a27bc113034fe71b8d10c10e"/>
+ <project name="apitrace" path="external/apitrace" remote="apitrace" revision="11f01789444d4ebe97581c31d8756d773e18356f"/>
<!-- Stock Android things -->
<project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" revision="f92a936f2aa97526d4593386754bdbf02db07a12"/>
<project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" revision="6e47ff2790f5656b5b074407829ceecf3e6188c4"/>
<project groups="linux,arm" name="platform/prebuilts/gcc/linux-x86/arm/arm-eabi-4.7" path="prebuilts/gcc/linux-x86/arm/arm-eabi-4.7" revision="1950e4760fa14688b83cdbb5acaa1af9f82ef434"/>
<project groups="linux,arm" name="platform/prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.7" path="prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.7" revision="ac6eb97a37035c09fb5ede0852f0881e9aadf9ad"/>
<project groups="linux,x86" name="platform/prebuilts/gcc/linux-x86/x86/i686-linux-android-4.7" path="prebuilts/gcc/linux-x86/x86/i686-linux-android-4.7" revision="737f591c5f95477148d26602c7be56cbea0cdeb9"/>
<project groups="linux,x86" name="platform/prebuilts/python/linux-x86/2.7.5" path="prebuilts/python/linux-x86/2.7.5" revision="51da9b1981be481b92a59a826d4d78dc73d0989a"/>
<project name="device/common" path="device/common" revision="798a3664597e6041985feab9aef42e98d458bc3d"/>
--- a/b2g/config/emulator/sources.xml
+++ b/b2g/config/emulator/sources.xml
@@ -14,23 +14,23 @@
<!--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="15c84c943e41ad834640a45e1e1c2ac804168af7"/>
+ <project name="gaia.git" path="gaia" remote="mozillaorg" revision="5458f73e319759543fddf7e96d7ece4d78318e32"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="7f792d756385bb894fba7645da59c67fe2c804bf"/>
<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="04ffbed6a18a2085a27bc113034fe71b8d10c10e"/>
+ <project name="apitrace" path="external/apitrace" remote="apitrace" revision="11f01789444d4ebe97581c31d8756d773e18356f"/>
<!-- Stock Android things -->
<project name="platform/abi/cpp" path="abi/cpp" revision="dd924f92906085b831bf1cbbc7484d3c043d613c"/>
<project name="platform/bionic" path="bionic" revision="c72b8f6359de7ed17c11ddc9dfdde3f615d188a9"/>
<project name="platform/bootable/recovery" path="bootable/recovery" revision="425f8b5fadf5889834c5acd27d23c9e0b2129c28"/>
<project name="device/common" path="device/common" revision="42b808b7e93d0619286ae8e59110b176b7732389"/>
<project name="device/sample" path="device/sample" revision="237bd668d0f114d801a8d6455ef5e02cc3577587"/>
<project name="platform_external_apriori" path="external/apriori" remote="b2g" revision="11816ad0406744f963537b23d68ed9c2afb412bd"/>
<project name="platform/external/bluetooth/bluez" path="external/bluetooth/bluez" revision="52a1a862a8bac319652b8f82d9541ba40bfa45ce"/>
--- a/b2g/config/flame/sources.xml
+++ b/b2g/config/flame/sources.xml
@@ -12,20 +12,20 @@
<!--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="15c84c943e41ad834640a45e1e1c2ac804168af7"/>
+ <project name="gaia" path="gaia" remote="mozillaorg" revision="5458f73e319759543fddf7e96d7ece4d78318e32"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="7f792d756385bb894fba7645da59c67fe2c804bf"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="dc5ca96695cab87b4c2fcd7c9f046ae3415a70a5"/>
- <project name="apitrace" path="external/apitrace" remote="apitrace" revision="04ffbed6a18a2085a27bc113034fe71b8d10c10e"/>
+ <project name="apitrace" path="external/apitrace" remote="apitrace" revision="11f01789444d4ebe97581c31d8756d773e18356f"/>
<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"/>
<project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" revision="95bb5b66b3ec5769c3de8d3f25d681787418e7d2"/>
<project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" revision="ebdad82e61c16772f6cd47e9f11936bf6ebe9aa0"/>
<project groups="linux,arm" name="platform/prebuilts/gcc/linux-x86/arm/arm-eabi-4.7" path="prebuilts/gcc/linux-x86/arm/arm-eabi-4.7" revision="8b880805d454664b3eed11d0f053cdeafa1ff06e"/>
--- a/b2g/config/gaia.json
+++ b/b2g/config/gaia.json
@@ -1,9 +1,9 @@
{
"git": {
"git_revision": "",
"remote": "",
"branch": ""
},
- "revision": "a9373a0a5aa0a03e259bb25765e350cf2e9e1a77",
+ "revision": "2a39622b30294c36997f9b8260230182344184de",
"repo_path": "/integration/gaia-central"
}
--- a/b2g/config/hamachi/sources.xml
+++ b/b2g/config/hamachi/sources.xml
@@ -12,22 +12,22 @@
<!--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="15c84c943e41ad834640a45e1e1c2ac804168af7"/>
+ <project name="gaia.git" path="gaia" remote="mozillaorg" revision="5458f73e319759543fddf7e96d7ece4d78318e32"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="7f792d756385bb894fba7645da59c67fe2c804bf"/>
<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="04ffbed6a18a2085a27bc113034fe71b8d10c10e"/>
+ <project name="apitrace" path="external/apitrace" remote="apitrace" revision="11f01789444d4ebe97581c31d8756d773e18356f"/>
<!-- Stock Android things -->
<project name="platform/abi/cpp" path="abi/cpp" revision="6426040f1be4a844082c9769171ce7f5341a5528"/>
<project name="platform/bionic" path="bionic" revision="d2eb6c7b6e1bc7643c17df2d9d9bcb1704d0b9ab"/>
<project name="platform/bootable/recovery" path="bootable/recovery" revision="746bc48f34f5060f90801925dcdd964030c1ab6d"/>
<project name="platform/development" path="development" revision="2460485184bc8535440bb63876d4e63ec1b4770c"/>
<project name="device/common" path="device/common" revision="0dcc1e03659db33b77392529466f9eb685cdd3c7"/>
<project name="device/sample" path="device/sample" revision="68b1cb978a20806176123b959cb05d4fa8adaea4"/>
<project name="platform_external_apriori" path="external/apriori" remote="b2g" revision="11816ad0406744f963537b23d68ed9c2afb412bd"/>
--- 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="15c84c943e41ad834640a45e1e1c2ac804168af7"/>
+ <project name="gaia.git" path="gaia" remote="mozillaorg" revision="5458f73e319759543fddf7e96d7ece4d78318e32"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="7f792d756385bb894fba7645da59c67fe2c804bf"/>
<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,20 +12,20 @@
<!--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="15c84c943e41ad834640a45e1e1c2ac804168af7"/>
+ <project name="gaia" path="gaia" remote="mozillaorg" revision="5458f73e319759543fddf7e96d7ece4d78318e32"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="7f792d756385bb894fba7645da59c67fe2c804bf"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="dc5ca96695cab87b4c2fcd7c9f046ae3415a70a5"/>
- <project name="apitrace" path="external/apitrace" remote="apitrace" revision="04ffbed6a18a2085a27bc113034fe71b8d10c10e"/>
+ <project name="apitrace" path="external/apitrace" remote="apitrace" revision="11f01789444d4ebe97581c31d8756d773e18356f"/>
<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"/>
<project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" revision="9025e50b9d29b3cabbbb21e1dd94d0d13121a17e"/>
<project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" revision="b89fda71fcd0fa0cf969310e75be3ea33e048b44"/>
<project groups="linux,arm" name="platform/prebuilts/gcc/linux-x86/arm/arm-eabi-4.7" path="prebuilts/gcc/linux-x86/arm/arm-eabi-4.7" revision="2e7d5348f35575870b3c7e567a9a9f6d66f8d6c5"/>
--- a/b2g/config/wasabi/sources.xml
+++ b/b2g/config/wasabi/sources.xml
@@ -12,22 +12,22 @@
<!--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="15c84c943e41ad834640a45e1e1c2ac804168af7"/>
+ <project name="gaia.git" path="gaia" remote="mozillaorg" revision="5458f73e319759543fddf7e96d7ece4d78318e32"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="7f792d756385bb894fba7645da59c67fe2c804bf"/>
<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="04ffbed6a18a2085a27bc113034fe71b8d10c10e"/>
+ <project name="apitrace" path="external/apitrace" remote="apitrace" revision="11f01789444d4ebe97581c31d8756d773e18356f"/>
<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="cd5dfce80bc3f0139a56b58aca633202ccaee7f8"/>
<project name="platform/bootable/recovery" path="bootable/recovery" revision="e0a9ac010df3afaa47ba107192c05ac8b5516435"/>
<project name="platform/development" path="development" revision="a384622f5fcb1d2bebb9102591ff7ae91fe8ed2d"/>
<project name="device/common" path="device/common" revision="7c65ea240157763b8ded6154a17d3c033167afb7"/>
<project name="device/sample" path="device/sample" revision="c328f3d4409db801628861baa8d279fb8855892f"/>
--- a/browser/components/loop/MozLoopAPI.jsm
+++ b/browser/components/loop/MozLoopAPI.jsm
@@ -28,49 +28,46 @@ function injectLoopAPI(targetWindow) {
let ringerStopper;
let api = {
/**
* Sets and gets the "do not disturb" mode activation flag.
*/
doNotDisturb: {
enumerable: true,
- configurable: true,
get: function() {
return MozLoopService.doNotDisturb;
},
set: function(aFlag) {
MozLoopService.doNotDisturb = aFlag;
}
},
/**
* Returns the current locale of the browser.
*
* @returns {String} The locale string
*/
locale: {
enumerable: true,
- configurable: true,
get: function() {
return MozLoopService.locale;
}
},
/**
* Returns translated strings associated with an element. Designed
* for use with l10n.js
*
* @param {String} key The element id
* @returns {Object} A JSON string containing the localized
* attribute/value pairs for the element.
*/
getStrings: {
enumerable: true,
- configurable: true,
writable: true,
value: function(key) {
return MozLoopService.getStrings(key);
}
},
/**
* Call to ensure that any necessary registrations for the Loop Service
@@ -80,17 +77,16 @@ function injectLoopAPI(targetWindow) {
* - err null on successful registration, non-null otherwise.
*
* @param {Function} callback Will be called once registration is complete,
* or straight away if registration has already
* happened.
*/
ensureRegistered: {
enumerable: true,
- configurable: true,
writable: true,
value: function(callback) {
// We translate from a promise to a callback, as we can't pass promises from
// Promise.jsm across the priv versus unpriv boundary.
return MozLoopService.register().then(() => {
callback(null);
}, err => {
callback(err);
@@ -107,17 +103,16 @@ function injectLoopAPI(targetWindow) {
* This is used to determine whether or not we should be registering with the
* push server on start.
*
* @param {Integer} expiryTimeSeconds The seconds since epoch of the expiry time
* of the url.
*/
noteCallUrlExpiry: {
enumerable: true,
- configurable: true,
writable: true,
value: function(expiryTimeSeconds) {
MozLoopService.noteCallUrlExpiry(expiryTimeSeconds);
}
},
/**
* Set any character preference under "loop."
@@ -125,17 +120,16 @@ function injectLoopAPI(targetWindow) {
* @param {String} prefName The name of the pref without the preceding "loop."
* @param {String} stringValue The value to set.
*
* Any errors thrown by the Mozilla pref API are logged to the console
* and cause false to be returned.
*/
setLoopCharPref: {
enumerable: true,
- configurable: true,
writable: true,
value: function(prefName, value) {
MozLoopService.setLoopCharPref(prefName, value);
}
},
/**
* Return any preference under "loop." that's coercible to a character
@@ -147,29 +141,27 @@ function injectLoopAPI(targetWindow) {
* Any errors thrown by the Mozilla pref API are logged to the console
* and cause null to be returned. This includes the case of the preference
* not being found.
*
* @return {String} on success, null on error
*/
getLoopCharPref: {
enumerable: true,
- configurable: true,
writable: true,
value: function(prefName) {
return MozLoopService.getLoopCharPref(prefName);
}
},
/**
* Starts alerting the user about an incoming call
*/
startAlerting: {
enumerable: true,
- configurable: true,
writable: true,
value: function() {
let chromeWindow = getChromeWindow(targetWindow);
chromeWindow.getAttention();
ringer = new chromeWindow.Audio();
ringer.src = Services.prefs.getCharPref("loop.ringtone");
ringer.loop = true;
ringer.load();
@@ -183,17 +175,16 @@ function injectLoopAPI(targetWindow) {
}
},
/**
* Stops alerting the user about an incoming call
*/
stopAlerting: {
enumerable: true,
- configurable: true,
writable: true,
value: function() {
if (ringerStopper) {
targetWindow.document.removeEventListener("visibilitychange",
ringerStopper);
ringerStopper = null;
}
if (ringer) {
@@ -219,31 +210,31 @@ function injectLoopAPI(targetWindow) {
* @param {String} path The path to make the request to.
* @param {String} method The request method, e.g. 'POST', 'GET'.
* @param {Object} payloadObj An object which is converted to JSON and
* transmitted with the request.
* @param {Function} callback Called when the request completes.
*/
hawkRequest: {
enumerable: true,
- configurable: true,
writable: true,
value: function(path, method, payloadObj, callback) {
// XXX Should really return a DOM promise here.
return MozLoopService.hawkRequest(path, method, payloadObj).then((response) => {
callback(null, response.body);
}, (error) => {
callback(Cu.cloneInto(error, targetWindow));
});
}
},
};
let contentObj = Cu.createObjectIn(targetWindow);
Object.defineProperties(contentObj, api);
+ Object.seal(contentObj);
Cu.makeObjectPropsNormal(contentObj);
targetWindow.navigator.wrappedJSObject.__defineGetter__("mozLoop", function() {
// We do this in a getter, so that we create these objects
// only on demand (this is a potential concern, since
// otherwise we might add one per iframe, and keep them
// alive for as long as the window is alive).
delete targetWindow.navigator.wrappedJSObject.mozLoop;
--- a/browser/components/loop/MozLoopService.jsm
+++ b/browser/components/loop/MozLoopService.jsm
@@ -42,31 +42,36 @@ XPCOMUtils.defineLazyModuleGetter(this,
XPCOMUtils.defineLazyModuleGetter(this, "MozLoopPushHandler",
"resource:///modules/loop/MozLoopPushHandler.jsm");
XPCOMUtils.defineLazyServiceGetter(this, "uuidgen",
"@mozilla.org/uuid-generator;1",
"nsIUUIDGenerator");
+// The current deferred for the registration process. This is set if in progress
+// or the registration was successful. This is null if a registration attempt was
+// unsuccessful.
+let gRegisteredDeferred = null;
+let gPushHandler = null;
+let gHawkClient = null;
+let gRegisteredLoopServer = false;
+let gLocalizedStrings = null;
+let gInitializeTimer = null;
+
/**
* Internal helper methods and state
*
* The registration is a two-part process. First we need to connect to
* and register with the push server. Then we need to take the result of that
* and register with the Loop server.
*/
let MozLoopServiceInternal = {
// The uri of the Loop server.
- loopServerUri: Services.prefs.getCharPref("loop.server"),
-
- // The current deferred for the registration process. This is set if in progress
- // or the registration was successful. This is null if a registration attempt was
- // unsuccessful.
- _registeredDeferred: null,
+ get loopServerUri() Services.prefs.getCharPref("loop.server"),
/**
* The initial delay for push registration. This ensures we don't start
* kicking off straight after browser startup, just a few seconds later.
*/
get initialRegistrationDelayMilliseconds() {
try {
// Let a pref override this for developer & testing use.
@@ -132,28 +137,28 @@ let MozLoopServiceInternal = {
* with the Loop server. It will return early if already registered.
*
* @param {Object} mockPushHandler Optional, test-only mock push handler. Used
* to allow mocking of the MozLoopPushHandler.
* @returns {Promise} a promise that is resolved with no params on completion, or
* rejected with an error code or string.
*/
promiseRegisteredWithServers: function(mockPushHandler) {
- if (this._registeredDeferred) {
- return this._registeredDeferred.promise;
+ if (gRegisteredDeferred) {
+ return gRegisteredDeferred.promise;
}
- this._registeredDeferred = Promise.defer();
+ gRegisteredDeferred = Promise.defer();
// We grab the promise early in case .initialize or its results sets
// it back to null on error.
- let result = this._registeredDeferred.promise;
+ let result = gRegisteredDeferred.promise;
- this._pushHandler = mockPushHandler || MozLoopPushHandler;
+ gPushHandler = mockPushHandler || MozLoopPushHandler;
- this._pushHandler.initialize(this.onPushRegistered.bind(this),
+ gPushHandler.initialize(this.onPushRegistered.bind(this),
this.onHandleNotification.bind(this));
return result;
},
/**
* Performs a hawk based request to the loop server.
*
@@ -163,35 +168,35 @@ let MozLoopServiceInternal = {
* transmitted with the request.
* @returns {Promise}
* Returns a promise that resolves to the response of the API call,
* or is rejected with an error. If the server response can be parsed
* as JSON and contains an 'error' property, the promise will be
* rejected with this JSON-parsed response.
*/
hawkRequest: function(path, method, payloadObj) {
- if (!this._hawkClient) {
- this._hawkClient = new HawkClient(this.loopServerUri);
+ if (!gHawkClient) {
+ gHawkClient = new HawkClient(this.loopServerUri);
}
let sessionToken;
try {
sessionToken = Services.prefs.getCharPref("loop.hawk-session-token");
} catch (x) {
// It is ok for this not to exist, we'll default to sending no-creds
}
let credentials;
if (sessionToken) {
// true = use a hex key, as required by the server (see bug 1032738).
credentials = deriveHawkCredentials(sessionToken, "sessionToken",
2 * 32, true);
}
- return this._hawkClient.request(path, method, credentials, payloadObj);
+ return gHawkClient.request(path, method, credentials, payloadObj);
},
/**
* Used to store a session token from a request if it exists in the headers.
*
* @param {Object} headers The request headers, which may include a
* "hawk-session-token" to be saved.
* @return true on success or no token, false on failure.
@@ -200,57 +205,56 @@ let MozLoopServiceInternal = {
let sessionToken = headers["hawk-session-token"];
if (sessionToken) {
// XXX should do more validation here
if (sessionToken.length === 64) {
Services.prefs.setCharPref("loop.hawk-session-token", sessionToken);
} else {
// XXX Bubble the precise details up to the UI somehow (bug 1013248).
console.warn("Loop server sent an invalid session token");
- this._registeredDeferred.reject("session-token-wrong-size");
- this._registeredDeferred = null;
+ gRegisteredDeferred.reject("session-token-wrong-size");
+ gRegisteredDeferred = null;
return false;
}
}
return true;
},
/**
* Callback from MozLoopPushHandler - The push server has been registered
* and has given us a push url.
*
* @param {String} pushUrl The push url given by the push server.
*/
onPushRegistered: function(err, pushUrl) {
if (err) {
- this._registeredDeferred.reject(err);
- this._registeredDeferred = null;
+ gRegisteredDeferred.reject(err);
+ gRegisteredDeferred = null;
return;
}
this.registerWithLoopServer(pushUrl);
},
/**
* Registers with the Loop server.
*
* @param {String} pushUrl The push url given by the push server.
* @param {Boolean} noRetry Optional, don't retry if authentication fails.
*/
registerWithLoopServer: function(pushUrl, noRetry) {
this.hawkRequest("/registration", "POST", { simple_push_url: pushUrl})
.then((response) => {
// If this failed we got an invalid token. storeSessionToken rejects
- // the _registeredDeferred promise for us, so here we just need to
+ // the gRegisteredDeferred promise for us, so here we just need to
// early return.
if (!this.storeSessionToken(response.headers))
return;
- this.registeredLoopServer = true;
- this._registeredDeferred.resolve();
+ gRegisteredDeferred.resolve();
// No need to clear the promise here, everything was good, so we don't need
// to re-register.
}, (error) => {
// There's other errors than invalid auth token, but we should only do the reset
// as a last resort.
if (error.code === 401 && error.errno === INVALID_AUTH_TOKEN) {
if (this.urlExpiryTimeIsInFuture()) {
// XXX Should this be reported to the user is a visible manner?
@@ -261,18 +265,18 @@ let MozLoopServiceInternal = {
// Authorization failed, invalid token, we need to try again with a new token.
Services.prefs.clearUserPref("loop.hawk-session-token");
this.registerWithLoopServer(pushUrl, true);
return;
}
// XXX Bubble the precise details up to the UI somehow (bug 1013248).
Cu.reportError("Failed to register with the loop server. error: " + error);
- this._registeredDeferred.reject(error.errno);
- this._registeredDeferred = null;
+ gRegisteredDeferred.reject(error.errno);
+ gRegisteredDeferred = null;
}
);
},
/**
* Callback from MozLoopPushHandler - A push notification has been received from
* the server.
*
@@ -288,18 +292,18 @@ let MozLoopServiceInternal = {
/**
* A getter to obtain and store the strings for loop. This is structured
* for use by l10n.js.
*
* @returns {Object} a map of element ids with attributes to set.
*/
get localizedStrings() {
- if (this._localizedStrings)
- return this._localizedStrings;
+ if (gLocalizedStrings)
+ return gLocalizedStrings;
var stringBundle =
Services.strings.createBundle('chrome://browser/locale/loop/loop.properties');
var map = {};
var enumerator = stringBundle.getSimpleEnumeration();
while (enumerator.hasMoreElements()) {
var string = enumerator.getNext().QueryInterface(Ci.nsIPropertyElement);
@@ -311,17 +315,17 @@ let MozLoopServiceInternal = {
property = key.substring(i + 1);
key = key.substring(0, i);
}
if (!(key in map))
map[key] = {};
map[key][property] = string.value;
}
- return this._localizedStrings = map;
+ return gLocalizedStrings = map;
},
/**
* Saves loop logs to the saved-telemetry-pings folder.
*
* @param {Object} pc The peerConnection in question.
*/
stageForTelemetryUpload: function(window, pc) {
@@ -440,54 +444,55 @@ let MozLoopServiceInternal = {
let pc_static = new window.mozRTCPeerConnectionStatic();
pc_static.registerPeerConnectionLifecycleCallback(onPCLifecycleChange);
}.bind(this), true);
};
Chat.open(contentWindow, origin, title, url, undefined, undefined, callback);
}
};
+Object.freeze(MozLoopServiceInternal);
+
+let gInitializeTimerFunc = () => {
+ // Kick off the push notification service into registering after a timeout
+ // this ensures we're not doing too much straight after the browser's finished
+ // starting up.
+ gInitializeTimer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
+ gInitializeTimer.initWithCallback(() => {
+ MozLoopService.register();
+ gInitializeTimer = null;
+ },
+ MozLoopServiceInternal.initialRegistrationDelayMilliseconds, Ci.nsITimer.TYPE_ONE_SHOT);
+};
/**
* Public API
*/
this.MozLoopService = {
+ set initializeTimerFunc(value) {
+ gInitializeTimerFunc = value;
+ },
+
/**
* Initialized the loop service, and starts registration with the
* push and loop servers.
*/
initialize: function() {
// Don't do anything if loop is not enabled.
if (!Services.prefs.getBoolPref("loop.enabled")) {
return;
}
// If expiresTime is in the future then kick-off registration.
if (MozLoopServiceInternal.urlExpiryTimeIsInFuture()) {
- this._startInitializeTimer();
+ gInitializeTimerFunc();
}
},
/**
- * Internal function, exposed for testing purposes only. Used to start the
- * initialize timer.
- */
- _startInitializeTimer: function() {
- // Kick off the push notification service into registering after a timeout
- // this ensures we're not doing too much straight after the browser's finished
- // starting up.
- this._initializeTimer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
- this._initializeTimer.initWithCallback(function() {
- this.register();
- this._initializeTimer = null;
- }.bind(this),
- MozLoopServiceInternal.initialRegistrationDelayMilliseconds, Ci.nsITimer.TYPE_ONE_SHOT);
- },
-
- /**
* Starts registration of Loop with the push server, and then will register
* with the Loop server. It will return early if already registered.
*
* @param {Object} mockPushHandler Optional, test-only mock push handler. Used
* to allow mocking of the MozLoopPushHandler.
* @returns {Promise} a promise that is resolved with no params on completion, or
* rejected with an error code or string.
*/
@@ -618,8 +623,9 @@ this.MozLoopService = {
* or is rejected with an error. If the server response can be parsed
* as JSON and contains an 'error' property, the promise will be
* rejected with this JSON-parsed response.
*/
hawkRequest: function(path, method, payloadObj) {
return MozLoopServiceInternal.hawkRequest(path, method, payloadObj);
},
};
+Object.freeze(this.MozLoopService);
--- a/browser/components/loop/test/xpcshell/test_loopservice_initialize.js
+++ b/browser/components/loop/test/xpcshell/test_loopservice_initialize.js
@@ -47,14 +47,14 @@ add_task(function test_initialize_starts
Assert.equal(startTimerCalled, true,
"should start the timer when expiry time is in the future");
});
function run_test()
{
// Override MozLoopService's initializeTimer, so that we can verify the timeout is called
// correctly.
- MozLoopService._startInitializeTimer = function() {
+ MozLoopService.initializeTimerFunc = function() {
startTimerCalled = true;
};
run_next_test();
}
--- a/browser/components/preferences/in-content/subdialogs.js
+++ b/browser/components/preferences/in-content/subdialogs.js
@@ -3,23 +3,25 @@
- You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
let gSubDialog = {
_closingCallback: null,
_frame: null,
_overlay: null,
+ _box: null,
_injectedStyleSheets: ["chrome://mozapps/content/preferences/preferences.css",
"chrome://browser/skin/preferences/preferences.css",
"chrome://browser/skin/preferences/in-content/preferences.css"],
init: function() {
this._frame = document.getElementById("dialogFrame");
this._overlay = document.getElementById("dialogOverlay");
+ this._box = document.getElementById("dialogBox");
// Make the close button work.
let dialogClose = document.getElementById("dialogClose");
dialogClose.addEventListener("command", this.close.bind(this));
// DOMTitleChanged isn't fired on the frame, only on the chromeEventHandler
let chromeBrowser = window.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIWebNavigation)
@@ -59,16 +61,20 @@ let gSubDialog = {
},
open: function(aURL, aFeatures = null, aParams = null, aClosingCallback = null) {
let features = aFeatures || "modal,centerscreen,resizable=no";
let dialog = window.openDialog(aURL, "dialogFrame", features, aParams);
if (aClosingCallback) {
this._closingCallback = aClosingCallback.bind(dialog);
}
+ let featureParams = new URLSearchParams(features.toLowerCase());
+ this._box.setAttribute("resizable", featureParams.has("resizable") &&
+ featureParams.get("resizable") != "no" &&
+ featureParams.get("resizable") != 0);
return dialog;
},
close: function(aEvent = null) {
if (this._closingCallback) {
try {
this._closingCallback.call(null, aEvent);
} catch (ex) {
--- a/browser/themes/shared/incontentprefs/preferences.css
+++ b/browser/themes/shared/incontentprefs/preferences.css
@@ -864,16 +864,23 @@ description > html|a {
#dialogBox {
border: 1px solid #666;
display: -moz-box;
margin: 0;
padding-right: 6px;
padding-left: 6px;
}
+#dialogBox[resizable="true"] {
+ resize: both;
+ overflow: hidden;
+ min-height: 30em;
+ min-width: 66ch;
+}
+
#dialogTitle {
-moz-margin-start: 5px !important;
}
.close-icon {
background-color: transparent !important;
border: none;
box-shadow: none;
@@ -883,18 +890,19 @@ description > html|a {
}
#dialogBox > .groupbox-body {
-moz-appearance: none;
padding: 0;
}
#dialogFrame {
+ -moz-box-flex: 1;
/* Default dialog dimensions */
- height: 20em;
+ height: 30em;
width: 66ch;
}
/* needs to be removed with bug 1035625 */
:-moz-any(dialog, window, prefwindow) resizer {
display: none;
}
--- a/dom/apps/src/AppsServiceChild.jsm
+++ b/dom/apps/src/AppsServiceChild.jsm
@@ -3,76 +3,346 @@
* You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
const Cu = Components.utils;
const Cc = Components.classes;
const Ci = Components.interfaces;
-// This module exposes a subset of the functionnalities of the parent DOM
-// Registry to content processes, to be be used from the AppsService component.
+// This module exposes a subset of the functionalities of the parent DOM
+// Registry to content processes, to be used from the AppsService component.
-this.EXPORTED_SYMBOLS = ["DOMApplicationRegistry"];
+this.EXPORTED_SYMBOLS = ["DOMApplicationRegistry", "WrappedManifestCache"];
Cu.import("resource://gre/modules/AppsUtils.jsm");
Cu.import("resource://gre/modules/Services.jsm");
function debug(s) {
//dump("-*- AppsServiceChild.jsm: " + s + "\n");
}
+const APPS_IPC_MSG_NAMES = [
+ "Webapps:AddApp",
+ "Webapps:RemoveApp",
+ "Webapps:UpdateApp",
+ "Webapps:CheckForUpdate:Return:KO",
+ "Webapps:FireEvent",
+ "Webapps:UpdateState"
+];
+
+// A simple cache for the wrapped manifests.
+this.WrappedManifestCache = {
+ _cache: { },
+
+ // Gets an entry from the cache, and populates the cache if needed.
+ get: function mcache_get(aManifestURL, aManifest, aWindow, aInnerWindowID) {
+ if (!aManifest) {
+ return;
+ }
+
+ if (!(aManifestURL in this._cache)) {
+ this._cache[aManifestURL] = { };
+ }
+
+ let winObjs = this._cache[aManifestURL];
+ if (!(aInnerWindowID in winObjs)) {
+ winObjs[aInnerWindowID] = Cu.cloneInto(aManifest, aWindow);
+ }
+
+ return winObjs[aInnerWindowID];
+ },
+
+ // Invalidates an entry in the cache.
+ evict: function mcache_evict(aManifestURL, aInnerWindowID) {
+ debug("Evicting manifest " + aManifestURL + " window ID " +
+ aInnerWindowID);
+ if (aManifestURL in this._cache) {
+ let winObjs = this._cache[aManifestURL];
+ if (aInnerWindowID in winObjs) {
+ delete winObjs[aInnerWindowID];
+ }
+
+ if (Object.keys(winObjs).length == 0) {
+ delete this._cache[aManifestURL];
+ }
+ }
+ },
+
+ observe: function(aSubject, aTopic, aData) {
+ // Clear the cache on memory pressure.
+ this._cache = { };
+ Cu.forceGC();
+ },
+
+ init: function() {
+ Services.obs.addObserver(this, "memory-pressure", false);
+ }
+};
+
+this.WrappedManifestCache.init();
+
+
+// DOMApplicationRegistry keeps a cache containing a list of apps in the device.
+// This information is updated with the data received from the main process and
+// it is queried by the DOM objects to set their state.
+// This module handle all the messages broadcasted from the parent process,
+// including DOM events, which are dispatched to the corresponding DOM objects.
+
this.DOMApplicationRegistry = {
+ // DOMApps will hold a list of arrays of weak references to
+ // mozIDOMApplication objects indexed by manifest URL.
+ DOMApps: {},
+
+ ready: false,
+ webapps: null,
+
init: function init() {
- debug("init");
this.cpmm = Cc["@mozilla.org/childprocessmessagemanager;1"]
.getService(Ci.nsISyncMessageSender);
- ["Webapps:AddApp", "Webapps:RemoveApp"].forEach((function(aMsgName) {
+ APPS_IPC_MSG_NAMES.forEach((function(aMsgName) {
this.cpmm.addMessageListener(aMsgName, this);
}).bind(this));
+ this.cpmm.sendAsyncMessage("Webapps:RegisterForMessages", {
+ messages: APPS_IPC_MSG_NAMES
+ });
+
// We need to prime the cache with the list of apps.
- // XXX shoud we do this async and block callers if it's not yet there?
- this.webapps = this.cpmm.sendSyncMessage("Webapps:GetList", { })[0];
-
+ let list = this.cpmm.sendSyncMessage("Webapps:GetList", { })[0];
+ this.webapps = list.webapps;
// We need a fast mapping from localId -> app, so we add an index.
+ // We also add the manifest to the app object.
this.localIdIndex = { };
for (let id in this.webapps) {
let app = this.webapps[id];
this.localIdIndex[app.localId] = app;
+ app.manifest = list.manifests[id];
}
Services.obs.addObserver(this, "xpcom-shutdown", false);
},
observe: function(aSubject, aTopic, aData) {
- // cpmm.addMessageListener causes the DOMApplicationRegistry object to live
- // forever if we don't clean up properly.
+ // cpmm.addMessageListener causes the DOMApplicationRegistry object to
+ // live forever if we don't clean up properly.
this.webapps = null;
- ["Webapps:AddApp", "Webapps:RemoveApp"].forEach((function(aMsgName) {
+ this.DOMApps = null;
+
+ APPS_IPC_MSG_NAMES.forEach((aMsgName) => {
this.cpmm.removeMessageListener(aMsgName, this);
- }).bind(this));
+ });
+
+ this.cpmm.sendAsyncMessage("Webapps:UnregisterForMessages",
+ APPS_IPC_MSG_NAMES)
},
receiveMessage: function receiveMessage(aMessage) {
debug("Received " + aMessage.name + " message.");
- let msg = aMessage.json;
+ let msg = aMessage.data;
switch (aMessage.name) {
case "Webapps:AddApp":
this.webapps[msg.id] = msg.app;
this.localIdIndex[msg.app.localId] = msg.app;
+ if (msg.manifest) {
+ this.webapps[msg.id].manifest = msg.manifest;
+ }
break;
case "Webapps:RemoveApp":
+ delete this.DOMApps[this.webapps[msg.id].manifestURL];
delete this.localIdIndex[this.webapps[msg.id].localId];
delete this.webapps[msg.id];
break;
+ case "Webapps:UpdateApp":
+ let app = this.webapps[msg.oldId];
+ if (!app) {
+ return;
+ }
+
+ if (msg.app) {
+ for (let prop in msg.app) {
+ app[prop] = msg.app[prop];
+ }
+ }
+
+ this.webapps[msg.newId] = app;
+ this.localIdIndex[app.localId] = app;
+ delete this.webapps[msg.oldId];
+
+ let apps = this.DOMApps[msg.app.manifestURL];
+ if (!apps) {
+ return;
+ }
+ for (let i = 0; i < apps.length; i++) {
+ let domApp = apps[i].get();
+ if (!domApp || domApp._window === null) {
+ apps.splice(i, 1);
+ continue;
+ }
+ domApp._proxy = new Proxy(domApp, {
+ get: function(target, prop) {
+ if (!DOMApplicationRegistry.webapps[msg.newId]) {
+ return;
+ }
+ return DOMApplicationRegistry.webapps[msg.newId][prop];
+ },
+ set: function(target, prop, val) {
+ if (!DOMApplicationRegistry.webapps[msg.newId]) {
+ return;
+ }
+ DOMApplicationRegistry.webapps[msg.newId][prop] = val;
+ return;
+ },
+ });
+ }
+ break;
+ case "Webapps:FireEvent":
+ this._fireEvent(aMessage);
+ break;
+ case "Webapps:UpdateState":
+ this._updateState(msg);
+ break;
+ case "Webapps:CheckForUpdate:Return:KO":
+ let DOMApps = this.DOMApps[msg.manifestURL];
+ if (!DOMApps || !msg.requestID) {
+ return;
+ }
+ DOMApps.forEach((DOMApp) => {
+ let domApp = DOMApp.get();
+ if (domApp && msg.requestID) {
+ domApp._fireRequestResult(aMessage, true /* aIsError */);
+ }
+ });
+ break;
}
},
+ /**
+ * mozIDOMApplication management
+ */
+
+ // Every time a DOM app is created, we save a weak reference to it that will
+ // be used to dispatch events and fire request results.
+ addDOMApp: function(aApp, aManifestURL, aId) {
+ let weakRef = Cu.getWeakReference(aApp);
+
+ if (!this.DOMApps[aManifestURL]) {
+ this.DOMApps[aManifestURL] = [];
+ }
+
+ let apps = this.DOMApps[aManifestURL];
+
+ // Get rid of dead weak references.
+ for (let i = 0; i < apps.length; i++) {
+ let app = apps[i].get();
+ if (!app || app._window === null) {
+ apps.splice(i, 1);
+ }
+ }
+
+ apps.push(weakRef);
+
+ // Each DOM app contains a proxy object used to build their state. We
+ // return the handler for this proxy object with traps to get and set
+ // app properties kept in the DOMApplicationRegistry app cache.
+ return {
+ get: function(target, prop) {
+ if (!DOMApplicationRegistry.webapps[aId]) {
+ return;
+ }
+ return DOMApplicationRegistry.webapps[aId][prop];
+ },
+ set: function(target, prop, val) {
+ if (!DOMApplicationRegistry.webapps[aId]) {
+ return;
+ }
+ DOMApplicationRegistry.webapps[aId][prop] = val;
+ return;
+ },
+ };
+ },
+
+ _fireEvent: function(aMessage) {
+ let msg = aMessage.data;
+ debug("_fireEvent " + JSON.stringify(msg));
+ if (!this.DOMApps || !msg.manifestURL || !msg.eventType) {
+ return;
+ }
+
+ let DOMApps = this.DOMApps[msg.manifestURL];
+ if (!DOMApps) {
+ return;
+ }
+
+ // The parent might ask childs to trigger more than one event in one
+ // shot, so in order to avoid needless IPC we allow an array for the
+ // 'eventType' IPC message field.
+ if (!Array.isArray(msg.eventType)) {
+ msg.eventType = [msg.eventType];
+ }
+
+ DOMApps.forEach((DOMApp) => {
+ let domApp = DOMApp.get();
+ if (!domApp) {
+ return;
+ }
+ msg.eventType.forEach((aEventType) => {
+ if ('on' + aEventType in domApp) {
+ domApp._fireEvent(aEventType);
+ }
+ });
+
+ if (msg.requestID) {
+ aMessage.data.result = msg.manifestURL;
+ domApp._fireRequestResult(aMessage);
+ }
+ });
+ },
+
+ _updateState: function(aMessage) {
+ if (!this.DOMApps || !aMessage.id) {
+ return;
+ }
+
+ let app = this.webapps[aMessage.id];
+ if (!app) {
+ return;
+ }
+
+ if (aMessage.app) {
+ for (let prop in aMessage.app) {
+ app[prop] = aMessage.app[prop];
+ }
+ }
+
+ if ("error" in aMessage) {
+ app.downloadError = aMessage.error;
+ }
+
+ if (aMessage.manifest) {
+ app.manifest = aMessage.manifest;
+ // Evict the wrapped manifest cache for all the affected DOM objects.
+ let DOMApps = this.DOMApps[app.manifestURL];
+ if (!DOMApps) {
+ return;
+ }
+ DOMApps.forEach((DOMApp) => {
+ let domApp = DOMApp.get();
+ if (!domApp) {
+ return;
+ }
+ WrappedManifestCache.evict(app.manifestURL, domApp.innerWindowID);
+ });
+ }
+ },
+
+ /**
+ * nsIAppsService API
+ */
getAppByManifestURL: function getAppByManifestURL(aManifestURL) {
debug("getAppByManifestURL " + aManifestURL);
return AppsUtils.getAppByManifestURL(this.webapps, aManifestURL);
},
getAppLocalIdByManifestURL: function getAppLocalIdByManifestURL(aManifestURL) {
debug("getAppLocalIdByManifestURL " + aManifestURL);
return AppsUtils.getAppLocalIdByManifestURL(this.webapps, aManifestURL);
@@ -84,17 +354,17 @@ this.DOMApplicationRegistry = {
},
getAppLocalIdByStoreId: function(aStoreId) {
debug("getAppLocalIdByStoreId:" + aStoreId);
return AppsUtils.getAppLocalIdByStoreId(this.webapps, aStoreId);
},
getAppByLocalId: function getAppByLocalId(aLocalId) {
- debug("getAppByLocalId " + aLocalId);
+ debug("getAppByLocalId " + aLocalId + " - ready: " + this.ready);
let app = this.localIdIndex[aLocalId];
if (!app) {
debug("Ouch, No app!");
return null;
}
return new mozIApplication(app);
},
--- a/dom/apps/src/Webapps.js
+++ b/dom/apps/src/Webapps.js
@@ -7,16 +7,17 @@ const Ci = Components.interfaces;
const Cu = Components.utils;
const Cr = Components.results;
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/DOMRequestHelper.jsm");
Cu.import("resource://gre/modules/AppsUtils.jsm");
Cu.import("resource://gre/modules/BrowserElementPromptService.jsm");
+Cu.import("resource://gre/modules/AppsServiceChild.jsm");
XPCOMUtils.defineLazyServiceGetter(this, "cpmm",
"@mozilla.org/childprocessmessagemanager;1",
"nsIMessageSender");
function convertAppsArray(aApps, aWindow) {
let apps = new aWindow.Array();
for (let i = 0; i < aApps.length; i++) {
@@ -273,134 +274,121 @@ WebappsRegistry.prototype = {
flags: Ci.nsIClassInfo.DOM_OBJECT,
classDescription: "Webapps Registry"})
}
/**
* mozIDOMApplication object
*/
-// A simple cache for the wrapped manifests.
-let manifestCache = {
- _cache: { },
-
- // Gets an entry from the cache, and populates the cache if needed.
- get: function mcache_get(aManifestURL, aManifest, aWindow, aInnerWindowID) {
- if (!(aManifestURL in this._cache)) {
- this._cache[aManifestURL] = { };
- }
-
- let winObjs = this._cache[aManifestURL];
- if (!(aInnerWindowID in winObjs)) {
- winObjs[aInnerWindowID] = Cu.cloneInto(aManifest, aWindow);
- }
-
- return winObjs[aInnerWindowID];
- },
-
- // Invalidates an entry in the cache.
- evict: function mcache_evict(aManifestURL, aInnerWindowID) {
- if (aManifestURL in this._cache) {
- let winObjs = this._cache[aManifestURL];
- if (aInnerWindowID in winObjs) {
- delete winObjs[aInnerWindowID];
- }
-
- if (Object.keys(winObjs).length == 0) {
- delete this._cache[aManifestURL];
- }
- }
- },
-
- observe: function(aSubject, aTopic, aData) {
- // Clear the cache on memory pressure.
- this._cache = { };
- },
-
- init: function() {
- Services.obs.addObserver(this, "memory-pressure", false);
- }
-};
-
function createApplicationObject(aWindow, aApp) {
- let app = Cc["@mozilla.org/webapps/application;1"].createInstance(Ci.mozIDOMApplication);
+ let app = Cc["@mozilla.org/webapps/application;1"]
+ .createInstance(Ci.mozIDOMApplication);
app.wrappedJSObject.init(aWindow, aApp);
return app;
}
function WebappsApplication() {
this.wrappedJSObject = this;
}
WebappsApplication.prototype = {
__proto__: DOMRequestIpcHelper.prototype,
init: function(aWindow, aApp) {
+ let proxyHandler = DOMApplicationRegistry.addDOMApp(this,
+ aApp.manifestURL,
+ aApp.id);
+ this._proxy = new Proxy(this, proxyHandler);
+
this._window = aWindow;
- let principal = this._window.document.nodePrincipal;
- this._appStatus = principal.appStatus;
- this.origin = aApp.origin;
- this._manifest = aApp.manifest;
- this._updateManifest = aApp.updateManifest;
- this.manifestURL = aApp.manifestURL;
- this.receipts = aApp.receipts;
- this.installOrigin = aApp.installOrigin;
- this.installTime = aApp.installTime;
- this.installState = aApp.installState || "installed";
- this.removable = aApp.removable;
- this.lastUpdateCheck = aApp.lastUpdateCheck ? aApp.lastUpdateCheck
- : Date.now();
- this.updateTime = aApp.updateTime ? aApp.updateTime
- : aApp.installTime;
- this.progress = NaN;
- this.downloadAvailable = aApp.downloadAvailable;
- this.downloading = aApp.downloading;
- this.readyToApplyDownload = aApp.readyToApplyDownload;
- this.downloadSize = aApp.downloadSize || 0;
this._onprogress = null;
this._ondownloadsuccess = null;
this._ondownloaderror = null;
this._ondownloadavailable = null;
this._ondownloadapplied = null;
- this._downloadError = null;
+ this.initDOMRequestHelper(aWindow);
+ },
+
+ get _appStatus() {
+ return this._proxy.appStatus;
+ },
+
+ get downloadAvailable() {
+ return this._proxy.downloadAvailable;
+ },
+
+ get downloading() {
+ return this._proxy.downloading;
+ },
- this.initDOMRequestHelper(aWindow, [
- { name: "Webapps:CheckForUpdate:Return:KO", weakRef: true },
- { name: "Webapps:Connect:Return:OK", weakRef: true },
- { name: "Webapps:Connect:Return:KO", weakRef: true },
- { name: "Webapps:FireEvent", weakRef: true },
- { name: "Webapps:GetConnections:Return:OK", weakRef: true },
- { name: "Webapps:UpdateState", weakRef: true }
- ]);
+ get downloadSize() {
+ return this._proxy.downloadSize;
+ },
+
+ get installOrigin() {
+ return this._proxy.installOrigin;
+ },
+
+ get installState() {
+ return this._proxy.installState;
+ },
+
+ get installTime() {
+ return this._proxy.installTime;
+ },
- cpmm.sendAsyncMessage("Webapps:RegisterForMessages", {
- messages: ["Webapps:FireEvent",
- "Webapps:UpdateState"],
- app: {
- id: this.id,
- manifestURL: this.manifestURL,
- installState: this.installState,
- downloading: this.downloading
- }
- });
+ get lastUpdateCheck() {
+ return this._proxy.lastUpdateCheck;
+ },
+
+ get manifestURL() {
+ return this._proxy.manifestURL;
+ },
+
+ get origin() {
+ return this._proxy.origin;
+ },
+
+ get progress() {
+ return this._proxy.progress;
+ },
+
+ get readyToApplyDownload() {
+ return this._proxy.readyToApplyDownload;
+ },
+
+ get receipts() {
+ return this._proxy.receipts;
+ },
+
+ set receipts(aReceipts) {
+ this._proxy.receipts = aReceipts;
+ },
+
+ get removable() {
+ return this._proxy.removable;
+ },
+
+ get updateTime() {
+ return this._proxy.updateTime;
},
get manifest() {
- return manifestCache.get(this.manifestURL,
- this._manifest,
- this._window,
- this.innerWindowID);
+ return WrappedManifestCache.get(this.manifestURL,
+ this._proxy.manifest,
+ this._window,
+ this.innerWindowID);
},
get updateManifest() {
- return this.updateManifest =
- this._updateManifest ? Cu.cloneInto(this._updateManifest, this._window)
- : null;
+ return this._proxy.updateManifest ?
+ Cu.cloneInto(this._proxy.updateManifest, this._window) : null;
},
set onprogress(aCallback) {
this._onprogress = aCallback;
},
get onprogress() {
return this._onprogress;
@@ -435,20 +423,20 @@ WebappsApplication.prototype = {
},
get ondownloadapplied() {
return this._ondownloadapplied;
},
get downloadError() {
// Only return DOMError when we have an error.
- if (!this._downloadError) {
+ if (!this._proxy.downloadError) {
return null;
}
- return new this._window.DOMError(this._downloadError);
+ return new this._window.DOMError(this._proxy.downloadError);
},
download: function() {
cpmm.sendAsyncMessage("Webapps:Download",
{ manifestURL: this.manifestURL });
},
cancelDownload: function() {
@@ -480,51 +468,55 @@ WebappsApplication.prototype = {
},
clearBrowserData: function() {
let request = this.createRequest();
let browserChild =
BrowserElementPromptService.getBrowserElementChildForWindow(this._window);
if (browserChild) {
this.addMessageListeners("Webapps:ClearBrowserData:Return");
- browserChild.messageManager.sendAsyncMessage(
- "Webapps:ClearBrowserData",
- { manifestURL: this.manifestURL,
- oid: this._id,
- requestID: this.getRequestId(request) }
- );
+ browserChild.messageManager.sendAsyncMessage("Webapps:ClearBrowserData", {
+ manifestURL: this.manifestURL,
+ oid: this._id,
+ requestID: this.getRequestId(request)
+ });
} else {
Services.DOMRequest.fireErrorAsync(request, "NO_CLEARABLE_BROWSER");
}
return request;
},
connect: function(aKeyword, aRules) {
+ this.addMessageListeners(["Webapps:Connect:Return:OK",
+ "Webapps:Connect:Return:KO"]);
return this.createPromise(function (aResolve, aReject) {
- cpmm.sendAsyncMessage("Webapps:Connect",
- { keyword: aKeyword,
- rules: aRules,
- manifestURL: this.manifestURL,
- outerWindowID: this._id,
- requestID: this.getPromiseResolverId({
- resolve: aResolve,
- reject: aReject
- })});
+ cpmm.sendAsyncMessage("Webapps:Connect", {
+ keyword: aKeyword,
+ rules: aRules,
+ manifestURL: this.manifestURL,
+ outerWindowID: this._id,
+ requestID: this.getPromiseResolverId({
+ resolve: aResolve,
+ reject: aReject
+ })
+ });
}.bind(this));
},
getConnections: function() {
+ this.addMessageListeners("Webapps:GetConnections:Return:OK");
return this.createPromise(function (aResolve, aReject) {
- cpmm.sendAsyncMessage("Webapps:GetConnections",
- { manifestURL: this.manifestURL,
- outerWindowID: this._id,
- requestID: this.getPromiseResolverId({
- resolve: aResolve,
- reject: aReject
- })});
+ cpmm.sendAsyncMessage("Webapps:GetConnections", {
+ manifestURL: this.manifestURL,
+ outerWindowID: this._id,
+ requestID: this.getPromiseResolverId({
+ resolve: aResolve,
+ reject: aReject
+ })
+ });
}.bind(this));
},
addReceipt: function(receipt) {
let request = this.createRequest();
this.addMessageListeners(["Webapps:AddReceipt:Return:OK",
"Webapps:AddReceipt:Return:KO"]);
@@ -563,141 +555,92 @@ WebappsApplication.prototype = {
oid: this._id,
requestID: this.getRequestId(request) });
return request;
},
uninit: function() {
this._onprogress = null;
- cpmm.sendAsyncMessage("Webapps:UnregisterForMessages", [
- "Webapps:FireEvent",
- "Webapps:UpdateState"
- ]);
-
- manifestCache.evict(this.manifestURL, this.innerWindowID);
+ WrappedManifestCache.evict(this.manifestURL, this.innerWindowID);
},
_fireEvent: function(aName) {
let handler = this["_on" + aName];
if (handler) {
let event = new this._window.MozApplicationEvent(aName, {
application: this
});
try {
handler.handleEvent(event);
} catch (ex) {
dump("Event handler expection " + ex + "\n");
}
}
},
- _updateState: function(aMsg) {
- if (aMsg.app) {
- for (let prop in aMsg.app) {
- this[prop] = aMsg.app[prop];
- }
+ _fireRequestResult: function(aMessage, aIsError) {
+ let req;
+ let msg = aMessage.data;
+ req = this.takeRequest(msg.requestID);
+ if (!req) {
+ return;
}
- // Intentional use of 'in' so we unset the error if this is explicitly null.
- if ('error' in aMsg) {
- this._downloadError = aMsg.error;
- }
-
- if (aMsg.manifest) {
- this._manifest = aMsg.manifest;
- manifestCache.evict(this.manifestURL, this.innerWindowID);
- }
+ aIsError ? Services.DOMRequest.fireError(req, msg.error)
+ : Services.DOMRequest.fireSuccess(req, msg.result);
},
receiveMessage: function(aMessage) {
let msg = aMessage.json;
let req;
if (aMessage.name == "Webapps:Connect:Return:OK" ||
aMessage.name == "Webapps:Connect:Return:KO" ||
aMessage.name == "Webapps:GetConnections:Return:OK") {
req = this.takePromiseResolver(msg.requestID);
} else {
req = this.takeRequest(msg.requestID);
}
- // ondownload* callbacks should be triggered on all app instances
- if ((msg.oid != this._id || !req) &&
- aMessage.name !== "Webapps:FireEvent" &&
- aMessage.name !== "Webapps:UpdateState") {
+ if (msg.oid !== this._id || !req) {
return;
}
switch (aMessage.name) {
case "Webapps:Launch:Return:KO":
this.removeMessageListeners(["Webapps:Launch:Return:OK",
"Webapps:Launch:Return:KO"]);
Services.DOMRequest.fireError(req, "APP_INSTALL_PENDING");
break;
case "Webapps:Launch:Return:OK":
this.removeMessageListeners(["Webapps:Launch:Return:OK",
"Webapps:Launch:Return:KO"]);
Services.DOMRequest.fireSuccess(req, null);
break;
- case "Webapps:CheckForUpdate:Return:KO":
- Services.DOMRequest.fireError(req, msg.error);
- break;
- case "Webapps:FireEvent":
- if (msg.manifestURL != this.manifestURL) {
- return;
- }
-
- // The parent might ask childs to trigger more than one event in one
- // shot, so in order to avoid needless IPC we allow an array for the
- // 'eventType' IPC message field.
- if (!Array.isArray(msg.eventType)) {
- msg.eventType = [msg.eventType];
- }
-
- msg.eventType.forEach((aEventType) => {
- // If we are in a successful state clear any past errors.
- if (aEventType === 'downloadapplied' ||
- aEventType === 'downloadsuccess') {
- this._downloadError = null;
- }
-
- if ("_on" + aEventType in this) {
- this._fireEvent(aEventType);
- } else {
- dump("Unsupported event type " + aEventType + "\n");
- }
- });
-
- if (req) {
- Services.DOMRequest.fireSuccess(req, this.manifestURL);
- }
- break;
- case "Webapps:UpdateState":
- if (msg.manifestURL != this.manifestURL) {
- return;
- }
-
- this._updateState(msg);
- break;
case "Webapps:ClearBrowserData:Return":
this.removeMessageListeners(aMessage.name);
Services.DOMRequest.fireSuccess(req, null);
break;
case "Webapps:Connect:Return:OK":
+ this.removeMessageListeners(["Webapps:Connect:Return:OK",
+ "Webapps:Connect:Return:KO"]);
let messagePorts = [];
msg.messagePortIDs.forEach((aPortID) => {
let port = new this._window.MozInterAppMessagePort(aPortID);
messagePorts.push(port);
});
req.resolve(messagePorts);
break;
case "Webapps:Connect:Return:KO":
+ this.removeMessageListeners(["Webapps:Connect:Return:OK",
+ "Webapps:Connect:Return:KO"]);
req.reject("No connections registered");
break;
case "Webapps:GetConnections:Return:OK":
+ this.removeMessageListeners(aMessage.name);
let connections = [];
msg.connections.forEach((aConnection) => {
let connection =
new this._window.MozInterAppConnection(aConnection.keyword,
aConnection.pubAppManifestURL,
aConnection.subAppManifestURL);
connections.push(connection);
});
@@ -800,17 +743,16 @@ WebappsApplicationMgmt.prototype = {
return;
}
cpmm.sendAsyncMessage("Webapps:ApplyDownload",
{ manifestURL: aApp.manifestURL });
},
uninstall: function(aApp) {
- dump("-- webapps.js uninstall " + aApp.manifestURL + "\n");
let request = this.createRequest();
cpmm.sendAsyncMessage("Webapps:Uninstall", { origin: aApp.origin,
manifestURL: aApp.manifestURL,
oid: this._id,
requestID: this.getRequestId(request) });
return request;
},
@@ -869,22 +811,18 @@ WebappsApplicationMgmt.prototype = {
let app = msg.app;
let event = new this._window.MozApplicationEvent("applicationinstall",
{ application : createApplicationObject(this._window, app) });
this._oninstall.handleEvent(event);
}
break;
case "Webapps:Uninstall:Broadcast:Return:OK":
if (this._onuninstall) {
- let detail = {
- manifestURL: msg.manifestURL,
- origin: msg.origin
- };
let event = new this._window.MozApplicationEvent("applicationuninstall",
- { application : createApplicationObject(this._window, detail) });
+ { application : createApplicationObject(this._window, msg) });
this._onuninstall.handleEvent(event);
}
break;
case "Webapps:Uninstall:Return:OK":
Services.DOMRequest.fireSuccess(req, msg.manifestURL);
break;
case "Webapps:Uninstall:Return:KO":
Services.DOMRequest.fireError(req, "NOT_INSTALLED");
@@ -903,12 +841,10 @@ WebappsApplicationMgmt.prototype = {
classInfo: XPCOMUtils.generateCI({classID: Components.ID("{8c1bca96-266f-493a-8d57-ec7a95098c15}"),
contractID: "@mozilla.org/webapps/application-mgmt;1",
interfaces: [Ci.mozIDOMApplicationMgmt],
flags: Ci.nsIClassInfo.DOM_OBJECT,
classDescription: "Webapps Application Mgmt"})
}
-manifestCache.init();
-
this.NSGetFactory = XPCOMUtils.generateNSGetFactory([WebappsRegistry,
WebappsApplication]);
--- a/dom/apps/src/Webapps.jsm
+++ b/dom/apps/src/Webapps.jsm
@@ -174,16 +174,17 @@ this.DOMApplicationRegistry = {
this.frameMessages = ["Webapps:ClearBrowserData"];
this.messages.forEach((function(msgName) {
ppmm.addMessageListener(msgName, this);
}).bind(this));
cpmm.addMessageListener("Activities:Register:OK", this);
+ cpmm.addMessageListener("Activities:Register:KO", this);
Services.obs.addObserver(this, "xpcom-shutdown", false);
Services.obs.addObserver(this, "memory-pressure", false);
AppDownloadManager.registerCancelFunction(this.cancelDownload.bind(this));
this.appsFile = FileUtils.getFile(DIRECTORY_NAME,
["webapps", "webapps.json"], true).path;
@@ -270,28 +271,38 @@ this.DOMApplicationRegistry = {
Services.obs.notifyObservers(this, "webapps-registry-start", null);
this._registryStarted.resolve();
},
get registryStarted() {
return this._registryStarted.promise;
},
+ // The registry will be safe to clone when this promise is resolved.
+ _safeToClone: Promise.defer(),
+
// Notify we are done with registering apps and save a copy of the registry.
_registryReady: Promise.defer(),
notifyAppsRegistryReady: function notifyAppsRegistryReady() {
+ // Usually this promise will be resolved earlier, but just in case,
+ // resolve it here also.
+ this._safeToClone.resolve();
this._registryReady.resolve();
Services.obs.notifyObservers(this, "webapps-registry-ready", null);
this._saveApps();
},
get registryReady() {
return this._registryReady.promise;
},
+ get safeToClone() {
+ return this._safeToClone.promise;
+ },
+
// Ensure that the .to property in redirects is a relative URL.
sanitizeRedirects: function sanitizeRedirects(aSource) {
if (!aSource) {
return null;
}
let res = [];
for (let i = 0; i < aSource.length; i++) {
@@ -957,16 +968,17 @@ this.DOMApplicationRegistry = {
app.role = localeManifest.role;
if (app.appStatus >= Ci.nsIPrincipal.APP_STATUS_PRIVILEGED) {
app.redirects = this.sanitizeRedirects(manifest.redirects);
}
this._registerSystemMessages(manifest, app);
this._registerInterAppConnections(manifest, app);
appsToRegister.push({ manifest: manifest, app: app });
});
+ this._safeToClone.resolve();
this._registerActivitiesForApps(appsToRegister, aRunUpdate);
});
},
observe: function(aSubject, aTopic, aData) {
if (aTopic == "xpcom-shutdown") {
this.messages.forEach((function(msgName) {
ppmm.removeMessageListener(msgName, this);
@@ -1084,98 +1096,124 @@ this.DOMApplicationRegistry = {
return null;
}
}
let msg = aMessage.data || {};
let mm = aMessage.target;
msg.mm = mm;
+ let processedImmediately = true;
+
+ // There are two kind of messages: the messages that only make sense once the
+ // registry is ready, and those that can (or have to) be treated as soon as
+ // they're received.
switch (aMessage.name) {
- case "Webapps:Install": {
-#ifdef MOZ_WIDGET_ANDROID
- Services.obs.notifyObservers(mm, "webapps-runtime-install", JSON.stringify(msg));
-#else
- this.doInstall(msg, mm);
-#endif
- break;
- }
- case "Webapps:GetSelf":
- this.getSelf(msg, mm);
- break;
- case "Webapps:Uninstall":
-#ifdef MOZ_WIDGET_ANDROID
- Services.obs.notifyObservers(mm, "webapps-runtime-uninstall", JSON.stringify(msg));
-#else
- this.doUninstall(msg, mm);
-#endif
+ case "Activities:Register:KO":
+ dump("Activities didn't register correctly!");
+ case "Activities:Register:OK":
+ // Activities:Register:OK is special because it's one way the registryReady
+ // promise can be resolved.
+ // XXX: What to do when the activities registration failed? At this point
+ // just act as if nothing happened.
+ this.notifyAppsRegistryReady();
break;
- case "Webapps:Launch":
- this.doLaunch(msg, mm);
- break;
- case "Webapps:CheckInstalled":
- this.checkInstalled(msg, mm);
- break;
- case "Webapps:GetInstalled":
- this.getInstalled(msg, mm);
- break;
- case "Webapps:GetNotInstalled":
- this.getNotInstalled(msg, mm);
+ case "Webapps:GetList":
+ // GetList is special because it's synchronous. So far so well, it's the
+ // only synchronous message, if we get more at some point they should get
+ // this treatment also.
+ return this.doGetList();
+ case "child-process-shutdown":
+ this.removeMessageListener(["Webapps:Internal:AllMessages"], mm);
break;
- case "Webapps:GetAll":
- this.doGetAll(msg, mm);
- break;
- case "Webapps:InstallPackage": {
-#ifdef MOZ_WIDGET_ANDROID
- Services.obs.notifyObservers(mm, "webapps-runtime-install-package", JSON.stringify(msg));
-#else
- this.doInstallPackage(msg, mm);
-#endif
- break;
- }
case "Webapps:RegisterForMessages":
this.addMessageListener(msg.messages, msg.app, mm);
break;
case "Webapps:UnregisterForMessages":
this.removeMessageListener(msg, mm);
break;
- case "child-process-shutdown":
- this.removeMessageListener(["Webapps:Internal:AllMessages"], mm);
- break;
- case "Webapps:GetList":
- this.addMessageListener(["Webapps:AddApp", "Webapps:RemoveApp"], null, mm);
- return this.webapps;
- case "Webapps:Download":
- this.startDownload(msg.manifestURL);
- break;
- case "Webapps:CancelDownload":
- this.cancelDownload(msg.manifestURL);
- break;
- case "Webapps:CheckForUpdate":
- this.checkForUpdate(msg, mm);
- break;
- case "Webapps:ApplyDownload":
- this.applyDownload(msg.manifestURL);
- break;
- case "Activities:Register:OK":
- this.notifyAppsRegistryReady();
- break;
- case "Webapps:Install:Return:Ack":
- this.onInstallSuccessAck(msg.manifestURL);
- break;
- case "Webapps:AddReceipt":
- this.addReceipt(msg, mm);
- break;
- case "Webapps:RemoveReceipt":
- this.removeReceipt(msg, mm);
- break;
- case "Webapps:ReplaceReceipt":
- this.replaceReceipt(msg, mm);
- break;
+ default:
+ processedImmediately = false;
+ }
+
+ if (processedImmediately) {
+ return;
}
+
+ // For all the rest (asynchronous), we wait till the registry is ready
+ // before processing the message.
+ this.registryReady.then( () => {
+ switch (aMessage.name) {
+ case "Webapps:Install": {
+#ifdef MOZ_WIDGET_ANDROID
+ Services.obs.notifyObservers(mm, "webapps-runtime-install", JSON.stringify(msg));
+#else
+ this.doInstall(msg, mm);
+#endif
+ break;
+ }
+ case "Webapps:GetSelf":
+ this.getSelf(msg, mm);
+ break;
+ case "Webapps:Uninstall":
+#ifdef MOZ_WIDGET_ANDROID
+ Services.obs.notifyObservers(mm, "webapps-runtime-uninstall", JSON.stringify(msg));
+#else
+ this.doUninstall(msg, mm);
+#endif
+ break;
+ case "Webapps:Launch":
+ this.doLaunch(msg, mm);
+ break;
+ case "Webapps:CheckInstalled":
+ this.checkInstalled(msg, mm);
+ break;
+ case "Webapps:GetInstalled":
+ this.getInstalled(msg, mm);
+ break;
+ case "Webapps:GetNotInstalled":
+ this.getNotInstalled(msg, mm);
+ break;
+ case "Webapps:GetAll":
+ this.doGetAll(msg, mm);
+ break;
+ case "Webapps:InstallPackage": {
+#ifdef MOZ_WIDGET_ANDROID
+ Services.obs.notifyObservers(mm, "webapps-runtime-install-package", JSON.stringify(msg));
+#else
+ this.doInstallPackage(msg, mm);
+#endif
+ break;
+ }
+ case "Webapps:Download":
+ this.startDownload(msg.manifestURL);
+ break;
+ case "Webapps:CancelDownload":
+ this.cancelDownload(msg.manifestURL);
+ break;
+ case "Webapps:CheckForUpdate":
+ this.checkForUpdate(msg, mm);
+ break;
+ case "Webapps:ApplyDownload":
+ this.applyDownload(msg.manifestURL);
+ break;
+ case "Webapps:Install:Return:Ack":
+ this.onInstallSuccessAck(msg.manifestURL);
+ break;
+ case "Webapps:AddReceipt":
+ this.addReceipt(msg, mm);
+ break;
+ case "Webapps:RemoveReceipt":
+ this.removeReceipt(msg, mm);
+ break;
+ case "Webapps:ReplaceReceipt":
+ this.replaceReceipt(msg, mm);
+ break;
+ }
+ });
},
getAppInfo: function getAppInfo(aAppId) {
return AppsUtils.getAppInfo(this.webapps, aAppId);
},
// Some messages can be listened by several content processes:
// Webapps:AddApp
@@ -1240,16 +1278,48 @@ this.DOMApplicationRegistry = {
} else {
deferred.resolve();
}
});
return deferred.promise;
},
+ /**
+ * Returns the full list of apps and manifests.
+ */
+ doGetList: function() {
+ let tmp = [];
+
+ let res = {};
+ let done = false;
+
+ // We allow cloning the registry when the local processing has been done.
+ this.safeToClone.then( () => {
+ for (let id in this.webapps) {
+ tmp.push({ id: id });
+ }
+ this._readManifests(tmp).then(
+ function(manifests) {
+ manifests.forEach((item) => {
+ res[item.id] = item.manifest;
+ });
+ done = true;
+ }
+ );
+ });
+
+ let thread = Services.tm.currentThread;
+ while (!done) {
+ thread.processNextEvent(/* mayWait */ true);
+ }
+ return { webapps: this.webapps, manifests: res };
+ },
+
+
doLaunch: function (aData, aMm) {
this.launch(
aData.manifestURL,
aData.startPoint,
aData.timestamp,
function onsuccess() {
aMm.sendAsyncMessage("Webapps:Launch:Return:OK", aData);
},
@@ -1325,17 +1395,17 @@ this.DOMApplicationRegistry = {
this._saveApps().then(() => {
this.broadcastMessage("Webapps:UpdateState", {
app: {
progress: 0,
installState: download.previousState,
downloading: false
},
error: error,
- manifestURL: app.manifestURL,
+ id: app.id
})
this.broadcastMessage("Webapps:FireEvent", {
eventType: "downloaderror",
manifestURL: app.manifestURL
});
});
AppDownloadManager.remove(aManifestURL);
},
@@ -1356,17 +1426,17 @@ this.DOMApplicationRegistry = {
throw new Error("APP_IS_DOWNLOADING");
}
// If the caller is trying to start a download but we have nothing to
// download, send an error.
if (!app.downloadAvailable) {
this.broadcastMessage("Webapps:UpdateState", {
error: "NO_DOWNLOAD_AVAILABLE",
- manifestURL: app.manifestURL
+ id: app.id
});
this.broadcastMessage("Webapps:FireEvent", {
eventType: "downloaderror",
manifestURL: app.manifestURL
});
throw new Error("NO_DOWNLOAD_AVAILABLE");
}
@@ -1404,17 +1474,17 @@ this.DOMApplicationRegistry = {
debug("No appcache found, sending 'downloaded' for " + aManifestURL);
app.downloadAvailable = false;
yield this._saveApps();
this.broadcastMessage("Webapps:UpdateState", {
app: app,
manifest: jsonManifest,
- manifestURL: aManifestURL
+ id: app.id
});
this.broadcastMessage("Webapps:FireEvent", {
eventType: "downloadsuccess",
manifestURL: aManifestURL
});
}
return;
@@ -1458,17 +1528,17 @@ this.DOMApplicationRegistry = {
app.downloadAvailable = false;
app.readyToApplyDownload = true;
app.updateTime = Date.now();
yield this._saveApps();
this.broadcastMessage("Webapps:UpdateState", {
app: app,
- manifestURL: aManifestURL
+ id: app.id
});
this.broadcastMessage("Webapps:FireEvent", {
eventType: "downloadsuccess",
manifestURL: aManifestURL
});
if (app.installState == "pending") {
// We restarted a failed download, apply it automatically.
this.applyDownload(aManifestURL);
@@ -1560,17 +1630,17 @@ this.DOMApplicationRegistry = {
manifestURL: app.manifestURL },
true);
}
this.updateDataStore(this.webapps[id].localId, app.origin,
app.manifestURL, newManifest);
this.broadcastMessage("Webapps:UpdateState", {
app: app,
manifest: newManifest,
- manifestURL: app.manifestURL
+ id: app.id
});
this.broadcastMessage("Webapps:FireEvent", {
eventType: "downloadapplied",
manifestURL: app.manifestURL
});
}),
startOfflineCacheDownload: function(aManifest, aApp, aProfileDir, aIsUpdate) {
@@ -1599,17 +1669,17 @@ this.DOMApplicationRegistry = {
DOMApplicationRegistry.broadcastMessage("Webapps:UpdateState", {
// Clear any previous errors.
error: null,
app: {
downloading: true,
installState: aApp.installState,
progress: 0
},
- manifestURL: aApp.manifestURL
+ id: aApp.id
});
let cacheUpdate = updateSvc.scheduleAppUpdate(
appcacheURI, docURI, aApp.localId, false, aProfileDir);
// We save the download details for potential further usage like
// cancelling it.
let download = {
cacheUpdate: cacheUpdate,
@@ -1649,16 +1719,17 @@ this.DOMApplicationRegistry = {
this.notifyAppsRegistryReady();
}
},
checkForUpdate: function(aData, aMm) {
debug("checkForUpdate for " + aData.manifestURL);
function sendError(aError) {
+ debug("checkForUpdate error " + aError);
aData.error = aError;
aMm.sendAsyncMessage("Webapps:CheckForUpdate:Return:KO", aData);
}
let id = this._appIdForManifestURL(aData.manifestURL);
let app = this.webapps[id];
// We cannot update an app that does not exists.
@@ -1678,71 +1749,67 @@ this.DOMApplicationRegistry = {
sendError("APP_IS_DOWNLOADING");
return;
}
// If the app is packaged and its manifestURL has an app:// scheme,
// then we can't have an update.
if (app.origin.startsWith("app://") &&
app.manifestURL.startsWith("app://")) {
- aData.error = "NOT_UPDATABLE";
- aMm.sendAsyncMessage("Webapps:CheckForUpdate:Return:KO", aData);
+ sendError("NOT_UPDATABLE");
return;
}
// For non-removable hosted apps that lives in the core apps dir we
// only check the appcache because we can't modify the manifest even
// if it has changed.
let onlyCheckAppCache = false;
#ifdef MOZ_WIDGET_GONK
let appDir = FileUtils.getDir("coreAppsDir", ["webapps"], false);
onlyCheckAppCache = (app.basePath == appDir.path);
#endif
if (onlyCheckAppCache) {
// Bail out for packaged apps.
if (app.origin.startsWith("app://")) {
- aData.error = "NOT_UPDATABLE";
- aMm.sendAsyncMessage("Webapps:CheckForUpdate:Return:KO", aData);
+ sendError("NOT_UPDATABLE");
return;
}
// We need the manifest to check if we have an appcache.
this._readManifests([{ id: id }]).then((aResult) => {
let manifest = aResult[0].manifest;
if (!manifest.appcache_path) {
- aData.error = "NOT_UPDATABLE";
- aMm.sendAsyncMessage("Webapps:CheckForUpdate:Return:KO", aData);
+ sendError("NOT_UPDATABLE");
return;
}
debug("Checking only appcache for " + aData.manifestURL);
// Check if the appcache is updatable, and send "downloadavailable" or
// "downloadapplied".
let updateObserver = {
observe: function(aSubject, aTopic, aObsData) {
debug("onlyCheckAppCache updateSvc.checkForUpdate return for " +
app.manifestURL + " - event is " + aTopic);
if (aTopic == "offline-cache-update-available") {
app.downloadAvailable = true;
this._saveApps().then(() => {
this.broadcastMessage("Webapps:UpdateState", {
app: app,
- manifestURL: app.manifestURL
+ id: app.id
});
this.broadcastMessage("Webapps:FireEvent", {
eventType: "downloadavailable",
manifestURL: app.manifestURL,
requestID: aData.requestID
});
});
} else {
- aData.error = "NOT_UPDATABLE";
- aMm.sendAsyncMessage("Webapps:CheckForUpdate:Return:KO", aData);
+ sendError("NOT_UPDATABLE");
}
}
};
let helper = new ManifestHelper(manifest, aData.manifestURL);
debug("onlyCheckAppCache - launch updateSvc.checkForUpdate for " +
helper.fullAppcachePath());
updateSvc.checkForUpdate(Services.io.newURI(helper.fullAppcachePath(), null, null),
app.localId, false, updateObserver);
@@ -1792,17 +1859,17 @@ this.DOMApplicationRegistry = {
} else {
this._saveApps().then(() => {
// Like if we got a 304, just send a 'downloadapplied'
// or downloadavailable event.
let eventType = app.downloadAvailable ? "downloadavailable"
: "downloadapplied";
aMm.sendAsyncMessage("Webapps:UpdateState", {
app: app,
- manifestURL: app.manifestURL
+ id: app.id
});
aMm.sendAsyncMessage("Webapps:FireEvent", {
eventType: eventType,
manifestURL: app.manifestURL,
requestID: aData.requestID
});
});
}
@@ -1819,17 +1886,17 @@ this.DOMApplicationRegistry = {
app.lastCheckedUpdate = Date.now();
this._saveApps().then(() => {
// If the app is a packaged app, we just send a 'downloadapplied'
// or downloadavailable event.
let eventType = app.downloadAvailable ? "downloadavailable"
: "downloadapplied";
aMm.sendAsyncMessage("Webapps:UpdateState", {
app: app,
- manifestURL: app.manifestURL
+ id: app.id
});
aMm.sendAsyncMessage("Webapps:FireEvent", {
eventType: eventType,
manifestURL: app.manifestURL,
requestID: aData.requestID
});
});
} else {
@@ -1928,17 +1995,17 @@ this.DOMApplicationRegistry = {
// event.
aApp.downloadAvailable = true;
aApp.downloadSize = manifest.size;
aApp.updateManifest = aNewManifest;
yield this._saveApps();
this.broadcastMessage("Webapps:UpdateState", {
app: aApp,
- manifestURL: aApp.manifestURL
+ id: aApp.id
});
this.broadcastMessage("Webapps:FireEvent", {
eventType: "downloadavailable",
manifestURL: aApp.manifestURL,
requestID: aData.requestID
});
}),
@@ -1994,17 +2061,17 @@ this.DOMApplicationRegistry = {
// Update the registry.
this.webapps[aId] = aApp;
yield this._saveApps();
if (!manifest.appcache_path) {
this.broadcastMessage("Webapps:UpdateState", {
app: aApp,
manifest: aApp.manifest,
- manifestURL: aApp.manifestURL
+ id: aApp.id
});
this.broadcastMessage("Webapps:FireEvent", {
eventType: "downloadapplied",
manifestURL: aApp.manifestURL,
requestID: aData.requestID
});
} else {
// Check if the appcache is updatable, and send "downloadavailable" or
@@ -2028,17 +2095,17 @@ this.DOMApplicationRegistry = {
: "downloadapplied";
aApp.downloadAvailable = (eventType == "downloadavailable");
yield this._saveApps();
this.broadcastMessage("Webapps:UpdateState", {
app: aApp,
manifest: aApp.manifest,
- manifestURL: aApp.manifestURL
+ id: aApp.id
});
this.broadcastMessage("Webapps:FireEvent", {
eventType: eventType,
manifestURL: aApp.manifestURL,
requestID: aData.requestID
});
}
@@ -2459,17 +2526,18 @@ this.DOMApplicationRegistry = {
// Store the manifest and the updateManifest.
this._writeManifestFile(app.id, false, aManifest);
if (aUpdateManifest) {
this._writeManifestFile(app.id, true, aUpdateManifest);
}
this._saveApps().then(() => {
- this.broadcastMessage("Webapps:AddApp", { id: app.id, app: app });
+ this.broadcastMessage("Webapps:AddApp",
+ { id: app.id, app: app, manifest: aManifest });
});
}),
confirmInstall: Task.async(function*(aData, aProfileDir, aInstallSuccessCallback) {
debug("confirmInstall");
let origin = Services.io.newURI(aData.app.origin, null, null);
let id = this._appIdForManifestURL(aData.app.manifestURL);
@@ -2559,16 +2627,18 @@ this.DOMApplicationRegistry = {
};
}
// We notify about the successful installation via mgmt.oninstall and the
// corresponding DOMRequest.onsuccess event as soon as the app is properly
// saved in the registry.
yield this._saveApps();
+ aData.isPackage ? appObject.updateManifest = jsonManifest :
+ appObject.manifest = jsonManifest;
this.broadcastMessage("Webapps:AddApp", { id: id, app: appObject });
if (!aData.isPackage) {
this.updateAppHandlers(null, app.manifest, app);
if (aInstallSuccessCallback) {
try {
yield aInstallSuccessCallback(app, app.manifest);
} catch (e) {
@@ -2641,17 +2711,18 @@ this.DOMApplicationRegistry = {
yield this._saveApps();
this.updateAppHandlers(null, aManifest, aNewApp);
// Clear the manifest cache in case it holds the update manifest.
if (aId in this._manifestCache) {
delete this._manifestCache[aId];
}
- this.broadcastMessage("Webapps:AddApp", { id: aId, app: aNewApp });
+ this.broadcastMessage("Webapps:AddApp",
+ { id: aId, app: aNewApp, manifest: aManifest });
Services.obs.notifyObservers(null, "webapps-installed",
JSON.stringify({ manifestURL: aNewApp.manifestURL }));
if (supportUseCurrentProfile()) {
// Update the permissions for this app.
PermissionsInstaller.installPermissions({
manifest: aManifest,
origin: aNewApp.origin,
@@ -2801,32 +2872,32 @@ this.DOMApplicationRegistry = {
// Save the current state of the app to handle cases where we may be
// retrying a past download.
yield DOMApplicationRegistry._saveApps();
DOMApplicationRegistry.broadcastMessage("Webapps:UpdateState", {
// Clear any previous download errors.
error: null,
app: aOldApp,
- manifestURL: aNewApp.manifestURL
+ id: aId
});
let zipFile = yield this._getPackage(requestChannel, aId, aOldApp, aNewApp);
let hash = yield this._computeFileHash(zipFile.path);
let responseStatus = requestChannel.responseStatus;
let oldPackage = (responseStatus == 304 || hash == aOldApp.packageHash);
if (oldPackage) {
debug("package's etag or hash unchanged; sending 'applied' event");
// The package's Etag or hash has not changed.
// We send an "applied" event right away so code awaiting that event
// can proceed to access the app. We also throw an error to alert
// the caller that the package wasn't downloaded.
- this._sendAppliedEvent(aNewApp, aOldApp, aId);
+ this._sendAppliedEvent(aOldApp);
throw new Error("PACKAGE_UNCHANGED");
}
let newManifest = yield this._openAndReadPackage(zipFile, aOldApp, aNewApp,
isLocalFileInstall, aIsUpdate, aManifest, requestChannel, hash);
AppDownloadManager.remove(aNewApp.manifestURL);
@@ -2952,17 +3023,17 @@ this.DOMApplicationRegistry = {
return requestChannel;
},
_sendDownloadProgressEvent: function(aNewApp, aProgress) {
this.broadcastMessage("Webapps:UpdateState", {
app: {
progress: aProgress
},
- manifestURL: aNewApp.manifestURL
+ id: aNewApp.id
});
this.broadcastMessage("Webapps:FireEvent", {
eventType: "progress",
manifestURL: aNewApp.manifestURL
});
},
_getPackage: function(aRequestChannel, aId, aOldApp, aNewApp) {
@@ -3069,56 +3140,53 @@ this.DOMApplicationRegistry = {
/**
* Send an "applied" event right away for the package being installed.
*
* XXX We use this to exit the app update process early when the downloaded
* package is identical to the last one we installed. Presumably we do
* something similar after updating the app, and we could refactor both cases
* to use the same code to send the "applied" event.
*
- * @param aNewApp {Object} the new app data
- * @param aOldApp {Object} the currently stored app data
- * @param aId {String} the unique id of the app
+ * @param aApp {Object} app data
*/
- _sendAppliedEvent: function(aNewApp, aOldApp, aId) {
- aOldApp.downloading = false;
- aOldApp.downloadAvailable = false;
- aOldApp.downloadSize = 0;
- aOldApp.installState = "installed";
- aOldApp.readyToApplyDownload = false;
- if (aOldApp.staged && aOldApp.staged.manifestHash) {
+ _sendAppliedEvent: function(aApp) {
+ aApp.downloading = false;
+ aApp.downloadAvailable = false;
+ aApp.downloadSize = 0;
+ aApp.installState = "installed";
+ aApp.readyToApplyDownload = false;
+ if (aApp.staged && aApp.staged.manifestHash) {
// If we're here then the manifest has changed but the package
// hasn't. Let's clear this, so we don't keep offering
// a bogus update to the user
- aOldApp.manifestHash = aOldApp.staged.manifestHash;
- aOldApp.etag = aOldApp.staged.etag || aOldApp.etag;
- aOldApp.staged = {};
-
- // Move the staged update manifest to a non staged one.
+ aApp.manifestHash = aApp.staged.manifestHash;
+ aApp.etag = aApp.staged.etag || aApp.etag;
+ aApp.staged = {};
+ // Move the staged update manifest to a non staged one.
try {
- let staged = this._getAppDir(aId);
+ let staged = this._getAppDir(aApp.id);
staged.append("staged-update.webapp");
staged.moveTo(staged.parent, "update.webapp");
} catch (ex) {
// We don't really mind much if this fails.
}
}
// Save the updated registry, and cleanup the tmp directory.
this._saveApps().then(() => {
this.broadcastMessage("Webapps:UpdateState", {
- app: aOldApp,
- manifestURL: aNewApp.manifestURL
+ app: aApp,
+ id: aApp.id
});
this.broadcastMessage("Webapps:FireEvent", {
- manifestURL: aNewApp.manifestURL,
+ manifestURL: aApp.manifestURL,
eventType: ["downloadsuccess", "downloadapplied"]
});
});
- let file = FileUtils.getFile("TmpD", ["webapps", aId], false);
+ let file = FileUtils.getFile("TmpD", ["webapps", aApp.id], false);
if (file && file.exists()) {
file.remove(true);
}
},
_openAndReadPackage: function(aZipFile, aOldApp, aNewApp, aIsLocalFileInstall,
aIsUpdate, aManifest, aRequestChannel, aHash) {
return Task.spawn((function*() {
@@ -3427,19 +3495,20 @@ this.DOMApplicationRegistry = {
delete this.webapps[oldId];
// Rename the directories where the files are installed.
[DIRECTORY_NAME, "TmpD"].forEach(function(aDir) {
let parent = FileUtils.getDir(aDir, ["webapps"], true, true);
let dir = FileUtils.getDir(aDir, ["webapps", oldId], true, true);
dir.moveTo(parent, newId);
});
// Signals that we need to swap the old id with the new app.
- this.broadcastMessage("Webapps:RemoveApp", { id: oldId });
- this.broadcastMessage("Webapps:AddApp", { id: newId,
- app: aOldApp });
+ this.broadcastMessage("Webapps:UpdateApp", { oldId: oldId,
+ newId: newId,
+ app: aOldApp });
+
}
}
},
_getIds: function(aIsSigned, aZipReader, aConverter, aNewApp, aOldApp,
aIsUpdate) {
// Get ids.json if the file is signed
if (aIsSigned) {
@@ -3532,17 +3601,17 @@ this.DOMApplicationRegistry = {
if (aOldApp.staged) {
delete aOldApp.staged;
}
this._saveApps().then(() => {
this.broadcastMessage("Webapps:UpdateState", {
app: aOldApp,
error: aError,
- manifestURL: aNewApp.manifestURL
+ id: aNewApp.id
});
this.broadcastMessage("Webapps:FireEvent", {
eventType: "downloaderror",
manifestURL: aNewApp.manifestURL
});
});
AppDownloadManager.remove(aNewApp.manifestURL);
},
@@ -3712,19 +3781,23 @@ this.DOMApplicationRegistry = {
this._readManifests(tmp).then((aResult) => {
for (let i = 0; i < aResult.length; i++)
aData.apps[i].manifest = aResult[i].manifest;
aMm.sendAsyncMessage("Webapps:GetNotInstalled:Return:OK", aData);
});
},
doGetAll: function(aData, aMm) {
- this.getAll(function (apps) {
- aData.apps = apps;
- aMm.sendAsyncMessage("Webapps:GetAll:Return:OK", aData);
+ // We can't do this until the registry is ready.
+ debug("doGetAll");
+ this.registryReady.then(() => {
+ this.getAll(function (apps) {
+ aData.apps = apps;
+ aMm.sendAsyncMessage("Webapps:GetAll:Return:OK", aData);
+ });
});
},
getAll: function(aCallback) {
debug("getAll");
let apps = [];
let tmp = [];
@@ -4082,17 +4155,17 @@ let AppcacheObserver = function(aApp) {
};
AppcacheObserver.prototype = {
// nsIOfflineCacheUpdateObserver implementation
_sendProgressEvent: function() {
let app = this.app;
DOMApplicationRegistry.broadcastMessage("Webapps:UpdateState", {
app: app,
- manifestURL: app.manifestURL
+ id: app.id
});
DOMApplicationRegistry.broadcastMessage("Webapps:FireEvent", {
eventType: "progress",
manifestURL: app.manifestURL
});
},
updateStateChanged: function appObs_Update(aUpdate, aState) {
@@ -4114,17 +4187,17 @@ AppcacheObserver.prototype = {
return;
}
app.updateTime = Date.now();
app.downloading = false;
app.downloadAvailable = false;
DOMApplicationRegistry.broadcastMessage("Webapps:UpdateState", {
app: app,
- manifestURL: app.manifestURL
+ id: app.id
});
DOMApplicationRegistry.broadcastMessage("Webapps:FireEvent", {
eventType: ["downloadsuccess", "downloadapplied"],
manifestURL: app.manifestURL
});
}
let setError = function appObs_setError(aError) {
@@ -4137,17 +4210,17 @@ AppcacheObserver.prototype = {
if (app.isCanceling) {
delete app.isCanceling;
return;
}
DOMApplicationRegistry.broadcastMessage("Webapps:UpdateState", {
app: app,
error: aError,
- manifestURL: app.manifestURL
+ id: app.id
});
DOMApplicationRegistry.broadcastMessage("Webapps:FireEvent", {
eventType: "downloaderror",
manifestURL: app.manifestURL
});
}
switch (aState) {
--- a/dom/apps/tests/test_packaged_app_common.js
+++ b/dom/apps/tests/test_packaged_app_common.js
@@ -93,16 +93,17 @@ var PackagedTestHelper = (function Packa
ok(false, "Got unexpected " + evt.target.error.name);
finish();
};
navigator.mozApps.mgmt.oninstall = function(evt) {
var aApp = evt.application;
aApp.ondownloaderror = function(evt) {
var error = aApp.downloadError.name;
+ ok(true, "Got downloaderror " + error);
if (error == aExpectedError) {
ok(true, "Got expected " + aExpectedError);
var expected = {
name: aName,
manifestURL: aMiniManifestURL,
installOrigin: gInstallOrigin,
progress: 0,
installState: "pending",
--- a/dom/apps/tests/test_packaged_app_update.html
+++ b/dom/apps/tests/test_packaged_app_update.html
@@ -74,25 +74,25 @@ function checkLastAppState(aMiniManifest
function updateApp(aExpectedReady, aPreviousVersion, aNextVersion) {
var lApp = PackagedTestHelper.gApp;
var ondownloadappliedhandler =
checkLastAppState.bind(PackagedTestHelper, miniManifestURL, false, false,
aNextVersion, PackagedTestHelper.next);
- var ondownloadsuccesshandler =
- checkLastAppState.bind(undefined, miniManifestURL,
- aExpectedReady, false, aPreviousVersion,
- function() {
- navigator.mozApps.mgmt.applyDownload(lApp);
- });
+ var ondownloadsuccesshandler =
+ checkLastAppState.bind(undefined, miniManifestURL,
+ aExpectedReady, false, aPreviousVersion,
+ function() {
+ navigator.mozApps.mgmt.applyDownload(lApp);
+ });
- checkForUpdate(true, ondownloadsuccesshandler, ondownloadappliedhandler, null,
- true);
+ checkForUpdate(true, ondownloadsuccesshandler, ondownloadappliedhandler,
+ null, true);
}
var initialPermissionState = {
"geolocation": "prompt",
"audio-capture": "prompt",
"video-capture": "prompt",
"test-permission-read": "prompt",
@@ -249,17 +249,17 @@ var steps = [
},
function() {
info("== TEST == Update packaged app - Updating a pending app");
miniManifestURL = PackagedTestHelper.gSJS +
"?getManifest=true" +
"&appName=arandomname" +
"&appToFail1";
PackagedTestHelper.checkAppDownloadError(miniManifestURL,
- "MANIFEST_MISMATCH", 2, false, true,
+ "MANIFEST_MISMATCH", 1, false, true,
"arandomname",
function () {
checkForUpdate(false, null, null, null, false,
function (request) {
if (request.error.name === "PENDING_APP_NOT_UPDATABLE") {
info("Got expected PENDING_APP_NOT_UPDATEABLE");
} else {
ok(false, "Got unexpected " + request.error.name);
--- a/dom/apps/tests/test_receipt_operations.html
+++ b/dom/apps/tests/test_receipt_operations.html
@@ -238,9 +238,9 @@ function runTest() {
ok(true, "App uninstalled");
}
addLoadEvent(go);
</script>
</pre>
</body>
-</html>
\ No newline at end of file
+</html>
--- a/gfx/gl/GLContextProviderEGL.cpp
+++ b/gfx/gl/GLContextProviderEGL.cpp
@@ -652,20 +652,41 @@ CreateConfig(EGLConfig* aConfig, int32_t
}
if (!sEGLLibrary.fChooseConfig(EGL_DISPLAY(), attribs,
configs, ncfg, &ncfg) ||
ncfg < 1) {
return false;
}
+#ifdef MOZ_WIDGET_GONK
+ // On gonk, it's important to select a configuration with the
+ // the correct order as well as bits per channel.
+ // EGL_NATIVE_VISUAL_ID gives us the Android pixel format which
+ // is an enum that tells us both order and bits per channel.
+ // For example -
+ // HAL_PIXEL_FORMAT_RGBX_8888
+ // HAL_PIXEL_FORMAT_BGRA_8888
+ // HAL_PIXEL_FORMAT_RGB_565
+ for (int j = 0; j < ncfg; ++j) {
+ EGLConfig config = configs[j];
+ EGLint format;
+ if (sEGLLibrary.fGetConfigAttrib(EGL_DISPLAY(), config,
+ LOCAL_EGL_NATIVE_VISUAL_ID, &format) &&
+ format == GetGonkDisplay()->surfaceformat)
+ {
+ *aConfig = config;
+ return true;
+ }
+ }
+#endif
+
for (int j = 0; j < ncfg; ++j) {
EGLConfig config = configs[j];
EGLint r, g, b, a;
-
if (sEGLLibrary.fGetConfigAttrib(EGL_DISPLAY(), config,
LOCAL_EGL_RED_SIZE, &r) &&
sEGLLibrary.fGetConfigAttrib(EGL_DISPLAY(), config,
LOCAL_EGL_GREEN_SIZE, &g) &&
sEGLLibrary.fGetConfigAttrib(EGL_DISPLAY(), config,
LOCAL_EGL_BLUE_SIZE, &b) &&
sEGLLibrary.fGetConfigAttrib(EGL_DISPLAY(), config,
LOCAL_EGL_ALPHA_SIZE, &a) &&
--- a/toolkit/devtools/client/dbg-client.jsm
+++ b/toolkit/devtools/client/dbg-client.jsm
@@ -61,16 +61,18 @@ this.makeInfallible = DevToolsUtils.make
let LOG_PREF = "devtools.debugger.log";
let VERBOSE_PREF = "devtools.debugger.log.verbose";
let wantLogging = Services.prefs.getBoolPref(LOG_PREF);
let wantVerbose =
Services.prefs.getPrefType(VERBOSE_PREF) !== Services.prefs.PREF_INVALID &&
Services.prefs.getBoolPref(VERBOSE_PREF);
+let noop = () => {};
+
function dumpn(str) {
if (wantLogging) {
dump("DBG-CLIENT: " + str + "\n");
}
}
function dumpv(msg) {
if (wantVerbose) {
@@ -438,17 +440,17 @@ DebuggerClient.prototype = {
* Attach to a tab actor.
*
* @param string aTabActor
* The actor ID for the tab to attach.
* @param function aOnResponse
* Called with the response packet and a TabClient
* (which will be undefined on error).
*/
- attachTab: function (aTabActor, aOnResponse) {
+ attachTab: function (aTabActor, aOnResponse = noop) {
if (this._clients.has(aTabActor)) {
let cachedTab = this._clients.get(aTabActor);
let cachedResponse = {
cacheDisabled: cachedTab.cacheDisabled,
javascriptEnabled: cachedTab.javascriptEnabled,
traits: cachedTab.traits,
};
setTimeout(() => aOnResponse(cachedResponse, cachedTab), 0);
@@ -473,17 +475,17 @@ DebuggerClient.prototype = {
* Attach to an addon actor.
*
* @param string aAddonActor
* The actor ID for the addon to attach.
* @param function aOnResponse
* Called with the response packet and a AddonClient
* (which will be undefined on error).
*/
- attachAddon: function DC_attachAddon(aAddonActor, aOnResponse) {
+ attachAddon: function DC_attachAddon(aAddonActor, aOnResponse = noop) {
let packet = {
to: aAddonActor,
type: "attach"
};
this.request(packet, aResponse => {
let addonClient;
if (!aResponse.error) {
addonClient = new AddonClient(this, aAddonActor);
@@ -501,17 +503,17 @@ DebuggerClient.prototype = {
* The ID for the console actor to attach to.
* @param array aListeners
* The console listeners you want to start.
* @param function aOnResponse
* Called with the response packet and a WebConsoleClient
* instance (which will be undefined on error).
*/
attachConsole:
- function (aConsoleActor, aListeners, aOnResponse) {
+ function (aConsoleActor, aListeners, aOnResponse = noop) {
let packet = {
to: aConsoleActor,
type: "startListeners",
listeners: aListeners,
};
this.request(packet, (aResponse) => {
let consoleClient;
@@ -534,17 +536,17 @@ DebuggerClient.prototype = {
* The actor ID for the thread to attach.
* @param function aOnResponse
* Called with the response packet and a ThreadClient
* (which will be undefined on error).
* @param object aOptions
* Configuration options.
* - useSourceMaps: whether to use source maps or not.
*/
- attachThread: function (aThreadActor, aOnResponse, aOptions={}) {
+ attachThread: function (aThreadActor, aOnResponse = noop, aOptions={}) {
if (this._clients.has(aThreadActor)) {
setTimeout(() => aOnResponse({}, this._clients.get(aThreadActor)), 0);
return;
}
let packet = {
to: aThreadActor,
type: "attach",
@@ -563,17 +565,17 @@ DebuggerClient.prototype = {
* Attach to a trace actor.
*
* @param string aTraceActor
* The actor ID for the tracer to attach.
* @param function aOnResponse
* Called with the response packet and a TraceClient
* (which will be undefined on error).
*/
- attachTracer: function (aTraceActor, aOnResponse) {
+ attachTracer: function (aTraceActor, aOnResponse = noop) {
if (this._clients.has(aTraceActor)) {
setTimeout(() => aOnResponse({}, this._clients.get(aTraceActor)), 0);
return;
}
let packet = {
to: aTraceActor,
type: "attach"
@@ -1272,17 +1274,17 @@ TabClient.prototype = {
*
* @param object aOptions
* Configuration options.
* - useSourceMaps: whether to use source maps or not.
* @param function aOnResponse
* Called with the response packet and a ThreadClient
* (which will be undefined on error).
*/
- attachThread: function(aOptions={}, aOnResponse) {
+ attachThread: function(aOptions={}, aOnResponse = noop) {
if (this.thread) {
setTimeout(() => aOnResponse({}, this.thread), 0);
return;
}
let packet = {
to: this._threadActor,
type: "attach",
@@ -1620,17 +1622,17 @@ ThreadClient.prototype = {
*
* @param boolean aFlag
* Enables pausing if true, disables otherwise.
* @param function aOnResponse
* Called with the response packet.
*/
pauseOnExceptions: function (aPauseOnExceptions,
aIgnoreCaughtExceptions,
- aOnResponse) {
+ aOnResponse = noop) {
this._pauseOnExceptions = aPauseOnExceptions;
this._ignoreCaughtExceptions = aIgnoreCaughtExceptions;
// If the debuggee is paused, we have to send the flag via a reconfigure
// request.
if (this.paused) {
this.reconfigure({
pauseOnExceptions: aPauseOnExceptions,
@@ -1656,17 +1658,17 @@ ThreadClient.prototype = {
*
* @param array|string events
* An array of strings, representing the DOM event types to pause on,
* or "*" to pause on all DOM events. Pass an empty array to
* completely disable pausing on DOM events.
* @param function onResponse
* Called with the response packet in a future turn of the event loop.
*/
- pauseOnDOMEvents: function (events, onResponse) {
+ pauseOnDOMEvents: function (events, onResponse = noop) {
this._pauseOnDOMEvents = events;
// If the debuggee is paused, the value of the array will be communicated in
// the next resumption. Otherwise we have to force a pause in order to send
// the array.
if (this.paused) {
setTimeout(() => onResponse({}), 0);
return;
}
@@ -1734,17 +1736,18 @@ ThreadClient.prototype = {
/**
* Request to set a breakpoint in the specified location.
*
* @param object aLocation
* The source location object where the breakpoint will be set.
* @param function aOnResponse
* Called with the thread's response.
*/
- setBreakpoint: function ({ url, line, column, condition }, aOnResponse) {
+ setBreakpoint: function ({ url, line, column, condition },
+ aOnResponse = noop) {
// A helper function that sets the breakpoint.
let doSetBreakpoint = (aCallback) => {
const location = {
url: url,
line: line,
column: column
};
@@ -1762,19 +1765,17 @@ ThreadClient.prototype = {
let root = this.client.mainRoot;
bpClient = new BreakpointClient(
this.client,
aResponse.actor,
location,
root.traits.conditionalBreakpoints ? condition : undefined
);
}
- if (aOnResponse) {
- aOnResponse(aResponse, bpClient);
- }
+ aOnResponse(aResponse, bpClient);
if (aCallback) {
aCallback();
}
});
};
// If the debuggee is paused, just set the breakpoint.
if (this.paused) {
--- a/toolkit/devtools/server/actors/webapps.js
+++ b/toolkit/devtools/server/actors/webapps.js
@@ -257,17 +257,17 @@ WebappsActor.prototype = {
aApp.manifest = manifest;
// Needed to evict manifest cache on content side
// (has to be dispatched first, otherwise other messages like
// Install:Return:OK are going to use old manifest version)
reg.broadcastMessage("Webapps:UpdateState", {
app: aApp,
manifest: manifest,
- manifestURL: aApp.manifestURL
+ id: aApp.id
});
reg.broadcastMessage("Webapps:FireEvent", {
eventType: ["downloadsuccess", "downloadapplied"],
manifestURL: aApp.manifestURL
});
reg.broadcastMessage("Webapps:AddApp", { id: aId, app: aApp });
reg.broadcastMessage("Webapps:Install:Return:OK", {
app: aApp,