Bug 959505 - Rename KK's file to corrensponding Gonk version. r=sotaro
authorSolomon Chiu <schiu@mozilla.com>
Thu, 20 Feb 2014 18:41:45 +0800
changeset 171120 c762455e8f3d48fe6f8c0fdda13cc565b4f46e6c
parent 171119 a9026ee9a90c614c5bf6665c423fbd2fa3f66e05
child 171121 fb68ede267b925b2e2a3d341170e14b4edbfb0c7
push id270
push userpvanderbeken@mozilla.com
push dateThu, 06 Mar 2014 09:24:21 +0000
reviewerssotaro
bugs959505
milestone30.0a1
Bug 959505 - Rename KK's file to corrensponding Gonk version. r=sotaro
widget/gonk/nativewindow/BufferItemConsumer.cpp
widget/gonk/nativewindow/BufferItemConsumer.h
widget/gonk/nativewindow/BufferQueue.cpp
widget/gonk/nativewindow/BufferQueue.h
widget/gonk/nativewindow/ConsumerBase.cpp
widget/gonk/nativewindow/ConsumerBase.h
widget/gonk/nativewindow/IGraphicBufferConsumer.cpp
widget/gonk/nativewindow/IGraphicBufferConsumer.h
widget/gonk/nativewindow/Surface.cpp
widget/gonk/nativewindow/Surface.h
new file mode 100644
--- /dev/null
+++ b/widget/gonk/nativewindow/BufferItemConsumer.cpp
@@ -0,0 +1,106 @@
+/*
+ * 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 LOG_NDEBUG 0
+#define LOG_TAG "BufferItemConsumer"
+#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+#include <utils/Log.h>
+
+#include <gui/BufferItemConsumer.h>
+
+#define BI_LOGV(x, ...) ALOGV("[%s] "x, mName.string(), ##__VA_ARGS__)
+#define BI_LOGD(x, ...) ALOGD("[%s] "x, mName.string(), ##__VA_ARGS__)
+#define BI_LOGI(x, ...) ALOGI("[%s] "x, mName.string(), ##__VA_ARGS__)
+#define BI_LOGW(x, ...) ALOGW("[%s] "x, mName.string(), ##__VA_ARGS__)
+#define BI_LOGE(x, ...) ALOGE("[%s] "x, mName.string(), ##__VA_ARGS__)
+
+namespace android {
+
+BufferItemConsumer::BufferItemConsumer(const sp<BufferQueue>& bq,
+        uint32_t consumerUsage, int bufferCount, bool controlledByApp) :
+    ConsumerBase(bq, controlledByApp)
+{
+    mConsumer->setConsumerUsageBits(consumerUsage);
+    mConsumer->setMaxAcquiredBufferCount(bufferCount);
+}
+
+BufferItemConsumer::~BufferItemConsumer() {
+}
+
+void BufferItemConsumer::setName(const String8& name) {
+    Mutex::Autolock _l(mMutex);
+    mName = name;
+    mConsumer->setConsumerName(name);
+}
+
+status_t BufferItemConsumer::acquireBuffer(BufferItem *item,
+        nsecs_t presentWhen, bool waitForFence) {
+    status_t err;
+
+    if (!item) return BAD_VALUE;
+
+    Mutex::Autolock _l(mMutex);
+
+    err = acquireBufferLocked(item, presentWhen);
+    if (err != OK) {
+        if (err != NO_BUFFER_AVAILABLE) {
+            BI_LOGE("Error acquiring buffer: %s (%d)", strerror(err), err);
+        }
+        return err;
+    }
+
+    if (waitForFence) {
+        err = item->mFence->waitForever("BufferItemConsumer::acquireBuffer");
+        if (err != OK) {
+            BI_LOGE("Failed to wait for fence of acquired buffer: %s (%d)",
+                    strerror(-err), err);
+            return err;
+        }
+    }
+
+    item->mGraphicBuffer = mSlots[item->mBuf].mGraphicBuffer;
+
+    return OK;
+}
+
+status_t BufferItemConsumer::releaseBuffer(const BufferItem &item,
+        const sp<Fence>& releaseFence) {
+    status_t err;
+
+    Mutex::Autolock _l(mMutex);
+
+    err = addReleaseFenceLocked(item.mBuf, item.mGraphicBuffer, releaseFence);
+
+    err = releaseBufferLocked(item.mBuf, item.mGraphicBuffer, EGL_NO_DISPLAY,
+            EGL_NO_SYNC_KHR);
+    if (err != OK) {
+        BI_LOGE("Failed to release buffer: %s (%d)",
+                strerror(-err), err);
+    }
+    return err;
+}
+
+status_t BufferItemConsumer::setDefaultBufferSize(uint32_t w, uint32_t h) {
+    Mutex::Autolock _l(mMutex);
+    return mConsumer->setDefaultBufferSize(w, h);
+}
+
+status_t BufferItemConsumer::setDefaultBufferFormat(uint32_t defaultFormat) {
+    Mutex::Autolock _l(mMutex);
+    return mConsumer->setDefaultBufferFormat(defaultFormat);
+}
+
+} // namespace android
new file mode 100644
--- /dev/null
+++ b/widget/gonk/nativewindow/BufferItemConsumer.h
@@ -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.
+ */
+
+#ifndef ANDROID_GUI_BUFFERITEMCONSUMER_H
+#define ANDROID_GUI_BUFFERITEMCONSUMER_H
+
+#include <gui/ConsumerBase.h>
+
+#include <ui/GraphicBuffer.h>
+
+#include <utils/String8.h>
+#include <utils/Vector.h>
+#include <utils/threads.h>
+
+#define ANDROID_GRAPHICS_BUFFERITEMCONSUMER_JNI_ID "mBufferItemConsumer"
+
+namespace android {
+
+class BufferQueue;
+
+/**
+ * BufferItemConsumer is a BufferQueue consumer endpoint that allows clients
+ * access to the whole BufferItem entry from BufferQueue. Multiple buffers may
+ * be acquired at once, to be used concurrently by the client. This consumer can
+ * operate either in synchronous or asynchronous mode.
+ */
+class BufferItemConsumer: public ConsumerBase
+{
+  public:
+    typedef ConsumerBase::FrameAvailableListener FrameAvailableListener;
+
+    typedef BufferQueue::BufferItem BufferItem;
+
+    enum { INVALID_BUFFER_SLOT = BufferQueue::INVALID_BUFFER_SLOT };
+    enum { NO_BUFFER_AVAILABLE = BufferQueue::NO_BUFFER_AVAILABLE };
+
+    // Create a new buffer item consumer. The consumerUsage parameter determines
+    // the consumer usage flags passed to the graphics allocator. The
+    // bufferCount parameter specifies how many buffers can be locked for user
+    // access at the same time.
+    // controlledByApp tells whether this consumer is controlled by the
+    // application.
+    BufferItemConsumer(const sp<BufferQueue>& bq, uint32_t consumerUsage,
+            int bufferCount = BufferQueue::MIN_UNDEQUEUED_BUFFERS,
+            bool controlledByApp = false);
+
+    virtual ~BufferItemConsumer();
+
+    // set the name of the BufferItemConsumer that will be used to identify it in
+    // log messages.
+    void setName(const String8& name);
+
+    // Gets the next graphics buffer from the producer, filling out the
+    // passed-in BufferItem structure. Returns NO_BUFFER_AVAILABLE if the queue
+    // of buffers is empty, and INVALID_OPERATION if the maximum number of
+    // buffers is already acquired.
+    //
+    // Only a fixed number of buffers can be acquired at a time, determined by
+    // the construction-time bufferCount parameter. If INVALID_OPERATION is
+    // returned by acquireBuffer, then old buffers must be returned to the
+    // queue by calling releaseBuffer before more buffers can be acquired.
+    //
+    // If waitForFence is true, and the acquired BufferItem has a valid fence object,
+    // acquireBuffer will wait on the fence with no timeout before returning.
+    status_t acquireBuffer(BufferItem *item, nsecs_t presentWhen,
+        bool waitForFence = true);
+
+    // Returns an acquired buffer to the queue, allowing it to be reused. Since
+    // only a fixed number of buffers may be acquired at a time, old buffers
+    // must be released by calling releaseBuffer to ensure new buffers can be
+    // acquired by acquireBuffer. Once a BufferItem is released, the caller must
+    // not access any members of the BufferItem, and should immediately remove
+    // all of its references to the BufferItem itself.
+    status_t releaseBuffer(const BufferItem &item,
+            const sp<Fence>& releaseFence = Fence::NO_FENCE);
+
+    // setDefaultBufferSize is used to set the size of buffers returned by
+    // requestBuffers when a with and height of zero is requested.
+    status_t setDefaultBufferSize(uint32_t w, uint32_t h);
+
+    // setDefaultBufferFormat allows the BufferQueue to create
+    // GraphicBuffers of a defaultFormat if no format is specified
+    // in dequeueBuffer
+    status_t setDefaultBufferFormat(uint32_t defaultFormat);
+};
+
+} // namespace android
+
+#endif // ANDROID_GUI_CPUCONSUMER_H
new file mode 100644
--- /dev/null
+++ b/widget/gonk/nativewindow/BufferQueue.cpp
@@ -0,0 +1,1243 @@
+/*
+ * 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 LOG_TAG "BufferQueue"
+#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+//#define LOG_NDEBUG 0
+
+#define GL_GLEXT_PROTOTYPES
+#define EGL_EGLEXT_PROTOTYPES
+
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
+
+#include <gui/BufferQueue.h>
+#include <gui/IConsumerListener.h>
+#include <gui/ISurfaceComposer.h>
+#include <private/gui/ComposerService.h>
+
+#include <utils/Log.h>
+#include <utils/Trace.h>
+#include <utils/CallStack.h>
+
+// Macros for including the BufferQueue name in log messages
+#define ST_LOGV(x, ...) ALOGV("[%s] "x, mConsumerName.string(), ##__VA_ARGS__)
+#define ST_LOGD(x, ...) ALOGD("[%s] "x, mConsumerName.string(), ##__VA_ARGS__)
+#define ST_LOGI(x, ...) ALOGI("[%s] "x, mConsumerName.string(), ##__VA_ARGS__)
+#define ST_LOGW(x, ...) ALOGW("[%s] "x, mConsumerName.string(), ##__VA_ARGS__)
+#define ST_LOGE(x, ...) ALOGE("[%s] "x, mConsumerName.string(), ##__VA_ARGS__)
+
+#define ATRACE_BUFFER_INDEX(index)                                            \
+    if (ATRACE_ENABLED()) {                                                   \
+        char ___traceBuf[1024];                                               \
+        snprintf(___traceBuf, 1024, "%s: %d", mConsumerName.string(),         \
+                (index));                                                     \
+        android::ScopedTrace ___bufTracer(ATRACE_TAG, ___traceBuf);           \
+    }
+
+namespace android {
+
+// Get an ID that's unique within this process.
+static int32_t createProcessUniqueId() {
+    static volatile int32_t globalCounter = 0;
+    return android_atomic_inc(&globalCounter);
+}
+
+static const char* scalingModeName(int scalingMode) {
+    switch (scalingMode) {
+        case NATIVE_WINDOW_SCALING_MODE_FREEZE: return "FREEZE";
+        case NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW: return "SCALE_TO_WINDOW";
+        case NATIVE_WINDOW_SCALING_MODE_SCALE_CROP: return "SCALE_CROP";
+        default: return "Unknown";
+    }
+}
+
+BufferQueue::BufferQueue(const sp<IGraphicBufferAlloc>& allocator) :
+    mDefaultWidth(1),
+    mDefaultHeight(1),
+    mMaxAcquiredBufferCount(1),
+    mDefaultMaxBufferCount(2),
+    mOverrideMaxBufferCount(0),
+    mConsumerControlledByApp(false),
+    mDequeueBufferCannotBlock(false),
+    mUseAsyncBuffer(true),
+    mConnectedApi(NO_CONNECTED_API),
+    mAbandoned(false),
+    mFrameCounter(0),
+    mBufferHasBeenQueued(false),
+    mDefaultBufferFormat(PIXEL_FORMAT_RGBA_8888),
+    mConsumerUsageBits(0),
+    mTransformHint(0)
+{
+    // Choose a name using the PID and a process-unique ID.
+    mConsumerName = String8::format("unnamed-%d-%d", getpid(), createProcessUniqueId());
+
+    ST_LOGV("BufferQueue");
+    if (allocator == NULL) {
+        sp<ISurfaceComposer> composer(ComposerService::getComposerService());
+        mGraphicBufferAlloc = composer->createGraphicBufferAlloc();
+        if (mGraphicBufferAlloc == 0) {
+            ST_LOGE("createGraphicBufferAlloc() failed in BufferQueue()");
+        }
+    } else {
+        mGraphicBufferAlloc = allocator;
+    }
+}
+
+BufferQueue::~BufferQueue() {
+    ST_LOGV("~BufferQueue");
+}
+
+status_t BufferQueue::setDefaultMaxBufferCountLocked(int count) {
+    const int minBufferCount = mUseAsyncBuffer ? 2 : 1;
+    if (count < minBufferCount || count > NUM_BUFFER_SLOTS)
+        return BAD_VALUE;
+
+    mDefaultMaxBufferCount = count;
+    mDequeueCondition.broadcast();
+
+    return NO_ERROR;
+}
+
+void BufferQueue::setConsumerName(const String8& name) {
+    Mutex::Autolock lock(mMutex);
+    mConsumerName = name;
+}
+
+status_t BufferQueue::setDefaultBufferFormat(uint32_t defaultFormat) {
+    Mutex::Autolock lock(mMutex);
+    mDefaultBufferFormat = defaultFormat;
+    return NO_ERROR;
+}
+
+status_t BufferQueue::setConsumerUsageBits(uint32_t usage) {
+    Mutex::Autolock lock(mMutex);
+    mConsumerUsageBits = usage;
+    return NO_ERROR;
+}
+
+status_t BufferQueue::setTransformHint(uint32_t hint) {
+    ST_LOGV("setTransformHint: %02x", hint);
+    Mutex::Autolock lock(mMutex);
+    mTransformHint = hint;
+    return NO_ERROR;
+}
+
+status_t BufferQueue::setBufferCount(int bufferCount) {
+    ST_LOGV("setBufferCount: count=%d", bufferCount);
+
+    sp<IConsumerListener> listener;
+    {
+        Mutex::Autolock lock(mMutex);
+
+        if (mAbandoned) {
+            ST_LOGE("setBufferCount: BufferQueue has been abandoned!");
+            return NO_INIT;
+        }
+        if (bufferCount > NUM_BUFFER_SLOTS) {
+            ST_LOGE("setBufferCount: bufferCount too large (max %d)",
+                    NUM_BUFFER_SLOTS);
+            return BAD_VALUE;
+        }
+
+        // Error out if the user has dequeued buffers
+        for (int i=0 ; i<NUM_BUFFER_SLOTS; i++) {
+            if (mSlots[i].mBufferState == BufferSlot::DEQUEUED) {
+                ST_LOGE("setBufferCount: client owns some buffers");
+                return -EINVAL;
+            }
+        }
+
+        if (bufferCount == 0) {
+            mOverrideMaxBufferCount = 0;
+            mDequeueCondition.broadcast();
+            return NO_ERROR;
+        }
+
+        // fine to assume async to false before we're setting the buffer count
+        const int minBufferSlots = getMinMaxBufferCountLocked(false);
+        if (bufferCount < minBufferSlots) {
+            ST_LOGE("setBufferCount: requested buffer count (%d) is less than "
+                    "minimum (%d)", bufferCount, minBufferSlots);
+            return BAD_VALUE;
+        }
+
+        // here we're guaranteed that the client doesn't have dequeued buffers
+        // and will release all of its buffer references.  We don't clear the
+        // queue, however, so currently queued buffers still get displayed.
+        freeAllBuffersLocked();
+        mOverrideMaxBufferCount = bufferCount;
+        mDequeueCondition.broadcast();
+        listener = mConsumerListener;
+    } // scope for lock
+
+    if (listener != NULL) {
+        listener->onBuffersReleased();
+    }
+
+    return NO_ERROR;
+}
+
+int BufferQueue::query(int what, int* outValue)
+{
+    ATRACE_CALL();
+    Mutex::Autolock lock(mMutex);
+
+    if (mAbandoned) {
+        ST_LOGE("query: BufferQueue has been abandoned!");
+        return NO_INIT;
+    }
+
+    int value;
+    switch (what) {
+    case NATIVE_WINDOW_WIDTH:
+        value = mDefaultWidth;
+        break;
+    case NATIVE_WINDOW_HEIGHT:
+        value = mDefaultHeight;
+        break;
+    case NATIVE_WINDOW_FORMAT:
+        value = mDefaultBufferFormat;
+        break;
+    case NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS:
+        value = getMinUndequeuedBufferCount(false);
+        break;
+    case NATIVE_WINDOW_CONSUMER_RUNNING_BEHIND:
+        value = (mQueue.size() >= 2);
+        break;
+    case NATIVE_WINDOW_CONSUMER_USAGE_BITS:
+        value = mConsumerUsageBits;
+        break;
+    default:
+        return BAD_VALUE;
+    }
+    outValue[0] = value;
+    return NO_ERROR;
+}
+
+status_t BufferQueue::requestBuffer(int slot, sp<GraphicBuffer>* buf) {
+    ATRACE_CALL();
+    ST_LOGV("requestBuffer: slot=%d", slot);
+    Mutex::Autolock lock(mMutex);
+    if (mAbandoned) {
+        ST_LOGE("requestBuffer: BufferQueue has been abandoned!");
+        return NO_INIT;
+    }
+    if (slot < 0 || slot >= NUM_BUFFER_SLOTS) {
+        ST_LOGE("requestBuffer: slot index out of range [0, %d]: %d",
+                NUM_BUFFER_SLOTS, slot);
+        return BAD_VALUE;
+    } else if (mSlots[slot].mBufferState != BufferSlot::DEQUEUED) {
+        ST_LOGE("requestBuffer: slot %d is not owned by the client (state=%d)",
+                slot, mSlots[slot].mBufferState);
+        return BAD_VALUE;
+    }
+    mSlots[slot].mRequestBufferCalled = true;
+    *buf = mSlots[slot].mGraphicBuffer;
+    return NO_ERROR;
+}
+
+status_t BufferQueue::dequeueBuffer(int *outBuf, sp<Fence>* outFence, bool async,
+        uint32_t w, uint32_t h, uint32_t format, uint32_t usage) {
+    ATRACE_CALL();
+    ST_LOGV("dequeueBuffer: w=%d h=%d fmt=%#x usage=%#x", w, h, format, usage);
+
+    if ((w && !h) || (!w && h)) {
+        ST_LOGE("dequeueBuffer: invalid size: w=%u, h=%u", w, h);
+        return BAD_VALUE;
+    }
+
+    status_t returnFlags(OK);
+    EGLDisplay dpy = EGL_NO_DISPLAY;
+    EGLSyncKHR eglFence = EGL_NO_SYNC_KHR;
+
+    { // Scope for the lock
+        Mutex::Autolock lock(mMutex);
+
+        if (format == 0) {
+            format = mDefaultBufferFormat;
+        }
+        // turn on usage bits the consumer requested
+        usage |= mConsumerUsageBits;
+
+        int found = -1;
+        bool tryAgain = true;
+        while (tryAgain) {
+            if (mAbandoned) {
+                ST_LOGE("dequeueBuffer: BufferQueue has been abandoned!");
+                return NO_INIT;
+            }
+
+            const int maxBufferCount = getMaxBufferCountLocked(async);
+            if (async && mOverrideMaxBufferCount) {
+                // FIXME: some drivers are manually setting the buffer-count (which they
+                // shouldn't), so we do this extra test here to handle that case.
+                // This is TEMPORARY, until we get this fixed.
+                if (mOverrideMaxBufferCount < maxBufferCount) {
+                    ST_LOGE("dequeueBuffer: async mode is invalid with buffercount override");
+                    return BAD_VALUE;
+                }
+            }
+
+            // Free up any buffers that are in slots beyond the max buffer
+            // count.
+            for (int i = maxBufferCount; i < NUM_BUFFER_SLOTS; i++) {
+                assert(mSlots[i].mBufferState == BufferSlot::FREE);
+                if (mSlots[i].mGraphicBuffer != NULL) {
+                    freeBufferLocked(i);
+                    returnFlags |= IGraphicBufferProducer::RELEASE_ALL_BUFFERS;
+                }
+            }
+
+            // look for a free buffer to give to the client
+            found = INVALID_BUFFER_SLOT;
+            int dequeuedCount = 0;
+            int acquiredCount = 0;
+            for (int i = 0; i < maxBufferCount; i++) {
+                const int state = mSlots[i].mBufferState;
+                switch (state) {
+                    case BufferSlot::DEQUEUED:
+                        dequeuedCount++;
+                        break;
+                    case BufferSlot::ACQUIRED:
+                        acquiredCount++;
+                        break;
+                    case BufferSlot::FREE:
+                        /* We return the oldest of the free buffers to avoid
+                         * stalling the producer if possible.  This is because
+                         * the consumer may still have pending reads of the
+                         * buffers in flight.
+                         */
+                        if ((found < 0) ||
+                                mSlots[i].mFrameNumber < mSlots[found].mFrameNumber) {
+                            found = i;
+                        }
+                        break;
+                }
+            }
+
+            // clients are not allowed to dequeue more than one buffer
+            // if they didn't set a buffer count.
+            if (!mOverrideMaxBufferCount && dequeuedCount) {
+                ST_LOGE("dequeueBuffer: can't dequeue multiple buffers without "
+                        "setting the buffer count");
+                return -EINVAL;
+            }
+
+            // See whether a buffer has been queued since the last
+            // setBufferCount so we know whether to perform the min undequeued
+            // buffers check below.
+            if (mBufferHasBeenQueued) {
+                // make sure the client is not trying to dequeue more buffers
+                // than allowed.
+                const int newUndequeuedCount = maxBufferCount - (dequeuedCount+1);
+                const int minUndequeuedCount = getMinUndequeuedBufferCount(async);
+                if (newUndequeuedCount < minUndequeuedCount) {
+                    ST_LOGE("dequeueBuffer: min undequeued buffer count (%d) "
+                            "exceeded (dequeued=%d undequeudCount=%d)",
+                            minUndequeuedCount, dequeuedCount,
+                            newUndequeuedCount);
+                    return -EBUSY;
+                }
+            }
+
+            // If no buffer is found, wait for a buffer to be released or for
+            // the max buffer count to change.
+            tryAgain = found == INVALID_BUFFER_SLOT;
+            if (tryAgain) {
+                // return an error if we're in "cannot block" mode (producer and consumer
+                // are controlled by the application) -- however, the consumer is allowed
+                // to acquire briefly an extra buffer (which could cause us to have to wait here)
+                // and that's okay because we know the wait will be brief (it happens
+                // if we dequeue a buffer while the consumer has acquired one but not released
+                // the old one yet -- for e.g.: see GLConsumer::updateTexImage()).
+                if (mDequeueBufferCannotBlock && (acquiredCount <= mMaxAcquiredBufferCount)) {
+                    ST_LOGE("dequeueBuffer: would block! returning an error instead.");
+                    return WOULD_BLOCK;
+                }
+                mDequeueCondition.wait(mMutex);
+            }
+        }
+
+
+        if (found == INVALID_BUFFER_SLOT) {
+            // This should not happen.
+            ST_LOGE("dequeueBuffer: no available buffer slots");
+            return -EBUSY;
+        }
+
+        const int buf = found;
+        *outBuf = found;
+
+        ATRACE_BUFFER_INDEX(buf);
+
+        const bool useDefaultSize = !w && !h;
+        if (useDefaultSize) {
+            // use the default size
+            w = mDefaultWidth;
+            h = mDefaultHeight;
+        }
+
+        mSlots[buf].mBufferState = BufferSlot::DEQUEUED;
+
+        const sp<GraphicBuffer>& buffer(mSlots[buf].mGraphicBuffer);
+        if ((buffer == NULL) ||
+            (uint32_t(buffer->width)  != w) ||
+            (uint32_t(buffer->height) != h) ||
+            (uint32_t(buffer->format) != format) ||
+            ((uint32_t(buffer->usage) & usage) != usage))
+        {
+            mSlots[buf].mAcquireCalled = false;
+            mSlots[buf].mGraphicBuffer = NULL;
+            mSlots[buf].mRequestBufferCalled = false;
+            mSlots[buf].mEglFence = EGL_NO_SYNC_KHR;
+            mSlots[buf].mFence = Fence::NO_FENCE;
+            mSlots[buf].mEglDisplay = EGL_NO_DISPLAY;
+
+            returnFlags |= IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION;
+        }
+
+
+        if (CC_UNLIKELY(mSlots[buf].mFence == NULL)) {
+            ST_LOGE("dequeueBuffer: about to return a NULL fence from mSlot. "
+                    "buf=%d, w=%d, h=%d, format=%d",
+                    buf, buffer->width, buffer->height, buffer->format);
+        }
+
+        dpy = mSlots[buf].mEglDisplay;
+        eglFence = mSlots[buf].mEglFence;
+        *outFence = mSlots[buf].mFence;
+        mSlots[buf].mEglFence = EGL_NO_SYNC_KHR;
+        mSlots[buf].mFence = Fence::NO_FENCE;
+    }  // end lock scope
+
+    if (returnFlags & IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION) {
+        status_t error;
+        sp<GraphicBuffer> graphicBuffer(
+                mGraphicBufferAlloc->createGraphicBuffer(w, h, format, usage, &error));
+        if (graphicBuffer == 0) {
+            ST_LOGE("dequeueBuffer: SurfaceComposer::createGraphicBuffer failed");
+            return error;
+        }
+
+        { // Scope for the lock
+            Mutex::Autolock lock(mMutex);
+
+            if (mAbandoned) {
+                ST_LOGE("dequeueBuffer: BufferQueue has been abandoned!");
+                return NO_INIT;
+            }
+
+            mSlots[*outBuf].mFrameNumber = ~0;
+            mSlots[*outBuf].mGraphicBuffer = graphicBuffer;
+        }
+    }
+
+    if (eglFence != EGL_NO_SYNC_KHR) {
+        EGLint result = eglClientWaitSyncKHR(dpy, eglFence, 0, 1000000000);
+        // If something goes wrong, log the error, but return the buffer without
+        // synchronizing access to it.  It's too late at this point to abort the
+        // dequeue operation.
+        if (result == EGL_FALSE) {
+            ST_LOGE("dequeueBuffer: error waiting for fence: %#x", eglGetError());
+        } else if (result == EGL_TIMEOUT_EXPIRED_KHR) {
+            ST_LOGE("dequeueBuffer: timeout waiting for fence");
+        }
+        eglDestroySyncKHR(dpy, eglFence);
+    }
+
+    ST_LOGV("dequeueBuffer: returning slot=%d/%llu buf=%p flags=%#x", *outBuf,
+            mSlots[*outBuf].mFrameNumber,
+            mSlots[*outBuf].mGraphicBuffer->handle, returnFlags);
+
+    return returnFlags;
+}
+
+status_t BufferQueue::queueBuffer(int buf,
+        const QueueBufferInput& input, QueueBufferOutput* output) {
+    ATRACE_CALL();
+    ATRACE_BUFFER_INDEX(buf);
+
+    Rect crop;
+    uint32_t transform;
+    int scalingMode;
+    int64_t timestamp;
+    bool isAutoTimestamp;
+    bool async;
+    sp<Fence> fence;
+
+    input.deflate(&timestamp, &isAutoTimestamp, &crop, &scalingMode, &transform,
+            &async, &fence);
+
+    if (fence == NULL) {
+        ST_LOGE("queueBuffer: fence is NULL");
+        return BAD_VALUE;
+    }
+
+    switch (scalingMode) {
+        case NATIVE_WINDOW_SCALING_MODE_FREEZE:
+        case NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW:
+        case NATIVE_WINDOW_SCALING_MODE_SCALE_CROP:
+        case NATIVE_WINDOW_SCALING_MODE_NO_SCALE_CROP:
+            break;
+        default:
+            ST_LOGE("unknown scaling mode: %d", scalingMode);
+            return -EINVAL;
+    }
+
+    sp<IConsumerListener> listener;
+
+    { // scope for the lock
+        Mutex::Autolock lock(mMutex);
+
+        if (mAbandoned) {
+            ST_LOGE("queueBuffer: BufferQueue has been abandoned!");
+            return NO_INIT;
+        }
+
+        const int maxBufferCount = getMaxBufferCountLocked(async);
+        if (async && mOverrideMaxBufferCount) {
+            // FIXME: some drivers are manually setting the buffer-count (which they
+            // shouldn't), so we do this extra test here to handle that case.
+            // This is TEMPORARY, until we get this fixed.
+            if (mOverrideMaxBufferCount < maxBufferCount) {
+                ST_LOGE("queueBuffer: async mode is invalid with buffercount override");
+                return BAD_VALUE;
+            }
+        }
+        if (buf < 0 || buf >= maxBufferCount) {
+            ST_LOGE("queueBuffer: slot index out of range [0, %d]: %d",
+                    maxBufferCount, buf);
+            return -EINVAL;
+        } else if (mSlots[buf].mBufferState != BufferSlot::DEQUEUED) {
+            ST_LOGE("queueBuffer: slot %d is not owned by the client "
+                    "(state=%d)", buf, mSlots[buf].mBufferState);
+            return -EINVAL;
+        } else if (!mSlots[buf].mRequestBufferCalled) {
+            ST_LOGE("queueBuffer: slot %d was enqueued without requesting a "
+                    "buffer", buf);
+            return -EINVAL;
+        }
+
+        ST_LOGV("queueBuffer: slot=%d/%llu time=%#llx crop=[%d,%d,%d,%d] "
+                "tr=%#x scale=%s",
+                buf, mFrameCounter + 1, timestamp,
+                crop.left, crop.top, crop.right, crop.bottom,
+                transform, scalingModeName(scalingMode));
+
+        const sp<GraphicBuffer>& graphicBuffer(mSlots[buf].mGraphicBuffer);
+        Rect bufferRect(graphicBuffer->getWidth(), graphicBuffer->getHeight());
+        Rect croppedCrop;
+        crop.intersect(bufferRect, &croppedCrop);
+        if (croppedCrop != crop) {
+            ST_LOGE("queueBuffer: crop rect is not contained within the "
+                    "buffer in slot %d", buf);
+            return -EINVAL;
+        }
+
+        mSlots[buf].mFence = fence;
+        mSlots[buf].mBufferState = BufferSlot::QUEUED;
+        mFrameCounter++;
+        mSlots[buf].mFrameNumber = mFrameCounter;
+
+        BufferItem item;
+        item.mAcquireCalled = mSlots[buf].mAcquireCalled;
+        item.mGraphicBuffer = mSlots[buf].mGraphicBuffer;
+        item.mCrop = crop;
+        item.mTransform = transform & ~NATIVE_WINDOW_TRANSFORM_INVERSE_DISPLAY;
+        item.mTransformToDisplayInverse = bool(transform & NATIVE_WINDOW_TRANSFORM_INVERSE_DISPLAY);
+        item.mScalingMode = scalingMode;
+        item.mTimestamp = timestamp;
+        item.mIsAutoTimestamp = isAutoTimestamp;
+        item.mFrameNumber = mFrameCounter;
+        item.mBuf = buf;
+        item.mFence = fence;
+        item.mIsDroppable = mDequeueBufferCannotBlock || async;
+
+        if (mQueue.empty()) {
+            // when the queue is empty, we can ignore "mDequeueBufferCannotBlock", and
+            // simply queue this buffer.
+            mQueue.push_back(item);
+            listener = mConsumerListener;
+        } else {
+            // when the queue is not empty, we need to look at the front buffer
+            // state and see if we need to replace it.
+            Fifo::iterator front(mQueue.begin());
+            if (front->mIsDroppable) {
+                // buffer slot currently queued is marked free if still tracked
+                if (stillTracking(front)) {
+                    mSlots[front->mBuf].mBufferState = BufferSlot::FREE;
+                    // reset the frame number of the freed buffer so that it is the first in
+                    // line to be dequeued again.
+                    mSlots[front->mBuf].mFrameNumber = 0;
+                }
+                // and we record the new buffer in the queued list
+                *front = item;
+            } else {
+                mQueue.push_back(item);
+                listener = mConsumerListener;
+            }
+        }
+
+        mBufferHasBeenQueued = true;
+        mDequeueCondition.broadcast();
+
+        output->inflate(mDefaultWidth, mDefaultHeight, mTransformHint,
+                mQueue.size());
+
+        ATRACE_INT(mConsumerName.string(), mQueue.size());
+    } // scope for the lock
+
+    // call back without lock held
+    if (listener != 0) {
+        listener->onFrameAvailable();
+    }
+    return NO_ERROR;
+}
+
+void BufferQueue::cancelBuffer(int buf, const sp<Fence>& fence) {
+    ATRACE_CALL();
+    ST_LOGV("cancelBuffer: slot=%d", buf);
+    Mutex::Autolock lock(mMutex);
+
+    if (mAbandoned) {
+        ST_LOGW("cancelBuffer: BufferQueue has been abandoned!");
+        return;
+    }
+
+    if (buf < 0 || buf >= NUM_BUFFER_SLOTS) {
+        ST_LOGE("cancelBuffer: slot index out of range [0, %d]: %d",
+                NUM_BUFFER_SLOTS, buf);
+        return;
+    } else if (mSlots[buf].mBufferState != BufferSlot::DEQUEUED) {
+        ST_LOGE("cancelBuffer: slot %d is not owned by the client (state=%d)",
+                buf, mSlots[buf].mBufferState);
+        return;
+    } else if (fence == NULL) {
+        ST_LOGE("cancelBuffer: fence is NULL");
+        return;
+    }
+    mSlots[buf].mBufferState = BufferSlot::FREE;
+    mSlots[buf].mFrameNumber = 0;
+    mSlots[buf].mFence = fence;
+    mDequeueCondition.broadcast();
+}
+
+
+status_t BufferQueue::connect(const sp<IBinder>& token,
+        int api, bool producerControlledByApp, QueueBufferOutput* output) {
+    ATRACE_CALL();
+    ST_LOGV("connect: api=%d producerControlledByApp=%s", api,
+            producerControlledByApp ? "true" : "false");
+    Mutex::Autolock lock(mMutex);
+
+retry:
+    if (mAbandoned) {
+        ST_LOGE("connect: BufferQueue has been abandoned!");
+        return NO_INIT;
+    }
+
+    if (mConsumerListener == NULL) {
+        ST_LOGE("connect: BufferQueue has no consumer!");
+        return NO_INIT;
+    }
+
+    if (mConnectedApi != NO_CONNECTED_API) {
+        ST_LOGE("connect: already connected (cur=%d, req=%d)",
+                mConnectedApi, api);
+        return -EINVAL;
+    }
+
+    // If we disconnect and reconnect quickly, we can be in a state where our slots are
+    // empty but we have many buffers in the queue.  This can cause us to run out of
+    // memory if we outrun the consumer.  Wait here if it looks like we have too many
+    // buffers queued up.
+    int maxBufferCount = getMaxBufferCountLocked(false);    // worst-case, i.e. largest value
+    if (mQueue.size() > (size_t) maxBufferCount) {
+        // TODO: make this bound tighter?
+        ST_LOGV("queue size is %d, waiting", mQueue.size());
+        mDequeueCondition.wait(mMutex);
+        goto retry;
+    }
+
+    int err = NO_ERROR;
+    switch (api) {
+        case NATIVE_WINDOW_API_EGL:
+        case NATIVE_WINDOW_API_CPU:
+        case NATIVE_WINDOW_API_MEDIA:
+        case NATIVE_WINDOW_API_CAMERA:
+            mConnectedApi = api;
+            output->inflate(mDefaultWidth, mDefaultHeight, mTransformHint, mQueue.size());
+
+            // set-up a death notification so that we can disconnect
+            // automatically when/if the remote producer dies.
+            if (token != NULL && token->remoteBinder() != NULL) {
+                status_t err = token->linkToDeath(static_cast<IBinder::DeathRecipient*>(this));
+                if (err == NO_ERROR) {
+                    mConnectedProducerToken = token;
+                } else {
+                    ALOGE("linkToDeath failed: %s (%d)", strerror(-err), err);
+                }
+            }
+            break;
+        default:
+            err = -EINVAL;
+            break;
+    }
+
+    mBufferHasBeenQueued = false;
+    mDequeueBufferCannotBlock = mConsumerControlledByApp && producerControlledByApp;
+
+    return err;
+}
+
+void BufferQueue::binderDied(const wp<IBinder>& who) {
+    // If we're here, it means that a producer we were connected to died.
+    // We're GUARANTEED that we still are connected to it because it has no other way
+    // to get disconnected -- or -- we wouldn't be here because we're removing this
+    // callback upon disconnect. Therefore, it's okay to read mConnectedApi without
+    // synchronization here.
+    int api = mConnectedApi;
+    this->disconnect(api);
+}
+
+status_t BufferQueue::disconnect(int api) {
+    ATRACE_CALL();
+    ST_LOGV("disconnect: api=%d", api);
+
+    int err = NO_ERROR;
+    sp<IConsumerListener> listener;
+
+    { // Scope for the lock
+        Mutex::Autolock lock(mMutex);
+
+        if (mAbandoned) {
+            // it is not really an error to disconnect after the surface
+            // has been abandoned, it should just be a no-op.
+            return NO_ERROR;
+        }
+
+        switch (api) {
+            case NATIVE_WINDOW_API_EGL:
+            case NATIVE_WINDOW_API_CPU:
+            case NATIVE_WINDOW_API_MEDIA:
+            case NATIVE_WINDOW_API_CAMERA:
+                if (mConnectedApi == api) {
+                    freeAllBuffersLocked();
+                    // remove our death notification callback if we have one
+                    sp<IBinder> token = mConnectedProducerToken;
+                    if (token != NULL) {
+                        // this can fail if we're here because of the death notification
+                        // either way, we just ignore.
+                        token->unlinkToDeath(static_cast<IBinder::DeathRecipient*>(this));
+                    }
+                    mConnectedProducerToken = NULL;
+                    mConnectedApi = NO_CONNECTED_API;
+                    mDequeueCondition.broadcast();
+                    listener = mConsumerListener;
+                } else {
+                    ST_LOGE("disconnect: connected to another api (cur=%d, req=%d)",
+                            mConnectedApi, api);
+                    err = -EINVAL;
+                }
+                break;
+            default:
+                ST_LOGE("disconnect: unknown API %d", api);
+                err = -EINVAL;
+                break;
+        }
+    }
+
+    if (listener != NULL) {
+        listener->onBuffersReleased();
+    }
+
+    return err;
+}
+
+void BufferQueue::dump(String8& result, const char* prefix) const {
+    Mutex::Autolock _l(mMutex);
+
+    String8 fifo;
+    int fifoSize = 0;
+    Fifo::const_iterator i(mQueue.begin());
+    while (i != mQueue.end()) {
+        fifo.appendFormat("%02d:%p crop=[%d,%d,%d,%d], "
+                "xform=0x%02x, time=%#llx, scale=%s\n",
+                i->mBuf, i->mGraphicBuffer.get(),
+                i->mCrop.left, i->mCrop.top, i->mCrop.right,
+                i->mCrop.bottom, i->mTransform, i->mTimestamp,
+                scalingModeName(i->mScalingMode)
+                );
+        i++;
+        fifoSize++;
+    }
+
+
+    result.appendFormat(
+            "%s-BufferQueue mMaxAcquiredBufferCount=%d, mDequeueBufferCannotBlock=%d, default-size=[%dx%d], "
+            "default-format=%d, transform-hint=%02x, FIFO(%d)={%s}\n",
+            prefix, mMaxAcquiredBufferCount, mDequeueBufferCannotBlock, mDefaultWidth,
+            mDefaultHeight, mDefaultBufferFormat, mTransformHint,
+            fifoSize, fifo.string());
+
+    struct {
+        const char * operator()(int state) const {
+            switch (state) {
+                case BufferSlot::DEQUEUED: return "DEQUEUED";
+                case BufferSlot::QUEUED: return "QUEUED";
+                case BufferSlot::FREE: return "FREE";
+                case BufferSlot::ACQUIRED: return "ACQUIRED";
+                default: return "Unknown";
+            }
+        }
+    } stateName;
+
+    // just trim the free buffers to not spam the dump
+    int maxBufferCount = 0;
+    for (int i=NUM_BUFFER_SLOTS-1 ; i>=0 ; i--) {
+        const BufferSlot& slot(mSlots[i]);
+        if ((slot.mBufferState != BufferSlot::FREE) || (slot.mGraphicBuffer != NULL)) {
+            maxBufferCount = i+1;
+            break;
+        }
+    }
+
+    for (int i=0 ; i<maxBufferCount ; i++) {
+        const BufferSlot& slot(mSlots[i]);
+        const sp<GraphicBuffer>& buf(slot.mGraphicBuffer);
+        result.appendFormat(
+            "%s%s[%02d:%p] state=%-8s",
+                prefix, (slot.mBufferState == BufferSlot::ACQUIRED)?">":" ", i, buf.get(),
+                stateName(slot.mBufferState)
+        );
+
+        if (buf != NULL) {
+            result.appendFormat(
+                    ", %p [%4ux%4u:%4u,%3X]",
+                    buf->handle, buf->width, buf->height, buf->stride,
+                    buf->format);
+        }
+        result.append("\n");
+    }
+}
+
+void BufferQueue::freeBufferLocked(int slot) {
+    ST_LOGV("freeBufferLocked: slot=%d", slot);
+    mSlots[slot].mGraphicBuffer = 0;
+    if (mSlots[slot].mBufferState == BufferSlot::ACQUIRED) {
+        mSlots[slot].mNeedsCleanupOnRelease = true;
+    }
+    mSlots[slot].mBufferState = BufferSlot::FREE;
+    mSlots[slot].mFrameNumber = 0;
+    mSlots[slot].mAcquireCalled = false;
+
+    // destroy fence as BufferQueue now takes ownership
+    if (mSlots[slot].mEglFence != EGL_NO_SYNC_KHR) {
+        eglDestroySyncKHR(mSlots[slot].mEglDisplay, mSlots[slot].mEglFence);
+        mSlots[slot].mEglFence = EGL_NO_SYNC_KHR;
+    }
+    mSlots[slot].mFence = Fence::NO_FENCE;
+}
+
+void BufferQueue::freeAllBuffersLocked() {
+    mBufferHasBeenQueued = false;
+    for (int i = 0; i < NUM_BUFFER_SLOTS; i++) {
+        freeBufferLocked(i);
+    }
+}
+
+status_t BufferQueue::acquireBuffer(BufferItem *buffer, nsecs_t expectedPresent) {
+    ATRACE_CALL();
+    Mutex::Autolock _l(mMutex);
+
+    // Check that the consumer doesn't currently have the maximum number of
+    // buffers acquired.  We allow the max buffer count to be exceeded by one
+    // buffer, so that the consumer can successfully set up the newly acquired
+    // buffer before releasing the old one.
+    int numAcquiredBuffers = 0;
+    for (int i = 0; i < NUM_BUFFER_SLOTS; i++) {
+        if (mSlots[i].mBufferState == BufferSlot::ACQUIRED) {
+            numAcquiredBuffers++;
+        }
+    }
+    if (numAcquiredBuffers >= mMaxAcquiredBufferCount+1) {
+        ST_LOGE("acquireBuffer: max acquired buffer count reached: %d (max=%d)",
+                numAcquiredBuffers, mMaxAcquiredBufferCount);
+        return INVALID_OPERATION;
+    }
+
+    // check if queue is empty
+    // In asynchronous mode the list is guaranteed to be one buffer
+    // deep, while in synchronous mode we use the oldest buffer.
+    if (mQueue.empty()) {
+        return NO_BUFFER_AVAILABLE;
+    }
+
+    Fifo::iterator front(mQueue.begin());
+
+    // If expectedPresent is specified, we may not want to return a buffer yet.
+    // If it's specified and there's more than one buffer queued, we may
+    // want to drop a buffer.
+    if (expectedPresent != 0) {
+        const int MAX_REASONABLE_NSEC = 1000000000ULL;  // 1 second
+
+        // The "expectedPresent" argument indicates when the buffer is expected
+        // to be presented on-screen.  If the buffer's desired-present time
+        // is earlier (less) than expectedPresent, meaning it'll be displayed
+        // on time or possibly late if we show it ASAP, we acquire and return
+        // it.  If we don't want to display it until after the expectedPresent
+        // time, we return PRESENT_LATER without acquiring it.
+        //
+        // To be safe, we don't defer acquisition if expectedPresent is
+        // more than one second in the future beyond the desired present time
+        // (i.e. we'd be holding the buffer for a long time).
+        //
+        // NOTE: code assumes monotonic time values from the system clock are
+        // positive.
+
+        // Start by checking to see if we can drop frames.  We skip this check
+        // if the timestamps are being auto-generated by Surface -- if the
+        // app isn't generating timestamps explicitly, they probably don't
+        // want frames to be discarded based on them.
+        while (mQueue.size() > 1 && !mQueue[0].mIsAutoTimestamp) {
+            // If entry[1] is timely, drop entry[0] (and repeat).  We apply
+            // an additional criteria here: we only drop the earlier buffer if
+            // our desiredPresent falls within +/- 1 second of the expected
+            // present.  Otherwise, bogus desiredPresent times (e.g. 0 or
+            // a small relative timestamp), which normally mean "ignore the
+            // timestamp and acquire immediately", would cause us to drop
+            // frames.
+            //
+            // We may want to add an additional criteria: don't drop the
+            // earlier buffer if entry[1]'s fence hasn't signaled yet.
+            //
+            // (Vector front is [0], back is [size()-1])
+            const BufferItem& bi(mQueue[1]);
+            nsecs_t desiredPresent = bi.mTimestamp;
+            if (desiredPresent < expectedPresent - MAX_REASONABLE_NSEC ||
+                    desiredPresent > expectedPresent) {
+                // This buffer is set to display in the near future, or
+                // desiredPresent is garbage.  Either way we don't want to
+                // drop the previous buffer just to get this on screen sooner.
+                ST_LOGV("pts nodrop: des=%lld expect=%lld (%lld) now=%lld",
+                        desiredPresent, expectedPresent, desiredPresent - expectedPresent,
+                        systemTime(CLOCK_MONOTONIC));
+                break;
+            }
+            ST_LOGV("pts drop: queue1des=%lld expect=%lld size=%d",
+                    desiredPresent, expectedPresent, mQueue.size());
+            if (stillTracking(front)) {
+                // front buffer is still in mSlots, so mark the slot as free
+                mSlots[front->mBuf].mBufferState = BufferSlot::FREE;
+            }
+            mQueue.erase(front);
+            front = mQueue.begin();
+        }
+
+        // See if the front buffer is due.
+        nsecs_t desiredPresent = front->mTimestamp;
+        if (desiredPresent > expectedPresent &&
+                desiredPresent < expectedPresent + MAX_REASONABLE_NSEC) {
+            ST_LOGV("pts defer: des=%lld expect=%lld (%lld) now=%lld",
+                    desiredPresent, expectedPresent, desiredPresent - expectedPresent,
+                    systemTime(CLOCK_MONOTONIC));
+            return PRESENT_LATER;
+        }
+
+        ST_LOGV("pts accept: des=%lld expect=%lld (%lld) now=%lld",
+                desiredPresent, expectedPresent, desiredPresent - expectedPresent,
+                systemTime(CLOCK_MONOTONIC));
+    }
+
+    int buf = front->mBuf;
+    *buffer = *front;
+    ATRACE_BUFFER_INDEX(buf);
+
+    ST_LOGV("acquireBuffer: acquiring { slot=%d/%llu, buffer=%p }",
+            front->mBuf, front->mFrameNumber,
+            front->mGraphicBuffer->handle);
+    // if front buffer still being tracked update slot state
+    if (stillTracking(front)) {
+        mSlots[buf].mAcquireCalled = true;
+        mSlots[buf].mNeedsCleanupOnRelease = false;
+        mSlots[buf].mBufferState = BufferSlot::ACQUIRED;
+        mSlots[buf].mFence = Fence::NO_FENCE;
+    }
+
+    // If the buffer has previously been acquired by the consumer, set
+    // mGraphicBuffer to NULL to avoid unnecessarily remapping this
+    // buffer on the consumer side.
+    if (buffer->mAcquireCalled) {
+        buffer->mGraphicBuffer = NULL;
+    }
+
+    mQueue.erase(front);
+    mDequeueCondition.broadcast();
+
+    ATRACE_INT(mConsumerName.string(), mQueue.size());
+
+    return NO_ERROR;
+}
+
+status_t BufferQueue::releaseBuffer(
+        int buf, uint64_t frameNumber, EGLDisplay display,
+        EGLSyncKHR eglFence, const sp<Fence>& fence) {
+    ATRACE_CALL();
+    ATRACE_BUFFER_INDEX(buf);
+
+    if (buf == INVALID_BUFFER_SLOT || fence == NULL) {
+        return BAD_VALUE;
+    }
+
+    Mutex::Autolock _l(mMutex);
+
+    // If the frame number has changed because buffer has been reallocated,
+    // we can ignore this releaseBuffer for the old buffer.
+    if (frameNumber != mSlots[buf].mFrameNumber) {
+        return STALE_BUFFER_SLOT;
+    }
+
+
+    // Internal state consistency checks:
+    // Make sure this buffers hasn't been queued while we were owning it (acquired)
+    Fifo::iterator front(mQueue.begin());
+    Fifo::const_iterator const end(mQueue.end());
+    while (front != end) {
+        if (front->mBuf == buf) {
+            LOG_ALWAYS_FATAL("[%s] received new buffer(#%lld) on slot #%d that has not yet been "
+                    "acquired", mConsumerName.string(), frameNumber, buf);
+            break; // never reached
+        }
+        front++;
+    }
+
+    // The buffer can now only be released if its in the acquired state
+    if (mSlots[buf].mBufferState == BufferSlot::ACQUIRED) {
+        mSlots[buf].mEglDisplay = display;
+        mSlots[buf].mEglFence = eglFence;
+        mSlots[buf].mFence = fence;
+        mSlots[buf].mBufferState = BufferSlot::FREE;
+    } else if (mSlots[buf].mNeedsCleanupOnRelease) {
+        ST_LOGV("releasing a stale buf %d its state was %d", buf, mSlots[buf].mBufferState);
+        mSlots[buf].mNeedsCleanupOnRelease = false;
+        return STALE_BUFFER_SLOT;
+    } else {
+        ST_LOGE("attempted to release buf %d but its state was %d", buf, mSlots[buf].mBufferState);
+        return -EINVAL;
+    }
+
+    mDequeueCondition.broadcast();
+    return NO_ERROR;
+}
+
+status_t BufferQueue::consumerConnect(const sp<IConsumerListener>& consumerListener,
+        bool controlledByApp) {
+    ST_LOGV("consumerConnect controlledByApp=%s",
+            controlledByApp ? "true" : "false");
+    Mutex::Autolock lock(mMutex);
+
+    if (mAbandoned) {
+        ST_LOGE("consumerConnect: BufferQueue has been abandoned!");
+        return NO_INIT;
+    }
+    if (consumerListener == NULL) {
+        ST_LOGE("consumerConnect: consumerListener may not be NULL");
+        return BAD_VALUE;
+    }
+
+    mConsumerListener = consumerListener;
+    mConsumerControlledByApp = controlledByApp;
+
+    return NO_ERROR;
+}
+
+status_t BufferQueue::consumerDisconnect() {
+    ST_LOGV("consumerDisconnect");
+    Mutex::Autolock lock(mMutex);
+
+    if (mConsumerListener == NULL) {
+        ST_LOGE("consumerDisconnect: No consumer is connected!");
+        return -EINVAL;
+    }
+
+    mAbandoned = true;
+    mConsumerListener = NULL;
+    mQueue.clear();
+    freeAllBuffersLocked();
+    mDequeueCondition.broadcast();
+    return NO_ERROR;
+}
+
+status_t BufferQueue::getReleasedBuffers(uint32_t* slotMask) {
+    ST_LOGV("getReleasedBuffers");
+    Mutex::Autolock lock(mMutex);
+
+    if (mAbandoned) {
+        ST_LOGE("getReleasedBuffers: BufferQueue has been abandoned!");
+        return NO_INIT;
+    }
+
+    uint32_t mask = 0;
+    for (int i = 0; i < NUM_BUFFER_SLOTS; i++) {
+        if (!mSlots[i].mAcquireCalled) {
+            mask |= 1 << i;
+        }
+    }
+
+    // Remove buffers in flight (on the queue) from the mask where acquire has
+    // been called, as the consumer will not receive the buffer address, so
+    // it should not free these slots.
+    Fifo::iterator front(mQueue.begin());
+    while (front != mQueue.end()) {
+        if (front->mAcquireCalled)
+            mask &= ~(1 << front->mBuf);
+        front++;
+    }
+
+    *slotMask = mask;
+
+    ST_LOGV("getReleasedBuffers: returning mask %#x", mask);
+    return NO_ERROR;
+}
+
+status_t BufferQueue::setDefaultBufferSize(uint32_t w, uint32_t h) {
+    ST_LOGV("setDefaultBufferSize: w=%d, h=%d", w, h);
+    if (!w || !h) {
+        ST_LOGE("setDefaultBufferSize: dimensions cannot be 0 (w=%d, h=%d)",
+                w, h);
+        return BAD_VALUE;
+    }
+
+    Mutex::Autolock lock(mMutex);
+    mDefaultWidth = w;
+    mDefaultHeight = h;
+    return NO_ERROR;
+}
+
+status_t BufferQueue::setDefaultMaxBufferCount(int bufferCount) {
+    ATRACE_CALL();
+    Mutex::Autolock lock(mMutex);
+    return setDefaultMaxBufferCountLocked(bufferCount);
+}
+
+status_t BufferQueue::disableAsyncBuffer() {
+    ATRACE_CALL();
+    Mutex::Autolock lock(mMutex);
+    if (mConsumerListener != NULL) {
+        ST_LOGE("disableAsyncBuffer: consumer already connected!");
+        return INVALID_OPERATION;
+    }
+    mUseAsyncBuffer = false;
+    return NO_ERROR;
+}
+
+status_t BufferQueue::setMaxAcquiredBufferCount(int maxAcquiredBuffers) {
+    ATRACE_CALL();
+    Mutex::Autolock lock(mMutex);
+    if (maxAcquiredBuffers < 1 || maxAcquiredBuffers > MAX_MAX_ACQUIRED_BUFFERS) {
+        ST_LOGE("setMaxAcquiredBufferCount: invalid count specified: %d",
+                maxAcquiredBuffers);
+        return BAD_VALUE;
+    }
+    if (mConnectedApi != NO_CONNECTED_API) {
+        return INVALID_OPERATION;
+    }
+    mMaxAcquiredBufferCount = maxAcquiredBuffers;
+    return NO_ERROR;
+}
+
+int BufferQueue::getMinUndequeuedBufferCount(bool async) const {
+    // if dequeueBuffer is allowed to error out, we don't have to
+    // add an extra buffer.
+    if (!mUseAsyncBuffer)
+        return mMaxAcquiredBufferCount;
+
+    // we're in async mode, or we want to prevent the app to
+    // deadlock itself, we throw-in an extra buffer to guarantee it.
+    if (mDequeueBufferCannotBlock || async)
+        return mMaxAcquiredBufferCount+1;
+
+    return mMaxAcquiredBufferCount;
+}
+
+int BufferQueue::getMinMaxBufferCountLocked(bool async) const {
+    return getMinUndequeuedBufferCount(async) + 1;
+}
+
+int BufferQueue::getMaxBufferCountLocked(bool async) const {
+    int minMaxBufferCount = getMinMaxBufferCountLocked(async);
+
+    int maxBufferCount = mDefaultMaxBufferCount;
+    if (maxBufferCount < minMaxBufferCount) {
+        maxBufferCount = minMaxBufferCount;
+    }
+    if (mOverrideMaxBufferCount != 0) {
+        assert(mOverrideMaxBufferCount >= minMaxBufferCount);
+        maxBufferCount = mOverrideMaxBufferCount;
+    }
+
+    // Any buffers that are dequeued by the producer or sitting in the queue
+    // waiting to be consumed need to have their slots preserved.  Such
+    // buffers will temporarily keep the max buffer count up until the slots
+    // no longer need to be preserved.
+    for (int i = maxBufferCount; i < NUM_BUFFER_SLOTS; i++) {
+        BufferSlot::BufferState state = mSlots[i].mBufferState;
+        if (state == BufferSlot::QUEUED || state == BufferSlot::DEQUEUED) {
+            maxBufferCount = i + 1;
+        }
+    }
+
+    return maxBufferCount;
+}
+
+bool BufferQueue::stillTracking(const BufferItem *item) const {
+    const BufferSlot &slot = mSlots[item->mBuf];
+
+    ST_LOGV("stillTracking?: item: { slot=%d/%llu, buffer=%p }, "
+            "slot: { slot=%d/%llu, buffer=%p }",
+            item->mBuf, item->mFrameNumber,
+            (item->mGraphicBuffer.get() ? item->mGraphicBuffer->handle : 0),
+            item->mBuf, slot.mFrameNumber,
+            (slot.mGraphicBuffer.get() ? slot.mGraphicBuffer->handle : 0));
+
+    // Compare item with its original buffer slot.  We can check the slot
+    // as the buffer would not be moved to a different slot by the producer.
+    return (slot.mGraphicBuffer != NULL &&
+            item->mGraphicBuffer->handle == slot.mGraphicBuffer->handle);
+}
+
+BufferQueue::ProxyConsumerListener::ProxyConsumerListener(
+        const wp<ConsumerListener>& consumerListener):
+        mConsumerListener(consumerListener) {}
+
+BufferQueue::ProxyConsumerListener::~ProxyConsumerListener() {}
+
+void BufferQueue::ProxyConsumerListener::onFrameAvailable() {
+    sp<ConsumerListener> listener(mConsumerListener.promote());
+    if (listener != NULL) {
+        listener->onFrameAvailable();
+    }
+}
+
+void BufferQueue::ProxyConsumerListener::onBuffersReleased() {
+    sp<ConsumerListener> listener(mConsumerListener.promote());
+    if (listener != NULL) {
+        listener->onBuffersReleased();
+    }
+}
+
+}; // namespace android
new file mode 100644
--- /dev/null
+++ b/widget/gonk/nativewindow/BufferQueue.h
@@ -0,0 +1,574 @@
+/*
+ * 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_GUI_BUFFERQUEUE_H
+#define ANDROID_GUI_BUFFERQUEUE_H
+
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
+
+#include <binder/IBinder.h>
+
+#include <gui/IConsumerListener.h>
+#include <gui/IGraphicBufferAlloc.h>
+#include <gui/IGraphicBufferProducer.h>
+#include <gui/IGraphicBufferConsumer.h>
+
+#include <ui/Fence.h>
+#include <ui/GraphicBuffer.h>
+
+#include <utils/String8.h>
+#include <utils/Vector.h>
+#include <utils/threads.h>
+
+namespace android {
+// ----------------------------------------------------------------------------
+
+class BufferQueue : public BnGraphicBufferProducer,
+                    public BnGraphicBufferConsumer,
+                    private IBinder::DeathRecipient {
+public:
+    enum { MIN_UNDEQUEUED_BUFFERS = 2 };
+    enum { NUM_BUFFER_SLOTS = 32 };
+    enum { NO_CONNECTED_API = 0 };
+    enum { INVALID_BUFFER_SLOT = -1 };
+    enum { STALE_BUFFER_SLOT = 1, NO_BUFFER_AVAILABLE, PRESENT_LATER };
+
+    // When in async mode we reserve two slots in order to guarantee that the
+    // producer and consumer can run asynchronously.
+    enum { MAX_MAX_ACQUIRED_BUFFERS = NUM_BUFFER_SLOTS - 2 };
+
+    // for backward source compatibility
+    typedef ::android::ConsumerListener ConsumerListener;
+
+    // ProxyConsumerListener is a ConsumerListener implementation that keeps a weak
+    // reference to the actual consumer object.  It forwards all calls to that
+    // consumer object so long as it exists.
+    //
+    // This class exists to avoid having a circular reference between the
+    // BufferQueue object and the consumer object.  The reason this can't be a weak
+    // reference in the BufferQueue class is because we're planning to expose the
+    // consumer side of a BufferQueue as a binder interface, which doesn't support
+    // weak references.
+    class ProxyConsumerListener : public BnConsumerListener {
+    public:
+        ProxyConsumerListener(const wp<ConsumerListener>& consumerListener);
+        virtual ~ProxyConsumerListener();
+        virtual void onFrameAvailable();
+        virtual void onBuffersReleased();
+    private:
+        // mConsumerListener is a weak reference to the IConsumerListener.  This is
+        // the raison d'etre of ProxyConsumerListener.
+        wp<ConsumerListener> mConsumerListener;
+    };
+
+
+    // BufferQueue manages a pool of gralloc memory slots to be used by
+    // producers and consumers. allocator is used to allocate all the
+    // needed gralloc buffers.
+    BufferQueue(const sp<IGraphicBufferAlloc>& allocator = NULL);
+    virtual ~BufferQueue();
+
+    /*
+     * IBinder::DeathRecipient interface
+     */
+
+    virtual void binderDied(const wp<IBinder>& who);
+
+    /*
+     * IGraphicBufferProducer interface
+     */
+
+    // Query native window attributes.  The "what" values are enumerated in
+    // window.h (e.g. NATIVE_WINDOW_FORMAT).
+    virtual int query(int what, int* value);
+
+    // setBufferCount updates the number of available buffer slots.  If this
+    // method succeeds, buffer slots will be both unallocated and owned by
+    // the BufferQueue object (i.e. they are not owned by the producer or
+    // consumer).
+    //
+    // This will fail if the producer has dequeued any buffers, or if
+    // bufferCount is invalid.  bufferCount must generally be a value
+    // between the minimum undequeued buffer count and NUM_BUFFER_SLOTS
+    // (inclusive).  It may also be set to zero (the default) to indicate
+    // that the producer does not wish to set a value.  The minimum value
+    // can be obtained by calling query(NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS,
+    // ...).
+    //
+    // This may only be called by the producer.  The consumer will be told
+    // to discard buffers through the onBuffersReleased callback.
+    virtual status_t setBufferCount(int bufferCount);
+
+    // requestBuffer returns the GraphicBuffer for slot N.
+    //
+    // In normal operation, this is called the first time slot N is returned
+    // by dequeueBuffer.  It must be called again if dequeueBuffer returns
+    // flags indicating that previously-returned buffers are no longer valid.
+    virtual status_t requestBuffer(int slot, sp<GraphicBuffer>* buf);
+
+    // dequeueBuffer gets the next buffer slot index for the producer to use.
+    // If a buffer slot is available then that slot index is written to the
+    // location pointed to by the buf argument and a status of OK is returned.
+    // If no slot is available then a status of -EBUSY is returned and buf is
+    // unmodified.
+    //
+    // The fence parameter will be updated to hold the fence associated with
+    // the buffer. The contents of the buffer must not be overwritten until the
+    // fence signals. If the fence is Fence::NO_FENCE, the buffer may be
+    // written immediately.
+    //
+    // The width and height parameters must be no greater than the minimum of
+    // GL_MAX_VIEWPORT_DIMS and GL_MAX_TEXTURE_SIZE (see: glGetIntegerv).
+    // An error due to invalid dimensions might not be reported until
+    // updateTexImage() is called.  If width and height are both zero, the
+    // default values specified by setDefaultBufferSize() are used instead.
+    //
+    // The pixel formats are enumerated in graphics.h, e.g.
+    // HAL_PIXEL_FORMAT_RGBA_8888.  If the format is 0, the default format
+    // will be used.
+    //
+    // The usage argument specifies gralloc buffer usage flags.  The values
+    // are enumerated in gralloc.h, e.g. GRALLOC_USAGE_HW_RENDER.  These
+    // will be merged with the usage flags specified by setConsumerUsageBits.
+    //
+    // The return value may be a negative error value or a non-negative
+    // collection of flags.  If the flags are set, the return values are
+    // valid, but additional actions must be performed.
+    //
+    // If IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION is set, the
+    // producer must discard cached GraphicBuffer references for the slot
+    // returned in buf.
+    // If IGraphicBufferProducer::RELEASE_ALL_BUFFERS is set, the producer
+    // must discard cached GraphicBuffer references for all slots.
+    //
+    // In both cases, the producer will need to call requestBuffer to get a
+    // GraphicBuffer handle for the returned slot.
+    virtual status_t dequeueBuffer(int *buf, sp<Fence>* fence, bool async,
+            uint32_t width, uint32_t height, uint32_t format, uint32_t usage);
+
+    // queueBuffer returns a filled buffer to the BufferQueue.
+    //
+    // Additional data is provided in the QueueBufferInput struct.  Notably,
+    // a timestamp must be provided for the buffer. The timestamp is in
+    // nanoseconds, and must be monotonically increasing. Its other semantics
+    // (zero point, etc) are producer-specific and should be documented by the
+    // producer.
+    //
+    // The caller may provide a fence that signals when all rendering
+    // operations have completed.  Alternatively, NO_FENCE may be used,
+    // indicating that the buffer is ready immediately.
+    //
+    // Some values are returned in the output struct: the current settings
+    // for default width and height, the current transform hint, and the
+    // number of queued buffers.
+    virtual status_t queueBuffer(int buf,
+            const QueueBufferInput& input, QueueBufferOutput* output);
+
+    // cancelBuffer returns a dequeued buffer to the BufferQueue, but doesn't
+    // queue it for use by the consumer.
+    //
+    // The buffer will not be overwritten until the fence signals.  The fence
+    // will usually be the one obtained from dequeueBuffer.
+    virtual void cancelBuffer(int buf, const sp<Fence>& fence);
+
+    // connect attempts to connect a producer API to the BufferQueue.  This
+    // must be called before any other IGraphicBufferProducer methods are
+    // called except for getAllocator.  A consumer must already be connected.
+    //
+    // This method will fail if connect was previously called on the
+    // BufferQueue and no corresponding disconnect call was made (i.e. if
+    // it's still connected to a producer).
+    //
+    // APIs are enumerated in window.h (e.g. NATIVE_WINDOW_API_CPU).
+    virtual status_t connect(const sp<IBinder>& token,
+            int api, bool producerControlledByApp, QueueBufferOutput* output);
+
+    // disconnect attempts to disconnect a producer API from the BufferQueue.
+    // Calling this method will cause any subsequent calls to other
+    // IGraphicBufferProducer methods to fail except for getAllocator and connect.
+    // Successfully calling connect after this will allow the other methods to
+    // succeed again.
+    //
+    // This method will fail if the the BufferQueue is not currently
+    // connected to the specified producer API.
+    virtual status_t disconnect(int api);
+
+    /*
+     * IGraphicBufferConsumer interface
+     */
+
+    // acquireBuffer attempts to acquire ownership of the next pending buffer in
+    // the BufferQueue.  If no buffer is pending then it returns -EINVAL.  If a
+    // buffer is successfully acquired, the information about the buffer is
+    // returned in BufferItem.  If the buffer returned had previously been
+    // acquired then the BufferItem::mGraphicBuffer field of buffer is set to
+    // NULL and it is assumed that the consumer still holds a reference to the
+    // buffer.
+    //
+    // If presentWhen is nonzero, it indicates the time when the buffer will
+    // be displayed on screen.  If the buffer's timestamp is farther in the
+    // future, the buffer won't be acquired, and PRESENT_LATER will be
+    // returned.  The presentation time is in nanoseconds, and the time base
+    // is CLOCK_MONOTONIC.
+    virtual status_t acquireBuffer(BufferItem *buffer, nsecs_t presentWhen);
+
+    // releaseBuffer releases a buffer slot from the consumer back to the
+    // BufferQueue.  This may be done while the buffer's contents are still
+    // being accessed.  The fence will signal when the buffer is no longer
+    // in use. frameNumber is used to indentify the exact buffer returned.
+    //
+    // If releaseBuffer returns STALE_BUFFER_SLOT, then the consumer must free
+    // any references to the just-released buffer that it might have, as if it
+    // had received a onBuffersReleased() call with a mask set for the released
+    // buffer.
+    //
+    // Note that the dependencies on EGL will be removed once we switch to using
+    // the Android HW Sync HAL.
+    virtual status_t releaseBuffer(int buf, uint64_t frameNumber,
+            EGLDisplay display, EGLSyncKHR fence,
+            const sp<Fence>& releaseFence);
+
+    // consumerConnect connects a consumer to the BufferQueue.  Only one
+    // consumer may be connected, and when that consumer disconnects the
+    // BufferQueue is placed into the "abandoned" state, causing most
+    // interactions with the BufferQueue by the producer to fail.
+    // controlledByApp indicates whether the consumer is controlled by
+    // the application.
+    //
+    // consumer may not be NULL.
+    virtual status_t consumerConnect(const sp<IConsumerListener>& consumer, bool controlledByApp);
+
+    // consumerDisconnect disconnects a consumer from the BufferQueue. All
+    // buffers will be freed and the BufferQueue is placed in the "abandoned"
+    // state, causing most interactions with the BufferQueue by the producer to
+    // fail.
+    virtual status_t consumerDisconnect();
+
+    // getReleasedBuffers sets the value pointed to by slotMask to a bit mask
+    // indicating which buffer slots have been released by the BufferQueue
+    // but have not yet been released by the consumer.
+    //
+    // This should be called from the onBuffersReleased() callback.
+    virtual status_t getReleasedBuffers(uint32_t* slotMask);
+
+    // setDefaultBufferSize is used to set the size of buffers returned by
+    // dequeueBuffer when a width and height of zero is requested.  Default
+    // is 1x1.
+    virtual status_t setDefaultBufferSize(uint32_t w, uint32_t h);
+
+    // setDefaultMaxBufferCount sets the default value for the maximum buffer
+    // count (the initial default is 2). If the producer has requested a
+    // buffer count using setBufferCount, the default buffer count will only
+    // take effect if the producer sets the count back to zero.
+    //
+    // The count must be between 2 and NUM_BUFFER_SLOTS, inclusive.
+    virtual status_t setDefaultMaxBufferCount(int bufferCount);
+
+    // disableAsyncBuffer disables the extra buffer used in async mode
+    // (when both producer and consumer have set their "isControlledByApp"
+    // flag) and has dequeueBuffer() return WOULD_BLOCK instead.
+    //
+    // This can only be called before consumerConnect().
+    virtual status_t disableAsyncBuffer();
+
+    // setMaxAcquiredBufferCount sets the maximum number of buffers that can
+    // be acquired by the consumer at one time (default 1).  This call will
+    // fail if a producer is connected to the BufferQueue.
+    virtual status_t setMaxAcquiredBufferCount(int maxAcquiredBuffers);
+
+    // setConsumerName sets the name used in logging
+    virtual void setConsumerName(const String8& name);
+
+    // setDefaultBufferFormat allows the BufferQueue to create
+    // GraphicBuffers of a defaultFormat if no format is specified
+    // in dequeueBuffer.  Formats are enumerated in graphics.h; the
+    // initial default is HAL_PIXEL_FORMAT_RGBA_8888.
+    virtual status_t setDefaultBufferFormat(uint32_t defaultFormat);
+
+    // setConsumerUsageBits will turn on additional usage bits for dequeueBuffer.
+    // These are merged with the bits passed to dequeueBuffer.  The values are
+    // enumerated in gralloc.h, e.g. GRALLOC_USAGE_HW_RENDER; the default is 0.
+    virtual status_t setConsumerUsageBits(uint32_t usage);
+
+    // setTransformHint bakes in rotation to buffers so overlays can be used.
+    // The values are enumerated in window.h, e.g.
+    // NATIVE_WINDOW_TRANSFORM_ROT_90.  The default is 0 (no transform).
+    virtual status_t setTransformHint(uint32_t hint);
+
+    // dump our state in a String
+    virtual void dump(String8& result, const char* prefix) const;
+
+
+private:
+    // freeBufferLocked frees the GraphicBuffer and sync resources for the
+    // given slot.
+    void freeBufferLocked(int index);
+
+    // freeAllBuffersLocked frees the GraphicBuffer and sync resources for
+    // all slots.
+    void freeAllBuffersLocked();
+
+    // setDefaultMaxBufferCountLocked sets the maximum number of buffer slots
+    // that will be used if the producer does not override the buffer slot
+    // count.  The count must be between 2 and NUM_BUFFER_SLOTS, inclusive.
+    // The initial default is 2.
+    status_t setDefaultMaxBufferCountLocked(int count);
+
+    // getMinUndequeuedBufferCount returns the minimum number of buffers
+    // that must remain in a state other than DEQUEUED.
+    // The async parameter tells whether we're in asynchronous mode.
+    int getMinUndequeuedBufferCount(bool async) const;
+
+    // getMinBufferCountLocked returns the minimum number of buffers allowed
+    // given the current BufferQueue state.
+    // The async parameter tells whether we're in asynchronous mode.
+    int getMinMaxBufferCountLocked(bool async) const;
+
+    // getMaxBufferCountLocked returns the maximum number of buffers that can
+    // be allocated at once.  This value depends upon the following member
+    // variables:
+    //
+    //      mDequeueBufferCannotBlock
+    //      mMaxAcquiredBufferCount
+    //      mDefaultMaxBufferCount
+    //      mOverrideMaxBufferCount
+    //      async parameter
+    //
+    // Any time one of these member variables is changed while a producer is
+    // connected, mDequeueCondition must be broadcast.
+    int getMaxBufferCountLocked(bool async) const;
+
+    // stillTracking returns true iff the buffer item is still being tracked
+    // in one of the slots.
+    bool stillTracking(const BufferItem *item) const;
+
+    struct BufferSlot {
+
+        BufferSlot()
+        : mEglDisplay(EGL_NO_DISPLAY),
+          mBufferState(BufferSlot::FREE),
+          mRequestBufferCalled(false),
+          mFrameNumber(0),
+          mEglFence(EGL_NO_SYNC_KHR),
+          mAcquireCalled(false),
+          mNeedsCleanupOnRelease(false) {
+        }
+
+        // mGraphicBuffer points to the buffer allocated for this slot or is NULL
+        // if no buffer has been allocated.
+        sp<GraphicBuffer> mGraphicBuffer;
+
+        // mEglDisplay is the EGLDisplay used to create EGLSyncKHR objects.
+        EGLDisplay mEglDisplay;
+
+        // BufferState represents the different states in which a buffer slot
+        // can be.  All slots are initially FREE.
+        enum BufferState {
+            // FREE indicates that the buffer is available to be dequeued
+            // by the producer.  The buffer may be in use by the consumer for
+            // a finite time, so the buffer must not be modified until the
+            // associated fence is signaled.
+            //
+            // The slot is "owned" by BufferQueue.  It transitions to DEQUEUED
+            // when dequeueBuffer is called.
+            FREE = 0,
+
+            // DEQUEUED indicates that the buffer has been dequeued by the
+            // producer, but has not yet been queued or canceled.  The
+            // producer may modify the buffer's contents as soon as the
+            // associated ready fence is signaled.
+            //
+            // The slot is "owned" by the producer.  It can transition to
+            // QUEUED (via queueBuffer) or back to FREE (via cancelBuffer).
+            DEQUEUED = 1,
+
+            // QUEUED indicates that the buffer has been filled by the
+            // producer and queued for use by the consumer.  The buffer
+            // contents may continue to be modified for a finite time, so
+            // the contents must not be accessed until the associated fence
+            // is signaled.
+            //
+            // The slot is "owned" by BufferQueue.  It can transition to
+            // ACQUIRED (via acquireBuffer) or to FREE (if another buffer is
+            // queued in asynchronous mode).
+            QUEUED = 2,
+
+            // ACQUIRED indicates that the buffer has been acquired by the
+            // consumer.  As with QUEUED, the contents must not be accessed
+            // by the consumer until the fence is signaled.
+            //
+            // The slot is "owned" by the consumer.  It transitions to FREE
+            // when releaseBuffer is called.
+            ACQUIRED = 3
+        };
+
+        // mBufferState is the current state of this buffer slot.
+        BufferState mBufferState;
+
+        // mRequestBufferCalled is used for validating that the producer did
+        // call requestBuffer() when told to do so. Technically this is not
+        // needed but useful for debugging and catching producer bugs.
+        bool mRequestBufferCalled;
+
+        // mFrameNumber is the number of the queued frame for this slot.  This
+        // is used to dequeue buffers in LRU order (useful because buffers
+        // may be released before their release fence is signaled).
+        uint64_t mFrameNumber;
+
+        // mEglFence is the EGL sync object that must signal before the buffer
+        // associated with this buffer slot may be dequeued. It is initialized
+        // to EGL_NO_SYNC_KHR when the buffer is created and may be set to a
+        // new sync object in releaseBuffer.  (This is deprecated in favor of
+        // mFence, below.)
+        EGLSyncKHR mEglFence;
+
+        // mFence is a fence which will signal when work initiated by the
+        // previous owner of the buffer is finished. When the buffer is FREE,
+        // the fence indicates when the consumer has finished reading
+        // from the buffer, or when the producer has finished writing if it
+        // called cancelBuffer after queueing some writes. When the buffer is
+        // QUEUED, it indicates when the producer has finished filling the
+        // buffer. When the buffer is DEQUEUED or ACQUIRED, the fence has been
+        // passed to the consumer or producer along with ownership of the
+        // buffer, and mFence is set to NO_FENCE.
+        sp<Fence> mFence;
+
+        // Indicates whether this buffer has been seen by a consumer yet
+        bool mAcquireCalled;
+
+        // Indicates whether this buffer needs to be cleaned up by the
+        // consumer.  This is set when a buffer in ACQUIRED state is freed.
+        // It causes releaseBuffer to return STALE_BUFFER_SLOT.
+        bool mNeedsCleanupOnRelease;
+    };
+
+    // mSlots is the array of buffer slots that must be mirrored on the
+    // producer side. This allows buffer ownership to be transferred between
+    // the producer and consumer without sending a GraphicBuffer over binder.
+    // The entire array is initialized to NULL at construction time, and
+    // buffers are allocated for a slot when requestBuffer is called with
+    // that slot's index.
+    BufferSlot mSlots[NUM_BUFFER_SLOTS];
+
+    // mDefaultWidth holds the default width of allocated buffers. It is used
+    // in dequeueBuffer() if a width and height of zero is specified.
+    uint32_t mDefaultWidth;
+
+    // mDefaultHeight holds the default height of allocated buffers. It is used
+    // in dequeueBuffer() if a width and height of zero is specified.
+    uint32_t mDefaultHeight;
+
+    // mMaxAcquiredBufferCount is the number of buffers that the consumer may
+    // acquire at one time.  It defaults to 1 and can be changed by the
+    // consumer via the setMaxAcquiredBufferCount method, but this may only be
+    // done when no producer is connected to the BufferQueue.
+    //
+    // This value is used to derive the value returned for the
+    // MIN_UNDEQUEUED_BUFFERS query by the producer.
+    int mMaxAcquiredBufferCount;
+
+    // mDefaultMaxBufferCount is the default limit on the number of buffers
+    // that will be allocated at one time.  This default limit is set by the
+    // consumer.  The limit (as opposed to the default limit) may be
+    // overridden by the producer.
+    int mDefaultMaxBufferCount;
+
+    // mOverrideMaxBufferCount is the limit on the number of buffers that will
+    // be allocated at one time. This value is set by the image producer by
+    // calling setBufferCount. The default is zero, which means the producer
+    // doesn't care about the number of buffers in the pool. In that case
+    // mDefaultMaxBufferCount is used as the limit.
+    int mOverrideMaxBufferCount;
+
+    // mGraphicBufferAlloc is the connection to SurfaceFlinger that is used to
+    // allocate new GraphicBuffer objects.
+    sp<IGraphicBufferAlloc> mGraphicBufferAlloc;
+
+    // mConsumerListener is used to notify the connected consumer of
+    // asynchronous events that it may wish to react to.  It is initially set
+    // to NULL and is written by consumerConnect and consumerDisconnect.
+    sp<IConsumerListener> mConsumerListener;
+
+    // mConsumerControlledByApp whether the connected consumer is controlled by the
+    // application.
+    bool mConsumerControlledByApp;
+
+    // mDequeueBufferCannotBlock whether dequeueBuffer() isn't allowed to block.
+    // this flag is set during connect() when both consumer and producer are controlled
+    // by the application.
+    bool mDequeueBufferCannotBlock;
+
+    // mUseAsyncBuffer whether an extra buffer is used in async mode to prevent
+    // dequeueBuffer() from ever blocking.
+    bool mUseAsyncBuffer;
+
+    // mConnectedApi indicates the producer API that is currently connected
+    // to this BufferQueue.  It defaults to NO_CONNECTED_API (= 0), and gets
+    // updated by the connect and disconnect methods.
+    int mConnectedApi;
+
+    // mDequeueCondition condition used for dequeueBuffer in synchronous mode
+    mutable Condition mDequeueCondition;
+
+    // mQueue is a FIFO of queued buffers used in synchronous mode
+    typedef Vector<BufferItem> Fifo;
+    Fifo mQueue;
+
+    // mAbandoned indicates that the BufferQueue will no longer be used to
+    // consume image buffers pushed to it using the IGraphicBufferProducer
+    // interface.  It is initialized to false, and set to true in the
+    // consumerDisconnect method.  A BufferQueue that has been abandoned will
+    // return the NO_INIT error from all IGraphicBufferProducer methods
+    // capable of returning an error.
+    bool mAbandoned;
+
+    // mConsumerName is a string used to identify the BufferQueue in log
+    // messages.  It is set by the setConsumerName method.
+    String8 mConsumerName;
+
+    // mMutex is the mutex used to prevent concurrent access to the member
+    // variables of BufferQueue objects. It must be locked whenever the
+    // member variables are accessed.
+    mutable Mutex mMutex;
+
+    // mFrameCounter is the free running counter, incremented on every
+    // successful queueBuffer call, and buffer allocation.
+    uint64_t mFrameCounter;
+
+    // mBufferHasBeenQueued is true once a buffer has been queued.  It is
+    // reset when something causes all buffers to be freed (e.g. changing the
+    // buffer count).
+    bool mBufferHasBeenQueued;
+
+    // mDefaultBufferFormat can be set so it will override
+    // the buffer format when it isn't specified in dequeueBuffer
+    uint32_t mDefaultBufferFormat;
+
+    // mConsumerUsageBits contains flags the consumer wants for GraphicBuffers
+    uint32_t mConsumerUsageBits;
+
+    // mTransformHint is used to optimize for screen rotations
+    uint32_t mTransformHint;
+
+    // mConnectedProducerToken is used to set a binder death notification on the producer
+    sp<IBinder> mConnectedProducerToken;
+};
+
+// ----------------------------------------------------------------------------
+}; // namespace android
+
+#endif // ANDROID_GUI_BUFFERQUEUE_H
new file mode 100644
--- /dev/null
+++ b/widget/gonk/nativewindow/ConsumerBase.cpp
@@ -0,0 +1,264 @@
+/*
+ * 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 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<IGraphicBufferConsumer>& bufferQueue, bool controlledByApp) :
+        mAbandoned(false),
+        mConsumer(bufferQueue) {
+    // Choose a name using the PID and a process-unique ID.
+    mName = String8::format("unnamed-%d-%d", getpid(), createProcessUniqueId());
+
+    // Note that we can't create an sp<...>(this) in a ctor that will not keep a
+    // reference once the ctor ends, as that would cause the refcount of 'this'
+    // dropping to 0 at the end of the ctor.  Since all we need is a wp<...>
+    // that's what we create.
+    wp<ConsumerListener> listener = static_cast<ConsumerListener*>(this);
+    sp<IConsumerListener> proxy = new BufferQueue::ProxyConsumerListener(listener);
+
+    status_t err = mConsumer->consumerConnect(proxy, controlledByApp);
+    if (err != NO_ERROR) {
+        CB_LOGE("ConsumerBase: error connecting to BufferQueue: %s (%d)",
+                strerror(-err), err);
+    } else {
+        mConsumer->setConsumerName(mName);
+    }
+}
+
+ConsumerBase::~ConsumerBase() {
+    CB_LOGV("~ConsumerBase");
+    Mutex::Autolock lock(mMutex);
+
+    // Verify that abandon() has been called before we get here.  This should
+    // be done by ConsumerBase::onLastStrongRef(), but it's possible for a
+    // derived class to override that method and not call
+    // ConsumerBase::onLastStrongRef().
+    LOG_ALWAYS_FATAL_IF(!mAbandoned, "[%s] ~ConsumerBase was called, but the "
+        "consumer is not abandoned!", mName.string());
+}
+
+void ConsumerBase::onLastStrongRef(const void* id) {
+    abandon();
+}
+
+void ConsumerBase::freeBufferLocked(int slotIndex) {
+    CB_LOGV("freeBufferLocked: slotIndex=%d", slotIndex);
+    mSlots[slotIndex].mGraphicBuffer = 0;
+    mSlots[slotIndex].mFence = Fence::NO_FENCE;
+    mSlots[slotIndex].mFrameNumber = 0;
+}
+
+void ConsumerBase::onFrameAvailable() {
+    CB_LOGV("onFrameAvailable");
+
+    sp<FrameAvailableListener> listener;
+    { // scope for the lock
+        Mutex::Autolock lock(mMutex);
+        listener = mFrameAvailableListener.promote();
+    }
+
+    if (listener != NULL) {
+        CB_LOGV("actually calling onFrameAvailable");
+        listener->onFrameAvailable();
+    }
+}
+
+void ConsumerBase::onBuffersReleased() {
+    Mutex::Autolock lock(mMutex);
+
+    CB_LOGV("onBuffersReleased");
+
+    if (mAbandoned) {
+        // Nothing to do if we're already abandoned.
+        return;
+    }
+
+    uint32_t mask = 0;
+    mConsumer->getReleasedBuffers(&mask);
+    for (int i = 0; i < 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
+    mConsumer->consumerDisconnect();
+    mConsumer.clear();
+}
+
+void ConsumerBase::setFrameAvailableListener(
+        const wp<FrameAvailableListener>& listener) {
+    CB_LOGV("setFrameAvailableListener");
+    Mutex::Autolock lock(mMutex);
+    mFrameAvailableListener = listener;
+}
+
+void ConsumerBase::dump(String8& result) const {
+    dump(result, "");
+}
+
+void ConsumerBase::dump(String8& result, const char* prefix) const {
+    Mutex::Autolock _l(mMutex);
+    dumpLocked(result, prefix);
+}
+
+void ConsumerBase::dumpLocked(String8& result, const char* prefix) const {
+    result.appendFormat("%smAbandoned=%d\n", prefix, int(mAbandoned));
+
+    if (!mAbandoned) {
+        mConsumer->dump(result, prefix);
+    }
+}
+
+status_t ConsumerBase::acquireBufferLocked(BufferQueue::BufferItem *item,
+        nsecs_t presentWhen) {
+    status_t err = mConsumer->acquireBuffer(item, presentWhen);
+    if (err != NO_ERROR) {
+        return err;
+    }
+
+    if (item->mGraphicBuffer != NULL) {
+        mSlots[item->mBuf].mGraphicBuffer = item->mGraphicBuffer;
+    }
+
+    mSlots[item->mBuf].mFrameNumber = item->mFrameNumber;
+    mSlots[item->mBuf].mFence = item->mFence;
+
+    CB_LOGV("acquireBufferLocked: -> slot=%d/%llu",
+            item->mBuf, item->mFrameNumber);
+
+    return OK;
+}
+
+status_t ConsumerBase::addReleaseFence(int slot,
+        const sp<GraphicBuffer> graphicBuffer, const sp<Fence>& fence) {
+    Mutex::Autolock lock(mMutex);
+    return addReleaseFenceLocked(slot, graphicBuffer, fence);
+}
+
+status_t ConsumerBase::addReleaseFenceLocked(int slot,
+        const sp<GraphicBuffer> graphicBuffer, const sp<Fence>& fence) {
+    CB_LOGV("addReleaseFenceLocked: slot=%d", slot);
+
+    // If consumer no longer tracks this graphicBuffer, we can safely
+    // drop this fence, as it will never be received by the producer.
+    if (!stillTracking(slot, graphicBuffer)) {
+        return OK;
+    }
+
+    if (!mSlots[slot].mFence.get()) {
+        mSlots[slot].mFence = fence;
+    } else {
+        sp<Fence> mergedFence = Fence::merge(
+                String8::format("%.28s:%d", mName.string(), slot),
+                mSlots[slot].mFence, fence);
+        if (!mergedFence.get()) {
+            CB_LOGE("failed to merge release fences");
+            // synchronization is broken, the best we can do is hope fences
+            // signal in order so the new fence will act like a union
+            mSlots[slot].mFence = fence;
+            return BAD_VALUE;
+        }
+        mSlots[slot].mFence = mergedFence;
+    }
+
+    return OK;
+}
+
+status_t ConsumerBase::releaseBufferLocked(
+        int slot, const sp<GraphicBuffer> graphicBuffer,
+        EGLDisplay display, EGLSyncKHR eglFence) {
+    // If consumer no longer tracks this graphicBuffer (we received a new
+    // buffer on the same slot), the buffer producer is definitely no longer
+    // tracking it.
+    if (!stillTracking(slot, graphicBuffer)) {
+        return OK;
+    }
+
+    CB_LOGV("releaseBufferLocked: slot=%d/%llu",
+            slot, mSlots[slot].mFrameNumber);
+    status_t err = mConsumer->releaseBuffer(slot, mSlots[slot].mFrameNumber,
+            display, eglFence, mSlots[slot].mFence);
+    if (err == BufferQueue::STALE_BUFFER_SLOT) {
+        freeBufferLocked(slot);
+    }
+
+    mSlots[slot].mFence = Fence::NO_FENCE;
+
+    return err;
+}
+
+bool ConsumerBase::stillTracking(int slot,
+        const sp<GraphicBuffer> graphicBuffer) {
+    if (slot < 0 || slot >= BufferQueue::NUM_BUFFER_SLOTS) {
+        return false;
+    }
+    return (mSlots[slot].mGraphicBuffer != NULL &&
+            mSlots[slot].mGraphicBuffer->handle == graphicBuffer->handle);
+}
+
+} // namespace android
new file mode 100644
--- /dev/null
+++ b/widget/gonk/nativewindow/ConsumerBase.h
@@ -0,0 +1,238 @@
+/*
+ * 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>
+#include <gui/IConsumerListener.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 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
+    // IGraphicBufferProducer interface will fail with the NO_INIT error.
+    //
+    // Note that while calling this method causes all the buffers to be freed
+    // from the perspective of the the 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);
+
+    // dump writes the current state to a string. Child classes should add
+    // their state to the dump by overriding the dumpLocked method, which is
+    // called by these methods after locking the mutex.
+    void dump(String8& result) const;
+    void dump(String8& result, const char* prefix) const;
+
+    // setFrameAvailableListener sets the listener object that will be notified
+    // when a new frame becomes available.
+    void setFrameAvailableListener(const wp<FrameAvailableListener>& listener);
+
+private:
+    ConsumerBase(const ConsumerBase&);
+    void operator=(const ConsumerBase&);
+
+protected:
+    // ConsumerBase constructs a new ConsumerBase object to consume image
+    // buffers from the given IGraphicBufferConsumer.
+    // The controlledByApp flag indicates that this consumer is under the application's
+    // control.
+    ConsumerBase(const sp<IGraphicBufferConsumer>& consumer, bool controlledByApp = false);
+
+    // onLastStrongRef gets called by RefBase just before the dtor of the most
+    // derived class.  It is used to clean up the buffers so that ConsumerBase
+    // can coordinate the clean-up by calling into virtual methods implemented
+    // by the derived classes.  This would not be possible from the
+    // ConsuemrBase dtor because by the time that gets called the derived
+    // classes have already been destructed.
+    //
+    // This methods should not need to be overridden by derived classes, but
+    // if they are overridden the ConsumerBase implementation must be called
+    // from the derived class.
+    virtual void onLastStrongRef(const void* id);
+
+    // Implementation of the IConsumerListener interface.  These
+    // calls are used to notify the ConsumerBase of asynchronous events in the
+    // BufferQueue.  These methods should not need to be overridden by derived
+    // classes, but if they are overridden the ConsumerBase implementation
+    // must be called from the derived class.
+    virtual void onFrameAvailable();
+    virtual void onBuffersReleased();
+
+    // freeBufferLocked frees up the given buffer slot.  If the slot has been
+    // initialized this will release the reference to the GraphicBuffer in that
+    // slot.  Otherwise it has no effect.
+    //
+    // Derived classes should override this method to clean up any state they
+    // keep per slot.  If it is overridden, the derived class's implementation
+    // must call ConsumerBase::freeBufferLocked.
+    //
+    // 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.
+    //
+    // Derived classes should override this method to clean up any object
+    // state they keep (as opposed to per-slot state).  If it is overridden,
+    // the derived class's implementation must call ConsumerBase::abandonLocked.
+    //
+    // This method must be called with mMutex locked.
+    virtual void abandonLocked();
+
+    // dumpLocked dumps the current state of the ConsumerBase object to the
+    // result string.  Each line is prefixed with the string pointed to by the
+    // prefix argument.  The buffer argument points to a buffer that may be
+    // used for intermediate formatting data, and the size of that buffer is
+    // indicated by the size argument.
+    //
+    // Derived classes should override this method to dump their internal
+    // state.  If this method is overridden the derived class's implementation
+    // should call ConsumerBase::dumpLocked.
+    //
+    // This method must be called with mMutex locked.
+    virtual void dumpLocked(String8& result, const char* prefix) const;
+
+    // acquireBufferLocked fetches the next buffer from the BufferQueue and
+    // updates the buffer slot for the buffer returned.
+    //
+    // Derived classes should override this method to perform any
+    // initialization that must take place the first time a buffer is assigned
+    // to a slot.  If it is overridden the derived class's implementation must
+    // call ConsumerBase::acquireBufferLocked.
+    virtual status_t acquireBufferLocked(IGraphicBufferConsumer::BufferItem *item,
+        nsecs_t presentWhen);
+
+    // releaseBufferLocked relinquishes control over a buffer, returning that
+    // control to the BufferQueue.
+    //
+    // Derived classes should override this method to perform any cleanup that
+    // must take place when a buffer is released back to the BufferQueue.  If
+    // it is overridden the derived class's implementation must call
+    // ConsumerBase::releaseBufferLocked.e
+    virtual status_t releaseBufferLocked(int slot,
+            const sp<GraphicBuffer> graphicBuffer,
+            EGLDisplay display, EGLSyncKHR eglFence);
+
+    // returns true iff the slot still has the graphicBuffer in it.
+    bool stillTracking(int slot, const sp<GraphicBuffer> graphicBuffer);
+
+    // addReleaseFence* adds the sync points associated with a fence to the set
+    // of sync points that must be reached before the buffer in the given slot
+    // may be used after the slot has been released.  This should be called by
+    // derived classes each time some asynchronous work is kicked off that
+    // references the buffer.
+    status_t addReleaseFence(int slot,
+            const sp<GraphicBuffer> graphicBuffer, const sp<Fence>& fence);
+    status_t addReleaseFenceLocked(int slot,
+            const sp<GraphicBuffer> graphicBuffer, const sp<Fence>& fence);
+
+    // Slot contains the information and object references that
+    // 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;
+
+        // the frame number of the last acquired frame for this slot
+        uint64_t mFrameNumber;
+    };
+
+    // 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 IGraphicBufferProducer
+    // 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.
+    wp<FrameAvailableListener> mFrameAvailableListener;
+
+    // The ConsumerBase has-a BufferQueue and is responsible for creating this object
+    // if none is supplied
+    sp<IGraphicBufferConsumer> mConsumer;
+
+    // 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 or when any of the *Locked methods are
+    // called.
+    //
+    // This mutex is intended to be locked by derived classes.
+    mutable Mutex mMutex;
+};
+
+// ----------------------------------------------------------------------------
+}; // namespace android
+
+#endif // ANDROID_GUI_CONSUMERBASE_H
new file mode 100644
--- /dev/null
+++ b/widget/gonk/nativewindow/IGraphicBufferConsumer.cpp
@@ -0,0 +1,485 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define EGL_EGLEXT_PROTOTYPES
+
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
+
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <utils/Errors.h>
+
+#include <binder/Parcel.h>
+#include <binder/IInterface.h>
+
+#include <gui/IConsumerListener.h>
+#include <gui/IGraphicBufferConsumer.h>
+
+#include <ui/GraphicBuffer.h>
+#include <ui/Fence.h>
+
+#include <system/window.h>
+
+namespace android {
+// ---------------------------------------------------------------------------
+
+IGraphicBufferConsumer::BufferItem::BufferItem() :
+    mTransform(0),
+    mScalingMode(NATIVE_WINDOW_SCALING_MODE_FREEZE),
+    mTimestamp(0),
+    mIsAutoTimestamp(false),
+    mFrameNumber(0),
+    mBuf(INVALID_BUFFER_SLOT),
+    mIsDroppable(false),
+    mAcquireCalled(false),
+    mTransformToDisplayInverse(false) {
+    mCrop.makeInvalid();
+}
+
+size_t IGraphicBufferConsumer::BufferItem::getPodSize() const {
+    size_t c =  sizeof(mCrop) +
+            sizeof(mTransform) +
+            sizeof(mScalingMode) +
+            sizeof(mTimestamp) +
+            sizeof(mIsAutoTimestamp) +
+            sizeof(mFrameNumber) +
+            sizeof(mBuf) +
+            sizeof(mIsDroppable) +
+            sizeof(mAcquireCalled) +
+            sizeof(mTransformToDisplayInverse);
+    return c;
+}
+
+size_t IGraphicBufferConsumer::BufferItem::getFlattenedSize() const {
+    size_t c = 0;
+    if (mGraphicBuffer != 0) {
+        c += mGraphicBuffer->getFlattenedSize();
+        FlattenableUtils::align<4>(c);
+    }
+    if (mFence != 0) {
+        c += mFence->getFlattenedSize();
+        FlattenableUtils::align<4>(c);
+    }
+    return sizeof(int32_t) + c + getPodSize();
+}
+
+size_t IGraphicBufferConsumer::BufferItem::getFdCount() const {
+    size_t c = 0;
+    if (mGraphicBuffer != 0) {
+        c += mGraphicBuffer->getFdCount();
+    }
+    if (mFence != 0) {
+        c += mFence->getFdCount();
+    }
+    return c;
+}
+
+status_t IGraphicBufferConsumer::BufferItem::flatten(
+        void*& buffer, size_t& size, int*& fds, size_t& count) const {
+
+    // make sure we have enough space
+    if (count < BufferItem::getFlattenedSize()) {
+        return NO_MEMORY;
+    }
+
+    // content flags are stored first
+    uint32_t& flags = *static_cast<uint32_t*>(buffer);
+
+    // advance the pointer
+    FlattenableUtils::advance(buffer, size, sizeof(uint32_t));
+
+    flags = 0;
+    if (mGraphicBuffer != 0) {
+        status_t err = mGraphicBuffer->flatten(buffer, size, fds, count);
+        if (err) return err;
+        size -= FlattenableUtils::align<4>(buffer);
+        flags |= 1;
+    }
+    if (mFence != 0) {
+        status_t err = mFence->flatten(buffer, size, fds, count);
+        if (err) return err;
+        size -= FlattenableUtils::align<4>(buffer);
+        flags |= 2;
+    }
+
+    // check we have enough space (in case flattening the fence/graphicbuffer lied to us)
+    if (size < getPodSize()) {
+        return NO_MEMORY;
+    }
+
+    FlattenableUtils::write(buffer, size, mCrop);
+    FlattenableUtils::write(buffer, size, mTransform);
+    FlattenableUtils::write(buffer, size, mScalingMode);
+    FlattenableUtils::write(buffer, size, mTimestamp);
+    FlattenableUtils::write(buffer, size, mIsAutoTimestamp);
+    FlattenableUtils::write(buffer, size, mFrameNumber);
+    FlattenableUtils::write(buffer, size, mBuf);
+    FlattenableUtils::write(buffer, size, mIsDroppable);
+    FlattenableUtils::write(buffer, size, mAcquireCalled);
+    FlattenableUtils::write(buffer, size, mTransformToDisplayInverse);
+
+    return NO_ERROR;
+}
+
+status_t IGraphicBufferConsumer::BufferItem::unflatten(
+        void const*& buffer, size_t& size, int const*& fds, size_t& count) {
+
+    if (size < sizeof(uint32_t))
+        return NO_MEMORY;
+
+    uint32_t flags = 0;
+    FlattenableUtils::read(buffer, size, flags);
+
+    if (flags & 1) {
+        mGraphicBuffer = new GraphicBuffer();
+        status_t err = mGraphicBuffer->unflatten(buffer, size, fds, count);
+        if (err) return err;
+        size -= FlattenableUtils::align<4>(buffer);
+    }
+
+    if (flags & 2) {
+        mFence = new Fence();
+        status_t err = mFence->unflatten(buffer, size, fds, count);
+        if (err) return err;
+        size -= FlattenableUtils::align<4>(buffer);
+    }
+
+    // check we have enough space
+    if (size < getPodSize()) {
+        return NO_MEMORY;
+    }
+
+    FlattenableUtils::read(buffer, size, mCrop);
+    FlattenableUtils::read(buffer, size, mTransform);
+    FlattenableUtils::read(buffer, size, mScalingMode);
+    FlattenableUtils::read(buffer, size, mTimestamp);
+    FlattenableUtils::read(buffer, size, mIsAutoTimestamp);
+    FlattenableUtils::read(buffer, size, mFrameNumber);
+    FlattenableUtils::read(buffer, size, mBuf);
+    FlattenableUtils::read(buffer, size, mIsDroppable);
+    FlattenableUtils::read(buffer, size, mAcquireCalled);
+    FlattenableUtils::read(buffer, size, mTransformToDisplayInverse);
+
+    return NO_ERROR;
+}
+
+// ---------------------------------------------------------------------------
+
+enum {
+    ACQUIRE_BUFFER = IBinder::FIRST_CALL_TRANSACTION,
+    RELEASE_BUFFER,
+    CONSUMER_CONNECT,
+    CONSUMER_DISCONNECT,
+    GET_RELEASED_BUFFERS,
+    SET_DEFAULT_BUFFER_SIZE,
+    SET_DEFAULT_MAX_BUFFER_COUNT,
+    DISABLE_ASYNC_BUFFER,
+    SET_MAX_ACQUIRED_BUFFER_COUNT,
+    SET_CONSUMER_NAME,
+    SET_DEFAULT_BUFFER_FORMAT,
+    SET_CONSUMER_USAGE_BITS,
+    SET_TRANSFORM_HINT,
+    DUMP,
+};
+
+
+class BpGraphicBufferConsumer : public BpInterface<IGraphicBufferConsumer>
+{
+public:
+    BpGraphicBufferConsumer(const sp<IBinder>& impl)
+        : BpInterface<IGraphicBufferConsumer>(impl)
+    {
+    }
+
+    virtual status_t acquireBuffer(BufferItem *buffer, nsecs_t presentWhen) {
+        Parcel data, reply;
+        data.writeInterfaceToken(IGraphicBufferConsumer::getInterfaceDescriptor());
+        data.writeInt64(presentWhen);
+        status_t result = remote()->transact(ACQUIRE_BUFFER, data, &reply);
+        if (result != NO_ERROR) {
+            return result;
+        }
+        result = reply.read(*buffer);
+        if (result != NO_ERROR) {
+            return result;
+        }
+        return reply.readInt32();
+    }
+
+    virtual status_t releaseBuffer(int buf, uint64_t frameNumber,
+            EGLDisplay display, EGLSyncKHR fence,
+            const sp<Fence>& releaseFence) {
+        Parcel data, reply;
+        data.writeInterfaceToken(IGraphicBufferConsumer::getInterfaceDescriptor());
+        data.writeInt32(buf);
+        data.writeInt64(frameNumber);
+        data.write(*releaseFence);
+        status_t result = remote()->transact(RELEASE_BUFFER, data, &reply);
+        if (result != NO_ERROR) {
+            return result;
+        }
+        return reply.readInt32();
+    }
+
+    virtual status_t consumerConnect(const sp<IConsumerListener>& consumer, bool controlledByApp) {
+        Parcel data, reply;
+        data.writeInterfaceToken(IGraphicBufferConsumer::getInterfaceDescriptor());
+        data.writeStrongBinder(consumer->asBinder());
+        data.writeInt32(controlledByApp);
+        status_t result = remote()->transact(CONSUMER_CONNECT, data, &reply);
+        if (result != NO_ERROR) {
+            return result;
+        }
+        return reply.readInt32();
+    }
+
+    virtual status_t consumerDisconnect() {
+        Parcel data, reply;
+        data.writeInterfaceToken(IGraphicBufferConsumer::getInterfaceDescriptor());
+        status_t result = remote()->transact(CONSUMER_DISCONNECT, data, &reply);
+        if (result != NO_ERROR) {
+            return result;
+        }
+        return reply.readInt32();
+    }
+
+    virtual status_t getReleasedBuffers(uint32_t* slotMask) {
+        Parcel data, reply;
+        data.writeInterfaceToken(IGraphicBufferConsumer::getInterfaceDescriptor());
+        status_t result = remote()->transact(GET_RELEASED_BUFFERS, data, &reply);
+        if (result != NO_ERROR) {
+            return result;
+        }
+        *slotMask = reply.readInt32();
+        return reply.readInt32();
+    }
+
+    virtual status_t setDefaultBufferSize(uint32_t w, uint32_t h) {
+        Parcel data, reply;
+        data.writeInterfaceToken(IGraphicBufferConsumer::getInterfaceDescriptor());
+        data.writeInt32(w);
+        data.writeInt32(h);
+        status_t result = remote()->transact(SET_DEFAULT_BUFFER_SIZE, data, &reply);
+        if (result != NO_ERROR) {
+            return result;
+        }
+        return reply.readInt32();
+    }
+
+    virtual status_t setDefaultMaxBufferCount(int bufferCount) {
+        Parcel data, reply;
+        data.writeInterfaceToken(IGraphicBufferConsumer::getInterfaceDescriptor());
+        data.writeInt32(bufferCount);
+        status_t result = remote()->transact(SET_DEFAULT_MAX_BUFFER_COUNT, data, &reply);
+        if (result != NO_ERROR) {
+            return result;
+        }
+        return reply.readInt32();
+    }
+
+    virtual status_t disableAsyncBuffer() {
+        Parcel data, reply;
+        data.writeInterfaceToken(IGraphicBufferConsumer::getInterfaceDescriptor());
+        status_t result = remote()->transact(DISABLE_ASYNC_BUFFER, data, &reply);
+        if (result != NO_ERROR) {
+            return result;
+        }
+        return reply.readInt32();
+    }
+
+    virtual status_t setMaxAcquiredBufferCount(int maxAcquiredBuffers) {
+        Parcel data, reply;
+        data.writeInterfaceToken(IGraphicBufferConsumer::getInterfaceDescriptor());
+        data.writeInt32(maxAcquiredBuffers);
+        status_t result = remote()->transact(SET_MAX_ACQUIRED_BUFFER_COUNT, data, &reply);
+        if (result != NO_ERROR) {
+            return result;
+        }
+        return reply.readInt32();
+    }
+
+    virtual void setConsumerName(const String8& name) {
+        Parcel data, reply;
+        data.writeInterfaceToken(IGraphicBufferConsumer::getInterfaceDescriptor());
+        data.writeString8(name);
+        remote()->transact(SET_CONSUMER_NAME, data, &reply);
+    }
+
+    virtual status_t setDefaultBufferFormat(uint32_t defaultFormat) {
+        Parcel data, reply;
+        data.writeInterfaceToken(IGraphicBufferConsumer::getInterfaceDescriptor());
+        data.writeInt32(defaultFormat);
+        status_t result = remote()->transact(SET_DEFAULT_BUFFER_FORMAT, data, &reply);
+        if (result != NO_ERROR) {
+            return result;
+        }
+        return reply.readInt32();
+    }
+
+    virtual status_t setConsumerUsageBits(uint32_t usage) {
+        Parcel data, reply;
+        data.writeInterfaceToken(IGraphicBufferConsumer::getInterfaceDescriptor());
+        data.writeInt32(usage);
+        status_t result = remote()->transact(SET_CONSUMER_USAGE_BITS, data, &reply);
+        if (result != NO_ERROR) {
+            return result;
+        }
+        return reply.readInt32();
+    }
+
+    virtual status_t setTransformHint(uint32_t hint) {
+        Parcel data, reply;
+        data.writeInterfaceToken(IGraphicBufferConsumer::getInterfaceDescriptor());
+        data.writeInt32(hint);
+        status_t result = remote()->transact(SET_TRANSFORM_HINT, data, &reply);
+        if (result != NO_ERROR) {
+            return result;
+        }
+        return reply.readInt32();
+    }
+
+    virtual void dump(String8& result, const char* prefix) const {
+        Parcel data, reply;
+        data.writeInterfaceToken(IGraphicBufferConsumer::getInterfaceDescriptor());
+        data.writeString8(result);
+        data.writeString8(String8(prefix ? prefix : ""));
+        remote()->transact(DUMP, data, &reply);
+        reply.readString8();
+    }
+};
+
+IMPLEMENT_META_INTERFACE(GraphicBufferConsumer, "android.gui.IGraphicBufferConsumer");
+
+// ----------------------------------------------------------------------
+
+status_t BnGraphicBufferConsumer::onTransact(
+        uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
+{
+    switch(code) {
+        case ACQUIRE_BUFFER: {
+            CHECK_INTERFACE(IGraphicBufferConsumer, data, reply);
+            BufferItem item;
+            int64_t presentWhen = data.readInt64();
+            status_t result = acquireBuffer(&item, presentWhen);
+            status_t err = reply->write(item);
+            if (err) return err;
+            reply->writeInt32(result);
+            return NO_ERROR;
+        } break;
+        case RELEASE_BUFFER: {
+            CHECK_INTERFACE(IGraphicBufferConsumer, data, reply);
+            int buf = data.readInt32();
+            uint64_t frameNumber = data.readInt64();
+            sp<Fence> releaseFence = new Fence();
+            status_t err = data.read(*releaseFence);
+            if (err) return err;
+            status_t result = releaseBuffer(buf, frameNumber,
+                    EGL_NO_DISPLAY, EGL_NO_SYNC_KHR, releaseFence);
+            reply->writeInt32(result);
+            return NO_ERROR;
+        } break;
+        case CONSUMER_CONNECT: {
+            CHECK_INTERFACE(IGraphicBufferConsumer, data, reply);
+            sp<IConsumerListener> consumer = IConsumerListener::asInterface( data.readStrongBinder() );
+            bool controlledByApp = data.readInt32();
+            status_t result = consumerConnect(consumer, controlledByApp);
+            reply->writeInt32(result);
+            return NO_ERROR;
+        } break;
+        case CONSUMER_DISCONNECT: {
+            CHECK_INTERFACE(IGraphicBufferConsumer, data, reply);
+            status_t result = consumerDisconnect();
+            reply->writeInt32(result);
+            return NO_ERROR;
+        } break;
+        case GET_RELEASED_BUFFERS: {
+            CHECK_INTERFACE(IGraphicBufferConsumer, data, reply);
+            uint32_t slotMask;
+            status_t result = getReleasedBuffers(&slotMask);
+            reply->writeInt32(slotMask);
+            reply->writeInt32(result);
+            return NO_ERROR;
+        } break;
+        case SET_DEFAULT_BUFFER_SIZE: {
+            CHECK_INTERFACE(IGraphicBufferConsumer, data, reply);
+            uint32_t w = data.readInt32();
+            uint32_t h = data.readInt32();
+            status_t result = setDefaultBufferSize(w, h);
+            reply->writeInt32(result);
+            return NO_ERROR;
+        } break;
+        case SET_DEFAULT_MAX_BUFFER_COUNT: {
+            CHECK_INTERFACE(IGraphicBufferConsumer, data, reply);
+            uint32_t bufferCount = data.readInt32();
+            status_t result = setDefaultMaxBufferCount(bufferCount);
+            reply->writeInt32(result);
+            return NO_ERROR;
+        } break;
+        case DISABLE_ASYNC_BUFFER: {
+            CHECK_INTERFACE(IGraphicBufferConsumer, data, reply);
+            status_t result = disableAsyncBuffer();
+            reply->writeInt32(result);
+            return NO_ERROR;
+        } break;
+        case SET_MAX_ACQUIRED_BUFFER_COUNT: {
+            CHECK_INTERFACE(IGraphicBufferConsumer, data, reply);
+            uint32_t maxAcquiredBuffers = data.readInt32();
+            status_t result = setMaxAcquiredBufferCount(maxAcquiredBuffers);
+            reply->writeInt32(result);
+            return NO_ERROR;
+        } break;
+        case SET_CONSUMER_NAME: {
+            CHECK_INTERFACE(IGraphicBufferConsumer, data, reply);
+            setConsumerName( data.readString8() );
+            return NO_ERROR;
+        } break;
+        case SET_DEFAULT_BUFFER_FORMAT: {
+            CHECK_INTERFACE(IGraphicBufferConsumer, data, reply);
+            uint32_t defaultFormat = data.readInt32();
+            status_t result = setDefaultBufferFormat(defaultFormat);
+            reply->writeInt32(result);
+            return NO_ERROR;
+        } break;
+        case SET_CONSUMER_USAGE_BITS: {
+            CHECK_INTERFACE(IGraphicBufferConsumer, data, reply);
+            uint32_t usage = data.readInt32();
+            status_t result = setConsumerUsageBits(usage);
+            reply->writeInt32(result);
+            return NO_ERROR;
+        } break;
+        case SET_TRANSFORM_HINT: {
+            CHECK_INTERFACE(IGraphicBufferConsumer, data, reply);
+            uint32_t hint = data.readInt32();
+            status_t result = setTransformHint(hint);
+            reply->writeInt32(result);
+            return NO_ERROR;
+        } break;
+        case DUMP: {
+            CHECK_INTERFACE(IGraphicBufferConsumer, data, reply);
+            String8 result = data.readString8();
+            String8 prefix = data.readString8();
+            static_cast<IGraphicBufferConsumer*>(this)->dump(result, prefix);
+            reply->writeString8(result);
+            return NO_ERROR;
+        }
+    }
+    return BBinder::onTransact(code, data, reply, flags);
+}
+
+}; // namespace android
new file mode 100644
--- /dev/null
+++ b/widget/gonk/nativewindow/IGraphicBufferConsumer.h
@@ -0,0 +1,220 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_GUI_IGRAPHICBUFFERCONSUMER_H
+#define ANDROID_GUI_IGRAPHICBUFFERCONSUMER_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <utils/Errors.h>
+#include <utils/RefBase.h>
+#include <utils/Timers.h>
+
+#include <binder/IInterface.h>
+#include <ui/Rect.h>
+
+namespace android {
+// ----------------------------------------------------------------------------
+
+class IConsumerListener;
+class GraphicBuffer;
+class Fence;
+
+class IGraphicBufferConsumer : public IInterface {
+
+public:
+
+    // public facing structure for BufferSlot
+    class BufferItem : public Flattenable<BufferItem> {
+        friend class Flattenable<BufferItem>;
+        size_t getPodSize() const;
+        size_t getFlattenedSize() const;
+        size_t getFdCount() const;
+        status_t flatten(void*& buffer, size_t& size, int*& fds, size_t& count) const;
+        status_t unflatten(void const*& buffer, size_t& size, int const*& fds, size_t& count);
+
+    public:
+        enum { INVALID_BUFFER_SLOT = -1 };
+        BufferItem();
+
+        // mGraphicBuffer points to the buffer allocated for this slot, or is NULL
+        // if the buffer in this slot has been acquired in the past (see
+        // BufferSlot.mAcquireCalled).
+        sp<GraphicBuffer> mGraphicBuffer;
+
+        // mFence is a fence that will signal when the buffer is idle.
+        sp<Fence> mFence;
+
+        // mCrop is the current crop rectangle for this buffer slot.
+        Rect mCrop;
+
+        // mTransform is the current transform flags for this buffer slot.
+        uint32_t mTransform;
+
+        // mScalingMode is the current scaling mode for this buffer slot.
+        uint32_t mScalingMode;
+
+        // mTimestamp is the current timestamp for this buffer slot. This gets
+        // to set by queueBuffer each time this slot is queued.
+        int64_t mTimestamp;
+
+        // mIsAutoTimestamp indicates whether mTimestamp was generated
+        // automatically when the buffer was queued.
+        bool mIsAutoTimestamp;
+
+        // mFrameNumber is the number of the queued frame for this slot.
+        uint64_t mFrameNumber;
+
+        // mBuf is the slot index of this buffer
+        int mBuf;
+
+        // mIsDroppable whether this buffer was queued with the
+        // property that it can be replaced by a new buffer for the purpose of
+        // making sure dequeueBuffer() won't block.
+        // i.e.: was the BufferQueue in "mDequeueBufferCannotBlock" when this buffer
+        // was queued.
+        bool mIsDroppable;
+
+        // Indicates whether this buffer has been seen by a consumer yet
+        bool mAcquireCalled;
+
+        // Indicates this buffer must be transformed by the inverse transform of the screen
+        // it is displayed onto. This is applied after mTransform.
+        bool mTransformToDisplayInverse;
+    };
+
+
+    // acquireBuffer attempts to acquire ownership of the next pending buffer in
+    // the BufferQueue.  If no buffer is pending then it returns -EINVAL.  If a
+    // buffer is successfully acquired, the information about the buffer is
+    // returned in BufferItem.  If the buffer returned had previously been
+    // acquired then the BufferItem::mGraphicBuffer field of buffer is set to
+    // NULL and it is assumed that the consumer still holds a reference to the
+    // buffer.
+    //
+    // If presentWhen is nonzero, it indicates the time when the buffer will
+    // be displayed on screen.  If the buffer's timestamp is farther in the
+    // future, the buffer won't be acquired, and PRESENT_LATER will be
+    // returned.  The presentation time is in nanoseconds, and the time base
+    // is CLOCK_MONOTONIC.
+    virtual status_t acquireBuffer(BufferItem *buffer, nsecs_t presentWhen) = 0;
+
+    // releaseBuffer releases a buffer slot from the consumer back to the
+    // BufferQueue.  This may be done while the buffer's contents are still
+    // being accessed.  The fence will signal when the buffer is no longer
+    // in use. frameNumber is used to indentify the exact buffer returned.
+    //
+    // If releaseBuffer returns STALE_BUFFER_SLOT, then the consumer must free
+    // any references to the just-released buffer that it might have, as if it
+    // had received a onBuffersReleased() call with a mask set for the released
+    // buffer.
+    //
+    // Note that the dependencies on EGL will be removed once we switch to using
+    // the Android HW Sync HAL.
+    virtual status_t releaseBuffer(int buf, uint64_t frameNumber,
+            EGLDisplay display, EGLSyncKHR fence,
+            const sp<Fence>& releaseFence) = 0;
+
+    // consumerConnect connects a consumer to the BufferQueue.  Only one
+    // consumer may be connected, and when that consumer disconnects the
+    // BufferQueue is placed into the "abandoned" state, causing most
+    // interactions with the BufferQueue by the producer to fail.
+    // controlledByApp indicates whether the consumer is controlled by
+    // the application.
+    //
+    // consumer may not be NULL.
+    virtual status_t consumerConnect(const sp<IConsumerListener>& consumer, bool controlledByApp) = 0;
+
+    // consumerDisconnect disconnects a consumer from the BufferQueue. All
+    // buffers will be freed and the BufferQueue is placed in the "abandoned"
+    // state, causing most interactions with the BufferQueue by the producer to
+    // fail.
+    virtual status_t consumerDisconnect() = 0;
+
+    // getReleasedBuffers sets the value pointed to by slotMask to a bit mask
+    // indicating which buffer slots have been released by the BufferQueue
+    // but have not yet been released by the consumer.
+    //
+    // This should be called from the onBuffersReleased() callback.
+    virtual status_t getReleasedBuffers(uint32_t* slotMask) = 0;
+
+    // setDefaultBufferSize is used to set the size of buffers returned by
+    // dequeueBuffer when a width and height of zero is requested.  Default
+    // is 1x1.
+    virtual status_t setDefaultBufferSize(uint32_t w, uint32_t h) = 0;
+
+    // setDefaultMaxBufferCount sets the default value for the maximum buffer
+    // count (the initial default is 2). If the producer has requested a
+    // buffer count using setBufferCount, the default buffer count will only
+    // take effect if the producer sets the count back to zero.
+    //
+    // The count must be between 2 and NUM_BUFFER_SLOTS, inclusive.
+    virtual status_t setDefaultMaxBufferCount(int bufferCount) = 0;
+
+    // disableAsyncBuffer disables the extra buffer used in async mode
+    // (when both producer and consumer have set their "isControlledByApp"
+    // flag) and has dequeueBuffer() return WOULD_BLOCK instead.
+    //
+    // This can only be called before consumerConnect().
+    virtual status_t disableAsyncBuffer() = 0;
+
+    // setMaxAcquiredBufferCount sets the maximum number of buffers that can
+    // be acquired by the consumer at one time (default 1).  This call will
+    // fail if a producer is connected to the BufferQueue.
+    virtual status_t setMaxAcquiredBufferCount(int maxAcquiredBuffers) = 0;
+
+    // setConsumerName sets the name used in logging
+    virtual void setConsumerName(const String8& name) = 0;
+
+    // setDefaultBufferFormat allows the BufferQueue to create
+    // GraphicBuffers of a defaultFormat if no format is specified
+    // in dequeueBuffer.  Formats are enumerated in graphics.h; the
+    // initial default is HAL_PIXEL_FORMAT_RGBA_8888.
+    virtual status_t setDefaultBufferFormat(uint32_t defaultFormat) = 0;
+
+    // setConsumerUsageBits will turn on additional usage bits for dequeueBuffer.
+    // These are merged with the bits passed to dequeueBuffer.  The values are
+    // enumerated in gralloc.h, e.g. GRALLOC_USAGE_HW_RENDER; the default is 0.
+    virtual status_t setConsumerUsageBits(uint32_t usage) = 0;
+
+    // setTransformHint bakes in rotation to buffers so overlays can be used.
+    // The values are enumerated in window.h, e.g.
+    // NATIVE_WINDOW_TRANSFORM_ROT_90.  The default is 0 (no transform).
+    virtual status_t setTransformHint(uint32_t hint) = 0;
+
+    // dump state into a string
+    virtual void dump(String8& result, const char* prefix) const = 0;
+
+public:
+    DECLARE_META_INTERFACE(GraphicBufferConsumer);
+};
+
+// ----------------------------------------------------------------------------
+
+class BnGraphicBufferConsumer : public BnInterface<IGraphicBufferConsumer>
+{
+public:
+    virtual status_t    onTransact( uint32_t code,
+                                    const Parcel& data,
+                                    Parcel* reply,
+                                    uint32_t flags = 0);
+};
+
+// ----------------------------------------------------------------------------
+}; // namespace android
+
+#endif // ANDROID_GUI_IGRAPHICBUFFERCONSUMER_H
new file mode 100644
--- /dev/null
+++ b/widget/gonk/nativewindow/Surface.cpp
@@ -0,0 +1,842 @@
+/*
+ * 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 "Surface"
+#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+//#define LOG_NDEBUG 0
+
+#include <android/native_window.h>
+
+#include <binder/Parcel.h>
+
+#include <utils/Log.h>
+#include <utils/Trace.h>
+
+#include <ui/Fence.h>
+
+#include <gui/ISurfaceComposer.h>
+#include <gui/SurfaceComposerClient.h>
+#include <gui/GLConsumer.h>
+#include <gui/Surface.h>
+
+#include <private/gui/ComposerService.h>
+
+namespace android {
+
+Surface::Surface(
+        const sp<IGraphicBufferProducer>& bufferProducer,
+        bool controlledByApp)
+    : mGraphicBufferProducer(bufferProducer)
+{
+    // Initialize the ANativeWindow function pointers.
+    ANativeWindow::setSwapInterval  = hook_setSwapInterval;
+    ANativeWindow::dequeueBuffer    = hook_dequeueBuffer;
+    ANativeWindow::cancelBuffer     = hook_cancelBuffer;
+    ANativeWindow::queueBuffer      = hook_queueBuffer;
+    ANativeWindow::query            = hook_query;
+    ANativeWindow::perform          = hook_perform;
+
+    ANativeWindow::dequeueBuffer_DEPRECATED = hook_dequeueBuffer_DEPRECATED;
+    ANativeWindow::cancelBuffer_DEPRECATED  = hook_cancelBuffer_DEPRECATED;
+    ANativeWindow::lockBuffer_DEPRECATED    = hook_lockBuffer_DEPRECATED;
+    ANativeWindow::queueBuffer_DEPRECATED   = hook_queueBuffer_DEPRECATED;
+
+    const_cast<int&>(ANativeWindow::minSwapInterval) = 0;
+    const_cast<int&>(ANativeWindow::maxSwapInterval) = 1;
+
+    mReqWidth = 0;
+    mReqHeight = 0;
+    mReqFormat = 0;
+    mReqUsage = 0;
+    mTimestamp = NATIVE_WINDOW_TIMESTAMP_AUTO;
+    mCrop.clear();
+    mScalingMode = NATIVE_WINDOW_SCALING_MODE_FREEZE;
+    mTransform = 0;
+    mDefaultWidth = 0;
+    mDefaultHeight = 0;
+    mUserWidth = 0;
+    mUserHeight = 0;
+    mTransformHint = 0;
+    mConsumerRunningBehind = false;
+    mConnectedToCpu = false;
+    mProducerControlledByApp = controlledByApp;
+    mSwapIntervalZero = false;
+}
+
+Surface::~Surface() {
+    if (mConnectedToCpu) {
+        Surface::disconnect(NATIVE_WINDOW_API_CPU);
+    }
+}
+
+sp<IGraphicBufferProducer> Surface::getIGraphicBufferProducer() const {
+    return mGraphicBufferProducer;
+}
+
+int Surface::hook_setSwapInterval(ANativeWindow* window, int interval) {
+    Surface* c = getSelf(window);
+    return c->setSwapInterval(interval);
+}
+
+int Surface::hook_dequeueBuffer(ANativeWindow* window,
+        ANativeWindowBuffer** buffer, int* fenceFd) {
+    Surface* c = getSelf(window);
+    return c->dequeueBuffer(buffer, fenceFd);
+}
+
+int Surface::hook_cancelBuffer(ANativeWindow* window,
+        ANativeWindowBuffer* buffer, int fenceFd) {
+    Surface* c = getSelf(window);
+    return c->cancelBuffer(buffer, fenceFd);
+}
+
+int Surface::hook_queueBuffer(ANativeWindow* window,
+        ANativeWindowBuffer* buffer, int fenceFd) {
+    Surface* c = getSelf(window);
+    return c->queueBuffer(buffer, fenceFd);
+}
+
+int Surface::hook_dequeueBuffer_DEPRECATED(ANativeWindow* window,
+        ANativeWindowBuffer** buffer) {
+    Surface* c = getSelf(window);
+    ANativeWindowBuffer* buf;
+    int fenceFd = -1;
+    int result = c->dequeueBuffer(&buf, &fenceFd);
+    sp<Fence> fence(new Fence(fenceFd));
+    int waitResult = fence->waitForever("dequeueBuffer_DEPRECATED");
+    if (waitResult != OK) {
+        ALOGE("dequeueBuffer_DEPRECATED: Fence::wait returned an error: %d",
+                waitResult);
+        c->cancelBuffer(buf, -1);
+        return waitResult;
+    }
+    *buffer = buf;
+    return result;
+}
+
+int Surface::hook_cancelBuffer_DEPRECATED(ANativeWindow* window,
+        ANativeWindowBuffer* buffer) {
+    Surface* c = getSelf(window);
+    return c->cancelBuffer(buffer, -1);
+}
+
+int Surface::hook_lockBuffer_DEPRECATED(ANativeWindow* window,
+        ANativeWindowBuffer* buffer) {
+    Surface* c = getSelf(window);
+    return c->lockBuffer_DEPRECATED(buffer);
+}
+
+int Surface::hook_queueBuffer_DEPRECATED(ANativeWindow* window,
+        ANativeWindowBuffer* buffer) {
+    Surface* c = getSelf(window);
+    return c->queueBuffer(buffer, -1);
+}
+
+int Surface::hook_query(const ANativeWindow* window,
+                                int what, int* value) {
+    const Surface* c = getSelf(window);
+    return c->query(what, value);
+}
+
+int Surface::hook_perform(ANativeWindow* window, int operation, ...) {
+    va_list args;
+    va_start(args, operation);
+    Surface* c = getSelf(window);
+    return c->perform(operation, args);
+}
+
+int Surface::setSwapInterval(int interval) {
+    ATRACE_CALL();
+    // EGL specification states:
+    //  interval is silently clamped to minimum and maximum implementation
+    //  dependent values before being stored.
+
+    if (interval < minSwapInterval)
+        interval = minSwapInterval;
+
+    if (interval > maxSwapInterval)
+        interval = maxSwapInterval;
+
+    mSwapIntervalZero = (interval == 0);
+
+    return NO_ERROR;
+}
+
+int Surface::dequeueBuffer(android_native_buffer_t** buffer, int* fenceFd) {
+    ATRACE_CALL();
+    ALOGV("Surface::dequeueBuffer");
+    Mutex::Autolock lock(mMutex);
+    int buf = -1;
+    int reqW = mReqWidth ? mReqWidth : mUserWidth;
+    int reqH = mReqHeight ? mReqHeight : mUserHeight;
+    sp<Fence> fence;
+    status_t result = mGraphicBufferProducer->dequeueBuffer(&buf, &fence, mSwapIntervalZero,
+            reqW, reqH, mReqFormat, mReqUsage);
+    if (result < 0) {
+        ALOGV("dequeueBuffer: IGraphicBufferProducer::dequeueBuffer(%d, %d, %d, %d)"
+             "failed: %d", mReqWidth, mReqHeight, mReqFormat, mReqUsage,
+             result);
+        return result;
+    }
+    sp<GraphicBuffer>& gbuf(mSlots[buf].buffer);
+
+    // this should never happen
+    ALOGE_IF(fence == NULL, "Surface::dequeueBuffer: received null Fence! buf=%d", buf);
+
+    if (result & IGraphicBufferProducer::RELEASE_ALL_BUFFERS) {
+        freeAllBuffers();
+    }
+
+    if ((result & IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION) || gbuf == 0) {
+        result = mGraphicBufferProducer->requestBuffer(buf, &gbuf);
+        if (result != NO_ERROR) {
+            ALOGE("dequeueBuffer: IGraphicBufferProducer::requestBuffer failed: %d", result);
+            return result;
+        }
+    }
+
+    if (fence->isValid()) {
+        *fenceFd = fence->dup();
+        if (*fenceFd == -1) {
+            ALOGE("dequeueBuffer: error duping fence: %d", errno);
+            // dup() should never fail; something is badly wrong. Soldier on
+            // and hope for the best; the worst that should happen is some
+            // visible corruption that lasts until the next frame.
+        }
+    } else {
+        *fenceFd = -1;
+    }
+
+    *buffer = gbuf.get();
+    return OK;
+}
+
+int Surface::cancelBuffer(android_native_buffer_t* buffer,
+        int fenceFd) {
+    ATRACE_CALL();
+    ALOGV("Surface::cancelBuffer");
+    Mutex::Autolock lock(mMutex);
+    int i = getSlotFromBufferLocked(buffer);
+    if (i < 0) {
+        return i;
+    }
+    sp<Fence> fence(fenceFd >= 0 ? new Fence(fenceFd) : Fence::NO_FENCE);
+    mGraphicBufferProducer->cancelBuffer(i, fence);
+    return OK;
+}
+
+int Surface::getSlotFromBufferLocked(
+        android_native_buffer_t* buffer) const {
+    bool dumpedState = false;
+    for (int i = 0; i < NUM_BUFFER_SLOTS; i++) {
+        if (mSlots[i].buffer != NULL &&
+                mSlots[i].buffer->handle == buffer->handle) {
+            return i;
+        }
+    }
+    ALOGE("getSlotFromBufferLocked: unknown buffer: %p", buffer->handle);
+    return BAD_VALUE;
+}
+
+int Surface::lockBuffer_DEPRECATED(android_native_buffer_t* buffer) {
+    ALOGV("Surface::lockBuffer");
+    Mutex::Autolock lock(mMutex);
+    return OK;
+}
+
+int Surface::queueBuffer(android_native_buffer_t* buffer, int fenceFd) {
+    ATRACE_CALL();
+    ALOGV("Surface::queueBuffer");
+    Mutex::Autolock lock(mMutex);
+    int64_t timestamp;
+    bool isAutoTimestamp = false;
+    if (mTimestamp == NATIVE_WINDOW_TIMESTAMP_AUTO) {
+        timestamp = systemTime(SYSTEM_TIME_MONOTONIC);
+        isAutoTimestamp = true;
+        ALOGV("Surface::queueBuffer making up timestamp: %.2f ms",
+            timestamp / 1000000.f);
+    } else {
+        timestamp = mTimestamp;
+    }
+    int i = getSlotFromBufferLocked(buffer);
+    if (i < 0) {
+        return i;
+    }
+
+
+    // Make sure the crop rectangle is entirely inside the buffer.
+    Rect crop;
+    mCrop.intersect(Rect(buffer->width, buffer->height), &crop);
+
+    sp<Fence> fence(fenceFd >= 0 ? new Fence(fenceFd) : Fence::NO_FENCE);
+    IGraphicBufferProducer::QueueBufferOutput output;
+    IGraphicBufferProducer::QueueBufferInput input(timestamp, isAutoTimestamp,
+            crop, mScalingMode, mTransform, mSwapIntervalZero, fence);
+    status_t err = mGraphicBufferProducer->queueBuffer(i, input, &output);
+    if (err != OK)  {
+        ALOGE("queueBuffer: error queuing buffer to SurfaceTexture, %d", err);
+    }
+    uint32_t numPendingBuffers = 0;
+    output.deflate(&mDefaultWidth, &mDefaultHeight, &mTransformHint,
+            &numPendingBuffers);
+
+    mConsumerRunningBehind = (numPendingBuffers >= 2);
+
+    return err;
+}
+
+int Surface::query(int what, int* value) const {
+    ATRACE_CALL();
+    ALOGV("Surface::query");
+    { // scope for the lock
+        Mutex::Autolock lock(mMutex);
+        switch (what) {
+            case NATIVE_WINDOW_FORMAT:
+                if (mReqFormat) {
+                    *value = mReqFormat;
+                    return NO_ERROR;
+                }
+                break;
+            case NATIVE_WINDOW_QUEUES_TO_WINDOW_COMPOSER: {
+                sp<ISurfaceComposer> composer(
+                        ComposerService::getComposerService());
+                if (composer->authenticateSurfaceTexture(mGraphicBufferProducer)) {
+                    *value = 1;
+                } else {
+                    *value = 0;
+                }
+                return NO_ERROR;
+            }
+            case NATIVE_WINDOW_CONCRETE_TYPE:
+                *value = NATIVE_WINDOW_SURFACE;
+                return NO_ERROR;
+            case NATIVE_WINDOW_DEFAULT_WIDTH:
+                *value = mUserWidth ? mUserWidth : mDefaultWidth;
+                return NO_ERROR;
+            case NATIVE_WINDOW_DEFAULT_HEIGHT:
+                *value = mUserHeight ? mUserHeight : mDefaultHeight;
+                return NO_ERROR;
+            case NATIVE_WINDOW_TRANSFORM_HINT:
+                *value = mTransformHint;
+                return NO_ERROR;
+            case NATIVE_WINDOW_CONSUMER_RUNNING_BEHIND: {
+                status_t err = NO_ERROR;
+                if (!mConsumerRunningBehind) {
+                    *value = 0;
+                } else {
+                    err = mGraphicBufferProducer->query(what, value);
+                    if (err == NO_ERROR) {
+                        mConsumerRunningBehind = *value;
+                    }
+                }
+                return err;
+            }
+        }
+    }
+    return mGraphicBufferProducer->query(what, value);
+}
+
+int Surface::perform(int operation, va_list args)
+{
+    int res = NO_ERROR;
+    switch (operation) {
+    case NATIVE_WINDOW_CONNECT:
+        // deprecated. must return NO_ERROR.
+        break;
+    case NATIVE_WINDOW_DISCONNECT:
+        // deprecated. must return NO_ERROR.
+        break;
+    case NATIVE_WINDOW_SET_USAGE:
+        res = dispatchSetUsage(args);
+        break;
+    case NATIVE_WINDOW_SET_CROP:
+        res = dispatchSetCrop(args);
+        break;
+    case NATIVE_WINDOW_SET_BUFFER_COUNT:
+        res = dispatchSetBufferCount(args);
+        break;
+    case NATIVE_WINDOW_SET_BUFFERS_GEOMETRY:
+        res = dispatchSetBuffersGeometry(args);
+        break;
+    case NATIVE_WINDOW_SET_BUFFERS_TRANSFORM:
+        res = dispatchSetBuffersTransform(args);
+        break;
+    case NATIVE_WINDOW_SET_BUFFERS_TIMESTAMP:
+        res = dispatchSetBuffersTimestamp(args);
+        break;
+    case NATIVE_WINDOW_SET_BUFFERS_DIMENSIONS:
+        res = dispatchSetBuffersDimensions(args);
+        break;
+    case NATIVE_WINDOW_SET_BUFFERS_USER_DIMENSIONS:
+        res = dispatchSetBuffersUserDimensions(args);
+        break;
+    case NATIVE_WINDOW_SET_BUFFERS_FORMAT:
+        res = dispatchSetBuffersFormat(args);
+        break;
+    case NATIVE_WINDOW_LOCK:
+        res = dispatchLock(args);
+        break;
+    case NATIVE_WINDOW_UNLOCK_AND_POST:
+        res = dispatchUnlockAndPost(args);
+        break;
+    case NATIVE_WINDOW_SET_SCALING_MODE:
+        res = dispatchSetScalingMode(args);
+        break;
+    case NATIVE_WINDOW_API_CONNECT:
+        res = dispatchConnect(args);
+        break;
+    case NATIVE_WINDOW_API_DISCONNECT:
+        res = dispatchDisconnect(args);
+        break;
+    default:
+        res = NAME_NOT_FOUND;
+        break;
+    }
+    return res;
+}
+
+int Surface::dispatchConnect(va_list args) {
+    int api = va_arg(args, int);
+    return connect(api);
+}
+
+int Surface::dispatchDisconnect(va_list args) {
+    int api = va_arg(args, int);
+    return disconnect(api);
+}
+
+int Surface::dispatchSetUsage(va_list args) {
+    int usage = va_arg(args, int);
+    return setUsage(usage);
+}
+
+int Surface::dispatchSetCrop(va_list args) {
+    android_native_rect_t const* rect = va_arg(args, android_native_rect_t*);
+    return setCrop(reinterpret_cast<Rect const*>(rect));
+}
+
+int Surface::dispatchSetBufferCount(va_list args) {
+    size_t bufferCount = va_arg(args, size_t);
+    return setBufferCount(bufferCount);
+}
+
+int Surface::dispatchSetBuffersGeometry(va_list args) {
+    int w = va_arg(args, int);
+    int h = va_arg(args, int);
+    int f = va_arg(args, int);
+    int err = setBuffersDimensions(w, h);
+    if (err != 0) {
+        return err;
+    }
+    return setBuffersFormat(f);
+}
+
+int Surface::dispatchSetBuffersDimensions(va_list args) {
+    int w = va_arg(args, int);
+    int h = va_arg(args, int);
+    return setBuffersDimensions(w, h);
+}
+
+int Surface::dispatchSetBuffersUserDimensions(va_list args) {
+    int w = va_arg(args, int);
+    int h = va_arg(args, int);
+    return setBuffersUserDimensions(w, h);
+}
+
+int Surface::dispatchSetBuffersFormat(va_list args) {
+    int f = va_arg(args, int);
+    return setBuffersFormat(f);
+}
+
+int Surface::dispatchSetScalingMode(va_list args) {
+    int m = va_arg(args, int);
+    return setScalingMode(m);
+}
+
+int Surface::dispatchSetBuffersTransform(va_list args) {
+    int transform = va_arg(args, int);
+    return setBuffersTransform(transform);
+}
+
+int Surface::dispatchSetBuffersTimestamp(va_list args) {
+    int64_t timestamp = va_arg(args, int64_t);
+    return setBuffersTimestamp(timestamp);
+}
+
+int Surface::dispatchLock(va_list args) {
+    ANativeWindow_Buffer* outBuffer = va_arg(args, ANativeWindow_Buffer*);
+    ARect* inOutDirtyBounds = va_arg(args, ARect*);
+    return lock(outBuffer, inOutDirtyBounds);
+}
+
+int Surface::dispatchUnlockAndPost(va_list args) {
+    return unlockAndPost();
+}
+
+
+int Surface::connect(int api) {
+    ATRACE_CALL();
+    ALOGV("Surface::connect");
+    static sp<BBinder> sLife = new BBinder();
+    Mutex::Autolock lock(mMutex);
+    IGraphicBufferProducer::QueueBufferOutput output;
+    int err = mGraphicBufferProducer->connect(sLife, api, mProducerControlledByApp, &output);
+    if (err == NO_ERROR) {
+        uint32_t numPendingBuffers = 0;
+        output.deflate(&mDefaultWidth, &mDefaultHeight, &mTransformHint,
+                &numPendingBuffers);
+        mConsumerRunningBehind = (numPendingBuffers >= 2);
+    }
+    if (!err && api == NATIVE_WINDOW_API_CPU) {
+        mConnectedToCpu = true;
+    }
+    return err;
+}
+
+
+int Surface::disconnect(int api) {
+    ATRACE_CALL();
+    ALOGV("Surface::disconnect");
+    Mutex::Autolock lock(mMutex);
+    freeAllBuffers();
+    int err = mGraphicBufferProducer->disconnect(api);
+    if (!err) {
+        mReqFormat = 0;
+        mReqWidth = 0;
+        mReqHeight = 0;
+        mReqUsage = 0;
+        mCrop.clear();
+        mScalingMode = NATIVE_WINDOW_SCALING_MODE_FREEZE;
+        mTransform = 0;
+        if (api == NATIVE_WINDOW_API_CPU) {
+            mConnectedToCpu = false;
+        }
+    }
+    return err;
+}
+
+int Surface::setUsage(uint32_t reqUsage)
+{
+    ALOGV("Surface::setUsage");
+    Mutex::Autolock lock(mMutex);
+    mReqUsage = reqUsage;
+    return OK;
+}
+
+int Surface::setCrop(Rect const* rect)
+{
+    ATRACE_CALL();
+
+    Rect realRect;
+    if (rect == NULL || rect->isEmpty()) {
+        realRect.clear();
+    } else {
+        realRect = *rect;
+    }
+
+    ALOGV("Surface::setCrop rect=[%d %d %d %d]",
+            realRect.left, realRect.top, realRect.right, realRect.bottom);
+
+    Mutex::Autolock lock(mMutex);
+    mCrop = realRect;
+    return NO_ERROR;
+}
+
+int Surface::setBufferCount(int bufferCount)
+{
+    ATRACE_CALL();
+    ALOGV("Surface::setBufferCount");
+    Mutex::Autolock lock(mMutex);
+
+    status_t err = mGraphicBufferProducer->setBufferCount(bufferCount);
+    ALOGE_IF(err, "IGraphicBufferProducer::setBufferCount(%d) returned %s",
+            bufferCount, strerror(-err));
+
+    if (err == NO_ERROR) {
+        freeAllBuffers();
+    }
+
+    return err;
+}
+
+int Surface::setBuffersDimensions(int w, int h)
+{
+    ATRACE_CALL();
+    ALOGV("Surface::setBuffersDimensions");
+
+    if (w<0 || h<0)
+        return BAD_VALUE;
+
+    if ((w && !h) || (!w && h))
+        return BAD_VALUE;
+
+    Mutex::Autolock lock(mMutex);
+    mReqWidth = w;
+    mReqHeight = h;
+    return NO_ERROR;
+}
+
+int Surface::setBuffersUserDimensions(int w, int h)
+{
+    ATRACE_CALL();
+    ALOGV("Surface::setBuffersUserDimensions");
+
+    if (w<0 || h<0)
+        return BAD_VALUE;
+
+    if ((w && !h) || (!w && h))
+        return BAD_VALUE;
+
+    Mutex::Autolock lock(mMutex);
+    mUserWidth = w;
+    mUserHeight = h;
+    return NO_ERROR;
+}
+
+int Surface::setBuffersFormat(int format)
+{
+    ALOGV("Surface::setBuffersFormat");
+
+    if (format<0)
+        return BAD_VALUE;
+
+    Mutex::Autolock lock(mMutex);
+    mReqFormat = format;
+    return NO_ERROR;
+}
+
+int Surface::setScalingMode(int mode)
+{
+    ATRACE_CALL();
+    ALOGV("Surface::setScalingMode(%d)", mode);
+
+    switch (mode) {
+        case NATIVE_WINDOW_SCALING_MODE_FREEZE:
+        case NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW:
+        case NATIVE_WINDOW_SCALING_MODE_SCALE_CROP:
+            break;
+        default:
+            ALOGE("unknown scaling mode: %d", mode);
+            return BAD_VALUE;
+    }
+
+    Mutex::Autolock lock(mMutex);
+    mScalingMode = mode;
+    return NO_ERROR;
+}
+
+int Surface::setBuffersTransform(int transform)
+{
+    ATRACE_CALL();
+    ALOGV("Surface::setBuffersTransform");
+    Mutex::Autolock lock(mMutex);
+    mTransform = transform;
+    return NO_ERROR;
+}
+
+int Surface::setBuffersTimestamp(int64_t timestamp)
+{
+    ALOGV("Surface::setBuffersTimestamp");
+    Mutex::Autolock lock(mMutex);
+    mTimestamp = timestamp;
+    return NO_ERROR;
+}
+
+void Surface::freeAllBuffers() {
+    for (int i = 0; i < NUM_BUFFER_SLOTS; i++) {
+        mSlots[i].buffer = 0;
+    }
+}
+
+// ----------------------------------------------------------------------
+// the lock/unlock APIs must be used from the same thread
+
+static status_t copyBlt(
+        const sp<GraphicBuffer>& dst,
+        const sp<GraphicBuffer>& src,
+        const Region& reg)
+{
+    // src and dst with, height and format must be identical. no verification
+    // is done here.
+    status_t err;
+    uint8_t const * src_bits = NULL;
+    err = src->lock(GRALLOC_USAGE_SW_READ_OFTEN, reg.bounds(), (void**)&src_bits);
+    ALOGE_IF(err, "error locking src buffer %s", strerror(-err));
+
+    uint8_t* dst_bits = NULL;
+    err = dst->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, reg.bounds(), (void**)&dst_bits);
+    ALOGE_IF(err, "error locking dst buffer %s", strerror(-err));
+
+    Region::const_iterator head(reg.begin());
+    Region::const_iterator tail(reg.end());
+    if (head != tail && src_bits && dst_bits) {
+        const size_t bpp = bytesPerPixel(src->format);
+        const size_t dbpr = dst->stride * bpp;
+        const size_t sbpr = src->stride * bpp;
+
+        while (head != tail) {
+            const Rect& r(*head++);
+            ssize_t h = r.height();
+            if (h <= 0) continue;
+            size_t size = r.width() * bpp;
+            uint8_t const * s = src_bits + (r.left + src->stride * r.top) * bpp;
+            uint8_t       * d = dst_bits + (r.left + dst->stride * r.top) * bpp;
+            if (dbpr==sbpr && size==sbpr) {
+                size *= h;
+                h = 1;
+            }
+            do {
+                memcpy(d, s, size);
+                d += dbpr;
+                s += sbpr;
+            } while (--h > 0);
+        }
+    }
+
+    if (src_bits)
+        src->unlock();
+
+    if (dst_bits)
+        dst->unlock();
+
+    return err;
+}
+
+// ----------------------------------------------------------------------------
+
+status_t Surface::lock(
+        ANativeWindow_Buffer* outBuffer, ARect* inOutDirtyBounds)
+{
+    if (mLockedBuffer != 0) {
+        ALOGE("Surface::lock failed, already locked");
+        return INVALID_OPERATION;
+    }
+
+    if (!mConnectedToCpu) {
+        int err = Surface::connect(NATIVE_WINDOW_API_CPU);
+        if (err) {
+            return err;
+        }
+        // we're intending to do software rendering from this point
+        setUsage(GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN);
+    }
+
+    ANativeWindowBuffer* out;
+    int fenceFd = -1;
+    status_t err = dequeueBuffer(&out, &fenceFd);
+    ALOGE_IF(err, "dequeueBuffer failed (%s)", strerror(-err));
+    if (err == NO_ERROR) {
+        sp<GraphicBuffer> backBuffer(GraphicBuffer::getSelf(out));
+        sp<Fence> fence(new Fence(fenceFd));
+
+        err = fence->waitForever("Surface::lock");
+        if (err != OK) {
+            ALOGE("Fence::wait failed (%s)", strerror(-err));
+            cancelBuffer(out, fenceFd);
+            return err;
+        }
+
+        const Rect bounds(backBuffer->width, backBuffer->height);
+
+        Region newDirtyRegion;
+        if (inOutDirtyBounds) {
+            newDirtyRegion.set(static_cast<Rect const&>(*inOutDirtyBounds));
+            newDirtyRegion.andSelf(bounds);
+        } else {
+            newDirtyRegion.set(bounds);
+        }
+
+        // figure out if we can copy the frontbuffer back
+        const sp<GraphicBuffer>& frontBuffer(mPostedBuffer);
+        const bool canCopyBack = (frontBuffer != 0 &&
+                backBuffer->width  == frontBuffer->width &&
+                backBuffer->height == frontBuffer->height &&
+                backBuffer->format == frontBuffer->format);
+
+        if (canCopyBack) {
+            // copy the area that is invalid and not repainted this round
+            const Region copyback(mDirtyRegion.subtract(newDirtyRegion));
+            if (!copyback.isEmpty())
+                copyBlt(backBuffer, frontBuffer, copyback);
+        } else {
+            // if we can't copy-back anything, modify the user's dirty
+            // region to make sure they redraw the whole buffer
+            newDirtyRegion.set(bounds);
+            mDirtyRegion.clear();
+            Mutex::Autolock lock(mMutex);
+            for (size_t i=0 ; i<NUM_BUFFER_SLOTS ; i++) {
+                mSlots[i].dirtyRegion.clear();
+            }
+        }
+
+
+        { // scope for the lock
+            Mutex::Autolock lock(mMutex);
+            int backBufferSlot(getSlotFromBufferLocked(backBuffer.get()));
+            if (backBufferSlot >= 0) {
+                Region& dirtyRegion(mSlots[backBufferSlot].dirtyRegion);
+                mDirtyRegion.subtract(dirtyRegion);
+                dirtyRegion = newDirtyRegion;
+            }
+        }
+
+        mDirtyRegion.orSelf(newDirtyRegion);
+        if (inOutDirtyBounds) {
+            *inOutDirtyBounds = newDirtyRegion.getBounds();
+        }
+
+        void* vaddr;
+        status_t res = backBuffer->lock(
+                GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN,
+                newDirtyRegion.bounds(), &vaddr);
+
+        ALOGW_IF(res, "failed locking buffer (handle = %p)",
+                backBuffer->handle);
+
+        if (res != 0) {
+            err = INVALID_OPERATION;
+        } else {
+            mLockedBuffer = backBuffer;
+            outBuffer->width  = backBuffer->width;
+            outBuffer->height = backBuffer->height;
+            outBuffer->stride = backBuffer->stride;
+            outBuffer->format = backBuffer->format;
+            outBuffer->bits   = vaddr;
+        }
+    }
+    return err;
+}
+
+status_t Surface::unlockAndPost()
+{
+    if (mLockedBuffer == 0) {
+        ALOGE("Surface::unlockAndPost failed, no locked buffer");
+        return INVALID_OPERATION;
+    }
+
+    status_t err = mLockedBuffer->unlock();
+    ALOGE_IF(err, "failed unlocking buffer (%p)", mLockedBuffer->handle);
+
+    err = queueBuffer(mLockedBuffer.get(), -1);
+    ALOGE_IF(err, "queueBuffer (handle=%p) failed (%s)",
+            mLockedBuffer->handle, strerror(-err));
+
+    mPostedBuffer = mLockedBuffer;
+    mLockedBuffer = 0;
+    return err;
+}
+
+}; // namespace android
new file mode 100644
--- /dev/null
+++ b/widget/gonk/nativewindow/Surface.h
@@ -0,0 +1,261 @@
+/*
+ * 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_SURFACE_H
+#define ANDROID_GUI_SURFACE_H
+
+#include <gui/IGraphicBufferProducer.h>
+#include <gui/BufferQueue.h>
+
+#include <ui/ANativeObjectBase.h>
+#include <ui/Region.h>
+
+#include <utils/RefBase.h>
+#include <utils/threads.h>
+#include <utils/KeyedVector.h>
+
+struct ANativeWindow_Buffer;
+
+namespace android {
+
+/*
+ * An implementation of ANativeWindow that feeds graphics buffers into a
+ * BufferQueue.
+ *
+ * This is typically used by programs that want to render frames through
+ * some means (maybe OpenGL, a software renderer, or a hardware decoder)
+ * and have the frames they create forwarded to SurfaceFlinger for
+ * compositing.  For example, a video decoder could render a frame and call
+ * eglSwapBuffers(), which invokes ANativeWindow callbacks defined by
+ * Surface.  Surface then forwards the buffers through Binder IPC
+ * to the BufferQueue's producer interface, providing the new frame to a
+ * consumer such as GLConsumer.
+ */
+class Surface
+    : public ANativeObjectBase<ANativeWindow, Surface, RefBase>
+{
+public:
+
+    /*
+     * creates a Surface from the given IGraphicBufferProducer (which concrete
+     * implementation is a BufferQueue).
+     *
+     * Surface is mainly state-less while it's disconnected, it can be
+     * viewed as a glorified IGraphicBufferProducer holder. It's therefore
+     * safe to create other Surfaces from the same IGraphicBufferProducer.
+     *
+     * However, once a Surface is connected, it'll prevent other Surfaces
+     * referring to the same IGraphicBufferProducer to become connected and
+     * therefore prevent them to be used as actual producers of buffers.
+     *
+     * the controlledByApp flag indicates that this Surface (producer) is
+     * controlled by the application. This flag is used at connect time.
+     */
+    Surface(const sp<IGraphicBufferProducer>& bufferProducer, bool controlledByApp = false);
+
+    /* getIGraphicBufferProducer() returns the IGraphicBufferProducer this
+     * Surface was created with. Usually it's an error to use the
+     * IGraphicBufferProducer while the Surface is connected.
+     */
+    sp<IGraphicBufferProducer> getIGraphicBufferProducer() const;
+
+    /* convenience function to check that the given surface is non NULL as
+     * well as its IGraphicBufferProducer */
+    static bool isValid(const sp<Surface>& surface) {
+        return surface != NULL && surface->getIGraphicBufferProducer() != NULL;
+    }
+
+protected:
+    virtual ~Surface();
+
+private:
+    // can't be copied
+    Surface& operator = (const Surface& rhs);
+    Surface(const Surface& rhs);
+
+    // ANativeWindow hooks
+    static int hook_cancelBuffer(ANativeWindow* window,
+            ANativeWindowBuffer* buffer, int fenceFd);
+    static int hook_dequeueBuffer(ANativeWindow* window,
+            ANativeWindowBuffer** buffer, int* fenceFd);
+    static int hook_perform(ANativeWindow* window, int operation, ...);
+    static int hook_query(const ANativeWindow* window, int what, int* value);
+    static int hook_queueBuffer(ANativeWindow* window,
+            ANativeWindowBuffer* buffer, int fenceFd);
+    static int hook_setSwapInterval(ANativeWindow* window, int interval);
+
+    static int hook_cancelBuffer_DEPRECATED(ANativeWindow* window,
+            ANativeWindowBuffer* buffer);
+    static int hook_dequeueBuffer_DEPRECATED(ANativeWindow* window,
+            ANativeWindowBuffer** buffer);
+    static int hook_lockBuffer_DEPRECATED(ANativeWindow* window,
+            ANativeWindowBuffer* buffer);
+    static int hook_queueBuffer_DEPRECATED(ANativeWindow* window,
+            ANativeWindowBuffer* buffer);
+
+    int dispatchConnect(va_list args);
+    int dispatchDisconnect(va_list args);
+    int dispatchSetBufferCount(va_list args);
+    int dispatchSetBuffersGeometry(va_list args);
+    int dispatchSetBuffersDimensions(va_list args);
+    int dispatchSetBuffersUserDimensions(va_list args);
+    int dispatchSetBuffersFormat(va_list args);
+    int dispatchSetScalingMode(va_list args);
+    int dispatchSetBuffersTransform(va_list args);
+    int dispatchSetBuffersTimestamp(va_list args);
+    int dispatchSetCrop(va_list args);
+    int dispatchSetPostTransformCrop(va_list args);
+    int dispatchSetUsage(va_list args);
+    int dispatchLock(va_list args);
+    int dispatchUnlockAndPost(va_list args);
+
+protected:
+    virtual int dequeueBuffer(ANativeWindowBuffer** buffer, int* fenceFd);
+    virtual int cancelBuffer(ANativeWindowBuffer* buffer, int fenceFd);
+    virtual int queueBuffer(ANativeWindowBuffer* buffer, int fenceFd);
+    virtual int perform(int operation, va_list args);
+    virtual int query(int what, int* value) const;
+    virtual int setSwapInterval(int interval);
+
+    virtual int lockBuffer_DEPRECATED(ANativeWindowBuffer* buffer);
+
+    virtual int connect(int api);
+    virtual int disconnect(int api);
+    virtual int setBufferCount(int bufferCount);
+    virtual int setBuffersDimensions(int w, int h);
+    virtual int setBuffersUserDimensions(int w, int h);
+    virtual int setBuffersFormat(int format);
+    virtual int setScalingMode(int mode);
+    virtual int setBuffersTransform(int transform);
+    virtual int setBuffersTimestamp(int64_t timestamp);
+    virtual int setCrop(Rect const* rect);
+    virtual int setUsage(uint32_t reqUsage);
+
+public:
+    virtual int lock(ANativeWindow_Buffer* outBuffer, ARect* inOutDirtyBounds);
+    virtual int unlockAndPost();
+
+protected:
+    enum { NUM_BUFFER_SLOTS = BufferQueue::NUM_BUFFER_SLOTS };
+    enum { DEFAULT_FORMAT = PIXEL_FORMAT_RGBA_8888 };
+
+private:
+    void freeAllBuffers();
+    int getSlotFromBufferLocked(android_native_buffer_t* buffer) const;
+
+    struct BufferSlot {
+        sp<GraphicBuffer> buffer;
+        Region dirtyRegion;
+    };
+
+    // mSurfaceTexture is the interface to the surface texture server. All
+    // operations on the surface texture client ultimately translate into
+    // interactions with the server using this interface.
+    // TODO: rename to mBufferProducer
+    sp<IGraphicBufferProducer> mGraphicBufferProducer;
+
+    // mSlots stores the buffers that have been allocated for each buffer slot.
+    // It is initialized to null pointers, and gets filled in with the result of
+    // IGraphicBufferProducer::requestBuffer when the client dequeues a buffer from a
+    // slot that has not yet been used. The buffer allocated to a slot will also
+    // be replaced if the requested buffer usage or geometry differs from that
+    // of the buffer allocated to a slot.
+    BufferSlot mSlots[NUM_BUFFER_SLOTS];
+
+    // mReqWidth is the buffer width that will be requested at the next dequeue
+    // operation. It is initialized to 1.
+    uint32_t mReqWidth;
+
+    // mReqHeight is the buffer height that will be requested at the next
+    // dequeue operation. It is initialized to 1.
+    uint32_t mReqHeight;
+
+    // mReqFormat is the buffer pixel format that will be requested at the next
+    // deuque operation. It is initialized to PIXEL_FORMAT_RGBA_8888.
+    uint32_t mReqFormat;
+
+    // mReqUsage is the set of buffer usage flags that will be requested
+    // at the next deuque operation. It is initialized to 0.
+    uint32_t mReqUsage;
+
+    // mTimestamp is the timestamp that will be used for the next buffer queue
+    // operation. It defaults to NATIVE_WINDOW_TIMESTAMP_AUTO, which means that
+    // a timestamp is auto-generated when queueBuffer is called.
+    int64_t mTimestamp;
+
+    // mCrop is the crop rectangle that will be used for the next buffer
+    // that gets queued. It is set by calling setCrop.
+    Rect mCrop;
+
+    // mScalingMode is the scaling mode that will be used for the next
+    // buffers that get queued. It is set by calling setScalingMode.
+    int mScalingMode;
+
+    // mTransform is the transform identifier that will be used for the next
+    // buffer that gets queued. It is set by calling setTransform.
+    uint32_t mTransform;
+
+     // mDefaultWidth is default width of the buffers, regardless of the
+     // native_window_set_buffers_dimensions call.
+     uint32_t mDefaultWidth;
+
+     // mDefaultHeight is default height of the buffers, regardless of the
+     // native_window_set_buffers_dimensions call.
+     uint32_t mDefaultHeight;
+
+     // mUserWidth, if non-zero, is an application-specified override
+     // of mDefaultWidth.  This is lower priority than the width set by
+     // native_window_set_buffers_dimensions.
+     uint32_t mUserWidth;
+
+     // mUserHeight, if non-zero, is an application-specified override
+     // of mDefaultHeight.  This is lower priority than the height set
+     // by native_window_set_buffers_dimensions.
+     uint32_t mUserHeight;
+
+    // mTransformHint is the transform probably applied to buffers of this
+    // window. this is only a hint, actual transform may differ.
+    uint32_t mTransformHint;
+
+    // mProducerControlledByApp whether this buffer producer is controlled
+    // by the application
+    bool mProducerControlledByApp;
+
+    // mSwapIntervalZero set if we should drop buffers at queue() time to
+    // achieve an asynchronous swap interval
+    bool mSwapIntervalZero;
+
+    // mConsumerRunningBehind whether the consumer is running more than
+    // one buffer behind the producer.
+    mutable bool mConsumerRunningBehind;
+
+    // mMutex is the mutex used to prevent concurrent access to the member
+    // variables of Surface objects. It must be locked whenever the
+    // member variables are accessed.
+    mutable Mutex mMutex;
+
+    // must be used from the lock/unlock thread
+    sp<GraphicBuffer>           mLockedBuffer;
+    sp<GraphicBuffer>           mPostedBuffer;
+    bool                        mConnectedToCpu;
+
+    // must be accessed from lock/unlock thread only
+    Region mDirtyRegion;
+};
+
+}; // namespace android
+
+#endif  // ANDROID_GUI_SURFACE_H