Merge b2g-inbound to m-c.
Merge b2g-inbound to m-c.
--- 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(×tamp, &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',
]