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