Implement changes of buffer state in Gain/Post/Acquire/Release methods in BufferHubBuffer.

Create shortcuts to atomics in BufferHubBuffer;
Implement changes of buffer state in the four usages of the buffer;
Create 16 unit tests for the 16 buffer state transitions.

Test: BufferHubBuffer_test
Bug: 118718711
Change-Id: I2067cd141611e66732e28344f26d73f261072b8b
diff --git a/libs/ui/BufferHubBuffer.cpp b/libs/ui/BufferHubBuffer.cpp
index e747ee1..3816c1b 100644
--- a/libs/ui/BufferHubBuffer.cpp
+++ b/libs/ui/BufferHubBuffer.cpp
@@ -61,6 +61,16 @@
 // to use Binder.
 static constexpr char kBufferHubClientPath[] = "system/buffer_hub/client";
 
+using dvr::BufferHubDefs::AnyClientAcquired;
+using dvr::BufferHubDefs::AnyClientGained;
+using dvr::BufferHubDefs::AnyClientPosted;
+using dvr::BufferHubDefs::IsClientAcquired;
+using dvr::BufferHubDefs::IsClientGained;
+using dvr::BufferHubDefs::IsClientPosted;
+using dvr::BufferHubDefs::IsClientReleased;
+using dvr::BufferHubDefs::kHighBitsMask;
+using dvr::BufferHubDefs::kMetadataHeaderSize;
+
 } // namespace
 
 BufferHubClient::BufferHubClient() : Client(ClientChannelFactory::Create(kBufferHubClientPath)) {}
@@ -71,7 +81,7 @@
 BufferHubClient::~BufferHubClient() {}
 
 bool BufferHubClient::IsValid() const {
-  return IsConnected() && GetChannelHandle().valid();
+    return IsConnected() && GetChannelHandle().valid();
 }
 
 LocalChannelHandle BufferHubClient::TakeChannelHandle() {
@@ -151,11 +161,17 @@
     }
 
     size_t metadataSize = static_cast<size_t>(bufferTraits.metadata_size());
-    if (metadataSize < dvr::BufferHubDefs::kMetadataHeaderSize) {
+    if (metadataSize < kMetadataHeaderSize) {
         ALOGE("BufferHubBuffer::ImportGraphicBuffer: metadata too small: %zu", metadataSize);
         return -EINVAL;
     }
 
+    // Populate shortcuts to the atomics in metadata.
+    auto metadata_header = mMetadata.metadata_header();
+    buffer_state_ = &metadata_header->buffer_state;
+    fence_state_ = &metadata_header->fence_state;
+    active_clients_bit_mask_ = &metadata_header->active_clients_bit_mask;
+
     // Import the buffer: We only need to hold on the native_handle_t here so that
     // GraphicBuffer instance can be created in future.
     mBufferHandle = bufferTraits.take_buffer_handle();
@@ -176,7 +192,93 @@
 
     // TODO(b/112012161) Set up shared fences.
     ALOGD("BufferHubBuffer::ImportGraphicBuffer: id=%d, buffer_state=%" PRIx64 ".", id(),
-          mMetadata.metadata_header()->buffer_state.load(std::memory_order_acquire));
+          buffer_state_->load(std::memory_order_acquire));
+    return 0;
+}
+
+int BufferHubBuffer::Gain() {
+    uint64_t current_buffer_state = buffer_state_->load(std::memory_order_acquire);
+    if (IsClientGained(current_buffer_state, mClientStateMask)) {
+        ALOGV("%s: Buffer is already gained by this client %" PRIx64 ".", __FUNCTION__,
+              mClientStateMask);
+        return 0;
+    }
+    do {
+        if (AnyClientGained(current_buffer_state & (~mClientStateMask)) ||
+            AnyClientAcquired(current_buffer_state)) {
+            ALOGE("%s: Buffer is in use, id=%d mClientStateMask=%" PRIx64 " state=%" PRIx64 ".",
+                  __FUNCTION__, mId, mClientStateMask, current_buffer_state);
+            return -EBUSY;
+        }
+        // Change the buffer state to gained state, whose value happens to be the same as
+        // mClientStateMask.
+    } while (!buffer_state_->compare_exchange_weak(current_buffer_state, mClientStateMask,
+                                                   std::memory_order_acq_rel,
+                                                   std::memory_order_acquire));
+    // TODO(b/119837586): Update fence state and return GPU fence.
+    return 0;
+}
+
+int BufferHubBuffer::Post() {
+    uint64_t current_buffer_state = buffer_state_->load(std::memory_order_acquire);
+    uint64_t current_active_clients_bit_mask = 0ULL;
+    uint64_t updated_buffer_state = 0ULL;
+    do {
+        if (!IsClientGained(current_buffer_state, mClientStateMask)) {
+            ALOGE("%s: Cannot post a buffer that is not gained by this client. buffer_id=%d "
+                  "mClientStateMask=%" PRIx64 " state=%" PRIx64 ".",
+                  __FUNCTION__, mId, mClientStateMask, current_buffer_state);
+            return -EBUSY;
+        }
+        // Set the producer client buffer state to released, other clients' buffer state to posted.
+        current_active_clients_bit_mask = active_clients_bit_mask_->load(std::memory_order_acquire);
+        updated_buffer_state =
+                current_active_clients_bit_mask & (~mClientStateMask) & kHighBitsMask;
+    } while (!buffer_state_->compare_exchange_weak(current_buffer_state, updated_buffer_state,
+                                                   std::memory_order_acq_rel,
+                                                   std::memory_order_acquire));
+    // TODO(b/119837586): Update fence state and return GPU fence if needed.
+    return 0;
+}
+
+int BufferHubBuffer::Acquire() {
+    uint64_t current_buffer_state = buffer_state_->load(std::memory_order_acquire);
+    if (IsClientAcquired(current_buffer_state, mClientStateMask)) {
+        ALOGV("%s: Buffer is already acquired by this client %" PRIx64 ".", __FUNCTION__,
+              mClientStateMask);
+        return 0;
+    }
+    uint64_t updated_buffer_state = 0ULL;
+    do {
+        if (!IsClientPosted(current_buffer_state, mClientStateMask)) {
+            ALOGE("%s: Cannot acquire a buffer that is not in posted state. buffer_id=%d "
+                  "mClientStateMask=%" PRIx64 " state=%" PRIx64 ".",
+                  __FUNCTION__, mId, mClientStateMask, current_buffer_state);
+            return -EBUSY;
+        }
+        // Change the buffer state for this consumer from posted to acquired.
+        updated_buffer_state = current_buffer_state ^ mClientStateMask;
+    } while (!buffer_state_->compare_exchange_weak(current_buffer_state, updated_buffer_state,
+                                                   std::memory_order_acq_rel,
+                                                   std::memory_order_acquire));
+    // TODO(b/119837586): Update fence state and return GPU fence.
+    return 0;
+}
+
+int BufferHubBuffer::Release() {
+    uint64_t current_buffer_state = buffer_state_->load(std::memory_order_acquire);
+    if (IsClientReleased(current_buffer_state, mClientStateMask)) {
+        ALOGV("%s: Buffer is already released by this client %" PRIx64 ".", __FUNCTION__,
+              mClientStateMask);
+        return 0;
+    }
+    uint64_t updated_buffer_state = 0ULL;
+    do {
+        updated_buffer_state = current_buffer_state & (~mClientStateMask);
+    } while (!buffer_state_->compare_exchange_weak(current_buffer_state, updated_buffer_state,
+                                                   std::memory_order_acq_rel,
+                                                   std::memory_order_acquire));
+    // TODO(b/119837586): Update fence state and return GPU fence if needed.
     return 0;
 }