Merge mozilla-central to mozilla-inbound on a CLOSED TREE
authorCarsten "Tomcat" Book <cbook@mozilla.com>
Mon, 15 Dec 2014 15:33:21 +0100
changeset 219732 c34dc0025f57ad8d723422163ee04d5441c96434
parent 219731 e7b88b459b2ab59076be42ead7362f5a7f5eca40 (current diff)
parent 219552 a25d603f8385499a35f54bae56d2c6d72f67218b (diff)
child 219733 32b690a356837c5ee7835c6774a40fb4cd24de63
push id10400
push userryanvm@gmail.com
push dateMon, 15 Dec 2014 18:54:54 +0000
treeherderfx-team@5d6e0d038f95 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone37.0a1
Merge mozilla-central to mozilla-inbound on a CLOSED TREE
--- a/b2g/app/moz.build
+++ b/b2g/app/moz.build
@@ -53,17 +53,17 @@ if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gonk
     OS_LIBS += [
         'ui',
         'EGL',
         'hardware_legacy',
         'hardware',
         'cutils',
     ]
     OS_LIBS += CONFIG['MOZ_ZLIB_LIBS']
-    if CONFIG['ANDROID_VERSION'] in ('17', '18', '19'):
+    if CONFIG['ANDROID_VERSION'] in ('17', '18', '19', '21'):
         OS_LIBS += [
             'gui',
             'suspend',
         ]
     OS_LIBS += [
         'binder',
         'utils',
     ]
--- a/b2g/config/dolphin/sources.xml
+++ b/b2g/config/dolphin/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="3ab0d9c70f0b2e1ededc679112c392303f037361">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="e2a3e606675c346b6e6f35351a458040be599b09"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="c5b01c018e79a36d7ca1e466c143c76fac7da705"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="50ad16a280fe9cfa0716f8c6ba16afdf7f266b49"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="fe893bb760a3bb64375f62fdf4762a58c59df9ef"/>
   <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="04e95f6fbe74ff8627d3a80b5967b794388e75ff"/>
+  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="09519af2056879ce0ea59f7085ac4b282c7d01d0"/>
   <!-- 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="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"/>
   <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="a1e239a0bb5cd1d69680bf1075883aa9a7bf2429"/>
   <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="c7931763d41be602407ed9d71e2c0292c6597e00"/>
   <project groups="linux,x86" name="platform/prebuilts/python/linux-x86/2.7.5" path="prebuilts/python/linux-x86/2.7.5" revision="83760d213fb3bec7b4117d266fcfbf6fe2ba14ab"/>
   <project name="device/common" path="device/common" revision="6a2995683de147791e516aae2ccb31fdfbe2ad30"/>
--- 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="df362ace56338da8173d30d3e09e08c42c1accfa">
     <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="e2a3e606675c346b6e6f35351a458040be599b09"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="c5b01c018e79a36d7ca1e466c143c76fac7da705"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="50ad16a280fe9cfa0716f8c6ba16afdf7f266b49"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="d5d3f93914558b6f168447b805cd799c8233e300"/>
   <project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="6fa7a4936414ceb4055fd27f7a30e76790f834fb"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="fe893bb760a3bb64375f62fdf4762a58c59df9ef"/>
-  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="04e95f6fbe74ff8627d3a80b5967b794388e75ff"/>
+  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="09519af2056879ce0ea59f7085ac4b282c7d01d0"/>
   <!-- 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="0e94c080bee081a50aa2097527b0b40852f9143f">
     <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="e2a3e606675c346b6e6f35351a458040be599b09"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="c5b01c018e79a36d7ca1e466c143c76fac7da705"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="50ad16a280fe9cfa0716f8c6ba16afdf7f266b49"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="fe893bb760a3bb64375f62fdf4762a58c59df9ef"/>
-  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="04e95f6fbe74ff8627d3a80b5967b794388e75ff"/>
+  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="09519af2056879ce0ea59f7085ac4b282c7d01d0"/>
   <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"/>
@@ -131,12 +131,12 @@
   <project name="android-development" path="development" remote="b2g" revision="dab55669da8f48b6e57df95d5af9f16b4a87b0b1"/>
   <project name="device/generic/armv7-a-neon" path="device/generic/armv7-a-neon" revision="3a9a17613cc685aa232432566ad6cc607eab4ec1"/>
   <project name="device_generic_goldfish" path="device/generic/goldfish" remote="b2g" revision="197cd9492b9fadaa915c5daf36ff557f8f4a8d1c"/>
   <project name="platform/external/libnfc-nci" path="external/libnfc-nci" revision="7d33aaf740bbf6c7c6e9c34a92b371eda311b66b"/>
   <project name="libnfcemu" path="external/libnfcemu" remote="b2g" revision="125ccf9bd5986c7728ea44508b3e1d1185ac028b"/>
   <project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="c5f8d282efe4a4e8b1e31a37300944e338e60e4f"/>
   <project name="platform/external/wpa_supplicant_8" path="external/wpa_supplicant_8" revision="0e56e450367cd802241b27164a2979188242b95f"/>
   <project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="9f28c4faea3b2f01db227b2467b08aeba96d9bec"/>
-  <project name="platform_system_nfcd" path="system/nfcd" remote="b2g" revision="58567be92162a64b3bbcc1cce911a27ca935610f"/>
+  <project name="platform_system_nfcd" path="system/nfcd" remote="b2g" revision="026478f008f26e568fb189a5be2928f9b18e3efa"/>
   <project name="android-sdk" path="sdk" remote="b2g" revision="8b1365af38c9a653df97349ee53a3f5d64fd590a"/>
   <project name="darwinstreamingserver" path="system/darwinstreamingserver" remote="b2g" revision="cf85968c7f85e0ec36e72c87ceb4837a943b8af6"/>
 </manifest>
--- a/b2g/config/emulator-kk/sources.xml
+++ b/b2g/config/emulator-kk/sources.xml
@@ -10,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="3ab0d9c70f0b2e1ededc679112c392303f037361">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="e2a3e606675c346b6e6f35351a458040be599b09"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="c5b01c018e79a36d7ca1e466c143c76fac7da705"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="50ad16a280fe9cfa0716f8c6ba16afdf7f266b49"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="fe893bb760a3bb64375f62fdf4762a58c59df9ef"/>
   <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="04e95f6fbe74ff8627d3a80b5967b794388e75ff"/>
+  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="09519af2056879ce0ea59f7085ac4b282c7d01d0"/>
   <!-- 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="df362ace56338da8173d30d3e09e08c42c1accfa">
     <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="e2a3e606675c346b6e6f35351a458040be599b09"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="c5b01c018e79a36d7ca1e466c143c76fac7da705"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="50ad16a280fe9cfa0716f8c6ba16afdf7f266b49"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="d5d3f93914558b6f168447b805cd799c8233e300"/>
   <project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="6fa7a4936414ceb4055fd27f7a30e76790f834fb"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="fe893bb760a3bb64375f62fdf4762a58c59df9ef"/>
-  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="04e95f6fbe74ff8627d3a80b5967b794388e75ff"/>
+  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="09519af2056879ce0ea59f7085ac4b282c7d01d0"/>
   <!-- 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-kk/sources.xml
+++ b/b2g/config/flame-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="3ab0d9c70f0b2e1ededc679112c392303f037361">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="e2a3e606675c346b6e6f35351a458040be599b09"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="c5b01c018e79a36d7ca1e466c143c76fac7da705"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="50ad16a280fe9cfa0716f8c6ba16afdf7f266b49"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="fe893bb760a3bb64375f62fdf4762a58c59df9ef"/>
   <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="04e95f6fbe74ff8627d3a80b5967b794388e75ff"/>
+  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="09519af2056879ce0ea59f7085ac4b282c7d01d0"/>
   <!-- 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="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"/>
   <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="a1e239a0bb5cd1d69680bf1075883aa9a7bf2429"/>
   <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="c7931763d41be602407ed9d71e2c0292c6597e00"/>
   <project groups="linux,x86" name="platform/prebuilts/python/linux-x86/2.7.5" path="prebuilts/python/linux-x86/2.7.5" revision="a32003194f707f66a2d8cdb913ed1869f1926c5d"/>
   <project name="device/common" path="device/common" revision="96d4d2006c4fcb2f19a3fa47ab10cb409faa017b"/>
@@ -151,13 +151,13 @@
   <project name="platform/hardware/qcom/camera" path="hardware/qcom/camera" revision="2a1ded216a91bf62a72b1640cf01ab4998f37028"/>
   <project name="platform/hardware/qcom/display" path="hardware/qcom/display" revision="f8bec8a61dc0f2581fa72a31d4144084b47ef7cf"/>
   <project name="platform/hardware/qcom/gps" path="hardware/qcom/gps" revision="9883ea57b0668d8f60dba025d4522dfa69a1fbfa"/>
   <project name="platform/hardware/qcom/media" path="hardware/qcom/media" revision="a558dc844bf5144fc38603fd8f4df8d9557052a5"/>
   <project name="platform/hardware/qcom/wlan" path="hardware/qcom/wlan" revision="57ee1320ed7b4a1a1274d8f3f6c177cd6b9becb2"/>
   <project name="platform/hardware/ril" path="hardware/ril" revision="12b1977cc704b35f2e9db2bb423fa405348bc2f3"/>
   <project name="platform/system/bluetooth" path="system/bluetooth" revision="985bf15264d865fe7b9c5b45f61c451cbaafa43d"/>
   <project name="platform/system/core" path="system/core" revision="350eac5403124dacb2a5fd9e28ac290a59fc3b8e"/>
-  <project name="platform_system_nfcd" path="system/nfcd" remote="b2g" revision="58567be92162a64b3bbcc1cce911a27ca935610f"/>
+  <project name="platform_system_nfcd" path="system/nfcd" remote="b2g" revision="026478f008f26e568fb189a5be2928f9b18e3efa"/>
   <project name="platform/system/qcom" path="system/qcom" revision="63e3f6f176caad587d42bba4c16b66d953fb23c2"/>
   <project name="platform/vendor/qcom-opensource/wlan/prima" path="vendor/qcom/opensource/wlan/prima" revision="d8952a42771045fca73ec600e2b42a4c7129d723"/>
   <project name="platform/vendor/qcom/msm8610" path="device/qcom/msm8610" revision="018b44e52b2bac5d3631d559550e88a4b68c6e67"/>
 </manifest>
--- 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="0e94c080bee081a50aa2097527b0b40852f9143f">
     <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="e2a3e606675c346b6e6f35351a458040be599b09"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="c5b01c018e79a36d7ca1e466c143c76fac7da705"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="50ad16a280fe9cfa0716f8c6ba16afdf7f266b49"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="fe893bb760a3bb64375f62fdf4762a58c59df9ef"/>
-  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="04e95f6fbe74ff8627d3a80b5967b794388e75ff"/>
+  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="09519af2056879ce0ea59f7085ac4b282c7d01d0"/>
   <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"/>
@@ -140,13 +140,13 @@
   <project name="platform/hardware/qcom/camera" path="hardware/qcom/camera" revision="5e110615212302c5d798a3c223dcee458817651c"/>
   <project name="platform/hardware/qcom/display" path="hardware/qcom/display" revision="fa9ffd47948eb24466de227e48fe9c4a7c5e7711"/>
   <project name="platform/hardware/qcom/gps" path="hardware/qcom/gps" revision="cd76b19aafd4229ccf83853d02faef8c51ca8b34"/>
   <project name="platform/hardware/qcom/media" path="hardware/qcom/media" revision="8a0d0b0d9889ef99c4c6317c810db4c09295f15a"/>
   <project name="platform/hardware/qcom/wlan" path="hardware/qcom/wlan" revision="2208fa3537ace873b8f9ec2355055761c79dfd5f"/>
   <project name="platform/hardware/ril" path="hardware/ril" revision="c4e2ac95907a5519a0e09f01a0d8e27fec101af0"/>
   <project name="platform/system/bluetooth" path="system/bluetooth" revision="e1eb226fa3ad3874ea7b63c56a9dc7012d7ff3c2"/>
   <project name="platform/system/core" path="system/core" revision="adc485d8755af6a61641d197de7cfef667722580"/>
-  <project name="platform_system_nfcd" path="system/nfcd" remote="b2g" revision="58567be92162a64b3bbcc1cce911a27ca935610f"/>
+  <project name="platform_system_nfcd" path="system/nfcd" remote="b2g" revision="026478f008f26e568fb189a5be2928f9b18e3efa"/>
   <project name="platform/system/qcom" path="system/qcom" revision="1cdab258b15258b7f9657da70e6f06ebd5a2fc25"/>
   <project name="platform/vendor/qcom/msm8610" path="device/qcom/msm8610" revision="4ae5df252123591d5b941191790e7abed1bce5a4"/>
   <project name="platform/vendor/qcom-opensource/wlan/prima" path="vendor/qcom/opensource/wlan/prima" revision="ce18b47b4a4f93a581d672bbd5cb6d12fe796ca9"/>
 </manifest>
--- a/b2g/config/gaia.json
+++ b/b2g/config/gaia.json
@@ -1,9 +1,9 @@
 {
     "git": {
         "git_revision": "", 
         "remote": "", 
         "branch": ""
     }, 
-    "revision": "f741dca42f03f16982c026484be42126a60a8adc", 
+    "revision": "9607d52833bfa08f7aededcb384cf2be5b707b6b", 
     "repo_path": "integration/gaia-central"
 }
--- a/b2g/config/hamachi/sources.xml
+++ b/b2g/config/hamachi/sources.xml
@@ -12,21 +12,21 @@
   <!--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="df362ace56338da8173d30d3e09e08c42c1accfa">
     <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="e2a3e606675c346b6e6f35351a458040be599b09"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="c5b01c018e79a36d7ca1e466c143c76fac7da705"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="50ad16a280fe9cfa0716f8c6ba16afdf7f266b49"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="fe893bb760a3bb64375f62fdf4762a58c59df9ef"/>
-  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="04e95f6fbe74ff8627d3a80b5967b794388e75ff"/>
+  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="09519af2056879ce0ea59f7085ac4b282c7d01d0"/>
   <!-- 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="df362ace56338da8173d30d3e09e08c42c1accfa">
     <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="e2a3e606675c346b6e6f35351a458040be599b09"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="c5b01c018e79a36d7ca1e466c143c76fac7da705"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="50ad16a280fe9cfa0716f8c6ba16afdf7f266b49"/>
   <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="fe893bb760a3bb64375f62fdf4762a58c59df9ef"/>
   <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="0e94c080bee081a50aa2097527b0b40852f9143f">
     <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="e2a3e606675c346b6e6f35351a458040be599b09"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="c5b01c018e79a36d7ca1e466c143c76fac7da705"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="50ad16a280fe9cfa0716f8c6ba16afdf7f266b49"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="fe893bb760a3bb64375f62fdf4762a58c59df9ef"/>
-  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="04e95f6fbe74ff8627d3a80b5967b794388e75ff"/>
+  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="09519af2056879ce0ea59f7085ac4b282c7d01d0"/>
   <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"/>
@@ -126,17 +126,17 @@
   <project name="platform/system/netd" path="system/netd" revision="56112dd7b811301b718d0643a82fd5cac9522073"/>
   <project name="platform/system/security" path="system/security" revision="f48ff68fedbcdc12b570b7699745abb6e7574907"/>
   <project name="platform/system/vold" path="system/vold" revision="8de05d4a52b5a91e7336e6baa4592f945a6ddbea"/>
   <default remote="caf" revision="refs/tags/android-4.3_r2.1" sync-j="4"/>
   <!-- Nexus 4 specific things -->
   <project name="device-mako" path="device/lge/mako" remote="b2g" revision="78d17f0c117f0c66dd55ee8d5c5dde8ccc93ecba"/>
   <project name="device/generic/armv7-a-neon" path="device/generic/armv7-a-neon" revision="3a9a17613cc685aa232432566ad6cc607eab4ec1"/>
   <project name="device/lge/mako-kernel" path="device/lge/mako-kernel" revision="d1729e53d71d711c8fde25eab8728ff2b9b4df0e"/>
-  <project name="platform_system_nfcd" path="system/nfcd" remote="b2g" revision="58567be92162a64b3bbcc1cce911a27ca935610f"/>
+  <project name="platform_system_nfcd" path="system/nfcd" remote="b2g" revision="026478f008f26e568fb189a5be2928f9b18e3efa"/>
   <project name="platform/external/libnfc-nci" path="external/libnfc-nci" revision="7d33aaf740bbf6c7c6e9c34a92b371eda311b66b"/>
   <project name="platform/external/wpa_supplicant_8" path="external/wpa_supplicant_8" revision="0e56e450367cd802241b27164a2979188242b95f"/>
   <project name="platform/hardware/broadcom/wlan" path="hardware/broadcom/wlan" revision="0e1929fa3aa38bf9d40e9e953d619fab8164c82e"/>
   <project name="platform/hardware/qcom/audio" path="hardware/qcom/audio" revision="b0a528d839cfd9d170d092fe3743b5252b4243a6"/>
   <project name="platform/hardware/qcom/bt" path="hardware/qcom/bt" revision="380945eaa249a2dbdde0daa4c8adb8ca325edba6"/>
   <project name="platform/hardware/qcom/display" path="hardware/qcom/display" revision="6f3b0272cefaffeaed2a7d2bb8f633059f163ddc"/>
   <project name="platform/hardware/qcom/keymaster" path="hardware/qcom/keymaster" revision="16da8262c997a5a0d797885788a64a0771b26910"/>
   <project name="platform/hardware/qcom/media" path="hardware/qcom/media" revision="689b476ba3eb46c34b81343295fe144a0e81a18e"/>
--- a/b2g/config/wasabi/sources.xml
+++ b/b2g/config/wasabi/sources.xml
@@ -12,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="df362ace56338da8173d30d3e09e08c42c1accfa">
     <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="e2a3e606675c346b6e6f35351a458040be599b09"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="c5b01c018e79a36d7ca1e466c143c76fac7da705"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="50ad16a280fe9cfa0716f8c6ba16afdf7f266b49"/>
   <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="fe893bb760a3bb64375f62fdf4762a58c59df9ef"/>
-  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="04e95f6fbe74ff8627d3a80b5967b794388e75ff"/>
+  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="09519af2056879ce0ea59f7085ac4b282c7d01d0"/>
   <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/configure.in
+++ b/configure.in
@@ -7279,17 +7279,17 @@ export MOZ_CRT
 AC_SUBST(MOZ_GLUE_IN_PROGRAM)
 AC_SUBST_LIST(WIN32_CRT_LIBS)
 
 dnl We need to wrap dlopen and related functions on Android because we use
 dnl our own linker.
 if test "$OS_TARGET" = Android; then
     MOZ_GLUE_WRAP_LDFLAGS="${MOZ_GLUE_WRAP_LDFLAGS} -Wl,--wrap=PR_GetEnv,--wrap=PR_SetEnv"
     if test "$MOZ_WIDGET_TOOLKIT" = gonk -a -n "$MOZ_NUWA_PROCESS"; then
-        MOZ_GLUE_WRAP_LDFLAGS="${MOZ_GLUE_WRAP_LDFLAGS} -Wl,--wrap=pthread_create,--wrap=epoll_wait,--wrap=poll,--wrap=pthread_cond_timedwait,--wrap=__pthread_cond_timedwait,--wrap=pthread_cond_wait,--wrap=epoll_create,--wrap=epoll_ctl,--wrap=close,--wrap=pthread_key_create,--wrap=pthread_key_delete,--wrap=socketpair,--wrap=pthread_self,--wrap=pthread_mutex_lock,--wrap=pthread_join,--wrap=pipe,--wrap=pipe2"
+        MOZ_GLUE_WRAP_LDFLAGS="${MOZ_GLUE_WRAP_LDFLAGS} -Wl,--wrap=pthread_create,--wrap=epoll_wait,--wrap=poll,--wrap=pthread_cond_timedwait,--wrap=pthread_cond_wait,--wrap=epoll_create,--wrap=epoll_ctl,--wrap=close,--wrap=pthread_key_create,--wrap=pthread_key_delete,--wrap=socketpair,--wrap=pthread_self,--wrap=pthread_mutex_lock,--wrap=pthread_join,--wrap=pipe,--wrap=pipe2"
     fi
 fi
 
 AC_SUBST_LIST(MOZ_GLUE_WRAP_LDFLAGS)
 export MOZ_GLUE_WRAP_LDFLAGS
 
 dnl ========================================================
 dnl JS opt-mode assertions and minidump instrumentation
--- a/dom/camera/CameraControlImpl.cpp
+++ b/dom/camera/CameraControlImpl.cpp
@@ -10,39 +10,36 @@
 #include "nsIWeakReferenceUtils.h"
 #include "CameraCommon.h"
 #include "nsGlobalWindow.h"
 #include "DeviceStorageFileDescriptor.h"
 #include "CameraControlListener.h"
 
 using namespace mozilla;
 
-nsWeakPtr CameraControlImpl::sCameraThread;
+/* static */ StaticRefPtr<nsIThread> CameraControlImpl::sCameraThread;
 
-CameraControlImpl::CameraControlImpl(uint32_t aCameraId)
+CameraControlImpl::CameraControlImpl()
   : mListenerLock(PR_NewRWLock(PR_RWLOCK_RANK_NONE, "CameraControlImpl.Listeners.Lock"))
-  , mCameraId(aCameraId)
   , mPreviewState(CameraControlListener::kPreviewStopped)
   , mHardwareState(CameraControlListener::kHardwareClosed)
   , mHardwareStateChangeReason(NS_OK)
 {
   DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this);
 
   // reuse the same camera thread to conserve resources
-  nsCOMPtr<nsIThread> ct = do_QueryReferent(sCameraThread);
+  nsCOMPtr<nsIThread> ct = do_QueryInterface(sCameraThread);
   if (ct) {
     mCameraThread = ct.forget();
   } else {
     nsresult rv = NS_NewNamedThread("CameraThread", getter_AddRefs(mCameraThread));
     if (NS_FAILED(rv)) {
       MOZ_CRASH("Failed to create new Camera Thread");
     }
-
-    // keep a weak reference to the new thread
-    sCameraThread = do_GetWeakReference(mCameraThread);
+    sCameraThread = mCameraThread;
   }
 
   // Care must be taken with the mListenerLock read-write lock to prevent
   // deadlocks. Currently this is handled by ensuring that any attempts to
   // acquire the lock for writing (as in Add/RemoveListener()) happen in a
   // runnable dispatched to the Camera Thread--even if the method is being
   // called from that thread. This ensures that if a registered listener
   // (which is invoked with a read-lock) tries to call Add/RemoveListener(),
@@ -53,30 +50,26 @@ CameraControlImpl::CameraControlImpl(uin
   // the read-write lock allows multiple simultaneous read-locks.
   if (!mListenerLock) {
     MOZ_CRASH("Out of memory getting new PRRWLock");
   }
 }
 
 CameraControlImpl::~CameraControlImpl()
 {
+  DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this);
+
   MOZ_ASSERT(mListenerLock, "mListenerLock missing in ~CameraControlImpl()");
   if (mListenerLock) {
     PR_DestroyRWLock(mListenerLock);
     mListenerLock = nullptr;
   }
 }
 
 void
-CameraControlImpl::Shutdown()
-{
-  DOM_CAMERA_LOGT("%s:%d\n", __func__, __LINE__);
-}
-
-void
 CameraControlImpl::OnHardwareStateChange(CameraControlListener::HardwareState aNewState,
                                          nsresult aReason)
 {
   // This callback can run on threads other than the Main Thread and
   //  the Camera Thread. On Gonk, it may be called from the camera's
   //  local binder thread, should the mediaserver process die.
   RwLockAutoEnterRead lock(mListenerLock);
 
--- a/dom/camera/CameraControlImpl.h
+++ b/dom/camera/CameraControlImpl.h
@@ -23,17 +23,17 @@ namespace mozilla {
 
 namespace layers {
   class Image;
 }
 
 class CameraControlImpl : public ICameraControl
 {
 public:
-  explicit CameraControlImpl(uint32_t aCameraId);
+  explicit CameraControlImpl();
   virtual void AddListener(CameraControlListener* aListener) MOZ_OVERRIDE;
   virtual void RemoveListener(CameraControlListener* aListener) MOZ_OVERRIDE;
 
   // See ICameraControl.h for these methods' return values.
   virtual nsresult Start(const Configuration* aConfig = nullptr) MOZ_OVERRIDE;
   virtual nsresult Stop() MOZ_OVERRIDE;
   virtual nsresult SetConfiguration(const Configuration& aConfig) MOZ_OVERRIDE;
   virtual nsresult StartPreview() MOZ_OVERRIDE;
@@ -42,20 +42,16 @@ public:
   virtual nsresult StartFaceDetection() MOZ_OVERRIDE;
   virtual nsresult StopFaceDetection() MOZ_OVERRIDE;
   virtual nsresult TakePicture() MOZ_OVERRIDE;
   virtual nsresult StartRecording(DeviceStorageFileDescriptor* aFileDescriptor,
                                   const StartRecordingOptions* aOptions) MOZ_OVERRIDE;
   virtual nsresult StopRecording() MOZ_OVERRIDE;
   virtual nsresult ResumeContinuousFocus() MOZ_OVERRIDE;
 
-  uint32_t GetCameraId() { return mCameraId; }
-
-  virtual void Shutdown() MOZ_OVERRIDE;
-
   // Event handlers called directly from outside this class.
   void OnShutter();
   void OnUserError(CameraControlListener::UserContext aContext, nsresult aError);
   void OnSystemError(CameraControlListener::SystemContext aContext, nsresult aError);
   void OnAutoFocusMoving(bool aIsMoving);
 
 protected:
   // Event handlers.
@@ -72,17 +68,17 @@ protected:
                              nsresult aReason);
   void OnConfigurationChange();
 
   // When we create a new CameraThread, we keep a static reference to it so
   // that multiple CameraControl instances can find and reuse it; but we
   // don't want that reference to keep the thread object around unnecessarily,
   // so we make it a weak reference. The strong dynamic references will keep
   // the thread object alive as needed.
-  static nsWeakPtr sCameraThread;
+  static StaticRefPtr<nsIThread> sCameraThread;
   nsCOMPtr<nsIThread> mCameraThread;
 
   virtual ~CameraControlImpl();
 
   virtual void BeginBatchParameterSet() MOZ_OVERRIDE { }
   virtual void EndBatchParameterSet() MOZ_OVERRIDE { }
 
   // Manage camera event listeners.
@@ -123,18 +119,16 @@ protected:
   virtual nsresult StopRecordingImpl() = 0;
   virtual nsresult ResumeContinuousFocusImpl() = 0;
   virtual nsresult PushParametersImpl() = 0;
   virtual nsresult PullParametersImpl() = 0;
 
   void OnShutterInternal();
   void OnClosedInternal();
 
-  uint32_t mCameraId;
-
   CameraControlListener::CameraListenerConfiguration mCurrentConfiguration;
 
   CameraControlListener::PreviewState   mPreviewState;
   CameraControlListener::HardwareState  mHardwareState;
   nsresult                              mHardwareStateChangeReason;
 
 private:
   CameraControlImpl(const CameraControlImpl&) MOZ_DELETE;
--- a/dom/camera/CameraPreviewMediaStream.cpp
+++ b/dom/camera/CameraPreviewMediaStream.cpp
@@ -131,16 +131,17 @@ CameraPreviewMediaStream::OnPreviewState
     }
   }
 }
 
 void
 CameraPreviewMediaStream::Destroy()
 {
   MutexAutoLock lock(mMutex);
+  mMainThreadDestroyed = true;
   DestroyImpl();
 }
 
 void
 CameraPreviewMediaStream::Invalidate()
 {
   MutexAutoLock lock(mMutex);
   --mInvalidatePending;
--- a/dom/camera/CameraPreviewMediaStream.h
+++ b/dom/camera/CameraPreviewMediaStream.h
@@ -27,35 +27,35 @@ protected:
   ~FakeMediaStreamGraph()
   {}
 };
 
 /**
  * This is a stream for camera preview.
  *
  * XXX It is a temporary fix of SourceMediaStream.
- * A camera preview requests no delay and no buffering stream.
- * But the SourceMediaStream do not support it.
+ * A camera preview requests no delay and no buffering stream,
+ * but the SourceMediaStream does not support it.
  */
 class CameraPreviewMediaStream : public MediaStream
 {
   typedef mozilla::layers::Image Image;
 
 public:
   explicit CameraPreviewMediaStream(DOMMediaStream* aWrapper);
 
   virtual void AddAudioOutput(void* aKey) MOZ_OVERRIDE;
   virtual void SetAudioOutputVolume(void* aKey, float aVolume) MOZ_OVERRIDE;
   virtual void RemoveAudioOutput(void* aKey) MOZ_OVERRIDE;
   virtual void AddVideoOutput(VideoFrameContainer* aContainer) MOZ_OVERRIDE;
   virtual void RemoveVideoOutput(VideoFrameContainer* aContainer) MOZ_OVERRIDE;
   virtual void ChangeExplicitBlockerCount(int32_t aDelta) MOZ_OVERRIDE;
   virtual void AddListener(MediaStreamListener* aListener) MOZ_OVERRIDE;
   virtual void RemoveListener(MediaStreamListener* aListener) MOZ_OVERRIDE;
-  virtual void Destroy();
+  virtual void Destroy() MOZ_OVERRIDE;
   void OnPreviewStateChange(bool aActive);
 
   void Invalidate();
 
   // Call these on any thread.
   void SetCurrentFrame(const gfxIntSize& aIntrinsicSize, Image* aImage);
   void ClearCurrentFrame();
   void RateLimit(bool aLimit);
--- a/dom/camera/DOMCameraCapabilities.cpp
+++ b/dom/camera/DOMCameraCapabilities.cpp
@@ -2,26 +2,90 @@
 /* vim:set ts=2 sw=2 sts=2 et cindent: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "DOMCameraCapabilities.h"
 #include "nsPIDOMWindow.h"
 #include "nsContentUtils.h"
+#include "nsProxyRelease.h"
 #include "mozilla/dom/CameraManagerBinding.h"
 #include "mozilla/dom/CameraCapabilitiesBinding.h"
 #include "Navigator.h"
 #include "CameraCommon.h"
 #include "ICameraControl.h"
+#include "CameraControlListener.h"
 
 namespace mozilla {
 namespace dom {
 
 /**
+ * CameraClosedListenerProxy and CameraClosedMessage
+ */
+template<class T>
+class CameraClosedMessage : public nsRunnable
+{
+public:
+  CameraClosedMessage(nsMainThreadPtrHandle<T> aListener)
+    : mListener(aListener)
+  {
+    DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this);
+  }
+
+  NS_IMETHODIMP
+  Run() MOZ_OVERRIDE
+  {
+    MOZ_ASSERT(NS_IsMainThread());
+
+    nsRefPtr<T> listener = mListener.get();
+    if (listener) {
+      listener->OnHardwareClosed();
+    }
+    return NS_OK;
+  }
+
+protected:
+  virtual ~CameraClosedMessage()
+  {
+    DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this);
+  }
+
+  nsMainThreadPtrHandle<T> mListener;
+};
+
+template<class T>
+class CameraClosedListenerProxy : public CameraControlListener
+{
+public:
+  CameraClosedListenerProxy(T* aListener)
+    : mListener(new nsMainThreadPtrHolder<T>(aListener))
+  {
+    DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this);
+  }
+
+  virtual void
+  OnHardwareStateChange(HardwareState aState, nsresult aReason) MOZ_OVERRIDE
+  {
+    if (aState != kHardwareClosed) {
+      return;
+    }
+    NS_DispatchToMainThread(new CameraClosedMessage<T>(mListener));
+  }
+
+protected:
+  virtual ~CameraClosedListenerProxy()
+  {
+    DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this);
+  }
+
+  nsMainThreadPtrHandle<T> mListener;
+};
+
+/**
  * CameraRecorderVideoProfile
  */
 NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(CameraRecorderVideoProfile, mParent)
 
 NS_IMPL_CYCLE_COLLECTING_ADDREF(CameraRecorderVideoProfile)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(CameraRecorderVideoProfile)
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(CameraRecorderVideoProfile)
@@ -91,17 +155,20 @@ CameraRecorderAudioProfile::CameraRecord
 CameraRecorderAudioProfile::~CameraRecorderAudioProfile()
 {
   DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this);
 }
 
 /**
  * CameraRecorderProfile
  */
-NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(CameraRecorderProfile, mParent)
+NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(CameraRecorderProfile,
+                                      mParent,
+                                      mVideo,
+                                      mAudio)
 
 NS_IMPL_CYCLE_COLLECTING_ADDREF(CameraRecorderProfile)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(CameraRecorderProfile)
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(CameraRecorderProfile)
   NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
   NS_INTERFACE_MAP_ENTRY(nsISupports)
 NS_INTERFACE_MAP_END
@@ -131,17 +198,19 @@ CameraRecorderProfile::CameraRecorderPro
 CameraRecorderProfile::~CameraRecorderProfile()
 {
   DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this);
 }
 
 /**
  * CameraRecorderProfiles
  */
-NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(CameraRecorderProfiles, mParent)
+NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(CameraRecorderProfiles,
+                                      mParent,
+                                      mProfiles)
 
 NS_IMPL_CYCLE_COLLECTING_ADDREF(CameraRecorderProfiles)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(CameraRecorderProfiles)
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(CameraRecorderProfiles)
   NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
   NS_INTERFACE_MAP_ENTRY(nsISupports)
 NS_INTERFACE_MAP_END
@@ -153,40 +222,51 @@ CameraRecorderProfiles::WrapObject(JSCon
 }
 
 CameraRecorderProfiles::CameraRecorderProfiles(nsISupports* aParent,
                                                ICameraControl* aCameraControl)
   : mParent(aParent)
   , mCameraControl(aCameraControl)
 {
   DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this);
+  if (mCameraControl) {
+    mListener = new CameraClosedListenerProxy<CameraRecorderProfiles>(this);
+    mCameraControl->AddListener(mListener);
+  }
 }
 
 CameraRecorderProfiles::~CameraRecorderProfiles()
 {
   DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this);
 }
 
 void
 CameraRecorderProfiles::GetSupportedNames(unsigned aFlags, nsTArray<nsString>& aNames)
 {
   DOM_CAMERA_LOGT("%s:%d : this=%p, flags=0x%x\n",
     __func__, __LINE__, this, aFlags);
+  if (!mCameraControl) {
+    aNames.Clear();
+    return;
+  }
 
   nsresult rv = mCameraControl->GetRecorderProfiles(aNames);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     aNames.Clear();
   }
 }
 
 CameraRecorderProfile*
 CameraRecorderProfiles::NamedGetter(const nsAString& aName, bool& aFound)
 {
   DOM_CAMERA_LOGT("%s:%d : this=%p, name='%s'\n", __func__, __LINE__, this,
     NS_ConvertUTF16toUTF8(aName).get());
+  if (!mCameraControl) {
+    return nullptr;
+  }
 
   CameraRecorderProfile* profile = mProfiles.GetWeak(aName, &aFound);
   if (!aFound || !profile) {
     nsRefPtr<ICameraControl::RecorderProfile> p = mCameraControl->GetProfileInfo(aName);
     if (p) {
       profile = new CameraRecorderProfile(this, *p);
       mProfiles.Put(aName, profile);
       aFound = true;
@@ -199,16 +279,29 @@ bool
 CameraRecorderProfiles::NameIsEnumerable(const nsAString& aName)
 {
   DOM_CAMERA_LOGT("%s:%d : this=%p, name='%s' (always returns true)\n",
     __func__, __LINE__, this, NS_ConvertUTF16toUTF8(aName).get());
 
   return true;
 }
 
+void
+CameraRecorderProfiles::OnHardwareClosed()
+{
+  DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this);
+  MOZ_ASSERT(NS_IsMainThread());
+
+  if (mCameraControl) {
+    mCameraControl->RemoveListener(mListener);
+    mCameraControl = nullptr;
+  }
+  mListener = nullptr;
+}
+
 /**
  * CameraCapabilities
  */
 NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(CameraCapabilities, mWindow)
 
 NS_IMPL_CYCLE_COLLECTING_ADDREF(CameraCapabilities)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(CameraCapabilities)
 
@@ -221,35 +314,45 @@ NS_INTERFACE_MAP_END
 bool
 CameraCapabilities::HasSupport(JSContext* aCx, JSObject* aGlobal)
 {
   return Navigator::HasCameraSupport(aCx, aGlobal);
 }
 
 CameraCapabilities::CameraCapabilities(nsPIDOMWindow* aWindow,
                                        ICameraControl* aCameraControl)
-  : mMaxFocusAreas(0)
-  , mMaxMeteringAreas(0)
-  , mMaxDetectedFaces(0)
-  , mMinExposureCompensation(0.0)
-  , mMaxExposureCompensation(0.0)
-  , mExposureCompensationStep(0.0)
-  , mWindow(aWindow)
+  : mWindow(aWindow)
   , mCameraControl(aCameraControl)
 {
   DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this);
-  MOZ_COUNT_CTOR(CameraCapabilities);
+  if (mCameraControl) {
+    mListener = new CameraClosedListenerProxy<CameraCapabilities>(this);
+    mCameraControl->AddListener(mListener);
+  }
 }
 
 CameraCapabilities::~CameraCapabilities()
 {
   DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this);
   MOZ_COUNT_DTOR(CameraCapabilities);
 }
 
+void
+CameraCapabilities::OnHardwareClosed()
+{
+  DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this);
+  MOZ_ASSERT(NS_IsMainThread());
+
+  if (mCameraControl) {
+    mCameraControl->RemoveListener(mListener);
+    mCameraControl = nullptr;
+  }
+  mListener = nullptr;
+}
+
 JSObject*
 CameraCapabilities::WrapObject(JSContext* aCx)
 {
   return CameraCapabilitiesBinding::Wrap(aCx, this);
 }
 
 #define LOG_IF_ERROR(rv, param)                               \
   do {                                                        \
@@ -257,16 +360,20 @@ CameraCapabilities::WrapObject(JSContext
       DOM_CAMERA_LOGW("Error %x trying to get " #param "\n",  \
         (rv));                                                \
     }                                                         \
   } while(0)
 
 nsresult
 CameraCapabilities::TranslateToDictionary(uint32_t aKey, nsTArray<CameraSize>& aSizes)
 {
+  if (NS_WARN_IF(!mCameraControl)) {
+    return NS_ERROR_NOT_AVAILABLE;
+  }
+
   nsresult rv;
   nsTArray<ICameraControl::Size> sizes;
 
   rv = mCameraControl->Get(aKey, sizes);
   if (NS_FAILED(rv)) {
     return rv;
   }
 
@@ -276,225 +383,230 @@ CameraCapabilities::TranslateToDictionar
     CameraSize* s = aSizes.AppendElement();
     s->mWidth = sizes[i].width;
     s->mHeight = sizes[i].height;
   }
 
   return NS_OK;
 }
 
+// The following attributes are tagged [Cached, Constant] in the WebIDL, so
+// the framework will handle caching them for us.
+
 void
-CameraCapabilities::GetPreviewSizes(nsTArray<dom::CameraSize>& retval)
+CameraCapabilities::GetPreviewSizes(nsTArray<dom::CameraSize>& aRetVal)
 {
-  if (mPreviewSizes.Length() == 0) {
-    nsresult rv = TranslateToDictionary(CAMERA_PARAM_SUPPORTED_PREVIEWSIZES,
-                                        mPreviewSizes);
-    LOG_IF_ERROR(rv, CAMERA_PARAM_SUPPORTED_PREVIEWSIZES);
-  }
-  retval = mPreviewSizes;
+  nsresult rv = TranslateToDictionary(CAMERA_PARAM_SUPPORTED_PREVIEWSIZES, aRetVal);
+  LOG_IF_ERROR(rv, CAMERA_PARAM_SUPPORTED_PREVIEWSIZES);
 }
 
 void
-CameraCapabilities::GetPictureSizes(nsTArray<dom::CameraSize>& retval)
+CameraCapabilities::GetPictureSizes(nsTArray<dom::CameraSize>& aRetVal)
 {
-  if (mPictureSizes.Length() == 0) {
-    nsresult rv = TranslateToDictionary(CAMERA_PARAM_SUPPORTED_PICTURESIZES,
-                                        mPictureSizes);
-    LOG_IF_ERROR(rv, CAMERA_PARAM_SUPPORTED_PICTURESIZES);
-  }
-  retval = mPictureSizes;
+  nsresult rv = TranslateToDictionary(CAMERA_PARAM_SUPPORTED_PICTURESIZES, aRetVal);
+  LOG_IF_ERROR(rv, CAMERA_PARAM_SUPPORTED_PICTURESIZES);
 }
 
 void
-CameraCapabilities::GetThumbnailSizes(nsTArray<dom::CameraSize>& retval)
+CameraCapabilities::GetThumbnailSizes(nsTArray<dom::CameraSize>& aRetVal)
 {
-  if (mThumbnailSizes.Length() == 0) {
-    nsresult rv = TranslateToDictionary(CAMERA_PARAM_SUPPORTED_JPEG_THUMBNAIL_SIZES,
-                                        mThumbnailSizes);
-    LOG_IF_ERROR(rv, CAMERA_PARAM_SUPPORTED_JPEG_THUMBNAIL_SIZES);
-  }
-  retval = mThumbnailSizes;
+  nsresult rv = TranslateToDictionary(CAMERA_PARAM_SUPPORTED_JPEG_THUMBNAIL_SIZES, aRetVal);
+  LOG_IF_ERROR(rv, CAMERA_PARAM_SUPPORTED_JPEG_THUMBNAIL_SIZES);
 }
 
 void
-CameraCapabilities::GetVideoSizes(nsTArray<dom::CameraSize>& retval)
+CameraCapabilities::GetVideoSizes(nsTArray<dom::CameraSize>& aRetVal)
 {
-  if (mVideoSizes.Length() == 0) {
-    nsresult rv = TranslateToDictionary(CAMERA_PARAM_SUPPORTED_VIDEOSIZES,
-                                        mVideoSizes);
-    LOG_IF_ERROR(rv, CAMERA_PARAM_SUPPORTED_VIDEOSIZES);
-  }
-  retval = mVideoSizes;
+  nsresult rv = TranslateToDictionary(CAMERA_PARAM_SUPPORTED_VIDEOSIZES, aRetVal);
+  LOG_IF_ERROR(rv, CAMERA_PARAM_SUPPORTED_VIDEOSIZES);
 }
 
 void
-CameraCapabilities::GetFileFormats(nsTArray<nsString>& retval)
+CameraCapabilities::GetFileFormats(nsTArray<nsString>& aRetVal)
 {
-  if (mFileFormats.Length() == 0) {
-    nsresult rv = mCameraControl->Get(CAMERA_PARAM_SUPPORTED_PICTUREFORMATS,
-                                      mFileFormats);
-    LOG_IF_ERROR(rv, CAMERA_PARAM_SUPPORTED_PICTUREFORMATS);
+  if (NS_WARN_IF(!mCameraControl)) {
+    return;
   }
-  retval = mFileFormats;
+
+  nsresult rv = mCameraControl->Get(CAMERA_PARAM_SUPPORTED_PICTUREFORMATS, aRetVal);
+  LOG_IF_ERROR(rv, CAMERA_PARAM_SUPPORTED_PICTUREFORMATS);
 }
 
 void
-CameraCapabilities::GetWhiteBalanceModes(nsTArray<nsString>& retval)
+CameraCapabilities::GetWhiteBalanceModes(nsTArray<nsString>& aRetVal)
 {
-  if (mWhiteBalanceModes.Length() == 0) {
-    nsresult rv = mCameraControl->Get(CAMERA_PARAM_SUPPORTED_WHITEBALANCES,
-                                      mWhiteBalanceModes);
-    LOG_IF_ERROR(rv, CAMERA_PARAM_SUPPORTED_WHITEBALANCES);
+  if (NS_WARN_IF(!mCameraControl)) {
+    return;
   }
-  retval = mWhiteBalanceModes;
+
+  nsresult rv = mCameraControl->Get(CAMERA_PARAM_SUPPORTED_WHITEBALANCES, aRetVal);
+  LOG_IF_ERROR(rv, CAMERA_PARAM_SUPPORTED_WHITEBALANCES);
 }
 
 void
-CameraCapabilities::GetSceneModes(nsTArray<nsString>& retval)
+CameraCapabilities::GetSceneModes(nsTArray<nsString>& aRetVal)
 {
-  if (mSceneModes.Length() == 0) {
-    nsresult rv = mCameraControl->Get(CAMERA_PARAM_SUPPORTED_SCENEMODES,
-                                      mSceneModes);
-    LOG_IF_ERROR(rv, CAMERA_PARAM_SUPPORTED_SCENEMODES);
+  if (NS_WARN_IF(!mCameraControl)) {
+    return;
   }
-  retval = mSceneModes;
+
+  nsresult rv = mCameraControl->Get(CAMERA_PARAM_SUPPORTED_SCENEMODES, aRetVal);
+  LOG_IF_ERROR(rv, CAMERA_PARAM_SUPPORTED_SCENEMODES);
 }
 
 void
-CameraCapabilities::GetEffects(nsTArray<nsString>& retval)
+CameraCapabilities::GetEffects(nsTArray<nsString>& aRetVal)
 {
-  if (mEffects.Length() == 0) {
-    nsresult rv = mCameraControl->Get(CAMERA_PARAM_SUPPORTED_EFFECTS,
-                                      mEffects);
-    LOG_IF_ERROR(rv, CAMERA_PARAM_SUPPORTED_EFFECTS);
+  if (NS_WARN_IF(!mCameraControl)) {
+    return;
   }
-  retval = mEffects;
+
+  nsresult rv = mCameraControl->Get(CAMERA_PARAM_SUPPORTED_EFFECTS, aRetVal);
+  LOG_IF_ERROR(rv, CAMERA_PARAM_SUPPORTED_EFFECTS);
 }
 
 void
-CameraCapabilities::GetFlashModes(nsTArray<nsString>& retval)
+CameraCapabilities::GetFlashModes(nsTArray<nsString>& aRetVal)
 {
-  if (mFlashModes.Length() == 0) {
-    nsresult rv = mCameraControl->Get(CAMERA_PARAM_SUPPORTED_FLASHMODES,
-                                      mFlashModes);
-    LOG_IF_ERROR(rv, CAMERA_PARAM_SUPPORTED_FLASHMODES);
+  if (NS_WARN_IF(!mCameraControl)) {
+    return;
   }
-  retval = mFlashModes;
+
+  nsresult rv = mCameraControl->Get(CAMERA_PARAM_SUPPORTED_FLASHMODES, aRetVal);
+  LOG_IF_ERROR(rv, CAMERA_PARAM_SUPPORTED_FLASHMODES);
 }
 
 void
-CameraCapabilities::GetFocusModes(nsTArray<nsString>& retval)
+CameraCapabilities::GetFocusModes(nsTArray<nsString>& aRetVal)
 {
-  if (mFocusModes.Length() == 0) {
-    nsresult rv = mCameraControl->Get(CAMERA_PARAM_SUPPORTED_FOCUSMODES,
-                                      mFocusModes);
-    LOG_IF_ERROR(rv, CAMERA_PARAM_SUPPORTED_FOCUSMODES);
+  if (NS_WARN_IF(!mCameraControl)) {
+    return;
   }
-  retval = mFocusModes;
+
+  nsresult rv = mCameraControl->Get(CAMERA_PARAM_SUPPORTED_FOCUSMODES, aRetVal);
+  LOG_IF_ERROR(rv, CAMERA_PARAM_SUPPORTED_FOCUSMODES);
 }
 
 void
-CameraCapabilities::GetZoomRatios(nsTArray<double>& retval)
+CameraCapabilities::GetZoomRatios(nsTArray<double>& aRetVal)
 {
-  if (mZoomRatios.Length() == 0) {
-    nsresult rv = mCameraControl->Get(CAMERA_PARAM_SUPPORTED_ZOOMRATIOS,
-                                      mZoomRatios);
-    LOG_IF_ERROR(rv, CAMERA_PARAM_SUPPORTED_ZOOMRATIOS);
+  if (NS_WARN_IF(!mCameraControl)) {
+    return;
   }
-  retval = mZoomRatios;
+
+  nsresult rv = mCameraControl->Get(CAMERA_PARAM_SUPPORTED_ZOOMRATIOS, aRetVal);
+  LOG_IF_ERROR(rv, CAMERA_PARAM_SUPPORTED_ZOOMRATIOS);
 }
 
 uint32_t
 CameraCapabilities::MaxFocusAreas()
 {
-  if (mMaxFocusAreas == 0) {
-    int32_t areas;
-    nsresult rv = mCameraControl->Get(CAMERA_PARAM_SUPPORTED_MAXFOCUSAREAS,
-                                      areas);
-    LOG_IF_ERROR(rv, CAMERA_PARAM_SUPPORTED_MAXFOCUSAREAS);
-    mMaxFocusAreas = areas < 0 ? 0 : areas;
+  if (NS_WARN_IF(!mCameraControl)) {
+    return 0;
   }
-  return mMaxFocusAreas;
+
+  int32_t areas = 0;
+  nsresult rv = mCameraControl->Get(CAMERA_PARAM_SUPPORTED_MAXFOCUSAREAS, areas);
+  LOG_IF_ERROR(rv, CAMERA_PARAM_SUPPORTED_MAXFOCUSAREAS);
+  return areas < 0 ? 0 : areas;
 }
 
 uint32_t
 CameraCapabilities::MaxMeteringAreas()
 {
-  if (mMaxMeteringAreas == 0) {
-    int32_t areas;
-    nsresult rv = mCameraControl->Get(CAMERA_PARAM_SUPPORTED_MAXMETERINGAREAS,
-                                      areas);
-    LOG_IF_ERROR(rv, CAMERA_PARAM_SUPPORTED_MAXMETERINGAREAS);
-    mMaxMeteringAreas = areas < 0 ? 0 : areas;
+  if (NS_WARN_IF(!mCameraControl)) {
+    return 0;
   }
-  return mMaxMeteringAreas;
+
+  int32_t areas = 0;
+  nsresult rv = mCameraControl->Get(CAMERA_PARAM_SUPPORTED_MAXMETERINGAREAS, areas);
+  LOG_IF_ERROR(rv, CAMERA_PARAM_SUPPORTED_MAXMETERINGAREAS);
+  return areas < 0 ? 0 : areas;
 }
 
 uint32_t
 CameraCapabilities::MaxDetectedFaces()
 {
-  if (mMaxDetectedFaces == 0) {
-    int32_t faces;
-    nsresult rv = mCameraControl->Get(CAMERA_PARAM_SUPPORTED_MAXDETECTEDFACES,
-                                      faces);
-    LOG_IF_ERROR(rv, CAMERA_PARAM_SUPPORTED_MAXDETECTEDFACES);
-    mMaxDetectedFaces = faces < 0 ? 0 : faces;
+  if (NS_WARN_IF(!mCameraControl)) {
+    return 0;
   }
-  return mMaxDetectedFaces;
+
+  int32_t faces = 0;
+  nsresult rv = mCameraControl->Get(CAMERA_PARAM_SUPPORTED_MAXDETECTEDFACES, faces);
+  LOG_IF_ERROR(rv, CAMERA_PARAM_SUPPORTED_MAXDETECTEDFACES);
+  return faces < 0 ? 0 : faces;
 }
 
 double
 CameraCapabilities::MinExposureCompensation()
 {
-  if (mMinExposureCompensation == 0.0) {
-    nsresult rv = mCameraControl->Get(CAMERA_PARAM_SUPPORTED_MINEXPOSURECOMPENSATION,
-                                      mMinExposureCompensation);
-    LOG_IF_ERROR(rv, CAMERA_PARAM_SUPPORTED_MINEXPOSURECOMPENSATION);
+  if (NS_WARN_IF(!mCameraControl)) {
+    return 0.0;
   }
-  return mMinExposureCompensation;
+
+  double minEv = 0.0;
+  nsresult rv = mCameraControl->Get(CAMERA_PARAM_SUPPORTED_MINEXPOSURECOMPENSATION, minEv);
+  LOG_IF_ERROR(rv, CAMERA_PARAM_SUPPORTED_MINEXPOSURECOMPENSATION);
+  return minEv;
 }
 
 double
 CameraCapabilities::MaxExposureCompensation()
 {
-  if (mMaxExposureCompensation == 0.0) {
-    nsresult rv = mCameraControl->Get(CAMERA_PARAM_SUPPORTED_MAXEXPOSURECOMPENSATION,
-                                      mMaxExposureCompensation);
-    LOG_IF_ERROR(rv, CAMERA_PARAM_SUPPORTED_MAXEXPOSURECOMPENSATION);
+  if (NS_WARN_IF(!mCameraControl)) {
+    return 0.0;
   }
-  return mMaxExposureCompensation;
+
+  double maxEv = 0.0;
+  nsresult rv = mCameraControl->Get(CAMERA_PARAM_SUPPORTED_MAXEXPOSURECOMPENSATION, maxEv);
+  LOG_IF_ERROR(rv, CAMERA_PARAM_SUPPORTED_MAXEXPOSURECOMPENSATION);
+  return maxEv;
 }
 
 double
 CameraCapabilities::ExposureCompensationStep()
 {
-  if (mExposureCompensationStep == 0.0) {
-    nsresult rv = mCameraControl->Get(CAMERA_PARAM_SUPPORTED_EXPOSURECOMPENSATIONSTEP,
-                                      mExposureCompensationStep);
-    LOG_IF_ERROR(rv, CAMERA_PARAM_SUPPORTED_EXPOSURECOMPENSATIONSTEP);
+  if (NS_WARN_IF(!mCameraControl)) {
+    return 0.0;
   }
-  return mExposureCompensationStep;
+
+  double evStep = 0.0;
+  nsresult rv = mCameraControl->Get(CAMERA_PARAM_SUPPORTED_EXPOSURECOMPENSATIONSTEP, evStep);
+  LOG_IF_ERROR(rv, CAMERA_PARAM_SUPPORTED_EXPOSURECOMPENSATIONSTEP);
+  return evStep;
 }
 
 CameraRecorderProfiles*
 CameraCapabilities::RecorderProfiles()
 {
-  nsRefPtr<CameraRecorderProfiles> profiles = mRecorderProfiles;
-  if (!mRecorderProfiles) {
-    profiles = new CameraRecorderProfiles(this, mCameraControl);
-    mRecorderProfiles = profiles;
+  if (NS_WARN_IF(!mCameraControl)) {
+    return nullptr;
   }
+
+  nsRefPtr<CameraRecorderProfiles> profiles =
+    new CameraRecorderProfiles(this, mCameraControl);
   return profiles;
 }
 
 void
-CameraCapabilities::GetIsoModes(nsTArray<nsString>& retval)
+CameraCapabilities::GetIsoModes(nsTArray<nsString>& aRetVal)
 {
-  if (mIsoModes.Length() == 0) {
-    nsresult rv = mCameraControl->Get(CAMERA_PARAM_SUPPORTED_ISOMODES,
-                                      mIsoModes);
-    LOG_IF_ERROR(rv, CAMERA_PARAM_SUPPORTED_ISOMODES);
+  if (NS_WARN_IF(!mCameraControl)) {
+    return;
   }
-  retval = mIsoModes;
+
+  nsresult rv = mCameraControl->Get(CAMERA_PARAM_SUPPORTED_ISOMODES, aRetVal);
+  LOG_IF_ERROR(rv, CAMERA_PARAM_SUPPORTED_ISOMODES);
+}
+
+void
+CameraCapabilities::GetMeteringModes(nsTArray<nsString>& aRetVal)
+{
+  if (NS_WARN_IF(!mCameraControl)) {
+    return;
+  }
+
+  nsresult rv = mCameraControl->Get(CAMERA_PARAM_SUPPORTED_METERINGMODES, aRetVal);
+  LOG_IF_ERROR(rv, CAMERA_PARAM_SUPPORTED_METERINGMODES);
 }
 
 } // namespace dom
 } // namespace mozilla
--- a/dom/camera/DOMCameraCapabilities.h
+++ b/dom/camera/DOMCameraCapabilities.h
@@ -141,38 +141,43 @@ protected:
 
 private:
   DISALLOW_EVIL_CONSTRUCTORS(CameraRecorderProfile);
 };
 
 /**
  * CameraRecorderProfiles
  */
+template<class T> class CameraClosedListenerProxy;
+
 class CameraRecorderProfiles MOZ_FINAL : public nsISupports
                                        , public nsWrapperCache
 {
 public:
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
   NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(CameraRecorderProfiles)
 
   explicit CameraRecorderProfiles(nsISupports* aParent,
                                   ICameraControl* aCameraControl);
   nsISupports* GetParentObject() const { return mParent; }
   virtual JSObject* WrapObject(JSContext* aCx) MOZ_OVERRIDE;
 
   CameraRecorderProfile* NamedGetter(const nsAString& aName, bool& aFound);
   bool NameIsEnumerable(const nsAString& aName);
   void GetSupportedNames(unsigned aFlags, nsTArray<nsString>& aNames);
 
+  virtual void OnHardwareClosed();
+
 protected:
   virtual ~CameraRecorderProfiles();
 
   nsCOMPtr<nsISupports> mParent;
   nsRefPtr<ICameraControl> mCameraControl;
   nsRefPtrHashtable<nsStringHashKey, CameraRecorderProfile> mProfiles;
+  nsRefPtr<CameraClosedListenerProxy<CameraRecorderProfiles>> mListener;
 
 private:
   DISALLOW_EVIL_CONSTRUCTORS(CameraRecorderProfiles);
 };
 
 /**
  * CameraCapabilities
  */
@@ -210,50 +215,30 @@ public:
   void GetZoomRatios(nsTArray<double>& aRetVal);
   uint32_t MaxFocusAreas();
   uint32_t MaxMeteringAreas();
   uint32_t MaxDetectedFaces();
   double MinExposureCompensation();
   double MaxExposureCompensation();
   double ExposureCompensationStep();
   void GetIsoModes(nsTArray<nsString>& aRetVal);
+  void GetMeteringModes(nsTArray<nsString>& aRetVal);
 
   CameraRecorderProfiles* RecorderProfiles();
 
+  virtual void OnHardwareClosed();
+
 protected:
   ~CameraCapabilities();
 
   nsresult TranslateToDictionary(uint32_t aKey, nsTArray<CameraSize>& aSizes);
 
-  nsTArray<CameraSize> mPreviewSizes;
-  nsTArray<CameraSize> mPictureSizes;
-  nsTArray<CameraSize> mThumbnailSizes;
-  nsTArray<CameraSize> mVideoSizes;
-
-  nsTArray<nsString> mFileFormats;
-  nsTArray<nsString> mWhiteBalanceModes;
-  nsTArray<nsString> mSceneModes;
-  nsTArray<nsString> mEffects;
-  nsTArray<nsString> mFlashModes;
-  nsTArray<nsString> mFocusModes;
-  nsTArray<nsString> mIsoModes;
-
-  nsTArray<double> mZoomRatios;
-
-  uint32_t mMaxFocusAreas;
-  uint32_t mMaxMeteringAreas;
-  uint32_t mMaxDetectedFaces;
-
-  double mMinExposureCompensation;
-  double mMaxExposureCompensation;
-  double mExposureCompensationStep;
-
   nsRefPtr<nsPIDOMWindow> mWindow;
   nsRefPtr<ICameraControl> mCameraControl;
-  nsRefPtr<CameraRecorderProfiles> mRecorderProfiles;
+  nsRefPtr<CameraClosedListenerProxy<CameraCapabilities>> mListener;
 
 private:
   DISALLOW_EVIL_CONSTRUCTORS(CameraCapabilities);
 };
 
 } // namespace dom
 } // namespace mozilla
 
--- a/dom/camera/DOMCameraControl.cpp
+++ b/dom/camera/DOMCameraControl.cpp
@@ -49,23 +49,29 @@ using namespace mozilla::ipc;
 
 #ifdef MOZ_WIDGET_GONK
 StaticRefPtr<ICameraControl> nsDOMCameraControl::sCachedCameraControl;
 /* static */ nsresult nsDOMCameraControl::sCachedCameraControlStartResult = NS_OK;
 /* static */ nsCOMPtr<nsITimer> nsDOMCameraControl::sDiscardCachedCameraControlTimer;
 #endif
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(nsDOMCameraControl)
-  NS_INTERFACE_MAP_ENTRY(nsISupports)
+  NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
+  // nsISupports is an ambiguous base of nsDOMCameraControl
+  // so we have to work around that.
+  if ( aIID.Equals(NS_GET_IID(nsDOMCameraControl)) )
+    foundInterface = static_cast<nsISupports*>(static_cast<void*>(this));
+  else
 NS_INTERFACE_MAP_END_INHERITING(DOMMediaStream)
 
 NS_IMPL_ADDREF_INHERITED(nsDOMCameraControl, DOMMediaStream)
 NS_IMPL_RELEASE_INHERITED(nsDOMCameraControl, DOMMediaStream)
 
 NS_IMPL_CYCLE_COLLECTION_INHERITED(nsDOMCameraControl, DOMMediaStream,
+                                   mAudioChannelAgent,
                                    mCapabilities,
                                    mWindow,
                                    mGetCameraPromise,
                                    mAutoFocusPromise,
                                    mTakePicturePromise,
                                    mStartRecordingPromise,
                                    mReleasePromise,
                                    mSetConfigurationPromise)
@@ -128,17 +134,17 @@ nsDOMCameraControl::DOMCameraConfigurati
 }
 
 nsDOMCameraControl::DOMCameraConfiguration::~DOMCameraConfiguration()
 {
   MOZ_COUNT_DTOR(nsDOMCameraControl::DOMCameraConfiguration);
 }
 
 #ifdef MOZ_WIDGET_GONK
-// This shoudl be long enough for even our slowest platforms.
+// This should be long enough for even our slowest platforms.
 static const unsigned long kCachedCameraTimeoutMs = 3500;
 
 // Open the battery-door-facing camera by default.
 static const uint32_t kDefaultCameraId = 0;
 
 /* static */ void
 nsDOMCameraControl::PreinitCameraHardware()
 {
@@ -378,124 +384,146 @@ nsDOMCameraControl::Get(uint32_t aKey, n
       v.mRight,
       v.mWeight
     );
   }
 
   return NS_OK;
 }
 
+#define THROW_IF_NO_CAMERACONTROL(...)                                          \
+  do {                                                                          \
+    if (!mCameraControl) {                                                      \
+      DOM_CAMERA_LOGW("mCameraControl is null at %s:%d\n", __func__, __LINE__); \
+      aRv = NS_ERROR_NOT_AVAILABLE;                                             \
+      return __VA_ARGS__;                                                       \
+    }                                                                           \
+  } while (0)
+
 void
 nsDOMCameraControl::GetEffect(nsString& aEffect, ErrorResult& aRv)
 {
-  MOZ_ASSERT(mCameraControl);
+  THROW_IF_NO_CAMERACONTROL();
   aRv = mCameraControl->Get(CAMERA_PARAM_EFFECT, aEffect);
 }
 void
 nsDOMCameraControl::SetEffect(const nsAString& aEffect, ErrorResult& aRv)
 {
-  MOZ_ASSERT(mCameraControl);
+  THROW_IF_NO_CAMERACONTROL();
   aRv = mCameraControl->Set(CAMERA_PARAM_EFFECT, aEffect);
 }
 
 void
 nsDOMCameraControl::GetWhiteBalanceMode(nsString& aWhiteBalanceMode, ErrorResult& aRv)
 {
-  MOZ_ASSERT(mCameraControl);
+  THROW_IF_NO_CAMERACONTROL();
   aRv = mCameraControl->Get(CAMERA_PARAM_WHITEBALANCE, aWhiteBalanceMode);
 }
 void
 nsDOMCameraControl::SetWhiteBalanceMode(const nsAString& aWhiteBalanceMode, ErrorResult& aRv)
 {
-  MOZ_ASSERT(mCameraControl);
+  THROW_IF_NO_CAMERACONTROL();
   aRv = mCameraControl->Set(CAMERA_PARAM_WHITEBALANCE, aWhiteBalanceMode);
 }
 
 void
 nsDOMCameraControl::GetSceneMode(nsString& aSceneMode, ErrorResult& aRv)
 {
-  MOZ_ASSERT(mCameraControl);
+  THROW_IF_NO_CAMERACONTROL();
   aRv = mCameraControl->Get(CAMERA_PARAM_SCENEMODE, aSceneMode);
 }
 void
 nsDOMCameraControl::SetSceneMode(const nsAString& aSceneMode, ErrorResult& aRv)
 {
-  MOZ_ASSERT(mCameraControl);
+  THROW_IF_NO_CAMERACONTROL();
   aRv = mCameraControl->Set(CAMERA_PARAM_SCENEMODE, aSceneMode);
 }
 
 void
 nsDOMCameraControl::GetFlashMode(nsString& aFlashMode, ErrorResult& aRv)
 {
-  MOZ_ASSERT(mCameraControl);
+  THROW_IF_NO_CAMERACONTROL();
   aRv = mCameraControl->Get(CAMERA_PARAM_FLASHMODE, aFlashMode);
 }
 void
 nsDOMCameraControl::SetFlashMode(const nsAString& aFlashMode, ErrorResult& aRv)
 {
-  MOZ_ASSERT(mCameraControl);
+  THROW_IF_NO_CAMERACONTROL();
   aRv = mCameraControl->Set(CAMERA_PARAM_FLASHMODE, aFlashMode);
 }
 
 void
 nsDOMCameraControl::GetFocusMode(nsString& aFocusMode, ErrorResult& aRv)
 {
-  MOZ_ASSERT(mCameraControl);
+  THROW_IF_NO_CAMERACONTROL();
   aRv = mCameraControl->Get(CAMERA_PARAM_FOCUSMODE, aFocusMode);
 }
 void
 nsDOMCameraControl::SetFocusMode(const nsAString& aFocusMode, ErrorResult& aRv)
 {
-  MOZ_ASSERT(mCameraControl);
+  THROW_IF_NO_CAMERACONTROL();
   aRv = mCameraControl->Set(CAMERA_PARAM_FOCUSMODE, aFocusMode);
 }
 
 void
 nsDOMCameraControl::GetIsoMode(nsString& aIsoMode, ErrorResult& aRv)
 {
-  MOZ_ASSERT(mCameraControl);
+  THROW_IF_NO_CAMERACONTROL();
   aRv = mCameraControl->Get(CAMERA_PARAM_ISOMODE, aIsoMode);
 }
 void
 nsDOMCameraControl::SetIsoMode(const nsAString& aIsoMode, ErrorResult& aRv)
 {
-  MOZ_ASSERT(mCameraControl);
+  THROW_IF_NO_CAMERACONTROL();
   aRv = mCameraControl->Set(CAMERA_PARAM_ISOMODE, aIsoMode);
 }
 
 double
 nsDOMCameraControl::GetPictureQuality(ErrorResult& aRv)
 {
-  MOZ_ASSERT(mCameraControl);
+  THROW_IF_NO_CAMERACONTROL(1.0);
 
   double quality;
   aRv = mCameraControl->Get(CAMERA_PARAM_PICTURE_QUALITY, quality);
   return quality;
 }
 void
 nsDOMCameraControl::SetPictureQuality(double aQuality, ErrorResult& aRv)
 {
-  MOZ_ASSERT(mCameraControl);
+  THROW_IF_NO_CAMERACONTROL();
   aRv = mCameraControl->Set(CAMERA_PARAM_PICTURE_QUALITY, aQuality);
 }
 
+void
+nsDOMCameraControl::GetMeteringMode(nsString& aMode, ErrorResult& aRv)
+{
+  THROW_IF_NO_CAMERACONTROL();
+  aRv = mCameraControl->Get(CAMERA_PARAM_METERINGMODE, aMode);
+}
+void
+nsDOMCameraControl::SetMeteringMode(const nsAString& aMode, ErrorResult& aRv)
+{
+  THROW_IF_NO_CAMERACONTROL();
+  aRv = mCameraControl->Set(CAMERA_PARAM_METERINGMODE, aMode);
+}
+
 double
 nsDOMCameraControl::GetZoom(ErrorResult& aRv)
 {
-  MOZ_ASSERT(mCameraControl);
+  THROW_IF_NO_CAMERACONTROL(1.0);
 
   double zoom = 1.0;
   aRv = mCameraControl->Get(CAMERA_PARAM_ZOOM, zoom);
   return zoom;
 }
 
 void
 nsDOMCameraControl::SetZoom(double aZoom, ErrorResult& aRv)
 {
-  MOZ_ASSERT(mCameraControl);
+  THROW_IF_NO_CAMERACONTROL();
   aRv = mCameraControl->Set(CAMERA_PARAM_ZOOM, aZoom);
 }
 
 void
 nsDOMCameraControl::GetMeteringAreas(nsTArray<CameraRegion>& aAreas, ErrorResult& aRv)
 {
   aRv = Get(CAMERA_PARAM_METERINGAREAS, aAreas);
 }
@@ -516,141 +544,150 @@ nsDOMCameraControl::SetFocusAreas(const 
 {
   aRv = Set(CAMERA_PARAM_FOCUSAREAS, aFocusAreas,
             mCurrentConfiguration->mMaxFocusAreas);
 }
 
 void
 nsDOMCameraControl::GetPictureSize(CameraSize& aSize, ErrorResult& aRv)
 {
+  THROW_IF_NO_CAMERACONTROL();
+
   ICameraControl::Size size;
   aRv = mCameraControl->Get(CAMERA_PARAM_PICTURE_SIZE, size);
   if (aRv.Failed()) {
     return;
   }
 
   aSize.mWidth = size.width;
   aSize.mHeight = size.height;
 }
 
 void
 nsDOMCameraControl::SetPictureSize(const CameraSize& aSize, ErrorResult& aRv)
 {
+  THROW_IF_NO_CAMERACONTROL();
   ICameraControl::Size s = { aSize.mWidth, aSize.mHeight };
   aRv = mCameraControl->Set(CAMERA_PARAM_PICTURE_SIZE, s);
 }
 
 void
 nsDOMCameraControl::GetThumbnailSize(CameraSize& aSize, ErrorResult& aRv)
 {
+  THROW_IF_NO_CAMERACONTROL();
   ICameraControl::Size size;
   aRv = mCameraControl->Get(CAMERA_PARAM_THUMBNAILSIZE, size);
   if (aRv.Failed()) {
     return;
   }
 
   aSize.mWidth = size.width;
   aSize.mHeight = size.height;
 }
 
 void
 nsDOMCameraControl::SetThumbnailSize(const CameraSize& aSize, ErrorResult& aRv)
 {
+  THROW_IF_NO_CAMERACONTROL();
   ICameraControl::Size s = { aSize.mWidth, aSize.mHeight };
   aRv = mCameraControl->Set(CAMERA_PARAM_THUMBNAILSIZE, s);
 }
 
 double
 nsDOMCameraControl::GetFocalLength(ErrorResult& aRv)
 {
-  MOZ_ASSERT(mCameraControl);
+  THROW_IF_NO_CAMERACONTROL(0.0);
 
   double focalLength;
   aRv = mCameraControl->Get(CAMERA_PARAM_FOCALLENGTH, focalLength);
   return focalLength;
 }
 
 double
 nsDOMCameraControl::GetFocusDistanceNear(ErrorResult& aRv)
 {
-  MOZ_ASSERT(mCameraControl);
+  THROW_IF_NO_CAMERACONTROL(0.0);
 
   double distance;
   aRv = mCameraControl->Get(CAMERA_PARAM_FOCUSDISTANCENEAR, distance);
   return distance;
 }
 
 double
 nsDOMCameraControl::GetFocusDistanceOptimum(ErrorResult& aRv)
 {
-  MOZ_ASSERT(mCameraControl);
+  THROW_IF_NO_CAMERACONTROL(0.0);
 
   double distance;
   aRv = mCameraControl->Get(CAMERA_PARAM_FOCUSDISTANCEOPTIMUM, distance);
   return distance;
 }
 
 double
 nsDOMCameraControl::GetFocusDistanceFar(ErrorResult& aRv)
 {
-  MOZ_ASSERT(mCameraControl);
+  THROW_IF_NO_CAMERACONTROL(0.0);
 
   double distance;
   aRv = mCameraControl->Get(CAMERA_PARAM_FOCUSDISTANCEFAR, distance);
   return distance;
 }
 
 void
 nsDOMCameraControl::SetExposureCompensation(double aCompensation, ErrorResult& aRv)
 {
-  MOZ_ASSERT(mCameraControl);
+  THROW_IF_NO_CAMERACONTROL();
   aRv = mCameraControl->Set(CAMERA_PARAM_EXPOSURECOMPENSATION, aCompensation);
 }
 
 double
 nsDOMCameraControl::GetExposureCompensation(ErrorResult& aRv)
 {
-  MOZ_ASSERT(mCameraControl);
+  THROW_IF_NO_CAMERACONTROL(0.0);
 
   double compensation;
   aRv = mCameraControl->Get(CAMERA_PARAM_EXPOSURECOMPENSATION, compensation);
   return compensation;
 }
 
 int32_t
 nsDOMCameraControl::SensorAngle()
 {
-  MOZ_ASSERT(mCameraControl);
-
   int32_t angle = 0;
-  mCameraControl->Get(CAMERA_PARAM_SENSORANGLE, angle);
+  if (mCameraControl) {
+    mCameraControl->Get(CAMERA_PARAM_SENSORANGLE, angle);
+  }
   return angle;
 }
 
 already_AddRefed<dom::CameraCapabilities>
 nsDOMCameraControl::Capabilities()
 {
+  if (!mCameraControl) {
+    DOM_CAMERA_LOGW("mCameraControl is null at %s:%d\n", __func__, __LINE__);
+    return nullptr;
+  }
+
   nsRefPtr<CameraCapabilities> caps = mCapabilities;
-
   if (!caps) {
     caps = new CameraCapabilities(mWindow, mCameraControl);
     mCapabilities = caps;
   }
 
   return caps.forget();
 }
 
 // Methods.
 already_AddRefed<Promise>
 nsDOMCameraControl::StartRecording(const CameraStartRecordingOptions& aOptions,
                                    nsDOMDeviceStorage& aStorageArea,
                                    const nsAString& aFilename,
                                    ErrorResult& aRv)
 {
-  MOZ_ASSERT(mCameraControl);
+  DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this);
 
   nsRefPtr<Promise> promise = CreatePromise(aRv);
   if (aRv.Failed()) {
     return nullptr;
   }
 
   if (mStartRecordingPromise) {
     promise->MaybeReject(NS_ERROR_IN_PROGRESS);
@@ -689,17 +726,19 @@ nsDOMCameraControl::StartRecording(const
   return promise.forget();
 }
 
 void
 nsDOMCameraControl::OnCreatedFileDescriptor(bool aSucceeded)
 {
   nsresult rv = NS_ERROR_FAILURE;
 
-  if (aSucceeded && mDSFileDescriptor->mFileDescriptor.IsValid()) {
+  if (!mCameraControl) {
+    rv = NS_ERROR_NOT_AVAILABLE;
+  } else if (aSucceeded && mDSFileDescriptor->mFileDescriptor.IsValid()) {
     ICameraControl::StartRecordingOptions o;
 
     o.rotation = mOptions.mRotation;
     o.maxFileSizeBytes = mOptions.mMaxFileSizeBytes;
     o.maxVideoLengthMs = mOptions.mMaxVideoLengthMs;
     o.autoEnableLowLightTorch = mOptions.mAutoEnableLowLightTorch;
     rv = mCameraControl->StartRecording(mDSFileDescriptor.get(), &o);
     if (NS_SUCCEEDED(rv)) {
@@ -717,40 +756,43 @@ nsDOMCameraControl::OnCreatedFileDescrip
       new CloseFileRunnable(mDSFileDescriptor->mFileDescriptor);
     closer->Dispatch();
   }
 }
 
 void
 nsDOMCameraControl::StopRecording(ErrorResult& aRv)
 {
-  MOZ_ASSERT(mCameraControl);
+  DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this);
+  THROW_IF_NO_CAMERACONTROL();
 
 #ifdef MOZ_B2G
   if (mAudioChannelAgent) {
     mAudioChannelAgent->StopPlaying();
     mAudioChannelAgent = nullptr;
   }
 #endif
 
   aRv = mCameraControl->StopRecording();
 }
 
 void
 nsDOMCameraControl::ResumePreview(ErrorResult& aRv)
 {
-  MOZ_ASSERT(mCameraControl);
+  DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this);
+  THROW_IF_NO_CAMERACONTROL();
   aRv = mCameraControl->StartPreview();
 }
 
 already_AddRefed<Promise>
 nsDOMCameraControl::SetConfiguration(const CameraConfiguration& aConfiguration,
                                      ErrorResult& aRv)
 {
-  MOZ_ASSERT(mCameraControl);
+  DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this);
+  THROW_IF_NO_CAMERACONTROL(nullptr);
 
   nsRefPtr<Promise> promise = CreatePromise(aRv);
   if (aRv.Failed()) {
     return nullptr;
   }
 
   if (mTakePicturePromise) {
     // We're busy taking a picture, can't change modes right now.
@@ -774,17 +816,18 @@ nsDOMCameraControl::SetConfiguration(con
 
   mSetConfigurationPromise = promise;
   return promise.forget();
 }
 
 already_AddRefed<Promise>
 nsDOMCameraControl::AutoFocus(ErrorResult& aRv)
 {
-  MOZ_ASSERT(mCameraControl);
+  DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this);
+  THROW_IF_NO_CAMERACONTROL(nullptr);
 
   nsRefPtr<Promise> promise = mAutoFocusPromise.forget();
   if (promise) {
     // There is already a call to AutoFocus() in progress, cancel it and
     // invoke the error callback (if one was passed in).
     promise->MaybeReject(NS_ERROR_IN_PROGRESS);
   }
 
@@ -802,32 +845,35 @@ nsDOMCameraControl::AutoFocus(ErrorResul
 
   mAutoFocusPromise = promise;
   return promise.forget();
 }
 
 void
 nsDOMCameraControl::StartFaceDetection(ErrorResult& aRv)
 {
-  MOZ_ASSERT(mCameraControl);
+  DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this);
+  THROW_IF_NO_CAMERACONTROL();
   aRv = mCameraControl->StartFaceDetection();
 }
 
 void
 nsDOMCameraControl::StopFaceDetection(ErrorResult& aRv)
 {
-  MOZ_ASSERT(mCameraControl);
+  DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this);
+  THROW_IF_NO_CAMERACONTROL();
   aRv = mCameraControl->StopFaceDetection();
 }
 
 already_AddRefed<Promise>
 nsDOMCameraControl::TakePicture(const CameraPictureOptions& aOptions,
                                 ErrorResult& aRv)
 {
-  MOZ_ASSERT(mCameraControl);
+  DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this);
+  THROW_IF_NO_CAMERACONTROL(nullptr);
 
   nsRefPtr<Promise> promise = CreatePromise(aRv);
   if (aRv.Failed()) {
     return nullptr;
   }
 
   if (mTakePicturePromise) {
     // There is already a call to TakePicture() in progress, abort this new
@@ -866,56 +912,70 @@ nsDOMCameraControl::TakePicture(const Ca
 
   mTakePicturePromise = promise;
   return promise.forget();
 }
 
 already_AddRefed<Promise>
 nsDOMCameraControl::ReleaseHardware(ErrorResult& aRv)
 {
-  MOZ_ASSERT(mCameraControl);
+  DOM_CAMERA_LOGI("%s:%d : this=%p\n", __func__, __LINE__, this);
 
   nsRefPtr<Promise> promise = CreatePromise(aRv);
   if (aRv.Failed()) {
     return nullptr;
   }
 
+  if (!mCameraControl) {
+    // Always succeed if the camera instance is already closed.
+    promise->MaybeResolve(JS::UndefinedHandleValue);
+    return promise.forget();
+  }
+
   aRv = mCameraControl->Stop();
   if (aRv.Failed()) {
     return nullptr;
   }
 
+  // Once we stop the camera, there's nothing we can do with it,
+  // so we can throw away this reference. (This won't prevent us
+  // from receiving the last underlying events.)
+  mCameraControl = nullptr;
   mReleasePromise = promise;
+
   return promise.forget();
 }
 
 void
 nsDOMCameraControl::ResumeContinuousFocus(ErrorResult& aRv)
 {
-  MOZ_ASSERT(mCameraControl);
+  DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this);
+  THROW_IF_NO_CAMERACONTROL();
   aRv = mCameraControl->ResumeContinuousFocus();
 }
 
 void
 nsDOMCameraControl::Shutdown()
 {
-  DOM_CAMERA_LOGI("%s:%d\n", __func__, __LINE__);
-  MOZ_ASSERT(mCameraControl);
+  DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this);
 
   // Remove any pending solicited event handlers; these
   // reference our window object, which in turn references
   // us. If we don't remove them, we can leak DOM objects.
   AbortPromise(mGetCameraPromise);
   AbortPromise(mAutoFocusPromise);
   AbortPromise(mTakePicturePromise);
   AbortPromise(mStartRecordingPromise);
   AbortPromise(mReleasePromise);
   AbortPromise(mSetConfigurationPromise);
 
-  mCameraControl->Shutdown();
+  if (mCameraControl) {
+    mCameraControl->Stop();
+    mCameraControl = nullptr;
+  }
 }
 
 nsresult
 nsDOMCameraControl::NotifyRecordingStatusChange(const nsString& aMsg)
 {
   NS_ENSURE_TRUE(mWindow, NS_ERROR_FAILURE);
 
   return MediaManager::NotifyRecordingStatusChange(mWindow,
@@ -981,17 +1041,19 @@ nsDOMCameraControl::DispatchStateEvent(c
   DispatchTrustedEvent(event);
 }
 
 // Camera Control event handlers--must only be called from the Main Thread!
 void
 nsDOMCameraControl::OnHardwareStateChange(CameraControlListener::HardwareState aState,
                                           nsresult aReason)
 {
+  DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this);
   MOZ_ASSERT(NS_IsMainThread());
+
   ErrorResult ignored;
 
   switch (aState) {
     case CameraControlListener::kHardwareOpen:
       DOM_CAMERA_LOGI("DOM OnHardwareStateChange: open\n");
       MOZ_ASSERT(aReason == NS_OK);
       {
         // The hardware is open, so we can return a camera to JS, even if
@@ -1053,25 +1115,25 @@ nsDOMCameraControl::OnHardwareStateChang
       DOM_CAMERA_LOGE("DOM OnHardwareStateChange: UNKNOWN=%d\n", aState);
       MOZ_ASSERT_UNREACHABLE("Unanticipated camera hardware state");
   }
 }
 
 void
 nsDOMCameraControl::OnShutter()
 {
+  DOM_CAMERA_LOGI("DOM ** SNAP **\n");
   MOZ_ASSERT(NS_IsMainThread());
-
-  DOM_CAMERA_LOGI("DOM ** SNAP **\n");
   DispatchTrustedEvent(NS_LITERAL_STRING("shutter"));
 }
 
 void
 nsDOMCameraControl::OnPreviewStateChange(CameraControlListener::PreviewState aState)
 {
+  DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this);
   MOZ_ASSERT(NS_IsMainThread());
 
   mPreviewState = aState;
   nsString state;
   switch (aState) {
     case CameraControlListener::kPreviewStarted:
       state = NS_LITERAL_STRING("started");
       break;
@@ -1084,16 +1146,17 @@ nsDOMCameraControl::OnPreviewStateChange
   DispatchPreviewStateEvent(aState);
 }
 
 void
 nsDOMCameraControl::OnRecorderStateChange(CameraControlListener::RecorderState aState,
                                           int32_t aArg, int32_t aTrackNum)
 {
   // For now, we do nothing with 'aStatus' and 'aTrackNum'.
+  DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this);
   MOZ_ASSERT(NS_IsMainThread());
 
   ErrorResult ignored;
   nsString state;
 
   switch (aState) {
     case CameraControlListener::kRecorderStarted:
       {
@@ -1143,16 +1206,17 @@ nsDOMCameraControl::OnRecorderStateChang
   }
 
   DispatchStateEvent(NS_LITERAL_STRING("recorderstatechange"), state);
 }
 
 void
 nsDOMCameraControl::OnConfigurationChange(DOMCameraConfiguration* aConfiguration)
 {
+  DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this);
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(aConfiguration != nullptr);
 
   // Update our record of the current camera configuration
   mCurrentConfiguration = aConfiguration;
 
   DOM_CAMERA_LOGI("DOM OnConfigurationChange: this=%p\n", this);
   DOM_CAMERA_LOGI("    mode                   : %s\n",
@@ -1169,31 +1233,32 @@ nsDOMCameraControl::OnConfigurationChang
   nsRefPtr<Promise> promise = mSetConfigurationPromise.forget();
   if (promise) {
     promise->MaybeResolve(*aConfiguration);
   }
 
   CameraConfigurationEventInit eventInit;
   eventInit.mMode = mCurrentConfiguration->mMode;
   eventInit.mRecorderProfile = mCurrentConfiguration->mRecorderProfile;
-  eventInit.mPreviewSize = new DOMRect(this, 0, 0,
+  eventInit.mPreviewSize = new DOMRect(static_cast<DOMMediaStream*>(this), 0, 0,
                                        mCurrentConfiguration->mPreviewSize.mWidth,
                                        mCurrentConfiguration->mPreviewSize.mHeight);
 
   nsRefPtr<CameraConfigurationEvent> event =
     CameraConfigurationEvent::Constructor(this,
                                           NS_LITERAL_STRING("configurationchanged"),
                                           eventInit);
 
   DispatchTrustedEvent(event);
 }
 
 void
 nsDOMCameraControl::OnAutoFocusComplete(bool aAutoFocusSucceeded)
 {
+  DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this);
   MOZ_ASSERT(NS_IsMainThread());
 
   nsRefPtr<Promise> promise = mAutoFocusPromise.forget();
   if (promise) {
     promise->MaybeResolve(aAutoFocusSucceeded);
   }
 
   if (aAutoFocusSucceeded) {
@@ -1201,16 +1266,17 @@ nsDOMCameraControl::OnAutoFocusComplete(
   } else {
     DispatchStateEvent(NS_LITERAL_STRING("focus"), NS_LITERAL_STRING("unfocused"));
   }
 }
 
 void
 nsDOMCameraControl::OnAutoFocusMoving(bool aIsMoving)
 {
+  DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this);
   MOZ_ASSERT(NS_IsMainThread());
 
   if (aIsMoving) {
     DispatchStateEvent(NS_LITERAL_STRING("focus"), NS_LITERAL_STRING("focusing"));
   }
 }
 
 void
@@ -1220,17 +1286,17 @@ nsDOMCameraControl::OnFacesDetected(cons
   MOZ_ASSERT(NS_IsMainThread());
 
   Sequence<OwningNonNull<DOMCameraDetectedFace> > faces;
   uint32_t len = aFaces.Length();
 
   if (faces.SetCapacity(len)) {
     nsRefPtr<DOMCameraDetectedFace> f;
     for (uint32_t i = 0; i < len; ++i) {
-      f = new DOMCameraDetectedFace(this, aFaces[i]);
+      f = new DOMCameraDetectedFace(static_cast<DOMMediaStream*>(this), aFaces[i]);
       *faces.AppendElement() = f.forget().take();
     }
   }
 
   CameraFacesDetectedEventInit eventInit;
   eventInit.mFaces.SetValue(faces);
 
   nsRefPtr<CameraFacesDetectedEvent> event =
@@ -1239,16 +1305,17 @@ nsDOMCameraControl::OnFacesDetected(cons
                                           eventInit);
 
   DispatchTrustedEvent(event);
 }
 
 void
 nsDOMCameraControl::OnTakePictureComplete(nsIDOMBlob* aPicture)
 {
+  DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this);
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(aPicture);
 
   nsRefPtr<Promise> promise = mTakePicturePromise.forget();
   if (promise) {
     nsCOMPtr<nsIDOMBlob> picture = aPicture;
     promise->MaybeResolve(picture);
   }
@@ -1262,17 +1329,18 @@ nsDOMCameraControl::OnTakePictureComplet
                                                      eventInit);
 
   DispatchTrustedEvent(event);
 }
 
 void
 nsDOMCameraControl::OnUserError(CameraControlListener::UserContext aContext, nsresult aError)
 {
-  DOM_CAMERA_LOGI("DOM OnUserError aContext=%u, aError=0x%x\n", aContext, aError);
+  DOM_CAMERA_LOGI("DOM OnUserError : this=%paContext=%u, aError=0x%x\n",
+    this, aContext, aError);
   MOZ_ASSERT(NS_IsMainThread());
 
   nsRefPtr<Promise> promise;
 
   switch (aContext) {
     case CameraControlListener::kInStartCamera:
       promise = mGetCameraPromise.forget();
       break;
--- a/dom/camera/DOMCameraControl.h
+++ b/dom/camera/DOMCameraControl.h
@@ -13,16 +13,17 @@
 #include "ICameraControl.h"
 #include "CameraCommon.h"
 #include "DOMMediaStream.h"
 #include "AudioChannelAgent.h"
 #include "nsProxyRelease.h"
 #include "nsHashPropertyBag.h"
 #include "DeviceStorage.h"
 #include "DOMCameraControlListener.h"
+#include "nsWeakReference.h"
 #ifdef MOZ_WIDGET_GONK
 #include "nsITimer.h"
 #endif
 
 class nsDOMDeviceStorage;
 class nsPIDOMWindow;
 class nsIDOMBlob;
 
@@ -34,20 +35,27 @@ namespace dom {
   struct CameraStartRecordingOptions;
   struct CameraRegion;
   struct CameraSize;
   template<typename T> class Optional;
 }
 class ErrorResult;
 class StartRecordingHelper;
 
+#define NS_DOM_CAMERA_CONTROL_CID \
+{ 0x3700c096, 0xf920, 0x438d, \
+  { 0x8b, 0x3f, 0x15, 0xb3, 0xc9, 0x96, 0x23, 0x62 } }
+
 // Main camera control.
 class nsDOMCameraControl MOZ_FINAL : public DOMMediaStream
+                                   , public nsSupportsWeakReference
 {
 public:
+  NS_DECLARE_STATIC_IID_ACCESSOR(NS_DOM_CAMERA_CONTROL_CID)
+
   NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(nsDOMCameraControl, DOMMediaStream)
   NS_DECL_ISUPPORTS_INHERITED
 
   // Because this header's filename doesn't match its C++ or DOM-facing
   // classname, we can't rely on the [Func="..."] WebIDL tag to implicitly
   // include the right header for us; instead we must explicitly include a
   // HasSupport() method in each header. We can get rid of these with the
   // Great Renaming proposed in bug 983177.
@@ -82,16 +90,18 @@ public:
   void SetExposureCompensation(double aCompensation, ErrorResult& aRv);
   double GetExposureCompensation(ErrorResult& aRv);
   int32_t SensorAngle();
   already_AddRefed<dom::CameraCapabilities> Capabilities();
   void GetIsoMode(nsString& aMode, ErrorResult& aRv);
   void SetIsoMode(const nsAString& aMode, ErrorResult& aRv);
   double GetPictureQuality(ErrorResult& aRv);
   void SetPictureQuality(double aQuality, ErrorResult& aRv);
+  void GetMeteringMode(nsString& aMode, ErrorResult& aRv);
+  void SetMeteringMode(const nsAString& aMode, ErrorResult& aRv);
 
   // Methods.
   already_AddRefed<dom::Promise> SetConfiguration(const dom::CameraConfiguration& aConfiguration,
                                                   ErrorResult& aRv);
   void GetMeteringAreas(nsTArray<dom::CameraRegion>& aAreas, ErrorResult& aRv);
   void SetMeteringAreas(const dom::Optional<dom::Sequence<dom::CameraRegion> >& aAreas, ErrorResult& aRv);
   void GetFocusAreas(nsTArray<dom::CameraRegion>& aAreas, ErrorResult& aRv);
   void SetFocusAreas(const dom::Optional<dom::Sequence<dom::CameraRegion> >& aAreas, ErrorResult& aRv);
@@ -110,16 +120,18 @@ public:
                                                 ErrorResult& aRv);
   void StopRecording(ErrorResult& aRv);
   void ResumePreview(ErrorResult& aRv);
   already_AddRefed<dom::Promise> ReleaseHardware(ErrorResult& aRv);
   void ResumeContinuousFocus(ErrorResult& aRv);
 
   virtual JSObject* WrapObject(JSContext* aCx) MOZ_OVERRIDE;
 
+  operator nsISupports*() { return static_cast<DOMMediaStream*>(this); }
+
 #ifdef MOZ_WIDGET_GONK
   static void PreinitCameraHardware();
   static void DiscardCachedCameraInstance(nsITimer* aTimer, void* aClosure);
 #endif
 
   IMPL_EVENT_HANDLER(facesdetected)
   IMPL_EVENT_HANDLER(shutter)
   IMPL_EVENT_HANDLER(close)
@@ -217,11 +229,13 @@ protected:
   static nsCOMPtr<nsITimer> sDiscardCachedCameraControlTimer;
 #endif
 
 private:
   nsDOMCameraControl(const nsDOMCameraControl&) MOZ_DELETE;
   nsDOMCameraControl& operator=(const nsDOMCameraControl&) MOZ_DELETE;
 };
 
+NS_DEFINE_STATIC_IID_ACCESSOR(nsDOMCameraControl, NS_DOM_CAMERA_CONTROL_CID)
+
 } // namespace mozilla
 
 #endif // DOM_CAMERA_DOMCAMERACONTROL_H
--- a/dom/camera/DOMCameraControlListener.cpp
+++ b/dom/camera/DOMCameraControlListener.cpp
@@ -10,33 +10,34 @@
 #include "mozilla/dom/CameraManagerBinding.h"
 #include "mozilla/dom/File.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
 
 DOMCameraControlListener::DOMCameraControlListener(nsDOMCameraControl* aDOMCameraControl,
                                                    CameraPreviewMediaStream* aStream)
-  : mDOMCameraControl(new nsMainThreadPtrHolder<nsDOMCameraControl>(aDOMCameraControl))
+  : mDOMCameraControl(
+      new nsMainThreadPtrHolder<nsISupports>(static_cast<DOMMediaStream*>(aDOMCameraControl)))
   , mStream(aStream)
 {
   DOM_CAMERA_LOGT("%s:%d : this=%p, camera=%p, stream=%p\n",
     __func__, __LINE__, this, aDOMCameraControl, aStream);
 }
 
 DOMCameraControlListener::~DOMCameraControlListener()
 {
   DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this);
 }
 
 // Boilerplate callback runnable
 class DOMCameraControlListener::DOMCallback : public nsRunnable
 {
 public:
-  explicit DOMCallback(nsMainThreadPtrHandle<nsDOMCameraControl> aDOMCameraControl)
+  explicit DOMCallback(nsMainThreadPtrHandle<nsISupports> aDOMCameraControl)
     : mDOMCameraControl(aDOMCameraControl)
   {
     MOZ_COUNT_CTOR(DOMCameraControlListener::DOMCallback);
   }
 
 protected:
   virtual ~DOMCallback()
   {
@@ -46,36 +47,38 @@ protected:
 public:
   virtual void RunCallback(nsDOMCameraControl* aDOMCameraControl) = 0;
 
   NS_IMETHOD
   Run() MOZ_OVERRIDE
   {
     MOZ_ASSERT(NS_IsMainThread());
 
-    nsRefPtr<nsDOMCameraControl> camera = mDOMCameraControl.get();
-    if (camera) {
-      RunCallback(camera);
+    nsRefPtr<nsDOMCameraControl> camera = do_QueryObject(mDOMCameraControl.get());
+    if (!camera) {
+      DOM_CAMERA_LOGE("do_QueryObject failed to get an nsDOMCameraControl\n");
+      return NS_ERROR_INVALID_ARG;
     }
+    RunCallback(camera);
     return NS_OK;
   }
 
 protected:
-  nsMainThreadPtrHandle<nsDOMCameraControl> mDOMCameraControl;
+  nsMainThreadPtrHandle<nsISupports> mDOMCameraControl;
 };
 
 // Specific callback handlers
 void
 DOMCameraControlListener::OnHardwareStateChange(HardwareState aState,
                                                 nsresult aReason)
 {
   class Callback : public DOMCallback
   {
   public:
-    Callback(nsMainThreadPtrHandle<nsDOMCameraControl> aDOMCameraControl,
+    Callback(nsMainThreadPtrHandle<nsISupports> aDOMCameraControl,
              HardwareState aState, nsresult aReason)
       : DOMCallback(aDOMCameraControl)
       , mState(aState)
       , mReason(aReason)
     { }
 
     void
     RunCallback(nsDOMCameraControl* aDOMCameraControl) MOZ_OVERRIDE
@@ -92,17 +95,17 @@ DOMCameraControlListener::OnHardwareStat
 }
 
 void
 DOMCameraControlListener::OnPreviewStateChange(PreviewState aState)
 {
   class Callback : public DOMCallback
   {
   public:
-    Callback(nsMainThreadPtrHandle<nsDOMCameraControl> aDOMCameraControl,
+    Callback(nsMainThreadPtrHandle<nsISupports> aDOMCameraControl,
              PreviewState aState)
       : DOMCallback(aDOMCameraControl)
       , mState(aState)
     { }
 
     void
     RunCallback(nsDOMCameraControl* aDOMCameraControl) MOZ_OVERRIDE
     {
@@ -146,17 +149,17 @@ DOMCameraControlListener::OnPreviewState
 
 void
 DOMCameraControlListener::OnRecorderStateChange(RecorderState aState,
                                                 int32_t aStatus, int32_t aTrackNum)
 {
   class Callback : public DOMCallback
   {
   public:
-    Callback(nsMainThreadPtrHandle<nsDOMCameraControl> aDOMCameraControl,
+    Callback(nsMainThreadPtrHandle<nsISupports> aDOMCameraControl,
              RecorderState aState,
              int32_t aStatus,
              int32_t aTrackNum)
       : DOMCallback(aDOMCameraControl)
       , mState(aState)
       , mStatus(aStatus)
       , mTrackNum(aTrackNum)
     { }
@@ -177,17 +180,17 @@ DOMCameraControlListener::OnRecorderStat
 }
 
 void
 DOMCameraControlListener::OnConfigurationChange(const CameraListenerConfiguration& aConfiguration)
 {
   class Callback : public DOMCallback
   {
   public:
-    Callback(nsMainThreadPtrHandle<nsDOMCameraControl> aDOMCameraControl,
+    Callback(nsMainThreadPtrHandle<nsISupports> aDOMCameraControl,
              const CameraListenerConfiguration& aConfiguration)
       : DOMCallback(aDOMCameraControl)
       , mConfiguration(aConfiguration)
     { }
 
     void
     RunCallback(nsDOMCameraControl* aDOMCameraControl) MOZ_OVERRIDE
     {
@@ -226,17 +229,17 @@ DOMCameraControlListener::OnConfiguratio
 }
 
 void
 DOMCameraControlListener::OnAutoFocusMoving(bool aIsMoving)
 {
   class Callback : public DOMCallback
   {
   public:
-    Callback(nsMainThreadPtrHandle<nsDOMCameraControl> aDOMCameraControl, bool aIsMoving)
+    Callback(nsMainThreadPtrHandle<nsISupports> aDOMCameraControl, bool aIsMoving)
       : DOMCallback(aDOMCameraControl)
       , mIsMoving(aIsMoving)
     { }
 
     void
     RunCallback(nsDOMCameraControl* aDOMCameraControl) MOZ_OVERRIDE
     {
       aDOMCameraControl->OnAutoFocusMoving(mIsMoving);
@@ -250,17 +253,17 @@ DOMCameraControlListener::OnAutoFocusMov
 }
 
 void
 DOMCameraControlListener::OnFacesDetected(const nsTArray<ICameraControl::Face>& aFaces)
 {
   class Callback : public DOMCallback
   {
   public:
-    Callback(nsMainThreadPtrHandle<nsDOMCameraControl> aDOMCameraControl,
+    Callback(nsMainThreadPtrHandle<nsISupports> aDOMCameraControl,
              const nsTArray<ICameraControl::Face>& aFaces)
       : DOMCallback(aDOMCameraControl)
       , mFaces(aFaces)
     { }
 
     void
     RunCallback(nsDOMCameraControl* aDOMCameraControl) MOZ_OVERRIDE
     {
@@ -275,17 +278,17 @@ DOMCameraControlListener::OnFacesDetecte
 }
 
 void
 DOMCameraControlListener::OnShutter()
 {
   class Callback : public DOMCallback
   {
   public:
-    explicit Callback(nsMainThreadPtrHandle<nsDOMCameraControl> aDOMCameraControl)
+    explicit Callback(nsMainThreadPtrHandle<nsISupports> aDOMCameraControl)
       : DOMCallback(aDOMCameraControl)
     { }
 
     void
     RunCallback(nsDOMCameraControl* aDOMCameraControl) MOZ_OVERRIDE
     {
       aDOMCameraControl->OnShutter();
     }
@@ -310,17 +313,17 @@ DOMCameraControlListener::OnNewPreviewFr
 }
 
 void
 DOMCameraControlListener::OnAutoFocusComplete(bool aAutoFocusSucceeded)
 {
   class Callback : public DOMCallback
   {
   public:
-    Callback(nsMainThreadPtrHandle<nsDOMCameraControl> aDOMCameraControl,
+    Callback(nsMainThreadPtrHandle<nsISupports> aDOMCameraControl,
              bool aAutoFocusSucceeded)
       : DOMCallback(aDOMCameraControl)
       , mAutoFocusSucceeded(aAutoFocusSucceeded)
     { }
 
     void
     RunCallback(nsDOMCameraControl* aDOMCameraControl) MOZ_OVERRIDE
     {
@@ -335,29 +338,29 @@ DOMCameraControlListener::OnAutoFocusCom
 }
 
 void
 DOMCameraControlListener::OnTakePictureComplete(uint8_t* aData, uint32_t aLength, const nsAString& aMimeType)
 {
   class Callback : public DOMCallback
   {
   public:
-    Callback(nsMainThreadPtrHandle<nsDOMCameraControl> aDOMCameraControl,
+    Callback(nsMainThreadPtrHandle<nsISupports> aDOMCameraControl,
              uint8_t* aData, uint32_t aLength, const nsAString& aMimeType)
       : DOMCallback(aDOMCameraControl)
       , mData(aData)
       , mLength(aLength)
       , mMimeType(aMimeType)
     { }
 
     void
     RunCallback(nsDOMCameraControl* aDOMCameraControl) MOZ_OVERRIDE
     {
       nsCOMPtr<nsIDOMBlob> picture =
-        File::CreateMemoryFile(mDOMCameraControl,
+        File::CreateMemoryFile(mDOMCameraControl.get(),
                                static_cast<void*>(mData),
                                static_cast<uint64_t>(mLength),
                                mMimeType);
       aDOMCameraControl->OnTakePictureComplete(picture);
     }
 
   protected:
     uint8_t* mData;
@@ -369,17 +372,17 @@ DOMCameraControlListener::OnTakePictureC
 }
 
 void
 DOMCameraControlListener::OnUserError(UserContext aContext, nsresult aError)
 {
   class Callback : public DOMCallback
   {
   public:
-    Callback(nsMainThreadPtrHandle<nsDOMCameraControl> aDOMCameraControl,
+    Callback(nsMainThreadPtrHandle<nsISupports> aDOMCameraControl,
              UserContext aContext,
              nsresult aError)
       : DOMCallback(aDOMCameraControl)
       , mContext(aContext)
       , mError(aError)
     { }
 
     virtual void
--- a/dom/camera/DOMCameraControlListener.h
+++ b/dom/camera/DOMCameraControlListener.h
@@ -30,17 +30,17 @@ public:
   virtual void OnShutter() MOZ_OVERRIDE;
   virtual void OnRateLimitPreview(bool aLimit) MOZ_OVERRIDE;
   virtual bool OnNewPreviewFrame(layers::Image* aImage, uint32_t aWidth, uint32_t aHeight) MOZ_OVERRIDE;
   virtual void OnUserError(UserContext aContext, nsresult aError) MOZ_OVERRIDE;
 
 protected:
   virtual ~DOMCameraControlListener();
 
-  nsMainThreadPtrHandle<nsDOMCameraControl> mDOMCameraControl;
+  nsMainThreadPtrHandle<nsISupports> mDOMCameraControl;
   CameraPreviewMediaStream* mStream;
 
   class DOMCallback;
 
 private:
   DOMCameraControlListener(const DOMCameraControlListener&) MOZ_DELETE;
   DOMCameraControlListener& operator=(const DOMCameraControlListener&) MOZ_DELETE;
 };
--- a/dom/camera/DOMCameraManager.cpp
+++ b/dom/camera/DOMCameraManager.cpp
@@ -337,40 +337,58 @@ nsDOMCameraManager::PermissionCancelled(
 }
 
 void
 nsDOMCameraManager::Register(nsDOMCameraControl* aDOMCameraControl)
 {
   DOM_CAMERA_LOGI(">>> Register( aDOMCameraControl = %p ) mWindowId = 0x%" PRIx64 "\n", aDOMCameraControl, mWindowId);
   MOZ_ASSERT(NS_IsMainThread());
 
-  // Put the camera control into the hash table
   CameraControls* controls = sActiveWindows->Get(mWindowId);
   if (!controls) {
-    controls = new CameraControls;
+    controls = new CameraControls();
     sActiveWindows->Put(mWindowId, controls);
   }
-  controls->AppendElement(aDOMCameraControl);
+
+  // Remove any stale CameraControl objects to limit our memory usage
+  uint32_t i = controls->Length();
+  while (i > 0) {
+    --i;
+    nsRefPtr<nsDOMCameraControl> cameraControl =
+      do_QueryObject(controls->ElementAt(i));
+    if (!cameraControl) {
+      controls->RemoveElementAt(i);
+    }
+  }
+
+  // Put the camera control into the hash table
+  nsWeakPtr cameraControl =
+    do_GetWeakReference(static_cast<DOMMediaStream*>(aDOMCameraControl));
+  controls->AppendElement(cameraControl);
 }
 
 void
 nsDOMCameraManager::Shutdown(uint64_t aWindowId)
 {
   DOM_CAMERA_LOGI(">>> Shutdown( aWindowId = 0x%" PRIx64 " )\n", aWindowId);
   MOZ_ASSERT(NS_IsMainThread());
 
   CameraControls* controls = sActiveWindows->Get(aWindowId);
   if (!controls) {
     return;
   }
 
-  uint32_t length = controls->Length();
-  for (uint32_t i = 0; i < length; i++) {
-    nsRefPtr<nsDOMCameraControl> cameraControl = controls->ElementAt(i);
-    cameraControl->Shutdown();
+  uint32_t i = controls->Length();
+  while (i > 0) {
+    --i;
+    nsRefPtr<nsDOMCameraControl> cameraControl =
+      do_QueryObject(controls->ElementAt(i));
+    if (cameraControl) {
+      cameraControl->Shutdown();
+    }
   }
   controls->Clear();
 
   sActiveWindows->Remove(aWindowId);
 }
 
 void
 nsDOMCameraManager::XpComShutdown()
--- a/dom/camera/DOMCameraManager.h
+++ b/dom/camera/DOMCameraManager.h
@@ -24,17 +24,17 @@ class nsPIDOMWindow;
 namespace mozilla {
   class ErrorResult;
   class nsDOMCameraControl;
   namespace dom {
     struct CameraConfiguration;
   }
 }
 
-typedef nsTArray<nsRefPtr<mozilla::nsDOMCameraControl> > CameraControls;
+typedef nsTArray<nsWeakPtr> CameraControls;
 typedef nsClassHashtable<nsUint64HashKey, CameraControls> WindowTable;
 
 class nsDOMCameraManager MOZ_FINAL
   : public nsIObserver
   , public nsSupportsWeakReference
   , public nsWrapperCache
 {
 public:
--- a/dom/camera/FallbackCameraControl.cpp
+++ b/dom/camera/FallbackCameraControl.cpp
@@ -17,17 +17,17 @@ namespace mozilla {
 
 /**
  * Fallback camera control subclass. Can be used as a template for the
  * definition of new camera support classes.
  */
 class FallbackCameraControl : public CameraControlImpl
 {
 public:
-  explicit FallbackCameraControl(uint32_t aCameraId) : CameraControlImpl(aCameraId) { }
+  explicit FallbackCameraControl() : CameraControlImpl() { }
 
   virtual nsresult Set(uint32_t aKey, const nsAString& aValue) MOZ_OVERRIDE { return NS_ERROR_NOT_IMPLEMENTED; }
   virtual nsresult Get(uint32_t aKey, nsAString& aValue) MOZ_OVERRIDE { return NS_ERROR_NOT_IMPLEMENTED; }
   virtual nsresult Set(uint32_t aKey, double aValue) MOZ_OVERRIDE { return NS_ERROR_NOT_IMPLEMENTED; }
   virtual nsresult Get(uint32_t aKey, double& aValue) MOZ_OVERRIDE { return NS_ERROR_NOT_IMPLEMENTED; }
   virtual nsresult Set(uint32_t aKey, int32_t aValue) MOZ_OVERRIDE { return NS_ERROR_NOT_IMPLEMENTED; }
   virtual nsresult Get(uint32_t aKey, int32_t& aValue) MOZ_OVERRIDE { return NS_ERROR_NOT_IMPLEMENTED; }
   virtual nsresult Set(uint32_t aKey, int64_t aValue) MOZ_OVERRIDE { return NS_ERROR_NOT_IMPLEMENTED; }
--- a/dom/camera/GonkCameraControl.cpp
+++ b/dom/camera/GonkCameraControl.cpp
@@ -56,17 +56,17 @@ using namespace android;
       NS_WARNING("Camera hardware is not initialized");                   \
       DOM_CAMERA_LOGE("%s:%d : mCameraHw is null\n", __func__, __LINE__); \
       return NS_ERROR_NOT_INITIALIZED;                                    \
     }                                                                     \
   } while(0)
 
 // Construct nsGonkCameraControl on the main thread.
 nsGonkCameraControl::nsGonkCameraControl(uint32_t aCameraId)
-  : CameraControlImpl(aCameraId)
+  : mCameraId(aCameraId)
   , mLastPictureSize({0, 0})
   , mLastThumbnailSize({0, 0})
   , mPreviewFps(30)
   , mResumePreviewAfterTakingPicture(false) // XXXmikeh - see bug 950102
   , mFlashSupported(false)
   , mLuminanceSupported(false)
   , mAutoFlashModeOverridden(false)
   , mSeparateVideoAndPreviewSizesSupported(false)
@@ -221,16 +221,40 @@ nsGonkCameraControl::Initialize()
     DOM_CAMERA_LOGI(" - support for separate preview and video sizes\n");
     mParams.Get(CAMERA_PARAM_VIDEOSIZE, mLastRecorderSize);
     DOM_CAMERA_LOGI(" - default video recorder size:   %u x %u\n",
       mLastRecorderSize.width, mLastRecorderSize.height);
   } else {
     mLastRecorderSize = mCurrentConfiguration.mPreviewSize;
   }
 
+  nsAutoTArray<nsString, 8> modes;
+  mParams.Get(CAMERA_PARAM_SUPPORTED_METERINGMODES, modes);
+  if (!modes.IsEmpty()) {
+    nsString mode;
+    const char* kCenterWeighted = "center-weighted";
+
+    mParams.Get(CAMERA_PARAM_METERINGMODE, mode);
+    if (!mode.EqualsASCII(kCenterWeighted)) {
+      nsTArray<nsString>::index_type i = modes.Length();
+      while (i > 0) {
+        --i;
+        if (modes[i].EqualsASCII(kCenterWeighted)) {
+          mParams.Set(CAMERA_PARAM_METERINGMODE, kCenterWeighted);
+          PushParametersImpl();
+          break;
+        }
+      }
+    }
+
+    mParams.Get(CAMERA_PARAM_METERINGMODE, mode);
+    DOM_CAMERA_LOGI(" - metering mode:                 '%s'\n",
+      NS_ConvertUTF16toUTF8(mode).get());
+  }
+      
   return NS_OK;
 }
 
 nsGonkCameraControl::~nsGonkCameraControl()
 {
   DOM_CAMERA_LOGT("%s:%d : this=%p, mCameraHw = %p\n", __func__, __LINE__, this, mCameraHw.get());
 
   StopImpl();
--- a/dom/camera/GonkCameraControl.h
+++ b/dom/camera/GonkCameraControl.h
@@ -149,16 +149,18 @@ protected:
   nsresult SetPictureSize(const Size& aSize);
   nsresult SetPictureSizeImpl(const Size& aSize);
   nsresult SetThumbnailSize(const Size& aSize);
   nsresult UpdateThumbnailSize();
   nsresult SetThumbnailSizeImpl(const Size& aSize);
 
   int32_t RationalizeRotation(int32_t aRotation);
 
+  uint32_t                  mCameraId;
+
   android::sp<android::GonkCameraHardware> mCameraHw;
 
   Size                      mLastPictureSize;
   Size                      mLastThumbnailSize;
   Size                      mLastRecorderSize;
   uint32_t                  mPreviewFps;
   bool                      mResumePreviewAfterTakingPicture;
   bool                      mFlashSupported;
--- a/dom/camera/GonkCameraParameters.cpp
+++ b/dom/camera/GonkCameraParameters.cpp
@@ -15,16 +15,17 @@
  */
 
 #include "GonkCameraParameters.h"
 #include "camera/CameraParameters.h"
 #include "CameraPreferences.h"
 #include "ICameraControl.h"
 #include "CameraCommon.h"
 #include "mozilla/Hal.h"
+#include "nsDataHashtable.h"
 
 using namespace mozilla;
 using namespace android;
 
 /* static */ bool
 GonkCameraParameters::IsLowMemoryPlatform()
 {
   bool testIsLowMem = false;
@@ -114,16 +115,19 @@ GonkCameraParameters::Parameters::GetTex
       // for those that don't, we use the raw string key.
       return "hdr-need-1x";
     case CAMERA_PARAM_RECORDINGHINT:
       return KEY_RECORDING_HINT;
     case CAMERA_PARAM_PICTURE_QUALITY:
       return KEY_JPEG_QUALITY;
     case CAMERA_PARAM_PREFERRED_PREVIEWSIZE_FOR_VIDEO:
       return KEY_PREFERRED_PREVIEW_SIZE_FOR_VIDEO;
+    case CAMERA_PARAM_METERINGMODE:
+      // Not every platform defines KEY_AUTO_EXPOSURE.
+      return "auto-exposure";
 
     case CAMERA_PARAM_SUPPORTED_PREVIEWSIZES:
       return KEY_SUPPORTED_PREVIEW_SIZES;
     case CAMERA_PARAM_SUPPORTED_PICTURESIZES:
       return KEY_SUPPORTED_PICTURE_SIZES;
     case CAMERA_PARAM_SUPPORTED_VIDEOSIZES:
       return KEY_SUPPORTED_VIDEO_SIZES;
     case CAMERA_PARAM_SUPPORTED_PICTUREFORMATS:
@@ -155,16 +159,19 @@ GonkCameraParameters::Parameters::GetTex
     case CAMERA_PARAM_SUPPORTED_MAXDETECTEDFACES:
       return KEY_MAX_NUM_DETECTED_FACES_HW;
     case CAMERA_PARAM_SUPPORTED_JPEG_THUMBNAIL_SIZES:
       return KEY_SUPPORTED_JPEG_THUMBNAIL_SIZES;
     case CAMERA_PARAM_SUPPORTED_ISOMODES:
       // Not every platform defines KEY_SUPPORTED_ISO_MODES;
       // for those that don't, we use the raw string key.
       return "iso-values";
+    case CAMERA_PARAM_SUPPORTED_METERINGMODES:
+      // Not every platform defines KEY_SUPPORTED_AUTO_EXPOSURE.
+      return "auto-exposure-values";
     default:
       DOM_CAMERA_LOGE("Unhandled camera parameter value %u\n", aKey);
       return nullptr;
   }
 }
 
 GonkCameraParameters::GonkCameraParameters()
   : mLock(PR_NewRWLock(PR_RWLOCK_RANK_NONE, "GonkCameraParameters.Lock"))
@@ -273,17 +280,17 @@ GonkCameraParameters::Initialize()
   }
 
   // The return code from GetListAsArray() doesn't matter. If it fails,
   // the isoModes array will be empty, and the subsequent loop won't
   // execute.
   nsString s;
   nsTArray<nsCString> isoModes;
   GetListAsArray(CAMERA_PARAM_SUPPORTED_ISOMODES, isoModes);
-  for (nsTArray<nsCString>::size_type i = 0; i < isoModes.Length(); ++i) {
+  for (nsTArray<nsCString>::index_type i = 0; i < isoModes.Length(); ++i) {
     rv = MapIsoFromGonk(isoModes[i].get(), s);
     if (NS_FAILED(rv)) {
       DOM_CAMERA_LOGW("Unrecognized ISO mode value '%s'\n", isoModes[i].get());
       continue;
     }
     *mIsoModes.AppendElement() = s;
     mIsoModeMap.Put(s, new nsCString(isoModes[i]));
   }
@@ -294,16 +301,32 @@ GonkCameraParameters::Initialize()
     while (mSceneModes.RemoveElement(NS_LITERAL_STRING("hdr"))) {
       hdrRemoved = true;
     }
     if (hdrRemoved) {
       DOM_CAMERA_LOGI("Disabling HDR support due to low memory\n");
     }
   }
 
+  // Some platforms have strange duplicate metering mode values.
+  // We filter any out here.
+  nsDataHashtable<nsStringHashKey, bool> uniqueModes;
+  GetListAsArray(CAMERA_PARAM_SUPPORTED_METERINGMODES, mMeteringModes);
+  nsTArray<nsCString>::index_type i = mMeteringModes.Length();
+  while (i > 0) {
+    --i;
+    if (!uniqueModes.Get(mMeteringModes[i])) {
+      uniqueModes.Put(mMeteringModes[i], true);
+    } else {
+      DOM_CAMERA_LOGW("Dropped duplicate metering mode '%s' (index=%u)\n",
+        NS_ConvertUTF16toUTF8(mMeteringModes[i]).get(), i);
+      mMeteringModes.RemoveElementAt(i);
+    }
+  }
+  
   mInitialized = true;
   return NS_OK;
 }
 
 // Handle nsAStrings
 nsresult
 GonkCameraParameters::SetTranslated(uint32_t aKey, const nsAString& aValue)
 {
@@ -931,16 +954,20 @@ GonkCameraParameters::GetTranslated(uint
     case CAMERA_PARAM_SUPPORTED_ISOMODES:
       aValues = mIsoModes;
       return NS_OK;
 
     case CAMERA_PARAM_SUPPORTED_SCENEMODES:
       aValues = mSceneModes;
       return NS_OK;
 
+    case CAMERA_PARAM_SUPPORTED_METERINGMODES:
+      aValues = mMeteringModes;
+      return NS_OK;
+
     default:
       return GetListAsArray(aKey, aValues);
   }
 }
 
 nsresult
 GonkCameraParameters::GetTranslated(uint32_t aKey, nsTArray<double>& aValues)
 {
--- a/dom/camera/GonkCameraParameters.h
+++ b/dom/camera/GonkCameraParameters.h
@@ -97,16 +97,17 @@ protected:
 
   // Required internal properties
   double mExposureCompensationStep;
   int32_t mExposureCompensationMinIndex;
   int32_t mExposureCompensationMaxIndex;
   nsTArray<int> mZoomRatios;
   nsTArray<nsString> mIsoModes;
   nsTArray<nsString> mSceneModes;
+  nsTArray<nsString> mMeteringModes;
   nsClassHashtable<nsStringHashKey, nsCString> mIsoModeMap;
 
   // This subclass of android::CameraParameters just gives
   // all of the AOSP getters and setters the same signature.
   class Parameters : public android::CameraParameters
   {
   public:
     using android::CameraParameters::set;
--- a/dom/camera/ICameraControl.h
+++ b/dom/camera/ICameraControl.h
@@ -50,16 +50,17 @@ enum {
   CAMERA_PARAM_THUMBNAILSIZE,
   CAMERA_PARAM_THUMBNAILQUALITY,
   CAMERA_PARAM_SENSORANGLE,
   CAMERA_PARAM_ISOMODE,
   CAMERA_PARAM_LUMINANCE,
   CAMERA_PARAM_SCENEMODE_HDR_RETURNNORMALPICTURE,
   CAMERA_PARAM_RECORDINGHINT,
   CAMERA_PARAM_PREFERRED_PREVIEWSIZE_FOR_VIDEO,
+  CAMERA_PARAM_METERINGMODE,
 
   // supported features
   CAMERA_PARAM_SUPPORTED_PREVIEWSIZES,
   CAMERA_PARAM_SUPPORTED_PICTURESIZES,
   CAMERA_PARAM_SUPPORTED_VIDEOSIZES,
   CAMERA_PARAM_SUPPORTED_PICTUREFORMATS,
   CAMERA_PARAM_SUPPORTED_WHITEBALANCES,
   CAMERA_PARAM_SUPPORTED_SCENEMODES,
@@ -70,17 +71,18 @@ enum {
   CAMERA_PARAM_SUPPORTED_MAXMETERINGAREAS,
   CAMERA_PARAM_SUPPORTED_MINEXPOSURECOMPENSATION,
   CAMERA_PARAM_SUPPORTED_MAXEXPOSURECOMPENSATION,
   CAMERA_PARAM_SUPPORTED_EXPOSURECOMPENSATIONSTEP,
   CAMERA_PARAM_SUPPORTED_ZOOM,
   CAMERA_PARAM_SUPPORTED_ZOOMRATIOS,
   CAMERA_PARAM_SUPPORTED_MAXDETECTEDFACES,
   CAMERA_PARAM_SUPPORTED_JPEG_THUMBNAIL_SIZES,
-  CAMERA_PARAM_SUPPORTED_ISOMODES
+  CAMERA_PARAM_SUPPORTED_ISOMODES,
+  CAMERA_PARAM_SUPPORTED_METERINGMODES
 };
 
 class ICameraControl
 {
 public:
   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(ICameraControl)
 
   // Returns the number of cameras supported by the system.
@@ -246,17 +248,17 @@ public:
   //  - NS_ERROR_FAILURE if an asynchronous method could not be dispatched.
   virtual nsresult Start(const Configuration* aInitialConfig = nullptr) = 0;
   virtual nsresult Stop() = 0;
   virtual nsresult SetConfiguration(const Configuration& aConfig) = 0;
   virtual nsresult StartPreview() = 0;
   virtual nsresult StopPreview() = 0;
   virtual nsresult AutoFocus() = 0;
   virtual nsresult TakePicture() = 0;
-  virtual nsresult StartRecording(DeviceStorageFileDescriptor *aFileDescriptor,
+  virtual nsresult StartRecording(DeviceStorageFileDescriptor* aFileDescriptor,
                                   const StartRecordingOptions* aOptions = nullptr) = 0;
   virtual nsresult StopRecording() = 0;
   virtual nsresult StartFaceDetection() = 0;
   virtual nsresult StopFaceDetection() = 0;
   virtual nsresult ResumeContinuousFocus() = 0;
 
   // Camera parameter getters and setters. 'aKey' must be one of the
   // CAMERA_PARAM_* values enumerated above.
@@ -288,20 +290,16 @@ public:
 
   virtual nsresult Get(uint32_t aKey, nsTArray<Size>& aSizes) = 0;
   virtual nsresult Get(uint32_t aKey, nsTArray<nsString>& aValues) = 0;
   virtual nsresult Get(uint32_t aKey, nsTArray<double>& aValues) = 0;
 
   virtual nsresult GetRecorderProfiles(nsTArray<nsString>& aProfiles) = 0;
   virtual RecorderProfile* GetProfileInfo(const nsAString& aProfile) = 0;
 
-  virtual uint32_t GetCameraId() = 0;
-
-  virtual void Shutdown() = 0;
-
 protected:
   virtual ~ICameraControl() { }
 
   friend class ICameraControlParameterSetAutoEnter;
 
   virtual void BeginBatchParameterSet() = 0;
   virtual void EndBatchParameterSet() = 0;
 };
--- a/dom/camera/test/test_bug975472.html
+++ b/dom/camera/test/test_bug975472.html
@@ -7,16 +7,18 @@
   <script type="text/javascript" src="camera_common.js"></script>
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
 </head>
 <body>
 <video id="viewfinder" width="200" height="200" autoplay></video>
 <img src="#" alt="This image is going to load" id="testimage"/>
 <script class="testbody" type="text/javascript;version=1.7">
 
+const Cr = Components.results;
+
 var whichCamera = navigator.mozCameras.getListOfCameras()[0];
 var config = {
   mode: 'picture',
   recorderProfile: 'cif',
   previewSize: {
     width: 352,
     height: 288
   }
@@ -50,101 +52,125 @@ var tests = [
         ok(false, "release() failed with: " + error);
       }
       camera.release().then(onSuccess, onError);
     }
   },
   {
     key: "set-picture-size-after-release",
     func: function testSetPictureSize(camera) {
-      camera.setPictureSize({ width: 0, height: 0 });
-      next();
+      try {
+        camera.setPictureSize({ width: 0, height: 0 });
+      } catch(e) {
+        ok(e.result === SpecialPowers.Cr.NS_ERROR_NOT_AVAILABLE,
+          "setPictureSize() failed with: " + e.name);
+        next();
+      }
     }
   },
   {
     key: "set-thumbnail-size-after-release",
     func: function testSetThumbnailSize(camera) {
-      camera.setThumbnailSize({ width: 0, height: 0 });
-      next();
+      try {
+        camera.setThumbnailSize({ width: 0, height: 0 });
+      } catch(e) {
+        ok(e.result === SpecialPowers.Cr.NS_ERROR_NOT_AVAILABLE,
+          "setThumbnailSize() failed with: " + e.name);
+        next();
+      }
     }
   },
   {
     key: "get-sensor-angle-after-release",
     func: function testGetSensorAngle(camera) {
       ok(camera.sensorAngle == 0, "camera.sensorAngle = " + camera.sensorAngle);
       next();
     }
   },
   {
     key: "resume-preview-after-release",
     func: function testResumePreview(camera) {
-      camera.resumePreview();
-      next();
+      try {
+        camera.resumePreview();
+      } catch(e) {
+        ok(e.result === SpecialPowers.Cr.NS_ERROR_NOT_AVAILABLE,
+          "resumePreview() failed with: " + e.name);
+        next();
+      }
     }
   },
   {
     key: "auto-focus-after-release",
     func: function testAutoFocus(camera) {
       function onSuccess(success) {
         ok(false, "autoFocus() succeeded incorrectly");
       }
       function onError(error) {
-        ok(error.name === "NS_ERROR_NOT_INITIALIZED", "autoFocus() failed with: " + error);
+        ok(error.name === "NS_ERROR_NOT_AVAILABLE",
+          "autoFocus() failed with: " + error.name);
         next();
       }
       camera.autoFocus().then(onSuccess, onError);
     }
   },
   {
     key: "take-picture-after-release",
     func: function testTakePicture(camera) {
       function onSuccess(picture) {
         ok(false, "takePicture() succeeded incorrectly");
       }
       function onError(error) {
-        ok(error.name === "NS_ERROR_NOT_INITIALIZED", "takePicture() failed with: " + error);
+        ok(error.name === "NS_ERROR_NOT_AVAILABLE",
+          "takePicture() failed with: " + error.name);
         next();
       }
       camera.takePicture(null).then(onSuccess, onError);
     }
   },
   {
     key: "start-recording-after-release",
     func: function testStartRecording(camera) {
       function onSuccess(picture) {
         ok(false, "startRecording() process succeeded incorrectly");
       }
       function onError(error) {
-        ok(error.name === "NS_ERROR_FAILURE", "startRecording() failed with: " + error);
+        ok(error.name === "NS_ERROR_NOT_AVAILABLE",
+          "startRecording() failed with: " + error.name);
         next();
       }
       var recordingOptions = {
         profile: 'cif',
         rotation: 0
       };
       camera.startRecording(recordingOptions,
                             navigator.getDeviceStorage('videos'),
                             'bug975472.mp4').then(onSuccess, onError);
     }
   },
   {
     key: "stop-recording-after-release",
     func: function testStopRecording(camera) {
-      camera.stopRecording();
-      next();
+      try {
+        camera.stopRecording();
+      } catch(e) {
+        ok(e.result === SpecialPowers.Cr.NS_ERROR_NOT_AVAILABLE,
+          "stopRecording() failed with: " + e.name);
+        next();
+      }
     }
   },
   {
     key: "set-configuration-after-release",
     func: function testSetConfiguration(camera) {
       function onSuccess(picture) {
         ok(false, "setConfiguration() process succeeded incorrectly");
       }
       function onError(error) {
-        ok(error.name === "NS_ERROR_NOT_INITIALIZED", "setConfiguration() failed with: " + error);
+        ok(error.name === "NS_ERROR_NOT_AVAILABLE",
+          "setConfiguration() failed with: " + error.name);
         next();
       }
       camera.setConfiguration(config).then(onSuccess, onError);
     }
   },
 ];
 
 var testGenerator = function() {
--- a/dom/camera/test/test_camera_fake_parameters.html
+++ b/dom/camera/test/test_camera_fake_parameters.html
@@ -396,16 +396,44 @@ var tests = [
             throw e;
           }
         }
       }
 
       nextSize();
     },
   },
+  {
+    key: "bug-1052851",
+    prep: function setupFakeMetering(test) {
+      // We should reject duplicate values.
+      test.setFakeParameters(
+        "auto-exposure=frame-average;auto-exposure-values=spot,frame-average,center-weighted,spot,center-weighted",
+        function () {
+        run();
+      });
+    },
+    test: function testFakeMetering(cam, cap) {
+      ok(cap.meteringModes.length == 3, "Metering modes length = " + cap.meteringModes.length);
+
+      // make sure expected values are present
+      [ "spot", "frame-average", "center-weighted" ].forEach(function(mode) {
+        ok(cap.meteringModes.indexOf(mode) != -1, "Metering mode '" + mode + "' is present");
+      });
+
+      // test setters/getters for individual metering modes
+      cap.meteringModes.forEach(function(mode, index) {
+        cam.meteringMode = mode;
+        ok(cam.meteringMode === mode,
+          "Metering Mode[" + index + "] = " + mode + ", cam.meteringMode = " + cam.meteringMode);
+      });
+
+      next();
+    }
+  },
 ];
 
 var testGenerator = function() {
   for (var i = 0; i < tests.length; ++i) {
     yield tests[i];
   }
 }();
 
--- a/dom/nfc/gonk/Nfc.js
+++ b/dom/nfc/gonk/Nfc.js
@@ -392,17 +392,17 @@ Nfc.prototype = {
 
   classID:   NFC_CID,
   classInfo: XPCOMUtils.generateCI({classID: NFC_CID,
                                     classDescription: "Nfc",
                                     interfaces: [Ci.nsINfcService]}),
 
   QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver, Ci.nsINfcGonkEventListener]),
 
-  rfState: null,
+  rfState: NFC.NFC_RF_STATE_IDLE,
 
   nfcService: null,
 
   targetsByRequestId: null,
 
   /**
    * Send arbitrary message to Nfc service.
    *
--- a/dom/nfc/gonk/NfcOptions.h
+++ b/dom/nfc/gonk/NfcOptions.h
@@ -94,17 +94,17 @@ struct EventOptions
   nsString mType;
   int32_t mStatus;
   int32_t mErrorCode;
   int32_t mSessionId;
   nsString mRequestId;
   int32_t mMajorVersion;
   int32_t mMinorVersion;
   nsTArray<uint8_t> mTechList;
-  bool mIsP2P;
+  int32_t mIsP2P;
   nsTArray<NDEFRecordStruct> mRecords;
   int32_t mTagType;
   int32_t mMaxNDEFSize;
   int32_t mIsReadOnly;
   int32_t mIsFormatable;
   int32_t mRfState;
 
   int32_t mOriginType;
--- a/dom/nfc/nsNfc.js
+++ b/dom/nfc/nsNfc.js
@@ -241,16 +241,23 @@ MozNFCPeerImpl.prototype = {
   },
 
   classID: Components.ID("{c1b2bcf0-35eb-11e3-aa6e-0800200c9a66}"),
   contractID: "@mozilla.org/nfc/NFCPeer;1",
   QueryInterface: XPCOMUtils.generateQI([Ci.nsISupports,
                                          Ci.nsIDOMGlobalPropertyInitializer]),
 };
 
+// Should be mapped to the RFState defined in WebIDL.
+let RFState = {
+  IDLE: "idle",
+  LISTEN: "listen",
+  DISCOVERY: "discovery"
+};
+
 /**
  * Implementation of navigator NFC object.
  */
 function MozNFCImpl() {
   debug("In MozNFCImpl Constructor");
   try {
     this._nfcContentHelper = Cc["@mozilla.org/nfc/content-helper;1"]
                                .getService(Ci.nsINfcContentHelper);
@@ -265,23 +272,16 @@ function MozNFCImpl() {
 MozNFCImpl.prototype = {
   _nfcContentHelper: null,
   _window: null,
   _rfState: null,
   nfcPeer: null,
   nfcTag: null,
   eventService: null,
 
-  // Should be mapped to the RFState defined in WebIDL.
-  rfState: {
-    IDLE: "idle",
-    LISTEN: "listen",
-    DISCOVERY: "discovery"
-  },
-
   init: function init(aWindow) {
     debug("MozNFCImpl init called");
     this._window = aWindow;
     this.defineEventHandlerGetterSetter("ontagfound");
     this.defineEventHandlerGetterSetter("ontaglost");
     this.defineEventHandlerGetterSetter("onpeerready");
     this.defineEventHandlerGetterSetter("onpeerfound");
     this.defineEventHandlerGetterSetter("onpeerlost");
@@ -311,32 +311,36 @@ MozNFCImpl.prototype = {
   },
 
   notifySendFileStatus: function notifySendFileStatus(status, requestId) {
     this._nfcContentHelper.notifySendFileStatus(status, requestId);
   },
 
   startPoll: function startPoll() {
     let callback = new NfcCallback(this._window);
-    this._nfcContentHelper.changeRFState(this.rfState.DISCOVERY, callback);
+    this._nfcContentHelper.changeRFState(RFState.DISCOVERY, callback);
     return callback.promise;
   },
 
   stopPoll: function stopPoll() {
     let callback = new NfcCallback(this._window);
-    this._nfcContentHelper.changeRFState(this.rfState.LISTEN, callback);
+    this._nfcContentHelper.changeRFState(RFState.LISTEN, callback);
     return callback.promise;
   },
 
   powerOff: function powerOff() {
     let callback = new NfcCallback(this._window);
-    this._nfcContentHelper.changeRFState(this.rfState.IDLE, callback);
+    this._nfcContentHelper.changeRFState(RFState.IDLE, callback);
     return callback.promise;
   },
 
+  get enabled() {
+    return this._rfState != RFState.IDLE;
+  },
+
   defineEventHandlerGetterSetter: function defineEventHandlerGetterSetter(name) {
     Object.defineProperty(this, name, {
       get: function get() {
         return this.__DOM_IMPL__.getEventHandler(name);
       },
       set: function set(handler) {
         this.__DOM_IMPL__.setEventHandler(name, handler);
       }
--- a/dom/system/gonk/ril_worker.js
+++ b/dom/system/gonk/ril_worker.js
@@ -1721,23 +1721,51 @@ RilObject.prototype = {
         Buf.writeInt32(1);
         Buf.writeInt32(options.callIndex);
         Buf.sendParcel();
       });
     }
   },
 
   hangUpForeground: function(options) {
+    for each (let currentCall in this.currentCalls) {
+      if (currentCall.state == CALL_STATE_ACTIVE) {
+        currentCall.hangUpLocal = true;
+      }
+    }
+
     this.telephonyRequestQueue.push(REQUEST_HANGUP_FOREGROUND_RESUME_BACKGROUND, () => {
       this.context.Buf.simpleRequest(REQUEST_HANGUP_FOREGROUND_RESUME_BACKGROUND,
                                      options);
     });
   },
 
   hangUpBackground: function(options) {
+    let waitingCalls = [];
+    let heldCalls = [];
+
+    for each (let currentCall in this.currentCalls) {
+      switch (currentCall.state) {
+        case CALL_STATE_WAITING:
+          waitingCalls.push(currentCall);
+          break;
+        case CALL_STATE_HOLDING:
+          heldCalls.push(currentCall);
+          break;
+      }
+    }
+
+    // When both a held and a waiting call exist, the request shall apply to
+    // the waiting call.
+    if (waitingCalls.length) {
+      waitingCalls.forEach(call => call.hangUpLocal = true);
+    } else {
+      heldCalls.forEach(call => call.hangUpLocal = true);
+    }
+
     this.telephonyRequestQueue.push(REQUEST_HANGUP_WAITING_OR_BACKGROUND, () => {
       this.context.Buf.simpleRequest(REQUEST_HANGUP_WAITING_OR_BACKGROUND,
                                      options);
     });
   },
 
   switchActiveCall: function(options) {
     this.telephonyRequestQueue.push(REQUEST_SWITCH_WAITING_OR_HOLDING_AND_ACTIVE, () => {
--- a/dom/telephony/gonk/TelephonyService.js
+++ b/dom/telephony/gonk/TelephonyService.js
@@ -1236,17 +1236,17 @@ TelephonyService.prototype = {
       call.name = pick(aCall.name, "");
       call.numberPresentaation = pick(aCall.numberPresentation, nsITelephonyService.CALL_PRESENTATION_ALLOWED);
       call.namePresentaation = pick(aCall.namePresentation, nsITelephonyService.CALL_PRESENTATION_ALLOWED);
 
       this._currentCalls[aClientId][aCall.callIndex] = call;
     }
 
     // Handle cached dial request.
-    if (this._cachedDialRequest && !this._getOneActiveCall()) {
+    if (this._cachedDialRequest && !this._getOneActiveCall(aClientId)) {
       if (DEBUG) debug("All calls held. Perform the cached dial request.");
 
       let request = this._cachedDialRequest;
       this._sendDialCallRequest(request.clientId, request.options, request.callback);
       this._cachedDialRequest = null;
     }
 
     this._notifyAllListeners("callStateChanged", [aClientId,
--- a/dom/webidl/CameraCapabilities.webidl
+++ b/dom/webidl/CameraCapabilities.webidl
@@ -81,11 +81,12 @@ interface CameraCapabilities
 
   [Constant, Cached] readonly attribute double minExposureCompensation;
   [Constant, Cached] readonly attribute double maxExposureCompensation;
   [Constant, Cached] readonly attribute double exposureCompensationStep;
 
   [Constant, Cached] readonly attribute CameraRecorderProfiles recorderProfiles;
 
   [Constant, Cached] readonly attribute sequence<DOMString> isoModes;
+  [Constant, Cached] readonly attribute sequence<DOMString> meteringModes;
 
   jsonifier;
 };
--- a/dom/webidl/CameraControl.webidl
+++ b/dom/webidl/CameraControl.webidl
@@ -284,16 +284,21 @@ interface CameraControl : MediaStream
   void setThumbnailSize(optional CameraSize size);
 
   /* the angle, in degrees, that the image sensor is mounted relative
      to the display; e.g. if 'sensorAngle' is 270 degrees (or -90 degrees),
      then the preview stream needs to be rotated +90 degrees to have the
      same orientation as the real world. */
   readonly attribute long   sensorAngle;
 
+  /* the mode the camera will use to determine the correct exposure of
+     the scene; supported modes are exposed by capabilities.meteringModes. */
+  [Throws]
+  attribute DOMString       meteringMode;
+
   /* tell the camera to attempt to focus the image */
   [Throws]
   Promise<boolean> autoFocus();
 
   /* the event dispatched whenever the focus state changes due to calling
      autoFocus or due to continuous autofocus.
 
      if continuous autofocus is supported and focusMode is set to enable it,
--- a/dom/webidl/MozNFC.webidl
+++ b/dom/webidl/MozNFC.webidl
@@ -71,16 +71,21 @@ interface MozNFCManager {
 
 [JSImplementation="@mozilla.org/navigatorNfc;1",
  NavigatorProperty="mozNfc",
  Func="Navigator::HasNFCSupport",
  CheckPermissions="nfc nfc-share",
  AvailableIn="PrivilegedApps"]
 interface MozNFC : EventTarget {
   /**
+   * Indicate if NFC is enabled.
+   */
+  readonly attribute boolean enabled;
+
+  /**
    * This event will be fired when another NFCPeer is detected, and user confirms
    * to share data to the NFCPeer object by calling mozNFC.notifyUserAcceptedP2P.
    * The event will be type of NFCPeerEvent.
    */
   [CheckPermissions="nfc-share", AvailableIn=CertifiedApps]
   attribute EventHandler onpeerready;
 
   /**
--- a/mozglue/build/Nuwa.cpp
+++ b/mozglue/build/Nuwa.cpp
@@ -50,20 +50,16 @@ int __real_pthread_join(pthread_t thread
 int __real_epoll_wait(int epfd,
                       struct epoll_event *events,
                       int maxevents,
                       int timeout);
 int __real_pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mtx);
 int __real_pthread_cond_timedwait(pthread_cond_t *cond,
                                   pthread_mutex_t *mtx,
                                   const struct timespec *abstime);
-int __real___pthread_cond_timedwait(pthread_cond_t *cond,
-                                    pthread_mutex_t *mtx,
-                                    const struct timespec *abstime,
-                                    clockid_t clock);
 int __real_pthread_mutex_lock(pthread_mutex_t *mtx);
 int __real_poll(struct pollfd *fds, nfds_t nfds, int timeout);
 int __real_epoll_create(int size);
 int __real_socketpair(int domain, int type, int protocol, int sv[2]);
 int __real_pipe2(int __pipedes[2], int flags);
 int __real_pipe(int __pipedes[2]);
 int __real_epoll_ctl(int aEpollFd, int aOp, int aFd, struct epoll_event *aEvent);
 int __real_close(int aFd);
@@ -1118,57 +1114,16 @@ extern "C" MFBT_API int
     }
     RECREATE_GATE_VIP();
   }
   THREAD_FREEZE_POINT2_VIP();
 
   return rv;
 }
 
-extern "C" int __pthread_cond_timedwait(pthread_cond_t *cond,
-                                        pthread_mutex_t *mtx,
-                                        const struct timespec *abstime,
-                                        clockid_t clock);
-
-extern "C" MFBT_API int
-__wrap___pthread_cond_timedwait(pthread_cond_t *cond,
-                                pthread_mutex_t *mtx,
-                                const struct timespec *abstime,
-                                clockid_t clock) {
-  int rv = 0;
-
-  THREAD_FREEZE_POINT1_VIP();
-  if (freezePoint2) {
-    RECREATE_CONTINUE();
-    RECREATE_PASS_VIP();
-    RECREATE_GATE_VIP();
-    return rv;
-  }
-  if (recreated && mtx) {
-    if (!freezePoint1) {
-      tinfo->condMutex = mtx;
-      if (!pthread_mutex_trylock(mtx)) {
-        tinfo->condMutexNeedsBalancing = true;
-      }
-    }
-    RECREATE_CONTINUE();
-    RECREATE_PASS_VIP();
-  }
-  rv = REAL(__pthread_cond_timedwait)(cond, mtx, abstime, clock);
-  if (recreated && mtx) {
-    if (tinfo->condMutex) {
-      tinfo->condMutexNeedsBalancing = false;
-      pthread_mutex_unlock(mtx);
-    }
-    RECREATE_GATE_VIP();
-  }
-  THREAD_FREEZE_POINT2_VIP();
-
-  return rv;
-}
 
 extern "C" MFBT_API int
 __wrap_pthread_mutex_lock(pthread_mutex_t *mtx) {
   int rv = 0;
 
   THREAD_FREEZE_POINT1();
   if (freezePoint2) {
     return rv;