Merge "a window could get stuck to gpu composition"
diff --git a/include/binder/CursorWindow.h b/include/binder/CursorWindow.h
deleted file mode 100644
index 8a2979a..0000000
--- a/include/binder/CursorWindow.h
+++ /dev/null
@@ -1,193 +0,0 @@
-/*
- * Copyright (C) 2006 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__DATABASE_WINDOW_H
-#define _ANDROID__DATABASE_WINDOW_H
-
-#include <cutils/log.h>
-#include <stddef.h>
-#include <stdint.h>
-
-#include <binder/Parcel.h>
-#include <utils/String8.h>
-
-#if LOG_NDEBUG
-
-#define IF_LOG_WINDOW() if (false)
-#define LOG_WINDOW(...)
-
-#else
-
-#define IF_LOG_WINDOW() IF_ALOG(LOG_DEBUG, "CursorWindow")
-#define LOG_WINDOW(...) ALOG(LOG_DEBUG, "CursorWindow", __VA_ARGS__)
-
-#endif
-
-namespace android {
-
-/**
- * This class stores a set of rows from a database in a buffer. The begining of the
- * window has first chunk of RowSlots, which are offsets to the row directory, followed by
- * an offset to the next chunk in a linked-list of additional chunk of RowSlots in case
- * the pre-allocated chunk isn't big enough to refer to all rows. Each row directory has a
- * FieldSlot per column, which has the size, offset, and type of the data for that field.
- * Note that the data types come from sqlite3.h.
- *
- * Strings are stored in UTF-8.
- */
-class CursorWindow {
-    CursorWindow(const String8& name, int ashmemFd,
-            void* data, size_t size, bool readOnly);
-
-public:
-    /* Field types. */
-    enum {
-        FIELD_TYPE_NULL = 0,
-        FIELD_TYPE_INTEGER = 1,
-        FIELD_TYPE_FLOAT = 2,
-        FIELD_TYPE_STRING = 3,
-        FIELD_TYPE_BLOB = 4,
-    };
-
-    /* Opaque type that describes a field slot. */
-    struct FieldSlot {
-    private:
-        int32_t type;
-        union {
-            double d;
-            int64_t l;
-            struct {
-                uint32_t offset;
-                uint32_t size;
-            } buffer;
-        } data;
-
-        friend class CursorWindow;
-    } __attribute((packed));
-
-    ~CursorWindow();
-
-    static status_t create(const String8& name, size_t size, CursorWindow** outCursorWindow);
-    static status_t createFromParcel(Parcel* parcel, CursorWindow** outCursorWindow);
-
-    status_t writeToParcel(Parcel* parcel);
-
-    inline String8 name() { return mName; }
-    inline size_t size() { return mSize; }
-    inline size_t freeSpace() { return mSize - mHeader->freeOffset; }
-    inline uint32_t getNumRows() { return mHeader->numRows; }
-    inline uint32_t getNumColumns() { return mHeader->numColumns; }
-
-    status_t clear();
-    status_t setNumColumns(uint32_t numColumns);
-
-    /**
-     * Allocate a row slot and its directory.
-     * The row is initialized will null entries for each field.
-     */
-    status_t allocRow();
-    status_t freeLastRow();
-
-    status_t putBlob(uint32_t row, uint32_t column, const void* value, size_t size);
-    status_t putString(uint32_t row, uint32_t column, const char* value, size_t sizeIncludingNull);
-    status_t putLong(uint32_t row, uint32_t column, int64_t value);
-    status_t putDouble(uint32_t row, uint32_t column, double value);
-    status_t putNull(uint32_t row, uint32_t column);
-
-    /**
-     * Gets the field slot at the specified row and column.
-     * Returns null if the requested row or column is not in the window.
-     */
-    FieldSlot* getFieldSlot(uint32_t row, uint32_t column);
-
-    inline int32_t getFieldSlotType(FieldSlot* fieldSlot) {
-        return fieldSlot->type;
-    }
-
-    inline int64_t getFieldSlotValueLong(FieldSlot* fieldSlot) {
-        return fieldSlot->data.l;
-    }
-
-    inline double getFieldSlotValueDouble(FieldSlot* fieldSlot) {
-        return fieldSlot->data.d;
-    }
-
-    inline const char* getFieldSlotValueString(FieldSlot* fieldSlot,
-            size_t* outSizeIncludingNull) {
-        *outSizeIncludingNull = fieldSlot->data.buffer.size;
-        return static_cast<char*>(offsetToPtr(fieldSlot->data.buffer.offset));
-    }
-
-    inline const void* getFieldSlotValueBlob(FieldSlot* fieldSlot, size_t* outSize) {
-        *outSize = fieldSlot->data.buffer.size;
-        return offsetToPtr(fieldSlot->data.buffer.offset);
-    }
-
-private:
-    static const size_t ROW_SLOT_CHUNK_NUM_ROWS = 100;
-
-    struct Header {
-        // Offset of the lowest unused byte in the window.
-        uint32_t freeOffset;
-
-        // Offset of the first row slot chunk.
-        uint32_t firstChunkOffset;
-
-        uint32_t numRows;
-        uint32_t numColumns;
-    };
-
-    struct RowSlot {
-        uint32_t offset;
-    };
-
-    struct RowSlotChunk {
-        RowSlot slots[ROW_SLOT_CHUNK_NUM_ROWS];
-        uint32_t nextChunkOffset;
-    };
-
-    String8 mName;
-    int mAshmemFd;
-    void* mData;
-    size_t mSize;
-    bool mReadOnly;
-    Header* mHeader;
-
-    inline void* offsetToPtr(uint32_t offset) {
-        return static_cast<uint8_t*>(mData) + offset;
-    }
-
-    inline uint32_t offsetFromPtr(void* ptr) {
-        return static_cast<uint8_t*>(ptr) - static_cast<uint8_t*>(mData);
-    }
-
-    /**
-     * Allocate a portion of the window. Returns the offset
-     * of the allocation, or 0 if there isn't enough space.
-     * If aligned is true, the allocation gets 4 byte alignment.
-     */
-    uint32_t alloc(size_t size, bool aligned = false);
-
-    RowSlot* getRowSlot(uint32_t row);
-    RowSlot* allocRowSlot();
-
-    status_t putBlobOrString(uint32_t row, uint32_t column,
-            const void* value, size_t size, int32_t type);
-};
-
-}; // namespace android
-
-#endif
diff --git a/include/gui/BufferQueue.h b/include/gui/BufferQueue.h
index dd1558c..8c21a28 100644
--- a/include/gui/BufferQueue.h
+++ b/include/gui/BufferQueue.h
@@ -40,6 +40,7 @@
     };
     enum { NUM_BUFFER_SLOTS = 32 };
     enum { NO_CONNECTED_API = 0 };
+    enum { INVALID_BUFFER_SLOT = -1 };
 
     struct FrameAvailableListener : public virtual RefBase {
         // onFrameAvailable() is called from queueBuffer() each time an
@@ -119,8 +120,91 @@
     // connected to the specified client API.
     virtual status_t disconnect(int api);
 
-protected:
+    // dump our state in a String
+    virtual void dump(String8& result) const;
+    virtual void dump(String8& result, const char* prefix, char* buffer, size_t SIZE) const;
 
+    // public facing structure for BufferSlot
+    struct BufferItem {
+
+        BufferItem()
+         :
+           mTransform(0),
+           mScalingMode(NATIVE_WINDOW_SCALING_MODE_FREEZE),
+           mTimestamp(0),
+           mFrameNumber(0),
+           mBuf(INVALID_BUFFER_SLOT) {
+             mCrop.makeInvalid();
+         }
+        // mGraphicBuffer points to the buffer allocated for this slot or is NULL
+        // if no buffer has been allocated.
+        sp<GraphicBuffer> mGraphicBuffer;
+
+        // mCrop is the current crop rectangle for this buffer slot. This gets
+        // set to mNextCrop each time queueBuffer gets called for this buffer.
+        Rect mCrop;
+
+        // mTransform is the current transform flags for this buffer slot. This
+        // gets set to mNextTransform each time queueBuffer gets called for this
+        // slot.
+        uint32_t mTransform;
+
+        // mScalingMode is the current scaling mode for this buffer slot. This
+        // gets set to mNextScalingMode each time queueBuffer gets called for
+        // this slot.
+        uint32_t mScalingMode;
+
+        // mTimestamp is the current timestamp for this buffer slot. This gets
+        // to set by queueBuffer each time this slot is queued.
+        int64_t mTimestamp;
+
+        // mFrameNumber is the number of the queued frame for this slot.
+        uint64_t mFrameNumber;
+
+        // buf is the slot index of this buffer
+        int mBuf;
+
+    };
+
+    // The following public functions is the consumer facing interface
+
+    // acquire consumes a buffer by transferring its ownership to a consumer.
+    // buffer contains the GraphicBuffer and its corresponding information.
+    // buffer.mGraphicsBuffer will be NULL when the buffer has been already
+    // acquired by the consumer.
+
+    status_t acquire(BufferItem *buffer);
+
+    // releaseBuffer releases a buffer slot from the consumer back to the
+    // BufferQueue pending a fence sync.
+    status_t releaseBuffer(int buf, EGLDisplay display, EGLSyncKHR fence);
+
+    // consumerDisconnect disconnects a consumer from the BufferQueue. All
+    // buffers will be freed.
+    status_t consumerDisconnect();
+
+    // setDefaultBufferSize is used to set the size of buffers returned by
+    // requestBuffers when a with and height of zero is requested.
+    status_t setDefaultBufferSize(uint32_t w, uint32_t h);
+
+    // setBufferCountServer set the buffer count. If the client has requested
+    // a buffer count using setBufferCount, the server-buffer count will
+    // take effect once the client sets the count back to zero.
+    status_t setBufferCountServer(int bufferCount);
+
+    // isSynchronousMode returns whether the SurfaceTexture is currently in
+    // synchronous mode.
+    bool isSynchronousMode() const;
+
+    // setConsumerName sets the name used in logging
+    void setConsumerName(const String8& name);
+
+    // setFrameAvailableListener sets the listener object that will be notified
+    // when a new frame becomes available.
+    void setFrameAvailableListener(const sp<FrameAvailableListener>& listener);
+
+
+private:
     // freeBufferLocked frees the resources (both GraphicBuffer and EGLImage)
     // for the given slot.
     void freeBufferLocked(int index);
@@ -145,20 +229,18 @@
 
     status_t setBufferCountServerLocked(int bufferCount);
 
-    enum { INVALID_BUFFER_SLOT = -1 };
-
     struct BufferSlot {
 
         BufferSlot()
-        : mEglImage(EGL_NO_IMAGE_KHR),
-          mEglDisplay(EGL_NO_DISPLAY),
+        : mEglDisplay(EGL_NO_DISPLAY),
           mBufferState(BufferSlot::FREE),
           mRequestBufferCalled(false),
           mTransform(0),
           mScalingMode(NATIVE_WINDOW_SCALING_MODE_FREEZE),
           mTimestamp(0),
           mFrameNumber(0),
-          mFence(EGL_NO_SYNC_KHR) {
+          mFence(EGL_NO_SYNC_KHR),
+          mAcquireCalled(false) {
             mCrop.makeInvalid();
         }
 
@@ -166,9 +248,6 @@
         // if no buffer has been allocated.
         sp<GraphicBuffer> mGraphicBuffer;
 
-        // mEglImage is the EGLImage created from mGraphicBuffer.
-        EGLImageKHR mEglImage;
-
         // mEglDisplay is the EGLDisplay used to create mEglImage.
         EGLDisplay mEglDisplay;
 
@@ -178,6 +257,7 @@
             // FREE indicates that the buffer is not currently being used and
             // will not be used in the future until it gets dequeued and
             // subsequently queued by the client.
+            // aka "owned by BufferQueue, ready to be dequeued"
             FREE = 0,
 
             // DEQUEUED indicates that the buffer has been dequeued by the
@@ -190,6 +270,7 @@
             // dequeued by the client.  That means that the current buffer can
             // be in either the DEQUEUED or QUEUED state.  In asynchronous mode,
             // however, the current buffer is always in the QUEUED state.
+            // aka "owned by producer, ready to be queued"
             DEQUEUED = 1,
 
             // QUEUED indicates that the buffer has been queued by the client,
@@ -199,7 +280,11 @@
             // the current buffer may be dequeued by the client under some
             // circumstances. See the note about the current buffer in the
             // documentation for DEQUEUED.
+            // aka "owned by BufferQueue, ready to be acquired"
             QUEUED = 2,
+
+            // aka "owned by consumer, ready to be released"
+            ACQUIRED = 3
         };
 
         // mBufferState is the current state of this buffer slot.
@@ -236,6 +321,9 @@
         // to EGL_NO_SYNC_KHR when the buffer is created and (optionally, based
         // on a compile-time option) set to a new sync object in updateTexImage.
         EGLSyncKHR mFence;
+
+        // Indicates whether this buffer has been seen by a consumer yet
+        bool mAcquireCalled;
     };
 
     // mSlots is the array of buffer slots that must be mirrored on the client
@@ -245,7 +333,6 @@
     // for a slot when requestBuffer is called with that slot's index.
     BufferSlot mSlots[NUM_BUFFER_SLOTS];
 
-
     // mDefaultWidth holds the default width of allocated buffers. It is used
     // in requestBuffers() if a width and height of zero is specified.
     uint32_t mDefaultWidth;
@@ -271,14 +358,6 @@
     // mServerBufferCount buffer count requested by the server-side
     int mServerBufferCount;
 
-    // mCurrentTexture is the buffer slot index of the buffer that is currently
-    // bound to the OpenGL texture. It is initialized to INVALID_BUFFER_SLOT,
-    // indicating that no buffer slot is currently bound to the texture. Note,
-    // however, that a value of INVALID_BUFFER_SLOT does not necessarily mean
-    // that no buffer is bound to the texture. A call to setBufferCount will
-    // reset mCurrentTexture to INVALID_BUFFER_SLOT.
-    int mCurrentTexture;
-
     // mNextCrop is the crop rectangle that will be used for the next buffer
     // that gets queued. It is set by calling setCrop.
     Rect mNextCrop;
@@ -327,7 +406,7 @@
 
     // mName is a string used to identify the BufferQueue in log messages.
     // It is set by the setName method.
-    String8 mName;
+    String8 mConsumerName;
 
     // mMutex is the mutex used to prevent concurrent access to the member
     // variables of BufferQueue objects. It must be locked whenever the
@@ -337,6 +416,8 @@
     // mFrameCounter is the free running counter, incremented for every buffer queued
     // with the surface Texture.
     uint64_t mFrameCounter;
+
+    bool mBufferHasBeenQueued;
 };
 
 // ----------------------------------------------------------------------------
diff --git a/include/gui/SurfaceTexture.h b/include/gui/SurfaceTexture.h
index dcab049..5531e53 100644
--- a/include/gui/SurfaceTexture.h
+++ b/include/gui/SurfaceTexture.h
@@ -153,8 +153,8 @@
     void setName(const String8& name);
 
     // dump our state in a String
-    void dump(String8& result) const;
-    void dump(String8& result, const char* prefix, char* buffer, size_t SIZE) const;
+    virtual void dump(String8& result) const;
+    virtual void dump(String8& result, const char* prefix, char* buffer, size_t SIZE) const;
 
 protected:
 
@@ -217,6 +217,56 @@
     // browser's tile cache exceeds.
     const GLenum mTexTarget;
 
+    // SurfaceTexture maintains EGL information about GraphicBuffers that corresponds
+    // directly with BufferQueue's buffers
+    struct EGLSlot {
+        EGLSlot()
+        : mEglImage(EGL_NO_IMAGE_KHR),
+          mEglDisplay(EGL_NO_DISPLAY),
+          mFence(EGL_NO_SYNC_KHR) {
+        }
+
+        sp<GraphicBuffer> mGraphicBuffer;
+
+        // mEglImage is the EGLImage created from mGraphicBuffer.
+        EGLImageKHR mEglImage;
+
+        // mEglDisplay is the EGLDisplay used to create mEglImage.
+        EGLDisplay mEglDisplay;
+
+        // mFence 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 (optionally, based
+        // on a compile-time option) set to a new sync object in updateTexImage.
+        EGLSyncKHR mFence;
+    };
+
+    EGLSlot mEGLSlots[NUM_BUFFER_SLOTS];
+
+    // mAbandoned indicates that the BufferQueue will no longer be used to
+    // consume images buffers pushed to it using the ISurfaceTexture interface.
+    // It is initialized to false, and set to true in the abandon method.  A
+    // BufferQueue that has been abandoned will return the NO_INIT error from
+    // all ISurfaceTexture methods capable of returning an error.
+    bool mAbandoned;
+
+    // mName is a string used to identify the SurfaceTexture in log messages.
+    // It can be set by the setName method.
+    String8 mName;
+
+    // mMutex is the mutex used to prevent concurrent access to the member
+    // variables of SurfaceTexture objects. It must be locked whenever the
+    // member variables are accessed.
+    mutable Mutex mMutex;
+
+    // mCurrentTexture is the buffer slot index of the buffer that is currently
+    // bound to the OpenGL texture. It is initialized to INVALID_BUFFER_SLOT,
+    // indicating that no buffer slot is currently bound to the texture. Note,
+    // however, that a value of INVALID_BUFFER_SLOT does not necessarily mean
+    // that no buffer is bound to the texture. A call to setBufferCount will
+    // reset mCurrentTexture to INVALID_BUFFER_SLOT.
+    int mCurrentTexture;
+
 };
 
 // ----------------------------------------------------------------------------
diff --git a/libs/binder/Android.mk b/libs/binder/Android.mk
index 3a12e96..fd116b7 100644
--- a/libs/binder/Android.mk
+++ b/libs/binder/Android.mk
@@ -16,7 +16,6 @@
 sources := \
     Binder.cpp \
     BpBinder.cpp \
-    CursorWindow.cpp \
     IInterface.cpp \
     IMemory.cpp \
     IPCThreadState.cpp \
diff --git a/libs/binder/CursorWindow.cpp b/libs/binder/CursorWindow.cpp
deleted file mode 100644
index a6e5f71..0000000
--- a/libs/binder/CursorWindow.cpp
+++ /dev/null
@@ -1,351 +0,0 @@
-/*
- * Copyright (C) 2006-2007 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.
- */
-
-#undef LOG_TAG
-#define LOG_TAG "CursorWindow"
-
-#include <utils/Log.h>
-#include <binder/CursorWindow.h>
-
-#include <cutils/ashmem.h>
-#include <sys/mman.h>
-
-#include <assert.h>
-#include <string.h>
-#include <stdlib.h>
-
-namespace android {
-
-CursorWindow::CursorWindow(const String8& name, int ashmemFd,
-        void* data, size_t size, bool readOnly) :
-        mName(name), mAshmemFd(ashmemFd), mData(data), mSize(size), mReadOnly(readOnly) {
-    mHeader = static_cast<Header*>(mData);
-}
-
-CursorWindow::~CursorWindow() {
-    ::munmap(mData, mSize);
-    ::close(mAshmemFd);
-}
-
-status_t CursorWindow::create(const String8& name, size_t size, CursorWindow** outCursorWindow) {
-    String8 ashmemName("CursorWindow: ");
-    ashmemName.append(name);
-
-    status_t result;
-    int ashmemFd = ashmem_create_region(ashmemName.string(), size);
-    if (ashmemFd < 0) {
-        result = -errno;
-    } else {
-        result = ashmem_set_prot_region(ashmemFd, PROT_READ | PROT_WRITE);
-        if (result >= 0) {
-            void* data = ::mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, ashmemFd, 0);
-            if (data == MAP_FAILED) {
-                result = -errno;
-            } else {
-                result = ashmem_set_prot_region(ashmemFd, PROT_READ);
-                if (result >= 0) {
-                    CursorWindow* window = new CursorWindow(name, ashmemFd,
-                            data, size, false /*readOnly*/);
-                    result = window->clear();
-                    if (!result) {
-                        LOG_WINDOW("Created new CursorWindow: freeOffset=%d, "
-                                "numRows=%d, numColumns=%d, mSize=%d, mData=%p",
-                                window->mHeader->freeOffset,
-                                window->mHeader->numRows,
-                                window->mHeader->numColumns,
-                                window->mSize, window->mData);
-                        *outCursorWindow = window;
-                        return OK;
-                    }
-                    delete window;
-                }
-            }
-            ::munmap(data, size);
-        }
-        ::close(ashmemFd);
-    }
-    *outCursorWindow = NULL;
-    return result;
-}
-
-status_t CursorWindow::createFromParcel(Parcel* parcel, CursorWindow** outCursorWindow) {
-    String8 name = parcel->readString8();
-
-    status_t result;
-    int ashmemFd = parcel->readFileDescriptor();
-    if (ashmemFd == int(BAD_TYPE)) {
-        result = BAD_TYPE;
-    } else {
-        ssize_t size = ashmem_get_size_region(ashmemFd);
-        if (size < 0) {
-            result = UNKNOWN_ERROR;
-        } else {
-            int dupAshmemFd = ::dup(ashmemFd);
-            if (dupAshmemFd < 0) {
-                result = -errno;
-            } else {
-                void* data = ::mmap(NULL, size, PROT_READ, MAP_SHARED, dupAshmemFd, 0);
-                if (data == MAP_FAILED) {
-                    result = -errno;
-                } else {
-                    CursorWindow* window = new CursorWindow(name, dupAshmemFd,
-                            data, size, true /*readOnly*/);
-                    LOG_WINDOW("Created CursorWindow from parcel: freeOffset=%d, "
-                            "numRows=%d, numColumns=%d, mSize=%d, mData=%p",
-                            window->mHeader->freeOffset,
-                            window->mHeader->numRows,
-                            window->mHeader->numColumns,
-                            window->mSize, window->mData);
-                    *outCursorWindow = window;
-                    return OK;
-                }
-                ::close(dupAshmemFd);
-            }
-        }
-    }
-    *outCursorWindow = NULL;
-    return result;
-}
-
-status_t CursorWindow::writeToParcel(Parcel* parcel) {
-    status_t status = parcel->writeString8(mName);
-    if (!status) {
-        status = parcel->writeDupFileDescriptor(mAshmemFd);
-    }
-    return status;
-}
-
-status_t CursorWindow::clear() {
-    if (mReadOnly) {
-        return INVALID_OPERATION;
-    }
-
-    mHeader->freeOffset = sizeof(Header) + sizeof(RowSlotChunk);
-    mHeader->firstChunkOffset = sizeof(Header);
-    mHeader->numRows = 0;
-    mHeader->numColumns = 0;
-
-    RowSlotChunk* firstChunk = static_cast<RowSlotChunk*>(offsetToPtr(mHeader->firstChunkOffset));
-    firstChunk->nextChunkOffset = 0;
-    return OK;
-}
-
-status_t CursorWindow::setNumColumns(uint32_t numColumns) {
-    if (mReadOnly) {
-        return INVALID_OPERATION;
-    }
-
-    uint32_t cur = mHeader->numColumns;
-    if ((cur > 0 || mHeader->numRows > 0) && cur != numColumns) {
-        ALOGE("Trying to go from %d columns to %d", cur, numColumns);
-        return INVALID_OPERATION;
-    }
-    mHeader->numColumns = numColumns;
-    return OK;
-}
-
-status_t CursorWindow::allocRow() {
-    if (mReadOnly) {
-        return INVALID_OPERATION;
-    }
-
-    // Fill in the row slot
-    RowSlot* rowSlot = allocRowSlot();
-    if (rowSlot == NULL) {
-        return NO_MEMORY;
-    }
-
-    // Allocate the slots for the field directory
-    size_t fieldDirSize = mHeader->numColumns * sizeof(FieldSlot);
-    uint32_t fieldDirOffset = alloc(fieldDirSize, true /*aligned*/);
-    if (!fieldDirOffset) {
-        mHeader->numRows--;
-        LOG_WINDOW("The row failed, so back out the new row accounting "
-                "from allocRowSlot %d", mHeader->numRows);
-        return NO_MEMORY;
-    }
-    FieldSlot* fieldDir = static_cast<FieldSlot*>(offsetToPtr(fieldDirOffset));
-    memset(fieldDir, 0, fieldDirSize);
-
-    LOG_WINDOW("Allocated row %u, rowSlot is at offset %u, fieldDir is %d bytes at offset %u\n",
-            mHeader->numRows - 1, offsetFromPtr(rowSlot), fieldDirSize, fieldDirOffset);
-    rowSlot->offset = fieldDirOffset;
-    return OK;
-}
-
-status_t CursorWindow::freeLastRow() {
-    if (mReadOnly) {
-        return INVALID_OPERATION;
-    }
-
-    if (mHeader->numRows > 0) {
-        mHeader->numRows--;
-    }
-    return OK;
-}
-
-uint32_t CursorWindow::alloc(size_t size, bool aligned) {
-    uint32_t padding;
-    if (aligned) {
-        // 4 byte alignment
-        padding = (~mHeader->freeOffset + 1) & 3;
-    } else {
-        padding = 0;
-    }
-
-    uint32_t offset = mHeader->freeOffset + padding;
-    uint32_t nextFreeOffset = offset + size;
-    if (nextFreeOffset > mSize) {
-        ALOGW("Window is full: requested allocation %d bytes, "
-                "free space %d bytes, window size %d bytes",
-                size, freeSpace(), mSize);
-        return 0;
-    }
-
-    mHeader->freeOffset = nextFreeOffset;
-    return offset;
-}
-
-CursorWindow::RowSlot* CursorWindow::getRowSlot(uint32_t row) {
-    uint32_t chunkPos = row;
-    RowSlotChunk* chunk = static_cast<RowSlotChunk*>(
-            offsetToPtr(mHeader->firstChunkOffset));
-    while (chunkPos >= ROW_SLOT_CHUNK_NUM_ROWS) {
-        chunk = static_cast<RowSlotChunk*>(offsetToPtr(chunk->nextChunkOffset));
-        chunkPos -= ROW_SLOT_CHUNK_NUM_ROWS;
-    }
-    return &chunk->slots[chunkPos];
-}
-
-CursorWindow::RowSlot* CursorWindow::allocRowSlot() {
-    uint32_t chunkPos = mHeader->numRows;
-    RowSlotChunk* chunk = static_cast<RowSlotChunk*>(
-            offsetToPtr(mHeader->firstChunkOffset));
-    while (chunkPos > ROW_SLOT_CHUNK_NUM_ROWS) {
-        chunk = static_cast<RowSlotChunk*>(offsetToPtr(chunk->nextChunkOffset));
-        chunkPos -= ROW_SLOT_CHUNK_NUM_ROWS;
-    }
-    if (chunkPos == ROW_SLOT_CHUNK_NUM_ROWS) {
-        if (!chunk->nextChunkOffset) {
-            chunk->nextChunkOffset = alloc(sizeof(RowSlotChunk), true /*aligned*/);
-            if (!chunk->nextChunkOffset) {
-                return NULL;
-            }
-        }
-        chunk = static_cast<RowSlotChunk*>(offsetToPtr(chunk->nextChunkOffset));
-        chunk->nextChunkOffset = 0;
-        chunkPos = 0;
-    }
-    mHeader->numRows += 1;
-    return &chunk->slots[chunkPos];
-}
-
-CursorWindow::FieldSlot* CursorWindow::getFieldSlot(uint32_t row, uint32_t column) {
-    if (row >= mHeader->numRows || column >= mHeader->numColumns) {
-        ALOGE("Failed to read row %d, column %d from a CursorWindow which "
-                "has %d rows, %d columns.",
-                row, column, mHeader->numRows, mHeader->numColumns);
-        return NULL;
-    }
-    RowSlot* rowSlot = getRowSlot(row);
-    if (!rowSlot) {
-        ALOGE("Failed to find rowSlot for row %d.", row);
-        return NULL;
-    }
-    FieldSlot* fieldDir = static_cast<FieldSlot*>(offsetToPtr(rowSlot->offset));
-    return &fieldDir[column];
-}
-
-status_t CursorWindow::putBlob(uint32_t row, uint32_t column, const void* value, size_t size) {
-    return putBlobOrString(row, column, value, size, FIELD_TYPE_BLOB);
-}
-
-status_t CursorWindow::putString(uint32_t row, uint32_t column, const char* value,
-        size_t sizeIncludingNull) {
-    return putBlobOrString(row, column, value, sizeIncludingNull, FIELD_TYPE_STRING);
-}
-
-status_t CursorWindow::putBlobOrString(uint32_t row, uint32_t column,
-        const void* value, size_t size, int32_t type) {
-    if (mReadOnly) {
-        return INVALID_OPERATION;
-    }
-
-    FieldSlot* fieldSlot = getFieldSlot(row, column);
-    if (!fieldSlot) {
-        return BAD_VALUE;
-    }
-
-    uint32_t offset = alloc(size);
-    if (!offset) {
-        return NO_MEMORY;
-    }
-
-    memcpy(offsetToPtr(offset), value, size);
-
-    fieldSlot->type = type;
-    fieldSlot->data.buffer.offset = offset;
-    fieldSlot->data.buffer.size = size;
-    return OK;
-}
-
-status_t CursorWindow::putLong(uint32_t row, uint32_t column, int64_t value) {
-    if (mReadOnly) {
-        return INVALID_OPERATION;
-    }
-
-    FieldSlot* fieldSlot = getFieldSlot(row, column);
-    if (!fieldSlot) {
-        return BAD_VALUE;
-    }
-
-    fieldSlot->type = FIELD_TYPE_INTEGER;
-    fieldSlot->data.l = value;
-    return OK;
-}
-
-status_t CursorWindow::putDouble(uint32_t row, uint32_t column, double value) {
-    if (mReadOnly) {
-        return INVALID_OPERATION;
-    }
-
-    FieldSlot* fieldSlot = getFieldSlot(row, column);
-    if (!fieldSlot) {
-        return BAD_VALUE;
-    }
-
-    fieldSlot->type = FIELD_TYPE_FLOAT;
-    fieldSlot->data.d = value;
-    return OK;
-}
-
-status_t CursorWindow::putNull(uint32_t row, uint32_t column) {
-    if (mReadOnly) {
-        return INVALID_OPERATION;
-    }
-
-    FieldSlot* fieldSlot = getFieldSlot(row, column);
-    if (!fieldSlot) {
-        return BAD_VALUE;
-    }
-
-    fieldSlot->type = FIELD_TYPE_NULL;
-    fieldSlot->data.buffer.offset = 0;
-    fieldSlot->data.buffer.size = 0;
-    return OK;
-}
-
-}; // namespace android
diff --git a/libs/gui/BufferQueue.cpp b/libs/gui/BufferQueue.cpp
index 261336a..d761680 100644
--- a/libs/gui/BufferQueue.cpp
+++ b/libs/gui/BufferQueue.cpp
@@ -15,6 +15,8 @@
  */
 
 #define LOG_TAG "BufferQueue"
+//#define LOG_NDEBUG 0
+#define ATRACE_TAG ATRACE_TAG_GRAPHICS
 
 #define GL_GLEXT_PROTOTYPES
 #define EGL_EGLEXT_PROTOTYPES
@@ -27,6 +29,8 @@
 #include <private/gui/ComposerService.h>
 
 #include <utils/Log.h>
+#include <gui/SurfaceTexture.h>
+#include <utils/Trace.h>
 
 // This compile option causes SurfaceTexture to return the buffer that is currently
 // attached to the GL texture from dequeueBuffer when no other buffers are
@@ -34,6 +38,10 @@
 // implicit cross-process synchronization to prevent the buffer from being
 // written to before the buffer has (a) been detached from the GL texture and
 // (b) all GL reads from the buffer have completed.
+
+// During refactoring, do not support dequeuing the current buffer
+#undef ALLOW_DEQUEUE_CURRENT_BUFFER
+
 #ifdef ALLOW_DEQUEUE_CURRENT_BUFFER
 #define FLAG_ALLOW_DEQUEUE_CURRENT_BUFFER    true
 #warning "ALLOW_DEQUEUE_CURRENT_BUFFER enabled"
@@ -42,11 +50,11 @@
 #endif
 
 // Macros for including the BufferQueue name in log messages
-#define ST_LOGV(x, ...) ALOGV("[%s] "x, mName.string(), ##__VA_ARGS__)
-#define ST_LOGD(x, ...) ALOGD("[%s] "x, mName.string(), ##__VA_ARGS__)
-#define ST_LOGI(x, ...) ALOGI("[%s] "x, mName.string(), ##__VA_ARGS__)
-#define ST_LOGW(x, ...) ALOGW("[%s] "x, mName.string(), ##__VA_ARGS__)
-#define ST_LOGE(x, ...) ALOGE("[%s] "x, mName.string(), ##__VA_ARGS__)
+#define ST_LOGV(x, ...) ALOGV("[%s] "x, mConsumerName.string(), ##__VA_ARGS__)
+#define ST_LOGD(x, ...) ALOGD("[%s] "x, mConsumerName.string(), ##__VA_ARGS__)
+#define ST_LOGI(x, ...) ALOGI("[%s] "x, mConsumerName.string(), ##__VA_ARGS__)
+#define ST_LOGW(x, ...) ALOGW("[%s] "x, mConsumerName.string(), ##__VA_ARGS__)
+#define ST_LOGE(x, ...) ALOGE("[%s] "x, mConsumerName.string(), ##__VA_ARGS__)
 
 namespace android {
 
@@ -63,17 +71,17 @@
     mBufferCount(MIN_ASYNC_BUFFER_SLOTS),
     mClientBufferCount(0),
     mServerBufferCount(MIN_ASYNC_BUFFER_SLOTS),
-    mCurrentTexture(INVALID_BUFFER_SLOT),
     mNextTransform(0),
     mNextScalingMode(NATIVE_WINDOW_SCALING_MODE_FREEZE),
     mSynchronousMode(false),
     mAllowSynchronousMode(allowSynchronousMode),
     mConnectedApi(NO_CONNECTED_API),
     mAbandoned(false),
-    mFrameCounter(0)
+    mFrameCounter(0),
+    mBufferHasBeenQueued(false)
 {
     // Choose a name using the PID and a process-unique ID.
-    mName = String8::format("unnamed-%d-%d", getpid(), createProcessUniqueId());
+    mConsumerName = String8::format("unnamed-%d-%d", getpid(), createProcessUniqueId());
 
     ST_LOGV("BufferQueue");
     sp<ISurfaceComposer> composer(ComposerService::getComposerService());
@@ -119,6 +127,23 @@
     return OK;
 }
 
+bool BufferQueue::isSynchronousMode() const {
+    Mutex::Autolock lock(mMutex);
+    return mSynchronousMode;
+}
+
+void BufferQueue::setConsumerName(const String8& name) {
+    Mutex::Autolock lock(mMutex);
+    mConsumerName = name;
+}
+
+void BufferQueue::setFrameAvailableListener(
+        const sp<FrameAvailableListener>& listener) {
+    ST_LOGV("setFrameAvailableListener");
+    Mutex::Autolock lock(mMutex);
+    mFrameAvailableListener = listener;
+}
+
 status_t BufferQueue::setBufferCount(int bufferCount) {
     ST_LOGV("setBufferCount: count=%d", bufferCount);
     Mutex::Autolock lock(mMutex);
@@ -160,7 +185,7 @@
     freeAllBuffersLocked();
     mBufferCount = bufferCount;
     mClientBufferCount = bufferCount;
-    mCurrentTexture = INVALID_BUFFER_SLOT;
+    mBufferHasBeenQueued = false;
     mQueue.clear();
     mDequeueCondition.signal();
     return OK;
@@ -168,6 +193,7 @@
 
 int BufferQueue::query(int what, int* outValue)
 {
+    ATRACE_CALL();
     Mutex::Autolock lock(mMutex);
 
     if (mAbandoned) {
@@ -198,6 +224,7 @@
 }
 
 status_t BufferQueue::requestBuffer(int slot, sp<GraphicBuffer>* buf) {
+    ATRACE_CALL();
     ST_LOGV("requestBuffer: slot=%d", slot);
     Mutex::Autolock lock(mMutex);
     if (mAbandoned) {
@@ -216,6 +243,7 @@
 
 status_t BufferQueue::dequeueBuffer(int *outBuf, uint32_t w, uint32_t h,
         uint32_t format, uint32_t usage) {
+    ATRACE_CALL();
     ST_LOGV("dequeueBuffer: w=%d h=%d fmt=%#x usage=%#x", w, h, format, usage);
 
     if ((w && !h) || (!w && h)) {
@@ -276,7 +304,7 @@
                 mBufferCount = mServerBufferCount;
                 if (mBufferCount < minBufferCountNeeded)
                     mBufferCount = minBufferCountNeeded;
-                mCurrentTexture = INVALID_BUFFER_SLOT;
+                mBufferHasBeenQueued = false;
                 returnFlags |= ISurfaceTexture::RELEASE_ALL_BUFFERS;
             }
 
@@ -290,19 +318,12 @@
                     dequeuedCount++;
                 }
 
-                // if buffer is FREE it CANNOT be current
-                ALOGW_IF((state == BufferSlot::FREE) && (mCurrentTexture==i),
-                        "dequeueBuffer: buffer %d is both FREE and current!",
-                        i);
-
-                if (FLAG_ALLOW_DEQUEUE_CURRENT_BUFFER) {
-                    if (state == BufferSlot::FREE || i == mCurrentTexture) {
-                        foundSync = i;
-                        if (i != mCurrentTexture) {
-                            found = i;
-                            break;
-                        }
-                    }
+                // this logic used to be if (FLAG_ALLOW_DEQUEUE_CURRENT_BUFFER)
+                // but dequeuing the current buffer is disabled.
+                if (false) {
+                    // This functionality has been temporarily removed so
+                    // BufferQueue and SurfaceTexture can be refactored into
+                    // separate objects
                 } else {
                     if (state == BufferSlot::FREE) {
                         /* We return the oldest of the free buffers to avoid
@@ -331,8 +352,7 @@
             // See whether a buffer has been queued since the last
             // setBufferCount so we know whether to perform the
             // MIN_UNDEQUEUED_BUFFERS check below.
-            bool bufferHasBeenQueued = mCurrentTexture != INVALID_BUFFER_SLOT;
-            if (bufferHasBeenQueued) {
+            if (mBufferHasBeenQueued) {
                 // make sure the client is not trying to dequeue more buffers
                 // than allowed.
                 const int avail = mBufferCount - (dequeuedCount+1);
@@ -404,27 +424,23 @@
             if (updateFormat) {
                 mPixelFormat = format;
             }
+
+            mSlots[buf].mAcquireCalled = false;
             mSlots[buf].mGraphicBuffer = graphicBuffer;
             mSlots[buf].mRequestBufferCalled = false;
             mSlots[buf].mFence = EGL_NO_SYNC_KHR;
-            if (mSlots[buf].mEglImage != EGL_NO_IMAGE_KHR) {
-                eglDestroyImageKHR(mSlots[buf].mEglDisplay,
-                        mSlots[buf].mEglImage);
-                mSlots[buf].mEglImage = EGL_NO_IMAGE_KHR;
-                mSlots[buf].mEglDisplay = EGL_NO_DISPLAY;
-            }
-            if (mCurrentTexture == buf) {
-                // The current texture no longer references the buffer in this slot
-                // since we just allocated a new buffer.
-                mCurrentTexture = INVALID_BUFFER_SLOT;
-            }
+            mSlots[buf].mEglDisplay = EGL_NO_DISPLAY;
+
+
+
+
             returnFlags |= ISurfaceTexture::BUFFER_NEEDS_REALLOCATION;
         }
 
         dpy = mSlots[buf].mEglDisplay;
         fence = mSlots[buf].mFence;
         mSlots[buf].mFence = EGL_NO_SYNC_KHR;
-    }
+    }  // end lock scope
 
     if (fence != EGL_NO_SYNC_KHR) {
         EGLint result = eglClientWaitSyncKHR(dpy, fence, 0, 1000000000);
@@ -437,6 +453,7 @@
             ALOGE("dequeueBuffer: timeout waiting for fence");
         }
         eglDestroySyncKHR(dpy, fence);
+
     }
 
     ST_LOGV("dequeueBuffer: returning slot=%d buf=%p flags=%#x", *outBuf,
@@ -446,6 +463,7 @@
 }
 
 status_t BufferQueue::setSynchronousMode(bool enabled) {
+    ATRACE_CALL();
     ST_LOGV("setSynchronousMode: enabled=%d", enabled);
     Mutex::Autolock lock(mMutex);
 
@@ -478,6 +496,7 @@
 
 status_t BufferQueue::queueBuffer(int buf, int64_t timestamp,
         uint32_t* outWidth, uint32_t* outHeight, uint32_t* outTransform) {
+    ATRACE_CALL();
     ST_LOGV("queueBuffer: slot=%d time=%lld", buf, timestamp);
 
     sp<FrameAvailableListener> listener;
@@ -496,9 +515,6 @@
             ST_LOGE("queueBuffer: slot %d is not owned by the client "
                     "(state=%d)", buf, mSlots[buf].mBufferState);
             return -EINVAL;
-        } else if (buf == mCurrentTexture) {
-            ST_LOGE("queueBuffer: slot %d is current!", buf);
-            return -EINVAL;
         } else if (!mSlots[buf].mRequestBufferCalled) {
             ST_LOGE("queueBuffer: slot %d was enqueued without requesting a "
                     "buffer", buf);
@@ -538,11 +554,14 @@
         mFrameCounter++;
         mSlots[buf].mFrameNumber = mFrameCounter;
 
+        mBufferHasBeenQueued = true;
         mDequeueCondition.signal();
 
         *outWidth = mDefaultWidth;
         *outHeight = mDefaultHeight;
         *outTransform = 0;
+
+        ATRACE_INT(mConsumerName.string(), mQueue.size());
     } // scope for the lock
 
     // call back without lock held
@@ -553,6 +572,7 @@
 }
 
 void BufferQueue::cancelBuffer(int buf) {
+    ATRACE_CALL();
     ST_LOGV("cancelBuffer: slot=%d", buf);
     Mutex::Autolock lock(mMutex);
 
@@ -576,6 +596,7 @@
 }
 
 status_t BufferQueue::setCrop(const Rect& crop) {
+    ATRACE_CALL();
     ST_LOGV("setCrop: crop=[%d,%d,%d,%d]", crop.left, crop.top, crop.right,
             crop.bottom);
 
@@ -589,6 +610,7 @@
 }
 
 status_t BufferQueue::setTransform(uint32_t transform) {
+    ATRACE_CALL();
     ST_LOGV("setTransform: xform=%#x", transform);
     Mutex::Autolock lock(mMutex);
     if (mAbandoned) {
@@ -600,6 +622,7 @@
 }
 
 status_t BufferQueue::setScalingMode(int mode) {
+    ATRACE_CALL();
     ST_LOGV("setScalingMode: mode=%d", mode);
 
     switch (mode) {
@@ -618,6 +641,7 @@
 
 status_t BufferQueue::connect(int api,
         uint32_t* outWidth, uint32_t* outHeight, uint32_t* outTransform) {
+    ATRACE_CALL();
     ST_LOGV("connect: api=%d", api);
     Mutex::Autolock lock(mMutex);
 
@@ -647,10 +671,14 @@
             err = -EINVAL;
             break;
     }
+
+    mBufferHasBeenQueued = false;
+
     return err;
 }
 
 status_t BufferQueue::disconnect(int api) {
+    ATRACE_CALL();
     ST_LOGV("disconnect: api=%d", api);
     Mutex::Autolock lock(mMutex);
 
@@ -687,26 +715,188 @@
     return err;
 }
 
+void BufferQueue::dump(String8& result) const
+{
+    char buffer[1024];
+    BufferQueue::dump(result, "", buffer, 1024);
+}
+
+void BufferQueue::dump(String8& result, const char* prefix,
+        char* buffer, size_t SIZE) const
+{
+    Mutex::Autolock _l(mMutex);
+    snprintf(buffer, SIZE,
+            "%snext   : {crop=[%d,%d,%d,%d], transform=0x%02x}\n"
+            ,prefix, mNextCrop.left, mNextCrop.top, mNextCrop.right,
+            mNextCrop.bottom, mNextTransform
+    );
+    result.append(buffer);
+
+    String8 fifo;
+    int fifoSize = 0;
+    Fifo::const_iterator i(mQueue.begin());
+    while (i != mQueue.end()) {
+       snprintf(buffer, SIZE, "%02d ", *i++);
+       fifoSize++;
+       fifo.append(buffer);
+    }
+
+    snprintf(buffer, SIZE,
+            "%s-BufferQueue mBufferCount=%d, mSynchronousMode=%d, default-size=[%dx%d], "
+            "mPixelFormat=%d, FIFO(%d)={%s}\n",
+            prefix, mBufferCount, mSynchronousMode, mDefaultWidth,
+            mDefaultHeight, mPixelFormat, fifoSize, fifo.string());
+    result.append(buffer);
+
+
+    struct {
+        const char * operator()(int state) const {
+            switch (state) {
+                case BufferSlot::DEQUEUED: return "DEQUEUED";
+                case BufferSlot::QUEUED: return "QUEUED";
+                case BufferSlot::FREE: return "FREE";
+                case BufferSlot::ACQUIRED: return "ACQUIRED";
+                default: return "Unknown";
+            }
+        }
+    } stateName;
+
+    for (int i=0 ; i<mBufferCount ; i++) {
+        const BufferSlot& slot(mSlots[i]);
+        snprintf(buffer, SIZE,
+                "%s%s[%02d] "
+                "state=%-8s, crop=[%d,%d,%d,%d], "
+                "transform=0x%02x, timestamp=%lld",
+                prefix, (slot.mBufferState == BufferSlot::ACQUIRED)?">":" ", i,
+                stateName(slot.mBufferState),
+                slot.mCrop.left, slot.mCrop.top, slot.mCrop.right,
+                slot.mCrop.bottom, slot.mTransform, slot.mTimestamp
+        );
+        result.append(buffer);
+
+        const sp<GraphicBuffer>& buf(slot.mGraphicBuffer);
+        if (buf != NULL) {
+            snprintf(buffer, SIZE,
+                    ", %p [%4ux%4u:%4u,%3X]",
+                    buf->handle, buf->width, buf->height, buf->stride,
+                    buf->format);
+            result.append(buffer);
+        }
+        result.append("\n");
+    }
+}
+
 void BufferQueue::freeBufferLocked(int i) {
     mSlots[i].mGraphicBuffer = 0;
     mSlots[i].mBufferState = BufferSlot::FREE;
     mSlots[i].mFrameNumber = 0;
-    if (mSlots[i].mEglImage != EGL_NO_IMAGE_KHR) {
-        eglDestroyImageKHR(mSlots[i].mEglDisplay, mSlots[i].mEglImage);
-        mSlots[i].mEglImage = EGL_NO_IMAGE_KHR;
-        mSlots[i].mEglDisplay = EGL_NO_DISPLAY;
+    mSlots[i].mAcquireCalled = false;
+
+    // destroy fence as BufferQueue now takes ownership
+    if (mSlots[i].mFence != EGL_NO_SYNC_KHR) {
+        eglDestroySyncKHR(mSlots[i].mEglDisplay, mSlots[i].mFence);
+        mSlots[i].mFence = EGL_NO_SYNC_KHR;
     }
 }
 
 void BufferQueue::freeAllBuffersLocked() {
     ALOGW_IF(!mQueue.isEmpty(),
             "freeAllBuffersLocked called but mQueue is not empty");
-    mCurrentTexture = INVALID_BUFFER_SLOT;
+    mQueue.clear();
+    mBufferHasBeenQueued = false;
     for (int i = 0; i < NUM_BUFFER_SLOTS; i++) {
         freeBufferLocked(i);
     }
 }
 
+status_t BufferQueue::acquire(BufferItem *buffer) {
+    Mutex::Autolock _l(mMutex);
+    // check if queue is empty
+    // In asynchronous mode the list is guaranteed to be one buffer
+    // deep, while in synchronous mode we use the oldest buffer.
+    if (!mQueue.empty()) {
+        Fifo::iterator front(mQueue.begin());
+        int buf = *front;
+
+        if (mSlots[buf].mAcquireCalled) {
+            buffer->mGraphicBuffer = NULL;
+        }
+        else {
+            buffer->mGraphicBuffer = mSlots[buf].mGraphicBuffer;
+        }
+        buffer->mCrop = mSlots[buf].mCrop;
+        buffer->mTransform = mSlots[buf].mTransform;
+        buffer->mScalingMode = mSlots[buf].mScalingMode;
+        buffer->mFrameNumber = mSlots[buf].mFrameNumber;
+        buffer->mBuf = buf;
+        mSlots[buf].mAcquireCalled = true;
+
+        mSlots[buf].mBufferState = BufferSlot::ACQUIRED;
+        mQueue.erase(front);
+
+        ATRACE_INT(mConsumerName.string(), mQueue.size());
+    }
+    else {
+        return -EINVAL; //should be a better return code
+    }
+
+    return OK;
+}
+
+status_t BufferQueue::releaseBuffer(int buf, EGLDisplay display,
+        EGLSyncKHR fence) {
+    Mutex::Autolock _l(mMutex);
+
+    if (buf == INVALID_BUFFER_SLOT) {
+        return -EINVAL;
+    }
+
+    mSlots[buf].mEglDisplay = display;
+    mSlots[buf].mFence = fence;
+
+    // The current buffer becomes FREE if it was still in the queued
+    // state. If it has already been given to the client
+    // (synchronous mode), then it stays in DEQUEUED state.
+    if (mSlots[buf].mBufferState == BufferSlot::QUEUED
+            || mSlots[buf].mBufferState == BufferSlot::ACQUIRED) {
+        mSlots[buf].mBufferState = BufferSlot::FREE;
+    }
+    mDequeueCondition.signal();
+
+    return OK;
+}
+
+status_t BufferQueue::consumerDisconnect() {
+    Mutex::Autolock lock(mMutex);
+    // Once the SurfaceTexture disconnects, the BufferQueue
+    // is considered abandoned
+    mAbandoned = true;
+    freeAllBuffersLocked();
+    mDequeueCondition.signal();
+    return OK;
+}
+
+status_t BufferQueue::setDefaultBufferSize(uint32_t w, uint32_t h)
+{
+    ST_LOGV("setDefaultBufferSize: w=%d, h=%d", w, h);
+    if (!w || !h) {
+        ST_LOGE("setDefaultBufferSize: dimensions cannot be 0 (w=%d, h=%d)",
+                w, h);
+        return BAD_VALUE;
+    }
+
+    Mutex::Autolock lock(mMutex);
+    mDefaultWidth = w;
+    mDefaultHeight = h;
+    return OK;
+}
+
+status_t BufferQueue::setBufferCountServer(int bufferCount) {
+    ATRACE_CALL();
+    Mutex::Autolock lock(mMutex);
+    return setBufferCountServerLocked(bufferCount);
+}
+
 void BufferQueue::freeAllBuffersExceptHeadLocked() {
     ALOGW_IF(!mQueue.isEmpty(),
             "freeAllBuffersExceptCurrentLocked called but mQueue is not empty");
@@ -715,7 +905,7 @@
         Fifo::iterator front(mQueue.begin());
         head = *front;
     }
-    mCurrentTexture = INVALID_BUFFER_SLOT;
+    mBufferHasBeenQueued = false;
     for (int i = 0; i < NUM_BUFFER_SLOTS; i++) {
         if (i != head) {
             freeBufferLocked(i);
diff --git a/libs/gui/SurfaceTexture.cpp b/libs/gui/SurfaceTexture.cpp
index 5f0013c..b42aa34 100644
--- a/libs/gui/SurfaceTexture.cpp
+++ b/libs/gui/SurfaceTexture.cpp
@@ -15,6 +15,7 @@
  */
 
 #define LOG_TAG "SurfaceTexture"
+#define ATRACE_TAG ATRACE_TAG_GRAPHICS
 //#define LOG_NDEBUG 0
 
 #define GL_GLEXT_PROTOTYPES
@@ -36,6 +37,7 @@
 
 #include <utils/Log.h>
 #include <utils/String8.h>
+#include <utils/Trace.h>
 
 // This compile option makes SurfaceTexture use the EGL_KHR_fence_sync extension
 // to synchronize access to the buffers.  It will cause dequeueBuffer to stall,
@@ -96,6 +98,11 @@
 
 static void mtxMul(float out[16], const float a[16], const float b[16]);
 
+// Get an ID that's unique within this process.
+static int32_t createProcessUniqueId() {
+    static volatile int32_t globalCounter = 0;
+    return android_atomic_inc(&globalCounter);
+}
 
 SurfaceTexture::SurfaceTexture(GLuint tex, bool allowSynchronousMode,
         GLenum texTarget, bool useFenceSync) :
@@ -108,8 +115,13 @@
 #else
     mUseFenceSync(false),
 #endif
-    mTexTarget(texTarget)
+    mTexTarget(texTarget),
+    mAbandoned(false),
+    mCurrentTexture(BufferQueue::INVALID_BUFFER_SLOT)
 {
+    // Choose a name using the PID and a process-unique ID.
+    mName = String8::format("unnamed-%d-%d", getpid(), createProcessUniqueId());
+    BufferQueue::setConsumerName(mName);
 
     ST_LOGV("SurfaceTexture");
     memcpy(mCurrentTransformMatrix, mtxIdentity,
@@ -118,31 +130,22 @@
 
 SurfaceTexture::~SurfaceTexture() {
     ST_LOGV("~SurfaceTexture");
-    freeAllBuffersLocked();
+    abandon();
 }
 
 status_t SurfaceTexture::setBufferCountServer(int bufferCount) {
     Mutex::Autolock lock(mMutex);
-    return setBufferCountServerLocked(bufferCount);
+    return BufferQueue::setBufferCountServer(bufferCount);
 }
 
 
 status_t SurfaceTexture::setDefaultBufferSize(uint32_t w, uint32_t h)
 {
-    ST_LOGV("setDefaultBufferSize: w=%d, h=%d", w, h);
-    if (!w || !h) {
-        ST_LOGE("setDefaultBufferSize: dimensions cannot be 0 (w=%d, h=%d)",
-                w, h);
-        return BAD_VALUE;
-    }
-
-    Mutex::Autolock lock(mMutex);
-    mDefaultWidth = w;
-    mDefaultHeight = h;
-    return OK;
+    return BufferQueue::setDefaultBufferSize(w, h);
 }
 
 status_t SurfaceTexture::updateTexImage() {
+    ATRACE_CALL();
     ST_LOGV("updateTexImage");
     Mutex::Autolock lock(mMutex);
 
@@ -151,23 +154,35 @@
         return NO_INIT;
     }
 
+    BufferItem item;
+
     // In asynchronous mode the list is guaranteed to be one buffer
     // deep, while in synchronous mode we use the oldest buffer.
-    if (!mQueue.empty()) {
-        Fifo::iterator front(mQueue.begin());
-        int buf = *front;
+    if (acquire(&item) == NO_ERROR) {
+        int buf = item.mBuf;
+        // This buffer was newly allocated, so we need to clean up on our side
+        if (item.mGraphicBuffer != NULL) {
+            mEGLSlots[buf].mGraphicBuffer = 0;
+            if (mEGLSlots[buf].mEglImage != EGL_NO_IMAGE_KHR) {
+                eglDestroyImageKHR(mEGLSlots[buf].mEglDisplay,
+                        mEGLSlots[buf].mEglImage);
+                mEGLSlots[buf].mEglImage = EGL_NO_IMAGE_KHR;
+                mEGLSlots[buf].mEglDisplay = EGL_NO_DISPLAY;
+            }
+            mEGLSlots[buf].mGraphicBuffer = item.mGraphicBuffer;
+        }
 
         // Update the GL texture object.
-        EGLImageKHR image = mSlots[buf].mEglImage;
+        EGLImageKHR image = mEGLSlots[buf].mEglImage;
         EGLDisplay dpy = eglGetCurrentDisplay();
         if (image == EGL_NO_IMAGE_KHR) {
-            if (mSlots[buf].mGraphicBuffer == 0) {
+            if (item.mGraphicBuffer == 0) {
                 ST_LOGE("buffer at slot %d is null", buf);
                 return BAD_VALUE;
             }
-            image = createImage(dpy, mSlots[buf].mGraphicBuffer);
-            mSlots[buf].mEglImage = image;
-            mSlots[buf].mEglDisplay = dpy;
+            image = createImage(dpy, item.mGraphicBuffer);
+            mEGLSlots[buf].mEglImage = image;
+            mEGLSlots[buf].mEglDisplay = dpy;
             if (image == EGL_NO_IMAGE_KHR) {
                 // NOTE: if dpy was invalid, createImage() is guaranteed to
                 // fail. so we'd end up here.
@@ -190,6 +205,8 @@
             failed = true;
         }
         if (failed) {
+            releaseBuffer(buf, mEGLSlots[buf].mEglDisplay,
+                    mEGLSlots[buf].mFence);
             return -EINVAL;
         }
 
@@ -200,40 +217,37 @@
                 if (fence == EGL_NO_SYNC_KHR) {
                     ALOGE("updateTexImage: error creating fence: %#x",
                             eglGetError());
+                    releaseBuffer(buf, mEGLSlots[buf].mEglDisplay,
+                            mEGLSlots[buf].mFence);
                     return -EINVAL;
                 }
                 glFlush();
-                mSlots[mCurrentTexture].mFence = fence;
+                mEGLSlots[mCurrentTexture].mFence = fence;
             }
         }
 
         ST_LOGV("updateTexImage: (slot=%d buf=%p) -> (slot=%d buf=%p)",
                 mCurrentTexture,
                 mCurrentTextureBuf != NULL ? mCurrentTextureBuf->handle : 0,
-                buf, mSlots[buf].mGraphicBuffer->handle);
+                buf, item.mGraphicBuffer != NULL ? item.mGraphicBuffer->handle : 0);
 
-        if (mCurrentTexture != INVALID_BUFFER_SLOT) {
-            // The current buffer becomes FREE if it was still in the queued
-            // state. If it has already been given to the client
-            // (synchronous mode), then it stays in DEQUEUED state.
-            if (mSlots[mCurrentTexture].mBufferState == BufferSlot::QUEUED) {
-                mSlots[mCurrentTexture].mBufferState = BufferSlot::FREE;
-            }
-        }
+        // release old buffer
+        releaseBuffer(mCurrentTexture,
+                mEGLSlots[mCurrentTexture].mEglDisplay,
+                mEGLSlots[mCurrentTexture].mFence);
 
         // Update the SurfaceTexture state.
         mCurrentTexture = buf;
-        mCurrentTextureBuf = mSlots[buf].mGraphicBuffer;
-        mCurrentCrop = mSlots[buf].mCrop;
-        mCurrentTransform = mSlots[buf].mTransform;
-        mCurrentScalingMode = mSlots[buf].mScalingMode;
-        mCurrentTimestamp = mSlots[buf].mTimestamp;
+        mCurrentTextureBuf = mEGLSlots[buf].mGraphicBuffer;
+        mCurrentCrop = item.mCrop;
+        mCurrentTransform = item.mTransform;
+        mCurrentScalingMode = item.mScalingMode;
+        mCurrentTimestamp = item.mTimestamp;
         computeCurrentTransformMatrix();
 
         // Now that we've passed the point at which failures can happen,
         // it's safe to remove the buffer from the front of the queue.
-        mQueue.erase(front);
-        mDequeueCondition.signal();
+
     } else {
         // We always bind the texture even if we don't update its contents.
         glBindTexture(mTexTarget, mTexName);
@@ -299,7 +313,7 @@
         }
     }
 
-    sp<GraphicBuffer>& buf(mSlots[mCurrentTexture].mGraphicBuffer);
+    sp<GraphicBuffer>& buf(mCurrentTextureBuf);
     float tx, ty, sx, sy;
     if (!mCurrentCrop.isEmpty()) {
         // In order to prevent bilinear sampling at the of the crop rectangle we
@@ -371,7 +385,7 @@
         const sp<FrameAvailableListener>& listener) {
     ST_LOGV("setFrameAvailableListener");
     Mutex::Autolock lock(mMutex);
-    mFrameAvailableListener = listener;
+    BufferQueue::setFrameAvailableListener(listener);
 }
 
 EGLImageKHR SurfaceTexture::createImage(EGLDisplay dpy,
@@ -412,22 +426,33 @@
 
 bool SurfaceTexture::isSynchronousMode() const {
     Mutex::Autolock lock(mMutex);
-    return mSynchronousMode;
+    return BufferQueue::isSynchronousMode();
 }
 
-
-
 void SurfaceTexture::abandon() {
     Mutex::Autolock lock(mMutex);
-    mQueue.clear();
     mAbandoned = true;
     mCurrentTextureBuf.clear();
-    freeAllBuffersLocked();
-    mDequeueCondition.signal();
+
+    // destroy all egl buffers
+    for (int i =0; i < NUM_BUFFER_SLOTS; i++) {
+        mEGLSlots[i].mGraphicBuffer = 0;
+        if (mEGLSlots[i].mEglImage != EGL_NO_IMAGE_KHR) {
+            eglDestroyImageKHR(mEGLSlots[i].mEglDisplay,
+                    mEGLSlots[i].mEglImage);
+            mEGLSlots[i].mEglImage = EGL_NO_IMAGE_KHR;
+            mEGLSlots[i].mEglDisplay = EGL_NO_DISPLAY;
+        }
+    }
+
+    // disconnect from the BufferQueue
+    BufferQueue::consumerDisconnect();
 }
 
 void SurfaceTexture::setName(const String8& name) {
+    Mutex::Autolock _l(mMutex);
     mName = name;
+    BufferQueue::setConsumerName(name);
 }
 
 void SurfaceTexture::dump(String8& result) const
@@ -440,68 +465,19 @@
         char* buffer, size_t SIZE) const
 {
     Mutex::Autolock _l(mMutex);
-    snprintf(buffer, SIZE,
-            "%smBufferCount=%d, mSynchronousMode=%d, default-size=[%dx%d], "
-            "mPixelFormat=%d, mTexName=%d\n",
-            prefix, mBufferCount, mSynchronousMode, mDefaultWidth,
-            mDefaultHeight, mPixelFormat, mTexName);
+    snprintf(buffer, SIZE, "%smTexName=%d\n", prefix, mTexName);
     result.append(buffer);
 
-    String8 fifo;
-    int fifoSize = 0;
-    Fifo::const_iterator i(mQueue.begin());
-    while (i != mQueue.end()) {
-        snprintf(buffer, SIZE, "%02d ", *i++);
-        fifoSize++;
-        fifo.append(buffer);
-    }
-
     snprintf(buffer, SIZE,
-            "%scurrent: {crop=[%d,%d,%d,%d], transform=0x%02x, current=%d}\n"
-            "%snext   : {crop=[%d,%d,%d,%d], transform=0x%02x, FIFO(%d)={%s}}\n"
-            ,
-            prefix, mCurrentCrop.left,
+            "%snext   : {crop=[%d,%d,%d,%d], transform=0x%02x, current=%d}\n"
+            ,prefix, mCurrentCrop.left,
             mCurrentCrop.top, mCurrentCrop.right, mCurrentCrop.bottom,
-            mCurrentTransform, mCurrentTexture,
-            prefix, mNextCrop.left, mNextCrop.top, mNextCrop.right,
-            mNextCrop.bottom, mNextTransform, fifoSize, fifo.string()
+            mCurrentTransform, mCurrentTexture
     );
     result.append(buffer);
 
-    struct {
-        const char * operator()(int state) const {
-            switch (state) {
-                case BufferSlot::DEQUEUED: return "DEQUEUED";
-                case BufferSlot::QUEUED: return "QUEUED";
-                case BufferSlot::FREE: return "FREE";
-                default: return "Unknown";
-            }
-        }
-    } stateName;
 
-    for (int i=0 ; i<mBufferCount ; i++) {
-        const BufferSlot& slot(mSlots[i]);
-        snprintf(buffer, SIZE,
-                "%s%s[%02d] "
-                "state=%-8s, crop=[%d,%d,%d,%d], "
-                "transform=0x%02x, timestamp=%lld",
-                prefix, (i==mCurrentTexture)?">":" ", i,
-                stateName(slot.mBufferState),
-                slot.mCrop.left, slot.mCrop.top, slot.mCrop.right,
-                slot.mCrop.bottom, slot.mTransform, slot.mTimestamp
-        );
-        result.append(buffer);
-
-        const sp<GraphicBuffer>& buf(slot.mGraphicBuffer);
-        if (buf != NULL) {
-            snprintf(buffer, SIZE,
-                    ", %p [%4ux%4u:%4u,%3X]",
-                    buf->handle, buf->width, buf->height, buf->stride,
-                    buf->format);
-            result.append(buffer);
-        }
-        result.append("\n");
-    }
+    BufferQueue::dump(result, prefix, buffer, SIZE);
 }
 
 static void mtxMul(float out[16], const float a[16], const float b[16]) {
diff --git a/libs/gui/SurfaceTextureClient.cpp b/libs/gui/SurfaceTextureClient.cpp
index dac54a8..f88dcaf 100644
--- a/libs/gui/SurfaceTextureClient.cpp
+++ b/libs/gui/SurfaceTextureClient.cpp
@@ -15,9 +15,11 @@
  */
 
 #define LOG_TAG "SurfaceTextureClient"
+#define ATRACE_TAG ATRACE_TAG_GRAPHICS
 //#define LOG_NDEBUG 0
 
 #include <utils/Log.h>
+#include <utils/Trace.h>
 
 #include <gui/ISurfaceComposer.h>
 #include <gui/SurfaceComposerClient.h>
@@ -121,6 +123,7 @@
 }
 
 int SurfaceTextureClient::setSwapInterval(int interval) {
+    ATRACE_CALL();
     // EGL specification states:
     //  interval is silently clamped to minimum and maximum implementation
     //  dependent values before being stored.
@@ -138,6 +141,7 @@
 }
 
 int SurfaceTextureClient::dequeueBuffer(android_native_buffer_t** buffer) {
+    ATRACE_CALL();
     ALOGV("SurfaceTextureClient::dequeueBuffer");
     Mutex::Autolock lock(mMutex);
     int buf = -1;
@@ -167,6 +171,7 @@
 }
 
 int SurfaceTextureClient::cancelBuffer(android_native_buffer_t* buffer) {
+    ATRACE_CALL();
     ALOGV("SurfaceTextureClient::cancelBuffer");
     Mutex::Autolock lock(mMutex);
     int i = getSlotFromBufferLocked(buffer);
@@ -213,6 +218,7 @@
 }
 
 int SurfaceTextureClient::queueBuffer(android_native_buffer_t* buffer) {
+    ATRACE_CALL();
     ALOGV("SurfaceTextureClient::queueBuffer");
     Mutex::Autolock lock(mMutex);
     int64_t timestamp;
@@ -236,6 +242,7 @@
 }
 
 int SurfaceTextureClient::query(int what, int* value) const {
+    ATRACE_CALL();
     ALOGV("SurfaceTextureClient::query");
     { // scope for the lock
         Mutex::Autolock lock(mMutex);
@@ -404,6 +411,7 @@
 
 
 int SurfaceTextureClient::connect(int api) {
+    ATRACE_CALL();
     ALOGV("SurfaceTextureClient::connect");
     Mutex::Autolock lock(mMutex);
     int err = mSurfaceTexture->connect(api,
@@ -415,6 +423,7 @@
 }
 
 int SurfaceTextureClient::disconnect(int api) {
+    ATRACE_CALL();
     ALOGV("SurfaceTextureClient::disconnect");
     Mutex::Autolock lock(mMutex);
     freeAllBuffers();
@@ -441,6 +450,7 @@
 
 int SurfaceTextureClient::setCrop(Rect const* rect)
 {
+    ATRACE_CALL();
     ALOGV("SurfaceTextureClient::setCrop");
     Mutex::Autolock lock(mMutex);
 
@@ -459,6 +469,7 @@
 
 int SurfaceTextureClient::setBufferCount(int bufferCount)
 {
+    ATRACE_CALL();
     ALOGV("SurfaceTextureClient::setBufferCount");
     Mutex::Autolock lock(mMutex);
 
@@ -475,6 +486,7 @@
 
 int SurfaceTextureClient::setBuffersDimensions(int w, int h)
 {
+    ATRACE_CALL();
     ALOGV("SurfaceTextureClient::setBuffersDimensions");
     Mutex::Autolock lock(mMutex);
 
@@ -508,6 +520,7 @@
 
 int SurfaceTextureClient::setScalingMode(int mode)
 {
+    ATRACE_CALL();
     ALOGV("SurfaceTextureClient::setScalingMode(%d)", mode);
     Mutex::Autolock lock(mMutex);
     // mode is validated on the server
@@ -520,6 +533,7 @@
 
 int SurfaceTextureClient::setBuffersTransform(int transform)
 {
+    ATRACE_CALL();
     ALOGV("SurfaceTextureClient::setBuffersTransform");
     Mutex::Autolock lock(mMutex);
     status_t err = mSurfaceTexture->setTransform(transform);
diff --git a/opengl/libs/EGL/eglApi.cpp b/opengl/libs/EGL/eglApi.cpp
index a5dc832..a1bd82d 100644
--- a/opengl/libs/EGL/eglApi.cpp
+++ b/opengl/libs/EGL/eglApi.cpp
@@ -14,6 +14,8 @@
  ** limitations under the License.
  */
 
+#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+
 #include <ctype.h>
 #include <stdlib.h>
 #include <string.h>
@@ -34,6 +36,7 @@
 #include <utils/KeyedVector.h>
 #include <utils/SortedVector.h>
 #include <utils/String8.h>
+#include <utils/Trace.h>
 
 #include "egl_impl.h"
 #include "egl_tls.h"
@@ -348,6 +351,7 @@
 }
 
 void EGLAPI eglBeginFrame(EGLDisplay dpy, EGLSurface surface) {
+    ATRACE_CALL();
     clearError();
 
     egl_display_t const * const dp = validate_display(dpy);
@@ -712,6 +716,7 @@
 
 EGLBoolean eglSwapBuffers(EGLDisplay dpy, EGLSurface draw)
 {
+    ATRACE_CALL();
     clearError();
 
     egl_display_t const * const dp = validate_display(dpy);
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index e96cf32..df7fe5c 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -14,6 +14,8 @@
  * limitations under the License.
  */
 
+#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+
 #include <stdlib.h>
 #include <stdint.h>
 #include <sys/types.h>
@@ -26,6 +28,7 @@
 #include <utils/Errors.h>
 #include <utils/Log.h>
 #include <utils/StopWatch.h>
+#include <utils/Trace.h>
 
 #include <ui/GraphicBuffer.h>
 #include <ui/PixelFormat.h>
@@ -267,6 +270,8 @@
 
 void Layer::onDraw(const Region& clip) const
 {
+    ATRACE_CALL();
+
     if (CC_UNLIKELY(mActiveBuffer == 0)) {
         // the texture has not been created yet, this Layer has
         // in fact never been drawn into. This happens frequently with
@@ -365,6 +370,8 @@
 
 uint32_t Layer::doTransaction(uint32_t flags)
 {
+    ATRACE_CALL();
+
     const Layer::State& front(drawingState());
     const Layer::State& temp(currentState());
 
@@ -418,6 +425,8 @@
 
 void Layer::lockPageFlip(bool& recomputeVisibleRegions)
 {
+    ATRACE_CALL();
+
     if (mQueuedFrames > 0) {
 
         // if we've already called updateTexImage() without going through
@@ -546,6 +555,8 @@
 void Layer::unlockPageFlip(
         const Transform& planeTransform, Region& outDirtyRegion)
 {
+    ATRACE_CALL();
+
     Region postedRegion(mPostedDirtyRegion);
     if (!postedRegion.isEmpty()) {
         mPostedDirtyRegion.clear();
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 62461bb..42ed4fa 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -14,6 +14,8 @@
  * limitations under the License.
  */
 
+#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+
 #include <stdlib.h>
 #include <stdio.h>
 #include <stdint.h>
@@ -39,6 +41,7 @@
 #include <utils/String8.h>
 #include <utils/String16.h>
 #include <utils/StopWatch.h>
+#include <utils/Trace.h>
 
 #include <ui/GraphicBufferAllocator.h>
 #include <ui/PixelFormat.h>
@@ -402,6 +405,7 @@
 
 void SurfaceFlinger::onMessageReceived(int32_t what)
 {
+    ATRACE_CALL();
     switch (what) {
         case MessageQueue::REFRESH: {
 //        case MessageQueue::INVALIDATE: {
@@ -737,6 +741,7 @@
 
 void SurfaceFlinger::handlePageFlip()
 {
+    ATRACE_CALL();
     const DisplayHardware& hw = graphicPlane(0).displayHardware();
     const Region screenRegion(hw.bounds());