Merge m-c to fx-team.
authorRyan VanderMeulen <ryanvm@gmail.com>
Wed, 26 Feb 2014 16:44:04 -0500
changeset 171294 551e6c666d5256b799605461ba74168438487c14
parent 171293 e82cb49c7a8d396d7e4a1ba74c3e970492ce3041 (current diff)
parent 171161 bb9edb4d5144d414e355b8d09a74c94ba57096bf (diff)
child 171295 588d1ff56939e47de4a73dbcf42b332e4e9b0097
push id270
push userpvanderbeken@mozilla.com
push dateThu, 06 Mar 2014 09:24:21 +0000
milestone30.0a1
Merge m-c to fx-team.
testing/marionette/client/marionette/tests/unit/test_getstatus.py
widget/gonk/nativewindow/GonkBufferQueue.cpp
widget/gonk/nativewindow/GonkConsumerBase.cpp
widget/gonk/nativewindow/GonkConsumerBase.h
--- a/b2g/config/emulator-ics/config.json
+++ b/b2g/config/emulator-ics/config.json
@@ -1,13 +1,13 @@
 {
     "config_version": 2,
     "tooltool_manifest": "releng-emulator-ics.tt",
     "mock_target": "mozilla-centos6-x86_64",
-    "mock_packages": ["ccache", "make", "bison", "flex", "gcc", "g++", "mpfr", "zlib-devel", "ncurses-devel", "zip", "autoconf213", "glibc-static", "perl-Digest-SHA", "wget", "alsa-lib", "atk", "cairo", "dbus-glib", "fontconfig", "freetype", "glib2", "gtk2", "libXRender", "libXt", "pango", "mozilla-python27-mercurial", "openssh-clients", "nss-devel", "glibc-devel.i686", "libstdc++.i686", "zlib-devel.i686", "ncurses-devel.i686", "libX11-devel.i686", "mesa-libGL-devel.i686", "mesa-libGL-devel", "libX11-devel", "git"],
+    "mock_packages": ["ccache", "make", "bison", "flex", "gcc", "g++", "mpfr", "zlib-devel", "ncurses-devel", "zip", "autoconf213", "glibc-static", "perl-Digest-SHA", "wget", "alsa-lib", "atk", "cairo", "dbus-glib", "fontconfig", "freetype", "glib2", "gtk2", "libXRender", "libXt", "pango", "mozilla-python27-mercurial", "openssh-clients", "nss-devel", "glibc-devel.i686", "libstdc++.i686", "zlib-devel.i686", "ncurses-devel.i686", "libX11-devel.i686", "mesa-libGL-devel.i686", "mesa-libGL-devel", "libX11-devel", "git", "libxml2"],
     "mock_files": [["/home/cltbld/.ssh", "/home/mock_mozilla/.ssh"]],
     "build_targets": ["droid", "package-emulator", "package-tests"],
     "upload_files": [
         "{workdir}/out/target/product/generic/*.tar.bz2",
         "{workdir}/out/target/product/generic/tests/*.zip",
         "{workdir}/out/emulator.tar.gz",
         "{objdir}/dist/b2g-*.crashreporter-symbols.zip",
         "{workdir}/sources.xml"
--- a/b2g/config/emulator-ics/sources.xml
+++ b/b2g/config/emulator-ics/sources.xml
@@ -1,29 +1,36 @@
 <?xml version="1.0" ?><manifest>
+  <!--original fetch url was https://android.googlesource.com/-->
   <remote fetch="https://git.mozilla.org/external/aosp" name="aosp"/>
+  <!--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/b2g-->
   <remote fetch="https://git.mozilla.org/b2g" name="b2gmozilla"/>
+  <!--original fetch url was git://github.com/mozilla-b2g/-->
   <remote fetch="https://git.mozilla.org/b2g" name="b2g"/>
+  <!--original fetch url was git://github.com/mozilla/-->
   <remote fetch="https://git.mozilla.org/b2g" name="mozilla"/>
+  <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
+  <!--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="59605a7c026ff06cc1613af3938579b1dddc6cfe">
     <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="ec159aac19ff25912f1d68ffb44b29f797583ef5"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="c8d34e6e98d4b99921fda59ddd89f2dcdce201fc"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="15e8982284c4560f9c74c2b9fe8bb361ebfe0cb6"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="d11f524d00cacf5ba0dfbf25e4aa2158b1c3a036"/>
   <project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="022eadd5917615ff00c47eaaafa792b45e9c8a28"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="3d5c964015967ca8c86abe6dbbebee3cb82b1609"/>
-  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="8c449b53328059e9b55bb34baec9b27a15055a7e"/>
+  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="52ca41d9fa6ef88e65d9da52e375716c68d48646"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="dd924f92906085b831bf1cbbc7484d3c043d613c"/>
   <project name="platform/bionic" path="bionic" revision="c72b8f6359de7ed17c11ddc9dfdde3f615d188a9"/>
   <project name="platform/bootable/recovery" path="bootable/recovery" revision="425f8b5fadf5889834c5acd27d23c9e0b2129c28"/>
   <project name="device/common" path="device/common" revision="42b808b7e93d0619286ae8e59110b176b7732389"/>
   <project name="device/sample" path="device/sample" revision="237bd668d0f114d801a8d6455ef5e02cc3577587"/>
   <project name="platform_external_apriori" path="external/apriori" remote="b2g" revision="11816ad0406744f963537b23d68ed9c2afb412bd"/>
   <project name="platform/external/bluetooth/bluez" path="external/bluetooth/bluez" revision="52a1a862a8bac319652b8f82d9541ba40bfa45ce"/>
--- a/b2g/config/emulator-jb/sources.xml
+++ b/b2g/config/emulator-jb/sources.xml
@@ -1,25 +1,31 @@
 <?xml version="1.0" ?><manifest>
+  <!--original fetch url was https://android.googlesource.com/-->
   <remote fetch="https://git.mozilla.org/external/aosp" name="aosp"/>
+  <!--original fetch url was git://github.com/mozilla-b2g/-->
   <remote fetch="https://git.mozilla.org/b2g" name="b2g"/>
+  <!--original fetch url was git://github.com/mozilla/-->
   <remote fetch="https://git.mozilla.org/b2g" name="mozilla"/>
+  <!--original fetch url was git://github.com/apitrace/-->
   <remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/>
+  <!--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="97a5b461686757dbb8ecab2aac5903e41d2e1afe">
     <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="ec159aac19ff25912f1d68ffb44b29f797583ef5"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="c8d34e6e98d4b99921fda59ddd89f2dcdce201fc"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="15e8982284c4560f9c74c2b9fe8bb361ebfe0cb6"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="3d5c964015967ca8c86abe6dbbebee3cb82b1609"/>
-  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="8c449b53328059e9b55bb34baec9b27a15055a7e"/>
+  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="52ca41d9fa6ef88e65d9da52e375716c68d48646"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="905bfa3548eb75cf1792d0d8412b92113bbd4318"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="c3d7efc45414f1b44cd9c479bb2758c91c4707c0"/>
   <!-- Stock Android things -->
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.1" path="prebuilts/clang/linux-x86/3.1" revision="5c45f43419d5582949284eee9cef0c43d866e03b"/>
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.2" path="prebuilts/clang/linux-x86/3.2" revision="3748b4168e7bd8d46457d4b6786003bc6a5223ce"/>
   <project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" revision="9025e50b9d29b3cabbbb21e1dd94d0d13121a17e"/>
   <project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" revision="b89fda71fcd0fa0cf969310e75be3ea33e048b44"/>
   <project groups="linux,arm" name="platform/prebuilts/gcc/linux-x86/arm/arm-eabi-4.7" path="prebuilts/gcc/linux-x86/arm/arm-eabi-4.7" revision="2e7d5348f35575870b3c7e567a9a9f6d66f8d6c5"/>
--- a/b2g/config/emulator/config.json
+++ b/b2g/config/emulator/config.json
@@ -1,13 +1,13 @@
 {
     "config_version": 2,
     "tooltool_manifest": "releng-emulator.tt",
     "mock_target": "mozilla-centos6-x86_64",
-    "mock_packages": ["ccache", "make", "bison", "flex", "gcc", "g++", "mpfr", "zlib-devel", "ncurses-devel", "zip", "autoconf213", "glibc-static", "perl-Digest-SHA", "wget", "alsa-lib", "atk", "cairo", "dbus-glib", "fontconfig", "freetype", "glib2", "gtk2", "libXRender", "libXt", "pango", "mozilla-python27-mercurial", "openssh-clients", "nss-devel", "glibc-devel.i686", "libstdc++.i686", "zlib-devel.i686", "ncurses-devel.i686", "libX11-devel.i686", "mesa-libGL-devel.i686", "mesa-libGL-devel", "libX11-devel", "git"],
+    "mock_packages": ["ccache", "make", "bison", "flex", "gcc", "g++", "mpfr", "zlib-devel", "ncurses-devel", "zip", "autoconf213", "glibc-static", "perl-Digest-SHA", "wget", "alsa-lib", "atk", "cairo", "dbus-glib", "fontconfig", "freetype", "glib2", "gtk2", "libXRender", "libXt", "pango", "mozilla-python27-mercurial", "openssh-clients", "nss-devel", "glibc-devel.i686", "libstdc++.i686", "zlib-devel.i686", "ncurses-devel.i686", "libX11-devel.i686", "mesa-libGL-devel.i686", "mesa-libGL-devel", "libX11-devel", "git", "libxml2"],
     "mock_files": [["/home/cltbld/.ssh", "/home/mock_mozilla/.ssh"]],
     "build_targets": ["droid", "package-emulator", "package-tests"],
     "upload_files": [
         "{workdir}/out/target/product/generic/*.tar.bz2",
         "{workdir}/out/target/product/generic/tests/*.zip",
         "{workdir}/out/emulator.tar.gz",
         "{objdir}/dist/b2g-*.crashreporter-symbols.zip",
         "{workdir}/sources.xml"
--- a/b2g/config/emulator/sources.xml
+++ b/b2g/config/emulator/sources.xml
@@ -1,29 +1,36 @@
 <?xml version="1.0" ?><manifest>
+  <!--original fetch url was https://android.googlesource.com/-->
   <remote fetch="https://git.mozilla.org/external/aosp" name="aosp"/>
+  <!--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/b2g-->
   <remote fetch="https://git.mozilla.org/b2g" name="b2gmozilla"/>
+  <!--original fetch url was git://github.com/mozilla-b2g/-->
   <remote fetch="https://git.mozilla.org/b2g" name="b2g"/>
+  <!--original fetch url was git://github.com/mozilla/-->
   <remote fetch="https://git.mozilla.org/b2g" name="mozilla"/>
+  <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
+  <!--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="59605a7c026ff06cc1613af3938579b1dddc6cfe">
     <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="ec159aac19ff25912f1d68ffb44b29f797583ef5"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="c8d34e6e98d4b99921fda59ddd89f2dcdce201fc"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="15e8982284c4560f9c74c2b9fe8bb361ebfe0cb6"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="d11f524d00cacf5ba0dfbf25e4aa2158b1c3a036"/>
   <project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="022eadd5917615ff00c47eaaafa792b45e9c8a28"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="3d5c964015967ca8c86abe6dbbebee3cb82b1609"/>
-  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="8c449b53328059e9b55bb34baec9b27a15055a7e"/>
+  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="52ca41d9fa6ef88e65d9da52e375716c68d48646"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="dd924f92906085b831bf1cbbc7484d3c043d613c"/>
   <project name="platform/bionic" path="bionic" revision="c72b8f6359de7ed17c11ddc9dfdde3f615d188a9"/>
   <project name="platform/bootable/recovery" path="bootable/recovery" revision="425f8b5fadf5889834c5acd27d23c9e0b2129c28"/>
   <project name="device/common" path="device/common" revision="42b808b7e93d0619286ae8e59110b176b7732389"/>
   <project name="device/sample" path="device/sample" revision="237bd668d0f114d801a8d6455ef5e02cc3577587"/>
   <project name="platform_external_apriori" path="external/apriori" remote="b2g" revision="11816ad0406744f963537b23d68ed9c2afb412bd"/>
   <project name="platform/external/bluetooth/bluez" path="external/bluetooth/bluez" revision="52a1a862a8bac319652b8f82d9541ba40bfa45ce"/>
--- a/b2g/config/gaia.json
+++ b/b2g/config/gaia.json
@@ -1,4 +1,9 @@
 {
-    "revision": "d1729e9d8fcc010e42ef73befa93d3c07a4304c6", 
+    "git": {
+        "remote": "", 
+        "branch": "", 
+        "revision": ""
+    }, 
+    "revision": "8bb0cf53956e54999a5f876434207216d9d8982a", 
     "repo_path": "/integration/gaia-central"
 }
--- a/b2g/config/hamachi/sources.xml
+++ b/b2g/config/hamachi/sources.xml
@@ -1,27 +1,33 @@
 <?xml version="1.0" ?><manifest>
+  <!--original fetch url was https://android.googlesource.com/-->
   <remote fetch="https://git.mozilla.org/external/aosp" name="aosp"/>
+  <!--original fetch url was git://github.com/mozilla-b2g/-->
   <remote fetch="https://git.mozilla.org/b2g" name="b2g"/>
+  <!--original fetch url was git://github.com/mozilla/-->
   <remote fetch="https://git.mozilla.org/b2g" name="mozilla"/>
+  <!--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"/>
+  <!--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="59605a7c026ff06cc1613af3938579b1dddc6cfe">
     <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="ec159aac19ff25912f1d68ffb44b29f797583ef5"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="c8d34e6e98d4b99921fda59ddd89f2dcdce201fc"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="15e8982284c4560f9c74c2b9fe8bb361ebfe0cb6"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="84f2f2fce22605e17d511ff1767e54770067b5b5"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="3d5c964015967ca8c86abe6dbbebee3cb82b1609"/>
-  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="8c449b53328059e9b55bb34baec9b27a15055a7e"/>
+  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="52ca41d9fa6ef88e65d9da52e375716c68d48646"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="6426040f1be4a844082c9769171ce7f5341a5528"/>
   <project name="platform/bionic" path="bionic" revision="d2eb6c7b6e1bc7643c17df2d9d9bcb1704d0b9ab"/>
   <project name="platform/bootable/recovery" path="bootable/recovery" revision="746bc48f34f5060f90801925dcdd964030c1ab6d"/>
   <project name="platform/development" path="development" revision="2460485184bc8535440bb63876d4e63ec1b4770c"/>
   <project name="device/common" path="device/common" revision="0dcc1e03659db33b77392529466f9eb685cdd3c7"/>
   <project name="device/sample" path="device/sample" revision="68b1cb978a20806176123b959cb05d4fa8adaea4"/>
   <project name="platform_external_apriori" path="external/apriori" remote="b2g" revision="11816ad0406744f963537b23d68ed9c2afb412bd"/>
--- a/b2g/config/helix/sources.xml
+++ b/b2g/config/helix/sources.xml
@@ -1,21 +1,26 @@
 <?xml version="1.0" ?><manifest>
+  <!--original fetch url was https://android.googlesource.com/-->
   <remote fetch="https://git.mozilla.org/external/aosp" name="aosp"/>
+  <!--original fetch url was git://github.com/mozilla-b2g/-->
   <remote fetch="https://git.mozilla.org/b2g" name="b2g"/>
+  <!--original fetch url was git://github.com/mozilla/-->
   <remote fetch="https://git.mozilla.org/b2g" name="mozilla"/>
+  <!--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"/>
   <default remote="caf" revision="b2g/ics_strawberry" sync-j="4"/>
   <!-- Gonk specific things and forks -->
   <project name="platform_build" path="build" remote="b2g" revision="59605a7c026ff06cc1613af3938579b1dddc6cfe">
     <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="ec159aac19ff25912f1d68ffb44b29f797583ef5"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="c8d34e6e98d4b99921fda59ddd89f2dcdce201fc"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="15e8982284c4560f9c74c2b9fe8bb361ebfe0cb6"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="84f2f2fce22605e17d511ff1767e54770067b5b5"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="3d5c964015967ca8c86abe6dbbebee3cb82b1609"/>
   <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/inari/sources.xml
+++ b/b2g/config/inari/sources.xml
@@ -1,28 +1,35 @@
 <?xml version="1.0" ?><manifest>
+  <!--original fetch url was https://android.googlesource.com/-->
   <remote fetch="https://git.mozilla.org/external/aosp" name="aosp"/>
+  <!--original fetch url was https://git.mozilla.org/b2g-->
   <remote fetch="https://git.mozilla.org/b2g" name="b2gmozilla"/>
+  <!--original fetch url was git://github.com/mozilla-b2g/-->
   <remote fetch="https://git.mozilla.org/b2g" name="b2g"/>
+  <!--original fetch url was git://github.com/mozilla/-->
   <remote fetch="https://git.mozilla.org/b2g" name="mozilla"/>
+  <!--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"/>
+  <!--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="59605a7c026ff06cc1613af3938579b1dddc6cfe">
     <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="ec159aac19ff25912f1d68ffb44b29f797583ef5"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="c8d34e6e98d4b99921fda59ddd89f2dcdce201fc"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="15e8982284c4560f9c74c2b9fe8bb361ebfe0cb6"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="84f2f2fce22605e17d511ff1767e54770067b5b5"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="3d5c964015967ca8c86abe6dbbebee3cb82b1609"/>
-  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="8c449b53328059e9b55bb34baec9b27a15055a7e"/>
+  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="52ca41d9fa6ef88e65d9da52e375716c68d48646"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="6426040f1be4a844082c9769171ce7f5341a5528"/>
   <project name="platform/bionic" path="bionic" revision="cd5dfce80bc3f0139a56b58aca633202ccaee7f8"/>
   <project name="platform/bootable/recovery" path="bootable/recovery" revision="e0a9ac010df3afaa47ba107192c05ac8b5516435"/>
   <project name="platform/development" path="development" revision="a384622f5fcb1d2bebb9102591ff7ae91fe8ed2d"/>
   <project name="device/common" path="device/common" revision="7c65ea240157763b8ded6154a17d3c033167afb7"/>
   <project name="device/sample" path="device/sample" revision="c328f3d4409db801628861baa8d279fb8855892f"/>
   <project name="platform_external_apriori" path="external/apriori" remote="b2g" revision="11816ad0406744f963537b23d68ed9c2afb412bd"/>
--- a/b2g/config/leo/sources.xml
+++ b/b2g/config/leo/sources.xml
@@ -1,27 +1,33 @@
 <?xml version="1.0" ?><manifest>
+  <!--original fetch url was https://android.googlesource.com/-->
   <remote fetch="https://git.mozilla.org/external/aosp" name="aosp"/>
+  <!--original fetch url was git://github.com/mozilla-b2g/-->
   <remote fetch="https://git.mozilla.org/b2g" name="b2g"/>
+  <!--original fetch url was git://github.com/mozilla/-->
   <remote fetch="https://git.mozilla.org/b2g" name="mozilla"/>
+  <!--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"/>
+  <!--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="59605a7c026ff06cc1613af3938579b1dddc6cfe">
     <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="ec159aac19ff25912f1d68ffb44b29f797583ef5"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="c8d34e6e98d4b99921fda59ddd89f2dcdce201fc"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="15e8982284c4560f9c74c2b9fe8bb361ebfe0cb6"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="84f2f2fce22605e17d511ff1767e54770067b5b5"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="3d5c964015967ca8c86abe6dbbebee3cb82b1609"/>
-  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="8c449b53328059e9b55bb34baec9b27a15055a7e"/>
+  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="52ca41d9fa6ef88e65d9da52e375716c68d48646"/>
   <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"/>
   <project name="platform/bootable/recovery" path="bootable/recovery" revision="575fdbf046e966a5915b1f1e800e5d6ad0ea14c0"/>
   <project name="platform/development" path="development" revision="b1025ec93beeb480caaf3049d171283c3846461d"/>
   <project name="device/common" path="device/common" revision="0dcc1e03659db33b77392529466f9eb685cdd3c7"/>
   <project name="device/sample" path="device/sample" revision="68b1cb978a20806176123b959cb05d4fa8adaea4"/>
--- a/b2g/config/mako/sources.xml
+++ b/b2g/config/mako/sources.xml
@@ -1,25 +1,31 @@
 <?xml version="1.0" ?><manifest>
+  <!--original fetch url was https://android.googlesource.com/-->
   <remote fetch="https://git.mozilla.org/external/aosp" name="aosp"/>
+  <!--original fetch url was git://github.com/mozilla-b2g/-->
   <remote fetch="https://git.mozilla.org/b2g" name="b2g"/>
+  <!--original fetch url was git://github.com/mozilla/-->
   <remote fetch="https://git.mozilla.org/b2g" name="mozilla"/>
+  <!--original fetch url was git://github.com/apitrace/-->
   <remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/>
+  <!--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="97a5b461686757dbb8ecab2aac5903e41d2e1afe">
     <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="ec159aac19ff25912f1d68ffb44b29f797583ef5"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="c8d34e6e98d4b99921fda59ddd89f2dcdce201fc"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="15e8982284c4560f9c74c2b9fe8bb361ebfe0cb6"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="3d5c964015967ca8c86abe6dbbebee3cb82b1609"/>
-  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="8c449b53328059e9b55bb34baec9b27a15055a7e"/>
+  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="52ca41d9fa6ef88e65d9da52e375716c68d48646"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="905bfa3548eb75cf1792d0d8412b92113bbd4318"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="c3d7efc45414f1b44cd9c479bb2758c91c4707c0"/>
   <!-- Stock Android things -->
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.1" path="prebuilts/clang/linux-x86/3.1" revision="5c45f43419d5582949284eee9cef0c43d866e03b"/>
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.2" path="prebuilts/clang/linux-x86/3.2" revision="3748b4168e7bd8d46457d4b6786003bc6a5223ce"/>
   <project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" revision="9025e50b9d29b3cabbbb21e1dd94d0d13121a17e"/>
   <project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" revision="b89fda71fcd0fa0cf969310e75be3ea33e048b44"/>
   <project groups="linux,arm" name="platform/prebuilts/gcc/linux-x86/arm/arm-eabi-4.7" path="prebuilts/gcc/linux-x86/arm/arm-eabi-4.7" revision="2e7d5348f35575870b3c7e567a9a9f6d66f8d6c5"/>
--- a/b2g/config/wasabi/sources.xml
+++ b/b2g/config/wasabi/sources.xml
@@ -1,27 +1,33 @@
 <?xml version="1.0" ?><manifest>
+  <!--original fetch url was https://android.googlesource.com/-->
   <remote fetch="https://git.mozilla.org/external/aosp" name="aosp"/>
+  <!--original fetch url was git://github.com/mozilla-b2g/-->
   <remote fetch="https://git.mozilla.org/b2g" name="b2g"/>
+  <!--original fetch url was git://github.com/mozilla/-->
   <remote fetch="https://git.mozilla.org/b2g" name="mozilla"/>
+  <!--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"/>
+  <!--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="59605a7c026ff06cc1613af3938579b1dddc6cfe">
     <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="ec159aac19ff25912f1d68ffb44b29f797583ef5"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="c8d34e6e98d4b99921fda59ddd89f2dcdce201fc"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="15e8982284c4560f9c74c2b9fe8bb361ebfe0cb6"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="84f2f2fce22605e17d511ff1767e54770067b5b5"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="3d5c964015967ca8c86abe6dbbebee3cb82b1609"/>
-  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="8c449b53328059e9b55bb34baec9b27a15055a7e"/>
+  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="52ca41d9fa6ef88e65d9da52e375716c68d48646"/>
   <project name="gonk-patches" path="patches" remote="b2g" revision="223a2421006e8f5da33f516f6891c87cae86b0f6"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="6426040f1be4a844082c9769171ce7f5341a5528"/>
   <project name="platform/bionic" path="bionic" revision="cd5dfce80bc3f0139a56b58aca633202ccaee7f8"/>
   <project name="platform/bootable/recovery" path="bootable/recovery" revision="e0a9ac010df3afaa47ba107192c05ac8b5516435"/>
   <project name="platform/development" path="development" revision="a384622f5fcb1d2bebb9102591ff7ae91fe8ed2d"/>
   <project name="device/common" path="device/common" revision="7c65ea240157763b8ded6154a17d3c033167afb7"/>
   <project name="device/sample" path="device/sample" revision="c328f3d4409db801628861baa8d279fb8855892f"/>
--- a/browser/app/Makefile.in
+++ b/browser/app/Makefile.in
@@ -56,21 +56,16 @@ include $(topsrcdir)/config/config.mk
 
 ifeq ($(OS_ARCH),WINNT)
 RCINCLUDE = splash.rc
 # Rebuild firefox.exe if the manifest changes - it's included by splash.rc.
 # (this dependency should really be just for firefox.exe, not other targets)
 # Note the manifest file exists in the tree, so we use the explicit filename
 # here.
 EXTRA_DEPS += firefox.exe.manifest
-ifndef GNU_CC
-RCFLAGS += -DMOZ_PHOENIX -I$(srcdir)
-else
-RCFLAGS += -DMOZ_PHOENIX --include-dir $(srcdir)
-endif
 endif
 
 PROGRAMS_DEST = $(DIST)/bin
 
 include $(topsrcdir)/config/rules.mk
 
 ifeq ($(OS_ARCH),WINNT) #{
 #
--- a/browser/app/moz.build
+++ b/browser/app/moz.build
@@ -32,8 +32,11 @@ LOCAL_INCLUDES += [
     '/xpcom/base',
     '/xpcom/build',
 ]
 
 if CONFIG['_MSC_VER']:
     # Always enter a Windows program through wmain, whether or not we're
     # a console application.
     WIN32_EXE_LDFLAGS += ['-ENTRY:wmainCRTStartup']
+
+if CONFIG['OS_ARCH'] == 'WINNT':
+    DEFINES['MOZ_PHOENIX'] = True
--- a/config/expandlibs_exec.py
+++ b/config/expandlibs_exec.py
@@ -343,17 +343,18 @@ def main():
         sys.stderr.write(stdout)
         sys.stderr.flush()
         if proc.returncode:
             exit(proc.returncode)
     if not options.depend:
         return
     ensureParentDir(options.depend)
     mk = Makefile()
-    deps = [dep for dep in deps if os.path.isfile(dep) and dep != options.target]
+    deps = [dep for dep in deps if os.path.isfile(dep) and dep != options.target
+            and os.path.abspath(dep) != os.path.abspath(options.depend)]
     no_dynamic_lib = [dep for dep in deps if not isDynamicLib(dep)]
     mk.create_rule([options.target]).add_dependencies(no_dynamic_lib)
     if len(deps) != len(no_dynamic_lib):
         mk.create_rule(['%s_order_only' % options.target]).add_dependencies(dep for dep in deps if isDynamicLib(dep))
 
     with open(options.depend, 'w') as depfile:
         mk.dump(depfile, removal_guard=True)
 
--- a/configure.in
+++ b/configure.in
@@ -244,17 +244,19 @@ if test -n "$gonkdir" ; then
         MOZ_B2G_CAMERA=1
         MOZ_OMX_DECODER=1
         AC_SUBST(MOZ_OMX_DECODER)
         MOZ_OMX_ENCODER=1
         AC_SUBST(MOZ_OMX_ENCODER)
         AC_DEFINE(MOZ_OMX_ENCODER)
         ;;
     19)
-        GONK_INCLUDES="-I$gonkdir/frameworks/native/include"
+        GONK_INCLUDES="-I$gonkdir/frameworks/native/include -I$gonkdir/frameworks/av/include -I$gonkdir/frameworks/av/include/media -I$gonkdir/frameworks/av/include/camera -I$gonkdir/frameworks/native/include/media/openmax -I$gonkdir/frameworks/av/media/libstagefright/include"
+        MOZ_B2G_CAMERA=1
+        MOZ_OMX_DECODER=1
         MOZ_B2G_BT=1
         MOZ_B2G_BT_BLUEDROID=1
         MOZ_NFC=1
 
         ;;
     *)
         AC_MSG_ERROR([Unsupported platform version: $ANDROID_VERSION])
         ;;
--- a/content/media/encoder/OmxTrackEncoder.cpp
+++ b/content/media/encoder/OmxTrackEncoder.cpp
@@ -21,21 +21,24 @@
 using namespace android;
 
 namespace mozilla {
 
 #define ENCODER_CONFIG_FRAME_RATE 30 // fps
 #define GET_ENCODED_VIDEO_FRAME_TIMEOUT 100000 // microseconds
 
 nsresult
-OmxVideoTrackEncoder::Init(int aWidth, int aHeight, TrackRate aTrackRate)
+OmxVideoTrackEncoder::Init(int aWidth, int aHeight, int aDisplayWidth,
+                           int aDisplayHeight, TrackRate aTrackRate)
 {
   mFrameWidth = aWidth;
   mFrameHeight = aHeight;
   mTrackRate = aTrackRate;
+  mDisplayWidth = aDisplayWidth;
+  mDisplayHeight = aDisplayHeight;
 
   mEncoder = OMXCodecWrapper::CreateAVCEncoder();
   NS_ENSURE_TRUE(mEncoder, NS_ERROR_FAILURE);
 
   nsresult rv = mEncoder->Configure(mFrameWidth, mFrameHeight,
                                     ENCODER_CONFIG_FRAME_RATE);
 
   ReentrantMonitorAutoEnter mon(mReentrantMonitor);
--- a/content/media/encoder/OmxTrackEncoder.h
+++ b/content/media/encoder/OmxTrackEncoder.h
@@ -30,17 +30,19 @@ public:
     : VideoTrackEncoder()
   {}
 
   already_AddRefed<TrackMetadataBase> GetMetadata() MOZ_OVERRIDE;
 
   nsresult GetEncodedTrack(EncodedFrameContainer& aData) MOZ_OVERRIDE;
 
 protected:
-  nsresult Init(int aWidth, int aHeight, TrackRate aTrackRate) MOZ_OVERRIDE;
+  nsresult Init(int aWidth, int aHeight,
+                int aDisplayWidth, int aDisplayHeight,
+                TrackRate aTrackRate) MOZ_OVERRIDE;
 
 private:
   nsAutoPtr<android::OMXVideoEncoder> mEncoder;
 };
 
 class OmxAudioTrackEncoder MOZ_FINAL : public AudioTrackEncoder
 {
 public:
--- a/content/media/encoder/TrackEncoder.cpp
+++ b/content/media/encoder/TrackEncoder.cpp
@@ -158,17 +158,20 @@ VideoTrackEncoder::NotifyQueuedTrackChan
 
    // Check and initialize parameters for codec encoder.
   if (!mInitialized) {
     VideoSegment::ChunkIterator iter(const_cast<VideoSegment&>(video));
     while (!iter.IsEnded()) {
       VideoChunk chunk = *iter;
       if (!chunk.IsNull()) {
         gfx::IntSize imgsize = chunk.mFrame.GetImage()->GetSize();
-        nsresult rv = Init(imgsize.width, imgsize.height, aTrackRate);
+        gfxIntSize intrinsicSize = chunk.mFrame.GetIntrinsicSize();
+        nsresult rv = Init(imgsize.width, imgsize.height,
+                           intrinsicSize.width, intrinsicSize.height,
+                           aTrackRate);
         if (NS_FAILED(rv)) {
           LOG("[VideoTrackEncoder]: Fail to initialize the encoder!");
           NotifyCancel();
         }
         break;
       }
 
       iter.Next();
@@ -209,17 +212,18 @@ VideoTrackEncoder::AppendVideoSegment(co
 }
 
 void
 VideoTrackEncoder::NotifyEndOfStream()
 {
   // If source video track is muted till the end of encoding, initialize the
   // encoder with default frame width, frame height, and track rate.
   if (!mCanceled && !mInitialized) {
-    Init(DEFAULT_FRAME_WIDTH, DEFAULT_FRAME_HEIGHT, DEFAULT_TRACK_RATE);
+    Init(DEFAULT_FRAME_WIDTH, DEFAULT_FRAME_HEIGHT,
+         DEFAULT_FRAME_WIDTH, DEFAULT_FRAME_HEIGHT, DEFAULT_TRACK_RATE);
   }
 
   ReentrantMonitorAutoEnter mon(mReentrantMonitor);
   mEndOfStream = true;
   mReentrantMonitor.NotifyAll();
 }
 
 void
--- a/content/media/encoder/TrackEncoder.h
+++ b/content/media/encoder/TrackEncoder.h
@@ -217,16 +217,18 @@ protected:
 
 class VideoTrackEncoder : public TrackEncoder
 {
 public:
   VideoTrackEncoder()
     : TrackEncoder()
     , mFrameWidth(0)
     , mFrameHeight(0)
+    , mDisplayWidth(0)
+    , mDisplayHeight(0)
     , mTrackRate(0)
     , mTotalFrameDuration(0)
   {}
 
   /**
    * Notified by the same callbcak of MediaEncoder when it has received a track
    * change from MediaStreamGraph. Called on the MediaStreamGraph thread.
    */
@@ -239,17 +241,18 @@ public:
 protected:
   /**
    * Initialized the video encoder. In order to collect the value of width and
    * height of source frames, this initialization is delayed until we have
    * received the first valid video frame from MediaStreamGraph;
    * mReentrantMonitor will be notified after it has successfully initialized,
    * and this method is called on the MediaStramGraph thread.
    */
-  virtual nsresult Init(int aWidth, int aHeight, TrackRate aTrackRate) = 0;
+  virtual nsresult Init(int aWidth, int aHeight, int aDisplayWidth,
+                        int aDisplayHeight, TrackRate aTrackRate) = 0;
 
   /**
    * Appends source video frames to mRawSegment. We only append the source chunk
    * if it is unique to mLastChunk. Called on the MediaStreamGraph thread.
    */
   nsresult AppendVideoSegment(const VideoSegment& aSegment);
 
   /**
@@ -271,16 +274,26 @@ protected:
   int mFrameWidth;
 
   /**
    * The height of source video frame, ceiled if the source height is odd.
    */
   int mFrameHeight;
 
   /**
+   * The display width of source video frame.
+   */
+  int mDisplayWidth;
+
+  /**
+   * The display height of source video frame.
+   */
+  int mDisplayHeight;
+
+  /**
    * The track rate of source video.
    */
   TrackRate mTrackRate;
 
   /**
    * The total duration of frames in encoded video in TrackTicks, kept track of
    * in subclasses.
    */
--- a/content/media/encoder/VP8TrackEncoder.cpp
+++ b/content/media/encoder/VP8TrackEncoder.cpp
@@ -48,29 +48,33 @@ VP8TrackEncoder::~VP8TrackEncoder()
 
   if (mVPXImageWrapper) {
     vpx_img_free(mVPXImageWrapper);
   }
   MOZ_COUNT_DTOR(VP8TrackEncoder);
 }
 
 nsresult
-VP8TrackEncoder::Init(int32_t aWidth, int32_t aHeight, TrackRate aTrackRate)
+VP8TrackEncoder::Init(int32_t aWidth, int32_t aHeight, int32_t aDisplayWidth,
+                      int32_t aDisplayHeight,TrackRate aTrackRate)
 {
-  if (aWidth < 1 || aHeight < 1 || aTrackRate <= 0) {
+  if (aWidth < 1 || aHeight < 1 || aDisplayWidth < 1 || aDisplayHeight < 1
+      || aTrackRate <= 0) {
     return NS_ERROR_FAILURE;
   }
 
   ReentrantMonitorAutoEnter mon(mReentrantMonitor);
 
   mTrackRate = aTrackRate;
   mEncodedFrameRate = DEFAULT_ENCODE_FRAMERATE;
   mEncodedFrameDuration = mTrackRate / mEncodedFrameRate;
   mFrameWidth = aWidth;
   mFrameHeight = aHeight;
+  mDisplayWidth = aDisplayWidth;
+  mDisplayHeight = aDisplayHeight;
 
   // Encoder configuration structure.
   vpx_codec_enc_cfg_t config;
   memset(&config, 0, sizeof(vpx_codec_enc_cfg_t));
   if (vpx_codec_enc_config_default(vpx_codec_vp8_cx(), &config, 0)) {
     return NS_ERROR_FAILURE;
   }
 
@@ -148,16 +152,18 @@ VP8TrackEncoder::GetMetadata()
 
   if (mCanceled || mEncodingComplete) {
     return nullptr;
   }
 
   nsRefPtr<VP8Metadata> meta = new VP8Metadata();
   meta->mWidth = mFrameWidth;
   meta->mHeight = mFrameHeight;
+  meta->mDisplayWidth = mDisplayWidth;
+  meta->mDisplayHeight = mDisplayHeight;
   meta->mEncodedFrameRate = mEncodedFrameRate;
 
   return meta.forget();
 }
 
 nsresult
 VP8TrackEncoder::GetEncodedPartitions(EncodedFrameContainer& aData)
 {
--- a/content/media/encoder/VP8TrackEncoder.h
+++ b/content/media/encoder/VP8TrackEncoder.h
@@ -33,16 +33,17 @@ public:
   virtual ~VP8TrackEncoder();
 
   already_AddRefed<TrackMetadataBase> GetMetadata() MOZ_FINAL MOZ_OVERRIDE;
 
   nsresult GetEncodedTrack(EncodedFrameContainer& aData) MOZ_FINAL MOZ_OVERRIDE;
 
 protected:
   nsresult Init(int32_t aWidth, int32_t aHeight,
+                int32_t aDisplayWidth, int32_t aDisplayHeight,
                 TrackRate aTrackRate) MOZ_FINAL MOZ_OVERRIDE;
 
 private:
   // Calculate the target frame's encoded duration.
   TrackTicks CalculateEncodedDuration(TrackTicks aDurationCopied);
 
   // Calculate the mRemainingTicks for next target frame.
   TrackTicks CalculateRemainingTicks(TrackTicks aDurationCopied,
--- a/content/media/webm/EbmlComposer.cpp
+++ b/content/media/webm/EbmlComposer.cpp
@@ -36,17 +36,18 @@ void EbmlComposer::GenerateHeader()
       writeSegmentInformation(&ebml, &ebmlLoc, TIME_CODE_SCALE, 0);
       {
         EbmlLoc trackLoc;
         Ebml_StartSubElement(&ebml, &trackLoc, Tracks);
         {
           // Video
           if (mWidth > 0 && mHeight > 0) {
             writeVideoTrack(&ebml, 0x1, 0, "V_VP8",
-                            mWidth, mHeight, mFrameRate);
+                            mWidth, mHeight,
+                            mDisplayWidth, mDisplayHeight, mFrameRate);
           }
           // Audio
           if (mCodecPrivateData.Length() > 0) {
             writeAudioTrack(&ebml, 0x2, 0x0, "A_VORBIS", mSampleFreq,
                             mChannels, mCodecPrivateData.Elements(),
                             mCodecPrivateData.Length());
           }
         }
@@ -118,23 +119,28 @@ EbmlComposer::WriteSimpleBlock(EncodedFr
   }
   MOZ_ASSERT_IF(ebml.offset > DEFAULT_HEADER_SIZE + aFrame->GetFrameData().Length(),
                 "write more data > EBML_BUFFER_SIZE");
   mClusterBuffs.LastElement().SetLength(ebml.offset);
 }
 
 void
 EbmlComposer::SetVideoConfig(uint32_t aWidth, uint32_t aHeight,
+                             uint32_t aDisplayWidth, uint32_t aDisplayHeight,
                              float aFrameRate)
 {
   MOZ_ASSERT(aWidth > 0, "Width should > 0");
   MOZ_ASSERT(aHeight > 0, "Height should > 0");
+  MOZ_ASSERT(aDisplayWidth > 0, "DisplayWidth should > 0");
+  MOZ_ASSERT(aDisplayHeight > 0, "DisplayHeight should > 0");
   MOZ_ASSERT(aFrameRate > 0, "FrameRate should > 0");
   mWidth = aWidth;
   mHeight = aHeight;
+  mDisplayWidth = aDisplayWidth;
+  mDisplayHeight = aDisplayHeight;
   mFrameRate = aFrameRate;
 }
 
 void
 EbmlComposer::SetAudioConfig(uint32_t aSampleFreq, uint32_t aChannels,
                              uint32_t aBitDepth)
 {
   MOZ_ASSERT(aSampleFreq > 0, "SampleFreq should > 0");
--- a/content/media/webm/EbmlComposer.h
+++ b/content/media/webm/EbmlComposer.h
@@ -14,17 +14,18 @@ namespace mozilla {
  * A WebM muxer helper for package the valid WebM format.
  */
 class EbmlComposer {
 public:
   EbmlComposer();
   /*
    * Assign the parameter which header required.
    */
-  void SetVideoConfig(uint32_t aWidth, uint32_t aHeight, float aFrameRate);
+  void SetVideoConfig(uint32_t aWidth, uint32_t aHeight, uint32_t aDisplayWidth,
+                      uint32_t aDisplayHeight, float aFrameRate);
 
   void SetAudioConfig(uint32_t aSampleFreq, uint32_t aChannels,
                       uint32_t bitDepth);
   /*
    * Set the CodecPrivateData for writing in header.
    */
   void SetAudioCodecPrivateData(nsTArray<uint8_t>& aBufs)
   {
@@ -59,16 +60,18 @@ private:
   nsTArray<uint8_t> mCodecPrivateData;
 
   // The timecode of the cluster.
   uint64_t mClusterTimecode;
 
   // Video configuration
   int mWidth;
   int mHeight;
+  int mDisplayWidth;
+  int mDisplayHeight;
   float mFrameRate;
   // Audio configuration
   float mSampleFreq;
   int mBitDepth;
   int mChannels;
 };
 
 }
--- a/content/media/webm/WebMWriter.cpp
+++ b/content/media/webm/WebMWriter.cpp
@@ -38,16 +38,17 @@ WebMWriter::GetContainerData(nsTArray<ns
 nsresult
 WebMWriter::SetMetadata(TrackMetadataBase* aMetadata)
 {
   MOZ_ASSERT(aMetadata);
   if (aMetadata->GetKind() == TrackMetadataBase::METADATA_VP8) {
     VP8Metadata* meta = static_cast<VP8Metadata*>(aMetadata);
     MOZ_ASSERT(meta, "Cannot find vp8 encoder metadata");
     mEbmlComposer->SetVideoConfig(meta->mWidth, meta->mHeight,
+                                  meta->mDisplayWidth, meta->mDisplayHeight,
                                   meta->mEncodedFrameRate);
     mMetadataRequiredFlag = mMetadataRequiredFlag & ~ContainerWriter::CREATE_VIDEO_TRACK;
   }
 
   if (aMetadata->GetKind() == TrackMetadataBase::METADATA_VORBIS) {
     VorbisMetadata* meta = static_cast<VorbisMetadata*>(aMetadata);
     MOZ_ASSERT(meta, "Cannot find vorbis encoder metadata");
     mEbmlComposer->SetAudioConfig(meta->mSamplingFrequency, meta->mChannels, meta->mBitDepth);
--- a/content/media/webm/WebMWriter.h
+++ b/content/media/webm/WebMWriter.h
@@ -24,16 +24,18 @@ public:
 };
 
 // VP8 meta data structure
 class VP8Metadata : public TrackMetadataBase
 {
 public:
   int32_t mWidth;
   int32_t mHeight;
+  int32_t mDisplayWidth;
+  int32_t mDisplayHeight;
   int32_t mEncodedFrameRate;
   MetadataKind GetKind() const MOZ_OVERRIDE { return METADATA_VP8; }
 };
 
 /**
  * WebM writer helper
  * This class accepts encoder to set audio or video meta data or
  * encoded data to ebml Composer, and get muxing data through GetContainerData.
--- a/dom/camera/GonkCameraHwMgr.cpp
+++ b/dom/camera/GonkCameraHwMgr.cpp
@@ -158,22 +158,29 @@ GonkCameraHardware::Init()
   DOM_CAMERA_LOGI("Sensor orientation: base=%d, offset=%d, final=%d\n", info.orientation, offset, mSensorOrientation);
 
   // Disable shutter sound in android CameraService because gaia camera app will play it
   mCamera->sendCommand(CAMERA_CMD_ENABLE_SHUTTER_SOUND, 0, 0);
 
   mNativeWindow = new GonkNativeWindow();
   mNativeWindow->setNewFrameCallback(this);
   mCamera->setListener(this);
-#if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 17
+
+#if defined(MOZ_WIDGET_GONK)
+
+#if ANDROID_VERSION >= 19
+  mCamera->setPreviewTarget(mNativeWindow->getBufferQueue());
+#elif (ANDROID_VERSION == 17) || (ANDROID_VERSION == 18)
   mCamera->setPreviewTexture(mNativeWindow->getBufferQueue());
 #else
   mCamera->setPreviewTexture(mNativeWindow);
 #endif
 
+#endif
+
   return NS_OK;
 }
 
 sp<GonkCameraHardware>
 GonkCameraHardware::Connect(mozilla::nsGonkCameraControl* aTarget, uint32_t aCameraId)
 {
 #if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 18
   sp<Camera> camera = Camera::connect(aCameraId, /* clientPackageName */String16("gonk.camera"), Camera::USE_CALLING_UID);
--- a/dom/datastore/DataStore.jsm
+++ b/dom/datastore/DataStore.jsm
@@ -305,26 +305,33 @@ this.DataStore.prototype = {
   receiveMessage: function(aMessage) {
     debug("receiveMessage");
 
     if (aMessage.name != "DataStore:Changed:Return:OK") {
       debug("Wrong message: " + aMessage.name);
       return;
     }
 
+    // If this message is not for this DataStore, let's ignore it.
+    if (aMessage.data.owner != this._owner ||
+        aMessage.data.store != this._name) {
+      return;
+    }
+
     let self = this;
 
     this.retrieveRevisionId(
       function() {
         // If we have an active cursor we don't emit events.
         if (self._cursor) {
           return;
         }
 
-        let event = new self._window.DataStoreChangeEvent('change', aMessage.data);
+        let event = new self._window.DataStoreChangeEvent('change',
+                                                          aMessage.data.message);
         self.__DOM_IMPL__.dispatchEvent(event);
       }
     );
   },
 
   get exposedObject() {
     debug("get exposedObject");
     return this._exposedObject;
--- a/dom/datastore/DataStoreChangeNotifier.jsm
+++ b/dom/datastore/DataStoreChangeNotifier.jsm
@@ -51,42 +51,35 @@ this.DataStoreChangeNotifier = {
         break;
 
       default:
         debug("Wrong observer topic: " + aTopic);
         break;
     }
   },
 
-  broadcastMessage: function broadcastMessage(aMsgName, aData) {
-    debug("Broadast");
-    this.children.forEach(function(obj) {
-      if (obj.store == aData.store && obj.owner == aData.owner) {
-        obj.mm.sendAsyncMessage(aMsgName, aData.message);
-      }
-    });
-  },
-
   receiveMessage: function(aMessage) {
     debug("receiveMessage");
 
     // No check has to be done when the message is 'child-process-shutdown'
     // because at this point the target is already disconnected from
     // nsFrameMessageManager, so that assertAppHasStatus will always fail.
     let prefName = 'dom.testing.datastore_enabled_for_hosted_apps';
     if (aMessage.name != 'child-process-shutdown' &&
         (Services.prefs.getPrefType(prefName) == Services.prefs.PREF_INVALID ||
          !Services.prefs.getBoolPref(prefName)) &&
         !aMessage.target.assertAppHasStatus(Ci.nsIPrincipal.APP_STATUS_CERTIFIED)) {
       return;
     }
 
     switch (aMessage.name) {
       case "DataStore:Changed":
-        this.broadcastMessage("DataStore:Changed:Return:OK", aMessage.data);
+        debug("Broadasting message.");
+        let childMM = aMessage.target.QueryInterface(Ci.nsIMessageSender);
+        childMM.sendAsyncMessage("DataStore:Changed:Return:OK", aMessage.data);
         break;
 
       case "DataStore:RegisterForMessages":
         debug("Register!");
 
         for (let i = 0; i < this.children.length; ++i) {
           if (this.children[i].mm == aMessage.target &&
               this.children[i].store == aMessage.data.store &&
--- a/dom/datastore/tests/file_basic.html
+++ b/dom/datastore/tests/file_basic.html
@@ -118,18 +118,17 @@
     function() { testStoreGet(gId, "hello world 2"); },
 
     // getLength
     function() { testStoreGetLength(3).then(function() { runTest(); }, cbError); },
 
     // Remove
     function() { testStoreRemove(gId).then(function(what) {
                    runTest(); }, cbError); },
-    function() { testStoreGet(gId).catch(function() {
-                   runTest(); }); },
+    function() { testStoreGet(gId, undefined); },
 
     // Remove - wrong ID
     function() { testStoreRemove(gId).then(function(what) {
                    runTest(); }, cbError); },
 
     // Clear
     function() { testStoreClear().then(function(what) {
                    runTest(); }, cbError); },
new file mode 100644
--- /dev/null
+++ b/dom/datastore/tests/file_bug976311.html
@@ -0,0 +1,88 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+  <meta charset="utf-8">
+  <title>Test for DataStore - bug 976311 app1</title>
+</head>
+<body>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+  <script type="application/javascript;version=1.7">
+
+  var gStores = [];
+  var expectedWhere;
+
+  function is(a, b, msg) {
+    ok(a === b, msg);
+  }
+
+  function ok(a, msg) {
+    alert((a ? 'OK' : 'KO')+ ' ' + msg)
+  }
+
+  function cbError() {
+    alert('KO error');
+  }
+
+  function finish() {
+    alert('DONE');
+  }
+
+  function checkEvent(id) {
+    is(expectedWhere, id, "Message on the correct DS: " + id + " " + expectedWhere);
+    runTest();
+  }
+
+  function testGetDataStores() {
+    navigator.getDataStores('foo').then(function(stores) {
+      is(stores.length, 2, "getDataStores('foo') returns 1 element");
+
+      is(stores[0].name, 'foo', 'The dataStore.name is foo');
+      is(stores[0].readOnly, false, 'The dataStore foo is not in readonly');
+      stores[0].onchange = function(evt) { checkEvent(0); }
+      gStores.push(stores[0]);
+
+      is(stores[1].name, 'foo', 'The dataStore.name is foo');
+      is(stores[1].readOnly, false, 'The dataStore foo is not in readonly');
+      stores[1].onchange = function(evt) { checkEvent(1); }
+      gStores.push(stores[1]);
+
+      runTest();
+    }, cbError);
+  }
+
+  function testStoreAdd(where, value) {
+    expectedWhere = where;
+    dump("ADD TO: " + gStores[where].owner + "\n");
+    gStores[where].add({ a: value });
+  }
+
+  var tests = [
+    // Test for GetDataStore
+    testGetDataStores,
+
+    function() { testStoreAdd(0, 1); },
+    function() { testStoreAdd(1, 2); },
+    function() { testStoreAdd(0, 3); },
+    function() { testStoreAdd(1, 4); }
+  ];
+
+  function runTest() {
+    if (!tests.length) {
+      finish();
+      return;
+    }
+
+    var test = tests.shift();
+    test();
+  }
+
+  runTest();
+  </script>
+</pre>
+</body>
+</html>
+
new file mode 100644
--- /dev/null
+++ b/dom/datastore/tests/file_bug976311.template.webapp
@@ -0,0 +1,12 @@
+{
+  "name": "Really Rapid Release (hosted)",
+  "description": "Updated even faster than <a href='http://mozilla.org'>Firefox</a>, just to annoy slashdotters.",
+  "launch_path": "/tests/dom/datastore/tests/TESTTOKEN",
+  "icons": { "128": "default_icon" },
+  "datastores-owned" : {
+    "foo" : { "access": "readwrite", "description" : "This store is called foo" }
+  },
+  "datastores-access" : {
+    "foo" : { "readonly": false, "description" : "This store is called foo" }
+  }
+}
--- a/dom/datastore/tests/mochitest.ini
+++ b/dom/datastore/tests/mochitest.ini
@@ -9,20 +9,23 @@ support-files =
   file_app.template.webapp
   file_app2.template.webapp
   file_arrays.html
   file_sync.html
   file_bug924104.html
   file_certifiedApp.html
   file_keys.html
   file_duplicate.html
+  file_bug976311.html
+  file_bug976311.template.webapp
 
 [test_app_install.html]
 [test_readonly.html]
 [test_basic.html]
 [test_changes.html]
 [test_arrays.html]
 [test_oop.html]
 [test_sync.html]
 [test_bug924104.html]
 [test_certifiedApp.html]
 [test_keys.html]
 [test_duplicate.html]
+[test_bug976311.html]
new file mode 100644
--- /dev/null
+++ b/dom/datastore/tests/test_bug976311.html
@@ -0,0 +1,135 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+  <meta charset="utf-8">
+  <title>Test for DataStore - bug 976311</title>
+  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<div id="container"></div>
+  <script type="application/javascript;version=1.7">
+
+  var gHostedManifestURL = 'http://test/tests/dom/datastore/tests/file_app.sjs?testToken=file_bug976311.html&template=file_bug976311.template.webapp';
+  var gHostedManifestURL2 = 'http://example.com/tests/dom/datastore/tests/file_app.sjs?testToken=file_bug976311.html&template=file_bug976311.template.webapp';
+  var gApps = [];
+
+  function cbError() {
+    ok(false, "Error callback invoked");
+    finish();
+  }
+
+  function installApp(aApp) {
+    var request = navigator.mozApps.install(aApp);
+    request.onerror = cbError;
+    request.onsuccess = function() {
+      gApps.push(request.result);
+      runTest();
+    }
+  }
+
+  function uninstallApps() {
+    if (!gApps.length) {
+      ok(true, "All done!");
+      runTest();
+      return;
+    }
+
+    var app = gApps.pop();
+    var request = navigator.mozApps.mgmt.uninstall(app);
+    request.onerror = cbError;
+    request.onsuccess = uninstallApps;
+  }
+
+
+  function testApp() {
+   var ifr = document.createElement('iframe');
+   ifr.setAttribute('mozbrowser', 'true');
+   ifr.setAttribute('mozapp', gApps[0].manifestURL);
+   ifr.setAttribute('src', gApps[0].manifest.launch_path);
+   var domParent = document.getElementById('container');
+
+   // Set us up to listen for messages from the app.
+   var listener = function(e) {
+     var message = e.detail.message;
+     if (/^OK/.exec(message)) {
+       ok(true, "Message from app: " + message);
+     } else if (/KO/.exec(message)) {
+       ok(false, "Message from app: " + message);
+     } else if (/DONE/.exec(message)) {
+       ok(true, "Messaging from app complete");
+       ifr.removeEventListener('mozbrowsershowmodalprompt', listener);
+       domParent.removeChild(ifr);
+       runTest();
+     }
+   }
+
+   // This event is triggered when the app calls "alert".
+   ifr.addEventListener('mozbrowsershowmodalprompt', listener, false);
+   domParent.appendChild(ifr);
+
+  }
+
+  var tests = [
+    // Permissions
+    function() {
+      SpecialPowers.pushPermissions(
+        [{ "type": "browser", "allow": 1, "context": document },
+         { "type": "embed-apps", "allow": 1, "context": document },
+         { "type": "webapps-manage", "allow": 1, "context": document }], runTest);
+    },
+
+    // Preferences
+    function() {
+      SpecialPowers.pushPrefEnv({"set": [["dom.datastore.enabled", true],
+                                         ["dom.testing.ignore_ipc_principal", true],
+                                         ["dom.testing.datastore_enabled_for_hosted_apps", true]]}, runTest);
+    },
+
+    function() {
+      SpecialPowers.setAllAppsLaunchable(true);
+      SpecialPowers.setBoolPref("dom.mozBrowserFramesEnabled", true);
+      runTest();
+    },
+
+    // No confirmation needed when an app is installed
+    function() {
+      SpecialPowers.autoConfirmAppInstall(runTest);
+    },
+
+    // Installing the app1
+    function() { installApp(gHostedManifestURL); },
+
+    // Installing the app2
+    function() { installApp(gHostedManifestURL2); },
+
+    // Run tests in app
+    testApp,
+
+    // Uninstall the apps
+    uninstallApps
+  ];
+
+  function runTest() {
+    if (!tests.length) {
+      finish();
+      return;
+    }
+
+    var test = tests.shift();
+    test();
+  }
+
+  function finish() {
+    SimpleTest.finish();
+  }
+
+  if (SpecialPowers.isMainProcess()) {
+    SpecialPowers.Cu.import("resource://gre/modules/DataStoreChangeNotifier.jsm");
+  }
+
+  SimpleTest.waitForExplicitFinish();
+  runTest();
+  </script>
+</body>
+</html>
--- a/dom/wifi/WifiWorker.js
+++ b/dom/wifi/WifiWorker.js
@@ -291,17 +291,19 @@ var WifiManager = (function() {
 
   function syncDebug() {
     if (debugEnabled !== DEBUG) {
       let wanted = DEBUG;
       wifiCommand.setLogLevel(wanted ? "DEBUG" : "INFO", function(ok) {
         if (ok)
           debugEnabled = wanted;
       });
-      p2pManager.setDebug(DEBUG);
+      if (p2pSupported && p2pManager) {
+        p2pManager.setDebug(DEBUG);
+      }
     }
   }
 
   function getDebugEnabled(callback) {
     wifiCommand.getLogLevel(function(level) {
       if (level === null) {
         debug("Unable to get wpa_supplicant's log level");
         callback(false);
@@ -2497,16 +2499,89 @@ WifiWorker.prototype = {
 
       // Otherwise, let the client know that it failed, it's responsible for
       // trying again in a few seconds.
       sent = true;
       this._sendMessage(message, false, "ScanFailed", msg);
     }).bind(this));
   },
 
+  getWifiScanResults: function(callback) {
+    var count = 0;
+    var timer = null;
+    var self = this;
+
+    self.waitForScan(waitForScanCallback);
+    doScan();
+    function doScan() {
+      WifiManager.scan(true, function (ok) {
+        if (!ok) {
+          if (!timer) {
+            count = 0;
+            timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
+          }
+
+          if (count++ >= 3) {
+            timer = null;
+            this.wantScanResults.splice(this.wantScanResults.indexOf(waitForScanCallback), 1);
+            callback.onfailure();
+            return;
+          }
+
+          // Else it's still running, continue waiting.
+          timer.initWithCallback(doScan, 10000, Ci.nsITimer.TYPE_ONE_SHOT);
+          return;
+        }
+      });
+    }
+
+    function waitForScanCallback(networks) {
+      if (networks === null) {
+        callback.onfailure();
+        return;
+      }
+
+      var wifiScanResults = new Array();
+      var net;
+      for (let net in networks) {
+        let value = networks[net];
+        wifiScanResults.push(transformResult(value));
+      }
+      callback.onready(wifiScanResults.length, wifiScanResults);
+    }
+
+    function transformResult(element) {
+      var result = new WifiScanResult();
+      result.connected = false;
+      for (let id in element) {
+        if (id === "__exposedProps__") {
+          continue;
+        }
+        if (id === "security") {
+          result[id] = 0;
+          var security = element[id];
+          for (let j = 0; j < security.length; j++) {
+            if (security[j] === "WPA-PSK") {
+              result[id] |= Ci.nsIWifiScanResult.WPA_PSK;
+            } else if (security[j] === "WPA-EAP") {
+              result[id] |= Ci.nsIWifiScanResult.WPA_EAP;
+            } else if (security[j] === "WEP") {
+              result[id] |= Ci.nsIWifiScanResult.WEP;
+            } else {
+             result[id] = 0;
+            }
+          }
+        } else {
+          result[id] = element[id];
+        }
+      }
+      return result;
+    }
+  },
+
   getKnownNetworks: function(msg) {
     const message = "WifiManager:getKnownNetworks:Return";
     if (!WifiManager.enabled) {
       this._sendMessage(message, false, "Wifi is disabled", msg);
       return;
     }
 
     this._reloadConfiguredNetworks((function(ok) {
--- a/gfx/2d/FilterNodeSoftware.cpp
+++ b/gfx/2d/FilterNodeSoftware.cpp
@@ -529,32 +529,32 @@ FilterNodeSoftware::Create(FilterType aT
       break;
     case FilterType::PREMULTIPLY:
       filter = new FilterNodePremultiplySoftware();
       break;
     case FilterType::UNPREMULTIPLY:
       filter = new FilterNodeUnpremultiplySoftware();
       break;
     case FilterType::POINT_DIFFUSE:
-      filter = new FilterNodeLightingSoftware<PointLightSoftware, DiffuseLightingSoftware>();
+      filter = new FilterNodeLightingSoftware<PointLightSoftware, DiffuseLightingSoftware>("FilterNodeLightingSoftware<PointLight, DiffuseLighting>");
       break;
     case FilterType::POINT_SPECULAR:
-      filter = new FilterNodeLightingSoftware<PointLightSoftware, SpecularLightingSoftware>();
+      filter = new FilterNodeLightingSoftware<PointLightSoftware, SpecularLightingSoftware>("FilterNodeLightingSoftware<PointLight, SpecularLighting>");
       break;
     case FilterType::SPOT_DIFFUSE:
-      filter = new FilterNodeLightingSoftware<SpotLightSoftware, DiffuseLightingSoftware>();
+      filter = new FilterNodeLightingSoftware<SpotLightSoftware, DiffuseLightingSoftware>("FilterNodeLightingSoftware<SpotLight, DiffuseLighting>");
       break;
     case FilterType::SPOT_SPECULAR:
-      filter = new FilterNodeLightingSoftware<SpotLightSoftware, SpecularLightingSoftware>();
+      filter = new FilterNodeLightingSoftware<SpotLightSoftware, SpecularLightingSoftware>("FilterNodeLightingSoftware<SpotLight, SpecularLighting>");
       break;
     case FilterType::DISTANT_DIFFUSE:
-      filter = new FilterNodeLightingSoftware<DistantLightSoftware, DiffuseLightingSoftware>();
+      filter = new FilterNodeLightingSoftware<DistantLightSoftware, DiffuseLightingSoftware>("FilterNodeLightingSoftware<DistantLight, DiffuseLighting>");
       break;
     case FilterType::DISTANT_SPECULAR:
-      filter = new FilterNodeLightingSoftware<DistantLightSoftware, SpecularLightingSoftware>();
+      filter = new FilterNodeLightingSoftware<DistantLightSoftware, SpecularLightingSoftware>("FilterNodeLightingSoftware<DistantLight, SpecularLighting>");
       break;
   }
   return filter;
 }
 
 void
 FilterNodeSoftware::Draw(DrawTarget* aDrawTarget,
                          const Rect &aSourceRect,
@@ -3054,18 +3054,21 @@ DistantLightSoftware::SetAttribute(uint3
 
 static inline Point3D Normalized(const Point3D &vec) {
   Point3D copy(vec);
   copy.Normalize();
   return copy;
 }
 
 template<typename LightType, typename LightingType>
-FilterNodeLightingSoftware<LightType, LightingType>::FilterNodeLightingSoftware()
+FilterNodeLightingSoftware<LightType, LightingType>::FilterNodeLightingSoftware(const char* aTypeName)
  : mSurfaceScale(0)
+#if defined(MOZILLA_INTERNAL_API) && (defined(DEBUG) || defined(FORCE_BUILD_REFCNT_LOGGING))
+ , mTypeName(aTypeName)
+#endif
 {}
 
 template<typename LightType, typename LightingType>
 int32_t
 FilterNodeLightingSoftware<LightType, LightingType>::InputIndex(uint32_t aInputEnumIndex)
 {
   switch (aInputEnumIndex) {
     case IN_LIGHTING_IN: return 0;
--- a/gfx/2d/FilterNodeSoftware.h
+++ b/gfx/2d/FilterNodeSoftware.h
@@ -678,18 +678,22 @@ protected:
   virtual int32_t InputIndex(uint32_t aInputEnumIndex) MOZ_OVERRIDE;
   virtual void RequestFromInputsForRect(const IntRect &aRect) MOZ_OVERRIDE;
 };
 
 template<typename LightType, typename LightingType>
 class FilterNodeLightingSoftware : public FilterNodeSoftware
 {
 public:
-  MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(FilterNodeLightingSoftware)
-  FilterNodeLightingSoftware();
+#if defined(MOZILLA_INTERNAL_API) && (defined(DEBUG) || defined(FORCE_BUILD_REFCNT_LOGGING))
+  // Helpers for refcounted
+  virtual const char* typeName() const MOZ_OVERRIDE { return mTypeName; }
+  virtual size_t typeSize() const MOZ_OVERRIDE { return sizeof(*this); }
+#endif
+  explicit FilterNodeLightingSoftware(const char* aTypeName);
   virtual const char* GetName() MOZ_OVERRIDE { return "Lighting"; }
   using FilterNodeSoftware::SetAttribute;
   virtual void SetAttribute(uint32_t aIndex, Float) MOZ_OVERRIDE;
   virtual void SetAttribute(uint32_t aIndex, const Size &) MOZ_OVERRIDE;
   virtual void SetAttribute(uint32_t aIndex, const Point3D &) MOZ_OVERRIDE;
   virtual void SetAttribute(uint32_t aIndex, const Color &) MOZ_OVERRIDE;
 
 protected:
@@ -704,14 +708,17 @@ private:
                                            CoordType aKernelUnitLengthX,
                                            CoordType aKernelUnitLengthY);
 
   LightType mLight;
   LightingType mLighting;
   Float mSurfaceScale;
   Size mKernelUnitLength;
   Color mColor;
+#if defined(MOZILLA_INTERNAL_API) && (defined(DEBUG) || defined(FORCE_BUILD_REFCNT_LOGGING))
+  const char* mTypeName;
+#endif
 };
 
 }
 }
 
 #endif // _MOZILLA_GFX_FILTERNODESOFTWARE_H_
--- a/gfx/layers/opengl/OGLShaderProgram.cpp
+++ b/gfx/layers/opengl/OGLShaderProgram.cpp
@@ -178,16 +178,22 @@ ProgramProfileOGL::GetProfileFor(ShaderC
 
   if (!(aConfig.mFeatures & ENABLE_RENDER_COLOR)) {
     vs << "  vTexCoord = (uTextureTransform * vec4(aTexCoord.x, aTexCoord.y, 0.0, 1.0)).xy;" << endl;
   }
 
   vs << "  gl_Position = finalPosition;" << endl;
   vs << "}" << endl;
 
+  if (aConfig.mFeatures & ENABLE_TEXTURE_RECT) {
+    fs << "#extension GL_ARB_texture_rectangle : require" << endl;
+  }
+  if (aConfig.mFeatures & ENABLE_TEXTURE_EXTERNAL) {
+    fs << "#extension GL_OES_EGL_image_external : require" << endl;
+  }
   fs << "#ifdef GL_ES" << endl;
   fs << "precision mediump float;" << endl;
   fs << "#define COLOR_PRECISION lowp" << endl;
   fs << "#else" << endl;
   fs << "#define COLOR_PRECISION" << endl;
   fs << "#endif" << endl;
   if (aConfig.mFeatures & ENABLE_RENDER_COLOR) {
     fs << "uniform COLOR_PRECISION vec4 uRenderColor;" << endl;
@@ -208,24 +214,22 @@ ProgramProfileOGL::GetProfileFor(ShaderC
       fs << "uniform COLOR_PRECISION float uLayerOpacity;" << endl;
     }
   }
 
   const char *sampler2D = "sampler2D";
   const char *texture2D = "texture2D";
 
   if (aConfig.mFeatures & ENABLE_TEXTURE_RECT) {
-    fs << "#extension GL_ARB_texture_rectangle : require" << endl;
     fs << "uniform vec2 uTexCoordMultiplier;" << endl;
     sampler2D = "sampler2DRect";
     texture2D = "texture2DRect";
   }
 
   if (aConfig.mFeatures & ENABLE_TEXTURE_EXTERNAL) {
-    fs << "#extension GL_OES_EGL_image_external : require" << endl;
     sampler2D = "samplerExternalOES";
   }
 
   if (aConfig.mFeatures & ENABLE_TEXTURE_YCBCR) {
     fs << "uniform sampler2D uYTexture;" << endl;
     fs << "uniform sampler2D uCbTexture;" << endl;
     fs << "uniform sampler2D uCrTexture;" << endl;
   } else if (aConfig.mFeatures & ENABLE_TEXTURE_COMPONENT_ALPHA) {
--- a/ipc/moz.build
+++ b/ipc/moz.build
@@ -16,14 +16,14 @@ if CONFIG['MOZ_B2G_RIL']:
 
 if CONFIG['MOZ_B2G_BT_BLUEZ']:
     DIRS += ['dbus']
 
 if CONFIG['MOZ_NFC']:
     DIRS += ['nfc']
 
 if CONFIG['MOZ_B2G_RIL'] or CONFIG['MOZ_B2G_BT'] or CONFIG['MOZ_NFC'] or CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gonk':
-    DIRS += ['unixsocket']
+    DIRS += ['unixfd', 'unixsocket']
 
 if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gonk':
-    DIRS += ['netd', 'keystore']
+    DIRS += ['keystore', 'netd']
 
 TOOL_DIRS += ['app']
new file mode 100644
--- /dev/null
+++ b/ipc/unixfd/UnixFdWatcher.cpp
@@ -0,0 +1,119 @@
+/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
+/* vim: set ts=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 "UnixFdWatcher.h"
+
+#ifdef CHROMIUM_LOG
+#undef CHROMIUM_LOG
+#endif
+
+#if defined(MOZ_WIDGET_GONK)
+#include <android/log.h>
+#define CHROMIUM_LOG(args...)  __android_log_print(ANDROID_LOG_INFO, "I/O", args);
+#else
+#include <stdio.h>
+#define IODEBUG true
+#define CHROMIUM_LOG(args...) if (IODEBUG) printf(args);
+#endif
+
+namespace mozilla {
+namespace ipc {
+
+UnixFdWatcher::~UnixFdWatcher()
+{
+  NS_WARN_IF(IsOpen()); /* mFd should have been closed already */
+}
+
+void
+UnixFdWatcher::Close()
+{
+  MOZ_ASSERT(MessageLoopForIO::current() == mIOLoop);
+
+  if (NS_WARN_IF(!IsOpen())) {
+    /* mFd should have been open */
+    return;
+  }
+  OnClose();
+  RemoveWatchers(READ_WATCHER|WRITE_WATCHER);
+  mFd.dispose();
+}
+
+void
+UnixFdWatcher::AddWatchers(unsigned long aWatchers, bool aPersistent)
+{
+  MOZ_ASSERT(MessageLoopForIO::current() == mIOLoop);
+  MOZ_ASSERT(IsOpen());
+
+  // Before we add a watcher, we need to remove it! Removing is always
+  // safe, but adding the same watcher twice can lead to endless loops
+  // inside libevent.
+  RemoveWatchers(aWatchers);
+
+  if (aWatchers & READ_WATCHER) {
+    MessageLoopForIO::current()->WatchFileDescriptor(
+      mFd,
+      aPersistent,
+      MessageLoopForIO::WATCH_READ,
+      &mReadWatcher,
+      this);
+  }
+  if (aWatchers & WRITE_WATCHER) {
+    MessageLoopForIO::current()->WatchFileDescriptor(
+      mFd,
+      aPersistent,
+      MessageLoopForIO::WATCH_WRITE,
+      &mWriteWatcher,
+      this);
+  }
+}
+
+void
+UnixFdWatcher::RemoveWatchers(unsigned long aWatchers)
+{
+  MOZ_ASSERT(MessageLoopForIO::current() == mIOLoop);
+  MOZ_ASSERT(IsOpen());
+
+  if (aWatchers & READ_WATCHER) {
+    mReadWatcher.StopWatchingFileDescriptor();
+  }
+  if (aWatchers & WRITE_WATCHER) {
+    mWriteWatcher.StopWatchingFileDescriptor();
+  }
+}
+
+void
+UnixFdWatcher::OnError(const char* aFunction, int aErrno)
+{
+  MOZ_ASSERT(MessageLoopForIO::current() == mIOLoop);
+
+  CHROMIUM_LOG("%s failed with error %d (%s)",
+               aFunction, aErrno, strerror(aErrno));
+}
+
+UnixFdWatcher::UnixFdWatcher(MessageLoop* aIOLoop)
+: mIOLoop(aIOLoop)
+{
+  MOZ_ASSERT(mIOLoop);
+}
+
+UnixFdWatcher::UnixFdWatcher(MessageLoop* aIOLoop, int aFd)
+: mIOLoop(aIOLoop)
+, mFd(aFd)
+{
+  MOZ_ASSERT(mIOLoop);
+}
+
+void
+UnixFdWatcher::SetFd(int aFd)
+{
+  MOZ_ASSERT(MessageLoopForIO::current() == mIOLoop);
+  MOZ_ASSERT(!IsOpen());
+
+  mFd = aFd;
+}
+
+}
+}
new file mode 100644
--- /dev/null
+++ b/ipc/unixfd/UnixFdWatcher.h
@@ -0,0 +1,62 @@
+/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
+/* vim: set ts=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 "base/message_loop.h"
+#include "mozilla/FileUtils.h"
+
+namespace mozilla {
+namespace ipc {
+
+class UnixFdWatcher : public MessageLoopForIO::Watcher
+{
+public:
+  enum {
+    READ_WATCHER = 1<<0,
+    WRITE_WATCHER = 1<<1
+  };
+
+  virtual ~UnixFdWatcher();
+
+  MessageLoop* GetIOLoop() const
+  {
+    return mIOLoop;
+  }
+
+  int GetFd() const
+  {
+    return mFd;
+  }
+
+  bool IsOpen() const
+  {
+    return GetFd() >= 0;
+  }
+
+  virtual void Close();
+
+  void AddWatchers(unsigned long aWatchers, bool aPersistent);
+  void RemoveWatchers(unsigned long aWatchers);
+
+  // Callback method that's run before closing the file descriptor
+  virtual void OnClose() {};
+
+  // Callback method that's run on POSIX errors
+  virtual void OnError(const char* aFunction, int aErrno);
+
+protected:
+  UnixFdWatcher(MessageLoop* aIOLoop);
+  UnixFdWatcher(MessageLoop* aIOLoop, int aFd);
+  void SetFd(int aFd);
+
+private:
+  MessageLoop* mIOLoop;
+  ScopedClose mFd;
+  MessageLoopForIO::FileDescriptorWatcher mReadWatcher;
+  MessageLoopForIO::FileDescriptorWatcher mWriteWatcher;
+};
+
+}
+}
new file mode 100644
--- /dev/null
+++ b/ipc/unixfd/UnixFileWatcher.cpp
@@ -0,0 +1,44 @@
+/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
+/* vim: set ts=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 <fcntl.h>
+#include "UnixFileWatcher.h"
+
+namespace mozilla {
+namespace ipc {
+
+UnixFileWatcher::~UnixFileWatcher()
+{
+}
+
+nsresult
+UnixFileWatcher::Open(const char* aFilename, int aFlags, mode_t aMode)
+{
+  MOZ_ASSERT(MessageLoopForIO::current() == GetIOLoop());
+
+  int fd = TEMP_FAILURE_RETRY(open(aFilename, aFlags, aMode));
+  if (fd < 0) {
+    OnError("open", errno);
+    return NS_ERROR_FAILURE;
+  }
+  SetFd(fd);
+  OnOpened();
+
+  return NS_OK;
+}
+
+UnixFileWatcher::UnixFileWatcher(MessageLoop* aIOLoop)
+: UnixFdWatcher(aIOLoop)
+{
+}
+
+UnixFileWatcher::UnixFileWatcher(MessageLoop* aIOLoop, int aFd)
+: UnixFdWatcher(aIOLoop, aFd)
+{
+}
+
+}
+}
new file mode 100644
--- /dev/null
+++ b/ipc/unixfd/UnixFileWatcher.h
@@ -0,0 +1,28 @@
+/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
+/* vim: set ts=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 "UnixFdWatcher.h"
+
+namespace mozilla {
+namespace ipc {
+
+class UnixFileWatcher : public UnixFdWatcher
+{
+public:
+  virtual ~UnixFileWatcher();
+
+  nsresult Open(const char* aFilename, int aFlags, mode_t aMode = 0);
+
+  // Callback method for successful open requests
+  virtual void OnOpened() {};
+
+protected:
+  UnixFileWatcher(MessageLoop* aIOLoop);
+  UnixFileWatcher(MessageLoop* aIOLoop, int aFd);
+};
+
+}
+}
new file mode 100644
--- /dev/null
+++ b/ipc/unixfd/UnixSocketWatcher.cpp
@@ -0,0 +1,155 @@
+/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
+/* vim: set ts=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 <fcntl.h>
+#include "UnixSocketWatcher.h"
+
+namespace mozilla {
+namespace ipc {
+
+UnixSocketWatcher::~UnixSocketWatcher()
+{
+}
+
+void UnixSocketWatcher::Close()
+{
+  MOZ_ASSERT(MessageLoopForIO::current() == GetIOLoop());
+
+  mConnectionStatus = SOCKET_IS_DISCONNECTED;
+  UnixFdWatcher::Close();
+}
+
+nsresult
+UnixSocketWatcher::Connect(const struct sockaddr* aAddr, socklen_t aAddrLen)
+{
+  MOZ_ASSERT(MessageLoopForIO::current() == GetIOLoop());
+  MOZ_ASSERT(IsOpen());
+  MOZ_ASSERT(aAddr || !aAddrLen);
+
+  // Select non-blocking IO.
+  if (TEMP_FAILURE_RETRY(fcntl(GetFd(), F_SETFL, O_NONBLOCK)) < 0) {
+    OnError("fcntl", errno);
+    return NS_ERROR_FAILURE;
+  }
+
+  if (connect(GetFd(), aAddr, aAddrLen) < 0) {
+    if (errno == EINPROGRESS) {
+      // Select blocking IO again, since we've now at least queue'd the connect
+      // as nonblock.
+      int flags = TEMP_FAILURE_RETRY(fcntl(GetFd(), F_GETFL, 0));
+      if (flags < 0) {
+        OnError("fcntl", errno);
+        return NS_ERROR_FAILURE;
+      }
+      if (TEMP_FAILURE_RETRY(fcntl(GetFd(), F_SETFL, flags&~O_NONBLOCK)) < 0) {
+        OnError("fcntl", errno);
+        return NS_ERROR_FAILURE;
+      }
+      mConnectionStatus = SOCKET_IS_CONNECTING;
+      // Set up a write watch to receive the connect signal
+      AddWatchers(WRITE_WATCHER, false);
+    } else {
+      OnError("connect", errno);
+    }
+    return NS_ERROR_FAILURE;
+  }
+
+  mConnectionStatus = SOCKET_IS_CONNECTED;
+  OnConnected();
+
+  return NS_OK;
+}
+
+nsresult
+UnixSocketWatcher::Listen(const struct sockaddr* aAddr, socklen_t aAddrLen)
+{
+  MOZ_ASSERT(MessageLoopForIO::current() == GetIOLoop());
+  MOZ_ASSERT(IsOpen());
+  MOZ_ASSERT(aAddr || !aAddrLen);
+
+  if (bind(GetFd(), aAddr, aAddrLen) < 0) {
+    OnError("bind", errno);
+    return NS_ERROR_FAILURE;
+  }
+  if (listen(GetFd(), 1) < 0) {
+    OnError("listen", errno);
+    return NS_ERROR_FAILURE;
+  }
+  mConnectionStatus = SOCKET_IS_LISTENING;
+  OnListening();
+
+  return NS_OK;
+}
+
+UnixSocketWatcher::UnixSocketWatcher(MessageLoop* aIOLoop)
+: UnixFdWatcher(aIOLoop)
+, mConnectionStatus(SOCKET_IS_DISCONNECTED)
+{
+}
+
+UnixSocketWatcher::UnixSocketWatcher(MessageLoop* aIOLoop, int aFd,
+                                     ConnectionStatus aConnectionStatus)
+: UnixFdWatcher(aIOLoop, aFd)
+, mConnectionStatus(aConnectionStatus)
+{
+}
+
+void
+UnixSocketWatcher::SetSocket(int aFd, ConnectionStatus aConnectionStatus)
+{
+  MOZ_ASSERT(MessageLoopForIO::current() == GetIOLoop());
+
+  SetFd(aFd);
+  mConnectionStatus = aConnectionStatus;
+}
+
+void
+UnixSocketWatcher::OnFileCanReadWithoutBlocking(int aFd)
+{
+  MOZ_ASSERT(MessageLoopForIO::current() == GetIOLoop());
+  MOZ_ASSERT(aFd == GetFd());
+
+  if (mConnectionStatus == SOCKET_IS_CONNECTED) {
+    OnSocketCanReceiveWithoutBlocking();
+  } else if (mConnectionStatus == SOCKET_IS_LISTENING) {
+    int fd = TEMP_FAILURE_RETRY(accept(GetFd(), NULL, NULL));
+    if (fd < 0) {
+      OnError("accept", errno);
+    } else {
+      OnAccepted(fd);
+    }
+  } else {
+    NS_NOTREACHED("invalid connection state for reading");
+  }
+}
+
+void
+UnixSocketWatcher::OnFileCanWriteWithoutBlocking(int aFd)
+{
+  MOZ_ASSERT(MessageLoopForIO::current() == GetIOLoop());
+  MOZ_ASSERT(aFd == GetFd());
+
+  if (mConnectionStatus == SOCKET_IS_CONNECTED) {
+    OnSocketCanSendWithoutBlocking();
+  } else if (mConnectionStatus == SOCKET_IS_CONNECTING) {
+    RemoveWatchers(WRITE_WATCHER);
+    int error = 0;
+    socklen_t len = sizeof(error);
+    if (getsockopt(GetFd(), SOL_SOCKET, SO_ERROR, &error, &len) < 0) {
+      OnError("getsockopt", errno);
+    } else if (error) {
+      OnError("connect", error);
+    } else {
+      mConnectionStatus = SOCKET_IS_CONNECTED;
+      OnConnected();
+    }
+  } else {
+    NS_NOTREACHED("invalid connection state for writing");
+  }
+}
+
+}
+}
new file mode 100644
--- /dev/null
+++ b/ipc/unixfd/UnixSocketWatcher.h
@@ -0,0 +1,66 @@
+/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
+/* vim: set ts=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 "UnixFdWatcher.h"
+
+namespace mozilla {
+namespace ipc {
+
+class UnixSocketWatcher : public UnixFdWatcher
+{
+public:
+  enum ConnectionStatus {
+    SOCKET_IS_DISCONNECTED = 0,
+    SOCKET_IS_LISTENING,
+    SOCKET_IS_CONNECTING,
+    SOCKET_IS_CONNECTED
+  };
+
+  virtual ~UnixSocketWatcher();
+
+  virtual void Close() MOZ_OVERRIDE;
+
+  ConnectionStatus GetConnectionStatus() const
+  {
+    return mConnectionStatus;
+  }
+
+  // Connect to a peer
+  nsresult Connect(const struct sockaddr* aAddr, socklen_t aAddrLen);
+
+  // Listen on socket for incomming connection requests
+  nsresult Listen(const struct sockaddr* aAddr, socklen_t aAddrLen);
+
+  // Callback method for accepted connections
+  virtual void OnAccepted(int aFd) {};
+
+  // Callback method for successful connection requests
+  virtual void OnConnected() {};
+
+  // Callback method for successful listen requests
+  virtual void OnListening() {};
+
+  // Callback method for receiving from socket
+  virtual void OnSocketCanReceiveWithoutBlocking() {};
+
+  // Callback method for sending on socket
+  virtual void OnSocketCanSendWithoutBlocking() {};
+
+protected:
+  UnixSocketWatcher(MessageLoop* aIOLoop);
+  UnixSocketWatcher(MessageLoop* aIOLoop, int aFd,
+                    ConnectionStatus aConnectionStatus);
+  void SetSocket(int aFd, ConnectionStatus aConnectionStatus);
+
+private:
+  void OnFileCanReadWithoutBlocking(int aFd) MOZ_OVERRIDE;
+  void OnFileCanWriteWithoutBlocking(int aFd) MOZ_OVERRIDE;
+
+  ConnectionStatus mConnectionStatus;
+};
+
+}
+}
new file mode 100644
--- /dev/null
+++ b/ipc/unixfd/moz.build
@@ -0,0 +1,23 @@
+# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
+# 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/.
+
+EXPORTS.mozilla.ipc += [
+    'UnixFdWatcher.h',
+    'UnixFileWatcher.h',
+    'UnixSocketWatcher.h'
+]
+
+SOURCES += [
+    'UnixFdWatcher.cpp',
+    'UnixFileWatcher.cpp',
+    'UnixSocketWatcher.cpp'
+]
+
+FAIL_ON_WARNINGS = True
+
+include('/ipc/chromium/chromium-config.mozbuild')
+
+FINAL_LIBRARY = 'xul'
--- a/ipc/unixsocket/UnixSocket.cpp
+++ b/ipc/unixsocket/UnixSocket.cpp
@@ -11,69 +11,62 @@
 #include <stdlib.h>
 #include <errno.h>
 
 #include <sys/socket.h>
 
 #include "base/eintr_wrapper.h"
 #include "base/message_loop.h"
 
+#include "mozilla/ipc/UnixSocketWatcher.h"
 #include "mozilla/Monitor.h"
 #include "mozilla/FileUtils.h"
 #include "nsString.h"
 #include "nsTArray.h"
 #include "nsXULAppAPI.h"
 
 static const size_t MAX_READ_SIZE = 1 << 16;
 
 #undef CHROMIUM_LOG
 #if defined(MOZ_WIDGET_GONK)
 #include <android/log.h>
-#define CHROMIUM_LOG(args...)  __android_log_print(ANDROID_LOG_INFO, "GonkDBus", args);
+#define CHROMIUM_LOG(args...)  __android_log_print(ANDROID_LOG_INFO, "I/O", args);
 #else
-#define BTDEBUG true
-#define CHROMIUM_LOG(args...) if (BTDEBUG) printf(args);
+#define IODEBUG true
+#define CHROMIUM_LOG(args...) if (IODEBUG) printf(args);
 #endif
 
-static const int SOCKET_RETRY_TIME_MS = 1000;
-
 namespace mozilla {
 namespace ipc {
 
-class UnixSocketImpl : public MessageLoopForIO::Watcher
+class UnixSocketImpl : public UnixSocketWatcher
 {
 public:
-  UnixSocketImpl(UnixSocketConsumer* aConsumer, UnixSocketConnector* aConnector,
-                 const nsACString& aAddress,
-                 SocketConnectionStatus aConnectionStatus)
-    : mConsumer(aConsumer)
-    , mIOLoop(nullptr)
+  UnixSocketImpl(MessageLoop* mIOLoop,
+                 UnixSocketConsumer* aConsumer, UnixSocketConnector* aConnector,
+                 const nsACString& aAddress)
+    : UnixSocketWatcher(mIOLoop)
+    , mConsumer(aConsumer)
     , mConnector(aConnector)
     , mShuttingDownOnIOThread(false)
     , mAddress(aAddress)
     , mDelayedConnectTask(nullptr)
-    , mConnectionStatus(aConnectionStatus)
   {
   }
 
   ~UnixSocketImpl()
   {
     MOZ_ASSERT(NS_IsMainThread());
     MOZ_ASSERT(IsShutdownOnMainThread());
   }
 
   void QueueWriteData(UnixSocketRawData* aData)
   {
     mOutgoingQ.AppendElement(aData);
-    OnFileCanWriteWithoutBlocking(mFd);
-  }
-
-  bool isFdValid()
-  {
-    return mFd > 0;
+    AddWatchers(WRITE_WATCHER, false);
   }
 
   bool IsShutdownOnMainThread()
   {
     MOZ_ASSERT(NS_IsMainThread());
     return mConsumer == nullptr;
   }
 
@@ -89,34 +82,21 @@ public:
     return mShuttingDownOnIOThread;
   }
 
   void ShutdownOnIOThread()
   {
     MOZ_ASSERT(!NS_IsMainThread());
     MOZ_ASSERT(!mShuttingDownOnIOThread);
 
-    mReadWatcher.StopWatchingFileDescriptor();
-    mWriteWatcher.StopWatchingFileDescriptor();
+    RemoveWatchers(READ_WATCHER|WRITE_WATCHER);
 
     mShuttingDownOnIOThread = true;
   }
 
-  void SetUpIO()
-  {
-    MOZ_ASSERT(!mIOLoop);
-    MOZ_ASSERT(mFd >= 0);
-    mIOLoop = MessageLoopForIO::current();
-    mIOLoop->WatchFileDescriptor(mFd,
-                                 true,
-                                 MessageLoopForIO::WATCH_READ,
-                                 &mReadWatcher,
-                                 this);
-  }
-
   void SetDelayedConnectTask(CancelableTask* aTask)
   {
     MOZ_ASSERT(NS_IsMainThread());
     mDelayedConnectTask = aTask;
   }
 
   void ClearDelayedConnectTask()
   {
@@ -140,26 +120,21 @@ public:
   void Connect();
 
   /**
    * Run bind/listen to prepare for further runs of accept()
    */
   void Listen();
 
   /**
-   * Accept an incoming connection
-   */
-  void Accept();
-
-  /**
    * Set up flags on whatever our current file descriptor is.
    *
    * @return true if successful, false otherwise
    */
-  bool SetSocketFlags();
+  bool SetSocketFlags(int aFd);
 
   void GetSocketAddr(nsAString& aAddrStr)
   {
     if (!mConnector) {
       NS_WARNING("No connector to get socket address from!");
       aAddrStr.Truncate();
       return;
     }
@@ -168,64 +143,34 @@ public:
 
   /**
    * Consumer pointer. Non-thread safe RefPtr, so should only be manipulated
    * directly from main thread. All non-main-thread accesses should happen with
    * mImpl as container.
    */
   RefPtr<UnixSocketConsumer> mConsumer;
 
+  void OnAccepted(int aFd) MOZ_OVERRIDE;
+  void OnConnected() MOZ_OVERRIDE;
+  void OnError(const char* aFunction, int aErrno) MOZ_OVERRIDE;
+  void OnListening() MOZ_OVERRIDE;
+  void OnSocketCanReceiveWithoutBlocking() MOZ_OVERRIDE;
+  void OnSocketCanSendWithoutBlocking() MOZ_OVERRIDE;
+
 private:
 
   void FireSocketError();
 
   /**
-   * libevent triggered functions that reads data from socket when available and
-   * guarenteed non-blocking. Only to be called on IO thread.
-   *
-   * @param aFd File descriptor to read from
-   */
-  virtual void OnFileCanReadWithoutBlocking(int aFd);
-
-  /**
-   * libevent or developer triggered functions that writes data to socket when
-   * available and guarenteed non-blocking. Only to be called on IO thread.
-   *
-   * @param aFd File descriptor to read from
-   */
-  virtual void OnFileCanWriteWithoutBlocking(int aFd);
-
-  /**
-   * IO Loop pointer. Must be initalized and called from IO thread only.
-   */
-  MessageLoopForIO* mIOLoop;
-
-  /**
    * Raw data queue. Must be pushed/popped from IO thread only.
    */
   typedef nsTArray<UnixSocketRawData* > UnixSocketRawDataQueue;
   UnixSocketRawDataQueue mOutgoingQ;
 
   /**
-   * Read watcher for libevent. Only to be accessed on IO Thread.
-   */
-  MessageLoopForIO::FileDescriptorWatcher mReadWatcher;
-
-  /**
-   * Write watcher for libevent. Only to be accessed on IO Thread.
-   */
-  MessageLoopForIO::FileDescriptorWatcher mWriteWatcher;
-
-  /**
-   * File descriptor to read from/write to. Connection happens on user provided
-   * thread. Read/write/close happens on IO thread.
-   */
-  ScopedClose mFd;
-
-  /**
    * Connector object used to create the connection we are currently using.
    */
   nsAutoPtr<UnixSocketConnector> mConnector;
 
   /**
    * If true, do not requeue whatever task we're running
    */
   bool mShuttingDownOnIOThread;
@@ -244,22 +189,16 @@ private:
    * Address struct of the socket currently in use
    */
   sockaddr_any mAddr;
 
   /**
    * Task member for delayed connect task. Should only be access on main thread.
    */
   CancelableTask* mDelayedConnectTask;
-
-  /**
-   * Socket connection status. Duplicate from UnixSocketConsumer. Should only
-   * be accessed on I/O thread.
-   */
-  SocketConnectionStatus mConnectionStatus;
 };
 
 template<class T>
 class DeleteInstanceRunnable : public nsRunnable
 {
 public:
   DeleteInstanceRunnable(T* aInstance)
   : mInstance(aInstance)
@@ -398,36 +337,37 @@ public:
     // upper layer
     mImpl->mConsumer->CloseSocket();
     return NS_OK;
   }
 private:
   UnixSocketImpl* mImpl;
 };
 
-class SocketAcceptTask : public CancelableTask {
+class SocketListenTask : public CancelableTask
+{
   virtual void Run();
 
   UnixSocketImpl* mImpl;
 public:
-  SocketAcceptTask(UnixSocketImpl* aImpl) : mImpl(aImpl) { }
+  SocketListenTask(UnixSocketImpl* aImpl) : mImpl(aImpl) { }
 
   virtual void Cancel()
   {
     MOZ_ASSERT(!NS_IsMainThread());
     mImpl = nullptr;
   }
 };
 
-void SocketAcceptTask::Run()
+void SocketListenTask::Run()
 {
   MOZ_ASSERT(!NS_IsMainThread());
 
   if (mImpl) {
-    mImpl->Accept();
+    mImpl->Listen();
   }
 }
 
 class SocketConnectTask : public Task {
   virtual void Run();
 
   UnixSocketImpl* mImpl;
 public:
@@ -473,206 +413,294 @@ public:
   ShutdownSocketTask(UnixSocketImpl* aImpl) : mImpl(aImpl) { }
 };
 
 void ShutdownSocketTask::Run()
 {
   MOZ_ASSERT(!NS_IsMainThread());
 
   // At this point, there should be no new events on the IO thread after this
-  // one with the possible exception of a SocketAcceptTask that
+  // one with the possible exception of a SocketListenTask that
   // ShutdownOnIOThread will cancel for us. We are now fully shut down, so we
   // can send a message to the main thread that will delete mImpl safely knowing
   // that no more tasks reference it.
   mImpl->ShutdownOnIOThread();
 
   nsRefPtr<nsIRunnable> t(new DeleteInstanceRunnable<UnixSocketImpl>(mImpl));
   nsresult rv = NS_DispatchToMainThread(t);
   NS_ENSURE_SUCCESS_VOID(rv);
 }
 
 void
 UnixSocketImpl::FireSocketError()
 {
-  MOZ_ASSERT(!NS_IsMainThread());
+  MOZ_ASSERT(MessageLoopForIO::current() == GetIOLoop());
 
   // Clean up watchers, statuses, fds
-  mReadWatcher.StopWatchingFileDescriptor();
-  mWriteWatcher.StopWatchingFileDescriptor();
-  mConnectionStatus = SOCKET_DISCONNECTED;
-  mFd.reset(-1);
+  Close();
 
   // Tell the main thread we've errored
   nsRefPtr<OnSocketEventTask> t =
     new OnSocketEventTask(this, OnSocketEventTask::CONNECT_ERROR);
   NS_DispatchToMainThread(t);
 }
 
 void
-UnixSocketImpl::Accept()
+UnixSocketImpl::Listen()
 {
-  MOZ_ASSERT(!NS_IsMainThread());
+  MOZ_ASSERT(MessageLoopForIO::current() == GetIOLoop());
   MOZ_ASSERT(mConnector);
 
   // This will set things we don't particularly care about, but it will hand
   // back the correct structure size which is what we do care about.
   if (!mConnector->CreateAddr(true, mAddrSize, mAddr, nullptr)) {
     NS_WARNING("Cannot create socket address!");
     FireSocketError();
     return;
   }
 
-  if (mFd.get() < 0) {
-    mFd = mConnector->Create();
-    if (mFd.get() < 0) {
+  if (!IsOpen()) {
+    int fd = mConnector->Create();
+    if (fd < 0) {
       NS_WARNING("Cannot create socket fd!");
       FireSocketError();
       return;
     }
+    SetFd(fd);
 
-    if (!SetSocketFlags()) {
+    if (!SetSocketFlags(GetFd())) {
       NS_WARNING("Cannot set socket flags!");
       FireSocketError();
       return;
     }
 
-    if (bind(mFd.get(), (struct sockaddr*)&mAddr, mAddrSize)) {
-#ifdef DEBUG
-      CHROMIUM_LOG("...bind(%d) gave errno %d", mFd.get(), errno);
-#endif
-      FireSocketError();
-      return;
-    }
-
-    if (listen(mFd.get(), 1)) {
-#ifdef DEBUG
-      CHROMIUM_LOG("...listen(%d) gave errno %d", mFd.get(), errno);
-#endif
-      FireSocketError();
-      return;
-    }
-
-    if (!mConnector->SetUpListenSocket(mFd)) {
-      NS_WARNING("Could not set up listen socket!");
-      FireSocketError();
-      return;
-    }
-
+    // calls OnListening on success, or OnError otherwise
+    nsresult rv = UnixSocketWatcher::Listen(
+      reinterpret_cast<struct sockaddr*>(&mAddr), mAddrSize);
+    NS_WARN_IF(NS_FAILED(rv));
   }
-
-  SetUpIO();
 }
 
 void
 UnixSocketImpl::Connect()
 {
-  MOZ_ASSERT(!NS_IsMainThread());
+  MOZ_ASSERT(MessageLoopForIO::current() == GetIOLoop());
   MOZ_ASSERT(mConnector);
 
-  if (mFd.get() < 0) {
-    mFd = mConnector->Create();
-    if (mFd.get() < 0) {
+  if (!IsOpen()) {
+    int fd = mConnector->Create();
+    if (fd < 0) {
       NS_WARNING("Cannot create socket fd!");
       FireSocketError();
       return;
     }
+    SetFd(fd);
   }
 
-  int ret;
-
   if (!mConnector->CreateAddr(false, mAddrSize, mAddr, mAddress.get())) {
     NS_WARNING("Cannot create socket address!");
     FireSocketError();
     return;
   }
 
-  // Select non-blocking IO.
-  if (-1 == fcntl(mFd.get(), F_SETFL, O_NONBLOCK)) {
-    NS_WARNING("Cannot set nonblock!");
-    FireSocketError();
+  // calls OnConnected() on success, or OnError() otherwise
+  nsresult rv = UnixSocketWatcher::Connect(
+    reinterpret_cast<struct sockaddr*>(&mAddr), mAddrSize);
+  NS_WARN_IF(NS_FAILED(rv));
+}
+
+bool
+UnixSocketImpl::SetSocketFlags(int aFd)
+{
+  // Set socket addr to be reused even if kernel is still waiting to close
+  int n = 1;
+  setsockopt(aFd, SOL_SOCKET, SO_REUSEADDR, &n, sizeof(n));
+
+  // Set close-on-exec bit.
+  int flags = fcntl(aFd, F_GETFD);
+  if (-1 == flags) {
+    return false;
+  }
+
+  flags |= FD_CLOEXEC;
+  if (-1 == fcntl(aFd, F_SETFD, flags)) {
+    return false;
+  }
+
+  return true;
+}
+
+void
+UnixSocketImpl::OnAccepted(int aFd)
+{
+  MOZ_ASSERT(MessageLoopForIO::current() == GetIOLoop());
+  MOZ_ASSERT(GetConnectionStatus() == SOCKET_IS_LISTENING);
+
+  if (!mConnector->SetUp(aFd)) {
+    NS_WARNING("Could not set up socket!");
     return;
   }
 
-  ret = connect(mFd.get(), (struct sockaddr*)&mAddr, mAddrSize);
-
-  if (ret) {
-    if (errno == EINPROGRESS) {
-      // Select blocking IO again, since we've now at least queue'd the connect
-      // as nonblock.
-      int current_opts = fcntl(mFd.get(), F_GETFL, 0);
-      if (-1 == current_opts) {
-        NS_WARNING("Cannot get socket opts!");
-        FireSocketError();
-        return;
-      }
-      if (-1 == fcntl(mFd.get(), F_SETFL, current_opts & ~O_NONBLOCK)) {
-        NS_WARNING("Cannot set socket opts to blocking!");
-        FireSocketError();
-        return;
-      }
-
-      // Set up a write watch to make sure we receive the connect signal
-      MessageLoopForIO::current()->WatchFileDescriptor(
-        mFd.get(),
-        false,
-        MessageLoopForIO::WATCH_WRITE,
-        &mWriteWatcher,
-        this);
-
-#ifdef DEBUG
-      CHROMIUM_LOG("UnixSocket Connection delayed!");
-#endif
-      return;
-    }
-#if DEBUG
-    CHROMIUM_LOG("Socket connect errno=%d\n", errno);
-#endif
-    FireSocketError();
+  RemoveWatchers(READ_WATCHER|WRITE_WATCHER);
+  Close();
+  SetSocket(aFd, SOCKET_IS_CONNECTED);
+  if (!SetSocketFlags(GetFd())) {
     return;
   }
 
-  if (!SetSocketFlags()) {
+  nsRefPtr<OnSocketEventTask> t =
+    new OnSocketEventTask(this, OnSocketEventTask::CONNECT_SUCCESS);
+  NS_DispatchToMainThread(t);
+
+  AddWatchers(READ_WATCHER, true);
+  if (!mOutgoingQ.IsEmpty()) {
+    AddWatchers(WRITE_WATCHER, false);
+  }
+}
+
+void
+UnixSocketImpl::OnConnected()
+{
+  MOZ_ASSERT(MessageLoopForIO::current() == GetIOLoop());
+  MOZ_ASSERT(GetConnectionStatus() == SOCKET_IS_CONNECTED);
+
+  if (!SetSocketFlags(GetFd())) {
     NS_WARNING("Cannot set socket flags!");
     FireSocketError();
     return;
   }
 
-  if (!mConnector->SetUp(mFd)) {
+  if (!mConnector->SetUp(GetFd())) {
     NS_WARNING("Could not set up socket!");
     FireSocketError();
     return;
   }
 
   nsRefPtr<OnSocketEventTask> t =
     new OnSocketEventTask(this, OnSocketEventTask::CONNECT_SUCCESS);
   NS_DispatchToMainThread(t);
-  mConnectionStatus = SOCKET_CONNECTED;
+
+  AddWatchers(READ_WATCHER, true);
+  if (!mOutgoingQ.IsEmpty()) {
+    AddWatchers(WRITE_WATCHER, false);
+  }
+}
+
+void
+UnixSocketImpl::OnListening()
+{
+  MOZ_ASSERT(MessageLoopForIO::current() == GetIOLoop());
+  MOZ_ASSERT(GetConnectionStatus() == SOCKET_IS_LISTENING);
 
-  SetUpIO();
+  if (!mConnector->SetUpListenSocket(GetFd())) {
+    NS_WARNING("Could not set up listen socket!");
+    FireSocketError();
+    return;
+  }
+
+  AddWatchers(READ_WATCHER, true);
+}
+
+void
+UnixSocketImpl::OnError(const char* aFunction, int aErrno)
+{
+  MOZ_ASSERT(MessageLoopForIO::current() == GetIOLoop());
+
+  UnixFdWatcher::OnError(aFunction, aErrno);
+  FireSocketError();
 }
 
-bool
-UnixSocketImpl::SetSocketFlags()
+void
+UnixSocketImpl::OnSocketCanReceiveWithoutBlocking()
 {
-  // Set socket addr to be reused even if kernel is still waiting to close
-  int n = 1;
-  setsockopt(mFd, SOL_SOCKET, SO_REUSEADDR, &n, sizeof(n));
+  MOZ_ASSERT(MessageLoopForIO::current() == GetIOLoop());
+  MOZ_ASSERT(GetConnectionStatus() == SOCKET_IS_CONNECTED);
+
+  // Read all of the incoming data.
+  while (true) {
+    nsAutoPtr<UnixSocketRawData> incoming(new UnixSocketRawData(MAX_READ_SIZE));
+
+    ssize_t ret = read(GetFd(), incoming->mData, incoming->mSize);
+    if (ret <= 0) {
+      if (ret == -1) {
+        if (errno == EINTR) {
+          continue; // retry system call when interrupted
+        }
+        if (errno == EAGAIN || errno == EWOULDBLOCK) {
+          return; // no data available: return and re-poll
+        }
+
+#ifdef DEBUG
+        NS_WARNING("Cannot read from network");
+#endif
+        // else fall through to error handling on other errno's
+      }
+
+      // We're done with our descriptors. Ensure that spurious events don't
+      // cause us to end up back here.
+      RemoveWatchers(READ_WATCHER|WRITE_WATCHER);
+      nsRefPtr<RequestClosingSocketTask> t = new RequestClosingSocketTask(this);
+      NS_DispatchToMainThread(t);
+      return;
+    }
+
+    incoming->mSize = ret;
+    nsRefPtr<SocketReceiveTask> t =
+      new SocketReceiveTask(this, incoming.forget());
+    NS_DispatchToMainThread(t);
 
-  // Set close-on-exec bit.
-  int flags = fcntl(mFd, F_GETFD);
-  if (-1 == flags) {
-    return false;
+    // If ret is less than MAX_READ_SIZE, there's no
+    // more data in the socket for us to read now.
+    if (ret < ssize_t(MAX_READ_SIZE)) {
+      return;
+    }
   }
+}
+
+void
+UnixSocketImpl::OnSocketCanSendWithoutBlocking()
+{
+  MOZ_ASSERT(MessageLoopForIO::current() == GetIOLoop());
+  MOZ_ASSERT(GetConnectionStatus() == SOCKET_IS_CONNECTED);
 
-  flags |= FD_CLOEXEC;
-  if (-1 == fcntl(mFd, F_SETFD, flags)) {
-    return false;
+  // Try to write the bytes of mCurrentRilRawData.  If all were written, continue.
+  //
+  // Otherwise, save the byte position of the next byte to write
+  // within mCurrentWriteOffset, and request another write when the
+  // system won't block.
+  //
+  while (true) {
+    UnixSocketRawData* data;
+    if (mOutgoingQ.IsEmpty()) {
+      return;
+    }
+    data = mOutgoingQ.ElementAt(0);
+    const uint8_t *toWrite;
+    toWrite = data->mData;
+
+    while (data->mCurrentWriteOffset < data->mSize) {
+      ssize_t write_amount = data->mSize - data->mCurrentWriteOffset;
+      ssize_t written;
+      written = write (GetFd(), toWrite + data->mCurrentWriteOffset,
+                         write_amount);
+      if (written > 0) {
+        data->mCurrentWriteOffset += written;
+      }
+      if (written != write_amount) {
+        break;
+      }
+    }
+
+    if (data->mCurrentWriteOffset != data->mSize) {
+      AddWatchers(WRITE_WATCHER, false);
+      return;
+    }
+    mOutgoingQ.RemoveElementAt(0);
+    delete data;
   }
-
-  return true;
 }
 
 UnixSocketConsumer::UnixSocketConsumer() : mImpl(nullptr)
                                          , mConnectionStatus(SOCKET_DISCONNECTED)
                                          , mConnectTimestamp(0)
                                          , mConnectDelayMs(0)
 {
 }
@@ -733,176 +761,16 @@ UnixSocketConsumer::CloseSocket()
                                    new ShutdownSocketTask(mImpl));
 
   mImpl = nullptr;
 
   NotifyDisconnect();
 }
 
 void
-UnixSocketImpl::OnFileCanReadWithoutBlocking(int aFd)
-{
-  MOZ_ASSERT(!NS_IsMainThread());
-  MOZ_ASSERT(!mShuttingDownOnIOThread);
-
-  if (mConnectionStatus == SOCKET_CONNECTED) {
-    // Read all of the incoming data.
-    while (true) {
-      nsAutoPtr<UnixSocketRawData> incoming(new UnixSocketRawData(MAX_READ_SIZE));
-
-      ssize_t ret = read(aFd, incoming->mData, incoming->mSize);
-      if (ret <= 0) {
-        if (ret == -1) {
-          if (errno == EINTR) {
-            continue; // retry system call when interrupted
-          }
-          if (errno == EAGAIN || errno == EWOULDBLOCK) {
-            return; // no data available: return and re-poll
-          }
-
-#ifdef DEBUG
-          NS_WARNING("Cannot read from network");
-#endif
-          // else fall through to error handling on other errno's
-        }
-
-        // We're done with our descriptors. Ensure that spurious events don't
-        // cause us to end up back here.
-        mReadWatcher.StopWatchingFileDescriptor();
-        mWriteWatcher.StopWatchingFileDescriptor();
-        nsRefPtr<RequestClosingSocketTask> t = new RequestClosingSocketTask(this);
-        NS_DispatchToMainThread(t);
-        return;
-      }
-
-      incoming->mSize = ret;
-      nsRefPtr<SocketReceiveTask> t =
-        new SocketReceiveTask(this, incoming.forget());
-      NS_DispatchToMainThread(t);
-
-      // If ret is less than MAX_READ_SIZE, there's no
-      // more data in the socket for us to read now.
-      if (ret < ssize_t(MAX_READ_SIZE)) {
-        return;
-      }
-    }
-
-    MOZ_CRASH("We returned early");
-  } else if (mConnectionStatus == SOCKET_LISTENING) {
-    int client_fd = accept(mFd.get(), (struct sockaddr*)&mAddr, &mAddrSize);
-
-    if (client_fd < 0) {
-      return;
-    }
-
-    if (!mConnector->SetUp(client_fd)) {
-      NS_WARNING("Could not set up socket!");
-      return;
-    }
-
-    mReadWatcher.StopWatchingFileDescriptor();
-    mWriteWatcher.StopWatchingFileDescriptor();
-
-    mFd.reset(client_fd);
-    if (!SetSocketFlags()) {
-      return;
-    }
-
-    mIOLoop = nullptr;
-
-    nsRefPtr<OnSocketEventTask> t =
-      new OnSocketEventTask(this, OnSocketEventTask::CONNECT_SUCCESS);
-    NS_DispatchToMainThread(t);
-    mConnectionStatus = SOCKET_CONNECTED;
-
-    SetUpIO();
-  }
-}
-
-void
-UnixSocketImpl::OnFileCanWriteWithoutBlocking(int aFd)
-{
-  MOZ_ASSERT(!NS_IsMainThread());
-  MOZ_ASSERT(!mShuttingDownOnIOThread);
-
-  MOZ_ASSERT(aFd >= 0);
-  if (mConnectionStatus == SOCKET_CONNECTED) {
-    // Try to write the bytes of mCurrentRilRawData.  If all were written, continue.
-    //
-    // Otherwise, save the byte position of the next byte to write
-    // within mCurrentWriteOffset, and request another write when the
-    // system won't block.
-    //
-    while (true) {
-      UnixSocketRawData* data;
-      if (mOutgoingQ.IsEmpty()) {
-        return;
-      }
-      data = mOutgoingQ.ElementAt(0);
-      const uint8_t *toWrite;
-      toWrite = data->mData;
-
-      while (data->mCurrentWriteOffset < data->mSize) {
-        ssize_t write_amount = data->mSize - data->mCurrentWriteOffset;
-        ssize_t written;
-        written = write (aFd, toWrite + data->mCurrentWriteOffset,
-                         write_amount);
-        if (written > 0) {
-          data->mCurrentWriteOffset += written;
-        }
-        if (written != write_amount) {
-          break;
-        }
-      }
-
-      if (data->mCurrentWriteOffset != data->mSize) {
-        MessageLoopForIO::current()->WatchFileDescriptor(
-          aFd,
-          false,
-          MessageLoopForIO::WATCH_WRITE,
-          &mWriteWatcher,
-          this);
-        return;
-      }
-      mOutgoingQ.RemoveElementAt(0);
-      delete data;
-    }
-  } else if (mConnectionStatus == SOCKET_CONNECTING) {
-    int error, ret;
-    socklen_t len = sizeof(error);
-    ret = getsockopt(mFd.get(), SOL_SOCKET, SO_ERROR, &error, &len);
-
-    if (ret || error) {
-      NS_WARNING("getsockopt failure on async socket connect!");
-      FireSocketError();
-      return;
-    }
-
-    if (!SetSocketFlags()) {
-      NS_WARNING("Cannot set socket flags!");
-      FireSocketError();
-      return;
-    }
-
-    if (!mConnector->SetUp(mFd)) {
-      NS_WARNING("Could not set up socket!");
-      FireSocketError();
-      return;
-    }
-
-    nsRefPtr<OnSocketEventTask> t =
-      new OnSocketEventTask(this, OnSocketEventTask::CONNECT_SUCCESS);
-    NS_DispatchToMainThread(t);
-    mConnectionStatus = SOCKET_CONNECTED;
-
-    SetUpIO();
-  }
-}
-
-void
 UnixSocketConsumer::GetSocketAddr(nsAString& aAddrStr)
 {
   aAddrStr.Truncate();
   if (!mImpl || mConnectionStatus != SOCKET_CONNECTED) {
     NS_WARNING("No socket currently open!");
     return;
   }
   mImpl->GetSocketAddr(aAddrStr);
@@ -946,18 +814,18 @@ UnixSocketConsumer::ConnectSocket(UnixSo
   nsAutoPtr<UnixSocketConnector> connector(aConnector);
 
   if (mImpl) {
     NS_WARNING("Socket already connecting/connected!");
     return false;
   }
 
   nsCString addr(aAddress);
-  mImpl = new UnixSocketImpl(this, connector.forget(), addr, SOCKET_CONNECTING);
   MessageLoop* ioLoop = XRE_GetIOMessageLoop();
+  mImpl = new UnixSocketImpl(ioLoop, this, connector.forget(), addr);
   mConnectionStatus = SOCKET_CONNECTING;
   if (aDelayMs > 0) {
     SocketDelayedConnectTask* connectTask = new SocketDelayedConnectTask(mImpl);
     mImpl->SetDelayedConnectTask(connectTask);
     MessageLoop::current()->PostDelayedTask(FROM_HERE, connectTask, aDelayMs);
   } else {
     ioLoop->PostTask(FROM_HERE, new SocketConnectTask(mImpl));
   }
@@ -972,21 +840,21 @@ UnixSocketConsumer::ListenSocket(UnixSoc
 
   nsAutoPtr<UnixSocketConnector> connector(aConnector);
 
   if (mImpl) {
     NS_WARNING("Socket already connecting/connected!");
     return false;
   }
 
-  mImpl = new UnixSocketImpl(this, connector.forget(), EmptyCString(),
-                             SOCKET_LISTENING);
+  mImpl = new UnixSocketImpl(XRE_GetIOMessageLoop(), this, connector.forget(),
+                             EmptyCString());
   mConnectionStatus = SOCKET_LISTENING;
   XRE_GetIOMessageLoop()->PostTask(FROM_HERE,
-                                   new SocketAcceptTask(mImpl));
+                                   new SocketListenTask(mImpl));
   return true;
 }
 
 uint32_t
 UnixSocketConsumer::CalculateConnectDelayMs() const
 {
   MOZ_ASSERT(NS_IsMainThread());
 
--- a/js/src/builtin/Object.cpp
+++ b/js/src/builtin/Object.cpp
@@ -651,31 +651,31 @@ obj_hasOwnProperty(JSContext *cx, unsign
         return false;
 
     /* Step 2. */
     RootedObject obj(cx, ToObject(cx, args.thisv()));
     if (!obj)
         return false;
 
     /* Non-standard code for proxies. */
-    RootedObject obj2(cx);
-    RootedShape prop(cx);
     if (obj->is<ProxyObject>()) {
         bool has;
         if (!Proxy::hasOwn(cx, obj, idRoot, &has))
             return false;
         args.rval().setBoolean(has);
         return true;
     }
 
     /* Step 3. */
-    if (!HasOwnProperty<CanGC>(cx, obj->getOps()->lookupGeneric, obj, idRoot, &obj2, &prop))
+    bool found;
+    if (!HasOwnProperty(cx, obj, idRoot, &found))
         return false;
+
     /* Step 4,5. */
-    args.rval().setBoolean(!!prop);
+    args.rval().setBoolean(found);
     return true;
 }
 
 /* ES5 15.2.4.6. */
 static bool
 obj_isPrototypeOf(JSContext *cx, unsigned argc, Value *vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
--- a/js/src/frontend/Parser.cpp
+++ b/js/src/frontend/Parser.cpp
@@ -6424,18 +6424,20 @@ Parser<ParseHandler>::assignExprWithoutY
     }
     return res;
 }
 
 template <typename ParseHandler>
 bool
 Parser<ParseHandler>::argumentList(Node listNode, bool *isSpread)
 {
-    if (tokenStream.matchToken(TOK_RP, TokenStream::Operand))
+    if (tokenStream.matchToken(TOK_RP, TokenStream::Operand)) {
+        handler.setEndPosition(listNode, pos().end);
         return true;
+    }
 
     uint32_t startYieldOffset = pc->lastYieldOffset;
     bool arg0 = true;
 
     do {
         bool spread = false;
         uint32_t begin = 0;
         if (tokenStream.matchToken(TOK_TRIPLEDOT, TokenStream::Operand)) {
@@ -6478,16 +6480,17 @@ Parser<ParseHandler>::argumentList(Node 
 
         handler.addList(listNode, argNode);
     } while (tokenStream.matchToken(TOK_COMMA));
 
     if (tokenStream.getToken() != TOK_RP) {
         report(ParseError, false, null(), JSMSG_PAREN_AFTER_ARGS);
         return false;
     }
+    handler.setEndPosition(listNode, pos().end);
     return true;
 }
 
 template <typename ParseHandler>
 typename ParseHandler::Node
 Parser<ParseHandler>::memberExpr(TokenKind tt, bool allowCallSyntax)
 {
     JS_ASSERT(tokenStream.isCurrentTokenType(tt));
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/debug/bug973566.js
@@ -0,0 +1,7 @@
+Object.prototype[1] = 'peek';
+var g = newGlobal();
+var dbg = Debugger(g);
+dbg.onEnterFrame = function (frame) {
+    var lines = frame.script.getAllOffsets();
+};
+g.eval("1;");
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/ion/bug901086.js
@@ -0,0 +1,15 @@
+enableSPSProfilingAssertions(false);
+function foo(obj,x,y,z) {
+    if (!y)
+	assertEq(0, 1);
+    obj.x = x;
+    return y + z;
+}
+function bar() {
+    var objz = {x:2}
+    for(var i = 0; i < 1100; i++) {
+	foo(objz,1,2,3);
+	foo(objz, false, "bar", "foo");
+    }
+}
+bar();
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/ion/inlining/TypedObject-storage-opaque.js
@@ -0,0 +1,33 @@
+/* -*- Mode: C++; tab-width: 8; 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/. */
+
+/* Used to verify that the JIT resolves the transparent/opaque type
+ * tests internal to storage().
+ *
+ * In this case the argument type is always an opaque object, so
+ * ObjectIsOpaqueTypedObject resolves to true and
+ * ObjectIsTransparentTypedObject resolves to false.
+ *
+ * Load this into the js shell with IONFLAGS=logs, then exit and run
+ * iongraph.  func01 will likely be the one we want (look for calls to
+ * ObjectIsOpaqueTypedObject and ObjectIsTransparentTypedObject in the
+ * graph for pass00).
+ */
+
+var T = TypedObject;
+
+function check(v) {
+    return T.storage(v);
+}
+
+function test() {
+    var AT = new T.ArrayType(T.Any,10);
+    var v = new AT(10);
+    for ( var i=0 ; i < 1000 ; i++ )
+        check(v);
+    return check(v);
+}
+
+test();
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/ion/inlining/TypedObject-storage-transparent.js
@@ -0,0 +1,33 @@
+/* -*- Mode: C++; tab-width: 8; 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/. */
+
+/* Used to verify that the JIT resolves the transparent/opaque type
+ * tests internal to storage().
+ *
+ * In this case the argument type is always a transparent object, so
+ * ObjectIsOpaqueTypedObject resolves to false and
+ * ObjectIsTransparentTypedObject resolves to true.
+ *
+ * Load this into the js shell with IONFLAGS=logs, then exit and run
+ * iongraph.  func01 will likely be the one we want (look for calls to
+ * ObjectIsOpaqueTypedObject and ObjectIsTransparentTypedObject in the
+ * graph for pass00).
+ */
+
+var T = TypedObject;
+
+function check(v) {
+    return T.storage(v);
+}
+
+function test() {
+    var AT = new T.ArrayType(T.int32,10);
+    var v = new AT(10);
+    for ( var i=0 ; i < 1000 ; i++ )
+        check(v);
+    return check(v);
+}
+
+test();
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/ion/inlining/TypedObject-storage-unknown.js
@@ -0,0 +1,36 @@
+/* -*- Mode: C++; tab-width: 8; 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/. */
+
+/* Used to verify that the JIT resolves the transparent/opaque type
+ * tests internal to storage().
+ *
+ * In this case the argument type is variable and thus unknown to the
+ * JIT, so both ObjectIsOpaqueTypedObject and
+ * ObjectIsTransparentTypedObject are resolved as uses of the
+ * "HasClass" primitive.
+ *
+ * Load this into the js shell with IONFLAGS=logs, then exit and run
+ * iongraph.  func01 will likely be the one we want (look for calls to
+ * ObjectIsOpaqueTypedObject and ObjectIsTransparentTypedObject in the
+ * graph for pass00).
+ */
+
+var T = TypedObject;
+
+function check(v) {
+    return T.storage(v);
+}
+
+function test() {
+    var AT = new T.ArrayType(T.int32,10);
+    var v = new Object;         // Not actually a typed object
+    var w = new AT(10);         // Actually a typed object
+    var a = [v,w];
+    for ( var i=0 ; i < 1000 ; i++ )
+        try { check(a[i%2]); } catch (e) {}
+    try { return check(a[1]); } catch (e) {}
+}
+
+test();
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/ion/inlining/TypedObject-storage-wrong.js
@@ -0,0 +1,32 @@
+/* -*- Mode: C++; tab-width: 8; 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/. */
+
+/* Used to verify that the JIT resolves the transparent/opaque type
+ * tests internal to storage().
+ *
+ * In this case the argument type is always a non-TypedObject, so both
+ * ObjectIsOpaqueTypedObject and ObjectIsTransparentTypedObject
+ * resolve to false.
+ *
+ * Load this into the js shell with IONFLAGS=logs, then exit and run
+ * iongraph.  func01 will likely be the one we want (look for calls to
+ * ObjectIsOpaqueTypedObject and ObjectIsTransparentTypedObject in the
+ * graph for pass00).
+ */
+
+var T = TypedObject;
+
+function check(v) {
+    return T.storage(v);
+}
+
+function test() {
+    var v = new Object;         // Not actually a typed object
+    for ( var i=0 ; i < 1000 ; i++ )
+        try { check(v); } catch (e) {}
+    try { return check(v); } catch (e) {}
+}
+
+test();
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/parser/bug-975484.js
@@ -0,0 +1,7 @@
+var loc = Reflect.parse("f()").body[0].expression.loc;
+assertEq(loc.start.column, 0);
+assertEq(loc.end.column, 3);
+
+loc = Reflect.parse("f(x)").body[0].expression.loc;
+assertEq(loc.start.column, 0);
+assertEq(loc.end.column, 4);
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/xdr/scope.js
@@ -0,0 +1,19 @@
+load(libdir + 'bytecode-cache.js');
+var test = "";
+
+// code a function which has both used and unused inner functions.
+test  = (function () {
+  function f() {
+    var x = 3;
+    (function() {
+      with(obj) {
+        (function() {
+          assertEq(x, 2);
+        })();
+      }
+    })();
+  };
+
+  return "var obj = { x : 2 };" + f.toSource() + "; f()";
+})();
+evalWithCache(test, { assertEqBytecode: true, assertEqResult : true });
--- a/js/src/jit/CodeGenerator.cpp
+++ b/js/src/jit/CodeGenerator.cpp
@@ -8006,16 +8006,29 @@ CodeGenerator::visitHaveSameClass(LHaveS
     masm.loadObjClass(rhs, output);
     masm.cmpPtr(temp, output);
     masm.emitSet(Assembler::Equal, output);
 
     return true;
 }
 
 bool
+CodeGenerator::visitHasClass(LHasClass *ins)
+{
+    Register lhs = ToRegister(ins->lhs());
+    Register output = ToRegister(ins->output());
+
+    masm.loadObjClass(lhs, output);
+    masm.cmpPtr(output, ImmPtr(ins->mir()->getClass()));
+    masm.emitSet(Assembler::Equal, output);
+
+    return true;
+}
+
+bool
 CodeGenerator::visitAsmJSCall(LAsmJSCall *ins)
 {
     MAsmJSCall *mir = ins->mir();
 
 #if defined(JS_CODEGEN_ARM)
     if (!useHardFpABI() && mir->callee().which() == MAsmJSCall::Callee::Builtin) {
         for (unsigned i = 0, e = ins->numOperands(); i < e; i++) {
             LAllocation *a = ins->getOperand(i);
--- a/js/src/jit/CodeGenerator.h
+++ b/js/src/jit/CodeGenerator.h
@@ -275,16 +275,17 @@ class CodeGenerator : public CodeGenerat
     bool visitFunctionBoundary(LFunctionBoundary *lir);
     bool visitGetDOMProperty(LGetDOMProperty *lir);
     bool visitGetDOMMember(LGetDOMMember *lir);
     bool visitSetDOMProperty(LSetDOMProperty *lir);
     bool visitCallDOMNative(LCallDOMNative *lir);
     bool visitCallGetIntrinsicValue(LCallGetIntrinsicValue *lir);
     bool visitIsCallable(LIsCallable *lir);
     bool visitHaveSameClass(LHaveSameClass *lir);
+    bool visitHasClass(LHasClass *lir);
     bool visitAsmJSCall(LAsmJSCall *lir);
     bool visitAsmJSParameter(LAsmJSParameter *lir);
     bool visitAsmJSReturn(LAsmJSReturn *ret);
     bool visitAsmJSVoidReturn(LAsmJSVoidReturn *ret);
 
     bool visitCheckOverRecursed(LCheckOverRecursed *lir);
     bool visitCheckOverRecursedFailure(CheckOverRecursedFailure *ool);
     bool visitAsmJSCheckOverRecursed(LAsmJSCheckOverRecursed *lir);
--- a/js/src/jit/IonBuilder.h
+++ b/js/src/jit/IonBuilder.h
@@ -674,16 +674,17 @@ class IonBuilder : public MIRGenerator
     InliningStatus inlineUnsafeSetReservedSlot(CallInfo &callInfo);
     InliningStatus inlineUnsafeGetReservedSlot(CallInfo &callInfo);
 
     // Utility intrinsics.
     InliningStatus inlineIsCallable(CallInfo &callInfo);
     InliningStatus inlineHaveSameClass(CallInfo &callInfo);
     InliningStatus inlineToObject(CallInfo &callInfo);
     InliningStatus inlineDump(CallInfo &callInfo);
+    InliningStatus inlineHasClass(CallInfo &callInfo, const Class *clasp);
 
     // Testing functions.
     InliningStatus inlineForceSequentialOrInParallelSection(CallInfo &callInfo);
     InliningStatus inlineBailout(CallInfo &callInfo);
     InliningStatus inlineAssertFloat32(CallInfo &callInfo);
 
     // Main inlining functions
     InliningStatus inlineNativeCall(CallInfo &callInfo, JSNative native);
--- a/js/src/jit/LIR-Common.h
+++ b/js/src/jit/LIR-Common.h
@@ -5638,16 +5638,32 @@ class LHaveSameClass : public LInstructi
     const LAllocation *rhs() {
         return getOperand(1);
     }
     MHaveSameClass *mir() const {
         return mir_->toHaveSameClass();
     }
 };
 
+class LHasClass : public LInstructionHelper<1, 1, 0>
+{
+  public:
+    LIR_HEADER(HasClass);
+    LHasClass(const LAllocation &lhs) {
+        setOperand(0, lhs);
+    }
+
+    const LAllocation *lhs() {
+        return getOperand(0);
+    }
+    MHasClass *mir() const {
+        return mir_->toHasClass();
+    }
+};
+
 class LAsmJSLoadHeap : public LInstructionHelper<1, 1, 0>
 {
   public:
     LIR_HEADER(AsmJSLoadHeap);
     LAsmJSLoadHeap(const LAllocation &ptr) {
         setOperand(0, ptr);
     }
     MAsmJSLoadHeap *mir() const {
--- a/js/src/jit/LOpcodes.h
+++ b/js/src/jit/LOpcodes.h
@@ -270,16 +270,17 @@
     _(InterruptCheckImplicit)       \
     _(FunctionBoundary)             \
     _(GetDOMProperty)               \
     _(GetDOMMember)                 \
     _(SetDOMProperty)               \
     _(CallDOMNative)                \
     _(IsCallable)                   \
     _(HaveSameClass)                \
+    _(HasClass)                      \
     _(AsmJSLoadHeap)                \
     _(AsmJSStoreHeap)               \
     _(AsmJSLoadGlobalVar)           \
     _(AsmJSStoreGlobalVar)          \
     _(AsmJSLoadFFIFunc)             \
     _(AsmJSParameter)               \
     _(AsmJSReturn)                  \
     _(AsmJSVoidReturn)              \
--- a/js/src/jit/LinearScan.cpp
+++ b/js/src/jit/LinearScan.cpp
@@ -1074,17 +1074,17 @@ LinearScanAllocator::findBestBlockedRegi
     for (RegisterSet regs(allRegisters_); !regs.empty(needFloat); ) {
         AnyRegister reg = regs.takeAny(needFloat);
         nextUsePos[reg.code()] = CodePosition::MAX;
     }
     for (IntervalIterator i(active.begin()); i != active.end(); i++) {
         LAllocation *alloc = i->getAllocation();
         if (alloc->isRegister(needFloat)) {
             AnyRegister reg = alloc->toRegister();
-            if (i->start().ins() == current->start().ins()) {
+            if (i->start() == current->start()) {
                 nextUsePos[reg.code()] = CodePosition::MIN;
                 IonSpew(IonSpew_RegAlloc, "   Disqualifying %s due to recency", reg.name());
             } else if (nextUsePos[reg.code()] != CodePosition::MIN) {
                 nextUsePos[reg.code()] = i->nextUsePosAfter(current->start());
                 IonSpew(IonSpew_RegAlloc, "   Register %s next used %u", reg.name(),
                         nextUsePos[reg.code()].pos());
             }
         }
--- a/js/src/jit/Lowering.cpp
+++ b/js/src/jit/Lowering.cpp
@@ -3326,16 +3326,24 @@ LIRGenerator::visitHaveSameClass(MHaveSa
 
     JS_ASSERT(lhs->type() == MIRType_Object);
     JS_ASSERT(rhs->type() == MIRType_Object);
 
     return define(new(alloc()) LHaveSameClass(useRegister(lhs), useRegister(rhs), temp()), ins);
 }
 
 bool
+LIRGenerator::visitHasClass(MHasClass *ins)
+{
+    JS_ASSERT(ins->object()->type() == MIRType_Object);
+    JS_ASSERT(ins->type() == MIRType_Boolean);
+    return define(new(alloc()) LHasClass(useRegister(ins->object())), ins);
+}
+
+bool
 LIRGenerator::visitAsmJSLoadGlobalVar(MAsmJSLoadGlobalVar *ins)
 {
     return define(new(alloc()) LAsmJSLoadGlobalVar, ins);
 }
 
 bool
 LIRGenerator::visitAsmJSStoreGlobalVar(MAsmJSStoreGlobalVar *ins)
 {
--- a/js/src/jit/Lowering.h
+++ b/js/src/jit/Lowering.h
@@ -232,16 +232,17 @@ class LIRGenerator : public LIRGenerator
     bool visitThrow(MThrow *ins);
     bool visitIn(MIn *ins);
     bool visitInArray(MInArray *ins);
     bool visitInstanceOf(MInstanceOf *ins);
     bool visitCallInstanceOf(MCallInstanceOf *ins);
     bool visitFunctionBoundary(MFunctionBoundary *ins);
     bool visitIsCallable(MIsCallable *ins);
     bool visitHaveSameClass(MHaveSameClass *ins);
+    bool visitHasClass(MHasClass *ins);
     bool visitAsmJSLoadGlobalVar(MAsmJSLoadGlobalVar *ins);
     bool visitAsmJSStoreGlobalVar(MAsmJSStoreGlobalVar *ins);
     bool visitAsmJSLoadFFIFunc(MAsmJSLoadFFIFunc *ins);
     bool visitAsmJSParameter(MAsmJSParameter *ins);
     bool visitAsmJSReturn(MAsmJSReturn *ins);
     bool visitAsmJSVoidReturn(MAsmJSVoidReturn *ins);
     bool visitAsmJSPassStackArg(MAsmJSPassStackArg *ins);
     bool visitAsmJSCall(MAsmJSCall *ins);
--- a/js/src/jit/MCallOptimize.cpp
+++ b/js/src/jit/MCallOptimize.cpp
@@ -150,16 +150,22 @@ IonBuilder::inlineNativeCall(CallInfo &c
     // Utility intrinsics.
     if (native == intrinsic_IsCallable)
         return inlineIsCallable(callInfo);
     if (native == intrinsic_HaveSameClass)
         return inlineHaveSameClass(callInfo);
     if (native == intrinsic_ToObject)
         return inlineToObject(callInfo);
 
+    // TypedObject intrinsics.
+    if (native == intrinsic_ObjectIsTransparentTypedObject)
+        return inlineHasClass(callInfo, &TransparentTypedObject::class_);
+    if (native == intrinsic_ObjectIsOpaqueTypedObject)
+        return inlineHasClass(callInfo, &OpaqueTypedObject::class_);
+
     // Testing Functions
     if (native == testingFunc_inParallelSection)
         return inlineForceSequentialOrInParallelSection(callInfo);
     if (native == testingFunc_bailout)
         return inlineBailout(callInfo);
     if (native == testingFunc_assertFloat32)
         return inlineAssertFloat32(callInfo);
 
@@ -1437,16 +1443,41 @@ IonBuilder::inlineNewDenseArrayForParall
                                                           templateObject);
     current->add(newObject);
     current->push(newObject);
 
     return InliningStatus_Inlined;
 }
 
 IonBuilder::InliningStatus
+IonBuilder::inlineHasClass(CallInfo &callInfo, const Class *clasp)
+{
+    if (callInfo.constructing() || callInfo.argc() != 1)
+        return InliningStatus_NotInlined;
+
+    if (callInfo.getArg(0)->type() != MIRType_Object)
+        return InliningStatus_NotInlined;
+    if (getInlineReturnType() != MIRType_Boolean)
+        return InliningStatus_NotInlined;
+
+    types::TemporaryTypeSet *types = callInfo.getArg(0)->resultTypeSet();
+    const Class *knownClass = types ? types->getKnownClass() : nullptr;
+    if (knownClass) {
+        pushConstant(BooleanValue(knownClass == clasp));
+    } else {
+        MHasClass *hasClass = MHasClass::New(alloc(), callInfo.getArg(0), clasp);
+        current->add(hasClass);
+        current->push(hasClass);
+    }
+
+    callInfo.setImplicitlyUsedUnchecked();
+    return InliningStatus_Inlined;
+}
+
+IonBuilder::InliningStatus
 IonBuilder::inlineUnsafeSetReservedSlot(CallInfo &callInfo)
 {
     if (callInfo.argc() != 3 || callInfo.constructing())
         return InliningStatus_NotInlined;
     if (getInlineReturnType() != MIRType_Undefined)
         return InliningStatus_NotInlined;
     if (callInfo.getArg(0)->type() != MIRType_Object)
         return InliningStatus_NotInlined;
--- a/js/src/jit/MIR.h
+++ b/js/src/jit/MIR.h
@@ -9352,16 +9352,49 @@ class MHaveSameClass
     TypePolicy *typePolicy() {
         return this;
     }
     AliasSet getAliasSet() const {
         return AliasSet::None();
     }
 };
 
+class MHasClass
+    : public MUnaryInstruction,
+      public SingleObjectPolicy
+{
+    const Class *class_;
+
+    MHasClass(MDefinition *object, const Class *clasp)
+      : MUnaryInstruction(object)
+      , class_(clasp)
+    {
+        JS_ASSERT(object->type() == MIRType_Object);
+        setResultType(MIRType_Boolean);
+        setMovable();
+    }
+
+  public:
+    INSTRUCTION_HEADER(HasClass);
+
+    static MHasClass *New(TempAllocator &alloc, MDefinition *obj, const Class *clasp) {
+        return new(alloc) MHasClass(obj, clasp);
+    }
+
+    MDefinition *object() const {
+        return getOperand(0);
+    }
+    const Class *getClass() const {
+        return class_;
+    }
+    AliasSet getAliasSet() const {
+        return AliasSet::None();
+    }
+};
+
 // Increase the usecount of the provided script upon execution and test if
 // the usecount surpasses the threshold. Upon hit it will recompile the
 // outermost script (i.e. not the inlined script).
 class MRecompileCheck : public MNullaryInstruction
 {
     JSScript *script_;
     uint32_t recompileThreshold_;
 
--- a/js/src/jit/MOpcodes.h
+++ b/js/src/jit/MOpcodes.h
@@ -184,16 +184,17 @@ namespace jit {
     _(CallInstanceOf)                                                       \
     _(InterruptCheck)                                                       \
     _(FunctionBoundary)                                                     \
     _(GetDOMProperty)                                                       \
     _(GetDOMMember)                                                         \
     _(SetDOMProperty)                                                       \
     _(IsCallable)                                                           \
     _(HaveSameClass)                                                        \
+    _(HasClass)                                                              \
     _(AsmJSNeg)                                                             \
     _(AsmJSUnsignedToDouble)                                                \
     _(AsmJSUnsignedToFloat32)                                               \
     _(AsmJSLoadHeap)                                                        \
     _(AsmJSStoreHeap)                                                       \
     _(AsmJSLoadGlobalVar)                                                   \
     _(AsmJSStoreGlobalVar)                                                  \
     _(AsmJSLoadFuncPtr)                                                     \
--- a/js/src/jit/ParallelSafetyAnalysis.cpp
+++ b/js/src/jit/ParallelSafetyAnalysis.cpp
@@ -293,16 +293,17 @@ class ParallelSafetyVisitor : public MIn
     UNSAFE_OP(InArray)
     SAFE_OP(GuardThreadExclusive)
     SAFE_OP(InterruptCheckPar)
     SAFE_OP(CheckOverRecursedPar)
     SAFE_OP(FunctionDispatch)
     SAFE_OP(TypeObjectDispatch)
     SAFE_OP(IsCallable)
     SAFE_OP(HaveSameClass)
+    SAFE_OP(HasClass)
     UNSAFE_OP(EffectiveAddress)
     UNSAFE_OP(AsmJSUnsignedToDouble)
     UNSAFE_OP(AsmJSUnsignedToFloat32)
     UNSAFE_OP(AsmJSNeg)
     UNSAFE_OP(AsmJSLoadHeap)
     UNSAFE_OP(AsmJSStoreHeap)
     UNSAFE_OP(AsmJSLoadGlobalVar)
     UNSAFE_OP(AsmJSStoreGlobalVar)
--- a/js/src/js.msg
+++ b/js/src/js.msg
@@ -430,8 +430,9 @@ MSG_DEF(JSMSG_MODULES_NOT_IMPLEMENTED,  
 MSG_DEF(JSMSG_EXPORT_DECL_AT_TOP_LEVEL, 376, 0, JSEXN_SYNTAXERR, "export declarations may only appear at top level")
 MSG_DEF(JSMSG_RC_AFTER_EXPORT_SPEC_LIST, 377, 0, JSEXN_SYNTAXERR, "missing '}' after export specifier list")
 MSG_DEF(JSMSG_NO_EXPORT_NAME,           378, 0, JSEXN_SYNTAXERR, "missing export name")
 MSG_DEF(JSMSG_DECLARATION_AFTER_EXPORT, 379, 0, JSEXN_SYNTAXERR, "missing declaration after 'export' keyword")
 MSG_DEF(JSMSG_INVALID_PROTOTYPE,        380, 0, JSEXN_TYPEERR, "prototype field is not an object")
 MSG_DEF(JSMSG_TYPEDOBJECT_HANDLE_TO_UNSIZED, 381, 0, JSEXN_TYPEERR, "cannot create a handle to an unsized type")
 MSG_DEF(JSMSG_SETPROTOTYPEOF_FAIL,      382, 1, JSEXN_TYPEERR, "[[SetPrototypeOf]] failed on {0}")
 MSG_DEF(JSMSG_INVALID_ARG_TYPE,         383, 3, JSEXN_TYPEERR, "Invalid type: {0} can't be a{1} {2}")
+MSG_DEF(JSMSG_TERMINATED,               384, 1, JSEXN_ERR, "Script terminated by timeout at:\n{0}")
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -4572,52 +4572,48 @@ JS_CompileUCScript(JSContext *cx, JS::Ha
                    size_t length, const JS::CompileOptions &options)
 {
     return Compile(cx, obj, options, chars, length);
 }
 
 JS_PUBLIC_API(bool)
 JS_BufferIsCompilableUnit(JSContext *cx, HandleObject obj, const char *utf8, size_t length)
 {
-    bool result;
-    JSExceptionState *exnState;
-    JSErrorReporter older;
-
     AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, obj);
+
+    cx->clearPendingException();
+
     jschar *chars = JS::UTF8CharsToNewTwoByteCharsZ(cx, JS::UTF8Chars(utf8, length), &length).get();
     if (!chars)
         return true;
 
-    /*
-     * Return true on any out-of-memory error, so our caller doesn't try to
-     * collect more buffered source.
-     */
-    result = true;
-    exnState = JS_SaveExceptionState(cx);
-    {
-        CompileOptions options(cx);
-        options.setCompileAndGo(false);
-        Parser<frontend::FullParseHandler> parser(cx, &cx->tempLifoAlloc(),
-                                                  options, chars, length,
-                                                  /* foldConstants = */ true, nullptr, nullptr);
-        older = JS_SetErrorReporter(cx, nullptr);
-        if (!parser.parse(obj) && parser.isUnexpectedEOF()) {
-            /*
-             * We ran into an error. If it was because we ran out of
-             * source, we return false so our caller knows to try to
-             * collect more buffered source.
-             */
+    // Return true on any out-of-memory error or non-EOF-related syntax error, so our
+    // caller doesn't try to collect more buffered source.
+    bool result = true;
+
+    CompileOptions options(cx);
+    options.setCompileAndGo(false);
+    Parser<frontend::FullParseHandler> parser(cx, &cx->tempLifoAlloc(),
+                                              options, chars, length,
+                                              /* foldConstants = */ true, nullptr, nullptr);
+    JSErrorReporter older = JS_SetErrorReporter(cx, nullptr);
+    if (!parser.parse(obj)) {
+        // We ran into an error. If it was because we ran out of source, we
+        // return false so our caller knows to try to collect more buffered
+        // source.
+        if (parser.isUnexpectedEOF())
             result = false;
-        }
-        JS_SetErrorReporter(cx, older);
+
+        cx->clearPendingException();
     }
+    JS_SetErrorReporter(cx, older);
+
     js_free(chars);
-    JS_RestoreExceptionState(cx, exnState);
     return result;
 }
 
 JS_PUBLIC_API(JSObject *)
 JS_GetGlobalFromScript(JSScript *script)
 {
     JS_ASSERT(!script->isCachedEval());
     return &script->global();
@@ -5871,16 +5867,43 @@ JS_ReportPendingException(JSContext *cx)
     CHECK_REQUEST(cx);
 
     // This can only fail due to oom.
     bool ok = js_ReportUncaughtException(cx);
     JS_ASSERT(!cx->isExceptionPending());
     return ok;
 }
 
+JS::AutoSaveExceptionState::AutoSaveExceptionState(JSContext *cx)
+    : context(cx), wasThrowing(cx->throwing), exceptionValue(cx)
+{
+    AssertHeapIsIdle(cx);
+    CHECK_REQUEST(cx);
+    if (wasThrowing) {
+        exceptionValue = cx->unwrappedException_;
+        cx->clearPendingException();
+    }
+}
+
+void
+JS::AutoSaveExceptionState::restore()
+{
+    context->throwing = wasThrowing;
+    context->unwrappedException_ = exceptionValue;
+    drop();
+}
+
+JS::AutoSaveExceptionState::~AutoSaveExceptionState()
+{
+    if (wasThrowing && !context->isExceptionPending()) {
+        context->throwing = true;
+        context->unwrappedException_ = exceptionValue;
+    }
+}
+
 struct JSExceptionState {
     bool throwing;
     jsval exception;
 };
 
 JS_PUBLIC_API(JSExceptionState *)
 JS_SaveExceptionState(JSContext *cx)
 {
--- a/js/src/jsapi.h
+++ b/js/src/jsapi.h
@@ -4575,27 +4575,70 @@ extern JS_PUBLIC_API(void)
 JS_SetPendingException(JSContext *cx, JS::HandleValue v);
 
 extern JS_PUBLIC_API(void)
 JS_ClearPendingException(JSContext *cx);
 
 extern JS_PUBLIC_API(bool)
 JS_ReportPendingException(JSContext *cx);
 
+namespace JS {
+
 /*
- * Save the current exception state.  This takes a snapshot of cx's current
- * exception state without making any change to that state.
+ * Save and later restore the current exception state of a given JSContext.
+ * This is useful for implementing behavior in C++ that's like try/catch
+ * or try/finally in JS.
+ *
+ * Typical usage:
  *
- * The returned state pointer MUST be passed later to JS_RestoreExceptionState
- * (to restore that saved state, overriding any more recent state) or else to
- * JS_DropExceptionState (to free the state struct in case it is not correct
- * or desirable to restore it).  Both Restore and Drop free the state struct,
- * so callers must stop using the pointer returned from Save after calling the
- * Release or Drop API.
+ *     bool ok = JS_EvaluateScript(cx, ...);
+ *     AutoSaveExceptionState savedExc(cx);
+ *     ... cleanup that might re-enter JS ...
+ *     return ok;
  */
+class JS_PUBLIC_API(AutoSaveExceptionState)
+{
+  private:
+    JSContext *context;
+    bool wasThrowing;
+    RootedValue exceptionValue;
+
+  public:
+    /*
+     * Take a snapshot of cx's current exception state. Then clear any current
+     * pending exception in cx.
+     */
+    explicit AutoSaveExceptionState(JSContext *cx);
+
+    /*
+     * If neither drop() nor restore() was called, restore the exception
+     * state only if no exception is currently pending on cx.
+     */
+    ~AutoSaveExceptionState();
+
+    /*
+     * Discard any stored exception state.
+     * If this is called, the destructor is a no-op.
+     */
+    void drop() {
+        wasThrowing = false;
+        exceptionValue.setUndefined();
+    }
+
+    /*
+     * Replace cx's exception state with the stored exception state. Then
+     * discard the stored exception state. If this is called, the
+     * destructor is a no-op.
+     */
+    void restore();
+};
+
+} /* namespace JS */
+
+/* Deprecated API. Use AutoSaveExceptionState instead. */
 extern JS_PUBLIC_API(JSExceptionState *)
 JS_SaveExceptionState(JSContext *cx);
 
 extern JS_PUBLIC_API(void)
 JS_RestoreExceptionState(JSContext *cx, JSExceptionState *state);
 
 extern JS_PUBLIC_API(void)
 JS_DropExceptionState(JSContext *cx, JSExceptionState *state);
--- a/js/src/jscntxt.cpp
+++ b/js/src/jscntxt.cpp
@@ -1003,50 +1003,54 @@ js_GetErrorMessage(void *userRef, const 
 bool
 js_InvokeOperationCallback(JSContext *cx)
 {
     JS_ASSERT_REQUEST_DEPTH(cx);
 
     JSRuntime *rt = cx->runtime();
     JS_ASSERT(rt->interrupt);
 
-    /*
-     * Reset the callback counter first, then run GC and yield. If another
-     * thread is racing us here we will accumulate another callback request
-     * which will be serviced at the next opportunity.
-     */
+    // Reset the callback counter first, then run GC and yield. If another
+    // thread is racing us here we will accumulate another callback request
+    // which will be serviced at the next opportunity.
     rt->interrupt = false;
 
-    /*
-     * IonMonkey sets its stack limit to UINTPTR_MAX to trigger operation
-     * callbacks.
-     */
+    // IonMonkey sets its stack limit to UINTPTR_MAX to trigger operation
+    // callbacks.
     rt->resetIonStackLimit();
 
     js::gc::GCIfNeeded(cx);
 
 #ifdef JS_ION
 #ifdef JS_THREADSAFE
     rt->interruptPar = false;
 #endif
 
-    /*
-     * A worker thread may have set the callback after finishing an Ion
-     * compilation.
-     */
+    // A worker thread may have set the callback after finishing an Ion
+    // compilation.
     jit::AttachFinishedCompilations(cx);
 #endif
 
-    /*
-     * Important: Additional callbacks can occur inside the callback handler
-     * if it re-enters the JS engine. The embedding must ensure that the
-     * callback is disconnected before attempting such re-entry.
-     */
+    // Important: Additional callbacks can occur inside the callback handler
+    // if it re-enters the JS engine. The embedding must ensure that the
+    // callback is disconnected before attempting such re-entry.
     JSOperationCallback cb = cx->runtime()->operationCallback;
-    return !cb || cb(cx);
+    if (!cb || cb(cx))
+        return true;
+
+    // No need to set aside any pending exception here: ComputeStackString
+    // already does that.
+    Rooted<JSString*> stack(cx, ComputeStackString(cx));
+    const jschar *chars = stack ? stack->getCharsZ(cx) : nullptr;
+    if (!chars)
+        chars = MOZ_UTF16("(stack not available)");
+    JS_ReportErrorFlagsAndNumberUC(cx, JSREPORT_WARNING, js_GetErrorMessage, nullptr,
+                                   JSMSG_TERMINATED, chars);
+
+    return false;
 }
 
 bool
 js_HandleExecutionInterrupt(JSContext *cx)
 {
     if (cx->runtime()->interrupt)
         return js_InvokeOperationCallback(cx);
     return true;
--- a/js/src/jscntxt.h
+++ b/js/src/jscntxt.h
@@ -407,16 +407,17 @@ struct JSContext : public js::ExclusiveC
 {
     explicit JSContext(JSRuntime *rt);
     ~JSContext();
 
     JSRuntime *runtime() const { return runtime_; }
     js::PerThreadData &mainThread() const { return runtime()->mainThread; }
 
     friend class js::ExclusiveContext;
+    friend class JS::AutoSaveExceptionState;
 
   private:
     /* Exception state -- the exception member is a GC root by definition. */
     bool                throwing;            /* is there a pending exception? */
     js::Value           unwrappedException_; /* most-recently-thrown exception */
 
     /* Per-context options. */
     JS::ContextOptions  options_;
@@ -1028,16 +1029,19 @@ bool intrinsic_UnsafeGetReservedSlot(JSC
 bool intrinsic_HaveSameClass(JSContext *cx, unsigned argc, Value *vp);
 bool intrinsic_IsPackedArray(JSContext *cx, unsigned argc, Value *vp);
 
 bool intrinsic_ShouldForceSequential(JSContext *cx, unsigned argc, Value *vp);
 bool intrinsic_NewParallelArray(JSContext *cx, unsigned argc, Value *vp);
 bool intrinsic_ForkJoinGetSlice(JSContext *cx, unsigned argc, Value *vp);
 bool intrinsic_InParallelSection(JSContext *cx, unsigned argc, Value *vp);
 
+bool intrinsic_ObjectIsTransparentTypedObject(JSContext *cx, unsigned argc, Value *vp);
+bool intrinsic_ObjectIsOpaqueTypedObject(JSContext *cx, unsigned argc, Value *vp);
+
 class AutoLockForExclusiveAccess
 {
 #ifdef JS_THREADSAFE
     JSRuntime *runtime;
 
     void init(JSRuntime *rt) {
         runtime = rt;
         if (runtime->numExclusiveThreads) {
--- a/js/src/jsexn.cpp
+++ b/js/src/jsexn.cpp
@@ -183,33 +183,32 @@ js::CopyErrorReport(JSContext *cx, JSErr
 #undef JS_CHARS_SIZE
     return copy;
 }
 
 struct SuppressErrorsGuard
 {
     JSContext *cx;
     JSErrorReporter prevReporter;
-    JSExceptionState *prevState;
+    JS::AutoSaveExceptionState prevState;
 
     SuppressErrorsGuard(JSContext *cx)
       : cx(cx),
         prevReporter(JS_SetErrorReporter(cx, nullptr)),
-        prevState(JS_SaveExceptionState(cx))
+        prevState(cx)
     {}
 
     ~SuppressErrorsGuard()
     {
-        JS_RestoreExceptionState(cx, prevState);
         JS_SetErrorReporter(cx, prevReporter);
     }
 };
 
-static JSString *
-ComputeStackString(JSContext *cx)
+JSString *
+js::ComputeStackString(JSContext *cx)
 {
     StringBuffer sb(cx);
 
     {
         RootedAtom atom(cx);
         SuppressErrorsGuard seg(cx);
         // We should get rid of the CURRENT_CONTEXT and STOP_AT_SAVED here.
         // See bug 960820.
--- a/js/src/jsexn.h
+++ b/js/src/jsexn.h
@@ -12,18 +12,21 @@
 #define jsexn_h
 
 #include "jsapi.h"
 #include "NamespaceImports.h"
 
 namespace js {
 class ErrorObject;
 
-extern JSErrorReport *
+JSErrorReport *
 CopyErrorReport(JSContext *cx, JSErrorReport *report);
+
+JSString *
+ComputeStackString(JSContext *cx);
 }
 
 /*
  * Given a JSErrorReport, check to see if there is an exception associated with
  * the error number.  If there is, then create an appropriate exception object,
  * set it as the pending exception, and set the JSREPORT_EXCEPTION flag on the
  * error report.  Exception-aware host error reporters should probably ignore
  * error reports so flagged.
--- a/js/src/jsobj.cpp
+++ b/js/src/jsobj.cpp
@@ -4270,16 +4270,28 @@ js::HasOwnProperty<CanGC>(JSContext *cx,
                           HandleObject obj, HandleId id,
                           MutableHandleObject objp, MutableHandleShape propp);
 
 template bool
 js::HasOwnProperty<NoGC>(JSContext *cx, LookupGenericOp lookup,
                          JSObject *obj, jsid id,
                          FakeMutableHandle<JSObject*> objp, FakeMutableHandle<Shape*> propp);
 
+bool
+js::HasOwnProperty(JSContext *cx, HandleObject obj, HandleId id, bool *resultp)
+{
+    RootedObject pobj(cx);
+    RootedShape shape(cx);
+    if (!HasOwnProperty<CanGC>(cx, obj->getOps()->lookupGeneric, obj, id, &pobj, &shape))
+        return false;
+    *resultp = (shape != nullptr);
+    return true;
+}
+
+
 template <AllowGC allowGC>
 static MOZ_ALWAYS_INLINE bool
 NativeGetInline(JSContext *cx,
                 typename MaybeRooted<JSObject*, allowGC>::HandleType obj,
                 typename MaybeRooted<JSObject*, allowGC>::HandleType receiver,
                 typename MaybeRooted<JSObject*, allowGC>::HandleType pobj,
                 typename MaybeRooted<Shape*, allowGC>::HandleType shape,
                 typename MaybeRooted<Value, allowGC>::MutableHandleType vp)
--- a/js/src/jsobj.h
+++ b/js/src/jsobj.h
@@ -1281,16 +1281,20 @@ DenseRangeRef::mark(JSTracer *trc)
     js::gc::IsObjectMarked(&owner);
     uint32_t initLen = owner->getDenseInitializedLength();
     uint32_t clampedStart = Min(start, initLen);
     gc::MarkArraySlots(trc, Min(end, initLen) - clampedStart,
                        owner->getDenseElements() + clampedStart, "element");
 }
 #endif
 
+/* Set *resultp to tell whether obj has an own property with the given id. */
+bool
+HasOwnProperty(JSContext *cx, HandleObject obj, HandleId id, bool *resultp);
+
 template <AllowGC allowGC>
 extern bool
 HasOwnProperty(JSContext *cx, LookupGenericOp lookup,
                typename MaybeRooted<JSObject*, allowGC>::HandleType obj,
                typename MaybeRooted<jsid, allowGC>::HandleType id,
                typename MaybeRooted<JSObject*, allowGC>::MutableHandleType objp,
                typename MaybeRooted<Shape*, allowGC>::MutableHandleType propp);
 
--- a/js/src/jsscript.cpp
+++ b/js/src/jsscript.cpp
@@ -918,18 +918,21 @@ js::XDRScript(XDRState<mode> *xdr, Handl
                     funEnclosingScope = function->lazyScript()->enclosingScope();
                 else
                     funEnclosingScope = function->nonLazyScript()->enclosingStaticScope();
 
                 StaticScopeIter<NoGC> ssi(funEnclosingScope);
                 if (ssi.done() || ssi.type() == StaticScopeIter<NoGC>::FUNCTION) {
                     JS_ASSERT(ssi.done() == !fun);
                     funEnclosingScopeIndex = UINT32_MAX;
+                } else if (ssi.type() == StaticScopeIter<NoGC>::BLOCK) {
+                    funEnclosingScopeIndex = FindScopeObjectIndex(script, ssi.block());
+                    JS_ASSERT(funEnclosingScopeIndex < i);
                 } else {
-                    funEnclosingScopeIndex = FindScopeObjectIndex(script, ssi.block());
+                    funEnclosingScopeIndex = FindScopeObjectIndex(script, ssi.staticWith());
                     JS_ASSERT(funEnclosingScopeIndex < i);
                 }
             }
 
             if (!xdr->codeUint32(&funEnclosingScopeIndex))
                 return false;
 
             if (mode == XDR_DECODE) {
@@ -2794,20 +2797,22 @@ js::CloneScript(JSContext *cx, HandleObj
                     if (innerFun->isInterpretedLazy()) {
                         AutoCompartment ac(cx, innerFun);
                         if (!innerFun->getOrCreateScript(cx))
                             return nullptr;
                     }
                     RootedObject staticScope(cx, innerFun->nonLazyScript()->enclosingStaticScope());
                     StaticScopeIter<CanGC> ssi(cx, staticScope);
                     RootedObject enclosingScope(cx);
-                    if (!ssi.done() && ssi.type() == StaticScopeIter<CanGC>::BLOCK)
+                    if (ssi.done() || ssi.type() == StaticScopeIter<CanGC>::FUNCTION)
+                        enclosingScope = fun;
+                    else if (ssi.type() == StaticScopeIter<CanGC>::BLOCK)
                         enclosingScope = objects[FindScopeObjectIndex(src, ssi.block())];
                     else
-                        enclosingScope = fun;
+                        enclosingScope = objects[FindScopeObjectIndex(src, ssi.staticWith())];
 
                     clone = CloneFunctionAndScript(cx, enclosingScope, innerFun);
                 }
             } else {
                 /*
                  * Clone object literals emitted for the JSOP_NEWOBJECT opcode. We only emit that
                  * instead of the less-optimized JSOP_NEWINIT for self-hosted code or code compiled
                  * with JSOPTION_COMPILE_N_GO set. As we don't clone the latter type of code, this
--- a/js/src/shell/js.cpp
+++ b/js/src/shell/js.cpp
@@ -315,20 +315,19 @@ GetContextData(JSContext *cx)
 }
 
 static bool
 ShellOperationCallback(JSContext *cx)
 {
     if (!gTimedOut)
         return true;
 
-    JS_ClearPendingException(cx);
-
     bool result;
     if (!gTimeoutFunc.isNull()) {
+        JS::AutoSaveExceptionState savedExc(cx);
         JSAutoCompartment ac(cx, &gTimeoutFunc.toObject());
         RootedValue rval(cx);
         HandleValue timeoutFunc = HandleValue::fromMarkedLocation(&gTimeoutFunc);
         if (!JS_CallFunctionValue(cx, JS::NullPtr(), timeoutFunc, JS::EmptyValueArray, &rval))
             return false;
         if (rval.isBoolean())
             result = rval.toBoolean();
         else
--- a/js/src/vm/Debugger.cpp
+++ b/js/src/vm/Debugger.cpp
@@ -3365,17 +3365,17 @@ DebuggerScript_getAllOffsets(JSContext *
         if (!flowData[offset].hasNoEdges() && flowData[offset].lineno() != lineno) {
             /* Get the offsets array for this line. */
             RootedObject offsets(cx);
             RootedValue offsetsv(cx);
 
             RootedId id(cx, INT_TO_JSID(lineno));
 
             bool found;
-            if (!JSObject::hasProperty(cx, result, id, &found))
+            if (!js::HasOwnProperty(cx, result, id, &found))
                 return false;
             if (found && !JSObject::getGeneric(cx, result, result, id, &offsetsv))
                 return false;
 
             if (offsetsv.isObject()) {
                 offsets = &offsetsv.toObject();
             } else {
                 JS_ASSERT(offsetsv.isUndefined());
--- a/js/src/vm/SelfHosting.cpp
+++ b/js/src/vm/SelfHosting.cpp
@@ -614,16 +614,32 @@ intrinsic_InParallelSectionPar(ForkJoinC
     CallArgs args = CallArgsFromVp(argc, vp);
     args.rval().setBoolean(true);
     return true;
 }
 
 JS_JITINFO_NATIVE_PARALLEL(intrinsic_InParallelSection_jitInfo,
                            intrinsic_InParallelSectionPar);
 
+/* These wrappers are needed in order to recognize the function
+ * pointers within the JIT, and the raw js:: functions can't be used
+ * directly because they take a ThreadSafeContext* argument.
+ */
+bool
+js::intrinsic_ObjectIsTransparentTypedObject(JSContext *cx, unsigned argc, Value *vp)
+{
+    return js::ObjectIsTransparentTypedObject(cx, argc, vp);
+}
+
+bool
+js::intrinsic_ObjectIsOpaqueTypedObject(JSContext *cx, unsigned argc, Value *vp)
+{
+    return js::ObjectIsOpaqueTypedObject(cx, argc, vp);
+}
+
 /**
  * Returns the default locale as a well-formed, but not necessarily canonicalized,
  * BCP-47 language tag.
  */
 static bool
 intrinsic_RuntimeDefaultLocale(JSContext *cx, unsigned argc, Value *vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
@@ -694,23 +710,23 @@ static const JSFunctionSpec intrinsic_fu
               &js::AttachTypedObjectJitInfo, 5, 0),
     JS_FNINFO("SetTypedObjectOffset",
               JSNativeThreadSafeWrapper<js::SetTypedObjectOffset>,
               &js::SetTypedObjectOffsetJitInfo, 2, 0),
     JS_FNINFO("ObjectIsTypeDescr",
               JSNativeThreadSafeWrapper<js::ObjectIsTypeDescr>,
               &js::ObjectIsTypeDescrJitInfo, 5, 0),
     JS_FNINFO("ObjectIsTransparentTypedObject",
-              JSNativeThreadSafeWrapper<js::ObjectIsTransparentTypedObject>,
+              intrinsic_ObjectIsTransparentTypedObject,
               &js::ObjectIsTransparentTypedObjectJitInfo, 5, 0),
     JS_FNINFO("TypedObjectIsAttached",
               JSNativeThreadSafeWrapper<js::TypedObjectIsAttached>,
               &js::TypedObjectIsAttachedJitInfo, 1, 0),
     JS_FNINFO("ObjectIsOpaqueTypedObject",
-              JSNativeThreadSafeWrapper<js::ObjectIsOpaqueTypedObject>,
+              intrinsic_ObjectIsOpaqueTypedObject,
               &js::ObjectIsOpaqueTypedObjectJitInfo, 5, 0),
     JS_FNINFO("ClampToUint8",
               JSNativeThreadSafeWrapper<js::ClampToUint8>,
               &js::ClampToUint8JitInfo, 1, 0),
     JS_FNINFO("Memcpy",
               JSNativeThreadSafeWrapper<js::Memcpy>,
               &js::MemcpyJitInfo, 5, 0),
     JS_FN("GetTypedObjectModule", js::GetTypedObjectModule, 0, 0),
--- a/js/src/vm/StructuredClone.cpp
+++ b/js/src/vm/StructuredClone.cpp
@@ -1028,24 +1028,21 @@ JSStructuredCloneWriter::write(const Val
             ids.popBack();
             checkStack();
             if (JSID_IS_STRING(id) || JSID_IS_INT(id)) {
                 /*
                  * If obj still has an own property named id, write it out.
                  * The cost of re-checking could be avoided by using
                  * NativeIterators.
                  */
-                RootedObject obj2(context());
-                RootedShape prop(context());
-                if (!HasOwnProperty<CanGC>(context(), obj->getOps()->lookupGeneric, obj, id,
-                                           &obj2, &prop)) {
+                bool found;
+                if (!HasOwnProperty(context(), obj, id, &found))
                     return false;
-                }
 
-                if (prop) {
+                if (found) {
                     RootedValue val(context());
                     if (!writeId(id) ||
                         !JSObject::getGeneric(context(), obj, obj, id, &val) ||
                         !startWrite(val))
                         return false;
                 }
             }
         } else {
--- a/js/xpconnect/src/XPCDebug.cpp
+++ b/js/xpconnect/src/XPCDebug.cpp
@@ -41,28 +41,23 @@ xpc_DumpJSStack(JSContext* cx, bool show
     }
     return true;
 }
 
 char*
 xpc_PrintJSStack(JSContext* cx, bool showArgs, bool showLocals,
                  bool showThisProps)
 {
-    char* buf;
-    JSExceptionState *state = JS_SaveExceptionState(cx);
-    if (!state)
-        DebugDump("%s", "Call to a debug function modifying state!\n");
+    JS::AutoSaveExceptionState state(cx);
 
-    JS_ClearPendingException(cx);
-
-    buf = JS::FormatStackDump(cx, nullptr, showArgs, showLocals, showThisProps);
+    char *buf = JS::FormatStackDump(cx, nullptr, showArgs, showLocals, showThisProps);
     if (!buf)
         DebugDump("%s", "Failed to format JavaScript stack for dump\n");
 
-    JS_RestoreExceptionState(cx, state);
+    state.restore();
     return buf;
 }
 
 /***************************************************************************/
 
 static void
 xpcDumpEvalErrorReporter(JSContext *cx, const char *message,
                          JSErrorReport *report)
@@ -94,30 +89,32 @@ xpc_DumpEvalInJSStackFrame(JSContext* cx
         num++;
     }
 
     if (!frame) {
         DebugDump("%s", "invalid frame number!\n");
         return false;
     }
 
-    JSExceptionState* exceptionState = JS_SaveExceptionState(cx);
+    JS::AutoSaveExceptionState exceptionState(cx);
     JSErrorReporter older = JS_SetErrorReporter(cx, xpcDumpEvalErrorReporter);
 
     JS::RootedValue rval(cx);
     JSString* str;
     JSAutoByteString bytes;
     if (frame.evaluateInStackFrame(cx, text, strlen(text), "eval", 1, &rval) &&
         nullptr != (str = ToString(cx, rval)) &&
         bytes.encodeLatin1(cx, str)) {
         DebugDump("%s\n", bytes.ptr());
-    } else
+    } else {
         DebugDump("%s", "eval failed!\n");
+    }
+
     JS_SetErrorReporter(cx, older);
-    JS_RestoreExceptionState(cx, exceptionState);
+    exceptionState.restore();
     return true;
 }
 
 /***************************************************************************/
 
 JSTrapStatus
 xpc_DebuggerKeywordHandler(JSContext *cx, JSScript *script, jsbytecode *pc,
                            jsval *rval, void *closure)
--- a/js/xpconnect/src/XPCJSRuntime.cpp
+++ b/js/xpconnect/src/XPCJSRuntime.cpp
@@ -3065,21 +3065,21 @@ XPCJSRuntime::XPCJSRuntime(nsXPConnect* 
     // MacOS has a gargantuan default stack size of 8MB. Go wild with 7MB,
     // and give trusted script 140k extra. The stack is huge on mac anyway.
     const size_t kStackQuota = 7 * 1024 * 1024;
     const size_t kTrustedScriptBuffer = 140 * 1024;
 #elif defined(MOZ_ASAN)
     // ASan requires more stack space due to red-zones, so give it double the
     // default (2MB on 32-bit, 4MB on 64-bit). ASAN stack frame measurements
     // were not taken at the time of this writing, so we hazard a guess that
-    // ASAN builds have roughly twice the stack overhead as normal builds.
+    // ASAN builds have roughly thrice the stack overhead as normal builds.
     // On normal builds, the largest stack frame size we might encounter is
-    // 8.2k, so let's use a buffer of 8.2 * 2 * 10 = 164k.
+    // 8.2k, so let's use a buffer of 8.2 * 3 * 10 = 246k.
     const size_t kStackQuota =  2 * kDefaultStackQuota;
-    const size_t kTrustedScriptBuffer = 164 * 1024;
+    const size_t kTrustedScriptBuffer = 246 * 1024;
 #elif defined(XP_WIN)
     // 1MB is the default stack size on Windows, so the default 1MB stack quota
     // we'd get on win32 is slightly too large. Use 900k instead. And since
     // windows stack frames are 3.4k each, let's use a buffer of 40k.
     const size_t kStackQuota = 900 * 1024;
     const size_t kTrustedScriptBuffer = 40 * 1024;
     // The following two configurations are linux-only. Given the numbers above,
     // we use 50k and 100k trusted buffers on 32-bit and 64-bit respectively.
--- a/js/xpconnect/src/XPCWrappedJSClass.cpp
+++ b/js/xpconnect/src/XPCWrappedJSClass.cpp
@@ -48,36 +48,26 @@ bool AutoScriptEvaluate::StartEvaluating
     mAutoCompartment.construct(mJSContext, scope);
 
     // Saving the exception state keeps us from interfering with another script
     // that may also be running on this context.  This occurred first with the
     // js debugger, as described in
     // http://bugzilla.mozilla.org/show_bug.cgi?id=88130 but presumably could
     // show up in any situation where a script calls into a wrapped js component
     // on the same context, while the context has a nonzero exception state.
-    // Because JS_SaveExceptionState/JS_RestoreExceptionState use malloc
-    // and addroot, we avoid them if possible by returning null (as opposed to
-    // a JSExceptionState with no information) when there is no pending
-    // exception.
-    if (JS_IsExceptionPending(mJSContext)) {
-        mState = JS_SaveExceptionState(mJSContext);
-        JS_ClearPendingException(mJSContext);
-    }
+    mState.construct(mJSContext);
 
     return true;
 }
 
 AutoScriptEvaluate::~AutoScriptEvaluate()
 {
     if (!mJSContext || !mEvaluated)
         return;
-    if (mState)
-        JS_RestoreExceptionState(mJSContext, mState);
-    else
-        JS_ClearPendingException(mJSContext);
+    mState.ref().restore();
 
     JS_EndRequest(mJSContext);
 
     if (mErrorReporterSet)
         JS_SetErrorReporter(mJSContext, nullptr);
 }
 
 // It turns out that some errors may be not worth reporting. So, this
--- a/js/xpconnect/src/xpcprivate.h
+++ b/js/xpconnect/src/xpcprivate.h
@@ -2933,18 +2933,17 @@ private:
 class MOZ_STACK_CLASS AutoScriptEvaluate
 {
 public:
     /**
      * Saves the JSContext as well as initializing our state
      * @param cx The JSContext, this can be null, we don't do anything then
      */
     AutoScriptEvaluate(JSContext * cx MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
-         : mJSContext(cx), mState(0), mErrorReporterSet(false),
-           mEvaluated(false) {
+         : mJSContext(cx), mErrorReporterSet(false), mEvaluated(false) {
         MOZ_GUARD_OBJECT_NOTIFIER_INIT;
     }
 
     /**
      * Does the pre script evaluation and sets the error reporter if given
      * This function should only be called once, and will assert if called
      * more than once
      * @param errorReporter the error reporter callback function to set
@@ -2953,17 +2952,17 @@ public:
     bool StartEvaluating(JS::HandleObject scope, JSErrorReporter errorReporter = nullptr);
 
     /**
      * Does the post script evaluation and resets the error reporter
      */
     ~AutoScriptEvaluate();
 private:
     JSContext* mJSContext;
-    JSExceptionState* mState;
+    mozilla::Maybe<JS::AutoSaveExceptionState> mState;
     bool mErrorReporterSet;
     bool mEvaluated;
     mozilla::Maybe<JSAutoCompartment> mAutoCompartment;
     MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
 
     // No copying or assignment allowed
     AutoScriptEvaluate(const AutoScriptEvaluate &) MOZ_DELETE;
     AutoScriptEvaluate & operator =(const AutoScriptEvaluate &) MOZ_DELETE;
--- a/layout/base/PositionedEventTargeting.cpp
+++ b/layout/base/PositionedEventTargeting.cpp
@@ -196,18 +196,20 @@ IsElementClickable(nsIFrame* aFrame, nsI
           tag == nsGkAtoms::menubutton ||
           tag == nsGkAtoms::menuitem ||
           tag == nsGkAtoms::menulist ||
           tag == nsGkAtoms::scrollbarbutton ||
           tag == nsGkAtoms::resizer) {
         return true;
       }
     }
-    if (content->AttrValueIs(kNameSpaceID_None, nsGkAtoms::role,
-                             nsGkAtoms::button, eIgnoreCase)) {
+    static nsIContent::AttrValuesArray clickableRoles[] =
+      { &nsGkAtoms::button, &nsGkAtoms::key, nullptr };
+    if (content->FindAttrValueIn(kNameSpaceID_None, nsGkAtoms::role,
+                                 clickableRoles, eIgnoreCase) >= 0) {
       return true;
     }
     if (content->IsEditable()) {
       return true;
     }
     nsCOMPtr<nsIURI> linkURI;
     if (content->IsLink(getter_AddRefs(linkURI))) {
       return true;
--- a/layout/base/nsDocumentViewer.cpp
+++ b/layout/base/nsDocumentViewer.cpp
@@ -2220,16 +2220,21 @@ nsDocumentViewer::CreateStyleSet(nsIDocu
 
   if (!shouldOverride) {
     sheet = nsLayoutStylesheetCache::ScrollbarsSheet();
     if (sheet) {
       styleSet->PrependStyleSheet(nsStyleSet::eAgentSheet, sheet);
     }
   }
 
+  sheet = nsLayoutStylesheetCache::NumberControlSheet();
+  if (sheet) {
+    styleSet->PrependStyleSheet(nsStyleSet::eAgentSheet, sheet);
+  }
+
   sheet = nsLayoutStylesheetCache::FormsSheet();
   if (sheet) {
     styleSet->PrependStyleSheet(nsStyleSet::eAgentSheet, sheet);
   }
 
   sheet = nsLayoutStylesheetCache::FullScreenOverrideSheet();
   if (sheet) {
     styleSet->PrependStyleSheet(nsStyleSet::eOverrideSheet, sheet);
--- a/layout/base/tests/test_event_target_radius.html
+++ b/layout/base/tests/test_event_target_radius.html
@@ -23,17 +23,18 @@ https://bugzilla.mozilla.org/show_bug.cg
 
   <input class="target" id="t3_1" hidden></input>
   <a href="#" class="target" id="t3_2" hidden></a>
   <label class="target" id="t3_3" hidden></label>
   <button class="target" id="t3_4" hidden></button>
   <select class="target" id="t3_5" hidden></select>
   <textarea class="target" id="t3_6" hidden></textarea>
   <div role="button" class="target" id="t3_7" hidden></div>
-  <img class="target" id="t3_8" hidden></img>
+  <div role="key" class="target" id="t3_8" hidden></div>
+  <img class="target" id="t3_9" hidden></img>
 
   <div class="target" style="transform:translate(-80px,0);" id="t4" onmousedown="x=1" hidden></div>
 
   <div class="target" style="left:0; z-index:1" id="t5_left" onmousedown="x=1" hidden></div>
   <div class="target" style="left:106px;" id="t5_right" onmousedown="x=1" hidden></div>
   <div class="target" style="left:0; top:210px;" id="t5_below" onmousedown="x=1" hidden></div>
 
   <div class="target" id="t6" onmousedown="x=1" hidden>
@@ -146,19 +147,19 @@ function test3() {
   t2.onclick = null;
   // Keypresses don't make click radius targets
   t2.onkeypress = function() {};
   testMouseClick("t2", 100 + 11*mm, 10, "body", "DIV with onkeypress");
   t2.onkeypress = null;
   setShowing("t2", false);
 
   // Now check that certain elements are click radius targets and others are not
-  for (var i = 1; i <= 8; ++i) {
+  for (var i = 1; i <= 9; ++i) {
     var id = "t3_" + i;
-    var shouldHit = i <= 7;
+    var shouldHit = i <= 8;
     setShowing(id, true);
     testMouseClick(id, 100 + 11*mm, 10, shouldHit ? id : "body",
                    "<" + document.getElementById(id).tagName + "> element");
     setShowing(id, false);
   }
 
   // Check that our targeting computations take into account the effects of
   // CSS transforms
--- a/layout/style/forms.css
+++ b/layout/style/forms.css
@@ -896,23 +896,19 @@ input[type=range]::-moz-range-thumb {
   height: 1em;
   border: 0.1em solid grey;
   border-radius: 0.5em;
   background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg'><linearGradient id='g' x2='0' y2='100%'><stop stop-color='%23ddd'/><stop offset='100%' stop-color='white'/></linearGradient><rect fill='url(%23g)' width='100%' height='100%'/></svg>");
   /* Prevent nsFrame::HandlePress setting mouse capture to this element. */
   -moz-user-select: none ! important;
 }
 
-input[type="number"] {
-  -moz-appearance: number-input;
-  /* Has to revert some properties applied by the generic input rule. */
-  -moz-binding: none;
-  width: 149px; /* to match type=text */
-  overflow-clip-box: content-box;
-}
+/* As a temporary workaround until bug 677302 the rule for input[type=number]
+ * has moved to number-control.css
+ */
 
 input[type=number]::-moz-number-wrapper {
   /* Prevent styling that would change the type of frame we construct. */
   display: flex;
   float: none !important;
   position: static !important;
   height: 100%;
 }
--- a/layout/style/jar.mn
+++ b/layout/style/jar.mn
@@ -5,12 +5,13 @@
 toolkit.jar:
 *  res/ua.css    (ua.css)
    res/html.css    (html.css)
    res/quirk.css    (quirk.css)
    res/full-screen-override.css    (full-screen-override.css)
    res/plaintext.css     (plaintext.css)
    res/viewsource.css    (viewsource.css)
 *  res/forms.css    (forms.css)
+   res/number-control.css    (number-control.css)
    res/arrow.gif    (arrow.gif)
    res/arrowd.gif   (arrowd.gif)
 
 % resource gre-resources %res/
--- a/layout/style/nsLayoutStylesheetCache.cpp
+++ b/layout/style/nsLayoutStylesheetCache.cpp
@@ -3,24 +3,31 @@
 /* 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 "nsLayoutStylesheetCache.h"
 
 #include "nsAppDirectoryServiceDefs.h"
 #include "mozilla/MemoryReporting.h"
+#include "mozilla/Preferences.h"
 #include "mozilla/css/Loader.h"
 #include "nsIFile.h"
 #include "nsNetUtil.h"
 #include "nsIObserverService.h"
 #include "nsServiceManagerUtils.h"
 #include "nsIXULRuntime.h"
 #include "nsCSSStyleSheet.h"
 
+using namespace mozilla;
+
+static bool sNumberControlEnabled;
+
+#define NUMBER_CONTROL_PREF "dom.forms.number"
+
 NS_IMPL_ISUPPORTS2(
   nsLayoutStylesheetCache, nsIObserver, nsIMemoryReporter)
 
 nsresult
 nsLayoutStylesheetCache::Observe(nsISupports* aSubject,
                             const char* aTopic,
                             const char16_t* aData)
 {
@@ -30,16 +37,17 @@ nsLayoutStylesheetCache::Observe(nsISupp
   }
   else if (!strcmp(aTopic, "profile-do-change")) {
     InitFromProfile();
   }
   else if (strcmp(aTopic, "chrome-flush-skin-caches") == 0 ||
            strcmp(aTopic, "chrome-flush-caches") == 0) {
     mScrollbarsSheet = nullptr;
     mFormsSheet = nullptr;
+    mNumberControlSheet = nullptr;
   }
   else {
     NS_NOTREACHED("Unexpected observer topic.");
   }
   return NS_OK;
 }
 
 nsCSSStyleSheet*
@@ -81,16 +89,41 @@ nsLayoutStylesheetCache::FormsSheet()
 
     NS_ASSERTION(gStyleCache->mFormsSheet, "Could not load forms.css.");
   }
 
   return gStyleCache->mFormsSheet;
 }
 
 nsCSSStyleSheet*
+nsLayoutStylesheetCache::NumberControlSheet()
+{
+  EnsureGlobal();
+  if (!gStyleCache)
+    return nullptr;
+
+  if (!sNumberControlEnabled) {
+    return nullptr;
+  }
+
+  if (!gStyleCache->mNumberControlSheet) {
+    nsCOMPtr<nsIURI> sheetURI;
+    NS_NewURI(getter_AddRefs(sheetURI),
+              NS_LITERAL_CSTRING("resource://gre-resources/number-control.css"));
+
+    if (sheetURI)
+      LoadSheet(sheetURI, gStyleCache->mNumberControlSheet, false);
+
+    NS_ASSERTION(gStyleCache->mNumberControlSheet, "Could not load number-control.css");
+  }
+
+  return gStyleCache->mNumberControlSheet;
+}
+
+nsCSSStyleSheet*
 nsLayoutStylesheetCache::UserContentSheet()
 {
   EnsureGlobal();
   if (!gStyleCache)
     return nullptr;
 
   return gStyleCache->mUserContentSheet;
 }
@@ -159,16 +192,17 @@ size_t
 nsLayoutStylesheetCache::SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const
 {
   size_t n = aMallocSizeOf(this);
 
   #define MEASURE(s) n += s ? s->SizeOfIncludingThis(aMallocSizeOf) : 0;
 
   MEASURE(mScrollbarsSheet);
   MEASURE(mFormsSheet);
+  MEASURE(mNumberControlSheet);
   MEASURE(mUserContentSheet);
   MEASURE(mUserChromeSheet);
   MEASURE(mUASheet);
   MEASURE(mQuirkSheet);
   MEASURE(mFullScreenOverrideSheet);
 
   // Measurement of the following members may be added later if DMD finds it is
   // worthwhile:
@@ -232,16 +266,19 @@ nsLayoutStylesheetCache::EnsureGlobal()
   if (gStyleCache) return;
 
   gStyleCache = new nsLayoutStylesheetCache();
   if (!gStyleCache) return;
 
   NS_ADDREF(gStyleCache);
 
   gStyleCache->InitMemoryReporter();
+
+  Preferences::AddBoolVarCache(&sNumberControlEnabled, NUMBER_CONTROL_PREF,
+                               true);
 }
 
 void
 nsLayoutStylesheetCache::InitFromProfile()
 {
   nsCOMPtr<nsIXULRuntime> appInfo = do_GetService("@mozilla.org/xre/app-info;1");
   if (appInfo) {
     bool inSafeMode = false;
--- a/layout/style/nsLayoutStylesheetCache.h
+++ b/layout/style/nsLayoutStylesheetCache.h
@@ -28,16 +28,19 @@ class nsLayoutStylesheetCache MOZ_FINAL
  , public nsIMemoryReporter
 {
   NS_DECL_ISUPPORTS
   NS_DECL_NSIOBSERVER
   NS_DECL_NSIMEMORYREPORTER
 
   static nsCSSStyleSheet* ScrollbarsSheet();
   static nsCSSStyleSheet* FormsSheet();
+  // This function is expected to return nullptr when the dom.forms.number
+  // pref is disabled.
+  static nsCSSStyleSheet* NumberControlSheet();
   static nsCSSStyleSheet* UserContentSheet();
   static nsCSSStyleSheet* UserChromeSheet();
   static nsCSSStyleSheet* UASheet();
   static nsCSSStyleSheet* QuirkSheet();
   static nsCSSStyleSheet* FullScreenOverrideSheet();
 
   static void Shutdown();
 
@@ -53,16 +56,17 @@ private:
   static void LoadSheetFile(nsIFile* aFile, nsRefPtr<nsCSSStyleSheet> &aSheet);
   static void LoadSheet(nsIURI* aURI, nsRefPtr<nsCSSStyleSheet> &aSheet,
                         bool aEnableUnsafeRules);
 
   static nsLayoutStylesheetCache* gStyleCache;
   static mozilla::css::Loader* gCSSLoader;
   nsRefPtr<nsCSSStyleSheet> mScrollbarsSheet;
   nsRefPtr<nsCSSStyleSheet> mFormsSheet;
+  nsRefPtr<nsCSSStyleSheet> mNumberControlSheet;
   nsRefPtr<nsCSSStyleSheet> mUserContentSheet;
   nsRefPtr<nsCSSStyleSheet> mUserChromeSheet;
   nsRefPtr<nsCSSStyleSheet> mUASheet;
   nsRefPtr<nsCSSStyleSheet> mQuirkSheet;
   nsRefPtr<nsCSSStyleSheet> mFullScreenOverrideSheet;
 };
 
 #endif
--- a/layout/style/nsRuleNode.cpp
+++ b/layout/style/nsRuleNode.cpp
@@ -5102,17 +5102,17 @@ nsRuleNode::ComputeDisplayData(void* aSt
                         "animIterationCount.num computed incorrectly");
       NS_ABORT_IF_FALSE(!canStoreInRuleTree,
                         "should have made canStoreInRuleTree false above");
       animation->SetIterationCount(parentDisplay->mAnimations[i].GetIterationCount());
     } else if (animIterationCount.unit == eCSSUnit_Initial ||
                animIterationCount.unit == eCSSUnit_Unset) {
       animation->SetIterationCount(1.0f);
     } else if (animIterationCount.list) {
-      switch(animIterationCount.list->mValue.GetUnit()) {
+      switch (animIterationCount.list->mValue.GetUnit()) {
         case eCSSUnit_Enumerated:
           NS_ABORT_IF_FALSE(animIterationCount.list->mValue.GetIntValue() ==
                               NS_STYLE_ANIMATION_ITERATION_COUNT_INFINITE,
                             "unexpected value");
           animation->SetIterationCount(NS_IEEEPositiveInfinity());
           break;
         case eCSSUnit_Number:
           animation->SetIterationCount(
@@ -8368,17 +8368,17 @@ nsRuleNode::ComputeSVGResetData(void* aS
     case eCSSUnit_Inherit:
       canStoreInRuleTree = false;
       svgReset->mFilters = parentSVGReset->mFilters;
       break;
     case eCSSUnit_List:
     case eCSSUnit_ListDep: {
       svgReset->mFilters.Clear();
       const nsCSSValueList* cur = filterValue->GetListValue();
-      while(cur) {
+      while (cur) {
         nsStyleFilter styleFilter;
         if (!SetStyleFilterToCSSValue(&styleFilter, cur->mValue, aContext,
                                       mPresContext, canStoreInRuleTree)) {
           svgReset->mFilters.Clear();
           break;
         }
         NS_ABORT_IF_FALSE(styleFilter.GetType() != NS_STYLE_FILTER_NONE,
                           "filter should be set");
new file mode 100644
--- /dev/null
+++ b/layout/style/number-control.css
@@ -0,0 +1,17 @@
+/* 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/. */
+
+/* This file exists purely because we need the styling for input[type=number]
+ * to apply only if the pref dom.forms.number is true. Once bug 677302 is
+ * fixed this rule can move back to forms.css.
+ */
+
+input[type="number"] {
+  -moz-appearance: number-input;
+  /* Has to revert some properties applied by the generic input rule. */
+  -moz-binding: none;
+  width: 149px; /* to match type=text */
+  overflow-clip-box: content-box;
+}
+
--- a/media/libmkv/WebMElement.c
+++ b/media/libmkv/WebMElement.c
@@ -52,32 +52,39 @@ static UInt64 generateTrackID(unsigned i
   r = r << 32;
   r +=  rand();
 //  UInt64 rval = t ^ r;
   return t ^ r;
 }
 
 void writeVideoTrack(EbmlGlobal *glob, unsigned int trackNumber, int flagLacing,
                      const char *codecId, unsigned int pixelWidth, unsigned int pixelHeight,
+                     unsigned int displayWidth, unsigned int displayHeight,
                      double frameRate) {
   EbmlLoc start;
   UInt64 trackID;
   Ebml_StartSubElement(glob, &start, TrackEntry);
   Ebml_SerializeUnsigned(glob, TrackNumber, trackNumber);
   trackID = generateTrackID(trackNumber);
   Ebml_SerializeUnsigned(glob, TrackUID, trackID);
   Ebml_SerializeString(glob, CodecName, "VP8");  // TODO shouldn't be fixed
 
   Ebml_SerializeUnsigned(glob, TrackType, 1); // video is always 1
   Ebml_SerializeString(glob, CodecID, codecId);
   {
     EbmlLoc videoStart;
     Ebml_StartSubElement(glob, &videoStart, Video);
     Ebml_SerializeUnsigned(glob, PixelWidth, pixelWidth);
     Ebml_SerializeUnsigned(glob, PixelHeight, pixelHeight);
+    if (pixelWidth != displayWidth) {
+      Ebml_SerializeUnsigned(glob, DisplayWidth, displayWidth);
+    }
+    if (pixelHeight != displayHeight) {
+      Ebml_SerializeUnsigned(glob, DisplayHeight, displayHeight);
+    }
     Ebml_SerializeFloat(glob, FrameRate, frameRate);
     Ebml_EndSubElement(glob, &videoStart); // Video
   }
   Ebml_EndSubElement(glob, &start); // Track Entry
 }
 void writeAudioTrack(EbmlGlobal *glob, unsigned int trackNumber, int flagLacing,
                      const char *codecId, double samplingFrequency, unsigned int channels,
                      unsigned char *private, unsigned long privateSize) {
--- a/media/libmkv/WebMElement.h
+++ b/media/libmkv/WebMElement.h
@@ -16,16 +16,17 @@ extern "C" {
 #include "EbmlWriter.h"
 
 // these are helper functions
 void writeHeader(EbmlGlobal *ebml);
 void writeSegmentInformation(EbmlGlobal *ebml, EbmlLoc *startInfo, unsigned long timeCodeScale, double duration);
 // this function is a helper only, it assumes a lot of defaults
 void writeVideoTrack(EbmlGlobal *ebml, unsigned int trackNumber, int flagLacing,
                      const char *codecId, unsigned int pixelWidth, unsigned int pixelHeight,
+                     unsigned int displayWidth, unsigned int displayHeight,
                      double frameRate);
 void writeAudioTrack(EbmlGlobal *glob, unsigned int trackNumber, int flagLacing,
                      const char *codecId, double samplingFrequency, unsigned int channels,
                      unsigned char *private_, unsigned long privateSize);
 
 void writeSimpleBlock(EbmlGlobal *ebml, unsigned char trackNumber, short timeCode,
                       int isKeyframe, unsigned char lacingFlag, int discardable,
                       unsigned char *data, unsigned long dataLength);
new file mode 100644
--- /dev/null
+++ b/media/libmkv/bug970774.patch
@@ -0,0 +1,64 @@
+diff --git a/media/libmkv/WebMElement.c b/media/libmkv/WebMElement.c
+--- a/media/libmkv/WebMElement.c
++++ b/media/libmkv/WebMElement.c
+@@ -52,32 +52,39 @@ static UInt64 generateTrackID(unsigned i
+   r = r << 32;
+   r +=  rand();
+ //  UInt64 rval = t ^ r;
+   return t ^ r;
+ }
+ 
+ void writeVideoTrack(EbmlGlobal *glob, unsigned int trackNumber, int flagLacing,
+                      const char *codecId, unsigned int pixelWidth, unsigned int pixelHeight,
++                     unsigned int displayWidth, unsigned int displayHeight,
+                      double frameRate) {
+   EbmlLoc start;
+   UInt64 trackID;
+   Ebml_StartSubElement(glob, &start, TrackEntry);
+   Ebml_SerializeUnsigned(glob, TrackNumber, trackNumber);
+   trackID = generateTrackID(trackNumber);
+   Ebml_SerializeUnsigned(glob, TrackUID, trackID);
+   Ebml_SerializeString(glob, CodecName, "VP8");  // TODO shouldn't be fixed
+ 
+   Ebml_SerializeUnsigned(glob, TrackType, 1); // video is always 1
+   Ebml_SerializeString(glob, CodecID, codecId);
+   {
+     EbmlLoc videoStart;
+     Ebml_StartSubElement(glob, &videoStart, Video);
+     Ebml_SerializeUnsigned(glob, PixelWidth, pixelWidth);
+     Ebml_SerializeUnsigned(glob, PixelHeight, pixelHeight);
++    if (pixelWidth != displayWidth) {
++      Ebml_SerializeUnsigned(glob, DisplayWidth, displayWidth);
++    }
++    if (pixelHeight != displayHeight) {
++      Ebml_SerializeUnsigned(glob, DisplayHeight, displayHeight);
++    }
+     Ebml_SerializeFloat(glob, FrameRate, frameRate);
+     Ebml_EndSubElement(glob, &videoStart); // Video
+   }
+   Ebml_EndSubElement(glob, &start); // Track Entry
+ }
+ void writeAudioTrack(EbmlGlobal *glob, unsigned int trackNumber, int flagLacing,
+                      const char *codecId, double samplingFrequency, unsigned int channels,
+                      unsigned char *private, unsigned long privateSize) {
+diff --git a/media/libmkv/WebMElement.h b/media/libmkv/WebMElement.h
+--- a/media/libmkv/WebMElement.h
++++ b/media/libmkv/WebMElement.h
+@@ -16,16 +16,17 @@ extern "C" {
+ #include "EbmlWriter.h"
+ 
+ // these are helper functions
+ void writeHeader(EbmlGlobal *ebml);
+ void writeSegmentInformation(EbmlGlobal *ebml, EbmlLoc *startInfo, unsigned long timeCodeScale, double duration);
+ // this function is a helper only, it assumes a lot of defaults
+ void writeVideoTrack(EbmlGlobal *ebml, unsigned int trackNumber, int flagLacing,
+                      const char *codecId, unsigned int pixelWidth, unsigned int pixelHeight,
++                     unsigned int displayWidth, unsigned int displayHeight,
+                      double frameRate);
+ void writeAudioTrack(EbmlGlobal *glob, unsigned int trackNumber, int flagLacing,
+                      const char *codecId, double samplingFrequency, unsigned int channels,
+                      unsigned char *private_, unsigned long privateSize);
+ 
+ void writeSimpleBlock(EbmlGlobal *ebml, unsigned char trackNumber, short timeCode,
+                       int isKeyframe, unsigned char lacingFlag, int discardable,
+                       unsigned char *data, unsigned long dataLength);
--- a/media/libmkv/update.sh
+++ b/media/libmkv/update.sh
@@ -30,8 +30,9 @@ else
   echo "Remember to update README_MOZILLA with the version details."
 fi
 
 # Apply any patches against upstream here.
 patch -p1 < source_fix.patch
 patch -p1 < gecko_fix.patch
 patch -p1 < const_fix.patch
 patch -p3 < bock_fix.patch
+patch -p3 < bug970774.patch
--- a/mfbt/RefPtr.h
+++ b/mfbt/RefPtr.h
@@ -96,21 +96,28 @@ class RefCounted
       MOZ_ASSERT(refCnt > 0);
       return refCnt == 1;
     }
 
   private:
     mutable typename Conditional<Atomicity == AtomicRefCount, Atomic<MozRefCountType>, MozRefCountType>::Type refCnt;
 };
 
+#if defined(MOZILLA_INTERNAL_API) && (defined(DEBUG) || defined(FORCE_BUILD_REFCNT_LOGGING))
 #define MOZ_DECLARE_REFCOUNTED_TYPENAME(T) \
-  const char* typeName() const { return #T; }
+  const char* typeName() const { return #T; } \
+  size_t typeSize() const { return sizeof(*this); }
 
 #define MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(T) \
-  virtual const char* typeName() const { return #T; }
+  virtual const char* typeName() const { return #T; } \
+  virtual size_t typeSize() const { return sizeof(*this); }
+#else
+#define MOZ_DECLARE_REFCOUNTED_TYPENAME(T)
+#define MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(T)
+#endif
 
 }
 
 template<typename T>
 class RefCounted : public detail::RefCounted<T, detail::NonAtomicRefCount>
 {
   public:
     ~RefCounted() {
--- a/netwerk/protocol/http/HttpBaseChannel.cpp
+++ b/netwerk/protocol/http/HttpBaseChannel.cpp
@@ -1805,16 +1805,27 @@ HttpBaseChannel::SetupReplacementChannel
   // convey the referrer if one was used for this channel to the next one
   if (mReferrer)
     httpChannel->SetReferrer(mReferrer);
   // convey the mAllowPipelining flag
   httpChannel->SetAllowPipelining(mAllowPipelining);
   // convey the new redirection limit
   httpChannel->SetRedirectionLimit(mRedirectionLimit - 1);
 
+  // convey the Accept header value
+  {
+    nsAutoCString oldAcceptValue;
+    nsresult hasHeader = mRequestHead.GetHeader(nsHttp::Accept, oldAcceptValue);
+    if (NS_SUCCEEDED(hasHeader)) {
+      httpChannel->SetRequestHeader(NS_LITERAL_CSTRING("Accept"),
+                                    oldAcceptValue,
+                                    false);
+    }
+  }
+
   nsCOMPtr<nsIHttpChannelInternal> httpInternal = do_QueryInterface(newChannel);
   if (httpInternal) {
     // convey the mForceAllowThirdPartyCookie flag
     httpInternal->SetForceAllowThirdPartyCookie(mForceAllowThirdPartyCookie);
     // convey the spdy flag
     httpInternal->SetAllowSpdy(mAllowSpdy);
 
     // update the DocumentURI indicator since we are being redirected.
new file mode 100644
--- /dev/null
+++ b/netwerk/test/unit/test_bug401564.js
@@ -0,0 +1,49 @@
+/* -*- Mode: JavaScript; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+"use strict";
+Cu.import("resource://testing-common/httpd.js");
+
+var httpserver = null;
+const noRedirectURI = "/content";
+const pageValue = "Final page";
+const acceptType = "application/json";
+
+function redirectHandler(metadata, response)
+{
+  response.setStatusLine(metadata.httpVersion, 302, "Moved Temporarily");
+  response.setHeader("Location", noRedirectURI, false);
+}
+
+function contentHandler(metadata, response)
+{
+  do_check_eq(metadata.getHeader("Accept"), acceptType);
+  httpserver.stop(do_test_finished);
+}
+
+function dummyHandler(request, buffer)
+{
+}
+
+function run_test()
+{
+  httpserver = new HttpServer();
+  httpserver.registerPathHandler("/redirect", redirectHandler);
+  httpserver.registerPathHandler("/content", contentHandler);
+  httpserver.start(-1);
+
+  var prefs = Cc["@mozilla.org/preferences-service;1"]
+                .getService(Components.interfaces.nsIPrefBranch);
+  prefs.setBoolPref("network.http.prompt-temp-redirect", false);
+
+  var ios = Cc["@mozilla.org/network/io-service;1"].getService(Ci.nsIIOService);
+  var chan = ios.newChannel("http://localhost:" +
+                            httpserver.identity.primaryPort + "/redirect",
+                            "",
+                            null);
+
+  chan.QueryInterface(Ci.nsIHttpChannel);
+  chan.setRequestHeader("Accept", acceptType, false);
+
+  chan.asyncOpen(new ChannelListener(dummyHandler, null), null);
+
+  do_test_pending();
+}
--- a/netwerk/test/unit/xpcshell.ini
+++ b/netwerk/test/unit/xpcshell.ini
@@ -91,16 +91,17 @@ skip-if = "FTP channel implementation ne
 [test_bug371473.js]
 [test_bug376660.js]
 [test_bug376844.js]
 [test_bug376865.js]
 [test_bug379034.js]
 [test_bug380994.js]
 [test_bug388281.js]
 [test_bug396389.js]
+[test_bug401564.js]
 [test_bug411952.js]
 [test_bug412945.js]
 [test_bug414122.js]
 [test_bug427957.js]
 [test_bug429347.js]
 [test_bug455311.js]
 [test_bug455598.js]
 [test_bug468426.js]
--- a/testing/marionette/client/marionette/marionette.py
+++ b/testing/marionette/client/marionette/marionette.py
@@ -580,17 +580,17 @@ class Marionette(object):
                     time.sleep(5)
                     return True
             except socket.error:
                 pass
             time.sleep(1)
         return False
 
     def _send_message(self, command, response_key="ok", **kwargs):
-        if not self.session and command not in ("newSession", "getStatus"):
+        if not self.session and command != "newSession":
             raise MarionetteException("Please start a session")
 
         message = {"name": command}
         if self.session:
             message["sessionId"] = self.session
         if kwargs:
             message["parameters"] = kwargs
 
@@ -697,19 +697,16 @@ class Marionette(object):
     def absolute_url(self, relative_url):
         '''
         Returns an absolute url for files served from Marionette's www directory.
 
         :param relative_url: The url of a static file, relative to Marionette's www directory.
         '''
         return "%s%s" % (self.baseurl, relative_url)
 
-    def status(self):
-        return self._send_message('getStatus', 'value')
-
     def start_session(self, desired_capabilities=None):
         """Create a new Marionette session.
 
         This method must be called before performing any other action.
 
         :params desired_capabilities: An optional dict of desired
             capabilities.  This is currently ignored.
 
deleted file mode 100644
--- a/testing/marionette/client/marionette/tests/unit/test_getstatus.py
+++ /dev/null
@@ -1,19 +0,0 @@
-# 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/.
-
-from marionette_test import MarionetteTestCase
-
-class TestGetStatus(MarionetteTestCase):
-    def test_getStatus(self):
-        status = self.marionette.status()
-        self.assertTrue("os" in status)
-        status_os = status['os']
-        self.assertTrue("version" in status_os)
-        self.assertTrue("name" in status_os)
-        self.assertTrue("arch" in status_os)
-        self.assertTrue("build" in status)
-        status_build = status['build']
-        self.assertTrue("revision" in status_build)
-        self.assertTrue("time" in status_build)
-        self.assertTrue("version" in status_build)
--- a/testing/marionette/client/marionette/tests/unit/unit-tests.ini
+++ b/testing/marionette/client/marionette/tests/unit/unit-tests.ini
@@ -10,17 +10,16 @@ b2g = true
 
 ; true if the test should be skipped
 skip = false
 
 [test_session.py]
 
 [test_expectedfail.py]
 expected = fail
-[test_getstatus.py]
 [test_import_script.py]
 [test_import_script_reuse_window.py]
 b2g = false
 [test_click.py]
 [test_click_chrome.py]
 b2g = false
 [test_selected.py]
 [test_selected_chrome.py]
--- a/testing/marionette/marionette-server.js
+++ b/testing/marionette/marionette-server.js
@@ -583,43 +583,16 @@ MarionetteServerConnection.prototype = {
     // compatibility.  They only check for the presence of this
     // property and should so not be in caps if not on a B2G device.
     if (isB2G)
       caps.b2g = true;
 
     this.sendResponse(caps, this.command_id);
   },
 
-  getStatus: function MDA_getStatus(){
-    this.command_id = this.getCommandId();
-
-    let arch;
-    try {
-      arch = (Services.appinfo.XPCOMABI || 'unknown').split('-')[0]
-    }
-    catch (ignored) {
-      arch = 'unknown'
-    };
-
-    let value = {
-          'os': {
-            'arch': arch,
-            'name': Services.appinfo.OS,
-            'version': 'unknown'
-          },
-          'build': {
-            'revision': 'unknown',
-            'time': Services.appinfo.platformBuildID,
-            'version': Services.appinfo.version
-          }
-    };
-
-    this.sendResponse(value, this.command_id);
-  },
-
   /**
    * Log message. Accepts user defined log-level.
    *
    * @param object aRequest
    *        'value' member holds log message
    *        'level' member hold log level
    */
   log: function MDA_log(aRequest) {
@@ -2428,17 +2401,16 @@ MarionetteServerConnection.prototype = {
   }
 };
 
 MarionetteServerConnection.prototype.requestTypes = {
   "getMarionetteID": MarionetteServerConnection.prototype.getMarionetteID,
   "sayHello": MarionetteServerConnection.prototype.sayHello,
   "newSession": MarionetteServerConnection.prototype.newSession,
   "getSessionCapabilities": MarionetteServerConnection.prototype.getSessionCapabilities,
-  "getStatus": MarionetteServerConnection.prototype.getStatus,
   "log": MarionetteServerConnection.prototype.log,
   "getLogs": MarionetteServerConnection.prototype.getLogs,
   "setContext": MarionetteServerConnection.prototype.setContext,
   "executeScript": MarionetteServerConnection.prototype.execute,
   "setScriptTimeout": MarionetteServerConnection.prototype.setScriptTimeout,
   "timeouts": MarionetteServerConnection.prototype.timeouts,
   "singleTap": MarionetteServerConnection.prototype.singleTap,
   "actionChain": MarionetteServerConnection.prototype.actionChain,
--- a/testing/mochitest/tests/SimpleTest/SimpleTest.js
+++ b/testing/mochitest/tests/SimpleTest/SimpleTest.js
@@ -308,16 +308,31 @@ SimpleTest.getTestFileURL = function(pat
 };
 
 SimpleTest._getCurrentTestURL = function() {
     return parentRunner && parentRunner.currentTestURL ||
            typeof gTestPath == "string" && gTestPath ||
            "unknown test url";
 };
 
+SimpleTest._forceLogMessageOutput = false;
+
+/**
+ * Force all test messages to be displayed.  Only applies for the current test.
+ */
+SimpleTest.requestCompleteLog = function() {
+    if (SimpleTest._forceLogMessageOutput)
+        return;
+
+    SimpleTest._forceLogMessageOutput = true;
+    SimpleTest.registerCleanupFunction(function() {
+        SimpleTest._forceLogMessageOutput = false;
+    });
+};
+
 SimpleTest._logResult = (function () {
     var numCoalescedMessages = 1;
     var coalesceThreshold = 100;
 
     function logResult(test, passString, failString) {
         var isError = !test.result == !test.todo;
         var outputCoalescedMessage = numCoalescedMessages == coalesceThreshold;
 
@@ -329,17 +344,18 @@ SimpleTest._logResult = (function () {
         // TEST-PASS/TEST-KNOWN-FAIL messages.  But we always want to log
         // errors and informative messages.  We also want to output messages
         // every so often to let the user know the test is still running.
         // If they user is only running a single test, it is likely that they
         // want to see all the test messages.
         var shouldLog = (isError ||
                          passString == "TEST-INFO" ||
                          outputCoalescedMessage ||
-                         runningSingleTest);
+                         runningSingleTest ||
+                         SimpleTest._forceLogMessageOutput);
 
         if (!shouldLog) {
             ++numCoalescedMessages;
             return;
         }
 
         var resultString = test.result ? passString : failString;
         var url = SimpleTest._getCurrentTestURL();
--- a/toolkit/components/maintenanceservice/Makefile.in
+++ b/toolkit/components/maintenanceservice/Makefile.in
@@ -14,21 +14,16 @@ ifeq ($(OS_ARCH),WINNT)
 LIBS += $(call EXPAND_LIBNAME_PATH,updatecommon-standalone,../../mozapps/update/common-standalone)
 else
 LIBS += $(call EXPAND_LIBNAME_PATH,updatecommon,../../mozapps/update/common)
 endif
 
 RCINCLUDE = maintenanceservice.rc
 
 OS_LIBS += $(call EXPAND_LIBNAME,comctl32 ws2_32 shell32)
-ifndef GNU_CC
-RCFLAGS += -I$(srcdir)
-else
-RCFLAGS += --include-dir $(srcdir)
-endif
 
 ifndef MOZ_WINCONSOLE
 ifdef MOZ_DEBUG
 MOZ_WINCONSOLE = 1
 else
 MOZ_WINCONSOLE = 0
 endif
 endif
--- a/toolkit/mozapps/update/updater/Makefile.in
+++ b/toolkit/mozapps/update/updater/Makefile.in
@@ -17,22 +17,16 @@ LIBS += \
   $(call EXPAND_LIBNAME_PATH,mar,$(DEPTH)/modules/libmar/src) \
   $(MOZ_BZ2_LIBS) \
   $(NULL)
 
 ifeq ($(OS_ARCH),WINNT)
 LIBS += $(call EXPAND_LIBNAME_PATH,verifymar,$(DEPTH)/modules/libmar/verify)
 RCINCLUDE = updater.rc
 OS_LIBS += $(call EXPAND_LIBNAME,comctl32 ws2_32 shell32 shlwapi)
-ifndef GNU_CC
-RCFLAGS += -I$(srcdir)
-else
-RCFLAGS += --include-dir $(srcdir)
-endif
-
 endif
 
 ifdef MOZ_WIDGET_GTK
 OS_CXXFLAGS += $(TK_CFLAGS)
 OS_LIBS += $(TK_LIBS)
 endif
 
 ifeq (cocoa,$(MOZ_WIDGET_TOOLKIT))
@@ -74,16 +68,8 @@ libs::
 endif
 
 ifeq ($(OS_ARCH),WINNT)
 EXTRA_LIBS += $(call EXPAND_LIBNAME,crypt32)
 EXTRA_LIBS += $(call EXPAND_LIBNAME,advapi32)
 endif
 
 CXXFLAGS += $(MOZ_BZ2_CFLAGS)
-
-ifneq (,$(filter beta release esr,$(MOZ_UPDATE_CHANNEL)))
-RCFLAGS += -DMAR_SIGNING_RELEASE_BETA=1
-else
-ifneq (,$(filter nightly aurora nightly-elm nightly-profiling nightly-oak,$(MOZ_UPDATE_CHANNEL)))
-RCFLAGS += -DMAR_SIGNING_AURORA_NIGHTLY=1
-endif
-endif
--- a/toolkit/mozapps/update/updater/moz.build
+++ b/toolkit/mozapps/update/updater/moz.build
@@ -67,8 +67,13 @@ LOCAL_INCLUDES += [
 DELAYLOAD_DLLS += [
     'crypt32.dll',
     'userenv.dll',
     'wsock32.dll',
 ]
 
 if CONFIG['_MSC_VER']:
     WIN32_EXE_LDFLAGS += ['-ENTRY:wmainCRTStartup']
+
+if CONFIG['MOZ_UPDATE_CHANNEL'] in ('beta', 'release', 'esr'):
+    DEFINES['MAR_SIGNING_RELEASE_BETA'] = '1'
+elif CONFIG['MOZ_UPDATE_CHANNEL'] in ('nightly', 'aurora', 'nightly-elm', 'nightly-profiling', 'nightly-oak'):
+    DEFINES['MAR_SIGNING_AURORA_NIGHTLY'] = '1'
--- a/tools/mercurial/hgsetup/wizard.py
+++ b/tools/mercurial/hgsetup/wizard.py
@@ -60,17 +60,17 @@ https://hg.mozilla.org/hgcustom/version-
 MQEXT_INFO = '''
 The mqext extension (https://bitbucket.org/sfink/mqext) provides a number of
 useful abilities to Mercurial, including automatically committing changes to
 your mq patch queue.
 '''.strip()
 
 QIMPORTBZ_INFO = '''
 The qimportbz extension
-(https://hg.mozilla.org/users/robarnold_cmu.edu/qimportbz) makes it possible to
+(https://hg.mozilla.org/hgcustom/version-control-tools/file/default/hgext/qimportbz/README) makes it possible to
 import patches from Bugzilla using a friendly bz:// URL handler. e.g.
 |hg qimport bz://123456|.
 '''.strip()
 
 QNEWCURRENTUSER_INFO = '''
 The mercurial queues command |hg qnew|, which creates new patches in your patch
 queue does not set patch author information by default. Author information
 should be included when uploading for review.
@@ -201,33 +201,28 @@ class MercurialSetupWizard(object):
             if update_mqext:
                 self.update_mercurial_repo(
                 hg,
                 'https://bitbucket.org/sfink/mqext',
                 os.path.join(self.ext_dir, 'mqext'),
                 'default',
                 'Ensuring mqext extension is up to date...')
 
-            update_qimportbz = 'qimportbz' in active
+            activate_qimportbz = True
             if 'qimportbz' not in active:
                 print(QIMPORTBZ_INFO)
-                if self._prompt_yn('Would you like to activate qimportbz'):
-                    update_qimportbz = True
-                    c.activate_extension('qimportbz',
-                        os.path.join(self.ext_dir, 'qimportbz'))
-                    print('Activated qimportbz extension.')
-                    print('')
+                if not self._prompt_yn('Would you like to activate qimportbz'):
+                    activate_qimportbz = False
 
-            if update_qimportbz:
-                self.update_mercurial_repo(
-                    hg,
-                    'https://hg.mozilla.org/users/robarnold_cmu.edu/qimportbz',
-                    os.path.join(self.ext_dir, 'qimportbz'),
-                    'default',
-                    'Ensuring qimportbz extension is up to date...')
+            if activate_qimportbz:
+                update_vcs_tools = True
+                c.activate_extension('qimportbz',
+                    os.path.join(self.vcs_tools_dir, 'hgext', 'qimportbz'))
+                print('Activated qimportbz extension.')
+                print('')
 
             if not c.have_qnew_currentuser_default():
                 print(QNEWCURRENTUSER_INFO)
                 if self._prompt_yn('Would you like qnew to set patch author by '
                                    'default'):
                     c.ensure_qnew_currentuser_default()
                     print('Configured qnew to set patch author by default.')
                     print('')
@@ -236,17 +231,17 @@ class MercurialSetupWizard(object):
             self.update_mercurial_repo(
                 hg,
                 'https://hg.mozilla.org/hgcustom/version-control-tools',
                 self.vcs_tools_dir,
                 'default',
                 'Ensuring version-control-tools is up to date...')
 
         # Look for and clean up old extensions.
-        for ext in {'bzexport',}:
+        for ext in {'bzexport', 'qimportbz'}:
             path = os.path.join(self.ext_dir, ext)
             if os.path.exists(path):
                 if self._prompt_yn('Would you like to remove the old and no '
                     'longer referenced repository at %s' % path):
                     print('Cleaning up old repository: %s' % path)
                     shutil.rmtree(path)
 
         c.add_mozilla_host_fingerprints()
--- a/webapprt/win/Makefile.in
+++ b/webapprt/win/Makefile.in
@@ -26,24 +26,16 @@ include $(topsrcdir)/toolkit/mozapps/ins
 CONFIG_DIR = instgen
 SFX_MODULE = $(topsrcdir)/other-licenses/7zstub/firefox/7zSD.sfx
 APP_VERSION := $(shell cat $(topsrcdir)/browser/config/version.txt)
 DEFINES += -DAPP_VERSION=$(APP_VERSION)
 
 OS_LIBS += $(call EXPAND_LIBNAME,shell32)
 
 RCINCLUDE = webapprt.rc
-ifndef GNU_CC
-RCFLAGS += -I$(srcdir)
-else
-RCFLAGS += --include-dir $(srcdir)
-endif
-ifdef DEBUG
-RCFLAGS += -DDEBUG
-endif
 
 # Uninstaller
 ifdef LOCALE_MERGEDIR
 PPL_LOCALE_ARGS = \
   --l10n-dir=$(LOCALE_MERGEDIR)/webapprt/webapp-uninstaller \
   --l10n-dir=$(call EXPAND_LOCALE_SRCDIR,webapprt/locales)/webapp-uninstaller \
   --l10n-dir=$(topsrcdir)/webapprt/locales/en-US/webapp-uninstaller \
   $(NULL)
--- a/webapprt/win/moz.build
+++ b/webapprt/win/moz.build
@@ -6,16 +6,18 @@
 
 PROGRAM = 'webapprt-stub'
 
 SOURCES += [
     'webapprt.cpp',
 ]
 
 DEFINES['XPCOM_GLUE'] = True
+if CONFIG['DEBUG']:
+    DEFINES['DEBUG'] = True
 
 # Statically link against the CRT
 USE_STATIC_LIBS = True
 
 GENERATED_INCLUDES += ['/build']
 LOCAL_INCLUDES += [
     '/toolkit/xre',
     '/xpcom/base',
--- a/widget/gonk/nativewindow/FakeSurfaceComposer.cpp
+++ b/widget/gonk/nativewindow/FakeSurfaceComposer.cpp
@@ -54,16 +54,22 @@ sp<IGraphicBufferAlloc> FakeSurfaceCompo
 }
 
 sp<IBinder> FakeSurfaceComposer::createDisplay(const String8& displayName,
         bool secure)
 {
     return nullptr;
 }
 
+#if ANDROID_VERSION >= 19
+void FakeSurfaceComposer::destroyDisplay(const sp<IBinder>& display)
+{
+}
+#endif
+
 sp<IBinder> FakeSurfaceComposer::getBuiltInDisplay(int32_t id) {
     return nullptr;
 }
 
 void FakeSurfaceComposer::setTransactionState(
         const Vector<ComposerState>& state,
         const Vector<DisplayState>& displays,
         uint32_t flags)
@@ -86,16 +92,25 @@ sp<IDisplayEventConnection> FakeSurfaceC
 status_t FakeSurfaceComposer::captureScreen(const sp<IBinder>& display,
         const sp<IGraphicBufferProducer>& producer,
         uint32_t reqWidth, uint32_t reqHeight,
         uint32_t minLayerZ, uint32_t maxLayerZ,
         bool isCpuConsumer) {
     return INVALID_OPERATION;
 }
 
+#if ANDROID_VERSION >= 19
+status_t FakeSurfaceComposer::captureScreen(const sp<IBinder>& display,
+    const sp<IGraphicBufferProducer>& producer,
+    uint32_t reqWidth, uint32_t reqHeight,
+    uint32_t minLayerZ, uint32_t maxLayerZ) {
+    return INVALID_OPERATION;
+}
+#endif
+
 void FakeSurfaceComposer::blank(const sp<IBinder>& display) {
 }
 
 void FakeSurfaceComposer::unblank(const sp<IBinder>& display) {
 }
 
 status_t FakeSurfaceComposer::getDisplayInfo(const sp<IBinder>& display, DisplayInfo* info) {
     return INVALID_OPERATION;
--- a/widget/gonk/nativewindow/FakeSurfaceComposer.h
+++ b/widget/gonk/nativewindow/FakeSurfaceComposer.h
@@ -40,16 +40,21 @@ class FakeSurfaceComposer : public Binde
 public:
     static char const* getServiceName() {
         return "FakeSurfaceComposer";
     }
 
     // Instantiate MediaResourceManagerService and register to service manager.
     // If service manager is not present, wait until service manager becomes present.
     static  void instantiate();
+#if ANDROID_VERSION >= 19
+    virtual void destroyDisplay(const sp<android::IBinder>& display);
+    virtual status_t captureScreen(const sp<IBinder>& display, const sp<IGraphicBufferProducer>& producer,
+            uint32_t reqWidth, uint32_t reqHeight, uint32_t minLayerZ, uint32_t maxLayerZ);
+#endif
 
 private:
     FakeSurfaceComposer();
     // We're reference counted, never destroy FakeSurfaceComposer directly
     virtual ~FakeSurfaceComposer();
 
     /* ------------------------------------------------------------------------
      * ISurfaceComposer interface
--- a/widget/gonk/nativewindow/GonkBufferQueue.h
+++ b/widget/gonk/nativewindow/GonkBufferQueue.h
@@ -1,662 +1,20 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- * Copyright (C) 2013 Mozilla Foundation
+/* Copyright 2013 Mozilla Foundation and Mozilla contributors
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * You may obtain a copy of the License at
  *
- *      http://www.apache.org/licenses/LICENSE-2.0
+ *     http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
 
-#ifndef NATIVEWINDOW_GONKBUFFERQUEUE_H
-#define NATIVEWINDOW_GONKBUFFERQUEUE_H
-
-#include <gui/IGraphicBufferAlloc.h>
-#if ANDROID_VERSION == 17
-#include <gui/ISurfaceTexture.h>
-#else
-#include <gui/IGraphicBufferProducer.h>
-#endif
-
-#include <ui/Fence.h>
-#include <ui/GraphicBuffer.h>
-
-#include <utils/String8.h>
-#include <utils/Vector.h>
-#include <utils/threads.h>
-
-#include "mozilla/layers/LayersSurfaces.h"
-
-#if ANDROID_VERSION == 17
-#define IGraphicBufferProducer ISurfaceTexture
-#endif
-
-namespace android {
-// ----------------------------------------------------------------------------
-
-#if ANDROID_VERSION == 17
-class GonkBufferQueue : public BnSurfaceTexture {
-#else
-class GonkBufferQueue : public BnGraphicBufferProducer {
-#endif
-    typedef mozilla::layers::SurfaceDescriptor SurfaceDescriptor;
-
-public:
-    enum { MIN_UNDEQUEUED_BUFFERS = 2 };
-    enum { NUM_BUFFER_SLOTS = 32 };
-    enum { NO_CONNECTED_API = 0 };
-    enum { INVALID_BUFFER_SLOT = -1 };
-    enum { STALE_BUFFER_SLOT = 1, NO_BUFFER_AVAILABLE };
-
-    // When in async mode we reserve two slots in order to guarantee that the
-    // producer and consumer can run asynchronously.
-    enum { MAX_MAX_ACQUIRED_BUFFERS = NUM_BUFFER_SLOTS - 2 };
-
-    // ConsumerListener is the interface through which the GonkBufferQueue notifies
-    // the consumer of events that the consumer may wish to react to.  Because
-    // the consumer will generally have a mutex that is locked during calls from
-    // the consumer to the GonkBufferQueue, these calls from the GonkBufferQueue to the
-    // consumer *MUST* be called only when the GonkBufferQueue mutex is NOT locked.
-    struct ConsumerListener : public virtual RefBase {
-        // onFrameAvailable is called from queueBuffer each time an additional
-        // frame becomes available for consumption. This means that frames that
-        // are queued while in asynchronous mode only trigger the callback if no
-        // previous frames are pending. Frames queued while in synchronous mode
-        // always trigger the callback.
-        //
-        // This is called without any lock held and can be called concurrently
-        // by multiple threads.
-        virtual void onFrameAvailable() = 0;
-
-        // onBuffersReleased is called to notify the buffer consumer that the
-        // GonkBufferQueue has released its references to one or more GraphicBuffers
-        // contained in its slots.  The buffer consumer should then call
-        // GonkBufferQueue::getReleasedBuffers to retrieve the list of buffers
-        //
-        // This is called without any lock held and can be called concurrently
-        // by multiple threads.
-        virtual void onBuffersReleased() = 0;
-    };
-
-    // ProxyConsumerListener is a ConsumerListener implementation that keeps a weak
-    // reference to the actual consumer object.  It forwards all calls to that
-    // consumer object so long as it exists.
-    //
-    // This class exists to avoid having a circular reference between the
-    // GonkBufferQueue object and the consumer object.  The reason this can't be a weak
-    // reference in the GonkBufferQueue class is because we're planning to expose the
-    // consumer side of a GonkBufferQueue as a binder interface, which doesn't support
-    // weak references.
-    class ProxyConsumerListener : public GonkBufferQueue::ConsumerListener {
-    public:
-
-        ProxyConsumerListener(const wp<GonkBufferQueue::ConsumerListener>& consumerListener);
-        virtual ~ProxyConsumerListener();
-        virtual void onFrameAvailable();
-        virtual void onBuffersReleased();
-
-    private:
-
-        // mConsumerListener is a weak reference to the ConsumerListener.  This is
-        // the raison d'etre of ProxyConsumerListener.
-        wp<GonkBufferQueue::ConsumerListener> mConsumerListener;
-    };
-
-
-    // GonkBufferQueue manages a pool of gralloc memory slots to be used by
-    // producers and consumers. allowSynchronousMode specifies whether or not
-    // synchronous mode can be enabled by the producer. allocator is used to
-    // allocate all the needed gralloc buffers.
-    GonkBufferQueue(bool allowSynchronousMode = true,
-            const sp<IGraphicBufferAlloc>& allocator = NULL);
-    virtual ~GonkBufferQueue();
-
-    // Query native window attributes.  The "what" values are enumerated in
-    // window.h (e.g. NATIVE_WINDOW_FORMAT).
-    virtual int query(int what, int* value);
-
-    // setBufferCount updates the number of available buffer slots.  If this
-    // method succeeds, buffer slots will be both unallocated and owned by
-    // the GonkBufferQueue object (i.e. they are not owned by the producer or
-    // consumer).
-    //
-    // This will fail if the producer has dequeued any buffers, or if
-    // bufferCount is invalid.  bufferCount must generally be a value
-    // between the minimum undequeued buffer count and NUM_BUFFER_SLOTS
-    // (inclusive).  It may also be set to zero (the default) to indicate
-    // that the producer does not wish to set a value.  The minimum value
-    // can be obtained by calling query(NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS,
-    // ...).
-    //
-    // This may only be called by the producer.  The consumer will be told
-    // to discard buffers through the onBuffersReleased callback.
-    virtual status_t setBufferCount(int bufferCount);
-
-    // requestBuffer returns the GraphicBuffer for slot N.
-    //
-    // In normal operation, this is called the first time slot N is returned
-    // by dequeueBuffer.  It must be called again if dequeueBuffer returns
-    // flags indicating that previously-returned buffers are no longer valid.
-    virtual status_t requestBuffer(int slot, sp<GraphicBuffer>* buf);
-
-    // dequeueBuffer gets the next buffer slot index for the producer to use.
-    // If a buffer slot is available then that slot index is written to the
-    // location pointed to by the buf argument and a status of OK is returned.
-    // If no slot is available then a status of -EBUSY is returned and buf is
-    // unmodified.
-    //
-    // The fence parameter will be updated to hold the fence associated with
-    // the buffer. The contents of the buffer must not be overwritten until the
-    // fence signals. If the fence is Fence::NO_FENCE, the buffer may be
-    // written immediately.
-    //
-    // The width and height parameters must be no greater than the minimum of
-    // GL_MAX_VIEWPORT_DIMS and GL_MAX_TEXTURE_SIZE (see: glGetIntegerv).
-    // An error due to invalid dimensions might not be reported until
-    // updateTexImage() is called.  If width and height are both zero, the
-    // default values specified by setDefaultBufferSize() are used instead.
-    //
-    // The pixel formats are enumerated in graphics.h, e.g.
-    // HAL_PIXEL_FORMAT_RGBA_8888.  If the format is 0, the default format
-    // will be used.
-    //
-    // The usage argument specifies gralloc buffer usage flags.  The values
-    // are enumerated in gralloc.h, e.g. GRALLOC_USAGE_HW_RENDER.  These
-    // will be merged with the usage flags specified by setConsumerUsageBits.
-    //
-    // The return value may be a negative error value or a non-negative
-    // collection of flags.  If the flags are set, the return values are
-    // valid, but additional actions must be performed.
-    //
-    // If IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION is set, the
-    // producer must discard cached GraphicBuffer references for the slot
-    // returned in buf.
-    // If IGraphicBufferProducer::RELEASE_ALL_BUFFERS is set, the producer
-    // must discard cached GraphicBuffer references for all slots.
-    //
-    // In both cases, the producer will need to call requestBuffer to get a
-    // GraphicBuffer handle for the returned slot.
-#if ANDROID_VERSION == 17
-    virtual status_t dequeueBuffer(int *buf, sp<Fence>& fence,
-            uint32_t width, uint32_t height, uint32_t format, uint32_t usage) {
-        return dequeueBuffer(buf, &fence, width, height, format, usage);
-    }
-#endif
-
-    virtual status_t dequeueBuffer(int *buf, sp<Fence>* fence,
-            uint32_t width, uint32_t height, uint32_t format, uint32_t usage);
-
-    // queueBuffer returns a filled buffer to the GonkBufferQueue.
-    //
-    // Additional data is provided in the QueueBufferInput struct.  Notably,
-    // a timestamp must be provided for the buffer. The timestamp is in
-    // nanoseconds, and must be monotonically increasing. Its other semantics
-    // (zero point, etc) are producer-specific and should be documented by the
-    // producer.
-    //
-    // The caller may provide a fence that signals when all rendering
-    // operations have completed.  Alternatively, NO_FENCE may be used,
-    // indicating that the buffer is ready immediately.
-    //
-    // Some values are returned in the output struct: the current settings
-    // for default width and height, the current transform hint, and the
-    // number of queued buffers.
-    virtual status_t queueBuffer(int buf,
-            const QueueBufferInput& input, QueueBufferOutput* output);
-
-    // cancelBuffer returns a dequeued buffer to the GonkBufferQueue, but doesn't
-    // queue it for use by the consumer.
-    //
-    // The buffer will not be overwritten until the fence signals.  The fence
-    // will usually be the one obtained from dequeueBuffer.
-#if ANDROID_VERSION == 17
-    virtual void cancelBuffer(int buf, sp<Fence> fence);
-#else
-    virtual void cancelBuffer(int buf, const sp<Fence>& fence);
+#if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 19
+# include "GonkBufferQueueKK.h"
+#elif defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 17
+# include "GonkBufferQueueJB.h"
 #endif
-
-    // setSynchronousMode sets whether dequeueBuffer is synchronous or
-    // asynchronous. In synchronous mode, dequeueBuffer blocks until
-    // a buffer is available, the currently bound buffer can be dequeued and
-    // queued buffers will be acquired in order.  In asynchronous mode,
-    // a queued buffer may be replaced by a subsequently queued buffer.
-    //
-    // The default mode is asynchronous.
-    virtual status_t setSynchronousMode(bool enabled);
-
-    // connect attempts to connect a producer API to the GonkBufferQueue.  This
-    // must be called before any other IGraphicBufferProducer methods are
-    // called except for getAllocator.  A consumer must already be connected.
-    //
-    // This method will fail if connect was previously called on the
-    // GonkBufferQueue and no corresponding disconnect call was made (i.e. if
-    // it's still connected to a producer).
-    //
-    // APIs are enumerated in window.h (e.g. NATIVE_WINDOW_API_CPU).
-    virtual status_t connect(int api, QueueBufferOutput* output);
-
-    // disconnect attempts to disconnect a producer API from the GonkBufferQueue.
-    // Calling this method will cause any subsequent calls to other
-    // IGraphicBufferProducer methods to fail except for getAllocator and connect.
-    // Successfully calling connect after this will allow the other methods to
-    // succeed again.
-    //
-    // This method will fail if the the GonkBufferQueue is not currently
-    // connected to the specified producer API.
-    virtual status_t disconnect(int api);
-
-    // dump our state in a String
-    virtual void dump(String8& result) const;
-    virtual void dump(String8& result, const char* prefix, char* buffer, size_t SIZE) const;
-
-    // public facing structure for BufferSlot
-    struct BufferItem {
-
-        BufferItem()
-         :
-           mSurfaceDescriptor(SurfaceDescriptor()),
-           mTransform(0),
-           mScalingMode(NATIVE_WINDOW_SCALING_MODE_FREEZE),
-           mTimestamp(0),
-           mFrameNumber(0),
-           mBuf(INVALID_BUFFER_SLOT) {
-             mCrop.makeInvalid();
-        }
-        // mGraphicBuffer points to the buffer allocated for this slot, or is NULL
-        // if the buffer in this slot has been acquired in the past (see
-        // BufferSlot.mAcquireCalled).
-        sp<GraphicBuffer> mGraphicBuffer;
-
-        // mSurfaceDescriptor is the token to remotely allocated GraphicBuffer.
-        SurfaceDescriptor mSurfaceDescriptor;
-
-        // mCrop is the current crop rectangle for this buffer slot.
-        Rect mCrop;
-
-        // mTransform is the current transform flags for this buffer slot.
-        uint32_t mTransform;
-
-        // mScalingMode is the current scaling mode for this buffer slot.
-        uint32_t mScalingMode;
-
-        // mTimestamp is the current timestamp for this buffer slot. This gets
-        // to set by queueBuffer each time this slot is queued.
-        int64_t mTimestamp;
-
-        // mFrameNumber is the number of the queued frame for this slot.
-        uint64_t mFrameNumber;
-
-        // mBuf is the slot index of this buffer
-        int mBuf;
-
-        // mFence is a fence that will signal when the buffer is idle.
-        sp<Fence> mFence;
-    };
-
-    // The following public functions are the consumer-facing interface
-
-    // acquireBuffer attempts to acquire ownership of the next pending buffer in
-    // the GonkBufferQueue.  If no buffer is pending then it returns -EINVAL.  If a
-    // buffer is successfully acquired, the information about the buffer is
-    // returned in BufferItem.  If the buffer returned had previously been
-    // acquired then the BufferItem::mGraphicBuffer field of buffer is set to
-    // NULL and it is assumed that the consumer still holds a reference to the
-    // buffer.
-    status_t acquireBuffer(BufferItem *buffer);
-
-    // releaseBuffer releases a buffer slot from the consumer back to the
-    // GonkBufferQueue.  This may be done while the buffer's contents are still
-    // being accessed.  The fence will signal when the buffer is no longer
-    // in use.
-    //
-    // If releaseBuffer returns STALE_BUFFER_SLOT, then the consumer must free
-    // any references to the just-released buffer that it might have, as if it
-    // had received a onBuffersReleased() call with a mask set for the released
-    // buffer.
-    //
-    // Note that the dependencies on EGL will be removed once we switch to using
-    // the Android HW Sync HAL.
-    status_t releaseBuffer(int buf, const sp<Fence>& releaseFence);
-
-    // consumerConnect connects a consumer to the GonkBufferQueue.  Only one
-    // consumer may be connected, and when that consumer disconnects the
-    // GonkBufferQueue is placed into the "abandoned" state, causing most
-    // interactions with the GonkBufferQueue by the producer to fail.
-    //
-    // consumer may not be NULL.
-    status_t consumerConnect(const sp<ConsumerListener>& consumer);
-
-    // consumerDisconnect disconnects a consumer from the GonkBufferQueue. All
-    // buffers will be freed and the GonkBufferQueue is placed in the "abandoned"
-    // state, causing most interactions with the GonkBufferQueue by the producer to
-    // fail.
-    status_t consumerDisconnect();
-
-    // getReleasedBuffers sets the value pointed to by slotMask to a bit mask
-    // indicating which buffer slots have been released by the GonkBufferQueue
-    // but have not yet been released by the consumer.
-    //
-    // This should be called from the onBuffersReleased() callback.
-    status_t getReleasedBuffers(uint32_t* slotMask);
-
-    // setDefaultBufferSize is used to set the size of buffers returned by
-    // dequeueBuffer when a width and height of zero is requested.  Default
-    // is 1x1.
-    status_t setDefaultBufferSize(uint32_t w, uint32_t h);
-
-    // setDefaultMaxBufferCount sets the default value for the maximum buffer
-    // count (the initial default is 2). If the producer has requested a
-    // buffer count using setBufferCount, the default buffer count will only
-    // take effect if the producer sets the count back to zero.
-    //
-    // The count must be between 2 and NUM_BUFFER_SLOTS, inclusive.
-    status_t setDefaultMaxBufferCount(int bufferCount);
-
-    // setMaxAcquiredBufferCount sets the maximum number of buffers that can
-    // be acquired by the consumer at one time (default 1).  This call will
-    // fail if a producer is connected to the GonkBufferQueue.
-    status_t setMaxAcquiredBufferCount(int maxAcquiredBuffers);
-
-    // isSynchronousMode returns whether the GonkBufferQueue is currently in
-    // synchronous mode.
-    bool isSynchronousMode() const;
-
-    // setConsumerName sets the name used in logging
-    void setConsumerName(const String8& name);
-
-    // setDefaultBufferFormat allows the GonkBufferQueue to create
-    // GraphicBuffers of a defaultFormat if no format is specified
-    // in dequeueBuffer.  Formats are enumerated in graphics.h; the
-    // initial default is HAL_PIXEL_FORMAT_RGBA_8888.
-    status_t setDefaultBufferFormat(uint32_t defaultFormat);
-
-    // setConsumerUsageBits will turn on additional usage bits for dequeueBuffer.
-    // These are merged with the bits passed to dequeueBuffer.  The values are
-    // enumerated in gralloc.h, e.g. GRALLOC_USAGE_HW_RENDER; the default is 0.
-    status_t setConsumerUsageBits(uint32_t usage);
-
-    // setTransformHint bakes in rotation to buffers so overlays can be used.
-    // The values are enumerated in window.h, e.g.
-    // NATIVE_WINDOW_TRANSFORM_ROT_90.  The default is 0 (no transform).
-    status_t setTransformHint(uint32_t hint);
-
-    int getGeneration();
-
-    SurfaceDescriptor *getSurfaceDescriptorFromBuffer(ANativeWindowBuffer* buffer);
-
-private:
-    // releaseBufferFreeListUnlocked releases the resources in the freeList;
-    // this must be called with mMutex unlocked.
-    void releaseBufferFreeListUnlocked(nsTArray<SurfaceDescriptor>& freeList);
-
-    // freeBufferLocked frees the GraphicBuffer and sync resources for the
-    // given slot.
-    //void freeBufferLocked(int index);
-
-    // freeAllBuffersLocked frees the GraphicBuffer and sync resources for
-    // all slots.
-    //void freeAllBuffersLocked();
-    void freeAllBuffersLocked(nsTArray<SurfaceDescriptor>& freeList);
-
-    // setDefaultMaxBufferCountLocked sets the maximum number of buffer slots
-    // that will be used if the producer does not override the buffer slot
-    // count.  The count must be between 2 and NUM_BUFFER_SLOTS, inclusive.
-    // The initial default is 2.
-    status_t setDefaultMaxBufferCountLocked(int count);
-
-    // getMinBufferCountLocked returns the minimum number of buffers allowed
-    // given the current GonkBufferQueue state.
-    int getMinMaxBufferCountLocked() const;
-
-    // getMinUndequeuedBufferCountLocked returns the minimum number of buffers
-    // that must remain in a state other than DEQUEUED.
-    int getMinUndequeuedBufferCountLocked() const;
-
-    // getMaxBufferCountLocked returns the maximum number of buffers that can
-    // be allocated at once.  This value depends upon the following member
-    // variables:
-    //
-    //      mSynchronousMode
-    //      mMaxAcquiredBufferCount
-    //      mDefaultMaxBufferCount
-    //      mOverrideMaxBufferCount
-    //
-    // Any time one of these member variables is changed while a producer is
-    // connected, mDequeueCondition must be broadcast.
-    int getMaxBufferCountLocked() const;
-
-    struct BufferSlot {
-
-        BufferSlot()
-        : mSurfaceDescriptor(SurfaceDescriptor()),
-          mBufferState(BufferSlot::FREE),
-          mRequestBufferCalled(false),
-          mTransform(0),
-          mScalingMode(NATIVE_WINDOW_SCALING_MODE_FREEZE),
-          mTimestamp(0),
-          mFrameNumber(0),
-          mAcquireCalled(false),
-          mNeedsCleanupOnRelease(false) {
-            mCrop.makeInvalid();
-        }
-
-        // mGraphicBuffer points to the buffer allocated for this slot or is NULL
-        // if no buffer has been allocated.
-        sp<GraphicBuffer> mGraphicBuffer;
-
-        // mSurfaceDescriptor is the token to remotely allocated GraphicBuffer.
-        SurfaceDescriptor mSurfaceDescriptor;
-
-        // BufferState represents the different states in which a buffer slot
-        // can be.  All slots are initially FREE.
-        enum BufferState {
-            // FREE indicates that the buffer is available to be dequeued
-            // by the producer.  The buffer may be in use by the consumer for
-            // a finite time, so the buffer must not be modified until the
-            // associated fence is signaled.
-            //
-            // The slot is "owned" by GonkBufferQueue.  It transitions to DEQUEUED
-            // when dequeueBuffer is called.
-            FREE = 0,
-
-            // DEQUEUED indicates that the buffer has been dequeued by the
-            // producer, but has not yet been queued or canceled.  The
-            // producer may modify the buffer's contents as soon as the
-            // associated ready fence is signaled.
-            //
-            // The slot is "owned" by the producer.  It can transition to
-            // QUEUED (via queueBuffer) or back to FREE (via cancelBuffer).
-            DEQUEUED = 1,
-
-            // QUEUED indicates that the buffer has been filled by the
-            // producer and queued for use by the consumer.  The buffer
-            // contents may continue to be modified for a finite time, so
-            // the contents must not be accessed until the associated fence
-            // is signaled.
-            //
-            // The slot is "owned" by GonkBufferQueue.  It can transition to
-            // ACQUIRED (via acquireBuffer) or to FREE (if another buffer is
-            // queued in asynchronous mode).
-            QUEUED = 2,
-
-            // ACQUIRED indicates that the buffer has been acquired by the
-            // consumer.  As with QUEUED, the contents must not be accessed
-            // by the consumer until the fence is signaled.
-            //
-            // The slot is "owned" by the consumer.  It transitions to FREE
-            // when releaseBuffer is called.
-            ACQUIRED = 3
-        };
-
-        // mBufferState is the current state of this buffer slot.
-        BufferState mBufferState;
-
-        // mRequestBufferCalled is used for validating that the producer did
-        // call requestBuffer() when told to do so. Technically this is not
-        // needed but useful for debugging and catching producer bugs.
-        bool mRequestBufferCalled;
-
-        // mCrop is the current crop rectangle for this buffer slot.
-        Rect mCrop;
-
-        // mTransform is the current transform flags for this buffer slot.
-        // (example: NATIVE_WINDOW_TRANSFORM_ROT_90)
-        uint32_t mTransform;
-
-        // mScalingMode is the current scaling mode for this buffer slot.
-        // (example: NATIVE_WINDOW_SCALING_MODE_FREEZE)
-        uint32_t mScalingMode;
-
-        // mTimestamp is the current timestamp for this buffer slot. This gets
-        // to set by queueBuffer each time this slot is queued.
-        int64_t mTimestamp;
-
-        // mFrameNumber is the number of the queued frame for this slot.  This
-        // is used to dequeue buffers in LRU order (useful because buffers
-        // may be released before their release fence is signaled).
-        uint64_t mFrameNumber;
-
-        // mEglFence is the EGL sync object that must signal before the buffer
-        // associated with this buffer slot may be dequeued. It is initialized
-        // to EGL_NO_SYNC_KHR when the buffer is created and may be set to a
-        // new sync object in releaseBuffer.  (This is deprecated in favor of
-        // mFence, below.)
-        //EGLSyncKHR mEglFence;
-
-        // mFence is a fence which will signal when work initiated by the
-        // previous owner of the buffer is finished. When the buffer is FREE,
-        // the fence indicates when the consumer has finished reading
-        // from the buffer, or when the producer has finished writing if it
-        // called cancelBuffer after queueing some writes. When the buffer is
-        // QUEUED, it indicates when the producer has finished filling the
-        // buffer. When the buffer is DEQUEUED or ACQUIRED, the fence has been
-        // passed to the consumer or producer along with ownership of the
-        // buffer, and mFence is set to NO_FENCE.
-        sp<Fence> mFence;
-
-        // Indicates whether this buffer has been seen by a consumer yet
-        bool mAcquireCalled;
-
-        // Indicates whether this buffer needs to be cleaned up by the
-        // consumer.  This is set when a buffer in ACQUIRED state is freed.
-        // It causes releaseBuffer to return STALE_BUFFER_SLOT.
-        bool mNeedsCleanupOnRelease;
-    };
-
-    // mSlots is the array of buffer slots that must be mirrored on the
-    // producer side. This allows buffer ownership to be transferred between
-    // the producer and consumer without sending a GraphicBuffer over binder.
-    // The entire array is initialized to NULL at construction time, and
-    // buffers are allocated for a slot when requestBuffer is called with
-    // that slot's index.
-    BufferSlot mSlots[NUM_BUFFER_SLOTS];
-
-    // mDefaultWidth holds the default width of allocated buffers. It is used
-    // in dequeueBuffer() if a width and height of zero is specified.
-    uint32_t mDefaultWidth;
-
-    // mDefaultHeight holds the default height of allocated buffers. It is used
-    // in dequeueBuffer() if a width and height of zero is specified.
-    uint32_t mDefaultHeight;
-
-    // mMaxAcquiredBufferCount is the number of buffers that the consumer may
-    // acquire at one time.  It defaults to 1 and can be changed by the
-    // consumer via the setMaxAcquiredBufferCount method, but this may only be
-    // done when no producer is connected to the GonkBufferQueue.
-    //
-    // This value is used to derive the value returned for the
-    // MIN_UNDEQUEUED_BUFFERS query by the producer.
-    int mMaxAcquiredBufferCount;
-
-    // mDefaultMaxBufferCount is the default limit on the number of buffers
-    // that will be allocated at one time.  This default limit is set by the
-    // consumer.  The limit (as opposed to the default limit) may be
-    // overridden by the producer.
-    int mDefaultMaxBufferCount;
-
-    // mOverrideMaxBufferCount is the limit on the number of buffers that will
-    // be allocated at one time. This value is set by the image producer by
-    // calling setBufferCount. The default is zero, which means the producer
-    // doesn't care about the number of buffers in the pool. In that case
-    // mDefaultMaxBufferCount is used as the limit.
-    int mOverrideMaxBufferCount;
-
-    // mGraphicBufferAlloc is the connection to SurfaceFlinger that is used to
-    // allocate new GraphicBuffer objects.
-    sp<IGraphicBufferAlloc> mGraphicBufferAlloc;
-
-    // mConsumerListener is used to notify the connected consumer of
-    // asynchronous events that it may wish to react to.  It is initially set
-    // to NULL and is written by consumerConnect and consumerDisconnect.
-    sp<ConsumerListener> mConsumerListener;
-
-    // mSynchronousMode whether we're in synchronous mode or not
-    bool mSynchronousMode;
-
-    // mAllowSynchronousMode whether we allow synchronous mode or not.  Set
-    // when the GonkBufferQueue is created (by the consumer).
-    const bool mAllowSynchronousMode;
-
-    // mConnectedApi indicates the producer API that is currently connected
-    // to this GonkBufferQueue.  It defaults to NO_CONNECTED_API (= 0), and gets
-    // updated by the connect and disconnect methods.
-    int mConnectedApi;
-
-    // mDequeueCondition condition used for dequeueBuffer in synchronous mode
-    mutable Condition mDequeueCondition;
-
-    // mQueue is a FIFO of queued buffers used in synchronous mode
-    typedef Vector<int> Fifo;
-    Fifo mQueue;
-
-    // mAbandoned indicates that the GonkBufferQueue will no longer be used to
-    // consume image buffers pushed to it using the IGraphicBufferProducer
-    // interface.  It is initialized to false, and set to true in the
-    // consumerDisconnect method.  A GonkBufferQueue that has been abandoned will
-    // return the NO_INIT error from all IGraphicBufferProducer methods
-    // capable of returning an error.
-    bool mAbandoned;
-
-    // mConsumerName is a string used to identify the GonkBufferQueue in log
-    // messages.  It is set by the setConsumerName method.
-    String8 mConsumerName;
-
-    // mMutex is the mutex used to prevent concurrent access to the member
-    // variables of GonkBufferQueue objects. It must be locked whenever the
-    // member variables are accessed.
-    mutable Mutex mMutex;
-
-    // mFrameCounter is the free running counter, incremented on every
-    // successful queueBuffer call.
-    uint64_t mFrameCounter;
-
-    // mBufferHasBeenQueued is true once a buffer has been queued.  It is
-    // reset when something causes all buffers to be freed (e.g. changing the
-    // buffer count).
-    bool mBufferHasBeenQueued;
-
-    // mDefaultBufferFormat can be set so it will override
-    // the buffer format when it isn't specified in dequeueBuffer
-    uint32_t mDefaultBufferFormat;
-
-    // mConsumerUsageBits contains flags the consumer wants for GraphicBuffers
-    uint32_t mConsumerUsageBits;
-
-    // mTransformHint is used to optimize for screen rotations
-    uint32_t mTransformHint;
-
-    // mGeneration is the current generation of buffer slots
-    uint32_t mGeneration;
-};
-
-// ----------------------------------------------------------------------------
-}; // namespace android
-
-#endif // ANDROID_GUI_BUFFERQUEUE_H
rename from widget/gonk/nativewindow/GonkBufferQueue.cpp
rename to widget/gonk/nativewindow/GonkBufferQueueJB.cpp
--- a/widget/gonk/nativewindow/GonkBufferQueue.cpp
+++ b/widget/gonk/nativewindow/GonkBufferQueueJB.cpp
@@ -21,17 +21,17 @@
 
 #define GL_GLEXT_PROTOTYPES
 #define EGL_EGLEXT_PROTOTYPES
 
 #include <utils/Log.h>
 
 #include "mozilla/layers/ImageBridgeChild.h"
 
-#include "GonkBufferQueue.h"
+#include "GonkBufferQueueJB.h"
 
 // Macros for including the GonkBufferQueue name in log messages
 #define ST_LOGV(...) __android_log_print(ANDROID_LOG_VERBOSE, LOG_TAG, __VA_ARGS__)
 #define ST_LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)
 #define ST_LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)
 #define ST_LOGW(...) __android_log_print(ANDROID_LOG_WARN, LOG_TAG, __VA_ARGS__)
 #define ST_LOGE(...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)
 
copy from widget/gonk/nativewindow/GonkBufferQueue.h
copy to widget/gonk/nativewindow/GonkBufferQueueJB.h
--- a/widget/gonk/nativewindow/GonkBufferQueue.h
+++ b/widget/gonk/nativewindow/GonkBufferQueueJB.h
@@ -10,18 +10,18 @@
  *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
 
-#ifndef NATIVEWINDOW_GONKBUFFERQUEUE_H
-#define NATIVEWINDOW_GONKBUFFERQUEUE_H
+#ifndef NATIVEWINDOW_GONKBUFFERQUEUE_JB_H
+#define NATIVEWINDOW_GONKBUFFERQUEUE_JB_H
 
 #include <gui/IGraphicBufferAlloc.h>
 #if ANDROID_VERSION == 17
 #include <gui/ISurfaceTexture.h>
 #else
 #include <gui/IGraphicBufferProducer.h>
 #endif
 
new file mode 100644
--- /dev/null
+++ b/widget/gonk/nativewindow/GonkBufferQueueKK.cpp
@@ -0,0 +1,1287 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ * Copyright (C) 2013 Mozilla Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "GonkBufferQueue"
+#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+#define LOG_NDEBUG 0
+
+#define GL_GLEXT_PROTOTYPES
+#define EGL_EGLEXT_PROTOTYPES
+
+#include <utils/Log.h>
+#include <utils/Trace.h>
+#include <utils/CallStack.h>
+#include <cutils/compiler.h>
+#include "mozilla/layers/ImageBridgeChild.h"
+#include "GonkBufferQueueKK.h"
+
+// Macros for including the GonkBufferQueue name in log messages
+#define ST_LOGV(...) __android_log_print(ANDROID_LOG_VERBOSE, LOG_TAG, __VA_ARGS__)
+#define ST_LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)
+#define ST_LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)
+#define ST_LOGW(...) __android_log_print(ANDROID_LOG_WARN, LOG_TAG, __VA_ARGS__)
+#define ST_LOGE(...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)
+
+#define ATRACE_BUFFER_INDEX(index)
+
+using namespace mozilla;
+using namespace mozilla::gfx;
+using namespace mozilla::layers;
+
+namespace android {
+
+// Get an ID that's unique within this process.
+static int32_t createProcessUniqueId() {
+    static volatile int32_t globalCounter = 0;
+    return android_atomic_inc(&globalCounter);
+}
+
+static const char* scalingModeName(int scalingMode) {
+    switch (scalingMode) {
+        case NATIVE_WINDOW_SCALING_MODE_FREEZE: return "FREEZE";
+        case NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW: return "SCALE_TO_WINDOW";
+        case NATIVE_WINDOW_SCALING_MODE_SCALE_CROP: return "SCALE_CROP";
+        default: return "Unknown";
+    }
+}
+
+GonkBufferQueue::GonkBufferQueue(bool allowSynchronousMode,
+        const sp<IGraphicBufferAlloc>& allocator) :
+    mDefaultWidth(1),
+    mDefaultHeight(1),
+    mMaxAcquiredBufferCount(1),
+    mDefaultMaxBufferCount(2),
+    mOverrideMaxBufferCount(0),
+//    mSynchronousMode(true), // GonkBufferQueue always works in sync mode.
+    mConsumerControlledByApp(false),
+    mDequeueBufferCannotBlock(false),
+    mUseAsyncBuffer(true),
+    mConnectedApi(NO_CONNECTED_API),
+    mAbandoned(false),
+    mFrameCounter(0),
+    mBufferHasBeenQueued(false),
+    mDefaultBufferFormat(PIXEL_FORMAT_RGBA_8888),
+    mConsumerUsageBits(0),
+    mTransformHint(0),
+    mGeneration(0)
+{
+    // Choose a name using the PID and a process-unique ID.
+    mConsumerName = String8::format("unnamed-%d-%d", getpid(), createProcessUniqueId());
+
+    ST_LOGV("GonkBufferQueue");
+}
+
+GonkBufferQueue::~GonkBufferQueue() {
+    ST_LOGV("~GonkBufferQueue");
+}
+
+status_t GonkBufferQueue::setDefaultMaxBufferCountLocked(int count) {
+    if (count < 2 || count > NUM_BUFFER_SLOTS)
+        return BAD_VALUE;
+
+    mDefaultMaxBufferCount = count;
+    mDequeueCondition.broadcast();
+
+    return NO_ERROR;
+}
+
+void GonkBufferQueue::setConsumerName(const String8& name) {
+    Mutex::Autolock lock(mMutex);
+    mConsumerName = name;
+}
+
+status_t GonkBufferQueue::setDefaultBufferFormat(uint32_t defaultFormat) {
+    Mutex::Autolock lock(mMutex);
+    mDefaultBufferFormat = defaultFormat;
+    return NO_ERROR;
+}
+
+status_t GonkBufferQueue::setConsumerUsageBits(uint32_t usage) {
+    Mutex::Autolock lock(mMutex);
+    mConsumerUsageBits = usage;
+    return NO_ERROR;
+}
+
+status_t GonkBufferQueue::setTransformHint(uint32_t hint) {
+    ST_LOGV("setTransformHint: %02x", hint);
+    Mutex::Autolock lock(mMutex);
+    mTransformHint = hint;
+    return NO_ERROR;
+}
+
+int GonkBufferQueue::getGeneration() {
+    return mGeneration;
+}
+
+mozilla::layers::SurfaceDescriptor*
+GonkBufferQueue::getSurfaceDescriptorFromBuffer(ANativeWindowBuffer* buffer)
+{
+    Mutex::Autolock _l(mMutex);
+    if (buffer == NULL) {
+        ST_LOGE("getSlotFromBufferLocked: encountered NULL buffer");
+        return nullptr;
+    }
+
+    for (int i = 0; i < NUM_BUFFER_SLOTS; i++) {
+        if (mSlots[i].mGraphicBuffer != NULL && mSlots[i].mGraphicBuffer->handle == buffer->handle) {
+            return &mSlots[i].mSurfaceDescriptor;
+        }
+    }
+    ST_LOGE("getSlotFromBufferLocked: unknown buffer: %p", buffer->handle);
+    return nullptr;
+}
+
+status_t GonkBufferQueue::setBufferCount(int bufferCount) {
+    ST_LOGV("setBufferCount: count=%d", bufferCount);
+
+    sp<IConsumerListener> listener;
+    nsAutoTArray<SurfaceDescriptor, NUM_BUFFER_SLOTS> freeList;
+    {
+        Mutex::Autolock lock(mMutex);
+
+        if (mAbandoned) {
+            ST_LOGE("setBufferCount: GonkBufferQueue has been abandoned!");
+            return NO_INIT;
+        }
+        if (bufferCount > NUM_BUFFER_SLOTS) {
+            ST_LOGE("setBufferCount: bufferCount too large (max %d)",
+                    NUM_BUFFER_SLOTS);
+            return BAD_VALUE;
+        }
+
+        // Error out if the user has dequeued buffers
+        for (int i=0 ; i<NUM_BUFFER_SLOTS; i++) {
+            if (mSlots[i].mBufferState == BufferSlot::DEQUEUED) {
+                ST_LOGE("setBufferCount: client owns some buffers");
+                return -EINVAL;
+            }
+        }
+
+        if (bufferCount == 0) {
+            mOverrideMaxBufferCount = 0;
+            mDequeueCondition.broadcast();
+            return NO_ERROR;
+        }
+
+        // fine to assume async to false before we're setting the buffer count
+        const int minBufferSlots = getMinMaxBufferCountLocked(false);
+        if (bufferCount < minBufferSlots) {
+            ST_LOGE("setBufferCount: requested buffer count (%d) is less than "
+                    "minimum (%d)", bufferCount, minBufferSlots);
+            return BAD_VALUE;
+        }
+
+        // here we're guaranteed that the client doesn't have dequeued buffers
+        // and will release all of its buffer references.  We don't clear the
+        // queue, however, so currently queued buffers still get displayed.
+        // XXX: Should this use drainQueueAndFreeBuffersLocked instead?
+        freeAllBuffersLocked(freeList);
+        mOverrideMaxBufferCount = bufferCount;
+        mDequeueCondition.broadcast();
+        listener = mConsumerListener;
+    } // scope for lock
+    releaseBufferFreeListUnlocked(freeList);
+
+    if (listener != NULL) {
+        listener->onBuffersReleased();
+    }
+
+    return NO_ERROR;
+}
+
+int GonkBufferQueue::query(int what, int* outValue)
+{
+    ATRACE_CALL();
+    Mutex::Autolock lock(mMutex);
+
+    if (mAbandoned) {
+        ST_LOGE("query: GonkBufferQueue has been abandoned!");
+        return NO_INIT;
+    }
+
+    int value;
+    switch (what) {
+    case NATIVE_WINDOW_WIDTH:
+        value = mDefaultWidth;
+        break;
+    case NATIVE_WINDOW_HEIGHT:
+        value = mDefaultHeight;
+        break;
+    case NATIVE_WINDOW_FORMAT:
+        value = mDefaultBufferFormat;
+        break;
+    case NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS:
+        value = getMinUndequeuedBufferCount(false);
+        break;
+    case NATIVE_WINDOW_CONSUMER_RUNNING_BEHIND:
+        value = (mQueue.size() >= 2);
+        break;
+    case NATIVE_WINDOW_CONSUMER_USAGE_BITS:
+        value = mConsumerUsageBits;
+        break;
+    default:
+        return BAD_VALUE;
+    }
+    outValue[0] = value;
+    return NO_ERROR;
+}
+
+status_t GonkBufferQueue::requestBuffer(int slot, sp<GraphicBuffer>* buf) {
+    ATRACE_CALL();
+    ST_LOGV("requestBuffer: slot=%d", slot);
+    Mutex::Autolock lock(mMutex);
+    if (mAbandoned) {
+        ST_LOGE("requestBuffer: GonkBufferQueue has been abandoned!");
+        return NO_INIT;
+    }
+    if (slot < 0 || slot >= NUM_BUFFER_SLOTS) {
+        ST_LOGE("requestBuffer: slot index out of range [0, %d]: %d",
+                NUM_BUFFER_SLOTS, slot);
+        return BAD_VALUE;
+    } else if (mSlots[slot].mBufferState != BufferSlot::DEQUEUED) {
+        ST_LOGE("requestBuffer: slot %d is not owned by the client (state=%d)",
+                slot, mSlots[slot].mBufferState);
+        return BAD_VALUE;
+    }
+    mSlots[slot].mRequestBufferCalled = true;
+    *buf = mSlots[slot].mGraphicBuffer;
+    return NO_ERROR;
+}
+
+status_t GonkBufferQueue::dequeueBuffer(int *outBuf, sp<Fence>* outFence, bool async,
+            uint32_t w, uint32_t h, uint32_t format, uint32_t usage) {
+    ATRACE_CALL();
+    ST_LOGV("dequeueBuffer: w=%d h=%d fmt=%#x usage=%#x", w, h, format, usage);
+
+    if ((w && !h) || (!w && h)) {
+        ST_LOGE("dequeueBuffer: invalid size: w=%u, h=%u", w, h);
+        return BAD_VALUE;
+    }
+
+    status_t returnFlags(OK);
+    int buf = INVALID_BUFFER_SLOT;
+    uint32_t generation;
+    SurfaceDescriptor descOld;
+
+    { // Scope for the lock
+        Mutex::Autolock lock(mMutex);
+        generation = mGeneration;
+
+        if (format == 0) {
+            format = mDefaultBufferFormat;
+        }
+        // turn on usage bits the consumer requested
+        usage |= mConsumerUsageBits;
+
+        int found = -1;
+        bool tryAgain = true;
+        while (tryAgain) {
+            if (mAbandoned) {
+                ST_LOGE("dequeueBuffer: GonkBufferQueue has been abandoned!");
+                return NO_INIT;
+            }
+
+            const int maxBufferCount = getMaxBufferCountLocked(async);
+            if (async && mOverrideMaxBufferCount) {
+                // FIXME: some drivers are manually setting the buffer-count (which they
+                // shouldn't), so we do this extra test here to handle that case.
+                // This is TEMPORARY, until we get this fixed.
+                if (mOverrideMaxBufferCount < maxBufferCount) {
+                    ST_LOGE("dequeueBuffer: async mode is invalid with buffercount override");
+                    return BAD_VALUE;
+                }
+            }
+
+            // Free up any buffers that are in slots beyond the max buffer
+            // count.
+            //for (int i = maxBufferCount; i < NUM_BUFFER_SLOTS; i++) {
+            //    assert(mSlots[i].mBufferState == BufferSlot::FREE);
+            //    if (mSlots[i].mGraphicBuffer != NULL) {
+            //        freeBufferLocked(i);
+            //        returnFlags |= IGraphicBufferProducer::RELEASE_ALL_BUFFERS;
+            //    }
+            //}
+
+            // look for a free buffer to give to the client
+            found = INVALID_BUFFER_SLOT;
+            int dequeuedCount = 0;
+            int acquiredCount = 0;
+            for (int i = 0; i < maxBufferCount; i++) {
+                const int state = mSlots[i].mBufferState;
+                switch (state) {
+                    case BufferSlot::DEQUEUED:
+                    dequeuedCount++;
+                        break;
+                    case BufferSlot::ACQUIRED:
+                        acquiredCount++;
+                        break;
+                    case BufferSlot::FREE:
+                    /* We return the oldest of the free buffers to avoid
+                     * stalling the producer if possible.  This is because
+                     * the consumer may still have pending reads of the
+                     * buffers in flight.
+                     */
+                    if ((found < 0) ||
+                            mSlots[i].mFrameNumber < mSlots[found].mFrameNumber) {
+                        found = i;
+                    }
+                        break;
+                }
+            }
+
+            // clients are not allowed to dequeue more than one buffer
+            // if they didn't set a buffer count.
+            if (!mOverrideMaxBufferCount && dequeuedCount) {
+                ST_LOGE("dequeueBuffer: can't dequeue multiple buffers without "
+                        "setting the buffer count");
+                return -EINVAL;
+            }
+
+            // See whether a buffer has been queued since the last
+            // setBufferCount so we know whether to perform the min undequeued
+            // buffers check below.
+            if (mBufferHasBeenQueued) {
+                // make sure the client is not trying to dequeue more buffers
+                // than allowed.
+                const int newUndequeuedCount = maxBufferCount - (dequeuedCount+1);
+                const int minUndequeuedCount = getMinUndequeuedBufferCount(async);
+                if (newUndequeuedCount < minUndequeuedCount) {
+                    ST_LOGE("dequeueBuffer: min undequeued buffer count (%d) "
+                            "exceeded (dequeued=%d undequeudCount=%d)",
+                            minUndequeuedCount, dequeuedCount,
+                            newUndequeuedCount);
+                    return -EBUSY;
+                }
+            }
+
+            // If no buffer is found, wait for a buffer to be released or for
+            // the max buffer count to change.
+            tryAgain = found == INVALID_BUFFER_SLOT;
+            if (tryAgain) {
+                // return an error if we're in "cannot block" mode (producer and consumer
+                // are controlled by the application) -- however, the consumer is allowed
+                // to acquire briefly an extra buffer (which could cause us to have to wait here)
+                // and that's okay because we know the wait will be brief (it happens
+                // if we dequeue a buffer while the consumer has acquired one but not released
+                // the old one yet -- for e.g.: see GLConsumer::updateTexImage()).
+                if (mDequeueBufferCannotBlock && (acquiredCount <= mMaxAcquiredBufferCount)) {
+                    ST_LOGE("dequeueBuffer: would block! returning an error instead.");
+                    return WOULD_BLOCK;
+                }
+                mDequeueCondition.wait(mMutex);
+            }
+        }
+
+
+        if (found == INVALID_BUFFER_SLOT) {
+            // This should not happen.
+            ST_LOGE("dequeueBuffer: no available buffer slots");
+            return -EBUSY;
+        }
+
+        buf = found;
+        *outBuf = found;
+
+        const bool useDefaultSize = !w && !h;
+        if (useDefaultSize) {
+            // use the default size
+            w = mDefaultWidth;
+            h = mDefaultHeight;
+        }
+
+        mSlots[buf].mBufferState = BufferSlot::DEQUEUED;
+
+        const sp<GraphicBuffer>& buffer(mSlots[buf].mGraphicBuffer);
+        if ((buffer == NULL) ||
+            (uint32_t(buffer->width)  != w) ||
+            (uint32_t(buffer->height) != h) ||
+            (uint32_t(buffer->format) != format) ||
+            ((uint32_t(buffer->usage) & usage) != usage))
+        {
+            mSlots[buf].mAcquireCalled = false;
+            mSlots[buf].mGraphicBuffer = NULL;
+            mSlots[buf].mRequestBufferCalled = false;
+            mSlots[buf].mFence = Fence::NO_FENCE;
+            descOld = mSlots[buf].mSurfaceDescriptor;
+            mSlots[buf].mSurfaceDescriptor = SurfaceDescriptor();
+
+            returnFlags |= IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION;
+        }
+
+
+        if (CC_UNLIKELY(mSlots[buf].mFence == NULL)) {
+            ST_LOGE("dequeueBuffer: about to return a NULL fence from mSlot. "
+                    "buf=%d, w=%d, h=%d, format=%d",
+                    buf, buffer->width, buffer->height, buffer->format);
+        }
+        *outFence = mSlots[buf].mFence;
+        mSlots[buf].mFence = Fence::NO_FENCE;
+    }  // end lock scope
+
+    SurfaceDescriptor desc;
+    ImageBridgeChild* ibc;
+    sp<GraphicBuffer> graphicBuffer;
+    if (returnFlags & IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION) {
+        usage |= GraphicBuffer::USAGE_HW_TEXTURE;
+        status_t error;
+        ibc = ImageBridgeChild::GetSingleton();
+        ST_LOGD("dequeueBuffer: about to alloc surface descriptor");
+        ibc->AllocSurfaceDescriptorGralloc(IntSize(w, h),
+                                           format,
+                                           usage,
+                                           &desc);
+        // We can only use a gralloc buffer here.  If we didn't get
+        // one back, something went wrong.
+        ST_LOGD("dequeueBuffer: got surface descriptor");
+        if (SurfaceDescriptor::TSurfaceDescriptorGralloc != desc.type()) {
+            MOZ_ASSERT(SurfaceDescriptor::T__None == desc.type());
+            ST_LOGE("dequeueBuffer: failed to alloc gralloc buffer");
+            return -ENOMEM;
+        }
+        graphicBuffer = GrallocBufferActor::GetFrom(desc.get_SurfaceDescriptorGralloc());
+        error = graphicBuffer->initCheck();
+        if (error != NO_ERROR) {
+            ST_LOGE("dequeueBuffer: createGraphicBuffer failed with error %d", error);
+            return error;
+        }
+
+        bool tooOld = false;
+        { // Scope for the lock
+            Mutex::Autolock lock(mMutex);
+
+            if (mAbandoned) {
+                ST_LOGE("dequeueBuffer: SurfaceTexture has been abandoned!");
+                return NO_INIT;
+            }
+
+            if (generation == mGeneration) {
+                mSlots[buf].mGraphicBuffer = graphicBuffer;
+                mSlots[buf].mSurfaceDescriptor = desc;
+                mSlots[buf].mSurfaceDescriptor.get_SurfaceDescriptorGralloc().external() = true;
+                ST_LOGD("dequeueBuffer: returning slot=%d buf=%p ", buf,
+                        mSlots[buf].mGraphicBuffer->handle);
+            } else {
+                tooOld = true;
+            }
+        }
+
+        if (IsSurfaceDescriptorValid(descOld)) {
+            ibc->DeallocSurfaceDescriptorGralloc(descOld);
+        }
+
+        if (tooOld) {
+            ibc->DeallocSurfaceDescriptorGralloc(desc);
+        }
+    }
+
+    ST_LOGV("dequeueBuffer: returning slot=%d/%llu buf=%p flags=%#x", *outBuf,
+            mSlots[*outBuf].mFrameNumber,
+            mSlots[*outBuf].mGraphicBuffer->handle, returnFlags);
+
+    return returnFlags;
+}
+
+status_t GonkBufferQueue::queueBuffer(int buf,
+        const QueueBufferInput& input, QueueBufferOutput* output) {
+    ATRACE_CALL();
+
+    Rect crop;
+    uint32_t transform;
+    int scalingMode;
+    int64_t timestamp;
+    bool isAutoTimestamp;
+    bool async;
+    sp<Fence> fence;
+
+    input.deflate(&timestamp, &isAutoTimestamp, &crop, &scalingMode, &transform,
+             &async, &fence);
+
+    if (fence == NULL) {
+        ST_LOGE("queueBuffer: fence is NULL");
+        return BAD_VALUE;
+    }
+
+    ST_LOGV("queueBuffer: slot=%d time=%#llx crop=[%d,%d,%d,%d] tr=%#x "
+            "scale=%s",
+            buf, timestamp, crop.left, crop.top, crop.right, crop.bottom,
+            transform, scalingModeName(scalingMode));
+
+    switch (scalingMode) {
+        case NATIVE_WINDOW_SCALING_MODE_FREEZE:
+        case NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW:
+        case NATIVE_WINDOW_SCALING_MODE_SCALE_CROP:
+        case NATIVE_WINDOW_SCALING_MODE_NO_SCALE_CROP:
+            break;
+        default:
+            ST_LOGE("unknown scaling mode: %d", scalingMode);
+            return -EINVAL;
+    }
+
+    sp<IConsumerListener> listener;
+
+    { // scope for the lock
+        Mutex::Autolock lock(mMutex);
+
+        if (mAbandoned) {
+            ST_LOGE("queueBuffer: GonkBufferQueue has been abandoned!");
+            return NO_INIT;
+        }
+
+        const int maxBufferCount = getMaxBufferCountLocked(async);
+        if (async && mOverrideMaxBufferCount) {
+            // FIXME: some drivers are manually setting the buffer-count (which they
+            // shouldn't), so we do this extra test here to handle that case.
+            // This is TEMPORARY, until we get this fixed.
+            if (mOverrideMaxBufferCount < maxBufferCount) {
+                ST_LOGE("queueBuffer: async mode is invalid with buffercount override");
+                return BAD_VALUE;
+            }
+        }
+        if (buf < 0 || buf >= maxBufferCount) {
+            ST_LOGE("queueBuffer: slot index out of range [0, %d]: %d",
+                    maxBufferCount, buf);
+            return -EINVAL;
+        } else if (mSlots[buf].mBufferState != BufferSlot::DEQUEUED) {
+            ST_LOGE("queueBuffer: slot %d is not owned by the client "
+                    "(state=%d)", buf, mSlots[buf].mBufferState);
+            return -EINVAL;
+        } else if (!mSlots[buf].mRequestBufferCalled) {
+            ST_LOGE("queueBuffer: slot %d was enqueued without requesting a "
+                    "buffer", buf);
+            return -EINVAL;
+        }
+
+        ST_LOGV("queueBuffer: slot=%d/%llu time=%#llx crop=[%d,%d,%d,%d] "
+                "tr=%#x scale=%s",
+                buf, mFrameCounter + 1, timestamp,
+                crop.left, crop.top, crop.right, crop.bottom,
+                transform, scalingModeName(scalingMode));
+
+        const sp<GraphicBuffer>& graphicBuffer(mSlots[buf].mGraphicBuffer);
+        Rect bufferRect(graphicBuffer->getWidth(), graphicBuffer->getHeight());
+        Rect croppedCrop;
+        crop.intersect(bufferRect, &croppedCrop);
+        if (croppedCrop != crop) {
+            ST_LOGE("queueBuffer: crop rect is not contained within the "
+                    "buffer in slot %d", buf);
+            return -EINVAL;
+        }
+
+        mSlots[buf].mFence = fence;
+        mSlots[buf].mBufferState = BufferSlot::QUEUED;
+        mFrameCounter++;
+        mSlots[buf].mFrameNumber = mFrameCounter;
+
+        BufferItem item;
+        item.mAcquireCalled = mSlots[buf].mAcquireCalled;
+        item.mGraphicBuffer = mSlots[buf].mGraphicBuffer;
+        item.mCrop = crop;
+        item.mTransform = transform & ~NATIVE_WINDOW_TRANSFORM_INVERSE_DISPLAY;
+        item.mTransformToDisplayInverse = bool(transform & NATIVE_WINDOW_TRANSFORM_INVERSE_DISPLAY);
+        item.mScalingMode = scalingMode;
+        item.mTimestamp = timestamp;
+        item.mIsAutoTimestamp = isAutoTimestamp;
+        item.mFrameNumber = mFrameCounter;
+        item.mBuf = buf;
+        item.mFence = fence;
+        item.mIsDroppable = mDequeueBufferCannotBlock || async;
+
+        if (mQueue.empty()) {
+            // when the queue is empty, we can ignore "mDequeueBufferCannotBlock", and
+            // simply queue this buffer.
+            mQueue.push_back(item);
+            listener = mConsumerListener;
+        } else {
+            // when the queue is not empty, we need to look at the front buffer
+            // state and see if we need to replace it.
+            Fifo::iterator front(mQueue.begin());
+            if (front->mIsDroppable) {
+                // buffer slot currently queued is marked free if still tracked
+                if (stillTracking(front)) {
+                    mSlots[front->mBuf].mBufferState = BufferSlot::FREE;
+                    // reset the frame number of the freed buffer so that it is the first in
+                    // line to be dequeued again.
+                    mSlots[front->mBuf].mFrameNumber = 0;
+                }
+                // and we record the new buffer in the queued list
+                *front = item;
+            } else {
+                mQueue.push_back(item);
+                listener = mConsumerListener;
+            }
+        }
+
+        mBufferHasBeenQueued = true;
+        mDequeueCondition.broadcast();
+
+        output->inflate(mDefaultWidth, mDefaultHeight, mTransformHint,
+                mQueue.size());
+
+    } // scope for the lock
+
+    // call back without lock held
+    if (listener != 0) {
+        listener->onFrameAvailable();
+    }
+    return NO_ERROR;
+}
+
+void GonkBufferQueue::cancelBuffer(int buf, const sp<Fence>& fence) {
+    ATRACE_CALL();
+    ST_LOGV("cancelBuffer: slot=%d", buf);
+    Mutex::Autolock lock(mMutex);
+
+    if (mAbandoned) {
+        ST_LOGW("cancelBuffer: GonkBufferQueue has been abandoned!");
+        return;
+    }
+
+    if (buf < 0 || buf >= NUM_BUFFER_SLOTS) {
+        ST_LOGE("cancelBuffer: slot index out of range [0, %d]: %d",
+                NUM_BUFFER_SLOTS, buf);
+        return;
+    } else if (mSlots[buf].mBufferState != BufferSlot::DEQUEUED) {
+        ST_LOGE("cancelBuffer: slot %d is not owned by the client (state=%d)",
+                buf, mSlots[buf].mBufferState);
+        return;
+    } else if (fence == NULL) {
+        ST_LOGE("cancelBuffer: fence is NULL");
+        return;
+    }
+    mSlots[buf].mBufferState = BufferSlot::FREE;
+    mSlots[buf].mFrameNumber = 0;
+    mSlots[buf].mFence = fence;
+    mDequeueCondition.broadcast();
+}
+
+
+status_t GonkBufferQueue::connect(const sp<IBinder>& token,
+        int api, bool producerControlledByApp, QueueBufferOutput* output) {
+    ATRACE_CALL();
+    ST_LOGV("connect: api=%d producerControlledByApp=%s", api,
+            producerControlledByApp ? "true" : "false");
+    Mutex::Autolock lock(mMutex);
+
+retry:
+    if (mAbandoned) {
+        ST_LOGE("connect: GonkBufferQueue has been abandoned!");
+        return NO_INIT;
+    }
+
+    if (mConsumerListener == NULL) {
+        ST_LOGE("connect: GonkBufferQueue has no consumer!");
+        return NO_INIT;
+    }
+
+    if (mConnectedApi != NO_CONNECTED_API) {
+        ST_LOGE("connect: already connected (cur=%d, req=%d)",
+                mConnectedApi, api);
+        return -EINVAL;
+    }
+
+    // If we disconnect and reconnect quickly, we can be in a state where our slots are
+    // empty but we have many buffers in the queue.  This can cause us to run out of
+    // memory if we outrun the consumer.  Wait here if it looks like we have too many
+    // buffers queued up.
+    int maxBufferCount = getMaxBufferCountLocked(false);    // worst-case, i.e. largest value
+    if (mQueue.size() > (size_t) maxBufferCount) {
+        // TODO: make this bound tighter?
+        ST_LOGV("queue size is %d, waiting", mQueue.size());
+        mDequeueCondition.wait(mMutex);
+        goto retry;
+    }
+
+    int err = NO_ERROR;
+    switch (api) {
+        case NATIVE_WINDOW_API_EGL:
+        case NATIVE_WINDOW_API_CPU:
+        case NATIVE_WINDOW_API_MEDIA:
+        case NATIVE_WINDOW_API_CAMERA:
+            mConnectedApi = api;
+            output->inflate(mDefaultWidth, mDefaultHeight, mTransformHint, mQueue.size());
+
+            // set-up a death notification so that we can disconnect
+            // automatically when/if the remote producer dies.
+            if (token != NULL && token->remoteBinder() != NULL) {
+                status_t err = token->linkToDeath(static_cast<IBinder::DeathRecipient*>(this));
+                if (err == NO_ERROR) {
+                    mConnectedProducerToken = token;
+                } else {
+                    ALOGE("linkToDeath failed: %s (%d)", strerror(-err), err);
+                }
+            }
+            break;
+        default:
+            err = -EINVAL;
+            break;
+    }
+
+    mBufferHasBeenQueued = false;
+    mDequeueBufferCannotBlock = mConsumerControlledByApp && producerControlledByApp;
+
+    return err;
+}
+
+void GonkBufferQueue::binderDied(const wp<IBinder>& who) {
+    // If we're here, it means that a producer we were connected to died.
+    // We're GUARANTEED that we still are connected to it because it has no other way
+    // to get disconnected -- or -- we wouldn't be here because we're removing this
+    // callback upon disconnect. Therefore, it's okay to read mConnectedApi without
+    // synchronization here.
+    int api = mConnectedApi;
+    this->disconnect(api);
+}
+
+status_t GonkBufferQueue::disconnect(int api) {
+    ATRACE_CALL();
+    ST_LOGV("disconnect: api=%d", api);
+
+    int err = NO_ERROR;
+    sp<IConsumerListener> listener;
+    nsAutoTArray<SurfaceDescriptor, NUM_BUFFER_SLOTS> freeList;
+
+    { // Scope for the lock
+        Mutex::Autolock lock(mMutex);
+
+        if (mAbandoned) {
+            // it is not really an error to disconnect after the surface
+            // has been abandoned, it should just be a no-op.
+            return NO_ERROR;
+        }
+
+        switch (api) {
+            case NATIVE_WINDOW_API_EGL:
+            case NATIVE_WINDOW_API_CPU:
+            case NATIVE_WINDOW_API_MEDIA:
+            case NATIVE_WINDOW_API_CAMERA:
+                if (mConnectedApi == api) {
+                    freeAllBuffersLocked(freeList);
+                    mConnectedApi = NO_CONNECTED_API;
+                    mDequeueCondition.broadcast();
+                    listener = mConsumerListener;
+                } else {
+                    ST_LOGE("disconnect: connected to another api (cur=%d, req=%d)",
+                            mConnectedApi, api);
+                    err = -EINVAL;
+                }
+                break;
+            default:
+                ST_LOGE("disconnect: unknown API %d", api);
+                err = -EINVAL;
+                break;
+        }
+    }
+    releaseBufferFreeListUnlocked(freeList);
+
+    if (listener != NULL) {
+        listener->onBuffersReleased();
+    }
+
+    return err;
+}
+
+void GonkBufferQueue::dump(String8& result, const char* prefix) const {
+    Mutex::Autolock _l(mMutex);
+
+    String8 fifo;
+    int fifoSize = 0;
+    Fifo::const_iterator i(mQueue.begin());
+    while (i != mQueue.end()) {
+        fifo.appendFormat("%02d:%p crop=[%d,%d,%d,%d], "
+                "xform=0x%02x, time=%#llx, scale=%s\n",
+                i->mBuf, i->mGraphicBuffer.get(),
+                i->mCrop.left, i->mCrop.top, i->mCrop.right,
+                i->mCrop.bottom, i->mTransform, i->mTimestamp,
+                scalingModeName(i->mScalingMode)
+                );
+        i++;
+        fifoSize++;
+    }
+
+
+    result.appendFormat(
+            "%s-BufferQueue mMaxAcquiredBufferCount=%d, mDequeueBufferCannotBlock=%d, default-size=[%dx%d], "
+            "default-format=%d, transform-hint=%02x, FIFO(%d)={%s}\n",
+            prefix, mMaxAcquiredBufferCount, mDequeueBufferCannotBlock, mDefaultWidth,
+            mDefaultHeight, mDefaultBufferFormat, mTransformHint,
+            fifoSize, fifo.string());
+
+    struct {
+        const char * operator()(int state) const {
+            switch (state) {
+                case BufferSlot::DEQUEUED: return "DEQUEUED";
+                case BufferSlot::QUEUED: return "QUEUED";
+                case BufferSlot::FREE: return "FREE";
+                case BufferSlot::ACQUIRED: return "ACQUIRED";
+                default: return "Unknown";
+            }
+        }
+    } stateName;
+
+    // just trim the free buffers to not spam the dump
+    int maxBufferCount = 0;
+    for (int i=NUM_BUFFER_SLOTS-1 ; i>=0 ; i--) {
+        const BufferSlot& slot(mSlots[i]);
+        if ((slot.mBufferState != BufferSlot::FREE) || (slot.mGraphicBuffer != NULL)) {
+            maxBufferCount = i+1;
+            break;
+        }
+    }
+
+    for (int i=0 ; i<maxBufferCount ; i++) {
+        const BufferSlot& slot(mSlots[i]);
+        const sp<GraphicBuffer>& buf(slot.mGraphicBuffer);
+        result.appendFormat(
+            "%s%s[%02d:%p] state=%-8s",
+                prefix, (slot.mBufferState == BufferSlot::ACQUIRED)?">":" ", i, buf.get(),
+                stateName(slot.mBufferState)
+        );
+
+        if (buf != NULL) {
+            result.appendFormat(
+                    ", %p [%4ux%4u:%4u,%3X]",
+                    buf->handle, buf->width, buf->height, buf->stride,
+                    buf->format);
+        }
+        result.append("\n");
+    }
+}
+
+void GonkBufferQueue::releaseBufferFreeListUnlocked(nsTArray<SurfaceDescriptor>& freeList)
+{
+    // This function MUST ONLY be called with mMutex unlocked; else there
+    // is a risk of deadlock with the ImageBridge thread.
+
+    ST_LOGD("releaseBufferFreeListUnlocked: E");
+    ImageBridgeChild *ibc = ImageBridgeChild::GetSingleton();
+
+    for (uint32_t i = 0; i < freeList.Length(); ++i) {
+        ibc->DeallocSurfaceDescriptorGralloc(freeList[i]);
+    }
+
+    freeList.Clear();
+    ST_LOGD("releaseBufferFreeListUnlocked: X");
+}
+
+void GonkBufferQueue::freeAllBuffersLocked(nsTArray<SurfaceDescriptor>& freeList)
+{
+    ALOGW_IF(!mQueue.isEmpty(),
+            "freeAllBuffersLocked called but mQueue is not empty");
+    ++mGeneration;
+    mQueue.clear();
+    mBufferHasBeenQueued = false;
+    for (int i = 0; i < NUM_BUFFER_SLOTS; i++) {
+        if (mSlots[i].mGraphicBuffer.get() && mSlots[i].mBufferState != BufferSlot::ACQUIRED) {
+            SurfaceDescriptor* desc = freeList.AppendElement();
+            *desc = mSlots[i].mSurfaceDescriptor;
+        }
+        mSlots[i].mGraphicBuffer = 0;
+        mSlots[i].mSurfaceDescriptor = SurfaceDescriptor();
+        if (mSlots[i].mBufferState == BufferSlot::ACQUIRED) {
+            mSlots[i].mNeedsCleanupOnRelease = true;
+        }
+        mSlots[i].mBufferState = BufferSlot::FREE;
+        mSlots[i].mFrameNumber = 0;
+        mSlots[i].mAcquireCalled = false;
+        // destroy fence as GonkBufferQueue now takes ownership
+        mSlots[i].mFence = Fence::NO_FENCE;
+    }
+}
+
+status_t GonkBufferQueue::acquireBuffer(BufferItem *buffer, nsecs_t expectedPresent) {
+    ATRACE_CALL();
+    Mutex::Autolock _l(mMutex);
+
+    // Check that the consumer doesn't currently have the maximum number of
+    // buffers acquired.  We allow the max buffer count to be exceeded by one
+    // buffer, so that the consumer can successfully set up the newly acquired
+    // buffer before releasing the old one.
+    int numAcquiredBuffers = 0;
+    for (int i = 0; i < NUM_BUFFER_SLOTS; i++) {
+        if (mSlots[i].mBufferState == BufferSlot::ACQUIRED) {
+            numAcquiredBuffers++;
+        }
+    }
+    if (numAcquiredBuffers >= mMaxAcquiredBufferCount+1) {
+        ST_LOGE("acquireBuffer: max acquired buffer count reached: %d (max=%d)",
+                numAcquiredBuffers, mMaxAcquiredBufferCount);
+        return INVALID_OPERATION;
+    }
+
+    // check if queue is empty
+    // In asynchronous mode the list is guaranteed to be one buffer
+    // deep, while in synchronous mode we use the oldest buffer.
+    if (mQueue.empty()) {
+        return NO_BUFFER_AVAILABLE;
+    }
+
+    Fifo::iterator front(mQueue.begin());
+
+    // If expectedPresent is specified, we may not want to return a buffer yet.
+    // If it's specified and there's more than one buffer queued, we may
+    // want to drop a buffer.
+    if (expectedPresent != 0) {
+        const int MAX_REASONABLE_NSEC = 1000000000ULL;  // 1 second
+
+        // The "expectedPresent" argument indicates when the buffer is expected
+        // to be presented on-screen.  If the buffer's desired-present time
+        // is earlier (less) than expectedPresent, meaning it'll be displayed
+        // on time or possibly late if we show it ASAP, we acquire and return
+        // it.  If we don't want to display it until after the expectedPresent
+        // time, we return PRESENT_LATER without acquiring it.
+        //
+        // To be safe, we don't defer acquisition if expectedPresent is
+        // more than one second in the future beyond the desired present time
+        // (i.e. we'd be holding the buffer for a long time).
+        //
+        // NOTE: code assumes monotonic time values from the system clock are
+        // positive.
+
+        // Start by checking to see if we can drop frames.  We skip this check
+        // if the timestamps are being auto-generated by Surface -- if the
+        // app isn't generating timestamps explicitly, they probably don't
+        // want frames to be discarded based on them.
+        while (mQueue.size() > 1 && !mQueue[0].mIsAutoTimestamp) {
+            // If entry[1] is timely, drop entry[0] (and repeat).  We apply
+            // an additional criteria here: we only drop the earlier buffer if
+            // our desiredPresent falls within +/- 1 second of the expected
+            // present.  Otherwise, bogus desiredPresent times (e.g. 0 or
+            // a small relative timestamp), which normally mean "ignore the
+            // timestamp and acquire immediately", would cause us to drop
+            // frames.
+            //
+            // We may want to add an additional criteria: don't drop the
+            // earlier buffer if entry[1]'s fence hasn't signaled yet.
+            //
+            // (Vector front is [0], back is [size()-1])
+            const BufferItem& bi(mQueue[1]);
+            nsecs_t desiredPresent = bi.mTimestamp;
+            if (desiredPresent < expectedPresent - MAX_REASONABLE_NSEC ||
+                    desiredPresent > expectedPresent) {
+                // This buffer is set to display in the near future, or
+                // desiredPresent is garbage.  Either way we don't want to
+                // drop the previous buffer just to get this on screen sooner.
+                ST_LOGV("pts nodrop: des=%lld expect=%lld (%lld) now=%lld",
+                        desiredPresent, expectedPresent, desiredPresent - expectedPresent,
+                        systemTime(CLOCK_MONOTONIC));
+                break;
+            }
+            ST_LOGV("pts drop: queue1des=%lld expect=%lld size=%d",
+                    desiredPresent, expectedPresent, mQueue.size());
+            if (stillTracking(front)) {
+                // front buffer is still in mSlots, so mark the slot as free
+                mSlots[front->mBuf].mBufferState = BufferSlot::FREE;
+            }
+            mQueue.erase(front);
+            front = mQueue.begin();
+        }
+
+        // See if the front buffer is due.
+        nsecs_t desiredPresent = front->mTimestamp;
+        if (desiredPresent > expectedPresent &&
+                desiredPresent < expectedPresent + MAX_REASONABLE_NSEC) {
+            ST_LOGV("pts defer: des=%lld expect=%lld (%lld) now=%lld",
+                    desiredPresent, expectedPresent, desiredPresent - expectedPresent,
+                    systemTime(CLOCK_MONOTONIC));
+            return PRESENT_LATER;
+        }
+
+        ST_LOGV("pts accept: des=%lld expect=%lld (%lld) now=%lld",
+                desiredPresent, expectedPresent, desiredPresent - expectedPresent,
+                systemTime(CLOCK_MONOTONIC));
+    }
+
+    int buf = front->mBuf;
+    buffer->mGraphicBuffer = mSlots[buf].mGraphicBuffer;
+    buffer->mSurfaceDescriptor = mSlots[buf].mSurfaceDescriptor;
+    buffer->mFrameNumber = mSlots[buf].mFrameNumber;
+    buffer->mBuf = buf;
+    buffer->mFence = mSlots[buf].mFence;
+    ATRACE_BUFFER_INDEX(buf);
+
+    ST_LOGV("acquireBuffer: acquiring { slot=%d/%llu, buffer=%p }",
+            front->mBuf, front->mFrameNumber,
+            front->mGraphicBuffer->handle);
+    // if front buffer still being tracked update slot state
+    if (stillTracking(front)) {
+        mSlots[buf].mAcquireCalled = true;
+        mSlots[buf].mNeedsCleanupOnRelease = false;
+        mSlots[buf].mBufferState = BufferSlot::ACQUIRED;
+        mSlots[buf].mFence = Fence::NO_FENCE;
+    }
+
+    // If the buffer has previously been acquired by the consumer, set
+    // mGraphicBuffer to NULL to avoid unnecessarily remapping this
+    // buffer on the consumer side.
+    //if (buffer->mAcquireCalled) {
+    //    buffer->mGraphicBuffer = NULL;
+    //}
+
+    mQueue.erase(front);
+    mDequeueCondition.broadcast();
+
+    return NO_ERROR;
+}
+
+status_t GonkBufferQueue::releaseBuffer(int buf, uint64_t frameNumber, const sp<Fence>& fence) {
+    ATRACE_CALL();
+
+    if (buf == INVALID_BUFFER_SLOT || fence == NULL) {
+        return BAD_VALUE;
+    }
+
+    Mutex::Autolock _l(mMutex);
+
+    // If the frame number has changed because buffer has been reallocated,
+    // we can ignore this releaseBuffer for the old buffer.
+    //if (frameNumber != mSlots[buf].mFrameNumber) {
+    //    return STALE_BUFFER_SLOT;
+    //}
+
+
+    // Internal state consistency checks:
+    // Make sure this buffers hasn't been queued while we were owning it (acquired)
+    Fifo::iterator front(mQueue.begin());
+    Fifo::const_iterator const end(mQueue.end());
+    while (front != end) {
+        if (front->mBuf == buf) {
+            LOG_ALWAYS_FATAL("[%s] received new buffer(#%lld) on slot #%d that has not yet been "
+                    "acquired", mConsumerName.string(), frameNumber, buf);
+            break; // never reached
+        }
+        front++;
+    }
+
+    // The buffer can now only be released if its in the acquired state
+    if (mSlots[buf].mBufferState == BufferSlot::ACQUIRED) {
+        mSlots[buf].mFence = fence;
+        mSlots[buf].mBufferState = BufferSlot::FREE;
+    } else if (mSlots[buf].mNeedsCleanupOnRelease) {
+        ST_LOGV("releasing a stale buf %d its state was %d", buf, mSlots[buf].mBufferState);
+        mSlots[buf].mNeedsCleanupOnRelease = false;
+        return STALE_BUFFER_SLOT;
+    } else {
+        ST_LOGE("attempted to release buf %d but its state was %d", buf, mSlots[buf].mBufferState);
+        return -EINVAL;
+    }
+
+    mDequeueCondition.broadcast();
+    return NO_ERROR;
+}
+
+status_t GonkBufferQueue::consumerConnect(const sp<IConsumerListener>& consumerListener,
+        bool controlledByApp) {
+    ST_LOGV("consumerConnect controlledByApp=%s",
+            controlledByApp ? "true" : "false");
+    Mutex::Autolock lock(mMutex);
+
+    if (mAbandoned) {
+        ST_LOGE("consumerConnect: GonkBufferQueue has been abandoned!");
+        return NO_INIT;
+    }
+    if (consumerListener == NULL) {
+        ST_LOGE("consumerConnect: consumerListener may not be NULL");
+        return BAD_VALUE;
+    }
+
+    mConsumerListener = consumerListener;
+    mConsumerControlledByApp = controlledByApp;
+
+    return NO_ERROR;
+}
+
+status_t GonkBufferQueue::consumerDisconnect() {
+    ST_LOGV("consumerDisconnect");
+    nsAutoTArray<SurfaceDescriptor, NUM_BUFFER_SLOTS> freeList;
+    {
+        Mutex::Autolock lock(mMutex);
+
+        if (mConsumerListener == NULL) {
+            ST_LOGE("consumerDisconnect: No consumer is connected!");
+            return -EINVAL;
+        }
+
+        mAbandoned = true;
+        mConsumerListener = NULL;
+        mQueue.clear();
+        freeAllBuffersLocked(freeList);
+    }
+    releaseBufferFreeListUnlocked(freeList);
+    mDequeueCondition.broadcast();
+
+    return NO_ERROR;
+}
+
+status_t GonkBufferQueue::getReleasedBuffers(uint32_t* slotMask) {
+    ST_LOGV("getReleasedBuffers");
+    Mutex::Autolock lock(mMutex);
+
+    if (mAbandoned) {
+        ST_LOGE("getReleasedBuffers: GonkBufferQueue has been abandoned!");
+        return NO_INIT;
+    }
+
+    uint32_t mask = 0;
+    for (int i = 0; i < NUM_BUFFER_SLOTS; i++) {
+        if (!mSlots[i].mAcquireCalled) {
+            mask |= 1 << i;
+        }
+    }
+
+    // Remove buffers in flight (on the queue) from the mask where acquire has
+    // been called, as the consumer will not receive the buffer address, so
+    // it should not free these slots.
+    Fifo::iterator front(mQueue.begin());
+    while (front != mQueue.end()) {
+        if (front->mAcquireCalled)
+            mask &= ~(1 << front->mBuf);
+        front++;
+    }
+
+    *slotMask = mask;
+
+    ST_LOGV("getReleasedBuffers: returning mask %#x", mask);
+    return NO_ERROR;
+}
+
+status_t GonkBufferQueue::setDefaultBufferSize(uint32_t w, uint32_t h) {
+    ST_LOGV("setDefaultBufferSize: w=%d, h=%d", w, h);
+    if (!w || !h) {
+        ST_LOGE("setDefaultBufferSize: dimensions cannot be 0 (w=%d, h=%d)",
+                w, h);
+        return BAD_VALUE;
+    }
+
+    Mutex::Autolock lock(mMutex);
+    mDefaultWidth = w;
+    mDefaultHeight = h;
+    return NO_ERROR;
+}
+
+status_t GonkBufferQueue::setDefaultMaxBufferCount(int bufferCount) {
+    ATRACE_CALL();
+    Mutex::Autolock lock(mMutex);
+    return setDefaultMaxBufferCountLocked(bufferCount);
+}
+
+status_t GonkBufferQueue::disableAsyncBuffer() {
+    ATRACE_CALL();
+    Mutex::Autolock lock(mMutex);
+    if (mConsumerListener != NULL) {
+        ST_LOGE("disableAsyncBuffer: consumer already connected!");
+        return INVALID_OPERATION;
+    }
+    mUseAsyncBuffer = false;
+    return NO_ERROR;
+}
+
+status_t GonkBufferQueue::setMaxAcquiredBufferCount(int maxAcquiredBuffers) {
+    ATRACE_CALL();
+    Mutex::Autolock lock(mMutex);
+    if (maxAcquiredBuffers < 1 || maxAcquiredBuffers > MAX_MAX_ACQUIRED_BUFFERS) {
+        ST_LOGE("setMaxAcquiredBufferCount: invalid count specified: %d",
+                maxAcquiredBuffers);
+        return BAD_VALUE;
+    }
+    if (mConnectedApi != NO_CONNECTED_API) {
+        return INVALID_OPERATION;
+    }
+    mMaxAcquiredBufferCount = maxAcquiredBuffers;
+    return NO_ERROR;
+}
+
+int GonkBufferQueue::getMinUndequeuedBufferCount(bool async) const {
+    // if dequeueBuffer is allowed to error out, we don't have to
+    // add an extra buffer.
+    if (!mUseAsyncBuffer)
+        return mMaxAcquiredBufferCount;
+
+    // we're in async mode, or we want to prevent the app to
+    // deadlock itself, we throw-in an extra buffer to guarantee it.
+    if (mDequeueBufferCannotBlock || async)
+        return mMaxAcquiredBufferCount + 1;
+
+    return mMaxAcquiredBufferCount;
+}
+
+int GonkBufferQueue::getMinMaxBufferCountLocked(bool async) const {
+    return getMinUndequeuedBufferCount(async) + 1;
+}
+
+int GonkBufferQueue::getMaxBufferCountLocked(bool async) const {
+    int minMaxBufferCount = getMinMaxBufferCountLocked(async);
+
+    int maxBufferCount = mDefaultMaxBufferCount;
+    if (maxBufferCount < minMaxBufferCount) {
+        maxBufferCount = minMaxBufferCount;
+    }
+    if (mOverrideMaxBufferCount != 0) {
+        assert(mOverrideMaxBufferCount >= minMaxBufferCount);
+        maxBufferCount = mOverrideMaxBufferCount;
+    }
+
+    // Any buffers that are dequeued by the producer or sitting in the queue
+    // waiting to be consumed need to have their slots preserved.  Such
+    // buffers will temporarily keep the max buffer count up until the slots
+    // no longer need to be preserved.
+    for (int i = maxBufferCount; i < NUM_BUFFER_SLOTS; i++) {
+        BufferSlot::BufferState state = mSlots[i].mBufferState;
+        if (state == BufferSlot::QUEUED || state == BufferSlot::DEQUEUED) {
+            maxBufferCount = i + 1;
+        }
+    }
+
+    return maxBufferCount;
+}
+
+bool GonkBufferQueue::stillTracking(const BufferItem *item) const {
+    const BufferSlot &slot = mSlots[item->mBuf];
+
+    ST_LOGV("stillTracking?: item: { slot=%d/%llu, buffer=%p }, "
+            "slot: { slot=%d/%llu, buffer=%p }",
+            item->mBuf, item->mFrameNumber,
+            (item->mGraphicBuffer.get() ? item->mGraphicBuffer->handle : 0),
+            item->mBuf, slot.mFrameNumber,
+            (slot.mGraphicBuffer.get() ? slot.mGraphicBuffer->handle : 0));
+
+    // Compare item with its original buffer slot.  We can check the slot
+    // as the buffer would not be moved to a different slot by the producer.
+    return (slot.mGraphicBuffer != NULL &&
+            item->mGraphicBuffer->handle == slot.mGraphicBuffer->handle);
+}
+
+GonkBufferQueue::ProxyConsumerListener::ProxyConsumerListener(
+        const wp<ConsumerListener>& consumerListener):
+        mConsumerListener(consumerListener) {}
+
+GonkBufferQueue::ProxyConsumerListener::~ProxyConsumerListener() {}
+
+void GonkBufferQueue::ProxyConsumerListener::onFrameAvailable() {
+    sp<ConsumerListener> listener(mConsumerListener.promote());
+    if (listener != NULL) {
+        listener->onFrameAvailable();
+    }
+}
+
+void GonkBufferQueue::ProxyConsumerListener::onBuffersReleased() {
+    sp<ConsumerListener> listener(mConsumerListener.promote());
+    if (listener != NULL) {
+        listener->onBuffersReleased();
+    }
+}
+
+}; // namespace android
new file mode 100644
--- /dev/null
+++ b/widget/gonk/nativewindow/GonkBufferQueueKK.h
@@ -0,0 +1,576 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ * Copyright (C) 2013 Mozilla Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef NATIVEWINDOW_GONKBUFFERQUEUE_KK_H
+#define NATIVEWINDOW_GONKBUFFERQUEUE_KK_H
+
+#include <gui/IConsumerListener.h>
+#include <gui/IGraphicBufferAlloc.h>
+#include <gui/IGraphicBufferProducer.h>
+#include "IGonkGraphicBufferConsumer.h"
+
+#include <ui/Fence.h>
+#include <ui/GraphicBuffer.h>
+
+#include <utils/String8.h>
+#include <utils/Vector.h>
+#include <utils/threads.h>
+
+#include "mozilla/layers/LayersSurfaces.h"
+
+namespace android {
+// ----------------------------------------------------------------------------
+
+class GonkBufferQueue : public BnGraphicBufferProducer,
+                    public BnGonkGraphicBufferConsumer,
+                    private IBinder::DeathRecipient {
+    typedef mozilla::layers::SurfaceDescriptor SurfaceDescriptor;
+
+public:
+    enum { MIN_UNDEQUEUED_BUFFERS = 2 };
+    enum { NUM_BUFFER_SLOTS = 32 };
+    enum { NO_CONNECTED_API = 0 };
+    enum { INVALID_BUFFER_SLOT = -1 };
+    enum { STALE_BUFFER_SLOT = 1, NO_BUFFER_AVAILABLE, PRESENT_LATER };
+
+    // When in async mode we reserve two slots in order to guarantee that the
+    // producer and consumer can run asynchronously.
+    enum { MAX_MAX_ACQUIRED_BUFFERS = NUM_BUFFER_SLOTS - 2 };
+
+    // for backward source compatibility
+    typedef ::android::ConsumerListener ConsumerListener;
+
+    // ProxyConsumerListener is a ConsumerListener implementation that keeps a weak
+    // reference to the actual consumer object.  It forwards all calls to that
+    // consumer object so long as it exists.
+    //
+    // This class exists to avoid having a circular reference between the
+    // GonkBufferQueue object and the consumer object.  The reason this can't be a weak
+    // reference in the GonkBufferQueue class is because we're planning to expose the
+    // consumer side of a GonkBufferQueue as a binder interface, which doesn't support
+    // weak references.
+    class ProxyConsumerListener : public BnConsumerListener {
+    public:
+        ProxyConsumerListener(const wp<ConsumerListener>& consumerListener);
+        virtual ~ProxyConsumerListener();
+        virtual void onFrameAvailable();
+        virtual void onBuffersReleased();
+    private:
+        // mConsumerListener is a weak reference to the IConsumerListener.  This is
+        // the raison d'etre of ProxyConsumerListener.
+        wp<ConsumerListener> mConsumerListener;
+    };
+
+
+    // BufferQueue manages a pool of gralloc memory slots to be used by
+    // producers and consumers. allocator is used to allocate all the
+    // needed gralloc buffers.
+    GonkBufferQueue(bool allowSynchronousMode = true,
+            const sp<IGraphicBufferAlloc>& allocator = NULL);
+    virtual ~GonkBufferQueue();
+
+    /*
+     * IBinder::DeathRecipient interface
+     */
+
+    virtual void binderDied(const wp<IBinder>& who);
+
+    /*
+     * IGraphicBufferProducer interface
+     */
+
+    // Query native window attributes.  The "what" values are enumerated in
+    // window.h (e.g. NATIVE_WINDOW_FORMAT).
+    virtual int query(int what, int* value);
+
+    // setBufferCount updates the number of available buffer slots.  If this
+    // method succeeds, buffer slots will be both unallocated and owned by
+    // the GonkBufferQueue object (i.e. they are not owned by the producer or
+    // consumer).
+    //
+    // This will fail if the producer has dequeued any buffers, or if
+    // bufferCount is invalid.  bufferCount must generally be a value
+    // between the minimum undequeued buffer count and NUM_BUFFER_SLOTS
+    // (inclusive).  It may also be set to zero (the default) to indicate
+    // that the producer does not wish to set a value.  The minimum value
+    // can be obtained by calling query(NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS,
+    // ...).
+    //
+    // This may only be called by the producer.  The consumer will be told
+    // to discard buffers through the onBuffersReleased callback.
+    virtual status_t setBufferCount(int bufferCount);
+
+    // requestBuffer returns the GraphicBuffer for slot N.
+    //
+    // In normal operation, this is called the first time slot N is returned
+    // by dequeueBuffer.  It must be called again if dequeueBuffer returns
+    // flags indicating that previously-returned buffers are no longer valid.
+    virtual status_t requestBuffer(int slot, sp<GraphicBuffer>* buf);
+
+    // dequeueBuffer gets the next buffer slot index for the producer to use.
+    // If a buffer slot is available then that slot index is written to the
+    // location pointed to by the buf argument and a status of OK is returned.
+    // If no slot is available then a status of -EBUSY is returned and buf is
+    // unmodified.
+    //
+    // The fence parameter will be updated to hold the fence associated with
+    // the buffer. The contents of the buffer must not be overwritten until the
+    // fence signals. If the fence is Fence::NO_FENCE, the buffer may be
+    // written immediately.
+    //
+    // The width and height parameters must be no greater than the minimum of
+    // GL_MAX_VIEWPORT_DIMS and GL_MAX_TEXTURE_SIZE (see: glGetIntegerv).
+    // An error due to invalid dimensions might not be reported until
+    // updateTexImage() is called.  If width and height are both zero, the
+    // default values specified by setDefaultBufferSize() are used instead.
+    //
+    // The pixel formats are enumerated in graphics.h, e.g.
+    // HAL_PIXEL_FORMAT_RGBA_8888.  If the format is 0, the default format
+    // will be used.
+    //
+    // The usage argument specifies gralloc buffer usage flags.  The values
+    // are enumerated in gralloc.h, e.g. GRALLOC_USAGE_HW_RENDER.  These
+    // will be merged with the usage flags specified by setConsumerUsageBits.
+    //
+    // The return value may be a negative error value or a non-negative
+    // collection of flags.  If the flags are set, the return values are
+    // valid, but additional actions must be performed.
+    //
+    // If IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION is set, the
+    // producer must discard cached GraphicBuffer references for the slot
+    // returned in buf.
+    // If IGraphicBufferProducer::RELEASE_ALL_BUFFERS is set, the producer
+    // must discard cached GraphicBuffer references for all slots.
+    //
+    // In both cases, the producer will need to call requestBuffer to get a
+    // GraphicBuffer handle for the returned slot.
+    virtual status_t dequeueBuffer(int *buf, sp<Fence>* fence, bool async,
+            uint32_t width, uint32_t height, uint32_t format, uint32_t usage);
+
+    // queueBuffer returns a filled buffer to the GonkBufferQueue.
+    //
+    // Additional data is provided in the QueueBufferInput struct.  Notably,
+    // a timestamp must be provided for the buffer. The timestamp is in
+    // nanoseconds, and must be monotonically increasing. Its other semantics
+    // (zero point, etc) are producer-specific and should be documented by the
+    // producer.
+    //
+    // The caller may provide a fence that signals when all rendering
+    // operations have completed.  Alternatively, NO_FENCE may be used,
+    // indicating that the buffer is ready immediately.
+    //
+    // Some values are returned in the output struct: the current settings
+    // for default width and height, the current transform hint, and the
+    // number of queued buffers.
+    virtual status_t queueBuffer(int buf,
+            const QueueBufferInput& input, QueueBufferOutput* output);
+
+    // cancelBuffer returns a dequeued buffer to the GonkBufferQueue, but doesn't
+    // queue it for use by the consumer.
+    //
+    // The buffer will not be overwritten until the fence signals.  The fence
+    // will usually be the one obtained from dequeueBuffer.
+    virtual void cancelBuffer(int buf, const sp<Fence>& fence);
+
+    // connect attempts to connect a producer API to the GonkBufferQueue.  This
+    // must be called before any other IGraphicBufferProducer methods are
+    // called except for getAllocator.  A consumer must already be connected.
+    //
+    // This method will fail if connect was previously called on the
+    // GonkBufferQueue and no corresponding disconnect call was made (i.e. if
+    // it's still connected to a producer).
+    //
+    // APIs are enumerated in window.h (e.g. NATIVE_WINDOW_API_CPU).
+    virtual status_t connect(const sp<IBinder>& token,
+            int api, bool producerControlledByApp, QueueBufferOutput* output);
+
+    // disconnect attempts to disconnect a producer API from the GonkBufferQueue.
+    // Calling this method will cause any subsequent calls to other
+    // IGraphicBufferProducer methods to fail except for getAllocator and connect.
+    // Successfully calling connect after this will allow the other methods to
+    // succeed again.
+    //
+    // This method will fail if the the GonkBufferQueue is not currently
+    // connected to the specified producer API.
+    virtual status_t disconnect(int api);
+
+    /*
+     * IGraphicBufferConsumer interface
+     */
+
+    // acquireBuffer attempts to acquire ownership of the next pending buffer in
+    // the GonkBufferQueue.  If no buffer is pending then it returns -EINVAL.  If a
+    // buffer is successfully acquired, the information about the buffer is
+    // returned in BufferItem.  If the buffer returned had previously been
+    // acquired then the BufferItem::mGraphicBuffer field of buffer is set to
+    // NULL and it is assumed that the consumer still holds a reference to the
+    // buffer.
+    //
+    // If presentWhen is nonzero, it indicates the time when the buffer will
+    // be displayed on screen.  If the buffer's timestamp is farther in the
+    // future, the buffer won't be acquired, and PRESENT_LATER will be
+    // returned.  The presentation time is in nanoseconds, and the time base
+    // is CLOCK_MONOTONIC.
+    virtual status_t acquireBuffer(BufferItem *buffer, nsecs_t presentWhen);
+
+    // releaseBuffer releases a buffer slot from the consumer back to the
+    // GonkBufferQueue.  This may be done while the buffer's contents are still
+    // being accessed.  The fence will signal when the buffer is no longer
+    // in use. frameNumber is used to indentify the exact buffer returned.
+    //
+    // If releaseBuffer returns STALE_BUFFER_SLOT, then the consumer must free
+    // any references to the just-released buffer that it might have, as if it
+    // had received a onBuffersReleased() call with a mask set for the released
+    // buffer.
+    //
+    // Note that the dependencies on EGL will be removed once we switch to using
+    // the Android HW Sync HAL.
+    virtual status_t releaseBuffer(int buf, uint64_t frameNumber,
+                    const sp<Fence>& releaseFence);
+
+    // consumerConnect connects a consumer to the GonkBufferQueue.  Only one
+    // consumer may be connected, and when that consumer disconnects the
+    // GonkBufferQueue is placed into the "abandoned" state, causing most
+    // interactions with the GonkBufferQueue by the producer to fail.
+    // controlledByApp indicates whether the consumer is controlled by
+    // the application.
+    //
+    // consumer may not be NULL.
+    virtual status_t consumerConnect(const sp<IConsumerListener>& consumer, bool controlledByApp);
+
+    // consumerDisconnect disconnects a consumer from the GonkBufferQueue. All
+    // buffers will be freed and the GonkBufferQueue is placed in the "abandoned"
+    // state, causing most interactions with the GonkBufferQueue by the producer to
+    // fail.
+    virtual status_t consumerDisconnect();
+
+    // getReleasedBuffers sets the value pointed to by slotMask to a bit mask
+    // indicating which buffer slots have been released by the GonkBufferQueue
+    // but have not yet been released by the consumer.
+    //
+    // This should be called from the onBuffersReleased() callback.
+    virtual status_t getReleasedBuffers(uint32_t* slotMask);
+
+    // setDefaultBufferSize is used to set the size of buffers returned by
+    // dequeueBuffer when a width and height of zero is requested.  Default
+    // is 1x1.
+    virtual status_t setDefaultBufferSize(uint32_t w, uint32_t h);
+
+    // setDefaultMaxBufferCount sets the default value for the maximum buffer
+    // count (the initial default is 2). If the producer has requested a
+    // buffer count using setBufferCount, the default buffer count will only
+    // take effect if the producer sets the count back to zero.
+    //
+    // The count must be between 2 and NUM_BUFFER_SLOTS, inclusive.
+    virtual status_t setDefaultMaxBufferCount(int bufferCount);
+
+    // disableAsyncBuffer disables the extra buffer used in async mode
+    // (when both producer and consumer have set their "isControlledByApp"
+    // flag) and has dequeueBuffer() return WOULD_BLOCK instead.
+    //
+    // This can only be called before consumerConnect().
+    virtual status_t disableAsyncBuffer();
+
+    // setMaxAcquiredBufferCount sets the maximum number of buffers that can
+    // be acquired by the consumer at one time (default 1).  This call will
+    // fail if a producer is connected to the GonkBufferQueue.
+    virtual status_t setMaxAcquiredBufferCount(int maxAcquiredBuffers);
+
+    // setConsumerName sets the name used in logging
+    virtual void setConsumerName(const String8& name);
+
+    // setDefaultBufferFormat allows the GonkBufferQueue to create
+    // GraphicBuffers of a defaultFormat if no format is specified
+    // in dequeueBuffer.  Formats are enumerated in graphics.h; the
+    // initial default is HAL_PIXEL_FORMAT_RGBA_8888.
+    virtual status_t setDefaultBufferFormat(uint32_t defaultFormat);
+
+    // setConsumerUsageBits will turn on additional usage bits for dequeueBuffer.
+    // These are merged with the bits passed to dequeueBuffer.  The values are
+    // enumerated in gralloc.h, e.g. GRALLOC_USAGE_HW_RENDER; the default is 0.
+    virtual status_t setConsumerUsageBits(uint32_t usage);
+
+    // setTransformHint bakes in rotation to buffers so overlays can be used.
+    // The values are enumerated in window.h, e.g.
+    // NATIVE_WINDOW_TRANSFORM_ROT_90.  The default is 0 (no transform).
+    virtual status_t setTransformHint(uint32_t hint);
+
+    // dump our state in a String
+    virtual void dump(String8& result, const char* prefix) const;
+
+    int getGeneration();
+    SurfaceDescriptor *getSurfaceDescriptorFromBuffer(ANativeWindowBuffer* buffer);
+
+private:
+    // releaseBufferFreeListUnlocked releases the resources in the freeList;
+    // this must be called with mMutex unlocked.
+    void releaseBufferFreeListUnlocked(nsTArray<SurfaceDescriptor>& freeList);
+
+    // freeBufferLocked frees the GraphicBuffer and sync resources for the
+    // given slot.
+    //void freeBufferLocked(int index);
+
+    // freeAllBuffersLocked frees the GraphicBuffer and sync resources for
+    // all slots.
+    //void freeAllBuffersLocked();
+    void freeAllBuffersLocked(nsTArray<SurfaceDescriptor>& freeList);
+
+    // setDefaultMaxBufferCountLocked sets the maximum number of buffer slots
+    // that will be used if the producer does not override the buffer slot
+    // count.  The count must be between 2 and NUM_BUFFER_SLOTS, inclusive.
+    // The initial default is 2.
+    status_t setDefaultMaxBufferCountLocked(int count);
+
+    // getMinUndequeuedBufferCount returns the minimum number of buffers
+    // that must remain in a state other than DEQUEUED.
+    // The async parameter tells whether we're in asynchronous mode.
+    int getMinUndequeuedBufferCount(bool async) const;
+
+    // getMinBufferCountLocked returns the minimum number of buffers allowed
+    // given the current GonkBufferQueue state.
+    // The async parameter tells whether we're in asynchronous mode.
+    int getMinMaxBufferCountLocked(bool async) const;
+
+    // getMaxBufferCountLocked returns the maximum number of buffers that can
+    // be allocated at once.  This value depends upon the following member
+    // variables:
+    //
+    //      mDequeueBufferCannotBlock
+    //      mMaxAcquiredBufferCount
+    //      mDefaultMaxBufferCount
+    //      mOverrideMaxBufferCount
+    //      async parameter
+    //
+    // Any time one of these member variables is changed while a producer is
+    // connected, mDequeueCondition must be broadcast.
+    int getMaxBufferCountLocked(bool async) const;
+
+    // stillTracking returns true iff the buffer item is still being tracked
+    // in one of the slots.
+    bool stillTracking(const BufferItem *item) const;
+
+    struct BufferSlot {
+
+        BufferSlot()
+        : mSurfaceDescriptor(SurfaceDescriptor()),
+          mBufferState(BufferSlot::FREE),
+          mRequestBufferCalled(false),
+          mFrameNumber(0),
+          mAcquireCalled(false),
+          mNeedsCleanupOnRelease(false) {
+        }
+
+        // mGraphicBuffer points to the buffer allocated for this slot or is NULL
+        // if no buffer has been allocated.
+        sp<GraphicBuffer> mGraphicBuffer;
+
+        // mSurfaceDescriptor is the token to remotely allocated GraphicBuffer.
+        SurfaceDescriptor mSurfaceDescriptor;
+
+        // BufferState represents the different states in which a buffer slot
+        // can be.  All slots are initially FREE.
+        enum BufferState {
+            // FREE indicates that the buffer is available to be dequeued
+            // by the producer.  The buffer may be in use by the consumer for
+            // a finite time, so the buffer must not be modified until the
+            // associated fence is signaled.
+            //
+            // The slot is "owned" by GonkBufferQueue.  It transitions to DEQUEUED
+            // when dequeueBuffer is called.
+            FREE = 0,
+
+            // DEQUEUED indicates that the buffer has been dequeued by the
+            // producer, but has not yet been queued or canceled.  The
+            // producer may modify the buffer's contents as soon as the
+            // associated ready fence is signaled.
+            //
+            // The slot is "owned" by the producer.  It can transition to
+            // QUEUED (via queueBuffer) or back to FREE (via cancelBuffer).
+            DEQUEUED = 1,
+
+            // QUEUED indicates that the buffer has been filled by the
+            // producer and queued for use by the consumer.  The buffer
+            // contents may continue to be modified for a finite time, so
+            // the contents must not be accessed until the associated fence
+            // is signaled.
+            //
+            // The slot is "owned" by GonkBufferQueue.  It can transition to
+            // ACQUIRED (via acquireBuffer) or to FREE (if another buffer is
+            // queued in asynchronous mode).
+            QUEUED = 2,
+
+            // ACQUIRED indicates that the buffer has been acquired by the
+            // consumer.  As with QUEUED, the contents must not be accessed
+            // by the consumer until the fence is signaled.
+            //
+            // The slot is "owned" by the consumer.  It transitions to FREE
+            // when releaseBuffer is called.
+            ACQUIRED = 3
+        };
+
+        // mBufferState is the current state of this buffer slot.
+        BufferState mBufferState;
+
+        // mRequestBufferCalled is used for validating that the producer did
+        // call requestBuffer() when told to do so. Technically this is not
+        // needed but useful for debugging and catching producer bugs.
+        bool mRequestBufferCalled;
+
+        // mFrameNumber is the number of the queued frame for this slot.  This
+        // is used to dequeue buffers in LRU order (useful because buffers
+        // may be released before their release fence is signaled).
+        uint64_t mFrameNumber;
+
+        // mFence is a fence which will signal when work initiated by the
+        // previous owner of the buffer is finished. When the buffer is FREE,
+        // the fence indicates when the consumer has finished reading
+        // from the buffer, or when the producer has finished writing if it
+        // called cancelBuffer after queueing some writes. When the buffer is
+        // QUEUED, it indicates when the producer has finished filling the
+        // buffer. When the buffer is DEQUEUED or ACQUIRED, the fence has been
+        // passed to the consumer or producer along with ownership of the
+        // buffer, and mFence is set to NO_FENCE.
+        sp<Fence> mFence;
+
+        // Indicates whether this buffer has been seen by a consumer yet
+        bool mAcquireCalled;
+
+        // Indicates whether this buffer needs to be cleaned up by the
+        // consumer.  This is set when a buffer in ACQUIRED state is freed.
+        // It causes releaseBuffer to return STALE_BUFFER_SLOT.
+        bool mNeedsCleanupOnRelease;
+    };
+
+    // mSlots is the array of buffer slots that must be mirrored on the
+    // producer side. This allows buffer ownership to be transferred between
+    // the producer and consumer without sending a GraphicBuffer over binder.
+    // The entire array is initialized to NULL at construction time, and
+    // buffers are allocated for a slot when requestBuffer is called with
+    // that slot's index.
+    BufferSlot mSlots[NUM_BUFFER_SLOTS];
+
+    // mDefaultWidth holds the default width of allocated buffers. It is used
+    // in dequeueBuffer() if a width and height of zero is specified.
+    uint32_t mDefaultWidth;
+
+    // mDefaultHeight holds the default height of allocated buffers. It is used
+    // in dequeueBuffer() if a width and height of zero is specified.
+    uint32_t mDefaultHeight;
+
+    // mMaxAcquiredBufferCount is the number of buffers that the consumer may
+    // acquire at one time.  It defaults to 1 and can be changed by the
+    // consumer via the setMaxAcquiredBufferCount method, but this may only be
+    // done when no producer is connected to the GonkBufferQueue.
+    //
+    // This value is used to derive the value returned for the
+    // MIN_UNDEQUEUED_BUFFERS query by the producer.
+    int mMaxAcquiredBufferCount;
+
+    // mDefaultMaxBufferCount is the default limit on the number of buffers
+    // that will be allocated at one time.  This default limit is set by the
+    // consumer.  The limit (as opposed to the default limit) may be
+    // overridden by the producer.
+    int mDefaultMaxBufferCount;
+
+    // mOverrideMaxBufferCount is the limit on the number of buffers that will
+    // be allocated at one time. This value is set by the image producer by
+    // calling setBufferCount. The default is zero, which means the producer
+    // doesn't care about the number of buffers in the pool. In that case
+    // mDefaultMaxBufferCount is used as the limit.
+    int mOverrideMaxBufferCount;
+
+    // mGraphicBufferAlloc is the connection to SurfaceFlinger that is used to
+    // allocate new GraphicBuffer objects.
+    sp<IGraphicBufferAlloc> mGraphicBufferAlloc;
+
+    // mConsumerListener is used to notify the connected consumer of
+    // asynchronous events that it may wish to react to.  It is initially set
+    // to NULL and is written by consumerConnect and consumerDisconnect.
+    sp<IConsumerListener> mConsumerListener;
+
+    // mConsumerControlledByApp whether the connected consumer is controlled by the
+    // application.
+    bool mConsumerControlledByApp;
+
+    // mDequeueBufferCannotBlock whether dequeueBuffer() isn't allowed to block.
+    // this flag is set during connect() when both consumer and producer are controlled
+    // by the application.
+    bool mDequeueBufferCannotBlock;
+
+    // mUseAsyncBuffer whether an extra buffer is used in async mode to prevent
+    // dequeueBuffer() from ever blocking.
+    bool mUseAsyncBuffer;
+
+    // mConnectedApi indicates the producer API that is currently connected
+    // to this GonkBufferQueue.  It defaults to NO_CONNECTED_API (= 0), and gets
+    // updated by the connect and disconnect methods.
+    int mConnectedApi;
+
+    // mDequeueCondition condition used for dequeueBuffer in synchronous mode
+    mutable Condition mDequeueCondition;
+
+    // mQueue is a FIFO of queued buffers used in synchronous mode
+    typedef Vector<BufferItem> Fifo;
+    Fifo mQueue;
+
+    // mAbandoned indicates that the GonkBufferQueue will no longer be used to
+    // consume image buffers pushed to it using the IGraphicBufferProducer
+    // interface.  It is initialized to false, and set to true in the
+    // consumerDisconnect method.  A GonkBufferQueue that has been abandoned will
+    // return the NO_INIT error from all IGraphicBufferProducer methods
+    // capable of returning an error.
+    bool mAbandoned;
+
+    // mConsumerName is a string used to identify the GonkBufferQueue in log
+    // messages.  It is set by the setConsumerName method.
+    String8 mConsumerName;
+
+    // mMutex is the mutex used to prevent concurrent access to the member
+    // variables of GonkBufferQueue objects. It must be locked whenever the
+    // member variables are accessed.
+    mutable Mutex mMutex;
+
+    // mFrameCounter is the free running counter, incremented on every
+    // successful queueBuffer call, and buffer allocation.
+    uint64_t mFrameCounter;
+
+    // mBufferHasBeenQueued is true once a buffer has been queued.  It is
+    // reset when something causes all buffers to be freed (e.g. changing the
+    // buffer count).
+    bool mBufferHasBeenQueued;
+
+    // mDefaultBufferFormat can be set so it will override
+    // the buffer format when it isn't specified in dequeueBuffer
+    uint32_t mDefaultBufferFormat;
+
+    // mConsumerUsageBits contains flags the consumer wants for GraphicBuffers
+    uint32_t mConsumerUsageBits;
+
+    // mTransformHint is used to optimize for screen rotations
+    uint32_t mTransformHint;
+
+    // mConnectedProducerToken is used to set a binder death notification on the producer
+    sp<IBinder> mConnectedProducerToken;
+
+    // mGeneration is the current generation of buffer slots
+    uint32_t mGeneration;
+};
+
+// ----------------------------------------------------------------------------
+}; // namespace android
+
+#endif // ANDROID_GUI_BUFFERQUEUE_H
rename from widget/gonk/nativewindow/GonkConsumerBase.cpp
rename to widget/gonk/nativewindow/GonkConsumerBaseJB.cpp
--- a/widget/gonk/nativewindow/GonkConsumerBase.cpp
+++ b/widget/gonk/nativewindow/GonkConsumerBaseJB.cpp
@@ -22,17 +22,17 @@
 #define EGL_EGLEXT_PROTOTYPES
 
 #include <hardware/hardware.h>
 
 #include <gui/IGraphicBufferAlloc.h>
 #include <utils/Log.h>
 #include <utils/String8.h>
 
-#include "GonkConsumerBase.h"
+#include "GonkConsumerBaseJB.h"
 
 // Macros for including the GonkConsumerBase name in log messages
 #define CB_LOGV(...) __android_log_print(ANDROID_LOG_VERBOSE, LOG_TAG, __VA_ARGS__)
 #define CB_LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)
 #define CB_LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)
 #define CB_LOGW(...) __android_log_print(ANDROID_LOG_WARN, LOG_TAG, __VA_ARGS__)
 #define CB_LOGE(...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)
 
rename from widget/gonk/nativewindow/GonkConsumerBase.h
rename to widget/gonk/nativewindow/GonkConsumerBaseJB.h
--- a/widget/gonk/nativewindow/GonkConsumerBase.h
+++ b/widget/gonk/nativewindow/GonkConsumerBaseJB.h
@@ -10,26 +10,26 @@
  *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
 
-#ifndef NATIVEWINDOW_GONKCONSUMERBASE_H
-#define NATIVEWINDOW_GONKCONSUMERBASE_H
+#ifndef NATIVEWINDOW_GONKCONSUMERBASE_JB_H
+#define NATIVEWINDOW_GONKCONSUMERBASE_JB_H
 
 #include <ui/GraphicBuffer.h>
 
 #include <utils/String8.h>
 #include <utils/Vector.h>
 #include <utils/threads.h>
 
-#include "GonkBufferQueue.h"
+#include "GonkBufferQueueJB.h"
 
 namespace android {
 // ----------------------------------------------------------------------------
 
 class String8;
 
 // GonkConsumerBase is a base class for GonkBufferQueue consumer end-points. It
 // handles common tasks like management of the connection to the GonkBufferQueue
new file mode 100644
--- /dev/null
+++ b/widget/gonk/nativewindow/GonkConsumerBaseKK.cpp
@@ -0,0 +1,259 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ * Copyright (C) 2013 Mozilla Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "GonkConsumerBase"
+#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+//#define LOG_NDEBUG 0
+
+#define EGL_EGLEXT_PROTOTYPES
+
+#include <hardware/hardware.h>
+
+#include <gui/IGraphicBufferAlloc.h>
+#include <utils/Log.h>
+#include <utils/String8.h>
+
+#include "GonkConsumerBaseKK.h"
+
+// Macros for including the GonkConsumerBase name in log messages
+#define CB_LOGV(...) __android_log_print(ANDROID_LOG_VERBOSE, LOG_TAG, __VA_ARGS__)
+#define CB_LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)
+#define CB_LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)
+#define CB_LOGW(...) __android_log_print(ANDROID_LOG_WARN, LOG_TAG, __VA_ARGS__)
+#define CB_LOGE(...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)
+
+namespace android {
+
+// Get an ID that's unique within this process.
+static int32_t createProcessUniqueId() {
+    static volatile int32_t globalCounter = 0;
+    return android_atomic_inc(&globalCounter);
+}
+
+GonkConsumerBase::GonkConsumerBase(const sp<GonkBufferQueue>& bufferQueue, bool controlledByApp) :
+        mAbandoned(false),
+        mConsumer(bufferQueue) {
+    // Choose a name using the PID and a process-unique ID.
+    mName = String8::format("unnamed-%d-%d", getpid(), createProcessUniqueId());
+
+    // Note that we can't create an sp<...>(this) in a ctor that will not keep a
+    // reference once the ctor ends, as that would cause the refcount of 'this'
+    // dropping to 0 at the end of the ctor.  Since all we need is a wp<...>
+    // that's what we create.
+    wp<ConsumerListener> listener = static_cast<ConsumerListener*>(this);
+    sp<IConsumerListener> proxy = new GonkBufferQueue::ProxyConsumerListener(listener);
+
+    status_t err = mConsumer->consumerConnect(proxy, controlledByApp);
+    if (err != NO_ERROR) {
+        CB_LOGE("GonkConsumerBase: error connecting to GonkBufferQueue: %s (%d)",
+                strerror(-err), err);
+    } else {
+        mConsumer->setConsumerName(mName);
+    }
+}
+
+GonkConsumerBase::~GonkConsumerBase() {
+    CB_LOGV("~GonkConsumerBase");
+    Mutex::Autolock lock(mMutex);
+
+    // Verify that abandon() has been called before we get here.  This should
+    // be done by GonkConsumerBase::onLastStrongRef(), but it's possible for a
+    // derived class to override that method and not call
+    // GonkConsumerBase::onLastStrongRef().
+    LOG_ALWAYS_FATAL_IF(!mAbandoned, "[%s] ~GonkConsumerBase was called, but the "
+        "consumer is not abandoned!", mName.string());
+}
+
+void GonkConsumerBase::onLastStrongRef(const void* id) {
+    abandon();
+}
+
+void GonkConsumerBase::freeBufferLocked(int slotIndex) {
+    CB_LOGV("freeBufferLocked: slotIndex=%d", slotIndex);
+    mSlots[slotIndex].mGraphicBuffer = 0;
+    mSlots[slotIndex].mFence = Fence::NO_FENCE;
+    mSlots[slotIndex].mFrameNumber = 0;
+}
+
+// Used for refactoring, should not be in final interface
+sp<GonkBufferQueue> GonkConsumerBase::getBufferQueue() const {
+    Mutex::Autolock lock(mMutex);
+    return mConsumer;
+}
+
+void GonkConsumerBase::onFrameAvailable() {
+    CB_LOGV("onFrameAvailable");
+
+    sp<FrameAvailableListener> listener;
+    { // scope for the lock
+        Mutex::Autolock lock(mMutex);
+        listener = mFrameAvailableListener.promote();
+    }
+
+    if (listener != NULL) {
+        CB_LOGV("actually calling onFrameAvailable");
+        listener->onFrameAvailable();
+    }
+}
+
+void GonkConsumerBase::onBuffersReleased() {
+    Mutex::Autolock lock(mMutex);
+
+    CB_LOGV("onBuffersReleased");
+
+    if (mAbandoned) {
+        // Nothing to do if we're already abandoned.
+        return;
+    }
+
+    uint32_t mask = 0;
+    mConsumer->getReleasedBuffers(&mask);
+    for (int i = 0; i < GonkBufferQueue::NUM_BUFFER_SLOTS; i++) {
+        if (mask & (1 << i)) {
+            freeBufferLocked(i);
+        }
+    }
+}
+
+void GonkConsumerBase::abandon() {
+    CB_LOGV("abandon");
+    Mutex::Autolock lock(mMutex);
+
+    if (!mAbandoned) {
+        abandonLocked();
+        mAbandoned = true;
+    }
+}
+
+void GonkConsumerBase::abandonLocked() {
+	CB_LOGV("abandonLocked");
+    for (int i =0; i < GonkBufferQueue::NUM_BUFFER_SLOTS; i++) {
+        freeBufferLocked(i);
+    }
+    // disconnect from the BufferQueue
+    mConsumer->consumerDisconnect();
+    mConsumer.clear();
+}
+
+void GonkConsumerBase::setFrameAvailableListener(
+        const wp<FrameAvailableListener>& listener) {
+    CB_LOGV("setFrameAvailableListener");
+    Mutex::Autolock lock(mMutex);
+    mFrameAvailableListener = listener;
+}
+
+void GonkConsumerBase::dump(String8& result) const {
+    dump(result, "");
+}
+
+void GonkConsumerBase::dump(String8& result, const char* prefix) const {
+    Mutex::Autolock _l(mMutex);
+    dumpLocked(result, prefix);
+}
+
+void GonkConsumerBase::dumpLocked(String8& result, const char* prefix) const {
+    result.appendFormat("%smAbandoned=%d\n", prefix, int(mAbandoned));
+
+    if (!mAbandoned) {
+        mConsumer->dump(result, prefix);
+    }
+}
+
+status_t GonkConsumerBase::acquireBufferLocked(IGonkGraphicBufferConsumer::BufferItem *item,
+        nsecs_t presentWhen) {
+    status_t err = mConsumer->acquireBuffer(item, presentWhen);
+    if (err != NO_ERROR) {
+        return err;
+    }
+
+    if (item->mGraphicBuffer != NULL) {
+        mSlots[item->mBuf].mGraphicBuffer = item->mGraphicBuffer;
+    }
+
+    mSlots[item->mBuf].mFrameNumber = item->mFrameNumber;
+    mSlots[item->mBuf].mFence = item->mFence;
+
+    CB_LOGV("acquireBufferLocked: -> slot=%d", item->mBuf);
+
+    return OK;
+}
+
+status_t GonkConsumerBase::addReleaseFence(int slot,
+        const sp<GraphicBuffer> graphicBuffer, const sp<Fence>& fence) {
+    Mutex::Autolock lock(mMutex);
+    return addReleaseFenceLocked(slot, graphicBuffer, fence);
+}
+
+status_t GonkConsumerBase::addReleaseFenceLocked(int slot,
+        const sp<GraphicBuffer> graphicBuffer, const sp<Fence>& fence) {
+    CB_LOGV("addReleaseFenceLocked: slot=%d", slot);
+
+    // If consumer no longer tracks this graphicBuffer, we can safely
+    // drop this fence, as it will never be received by the producer.
+    if (!stillTracking(slot, graphicBuffer)) {
+        return OK;
+    }
+
+    if (!mSlots[slot].mFence.get()) {
+        mSlots[slot].mFence = fence;
+    } else {
+        sp<Fence> mergedFence = Fence::merge(
+                String8::format("%.28s:%d", mName.string(), slot),
+                mSlots[slot].mFence, fence);
+        if (!mergedFence.get()) {
+            CB_LOGE("failed to merge release fences");
+            // synchronization is broken, the best we can do is hope fences
+            // signal in order so the new fence will act like a union
+            mSlots[slot].mFence = fence;
+            return BAD_VALUE;
+        }
+        mSlots[slot].mFence = mergedFence;
+    }
+
+    return OK;
+}
+
+status_t GonkConsumerBase::releaseBufferLocked(int slot, const sp<GraphicBuffer> graphicBuffer) {
+    // If consumer no longer tracks this graphicBuffer (we received a new
+    // buffer on the same slot), the buffer producer is definitely no longer
+    // tracking it.
+    if (!stillTracking(slot, graphicBuffer)) {
+        return OK;
+    }
+
+    CB_LOGV("releaseBufferLocked: slot=%d/%llu",
+            slot, mSlots[slot].mFrameNumber);
+    status_t err = mConsumer->releaseBuffer(slot, mSlots[slot].mFrameNumber, mSlots[slot].mFence);
+    if (err == GonkBufferQueue::STALE_BUFFER_SLOT) {
+        freeBufferLocked(slot);
+    }
+
+    mSlots[slot].mFence = Fence::NO_FENCE;
+
+    return err;
+}
+
+bool GonkConsumerBase::stillTracking(int slot,
+        const sp<GraphicBuffer> graphicBuffer) {
+    if (slot < 0 || slot >= GonkBufferQueue::NUM_BUFFER_SLOTS) {
+        return false;
+    }
+    return (mSlots[slot].mGraphicBuffer != NULL &&
+            mSlots[slot].mGraphicBuffer->handle == graphicBuffer->handle);
+}
+
+} // namespace android
new file mode 100644
--- /dev/null
+++ b/widget/gonk/nativewindow/GonkConsumerBaseKK.h
@@ -0,0 +1,240 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ * Copyright (C) 2013 Mozilla Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef NATIVEWINDOW_GONKCONSUMERBASE_KK_H
+#define NATIVEWINDOW_GONKCONSUMERBASE_KK_H
+
+#include <ui/GraphicBuffer.h>
+
+#include <utils/String8.h>
+#include <utils/Vector.h>
+#include <utils/threads.h>
+#include <gui/IConsumerListener.h>
+
+#include "GonkBufferQueueKK.h"
+
+namespace android {
+// ----------------------------------------------------------------------------
+
+class String8;
+
+// GonkConsumerBase is a base class for GonkBufferQueue consumer end-points. It
+// handles common tasks like management of the connection to the GonkBufferQueue
+// and the buffer pool.
+class GonkConsumerBase : public virtual RefBase,
+        protected ConsumerListener {
+public:
+    struct FrameAvailableListener : public virtual RefBase {
+        // onFrameAvailable() is called each time an additional frame becomes
+        // available for consumption. This means that frames that are queued
+        // while in asynchronous mode only trigger the callback if no previous
+        // frames are pending. Frames queued while in synchronous mode always
+        // trigger the callback.
+        //
+        // This is called without any lock held and can be called concurrently
+        // by multiple threads.
+        virtual void onFrameAvailable() = 0;
+    };
+
+    virtual ~GonkConsumerBase();
+
+    // abandon frees all the buffers and puts the GonkConsumerBase into the
+    // 'abandoned' state.  Once put in this state the GonkConsumerBase can never
+    // leave it.  When in the 'abandoned' state, all methods of the
+    // IGraphicBufferProducer interface will fail with the NO_INIT error.
+    //
+    // Note that while calling this method causes all the buffers to be freed
+    // from the perspective of the the GonkConsumerBase, if there are additional
+    // references on the buffers (e.g. if a buffer is referenced by a client
+    // or by OpenGL ES as a texture) then those buffer will remain allocated.
+    void abandon();
+
+    // set the name of the GonkConsumerBase that will be used to identify it in
+    // log messages.
+    void setName(const String8& name);
+
+    // getBufferQueue returns the GonkBufferQueue object to which this
+    // GonkConsumerBase is connected.
+    sp<GonkBufferQueue> getBufferQueue() const;
+
+    // dump writes the current state to a string. Child classes should add
+    // their state to the dump by overriding the dumpLocked method, which is
+    // called by these methods after locking the mutex.
+    void dump(String8& result) const;
+    void dump(String8& result, const char* prefix) const;
+
+    // setFrameAvailableListener sets the listener object that will be notified
+    // when a new frame becomes available.
+    void setFrameAvailableListener(const wp<FrameAvailableListener>& listener);
+
+private:
+    GonkConsumerBase(const GonkConsumerBase&);
+    void operator=(const GonkConsumerBase&);
+
+protected:
+
+    // GonkConsumerBase constructs a new GonkConsumerBase object to consume image
+    // buffers from the given GonkBufferQueue.
+    GonkConsumerBase(const sp<GonkBufferQueue>& bufferQueue, bool controlledByApp = false);
+
+    // onLastStrongRef gets called by RefBase just before the dtor of the most
+    // derived class.  It is used to clean up the buffers so that GonkConsumerBase
+    // can coordinate the clean-up by calling into virtual methods implemented
+    // by the derived classes.  This would not be possible from the
+    // ConsuemrBase dtor because by the time that gets called the derived
+    // classes have already been destructed.
+    //
+    // This methods should not need to be overridden by derived classes, but
+    // if they are overridden the GonkConsumerBase implementation must be called
+    // from the derived class.
+    virtual void onLastStrongRef(const void* id);
+
+    // Implementation of the GonkBufferQueue::ConsumerListener interface.  These
+    // calls are used to notify the GonkConsumerBase of asynchronous events in the
+    // GonkBufferQueue.  These methods should not need to be overridden by derived
+    // classes, but if they are overridden the GonkConsumerBase implementation
+    // must be called from the derived class.
+    virtual void onFrameAvailable();
+    virtual void onBuffersReleased();
+
+    // freeBufferLocked frees up the given buffer slot.  If the slot has been
+    // initialized this will release the reference to the GraphicBuffer in that
+    // slot.  Otherwise it has no effect.
+    //
+    // Derived classes should override this method to clean up any state they
+    // keep per slot.  If it is overridden, the derived class's implementation
+    // must call GonkConsumerBase::freeBufferLocked.
+    //
+    // This method must be called with mMutex locked.
+    virtual void freeBufferLocked(int slotIndex);
+
+    // abandonLocked puts the GonkBufferQueue into the abandoned state, causing
+    // all future operations on it to fail. This method rather than the public
+    // abandon method should be overridden by child classes to add abandon-
+    // time behavior.
+    //
+    // Derived classes should override this method to clean up any object
+    // state they keep (as opposed to per-slot state).  If it is overridden,
+    // the derived class's implementation must call GonkConsumerBase::abandonLocked.
+    //
+    // This method must be called with mMutex locked.
+    virtual void abandonLocked();
+
+    // dumpLocked dumps the current state of the GonkConsumerBase object to the
+    // result string.  Each line is prefixed with the string pointed to by the
+    // prefix argument.  The buffer argument points to a buffer that may be
+    // used for intermediate formatting data, and the size of that buffer is
+    // indicated by the size argument.
+    //
+    // Derived classes should override this method to dump their internal
+    // state.  If this method is overridden the derived class's implementation
+    // should call GonkConsumerBase::dumpLocked.
+    //
+    // This method must be called with mMutex locked.
+    virtual void dumpLocked(String8& result, const char* prefix) const;
+
+    // acquireBufferLocked fetches the next buffer from the GonkBufferQueue and
+    // updates the buffer slot for the buffer returned.
+    //
+    // Derived classes should override this method to perform any
+    // initialization that must take place the first time a buffer is assigned
+    // to a slot.  If it is overridden the derived class's implementation must
+    // call GonkConsumerBase::acquireBufferLocked.
+    virtual status_t acquireBufferLocked(IGonkGraphicBufferConsumer::BufferItem *item,
+        nsecs_t presentWhen);
+
+    // releaseBufferLocked relinquishes control over a buffer, returning that
+    // control to the GonkBufferQueue.
+    //
+    // Derived classes should override this method to perform any cleanup that
+    // must take place when a buffer is released back to the GonkBufferQueue.  If
+    // it is overridden the derived class's implementation must call
+    // GonkConsumerBase::releaseBufferLocked.
+    virtual status_t releaseBufferLocked(int slot, const sp<GraphicBuffer> graphicBuffer);
+
+    // returns true iff the slot still has the graphicBuffer in it.
+    bool stillTracking(int slot, const sp<GraphicBuffer> graphicBuffer);
+
+    // addReleaseFence* adds the sync points associated with a fence to the set
+    // of sync points that must be reached before the buffer in the given slot
+    // may be used after the slot has been released.  This should be called by
+    // derived classes each time some asynchronous work is kicked off that
+    // references the buffer.
+    status_t addReleaseFence(int slot,
+            const sp<GraphicBuffer> graphicBuffer, const sp<Fence>& fence);
+    status_t addReleaseFenceLocked(int slot,
+            const sp<GraphicBuffer> graphicBuffer, const sp<Fence>& fence);
+
+    // Slot contains the information and object references that
+    // GonkConsumerBase maintains about a GonkBufferQueue buffer slot.
+    struct Slot {
+        // mGraphicBuffer is the Gralloc buffer store in the slot or NULL if
+        // no Gralloc buffer is in the slot.
+        sp<GraphicBuffer> mGraphicBuffer;
+
+        // mFence is a fence which will signal when the buffer associated with
+        // this buffer slot is no longer being used by the consumer and can be
+        // overwritten. The buffer can be dequeued before the fence signals;
+        // the producer is responsible for delaying writes until it signals.
+        sp<Fence> mFence;
+
+        // the frame number of the last acquired frame for this slot
+        uint64_t mFrameNumber;
+    };
+
+    // mSlots stores the buffers that have been allocated by the GonkBufferQueue
+    // for each buffer slot.  It is initialized to null pointers, and gets
+    // filled in with the result of GonkBufferQueue::acquire when the
+    // client dequeues a buffer from a
+    // slot that has not yet been used. The buffer allocated to a slot will also
+    // be replaced if the requested buffer usage or geometry differs from that
+    // of the buffer allocated to a slot.
+    Slot mSlots[GonkBufferQueue::NUM_BUFFER_SLOTS];
+
+    // mAbandoned indicates that the GonkBufferQueue will no longer be used to
+    // consume images buffers pushed to it using the IGraphicBufferProducer
+    // interface. It is initialized to false, and set to true in the abandon
+    // method.  A GonkBufferQueue that has been abandoned will return the NO_INIT
+    // error from all IGonkConsumerBase methods capable of returning an error.
+    bool mAbandoned;
+
+    // mName is a string used to identify the GonkConsumerBase in log messages.
+    // It can be set by the setName method.
+    String8 mName;
+
+    // mFrameAvailableListener is the listener object that will be called when a
+    // new frame becomes available. If it is not NULL it will be called from
+    // queueBuffer.
+    wp<FrameAvailableListener> mFrameAvailableListener;
+
+    // The GonkConsumerBase has-a GonkBufferQueue and is responsible for creating this object
+    // if none is supplied
+    sp<GonkBufferQueue> mConsumer;
+
+    // mMutex is the mutex used to prevent concurrent access to the member
+    // variables of GonkConsumerBase objects. It must be locked whenever the
+    // member variables are accessed or when any of the *Locked methods are
+    // called.
+    //
+    // This mutex is intended to be locked by derived classes.
+    mutable Mutex mMutex;
+};
+
+// ----------------------------------------------------------------------------
+}; // namespace android
+
+#endif // NATIVEWINDOW_GONKCONSUMERBASE_H
--- a/widget/gonk/nativewindow/GonkNativeWindow.h
+++ b/widget/gonk/nativewindow/GonkNativeWindow.h
@@ -8,13 +8,15 @@
  *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
 
-#if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 17
+#if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 19
+# include "GonkNativeWindowKK.h"
+#elif defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 17
 # include "GonkNativeWindowJB.h"
 #elif defined(MOZ_WIDGET_GONK) && ANDROID_VERSION == 15
 # include "GonkNativeWindowICS.h"
 #endif
--- a/widget/gonk/nativewindow/GonkNativeWindowClient.h
+++ b/widget/gonk/nativewindow/GonkNativeWindowClient.h
@@ -8,13 +8,15 @@
  *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
 
-#if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >=  17
+#if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >=  19
+# include "GonkNativeWindowClientKK.h"
+#elif defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >=  17
 # include "GonkNativeWindowClientJB.h"
 #elif defined(MOZ_WIDGET_GONK) && ANDROID_VERSION == 15
 # include "GonkNativeWindowClientICS.h"
 #endif
--- a/widget/gonk/nativewindow/GonkNativeWindowClientJB.cpp
+++ b/widget/gonk/nativewindow/GonkNativeWindowClientJB.cpp
@@ -281,16 +281,17 @@ int GonkNativeWindowClient::queueBuffer(
 
 
     // Make sure the crop rectangle is entirely inside the buffer.
     Rect crop;
     mCrop.intersect(Rect(buffer->width, buffer->height), &crop);
 
     sp<Fence> fence(fenceFd >= 0 ? new Fence(fenceFd) : Fence::NO_FENCE);
     IGraphicBufferProducer::QueueBufferOutput output;
+
     IGraphicBufferProducer::QueueBufferInput input(timestamp, crop, mScalingMode,
             mTransform, fence);
     status_t err = mBufferProducer->queueBuffer(i, input, &output);
     if (err != OK)  {
         ALOGE("queueBuffer: error queuing buffer to SurfaceTexture, %d", err);
     }
     uint32_t numPendingBuffers = 0;
     output.deflate(&mDefaultWidth, &mDefaultHeight, &mTransformHint,
@@ -491,18 +492,20 @@ int GonkNativeWindowClient::dispatchLock
 
 int GonkNativeWindowClient::dispatchUnlockAndPost(va_list args) {
     return unlockAndPost();
 }
 
 
 int GonkNativeWindowClient::connect(int api) {
     ALOGV("GonkNativeWindowClient::connect");
+
     Mutex::Autolock lock(mMutex);
     IGraphicBufferProducer::QueueBufferOutput output;
+
     int err = mBufferProducer->connect(api, &output);
     if (err == NO_ERROR) {
         uint32_t numPendingBuffers = 0;
         output.deflate(&mDefaultWidth, &mDefaultHeight, &mTransformHint,
                 &numPendingBuffers);
         mConsumerRunningBehind = (numPendingBuffers >= 2);
     }
     if (!err && api == NATIVE_WINDOW_API_CPU) {
new file mode 100644
--- /dev/null
+++ b/widget/gonk/nativewindow/GonkNativeWindowClientKK.cpp
@@ -0,0 +1,674 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ * Copyright (C) 2013 Mozilla Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "GonkNativeWindowClient"
+#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+//#define LOG_NDEBUG 0
+
+#include <android/native_window.h>
+
+#include <binder/Parcel.h>
+
+#include <utils/Log.h>
+#include <utils/Trace.h>
+
+#include <ui/Fence.h>
+
+#include "GonkNativeWindowClientKK.h"
+
+namespace android {
+
+GonkNativeWindowClient::GonkNativeWindowClient(
+        const sp<IGraphicBufferProducer>& bufferProducer,
+        bool controlledByApp)
+    : mGraphicBufferProducer(bufferProducer)
+{
+    // Initialize the ANativeWindow function pointers.
+    ANativeWindow::setSwapInterval  = hook_setSwapInterval;
+    ANativeWindow::dequeueBuffer    = hook_dequeueBuffer;
+    ANativeWindow::cancelBuffer     = hook_cancelBuffer;
+    ANativeWindow::queueBuffer      = hook_queueBuffer;
+    ANativeWindow::query            = hook_query;
+    ANativeWindow::perform          = hook_perform;
+
+    ANativeWindow::dequeueBuffer_DEPRECATED = hook_dequeueBuffer_DEPRECATED;
+    ANativeWindow::cancelBuffer_DEPRECATED  = hook_cancelBuffer_DEPRECATED;
+    ANativeWindow::lockBuffer_DEPRECATED    = hook_lockBuffer_DEPRECATED;
+    ANativeWindow::queueBuffer_DEPRECATED   = hook_queueBuffer_DEPRECATED;
+
+    const_cast<int&>(ANativeWindow::minSwapInterval) = 0;
+    const_cast<int&>(ANativeWindow::maxSwapInterval) = 1;
+
+    mReqWidth = 0;
+    mReqHeight = 0;
+    mReqFormat = 0;
+    mReqUsage = 0;
+    mTimestamp = NATIVE_WINDOW_TIMESTAMP_AUTO;
+    mCrop.clear();
+    mScalingMode = NATIVE_WINDOW_SCALING_MODE_FREEZE;
+    mTransform = 0;
+    mDefaultWidth = 0;
+    mDefaultHeight = 0;
+    mUserWidth = 0;
+    mUserHeight = 0;
+    mTransformHint = 0;
+    mConsumerRunningBehind = false;
+    mConnectedToCpu = false;
+    mProducerControlledByApp = controlledByApp;
+    mSwapIntervalZero = false;
+}
+
+GonkNativeWindowClient::~GonkNativeWindowClient() {
+    if (mConnectedToCpu) {
+        GonkNativeWindowClient::disconnect(NATIVE_WINDOW_API_CPU);
+    }
+}
+
+sp<IGraphicBufferProducer> GonkNativeWindowClient::getIGraphicBufferProducer() const {
+    return mGraphicBufferProducer;
+}
+
+int GonkNativeWindowClient::hook_setSwapInterval(ANativeWindow* window, int interval) {
+    GonkNativeWindowClient* c = getSelf(window);
+    return c->setSwapInterval(interval);
+}
+
+int GonkNativeWindowClient::hook_dequeueBuffer(ANativeWindow* window,
+        ANativeWindowBuffer** buffer, int* fenceFd) {
+    GonkNativeWindowClient* c = getSelf(window);
+    return c->dequeueBuffer(buffer, fenceFd);
+}
+
+int GonkNativeWindowClient::hook_cancelBuffer(ANativeWindow* window,
+        ANativeWindowBuffer* buffer, int fenceFd) {
+    GonkNativeWindowClient* c = getSelf(window);
+    return c->cancelBuffer(buffer, fenceFd);
+}
+
+int GonkNativeWindowClient::hook_queueBuffer(ANativeWindow* window,
+        ANativeWindowBuffer* buffer, int fenceFd) {
+    GonkNativeWindowClient* c = getSelf(window);
+    return c->queueBuffer(buffer, fenceFd);
+}
+
+int GonkNativeWindowClient::hook_dequeueBuffer_DEPRECATED(ANativeWindow* window,
+        ANativeWindowBuffer** buffer) {
+    GonkNativeWindowClient* c = getSelf(window);
+    ANativeWindowBuffer* buf;
+    int fenceFd = -1;
+    int result = c->dequeueBuffer(&buf, &fenceFd);
+    sp<Fence> fence(new Fence(fenceFd));
+    int waitResult = fence->waitForever("dequeueBuffer_DEPRECATED");
+    if (waitResult != OK) {
+        ALOGE("dequeueBuffer_DEPRECATED: Fence::wait returned an error: %d",
+                waitResult);
+        c->cancelBuffer(buf, -1);
+        return waitResult;
+    }
+    *buffer = buf;
+    return result;
+}
+
+int GonkNativeWindowClient::hook_cancelBuffer_DEPRECATED(ANativeWindow* window,
+        ANativeWindowBuffer* buffer) {
+    GonkNativeWindowClient* c = getSelf(window);
+    return c->cancelBuffer(buffer, -1);
+}
+
+int GonkNativeWindowClient::hook_lockBuffer_DEPRECATED(ANativeWindow* window,
+        ANativeWindowBuffer* buffer) {
+    GonkNativeWindowClient* c = getSelf(window);
+    return c->lockBuffer_DEPRECATED(buffer);
+}
+
+int GonkNativeWindowClient::hook_queueBuffer_DEPRECATED(ANativeWindow* window,
+        ANativeWindowBuffer* buffer) {
+    GonkNativeWindowClient* c = getSelf(window);
+    return c->queueBuffer(buffer, -1);
+}
+
+int GonkNativeWindowClient::hook_query(const ANativeWindow* window,
+                                int what, int* value) {
+    const GonkNativeWindowClient* c = getSelf(window);
+    return c->query(what, value);
+}
+
+int GonkNativeWindowClient::hook_perform(ANativeWindow* window, int operation, ...) {
+    va_list args;
+    va_start(args, operation);
+    GonkNativeWindowClient* c = getSelf(window);
+    return c->perform(operation, args);
+}
+
+int GonkNativeWindowClient::setSwapInterval(int interval) {
+    ATRACE_CALL();
+    // EGL specification states:
+    //  interval is silently clamped to minimum and maximum implementation
+    //  dependent values before being stored.
+
+    if (interval < minSwapInterval)
+        interval = minSwapInterval;
+
+    if (interval > maxSwapInterval)
+        interval = maxSwapInterval;
+
+    return NO_ERROR;
+}
+
+int GonkNativeWindowClient::dequeueBuffer(android_native_buffer_t** buffer, int* fenceFd) {
+    ATRACE_CALL();
+    ALOGV("GonkNativeWindowClient::dequeueBuffer");
+    Mutex::Autolock lock(mMutex);
+    int buf = -1;
+    int reqW = mReqWidth ? mReqWidth : mUserWidth;
+    int reqH = mReqHeight ? mReqHeight : mUserHeight;
+    sp<Fence> fence;
+    status_t result = mGraphicBufferProducer->dequeueBuffer(&buf, &fence, mSwapIntervalZero,
+            reqW, reqH, mReqFormat, mReqUsage);
+    if (result < 0) {
+        ALOGV("dequeueBuffer: IGraphicBufferProducer::dequeueBuffer(%d, %d, %d, %d)"
+             "failed: %d", mReqWidth, mReqHeight, mReqFormat, mReqUsage,
+             result);
+        return result;
+    }
+    sp<GraphicBuffer>& gbuf(mSlots[buf].buffer);
+
+    // this should never happen
+    ALOGE_IF(fence == NULL, "Surface::dequeueBuffer: received null Fence! buf=%d", buf);
+
+    if (result & IGraphicBufferProducer::RELEASE_ALL_BUFFERS) {
+        freeAllBuffers();
+    }
+
+    if ((result & IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION) || gbuf == 0) {
+        result = mGraphicBufferProducer->requestBuffer(buf, &gbuf);
+        if (result != NO_ERROR) {
+            ALOGE("dequeueBuffer: IGraphicBufferProducer::requestBuffer failed: %d", result);
+            return result;
+        }
+    }
+
+    if (fence->isValid()) {
+        *fenceFd = fence->dup();
+        if (*fenceFd == -1) {
+            ALOGE("dequeueBuffer: error duping fence: %d", errno);
+            // dup() should never fail; something is badly wrong. Soldier on
+            // and hope for the best; the worst that should happen is some
+            // visible corruption that lasts until the next frame.
+        }
+    } else {
+        *fenceFd = -1;
+    }
+
+    *buffer = gbuf.get();
+    return OK;
+}
+
+int GonkNativeWindowClient::cancelBuffer(android_native_buffer_t* buffer,
+        int fenceFd) {
+    ATRACE_CALL();
+    ALOGV("GonkNativeWindowClient::cancelBuffer");
+    Mutex::Autolock lock(mMutex);
+    int i = getSlotFromBufferLocked(buffer);
+    if (i < 0) {
+        return i;
+    }
+    sp<Fence> fence(fenceFd >= 0 ? new Fence(fenceFd) : Fence::NO_FENCE);
+    mGraphicBufferProducer->cancelBuffer(i, fence);
+    return OK;
+}
+
+int GonkNativeWindowClient::getSlotFromBufferLocked(
+        android_native_buffer_t* buffer) const {
+    bool dumpedState = false;
+    for (int i = 0; i < NUM_BUFFER_SLOTS; i++) {
+        if (mSlots[i].buffer != NULL &&
+                mSlots[i].buffer->handle == buffer->handle) {
+            return i;
+        }
+    }
+    ALOGE("getSlotFromBufferLocked: unknown buffer: %p", buffer->handle);
+    return BAD_VALUE;
+}
+
+int GonkNativeWindowClient::lockBuffer_DEPRECATED(android_native_buffer_t* buffer) {
+    ALOGV("GonkNativeWindowClient::lockBuffer");
+    Mutex::Autolock lock(mMutex);
+    return OK;
+}
+
+int GonkNativeWindowClient::queueBuffer(android_native_buffer_t* buffer, int fenceFd) {
+    ATRACE_CALL();
+    ALOGV("GonkNativeWindowClient::queueBuffer");
+    Mutex::Autolock lock(mMutex);
+    int64_t timestamp;
+    bool isAutoTimestamp = false;
+    if (mTimestamp == NATIVE_WINDOW_TIMESTAMP_AUTO) {
+        timestamp = systemTime(SYSTEM_TIME_MONOTONIC);
+        isAutoTimestamp = true;
+        ALOGV("GonkNativeWindowClient::queueBuffer making up timestamp: %.2f ms",
+             timestamp / 1000000.f);
+    } else {
+        timestamp = mTimestamp;
+    }
+    int i = getSlotFromBufferLocked(buffer);
+    if (i < 0) {
+        return i;
+    }
+
+
+    // Make sure the crop rectangle is entirely inside the buffer.
+    Rect crop;
+    mCrop.intersect(Rect(buffer->width, buffer->height), &crop);
+
+    sp<Fence> fence(fenceFd >= 0 ? new Fence(fenceFd) : Fence::NO_FENCE);
+    IGraphicBufferProducer::QueueBufferOutput output;
+    IGraphicBufferProducer::QueueBufferInput input(timestamp, isAutoTimestamp,
+            crop, mScalingMode, mTransform, mSwapIntervalZero, fence);
+    status_t err = mGraphicBufferProducer->queueBuffer(i, input, &output);
+    if (err != OK)  {
+        ALOGE("queueBuffer: error queuing buffer to SurfaceTexture, %d", err);
+    }
+    uint32_t numPendingBuffers = 0;
+    output.deflate(&mDefaultWidth, &mDefaultHeight, &mTransformHint,
+            &numPendingBuffers);
+
+    mConsumerRunningBehind = (numPendingBuffers >= 2);
+
+    return err;
+}
+
+int GonkNativeWindowClient::query(int what, int* value) const {
+    ATRACE_CALL();
+    ALOGV("GonkNativeWindowClient::query");
+    { // scope for the lock
+        Mutex::Autolock lock(mMutex);
+        switch (what) {
+            case NATIVE_WINDOW_FORMAT:
+                if (mReqFormat) {
+                    *value = mReqFormat;
+                    return NO_ERROR;
+                }
+                break;
+            case NATIVE_WINDOW_QUEUES_TO_WINDOW_COMPOSER: {
+                //sp<ISurfaceComposer> composer(
+                //        ComposerService::getComposerService());
+                //if (composer->authenticateSurfaceTexture(mGraphicBufferProducer)) {
+                //    *value = 1;
+                //} else {
+                    *value = 0;
+                //}
+                return NO_ERROR;
+            }
+            case NATIVE_WINDOW_CONCRETE_TYPE:
+                *value = NATIVE_WINDOW_SURFACE;
+                return NO_ERROR;
+            case NATIVE_WINDOW_DEFAULT_WIDTH:
+                *value = mUserWidth ? mUserWidth : mDefaultWidth;
+                return NO_ERROR;
+            case NATIVE_WINDOW_DEFAULT_HEIGHT:
+                *value = mUserHeight ? mUserHeight : mDefaultHeight;
+                return NO_ERROR;
+            case NATIVE_WINDOW_TRANSFORM_HINT:
+                *value = mTransformHint;
+                return NO_ERROR;
+            case NATIVE_WINDOW_CONSUMER_RUNNING_BEHIND: {
+                status_t err = NO_ERROR;
+                if (!mConsumerRunningBehind) {
+                    *value = 0;
+                } else {
+                    err = mGraphicBufferProducer->query(what, value);
+                    if (err == NO_ERROR) {
+                        mConsumerRunningBehind = *value;
+                    }
+                }
+                return err;
+            }
+        }
+    }
+    return mGraphicBufferProducer->query(what, value);
+}
+
+int GonkNativeWindowClient::perform(int operation, va_list args)
+{
+    int res = NO_ERROR;
+    switch (operation) {
+    case NATIVE_WINDOW_CONNECT:
+        // deprecated. must return NO_ERROR.
+        break;
+    case NATIVE_WINDOW_DISCONNECT:
+        // deprecated. must return NO_ERROR.
+        break;
+    case NATIVE_WINDOW_SET_USAGE:
+        res = dispatchSetUsage(args);
+        break;
+    case NATIVE_WINDOW_SET_CROP:
+        res = dispatchSetCrop(args);
+        break;
+    case NATIVE_WINDOW_SET_BUFFER_COUNT:
+        res = dispatchSetBufferCount(args);
+        break;
+    case NATIVE_WINDOW_SET_BUFFERS_GEOMETRY:
+        res = dispatchSetBuffersGeometry(args);
+        break;
+    case NATIVE_WINDOW_SET_BUFFERS_TRANSFORM:
+        res = dispatchSetBuffersTransform(args);
+        break;
+    case NATIVE_WINDOW_SET_BUFFERS_TIMESTAMP:
+        res = dispatchSetBuffersTimestamp(args);
+        break;
+    case NATIVE_WINDOW_SET_BUFFERS_DIMENSIONS:
+        res = dispatchSetBuffersDimensions(args);
+        break;
+    case NATIVE_WINDOW_SET_BUFFERS_USER_DIMENSIONS:
+        res = dispatchSetBuffersUserDimensions(args);
+        break;
+    case NATIVE_WINDOW_SET_BUFFERS_FORMAT:
+        res = dispatchSetBuffersFormat(args);
+        break;
+    case NATIVE_WINDOW_LOCK:
+        res = dispatchLock(args);
+        break;
+    case NATIVE_WINDOW_UNLOCK_AND_POST:
+        res = dispatchUnlockAndPost(args);
+        break;
+    case NATIVE_WINDOW_SET_SCALING_MODE:
+        res = dispatchSetScalingMode(args);
+        break;
+    case NATIVE_WINDOW_API_CONNECT:
+        res = dispatchConnect(args);
+        break;
+    case NATIVE_WINDOW_API_DISCONNECT:
+        res = dispatchDisconnect(args);
+        break;
+    default:
+        res = NAME_NOT_FOUND;
+        break;
+    }
+    return res;
+}
+
+int GonkNativeWindowClient::dispatchConnect(va_list args) {
+    int api = va_arg(args, int);
+    return connect(api);
+}
+
+int GonkNativeWindowClient::dispatchDisconnect(va_list args) {
+    int api = va_arg(args, int);
+    return disconnect(api);
+}
+
+int GonkNativeWindowClient::dispatchSetUsage(va_list args) {
+    int usage = va_arg(args, int);
+    return setUsage(usage);
+}
+
+int GonkNativeWindowClient::dispatchSetCrop(va_list args) {
+    android_native_rect_t const* rect = va_arg(args, android_native_rect_t*);
+    return setCrop(reinterpret_cast<Rect const*>(rect));
+}
+
+int GonkNativeWindowClient::dispatchSetBufferCount(va_list args) {
+    size_t bufferCount = va_arg(args, size_t);
+    return setBufferCount(bufferCount);
+}
+
+int GonkNativeWindowClient::dispatchSetBuffersGeometry(va_list args) {
+    int w = va_arg(args, int);
+    int h = va_arg(args, int);
+    int f = va_arg(args, int);
+    int err = setBuffersDimensions(w, h);
+    if (err != 0) {
+        return err;
+    }
+    return setBuffersFormat(f);
+}
+
+int GonkNativeWindowClient::dispatchSetBuffersDimensions(va_list args) {
+    int w = va_arg(args, int);
+    int h = va_arg(args, int);
+    return setBuffersDimensions(w, h);
+}
+
+int GonkNativeWindowClient::dispatchSetBuffersUserDimensions(va_list args) {
+    int w = va_arg(args, int);
+    int h = va_arg(args, int);
+    return setBuffersUserDimensions(w, h);
+}
+
+int GonkNativeWindowClient::dispatchSetBuffersFormat(va_list args) {
+    int f = va_arg(args, int);
+    return setBuffersFormat(f);
+}
+
+int GonkNativeWindowClient::dispatchSetScalingMode(va_list args) {
+    int m = va_arg(args, int);
+    return setScalingMode(m);
+}
+
+int GonkNativeWindowClient::dispatchSetBuffersTransform(va_list args) {
+    int transform = va_arg(args, int);
+    return setBuffersTransform(transform);
+}
+
+int GonkNativeWindowClient::dispatchSetBuffersTimestamp(va_list args) {
+    int64_t timestamp = va_arg(args, int64_t);
+    return setBuffersTimestamp(timestamp);
+}
+
+int GonkNativeWindowClient::dispatchLock(va_list args) {
+    ANativeWindow_Buffer* outBuffer = va_arg(args, ANativeWindow_Buffer*);
+    ARect* inOutDirtyBounds = va_arg(args, ARect*);
+    return lock(outBuffer, inOutDirtyBounds);
+}
+
+int GonkNativeWindowClient::dispatchUnlockAndPost(va_list args) {
+    return unlockAndPost();
+}
+
+
+int GonkNativeWindowClient::connect(int api) {
+    ATRACE_CALL();
+    ALOGV("GonkNativeWindowClient::connect");
+    static sp<BBinder> sLife = new BBinder();
+    Mutex::Autolock lock(mMutex);
+    IGraphicBufferProducer::QueueBufferOutput output;
+    int err = mGraphicBufferProducer->connect(sLife, api, true, &output);
+    if (err == NO_ERROR) {
+        uint32_t numPendingBuffers = 0;
+        output.deflate(&mDefaultWidth, &mDefaultHeight, &mTransformHint,
+                &numPendingBuffers);
+        mConsumerRunningBehind = (numPendingBuffers >= 2);
+    }
+    if (!err && api == NATIVE_WINDOW_API_CPU) {
+        mConnectedToCpu = true;
+    }
+    return err;
+}
+
+
+int GonkNativeWindowClient::disconnect(int api) {
+    ATRACE_CALL();
+    ALOGV("GonkNativeWindowClient::disconnect");
+    Mutex::Autolock lock(mMutex);
+    freeAllBuffers();
+    int err = mGraphicBufferProducer->disconnect(api);
+    if (!err) {
+        mReqFormat = 0;
+        mReqWidth = 0;
+        mReqHeight = 0;
+        mReqUsage = 0;
+        mCrop.clear();
+        mScalingMode = NATIVE_WINDOW_SCALING_MODE_FREEZE;
+        mTransform = 0;
+        if (api == NATIVE_WINDOW_API_CPU) {
+            mConnectedToCpu = false;
+        }
+    }
+    return err;
+}
+
+int GonkNativeWindowClient::setUsage(uint32_t reqUsage)
+{
+    ALOGV("GonkNativeWindowClient::setUsage");
+    Mutex::Autolock lock(mMutex);
+    mReqUsage = reqUsage;
+    return OK;
+}
+
+int GonkNativeWindowClient::setCrop(Rect const* rect)
+{
+    ATRACE_CALL();
+
+    Rect realRect;
+    if (rect == NULL || rect->isEmpty()) {
+        realRect.clear();
+    } else {
+        realRect = *rect;
+    }
+
+    ALOGV("GonkNativeWindowClient::setCrop rect=[%d %d %d %d]",
+            realRect.left, realRect.top, realRect.right, realRect.bottom);
+
+    Mutex::Autolock lock(mMutex);
+    mCrop = realRect;
+    return NO_ERROR;
+}
+
+int GonkNativeWindowClient::setBufferCount(int bufferCount)
+{
+    ATRACE_CALL();
+    ALOGV("GonkNativeWindowClient::setBufferCount");
+    Mutex::Autolock lock(mMutex);
+
+    status_t err = mGraphicBufferProducer->setBufferCount(bufferCount);
+    ALOGE_IF(err, "IGraphicBufferProducer::setBufferCount(%d) returned %s",
+            bufferCount, strerror(-err));
+
+    if (err == NO_ERROR) {
+        freeAllBuffers();
+    }
+
+    return err;
+}
+
+int GonkNativeWindowClient::setBuffersDimensions(int w, int h)
+{
+    ATRACE_CALL();
+    ALOGV("GonkNativeWindowClient::setBuffersDimensions");
+
+    if (w<0 || h<0)
+        return BAD_VALUE;
+
+    if ((w && !h) || (!w && h))
+        return BAD_VALUE;
+
+    Mutex::Autolock lock(mMutex);
+    mReqWidth = w;
+    mReqHeight = h;
+    return NO_ERROR;
+}
+
+int GonkNativeWindowClient::setBuffersUserDimensions(int w, int h)
+{
+    ATRACE_CALL();
+    ALOGV("GonkNativeWindowClient::setBuffersUserDimensions");
+
+    if (w<0 || h<0)
+        return BAD_VALUE;
+
+    if ((w && !h) || (!w && h))
+        return BAD_VALUE;
+
+    Mutex::Autolock lock(mMutex);
+    mUserWidth = w;
+    mUserHeight = h;
+    return NO_ERROR;
+}
+
+int GonkNativeWindowClient::setBuffersFormat(int format)
+{
+    ALOGV("GonkNativeWindowClient::setBuffersFormat");
+
+    if (format<0)
+        return BAD_VALUE;
+
+    Mutex::Autolock lock(mMutex);
+    mReqFormat = format;
+    return NO_ERROR;
+}
+
+int GonkNativeWindowClient::setScalingMode(int mode)
+{
+    ATRACE_CALL();
+    ALOGV("GonkNativeWindowClient::setScalingMode(%d)", mode);
+
+    switch (mode) {
+        case NATIVE_WINDOW_SCALING_MODE_FREEZE:
+        case NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW:
+        case NATIVE_WINDOW_SCALING_MODE_SCALE_CROP:
+            break;
+        default:
+            ALOGE("unknown scaling mode: %d", mode);
+            return BAD_VALUE;
+    }
+
+    Mutex::Autolock lock(mMutex);
+    mScalingMode = mode;
+    return NO_ERROR;
+}
+
+int GonkNativeWindowClient::setBuffersTransform(int transform)
+{
+    ATRACE_CALL();
+    ALOGV("GonkNativeWindowClient::setBuffersTransform");
+    Mutex::Autolock lock(mMutex);
+    mTransform = transform;
+    return NO_ERROR;
+}
+
+int GonkNativeWindowClient::setBuffersTimestamp(int64_t timestamp)
+{
+    ALOGV("GonkNativeWindowClient::setBuffersTimestamp");
+    Mutex::Autolock lock(mMutex);
+    mTimestamp = timestamp;
+    return NO_ERROR;
+}
+
+void GonkNativeWindowClient::freeAllBuffers() {
+    for (int i = 0; i < NUM_BUFFER_SLOTS; i++) {
+        mSlots[i].buffer = 0;
+    }
+}
+
+// ----------------------------------------------------------------------
+// the lock/unlock APIs must be used from the same thread
+
+// ----------------------------------------------------------------------------
+
+status_t GonkNativeWindowClient::lock(
+        ANativeWindow_Buffer* outBuffer, ARect* inOutDirtyBounds)
+{
+    return INVALID_OPERATION;
+}
+
+status_t GonkNativeWindowClient::unlockAndPost()
+{
+    return INVALID_OPERATION;
+}
+
+}; // namespace android
new file mode 100644
--- /dev/null
+++ b/widget/gonk/nativewindow/GonkNativeWindowClientKK.h
@@ -0,0 +1,263 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ * Copyright (C) 2013 Mozilla Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef NATIVEWINDOW_GONKNATIVEWINDOWCLIENT_KK_H
+#define NATIVEWINDOW_GONKNATIVEWINDOWCLIENT_KK_H
+
+#include <gui/IGraphicBufferProducer.h>
+
+#include <ui/ANativeObjectBase.h>
+#include <ui/Region.h>
+
+#include <utils/RefBase.h>
+#include <utils/threads.h>
+#include <utils/KeyedVector.h>
+
+#include "GonkBufferQueue.h"
+
+struct ANativeWindow_Buffer;
+
+namespace android {
+
+/*
+ * An implementation of ANativeWindow that feeds graphics buffers into a
+ * BufferQueue.
+ *
+ * This is typically used by programs that want to render frames through
+ * some means (maybe OpenGL, a software renderer, or a hardware decoder)
+ * and have the frames they create forwarded to SurfaceFlinger for
+ * compositing.  For example, a video decoder could render a frame and call
+ * eglSwapBuffers(), which invokes ANativeWindow callbacks defined by
+ * GonkNativeWindowClient.  GonkNativeWindowClient then forwards the buffers through Binder IPC
+ * to the BufferQueue's producer interface, providing the new frame to a
+ * consumer such as GLConsumer.
+ */
+class GonkNativeWindowClient
+    : public ANativeObjectBase<ANativeWindow, GonkNativeWindowClient, RefBase>
+{
+public:
+
+    /*
+     * creates a GonkNativeWindowClient from the given IGraphicBufferProducer (which concrete
+     * implementation is a BufferQueue).
+     *
+     * GonkNativeWindowClient is mainly state-less while it's disconnected, it can be
+     * viewed as a glorified IGraphicBufferProducer holder. It's therefore
+     * safe to create other GonkNativeWindowClients from the same IGraphicBufferProducer.
+     *
+     * However, once a GonkNativeWindowClient is connected, it'll prevent other GonkNativeWindowClients
+     * referring to the same IGraphicBufferProducer to become connected and
+     * therefore prevent them to be used as actual producers of buffers.
+     *
+     * the controlledByApp flag indicates that this Surface (producer) is
+     * controlled by the application. This flag is used at connect time.
+     */
+    GonkNativeWindowClient(const sp<IGraphicBufferProducer>& bufferProducer, bool controlledByApp = false);
+
+    /* getIGraphicBufferProducer() returns the IGraphicBufferProducer this
+     * GonkNativeWindowClient was created with. Usually it's an error to use the
+     * IGraphicBufferProducer while the GonkNativeWindowClient is connected.
+     */
+    sp<IGraphicBufferProducer> getIGraphicBufferProducer() const;
+
+    /* convenience function to check that the given surface is non NULL as
+     * well as its IGraphicBufferProducer */
+    static bool isValid(const sp<GonkNativeWindowClient>& surface) {
+        return surface != NULL && surface->getIGraphicBufferProducer() != NULL;
+    }
+
+protected:
+    virtual ~GonkNativeWindowClient();
+
+private:
+    // can't be copied
+    GonkNativeWindowClient& operator = (const GonkNativeWindowClient& rhs);
+    GonkNativeWindowClient(const GonkNativeWindowClient& rhs);
+
+    // ANativeWindow hooks
+    static int hook_cancelBuffer(ANativeWindow* window,
+            ANativeWindowBuffer* buffer, int fenceFd);
+    static int hook_dequeueBuffer(ANativeWindow* window,
+            ANativeWindowBuffer** buffer, int* fenceFd);
+    static int hook_perform(ANativeWindow* window, int operation, ...);
+    static int hook_query(const ANativeWindow* window, int what, int* value);
+    static int hook_queueBuffer(ANativeWindow* window,
+            ANativeWindowBuffer* buffer, int fenceFd);
+    static int hook_setSwapInterval(ANativeWindow* window, int interval);
+
+    static int hook_cancelBuffer_DEPRECATED(ANativeWindow* window,
+            ANativeWindowBuffer* buffer);
+    static int hook_dequeueBuffer_DEPRECATED(ANativeWindow* window,
+            ANativeWindowBuffer** buffer);
+    static int hook_lockBuffer_DEPRECATED(ANativeWindow* window,
+            ANativeWindowBuffer* buffer);
+    static int hook_queueBuffer_DEPRECATED(ANativeWindow* window,
+            ANativeWindowBuffer* buffer);
+
+    int dispatchConnect(va_list args);
+    int dispatchDisconnect(va_list args);
+    int dispatchSetBufferCount(va_list args);
+    int dispatchSetBuffersGeometry(va_list args);
+    int dispatchSetBuffersDimensions(va_list args);
+    int dispatchSetBuffersUserDimensions(va_list args);
+    int dispatchSetBuffersFormat(va_list args);
+    int dispatchSetScalingMode(va_list args);
+    int dispatchSetBuffersTransform(va_list args);
+    int dispatchSetBuffersTimestamp(va_list args);
+    int dispatchSetCrop(va_list args);
+    int dispatchSetPostTransformCrop(va_list args);
+    int dispatchSetUsage(va_list args);
+    int dispatchLock(va_list args);
+    int dispatchUnlockAndPost(va_list args);
+
+protected:
+    virtual int dequeueBuffer(ANativeWindowBuffer** buffer, int* fenceFd);
+    virtual int cancelBuffer(ANativeWindowBuffer* buffer, int fenceFd);
+    virtual int queueBuffer(ANativeWindowBuffer* buffer, int fenceFd);
+    virtual int perform(int operation, va_list args);
+    virtual int query(int what, int* value) const;
+    virtual int setSwapInterval(int interval);
+
+    virtual int lockBuffer_DEPRECATED(ANativeWindowBuffer* buffer);
+
+    virtual int connect(int api);
+    virtual int disconnect(int api);
+    virtual int setBufferCount(int bufferCount);
+    virtual int setBuffersDimensions(int w, int h);
+    virtual int setBuffersUserDimensions(int w, int h);
+    virtual int setBuffersFormat(int format);
+    virtual int setScalingMode(int mode);
+    virtual int setBuffersTransform(int transform);
+    virtual int setBuffersTimestamp(int64_t timestamp);
+    virtual int setCrop(Rect const* rect);
+    virtual int setUsage(uint32_t reqUsage);
+
+public:
+    virtual int lock(ANativeWindow_Buffer* outBuffer, ARect* inOutDirtyBounds);
+    virtual int unlockAndPost();
+
+protected:
+    enum { NUM_BUFFER_SLOTS = GonkBufferQueue::NUM_BUFFER_SLOTS };
+    enum { DEFAULT_FORMAT = PIXEL_FORMAT_RGBA_8888 };
+
+private:
+    void freeAllBuffers();
+    int getSlotFromBufferLocked(android_native_buffer_t* buffer) const;
+
+    struct BufferSlot {
+        sp<GraphicBuffer> buffer;
+        Region dirtyRegion;
+    };
+
+    // mSurfaceTexture is the interface to the surface texture server. All
+    // operations on the surface texture client ultimately translate into
+    // interactions with the server using this interface.
+    // TODO: rename to mBufferProducer
+    sp<IGraphicBufferProducer> mGraphicBufferProducer;
+
+    // mSlots stores the buffers that have been allocated for each buffer slot.
+    // It is initialized to null pointers, and gets filled in with the result of
+    // IGraphicBufferProducer::requestBuffer when the client dequeues a buffer from a
+    // slot that has not yet been used. The buffer allocated to a slot will also
+    // be replaced if the requested buffer usage or geometry differs from that
+    // of the buffer allocated to a slot.
+    BufferSlot mSlots[NUM_BUFFER_SLOTS];
+
+    // mReqWidth is the buffer width that will be requested at the next dequeue
+    // operation. It is initialized to 1.
+    uint32_t mReqWidth;
+
+    // mReqHeight is the buffer height that will be requested at the next
+    // dequeue operation. It is initialized to 1.
+    uint32_t mReqHeight;
+
+    // mReqFormat is the buffer pixel format that will be requested at the next
+    // deuque operation. It is initialized to PIXEL_FORMAT_RGBA_8888.
+    uint32_t mReqFormat;
+
+    // mReqUsage is the set of buffer usage flags that will be requested
+    // at the next deuque operation. It is initialized to 0.
+    uint32_t mReqUsage;
+
+    // mTimestamp is the timestamp that will be used for the next buffer queue
+    // operation. It defaults to NATIVE_WINDOW_TIMESTAMP_AUTO, which means that
+    // a timestamp is auto-generated when queueBuffer is called.
+    int64_t mTimestamp;
+
+    // mCrop is the crop rectangle that will be used for the next buffer
+    // that gets queued. It is set by calling setCrop.
+    Rect mCrop;
+
+    // mScalingMode is the scaling mode that will be used for the next
+    // buffers that get queued. It is set by calling setScalingMode.
+    int mScalingMode;
+
+    // mTransform is the transform identifier that will be used for the next
+    // buffer that gets queued. It is set by calling setTransform.
+    uint32_t mTransform;
+
+     // mDefaultWidth is default width of the buffers, regardless of the
+     // native_window_set_buffers_dimensions call.
+     uint32_t mDefaultWidth;
+
+     // mDefaultHeight is default height of the buffers, regardless of the
+     // native_window_set_buffers_dimensions call.
+     uint32_t mDefaultHeight;
+
+     // mUserWidth, if non-zero, is an application-specified override
+     // of mDefaultWidth.  This is lower priority than the width set by
+     // native_window_set_buffers_dimensions.
+     uint32_t mUserWidth;
+
+     // mUserHeight, if non-zero, is an application-specified override
+     // of mDefaultHeight.  This is lower priority than the height set
+     // by native_window_set_buffers_dimensions.
+     uint32_t mUserHeight;
+
+    // mTransformHint is the transform probably applied to buffers of this
+    // window. this is only a hint, actual transform may differ.
+    uint32_t mTransformHint;
+
+    // mProducerControlledByApp whether this buffer producer is controlled
+    // by the application
+    bool mProducerControlledByApp;
+
+    // mSwapIntervalZero set if we should drop buffers at queue() time to
+    // achieve an asynchronous swap interval
+    bool mSwapIntervalZero;
+
+    // mConsumerRunningBehind whether the consumer is running more than
+    // one buffer behind the producer.
+    mutable bool mConsumerRunningBehind;
+
+    // mMutex is the mutex used to prevent concurrent access to the member
+    // variables of GonkNativeWindowClient objects. It must be locked whenever the
+    // member variables are accessed.
+    mutable Mutex mMutex;
+
+    // must be used from the lock/unlock thread
+    sp<GraphicBuffer>           mLockedBuffer;
+    sp<GraphicBuffer>           mPostedBuffer;
+    bool                        mConnectedToCpu;
+
+    // must be accessed from lock/unlock thread only
+    Region mDirtyRegion;
+};
+
+}; // namespace android
+
+#endif  // NATIVEWINDOW_GONKNATIVEWINDOWCLIENT_JB_H
--- a/widget/gonk/nativewindow/GonkNativeWindowJB.h
+++ b/widget/gonk/nativewindow/GonkNativeWindowJB.h
@@ -19,17 +19,17 @@
 #define NATIVEWINDOW_GONKNATIVEWINDOW_JB_H
 
 #include <ui/GraphicBuffer.h>
 #include <utils/String8.h>
 #include <utils/Vector.h>
 #include <utils/threads.h>
 
 #include "CameraCommon.h"
-#include "GonkConsumerBase.h"
+#include "GonkConsumerBaseJB.h"
 #include "GrallocImages.h"
 #include "mozilla/layers/ImageBridgeChild.h"
 #include "mozilla/layers/LayersSurfaces.h"
 
 namespace mozilla {
 namespace layers {
     class PGrallocBufferChild;
 }
new file mode 100644
--- /dev/null
+++ b/widget/gonk/nativewindow/GonkNativeWindowKK.cpp
@@ -0,0 +1,175 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ * Copyright (C) 2013 Mozilla Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "GonkNativeWindow"
+#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+#include <utils/Log.h>
+
+#include "GonkNativeWindowKK.h"
+#include "GrallocImages.h"
+
+#define BI_LOGV(...) __android_log_print(ANDROID_LOG_VERBOSE, LOG_TAG, __VA_ARGS__)
+#define BI_LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)
+#define BI_LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)
+#define BI_LOGW(...) __android_log_print(ANDROID_LOG_WARN, LOG_TAG, __VA_ARGS__)
+#define BI_LOGE(...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)
+
+using namespace mozilla::layers;
+
+namespace android {
+
+GonkNativeWindow::GonkNativeWindow() :
+    GonkConsumerBase(new GonkBufferQueue(true), false)
+{
+    mConsumer->setMaxAcquiredBufferCount(GonkBufferQueue::MIN_UNDEQUEUED_BUFFERS);
+}
+
+GonkNativeWindow::GonkNativeWindow(const sp<GonkBufferQueue>& bq,
+        uint32_t consumerUsage, int bufferCount, bool controlledByApp) :
+    GonkConsumerBase(bq, controlledByApp)
+{
+    mConsumer->setConsumerUsageBits(consumerUsage);
+    mConsumer->setMaxAcquiredBufferCount(bufferCount);
+}
+
+GonkNativeWindow::~GonkNativeWindow() {
+}
+
+void GonkNativeWindow::setName(const String8& name) {
+    Mutex::Autolock _l(mMutex);
+    mName = name;
+    mConsumer->setConsumerName(name);
+}
+
+status_t GonkNativeWindow::acquireBuffer(BufferItem *item,
+        nsecs_t presentWhen, bool waitForFence) {
+    status_t err;
+
+    if (!item) return BAD_VALUE;
+
+    Mutex::Autolock _l(mMutex);
+
+    err = acquireBufferLocked(item, presentWhen);
+    if (err != OK) {
+        if (err != NO_BUFFER_AVAILABLE) {
+            BI_LOGE("Error acquiring buffer: %s (%d)", strerror(err), err);
+        }
+        return err;
+    }
+
+    if (waitForFence) {
+        err = item->mFence->waitForever("GonkNativeWindow::acquireBuffer");
+        if (err != OK) {
+            BI_LOGE("Failed to wait for fence of acquired buffer: %s (%d)",
+                    strerror(-err), err);
+            return err;
+        }
+    }
+
+    item->mGraphicBuffer = mSlots[item->mBuf].mGraphicBuffer;
+
+    return OK;
+}
+
+status_t GonkNativeWindow::releaseBuffer(const BufferItem &item,
+        const sp<Fence>& releaseFence) {
+    status_t err;
+
+    Mutex::Autolock _l(mMutex);
+
+    err = addReleaseFenceLocked(item.mBuf, item.mGraphicBuffer, releaseFence);
+
+    err = releaseBufferLocked(item.mBuf, item.mGraphicBuffer);
+    if (err != OK) {
+        BI_LOGE("Failed to release buffer: %s (%d)",
+                strerror(-err), err);
+    }
+    return err;
+}
+
+status_t GonkNativeWindow::setDefaultBufferSize(uint32_t w, uint32_t h) {
+    Mutex::Autolock _l(mMutex);
+    return mConsumer->setDefaultBufferSize(w, h);
+}
+
+status_t GonkNativeWindow::setDefaultBufferFormat(uint32_t defaultFormat) {
+    Mutex::Autolock _l(mMutex);
+    return mConsumer->setDefaultBufferFormat(defaultFormat);
+}
+
+already_AddRefed<GraphicBufferLocked>
+GonkNativeWindow::getCurrentBuffer()
+{
+    Mutex::Autolock _l(mMutex);
+    BufferItem item;
+
+    // In asynchronous mode the list is guaranteed to be one buffer
+    // deep, while in synchronous mode we use the oldest buffer.
+    status_t err = acquireBufferLocked(&item, 0); //???