Merge m-c to inbound
authorWes Kocher <wkocher@mozilla.com>
Wed, 23 Jul 2014 18:55:48 -0700
changeset 217437 f654e6bf1089820f000b61fcb5fc3099d17bffe9
parent 217436 9c3d8f8b46f7cddc778420daa47002afd708a7c1 (current diff)
parent 217390 a91ec42d6a9cd718673372a2c70bfca7903c3ca6 (diff)
child 217438 3a5cfc71b3d30980ccd42535d9a001ad5410d8b4
push id3979
push userraliiev@mozilla.com
push dateMon, 13 Oct 2014 16:35:44 +0000
treeherdermozilla-beta@30f2cc610691 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone34.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge m-c to inbound
--- 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,