Merge b2g-inbound to m-c. a=merge
authorRyan VanderMeulen <ryanvm@gmail.com>
Wed, 22 Oct 2014 16:03:57 -0400
changeset 236100 a4a78522b8d84b5a71cb9e42d2075e38ac2ad913
parent 236070 6066a2a0766fb6fa03fc96a89a023b3b8afe40c1 (current diff)
parent 236099 f5705a33a614956a3cd5717658e124c7e8f5ef78 (diff)
child 236120 7e2fb51abd4b63285c45b61145862b52cd60c18a
push id4311
push userraliiev@mozilla.com
push dateMon, 12 Jan 2015 19:37:41 +0000
treeherdermozilla-beta@150c9fed433b [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
configure.in
dom/system/gonk/tests/marionette/test_neighboring_cell_ids.js
layout/base/nsDisplayList.cpp
--- a/b2g/app/Makefile.in
+++ b/b2g/app/Makefile.in
@@ -15,16 +15,24 @@ UA_UPDATE_FILE = ua-update.json
 
 UA_UPDATE_FILES = $(UA_UPDATE_FILE)
 UA_UPDATE_DEST  = $(FINAL_TARGET)
 INSTALL_TARGETS += UA_UPDATE
 
 # Make sure the standalone glue doesn't try to get libxpcom.so from b2g/app.
 NSDISTMODE = copy
 
+# Copy the Firefox OS fonts if available
+ifdef MOZTTDIR
+include $(MOZTTDIR)/fonts.mk
+MOZTT_DEST = $(FINAL_TARGET)/fonts
+MOZTT_FILES = $(patsubst external/moztt/%,$(MOZTTDIR)/%,$(filter external/moztt/%,$(subst :, ,$(PRODUCT_COPY_FILES))))
+INSTALL_TARGETS += MOZTT
+endif
+
 include $(topsrcdir)/config/rules.mk
 
 APP_ICON = b2g
 
 ifeq ($(OS_ARCH),WINNT)
 REDIT_PATH = $(LIBXUL_DIST)/bin
 endif
 
--- 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="4d7f051cede6544f4c83580253c743c22b0cb279"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="27a1d1baaa8e375b70e043efee67d5f2206c330b"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="314f305d3163cc094e6fe7701d95a98fc180b639"/>
   <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="a7631963e5f702a0c6027f5575e5e0deeededea6"/>
--- 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="70eb0cb0977d6295e7da8896f9efb9f3ca1c13ea">
     <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="4d7f051cede6544f4c83580253c743c22b0cb279"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="27a1d1baaa8e375b70e043efee67d5f2206c330b"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="314f305d3163cc094e6fe7701d95a98fc180b639"/>
   <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="a7631963e5f702a0c6027f5575e5e0deeededea6"/>
   <!-- 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="4d7f051cede6544f4c83580253c743c22b0cb279"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="27a1d1baaa8e375b70e043efee67d5f2206c330b"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="314f305d3163cc094e6fe7701d95a98fc180b639"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="a7631963e5f702a0c6027f5575e5e0deeededea6"/>
   <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"/>
--- 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="4d7f051cede6544f4c83580253c743c22b0cb279"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="27a1d1baaa8e375b70e043efee67d5f2206c330b"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="314f305d3163cc094e6fe7701d95a98fc180b639"/>
   <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="a7631963e5f702a0c6027f5575e5e0deeededea6"/>
--- 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="70eb0cb0977d6295e7da8896f9efb9f3ca1c13ea">
     <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="4d7f051cede6544f4c83580253c743c22b0cb279"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="27a1d1baaa8e375b70e043efee67d5f2206c330b"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="314f305d3163cc094e6fe7701d95a98fc180b639"/>
   <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="a7631963e5f702a0c6027f5575e5e0deeededea6"/>
   <!-- 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="4d7f051cede6544f4c83580253c743c22b0cb279"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="27a1d1baaa8e375b70e043efee67d5f2206c330b"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="314f305d3163cc094e6fe7701d95a98fc180b639"/>
   <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="a7631963e5f702a0c6027f5575e5e0deeededea6"/>
--- 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="4d7f051cede6544f4c83580253c743c22b0cb279"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="27a1d1baaa8e375b70e043efee67d5f2206c330b"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="314f305d3163cc094e6fe7701d95a98fc180b639"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="a7631963e5f702a0c6027f5575e5e0deeededea6"/>
   <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"/>
--- a/b2g/config/gaia.json
+++ b/b2g/config/gaia.json
@@ -1,9 +1,9 @@
 {
     "git": {
         "git_revision": "", 
         "remote": "", 
         "branch": ""
     }, 
-    "revision": "d3b2bb39fd5873ff8d537a3267d21d20491c3d1d", 
+    "revision": "8d483aad9a257678544e70bdfadee0e576cc3239", 
     "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="70eb0cb0977d6295e7da8896f9efb9f3ca1c13ea">
     <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="4d7f051cede6544f4c83580253c743c22b0cb279"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="27a1d1baaa8e375b70e043efee67d5f2206c330b"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="314f305d3163cc094e6fe7701d95a98fc180b639"/>
   <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="a7631963e5f702a0c6027f5575e5e0deeededea6"/>
   <!-- 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="70eb0cb0977d6295e7da8896f9efb9f3ca1c13ea">
     <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="4d7f051cede6544f4c83580253c743c22b0cb279"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="27a1d1baaa8e375b70e043efee67d5f2206c330b"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="314f305d3163cc094e6fe7701d95a98fc180b639"/>
   <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/mozconfigs/linux32_gecko/debug
+++ b/b2g/config/mozconfigs/linux32_gecko/debug
@@ -29,9 +29,12 @@ no_sccache=
 #B2G options
 ac_add_options --enable-application=b2g
 ENABLE_MARIONETTE=1
 ac_add_options --disable-elf-hack
 export CXXFLAGS=-DMOZ_ENABLE_JS_DUMP
 
 GAIADIR=$topsrcdir/gaia
 
+# Include Firefox OS fonts.
+MOZTTDIR=$topsrcdir/moztt
+
 . "$topsrcdir/b2g/config/mozconfigs/common.override"
--- a/b2g/config/mozconfigs/linux32_gecko/nightly
+++ b/b2g/config/mozconfigs/linux32_gecko/nightly
@@ -27,12 +27,15 @@ no_sccache=
 
 #B2G options
 ac_add_options --enable-application=b2g
 ac_add_options --disable-elf-hack
 export CXXFLAGS=-DMOZ_ENABLE_JS_DUMP
 
 GAIADIR=$topsrcdir/gaia
 
+# Include Firefox OS fonts.
+MOZTTDIR=$topsrcdir/moztt
+
 # Build simulator xpi and phone tweaks for b2g-desktop
 FXOS_SIMULATOR=1
 
 . "$topsrcdir/b2g/config/mozconfigs/common.override"
--- a/b2g/config/mozconfigs/linux64_gecko/debug
+++ b/b2g/config/mozconfigs/linux64_gecko/debug
@@ -29,9 +29,12 @@ no_sccache=
 #B2G options
 ac_add_options --enable-application=b2g
 ENABLE_MARIONETTE=1
 ac_add_options --disable-elf-hack
 export CXXFLAGS=-DMOZ_ENABLE_JS_DUMP
 
 GAIADIR=$topsrcdir/gaia
 
+# Include Firefox OS fonts.
+MOZTTDIR=$topsrcdir/moztt
+
 . "$topsrcdir/b2g/config/mozconfigs/common.override"
--- a/b2g/config/mozconfigs/linux64_gecko/nightly
+++ b/b2g/config/mozconfigs/linux64_gecko/nightly
@@ -27,12 +27,15 @@ no_sccache=
 
 #B2G options
 ac_add_options --enable-application=b2g
 ac_add_options --disable-elf-hack
 export CXXFLAGS=-DMOZ_ENABLE_JS_DUMP
 
 GAIADIR=$topsrcdir/gaia
 
+# Include Firefox OS fonts.
+MOZTTDIR=$topsrcdir/moztt
+
 # Build simulator xpi and phone tweaks for b2g-desktop
 FXOS_SIMULATOR=1
 
 . "$topsrcdir/b2g/config/mozconfigs/common.override"
--- a/b2g/config/mozconfigs/macosx64_gecko/debug
+++ b/b2g/config/mozconfigs/macosx64_gecko/debug
@@ -27,9 +27,12 @@ ac_add_options --enable-application=b2g
 ac_add_options --enable-debug-symbols
 ac_add_options --enable-debug
 ENABLE_MARIONETTE=1
 
 export CXXFLAGS=-DMOZ_ENABLE_JS_DUMP
 
 GAIADIR=$topsrcdir/gaia
 
+# Include Firefox OS fonts.
+MOZTTDIR=$topsrcdir/moztt
+
 . "$topsrcdir/b2g/config/mozconfigs/common.override"
--- a/b2g/config/mozconfigs/macosx64_gecko/nightly
+++ b/b2g/config/mozconfigs/macosx64_gecko/nightly
@@ -24,12 +24,15 @@ ac_add_options --enable-warnings-as-erro
 
 # B2G Stuff
 ac_add_options --enable-application=b2g
 ac_add_options --enable-debug-symbols
 export CXXFLAGS=-DMOZ_ENABLE_JS_DUMP
 
 GAIADIR=$topsrcdir/gaia
 
+# Include Firefox OS fonts.
+MOZTTDIR=$topsrcdir/moztt
+
 # Build simulator xpi and phone tweaks for b2g-desktop
 FXOS_SIMULATOR=1
 
 . "$topsrcdir/b2g/config/mozconfigs/common.override"
--- a/b2g/config/mozconfigs/win32_gecko/debug
+++ b/b2g/config/mozconfigs/win32_gecko/debug
@@ -23,9 +23,12 @@ fi
 # B2G Options
 ac_add_options --enable-application=b2g
 ENABLE_MARIONETTE=1
 
 export CXXFLAGS=-DMOZ_ENABLE_JS_DUMP
 
 GAIADIR=$topsrcdir/gaia
 
+# Include Firefox OS fonts.
+MOZTTDIR=$topsrcdir/moztt
+
 . "$topsrcdir/b2g/config/mozconfigs/common.override"
--- a/b2g/config/mozconfigs/win32_gecko/nightly
+++ b/b2g/config/mozconfigs/win32_gecko/nightly
@@ -20,12 +20,15 @@ else
 fi
 
 # B2G Options
 ac_add_options --enable-application=b2g
 export CXXFLAGS=-DMOZ_ENABLE_JS_DUMP
 
 GAIADIR=$topsrcdir/gaia
 
+# Include Firefox OS fonts.
+MOZTTDIR=$topsrcdir/moztt
+
 # Build simulator xpi and phone tweaks for b2g-desktop
 FXOS_SIMULATOR=1
 
 . "$topsrcdir/b2g/config/mozconfigs/common.override"
--- 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="4d7f051cede6544f4c83580253c743c22b0cb279"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="27a1d1baaa8e375b70e043efee67d5f2206c330b"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="314f305d3163cc094e6fe7701d95a98fc180b639"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="a7631963e5f702a0c6027f5575e5e0deeededea6"/>
   <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"/>
--- a/b2g/config/tooltool-manifests/linux32/releng.manifest
+++ b/b2g/config/tooltool-manifests/linux32/releng.manifest
@@ -5,10 +5,17 @@
 "algorithm": "sha512",
 "filename": "setup.sh"
 },
 {
 "size": 168202,
 "digest": "5520f53fc10fcb569f235aff5c78ea5b69c878a8439b95aa758de2b83fc9f09bd4758c5fd701d84c58776386e210f3f30e5c9da6fdd8358d7dd371c764179339",
 "algorithm": "sha512",
 "filename": "sccache.tar.bz2"
+},
+{
+"size": 31057326,
+"digest": "b844c3e52be493d2cacafa58c4a924b89c9be8d2dcc2a7c71aed58c253d8035fba4d51df309f73e3c4342a1f3c3898a9a25c4815e2112888d1280f43c41c8e51",
+"algorithm": "sha512",
+"filename": "moztt.tar.bz2",
+"unpack": "True"
 }
 ]
--- a/b2g/config/tooltool-manifests/linux64/releng.manifest
+++ b/b2g/config/tooltool-manifests/linux64/releng.manifest
@@ -5,10 +5,17 @@
 "algorithm": "sha512",
 "filename": "setup.sh"
 },
 {
 "size": 168202,
 "digest": "5520f53fc10fcb569f235aff5c78ea5b69c878a8439b95aa758de2b83fc9f09bd4758c5fd701d84c58776386e210f3f30e5c9da6fdd8358d7dd371c764179339",
 "algorithm": "sha512",
 "filename": "sccache.tar.bz2"
+},
+{
+"size": 31057326,
+"digest": "b844c3e52be493d2cacafa58c4a924b89c9be8d2dcc2a7c71aed58c253d8035fba4d51df309f73e3c4342a1f3c3898a9a25c4815e2112888d1280f43c41c8e51",
+"algorithm": "sha512",
+"filename": "moztt.tar.bz2",
+"unpack": "True"
 }
 ]
--- a/b2g/config/tooltool-manifests/macosx64/releng.manifest
+++ b/b2g/config/tooltool-manifests/macosx64/releng.manifest
@@ -14,10 +14,17 @@
 "algorithm": "sha512",
 "filename": "clang.tar.bz2"
 },
 {
 "size": 168202,
 "digest": "5520f53fc10fcb569f235aff5c78ea5b69c878a8439b95aa758de2b83fc9f09bd4758c5fd701d84c58776386e210f3f30e5c9da6fdd8358d7dd371c764179339",
 "algorithm": "sha512",
 "filename": "sccache.tar.bz2"
+},
+{
+"size": 31057326,
+"digest": "b844c3e52be493d2cacafa58c4a924b89c9be8d2dcc2a7c71aed58c253d8035fba4d51df309f73e3c4342a1f3c3898a9a25c4815e2112888d1280f43c41c8e51",
+"algorithm": "sha512",
+"filename": "moztt.tar.bz2",
+"unpack": "True"
 }
 ]
--- a/b2g/config/tooltool-manifests/win32/releng.manifest
+++ b/b2g/config/tooltool-manifests/win32/releng.manifest
@@ -1,8 +1,15 @@
 [
 {
 "size": 266240,
 "digest": "bb345b0e700ffab4d09436981f14b5de84da55a3f18a7f09ebc4364a4488acdeab8d46f447b12ac70f2da1444a68b8ce8b8675f0dae2ccf845e966d1df0f0869",
 "algorithm": "sha512",
 "filename": "mozmake.exe"
+},
+{
+"size": 31057326,
+"digest": "b844c3e52be493d2cacafa58c4a924b89c9be8d2dcc2a7c71aed58c253d8035fba4d51df309f73e3c4342a1f3c3898a9a25c4815e2112888d1280f43c41c8e51",
+"algorithm": "sha512",
+"filename": "moztt.tar.bz2",
+"unpack": "True"
 }
 ]
--- 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="70eb0cb0977d6295e7da8896f9efb9f3ca1c13ea">
     <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="4d7f051cede6544f4c83580253c743c22b0cb279"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="27a1d1baaa8e375b70e043efee67d5f2206c330b"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="314f305d3163cc094e6fe7701d95a98fc180b639"/>
   <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="a7631963e5f702a0c6027f5575e5e0deeededea6"/>
   <project name="gonk-patches" path="patches" remote="b2g" revision="223a2421006e8f5da33f516f6891c87cae86b0f6"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="6426040f1be4a844082c9769171ce7f5341a5528"/>
--- a/b2g/installer/package-manifest.in
+++ b/b2g/installer/package-manifest.in
@@ -881,8 +881,12 @@ bin/components/@DLL_PREFIX@nkgnomevfs@DL
 @BINPATH@/@DLL_PREFIX@plugin_child_interpose@DLL_SUFFIX@
 #endif
 
 #ifdef PACKAGE_GAIA
 [gaia]
 @BINPATH@/gaia/*
 @BINPATH@/b2g-bin@BIN_SUFFIX@
 #endif
+
+#ifdef PACKAGE_MOZTT
+@BINPATH@/fonts/*
+#endif
--- a/configure.in
+++ b/configure.in
@@ -178,16 +178,25 @@ if test -n "$FXOS_SIMULATOR" -a -z "$GAI
     AC_MSG_ERROR([FXOS_SIMULATOR=1 requires GAIADIR to be defined])
 fi
 
 if test -n "$FXOS_SIMULATOR" ; then
     AC_DEFINE(FXOS_SIMULATOR)
     AC_SUBST(FXOS_SIMULATOR)
 fi
 
+if test -n "$MOZTTDIR" -a ! -d "$MOZTTDIR" ; then
+    AC_MSG_ERROR([MOZTTDIR '$MOZTTDIR' isn't a valid directory])
+fi
+
+AC_SUBST(MOZTTDIR)
+if test -n "$MOZTTDIR" ; then
+    AC_DEFINE(PACKAGE_MOZTT)
+fi
+
 MOZ_ARG_WITH_STRING(gonk,
 [  --with-gonk=DIR
                location of gonk dir],
     gonkdir=$withval)
 
 MOZ_ARG_WITH_STRING(gonk-toolchain-prefix,
 [  --with-gonk-toolchain-prefix=DIR
                           prefix to gonk toolchain commands],
--- a/dom/bluetooth/bluedroid/BluetoothServiceBluedroid.cpp
+++ b/dom/bluetooth/bluedroid/BluetoothServiceBluedroid.cpp
@@ -87,20 +87,21 @@ public:
 
     // Bluetooth just enabled, clear profile controllers and runnable arrays.
     sControllerArray.Clear();
     sBondingRunnableArray.Clear();
     sGetDeviceRunnableArray.Clear();
     sSetPropertyRunnableArray.Clear();
     sUnbondingRunnableArray.Clear();
 
-    // Bluetooth scan mode is NONE by default
+    // Bluetooth scan mode is SCAN_MODE_CONNECTABLE by default, i.e., It should
+    // be connectable and non-discoverable.
     NS_ENSURE_TRUE(sBtInterface, NS_ERROR_FAILURE);
     sBtInterface->SetAdapterProperty(
-      BluetoothNamedValue(NS_ConvertUTF8toUTF16("Discoverable"), true),
+      BluetoothNamedValue(NS_ConvertUTF8toUTF16("Discoverable"), false),
       new SetAdapterPropertyResultHandler());
 
     // Try to fire event 'AdapterAdded' to fit the original behaviour when
     // we used BlueZ as backend.
     BluetoothService* bs = BluetoothService::Get();
     NS_ENSURE_TRUE(bs, NS_ERROR_FAILURE);
 
     bs->AdapterAddedReceived();
--- a/dom/bluetooth2/bluedroid/BluetoothServiceBluedroid.cpp
+++ b/dom/bluetooth2/bluedroid/BluetoothServiceBluedroid.cpp
@@ -102,20 +102,21 @@ public:
     sControllerArray.Clear();
     sChangeDiscoveryRunnableArray.Clear();
     sSetPropertyRunnableArray.Clear();
     sGetDeviceRunnableArray.Clear();
     sFetchUuidsRunnableArray.Clear();
     sBondingRunnableArray.Clear();
     sUnbondingRunnableArray.Clear();
 
-    // Bluetooth scan mode is NONE by default
+    // Bluetooth scan mode is SCAN_MODE_CONNECTABLE by default, i.e., It should
+    // be connectable and non-discoverable.
     NS_ENSURE_TRUE(sBtInterface, NS_ERROR_FAILURE);
     sBtInterface->SetAdapterProperty(
-      BluetoothNamedValue(NS_ConvertUTF8toUTF16("Discoverable"), true),
+      BluetoothNamedValue(NS_ConvertUTF8toUTF16("Discoverable"), false),
       new SetAdapterPropertyResultHandler());
 
     // Trigger BluetoothOppManager to listen
     BluetoothOppManager* opp = BluetoothOppManager::Get();
     if (!opp || !opp->Listen()) {
       BT_LOGR("Fail to start BluetoothOppManager listening");
     }
 
--- a/dom/camera/GonkCameraParameters.cpp
+++ b/dom/camera/GonkCameraParameters.cpp
@@ -347,17 +347,17 @@ GonkCameraParameters::GetTranslated(uint
 
 // Handle ICameraControl::Sizes
 nsresult
 GonkCameraParameters::SetTranslated(uint32_t aKey, const ICameraControl::Size& aSize)
 {
   if (aSize.width > INT_MAX || aSize.height > INT_MAX) {
     // AOSP can only handle signed ints.
     DOM_CAMERA_LOGE("Camera parameter aKey=%d out of bounds (width=%u, height=%u)\n",
-      aSize.width, aSize.height);
+      aKey, aSize.width, aSize.height);
     return NS_ERROR_INVALID_ARG;
   }
 
   nsresult rv;
 
   switch (aKey) {
     case CAMERA_PARAM_THUMBNAILSIZE:
       // This is a special case--for some reason the thumbnail size
--- a/dom/camera/GonkCameraParameters.h
+++ b/dom/camera/GonkCameraParameters.h
@@ -116,17 +116,23 @@ protected:
 
     void set(const char* aKey, float aValue)      { setFloat(aKey, aValue); }
     void set(const char* aKey, double aValue)     { setFloat(aKey, aValue); }
     void set(const char* aKey, bool aValue)       { set(aKey, aValue ? TRUE : FALSE); }
     void get(const char* aKey, float& aRet)       { aRet = getFloat(aKey); }
     void get(const char* aKey, double& aRet)      { aRet = getFloat(aKey); }
     void get(const char* aKey, const char*& aRet) { aRet = get(aKey); }
     void get(const char* aKey, int& aRet)         { aRet = getInt(aKey); }
-    void get(const char* aKey, bool& aRet)        { aRet = strcmp(get(aKey), FALSE); }
+
+    void
+    get(const char* aKey, bool& aRet)
+    {
+      const char* value = get(aKey);
+      aRet = value ? strcmp(value, TRUE) == 0 : false;
+    }
 
     void remove(const char* aKey)                 { android::CameraParameters::remove(aKey); }
 
     static const char* GetTextKey(uint32_t aKey);
   };
 
   Parameters mParams;
 
--- a/dom/mobileconnection/gonk/MobileConnectionService.js
+++ b/dom/mobileconnection/gonk/MobileConnectionService.js
@@ -24,23 +24,37 @@ const MOBILECONNECTIONINFO_CID =
 const MOBILENETWORKINFO_CID =
   Components.ID("{a6c8416c-09b4-46d1-bf29-6520d677d085}");
 const MOBILECELLINFO_CID =
   Components.ID("{0635d9ab-997e-4cdf-84e7-c1883752dff3}");
 const MOBILECALLFORWARDINGOPTIONS_CID =
   Components.ID("{e0cf4463-ee63-4b05-ab2e-d94bf764836c}");
 const TELEPHONYDIALCALLBACK_CID =
   Components.ID("{c2af1a5d-3649-44ef-a1ff-18e9ac1dec51}");
+const NEIGHBORINGCELLINFO_CID =
+  Components.ID("{6078cbf1-f34c-44fa-96f8-11a88d4bfdd3}");
+const GSMCELLINFO_CID =
+  Components.ID("{e3cf3aa0-f992-48fe-967b-ec98a28c8535}");
+const WCDMACELLINFO_CID =
+  Components.ID("{62e2c83c-b535-4068-9762-8039fac48106}");
+const CDMACELLINFO_CID =
+  Components.ID("{40f491f0-dd8b-42fd-af32-aef5b002749a}");
+const LTECELLINFO_CID =
+  Components.ID("{715e2c76-3b08-41e4-8ea5-e60c5ce6393e}");
+
 
 const NS_XPCOM_SHUTDOWN_OBSERVER_ID      = "xpcom-shutdown";
 const NS_PREFBRANCH_PREFCHANGE_TOPIC_ID  = "nsPref:changed";
 const NS_NETWORK_ACTIVE_CHANGED_TOPIC_ID = "network-active-changed";
 
 const kPrefRilDebuggingEnabled = "ril.debugging.enabled";
 
+const INT32_MAX = 2147483647;
+const UNKNOWN_RSSI = 99;
+
 XPCOMUtils.defineLazyServiceGetter(this, "gSystemMessenger",
                                    "@mozilla.org/system-message-internal;1",
                                    "nsISystemMessagesInternal");
 
 XPCOMUtils.defineLazyServiceGetter(this, "gNetworkManager",
                                    "@mozilla.org/network/manager;1",
                                    "nsINetworkManager");
 
@@ -133,16 +147,144 @@ MobileCallForwardingOptions.prototype = 
   active: false,
   action: Ci.nsIMobileConnection.CALL_FORWARD_ACTION_UNKNOWN,
   reason: Ci.nsIMobileConnection.CALL_FORWARD_REASON_UNKNOWN,
   number: null,
   timeSeconds: -1,
   serviceClass: Ci.nsIMobileConnection.ICC_SERVICE_CLASS_NONE
 }
 
+function NeighboringCellInfo() {}
+NeighboringCellInfo.prototype = {
+  QueryInterface: XPCOMUtils.generateQI([Ci.nsINeighboringCellInfo]),
+  classID:        NEIGHBORINGCELLINFO_CID,
+  classInfo:      XPCOMUtils.generateCI({
+    classID:          NEIGHBORINGCELLINFO_CID,
+    classDescription: "NeighboringCellInfo",
+    interfaces:       [Ci.nsINeighboringCellInfo]
+  }),
+
+  // nsINeighboringCellInfo
+
+  networkType: null,
+  gsmLocationAreaCode: -1,
+  gsmCellId: -1,
+  wcdmaPsc: -1,
+  signalStrength: UNKNOWN_RSSI
+};
+
+function CellInfo() {}
+CellInfo.prototype = {
+
+  // nsICellInfo
+
+  type: null,
+  registered: false,
+  timestampType: Ci.nsICellInfo.TIMESTAMP_TYPE_UNKNOWN,
+  timestamp: 0
+};
+
+function GsmCellInfo() {}
+GsmCellInfo.prototype = {
+  __proto__: CellInfo.prototype,
+  QueryInterface: XPCOMUtils.generateQI([Ci.nsICellInfo,
+                                         Ci.nsIGsmCellInfo]),
+  classID: GSMCELLINFO_CID,
+  classInfo: XPCOMUtils.generateCI({
+    classID:          GSMCELLINFO_CID,
+    classDescription: "GsmCellInfo",
+    interfaces:       [Ci.nsIGsmCellInfo]
+  }),
+
+  // nsIGsmCellInfo
+
+  mcc: INT32_MAX,
+  mnc: INT32_MAX,
+  lac: INT32_MAX,
+  cid: INT32_MAX,
+  signalStrength: UNKNOWN_RSSI,
+  bitErrorRate: UNKNOWN_RSSI
+};
+
+function WcdmaCellInfo() {}
+WcdmaCellInfo.prototype = {
+  __proto__: CellInfo.prototype,
+  QueryInterface: XPCOMUtils.generateQI([Ci.nsICellInfo,
+                                         Ci.nsIWcdmaCellInfo]),
+  classID: WCDMACELLINFO_CID,
+  classInfo: XPCOMUtils.generateCI({
+    classID:          WCDMACELLINFO_CID,
+    classDescription: "WcdmaCellInfo",
+    interfaces:       [Ci.nsIWcdmaCellInfo]
+  }),
+
+  // nsIWcdmaCellInfo
+
+  mcc: INT32_MAX,
+  mnc: INT32_MAX,
+  lac: INT32_MAX,
+  cid: INT32_MAX,
+  psc: INT32_MAX,
+  signalStrength: UNKNOWN_RSSI,
+  bitErrorRate: UNKNOWN_RSSI
+};
+
+function LteCellInfo() {}
+LteCellInfo.prototype = {
+  __proto__: CellInfo.prototype,
+  QueryInterface: XPCOMUtils.generateQI([Ci.nsICellInfo,
+                                         Ci.nsILteCellInfo]),
+  classID: LTECELLINFO_CID,
+  classInfo: XPCOMUtils.generateCI({
+    classID:          LTECELLINFO_CID,
+    classDescription: "LteCellInfo",
+    interfaces:       [Ci.nsILteCellInfo]
+  }),
+
+  // nsILteCellInfo
+
+  mcc: INT32_MAX,
+  mnc: INT32_MAX,
+  cid: INT32_MAX,
+  pcid: INT32_MAX,
+  tac: INT32_MAX,
+  signalStrength: UNKNOWN_RSSI,
+  rsrp: INT32_MAX,
+  rsrq: INT32_MAX,
+  rssnr: INT32_MAX,
+  cqi: INT32_MAX,
+  timingAdvance: INT32_MAX
+};
+
+function CdmaCellInfo() {}
+CdmaCellInfo.prototype = {
+  __proto__: CellInfo.prototype,
+  QueryInterface: XPCOMUtils.generateQI([Ci.nsICellInfo,
+                                         Ci.nsICdmaCellInfo]),
+  classID: CDMACELLINFO_CID,
+  classInfo: XPCOMUtils.generateCI({
+    classID:          CDMACELLINFO_CID,
+    classDescription: "CdmaCellInfo",
+    interfaces:       [Ci.nsICdmaCellInfo]
+  }),
+
+  // nsICdmaCellInfo
+
+  networkId: INT32_MAX,
+  systemId: INT32_MAX,
+  baseStationId: INT32_MAX,
+  longitude: INT32_MAX,
+  latitude: INT32_MAX,
+  cdmaDbm: INT32_MAX,
+  cdmaEcio: INT32_MAX,
+  evdoDbm: INT32_MAX,
+  evdoEcio: INT32_MAX,
+  evdoSnr: INT32_MAX
+};
+
 /**
  * Wrap a MobileConnectionCallback to a TelephonyDialCallback.
  */
 function TelephonyDialCallback(aCallback) {
   this.callback = aCallback;
 }
 TelephonyDialCallback.prototype = {
   QueryInterface:   XPCOMUtils.generateQI([Ci.nsITelephonyDialCallback]),
@@ -899,16 +1041,77 @@ MobileConnectionProvider.prototype = {
         aCallback.notifyError(aResponse.errorMsg);
         return true;
       }
 
       aCallback.notifySuccess();
       return true;
     }).bind(this));
   },
+
+  getCellInfoList: function(aCallback) {
+    this._radioInterface.sendWorkerMessage("getCellInfoList",
+                                           null,
+                                           function(aResponse) {
+      if (aResponse.errorMsg) {
+        aCallback.notifyGetCellInfoListFailed(aResponse.errorMsg);
+        return;
+      }
+
+      let cellInfoList = [];
+      let count = aResponse.result.length;
+      for (let i = 0; i < count; i++) {
+        let srcCellInfo = aResponse.result[i];
+        let cellInfo;
+        switch (srcCellInfo.type) {
+          case RIL.CELL_INFO_TYPE_GSM:
+            cellInfo = new GsmCellInfo();
+            break;
+          case RIL.CELL_INFO_TYPE_WCDMA:
+            cellInfo = new WcdmaCellInfo();
+            break;
+          case RIL.CELL_INFO_TYPE_LTE:
+            cellInfo = new LteCellInfo();
+            break;
+          case RIL.CELL_INFO_TYPE_CDMA:
+            cellInfo = new CdmaCellInfo();
+            break;
+        }
+
+        if (!cellInfo) {
+          continue;
+        }
+        this._updateInfo(cellInfo, srcCellInfo);
+        cellInfoList.push(cellInfo);
+      }
+      aCallback.notifyGetCellInfoList(count, cellInfoList);
+    }.bind(this));
+  },
+
+  getNeighboringCellIds: function(aCallback) {
+    this._radioInterface.sendWorkerMessage("getNeighboringCellIds",
+                                           null,
+                                           function(aResponse) {
+      if (aResponse.errorMsg) {
+        aCallback.notifyGetNeighboringCellIdsFailed(aResponse.errorMsg);
+        return;
+      }
+
+      let neighboringCellIds = [];
+      let count = aResponse.result.length;
+      for (let i = 0; i < count; i++) {
+        let srcCellInfo = aResponse.result[i];
+        let cellInfo = new NeighboringCellInfo();
+        this._updateInfo(cellInfo, srcCellInfo);
+        neighboringCellIds.push(cellInfo);
+      }
+      aCallback.notifyGetNeighboringCellIds(count, neighboringCellIds);
+
+    }.bind(this));
+  },
 };
 
 function MobileConnectionService() {
   this._providers = [];
 
   let numClients = gRadioInterfaceLayer.numRadioInterfaces;
   for (let i = 0; i < numClients; i++) {
     let radioInterface = gRadioInterfaceLayer.getRadioInterface(i);
--- a/dom/mobileconnection/interfaces/nsICellInfo.idl
+++ b/dom/mobileconnection/interfaces/nsICellInfo.idl
@@ -1,21 +1,25 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsISupports.idl"
 
-[scriptable, uuid(1aed4c36-979e-4d20-9fa0-55139da8301e)]
+interface nsICellInfo;
+
+[scriptable, uuid(d8fae631-7ade-4024-b288-7efe75e6b091)]
 interface nsICellInfoListCallback : nsISupports
 {
   /**
-   * result is an array of nsICellInfo.
+   * result is an array of nsICellInfo, which could be instances of
+   * nsIGsmCellInfo, nsIWcdmaCellInfo, nsICdmaCellInfo or nsILteCellInfo.
    */
-  void notifyGetCellInfoList(in jsval result);
+  void notifyGetCellInfoList(in uint32_t count,
+                             [array, size_is(count)] in nsICellInfo result);
 
   /**
    * Callback function with error message.
    */
   void notifyGetCellInfoListFailed(in DOMString error);
 };
 
 [scriptable, uuid(86667898-c9ab-44ee-8a9a-026916b3183e)]
--- a/dom/mobileconnection/interfaces/nsIMobileConnectionService.idl
+++ b/dom/mobileconnection/interfaces/nsIMobileConnectionService.idl
@@ -1,18 +1,20 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsISupports.idl"
 
+interface nsICellInfoListCallback;
 interface nsIMobileCallForwardingOptions;
 interface nsIMobileConnection;
 interface nsIMobileConnectionInfo;
 interface nsIMobileNetworkInfo;
+interface nsINeighboringCellIdsCallback;
 interface nsIVariant;
 
 [scriptable, uuid(823d935e-8262-47ed-8429-8203096b2ff4)]
 interface nsIMobileConnectionListener : nsISupports
 {
   /**
    * Notify when voice info is changed.
    */
@@ -229,17 +231,17 @@ interface nsIMobileConnectionService : n
 
 %{C++
 template<typename T> struct already_AddRefed;
 
 already_AddRefed<nsIMobileConnectionService>
 NS_CreateMobileConnectionService();
 %}
 
-[scriptable, uuid(bde83c1d-1335-43b6-8268-ec7e320167f0)]
+[scriptable, uuid(cfc7d15b-d2c2-4f28-ad9f-b250030c3073)]
 interface nsIMobileConnection : nsISupports
 {
   /*
    * ICC service class.
    */
   const long ICC_SERVICE_CLASS_NONE       = 0; // not available
   const long ICC_SERVICE_CLASS_VOICE      = (1 << 0);
   const long ICC_SERVICE_CLASS_DATA       = (1 << 1);
@@ -759,9 +761,28 @@ interface nsIMobileConnection : nsISuppo
    * 'GenericFailure'.
    *
    * Note: Request is not available when radioState is null, 'enabling', or
    * 'disabling'. Calling the function in above conditions will receive
    * 'InvalidStateError' error.
    */
   void setRadioEnabled(in bool enabled,
                        in nsIMobileConnectionCallback requestCallback);
+
+  /**
+   * Request neighboring cell ids in GSM/UMTS network.
+   *
+   * @param callback
+   *        Called when request is finished. See nsINeighboringCellIdsCallback
+   *        for details.
+   */
+  void getNeighboringCellIds(in nsINeighboringCellIdsCallback callback);
+
+  /**
+   * Request all of the current cell information known to the radio, including
+   * neighboring cells.
+   *
+   * @param callback
+   *        Called when request is finished. See nsICellInfoListCallback
+   *        for details.
+   */
+  void getCellInfoList(in nsICellInfoListCallback callback);
 };
--- a/dom/mobileconnection/interfaces/nsINeighboringCellInfo.idl
+++ b/dom/mobileconnection/interfaces/nsINeighboringCellInfo.idl
@@ -1,21 +1,24 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsISupports.idl"
 
-[scriptable, uuid(909f5972-c74e-44dd-b72a-7ddb62aae617)]
+interface nsINeighboringCellInfo;
+
+[scriptable, uuid(0941cb79-36e5-41e0-b05f-cdb854c53f03)]
 interface nsINeighboringCellIdsCallback : nsISupports
 {
   /**
    * result is an array of nsINeighboringCellInfo.
    */
-  void notifyGetNeighboringCellIds(in jsval result);
+  void notifyGetNeighboringCellIds(in uint32_t count,
+                                   [array, size_is(count)] in nsINeighboringCellInfo result);
 
   /**
    * Callback function with error message.
    */
   void notifyGetNeighboringCellIdsFailed(in DOMString error);
 };
 
 [scriptable, uuid(87dc222e-abb3-4342-95bf-626aa19fa20e)]
--- a/dom/mobileconnection/ipc/MobileConnectionChild.cpp
+++ b/dom/mobileconnection/ipc/MobileConnectionChild.cpp
@@ -335,16 +335,30 @@ MobileConnectionChild::ExitEmergencyCbMo
 NS_IMETHODIMP
 MobileConnectionChild::SetRadioEnabled(bool aEnabled,
                                        nsIMobileConnectionCallback* aCallback)
 {
   return SendRequest(SetRadioEnabledRequest(aEnabled), aCallback)
     ? NS_OK : NS_ERROR_FAILURE;
 }
 
+NS_IMETHODIMP
+MobileConnectionChild::GetNeighboringCellIds(nsINeighboringCellIdsCallback* aCallback)
+{
+  // This function is supported in chrome context only.
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+MobileConnectionChild::GetCellInfoList(nsICellInfoListCallback* aCallback)
+{
+  // This function is supported in chrome context only.
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
 bool
 MobileConnectionChild::SendRequest(const MobileConnectionRequest& aRequest,
                                    nsIMobileConnectionCallback* aCallback)
 {
   NS_ENSURE_TRUE(mLive, false);
 
   // Deallocated in MobileConnectionChild::DeallocPMobileConnectionRequestChild().
   MobileConnectionRequestChild* actor =
--- a/dom/mobileconnection/tests/marionette/manifest.ini
+++ b/dom/mobileconnection/tests/marionette/manifest.ini
@@ -31,8 +31,9 @@ disabled = Bug 979137
 [test_mobile_supported_network_types.js]
 [test_mobile_call_forwarding.js]
 [test_mobile_call_forwarding_set_error.js]
 [test_mobile_call_forwarding_get_error.js]
 [test_mobile_voice_privacy.js]
 [test_dsds_mobile_data_connection.js]
 [test_mobile_clir.js]
 [test_mobile_clir_radio_off.js]
+[test_mobile_neighboring_cell_ids.js]
new file mode 100644
--- /dev/null
+++ b/dom/mobileconnection/tests/marionette/test_mobile_neighboring_cell_ids.js
@@ -0,0 +1,38 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+MARIONETTE_TIMEOUT = 30000;
+// This test must run in chrome context.
+MARIONETTE_CONTEXT = "chrome";
+
+let Promise = Cu.import("resource://gre/modules/Promise.jsm").Promise;
+
+let service = Cc["@mozilla.org/mobileconnection/mobileconnectionservice;1"]
+              .getService(Ci.nsIMobileConnectionService);
+ok(service, "service.constructor is " + service.constructor);
+
+let mobileConnection = service.getItemByServiceId(0);
+ok(mobileConnection, "mobileConnection.constructor is " + mobileConnection.constrctor);
+
+function testGetNeighboringCellIds() {
+  log("Test getting mobile neighboring cell ids");
+  let deferred = Promise.defer();
+
+  mobileConnection.getNeighboringCellIds({
+    notifyGetNeighboringCellIds: function(aResult) {
+      deferred.resolve(aResult);
+    },
+    notifyGetNeighboringCellIdsFailed: function(aError) {
+      deferred.reject(aError);
+    }
+  });
+  return deferred.promise;
+}
+
+// Start tests
+testGetNeighboringCellIds()
+  .then(function resolve(aResult) {
+    ok(false, "getNeighboringCellIds should not success");
+  }, function reject(aError) {
+    is(aError, "RequestNotSupported", "failed to getNeighboringCellIds");
+  }).then(finish);
\ No newline at end of file
--- a/dom/system/gonk/AutoMounter.cpp
+++ b/dom/system/gonk/AutoMounter.cpp
@@ -75,20 +75,23 @@ USING_MTP_NAMESPACE
 #define ICS_SYS_USB_FUNCTIONS "/sys/devices/virtual/android_usb/android0/functions"
 #define ICS_SYS_UMS_DIRECTORY "/sys/devices/virtual/android_usb/android0/f_mass_storage"
 #define ICS_SYS_MTP_DIRECTORY "/sys/devices/virtual/android_usb/android0/f_mtp"
 #define ICS_SYS_USB_STATE     "/sys/devices/virtual/android_usb/android0/state"
 
 #define USE_DEBUG 0
 
 #undef LOG
+#undef LOGW
+#undef ERR
 #define LOG(args...)  __android_log_print(ANDROID_LOG_INFO,  "AutoMounter", ## args)
 #define LOGW(args...) __android_log_print(ANDROID_LOG_WARN,  "AutoMounter", ## args)
 #define ERR(args...)  __android_log_print(ANDROID_LOG_ERROR, "AutoMounter", ## args)
 
+#undef DBG
 #if USE_DEBUG
 #define DBG(args...)  __android_log_print(ANDROID_LOG_DEBUG, "AutoMounter" , ## args)
 #else
 #define DBG(args...)
 #endif
 
 namespace mozilla {
 namespace system {
@@ -265,17 +268,17 @@ public:
       }
     }
   }
 
   void UpdateState();
 
   void ConfigureUsbFunction(const char* aUsbFunc);
 
-  void StartMtpServer();
+  bool StartMtpServer();
   void StopMtpServer();
 
   void StartUmsSharing();
   void StopUmsSharing();
 
 
   const char* ModeStr(int32_t aMode)
   {
@@ -577,34 +580,54 @@ SetUsbFunction(const char* aUsbFunc)
       }
     }
   }
 
   LOG("SetUsbFunction(%s) %s to '%s'", aUsbFunc, SYS_USB_CONFIG, newSysUsbConfig);
   property_set(SYS_USB_CONFIG, newSysUsbConfig);
 }
 
-void
+bool
 AutoMounter::StartMtpServer()
 {
   if (sMozMtpServer) {
     // Mtp Server is already running - nothing to do
-    return;
+    return true;
   }
   LOG("Starting MtpServer");
+
+  // For debugging, Change the #if 0 to #if 1, and then attach gdb during
+  // the 5 second interval below. Otherwise, configuring MTP will cause adb
+  // (and thus gdb) to get bounced.
+#if 0
+  LOG("Sleeping");
+  PRTime now = PR_Now();
+  PRTime stopTime = now + 5000000;
+  while (PR_Now() < stopTime) {
+    LOG("Sleeping...");
+    sleep(1);
+  }
+  LOG("Sleep done");
+#endif
+
   sMozMtpServer = new MozMtpServer();
-  sMozMtpServer->Run();
+  if (!sMozMtpServer->Init()) {
+    return false;
+  }
 
   VolumeArray::index_type volIndex;
   VolumeArray::size_type  numVolumes = VolumeManager::NumVolumes();
   for (volIndex = 0; volIndex < numVolumes; volIndex++) {
     RefPtr<Volume> vol = VolumeManager::GetVolume(volIndex);
     nsRefPtr<MozMtpStorage> storage = new MozMtpStorage(vol, sMozMtpServer);
     mMozMtpStorage.AppendElement(storage);
   }
+
+  sMozMtpServer->Run();
+  return true;
 }
 
 void
 AutoMounter::StopMtpServer()
 {
   LOG("Stopping MtpServer");
 
   mMozMtpStorage.Clear();
@@ -731,18 +754,23 @@ AutoMounter::UpdateState()
         break;
       }
       if (mtpEnabled) {
         if (mtpConfigured) {
           // The USB layer has already been configured. Now we can go ahead
           // and start the MTP server. This particular codepath will not
           // normally be taken, but it could happen if you stop and restart
           // b2g while sys.usb.config is set to enable mtp.
-          StartMtpServer();
-          SetState(STATE_MTP_STARTED);
+          if (StartMtpServer()) {
+            SetState(STATE_MTP_STARTED);
+          } else {
+            // Unable to start MTP. Go back to UMS.
+            SetUsbFunction(USB_FUNC_UMS);
+            SetState(STATE_UMS_CONFIGURING);
+          }
         } else {
           // We need to configure USB to use mtp. Wait for it to be configured
           // before we start the MTP server.
           SetUsbFunction(USB_FUNC_MTP);
           SetState(STATE_MTP_CONFIGURING);
         }
       } else if (umsConfigured) {
         // UMS is already configured.
@@ -758,18 +786,23 @@ AutoMounter::UpdateState()
 
     case STATE_MTP_CONFIGURING:
       // While configuring, the USB configuration state will change from
       // CONFIGURED -> CONNECTED -> DISCONNECTED -> CONNECTED -> CONFIGURED
       // so we don't check for cable unplugged here.
       if (mtpEnabled && mtpConfigured) {
         // The USB layer has been configured. Now we can go ahead and start
         // the MTP server.
-        StartMtpServer();
-        SetState(STATE_MTP_STARTED);
+        if (StartMtpServer()) {
+          SetState(STATE_MTP_STARTED);
+        } else {
+          // Unable to start MTP. Go back to UMS.
+          SetUsbFunction(USB_FUNC_UMS);
+          SetState(STATE_UMS_CONFIGURING);
+        }
         break;
       }
       if (rndisConfigured) {
         SetState(STATE_RNDIS_CONFIGURED);
         break;
       }
       break;
 
--- a/dom/system/gonk/AutoMounterSetting.cpp
+++ b/dom/system/gonk/AutoMounterSetting.cpp
@@ -19,16 +19,17 @@
 #include "nsThreadUtils.h"
 #include "xpcpublic.h"
 #include "mozilla/dom/ScriptSettings.h"
 #include "mozilla/Attributes.h"
 #include "mozilla/dom/BindingUtils.h"
 #include "mozilla/dom/SettingChangeNotificationBinding.h"
 
 #undef LOG
+#undef ERR
 #define LOG(args...)  __android_log_print(ANDROID_LOG_INFO, "AutoMounterSetting" , ## args)
 #define ERR(args...)  __android_log_print(ANDROID_LOG_ERROR, "AutoMounterSetting" , ## args)
 
 #define UMS_MODE                  "ums.mode"
 #define UMS_STATUS                "ums.status"
 #define UMS_VOLUME_ENABLED_PREFIX "ums.volume."
 #define UMS_VOLUME_ENABLED_SUFFIX ".enabled"
 #define MOZSETTINGS_CHANGED       "mozsettings-changed"
--- a/dom/system/gonk/MozMtpDatabase.cpp
+++ b/dom/system/gonk/MozMtpDatabase.cpp
@@ -166,19 +166,39 @@ MozMtpDatabase::GetEntry(MtpObjectHandle
   }
   return entry;
 }
 
 void
 MozMtpDatabase::RemoveEntry(MtpObjectHandle aHandle)
 {
   MutexAutoLock lock(mMutex);
+  if (!IsValidHandle(aHandle)) {
+    return;
+  }
 
-  if (aHandle > 0 && aHandle < mDb.Length()) {
-    mDb[aHandle] = nullptr;
+  RefPtr<DbEntry> removedEntry = mDb[aHandle];
+  mDb[aHandle] = nullptr;
+  MTP_DBG("0x%08x removed", aHandle);
+  // if the entry is not a folder, just return.
+  if (removedEntry->mObjectFormat != MTP_FORMAT_ASSOCIATION) {
+    return;
+  }
+
+  // Find out and remove the children of aHandle.
+  // Since the index for a directory will always be less than the index of any of its children,
+  // we can remove the entire subtree in one pass.
+  ProtectedDbArray::size_type numEntries = mDb.Length();
+  ProtectedDbArray::index_type entryIndex;
+  for (entryIndex = aHandle+1; entryIndex < numEntries; entryIndex++) {
+    RefPtr<DbEntry> entry = mDb[entryIndex];
+    if (entry && IsValidHandle(entry->mParent) && !mDb[entry->mParent]) {
+      mDb[entryIndex] = nullptr;
+      MTP_DBG("0x%08x removed", aHandle);
+    }
   }
 }
 
 void
 MozMtpDatabase::RemoveEntryAndNotify(MtpObjectHandle aHandle, RefCountedMtpServer* aMtpServer)
 {
   RemoveEntry(aHandle);
   aMtpServer->sendObjectRemoved(aHandle);
--- a/dom/system/gonk/MozMtpDatabase.h
+++ b/dom/system/gonk/MozMtpDatabase.h
@@ -221,16 +221,21 @@ private:
     MatchAll,
     MatchHandle,
     MatchParent,
     MatchFormat,
     MatchHandleFormat,
     MatchParentFormat,
   };
 
+  bool IsValidHandle(MtpObjectHandle aHandle)
+  {
+    return aHandle > 0 && aHandle < mDb.Length();
+  }
+
   void AddEntry(DbEntry* aEntry);
   void AddEntryAndNotify(DbEntry* aEntr, RefCountedMtpServer* aMtpServer);
   void DumpEntries(const char* aLabel);
   MtpObjectHandle FindEntryByPath(const nsACString& aPath);
   mozilla::TemporaryRef<DbEntry> GetEntry(MtpObjectHandle aHandle);
   void RemoveEntry(MtpObjectHandle aHandle);
   void RemoveEntryAndNotify(MtpObjectHandle aHandle, RefCountedMtpServer* aMtpServer);
   void QueryEntries(MatchType aMatchType, uint32_t aMatchField1,
--- a/dom/system/gonk/MozMtpServer.cpp
+++ b/dom/system/gonk/MozMtpServer.cpp
@@ -15,17 +15,16 @@
 #include <stdio.h>
 #include <unistd.h>
 
 #include <cutils/properties.h>
 #include <private/android_filesystem_config.h>
 
 #include "base/message_loop.h"
 #include "DeviceStorage.h"
-#include "mozilla/FileUtils.h"
 #include "mozilla/LazyIdleThread.h"
 #include "mozilla/Scoped.h"
 #include "mozilla/Services.h"
 #include "mozilla/StaticPtr.h"
 #include "nsAutoPtr.h"
 #include "nsIObserver.h"
 #include "nsIObserverService.h"
 #include "nsISupportsImpl.h"
@@ -220,38 +219,43 @@ MozMtpServer::GetMtpServer()
 
 already_AddRefed<MozMtpDatabase>
 MozMtpServer::GetMozMtpDatabase()
 {
   nsRefPtr<MozMtpDatabase> db = mMozMtpDatabase;
   return db.forget();
 }
 
-void
-MozMtpServer::Run()
+bool
+MozMtpServer::Init()
 {
   MOZ_ASSERT(MessageLoop::current() == XRE_GetIOMessageLoop());
 
   const char *mtpUsbFilename = "/dev/mtp_usb";
-  ScopedClose mtpUsbFd(open(mtpUsbFilename, O_RDWR));
-  if (mtpUsbFd.get() < 0) {
+  mMtpUsbFd = open(mtpUsbFilename, O_RDWR);
+  if (mMtpUsbFd.get() < 0) {
     MTP_ERR("open of '%s' failed", mtpUsbFilename);
-    return;
+    return false;
   }
-  MTP_LOG("Opened '%s' fd %d", mtpUsbFilename, mtpUsbFd.get());
+  MTP_LOG("Opened '%s' fd %d", mtpUsbFilename, mMtpUsbFd.get());
 
   mMozMtpDatabase = new MozMtpDatabase();
-  mMtpServer = new RefCountedMtpServer(mtpUsbFd.get(),        // fd
+  mMtpServer = new RefCountedMtpServer(mMtpUsbFd.get(),        // fd
                                        mMozMtpDatabase.get(), // MtpDatabase
                                        false,                 // ptp?
                                        AID_MEDIA_RW,          // file group
                                        0664,                  // file permissions
                                        0775);                 // dir permissions
+  return true;
+}
 
+void
+MozMtpServer::Run()
+{
   nsresult rv = NS_NewNamedThread("MtpServer", getter_AddRefs(mServerThread));
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return;
   }
   MOZ_ASSERT(mServerThread);
-  mServerThread->Dispatch(new MtpServerRunnable(mtpUsbFd.forget(), this), NS_DISPATCH_NORMAL);
+  mServerThread->Dispatch(new MtpServerRunnable(mMtpUsbFd.forget(), this), NS_DISPATCH_NORMAL);
 }
 
 END_MTP_NAMESPACE
--- a/dom/system/gonk/MozMtpServer.h
+++ b/dom/system/gonk/MozMtpServer.h
@@ -5,16 +5,18 @@
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_system_mozmtpserver_h__
 #define mozilla_system_mozmtpserver_h__
 
 #include "MozMtpCommon.h"
 #include "MozMtpDatabase.h"
 
+#include "mozilla/FileUtils.h"
+
 #include "nsAutoPtr.h"
 #include "nsCOMPtr.h"
 #include "nsIThread.h"
 
 namespace mozilla {
 namespace system {
   class Volume;
 }
@@ -35,26 +37,26 @@ public:
   }
 };
 
 class MozMtpServer
 {
 public:
   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(MozMtpServer)
 
+  bool Init();
   void Run();
 
-//  void UpdateStorage(android::MtpStorageID id, Volume *vol);
-
   already_AddRefed<RefCountedMtpServer> GetMtpServer();
   already_AddRefed<MozMtpDatabase> GetMozMtpDatabase();
 
 private:
   nsRefPtr<RefCountedMtpServer> mMtpServer;
   nsRefPtr<MozMtpDatabase> mMozMtpDatabase;
   nsCOMPtr<nsIThread> mServerThread;
+  ScopedClose mMtpUsbFd;
 };
 
 END_MTP_NAMESPACE
 
 #endif  // mozilla_system_mozmtpserver_h__
 
 
--- a/dom/system/gonk/OpenFileFinder.cpp
+++ b/dom/system/gonk/OpenFileFinder.cpp
@@ -8,20 +8,23 @@
 #include "nsPrintfCString.h"
 
 #include <sys/stat.h>
 #include <errno.h>
 
 #define USE_DEBUG 0
 
 #undef LOG
+#undef LOGW
+#undef ERR
 #define LOG(args...)  __android_log_print(ANDROID_LOG_INFO,  "OpenFileFinder", ## args)
 #define LOGW(args...) __android_log_print(ANDROID_LOG_WARN,  "OpenFileFinder", ## args)
 #define ERR(args...)  __android_log_print(ANDROID_LOG_ERROR, "OpenFileFinder", ## args)
 
+#undef DBG
 #if USE_DEBUG
 #define DBG(args...)  __android_log_print(ANDROID_LOG_DEBUG, "OpenFileFinder" , ## args)
 #else
 #define DBG(args...)
 #endif
 
 namespace mozilla {
 namespace system {
--- a/dom/system/gonk/RadioInterfaceLayer.js
+++ b/dom/system/gonk/RadioInterfaceLayer.js
@@ -48,26 +48,16 @@ let RILQUIRKS_HAVE_IPV6 =
   libcutils.property_get("ro.moz.ril.ipv6", "false") == "true";
 
 const RADIOINTERFACELAYER_CID =
   Components.ID("{2d831c8d-6017-435b-a80c-e5d422810cea}");
 const RADIOINTERFACE_CID =
   Components.ID("{6a7c91f0-a2b3-4193-8562-8969296c0b54}");
 const RILNETWORKINTERFACE_CID =
   Components.ID("{3bdd52a9-3965-4130-b569-0ac5afed045e}");
-const NEIGHBORINGCELLINFO_CID =
-  Components.ID("{f9dfe26a-851e-4a8b-a769-cbb1baae7ded}");
-const GSMCELLINFO_CID =
-  Components.ID("{41f6201e-7263-42e3-b31f-38a9dc8a280a}");
-const WCDMACELLINFO_CID =
-  Components.ID("{eeaaf307-df6e-4c98-b121-e3302b1fc468}");
-const CDMACELLINFO_CID =
-  Components.ID("{b497d6e4-4cb8-4d6e-b673-840c7d5ddf25}");
-const LTECELLINFO_CID =
-  Components.ID("{c7e0a78a-4e99-42f5-9251-e6172c5ed8d8}");
 
 const NS_XPCOM_SHUTDOWN_OBSERVER_ID      = "xpcom-shutdown";
 const kNetworkConnStateChangedTopic      = "network-connection-state-changed";
 const kSmsReceivedObserverTopic          = "sms-received";
 const kSilentSmsReceivedObserverTopic    = "silent-sms-received";
 const kSmsSendingObserverTopic           = "sms-sending";
 const kSmsSentObserverTopic              = "sms-sent";
 const kSmsFailedObserverTopic            = "sms-failed";
@@ -92,19 +82,16 @@ const DOM_MOBILE_MESSAGE_DELIVERY_RECEIV
 const DOM_MOBILE_MESSAGE_DELIVERY_SENDING  = "sending";
 const DOM_MOBILE_MESSAGE_DELIVERY_SENT     = "sent";
 const DOM_MOBILE_MESSAGE_DELIVERY_ERROR    = "error";
 
 const RADIO_POWER_OFF_TIMEOUT = 30000;
 const SMS_HANDLED_WAKELOCK_TIMEOUT = 5000;
 const HW_DEFAULT_CLIENT_ID = 0;
 
-const INT32_MAX = 2147483647;
-const UNKNOWN_RSSI = 99;
-
 const RIL_IPC_ICCMANAGER_MSG_NAMES = [
   "RIL:GetRilContext",
   "RIL:SendStkResponse",
   "RIL:SendStkMenuSelection",
   "RIL:SendStkTimerExpiration",
   "RIL:SendStkEventDownload",
   "RIL:GetCardLockState",
   "RIL:UnlockCardLock",
@@ -957,137 +944,16 @@ CdmaIccInfo.prototype = {
                                          Ci.nsIIccInfo]),
 
   // nsICdmaIccInfo
 
   mdn: null,
   prlVersion: 0
 };
 
-function NeighboringCellInfo() {}
-NeighboringCellInfo.prototype = {
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsINeighboringCellInfo]),
-  classID:        NEIGHBORINGCELLINFO_CID,
-  classInfo:      XPCOMUtils.generateCI({
-    classID:          NEIGHBORINGCELLINFO_CID,
-    classDescription: "NeighboringCellInfo",
-    interfaces:       [Ci.nsINeighboringCellInfo]
-  }),
-
-  // nsINeighboringCellInfo
-
-  networkType: null,
-  gsmLocationAreaCode: -1,
-  gsmCellId: -1,
-  wcdmaPsc: -1,
-  signalStrength: UNKNOWN_RSSI
-};
-
-function CellInfo() {}
-CellInfo.prototype = {
-  type: null,
-  registered: false,
-  timestampType: Ci.nsICellInfo.TIMESTAMP_TYPE_UNKNOWN,
-  timestamp: 0
-};
-
-function GsmCellInfo() {}
-GsmCellInfo.prototype = {
-  __proto__: CellInfo.prototype,
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsIGsmCellInfo]),
-  classID: GSMCELLINFO_CID,
-  classInfo: XPCOMUtils.generateCI({
-    classID:          GSMCELLINFO_CID,
-    classDescription: "GsmCellInfo",
-    interfaces:       [Ci.nsIGsmCellInfo]
-  }),
-
-  // nsIGsmCellInfo
-
-  mcc: INT32_MAX,
-  mnc: INT32_MAX,
-  lac: INT32_MAX,
-  cid: INT32_MAX,
-  signalStrength: UNKNOWN_RSSI,
-  bitErrorRate: UNKNOWN_RSSI
-};
-
-function WcdmaCellInfo() {}
-WcdmaCellInfo.prototype = {
-  __proto__: CellInfo.prototype,
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsIWcdmaCellInfo]),
-  classID: WCDMACELLINFO_CID,
-  classInfo: XPCOMUtils.generateCI({
-    classID:          WCDMACELLINFO_CID,
-    classDescription: "WcdmaCellInfo",
-    interfaces:       [Ci.nsIWcdmaCellInfo]
-  }),
-
-  // nsIWcdmaCellInfo
-
-  mcc: INT32_MAX,
-  mnc: INT32_MAX,
-  lac: INT32_MAX,
-  cid: INT32_MAX,
-  psc: INT32_MAX,
-  signalStrength: UNKNOWN_RSSI,
-  bitErrorRate: UNKNOWN_RSSI
-};
-
-function LteCellInfo() {}
-LteCellInfo.prototype = {
-  __proto__: CellInfo.prototype,
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsILteCellInfo]),
-  classID: LTECELLINFO_CID,
-  classInfo: XPCOMUtils.generateCI({
-    classID:          LTECELLINFO_CID,
-    classDescription: "LteCellInfo",
-    interfaces:       [Ci.nsILteCellInfo]
-  }),
-
-  // nsILteCellInfo
-
-  mcc: INT32_MAX,
-  mnc: INT32_MAX,
-  cid: INT32_MAX,
-  pcid: INT32_MAX,
-  tac: INT32_MAX,
-  signalStrength: UNKNOWN_RSSI,
-  rsrp: INT32_MAX,
-  rsrq: INT32_MAX,
-  rssnr: INT32_MAX,
-  cqi: INT32_MAX,
-  timingAdvance: INT32_MAX
-};
-
-function CdmaCellInfo() {}
-CdmaCellInfo.prototype = {
-  __proto__: CellInfo.prototype,
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsICdmaCellInfo]),
-  classID: CDMACELLINFO_CID,
-  classInfo: XPCOMUtils.generateCI({
-    classID:          CDMACELLINFO_CID,
-    classDescription: "CdmaCellInfo",
-    interfaces:       [Ci.nsICdmaCellInfo]
-  }),
-
-  // nsICdmaCellInfo
-
-  networkId: INT32_MAX,
-  systemId: INT32_MAX,
-  baseStationId: INT32_MAX,
-  longitude: INT32_MAX,
-  latitude: INT32_MAX,
-  cdmaDbm: INT32_MAX,
-  cdmaEcio: INT32_MAX,
-  evdoDbm: INT32_MAX,
-  evdoEcio: INT32_MAX,
-  evdoSnr: INT32_MAX
-};
-
 function DataConnectionHandler(clientId, radioInterface) {
   // Initial owning attributes.
   this.clientId = clientId;
   this.radioInterface = radioInterface;
   this.dataCallSettings = {
     oldEnabled: false,
     enabled: false,
     roamingEnabled: false
@@ -3890,77 +3756,16 @@ RadioInterface.prototype = {
     if (callback) {
       this.workerMessenger.send(rilMessageType, message, function(response) {
         return callback.handleResponse(response);
       });
     } else {
       this.workerMessenger.send(rilMessageType, message);
     }
   },
-
-  getCellInfoList: function(callback) {
-    this.workerMessenger.send("getCellInfoList",
-                              null,
-                              function(response) {
-      if (response.errorMsg) {
-        callback.notifyGetCellInfoListFailed(response.errorMsg);
-        return;
-      }
-
-      let cellInfoList = [];
-      let count = response.result.length;
-      for (let i = 0; i < count; i++) {
-        let srcCellInfo = response.result[i];
-        let cellInfo;
-        switch (srcCellInfo.type) {
-          case RIL.CELL_INFO_TYPE_GSM:
-            cellInfo = new GsmCellInfo();
-            break;
-          case RIL.CELL_INFO_TYPE_WCDMA:
-            cellInfo = new WcdmaCellInfo();
-            break;
-          case RIL.CELL_INFO_TYPE_LTE:
-            cellInfo = new LteCellInfo();
-            break;
-          case RIL.CELL_INFO_TYPE_CDMA:
-            cellInfo = new CdmaCellInfo();
-            break;
-        }
-
-        if (!cellInfo) {
-          continue;
-        }
-        this.updateInfo(srcCellInfo, cellInfo);
-        cellInfoList.push(cellInfo);
-      }
-      callback.notifyGetCellInfoList(cellInfoList);
-    }.bind(this));
-  },
-
-  getNeighboringCellIds: function(callback) {
-    this.workerMessenger.send("getNeighboringCellIds",
-                              null,
-                              function(response) {
-      if (response.errorMsg) {
-        callback.notifyGetNeighboringCellIdsFailed(response.errorMsg);
-        return;
-      }
-
-      let neighboringCellIds = [];
-      let count = response.result.length;
-      for (let i = 0; i < count; i++) {
-        let srcCellInfo = response.result[i];
-        let cellInfo = new NeighboringCellInfo();
-        this.updateInfo(srcCellInfo, cellInfo);
-        neighboringCellIds.push(cellInfo);
-      }
-      callback.notifyGetNeighboringCellIds(neighboringCellIds);
-
-    }.bind(this));
-  }
 };
 
 function DataCall(clientId, apnSetting) {
   this.clientId = clientId;
   this.apnProfile = {
     apn: apnSetting.apn,
     user: apnSetting.user,
     password: apnSetting.password,
--- a/dom/system/gonk/VolumeManagerLog.h
+++ b/dom/system/gonk/VolumeManagerLog.h
@@ -7,18 +7,20 @@
 
 #define USE_DEBUG 0
 
 #if !defined(VOLUME_MANAGER_LOG_TAG)
 #define VOLUME_MANAGER_LOG_TAG  "VolumeManager"
 #endif
 
 #undef LOG
+#undef ERR
 #define LOG(args...)  __android_log_print(ANDROID_LOG_INFO,  VOLUME_MANAGER_LOG_TAG, ## args)
 #define ERR(args...)  __android_log_print(ANDROID_LOG_ERROR, VOLUME_MANAGER_LOG_TAG, ## args)
 
+#undef DBG
 #if USE_DEBUG
 #define DBG(args...)  __android_log_print(ANDROID_LOG_DEBUG, VOLUME_MANAGER_LOG_TAG, ## args)
 #else
 #define DBG(args...)
 #endif
 
 #endif  // mozilla_system_volumemanagerlog_h__
--- a/dom/system/gonk/nsIRadioInterfaceLayer.idl
+++ b/dom/system/gonk/nsIRadioInterfaceLayer.idl
@@ -1,20 +1,18 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsISupports.idl"
 #include "nsINetworkManager.idl"
 
-interface nsICellInfoListCallback;
 interface nsIIccInfo;
 interface nsIMobileConnectionInfo;
 interface nsIMobileMessageCallback;
-interface nsINeighboringCellIdsCallback;
 
 [scriptable, uuid(6e0f45b8-410e-11e3-8c8e-b715b2cd0128)]
 interface nsIRilNetworkInterface : nsINetworkInterface
 {
   readonly attribute unsigned long serviceId;
   readonly attribute DOMString iccId;
 
   /* The following attributes are for MMS proxy settings. */
@@ -37,17 +35,17 @@ interface nsIRilContext : nsISupports
 };
 
 [scriptable, function, uuid(3bc96351-53b0-47a1-a888-c74c64b60f25)]
 interface nsIRilSendWorkerMessageCallback : nsISupports
 {
   boolean handleResponse(in jsval response);
 };
 
-[scriptable, uuid(c13a8890-797b-4557-b92f-6b959f56c1d8)]
+[scriptable, uuid(622e8809-1a89-45f7-9b35-7e49b5aaa69f)]
 interface nsIRadioInterface : nsISupports
 {
   readonly attribute nsIRilContext rilContext;
 
   /**
    * PDP APIs
    */
   void setupDataCallByType(in DOMString apntype);
@@ -67,27 +65,16 @@ interface nsIRadioInterface : nsISupport
                in boolean silent,
                in nsIMobileMessageCallback request);
 
   void sendWorkerMessage(in DOMString type,
               [optional] in jsval message,
               [optional] in nsIRilSendWorkerMessageCallback callback);
 
   void getSmscAddress(in nsIMobileMessageCallback request);
-
-  /**
-   * Request neighboring cell ids in GSM/UMTS network.
-   */
-  void getNeighboringCellIds(in nsINeighboringCellIdsCallback callback);
-
-  /**
-   * Request all of the current cell information known to the radio, including
-   * neighboring cells.
-   */
-  void getCellInfoList(in nsICellInfoListCallback callback);
 };
 
 [scriptable, uuid(78b65e8c-68e7-4510-9a05-65bba12b283e)]
 interface nsIRadioInterfaceLayer : nsISupports
 {
   readonly attribute unsigned long numRadioInterfaces;
 
   nsIRadioInterface getRadioInterface(in unsigned long clientId);
--- a/dom/system/gonk/ril_worker.js
+++ b/dom/system/gonk/ril_worker.js
@@ -210,16 +210,17 @@ BufObject.prototype = {
 
 const TELEPHONY_REQUESTS = [
   REQUEST_GET_CURRENT_CALLS,
   REQUEST_ANSWER,
   REQUEST_CONFERENCE,
   REQUEST_DIAL,
   REQUEST_DIAL_EMERGENCY_CALL,
   REQUEST_HANGUP,
+  REQUEST_HANGUP_FOREGROUND_RESUME_BACKGROUND,
   REQUEST_HANGUP_WAITING_OR_BACKGROUND,
   REQUEST_SEPARATE_CONNECTION,
   REQUEST_SWITCH_WAITING_OR_HOLDING_AND_ACTIVE,
   REQUEST_UDUB
 ];
 
 function TelephonyRequestEntry(request, action, options) {
   this.request = request;
@@ -1774,23 +1775,35 @@ RilObject.prototype = {
   sendRilRequestHangUp: function(callIndex) {
     let Buf = this.context.Buf;
     Buf.newParcel(REQUEST_HANGUP);
     Buf.writeInt32(1);
     Buf.writeInt32(callIndex);
     Buf.sendParcel();
   },
 
-  sendHangUpBackgroundRequest: function() {
+  sendHangUpForegroundRequest: function(options) {
+    this.telephonyRequestQueue.push(REQUEST_HANGUP_FOREGROUND_RESUME_BACKGROUND,
+                                    this.sendRilRequestHangUpForeground,
+                                    options);
+  },
+
+  sendRilRequestHangUpForeground: function(options) {
+    this.context.Buf.simpleRequest(REQUEST_HANGUP_FOREGROUND_RESUME_BACKGROUND,
+                                   options);
+  },
+
+  sendHangUpBackgroundRequest: function(options) {
     this.telephonyRequestQueue.push(REQUEST_HANGUP_WAITING_OR_BACKGROUND,
-                                   this.sendRilRequestHangUpWaiting, null);
-  },
-
-  sendRilRequestHangUpWaiting: function() {
-    this.context.Buf.simpleRequest(REQUEST_HANGUP_WAITING_OR_BACKGROUND);
+                                    this.sendRilRequestHangUpWaiting, options);
+  },
+
+  sendRilRequestHangUpWaiting: function(options) {
+    this.context.Buf.simpleRequest(REQUEST_HANGUP_WAITING_OR_BACKGROUND,
+                                   options);
   },
 
   /**
    * Mute or unmute the radio.
    *
    * @param mute
    *        Boolean to indicate whether to mute or unmute the radio.
    */
@@ -1956,16 +1969,37 @@ RilObject.prototype = {
   sendRilRequestSeparateConnection: function(options) {
     let Buf = this.context.Buf;
     Buf.newParcel(REQUEST_SEPARATE_CONNECTION, options);
     Buf.writeInt32(1);
     Buf.writeInt32(options.callIndex);
     Buf.sendParcel();
   },
 
+  hangUpConference: function(options) {
+    if (this._isCdma) {
+      // In cdma, ril only maintains one call index.
+      let call = this.currentCalls[1];
+      if (!call) {
+        options.success = false;
+        options.errorMsg = GECKO_ERROR_GENERIC_FAILURE;
+        this.sendChromeMessage(options);
+        return;
+      }
+      call.hangUpLocal = true;
+      this.sendHangUpRequest(1);
+    } else {
+      if (this.currentConference.state === CALL_STATE_ACTIVE) {
+        this.sendHangUpForegroundRequest(options);
+      } else {
+        this.sendHangUpBackgroundRequest(options);
+      }
+    }
+  },
+
   holdConference: function() {
     if (this._isCdma) {
       return;
     }
 
     this.sendSwitchWaitingRequest();
   },
 
@@ -5425,36 +5459,29 @@ RilObject.prototype[REQUEST_GET_IMSI] = 
     this.context.debug("IMSI: " + this.iccInfoPrivate.imsi);
   }
 
   options.rilMessageType = "iccimsi";
   options.imsi = this.iccInfoPrivate.imsi;
   this.sendChromeMessage(options);
 };
 RilObject.prototype[REQUEST_HANGUP] = function REQUEST_HANGUP(length, options) {
-  if (options.rilRequestError) {
-    return;
-  }
-
-  this.getCurrentCalls();
+  options.success = options.rilRequestError === 0;
+  options.errorMsg = RIL_ERROR_TO_GECKO_ERROR[options.rilRequestError];
+  this.sendChromeMessage(options);
+
+  if (options.success) {
+    this.getCurrentCalls();
+  }
 };
 RilObject.prototype[REQUEST_HANGUP_WAITING_OR_BACKGROUND] = function REQUEST_HANGUP_WAITING_OR_BACKGROUND(length, options) {
-  if (options.rilRequestError) {
-    return;
-  }
-
-  this.getCurrentCalls();
-};
-// TODO Bug 1012599: This one is not used.
+  RilObject.prototype[REQUEST_HANGUP].call(this, length, options);
+};
 RilObject.prototype[REQUEST_HANGUP_FOREGROUND_RESUME_BACKGROUND] = function REQUEST_HANGUP_FOREGROUND_RESUME_BACKGROUND(length, options) {
-  if (options.rilRequestError) {
-    return;
-  }
-
-  this.getCurrentCalls();
+  RilObject.prototype[REQUEST_HANGUP].call(this, length, options);
 };
 RilObject.prototype[REQUEST_SWITCH_WAITING_OR_HOLDING_AND_ACTIVE] = function REQUEST_SWITCH_WAITING_OR_HOLDING_AND_ACTIVE(length, options) {
   if (options.rilRequestError) {
     return;
   }
 
   this.getCurrentCalls();
 };
@@ -7839,16 +7866,22 @@ GsmPDUHelperObject.prototype = {
     }
 
     if (DEBUG) {
       this.context.debug("After header, " + length + " septets left of user data");
     }
 
     msg.body = null;
     msg.data = null;
+
+    if (length <= 0) {
+      // No data to read.
+      return;
+    }
+
     switch (msg.encoding) {
       case PDU_DCS_MSG_CODING_7BITS_ALPHABET:
         // 7 bit encoding allows 140 octets, which means 160 characters
         // ((140x8) / 7 = 160 chars)
         if (length > PDU_MAX_USER_DATA_7BIT) {
           if (DEBUG) {
             this.context.debug("PDU error: user data is too long: " + length);
           }
--- a/dom/system/gonk/tests/marionette/manifest.ini
+++ b/dom/system/gonk/tests/marionette/manifest.ini
@@ -7,9 +7,8 @@ qemu = true
 disabled = Bug 808783
 [test_fakevolume.js]
 [test_ril_code_quality.py]
 [test_screen_state.js]
 [test_dsds_numRadioInterfaces.js]
 [test_data_connection.js]
 [test_network_active_changed.js]
 [test_multiple_data_connection.js]
-[test_neighboring_cell_ids.js]
deleted file mode 100644
--- a/dom/system/gonk/tests/marionette/test_neighboring_cell_ids.js
+++ /dev/null
@@ -1,33 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- * http://creativecommons.org/publicdomain/zero/1.0/ */
-
-MARIONETTE_TIMEOUT = 30000;
-MARIONETTE_HEAD_JS = "head.js";
-
-function testGetNeighboringCellIds() {
-  log("Test getting neighboring cell ids");
-  let deferred = Promise.defer();
-
-  radioInterface.getNeighboringCellIds({
-    notifyGetNeighboringCellIds: function(aResult) {
-      deferred.resolve(aResult);
-    },
-    notifyGetNeighboringCellIdsFailed: function(aError) {
-      deferred.reject(aError);
-    }
-  });
-  return deferred.promise;
-}
-
-// Start tests
-startTestBase(function() {
-  // TODO: Bug 1028837 - B2G Emulator: support neighboring cell ids.
-  // Currently, emulator does not support RIL_REQUEST_NEIGHBORING_CELL_IDS,
-  // so we expect to get a 'RequestNotSupported' error here.
-  return testGetNeighboringCellIds()
-    .then(function resolve(aResult) {
-      ok(false, "getNeighboringCellIds should not success");
-    }, function reject(aError) {
-      is(aError, "RequestNotSupported", "failed to getNeighboringCellIds");
-    });
-});
--- a/dom/telephony/TelephonyCallGroup.cpp
+++ b/dom/telephony/TelephonyCallGroup.cpp
@@ -1,23 +1,25 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "TelephonyCallGroup.h"
-#include "mozilla/dom/TelephonyCallGroupBinding.h"
 
 #include "CallsList.h"
+#include "Telephony.h"
 #include "mozilla/dom/CallEvent.h"
 #include "mozilla/dom/CallGroupErrorEvent.h"
-#include "Telephony.h"
+#include "mozilla/dom/TelephonyCallGroupBinding.h"
+#include "mozilla/dom/telephony/TelephonyCallback.h"
 
 using namespace mozilla::dom;
+using namespace mozilla::dom::telephony;
 using mozilla::ErrorResult;
 
 TelephonyCallGroup::TelephonyCallGroup(nsPIDOMWindow* aOwner)
   : DOMEventTargetHelper(aOwner)
   , mCallState(nsITelephonyService::CALL_STATE_UNKNOWN)
 {
 }
 
@@ -272,16 +274,38 @@ TelephonyCallGroup::Remove(TelephonyCall
   call = GetCall(serviceId, callIndex);
   if (call) {
     aRv = mTelephony->Service()->SeparateCall(serviceId, callIndex);
   } else {
     NS_WARNING("Didn't have this call. Ignore!");
   }
 }
 
+already_AddRefed<Promise>
+TelephonyCallGroup::HangUp(ErrorResult& aRv)
+{
+  MOZ_ASSERT(!mCalls.IsEmpty());
+
+  nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(GetOwner());
+  if (!global) {
+    aRv.Throw(NS_ERROR_FAILURE);
+    return nullptr;
+  }
+
+  nsRefPtr<Promise> promise = Promise::Create(global, aRv);
+  NS_ENSURE_TRUE(!aRv.Failed(), nullptr);
+
+  nsCOMPtr<nsITelephonyCallback> callback = new TelephonyCallback(promise);
+  aRv = mTelephony->Service()->HangUpConference(mCalls[0]->ServiceId(),
+                                                callback);
+  NS_ENSURE_TRUE(!aRv.Failed(), nullptr);
+
+  return promise.forget();
+}
+
 void
 TelephonyCallGroup::Hold(ErrorResult& aRv)
 {
   if (mCallState != nsITelephonyService::CALL_STATE_CONNECTED) {
     NS_WARNING("Hold non-connected call ignored!");
     return;
   }
 
--- a/dom/telephony/TelephonyCallGroup.h
+++ b/dom/telephony/TelephonyCallGroup.h
@@ -2,16 +2,17 @@
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_dom_telephony_telephonycallgroup_h__
 #define mozilla_dom_telephony_telephonycallgroup_h__
 
+#include "mozilla/dom/Promise.h"
 #include "mozilla/dom/telephony/TelephonyCommon.h"
 
 namespace mozilla {
 namespace dom {
 
 class TelephonyCallGroup MOZ_FINAL : public DOMEventTargetHelper
 {
   nsRefPtr<Telephony> mTelephony;
@@ -47,16 +48,19 @@ public:
   Add(TelephonyCall& aCall, ErrorResult& aRv);
 
   void
   Add(TelephonyCall& aCall, TelephonyCall& aSecondCall, ErrorResult& aRv);
 
   void
   Remove(TelephonyCall& aCall, ErrorResult& aRv);
 
+  already_AddRefed<Promise>
+  HangUp(ErrorResult& aRv);
+
   void
   Hold(ErrorResult& aRv);
 
   void
   Resume(ErrorResult& aRv);
 
   void
   GetState(nsString& aState) const
--- a/dom/telephony/gonk/TelephonyService.js
+++ b/dom/telephony/gonk/TelephonyService.js
@@ -1033,16 +1033,26 @@ TelephonyService.prototype = {
       }
 
       if (response.isCdma) {
         onCdmaSeparateCallSuccess.call(this);
       }
     });
   },
 
+  hangUpConference: function(aClientId, aCallback) {
+    this._sendToRilWorker(aClientId, "hangUpConference", null, response => {
+      if (!response.success) {
+        aCallback.notifyError(response.errorMsg);
+      } else {
+        aCallback.notifySuccess();
+      }
+    });
+  },
+
   holdConference: function(aClientId) {
     this._sendToRilWorker(aClientId, "holdConference");
   },
 
   resumeConference: function(aClientId) {
     this._sendToRilWorker(aClientId, "resumeConference");
   },
 
--- a/dom/telephony/ipc/PTelephony.ipdl
+++ b/dom/telephony/ipc/PTelephony.ipdl
@@ -25,21 +25,27 @@ struct DialRequest
 };
 
 struct USSDRequest
 {
   uint32_t clientId;
   nsString ussd;
 };
 
+struct HangUpConferenceRequest
+{
+  uint32_t clientId;
+};
+
 union IPCTelephonyRequest
 {
   EnumerateCallsRequest;
   DialRequest;
   USSDRequest;
+  HangUpConferenceRequest;
 };
 
 sync protocol PTelephony {
   manager PContent;
   manages PTelephonyRequest;
 
 child:
   NotifyCallError(uint32_t aClientId, int32_t aCallIndex, nsString aError);
--- a/dom/telephony/ipc/TelephonyIPCService.cpp
+++ b/dom/telephony/ipc/TelephonyIPCService.cpp
@@ -249,16 +249,23 @@ TelephonyIPCService::SeparateCall(uint32
     return NS_ERROR_FAILURE;
   }
 
   mPTelephonyChild->SendSeparateCall(aClientId, aCallIndex);
   return NS_OK;
 }
 
 NS_IMETHODIMP
+TelephonyIPCService::HangUpConference(uint32_t aClientId,
+                                      nsITelephonyCallback *aCallback)
+{
+  return SendRequest(nullptr, aCallback, HangUpConferenceRequest(aClientId));
+}
+
+NS_IMETHODIMP
 TelephonyIPCService::HoldConference(uint32_t aClientId)
 {
   if (!mPTelephonyChild) {
     NS_WARNING("TelephonyService used after shutdown has begun!");
     return NS_ERROR_FAILURE;
   }
 
   mPTelephonyChild->SendHoldConference(aClientId);
--- a/dom/telephony/ipc/TelephonyParent.cpp
+++ b/dom/telephony/ipc/TelephonyParent.cpp
@@ -40,16 +40,18 @@ TelephonyParent::RecvPTelephonyRequestCo
 
   switch (aRequest.type()) {
     case IPCTelephonyRequest::TEnumerateCallsRequest:
       return actor->DoRequest(aRequest.get_EnumerateCallsRequest());
     case IPCTelephonyRequest::TDialRequest:
       return actor->DoRequest(aRequest.get_DialRequest());
     case IPCTelephonyRequest::TUSSDRequest:
       return actor->DoRequest(aRequest.get_USSDRequest());
+    case IPCTelephonyRequest::THangUpConferenceRequest:
+      return actor->DoRequest(aRequest.get_HangUpConferenceRequest());
     default:
       MOZ_CRASH("Unknown type!");
   }
 
   return false;
 }
 
 PTelephonyRequestParent*
@@ -446,16 +448,30 @@ TelephonyRequestParent::DoRequest(const 
     service->SendUSSD(aRequest.clientId(), aRequest.ussd(), this);
   } else {
     return NS_SUCCEEDED(NotifyError(NS_LITERAL_STRING("InvalidStateError")));
   }
 
   return true;
 }
 
+bool
+TelephonyRequestParent::DoRequest(const HangUpConferenceRequest& aRequest)
+{
+  nsCOMPtr<nsITelephonyService> service =
+    do_GetService(TELEPHONY_SERVICE_CONTRACTID);
+  if (service) {
+    service->HangUpConference(aRequest.clientId(), this);
+  } else {
+    return NS_SUCCEEDED(NotifyError(NS_LITERAL_STRING("InvalidStateError")));
+  }
+
+  return true;
+}
+
 nsresult
 TelephonyRequestParent::SendResponse(const IPCTelephonyResponse& aResponse)
 {
   NS_ENSURE_TRUE(!mActorDestroyed, NS_ERROR_FAILURE);
 
   return Send__delete__(this, aResponse) ? NS_OK : NS_ERROR_FAILURE;
 }
 
--- a/dom/telephony/ipc/TelephonyParent.h
+++ b/dom/telephony/ipc/TelephonyParent.h
@@ -124,13 +124,16 @@ private:
   bool
   DoRequest(const EnumerateCallsRequest& aRequest);
 
   bool
   DoRequest(const DialRequest& aRequest);
 
   bool
   DoRequest(const USSDRequest& aRequest);
+
+  bool
+  DoRequest(const HangUpConferenceRequest& aRequest);
 };
 
 END_TELEPHONY_NAMESPACE
 
 #endif /* mozilla_dom_telephony_TelephonyParent_h */
--- a/dom/telephony/nsITelephonyService.idl
+++ b/dom/telephony/nsITelephonyService.idl
@@ -235,17 +235,17 @@ interface nsITelephonyDialCallback : nsI
 #define TELEPHONY_SERVICE_CONTRACTID \
   "@mozilla.org/telephony/telephonyservice;1"
 %}
 
 /**
  * XPCOM component (in the content process) that provides the telephony
  * information.
  */
-[scriptable, uuid(79188caa-046a-48e1-b9c5-2e891504dc7a)]
+[scriptable, uuid(6fa2d94b-80ee-4085-b6a0-535811ba9bb6)]
 interface nsITelephonyService : nsISupports
 {
   const unsigned short CALL_STATE_UNKNOWN = 0;
   const unsigned short CALL_STATE_DIALING = 1;
   const unsigned short CALL_STATE_ALERTING = 2;
   const unsigned short CALL_STATE_CONNECTING = 3;
   const unsigned short CALL_STATE_CONNECTED = 4;
   const unsigned short CALL_STATE_HOLDING = 5;
@@ -291,16 +291,18 @@ interface nsITelephonyService : nsISuppo
 
   void answerCall(in unsigned long clientId, in unsigned long callIndex);
   void rejectCall(in unsigned long clientId, in unsigned long callIndex);
   void holdCall(in unsigned long clientId, in unsigned long callIndex);
   void resumeCall(in unsigned long clientId, in unsigned long callIndex);
 
   void conferenceCall(in unsigned long clientId);
   void separateCall(in unsigned long clientId, in unsigned long callIndex);
+  void hangUpConference(in unsigned long clientId,
+                        in nsITelephonyCallback callback);
   void holdConference(in unsigned long clientId);
   void resumeConference(in unsigned long clientId);
 
   /**
    * Send an USSD on existing session. It results in error if the session is
    * not existed.
    *
    * If successful, callback.notifySuccess() will be called.
--- a/dom/telephony/test/marionette/head.js
+++ b/dom/telephony/test/marionette/head.js
@@ -1106,16 +1106,54 @@ let emulator = (function() {
 
     remoteHangUp(callToHangUp)
       .then(receive.bind(null, "remoteHangUp"));
 
     return deferred.promise;
   }
 
   /**
+   * Hangup conference.
+   *
+   * @return A deferred promise.
+   */
+  function hangUpConference() {
+    log("Hangup conference.");
+
+    let deferred = Promise.defer();
+    let done = function() {
+      deferred.resolve();
+    };
+
+    let pending = ["conference.hangUp", "conference.onstatechange"];
+    let receive = function(name) {
+      receivedPending(name, pending, done);
+    };
+
+    for (let call of conference.calls) {
+      let callName = "Call (" + call.id.number + ')';
+
+      let onstatechange = callName + ".onstatechange";
+      pending.push(onstatechange);
+      check_onstatechange(call, callName, 'disconnected',
+                          receive.bind(null, onstatechange));
+    }
+
+    check_onstatechange(conference, 'conference', '', function() {
+      receive("conference.onstatechange");
+    });
+
+    conference.hangUp().then(() => {
+      receive("conference.hangUp");
+    });
+
+    return deferred.promise;
+  }
+
+  /**
    * Create a conference with an outgoing call and an incoming call.
    *
    * @param outNumber
    *        Number of an outgoing call.
    * @param inNumber
    *        Number of an incoming call.
    * @return Promise<[outCall, inCall]>
    */
@@ -1249,16 +1287,17 @@ let emulator = (function() {
   this.gRemoteAnswer = remoteAnswer;
   this.gRemoteHangUp = remoteHangUp;
   this.gRemoteHangUpCalls = remoteHangUpCalls;
   this.gAddCallsToConference = addCallsToConference;
   this.gHoldConference = holdConference;
   this.gResumeConference = resumeConference;
   this.gRemoveCallInConference = removeCallInConference;
   this.gHangUpCallInConference = hangUpCallInConference;
+  this.gHangUpConference = hangUpConference;
   this.gSetupConference = setupConference;
   this.gReceivedPending = receivedPending;
 }());
 
 function _startTest(permissions, test) {
   function permissionSetUp() {
     SpecialPowers.setBoolPref("dom.mozSettings.enabled", true);
     for (let per of permissions) {
--- a/dom/telephony/test/marionette/manifest.ini
+++ b/dom/telephony/test/marionette/manifest.ini
@@ -47,16 +47,17 @@ disabled = Bug 821958
 [test_call_mute.js]
 [test_dsds_normal_call.js]
 [test_dsds_connection_conflict.js]
 [test_audiomanager_phonestate.js]
 [test_outgoing_answer_radio_off.js]
 [test_conference_two_calls.js]
 [test_conference_add_error.js]
 [test_conference_remove_error.js]
+[test_conference_two_hangup_all.js]
 [test_conference_two_hangup_one.js]
 [test_conference_two_hold_resume.js]
 [test_conference_two_remove_one.js]
 [test_conference_three_hangup_one.js]
 [test_conference_three_remove_one.js]
 [test_conference_add_twice_error.js]
 [test_outgoing_when_two_calls_on_line.js]
 [test_call_presentation.js]
new file mode 100644
--- /dev/null
+++ b/dom/telephony/test/marionette/test_conference_two_hangup_all.js
@@ -0,0 +1,56 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+MARIONETTE_TIMEOUT = 60000;
+MARIONETTE_HEAD_JS = 'head.js';
+
+function testConferenceHangUpForeground() {
+  log('= testConferenceHangUpForeground =');
+
+  let outCall;
+  let inCall;
+  let outNumber = "5555550101";
+  let inNumber  = "5555550201";
+
+  return Promise.resolve()
+    .then(() => gSetupConference([outNumber, inNumber]))
+    .then(calls => {
+      [outCall, inCall] = calls;
+    })
+    .then(() => gHangUpConference())
+    .then(() => gCheckAll(null, [], '', [], []));
+}
+
+function testConferenceHangUpBackground() {
+  log('= testConferenceHangUpBackground =');
+
+  let outCall;
+  let inCall;
+  let outNumber = "5555550101";
+  let inNumber  = "5555550201";
+  let outInfo = gOutCallStrPool(outNumber);
+  let inInfo = gInCallStrPool(inNumber);
+
+  return Promise.resolve()
+    .then(() => gSetupConference([outNumber, inNumber]))
+    .then(calls => {
+      [outCall, inCall] = calls;
+    })
+    .then(() => gHoldConference([outCall, inCall], function() {
+      gCheckState(null, [], 'held', [outCall, inCall]);
+    }))
+    .then(() => gCheckAll(null, [], 'held', [outCall, inCall],
+                          [outInfo.held, inInfo.held]))
+    .then(() => gHangUpConference())
+    .then(() => gCheckAll(null, [], '', [], []));
+}
+
+// Start the test
+startTest(function() {
+  testConferenceHangUpForeground()
+    .then(() => testConferenceHangUpBackground())
+    .then(null, error => {
+      ok(false, 'promise rejects during test.');
+    })
+    .then(finish);
+});
--- a/dom/voicemail/test/marionette/head.js
+++ b/dom/voicemail/test/marionette/head.js
@@ -131,17 +131,17 @@ let PDUBuilder = {
       for each (let header in options.headers) {
         headerLength += 2; // id + length octets
         if (header.octets) {
           headerLength += header.octets.length;
         }
       };
     }
 
-    let encodedBodyLength = options.body.length;
+    let encodedBodyLength = (options.body) ? options.body.length : 0;
     let headerOctets = (headerLength ? headerLength + 1 : 0);
 
     let paddingBits;
     let userDataLengthInSeptets;
     let headerSeptets = Math.ceil(headerOctets * 8 / 7);
     userDataLengthInSeptets = headerSeptets + encodedBodyLength;
     paddingBits = headerSeptets * 7 - headerOctets * 8;
 
@@ -156,19 +156,21 @@ let PDUBuilder = {
         if (header.octets) {
           for each (let octet in header.octets) {
             this.writeHexOctet(octet);
           }
         }
       }
     }
 
-    this.writeStringAsSeptets(options.body, paddingBits,
-                              RIL.PDU_NL_IDENTIFIER_DEFAULT,
-                              RIL.PDU_NL_IDENTIFIER_DEFAULT);
+    if (encodedBodyLength > 0) {
+      this.writeStringAsSeptets(options.body, paddingBits,
+                                RIL.PDU_NL_IDENTIFIER_DEFAULT,
+                                RIL.PDU_NL_IDENTIFIER_DEFAULT);
+    }
     return this.buf;
   },
 
   buildLevel2DiscardMwi: function(aActive, aSender, aBody) {
     return MWI_PDU_PREFIX +
            this.buildAddress(aSender) +
            MWI_PID_DEFAULT +
            (aActive ? MWI_DCS_DISCARD_ACTIVE : MWI_DCS_DISCARD_INACTIVE) +
--- a/dom/voicemail/test/marionette/test_voicemail_statuschanged.js
+++ b/dom/voicemail/test/marionette/test_voicemail_statuschanged.js
@@ -15,46 +15,47 @@ function checkEventStatus(aEvent, aServi
 
   checkVoicemailStatus(status, 0, aHasMessages, aMessageCount, aReturnNumber,
                        aReturnMessage);
 
   compareVoicemailStatus(voicemail.getStatus(0), status);
   compareVoicemailStatus(voicemail.getStatus(), status);
 }
 
-function testLevel2DiscardActive(aActive) {
+function testLevel2Discard(aActive) {
   log("    Active: " + aActive);
 
   let sender = "+15125551235";
   let body = "1 new voicemail";
   let pdu = PDUBuilder.buildLevel2DiscardMwi(aActive, sender, body);
   return sendIndicatorPDUAndWait(pdu)
     .then((aResults) => checkEventStatus(aResults[0], 0, aActive,
                                          (aActive ? -1 : 0), sender, body));
 }
 
 // Tests for Level 3 MWI with a message count in the User Data Header
-function testLevel3DiscardActive(aMessageCount) {
-  log("    Message Count: " + aMessageCount);
+function testLevel3Discard(aMessageCount, aBody) {
+  log("    Message Count: " + aMessageCount + ", Body: " + aBody);
 
   let sender = "+15125551236";
-  let body = aMessageCount + " voicemails";
-  let pdu = PDUBuilder.buildLevel3DiscardMwi(aMessageCount, sender, body);
+  let pdu = PDUBuilder.buildLevel3DiscardMwi(aMessageCount, sender, aBody);
   return sendIndicatorPDUAndWait(pdu)
     .then((aResults) => checkEventStatus(aResults[0], 0, !!aMessageCount,
-                                         aMessageCount, sender, body));
+                                         aMessageCount, sender, aBody));
 }
 
 startTestCommon(function() {
   return Promise.resolve()
 
     .then(() => log("Testing Message Waiting Indication Group"))
     // Level 2 discarded active/inactive MWI.
     .then(() => log("  Discard Message"))
-    .then(() => testLevel2DiscardActive(true))
-    .then(() => testLevel2DiscardActive(false))
+    .then(() => testLevel2Discard(true))
+    .then(() => testLevel2Discard(false))
 
     .then(() => log("Testing Special SMS Message Indication"))
     .then(() => log("  Discard Message"))
     // Level 3 discarded active/inactive MWI.
-    .then(() => testLevel3DiscardActive(3))
-    .then(() => testLevel3DiscardActive(0));
+    .then(() => testLevel3Discard(3, "3 voicemails"))
+    .then(() => testLevel3Discard(0, "0 voicemail"))
+    .then(() => testLevel3Discard(3, null))
+    .then(() => testLevel3Discard(0, null));
 });
--- a/dom/webidl/TelephonyCallGroup.webidl
+++ b/dom/webidl/TelephonyCallGroup.webidl
@@ -12,16 +12,19 @@ interface TelephonyCallGroup : EventTarg
   void add(TelephonyCall call);
 
   [Throws]
   void add(TelephonyCall call, TelephonyCall secondCall);
 
   [Throws]
   void remove(TelephonyCall call);
 
+  [NewObject, Throws]
+  Promise<void> hangUp();
+
   [Throws]
   void hold();
 
   [Throws]
   void resume();
 
   readonly attribute DOMString state;
 
--- a/gfx/layers/FrameMetrics.h
+++ b/gfx/layers/FrameMetrics.h
@@ -354,19 +354,16 @@ public:
   // This can vary based on a variety of things, such as reflowing-zoom. The
   // conversion factor for device pixels to layers pixels is just the
   // resolution.
   CSSToLayoutDeviceScale mDevPixelsPerCSSPixel;
 
   // Whether or not this frame may have touch listeners.
   bool mMayHaveTouchListeners;
 
-  // Whether or not this frame may have touch caret.
-  bool mMayHaveTouchCaret;
-
 public:
   void SetIsRoot(bool aIsRoot)
   {
     mIsRoot = aIsRoot;
   }
 
   bool GetIsRoot() const
   {
@@ -525,20 +522,33 @@ public:
     return mContentDescription;
   }
 
   void SetContentDescription(const nsCString& aContentDescription)
   {
     mContentDescription = aContentDescription;
   }
 
+  bool GetMayHaveTouchCaret() const
+  {
+    return mMayHaveTouchCaret;
+  }
+
+  void SetMayHaveTouchCaret(bool aMayHaveTouchCaret)
+  {
+    mMayHaveTouchCaret = aMayHaveTouchCaret;
+  }
+
 private:
   // New fields from now on should be made private and old fields should
   // be refactored to be private.
 
+  // Whether or not this frame may have a touch caret.
+  bool mMayHaveTouchCaret;
+
   // Whether or not this is the root scroll frame for the root content document.
   bool mIsRoot;
 
   // Whether or not this frame is for an element marked 'scrollgrab'.
   bool mHasScrollgrab;
 
   // A unique ID assigned to each scrollable frame.
   ViewID mScrollId;
--- a/gfx/layers/apz/src/AsyncPanZoomController.cpp
+++ b/gfx/layers/apz/src/AsyncPanZoomController.cpp
@@ -1031,17 +1031,17 @@ nsEventStatus AsyncPanZoomController::Re
       if (block->GetOverscrollHandoffChain()->HasFastMovingApzc()) {
         // If we're already in a fast fling, then we want the touch event to stop the fling
         // and to disallow the touch event from being used as part of a fling.
         block->DisallowSingleTap();
       }
       block->GetOverscrollHandoffChain()->CancelAnimations();
     }
 
-    if (mFrameMetrics.mMayHaveTouchListeners || mFrameMetrics.mMayHaveTouchCaret) {
+    if (mFrameMetrics.mMayHaveTouchListeners || mFrameMetrics.GetMayHaveTouchCaret()) {
       // Content may intercept the touch events and prevent-default them. So we schedule
       // a timeout to give content time to do that.
       ScheduleContentResponseTimeout();
     } else {
       // Content won't prevent-default this, so we can just pretend like we scheduled
       // a timeout and it expired. Note that we will still receive a ContentReceivedTouch
       // callback for this block, and so we need to make sure we adjust the touch balance.
       APZC_LOG("%p not waiting for content response on block %p\n", this, block);
@@ -2672,17 +2672,17 @@ void AsyncPanZoomController::NotifyLayer
 
   ReentrantMonitorAutoEnter lock(mMonitor);
   bool isDefault = mFrameMetrics.IsDefault();
 
   mLastContentPaintMetrics = aLayerMetrics;
   UpdateTransformScale();
 
   mFrameMetrics.mMayHaveTouchListeners = aLayerMetrics.mMayHaveTouchListeners;
-  mFrameMetrics.mMayHaveTouchCaret = aLayerMetrics.mMayHaveTouchCaret;
+  mFrameMetrics.SetMayHaveTouchCaret(aLayerMetrics.GetMayHaveTouchCaret());
   mFrameMetrics.SetScrollParentId(aLayerMetrics.GetScrollParentId());
   APZC_LOG_FM(aLayerMetrics, "%p got a NotifyLayersUpdated with aIsFirstPaint=%d", this, aIsFirstPaint);
 
   LogRendertraceRect(GetGuid(), "page", "brown", aLayerMetrics.mScrollableRect);
   LogRendertraceRect(GetGuid(), "painted displayport", "lightgreen",
     aLayerMetrics.mDisplayPort + aLayerMetrics.GetScrollOffset());
   if (!aLayerMetrics.mCriticalDisplayPort.IsEmpty()) {
     LogRendertraceRect(GetGuid(), "painted critical displayport", "darkgreen",
--- a/gfx/layers/ipc/CompositorParent.cpp
+++ b/gfx/layers/ipc/CompositorParent.cpp
@@ -58,16 +58,17 @@
 #include "mozilla/ipc/ProtocolTypes.h"
 #include "mozilla/unused.h"
 #include "mozilla/Hal.h"
 #include "mozilla/HalTypes.h"
 #include "mozilla/StaticPtr.h"
 #ifdef MOZ_ENABLE_PROFILER_SPS
 #include "ProfilerMarkers.h"
 #endif
+#include "mozilla/VsyncDispatcher.h"
 
 namespace mozilla {
 namespace layers {
 
 using namespace base;
 using namespace mozilla::ipc;
 using namespace mozilla::gfx;
 using namespace std;
@@ -185,16 +186,127 @@ static Thread* CompositorThread() {
   return sCompositorThreadHolder ? sCompositorThreadHolder->GetCompositorThread() : nullptr;
 }
 
 static void SetThreadPriority()
 {
   hal::SetCurrentThreadPriority(hal::THREAD_PRIORITY_COMPOSITOR);
 }
 
+CompositorVsyncObserver::CompositorVsyncObserver(CompositorParent* aCompositorParent)
+  : mNeedsComposite(false)
+  , mIsObservingVsync(false)
+  , mCompositorParent(aCompositorParent)
+  , mCurrentCompositeTaskMonitor("CurrentCompositeTaskMonitor")
+  , mCurrentCompositeTask(nullptr)
+{
+
+}
+
+CompositorVsyncObserver::~CompositorVsyncObserver()
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  UnobserveVsync();
+  mCompositorParent = nullptr;
+  mNeedsComposite = false;
+  CancelCurrentCompositeTask();
+}
+
+/**
+ * TODO Potential performance heuristics:
+ * If a composite takes 17 ms, do we composite ASAP or wait until next vsync?
+ * If a layer transaction comes after vsync, do we composite ASAP or wait until
+ * next vsync?
+ * How many skipped vsync events until we stop listening to vsync events?
+ */
+void
+CompositorVsyncObserver::SetNeedsComposite(bool aNeedsComposite)
+{
+  MOZ_ASSERT(CompositorParent::IsInCompositorThread());
+  mNeedsComposite = aNeedsComposite;
+
+  if (!mIsObservingVsync && mNeedsComposite) {
+    ObserveVsync();
+  }
+}
+
+bool
+CompositorVsyncObserver::NotifyVsync(TimeStamp aVsyncTimestamp)
+{
+  // Called from the vsync dispatch thread
+  MOZ_ASSERT(!CompositorParent::IsInCompositorThread());
+  MOZ_ASSERT(!NS_IsMainThread());
+
+  MonitorAutoLock lock(mCurrentCompositeTaskMonitor);
+  if (mCurrentCompositeTask == nullptr) {
+    mCurrentCompositeTask = NewRunnableMethod(this,
+                                              &CompositorVsyncObserver::Composite,
+                                              aVsyncTimestamp);
+    CompositorParent::CompositorLoop()->PostTask(FROM_HERE, mCurrentCompositeTask);
+  }
+  return true;
+}
+
+void
+CompositorVsyncObserver::CancelCurrentCompositeTask()
+{
+  MOZ_ASSERT(CompositorParent::IsInCompositorThread() || NS_IsMainThread());
+  MonitorAutoLock lock(mCurrentCompositeTaskMonitor);
+  if (mCurrentCompositeTask) {
+    mCurrentCompositeTask->Cancel();
+    mCurrentCompositeTask = nullptr;
+  }
+}
+
+void
+CompositorVsyncObserver::Composite(TimeStamp aVsyncTimestamp)
+{
+  MOZ_ASSERT(CompositorParent::IsInCompositorThread());
+  {
+    MonitorAutoLock lock(mCurrentCompositeTaskMonitor);
+    mCurrentCompositeTask = nullptr;
+  }
+
+  if (mNeedsComposite && mCompositorParent) {
+    mNeedsComposite = false;
+    mCompositorParent->CompositeCallback(aVsyncTimestamp);
+  } else {
+    // We're getting vsync notifications but we don't need to composite so
+    // unregister the vsync.
+    UnobserveVsync();
+  }
+}
+
+bool
+CompositorVsyncObserver::NeedsComposite()
+{
+  MOZ_ASSERT(CompositorParent::IsInCompositorThread());
+  return mNeedsComposite;
+}
+
+/**
+ * Since the vsync thread has its own locks before notifying us of vsync
+ * we can't register/unregister from the vsync thread. Any other thread is fine
+ */
+void
+CompositorVsyncObserver::ObserveVsync()
+{
+  MOZ_ASSERT(CompositorParent::IsInCompositorThread());
+  VsyncDispatcher::GetInstance()->AddCompositorVsyncObserver(this);
+  mIsObservingVsync = true;
+}
+
+void
+CompositorVsyncObserver::UnobserveVsync()
+{
+  MOZ_ASSERT(CompositorParent::IsInCompositorThread() || NS_IsMainThread());
+  VsyncDispatcher::GetInstance()->RemoveCompositorVsyncObserver(this);
+  mIsObservingVsync = false;
+}
+
 void CompositorParent::StartUp()
 {
   MOZ_ASSERT(NS_IsMainThread(), "Should be on the main Thread!");
   MOZ_ASSERT(!sCompositorThreadHolder, "The compositor thread has already been started!");
 
   sCompositorThreadHolder = new CompositorThreadHolder();
 }
 
@@ -249,16 +361,20 @@ CompositorParent::CompositorParent(nsIWi
   CompositorLoop()->PostTask(FROM_HERE, NewRunnableFunction(SetThreadPriority));
 
   mRootLayerTreeID = AllocateLayerTreeId();
   sIndirectLayerTrees[mRootLayerTreeID].mParent = this;
 
   if (gfxPrefs::AsyncPanZoomEnabled()) {
     mApzcTreeManager = new APZCTreeManager();
   }
+
+  if (gfxPrefs::VsyncAlignedCompositor()) {
+    mCompositorVsyncObserver = new CompositorVsyncObserver(this);
+  }
 }
 
 bool
 CompositorParent::IsInCompositorThread()
 {
   return CompositorThread() && CompositorThread()->thread_id() == PlatformThread::CurrentId();
 }
 
@@ -288,16 +404,17 @@ CompositorParent::Destroy()
   mCompositor = nullptr;
 
   mCompositionManager = nullptr;
   if (mApzcTreeManager) {
     mApzcTreeManager->ClearTree();
     mApzcTreeManager = nullptr;
   }
   sIndirectLayerTrees.erase(mRootLayerTreeID);
+  mCompositorVsyncObserver = nullptr;
 }
 
 void
 CompositorParent::ForceIsFirstPaint()
 {
   mCompositionManager->ForceIsFirstPaint();
 }
 
@@ -369,22 +486,27 @@ CompositorParent::RecvMakeSnapshot(const
   RefPtr<DrawTarget> target = GetDrawTargetForDescriptor(aInSnapshot, gfx::BackendType::CAIRO);
   ForceComposeToTarget(target, &aRect);
   return true;
 }
 
 bool
 CompositorParent::RecvFlushRendering()
 {
-  // If we're waiting to do a composite, then cancel it
-  // and do it immediately instead.
-  if (mCurrentCompositeTask) {
+  if (gfxPrefs::VsyncAlignedCompositor() && mCompositorVsyncObserver->NeedsComposite()) {
+    mCompositorVsyncObserver->SetNeedsComposite(false);
+    CancelCurrentCompositeTask();
+    ForceComposeToTarget(nullptr);
+  } else if (mCurrentCompositeTask) {
+    // If we're waiting to do a composite, then cancel it
+    // and do it immediately instead.
     CancelCurrentCompositeTask();
     ForceComposeToTarget(nullptr);
   }
+
   return true;
 }
 
 bool
 CompositorParent::RecvNotifyRegionInvalidated(const nsIntRegion& aRegion)
 {
   if (mLayerManager) {
     mLayerManager->AddInvalidRegion(aRegion);
@@ -492,17 +614,19 @@ CompositorParent::ForceComposition()
   // Cancel the orientation changed state to force composition
   mForceCompositionTask = nullptr;
   ScheduleRenderOnCompositorThread();
 }
 
 void
 CompositorParent::CancelCurrentCompositeTask()
 {
-  if (mCurrentCompositeTask) {
+  if (gfxPrefs::VsyncAlignedCompositor()) {
+    mCompositorVsyncObserver->CancelCurrentCompositeTask();
+  } else if (mCurrentCompositeTask) {
     mCurrentCompositeTask->Cancel();
     mCurrentCompositeTask = nullptr;
   }
 }
 
 void
 CompositorParent::SetEGLSurfaceSize(int width, int height)
 {
@@ -599,53 +723,76 @@ CalculateCompositionFrameRate()
       return kDefaultFrameRate;
     }
     return layoutFrameRatePref;
   }
   return compositionFrameRatePref;
 }
 
 void
-CompositorParent::ScheduleComposition()
+CompositorParent::ScheduleSoftwareTimerComposition()
 {
+  MOZ_ASSERT(!gfxPrefs::VsyncAlignedCompositor());
+
   if (mCurrentCompositeTask || mPaused) {
     return;
   }
 
   bool initialComposition = mLastCompose.IsNull();
   TimeDuration delta;
   if (!initialComposition)
     delta = TimeStamp::Now() - mLastCompose;
 
   int32_t rate = CalculateCompositionFrameRate();
 
   // If rate == 0 (ASAP mode), minFrameDelta must be 0 so there's no delay.
   TimeDuration minFrameDelta = TimeDuration::FromMilliseconds(
     rate == 0 ? 0.0 : std::max(0.0, 1000.0 / rate));
 
-
-  mCurrentCompositeTask = NewRunnableMethod(this, &CompositorParent::CompositeCallback);
+  mCurrentCompositeTask = NewRunnableMethod(this,
+                                            &CompositorParent::CompositeCallback,
+                                            TimeStamp::Now());
 
   if (!initialComposition && delta < minFrameDelta) {
     TimeDuration delay = minFrameDelta - delta;
 #ifdef COMPOSITOR_PERFORMANCE_WARNING
     mExpectedComposeStartTime = TimeStamp::Now() + delay;
 #endif
     ScheduleTask(mCurrentCompositeTask, delay.ToMilliseconds());
   } else {
 #ifdef COMPOSITOR_PERFORMANCE_WARNING
     mExpectedComposeStartTime = TimeStamp::Now();
 #endif
     ScheduleTask(mCurrentCompositeTask, 0);
   }
 }
 
 void
-CompositorParent::CompositeCallback()
+CompositorParent::ScheduleComposition()
 {
+  MOZ_ASSERT(IsInCompositorThread());
+  if (gfxPrefs::VsyncAlignedCompositor()) {
+    mCompositorVsyncObserver->SetNeedsComposite(true);
+  } else {
+    ScheduleSoftwareTimerComposition();
+  }
+}
+
+void
+CompositorParent::CompositeCallback(TimeStamp aScheduleTime)
+{
+  if (gfxPrefs::VsyncAlignedCompositor()) {
+    // Align OMTA to vsync time.
+    // TODO: ensure it aligns with the refresh / start time of
+    // animations
+    mLastCompose = aScheduleTime;
+  } else {
+    mLastCompose = TimeStamp::Now();
+  }
+
   mCurrentCompositeTask = nullptr;
   CompositeToTarget(nullptr);
 }
 
 // Go down the composite layer tree, setting properties to match their
 // content-side counterparts.
 static void
 SetShadowProperties(Layer* aLayer)
@@ -679,18 +826,16 @@ CompositorParent::CompositeToTarget(Draw
   TimeDuration scheduleDelta = TimeStamp::Now() - mExpectedComposeStartTime;
   if (scheduleDelta > TimeDuration::FromMilliseconds(2) ||
       scheduleDelta < TimeDuration::FromMilliseconds(-2)) {
     printf_stderr("Compositor: Compose starting off schedule by %4.1f ms\n",
                   scheduleDelta.ToMilliseconds());
   }
 #endif
 
-  mLastCompose = TimeStamp::Now();
-
   if (!CanComposite()) {
     DidComposite();
     return;
   }
 
   AutoResolveRefLayers resolve(mCompositionManager);
   SetShadowProperties(mLayerManager->GetRoot());
 
@@ -833,24 +978,28 @@ CompositorParent::ShadowLayersUpdated(La
       DidComposite();
     }
     // When testing we synchronously update the shadow tree with the animated
     // values to avoid race conditions when calling GetAnimationTransform etc.
     // (since the above SetShadowProperties will remove animation effects).
     // However, we only do this update when a composite operation is already
     // scheduled in order to better match the behavior under regular sampling
     // conditions.
-    if (mIsTesting && root && mCurrentCompositeTask) {
+    bool needTestComposite = mIsTesting && root &&
+                             (mCurrentCompositeTask ||
+                             (gfxPrefs::VsyncAlignedCompositor() &&
+                              mCompositorVsyncObserver->NeedsComposite()));
+    if (needTestComposite) {
       AutoResolveRefLayers resolve(mCompositionManager);
       SetShadowProperties(mLayerManager->GetRoot());
       bool requestNextFrame =
         mCompositionManager->TransformShadowTree(mTestTime);
       if (!requestNextFrame) {
         CancelCurrentCompositeTask();
-        // Pretend we composited in case someone is wating for this event.
+        // Pretend we composited in case someone is waiting for this event.
         DidComposite();
       }
     }
   }
   mLayerManager->NotifyShadowTreeTransaction();
 }
 
 void
@@ -865,18 +1014,22 @@ CompositorParent::SetTestSampleTime(Laye
 {
   if (aTime.IsNull()) {
     return false;
   }
 
   mIsTesting = true;
   mTestTime = aTime;
 
+  bool testComposite = mCompositionManager && (mCurrentCompositeTask ||
+                                               (gfxPrefs::VsyncAlignedCompositor()
+                                               && mCompositorVsyncObserver->NeedsComposite()));
+
   // Update but only if we were already scheduled to animate
-  if (mCompositionManager && mCurrentCompositeTask) {
+  if (testComposite) {
     AutoResolveRefLayers resolve(mCompositionManager);
     SetShadowProperties(mLayerManager->GetRoot());
     bool requestNextFrame = mCompositionManager->TransformShadowTree(aTime);
     if (!requestNextFrame) {
       CancelCurrentCompositeTask();
       // Pretend we composited in case someone is wating for this event.
       DidComposite();
     }
--- a/gfx/layers/ipc/CompositorParent.h
+++ b/gfx/layers/ipc/CompositorParent.h
@@ -30,32 +30,34 @@
 #include "mozilla/layers/GeckoContentController.h"
 #include "mozilla/layers/LayersMessages.h"  // for TargetConfig
 #include "mozilla/layers/PCompositorParent.h"
 #include "mozilla/layers/APZTestData.h"
 #include "nsAutoPtr.h"                  // for nsRefPtr
 #include "nsISupportsImpl.h"
 #include "nsSize.h"                     // for nsIntSize
 #include "ThreadSafeRefcountingWithMainThreadDestruction.h"
+#include "mozilla/VsyncDispatcher.h"
 
 class CancelableTask;
 class MessageLoop;
 class gfxContext;
 class nsIWidget;
 
 namespace mozilla {
 namespace gfx {
 class DrawTarget;
 }
 
 namespace layers {
 
 class APZCTreeManager;
 class AsyncCompositionManager;
 class Compositor;
+class CompositorParent;
 class LayerManagerComposite;
 class LayerTransactionParent;
 
 struct ScopedLayerTreeRegistration
 {
   ScopedLayerTreeRegistration(uint64_t aLayersId,
                               Layer* aRoot,
                               GeckoContentController* aController);
@@ -82,20 +84,55 @@ private:
   base::Thread* const mCompositorThread;
 
   static base::Thread* CreateCompositorThread();
   static void DestroyCompositorThread(base::Thread* aCompositorThread);
 
   friend class CompositorParent;
 };
 
+/**
+ * Manages the vsync (de)registration and tracking on behalf of the
+ * compositor when it need to paint.
+ * Turns vsync notifications into scheduled composites.
+ **/
+
+class CompositorVsyncObserver MOZ_FINAL : public VsyncObserver
+{
+  NS_INLINE_DECL_THREADSAFE_REFCOUNTING_WITH_MAIN_THREAD_DESTRUCTION(CompositorVsyncObserver)
+  friend class CompositorParent;
+
+public:
+  CompositorVsyncObserver(CompositorParent* aCompositorParent);
+  virtual bool NotifyVsync(TimeStamp aVsyncTimestamp) MOZ_OVERRIDE;
+  void SetNeedsComposite(bool aSchedule);
+  bool NeedsComposite();
+  void CancelCurrentCompositeTask();
+ 
+private:
+  virtual ~CompositorVsyncObserver();
+
+  void Composite(TimeStamp aVsyncTimestamp);
+  void NotifyCompositeTaskExecuted();
+  void ObserveVsync();
+  void UnobserveVsync();
+
+  bool mNeedsComposite;
+  bool mIsObservingVsync;
+  nsRefPtr<CompositorParent> mCompositorParent;
+
+  mozilla::Monitor mCurrentCompositeTaskMonitor;
+  CancelableTask* mCurrentCompositeTask;
+};
+
 class CompositorParent MOZ_FINAL : public PCompositorParent,
                                    public ShadowLayersManager
 {
   NS_INLINE_DECL_THREADSAFE_REFCOUNTING_WITH_MAIN_THREAD_DESTRUCTION(CompositorParent)
+  friend class CompositorVsyncObserver;
 
 public:
   explicit CompositorParent(nsIWidget* aWidget,
                             bool aUseExternalSurfaceSize = false,
                             int aSurfaceWidth = -1, int aSurfaceHeight = -1);
 
   // IToplevelProtocol::CloneToplevel()
   virtual IToplevelProtocol*
@@ -282,28 +319,29 @@ protected:
 
   virtual PLayerTransactionParent*
     AllocPLayerTransactionParent(const nsTArray<LayersBackend>& aBackendHints,
                                  const uint64_t& aId,
                                  TextureFactoryIdentifier* aTextureFactoryIdentifier,
                                  bool* aSuccess) MOZ_OVERRIDE;
   virtual bool DeallocPLayerTransactionParent(PLayerTransactionParent* aLayers) MOZ_OVERRIDE;
   virtual void ScheduleTask(CancelableTask*, int);
-  void CompositeCallback();
+  void CompositeCallback(TimeStamp aScheduleTime);
   void CompositeToTarget(gfx::DrawTarget* aTarget, const nsIntRect* aRect = nullptr);
   void ForceComposeToTarget(gfx::DrawTarget* aTarget, const nsIntRect* aRect = nullptr);
 
   void SetEGLSurfaceSize(int width, int height);
 
   void InitializeLayerManager(const nsTArray<LayersBackend>& aBackendHints);
   void PauseComposition();
   void ResumeComposition();
   void ResumeCompositionAndResize(int width, int height);
   void ForceComposition();
   void CancelCurrentCompositeTask();
+  void ScheduleSoftwareTimerComposition();
 
   /**
    * Add a compositor to the global compositor map.
    */
   static void AddCompositor(CompositorParent* compositor, uint64_t* id);
   /**
    * Remove a compositor from the global compositor map.
    */
@@ -343,16 +381,17 @@ protected:
   uint64_t mRootLayerTreeID;
 
   bool mOverrideComposeReadiness;
   CancelableTask* mForceCompositionTask;
 
   nsRefPtr<APZCTreeManager> mApzcTreeManager;
 
   nsRefPtr<CompositorThreadHolder> mCompositorThreadHolder;
+  nsRefPtr<CompositorVsyncObserver> mCompositorVsyncObserver;
 
   DISALLOW_EVIL_CONSTRUCTORS(CompositorParent);
 };
 
 } // layers
 } // mozilla
 
 #endif // mozilla_layers_CompositorParent_h
--- a/gfx/thebes/gfxPrefs.h
+++ b/gfx/thebes/gfxPrefs.h
@@ -198,17 +198,18 @@ private:
   DECL_GFX_PREF(Live, "gfx.layerscope.enabled",                LayerScopeEnabled, bool, false);
   DECL_GFX_PREF(Live, "gfx.layerscope.port",                   LayerScopePort, int32_t, 23456);
   DECL_GFX_PREF(Live, "gfx.perf-warnings.enabled",             PerfWarnings, bool, false);
   DECL_GFX_PREF(Once, "gfx.work-around-driver-bugs",           WorkAroundDriverBugs, bool, true);
 
   DECL_GFX_PREF(Live, "gfx.draw-color-bars",                   CompositorDrawColorBars, bool, false);
 
   // Use vsync events generated by hardware
-  DECL_GFX_PREF(Once, "gfx.frameuniformity.hw-vsync",          FrameUniformityHWVsyncEnabled, bool, false);
+  DECL_GFX_PREF(Once, "gfx.vsync.hw-vsync.enabled",            HardwareVsyncEnabled, bool, false);
+  DECL_GFX_PREF(Once, "gfx.vsync.compositor",                  VsyncAlignedCompositor, bool, false);
   DECL_GFX_PREF(Once, "gfx.touch.resample",                    TouchResampling, bool, false);
   // These times should be in nanoseconds
   DECL_GFX_PREF(Once, "gfx.touch.resample.max-predict",        TouchResampleMaxPredict, int32_t, 8000000);
   DECL_GFX_PREF(Once, "gfx.touch.resample.vsync-adjust",       TouchVsyncSampleAdjust, int32_t, 5000000);
   DECL_GFX_PREF(Once, "gfx.touch.resample.min-resample",       TouchResampleMinTime, int32_t, 2000000);
   DECL_GFX_PREF(Once, "gfx.touch.resample.delay-threshold",    TouchResampleVsyncDelayThreshold, int32_t, 20000000);
 
   DECL_GFX_PREF(Live, "gl.msaa-level",                         MSAALevel, uint32_t, 2);
--- a/layout/base/nsDisplayList.cpp
+++ b/layout/base/nsDisplayList.cpp
@@ -756,17 +756,17 @@ nsDisplayScrollLayer::ComputeFrameMetric
     nsIDocument* document = nullptr;
     document = presShell->GetDocument();
     if (document) {
       nsCOMPtr<nsPIDOMWindow> innerWin(document->GetInnerWindow());
       if (innerWin) {
         metrics.mMayHaveTouchListeners = innerWin->HasTouchEventListeners();
       }
     }
-    metrics.mMayHaveTouchCaret = presShell->MayHaveTouchCaret();
+    metrics.SetMayHaveTouchCaret(presShell->MayHaveTouchCaret());
   }
 
   LayoutDeviceToParentLayerScale layoutToParentLayerScale =
     // The ScreenToParentLayerScale should be mTransformScale which is not calculated yet,
     // but we don't yet handle CSS transforms, so we assume it's 1 here.
     metrics.mCumulativeResolution * LayerToScreenScale(1.0) * ScreenToParentLayerScale(1.0);
 
   // Calculate the composition bounds as the size of the scroll frame and
--- a/widget/gonk/GeckoTouchDispatcher.cpp
+++ b/widget/gonk/GeckoTouchDispatcher.cpp
@@ -62,17 +62,17 @@ GeckoTouchDispatcher::GeckoTouchDispatch
   // The first thing to touch gfxPrefs MUST occur on the main thread and init
   // the singleton
   MOZ_ASSERT(sTouchDispatcher == nullptr);
   MOZ_ASSERT(NS_IsMainThread());
   gfxPrefs::GetSingleton();
 
   mEnabledUniformityInfo = gfxPrefs::UniformityInfo();
   mResamplingEnabled = gfxPrefs::TouchResampling() &&
-                       gfxPrefs::FrameUniformityHWVsyncEnabled();
+                       gfxPrefs::HardwareVsyncEnabled();
   mVsyncAdjust = gfxPrefs::TouchVsyncSampleAdjust();
   mMaxPredict = gfxPrefs::TouchResampleMaxPredict();
   mMinResampleTime = gfxPrefs::TouchResampleMinTime();
   mDelayedVsyncThreshold = gfxPrefs::TouchResampleVsyncDelayThreshold();
   sTouchDispatcher = this;
   ClearOnShutdown(&sTouchDispatcher);
 }
 
--- a/widget/gonk/HwcComposer2D.cpp
+++ b/widget/gonk/HwcComposer2D.cpp
@@ -213,17 +213,17 @@ HwcComposer2D::RegisterHwcEventCallback(
         return false;
     }
 
     // Disable Vsync first, and then register callback functions.
     device->eventControl(device, HWC_DISPLAY_PRIMARY, HWC_EVENT_VSYNC, false);
     device->registerProcs(device, &sHWCProcs);
     mHasHWVsync = true;
 
-    if (!gfxPrefs::FrameUniformityHWVsyncEnabled()) {
+    if (!gfxPrefs::HardwareVsyncEnabled()) {
         device->eventControl(device, HWC_DISPLAY_PRIMARY, HWC_EVENT_VSYNC, false);
         mHasHWVsync = false;
     }
 
     return mHasHWVsync;
 }
 
 void
new file mode 100644
--- /dev/null
+++ b/widget/shared/VsyncDispatcher.cpp
@@ -0,0 +1,48 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "VsyncDispatcher.h"
+#include "mozilla/ClearOnShutdown.h"
+#include "CompositorParent.h"
+
+using namespace mozilla::layers;
+
+namespace mozilla {
+
+StaticRefPtr<VsyncDispatcher> sVsyncDispatcher;
+
+/*static*/ VsyncDispatcher*
+VsyncDispatcher::GetInstance()
+{
+  if (!sVsyncDispatcher) {
+    sVsyncDispatcher = new VsyncDispatcher();
+    ClearOnShutdown(&sVsyncDispatcher);
+  }
+
+  return sVsyncDispatcher;
+}
+
+VsyncDispatcher::VsyncDispatcher()
+{
+
+}
+
+VsyncDispatcher::~VsyncDispatcher()
+{
+}
+
+void
+VsyncDispatcher::AddCompositorVsyncObserver(VsyncObserver* aVsyncObserver)
+{
+  MOZ_ASSERT(CompositorParent::IsInCompositorThread());
+}
+
+void
+VsyncDispatcher::RemoveCompositorVsyncObserver(VsyncObserver* aVsyncObserver)
+{
+  MOZ_ASSERT(CompositorParent::IsInCompositorThread());
+}
+
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/widget/shared/VsyncDispatcher.h
@@ -0,0 +1,44 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_widget_VsyncDispatcher_h
+#define mozilla_widget_VsyncDispatcher_h
+
+#include "nsISupportsImpl.h"
+
+namespace mozilla {
+class TimeStamp;
+
+class VsyncObserver
+{
+public:
+  // The method called when a vsync occurs. Return true if some work was done.
+  // Vsync notifications will occur on the hardware vsync thread
+  virtual bool NotifyVsync(TimeStamp aVsyncTimestamp) = 0;
+
+protected:
+  virtual ~VsyncObserver() { }
+};
+
+// VsyncDispatcher is used to dispatch vsync events to the registered observers.
+class VsyncDispatcher
+{
+  NS_INLINE_DECL_THREADSAFE_REFCOUNTING(VsyncDispatcher)
+
+public:
+  static VsyncDispatcher* GetInstance();
+
+  // Compositor vsync observers must be added/removed on the compositor thread
+  void AddCompositorVsyncObserver(VsyncObserver* aVsyncObserver);
+  void RemoveCompositorVsyncObserver(VsyncObserver* aVsyncObserver);
+
+private:
+  VsyncDispatcher();
+  virtual ~VsyncDispatcher();
+};
+
+} // namespace mozilla
+
+#endif // __mozilla_widget_VsyncDispatcher_h
--- a/widget/shared/moz.build
+++ b/widget/shared/moz.build
@@ -2,19 +2,24 @@
 # vim: set filetype=python:
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 if CONFIG['MOZ_X11']:
     DIRS += ['x11']
 
+EXPORTS.mozilla += [
+    'VsyncDispatcher.h',
+]
+
 UNIFIED_SOURCES += [
     'nsShmImage.cpp',
     'SharedWidgetUtils.cpp',
+    'VsyncDispatcher.cpp',
     'WidgetEventImpl.cpp',
 ]
 
 include('/ipc/chromium/chromium-config.mozbuild')
 
 FAIL_ON_WARNINGS = True
 
 FINAL_LIBRARY = 'xul'