| #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 |