BufferQueueProducer: Signal consumer when a buffer is detached

When a buffer is detached, it should be cleared from the consumer-side
cache as well.

Not doing so can leak buffers no longer owned by the queue for extended
lengths of time, depending on the exact usage patterns of the producer
and consumer.

Bug: 28695173
Change-Id: I2c618be51f2c827d92d0e19b92a2d5befda87c38
diff --git a/libs/gui/BufferQueueProducer.cpp b/libs/gui/BufferQueueProducer.cpp
index 69a408c..be3b6c3 100644
--- a/libs/gui/BufferQueueProducer.cpp
+++ b/libs/gui/BufferQueueProducer.cpp
@@ -553,44 +553,53 @@
     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> listener;
+    {
+        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->mSharedBufferMode || mCore->mSharedBufferSlot == slot) {
+            BQ_LOGE("detachBuffer: cannot detach a buffer in shared 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();
+        listener = mCore->mConsumerListener;
     }
 
-    if (mCore->mConnectedApi == BufferQueueCore::NO_CONNECTED_API) {
-        BQ_LOGE("detachBuffer: BufferQueue has no connected producer");
-        return NO_INIT;
+    if (listener != NULL) {
+        listener->onBuffersReleased();
     }
 
-    if (mCore->mSharedBufferMode || mCore->mSharedBufferSlot == slot) {
-        BQ_LOGE("detachBuffer: cannot detach a buffer in shared 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();
-
     return NO_ERROR;
 }