Merge "Revert "Implement video plane layer""
diff --git a/cmds/atrace/atrace.cpp b/cmds/atrace/atrace.cpp
index b500a6b..34dc9fe 100644
--- a/cmds/atrace/atrace.cpp
+++ b/cmds/atrace/atrace.cpp
@@ -17,6 +17,7 @@
 #include <errno.h>
 #include <fcntl.h>
 #include <getopt.h>
+#include <inttypes.h>
 #include <signal.h>
 #include <stdarg.h>
 #include <stdbool.h>
@@ -368,7 +369,7 @@
 static bool setTagsProperty(uint64_t tags)
 {
     char buf[64];
-    snprintf(buf, 64, "%#llx", tags);
+    snprintf(buf, 64, "%#" PRIx64, tags);
     if (property_set(k_traceTagsProperty, buf) < 0) {
         fprintf(stderr, "error setting trace tags system property\n");
         return false;
@@ -665,7 +666,7 @@
     close(traceFD);
 }
 
-static void handleSignal(int signo)
+static void handleSignal(int /*signo*/)
 {
     if (!g_nohup) {
         g_traceAborted = true;
diff --git a/cmds/flatland/Android.mk b/cmds/flatland/Android.mk
index 5e57f02..d9478fe 100644
--- a/cmds/flatland/Android.mk
+++ b/cmds/flatland/Android.mk
@@ -1,3 +1,4 @@
+local_target_dir := $(TARGET_OUT_DATA)/local/tmp
 LOCAL_PATH:= $(call my-dir)
 include $(CLEAR_VARS)
 
@@ -11,6 +12,8 @@
 
 LOCAL_MODULE_TAGS := tests
 
+LOCAL_MODULE_PATH := $(local_target_dir)
+
 LOCAL_SHARED_LIBRARIES := \
     libEGL      \
     libGLESv2   \
diff --git a/cmds/flatland/Composers.cpp b/cmds/flatland/Composers.cpp
index 15cdb29..1173a81 100644
--- a/cmds/flatland/Composers.cpp
+++ b/cmds/flatland/Composers.cpp
@@ -122,12 +122,12 @@
     virtual void tearDown() {
     }
 
-    virtual bool compose(GLuint texName, const sp<GLConsumer>& glc) {
+    virtual bool compose(GLuint /*texName*/, const sp<GLConsumer>& /*glc*/) {
         return true;
     }
 
 protected:
-    virtual bool setUp(GLHelper* helper) {
+    virtual bool setUp(GLHelper* /*helper*/) {
         return true;
     }
 
diff --git a/cmds/flatland/GLHelper.cpp b/cmds/flatland/GLHelper.cpp
index 42694b3..4b5aba9 100644
--- a/cmds/flatland/GLHelper.cpp
+++ b/cmds/flatland/GLHelper.cpp
@@ -201,14 +201,16 @@
 
 bool GLHelper::createNamedSurfaceTexture(GLuint name, uint32_t w, uint32_t h,
         sp<GLConsumer>* glConsumer, EGLSurface* surface) {
-    sp<BufferQueue> bq = new BufferQueue(mGraphicBufferAlloc);
-    sp<GLConsumer> glc = new GLConsumer(bq, name,
+    sp<IGraphicBufferProducer> producer;
+    sp<IGraphicBufferConsumer> consumer;
+    BufferQueue::createBufferQueue(&producer, &consumer, mGraphicBufferAlloc);
+    sp<GLConsumer> glc = new GLConsumer(consumer, name,
             GL_TEXTURE_EXTERNAL_OES, false);
     glc->setDefaultBufferSize(w, h);
     glc->setDefaultMaxBufferCount(3);
     glc->setConsumerUsageBits(GRALLOC_USAGE_HW_COMPOSER);
 
-    sp<ANativeWindow> anw = new Surface(bq);
+    sp<ANativeWindow> anw = new Surface(producer);
     EGLSurface s = eglCreateWindowSurface(mDisplay, mConfig, anw.get(), NULL);
     if (s == EGL_NO_SURFACE) {
         fprintf(stderr, "eglCreateWindowSurface error: %#x\n", eglGetError());
@@ -332,7 +334,7 @@
 
 static void printShaderSource(const char* const* src) {
     for (size_t i = 0; i < MAX_SHADER_LINES && src[i] != NULL; i++) {
-        fprintf(stderr, "%3d: %s\n", i+1, src[i]);
+        fprintf(stderr, "%3zu: %s\n", i+1, src[i]);
     }
 }
 
diff --git a/cmds/flatland/Main.cpp b/cmds/flatland/Main.cpp
index e80dbb1..866203f 100644
--- a/cmds/flatland/Main.cpp
+++ b/cmds/flatland/Main.cpp
@@ -600,7 +600,7 @@
 
     uint32_t runHeight = b.runHeights[run];
     uint32_t runWidth = b.width * runHeight / b.height;
-    printf(" %-*s | %4d x %4d | ", g_BenchmarkNameLen, b.name,
+    printf(" %-*s | %4d x %4d | ", static_cast<int>(g_BenchmarkNameLen), b.name,
             runWidth, runHeight);
     fflush(stdout);
 
@@ -690,8 +690,9 @@
     size_t len = strlen(scenario);
     size_t leftPad = (g_BenchmarkNameLen - len) / 2;
     size_t rightPad = g_BenchmarkNameLen - len - leftPad;
-    printf(" %*s%s%*s | Resolution  | Time (ms)\n", leftPad, "",
-            "Scenario", rightPad, "");
+    printf(" %*s%s%*s | Resolution  | Time (ms)\n",
+            static_cast<int>(leftPad), "",
+            "Scenario", static_cast<int>(rightPad), "");
 }
 
 // Run ALL the benchmarks!
diff --git a/cmds/installd/commands.c b/cmds/installd/commands.c
index ef063e7..f1f6f99 100644
--- a/cmds/installd/commands.c
+++ b/cmds/installd/commands.c
@@ -1,19 +1,20 @@
 /*
 ** Copyright 2008, 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 
+** 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 
+** 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.
 */
 
+#include <inttypes.h>
 #include <sys/capability.h>
 #include "installd.h"
 #include <diskusage/dirsize.h>
@@ -115,6 +116,8 @@
     if (create_pkg_path(pkgdir, pkgname, PKG_DIR_POSTFIX, userid))
         return -1;
 
+    remove_profile_file(pkgname);
+
     /* delete contents AND directory, no exceptions */
     return delete_dir_contents(pkgdir, 1, NULL);
 }
@@ -155,7 +158,7 @@
     if (stat(pkgdir, &s) < 0) return -1;
 
     if (s.st_uid != 0 || s.st_gid != 0) {
-        ALOGE("fixing uid of non-root pkg: %s %lu %lu\n", pkgdir, s.st_uid, s.st_gid);
+        ALOGE("fixing uid of non-root pkg: %s %" PRIu32 " %" PRIu32 "\n", pkgdir, s.st_uid, s.st_gid);
         return -1;
     }
 
@@ -557,9 +560,9 @@
         return -1;
     }
 
-    dstlen = srclen + strlen(DALVIK_CACHE_PREFIX) + 
+    dstlen = srclen + strlen(DALVIK_CACHE_PREFIX) +
         strlen(DALVIK_CACHE_POSTFIX) + 1;
-    
+
     if (dstlen > PKG_PATH_MAX) {
         return -1;
     }
@@ -568,7 +571,7 @@
             DALVIK_CACHE_PREFIX,
             src + 1, /* skip the leading / */
             DALVIK_CACHE_POSTFIX);
-    
+
     for(tmp = path + strlen(DALVIK_CACHE_PREFIX); *tmp; tmp++) {
         if (*tmp == '/') {
             *tmp = '@';
@@ -579,8 +582,13 @@
 }
 
 static void run_dexopt(int zip_fd, int odex_fd, const char* input_file_name,
-    const char* output_file_name, const char* dexopt_flags)
+    const char* output_file_name)
 {
+    /* platform-specific flags affecting optimization and verification */
+    char dexopt_flags[PROPERTY_VALUE_MAX];
+    property_get("dalvik.vm.dexopt-flags", dexopt_flags, "");
+    ALOGV("dalvik.vm.dexopt-flags=%s\n", dexopt_flags);
+
     static const char* DEX_OPT_BIN = "/system/bin/dexopt";
     static const int MAX_INT_LEN = 12;      // '-'+10dig+'\0' -OR- 0x+8dig
     char zip_num[MAX_INT_LEN];
@@ -596,24 +604,37 @@
 }
 
 static void run_dex2oat(int zip_fd, int oat_fd, const char* input_file_name,
-    const char* output_file_name, const char* dexopt_flags)
+    const char* output_file_name, const char *pkgname)
 {
+    char dex2oat_flags[PROPERTY_VALUE_MAX];
+    property_get("dalvik.vm.dex2oat-flags", dex2oat_flags, "");
+    ALOGV("dalvik.vm.dex2oat-flags=%s\n", dex2oat_flags);
+
     static const char* DEX2OAT_BIN = "/system/bin/dex2oat";
     static const int MAX_INT_LEN = 12;      // '-'+10dig+'\0' -OR- 0x+8dig
     char zip_fd_arg[strlen("--zip-fd=") + MAX_INT_LEN];
     char zip_location_arg[strlen("--zip-location=") + PKG_PATH_MAX];
     char oat_fd_arg[strlen("--oat-fd=") + MAX_INT_LEN];
     char oat_location_arg[strlen("--oat-name=") + PKG_PATH_MAX];
+    char profile_file[strlen("--profile-file=") + PKG_PATH_MAX];
 
     sprintf(zip_fd_arg, "--zip-fd=%d", zip_fd);
     sprintf(zip_location_arg, "--zip-location=%s", input_file_name);
     sprintf(oat_fd_arg, "--oat-fd=%d", oat_fd);
     sprintf(oat_location_arg, "--oat-location=%s", output_file_name);
+    if (strcmp(pkgname, "*") != 0) {
+        snprintf(profile_file, sizeof(profile_file), "--profile-file=%s/%s",
+                 DALVIK_CACHE_PREFIX "profiles", pkgname);
+    } else {
+        strcpy(profile_file, "--no-profile-file");
+    }
 
     ALOGV("Running %s in=%s out=%s\n", DEX2OAT_BIN, input_file_name, output_file_name);
     execl(DEX2OAT_BIN, DEX2OAT_BIN,
           zip_fd_arg, zip_location_arg,
           oat_fd_arg, oat_location_arg,
+          profile_file,
+          strlen(dex2oat_flags) > 0 ? dex2oat_flags : NULL,
           (char*) NULL);
     ALOGE("execl(%s) failed: %s\n", DEX2OAT_BIN, strerror(errno));
 }
@@ -644,12 +665,12 @@
     }
 }
 
-int dexopt(const char *apk_path, uid_t uid, int is_public)
+int dexopt(const char *apk_path, uid_t uid, int is_public,
+           const char *pkgname)
 {
     struct utimbuf ut;
     struct stat apk_stat, dex_stat;
     char out_path[PKG_PATH_MAX];
-    char dexopt_flags[PROPERTY_VALUE_MAX];
     char persist_sys_dalvik_vm_lib[PROPERTY_VALUE_MAX];
     char *end;
     int res, zip_fd=-1, out_fd=-1;
@@ -658,11 +679,7 @@
         return -1;
     }
 
-    /* platform-specific flags affecting optimization and verification */
-    property_get("dalvik.vm.dexopt-flags", dexopt_flags, "");
-    ALOGV("dalvik.vm.dexopt_flags=%s\n", dexopt_flags);
-
-    /* The command to run depend ones the value of persist.sys.dalvik.vm.lib */
+    /* The command to run depend on the value of persist.sys.dalvik.vm.lib */
     property_get("persist.sys.dalvik.vm.lib.1", persist_sys_dalvik_vm_lib, "libdvm.so");
 
     /* Before anything else: is there a .odex file?  If so, we have
@@ -703,6 +720,12 @@
         goto fail;
     }
 
+    // Create profile file if there is a package name present.
+    if (strcmp(pkgname, "*") != 0) {
+        create_profile_file(pkgname, uid);
+    }
+
+
     ALOGV("DexInv: --- BEGIN '%s' ---\n", apk_path);
 
     pid_t pid;
@@ -733,9 +756,9 @@
         }
 
         if (strncmp(persist_sys_dalvik_vm_lib, "libdvm", 6) == 0) {
-            run_dexopt(zip_fd, out_fd, apk_path, out_path, dexopt_flags);
+            run_dexopt(zip_fd, out_fd, apk_path, out_path);
         } else if (strncmp(persist_sys_dalvik_vm_lib, "libart", 6) == 0) {
-            run_dex2oat(zip_fd, out_fd, apk_path, out_path, dexopt_flags);
+            run_dex2oat(zip_fd, out_fd, apk_path, out_path, pkgname);
         } else {
             exit(69);   /* Unexpected persist.sys.dalvik.vm.lib value */
         }
@@ -799,12 +822,12 @@
 
     int srcend = strlen(srcpath);
     int dstend = strlen(dstpath);
-    
+
     if (lstat(srcpath, statbuf) < 0) {
         ALOGW("Unable to stat %s: %s\n", srcpath, strerror(errno));
         return 1;
     }
-    
+
     if ((statbuf->st_mode&S_IFDIR) == 0) {
         mkinnerdirs(dstpath, dstbasepos, S_IRWXU|S_IRWXG|S_IXOTH,
                 dstuid, dstgid, statbuf);
@@ -830,7 +853,7 @@
     }
 
     res = 0;
-    
+
     while ((de = readdir(d))) {
         const char *name = de->d_name;
             /* always skip "." and ".." */
@@ -838,32 +861,32 @@
             if (name[1] == 0) continue;
             if ((name[1] == '.') && (name[2] == 0)) continue;
         }
-        
+
         if ((srcend+strlen(name)) >= (PKG_PATH_MAX-2)) {
             ALOGW("Source path too long; skipping: %s/%s\n", srcpath, name);
             continue;
         }
-        
+
         if ((dstend+strlen(name)) >= (PKG_PATH_MAX-2)) {
             ALOGW("Destination path too long; skipping: %s/%s\n", dstpath, name);
             continue;
         }
-        
+
         srcpath[srcend] = dstpath[dstend] = '/';
         strcpy(srcpath+srcend+1, name);
         strcpy(dstpath+dstend+1, name);
-        
+
         if (movefileordir(srcpath, dstpath, dstbasepos, dstuid, dstgid, statbuf) != 0) {
             res = 1;
         }
-        
+
         // Note: we will be leaving empty directories behind in srcpath,
         // but that is okay, the package manager will be erasing all of the
         // data associated with .apks that disappear.
-        
+
         srcpath[srcend] = dstpath[dstend] = 0;
     }
-    
+
     closedir(d);
     return res;
 }
@@ -905,7 +928,7 @@
                         UPDATE_COMMANDS_DIR_PREFIX, name);
                 continue;
             }
-            
+
             bufp = 0;
             bufe = 0;
             buf[PKG_PATH_MAX] = 0;
diff --git a/cmds/installd/installd.c b/cmds/installd/installd.c
index 549aaab..b4df3a3 100644
--- a/cmds/installd/installd.c
+++ b/cmds/installd/installd.c
@@ -38,8 +38,8 @@
 
 static int do_dexopt(char **arg, char reply[REPLY_MAX])
 {
-        /* apk_path, uid, is_public */
-    return dexopt(arg[0], atoi(arg[1]), atoi(arg[2]));
+        /* apk_path, uid, is_public, pkgname */
+    return dexopt(arg[0], atoi(arg[1]), atoi(arg[2]), arg[3]);
 }
 
 static int do_move_dex(char **arg, char reply[REPLY_MAX])
@@ -138,7 +138,7 @@
 struct cmdinfo cmds[] = {
     { "ping",                 0, do_ping },
     { "install",              4, do_install },
-    { "dexopt",               3, do_dexopt },
+    { "dexopt",               4, do_dexopt },
     { "movedex",              2, do_move_dex },
     { "rmdex",                1, do_rm_dex },
     { "remove",               2, do_remove },
diff --git a/cmds/installd/installd.h b/cmds/installd/installd.h
index cab5cb7..b458031 100644
--- a/cmds/installd/installd.h
+++ b/cmds/installd/installd.h
@@ -189,6 +189,8 @@
 
 int ensure_dir(const char* path, mode_t mode, uid_t uid, gid_t gid);
 int ensure_media_user_dirs(userid_t userid);
+int create_profile_file(const char *pkgname, gid_t gid);
+void remove_profile_file(const char *pkgname);
 
 /* commands.c */
 
@@ -207,7 +209,7 @@
              const char *fwdlock_apkpath, const char *asecpath, int64_t *codesize,
              int64_t *datasize, int64_t *cachesize, int64_t *asecsize);
 int free_cache(int64_t free_size);
-int dexopt(const char *apk_path, uid_t uid, int is_public);
+int dexopt(const char *apk_path, uid_t uid, int is_public, const char *pkgName);
 int movefiles();
 int linklib(const char* target, const char* source, int userId);
 int idmap(const char *target_path, const char *overlay_path, uid_t uid);
diff --git a/cmds/installd/tests/Android.mk b/cmds/installd/tests/Android.mk
index c0192f4..4faf3c0 100644
--- a/cmds/installd/tests/Android.mk
+++ b/cmds/installd/tests/Android.mk
@@ -18,7 +18,7 @@
     libgtest_main
 
 c_includes := \
-    frameworks/base/cmds/installd
+    frameworks/native/cmds/installd
 
 $(foreach file,$(test_src_files), \
     $(eval include $(CLEAR_VARS)) \
diff --git a/cmds/installd/utils.c b/cmds/installd/utils.c
index ef634c6..8f4da65 100644
--- a/cmds/installd/utils.c
+++ b/cmds/installd/utils.c
@@ -1,16 +1,16 @@
 /*
 ** Copyright 2008, 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 
+** 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 
+** 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.
 */
 
@@ -435,7 +435,7 @@
 {
     cache->numCollected++;
     if ((cache->numCollected%20000) == 0) {
-        ALOGI("Collected cache so far: %d directories, %d files",
+        ALOGI("Collected cache so far: %zd directories, %zd files",
             cache->numDirs, cache->numFiles);
     }
 }
@@ -730,7 +730,7 @@
     int skip = 0;
     char path[PATH_MAX];
 
-    ALOGI("Collected cache files: %d directories, %d files",
+    ALOGI("Collected cache files: %zd directories, %zd files",
         cache->numDirs, cache->numFiles);
 
     CACHE_NOISY(ALOGI("Sorting files..."));
@@ -1005,3 +1005,59 @@
 
     return 0;
 }
+
+int create_profile_file(const char *pkgname, gid_t gid) {
+    const char *profile_dir = DALVIK_CACHE_PREFIX "profiles";
+    struct stat profileStat;
+    char profile_file[PKG_PATH_MAX];
+
+    // If we don't have a profile directory under dalvik-cache we need to create one.
+    if (stat(profile_dir, &profileStat) < 0) {
+        // Create the profile directory under dalvik-cache.
+        if (mkdir(profile_dir, 0711) < 0) {
+            ALOGE("cannot make profile dir '%s': %s\n", profile_dir, strerror(errno));
+            return -1;
+        }
+
+        // Make the profile directory write-only for group and other. Owner can rwx it.
+        if (chmod(profile_dir, 0711) < 0) {
+            ALOGE("cannot chown profile dir '%s': %s\n", profile_dir, strerror(errno));
+            unlink(profile_dir);
+            return -1;
+        }
+    }
+
+    snprintf(profile_file, sizeof(profile_file), "%s/%s", profile_dir, pkgname);
+
+    // The 'system' user needs to be able to read the profile to determine if dex2oat
+    // needs to be run.  This is done in dalvik.system.DexFile.isDexOptNeededInternal().  So
+    // we make it world readable.  Not a problem since the dalvik cache is world
+    // readable anyway.
+
+    int fd = open(profile_file, O_WRONLY | O_CREAT | O_EXCL | O_NOFOLLOW, 0664);
+
+    // Open will fail if the file already exists.  We want to ignore that.
+    if (fd >= 0) {
+        if (fchown(fd, -1, gid) < 0) {
+            ALOGE("cannot chown profile file '%s': %s\n", profile_file, strerror(errno));
+            close(fd);
+            unlink(profile_file);
+            return -1;
+        }
+
+        if (fchmod(fd, 0664) < 0) {
+            ALOGE("cannot chmod profile file '%s': %s\n", profile_file, strerror(errno));
+            close(fd);
+            unlink(profile_file);
+            return -1;
+        }
+        close(fd);
+    }
+    return 0;
+}
+
+void remove_profile_file(const char *pkgname) {
+    char profile_file[PKG_PATH_MAX];
+    snprintf(profile_file, sizeof(profile_file), "%s/%s", DALVIK_CACHE_PREFIX "profiles", pkgname);
+    unlink(profile_file);
+}
diff --git a/cmds/screenshot/Android.mk b/cmds/screenshot/Android.mk
deleted file mode 100644
index 1ee7807..0000000
--- a/cmds/screenshot/Android.mk
+++ /dev/null
@@ -1,12 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := screenshot.c
-
-LOCAL_MODULE := screenshot
-
-LOCAL_SHARED_LIBRARIES := libcutils libz liblog
-LOCAL_STATIC_LIBRARIES := libpng
-LOCAL_C_INCLUDES += external/zlib external/libpng
-
-include $(BUILD_EXECUTABLE)
diff --git a/cmds/screenshot/screenshot.c b/cmds/screenshot/screenshot.c
deleted file mode 100644
index be1ecd4..0000000
--- a/cmds/screenshot/screenshot.c
+++ /dev/null
@@ -1,171 +0,0 @@
-#include <stdlib.h>
-#include <stdio.h>
-#include <unistd.h>
-#include <string.h>
-#include <fcntl.h>
-#include <errno.h>
-
-#include <linux/fb.h>
-
-#include <zlib.h>
-#include <png.h>
-
-#include "private/android_filesystem_config.h"
-
-#define LOG_TAG "screenshot"
-#include <utils/Log.h>
-
-void take_screenshot(FILE *fb_in, FILE *fb_out) {
-    int fb;
-    char imgbuf[0x10000];
-    struct fb_var_screeninfo vinfo;
-    png_structp png;
-    png_infop info;
-    unsigned int r,c,rowlen;
-    unsigned int bytespp,offset;
-
-    fb = fileno(fb_in);
-    if(fb < 0) {
-        ALOGE("failed to open framebuffer\n");
-        return;
-    }
-    fb_in = fdopen(fb, "r");
-
-    if(ioctl(fb, FBIOGET_VSCREENINFO, &vinfo) < 0) {
-        ALOGE("failed to get framebuffer info\n");
-        return;
-    }
-    fcntl(fb, F_SETFD, FD_CLOEXEC);
-
-    png = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
-    if (png == NULL) {
-        ALOGE("failed png_create_write_struct\n");
-        fclose(fb_in);
-        return;
-    }
-
-    png_init_io(png, fb_out);
-    info = png_create_info_struct(png);
-    if (info == NULL) {
-        ALOGE("failed png_create_info_struct\n");
-        png_destroy_write_struct(&png, NULL);
-        fclose(fb_in);
-        return;
-    }
-    if (setjmp(png_jmpbuf(png))) {
-        ALOGE("failed png setjmp\n");
-        png_destroy_write_struct(&png, NULL);
-        fclose(fb_in);
-        return;
-    }
-
-    bytespp = vinfo.bits_per_pixel / 8;
-    png_set_IHDR(png, info,
-        vinfo.xres, vinfo.yres, vinfo.bits_per_pixel / 4, 
-        PNG_COLOR_TYPE_RGB_ALPHA, PNG_INTERLACE_NONE,
-        PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
-    png_write_info(png, info);
-
-    rowlen=vinfo.xres * bytespp;
-    if (rowlen > sizeof(imgbuf)) {
-        ALOGE("crazy rowlen: %d\n", rowlen);
-        png_destroy_write_struct(&png, NULL);
-        fclose(fb_in);
-        return;
-    }
-
-    offset = vinfo.xoffset * bytespp + vinfo.xres * vinfo.yoffset * bytespp;
-    fseek(fb_in, offset, SEEK_SET);
-
-    for(r=0; r<vinfo.yres; r++) {
-        int len = fread(imgbuf, 1, rowlen, fb_in);
-        if (len <= 0) break;
-        png_write_row(png, (png_bytep)imgbuf);
-    }
-
-    png_write_end(png, info);
-    fclose(fb_in);
-    png_destroy_write_struct(&png, NULL);
-}
-
-void fork_sound(const char* path) {
-    pid_t pid = fork();
-    if (pid == 0) {
-        execl("/system/bin/stagefright", "stagefright", "-o", "-a", path, NULL);
-    }
-}
-
-void usage() {
-    fprintf(stderr,
-            "usage: screenshot [-s soundfile] filename.png\n"
-            "   -s: play a sound effect to signal success\n"
-            "   -i: autoincrement to avoid overwriting filename.png\n"
-    );
-}
-
-int main(int argc, char**argv) {
-    FILE *png = NULL;
-    FILE *fb_in = NULL;
-    char outfile[PATH_MAX] = "";
-
-    char * soundfile = NULL;
-    int do_increment = 0;
-
-    int c;
-    while ((c = getopt(argc, argv, "s:i")) != -1) {
-        switch (c) {
-            case 's': soundfile = optarg; break;
-            case 'i': do_increment = 1; break;
-            case '?':
-            case 'h':
-                usage(); exit(1);
-        }
-    }
-    argc -= optind;
-    argv += optind;
-
-    if (argc < 1) {
-        usage(); exit(1);
-    }
-
-    strlcpy(outfile, argv[0], PATH_MAX);
-    if (do_increment) {
-        struct stat st;
-        char base[PATH_MAX] = "";
-        int i = 0;
-        while (stat(outfile, &st) == 0) {
-            if (!base[0]) {
-                char *p = strrchr(outfile, '.');
-                if (p) *p = '\0';
-                strcpy(base, outfile);
-            }
-            snprintf(outfile, PATH_MAX, "%s-%d.png", base, ++i);
-        }
-    }
-
-    fb_in = fopen("/dev/graphics/fb0", "r");
-    if (!fb_in) {
-        fprintf(stderr, "error: could not read framebuffer\n");
-        exit(1);
-    }
-
-    /* switch to non-root user and group */
-    gid_t groups[] = { AID_LOG, AID_SDCARD_RW };
-    setgroups(sizeof(groups)/sizeof(groups[0]), groups);
-    setuid(AID_SHELL);
-
-    png = fopen(outfile, "w");
-    if (!png) {
-        fprintf(stderr, "error: writing file %s: %s\n",
-                outfile, strerror(errno));
-        exit(1);
-    }
-
-    take_screenshot(fb_in, png);
-
-    if (soundfile) {
-        fork_sound(soundfile);
-    }
-
-    exit(0);
-}
diff --git a/data/etc/android.software.accessibility.xml b/data/etc/android.software.accessibility.xml
deleted file mode 100644
index 709b3f0..0000000
--- a/data/etc/android.software.accessibility.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2014 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.
--->
-
-<permissions>
-    <feature name="android.software.accessibility" />
-</permissions>
diff --git a/data/etc/handheld_core_hardware.xml b/data/etc/handheld_core_hardware.xml
index 3ff8969..4d81fb6 100644
--- a/data/etc/handheld_core_hardware.xml
+++ b/data/etc/handheld_core_hardware.xml
@@ -35,7 +35,6 @@
     <feature name="android.hardware.screen.landscape" />
 
     <!-- basic system services -->
-    <feature name="android.software.accessibility" />
     <feature name="android.software.app_widgets" />
     <feature name="android.software.backup" />
     <feature name="android.software.home_screen" />
diff --git a/data/etc/tablet_core_hardware.xml b/data/etc/tablet_core_hardware.xml
index 11c5d93..2a74b0f 100644
--- a/data/etc/tablet_core_hardware.xml
+++ b/data/etc/tablet_core_hardware.xml
@@ -36,7 +36,6 @@
     <feature name="android.hardware.screen.landscape" />
 
     <!-- basic system services -->
-    <feature name="android.software.accessibility" />
     <feature name="android.software.app_widgets" />
     <feature name="android.software.backup" />
     <feature name="android.software.home_screen" />
diff --git a/data/etc/wearable_core_hardware.xml b/data/etc/wearable_core_hardware.xml
index c34b25c..215665f 100644
--- a/data/etc/wearable_core_hardware.xml
+++ b/data/etc/wearable_core_hardware.xml
@@ -33,10 +33,12 @@
     <feature name="android.hardware.screen.landscape" />
 
     <!-- basic system services -->
-    <feature name="android.software.accessibility" />
     <feature name="android.software.home_screen" />
     <feature name="android.software.input_methods" />
 
+    <!-- Feature to specify if the device supports adding device admins. -->
+    <feature name="android.software.device_admin" />
+
     <!-- devices with GPS must include android.hardware.location.gps.xml -->
     <!-- devices with an autofocus camera and/or flash must include either
          android.hardware.camera.autofocus.xml or
diff --git a/include/android/keycodes.h b/include/android/keycodes.h
index 1ca1332..b6a5f4c 100644
--- a/include/android/keycodes.h
+++ b/include/android/keycodes.h
@@ -266,6 +266,8 @@
     AKEYCODE_BRIGHTNESS_DOWN = 220,
     AKEYCODE_BRIGHTNESS_UP   = 221,
     AKEYCODE_MEDIA_AUDIO_TRACK = 222,
+    AKEYCODE_SLEEP           = 223,
+    AKEYCODE_WAKEUP          = 224,
 
     // NOTE: If you add a new keycode here you must also add it to several other files.
     //       Refer to frameworks/base/core/java/android/view/KeyEvent.java for the full list.
diff --git a/include/binder/Parcel.h b/include/binder/Parcel.h
index e9966fe..548fbf8 100644
--- a/include/binder/Parcel.h
+++ b/include/binder/Parcel.h
@@ -105,6 +105,7 @@
     status_t            writeStrongBinder(const sp<IBinder>& val);
     status_t            writeWeakBinder(const wp<IBinder>& val);
     status_t            writeInt32Array(size_t len, const int32_t *val);
+    status_t            writeByteArray(size_t len, const uint8_t *val);
 
     template<typename T>
     status_t            write(const Flattenable<T>& val);
diff --git a/include/gui/BufferItem.h b/include/gui/BufferItem.h
new file mode 100644
index 0000000..5effd10
--- /dev/null
+++ b/include/gui/BufferItem.h
@@ -0,0 +1,103 @@
+/*
+ * Copyright 2014 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_BUFFERITEM_H
+#define ANDROID_GUI_BUFFERITEM_H
+
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
+
+#include <gui/IGraphicBufferConsumer.h>
+
+#include <ui/Rect.h>
+
+#include <utils/Flattenable.h>
+#include <utils/StrongPointer.h>
+
+namespace android {
+
+class Fence;
+class GraphicBuffer;
+
+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:
+    // The default value of mBuf, used to indicate this doesn't correspond to a slot.
+    enum { INVALID_BUFFER_SLOT = -1 };
+    BufferItem();
+    operator IGraphicBufferConsumer::BufferItem() const;
+
+    static const char* scalingModeName(uint32_t scalingMode);
+
+    // 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.
+    // refer to NATIVE_WINDOW_TRANSFORM_* in <window.h>
+    uint32_t mTransform;
+
+    // mScalingMode is the current scaling mode for this buffer slot.
+    // refer to NATIVE_WINDOW_SCALING_* in <window.h>
+    uint32_t mScalingMode;
+
+    // mTimestamp is the current timestamp for this buffer slot. This gets
+    // to set by queueBuffer each time this slot is queued. This value
+    // is guaranteed to be monotonically increasing for each newly
+    // acquired buffer.
+    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;
+
+    // mSlot is the slot index of this buffer (default INVALID_BUFFER_SLOT).
+    int mSlot;
+
+    // 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;
+};
+
+} // namespace android
+
+#endif
diff --git a/include/gui/BufferQueue.h b/include/gui/BufferQueue.h
index 15dc645..f74dc26 100644
--- a/include/gui/BufferQueue.h
+++ b/include/gui/BufferQueue.h
@@ -17,28 +17,54 @@
 #ifndef ANDROID_GUI_BUFFERQUEUE_H
 #define ANDROID_GUI_BUFFERQUEUE_H
 
-#include <EGL/egl.h>
-#include <EGL/eglext.h>
+#include <gui/BufferQueueProducer.h>
+#include <gui/BufferQueueConsumer.h>
+#include <gui/IConsumerListener.h>
+
+// These are only required to keep other parts of the framework with incomplete
+// dependencies building successfully
+#include <gui/IGraphicBufferAlloc.h>
 
 #include <binder/IBinder.h>
 
-#include <gui/IConsumerListener.h>
-#include <gui/IGraphicBufferAlloc.h>
-#include <gui/IGraphicBufferProducer.h>
-#include <gui/IGraphicBufferConsumer.h>
-
-#include <ui/Fence.h>
-#include <ui/GraphicBuffer.h>
-
-#include <utils/String8.h>
-#include <utils/Vector.h>
-#include <utils/threads.h>
-
 namespace android {
-// ----------------------------------------------------------------------------
 
-class BufferQueue : public BnGraphicBufferProducer,
-                    public BnGraphicBufferConsumer,
+// BQProducer and BQConsumer are thin shim classes to allow methods with the
+// same signature in both IGraphicBufferProducer and IGraphicBufferConsumer.
+// This will stop being an issue when we deprecate creating BufferQueues
+// directly (as opposed to using the *Producer and *Consumer interfaces).
+class BQProducer : public BnGraphicBufferProducer {
+public:
+    virtual status_t detachProducerBuffer(int slot) = 0;
+    virtual status_t attachProducerBuffer(int* slot,
+            const sp<GraphicBuffer>& buffer) = 0;
+
+    virtual status_t detachBuffer(int slot) {
+        return detachProducerBuffer(slot);
+    }
+
+    virtual status_t attachBuffer(int* slot, const sp<GraphicBuffer>& buffer) {
+        return attachProducerBuffer(slot, buffer);
+    }
+};
+
+class BQConsumer : public BnGraphicBufferConsumer {
+public:
+    virtual status_t detachConsumerBuffer(int slot) = 0;
+    virtual status_t attachConsumerBuffer(int* slot,
+            const sp<GraphicBuffer>& buffer) = 0;
+
+    virtual status_t detachBuffer(int slot) {
+        return detachConsumerBuffer(slot);
+    }
+
+    virtual status_t attachBuffer(int* slot, const sp<GraphicBuffer>& buffer) {
+        return attachConsumerBuffer(slot, buffer);
+    }
+};
+
+class BufferQueue : public BQProducer,
+                    public BQConsumer,
                     private IBinder::DeathRecipient {
 public:
     // BufferQueue will keep track of at most this value of buffers.
@@ -74,6 +100,7 @@
         virtual ~ProxyConsumerListener();
         virtual void onFrameAvailable();
         virtual void onBuffersReleased();
+        virtual void onSidebandStreamChanged();
     private:
         // mConsumerListener is a weak reference to the IConsumerListener.  This is
         // the raison d'etre of ProxyConsumerListener.
@@ -84,6 +111,15 @@
     // producers and consumers. allocator is used to allocate all the
     // needed gralloc buffers.
     BufferQueue(const sp<IGraphicBufferAlloc>& allocator = NULL);
+
+    static void createBufferQueue(sp<BnGraphicBufferProducer>* outProducer,
+            sp<BnGraphicBufferConsumer>* outConsumer,
+            const sp<IGraphicBufferAlloc>& allocator = NULL);
+
+    static void createBufferQueue(sp<IGraphicBufferProducer>* outProducer,
+            sp<IGraphicBufferConsumer>* outConsumer,
+            const sp<IGraphicBufferAlloc>& allocator = NULL);
+
     virtual ~BufferQueue();
 
     /*
@@ -164,6 +200,13 @@
     virtual status_t dequeueBuffer(int *buf, sp<Fence>* fence, bool async,
             uint32_t width, uint32_t height, uint32_t format, uint32_t usage);
 
+    // See IGraphicBufferProducer::detachBuffer
+    virtual status_t detachProducerBuffer(int slot);
+
+    // See IGraphicBufferProducer::attachBuffer
+    virtual status_t attachProducerBuffer(int* slot,
+            const sp<GraphicBuffer>& buffer);
+
     // queueBuffer returns a filled buffer to the BufferQueue.
     //
     // Additional data is provided in the QueueBufferInput struct.  Notably,
@@ -211,6 +254,18 @@
     // connected to the specified producer API.
     virtual status_t disconnect(int api);
 
+    // Attaches a sideband buffer stream to the BufferQueue.
+    //
+    // A sideband stream is a device-specific mechanism for passing buffers
+    // from the producer to the consumer without using dequeueBuffer/
+    // queueBuffer. If a sideband stream is present, the consumer can choose
+    // whether to acquire buffers from the sideband stream or from the queued
+    // buffers.
+    //
+    // Passing NULL or a different stream handle will detach the previous
+    // handle if any.
+    virtual status_t setSidebandStream(const sp<NativeHandle>& stream);
+
     /*
      * IGraphicBufferConsumer interface
      */
@@ -230,6 +285,13 @@
     // is CLOCK_MONOTONIC.
     virtual status_t acquireBuffer(BufferItem* buffer, nsecs_t presentWhen);
 
+    // See IGraphicBufferConsumer::detachBuffer
+    virtual status_t detachConsumerBuffer(int slot);
+
+    // See IGraphicBufferConsumer::attachBuffer
+    virtual status_t attachConsumerBuffer(int* slot,
+            const sp<GraphicBuffer>& buffer);
+
     // 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
@@ -313,268 +375,15 @@
     // NATIVE_WINDOW_TRANSFORM_ROT_90.  The default is 0 (no transform).
     virtual status_t setTransformHint(uint32_t hint);
 
+    // Retrieve the BufferQueue's sideband stream, if any.
+    virtual sp<NativeHandle> getSidebandStream() const;
+
     // dump our state in a String
     virtual void dump(String8& result, const char* prefix) const;
 
 private:
-    // The default API number used to indicate no producer client is connected.
-    enum { NO_CONNECTED_API = 0 };
-
-    // Aliases for using enums from <IGraphicBufferConsumer.h>
-    enum { STALE_BUFFER_SLOT = IGraphicBufferConsumer::STALE_BUFFER_SLOT };
-
-    // 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();
-
-    // 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 BufferQueue 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()
-        : mEglDisplay(EGL_NO_DISPLAY),
-          mBufferState(BufferSlot::FREE),
-          mRequestBufferCalled(false),
-          mFrameNumber(0),
-          mEglFence(EGL_NO_SYNC_KHR),
-          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;
-
-        // mEglDisplay is the EGLDisplay used to create EGLSyncKHR objects.
-        EGLDisplay mEglDisplay;
-
-        // 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 BufferQueue.  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 BufferQueue.  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;
-
-        // 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 BufferQueue.
-    //
-    // 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 BufferQueue.  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 BufferQueue 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 BufferQueue 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 BufferQueue 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 BufferQueue 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;
+    sp<BufferQueueProducer> mProducer;
+    sp<BufferQueueConsumer> mConsumer;
 };
 
 // ----------------------------------------------------------------------------
diff --git a/include/gui/BufferQueueConsumer.h b/include/gui/BufferQueueConsumer.h
new file mode 100644
index 0000000..7f24c83
--- /dev/null
+++ b/include/gui/BufferQueueConsumer.h
@@ -0,0 +1,181 @@
+/*
+ * Copyright 2014 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_BUFFERQUEUECONSUMER_H
+#define ANDROID_GUI_BUFFERQUEUECONSUMER_H
+
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
+
+#include <gui/BufferQueueDefs.h>
+#include <gui/IGraphicBufferConsumer.h>
+
+namespace android {
+
+class BufferQueueCore;
+
+class BufferQueueConsumer : public BnGraphicBufferConsumer {
+
+public:
+    BufferQueueConsumer(const sp<BufferQueueCore>& core);
+    virtual ~BufferQueueConsumer();
+
+    // acquireBuffer attempts to acquire ownership of the next pending buffer in
+    // the BufferQueue. If no buffer is pending then it returns
+    // NO_BUFFER_AVAILABLE. 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 expectedPresent 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* outBuffer,
+            nsecs_t expectedPresent);
+
+    // See IGraphicBufferConsumer::detachBuffer
+    virtual status_t detachBuffer(int slot);
+
+    // See IGraphicBufferConsumer::attachBuffer
+    virtual status_t attachBuffer(int* slot, const sp<GraphicBuffer>& buffer);
+
+    // 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 slot, uint64_t frameNumber,
+            const sp<Fence>& releaseFence, EGLDisplay display,
+            EGLSyncKHR fence);
+
+    // connect 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.
+    //
+    // consumerListener may not be NULL.
+    virtual status_t connect(const sp<IConsumerListener>& consumerListener,
+            bool controlledByApp);
+
+    // disconnect 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 disconnect();
+
+    // getReleasedBuffers sets the value pointed to by outSlotMask 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* outSlotMask);
+
+    // 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 width, uint32_t height);
+
+    // 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 connect().
+    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 BufferQueue.
+    virtual status_t setMaxAcquiredBufferCount(int maxAcquiredBuffers);
+
+    // setConsumerName sets the name used in logging
+    virtual void setConsumerName(const String8& name);
+
+    // 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);
+
+    // 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);
+
+    // Retrieve the sideband buffer stream, if any.
+    virtual sp<NativeHandle> getSidebandStream() const;
+
+    // dump our state in a String
+    virtual void dump(String8& result, const char* prefix) const;
+
+    // Functions required for backwards compatibility.
+    // These will be modified/renamed in IGraphicBufferConsumer and will be
+    // removed from this class at that time. See b/13306289.
+
+    virtual status_t releaseBuffer(int buf, uint64_t frameNumber,
+            EGLDisplay display, EGLSyncKHR fence,
+            const sp<Fence>& releaseFence) {
+        return releaseBuffer(buf, frameNumber, releaseFence, display, fence);
+    }
+
+    virtual status_t consumerConnect(const sp<IConsumerListener>& consumer,
+            bool controlledByApp) {
+        return connect(consumer, controlledByApp);
+    }
+
+    virtual status_t consumerDisconnect() { return disconnect(); }
+
+    // End functions required for backwards compatibility
+
+private:
+    sp<BufferQueueCore> mCore;
+
+    // This references mCore->mSlots. Lock mCore->mMutex while accessing.
+    BufferQueueDefs::SlotsType& mSlots;
+
+    // This is a cached copy of the name stored in the BufferQueueCore.
+    // It's updated during setConsumerName.
+    String8 mConsumerName;
+
+}; // class BufferQueueConsumer
+
+} // namespace android
+
+#endif
diff --git a/include/gui/BufferQueueCore.h b/include/gui/BufferQueueCore.h
new file mode 100644
index 0000000..89f2779
--- /dev/null
+++ b/include/gui/BufferQueueCore.h
@@ -0,0 +1,241 @@
+/*
+ * Copyright 2014 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_BUFFERQUEUECORE_H
+#define ANDROID_GUI_BUFFERQUEUECORE_H
+
+#include <gui/BufferQueueDefs.h>
+#include <gui/BufferSlot.h>
+
+#include <utils/Condition.h>
+#include <utils/Mutex.h>
+#include <utils/NativeHandle.h>
+#include <utils/RefBase.h>
+#include <utils/String8.h>
+#include <utils/StrongPointer.h>
+#include <utils/Trace.h>
+#include <utils/Vector.h>
+
+#define BQ_LOGV(x, ...) ALOGV("[%s] "x, mConsumerName.string(), ##__VA_ARGS__)
+#define BQ_LOGD(x, ...) ALOGD("[%s] "x, mConsumerName.string(), ##__VA_ARGS__)
+#define BQ_LOGI(x, ...) ALOGI("[%s] "x, mConsumerName.string(), ##__VA_ARGS__)
+#define BQ_LOGW(x, ...) ALOGW("[%s] "x, mConsumerName.string(), ##__VA_ARGS__)
+#define BQ_LOGE(x, ...) ALOGE("[%s] "x, mConsumerName.string(), ##__VA_ARGS__)
+
+#define ATRACE_BUFFER_INDEX(index)                                   \
+    if (ATRACE_ENABLED()) {                                          \
+        char ___traceBuf[1024];                                      \
+        snprintf(___traceBuf, 1024, "%s: %d",                        \
+                mCore->mConsumerName.string(), (index));             \
+        android::ScopedTrace ___bufTracer(ATRACE_TAG, ___traceBuf);  \
+    }
+
+namespace android {
+
+class BufferItem;
+class IBinder;
+class IConsumerListener;
+class IGraphicBufferAlloc;
+
+class BufferQueueCore : public virtual RefBase {
+
+    friend class BufferQueueProducer;
+    friend class BufferQueueConsumer;
+
+public:
+    // Used as a placeholder slot number when the value isn't pointing to an
+    // existing buffer.
+    enum { INVALID_BUFFER_SLOT = -1 }; // TODO: Extract from IGBC::BufferItem
+
+    // We reserve two slots in order to guarantee that the producer and
+    // consumer can run asynchronously.
+    enum { MAX_MAX_ACQUIRED_BUFFERS = BufferQueueDefs::NUM_BUFFER_SLOTS - 2 };
+
+    // The default API number used to indicate that no producer is connected
+    enum { NO_CONNECTED_API = 0 };
+
+    typedef Vector<BufferItem> Fifo;
+
+    // BufferQueueCore manages a pool of gralloc memory slots to be used by
+    // producers and consumers. allocator is used to allocate all the needed
+    // gralloc buffers.
+    BufferQueueCore(const sp<IGraphicBufferAlloc>& allocator = NULL);
+    virtual ~BufferQueueCore();
+
+private:
+    // Dump our state in a string
+    void dump(String8& result, const char* prefix) const;
+
+    // getMinUndequeuedBufferCountLocked 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 getMinUndequeuedBufferCountLocked(bool async) const;
+
+    // getMinMaxBufferCountLocked returns the minimum number of buffers allowed
+    // given the current BufferQueue state. The async parameter tells whether
+    // we're in asynchonous mode.
+    int getMinMaxBufferCountLocked(bool async) const;
+
+    // getMaxBufferCountLocked returns the maximum number of buffers that can be
+    // allocated at once. This value depends on 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;
+
+    // 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);
+
+    // freeBufferLocked frees the GraphicBuffer and sync resources for the
+    // given slot.
+    void freeBufferLocked(int slot);
+
+    // freeAllBuffersLocked frees the GraphicBuffer and sync resources for
+    // all slots.
+    void freeAllBuffersLocked();
+
+    // stillTracking returns true iff the buffer item is still being tracked
+    // in one of the slots.
+    bool stillTracking(const BufferItem* item) const;
+
+    // mAllocator is the connection to SurfaceFlinger that is used to allocate
+    // new GraphicBuffer objects.
+    sp<IGraphicBufferAlloc> mAllocator;
+
+    // mMutex is the mutex used to prevent concurrent access to the member
+    // variables of BufferQueueCore objects. It must be locked whenever any
+    // member variable is accessed.
+    mutable Mutex mMutex;
+
+    // mIsAbandoned indicates that the BufferQueue 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 BufferQueue that is abandoned will return
+    // the NO_INIT error from all IGraphicBufferProducer methods capable of
+    // returning an error.
+    bool mIsAbandoned;
+
+    // mConsumerControlledByApp indicates whether the connected consumer is
+    // controlled by the application.
+    bool mConsumerControlledByApp;
+
+    // mConsumerName is a string used to identify the BufferQueue in log
+    // messages. It is set by the IGraphicBufferConsumer::setConsumerName
+    // method.
+    String8 mConsumerName;
+
+    // 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;
+
+    // mConsumerUsageBits contains flags that the consumer wants for
+    // GraphicBuffers.
+    uint32_t mConsumerUsageBits;
+
+    // mConnectedApi indicates the producer API that is currently connected
+    // to this BufferQueue. It defaults to NO_CONNECTED_API, and gets updated
+    // by the connect and disconnect methods.
+    int mConnectedApi;
+
+    // mConnectedProducerToken is used to set a binder death notification on
+    // the producer.
+    sp<IBinder> mConnectedProducerToken;
+
+    // mSlots is an 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.
+    BufferQueueDefs::SlotsType mSlots;
+
+    // mQueue is a FIFO of queued buffers used in synchronous mode.
+    Fifo mQueue;
+
+    // mOverrideMaxBufferCount is the limit on the number of buffers that will
+    // be allocated at one time. This value is set by the producer by calling
+    // setBufferCount. The default is 0, which means that the producer doesn't
+    // care about the number of buffers in the pool. In that case,
+    // mDefaultMaxBufferCount is used as the limit.
+    int mOverrideMaxBufferCount;
+
+    // mDequeueCondition is a condition variable used for dequeueBuffer in
+    // synchronous mode.
+    mutable Condition mDequeueCondition;
+
+    // mUseAsyncBuffer indicates whether an extra buffer is used in async mode
+    // to prevent dequeueBuffer from blocking.
+    bool mUseAsyncBuffer;
+
+    // mDequeueBufferCannotBlock indicates whether dequeueBuffer is allowed to
+    // block. This flag is set during connect when both the producer and
+    // consumer are controlled by the application.
+    bool mDequeueBufferCannotBlock;
+
+    // mDefaultBufferFormat can be set so it will override the buffer format
+    // when it isn't specified in dequeueBuffer.
+    uint32_t mDefaultBufferFormat;
+
+    // mDefaultWidth holds the default width of allocated buffers. It is used
+    // in dequeueBuffer if a width and height of 0 are specified.
+    int mDefaultWidth;
+
+    // mDefaultHeight holds the default height of allocated buffers. It is used
+    // in dequeueBuffer if a width and height of 0 are specified.
+    int mDefaultHeight;
+
+    // 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 overriden by the
+    // producer.
+    int mDefaultMaxBufferCount;
+
+    // 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 setMaxAcquiredBufferCount, but this may only be done while no
+    // producer is connected to the BufferQueue. This value is used to derive
+    // the value returned for the MIN_UNDEQUEUED_BUFFERS query to the producer.
+    int mMaxAcquiredBufferCount;
+
+    // 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;
+
+    // mFrameCounter is the free running counter, incremented on every
+    // successful queueBuffer call and buffer allocation.
+    uint64_t mFrameCounter;
+
+    // mTransformHint is used to optimize for screen rotations.
+    uint32_t mTransformHint;
+
+    // mSidebandStream is a handle to the sideband buffer stream, if any
+    sp<NativeHandle> mSidebandStream;
+
+}; // class BufferQueueCore
+
+} // namespace android
+
+#endif
diff --git a/include/gui/BufferQueueDefs.h b/include/gui/BufferQueueDefs.h
new file mode 100644
index 0000000..bccc881
--- /dev/null
+++ b/include/gui/BufferQueueDefs.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2014 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_BUFFERQUEUECOREDEFS_H
+#define ANDROID_GUI_BUFFERQUEUECOREDEFS_H
+
+#include <gui/BufferSlot.h>
+
+namespace android {
+    class BufferQueueCore;
+
+    namespace BufferQueueDefs {
+        // BufferQueue will keep track of at most this value of buffers.
+        // Attempts at runtime to increase the number of buffers past this
+        // will fail.
+        enum { NUM_BUFFER_SLOTS = 32 };
+
+        typedef BufferSlot SlotsType[NUM_BUFFER_SLOTS];
+    } // namespace BufferQueueDefs
+} // namespace android
+
+#endif
diff --git a/include/gui/BufferQueueProducer.h b/include/gui/BufferQueueProducer.h
new file mode 100644
index 0000000..0013b0a
--- /dev/null
+++ b/include/gui/BufferQueueProducer.h
@@ -0,0 +1,194 @@
+/*
+ * Copyright 2014 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_BUFFERQUEUEPRODUCER_H
+#define ANDROID_GUI_BUFFERQUEUEPRODUCER_H
+
+#include <gui/BufferQueueDefs.h>
+#include <gui/IGraphicBufferProducer.h>
+
+namespace android {
+
+class BufferSlot;
+
+class BufferQueueProducer : public BnGraphicBufferProducer,
+                            private IBinder::DeathRecipient {
+public:
+    friend class BufferQueue; // Needed to access binderDied
+
+    BufferQueueProducer(const sp<BufferQueueCore>& core);
+    virtual ~BufferQueueProducer();
+
+    // 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);
+
+    // setBufferCount updates the number of available buffer slots.  If this
+    // method succeeds, buffer slots will be both unallocated and owned by
+    // the BufferQueue 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 (exclusive) 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);
+
+    // 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 outFence 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 *outSlot, sp<Fence>* outFence, bool async,
+            uint32_t width, uint32_t height, uint32_t format, uint32_t usage);
+
+    // See IGraphicBufferProducer::detachBuffer
+    virtual status_t detachBuffer(int slot);
+
+    // See IGraphicBufferProducer::attachBuffer
+    virtual status_t attachBuffer(int* outSlot, const sp<GraphicBuffer>& buffer);
+
+    // queueBuffer returns a filled buffer to the BufferQueue.
+    //
+    // 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 slot,
+            const QueueBufferInput& input, QueueBufferOutput* output);
+
+    // cancelBuffer returns a dequeued buffer to the BufferQueue, 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 slot, const sp<Fence>& fence);
+
+    // Query native window attributes.  The "what" values are enumerated in
+    // window.h (e.g. NATIVE_WINDOW_FORMAT).
+    virtual int query(int what, int* outValue);
+
+    // connect attempts to connect a producer API to the BufferQueue.  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
+    // BufferQueue 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 BufferQueue.
+    // 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 BufferQueue is not currently
+    // connected to the specified producer API.
+    virtual status_t disconnect(int api);
+
+    // Attaches a sideband buffer stream to the IGraphicBufferProducer.
+    //
+    // A sideband stream is a device-specific mechanism for passing buffers
+    // from the producer to the consumer without using dequeueBuffer/
+    // queueBuffer. If a sideband stream is present, the consumer can choose
+    // whether to acquire buffers from the sideband stream or from the queued
+    // buffers.
+    //
+    // Passing NULL or a different stream handle will detach the previous
+    // handle if any.
+    virtual status_t setSidebandStream(const sp<NativeHandle>& stream);
+
+private:
+    // This is required by the IBinder::DeathRecipient interface
+    virtual void binderDied(const wp<IBinder>& who);
+
+    // waitForFreeSlotThenRelock finds the oldest slot in the FREE state. It may
+    // block if there are no available slots and we are not in non-blocking
+    // mode (producer and consumer controlled by the application). If it blocks,
+    // it will release mCore->mMutex while blocked so that other operations on
+    // the BufferQueue may succeed.
+    status_t waitForFreeSlotThenRelock(const char* caller, bool async,
+            int* found, status_t* returnFlags) const;
+
+    sp<BufferQueueCore> mCore;
+
+    // This references mCore->mSlots. Lock mCore->mMutex while accessing.
+    BufferQueueDefs::SlotsType& mSlots;
+
+    // This is a cached copy of the name stored in the BufferQueueCore.
+    // It's updated during connect and dequeueBuffer (which should catch
+    // most updates).
+    String8 mConsumerName;
+
+}; // class BufferQueueProducer
+
+} // namespace android
+
+#endif
diff --git a/include/gui/BufferSlot.h b/include/gui/BufferSlot.h
new file mode 100644
index 0000000..6085e11
--- /dev/null
+++ b/include/gui/BufferSlot.h
@@ -0,0 +1,142 @@
+/*
+ * Copyright 2014 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_BUFFERSLOT_H
+#define ANDROID_GUI_BUFFERSLOT_H
+
+#include <ui/Fence.h>
+#include <ui/GraphicBuffer.h>
+
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
+
+#include <utils/StrongPointer.h>
+
+namespace android {
+
+class Fence;
+
+struct BufferSlot {
+
+    BufferSlot()
+    : mEglDisplay(EGL_NO_DISPLAY),
+      mBufferState(BufferSlot::FREE),
+      mRequestBufferCalled(false),
+      mFrameNumber(0),
+      mEglFence(EGL_NO_SYNC_KHR),
+      mAcquireCalled(false),
+      mNeedsCleanupOnRelease(false),
+      mAttachedByConsumer(false) {
+    }
+
+    // mGraphicBuffer points to the buffer allocated for this slot or is NULL
+    // if no buffer has been allocated.
+    sp<GraphicBuffer> mGraphicBuffer;
+
+    // mEglDisplay is the EGLDisplay used to create EGLSyncKHR objects.
+    EGLDisplay mEglDisplay;
+
+    // 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 BufferQueue.  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 BufferQueue.  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
+    };
+
+    static const char* bufferStateName(BufferState state);
+
+    // 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;
+
+    // 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;
+
+    // Indicates whether the buffer was attached on the consumer side.
+    // If so, it needs to set the BUFFER_NEEDS_REALLOCATION flag when dequeued
+    // to prevent the producer from using a stale cached buffer.
+    bool mAttachedByConsumer;
+};
+
+} // namespace android
+
+#endif
diff --git a/include/gui/ConsumerBase.h b/include/gui/ConsumerBase.h
index fb21185..100bb26 100644
--- a/include/gui/ConsumerBase.h
+++ b/include/gui/ConsumerBase.h
@@ -101,11 +101,14 @@
 
     // Implementation of the IConsumerListener interface.  These
     // calls are used to notify the ConsumerBase of asynchronous events in the
-    // BufferQueue.  These methods should not need to be overridden by derived
-    // classes, but if they are overridden the ConsumerBase implementation
-    // must be called from the derived class.
+    // BufferQueue.  The onFrameAvailable and onBuffersReleased methods should
+    // not need to be overridden by derived classes, but if they are overridden
+    // the ConsumerBase implementation must be called from the derived class.
+    // The ConsumerBase version of onSidebandStreamChanged does nothing and can
+    // be overriden by derived classes if they want the notification.
     virtual void onFrameAvailable();
     virtual void onBuffersReleased();
+    virtual void onSidebandStreamChanged();
 
     // freeBufferLocked frees up the given buffer slot.  If the slot has been
     // initialized this will release the reference to the GraphicBuffer in that
diff --git a/include/gui/IConsumerListener.h b/include/gui/IConsumerListener.h
index ac2f9bb..260099e 100644
--- a/include/gui/IConsumerListener.h
+++ b/include/gui/IConsumerListener.h
@@ -57,6 +57,12 @@
     // This is called without any lock held and can be called concurrently
     // by multiple threads.
     virtual void onBuffersReleased() = 0; /* Asynchronous */
+
+    // onSidebandStreamChanged is called to notify the buffer consumer that the
+    // BufferQueue's sideband buffer stream has changed. This is called when a
+    // stream is first attached and when it is either detached or replaced by a
+    // different stream.
+    virtual void onSidebandStreamChanged() = 0; /* Asynchronous */
 };
 
 
diff --git a/include/gui/IGraphicBufferConsumer.h b/include/gui/IGraphicBufferConsumer.h
index 9a6645c..b0d4c76 100644
--- a/include/gui/IGraphicBufferConsumer.h
+++ b/include/gui/IGraphicBufferConsumer.h
@@ -30,9 +30,10 @@
 namespace android {
 // ----------------------------------------------------------------------------
 
-class IConsumerListener;
-class GraphicBuffer;
 class Fence;
+class GraphicBuffer;
+class IConsumerListener;
+class NativeHandle;
 
 class IGraphicBufferConsumer : public IInterface {
 
@@ -139,6 +140,36 @@
     // * INVALID_OPERATION - too many buffers have been acquired
     virtual status_t acquireBuffer(BufferItem* buffer, nsecs_t presentWhen) = 0;
 
+    // detachBuffer attempts to remove all ownership of the buffer in the given
+    // slot from the buffer queue. If this call succeeds, the slot will be
+    // freed, and there will be no way to obtain the buffer from this interface.
+    // The freed slot will remain unallocated until either it is selected to
+    // hold a freshly allocated buffer in dequeueBuffer or a buffer is attached
+    // to the slot. The buffer must have already been acquired.
+    //
+    // Return of a value other than NO_ERROR means an error has occurred:
+    // * BAD_VALUE - the given slot number is invalid, either because it is
+    //               out of the range [0, NUM_BUFFER_SLOTS) or because the slot
+    //               it refers to is not currently acquired.
+    virtual status_t detachBuffer(int slot) = 0;
+
+    // attachBuffer attempts to transfer ownership of a buffer to the buffer
+    // queue. If this call succeeds, it will be as if this buffer was acquired
+    // from the returned slot number. As such, this call will fail if attaching
+    // this buffer would cause too many buffers to be simultaneously acquired.
+    //
+    // If the buffer is successfully attached, its frameNumber is initialized
+    // to 0. This must be passed into the releaseBuffer call or else the buffer
+    // will be deallocated as stale.
+    //
+    // Return of a value other than NO_ERROR means an error has occurred:
+    // * BAD_VALUE - outSlot or buffer were NULL
+    // * INVALID_OPERATION - cannot attach the buffer because it would cause too
+    //                       many buffers to be acquired.
+    // * NO_MEMORY - no free slots available
+    virtual status_t attachBuffer(int *outSlot,
+            const sp<GraphicBuffer>& buffer) = 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
@@ -266,6 +297,9 @@
     // Return of a value other than NO_ERROR means an unknown error has occurred.
     virtual status_t setTransformHint(uint32_t hint) = 0;
 
+    // Retrieve the sideband buffer stream, if any.
+    virtual sp<NativeHandle> getSidebandStream() const = 0;
+
     // dump state into a string
     virtual void dump(String8& result, const char* prefix) const = 0;
 
diff --git a/include/gui/IGraphicBufferProducer.h b/include/gui/IGraphicBufferProducer.h
index 7002530..0874f03 100644
--- a/include/gui/IGraphicBufferProducer.h
+++ b/include/gui/IGraphicBufferProducer.h
@@ -32,6 +32,7 @@
 namespace android {
 // ----------------------------------------------------------------------------
 
+class NativeHandle;
 class Surface;
 
 /*
@@ -150,12 +151,14 @@
     //
     // Return of a negative means an error has occurred:
     // * NO_INIT - the buffer queue has been abandoned.
-    // * BAD_VALUE - one of the below conditions occurred:
-    //              * both in async mode and buffer count was less than the
-    //                max numbers of buffers that can be allocated at once
-    //              * attempting dequeue more than one buffer at a time
-    //                without setting the buffer count with setBufferCount()
-    // * -EBUSY - attempting to dequeue too many buffers at a time
+    // * BAD_VALUE - both in async mode and buffer count was less than the
+    //               max numbers of buffers that can be allocated at once.
+    // * INVALID_OPERATION - cannot attach the buffer because it would cause
+    //                       too many buffers to be dequeued, either because
+    //                       the producer already has a single buffer dequeued
+    //                       and did not set a buffer count, or because a
+    //                       buffer count was set and this call would cause
+    //                       it to be exceeded.
     // * WOULD_BLOCK - no buffer is currently available, and blocking is disabled
     //                 since both the producer/consumer are controlled by app
     // * NO_MEMORY - out of memory, cannot allocate the graphics buffer.
@@ -165,6 +168,49 @@
     virtual status_t dequeueBuffer(int* slot, sp<Fence>* fence, bool async,
             uint32_t w, uint32_t h, uint32_t format, uint32_t usage) = 0;
 
+    // detachBuffer attempts to remove all ownership of the buffer in the given
+    // slot from the buffer queue. If this call succeeds, the slot will be
+    // freed, and there will be no way to obtain the buffer from this interface.
+    // The freed slot will remain unallocated until either it is selected to
+    // hold a freshly allocated buffer in dequeueBuffer or a buffer is attached
+    // to the slot. The buffer must have already been dequeued, and the caller
+    // must already possesses the sp<GraphicBuffer> (i.e., must have called
+    // requestBuffer).
+    //
+    // Return of a value other than NO_ERROR means an error has occurred:
+    // * NO_INIT - the buffer queue has been abandoned.
+    // * BAD_VALUE - the given slot number is invalid, either because it is
+    //               out of the range [0, NUM_BUFFER_SLOTS), or because the slot
+    //               it refers to is not currently dequeued and requested.
+    virtual status_t detachBuffer(int slot) = 0;
+
+    // attachBuffer attempts to transfer ownership of a buffer to the buffer
+    // queue. If this call succeeds, it will be as if this buffer was dequeued
+    // from the returned slot number. As such, this call will fail if attaching
+    // this buffer would cause too many buffers to be simultaneously dequeued.
+    //
+    // If attachBuffer returns the RELEASE_ALL_BUFFERS flag, the caller is
+    // expected to release all of the mirrored slot->buffer mappings.
+    //
+    // A non-negative value with flags set (see above) will be returned upon
+    // success.
+    //
+    // Return of a negative value means an error has occurred:
+    // * NO_INIT - the buffer queue has been abandoned.
+    // * BAD_VALUE - outSlot or buffer were NULL or invalid combination of
+    //               async mode and buffer count override.
+    // * INVALID_OPERATION - cannot attach the buffer because it would cause
+    //                       too many buffers to be dequeued, either because
+    //                       the producer already has a single buffer dequeued
+    //                       and did not set a buffer count, or because a
+    //                       buffer count was set and this call would cause
+    //                       it to be exceeded.
+    // * WOULD_BLOCK - no buffer slot is currently available, and blocking is
+    //                 disabled since both the producer/consumer are
+    //                 controlled by the app.
+    virtual status_t attachBuffer(int* outSlot,
+            const sp<GraphicBuffer>& buffer) = 0;
+
     // queueBuffer indicates that the client has finished filling in the
     // contents of the buffer associated with slot and transfers ownership of
     // that slot back to the server.
@@ -347,6 +393,18 @@
     //             * api was out of range (see above).
     // * DEAD_OBJECT - the token is hosted by an already-dead process
     virtual status_t disconnect(int api) = 0;
+
+    // Attaches a sideband buffer stream to the IGraphicBufferProducer.
+    //
+    // A sideband stream is a device-specific mechanism for passing buffers
+    // from the producer to the consumer without using dequeueBuffer/
+    // queueBuffer. If a sideband stream is present, the consumer can choose
+    // whether to acquire buffers from the sideband stream or from the queued
+    // buffers.
+    //
+    // Passing NULL or a different stream handle will detach the previous
+    // handle if any.
+    virtual status_t setSidebandStream(const sp<NativeHandle>& stream) = 0;
 };
 
 // ----------------------------------------------------------------------------
diff --git a/include/gui/Surface.h b/include/gui/Surface.h
index 6f8a97c..d8e9756 100644
--- a/include/gui/Surface.h
+++ b/include/gui/Surface.h
@@ -78,6 +78,19 @@
         return surface != NULL && surface->getIGraphicBufferProducer() != NULL;
     }
 
+    /* Attaches a sideband buffer stream to the Surface's IGraphicBufferProducer.
+     *
+     * A sideband stream is a device-specific mechanism for passing buffers
+     * from the producer to the consumer without using dequeueBuffer/
+     * queueBuffer. If a sideband stream is present, the consumer can choose
+     * whether to acquire buffers from the sideband stream or from the queued
+     * buffers.
+     *
+     * Passing NULL or a different stream handle will detach the previous
+     * handle if any.
+     */
+    void setSidebandStream(const sp<NativeHandle>& stream);
+
 protected:
     virtual ~Surface();
 
diff --git a/include/input/KeycodeLabels.h b/include/input/KeycodeLabels.h
index 19582e9..a8d63da 100644
--- a/include/input/KeycodeLabels.h
+++ b/include/input/KeycodeLabels.h
@@ -247,6 +247,8 @@
     { "BRIGHTNESS_DOWN", 220 },
     { "BRIGHTNESS_UP", 221 },
     { "MEDIA_AUDIO_TRACK", 222 },
+    { "SLEEP", 223 },
+    { "WAKEUP", 224 },
 
     // NOTE: If you add a new keycode here you must also add it to several other files.
     //       Refer to frameworks/base/core/java/android/view/KeyEvent.java for the full list.
diff --git a/include/media/openmax/OMX_AudioExt.h b/include/media/openmax/OMX_AudioExt.h
index aa6e6d0..dc6457b 100644
--- a/include/media/openmax/OMX_AudioExt.h
+++ b/include/media/openmax/OMX_AudioExt.h
@@ -43,6 +43,7 @@
 typedef enum OMX_AUDIO_CODINGEXTTYPE {
     OMX_AUDIO_CodingAndroidUnused = OMX_AUDIO_CodingKhronosExtensions + 0x00100000,
     OMX_AUDIO_CodingAndroidAC3,         /**< AC3 encoded data */
+    OMX_AUDIO_CodingAndroidOPUS,        /**< OPUS encoded data */
 } OMX_AUDIO_CODINGEXTTYPE;
 
 typedef struct OMX_AUDIO_PARAM_ANDROID_AC3TYPE {
@@ -54,6 +55,20 @@
                                         variable or unknown sampling rate. */
 } OMX_AUDIO_PARAM_ANDROID_AC3TYPE;
 
+typedef struct OMX_AUDIO_PARAM_ANDROID_OPUSTYPE {
+    OMX_U32 nSize;            /**< size of the structure in bytes */
+    OMX_VERSIONTYPE nVersion; /**< OMX specification version information */
+    OMX_U32 nPortIndex;       /**< port that this structure applies to */
+    OMX_U32 nChannels;        /**< Number of channels */
+    OMX_U32 nBitRate;         /**< Bit rate of the encoded data data.  Use 0 for variable
+                                   rate or unknown bit rates. Encoding is set to the
+                                   bitrate closest to specified  value (in bps) */
+    OMX_U32 nSampleRate;      /**< Sampling rate of the source data.  Use 0 for
+                                   variable or unknown sampling rate. */
+    OMX_U32 nAudioBandWidth;  /**< Audio band width (in Hz) to which an encoder should
+                                   limit the audio signal. Use 0 to let encoder decide */
+} OMX_AUDIO_PARAM_ANDROID_OPUSTYPE;
+
 #ifdef __cplusplus
 }
 #endif /* __cplusplus */
diff --git a/include/media/openmax/OMX_IndexExt.h b/include/media/openmax/OMX_IndexExt.h
index c47a885..ffcd4f3 100644
--- a/include/media/openmax/OMX_IndexExt.h
+++ b/include/media/openmax/OMX_IndexExt.h
@@ -58,6 +58,7 @@
     /* Audio parameters and configurations */
     OMX_IndexExtAudioStartUnused = OMX_IndexKhronosExtensions + 0x00400000,
     OMX_IndexParamAudioAndroidAc3,                  /**< reference: OMX_AUDIO_PARAM_ANDROID_AC3TYPE */
+    OMX_IndexParamAudioAndroidOpus,                 /**< reference: OMX_AUDIO_PARAM_ANDROID_OPUSTYPE */
 
     /* Image parameters and configurations */
     OMX_IndexExtImageStartUnused = OMX_IndexKhronosExtensions + 0x00500000,
diff --git a/include/ui/FramebufferNativeWindow.h b/include/ui/FramebufferNativeWindow.h
index 5ec738f..5cd8101 100644
--- a/include/ui/FramebufferNativeWindow.h
+++ b/include/ui/FramebufferNativeWindow.h
@@ -17,6 +17,8 @@
 #ifndef ANDROID_FRAMEBUFFER_NATIVE_WINDOW_H
 #define ANDROID_FRAMEBUFFER_NATIVE_WINDOW_H
 
+#warning "FramebufferNativeWindow is deprecated"
+
 #include <stdint.h>
 #include <sys/types.h>
 
diff --git a/libs/binder/Parcel.cpp b/libs/binder/Parcel.cpp
index a38e3dd..4298522 100644
--- a/libs/binder/Parcel.cpp
+++ b/libs/binder/Parcel.cpp
@@ -631,6 +631,16 @@
     }
     return ret;
 }
+status_t Parcel::writeByteArray(size_t len, const uint8_t *val) {
+    if (!val) {
+        return writeAligned(-1);
+    }
+    status_t ret = writeAligned(len);
+    if (ret == NO_ERROR) {
+        ret = write(val, len * sizeof(*val));
+    }
+    return ret;
+}
 
 status_t Parcel::writeInt64(int64_t val)
 {
@@ -933,7 +943,8 @@
 
 status_t Parcel::read(void* outData, size_t len) const
 {
-    if ((mDataPos+PAD_SIZE(len)) >= mDataPos && (mDataPos+PAD_SIZE(len)) <= mDataSize) {
+    if ((mDataPos+PAD_SIZE(len)) >= mDataPos && (mDataPos+PAD_SIZE(len)) <= mDataSize
+            && len <= PAD_SIZE(len)) {
         memcpy(outData, mData+mDataPos, len);
         mDataPos += PAD_SIZE(len);
         ALOGV("read Setting data pos of %p to %d\n", this, mDataPos);
@@ -944,7 +955,8 @@
 
 const void* Parcel::readInplace(size_t len) const
 {
-    if ((mDataPos+PAD_SIZE(len)) >= mDataPos && (mDataPos+PAD_SIZE(len)) <= mDataSize) {
+    if ((mDataPos+PAD_SIZE(len)) >= mDataPos && (mDataPos+PAD_SIZE(len)) <= mDataSize
+            && len <= PAD_SIZE(len)) {
         const void* data = mData+mDataPos;
         mDataPos += PAD_SIZE(len);
         ALOGV("readInplace Setting data pos of %p to %d\n", this, mDataPos);
diff --git a/libs/gui/Android.mk b/libs/gui/Android.mk
index c14c950..0a77317 100644
--- a/libs/gui/Android.mk
+++ b/libs/gui/Android.mk
@@ -5,8 +5,13 @@
 	IGraphicBufferConsumer.cpp \
 	IConsumerListener.cpp \
 	BitTube.cpp \
+	BufferItem.cpp \
 	BufferItemConsumer.cpp \
 	BufferQueue.cpp \
+	BufferQueueConsumer.cpp \
+	BufferQueueCore.cpp \
+	BufferQueueProducer.cpp \
+	BufferSlot.cpp \
 	ConsumerBase.cpp \
 	CpuConsumer.cpp \
 	DisplayEventReceiver.cpp \
diff --git a/libs/gui/BufferItem.cpp b/libs/gui/BufferItem.cpp
new file mode 100644
index 0000000..d3fa43e
--- /dev/null
+++ b/libs/gui/BufferItem.cpp
@@ -0,0 +1,192 @@
+/*
+ * Copyright 2014 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.
+ */
+
+#include <gui/BufferItem.h>
+
+#include <ui/Fence.h>
+#include <ui/GraphicBuffer.h>
+
+#include <system/window.h>
+
+namespace android {
+
+BufferItem::BufferItem() :
+    mTransform(0),
+    mScalingMode(NATIVE_WINDOW_SCALING_MODE_FREEZE),
+    mTimestamp(0),
+    mIsAutoTimestamp(false),
+    mFrameNumber(0),
+    mSlot(INVALID_BUFFER_SLOT),
+    mIsDroppable(false),
+    mAcquireCalled(false),
+    mTransformToDisplayInverse(false) {
+    mCrop.makeInvalid();
+}
+
+BufferItem::operator IGraphicBufferConsumer::BufferItem() const {
+    IGraphicBufferConsumer::BufferItem bufferItem;
+    bufferItem.mGraphicBuffer = mGraphicBuffer;
+    bufferItem.mFence = mFence;
+    bufferItem.mCrop = mCrop;
+    bufferItem.mTransform = mTransform;
+    bufferItem.mScalingMode = mScalingMode;
+    bufferItem.mTimestamp = mTimestamp;
+    bufferItem.mIsAutoTimestamp = mIsAutoTimestamp;
+    bufferItem.mFrameNumber = mFrameNumber;
+    bufferItem.mBuf = mSlot;
+    bufferItem.mIsDroppable = mIsDroppable;
+    bufferItem.mAcquireCalled = mAcquireCalled;
+    bufferItem.mTransformToDisplayInverse = mTransformToDisplayInverse;
+    return bufferItem;
+}
+
+size_t BufferItem::getPodSize() const {
+    size_t c =  sizeof(mCrop) +
+            sizeof(mTransform) +
+            sizeof(mScalingMode) +
+            sizeof(mTimestamp) +
+            sizeof(mIsAutoTimestamp) +
+            sizeof(mFrameNumber) +
+            sizeof(mSlot) +
+            sizeof(mIsDroppable) +
+            sizeof(mAcquireCalled) +
+            sizeof(mTransformToDisplayInverse);
+    return c;
+}
+
+size_t 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 BufferItem::getFdCount() const {
+    size_t c = 0;
+    if (mGraphicBuffer != 0) {
+        c += mGraphicBuffer->getFdCount();
+    }
+    if (mFence != 0) {
+        c += mFence->getFdCount();
+    }
+    return c;
+}
+
+status_t 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, mSlot);
+    FlattenableUtils::write(buffer, size, mIsDroppable);
+    FlattenableUtils::write(buffer, size, mAcquireCalled);
+    FlattenableUtils::write(buffer, size, mTransformToDisplayInverse);
+
+    return NO_ERROR;
+}
+
+status_t 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, mSlot);
+    FlattenableUtils::read(buffer, size, mIsDroppable);
+    FlattenableUtils::read(buffer, size, mAcquireCalled);
+    FlattenableUtils::read(buffer, size, mTransformToDisplayInverse);
+
+    return NO_ERROR;
+}
+
+const char* BufferItem::scalingModeName(uint32_t 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";
+    }
+}
+
+} // namespace android
diff --git a/libs/gui/BufferQueue.cpp b/libs/gui/BufferQueue.cpp
index 2fa0433..c306f9d 100644
--- a/libs/gui/BufferQueue.cpp
+++ b/libs/gui/BufferQueue.cpp
@@ -18,1217 +18,11 @@
 #define ATRACE_TAG ATRACE_TAG_GRAPHICS
 //#define LOG_NDEBUG 0
 
-#define GL_GLEXT_PROTOTYPES
-#define EGL_EGLEXT_PROTOTYPES
-
-#include <EGL/egl.h>
-#include <EGL/eglext.h>
-
 #include <gui/BufferQueue.h>
-#include <gui/IConsumerListener.h>
-#include <gui/ISurfaceComposer.h>
-#include <private/gui/ComposerService.h>
-
-#include <utils/Log.h>
-#include <utils/Trace.h>
-
-// Macros for including the BufferQueue name in log messages
-#define ST_LOGV(x, ...) ALOGV("[%s] "x, mConsumerName.string(), ##__VA_ARGS__)
-#define ST_LOGD(x, ...) ALOGD("[%s] "x, mConsumerName.string(), ##__VA_ARGS__)
-#define ST_LOGI(x, ...) ALOGI("[%s] "x, mConsumerName.string(), ##__VA_ARGS__)
-#define ST_LOGW(x, ...) ALOGW("[%s] "x, mConsumerName.string(), ##__VA_ARGS__)
-#define ST_LOGE(x, ...) ALOGE("[%s] "x, mConsumerName.string(), ##__VA_ARGS__)
-
-#define ATRACE_BUFFER_INDEX(index)                                            \
-    if (ATRACE_ENABLED()) {                                                   \
-        char ___traceBuf[1024];                                               \
-        snprintf(___traceBuf, 1024, "%s: %d", mConsumerName.string(),         \
-                (index));                                                     \
-        android::ScopedTrace ___bufTracer(ATRACE_TAG, ___traceBuf);           \
-    }
+#include <gui/BufferQueueCore.h>
 
 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";
-    }
-}
-
-BufferQueue::BufferQueue(const sp<IGraphicBufferAlloc>& allocator) :
-    mDefaultWidth(1),
-    mDefaultHeight(1),
-    mMaxAcquiredBufferCount(1),
-    mDefaultMaxBufferCount(2),
-    mOverrideMaxBufferCount(0),
-    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)
-{
-    // Choose a name using the PID and a process-unique ID.
-    mConsumerName = String8::format("unnamed-%d-%d", getpid(), createProcessUniqueId());
-
-    ST_LOGV("BufferQueue");
-    if (allocator == NULL) {
-        sp<ISurfaceComposer> composer(ComposerService::getComposerService());
-        mGraphicBufferAlloc = composer->createGraphicBufferAlloc();
-        if (mGraphicBufferAlloc == 0) {
-            ST_LOGE("createGraphicBufferAlloc() failed in BufferQueue()");
-        }
-    } else {
-        mGraphicBufferAlloc = allocator;
-    }
-}
-
-BufferQueue::~BufferQueue() {
-    ST_LOGV("~BufferQueue");
-}
-
-status_t BufferQueue::setDefaultMaxBufferCountLocked(int count) {
-    const int minBufferCount = mUseAsyncBuffer ? 2 : 1;
-    if (count < minBufferCount || count > NUM_BUFFER_SLOTS)
-        return BAD_VALUE;
-
-    mDefaultMaxBufferCount = count;
-    mDequeueCondition.broadcast();
-
-    return NO_ERROR;
-}
-
-void BufferQueue::setConsumerName(const String8& name) {
-    Mutex::Autolock lock(mMutex);
-    mConsumerName = name;
-}
-
-status_t BufferQueue::setDefaultBufferFormat(uint32_t defaultFormat) {
-    Mutex::Autolock lock(mMutex);
-    mDefaultBufferFormat = defaultFormat;
-    return NO_ERROR;
-}
-
-status_t BufferQueue::setConsumerUsageBits(uint32_t usage) {
-    Mutex::Autolock lock(mMutex);
-    mConsumerUsageBits = usage;
-    return NO_ERROR;
-}
-
-status_t BufferQueue::setTransformHint(uint32_t hint) {
-    ST_LOGV("setTransformHint: %02x", hint);
-    Mutex::Autolock lock(mMutex);
-    mTransformHint = hint;
-    return NO_ERROR;
-}
-
-status_t BufferQueue::setBufferCount(int bufferCount) {
-    ST_LOGV("setBufferCount: count=%d", bufferCount);
-
-    sp<IConsumerListener> listener;
-    {
-        Mutex::Autolock lock(mMutex);
-
-        if (mAbandoned) {
-            ST_LOGE("setBufferCount: BufferQueue 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.
-        freeAllBuffersLocked();
-        mOverrideMaxBufferCount = bufferCount;
-        mDequeueCondition.broadcast();
-        listener = mConsumerListener;
-    } // scope for lock
-
-    if (listener != NULL) {
-        listener->onBuffersReleased();
-    }
-
-    return NO_ERROR;
-}
-
-int BufferQueue::query(int what, int* outValue)
-{
-    ATRACE_CALL();
-    Mutex::Autolock lock(mMutex);
-
-    if (outValue == NULL) {
-        ST_LOGE("query: outValue was NULL");
-        return BAD_VALUE;
-    }
-
-    if (mAbandoned) {
-        ST_LOGE("query: BufferQueue 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 BufferQueue::requestBuffer(int slot, sp<GraphicBuffer>* buf) {
-    ATRACE_CALL();
-    ST_LOGV("requestBuffer: slot=%d", slot);
-    Mutex::Autolock lock(mMutex);
-    if (mAbandoned) {
-        ST_LOGE("requestBuffer: BufferQueue 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 BufferQueue::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);
-    EGLDisplay dpy = EGL_NO_DISPLAY;
-    EGLSyncKHR eglFence = EGL_NO_SYNC_KHR;
-
-    { // Scope for the lock
-        Mutex::Autolock lock(mMutex);
-
-        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: BufferQueue 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;
-        }
-
-        const int buf = found;
-        *outBuf = found;
-
-        ATRACE_BUFFER_INDEX(buf);
-
-        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].mEglFence = EGL_NO_SYNC_KHR;
-            mSlots[buf].mFence = Fence::NO_FENCE;
-            mSlots[buf].mEglDisplay = EGL_NO_DISPLAY;
-
-            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);
-        }
-
-        dpy = mSlots[buf].mEglDisplay;
-        eglFence = mSlots[buf].mEglFence;
-        *outFence = mSlots[buf].mFence;
-        mSlots[buf].mEglFence = EGL_NO_SYNC_KHR;
-        mSlots[buf].mFence = Fence::NO_FENCE;
-    }  // end lock scope
-
-    if (returnFlags & IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION) {
-        status_t error;
-        sp<GraphicBuffer> graphicBuffer(
-                mGraphicBufferAlloc->createGraphicBuffer(w, h, format, usage, &error));
-        if (graphicBuffer == 0) {
-            ST_LOGE("dequeueBuffer: SurfaceComposer::createGraphicBuffer failed");
-            return error;
-        }
-
-        { // Scope for the lock
-            Mutex::Autolock lock(mMutex);
-
-            if (mAbandoned) {
-                ST_LOGE("dequeueBuffer: BufferQueue has been abandoned!");
-                return NO_INIT;
-            }
-
-            mSlots[*outBuf].mFrameNumber = ~0;
-            mSlots[*outBuf].mGraphicBuffer = graphicBuffer;
-        }
-    }
-
-    if (eglFence != EGL_NO_SYNC_KHR) {
-        EGLint result = eglClientWaitSyncKHR(dpy, eglFence, 0, 1000000000);
-        // If something goes wrong, log the error, but return the buffer without
-        // synchronizing access to it.  It's too late at this point to abort the
-        // dequeue operation.
-        if (result == EGL_FALSE) {
-            ST_LOGE("dequeueBuffer: error waiting for fence: %#x", eglGetError());
-        } else if (result == EGL_TIMEOUT_EXPIRED_KHR) {
-            ST_LOGE("dequeueBuffer: timeout waiting for fence");
-        }
-        eglDestroySyncKHR(dpy, eglFence);
-    }
-
-    ST_LOGV("dequeueBuffer: returning slot=%d/%llu buf=%p flags=%#x", *outBuf,
-            mSlots[*outBuf].mFrameNumber,
-            mSlots[*outBuf].mGraphicBuffer->handle, returnFlags);
-
-    return returnFlags;
-}
-
-status_t BufferQueue::queueBuffer(int buf,
-        const QueueBufferInput& input, QueueBufferOutput* output) {
-    ATRACE_CALL();
-    ATRACE_BUFFER_INDEX(buf);
-
-    Rect crop;
-    uint32_t transform;
-    int scalingMode;
-    int64_t timestamp;
-    bool isAutoTimestamp;
-    bool async;
-    sp<Fence> fence;
-
-    input.deflate(&timestamp, &isAutoTimestamp, &crop, &scalingMode, &transform,
-            &async, &fence);
-
-    if (fence == NULL) {
-        ST_LOGE("queueBuffer: fence is NULL");
-        return BAD_VALUE;
-    }
-
-    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: BufferQueue 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());
-
-        ATRACE_INT(mConsumerName.string(), mQueue.size());
-    } // scope for the lock
-
-    // call back without lock held
-    if (listener != 0) {
-        listener->onFrameAvailable();
-    }
-    return NO_ERROR;
-}
-
-void BufferQueue::cancelBuffer(int buf, const sp<Fence>& fence) {
-    ATRACE_CALL();
-    ST_LOGV("cancelBuffer: slot=%d", buf);
-    Mutex::Autolock lock(mMutex);
-
-    if (mAbandoned) {
-        ST_LOGW("cancelBuffer: BufferQueue 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 BufferQueue::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: BufferQueue has been abandoned!");
-        return NO_INIT;
-    }
-
-    if (mConsumerListener == NULL) {
-        ST_LOGE("connect: BufferQueue has no consumer!");
-        return NO_INIT;
-    }
-
-    if (output == NULL) {
-        ST_LOGE("connect: output was NULL");
-        return BAD_VALUE;
-    }
-
-    if (mConnectedApi != NO_CONNECTED_API) {
-        ST_LOGE("connect: already connected (cur=%d, req=%d)",
-                mConnectedApi, api);
-        return BAD_VALUE;
-    }
-
-    // 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 = BAD_VALUE;
-            break;
-    }
-
-    mBufferHasBeenQueued = false;
-    mDequeueBufferCannotBlock = mConsumerControlledByApp && producerControlledByApp;
-
-    return err;
-}
-
-void BufferQueue::binderDied(const wp<IBinder>& who __attribute__((unused))) {
-    // 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 BufferQueue::disconnect(int api) {
-    ATRACE_CALL();
-    ST_LOGV("disconnect: api=%d", api);
-
-    int err = NO_ERROR;
-    sp<IConsumerListener> listener;
-
-    { // 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();
-                    // remove our death notification callback if we have one
-                    sp<IBinder> token = mConnectedProducerToken;
-                    if (token != NULL) {
-                        // this can fail if we're here because of the death notification
-                        // either way, we just ignore.
-                        token->unlinkToDeath(static_cast<IBinder::DeathRecipient*>(this));
-                    }
-                    mConnectedProducerToken = NULL;
-                    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;
-        }
-    }
-
-    if (listener != NULL) {
-        listener->onBuffersReleased();
-    }
-
-    return err;
-}
-
-void BufferQueue::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 BufferQueue::freeBufferLocked(int slot) {
-    ST_LOGV("freeBufferLocked: slot=%d", slot);
-    mSlots[slot].mGraphicBuffer = 0;
-    if (mSlots[slot].mBufferState == BufferSlot::ACQUIRED) {
-        mSlots[slot].mNeedsCleanupOnRelease = true;
-    }
-    mSlots[slot].mBufferState = BufferSlot::FREE;
-    mSlots[slot].mFrameNumber = 0;
-    mSlots[slot].mAcquireCalled = false;
-
-    // destroy fence as BufferQueue now takes ownership
-    if (mSlots[slot].mEglFence != EGL_NO_SYNC_KHR) {
-        eglDestroySyncKHR(mSlots[slot].mEglDisplay, mSlots[slot].mEglFence);
-        mSlots[slot].mEglFence = EGL_NO_SYNC_KHR;
-    }
-    mSlots[slot].mFence = Fence::NO_FENCE;
-}
-
-void BufferQueue::freeAllBuffersLocked() {
-    mBufferHasBeenQueued = false;
-    for (int i = 0; i < NUM_BUFFER_SLOTS; i++) {
-        freeBufferLocked(i);
-    }
-}
-
-status_t BufferQueue::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 = *front;
-    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();
-
-    ATRACE_INT(mConsumerName.string(), mQueue.size());
-
-    return NO_ERROR;
-}
-
-status_t BufferQueue::releaseBuffer(
-        int buf, uint64_t frameNumber, EGLDisplay display,
-        EGLSyncKHR eglFence, const sp<Fence>& fence) {
-    ATRACE_CALL();
-    ATRACE_BUFFER_INDEX(buf);
-
-    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].mEglDisplay = display;
-        mSlots[buf].mEglFence = eglFence;
-        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 BufferQueue::consumerConnect(const sp<IConsumerListener>& consumerListener,
-        bool controlledByApp) {
-    ST_LOGV("consumerConnect controlledByApp=%s",
-            controlledByApp ? "true" : "false");
-    Mutex::Autolock lock(mMutex);
-
-    if (mAbandoned) {
-        ST_LOGE("consumerConnect: BufferQueue 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 BufferQueue::consumerDisconnect() {
-    ST_LOGV("consumerDisconnect");
-    Mutex::Autolock lock(mMutex);
-
-    if (mConsumerListener == NULL) {
-        ST_LOGE("consumerDisconnect: No consumer is connected!");
-        return -EINVAL;
-    }
-
-    mAbandoned = true;
-    mConsumerListener = NULL;
-    mQueue.clear();
-    freeAllBuffersLocked();
-    mDequeueCondition.broadcast();
-    return NO_ERROR;
-}
-
-status_t BufferQueue::getReleasedBuffers(uint32_t* slotMask) {
-    ST_LOGV("getReleasedBuffers");
-    Mutex::Autolock lock(mMutex);
-
-    if (mAbandoned) {
-        ST_LOGE("getReleasedBuffers: BufferQueue 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 BufferQueue::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 BufferQueue::setDefaultMaxBufferCount(int bufferCount) {
-    ATRACE_CALL();
-    Mutex::Autolock lock(mMutex);
-    return setDefaultMaxBufferCountLocked(bufferCount);
-}
-
-status_t BufferQueue::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 BufferQueue::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 BufferQueue::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 BufferQueue::getMinMaxBufferCountLocked(bool async) const {
-    return getMinUndequeuedBufferCount(async) + 1;
-}
-
-int BufferQueue::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 BufferQueue::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);
-}
-
 BufferQueue::ProxyConsumerListener::ProxyConsumerListener(
         const wp<ConsumerListener>& consumerListener):
         mConsumerListener(consumerListener) {}
@@ -1249,4 +43,172 @@
     }
 }
 
+void BufferQueue::createBufferQueue(sp<BnGraphicBufferProducer>* outProducer,
+        sp<BnGraphicBufferConsumer>* outConsumer,
+        const sp<IGraphicBufferAlloc>& allocator) {
+    LOG_ALWAYS_FATAL_IF(outProducer == NULL,
+            "BufferQueue: outProducer must not be NULL");
+    LOG_ALWAYS_FATAL_IF(outConsumer == NULL,
+            "BufferQueue: outConsumer must not be NULL");
+
+    sp<BufferQueueCore> core(new BufferQueueCore(allocator));
+    *outProducer = new BufferQueueProducer(core);
+    *outConsumer = new BufferQueueConsumer(core);
+}
+
+void BufferQueue::createBufferQueue(sp<IGraphicBufferProducer>* outProducer,
+        sp<IGraphicBufferConsumer>* outConsumer,
+        const sp<IGraphicBufferAlloc>& allocator) {
+    LOG_ALWAYS_FATAL_IF(outProducer == NULL,
+            "BufferQueue: outProducer must not be NULL");
+    LOG_ALWAYS_FATAL_IF(outConsumer == NULL,
+            "BufferQueue: outConsumer must not be NULL");
+
+    sp<BufferQueueCore> core(new BufferQueueCore(allocator));
+    *outProducer = new BufferQueueProducer(core);
+    *outConsumer = new BufferQueueConsumer(core);
+}
+
+BufferQueue::BufferQueue(const sp<IGraphicBufferAlloc>& allocator) :
+    mProducer(),
+    mConsumer()
+{
+    sp<BufferQueueCore> core(new BufferQueueCore(allocator));
+    mProducer = new BufferQueueProducer(core);
+    mConsumer = new BufferQueueConsumer(core);
+}
+
+BufferQueue::~BufferQueue() {}
+
+void BufferQueue::binderDied(const wp<IBinder>& who) {
+    mProducer->binderDied(who);
+}
+
+int BufferQueue::query(int what, int* outValue) {
+    return mProducer->query(what, outValue);
+}
+
+status_t BufferQueue::setBufferCount(int bufferCount) {
+    return mProducer->setBufferCount(bufferCount);
+}
+
+status_t BufferQueue::requestBuffer(int slot, sp<GraphicBuffer>* buf) {
+    return mProducer->requestBuffer(slot, buf);
+}
+
+status_t BufferQueue::dequeueBuffer(int *outBuf, sp<Fence>* outFence, bool async,
+        uint32_t w, uint32_t h, uint32_t format, uint32_t usage) {
+    return mProducer->dequeueBuffer(outBuf, outFence, async, w, h, format, usage);
+}
+
+status_t BufferQueue::detachProducerBuffer(int slot) {
+    return mProducer->detachBuffer(slot);
+}
+
+status_t BufferQueue::attachProducerBuffer(int* slot,
+        const sp<GraphicBuffer>& buffer) {
+    return mProducer->attachBuffer(slot, buffer);
+}
+
+status_t BufferQueue::queueBuffer(int buf,
+        const QueueBufferInput& input, QueueBufferOutput* output) {
+    return mProducer->queueBuffer(buf, input, output);
+}
+
+void BufferQueue::cancelBuffer(int buf, const sp<Fence>& fence) {
+    mProducer->cancelBuffer(buf, fence);
+}
+
+status_t BufferQueue::connect(const sp<IBinder>& token,
+        int api, bool producerControlledByApp, QueueBufferOutput* output) {
+    return mProducer->connect(token, api, producerControlledByApp, output);
+}
+
+status_t BufferQueue::disconnect(int api) {
+    return mProducer->disconnect(api);
+}
+
+status_t BufferQueue::setSidebandStream(const sp<NativeHandle>& stream) {
+    return mProducer->setSidebandStream(stream);
+}
+
+status_t BufferQueue::acquireBuffer(BufferItem* buffer, nsecs_t presentWhen) {
+    return mConsumer->acquireBuffer(buffer, presentWhen);
+}
+
+status_t BufferQueue::detachConsumerBuffer(int slot) {
+    return mConsumer->detachBuffer(slot);
+}
+
+status_t BufferQueue::attachConsumerBuffer(int* slot,
+        const sp<GraphicBuffer>& buffer) {
+    return mConsumer->attachBuffer(slot, buffer);
+}
+
+status_t BufferQueue::releaseBuffer(
+        int buf, uint64_t frameNumber, EGLDisplay display,
+        EGLSyncKHR eglFence, const sp<Fence>& fence) {
+    return mConsumer->releaseBuffer(buf, frameNumber, fence, display, eglFence);
+}
+
+status_t BufferQueue::consumerConnect(const sp<IConsumerListener>& consumerListener,
+        bool controlledByApp) {
+    return mConsumer->connect(consumerListener, controlledByApp);
+}
+
+status_t BufferQueue::consumerDisconnect() {
+    return mConsumer->disconnect();
+}
+
+status_t BufferQueue::getReleasedBuffers(uint32_t* slotMask) {
+    return mConsumer->getReleasedBuffers(slotMask);
+}
+
+status_t BufferQueue::setDefaultBufferSize(uint32_t w, uint32_t h) {
+    return mConsumer->setDefaultBufferSize(w, h);
+}
+
+status_t BufferQueue::setDefaultMaxBufferCount(int bufferCount) {
+    return mConsumer->setDefaultMaxBufferCount(bufferCount);
+}
+
+status_t BufferQueue::disableAsyncBuffer() {
+    return mConsumer->disableAsyncBuffer();
+}
+
+status_t BufferQueue::setMaxAcquiredBufferCount(int maxAcquiredBuffers) {
+    return mConsumer->setMaxAcquiredBufferCount(maxAcquiredBuffers);
+}
+
+void BufferQueue::setConsumerName(const String8& name) {
+    mConsumer->setConsumerName(name);
+}
+
+status_t BufferQueue::setDefaultBufferFormat(uint32_t defaultFormat) {
+    return mConsumer->setDefaultBufferFormat(defaultFormat);
+}
+
+status_t BufferQueue::setConsumerUsageBits(uint32_t usage) {
+    return mConsumer->setConsumerUsageBits(usage);
+}
+
+status_t BufferQueue::setTransformHint(uint32_t hint) {
+    return mConsumer->setTransformHint(hint);
+}
+
+sp<NativeHandle> BufferQueue::getSidebandStream() const {
+    return mConsumer->getSidebandStream();
+}
+
+void BufferQueue::dump(String8& result, const char* prefix) const {
+    mConsumer->dump(result, prefix);
+}
+
+void BufferQueue::ProxyConsumerListener::onSidebandStreamChanged() {
+    sp<ConsumerListener> listener(mConsumerListener.promote());
+    if (listener != NULL) {
+        listener->onSidebandStreamChanged();
+    }
+}
+
 }; // namespace android
diff --git a/libs/gui/BufferQueueConsumer.cpp b/libs/gui/BufferQueueConsumer.cpp
new file mode 100644
index 0000000..756cd61
--- /dev/null
+++ b/libs/gui/BufferQueueConsumer.cpp
@@ -0,0 +1,489 @@
+/*
+ * Copyright 2014 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 LOG_TAG "BufferQueueConsumer"
+#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+//#define LOG_NDEBUG 0
+
+#include <gui/BufferItem.h>
+#include <gui/BufferQueueConsumer.h>
+#include <gui/BufferQueueCore.h>
+#include <gui/IConsumerListener.h>
+
+namespace android {
+
+BufferQueueConsumer::BufferQueueConsumer(const sp<BufferQueueCore>& core) :
+    mCore(core),
+    mSlots(core->mSlots),
+    mConsumerName() {}
+
+BufferQueueConsumer::~BufferQueueConsumer() {}
+
+status_t BufferQueueConsumer::acquireBuffer(BufferItem* outBuffer,
+        nsecs_t expectedPresent) {
+    ATRACE_CALL();
+    Mutex::Autolock lock(mCore->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 s = 0; s < BufferQueueDefs::NUM_BUFFER_SLOTS; ++s) {
+        if (mSlots[s].mBufferState == BufferSlot::ACQUIRED) {
+            ++numAcquiredBuffers;
+        }
+    }
+    if (numAcquiredBuffers >= mCore->mMaxAcquiredBufferCount + 1) {
+        BQ_LOGE("acquireBuffer: max acquired buffer count reached: %d (max %d)",
+                numAcquiredBuffers, mCore->mMaxAcquiredBufferCount);
+        return INVALID_OPERATION;
+    }
+
+    // Check if the 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 (mCore->mQueue.empty()) {
+        return NO_BUFFER_AVAILABLE;
+    }
+
+    BufferQueueCore::Fifo::iterator front(mCore->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 will be displayed
+        // on time or possibly late if we show it as soon as possible -- 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, it probably doesn't want frames to
+        // be discarded based on them.
+        while (mCore->mQueue.size() > 1 && !mCore->mQueue[0].mIsAutoTimestamp) {
+            // If entry[1] is timely, drop entry[0] (and repeat). We apply an
+            // additional criterion 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 criterion: don't drop the
+            // earlier buffer if entry[1]'s fence hasn't signaled yet.
+            const BufferItem& bufferItem(mCore->mQueue[1]);
+            nsecs_t desiredPresent = bufferItem.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 the screen sooner.
+                BQ_LOGV("acquireBuffer: nodrop desire=%lld expect=%lld "
+                        "(%lld) now=%lld", desiredPresent, expectedPresent,
+                        desiredPresent - expectedPresent,
+                        systemTime(CLOCK_MONOTONIC));
+                break;
+            }
+
+            BQ_LOGV("acquireBuffer: drop desire=%lld expect=%lld size=%d",
+                    desiredPresent, expectedPresent, mCore->mQueue.size());
+            if (mCore->stillTracking(front)) {
+                // Front buffer is still in mSlots, so mark the slot as free
+                mSlots[front->mSlot].mBufferState = BufferSlot::FREE;
+            }
+            mCore->mQueue.erase(front);
+            front = mCore->mQueue.begin();
+        }
+
+        // See if the front buffer is due
+        nsecs_t desiredPresent = front->mTimestamp;
+        if (desiredPresent > expectedPresent &&
+                desiredPresent < expectedPresent + MAX_REASONABLE_NSEC) {
+            BQ_LOGV("acquireBuffer: defer desire=%lld expect=%lld "
+                    "(%lld) now=%lld", desiredPresent, expectedPresent,
+                    desiredPresent - expectedPresent,
+                    systemTime(CLOCK_MONOTONIC));
+            return PRESENT_LATER;
+        }
+
+        BQ_LOGV("acquireBuffer: accept desire=%lld expect=%lld "
+                "(%lld) now=%lld", desiredPresent, expectedPresent,
+                desiredPresent - expectedPresent,
+                systemTime(CLOCK_MONOTONIC));
+    }
+
+    int slot = front->mSlot;
+    *outBuffer = *front;
+    ATRACE_BUFFER_INDEX(slot);
+
+    BQ_LOGV("acquireBuffer: acquiring { slot=%d/%llu buffer=%p }",
+            slot, front->mFrameNumber, front->mGraphicBuffer->handle);
+    // If the front buffer is still being tracked, update its slot state
+    if (mCore->stillTracking(front)) {
+        mSlots[slot].mAcquireCalled = true;
+        mSlots[slot].mNeedsCleanupOnRelease = false;
+        mSlots[slot].mBufferState = BufferSlot::ACQUIRED;
+        mSlots[slot].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 (outBuffer->mAcquireCalled) {
+        outBuffer->mGraphicBuffer = NULL;
+    }
+
+    mCore->mQueue.erase(front);
+    // TODO: Should this call be after we free a slot while dropping buffers?
+    // Simply acquiring the next buffer doesn't enable a producer to dequeue.
+    mCore->mDequeueCondition.broadcast();
+
+    ATRACE_INT(mCore->mConsumerName.string(), mCore->mQueue.size());
+
+    return NO_ERROR;
+}
+
+status_t BufferQueueConsumer::detachBuffer(int slot) {
+    ATRACE_CALL();
+    ATRACE_BUFFER_INDEX(slot);
+    BQ_LOGV("detachBuffer(C): slot %d", slot);
+    Mutex::Autolock lock(mCore->mMutex);
+
+    if (mCore->mIsAbandoned) {
+        BQ_LOGE("detachBuffer(C): BufferQueue has been abandoned");
+        return NO_INIT;
+    }
+
+    if (slot < 0 || slot >= BufferQueueDefs::NUM_BUFFER_SLOTS) {
+        BQ_LOGE("detachBuffer(C): slot index %d out of range [0, %d)",
+                slot, BufferQueueDefs::NUM_BUFFER_SLOTS);
+        return BAD_VALUE;
+    } else if (mSlots[slot].mBufferState != BufferSlot::ACQUIRED) {
+        BQ_LOGE("detachBuffer(C): slot %d is not owned by the consumer "
+                "(state = %d)", slot, mSlots[slot].mBufferState);
+        return BAD_VALUE;
+    }
+
+    mCore->freeBufferLocked(slot);
+    mCore->mDequeueCondition.broadcast();
+
+    return NO_ERROR;
+}
+
+status_t BufferQueueConsumer::attachBuffer(int* outSlot,
+        const sp<android::GraphicBuffer>& buffer) {
+    ATRACE_CALL();
+
+    if (outSlot == NULL) {
+        BQ_LOGE("attachBuffer(P): outSlot must not be NULL");
+        return BAD_VALUE;
+    } else if (buffer == NULL) {
+        BQ_LOGE("attachBuffer(P): cannot attach NULL buffer");
+        return BAD_VALUE;
+    }
+
+    Mutex::Autolock lock(mCore->mMutex);
+
+    // Make sure we don't have too many acquired buffers and find a free slot
+    // to put the buffer into (the oldest if there are multiple).
+    int numAcquiredBuffers = 0;
+    int found = BufferQueueCore::INVALID_BUFFER_SLOT;
+    for (int s = 0; s < BufferQueueDefs::NUM_BUFFER_SLOTS; ++s) {
+        if (mSlots[s].mBufferState == BufferSlot::ACQUIRED) {
+            ++numAcquiredBuffers;
+        } else if (mSlots[s].mBufferState == BufferSlot::FREE) {
+            if (found == BufferQueueCore::INVALID_BUFFER_SLOT ||
+                    mSlots[s].mFrameNumber < mSlots[found].mFrameNumber) {
+                found = s;
+            }
+        }
+    }
+
+    if (numAcquiredBuffers >= mCore->mMaxAcquiredBufferCount + 1) {
+        BQ_LOGE("attachBuffer(P): max acquired buffer count reached: %d "
+                "(max %d)", numAcquiredBuffers,
+                mCore->mMaxAcquiredBufferCount);
+        return INVALID_OPERATION;
+    }
+    if (found == BufferQueueCore::INVALID_BUFFER_SLOT) {
+        BQ_LOGE("attachBuffer(P): could not find free buffer slot");
+        return NO_MEMORY;
+    }
+
+    *outSlot = found;
+    ATRACE_BUFFER_INDEX(*outSlot);
+    BQ_LOGV("attachBuffer(C): returning slot %d", *outSlot);
+
+    mSlots[*outSlot].mGraphicBuffer = buffer;
+    mSlots[*outSlot].mBufferState = BufferSlot::ACQUIRED;
+    mSlots[*outSlot].mAttachedByConsumer = true;
+    mSlots[*outSlot].mAcquireCalled = true;
+    mSlots[*outSlot].mNeedsCleanupOnRelease = false;
+    mSlots[*outSlot].mFence = Fence::NO_FENCE;
+    mSlots[*outSlot].mFrameNumber = 0;
+
+    return NO_ERROR;
+}
+
+status_t BufferQueueConsumer::releaseBuffer(int slot, uint64_t frameNumber,
+        const sp<Fence>& releaseFence, EGLDisplay eglDisplay,
+        EGLSyncKHR eglFence) {
+    ATRACE_CALL();
+    ATRACE_BUFFER_INDEX(slot);
+
+    if (slot < 0 || slot >= BufferQueueDefs::NUM_BUFFER_SLOTS ||
+            releaseFence == NULL) {
+        return BAD_VALUE;
+    }
+
+    Mutex::Autolock lock(mCore->mMutex);
+
+    // If the frame number has changed because the buffer has been reallocated,
+    // we can ignore this releaseBuffer for the old buffer
+    if (frameNumber != mSlots[slot].mFrameNumber) {
+        return STALE_BUFFER_SLOT;
+    }
+
+    // Make sure this buffer hasn't been queued while acquired by the consumer
+    BufferQueueCore::Fifo::iterator current(mCore->mQueue.begin());
+    while (current != mCore->mQueue.end()) {
+        if (current->mSlot == slot) {
+            BQ_LOGE("releaseBuffer: buffer slot %d pending release is "
+                    "currently queued", slot);
+            return BAD_VALUE;
+        }
+        ++current;
+    }
+
+    if (mSlots[slot].mBufferState == BufferSlot::ACQUIRED) {
+        mSlots[slot].mEglDisplay = eglDisplay;
+        mSlots[slot].mEglFence = eglFence;
+        mSlots[slot].mFence = releaseFence;
+        mSlots[slot].mBufferState = BufferSlot::FREE;
+    } else if (mSlots[slot].mNeedsCleanupOnRelease) {
+        BQ_LOGV("releaseBuffer: releasing a stale buffer slot %d "
+                "(state = %d)", slot, mSlots[slot].mBufferState);
+        mSlots[slot].mNeedsCleanupOnRelease = false;
+        return STALE_BUFFER_SLOT;
+    } else {
+        BQ_LOGV("releaseBuffer: attempted to release buffer slot %d "
+                "but its state was %d", slot, mSlots[slot].mBufferState);
+        return BAD_VALUE;
+    }
+
+    mCore->mDequeueCondition.broadcast();
+
+    return NO_ERROR;
+}
+
+status_t BufferQueueConsumer::connect(
+        const sp<IConsumerListener>& consumerListener, bool controlledByApp) {
+    ATRACE_CALL();
+
+    if (consumerListener == NULL) {
+        BQ_LOGE("connect(C): consumerListener may not be NULL");
+        return BAD_VALUE;
+    }
+
+    BQ_LOGV("connect(C): controlledByApp=%s",
+            controlledByApp ? "true" : "false");
+
+    Mutex::Autolock lock(mCore->mMutex);
+
+    if (mCore->mIsAbandoned) {
+        BQ_LOGE("connect(C): BufferQueue has been abandoned");
+        return NO_INIT;
+    }
+
+    mCore->mConsumerListener = consumerListener;
+    mCore->mConsumerControlledByApp = controlledByApp;
+
+    return NO_ERROR;
+}
+
+status_t BufferQueueConsumer::disconnect() {
+    ATRACE_CALL();
+
+    BQ_LOGV("disconnect(C)");
+
+    Mutex::Autolock lock(mCore->mMutex);
+
+    if (mCore->mConsumerListener == NULL) {
+        BQ_LOGE("disconnect(C): no consumer is connected");
+        return BAD_VALUE;
+    }
+
+    mCore->mIsAbandoned = true;
+    mCore->mConsumerListener = NULL;
+    mCore->mQueue.clear();
+    mCore->freeAllBuffersLocked();
+    mCore->mDequeueCondition.broadcast();
+    return NO_ERROR;
+}
+
+status_t BufferQueueConsumer::getReleasedBuffers(uint32_t *outSlotMask) {
+    ATRACE_CALL();
+
+    if (outSlotMask == NULL) {
+        BQ_LOGE("getReleasedBuffers: outSlotMask may not be NULL");
+        return BAD_VALUE;
+    }
+
+    Mutex::Autolock lock(mCore->mMutex);
+
+    if (mCore->mIsAbandoned) {
+        BQ_LOGE("getReleasedBuffers: BufferQueue has been abandoned");
+        return NO_INIT;
+    }
+
+    uint32_t mask = 0;
+    for (int s = 0; s < BufferQueueDefs::NUM_BUFFER_SLOTS; ++s) {
+        if (!mSlots[s].mAcquireCalled) {
+            mask |= (1u << s);
+        }
+    }
+
+    // Remove from the mask queued buffers for which acquire has been called,
+    // since the consumer will not receive their buffer addresses and so must
+    // retain their cached information
+    BufferQueueCore::Fifo::iterator current(mCore->mQueue.begin());
+    while (current != mCore->mQueue.end()) {
+        if (current->mAcquireCalled) {
+            mask &= ~(1u << current->mSlot);
+        }
+        ++current;
+    }
+
+    BQ_LOGV("getReleasedBuffers: returning mask %#x", mask);
+    *outSlotMask = mask;
+    return NO_ERROR;
+}
+
+status_t BufferQueueConsumer::setDefaultBufferSize(uint32_t width,
+        uint32_t height) {
+    ATRACE_CALL();
+
+    if (width == 0 || height == 0) {
+        BQ_LOGV("setDefaultBufferSize: dimensions cannot be 0 (width=%u "
+                "height=%u)", width, height);
+        return BAD_VALUE;
+    }
+
+    BQ_LOGV("setDefaultBufferSize: width=%u height=%u", width, height);
+
+    Mutex::Autolock lock(mCore->mMutex);
+    mCore->mDefaultWidth = width;
+    mCore->mDefaultHeight = height;
+    return NO_ERROR;
+}
+
+status_t BufferQueueConsumer::setDefaultMaxBufferCount(int bufferCount) {
+    ATRACE_CALL();
+    Mutex::Autolock lock(mCore->mMutex);
+    return mCore->setDefaultMaxBufferCountLocked(bufferCount);
+}
+
+status_t BufferQueueConsumer::disableAsyncBuffer() {
+    ATRACE_CALL();
+
+    Mutex::Autolock lock(mCore->mMutex);
+
+    if (mCore->mConsumerListener != NULL) {
+        BQ_LOGE("disableAsyncBuffer: consumer already connected");
+        return INVALID_OPERATION;
+    }
+
+    BQ_LOGV("disableAsyncBuffer");
+    mCore->mUseAsyncBuffer = false;
+    return NO_ERROR;
+}
+
+status_t BufferQueueConsumer::setMaxAcquiredBufferCount(
+        int maxAcquiredBuffers) {
+    ATRACE_CALL();
+
+    if (maxAcquiredBuffers < 1 ||
+            maxAcquiredBuffers > BufferQueueCore::MAX_MAX_ACQUIRED_BUFFERS) {
+        BQ_LOGE("setMaxAcquiredBufferCount: invalid count %d",
+                maxAcquiredBuffers);
+        return BAD_VALUE;
+    }
+
+    Mutex::Autolock lock(mCore->mMutex);
+
+    if (mCore->mConnectedApi != BufferQueueCore::NO_CONNECTED_API) {
+        BQ_LOGE("setMaxAcquiredBufferCount: producer is already connected");
+        return INVALID_OPERATION;
+    }
+
+    BQ_LOGV("setMaxAcquiredBufferCount: %d", maxAcquiredBuffers);
+    mCore->mMaxAcquiredBufferCount = maxAcquiredBuffers;
+    return NO_ERROR;
+}
+
+void BufferQueueConsumer::setConsumerName(const String8& name) {
+    ATRACE_CALL();
+    BQ_LOGV("setConsumerName: '%s'", name.string());
+    Mutex::Autolock lock(mCore->mMutex);
+    mCore->mConsumerName = name;
+    mConsumerName = name;
+}
+
+status_t BufferQueueConsumer::setDefaultBufferFormat(uint32_t defaultFormat) {
+    ATRACE_CALL();
+    BQ_LOGV("setDefaultBufferFormat: %u", defaultFormat);
+    Mutex::Autolock lock(mCore->mMutex);
+    mCore->mDefaultBufferFormat = defaultFormat;
+    return NO_ERROR;
+}
+
+status_t BufferQueueConsumer::setConsumerUsageBits(uint32_t usage) {
+    ATRACE_CALL();
+    BQ_LOGV("setConsumerUsageBits: %#x", usage);
+    Mutex::Autolock lock(mCore->mMutex);
+    mCore->mConsumerUsageBits = usage;
+    return NO_ERROR;
+}
+
+status_t BufferQueueConsumer::setTransformHint(uint32_t hint) {
+    ATRACE_CALL();
+    BQ_LOGV("setTransformHint: %#x", hint);
+    Mutex::Autolock lock(mCore->mMutex);
+    mCore->mTransformHint = hint;
+    return NO_ERROR;
+}
+
+sp<NativeHandle> BufferQueueConsumer::getSidebandStream() const {
+    return mCore->mSidebandStream;
+}
+
+void BufferQueueConsumer::dump(String8& result, const char* prefix) const {
+    mCore->dump(result, prefix);
+}
+
+} // namespace android
diff --git a/libs/gui/BufferQueueCore.cpp b/libs/gui/BufferQueueCore.cpp
new file mode 100644
index 0000000..300b23a
--- /dev/null
+++ b/libs/gui/BufferQueueCore.cpp
@@ -0,0 +1,225 @@
+/*
+ * Copyright 2014 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 LOG_TAG "BufferQueueCore"
+#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+//#define LOG_NDEBUG 0
+
+#define EGL_EGLEXT_PROTOTYPES
+
+#include <gui/BufferItem.h>
+#include <gui/BufferQueueCore.h>
+#include <gui/IConsumerListener.h>
+#include <gui/IGraphicBufferAlloc.h>
+#include <gui/ISurfaceComposer.h>
+#include <private/gui/ComposerService.h>
+
+template <typename T>
+static inline T max(T a, T b) { return a > b ? a : b; }
+
+namespace android {
+
+static String8 getUniqueName() {
+    static volatile int32_t counter = 0;
+    return String8::format("unnamed-%d-%d", getpid(),
+            android_atomic_inc(&counter));
+}
+
+BufferQueueCore::BufferQueueCore(const sp<IGraphicBufferAlloc>& allocator) :
+    mAllocator(allocator),
+    mMutex(),
+    mIsAbandoned(false),
+    mConsumerControlledByApp(false),
+    mConsumerName(getUniqueName()),
+    mConsumerListener(),
+    mConsumerUsageBits(0),
+    mConnectedApi(NO_CONNECTED_API),
+    mConnectedProducerToken(),
+    mSlots(),
+    mQueue(),
+    mOverrideMaxBufferCount(0),
+    mDequeueCondition(),
+    mUseAsyncBuffer(true),
+    mDequeueBufferCannotBlock(false),
+    mDefaultBufferFormat(PIXEL_FORMAT_RGBA_8888),
+    mDefaultWidth(1),
+    mDefaultHeight(1),
+    mDefaultMaxBufferCount(2),
+    mMaxAcquiredBufferCount(1),
+    mBufferHasBeenQueued(false),
+    mFrameCounter(0),
+    mTransformHint(0)
+{
+    if (allocator == NULL) {
+        sp<ISurfaceComposer> composer(ComposerService::getComposerService());
+        mAllocator = composer->createGraphicBufferAlloc();
+        if (mAllocator == NULL) {
+            BQ_LOGE("createGraphicBufferAlloc failed");
+        }
+    }
+}
+
+BufferQueueCore::~BufferQueueCore() {}
+
+void BufferQueueCore::dump(String8& result, const char* prefix) const {
+    Mutex::Autolock lock(mMutex);
+
+    String8 fifo;
+    Fifo::const_iterator current(mQueue.begin());
+    while (current != mQueue.end()) {
+        fifo.appendFormat("%02d:%p crop=[%d,%d,%d,%d], "
+                "xform=0x%02x, time=%#llx, scale=%s\n",
+                current->mSlot, current->mGraphicBuffer.get(),
+                current->mCrop.left, current->mCrop.top, current->mCrop.right,
+                current->mCrop.bottom, current->mTransform, current->mTimestamp,
+                BufferItem::scalingModeName(current->mScalingMode));
+        ++current;
+    }
+
+    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,
+            mQueue.size(), fifo.string());
+
+    // Trim the free buffers so as to not spam the dump
+    int maxBufferCount = 0;
+    for (int s = BufferQueueDefs::NUM_BUFFER_SLOTS - 1; s >= 0; --s) {
+        const BufferSlot& slot(mSlots[s]);
+        if (slot.mBufferState != BufferSlot::FREE ||
+                slot.mGraphicBuffer != NULL) {
+            maxBufferCount = s + 1;
+            break;
+        }
+    }
+
+    for (int s = 0; s < maxBufferCount; ++s) {
+        const BufferSlot& slot(mSlots[s]);
+        const sp<GraphicBuffer>& buffer(slot.mGraphicBuffer);
+        result.appendFormat("%s%s[%02d:%p] state=%-8s", prefix,
+                (slot.mBufferState == BufferSlot::ACQUIRED) ? ">" : " ",
+                s, buffer.get(),
+                BufferSlot::bufferStateName(slot.mBufferState));
+
+        if (buffer != NULL) {
+            result.appendFormat(", %p [%4ux%4u:%4u,%3X]", buffer->handle,
+                    buffer->width, buffer->height, buffer->stride,
+                    buffer->format);
+        }
+
+        result.append("\n");
+    }
+}
+
+int BufferQueueCore::getMinUndequeuedBufferCountLocked(bool async) const {
+    // If dequeueBuffer is allowed to error out, we don't have to add an
+    // extra buffer.
+    if (!mUseAsyncBuffer) {
+        return mMaxAcquiredBufferCount;
+    }
+
+    if (mDequeueBufferCannotBlock || async) {
+        return mMaxAcquiredBufferCount + 1;
+    }
+
+    return mMaxAcquiredBufferCount;
+}
+
+int BufferQueueCore::getMinMaxBufferCountLocked(bool async) const {
+    return getMinUndequeuedBufferCountLocked(async) + 1;
+}
+
+int BufferQueueCore::getMaxBufferCountLocked(bool async) const {
+    int minMaxBufferCount = getMinMaxBufferCountLocked(async);
+
+    int maxBufferCount = max(mDefaultMaxBufferCount, 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 s = maxBufferCount; s < BufferQueueDefs::NUM_BUFFER_SLOTS; ++s) {
+        BufferSlot::BufferState state = mSlots[s].mBufferState;
+        if (state == BufferSlot::QUEUED || state == BufferSlot::DEQUEUED) {
+            maxBufferCount = s + 1;
+        }
+    }
+
+    return maxBufferCount;
+}
+
+status_t BufferQueueCore::setDefaultMaxBufferCountLocked(int count) {
+    const int minBufferCount = mUseAsyncBuffer ? 2 : 1;
+    if (count < minBufferCount || count > BufferQueueDefs::NUM_BUFFER_SLOTS) {
+        BQ_LOGV("setDefaultMaxBufferCount: invalid count %d, should be in "
+                "[%d, %d]", minBufferCount, BufferQueueDefs::NUM_BUFFER_SLOTS);
+        return BAD_VALUE;
+    }
+
+    BQ_LOGV("setDefaultMaxBufferCount: setting count to %d", count);
+    mDefaultMaxBufferCount = count;
+    mDequeueCondition.broadcast();
+
+    return NO_ERROR;
+}
+
+void BufferQueueCore::freeBufferLocked(int slot) {
+    BQ_LOGV("freeBufferLocked: slot %d", slot);
+    mSlots[slot].mGraphicBuffer.clear();
+    if (mSlots[slot].mBufferState == BufferSlot::ACQUIRED) {
+        mSlots[slot].mNeedsCleanupOnRelease = true;
+    }
+    mSlots[slot].mBufferState = BufferSlot::FREE;
+    mSlots[slot].mFrameNumber = 0;
+    mSlots[slot].mAcquireCalled = false;
+
+    // Destroy fence as BufferQueue now takes ownership
+    if (mSlots[slot].mEglFence != EGL_NO_SYNC_KHR) {
+        eglDestroySyncKHR(mSlots[slot].mEglDisplay, mSlots[slot].mEglFence);
+        mSlots[slot].mEglFence = EGL_NO_SYNC_KHR;
+    }
+    mSlots[slot].mFence = Fence::NO_FENCE;
+}
+
+void BufferQueueCore::freeAllBuffersLocked() {
+    mBufferHasBeenQueued = false;
+    for (int s = 0; s < BufferQueueDefs::NUM_BUFFER_SLOTS; ++s) {
+        freeBufferLocked(s);
+    }
+}
+
+bool BufferQueueCore::stillTracking(const BufferItem* item) const {
+    const BufferSlot& slot = mSlots[item->mSlot];
+
+    BQ_LOGV("stillTracking: item { slot=%d/%llu buffer=%p } "
+            "slot { slot=%d/%llu buffer=%p }",
+            item->mSlot, item->mFrameNumber,
+            (item->mGraphicBuffer.get() ? item->mGraphicBuffer->handle : 0),
+            item->mSlot, 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);
+}
+
+} // namespace android
diff --git a/libs/gui/BufferQueueProducer.cpp b/libs/gui/BufferQueueProducer.cpp
new file mode 100644
index 0000000..7db344a
--- /dev/null
+++ b/libs/gui/BufferQueueProducer.cpp
@@ -0,0 +1,809 @@
+/*
+ * Copyright 2014 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 LOG_TAG "BufferQueueProducer"
+#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+//#define LOG_NDEBUG 0
+
+#define EGL_EGLEXT_PROTOTYPES
+
+#include <gui/BufferItem.h>
+#include <gui/BufferQueueCore.h>
+#include <gui/BufferQueueProducer.h>
+#include <gui/IConsumerListener.h>
+#include <gui/IGraphicBufferAlloc.h>
+
+#include <utils/Log.h>
+#include <utils/Trace.h>
+
+namespace android {
+
+BufferQueueProducer::BufferQueueProducer(const sp<BufferQueueCore>& core) :
+    mCore(core),
+    mSlots(core->mSlots),
+    mConsumerName() {}
+
+BufferQueueProducer::~BufferQueueProducer() {}
+
+status_t BufferQueueProducer::requestBuffer(int slot, sp<GraphicBuffer>* buf) {
+    ATRACE_CALL();
+    BQ_LOGV("requestBuffer: slot %d", slot);
+    Mutex::Autolock lock(mCore->mMutex);
+
+    if (mCore->mIsAbandoned) {
+        BQ_LOGE("requestBuffer: BufferQueue has been abandoned");
+        return NO_INIT;
+    }
+
+    if (slot < 0 || slot >= BufferQueueDefs::NUM_BUFFER_SLOTS) {
+        BQ_LOGE("requestBuffer: slot index %d out of range [0, %d)",
+                slot, BufferQueueDefs::NUM_BUFFER_SLOTS);
+        return BAD_VALUE;
+    } else if (mSlots[slot].mBufferState != BufferSlot::DEQUEUED) {
+        BQ_LOGE("requestBuffer: slot %d is not owned by the producer "
+                "(state = %d)", slot, mSlots[slot].mBufferState);
+        return BAD_VALUE;
+    }
+
+    mSlots[slot].mRequestBufferCalled = true;
+    *buf = mSlots[slot].mGraphicBuffer;
+    return NO_ERROR;
+}
+
+status_t BufferQueueProducer::setBufferCount(int bufferCount) {
+    ATRACE_CALL();
+    BQ_LOGV("setBufferCount: count = %d", bufferCount);
+
+    sp<IConsumerListener> listener;
+    { // Autolock scope
+        Mutex::Autolock lock(mCore->mMutex);
+
+        if (mCore->mIsAbandoned) {
+            BQ_LOGE("setBufferCount: BufferQueue has been abandoned");
+            return NO_INIT;
+        }
+
+        if (bufferCount > BufferQueueDefs::NUM_BUFFER_SLOTS) {
+            BQ_LOGE("setBufferCount: bufferCount %d too large (max %d)",
+                    bufferCount, BufferQueueDefs::NUM_BUFFER_SLOTS);
+            return BAD_VALUE;
+        }
+
+        // There must be no dequeued buffers when changing the buffer count.
+        for (int s = 0; s < BufferQueueDefs::NUM_BUFFER_SLOTS; ++s) {
+            if (mSlots[s].mBufferState == BufferSlot::DEQUEUED) {
+                BQ_LOGE("setBufferCount: buffer owned by producer");
+                return BAD_VALUE;
+            }
+        }
+
+        if (bufferCount == 0) {
+            mCore->mOverrideMaxBufferCount = 0;
+            mCore->mDequeueCondition.broadcast();
+            return NO_ERROR;
+        }
+
+        const int minBufferSlots = mCore->getMinMaxBufferCountLocked(false);
+        if (bufferCount < minBufferSlots) {
+            BQ_LOGE("setBufferCount: requested buffer count %d is less than "
+                    "minimum %d", bufferCount, minBufferSlots);
+            return BAD_VALUE;
+        }
+
+        // Here we are guaranteed that the producer doesn't have any dequeued
+        // buffers and will release all of its buffer references. We don't
+        // clear the queue, however, so that currently queued buffers still
+        // get displayed.
+        mCore->freeAllBuffersLocked();
+        mCore->mOverrideMaxBufferCount = bufferCount;
+        mCore->mDequeueCondition.broadcast();
+        listener = mCore->mConsumerListener;
+    } // Autolock scope
+
+    // Call back without lock held
+    if (listener != NULL) {
+        listener->onBuffersReleased();
+    }
+
+    return NO_ERROR;
+}
+
+status_t BufferQueueProducer::waitForFreeSlotThenRelock(const char* caller,
+        bool async, int* found, status_t* returnFlags) const {
+    bool tryAgain = true;
+    while (tryAgain) {
+        if (mCore->mIsAbandoned) {
+            BQ_LOGE("%s: BufferQueue has been abandoned", caller);
+            return NO_INIT;
+        }
+
+        const int maxBufferCount = mCore->getMaxBufferCountLocked(async);
+        if (async && mCore->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 (mCore->mOverrideMaxBufferCount < maxBufferCount) {
+                BQ_LOGE("%s: async mode is invalid with buffer count override",
+                        caller);
+                return BAD_VALUE;
+            }
+        }
+
+        // Free up any buffers that are in slots beyond the max buffer count
+        for (int s = maxBufferCount; s < BufferQueueDefs::NUM_BUFFER_SLOTS; ++s) {
+            assert(mSlots[s].mBufferState == BufferSlot::FREE);
+            if (mSlots[s].mGraphicBuffer != NULL) {
+                mCore->freeBufferLocked(s);
+                *returnFlags |= RELEASE_ALL_BUFFERS;
+            }
+        }
+
+        // Look for a free buffer to give to the client
+        *found = BufferQueueCore::INVALID_BUFFER_SLOT;
+        int dequeuedCount = 0;
+        int acquiredCount = 0;
+        for (int s = 0; s < maxBufferCount; ++s) {
+            switch (mSlots[s].mBufferState) {
+                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, since the consumer
+                    // may still have pending reads of in-flight buffers
+                    if (*found == BufferQueueCore::INVALID_BUFFER_SLOT ||
+                            mSlots[s].mFrameNumber < mSlots[*found].mFrameNumber) {
+                        *found = s;
+                    }
+                    break;
+                default:
+                    break;
+            }
+        }
+
+        // Producers are not allowed to dequeue more than one buffer if they
+        // did not set a buffer count
+        if (!mCore->mOverrideMaxBufferCount && dequeuedCount) {
+            BQ_LOGE("%s: can't dequeue multiple buffers without setting the "
+                    "buffer count", caller);
+            return INVALID_OPERATION;
+        }
+
+        // See whether a buffer has been queued since the last
+        // setBufferCount so we know whether to perform the min undequeued
+        // buffers check below
+        if (mCore->mBufferHasBeenQueued) {
+            // Make sure the producer is not trying to dequeue more buffers
+            // than allowed
+            const int newUndequeuedCount =
+                maxBufferCount - (dequeuedCount + 1);
+            const int minUndequeuedCount =
+                mCore->getMinUndequeuedBufferCountLocked(async);
+            if (newUndequeuedCount < minUndequeuedCount) {
+                BQ_LOGE("%s: min undequeued buffer count (%d) exceeded "
+                        "(dequeued=%d undequeued=%d)",
+                        caller, minUndequeuedCount,
+                        dequeuedCount, newUndequeuedCount);
+                return INVALID_OPERATION;
+            }
+        }
+
+        // If no buffer is found, wait for a buffer to be released or for
+        // the max buffer count to change
+        tryAgain = (*found == BufferQueueCore::INVALID_BUFFER_SLOT);
+        if (tryAgain) {
+            // Return an error if we're in non-blocking mode (producer and
+            // consumer are controlled by the application).
+            // However, the consumer is allowed to briefly acquire an extra
+            // buffer (which could cause us to have to wait here), which is
+            // okay, since it is only used to implement an atomic acquire +
+            // release (e.g., in GLConsumer::updateTexImage())
+            if (mCore->mDequeueBufferCannotBlock &&
+                    (acquiredCount <= mCore->mMaxAcquiredBufferCount)) {
+                return WOULD_BLOCK;
+            }
+            mCore->mDequeueCondition.wait(mCore->mMutex);
+        }
+    } // while (tryAgain)
+
+    return NO_ERROR;
+}
+
+status_t BufferQueueProducer::dequeueBuffer(int *outSlot,
+        sp<android::Fence> *outFence, bool async,
+        uint32_t width, uint32_t height, uint32_t format, uint32_t usage) {
+    ATRACE_CALL();
+    { // Autolock scope
+        Mutex::Autolock lock(mCore->mMutex);
+        mConsumerName = mCore->mConsumerName;
+    } // Autolock scope
+
+    BQ_LOGV("dequeueBuffer: async=%s w=%u h=%u format=%#x, usage=%#x",
+            async ? "true" : "false", width, height, format, usage);
+
+    if ((width && !height) || (!width && height)) {
+        BQ_LOGE("dequeueBuffer: invalid size: w=%u h=%u", width, height);
+        return BAD_VALUE;
+    }
+
+    status_t returnFlags = NO_ERROR;
+    EGLDisplay eglDisplay = EGL_NO_DISPLAY;
+    EGLSyncKHR eglFence = EGL_NO_SYNC_KHR;
+    bool attachedByConsumer = false;
+
+    { // Autolock scope
+        Mutex::Autolock lock(mCore->mMutex);
+
+        if (format == 0) {
+            format = mCore->mDefaultBufferFormat;
+        }
+
+        // Enable the usage bits the consumer requested
+        usage |= mCore->mConsumerUsageBits;
+
+        int found;
+        status_t status = waitForFreeSlotThenRelock("dequeueBuffer", async,
+                &found, &returnFlags);
+        if (status != NO_ERROR) {
+            return status;
+        }
+
+        // This should not happen
+        if (found == BufferQueueCore::INVALID_BUFFER_SLOT) {
+            BQ_LOGE("dequeueBuffer: no available buffer slots");
+            return -EBUSY;
+        }
+
+        *outSlot = found;
+        ATRACE_BUFFER_INDEX(found);
+
+        attachedByConsumer = mSlots[found].mAttachedByConsumer;
+
+        const bool useDefaultSize = !width && !height;
+        if (useDefaultSize) {
+            width = mCore->mDefaultWidth;
+            height = mCore->mDefaultHeight;
+        }
+
+        mSlots[found].mBufferState = BufferSlot::DEQUEUED;
+
+        const sp<GraphicBuffer>& buffer(mSlots[found].mGraphicBuffer);
+        if ((buffer == NULL) ||
+                (static_cast<uint32_t>(buffer->width) != width) ||
+                (static_cast<uint32_t>(buffer->height) != height) ||
+                (static_cast<uint32_t>(buffer->format) != format) ||
+                ((static_cast<uint32_t>(buffer->usage) & usage) != usage))
+        {
+            mSlots[found].mAcquireCalled = false;
+            mSlots[found].mGraphicBuffer = NULL;
+            mSlots[found].mRequestBufferCalled = false;
+            mSlots[found].mEglDisplay = EGL_NO_DISPLAY;
+            mSlots[found].mEglFence = EGL_NO_SYNC_KHR;
+            mSlots[found].mFence = Fence::NO_FENCE;
+
+            returnFlags |= BUFFER_NEEDS_REALLOCATION;
+        }
+
+        if (CC_UNLIKELY(mSlots[found].mFence == NULL)) {
+            BQ_LOGE("dequeueBuffer: about to return a NULL fence - "
+                    "slot=%d w=%d h=%d format=%u",
+                    found, buffer->width, buffer->height, buffer->format);
+        }
+
+        eglDisplay = mSlots[found].mEglDisplay;
+        eglFence = mSlots[found].mEglFence;
+        *outFence = mSlots[found].mFence;
+        mSlots[found].mEglFence = EGL_NO_SYNC_KHR;
+        mSlots[found].mFence = Fence::NO_FENCE;
+    } // Autolock scope
+
+    if (returnFlags & BUFFER_NEEDS_REALLOCATION) {
+        status_t error;
+        sp<GraphicBuffer> graphicBuffer(mCore->mAllocator->createGraphicBuffer(
+                    width, height, format, usage, &error));
+        if (graphicBuffer == NULL) {
+            BQ_LOGE("dequeueBuffer: createGraphicBuffer failed");
+            return error;
+        }
+
+        { // Autolock scope
+            Mutex::Autolock lock(mCore->mMutex);
+
+            if (mCore->mIsAbandoned) {
+                BQ_LOGE("dequeueBuffer: BufferQueue has been abandoned");
+                return NO_INIT;
+            }
+
+            mSlots[*outSlot].mFrameNumber = UINT32_MAX;
+            mSlots[*outSlot].mGraphicBuffer = graphicBuffer;
+        } // Autolock scope
+    }
+
+    if (attachedByConsumer) {
+        returnFlags |= BUFFER_NEEDS_REALLOCATION;
+    }
+
+    if (eglFence != EGL_NO_SYNC_KHR) {
+        EGLint result = eglClientWaitSyncKHR(eglDisplay, eglFence, 0,
+                1000000000);
+        // If something goes wrong, log the error, but return the buffer without
+        // synchronizing access to it. It's too late at this point to abort the
+        // dequeue operation.
+        if (result == EGL_FALSE) {
+            BQ_LOGE("dequeueBuffer: error %#x waiting for fence",
+                    eglGetError());
+        } else if (result == EGL_TIMEOUT_EXPIRED_KHR) {
+            BQ_LOGE("dequeueBuffer: timeout waiting for fence");
+        }
+        eglDestroySyncKHR(eglDisplay, eglFence);
+    }
+
+    BQ_LOGV("dequeueBuffer: returning slot=%d/%llu buf=%p flags=%#x", *outSlot,
+            mSlots[*outSlot].mFrameNumber,
+            mSlots[*outSlot].mGraphicBuffer->handle, returnFlags);
+
+    return returnFlags;
+}
+
+status_t BufferQueueProducer::detachBuffer(int slot) {
+    ATRACE_CALL();
+    ATRACE_BUFFER_INDEX(slot);
+    BQ_LOGV("detachBuffer(P): slot %d", slot);
+    Mutex::Autolock lock(mCore->mMutex);
+
+    if (mCore->mIsAbandoned) {
+        BQ_LOGE("detachBuffer(P): BufferQueue has been abandoned");
+        return NO_INIT;
+    }
+
+    if (slot < 0 || slot >= BufferQueueDefs::NUM_BUFFER_SLOTS) {
+        BQ_LOGE("detachBuffer(P): slot index %d out of range [0, %d)",
+                slot, BufferQueueDefs::NUM_BUFFER_SLOTS);
+        return BAD_VALUE;
+    } else if (mSlots[slot].mBufferState != BufferSlot::DEQUEUED) {
+        BQ_LOGE("detachBuffer(P): slot %d is not owned by the producer "
+                "(state = %d)", slot, mSlots[slot].mBufferState);
+        return BAD_VALUE;
+    } else if (!mSlots[slot].mRequestBufferCalled) {
+        BQ_LOGE("detachBuffer(P): buffer in slot %d has not been requested",
+                slot);
+        return BAD_VALUE;
+    }
+
+    mCore->freeBufferLocked(slot);
+    mCore->mDequeueCondition.broadcast();
+
+    return NO_ERROR;
+}
+
+status_t BufferQueueProducer::attachBuffer(int* outSlot,
+        const sp<android::GraphicBuffer>& buffer) {
+    ATRACE_CALL();
+
+    if (outSlot == NULL) {
+        BQ_LOGE("attachBuffer(P): outSlot must not be NULL");
+        return BAD_VALUE;
+    } else if (buffer == NULL) {
+        BQ_LOGE("attachBuffer(P): cannot attach NULL buffer");
+        return BAD_VALUE;
+    }
+
+    Mutex::Autolock lock(mCore->mMutex);
+
+    status_t returnFlags = NO_ERROR;
+    int found;
+    // TODO: Should we provide an async flag to attachBuffer? It seems
+    // unlikely that buffers which we are attaching to a BufferQueue will
+    // be asynchronous (droppable), but it may not be impossible.
+    status_t status = waitForFreeSlotThenRelock("attachBuffer(P)", false,
+            &found, &returnFlags);
+    if (status != NO_ERROR) {
+        return status;
+    }
+
+    // This should not happen
+    if (found == BufferQueueCore::INVALID_BUFFER_SLOT) {
+        BQ_LOGE("attachBuffer(P): no available buffer slots");
+        return -EBUSY;
+    }
+
+    *outSlot = found;
+    ATRACE_BUFFER_INDEX(*outSlot);
+    BQ_LOGV("attachBuffer(P): returning slot %d flags=%#x",
+            *outSlot, returnFlags);
+
+    mSlots[*outSlot].mGraphicBuffer = buffer;
+    mSlots[*outSlot].mBufferState = BufferSlot::DEQUEUED;
+    mSlots[*outSlot].mEglFence = EGL_NO_SYNC_KHR;
+    mSlots[*outSlot].mFence = Fence::NO_FENCE;
+
+    return returnFlags;
+}
+
+status_t BufferQueueProducer::queueBuffer(int slot,
+        const QueueBufferInput &input, QueueBufferOutput *output) {
+    ATRACE_CALL();
+    ATRACE_BUFFER_INDEX(slot);
+
+    int64_t timestamp;
+    bool isAutoTimestamp;
+    Rect crop;
+    int scalingMode;
+    uint32_t transform;
+    bool async;
+    sp<Fence> fence;
+    input.deflate(&timestamp, &isAutoTimestamp, &crop, &scalingMode, &transform,
+            &async, &fence);
+
+    if (fence == NULL) {
+        BQ_LOGE("queueBuffer: fence is NULL");
+        return BAD_VALUE;
+    }
+
+    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:
+            BQ_LOGE("queueBuffer: unknown scaling mode %d", scalingMode);
+            return BAD_VALUE;
+    }
+
+    sp<IConsumerListener> listener;
+    { // Autolock scope
+        Mutex::Autolock lock(mCore->mMutex);
+
+        if (mCore->mIsAbandoned) {
+            BQ_LOGE("queueBuffer: BufferQueue has been abandoned");
+            return NO_INIT;
+        }
+
+        const int maxBufferCount = mCore->getMaxBufferCountLocked(async);
+        if (async && mCore->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 (mCore->mOverrideMaxBufferCount < maxBufferCount) {
+                BQ_LOGE("queueBuffer: async mode is invalid with "
+                        "buffer count override");
+                return BAD_VALUE;
+            }
+        }
+
+        if (slot < 0 || slot >= maxBufferCount) {
+            BQ_LOGE("queueBuffer: slot index %d out of range [0, %d)",
+                    slot, maxBufferCount);
+            return BAD_VALUE;
+        } else if (mSlots[slot].mBufferState != BufferSlot::DEQUEUED) {
+            BQ_LOGE("queueBuffer: slot %d is not owned by the producer "
+                    "(state = %d)", slot, mSlots[slot].mBufferState);
+            return BAD_VALUE;
+        } else if (!mSlots[slot].mRequestBufferCalled) {
+            BQ_LOGE("queueBuffer: slot %d was queued without requesting "
+                    "a buffer", slot);
+            return BAD_VALUE;
+        }
+
+        BQ_LOGV("queueBuffer: slot=%d/%llu time=%llu crop=[%d,%d,%d,%d] "
+                "transform=%#x scale=%s",
+                slot, mCore->mFrameCounter + 1, timestamp,
+                crop.left, crop.top, crop.right, crop.bottom,
+                transform, BufferItem::scalingModeName(scalingMode));
+
+        const sp<GraphicBuffer>& graphicBuffer(mSlots[slot].mGraphicBuffer);
+        Rect bufferRect(graphicBuffer->getWidth(), graphicBuffer->getHeight());
+        Rect croppedRect;
+        crop.intersect(bufferRect, &croppedRect);
+        if (croppedRect != crop) {
+            BQ_LOGE("queueBuffer: crop rect is not contained within the "
+                    "buffer in slot %d", slot);
+            return BAD_VALUE;
+        }
+
+        mSlots[slot].mFence = fence;
+        mSlots[slot].mBufferState = BufferSlot::QUEUED;
+        ++mCore->mFrameCounter;
+        mSlots[slot].mFrameNumber = mCore->mFrameCounter;
+
+        BufferItem item;
+        item.mAcquireCalled = mSlots[slot].mAcquireCalled;
+        item.mGraphicBuffer = mSlots[slot].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 = mCore->mFrameCounter;
+        item.mSlot = slot;
+        item.mFence = fence;
+        item.mIsDroppable = mCore->mDequeueBufferCannotBlock || async;
+
+        if (mCore->mQueue.empty()) {
+            // When the queue is empty, we can ignore mDequeueBufferCannotBlock
+            // and simply queue this buffer
+            mCore->mQueue.push_back(item);
+            listener = mCore->mConsumerListener;
+        } else {
+            // When the queue is not empty, we need to look at the front buffer
+            // state to see if we need to replace it
+            BufferQueueCore::Fifo::iterator front(mCore->mQueue.begin());
+            if (front->mIsDroppable) {
+                // If the front queued buffer is still being tracked, we first
+                // mark it as freed
+                if (mCore->stillTracking(front)) {
+                    mSlots[front->mSlot].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->mSlot].mFrameNumber = 0;
+                }
+                // Overwrite the droppable buffer with the incoming one
+                *front = item;
+            } else {
+                mCore->mQueue.push_back(item);
+                listener = mCore->mConsumerListener;
+            }
+        }
+
+        mCore->mBufferHasBeenQueued = true;
+        mCore->mDequeueCondition.broadcast();
+
+        output->inflate(mCore->mDefaultWidth, mCore->mDefaultHeight,
+                mCore->mTransformHint, mCore->mQueue.size());
+
+        ATRACE_INT(mCore->mConsumerName.string(), mCore->mQueue.size());
+    } // Autolock scope
+
+    // Call back without lock held
+    if (listener != NULL) {
+        listener->onFrameAvailable();
+    }
+
+    return NO_ERROR;
+}
+
+void BufferQueueProducer::cancelBuffer(int slot, const sp<Fence>& fence) {
+    ATRACE_CALL();
+    BQ_LOGV("cancelBuffer: slot %d", slot);
+    Mutex::Autolock lock(mCore->mMutex);
+
+    if (mCore->mIsAbandoned) {
+        BQ_LOGE("cancelBuffer: BufferQueue has been abandoned");
+        return;
+    }
+
+    if (slot < 0 || slot >= BufferQueueDefs::NUM_BUFFER_SLOTS) {
+        BQ_LOGE("cancelBuffer: slot index %d out of range [0, %d)",
+                slot, BufferQueueDefs::NUM_BUFFER_SLOTS);
+        return;
+    } else if (mSlots[slot].mBufferState != BufferSlot::DEQUEUED) {
+        BQ_LOGE("cancelBuffer: slot %d is not owned by the producer "
+                "(state = %d)", slot, mSlots[slot].mBufferState);
+        return;
+    } else if (fence == NULL) {
+        BQ_LOGE("cancelBuffer: fence is NULL");
+        return;
+    }
+
+    mSlots[slot].mBufferState = BufferSlot::FREE;
+    mSlots[slot].mFrameNumber = 0;
+    mSlots[slot].mFence = fence;
+    mCore->mDequeueCondition.broadcast();
+}
+
+int BufferQueueProducer::query(int what, int *outValue) {
+    ATRACE_CALL();
+    Mutex::Autolock lock(mCore->mMutex);
+
+    if (outValue == NULL) {
+        BQ_LOGE("query: outValue was NULL");
+        return BAD_VALUE;
+    }
+
+    if (mCore->mIsAbandoned) {
+        BQ_LOGE("query: BufferQueue has been abandoned");
+        return NO_INIT;
+    }
+
+    int value;
+    switch (what) {
+        case NATIVE_WINDOW_WIDTH:
+            value = mCore->mDefaultWidth;
+            break;
+        case NATIVE_WINDOW_HEIGHT:
+            value = mCore->mDefaultHeight;
+            break;
+        case NATIVE_WINDOW_FORMAT:
+            value = mCore->mDefaultBufferFormat;
+            break;
+        case NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS:
+            value = mCore->getMinUndequeuedBufferCountLocked(false);
+            break;
+        case NATIVE_WINDOW_CONSUMER_RUNNING_BEHIND:
+            value = (mCore->mQueue.size() > 1);
+            break;
+        case NATIVE_WINDOW_CONSUMER_USAGE_BITS:
+            value = mCore->mConsumerUsageBits;
+            break;
+        default:
+            return BAD_VALUE;
+    }
+
+    BQ_LOGV("query: %d? %d", what, value);
+    *outValue = value;
+    return NO_ERROR;
+}
+
+status_t BufferQueueProducer::connect(const sp<android::IBinder> &token,
+        int api, bool producerControlledByApp, QueueBufferOutput *output) {
+    ATRACE_CALL();
+    Mutex::Autolock lock(mCore->mMutex);
+    mConsumerName = mCore->mConsumerName;
+    BQ_LOGV("connect(P): api=%d producerControlledByApp=%s", api,
+            producerControlledByApp ? "true" : "false");
+
+    // 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.
+    while (true) {
+        if (mCore->mIsAbandoned) {
+            BQ_LOGE("connect(P): BufferQueue has been abandoned");
+            return NO_INIT;
+        }
+
+        if (mCore->mConsumerListener == NULL) {
+            BQ_LOGE("connect(P): BufferQueue has no consumer");
+            return NO_INIT;
+        }
+
+        if (output == NULL) {
+            BQ_LOGE("connect(P): output was NULL");
+            return BAD_VALUE;
+        }
+
+        if (mCore->mConnectedApi != BufferQueueCore::NO_CONNECTED_API) {
+            BQ_LOGE("connect(P): already connected (cur=%d req=%d)",
+                    mCore->mConnectedApi, api);
+            return BAD_VALUE;
+        }
+
+        size_t maxBufferCount = mCore->getMaxBufferCountLocked(false);
+        if (mCore->mQueue.size() <= maxBufferCount) {
+            // The queue size seems small enough to proceed
+            // TODO: Make this bound tighter?
+            break;
+        }
+
+        BQ_LOGV("connect(P): queue size is %d, waiting", mCore->mQueue.size());
+        mCore->mDequeueCondition.wait(mCore->mMutex);
+    }
+
+    int status = NO_ERROR;
+    switch (api) {
+        case NATIVE_WINDOW_API_EGL:
+        case NATIVE_WINDOW_API_CPU:
+        case NATIVE_WINDOW_API_MEDIA:
+        case NATIVE_WINDOW_API_CAMERA:
+            mCore->mConnectedApi = api;
+            output->inflate(mCore->mDefaultWidth, mCore->mDefaultHeight,
+                    mCore->mTransformHint, mCore->mQueue.size());
+
+            // Set up a death notification so that we can disconnect
+            // automatically if the remote producer dies
+            if (token != NULL && token->remoteBinder() != NULL) {
+                status = token->linkToDeath(
+                        static_cast<IBinder::DeathRecipient*>(this));
+                if (status == NO_ERROR) {
+                    mCore->mConnectedProducerToken = token;
+                } else {
+                    BQ_LOGE("connect(P): linkToDeath failed: %s (%d)",
+                            strerror(-status), status);
+                }
+            }
+            break;
+        default:
+            BQ_LOGE("connect(P): unknown API %d", api);
+            status = BAD_VALUE;
+            break;
+    }
+
+    mCore->mBufferHasBeenQueued = false;
+    mCore->mDequeueBufferCannotBlock =
+            mCore->mConsumerControlledByApp && producerControlledByApp;
+
+    return status;
+}
+
+status_t BufferQueueProducer::disconnect(int api) {
+    ATRACE_CALL();
+    BQ_LOGV("disconnect(P): api %d", api);
+
+    int status = NO_ERROR;
+    sp<IConsumerListener> listener;
+    { // Autolock scope
+        Mutex::Autolock lock(mCore->mMutex);
+
+        if (mCore->mIsAbandoned) {
+            // It's 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 (mCore->mConnectedApi == api) {
+                    mCore->freeAllBuffersLocked();
+
+                    // Remove our death notification callback if we have one
+                    sp<IBinder> token = mCore->mConnectedProducerToken;
+                    if (token != NULL) {
+                        // This can fail if we're here because of the death
+                        // notification, but we just ignore it
+                        token->unlinkToDeath(
+                                static_cast<IBinder::DeathRecipient*>(this));
+                    }
+                    mCore->mConnectedProducerToken = NULL;
+                    mCore->mConnectedApi = BufferQueueCore::NO_CONNECTED_API;
+                    mCore->mSidebandStream.clear();
+                    mCore->mDequeueCondition.broadcast();
+                    listener = mCore->mConsumerListener;
+                } else {
+                    BQ_LOGE("disconnect(P): connected to another API "
+                            "(cur=%d req=%d)", mCore->mConnectedApi, api);
+                    status = BAD_VALUE;
+                }
+                break;
+            default:
+                BQ_LOGE("disconnect(P): unknown API %d", api);
+                status = BAD_VALUE;
+                break;
+        }
+    } // Autolock scope
+
+    // Call back without lock held
+    if (listener != NULL) {
+        listener->onBuffersReleased();
+    }
+
+    return status;
+}
+
+status_t BufferQueueProducer::setSidebandStream(const sp<NativeHandle>& stream) {
+    Mutex::Autolock _l(mCore->mMutex);
+    mCore->mSidebandStream = stream;
+    return NO_ERROR;
+}
+
+void BufferQueueProducer::binderDied(const wp<android::IBinder>& /* who */) {
+    // If we're here, it means that a producer we were connected to died.
+    // We're guaranteed that we are still connected to it because we remove
+    // this callback upon disconnect. It's therefore safe to read mConnectedApi
+    // without synchronization here.
+    int api = mCore->mConnectedApi;
+    disconnect(api);
+}
+
+} // namespace android
diff --git a/libs/gui/BufferSlot.cpp b/libs/gui/BufferSlot.cpp
new file mode 100644
index 0000000..b8877fe
--- /dev/null
+++ b/libs/gui/BufferSlot.cpp
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2014 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.
+ */
+
+#include <gui/BufferSlot.h>
+
+namespace android {
+
+const char* BufferSlot::bufferStateName(BufferState state) {
+    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";
+    }
+}
+
+} // namespace android
diff --git a/libs/gui/ConsumerBase.cpp b/libs/gui/ConsumerBase.cpp
index c5900aa..b6adc54 100644
--- a/libs/gui/ConsumerBase.cpp
+++ b/libs/gui/ConsumerBase.cpp
@@ -130,6 +130,9 @@
     }
 }
 
+void ConsumerBase::onSidebandStreamChanged() {
+}
+
 void ConsumerBase::abandon() {
     CB_LOGV("abandon");
     Mutex::Autolock lock(mMutex);
diff --git a/libs/gui/IConsumerListener.cpp b/libs/gui/IConsumerListener.cpp
index 5304462..4ccf0ac 100644
--- a/libs/gui/IConsumerListener.cpp
+++ b/libs/gui/IConsumerListener.cpp
@@ -28,7 +28,8 @@
 
 enum {
     ON_FRAME_AVAILABLE = IBinder::FIRST_CALL_TRANSACTION,
-    ON_BUFFER_RELEASED
+    ON_BUFFER_RELEASED,
+    ON_SIDEBAND_STREAM_CHANGED,
 };
 
 class BpConsumerListener : public BpInterface<IConsumerListener>
@@ -49,6 +50,12 @@
         data.writeInterfaceToken(IConsumerListener::getInterfaceDescriptor());
         remote()->transact(ON_BUFFER_RELEASED, data, &reply, IBinder::FLAG_ONEWAY);
     }
+
+    virtual void onSidebandStreamChanged() {
+        Parcel data, reply;
+        data.writeInterfaceToken(IConsumerListener::getInterfaceDescriptor());
+        remote()->transact(ON_SIDEBAND_STREAM_CHANGED, data, &reply, IBinder::FLAG_ONEWAY);
+    }
 };
 
 IMPLEMENT_META_INTERFACE(ConsumerListener, "android.gui.IConsumerListener");
@@ -67,6 +74,10 @@
             CHECK_INTERFACE(IConsumerListener, data, reply);
             onBuffersReleased();
             return NO_ERROR;
+        case ON_SIDEBAND_STREAM_CHANGED:
+            CHECK_INTERFACE(IConsumerListener, data, reply);
+            onSidebandStreamChanged();
+            return NO_ERROR;
     }
     return BBinder::onTransact(code, data, reply, flags);
 }
diff --git a/libs/gui/IGraphicBufferConsumer.cpp b/libs/gui/IGraphicBufferConsumer.cpp
index 876c895..3598a86 100644
--- a/libs/gui/IGraphicBufferConsumer.cpp
+++ b/libs/gui/IGraphicBufferConsumer.cpp
@@ -24,6 +24,7 @@
 #include <sys/types.h>
 
 #include <utils/Errors.h>
+#include <utils/NativeHandle.h>
 
 #include <binder/Parcel.h>
 #include <binder/IInterface.h>
@@ -183,6 +184,8 @@
 
 enum {
     ACQUIRE_BUFFER = IBinder::FIRST_CALL_TRANSACTION,
+    DETACH_BUFFER,
+    ATTACH_BUFFER,
     RELEASE_BUFFER,
     CONSUMER_CONNECT,
     CONSUMER_DISCONNECT,
@@ -195,6 +198,7 @@
     SET_DEFAULT_BUFFER_FORMAT,
     SET_CONSUMER_USAGE_BITS,
     SET_TRANSFORM_HINT,
+    GET_SIDEBAND_STREAM,
     DUMP,
 };
 
@@ -222,6 +226,31 @@
         return reply.readInt32();
     }
 
+    virtual status_t detachBuffer(int slot) {
+        Parcel data, reply;
+        data.writeInterfaceToken(IGraphicBufferConsumer::getInterfaceDescriptor());
+        data.writeInt32(slot);
+        status_t result = remote()->transact(DETACH_BUFFER, data, &reply);
+        if (result != NO_ERROR) {
+            return result;
+        }
+        result = reply.readInt32();
+        return result;
+    }
+
+    virtual status_t attachBuffer(int* slot, const sp<GraphicBuffer>& buffer) {
+        Parcel data, reply;
+        data.writeInterfaceToken(IGraphicBufferConsumer::getInterfaceDescriptor());
+        data.write(*buffer.get());
+        status_t result = remote()->transact(ATTACH_BUFFER, data, &reply);
+        if (result != NO_ERROR) {
+            return result;
+        }
+        *slot = reply.readInt32();
+        result = reply.readInt32();
+        return result;
+    }
+
     virtual status_t releaseBuffer(int buf, uint64_t frameNumber,
             EGLDisplay display __attribute__((unused)), EGLSyncKHR fence __attribute__((unused)),
             const sp<Fence>& releaseFence) {
@@ -354,6 +383,20 @@
         return reply.readInt32();
     }
 
+    virtual sp<NativeHandle> getSidebandStream() const {
+        Parcel data, reply;
+        status_t err;
+        data.writeInterfaceToken(IGraphicBufferConsumer::getInterfaceDescriptor());
+        if ((err = remote()->transact(GET_SIDEBAND_STREAM, data, &reply)) != NO_ERROR) {
+            return NULL;
+        }
+        sp<NativeHandle> stream;
+        if (reply.readInt32()) {
+            stream = NativeHandle::create(reply.readNativeHandle());
+        }
+        return stream;
+    }
+
     virtual void dump(String8& result, const char* prefix) const {
         Parcel data, reply;
         data.writeInterfaceToken(IGraphicBufferConsumer::getInterfaceDescriptor());
@@ -382,6 +425,23 @@
             reply->writeInt32(result);
             return NO_ERROR;
         } break;
+        case DETACH_BUFFER: {
+            CHECK_INTERFACE(IGraphicBufferConsumer, data, reply);
+            int slot = data.readInt32();
+            int result = detachBuffer(slot);
+            reply->writeInt32(result);
+            return NO_ERROR;
+        } break;
+        case ATTACH_BUFFER: {
+            CHECK_INTERFACE(IGraphicBufferConsumer, data, reply);
+            sp<GraphicBuffer> buffer = new GraphicBuffer();
+            data.read(*buffer.get());
+            int slot;
+            int result = attachBuffer(&slot, buffer);
+            reply->writeInt32(slot);
+            reply->writeInt32(result);
+            return NO_ERROR;
+        } break;
         case RELEASE_BUFFER: {
             CHECK_INTERFACE(IGraphicBufferConsumer, data, reply);
             int buf = data.readInt32();
diff --git a/libs/gui/IGraphicBufferProducer.cpp b/libs/gui/IGraphicBufferProducer.cpp
index 0f461e5..1d4ec1c 100644
--- a/libs/gui/IGraphicBufferProducer.cpp
+++ b/libs/gui/IGraphicBufferProducer.cpp
@@ -18,9 +18,10 @@
 #include <sys/types.h>
 
 #include <utils/Errors.h>
+#include <utils/NativeHandle.h>
 #include <utils/RefBase.h>
-#include <utils/Vector.h>
 #include <utils/Timers.h>
+#include <utils/Vector.h>
 
 #include <binder/Parcel.h>
 #include <binder/IInterface.h>
@@ -34,11 +35,14 @@
     REQUEST_BUFFER = IBinder::FIRST_CALL_TRANSACTION,
     SET_BUFFER_COUNT,
     DEQUEUE_BUFFER,
+    DETACH_BUFFER,
+    ATTACH_BUFFER,
     QUEUE_BUFFER,
     CANCEL_BUFFER,
     QUERY,
     CONNECT,
     DISCONNECT,
+    SET_SIDEBAND_STREAM,
 };
 
 class BpGraphicBufferProducer : public BpInterface<IGraphicBufferProducer>
@@ -106,6 +110,31 @@
         return result;
     }
 
+    virtual status_t detachBuffer(int slot) {
+        Parcel data, reply;
+        data.writeInterfaceToken(IGraphicBufferProducer::getInterfaceDescriptor());
+        data.writeInt32(slot);
+        status_t result = remote()->transact(DETACH_BUFFER, data, &reply);
+        if (result != NO_ERROR) {
+            return result;
+        }
+        result = reply.readInt32();
+        return result;
+    }
+
+    virtual status_t attachBuffer(int* slot, const sp<GraphicBuffer>& buffer) {
+        Parcel data, reply;
+        data.writeInterfaceToken(IGraphicBufferProducer::getInterfaceDescriptor());
+        data.write(*buffer.get());
+        status_t result = remote()->transact(ATTACH_BUFFER, data, &reply);
+        if (result != NO_ERROR) {
+            return result;
+        }
+        *slot = reply.readInt32();
+        result = reply.readInt32();
+        return result;
+    }
+
     virtual status_t queueBuffer(int buf,
             const QueueBufferInput& input, QueueBufferOutput* output) {
         Parcel data, reply;
@@ -169,6 +198,22 @@
         result = reply.readInt32();
         return result;
     }
+
+    virtual status_t setSidebandStream(const sp<NativeHandle>& stream) {
+        Parcel data, reply;
+        status_t result;
+        data.writeInterfaceToken(IGraphicBufferProducer::getInterfaceDescriptor());
+        if (stream.get()) {
+            data.writeInt32(true);
+            data.writeNativeHandle(stream->handle());
+        } else {
+            data.writeInt32(false);
+        }
+        if ((result = remote()->transact(SET_SIDEBAND_STREAM, data, &reply)) == NO_ERROR) {
+            result = reply.readInt32();
+        }
+        return result;
+    }
 };
 
 IMPLEMENT_META_INTERFACE(GraphicBufferProducer, "android.gui.IGraphicBufferProducer");
@@ -216,6 +261,23 @@
             reply->writeInt32(result);
             return NO_ERROR;
         } break;
+        case DETACH_BUFFER: {
+            CHECK_INTERFACE(IGraphicBufferProducer, data, reply);
+            int slot = data.readInt32();
+            int result = detachBuffer(slot);
+            reply->writeInt32(result);
+            return NO_ERROR;
+        } break;
+        case ATTACH_BUFFER: {
+            CHECK_INTERFACE(IGraphicBufferProducer, data, reply);
+            sp<GraphicBuffer> buffer = new GraphicBuffer();
+            data.read(*buffer.get());
+            int slot;
+            int result = attachBuffer(&slot, buffer);
+            reply->writeInt32(slot);
+            reply->writeInt32(result);
+            return NO_ERROR;
+        } break;
         case QUEUE_BUFFER: {
             CHECK_INTERFACE(IGraphicBufferProducer, data, reply);
             int buf = data.readInt32();
@@ -263,6 +325,16 @@
             reply->writeInt32(res);
             return NO_ERROR;
         } break;
+        case SET_SIDEBAND_STREAM: {
+            CHECK_INTERFACE(IGraphicBufferProducer, data, reply);
+            sp<NativeHandle> stream;
+            if (data.readInt32()) {
+                stream = NativeHandle::create(data.readNativeHandle());
+            }
+            status_t result = setSidebandStream(stream);
+            reply->writeInt32(result);
+            return NO_ERROR;
+        } break;
     }
     return BBinder::onTransact(code, data, reply, flags);
 }
diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp
index 975d005..b628a15 100644
--- a/libs/gui/Surface.cpp
+++ b/libs/gui/Surface.cpp
@@ -178,19 +178,38 @@
 int Surface::dequeueBuffer(android_native_buffer_t** buffer, int* fenceFd) {
     ATRACE_CALL();
     ALOGV("Surface::dequeueBuffer");
-    Mutex::Autolock lock(mMutex);
+
+    int reqW;
+    int reqH;
+    bool swapIntervalZero;
+    uint32_t reqFormat;
+    uint32_t reqUsage;
+
+    {
+        Mutex::Autolock lock(mMutex);
+
+        reqW = mReqWidth ? mReqWidth : mUserWidth;
+        reqH = mReqHeight ? mReqHeight : mUserHeight;
+
+        swapIntervalZero = mSwapIntervalZero;
+        reqFormat = mReqFormat;
+        reqUsage = mReqUsage;
+    } // Drop the lock so that we can still touch the Surface while blocking in IGBP::dequeueBuffer
+
     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);
+    status_t result = mGraphicBufferProducer->dequeueBuffer(&buf, &fence, swapIntervalZero,
+            reqW, reqH, reqFormat, reqUsage);
+
     if (result < 0) {
-        ALOGV("dequeueBuffer: IGraphicBufferProducer::dequeueBuffer(%d, %d, %d, %d)"
-             "failed: %d", mReqWidth, mReqHeight, mReqFormat, mReqUsage,
+        ALOGV("dequeueBuffer: IGraphicBufferProducer::dequeueBuffer(%d, %d, %d, %d, %d)"
+             "failed: %d", swapIntervalZero, reqW, reqH, reqFormat, reqUsage,
              result);
         return result;
     }
+
+    Mutex::Autolock lock(mMutex);
+
     sp<GraphicBuffer>& gbuf(mSlots[buf].buffer);
 
     // this should never happen
diff --git a/libs/gui/tests/BufferQueue_test.cpp b/libs/gui/tests/BufferQueue_test.cpp
index 06f9a92..5aa34a5 100644
--- a/libs/gui/tests/BufferQueue_test.cpp
+++ b/libs/gui/tests/BufferQueue_test.cpp
@@ -23,29 +23,32 @@
 #include <utils/threads.h>
 
 #include <ui/GraphicBuffer.h>
-#include <ui/FramebufferNativeWindow.h>
 
+#include <binder/IServiceManager.h>
 #include <gui/BufferQueue.h>
 
 namespace android {
 
 class BufferQueueTest : public ::testing::Test {
+
+public:
+    static const String16 PRODUCER_NAME;
+    static const String16 CONSUMER_NAME;
+
 protected:
-
-    BufferQueueTest() {}
-
-    virtual void SetUp() {
+    BufferQueueTest() {
         const ::testing::TestInfo* const testInfo =
             ::testing::UnitTest::GetInstance()->current_test_info();
         ALOGV("Begin test: %s.%s", testInfo->test_case_name(),
                 testInfo->name());
 
-        mBQ = new BufferQueue();
+        BufferQueue::createBufferQueue(&mProducer, &mConsumer);
+        sp<IServiceManager> serviceManager = defaultServiceManager();
+        serviceManager->addService(PRODUCER_NAME, mProducer.get());
+        serviceManager->addService(CONSUMER_NAME, mConsumer.get());
     }
 
-    virtual void TearDown() {
-        mBQ.clear();
-
+    ~BufferQueueTest() {
         const ::testing::TestInfo* const testInfo =
             ::testing::UnitTest::GetInstance()->current_test_info();
         ALOGV("End test:   %s.%s", testInfo->test_case_name(),
@@ -53,25 +56,31 @@
     }
 
     void GetMinUndequeuedBufferCount(int* bufferCount) {
-        ASSERT_NE((void*)NULL, bufferCount);
-        ASSERT_EQ(OK, mBQ->query(NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS, bufferCount));
-        ASSERT_LE(0, *bufferCount); // non-negative
+        ASSERT_TRUE(bufferCount != NULL);
+        ASSERT_EQ(OK, mProducer->query(NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS,
+                    bufferCount));
+        ASSERT_GE(*bufferCount, 0);
     }
 
-    sp<BufferQueue> mBQ;
+    sp<BnGraphicBufferProducer> mProducer;
+    sp<BnGraphicBufferConsumer> mConsumer;
 };
 
+const String16 BufferQueueTest::PRODUCER_NAME = String16("BQTestProducer");
+const String16 BufferQueueTest::CONSUMER_NAME = String16("BQTestConsumer");
+
 struct DummyConsumer : public BnConsumerListener {
     virtual void onFrameAvailable() {}
     virtual void onBuffersReleased() {}
+    virtual void onSidebandStreamChanged() {}
 };
 
 TEST_F(BufferQueueTest, AcquireBuffer_ExceedsMaxAcquireCount_Fails) {
     sp<DummyConsumer> dc(new DummyConsumer);
-    mBQ->consumerConnect(dc, false);
+    mConsumer->consumerConnect(dc, false);
     IGraphicBufferProducer::QueueBufferOutput qbo;
-    mBQ->connect(NULL, NATIVE_WINDOW_API_CPU, false, &qbo);
-    mBQ->setBufferCount(4);
+    mProducer->connect(NULL, NATIVE_WINDOW_API_CPU, false, &qbo);
+    mProducer->setBufferCount(4);
 
     int slot;
     sp<Fence> fence;
@@ -82,50 +91,198 @@
 
     for (int i = 0; i < 2; i++) {
         ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION,
-                mBQ->dequeueBuffer(&slot, &fence, false, 1, 1, 0,
+                mProducer->dequeueBuffer(&slot, &fence, false, 1, 1, 0,
                     GRALLOC_USAGE_SW_READ_OFTEN));
-        ASSERT_EQ(OK, mBQ->requestBuffer(slot, &buf));
-        ASSERT_EQ(OK, mBQ->queueBuffer(slot, qbi, &qbo));
-        ASSERT_EQ(OK, mBQ->acquireBuffer(&item, 0));
+        ASSERT_EQ(OK, mProducer->requestBuffer(slot, &buf));
+        ASSERT_EQ(OK, mProducer->queueBuffer(slot, qbi, &qbo));
+        ASSERT_EQ(OK, mConsumer->acquireBuffer(&item, 0));
     }
 
     ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION,
-            mBQ->dequeueBuffer(&slot, &fence, false, 1, 1, 0,
+            mProducer->dequeueBuffer(&slot, &fence, false, 1, 1, 0,
                 GRALLOC_USAGE_SW_READ_OFTEN));
-    ASSERT_EQ(OK, mBQ->requestBuffer(slot, &buf));
-    ASSERT_EQ(OK, mBQ->queueBuffer(slot, qbi, &qbo));
+    ASSERT_EQ(OK, mProducer->requestBuffer(slot, &buf));
+    ASSERT_EQ(OK, mProducer->queueBuffer(slot, qbi, &qbo));
 
     // Acquire the third buffer, which should fail.
-    ASSERT_EQ(INVALID_OPERATION, mBQ->acquireBuffer(&item, 0));
+    ASSERT_EQ(INVALID_OPERATION, mConsumer->acquireBuffer(&item, 0));
 }
 
 TEST_F(BufferQueueTest, SetMaxAcquiredBufferCountWithIllegalValues_ReturnsError) {
     sp<DummyConsumer> dc(new DummyConsumer);
-    mBQ->consumerConnect(dc, false);
+    mConsumer->consumerConnect(dc, false);
 
     int minBufferCount;
     ASSERT_NO_FATAL_FAILURE(GetMinUndequeuedBufferCount(&minBufferCount));
-    EXPECT_EQ(BAD_VALUE, mBQ->setMaxAcquiredBufferCount(minBufferCount - 1));
+    EXPECT_EQ(BAD_VALUE, mConsumer->setMaxAcquiredBufferCount(
+                minBufferCount - 1));
 
-    EXPECT_EQ(BAD_VALUE, mBQ->setMaxAcquiredBufferCount(0));
-    EXPECT_EQ(BAD_VALUE, mBQ->setMaxAcquiredBufferCount(-3));
-    EXPECT_EQ(BAD_VALUE, mBQ->setMaxAcquiredBufferCount(
+    EXPECT_EQ(BAD_VALUE, mConsumer->setMaxAcquiredBufferCount(0));
+    EXPECT_EQ(BAD_VALUE, mConsumer->setMaxAcquiredBufferCount(-3));
+    EXPECT_EQ(BAD_VALUE, mConsumer->setMaxAcquiredBufferCount(
             BufferQueue::MAX_MAX_ACQUIRED_BUFFERS+1));
-    EXPECT_EQ(BAD_VALUE, mBQ->setMaxAcquiredBufferCount(100));
+    EXPECT_EQ(BAD_VALUE, mConsumer->setMaxAcquiredBufferCount(100));
 }
 
 TEST_F(BufferQueueTest, SetMaxAcquiredBufferCountWithLegalValues_Succeeds) {
     sp<DummyConsumer> dc(new DummyConsumer);
-    mBQ->consumerConnect(dc, false);
+    mConsumer->consumerConnect(dc, false);
 
     int minBufferCount;
     ASSERT_NO_FATAL_FAILURE(GetMinUndequeuedBufferCount(&minBufferCount));
 
-    EXPECT_EQ(OK, mBQ->setMaxAcquiredBufferCount(1));
-    EXPECT_EQ(OK, mBQ->setMaxAcquiredBufferCount(2));
-    EXPECT_EQ(OK, mBQ->setMaxAcquiredBufferCount(minBufferCount));
-    EXPECT_EQ(OK, mBQ->setMaxAcquiredBufferCount(
+    EXPECT_EQ(OK, mConsumer->setMaxAcquiredBufferCount(1));
+    EXPECT_EQ(OK, mConsumer->setMaxAcquiredBufferCount(2));
+    EXPECT_EQ(OK, mConsumer->setMaxAcquiredBufferCount(minBufferCount));
+    EXPECT_EQ(OK, mConsumer->setMaxAcquiredBufferCount(
             BufferQueue::MAX_MAX_ACQUIRED_BUFFERS));
 }
 
+TEST_F(BufferQueueTest, DetachAndReattachOnProducerSide) {
+    sp<DummyConsumer> dc(new DummyConsumer);
+    ASSERT_EQ(OK, mConsumer->consumerConnect(dc, false));
+    IGraphicBufferProducer::QueueBufferOutput output;
+    ASSERT_EQ(OK,
+            mProducer->connect(NULL, NATIVE_WINDOW_API_CPU, false, &output));
+
+    ASSERT_EQ(BAD_VALUE, mProducer->detachBuffer(-1)); // Index too low
+    ASSERT_EQ(BAD_VALUE, mProducer->detachBuffer(
+                BufferQueueDefs::NUM_BUFFER_SLOTS)); // Index too high
+    ASSERT_EQ(BAD_VALUE, mProducer->detachBuffer(0)); // Not dequeued
+
+    int slot;
+    sp<Fence> fence;
+    sp<GraphicBuffer> buffer;
+    ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION,
+            mProducer->dequeueBuffer(&slot, &fence, false, 0, 0, 0,
+                    GRALLOC_USAGE_SW_WRITE_OFTEN));
+    ASSERT_EQ(BAD_VALUE, mProducer->detachBuffer(slot)); // Not requested
+    ASSERT_EQ(OK, mProducer->requestBuffer(slot, &buffer));
+    ASSERT_EQ(OK, mProducer->detachBuffer(slot));
+    ASSERT_EQ(BAD_VALUE, mProducer->detachBuffer(slot)); // Not dequeued
+
+    sp<GraphicBuffer> safeToClobberBuffer;
+    // Can no longer request buffer from this slot
+    ASSERT_EQ(BAD_VALUE, mProducer->requestBuffer(slot, &safeToClobberBuffer));
+
+    uint32_t* dataIn;
+    ASSERT_EQ(OK, buffer->lock(GraphicBuffer::USAGE_SW_WRITE_OFTEN,
+            reinterpret_cast<void**>(&dataIn)));
+    *dataIn = 0x12345678;
+    ASSERT_EQ(OK, buffer->unlock());
+
+    int newSlot;
+    ASSERT_EQ(BAD_VALUE, mProducer->attachBuffer(NULL, safeToClobberBuffer));
+    ASSERT_EQ(BAD_VALUE, mProducer->attachBuffer(&newSlot, NULL));
+
+    ASSERT_EQ(OK, mProducer->attachBuffer(&newSlot, buffer));
+    IGraphicBufferProducer::QueueBufferInput input(0, false, Rect(0, 0, 1, 1),
+            NATIVE_WINDOW_SCALING_MODE_FREEZE, 0, false, Fence::NO_FENCE);
+    ASSERT_EQ(OK, mProducer->queueBuffer(newSlot, input, &output));
+
+    IGraphicBufferConsumer::BufferItem item;
+    ASSERT_EQ(OK, mConsumer->acquireBuffer(&item, static_cast<nsecs_t>(0)));
+
+    uint32_t* dataOut;
+    ASSERT_EQ(OK, item.mGraphicBuffer->lock(GraphicBuffer::USAGE_SW_READ_OFTEN,
+            reinterpret_cast<void**>(&dataOut)));
+    ASSERT_EQ(*dataOut, 0x12345678);
+}
+
+TEST_F(BufferQueueTest, DetachAndReattachOnConsumerSide) {
+    sp<DummyConsumer> dc(new DummyConsumer);
+    ASSERT_EQ(OK, mConsumer->consumerConnect(dc, false));
+    IGraphicBufferProducer::QueueBufferOutput output;
+    ASSERT_EQ(OK,
+            mProducer->connect(NULL, NATIVE_WINDOW_API_CPU, false, &output));
+
+    int slot;
+    sp<Fence> fence;
+    sp<GraphicBuffer> buffer;
+    ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION,
+            mProducer->dequeueBuffer(&slot, &fence, false, 0, 0, 0,
+                    GRALLOC_USAGE_SW_WRITE_OFTEN));
+    ASSERT_EQ(OK, mProducer->requestBuffer(slot, &buffer));
+    IGraphicBufferProducer::QueueBufferInput input(0, false, Rect(0, 0, 1, 1),
+            NATIVE_WINDOW_SCALING_MODE_FREEZE, 0, false, Fence::NO_FENCE);
+    ASSERT_EQ(OK, mProducer->queueBuffer(slot, input, &output));
+
+    ASSERT_EQ(BAD_VALUE, mConsumer->detachBuffer(-1)); // Index too low
+    ASSERT_EQ(BAD_VALUE, mConsumer->detachBuffer(
+            BufferQueueDefs::NUM_BUFFER_SLOTS)); // Index too high
+    ASSERT_EQ(BAD_VALUE, mConsumer->detachBuffer(0)); // Not acquired
+
+    IGraphicBufferConsumer::BufferItem item;
+    ASSERT_EQ(OK, mConsumer->acquireBuffer(&item, static_cast<nsecs_t>(0)));
+
+    ASSERT_EQ(OK, mConsumer->detachBuffer(item.mBuf));
+    ASSERT_EQ(BAD_VALUE, mConsumer->detachBuffer(item.mBuf)); // Not acquired
+
+    uint32_t* dataIn;
+    ASSERT_EQ(OK, item.mGraphicBuffer->lock(
+            GraphicBuffer::USAGE_SW_WRITE_OFTEN,
+            reinterpret_cast<void**>(&dataIn)));
+    *dataIn = 0x12345678;
+    ASSERT_EQ(OK, item.mGraphicBuffer->unlock());
+
+    int newSlot;
+    sp<GraphicBuffer> safeToClobberBuffer;
+    ASSERT_EQ(BAD_VALUE, mConsumer->attachBuffer(NULL, safeToClobberBuffer));
+    ASSERT_EQ(BAD_VALUE, mConsumer->attachBuffer(&newSlot, NULL));
+    ASSERT_EQ(OK, mConsumer->attachBuffer(&newSlot, item.mGraphicBuffer));
+
+    ASSERT_EQ(OK, mConsumer->releaseBuffer(item.mBuf, 0, EGL_NO_DISPLAY,
+            EGL_NO_SYNC_KHR, Fence::NO_FENCE));
+
+    ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION,
+            mProducer->dequeueBuffer(&slot, &fence, false, 0, 0, 0,
+                    GRALLOC_USAGE_SW_WRITE_OFTEN));
+    ASSERT_EQ(OK, mProducer->requestBuffer(slot, &buffer));
+
+    uint32_t* dataOut;
+    ASSERT_EQ(OK, buffer->lock(GraphicBuffer::USAGE_SW_READ_OFTEN,
+            reinterpret_cast<void**>(&dataOut)));
+    ASSERT_EQ(*dataOut, 0x12345678);
+}
+
+TEST_F(BufferQueueTest, MoveFromConsumerToProducer) {
+    sp<DummyConsumer> dc(new DummyConsumer);
+    ASSERT_EQ(OK, mConsumer->consumerConnect(dc, false));
+    IGraphicBufferProducer::QueueBufferOutput output;
+    ASSERT_EQ(OK,
+            mProducer->connect(NULL, NATIVE_WINDOW_API_CPU, false, &output));
+
+    int slot;
+    sp<Fence> fence;
+    sp<GraphicBuffer> buffer;
+    ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION,
+            mProducer->dequeueBuffer(&slot, &fence, false, 0, 0, 0,
+                    GRALLOC_USAGE_SW_WRITE_OFTEN));
+    ASSERT_EQ(OK, mProducer->requestBuffer(slot, &buffer));
+
+    uint32_t* dataIn;
+    ASSERT_EQ(OK, buffer->lock(GraphicBuffer::USAGE_SW_WRITE_OFTEN,
+            reinterpret_cast<void**>(&dataIn)));
+    *dataIn = 0x12345678;
+    ASSERT_EQ(OK, buffer->unlock());
+
+    IGraphicBufferProducer::QueueBufferInput input(0, false, Rect(0, 0, 1, 1),
+            NATIVE_WINDOW_SCALING_MODE_FREEZE, 0, false, Fence::NO_FENCE);
+    ASSERT_EQ(OK, mProducer->queueBuffer(slot, input, &output));
+
+    IGraphicBufferConsumer::BufferItem item;
+    ASSERT_EQ(OK, mConsumer->acquireBuffer(&item, static_cast<nsecs_t>(0)));
+    ASSERT_EQ(OK, mConsumer->detachBuffer(item.mBuf));
+
+    int newSlot;
+    ASSERT_EQ(OK, mProducer->attachBuffer(&newSlot, item.mGraphicBuffer));
+    ASSERT_EQ(OK, mProducer->queueBuffer(newSlot, input, &output));
+    ASSERT_EQ(OK, mConsumer->acquireBuffer(&item, static_cast<nsecs_t>(0)));
+
+    uint32_t* dataOut;
+    ASSERT_EQ(OK, item.mGraphicBuffer->lock(GraphicBuffer::USAGE_SW_READ_OFTEN,
+            reinterpret_cast<void**>(&dataOut)));
+    ASSERT_EQ(*dataOut, 0x12345678);
+}
+
 } // namespace android
diff --git a/libs/gui/tests/CpuConsumer_test.cpp b/libs/gui/tests/CpuConsumer_test.cpp
index afbc026..9f61a09 100644
--- a/libs/gui/tests/CpuConsumer_test.cpp
+++ b/libs/gui/tests/CpuConsumer_test.cpp
@@ -33,8 +33,6 @@
 #include <utils/Mutex.h>
 #include <utils/Condition.h>
 
-#include <ui/FramebufferNativeWindow.h>
-
 #define CPU_CONSUMER_TEST_FORMAT_RAW 0
 #define CPU_CONSUMER_TEST_FORMAT_Y8 0
 #define CPU_CONSUMER_TEST_FORMAT_Y16 0
@@ -656,7 +654,7 @@
     ALOGV("Locking frame %d (too many)", params.maxLockedBuffers);
     CpuConsumer::LockedBuffer bTooMuch;
     err = mCC->lockNextBuffer(&bTooMuch);
-    ASSERT_TRUE(err == INVALID_OPERATION) << "Allowing too many locks";
+    ASSERT_TRUE(err == NOT_ENOUGH_DATA) << "Allowing too many locks";
 
     ALOGV("Unlocking frame 0");
     err = mCC->unlockBuffer(b[0]);
diff --git a/libs/gui/tests/DisconnectWaiter.h b/libs/gui/tests/DisconnectWaiter.h
index 3a30a19..56e96c2 100644
--- a/libs/gui/tests/DisconnectWaiter.h
+++ b/libs/gui/tests/DisconnectWaiter.h
@@ -57,6 +57,8 @@
         }
     }
 
+    virtual void onSidebandStreamChanged() {}
+
     void finishDisconnect() {
         Mutex::Autolock lock(mMutex);
         mWaitForDisconnect = true;
diff --git a/libs/gui/tests/IGraphicBufferProducer_test.cpp b/libs/gui/tests/IGraphicBufferProducer_test.cpp
index d16177b..c2653c2 100644
--- a/libs/gui/tests/IGraphicBufferProducer_test.cpp
+++ b/libs/gui/tests/IGraphicBufferProducer_test.cpp
@@ -23,7 +23,6 @@
 #include <utils/threads.h>
 
 #include <ui/GraphicBuffer.h>
-#include <ui/FramebufferNativeWindow.h>
 
 #include <gui/BufferQueue.h>
 
@@ -67,6 +66,7 @@
 struct DummyConsumer : public BnConsumerListener {
     virtual void onFrameAvailable() {}
     virtual void onBuffersReleased() {}
+    virtual void onSidebandStreamChanged() {}
 };
 
 class IGraphicBufferProducerTest : public ::testing::Test {
diff --git a/libs/ui/FramebufferNativeWindow.cpp b/libs/ui/FramebufferNativeWindow.cpp
index 31a69b2..918f2e7 100644
--- a/libs/ui/FramebufferNativeWindow.cpp
+++ b/libs/ui/FramebufferNativeWindow.cpp
@@ -259,8 +259,8 @@
     return 0;
 }
 
-int FramebufferNativeWindow::lockBuffer_DEPRECATED(ANativeWindow* window, 
-        ANativeWindowBuffer* buffer)
+int FramebufferNativeWindow::lockBuffer_DEPRECATED(ANativeWindow* /*window*/, 
+        ANativeWindowBuffer* /*buffer*/)
 {
     return NO_ERROR;
 }
@@ -326,7 +326,7 @@
     return BAD_VALUE;
 }
 
-int FramebufferNativeWindow::perform(ANativeWindow* window,
+int FramebufferNativeWindow::perform(ANativeWindow* /*window*/,
         int operation, ...)
 {
     switch (operation) {
diff --git a/libs/ui/Region.cpp b/libs/ui/Region.cpp
index 7de48a4..fa812f4 100644
--- a/libs/ui/Region.cpp
+++ b/libs/ui/Region.cpp
@@ -16,6 +16,7 @@
 
 #define LOG_TAG "Region"
 
+#include <inttypes.h>
 #include <limits.h>
 
 #include <utils/Log.h>
@@ -814,7 +815,7 @@
     size_t SIZE = 256;
     char buffer[SIZE];
 
-    snprintf(buffer, SIZE, "  Region %s (this=%p, count=%d)\n",
+    snprintf(buffer, SIZE, "  Region %s (this=%p, count=%" PRIdPTR ")\n",
             what, this, tail-head);
     out.append(buffer);
     while (head != tail) {
@@ -830,7 +831,7 @@
     (void)flags;
     const_iterator head = begin();
     const_iterator const tail = end();
-    ALOGD("  Region %s (this=%p, count=%d)\n", what, this, tail-head);
+    ALOGD("  Region %s (this=%p, count=%" PRIdPTR ")\n", what, this, tail-head);
     while (head != tail) {
         ALOGD("    [%3d, %3d, %3d, %3d]\n",
                 head->left, head->top, head->right, head->bottom);
diff --git a/libs/ui/tests/Android.mk b/libs/ui/tests/Android.mk
index 6f62a55..b0c57db 100644
--- a/libs/ui/tests/Android.mk
+++ b/libs/ui/tests/Android.mk
@@ -26,8 +26,6 @@
 )
 
 # Build the unit tests.
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
 
 # Build the manual test programs.
 include $(call all-makefiles-under, $(LOCAL_PATH))
diff --git a/opengl/libagl/BufferObjectManager.h b/opengl/libagl/BufferObjectManager.h
index 9e9340a..6487faa 100644
--- a/opengl/libagl/BufferObjectManager.h
+++ b/opengl/libagl/BufferObjectManager.h
@@ -69,10 +69,10 @@
     KeyedVector<GLuint, gl::buffer_t*>  mBuffers;
 };
 
-void EGLBufferObjectManager::incStrong(const void* id) const {
+void EGLBufferObjectManager::incStrong(const void* /*id*/) const {
     android_atomic_inc(&mCount);
 }
-void EGLBufferObjectManager::decStrong(const void* id) const {
+void EGLBufferObjectManager::decStrong(const void* /*id*/) const {
     if (android_atomic_dec(&mCount) == 1) {
         delete this;
     }
diff --git a/opengl/libagl/array.cpp b/opengl/libagl/array.cpp
index 7fbe9b5..54207fa 100644
--- a/opengl/libagl/array.cpp
+++ b/opengl/libagl/array.cpp
@@ -397,9 +397,9 @@
     }
 }
 
+#if VC_CACHE_STATISTICS
 void vertex_cache_t::dump_stats(GLenum mode)
 {
-#if VC_CACHE_STATISTICS
     nsecs_t time = systemTime(SYSTEM_TIME_THREAD) - startTime;
     uint32_t hits = total - misses;
     uint32_t prim_count;
@@ -418,8 +418,12 @@
             total, hits, misses, (hits*100)/total,
             prim_count, int(ns2us(time)), int(prim_count*float(seconds(1))/time),
             float(misses) / prim_count);
-#endif
 }
+#else
+void vertex_cache_t::dump_stats(GLenum /*mode*/)
+{
+}
+#endif
 
 // ----------------------------------------------------------------------------
 #if 0
diff --git a/opengl/libagl/egl.cpp b/opengl/libagl/egl.cpp
index f925e7d..1feac8b 100644
--- a/opengl/libagl/egl.cpp
+++ b/opengl/libagl/egl.cpp
@@ -206,7 +206,7 @@
     return EGL_BUFFER_PRESERVED;
 }
 EGLBoolean egl_surface_t::setSwapRectangle(
-        EGLint l, EGLint t, EGLint w, EGLint h)
+        EGLint /*l*/, EGLint /*t*/, EGLint /*w*/, EGLint /*h*/)
 {
     return EGL_FALSE;
 }
@@ -793,7 +793,7 @@
     static bool mask(GLint reqValue, GLint confValue) {
         return (confValue & reqValue) == reqValue;
     }
-    static bool ignore(GLint reqValue, GLint confValue) {
+    static bool ignore(GLint /*reqValue*/, GLint /*confValue*/) {
         return true;
     }
 };
@@ -1197,7 +1197,7 @@
     return 0;
 }
 
-static EGLBoolean getConfigAttrib(EGLDisplay dpy, EGLConfig config,
+static EGLBoolean getConfigAttrib(EGLDisplay /*dpy*/, EGLConfig config,
         EGLint attribute, EGLint *value)
 {
     size_t numConfigs =  NELEM(gConfigs);
@@ -1227,7 +1227,7 @@
 }
 
 static EGLSurface createWindowSurface(EGLDisplay dpy, EGLConfig config,
-        NativeWindowType window, const EGLint *attrib_list)
+        NativeWindowType window, const EGLint* /*attrib_list*/)
 {
     if (egl_display_t::is_valid(dpy) == EGL_FALSE)
         return setError(EGL_BAD_DISPLAY, EGL_NO_SURFACE);
@@ -1276,7 +1276,7 @@
 }
 
 static EGLSurface createPixmapSurface(EGLDisplay dpy, EGLConfig config,
-        NativePixmapType pixmap, const EGLint *attrib_list)
+        NativePixmapType pixmap, const EGLint* /*attrib_list*/)
 {
     if (egl_display_t::is_valid(dpy) == EGL_FALSE)
         return setError(EGL_BAD_DISPLAY, EGL_NO_SURFACE);
@@ -1655,7 +1655,7 @@
 }
 
 EGLContext eglCreateContext(EGLDisplay dpy, EGLConfig config,
-                            EGLContext share_list, const EGLint *attrib_list)
+                            EGLContext /*share_list*/, const EGLint* /*attrib_list*/)
 {
     if (egl_display_t::is_valid(dpy) == EGL_FALSE)
         return setError(EGL_BAD_DISPLAY, EGL_NO_SURFACE);
@@ -1853,7 +1853,7 @@
     return EGL_TRUE;
 }
 
-EGLBoolean eglWaitNative(EGLint engine)
+EGLBoolean eglWaitNative(EGLint /*engine*/)
 {
     return EGL_TRUE;
 }
@@ -1887,8 +1887,8 @@
     return EGL_TRUE;
 }
 
-EGLBoolean eglCopyBuffers(  EGLDisplay dpy, EGLSurface surface,
-                            NativePixmapType target)
+EGLBoolean eglCopyBuffers(  EGLDisplay dpy, EGLSurface /*surface*/,
+                            NativePixmapType /*target*/)
 {
     if (egl_display_t::is_valid(dpy) == EGL_FALSE)
         return setError(EGL_BAD_DISPLAY, EGL_FALSE);
@@ -1924,7 +1924,7 @@
 // ----------------------------------------------------------------------------
 
 EGLBoolean eglSurfaceAttrib(
-        EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint value)
+        EGLDisplay dpy, EGLSurface /*surface*/, EGLint /*attribute*/, EGLint /*value*/)
 {
     if (egl_display_t::is_valid(dpy) == EGL_FALSE)
         return setError(EGL_BAD_DISPLAY, EGL_FALSE);
@@ -1933,7 +1933,7 @@
 }
 
 EGLBoolean eglBindTexImage(
-        EGLDisplay dpy, EGLSurface surface, EGLint buffer)
+        EGLDisplay dpy, EGLSurface /*surface*/, EGLint /*buffer*/)
 {
     if (egl_display_t::is_valid(dpy) == EGL_FALSE)
         return setError(EGL_BAD_DISPLAY, EGL_FALSE);
@@ -1942,7 +1942,7 @@
 }
 
 EGLBoolean eglReleaseTexImage(
-        EGLDisplay dpy, EGLSurface surface, EGLint buffer)
+        EGLDisplay dpy, EGLSurface /*surface*/, EGLint /*buffer*/)
 {
     if (egl_display_t::is_valid(dpy) == EGL_FALSE)
         return setError(EGL_BAD_DISPLAY, EGL_FALSE);
@@ -1950,7 +1950,7 @@
     return setError(EGL_BAD_PARAMETER, EGL_FALSE);
 }
 
-EGLBoolean eglSwapInterval(EGLDisplay dpy, EGLint interval)
+EGLBoolean eglSwapInterval(EGLDisplay dpy, EGLint /*interval*/)
 {
     if (egl_display_t::is_valid(dpy) == EGL_FALSE)
         return setError(EGL_BAD_DISPLAY, EGL_FALSE);
@@ -1987,8 +1987,8 @@
 }
 
 EGLSurface eglCreatePbufferFromClientBuffer(
-          EGLDisplay dpy, EGLenum buftype, EGLClientBuffer buffer,
-          EGLConfig config, const EGLint *attrib_list)
+          EGLDisplay dpy, EGLenum /*buftype*/, EGLClientBuffer /*buffer*/,
+          EGLConfig /*config*/, const EGLint* /*attrib_list*/)
 {
     if (egl_display_t::is_valid(dpy) == EGL_FALSE)
         return setError(EGL_BAD_DISPLAY, EGL_NO_SURFACE);
@@ -2011,21 +2011,21 @@
     return NULL;
 }
 
-EGLBoolean eglLockSurfaceKHR(EGLDisplay dpy, EGLSurface surface,
-        const EGLint *attrib_list)
+EGLBoolean eglLockSurfaceKHR(EGLDisplay /*dpy*/, EGLSurface /*surface*/,
+        const EGLint* /*attrib_list*/)
 {
     EGLBoolean result = EGL_FALSE;
     return result;
 }
 
-EGLBoolean eglUnlockSurfaceKHR(EGLDisplay dpy, EGLSurface surface)
+EGLBoolean eglUnlockSurfaceKHR(EGLDisplay /*dpy*/, EGLSurface /*surface*/)
 {
     EGLBoolean result = EGL_FALSE;
     return result;
 }
 
 EGLImageKHR eglCreateImageKHR(EGLDisplay dpy, EGLContext ctx, EGLenum target,
-        EGLClientBuffer buffer, const EGLint *attrib_list)
+        EGLClientBuffer buffer, const EGLint* /*attrib_list*/)
 {
     if (egl_display_t::is_valid(dpy) == EGL_FALSE) {
         return setError(EGL_BAD_DISPLAY, EGL_NO_IMAGE_KHR);
@@ -2106,7 +2106,7 @@
     return FENCE_SYNC_HANDLE;
 }
 
-EGLBoolean eglDestroySyncKHR(EGLDisplay dpy, EGLSyncKHR sync)
+EGLBoolean eglDestroySyncKHR(EGLDisplay /*dpy*/, EGLSyncKHR sync)
 {
     if (sync != FENCE_SYNC_HANDLE) {
         return setError(EGL_BAD_PARAMETER, EGL_FALSE);
@@ -2115,8 +2115,8 @@
     return EGL_TRUE;
 }
 
-EGLint eglClientWaitSyncKHR(EGLDisplay dpy, EGLSyncKHR sync, EGLint flags,
-        EGLTimeKHR timeout)
+EGLint eglClientWaitSyncKHR(EGLDisplay /*dpy*/, EGLSyncKHR sync, EGLint /*flags*/,
+        EGLTimeKHR /*timeout*/)
 {
     if (sync != FENCE_SYNC_HANDLE) {
         return setError(EGL_BAD_PARAMETER, EGL_FALSE);
@@ -2125,7 +2125,7 @@
     return EGL_CONDITION_SATISFIED_KHR;
 }
 
-EGLBoolean eglGetSyncAttribKHR(EGLDisplay dpy, EGLSyncKHR sync,
+EGLBoolean eglGetSyncAttribKHR(EGLDisplay /*dpy*/, EGLSyncKHR sync,
         EGLint attribute, EGLint *value)
 {
     if (sync != FENCE_SYNC_HANDLE) {
diff --git a/opengl/libagl/light.cpp b/opengl/libagl/light.cpp
index fafec3f..479bf7e 100644
--- a/opengl/libagl/light.cpp
+++ b/opengl/libagl/light.cpp
@@ -105,7 +105,7 @@
     c->lighting.shadeModel = GL_SMOOTH;
 }
 
-void ogles_uninit_light(ogles_context_t* c)
+void ogles_uninit_light(ogles_context_t* /*c*/)
 {
 }
 
@@ -285,7 +285,7 @@
     invalidate_lighting(c);
 }
 
-void lightVertexNop(ogles_context_t*, vertex_t* v)
+void lightVertexNop(ogles_context_t*, vertex_t* /*v*/)
 {
     // we should never end-up here
 }
diff --git a/opengl/libagl/primitives.cpp b/opengl/libagl/primitives.cpp
index 769ec40..57a798d 100644
--- a/opengl/libagl/primitives.cpp
+++ b/opengl/libagl/primitives.cpp
@@ -94,7 +94,7 @@
 }
 
 static void lightTriangleDarkFlat(ogles_context_t* c,
-        vertex_t* v0, vertex_t* v1, vertex_t* v2)
+        vertex_t* /*v0*/, vertex_t* /*v1*/, vertex_t* v2)
 {
     if (!(v2->flags & vertex_t::LIT)) {
         v2->flags |= vertex_t::LIT;
@@ -118,7 +118,7 @@
 }
 
 static void lightTriangleFlat(ogles_context_t* c,
-        vertex_t* v0, vertex_t* v1, vertex_t* v2)
+        vertex_t* /*v0*/, vertex_t* /*v1*/, vertex_t* v2)
 {
     if (!(v2->flags & vertex_t::LIT))
         c->lighting.lightVertex(c, v2);
@@ -567,8 +567,8 @@
 #pragma mark Triangle
 #endif
 
-void primitive_nop_triangle(ogles_context_t* c,
-        vertex_t* v0, vertex_t* v1, vertex_t* v2) {
+void primitive_nop_triangle(ogles_context_t* /*c*/,
+        vertex_t* /*v0*/, vertex_t* /*v1*/, vertex_t* /*v2*/) {
 }
 
 void primitive_clip_triangle(ogles_context_t* c,
@@ -823,7 +823,7 @@
 
 
 static inline
-bool cull_triangle(ogles_context_t* c, vertex_t* v0, vertex_t* v1, vertex_t* v2)
+bool cull_triangle(ogles_context_t* c, vertex_t* /*v0*/, vertex_t* /*v1*/, vertex_t* /*v2*/)
 {
     if (ggl_likely(c->cull.enable)) {
         const GLenum winding = (c->lerp.area() > 0) ? GL_CW : GL_CCW;
diff --git a/opengl/libagl/state.cpp b/opengl/libagl/state.cpp
index 4bc653a..1d5def5 100644
--- a/opengl/libagl/state.cpp
+++ b/opengl/libagl/state.cpp
@@ -219,11 +219,11 @@
 #endif
 
 // These ones are super-easy, we're not supporting those features!
-void glSampleCoverage(GLclampf value, GLboolean invert) {
+void glSampleCoverage(GLclampf /*value*/, GLboolean /*invert*/) {
 }
-void glSampleCoveragex(GLclampx value, GLboolean invert) {
+void glSampleCoveragex(GLclampx /*value*/, GLboolean /*invert*/) {
 }
-void glStencilFunc(GLenum func, GLint ref, GLuint mask) {
+void glStencilFunc(GLenum func, GLint /*ref*/, GLuint /*mask*/) {
     ogles_context_t* c = ogles_context_t::get();
     if (func < GL_NEVER || func > GL_ALWAYS) {
         ogles_error(c, GL_INVALID_ENUM);
diff --git a/opengl/libagl/texture.cpp b/opengl/libagl/texture.cpp
index 08536df..9aa1c4f 100644
--- a/opengl/libagl/texture.cpp
+++ b/opengl/libagl/texture.cpp
@@ -1223,10 +1223,10 @@
 // ----------------------------------------------------------------------------
 
 void glCompressedTexSubImage2D(
-        GLenum target, GLint level, GLint xoffset,
-        GLint yoffset, GLsizei width, GLsizei height,
-        GLenum format, GLsizei imageSize,
-        const GLvoid *data)
+        GLenum /*target*/, GLint /*level*/, GLint /*xoffset*/,
+        GLint /*yoffset*/, GLsizei /*width*/, GLsizei /*height*/,
+        GLenum /*format*/, GLsizei /*imageSize*/,
+        const GLvoid* /*data*/)
 {
     ogles_context_t* c = ogles_context_t::get();
     ogles_error(c, GL_INVALID_ENUM);
diff --git a/opengl/libagl/vertex.cpp b/opengl/libagl/vertex.cpp
index dad04d6..9aacdb3 100644
--- a/opengl/libagl/vertex.cpp
+++ b/opengl/libagl/vertex.cpp
@@ -41,7 +41,7 @@
     c->currentNormal.z = 0x10000;
 }
 
-void ogles_uninit_vertex(ogles_context_t* c)
+void ogles_uninit_vertex(ogles_context_t* /*c*/)
 {
 }
 
diff --git a/opengl/libs/Android.mk b/opengl/libs/Android.mk
index 528b983..7328a1d 100644
--- a/opengl/libs/Android.mk
+++ b/opengl/libs/Android.mk
@@ -48,7 +48,7 @@
 ifeq ($(BOARD_ALLOW_EGL_HIBERNATION),true)
   LOCAL_CFLAGS += -DBOARD_ALLOW_EGL_HIBERNATION
 endif
-ifeq ($(TARGET_BOARD_PLATFORM), omap4)
+ifneq ($(filter omap3 omap4,$(TARGET_BOARD_PLATFORM)),)
   LOCAL_CFLAGS += -DWORKAROUND_BUG_10194508=1
 endif
 ifneq ($(MAX_EGL_CACHE_ENTRY_SIZE),)
diff --git a/opengl/libs/EGL/egl_display.cpp b/opengl/libs/EGL/egl_display.cpp
index 26240f1..7784ca6 100644
--- a/opengl/libs/EGL/egl_display.cpp
+++ b/opengl/libs/EGL/egl_display.cpp
@@ -313,7 +313,7 @@
 }
 
 EGLBoolean egl_display_t::makeCurrent(egl_context_t* c, egl_context_t* cur_c,
-        EGLSurface draw, EGLSurface read, EGLContext ctx,
+        EGLSurface draw, EGLSurface read, EGLContext /*ctx*/,
         EGLSurface impl_draw, EGLSurface impl_read, EGLContext impl_ctx)
 {
     EGLBoolean result;
diff --git a/opengl/libs/GLES_CM/gl.cpp b/opengl/libs/GLES_CM/gl.cpp
index 18ef6f9..893577b 100644
--- a/opengl/libs/GLES_CM/gl.cpp
+++ b/opengl/libs/GLES_CM/gl.cpp
@@ -53,34 +53,34 @@
 }
 
 void glColorPointerBounds(GLint size, GLenum type, GLsizei stride,
-        const GLvoid *ptr, GLsizei count) {
+        const GLvoid *ptr, GLsizei /*count*/) {
     glColorPointer(size, type, stride, ptr);
 }
 void glNormalPointerBounds(GLenum type, GLsizei stride,
-        const GLvoid *pointer, GLsizei count) {
+        const GLvoid *pointer, GLsizei /*count*/) {
     glNormalPointer(type, stride, pointer);
 }
 void glTexCoordPointerBounds(GLint size, GLenum type,
-        GLsizei stride, const GLvoid *pointer, GLsizei count) {
+        GLsizei stride, const GLvoid *pointer, GLsizei /*count*/) {
     glTexCoordPointer(size, type, stride, pointer);
 }
 void glVertexPointerBounds(GLint size, GLenum type,
-        GLsizei stride, const GLvoid *pointer, GLsizei count) {
+        GLsizei stride, const GLvoid *pointer, GLsizei /*count*/) {
     glVertexPointer(size, type, stride, pointer);
 }
 
 void GL_APIENTRY glPointSizePointerOESBounds(GLenum type,
-        GLsizei stride, const GLvoid *pointer, GLsizei count) {
+        GLsizei stride, const GLvoid *pointer, GLsizei /*count*/) {
     glPointSizePointerOES(type, stride, pointer);
 }
 
 GL_API void GL_APIENTRY glMatrixIndexPointerOESBounds(GLint size, GLenum type,
-        GLsizei stride, const GLvoid *pointer, GLsizei count) {
+        GLsizei stride, const GLvoid *pointer, GLsizei /*count*/) {
     glMatrixIndexPointerOES(size, type, stride, pointer);
 }
 
 GL_API void GL_APIENTRY glWeightPointerOESBounds(GLint size, GLenum type,
-        GLsizei stride, const GLvoid *pointer, GLsizei count) {
+        GLsizei stride, const GLvoid *pointer, GLsizei /*count*/) {
     glWeightPointerOES(size, type, stride, pointer);
 }
 
diff --git a/opengl/libs/GLES_trace/src/gltrace_egl.cpp b/opengl/libs/GLES_trace/src/gltrace_egl.cpp
index 9d1682a..4f9b006 100644
--- a/opengl/libs/GLES_trace/src/gltrace_egl.cpp
+++ b/opengl/libs/GLES_trace/src/gltrace_egl.cpp
@@ -71,7 +71,7 @@
     glContext->traceGLMessage(&glmessage);
 }
 
-void GLTrace_eglSwapBuffers(void *dpy, void *draw) {
+void GLTrace_eglSwapBuffers(void* /*dpy*/, void* /*draw*/) {
     GLMessage glmessage;
     GLTraceContext *glContext = getGLTraceContext();
 
diff --git a/opengl/tests/EGLTest/EGL_test.cpp b/opengl/tests/EGLTest/EGL_test.cpp
index f6644fb..fea52f3 100644
--- a/opengl/tests/EGLTest/EGL_test.cpp
+++ b/opengl/tests/EGLTest/EGL_test.cpp
@@ -103,6 +103,7 @@
     struct DummyConsumer : public BnConsumerListener {
         virtual void onFrameAvailable() {}
         virtual void onBuffersReleased() {}
+        virtual void onSidebandStreamChanged() {}
     };
 
     // Create a EGLSurface
diff --git a/opengl/tests/angeles/Android.mk b/opengl/tests/angeles/Android.mk
index ae4f76d..c78224e 100644
--- a/opengl/tests/angeles/Android.mk
+++ b/opengl/tests/angeles/Android.mk
@@ -3,7 +3,8 @@
 LOCAL_PATH:= $(call my-dir)
 include $(CLEAR_VARS)
 LOCAL_SRC_FILES:= app-linux.cpp demo.c.arm
-LOCAL_SHARED_LIBRARIES := libEGL libGLESv1_CM libui
+LOCAL_SHARED_LIBRARIES := libEGL libGLESv1_CM libui libgui libutils
+LOCAL_STATIC_LIBRARIES += libglTest
 LOCAL_C_INCLUDES += $(call include-path-for, opengl-tests-includes)
 LOCAL_MODULE:= angeles
 LOCAL_MODULE_TAGS := optional
diff --git a/opengl/tests/angeles/app-linux.cpp b/opengl/tests/angeles/app-linux.cpp
index 6ac68a2..e490351 100644
--- a/opengl/tests/angeles/app-linux.cpp
+++ b/opengl/tests/angeles/app-linux.cpp
@@ -52,8 +52,8 @@
 #include <EGL/egl.h>
 #include <GLES/gl.h>
 
-#include <ui/FramebufferNativeWindow.h>
-#include "EGLUtils.h"
+#include <EGLUtils.h>
+#include <WindowSurface.h>
 
 using namespace android;
 
@@ -118,7 +118,7 @@
         fprintf(stderr, "EGL Error: 0x%04x\n", (int)error);
 }
 
-static int initGraphics(unsigned samples)
+static int initGraphics(unsigned samples, const WindowSurface& windowSurface)
 {
     EGLint configAttribs[] = {
             EGL_DEPTH_SIZE, 16,
@@ -135,7 +135,7 @@
     EGLint w, h;
     EGLDisplay dpy;
 
-    EGLNativeWindowType window = android_createDisplaySurface();
+    EGLNativeWindowType window = windowSurface.getSurface();
 
     dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY);
     eglInitialize(dpy, &majorVersion, &minorVersion);
@@ -193,7 +193,8 @@
         printf("Multisample enabled: GL_SAMPLES = %u\n", samples);
     }
 
-    if (!initGraphics(samples))
+    WindowSurface windowSurface;
+    if (!initGraphics(samples, windowSurface))
     {
         fprintf(stderr, "Graphics initialization failed.\n");
         return EXIT_FAILURE;
diff --git a/opengl/tests/fillrate/Android.mk b/opengl/tests/fillrate/Android.mk
index 4dade21..21ff52a 100644
--- a/opengl/tests/fillrate/Android.mk
+++ b/opengl/tests/fillrate/Android.mk
@@ -9,7 +9,10 @@
 	libutils \
     libEGL \
     libGLESv1_CM \
-    libui
+    libui \
+    libgui
+
+LOCAL_STATIC_LIBRARIES += libglTest
 
 LOCAL_C_INCLUDES += $(call include-path-for, opengl-tests-includes)
 
diff --git a/opengl/tests/fillrate/fillrate.cpp b/opengl/tests/fillrate/fillrate.cpp
index a708647..1d9b026 100644
--- a/opengl/tests/fillrate/fillrate.cpp
+++ b/opengl/tests/fillrate/fillrate.cpp
@@ -25,8 +25,8 @@
 #include <GLES/glext.h>
 
 #include <utils/StopWatch.h>
-#include <ui/FramebufferNativeWindow.h>
-#include "EGLUtils.h"
+#include <WindowSurface.h>
+#include <EGLUtils.h>
 
 using namespace android;
 
@@ -45,7 +45,8 @@
      EGLint w, h;
      EGLDisplay dpy;
 
-     EGLNativeWindowType window = android_createDisplaySurface();
+     WindowSurface windowSurface;
+     EGLNativeWindowType window = windowSurface.getSurface();
      
      dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY);
      eglInitialize(dpy, &majorVersion, &minorVersion);
diff --git a/opengl/tests/filter/Android.mk b/opengl/tests/filter/Android.mk
index d3e4d38..4cf9c96 100644
--- a/opengl/tests/filter/Android.mk
+++ b/opengl/tests/filter/Android.mk
@@ -8,7 +8,11 @@
 	libcutils \
     libEGL \
     libGLESv1_CM \
-    libui
+    libui \
+    libgui \
+    libutils
+
+LOCAL_STATIC_LIBRARIES += libglTest
 
 LOCAL_C_INCLUDES += $(call include-path-for, opengl-tests-includes)
 
diff --git a/opengl/tests/filter/filter.cpp b/opengl/tests/filter/filter.cpp
index 0067327..289e6cc 100644
--- a/opengl/tests/filter/filter.cpp
+++ b/opengl/tests/filter/filter.cpp
@@ -5,8 +5,8 @@
 #include <GLES/gl.h>
 #include <GLES/glext.h>
 
-#include <ui/FramebufferNativeWindow.h>
-#include "EGLUtils.h"
+#include <WindowSurface.h>
+#include <EGLUtils.h>
 
 using namespace android;
 
@@ -40,8 +40,10 @@
      EGLDisplay dpy;
 
      EGLNativeWindowType window = 0;
+     WindowSurface* windowSurface = NULL;
      if (!usePbuffer) {
-         window = android_createDisplaySurface();
+         windowSurface = new WindowSurface();
+         window = windowSurface->getSurface();
      }
      
      dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY);
@@ -186,5 +188,6 @@
      }
 
      eglTerminate(dpy);
+     delete windowSurface;
      return 0;
 }
diff --git a/opengl/tests/finish/Android.mk b/opengl/tests/finish/Android.mk
index aa8adca..0b9b7ea 100644
--- a/opengl/tests/finish/Android.mk
+++ b/opengl/tests/finish/Android.mk
@@ -9,7 +9,10 @@
 	libutils \
     libEGL \
     libGLESv1_CM \
-    libui
+    libui \
+    libgui
+
+LOCAL_STATIC_LIBRARIES += libglTest
 
 LOCAL_C_INCLUDES += $(call include-path-for, opengl-tests-includes)
 
diff --git a/opengl/tests/finish/finish.cpp b/opengl/tests/finish/finish.cpp
index 11f0c22..ea3a60f 100644
--- a/opengl/tests/finish/finish.cpp
+++ b/opengl/tests/finish/finish.cpp
@@ -26,8 +26,8 @@
 
 #include <utils/Timers.h>
 
-#include <ui/FramebufferNativeWindow.h>
-#include "EGLUtils.h"
+#include <WindowSurface.h>
+#include <EGLUtils.h>
 
 using namespace android;
 
@@ -46,7 +46,8 @@
      EGLint w, h;
      EGLDisplay dpy;
 
-     EGLNativeWindowType window = android_createDisplaySurface();
+     WindowSurface windowSurface;
+     EGLNativeWindowType window = windowSurface.getSurface();
      
      dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY);
      eglInitialize(dpy, &majorVersion, &minorVersion);
diff --git a/opengl/tests/gl2_basic/Android.mk b/opengl/tests/gl2_basic/Android.mk
index d7819a1..520395c 100644
--- a/opengl/tests/gl2_basic/Android.mk
+++ b/opengl/tests/gl2_basic/Android.mk
@@ -8,7 +8,11 @@
 	libcutils \
     libEGL \
     libGLESv2 \
-    libui
+    libui \
+    libgui \
+    libutils
+
+LOCAL_STATIC_LIBRARIES += libglTest
 
 LOCAL_C_INCLUDES += $(call include-path-for, opengl-tests-includes)
 
diff --git a/opengl/tests/gl2_basic/gl2_basic.cpp b/opengl/tests/gl2_basic/gl2_basic.cpp
index 7007871..cdbf1cf 100644
--- a/opengl/tests/gl2_basic/gl2_basic.cpp
+++ b/opengl/tests/gl2_basic/gl2_basic.cpp
@@ -26,8 +26,8 @@
 
 #include <utils/Timers.h>
 
-#include <ui/FramebufferNativeWindow.h>
-#include "EGLUtils.h"
+#include <WindowSurface.h>
+#include <EGLUtils.h>
 
 using namespace android;
 
@@ -298,7 +298,8 @@
 
     checkEglError("printEGLConfigurations");
 
-    EGLNativeWindowType window = android_createDisplaySurface();

+    WindowSurface windowSurface;
+    EGLNativeWindowType window = windowSurface.getSurface();
     returnValue = EGLUtils::selectConfigForNativeWindow(dpy, s_configAttribs, window, &myConfig);
     if (returnValue) {
         printf("EGLUtils::selectConfigForNativeWindow() returned %d", returnValue);
diff --git a/opengl/tests/gl2_copyTexImage/Android.mk b/opengl/tests/gl2_copyTexImage/Android.mk
index 005c383..ff43558 100644
--- a/opengl/tests/gl2_copyTexImage/Android.mk
+++ b/opengl/tests/gl2_copyTexImage/Android.mk
@@ -8,7 +8,11 @@
 	libcutils \
     libEGL \
     libGLESv2 \
-    libui
+    libui \
+    libgui \
+    libutils
+
+LOCAL_STATIC_LIBRARIES += libglTest
 
 LOCAL_C_INCLUDES += $(call include-path-for, opengl-tests-includes)
 
diff --git a/opengl/tests/gl2_copyTexImage/gl2_copyTexImage.cpp b/opengl/tests/gl2_copyTexImage/gl2_copyTexImage.cpp
index 988d7ac..405a3f0 100644
--- a/opengl/tests/gl2_copyTexImage/gl2_copyTexImage.cpp
+++ b/opengl/tests/gl2_copyTexImage/gl2_copyTexImage.cpp
@@ -26,8 +26,8 @@
 
 #include <utils/Timers.h>
 
-#include <ui/FramebufferNativeWindow.h>
-#include "EGLUtils.h"
+#include <WindowSurface.h>
+#include <EGLUtils.h>
 
 using namespace android;
 
@@ -406,7 +406,8 @@
 
     checkEglError("printEGLConfigurations");
 
-    EGLNativeWindowType window = android_createDisplaySurface();
+    WindowSurface windowSurface;
+    EGLNativeWindowType window = windowSurface.getSurface();
     EGLint numConfigs = -1, n = 0;
     eglChooseConfig(dpy, s_configAttribs, 0, 0, &numConfigs);
     if (numConfigs) {
diff --git a/opengl/tests/gl2_yuvtex/Android.mk b/opengl/tests/gl2_yuvtex/Android.mk
index bb3cc0c..42cf771 100644
--- a/opengl/tests/gl2_yuvtex/Android.mk
+++ b/opengl/tests/gl2_yuvtex/Android.mk
@@ -9,7 +9,11 @@
     libEGL \
     libGLESv2 \
     libutils \
-    libui
+    libui \
+    libgui \
+    libutils
+
+LOCAL_STATIC_LIBRARIES += libglTest
 
 LOCAL_C_INCLUDES += $(call include-path-for, opengl-tests-includes)
 
diff --git a/opengl/tests/gl2_yuvtex/gl2_yuvtex.cpp b/opengl/tests/gl2_yuvtex/gl2_yuvtex.cpp
index d3e4932..98d8aa8 100644
--- a/opengl/tests/gl2_yuvtex/gl2_yuvtex.cpp
+++ b/opengl/tests/gl2_yuvtex/gl2_yuvtex.cpp
@@ -27,9 +27,9 @@
 
 #include <utils/Timers.h>
 
-#include <ui/FramebufferNativeWindow.h>
+#include <WindowSurface.h>
 #include <ui/GraphicBuffer.h>
-#include "EGLUtils.h"
+#include <EGLUtils.h>
 
 using namespace android;
 
@@ -364,7 +364,8 @@
         return 0;
     }
 
-    EGLNativeWindowType window = android_createDisplaySurface();
+    WindowSurface windowSurface;
+    EGLNativeWindowType window = windowSurface.getSurface();
     returnValue = EGLUtils::selectConfigForNativeWindow(dpy, s_configAttribs, window, &myConfig);
     if (returnValue) {
         printf("EGLUtils::selectConfigForNativeWindow() returned %d", returnValue);
diff --git a/opengl/tests/gl_basic/Android.mk b/opengl/tests/gl_basic/Android.mk
index 46bcc60..7f2259e 100644
--- a/opengl/tests/gl_basic/Android.mk
+++ b/opengl/tests/gl_basic/Android.mk
@@ -8,7 +8,11 @@
 	libcutils \
     libEGL \
     libGLESv1_CM \
-    libui
+    libui \
+    libgui \
+    libutils
+
+LOCAL_STATIC_LIBRARIES += libglTest
 
 LOCAL_C_INCLUDES += $(call include-path-for, opengl-tests-includes)
 
diff --git a/opengl/tests/gl_basic/gl_basic.cpp b/opengl/tests/gl_basic/gl_basic.cpp
index 23ce934..e50d88f 100644
--- a/opengl/tests/gl_basic/gl_basic.cpp
+++ b/opengl/tests/gl_basic/gl_basic.cpp
@@ -5,8 +5,8 @@
 #include <GLES/gl.h>
 #include <GLES/glext.h>
 
-#include <ui/FramebufferNativeWindow.h>
-#include "EGLUtils.h"
+#include <WindowSurface.h>
+#include <EGLUtils.h>
 
 #include <stdio.h>
 
@@ -23,7 +23,7 @@
 #define FIXED_ONE 0x10000
 #define ITERATIONS 50
 
-int init_gl_surface(void);
+int init_gl_surface(const WindowSurface& windowSurface);
 void free_gl_surface(void);
 void init_scene(void);
 void render();
@@ -194,7 +194,8 @@
     int q;
     int start, end;
     printf("Initializing EGL...\n");
-    if(!init_gl_surface())
+    WindowSurface windowSurface;
+    if(!init_gl_surface(windowSurface))
     {
         printf("GL initialisation failed - exiting\n");
         return 0;
@@ -209,7 +210,7 @@
     return 0;
 }
 
-int init_gl_surface(void)
+int init_gl_surface(const WindowSurface& windowSurface)
 {
     EGLint numConfigs = 1;
     EGLConfig myConfig = {0};
@@ -236,7 +237,7 @@
         return 0;
     }
 
-    EGLNativeWindowType window = android_createDisplaySurface();
+    EGLNativeWindowType window = windowSurface.getSurface();
     EGLUtils::selectConfigForNativeWindow(eglDisplay, attrib, window, &myConfig);
 
     if ( (eglSurface = eglCreateWindowSurface(eglDisplay, myConfig,
diff --git a/opengl/tests/gl_perf/Android.mk b/opengl/tests/gl_perf/Android.mk
index b0f825c..9a93fab 100644
--- a/opengl/tests/gl_perf/Android.mk
+++ b/opengl/tests/gl_perf/Android.mk
@@ -10,7 +10,11 @@
     liblog \
     libEGL \
     libGLESv2 \
-    libui
+    libui \
+    libgui \
+    libutils
+
+LOCAL_STATIC_LIBRARIES += libglTest
 
 LOCAL_C_INCLUDES += $(call include-path-for, opengl-tests-includes)
 
diff --git a/opengl/tests/gl_perf/gl2_perf.cpp b/opengl/tests/gl_perf/gl2_perf.cpp
index 224acaf..35df84f 100644
--- a/opengl/tests/gl_perf/gl2_perf.cpp
+++ b/opengl/tests/gl_perf/gl2_perf.cpp
@@ -26,8 +26,8 @@
 
 #include <utils/Timers.h>
 
-#include <ui/FramebufferNativeWindow.h>
-#include "EGLUtils.h"
+#include <WindowSurface.h>
+#include <EGLUtils.h>
 
 using namespace android;
 
@@ -86,7 +86,8 @@
         return 0;
     }
 
-    EGLNativeWindowType window = android_createDisplaySurface();

+    WindowSurface windowSurface;
+    EGLNativeWindowType window = windowSurface.getSurface();
     returnValue = EGLUtils::selectConfigForNativeWindow(dpy, s_configAttribs, window, &myConfig);
     if (returnValue) {
         printf("EGLUtils::selectConfigForNativeWindow() returned %d", returnValue);
diff --git a/opengl/tests/gl_yuvtex/Android.mk b/opengl/tests/gl_yuvtex/Android.mk
index e0e2c16..7f2020a 100644
--- a/opengl/tests/gl_yuvtex/Android.mk
+++ b/opengl/tests/gl_yuvtex/Android.mk
@@ -9,7 +9,10 @@
     libEGL \
     libGLESv1_CM \
     libutils \
-    libui
+    libui \
+    libgui
+
+LOCAL_STATIC_LIBRARIES += libglTest
 
 LOCAL_C_INCLUDES += $(call include-path-for, opengl-tests-includes)
 
diff --git a/opengl/tests/gl_yuvtex/gl_yuvtex.cpp b/opengl/tests/gl_yuvtex/gl_yuvtex.cpp
index 7a00f76..c923b07 100644
--- a/opengl/tests/gl_yuvtex/gl_yuvtex.cpp
+++ b/opengl/tests/gl_yuvtex/gl_yuvtex.cpp
@@ -27,9 +27,9 @@
 
 #include <utils/Timers.h>
 
-#include <ui/FramebufferNativeWindow.h>
+#include <WindowSurface.h>
 #include <ui/GraphicBuffer.h>
-#include "EGLUtils.h"
+#include <EGLUtils.h>
 
 using namespace android;
 
@@ -254,7 +254,8 @@
         return 0;
     }
 
-    EGLNativeWindowType window = android_createDisplaySurface();
+    WindowSurface windowSurface;
+    EGLNativeWindowType window = windowSurface.getSurface();
     returnValue = EGLUtils::selectConfigForNativeWindow(dpy, s_configAttribs, window, &myConfig);
     if (returnValue) {
         printf("EGLUtils::selectConfigForNativeWindow() returned %d", returnValue);
diff --git a/opengl/tests/hwc/hwcColorEquiv.cpp b/opengl/tests/hwc/hwcColorEquiv.cpp
index 160906d..c4624d2 100644
--- a/opengl/tests/hwc/hwcColorEquiv.cpp
+++ b/opengl/tests/hwc/hwcColorEquiv.cpp
@@ -85,7 +85,6 @@
 #include <GLES2/gl2.h>
 #include <GLES2/gl2ext.h>
 
-#include <ui/FramebufferNativeWindow.h>
 #include <ui/GraphicBuffer.h>
 
 #define LOG_TAG "hwcColorEquivTest"
diff --git a/opengl/tests/hwc/hwcCommit.cpp b/opengl/tests/hwc/hwcCommit.cpp
index 3681fbb..1bd5fdf 100644
--- a/opengl/tests/hwc/hwcCommit.cpp
+++ b/opengl/tests/hwc/hwcCommit.cpp
@@ -96,7 +96,6 @@
 #include <GLES2/gl2.h>
 #include <GLES2/gl2ext.h>
 
-#include <ui/FramebufferNativeWindow.h>
 #include <ui/GraphicBuffer.h>
 
 #define LOG_TAG "hwcCommitTest"
diff --git a/opengl/tests/hwc/hwcRects.cpp b/opengl/tests/hwc/hwcRects.cpp
index ec0403f..9b57623 100644
--- a/opengl/tests/hwc/hwcRects.cpp
+++ b/opengl/tests/hwc/hwcRects.cpp
@@ -104,7 +104,6 @@
 #include <GLES2/gl2.h>
 #include <GLES2/gl2ext.h>
 
-#include <ui/FramebufferNativeWindow.h>
 #include <ui/GraphicBuffer.h>
 
 #define LOG_TAG "hwcRectsTest"
diff --git a/opengl/tests/hwc/hwcStress.cpp b/opengl/tests/hwc/hwcStress.cpp
index 3e8ea8d..b1d6c76 100644
--- a/opengl/tests/hwc/hwcStress.cpp
+++ b/opengl/tests/hwc/hwcStress.cpp
@@ -101,7 +101,6 @@
 #include <GLES2/gl2.h>
 #include <GLES2/gl2ext.h>
 
-#include <ui/FramebufferNativeWindow.h>
 #include <ui/GraphicBuffer.h>
 
 #define LOG_TAG "hwcStressTest"
@@ -574,8 +573,8 @@
         // mod the wMod/hMod value must be equal to 0.
         size_t w = (width * maxSizeRatio) * testRandFract();
         size_t h = (height * maxSizeRatio) * testRandFract();
-        w = max(1u, w);
-        h = max(1u, h);
+        w = max(size_t(1u), w);
+        h = max(size_t(1u), h);
         if ((w % formatPtr->wMod) != 0) {
             w += formatPtr->wMod - (w % formatPtr->wMod);
         }
diff --git a/opengl/tests/hwc/hwcTestLib.cpp b/opengl/tests/hwc/hwcTestLib.cpp
index 9b224e2..7fae5e5 100644
--- a/opengl/tests/hwc/hwcTestLib.cpp
+++ b/opengl/tests/hwc/hwcTestLib.cpp
@@ -80,7 +80,11 @@
         exit(71);
     }
 
-    EGLNativeWindowType window = android_createDisplaySurface();
+    // The tests want to stop the framework and play with the hardware
+    // composer, which means it doesn't make sense to use WindowSurface
+    // here.  android_createDisplaySurface() is going away, so just
+    // politely fail here.
+    EGLNativeWindowType window = NULL; //android_createDisplaySurface();
     if (window == NULL) {
         testPrintE("android_createDisplaySurface failed");
         exit(72);
diff --git a/opengl/tests/hwc/hwcTestLib.h b/opengl/tests/hwc/hwcTestLib.h
index d403308..a942c10 100644
--- a/opengl/tests/hwc/hwcTestLib.h
+++ b/opengl/tests/hwc/hwcTestLib.h
@@ -27,7 +27,6 @@
 #include <GLES2/gl2.h>
 #include <GLES2/gl2ext.h>
 
-#include <ui/FramebufferNativeWindow.h>
 #include <ui/GraphicBuffer.h>
 
 #include <utils/Log.h>
diff --git a/opengl/tests/include/WindowSurface.h b/opengl/tests/include/WindowSurface.h
new file mode 100644
index 0000000..0ec1404
--- /dev/null
+++ b/opengl/tests/include/WindowSurface.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2014 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 OPENGL_TESTS_WINDOWSURFACE_H
+#define OPENGL_TESTS_WINDOWSURFACE_H
+
+#include <gui/SurfaceControl.h>
+
+#include <EGL/egl.h>
+
+namespace android {
+
+/*
+ * A window that covers the entire display surface.
+ *
+ * The window is destroyed when this object is destroyed, so don't try
+ * to use the surface after that point.
+ */
+class WindowSurface {
+public:
+    // Creates the window.
+    WindowSurface();
+
+    // Retrieves a handle to the window.
+    EGLNativeWindowType getSurface() const;
+
+private:
+    WindowSurface(const WindowSurface&);
+    WindowSurface& operator=(const WindowSurface&);
+
+    sp<SurfaceControl> mSurfaceControl;
+};
+
+} // namespace android
+
+#endif /* OPENGL_TESTS_WINDOWSURFACE_H */
diff --git a/opengl/tests/lib/Android.mk b/opengl/tests/lib/Android.mk
index 0352a37..a2752cd 100644
--- a/opengl/tests/lib/Android.mk
+++ b/opengl/tests/lib/Android.mk
@@ -17,7 +17,7 @@
 include $(CLEAR_VARS)
 LOCAL_MODULE_TAGS := tests
 LOCAL_MODULE:= libglTest
-LOCAL_SRC_FILES:= glTestLib.cpp
+LOCAL_SRC_FILES:= glTestLib.cpp WindowSurface.cpp
 LOCAL_C_INCLUDES += system/extras/tests/include \
     bionic \
     bionic/libstdc++/include \
diff --git a/opengl/tests/lib/WindowSurface.cpp b/opengl/tests/lib/WindowSurface.cpp
new file mode 100644
index 0000000..ff91260
--- /dev/null
+++ b/opengl/tests/lib/WindowSurface.cpp
@@ -0,0 +1,86 @@
+/*
+ * Copyright 2014 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.
+ */
+
+#include <WindowSurface.h>
+
+#include <gui/SurfaceComposerClient.h>
+#include <gui/ISurfaceComposer.h>
+#include <gui/Surface.h>
+#include <ui/DisplayInfo.h>
+
+using namespace android;
+
+WindowSurface::WindowSurface() {
+    status_t err;
+
+    sp<SurfaceComposerClient> surfaceComposerClient = new SurfaceComposerClient;
+    err = surfaceComposerClient->initCheck();
+    if (err != NO_ERROR) {
+        fprintf(stderr, "SurfaceComposerClient::initCheck error: %#x\n", err);
+        return;
+    }
+
+    // Get main display parameters.
+    sp<IBinder> mainDpy = SurfaceComposerClient::getBuiltInDisplay(
+            ISurfaceComposer::eDisplayIdMain);
+    DisplayInfo mainDpyInfo;
+    err = SurfaceComposerClient::getDisplayInfo(mainDpy, &mainDpyInfo);
+    if (err != NO_ERROR) {
+        fprintf(stderr, "ERROR: unable to get display characteristics\n");
+        return;
+    }
+
+    uint32_t width, height;
+    if (mainDpyInfo.orientation != DISPLAY_ORIENTATION_0 &&
+            mainDpyInfo.orientation != DISPLAY_ORIENTATION_180) {
+        // rotated
+        width = mainDpyInfo.h;
+        height = mainDpyInfo.w;
+    } else {
+        width = mainDpyInfo.w;
+        height = mainDpyInfo.h;
+    }
+
+    sp<SurfaceControl> sc = surfaceComposerClient->createSurface(
+            String8("Benchmark"), width, height,
+            PIXEL_FORMAT_RGBA_8888, ISurfaceComposerClient::eOpaque);
+    if (sc == NULL || !sc->isValid()) {
+        fprintf(stderr, "Failed to create SurfaceControl\n");
+        return;
+    }
+
+    SurfaceComposerClient::openGlobalTransaction();
+    err = sc->setLayer(0x7FFFFFFF);     // always on top
+    if (err != NO_ERROR) {
+        fprintf(stderr, "SurfaceComposer::setLayer error: %#x\n", err);
+        return;
+    }
+
+    err = sc->show();
+    if (err != NO_ERROR) {
+        fprintf(stderr, "SurfaceComposer::show error: %#x\n", err);
+        return;
+    }
+    SurfaceComposerClient::closeGlobalTransaction();
+
+    mSurfaceControl = sc;
+}
+
+EGLNativeWindowType WindowSurface::getSurface() const {
+    sp<ANativeWindow> anw = mSurfaceControl->getSurface();
+    return (EGLNativeWindowType) anw.get();
+}
+
diff --git a/opengl/tests/linetex/Android.mk b/opengl/tests/linetex/Android.mk
index 5b6384e..968756a 100644
--- a/opengl/tests/linetex/Android.mk
+++ b/opengl/tests/linetex/Android.mk
@@ -8,7 +8,11 @@
 	libcutils \
     libEGL \
     libGLESv1_CM \
-    libui
+    libui \
+    libgui \
+    libutils
+
+LOCAL_STATIC_LIBRARIES += libglTest
 
 LOCAL_C_INCLUDES += $(call include-path-for, opengl-tests-includes)
 
diff --git a/opengl/tests/linetex/linetex.cpp b/opengl/tests/linetex/linetex.cpp
index 8669492..7921f80 100644
--- a/opengl/tests/linetex/linetex.cpp
+++ b/opengl/tests/linetex/linetex.cpp
@@ -15,8 +15,6 @@
 ** limitations under the License.
 */
 
-#define LOG_TAG "fillrate"
-
 #include <unistd.h>
 #include <stdlib.h>
 #include <stdio.h>
@@ -26,8 +24,8 @@
 #include <GLES/glext.h>
 
 #include <utils/StopWatch.h>
-#include <ui/FramebufferNativeWindow.h>
-#include "EGLUtils.h"
+#include <WindowSurface.h>
+#include <EGLUtils.h>
 
 using namespace android;
 
@@ -46,7 +44,8 @@
      EGLint w, h;
      EGLDisplay dpy;
 
-     EGLNativeWindowType window = android_createDisplaySurface();
+     WindowSurface windowSurface;
+     EGLNativeWindowType window = windowSurface.getSurface();
      
      dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY);
      eglInitialize(dpy, &majorVersion, &minorVersion);
diff --git a/opengl/tests/swapinterval/Android.mk b/opengl/tests/swapinterval/Android.mk
index 5517f60..b0b15eb 100644
--- a/opengl/tests/swapinterval/Android.mk
+++ b/opengl/tests/swapinterval/Android.mk
@@ -9,7 +9,10 @@
 	libutils \
     libEGL \
     libGLESv1_CM \
-    libui
+    libui \
+    libgui
+
+LOCAL_STATIC_LIBRARIES += libglTest
 
 LOCAL_C_INCLUDES += $(call include-path-for, opengl-tests-includes)
 
diff --git a/opengl/tests/swapinterval/swapinterval.cpp b/opengl/tests/swapinterval/swapinterval.cpp
index a0f4bc4..3a8a8a1 100644
--- a/opengl/tests/swapinterval/swapinterval.cpp
+++ b/opengl/tests/swapinterval/swapinterval.cpp
@@ -23,8 +23,8 @@
 #include <GLES/glext.h>
 
 #include <utils/StopWatch.h>
-#include <ui/FramebufferNativeWindow.h>
-#include "EGLUtils.h"
+#include <WindowSurface.h>
+#include <EGLUtils.h>
 
 using namespace android;
 
@@ -45,7 +45,8 @@
     EGLDisplay dpy;
 
     
-    EGLNativeWindowType window = android_createDisplaySurface();
+    WindowSurface windowSurface;
+    EGLNativeWindowType window = windowSurface.getSurface();
 
     dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY);
     eglInitialize(dpy, &majorVersion, &minorVersion);
diff --git a/opengl/tests/textures/Android.mk b/opengl/tests/textures/Android.mk
index 97697d7..bee61f9 100644
--- a/opengl/tests/textures/Android.mk
+++ b/opengl/tests/textures/Android.mk
@@ -8,7 +8,11 @@
 	libcutils \
     libEGL \
     libGLESv1_CM \
-    libui
+    libui \
+    libgui \
+    libutils
+
+LOCAL_STATIC_LIBRARIES += libglTest
 
 LOCAL_C_INCLUDES += $(call include-path-for, opengl-tests-includes)
 
diff --git a/opengl/tests/textures/textures.cpp b/opengl/tests/textures/textures.cpp
index 5d3d94e..1e55db0 100644
--- a/opengl/tests/textures/textures.cpp
+++ b/opengl/tests/textures/textures.cpp
@@ -22,8 +22,8 @@
 #include <GLES/gl.h>
 #include <GLES/glext.h>
 
-#include <ui/FramebufferNativeWindow.h>
-#include "EGLUtils.h"
+#include <WindowSurface.h>
+#include <EGLUtils.h>
 
 using namespace android;
 
@@ -42,7 +42,8 @@
      EGLint w, h;
      EGLDisplay dpy;
 
-     EGLNativeWindowType window = android_createDisplaySurface();
+     WindowSurface windowSurface;
+     EGLNativeWindowType window = windowSurface.getSurface();
      
      dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY);
      eglInitialize(dpy, &majorVersion, &minorVersion);
@@ -114,5 +115,7 @@
      glDrawTexiOES(dim/2, dim/2, 0, dim/2, dim/2);
 
      eglSwapBuffers(dpy, surface);
+
+     sleep(2);      // so you have a chance to admire it
      return 0;
 }
diff --git a/opengl/tests/tritex/Android.mk b/opengl/tests/tritex/Android.mk
index 89faa87..64382ed 100644
--- a/opengl/tests/tritex/Android.mk
+++ b/opengl/tests/tritex/Android.mk
@@ -8,7 +8,11 @@
 	libcutils \
     libEGL \
     libGLESv1_CM \
-    libui
+    libui \
+    libgui \
+    libutils
+
+LOCAL_STATIC_LIBRARIES += libglTest
 
 LOCAL_C_INCLUDES += $(call include-path-for, opengl-tests-includes)
 
diff --git a/opengl/tests/tritex/tritex.cpp b/opengl/tests/tritex/tritex.cpp
index f183483..2db73ef 100644
--- a/opengl/tests/tritex/tritex.cpp
+++ b/opengl/tests/tritex/tritex.cpp
@@ -8,8 +8,8 @@
 #include <GLES/gl.h>
 #include <GLES/glext.h>
 
-#include <ui/FramebufferNativeWindow.h>
-#include "EGLUtils.h"
+#include <WindowSurface.h>
+#include <EGLUtils.h>
 
 #include <stdio.h>

 #include <stdlib.h>
@@ -25,7 +25,7 @@
 #define FIXED_ONE 0x10000
 #define ITERATIONS 50

 

-int init_gl_surface(void);

+int init_gl_surface(const WindowSurface&);

 void free_gl_surface(void);

 void init_scene(void);

 void render(int quads);

@@ -98,7 +98,8 @@
 
     printf("Initializing EGL...\n");
 

-    if(!init_gl_surface())

+    WindowSurface windowSurface;
+    if(!init_gl_surface(windowSurface))

     {

         printf("GL initialisation failed - exiting\n");

         return 0;

@@ -117,7 +118,7 @@
     return 0;

 }

 

-int init_gl_surface(void)

+int init_gl_surface(const WindowSurface& windowSurface)

 {

     EGLint numConfigs = 1;

     EGLConfig myConfig = {0};

@@ -140,7 +141,7 @@
         return 0;

     }

 
-    EGLNativeWindowType window = android_createDisplaySurface();

+    EGLNativeWindowType window = windowSurface.getSurface();

     EGLUtils::selectConfigForNativeWindow(eglDisplay, attrib, window, &myConfig);

 

     if ( (eglSurface = eglCreateWindowSurface(eglDisplay, myConfig,
diff --git a/opengl/tools/glgen/src/JType.java b/opengl/tools/glgen/src/JType.java
index b10e7e2..c6e227e 100644
--- a/opengl/tools/glgen/src/JType.java
+++ b/opengl/tools/glgen/src/JType.java
@@ -57,8 +57,8 @@
     typeMapping.put(new CType("EGLenum"), new JType("int"));
     typeMapping.put(new CType("EGLNativePixmapType"), new JType("int"));
     typeMapping.put(new CType("EGLNativeWindowType"), new JType("int"));
-    typeMapping.put(new CType("EGLNativeDisplayType"), new JType("int"));
-    typeMapping.put(new CType("EGLClientBuffer"), new JType("int"));
+    typeMapping.put(new CType("EGLNativeDisplayType"), new JType("long"));
+    typeMapping.put(new CType("EGLClientBuffer"), new JType("long"));
     typeMapping.put(new CType("EGLnsecsANDROID"), new JType("long"));
 
     // EGL nonprimitive types
diff --git a/opengl/tools/glgen/src/JniCodeEmitter.java b/opengl/tools/glgen/src/JniCodeEmitter.java
index b1bd1fd..e51b7a2 100644
--- a/opengl/tools/glgen/src/JniCodeEmitter.java
+++ b/opengl/tools/glgen/src/JniCodeEmitter.java
@@ -1283,7 +1283,7 @@
             for (int i = 0; i < numArgs; i++) {
                 String typecast;
                 if (i == numArgs - 1 && isPointerOffsetFunc) {
-                    typecast = "(GLvoid *)";
+                    typecast = "reinterpret_cast<GLvoid *>";
                 } else {
                     typecast = "(" + cfunc.getArgType(i).getDeclaration() + ")";
                 }
@@ -1297,6 +1297,8 @@
                 if (cfunc.getArgType(i).isEGLHandle() &&
                     !cfunc.getArgType(i).isPointer()){
                     out.print(cfunc.getArgName(i)+"_native");
+                } else if (i == numArgs - 1 && isPointerOffsetFunc){
+                    out.print("("+cfunc.getArgName(i)+")");
                 } else {
                     out.print(cfunc.getArgName(i));
                 }
diff --git a/opengl/tools/glgen/static/egl/EGLConfig.java b/opengl/tools/glgen/static/egl/EGLConfig.java
index a7a6bbb..9881070 100644
--- a/opengl/tools/glgen/static/egl/EGLConfig.java
+++ b/opengl/tools/glgen/static/egl/EGLConfig.java
@@ -22,7 +22,7 @@
  *
  */
 public class EGLConfig extends EGLObjectHandle {
-    private EGLConfig(int handle) {
+    private EGLConfig(long handle) {
         super(handle);
     }
 
@@ -32,6 +32,6 @@
         if (!(o instanceof EGLConfig)) return false;
 
         EGLConfig that = (EGLConfig) o;
-        return getHandle() == that.getHandle();
+        return getNativeHandle() == that.getNativeHandle();
     }
 }
diff --git a/opengl/tools/glgen/static/egl/EGLContext.java b/opengl/tools/glgen/static/egl/EGLContext.java
index c93bd6e..f791e7e 100644
--- a/opengl/tools/glgen/static/egl/EGLContext.java
+++ b/opengl/tools/glgen/static/egl/EGLContext.java
@@ -22,7 +22,7 @@
  *
  */
 public class EGLContext extends EGLObjectHandle {
-    private EGLContext(int handle) {
+    private EGLContext(long handle) {
         super(handle);
     }
 
@@ -32,6 +32,6 @@
         if (!(o instanceof EGLContext)) return false;
 
         EGLContext that = (EGLContext) o;
-        return getHandle() == that.getHandle();
+        return getNativeHandle() == that.getNativeHandle();
     }
 }
diff --git a/opengl/tools/glgen/static/egl/EGLDisplay.java b/opengl/tools/glgen/static/egl/EGLDisplay.java
index 5b8043a..e872761 100644
--- a/opengl/tools/glgen/static/egl/EGLDisplay.java
+++ b/opengl/tools/glgen/static/egl/EGLDisplay.java
@@ -22,7 +22,7 @@
  *
  */
 public class EGLDisplay extends EGLObjectHandle {
-    private EGLDisplay(int handle) {
+    private EGLDisplay(long handle) {
         super(handle);
     }
 
@@ -32,6 +32,6 @@
         if (!(o instanceof EGLDisplay)) return false;
 
         EGLDisplay that = (EGLDisplay) o;
-        return getHandle() == that.getHandle();
+        return getNativeHandle() == that.getNativeHandle();
     }
 }
diff --git a/opengl/tools/glgen/static/egl/EGLObjectHandle.java b/opengl/tools/glgen/static/egl/EGLObjectHandle.java
index d2710de..f961eb7 100644
--- a/opengl/tools/glgen/static/egl/EGLObjectHandle.java
+++ b/opengl/tools/glgen/static/egl/EGLObjectHandle.java
@@ -22,12 +22,30 @@
  *
  */
 public abstract class EGLObjectHandle {
-    private final int mHandle;
+    private final long mHandle;
 
+    /**
+     * @deprecated Use {@link #EGLObjectHandle(long)} instead. Handles
+     *     on 64 bit platforms will be wider than java ints.
+     */
+    @Deprecated
     protected EGLObjectHandle(int handle) {
         mHandle = handle;
     }
-
+    protected EGLObjectHandle(long handle) {
+        mHandle = handle;
+    }
+    /**
+     * @deprecated Use {@link #getNativeHandle()} instead. Handles on
+     *     64 bit platforms will be wider than java ints.
+     */
+    @Deprecated
+    public int getHandle() {
+        if ((mHandle & 0xffffffffL) != mHandle) {
+            throw new UnsupportedOperationException();
+        }
+        return (int)mHandle;
+    }
     /**
      * Returns the native handle of the wrapped EGL object. This handle can be
      * cast to the corresponding native type on the native side.
@@ -36,12 +54,17 @@
      *
      * @return the native handle of the wrapped EGL object.
      */
-    public int getHandle() {
+    public long getNativeHandle() {
         return mHandle;
     }
-
     @Override
     public int hashCode() {
-        return getHandle();
+        /*
+         * Based on the algorithm suggested in
+         * http://developer.android.com/reference/java/lang/Object.html
+         */
+        int result = 17;
+        result = 31 * result + (int) (mHandle ^ (mHandle >>> 32));
+        return result;
     }
 }
diff --git a/opengl/tools/glgen/static/egl/EGLSurface.java b/opengl/tools/glgen/static/egl/EGLSurface.java
index c379dc9..c200f72 100644
--- a/opengl/tools/glgen/static/egl/EGLSurface.java
+++ b/opengl/tools/glgen/static/egl/EGLSurface.java
@@ -22,7 +22,7 @@
  *
  */
 public class EGLSurface extends EGLObjectHandle {
-    private EGLSurface(int handle) {
+    private EGLSurface(long handle) {
         super(handle);
     }
 
@@ -32,6 +32,6 @@
         if (!(o instanceof EGLSurface)) return false;
 
         EGLSurface that = (EGLSurface) o;
-        return getHandle() == that.getHandle();
+        return getNativeHandle() == that.getNativeHandle();
     }
 }
diff --git a/opengl/tools/glgen/stubs/egl/EGL14cHeader.cpp b/opengl/tools/glgen/stubs/egl/EGL14cHeader.cpp
index 54de1e7..a372362 100644
--- a/opengl/tools/glgen/stubs/egl/EGL14cHeader.cpp
+++ b/opengl/tools/glgen/stubs/egl/EGL14cHeader.cpp
@@ -69,22 +69,22 @@
     jclass eglconfigClassLocal = _env->FindClass("android/opengl/EGLConfig");
     eglconfigClass = (jclass) _env->NewGlobalRef(eglconfigClassLocal);
 
-    egldisplayGetHandleID = _env->GetMethodID(egldisplayClass, "getHandle", "()I");
-    eglcontextGetHandleID = _env->GetMethodID(eglcontextClass, "getHandle", "()I");
-    eglsurfaceGetHandleID = _env->GetMethodID(eglsurfaceClass, "getHandle", "()I");
-    eglconfigGetHandleID = _env->GetMethodID(eglconfigClass, "getHandle", "()I");
+    egldisplayGetHandleID = _env->GetMethodID(egldisplayClass, "getNativeHandle", "()J");
+    eglcontextGetHandleID = _env->GetMethodID(eglcontextClass, "getNativeHandle", "()J");
+    eglsurfaceGetHandleID = _env->GetMethodID(eglsurfaceClass, "getNativeHandle", "()J");
+    eglconfigGetHandleID = _env->GetMethodID(eglconfigClass, "getNativeHandle", "()J");
 
 
-    egldisplayConstructor = _env->GetMethodID(egldisplayClass, "<init>", "(I)V");
-    eglcontextConstructor = _env->GetMethodID(eglcontextClass, "<init>", "(I)V");
-    eglsurfaceConstructor = _env->GetMethodID(eglsurfaceClass, "<init>", "(I)V");
-    eglconfigConstructor = _env->GetMethodID(eglconfigClass, "<init>", "(I)V");
+    egldisplayConstructor = _env->GetMethodID(egldisplayClass, "<init>", "(J)V");
+    eglcontextConstructor = _env->GetMethodID(eglcontextClass, "<init>", "(J)V");
+    eglsurfaceConstructor = _env->GetMethodID(eglsurfaceClass, "<init>", "(J)V");
+    eglconfigConstructor = _env->GetMethodID(eglconfigClass, "<init>", "(J)V");
 
-    jobject localeglNoContextObject = _env->NewObject(eglcontextClass, eglcontextConstructor, (jint)EGL_NO_CONTEXT);
+    jobject localeglNoContextObject = _env->NewObject(eglcontextClass, eglcontextConstructor, reinterpret_cast<jlong>(EGL_NO_CONTEXT));
     eglNoContextObject = _env->NewGlobalRef(localeglNoContextObject);
-    jobject localeglNoDisplayObject = _env->NewObject(egldisplayClass, egldisplayConstructor, (jint)EGL_NO_DISPLAY);
+    jobject localeglNoDisplayObject = _env->NewObject(egldisplayClass, egldisplayConstructor, reinterpret_cast<jlong>(EGL_NO_DISPLAY));
     eglNoDisplayObject = _env->NewGlobalRef(localeglNoDisplayObject);
-    jobject localeglNoSurfaceObject = _env->NewObject(eglsurfaceClass, eglsurfaceConstructor, (jint)EGL_NO_SURFACE);
+    jobject localeglNoSurfaceObject = _env->NewObject(eglsurfaceClass, eglsurfaceConstructor, reinterpret_cast<jlong>(EGL_NO_SURFACE));
     eglNoSurfaceObject = _env->NewGlobalRef(localeglNoSurfaceObject);
 
 
@@ -106,7 +106,8 @@
                           "Object is set to null.");
     }
 
-    return (void*) (_env->CallIntMethod(obj, mid));
+    jlong handle = _env->CallLongMethod(obj, mid);
+    return reinterpret_cast<void*>(handle);
 }
 
 static jobject
@@ -126,7 +127,7 @@
            return eglNoSurfaceObject;
     }
 
-    return _env->NewObject(cls, con, (jint)handle);
+    return _env->NewObject(cls, con, reinterpret_cast<jlong>(handle));
 }
 
 // --------------------------------------------------------------------------
diff --git a/opengl/tools/glgen/stubs/egl/EGLExtcHeader.cpp b/opengl/tools/glgen/stubs/egl/EGLExtcHeader.cpp
index 5e1ffa1..b5c19df 100644
--- a/opengl/tools/glgen/stubs/egl/EGLExtcHeader.cpp
+++ b/opengl/tools/glgen/stubs/egl/EGLExtcHeader.cpp
@@ -70,22 +70,22 @@
     jclass eglconfigClassLocal = _env->FindClass("android/opengl/EGLConfig");
     eglconfigClass = (jclass) _env->NewGlobalRef(eglconfigClassLocal);
 
-    egldisplayGetHandleID = _env->GetMethodID(egldisplayClass, "getHandle", "()I");
-    eglcontextGetHandleID = _env->GetMethodID(eglcontextClass, "getHandle", "()I");
-    eglsurfaceGetHandleID = _env->GetMethodID(eglsurfaceClass, "getHandle", "()I");
-    eglconfigGetHandleID = _env->GetMethodID(eglconfigClass, "getHandle", "()I");
+    egldisplayGetHandleID = _env->GetMethodID(egldisplayClass, "getNativeHandle", "()J");
+    eglcontextGetHandleID = _env->GetMethodID(eglcontextClass, "getNativeHandle", "()J");
+    eglsurfaceGetHandleID = _env->GetMethodID(eglsurfaceClass, "getNativeHandle", "()J");
+    eglconfigGetHandleID = _env->GetMethodID(eglconfigClass, "getNativeHandle", "()J");
 
 
-    egldisplayConstructor = _env->GetMethodID(egldisplayClass, "<init>", "(I)V");
-    eglcontextConstructor = _env->GetMethodID(eglcontextClass, "<init>", "(I)V");
-    eglsurfaceConstructor = _env->GetMethodID(eglsurfaceClass, "<init>", "(I)V");
-    eglconfigConstructor = _env->GetMethodID(eglconfigClass, "<init>", "(I)V");
+    egldisplayConstructor = _env->GetMethodID(egldisplayClass, "<init>", "(J)V");
+    eglcontextConstructor = _env->GetMethodID(eglcontextClass, "<init>", "(J)V");
+    eglsurfaceConstructor = _env->GetMethodID(eglsurfaceClass, "<init>", "(J)V");
+    eglconfigConstructor = _env->GetMethodID(eglconfigClass, "<init>", "(J)V");
 
-    jobject localeglNoContextObject = _env->NewObject(eglcontextClass, eglcontextConstructor, (jint)EGL_NO_CONTEXT);
+    jobject localeglNoContextObject = _env->NewObject(eglcontextClass, eglcontextConstructor, reinterpret_cast<jlong>(EGL_NO_CONTEXT));
     eglNoContextObject = _env->NewGlobalRef(localeglNoContextObject);
-    jobject localeglNoDisplayObject = _env->NewObject(egldisplayClass, egldisplayConstructor, (jint)EGL_NO_DISPLAY);
+    jobject localeglNoDisplayObject = _env->NewObject(egldisplayClass, egldisplayConstructor, reinterpret_cast<jlong>(EGL_NO_DISPLAY));
     eglNoDisplayObject = _env->NewGlobalRef(localeglNoDisplayObject);
-    jobject localeglNoSurfaceObject = _env->NewObject(eglsurfaceClass, eglsurfaceConstructor, (jint)EGL_NO_SURFACE);
+    jobject localeglNoSurfaceObject = _env->NewObject(eglsurfaceClass, eglsurfaceConstructor, reinterpret_cast<jlong>(EGL_NO_SURFACE));
     eglNoSurfaceObject = _env->NewGlobalRef(localeglNoSurfaceObject);
 
 
@@ -107,7 +107,7 @@
                           "Object is set to null.");
     }
 
-    return (void*) (_env->CallIntMethod(obj, mid));
+    return reinterpret_cast<void*>(_env->CallLongMethod(obj, mid));
 }
 
 static jobject
@@ -127,7 +127,7 @@
            return eglNoSurfaceObject;
     }
 
-    return _env->NewObject(cls, con, (jint)handle);
+    return _env->NewObject(cls, con, reinterpret_cast<jlong>(handle));
 }
 
 // --------------------------------------------------------------------------
diff --git a/opengl/tools/glgen/stubs/egl/eglCreatePbufferFromClientBuffer.cpp b/opengl/tools/glgen/stubs/egl/eglCreatePbufferFromClientBuffer.cpp
new file mode 100755
index 0000000..f09c171
--- /dev/null
+++ b/opengl/tools/glgen/stubs/egl/eglCreatePbufferFromClientBuffer.cpp
@@ -0,0 +1,74 @@
+/* EGLSurface eglCreatePbufferFromClientBuffer ( EGLDisplay dpy, EGLenum buftype, EGLClientBuffer buffer, EGLConfig config, const EGLint *attrib_list ) */
+static jobject
+android_eglCreatePbufferFromClientBuffer
+  (JNIEnv *_env, jobject _this, jobject dpy, jint buftype, jlong buffer, jobject config, jintArray attrib_list_ref, jint offset) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
+    EGLSurface _returnValue = (EGLSurface) 0;
+    EGLDisplay dpy_native = (EGLDisplay) fromEGLHandle(_env, egldisplayGetHandleID, dpy);
+    EGLConfig config_native = (EGLConfig) fromEGLHandle(_env, eglconfigGetHandleID, config);
+    bool attrib_list_sentinel = false;
+    EGLint *attrib_list_base = (EGLint *) 0;
+    jint _remaining;
+    EGLint *attrib_list = (EGLint *) 0;
+
+    if (!attrib_list_ref) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "attrib_list == null";
+        goto exit;
+    }
+    if (offset < 0) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "offset < 0";
+        goto exit;
+    }
+    _remaining = _env->GetArrayLength(attrib_list_ref) - offset;
+    attrib_list_base = (EGLint *)
+        _env->GetPrimitiveArrayCritical(attrib_list_ref, (jboolean *)0);
+    attrib_list = attrib_list_base + offset;
+    attrib_list_sentinel = false;
+    for (int i = _remaining - 1; i >= 0; i--)  {
+        if (attrib_list[i] == EGL_NONE){
+            attrib_list_sentinel = true;
+            break;
+        }
+    }
+    if (attrib_list_sentinel == false) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "attrib_list must contain EGL_NONE!";
+        goto exit;
+    }
+
+    _returnValue = eglCreatePbufferFromClientBuffer(
+        (EGLDisplay)dpy_native,
+        (EGLenum)buftype,
+        reinterpret_cast<EGLClientBuffer>(buffer),
+        (EGLConfig)config_native,
+        (EGLint *)attrib_list
+    );
+
+exit:
+    if (attrib_list_base) {
+        _env->ReleasePrimitiveArrayCritical(attrib_list_ref, attrib_list_base,
+            JNI_ABORT);
+    }
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
+    }
+    return toEGLHandle(_env, eglsurfaceClass, eglsurfaceConstructor, _returnValue);
+}
+
+static jobject
+android_eglCreatePbufferFromClientBufferInt
+  (JNIEnv *_env, jobject _this, jobject dpy, jint buftype, jint buffer, jobject config, jintArray attrib_list_ref, jint offset) {
+    if(sizeof(void*) != sizeof(uint32_t)) {
+        jniThrowException(_env, "java/lang/UnsupportedOperationException", "eglCreatePbufferFromClientBuffer");
+        return 0;
+    }
+    return android_eglCreatePbufferFromClientBuffer(_env, _this, dpy, buftype, buffer, config, attrib_list_ref, offset);
+}
+
diff --git a/opengl/tools/glgen/stubs/egl/eglCreatePbufferFromClientBuffer.java b/opengl/tools/glgen/stubs/egl/eglCreatePbufferFromClientBuffer.java
new file mode 100755
index 0000000..c2ed1d7
--- /dev/null
+++ b/opengl/tools/glgen/stubs/egl/eglCreatePbufferFromClientBuffer.java
@@ -0,0 +1,23 @@
+    // C function EGLSurface eglCreatePbufferFromClientBuffer ( EGLDisplay dpy, EGLenum buftype, EGLClientBuffer buffer, EGLConfig config, const EGLint *attrib_list )
+    // TODO Deprecate the below method
+    public static native EGLSurface eglCreatePbufferFromClientBuffer(
+        EGLDisplay dpy,
+        int buftype,
+        int buffer,
+        EGLConfig config,
+        int[] attrib_list,
+        int offset
+    );
+    // TODO Unhide the below method
+    /**
+     * {@hide}
+     */
+    public static native EGLSurface eglCreatePbufferFromClientBuffer(
+        EGLDisplay dpy,
+        int buftype,
+        long buffer,
+        EGLConfig config,
+        int[] attrib_list,
+        int offset
+    );
+
diff --git a/opengl/tools/glgen/stubs/egl/eglCreatePbufferFromClientBuffer.nativeReg b/opengl/tools/glgen/stubs/egl/eglCreatePbufferFromClientBuffer.nativeReg
new file mode 100755
index 0000000..477e625
--- /dev/null
+++ b/opengl/tools/glgen/stubs/egl/eglCreatePbufferFromClientBuffer.nativeReg
@@ -0,0 +1,2 @@
+{"eglCreatePbufferFromClientBuffer", "(Landroid/opengl/EGLDisplay;IILandroid/opengl/EGLConfig;[II)Landroid/opengl/EGLSurface;", (void *) android_eglCreatePbufferFromClientBufferInt },

+{"eglCreatePbufferFromClientBuffer", "(Landroid/opengl/EGLDisplay;IJLandroid/opengl/EGLConfig;[II)Landroid/opengl/EGLSurface;", (void *) android_eglCreatePbufferFromClientBuffer },
\ No newline at end of file
diff --git a/opengl/tools/glgen/stubs/egl/eglGetDisplay.cpp b/opengl/tools/glgen/stubs/egl/eglGetDisplay.cpp
new file mode 100755
index 0000000..003efd3
--- /dev/null
+++ b/opengl/tools/glgen/stubs/egl/eglGetDisplay.cpp
@@ -0,0 +1,23 @@
+/* EGLDisplay eglGetDisplay ( EGLNativeDisplayType display_id ) */
+static jobject
+android_eglGetDisplay
+  (JNIEnv *_env, jobject _this, jlong display_id) {
+    EGLDisplay _returnValue = (EGLDisplay) 0;
+    _returnValue = eglGetDisplay(
+        reinterpret_cast<EGLNativeDisplayType>(display_id)
+    );
+    return toEGLHandle(_env, egldisplayClass, egldisplayConstructor, _returnValue);
+}
+
+/* EGLDisplay eglGetDisplay ( EGLNativeDisplayType display_id ) */
+static jobject
+android_eglGetDisplayInt
+  (JNIEnv *_env, jobject _this, jint display_id) {
+
+    if ((EGLNativeDisplayType)display_id != EGL_DEFAULT_DISPLAY) {
+        jniThrowException(_env, "java/lang/UnsupportedOperationException", "eglGetDisplay");
+        return 0;
+    }
+    return android_eglGetDisplay(_env, _this, display_id);
+}
+
diff --git a/opengl/tools/glgen/stubs/egl/eglGetDisplay.java b/opengl/tools/glgen/stubs/egl/eglGetDisplay.java
new file mode 100755
index 0000000..7532abf
--- /dev/null
+++ b/opengl/tools/glgen/stubs/egl/eglGetDisplay.java
@@ -0,0 +1,13 @@
+    // C function EGLDisplay eglGetDisplay ( EGLNativeDisplayType display_id )
+
+    public static native EGLDisplay eglGetDisplay(
+        int display_id
+    );
+
+    /**
+     * {@hide}
+     */
+    public static native EGLDisplay eglGetDisplay(
+        long display_id
+    );
+
diff --git a/opengl/tools/glgen/stubs/egl/eglGetDisplay.nativeReg b/opengl/tools/glgen/stubs/egl/eglGetDisplay.nativeReg
new file mode 100755
index 0000000..acfbb1a
--- /dev/null
+++ b/opengl/tools/glgen/stubs/egl/eglGetDisplay.nativeReg
@@ -0,0 +1,2 @@
+{"eglGetDisplay", "(I)Landroid/opengl/EGLDisplay;", (void *) android_eglGetDisplayInt },
+{"eglGetDisplay", "(J)Landroid/opengl/EGLDisplay;", (void *) android_eglGetDisplay },
\ No newline at end of file
diff --git a/opengl/tools/glgen/stubs/gles11/common.cpp b/opengl/tools/glgen/stubs/gles11/common.cpp
index 75b75cb..c5a7a24 100644
--- a/opengl/tools/glgen/stubs/gles11/common.cpp
+++ b/opengl/tools/glgen/stubs/gles11/common.cpp
@@ -89,7 +89,7 @@
             getBasePointerID, buffer);
     if (pointer != 0L) {
         *array = NULL;
-        return (void *) (jint) pointer;
+        return reinterpret_cast<void*>(pointer);
     }
 
     *array = (jarray) _env->CallStaticObjectMethod(nioAccessClass,
diff --git a/opengl/tools/glgen/stubs/gles11/glGetActiveAttrib.cpp b/opengl/tools/glgen/stubs/gles11/glGetActiveAttrib.cpp
index 27b91fc..7d414d8 100644
--- a/opengl/tools/glgen/stubs/gles11/glGetActiveAttrib.cpp
+++ b/opengl/tools/glgen/stubs/gles11/glGetActiveAttrib.cpp
@@ -157,7 +157,7 @@
         (GLsizei *)length,
         (GLint *)size,
         (GLenum *)type,
-        (char *)name
+        reinterpret_cast<char *>(name)
     );
     if (_typeArray) {
         releasePointer(_env, _typeArray, type, JNI_TRUE);
diff --git a/opengl/tools/glgen/stubs/gles11/glGetActiveUniform.cpp b/opengl/tools/glgen/stubs/gles11/glGetActiveUniform.cpp
index 58f704c..a7376ba 100644
--- a/opengl/tools/glgen/stubs/gles11/glGetActiveUniform.cpp
+++ b/opengl/tools/glgen/stubs/gles11/glGetActiveUniform.cpp
@@ -157,7 +157,7 @@
         (GLsizei *)length,
         (GLint *)size,
         (GLenum *)type,
-        (char *)name
+        reinterpret_cast<char *>(name)
     );
     if (_typeArray) {
         releasePointer(_env, _typeArray, type, JNI_TRUE);
diff --git a/opengl/tools/glgen/stubs/gles11/glGetShaderSource.cpp b/opengl/tools/glgen/stubs/gles11/glGetShaderSource.cpp
index a7e1cd2..c995d9c 100644
--- a/opengl/tools/glgen/stubs/gles11/glGetShaderSource.cpp
+++ b/opengl/tools/glgen/stubs/gles11/glGetShaderSource.cpp
@@ -85,7 +85,7 @@
         (GLuint)shader,
         (GLsizei)bufsize,
         (GLsizei *)length,
-        (char *)source
+        reinterpret_cast<char *>(source)
     );
     if (_array) {
         releasePointer(_env, _array, length, JNI_TRUE);
diff --git a/opengl/tools/glgen/stubs/jsr239/GLCHeader.cpp b/opengl/tools/glgen/stubs/jsr239/GLCHeader.cpp
index 4743038..df11c53 100644
--- a/opengl/tools/glgen/stubs/jsr239/GLCHeader.cpp
+++ b/opengl/tools/glgen/stubs/jsr239/GLCHeader.cpp
@@ -128,7 +128,7 @@
             getBasePointerID, buffer);
     if (pointer != 0L) {
         *array = NULL;
-        return (void *) (jint) pointer;
+        return reinterpret_cast<void *>(pointer);
     }
 
     *array = (jarray) _env->CallStaticObjectMethod(nioAccessClass,
diff --git a/services/inputflinger/EventHub.cpp b/services/inputflinger/EventHub.cpp
index e2efd17..94fc0af 100644
--- a/services/inputflinger/EventHub.cpp
+++ b/services/inputflinger/EventHub.cpp
@@ -1291,7 +1291,8 @@
         device->classes |= INPUT_DEVICE_CLASS_EXTERNAL;
     }
 
-    if (device->classes & (INPUT_DEVICE_CLASS_JOYSTICK | INPUT_DEVICE_CLASS_GAMEPAD)) {
+    if (device->classes & (INPUT_DEVICE_CLASS_JOYSTICK | INPUT_DEVICE_CLASS_DPAD)
+            && device->classes & INPUT_DEVICE_CLASS_GAMEPAD) {
         device->controllerNumber = getNextControllerNumberLocked(device);
         setLedForController(device);
     }
diff --git a/services/inputflinger/InputReader.cpp b/services/inputflinger/InputReader.cpp
index 94e2a80..05b1a9c 100644
--- a/services/inputflinger/InputReader.cpp
+++ b/services/inputflinger/InputReader.cpp
@@ -218,6 +218,17 @@
 }
 
 
+// -- TouchAffineTransformation --
+void TouchAffineTransformation::applyTo(float& x, float& y) const {
+    float newX, newY;
+    newX = x * x_scale + y * x_ymix + x_offset;
+    newY = x * y_xmix + y * y_scale + y_offset;
+
+    x = newX;
+    y = newY;
+}
+
+
 // --- InputReader ---
 
 InputReader::InputReader(const sp<EventHubInterface>& eventHub,
@@ -2642,6 +2653,7 @@
     dumpVirtualKeys(dump);
     dumpRawPointerAxes(dump);
     dumpCalibration(dump);
+    dumpAffineTransformation(dump);
     dumpSurface(dump);
 
     dump.appendFormat(INDENT3 "Translation and Scaling Factors:\n");
@@ -2740,6 +2752,11 @@
         resolveCalibration();
     }
 
+    if (!changes || (changes & InputReaderConfiguration::TOUCH_AFFINE_TRANSFORMATION)) {
+        // Update location calibration to reflect current settings
+        updateAffineTransformation();
+    }
+
     if (!changes || (changes & InputReaderConfiguration::CHANGE_POINTER_SPEED)) {
         // Update pointer speed.
         mPointerVelocityControl.setParameters(mConfig.pointerVelocityControlParameters);
@@ -2831,6 +2848,13 @@
                 mParameters.deviceType == Parameters::DEVICE_TYPE_TOUCH_SCREEN
                         && getDevice()->isExternal();
     }
+
+    // Initial downs on external touch devices should wake the device.
+    // Normally we don't do this for internal touch screens to prevent them from waking
+    // up in your pocket but you can enable it using the input device configuration.
+    mParameters.wake = getDevice()->isExternal();
+    getDevice()->getConfiguration().tryGetProperty(String8("touch.wake"),
+            mParameters.wake);
 }
 
 void TouchInputMapper::dumpParameters(String8& dump) {
@@ -3258,6 +3282,9 @@
             break;
         }
 
+        // Location
+        updateAffineTransformation();
+
         if (mDeviceMode == DEVICE_MODE_POINTER) {
             // Compute pointer gesture detection parameters.
             float rawDiagonal = hypotf(rawWidth, rawHeight);
@@ -3624,6 +3651,22 @@
     }
 }
 
+void TouchInputMapper::dumpAffineTransformation(String8& dump) {
+    dump.append(INDENT3 "Affine Transformation:\n");
+
+    dump.appendFormat(INDENT4 "X scale: %0.3f\n", mAffineTransform.x_scale);
+    dump.appendFormat(INDENT4 "X ymix: %0.3f\n", mAffineTransform.x_ymix);
+    dump.appendFormat(INDENT4 "X offset: %0.3f\n", mAffineTransform.x_offset);
+    dump.appendFormat(INDENT4 "Y xmix: %0.3f\n", mAffineTransform.y_xmix);
+    dump.appendFormat(INDENT4 "Y scale: %0.3f\n", mAffineTransform.y_scale);
+    dump.appendFormat(INDENT4 "Y offset: %0.3f\n", mAffineTransform.y_offset);
+}
+
+void TouchInputMapper::updateAffineTransformation() {
+    mAffineTransform = getPolicy()->getTouchAffineTransformation(mDevice->getDescriptor(),
+            mSurfaceOrientation);
+}
+
 void TouchInputMapper::reset(nsecs_t when) {
     mCursorButtonAccumulator.reset(getDevice());
     mCursorScrollAccumulator.reset(getDevice());
@@ -3733,11 +3776,7 @@
                 getContext()->fadePointer();
             }
 
-            // Initial downs on external touch devices should wake the device.
-            // We don't do this for internal touch screens to prevent them from waking
-            // up in your pocket.
-            // TODO: Use the input device configuration to control this behavior more finely.
-            if (getDevice()->isExternal()) {
+            if (mParameters.wake) {
                 policyFlags |= POLICY_FLAG_WAKE_DROPPED;
             }
         }
@@ -4243,13 +4282,19 @@
             break;
         }
 
-        // X, Y, and the bounding box for coverage information
-        // Adjust coords for surface orientation.
-        float x, y, left, top, right, bottom;
+        // Adjust X,Y coords for device calibration
+        // TODO: Adjust coverage coords?
+        float xTransformed = in.x, yTransformed = in.y;
+        mAffineTransform.applyTo(xTransformed, yTransformed);
+
+        // Adjust X, Y, and coverage coords for surface orientation.
+        float x, y;
+        float left, top, right, bottom;
+
         switch (mSurfaceOrientation) {
         case DISPLAY_ORIENTATION_90:
-            x = float(in.y - mRawPointerAxes.y.minValue) * mYScale + mYTranslate;
-            y = float(mRawPointerAxes.x.maxValue - in.x) * mXScale + mXTranslate;
+            x = float(yTransformed - mRawPointerAxes.y.minValue) * mYScale + mYTranslate;
+            y = float(mRawPointerAxes.x.maxValue - xTransformed) * mXScale + mXTranslate;
             left = float(rawTop - mRawPointerAxes.y.minValue) * mYScale + mYTranslate;
             right = float(rawBottom- mRawPointerAxes.y.minValue) * mYScale + mYTranslate;
             bottom = float(mRawPointerAxes.x.maxValue - rawLeft) * mXScale + mXTranslate;
@@ -4260,8 +4305,8 @@
             }
             break;
         case DISPLAY_ORIENTATION_180:
-            x = float(mRawPointerAxes.x.maxValue - in.x) * mXScale + mXTranslate;
-            y = float(mRawPointerAxes.y.maxValue - in.y) * mYScale + mYTranslate;
+            x = float(mRawPointerAxes.x.maxValue - xTransformed) * mXScale + mXTranslate;
+            y = float(mRawPointerAxes.y.maxValue - yTransformed) * mYScale + mYTranslate;
             left = float(mRawPointerAxes.x.maxValue - rawRight) * mXScale + mXTranslate;
             right = float(mRawPointerAxes.x.maxValue - rawLeft) * mXScale + mXTranslate;
             bottom = float(mRawPointerAxes.y.maxValue - rawTop) * mYScale + mYTranslate;
@@ -4272,8 +4317,8 @@
             }
             break;
         case DISPLAY_ORIENTATION_270:
-            x = float(mRawPointerAxes.y.maxValue - in.y) * mYScale + mYTranslate;
-            y = float(in.x - mRawPointerAxes.x.minValue) * mXScale + mXTranslate;
+            x = float(mRawPointerAxes.y.maxValue - yTransformed) * mYScale + mYTranslate;
+            y = float(xTransformed - mRawPointerAxes.x.minValue) * mXScale + mXTranslate;
             left = float(mRawPointerAxes.y.maxValue - rawBottom) * mYScale + mYTranslate;
             right = float(mRawPointerAxes.y.maxValue - rawTop) * mYScale + mYTranslate;
             bottom = float(rawRight - mRawPointerAxes.x.minValue) * mXScale + mXTranslate;
@@ -4284,8 +4329,8 @@
             }
             break;
         default:
-            x = float(in.x - mRawPointerAxes.x.minValue) * mXScale + mXTranslate;
-            y = float(in.y - mRawPointerAxes.y.minValue) * mYScale + mYTranslate;
+            x = float(xTransformed - mRawPointerAxes.x.minValue) * mXScale + mXTranslate;
+            y = float(yTransformed - mRawPointerAxes.y.minValue) * mYScale + mYTranslate;
             left = float(rawLeft - mRawPointerAxes.x.minValue) * mXScale + mXTranslate;
             right = float(rawRight - mRawPointerAxes.x.minValue) * mXScale + mXTranslate;
             bottom = float(rawBottom - mRawPointerAxes.y.minValue) * mYScale + mYTranslate;
diff --git a/services/inputflinger/InputReader.h b/services/inputflinger/InputReader.h
index 6c4c927..c1ce5f7 100644
--- a/services/inputflinger/InputReader.h
+++ b/services/inputflinger/InputReader.h
@@ -138,6 +138,9 @@
         // The device name alias supplied by the may have changed for some devices.
         CHANGE_DEVICE_ALIAS = 1 << 5,
 
+        // The location calibration matrix changed.
+        TOUCH_AFFINE_TRANSFORMATION = 1 << 6,
+
         // All devices must be reopened.
         CHANGE_MUST_REOPEN = 1 << 31,
     };
@@ -252,6 +255,29 @@
 };
 
 
+struct TouchAffineTransformation {
+    float x_scale;
+    float x_ymix;
+    float x_offset;
+    float y_xmix;
+    float y_scale;
+    float y_offset;
+
+    TouchAffineTransformation() :
+        x_scale(1.0f), x_ymix(0.0f), x_offset(0.0f),
+        y_xmix(0.0f), y_scale(1.0f), y_offset(0.0f) {
+    }
+
+    TouchAffineTransformation(float xscale, float xymix, float xoffset,
+            float yxmix, float yscale, float yoffset) :
+        x_scale(xscale), x_ymix(xymix), x_offset(xoffset),
+        y_xmix(yxmix), y_scale(yscale), y_offset(yoffset) {
+    }
+
+    void applyTo(float& x, float& y) const;
+};
+
+
 /*
  * Input reader policy interface.
  *
@@ -287,6 +313,10 @@
 
     /* Gets a user-supplied alias for a particular input device, or an empty string if none. */
     virtual String8 getDeviceAlias(const InputDeviceIdentifier& identifier) = 0;
+
+    /* Gets the affine calibration associated with the specified device. */
+    virtual TouchAffineTransformation getTouchAffineTransformation(
+            const String8& inputDeviceDescriptor, int32_t surfaceRotation) = 0;
 };
 
 
@@ -518,6 +548,7 @@
     inline int32_t getControllerNumber() const { return mControllerNumber; }
     inline int32_t getGeneration() const { return mGeneration; }
     inline const String8& getName() const { return mIdentifier.name; }
+    inline const String8& getDescriptor() { return mIdentifier.descriptor; }
     inline uint32_t getClasses() const { return mClasses; }
     inline uint32_t getSources() const { return mSources; }
 
@@ -1216,6 +1247,8 @@
             GESTURE_MODE_SPOTS,
         };
         GestureMode gestureMode;
+
+        bool wake;
     } mParameters;
 
     // Immutable calibration parameters in parsed form.
@@ -1293,6 +1326,9 @@
         }
     } mCalibration;
 
+    // Affine location transformation/calibration
+    struct TouchAffineTransformation mAffineTransform;
+
     // Raw pointer axis information from the driver.
     RawPointerAxes mRawPointerAxes;
 
@@ -1342,7 +1378,9 @@
     virtual void parseCalibration();
     virtual void resolveCalibration();
     virtual void dumpCalibration(String8& dump);
+    virtual void dumpAffineTransformation(String8& dump);
     virtual bool hasStylus() const = 0;
+    virtual void updateAffineTransformation();
 
     virtual void syncTouch(nsecs_t when, bool* outHavePointerIds) = 0;
 
diff --git a/services/inputflinger/tests/InputReader_test.cpp b/services/inputflinger/tests/InputReader_test.cpp
index aaa973d..c6eb1fd 100644
--- a/services/inputflinger/tests/InputReader_test.cpp
+++ b/services/inputflinger/tests/InputReader_test.cpp
@@ -128,6 +128,7 @@
     InputReaderConfiguration mConfig;
     KeyedVector<int32_t, sp<FakePointerController> > mPointerControllers;
     Vector<InputDeviceInfo> mInputDevices;
+    TouchAffineTransformation transform;
 
 protected:
     virtual ~FakeInputReaderPolicy() { }
@@ -173,6 +174,15 @@
         return mInputDevices;
     }
 
+    TouchAffineTransformation getTouchAffineTransformation(const String8& inputDeviceDescriptor,
+            int32_t surfaceRotation) {
+        return transform;
+    }
+
+    void setTouchAffineTransformation(const TouchAffineTransformation t) {
+        transform = t;
+    }
+
 private:
     virtual void getReaderConfiguration(InputReaderConfiguration* outConfig) {
         *outConfig = mConfig;
@@ -2463,6 +2473,7 @@
     static const float Y_PRECISION;
 
     static const float GEOMETRIC_SCALE;
+    static const TouchAffineTransformation AFFINE_TRANSFORM;
 
     static const VirtualKeyDefinition VIRTUAL_KEYS[2];
 
@@ -2482,8 +2493,11 @@
 
     void prepareDisplay(int32_t orientation);
     void prepareVirtualKeys();
+    void prepareLocationCalibration();
     int32_t toRawX(float displayX);
     int32_t toRawY(float displayY);
+    float toCookedX(float rawX, float rawY);
+    float toCookedY(float rawX, float rawY);
     float toDisplayX(int32_t rawX);
     float toDisplayY(int32_t rawY);
 };
@@ -2510,6 +2524,8 @@
 const int32_t TouchInputMapperTest::RAW_SLOT_MAX = 9;
 const float TouchInputMapperTest::X_PRECISION = float(RAW_X_MAX - RAW_X_MIN + 1) / DISPLAY_WIDTH;
 const float TouchInputMapperTest::Y_PRECISION = float(RAW_Y_MAX - RAW_Y_MIN + 1) / DISPLAY_HEIGHT;
+const TouchAffineTransformation TouchInputMapperTest::AFFINE_TRANSFORM =
+        TouchAffineTransformation(1, -2, 3, -4, 5, -6);
 
 const float TouchInputMapperTest::GEOMETRIC_SCALE =
         avg(float(DISPLAY_WIDTH) / (RAW_X_MAX - RAW_X_MIN + 1),
@@ -2531,6 +2547,10 @@
     mFakeEventHub->addKey(DEVICE_ID, KEY_MENU, 0, AKEYCODE_MENU, POLICY_FLAG_WAKE);
 }
 
+void TouchInputMapperTest::prepareLocationCalibration() {
+    mFakePolicy->setTouchAffineTransformation(AFFINE_TRANSFORM);
+}
+
 int32_t TouchInputMapperTest::toRawX(float displayX) {
     return int32_t(displayX * (RAW_X_MAX - RAW_X_MIN + 1) / DISPLAY_WIDTH + RAW_X_MIN);
 }
@@ -2539,6 +2559,16 @@
     return int32_t(displayY * (RAW_Y_MAX - RAW_Y_MIN + 1) / DISPLAY_HEIGHT + RAW_Y_MIN);
 }
 
+float TouchInputMapperTest::toCookedX(float rawX, float rawY) {
+    AFFINE_TRANSFORM.applyTo(rawX, rawY);
+    return rawX;
+}
+
+float TouchInputMapperTest::toCookedY(float rawX, float rawY) {
+    AFFINE_TRANSFORM.applyTo(rawX, rawY);
+    return rawY;
+}
+
 float TouchInputMapperTest::toDisplayX(int32_t rawX) {
     return float(rawX - RAW_X_MIN) * DISPLAY_WIDTH / (RAW_X_MAX - RAW_X_MIN + 1);
 }
@@ -3226,6 +3256,30 @@
     ASSERT_EQ(tilt, args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_TILT));
 }
 
+TEST_F(SingleTouchInputMapperTest, Process_XYAxes_AffineCalibration) {
+    SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice);
+    addConfigurationProperty("touch.deviceType", "touchScreen");
+    prepareDisplay(DISPLAY_ORIENTATION_0);
+    prepareLocationCalibration();
+    prepareButtons();
+    prepareAxes(POSITION);
+    addMapperAndConfigure(mapper);
+
+    int32_t rawX = 100;
+    int32_t rawY = 200;
+
+    float x = toDisplayX(toCookedX(rawX, rawY));
+    float y = toDisplayY(toCookedY(rawX, rawY));
+
+    processDown(mapper, rawX, rawY);
+    processSync(mapper);
+
+    NotifyMotionArgs args;
+    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args));
+    ASSERT_NO_FATAL_FAILURE(assertPointerCoords(args.pointerCoords[0],
+            x, y, 1, 0, 0, 0, 0, 0, 0, 0));
+}
+
 TEST_F(SingleTouchInputMapperTest, Process_ShouldHandleAllButtons) {
     SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice);
     addConfigurationProperty("touch.deviceType", "touchScreen");
diff --git a/services/sensorservice/CorrectedGyroSensor.cpp b/services/sensorservice/CorrectedGyroSensor.cpp
index 31487a7..b07d544 100644
--- a/services/sensorservice/CorrectedGyroSensor.cpp
+++ b/services/sensorservice/CorrectedGyroSensor.cpp
@@ -61,7 +61,7 @@
     return mSensorFusion.activate(ident, enabled);
 }
 
-status_t CorrectedGyroSensor::setDelay(void* ident, int handle, int64_t ns) {
+status_t CorrectedGyroSensor::setDelay(void* ident, int /*handle*/, int64_t ns) {
     mSensorDevice.setDelay(ident, mGyro.getHandle(), ns);
     return mSensorFusion.setDelay(ident, ns);
 }
diff --git a/services/sensorservice/GravitySensor.cpp b/services/sensorservice/GravitySensor.cpp
index dd1f650..3cb3745 100644
--- a/services/sensorservice/GravitySensor.cpp
+++ b/services/sensorservice/GravitySensor.cpp
@@ -70,7 +70,7 @@
     return mSensorFusion.activate(ident, enabled);
 }
 
-status_t GravitySensor::setDelay(void* ident, int handle, int64_t ns) {
+status_t GravitySensor::setDelay(void* ident, int /*handle*/, int64_t ns) {
     return mSensorFusion.setDelay(ident, ns);
 }
 
diff --git a/services/sensorservice/OrientationSensor.cpp b/services/sensorservice/OrientationSensor.cpp
index 10b391c..6d85cca 100644
--- a/services/sensorservice/OrientationSensor.cpp
+++ b/services/sensorservice/OrientationSensor.cpp
@@ -69,7 +69,7 @@
     return mSensorFusion.activate(ident, enabled);
 }
 
-status_t OrientationSensor::setDelay(void* ident, int handle, int64_t ns) {
+status_t OrientationSensor::setDelay(void* ident, int /*handle*/, int64_t ns) {
     return mSensorFusion.setDelay(ident, ns);
 }
 
diff --git a/services/sensorservice/RotationVectorSensor.cpp b/services/sensorservice/RotationVectorSensor.cpp
index a2157b4..cb305eb 100644
--- a/services/sensorservice/RotationVectorSensor.cpp
+++ b/services/sensorservice/RotationVectorSensor.cpp
@@ -56,7 +56,7 @@
     return mSensorFusion.activate(ident, enabled);
 }
 
-status_t RotationVectorSensor::setDelay(void* ident, int handle, int64_t ns) {
+status_t RotationVectorSensor::setDelay(void* ident, int /*handle*/, int64_t ns) {
     return mSensorFusion.setDelay(ident, ns);
 }
 
@@ -105,7 +105,7 @@
     return mSensorFusion.activate(ident, enabled);
 }
 
-status_t GyroDriftSensor::setDelay(void* ident, int handle, int64_t ns) {
+status_t GyroDriftSensor::setDelay(void* ident, int /*handle*/, int64_t ns) {
     return mSensorFusion.setDelay(ident, ns);
 }
 
diff --git a/services/sensorservice/SensorDevice.cpp b/services/sensorservice/SensorDevice.cpp
index 19caa5c..3b64f0a 100644
--- a/services/sensorservice/SensorDevice.cpp
+++ b/services/sensorservice/SensorDevice.cpp
@@ -78,7 +78,7 @@
     Mutex::Autolock _l(mLock);
     for (size_t i=0 ; i<size_t(count) ; i++) {
         const Info& info = mActivationCount.valueFor(list[i].handle);
-        result.appendFormat("handle=0x%08x, active-count=%d, batch_period(ms)={ ", list[i].handle,
+        result.appendFormat("handle=0x%08x, active-count=%zu, batch_period(ms)={ ", list[i].handle,
                             info.batchParams.size());
         for (size_t j = 0; j < info.batchParams.size(); j++) {
             BatchParams params = info.batchParams.valueAt(j);
@@ -87,7 +87,7 @@
         }
         result.appendFormat(" }, selected=%4.1f ms\n", info.bestBatchParams.batchDelay / 1e6f);
 
-        result.appendFormat("handle=0x%08x, active-count=%d, batch_timeout(ms)={ ", list[i].handle,
+        result.appendFormat("handle=0x%08x, active-count=%zu, batch_timeout(ms)={ ", list[i].handle,
                             info.batchParams.size());
         for (size_t j = 0; j < info.batchParams.size(); j++) {
             BatchParams params = info.batchParams.valueAt(j);
@@ -309,7 +309,7 @@
     return mSensorDevice->common.version;
 }
 
-status_t SensorDevice::flush(void* ident, int handle) {
+status_t SensorDevice::flush(void* /*ident*/, int handle) {
     if (getHalDeviceVersion() < SENSORS_DEVICE_API_VERSION_1_1) {
         return INVALID_OPERATION;
     }
diff --git a/services/sensorservice/SensorFusion.cpp b/services/sensorservice/SensorFusion.cpp
index 8512d6b..6d93009 100644
--- a/services/sensorservice/SensorFusion.cpp
+++ b/services/sensorservice/SensorFusion.cpp
@@ -139,7 +139,7 @@
 
 void SensorFusion::dump(String8& result) {
     const Fusion& fusion(mFusion);
-    result.appendFormat("9-axis fusion %s (%d clients), gyro-rate=%7.2fHz, "
+    result.appendFormat("9-axis fusion %s (%zd clients), gyro-rate=%7.2fHz, "
             "q=< %g, %g, %g, %g > (%g), "
             "b=< %g, %g, %g >\n",
             mEnabled ? "enabled" : "disabled",
diff --git a/services/sensorservice/SensorInterface.cpp b/services/sensorservice/SensorInterface.cpp
index f1d1663..2bf5e72 100644
--- a/services/sensorservice/SensorInterface.cpp
+++ b/services/sensorservice/SensorInterface.cpp
@@ -50,7 +50,7 @@
     return mSensorDevice.activate(ident, mSensor.getHandle(), enabled);
 }
 
-status_t HardwareSensor::batch(void* ident, int handle, int flags,
+status_t HardwareSensor::batch(void* ident, int /*handle*/, int flags,
                                int64_t samplingPeriodNs, int64_t maxBatchReportLatencyNs) {
     return mSensorDevice.batch(ident, mSensor.getHandle(), flags, samplingPeriodNs,
                                maxBatchReportLatencyNs);
diff --git a/services/sensorservice/SensorInterface.h b/services/sensorservice/SensorInterface.h
index c295e22..3e76377 100644
--- a/services/sensorservice/SensorInterface.h
+++ b/services/sensorservice/SensorInterface.h
@@ -40,7 +40,7 @@
     virtual status_t setDelay(void* ident, int handle, int64_t ns) = 0;
 
     // Not all sensors need to support batching.
-    virtual status_t batch(void* ident, int handle, int flags, int64_t samplingPeriodNs,
+    virtual status_t batch(void* ident, int handle, int /*flags*/, int64_t samplingPeriodNs,
                            int64_t maxBatchReportLatencyNs) {
         if (maxBatchReportLatencyNs == 0) {
             return setDelay(ident, handle, samplingPeriodNs);
@@ -48,13 +48,13 @@
         return -EINVAL;
     }
 
-    virtual status_t flush(void* ident, int handle) {
+    virtual status_t flush(void* /*ident*/, int /*handle*/) {
         return -EINVAL;
     }
 
     virtual Sensor getSensor() const = 0;
     virtual bool isVirtual() const = 0;
-    virtual void autoDisable(void *ident, int handle) { }
+    virtual void autoDisable(void* /*ident*/, int /*handle*/) { }
 };
 
 // ---------------------------------------------------------------------------
diff --git a/services/sensorservice/SensorService.cpp b/services/sensorservice/SensorService.cpp
index 890717a..f0bfe2c 100644
--- a/services/sensorservice/SensorService.cpp
+++ b/services/sensorservice/SensorService.cpp
@@ -14,8 +14,9 @@
  * limitations under the License.
  */
 
-#include <stdint.h>
+#include <inttypes.h>
 #include <math.h>
+#include <stdint.h>
 #include <sys/types.h>
 
 #include <cutils/properties.h>
@@ -153,7 +154,7 @@
             char line[128];
             if (fp != NULL && fgets(line, sizeof(line), fp) != NULL) {
                 line[sizeof(line) - 1] = '\0';
-                sscanf(line, "%u", &mSocketBufferSize);
+                sscanf(line, "%zu", &mSocketBufferSize);
                 if (mSocketBufferSize > MAX_SOCKET_BUFFER_SIZE_BATCHED) {
                     mSocketBufferSize = MAX_SOCKET_BUFFER_SIZE_BATCHED;
                 }
@@ -200,7 +201,7 @@
 
 static const String16 sDump("android.permission.DUMP");
 
-status_t SensorService::dump(int fd, const Vector<String16>& args)
+status_t SensorService::dump(int fd, const Vector<String16>& /*args*/)
 {
     String8 result;
     if (!PermissionCache::checkCallingPermission(sDump)) {
@@ -257,7 +258,7 @@
                     result.appendFormat( "last=<%f>\n", e.data[0]);
                     break;
                 case SENSOR_TYPE_STEP_COUNTER:
-                    result.appendFormat( "last=<%llu>\n", e.u64.step_counter);
+                    result.appendFormat( "last=<%" PRIu64 ">\n", e.u64.step_counter);
                     break;
                 default:
                     // default to 3 values
@@ -273,19 +274,19 @@
         result.append("Active sensors:\n");
         for (size_t i=0 ; i<mActiveSensors.size() ; i++) {
             int handle = mActiveSensors.keyAt(i);
-            result.appendFormat("%s (handle=0x%08x, connections=%d)\n",
+            result.appendFormat("%s (handle=0x%08x, connections=%zu)\n",
                     getSensorName(handle).string(),
                     handle,
                     mActiveSensors.valueAt(i)->getNumConnections());
         }
 
-        result.appendFormat("%u Max Socket Buffer size\n", mSocketBufferSize);
-        result.appendFormat("%d active connections\n", mActiveConnections.size());
+        result.appendFormat("%zu Max Socket Buffer size\n", mSocketBufferSize);
+        result.appendFormat("%zd active connections\n", mActiveConnections.size());
 
         for (size_t i=0 ; i < mActiveConnections.size() ; i++) {
             sp<SensorEventConnection> connection(mActiveConnections[i].promote());
             if (connection != 0) {
-                result.appendFormat("Connection Number: %d \n", i);
+                result.appendFormat("Connection Number: %zu \n", i);
                 connection->dump(result);
             }
         }
@@ -426,20 +427,21 @@
 }
 
 void SensorService::recordLastValue(
-        sensors_event_t const * buffer, size_t count)
-{
+        const sensors_event_t* buffer, size_t count) {
     Mutex::Autolock _l(mLock);
-    // record the last event for each sensor
-    int32_t prev = buffer[0].sensor;
-    for (size_t i=1 ; i<count ; i++) {
-        // record the last event of each sensor type in this buffer
-        int32_t curr = buffer[i].sensor;
-        if (curr != prev) {
-            mLastEventSeen.editValueFor(prev) = buffer[i-1];
-            prev = curr;
+    const sensors_event_t* last = NULL;
+    for (size_t i = 0; i < count; i++) {
+        const sensors_event_t* event = &buffer[i];
+        if (event->type != SENSOR_TYPE_META_DATA) {
+            if (last && event->sensor != last->sensor) {
+                mLastEventSeen.editValueFor(last->sensor) = *last;
+            }
+            last = event;
         }
     }
-    mLastEventSeen.editValueFor(prev) = buffer[count-1];
+    if (last) {
+        mLastEventSeen.editValueFor(last->sensor) = *last;
+    }
 }
 
 void SensorService::sortEventBuffer(sensors_event_t* buffer, size_t count)
diff --git a/services/sensorservice/SensorService.h b/services/sensorservice/SensorService.h
index c968319..1dc2dd3 100644
--- a/services/sensorservice/SensorService.h
+++ b/services/sensorservice/SensorService.h
@@ -131,7 +131,7 @@
 
     String8 getSensorName(int handle) const;
     bool isVirtualSensor(int handle) const;
-    void recordLastValue(sensors_event_t const * buffer, size_t count);
+    void recordLastValue(const sensors_event_t* buffer, size_t count);
     static void sortEventBuffer(sensors_event_t* buffer, size_t count);
     Sensor registerSensor(SensorInterface* sensor);
     Sensor registerVirtualSensor(SensorInterface* sensor);
diff --git a/services/sensorservice/main_sensorservice.cpp b/services/sensorservice/main_sensorservice.cpp
index 303b65f..0a96f42 100644
--- a/services/sensorservice/main_sensorservice.cpp
+++ b/services/sensorservice/main_sensorservice.cpp
@@ -19,7 +19,7 @@
 
 using namespace android;
 
-int main(int argc, char** argv) {
+int main(int /*argc*/, char** /*argv*/) {
     SensorService::publishAndJoinThreadPool();
     return 0;
 }
diff --git a/services/surfaceflinger/DispSync.cpp b/services/surfaceflinger/DispSync.cpp
index ce07ab5..602f20a 100644
--- a/services/surfaceflinger/DispSync.cpp
+++ b/services/surfaceflinger/DispSync.cpp
@@ -287,7 +287,7 @@
 public:
     ZeroPhaseTracer() : mParity(false) {}
 
-    virtual void onDispSyncEvent(nsecs_t when) {
+    virtual void onDispSyncEvent(nsecs_t /*when*/) {
         mParity = !mParity;
         ATRACE_INT("ZERO_PHASE_VSYNC", mParity ? 1 : 0);
     }
diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp
index d7bbf5c..42993b9 100644
--- a/services/surfaceflinger/DisplayDevice.cpp
+++ b/services/surfaceflinger/DisplayDevice.cpp
@@ -77,16 +77,6 @@
     mNativeWindow = new Surface(producer, false);
     ANativeWindow* const window = mNativeWindow.get();
 
-    // Make sure that composition can never be stalled by a virtual display
-    // consumer that isn't processing buffers fast enough. We have to do this
-    // in two places:
-    // * Here, in case the display is composed entirely by HWC.
-    // * In makeCurrent(), using eglSwapInterval. Some EGL drivers set the
-    //   window's swap interval in eglMakeCurrent, so they'll override the
-    //   interval we set here.
-    if (mType >= DisplayDevice::DISPLAY_VIRTUAL)
-        window->setSwapInterval(window, 0);
-
     /*
      * Create our display's surface
      */
@@ -101,6 +91,16 @@
     eglQuerySurface(display, surface, EGL_WIDTH,  &mDisplayWidth);
     eglQuerySurface(display, surface, EGL_HEIGHT, &mDisplayHeight);
 
+    // Make sure that composition can never be stalled by a virtual display
+    // consumer that isn't processing buffers fast enough. We have to do this
+    // in two places:
+    // * Here, in case the display is composed entirely by HWC.
+    // * In makeCurrent(), using eglSwapInterval. Some EGL drivers set the
+    //   window's swap interval in eglMakeCurrent, so they'll override the
+    //   interval we set here.
+    if (mType >= DisplayDevice::DISPLAY_VIRTUAL)
+        window->setSwapInterval(window, 0);
+
     mDisplay = display;
     mSurface = surface;
     mFormat  = format;
@@ -464,7 +464,7 @@
     result.appendFormat(
         "+ DisplayDevice: %s\n"
         "   type=%x, hwcId=%d, layerStack=%u, (%4dx%4d), ANativeWindow=%p, orient=%2d (type=%08x), "
-        "flips=%u, isSecure=%d, secureVis=%d, acquired=%d, numLayers=%u\n"
+        "flips=%u, isSecure=%d, secureVis=%d, acquired=%d, numLayers=%zu\n"
         "   v:[%d,%d,%d,%d], f:[%d,%d,%d,%d], s:[%d,%d,%d,%d],"
         "transform:[[%0.3f,%0.3f,%0.3f][%0.3f,%0.3f,%0.3f][%0.3f,%0.3f,%0.3f]]\n",
         mDisplayName.string(), mType, mHwcDisplayId,
diff --git a/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp b/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp
index 0f34764..086ccf8 100644
--- a/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp
+++ b/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp
@@ -72,7 +72,7 @@
     return NO_ERROR;
 }
 
-status_t FramebufferSurface::prepareFrame(CompositionType compositionType) {
+status_t FramebufferSurface::prepareFrame(CompositionType /*compositionType*/) {
     return NO_ERROR;
 }
 
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
index 474f633..a6f8d15 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
@@ -16,15 +16,17 @@
 
 #define ATRACE_TAG ATRACE_TAG_GRAPHICS
 
+#include <inttypes.h>
+#include <math.h>
 #include <stdint.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <sys/types.h>
-#include <math.h>
 
 #include <utils/Errors.h>
 #include <utils/misc.h>
+#include <utils/NativeHandle.h>
 #include <utils/String8.h>
 #include <utils/Thread.h>
 #include <utils/Trace.h>
@@ -942,12 +944,22 @@
         SharedBuffer const* sb = reg.getSharedBuffer(&visibleRegion.numRects);
         visibleRegion.rects = reinterpret_cast<hwc_rect_t const *>(sb->data());
     }
+    virtual void setSidebandStream(const sp<NativeHandle>& stream) {
+        ALOG_ASSERT(stream->handle() != NULL);
+        getLayer()->compositionType = HWC_SIDEBAND;
+        getLayer()->sidebandStream = stream->handle();
+    }
     virtual void setBuffer(const sp<GraphicBuffer>& buffer) {
         if (buffer == 0 || buffer->handle == 0) {
             getLayer()->compositionType = HWC_FRAMEBUFFER;
             getLayer()->flags |= HWC_SKIP_LAYER;
             getLayer()->handle = 0;
         } else {
+            if (getLayer()->compositionType == HWC_SIDEBAND) {
+                // If this was a sideband layer but the stream was removed, reset
+                // it to FRAMEBUFFER. The HWC can change it to OVERLAY in prepare.
+                getLayer()->compositionType = HWC_FRAMEBUFFER;
+            }
             getLayer()->handle = buffer->handle;
         }
     }
@@ -1021,12 +1033,12 @@
                     mFlinger->getLayerSortedByZForHwcDisplay(i);
 
             result.appendFormat(
-                    "  Display[%d] : %ux%u, xdpi=%f, ydpi=%f, refresh=%lld\n",
+                    "  Display[%zd] : %ux%u, xdpi=%f, ydpi=%f, refresh=%" PRId64 "\n",
                     i, disp.width, disp.height, disp.xdpi, disp.ydpi, disp.refresh);
 
             if (disp.list) {
                 result.appendFormat(
-                        "  numHwLayers=%u, flags=%08x\n",
+                        "  numHwLayers=%zu, flags=%08x\n",
                         disp.list->numHwLayers, disp.list->flags);
 
                 result.append(
@@ -1065,7 +1077,7 @@
 
                     if (hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_3)) {
                         result.appendFormat(
-                                " %10s | %08x | %08x | %08x | %02x | %05x | %08x | [%7.1f,%7.1f,%7.1f,%7.1f] | [%5d,%5d,%5d,%5d] %s\n",
+                                " %10s | %08" PRIxPTR " | %08x | %08x | %02x | %05x | %08x | [%7.1f,%7.1f,%7.1f,%7.1f] | [%5d,%5d,%5d,%5d] %s\n",
                                         compositionTypeName[type],
                                         intptr_t(l.handle), l.hints, l.flags, l.transform, l.blending, format,
                                         l.sourceCropf.left, l.sourceCropf.top, l.sourceCropf.right, l.sourceCropf.bottom,
@@ -1073,7 +1085,7 @@
                                         name.string());
                     } else {
                         result.appendFormat(
-                                " %10s | %08x | %08x | %08x | %02x | %05x | %08x | [%7d,%7d,%7d,%7d] | [%5d,%5d,%5d,%5d] %s\n",
+                                " %10s | %08" PRIxPTR " | %08x | %08x | %02x | %05x | %08x | [%7d,%7d,%7d,%7d] | [%5d,%5d,%5d,%5d] %s\n",
                                         compositionTypeName[type],
                                         intptr_t(l.handle), l.hints, l.flags, l.transform, l.blending, format,
                                         l.sourceCrop.left, l.sourceCrop.top, l.sourceCrop.right, l.sourceCrop.bottom,
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.h b/services/surfaceflinger/DisplayHardware/HWComposer.h
index 9f96113..9218bf6 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.h
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.h
@@ -45,9 +45,10 @@
 namespace android {
 // ---------------------------------------------------------------------------
 
-class GraphicBuffer;
 class Fence;
 class FloatRect;
+class GraphicBuffer;
+class NativeHandle;
 class Region;
 class String8;
 class SurfaceFlinger;
@@ -164,6 +165,7 @@
         virtual void setFrame(const Rect& frame) = 0;
         virtual void setCrop(const FloatRect& crop) = 0;
         virtual void setVisibleRegionScreen(const Region& reg) = 0;
+        virtual void setSidebandStream(const sp<NativeHandle>& stream) = 0;
         virtual void setBuffer(const sp<GraphicBuffer>& buffer) = 0;
         virtual void setAcquireFenceFd(int fenceFd) = 0;
         virtual void setPlaneAlpha(uint8_t alpha) = 0;
diff --git a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
index a1820ab..11c42e0 100644
--- a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
+++ b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
@@ -374,6 +374,17 @@
     return result;
 }
 
+status_t VirtualDisplaySurface::detachBuffer(int /* slot */) {
+    VDS_LOGE("detachBuffer is not available for VirtualDisplaySurface");
+    return INVALID_OPERATION;
+}
+
+status_t VirtualDisplaySurface::attachBuffer(int* /* outSlot */,
+        const sp<GraphicBuffer>& /* buffer */) {
+    VDS_LOGE("attachBuffer is not available for VirtualDisplaySurface");
+    return INVALID_OPERATION;
+}
+
 status_t VirtualDisplaySurface::queueBuffer(int pslot,
         const QueueBufferInput& input, QueueBufferOutput* output) {
     VDS_LOGW_IF(mDbgState != DBG_STATE_GLES,
@@ -458,6 +469,10 @@
     return mSource[SOURCE_SINK]->disconnect(api);
 }
 
+status_t VirtualDisplaySurface::setSidebandStream(const sp<NativeHandle>& /*stream*/) {
+    return INVALID_OPERATION;
+}
+
 void VirtualDisplaySurface::updateQueueBufferOutput(
         const QueueBufferOutput& qbo) {
     uint32_t w, h, transformHint, numPendingBuffers;
diff --git a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h
index 6899904..0d30a1b 100644
--- a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h
+++ b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h
@@ -98,6 +98,8 @@
     virtual status_t setBufferCount(int bufferCount);
     virtual status_t dequeueBuffer(int* pslot, sp<Fence>* fence, bool async,
             uint32_t w, uint32_t h, uint32_t format, uint32_t usage);
+    virtual status_t detachBuffer(int slot);
+    virtual status_t attachBuffer(int* slot, const sp<GraphicBuffer>& buffer);
     virtual status_t queueBuffer(int pslot,
             const QueueBufferInput& input, QueueBufferOutput* output);
     virtual void cancelBuffer(int pslot, const sp<Fence>& fence);
@@ -105,6 +107,7 @@
     virtual status_t connect(const sp<IBinder>& token,
             int api, bool producerControlledByApp, QueueBufferOutput* output);
     virtual status_t disconnect(int api);
+    virtual status_t setSidebandStream(const sp<NativeHandle>& stream);
 
     //
     // Utility methods
diff --git a/services/surfaceflinger/Effects/Daltonizer.cpp b/services/surfaceflinger/Effects/Daltonizer.cpp
index f384ba4..feb8936 100644
--- a/services/surfaceflinger/Effects/Daltonizer.cpp
+++ b/services/surfaceflinger/Effects/Daltonizer.cpp
@@ -148,9 +148,6 @@
     // set to identity, errp, errd, errt ([0] for simulation only)
     mat4 correction(0);
 
-    // control: simulation post-correction (used for debugging):
-    // set to identity or lms2lmsp, lms2lmsd, lms2lmst
-    mat4 control;
     switch (mType) {
         case protanopia:
         case protanomaly:
@@ -172,12 +169,8 @@
             break;
     }
 
-    if (true) {
-        control = simulation;
-    }
-
-    mColorTransform = lms2rgb * control *
-            (simulation * rgb2lms + correction * (rgb2lms - simulation * rgb2lms));
+    mColorTransform = lms2rgb *
+        (simulation * rgb2lms + correction * (rgb2lms - simulation * rgb2lms));
 }
 
 } /* namespace android */
diff --git a/services/surfaceflinger/EventThread.cpp b/services/surfaceflinger/EventThread.cpp
index 3528b62..d868f32 100644
--- a/services/surfaceflinger/EventThread.cpp
+++ b/services/surfaceflinger/EventThread.cpp
@@ -328,7 +328,7 @@
             mDebugVsyncEnabled?"enabled":"disabled");
     result.appendFormat("  soft-vsync: %s\n",
             mUseSoftwareVSync?"enabled":"disabled");
-    result.appendFormat("  numListeners=%u,\n  events-delivered: %u\n",
+    result.appendFormat("  numListeners=%zu,\n  events-delivered: %u\n",
             mDisplayEventConnections.size(),
             mVSyncEvent[DisplayDevice::DISPLAY_PRIMARY].vsync.count);
     for (size_t i=0 ; i<mDisplayEventConnections.size() ; i++) {
diff --git a/services/surfaceflinger/FrameTracker.cpp b/services/surfaceflinger/FrameTracker.cpp
index d406672..2fb665e 100644
--- a/services/surfaceflinger/FrameTracker.cpp
+++ b/services/surfaceflinger/FrameTracker.cpp
@@ -17,6 +17,8 @@
 // This is needed for stdint.h to define INT64_MAX in C++
 #define __STDC_LIMIT_MACROS
 
+#include <inttypes.h>
+
 #include <cutils/log.h>
 
 #include <ui/Fence.h>
@@ -211,7 +213,7 @@
     const size_t o = mOffset;
     for (size_t i = 1; i < NUM_FRAME_RECORDS; i++) {
         const size_t index = (o+i) % NUM_FRAME_RECORDS;
-        result.appendFormat("%lld\t%lld\t%lld\n",
+        result.appendFormat("%" PRId64 "\t%" PRId64 "\t%" PRId64 "\n",
             mFrameRecords[index].desiredPresentTime,
             mFrameRecords[index].actualPresentTime,
             mFrameRecords[index].frameReadyTime);
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 465d376..019d892 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -27,6 +27,7 @@
 
 #include <utils/Errors.h>
 #include <utils/Log.h>
+#include <utils/NativeHandle.h>
 #include <utils/StopWatch.h>
 #include <utils/Trace.h>
 
@@ -66,6 +67,7 @@
         mFormat(PIXEL_FORMAT_NONE),
         mTransactionFlags(0),
         mQueuedFrames(0),
+        mSidebandStreamChanged(false),
         mCurrentTransform(0),
         mCurrentScalingMode(NATIVE_WINDOW_SCALING_MODE_FREEZE),
         mCurrentOpacity(true),
@@ -118,7 +120,7 @@
     mBufferQueue = new SurfaceTextureLayer(mFlinger);
     mSurfaceFlingerConsumer = new SurfaceFlingerConsumer(mBufferQueue, mTextureName);
     mSurfaceFlingerConsumer->setConsumerUsageBits(getEffectiveUsage(0));
-    mSurfaceFlingerConsumer->setFrameAvailableListener(this);
+    mSurfaceFlingerConsumer->setContentsChangedListener(this);
     mSurfaceFlingerConsumer->setName(mName);
 
 #ifdef TARGET_DISABLE_TRIPLE_BUFFERING
@@ -158,6 +160,13 @@
     mFlinger->signalLayerUpdate();
 }
 
+void Layer::onSidebandStreamChanged() {
+    if (android_atomic_release_cas(false, true, &mSidebandStreamChanged) == 0) {
+        // mSidebandStreamChanged was false
+        mFlinger->signalLayerUpdate();
+    }
+}
+
 // called with SurfaceFlinger::mStateLock from the drawing thread after
 // the layer has been remove from the current state list (and just before
 // it's removed from the drawing state list)
@@ -413,9 +422,13 @@
     Region visible = tr.transform(visibleRegion.intersect(hw->getViewport()));
     layer.setVisibleRegionScreen(visible);
 
-    // NOTE: buffer can be NULL if the client never drew into this
-    // layer yet, or if we ran out of memory
-    layer.setBuffer(mActiveBuffer);
+    if (mSidebandStream.get()) {
+        layer.setSidebandStream(mSidebandStream);
+    } else {
+        // NOTE: buffer can be NULL if the client never drew into this
+        // layer yet, or if we ran out of memory
+        layer.setBuffer(mActiveBuffer);
+    }
 }
 
 void Layer::setAcquireFence(const sp<const DisplayDevice>& /* hw */,
@@ -907,7 +920,7 @@
 
 bool Layer::onPreComposition() {
     mRefreshPending = false;
-    return mQueuedFrames > 0;
+    return mQueuedFrames > 0 || mSidebandStreamChanged;
 }
 
 void Layer::onPostComposition() {
@@ -950,6 +963,11 @@
 {
     ATRACE_CALL();
 
+    if (android_atomic_acquire_cas(true, false, &mSidebandStreamChanged) == 0) {
+        // mSidebandStreamChanged was true
+        mSidebandStream = mSurfaceFlingerConsumer->getSidebandStream();
+    }
+
     Region outDirtyRegion;
     if (mQueuedFrames > 0) {
 
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index 9283eaa..43de999 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -66,7 +66,7 @@
  * This also implements onFrameAvailable(), which notifies SurfaceFlinger
  * that new data has arrived.
  */
-class Layer : public SurfaceFlingerConsumer::FrameAvailableListener {
+class Layer : public SurfaceFlingerConsumer::ContentsChangedListener {
     static int32_t sSequence;
 
 public:
@@ -313,8 +313,9 @@
 
 
 private:
-    // Interface implementation for SurfaceFlingerConsumer::FrameAvailableListener
+    // Interface implementation for SurfaceFlingerConsumer::ContentsChangedListener
     virtual void onFrameAvailable();
+    virtual void onSidebandStreamChanged();
 
     void commitTransaction();
 
@@ -351,10 +352,12 @@
 
     // thread-safe
     volatile int32_t mQueuedFrames;
+    volatile int32_t mSidebandStreamChanged; // used like an atomic boolean
     FrameTracker mFrameTracker;
 
     // main thread
     sp<GraphicBuffer> mActiveBuffer;
+    sp<NativeHandle> mSidebandStream;
     Rect mCurrentCrop;
     uint32_t mCurrentTransform;
     uint32_t mCurrentScalingMode;
diff --git a/services/surfaceflinger/MessageQueue.cpp b/services/surfaceflinger/MessageQueue.cpp
index cc672b6..1ad86a6 100644
--- a/services/surfaceflinger/MessageQueue.cpp
+++ b/services/surfaceflinger/MessageQueue.cpp
@@ -179,7 +179,7 @@
     return queue->eventReceiver(fd, events);
 }
 
-int MessageQueue::eventReceiver(int fd, int events) {
+int MessageQueue::eventReceiver(int /*fd*/, int /*events*/) {
     ssize_t n;
     DisplayEventReceiver::Event buffer[8];
     while ((n = DisplayEventReceiver::getEvents(mEventTube, buffer, 8)) > 0) {
diff --git a/services/surfaceflinger/RenderEngine/GLES11RenderEngine.cpp b/services/surfaceflinger/RenderEngine/GLES11RenderEngine.cpp
index 521a5d2..cbff320 100644
--- a/services/surfaceflinger/RenderEngine/GLES11RenderEngine.cpp
+++ b/services/surfaceflinger/RenderEngine/GLES11RenderEngine.cpp
@@ -237,7 +237,7 @@
     }
 }
 
-void GLES11RenderEngine::beginGroup(const mat4& colorTransform) {
+void GLES11RenderEngine::beginGroup(const mat4& /*colorTransform*/) {
     // doesn't do anything in GLES 1.1
 }
 
diff --git a/services/surfaceflinger/RenderEngine/Program.cpp b/services/surfaceflinger/RenderEngine/Program.cpp
index 4a7fb58..0424e0c 100644
--- a/services/surfaceflinger/RenderEngine/Program.cpp
+++ b/services/surfaceflinger/RenderEngine/Program.cpp
@@ -25,7 +25,7 @@
 
 namespace android {
 
-Program::Program(const ProgramCache::Key& needs, const char* vertex, const char* fragment)
+Program::Program(const ProgramCache::Key& /*needs*/, const char* vertex, const char* fragment)
         : mInitialized(false) {
     GLuint vertexId = buildShader(vertex, GL_VERTEX_SHADER);
     GLuint fragmentId = buildShader(fragment, GL_FRAGMENT_SHADER);
@@ -112,7 +112,7 @@
     return shader;
 }
 
-String8& Program::dumpShader(String8& result, GLenum type) {
+String8& Program::dumpShader(String8& result, GLenum /*type*/) {
     GLuint shader = GL_FRAGMENT_SHADER ? mFragmentShader : mVertexShader;
     GLint l;
     glGetShaderiv(shader, GL_SHADER_SOURCE_LENGTH, &l);
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 808fa1b..e05417f 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -21,6 +21,7 @@
 #include <errno.h>
 #include <math.h>
 #include <dlfcn.h>
+#include <inttypes.h>
 
 #include <EGL/egl.h>
 
@@ -430,7 +431,7 @@
                 // FIXME: currently we don't get blank/unblank requests
                 // for displays other than the main display, so we always
                 // assume a connected display is unblanked.
-                ALOGD("marking display %d as acquired/unblanked", i);
+                ALOGD("marking display %zu as acquired/unblanked", i);
                 hw->acquireScreen();
             }
             mDisplays.add(token, hw);
@@ -1655,7 +1656,7 @@
                     case HWC_FRAMEBUFFER_TARGET: {
                         // this should not happen as the iterator shouldn't
                         // let us get there.
-                        ALOGW("HWC_FRAMEBUFFER_TARGET found in hwc list (index=%d)", i);
+                        ALOGW("HWC_FRAMEBUFFER_TARGET found in hwc list (index=%zu)", i);
                         break;
                     }
                 }
@@ -2242,7 +2243,7 @@
 
     const nsecs_t period =
             getHwComposer().getRefreshPeriod(HWC_DISPLAY_PRIMARY);
-    result.appendFormat("%lld\n", period);
+    result.appendFormat("%" PRId64 "\n", period);
 
     if (name.isEmpty()) {
         mAnimFrameTracker.dump(result);
@@ -2355,7 +2356,7 @@
     const LayerVector& currentLayers = mCurrentState.layersSortedByZ;
     const size_t count = currentLayers.size();
     colorizer.bold(result);
-    result.appendFormat("Visible layers (count = %d)\n", count);
+    result.appendFormat("Visible layers (count = %zu)\n", count);
     colorizer.reset(result);
     for (size_t i=0 ; i<count ; i++) {
         const sp<Layer>& layer(currentLayers[i]);
@@ -2367,7 +2368,7 @@
      */
 
     colorizer.bold(result);
-    result.appendFormat("Displays (%d entries)\n", mDisplays.size());
+    result.appendFormat("Displays (%zu entries)\n", mDisplays.size());
     colorizer.reset(result);
     for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) {
         const sp<const DisplayDevice>& hw(mDisplays[dpy]);
@@ -2977,7 +2978,7 @@
             const bool visible = (state.layerStack == hw->getLayerStack())
                                 && (state.z >= minLayerZ && state.z <= maxLayerZ)
                                 && (layer->isVisible());
-            ALOGE("%c index=%d, name=%s, layerStack=%d, z=%d, visible=%d, flags=%x, alpha=%x",
+            ALOGE("%c index=%zu, name=%s, layerStack=%d, z=%d, visible=%d, flags=%x, alpha=%x",
                     visible ? '+' : '-',
                             i, layer->getName().string(), state.layerStack, state.z,
                             layer->isVisible(), state.flags, state.alpha);
diff --git a/services/surfaceflinger/SurfaceFlingerConsumer.cpp b/services/surfaceflinger/SurfaceFlingerConsumer.cpp
index 6dc093e..a412543 100644
--- a/services/surfaceflinger/SurfaceFlingerConsumer.cpp
+++ b/services/surfaceflinger/SurfaceFlingerConsumer.cpp
@@ -21,8 +21,9 @@
 
 #include <private/gui/SyncFeatures.h>
 
-#include <utils/Trace.h>
 #include <utils/Errors.h>
+#include <utils/NativeHandle.h>
+#include <utils/Trace.h>
 
 namespace android {
 
@@ -112,6 +113,10 @@
     return mTransformToDisplayInverse;
 }
 
+sp<NativeHandle> SurfaceFlingerConsumer::getSidebandStream() const {
+    return mConsumer->getSidebandStream();
+}
+
 // We need to determine the time when a buffer acquired now will be
 // displayed.  This can be calculated:
 //   time when previous buffer's actual-present fence was signaled
@@ -154,6 +159,26 @@
     return prevVsync + hwcLatency * vsyncPeriod + extraPadding;
 }
 
+void SurfaceFlingerConsumer::setContentsChangedListener(
+        const wp<ContentsChangedListener>& listener) {
+    setFrameAvailableListener(listener);
+    Mutex::Autolock lock(mMutex);
+    mContentsChangedListener = listener;
+}
+
+void SurfaceFlingerConsumer::onSidebandStreamChanged() {
+    sp<ContentsChangedListener> listener;
+    {   // scope for the lock
+        Mutex::Autolock lock(mMutex);
+        ALOG_ASSERT(mFrameAvailableListener.unsafe_get() == mContentsChangedListener.unsafe_get());
+        listener = mContentsChangedListener.promote();
+    }
+
+    if (listener != NULL) {
+        listener->onSidebandStreamChanged();
+    }
+}
+
 // ---------------------------------------------------------------------------
 }; // namespace android
 
diff --git a/services/surfaceflinger/SurfaceFlingerConsumer.h b/services/surfaceflinger/SurfaceFlingerConsumer.h
index 688ad32..becd5d3 100644
--- a/services/surfaceflinger/SurfaceFlingerConsumer.h
+++ b/services/surfaceflinger/SurfaceFlingerConsumer.h
@@ -27,6 +27,10 @@
  */
 class SurfaceFlingerConsumer : public GLConsumer {
 public:
+    struct ContentsChangedListener: public FrameAvailableListener {
+        virtual void onSidebandStreamChanged() = 0;
+    };
+
     SurfaceFlingerConsumer(const sp<BufferQueue>& bq, uint32_t tex)
         : GLConsumer(bq, tex, GLConsumer::TEXTURE_EXTERNAL, false)
     {}
@@ -54,9 +58,19 @@
     // must be called from SF main thread
     bool getTransformToDisplayInverse() const;
 
+    // Sets the contents changed listener. This should be used instead of
+    // ConsumerBase::setFrameAvailableListener().
+    void setContentsChangedListener(const wp<ContentsChangedListener>& listener);
+
+    sp<NativeHandle> getSidebandStream() const;
+
 private:
     nsecs_t computeExpectedPresent();
 
+    virtual void onSidebandStreamChanged();
+
+    wp<ContentsChangedListener> mContentsChangedListener;
+
     // Indicates this buffer must be transformed by the inverse transform of the screen
     // it is displayed onto. This is applied after GLConsumer::mCurrentTransform.
     // This must be set/read from SurfaceFlinger's main thread.