Merge "Post to all existing and non-existing consumers of the buffer"
diff --git a/libs/vr/libbufferhub/buffer_hub-test.cpp b/libs/vr/libbufferhub/buffer_hub-test.cpp
index 1359f4c..487a604 100644
--- a/libs/vr/libbufferhub/buffer_hub-test.cpp
+++ b/libs/vr/libbufferhub/buffer_hub-test.cpp
@@ -361,9 +361,11 @@
   ASSERT_TRUE(p.get() != nullptr);
   ASSERT_EQ(0, p->GainAsync());
   ASSERT_EQ(0, p->Post(LocalHandle()));
-  // Producer state bit is in released state after post. The overall state of
-  // the buffer is also released because there is no consumer of this buffer.
-  ASSERT_TRUE(IsBufferReleased(p->buffer_state()));
+  // Producer state bit is in released state after post, other clients shall be
+  // in posted state although there is no consumer of this buffer yet.
+  ASSERT_TRUE(IsClientReleased(p->buffer_state(), p->client_state_mask()));
+  ASSERT_FALSE(IsBufferReleased(p->buffer_state()));
+  ASSERT_TRUE(AnyClientPosted(p->buffer_state()));
 
   // Gain in released state should succeed.
   LocalHandle invalid_fence;
@@ -450,27 +452,17 @@
   LocalHandle invalid_fence;
 
   // Post the gained buffer before any consumer gets created.
-  // The buffer should be in released state because it is not expected to be
-  // read by any clients.
   EXPECT_EQ(0, p->PostAsync(&metadata, invalid_fence));
-  EXPECT_TRUE(IsBufferReleased(p->buffer_state()));
+  EXPECT_FALSE(IsBufferReleased(p->buffer_state()));
   EXPECT_EQ(0, RETRY_EINTR(p->Poll(kPollTimeoutMs)));
 
-  // Newly created consumer will not be signalled for the posted buffer before
-  // its creation. It cannot acquire the buffer immediately.
+  // Newly created consumer will be signalled for the posted buffer although it
+  // is created after producer posting.
   std::unique_ptr<ConsumerBuffer> c =
       ConsumerBuffer::Import(p->CreateConsumer());
   ASSERT_TRUE(c.get() != nullptr);
-  EXPECT_FALSE(IsClientPosted(c->buffer_state(), c->client_state_mask()));
-  EXPECT_EQ(-EBUSY, c->AcquireAsync(&metadata, &invalid_fence));
-
-  // Producer should be able to gain back and post the buffer
-  EXPECT_EQ(0, p->GainAsync());
-  EXPECT_EQ(0, p->PostAsync(&metadata, invalid_fence));
-
-  // Consumer should be able to pick up the buffer this time.
+  EXPECT_TRUE(IsClientPosted(c->buffer_state(), c->client_state_mask()));
   EXPECT_EQ(0, c->AcquireAsync(&metadata, &invalid_fence));
-  EXPECT_TRUE(IsClientAcquired(c->buffer_state(), c->client_state_mask()));
 }
 
 TEST_F(LibBufferHubTest, TestCreateConsumerWhenBufferReleased) {
diff --git a/libs/vr/libbufferhub/include/private/dvr/buffer_hub_base.h b/libs/vr/libbufferhub/include/private/dvr/buffer_hub_base.h
index 440a59d..889763a 100644
--- a/libs/vr/libbufferhub/include/private/dvr/buffer_hub_base.h
+++ b/libs/vr/libbufferhub/include/private/dvr/buffer_hub_base.h
@@ -94,6 +94,12 @@
     return buffer_state_->load(std::memory_order_acquire);
   };
 
+  // Returns whether the buffer is already released by all current clients.
+  bool is_released() {
+    return (buffer_state() &
+            active_clients_bit_mask_->load(std::memory_order_acquire)) == 0;
+  }
+
   // A state mask which is unique to a buffer hub client among all its siblings
   // sharing the same concrete graphic buffer.
   uint32_t client_state_mask() const { return client_state_mask_; }
diff --git a/libs/vr/libbufferhub/producer_buffer.cpp b/libs/vr/libbufferhub/producer_buffer.cpp
index 5274bf2..edfdddf 100644
--- a/libs/vr/libbufferhub/producer_buffer.cpp
+++ b/libs/vr/libbufferhub/producer_buffer.cpp
@@ -89,13 +89,10 @@
     return -EBUSY;
   }
 
-  // Set the producer client buffer state to released, other clients' buffer
-  // state to posted.
-  uint32_t current_active_clients_bit_mask =
-      active_clients_bit_mask_->load(std::memory_order_acquire);
-  uint32_t updated_buffer_state = current_active_clients_bit_mask &
-                                  (~client_state_mask()) &
-                                  BufferHubDefs::kHighBitsMask;
+  // Set the producer client buffer state to released, that of all other clients
+  // (both existing and non-existing clients) to posted.
+  uint32_t updated_buffer_state =
+      (~client_state_mask()) & BufferHubDefs::kHighBitsMask;
   while (!buffer_state_->compare_exchange_weak(
       current_buffer_state, updated_buffer_state, std::memory_order_acq_rel,
       std::memory_order_acquire)) {
@@ -176,7 +173,9 @@
   }
   if (BufferHubDefs::AnyClientAcquired(current_buffer_state) ||
       BufferHubDefs::AnyClientGained(current_buffer_state) ||
-      (BufferHubDefs::AnyClientPosted(current_buffer_state) &&
+      (BufferHubDefs::AnyClientPosted(
+           current_buffer_state &
+           active_clients_bit_mask_->load(std::memory_order_acquire)) &&
        !gain_posted_buffer)) {
     ALOGE("%s: not released id=%d state=%" PRIx32 ".", __FUNCTION__, id(),
           current_buffer_state);
@@ -198,7 +197,9 @@
 
     if (BufferHubDefs::AnyClientAcquired(current_buffer_state) ||
         BufferHubDefs::AnyClientGained(current_buffer_state) ||
-        (BufferHubDefs::AnyClientPosted(current_buffer_state) &&
+        (BufferHubDefs::AnyClientPosted(
+             current_buffer_state &
+             active_clients_bit_mask_->load(std::memory_order_acquire)) &&
          !gain_posted_buffer)) {
       ALOGE(
           "%s: Failed to gain the buffer. The buffer is no longer released. "
diff --git a/services/vr/bufferhubd/producer_channel.cpp b/services/vr/bufferhubd/producer_channel.cpp
index 2a6e9da..409bce9 100644
--- a/services/vr/bufferhubd/producer_channel.cpp
+++ b/services/vr/bufferhubd/producer_channel.cpp
@@ -369,7 +369,9 @@
           (consumer_state_mask & BufferHubDefs::kHighBitsMask);
     }
   }
-  if (update_buffer_state) {
+  if (update_buffer_state || BufferHubDefs::IsClientPosted(
+                                 buffer_state_->load(std::memory_order_acquire),
+                                 consumer_state_mask)) {
     consumer->OnProducerPosted();
   }
 
@@ -537,8 +539,13 @@
 
   uint32_t current_buffer_state =
       buffer_state_->load(std::memory_order_acquire);
+  uint32_t current_active_clients_bit_mask =
+      active_clients_bit_mask_->load(std::memory_order_acquire);
+  // Signal producer if all current active consumers have released the buffer.
   if (BufferHubDefs::IsBufferReleased(current_buffer_state &
-                                      ~orphaned_consumer_bit_mask_)) {
+                                      ~orphaned_consumer_bit_mask_ &
+                                      current_active_clients_bit_mask)) {
+    buffer_state_->store(0U);
     SignalAvailable();
     if (orphaned_consumer_bit_mask_) {
       ALOGW(
@@ -564,8 +571,13 @@
 
   uint32_t current_buffer_state =
       buffer_state_->load(std::memory_order_acquire);
+  uint32_t current_active_clients_bit_mask =
+      active_clients_bit_mask_->load(std::memory_order_acquire);
+  // Signal producer if all current active consumers have released the buffer.
   if (BufferHubDefs::IsBufferReleased(current_buffer_state &
-                                      ~orphaned_consumer_bit_mask_)) {
+                                      ~orphaned_consumer_bit_mask_ &
+                                      current_active_clients_bit_mask)) {
+    buffer_state_->store(0U);
     SignalAvailable();
   }