Home | History | Annotate | Download | only in libbufferhub
      1 #include <poll.h>
      2 #include <sys/epoll.h>
      3 
      4 #include <pdx/default_transport/client_channel.h>
      5 #include <pdx/default_transport/client_channel_factory.h>
      6 #include <private/dvr/buffer_hub_base.h>
      7 
      8 using android::pdx::LocalChannelHandle;
      9 using android::pdx::LocalHandle;
     10 using android::pdx::Status;
     11 using android::pdx::default_transport::ClientChannel;
     12 using android::pdx::default_transport::ClientChannelFactory;
     13 
     14 namespace android {
     15 namespace dvr {
     16 
     17 BufferHubBase::BufferHubBase(LocalChannelHandle channel_handle)
     18     : Client{pdx::default_transport::ClientChannel::Create(
     19           std::move(channel_handle))},
     20       id_(-1),
     21       cid_(-1) {}
     22 BufferHubBase::BufferHubBase(const std::string& endpoint_path)
     23     : Client{pdx::default_transport::ClientChannelFactory::Create(
     24           endpoint_path)},
     25       id_(-1),
     26       cid_(-1) {}
     27 
     28 BufferHubBase::~BufferHubBase() {
     29   // buffer_state and fence_state are not reset here. They will be used to
     30   // clean up epoll fd if necessary in ProducerChannel::RemoveConsumer method.
     31   if (metadata_header_ != nullptr) {
     32     metadata_buffer_.Unlock();
     33   }
     34 }
     35 
     36 Status<LocalChannelHandle> BufferHubBase::CreateConsumer() {
     37   Status<LocalChannelHandle> status =
     38       InvokeRemoteMethod<BufferHubRPC::NewConsumer>();
     39   ALOGE_IF(!status,
     40            "BufferHub::CreateConsumer: Failed to create consumer channel: %s",
     41            status.GetErrorMessage().c_str());
     42   return status;
     43 }
     44 
     45 int BufferHubBase::ImportBuffer() {
     46   ATRACE_NAME("BufferHubBase::ImportBuffer");
     47 
     48   Status<BufferDescription<LocalHandle>> status =
     49       InvokeRemoteMethod<BufferHubRPC::GetBuffer>();
     50   if (!status) {
     51     ALOGE("BufferHubBase::ImportBuffer: Failed to get buffer: %s",
     52           status.GetErrorMessage().c_str());
     53     return -status.error();
     54   } else if (status.get().id() < 0) {
     55     ALOGE("BufferHubBase::ImportBuffer: Received an invalid id!");
     56     return -EIO;
     57   }
     58 
     59   auto buffer_desc = status.take();
     60 
     61   // Stash the buffer id to replace the value in id_.
     62   const int new_id = buffer_desc.id();
     63 
     64   // Import the buffer.
     65   IonBuffer ion_buffer;
     66   ALOGD_IF(TRACE, "BufferHubBase::ImportBuffer: id=%d.", buffer_desc.id());
     67 
     68   if (const int ret = buffer_desc.ImportBuffer(&ion_buffer))
     69     return ret;
     70 
     71   // Import the metadata.
     72   IonBuffer metadata_buffer;
     73   if (const int ret = buffer_desc.ImportMetadata(&metadata_buffer)) {
     74     ALOGE("Failed to import metadata buffer, error=%d", ret);
     75     return ret;
     76   }
     77   size_t metadata_buf_size = metadata_buffer.width();
     78   if (metadata_buf_size < BufferHubDefs::kMetadataHeaderSize) {
     79     ALOGE("BufferHubBase::ImportBuffer: metadata buffer too small: %zu",
     80           metadata_buf_size);
     81     return -ENOMEM;
     82   }
     83 
     84   // If all imports succee, replace the previous buffer and id.
     85   buffer_ = std::move(ion_buffer);
     86   metadata_buffer_ = std::move(metadata_buffer);
     87   metadata_buf_size_ = metadata_buf_size;
     88   user_metadata_size_ = metadata_buf_size_ - BufferHubDefs::kMetadataHeaderSize;
     89 
     90   void* metadata_ptr = nullptr;
     91   if (const int ret =
     92           metadata_buffer_.Lock(BufferHubDefs::kMetadataUsage, /*x=*/0,
     93                                 /*y=*/0, metadata_buf_size_,
     94                                 /*height=*/1, &metadata_ptr)) {
     95     ALOGE("BufferHubBase::ImportBuffer: Failed to lock metadata.");
     96     return ret;
     97   }
     98 
     99   // Set up shared fences.
    100   shared_acquire_fence_ = buffer_desc.take_acquire_fence();
    101   shared_release_fence_ = buffer_desc.take_release_fence();
    102   if (!shared_acquire_fence_ || !shared_release_fence_) {
    103     ALOGE("BufferHubBase::ImportBuffer: Failed to import shared fences.");
    104     return -EIO;
    105   }
    106 
    107   metadata_header_ =
    108       reinterpret_cast<BufferHubDefs::MetadataHeader*>(metadata_ptr);
    109   if (user_metadata_size_) {
    110     user_metadata_ptr_ =
    111         reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(metadata_ptr) +
    112                                 BufferHubDefs::kMetadataHeaderSize);
    113   } else {
    114     user_metadata_ptr_ = nullptr;
    115   }
    116 
    117   id_ = new_id;
    118   cid_ = buffer_desc.buffer_cid();
    119   client_state_mask_ = buffer_desc.client_state_mask();
    120 
    121   // Note that here the buffer_state, fence_state and active_clients_bit_mask
    122   // are mapped from shared memory as an atomic object. The std::atomic's
    123   // constructor will not be called so that the original value stored in the
    124   // memory region will be preserved.
    125   buffer_state_ = &metadata_header_->bufferState;
    126   ALOGD_IF(TRACE,
    127            "BufferHubBase::ImportBuffer: id=%d, buffer_state=%" PRIx32 ".",
    128            id(), buffer_state_->load(std::memory_order_acquire));
    129   fence_state_ = &metadata_header_->fenceState;
    130   ALOGD_IF(TRACE,
    131            "BufferHubBase::ImportBuffer: id=%d, fence_state=%" PRIx32 ".", id(),
    132            fence_state_->load(std::memory_order_acquire));
    133   active_clients_bit_mask_ = &metadata_header_->activeClientsBitMask;
    134   ALOGD_IF(
    135       TRACE,
    136       "BufferHubBase::ImportBuffer: id=%d, active_clients_bit_mask=%" PRIx32
    137       ".",
    138       id(), active_clients_bit_mask_->load(std::memory_order_acquire));
    139 
    140   return 0;
    141 }
    142 
    143 int BufferHubBase::CheckMetadata(size_t user_metadata_size) const {
    144   if (user_metadata_size && !user_metadata_ptr_) {
    145     ALOGE("BufferHubBase::CheckMetadata: doesn't support custom metadata.");
    146     return -EINVAL;
    147   }
    148   if (user_metadata_size > user_metadata_size_) {
    149     ALOGE("BufferHubBase::CheckMetadata: too big: %zu, maximum: %zu.",
    150           user_metadata_size, user_metadata_size_);
    151     return -E2BIG;
    152   }
    153   return 0;
    154 }
    155 
    156 int BufferHubBase::UpdateSharedFence(const LocalHandle& new_fence,
    157                                      const LocalHandle& shared_fence) {
    158   if (pending_fence_fd_.Get() != new_fence.Get()) {
    159     // First, replace the old fd if there was already one. Skipping if the new
    160     // one is the same as the old.
    161     if (pending_fence_fd_.IsValid()) {
    162       const int ret = epoll_ctl(shared_fence.Get(), EPOLL_CTL_DEL,
    163                                 pending_fence_fd_.Get(), nullptr);
    164       ALOGW_IF(ret,
    165                "BufferHubBase::UpdateSharedFence: failed to remove old fence "
    166                "fd from epoll set, error: %s.",
    167                strerror(errno));
    168     }
    169 
    170     if (new_fence.IsValid()) {
    171       // If ready fence is valid, we put that into the epoll set.
    172       epoll_event event;
    173       event.events = EPOLLIN;
    174       event.data.u32 = client_state_mask();
    175       pending_fence_fd_ = new_fence.Duplicate();
    176       if (epoll_ctl(shared_fence.Get(), EPOLL_CTL_ADD, pending_fence_fd_.Get(),
    177                     &event) < 0) {
    178         const int error = errno;
    179         ALOGE(
    180             "BufferHubBase::UpdateSharedFence: failed to add new fence fd "
    181             "into epoll set, error: %s.",
    182             strerror(error));
    183         return -error;
    184       }
    185       // Set bit in fence state to indicate that there is a fence from this
    186       // producer or consumer.
    187       fence_state_->fetch_or(client_state_mask());
    188     } else {
    189       // Unset bit in fence state to indicate that there is no fence, so that
    190       // when consumer to acquire or producer to acquire, it knows no need to
    191       // check fence for this buffer.
    192       fence_state_->fetch_and(~client_state_mask());
    193     }
    194   }
    195 
    196   return 0;
    197 }
    198 
    199 int BufferHubBase::Lock(int usage, int x, int y, int width, int height,
    200                         void** address) {
    201   return buffer_.Lock(usage, x, y, width, height, address);
    202 }
    203 
    204 int BufferHubBase::Unlock() { return buffer_.Unlock(); }
    205 
    206 int BufferHubBase::GetBlobReadWritePointer(size_t size, void** addr) {
    207   int width = static_cast<int>(size);
    208   int height = 1;
    209   int ret = Lock(usage(), 0, 0, width, height, addr);
    210   if (ret == 0)
    211     Unlock();
    212   return ret;
    213 }
    214 
    215 }  // namespace dvr
    216 }  // namespace android
    217