Bug 1098970 - Part 1: Add new LL native files. r=sotaro
authorBoris Chiou <boris.chiou@gmail.com>
Wed, 17 Dec 2014 18:26:00 +0100
changeset 220878 b8ecf0c5376fd0ac6900c908a1a5f0bab7f89f45
parent 220877 9592f4f944bc2923e8ce33b0d395b1c698d247a6
child 220879 6b38930f9b8df2389d76dc1e2bd7f0a2a73b6eea
push id28002
push userryanvm@gmail.com
push dateMon, 22 Dec 2014 22:32:35 +0000
treeherderautoland@3b5d17fb1517 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssotaro
bugs1098970
milestone37.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1098970 - Part 1: Add new LL native files. r=sotaro Copied from aosp/framework/native/gui.
widget/gonk/nativewindow/GonkBufferQueueLL/BufferItem.cpp
widget/gonk/nativewindow/GonkBufferQueueLL/BufferItem.h
widget/gonk/nativewindow/GonkBufferQueueLL/BufferQueue.cpp
widget/gonk/nativewindow/GonkBufferQueueLL/BufferQueue.h
widget/gonk/nativewindow/GonkBufferQueueLL/BufferQueueConsumer.cpp
widget/gonk/nativewindow/GonkBufferQueueLL/BufferQueueConsumer.h
widget/gonk/nativewindow/GonkBufferQueueLL/BufferQueueCore.cpp
widget/gonk/nativewindow/GonkBufferQueueLL/BufferQueueCore.h
widget/gonk/nativewindow/GonkBufferQueueLL/BufferQueueDefs.h
widget/gonk/nativewindow/GonkBufferQueueLL/BufferQueueProducer.cpp
widget/gonk/nativewindow/GonkBufferQueueLL/BufferQueueProducer.h
widget/gonk/nativewindow/GonkBufferQueueLL/BufferSlot.cpp
widget/gonk/nativewindow/GonkBufferQueueLL/BufferSlot.h
widget/gonk/nativewindow/GonkBufferQueueLL/ConsumerBase.cpp
widget/gonk/nativewindow/GonkBufferQueueLL/ConsumerBase.h
widget/gonk/nativewindow/GonkBufferQueueLL/IGraphicBufferConsumer.cpp
widget/gonk/nativewindow/GonkBufferQueueLL/IGraphicBufferConsumer.h
new file mode 100644
--- /dev/null
+++ b/widget/gonk/nativewindow/GonkBufferQueueLL/BufferItem.cpp
@@ -0,0 +1,192 @@
+/*
+ * Copyright 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <gui/BufferItem.h>
+
+#include <ui/Fence.h>
+#include <ui/GraphicBuffer.h>
+
+#include <system/window.h>
+
+namespace android {
+
+BufferItem::BufferItem() :
+    mTransform(0),
+    mScalingMode(NATIVE_WINDOW_SCALING_MODE_FREEZE),
+    mTimestamp(0),
+    mIsAutoTimestamp(false),
+    mFrameNumber(0),
+    mSlot(INVALID_BUFFER_SLOT),
+    mIsDroppable(false),
+    mAcquireCalled(false),
+    mTransformToDisplayInverse(false) {
+    mCrop.makeInvalid();
+}
+
+BufferItem::operator IGraphicBufferConsumer::BufferItem() const {
+    IGraphicBufferConsumer::BufferItem bufferItem;
+    bufferItem.mGraphicBuffer = mGraphicBuffer;
+    bufferItem.mFence = mFence;
+    bufferItem.mCrop = mCrop;
+    bufferItem.mTransform = mTransform;
+    bufferItem.mScalingMode = mScalingMode;
+    bufferItem.mTimestamp = mTimestamp;
+    bufferItem.mIsAutoTimestamp = mIsAutoTimestamp;
+    bufferItem.mFrameNumber = mFrameNumber;
+    bufferItem.mBuf = mSlot;
+    bufferItem.mIsDroppable = mIsDroppable;
+    bufferItem.mAcquireCalled = mAcquireCalled;
+    bufferItem.mTransformToDisplayInverse = mTransformToDisplayInverse;
+    return bufferItem;
+}
+
+size_t BufferItem::getPodSize() const {
+    size_t c =  sizeof(mCrop) +
+            sizeof(mTransform) +
+            sizeof(mScalingMode) +
+            sizeof(mTimestamp) +
+            sizeof(mIsAutoTimestamp) +
+            sizeof(mFrameNumber) +
+            sizeof(mSlot) +
+            sizeof(mIsDroppable) +
+            sizeof(mAcquireCalled) +
+            sizeof(mTransformToDisplayInverse);
+    return c;
+}
+
+size_t BufferItem::getFlattenedSize() const {
+    size_t c = 0;
+    if (mGraphicBuffer != 0) {
+        c += mGraphicBuffer->getFlattenedSize();
+        FlattenableUtils::align<4>(c);
+    }
+    if (mFence != 0) {
+        c += mFence->getFlattenedSize();
+        FlattenableUtils::align<4>(c);
+    }
+    return sizeof(int32_t) + c + getPodSize();
+}
+
+size_t BufferItem::getFdCount() const {
+    size_t c = 0;
+    if (mGraphicBuffer != 0) {
+        c += mGraphicBuffer->getFdCount();
+    }
+    if (mFence != 0) {
+        c += mFence->getFdCount();
+    }
+    return c;
+}
+
+status_t BufferItem::flatten(
+        void*& buffer, size_t& size, int*& fds, size_t& count) const {
+
+    // make sure we have enough space
+    if (count < BufferItem::getFlattenedSize()) {
+        return NO_MEMORY;
+    }
+
+    // content flags are stored first
+    uint32_t& flags = *static_cast<uint32_t*>(buffer);
+
+    // advance the pointer
+    FlattenableUtils::advance(buffer, size, sizeof(uint32_t));
+
+    flags = 0;
+    if (mGraphicBuffer != 0) {
+        status_t err = mGraphicBuffer->flatten(buffer, size, fds, count);
+        if (err) return err;
+        size -= FlattenableUtils::align<4>(buffer);
+        flags |= 1;
+    }
+    if (mFence != 0) {
+        status_t err = mFence->flatten(buffer, size, fds, count);
+        if (err) return err;
+        size -= FlattenableUtils::align<4>(buffer);
+        flags |= 2;
+    }
+
+    // check we have enough space (in case flattening the fence/graphicbuffer lied to us)
+    if (size < getPodSize()) {
+        return NO_MEMORY;
+    }
+
+    FlattenableUtils::write(buffer, size, mCrop);
+    FlattenableUtils::write(buffer, size, mTransform);
+    FlattenableUtils::write(buffer, size, mScalingMode);
+    FlattenableUtils::write(buffer, size, mTimestamp);
+    FlattenableUtils::write(buffer, size, mIsAutoTimestamp);
+    FlattenableUtils::write(buffer, size, mFrameNumber);
+    FlattenableUtils::write(buffer, size, mSlot);
+    FlattenableUtils::write(buffer, size, mIsDroppable);
+    FlattenableUtils::write(buffer, size, mAcquireCalled);
+    FlattenableUtils::write(buffer, size, mTransformToDisplayInverse);
+
+    return NO_ERROR;
+}
+
+status_t BufferItem::unflatten(
+        void const*& buffer, size_t& size, int const*& fds, size_t& count) {
+
+    if (size < sizeof(uint32_t))
+        return NO_MEMORY;
+
+    uint32_t flags = 0;
+    FlattenableUtils::read(buffer, size, flags);
+
+    if (flags & 1) {
+        mGraphicBuffer = new GraphicBuffer();
+        status_t err = mGraphicBuffer->unflatten(buffer, size, fds, count);
+        if (err) return err;
+        size -= FlattenableUtils::align<4>(buffer);
+    }
+
+    if (flags & 2) {
+        mFence = new Fence();
+        status_t err = mFence->unflatten(buffer, size, fds, count);
+        if (err) return err;
+        size -= FlattenableUtils::align<4>(buffer);
+    }
+
+    // check we have enough space
+    if (size < getPodSize()) {
+        return NO_MEMORY;
+    }
+
+    FlattenableUtils::read(buffer, size, mCrop);
+    FlattenableUtils::read(buffer, size, mTransform);
+    FlattenableUtils::read(buffer, size, mScalingMode);
+    FlattenableUtils::read(buffer, size, mTimestamp);
+    FlattenableUtils::read(buffer, size, mIsAutoTimestamp);
+    FlattenableUtils::read(buffer, size, mFrameNumber);
+    FlattenableUtils::read(buffer, size, mSlot);
+    FlattenableUtils::read(buffer, size, mIsDroppable);
+    FlattenableUtils::read(buffer, size, mAcquireCalled);
+    FlattenableUtils::read(buffer, size, mTransformToDisplayInverse);
+
+    return NO_ERROR;
+}
+
+const char* BufferItem::scalingModeName(uint32_t scalingMode) {
+    switch (scalingMode) {
+        case NATIVE_WINDOW_SCALING_MODE_FREEZE: return "FREEZE";
+        case NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW: return "SCALE_TO_WINDOW";
+        case NATIVE_WINDOW_SCALING_MODE_SCALE_CROP: return "SCALE_CROP";
+        default: return "Unknown";
+    }
+}
+
+} // namespace android
new file mode 100644
--- /dev/null
+++ b/widget/gonk/nativewindow/GonkBufferQueueLL/BufferItem.h
@@ -0,0 +1,103 @@
+/*
+ * Copyright 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_GUI_BUFFERITEM_H
+#define ANDROID_GUI_BUFFERITEM_H
+
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
+
+#include <gui/IGraphicBufferConsumer.h>
+
+#include <ui/Rect.h>
+
+#include <utils/Flattenable.h>
+#include <utils/StrongPointer.h>
+
+namespace android {
+
+class Fence;
+class GraphicBuffer;
+
+class BufferItem : public Flattenable<BufferItem> {
+    friend class Flattenable<BufferItem>;
+    size_t getPodSize() const;
+    size_t getFlattenedSize() const;
+    size_t getFdCount() const;
+    status_t flatten(void*& buffer, size_t& size, int*& fds, size_t& count) const;
+    status_t unflatten(void const*& buffer, size_t& size, int const*& fds, size_t& count);
+
+    public:
+    // The default value of mBuf, used to indicate this doesn't correspond to a slot.
+    enum { INVALID_BUFFER_SLOT = -1 };
+    BufferItem();
+    operator IGraphicBufferConsumer::BufferItem() const;
+
+    static const char* scalingModeName(uint32_t scalingMode);
+
+    // mGraphicBuffer points to the buffer allocated for this slot, or is NULL
+    // if the buffer in this slot has been acquired in the past (see
+    // BufferSlot.mAcquireCalled).
+    sp<GraphicBuffer> mGraphicBuffer;
+
+    // mFence is a fence that will signal when the buffer is idle.
+    sp<Fence> mFence;
+
+    // mCrop is the current crop rectangle for this buffer slot.
+    Rect mCrop;
+
+    // mTransform is the current transform flags for this buffer slot.
+    // refer to NATIVE_WINDOW_TRANSFORM_* in <window.h>
+    uint32_t mTransform;
+
+    // mScalingMode is the current scaling mode for this buffer slot.
+    // refer to NATIVE_WINDOW_SCALING_* in <window.h>
+    uint32_t mScalingMode;
+
+    // mTimestamp is the current timestamp for this buffer slot. This gets
+    // to set by queueBuffer each time this slot is queued. This value
+    // is guaranteed to be monotonically increasing for each newly
+    // acquired buffer.
+    int64_t mTimestamp;
+
+    // mIsAutoTimestamp indicates whether mTimestamp was generated
+    // automatically when the buffer was queued.
+    bool mIsAutoTimestamp;
+
+    // mFrameNumber is the number of the queued frame for this slot.
+    uint64_t mFrameNumber;
+
+    // mSlot is the slot index of this buffer (default INVALID_BUFFER_SLOT).
+    int mSlot;
+
+    // mIsDroppable whether this buffer was queued with the
+    // property that it can be replaced by a new buffer for the purpose of
+    // making sure dequeueBuffer() won't block.
+    // i.e.: was the BufferQueue in "mDequeueBufferCannotBlock" when this buffer
+    // was queued.
+    bool mIsDroppable;
+
+    // Indicates whether this buffer has been seen by a consumer yet
+    bool mAcquireCalled;
+
+    // Indicates this buffer must be transformed by the inverse transform of the screen
+    // it is displayed onto. This is applied after mTransform.
+    bool mTransformToDisplayInverse;
+};
+
+} // namespace android
+
+#endif
new file mode 100644
--- /dev/null
+++ b/widget/gonk/nativewindow/GonkBufferQueueLL/BufferQueue.cpp
@@ -0,0 +1,79 @@
+/*
+ * 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
+
+#include <gui/BufferQueue.h>
+#include <gui/BufferQueueConsumer.h>
+#include <gui/BufferQueueCore.h>
+#include <gui/BufferQueueProducer.h>
+
+namespace android {
+
+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();
+    }
+}
+
+void BufferQueue::ProxyConsumerListener::onSidebandStreamChanged() {
+    sp<ConsumerListener> listener(mConsumerListener.promote());
+    if (listener != NULL) {
+        listener->onSidebandStreamChanged();
+    }
+}
+
+void BufferQueue::createBufferQueue(sp<IGraphicBufferProducer>* outProducer,
+        sp<IGraphicBufferConsumer>* outConsumer,
+        const sp<IGraphicBufferAlloc>& allocator) {
+    LOG_ALWAYS_FATAL_IF(outProducer == NULL,
+            "BufferQueue: outProducer must not be NULL");
+    LOG_ALWAYS_FATAL_IF(outConsumer == NULL,
+            "BufferQueue: outConsumer must not be NULL");
+
+    sp<BufferQueueCore> core(new BufferQueueCore(allocator));
+    LOG_ALWAYS_FATAL_IF(core == NULL,
+            "BufferQueue: failed to create BufferQueueCore");
+
+    sp<IGraphicBufferProducer> producer(new BufferQueueProducer(core));
+    LOG_ALWAYS_FATAL_IF(producer == NULL,
+            "BufferQueue: failed to create BufferQueueProducer");
+
+    sp<IGraphicBufferConsumer> consumer(new BufferQueueConsumer(core));
+    LOG_ALWAYS_FATAL_IF(consumer == NULL,
+            "BufferQueue: failed to create BufferQueueConsumer");
+
+    *outProducer = producer;
+    *outConsumer = consumer;
+}
+
+}; // namespace android
new file mode 100644
--- /dev/null
+++ b/widget/gonk/nativewindow/GonkBufferQueueLL/BufferQueue.h
@@ -0,0 +1,88 @@
+/*
+ * 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 <gui/BufferQueueDefs.h>
+#include <gui/IGraphicBufferConsumer.h>
+#include <gui/IGraphicBufferProducer.h>
+#include <gui/IConsumerListener.h>
+
+// These are only required to keep other parts of the framework with incomplete
+// dependencies building successfully
+#include <gui/IGraphicBufferAlloc.h>
+
+namespace android {
+
+class BufferQueue {
+public:
+    // BufferQueue will keep track of at most this value of buffers.
+    // Attempts at runtime to increase the number of buffers past this will fail.
+    enum { NUM_BUFFER_SLOTS = BufferQueueDefs::NUM_BUFFER_SLOTS };
+    // Used as a placeholder slot# when the value isn't pointing to an existing buffer.
+    enum { INVALID_BUFFER_SLOT = IGraphicBufferConsumer::BufferItem::INVALID_BUFFER_SLOT };
+    // Alias to <IGraphicBufferConsumer.h> -- please scope from there in future code!
+    enum {
+        NO_BUFFER_AVAILABLE = IGraphicBufferConsumer::NO_BUFFER_AVAILABLE,
+        PRESENT_LATER = IGraphicBufferConsumer::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;
+    typedef IGraphicBufferConsumer::BufferItem BufferItem;
+
+    // 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();
+        virtual void onSidebandStreamChanged();
+    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.
+    static void createBufferQueue(sp<IGraphicBufferProducer>* outProducer,
+            sp<IGraphicBufferConsumer>* outConsumer,
+            const sp<IGraphicBufferAlloc>& allocator = NULL);
+
+private:
+    BufferQueue(); // Create through createBufferQueue
+};
+
+// ----------------------------------------------------------------------------
+}; // namespace android
+
+#endif // ANDROID_GUI_BUFFERQUEUE_H
new file mode 100644
--- /dev/null
+++ b/widget/gonk/nativewindow/GonkBufferQueueLL/BufferQueueConsumer.cpp
@@ -0,0 +1,523 @@
+/*
+ * Copyright 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <inttypes.h>
+
+#define LOG_TAG "BufferQueueConsumer"
+#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+//#define LOG_NDEBUG 0
+
+#include <gui/BufferItem.h>
+#include <gui/BufferQueueConsumer.h>
+#include <gui/BufferQueueCore.h>
+#include <gui/IConsumerListener.h>
+#include <gui/IProducerListener.h>
+
+namespace android {
+
+BufferQueueConsumer::BufferQueueConsumer(const sp<BufferQueueCore>& core) :
+    mCore(core),
+    mSlots(core->mSlots),
+    mConsumerName() {}
+
+BufferQueueConsumer::~BufferQueueConsumer() {}
+
+status_t BufferQueueConsumer::acquireBuffer(BufferItem* outBuffer,
+        nsecs_t expectedPresent) {
+    ATRACE_CALL();
+    Mutex::Autolock lock(mCore->mMutex);
+
+    // Check that the consumer doesn't currently have the maximum number of
+    // buffers acquired. We allow the max buffer count to be exceeded by one
+    // buffer so that the consumer can successfully set up the newly acquired
+    // buffer before releasing the old one.
+    int numAcquiredBuffers = 0;
+    for (int s = 0; s < BufferQueueDefs::NUM_BUFFER_SLOTS; ++s) {
+        if (mSlots[s].mBufferState == BufferSlot::ACQUIRED) {
+            ++numAcquiredBuffers;
+        }
+    }
+    if (numAcquiredBuffers >= mCore->mMaxAcquiredBufferCount + 1) {
+        BQ_LOGE("acquireBuffer: max acquired buffer count reached: %d (max %d)",
+                numAcquiredBuffers, mCore->mMaxAcquiredBufferCount);
+        return INVALID_OPERATION;
+    }
+
+    // Check if the queue is empty.
+    // In asynchronous mode the list is guaranteed to be one buffer deep,
+    // while in synchronous mode we use the oldest buffer.
+    if (mCore->mQueue.empty()) {
+        return NO_BUFFER_AVAILABLE;
+    }
+
+    BufferQueueCore::Fifo::iterator front(mCore->mQueue.begin());
+
+    // If expectedPresent is specified, we may not want to return a buffer yet.
+    // If it's specified and there's more than one buffer queued, we may want
+    // to drop a buffer.
+    if (expectedPresent != 0) {
+        const int MAX_REASONABLE_NSEC = 1000000000ULL; // 1 second
+
+        // The 'expectedPresent' argument indicates when the buffer is expected
+        // to be presented on-screen. If the buffer's desired present time is
+        // earlier (less) than expectedPresent -- meaning it will be displayed
+        // on time or possibly late if we show it as soon as possible -- we
+        // acquire and return it. If we don't want to display it until after the
+        // expectedPresent time, we return PRESENT_LATER without acquiring it.
+        //
+        // To be safe, we don't defer acquisition if expectedPresent is more
+        // than one second in the future beyond the desired present time
+        // (i.e., we'd be holding the buffer for a long time).
+        //
+        // NOTE: Code assumes monotonic time values from the system clock
+        // are positive.
+
+        // Start by checking to see if we can drop frames. We skip this check if
+        // the timestamps are being auto-generated by Surface. If the app isn't
+        // generating timestamps explicitly, it probably doesn't want frames to
+        // be discarded based on them.
+        while (mCore->mQueue.size() > 1 && !mCore->mQueue[0].mIsAutoTimestamp) {
+            // If entry[1] is timely, drop entry[0] (and repeat). We apply an
+            // additional criterion here: we only drop the earlier buffer if our
+            // desiredPresent falls within +/- 1 second of the expected present.
+            // Otherwise, bogus desiredPresent times (e.g., 0 or a small
+            // relative timestamp), which normally mean "ignore the timestamp
+            // and acquire immediately", would cause us to drop frames.
+            //
+            // We may want to add an additional criterion: don't drop the
+            // earlier buffer if entry[1]'s fence hasn't signaled yet.
+            const BufferItem& bufferItem(mCore->mQueue[1]);
+            nsecs_t desiredPresent = bufferItem.mTimestamp;
+            if (desiredPresent < expectedPresent - MAX_REASONABLE_NSEC ||
+                    desiredPresent > expectedPresent) {
+                // This buffer is set to display in the near future, or
+                // desiredPresent is garbage. Either way we don't want to drop
+                // the previous buffer just to get this on the screen sooner.
+                BQ_LOGV("acquireBuffer: nodrop desire=%" PRId64 " expect=%"
+                        PRId64 " (%" PRId64 ") now=%" PRId64,
+                        desiredPresent, expectedPresent,
+                        desiredPresent - expectedPresent,
+                        systemTime(CLOCK_MONOTONIC));
+                break;
+            }
+
+            BQ_LOGV("acquireBuffer: drop desire=%" PRId64 " expect=%" PRId64
+                    " size=%zu",
+                    desiredPresent, expectedPresent, mCore->mQueue.size());
+            if (mCore->stillTracking(front)) {
+                // Front buffer is still in mSlots, so mark the slot as free
+                mSlots[front->mSlot].mBufferState = BufferSlot::FREE;
+            }
+            mCore->mQueue.erase(front);
+            front = mCore->mQueue.begin();
+        }
+
+        // See if the front buffer is due
+        nsecs_t desiredPresent = front->mTimestamp;
+        if (desiredPresent > expectedPresent &&
+                desiredPresent < expectedPresent + MAX_REASONABLE_NSEC) {
+            BQ_LOGV("acquireBuffer: defer desire=%" PRId64 " expect=%" PRId64
+                    " (%" PRId64 ") now=%" PRId64,
+                    desiredPresent, expectedPresent,
+                    desiredPresent - expectedPresent,
+                    systemTime(CLOCK_MONOTONIC));
+            return PRESENT_LATER;
+        }
+
+        BQ_LOGV("acquireBuffer: accept desire=%" PRId64 " expect=%" PRId64 " "
+                "(%" PRId64 ") now=%" PRId64, desiredPresent, expectedPresent,
+                desiredPresent - expectedPresent,
+                systemTime(CLOCK_MONOTONIC));
+    }
+
+    int slot = front->mSlot;
+    *outBuffer = *front;
+    ATRACE_BUFFER_INDEX(slot);
+
+    BQ_LOGV("acquireBuffer: acquiring { slot=%d/%" PRIu64 " buffer=%p }",
+            slot, front->mFrameNumber, front->mGraphicBuffer->handle);
+    // If the front buffer is still being tracked, update its slot state
+    if (mCore->stillTracking(front)) {
+        mSlots[slot].mAcquireCalled = true;
+        mSlots[slot].mNeedsCleanupOnRelease = false;
+        mSlots[slot].mBufferState = BufferSlot::ACQUIRED;
+        mSlots[slot].mFence = Fence::NO_FENCE;
+    }
+
+    // If the buffer has previously been acquired by the consumer, set
+    // mGraphicBuffer to NULL to avoid unnecessarily remapping this buffer
+    // on the consumer side
+    if (outBuffer->mAcquireCalled) {
+        outBuffer->mGraphicBuffer = NULL;
+    }
+
+    mCore->mQueue.erase(front);
+
+    // We might have freed a slot while dropping old buffers, or the producer
+    // may be blocked waiting for the number of buffers in the queue to
+    // decrease.
+    mCore->mDequeueCondition.broadcast();
+
+    ATRACE_INT(mCore->mConsumerName.string(), mCore->mQueue.size());
+
+    return NO_ERROR;
+}
+
+status_t BufferQueueConsumer::detachBuffer(int slot) {
+    ATRACE_CALL();
+    ATRACE_BUFFER_INDEX(slot);
+    BQ_LOGV("detachBuffer(C): slot %d", slot);
+    Mutex::Autolock lock(mCore->mMutex);
+
+    if (mCore->mIsAbandoned) {
+        BQ_LOGE("detachBuffer(C): BufferQueue has been abandoned");
+        return NO_INIT;
+    }
+
+    if (slot < 0 || slot >= BufferQueueDefs::NUM_BUFFER_SLOTS) {
+        BQ_LOGE("detachBuffer(C): slot index %d out of range [0, %d)",
+                slot, BufferQueueDefs::NUM_BUFFER_SLOTS);
+        return BAD_VALUE;
+    } else if (mSlots[slot].mBufferState != BufferSlot::ACQUIRED) {
+        BQ_LOGE("detachBuffer(C): slot %d is not owned by the consumer "
+                "(state = %d)", slot, mSlots[slot].mBufferState);
+        return BAD_VALUE;
+    }
+
+    mCore->freeBufferLocked(slot);
+    mCore->mDequeueCondition.broadcast();
+
+    return NO_ERROR;
+}
+
+status_t BufferQueueConsumer::attachBuffer(int* outSlot,
+        const sp<android::GraphicBuffer>& buffer) {
+    ATRACE_CALL();
+
+    if (outSlot == NULL) {
+        BQ_LOGE("attachBuffer(P): outSlot must not be NULL");
+        return BAD_VALUE;
+    } else if (buffer == NULL) {
+        BQ_LOGE("attachBuffer(P): cannot attach NULL buffer");
+        return BAD_VALUE;
+    }
+
+    Mutex::Autolock lock(mCore->mMutex);
+
+    // Make sure we don't have too many acquired buffers and find a free slot
+    // to put the buffer into (the oldest if there are multiple).
+    int numAcquiredBuffers = 0;
+    int found = BufferQueueCore::INVALID_BUFFER_SLOT;
+    for (int s = 0; s < BufferQueueDefs::NUM_BUFFER_SLOTS; ++s) {
+        if (mSlots[s].mBufferState == BufferSlot::ACQUIRED) {
+            ++numAcquiredBuffers;
+        } else if (mSlots[s].mBufferState == BufferSlot::FREE) {
+            if (found == BufferQueueCore::INVALID_BUFFER_SLOT ||
+                    mSlots[s].mFrameNumber < mSlots[found].mFrameNumber) {
+                found = s;
+            }
+        }
+    }
+
+    if (numAcquiredBuffers >= mCore->mMaxAcquiredBufferCount + 1) {
+        BQ_LOGE("attachBuffer(P): max acquired buffer count reached: %d "
+                "(max %d)", numAcquiredBuffers,
+                mCore->mMaxAcquiredBufferCount);
+        return INVALID_OPERATION;
+    }
+    if (found == BufferQueueCore::INVALID_BUFFER_SLOT) {
+        BQ_LOGE("attachBuffer(P): could not find free buffer slot");
+        return NO_MEMORY;
+    }
+
+    *outSlot = found;
+    ATRACE_BUFFER_INDEX(*outSlot);
+    BQ_LOGV("attachBuffer(C): returning slot %d", *outSlot);
+
+    mSlots[*outSlot].mGraphicBuffer = buffer;
+    mSlots[*outSlot].mBufferState = BufferSlot::ACQUIRED;
+    mSlots[*outSlot].mAttachedByConsumer = true;
+    mSlots[*outSlot].mNeedsCleanupOnRelease = false;
+    mSlots[*outSlot].mFence = Fence::NO_FENCE;
+    mSlots[*outSlot].mFrameNumber = 0;
+
+    // mAcquireCalled tells BufferQueue that it doesn't need to send a valid
+    // GraphicBuffer pointer on the next acquireBuffer call, which decreases
+    // Binder traffic by not un/flattening the GraphicBuffer. However, it
+    // requires that the consumer maintain a cached copy of the slot <--> buffer
+    // mappings, which is why the consumer doesn't need the valid pointer on
+    // acquire.
+    //
+    // The StreamSplitter is one of the primary users of the attach/detach
+    // logic, and while it is running, all buffers it acquires are immediately
+    // detached, and all buffers it eventually releases are ones that were
+    // attached (as opposed to having been obtained from acquireBuffer), so it
+    // doesn't make sense to maintain the slot/buffer mappings, which would
+    // become invalid for every buffer during detach/attach. By setting this to
+    // false, the valid GraphicBuffer pointer will always be sent with acquire
+    // for attached buffers.
+    mSlots[*outSlot].mAcquireCalled = false;
+
+    return NO_ERROR;
+}
+
+status_t BufferQueueConsumer::releaseBuffer(int slot, uint64_t frameNumber,
+        const sp<Fence>& releaseFence, EGLDisplay eglDisplay,
+        EGLSyncKHR eglFence) {
+    ATRACE_CALL();
+    ATRACE_BUFFER_INDEX(slot);
+
+    if (slot < 0 || slot >= BufferQueueDefs::NUM_BUFFER_SLOTS ||
+            releaseFence == NULL) {
+        return BAD_VALUE;
+    }
+
+    sp<IProducerListener> listener;
+    { // Autolock scope
+        Mutex::Autolock lock(mCore->mMutex);
+
+        // If the frame number has changed because the buffer has been reallocated,
+        // we can ignore this releaseBuffer for the old buffer
+        if (frameNumber != mSlots[slot].mFrameNumber) {
+            return STALE_BUFFER_SLOT;
+        }
+
+        // Make sure this buffer hasn't been queued while acquired by the consumer
+        BufferQueueCore::Fifo::iterator current(mCore->mQueue.begin());
+        while (current != mCore->mQueue.end()) {
+            if (current->mSlot == slot) {
+                BQ_LOGE("releaseBuffer: buffer slot %d pending release is "
+                        "currently queued", slot);
+                return BAD_VALUE;
+            }
+            ++current;
+        }
+
+        if (mSlots[slot].mBufferState == BufferSlot::ACQUIRED) {
+            mSlots[slot].mEglDisplay = eglDisplay;
+            mSlots[slot].mEglFence = eglFence;
+            mSlots[slot].mFence = releaseFence;
+            mSlots[slot].mBufferState = BufferSlot::FREE;
+            listener = mCore->mConnectedProducerListener;
+            BQ_LOGV("releaseBuffer: releasing slot %d", slot);
+        } else if (mSlots[slot].mNeedsCleanupOnRelease) {
+            BQ_LOGV("releaseBuffer: releasing a stale buffer slot %d "
+                    "(state = %d)", slot, mSlots[slot].mBufferState);
+            mSlots[slot].mNeedsCleanupOnRelease = false;
+            return STALE_BUFFER_SLOT;
+        } else {
+            BQ_LOGV("releaseBuffer: attempted to release buffer slot %d "
+                    "but its state was %d", slot, mSlots[slot].mBufferState);
+            return BAD_VALUE;
+        }
+
+        mCore->mDequeueCondition.broadcast();
+    } // Autolock scope
+
+    // Call back without lock held
+    if (listener != NULL) {
+        listener->onBufferReleased();
+    }
+
+    return NO_ERROR;
+}
+
+status_t BufferQueueConsumer::connect(
+        const sp<IConsumerListener>& consumerListener, bool controlledByApp) {
+    ATRACE_CALL();
+
+    if (consumerListener == NULL) {
+        BQ_LOGE("connect(C): consumerListener may not be NULL");
+        return BAD_VALUE;
+    }
+
+    BQ_LOGV("connect(C): controlledByApp=%s",
+            controlledByApp ? "true" : "false");
+
+    Mutex::Autolock lock(mCore->mMutex);
+
+    if (mCore->mIsAbandoned) {
+        BQ_LOGE("connect(C): BufferQueue has been abandoned");
+        return NO_INIT;
+    }
+
+    mCore->mConsumerListener = consumerListener;
+    mCore->mConsumerControlledByApp = controlledByApp;
+
+    return NO_ERROR;
+}
+
+status_t BufferQueueConsumer::disconnect() {
+    ATRACE_CALL();
+
+    BQ_LOGV("disconnect(C)");
+
+    Mutex::Autolock lock(mCore->mMutex);
+
+    if (mCore->mConsumerListener == NULL) {
+        BQ_LOGE("disconnect(C): no consumer is connected");
+        return BAD_VALUE;
+    }
+
+    mCore->mIsAbandoned = true;
+    mCore->mConsumerListener = NULL;
+    mCore->mQueue.clear();
+    mCore->freeAllBuffersLocked();
+    mCore->mDequeueCondition.broadcast();
+    return NO_ERROR;
+}
+
+status_t BufferQueueConsumer::getReleasedBuffers(uint64_t *outSlotMask) {
+    ATRACE_CALL();
+
+    if (outSlotMask == NULL) {
+        BQ_LOGE("getReleasedBuffers: outSlotMask may not be NULL");
+        return BAD_VALUE;
+    }
+
+    Mutex::Autolock lock(mCore->mMutex);
+
+    if (mCore->mIsAbandoned) {
+        BQ_LOGE("getReleasedBuffers: BufferQueue has been abandoned");
+        return NO_INIT;
+    }
+
+    uint64_t mask = 0;
+    for (int s = 0; s < BufferQueueDefs::NUM_BUFFER_SLOTS; ++s) {
+        if (!mSlots[s].mAcquireCalled) {
+            mask |= (1ULL << s);
+        }
+    }
+
+    // Remove from the mask queued buffers for which acquire has been called,
+    // since the consumer will not receive their buffer addresses and so must
+    // retain their cached information
+    BufferQueueCore::Fifo::iterator current(mCore->mQueue.begin());
+    while (current != mCore->mQueue.end()) {
+        if (current->mAcquireCalled) {
+            mask &= ~(1ULL << current->mSlot);
+        }
+        ++current;
+    }
+
+    BQ_LOGV("getReleasedBuffers: returning mask %#" PRIx64, mask);
+    *outSlotMask = mask;
+    return NO_ERROR;
+}
+
+status_t BufferQueueConsumer::setDefaultBufferSize(uint32_t width,
+        uint32_t height) {
+    ATRACE_CALL();
+
+    if (width == 0 || height == 0) {
+        BQ_LOGV("setDefaultBufferSize: dimensions cannot be 0 (width=%u "
+                "height=%u)", width, height);
+        return BAD_VALUE;
+    }
+
+    BQ_LOGV("setDefaultBufferSize: width=%u height=%u", width, height);
+
+    Mutex::Autolock lock(mCore->mMutex);
+    mCore->mDefaultWidth = width;
+    mCore->mDefaultHeight = height;
+    return NO_ERROR;
+}
+
+status_t BufferQueueConsumer::setDefaultMaxBufferCount(int bufferCount) {
+    ATRACE_CALL();
+    Mutex::Autolock lock(mCore->mMutex);
+    return mCore->setDefaultMaxBufferCountLocked(bufferCount);
+}
+
+status_t BufferQueueConsumer::disableAsyncBuffer() {
+    ATRACE_CALL();
+
+    Mutex::Autolock lock(mCore->mMutex);
+
+    if (mCore->mConsumerListener != NULL) {
+        BQ_LOGE("disableAsyncBuffer: consumer already connected");
+        return INVALID_OPERATION;
+    }
+
+    BQ_LOGV("disableAsyncBuffer");
+    mCore->mUseAsyncBuffer = false;
+    return NO_ERROR;
+}
+
+status_t BufferQueueConsumer::setMaxAcquiredBufferCount(
+        int maxAcquiredBuffers) {
+    ATRACE_CALL();
+
+    if (maxAcquiredBuffers < 1 ||
+            maxAcquiredBuffers > BufferQueueCore::MAX_MAX_ACQUIRED_BUFFERS) {
+        BQ_LOGE("setMaxAcquiredBufferCount: invalid count %d",
+                maxAcquiredBuffers);
+        return BAD_VALUE;
+    }
+
+    Mutex::Autolock lock(mCore->mMutex);
+
+    if (mCore->mConnectedApi != BufferQueueCore::NO_CONNECTED_API) {
+        BQ_LOGE("setMaxAcquiredBufferCount: producer is already connected");
+        return INVALID_OPERATION;
+    }
+
+    BQ_LOGV("setMaxAcquiredBufferCount: %d", maxAcquiredBuffers);
+    mCore->mMaxAcquiredBufferCount = maxAcquiredBuffers;
+    return NO_ERROR;
+}
+
+void BufferQueueConsumer::setConsumerName(const String8& name) {
+    ATRACE_CALL();
+    BQ_LOGV("setConsumerName: '%s'", name.string());
+    Mutex::Autolock lock(mCore->mMutex);
+    mCore->mConsumerName = name;
+    mConsumerName = name;
+}
+
+status_t BufferQueueConsumer::setDefaultBufferFormat(uint32_t defaultFormat) {
+    ATRACE_CALL();
+    BQ_LOGV("setDefaultBufferFormat: %u", defaultFormat);
+    Mutex::Autolock lock(mCore->mMutex);
+    mCore->mDefaultBufferFormat = defaultFormat;
+    return NO_ERROR;
+}
+
+status_t BufferQueueConsumer::setConsumerUsageBits(uint32_t usage) {
+    ATRACE_CALL();
+    BQ_LOGV("setConsumerUsageBits: %#x", usage);
+    Mutex::Autolock lock(mCore->mMutex);
+    mCore->mConsumerUsageBits = usage;
+    return NO_ERROR;
+}
+
+status_t BufferQueueConsumer::setTransformHint(uint32_t hint) {
+    ATRACE_CALL();
+    BQ_LOGV("setTransformHint: %#x", hint);
+    Mutex::Autolock lock(mCore->mMutex);
+    mCore->mTransformHint = hint;
+    return NO_ERROR;
+}
+
+sp<NativeHandle> BufferQueueConsumer::getSidebandStream() const {
+    return mCore->mSidebandStream;
+}
+
+void BufferQueueConsumer::dump(String8& result, const char* prefix) const {
+    mCore->dump(result, prefix);
+}
+
+} // namespace android
new file mode 100644
--- /dev/null
+++ b/widget/gonk/nativewindow/GonkBufferQueueLL/BufferQueueConsumer.h
@@ -0,0 +1,181 @@
+/*
+ * Copyright 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_GUI_BUFFERQUEUECONSUMER_H
+#define ANDROID_GUI_BUFFERQUEUECONSUMER_H
+
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
+
+#include <gui/BufferQueueDefs.h>
+#include <gui/IGraphicBufferConsumer.h>
+
+namespace android {
+
+class BufferQueueCore;
+
+class BufferQueueConsumer : public BnGraphicBufferConsumer {
+
+public:
+    BufferQueueConsumer(const sp<BufferQueueCore>& core);
+    virtual ~BufferQueueConsumer();
+
+    // acquireBuffer attempts to acquire ownership of the next pending buffer in
+    // the BufferQueue. If no buffer is pending then it returns
+    // NO_BUFFER_AVAILABLE. If a buffer is successfully acquired, the
+    // information about the buffer is returned in BufferItem.  If the buffer
+    // returned had previously been acquired then the BufferItem::mGraphicBuffer
+    // field of buffer is set to NULL and it is assumed that the consumer still
+    // holds a reference to the buffer.
+    //
+    // If expectedPresent is nonzero, it indicates the time when the buffer
+    // will be displayed on screen. If the buffer's timestamp is farther in the
+    // future, the buffer won't be acquired, and PRESENT_LATER will be
+    // returned.  The presentation time is in nanoseconds, and the time base
+    // is CLOCK_MONOTONIC.
+    virtual status_t acquireBuffer(BufferItem* outBuffer,
+            nsecs_t expectedPresent);
+
+    // See IGraphicBufferConsumer::detachBuffer
+    virtual status_t detachBuffer(int slot);
+
+    // See IGraphicBufferConsumer::attachBuffer
+    virtual status_t attachBuffer(int* slot, const sp<GraphicBuffer>& buffer);
+
+    // releaseBuffer releases a buffer slot from the consumer back to the
+    // BufferQueue.  This may be done while the buffer's contents are still
+    // being accessed.  The fence will signal when the buffer is no longer
+    // in use. frameNumber is used to indentify the exact buffer returned.
+    //
+    // If releaseBuffer returns STALE_BUFFER_SLOT, then the consumer must free
+    // any references to the just-released buffer that it might have, as if it
+    // had received a onBuffersReleased() call with a mask set for the released
+    // buffer.
+    //
+    // Note that the dependencies on EGL will be removed once we switch to using
+    // the Android HW Sync HAL.
+    virtual status_t releaseBuffer(int slot, uint64_t frameNumber,
+            const sp<Fence>& releaseFence, EGLDisplay display,
+            EGLSyncKHR fence);
+
+    // connect connects a consumer to the BufferQueue.  Only one
+    // consumer may be connected, and when that consumer disconnects the
+    // BufferQueue is placed into the "abandoned" state, causing most
+    // interactions with the BufferQueue by the producer to fail.
+    // controlledByApp indicates whether the consumer is controlled by
+    // the application.
+    //
+    // consumerListener may not be NULL.
+    virtual status_t connect(const sp<IConsumerListener>& consumerListener,
+            bool controlledByApp);
+
+    // disconnect disconnects a consumer from the BufferQueue. All
+    // buffers will be freed and the BufferQueue is placed in the "abandoned"
+    // state, causing most interactions with the BufferQueue by the producer to
+    // fail.
+    virtual status_t disconnect();
+
+    // getReleasedBuffers sets the value pointed to by outSlotMask to a bit mask
+    // indicating which buffer slots have been released by the BufferQueue
+    // but have not yet been released by the consumer.
+    //
+    // This should be called from the onBuffersReleased() callback.
+    virtual status_t getReleasedBuffers(uint64_t* outSlotMask);
+
+    // setDefaultBufferSize is used to set the size of buffers returned by
+    // dequeueBuffer when a width and height of zero is requested.  Default
+    // is 1x1.
+    virtual status_t setDefaultBufferSize(uint32_t width, uint32_t height);
+
+    // setDefaultMaxBufferCount sets the default value for the maximum buffer
+    // count (the initial default is 2). If the producer has requested a
+    // buffer count using setBufferCount, the default buffer count will only
+    // take effect if the producer sets the count back to zero.
+    //
+    // The count must be between 2 and NUM_BUFFER_SLOTS, inclusive.
+    virtual status_t setDefaultMaxBufferCount(int bufferCount);
+
+    // disableAsyncBuffer disables the extra buffer used in async mode
+    // (when both producer and consumer have set their "isControlledByApp"
+    // flag) and has dequeueBuffer() return WOULD_BLOCK instead.
+    //
+    // This can only be called before connect().
+    virtual status_t disableAsyncBuffer();
+
+    // setMaxAcquiredBufferCount sets the maximum number of buffers that can
+    // be acquired by the consumer at one time (default 1).  This call will
+    // fail if a producer is connected to the BufferQueue.
+    virtual status_t setMaxAcquiredBufferCount(int maxAcquiredBuffers);
+
+    // setConsumerName sets the name used in logging
+    virtual void setConsumerName(const String8& name);
+
+    // setDefaultBufferFormat allows the BufferQueue to create
+    // GraphicBuffers of a defaultFormat if no format is specified
+    // in dequeueBuffer.  Formats are enumerated in graphics.h; the
+    // initial default is HAL_PIXEL_FORMAT_RGBA_8888.
+    virtual status_t setDefaultBufferFormat(uint32_t defaultFormat);
+
+    // setConsumerUsageBits will turn on additional usage bits for dequeueBuffer.
+    // These are merged with the bits passed to dequeueBuffer.  The values are
+    // enumerated in gralloc.h, e.g. GRALLOC_USAGE_HW_RENDER; the default is 0.
+    virtual status_t setConsumerUsageBits(uint32_t usage);
+
+    // setTransformHint bakes in rotation to buffers so overlays can be used.
+    // The values are enumerated in window.h, e.g.
+    // NATIVE_WINDOW_TRANSFORM_ROT_90.  The default is 0 (no transform).
+    virtual status_t setTransformHint(uint32_t hint);
+
+    // Retrieve the sideband buffer stream, if any.
+    virtual sp<NativeHandle> getSidebandStream() const;
+
+    // dump our state in a String
+    virtual void dump(String8& result, const char* prefix) const;
+
+    // Functions required for backwards compatibility.
+    // These will be modified/renamed in IGraphicBufferConsumer and will be
+    // removed from this class at that time. See b/13306289.
+
+    virtual status_t releaseBuffer(int buf, uint64_t frameNumber,
+            EGLDisplay display, EGLSyncKHR fence,
+            const sp<Fence>& releaseFence) {
+        return releaseBuffer(buf, frameNumber, releaseFence, display, fence);
+    }
+
+    virtual status_t consumerConnect(const sp<IConsumerListener>& consumer,
+            bool controlledByApp) {
+        return connect(consumer, controlledByApp);
+    }
+
+    virtual status_t consumerDisconnect() { return disconnect(); }
+
+    // End functions required for backwards compatibility
+
+private:
+    sp<BufferQueueCore> mCore;
+
+    // This references mCore->mSlots. Lock mCore->mMutex while accessing.
+    BufferQueueDefs::SlotsType& mSlots;
+
+    // This is a cached copy of the name stored in the BufferQueueCore.
+    // It's updated during setConsumerName.
+    String8 mConsumerName;
+
+}; // class BufferQueueConsumer
+
+} // namespace android
+
+#endif
new file mode 100644
--- /dev/null
+++ b/widget/gonk/nativewindow/GonkBufferQueueLL/BufferQueueCore.cpp
@@ -0,0 +1,238 @@
+/*
+ * Copyright 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "BufferQueueCore"
+#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+//#define LOG_NDEBUG 0
+
+#define EGL_EGLEXT_PROTOTYPES
+
+#include <inttypes.h>
+
+#include <gui/BufferItem.h>
+#include <gui/BufferQueueCore.h>
+#include <gui/IConsumerListener.h>
+#include <gui/IGraphicBufferAlloc.h>
+#include <gui/IProducerListener.h>
+#include <gui/ISurfaceComposer.h>
+#include <private/gui/ComposerService.h>
+
+template <typename T>
+static inline T max(T a, T b) { return a > b ? a : b; }
+
+namespace android {
+
+static String8 getUniqueName() {
+    static volatile int32_t counter = 0;
+    return String8::format("unnamed-%d-%d", getpid(),
+            android_atomic_inc(&counter));
+}
+
+BufferQueueCore::BufferQueueCore(const sp<IGraphicBufferAlloc>& allocator) :
+    mAllocator(allocator),
+    mMutex(),
+    mIsAbandoned(false),
+    mConsumerControlledByApp(false),
+    mConsumerName(getUniqueName()),
+    mConsumerListener(),
+    mConsumerUsageBits(0),
+    mConnectedApi(NO_CONNECTED_API),
+    mConnectedProducerListener(),
+    mSlots(),
+    mQueue(),
+    mOverrideMaxBufferCount(0),
+    mDequeueCondition(),
+    mUseAsyncBuffer(true),
+    mDequeueBufferCannotBlock(false),
+    mDefaultBufferFormat(PIXEL_FORMAT_RGBA_8888),
+    mDefaultWidth(1),
+    mDefaultHeight(1),
+    mDefaultMaxBufferCount(2),
+    mMaxAcquiredBufferCount(1),
+    mBufferHasBeenQueued(false),
+    mFrameCounter(0),
+    mTransformHint(0),
+    mIsAllocating(false),
+    mIsAllocatingCondition()
+{
+    if (allocator == NULL) {
+        sp<ISurfaceComposer> composer(ComposerService::getComposerService());
+        mAllocator = composer->createGraphicBufferAlloc();
+        if (mAllocator == NULL) {
+            BQ_LOGE("createGraphicBufferAlloc failed");
+        }
+    }
+}
+
+BufferQueueCore::~BufferQueueCore() {}
+
+void BufferQueueCore::dump(String8& result, const char* prefix) const {
+    Mutex::Autolock lock(mMutex);
+
+    String8 fifo;
+    Fifo::const_iterator current(mQueue.begin());
+    while (current != mQueue.end()) {
+        fifo.appendFormat("%02d:%p crop=[%d,%d,%d,%d], "
+                "xform=0x%02x, time=%#" PRIx64 ", scale=%s\n",
+                current->mSlot, current->mGraphicBuffer.get(),
+                current->mCrop.left, current->mCrop.top, current->mCrop.right,
+                current->mCrop.bottom, current->mTransform, current->mTimestamp,
+                BufferItem::scalingModeName(current->mScalingMode));
+        ++current;
+    }
+
+    result.appendFormat("%s-BufferQueue mMaxAcquiredBufferCount=%d, "
+            "mDequeueBufferCannotBlock=%d, default-size=[%dx%d], "
+            "default-format=%d, transform-hint=%02x, FIFO(%zu)={%s}\n",
+            prefix, mMaxAcquiredBufferCount, mDequeueBufferCannotBlock,
+            mDefaultWidth, mDefaultHeight, mDefaultBufferFormat, mTransformHint,
+            mQueue.size(), fifo.string());
+
+    // Trim the free buffers so as to not spam the dump
+    int maxBufferCount = 0;
+    for (int s = BufferQueueDefs::NUM_BUFFER_SLOTS - 1; s >= 0; --s) {
+        const BufferSlot& slot(mSlots[s]);
+        if (slot.mBufferState != BufferSlot::FREE ||
+                slot.mGraphicBuffer != NULL) {
+            maxBufferCount = s + 1;
+            break;
+        }
+    }
+
+    for (int s = 0; s < maxBufferCount; ++s) {
+        const BufferSlot& slot(mSlots[s]);
+        const sp<GraphicBuffer>& buffer(slot.mGraphicBuffer);
+        result.appendFormat("%s%s[%02d:%p] state=%-8s", prefix,
+                (slot.mBufferState == BufferSlot::ACQUIRED) ? ">" : " ",
+                s, buffer.get(),
+                BufferSlot::bufferStateName(slot.mBufferState));
+
+        if (buffer != NULL) {
+            result.appendFormat(", %p [%4ux%4u:%4u,%3X]", buffer->handle,
+                    buffer->width, buffer->height, buffer->stride,
+                    buffer->format);
+        }
+
+        result.append("\n");
+    }
+}
+
+int BufferQueueCore::getMinUndequeuedBufferCountLocked(bool async) const {
+    // If dequeueBuffer is allowed to error out, we don't have to add an
+    // extra buffer.
+    if (!mUseAsyncBuffer) {
+        return mMaxAcquiredBufferCount;
+    }
+
+    if (mDequeueBufferCannotBlock || async) {
+        return mMaxAcquiredBufferCount + 1;
+    }
+
+    return mMaxAcquiredBufferCount;
+}
+
+int BufferQueueCore::getMinMaxBufferCountLocked(bool async) const {
+    return getMinUndequeuedBufferCountLocked(async) + 1;
+}
+
+int BufferQueueCore::getMaxBufferCountLocked(bool async) const {
+    int minMaxBufferCount = getMinMaxBufferCountLocked(async);
+
+    int maxBufferCount = max(mDefaultMaxBufferCount, minMaxBufferCount);
+    if (mOverrideMaxBufferCount != 0) {
+        assert(mOverrideMaxBufferCount >= minMaxBufferCount);
+        maxBufferCount = mOverrideMaxBufferCount;
+    }
+
+    // Any buffers that are dequeued by the producer or sitting in the queue
+    // waiting to be consumed need to have their slots preserved. Such buffers
+    // will temporarily keep the max buffer count up until the slots no longer
+    // need to be preserved.
+    for (int s = maxBufferCount; s < BufferQueueDefs::NUM_BUFFER_SLOTS; ++s) {
+        BufferSlot::BufferState state = mSlots[s].mBufferState;
+        if (state == BufferSlot::QUEUED || state == BufferSlot::DEQUEUED) {
+            maxBufferCount = s + 1;
+        }
+    }
+
+    return maxBufferCount;
+}
+
+status_t BufferQueueCore::setDefaultMaxBufferCountLocked(int count) {
+    const int minBufferCount = mUseAsyncBuffer ? 2 : 1;
+    if (count < minBufferCount || count > BufferQueueDefs::NUM_BUFFER_SLOTS) {
+        BQ_LOGV("setDefaultMaxBufferCount: invalid count %d, should be in "
+                "[%d, %d]",
+                count, minBufferCount, BufferQueueDefs::NUM_BUFFER_SLOTS);
+        return BAD_VALUE;
+    }
+
+    BQ_LOGV("setDefaultMaxBufferCount: setting count to %d", count);
+    mDefaultMaxBufferCount = count;
+    mDequeueCondition.broadcast();
+
+    return NO_ERROR;
+}
+
+void BufferQueueCore::freeBufferLocked(int slot) {
+    BQ_LOGV("freeBufferLocked: slot %d", slot);
+    mSlots[slot].mGraphicBuffer.clear();
+    if (mSlots[slot].mBufferState == BufferSlot::ACQUIRED) {
+        mSlots[slot].mNeedsCleanupOnRelease = true;
+    }
+    mSlots[slot].mBufferState = BufferSlot::FREE;
+    mSlots[slot].mFrameNumber = UINT32_MAX;
+    mSlots[slot].mAcquireCalled = false;
+
+    // Destroy fence as BufferQueue now takes ownership
+    if (mSlots[slot].mEglFence != EGL_NO_SYNC_KHR) {
+        eglDestroySyncKHR(mSlots[slot].mEglDisplay, mSlots[slot].mEglFence);
+        mSlots[slot].mEglFence = EGL_NO_SYNC_KHR;
+    }
+    mSlots[slot].mFence = Fence::NO_FENCE;
+}
+
+void BufferQueueCore::freeAllBuffersLocked() {
+    mBufferHasBeenQueued = false;
+    for (int s = 0; s < BufferQueueDefs::NUM_BUFFER_SLOTS; ++s) {
+        freeBufferLocked(s);
+    }
+}
+
+bool BufferQueueCore::stillTracking(const BufferItem* item) const {
+    const BufferSlot& slot = mSlots[item->mSlot];
+
+    BQ_LOGV("stillTracking: item { slot=%d/%" PRIu64 " buffer=%p } "
+            "slot { slot=%d/%" PRIu64 " buffer=%p }",
+            item->mSlot, item->mFrameNumber,
+            (item->mGraphicBuffer.get() ? item->mGraphicBuffer->handle : 0),
+            item->mSlot, slot.mFrameNumber,
+            (slot.mGraphicBuffer.get() ? slot.mGraphicBuffer->handle : 0));
+
+    // Compare item with its original buffer slot. We can check the slot as
+    // the buffer would not be moved to a different slot by the producer.
+    return (slot.mGraphicBuffer != NULL) &&
+           (item->mGraphicBuffer->handle == slot.mGraphicBuffer->handle);
+}
+
+void BufferQueueCore::waitWhileAllocatingLocked() const {
+    ATRACE_CALL();
+    while (mIsAllocating) {
+        mIsAllocatingCondition.wait(mMutex);
+    }
+}
+
+} // namespace android
new file mode 100644
--- /dev/null
+++ b/widget/gonk/nativewindow/GonkBufferQueueLL/BufferQueueCore.h
@@ -0,0 +1,253 @@
+/*
+ * Copyright 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_GUI_BUFFERQUEUECORE_H
+#define ANDROID_GUI_BUFFERQUEUECORE_H
+
+#include <gui/BufferQueueDefs.h>
+#include <gui/BufferSlot.h>
+
+#include <utils/Condition.h>
+#include <utils/Mutex.h>
+#include <utils/NativeHandle.h>
+#include <utils/RefBase.h>
+#include <utils/String8.h>
+#include <utils/StrongPointer.h>
+#include <utils/Trace.h>
+#include <utils/Vector.h>
+
+#define BQ_LOGV(x, ...) ALOGV("[%s] "x, mConsumerName.string(), ##__VA_ARGS__)
+#define BQ_LOGD(x, ...) ALOGD("[%s] "x, mConsumerName.string(), ##__VA_ARGS__)
+#define BQ_LOGI(x, ...) ALOGI("[%s] "x, mConsumerName.string(), ##__VA_ARGS__)
+#define BQ_LOGW(x, ...) ALOGW("[%s] "x, mConsumerName.string(), ##__VA_ARGS__)
+#define BQ_LOGE(x, ...) ALOGE("[%s] "x, mConsumerName.string(), ##__VA_ARGS__)
+
+#define ATRACE_BUFFER_INDEX(index)                                   \
+    if (ATRACE_ENABLED()) {                                          \
+        char ___traceBuf[1024];                                      \
+        snprintf(___traceBuf, 1024, "%s: %d",                        \
+                mCore->mConsumerName.string(), (index));             \
+        android::ScopedTrace ___bufTracer(ATRACE_TAG, ___traceBuf);  \
+    }
+
+namespace android {
+
+class BufferItem;
+class IConsumerListener;
+class IGraphicBufferAlloc;
+class IProducerListener;
+
+class BufferQueueCore : public virtual RefBase {
+
+    friend class BufferQueueProducer;
+    friend class BufferQueueConsumer;
+
+public:
+    // Used as a placeholder slot number when the value isn't pointing to an
+    // existing buffer.
+    enum { INVALID_BUFFER_SLOT = -1 }; // TODO: Extract from IGBC::BufferItem
+
+    // We reserve two slots in order to guarantee that the producer and
+    // consumer can run asynchronously.
+    enum { MAX_MAX_ACQUIRED_BUFFERS = BufferQueueDefs::NUM_BUFFER_SLOTS - 2 };
+
+    // The default API number used to indicate that no producer is connected
+    enum { NO_CONNECTED_API = 0 };
+
+    typedef Vector<BufferItem> Fifo;
+
+    // BufferQueueCore manages a pool of gralloc memory slots to be used by
+    // producers and consumers. allocator is used to allocate all the needed
+    // gralloc buffers.
+    BufferQueueCore(const sp<IGraphicBufferAlloc>& allocator = NULL);
+    virtual ~BufferQueueCore();
+
+private:
+    // Dump our state in a string
+    void dump(String8& result, const char* prefix) const;
+
+    // getMinUndequeuedBufferCountLocked returns the minimum number of buffers
+    // that must remain in a state other than DEQUEUED. The async parameter
+    // tells whether we're in asynchronous mode.
+    int getMinUndequeuedBufferCountLocked(bool async) const;
+
+    // getMinMaxBufferCountLocked returns the minimum number of buffers allowed
+    // given the current BufferQueue state. The async parameter tells whether
+    // we're in asynchonous mode.
+    int getMinMaxBufferCountLocked(bool async) const;
+
+    // getMaxBufferCountLocked returns the maximum number of buffers that can be
+    // allocated at once. This value depends on the following member variables:
+    //
+    //     mDequeueBufferCannotBlock
+    //     mMaxAcquiredBufferCount
+    //     mDefaultMaxBufferCount
+    //     mOverrideMaxBufferCount
+    //     async parameter
+    //
+    // Any time one of these member variables is changed while a producer is
+    // connected, mDequeueCondition must be broadcast.
+    int getMaxBufferCountLocked(bool async) const;
+
+    // setDefaultMaxBufferCountLocked sets the maximum number of buffer slots
+    // that will be used if the producer does not override the buffer slot
+    // count. The count must be between 2 and NUM_BUFFER_SLOTS, inclusive. The
+    // initial default is 2.
+    status_t setDefaultMaxBufferCountLocked(int count);
+
+    // freeBufferLocked frees the GraphicBuffer and sync resources for the
+    // given slot.
+    void freeBufferLocked(int slot);
+
+    // freeAllBuffersLocked frees the GraphicBuffer and sync resources for
+    // all slots.
+    void freeAllBuffersLocked();
+
+    // stillTracking returns true iff the buffer item is still being tracked
+    // in one of the slots.
+    bool stillTracking(const BufferItem* item) const;
+
+    // waitWhileAllocatingLocked blocks until mIsAllocating is false.
+    void waitWhileAllocatingLocked() const;
+
+    // mAllocator is the connection to SurfaceFlinger that is used to allocate
+    // new GraphicBuffer objects.
+    sp<IGraphicBufferAlloc> mAllocator;
+
+    // mMutex is the mutex used to prevent concurrent access to the member
+    // variables of BufferQueueCore objects. It must be locked whenever any
+    // member variable is accessed.
+    mutable Mutex mMutex;
+
+    // mIsAbandoned indicates that the BufferQueue will no longer be used to
+    // consume image buffers pushed to it using the IGraphicBufferProducer
+    // interface. It is initialized to false, and set to true in the
+    // consumerDisconnect method. A BufferQueue that is abandoned will return
+    // the NO_INIT error from all IGraphicBufferProducer methods capable of
+    // returning an error.
+    bool mIsAbandoned;
+
+    // mConsumerControlledByApp indicates whether the connected consumer is
+    // controlled by the application.
+    bool mConsumerControlledByApp;
+
+    // mConsumerName is a string used to identify the BufferQueue in log
+    // messages. It is set by the IGraphicBufferConsumer::setConsumerName
+    // method.
+    String8 mConsumerName;
+
+    // mConsumerListener is used to notify the connected consumer of
+    // asynchronous events that it may wish to react to. It is initially
+    // set to NULL and is written by consumerConnect and consumerDisconnect.
+    sp<IConsumerListener> mConsumerListener;
+
+    // mConsumerUsageBits contains flags that the consumer wants for
+    // GraphicBuffers.
+    uint32_t mConsumerUsageBits;
+
+    // mConnectedApi indicates the producer API that is currently connected
+    // to this BufferQueue. It defaults to NO_CONNECTED_API, and gets updated
+    // by the connect and disconnect methods.
+    int mConnectedApi;
+
+    // mConnectedProducerToken is used to set a binder death notification on
+    // the producer.
+    sp<IProducerListener> mConnectedProducerListener;
+
+    // mSlots is an array of buffer slots that must be mirrored on the producer
+    // side. This allows buffer ownership to be transferred between the producer
+    // and consumer without sending a GraphicBuffer over Binder. The entire
+    // array is initialized to NULL at construction time, and buffers are
+    // allocated for a slot when requestBuffer is called with that slot's index.
+    BufferQueueDefs::SlotsType mSlots;
+
+    // mQueue is a FIFO of queued buffers used in synchronous mode.
+    Fifo mQueue;
+
+    // mOverrideMaxBufferCount is the limit on the number of buffers that will
+    // be allocated at one time. This value is set by the producer by calling
+    // setBufferCount. The default is 0, which means that the producer doesn't
+    // care about the number of buffers in the pool. In that case,
+    // mDefaultMaxBufferCount is used as the limit.
+    int mOverrideMaxBufferCount;
+
+    // mDequeueCondition is a condition variable used for dequeueBuffer in
+    // synchronous mode.
+    mutable Condition mDequeueCondition;
+
+    // mUseAsyncBuffer indicates whether an extra buffer is used in async mode
+    // to prevent dequeueBuffer from blocking.
+    bool mUseAsyncBuffer;
+
+    // mDequeueBufferCannotBlock indicates whether dequeueBuffer is allowed to
+    // block. This flag is set during connect when both the producer and
+    // consumer are controlled by the application.
+    bool mDequeueBufferCannotBlock;
+
+    // mDefaultBufferFormat can be set so it will override the buffer format
+    // when it isn't specified in dequeueBuffer.
+    uint32_t mDefaultBufferFormat;
+
+    // mDefaultWidth holds the default width of allocated buffers. It is used
+    // in dequeueBuffer if a width and height of 0 are specified.
+    int mDefaultWidth;
+
+    // mDefaultHeight holds the default height of allocated buffers. It is used
+    // in dequeueBuffer if a width and height of 0 are specified.
+    int mDefaultHeight;
+
+    // mDefaultMaxBufferCount is the default limit on the number of buffers that
+    // will be allocated at one time. This default limit is set by the consumer.
+    // The limit (as opposed to the default limit) may be overriden by the
+    // producer.
+    int mDefaultMaxBufferCount;
+
+    // mMaxAcquiredBufferCount is the number of buffers that the consumer may
+    // acquire at one time. It defaults to 1, and can be changed by the consumer
+    // via setMaxAcquiredBufferCount, but this may only be done while no
+    // producer is connected to the BufferQueue. This value is used to derive
+    // the value returned for the MIN_UNDEQUEUED_BUFFERS query to the producer.
+    int mMaxAcquiredBufferCount;
+
+    // mBufferHasBeenQueued is true once a buffer has been queued. It is reset
+    // when something causes all buffers to be freed (e.g., changing the buffer
+    // count).
+    bool mBufferHasBeenQueued;
+
+    // mFrameCounter is the free running counter, incremented on every
+    // successful queueBuffer call and buffer allocation.
+    uint64_t mFrameCounter;
+
+    // mTransformHint is used to optimize for screen rotations.
+    uint32_t mTransformHint;
+
+    // mSidebandStream is a handle to the sideband buffer stream, if any
+    sp<NativeHandle> mSidebandStream;
+
+    // mIsAllocating indicates whether a producer is currently trying to allocate buffers (which
+    // releases mMutex while doing the allocation proper). Producers should not modify any of the
+    // FREE slots while this is true. mIsAllocatingCondition is signaled when this value changes to
+    // false.
+    bool mIsAllocating;
+
+    // mIsAllocatingCondition is a condition variable used by producers to wait until mIsAllocating
+    // becomes false.
+    mutable Condition mIsAllocatingCondition;
+}; // class BufferQueueCore
+
+} // namespace android
+
+#endif
new file mode 100644
--- /dev/null
+++ b/widget/gonk/nativewindow/GonkBufferQueueLL/BufferQueueDefs.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_GUI_BUFFERQUEUECOREDEFS_H
+#define ANDROID_GUI_BUFFERQUEUECOREDEFS_H
+
+#include <gui/BufferSlot.h>
+
+namespace android {
+    class BufferQueueCore;
+
+    namespace BufferQueueDefs {
+        // BufferQueue will keep track of at most this value of buffers.
+        // Attempts at runtime to increase the number of buffers past this
+        // will fail.
+        enum { NUM_BUFFER_SLOTS = 64 };
+
+        typedef BufferSlot SlotsType[NUM_BUFFER_SLOTS];
+    } // namespace BufferQueueDefs
+} // namespace android
+
+#endif
new file mode 100644
--- /dev/null
+++ b/widget/gonk/nativewindow/GonkBufferQueueLL/BufferQueueProducer.cpp
@@ -0,0 +1,982 @@
+/*
+ * Copyright 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <inttypes.h>
+
+#define LOG_TAG "BufferQueueProducer"
+#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+//#define LOG_NDEBUG 0
+
+#define EGL_EGLEXT_PROTOTYPES
+
+#include <gui/BufferItem.h>
+#include <gui/BufferQueueCore.h>
+#include <gui/BufferQueueProducer.h>
+#include <gui/IConsumerListener.h>
+#include <gui/IGraphicBufferAlloc.h>
+#include <gui/IProducerListener.h>
+
+#include <utils/Log.h>
+#include <utils/Trace.h>
+
+namespace android {
+
+BufferQueueProducer::BufferQueueProducer(const sp<BufferQueueCore>& core) :
+    mCore(core),
+    mSlots(core->mSlots),
+    mConsumerName(),
+    mStickyTransform(0) {}
+
+BufferQueueProducer::~BufferQueueProducer() {}
+
+status_t BufferQueueProducer::requestBuffer(int slot, sp<GraphicBuffer>* buf) {
+    ATRACE_CALL();
+    BQ_LOGV("requestBuffer: slot %d", slot);
+    Mutex::Autolock lock(mCore->mMutex);
+
+    if (mCore->mIsAbandoned) {
+        BQ_LOGE("requestBuffer: BufferQueue has been abandoned");
+        return NO_INIT;
+    }
+
+    if (slot < 0 || slot >= BufferQueueDefs::NUM_BUFFER_SLOTS) {
+        BQ_LOGE("requestBuffer: slot index %d out of range [0, %d)",
+                slot, BufferQueueDefs::NUM_BUFFER_SLOTS);
+        return BAD_VALUE;
+    } else if (mSlots[slot].mBufferState != BufferSlot::DEQUEUED) {
+        BQ_LOGE("requestBuffer: slot %d is not owned by the producer "
+                "(state = %d)", slot, mSlots[slot].mBufferState);
+        return BAD_VALUE;
+    }
+
+    mSlots[slot].mRequestBufferCalled = true;
+    *buf = mSlots[slot].mGraphicBuffer;
+    return NO_ERROR;
+}
+
+status_t BufferQueueProducer::setBufferCount(int bufferCount) {
+    ATRACE_CALL();
+    BQ_LOGV("setBufferCount: count = %d", bufferCount);
+
+    sp<IConsumerListener> listener;
+    { // Autolock scope
+        Mutex::Autolock lock(mCore->mMutex);
+        mCore->waitWhileAllocatingLocked();
+
+        if (mCore->mIsAbandoned) {
+            BQ_LOGE("setBufferCount: BufferQueue has been abandoned");
+            return NO_INIT;
+        }
+
+        if (bufferCount > BufferQueueDefs::NUM_BUFFER_SLOTS) {
+            BQ_LOGE("setBufferCount: bufferCount %d too large (max %d)",
+                    bufferCount, BufferQueueDefs::NUM_BUFFER_SLOTS);
+            return BAD_VALUE;
+        }
+
+        // There must be no dequeued buffers when changing the buffer count.
+        for (int s = 0; s < BufferQueueDefs::NUM_BUFFER_SLOTS; ++s) {
+            if (mSlots[s].mBufferState == BufferSlot::DEQUEUED) {
+                BQ_LOGE("setBufferCount: buffer owned by producer");
+                return BAD_VALUE;
+            }
+        }
+
+        if (bufferCount == 0) {
+            mCore->mOverrideMaxBufferCount = 0;
+            mCore->mDequeueCondition.broadcast();
+            return NO_ERROR;
+        }
+
+        const int minBufferSlots = mCore->getMinMaxBufferCountLocked(false);
+        if (bufferCount < minBufferSlots) {
+            BQ_LOGE("setBufferCount: requested buffer count %d is less than "
+                    "minimum %d", bufferCount, minBufferSlots);
+            return BAD_VALUE;
+        }
+
+        // Here we are guaranteed that the producer doesn't have any dequeued
+        // buffers and will release all of its buffer references. We don't
+        // clear the queue, however, so that currently queued buffers still
+        // get displayed.
+        mCore->freeAllBuffersLocked();
+        mCore->mOverrideMaxBufferCount = bufferCount;
+        mCore->mDequeueCondition.broadcast();
+        listener = mCore->mConsumerListener;
+    } // Autolock scope
+
+    // Call back without lock held
+    if (listener != NULL) {
+        listener->onBuffersReleased();
+    }
+
+    return NO_ERROR;
+}
+
+status_t BufferQueueProducer::waitForFreeSlotThenRelock(const char* caller,
+        bool async, int* found, status_t* returnFlags) const {
+    bool tryAgain = true;
+    while (tryAgain) {
+        if (mCore->mIsAbandoned) {
+            BQ_LOGE("%s: BufferQueue has been abandoned", caller);
+            return NO_INIT;
+        }
+
+        const int maxBufferCount = mCore->getMaxBufferCountLocked(async);
+        if (async && mCore->mOverrideMaxBufferCount) {
+            // FIXME: Some drivers are manually setting the buffer count
+            // (which they shouldn't), so we do this extra test here to
+            // handle that case. This is TEMPORARY until we get this fixed.
+            if (mCore->mOverrideMaxBufferCount < maxBufferCount) {
+                BQ_LOGE("%s: async mode is invalid with buffer count override",
+                        caller);
+                return BAD_VALUE;
+            }
+        }
+
+        // Free up any buffers that are in slots beyond the max buffer count
+        for (int s = maxBufferCount; s < BufferQueueDefs::NUM_BUFFER_SLOTS; ++s) {
+            assert(mSlots[s].mBufferState == BufferSlot::FREE);
+            if (mSlots[s].mGraphicBuffer != NULL) {
+                mCore->freeBufferLocked(s);
+                *returnFlags |= RELEASE_ALL_BUFFERS;
+            }
+        }
+
+        // Look for a free buffer to give to the client
+        *found = BufferQueueCore::INVALID_BUFFER_SLOT;
+        int dequeuedCount = 0;
+        int acquiredCount = 0;
+        for (int s = 0; s < maxBufferCount; ++s) {
+            switch (mSlots[s].mBufferState) {
+                case BufferSlot::DEQUEUED:
+                    ++dequeuedCount;
+                    break;
+                case BufferSlot::ACQUIRED:
+                    ++acquiredCount;
+                    break;
+                case BufferSlot::FREE:
+                    // We return the oldest of the free buffers to avoid
+                    // stalling the producer if possible, since the consumer
+                    // may still have pending reads of in-flight buffers
+                    if (*found == BufferQueueCore::INVALID_BUFFER_SLOT ||
+                            mSlots[s].mFrameNumber < mSlots[*found].mFrameNumber) {
+                        *found = s;
+                    }
+                    break;
+                default:
+                    break;
+            }
+        }
+
+        // Producers are not allowed to dequeue more than one buffer if they
+        // did not set a buffer count
+        if (!mCore->mOverrideMaxBufferCount && dequeuedCount) {
+            BQ_LOGE("%s: can't dequeue multiple buffers without setting the "
+                    "buffer count", caller);
+            return INVALID_OPERATION;
+        }
+
+        // See whether a buffer has been queued since the last
+        // setBufferCount so we know whether to perform the min undequeued
+        // buffers check below
+        if (mCore->mBufferHasBeenQueued) {
+            // Make sure the producer is not trying to dequeue more buffers
+            // than allowed
+            const int newUndequeuedCount =
+                maxBufferCount - (dequeuedCount + 1);
+            const int minUndequeuedCount =
+                mCore->getMinUndequeuedBufferCountLocked(async);
+            if (newUndequeuedCount < minUndequeuedCount) {
+                BQ_LOGE("%s: min undequeued buffer count (%d) exceeded "
+                        "(dequeued=%d undequeued=%d)",
+                        caller, minUndequeuedCount,
+                        dequeuedCount, newUndequeuedCount);
+                return INVALID_OPERATION;
+            }
+        }
+
+        // If 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.
+        bool tooManyBuffers = mCore->mQueue.size()
+                            > static_cast<size_t>(maxBufferCount);
+        if (tooManyBuffers) {
+            BQ_LOGV("%s: queue size is %zu, waiting", caller,
+                    mCore->mQueue.size());
+        }
+
+        // If no buffer is found, or if the queue has too many buffers
+        // outstanding, wait for a buffer to be acquired or released, or for the
+        // max buffer count to change.
+        tryAgain = (*found == BufferQueueCore::INVALID_BUFFER_SLOT) ||
+                   tooManyBuffers;
+        if (tryAgain) {
+            // Return an error if we're in non-blocking mode (producer and
+            // consumer are controlled by the application).
+            // However, the consumer is allowed to briefly acquire an extra
+            // buffer (which could cause us to have to wait here), which is
+            // okay, since it is only used to implement an atomic acquire +
+            // release (e.g., in GLConsumer::updateTexImage())
+            if (mCore->mDequeueBufferCannotBlock &&
+                    (acquiredCount <= mCore->mMaxAcquiredBufferCount)) {
+                return WOULD_BLOCK;
+            }
+            mCore->mDequeueCondition.wait(mCore->mMutex);
+        }
+    } // while (tryAgain)
+
+    return NO_ERROR;
+}
+
+status_t BufferQueueProducer::dequeueBuffer(int *outSlot,
+        sp<android::Fence> *outFence, bool async,
+        uint32_t width, uint32_t height, uint32_t format, uint32_t usage) {
+    ATRACE_CALL();
+    { // Autolock scope
+        Mutex::Autolock lock(mCore->mMutex);
+        mConsumerName = mCore->mConsumerName;
+    } // Autolock scope
+
+    BQ_LOGV("dequeueBuffer: async=%s w=%u h=%u format=%#x, usage=%#x",
+            async ? "true" : "false", width, height, format, usage);
+
+    if ((width && !height) || (!width && height)) {
+        BQ_LOGE("dequeueBuffer: invalid size: w=%u h=%u", width, height);
+        return BAD_VALUE;
+    }
+
+    status_t returnFlags = NO_ERROR;
+    EGLDisplay eglDisplay = EGL_NO_DISPLAY;
+    EGLSyncKHR eglFence = EGL_NO_SYNC_KHR;
+    bool attachedByConsumer = false;
+
+    { // Autolock scope
+        Mutex::Autolock lock(mCore->mMutex);
+        mCore->waitWhileAllocatingLocked();
+
+        if (format == 0) {
+            format = mCore->mDefaultBufferFormat;
+        }
+
+        // Enable the usage bits the consumer requested
+        usage |= mCore->mConsumerUsageBits;
+
+        int found;
+        status_t status = waitForFreeSlotThenRelock("dequeueBuffer", async,
+                &found, &returnFlags);
+        if (status != NO_ERROR) {
+            return status;
+        }
+
+        // This should not happen
+        if (found == BufferQueueCore::INVALID_BUFFER_SLOT) {
+            BQ_LOGE("dequeueBuffer: no available buffer slots");
+            return -EBUSY;
+        }
+
+        *outSlot = found;
+        ATRACE_BUFFER_INDEX(found);
+
+        attachedByConsumer = mSlots[found].mAttachedByConsumer;
+
+        const bool useDefaultSize = !width && !height;
+        if (useDefaultSize) {
+            width = mCore->mDefaultWidth;
+            height = mCore->mDefaultHeight;
+        }
+
+        mSlots[found].mBufferState = BufferSlot::DEQUEUED;
+
+        const sp<GraphicBuffer>& buffer(mSlots[found].mGraphicBuffer);
+        if ((buffer == NULL) ||
+                (static_cast<uint32_t>(buffer->width) != width) ||
+                (static_cast<uint32_t>(buffer->height) != height) ||
+                (static_cast<uint32_t>(buffer->format) != format) ||
+                ((static_cast<uint32_t>(buffer->usage) & usage) != usage))
+        {
+            mSlots[found].mAcquireCalled = false;
+            mSlots[found].mGraphicBuffer = NULL;
+            mSlots[found].mRequestBufferCalled = false;
+            mSlots[found].mEglDisplay = EGL_NO_DISPLAY;
+            mSlots[found].mEglFence = EGL_NO_SYNC_KHR;
+            mSlots[found].mFence = Fence::NO_FENCE;
+
+            returnFlags |= BUFFER_NEEDS_REALLOCATION;
+        }
+
+        if (CC_UNLIKELY(mSlots[found].mFence == NULL)) {
+            BQ_LOGE("dequeueBuffer: about to return a NULL fence - "
+                    "slot=%d w=%d h=%d format=%u",
+                    found, buffer->width, buffer->height, buffer->format);
+        }
+
+        eglDisplay = mSlots[found].mEglDisplay;
+        eglFence = mSlots[found].mEglFence;
+        *outFence = mSlots[found].mFence;
+        mSlots[found].mEglFence = EGL_NO_SYNC_KHR;
+        mSlots[found].mFence = Fence::NO_FENCE;
+    } // Autolock scope
+
+    if (returnFlags & BUFFER_NEEDS_REALLOCATION) {
+        status_t error;
+        BQ_LOGV("dequeueBuffer: allocating a new buffer for slot %d", *outSlot);
+        sp<GraphicBuffer> graphicBuffer(mCore->mAllocator->createGraphicBuffer(
+                    width, height, format, usage, &error));
+        if (graphicBuffer == NULL) {
+            BQ_LOGE("dequeueBuffer: createGraphicBuffer failed");
+            return error;
+        }
+
+        { // Autolock scope
+            Mutex::Autolock lock(mCore->mMutex);
+
+            if (mCore->mIsAbandoned) {
+                BQ_LOGE("dequeueBuffer: BufferQueue has been abandoned");
+                return NO_INIT;
+            }
+
+            mSlots[*outSlot].mFrameNumber = UINT32_MAX;
+            mSlots[*outSlot].mGraphicBuffer = graphicBuffer;
+        } // Autolock scope
+    }
+
+    if (attachedByConsumer) {
+        returnFlags |= BUFFER_NEEDS_REALLOCATION;
+    }
+
+    if (eglFence != EGL_NO_SYNC_KHR) {
+        EGLint result = eglClientWaitSyncKHR(eglDisplay, eglFence, 0,
+                1000000000);
+        // If something goes wrong, log the error, but return the buffer without
+        // synchronizing access to it. It's too late at this point to abort the
+        // dequeue operation.
+        if (result == EGL_FALSE) {
+            BQ_LOGE("dequeueBuffer: error %#x waiting for fence",
+                    eglGetError());
+        } else if (result == EGL_TIMEOUT_EXPIRED_KHR) {
+            BQ_LOGE("dequeueBuffer: timeout waiting for fence");
+        }
+        eglDestroySyncKHR(eglDisplay, eglFence);
+    }
+
+    BQ_LOGV("dequeueBuffer: returning slot=%d/%" PRIu64 " buf=%p flags=%#x",
+            *outSlot,
+            mSlots[*outSlot].mFrameNumber,
+            mSlots[*outSlot].mGraphicBuffer->handle, returnFlags);
+
+    return returnFlags;
+}
+
+status_t BufferQueueProducer::detachBuffer(int slot) {
+    ATRACE_CALL();
+    ATRACE_BUFFER_INDEX(slot);
+    BQ_LOGV("detachBuffer(P): slot %d", slot);
+    Mutex::Autolock lock(mCore->mMutex);
+
+    if (mCore->mIsAbandoned) {
+        BQ_LOGE("detachBuffer(P): BufferQueue has been abandoned");
+        return NO_INIT;
+    }
+
+    if (slot < 0 || slot >= BufferQueueDefs::NUM_BUFFER_SLOTS) {
+        BQ_LOGE("detachBuffer(P): slot index %d out of range [0, %d)",
+                slot, BufferQueueDefs::NUM_BUFFER_SLOTS);
+        return BAD_VALUE;
+    } else if (mSlots[slot].mBufferState != BufferSlot::DEQUEUED) {
+        BQ_LOGE("detachBuffer(P): slot %d is not owned by the producer "
+                "(state = %d)", slot, mSlots[slot].mBufferState);
+        return BAD_VALUE;
+    } else if (!mSlots[slot].mRequestBufferCalled) {
+        BQ_LOGE("detachBuffer(P): buffer in slot %d has not been requested",
+                slot);
+        return BAD_VALUE;
+    }
+
+    mCore->freeBufferLocked(slot);
+    mCore->mDequeueCondition.broadcast();
+
+    return NO_ERROR;
+}
+
+status_t BufferQueueProducer::detachNextBuffer(sp<GraphicBuffer>* outBuffer,
+        sp<Fence>* outFence) {
+    ATRACE_CALL();
+
+    if (outBuffer == NULL) {
+        BQ_LOGE("detachNextBuffer: outBuffer must not be NULL");
+        return BAD_VALUE;
+    } else if (outFence == NULL) {
+        BQ_LOGE("detachNextBuffer: outFence must not be NULL");
+        return BAD_VALUE;
+    }
+
+    Mutex::Autolock lock(mCore->mMutex);
+    mCore->waitWhileAllocatingLocked();
+
+    if (mCore->mIsAbandoned) {
+        BQ_LOGE("detachNextBuffer: BufferQueue has been abandoned");
+        return NO_INIT;
+    }
+
+    // Find the oldest valid slot
+    int found = BufferQueueCore::INVALID_BUFFER_SLOT;
+    for (int s = 0; s < BufferQueueDefs::NUM_BUFFER_SLOTS; ++s) {
+        if (mSlots[s].mBufferState == BufferSlot::FREE &&
+                mSlots[s].mGraphicBuffer != NULL) {
+            if (found == BufferQueueCore::INVALID_BUFFER_SLOT ||
+                    mSlots[s].mFrameNumber < mSlots[found].mFrameNumber) {
+                found = s;
+            }
+        }
+    }
+
+    if (found == BufferQueueCore::INVALID_BUFFER_SLOT) {
+        return NO_MEMORY;
+    }
+
+    BQ_LOGV("detachNextBuffer detached slot %d", found);
+
+    *outBuffer = mSlots[found].mGraphicBuffer;
+    *outFence = mSlots[found].mFence;
+    mCore->freeBufferLocked(found);
+
+    return NO_ERROR;
+}
+
+status_t BufferQueueProducer::attachBuffer(int* outSlot,
+        const sp<android::GraphicBuffer>& buffer) {
+    ATRACE_CALL();
+
+    if (outSlot == NULL) {
+        BQ_LOGE("attachBuffer(P): outSlot must not be NULL");
+        return BAD_VALUE;
+    } else if (buffer == NULL) {
+        BQ_LOGE("attachBuffer(P): cannot attach NULL buffer");
+        return BAD_VALUE;
+    }
+
+    Mutex::Autolock lock(mCore->mMutex);
+    mCore->waitWhileAllocatingLocked();
+
+    status_t returnFlags = NO_ERROR;
+    int found;
+    // TODO: Should we provide an async flag to attachBuffer? It seems
+    // unlikely that buffers which we are attaching to a BufferQueue will
+    // be asynchronous (droppable), but it may not be impossible.
+    status_t status = waitForFreeSlotThenRelock("attachBuffer(P)", false,
+            &found, &returnFlags);
+    if (status != NO_ERROR) {
+        return status;
+    }
+
+    // This should not happen
+    if (found == BufferQueueCore::INVALID_BUFFER_SLOT) {
+        BQ_LOGE("attachBuffer(P): no available buffer slots");
+        return -EBUSY;
+    }
+
+    *outSlot = found;
+    ATRACE_BUFFER_INDEX(*outSlot);
+    BQ_LOGV("attachBuffer(P): returning slot %d flags=%#x",
+            *outSlot, returnFlags);
+
+    mSlots[*outSlot].mGraphicBuffer = buffer;
+    mSlots[*outSlot].mBufferState = BufferSlot::DEQUEUED;
+    mSlots[*outSlot].mEglFence = EGL_NO_SYNC_KHR;
+    mSlots[*outSlot].mFence = Fence::NO_FENCE;
+    mSlots[*outSlot].mRequestBufferCalled = true;
+
+    return returnFlags;
+}
+
+status_t BufferQueueProducer::queueBuffer(int slot,
+        const QueueBufferInput &input, QueueBufferOutput *output) {
+    ATRACE_CALL();
+    ATRACE_BUFFER_INDEX(slot);
+
+    int64_t timestamp;
+    bool isAutoTimestamp;
+    Rect crop;
+    int scalingMode;
+    uint32_t transform;
+    uint32_t stickyTransform;
+    bool async;
+    sp<Fence> fence;
+    input.deflate(&timestamp, &isAutoTimestamp, &crop, &scalingMode, &transform,
+            &async, &fence, &stickyTransform);
+
+    if (fence == NULL) {
+        BQ_LOGE("queueBuffer: fence is NULL");
+        // Temporary workaround for b/17946343: soldier-on instead of returning an error. This
+        // prevents the client from dying, at the risk of visible corruption due to hwcomposer
+        // reading the buffer before the producer is done rendering it. Unless the buffer is the
+        // last frame of an animation, the corruption will be transient.
+        fence = Fence::NO_FENCE;
+        // return BAD_VALUE;
+    }
+
+    switch (scalingMode) {
+        case NATIVE_WINDOW_SCALING_MODE_FREEZE:
+        case NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW:
+        case NATIVE_WINDOW_SCALING_MODE_SCALE_CROP:
+        case NATIVE_WINDOW_SCALING_MODE_NO_SCALE_CROP:
+            break;
+        default:
+            BQ_LOGE("queueBuffer: unknown scaling mode %d", scalingMode);
+            return BAD_VALUE;
+    }
+
+    sp<IConsumerListener> listener;
+    { // Autolock scope
+        Mutex::Autolock lock(mCore->mMutex);
+
+        if (mCore->mIsAbandoned) {
+            BQ_LOGE("queueBuffer: BufferQueue has been abandoned");
+            return NO_INIT;
+        }
+
+        const int maxBufferCount = mCore->getMaxBufferCountLocked(async);
+        if (async && mCore->mOverrideMaxBufferCount) {
+            // FIXME: Some drivers are manually setting the buffer count
+            // (which they shouldn't), so we do this extra test here to
+            // handle that case. This is TEMPORARY until we get this fixed.
+            if (mCore->mOverrideMaxBufferCount < maxBufferCount) {
+                BQ_LOGE("queueBuffer: async mode is invalid with "
+                        "buffer count override");
+                return BAD_VALUE;
+            }
+        }
+
+        if (slot < 0 || slot >= maxBufferCount) {
+            BQ_LOGE("queueBuffer: slot index %d out of range [0, %d)",
+                    slot, maxBufferCount);
+            return BAD_VALUE;
+        } else if (mSlots[slot].mBufferState != BufferSlot::DEQUEUED) {
+            BQ_LOGE("queueBuffer: slot %d is not owned by the producer "
+                    "(state = %d)", slot, mSlots[slot].mBufferState);
+            return BAD_VALUE;
+        } else if (!mSlots[slot].mRequestBufferCalled) {
+            BQ_LOGE("queueBuffer: slot %d was queued without requesting "
+                    "a buffer", slot);
+            return BAD_VALUE;
+        }
+
+        BQ_LOGV("queueBuffer: slot=%d/%" PRIu64 " time=%" PRIu64
+                " crop=[%d,%d,%d,%d] transform=%#x scale=%s",
+                slot, mCore->mFrameCounter + 1, timestamp,
+                crop.left, crop.top, crop.right, crop.bottom,
+                transform, BufferItem::scalingModeName(scalingMode));
+
+        const sp<GraphicBuffer>& graphicBuffer(mSlots[slot].mGraphicBuffer);
+        Rect bufferRect(graphicBuffer->getWidth(), graphicBuffer->getHeight());
+        Rect croppedRect;
+        crop.intersect(bufferRect, &croppedRect);
+        if (croppedRect != crop) {
+            BQ_LOGE("queueBuffer: crop rect is not contained within the "
+                    "buffer in slot %d", slot);
+            return BAD_VALUE;
+        }
+
+        mSlots[slot].mFence = fence;
+        mSlots[slot].mBufferState = BufferSlot::QUEUED;
+        ++mCore->mFrameCounter;
+        mSlots[slot].mFrameNumber = mCore->mFrameCounter;
+
+        BufferItem item;
+        item.mAcquireCalled = mSlots[slot].mAcquireCalled;
+        item.mGraphicBuffer = mSlots[slot].mGraphicBuffer;
+        item.mCrop = crop;
+        item.mTransform = transform & ~NATIVE_WINDOW_TRANSFORM_INVERSE_DISPLAY;
+        item.mTransformToDisplayInverse =
+                bool(transform & NATIVE_WINDOW_TRANSFORM_INVERSE_DISPLAY);
+        item.mScalingMode = scalingMode;
+        item.mTimestamp = timestamp;
+        item.mIsAutoTimestamp = isAutoTimestamp;
+        item.mFrameNumber = mCore->mFrameCounter;
+        item.mSlot = slot;
+        item.mFence = fence;
+        item.mIsDroppable = mCore->mDequeueBufferCannotBlock || async;
+
+        mStickyTransform = stickyTransform;
+
+        if (mCore->mQueue.empty()) {
+            // When the queue is empty, we can ignore mDequeueBufferCannotBlock
+            // and simply queue this buffer
+            mCore->mQueue.push_back(item);
+            listener = mCore->mConsumerListener;
+        } else {
+            // When the queue is not empty, we need to look at the front buffer
+            // state to see if we need to replace it
+            BufferQueueCore::Fifo::iterator front(mCore->mQueue.begin());
+            if (front->mIsDroppable) {
+                // If the front queued buffer is still being tracked, we first
+                // mark it as freed
+                if (mCore->stillTracking(front)) {
+                    mSlots[front->mSlot].mBufferState = BufferSlot::FREE;
+                    // Reset the frame number of the freed buffer so that it is
+                    // the first in line to be dequeued again
+                    mSlots[front->mSlot].mFrameNumber = 0;
+                }
+                // Overwrite the droppable buffer with the incoming one
+                *front = item;
+            } else {
+                mCore->mQueue.push_back(item);
+                listener = mCore->mConsumerListener;
+            }
+        }
+
+        mCore->mBufferHasBeenQueued = true;
+        mCore->mDequeueCondition.broadcast();
+
+        output->inflate(mCore->mDefaultWidth, mCore->mDefaultHeight,
+                mCore->mTransformHint, mCore->mQueue.size());
+
+        ATRACE_INT(mCore->mConsumerName.string(), mCore->mQueue.size());
+    } // Autolock scope
+
+    // Call back without lock held
+    if (listener != NULL) {
+        listener->onFrameAvailable();
+    }
+
+    return NO_ERROR;
+}
+
+void BufferQueueProducer::cancelBuffer(int slot, const sp<Fence>& fence) {
+    ATRACE_CALL();
+    BQ_LOGV("cancelBuffer: slot %d", slot);
+    Mutex::Autolock lock(mCore->mMutex);
+
+    if (mCore->mIsAbandoned) {
+        BQ_LOGE("cancelBuffer: BufferQueue has been abandoned");
+        return;
+    }
+
+    if (slot < 0 || slot >= BufferQueueDefs::NUM_BUFFER_SLOTS) {
+        BQ_LOGE("cancelBuffer: slot index %d out of range [0, %d)",
+                slot, BufferQueueDefs::NUM_BUFFER_SLOTS);
+        return;
+    } else if (mSlots[slot].mBufferState != BufferSlot::DEQUEUED) {
+        BQ_LOGE("cancelBuffer: slot %d is not owned by the producer "
+                "(state = %d)", slot, mSlots[slot].mBufferState);
+        return;
+    } else if (fence == NULL) {
+        BQ_LOGE("cancelBuffer: fence is NULL");
+        return;
+    }
+
+    mSlots[slot].mBufferState = BufferSlot::FREE;
+    mSlots[slot].mFrameNumber = 0;
+    mSlots[slot].mFence = fence;
+    mCore->mDequeueCondition.broadcast();
+}
+
+int BufferQueueProducer::query(int what, int *outValue) {
+    ATRACE_CALL();
+    Mutex::Autolock lock(mCore->mMutex);
+
+    if (outValue == NULL) {
+        BQ_LOGE("query: outValue was NULL");
+        return BAD_VALUE;
+    }
+
+    if (mCore->mIsAbandoned) {
+        BQ_LOGE("query: BufferQueue has been abandoned");
+        return NO_INIT;
+    }
+
+    int value;
+    switch (what) {
+        case NATIVE_WINDOW_WIDTH:
+            value = mCore->mDefaultWidth;
+            break;
+        case NATIVE_WINDOW_HEIGHT:
+            value = mCore->mDefaultHeight;
+            break;
+        case NATIVE_WINDOW_FORMAT:
+            value = mCore->mDefaultBufferFormat;
+            break;
+        case NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS:
+            value = mCore->getMinUndequeuedBufferCountLocked(false);
+            break;
+        case NATIVE_WINDOW_STICKY_TRANSFORM:
+            value = static_cast<int>(mStickyTransform);
+            break;
+        case NATIVE_WINDOW_CONSUMER_RUNNING_BEHIND:
+            value = (mCore->mQueue.size() > 1);
+            break;
+        case NATIVE_WINDOW_CONSUMER_USAGE_BITS:
+            value = mCore->mConsumerUsageBits;
+            break;
+        default:
+            return BAD_VALUE;
+    }
+
+    BQ_LOGV("query: %d? %d", what, value);
+    *outValue = value;
+    return NO_ERROR;
+}
+
+status_t BufferQueueProducer::connect(const sp<IProducerListener>& listener,
+        int api, bool producerControlledByApp, QueueBufferOutput *output) {
+    ATRACE_CALL();
+    Mutex::Autolock lock(mCore->mMutex);
+    mConsumerName = mCore->mConsumerName;
+    BQ_LOGV("connect(P): api=%d producerControlledByApp=%s", api,
+            producerControlledByApp ? "true" : "false");
+
+    if (mCore->mIsAbandoned) {
+        BQ_LOGE("connect(P): BufferQueue has been abandoned");
+        return NO_INIT;
+    }
+
+    if (mCore->mConsumerListener == NULL) {
+        BQ_LOGE("connect(P): BufferQueue has no consumer");
+        return NO_INIT;
+    }
+
+    if (output == NULL) {
+        BQ_LOGE("connect(P): output was NULL");
+        return BAD_VALUE;
+    }
+
+    if (mCore->mConnectedApi != BufferQueueCore::NO_CONNECTED_API) {
+        BQ_LOGE("connect(P): already connected (cur=%d req=%d)",
+                mCore->mConnectedApi, api);
+        return BAD_VALUE;
+    }
+
+    int status = NO_ERROR;
+    switch (api) {
+        case NATIVE_WINDOW_API_EGL:
+        case NATIVE_WINDOW_API_CPU:
+        case NATIVE_WINDOW_API_MEDIA:
+        case NATIVE_WINDOW_API_CAMERA:
+            mCore->mConnectedApi = api;
+            output->inflate(mCore->mDefaultWidth, mCore->mDefaultHeight,
+                    mCore->mTransformHint, mCore->mQueue.size());
+
+            // Set up a death notification so that we can disconnect
+            // automatically if the remote producer dies
+            if (listener != NULL &&
+                    listener->asBinder()->remoteBinder() != NULL) {
+                status = listener->asBinder()->linkToDeath(
+                        static_cast<IBinder::DeathRecipient*>(this));
+                if (status != NO_ERROR) {
+                    BQ_LOGE("connect(P): linkToDeath failed: %s (%d)",
+                            strerror(-status), status);
+                }
+            }
+            mCore->mConnectedProducerListener = listener;
+            break;
+        default:
+            BQ_LOGE("connect(P): unknown API %d", api);
+            status = BAD_VALUE;
+            break;
+    }
+
+    mCore->mBufferHasBeenQueued = false;
+    mCore->mDequeueBufferCannotBlock =
+            mCore->mConsumerControlledByApp && producerControlledByApp;
+
+    return status;
+}
+
+status_t BufferQueueProducer::disconnect(int api) {
+    ATRACE_CALL();
+    BQ_LOGV("disconnect(P): api %d", api);
+
+    int status = NO_ERROR;
+    sp<IConsumerListener> listener;
+    { // Autolock scope
+        Mutex::Autolock lock(mCore->mMutex);
+        mCore->waitWhileAllocatingLocked();
+
+        if (mCore->mIsAbandoned) {
+            // It's not really an error to disconnect after the surface has
+            // been abandoned; it should just be a no-op.
+            return NO_ERROR;
+        }
+
+        switch (api) {
+            case NATIVE_WINDOW_API_EGL:
+            case NATIVE_WINDOW_API_CPU:
+            case NATIVE_WINDOW_API_MEDIA:
+            case NATIVE_WINDOW_API_CAMERA:
+                if (mCore->mConnectedApi == api) {
+                    mCore->freeAllBuffersLocked();
+
+                    // Remove our death notification callback if we have one
+                    if (mCore->mConnectedProducerListener != NULL) {
+                        sp<IBinder> token =
+                                mCore->mConnectedProducerListener->asBinder();
+                        // This can fail if we're here because of the death
+                        // notification, but we just ignore it
+                        token->unlinkToDeath(
+                                static_cast<IBinder::DeathRecipient*>(this));
+                    }
+                    mCore->mConnectedProducerListener = NULL;
+                    mCore->mConnectedApi = BufferQueueCore::NO_CONNECTED_API;
+                    mCore->mSidebandStream.clear();
+                    mCore->mDequeueCondition.broadcast();
+                    listener = mCore->mConsumerListener;
+                } else {
+                    BQ_LOGE("disconnect(P): connected to another API "
+                            "(cur=%d req=%d)", mCore->mConnectedApi, api);
+                    status = BAD_VALUE;
+                }
+                break;
+            default:
+                BQ_LOGE("disconnect(P): unknown API %d", api);
+                status = BAD_VALUE;
+                break;
+        }
+    } // Autolock scope
+
+    // Call back without lock held
+    if (listener != NULL) {
+        listener->onBuffersReleased();
+    }
+
+    return status;
+}
+
+status_t BufferQueueProducer::setSidebandStream(const sp<NativeHandle>& stream) {
+    sp<IConsumerListener> listener;
+    { // Autolock scope
+        Mutex::Autolock _l(mCore->mMutex);
+        mCore->mSidebandStream = stream;
+        listener = mCore->mConsumerListener;
+    } // Autolock scope
+
+    if (listener != NULL) {
+        listener->onSidebandStreamChanged();
+    }
+    return NO_ERROR;
+}
+
+void BufferQueueProducer::allocateBuffers(bool async, uint32_t width,
+        uint32_t height, uint32_t format, uint32_t usage) {
+    ATRACE_CALL();
+    while (true) {
+        Vector<int> freeSlots;
+        size_t newBufferCount = 0;
+        uint32_t allocWidth = 0;
+        uint32_t allocHeight = 0;
+        uint32_t allocFormat = 0;
+        uint32_t allocUsage = 0;
+        { // Autolock scope
+            Mutex::Autolock lock(mCore->mMutex);
+            mCore->waitWhileAllocatingLocked();
+
+            int currentBufferCount = 0;
+            for (int slot = 0; slot < BufferQueueDefs::NUM_BUFFER_SLOTS; ++slot) {
+                if (mSlots[slot].mGraphicBuffer != NULL) {
+                    ++currentBufferCount;
+                } else {
+                    if (mSlots[slot].mBufferState != BufferSlot::FREE) {
+                        BQ_LOGE("allocateBuffers: slot %d without buffer is not FREE",
+                                slot);
+                        continue;
+                    }
+
+                    freeSlots.push_back(slot);
+                }
+            }
+
+            int maxBufferCount = mCore->getMaxBufferCountLocked(async);
+            BQ_LOGV("allocateBuffers: allocating from %d buffers up to %d buffers",
+                    currentBufferCount, maxBufferCount);
+            if (maxBufferCount <= currentBufferCount)
+                return;
+            newBufferCount = maxBufferCount - currentBufferCount;
+            if (freeSlots.size() < newBufferCount) {
+                BQ_LOGE("allocateBuffers: ran out of free slots");
+                return;
+            }
+            allocWidth = width > 0 ? width : mCore->mDefaultWidth;
+            allocHeight = height > 0 ? height : mCore->mDefaultHeight;
+            allocFormat = format != 0 ? format : mCore->mDefaultBufferFormat;
+            allocUsage = usage | mCore->mConsumerUsageBits;
+
+            mCore->mIsAllocating = true;
+        } // Autolock scope
+
+        Vector<sp<GraphicBuffer> > buffers;
+        for (size_t i = 0; i <  newBufferCount; ++i) {
+            status_t result = NO_ERROR;
+            sp<GraphicBuffer> graphicBuffer(mCore->mAllocator->createGraphicBuffer(
+                    allocWidth, allocHeight, allocFormat, allocUsage, &result));
+            if (result != NO_ERROR) {
+                BQ_LOGE("allocateBuffers: failed to allocate buffer (%u x %u, format"
+                        " %u, usage %u)", width, height, format, usage);
+                Mutex::Autolock lock(mCore->mMutex);
+                mCore->mIsAllocating = false;
+                mCore->mIsAllocatingCondition.broadcast();
+                return;
+            }
+            buffers.push_back(graphicBuffer);
+        }
+
+        { // Autolock scope
+            Mutex::Autolock lock(mCore->mMutex);
+            uint32_t checkWidth = width > 0 ? width : mCore->mDefaultWidth;
+            uint32_t checkHeight = height > 0 ? height : mCore->mDefaultHeight;
+            uint32_t checkFormat = format != 0 ? format : mCore->mDefaultBufferFormat;
+            uint32_t checkUsage = usage | mCore->mConsumerUsageBits;
+            if (checkWidth != allocWidth || checkHeight != allocHeight ||
+                checkFormat != allocFormat || checkUsage != allocUsage) {
+                // Something changed while we released the lock. Retry.
+                BQ_LOGV("allocateBuffers: size/format/usage changed while allocating. Retrying.");
+                mCore->mIsAllocating = false;
+                mCore->mIsAllocatingCondition.broadcast();
+                continue;
+            }
+
+            for (size_t i = 0; i < newBufferCount; ++i) {
+                int slot = freeSlots[i];
+                if (mSlots[slot].mBufferState != BufferSlot::FREE) {
+                    // A consumer allocated the FREE slot with attachBuffer. Discard the buffer we
+                    // allocated.
+                    BQ_LOGV("allocateBuffers: slot %d was acquired while allocating. "
+                            "Dropping allocated buffer.", slot);
+                    continue;
+                }
+                mCore->freeBufferLocked(slot); // Clean up the slot first
+                mSlots[slot].mGraphicBuffer = buffers[i];
+                mSlots[slot].mFrameNumber = 0;
+                mSlots[slot].mFence = Fence::NO_FENCE;
+                BQ_LOGV("allocateBuffers: allocated a new buffer in slot %d", slot);
+            }
+
+            mCore->mIsAllocating = false;
+            mCore->mIsAllocatingCondition.broadcast();
+        } // Autolock scope
+    }
+}
+
+void BufferQueueProducer::binderDied(const wp<android::IBinder>& /* who */) {
+    // If we're here, it means that a producer we were connected to died.
+    // We're guaranteed that we are still connected to it because we remove
+    // this callback upon disconnect. It's therefore safe to read mConnectedApi
+    // without synchronization here.
+    int api = mCore->mConnectedApi;
+    disconnect(api);
+}
+
+} // namespace android
new file mode 100644
--- /dev/null
+++ b/widget/gonk/nativewindow/GonkBufferQueueLL/BufferQueueProducer.h
@@ -0,0 +1,204 @@
+/*
+ * Copyright 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_GUI_BUFFERQUEUEPRODUCER_H
+#define ANDROID_GUI_BUFFERQUEUEPRODUCER_H
+
+#include <gui/BufferQueueDefs.h>
+#include <gui/IGraphicBufferProducer.h>
+
+namespace android {
+
+class BufferSlot;
+
+class BufferQueueProducer : public BnGraphicBufferProducer,
+                            private IBinder::DeathRecipient {
+public:
+    friend class BufferQueue; // Needed to access binderDied
+
+    BufferQueueProducer(const sp<BufferQueueCore>& core);
+    virtual ~BufferQueueProducer();
+
+    // requestBuffer returns the GraphicBuffer for slot N.
+    //
+    // In normal operation, this is called the first time slot N is returned
+    // by dequeueBuffer.  It must be called again if dequeueBuffer returns
+    // flags indicating that previously-returned buffers are no longer valid.
+    virtual status_t requestBuffer(int slot, sp<GraphicBuffer>* buf);
+
+    // setBufferCount updates the number of available buffer slots.  If this
+    // method succeeds, buffer slots will be both unallocated and owned by
+    // the BufferQueue object (i.e. they are not owned by the producer or
+    // consumer).
+    //
+    // This will fail if the producer has dequeued any buffers, or if
+    // bufferCount is invalid.  bufferCount must generally be a value
+    // between the minimum undequeued buffer count (exclusive) and NUM_BUFFER_SLOTS
+    // (inclusive).  It may also be set to zero (the default) to indicate
+    // that the producer does not wish to set a value.  The minimum value
+    // can be obtained by calling query(NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS,
+    // ...).
+    //
+    // This may only be called by the producer.  The consumer will be told
+    // to discard buffers through the onBuffersReleased callback.
+    virtual status_t setBufferCount(int bufferCount);
+
+    // dequeueBuffer gets the next buffer slot index for the producer to use.
+    // If a buffer slot is available then that slot index is written to the
+    // location pointed to by the buf argument and a status of OK is returned.
+    // If no slot is available then a status of -EBUSY is returned and buf is
+    // unmodified.
+    //
+    // The outFence parameter will be updated to hold the fence associated with
+    // the buffer. The contents of the buffer must not be overwritten until the
+    // fence signals. If the fence is Fence::NO_FENCE, the buffer may be
+    // written immediately.
+    //
+    // The width and height parameters must be no greater than the minimum of
+    // GL_MAX_VIEWPORT_DIMS and GL_MAX_TEXTURE_SIZE (see: glGetIntegerv).
+    // An error due to invalid dimensions might not be reported until
+    // updateTexImage() is called.  If width and height are both zero, the
+    // default values specified by setDefaultBufferSize() are used instead.
+    //
+    // The pixel formats are enumerated in graphics.h, e.g.
+    // HAL_PIXEL_FORMAT_RGBA_8888.  If the format is 0, the default format
+    // will be used.
+    //
+    // The usage argument specifies gralloc buffer usage flags.  The values
+    // are enumerated in gralloc.h, e.g. GRALLOC_USAGE_HW_RENDER.  These
+    // will be merged with the usage flags specified by setConsumerUsageBits.
+    //
+    // The return value may be a negative error value or a non-negative
+    // collection of flags.  If the flags are set, the return values are
+    // valid, but additional actions must be performed.
+    //
+    // If IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION is set, the
+    // producer must discard cached GraphicBuffer references for the slot
+    // returned in buf.
+    // If IGraphicBufferProducer::RELEASE_ALL_BUFFERS is set, the producer
+    // must discard cached GraphicBuffer references for all slots.
+    //
+    // In both cases, the producer will need to call requestBuffer to get a
+    // GraphicBuffer handle for the returned slot.
+    virtual status_t dequeueBuffer(int *outSlot, sp<Fence>* outFence, bool async,
+            uint32_t width, uint32_t height, uint32_t format, uint32_t usage);
+
+    // See IGraphicBufferProducer::detachBuffer
+    virtual status_t detachBuffer(int slot);
+
+    // See IGraphicBufferProducer::detachNextBuffer
+    virtual status_t detachNextBuffer(sp<GraphicBuffer>* outBuffer,
+            sp<Fence>* outFence);
+
+    // See IGraphicBufferProducer::attachBuffer
+    virtual status_t attachBuffer(int* outSlot, const sp<GraphicBuffer>& buffer);
+
+    // queueBuffer returns a filled buffer to the BufferQueue.
+    //
+    // Additional data is provided in the QueueBufferInput struct.  Notably,
+    // a timestamp must be provided for the buffer. The timestamp is in
+    // nanoseconds, and must be monotonically increasing. Its other semantics
+    // (zero point, etc) are producer-specific and should be documented by the
+    // producer.
+    //
+    // The caller may provide a fence that signals when all rendering
+    // operations have completed.  Alternatively, NO_FENCE may be used,
+    // indicating that the buffer is ready immediately.
+    //
+    // Some values are returned in the output struct: the current settings
+    // for default width and height, the current transform hint, and the
+    // number of queued buffers.
+    virtual status_t queueBuffer(int slot,
+            const QueueBufferInput& input, QueueBufferOutput* output);
+
+    // cancelBuffer returns a dequeued buffer to the BufferQueue, but doesn't
+    // queue it for use by the consumer.
+    //
+    // The buffer will not be overwritten until the fence signals.  The fence
+    // will usually be the one obtained from dequeueBuffer.
+    virtual void cancelBuffer(int slot, const sp<Fence>& fence);
+
+    // Query native window attributes.  The "what" values are enumerated in
+    // window.h (e.g. NATIVE_WINDOW_FORMAT).
+    virtual int query(int what, int* outValue);
+
+    // connect attempts to connect a producer API to the BufferQueue.  This
+    // must be called before any other IGraphicBufferProducer methods are
+    // called except for getAllocator.  A consumer must already be connected.
+    //
+    // This method will fail if connect was previously called on the
+    // BufferQueue and no corresponding disconnect call was made (i.e. if
+    // it's still connected to a producer).
+    //
+    // APIs are enumerated in window.h (e.g. NATIVE_WINDOW_API_CPU).
+    virtual status_t connect(const sp<IProducerListener>& listener,
+            int api, bool producerControlledByApp, QueueBufferOutput* output);
+
+    // disconnect attempts to disconnect a producer API from the BufferQueue.
+    // Calling this method will cause any subsequent calls to other
+    // IGraphicBufferProducer methods to fail except for getAllocator and connect.
+    // Successfully calling connect after this will allow the other methods to
+    // succeed again.
+    //
+    // This method will fail if the the BufferQueue is not currently
+    // connected to the specified producer API.
+    virtual status_t disconnect(int api);
+
+    // Attaches a sideband buffer stream to the IGraphicBufferProducer.
+    //
+    // A sideband stream is a device-specific mechanism for passing buffers
+    // from the producer to the consumer without using dequeueBuffer/
+    // queueBuffer. If a sideband stream is present, the consumer can choose
+    // whether to acquire buffers from the sideband stream or from the queued
+    // buffers.
+    //
+    // Passing NULL or a different stream handle will detach the previous
+    // handle if any.
+    virtual status_t setSidebandStream(const sp<NativeHandle>& stream);
+
+    // See IGraphicBufferProducer::allocateBuffers
+    virtual void allocateBuffers(bool async, uint32_t width, uint32_t height,
+            uint32_t format, uint32_t usage);
+
+private:
+    // This is required by the IBinder::DeathRecipient interface
+    virtual void binderDied(const wp<IBinder>& who);
+
+    // waitForFreeSlotThenRelock finds the oldest slot in the FREE state. It may
+    // block if there are no available slots and we are not in non-blocking
+    // mode (producer and consumer controlled by the application). If it blocks,
+    // it will release mCore->mMutex while blocked so that other operations on
+    // the BufferQueue may succeed.
+    status_t waitForFreeSlotThenRelock(const char* caller, bool async,
+            int* found, status_t* returnFlags) const;
+
+    sp<BufferQueueCore> mCore;
+
+    // This references mCore->mSlots. Lock mCore->mMutex while accessing.
+    BufferQueueDefs::SlotsType& mSlots;
+
+    // This is a cached copy of the name stored in the BufferQueueCore.
+    // It's updated during connect and dequeueBuffer (which should catch
+    // most updates).
+    String8 mConsumerName;
+
+    uint32_t mStickyTransform;
+
+}; // class BufferQueueProducer
+
+} // namespace android
+
+#endif
new file mode 100644
--- /dev/null
+++ b/widget/gonk/nativewindow/GonkBufferQueueLL/BufferSlot.cpp
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <gui/BufferSlot.h>
+
+namespace android {
+
+const char* BufferSlot::bufferStateName(BufferState state) {
+    switch (state) {
+        case BufferSlot::DEQUEUED: return "DEQUEUED";
+        case BufferSlot::QUEUED: return "QUEUED";
+        case BufferSlot::FREE: return "FREE";
+        case BufferSlot::ACQUIRED: return "ACQUIRED";
+        default: return "Unknown";
+    }
+}
+
+} // namespace android
new file mode 100644
--- /dev/null
+++ b/widget/gonk/nativewindow/GonkBufferQueueLL/BufferSlot.h
@@ -0,0 +1,142 @@
+/*
+ * Copyright 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_GUI_BUFFERSLOT_H
+#define ANDROID_GUI_BUFFERSLOT_H
+
+#include <ui/Fence.h>
+#include <ui/GraphicBuffer.h>
+
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
+
+#include <utils/StrongPointer.h>
+
+namespace android {
+
+class Fence;
+
+struct BufferSlot {
+
+    BufferSlot()
+    : mEglDisplay(EGL_NO_DISPLAY),
+      mBufferState(BufferSlot::FREE),
+      mRequestBufferCalled(false),
+      mFrameNumber(0),
+      mEglFence(EGL_NO_SYNC_KHR),
+      mAcquireCalled(false),
+      mNeedsCleanupOnRelease(false),
+      mAttachedByConsumer(false) {
+    }
+
+    // mGraphicBuffer points to the buffer allocated for this slot or is NULL
+    // if no buffer has been allocated.
+    sp<GraphicBuffer> mGraphicBuffer;
+
+    // mEglDisplay is the EGLDisplay used to create EGLSyncKHR objects.
+    EGLDisplay mEglDisplay;
+
+    // BufferState represents the different states in which a buffer slot
+    // can be.  All slots are initially FREE.
+    enum BufferState {
+        // FREE indicates that the buffer is available to be dequeued
+        // by the producer.  The buffer may be in use by the consumer for
+        // a finite time, so the buffer must not be modified until the
+        // associated fence is signaled.
+        //
+        // The slot is "owned" by BufferQueue.  It transitions to DEQUEUED
+        // when dequeueBuffer is called.
+        FREE = 0,
+
+        // DEQUEUED indicates that the buffer has been dequeued by the
+        // producer, but has not yet been queued or canceled.  The
+        // producer may modify the buffer's contents as soon as the
+        // associated ready fence is signaled.
+        //
+        // The slot is "owned" by the producer.  It can transition to
+        // QUEUED (via queueBuffer) or back to FREE (via cancelBuffer).
+        DEQUEUED = 1,
+
+        // QUEUED indicates that the buffer has been filled by the
+        // producer and queued for use by the consumer.  The buffer
+        // contents may continue to be modified for a finite time, so
+        // the contents must not be accessed until the associated fence
+        // is signaled.
+        //
+        // The slot is "owned" by BufferQueue.  It can transition to
+        // ACQUIRED (via acquireBuffer) or to FREE (if another buffer is
+        // queued in asynchronous mode).
+        QUEUED = 2,
+
+        // ACQUIRED indicates that the buffer has been acquired by the
+        // consumer.  As with QUEUED, the contents must not be accessed
+        // by the consumer until the fence is signaled.
+        //
+        // The slot is "owned" by the consumer.  It transitions to FREE
+        // when releaseBuffer is called.
+        ACQUIRED = 3
+    };
+
+    static const char* bufferStateName(BufferState state);
+
+    // mBufferState is the current state of this buffer slot.
+    BufferState mBufferState;
+
+    // mRequestBufferCalled is used for validating that the producer did
+    // call requestBuffer() when told to do so. Technically this is not
+    // needed but useful for debugging and catching producer bugs.
+    bool mRequestBufferCalled;
+
+    // mFrameNumber is the number of the queued frame for this slot.  This
+    // is used to dequeue buffers in LRU order (useful because buffers
+    // may be released before their release fence is signaled).
+    uint64_t mFrameNumber;
+
+    // mEglFence is the EGL sync object that must signal before the buffer
+    // associated with this buffer slot may be dequeued. It is initialized
+    // to EGL_NO_SYNC_KHR when the buffer is created and may be set to a
+    // new sync object in releaseBuffer.  (This is deprecated in favor of
+    // mFence, below.)
+    EGLSyncKHR mEglFence;
+
+    // mFence is a fence which will signal when work initiated by the
+    // previous owner of the buffer is finished. When the buffer is FREE,
+    // the fence indicates when the consumer has finished reading
+    // from the buffer, or when the producer has finished writing if it
+    // called cancelBuffer after queueing some writes. When the buffer is
+    // QUEUED, it indicates when the producer has finished filling the
+    // buffer. When the buffer is DEQUEUED or ACQUIRED, the fence has been
+    // passed to the consumer or producer along with ownership of the
+    // buffer, and mFence is set to NO_FENCE.
+    sp<Fence> mFence;
+
+    // Indicates whether this buffer has been seen by a consumer yet
+    bool mAcquireCalled;
+
+    // Indicates whether this buffer needs to be cleaned up by the
+    // consumer.  This is set when a buffer in ACQUIRED state is freed.
+    // It causes releaseBuffer to return STALE_BUFFER_SLOT.
+    bool mNeedsCleanupOnRelease;
+
+    // Indicates whether the buffer was attached on the consumer side.
+    // If so, it needs to set the BUFFER_NEEDS_REALLOCATION flag when dequeued
+    // to prevent the producer from using a stale cached buffer.
+    bool mAttachedByConsumer;
+};
+
+} // namespace android
+
+#endif
new file mode 100644
--- /dev/null
+++ b/widget/gonk/nativewindow/GonkBufferQueueLL/ConsumerBase.cpp
@@ -0,0 +1,269 @@
+/*
+ * 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.
+ */
+
+#include <inttypes.h>
+
+#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 __attribute__((unused))) {
+    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;
+    }
+
+    uint64_t mask = 0;
+    mConsumer->getReleasedBuffers(&mask);
+    for (int i = 0; i < BufferQueue::NUM_BUFFER_SLOTS; i++) {
+        if (mask & (1ULL << i)) {
+            freeBufferLocked(i);
+        }
+    }
+}
+
+void ConsumerBase::onSidebandStreamChanged() {
+}
+
+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/%" PRIu64,
+            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/%" PRIu64,
+            slot, mSlots[slot].mFrameNumber);
+    status_t err = mConsumer->releaseBuffer(slot, mSlots[slot].mFrameNumber,
+            display, eglFence, mSlots[slot].mFence);
+    if (err == IGraphicBufferConsumer::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/GonkBufferQueueLL/ConsumerBase.h
@@ -0,0 +1,241 @@
+/*
+ * 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.  The onFrameAvailable and onBuffersReleased methods should
+    // not need to be overridden by derived classes, but if they are overridden
+    // the ConsumerBase implementation must be called from the derived class.
+    // The ConsumerBase version of onSidebandStreamChanged does nothing and can
+    // be overriden by derived classes if they want the notification.
+    virtual void onFrameAvailable();
+    virtual void onBuffersReleased();
+    virtual void onSidebandStreamChanged();
+
+    // freeBufferLocked frees up the given buffer slot.  If the slot has been
+    // initialized this will release the reference to the GraphicBuffer in that
+    // 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/GonkBufferQueueLL/IGraphicBufferConsumer.cpp
@@ -0,0 +1,553 @@
+/*
+ * 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.
+ */
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <utils/Errors.h>
+#include <utils/NativeHandle.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();
+        c = FlattenableUtils::align<4>(c);
+    }
+    if (mFence != 0) {
+        c += mFence->getFlattenedSize();
+        c = 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;
+}
+
+static void writeBoolAsInt(void*& buffer, size_t& size, bool b) {
+    FlattenableUtils::write(buffer, size, static_cast<int32_t>(b));
+}
+
+static bool readBoolFromInt(void const*& buffer, size_t& size) {
+    int32_t i;
+    FlattenableUtils::read(buffer, size, i);
+    return static_cast<bool>(i);
+}
+
+status_t IGraphicBufferConsumer::BufferItem::flatten(
+        void*& buffer, size_t& size, int*& fds, size_t& count) const {
+
+    // make sure we have enough space
+    if (size < 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);
+    writeBoolAsInt(buffer, size, mIsAutoTimestamp);
+    FlattenableUtils::write(buffer, size, mFrameNumber);
+    FlattenableUtils::write(buffer, size, mBuf);
+    writeBoolAsInt(buffer, size, mIsDroppable);
+    writeBoolAsInt(buffer, size, mAcquireCalled);
+    writeBoolAsInt(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);
+    mIsAutoTimestamp = readBoolFromInt(buffer, size);
+    FlattenableUtils::read(buffer, size, mFrameNumber);
+    FlattenableUtils::read(buffer, size, mBuf);
+    mIsDroppable = readBoolFromInt(buffer, size);
+    mAcquireCalled = readBoolFromInt(buffer, size);
+    mTransformToDisplayInverse = readBoolFromInt(buffer, size);
+
+    return NO_ERROR;
+}
+
+// ---------------------------------------------------------------------------
+
+enum {
+    ACQUIRE_BUFFER = IBinder::FIRST_CALL_TRANSACTION,
+    DETACH_BUFFER,
+    ATTACH_BUFFER,
+    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,
+    GET_SIDEBAND_STREAM,
+    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 detachBuffer(int slot) {
+        Parcel data, reply;
+        data.writeInterfaceToken(IGraphicBufferConsumer::getInterfaceDescriptor());
+        data.writeInt32(slot);
+        status_t result = remote()->transact(DETACH_BUFFER, data, &reply);
+        if (result != NO_ERROR) {
+            return result;
+        }
+        result = reply.readInt32();
+        return result;
+    }
+
+    virtual status_t attachBuffer(int* slot, const sp<GraphicBuffer>& buffer) {
+        Parcel data, reply;
+        data.writeInterfaceToken(IGraphicBufferConsumer::getInterfaceDescriptor());
+        data.write(*buffer.get());
+        status_t result = remote()->transact(ATTACH_BUFFER, data, &reply);
+        if (result != NO_ERROR) {
+            return result;
+        }
+        *slot = reply.readInt32();
+        result = reply.readInt32();
+        return result;
+    }
+
+    virtual status_t releaseBuffer(int buf, uint64_t frameNumber,
+            EGLDisplay display __attribute__((unused)), EGLSyncKHR fence __attribute__((unused)),
+            const sp<Fence>& releaseFence) {
+        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(uint64_t* slotMask) {
+        Parcel data, reply;
+        if (slotMask == NULL) {
+            ALOGE("getReleasedBuffers: slotMask must not be NULL");
+            return BAD_VALUE;
+        }
+        data.writeInterfaceToken(IGraphicBufferConsumer::getInterfaceDescriptor());
+        status_t result = remote()->transact(GET_RELEASED_BUFFERS, data, &reply);
+        if (result != NO_ERROR) {
+            return result;
+        }
+        *slotMask = reply.readInt64();
+        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 sp<NativeHandle> getSidebandStream() const {
+        Parcel data, reply;
+        status_t err;
+        data.writeInterfaceToken(IGraphicBufferConsumer::getInterfaceDescriptor());
+        if ((err = remote()->transact(GET_SIDEBAND_STREAM, data, &reply)) != NO_ERROR) {
+            return NULL;
+        }
+        sp<NativeHandle> stream;
+        if (reply.readInt32()) {
+            stream = NativeHandle::create(reply.readNativeHandle(), true);
+        }
+        return stream;
+    }
+
+    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 DETACH_BUFFER: {
+            CHECK_INTERFACE(IGraphicBufferConsumer, data, reply);
+            int slot = data.readInt32();
+            int result = detachBuffer(slot);
+            reply->writeInt32(result);
+            return NO_ERROR;
+        } break;
+        case ATTACH_BUFFER: {
+            CHECK_INTERFACE(IGraphicBufferConsumer, data, reply);
+            sp<GraphicBuffer> buffer = new GraphicBuffer();
+            data.read(*buffer.get());
+            int slot;
+            int result = attachBuffer(&slot, buffer);
+            reply->writeInt32(slot);
+            reply->writeInt32(result);
+            return NO_ERROR;
+        } break;
+        case RELEASE_BUFFER: {
+            CHECK_INTERFACE(IGraphicBufferConsumer, data, reply);
+            int buf = data.readInt32();
+            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);
+            uint64_t slotMask;
+            status_t result = getReleasedBuffers(&slotMask);
+            reply->writeInt64(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/GonkBufferQueueLL/IGraphicBufferConsumer.h
@@ -0,0 +1,327 @@
+/*
+ * 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>
+
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
+
+namespace android {
+// ----------------------------------------------------------------------------
+
+class Fence;
+class GraphicBuffer;
+class IConsumerListener;
+class NativeHandle;
+
+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:
+        // The default value of mBuf, used to indicate this doesn't correspond to a slot.
+        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.
+        // refer to NATIVE_WINDOW_TRANSFORM_* in <window.h>
+        uint32_t mTransform;
+
+        // mScalingMode is the current scaling mode for this buffer slot.
+        // refer to NATIVE_WINDOW_SCALING_* in <window.h>
+        uint32_t mScalingMode;
+
+        // mTimestamp is the current timestamp for this buffer slot. This gets
+        // to set by queueBuffer each time this slot is queued. This value
+        // is guaranteed to be monotonically increasing for each newly
+        // acquired buffer.
+        int64_t mTimestamp;
+
+        // mIsAutoTimestamp indicates whether mTimestamp was generated
+        // automatically when the buffer was queued.
+        bool mIsAutoTimestamp;
+
+        // mFrameNumber is the number of the queued frame for this slot.
+        uint64_t mFrameNumber;
+
+        // mBuf is the slot index of this buffer (default INVALID_BUFFER_SLOT).
+        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;
+    };
+
+    enum {
+        // Returned by releaseBuffer, after which the consumer must
+        // free any references to the just-released buffer that it might have.
+        STALE_BUFFER_SLOT = 1,
+        // Returned by dequeueBuffer if there are no pending buffers available.
+        NO_BUFFER_AVAILABLE,
+        // Returned by dequeueBuffer if it's too early for the buffer to be acquired.
+        PRESENT_LATER,
+    };
+
+    // acquireBuffer attempts to acquire ownership of the next pending buffer in
+    // the BufferQueue.  If no buffer is pending then it returns
+    // NO_BUFFER_AVAILABLE.  If a buffer is successfully acquired, the
+    // information about the buffer is returned in BufferItem.
+    //
+    // If the buffer returned had previously been
+    // acquired then the BufferItem::mGraphicBuffer field of buffer is set to
+    // NULL and it is assumed that the consumer still holds a reference to the
+    // buffer.
+    //
+    // If presentWhen is non-zero, 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.
+    //
+    // Return of NO_ERROR means the operation completed as normal.
+    //
+    // Return of a positive value means the operation could not be completed
+    //    at this time, but the user should try again later:
+    // * NO_BUFFER_AVAILABLE - no buffer is pending (nothing queued by producer)
+    // * PRESENT_LATER - the buffer's timestamp is farther in the future
+    //
+    // Return of a negative value means an error has occurred:
+    // * INVALID_OPERATION - too many buffers have been acquired
+    virtual status_t acquireBuffer(BufferItem* buffer, nsecs_t presentWhen) = 0;
+
+    // detachBuffer attempts to remove all ownership of the buffer in the given
+    // slot from the buffer queue. If this call succeeds, the slot will be
+    // freed, and there will be no way to obtain the buffer from this interface.
+    // The freed slot will remain unallocated until either it is selected to
+    // hold a freshly allocated buffer in dequeueBuffer or a buffer is attached
+    // to the slot. The buffer must have already been acquired.
+    //
+    // Return of a value other than NO_ERROR means an error has occurred:
+    // * BAD_VALUE - the given slot number is invalid, either because it is
+    //               out of the range [0, NUM_BUFFER_SLOTS) or because the slot
+    //               it refers to is not currently acquired.
+    virtual status_t detachBuffer(int slot) = 0;
+
+    // attachBuffer attempts to transfer ownership of a buffer to the buffer
+    // queue. If this call succeeds, it will be as if this buffer was acquired
+    // from the returned slot number. As such, this call will fail if attaching
+    // this buffer would cause too many buffers to be simultaneously acquired.
+    //
+    // If the buffer is successfully attached, its frameNumber is initialized
+    // to 0. This must be passed into the releaseBuffer call or else the buffer
+    // will be deallocated as stale.
+    //
+    // Return of a value other than NO_ERROR means an error has occurred:
+    // * BAD_VALUE - outSlot or buffer were NULL
+    // * INVALID_OPERATION - cannot attach the buffer because it would cause too
+    //                       many buffers to be acquired.
+    // * NO_MEMORY - no free slots available
+    virtual status_t attachBuffer(int *outSlot,
+            const sp<GraphicBuffer>& buffer) = 0;
+
+    // releaseBuffer releases a buffer slot from the consumer back to the
+    // BufferQueue.  This may be done while the buffer's contents are still
+    // being accessed.  The fence will signal when the buffer is no longer
+    // 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.
+    //
+    // Return of NO_ERROR means the operation completed as normal.
+    //
+    // Return of a positive value means the operation could not be completed
+    //    at this time, but the user should try again later:
+    // * STALE_BUFFER_SLOT - see above (second paragraph)
+    //
+    // Return of a negative value means an error has occurred:
+    // * BAD_VALUE - one of the following could've happened:
+    //               * the buffer slot was invalid
+    //               * the fence was NULL
+    //               * the buffer slot specified is not in the acquired state
+    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.
+    //
+    // Return of a value other than NO_ERROR means an error has occurred:
+    // * NO_INIT - the buffer queue has been abandoned
+    // * BAD_VALUE - a NULL consumer was provided
+    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.
+    //
+    // Return of a value other than NO_ERROR means an error has occurred:
+    // * BAD_VALUE - no consumer is currently connected
+    virtual status_t consumerDisconnect() = 0;
+
+    // getReleasedBuffers sets the value pointed to by slotMask to a bit set.
+    // Each bit index with a 1 corresponds to a released buffer slot with that
+    // index value.  In particular, a released buffer is one that has
+    // been released by the BufferQueue but have not yet been released by the consumer.
+    //
+    // This should be called from the onBuffersReleased() callback.
+    //
+    // Return of a value other than NO_ERROR means an error has occurred:
+    // * NO_INIT - the buffer queue has been abandoned.
+    virtual status_t getReleasedBuffers(uint64_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.
+    //
+    // Return of a value other than NO_ERROR means an error has occurred:
+    // * BAD_VALUE - either w or h was zero
+    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.
+    //
+    // Return of a value other than NO_ERROR means an error has occurred:
+    // * BAD_VALUE - bufferCount was out of range (see above).
+    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().
+    //
+    // Return of a value other than NO_ERROR means an error has occurred:
+    // * INVALID_OPERATION - attempting to call this after 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.
+    //
+    // maxAcquiredBuffers must be (inclusive) between 1 and MAX_MAX_ACQUIRED_BUFFERS.
+    //
+    // Return of a value other than NO_ERROR means an error has occurred:
+    // * BAD_VALUE - maxAcquiredBuffers was out of range (see above).
+    // * INVALID_OPERATION - attempting to call this after a producer connected.
+    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.
+    //
+    // Return of a value other than NO_ERROR means an unknown error has occurred.
+    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.
+    //
+    // Return of a value other than NO_ERROR means an unknown error has occurred.
+    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).
+    //
+    // Return of a value other than NO_ERROR means an unknown error has occurred.
+    virtual status_t setTransformHint(uint32_t hint) = 0;
+
+    // Retrieve the sideband buffer stream, if any.
+    virtual sp<NativeHandle> getSidebandStream() const = 0;
+
+    // dump state into a string
+    virtual void dump(String8& result, const char* prefix) const = 0;
+
+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