Home | History | Annotate | Download | only in libbufferhub
      1 #include <private/dvr/consumer_buffer.h>
      2 
      3 using android::pdx::LocalChannelHandle;
      4 using android::pdx::LocalHandle;
      5 using android::pdx::Status;
      6 
      7 namespace android {
      8 namespace dvr {
      9 
     10 ConsumerBuffer::ConsumerBuffer(LocalChannelHandle channel)
     11     : BASE(std::move(channel)) {
     12   const int ret = ImportBuffer();
     13   if (ret < 0) {
     14     ALOGE("ConsumerBuffer::ConsumerBuffer: Failed to import buffer: %s",
     15           strerror(-ret));
     16     Close(ret);
     17   }
     18 }
     19 
     20 std::unique_ptr<ConsumerBuffer> ConsumerBuffer::Import(
     21     LocalChannelHandle channel) {
     22   ATRACE_NAME("ConsumerBuffer::Import");
     23   ALOGD_IF(TRACE, "ConsumerBuffer::Import: channel=%d", channel.value());
     24   return ConsumerBuffer::Create(std::move(channel));
     25 }
     26 
     27 std::unique_ptr<ConsumerBuffer> ConsumerBuffer::Import(
     28     Status<LocalChannelHandle> status) {
     29   return Import(status ? status.take()
     30                        : LocalChannelHandle{nullptr, -status.error()});
     31 }
     32 
     33 int ConsumerBuffer::LocalAcquire(DvrNativeBufferMetadata* out_meta,
     34                                  LocalHandle* out_fence) {
     35   if (!out_meta)
     36     return -EINVAL;
     37 
     38   // The buffer can be acquired iff the buffer state for this client is posted.
     39   uint32_t current_buffer_state =
     40       buffer_state_->load(std::memory_order_acquire);
     41   if (!BufferHubDefs::isClientPosted(current_buffer_state,
     42                                      client_state_mask())) {
     43     ALOGE(
     44         "%s: Failed to acquire the buffer. The buffer is not posted, id=%d "
     45         "state=%" PRIx32 " client_state_mask=%" PRIx32 ".",
     46         __FUNCTION__, id(), current_buffer_state, client_state_mask());
     47     return -EBUSY;
     48   }
     49 
     50   // Change the buffer state for this consumer from posted to acquired.
     51   uint32_t updated_buffer_state = current_buffer_state ^ client_state_mask();
     52   while (!buffer_state_->compare_exchange_weak(
     53       current_buffer_state, updated_buffer_state, std::memory_order_acq_rel,
     54       std::memory_order_acquire)) {
     55     ALOGD(
     56         "%s Failed to acquire the buffer. Current buffer state was changed to "
     57         "%" PRIx32
     58         " when trying to acquire the buffer and modify the buffer state to "
     59         "%" PRIx32 ". About to try again if the buffer is still posted.",
     60         __FUNCTION__, current_buffer_state, updated_buffer_state);
     61     if (!BufferHubDefs::isClientPosted(current_buffer_state,
     62                                        client_state_mask())) {
     63       ALOGE(
     64           "%s: Failed to acquire the buffer. The buffer is no longer posted, "
     65           "id=%d state=%" PRIx32 " client_state_mask=%" PRIx32 ".",
     66           __FUNCTION__, id(), current_buffer_state, client_state_mask());
     67       return -EBUSY;
     68     }
     69     // The failure of compare_exchange_weak updates current_buffer_state.
     70     updated_buffer_state = current_buffer_state ^ client_state_mask();
     71   }
     72 
     73   // Copy the canonical metadata.
     74   void* metadata_ptr = reinterpret_cast<void*>(&metadata_header_->metadata);
     75   memcpy(out_meta, metadata_ptr, sizeof(DvrNativeBufferMetadata));
     76   // Fill in the user_metadata_ptr in address space of the local process.
     77   if (out_meta->user_metadata_size) {
     78     out_meta->user_metadata_ptr =
     79         reinterpret_cast<uint64_t>(user_metadata_ptr_);
     80   } else {
     81     out_meta->user_metadata_ptr = 0;
     82   }
     83 
     84   uint32_t fence_state = fence_state_->load(std::memory_order_acquire);
     85   // If there is an acquire fence from producer, we need to return it.
     86   // The producer state bit mask is kFirstClientBitMask for now.
     87   if (fence_state & BufferHubDefs::kFirstClientBitMask) {
     88     *out_fence = shared_acquire_fence_.Duplicate();
     89   }
     90 
     91   return 0;
     92 }
     93 
     94 int ConsumerBuffer::Acquire(LocalHandle* ready_fence) {
     95   return Acquire(ready_fence, nullptr, 0);
     96 }
     97 
     98 int ConsumerBuffer::Acquire(LocalHandle* ready_fence, void* meta,
     99                             size_t user_metadata_size) {
    100   ATRACE_NAME("ConsumerBuffer::Acquire");
    101 
    102   if (const int error = CheckMetadata(user_metadata_size))
    103     return error;
    104 
    105   DvrNativeBufferMetadata canonical_meta;
    106   if (const int error = LocalAcquire(&canonical_meta, ready_fence))
    107     return error;
    108 
    109   if (meta && user_metadata_size) {
    110     void* metadata_src =
    111         reinterpret_cast<void*>(canonical_meta.user_metadata_ptr);
    112     if (metadata_src) {
    113       memcpy(meta, metadata_src, user_metadata_size);
    114     } else {
    115       ALOGW("ConsumerBuffer::Acquire: no user-defined metadata.");
    116     }
    117   }
    118 
    119   auto status = InvokeRemoteMethod<BufferHubRPC::ConsumerAcquire>();
    120   if (!status)
    121     return -status.error();
    122   return 0;
    123 }
    124 
    125 int ConsumerBuffer::AcquireAsync(DvrNativeBufferMetadata* out_meta,
    126                                  LocalHandle* out_fence) {
    127   ATRACE_NAME("ConsumerBuffer::AcquireAsync");
    128 
    129   if (const int error = LocalAcquire(out_meta, out_fence))
    130     return error;
    131 
    132   auto status = SendImpulse(BufferHubRPC::ConsumerAcquire::Opcode);
    133   if (!status)
    134     return -status.error();
    135   return 0;
    136 }
    137 
    138 int ConsumerBuffer::LocalRelease(const DvrNativeBufferMetadata* meta,
    139                                  const LocalHandle& release_fence) {
    140   if (const int error = CheckMetadata(meta->user_metadata_size))
    141     return error;
    142 
    143   // Set the buffer state of this client to released if it is not already in
    144   // released state.
    145   uint32_t current_buffer_state =
    146       buffer_state_->load(std::memory_order_acquire);
    147   if (BufferHubDefs::isClientReleased(current_buffer_state,
    148                                       client_state_mask())) {
    149     return 0;
    150   }
    151   uint32_t updated_buffer_state = current_buffer_state & (~client_state_mask());
    152   while (!buffer_state_->compare_exchange_weak(
    153       current_buffer_state, updated_buffer_state, std::memory_order_acq_rel,
    154       std::memory_order_acquire)) {
    155     ALOGD(
    156         "%s: Failed to release the buffer. Current buffer state was changed to "
    157         "%" PRIx32
    158         " when trying to release the buffer and modify the buffer state to "
    159         "%" PRIx32 ". About to try again.",
    160         __FUNCTION__, current_buffer_state, updated_buffer_state);
    161     // The failure of compare_exchange_weak updates current_buffer_state.
    162     updated_buffer_state = current_buffer_state & (~client_state_mask());
    163   }
    164 
    165   // On release, only the user requested metadata is copied back into the shared
    166   // memory for metadata. Since there are multiple consumers, it doesn't make
    167   // sense to send the canonical metadata back to the producer. However, one of
    168   // the consumer can still choose to write up to user_metadata_size bytes of
    169   // data into user_metadata_ptr.
    170   if (meta->user_metadata_ptr && meta->user_metadata_size) {
    171     void* metadata_src = reinterpret_cast<void*>(meta->user_metadata_ptr);
    172     memcpy(user_metadata_ptr_, metadata_src, meta->user_metadata_size);
    173   }
    174 
    175   // Send out the release fence through the shared epoll fd. Note that during
    176   // releasing the producer is not expected to be polling on the fence.
    177   if (const int error = UpdateSharedFence(release_fence, shared_release_fence_))
    178     return error;
    179 
    180   return 0;
    181 }
    182 
    183 int ConsumerBuffer::Release(const LocalHandle& release_fence) {
    184   ATRACE_NAME("ConsumerBuffer::Release");
    185 
    186   DvrNativeBufferMetadata meta;
    187   if (const int error = LocalRelease(&meta, release_fence))
    188     return error;
    189 
    190   return ReturnStatusOrError(InvokeRemoteMethod<BufferHubRPC::ConsumerRelease>(
    191       BorrowedFence(release_fence.Borrow())));
    192 }
    193 
    194 int ConsumerBuffer::ReleaseAsync() {
    195   DvrNativeBufferMetadata meta;
    196   return ReleaseAsync(&meta, LocalHandle());
    197 }
    198 
    199 int ConsumerBuffer::ReleaseAsync(const DvrNativeBufferMetadata* meta,
    200                                  const LocalHandle& release_fence) {
    201   ATRACE_NAME("ConsumerBuffer::ReleaseAsync");
    202 
    203   if (const int error = LocalRelease(meta, release_fence))
    204     return error;
    205 
    206   return ReturnStatusOrError(
    207       SendImpulse(BufferHubRPC::ConsumerRelease::Opcode));
    208 }
    209 
    210 int ConsumerBuffer::Discard() { return Release(LocalHandle()); }
    211 
    212 }  // namespace dvr
    213 }  // namespace android
    214