Merge b2g-inbound to m-c.
authorRyan VanderMeulen <ryanvm@gmail.com>
Wed, 26 Feb 2014 16:35:43 -0500
changeset 181764 bb9edb4d5144d414e355b8d09a74c94ba57096bf
parent 181704 8b52fb24991d57ff8dd5205fd9334cf1e26b04d2 (current diff)
parent 181763 677c0fa83472b8adba889287fe25d72c8652e809 (diff)
child 181767 75f877dc06037c2527fac9d92fd53f9d95a27c44
child 181812 551e6c666d5256b799605461ba74168438487c14
child 181841 6b08917b4d2fef32a7de9b4110ed348375cc0a82
push id5439
push userffxbld
push dateMon, 17 Mar 2014 23:08:15 +0000
treeherdermozilla-aurora@c0befb3c8038 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone30.0a1
Merge b2g-inbound to m-c.
configure.in
widget/gonk/nativewindow/GonkBufferQueue.cpp
widget/gonk/nativewindow/GonkBufferQueue.h
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/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/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/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/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/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); //???
+
+    if (err != NO_ERROR) {
+        return NULL;
+    }
+
+  nsRefPtr<GraphicBufferLocked> ret =
+    new CameraGraphicBuffer(this, item.mBuf, mConsumer->getGeneration(), item.mSurfaceDescriptor);
+
+  return ret.forget();
+}
+
+bool
+GonkNativeWindow::returnBuffer(uint32_t aIndex, uint32_t aGeneration) {
+    BI_LOGD("GonkNativeWindow::returnBuffer: slot=%d (generation=%d)", aIndex, aGeneration);
+    Mutex::Autolock lock(mMutex);
+
+    if (aGeneration != mConsumer->getGeneration()) {
+        BI_LOGD("returnBuffer: buffer is from generation %d (current is %d)",
+          aGeneration, mConsumer->getGeneration());
+        return false;
+    }
+    status_t err = releaseBufferLocked(aIndex, mSlots[aIndex].mGraphicBuffer);
+
+    if (err != NO_ERROR) {
+        return false;
+    }
+  return true;
+}
+
+mozilla::layers::SurfaceDescriptor *
+GonkNativeWindow::getSurfaceDescriptorFromBuffer(ANativeWindowBuffer* buffer)
+{
+    Mutex::Autolock lock(mMutex);
+
+    return mConsumer->getSurfaceDescriptorFromBuffer(buffer);
+}
+void GonkNativeWindow::setNewFrameCallback(
+        GonkNativeWindowNewFrameCallback* aCallback) {
+    BI_LOGD("setNewFrameCallback");
+    Mutex::Autolock lock(mMutex);
+    mNewFrameCallback = aCallback;
+}
+
+void GonkNativeWindow::onFrameAvailable() {
+    GonkConsumerBase::onFrameAvailable();
+
+    if (mNewFrameCallback) {
+      mNewFrameCallback->OnNewFrame();
+    }
+}
+
+} // namespace android
new file mode 100644
--- /dev/null
+++ b/widget/gonk/nativewindow/GonkNativeWindowKK.h
@@ -0,0 +1,186 @@
+/*
+ * 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_GONKNATIVEWINDOW_KK_H
+#define NATIVEWINDOW_GONKNATIVEWINDOW_KK_H
+
+#include <ui/GraphicBuffer.h>
+#include <utils/String8.h>
+#include <utils/Vector.h>
+#include <utils/threads.h>
+
+#include "CameraCommon.h"
+#include "GonkConsumerBaseKK.h"
+#include "GrallocImages.h"
+#include "IGonkGraphicBufferConsumer.h"
+#include "mozilla/layers/ImageBridgeChild.h"
+#include "mozilla/layers/LayersSurfaces.h"
+
+namespace mozilla {
+namespace layers {
+    class PGrallocBufferChild;
+}
+}
+
+namespace android {
+
+// The user of GonkNativeWindow who wants to receive notification of
+// new frames should implement this interface.
+class GonkNativeWindowNewFrameCallback {
+public:
+    virtual void OnNewFrame() = 0;
+};
+
+/**
+ * GonkNativeWindow is a GonkBufferQueue consumer endpoint that allows clients
+ * access to the whole BufferItem entry from GonkBufferQueue. Multiple buffers may
+ * be acquired at once, to be used concurrently by the client. This consumer can
+ * operate either in synchronous or asynchronous mode.
+ */
+class GonkNativeWindow: public GonkConsumerBase
+{
+    typedef mozilla::layers::GraphicBufferLocked GraphicBufferLocked;
+    typedef mozilla::layers::SurfaceDescriptor SurfaceDescriptor;
+  public:
+    typedef GonkConsumerBase::FrameAvailableListener FrameAvailableListener;
+    typedef IGonkGraphicBufferConsumer::BufferItem BufferItem;
+
+    enum { INVALID_BUFFER_SLOT = GonkBufferQueue::INVALID_BUFFER_SLOT };
+    enum { NO_BUFFER_AVAILABLE = GonkBufferQueue::NO_BUFFER_AVAILABLE };
+
+    // Create a new buffer item consumer. The consumerUsage parameter determines
+    // the consumer usage flags passed to the graphics allocator. The
+    // bufferCount parameter specifies how many buffers can be locked for user
+    // access at the same time.
+    // controlledByApp tells whether this consumer is controlled by the
+    // application.
+    GonkNativeWindow();
+    GonkNativeWindow(const sp<GonkBufferQueue>& bq, uint32_t consumerUsage,
+            int bufferCount = GonkBufferQueue::MIN_UNDEQUEUED_BUFFERS,
+            bool controlledByApp = false);
+
+    virtual ~GonkNativeWindow();
+
+    // set the name of the GonkNativeWindow that will be used to identify it in
+    // log messages.
+    void setName(const String8& name);
+
+    // Gets the next graphics buffer from the producer, filling out the
+    // passed-in BufferItem structure. Returns NO_BUFFER_AVAILABLE if the queue
+    // of buffers is empty, and INVALID_OPERATION if the maximum number of
+    // buffers is already acquired.
+    //
+    // Only a fixed number of buffers can be acquired at a time, determined by
+    // the construction-time bufferCount parameter. If INVALID_OPERATION is
+    // returned by acquireBuffer, then old buffers must be returned to the
+    // queue by calling releaseBuffer before more buffers can be acquired.
+    //
+    // If waitForFence is true, and the acquired BufferItem has a valid fence object,
+    // acquireBuffer will wait on the fence with no timeout before returning.
+    status_t acquireBuffer(BufferItem *item, nsecs_t presentWhen,
+        bool waitForFence = true);
+
+    // Returns an acquired buffer to the queue, allowing it to be reused. Since
+    // only a fixed number of buffers may be acquired at a time, old buffers
+    // must be released by calling releaseBuffer to ensure new buffers can be
+    // acquired by acquireBuffer. Once a BufferItem is released, the caller must
+    // not access any members of the BufferItem, and should immediately remove
+    // all of its references to the BufferItem itself.
+    status_t releaseBuffer(const BufferItem &item,
+            const sp<Fence>& releaseFence = Fence::NO_FENCE);
+
+    // setDefaultBufferSize is used to set the size of buffers returned by
+    // requestBuffers when a with and height of zero is requested.
+    status_t setDefaultBufferSize(uint32_t w, uint32_t h);
+
+    // setDefaultBufferFormat allows the BufferQueue to create
+    // GraphicBuffers of a defaultFormat if no format is specified
+    // in dequeueBuffer
+    status_t setDefaultBufferFormat(uint32_t defaultFormat);
+
+    // Get next frame from the queue, caller owns the returned buffer.
+    already_AddRefed<GraphicBufferLocked> getCurrentBuffer();
+
+    // Return the buffer to the queue and mark it as FREE. After that
+    // the buffer is useable again for the decoder.
+    bool returnBuffer(uint32_t index, uint32_t generation);
+
+    SurfaceDescriptor* getSurfaceDescriptorFromBuffer(ANativeWindowBuffer* buffer);
+
+    void setNewFrameCallback(GonkNativeWindowNewFrameCallback* aCallback);
+
+protected:
+    virtual void onFrameAvailable();
+
+private:
+    GonkNativeWindowNewFrameCallback* mNewFrameCallback;
+};
+
+// CameraGraphicBuffer maintains the buffer returned from GonkNativeWindow
+class CameraGraphicBuffer : public mozilla::layers::GraphicBufferLocked
+{
+    typedef mozilla::layers::SurfaceDescriptor SurfaceDescriptor;
+    typedef mozilla::layers::ImageBridgeChild ImageBridgeChild;
+
+public:
+    CameraGraphicBuffer(GonkNativeWindow* aNativeWindow,
+                        uint32_t aIndex,
+                        uint32_t aGeneration,
+                        SurfaceDescriptor aBuffer)
+        : GraphicBufferLocked(aBuffer)
+        , mNativeWindow(aNativeWindow)
+        , mIndex(aIndex)
+        , mGeneration(aGeneration)
+        , mLocked(true)
+    {
+        DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this);
+    }
+
+    virtual ~CameraGraphicBuffer()
+    {
+        DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this);
+    }
+
+    // Unlock either returns the buffer to the native window or
+    // destroys the buffer if the window is already released.
+    virtual void Unlock() MOZ_OVERRIDE
+    {
+        if (mLocked) {
+            // The window might have been destroyed. The buffer is no longer
+            // valid at that point.
+            sp<GonkNativeWindow> window = mNativeWindow.promote();
+            if (window.get() && window->returnBuffer(mIndex, mGeneration)) {
+                mLocked = false;
+            } else {
+                // If the window doesn't exist any more, release the buffer
+                // directly.
+                ImageBridgeChild *ibc = ImageBridgeChild::GetSingleton();
+                ibc->DeallocSurfaceDescriptorGralloc(mSurfaceDescriptor);
+            }
+        }
+    }
+
+protected:
+    wp<GonkNativeWindow> mNativeWindow;
+    uint32_t mIndex;
+    uint32_t mGeneration;
+    bool mLocked;
+};
+
+} // namespace android
+
+#endif // NATIVEWINDOW_GONKNATIVEWINDOW_JB_H
new file mode 100644
--- /dev/null
+++ b/widget/gonk/nativewindow/IGonkGraphicBufferConsumer.cpp
@@ -0,0 +1,481 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * 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 EGL_EGLEXT_PROTOTYPES
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <utils/Errors.h>
+
+#include <binder/Parcel.h>
+#include <binder/IInterface.h>
+
+#include <gui/IConsumerListener.h>
+#include "IGonkGraphicBufferConsumer.h"
+
+#include <ui/GraphicBuffer.h>
+#include <ui/Fence.h>
+
+#include <system/window.h>
+
+namespace android {
+// ---------------------------------------------------------------------------
+
+IGonkGraphicBufferConsumer::BufferItem::BufferItem() :
+    mTransform(0),
+    mScalingMode(NATIVE_WINDOW_SCALING_MODE_FREEZE),
+    mTimestamp(0),
+    mIsAutoTimestamp(false),
+    mFrameNumber(0),
+    mBuf(INVALID_BUFFER_SLOT),
+    mIsDroppable(false),
+    mAcquireCalled(false),
+    mTransformToDisplayInverse(false),
+    mSurfaceDescriptor(SurfaceDescriptor()) {
+    mCrop.makeInvalid();
+}
+
+size_t IGonkGraphicBufferConsumer::BufferItem::getPodSize() const {
+    size_t c =  sizeof(mCrop) +
+            sizeof(mTransform) +
+            sizeof(mScalingMode) +
+            sizeof(mTimestamp) +
+            sizeof(mIsAutoTimestamp) +
+            sizeof(mFrameNumber) +
+            sizeof(mBuf) +
+            sizeof(mIsDroppable) +
+            sizeof(mAcquireCalled) +
+            sizeof(mTransformToDisplayInverse);
+    return c;
+}
+
+size_t IGonkGraphicBufferConsumer::BufferItem::getFlattenedSize() const {
+    size_t c = 0;
+    if (mGraphicBuffer != 0) {
+        c += mGraphicBuffer->getFlattenedSize();
+        FlattenableUtils::align<4>(c);
+    }
+    if (mFence != 0) {
+        c += mFence->getFlattenedSize();
+        FlattenableUtils::align<4>(c);
+    }
+    return sizeof(int32_t) + c + getPodSize();
+}
+
+size_t IGonkGraphicBufferConsumer::BufferItem::getFdCount() const {
+    size_t c = 0;
+    if (mGraphicBuffer != 0) {
+        c += mGraphicBuffer->getFdCount();
+    }
+    if (mFence != 0) {
+        c += mFence->getFdCount();
+    }
+    return c;
+}
+
+status_t IGonkGraphicBufferConsumer::BufferItem::flatten(
+        void*& buffer, size_t& size, int*& fds, size_t& count) const {
+
+    // make sure we have enough space
+    if (count < BufferItem::getFlattenedSize()) {
+        return NO_MEMORY;
+    }
+
+    // content flags are stored first
+    uint32_t& flags = *static_cast<uint32_t*>(buffer);
+
+    // advance the pointer
+    FlattenableUtils::advance(buffer, size, sizeof(uint32_t));
+
+    flags = 0;
+    if (mGraphicBuffer != 0) {
+        status_t err = mGraphicBuffer->flatten(buffer, size, fds, count);
+        if (err) return err;
+        size -= FlattenableUtils::align<4>(buffer);
+        flags |= 1;
+    }
+    if (mFence != 0) {
+        status_t err = mFence->flatten(buffer, size, fds, count);
+        if (err) return err;
+        size -= FlattenableUtils::align<4>(buffer);
+        flags |= 2;
+    }
+
+    // check we have enough space (in case flattening the fence/graphicbuffer lied to us)
+    if (size < getPodSize()) {
+        return NO_MEMORY;
+    }
+
+    FlattenableUtils::write(buffer, size, mCrop);
+    FlattenableUtils::write(buffer, size, mTransform);
+    FlattenableUtils::write(buffer, size, mScalingMode);
+    FlattenableUtils::write(buffer, size, mTimestamp);
+    FlattenableUtils::write(buffer, size, mIsAutoTimestamp);
+    FlattenableUtils::write(buffer, size, mFrameNumber);
+    FlattenableUtils::write(buffer, size, mBuf);
+    FlattenableUtils::write(buffer, size, mIsDroppable);
+    FlattenableUtils::write(buffer, size, mAcquireCalled);
+    FlattenableUtils::write(buffer, size, mTransformToDisplayInverse);
+
+    return NO_ERROR;
+}
+
+status_t IGonkGraphicBufferConsumer::BufferItem::unflatten(
+        void const*& buffer, size_t& size, int const*& fds, size_t& count) {
+
+    if (size < sizeof(uint32_t))
+        return NO_MEMORY;
+
+    uint32_t flags = 0;
+    FlattenableUtils::read(buffer, size, flags);
+
+    if (flags & 1) {
+        mGraphicBuffer = new GraphicBuffer();
+        status_t err = mGraphicBuffer->unflatten(buffer, size, fds, count);
+        if (err) return err;
+        size -= FlattenableUtils::align<4>(buffer);
+    }
+
+    if (flags & 2) {
+        mFence = new Fence();
+        status_t err = mFence->unflatten(buffer, size, fds, count);
+        if (err) return err;
+        size -= FlattenableUtils::align<4>(buffer);
+    }
+
+    // check we have enough space
+    if (size < getPodSize()) {
+        return NO_MEMORY;
+    }
+
+    FlattenableUtils::read(buffer, size, mCrop);
+    FlattenableUtils::read(buffer, size, mTransform);
+    FlattenableUtils::read(buffer, size, mScalingMode);
+    FlattenableUtils::read(buffer, size, mTimestamp);
+    FlattenableUtils::read(buffer, size, mIsAutoTimestamp);
+    FlattenableUtils::read(buffer, size, mFrameNumber);
+    FlattenableUtils::read(buffer, size, mBuf);
+    FlattenableUtils::read(buffer, size, mIsDroppable);
+    FlattenableUtils::read(buffer, size, mAcquireCalled);
+    FlattenableUtils::read(buffer, size, mTransformToDisplayInverse);
+
+    return NO_ERROR;
+}
+
+// ---------------------------------------------------------------------------
+
+enum {
+    ACQUIRE_BUFFER = IBinder::FIRST_CALL_TRANSACTION,
+    RELEASE_BUFFER,
+    CONSUMER_CONNECT,
+    CONSUMER_DISCONNECT,
+    GET_RELEASED_BUFFERS,
+    SET_DEFAULT_BUFFER_SIZE,
+    SET_DEFAULT_MAX_BUFFER_COUNT,
+    DISABLE_ASYNC_BUFFER,
+    SET_MAX_ACQUIRED_BUFFER_COUNT,
+    SET_CONSUMER_NAME,
+    SET_DEFAULT_BUFFER_FORMAT,
+    SET_CONSUMER_USAGE_BITS,
+    SET_TRANSFORM_HINT,
+    DUMP,
+};
+
+class BpGonkGraphicBufferConsumer : public BpInterface<IGonkGraphicBufferConsumer>
+{
+public:
+    BpGonkGraphicBufferConsumer(const sp<IBinder>& impl)
+        : BpInterface<IGonkGraphicBufferConsumer>(impl)
+    {
+    }
+
+    virtual status_t acquireBuffer(BufferItem *buffer, nsecs_t presentWhen) {
+        Parcel data, reply;
+        data.writeInterfaceToken(IGonkGraphicBufferConsumer::getInterfaceDescriptor());
+        data.writeInt64(presentWhen);
+        status_t result = remote()->transact(ACQUIRE_BUFFER, data, &reply);
+        if (result != NO_ERROR) {
+            return result;
+        }
+        result = reply.read(*buffer);
+        if (result != NO_ERROR) {
+            return result;
+        }
+        return reply.readInt32();
+    }
+
+    virtual status_t releaseBuffer(int buf, uint64_t frameNumber,
+            const sp<Fence>& releaseFence) {
+        Parcel data, reply;
+        data.writeInterfaceToken(IGonkGraphicBufferConsumer::getInterfaceDescriptor());
+        data.writeInt32(buf);
+        data.writeInt64(frameNumber);
+        data.write(*releaseFence);
+        status_t result = remote()->transact(RELEASE_BUFFER, data, &reply);
+        if (result != NO_ERROR) {
+            return result;
+        }
+        return reply.readInt32();
+    }
+
+    virtual status_t consumerConnect(const sp<IConsumerListener>& consumer, bool controlledByApp) {
+        Parcel data, reply;
+        data.writeInterfaceToken(IGonkGraphicBufferConsumer::getInterfaceDescriptor());
+        data.writeStrongBinder(consumer->asBinder());
+        data.writeInt32(controlledByApp);
+        status_t result = remote()->transact(CONSUMER_CONNECT, data, &reply);
+        if (result != NO_ERROR) {
+            return result;
+        }
+        return reply.readInt32();
+    }
+
+    virtual status_t consumerDisconnect() {
+        Parcel data, reply;
+        data.writeInterfaceToken(IGonkGraphicBufferConsumer::getInterfaceDescriptor());
+        status_t result = remote()->transact(CONSUMER_DISCONNECT, data, &reply);
+        if (result != NO_ERROR) {
+            return result;
+        }
+        return reply.readInt32();
+    }
+
+    virtual status_t getReleasedBuffers(uint32_t* slotMask) {
+        Parcel data, reply;
+        data.writeInterfaceToken(IGonkGraphicBufferConsumer::getInterfaceDescriptor());
+        status_t result = remote()->transact(GET_RELEASED_BUFFERS, data, &reply);
+        if (result != NO_ERROR) {
+            return result;
+        }
+        *slotMask = reply.readInt32();
+        return reply.readInt32();
+    }
+
+    virtual status_t setDefaultBufferSize(uint32_t w, uint32_t h) {
+        Parcel data, reply;
+        data.writeInterfaceToken(IGonkGraphicBufferConsumer::getInterfaceDescriptor());
+        data.writeInt32(w);
+        data.writeInt32(h);
+        status_t result = remote()->transact(SET_DEFAULT_BUFFER_SIZE, data, &reply);
+        if (result != NO_ERROR) {
+            return result;
+        }
+        return reply.readInt32();
+    }
+
+    virtual status_t setDefaultMaxBufferCount(int bufferCount) {
+        Parcel data, reply;
+        data.writeInterfaceToken(IGonkGraphicBufferConsumer::getInterfaceDescriptor());
+        data.writeInt32(bufferCount);
+        status_t result = remote()->transact(SET_DEFAULT_MAX_BUFFER_COUNT, data, &reply);
+        if (result != NO_ERROR) {
+            return result;
+        }
+        return reply.readInt32();
+    }
+
+    virtual status_t disableAsyncBuffer() {
+        Parcel data, reply;
+        data.writeInterfaceToken(IGonkGraphicBufferConsumer::getInterfaceDescriptor());
+        status_t result = remote()->transact(DISABLE_ASYNC_BUFFER, data, &reply);
+        if (result != NO_ERROR) {
+            return result;
+        }
+        return reply.readInt32();
+    }
+
+    virtual status_t setMaxAcquiredBufferCount(int maxAcquiredBuffers) {
+        Parcel data, reply;
+        data.writeInterfaceToken(IGonkGraphicBufferConsumer::getInterfaceDescriptor());
+        data.writeInt32(maxAcquiredBuffers);
+        status_t result = remote()->transact(SET_MAX_ACQUIRED_BUFFER_COUNT, data, &reply);
+        if (result != NO_ERROR) {
+            return result;
+        }
+        return reply.readInt32();
+    }
+
+    virtual void setConsumerName(const String8& name) {
+        Parcel data, reply;
+        data.writeInterfaceToken(IGonkGraphicBufferConsumer::getInterfaceDescriptor());
+        data.writeString8(name);
+        remote()->transact(SET_CONSUMER_NAME, data, &reply);
+    }
+
+    virtual status_t setDefaultBufferFormat(uint32_t defaultFormat) {
+        Parcel data, reply;
+        data.writeInterfaceToken(IGonkGraphicBufferConsumer::getInterfaceDescriptor());
+        data.writeInt32(defaultFormat);
+        status_t result = remote()->transact(SET_DEFAULT_BUFFER_FORMAT, data, &reply);
+        if (result != NO_ERROR) {
+            return result;
+        }
+        return reply.readInt32();
+    }
+
+    virtual status_t setConsumerUsageBits(uint32_t usage) {
+        Parcel data, reply;
+        data.writeInterfaceToken(IGonkGraphicBufferConsumer::getInterfaceDescriptor());
+        data.writeInt32(usage);
+        status_t result = remote()->transact(SET_CONSUMER_USAGE_BITS, data, &reply);
+        if (result != NO_ERROR) {
+            return result;
+        }
+        return reply.readInt32();
+    }
+
+    virtual status_t setTransformHint(uint32_t hint) {
+        Parcel data, reply;
+        data.writeInterfaceToken(IGonkGraphicBufferConsumer::getInterfaceDescriptor());
+        data.writeInt32(hint);
+        status_t result = remote()->transact(SET_TRANSFORM_HINT, data, &reply);
+        if (result != NO_ERROR) {
+            return result;
+        }
+        return reply.readInt32();
+    }
+
+    virtual void dump(String8& result, const char* prefix) const {
+        Parcel data, reply;
+        data.writeInterfaceToken(IGonkGraphicBufferConsumer::getInterfaceDescriptor());
+        data.writeString8(result);
+        data.writeString8(String8(prefix ? prefix : ""));
+        remote()->transact(DUMP, data, &reply);
+        reply.readString8();
+    }
+};
+
+IMPLEMENT_META_INTERFACE(GonkGraphicBufferConsumer, "android.gui.IGonkGraphicBufferConsumer");
+// ----------------------------------------------------------------------
+
+status_t BnGonkGraphicBufferConsumer::onTransact(
+        uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
+{
+    switch(code) {
+        case ACQUIRE_BUFFER: {
+            CHECK_INTERFACE(IGonkGraphicBufferConsumer, data, reply);
+            BufferItem item;
+            int64_t presentWhen = data.readInt64();
+            status_t result = acquireBuffer(&item, presentWhen);
+            status_t err = reply->write(item);
+            if (err) return err;
+            reply->writeInt32(result);
+            return NO_ERROR;
+        } break;
+        case RELEASE_BUFFER: {
+            CHECK_INTERFACE(IGonkGraphicBufferConsumer, data, reply);
+            int buf = data.readInt32();
+            uint64_t frameNumber = data.readInt64();
+            sp<Fence> releaseFence = new Fence();
+            status_t err = data.read(*releaseFence);
+            if (err) return err;
+            status_t result = releaseBuffer(buf, frameNumber, releaseFence);
+            reply->writeInt32(result);
+            return NO_ERROR;
+        } break;
+
+        case CONSUMER_CONNECT: {
+            CHECK_INTERFACE(IGonkGraphicBufferConsumer, data, reply);
+            sp<IConsumerListener> consumer = IConsumerListener::asInterface( data.readStrongBinder() );
+            bool controlledByApp = data.readInt32();
+            status_t result = consumerConnect(consumer, controlledByApp);
+            reply->writeInt32(result);
+            return NO_ERROR;
+        } break;
+
+        case CONSUMER_DISCONNECT: {
+            CHECK_INTERFACE(IGonkGraphicBufferConsumer, data, reply);
+            status_t result = consumerDisconnect();
+            reply->writeInt32(result);
+            return NO_ERROR;
+        } break;
+        case GET_RELEASED_BUFFERS: {
+            CHECK_INTERFACE(IGonkGraphicBufferConsumer, data, reply);
+            uint32_t slotMask;
+            status_t result = getReleasedBuffers(&slotMask);
+            reply->writeInt32(slotMask);
+            reply->writeInt32(result);
+            return NO_ERROR;
+        } break;
+        case SET_DEFAULT_BUFFER_SIZE: {
+            CHECK_INTERFACE(IGonkGraphicBufferConsumer, data, reply);
+            uint32_t w = data.readInt32();
+            uint32_t h = data.readInt32();
+            status_t result = setDefaultBufferSize(w, h);
+            reply->writeInt32(result);
+            return NO_ERROR;
+        } break;
+        case SET_DEFAULT_MAX_BUFFER_COUNT: {
+            CHECK_INTERFACE(IGonkGraphicBufferConsumer, data, reply);
+            uint32_t bufferCount = data.readInt32();
+            status_t result = setDefaultMaxBufferCount(bufferCount);
+            reply->writeInt32(result);
+            return NO_ERROR;
+        } break;
+        case DISABLE_ASYNC_BUFFER: {
+            CHECK_INTERFACE(IGonkGraphicBufferConsumer, data, reply);
+            status_t result = disableAsyncBuffer();
+            reply->writeInt32(result);
+            return NO_ERROR;
+        } break;
+        case SET_MAX_ACQUIRED_BUFFER_COUNT: {
+            CHECK_INTERFACE(IGonkGraphicBufferConsumer, data, reply);
+            uint32_t maxAcquiredBuffers = data.readInt32();
+            status_t result = setMaxAcquiredBufferCount(maxAcquiredBuffers);
+            reply->writeInt32(result);
+            return NO_ERROR;
+        } break;
+        case SET_CONSUMER_NAME: {
+            CHECK_INTERFACE(IGonkGraphicBufferConsumer, data, reply);
+            setConsumerName( data.readString8() );
+            return NO_ERROR;
+        } break;
+        case SET_DEFAULT_BUFFER_FORMAT: {
+            CHECK_INTERFACE(IGonkGraphicBufferConsumer, data, reply);
+            uint32_t defaultFormat = data.readInt32();
+            status_t result = setDefaultBufferFormat(defaultFormat);
+            reply->writeInt32(result);
+            return NO_ERROR;
+        } break;
+        case SET_CONSUMER_USAGE_BITS: {
+            CHECK_INTERFACE(IGonkGraphicBufferConsumer, data, reply);
+            uint32_t usage = data.readInt32();
+            status_t result = setConsumerUsageBits(usage);
+            reply->writeInt32(result);
+            return NO_ERROR;
+        } break;
+        case SET_TRANSFORM_HINT: {
+            CHECK_INTERFACE(IGonkGraphicBufferConsumer, data, reply);
+            uint32_t hint = data.readInt32();
+            status_t result = setTransformHint(hint);
+            reply->writeInt32(result);
+            return NO_ERROR;
+        } break;
+
+        case DUMP: {
+            CHECK_INTERFACE(IGonkGraphicBufferConsumer, data, reply);
+            String8 result = data.readString8();
+            String8 prefix = data.readString8();
+            static_cast<IGonkGraphicBufferConsumer*>(this)->dump(result, prefix);
+            reply->writeString8(result);
+            return NO_ERROR;
+        }
+    }
+    return BBinder::onTransact(code, data, reply, flags);
+}
+
+}; // namespace android
new file mode 100644
--- /dev/null
+++ b/widget/gonk/nativewindow/IGonkGraphicBufferConsumer.h
@@ -0,0 +1,223 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * 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 ANDROID_GUI_IGONKGRAPHICBUFFERCONSUMER_H
+#define ANDROID_GUI_IGONKGRAPHICBUFFERCONSUMER_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <utils/Errors.h>
+#include <utils/RefBase.h>
+#include <utils/Timers.h>
+
+#include <binder/IInterface.h>
+#include <ui/Rect.h>
+
+#include "mozilla/layers/LayersSurfaces.h"
+
+namespace android {
+// ----------------------------------------------------------------------------
+
+class IConsumerListener;
+class GraphicBuffer;
+class Fence;
+
+class IGonkGraphicBufferConsumer : public IInterface {
+    typedef mozilla::layers::SurfaceDescriptor SurfaceDescriptor;
+public:
+
+    // public facing structure for BufferSlot
+    class BufferItem : public Flattenable<BufferItem> {
+        friend class Flattenable<BufferItem>;
+        size_t getPodSize() const;
+        size_t getFlattenedSize() const;
+        size_t getFdCount() const;
+        status_t flatten(void*& buffer, size_t& size, int*& fds, size_t& count) const;
+        status_t unflatten(void const*& buffer, size_t& size, int const*& fds, size_t& count);
+
+    public:
+        enum { INVALID_BUFFER_SLOT = -1 };
+        BufferItem();
+
+        // 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;
+
+        // mFence is a fence that will signal when the buffer is idle.
+        sp<Fence> mFence;
+
+        // 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;
+
+        // mIsAutoTimestamp indicates whether mTimestamp was generated
+        // automatically when the buffer was queued.
+        bool mIsAutoTimestamp;
+
+        // mFrameNumber is the number of the queued frame for this slot.
+        uint64_t mFrameNumber;
+
+        // mBuf is the slot index of this buffer
+        int mBuf;
+
+        // mIsDroppable whether this buffer was queued with the
+        // property that it can be replaced by a new buffer for the purpose of
+        // making sure dequeueBuffer() won't block.
+        // i.e.: was the BufferQueue in "mDequeueBufferCannotBlock" when this buffer
+        // was queued.
+        bool mIsDroppable;
+
+        // Indicates whether this buffer has been seen by a consumer yet
+        bool mAcquireCalled;
+
+        // Indicates this buffer must be transformed by the inverse transform of the screen
+        // it is displayed onto. This is applied after mTransform.
+        bool mTransformToDisplayInverse;
+
+        // mSurfaceDescriptor is the token to remotely allocated GraphicBuffer.
+        SurfaceDescriptor mSurfaceDescriptor;
+    };
+
+
+    // acquireBuffer attempts to acquire ownership of the next pending buffer in
+    // the BufferQueue.  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) = 0;
+
+    // releaseBuffer releases a buffer slot from the consumer back to the
+    // BufferQueue.  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) = 0;
+
+    // consumerConnect connects a consumer to the BufferQueue.  Only one
+    // consumer may be connected, and when that consumer disconnects the
+    // BufferQueue is placed into the "abandoned" state, causing most
+    // interactions with the BufferQueue 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) = 0;
+
+    // consumerDisconnect disconnects a consumer from the BufferQueue. All
+    // buffers will be freed and the BufferQueue is placed in the "abandoned"
+    // state, causing most interactions with the BufferQueue by the producer to
+    // fail.
+    virtual status_t consumerDisconnect() = 0;
+
+    // getReleasedBuffers sets the value pointed to by slotMask to a bit mask
+    // indicating which buffer slots have been released by the BufferQueue
+    // but have not yet been released by the consumer.
+    //
+    // This should be called from the onBuffersReleased() callback.
+    virtual status_t getReleasedBuffers(uint32_t* slotMask) = 0;
+
+    // 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) = 0;
+
+    // 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) = 0;
+
+    // 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() = 0;
+
+    // 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 BufferQueue.
+    virtual status_t setMaxAcquiredBufferCount(int maxAcquiredBuffers) = 0;
+
+    // setConsumerName sets the name used in logging
+    virtual void setConsumerName(const String8& name) = 0;
+
+    // setDefaultBufferFormat allows the BufferQueue 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) = 0;
+
+    // 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) = 0;
+
+    // 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) = 0;
+
+    // dump state into a string
+    virtual void dump(String8& result, const char* prefix) const = 0;
+
+public:
+    DECLARE_META_INTERFACE(GonkGraphicBufferConsumer);
+};
+
+// ----------------------------------------------------------------------------
+
+class BnGonkGraphicBufferConsumer : public BnInterface<IGonkGraphicBufferConsumer>
+{
+public:
+    virtual status_t    onTransact( uint32_t code,
+                                    const Parcel& data,
+                                    Parcel* reply,
+                                    uint32_t flags = 0);
+};
+
+// ----------------------------------------------------------------------------
+}; // namespace android
+
+#endif // ANDROID_GUI_IGRAPHICBUFFERCONSUMER_H
--- a/widget/gonk/nativewindow/moz.build
+++ b/widget/gonk/nativewindow/moz.build
@@ -10,38 +10,55 @@
 #
 # 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.
 
 EXPORTS += [
+    'GonkBufferQueue.h',
     'GonkNativeWindow.h',
     'GonkNativeWindowClient.h',
 ]
 
-if CONFIG['ANDROID_VERSION'] in ('17', '18'):
+if CONFIG['ANDROID_VERSION'] == '19':
     EXPORTS += [
-        'GonkBufferQueue.h',
-        'GonkConsumerBase.h',
+        'GonkBufferQueueKK.h',
+        'GonkConsumerBaseKK.h',
+        'GonkNativeWindowClientKK.h',
+        'GonkNativeWindowKK.h',
+        'IGonkGraphicBufferConsumer.h',
+    ]
+elif CONFIG['ANDROID_VERSION'] in ('17', '18'):
+    EXPORTS += [
+        'GonkBufferQueueJB.h',
+        'GonkConsumerBaseJB.h',
         'GonkNativeWindowClientJB.h',
         'GonkNativeWindowJB.h',
     ]
 elif CONFIG['ANDROID_VERSION'] == '15':
     EXPORTS += [
         'GonkNativeWindowClientICS.h',
         'GonkNativeWindowICS.h',
     ]
 
 if CONFIG['MOZ_B2G_CAMERA'] or CONFIG['MOZ_OMX_DECODER']:
-    if CONFIG['ANDROID_VERSION'] in ('17', '18'):
+    if CONFIG['ANDROID_VERSION'] == '19':
         SOURCES += [
-            'GonkBufferQueue.cpp',
-            'GonkConsumerBase.cpp',
+            'GonkBufferQueueKK.cpp',
+            'GonkConsumerBaseKK.cpp',
+            'GonkNativeWindowClientKK.cpp',
+            'GonkNativeWindowKK.cpp',
+            'IGonkGraphicBufferConsumer.cpp',
+        ]
+    elif CONFIG['ANDROID_VERSION'] in ('17', '18'):
+        SOURCES += [
+            'GonkBufferQueueJB.cpp',
+            'GonkConsumerBaseJB.cpp',
             'GonkNativeWindowClientJB.cpp',
             'GonkNativeWindowJB.cpp',
         ]
     elif CONFIG['ANDROID_VERSION'] == '15':
         SOURCES += [
             'GonkNativeWindowClientICS.cpp',
             'GonkNativeWindowICS.cpp',
         ]