blob: 581390f374ea558d49c7d6c0b11ed7891a1d3ad5 [file] [log] [blame]
Corey Tabaka52ea25c2017-09-13 18:02:48 -07001#include <sys/epoll.h>
2#include <sys/eventfd.h>
Alex Vakulenkoe4eec202017-01-27 14:41:04 -08003#include <sys/poll.h>
Alex Vakulenkoe4eec202017-01-27 14:41:04 -08004
5#include <algorithm>
6#include <atomic>
7#include <thread>
8
Fan Xu74df4902018-09-20 16:40:51 -07009#include <log/log.h>
Fan Xu74df4902018-09-20 16:40:51 -070010#include <private/dvr/buffer_channel.h>
Tianyu0c6b7ff2018-10-03 11:30:04 -070011#include <private/dvr/bufferhub_rpc.h>
Fan Xu74df4902018-09-20 16:40:51 -070012#include <private/dvr/consumer_channel.h>
13#include <private/dvr/producer_channel.h>
14#include <sync/sync.h>
15#include <utils/Trace.h>
Alex Vakulenkoe4eec202017-01-27 14:41:04 -080016
17using android::pdx::BorrowedHandle;
Corey Tabakacd52dd92017-04-07 18:03:57 -070018using android::pdx::ErrorStatus;
Alex Vakulenkoe4eec202017-01-27 14:41:04 -080019using android::pdx::Message;
20using android::pdx::RemoteChannelHandle;
Corey Tabakacd52dd92017-04-07 18:03:57 -070021using android::pdx::Status;
Alex Vakulenkoe4eec202017-01-27 14:41:04 -080022using android::pdx::rpc::BufferWrapper;
23using android::pdx::rpc::DispatchRemoteMethod;
24using android::pdx::rpc::WrapBuffer;
25
26namespace android {
27namespace dvr {
28
Jiwen 'Steve' Cai0728fa92018-04-24 19:03:14 -070029ProducerChannel::ProducerChannel(BufferHubService* service, int buffer_id,
30 int channel_id, IonBuffer buffer,
31 IonBuffer metadata_buffer,
32 size_t user_metadata_size, int* error)
33 : BufferHubChannel(service, buffer_id, channel_id, kProducerType),
34 buffer_(std::move(buffer)),
35 metadata_buffer_(std::move(metadata_buffer)),
36 user_metadata_size_(user_metadata_size),
37 metadata_buf_size_(BufferHubDefs::kMetadataHeaderSize +
38 user_metadata_size) {
39 if (!buffer_.IsValid()) {
40 ALOGE("ProducerChannel::ProducerChannel: Invalid buffer.");
41 *error = -EINVAL;
42 return;
43 }
44 if (!metadata_buffer_.IsValid()) {
45 ALOGE("ProducerChannel::ProducerChannel: Invalid metadata buffer.");
46 *error = -EINVAL;
47 return;
48 }
49
50 *error = InitializeBuffer();
51}
52
Alex Vakulenkoe4eec202017-01-27 14:41:04 -080053ProducerChannel::ProducerChannel(BufferHubService* service, int channel_id,
Corey Tabakacd52dd92017-04-07 18:03:57 -070054 uint32_t width, uint32_t height,
Hendrik Wagenaar108e84f2017-05-07 22:19:17 -070055 uint32_t layer_count, uint32_t format,
Corey Tabaka52ea25c2017-09-13 18:02:48 -070056 uint64_t usage, size_t user_metadata_size,
Hendrik Wagenaar108e84f2017-05-07 22:19:17 -070057 int* error)
Alex Vakulenkoe4eec202017-01-27 14:41:04 -080058 : BufferHubChannel(service, channel_id, channel_id, kProducerType),
59 pending_consumers_(0),
Alex Vakulenkoe4eec202017-01-27 14:41:04 -080060 producer_owns_(true),
Corey Tabaka52ea25c2017-09-13 18:02:48 -070061 user_metadata_size_(user_metadata_size),
62 metadata_buf_size_(BufferHubDefs::kMetadataHeaderSize +
63 user_metadata_size) {
64 if (int ret = buffer_.Alloc(width, height, layer_count, format, usage)) {
Hendrik Wagenaar4d3590f2017-05-06 22:36:04 -070065 ALOGE("ProducerChannel::ProducerChannel: Failed to allocate buffer: %s",
66 strerror(-ret));
67 *error = ret;
68 return;
Alex Vakulenkoe4eec202017-01-27 14:41:04 -080069 }
70
Corey Tabaka52ea25c2017-09-13 18:02:48 -070071 if (int ret = metadata_buffer_.Alloc(metadata_buf_size_, /*height=*/1,
72 /*layer_count=*/1,
73 BufferHubDefs::kMetadataFormat,
74 BufferHubDefs::kMetadataUsage)) {
75 ALOGE("ProducerChannel::ProducerChannel: Failed to allocate metadata: %s",
76 strerror(-ret));
77 *error = ret;
78 return;
79 }
80
Jiwen 'Steve' Cai0728fa92018-04-24 19:03:14 -070081 *error = InitializeBuffer();
82}
83
84int ProducerChannel::InitializeBuffer() {
Corey Tabaka52ea25c2017-09-13 18:02:48 -070085 void* metadata_ptr = nullptr;
86 if (int ret = metadata_buffer_.Lock(BufferHubDefs::kMetadataUsage, /*x=*/0,
87 /*y=*/0, metadata_buf_size_,
88 /*height=*/1, &metadata_ptr)) {
89 ALOGE("ProducerChannel::ProducerChannel: Failed to lock metadata.");
Jiwen 'Steve' Cai0728fa92018-04-24 19:03:14 -070090 return ret;
Corey Tabaka52ea25c2017-09-13 18:02:48 -070091 }
92 metadata_header_ =
93 reinterpret_cast<BufferHubDefs::MetadataHeader*>(metadata_ptr);
94
95 // Using placement new here to reuse shared memory instead of new allocation
96 // and also initialize the value to zero.
97 buffer_state_ =
98 new (&metadata_header_->buffer_state) std::atomic<uint64_t>(0);
Tianyu0c6b7ff2018-10-03 11:30:04 -070099 fence_state_ = new (&metadata_header_->fence_state) std::atomic<uint64_t>(0);
Tianyu67053492018-10-04 14:00:22 -0700100 active_clients_bit_mask_ =
101 new (&metadata_header_->active_clients_bit_mask) std::atomic<uint64_t>(0);
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700102
103 acquire_fence_fd_.Reset(epoll_create1(EPOLL_CLOEXEC));
104 release_fence_fd_.Reset(epoll_create1(EPOLL_CLOEXEC));
105 if (!acquire_fence_fd_ || !release_fence_fd_) {
106 ALOGE("ProducerChannel::ProducerChannel: Failed to create shared fences.");
Jiwen 'Steve' Cai0728fa92018-04-24 19:03:14 -0700107 return -EIO;
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700108 }
109
110 dummy_fence_fd_.Reset(eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK));
111 if (!dummy_fence_fd_) {
112 ALOGE("ProducerChannel::ProducerChannel: Failed to create dummy fences.");
Jiwen 'Steve' Cai0728fa92018-04-24 19:03:14 -0700113 return EIO;
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700114 }
115
116 epoll_event event;
117 event.events = 0;
118 event.data.u64 = 0ULL;
119 if (epoll_ctl(release_fence_fd_.Get(), EPOLL_CTL_ADD, dummy_fence_fd_.Get(),
120 &event) < 0) {
121 ALOGE(
122 "ProducerChannel::ProducerChannel: Failed to modify the shared "
123 "release fence to include the dummy fence: %s",
124 strerror(errno));
Jiwen 'Steve' Cai0728fa92018-04-24 19:03:14 -0700125 return -EIO;
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700126 }
127
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800128 // Success.
Jiwen 'Steve' Cai0728fa92018-04-24 19:03:14 -0700129 return 0;
130}
131
132std::unique_ptr<ProducerChannel> ProducerChannel::Create(
133 BufferHubService* service, int buffer_id, int channel_id, IonBuffer buffer,
134 IonBuffer metadata_buffer, size_t user_metadata_size) {
135 int error = 0;
136 std::unique_ptr<ProducerChannel> producer(new ProducerChannel(
137 service, buffer_id, channel_id, std::move(buffer),
138 std::move(metadata_buffer), user_metadata_size, &error));
139
140 if (error < 0)
141 return nullptr;
142 else
143 return producer;
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800144}
145
Corey Tabakacd52dd92017-04-07 18:03:57 -0700146Status<std::shared_ptr<ProducerChannel>> ProducerChannel::Create(
147 BufferHubService* service, int channel_id, uint32_t width, uint32_t height,
Hendrik Wagenaar108e84f2017-05-07 22:19:17 -0700148 uint32_t layer_count, uint32_t format, uint64_t usage,
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700149 size_t user_metadata_size) {
Corey Tabakacd52dd92017-04-07 18:03:57 -0700150 int error;
Jiwen 'Steve' Cai0057fdd2017-05-02 11:21:18 -0700151 std::shared_ptr<ProducerChannel> producer(
Hendrik Wagenaar108e84f2017-05-07 22:19:17 -0700152 new ProducerChannel(service, channel_id, width, height, layer_count,
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700153 format, usage, user_metadata_size, &error));
Corey Tabakacd52dd92017-04-07 18:03:57 -0700154 if (error < 0)
155 return ErrorStatus(-error);
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800156 else
Corey Tabakacd52dd92017-04-07 18:03:57 -0700157 return {std::move(producer)};
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800158}
159
160ProducerChannel::~ProducerChannel() {
Corey Tabaka3079cb72017-01-19 15:07:26 -0800161 ALOGD_IF(TRACE,
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700162 "ProducerChannel::~ProducerChannel: channel_id=%d buffer_id=%d "
163 "state=%" PRIx64 ".",
164 channel_id(), buffer_id(), buffer_state_->load());
Jiwen 'Steve' Cai23c1a732018-03-12 12:16:47 -0700165 for (auto consumer : consumer_channels_) {
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800166 consumer->OnProducerClosed();
Jiwen 'Steve' Cai23c1a732018-03-12 12:16:47 -0700167 }
168 Hangup();
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800169}
170
171BufferHubChannel::BufferInfo ProducerChannel::GetBufferInfo() const {
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700172 // Derive the mask of signaled buffers in this producer / consumer set.
173 uint64_t signaled_mask = signaled() ? BufferHubDefs::kProducerStateBit : 0;
174 for (const ConsumerChannel* consumer : consumer_channels_) {
175 signaled_mask |= consumer->signaled() ? consumer->consumer_state_bit() : 0;
176 }
177
Hendrik Wagenaar4d3590f2017-05-06 22:36:04 -0700178 return BufferInfo(buffer_id(), consumer_channels_.size(), buffer_.width(),
Hendrik Wagenaar108e84f2017-05-07 22:19:17 -0700179 buffer_.height(), buffer_.layer_count(), buffer_.format(),
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700180 buffer_.usage(), pending_consumers_, buffer_state_->load(),
Jiwen 'Steve' Cai2f260332018-02-15 18:39:47 -0800181 signaled_mask, metadata_header_->queue_index);
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800182}
183
184void ProducerChannel::HandleImpulse(Message& message) {
185 ATRACE_NAME("ProducerChannel::HandleImpulse");
186 switch (message.GetOp()) {
187 case BufferHubRPC::ProducerGain::Opcode:
188 OnProducerGain(message);
189 break;
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700190 case BufferHubRPC::ProducerPost::Opcode:
191 OnProducerPost(message, {});
192 break;
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800193 }
194}
195
196bool ProducerChannel::HandleMessage(Message& message) {
197 ATRACE_NAME("ProducerChannel::HandleMessage");
198 switch (message.GetOp()) {
199 case BufferHubRPC::GetBuffer::Opcode:
200 DispatchRemoteMethod<BufferHubRPC::GetBuffer>(
201 *this, &ProducerChannel::OnGetBuffer, message);
202 return true;
203
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800204 case BufferHubRPC::NewConsumer::Opcode:
205 DispatchRemoteMethod<BufferHubRPC::NewConsumer>(
206 *this, &ProducerChannel::OnNewConsumer, message);
207 return true;
208
209 case BufferHubRPC::ProducerPost::Opcode:
210 DispatchRemoteMethod<BufferHubRPC::ProducerPost>(
211 *this, &ProducerChannel::OnProducerPost, message);
212 return true;
213
214 case BufferHubRPC::ProducerGain::Opcode:
215 DispatchRemoteMethod<BufferHubRPC::ProducerGain>(
216 *this, &ProducerChannel::OnProducerGain, message);
217 return true;
218
Jiwen 'Steve' Cai23c1a732018-03-12 12:16:47 -0700219 case BufferHubRPC::ProducerBufferDetach::Opcode:
220 DispatchRemoteMethod<BufferHubRPC::ProducerBufferDetach>(
221 *this, &ProducerChannel::OnProducerDetach, message);
222 return true;
223
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800224 default:
225 return false;
226 }
227}
228
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700229BufferDescription<BorrowedHandle> ProducerChannel::GetBuffer(
230 uint64_t buffer_state_bit) {
Jiwen 'Steve' Cai57ae3ee2018-05-03 17:51:52 -0700231 return {buffer_,
232 metadata_buffer_,
233 buffer_id(),
234 channel_id(),
235 buffer_state_bit,
236 acquire_fence_fd_.Borrow(),
237 release_fence_fd_.Borrow()};
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700238}
239
240Status<BufferDescription<BorrowedHandle>> ProducerChannel::OnGetBuffer(
Corey Tabakad53870c2017-07-06 18:04:27 -0700241 Message& /*message*/) {
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800242 ATRACE_NAME("ProducerChannel::OnGetBuffer");
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700243 ALOGD_IF(TRACE, "ProducerChannel::OnGetBuffer: buffer=%d, state=%" PRIx64 ".",
244 buffer_id(), buffer_state_->load());
245 return {GetBuffer(BufferHubDefs::kProducerStateBit)};
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800246}
247
Corey Tabakacd52dd92017-04-07 18:03:57 -0700248Status<RemoteChannelHandle> ProducerChannel::CreateConsumer(Message& message) {
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800249 ATRACE_NAME("ProducerChannel::CreateConsumer");
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700250 ALOGD_IF(TRACE,
251 "ProducerChannel::CreateConsumer: buffer_id=%d, producer_owns=%d",
252 buffer_id(), producer_owns_);
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800253
254 int channel_id;
255 auto status = message.PushChannel(0, nullptr, &channel_id);
256 if (!status) {
257 ALOGE(
Corey Tabakacd52dd92017-04-07 18:03:57 -0700258 "ProducerChannel::CreateConsumer: Failed to push consumer channel: %s",
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800259 status.GetErrorMessage().c_str());
Corey Tabakacd52dd92017-04-07 18:03:57 -0700260 return ErrorStatus(ENOMEM);
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800261 }
262
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700263 // Try find the next consumer state bit which has not been claimed by any
264 // consumer yet.
Tianyu67053492018-10-04 14:00:22 -0700265 // memory_order_acquire is chosen here because all writes in other threads
266 // that release active_clients_bit_mask_ need to be visible here.
267 uint64_t current_active_clients_bit_mask =
268 active_clients_bit_mask_->load(std::memory_order_acquire);
Jiwen 'Steve' Cai2e06c1c2018-07-30 21:35:32 -0700269 uint64_t consumer_state_bit = BufferHubDefs::FindNextClearedBit(
Tianyu67053492018-10-04 14:00:22 -0700270 current_active_clients_bit_mask | orphaned_consumer_bit_mask_ |
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700271 BufferHubDefs::kProducerStateBit);
272 if (consumer_state_bit == 0ULL) {
273 ALOGE(
274 "ProducerChannel::CreateConsumer: reached the maximum mumber of "
275 "consumers per producer: 63.");
276 return ErrorStatus(E2BIG);
277 }
278
Tianyu67053492018-10-04 14:00:22 -0700279 uint64_t updated_active_clients_bit_mask =
280 current_active_clients_bit_mask | consumer_state_bit;
281 // Set the updated value only if the current value stays the same as what was
282 // read before. If the comparison succeeds, update the value without
283 // reordering anything before or after this read-modify-write in the current
284 // thread, and the modification will be visible in other threads that acquire
285 // active_clients_bit_mask_. If the comparison fails, load the result of
286 // all writes from all threads to updated_active_clients_bit_mask.
287 if (!active_clients_bit_mask_->compare_exchange_weak(
288 current_active_clients_bit_mask, updated_active_clients_bit_mask,
289 std::memory_order_acq_rel, std::memory_order_acquire)) {
290 ALOGE("Current active clients bit mask is changed to %" PRIu64
291 ", which was expected to be %" PRIu64 ".",
292 updated_active_clients_bit_mask, current_active_clients_bit_mask);
293 return ErrorStatus(EBUSY);
294 }
295
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700296 auto consumer =
297 std::make_shared<ConsumerChannel>(service(), buffer_id(), channel_id,
298 consumer_state_bit, shared_from_this());
Alex Vakulenkof0a7bd02017-03-31 18:06:19 -0700299 const auto channel_status = service()->SetChannel(channel_id, consumer);
300 if (!channel_status) {
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800301 ALOGE(
302 "ProducerChannel::CreateConsumer: failed to set new consumer channel: "
303 "%s",
Alex Vakulenkof0a7bd02017-03-31 18:06:19 -0700304 channel_status.GetErrorMessage().c_str());
Tianyu67053492018-10-04 14:00:22 -0700305 // Restore the consumer state bit and make it visible in other threads that
306 // acquire the active_clients_bit_mask_.
307 active_clients_bit_mask_->fetch_and(~consumer_state_bit,
308 std::memory_order_release);
Corey Tabakacd52dd92017-04-07 18:03:57 -0700309 return ErrorStatus(ENOMEM);
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800310 }
311
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700312 if (!producer_owns_ &&
313 !BufferHubDefs::IsBufferReleased(buffer_state_->load())) {
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800314 // Signal the new consumer when adding it to a posted producer.
315 if (consumer->OnProducerPosted())
316 pending_consumers_++;
317 }
318
Corey Tabakacd52dd92017-04-07 18:03:57 -0700319 return {status.take()};
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800320}
321
Corey Tabakacd52dd92017-04-07 18:03:57 -0700322Status<RemoteChannelHandle> ProducerChannel::OnNewConsumer(Message& message) {
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800323 ATRACE_NAME("ProducerChannel::OnNewConsumer");
324 ALOGD_IF(TRACE, "ProducerChannel::OnNewConsumer: buffer_id=%d", buffer_id());
Corey Tabakacd52dd92017-04-07 18:03:57 -0700325 return CreateConsumer(message);
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800326}
327
Tianyu0c6b7ff2018-10-03 11:30:04 -0700328Status<void> ProducerChannel::OnProducerPost(Message&,
329 LocalFence acquire_fence) {
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800330 ATRACE_NAME("ProducerChannel::OnProducerPost");
331 ALOGD_IF(TRACE, "ProducerChannel::OnProducerPost: buffer_id=%d", buffer_id());
332 if (!producer_owns_) {
333 ALOGE("ProducerChannel::OnProducerPost: Not in gained state!");
Corey Tabakacd52dd92017-04-07 18:03:57 -0700334 return ErrorStatus(EBUSY);
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800335 }
336
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700337 epoll_event event;
338 event.events = 0;
339 event.data.u64 = 0ULL;
340 int ret = epoll_ctl(release_fence_fd_.Get(), EPOLL_CTL_MOD,
341 dummy_fence_fd_.Get(), &event);
342 ALOGE_IF(ret < 0,
Tianyu0c6b7ff2018-10-03 11:30:04 -0700343 "ProducerChannel::OnProducerPost: Failed to modify the shared "
344 "release fence to include the dummy fence: %s",
345 strerror(errno));
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700346
347 eventfd_t dummy_fence_count = 0ULL;
348 if (eventfd_read(dummy_fence_fd_.Get(), &dummy_fence_count) < 0) {
349 const int error = errno;
350 if (error != EAGAIN) {
351 ALOGE(
352 "ProducerChannel::ProducerChannel: Failed to read dummy fence, "
353 "error: %s",
354 strerror(error));
355 return ErrorStatus(error);
356 }
Corey Tabaka8a4e6a92017-04-20 13:42:02 -0700357 }
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800358
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700359 ALOGW_IF(dummy_fence_count > 0,
360 "ProducerChannel::ProducerChannel: %" PRIu64
361 " dummy fence(s) was signaled during last release/gain cycle "
362 "buffer_id=%d.",
363 dummy_fence_count, buffer_id());
364
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800365 post_fence_ = std::move(acquire_fence);
366 producer_owns_ = false;
367
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700368 // Signal any interested consumers. If there are none, the buffer will stay
369 // in posted state until a consumer comes online. This behavior guarantees
370 // that no frame is silently dropped.
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800371 pending_consumers_ = 0;
372 for (auto consumer : consumer_channels_) {
373 if (consumer->OnProducerPosted())
374 pending_consumers_++;
375 }
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800376 ALOGD_IF(TRACE, "ProducerChannel::OnProducerPost: %d pending consumers",
377 pending_consumers_);
378
Corey Tabakacd52dd92017-04-07 18:03:57 -0700379 return {};
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800380}
381
Corey Tabakad53870c2017-07-06 18:04:27 -0700382Status<LocalFence> ProducerChannel::OnProducerGain(Message& /*message*/) {
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800383 ATRACE_NAME("ProducerChannel::OnGain");
384 ALOGD_IF(TRACE, "ProducerChannel::OnGain: buffer_id=%d", buffer_id());
385 if (producer_owns_) {
386 ALOGE("ProducerChanneL::OnGain: Already in gained state: channel=%d",
387 channel_id());
Corey Tabakacd52dd92017-04-07 18:03:57 -0700388 return ErrorStatus(EALREADY);
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800389 }
390
391 // There are still pending consumers, return busy.
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700392 if (pending_consumers_ > 0) {
393 ALOGE(
394 "ProducerChannel::OnGain: Producer (id=%d) is gaining a buffer that "
395 "still has %d pending consumer(s).",
396 buffer_id(), pending_consumers_);
Corey Tabakacd52dd92017-04-07 18:03:57 -0700397 return ErrorStatus(EBUSY);
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700398 }
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800399
400 ClearAvailable();
401 producer_owns_ = true;
Alex Vakulenko052f3ae2017-03-31 09:10:43 -0700402 post_fence_.close();
Corey Tabakacd52dd92017-04-07 18:03:57 -0700403 return {std::move(returned_fence_)};
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800404}
405
Jiwen 'Steve' Cai23c1a732018-03-12 12:16:47 -0700406Status<RemoteChannelHandle> ProducerChannel::OnProducerDetach(
407 Message& message) {
408 ATRACE_NAME("ProducerChannel::OnProducerDetach");
409 ALOGD_IF(TRACE, "ProducerChannel::OnProducerDetach: buffer_id=%d",
410 buffer_id());
411
412 uint64_t buffer_state = buffer_state_->load();
413 if (!BufferHubDefs::IsBufferGained(buffer_state)) {
414 // Can only detach a BufferProducer when it's in gained state.
415 ALOGW(
416 "ProducerChannel::OnProducerDetach: The buffer (id=%d, state=0x%" PRIx64
417 ") is not in gained state.",
418 buffer_id(), buffer_state);
419 return {};
420 }
421
422 int channel_id;
423 auto status = message.PushChannel(0, nullptr, &channel_id);
424 if (!status) {
425 ALOGE(
426 "ProducerChannel::OnProducerDetach: Failed to push detached buffer "
427 "channel: %s",
428 status.GetErrorMessage().c_str());
429 return ErrorStatus(ENOMEM);
430 }
431
432 // Make sure we unlock the buffer.
433 if (int ret = metadata_buffer_.Unlock()) {
434 ALOGE("ProducerChannel::OnProducerDetach: Failed to unlock metadata.");
435 return ErrorStatus(-ret);
436 };
437
Jiwen 'Steve' Cai9004b8c2018-10-03 18:52:23 -0700438 std::unique_ptr<BufferChannel> channel =
439 BufferChannel::Create(service(), buffer_id(), channel_id,
440 std::move(buffer_), user_metadata_size_);
Jiwen 'Steve' Caia8049a22018-03-28 15:14:02 -0700441 if (!channel) {
442 ALOGE("ProducerChannel::OnProducerDetach: Invalid buffer.");
443 return ErrorStatus(EINVAL);
444 }
Jiwen 'Steve' Cai23c1a732018-03-12 12:16:47 -0700445
Jiwen 'Steve' Caia8049a22018-03-28 15:14:02 -0700446 const auto channel_status =
447 service()->SetChannel(channel_id, std::move(channel));
Jiwen 'Steve' Cai23c1a732018-03-12 12:16:47 -0700448 if (!channel_status) {
449 // Technically, this should never fail, as we just pushed the channel. Note
450 // that LOG_FATAL will be stripped out in non-debug build.
451 LOG_FATAL(
452 "ProducerChannel::OnProducerDetach: Failed to set new detached buffer "
453 "channel: %s.",
454 channel_status.GetErrorMessage().c_str());
455 }
456
457 return status;
458}
459
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700460Status<LocalFence> ProducerChannel::OnConsumerAcquire(Message& /*message*/) {
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800461 ATRACE_NAME("ProducerChannel::OnConsumerAcquire");
462 ALOGD_IF(TRACE, "ProducerChannel::OnConsumerAcquire: buffer_id=%d",
463 buffer_id());
464 if (producer_owns_) {
465 ALOGE("ProducerChannel::OnConsumerAcquire: Not in posted state!");
Corey Tabakacd52dd92017-04-07 18:03:57 -0700466 return ErrorStatus(EBUSY);
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800467 }
468
469 // Return a borrowed fd to avoid unnecessary duplication of the underlying fd.
470 // Serialization just needs to read the handle.
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700471 return {std::move(post_fence_)};
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800472}
473
Corey Tabakacd52dd92017-04-07 18:03:57 -0700474Status<void> ProducerChannel::OnConsumerRelease(Message&,
475 LocalFence release_fence) {
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800476 ATRACE_NAME("ProducerChannel::OnConsumerRelease");
477 ALOGD_IF(TRACE, "ProducerChannel::OnConsumerRelease: buffer_id=%d",
478 buffer_id());
479 if (producer_owns_) {
480 ALOGE("ProducerChannel::OnConsumerRelease: Not in acquired state!");
Corey Tabakacd52dd92017-04-07 18:03:57 -0700481 return ErrorStatus(EBUSY);
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800482 }
483
484 // Attempt to merge the fences if necessary.
485 if (release_fence) {
486 if (returned_fence_) {
Corey Tabaka3079cb72017-01-19 15:07:26 -0800487 LocalFence merged_fence(sync_merge("bufferhub_merged",
488 returned_fence_.get_fd(),
489 release_fence.get_fd()));
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800490 const int error = errno;
491 if (!merged_fence) {
492 ALOGE("ProducerChannel::OnConsumerRelease: Failed to merge fences: %s",
493 strerror(error));
Corey Tabakacd52dd92017-04-07 18:03:57 -0700494 return ErrorStatus(error);
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800495 }
496 returned_fence_ = std::move(merged_fence);
497 } else {
498 returned_fence_ = std::move(release_fence);
499 }
500 }
501
Tianyu0c6b7ff2018-10-03 11:30:04 -0700502 DecrementPendingConsumers();
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700503 if (pending_consumers_ == 0) {
504 // Clear the producer bit atomically to transit into released state. This
505 // has to done by BufferHub as it requries synchronization among all
506 // consumers.
507 BufferHubDefs::ModifyBufferState(buffer_state_,
508 BufferHubDefs::kProducerStateBit, 0ULL);
509 ALOGD_IF(TRACE,
510 "ProducerChannel::OnConsumerRelease: releasing last consumer: "
511 "buffer_id=%d state=%" PRIx64 ".",
512 buffer_id(), buffer_state_->load());
513
514 if (orphaned_consumer_bit_mask_) {
515 ALOGW(
516 "ProducerChannel::OnConsumerRelease: orphaned buffer detected "
517 "during the this acquire/release cycle: id=%d orphaned=0x%" PRIx64
518 " queue_index=%" PRIu64 ".",
519 buffer_id(), orphaned_consumer_bit_mask_,
520 metadata_header_->queue_index);
521 orphaned_consumer_bit_mask_ = 0;
522 }
523
524 SignalAvailable();
525 }
526
527 ALOGE_IF(pending_consumers_ &&
528 BufferHubDefs::IsBufferReleased(buffer_state_->load()),
529 "ProducerChannel::OnConsumerRelease: buffer state inconsistent: "
530 "pending_consumers=%d, buffer buffer is in releaed state.",
531 pending_consumers_);
Corey Tabakacd52dd92017-04-07 18:03:57 -0700532 return {};
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800533}
534
Tianyu0c6b7ff2018-10-03 11:30:04 -0700535void ProducerChannel::DecrementPendingConsumers() {
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700536 if (pending_consumers_ == 0) {
Tianyu0c6b7ff2018-10-03 11:30:04 -0700537 ALOGE("ProducerChannel::DecrementPendingConsumers: no pending consumer.");
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700538 return;
539 }
540
541 --pending_consumers_;
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800542 ALOGD_IF(TRACE,
Tianyu0c6b7ff2018-10-03 11:30:04 -0700543 "ProducerChannel::DecrementPendingConsumers: buffer_id=%d %d "
544 "consumers left",
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800545 buffer_id(), pending_consumers_);
546}
547
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700548void ProducerChannel::OnConsumerOrphaned(ConsumerChannel* channel) {
549 // Ignore the orphaned consumer.
Tianyu0c6b7ff2018-10-03 11:30:04 -0700550 DecrementPendingConsumers();
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700551
552 const uint64_t consumer_state_bit = channel->consumer_state_bit();
553 ALOGE_IF(orphaned_consumer_bit_mask_ & consumer_state_bit,
554 "ProducerChannel::OnConsumerOrphaned: Consumer "
555 "(consumer_state_bit=%" PRIx64 ") is already orphaned.",
556 consumer_state_bit);
557 orphaned_consumer_bit_mask_ |= consumer_state_bit;
558
559 // Atomically clear the fence state bit as an orphaned consumer will never
560 // signal a release fence. Also clear the buffer state as it won't be released
561 // as well.
562 fence_state_->fetch_and(~consumer_state_bit);
563 BufferHubDefs::ModifyBufferState(buffer_state_, consumer_state_bit, 0ULL);
564
565 ALOGW(
566 "ProducerChannel::OnConsumerOrphaned: detected new orphaned consumer "
567 "buffer_id=%d consumer_state_bit=%" PRIx64 " queue_index=%" PRIu64
568 " buffer_state=%" PRIx64 " fence_state=%" PRIx64 ".",
569 buffer_id(), consumer_state_bit, metadata_header_->queue_index,
570 buffer_state_->load(), fence_state_->load());
571}
572
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800573void ProducerChannel::AddConsumer(ConsumerChannel* channel) {
574 consumer_channels_.push_back(channel);
575}
576
577void ProducerChannel::RemoveConsumer(ConsumerChannel* channel) {
578 consumer_channels_.erase(
579 std::find(consumer_channels_.begin(), consumer_channels_.end(), channel));
Tianyu67053492018-10-04 14:00:22 -0700580 // Restore the consumer state bit and make it visible in other threads that
581 // acquire the active_clients_bit_mask_.
582 active_clients_bit_mask_->fetch_and(~channel->consumer_state_bit(),
583 std::memory_order_release);
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700584
585 const uint64_t buffer_state = buffer_state_->load();
586 if (BufferHubDefs::IsBufferPosted(buffer_state) ||
587 BufferHubDefs::IsBufferAcquired(buffer_state)) {
588 // The consumer client is being destoryed without releasing. This could
589 // happen in corner cases when the consumer crashes. Here we mark it
590 // orphaned before remove it from producer.
591 OnConsumerOrphaned(channel);
592 }
593
594 if (BufferHubDefs::IsBufferReleased(buffer_state) ||
595 BufferHubDefs::IsBufferGained(buffer_state)) {
596 // The consumer is being close while it is suppose to signal a release
597 // fence. Signal the dummy fence here.
598 if (fence_state_->load() & channel->consumer_state_bit()) {
599 epoll_event event;
600 event.events = EPOLLIN;
601 event.data.u64 = channel->consumer_state_bit();
602 if (epoll_ctl(release_fence_fd_.Get(), EPOLL_CTL_MOD,
603 dummy_fence_fd_.Get(), &event) < 0) {
604 ALOGE(
605 "ProducerChannel::RemoveConsumer: Failed to modify the shared "
606 "release fence to include the dummy fence: %s",
607 strerror(errno));
608 return;
609 }
610 ALOGW(
611 "ProducerChannel::RemoveConsumer: signal dummy release fence "
612 "buffer_id=%d",
613 buffer_id());
614 eventfd_write(dummy_fence_fd_.Get(), 1);
615 }
616 }
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800617}
618
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800619// Returns true if the given parameters match the underlying buffer parameters.
Corey Tabakacd52dd92017-04-07 18:03:57 -0700620bool ProducerChannel::CheckParameters(uint32_t width, uint32_t height,
Hendrik Wagenaar108e84f2017-05-07 22:19:17 -0700621 uint32_t layer_count, uint32_t format,
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700622 uint64_t usage,
623 size_t user_metadata_size) {
624 return user_metadata_size == user_metadata_size_ &&
625 buffer_.width() == width && buffer_.height() == height &&
626 buffer_.layer_count() == layer_count && buffer_.format() == format &&
627 buffer_.usage() == usage;
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800628}
629
630} // namespace dvr
631} // namespace android