Merge b2g-inbound to m-c. a=merge
authorRyan VanderMeulen <ryanvm@gmail.com>
Tue, 21 Oct 2014 15:08:13 -0400
changeset 211524 a7605a5a207725ba0a9d247aa00545746bb7b2cf
parent 211461 5a50ea5c0a998519f573ff76bb0d0c06cb7a4a8e (current diff)
parent 211523 70d9d7813553df30dd0005df6bdcb192ccc951b6 (diff)
child 211579 15099ba111e847a4cd5d4baf2bcd038910ca5fcf
push id27679
push userryanvm@gmail.com
push dateTue, 21 Oct 2014 19:10:36 +0000
treeherdermozilla-central@a7605a5a2077 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone36.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge b2g-inbound to m-c. a=merge
--- a/b2g/config/dolphin/sources.xml
+++ b/b2g/config/dolphin/sources.xml
@@ -10,17 +10,17 @@
   <!--original fetch url was git://codeaurora.org/-->
   <remote fetch="https://git.mozilla.org/external/caf" name="caf"/>
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="3a2947df41a480de1457a6dcdbf46ad0af70d8e0">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="3ec94f448bb5c1c9c264896685c6ef77ab718c87"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="82174cee5ede9f23aedad8a39f8b8cdc1ae710c4"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="73d68c9c91bc568ce7c888ac057b3f44bd1b2e79"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
   <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="9f6b7471c881ee689183d681658cf2ba3dfc5610"/>
--- a/b2g/config/emulator-ics/sources.xml
+++ b/b2g/config/emulator-ics/sources.xml
@@ -14,17 +14,17 @@
   <!--original fetch url was git://github.com/apitrace/-->
   <remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/>
   <default remote="caf" revision="refs/tags/android-4.0.4_r2.1" sync-j="4"/>
   <!-- Gonk specific things and forks -->
   <project name="platform_build" path="build" remote="b2g" revision="84923f1940625c47ff4c1fdf01b10fde3b7d909e">
     <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="3ec94f448bb5c1c9c264896685c6ef77ab718c87"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="82174cee5ede9f23aedad8a39f8b8cdc1ae710c4"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="73d68c9c91bc568ce7c888ac057b3f44bd1b2e79"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="cd88d860656c31c7da7bb310d6a160d0011b0961"/>
   <project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="c058843242068d0df7c107e09da31b53d2e08fa6"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="9f6b7471c881ee689183d681658cf2ba3dfc5610"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="dd924f92906085b831bf1cbbc7484d3c043d613c"/>
--- a/b2g/config/emulator-jb/sources.xml
+++ b/b2g/config/emulator-jb/sources.xml
@@ -12,17 +12,17 @@
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="8986df0f82e15ac2798df0b6c2ee3435400677ac">
     <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="3ec94f448bb5c1c9c264896685c6ef77ab718c87"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="82174cee5ede9f23aedad8a39f8b8cdc1ae710c4"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="73d68c9c91bc568ce7c888ac057b3f44bd1b2e79"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="9f6b7471c881ee689183d681658cf2ba3dfc5610"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
   <!-- Stock Android things -->
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.1" path="prebuilts/clang/linux-x86/3.1" revision="5c45f43419d5582949284eee9cef0c43d866e03b"/>
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.2" path="prebuilts/clang/linux-x86/3.2" revision="3748b4168e7bd8d46457d4b6786003bc6a5223ce"/>
@@ -126,15 +126,15 @@
   <project name="platform/system/vold" path="system/vold" revision="8de05d4a52b5a91e7336e6baa4592f945a6ddbea"/>
   <default remote="caf" revision="refs/tags/android-4.3_r2.1" sync-j="4"/>
   <!-- Emulator specific things -->
   <project name="android-development" path="development" remote="b2g" revision="dab55669da8f48b6e57df95d5af9f16b4a87b0b1"/>
   <project name="device/generic/armv7-a-neon" path="device/generic/armv7-a-neon" revision="3a9a17613cc685aa232432566ad6cc607eab4ec1"/>
   <project name="device_generic_goldfish" path="device/generic/goldfish" remote="b2g" revision="197cd9492b9fadaa915c5daf36ff557f8f4a8d1c"/>
   <project name="platform/external/libnfc-nci" path="external/libnfc-nci" revision="7d33aaf740bbf6c7c6e9c34a92b371eda311b66b"/>
   <project name="libnfcemu" path="external/libnfcemu" remote="b2g" revision="125ccf9bd5986c7728ea44508b3e1d1185ac028b"/>
-  <project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="d259117b4976decbe2f76eeed85218bf0109190f"/>
+  <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="d872fc1462d367eb67833de6942c297d6c4dc874"/>
+  <project name="platform_system_nfcd" path="system/nfcd" remote="b2g" revision="a28a47cf4de9cc676e8a14d58826f7927d77f5d5"/>
   <project name="android-sdk" path="sdk" remote="b2g" revision="8b1365af38c9a653df97349ee53a3f5d64fd590a"/>
   <project name="darwinstreamingserver" path="system/darwinstreamingserver" remote="b2g" revision="cf85968c7f85e0ec36e72c87ceb4837a943b8af6"/>
 </manifest>
--- a/b2g/config/emulator-kk/sources.xml
+++ b/b2g/config/emulator-kk/sources.xml
@@ -10,17 +10,17 @@
   <!--original fetch url was git://codeaurora.org/-->
   <remote fetch="https://git.mozilla.org/external/caf" name="caf"/>
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="3a2947df41a480de1457a6dcdbf46ad0af70d8e0">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="3ec94f448bb5c1c9c264896685c6ef77ab718c87"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="82174cee5ede9f23aedad8a39f8b8cdc1ae710c4"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="73d68c9c91bc568ce7c888ac057b3f44bd1b2e79"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
   <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="9f6b7471c881ee689183d681658cf2ba3dfc5610"/>
--- a/b2g/config/emulator/sources.xml
+++ b/b2g/config/emulator/sources.xml
@@ -14,17 +14,17 @@
   <!--original fetch url was git://github.com/apitrace/-->
   <remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/>
   <default remote="caf" revision="refs/tags/android-4.0.4_r2.1" sync-j="4"/>
   <!-- Gonk specific things and forks -->
   <project name="platform_build" path="build" remote="b2g" revision="84923f1940625c47ff4c1fdf01b10fde3b7d909e">
     <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="3ec94f448bb5c1c9c264896685c6ef77ab718c87"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="82174cee5ede9f23aedad8a39f8b8cdc1ae710c4"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="73d68c9c91bc568ce7c888ac057b3f44bd1b2e79"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="cd88d860656c31c7da7bb310d6a160d0011b0961"/>
   <project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="c058843242068d0df7c107e09da31b53d2e08fa6"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="9f6b7471c881ee689183d681658cf2ba3dfc5610"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="dd924f92906085b831bf1cbbc7484d3c043d613c"/>
--- a/b2g/config/flame-kk/sources.xml
+++ b/b2g/config/flame-kk/sources.xml
@@ -10,17 +10,17 @@
   <!--original fetch url was git://codeaurora.org/-->
   <remote fetch="https://git.mozilla.org/external/caf" name="caf"/>
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="3a2947df41a480de1457a6dcdbf46ad0af70d8e0">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="3ec94f448bb5c1c9c264896685c6ef77ab718c87"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="82174cee5ede9f23aedad8a39f8b8cdc1ae710c4"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="73d68c9c91bc568ce7c888ac057b3f44bd1b2e79"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
   <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="9f6b7471c881ee689183d681658cf2ba3dfc5610"/>
@@ -146,13 +146,13 @@
   <project name="platform/hardware/qcom/camera" path="hardware/qcom/camera" revision="2a1ded216a91bf62a72b1640cf01ab4998f37028"/>
   <project name="platform/hardware/qcom/display" path="hardware/qcom/display" revision="e5a971282719907f73fb1da964ca40aad67a3be0"/>
   <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="d872fc1462d367eb67833de6942c297d6c4dc874"/>
+  <project name="platform_system_nfcd" path="system/nfcd" remote="b2g" revision="a28a47cf4de9cc676e8a14d58826f7927d77f5d5"/>
   <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="7704e16da545f4207812e593743d6743e1afb9c5"/>
 </manifest>
--- a/b2g/config/flame/sources.xml
+++ b/b2g/config/flame/sources.xml
@@ -12,17 +12,17 @@
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="8986df0f82e15ac2798df0b6c2ee3435400677ac">
     <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="3ec94f448bb5c1c9c264896685c6ef77ab718c87"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="82174cee5ede9f23aedad8a39f8b8cdc1ae710c4"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="73d68c9c91bc568ce7c888ac057b3f44bd1b2e79"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="9f6b7471c881ee689183d681658cf2ba3dfc5610"/>
   <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"/>
@@ -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="d872fc1462d367eb67833de6942c297d6c4dc874"/>
+  <project name="platform_system_nfcd" path="system/nfcd" remote="b2g" revision="a28a47cf4de9cc676e8a14d58826f7927d77f5d5"/>
   <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": "ce8e42aa3688f56113d68bc82409a7fea055547b", 
+    "revision": "2bf3274b9e149c6a0ffc13be4c7d3a2f7236e311", 
     "repo_path": "/integration/gaia-central"
 }
--- a/b2g/config/hamachi/sources.xml
+++ b/b2g/config/hamachi/sources.xml
@@ -12,17 +12,17 @@
   <!--original fetch url was git://github.com/apitrace/-->
   <remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/>
   <default remote="caf" revision="b2g/ics_strawberry" sync-j="4"/>
   <!-- Gonk specific things and forks -->
   <project name="platform_build" path="build" remote="b2g" revision="84923f1940625c47ff4c1fdf01b10fde3b7d909e">
     <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="3ec94f448bb5c1c9c264896685c6ef77ab718c87"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="82174cee5ede9f23aedad8a39f8b8cdc1ae710c4"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="73d68c9c91bc568ce7c888ac057b3f44bd1b2e79"/>
   <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="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="9f6b7471c881ee689183d681658cf2ba3dfc5610"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="6426040f1be4a844082c9769171ce7f5341a5528"/>
   <project name="platform/bionic" path="bionic" revision="d2eb6c7b6e1bc7643c17df2d9d9bcb1704d0b9ab"/>
--- a/b2g/config/helix/sources.xml
+++ b/b2g/config/helix/sources.xml
@@ -10,17 +10,17 @@
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <default remote="caf" revision="b2g/ics_strawberry" sync-j="4"/>
   <!-- Gonk specific things and forks -->
   <project name="platform_build" path="build" remote="b2g" revision="84923f1940625c47ff4c1fdf01b10fde3b7d909e">
     <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="3ec94f448bb5c1c9c264896685c6ef77ab718c87"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="82174cee5ede9f23aedad8a39f8b8cdc1ae710c4"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="73d68c9c91bc568ce7c888ac057b3f44bd1b2e79"/>
   <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="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
   <project name="gonk-patches" path="patches" remote="b2g" revision="223a2421006e8f5da33f516f6891c87cae86b0f6"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="6426040f1be4a844082c9769171ce7f5341a5528"/>
   <project name="platform/bionic" path="bionic" revision="d2eb6c7b6e1bc7643c17df2d9d9bcb1704d0b9ab"/>
--- a/b2g/config/nexus-4/sources.xml
+++ b/b2g/config/nexus-4/sources.xml
@@ -12,17 +12,17 @@
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="8986df0f82e15ac2798df0b6c2ee3435400677ac">
     <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="3ec94f448bb5c1c9c264896685c6ef77ab718c87"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="82174cee5ede9f23aedad8a39f8b8cdc1ae710c4"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="73d68c9c91bc568ce7c888ac057b3f44bd1b2e79"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="9f6b7471c881ee689183d681658cf2ba3dfc5610"/>
   <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"/>
@@ -124,17 +124,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="d872fc1462d367eb67833de6942c297d6c4dc874"/>
+  <project name="platform_system_nfcd" path="system/nfcd" remote="b2g" revision="a28a47cf4de9cc676e8a14d58826f7927d77f5d5"/>
   <project name="platform/external/libnfc-nci" path="external/libnfc-nci" revision="7d33aaf740bbf6c7c6e9c34a92b371eda311b66b"/>
   <project name="platform/external/wpa_supplicant_8" path="external/wpa_supplicant_8" revision="0e56e450367cd802241b27164a2979188242b95f"/>
   <project name="platform/hardware/broadcom/wlan" path="hardware/broadcom/wlan" revision="0e1929fa3aa38bf9d40e9e953d619fab8164c82e"/>
   <project name="platform/hardware/qcom/audio" path="hardware/qcom/audio" revision="b0a528d839cfd9d170d092fe3743b5252b4243a6"/>
   <project name="platform/hardware/qcom/bt" path="hardware/qcom/bt" revision="380945eaa249a2dbdde0daa4c8adb8ca325edba6"/>
   <project name="platform/hardware/qcom/display" path="hardware/qcom/display" revision="6f3b0272cefaffeaed2a7d2bb8f633059f163ddc"/>
   <project name="platform/hardware/qcom/keymaster" path="hardware/qcom/keymaster" revision="16da8262c997a5a0d797885788a64a0771b26910"/>
   <project name="platform/hardware/qcom/media" path="hardware/qcom/media" revision="689b476ba3eb46c34b81343295fe144a0e81a18e"/>
--- a/b2g/config/wasabi/sources.xml
+++ b/b2g/config/wasabi/sources.xml
@@ -12,17 +12,17 @@
   <!--original fetch url was git://github.com/apitrace/-->
   <remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/>
   <default remote="caf" revision="ics_chocolate_rb4.2" sync-j="4"/>
   <!-- Gonk specific things and forks -->
   <project name="platform_build" path="build" remote="b2g" revision="84923f1940625c47ff4c1fdf01b10fde3b7d909e">
     <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="3ec94f448bb5c1c9c264896685c6ef77ab718c87"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="82174cee5ede9f23aedad8a39f8b8cdc1ae710c4"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="73d68c9c91bc568ce7c888ac057b3f44bd1b2e79"/>
   <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="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="9f6b7471c881ee689183d681658cf2ba3dfc5610"/>
   <project name="gonk-patches" path="patches" remote="b2g" revision="223a2421006e8f5da33f516f6891c87cae86b0f6"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="6426040f1be4a844082c9769171ce7f5341a5528"/>
--- a/dom/bluetooth/bluedroid/BluetoothSocket.cpp
+++ b/dom/bluetooth/bluedroid/BluetoothSocket.cpp
@@ -138,16 +138,21 @@ public:
     AddWatchers(WRITE_WATCHER, false);
   }
 
   SocketConsumerBase* GetConsumer()
   {
     return mConsumer.get();
   }
 
+  SocketBase* GetSocketBase()
+  {
+    return GetConsumer();
+  }
+
   /**
    * Consumer pointer. Non-thread safe RefPtr, so should only be manipulated
    * directly from main thread. All non-main-thread accesses should happen with
    * mImpl as container.
    */
   RefPtr<BluetoothSocket> mConsumer;
 
 private:
@@ -656,17 +661,18 @@ bool
 BluetoothSocket::SendSocketData(UnixSocketRawData* aData)
 {
   MOZ_ASSERT(NS_IsMainThread());
   NS_ENSURE_TRUE(mImpl, false);
 
   MOZ_ASSERT(!mImpl->IsShutdownOnMainThread());
 
   XRE_GetIOMessageLoop()->PostTask(
-    FROM_HERE, new SocketIOSendTask<DroidSocketImpl>(mImpl, aData));
+    FROM_HERE,
+    new SocketIOSendTask<DroidSocketImpl, UnixSocketRawData>(mImpl, aData));
 
   return true;
 }
 
 void
 BluetoothSocket::ReceiveSocketData(nsAutoPtr<UnixSocketRawData>& aMessage)
 {
   MOZ_ASSERT(NS_IsMainThread());
--- a/dom/bluetooth2/bluedroid/BluetoothSocket.cpp
+++ b/dom/bluetooth2/bluedroid/BluetoothSocket.cpp
@@ -138,16 +138,21 @@ public:
     AddWatchers(WRITE_WATCHER, false);
   }
 
   SocketConsumerBase* GetConsumer()
   {
     return mConsumer.get();
   }
 
+  SocketBase* GetSocketBase()
+  {
+    return GetConsumer();
+  }
+
   /**
    * Consumer pointer. Non-thread safe RefPtr, so should only be manipulated
    * directly from main thread. All non-main-thread accesses should happen with
    * mImpl as container.
    */
   RefPtr<BluetoothSocket> mConsumer;
 
 private:
@@ -656,17 +661,17 @@ bool
 BluetoothSocket::SendSocketData(UnixSocketRawData* aData)
 {
   MOZ_ASSERT(NS_IsMainThread());
   NS_ENSURE_TRUE(mImpl, false);
 
   MOZ_ASSERT(!mImpl->IsShutdownOnMainThread());
 
   XRE_GetIOMessageLoop()->PostTask(
-    FROM_HERE, new SocketIOSendTask<DroidSocketImpl>(mImpl, aData));
+    FROM_HERE, new SocketIOSendTask<DroidSocketImpl, UnixSocketRawData>(mImpl, aData));
 
   return true;
 }
 
 void
 BluetoothSocket::ReceiveSocketData(nsAutoPtr<UnixSocketRawData>& aMessage)
 {
   MOZ_ASSERT(NS_IsMainThread());
--- a/dom/inputmethod/forms.js
+++ b/dom/inputmethod/forms.js
@@ -211,17 +211,17 @@ let FormAssistant = {
     addMessageListener("Forms:EndComposition", this);
   },
 
   ignoredInputTypes: new Set([
     'button', 'file', 'checkbox', 'radio', 'reset', 'submit', 'image',
     'range'
   ]),
 
-  isKeyboardOpened: false,
+  isHandlingFocus: false,
   selectionStart: -1,
   selectionEnd: -1,
   textBeforeCursor: "",
   textAfterCursor: "",
   scrollIntoViewTimeout: null,
   _focusedElement: null,
   _focusCounter: 0, // up one for every time we focus a new element
   _focusDeleteObserver: null,
@@ -299,17 +299,17 @@ let FormAssistant = {
       let MutationObserver = element.ownerDocument.defaultView.MutationObserver;
       this._focusDeleteObserver = new MutationObserver(function(mutations) {
         var del = [].some.call(mutations, function(m) {
           return [].some.call(m.removedNodes, function(n) {
             return n.contains(element);
           });
         });
         if (del && element === self.focusedElement) {
-          self.hideKeyboard();
+          self.unhandleFocus();
           self.selectionStart = -1;
           self.selectionEnd = -1;
         }
       });
 
       this._focusDeleteObserver.observe(element.ownerDocument.body, {
         childList: true,
         subtree: true
@@ -346,17 +346,17 @@ let FormAssistant = {
   },
 
   // Implements nsIEditorObserver get notification when the text content of
   // current input field has changed.
   EditAction: function fa_editAction() {
     if (this._editing) {
       return;
     }
-    this.sendKeyboardState(this.focusedElement);
+    this.sendInputState(this.focusedElement);
   },
 
   handleEvent: function fa_handleEvent(evt) {
     let target = evt.target;
 
     let range = null;
     switch (evt.type) {
       case "focus":
@@ -374,23 +374,23 @@ let FormAssistant = {
                                           : null;
         }
 
         if (!target) {
           break;
         }
 
         if (isContentEditable(target)) {
-          this.showKeyboard(this.getTopLevelEditable(target));
+          this.handleFocus(this.getTopLevelEditable(target));
           this.updateSelection();
           break;
         }
 
         if (this.isFocusableElement(target)) {
-          this.showKeyboard(target);
+          this.handleFocus(target);
           this.updateSelection();
         }
         break;
 
       case "pagehide":
       case "beforeunload":
         // We are only interested to the pagehide and beforeunload events from
         // the root document.
@@ -401,24 +401,24 @@ let FormAssistant = {
       case "submit":
         if (this.focusedElement) {
           this.focusedElement.blur();
         }
         break;
 
       case "blur":
         if (this.focusedElement) {
-          this.hideKeyboard();
+          this.unhandleFocus();
           this.selectionStart = -1;
           this.selectionEnd = -1;
         }
         break;
 
       case "resize":
-        if (!this.isKeyboardOpened)
+        if (!this.isHandlingFocus)
           return;
 
         if (this.scrollIntoViewTimeout) {
           content.clearTimeout(this.scrollIntoViewTimeout);
           this.scrollIntoViewTimeout = null;
         }
 
         // We may receive multiple resize events in quick succession, so wait
@@ -667,52 +667,51 @@ let FormAssistant = {
         });
         break;
       }
     }
     this._editing = false;
 
   },
 
-  showKeyboard: function fa_showKeyboard(target) {
+  handleFocus: function fa_handleFocus(target) {
     if (this.focusedElement === target)
       return;
 
     if (target instanceof HTMLOptionElement)
       target = target.parentNode;
 
     this.setFocusedElement(target);
 
     let count = this._focusCounter;
-    this.waitForNextTick(function fa_showKeyboardSync() {
+    this.waitForNextTick(function fa_handleFocusSync() {
       if (count !== this._focusCounter) {
         return;
       }
 
-      let kbOpened = this.sendKeyboardState(target);
-      if (this.isTextInputElement(target))
-        this.isKeyboardOpened = kbOpened;
+      let isHandlingFocus = this.sendInputState(target);
+      this.isHandlingFocus = isHandlingFocus;
     }.bind(this));
   },
 
-  hideKeyboard: function fa_hideKeyboard() {
+  unhandleFocus: function fa_unhandleFocus() {
     this.setFocusedElement(null);
 
     let count = this._focusCounter;
 
     // Wait for the next tick before unset the focused element and etc.
     // If the user move from one input from another,
     // the remote process should get one Forms:Input message instead of two.
-    this.waitForNextTick(function fa_hideKeyboardSync() {
+    this.waitForNextTick(function fa_unhandleFocusSync() {
       if (count !== this._focusCounter ||
-          !this.isKeyboardOpened) {
+          !this.isHandlingFocus) {
         return;
       }
 
-      this.isKeyboardOpened = false;
+      this.isHandlingFocus = false;
       sendAsyncMessage("Forms:Input", { "type": "blur" });
     }.bind(this));
   },
 
   isFocusableElement: function fa_isFocusableElement(element) {
     if (element instanceof HTMLSelectElement ||
         element instanceof HTMLTextAreaElement)
       return true;
@@ -720,34 +719,28 @@ let FormAssistant = {
     if (element instanceof HTMLOptionElement &&
         element.parentNode instanceof HTMLSelectElement)
       return true;
 
     return (element instanceof HTMLInputElement &&
             !this.ignoredInputTypes.has(element.type));
   },
 
-  isTextInputElement: function fa_isTextInputElement(element) {
-    return element instanceof HTMLInputElement ||
-           element instanceof HTMLTextAreaElement ||
-           isContentEditable(element);
-  },
-
   getTopLevelEditable: function fa_getTopLevelEditable(element) {
     function retrieveTopLevelEditable(element) {
       while (element && !isContentEditable(element))
         element = element.parentNode;
 
       return element;
     }
 
     return retrieveTopLevelEditable(element) || element;
   },
 
-  sendKeyboardState: function(element) {
+  sendInputState: function(element) {
     // FIXME/bug 729623: work around apparent bug in the IME manager
     // in gecko.
     let readonly = element.getAttribute("readonly");
     if (readonly) {
       return false;
     }
 
     sendAsyncMessage("Forms:Input", getJSON(element, this._focusCounter));
--- a/dom/inputmethod/mochitest/mochitest.ini
+++ b/dom/inputmethod/mochitest/mochitest.ini
@@ -19,8 +19,9 @@ support-files =
 [test_bug978918.html]
 [test_bug1026997.html]
 [test_bug1043828.html]
 [test_bug1059163.html]
 [test_bug1066515.html]
 [test_delete_focused_element.html]
 [test_sendkey_cancel.html]
 [test_two_inputs.html]
+[test_two_selects.html]
new file mode 100644
--- /dev/null
+++ b/dom/inputmethod/mochitest/test_two_selects.html
@@ -0,0 +1,151 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1079728
+-->
+<head>
+  <title>Test switching between two inputs</title>
+  <script type="application/javascript;version=1.7" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <script type="application/javascript;version=1.7" src="inputmethod_common.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1079728">Mozilla Bug 1079728</a>
+<p id="display"></p>
+<pre id="test">
+<script class="testbody" type="application/javascript;version=1.7">
+
+inputmethod_setup(function() {
+  runTest();
+});
+
+let appFrameScript = function appFrameScript() {
+  let select1 = content.document.body.firstElementChild;
+  let select2 = content.document.body.children[1];
+
+  let i = 1;
+
+  select1.focus();
+
+  addMessageListener('test:next', function() {
+    i++;
+    switch (i) {
+      case 2:
+        select2.focus();
+
+        break;
+
+      case 3:
+        select2.blur();
+        select2.focus();
+
+        break;
+
+      case 4:
+        select2.blur();
+
+        break;
+
+      case 5:
+        select2.focus();
+        select2.blur();
+
+        select1.focus();
+
+        break;
+
+      case 6:
+        select1.blur();
+
+        break;
+    }
+  });
+};
+
+function runTest() {
+  let im = navigator.mozInputMethod;
+
+  let i = 0;
+  im.oninputcontextchange = function(evt) {
+    var inputcontext = navigator.mozInputMethod.inputcontext;
+
+    i++;
+    switch (i) {
+      // focus on the first input receives the first input context.
+      case 1:
+        ok(!!inputcontext, 'Receving the first input context');
+        is(inputcontext.textAfterCursor, 'First');
+
+        mm.sendAsyncMessage('test:next');
+        break;
+
+      // focus on the second input (implicitly blur the first input)
+      // results the second input context.
+      case 2:
+        ok(!!inputcontext, 'Receving the second input context');
+        is(inputcontext.textAfterCursor, 'Second');
+
+
+        mm.sendAsyncMessage('test:next');
+        break;
+
+      // blur and re-focus on the second input results updated
+      // input context for the second input.
+      case 3:
+        ok(!!inputcontext, 'Receving the second input context');
+        is(inputcontext.textAfterCursor, 'Second');
+
+        mm.sendAsyncMessage('test:next');
+        break;
+
+      // blur on the second input results null input context
+      case 4:
+        is(inputcontext, null, 'Receving null inputcontext');
+
+        mm.sendAsyncMessage('test:next');
+        break;
+
+      // focus and blur on the second input sends no message;
+      // focus on the first input receives the first input context.
+      case 5:
+        ok(!!inputcontext, 'Receving the first input context');
+        is(inputcontext.textAfterCursor, 'First');
+
+        mm.sendAsyncMessage('test:next');
+        break;
+
+      // blur on the first input results null input context
+      case 6:
+        is(inputcontext, null, 'Receving null inputcontext');
+
+        inputmethod_cleanup();
+        break;
+
+      default:
+        ok(false, 'Receving extra inputcontextchange calls');
+        inputmethod_cleanup();
+
+        break;
+    }
+  };
+
+  // Set current page as an input method.
+  SpecialPowers.wrap(im).setActive(true);
+
+  let iframe = document.createElement('iframe');
+  iframe.src = 'data:text/html,<html><body><select><option>First</option></select><select><option>Second</option></select></html>';
+  iframe.setAttribute('mozbrowser', true);
+  document.body.appendChild(iframe);
+
+  let mm = SpecialPowers.getBrowserFrameMessageManager(iframe);
+
+  iframe.addEventListener('mozbrowserloadend', function() {
+    mm.loadFrameScript('data:,(' + encodeURIComponent(appFrameScript.toString()) + ')();', false);
+  });
+}
+
+</script>
+</pre>
+</body>
+</html>
+
--- a/dom/nfc/gonk/NfcGonkMessage.h
+++ b/dom/nfc/gonk/NfcGonkMessage.h
@@ -3,17 +3,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef NfcGonkMessage_h
 #define NfcGonkMessage_h
 
 namespace mozilla {
 
 #define NFCD_MAJOR_VERSION 1
-#define NFCD_MINOR_VERSION 12
+#define NFCD_MINOR_VERSION 13
 
 enum NfcRequest {
   ConfigReq = 0,
   ConnectReq,
   CloseReq,
   ReadNDEFReq,
   WriteNDEFReq,
   MakeReadOnlyNDEFReq,
--- a/dom/nfc/gonk/nfc_consts.js
+++ b/dom/nfc/gonk/nfc_consts.js
@@ -20,83 +20,59 @@ this.DEBUG_ALL = false;
 
 // Set individually to debug specific layers
 this.DEBUG_CONTENT_HELPER = false || DEBUG_ALL;
 this.DEBUG_NFC = false || DEBUG_ALL;
 
 // nfcd error codes
 this.NFC_SUCCESS = 0;
 this.NFC_ERROR_IO = -1;
-this.NFC_ERROR_CANCELLED = -2;
-this.NFC_ERROR_TIMEOUT = -3;
-this.NFC_ERROR_BUSY = -4;
-this.NFC_ERROR_CONNECT = -5;
-this.NFC_ERROR_DISCONNECT = -6;
-this.NFC_ERROR_READ = -7;
-this.NFC_ERROR_WRITE = -8;
-this.NFC_ERROR_INVALID_PARAM = -9;
-this.NFC_ERROR_INSUFFICIENT_RESOURCES = -10;
-this.NFC_ERROR_SOCKET_CREATION = -11;
-this.NFC_ERROR_SOCKET_NOT_CONNECTED = -12;
-this.NFC_ERROR_BUFFER_TOO_SMALL = -13;
-this.NFC_ERROR_SAP_USED = -14;
-this.NFC_ERROR_SERVICE_NAME_USED = -15;
-this.NFC_ERROR_SOCKET_OPTIONS = -16;
-this.NFC_ERROR_FAIL_ENABLE_DISCOVERY = -17;
-this.NFC_ERROR_FAIL_DISABLE_DISCOVERY = -18;
-this.NFC_ERROR_NOT_INITIALIZED = -19;
-this.NFC_ERROR_INITIALIZE_FAIL = -20;
-this.NFC_ERROR_DEINITIALIZE_FAIL = -21;
-this.NFC_ERROR_SE_CONNECTED = -22;
-this.NFC_ERROR_NO_SE_CONNECTED = -23;
-this.NFC_ERROR_NOT_SUPPORTED = -24;
-this.NFC_ERROR_BAD_SESSION_ID = -25;
-this.NFC_ERROR_LOST_TECH = -26;
-this.NFC_ERROR_BAD_TECH_TYPE = -27;
-this.NFC_ERROR_SELECT_SE_FAIL = -28;
-this.NFC_ERROR_DESELECT_SE_FAIL = -29;
-this.NFC_ERROR_FAIL_ENABLE_LOW_POWER_MODE = -30;
-this.NFC_ERROR_FAIL_DISABLE_LOW_POWER_MODE = -31;
+this.NFC_ERROR_TIMEOUT = -2;
+this.NFC_ERROR_BUSY = -3;
+this.NFC_ERROR_CONNECT = -4;
+this.NFC_ERROR_DISCONNECT = -5;
+this.NFC_ERROR_READ = -6;
+this.NFC_ERROR_WRITE = -7;
+this.NFC_ERROR_INVALID_PARAM = -8;
+this.NFC_ERROR_INSUFFICIENT_RESOURCES = -9;
+this.NFC_ERROR_SOCKET_CREATION = -10;
+this.NFC_ERROR_FAIL_ENABLE_DISCOVERY = -11;
+this.NFC_ERROR_FAIL_DISABLE_DISCOVERY = -12;
+this.NFC_ERROR_NOT_INITIALIZED = -13;
+this.NFC_ERROR_INITIALIZE_FAIL = -14;
+this.NFC_ERROR_DEINITIALIZE_FAIL = -15;
+this.NFC_ERROR_NOT_SUPPORTED = -16;
+this.NFC_ERROR_BAD_SESSION_ID = -17,
+this.NFC_ERROR_FAIL_ENABLE_LOW_POWER_MODE = -18;
+this.NFC_ERROR_FAIL_DISABLE_LOW_POWER_MODE = -19;
 
 // Gecko specific error codes
 this.NFC_GECKO_ERROR_GENERIC_FAILURE = 1;
 this.NFC_GECKO_ERROR_P2P_REG_INVALID = 2;
 this.NFC_GECKO_ERROR_NOT_ENABLED = 3;
 this.NFC_GECKO_ERROR_SEND_FILE_FAILED = 4;
 
 this.NFC_ERROR_MSG = {};
 this.NFC_ERROR_MSG[this.NFC_ERROR_IO] = "NfcIoError";
-this.NFC_ERROR_MSG[this.NFC_ERROR_CANCELLED] = "NfcCancelledError";
 this.NFC_ERROR_MSG[this.NFC_ERROR_TIMEOUT] = "NfcTimeoutError";
 this.NFC_ERROR_MSG[this.NFC_ERROR_BUSY] = "NfcBusyError";
 this.NFC_ERROR_MSG[this.NFC_ERROR_CONNECT] = "NfcConnectError";
 this.NFC_ERROR_MSG[this.NFC_ERROR_DISCONNECT] = "NfcDisconnectError";
 this.NFC_ERROR_MSG[this.NFC_ERROR_READ] = "NfcReadError";
 this.NFC_ERROR_MSG[this.NFC_ERROR_WRITE] = "NfcWriteError";
 this.NFC_ERROR_MSG[this.NFC_ERROR_INVALID_PARAM] = "NfcInvalidParamError";
 this.NFC_ERROR_MSG[this.NFC_ERROR_INSUFFICIENT_RESOURCES] = "NfcInsufficentResourcesError";
 this.NFC_ERROR_MSG[this.NFC_ERROR_SOCKET_CREATION] = "NfcSocketCreationError";
-this.NFC_ERROR_MSG[this.NFC_ERROR_SOCKET_NOT_CONNECTED] = "NfcSocketNotConntectedError";
-this.NFC_ERROR_MSG[this.NFC_ERROR_BUFFER_TOO_SMALL] = "NfcBufferTooSmallError";
-this.NFC_ERROR_MSG[this.NFC_ERROR_SAP_USED] = "NfcSapUsedError";
-this.NFC_ERROR_MSG[this.NFC_ERROR_SERVICE_NAME_USED] = "NfcServiceNameUsedError";
-this.NFC_ERROR_MSG[this.NFC_ERROR_SOCKET_OPTIONS] = "NfcSocketOptionsError";
 this.NFC_ERROR_MSG[this.NFC_ERROR_FAIL_ENABLE_DISCOVERY] = "NfcFailEnableDiscoveryError";
 this.NFC_ERROR_MSG[this.NFC_ERROR_FAIL_DISABLE_DISCOVERY] = "NfcFailDisableDiscoveryError";
 this.NFC_ERROR_MSG[this.NFC_ERROR_NOT_INITIALIZED] = "NfcNotInitializedError";
 this.NFC_ERROR_MSG[this.NFC_ERROR_INITIALIZE_FAIL] = "NfcInitializeFailError";
 this.NFC_ERROR_MSG[this.NFC_ERROR_DEINITIALIZE_FAIL] = "NfcDeinitializeFailError";
-this.NFC_ERROR_MSG[this.NFC_ERROR_SE_CONNECTED] = "NfcSeConnectedError";
-this.NFC_ERROR_MSG[this.NFC_ERROR_NO_SE_CONNECTED] = "NfcNoSeConnectedError";
 this.NFC_ERROR_MSG[this.NFC_ERROR_NOT_SUPPORTED] = "NfcNotSupportedError";
 this.NFC_ERROR_MSG[this.NFC_ERROR_BAD_SESSION_ID] = "NfcBadSessionIdError";
-this.NFC_ERROR_MSG[this.NFC_ERROR_LOST_TECH] = "NfcLostTechError";
-this.NFC_ERROR_MSG[this.NFC_ERROR_BAD_TECH_TYPE] = "NfcBadTechTypeError";
-this.NFC_ERROR_MSG[this.NFC_ERROR_SELECT_SE_FAIL] = "SelectSecureElementFailed";
-this.NFC_ERROR_MSG[this.NFC_ERROR_DESELECT_SE_FAIL] = "DeselectSecureElementFailed";
 this.NFC_ERROR_MSG[this.NFC_ERROR_FAIL_ENABLE_LOW_POWER_MODE] = "EnableLowPowerModeFail";
 this.NFC_ERROR_MSG[this.NFC_ERROR_FAIL_DISABLE_LOW_POWER_MODE] = "DisableLowPowerModeFail";
 this.NFC_ERROR_MSG[this.NFC_GECKO_ERROR_GENERIC_FAILURE] = "NfcGenericFailureError";
 this.NFC_ERROR_MSG[this.NFC_GECKO_ERROR_P2P_REG_INVALID] = "NfcP2PRegistrationInvalid";
 this.NFC_ERROR_MSG[this.NFC_GECKO_ERROR_NOT_ENABLED] = "NfcNotEnabledError";
 this.NFC_ERROR_MSG[this.NFC_GECKO_ERROR_SEND_FILE_FAILED] = "NfcSendFileFailed";
 
 // NFC powerlevels must match config PDUs.
--- a/dom/settings/SettingsRequestManager.jsm
+++ b/dom/settings/SettingsRequestManager.jsm
@@ -699,17 +699,19 @@ let SettingsRequestManager = {
       this.children.push(aMsgMgr);
       this.mmPrincipals.set(aMsgMgr, aPrincipal);
     }
   },
 
   removeObserver: function(aMsgMgr) {
     if (DEBUG) {
       let principal = this.mmPrincipals.get(aMsgMgr);
-      debug("Remove observer for " + principal.origin);
+      if (principal) {
+        debug("Remove observer for " + principal.origin);
+      }
     }
     let index = this.children.indexOf(aMsgMgr);
     if (index != -1) {
       this.children.splice(index, 1);
       this.mmPrincipals.delete(aMsgMgr);
     }
     if (DEBUG) debug("Principal/MessageManager pairs left: " + this.mmPrincipals.size);
   },
@@ -740,36 +742,41 @@ let SettingsRequestManager = {
     // consumable.
     if (index == 0) {
       this.queueConsume();
     }
   },
 
   removeMessageManager: function(aMsgMgr, aPrincipal) {
     if (DEBUG) debug("Removing message manager");
+    let msgMgrPrincipal = this.mmPrincipals.get(aMsgMgr);
     this.removeObserver(aMsgMgr);
-    let closedLockIDs = [];
+
     let lockIDs = Object.keys(this.lockInfo);
     for (let i in lockIDs) {
-      let lock = this.lockInfo[lockIDs[i]];
-      if (lock._mm == aMsgMgr) {
+      let lockId = lockIDs[i];
+      let lock = this.lockInfo[lockId];
+      if (lock._mm === aMsgMgr && msgMgrPrincipal === aPrincipal) {
         let is_finalizing = false;
-        for (let task_index in lock.tasks) {
-          if (lock.tasks[task_index].operation === "finalize") {
+        let task_index;
+        // Go in reverse order because finalize should be the last one
+        for (task_index = lock.tasks.length; task_index >= 0; task_index--) {
+          if (lock.tasks[task_index]
+              && lock.tasks[task_index].operation === "finalize") {
             is_finalizing = true;
             break;
           }
         }
         if (!is_finalizing) {
-          this.queueTask("finalize", {lockID: lockIDs[i]}, aPrincipal).then(
+          this.queueTask("finalize", {lockID: lockId}, aPrincipal).then(
             function() {
-              if (DEBUG) debug("Lock " + lockIDs[i] + " with dead message manager finalized");
+              if (DEBUG) debug("Lock " + lockId + " with dead message manager finalized");
             },
             function(error) {
-              if (DEBUG) debug("Lock " + lockIDs[i] + " with dead message manager NOT FINALIZED due to error: " + error);
+              if (DEBUG) debug("Lock " + lockId + " with dead message manager NOT FINALIZED due to error: " + error);
             }
           );
         }
       }
     }
   },
 
   receiveMessage: function(aMessage) {
--- a/dom/settings/moz.build
+++ b/dom/settings/moz.build
@@ -18,8 +18,10 @@ if CONFIG['MOZ_B2G']:
     MOCHITEST_CHROME_MANIFESTS += ['tests/chrome.ini']
 
 EXTRA_JS_MODULES += [
     'SettingsDB.jsm',
     'SettingsRequestManager.jsm'
 ]
 
 MOCHITEST_MANIFESTS += ['tests/mochitest.ini']
+
+XPCSHELL_TESTS_MANIFESTS += ['tests/unit/xpcshell.ini']
new file mode 100644
--- /dev/null
+++ b/dom/settings/tests/unit/test_settingsrequestmanager_messages.js
@@ -0,0 +1,154 @@
+"use strict";
+
+const Cu = Components.utils;
+
+Cu.import("resource://gre/modules/XPCOMUtils.jsm");
+Cu.import("resource://gre/modules/Services.jsm");
+
+XPCOMUtils.defineLazyServiceGetter(this, "cpmm",
+                                   "@mozilla.org/childprocessmessagemanager;1",
+                                   "nsIMessageSender");
+
+let principal = Services.scriptSecurityManager.getSystemPrincipal();
+let lockID = "{435d2192-4f21-48d4-90b7-285f147a56be}";
+
+// Helper to start the Settings Request Manager
+function startSettingsRequestManager() {
+  Cu.import("resource://gre/modules/SettingsRequestManager.jsm");
+}
+
+// Helper function to add a listener, send message and treat the reply
+function addAndSend(msg, reply, callback, payload, runNext = true) {
+  let handler = {
+    receiveMessage: function(message) {
+      if (message.name === reply) {
+        cpmm.removeMessageListener(reply, handler);
+        callback(message);
+        if (runNext) {
+          run_next_test();
+        }
+      }
+    }
+  };
+  cpmm.addMessageListener(reply, handler);
+  cpmm.sendAsyncMessage(msg, payload, undefined, principal);
+}
+
+// We need to trigger a Settings:Run message to make the queue progress
+function send_settingsRun() {
+  let msg = {lockID: lockID, isServiceLock: true};
+  cpmm.sendAsyncMessage("Settings:Run", msg, undefined, principal);
+}
+
+function kill_child() {
+  let msg = {lockID: lockID, isServiceLock: true};
+  cpmm.sendAsyncMessage("child-process-shutdown", msg, undefined, principal);
+}
+
+function run_test() {
+  do_get_profile();
+  startSettingsRequestManager();
+  run_next_test();
+}
+
+add_test(function test_createLock() {
+  let msg = {lockID: lockID, isServiceLock: true};
+  cpmm.sendAsyncMessage("Settings:CreateLock", msg, undefined, principal);
+  cpmm.sendAsyncMessage(
+    "Settings:RegisterForMessages", undefined, undefined, principal);
+  ok(true);
+  run_next_test();
+});
+
+add_test(function test_get_empty() {
+  let requestID = 10;
+  let msgReply = "Settings:Get:OK";
+  let msgHandler = function(message) {
+    equal(requestID, message.data.requestID);
+    equal(lockID, message.data.lockID);
+    ok(Object.keys(message.data.settings).length >= 0);
+  };
+
+  addAndSend("Settings:Get", msgReply, msgHandler, {
+    requestID: requestID,
+    lockID: lockID,
+    name: "language.current"
+  });
+
+  send_settingsRun();
+});
+
+add_test(function test_set_get_nonempty() {
+  let settings = { "language.current": "fr-FR:XPC" };
+  let requestIDSet = 20;
+  let msgReplySet = "Settings:Set:OK";
+  let msgHandlerSet = function(message) {
+    equal(requestIDSet, message.data.requestID);
+    equal(lockID, message.data.lockID);
+  };
+
+  addAndSend("Settings:Set", msgReplySet, msgHandlerSet, {
+    requestID: requestIDSet,
+    lockID: lockID,
+    settings: settings
+  }, false);
+
+  let requestIDGet = 25;
+  let msgReplyGet = "Settings:Get:OK";
+  let msgHandlerGet = function(message) {
+    equal(requestIDGet, message.data.requestID);
+    equal(lockID, message.data.lockID);
+    for(let p in settings) {
+      equal(settings[p], message.data.settings[p]);
+    }
+  };
+
+  addAndSend("Settings:Get", msgReplyGet, msgHandlerGet, {
+    requestID: requestIDGet,
+    lockID: lockID,
+    name: Object.keys(settings)[0]
+  });
+
+  // Set and Get have been push into the queue, let's run
+  send_settingsRun();
+});
+
+// This test exposes bug 1076597 behavior
+add_test(function test_wait_for_finalize() {
+  let settings = { "language.current": "en-US:XPC" };
+  let requestIDSet = 30;
+  let msgReplySet = "Settings:Set:OK";
+  let msgHandlerSet = function(message) {
+    equal(requestIDSet, message.data.requestID);
+    equal(lockID, message.data.lockID);
+  };
+
+  addAndSend("Settings:Set", msgReplySet, msgHandlerSet, {
+    requestID: requestIDSet,
+    lockID: lockID,
+    settings: settings
+  }, false);
+
+  let requestIDGet = 35;
+  let msgReplyGet = "Settings:Get:OK";
+  let msgHandlerGet = function(message) {
+    equal(requestIDGet, message.data.requestID);
+    equal(lockID, message.data.lockID);
+    for(let p in settings) {
+      equal(settings[p], message.data.settings[p]);
+    }
+  };
+
+  addAndSend("Settings:Get", msgReplyGet, msgHandlerGet, {
+    requestID: requestIDGet,
+    lockID: lockID,
+    name: Object.keys(settings)[0]
+  });
+
+  // We simulate a child death, which will force previous requests to be set
+  // into finalize state
+  kill_child();
+
+  // Then when we issue Settings:Run, those finalized should be triggered
+  send_settingsRun();
+});
new file mode 100644
--- /dev/null
+++ b/dom/settings/tests/unit/xpcshell.ini
@@ -0,0 +1,6 @@
+[DEFAULT]
+head =
+tail =
+
+[test_settingsrequestmanager_messages.js]
+skip-if = ((buildapp != 'b2g') || ((toolkit == 'gonk') && debug)) # bug 1080377: for some reason, this is not working on emulator-b2g debug build
--- a/dom/system/gonk/ril_worker.js
+++ b/dom/system/gonk/ril_worker.js
@@ -343,17 +343,17 @@ TelephonyRequestQueue.prototype = {
  * via post messages. It maintains state about the radio, ICC, calls, etc.
  * and acts upon state changes accordingly.
  */
 function RilObject(aContext) {
   this.context = aContext;
 
   this.telephonyRequestQueue = new TelephonyRequestQueue(this);
   this.currentCalls = {};
-  this.currentConference = {state: null, participants: {}};
+  this.currentConferenceState = CALL_STATE_UNKNOWN;
   this.currentDataCalls = {};
   this._pendingSentSmsMap = {};
   this.pendingNetworkType = {};
   this._receivedSmsCbPagesMap = {};
   this._getCurrentCallsRetryCount = 0;
 
   // Init properties that are only initialized once.
   this.v5Legacy = RILQUIRKS_V5_LEGACY;
@@ -370,19 +370,19 @@ RilObject.prototype = {
   v5Legacy: null,
 
   /**
    * Valid calls.
    */
   currentCalls: null,
 
   /**
-   * Existing conference call and its participants.
-   */
-  currentConference: null,
+   * Call state of current conference group.
+   */
+  currentConferenceState: null,
 
   /**
    * Existing data calls.
    */
   currentDataCalls: null,
 
   /**
    * Outgoing messages waiting for SMS-STATUS-REPORT.
@@ -1914,34 +1914,21 @@ RilObject.prototype = {
     if (this._isCdma) {
       options.featureStr = "";
       this.sendCdmaFlashCommand(options);
     } else if (call.state == CALL_STATE_HOLDING) {
       this.sendSwitchWaitingRequest();
     }
   },
 
-  // Flag indicating whether user has requested making a conference call.
-  _hasConferenceRequest: false,
-
   conferenceCall: function(options) {
     if (this._isCdma) {
       options.featureStr = "";
       this.sendCdmaFlashCommand(options);
     } else {
-      // Only accept one conference request at a time..
-      if (this._hasConferenceRequest) {
-        options.success = false;
-        options.errorName = "addError";
-        options.errorMsg = GECKO_ERROR_GENERIC_FAILURE;
-        this.sendChromeMessage(options);
-        return;
-      }
-
-      this._hasConferenceRequest = true;
       this.telephonyRequestQueue.push(REQUEST_CONFERENCE,
                                       this.sendRilRequestConference, options);
     }
   },
 
   sendRilRequestConference: function(options) {
     this.context.Buf.simpleRequest(REQUEST_CONFERENCE, options);
   },
@@ -3828,181 +3815,194 @@ RilObject.prototype = {
       // do it by ourself.
       if (!this.overrideICCNetworkName()) {
         this._sendNetworkInfoMessage(NETWORK_INFO_OPERATOR, this.operator);
       }
     }
   },
 
   /**
-   * Helpers for processing call state and handle the active call.
-   */
-  _processCalls: function(newCalls) {
-    let conferenceChanged = false;
-    let clearConferenceRequest = false;
-
-    // Go through the calls we currently have on file and see if any of them
-    // changed state. Remove them from the newCalls map as we deal with them
-    // so that only new calls remain in the map after we're done.
+   * Classify new calls into three groups: (removed, remained, added).
+   */
+  _classifyCalls: function(newCalls) {
+    newCalls = newCalls || {};
+
+    let removedCalls = [];
+    let remainedCalls = [];
+    let addedCalls = [];
+
     for each (let currentCall in this.currentCalls) {
-      let newCall;
-      if (newCalls) {
-        newCall = newCalls[currentCall.callIndex];
-        delete newCalls[currentCall.callIndex];
-      }
-
-      // Call is no longer reported by the radio. Remove from our map and send
-      // disconnected state change.
+      let newCall = newCalls[currentCall.callIndex];
       if (!newCall) {
-        if (this.currentConference.participants[currentCall.callIndex]) {
-          conferenceChanged = true;
-        }
-        this._removeVoiceCall(currentCall,
-                              currentCall.hangUpLocal ?
-                                GECKO_CALL_ERROR_NORMAL_CALL_CLEARING : null);
-        continue;
-      }
-
-      // Call is still valid.
-      if (newCall.state == currentCall.state &&
-          newCall.isMpty == currentCall.isMpty) {
-        continue;
-      }
-
-      // State has changed.
-      if (newCall.state == CALL_STATE_INCOMING &&
-          currentCall.state == CALL_STATE_WAITING) {
-        // Update the call internally but we don't notify chrome since these two
-        // states are viewed as the same one there.
-        currentCall.state = newCall.state;
-        continue;
-      }
-
-      if (!currentCall.started && newCall.state == CALL_STATE_ACTIVE) {
-        currentCall.started = new Date().getTime();
-      }
-
-      if (currentCall.isMpty == newCall.isMpty &&
-          newCall.state != currentCall.state) {
-        currentCall.state = newCall.state;
-        if (currentCall.isConference) {
-          conferenceChanged = true;
-        }
-        this._handleChangedCallState(currentCall);
-        continue;
-      }
-
-      // '.isMpty' becomes false when the conference call is put on hold.
-      // We need to introduce additional 'isConference' to correctly record the
-      // real conference status
-
-      // Update a possible conference participant when .isMpty changes.
-      if (!currentCall.isMpty && newCall.isMpty) {
-        if (this._hasConferenceRequest) {
-          conferenceChanged = true;
-          clearConferenceRequest = true;
-          currentCall.state = newCall.state;
-          currentCall.isMpty = newCall.isMpty;
-          currentCall.isConference = true;
-          this.currentConference.participants[currentCall.callIndex] = currentCall;
-          this._handleChangedCallState(currentCall);
-        } else if (currentCall.isConference) {
-          // The case happens when resuming a held conference call.
-          conferenceChanged = true;
-          currentCall.state = newCall.state;
-          currentCall.isMpty = newCall.isMpty;
-          this.currentConference.participants[currentCall.callIndex] = currentCall;
-          this._handleChangedCallState(currentCall);
-        } else {
-          // Weird. This sometimes happens when we switch two calls, but it is
-          // not a conference call.
-          currentCall.state = newCall.state;
-          this._handleChangedCallState(currentCall);
-        }
-      } else if (currentCall.isMpty && !newCall.isMpty) {
-        if (!this.currentConference.participants[newCall.callIndex]) {
-          continue;
-        }
-
-        // '.isMpty' of a conference participant is set to false by rild when
-        // the conference call is put on hold. We don't actually know if the call
-        // still attends the conference until updating all calls finishes. We
-        // cache it for further determination.
-        if (newCall.state != CALL_STATE_HOLDING) {
-          delete this.currentConference.participants[newCall.callIndex];
-          currentCall.state = newCall.state;
-          currentCall.isMpty = newCall.isMpty;
-          currentCall.isConference = false;
-          conferenceChanged = true;
-          this._handleChangedCallState(currentCall);
-          continue;
-        }
-
-        if (!this.currentConference.cache) {
-          this.currentConference.cache = {};
-        }
-        this.currentConference.cache[currentCall.callIndex] = newCall;
-        currentCall.state = newCall.state;
-        currentCall.isMpty = newCall.isMpty;
-        conferenceChanged = true;
-      }
-    }
-
-    // We have a successful dialing request. Check whether we could find a new
-    // call for it.
-    if (this.pendingMO) {
-      let options = this.pendingMO.options;
-      this.pendingMO = null;
-
-      // Find the callIndex of the new outgoing call.
-      let callIndex = -1;
-      for (let i in newCalls) {
-        if (newCalls[i].state !== CALL_STATE_INCOMING) {
-          callIndex = newCalls[i].callIndex;
-          newCalls[i].isEmergency = options.isEmergency;
-          break;
-        }
-      }
-
-      if (callIndex === -1) {
-        // The call doesn't exist.
-        options.success = false;
-        options.errorMsg = GECKO_CALL_ERROR_UNSPECIFIED;
-        this.sendChromeMessage(options);
+        removedCalls.push(currentCall);
       } else {
-        options.success = true;
-        options.callIndex = callIndex;
-        this.sendChromeMessage(options);
+        remainedCalls.push(newCall);
+        delete newCalls[currentCall.callIndex];
       }
     }
 
     // Go through any remaining calls that are new to us.
     for each (let newCall in newCalls) {
-      if (!newCall.isVoice) {
+      if (newCall.isVoice) {
+        addedCalls.push(newCall);
+      }
+    }
+
+    return [removedCalls, remainedCalls, addedCalls];
+  },
+
+  /**
+   * Check the calls in addedCalls and assign an appropriate one to pendingMO.
+   * Also update the |isEmergency| on that call.
+   */
+  _assignPendingMO: function(addedCalls) {
+    let options = this.pendingMO.options;
+    this.pendingMO = null;
+
+    for (let call of addedCalls) {
+      if (call.state !== CALL_STATE_INCOMING) {
+        call.isEmergency = options.isEmergency;
+        options.success = true;
+        options.callIndex = call.callIndex;
+        this.sendChromeMessage(options);
+        return;
+      }
+    }
+
+    // The call doesn't exist.
+    options.success = false;
+    options.errorMsg = GECKO_CALL_ERROR_UNSPECIFIED;
+    this.sendChromeMessage(options);
+  },
+
+  /**
+   * Check the currentCalls and identify the conference group.
+   * Return the conference state and the group as a set.
+   */
+  _detectConference: function() {
+    // There are some difficuties to identify the conference by |.isMpty| so we
+    // don't rely on this flag.
+    //  - |.isMpty| becomes false when the conference call is put on hold.
+    //  - |.isMpty| may remain true when other participants left the conference.
+
+    // All the calls in the conference should have the same state and it is
+    // either ACTIVE or HOLDING. That means, if we find a group of call with
+    // the same state and its size is larger than 2, it must be a conference.
+    let activeCalls = new Set();
+    let holdingCalls = new Set();
+
+    for each (let call in this.currentCalls) {
+      if (call.state === CALL_STATE_ACTIVE) {
+        activeCalls.add(call);
+      } else if (call.state === CALL_STATE_HOLDING) {
+        holdingCalls.add(call);
+      }
+    }
+
+    if (activeCalls.size >= 2) {
+      return [CALL_STATE_ACTIVE, activeCalls];
+    } else if (holdingCalls.size >= 2) {
+      return [CALL_STATE_HOLDING, holdingCalls];
+    }
+
+    return [CALL_STATE_UNKNOWN, new Set()];
+  },
+
+  /**
+   * Helpers for processing call state changes.
+   */
+  _processClassifiedCalls: function(removedCalls, remainedCalls, addedCalls,
+                                    failCause) {
+    // Handle removed calls.
+    for (let call of removedCalls) {
+      this._removeVoiceCall(call, call.hangUpLocal ?
+                            GECKO_CALL_ERROR_NORMAL_CALL_CLEARING : failCause);
+    }
+
+    let changedCalls = new Set();
+
+    // Handle remained calls.
+    for (let newCall of remainedCalls) {
+      let oldCall = this.currentCalls[newCall.callIndex];
+      if (oldCall.state == newCall.state) {
         continue;
       }
 
-      if (newCall.isMpty) {
-        conferenceChanged = true;
-      }
-
-      this._addNewVoiceCall(newCall);
-    }
-
-    if (clearConferenceRequest) {
-      this._hasConferenceRequest = false;
-    }
-    if (conferenceChanged) {
-      this._ensureConference();
-    }
-
-    // Update audio state.
-    let message = {rilMessageType: "audioStateChanged",
-                   state: this._detectAudioState()};
-    this.sendChromeMessage(message);
+      if (oldCall.state == CALL_STATE_WAITING &&
+          newCall.state == CALL_STATE_INCOMING) {
+        // Update the call internally but we don't notify chrome since these two
+        // states are viewed as the same one there.
+        oldCall.state = newCall.state;
+        continue;
+      }
+
+      if (!oldCall.started && newCall.state == CALL_STATE_ACTIVE) {
+        oldCall.started = new Date().getTime();
+      }
+
+      oldCall.state = newCall.state;
+      changedCalls.add(oldCall);
+    }
+
+    // Handle pendingMO.
+    if (this.pendingMO) {
+      this._assignPendingMO(addedCalls);
+    }
+
+    // Handle added calls.
+    for (let call of addedCalls) {
+      this._addVoiceCall(call);
+      changedCalls.add(call);
+    }
+
+    // Detect conference and update isConference flag.
+    let [newConferenceState, conference] = this._detectConference();
+    for each (let call in this.currentCalls) {
+      let isConference = conference.has(call);
+      if (call.isConference != isConference) {
+        call.isConference = isConference;
+        changedCalls.add(call);
+      }
+    }
+
+    // Update audio state. We have to send the message before callstatechange
+    // to make sure that the audio state is ready first.
+    this.sendChromeMessage({
+      rilMessageType: "audioStateChanged",
+      state: this._detectAudioState()
+    });
+
+    // Notify call state change.
+    for (let call of changedCalls) {
+      this._handleChangedCallState(call);
+    }
+
+    // Notify conference state change.
+    if (this.currentConferenceState != newConferenceState) {
+      this.currentConferenceState = newConferenceState;
+      let message = {rilMessageType: "conferenceCallStateChanged",
+                     state: newConferenceState};
+      this.sendChromeMessage(message);
+    }
+  },
+
+  _processCalls: function(newCalls) {
+    let [removed, remained, added] = this._classifyCalls(newCalls);
+
+    // Let's get the failCause first if there are removed calls. Otherwise, we
+    // need to trigger another async request when removing call and it cause
+    // the order of callDisconnected and conferenceCallStateChanged
+    // unpredictable.
+    if (removed.length) {
+      this.getFailCauseCode((function(removed, remained, added, failCause) {
+        this._processClassifiedCalls(removed, remained, added, failCause);
+      }).bind(this, removed, remained, added));
+    } else {
+      this._processClassifiedCalls(removed, remained, added);
+    }
   },
 
   _detectAudioState: function() {
     let callNum = Object.keys(this.currentCalls).length;
     if (!callNum) {
       return AUDIO_STATE_NO_CALL;
     }
 
@@ -4010,100 +4010,33 @@ RilObject.prototype = {
     if (callNum == 1 &&
         this.currentCalls[firstIndex].state == CALL_STATE_INCOMING) {
       return AUDIO_STATE_INCOMING;
     }
 
     return AUDIO_STATE_IN_CALL;
   },
 
-  _addNewVoiceCall: function(newCall) {
+  _addVoiceCall: function(newCall) {
     // Format international numbers appropriately.
     if (newCall.number && newCall.toa == TOA_INTERNATIONAL &&
         newCall.number[0] != "+") {
       newCall.number = "+" + newCall.number;
     }
 
-    if (newCall.state == CALL_STATE_INCOMING) {
-      newCall.isOutgoing = false;
-    } else if (newCall.state == CALL_STATE_DIALING) {
-      newCall.isOutgoing = true;
-    }
-
-    // Set flag for conference.
-    newCall.isConference = newCall.isMpty ? true : false;
-
-    // Add to our map.
-    if (newCall.isMpty) {
-      this.currentConference.participants[newCall.callIndex] = newCall;
-    }
-    this._handleChangedCallState(newCall);
+    newCall.isOutgoing = !(newCall.state == CALL_STATE_INCOMING);
+    newCall.isConference = false;
+
     this.currentCalls[newCall.callIndex] = newCall;
   },
 
-  _removeVoiceCall: function(removedCall, failCause) {
-    if (this.currentConference.participants[removedCall.callIndex]) {
-      removedCall.isConference = false;
-      delete this.currentConference.participants[removedCall.callIndex];
-      delete this.currentCalls[removedCall.callIndex];
-      // We don't query the fail cause here as it triggers another asynchrouns
-      // request that leads to a problem of updating all conferece participants
-      // in one task.
-      this._handleDisconnectedCall(removedCall);
-    } else {
-      delete this.currentCalls[removedCall.callIndex];
-      if (failCause) {
-        removedCall.failCause = failCause;
-        this._handleDisconnectedCall(removedCall);
-      } else {
-        this.getFailCauseCode((function(call, failCause) {
-          call.failCause = failCause;
-          this._handleDisconnectedCall(call);
-        }).bind(this, removedCall));
-      }
-    }
-  },
-
-  _ensureConference: function() {
-    let oldState = this.currentConference.state;
-    let remaining = Object.keys(this.currentConference.participants);
-
-    if (remaining.length == 1) {
-      // Remove that if only does one remain in a conference call.
-      let call = this.currentCalls[remaining[0]];
-      call.isConference = false;
-      this._handleChangedCallState(call);
-      delete this.currentConference.participants[call.callIndex];
-    } else if (remaining.length > 1) {
-      for each (let call in this.currentConference.cache) {
-        call.isConference = true;
-        this.currentConference.participants[call.callIndex] = call;
-        this.currentCalls[call.callIndex] = call;
-        this._handleChangedCallState(call);
-      }
-    }
-    delete this.currentConference.cache;
-
-    // Update the conference call's state.
-    let state = CALL_STATE_UNKNOWN;
-    for each (let call in this.currentConference.participants) {
-      if (state != CALL_STATE_UNKNOWN && state != call.state) {
-        // Each participant should have the same state, otherwise something
-        // wrong happens.
-        state = CALL_STATE_UNKNOWN;
-        break;
-      }
-      state = call.state;
-    }
-    if (oldState != state) {
-      this.currentConference.state = state;
-      let message = {rilMessageType: "conferenceCallStateChanged",
-                     state: state};
-      this.sendChromeMessage(message);
-    }
+  _removeVoiceCall: function(call, failCause) {
+    delete this.currentCalls[call.callIndex];
+    call.failCause = failCause;
+    this._handleDisconnectedCall(call);
   },
 
   _handleChangedCallState: function(changedCall) {
     let message = {rilMessageType: "callStateChange",
                    call: changedCall};
     this.sendChromeMessage(message);
   },
 
@@ -5523,17 +5456,16 @@ RilObject.prototype[REQUEST_SWITCH_WAITI
     return;
   }
 
   this.getCurrentCalls();
 };
 RilObject.prototype[REQUEST_CONFERENCE] = function REQUEST_CONFERENCE(length, options) {
   options.success = (options.rilRequestError === 0);
   if (!options.success) {
-    this._hasConferenceRequest = false;
     options.errorName = "addError";
     options.errorMsg = RIL_ERROR_TO_GECKO_ERROR[options.rilRequestError];
     this.sendChromeMessage(options);
     return;
   }
 
   this.sendChromeMessage(options);
 };
--- a/dom/telephony/Telephony.cpp
+++ b/dom/telephony/Telephony.cpp
@@ -490,16 +490,21 @@ Telephony::CallStateChanged(uint32_t aSe
       = GetCallFromEverywhere(aServiceId, aCallIndex);
 
   if (modifiedCall) {
     modifiedCall->UpdateEmergency(aIsEmergency);
     modifiedCall->UpdateSwitchable(aIsSwitchable);
     modifiedCall->UpdateMergeable(aIsMergeable);
 
     if (modifiedCall->CallState() != aCallState) {
+      if (aCallState == nsITelephonyService::CALL_STATE_DISCONNECTED) {
+        modifiedCall->ChangeStateInternal(aCallState, true);
+        return NS_OK;
+      }
+
       // We don't fire the statechange event on a call in conference here.
       // Instead, the event will be fired later in
       // TelephonyCallGroup::ChangeState(). Thus the sequence of firing the
       // statechange events is guaranteed: first on TelephonyCallGroup then on
       // individual TelephonyCall objects.
       bool fireEvent = !aIsConference;
       modifiedCall->ChangeStateInternal(aCallState, fireEvent);
     }
--- a/dom/telephony/test/marionette/head.js
+++ b/dom/telephony/test/marionette/head.js
@@ -223,36 +223,45 @@ let emulator = (function() {
    * Convenient helper to compare a TelephonyCall and a received call event.
    */
   function checkEventCallState(event, call, state) {
     is(call, event.call, "event.call");
     is(call.state, state, "call state");
   }
 
   /**
+   * Convenient helper to compare two call lists. Size should be the same and
+   * order is not important.
+   */
+  function checkCalls(actualCalls, expectedCalls) {
+    if (actualCalls.length == expectedCalls.length) {
+      let expectedSet = new Set(expectedCalls);
+      for (let i = 0; i < actualCalls.length; ++i) {
+        ok(expectedSet.has(actualCalls[i]), "should contain the call");
+      }
+    }
+  }
+
+  /**
    * Convenient helper to check mozTelephony.active and mozTelephony.calls.
    */
   function checkTelephonyActiveAndCalls(active, calls) {
     is(telephony.active, active, "telephony.active");
     is(telephony.calls.length, calls.length, "telephony.calls");
-    for (let i = 0; i < calls.length; ++i) {
-      is(telephony.calls[i], calls[i]);
-    }
+    checkCalls(telephony.calls, calls);
   }
 
   /**
    * Convenient helper to check mozTelephony.conferenceGroup.state and
    * .conferenceGroup.calls.
    */
   function checkConferenceStateAndCalls(state, calls) {
     is(conference.state, state, "conference.state");
     is(conference.calls.length, calls.length, "conference.calls");
-    for (let i = 0; i < calls.length; i++) {
-      is(conference.calls[i], calls[i]);
-    }
+    checkCalls(conference.calls, calls);
   }
 
   /**
    * Convenient helper to handle *.oncallschanged event.
    *
    * @param container
    *        Representation of "mozTelephony" or "mozTelephony.conferenceGroup."
    * @param containerName
--- a/ipc/unixsocket/SocketBase.cpp
+++ b/ipc/unixsocket/SocketBase.cpp
@@ -10,66 +10,137 @@
 #include <errno.h>
 #include <string.h>
 #include <unistd.h>
 
 namespace mozilla {
 namespace ipc {
 
 //
-// UnixSocketRawData
+// UnixSocketIOBuffer
 //
 
-UnixSocketRawData::UnixSocketRawData(const void* aData, size_t aSize)
+UnixSocketIOBuffer::UnixSocketIOBuffer(const void* aData, size_t aSize)
 : mSize(aSize)
 , mOffset(0)
 , mAvailableSpace(aSize)
 {
   MOZ_ASSERT(aData || !mSize);
 
   mData = new uint8_t[mAvailableSpace];
   memcpy(mData, aData, mSize);
 }
 
-UnixSocketRawData::UnixSocketRawData(size_t aSize)
+UnixSocketIOBuffer::UnixSocketIOBuffer(size_t aAvailableSpace)
 : mSize(0)
 , mOffset(0)
-, mAvailableSpace(aSize)
+, mAvailableSpace(aAvailableSpace)
 {
   mData = new uint8_t[mAvailableSpace];
 }
 
+UnixSocketIOBuffer::~UnixSocketIOBuffer()
+{ }
+
+const uint8_t*
+UnixSocketIOBuffer::Consume(size_t aLen)
+{
+  if (NS_WARN_IF(GetSize() < aLen)) {
+    return nullptr;
+  }
+  uint8_t* data = mData + mOffset;
+  mOffset += aLen;
+  return data;
+}
+
+nsresult
+UnixSocketIOBuffer::Read(void* aValue, size_t aLen)
+{
+  const uint8_t* data = Consume(aLen);
+  if (!data) {
+    return NS_ERROR_OUT_OF_MEMORY;
+  }
+  memcpy(aValue, data, aLen);
+  return NS_OK;
+}
+
+uint8_t*
+UnixSocketIOBuffer::Append(size_t aLen)
+{
+  if (((mAvailableSpace - mSize) < aLen)) {
+    size_t availableSpace = mAvailableSpace + std::max(mAvailableSpace, aLen);
+    uint8_t* data = new uint8_t[availableSpace];
+    memcpy(data, mData, mSize);
+    mData = data;
+    mAvailableSpace = availableSpace;
+  }
+  uint8_t* data = mData + mSize;
+  mSize += aLen;
+  return data;
+}
+
+nsresult
+UnixSocketIOBuffer::Write(const void* aValue, size_t aLen)
+{
+  uint8_t* data = Append(aLen);
+  if (!data) {
+    return NS_ERROR_OUT_OF_MEMORY;
+  }
+  memcpy(data, aValue, aLen);
+  return NS_OK;
+}
+
+void
+UnixSocketIOBuffer::CleanupLeadingSpace()
+{
+  if (GetLeadingSpace()) {
+    if (GetSize() <= GetLeadingSpace()) {
+      memcpy(mData, GetData(), GetSize());
+    } else {
+      memmove(mData, GetData(), GetSize());
+    }
+    mOffset = 0;
+  }
+}
+
+//
+// UnixSocketRawData
+//
+
+UnixSocketRawData::UnixSocketRawData(const void* aData, size_t aSize)
+: UnixSocketIOBuffer(aData, aSize)
+{ }
+
+UnixSocketRawData::UnixSocketRawData(size_t aSize)
+: UnixSocketIOBuffer(aSize)
+{ }
+
 ssize_t
 UnixSocketRawData::Receive(int aFd)
 {
   if (!GetTrailingSpace()) {
     if (!GetLeadingSpace()) {
       return -1; /* buffer is full */
     }
     /* free up space at the end of data buffer */
-    if (GetSize() <= GetLeadingSpace()) {
-      memcpy(mData, GetData(), GetSize());
-    } else {
-      memmove(mData, GetData(), GetSize());
-    }
-    mOffset = 0;
+    CleanupLeadingSpace();
   }
 
   ssize_t res =
     TEMP_FAILURE_RETRY(read(aFd, GetTrailingBytes(), GetTrailingSpace()));
 
   if (res < 0) {
     /* I/O error */
     return -1;
   } else if (!res) {
     /* EOF or peer shutdown sending */
     return 0;
   }
 
-  mSize += res;
+  Append(res); /* mark read data as 'valid' */
 
   return res;
 }
 
 ssize_t
 UnixSocketRawData::Send(int aFd)
 {
   if (!GetSize()) {
@@ -89,74 +160,74 @@ UnixSocketRawData::Send(int aFd)
   }
 
   Consume(res);
 
   return res;
 }
 
 //
-// SocketConsumerBase
+// SocketBase
 //
 
-SocketConsumerBase::~SocketConsumerBase()
+SocketBase::~SocketBase()
 {
   MOZ_ASSERT(mConnectionStatus == SOCKET_DISCONNECTED);
 }
 
 SocketConnectionStatus
-SocketConsumerBase::GetConnectionStatus() const
+SocketBase::GetConnectionStatus() const
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   return mConnectionStatus;
 }
 
 int
-SocketConsumerBase::GetSuggestedConnectDelayMs() const
+SocketBase::GetSuggestedConnectDelayMs() const
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   return mConnectDelayMs;
 }
 
 void
-SocketConsumerBase::NotifySuccess()
+SocketBase::NotifySuccess()
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   mConnectionStatus = SOCKET_CONNECTED;
   mConnectTimestamp = PR_IntervalNow();
   OnConnectSuccess();
 }
 
 void
-SocketConsumerBase::NotifyError()
+SocketBase::NotifyError()
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   mConnectionStatus = SOCKET_DISCONNECTED;
   mConnectDelayMs = CalculateConnectDelayMs();
   mConnectTimestamp = 0;
   OnConnectError();
 }
 
 void
-SocketConsumerBase::NotifyDisconnect()
+SocketBase::NotifyDisconnect()
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   mConnectionStatus = SOCKET_DISCONNECTED;
   mConnectDelayMs = CalculateConnectDelayMs();
   mConnectTimestamp = 0;
   OnDisconnect();
 }
 
 uint32_t
-SocketConsumerBase::CalculateConnectDelayMs() const
+SocketBase::CalculateConnectDelayMs() const
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   uint32_t connectDelayMs = mConnectDelayMs;
 
   if (mConnectTimestamp && (PR_IntervalNow()-mConnectTimestamp) > connectDelayMs) {
     // reset delay if connection has been opened for a while, or...
     connectDelayMs = 0;
@@ -165,30 +236,36 @@ SocketConsumerBase::CalculateConnectDela
     connectDelayMs = 1<<10;
   } else if (connectDelayMs < (1<<16)) {
     // ...otherwise increase delay by a factor of 2
     connectDelayMs <<= 1;
   }
   return connectDelayMs;
 }
 
-SocketConsumerBase::SocketConsumerBase()
+SocketBase::SocketBase()
 : mConnectionStatus(SOCKET_DISCONNECTED)
 , mConnectTimestamp(0)
 , mConnectDelayMs(0)
 { }
 
 void
-SocketConsumerBase::SetConnectionStatus(
-  SocketConnectionStatus aConnectionStatus)
+SocketBase::SetConnectionStatus(SocketConnectionStatus aConnectionStatus)
 {
   mConnectionStatus = aConnectionStatus;
 }
 
 //
+// SocketConsumerBase
+//
+
+SocketConsumerBase::~SocketConsumerBase()
+{ }
+
+//
 // SocketIOBase
 //
 
 SocketIOBase::~SocketIOBase()
 { }
 
 void
 SocketIOBase::EnqueueData(UnixSocketRawData* aData)
--- a/ipc/unixsocket/SocketBase.h
+++ b/ipc/unixsocket/SocketBase.h
@@ -18,20 +18,162 @@
 #include "GeckoTaskTracer.h"
 using namespace mozilla::tasktracer;
 #endif
 
 namespace mozilla {
 namespace ipc {
 
 //
+// UnixSocketIOBuffer
+//
+
+class UnixSocketIOBuffer
+{
+public:
+  const uint8_t* GetData() const
+  {
+    return mData + mOffset;
+  }
+
+  size_t GetSize() const
+  {
+    return mSize - mOffset;
+  }
+
+  const uint8_t* Consume(size_t aLen);
+
+  nsresult Read(void* aValue, size_t aLen);
+
+  nsresult Read(int8_t& aValue)
+  {
+    return Read(&aValue, sizeof(aValue));
+  }
+
+  nsresult Read(uint8_t& aValue)
+  {
+    return Read(&aValue, sizeof(aValue));
+  }
+
+  nsresult Read(int16_t& aValue)
+  {
+    return Read(&aValue, sizeof(aValue));
+  }
+
+  nsresult Read(uint16_t& aValue)
+  {
+    return Read(&aValue, sizeof(aValue));
+  }
+
+  nsresult Read(int32_t& aValue)
+  {
+    return Read(&aValue, sizeof(aValue));
+  }
+
+  nsresult Read(uint32_t& aValue)
+  {
+    return Read(&aValue, sizeof(aValue));
+  }
+
+  uint8_t* Append(size_t aLen);
+
+  nsresult Write(const void* aValue, size_t aLen);
+
+  nsresult Write(int8_t aValue)
+  {
+    return Write(&aValue, sizeof(aValue));
+  }
+
+  nsresult Write(uint8_t aValue)
+  {
+    return Write(&aValue, sizeof(aValue));
+  }
+
+  nsresult Write(int16_t aValue)
+  {
+    return Write(&aValue, sizeof(aValue));
+  }
+
+  nsresult Write(uint16_t aValue)
+  {
+    return Write(&aValue, sizeof(aValue));
+  }
+
+  nsresult Write(int32_t aValue)
+  {
+    return Write(&aValue, sizeof(aValue));
+  }
+
+  nsresult Write(uint32_t aValue)
+  {
+    return Write(&aValue, sizeof(aValue));
+  }
+
+protected:
+
+  /* This constructor copies aData of aSize bytes length into the
+   * new instance of |UnixSocketIOBuffer|.
+   */
+  UnixSocketIOBuffer(const void* aData, size_t aSize);
+
+  /* This constructor reserves aAvailableSpace bytes of space.
+   */
+  UnixSocketIOBuffer(size_t aAvailableSpace);
+
+  ~UnixSocketIOBuffer();
+
+  size_t GetLeadingSpace() const
+  {
+    return mOffset;
+  }
+
+  size_t GetTrailingSpace() const
+  {
+    return mAvailableSpace - mSize;
+  }
+
+  size_t GetAvailableSpace() const
+  {
+    return mAvailableSpace;
+  }
+
+  void* GetTrailingBytes()
+  {
+    return mData + mSize;
+  }
+
+  uint8_t* GetData(size_t aOffset)
+  {
+    MOZ_ASSERT(aOffset <= mSize);
+
+    return mData + aOffset;
+  }
+
+  void SetRange(size_t aOffset, size_t aSize)
+  {
+    MOZ_ASSERT((aOffset + aSize) <= mAvailableSpace);
+
+    mOffset = aOffset;
+    mSize = mOffset + aSize;
+  }
+
+  void CleanupLeadingSpace();
+
+private:
+  size_t mSize;
+  size_t mOffset;
+  size_t mAvailableSpace;
+  nsAutoArrayPtr<uint8_t> mData;
+};
+
+//
 // UnixSocketRawData
 //
 
-class UnixSocketRawData
+class UnixSocketRawData MOZ_FINAL : public UnixSocketIOBuffer
 {
 public:
   /* This constructor copies aData of aSize bytes length into the
    * new instance of |UnixSocketRawData|.
    */
   UnixSocketRawData(const void* aData, size_t aSize);
 
   /* This constructor reserves aSize bytes of space. Currently
@@ -46,110 +188,47 @@ public:
    */
   ssize_t Receive(int aFd);
 
   /**
    * Sends data to aFd from the beginning of the buffer. The returned value
    * is the number of bytes written, or a negative value on error.
    */
   ssize_t Send(int aFd);
-
-  const uint8_t* GetData() const
-  {
-    return mData + mOffset;
-  }
-
-  size_t GetSize() const
-  {
-    return mSize;
-  }
-
-  void Consume(size_t aSize)
-  {
-    MOZ_ASSERT(aSize <= mSize);
-
-    mSize -= aSize;
-    mOffset += aSize;
-  }
-
-protected:
-  size_t GetLeadingSpace() const
-  {
-    return mOffset;
-  }
-
-  size_t GetTrailingSpace() const
-  {
-    return mAvailableSpace - (mOffset + mSize);
-  }
-
-  size_t GetAvailableSpace() const
-  {
-    return mAvailableSpace;
-  }
-
-  void* GetTrailingBytes()
-  {
-    return mData + mOffset + mSize;
-  }
-
-private:
-  size_t mSize;
-  size_t mOffset;
-  size_t mAvailableSpace;
-  nsAutoArrayPtr<uint8_t> mData;
 };
 
 enum SocketConnectionStatus {
   SOCKET_DISCONNECTED = 0,
   SOCKET_LISTENING = 1,
   SOCKET_CONNECTING = 2,
   SOCKET_CONNECTED = 3
 };
 
 //
-// SocketConsumerBase
+// SocketBase
 //
 
-class SocketConsumerBase
+class SocketBase
 {
 public:
-  NS_INLINE_DECL_THREADSAFE_REFCOUNTING(SocketConsumerBase)
+  NS_INLINE_DECL_THREADSAFE_REFCOUNTING(SocketBase)
 
-  virtual ~SocketConsumerBase();
+  virtual ~SocketBase();
 
   SocketConnectionStatus GetConnectionStatus() const;
 
   int GetSuggestedConnectDelayMs() const;
 
   /**
    * Queues the internal representation of socket for deletion. Can be called
    * from main thread.
    */
   virtual void CloseSocket() = 0;
 
   /**
-   * Function to be called whenever data is received. This is only called on the
-   * main thread.
-   *
-   * @param aMessage Data received from the socket.
-   */
-  virtual void ReceiveSocketData(nsAutoPtr<UnixSocketRawData>& aMessage) = 0;
-
-  /**
-   * Queue data to be sent to the socket on the IO thread. Can only be called on
-   * originating thread.
-   *
-   * @param aMessage Data to be sent to socket
-   *
-   * @return true if data is queued, false otherwise (i.e. not connected)
-   */
-  virtual bool SendSocketData(UnixSocketRawData* aMessage) = 0;
-
-  /**
    * Callback for socket connect/accept success. Called after connect/accept has
    * finished. Will be run on main thread, before any reads take place.
    */
   virtual void OnConnectSuccess() = 0;
 
   /**
    * Callback for socket connect/accept error. Will be run on main thread.
    */
@@ -171,29 +250,57 @@ public:
   void NotifyError();
 
   /**
    * Called by implementation to notify consumer of disconnect.
    */
   void NotifyDisconnect();
 
 protected:
-  SocketConsumerBase();
+  SocketBase();
 
   void SetConnectionStatus(SocketConnectionStatus aConnectionStatus);
 
 private:
   uint32_t CalculateConnectDelayMs() const;
 
   SocketConnectionStatus mConnectionStatus;
   PRIntervalTime mConnectTimestamp;
   uint32_t mConnectDelayMs;
 };
 
 //
+// SocketConsumerBase
+//
+
+class SocketConsumerBase : public SocketBase
+{
+public:
+  virtual ~SocketConsumerBase();
+
+  /**
+   * Function to be called whenever data is received. This is only called on the
+   * main thread.
+   *
+   * @param aMessage Data received from the socket.
+   */
+  virtual void ReceiveSocketData(nsAutoPtr<UnixSocketRawData>& aMessage) = 0;
+
+  /**
+   * Queue data to be sent to the socket on the IO thread. Can only be called on
+   * originating thread.
+   *
+   * @param aMessage Data to be sent to socket
+   *
+   * @return true if data is queued, false otherwise (i.e. not connected)
+   */
+  virtual bool SendSocketData(UnixSocketRawData* aMessage) = 0;
+};
+
+//
 // Socket I/O runnables
 //
 
 /* |SocketIORunnable| is a runnable for sending a message from
  * the I/O thread to the main thread.
  */
 template <typename T>
 class SocketIORunnable : public nsRunnable
@@ -244,25 +351,25 @@ public:
 
     if (io->IsShutdownOnMainThread()) {
       NS_WARNING("I/O consumer has already been closed!");
       // Since we've already explicitly closed and the close happened before
       // this, this isn't really an error. Since we've warned, return OK.
       return NS_OK;
     }
 
-    SocketConsumerBase* consumer = io->GetConsumer();
-    MOZ_ASSERT(consumer);
+    SocketBase* base = io->GetSocketBase();
+    MOZ_ASSERT(base);
 
     if (mEvent == CONNECT_SUCCESS) {
-      consumer->NotifySuccess();
+      base->NotifySuccess();
     } else if (mEvent == CONNECT_ERROR) {
-      consumer->NotifyError();
+      base->NotifyError();
     } else if (mEvent == DISCONNECT) {
-      consumer->NotifyDisconnect();
+      base->NotifyDisconnect();
     }
 
     return NS_OK;
   }
 
 private:
   SocketEvent mEvent;
 };
@@ -320,20 +427,20 @@ public:
 
     if (io->IsShutdownOnMainThread()) {
       NS_WARNING("CloseSocket has already been called!");
       // Since we've already explicitly closed and the close happened before
       // this, this isn't really an error. Since we've warned, return OK.
       return NS_OK;
     }
 
-    SocketConsumerBase* consumer = io->GetConsumer();
-    MOZ_ASSERT(consumer);
+    SocketBase* base = io->GetSocketBase();
+    MOZ_ASSERT(base);
 
-    consumer->CloseSocket();
+    base->CloseSocket();
 
     return NS_OK;
   }
 };
 
 /* |SocketIODeleteInstanceRunnable| deletes an object on the main thread.
  */
 template<class T>
@@ -448,103 +555,104 @@ private:
 
 //
 // Socket I/O tasks
 //
 
 /* |SocketIOTask| holds a reference to a Socket I/O object. It's
  * supposed to run on the I/O thread.
  */
-template <typename T>
+template<typename Tio>
 class SocketIOTask : public CancelableTask
 {
 public:
   virtual ~SocketIOTask()
   { }
 
-  T* GetIO() const
+  Tio* GetIO() const
   {
     return mIO;
   }
 
   void Cancel() MOZ_OVERRIDE
   {
     mIO = nullptr;
   }
 
   bool IsCanceled() const
   {
     return !mIO;
   }
 
 protected:
-  SocketIOTask(T* aIO)
+  SocketIOTask(Tio* aIO)
   : mIO(aIO)
   {
     MOZ_ASSERT(mIO);
   }
 
 private:
-  T* mIO;
+  Tio* mIO;
 };
 
-/* |SocketIOSendTask| transfers an instance of |UnixSocketRawData| to
- * the I/O thread and queues it up for sending the contained data.
+/* |SocketIOSendTask| transfers an instance of |Tdata|, such as
+ * |UnixSocketRawData|, to the I/O thread and queues it up for
+ * sending the contained data.
  */
-template <typename T>
-class SocketIOSendTask MOZ_FINAL : public SocketIOTask<T>
+template<typename Tio, typename Tdata>
+class SocketIOSendTask MOZ_FINAL : public SocketIOTask<Tio>
 {
 public:
-  SocketIOSendTask(T* aIO, UnixSocketRawData* aData)
-  : SocketIOTask<T>(aIO)
+  SocketIOSendTask(Tio* aIO, Tdata* aData)
+  : SocketIOTask<Tio>(aIO)
   , mData(aData)
   {
     MOZ_ASSERT(aData);
   }
 
   void Run() MOZ_OVERRIDE
   {
     MOZ_ASSERT(!NS_IsMainThread());
-    MOZ_ASSERT(!SocketIOTask<T>::IsCanceled());
+    MOZ_ASSERT(!SocketIOTask<Tio>::IsCanceled());
 
-    T* io = SocketIOTask<T>::GetIO();
+    Tio* io = SocketIOTask<Tio>::GetIO();
     MOZ_ASSERT(!io->IsShutdownOnIOThread());
 
     io->Send(mData);
   }
 
 private:
-  UnixSocketRawData* mData;
+  Tdata* mData;
 };
 
 /* |SocketIOShutdownTask| signals shutdown to the Socket I/O object on
  * the I/O thread and sends it to the main thread for destruction.
  */
-template <typename T>
-class SocketIOShutdownTask MOZ_FINAL : public SocketIOTask<T>
+template<typename Tio>
+class SocketIOShutdownTask MOZ_FINAL : public SocketIOTask<Tio>
 {
 public:
-  SocketIOShutdownTask(T* aIO)
-  : SocketIOTask<T>(aIO)
+  SocketIOShutdownTask(Tio* aIO)
+  : SocketIOTask<Tio>(aIO)
   { }
 
   void Run() MOZ_OVERRIDE
   {
     MOZ_ASSERT(!NS_IsMainThread());
 
-    T* io = SocketIOTask<T>::GetIO();
+    Tio* io = SocketIOTask<Tio>::GetIO();
 
     // At this point, there should be no new events on the I/O thread
     // after this one with the possible exception of an accept task,
     // which ShutdownOnIOThread will cancel for us. We are now fully
     // shut down, so we can send a message to the main thread to delete
     // |io| safely knowing that it's not reference any longer.
     io->ShutdownOnIOThread();
 
-    nsRefPtr<nsRunnable> r = new SocketIODeleteInstanceRunnable<T>(io);
+    nsRefPtr<nsRunnable> r = new SocketIODeleteInstanceRunnable<Tio>(io);
     nsresult rv = NS_DispatchToMainThread(r);
     NS_ENSURE_SUCCESS_VOID(rv);
   }
 };
 
 }
 }
 
--- a/ipc/unixsocket/UnixSocket.cpp
+++ b/ipc/unixsocket/UnixSocket.cpp
@@ -26,16 +26,17 @@ public:
   UnixSocketConsumerIO(MessageLoop* mIOLoop,
                        UnixSocketConsumer* aConsumer,
                        UnixSocketConnector* aConnector,
                        const nsACString& aAddress);
   ~UnixSocketConsumerIO();
 
   void                GetSocketAddr(nsAString& aAddrStr) const;
   SocketConsumerBase* GetConsumer();
+  SocketBase*         GetSocketBase();
 
   // Shutdown state
   //
 
   bool IsShutdownOnMainThread() const;
   void ShutdownOnMainThread();
 
   bool IsShutdownOnIOThread() const;
@@ -152,16 +153,22 @@ UnixSocketConsumerIO::GetSocketAddr(nsAS
 }
 
 SocketConsumerBase*
 UnixSocketConsumerIO::GetConsumer()
 {
   return mConsumer.get();
 }
 
+SocketBase*
+UnixSocketConsumerIO::GetSocketBase()
+{
+  return GetConsumer();
+}
+
 bool
 UnixSocketConsumerIO::IsShutdownOnMainThread() const
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   return mConsumer == nullptr;
 }
 
@@ -543,17 +550,18 @@ UnixSocketConsumer::SendSocketData(UnixS
 {
   MOZ_ASSERT(NS_IsMainThread());
   if (!mIO) {
     return false;
   }
 
   MOZ_ASSERT(!mIO->IsShutdownOnMainThread());
   XRE_GetIOMessageLoop()->PostTask(
-    FROM_HERE, new SocketIOSendTask<UnixSocketConsumerIO>(mIO, aData));
+    FROM_HERE,
+    new SocketIOSendTask<UnixSocketConsumerIO, UnixSocketRawData>(mIO, aData));
 
   return true;
 }
 
 bool
 UnixSocketConsumer::SendSocketData(const nsACString& aStr)
 {
   if (aStr.Length() > MAX_READ_SIZE) {