OSDN Git Service

BufferQueueProducer: Signal consumer when a buffer is detached
authorEino-Ville Talvala <etalvala@google.com>
Fri, 10 Jun 2016 21:21:02 +0000 (14:21 -0700)
committerEino-Ville Talvala <etalvala@google.com>
Fri, 10 Jun 2016 21:21:02 +0000 (14:21 -0700)
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

libs/gui/BufferQueueProducer.cpp

index 69a408c..be3b6c3 100644 (file)
@@ -553,43 +553,52 @@ status_t BufferQueueProducer::detachBuffer(int slot) {
     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->mConnectedApi == BufferQueueCore::NO_CONNECTED_API) {
-        BQ_LOGE("detachBuffer: BufferQueue has no connected producer");
-        return NO_INIT;
-    }
+        if (mCore->mIsAbandoned) {
+            BQ_LOGE("detachBuffer: BufferQueue has been abandoned");
+            return NO_INIT;
+        }
 
-    if (mCore->mSharedBufferMode || mCore->mSharedBufferSlot == slot) {
-        BQ_LOGE("detachBuffer: cannot detach a buffer in shared buffer mode");
-        return BAD_VALUE;
-    }
+        if (mCore->mConnectedApi == BufferQueueCore::NO_CONNECTED_API) {
+            BQ_LOGE("detachBuffer: BufferQueue has no connected producer");
+            return NO_INIT;
+        }
 
-    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;
+        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;
     }
 
-    mSlots[slot].mBufferState.detachProducer();
-    mCore->mActiveBuffers.erase(slot);
-    mCore->mFreeSlots.insert(slot);
-    mCore->clearBufferSlotLocked(slot);
-    mCore->mDequeueCondition.broadcast();
-    VALIDATE_CONSISTENCY();
+    if (listener != NULL) {
+        listener->onBuffersReleased();
+    }
 
     return NO_ERROR;
 }