#include <sys/epoll.h>
#include <sys/eventfd.h>
#include <sys/poll.h>

#include <algorithm>
#include <atomic>
#include <thread>

#include <log/log.h>
#include <private/dvr/bufferhub_rpc.h>
#include <private/dvr/consumer_channel.h>
#include <private/dvr/producer_channel.h>
#include <sync/sync.h>
#include <utils/Trace.h>

using android::pdx::BorrowedHandle;
using android::pdx::ErrorStatus;
using android::pdx::Message;
using android::pdx::RemoteChannelHandle;
using android::pdx::Status;
using android::pdx::rpc::BufferWrapper;
using android::pdx::rpc::DispatchRemoteMethod;
using android::pdx::rpc::WrapBuffer;

namespace android {
namespace dvr {

ProducerChannel::ProducerChannel(BufferHubService* service, int buffer_id,
                                 int channel_id, IonBuffer buffer,
                                 IonBuffer metadata_buffer,
                                 size_t user_metadata_size, int* error)
    : BufferHubChannel(service, buffer_id, channel_id, kProducerType),
      buffer_(std::move(buffer)),
      metadata_buffer_(std::move(metadata_buffer)),
      user_metadata_size_(user_metadata_size),
      metadata_buf_size_(BufferHubDefs::kMetadataHeaderSize +
                         user_metadata_size) {
  if (!buffer_.IsValid()) {
    ALOGE("ProducerChannel::ProducerChannel: Invalid buffer.");
    *error = -EINVAL;
    return;
  }
  if (!metadata_buffer_.IsValid()) {
    ALOGE("ProducerChannel::ProducerChannel: Invalid metadata buffer.");
    *error = -EINVAL;
    return;
  }

  *error = InitializeBuffer();
}

ProducerChannel::ProducerChannel(BufferHubService* service, int channel_id,
                                 uint32_t width, uint32_t height,
                                 uint32_t layer_count, uint32_t format,
                                 uint64_t usage, size_t user_metadata_size,
                                 int* error)
    : BufferHubChannel(service, channel_id, channel_id, kProducerType),
      user_metadata_size_(user_metadata_size),
      metadata_buf_size_(BufferHubDefs::kMetadataHeaderSize +
                         user_metadata_size) {
  if (int ret = buffer_.Alloc(width, height, layer_count, format, usage)) {
    ALOGE("ProducerChannel::ProducerChannel: Failed to allocate buffer: %s",
          strerror(-ret));
    *error = ret;
    return;
  }

  if (int ret = metadata_buffer_.Alloc(metadata_buf_size_, /*height=*/1,
                                       /*layer_count=*/1,
                                       BufferHubDefs::kMetadataFormat,
                                       BufferHubDefs::kMetadataUsage)) {
    ALOGE("ProducerChannel::ProducerChannel: Failed to allocate metadata: %s",
          strerror(-ret));
    *error = ret;
    return;
  }

  *error = InitializeBuffer();
}

int ProducerChannel::InitializeBuffer() {
  void* metadata_ptr = nullptr;
  if (int ret = metadata_buffer_.Lock(BufferHubDefs::kMetadataUsage, /*x=*/0,
                                      /*y=*/0, metadata_buf_size_,
                                      /*height=*/1, &metadata_ptr)) {
    ALOGE("ProducerChannel::ProducerChannel: Failed to lock metadata.");
    return ret;
  }
  metadata_header_ =
      reinterpret_cast<BufferHubDefs::MetadataHeader*>(metadata_ptr);

  // Using placement new here to reuse shared memory instead of new allocation
  // and also initialize the value to zero.
  buffer_state_ = new (&metadata_header_->bufferState) std::atomic<uint32_t>(0);
  fence_state_ = new (&metadata_header_->fenceState) std::atomic<uint32_t>(0);
  active_clients_bit_mask_ =
      new (&metadata_header_->activeClientsBitMask) std::atomic<uint32_t>(0);

  // Producer channel is never created after consumer channel, and one buffer
  // only have one fixed producer for now. Thus, it is correct to assume
  // producer state bit is kFirstClientBitMask for now.
  active_clients_bit_mask_->store(BufferHubDefs::kFirstClientBitMask,
                                  std::memory_order_release);

  acquire_fence_fd_.Reset(epoll_create1(EPOLL_CLOEXEC));
  release_fence_fd_.Reset(epoll_create1(EPOLL_CLOEXEC));
  if (!acquire_fence_fd_ || !release_fence_fd_) {
    ALOGE("ProducerChannel::ProducerChannel: Failed to create shared fences.");
    return -EIO;
  }

  dummy_fence_fd_.Reset(eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK));
  if (!dummy_fence_fd_) {
    ALOGE("ProducerChannel::ProducerChannel: Failed to create dummy fences.");
    return EIO;
  }

  epoll_event event;
  event.events = 0;
  event.data.u32 = 0U;
  if (epoll_ctl(release_fence_fd_.Get(), EPOLL_CTL_ADD, dummy_fence_fd_.Get(),
                &event) < 0) {
    ALOGE(
        "ProducerChannel::ProducerChannel: Failed to modify the shared "
        "release fence to include the dummy fence: %s",
        strerror(errno));
    return -EIO;
  }

  // Success.
  return 0;
}

std::unique_ptr<ProducerChannel> ProducerChannel::Create(
    BufferHubService* service, int buffer_id, int channel_id, IonBuffer buffer,
    IonBuffer metadata_buffer, size_t user_metadata_size) {
  int error = 0;
  std::unique_ptr<ProducerChannel> producer(new ProducerChannel(
      service, buffer_id, channel_id, std::move(buffer),
      std::move(metadata_buffer), user_metadata_size, &error));

  if (error < 0)
    return nullptr;
  else
    return producer;
}

Status<std::shared_ptr<ProducerChannel>> ProducerChannel::Create(
    BufferHubService* service, int channel_id, uint32_t width, uint32_t height,
    uint32_t layer_count, uint32_t format, uint64_t usage,
    size_t user_metadata_size) {
  int error;
  std::shared_ptr<ProducerChannel> producer(
      new ProducerChannel(service, channel_id, width, height, layer_count,
                          format, usage, user_metadata_size, &error));
  if (error < 0)
    return ErrorStatus(-error);
  else
    return {std::move(producer)};
}

ProducerChannel::~ProducerChannel() {
  ALOGD_IF(TRACE,
           "ProducerChannel::~ProducerChannel: channel_id=%d buffer_id=%d "
           "state=%" PRIx32 ".",
           channel_id(), buffer_id(),
           buffer_state_->load(std::memory_order_acquire));
  for (auto consumer : consumer_channels_) {
    consumer->OnProducerClosed();
  }
  Hangup();
}

BufferHubChannel::BufferInfo ProducerChannel::GetBufferInfo() const {
  // Derive the mask of signaled buffers in this producer / consumer set.
  uint32_t signaled_mask = signaled() ? BufferHubDefs::kFirstClientBitMask : 0;
  for (const ConsumerChannel* consumer : consumer_channels_) {
    signaled_mask |= consumer->signaled() ? consumer->client_state_mask() : 0;
  }

  return BufferInfo(buffer_id(), consumer_channels_.size(), buffer_.width(),
                    buffer_.height(), buffer_.layer_count(), buffer_.format(),
                    buffer_.usage(),
                    buffer_state_->load(std::memory_order_acquire),
                    signaled_mask, metadata_header_->queueIndex);
}

void ProducerChannel::HandleImpulse(Message& message) {
  ATRACE_NAME("ProducerChannel::HandleImpulse");
  switch (message.GetOp()) {
    case BufferHubRPC::ProducerGain::Opcode:
      OnProducerGain(message);
      break;
    case BufferHubRPC::ProducerPost::Opcode:
      OnProducerPost(message, {});
      break;
  }
}

bool ProducerChannel::HandleMessage(Message& message) {
  ATRACE_NAME("ProducerChannel::HandleMessage");
  switch (message.GetOp()) {
    case BufferHubRPC::GetBuffer::Opcode:
      DispatchRemoteMethod<BufferHubRPC::GetBuffer>(
          *this, &ProducerChannel::OnGetBuffer, message);
      return true;

    case BufferHubRPC::NewConsumer::Opcode:
      DispatchRemoteMethod<BufferHubRPC::NewConsumer>(
          *this, &ProducerChannel::OnNewConsumer, message);
      return true;

    case BufferHubRPC::ProducerPost::Opcode:
      DispatchRemoteMethod<BufferHubRPC::ProducerPost>(
          *this, &ProducerChannel::OnProducerPost, message);
      return true;

    case BufferHubRPC::ProducerGain::Opcode:
      DispatchRemoteMethod<BufferHubRPC::ProducerGain>(
          *this, &ProducerChannel::OnProducerGain, message);
      return true;

    default:
      return false;
  }
}

BufferDescription<BorrowedHandle> ProducerChannel::GetBuffer(
    uint32_t client_state_mask) {
  return {buffer_,
          metadata_buffer_,
          buffer_id(),
          channel_id(),
          client_state_mask,
          acquire_fence_fd_.Borrow(),
          release_fence_fd_.Borrow()};
}

Status<BufferDescription<BorrowedHandle>> ProducerChannel::OnGetBuffer(
    Message& /*message*/) {
  ATRACE_NAME("ProducerChannel::OnGetBuffer");
  ALOGD_IF(TRACE, "ProducerChannel::OnGetBuffer: buffer=%d, state=%" PRIx32 ".",
           buffer_id(), buffer_state_->load(std::memory_order_acquire));
  return {GetBuffer(BufferHubDefs::kFirstClientBitMask)};
}

Status<uint32_t> ProducerChannel::CreateConsumerStateMask() {
  // Try find the next consumer state bit which has not been claimed by any
  // consumer yet.
  // memory_order_acquire is chosen here because all writes in other threads
  // that release active_clients_bit_mask_ need to be visible here.
  uint32_t current_active_clients_bit_mask =
      active_clients_bit_mask_->load(std::memory_order_acquire);
  uint32_t consumer_state_mask =
      BufferHubDefs::findNextAvailableClientStateMask(
          current_active_clients_bit_mask | orphaned_consumer_bit_mask_);
  if (consumer_state_mask == 0U) {
    ALOGE("%s: reached the maximum mumber of consumers per producer: 63.",
          __FUNCTION__);
    return ErrorStatus(E2BIG);
  }
  uint32_t updated_active_clients_bit_mask =
      current_active_clients_bit_mask | consumer_state_mask;
  // Set the updated value only if the current value stays the same as what was
  // read before. If the comparison succeeds, update the value without
  // reordering anything before or after this read-modify-write in the current
  // thread, and the modification will be visible in other threads that acquire
  // active_clients_bit_mask_. If the comparison fails, load the result of
  // all writes from all threads to updated_active_clients_bit_mask.
  // Keep on finding the next available slient state mask until succeed or out
  // of memory.
  while (!active_clients_bit_mask_->compare_exchange_weak(
      current_active_clients_bit_mask, updated_active_clients_bit_mask,
      std::memory_order_acq_rel, std::memory_order_acquire)) {
    ALOGE("%s: Current active clients bit mask is changed to %" PRIx32
          ", which was expected to be %" PRIx32
          ". Trying to generate a new client state mask to resolve race "
          "condition.",
          __FUNCTION__, updated_active_clients_bit_mask,
          current_active_clients_bit_mask);
    consumer_state_mask = BufferHubDefs::findNextAvailableClientStateMask(
        current_active_clients_bit_mask | orphaned_consumer_bit_mask_);
    if (consumer_state_mask == 0U) {
      ALOGE("%s: reached the maximum mumber of consumers per producer: %d.",
            __FUNCTION__, (BufferHubDefs::kMaxNumberOfClients - 1));
      return ErrorStatus(E2BIG);
    }
    updated_active_clients_bit_mask =
        current_active_clients_bit_mask | consumer_state_mask;
  }

  return {consumer_state_mask};
}

void ProducerChannel::RemoveConsumerClientMask(uint32_t consumer_state_mask) {
  // Clear up the buffer state and fence state in case there is already
  // something there due to possible race condition between producer post and
  // consumer failed to create channel.
  buffer_state_->fetch_and(~consumer_state_mask, std::memory_order_release);
  fence_state_->fetch_and(~consumer_state_mask, std::memory_order_release);

  // Restore the consumer state bit and make it visible in other threads that
  // acquire the active_clients_bit_mask_.
  active_clients_bit_mask_->fetch_and(~consumer_state_mask,
                                      std::memory_order_release);
}

Status<RemoteChannelHandle> ProducerChannel::CreateConsumer(
    Message& message, uint32_t consumer_state_mask) {
  ATRACE_NAME(__FUNCTION__);
  ALOGD("%s: buffer_id=%d", __FUNCTION__, buffer_id());

  int channel_id;
  auto status = message.PushChannel(0, nullptr, &channel_id);
  if (!status) {
    ALOGE("%s: Failed to push consumer channel: %s", __FUNCTION__,
          status.GetErrorMessage().c_str());
    RemoveConsumerClientMask(consumer_state_mask);
    return ErrorStatus(ENOMEM);
  }

  auto consumer = std::make_shared<ConsumerChannel>(
      service(), buffer_id(), channel_id, consumer_state_mask,
      shared_from_this());
  const auto channel_status = service()->SetChannel(channel_id, consumer);
  if (!channel_status) {
    ALOGE("%s: failed to set new consumer channel: %s.", __FUNCTION__,
          channel_status.GetErrorMessage().c_str());
    RemoveConsumerClientMask(consumer_state_mask);
    return ErrorStatus(ENOMEM);
  }

  uint32_t current_buffer_state =
      buffer_state_->load(std::memory_order_acquire);
  // Return the consumer channel handle without signal when adding the new
  // consumer to a buffer that is available to producer (a.k.a a fully-released
  // buffer) or a gained buffer.
  if (current_buffer_state == 0U ||
      BufferHubDefs::isAnyClientGained(current_buffer_state)) {
    return {status.take()};
  }

  // Signal the new consumer when adding it to a posted producer.
  bool update_buffer_state = true;
  if (!BufferHubDefs::isClientPosted(current_buffer_state,
                                     consumer_state_mask)) {
    uint32_t updated_buffer_state =
        current_buffer_state ^
        (consumer_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)) {
      ALOGV(
          "%s: Failed to post to the new consumer. "
          "Current buffer state was changed to %" PRIx32
          " when trying to acquire the buffer and modify the buffer state to "
          "%" PRIx32
          ". About to try again if the buffer is still not gained nor fully "
          "released.",
          __FUNCTION__, current_buffer_state, updated_buffer_state);
      if (current_buffer_state == 0U ||
          BufferHubDefs::isAnyClientGained(current_buffer_state)) {
        ALOGI("%s: buffer is gained or fully released, state=%" PRIx32 ".",
              __FUNCTION__, current_buffer_state);
        update_buffer_state = false;
        break;
      }
      updated_buffer_state =
          current_buffer_state ^
          (consumer_state_mask & BufferHubDefs::kHighBitsMask);
    }
  }
  if (update_buffer_state || BufferHubDefs::isClientPosted(
                                 buffer_state_->load(std::memory_order_acquire),
                                 consumer_state_mask)) {
    consumer->OnProducerPosted();
  }

  return {status.take()};
}

Status<RemoteChannelHandle> ProducerChannel::OnNewConsumer(Message& message) {
  ATRACE_NAME("ProducerChannel::OnNewConsumer");
  ALOGD_IF(TRACE, "ProducerChannel::OnNewConsumer: buffer_id=%d", buffer_id());
  auto status = CreateConsumerStateMask();
  if (!status.ok()) {
    return status.error_status();
  }
  return CreateConsumer(message, /*consumer_state_mask=*/status.get());
}

Status<void> ProducerChannel::OnProducerPost(Message&,
                                             LocalFence acquire_fence) {
  ATRACE_NAME("ProducerChannel::OnProducerPost");
  ALOGD_IF(TRACE, "%s: buffer_id=%d, state=0x%x", __FUNCTION__, buffer_id(),
           buffer_state_->load(std::memory_order_acquire));

  epoll_event event;
  event.events = 0;
  event.data.u32 = 0U;
  int ret = epoll_ctl(release_fence_fd_.Get(), EPOLL_CTL_MOD,
                      dummy_fence_fd_.Get(), &event);
  ALOGE_IF(ret < 0,
           "ProducerChannel::OnProducerPost: Failed to modify the shared "
           "release fence to include the dummy fence: %s",
           strerror(errno));

  eventfd_t dummy_fence_count = 0U;
  if (eventfd_read(dummy_fence_fd_.Get(), &dummy_fence_count) < 0) {
    const int error = errno;
    if (error != EAGAIN) {
      ALOGE(
          "ProducerChannel::ProducerChannel: Failed to read dummy fence, "
          "error: %s",
          strerror(error));
      return ErrorStatus(error);
    }
  }

  ALOGW_IF(dummy_fence_count > 0,
           "ProducerChannel::ProducerChannel: %" PRIu64
           " dummy fence(s) was signaled during last release/gain cycle "
           "buffer_id=%d.",
           dummy_fence_count, buffer_id());

  post_fence_ = std::move(acquire_fence);

  // Signal any interested consumers. If there are none, the buffer will stay
  // in posted state until a consumer comes online. This behavior guarantees
  // that no frame is silently dropped.
  for (auto& consumer : consumer_channels_) {
    consumer->OnProducerPosted();
  }

  return {};
}

Status<LocalFence> ProducerChannel::OnProducerGain(Message& /*message*/) {
  ATRACE_NAME("ProducerChannel::OnGain");
  ALOGD_IF(TRACE, "%s: buffer_id=%d", __FUNCTION__, buffer_id());

  ClearAvailable();
  post_fence_.close();
  for (auto& consumer : consumer_channels_) {
    consumer->OnProducerGained();
  }
  return {std::move(returned_fence_)};
}

// TODO(b/112338294) Keep here for reference. Remove it after new logic is
// written.
/* Status<RemoteChannelHandle> ProducerChannel::OnProducerDetach(
    Message& message) {
  ATRACE_NAME("ProducerChannel::OnProducerDetach");
  ALOGD_IF(TRACE, "ProducerChannel::OnProducerDetach: buffer_id=%d",
           buffer_id());

  uint32_t buffer_state = buffer_state_->load(std::memory_order_acquire);
  if (!BufferHubDefs::isClientGained(
      buffer_state, BufferHubDefs::kFirstClientStateMask)) {
    // Can only detach a ProducerBuffer when it's in gained state.
    ALOGW(
        "ProducerChannel::OnProducerDetach: The buffer (id=%d, state=%"
        PRIx32
        ") is not in gained state.",
        buffer_id(), buffer_state);
    return {};
  }

  int channel_id;
  auto status = message.PushChannel(0, nullptr, &channel_id);
  if (!status) {
    ALOGE(
        "ProducerChannel::OnProducerDetach: Failed to push detached buffer "
        "channel: %s",
        status.GetErrorMessage().c_str());
    return ErrorStatus(ENOMEM);
  }

  // Make sure we unlock the buffer.
  if (int ret = metadata_buffer_.Unlock()) {
    ALOGE("ProducerChannel::OnProducerDetach: Failed to unlock metadata.");
    return ErrorStatus(-ret);
  };

  std::unique_ptr<BufferChannel> channel =
      BufferChannel::Create(service(), buffer_id(), channel_id,
                            std::move(buffer_), user_metadata_size_);
  if (!channel) {
    ALOGE("ProducerChannel::OnProducerDetach: Invalid buffer.");
    return ErrorStatus(EINVAL);
  }

  const auto channel_status =
      service()->SetChannel(channel_id, std::move(channel));
  if (!channel_status) {
    // Technically, this should never fail, as we just pushed the channel.
    // Note that LOG_FATAL will be stripped out in non-debug build.
    LOG_FATAL(
        "ProducerChannel::OnProducerDetach: Failed to set new detached "
        "buffer channel: %s.", channel_status.GetErrorMessage().c_str());
  }

  return status;
} */

Status<LocalFence> ProducerChannel::OnConsumerAcquire(Message& /*message*/) {
  ATRACE_NAME("ProducerChannel::OnConsumerAcquire");
  ALOGD_IF(TRACE, "ProducerChannel::OnConsumerAcquire: buffer_id=%d",
           buffer_id());

  // Return a borrowed fd to avoid unnecessary duplication of the underlying
  // fd. Serialization just needs to read the handle.
  return {std::move(post_fence_)};
}

Status<void> ProducerChannel::OnConsumerRelease(Message&,
                                                LocalFence release_fence) {
  ATRACE_NAME("ProducerChannel::OnConsumerRelease");
  ALOGD_IF(TRACE, "ProducerChannel::OnConsumerRelease: buffer_id=%d",
           buffer_id());

  // Attempt to merge the fences if necessary.
  if (release_fence) {
    if (returned_fence_) {
      LocalFence merged_fence(sync_merge("bufferhub_merged",
                                         returned_fence_.get_fd(),
                                         release_fence.get_fd()));
      const int error = errno;
      if (!merged_fence) {
        ALOGE("ProducerChannel::OnConsumerRelease: Failed to merge fences: %s",
              strerror(error));
        return ErrorStatus(error);
      }
      returned_fence_ = std::move(merged_fence);
    } else {
      returned_fence_ = std::move(release_fence);
    }
  }

  if (IsBufferReleasedByAllActiveClientsExceptForOrphans()) {
    buffer_state_->store(0U);
    SignalAvailable();
    if (orphaned_consumer_bit_mask_) {
      ALOGW(
          "%s: orphaned buffer detected during the this acquire/release cycle: "
          "id=%d orphaned=0x%" PRIx32 " queue_index=%" PRId64 ".",
          __FUNCTION__, buffer_id(), orphaned_consumer_bit_mask_,
          metadata_header_->queueIndex);
      orphaned_consumer_bit_mask_ = 0;
    }
  }

  return {};
}

void ProducerChannel::OnConsumerOrphaned(const uint32_t& consumer_state_mask) {
  // Remember the ignored consumer so that newly added consumer won't be
  // taking the same state mask as this orphaned consumer.
  ALOGE_IF(orphaned_consumer_bit_mask_ & consumer_state_mask,
           "%s: Consumer (consumer_state_mask=%" PRIx32
           ") is already orphaned.",
           __FUNCTION__, consumer_state_mask);
  orphaned_consumer_bit_mask_ |= consumer_state_mask;

  if (IsBufferReleasedByAllActiveClientsExceptForOrphans()) {
    buffer_state_->store(0U);
    SignalAvailable();
  }

  // Atomically clear the fence state bit as an orphaned consumer will never
  // signal a release fence.
  fence_state_->fetch_and(~consumer_state_mask, std::memory_order_release);

  // Atomically set the buffer state of this consumer to released state.
  buffer_state_->fetch_and(~consumer_state_mask, std::memory_order_release);

  ALOGW(
      "%s: detected new orphaned consumer buffer_id=%d "
      "consumer_state_mask=%" PRIx32 " queue_index=%" PRId64
      " buffer_state=%" PRIx32 " fence_state=%" PRIx32 ".",
      __FUNCTION__, buffer_id(), consumer_state_mask,
      metadata_header_->queueIndex,
      buffer_state_->load(std::memory_order_acquire),
      fence_state_->load(std::memory_order_acquire));
}

void ProducerChannel::AddConsumer(ConsumerChannel* channel) {
  consumer_channels_.push_back(channel);
}

void ProducerChannel::RemoveConsumer(ConsumerChannel* channel) {
  consumer_channels_.erase(
      std::find(consumer_channels_.begin(), consumer_channels_.end(), channel));
  // Restore the consumer state bit and make it visible in other threads that
  // acquire the active_clients_bit_mask_.
  uint32_t consumer_state_mask = channel->client_state_mask();
  uint32_t current_active_clients_bit_mask =
      active_clients_bit_mask_->load(std::memory_order_acquire);
  uint32_t updated_active_clients_bit_mask =
      current_active_clients_bit_mask & (~consumer_state_mask);
  while (!active_clients_bit_mask_->compare_exchange_weak(
      current_active_clients_bit_mask, updated_active_clients_bit_mask,
      std::memory_order_acq_rel, std::memory_order_acquire)) {
    ALOGI(
        "%s: Failed to remove consumer state mask. Current active clients bit "
        "mask is changed to %" PRIx32
        " when trying to acquire and modify it to %" PRIx32
        ". About to try again.",
        __FUNCTION__, current_active_clients_bit_mask,
        updated_active_clients_bit_mask);
    updated_active_clients_bit_mask =
        current_active_clients_bit_mask & (~consumer_state_mask);
  }

  const uint32_t current_buffer_state =
      buffer_state_->load(std::memory_order_acquire);
  if (BufferHubDefs::isClientPosted(current_buffer_state,
                                    consumer_state_mask) ||
      BufferHubDefs::isClientAcquired(current_buffer_state,
                                      consumer_state_mask)) {
    // The consumer client is being destoryed without releasing. This could
    // happen in corner cases when the consumer crashes. Here we mark it
    // orphaned before remove it from producer.
    OnConsumerOrphaned(consumer_state_mask);
    return;
  }

  if (BufferHubDefs::isClientReleased(current_buffer_state,
                                      consumer_state_mask) ||
      BufferHubDefs::isAnyClientGained(current_buffer_state)) {
    // The consumer is being close while it is suppose to signal a release
    // fence. Signal the dummy fence here.
    if (fence_state_->load(std::memory_order_acquire) & consumer_state_mask) {
      epoll_event event;
      event.events = EPOLLIN;
      event.data.u32 = consumer_state_mask;
      if (epoll_ctl(release_fence_fd_.Get(), EPOLL_CTL_MOD,
                    dummy_fence_fd_.Get(), &event) < 0) {
        ALOGE(
            "%s: Failed to modify the shared release fence to include the "
            "dummy fence: %s",
            __FUNCTION__, strerror(errno));
        return;
      }
      ALOGW("%s: signal dummy release fence buffer_id=%d", __FUNCTION__,
            buffer_id());
      eventfd_write(dummy_fence_fd_.Get(), 1);
    }
  }
}

// Returns true if the given parameters match the underlying buffer
// parameters.
bool ProducerChannel::CheckParameters(uint32_t width, uint32_t height,
                                      uint32_t layer_count, uint32_t format,
                                      uint64_t usage,
                                      size_t user_metadata_size) const {
  return user_metadata_size == user_metadata_size_ &&
         buffer_.width() == width && buffer_.height() == height &&
         buffer_.layer_count() == layer_count && buffer_.format() == format &&
         buffer_.usage() == usage;
}

bool ProducerChannel::IsBufferReleasedByAllActiveClientsExceptForOrphans()
    const {
  return (buffer_state_->load(std::memory_order_acquire) &
          ~orphaned_consumer_bit_mask_ &
          active_clients_bit_mask_->load(std::memory_order_acquire)) == 0U;
}

}  // namespace dvr
}  // namespace android
