Merge changes I4589e02a,Id300e8b2 into nyc-dev

* changes:
  Switch SurfaceFlinger to HWC 2.0
  HWC2On1Adapter: Initialize variables and fix mutex
diff --git a/include/gui/BufferQueueCore.h b/include/gui/BufferQueueCore.h
index d10ba2f..2645d09 100644
--- a/include/gui/BufferQueueCore.h
+++ b/include/gui/BufferQueueCore.h
@@ -32,6 +32,7 @@
 
 #include <list>
 #include <set>
+#include <vector>
 
 #define BQ_LOGV(x, ...) ALOGV("[%s] " x, mConsumerName.string(), ##__VA_ARGS__)
 #define BQ_LOGD(x, ...) ALOGD("[%s] " x, mConsumerName.string(), ##__VA_ARGS__)
@@ -120,8 +121,9 @@
     void freeAllBuffersLocked();
 
     // If delta is positive, makes more slots available. If negative, takes
-    // away slots. Returns false if the request can't be met.
-    bool adjustAvailableSlotsLocked(int delta);
+    // away slots. Returns false if the request can't be met. Any slots that
+    // were freed will be appended to freedSlots.
+    bool adjustAvailableSlotsLocked(int delta, std::vector<int>* freedSlots);
 
     // waitWhileAllocatingLocked blocks until mIsAllocating is false.
     void waitWhileAllocatingLocked() const;
diff --git a/include/gui/IProducerListener.h b/include/gui/IProducerListener.h
index 3848a6c..895da4b 100644
--- a/include/gui/IProducerListener.h
+++ b/include/gui/IProducerListener.h
@@ -41,6 +41,9 @@
     // This is called without any lock held and can be called concurrently by
     // multiple threads.
     virtual void onBufferReleased() = 0; // Asynchronous
+
+    // onSlotFreed is called when the BufferQueue frees a buffer in a slot.
+    virtual void onSlotFreed(int /*slot*/) {}; // Asynchronous
 };
 
 class IProducerListener : public ProducerListener, public IInterface
diff --git a/include/media/hardware/HardwareAPI.h b/include/media/hardware/HardwareAPI.h
index 752b004..feec509 100644
--- a/include/media/hardware/HardwareAPI.h
+++ b/include/media/hardware/HardwareAPI.h
@@ -258,7 +258,7 @@
 };
 
 struct MediaImage2 {
-    enum Type {
+    enum Type : uint32_t {
         MEDIA_IMAGE_TYPE_UNKNOWN = 0,
         MEDIA_IMAGE_TYPE_YUV,
         MEDIA_IMAGE_TYPE_YUVA,
@@ -267,7 +267,7 @@
         MEDIA_IMAGE_TYPE_Y,
     };
 
-    enum PlaneIndex {
+    enum PlaneIndex : uint32_t {
         Y = 0,
         U = 1,
         V = 2,
@@ -294,6 +294,8 @@
         uint32_t mVertSubsampling;    // subsampling compared to the largest plane
     };
     PlaneInfo mPlane[MAX_NUM_PLANES];
+
+    void initFromV1(const MediaImage&); // for internal use only
 };
 
 // A pointer to this struct is passed to OMX_GetParameter when the extension
@@ -324,6 +326,7 @@
 // buffers, the component shall set mNumPlanes to 0, and mType to MEDIA_IMAGE_TYPE_UNKNOWN.
 
 // @deprecated: use DescribeColorFormat2Params
+struct DescribeColorFormat2Params;
 struct DescribeColorFormatParams {
     OMX_U32 nSize;
     OMX_VERSIONTYPE nVersion;
@@ -337,6 +340,8 @@
 
     // output: fill out the MediaImage fields
     MediaImage sMediaImage;
+
+    DescribeColorFormatParams(const DescribeColorFormat2Params&); // for internal use only
 };
 
 // A pointer to this struct is passed to OMX_GetParameter when the extension
@@ -356,6 +361,8 @@
 
     // output: fill out the MediaImage2 fields
     MediaImage2 sMediaImage;
+
+    void initFromV1(const DescribeColorFormatParams&); // for internal use only
 };
 
 // A pointer to this struct is passed to OMX_SetParameter or OMX_GetParameter
diff --git a/libs/gui/BufferQueueConsumer.cpp b/libs/gui/BufferQueueConsumer.cpp
index 4029496..aacbed5 100644
--- a/libs/gui/BufferQueueConsumer.cpp
+++ b/libs/gui/BufferQueueConsumer.cpp
@@ -277,35 +277,51 @@
     ATRACE_CALL();
     ATRACE_BUFFER_INDEX(slot);
     BQ_LOGV("detachBuffer: slot %d", slot);
-    Mutex::Autolock lock(mCore->mMutex);
 
-    if (mCore->mIsAbandoned) {
-        BQ_LOGE("detachBuffer: BufferQueue has been abandoned");
-        return NO_INIT;
+    sp<IConsumerListener> consumerListener;
+    sp<IProducerListener> producerListener;
+    {
+        Mutex::Autolock lock(mCore->mMutex);
+
+        if (mCore->mIsAbandoned) {
+            BQ_LOGE("detachBuffer: BufferQueue has been abandoned");
+            return NO_INIT;
+        }
+
+        if (mCore->mSingleBufferMode || slot == mCore->mSingleBufferSlot) {
+            BQ_LOGE("detachBuffer: detachBuffer not allowed in single buffer"
+                    "mode");
+            return BAD_VALUE;
+        }
+
+        if (slot < 0 || slot >= BufferQueueDefs::NUM_BUFFER_SLOTS) {
+            BQ_LOGE("detachBuffer: slot index %d out of range [0, %d)",
+                    slot, BufferQueueDefs::NUM_BUFFER_SLOTS);
+            return BAD_VALUE;
+        } else if (!mSlots[slot].mBufferState.isAcquired()) {
+            BQ_LOGE("detachBuffer: slot %d is not owned by the consumer "
+                    "(state = %s)", slot, mSlots[slot].mBufferState.string());
+            return BAD_VALUE;
+        }
+
+        mSlots[slot].mBufferState.detachConsumer();
+        mCore->mActiveBuffers.erase(slot);
+        mCore->mFreeSlots.insert(slot);
+        mCore->clearBufferSlotLocked(slot);
+        mCore->mDequeueCondition.broadcast();
+        VALIDATE_CONSISTENCY();
+        producerListener = mCore->mConnectedProducerListener;
+        consumerListener = mCore->mConsumerListener;
     }
 
-    if (mCore->mSingleBufferMode || slot == mCore->mSingleBufferSlot) {
-        BQ_LOGE("detachBuffer: detachBuffer not allowed in single buffer"
-                "mode");
-        return BAD_VALUE;
+    // Call back without lock held
+    if (producerListener != NULL) {
+        producerListener->onSlotFreed(slot);
+    }
+    if (consumerListener != NULL) {
+        consumerListener->onBuffersReleased();
     }
 
-    if (slot < 0 || slot >= BufferQueueDefs::NUM_BUFFER_SLOTS) {
-        BQ_LOGE("detachBuffer: slot index %d out of range [0, %d)",
-                slot, BufferQueueDefs::NUM_BUFFER_SLOTS);
-        return BAD_VALUE;
-    } else if (!mSlots[slot].mBufferState.isAcquired()) {
-        BQ_LOGE("detachBuffer: slot %d is not owned by the consumer "
-                "(state = %s)", slot, mSlots[slot].mBufferState.string());
-        return BAD_VALUE;
-    }
-
-    mSlots[slot].mBufferState.detachConsumer();
-    mCore->mActiveBuffers.erase(slot);
-    mCore->mFreeSlots.insert(slot);
-    mCore->clearBufferSlotLocked(slot);
-    mCore->mDequeueCondition.broadcast();
-    VALIDATE_CONSISTENCY();
 
     return NO_ERROR;
 }
@@ -576,30 +592,40 @@
         return BAD_VALUE;
     }
 
-    Mutex::Autolock lock(mCore->mMutex);
+    sp<IConsumerListener> listener;
+    {
+        Mutex::Autolock lock(mCore->mMutex);
+        if (mCore->mConnectedApi != BufferQueueCore::NO_CONNECTED_API) {
+            BQ_LOGE("setMaxBufferCount: producer is already connected");
+            return INVALID_OPERATION;
+        }
 
-    if (mCore->mConnectedApi != BufferQueueCore::NO_CONNECTED_API) {
-        BQ_LOGE("setMaxBufferCount: producer is already connected");
-        return INVALID_OPERATION;
+        if (bufferCount < mCore->mMaxAcquiredBufferCount) {
+            BQ_LOGE("setMaxBufferCount: invalid buffer count (%d) less than"
+                    "mMaxAcquiredBufferCount (%d)", bufferCount,
+                    mCore->mMaxAcquiredBufferCount);
+            return BAD_VALUE;
+        }
+
+        int delta = mCore->getMaxBufferCountLocked(mCore->mAsyncMode,
+                mCore->mDequeueBufferCannotBlock, bufferCount) -
+                mCore->getMaxBufferCountLocked();
+        if (!mCore->adjustAvailableSlotsLocked(delta, nullptr)) {
+            BQ_LOGE("setMaxBufferCount: BufferQueue failed to adjust the number"
+                    " of available slots. Delta = %d", delta);
+            return BAD_VALUE;
+        }
+
+        mCore->mMaxBufferCount = bufferCount;
+        if (delta < 0) {
+            listener = mCore->mConsumerListener;
+        }
     }
 
-    if (bufferCount < mCore->mMaxAcquiredBufferCount) {
-        BQ_LOGE("setMaxBufferCount: invalid buffer count (%d) less than"
-                "mMaxAcquiredBufferCount (%d)", bufferCount,
-                mCore->mMaxAcquiredBufferCount);
-        return BAD_VALUE;
+    // Call back without lock held
+    if (listener != NULL) {
+        listener->onBuffersReleased();
     }
-
-    int delta = mCore->getMaxBufferCountLocked(mCore->mAsyncMode,
-            mCore->mDequeueBufferCannotBlock, bufferCount) -
-            mCore->getMaxBufferCountLocked();
-    if (!mCore->adjustAvailableSlotsLocked(delta)) {
-        BQ_LOGE("setMaxBufferCount: BufferQueue failed to adjust the number of "
-                "available slots. Delta = %d", delta);
-        return BAD_VALUE;
-    }
-
-    mCore->mMaxBufferCount = bufferCount;
     return NO_ERROR;
 }
 
@@ -614,7 +640,9 @@
         return BAD_VALUE;
     }
 
-    sp<IConsumerListener> listener;
+    sp<IConsumerListener> consumerListener;
+    sp<IProducerListener> producerListener;
+    std::vector<int> freedSlots;
     { // Autolock scope
         Mutex::Autolock lock(mCore->mMutex);
         mCore->waitWhileAllocatingLocked();
@@ -651,7 +679,7 @@
         }
 
         int delta = maxAcquiredBuffers - mCore->mMaxAcquiredBufferCount;
-        if (!mCore->adjustAvailableSlotsLocked(delta)) {
+        if (!mCore->adjustAvailableSlotsLocked(delta, &freedSlots)) {
             return BAD_VALUE;
         }
 
@@ -659,12 +687,19 @@
         mCore->mMaxAcquiredBufferCount = maxAcquiredBuffers;
         VALIDATE_CONSISTENCY();
         if (delta < 0) {
-            listener = mCore->mConsumerListener;
+            consumerListener = mCore->mConsumerListener;
+            producerListener = mCore->mConnectedProducerListener;
         }
     }
+
     // Call back without lock held
-    if (listener != NULL) {
-        listener->onBuffersReleased();
+    if (consumerListener != NULL) {
+        consumerListener->onBuffersReleased();
+    }
+    if (producerListener != NULL) {
+        for (int i : freedSlots) {
+            producerListener->onSlotFreed(i);
+        }
     }
 
     return NO_ERROR;
diff --git a/libs/gui/BufferQueueCore.cpp b/libs/gui/BufferQueueCore.cpp
index ba07362..fc3ffed 100644
--- a/libs/gui/BufferQueueCore.cpp
+++ b/libs/gui/BufferQueueCore.cpp
@@ -226,7 +226,8 @@
     VALIDATE_CONSISTENCY();
 }
 
-bool BufferQueueCore::adjustAvailableSlotsLocked(int delta) {
+bool BufferQueueCore::adjustAvailableSlotsLocked(int delta,
+        std::vector<int>* freedSlots) {
     if (delta >= 0) {
         // If we're going to fail, do so before modifying anything
         if (delta > static_cast<int>(mUnusedSlots.size())) {
@@ -253,11 +254,17 @@
                 clearBufferSlotLocked(*slot);
                 mUnusedSlots.push_back(*slot);
                 mFreeSlots.erase(slot);
+                if (freedSlots) {
+                    freedSlots->push_back(*slot);
+                }
             } else if (!mFreeBuffers.empty()) {
                 int slot = mFreeBuffers.back();
                 clearBufferSlotLocked(slot);
                 mUnusedSlots.push_back(slot);
                 mFreeBuffers.pop_back();
+                if (freedSlots) {
+                    freedSlots->push_back(slot);
+                }
             } else {
                 return false;
             }
diff --git a/libs/gui/BufferQueueProducer.cpp b/libs/gui/BufferQueueProducer.cpp
index 17d4a2c..cb5d773 100644
--- a/libs/gui/BufferQueueProducer.cpp
+++ b/libs/gui/BufferQueueProducer.cpp
@@ -90,7 +90,9 @@
     BQ_LOGV("setMaxDequeuedBufferCount: maxDequeuedBuffers = %d",
             maxDequeuedBuffers);
 
-    sp<IConsumerListener> listener;
+    sp<IConsumerListener> consumerListener;
+    sp<IProducerListener> producerListener;
+    std::vector<int> freedSlots;
     { // Autolock scope
         Mutex::Autolock lock(mCore->mMutex);
         mCore->waitWhileAllocatingLocked();
@@ -142,20 +144,26 @@
         }
 
         int delta = maxDequeuedBuffers - mCore->mMaxDequeuedBufferCount;
-        if (!mCore->adjustAvailableSlotsLocked(delta)) {
+        if (!mCore->adjustAvailableSlotsLocked(delta, &freedSlots)) {
             return BAD_VALUE;
         }
         mCore->mMaxDequeuedBufferCount = maxDequeuedBuffers;
         VALIDATE_CONSISTENCY();
         if (delta < 0) {
-            listener = mCore->mConsumerListener;
+            consumerListener = mCore->mConsumerListener;
+            producerListener = mCore->mConnectedProducerListener;
         }
         mCore->mDequeueCondition.broadcast();
     } // Autolock scope
 
     // Call back without lock held
-    if (listener != NULL) {
-        listener->onBuffersReleased();
+    if (consumerListener != NULL) {
+        consumerListener->onBuffersReleased();
+    }
+    if (producerListener != NULL) {
+        for (int i : freedSlots) {
+            producerListener->onSlotFreed(i);
+        }
     }
 
     return NO_ERROR;
@@ -165,7 +173,9 @@
     ATRACE_CALL();
     BQ_LOGV("setAsyncMode: async = %d", async);
 
-    sp<IConsumerListener> listener;
+    sp<IConsumerListener> consumerListener;
+    sp<IProducerListener> producerListener;
+    std::vector<int> freedSlots;
     { // Autolock scope
         Mutex::Autolock lock(mCore->mMutex);
         mCore->waitWhileAllocatingLocked();
@@ -191,7 +201,7 @@
                 mCore->mDequeueBufferCannotBlock, mCore->mMaxBufferCount)
                 - mCore->getMaxBufferCountLocked();
 
-        if (!mCore->adjustAvailableSlotsLocked(delta)) {
+        if (!mCore->adjustAvailableSlotsLocked(delta, &freedSlots)) {
             BQ_LOGE("setAsyncMode: BufferQueue failed to adjust the number of "
                     "available slots. Delta = %d", delta);
             return BAD_VALUE;
@@ -199,12 +209,20 @@
         mCore->mAsyncMode = async;
         VALIDATE_CONSISTENCY();
         mCore->mDequeueCondition.broadcast();
-        listener = mCore->mConsumerListener;
+        if (delta < 0) {
+            consumerListener = mCore->mConsumerListener;
+            producerListener = mCore->mConnectedProducerListener;
+        }
     } // Autolock scope
 
     // Call back without lock held
-    if (listener != NULL) {
-        listener->onBuffersReleased();
+    if (consumerListener != NULL) {
+        consumerListener->onBuffersReleased();
+    }
+    if (producerListener != NULL) {
+        for (int i : freedSlots) {
+            producerListener->onSlotFreed(i);
+        }
     }
     return NO_ERROR;
 }
@@ -361,6 +379,9 @@
     EGLSyncKHR eglFence = EGL_NO_SYNC_KHR;
     bool attachedByConsumer = false;
 
+    sp<IConsumerListener> consumerListener;
+    sp<IProducerListener> producerListener;
+    int found = BufferItem::INVALID_BUFFER_SLOT;
     { // Autolock scope
         Mutex::Autolock lock(mCore->mMutex);
         mCore->waitWhileAllocatingLocked();
@@ -378,7 +399,6 @@
             height = mCore->mDefaultHeight;
         }
 
-        int found = BufferItem::INVALID_BUFFER_SLOT;
         while (found == BufferItem::INVALID_BUFFER_SLOT) {
             status_t status = waitForFreeSlotThenRelock(FreeSlotCaller::Dequeue,
                     &found);
@@ -408,6 +428,8 @@
                     mCore->mFreeSlots.insert(found);
                     mCore->clearBufferSlotLocked(found);
                     found = BufferItem::INVALID_BUFFER_SLOT;
+                    consumerListener = mCore->mConsumerListener;
+                    producerListener = mCore->mConnectedProducerListener;
                     continue;
                 }
             }
@@ -444,6 +466,10 @@
         if ((buffer == NULL) ||
                 buffer->needsReallocation(width, height, format, usage))
         {
+            if (buffer != NULL) {
+                consumerListener = mCore->mConsumerListener;
+                producerListener = mCore->mConnectedProducerListener;
+            }
             mSlots[found].mAcquireCalled = false;
             mSlots[found].mGraphicBuffer = NULL;
             mSlots[found].mRequestBufferCalled = false;
@@ -531,6 +557,14 @@
             mSlots[*outSlot].mFrameNumber,
             mSlots[*outSlot].mGraphicBuffer->handle, returnFlags);
 
+    // Call back without lock held
+    if (consumerListener != NULL) {
+        consumerListener->onBuffersReleased();
+    }
+    if (producerListener != NULL) {
+        producerListener->onSlotFreed(found);
+    }
+
     return returnFlags;
 }
 
@@ -538,44 +572,60 @@
     ATRACE_CALL();
     ATRACE_BUFFER_INDEX(slot);
     BQ_LOGV("detachBuffer: slot %d", slot);
-    Mutex::Autolock lock(mCore->mMutex);
 
-    if (mCore->mIsAbandoned) {
-        BQ_LOGE("detachBuffer: BufferQueue has been abandoned");
-        return NO_INIT;
+    sp<IConsumerListener> consumerListener;
+    sp<IProducerListener> producerListener;
+    {
+        Mutex::Autolock lock(mCore->mMutex);
+
+        if (mCore->mIsAbandoned) {
+            BQ_LOGE("detachBuffer: BufferQueue has been abandoned");
+            return NO_INIT;
+        }
+
+        if (mCore->mConnectedApi == BufferQueueCore::NO_CONNECTED_API) {
+            BQ_LOGE("detachBuffer: BufferQueue has no connected producer");
+            return NO_INIT;
+        }
+
+        if (mCore->mSingleBufferMode || mCore->mSingleBufferSlot == slot) {
+            BQ_LOGE("detachBuffer: cannot detach a buffer in single buffer "
+                    "mode");
+            return BAD_VALUE;
+        }
+
+        if (slot < 0 || slot >= BufferQueueDefs::NUM_BUFFER_SLOTS) {
+            BQ_LOGE("detachBuffer: slot index %d out of range [0, %d)",
+                    slot, BufferQueueDefs::NUM_BUFFER_SLOTS);
+            return BAD_VALUE;
+        } else if (!mSlots[slot].mBufferState.isDequeued()) {
+            BQ_LOGE("detachBuffer: slot %d is not owned by the producer "
+                    "(state = %s)", slot, mSlots[slot].mBufferState.string());
+            return BAD_VALUE;
+        } else if (!mSlots[slot].mRequestBufferCalled) {
+            BQ_LOGE("detachBuffer: buffer in slot %d has not been requested",
+                    slot);
+            return BAD_VALUE;
+        }
+
+        mSlots[slot].mBufferState.detachProducer();
+        mCore->mActiveBuffers.erase(slot);
+        mCore->mFreeSlots.insert(slot);
+        mCore->clearBufferSlotLocked(slot);
+        mCore->mDequeueCondition.broadcast();
+        VALIDATE_CONSISTENCY();
+        producerListener = mCore->mConnectedProducerListener;
+        consumerListener = mCore->mConsumerListener;
     }
 
-    if (mCore->mConnectedApi == BufferQueueCore::NO_CONNECTED_API) {
-        BQ_LOGE("detachBuffer: BufferQueue has no connected producer");
-        return NO_INIT;
+    // Call back without lock held
+    if (consumerListener != NULL) {
+        consumerListener->onBuffersReleased();
     }
-
-    if (mCore->mSingleBufferMode || mCore->mSingleBufferSlot == slot) {
-        BQ_LOGE("detachBuffer: cannot detach a buffer in single buffer mode");
-        return BAD_VALUE;
+    if (producerListener != NULL) {
+        producerListener->onSlotFreed(slot);
     }
 
-    if (slot < 0 || slot >= BufferQueueDefs::NUM_BUFFER_SLOTS) {
-        BQ_LOGE("detachBuffer: slot index %d out of range [0, %d)",
-                slot, BufferQueueDefs::NUM_BUFFER_SLOTS);
-        return BAD_VALUE;
-    } else if (!mSlots[slot].mBufferState.isDequeued()) {
-        BQ_LOGE("detachBuffer: slot %d is not owned by the producer "
-                "(state = %s)", slot, mSlots[slot].mBufferState.string());
-        return BAD_VALUE;
-    } else if (!mSlots[slot].mRequestBufferCalled) {
-        BQ_LOGE("detachBuffer: buffer in slot %d has not been requested",
-                slot);
-        return BAD_VALUE;
-    }
-
-    mSlots[slot].mBufferState.detachProducer();
-    mCore->mActiveBuffers.erase(slot);
-    mCore->mFreeSlots.insert(slot);
-    mCore->clearBufferSlotLocked(slot);
-    mCore->mDequeueCondition.broadcast();
-    VALIDATE_CONSISTENCY();
-
     return NO_ERROR;
 }
 
@@ -591,41 +641,55 @@
         return BAD_VALUE;
     }
 
-    Mutex::Autolock lock(mCore->mMutex);
+    sp<IConsumerListener> consumerListener;
+    sp<IProducerListener> producerListener;
+    int found = BufferQueueCore::INVALID_BUFFER_SLOT;
+    {
+        Mutex::Autolock lock(mCore->mMutex);
+        if (mCore->mIsAbandoned) {
+            BQ_LOGE("detachNextBuffer: BufferQueue has been abandoned");
+            return NO_INIT;
+        }
 
-    if (mCore->mIsAbandoned) {
-        BQ_LOGE("detachNextBuffer: BufferQueue has been abandoned");
-        return NO_INIT;
+        if (mCore->mConnectedApi == BufferQueueCore::NO_CONNECTED_API) {
+            BQ_LOGE("detachNextBuffer: BufferQueue has no connected producer");
+            return NO_INIT;
+        }
+
+        if (mCore->mSingleBufferMode) {
+            BQ_LOGE("detachNextBuffer: cannot detach a buffer in single buffer"
+                    "mode");
+            return BAD_VALUE;
+        }
+
+        mCore->waitWhileAllocatingLocked();
+
+        if (mCore->mFreeBuffers.empty()) {
+            return NO_MEMORY;
+        }
+
+        found = mCore->mFreeBuffers.front();
+        mCore->mFreeBuffers.remove(found);
+        mCore->mFreeSlots.insert(found);
+
+        BQ_LOGV("detachNextBuffer detached slot %d", found);
+
+        *outBuffer = mSlots[found].mGraphicBuffer;
+        *outFence = mSlots[found].mFence;
+        mCore->clearBufferSlotLocked(found);
+        VALIDATE_CONSISTENCY();
+        consumerListener = mCore->mConsumerListener;
+        producerListener = mCore->mConnectedProducerListener;
     }
 
-    if (mCore->mConnectedApi == BufferQueueCore::NO_CONNECTED_API) {
-        BQ_LOGE("detachNextBuffer: BufferQueue has no connected producer");
-        return NO_INIT;
+    // Call back without lock held
+    if (consumerListener != NULL) {
+        consumerListener->onBuffersReleased();
     }
-
-    if (mCore->mSingleBufferMode) {
-        BQ_LOGE("detachNextBuffer: cannot detach a buffer in single buffer"
-                "mode");
-        return BAD_VALUE;
+    if (producerListener != NULL) {
+        producerListener->onSlotFreed(found);
     }
 
-    mCore->waitWhileAllocatingLocked();
-
-    if (mCore->mFreeBuffers.empty()) {
-        return NO_MEMORY;
-    }
-
-    int found = mCore->mFreeBuffers.front();
-    mCore->mFreeBuffers.remove(found);
-    mCore->mFreeSlots.insert(found);
-
-    BQ_LOGV("detachNextBuffer detached slot %d", found);
-
-    *outBuffer = mSlots[found].mGraphicBuffer;
-    *outFence = mSlots[found].mFence;
-    mCore->clearBufferSlotLocked(found);
-    VALIDATE_CONSISTENCY();
-
     return NO_ERROR;
 }
 
@@ -1020,82 +1084,102 @@
 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: api=%d producerControlledByApp=%s", api,
-            producerControlledByApp ? "true" : "false");
-
-    if (mCore->mIsAbandoned) {
-        BQ_LOGE("connect: BufferQueue has been abandoned");
-        return NO_INIT;
-    }
-
-    if (mCore->mConsumerListener == NULL) {
-        BQ_LOGE("connect: BufferQueue has no consumer");
-        return NO_INIT;
-    }
-
-    if (output == NULL) {
-        BQ_LOGE("connect: output was NULL");
-        return BAD_VALUE;
-    }
-
-    if (mCore->mConnectedApi != BufferQueueCore::NO_CONNECTED_API) {
-        BQ_LOGE("connect: already connected (cur=%d req=%d)",
-                mCore->mConnectedApi, api);
-        return BAD_VALUE;
-    }
-
-    int delta = mCore->getMaxBufferCountLocked(mCore->mAsyncMode,
-            mDequeueTimeout < 0 ?
-            mCore->mConsumerControlledByApp && producerControlledByApp : false,
-            mCore->mMaxBufferCount) -
-            mCore->getMaxBufferCountLocked();
-    if (!mCore->adjustAvailableSlotsLocked(delta)) {
-        BQ_LOGE("connect: BufferQueue failed to adjust the number of available "
-                "slots. Delta = %d", delta);
-        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,
-                    static_cast<uint32_t>(mCore->mQueue.size()));
+    sp<IConsumerListener> consumerListener;
+    sp<IProducerListener> producerListener;
+    std::vector<int> freedSlots;
+    {
+        Mutex::Autolock lock(mCore->mMutex);
+        mConsumerName = mCore->mConsumerName;
+        BQ_LOGV("connect: api=%d producerControlledByApp=%s", api,
+                producerControlledByApp ? "true" : "false");
 
-            // Set up a death notification so that we can disconnect
-            // automatically if the remote producer dies
-            if (listener != NULL &&
-                    IInterface::asBinder(listener)->remoteBinder() != NULL) {
-                status = IInterface::asBinder(listener)->linkToDeath(
-                        static_cast<IBinder::DeathRecipient*>(this));
-                if (status != NO_ERROR) {
-                    BQ_LOGE("connect: linkToDeath failed: %s (%d)",
-                            strerror(-status), status);
+        if (mCore->mIsAbandoned) {
+            BQ_LOGE("connect: BufferQueue has been abandoned");
+            return NO_INIT;
+        }
+
+        if (mCore->mConsumerListener == NULL) {
+            BQ_LOGE("connect: BufferQueue has no consumer");
+            return NO_INIT;
+        }
+
+        if (output == NULL) {
+            BQ_LOGE("connect: output was NULL");
+            return BAD_VALUE;
+        }
+
+        if (mCore->mConnectedApi != BufferQueueCore::NO_CONNECTED_API) {
+            BQ_LOGE("connect: already connected (cur=%d req=%d)",
+                    mCore->mConnectedApi, api);
+            return BAD_VALUE;
+        }
+
+        bool dequeueBufferCannotBlock = mDequeueTimeout < 0 ?
+                mCore->mConsumerControlledByApp && producerControlledByApp :
+                false;
+        int delta = mCore->getMaxBufferCountLocked(mCore->mAsyncMode,
+                dequeueBufferCannotBlock, mCore->mMaxBufferCount) -
+                mCore->getMaxBufferCountLocked();
+
+        if (!mCore->adjustAvailableSlotsLocked(delta, &freedSlots)) {
+            BQ_LOGE("connect: BufferQueue failed to adjust the number of "
+                    "available slots. Delta = %d", delta);
+            return BAD_VALUE;
+        }
+
+        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,
+                        static_cast<uint32_t>(mCore->mQueue.size()));
+
+                // Set up a death notification so that we can disconnect
+                // automatically if the remote producer dies
+                if (listener != NULL &&
+                        IInterface::asBinder(listener)->remoteBinder() !=
+                        NULL) {
+                    status = IInterface::asBinder(listener)->linkToDeath(
+                            static_cast<IBinder::DeathRecipient*>(this));
+                    if (status != NO_ERROR) {
+                        BQ_LOGE("connect: linkToDeath failed: %s (%d)",
+                                strerror(-status), status);
+                    }
                 }
-            }
-            mCore->mConnectedProducerListener = listener;
-            break;
-        default:
-            BQ_LOGE("connect: unknown API %d", api);
-            status = BAD_VALUE;
-            break;
+                mCore->mConnectedProducerListener = listener;
+                break;
+            default:
+                BQ_LOGE("connect: unknown API %d", api);
+                status = BAD_VALUE;
+                break;
+        }
+
+        mCore->mBufferHasBeenQueued = false;
+        mCore->mDequeueBufferCannotBlock = dequeueBufferCannotBlock;
+
+        mCore->mAllowAllocation = true;
+        VALIDATE_CONSISTENCY();
+
+        if (delta < 0) {
+            consumerListener = mCore->mConsumerListener;
+            producerListener = listener;
+        }
     }
 
-    mCore->mBufferHasBeenQueued = false;
-    mCore->mDequeueBufferCannotBlock = false;
-    if (mDequeueTimeout < 0) {
-        mCore->mDequeueBufferCannotBlock =
-                mCore->mConsumerControlledByApp && producerControlledByApp;
+    // Call back without lock held
+    if (consumerListener != NULL) {
+        consumerListener->onBuffersReleased();
+    }
+    if (producerListener != NULL) {
+        for (int i : freedSlots) {
+            producerListener->onSlotFreed(i);
+        }
     }
 
-    mCore->mAllowAllocation = true;
-    VALIDATE_CONSISTENCY();
     return status;
 }
 
@@ -1323,19 +1407,40 @@
     ATRACE_CALL();
     BQ_LOGV("setDequeueTimeout: %" PRId64, timeout);
 
-    Mutex::Autolock lock(mCore->mMutex);
-    int delta = mCore->getMaxBufferCountLocked(mCore->mAsyncMode, false,
-            mCore->mMaxBufferCount) - mCore->getMaxBufferCountLocked();
-    if (!mCore->adjustAvailableSlotsLocked(delta)) {
-        BQ_LOGE("setDequeueTimeout: BufferQueue failed to adjust the number of "
-                "available slots. Delta = %d", delta);
-        return BAD_VALUE;
+    sp<IConsumerListener> consumerListener;
+    sp<IProducerListener> producerListener;
+    std::vector<int> freedSlots;
+    {
+        Mutex::Autolock lock(mCore->mMutex);
+        int delta = mCore->getMaxBufferCountLocked(mCore->mAsyncMode, false,
+                mCore->mMaxBufferCount) - mCore->getMaxBufferCountLocked();
+        if (!mCore->adjustAvailableSlotsLocked(delta, &freedSlots)) {
+            BQ_LOGE("setDequeueTimeout: BufferQueue failed to adjust the number"
+                    " of available slots. Delta = %d", delta);
+            return BAD_VALUE;
+        }
+
+        mDequeueTimeout = timeout;
+        mCore->mDequeueBufferCannotBlock = false;
+
+        VALIDATE_CONSISTENCY();
+
+        if (delta < 0) {
+            consumerListener = mCore->mConsumerListener;
+            producerListener = mCore->mConnectedProducerListener;
+        }
     }
 
-    mDequeueTimeout = timeout;
-    mCore->mDequeueBufferCannotBlock = false;
+    // Call back without lock held
+    if (consumerListener != NULL) {
+        consumerListener->onBuffersReleased();
+    }
+    if (producerListener != NULL) {
+        for (int i : freedSlots) {
+            producerListener->onSlotFreed(i);
+        }
+    }
 
-    VALIDATE_CONSISTENCY();
     return NO_ERROR;
 }
 
diff --git a/libs/gui/IProducerListener.cpp b/libs/gui/IProducerListener.cpp
index 81adc95..39c1da8 100644
--- a/libs/gui/IProducerListener.cpp
+++ b/libs/gui/IProducerListener.cpp
@@ -22,6 +22,7 @@
 
 enum {
     ON_BUFFER_RELEASED = IBinder::FIRST_CALL_TRANSACTION,
+    ON_SLOT_FREED,
 };
 
 class BpProducerListener : public BpInterface<IProducerListener>
@@ -37,6 +38,17 @@
         data.writeInterfaceToken(IProducerListener::getInterfaceDescriptor());
         remote()->transact(ON_BUFFER_RELEASED, data, &reply, IBinder::FLAG_ONEWAY);
     }
+
+    virtual void onSlotFreed(int slot) {
+        Parcel data, reply;
+        data.writeInterfaceToken(IProducerListener::getInterfaceDescriptor());
+        data.writeInt32(slot);
+        status_t err = remote()->transact(ON_SLOT_FREED, data, &reply,
+                IBinder::FLAG_ONEWAY);
+        if (err != NO_ERROR) {
+            ALOGE("onSlotFreed failed to transact %d", err);
+        }
+    }
 };
 
 // Out-of-line virtual method definition to trigger vtable emission in this
@@ -52,6 +64,12 @@
             CHECK_INTERFACE(IProducerListener, data, reply);
             onBufferReleased();
             return NO_ERROR;
+        case ON_SLOT_FREED: {
+            CHECK_INTERFACE(IProducerListener, data, reply);
+            int slot = data.readInt32();
+            onSlotFreed(slot);
+            return NO_ERROR;
+        }
     }
     return BBinder::onTransact(code, data, reply, flags);
 }
diff --git a/libs/gui/tests/IGraphicBufferProducer_test.cpp b/libs/gui/tests/IGraphicBufferProducer_test.cpp
index 45b6463..fad0baa 100644
--- a/libs/gui/tests/IGraphicBufferProducer_test.cpp
+++ b/libs/gui/tests/IGraphicBufferProducer_test.cpp
@@ -727,4 +727,55 @@
     ASSERT_EQ(NO_INIT, mProducer->attachBuffer(&slot, buffer));
 }
 
+struct TestListener : public BnProducerListener {
+    virtual void onBufferReleased() {}
+    virtual void onSlotFreed(int slot) {
+        ASSERT_EQ(1, slot);
+    }
+};
+
+TEST_F(IGraphicBufferProducerTest, SlotFreedListenerReturnsCorrectSlot) {
+    const ::testing::TestInfo* const testInfo =
+        ::testing::UnitTest::GetInstance()->current_test_info();
+    ALOGV("Begin test: %s.%s", testInfo->test_case_name(),
+            testInfo->name());
+
+    BufferQueue::createBufferQueue(&mProducer, &mConsumer);
+
+    sp<DummyConsumer> consumerListener = new DummyConsumer;
+    ASSERT_OK(mConsumer->consumerConnect(consumerListener, false));
+
+    sp<TestListener> producerListener = new TestListener;
+    IGraphicBufferProducer::QueueBufferOutput output;
+    ASSERT_OK(mProducer->connect(producerListener, TEST_API,
+            TEST_CONTROLLED_BY_APP, &output));
+
+    ASSERT_OK(mProducer->setMaxDequeuedBufferCount(2));
+
+    DequeueBufferResult buffer0;
+    sp<GraphicBuffer> buf;
+    ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION,
+            dequeueBuffer(DEFAULT_WIDTH, DEFAULT_HEIGHT, DEFAULT_FORMAT,
+            TEST_PRODUCER_USAGE_BITS, &buffer0));
+    ASSERT_OK(mProducer->requestBuffer(buffer0.slot, &buf));
+
+    DequeueBufferResult buffer1;
+    ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION,
+            dequeueBuffer(DEFAULT_WIDTH, DEFAULT_HEIGHT, DEFAULT_FORMAT,
+            TEST_PRODUCER_USAGE_BITS, &buffer1));
+
+    IGraphicBufferProducer::QueueBufferInput input = CreateBufferInput();
+    ASSERT_OK(mProducer->queueBuffer(buffer0.slot, input, &output));
+
+    DequeueBufferResult buffer2;
+    ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION,
+            dequeueBuffer(DEFAULT_WIDTH, DEFAULT_HEIGHT, DEFAULT_FORMAT,
+            TEST_PRODUCER_USAGE_BITS, &buffer2));
+
+    ASSERT_OK(mProducer->cancelBuffer(buffer1.slot, Fence::NO_FENCE));
+
+    ASSERT_OK(mProducer->setMaxDequeuedBufferCount(1));
+}
+
+
 } // namespace android
diff --git a/opengl/tests/hwc/Android.mk b/opengl/tests/hwc/Android.mk
index f83846b..693fba4 100644
--- a/opengl/tests/hwc/Android.mk
+++ b/opengl/tests/hwc/Android.mk
@@ -19,7 +19,7 @@
 
 LOCAL_MODULE_TAGS := tests
 LOCAL_MODULE:= libhwcTest
-LOCAL_CFLAGS := -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES
+LOCAL_CFLAGS := -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES -Wall -Wextra -Werror
 LOCAL_CXX_STL := libc++
 LOCAL_SRC_FILES:= hwcTestLib.cpp
 LOCAL_C_INCLUDES += system/extras/tests/include \
@@ -32,7 +32,7 @@
 
 LOCAL_MODULE:= hwcStress
 LOCAL_MODULE_TAGS := tests
-LOCAL_CFLAGS := -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES
+LOCAL_CFLAGS := -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES -Wall -Wextra -Werror
 LOCAL_CXX_STL := libc++
 LOCAL_SRC_FILES:= hwcStress.cpp
 
@@ -62,7 +62,7 @@
 
 LOCAL_MODULE:= hwcRects
 LOCAL_MODULE_TAGS := tests
-LOCAL_CFLAGS := -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES
+LOCAL_CFLAGS := -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES -Wall -Wextra -Werror
 LOCAL_CXX_STL := libc++
 LOCAL_SRC_FILES:= hwcRects.cpp
 
@@ -92,7 +92,7 @@
 
 LOCAL_MODULE:= hwcColorEquiv
 LOCAL_MODULE_TAGS := tests
-LOCAL_CFLAGS := -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES
+LOCAL_CFLAGS := -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES -Wall -Wextra -Werror
 LOCAL_CXX_STL := libc++
 LOCAL_SRC_FILES:= hwcColorEquiv.cpp
 
@@ -122,7 +122,7 @@
 
 LOCAL_MODULE:= hwcCommit
 LOCAL_MODULE_TAGS := tests
-LOCAL_CFLAGS := -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES
+LOCAL_CFLAGS := -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES -Wall -Wextra -Werror
 LOCAL_CXX_STL := libc++
 LOCAL_SRC_FILES:= hwcCommit.cpp
 
diff --git a/opengl/tests/hwc/hwcColorEquiv.cpp b/opengl/tests/hwc/hwcColorEquiv.cpp
index 06a0191..f1361b8 100644
--- a/opengl/tests/hwc/hwcColorEquiv.cpp
+++ b/opengl/tests/hwc/hwcColorEquiv.cpp
@@ -62,6 +62,8 @@
  *   frame for cases where an equivalent color does not exist.
  */
 
+#define LOG_TAG "hwcColorEquivTest"
+
 #include <algorithm>
 #include <assert.h>
 #include <cerrno>
@@ -87,7 +89,6 @@
 
 #include <ui/GraphicBuffer.h>
 
-#define LOG_TAG "hwcColorEquivTest"
 #include <utils/Log.h>
 #include <testUtil.h>
 
diff --git a/opengl/tests/hwc/hwcCommit.cpp b/opengl/tests/hwc/hwcCommit.cpp
index 1bcb860..6b287e9 100644
--- a/opengl/tests/hwc/hwcCommit.cpp
+++ b/opengl/tests/hwc/hwcCommit.cpp
@@ -70,6 +70,8 @@
  *   made and reported for each of the known graphic format.
  */
 
+#define LOG_TAG "hwcCommitTest"
+
 #include <algorithm>
 #include <assert.h>
 #include <cerrno>
@@ -98,7 +100,6 @@
 
 #include <ui/GraphicBuffer.h>
 
-#define LOG_TAG "hwcCommitTest"
 #include <utils/Log.h>
 #include <testUtil.h>
 
@@ -120,8 +121,6 @@
 const ColorFract defaultColor(0.5, 0.5, 0.5);
 const float      defaultAlpha = 1.0; // Opaque
 const HwcTestDim defaultSourceDim(1, 1);
-const struct hwc_rect defaultSourceCrop = {0, 0, 1, 1};
-const struct hwc_rect defaultDisplayFrame = {0, 0, 100, 100};
 
 // Global Constants
 const uint32_t printFieldWidth = 2;
diff --git a/opengl/tests/hwc/hwcRects.cpp b/opengl/tests/hwc/hwcRects.cpp
index 56c1a2a..2e2b204 100644
--- a/opengl/tests/hwc/hwcRects.cpp
+++ b/opengl/tests/hwc/hwcRects.cpp
@@ -80,6 +80,8 @@
  *   a list of attributes and the format of their expected value.
  */
 
+#define LOG_TAG "hwcRectsTest"
+
 #include <algorithm>
 #include <assert.h>
 #include <cerrno>
@@ -105,8 +107,6 @@
 #include <GLES2/gl2ext.h>
 
 #include <ui/GraphicBuffer.h>
-
-#define LOG_TAG "hwcRectsTest"
 #include <utils/Log.h>
 #include <testUtil.h>
 
diff --git a/opengl/tests/hwc/hwcStress.cpp b/opengl/tests/hwc/hwcStress.cpp
index b1d6c76..60c29ef 100644
--- a/opengl/tests/hwc/hwcStress.cpp
+++ b/opengl/tests/hwc/hwcStress.cpp
@@ -78,6 +78,8 @@
  * a different color from the rest of the rectangle.
  */
 
+#define LOG_TAG "hwcStressTest"
+
 #include <algorithm>
 #include <assert.h>
 #include <cerrno>
@@ -103,7 +105,6 @@
 
 #include <ui/GraphicBuffer.h>
 
-#define LOG_TAG "hwcStressTest"
 #include <utils/Log.h>
 #include <testUtil.h>
 
diff --git a/opengl/tests/lib/Android.mk b/opengl/tests/lib/Android.mk
index e5124ad..4407e7b 100644
--- a/opengl/tests/lib/Android.mk
+++ b/opengl/tests/lib/Android.mk
@@ -22,6 +22,6 @@
 LOCAL_C_INCLUDES += system/extras/tests/include \
 	$(call include-path-for, opengl-tests-includes)
 
-LOCAL_CFLAGS := -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES
+LOCAL_CFLAGS := -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES -Wall -Wextra -Werror
 
 include $(BUILD_STATIC_LIBRARY)
diff --git a/opengl/tests/lib/glTestLib.cpp b/opengl/tests/lib/glTestLib.cpp
index b434fc7..213dffd 100644
--- a/opengl/tests/lib/glTestLib.cpp
+++ b/opengl/tests/lib/glTestLib.cpp
@@ -31,7 +31,6 @@
 #include <utils/Log.h>
 #include <testUtil.h>
 
-using namespace std;
 using namespace android;
 
 void glTestPrintGLString(const char *name, GLenum s)
diff --git a/opengl/tools/glgen/stubs/gles11/glGetTransformFeedbackVarying.cpp b/opengl/tools/glgen/stubs/gles11/glGetTransformFeedbackVarying.cpp
index 47f232d..aa0d2a4 100644
--- a/opengl/tools/glgen/stubs/gles11/glGetTransformFeedbackVarying.cpp
+++ b/opengl/tools/glgen/stubs/gles11/glGetTransformFeedbackVarying.cpp
@@ -118,22 +118,35 @@
 static void
 android_glGetTransformFeedbackVarying__IIILjava_nio_IntBuffer_2Ljava_nio_IntBuffer_2Ljava_nio_IntBuffer_2B
   (JNIEnv *_env, jobject _this, jint program, jint index, jint bufsize, jobject length_buf, jobject size_buf, jobject type_buf, jbyte name) {
+    jniThrowException(_env, "java/lang/UnsupportedOperationException", "deprecated");
+}
+
+/* void glGetTransformFeedbackVarying ( GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLint *size, GLenum *type, GLchar *name ) */
+static void
+android_glGetTransformFeedbackVarying__IIILjava_nio_IntBuffer_2Ljava_nio_IntBuffer_2Ljava_nio_IntBuffer_2Ljava_nio_ByteBuffer_2
+  (JNIEnv *_env, jobject _this, jint program, jint index, jint bufsize, jobject length_buf, jobject size_buf, jobject type_buf, jobject name_buf) {
     jintArray _lengthArray = (jintArray) 0;
     jint _lengthBufferOffset = (jint) 0;
     jintArray _sizeArray = (jintArray) 0;
     jint _sizeBufferOffset = (jint) 0;
     jintArray _typeArray = (jintArray) 0;
     jint _typeBufferOffset = (jint) 0;
+    jbyteArray _nameArray = (jbyteArray)0;
+    jint _nameBufferOffset = (jint)0;
     jint _lengthRemaining;
     GLsizei *length = (GLsizei *) 0;
     jint _sizeRemaining;
     GLint *size = (GLint *) 0;
     jint _typeRemaining;
     GLenum *type = (GLenum *) 0;
+    jint _nameRemaining;
+    GLchar* name = (GLchar*)0;
+
 
     length = (GLsizei *)getPointer(_env, length_buf, (jarray*)&_lengthArray, &_lengthRemaining, &_lengthBufferOffset);
     size = (GLint *)getPointer(_env, size_buf, (jarray*)&_sizeArray, &_sizeRemaining, &_sizeBufferOffset);
     type = (GLenum *)getPointer(_env, type_buf, (jarray*)&_typeArray, &_typeRemaining, &_typeBufferOffset);
+    name = (GLchar*)getPointer(_env, name_buf, (jarray*)&_nameArray, &_nameRemaining, &_nameBufferOffset);
     if (length == NULL) {
         char * _lengthBase = (char *)_env->GetIntArrayElements(_lengthArray, (jboolean *) 0);
         length = (GLsizei *) (_lengthBase + _lengthBufferOffset);
@@ -146,6 +159,10 @@
         char * _typeBase = (char *)_env->GetIntArrayElements(_typeArray, (jboolean *) 0);
         type = (GLenum *) (_typeBase + _typeBufferOffset);
     }
+    if (name == NULL) {
+        char* _nameBase = (char *)_env->GetByteArrayElements(_nameArray, (jboolean*)0);
+        name = (GLchar *) (_nameBase + _nameBufferOffset);
+    }
     glGetTransformFeedbackVarying(
         (GLuint)program,
         (GLuint)index,
@@ -153,11 +170,7 @@
         (GLsizei *)length,
         (GLint *)size,
         (GLenum *)type,
-        // The cast below is incorrect. The driver will end up writing to the
-        // address specified by name, which will always crash the process since
-        // it is guaranteed to be in low memory. The additional static_cast
-        // suppresses the warning for now. http://b/19478262
-        (char *)static_cast<uintptr_t>(name)
+        (GLchar*)name
     );
     if (_typeArray) {
         releaseArrayPointer<jintArray, jint*, IntArrayReleaser>(_env, _typeArray, (jint*)type, JNI_TRUE);
@@ -168,6 +181,9 @@
     if (_lengthArray) {
         releaseArrayPointer<jintArray, jint*, IntArrayReleaser>(_env, _lengthArray, (jint*)length, JNI_TRUE);
     }
+    if (_nameArray) {
+        releaseArrayPointer<jbyteArray, jbyte*, ByteArrayReleaser>(_env, _nameArray, (jbyte*)name, JNI_TRUE);
+    }
 }
 
 /* void glGetTransformFeedbackVarying ( GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLint *size, GLenum *type, GLchar *name ) */
diff --git a/opengl/tools/glgen/stubs/gles11/glGetTransformFeedbackVarying.java b/opengl/tools/glgen/stubs/gles11/glGetTransformFeedbackVarying.java
index f73bbfe..e54359d 100644
--- a/opengl/tools/glgen/stubs/gles11/glGetTransformFeedbackVarying.java
+++ b/opengl/tools/glgen/stubs/gles11/glGetTransformFeedbackVarying.java
@@ -15,7 +15,10 @@
     );
 
     // C function void glGetTransformFeedbackVarying ( GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLint *size, GLenum *type, GLchar *name )
-
+    /**
+     * @deprecated
+     * Use the version that takes a ByteBuffer as the last argument, or the versions that return a String.
+     * */
     public static native void glGetTransformFeedbackVarying(
         int program,
         int index,
@@ -28,6 +31,18 @@
 
     // C function void glGetTransformFeedbackVarying ( GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLint *size, GLenum *type, GLchar *name )
 
+    public static native void glGetTransformFeedbackVarying(
+        int program,
+        int index,
+        int bufsize,
+        java.nio.IntBuffer length,
+        java.nio.IntBuffer size,
+        java.nio.IntBuffer type,
+        java.nio.ByteBuffer name
+    );
+
+    // C function void glGetTransformFeedbackVarying ( GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLint *size, GLenum *type, GLchar *name )
+
     public static native String glGetTransformFeedbackVarying(
         int program,
         int index,
diff --git a/opengl/tools/glgen/stubs/gles11/glGetTransformFeedbackVarying.nativeReg b/opengl/tools/glgen/stubs/gles11/glGetTransformFeedbackVarying.nativeReg
index 412d04c..7f5829b 100644
--- a/opengl/tools/glgen/stubs/gles11/glGetTransformFeedbackVarying.nativeReg
+++ b/opengl/tools/glgen/stubs/gles11/glGetTransformFeedbackVarying.nativeReg
@@ -1,4 +1,5 @@
 {"glGetTransformFeedbackVarying", "(III[II[II[II[BI)V", (void *) android_glGetTransformFeedbackVarying__III_3II_3II_3II_3BI },
 {"glGetTransformFeedbackVarying", "(IIILjava/nio/IntBuffer;Ljava/nio/IntBuffer;Ljava/nio/IntBuffer;B)V", (void *) android_glGetTransformFeedbackVarying__IIILjava_nio_IntBuffer_2Ljava_nio_IntBuffer_2Ljava_nio_IntBuffer_2B },
+{"glGetTransformFeedbackVarying", "(IIILjava/nio/IntBuffer;Ljava/nio/IntBuffer;Ljava/nio/IntBuffer;Ljava/nio/ByteBuffer;)V", (void *) android_glGetTransformFeedbackVarying__IIILjava_nio_IntBuffer_2Ljava_nio_IntBuffer_2Ljava_nio_IntBuffer_2Ljava_nio_ByteBuffer_2 },
 {"glGetTransformFeedbackVarying", "(II[II[II)Ljava/lang/String;", (void *) android_glGetTransformFeedbackVarying1 },
 {"glGetTransformFeedbackVarying", "(IILjava/nio/IntBuffer;Ljava/nio/IntBuffer;)Ljava/lang/String;", (void *) android_glGetTransformFeedbackVarying2 },
diff --git a/vulkan/libvulkan/Android.mk b/vulkan/libvulkan/Android.mk
index 779fedf..85b8ab2 100644
--- a/vulkan/libvulkan/Android.mk
+++ b/vulkan/libvulkan/Android.mk
@@ -16,6 +16,8 @@
 include $(CLEAR_VARS)
 
 LOCAL_CLANG := true
+LOCAL_SANITIZE := integer
+
 LOCAL_CFLAGS := -DLOG_TAG=\"vulkan\" \
 	-std=c99 -fvisibility=hidden -fstrict-aliasing \
 	-Weverything -Werror \
diff --git a/vulkan/libvulkan/swapchain.cpp b/vulkan/libvulkan/swapchain.cpp
index 5fefc62..7f944cf 100644
--- a/vulkan/libvulkan/swapchain.cpp
+++ b/vulkan/libvulkan/swapchain.cpp
@@ -511,16 +511,18 @@
         return VK_ERROR_INITIALIZATION_FAILED;
     }
 
-    uint32_t min_undequeued_buffers;
-    err = surface.window->query(
-        surface.window.get(), NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS,
-        reinterpret_cast<int*>(&min_undequeued_buffers));
-    if (err != 0) {
+    int query_value;
+    err = surface.window->query(surface.window.get(),
+                                NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS,
+                                &query_value);
+    if (err != 0 || query_value < 0) {
         // TODO(jessehall): Improve error reporting. Can we enumerate possible
         // errors and translate them to valid Vulkan result codes?
-        ALOGE("window->query failed: %s (%d)", strerror(-err), err);
+        ALOGE("window->query failed: %s (%d) value=%d", strerror(-err), err,
+              query_value);
         return VK_ERROR_INITIALIZATION_FAILED;
     }
+    uint32_t min_undequeued_buffers = static_cast<uint32_t>(query_value);
     // The MIN_UNDEQUEUED_BUFFERS query doesn't know whether we'll be using
     // async mode or not, and assumes not. But in async mode, the BufferQueue
     // requires an extra undequeued buffer.