dvr_read_buffer_queue: don't stop releasing buffer

We used to abort ReleaseBuffer logic if we cannot verify that the buffer
being released is in the target queue. However, in certain edge case,
this could be true and we still want to release the buffer. One example
is when a ProducerQueue closes and triggers its ConsumerQueue to remove
all its buffers. In this case, ConsumerQueue::ReleaseBuffer() should
still function properly.

Bug: 77982072
Test: dvr_buffer_queue-test
Change-Id: I6d8e2525470c8e3d78862d3f0753c8735d528b53
diff --git a/libs/vr/libdvr/dvr_buffer.cpp b/libs/vr/libdvr/dvr_buffer.cpp
index 1a99234..88b649f 100644
--- a/libs/vr/libdvr/dvr_buffer.cpp
+++ b/libs/vr/libdvr/dvr_buffer.cpp
@@ -48,7 +48,8 @@
     ALOGW_IF(
         write_buffer->slot != -1,
         "dvrWriteBufferDestroy: Destroying a buffer associated with a valid "
-        "buffer queue slot. This may indicate possible leaks.");
+        "buffer queue slot. This may indicate possible leaks, buffer_id=%d.",
+        dvrWriteBufferGetId(write_buffer));
     delete write_buffer;
   }
 }
@@ -118,7 +119,8 @@
     ALOGW_IF(
         read_buffer->slot != -1,
         "dvrReadBufferDestroy: Destroying a buffer associated with a valid "
-        "buffer queue slot. This may indicate possible leaks.");
+        "buffer queue slot. This may indicate possible leaks, buffer_id=%d.",
+        dvrReadBufferGetId(read_buffer));
     delete read_buffer;
   }
 }
diff --git a/libs/vr/libdvr/dvr_buffer_queue.cpp b/libs/vr/libdvr/dvr_buffer_queue.cpp
index c36d190..6991b15 100644
--- a/libs/vr/libdvr/dvr_buffer_queue.cpp
+++ b/libs/vr/libdvr/dvr_buffer_queue.cpp
@@ -434,12 +434,22 @@
     return -EINVAL;
   }
   if (read_buffer->read_buffer->id() != consumer_queue_->GetBufferId(slot)) {
-    ALOGE(
-        "DvrReadBufferQueue::ReleaseBuffer: Buffer to be released does not "
-        "belong to this buffer queue. Releasing buffer: id=%d, buffer in "
-        "queue: id=%d",
-        read_buffer->read_buffer->id(), consumer_queue_->GetBufferId(slot));
-    return -EINVAL;
+    if (consumer_queue_->GetBufferId(slot) > 0) {
+      ALOGE(
+          "DvrReadBufferQueue::ReleaseBuffer: Buffer to be released may not "
+          "belong to this queue (queue_id=%d): attempting to release buffer "
+          "(buffer_id=%d) at slot %d which holds a different buffer "
+          "(buffer_id=%d).",
+          consumer_queue_->id(), read_buffer->read_buffer->id(),
+          static_cast<int>(slot), consumer_queue_->GetBufferId(slot));
+    } else {
+      ALOGI(
+          "DvrReadBufferQueue::ReleaseBuffer: Buffer to be released may not "
+          "belong to this queue (queue_id=%d): attempting to release buffer "
+          "(buffer_id=%d) at slot %d which is empty.",
+          consumer_queue_->id(), read_buffer->read_buffer->id(),
+          static_cast<int>(slot));
+    }
   }
 
   pdx::LocalHandle fence(release_fence_fd);
diff --git a/libs/vr/libdvr/tests/dvr_buffer_queue-test.cpp b/libs/vr/libdvr/tests/dvr_buffer_queue-test.cpp
index 5d9d8b5..2d5f004 100644
--- a/libs/vr/libdvr/tests/dvr_buffer_queue-test.cpp
+++ b/libs/vr/libdvr/tests/dvr_buffer_queue-test.cpp
@@ -525,4 +525,55 @@
   }
 }
 
+TEST_F(DvrBufferQueueTest, ConsumerReleaseAfterProducerDestroy) {
+  int ret = api_.WriteBufferQueueCreate(
+      kBufferWidth, kBufferHeight, kBufferFormat, kLayerCount, kBufferUsage,
+      kQueueCapacity, sizeof(DvrNativeBufferMetadata), &write_queue_);
+  ASSERT_EQ(ret, 0);
+
+  DvrReadBufferQueue* read_queue = nullptr;
+  DvrReadBuffer* rb = nullptr;
+  DvrWriteBuffer* wb = nullptr;
+  DvrNativeBufferMetadata meta1;
+  DvrNativeBufferMetadata meta2;
+  int fence_fd = -1;
+
+  ret = api_.WriteBufferQueueCreateReadQueue(write_queue_, &read_queue);
+  ASSERT_EQ(ret, 0);
+
+  api_.ReadBufferQueueSetBufferAvailableCallback(
+      read_queue, &BufferAvailableCallback, this);
+
+  // Gain buffer for writing.
+  ret = api_.WriteBufferQueueGainBuffer(write_queue_, /*timeout=*/0, &wb,
+                                        &meta1, &fence_fd);
+  ASSERT_EQ(ret, 0);
+  close(fence_fd);
+
+  // Post buffer to the read_queue.
+  ret = api_.WriteBufferQueuePostBuffer(write_queue_, wb, &meta1, /*fence=*/-1);
+  ASSERT_EQ(ret, 0);
+  wb = nullptr;
+
+  // Acquire buffer for reading.
+  ret = api_.ReadBufferQueueAcquireBuffer(read_queue, /*timeout=*/10, &rb,
+                                          &meta2, &fence_fd);
+  ASSERT_EQ(ret, 0);
+  close(fence_fd);
+
+  // Destroy the write buffer queue and make sure the reader queue is picking
+  // these events up.
+  api_.WriteBufferQueueDestroy(write_queue_);
+  ret = api_.ReadBufferQueueHandleEvents(read_queue);
+  ASSERT_EQ(0, ret);
+
+  // Release buffer to the write_queue.
+  ret = api_.ReadBufferQueueReleaseBuffer(read_queue, rb, &meta2,
+                                          /*release_fence_fd=*/-1);
+  ASSERT_EQ(ret, 0);
+  rb = nullptr;
+
+  api_.ReadBufferQueueDestroy(read_queue);
+}
+
 }  // namespace