surfaceflinger: refactor FrambufferSurface

This change refactors the FramebufferSurface class to inherit from the new
ConsumerBase class.

Bug: 6620200
Change-Id: I46ec942ddb019658e3c5e79465548b171b2261f2
diff --git a/include/gui/BufferQueue.h b/include/gui/BufferQueue.h
index 0d36baa..85d8fb6 100644
--- a/include/gui/BufferQueue.h
+++ b/include/gui/BufferQueue.h
@@ -422,10 +422,6 @@
     // in requestBuffers() if a width and height of zero is specified.
     uint32_t mDefaultHeight;
 
-    // mPixelFormat holds the pixel format of allocated buffers. It is used
-    // in requestBuffers() if a format of zero is specified.
-    uint32_t mPixelFormat;
-
     // mMinUndequeuedBuffers is a constraint on the number of buffers
     // not dequeued at any time
     int mMinUndequeuedBuffers;
diff --git a/include/gui/ConsumerBase.h b/include/gui/ConsumerBase.h
new file mode 100644
index 0000000..d2bf0f6
--- /dev/null
+++ b/include/gui/ConsumerBase.h
@@ -0,0 +1,209 @@
+/*
+ * Copyright (C) 2010 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_CONSUMERBASE_H
+#define ANDROID_GUI_CONSUMERBASE_H
+
+#include <gui/BufferQueue.h>
+
+#include <ui/GraphicBuffer.h>
+
+#include <utils/String8.h>
+#include <utils/Vector.h>
+#include <utils/threads.h>
+
+namespace android {
+// ----------------------------------------------------------------------------
+
+class String8;
+
+// ConsumerBase is a base class for BufferQueue consumer end-points. It
+// handles common tasks like management of the connection to the BufferQueue
+// and the buffer pool.
+class ConsumerBase : public virtual RefBase,
+        protected BufferQueue::ConsumerListener {
+public:
+    struct FrameAvailableListener : public virtual RefBase {
+        // onFrameAvailable() is called each time an additional frame becomes
+        // available for consumption. This means that frames that are queued
+        // while in asynchronous mode only trigger the callback if no previous
+        // frames are pending. Frames queued while in synchronous mode always
+        // trigger the callback.
+        //
+        // This is called without any lock held and can be called concurrently
+        // by multiple threads.
+        virtual void onFrameAvailable() = 0;
+    };
+
+    virtual ~ConsumerBase();
+
+    // abandon frees all the buffers and puts the ConsumerBase into the
+    // 'abandoned' state.  Once put in this state the ConsumerBase can never
+    // leave it.  When in the 'abandoned' state, all methods of the
+    // ISurfaceTexture interface will fail with the NO_INIT error.
+    //
+    // Note that while calling this method causes all the buffers to be freed
+    // from the perspective of the the ConsumerBase, if there are additional
+    // references on the buffers (e.g. if a buffer is referenced by a client
+    // or by OpenGL ES as a texture) then those buffer will remain allocated.
+    void abandon();
+
+    // set the name of the ConsumerBase that will be used to identify it in
+    // log messages.
+    void setName(const String8& name);
+
+    // getBufferQueue returns the BufferQueue object to which this
+    // ConsumerBase is connected.
+    sp<BufferQueue> getBufferQueue() const;
+
+    // dump writes the current state to a string.  These methods should NOT be
+    // overridden by child classes.  Instead they should override the
+    // dumpLocked method, which is called by these methods after locking the
+    // mutex.
+    void dump(String8& result) const;
+    void dump(String8& result, const char* prefix, char* buffer, size_t SIZE) const;
+
+    // setFrameAvailableListener sets the listener object that will be notified
+    // when a new frame becomes available.
+    void setFrameAvailableListener(const sp<FrameAvailableListener>& listener);
+
+private:
+    ConsumerBase(const ConsumerBase&);
+    void operator=(const ConsumerBase&);
+
+protected:
+
+    // TODO: Fix this comment
+    // ConsumerBase constructs a new ConsumerBase object. tex indicates the
+    // name of the OpenGL ES texture to which images are to be streamed.
+    // allowSynchronousMode specifies whether or not synchronous mode can be
+    // enabled. texTarget specifies the OpenGL ES texture target to which the
+    // texture will be bound in updateTexImage. useFenceSync specifies whether
+    // fences should be used to synchronize access to buffers if that behavior
+    // is enabled at compile-time. A custom bufferQueue can be specified
+    // if behavior for queue/dequeue/connect etc needs to be customized.
+    // Otherwise a default BufferQueue will be created and used.
+    //
+    // For legacy reasons, the ConsumerBase is created in a state where it is
+    // considered attached to an OpenGL ES context for the purposes of the
+    // attachToContext and detachFromContext methods. However, despite being
+    // considered "attached" to a context, the specific OpenGL ES context
+    // doesn't get latched until the first call to updateTexImage. After that
+    // point, all calls to updateTexImage must be made with the same OpenGL ES
+    // context current.
+    //
+    // A ConsumerBase may be detached from one OpenGL ES context and then
+    // attached to a different context using the detachFromContext and
+    // attachToContext methods, respectively. The intention of these methods is
+    // purely to allow a ConsumerBase to be transferred from one consumer
+    // context to another. If such a transfer is not needed there is no
+    // requirement that either of these methods be called.
+    ConsumerBase(const sp<BufferQueue> &bufferQueue);
+
+    // Implementation of the BufferQueue::ConsumerListener interface.  These
+    // calls are used to notify the ConsumerBase of asynchronous events in the
+    // BufferQueue.
+    virtual void onFrameAvailable();
+    virtual void onBuffersReleased();
+
+    // freeBufferLocked frees up the given buffer slot.  If the slot has been
+    // initialized this will release the reference to the GraphicBuffer in that
+    // slot and destroy the EGLImage in that slot.  Otherwise it has no effect.
+    //
+    // This method must be called with mMutex locked.
+    virtual void freeBufferLocked(int slotIndex);
+
+    // abandonLocked puts the BufferQueue into the abandoned state, causing
+    // all future operations on it to fail. This method rather than the public
+    // abandon method should be overridden by child classes to add abandon-
+    // time behavior.
+    //
+    // This method must be called with mMutex locked.
+    virtual void abandonLocked();
+
+    virtual void dumpLocked(String8& result, const char* prefix, char* buffer,
+            size_t SIZE) const;
+
+    // acquireBufferLocked fetches the next buffer from the BufferQueue and
+    // updates the buffer slot for the buffer returned.
+    virtual status_t acquireBufferLocked(BufferQueue::BufferItem *item);
+
+    // releaseBufferLocked relinquishes control over a buffer, returning that
+    // control to the BufferQueue.
+    virtual status_t releaseBufferLocked(int buf, EGLDisplay display,
+           EGLSyncKHR eglFence, const sp<Fence>& fence);
+
+    // Slot contains the information and object references that
+    // ConsumerBase maintains about a BufferQueue buffer slot.
+    struct Slot {
+        // mGraphicBuffer is the Gralloc buffer store in the slot or NULL if
+        // no Gralloc buffer is in the slot.
+        sp<GraphicBuffer> mGraphicBuffer;
+
+        // mFence is a fence which will signal when the buffer associated with
+        // this buffer slot is no longer being used by the consumer and can be
+        // overwritten. The buffer can be dequeued before the fence signals;
+        // the producer is responsible for delaying writes until it signals.
+        sp<Fence> mFence;
+    };
+
+    // mSlots stores the buffers that have been allocated by the BufferQueue
+    // for each buffer slot.  It is initialized to null pointers, and gets
+    // filled in with the result of BufferQueue::acquire when the
+    // client dequeues a buffer from a
+    // slot that has not yet been used. The buffer allocated to a slot will also
+    // be replaced if the requested buffer usage or geometry differs from that
+    // of the buffer allocated to a slot.
+    Slot mSlots[BufferQueue::NUM_BUFFER_SLOTS];
+
+    // mAbandoned indicates that the BufferQueue will no longer be used to
+    // consume images buffers pushed to it using the ISurfaceTexture
+    // interface. It is initialized to false, and set to true in the abandon
+    // method.  A BufferQueue that has been abandoned will return the NO_INIT
+    // error from all IConsumerBase methods capable of returning an error.
+    bool mAbandoned;
+
+    // mName is a string used to identify the ConsumerBase in log messages.
+    // It can be set by the setName method.
+    String8 mName;
+
+    // mFrameAvailableListener is the listener object that will be called when a
+    // new frame becomes available. If it is not NULL it will be called from
+    // queueBuffer.
+    sp<FrameAvailableListener> mFrameAvailableListener;
+
+    // The ConsumerBase has-a BufferQueue and is responsible for creating this object
+    // if none is supplied
+    sp<BufferQueue> mBufferQueue;
+
+    // mAttached indicates whether the ConsumerBase is currently attached to
+    // an OpenGL ES context.  For legacy reasons, this is initialized to true,
+    // indicating that the ConsumerBase is considered to be attached to
+    // whatever context is current at the time of the first updateTexImage call.
+    // It is set to false by detachFromContext, and then set to true again by
+    // attachToContext.
+    bool mAttached;
+
+    // mMutex is the mutex used to prevent concurrent access to the member
+    // variables of ConsumerBase objects. It must be locked whenever the
+    // member variables are accessed.
+    mutable Mutex mMutex;
+};
+
+// ----------------------------------------------------------------------------
+}; // namespace android
+
+#endif // ANDROID_GUI_CONSUMERBASE_H
diff --git a/libs/gui/Android.mk b/libs/gui/Android.mk
index 7006957..3aa3a50 100644
--- a/libs/gui/Android.mk
+++ b/libs/gui/Android.mk
@@ -4,6 +4,7 @@
 LOCAL_SRC_FILES:= \
 	BitTube.cpp \
 	BufferQueue.cpp \
+	ConsumerBase.cpp \
 	DisplayEventReceiver.cpp \
 	IDisplayEventConnection.cpp \
 	ISensorEventConnection.cpp \
diff --git a/libs/gui/BufferQueue.cpp b/libs/gui/BufferQueue.cpp
index 23e3a4f..697635b 100644
--- a/libs/gui/BufferQueue.cpp
+++ b/libs/gui/BufferQueue.cpp
@@ -85,7 +85,6 @@
         const sp<IGraphicBufferAlloc>& allocator) :
     mDefaultWidth(1),
     mDefaultHeight(1),
-    mPixelFormat(PIXEL_FORMAT_RGBA_8888),
     mMinUndequeuedBuffers(bufferCount),
     mMinAsyncBufferSlots(bufferCount + 1),
     mMinSyncBufferSlots(bufferCount),
@@ -98,7 +97,7 @@
     mAbandoned(false),
     mFrameCounter(0),
     mBufferHasBeenQueued(false),
-    mDefaultBufferFormat(0),
+    mDefaultBufferFormat(PIXEL_FORMAT_RGBA_8888),
     mConsumerUsageBits(0),
     mTransformHint(0)
 {
@@ -125,7 +124,8 @@
     if (bufferCount > NUM_BUFFER_SLOTS)
         return BAD_VALUE;
 
-    // special-case, nothing to do
+    mServerBufferCount = bufferCount;
+
     if (bufferCount == mBufferCount)
         return OK;
 
@@ -133,7 +133,6 @@
         bufferCount >= mBufferCount) {
         // easy, we just have more buffers
         mBufferCount = bufferCount;
-        mServerBufferCount = bufferCount;
         mDequeueCondition.broadcast();
     } else {
         // we're here because we're either
@@ -150,7 +149,6 @@
         // own one. the actual resizing will happen during the next
         // dequeueBuffer.
 
-        mServerBufferCount = bufferCount;
         mDequeueCondition.broadcast();
     }
     return OK;
@@ -260,7 +258,7 @@
         value = mDefaultHeight;
         break;
     case NATIVE_WINDOW_FORMAT:
-        value = mPixelFormat;
+        value = mDefaultBufferFormat;
         break;
     case NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS:
         value = mSynchronousMode ?
@@ -447,12 +445,6 @@
             h = mDefaultHeight;
         }
 
-        const bool updateFormat = (format != 0);
-        if (!updateFormat) {
-            // keep the current (or default) format
-            format = mPixelFormat;
-        }
-
         // buffer is now in DEQUEUED (but can also be current at the same time,
         // if we're in synchronous mode)
         mSlots[buf].mBufferState = BufferSlot::DEQUEUED;
@@ -473,9 +465,6 @@
                         "failed");
                 return error;
             }
-            if (updateFormat) {
-                mPixelFormat = format;
-            }
 
             mSlots[buf].mAcquireCalled = false;
             mSlots[buf].mGraphicBuffer = graphicBuffer;
@@ -791,9 +780,9 @@
 
     snprintf(buffer, SIZE,
             "%s-BufferQueue mBufferCount=%d, mSynchronousMode=%d, default-size=[%dx%d], "
-            "mPixelFormat=%d, FIFO(%d)={%s}\n",
+            "default-format=%d, FIFO(%d)={%s}\n",
             prefix, mBufferCount, mSynchronousMode, mDefaultWidth,
-            mDefaultHeight, mPixelFormat, fifoSize, fifo.string());
+            mDefaultHeight, mDefaultBufferFormat, fifoSize, fifo.string());
     result.append(buffer);
 
 
@@ -835,21 +824,22 @@
     }
 }
 
-void BufferQueue::freeBufferLocked(int i) {
-    mSlots[i].mGraphicBuffer = 0;
-    if (mSlots[i].mBufferState == BufferSlot::ACQUIRED) {
-        mSlots[i].mNeedsCleanupOnRelease = true;
+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[i].mBufferState = BufferSlot::FREE;
-    mSlots[i].mFrameNumber = 0;
-    mSlots[i].mAcquireCalled = false;
+    mSlots[slot].mBufferState = BufferSlot::FREE;
+    mSlots[slot].mFrameNumber = 0;
+    mSlots[slot].mAcquireCalled = false;
 
     // destroy fence as BufferQueue now takes ownership
-    if (mSlots[i].mEglFence != EGL_NO_SYNC_KHR) {
-        eglDestroySyncKHR(mSlots[i].mEglDisplay, mSlots[i].mEglFence);
-        mSlots[i].mEglFence = EGL_NO_SYNC_KHR;
+    if (mSlots[slot].mEglFence != EGL_NO_SYNC_KHR) {
+        eglDestroySyncKHR(mSlots[slot].mEglDisplay, mSlots[slot].mEglFence);
+        mSlots[slot].mEglFence = EGL_NO_SYNC_KHR;
     }
-    mSlots[i].mFence.clear();
+    mSlots[slot].mFence.clear();
 }
 
 void BufferQueue::freeAllBuffersLocked() {
@@ -886,12 +876,14 @@
         buffer->mTimestamp = mSlots[buf].mTimestamp;
         buffer->mBuf = buf;
         buffer->mFence = mSlots[buf].mFence;
-        mSlots[buf].mAcquireCalled = true;
 
+        mSlots[buf].mAcquireCalled = true;
+        mSlots[buf].mNeedsCleanupOnRelease = false;
         mSlots[buf].mBufferState = BufferSlot::ACQUIRED;
+        mSlots[buf].mFence.clear();
+
         mQueue.erase(front);
         mDequeueCondition.broadcast();
-        mSlots[buf].mFence.clear();
 
         ATRACE_INT(mConsumerName.string(), mQueue.size());
     } else {
diff --git a/libs/gui/ConsumerBase.cpp b/libs/gui/ConsumerBase.cpp
new file mode 100644
index 0000000..af19ac0
--- /dev/null
+++ b/libs/gui/ConsumerBase.cpp
@@ -0,0 +1,205 @@
+/*
+ * Copyright (C) 2010 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 "ConsumerBase"
+#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 <hardware/hardware.h>
+
+#include <gui/IGraphicBufferAlloc.h>
+#include <gui/ISurfaceComposer.h>
+#include <gui/SurfaceComposerClient.h>
+#include <gui/ConsumerBase.h>
+
+#include <private/gui/ComposerService.h>
+
+#include <utils/Log.h>
+#include <utils/String8.h>
+#include <utils/Trace.h>
+
+// Macros for including the ConsumerBase name in log messages
+#define CB_LOGV(x, ...) ALOGV("[%s] "x, mName.string(), ##__VA_ARGS__)
+#define CB_LOGD(x, ...) ALOGD("[%s] "x, mName.string(), ##__VA_ARGS__)
+#define CB_LOGI(x, ...) ALOGI("[%s] "x, mName.string(), ##__VA_ARGS__)
+#define CB_LOGW(x, ...) ALOGW("[%s] "x, mName.string(), ##__VA_ARGS__)
+#define CB_LOGE(x, ...) ALOGE("[%s] "x, mName.string(), ##__VA_ARGS__)
+
+namespace android {
+
+// Get an ID that's unique within this process.
+static int32_t createProcessUniqueId() {
+    static volatile int32_t globalCounter = 0;
+    return android_atomic_inc(&globalCounter);
+}
+
+ConsumerBase::ConsumerBase(const sp<BufferQueue>& bufferQueue) :
+	mBufferQueue(bufferQueue) {
+    // Choose a name using the PID and a process-unique ID.
+    mName = String8::format("unnamed-%d-%d", getpid(), createProcessUniqueId());
+
+    // Note that we can't create an sp<...>(this) in a ctor that will not keep a
+    // reference once the ctor ends, as that would cause the refcount of 'this'
+    // dropping to 0 at the end of the ctor.  Since all we need is a wp<...>
+    // that's what we create.
+    wp<BufferQueue::ConsumerListener> listener;
+    sp<BufferQueue::ConsumerListener> proxy;
+    listener = static_cast<BufferQueue::ConsumerListener*>(this);
+    proxy = new BufferQueue::ProxyConsumerListener(listener);
+
+    status_t err = mBufferQueue->consumerConnect(proxy);
+    if (err != NO_ERROR) {
+        CB_LOGE("SurfaceTexture: error connecting to BufferQueue: %s (%d)",
+                strerror(-err), err);
+    } else {
+        mBufferQueue->setConsumerName(mName);
+    }
+}
+
+ConsumerBase::~ConsumerBase() {
+	CB_LOGV("~ConsumerBase");
+    abandon();
+}
+
+void ConsumerBase::freeBufferLocked(int slotIndex) {
+    CB_LOGV("freeBufferLocked: slotIndex=%d", slotIndex);
+    mSlots[slotIndex].mGraphicBuffer = 0;
+    mSlots[slotIndex].mFence = 0;
+}
+
+// Used for refactoring, should not be in final interface
+sp<BufferQueue> ConsumerBase::getBufferQueue() const {
+    Mutex::Autolock lock(mMutex);
+    return mBufferQueue;
+}
+
+void ConsumerBase::onFrameAvailable() {
+    CB_LOGV("onFrameAvailable");
+
+    sp<FrameAvailableListener> listener;
+    { // scope for the lock
+        Mutex::Autolock lock(mMutex);
+        listener = mFrameAvailableListener;
+    }
+
+    if (listener != NULL) {
+        CB_LOGV("actually calling onFrameAvailable");
+        listener->onFrameAvailable();
+    }
+}
+
+void ConsumerBase::onBuffersReleased() {
+    Mutex::Autolock lock(mMutex);
+
+    CB_LOGV("onBuffersReleased");
+
+    if (mAbandoned) {
+        // Nothing to do if we're already abandoned.
+        return;
+    }
+
+    uint32_t mask = 0;
+    mBufferQueue->getReleasedBuffers(&mask);
+    for (int i = 0; i < BufferQueue::NUM_BUFFER_SLOTS; i++) {
+        if (mask & (1 << i)) {
+            freeBufferLocked(i);
+        }
+    }
+}
+
+void ConsumerBase::abandon() {
+    CB_LOGV("abandon");
+    Mutex::Autolock lock(mMutex);
+
+    if (!mAbandoned) {
+        abandonLocked();
+        mAbandoned = true;
+    }
+}
+
+void ConsumerBase::abandonLocked() {
+	CB_LOGV("abandonLocked");
+    for (int i =0; i < BufferQueue::NUM_BUFFER_SLOTS; i++) {
+        freeBufferLocked(i);
+    }
+    // disconnect from the BufferQueue
+    mBufferQueue->consumerDisconnect();
+    mBufferQueue.clear();
+}
+
+void ConsumerBase::setFrameAvailableListener(
+        const sp<FrameAvailableListener>& listener) {
+    CB_LOGV("setFrameAvailableListener");
+    Mutex::Autolock lock(mMutex);
+    mFrameAvailableListener = listener;
+}
+
+void ConsumerBase::dump(String8& result) const {
+    char buffer[1024];
+    dump(result, "", buffer, 1024);
+}
+
+void ConsumerBase::dump(String8& result, const char* prefix,
+        char* buffer, size_t size) const {
+    Mutex::Autolock _l(mMutex);
+    dumpLocked(result, prefix, buffer, size);
+}
+
+void ConsumerBase::dumpLocked(String8& result, const char* prefix,
+        char* buffer, size_t SIZE) const {
+    snprintf(buffer, SIZE, "%smAbandoned=%d\n", prefix, int(mAbandoned));
+    result.append(buffer);
+
+    if (!mAbandoned) {
+        mBufferQueue->dump(result, prefix, buffer, SIZE);
+    }
+}
+
+status_t ConsumerBase::acquireBufferLocked(BufferQueue::BufferItem *item) {
+    status_t err = mBufferQueue->acquireBuffer(item);
+    if (err != NO_ERROR) {
+        return err;
+    }
+
+    if (item->mGraphicBuffer != NULL) {
+        mSlots[item->mBuf].mGraphicBuffer = item->mGraphicBuffer;
+    }
+
+    CB_LOGV("acquireBufferLocked: -> slot=%d", item->mBuf);
+
+    return OK;
+}
+
+status_t ConsumerBase::releaseBufferLocked(int slot, EGLDisplay display,
+       EGLSyncKHR eglFence, const sp<Fence>& fence) {
+    CB_LOGV("releaseBufferLocked: slot=%d", slot);
+    status_t err = mBufferQueue->releaseBuffer(slot, display, eglFence, fence);
+    if (err == BufferQueue::STALE_BUFFER_SLOT) {
+        freeBufferLocked(slot);
+    }
+
+    mSlots[slot].mFence.clear();
+
+    return err;
+}
+
+} // namespace android
\ No newline at end of file
diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp
index 175f808..56ac635 100644
--- a/services/surfaceflinger/DisplayDevice.cpp
+++ b/services/surfaceflinger/DisplayDevice.cpp
@@ -27,6 +27,8 @@
 #include <ui/DisplayInfo.h>
 #include <ui/PixelFormat.h>
 
+#include <gui/SurfaceTextureClient.h>
+
 #include <GLES/gl.h>
 #include <EGL/egl.h>
 #include <EGL/eglext.h>
@@ -100,11 +102,13 @@
 DisplayDevice::DisplayDevice(
         const sp<SurfaceFlinger>& flinger,
         int display,
-        const sp<ANativeWindow>& surface,
+        const sp<ANativeWindow>& nativeWindow,
+        const sp<FramebufferSurface>& framebufferSurface,
         EGLConfig config)
     : mFlinger(flinger),
       mId(display),
-      mNativeWindow(surface),
+      mNativeWindow(nativeWindow),
+      mFramebufferSurface(framebufferSurface),
       mDisplay(EGL_NO_DISPLAY),
       mSurface(EGL_NO_SURFACE),
       mContext(EGL_NO_CONTEXT),
@@ -164,12 +168,6 @@
 {
     ANativeWindow* const window = mNativeWindow.get();
 
-    int concreteType;
-    window->query(window, NATIVE_WINDOW_CONCRETE_TYPE, &concreteType);
-    if (concreteType == NATIVE_WINDOW_FRAMEBUFFER) {
-        mFramebufferSurface = static_cast<FramebufferSurface *>(mNativeWindow.get());
-    }
-
     int format;
     window->query(window, NATIVE_WINDOW_FORMAT, &format);
     mDpiX = window->xdpi;
@@ -216,16 +214,6 @@
     eglQuerySurface(display, surface, EGL_WIDTH,  &mDisplayWidth);
     eglQuerySurface(display, surface, EGL_HEIGHT, &mDisplayHeight);
 
-    if (mFramebufferSurface != NULL) {
-        if (mFramebufferSurface->isUpdateOnDemand()) {
-            mFlags |= PARTIAL_UPDATES;
-            // if we have partial updates, we definitely don't need to
-            // preserve the backbuffer, which may be costly.
-            eglSurfaceAttrib(display, surface,
-                    EGL_SWAP_BEHAVIOR, EGL_BUFFER_DESTROYED);
-        }
-    }
-
     mDisplay = display;
     mSurface = surface;
     mFormat  = format;
@@ -262,12 +250,6 @@
     } 
 #endif
     
-    if (mFlags & PARTIAL_UPDATES) {
-        if (mFramebufferSurface != NULL) {
-            mFramebufferSurface->setUpdateRectangle(dirty.getBounds());
-        }
-    }
-    
     mPageFlipCount++;
 }
 
diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h
index b34bcf1..78d44f3 100644
--- a/services/surfaceflinger/DisplayDevice.h
+++ b/services/surfaceflinger/DisplayDevice.h
@@ -62,7 +62,8 @@
     DisplayDevice(
             const sp<SurfaceFlinger>& flinger,
             int dpy,
-            const sp<ANativeWindow>& surface,
+            const sp<ANativeWindow>& nativeWindow,
+            const sp<FramebufferSurface>& framebufferSurface,
             EGLConfig config);
 
     ~DisplayDevice();
diff --git a/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp b/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp
index 7695e7f..f329136 100644
--- a/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp
+++ b/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp
@@ -1,6 +1,6 @@
 /*
  **
- ** Copyright 2007 The Android Open Source Project
+ ** Copyright 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.
@@ -48,17 +48,33 @@
 
 // ----------------------------------------------------------------------------
 
+class GraphicBufferAlloc : public BnGraphicBufferAlloc {
+public:
+    GraphicBufferAlloc() { };
+    virtual ~GraphicBufferAlloc() { };
+    virtual sp<GraphicBuffer> createGraphicBuffer(uint32_t w, uint32_t h,
+            PixelFormat format, uint32_t usage, status_t* error) {
+        sp<GraphicBuffer> graphicBuffer(new GraphicBuffer(w, h, format, usage));
+        return graphicBuffer;
+    }
+};
+
+
 /*
  * This implements the (main) framebuffer management. This class is used
  * mostly by SurfaceFlinger, but also by command line GL application.
  *
  */
 
-FramebufferSurface::FramebufferSurface()
-    : SurfaceTextureClient(),
-      fbDev(0), mCurrentBufferIndex(-1), mUpdateOnDemand(false)
+FramebufferSurface::FramebufferSurface():
+    ConsumerBase(new BufferQueue(true, NUM_FRAME_BUFFERS,
+            new GraphicBufferAlloc())),
+    fbDev(0),
+    mCurrentBufferSlot(-1),
+    mCurrentBuffer(0)
 {
     hw_module_t const* module;
+
     if (hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &module) == 0) {
         int stride;
         int err;
@@ -70,85 +86,64 @@
         if (!fbDev)
             return;
 
-        mUpdateOnDemand = (fbDev->setUpdateRect != 0);
-
-        const_cast<uint32_t&>(ANativeWindow::flags) = fbDev->flags;
-        const_cast<int&>(ANativeWindow::minSwapInterval) =  fbDev->minSwapInterval;
-        const_cast<int&>(ANativeWindow::maxSwapInterval) =  fbDev->maxSwapInterval;
-
-        if (fbDev->xdpi == 0 || fbDev->ydpi == 0) {
-            ALOGE("invalid screen resolution from fb HAL (xdpi=%f, ydpi=%f), "
-                   "defaulting to 160 dpi", fbDev->xdpi, fbDev->ydpi);
-            const_cast<float&>(ANativeWindow::xdpi) = 160;
-            const_cast<float&>(ANativeWindow::ydpi) = 160;
-        } else {
-            const_cast<float&>(ANativeWindow::xdpi) = fbDev->xdpi;
-            const_cast<float&>(ANativeWindow::ydpi) = fbDev->ydpi;
-        }
-
+        mName = "FramebufferSurface";
+        mBufferQueue->setConsumerName(mName);
+        mBufferQueue->setConsumerUsageBits(GRALLOC_USAGE_HW_FB |
+                GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_COMPOSER);
+        mBufferQueue->setDefaultBufferFormat(fbDev->format);
+        mBufferQueue->setDefaultBufferSize(fbDev->width, fbDev->height);
+        mBufferQueue->setSynchronousMode(true);
+        mBufferQueue->setBufferCountServer(NUM_FRAME_BUFFERS);
     } else {
         ALOGE("Couldn't get gralloc module");
     }
-
-    class GraphicBufferAlloc : public BnGraphicBufferAlloc {
-    public:
-        GraphicBufferAlloc() { };
-        virtual ~GraphicBufferAlloc() { };
-        virtual sp<GraphicBuffer> createGraphicBuffer(uint32_t w, uint32_t h,
-                PixelFormat format, uint32_t usage, status_t* error) {
-            sp<GraphicBuffer> graphicBuffer(new GraphicBuffer(w, h, format, usage));
-            return graphicBuffer;
-        }
-    };
-
-    mBufferQueue = new BufferQueue(true, NUM_FRAME_BUFFERS, new GraphicBufferAlloc());
-    mBufferQueue->setConsumerUsageBits(GRALLOC_USAGE_HW_FB|GRALLOC_USAGE_HW_RENDER|GRALLOC_USAGE_HW_COMPOSER);
-    mBufferQueue->setDefaultBufferFormat(fbDev->format);
-    mBufferQueue->setDefaultBufferSize(fbDev->width, fbDev->height);
-    mBufferQueue->setSynchronousMode(true);
-    mBufferQueue->setBufferCountServer(NUM_FRAME_BUFFERS);
-    setISurfaceTexture(mBufferQueue);
 }
 
-void FramebufferSurface::onFirstRef() {
-    class Listener : public BufferQueue::ConsumerListener {
-        const wp<FramebufferSurface> that;
-        virtual ~Listener() { }
-        virtual void onBuffersReleased() { }
-        void onFrameAvailable() {
-            sp<FramebufferSurface> self = that.promote();
-            if (self != NULL) {
-                BufferQueue::BufferItem item;
-                status_t err = self->mBufferQueue->acquireBuffer(&item);
-                if (err == 0) {
-                    if (item.mGraphicBuffer != 0) {
-                        self->mBuffers[item.mBuf] = item.mGraphicBuffer;
-                    }
-                    if (item.mFence.get()) {
-                        err = item.mFence->wait(Fence::TIMEOUT_NEVER);
-                        if (err) {
-                            ALOGE("failed waiting for buffer's fence: %d", err);
-                            self->mBufferQueue->releaseBuffer(item.mBuf,
-                                    EGL_NO_DISPLAY, EGL_NO_SYNC_KHR,
-                                    item.mFence);
-                            return;
-                        }
-                    }
-                    self->fbDev->post(self->fbDev, self->mBuffers[item.mBuf]->handle);
-                    if (self->mCurrentBufferIndex >= 0) {
-                        self->mBufferQueue->releaseBuffer(self->mCurrentBufferIndex,
-                                EGL_NO_DISPLAY, EGL_NO_SYNC_KHR, Fence::NO_FENCE);
-                    }
-                    self->mCurrentBufferIndex = item.mBuf;
-                }
-            }
-        }
-    public:
-        Listener(const sp<FramebufferSurface>& that) : that(that) { }
-    };
+status_t FramebufferSurface::nextBuffer(sp<GraphicBuffer>* buffer) {
+    Mutex::Autolock lock(mMutex);
 
-    mBufferQueue->setConsumerName(String8("FramebufferSurface"));
-    mBufferQueue->consumerConnect(new Listener(this));
+    BufferQueue::BufferItem item;
+    status_t err = acquireBufferLocked(&item);
+    if (err == BufferQueue::NO_BUFFER_AVAILABLE) {
+        if (buffer != NULL) {
+            *buffer = mCurrentBuffer;
+        }
+        return NO_ERROR;
+    } else if (err != NO_ERROR) {
+        ALOGE("error acquiring buffer: %s (%d)", strerror(-err), err);
+        return err;
+    }
+
+    // If the BufferQueue has freed and reallocated a buffer in mCurrentSlot
+    // then we may have acquired the slot we already own.  If we had released
+    // our current buffer before we call acquireBuffer then that release call
+    // would have returned STALE_BUFFER_SLOT, and we would have called
+    // freeBufferLocked on that slot.  Because the buffer slot has already
+    // been overwritten with the new buffer all we have to do is skip the
+    // releaseBuffer call and we should be in the same state we'd be in if we
+    // had released the old buffer first.
+    if (mCurrentBufferSlot != BufferQueue::INVALID_BUFFER_SLOT &&
+        item.mBuf != mCurrentBufferSlot) {
+        // Release the previous buffer.
+        err = releaseBufferLocked(mCurrentBufferSlot, EGL_NO_DISPLAY,
+                EGL_NO_SYNC_KHR, Fence::NO_FENCE);
+        if (err != NO_ERROR && err != BufferQueue::STALE_BUFFER_SLOT) {
+            ALOGE("error releasing buffer: %s (%d)", strerror(-err), err);
+            return err;
+        }
+    }
+
+    mCurrentBufferSlot = item.mBuf;
+    mCurrentBuffer = mSlots[mCurrentBufferSlot].mGraphicBuffer;
+    if (item.mFence != NULL) {
+        item.mFence->wait(Fence::TIMEOUT_NEVER);
+    }
+
+    if (buffer != NULL) {
+        *buffer = mCurrentBuffer;
+    }
+
+    return NO_ERROR;
 }
 
 FramebufferSurface::~FramebufferSurface() {
@@ -157,6 +152,29 @@
     }
 }
 
+void FramebufferSurface::onFrameAvailable() {
+    // XXX: The following code is here temporarily as part of the transition
+    // away from the framebuffer HAL.
+    sp<GraphicBuffer> buf;
+    status_t err = nextBuffer(&buf);
+    if (err != NO_ERROR) {
+        ALOGE("error latching next FramebufferSurface buffer: %s (%d)",
+                strerror(-err), err);
+        return;
+    }
+    err = fbDev->post(fbDev, buf->handle);
+    if (err != NO_ERROR) {
+        ALOGE("error posting framebuffer: %d", err);
+    }
+}
+
+void FramebufferSurface::freeBufferLocked(int slotIndex) {
+    ConsumerBase::freeBufferLocked(slotIndex);
+    if (slotIndex == mCurrentBufferSlot) {
+        mCurrentBufferSlot = BufferQueue::INVALID_BUFFER_SLOT;
+    }
+}
+
 float FramebufferSurface::getRefreshRate() const {
     /* FIXME: REFRESH_RATE is a temporary HACK until we are able to report the
      * refresh rate properly from the HAL. The WindowManagerService now relies
@@ -172,10 +190,7 @@
 
 status_t FramebufferSurface::setUpdateRectangle(const Rect& r)
 {
-    if (!mUpdateOnDemand) {
-        return INVALID_OPERATION;
-    }
-    return fbDev->setUpdateRect(fbDev, r.left, r.top, r.width(), r.height());
+    return INVALID_OPERATION;
 }
 
 status_t FramebufferSurface::compositionComplete()
@@ -190,38 +205,10 @@
     if (fbDev->common.version >= 1 && fbDev->dump) {
         const size_t SIZE = 4096;
         char buffer[SIZE];
-
         fbDev->dump(fbDev, buffer, SIZE);
         result.append(buffer);
     }
-}
-
-int FramebufferSurface::query(int what, int* value) const {
-    Mutex::Autolock _l(mLock);
-    framebuffer_device_t* fb = fbDev;
-    switch (what) {
-        case NATIVE_WINDOW_DEFAULT_WIDTH:
-        case NATIVE_WINDOW_WIDTH:
-            *value = fb->width;
-            return NO_ERROR;
-        case NATIVE_WINDOW_DEFAULT_HEIGHT:
-        case NATIVE_WINDOW_HEIGHT:
-            *value = fb->height;
-            return NO_ERROR;
-        case NATIVE_WINDOW_FORMAT:
-            *value = fb->format;
-            return NO_ERROR;
-        case NATIVE_WINDOW_CONCRETE_TYPE:
-            *value = NATIVE_WINDOW_FRAMEBUFFER;
-            return NO_ERROR;
-        case NATIVE_WINDOW_QUEUES_TO_WINDOW_COMPOSER:
-            *value = 0;
-            return NO_ERROR;
-        case NATIVE_WINDOW_TRANSFORM_HINT:
-            *value = 0;
-            return NO_ERROR;
-    }
-    return SurfaceTextureClient::query(what, value);
+    ConsumerBase::dump(result);
 }
 
 // ----------------------------------------------------------------------------
diff --git a/services/surfaceflinger/DisplayHardware/FramebufferSurface.h b/services/surfaceflinger/DisplayHardware/FramebufferSurface.h
index 672bfbb..95feaa0 100644
--- a/services/surfaceflinger/DisplayHardware/FramebufferSurface.h
+++ b/services/surfaceflinger/DisplayHardware/FramebufferSurface.h
@@ -20,9 +20,7 @@
 #include <stdint.h>
 #include <sys/types.h>
 
-#include <EGL/egl.h>
-
-#include <gui/SurfaceTextureClient.h>
+#include <gui/ConsumerBase.h>
 
 #define NUM_FRAME_BUFFERS  2
 
@@ -35,7 +33,7 @@
 
 // ---------------------------------------------------------------------------
 
-class FramebufferSurface : public SurfaceTextureClient {
+class FramebufferSurface : public ConsumerBase {
 public:
 
     static sp<FramebufferSurface> create();
@@ -43,28 +41,34 @@
     // TODO: this should be coming from HWC
     float getRefreshRate() const;
 
-    bool isUpdateOnDemand() const { return mUpdateOnDemand; }
+    bool isUpdateOnDemand() const { return false; }
     status_t setUpdateRectangle(const Rect& updateRect);
     status_t compositionComplete();
 
-    void dump(String8& result);
+    virtual void dump(String8& result);
 
-protected:
-    virtual void onFirstRef();
+    // nextBuffer waits for and then latches the next buffer from the
+    // BufferQueue and releases the previously latched buffer to the
+    // BufferQueue.  The new buffer is returned in the 'buffer' argument.
+    status_t nextBuffer(sp<GraphicBuffer>* buffer);
 
 private:
     FramebufferSurface();
     virtual ~FramebufferSurface(); // this class cannot be overloaded
-    virtual int query(int what, int* value) const;
+
+    virtual void onFrameAvailable();
+    virtual void freeBufferLocked(int slotIndex);
 
     framebuffer_device_t* fbDev;
 
-    sp<BufferQueue> mBufferQueue;
-    int mCurrentBufferIndex;
-    sp<GraphicBuffer> mBuffers[NUM_FRAME_BUFFERS];
+    // mCurrentBufferIndex is the slot index of the current buffer or
+    // INVALID_BUFFER_SLOT to indicate that either there is no current buffer
+    // or the buffer is not associated with a slot.
+    int mCurrentBufferSlot;
 
-    mutable Mutex mLock;
-    bool mUpdateOnDemand;
+    // mCurrentBuffer is the current buffer or NULL to indicate that there is
+    // no current buffer.
+    sp<GraphicBuffer> mCurrentBuffer;
 };
 
 // ---------------------------------------------------------------------------
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.h b/services/surfaceflinger/DisplayHardware/HWComposer.h
index b9c9337..607cbae 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.h
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.h
@@ -42,6 +42,7 @@
 
 class GraphicBuffer;
 class LayerBase;
+class Region;
 class String8;
 class SurfaceFlinger;
 
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 1269f3b..1f9d694 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -34,8 +34,9 @@
 
 #include <ui/DisplayInfo.h>
 
-#include <gui/IDisplayEventConnection.h>
 #include <gui/BitTube.h>
+#include <gui/BufferQueue.h>
+#include <gui/IDisplayEventConnection.h>
 #include <gui/SurfaceTextureClient.h>
 
 #include <ui/GraphicBufferAllocator.h>
@@ -351,22 +352,24 @@
 
     // Initialize the main display
     // create native window to main display
-    sp<FramebufferSurface> anw = FramebufferSurface::create();
-    ANativeWindow* const window = anw.get();
-    if (!window) {
+    sp<FramebufferSurface> fbs = FramebufferSurface::create();
+    if (fbs == NULL) {
         ALOGE("Display subsystem failed to initialize. check logs. exiting...");
         exit(0);
     }
 
+    sp<SurfaceTextureClient> stc(new SurfaceTextureClient(static_cast<sp<ISurfaceTexture> >(fbs->getBufferQueue())));
+
     // initialize the config and context
     int format;
-    window->query(window, NATIVE_WINDOW_FORMAT, &format);
+    ANativeWindow* const anw = stc.get();
+    anw->query(anw, NATIVE_WINDOW_FORMAT, &format);
     mEGLConfig  = selectEGLConfig(mEGLDisplay, format);
     mEGLContext = createGLContext(mEGLDisplay, mEGLConfig);
 
     // initialize our main display hardware
     mCurrentState.displays.add(DisplayDevice::DISPLAY_ID_MAIN, DisplayDeviceState());
-    sp<DisplayDevice> hw = new DisplayDevice(this, DisplayDevice::DISPLAY_ID_MAIN, anw, mEGLConfig);
+    sp<DisplayDevice> hw = new DisplayDevice(this, DisplayDevice::DISPLAY_ID_MAIN, anw, fbs, mEGLConfig);
     mDisplays.add(DisplayDevice::DISPLAY_ID_MAIN, hw);
 
     //  initialize OpenGL ES
@@ -868,7 +871,7 @@
             for (size_t i=0 ; i<cc ; i++) {
                 if (mDrawingState.displays.indexOfKey(curr[i].id) < 0) {
                     // FIXME: we need to pass the surface here
-                    sp<DisplayDevice> disp = new DisplayDevice(this, curr[i].id, 0, mEGLConfig);
+                    sp<DisplayDevice> disp = new DisplayDevice(this, curr[i].id, 0, 0, mEGLConfig);
                     mDisplays.add(curr[i].id, disp);
                 }
             }