Merge "Allow ProducerBuffer gain posted buffer."
diff --git a/libs/vr/libbufferhub/buffer_hub-test.cpp b/libs/vr/libbufferhub/buffer_hub-test.cpp
index 4d98dfc..8351efc 100644
--- a/libs/vr/libbufferhub/buffer_hub-test.cpp
+++ b/libs/vr/libbufferhub/buffer_hub-test.cpp
@@ -328,6 +328,36 @@
   EXPECT_FALSE(invalid_fence.IsValid());
 }
 
+TEST_F(LibBufferHubTest, TestGainPostedBuffer) {
+  std::unique_ptr<ProducerBuffer> p = ProducerBuffer::Create(
+      kWidth, kHeight, kFormat, kUsage, sizeof(uint64_t));
+  ASSERT_TRUE(p.get() != nullptr);
+
+  // The producer buffer starts in gained state. Post the buffer.
+  ASSERT_EQ(0, p->Post(LocalHandle()));
+
+  // Gain in posted state should only succeed with gain_posted_buffer = true.
+  LocalHandle invalid_fence;
+  EXPECT_EQ(-EBUSY, p->Gain(&invalid_fence, false));
+  EXPECT_EQ(0, p->Gain(&invalid_fence, true));
+}
+
+TEST_F(LibBufferHubTest, TestGainPostedBufferAsync) {
+  std::unique_ptr<ProducerBuffer> p = ProducerBuffer::Create(
+      kWidth, kHeight, kFormat, kUsage, sizeof(uint64_t));
+  ASSERT_TRUE(p.get() != nullptr);
+
+  // The producer buffer starts in gained state. Post the buffer.
+  ASSERT_EQ(0, p->Post(LocalHandle()));
+
+  // GainAsync in posted state should only succeed with gain_posted_buffer
+  // equals true.
+  DvrNativeBufferMetadata metadata;
+  LocalHandle invalid_fence;
+  EXPECT_EQ(-EBUSY, p->GainAsync(&metadata, &invalid_fence, false));
+  EXPECT_EQ(0, p->GainAsync(&metadata, &invalid_fence, true));
+}
+
 TEST_F(LibBufferHubTest, TestZeroConsumer) {
   std::unique_ptr<ProducerBuffer> p = ProducerBuffer::Create(
       kWidth, kHeight, kFormat, kUsage, sizeof(uint64_t));
diff --git a/libs/vr/libbufferhub/include/private/dvr/producer_buffer.h b/libs/vr/libbufferhub/include/private/dvr/producer_buffer.h
index d2d4d1e..2761416 100644
--- a/libs/vr/libbufferhub/include/private/dvr/producer_buffer.h
+++ b/libs/vr/libbufferhub/include/private/dvr/producer_buffer.h
@@ -52,11 +52,14 @@
 
   // Attempt to re-gain the buffer for writing. If |release_fence| is valid, it
   // must be waited on before using the buffer. If it is not valid then the
-  // buffer is free for immediate use. This call will only succeed if the buffer
-  // is in the released state.
-  // This returns zero or a negative unix error code.
-  int Gain(LocalHandle* release_fence);
-  int GainAsync();
+  // buffer is free for immediate use. This call will succeed if the buffer
+  // is in the released state, or in posted state and gain_posted_buffer is
+  // true.
+  //
+  // @param release_fence output fence.
+  // @param gain_posted_buffer whether to gain posted buffer or not.
+  // @return This returns zero or a negative unix error code.
+  int Gain(LocalHandle* release_fence, bool gain_posted_buffer = false);
 
   // Asynchronously marks a released buffer as gained. This method is similar to
   // the synchronous version above, except that it does not wait for BufferHub
@@ -64,7 +67,13 @@
   // the underlying message, no error is returned if this method is called when
   // the buffer is in an incorrect state. Returns zero if sending the message
   // succeeded, or a negative errno code if local error check fails.
-  int GainAsync(DvrNativeBufferMetadata* out_meta, LocalHandle* out_fence);
+  // TODO(b/112007999): gain_posted_buffer true is only used to prevent
+  // libdvrtracking from starving when there are non-responding clients. This
+  // gain_posted_buffer param can be removed once libdvrtracking start to use
+  // the new AHardwareBuffer API.
+  int GainAsync(DvrNativeBufferMetadata* out_meta, LocalHandle* out_fence,
+                bool gain_posted_buffer = false);
+  int GainAsync();
 
   // Detaches a ProducerBuffer from an existing producer/consumer set. Can only
   // be called when a producer buffer has exclusive access to the buffer (i.e.
@@ -92,7 +101,8 @@
   explicit ProducerBuffer(LocalChannelHandle channel);
 
   // Local state transition helpers.
-  int LocalGain(DvrNativeBufferMetadata* out_meta, LocalHandle* out_fence);
+  int LocalGain(DvrNativeBufferMetadata* out_meta, LocalHandle* out_fence,
+                bool gain_posted_buffer = false);
   int LocalPost(const DvrNativeBufferMetadata* meta,
                 const LocalHandle& ready_fence);
 };
diff --git a/libs/vr/libbufferhub/producer_buffer.cpp b/libs/vr/libbufferhub/producer_buffer.cpp
index 7b6f77a..8f0e3e3 100644
--- a/libs/vr/libbufferhub/producer_buffer.cpp
+++ b/libs/vr/libbufferhub/producer_buffer.cpp
@@ -134,7 +134,7 @@
 }
 
 int ProducerBuffer::LocalGain(DvrNativeBufferMetadata* out_meta,
-                              LocalHandle* out_fence) {
+                              LocalHandle* out_fence, bool gain_posted_buffer) {
   uint64_t buffer_state = buffer_state_->load();
   ALOGD_IF(TRACE, "ProducerBuffer::LocalGain: buffer=%d, state=%" PRIx64 ".",
            id(), buffer_state);
@@ -142,13 +142,14 @@
   if (!out_meta)
     return -EINVAL;
 
-  if (!BufferHubDefs::IsBufferReleased(buffer_state)) {
-    if (BufferHubDefs::IsBufferGained(buffer_state)) {
-      // We don't want to log error when gaining a newly allocated
-      // buffer.
-      ALOGI("ProducerBuffer::LocalGain: already gained id=%d.", id());
-      return -EALREADY;
-    }
+  if (BufferHubDefs::IsBufferGained(buffer_state)) {
+    // We don't want to log error when gaining a newly allocated
+    // buffer.
+    ALOGI("ProducerBuffer::LocalGain: already gained id=%d.", id());
+    return -EALREADY;
+  }
+  if (BufferHubDefs::IsBufferAcquired(buffer_state) ||
+      (BufferHubDefs::IsBufferPosted(buffer_state) && !gain_posted_buffer)) {
     ALOGE("ProducerBuffer::LocalGain: not released id=%d state=%" PRIx64 ".",
           id(), buffer_state);
     return -EBUSY;
@@ -180,11 +181,11 @@
   return 0;
 }
 
-int ProducerBuffer::Gain(LocalHandle* release_fence) {
+int ProducerBuffer::Gain(LocalHandle* release_fence, bool gain_posted_buffer) {
   ATRACE_NAME("ProducerBuffer::Gain");
 
   DvrNativeBufferMetadata meta;
-  if (const int error = LocalGain(&meta, release_fence))
+  if (const int error = LocalGain(&meta, release_fence, gain_posted_buffer))
     return error;
 
   auto status = InvokeRemoteMethod<BufferHubRPC::ProducerGain>();
@@ -194,10 +195,11 @@
 }
 
 int ProducerBuffer::GainAsync(DvrNativeBufferMetadata* out_meta,
-                              LocalHandle* release_fence) {
+                              LocalHandle* release_fence,
+                              bool gain_posted_buffer) {
   ATRACE_NAME("ProducerBuffer::GainAsync");
 
-  if (const int error = LocalGain(out_meta, release_fence))
+  if (const int error = LocalGain(out_meta, release_fence, gain_posted_buffer))
     return error;
 
   return ReturnStatusOrError(SendImpulse(BufferHubRPC::ProducerGain::Opcode));