Merge "Add NULL check to CallStack::toString"
diff --git a/cmds/installd/Android.mk b/cmds/installd/Android.mk
index 1dd4ee5..6eecb20 100644
--- a/cmds/installd/Android.mk
+++ b/cmds/installd/Android.mk
@@ -11,9 +11,8 @@
 
 LOCAL_SRC_FILES := \
     $(common_src_files)
-
+LOCAL_CFLAGS := -std=gnu99
 LOCAL_MODULE := libinstalld
-
 LOCAL_MODULE_TAGS := eng tests
 
 include $(BUILD_STATIC_LIBRARY)
@@ -36,7 +35,7 @@
     libdiskusage
 
 LOCAL_MODULE := installd
-
+LOCAL_CFLAGS := -std=gnu99
 LOCAL_MODULE_TAGS := optional
 
 include $(BUILD_EXECUTABLE)
diff --git a/cmds/installd/commands.c b/cmds/installd/commands.c
index 2a54710..e22fa6a 100644
--- a/cmds/installd/commands.c
+++ b/cmds/installd/commands.c
@@ -28,13 +28,15 @@
 dir_rec_t android_media_dir;
 dir_rec_array_t android_system_dirs;
 
-int install(const char *pkgname, uid_t uid, gid_t gid)
+int install(const char *pkgname, uid_t uid, gid_t gid, bool restrictHomeDir)
 {
     char pkgdir[PKG_PATH_MAX];
     char libsymlink[PKG_PATH_MAX];
     char applibdir[PKG_PATH_MAX];
     struct stat libStat;
 
+    mode_t defaultMode = restrictHomeDir ? 0700 : 0751;
+
     if ((uid < AID_SYSTEM) || (gid < AID_SYSTEM)) {
         ALOGE("invalid uid/gid: %d %d\n", uid, gid);
         return -1;
@@ -55,11 +57,11 @@
         return -1;
     }
 
-    if (mkdir(pkgdir, 0751) < 0) {
+    if (mkdir(pkgdir, defaultMode) < 0) {
         ALOGE("cannot create dir '%s': %s\n", pkgdir, strerror(errno));
         return -1;
     }
-    if (chmod(pkgdir, 0751) < 0) {
+    if (chmod(pkgdir, defaultMode) < 0) {
         ALOGE("cannot chmod dir '%s': %s\n", pkgdir, strerror(errno));
         unlink(pkgdir);
         return -1;
@@ -184,13 +186,15 @@
     return delete_dir_contents(pkgdir, 0, "lib");
 }
 
-int make_user_data(const char *pkgname, uid_t uid, uid_t persona)
+int make_user_data(const char *pkgname, uid_t uid, uid_t persona, bool restrictHomeDir)
 {
     char pkgdir[PKG_PATH_MAX];
     char applibdir[PKG_PATH_MAX];
     char libsymlink[PKG_PATH_MAX];
     struct stat libStat;
 
+    mode_t defaultMode = restrictHomeDir ? 0700 : 0751;
+
     // Create the data dir for the package
     if (create_pkg_path(pkgdir, pkgname, PKG_DIR_POSTFIX, persona)) {
         return -1;
@@ -204,11 +208,11 @@
         return -1;
     }
 
-    if (mkdir(pkgdir, 0751) < 0) {
+    if (mkdir(pkgdir, defaultMode) < 0) {
         ALOGE("cannot create dir '%s': %s\n", pkgdir, strerror(errno));
         return -errno;
     }
-    if (chmod(pkgdir, 0751) < 0) {
+    if (chmod(pkgdir, defaultMode) < 0) {
         ALOGE("cannot chmod dir '%s': %s\n", pkgdir, strerror(errno));
         unlink(pkgdir);
         return -errno;
@@ -283,53 +287,6 @@
     return 0;
 }
 
-int clone_persona_data(uid_t src_persona, uid_t target_persona, int copy)
-{
-    char src_data_dir[PKG_PATH_MAX];
-    char pkg_path[PKG_PATH_MAX];
-    DIR *d;
-    struct dirent *de;
-    struct stat s;
-    uid_t uid;
-
-    if (create_persona_path(src_data_dir, src_persona)) {
-        return -1;
-    }
-
-    d = opendir(src_data_dir);
-    if (d != NULL) {
-        while ((de = readdir(d))) {
-            const char *name = de->d_name;
-
-            if (de->d_type == DT_DIR) {
-                int subfd;
-                    /* always skip "." and ".." */
-                if (name[0] == '.') {
-                    if (name[1] == 0) continue;
-                    if ((name[1] == '.') && (name[2] == 0)) continue;
-                }
-                /* Create the full path to the package's data dir */
-                create_pkg_path(pkg_path, name, PKG_DIR_POSTFIX, src_persona);
-                /* Get the file stat */
-                if (stat(pkg_path, &s) < 0) continue;
-                /* Get the uid of the package */
-                ALOGI("Adding datadir for uid = %lu\n", s.st_uid);
-                uid = (uid_t) s.st_uid % PER_USER_RANGE;
-                /* Create the directory for the target */
-                make_user_data(name, uid + target_persona * PER_USER_RANGE,
-                               target_persona);
-            }
-        }
-        closedir(d);
-    }
-
-    if (ensure_media_user_dirs((userid_t) target_persona) == -1) {
-        return -1;
-    }
-
-    return 0;
-}
-
 int delete_cache(const char *pkgname, uid_t persona)
 {
     char cachedir[PKG_PATH_MAX];
diff --git a/cmds/installd/installd.c b/cmds/installd/installd.c
index 21d674a..bf21102 100644
--- a/cmds/installd/installd.c
+++ b/cmds/installd/installd.c
@@ -31,7 +31,11 @@
 
 static int do_install(char **arg, char reply[REPLY_MAX])
 {
-    return install(arg[0], atoi(arg[1]), atoi(arg[2])); /* pkgname, uid, gid */
+    bool restrictHomeDir = (strncmp(arg[3], "false", 6) != 0);
+    return install(arg[0],           /* pkgname */
+                   atoi(arg[1]),     /* uid */
+                   atoi(arg[2]),     /* gid */
+                   restrictHomeDir); /* restrictHomeDir */
 }
 
 static int do_dexopt(char **arg, char reply[REPLY_MAX])
@@ -103,7 +107,11 @@
 
 static int do_mk_user_data(char **arg, char reply[REPLY_MAX])
 {
-    return make_user_data(arg[0], atoi(arg[1]), atoi(arg[2])); /* pkgname, uid, userid */
+    bool restrictHomeDir = (strncmp(arg[3], "false", 6) != 0);
+    return make_user_data(arg[0],           /* pkgname */
+                          atoi(arg[1]),     /* uid */
+                          atoi(arg[2]),     /* userid */
+                          restrictHomeDir); /* restrictHomeDir */
 }
 
 static int do_rm_user(char **arg, char reply[REPLY_MAX])
@@ -111,11 +119,6 @@
     return delete_persona(atoi(arg[0])); /* userid */
 }
 
-static int do_clone_user_data(char **arg, char reply[REPLY_MAX])
-{
-    return clone_persona_data(atoi(arg[0]), atoi(arg[1]), atoi(arg[2]));
-}
-
 static int do_movefiles(char **arg, char reply[REPLY_MAX])
 {
     return movefiles();
@@ -134,7 +137,7 @@
 
 struct cmdinfo cmds[] = {
     { "ping",                 0, do_ping },
-    { "install",              3, do_install },
+    { "install",              4, do_install },
     { "dexopt",               3, do_dexopt },
     { "movedex",              2, do_move_dex },
     { "rmdex",                1, do_rm_dex },
@@ -147,9 +150,8 @@
     { "rmuserdata",           2, do_rm_user_data },
     { "movefiles",            0, do_movefiles },
     { "linklib",              3, do_linklib },
-    { "mkuserdata",           3, do_mk_user_data },
+    { "mkuserdata",           4, do_mk_user_data },
     { "rmuser",               1, do_rm_user },
-    { "cloneuserdata",        3, do_clone_user_data },
 };
 
 static int readx(int s, void *_buf, int count)
diff --git a/cmds/installd/installd.h b/cmds/installd/installd.h
index 0500c23..cf2bed6 100644
--- a/cmds/installd/installd.h
+++ b/cmds/installd/installd.h
@@ -20,6 +20,7 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <stdint.h>
+#include <stdbool.h>
 #include <inttypes.h>
 #include <sys/stat.h>
 #include <dirent.h>
@@ -192,14 +193,15 @@
 
 /* commands.c */
 
-int install(const char *pkgname, uid_t uid, gid_t gid);
+int install(const char *pkgname, uid_t uid, gid_t gid,
+            bool restrictHomeDirectory);
 int uninstall(const char *pkgname, uid_t persona);
 int renamepkg(const char *oldpkgname, const char *newpkgname);
 int fix_uid(const char *pkgname, uid_t uid, gid_t gid);
 int delete_user_data(const char *pkgname, uid_t persona);
-int make_user_data(const char *pkgname, uid_t uid, uid_t persona);
+int make_user_data(const char *pkgname, uid_t uid, uid_t persona,
+                   bool restrictHomeDirectory);
 int delete_persona(uid_t persona);
-int clone_persona_data(uid_t src_persona, uid_t target_persona, int copy);
 int delete_cache(const char *pkgname, uid_t persona);
 int move_dex(const char *src, const char *dst);
 int rm_dex(const char *path);
diff --git a/include/android/bitmap.h b/include/android/bitmap.h
index 5078277..6e18763 100644
--- a/include/android/bitmap.h
+++ b/include/android/bitmap.h
@@ -24,11 +24,14 @@
 extern "C" {
 #endif
 
-#define ANDROID_BITMAP_RESUT_SUCCESS            0
+#define ANDROID_BITMAP_RESULT_SUCCESS            0
 #define ANDROID_BITMAP_RESULT_BAD_PARAMETER     -1
 #define ANDROID_BITMAP_RESULT_JNI_EXCEPTION     -2
 #define ANDROID_BITMAP_RESULT_ALLOCATION_FAILED -3
 
+/* Backward compatibility: this macro used to be misspelled. */
+#define ANDROID_BITMAP_RESUT_SUCCESS ANDROID_BITMAP_RESULT_SUCCESS
+
 enum AndroidBitmapFormat {
     ANDROID_BITMAP_FORMAT_NONE      = 0,
     ANDROID_BITMAP_FORMAT_RGBA_8888 = 1,
diff --git a/include/gui/BufferQueue.h b/include/gui/BufferQueue.h
index 9e265ba..88bcd8f 100644
--- a/include/gui/BufferQueue.h
+++ b/include/gui/BufferQueue.h
@@ -182,8 +182,9 @@
            mBuf(INVALID_BUFFER_SLOT) {
              mCrop.makeInvalid();
          }
-        // mGraphicBuffer points to the buffer allocated for this slot or is NULL
-        // if no buffer has been allocated.
+        // 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;
 
         // mCrop is the current crop rectangle for this buffer slot.
diff --git a/services/surfaceflinger/DisplayHardware/GraphicBufferAlloc.h b/include/gui/GraphicBufferAlloc.h
similarity index 100%
rename from services/surfaceflinger/DisplayHardware/GraphicBufferAlloc.h
rename to include/gui/GraphicBufferAlloc.h
diff --git a/include/gui/SurfaceTexture.h b/include/gui/SurfaceTexture.h
index b498a5c..ae5d57a 100644
--- a/include/gui/SurfaceTexture.h
+++ b/include/gui/SurfaceTexture.h
@@ -74,14 +74,13 @@
             GLenum texTarget = GL_TEXTURE_EXTERNAL_OES, bool useFenceSync = true,
             const sp<BufferQueue> &bufferQueue = 0);
 
-    // updateTexImage sets the image contents of the target texture to that of
-    // the most recently queued buffer.
+    // updateTexImage acquires the most recently queued buffer, and sets the
+    // image contents of the target texture to it.
     //
     // This call may only be made while the OpenGL ES context to which the
     // target texture belongs is bound to the calling thread.
     //
-    // After calling this method the doGLFenceWait method must be called
-    // before issuing OpenGL ES commands that access the texture contents.
+    // This calls doGLFenceWait to ensure proper synchronization.
     status_t updateTexImage();
 
     // setReleaseFence stores a fence file descriptor that will signal when the
@@ -161,8 +160,7 @@
 
     // doGLFenceWait inserts a wait command into the OpenGL ES command stream
     // to ensure that it is safe for future OpenGL ES commands to access the
-    // current texture buffer.  This must be called each time updateTexImage
-    // is called before issuing OpenGL ES commands that access the texture.
+    // current texture buffer.
     status_t doGLFenceWait() const;
 
     // isSynchronousMode returns whether the SurfaceTexture is currently in
@@ -233,23 +231,33 @@
     virtual status_t releaseBufferLocked(int buf, EGLDisplay display,
            EGLSyncKHR eglFence);
 
+    status_t releaseBufferLocked(int buf, EGLSyncKHR eglFence) {
+        return releaseBufferLocked(buf, mEglDisplay, eglFence);
+    }
+
     static bool isExternalFormat(uint32_t format);
 
-private:
-    // this version of updateTexImage() takes a functor used to reject or not
-    // the newly acquired buffer.
-    // this API is TEMPORARY and intended to be used by SurfaceFlinger only,
-    // which is why class Layer is made a friend of SurfaceTexture below.
-    class BufferRejecter {
-        friend class SurfaceTexture;
-        virtual bool reject(const sp<GraphicBuffer>& buf,
-                const BufferQueue::BufferItem& item) = 0;
-    protected:
-        virtual ~BufferRejecter() { }
-    };
-    friend class Layer;
-    status_t updateTexImage(BufferRejecter* rejecter, bool skipSync);
+    // This releases the buffer in the slot referenced by mCurrentTexture,
+    // then updates state to refer to the BufferItem, which must be a
+    // newly-acquired buffer.
+    status_t releaseAndUpdateLocked(const BufferQueue::BufferItem& item);
 
+    // Binds mTexName and the current buffer to mTexTarget.  Uses
+    // mCurrentTexture if it's set, mCurrentTextureBuf if not.  If the
+    // bind succeeds, this calls doGLFenceWait.
+    status_t bindTextureImageLocked();
+
+    // Gets the current EGLDisplay and EGLContext values, and compares them
+    // to mEglDisplay and mEglContext.  If the fields have been previously
+    // set, the values must match; if not, the fields are set to the current
+    // values.
+    status_t checkAndUpdateEglStateLocked();
+
+    // If set, SurfaceTexture will use the EGL_ANDROID_native_fence_sync
+    // extension to create Android native fences for GLES activity.
+    static const bool sUseNativeFenceSync;
+
+private:
     // createImage creates a new EGLImage from a GraphicBuffer.
     EGLImageKHR createImage(EGLDisplay dpy,
             const sp<GraphicBuffer>& graphicBuffer);
@@ -269,9 +277,7 @@
 
     // doGLFenceWaitLocked inserts a wait command into the OpenGL ES command
     // stream to ensure that it is safe for future OpenGL ES commands to
-    // access the current texture buffer.  This must be called each time
-    // updateTexImage is called before issuing OpenGL ES commands that access
-    // the texture.
+    // access the current texture buffer.
     status_t doGLFenceWaitLocked() const;
 
     // syncForReleaseLocked performs the synchronization needed to release the
@@ -280,6 +286,13 @@
     // before the outstanding accesses have completed.
     status_t syncForReleaseLocked(EGLDisplay dpy);
 
+    // Normally, when we bind a buffer to a texture target, we bind a buffer
+    // that is referenced by an entry in mEglSlots.  In some situations we
+    // have a buffer in mCurrentTextureBuf, but no corresponding entry for
+    // it in our slot array.  bindUnslottedBuffer handles that situation by
+    // binding the buffer without touching the EglSlots.
+    status_t bindUnslottedBufferLocked(EGLDisplay dpy);
+
     // The default consumer usage flags that SurfaceTexture always sets on its
     // BufferQueue instance; these will be OR:d with any additional flags passed
     // from the SurfaceTexture user. In particular, SurfaceTexture will always
@@ -344,8 +357,8 @@
 
     // EGLSlot contains the information and object references that
     // SurfaceTexture maintains about a BufferQueue buffer slot.
-    struct EGLSlot {
-        EGLSlot()
+    struct EglSlot {
+        EglSlot()
         : mEglImage(EGL_NO_IMAGE_KHR),
           mEglFence(EGL_NO_SYNC_KHR) {
         }
@@ -379,7 +392,7 @@
     // slot that has not yet been used. The buffer allocated to a slot will also
     // be replaced if the requested buffer usage or geometry differs from that
     // of the buffer allocated to a slot.
-    EGLSlot mEglSlots[BufferQueue::NUM_BUFFER_SLOTS];
+    EglSlot mEglSlots[BufferQueue::NUM_BUFFER_SLOTS];
 
     // mCurrentTexture is the buffer slot index of the buffer that is currently
     // bound to the OpenGL texture. It is initialized to INVALID_BUFFER_SLOT,
diff --git a/include/gui/SurfaceTextureClient.h b/include/gui/SurfaceTextureClient.h
index 50fd1ba..56d861a 100644
--- a/include/gui/SurfaceTextureClient.h
+++ b/include/gui/SurfaceTextureClient.h
@@ -41,12 +41,6 @@
 
     SurfaceTextureClient(const sp<ISurfaceTexture>& surfaceTexture);
 
-    // SurfaceTextureClient is overloaded to assist in refactoring ST and BQ.
-    // SurfaceTexture is no longer an ISurfaceTexture, so client code
-    // calling the original constructor will fail. Thus this convenience method
-    // passes in the surfaceTexture's bufferQueue to the init method.
-    SurfaceTextureClient(const sp<SurfaceTexture>& surfaceTexture);
-
     sp<ISurfaceTexture> getISurfaceTexture() const;
 
 protected:
diff --git a/include/utils/Mutex.h b/include/utils/Mutex.h
index de6fb39..dd201c8 100644
--- a/include/utils/Mutex.h
+++ b/include/utils/Mutex.h
@@ -91,10 +91,10 @@
 inline Mutex::Mutex() {
     pthread_mutex_init(&mMutex, NULL);
 }
-inline Mutex::Mutex(const char* name) {
+inline Mutex::Mutex(__attribute__((unused)) const char* name) {
     pthread_mutex_init(&mMutex, NULL);
 }
-inline Mutex::Mutex(int type, const char* name) {
+inline Mutex::Mutex(int type, __attribute__((unused)) const char* name) {
     if (type == SHARED) {
         pthread_mutexattr_t attr;
         pthread_mutexattr_init(&attr);
diff --git a/include/utils/RWLock.h b/include/utils/RWLock.h
index a5abea2..90beb5f 100644
--- a/include/utils/RWLock.h
+++ b/include/utils/RWLock.h
@@ -84,10 +84,10 @@
 inline RWLock::RWLock() {
     pthread_rwlock_init(&mRWLock, NULL);
 }
-inline RWLock::RWLock(const char* name) {
+inline RWLock::RWLock(__attribute__((unused)) const char* name) {
     pthread_rwlock_init(&mRWLock, NULL);
 }
-inline RWLock::RWLock(int type, const char* name) {
+inline RWLock::RWLock(int type, __attribute__((unused)) const char* name) {
     if (type == SHARED) {
         pthread_rwlockattr_t attr;
         pthread_rwlockattr_init(&attr);
diff --git a/include/utils/RefBase.h b/include/utils/RefBase.h
index 99f5182..0a8e10a 100644
--- a/include/utils/RefBase.h
+++ b/include/utils/RefBase.h
@@ -165,10 +165,10 @@
 {
 public:
     inline LightRefBase() : mCount(0) { }
-    inline void incStrong(const void* id) const {
+    inline void incStrong(__attribute__((unused)) const void* id) const {
         android_atomic_inc(&mCount);
     }
-    inline void decStrong(const void* id) const {
+    inline void decStrong(__attribute__((unused)) const void* id) const {
         if (android_atomic_dec(&mCount) == 1) {
             delete static_cast<const T*>(this);
         }
diff --git a/libs/gui/Android.mk b/libs/gui/Android.mk
index d970a33..04444e9 100644
--- a/libs/gui/Android.mk
+++ b/libs/gui/Android.mk
@@ -3,29 +3,30 @@
 
 LOCAL_SRC_FILES:= \
 	BitTube.cpp \
+	BufferItemConsumer.cpp \
 	BufferQueue.cpp \
 	ConsumerBase.cpp \
+	CpuConsumer.cpp \
 	DisplayEventReceiver.cpp \
+	DummyConsumer.cpp \
+	GraphicBufferAlloc.cpp \
+	GuiConfig.cpp \
 	IDisplayEventConnection.cpp \
+	IGraphicBufferAlloc.cpp \
 	ISensorEventConnection.cpp \
 	ISensorServer.cpp \
+	ISurface.cpp \
+	ISurfaceComposer.cpp \
+	ISurfaceComposerClient.cpp \
 	ISurfaceTexture.cpp \
+	LayerState.cpp \
 	Sensor.cpp \
 	SensorEventQueue.cpp \
 	SensorManager.cpp \
-	SurfaceTexture.cpp \
-	SurfaceTextureClient.cpp \
-	ISurfaceComposer.cpp \
-	ISurface.cpp \
-	ISurfaceComposerClient.cpp \
-	IGraphicBufferAlloc.cpp \
-	LayerState.cpp \
 	Surface.cpp \
 	SurfaceComposerClient.cpp \
-	DummyConsumer.cpp \
-	CpuConsumer.cpp \
-	BufferItemConsumer.cpp \
-	GuiConfig.cpp
+	SurfaceTexture.cpp \
+	SurfaceTextureClient.cpp \
 
 LOCAL_SHARED_LIBRARIES := \
 	libbinder \
diff --git a/libs/gui/BufferQueue.cpp b/libs/gui/BufferQueue.cpp
index 086e298..609e7d2 100644
--- a/libs/gui/BufferQueue.cpp
+++ b/libs/gui/BufferQueue.cpp
@@ -29,7 +29,6 @@
 #include <private/gui/ComposerService.h>
 
 #include <utils/Log.h>
-#include <gui/SurfaceTexture.h>
 #include <utils/Trace.h>
 
 // Macros for including the BufferQueue name in log messages
diff --git a/services/surfaceflinger/DisplayHardware/GraphicBufferAlloc.cpp b/libs/gui/GraphicBufferAlloc.cpp
similarity index 96%
rename from services/surfaceflinger/DisplayHardware/GraphicBufferAlloc.cpp
rename to libs/gui/GraphicBufferAlloc.cpp
index 965ff01..b360e81 100644
--- a/services/surfaceflinger/DisplayHardware/GraphicBufferAlloc.cpp
+++ b/libs/gui/GraphicBufferAlloc.cpp
@@ -19,7 +19,7 @@
 
 #include <ui/GraphicBuffer.h>
 
-#include "DisplayHardware/GraphicBufferAlloc.h"
+#include <gui/GraphicBufferAlloc.h>
 
 // ----------------------------------------------------------------------------
 namespace android {
diff --git a/libs/gui/SurfaceTexture.cpp b/libs/gui/SurfaceTexture.cpp
index b4dfb5e..ee3079e 100644
--- a/libs/gui/SurfaceTexture.cpp
+++ b/libs/gui/SurfaceTexture.cpp
@@ -39,6 +39,8 @@
 #include <utils/String8.h>
 #include <utils/Trace.h>
 
+namespace android {
+
 // This compile option makes SurfaceTexture use the
 // EGL_ANDROID_native_fence_sync extension to create Android native fences to
 // signal when all GLES reads for a given buffer have completed.  It is not
@@ -48,9 +50,9 @@
 #ifdef USE_FENCE_SYNC
 #error "USE_NATIVE_FENCE_SYNC and USE_FENCE_SYNC are incompatible"
 #endif
-static const bool useNativeFenceSync = true;
+const bool SurfaceTexture::sUseNativeFenceSync = true;
 #else
-static const bool useNativeFenceSync = false;
+const bool SurfaceTexture::sUseNativeFenceSync = false;
 #endif
 
 // This compile option makes SurfaceTexture use the EGL_ANDROID_sync_wait
@@ -70,8 +72,6 @@
 #define ST_LOGW(x, ...) ALOGW("[%s] "x, mName.string(), ##__VA_ARGS__)
 #define ST_LOGE(x, ...) ALOGE("[%s] "x, mName.string(), ##__VA_ARGS__)
 
-namespace android {
-
 // Transform matrices
 static float mtxIdentity[16] = {
     1, 0, 0, 0,
@@ -154,7 +154,50 @@
 }
 
 status_t SurfaceTexture::updateTexImage() {
-    return SurfaceTexture::updateTexImage(NULL, false);
+    ATRACE_CALL();
+    ST_LOGV("updateTexImage");
+    Mutex::Autolock lock(mMutex);
+
+    if (mAbandoned) {
+        ST_LOGE("updateTexImage: SurfaceTexture is abandoned!");
+        return NO_INIT;
+    }
+
+    // Make sure the EGL state is the same as in previous calls.
+    status_t err = checkAndUpdateEglStateLocked();
+    if (err != NO_ERROR) {
+        return err;
+    }
+
+    BufferQueue::BufferItem item;
+
+    // Acquire the next buffer.
+    // In asynchronous mode the list is guaranteed to be one buffer
+    // deep, while in synchronous mode we use the oldest buffer.
+    err = acquireBufferLocked(&item);
+    if (err != NO_ERROR) {
+        if (err == BufferQueue::NO_BUFFER_AVAILABLE) {
+            // We always bind the texture even if we don't update its contents.
+            ST_LOGV("updateTexImage: no buffers were available");
+            glBindTexture(mTexTarget, mTexName);
+            err = NO_ERROR;
+        } else {
+            ST_LOGE("updateTexImage: acquire failed: %s (%d)",
+                strerror(-err), err);
+        }
+        return err;
+    }
+
+    // Release the previous buffer.
+    err = releaseAndUpdateLocked(item);
+    if (err != NO_ERROR) {
+        // We always bind the texture.
+        glBindTexture(mTexTarget, mTexName);
+        return err;
+    }
+
+    // Bind the new buffer to the GL texture, and wait until it's ready.
+    return bindTextureImageLocked();
 }
 
 status_t SurfaceTexture::acquireBufferLocked(BufferQueue::BufferItem *item) {
@@ -165,161 +208,162 @@
 
     int slot = item->mBuf;
     if (item->mGraphicBuffer != NULL) {
+        // This buffer has not been acquired before, so we must assume
+        // that any EGLImage in mEglSlots is stale.
         if (mEglSlots[slot].mEglImage != EGL_NO_IMAGE_KHR) {
-            eglDestroyImageKHR(mEglDisplay, mEglSlots[slot].mEglImage);
+            if (!eglDestroyImageKHR(mEglDisplay, mEglSlots[slot].mEglImage)) {
+                ST_LOGW("acquireBufferLocked: eglDestroyImageKHR failed for slot=%d",
+                      slot);
+                // keep going
+            }
             mEglSlots[slot].mEglImage = EGL_NO_IMAGE_KHR;
         }
     }
 
-    // Update the GL texture object. We may have to do this even when
-    // item.mGraphicBuffer == NULL, if we destroyed the EGLImage when
-    // detaching from a context but the buffer has not been re-allocated.
-    if (mEglSlots[slot].mEglImage == EGL_NO_IMAGE_KHR) {
-        EGLImageKHR image = createImage(mEglDisplay, mSlots[slot].mGraphicBuffer);
-        if (image == EGL_NO_IMAGE_KHR) {
-            return UNKNOWN_ERROR;
-        }
-        mEglSlots[slot].mEglImage = image;
-    }
-
     return NO_ERROR;
 }
 
 status_t SurfaceTexture::releaseBufferLocked(int buf, EGLDisplay display,
        EGLSyncKHR eglFence) {
-    status_t err = ConsumerBase::releaseBufferLocked(buf, mEglDisplay,
-           eglFence);
+    status_t err = ConsumerBase::releaseBufferLocked(buf, display, eglFence);
 
     mEglSlots[buf].mEglFence = EGL_NO_SYNC_KHR;
 
     return err;
 }
 
-status_t SurfaceTexture::updateTexImage(BufferRejecter* rejecter, bool skipSync) {
-    ATRACE_CALL();
-    ST_LOGV("updateTexImage");
-    Mutex::Autolock lock(mMutex);
-
+status_t SurfaceTexture::releaseAndUpdateLocked(const BufferQueue::BufferItem& item)
+{
     status_t err = NO_ERROR;
 
-    if (mAbandoned) {
-        ST_LOGE("updateTexImage: SurfaceTexture is abandoned!");
-        return NO_INIT;
-    }
-
     if (!mAttached) {
-        ST_LOGE("updateTexImage: SurfaceTexture is not attached to an OpenGL "
+        ST_LOGE("releaseAndUpdate: SurfaceTexture is not attached to an OpenGL "
                 "ES context");
         return INVALID_OPERATION;
     }
 
+    // Confirm state.
+    err = checkAndUpdateEglStateLocked();
+    if (err != NO_ERROR) {
+        return err;
+    }
+
+    int buf = item.mBuf;
+
+    // If the mEglSlot entry is empty, create an EGLImage for the gralloc
+    // buffer currently in the slot in ConsumerBase.
+    //
+    // We may have to do this even when item.mGraphicBuffer == NULL (which
+    // means the buffer was previously acquired), if we destroyed the
+    // EGLImage when detaching from a context but the buffer has not been
+    // re-allocated.
+    if (mEglSlots[buf].mEglImage == EGL_NO_IMAGE_KHR) {
+        EGLImageKHR image = createImage(mEglDisplay, mSlots[buf].mGraphicBuffer);
+        if (image == EGL_NO_IMAGE_KHR) {
+            ST_LOGW("releaseAndUpdate: unable to createImage on display=%p slot=%d",
+                  mEglDisplay, buf);
+            return UNKNOWN_ERROR;
+        }
+        mEglSlots[buf].mEglImage = image;
+    }
+
+    // Do whatever sync ops we need to do before releasing the old slot.
+    err = syncForReleaseLocked(mEglDisplay);
+    if (err != NO_ERROR) {
+        // Release the buffer we just acquired.  It's not safe to
+        // release the old buffer, so instead we just drop the new frame.
+        releaseBufferLocked(buf, mEglDisplay, EGL_NO_SYNC_KHR);
+        return err;
+    }
+
+    ST_LOGV("releaseAndUpdate: (slot=%d buf=%p) -> (slot=%d buf=%p)",
+            mCurrentTexture,
+            mCurrentTextureBuf != NULL ? mCurrentTextureBuf->handle : 0,
+            buf, mSlots[buf].mGraphicBuffer->handle);
+
+    // release old buffer
+    if (mCurrentTexture != BufferQueue::INVALID_BUFFER_SLOT) {
+        status_t status = releaseBufferLocked(mCurrentTexture, mEglDisplay,
+                mEglSlots[mCurrentTexture].mEglFence);
+        if (status != NO_ERROR && status != BufferQueue::STALE_BUFFER_SLOT) {
+            ST_LOGE("releaseAndUpdate: failed to release buffer: %s (%d)",
+                   strerror(-status), status);
+            err = status;
+            // keep going, with error raised [?]
+        }
+    }
+
+    // Update the SurfaceTexture state.
+    mCurrentTexture = buf;
+    mCurrentTextureBuf = mSlots[buf].mGraphicBuffer;
+    mCurrentCrop = item.mCrop;
+    mCurrentTransform = item.mTransform;
+    mCurrentScalingMode = item.mScalingMode;
+    mCurrentTimestamp = item.mTimestamp;
+    mCurrentFence = item.mFence;
+
+    computeCurrentTransformMatrixLocked();
+
+    return err;
+}
+
+status_t SurfaceTexture::bindTextureImageLocked() {
+    if (mEglDisplay == EGL_NO_DISPLAY) {
+        ALOGE("bindTextureImage: invalid display");
+        return INVALID_OPERATION;
+    }
+
+    GLint error;
+    while ((error = glGetError()) != GL_NO_ERROR) {
+        ST_LOGW("bindTextureImage: clearing GL error: %#04x", error);
+    }
+
+    glBindTexture(mTexTarget, mTexName);
+    if (mCurrentTexture == BufferQueue::INVALID_BUFFER_SLOT) {
+        if (mCurrentTextureBuf == NULL) {
+            ST_LOGE("bindTextureImage: no currently-bound texture");
+            return NO_INIT;
+        }
+        status_t err = bindUnslottedBufferLocked(mEglDisplay);
+        if (err != NO_ERROR) {
+            return err;
+        }
+    } else {
+        EGLImageKHR image = mEglSlots[mCurrentTexture].mEglImage;
+
+        glEGLImageTargetTexture2DOES(mTexTarget, (GLeglImageOES)image);
+
+        while ((error = glGetError()) != GL_NO_ERROR) {
+            ST_LOGE("bindTextureImage: error binding external texture image %p"
+                    ": %#04x", image, error);
+            return UNKNOWN_ERROR;
+        }
+    }
+
+    // Wait for the new buffer to be ready.
+    return doGLFenceWaitLocked();
+
+}
+
+status_t SurfaceTexture::checkAndUpdateEglStateLocked() {
     EGLDisplay dpy = eglGetCurrentDisplay();
     EGLContext ctx = eglGetCurrentContext();
 
     if ((mEglDisplay != dpy && mEglDisplay != EGL_NO_DISPLAY) ||
             dpy == EGL_NO_DISPLAY) {
-        ST_LOGE("updateTexImage: invalid current EGLDisplay");
+        ST_LOGE("checkAndUpdateEglState: invalid current EGLDisplay");
         return INVALID_OPERATION;
     }
 
     if ((mEglContext != ctx && mEglContext != EGL_NO_CONTEXT) ||
             ctx == EGL_NO_CONTEXT) {
-        ST_LOGE("updateTexImage: invalid current EGLContext");
+        ST_LOGE("checkAndUpdateEglState: invalid current EGLContext");
         return INVALID_OPERATION;
     }
 
     mEglDisplay = dpy;
     mEglContext = ctx;
-
-    BufferQueue::BufferItem item;
-
-    // In asynchronous mode the list is guaranteed to be one buffer
-    // deep, while in synchronous mode we use the oldest buffer.
-    err = acquireBufferLocked(&item);
-    if (err == NO_ERROR) {
-        int buf = item.mBuf;
-
-        // we call the rejecter here, in case the caller has a reason to
-        // not accept this buffer. this is used by SurfaceFlinger to
-        // reject buffers which have the wrong size
-        if (rejecter && rejecter->reject(mSlots[buf].mGraphicBuffer, item)) {
-            releaseBufferLocked(buf, dpy, EGL_NO_SYNC_KHR);
-            glBindTexture(mTexTarget, mTexName);
-            return NO_ERROR;
-        }
-
-        GLint error;
-        while ((error = glGetError()) != GL_NO_ERROR) {
-            ST_LOGW("updateTexImage: clearing GL error: %#04x", error);
-        }
-
-        EGLImageKHR image = mEglSlots[buf].mEglImage;
-        glBindTexture(mTexTarget, mTexName);
-        glEGLImageTargetTexture2DOES(mTexTarget, (GLeglImageOES)image);
-
-        while ((error = glGetError()) != GL_NO_ERROR) {
-            ST_LOGE("updateTexImage: error binding external texture image %p "
-                    "(slot %d): %#04x", image, buf, error);
-            err = UNKNOWN_ERROR;
-        }
-
-        if (err == NO_ERROR) {
-            err = syncForReleaseLocked(dpy);
-        }
-
-        if (err != NO_ERROR) {
-            // Release the buffer we just acquired.  It's not safe to
-            // release the old buffer, so instead we just drop the new frame.
-            releaseBufferLocked(buf, dpy, EGL_NO_SYNC_KHR);
-            return err;
-        }
-
-        ST_LOGV("updateTexImage: (slot=%d buf=%p) -> (slot=%d buf=%p)",
-                mCurrentTexture,
-                mCurrentTextureBuf != NULL ? mCurrentTextureBuf->handle : 0,
-                buf, mSlots[buf].mGraphicBuffer->handle);
-
-        // release old buffer
-        if (mCurrentTexture != BufferQueue::INVALID_BUFFER_SLOT) {
-            status_t status = releaseBufferLocked(mCurrentTexture, dpy,
-                    mEglSlots[mCurrentTexture].mEglFence);
-            if (status != NO_ERROR && status != BufferQueue::STALE_BUFFER_SLOT) {
-                ST_LOGE("updateTexImage: failed to release buffer: %s (%d)",
-                       strerror(-status), status);
-                err = status;
-            }
-        }
-
-        // Update the SurfaceTexture state.
-        mCurrentTexture = buf;
-        mCurrentTextureBuf = mSlots[buf].mGraphicBuffer;
-        mCurrentCrop = item.mCrop;
-        mCurrentTransform = item.mTransform;
-        mCurrentScalingMode = item.mScalingMode;
-        mCurrentTimestamp = item.mTimestamp;
-        mCurrentFence = item.mFence;
-        if (!skipSync) {
-            // SurfaceFlinger needs to lazily perform GLES synchronization
-            // only when it's actually going to use GLES for compositing.
-            // Eventually SurfaceFlinger should have its own consumer class,
-            // but for now we'll just hack it in to SurfaceTexture.
-            // SurfaceFlinger is responsible for calling doGLFenceWait before
-            // texturing from this SurfaceTexture.
-            doGLFenceWaitLocked();
-        }
-        computeCurrentTransformMatrixLocked();
-    } else  {
-        if (err < 0) {
-            ST_LOGE("updateTexImage: acquire failed: %s (%d)",
-                strerror(-err), err);
-            return err;
-        }
-        // We always bind the texture even if we don't update its contents.
-        glBindTexture(mTexTarget, mTexName);
-        return OK;
-    }
-
-    return err;
+    return NO_ERROR;
 }
 
 void SurfaceTexture::setReleaseFence(int fenceFd) {
@@ -427,30 +471,8 @@
         // The EGLImageKHR that was associated with the slot was destroyed when
         // the SurfaceTexture was detached from the old context, so we need to
         // recreate it here.
-        EGLImageKHR image = createImage(dpy, mCurrentTextureBuf);
-        if (image == EGL_NO_IMAGE_KHR) {
-            return UNKNOWN_ERROR;
-        }
-
-        // Attach the current buffer to the GL texture.
-        glEGLImageTargetTexture2DOES(mTexTarget, (GLeglImageOES)image);
-
-        GLint error;
-        status_t err = OK;
-        while ((error = glGetError()) != GL_NO_ERROR) {
-            ST_LOGE("attachToContext: error binding external texture image %p "
-                    "(slot %d): %#04x", image, mCurrentTexture, error);
-            err = UNKNOWN_ERROR;
-        }
-
-        // We destroy the EGLImageKHR here because the current buffer may no
-        // longer be associated with one of the buffer slots, so we have
-        // nowhere to to store it.  If the buffer is still associated with a
-        // slot then another EGLImageKHR will be created next time that buffer
-        // gets acquired in updateTexImage.
-        eglDestroyImageKHR(dpy, image);
-
-        if (err != OK) {
+        status_t err = bindUnslottedBufferLocked(dpy);
+        if (err != NO_ERROR) {
             return err;
         }
     }
@@ -463,11 +485,43 @@
     return OK;
 }
 
+status_t SurfaceTexture::bindUnslottedBufferLocked(EGLDisplay dpy) {
+    ST_LOGV("bindUnslottedBuffer ct=%d ctb=%p",
+            mCurrentTexture, mCurrentTextureBuf.get());
+
+    // Create a temporary EGLImageKHR.
+    EGLImageKHR image = createImage(dpy, mCurrentTextureBuf);
+    if (image == EGL_NO_IMAGE_KHR) {
+        return UNKNOWN_ERROR;
+    }
+
+    // Attach the current buffer to the GL texture.
+    glEGLImageTargetTexture2DOES(mTexTarget, (GLeglImageOES)image);
+
+    GLint error;
+    status_t err = OK;
+    while ((error = glGetError()) != GL_NO_ERROR) {
+        ST_LOGE("bindUnslottedBuffer: error binding external texture image %p "
+                "(slot %d): %#04x", image, mCurrentTexture, error);
+        err = UNKNOWN_ERROR;
+    }
+
+    // We destroy the EGLImageKHR here because the current buffer may no
+    // longer be associated with one of the buffer slots, so we have
+    // nowhere to to store it.  If the buffer is still associated with a
+    // slot then another EGLImageKHR will be created next time that buffer
+    // gets acquired in updateTexImage.
+    eglDestroyImageKHR(dpy, image);
+
+    return err;
+}
+
+
 status_t SurfaceTexture::syncForReleaseLocked(EGLDisplay dpy) {
     ST_LOGV("syncForReleaseLocked");
 
     if (mCurrentTexture != BufferQueue::INVALID_BUFFER_SLOT) {
-        if (useNativeFenceSync) {
+        if (sUseNativeFenceSync) {
             EGLSyncKHR sync = eglCreateSyncKHR(dpy,
                     EGL_SYNC_NATIVE_FENCE_ANDROID, NULL);
             if (sync == EGL_NO_SYNC_KHR) {
diff --git a/libs/gui/SurfaceTextureClient.cpp b/libs/gui/SurfaceTextureClient.cpp
index afdbf04..7588b9e 100644
--- a/libs/gui/SurfaceTextureClient.cpp
+++ b/libs/gui/SurfaceTextureClient.cpp
@@ -41,14 +41,6 @@
     SurfaceTextureClient::setISurfaceTexture(surfaceTexture);
 }
 
-// see SurfaceTextureClient.h
-SurfaceTextureClient::SurfaceTextureClient(const
-         sp<SurfaceTexture>& surfaceTexture)
-{
-    SurfaceTextureClient::init();
-    SurfaceTextureClient::setISurfaceTexture(surfaceTexture->getBufferQueue());
-}
-
 SurfaceTextureClient::SurfaceTextureClient() {
     SurfaceTextureClient::init();
 }
diff --git a/libs/gui/tests/SurfaceTextureClient_test.cpp b/libs/gui/tests/SurfaceTextureClient_test.cpp
index ec14a0d..baeca06 100644
--- a/libs/gui/tests/SurfaceTextureClient_test.cpp
+++ b/libs/gui/tests/SurfaceTextureClient_test.cpp
@@ -41,7 +41,7 @@
                 testInfo->name());
 
         mST = new SurfaceTexture(123);
-        mSTC = new SurfaceTextureClient(mST);
+        mSTC = new SurfaceTextureClient(mST->getBufferQueue());
         mANW = mSTC;
 
         // We need a valid GL context so we can test updateTexImage()
@@ -686,7 +686,7 @@
 
         for (int i = 0; i < NUM_SURFACE_TEXTURES; i++) {
             sp<SurfaceTexture> st(new SurfaceTexture(i));
-            sp<SurfaceTextureClient> stc(new SurfaceTextureClient(st));
+            sp<SurfaceTextureClient> stc(new SurfaceTextureClient(st->getBufferQueue()));
             mEglSurfaces[i] = eglCreateWindowSurface(mEglDisplay, myConfig,
                     static_cast<ANativeWindow*>(stc.get()), NULL);
             ASSERT_EQ(EGL_SUCCESS, eglGetError());
diff --git a/libs/gui/tests/SurfaceTexture_test.cpp b/libs/gui/tests/SurfaceTexture_test.cpp
index d9b40cf..58976ad 100644
--- a/libs/gui/tests/SurfaceTexture_test.cpp
+++ b/libs/gui/tests/SurfaceTexture_test.cpp
@@ -385,7 +385,7 @@
     virtual void SetUp() {
         GLTest::SetUp();
         mST = new SurfaceTexture(TEX_ID);
-        mSTC = new SurfaceTextureClient(mST);
+        mSTC = new SurfaceTextureClient(mST->getBufferQueue());
         mANW = mSTC;
         mTextureRenderer = new TextureRenderer(TEX_ID, mST);
         ASSERT_NO_FATAL_FAILURE(mTextureRenderer->SetUp());
diff --git a/services/surfaceflinger/Android.mk b/services/surfaceflinger/Android.mk
index 329bbd5..b4b19b4 100644
--- a/services/surfaceflinger/Android.mk
+++ b/services/surfaceflinger/Android.mk
@@ -11,12 +11,12 @@
     LayerDim.cpp                            \
     LayerScreenshot.cpp                     \
     DisplayHardware/FramebufferSurface.cpp  \
-    DisplayHardware/GraphicBufferAlloc.cpp  \
     DisplayHardware/HWComposer.cpp          \
     DisplayHardware/PowerHAL.cpp            \
     GLExtensions.cpp                        \
     MessageQueue.cpp                        \
     SurfaceFlinger.cpp                      \
+    SurfaceFlingerConsumer.cpp              \
     SurfaceTextureLayer.cpp                 \
     Transform.cpp                           \
     
diff --git a/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp b/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp
index 6c86a53..cccb29b 100644
--- a/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp
+++ b/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp
@@ -30,10 +30,10 @@
 
 #include <hardware/hardware.h>
 #include <gui/SurfaceTextureClient.h>
+#include <gui/GraphicBufferAlloc.h>
 #include <ui/GraphicBuffer.h>
 
 #include "DisplayHardware/FramebufferSurface.h"
-#include "DisplayHardware/GraphicBufferAlloc.h"
 #include "DisplayHardware/HWComposer.h"
 
 #ifndef NUM_FRAMEBUFFER_SURFACE_BUFFERS
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index b6aa005..a1d46d9 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -73,7 +73,7 @@
         HWComposer::HWCLayerInterface* layer) {
     LayerBaseClient::onLayerDisplayed(hw, layer);
     if (layer) {
-        mSurfaceTexture->setReleaseFence(layer->getAndResetReleaseFenceFd());
+        mSurfaceFlingerConsumer->setReleaseFence(layer->getAndResetReleaseFenceFd());
     }
 }
 
@@ -81,20 +81,20 @@
 {
     LayerBaseClient::onFirstRef();
 
-    // Creates a custom BufferQueue for SurfaceTexture to use
+    // Creates a custom BufferQueue for SurfaceFlingerConsumer to use
     sp<BufferQueue> bq = new SurfaceTextureLayer();
-    mSurfaceTexture = new SurfaceTexture(mTextureName, true,
+    mSurfaceFlingerConsumer = new SurfaceFlingerConsumer(mTextureName, true,
             GL_TEXTURE_EXTERNAL_OES, false, bq);
 
-    mSurfaceTexture->setConsumerUsageBits(getEffectiveUsage(0));
-    mSurfaceTexture->setFrameAvailableListener(this);
-    mSurfaceTexture->setSynchronousMode(true);
+    mSurfaceFlingerConsumer->setConsumerUsageBits(getEffectiveUsage(0));
+    mSurfaceFlingerConsumer->setFrameAvailableListener(this);
+    mSurfaceFlingerConsumer->setSynchronousMode(true);
 
 #ifdef TARGET_DISABLE_TRIPLE_BUFFERING
 #warning "disabling triple buffering"
-    mSurfaceTexture->setDefaultMaxBufferCount(2);
+    mSurfaceFlingerConsumer->setDefaultMaxBufferCount(2);
 #else
-    mSurfaceTexture->setDefaultMaxBufferCount(3);
+    mSurfaceFlingerConsumer->setDefaultMaxBufferCount(3);
 #endif
 
     const sp<const DisplayDevice> hw(mFlinger->getDefaultDisplayDevice());
@@ -115,12 +115,12 @@
 // in the purgatory list
 void Layer::onRemoved()
 {
-    mSurfaceTexture->abandon();
+    mSurfaceFlingerConsumer->abandon();
 }
 
 void Layer::setName(const String8& name) {
     LayerBase::setName(name);
-    mSurfaceTexture->setName(name);
+    mSurfaceFlingerConsumer->setName(name);
 }
 
 sp<ISurface> Layer::createSurface()
@@ -131,7 +131,7 @@
             sp<ISurfaceTexture> res;
             sp<const Layer> that( mOwner.promote() );
             if (that != NULL) {
-                res = that->mSurfaceTexture->getBufferQueue();
+                res = that->mSurfaceFlingerConsumer->getBufferQueue();
             }
             return res;
         }
@@ -146,7 +146,7 @@
 
 wp<IBinder> Layer::getSurfaceTextureBinder() const
 {
-    return mSurfaceTexture->getBufferQueue()->asBinder();
+    return mSurfaceFlingerConsumer->getBufferQueue()->asBinder();
 }
 
 status_t Layer::setBuffers( uint32_t w, uint32_t h,
@@ -177,15 +177,15 @@
     mOpaqueLayer = (flags & ISurfaceComposerClient::eOpaque);
     mCurrentOpacity = getOpacityForFormat(format);
 
-    mSurfaceTexture->setDefaultBufferSize(w, h);
-    mSurfaceTexture->setDefaultBufferFormat(format);
-    mSurfaceTexture->setConsumerUsageBits(getEffectiveUsage(0));
+    mSurfaceFlingerConsumer->setDefaultBufferSize(w, h);
+    mSurfaceFlingerConsumer->setDefaultBufferFormat(format);
+    mSurfaceFlingerConsumer->setConsumerUsageBits(getEffectiveUsage(0));
 
     return NO_ERROR;
 }
 
 Rect Layer::computeBufferCrop() const {
-    // Start with the SurfaceTexture's buffer crop...
+    // Start with the SurfaceFlingerConsumer's buffer crop...
     Rect crop;
     if (!mCurrentCrop.isEmpty()) {
         crop = mCurrentCrop;
@@ -202,7 +202,7 @@
     if (!s.active.crop.isEmpty()) {
         // Transform the window crop to match the buffer coordinate system,
         // which means using the inverse of the current transform set on the
-        // SurfaceTexture.
+        // SurfaceFlingerConsumer.
         uint32_t invTransform = mCurrentTransform;
         int winWidth = s.active.w;
         int winHeight = s.active.h;
@@ -284,7 +284,7 @@
     // acquire fence the first time a new buffer is acquired on EACH display.
 
     if (layer.getCompositionType() == HWC_OVERLAY) {
-        sp<Fence> fence = mSurfaceTexture->getCurrentFence();
+        sp<Fence> fence = mSurfaceFlingerConsumer->getCurrentFence();
         if (fence.get()) {
             fenceFd = fence->dup();
             if (fenceFd == -1) {
@@ -327,9 +327,11 @@
         return;
     }
 
-    status_t err = mSurfaceTexture->doGLFenceWait();
-    if (err != OK) {
-        ALOGE("onDraw: failed waiting for fence: %d", err);
+    // Bind the current buffer to the GL texture, and wait for it to be
+    // ready for us to draw into.
+    status_t err = mSurfaceFlingerConsumer->bindTextureImage();
+    if (err != NO_ERROR) {
+        ALOGW("onDraw: bindTextureImage failed (err=%d)", err);
         // Go ahead and draw the buffer anyway; no matter what we do the screen
         // is probably going to have something visibly wrong.
     }
@@ -342,8 +344,8 @@
 
         // Query the texture matrix given our current filtering mode.
         float textureMatrix[16];
-        mSurfaceTexture->setFilteringEnabled(useFiltering);
-        mSurfaceTexture->getTransformMatrix(textureMatrix);
+        mSurfaceFlingerConsumer->setFilteringEnabled(useFiltering);
+        mSurfaceFlingerConsumer->getTransformMatrix(textureMatrix);
 
         // Set things up for texturing.
         glBindTexture(GL_TEXTURE_EXTERNAL_OES, mTextureName);
@@ -462,7 +464,7 @@
 
         // record the new size, form this point on, when the client request
         // a buffer, it'll get the new size.
-        mSurfaceTexture->setDefaultBufferSize(
+        mSurfaceFlingerConsumer->setDefaultBufferSize(
                 temp.requested.w, temp.requested.h);
     }
 
@@ -507,13 +509,10 @@
 
 void Layer::onPostComposition() {
     if (mFrameLatencyNeeded) {
-        nsecs_t desiredPresentTime = mSurfaceTexture->getTimestamp();
+        nsecs_t desiredPresentTime = mSurfaceFlingerConsumer->getTimestamp();
         mFrameTracker.setDesiredPresentTime(desiredPresentTime);
 
-        sp<Fence> frameReadyFence = mSurfaceTexture->getCurrentFence();
-        // XXX: Temporarily don't use the fence from the SurfaceTexture to
-        // work around a driver bug.
-        frameReadyFence.clear();
+        sp<Fence> frameReadyFence = mSurfaceFlingerConsumer->getCurrentFence();
         if (frameReadyFence != NULL) {
             mFrameTracker.setFrameReadyFence(frameReadyFence);
         } else {
@@ -570,7 +569,7 @@
             mFlinger->signalLayerUpdate();
         }
 
-        struct Reject : public SurfaceTexture::BufferRejecter {
+        struct Reject : public SurfaceFlingerConsumer::BufferRejecter {
             Layer::State& front;
             Layer::State& current;
             bool& recomputeVisibleRegions;
@@ -655,14 +654,14 @@
 
         Reject r(mDrawingState, currentState(), recomputeVisibleRegions);
 
-        if (mSurfaceTexture->updateTexImage(&r, true) < NO_ERROR) {
+        if (mSurfaceFlingerConsumer->updateTexImage(&r) != NO_ERROR) {
             // something happened!
             recomputeVisibleRegions = true;
             return outDirtyRegion;
         }
 
         // update the active buffer
-        mActiveBuffer = mSurfaceTexture->getCurrentBuffer();
+        mActiveBuffer = mSurfaceFlingerConsumer->getCurrentBuffer();
         if (mActiveBuffer == NULL) {
             // this can only happen if the very first buffer was rejected.
             return outDirtyRegion;
@@ -676,9 +675,9 @@
             recomputeVisibleRegions = true;
          }
 
-        Rect crop(mSurfaceTexture->getCurrentCrop());
-        const uint32_t transform(mSurfaceTexture->getCurrentTransform());
-        const uint32_t scalingMode(mSurfaceTexture->getCurrentScalingMode());
+        Rect crop(mSurfaceFlingerConsumer->getCurrentCrop());
+        const uint32_t transform(mSurfaceFlingerConsumer->getCurrentTransform());
+        const uint32_t scalingMode(mSurfaceFlingerConsumer->getCurrentScalingMode());
         if ((crop != mCurrentCrop) ||
             (transform != mCurrentTransform) ||
             (scalingMode != mCurrentScalingMode))
@@ -737,8 +736,8 @@
 
     result.append(buffer);
 
-    if (mSurfaceTexture != 0) {
-        mSurfaceTexture->dump(result, "            ", buffer, SIZE);
+    if (mSurfaceFlingerConsumer != 0) {
+        mSurfaceFlingerConsumer->dump(result, "            ", buffer, SIZE);
     }
 }
 
@@ -780,7 +779,7 @@
             orientation = 0;
         }
     }
-    mSurfaceTexture->setTransformHint(orientation);
+    mSurfaceFlingerConsumer->setTransformHint(orientation);
 }
 
 // ---------------------------------------------------------------------------
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index 5ea3eb4..2d4afc4 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -20,8 +20,6 @@
 #include <stdint.h>
 #include <sys/types.h>
 
-#include <gui/SurfaceTexture.h>
-
 #include <utils/Timers.h>
 
 #include <ui/GraphicBuffer.h>
@@ -34,6 +32,7 @@
 #include <GLES/gl.h>
 #include <GLES/glext.h>
 
+#include "SurfaceFlingerConsumer.h"
 #include "FrameTracker.h"
 #include "LayerBase.h"
 #include "SurfaceTextureLayer.h"
@@ -49,7 +48,7 @@
 // ---------------------------------------------------------------------------
 
 class Layer : public LayerBaseClient,
-              public SurfaceTexture::FrameAvailableListener
+              public SurfaceFlingerConsumer::FrameAvailableListener
 {
 public:
             Layer(SurfaceFlinger* flinger, const sp<Client>& client);
@@ -92,7 +91,7 @@
     // only for debugging
     inline const sp<GraphicBuffer>& getActiveBuffer() const { return mActiveBuffer; }
 
-    // Updates the transform hint in our SurfaceTexture to match
+    // Updates the transform hint in our SurfaceFlingerConsumer to match
     // the current orientation of the display device.
     virtual void updateTransformHint(const sp<const DisplayDevice>& hw) const;
 
@@ -110,13 +109,13 @@
     Rect computeBufferCrop() const;
     static bool getOpacityForFormat(uint32_t format);
 
-    // Interface implementation for SurfaceTexture::FrameAvailableListener
+    // Interface implementation for SurfaceFlingerConsumer::FrameAvailableListener
     virtual void onFrameAvailable();
 
     // -----------------------------------------------------------------------
 
     // constants
-    sp<SurfaceTexture> mSurfaceTexture;
+    sp<SurfaceFlingerConsumer> mSurfaceFlingerConsumer;
     GLuint mTextureName;
 
     // thread-safe
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 41c5cce..f65b82f 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -40,6 +40,7 @@
 #include <gui/GuiConfig.h>
 #include <gui/IDisplayEventConnection.h>
 #include <gui/SurfaceTextureClient.h>
+#include <gui/GraphicBufferAlloc.h>
 
 #include <ui/GraphicBufferAllocator.h>
 #include <ui/PixelFormat.h>
@@ -65,7 +66,6 @@
 #include "SurfaceFlinger.h"
 
 #include "DisplayHardware/FramebufferSurface.h"
-#include "DisplayHardware/GraphicBufferAlloc.h"
 #include "DisplayHardware/HWComposer.h"
 
 
diff --git a/services/surfaceflinger/SurfaceFlingerConsumer.cpp b/services/surfaceflinger/SurfaceFlingerConsumer.cpp
new file mode 100644
index 0000000..a316896
--- /dev/null
+++ b/services/surfaceflinger/SurfaceFlingerConsumer.cpp
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) 2012 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 ATRACE_TAG ATRACE_TAG_GRAPHICS
+
+#include "SurfaceFlingerConsumer.h"
+
+#include <utils/Trace.h>
+#include <utils/Errors.h>
+
+
+namespace android {
+
+// ---------------------------------------------------------------------------
+
+status_t SurfaceFlingerConsumer::updateTexImage(BufferRejecter* rejecter)
+{
+    ATRACE_CALL();
+    ALOGV("updateTexImage");
+    Mutex::Autolock lock(mMutex);
+
+    if (mAbandoned) {
+        ALOGE("updateTexImage: SurfaceTexture is abandoned!");
+        return NO_INIT;
+    }
+
+    // Make sure the EGL state is the same as in previous calls.
+    status_t err = checkAndUpdateEglStateLocked();
+    if (err != NO_ERROR) {
+        return err;
+    }
+
+    BufferQueue::BufferItem item;
+
+    // Acquire the next buffer.
+    // In asynchronous mode the list is guaranteed to be one buffer
+    // deep, while in synchronous mode we use the oldest buffer.
+    err = acquireBufferLocked(&item);
+    if (err != NO_ERROR) {
+        if (err == BufferQueue::NO_BUFFER_AVAILABLE) {
+            // This variant of updateTexImage does not guarantee that the
+            // texture is bound, so no need to call glBindTexture.
+            err = NO_ERROR;
+        } else {
+            ALOGE("updateTexImage: acquire failed: %s (%d)",
+                strerror(-err), err);
+        }
+        return err;
+    }
+
+
+    // We call the rejecter here, in case the caller has a reason to
+    // not accept this buffer.  This is used by SurfaceFlinger to
+    // reject buffers which have the wrong size
+    int buf = item.mBuf;
+    if (rejecter && rejecter->reject(mSlots[buf].mGraphicBuffer, item)) {
+        releaseBufferLocked(buf, EGL_NO_SYNC_KHR);
+        return NO_ERROR;
+    }
+
+    // Release the previous buffer.
+    err = releaseAndUpdateLocked(item);
+    if (err != NO_ERROR) {
+        return err;
+    }
+
+    if (!sUseNativeFenceSync) {
+        // Bind the new buffer to the GL texture.
+        //
+        // Older devices require the "implicit" synchronization provided
+        // by glEGLImageTargetTexture2DOES, which this method calls.  Newer
+        // devices will either call this in Layer::onDraw, or (if it's not
+        // a GL-composited layer) not at all.
+        err = bindTextureImageLocked();
+    }
+
+    return err;
+}
+
+status_t SurfaceFlingerConsumer::bindTextureImage()
+{
+    Mutex::Autolock lock(mMutex);
+
+    return bindTextureImageLocked();
+}
+
+// ---------------------------------------------------------------------------
+}; // namespace android
+
diff --git a/services/surfaceflinger/SurfaceFlingerConsumer.h b/services/surfaceflinger/SurfaceFlingerConsumer.h
new file mode 100644
index 0000000..308a288
--- /dev/null
+++ b/services/surfaceflinger/SurfaceFlingerConsumer.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2012 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_SURFACEFLINGERCONSUMER_H
+#define ANDROID_SURFACEFLINGERCONSUMER_H
+
+#include <gui/SurfaceTexture.h>
+
+namespace android {
+// ----------------------------------------------------------------------------
+
+/*
+ * This is a thin wrapper around SurfaceTexture.
+ */
+class SurfaceFlingerConsumer : public SurfaceTexture {
+public:
+    SurfaceFlingerConsumer(GLuint tex, bool allowSynchronousMode = true,
+            GLenum texTarget = GL_TEXTURE_EXTERNAL_OES, bool useFenceSync = true,
+            const sp<BufferQueue> &bufferQueue = 0)
+        : SurfaceTexture(tex, allowSynchronousMode, texTarget, useFenceSync,
+            bufferQueue)
+    {}
+
+    class BufferRejecter {
+        friend class SurfaceFlingerConsumer;
+        virtual bool reject(const sp<GraphicBuffer>& buf,
+                const BufferQueue::BufferItem& item) = 0;
+
+    protected:
+        virtual ~BufferRejecter() { }
+    };
+
+    // This version of updateTexImage() takes a functor that may be used to
+    // reject the newly acquired buffer.  Unlike the SurfaceTexture version,
+    // this does not guarantee that the buffer has been bound to the GL
+    // texture.
+    status_t updateTexImage(BufferRejecter* rejecter);
+
+    // See SurfaceTexture::bindTextureImageLocked().
+    status_t bindTextureImage();
+};
+
+// ----------------------------------------------------------------------------
+}; // namespace android
+
+#endif // ANDROID_SURFACEFLINGERCONSUMER_H