blob: e141b912866e3b3cc10c633a561f3eaf6b87f539 [file] [log] [blame]
Alex Vakulenkoe4eec202017-01-27 14:41:04 -08001#include "producer_channel.h"
2
Alex Vakulenko4fe60582017-02-02 11:35:59 -08003#include <log/log.h>
Alex Vakulenkoe4eec202017-01-27 14:41:04 -08004#include <sync/sync.h>
Corey Tabaka52ea25c2017-09-13 18:02:48 -07005#include <sys/epoll.h>
6#include <sys/eventfd.h>
Alex Vakulenkoe4eec202017-01-27 14:41:04 -08007#include <sys/poll.h>
8#include <utils/Trace.h>
9
10#include <algorithm>
11#include <atomic>
12#include <thread>
13
Alex Vakulenkoe4eec202017-01-27 14:41:04 -080014#include <private/dvr/bufferhub_rpc.h>
15#include "consumer_channel.h"
Jiwen 'Steve' Cai23c1a732018-03-12 12:16:47 -070016#include "detached_buffer_channel.h"
Alex Vakulenkoe4eec202017-01-27 14:41:04 -080017
18using android::pdx::BorrowedHandle;
Corey Tabakacd52dd92017-04-07 18:03:57 -070019using android::pdx::ErrorStatus;
Alex Vakulenkoe4eec202017-01-27 14:41:04 -080020using android::pdx::Message;
21using android::pdx::RemoteChannelHandle;
Corey Tabakacd52dd92017-04-07 18:03:57 -070022using android::pdx::Status;
Alex Vakulenkoe4eec202017-01-27 14:41:04 -080023using android::pdx::rpc::BufferWrapper;
24using android::pdx::rpc::DispatchRemoteMethod;
25using android::pdx::rpc::WrapBuffer;
26
27namespace android {
28namespace dvr {
29
Corey Tabaka52ea25c2017-09-13 18:02:48 -070030namespace {
31
32static inline uint64_t FindNextClearedBit(uint64_t bits) {
33 return ~bits - (~bits & (~bits - 1));
34}
35
36} // namespace
37
Alex Vakulenkoe4eec202017-01-27 14:41:04 -080038ProducerChannel::ProducerChannel(BufferHubService* service, int channel_id,
Corey Tabakacd52dd92017-04-07 18:03:57 -070039 uint32_t width, uint32_t height,
Hendrik Wagenaar108e84f2017-05-07 22:19:17 -070040 uint32_t layer_count, uint32_t format,
Corey Tabaka52ea25c2017-09-13 18:02:48 -070041 uint64_t usage, size_t user_metadata_size,
Hendrik Wagenaar108e84f2017-05-07 22:19:17 -070042 int* error)
Alex Vakulenkoe4eec202017-01-27 14:41:04 -080043 : BufferHubChannel(service, channel_id, channel_id, kProducerType),
44 pending_consumers_(0),
Alex Vakulenkoe4eec202017-01-27 14:41:04 -080045 producer_owns_(true),
Corey Tabaka52ea25c2017-09-13 18:02:48 -070046 user_metadata_size_(user_metadata_size),
47 metadata_buf_size_(BufferHubDefs::kMetadataHeaderSize +
48 user_metadata_size) {
49 if (int ret = buffer_.Alloc(width, height, layer_count, format, usage)) {
Hendrik Wagenaar4d3590f2017-05-06 22:36:04 -070050 ALOGE("ProducerChannel::ProducerChannel: Failed to allocate buffer: %s",
51 strerror(-ret));
52 *error = ret;
53 return;
Alex Vakulenkoe4eec202017-01-27 14:41:04 -080054 }
55
Corey Tabaka52ea25c2017-09-13 18:02:48 -070056 if (int ret = metadata_buffer_.Alloc(metadata_buf_size_, /*height=*/1,
57 /*layer_count=*/1,
58 BufferHubDefs::kMetadataFormat,
59 BufferHubDefs::kMetadataUsage)) {
60 ALOGE("ProducerChannel::ProducerChannel: Failed to allocate metadata: %s",
61 strerror(-ret));
62 *error = ret;
63 return;
64 }
65
66 void* metadata_ptr = nullptr;
67 if (int ret = metadata_buffer_.Lock(BufferHubDefs::kMetadataUsage, /*x=*/0,
68 /*y=*/0, metadata_buf_size_,
69 /*height=*/1, &metadata_ptr)) {
70 ALOGE("ProducerChannel::ProducerChannel: Failed to lock metadata.");
71 *error = -ret;
72 return;
73 }
74 metadata_header_ =
75 reinterpret_cast<BufferHubDefs::MetadataHeader*>(metadata_ptr);
76
77 // Using placement new here to reuse shared memory instead of new allocation
78 // and also initialize the value to zero.
79 buffer_state_ =
80 new (&metadata_header_->buffer_state) std::atomic<uint64_t>(0);
81 fence_state_ =
82 new (&metadata_header_->fence_state) std::atomic<uint64_t>(0);
83
84 acquire_fence_fd_.Reset(epoll_create1(EPOLL_CLOEXEC));
85 release_fence_fd_.Reset(epoll_create1(EPOLL_CLOEXEC));
86 if (!acquire_fence_fd_ || !release_fence_fd_) {
87 ALOGE("ProducerChannel::ProducerChannel: Failed to create shared fences.");
88 *error = -EIO;
89 return;
90 }
91
92 dummy_fence_fd_.Reset(eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK));
93 if (!dummy_fence_fd_) {
94 ALOGE("ProducerChannel::ProducerChannel: Failed to create dummy fences.");
95 *error = -EIO;
96 return;
97 }
98
99 epoll_event event;
100 event.events = 0;
101 event.data.u64 = 0ULL;
102 if (epoll_ctl(release_fence_fd_.Get(), EPOLL_CTL_ADD, dummy_fence_fd_.Get(),
103 &event) < 0) {
104 ALOGE(
105 "ProducerChannel::ProducerChannel: Failed to modify the shared "
106 "release fence to include the dummy fence: %s",
107 strerror(errno));
108 *error = -EIO;
109 return;
110 }
111
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800112 // Success.
113 *error = 0;
114}
115
Corey Tabakacd52dd92017-04-07 18:03:57 -0700116Status<std::shared_ptr<ProducerChannel>> ProducerChannel::Create(
117 BufferHubService* service, int channel_id, uint32_t width, uint32_t height,
Hendrik Wagenaar108e84f2017-05-07 22:19:17 -0700118 uint32_t layer_count, uint32_t format, uint64_t usage,
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700119 size_t user_metadata_size) {
Corey Tabakacd52dd92017-04-07 18:03:57 -0700120 int error;
Jiwen 'Steve' Cai0057fdd2017-05-02 11:21:18 -0700121 std::shared_ptr<ProducerChannel> producer(
Hendrik Wagenaar108e84f2017-05-07 22:19:17 -0700122 new ProducerChannel(service, channel_id, width, height, layer_count,
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700123 format, usage, user_metadata_size, &error));
Corey Tabakacd52dd92017-04-07 18:03:57 -0700124 if (error < 0)
125 return ErrorStatus(-error);
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800126 else
Corey Tabakacd52dd92017-04-07 18:03:57 -0700127 return {std::move(producer)};
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800128}
129
130ProducerChannel::~ProducerChannel() {
Corey Tabaka3079cb72017-01-19 15:07:26 -0800131 ALOGD_IF(TRACE,
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700132 "ProducerChannel::~ProducerChannel: channel_id=%d buffer_id=%d "
133 "state=%" PRIx64 ".",
134 channel_id(), buffer_id(), buffer_state_->load());
Jiwen 'Steve' Cai23c1a732018-03-12 12:16:47 -0700135 for (auto consumer : consumer_channels_) {
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800136 consumer->OnProducerClosed();
Jiwen 'Steve' Cai23c1a732018-03-12 12:16:47 -0700137 service()->SetChannel(consumer->channel_id(), nullptr);
138 }
139 Hangup();
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800140}
141
142BufferHubChannel::BufferInfo ProducerChannel::GetBufferInfo() const {
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700143 // Derive the mask of signaled buffers in this producer / consumer set.
144 uint64_t signaled_mask = signaled() ? BufferHubDefs::kProducerStateBit : 0;
145 for (const ConsumerChannel* consumer : consumer_channels_) {
146 signaled_mask |= consumer->signaled() ? consumer->consumer_state_bit() : 0;
147 }
148
Hendrik Wagenaar4d3590f2017-05-06 22:36:04 -0700149 return BufferInfo(buffer_id(), consumer_channels_.size(), buffer_.width(),
Hendrik Wagenaar108e84f2017-05-07 22:19:17 -0700150 buffer_.height(), buffer_.layer_count(), buffer_.format(),
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700151 buffer_.usage(), pending_consumers_, buffer_state_->load(),
Jiwen 'Steve' Cai2f260332018-02-15 18:39:47 -0800152 signaled_mask, metadata_header_->queue_index);
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800153}
154
155void ProducerChannel::HandleImpulse(Message& message) {
156 ATRACE_NAME("ProducerChannel::HandleImpulse");
157 switch (message.GetOp()) {
158 case BufferHubRPC::ProducerGain::Opcode:
159 OnProducerGain(message);
160 break;
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700161 case BufferHubRPC::ProducerPost::Opcode:
162 OnProducerPost(message, {});
163 break;
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800164 }
165}
166
167bool ProducerChannel::HandleMessage(Message& message) {
168 ATRACE_NAME("ProducerChannel::HandleMessage");
169 switch (message.GetOp()) {
170 case BufferHubRPC::GetBuffer::Opcode:
171 DispatchRemoteMethod<BufferHubRPC::GetBuffer>(
172 *this, &ProducerChannel::OnGetBuffer, message);
173 return true;
174
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800175 case BufferHubRPC::NewConsumer::Opcode:
176 DispatchRemoteMethod<BufferHubRPC::NewConsumer>(
177 *this, &ProducerChannel::OnNewConsumer, message);
178 return true;
179
180 case BufferHubRPC::ProducerPost::Opcode:
181 DispatchRemoteMethod<BufferHubRPC::ProducerPost>(
182 *this, &ProducerChannel::OnProducerPost, message);
183 return true;
184
185 case BufferHubRPC::ProducerGain::Opcode:
186 DispatchRemoteMethod<BufferHubRPC::ProducerGain>(
187 *this, &ProducerChannel::OnProducerGain, message);
188 return true;
189
Jiwen 'Steve' Cai23c1a732018-03-12 12:16:47 -0700190 case BufferHubRPC::ProducerBufferDetach::Opcode:
191 DispatchRemoteMethod<BufferHubRPC::ProducerBufferDetach>(
192 *this, &ProducerChannel::OnProducerDetach, message);
193 return true;
194
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800195 default:
196 return false;
197 }
198}
199
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700200BufferDescription<BorrowedHandle> ProducerChannel::GetBuffer(
201 uint64_t buffer_state_bit) {
202 return {
203 buffer_, metadata_buffer_, buffer_id(),
204 buffer_state_bit, acquire_fence_fd_.Borrow(), release_fence_fd_.Borrow()};
205}
206
207Status<BufferDescription<BorrowedHandle>> ProducerChannel::OnGetBuffer(
Corey Tabakad53870c2017-07-06 18:04:27 -0700208 Message& /*message*/) {
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800209 ATRACE_NAME("ProducerChannel::OnGetBuffer");
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700210 ALOGD_IF(TRACE, "ProducerChannel::OnGetBuffer: buffer=%d, state=%" PRIx64 ".",
211 buffer_id(), buffer_state_->load());
212 return {GetBuffer(BufferHubDefs::kProducerStateBit)};
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800213}
214
Corey Tabakacd52dd92017-04-07 18:03:57 -0700215Status<RemoteChannelHandle> ProducerChannel::CreateConsumer(Message& message) {
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800216 ATRACE_NAME("ProducerChannel::CreateConsumer");
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700217 ALOGD_IF(TRACE,
218 "ProducerChannel::CreateConsumer: buffer_id=%d, producer_owns=%d",
219 buffer_id(), producer_owns_);
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800220
221 int channel_id;
222 auto status = message.PushChannel(0, nullptr, &channel_id);
223 if (!status) {
224 ALOGE(
Corey Tabakacd52dd92017-04-07 18:03:57 -0700225 "ProducerChannel::CreateConsumer: Failed to push consumer channel: %s",
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800226 status.GetErrorMessage().c_str());
Corey Tabakacd52dd92017-04-07 18:03:57 -0700227 return ErrorStatus(ENOMEM);
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800228 }
229
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700230 // Try find the next consumer state bit which has not been claimed by any
231 // consumer yet.
232 uint64_t consumer_state_bit = FindNextClearedBit(
233 active_consumer_bit_mask_ | orphaned_consumer_bit_mask_ |
234 BufferHubDefs::kProducerStateBit);
235 if (consumer_state_bit == 0ULL) {
236 ALOGE(
237 "ProducerChannel::CreateConsumer: reached the maximum mumber of "
238 "consumers per producer: 63.");
239 return ErrorStatus(E2BIG);
240 }
241
242 auto consumer =
243 std::make_shared<ConsumerChannel>(service(), buffer_id(), channel_id,
244 consumer_state_bit, shared_from_this());
Alex Vakulenkof0a7bd02017-03-31 18:06:19 -0700245 const auto channel_status = service()->SetChannel(channel_id, consumer);
246 if (!channel_status) {
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800247 ALOGE(
248 "ProducerChannel::CreateConsumer: failed to set new consumer channel: "
249 "%s",
Alex Vakulenkof0a7bd02017-03-31 18:06:19 -0700250 channel_status.GetErrorMessage().c_str());
Corey Tabakacd52dd92017-04-07 18:03:57 -0700251 return ErrorStatus(ENOMEM);
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800252 }
253
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700254 if (!producer_owns_ &&
255 !BufferHubDefs::IsBufferReleased(buffer_state_->load())) {
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800256 // Signal the new consumer when adding it to a posted producer.
257 if (consumer->OnProducerPosted())
258 pending_consumers_++;
259 }
260
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700261 active_consumer_bit_mask_ |= consumer_state_bit;
Corey Tabakacd52dd92017-04-07 18:03:57 -0700262 return {status.take()};
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800263}
264
Corey Tabakacd52dd92017-04-07 18:03:57 -0700265Status<RemoteChannelHandle> ProducerChannel::OnNewConsumer(Message& message) {
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800266 ATRACE_NAME("ProducerChannel::OnNewConsumer");
267 ALOGD_IF(TRACE, "ProducerChannel::OnNewConsumer: buffer_id=%d", buffer_id());
Corey Tabakacd52dd92017-04-07 18:03:57 -0700268 return CreateConsumer(message);
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800269}
270
Corey Tabakacd52dd92017-04-07 18:03:57 -0700271Status<void> ProducerChannel::OnProducerPost(
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700272 Message&, LocalFence acquire_fence) {
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800273 ATRACE_NAME("ProducerChannel::OnProducerPost");
274 ALOGD_IF(TRACE, "ProducerChannel::OnProducerPost: buffer_id=%d", buffer_id());
275 if (!producer_owns_) {
276 ALOGE("ProducerChannel::OnProducerPost: Not in gained state!");
Corey Tabakacd52dd92017-04-07 18:03:57 -0700277 return ErrorStatus(EBUSY);
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800278 }
279
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700280 epoll_event event;
281 event.events = 0;
282 event.data.u64 = 0ULL;
283 int ret = epoll_ctl(release_fence_fd_.Get(), EPOLL_CTL_MOD,
284 dummy_fence_fd_.Get(), &event);
285 ALOGE_IF(ret < 0,
286 "ProducerChannel::OnProducerPost: Failed to modify the shared "
287 "release fence to include the dummy fence: %s",
288 strerror(errno));
289
290 eventfd_t dummy_fence_count = 0ULL;
291 if (eventfd_read(dummy_fence_fd_.Get(), &dummy_fence_count) < 0) {
292 const int error = errno;
293 if (error != EAGAIN) {
294 ALOGE(
295 "ProducerChannel::ProducerChannel: Failed to read dummy fence, "
296 "error: %s",
297 strerror(error));
298 return ErrorStatus(error);
299 }
Corey Tabaka8a4e6a92017-04-20 13:42:02 -0700300 }
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800301
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700302 ALOGW_IF(dummy_fence_count > 0,
303 "ProducerChannel::ProducerChannel: %" PRIu64
304 " dummy fence(s) was signaled during last release/gain cycle "
305 "buffer_id=%d.",
306 dummy_fence_count, buffer_id());
307
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800308 post_fence_ = std::move(acquire_fence);
309 producer_owns_ = false;
310
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700311 // Signal any interested consumers. If there are none, the buffer will stay
312 // in posted state until a consumer comes online. This behavior guarantees
313 // that no frame is silently dropped.
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800314 pending_consumers_ = 0;
315 for (auto consumer : consumer_channels_) {
316 if (consumer->OnProducerPosted())
317 pending_consumers_++;
318 }
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800319 ALOGD_IF(TRACE, "ProducerChannel::OnProducerPost: %d pending consumers",
320 pending_consumers_);
321
Corey Tabakacd52dd92017-04-07 18:03:57 -0700322 return {};
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800323}
324
Corey Tabakad53870c2017-07-06 18:04:27 -0700325Status<LocalFence> ProducerChannel::OnProducerGain(Message& /*message*/) {
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800326 ATRACE_NAME("ProducerChannel::OnGain");
327 ALOGD_IF(TRACE, "ProducerChannel::OnGain: buffer_id=%d", buffer_id());
328 if (producer_owns_) {
329 ALOGE("ProducerChanneL::OnGain: Already in gained state: channel=%d",
330 channel_id());
Corey Tabakacd52dd92017-04-07 18:03:57 -0700331 return ErrorStatus(EALREADY);
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800332 }
333
334 // There are still pending consumers, return busy.
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700335 if (pending_consumers_ > 0) {
336 ALOGE(
337 "ProducerChannel::OnGain: Producer (id=%d) is gaining a buffer that "
338 "still has %d pending consumer(s).",
339 buffer_id(), pending_consumers_);
Corey Tabakacd52dd92017-04-07 18:03:57 -0700340 return ErrorStatus(EBUSY);
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700341 }
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800342
343 ClearAvailable();
344 producer_owns_ = true;
Alex Vakulenko052f3ae2017-03-31 09:10:43 -0700345 post_fence_.close();
Corey Tabakacd52dd92017-04-07 18:03:57 -0700346 return {std::move(returned_fence_)};
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800347}
348
Jiwen 'Steve' Cai23c1a732018-03-12 12:16:47 -0700349Status<RemoteChannelHandle> ProducerChannel::OnProducerDetach(
350 Message& message) {
351 ATRACE_NAME("ProducerChannel::OnProducerDetach");
352 ALOGD_IF(TRACE, "ProducerChannel::OnProducerDetach: buffer_id=%d",
353 buffer_id());
354
355 uint64_t buffer_state = buffer_state_->load();
356 if (!BufferHubDefs::IsBufferGained(buffer_state)) {
357 // Can only detach a BufferProducer when it's in gained state.
358 ALOGW(
359 "ProducerChannel::OnProducerDetach: The buffer (id=%d, state=0x%" PRIx64
360 ") is not in gained state.",
361 buffer_id(), buffer_state);
362 return {};
363 }
364
365 int channel_id;
366 auto status = message.PushChannel(0, nullptr, &channel_id);
367 if (!status) {
368 ALOGE(
369 "ProducerChannel::OnProducerDetach: Failed to push detached buffer "
370 "channel: %s",
371 status.GetErrorMessage().c_str());
372 return ErrorStatus(ENOMEM);
373 }
374
375 // Make sure we unlock the buffer.
376 if (int ret = metadata_buffer_.Unlock()) {
377 ALOGE("ProducerChannel::OnProducerDetach: Failed to unlock metadata.");
378 return ErrorStatus(-ret);
379 };
380
381 auto channel = std::make_shared<DetachedBufferChannel>(
382 service(), buffer_id(), channel_id, std::move(buffer_),
383 std::move(metadata_buffer_), user_metadata_size_);
384
385 const auto channel_status = service()->SetChannel(channel_id, channel);
386 if (!channel_status) {
387 // Technically, this should never fail, as we just pushed the channel. Note
388 // that LOG_FATAL will be stripped out in non-debug build.
389 LOG_FATAL(
390 "ProducerChannel::OnProducerDetach: Failed to set new detached buffer "
391 "channel: %s.",
392 channel_status.GetErrorMessage().c_str());
393 }
394
395 return status;
396}
397
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700398Status<LocalFence> ProducerChannel::OnConsumerAcquire(Message& /*message*/) {
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800399 ATRACE_NAME("ProducerChannel::OnConsumerAcquire");
400 ALOGD_IF(TRACE, "ProducerChannel::OnConsumerAcquire: buffer_id=%d",
401 buffer_id());
402 if (producer_owns_) {
403 ALOGE("ProducerChannel::OnConsumerAcquire: Not in posted state!");
Corey Tabakacd52dd92017-04-07 18:03:57 -0700404 return ErrorStatus(EBUSY);
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800405 }
406
407 // Return a borrowed fd to avoid unnecessary duplication of the underlying fd.
408 // Serialization just needs to read the handle.
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700409 return {std::move(post_fence_)};
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800410}
411
Corey Tabakacd52dd92017-04-07 18:03:57 -0700412Status<void> ProducerChannel::OnConsumerRelease(Message&,
413 LocalFence release_fence) {
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800414 ATRACE_NAME("ProducerChannel::OnConsumerRelease");
415 ALOGD_IF(TRACE, "ProducerChannel::OnConsumerRelease: buffer_id=%d",
416 buffer_id());
417 if (producer_owns_) {
418 ALOGE("ProducerChannel::OnConsumerRelease: Not in acquired state!");
Corey Tabakacd52dd92017-04-07 18:03:57 -0700419 return ErrorStatus(EBUSY);
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800420 }
421
422 // Attempt to merge the fences if necessary.
423 if (release_fence) {
424 if (returned_fence_) {
Corey Tabaka3079cb72017-01-19 15:07:26 -0800425 LocalFence merged_fence(sync_merge("bufferhub_merged",
426 returned_fence_.get_fd(),
427 release_fence.get_fd()));
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800428 const int error = errno;
429 if (!merged_fence) {
430 ALOGE("ProducerChannel::OnConsumerRelease: Failed to merge fences: %s",
431 strerror(error));
Corey Tabakacd52dd92017-04-07 18:03:57 -0700432 return ErrorStatus(error);
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800433 }
434 returned_fence_ = std::move(merged_fence);
435 } else {
436 returned_fence_ = std::move(release_fence);
437 }
438 }
439
440 OnConsumerIgnored();
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700441 if (pending_consumers_ == 0) {
442 // Clear the producer bit atomically to transit into released state. This
443 // has to done by BufferHub as it requries synchronization among all
444 // consumers.
445 BufferHubDefs::ModifyBufferState(buffer_state_,
446 BufferHubDefs::kProducerStateBit, 0ULL);
447 ALOGD_IF(TRACE,
448 "ProducerChannel::OnConsumerRelease: releasing last consumer: "
449 "buffer_id=%d state=%" PRIx64 ".",
450 buffer_id(), buffer_state_->load());
451
452 if (orphaned_consumer_bit_mask_) {
453 ALOGW(
454 "ProducerChannel::OnConsumerRelease: orphaned buffer detected "
455 "during the this acquire/release cycle: id=%d orphaned=0x%" PRIx64
456 " queue_index=%" PRIu64 ".",
457 buffer_id(), orphaned_consumer_bit_mask_,
458 metadata_header_->queue_index);
459 orphaned_consumer_bit_mask_ = 0;
460 }
461
462 SignalAvailable();
463 }
464
465 ALOGE_IF(pending_consumers_ &&
466 BufferHubDefs::IsBufferReleased(buffer_state_->load()),
467 "ProducerChannel::OnConsumerRelease: buffer state inconsistent: "
468 "pending_consumers=%d, buffer buffer is in releaed state.",
469 pending_consumers_);
Corey Tabakacd52dd92017-04-07 18:03:57 -0700470 return {};
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800471}
472
473void ProducerChannel::OnConsumerIgnored() {
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700474 if (pending_consumers_ == 0) {
475 ALOGE("ProducerChannel::OnConsumerIgnored: no pending consumer.");
476 return;
477 }
478
479 --pending_consumers_;
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800480 ALOGD_IF(TRACE,
481 "ProducerChannel::OnConsumerIgnored: buffer_id=%d %d consumers left",
482 buffer_id(), pending_consumers_);
483}
484
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700485void ProducerChannel::OnConsumerOrphaned(ConsumerChannel* channel) {
486 // Ignore the orphaned consumer.
487 OnConsumerIgnored();
488
489 const uint64_t consumer_state_bit = channel->consumer_state_bit();
490 ALOGE_IF(orphaned_consumer_bit_mask_ & consumer_state_bit,
491 "ProducerChannel::OnConsumerOrphaned: Consumer "
492 "(consumer_state_bit=%" PRIx64 ") is already orphaned.",
493 consumer_state_bit);
494 orphaned_consumer_bit_mask_ |= consumer_state_bit;
495
496 // Atomically clear the fence state bit as an orphaned consumer will never
497 // signal a release fence. Also clear the buffer state as it won't be released
498 // as well.
499 fence_state_->fetch_and(~consumer_state_bit);
500 BufferHubDefs::ModifyBufferState(buffer_state_, consumer_state_bit, 0ULL);
501
502 ALOGW(
503 "ProducerChannel::OnConsumerOrphaned: detected new orphaned consumer "
504 "buffer_id=%d consumer_state_bit=%" PRIx64 " queue_index=%" PRIu64
505 " buffer_state=%" PRIx64 " fence_state=%" PRIx64 ".",
506 buffer_id(), consumer_state_bit, metadata_header_->queue_index,
507 buffer_state_->load(), fence_state_->load());
508}
509
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800510void ProducerChannel::AddConsumer(ConsumerChannel* channel) {
511 consumer_channels_.push_back(channel);
512}
513
514void ProducerChannel::RemoveConsumer(ConsumerChannel* channel) {
515 consumer_channels_.erase(
516 std::find(consumer_channels_.begin(), consumer_channels_.end(), channel));
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700517 active_consumer_bit_mask_ &= ~channel->consumer_state_bit();
518
519 const uint64_t buffer_state = buffer_state_->load();
520 if (BufferHubDefs::IsBufferPosted(buffer_state) ||
521 BufferHubDefs::IsBufferAcquired(buffer_state)) {
522 // The consumer client is being destoryed without releasing. This could
523 // happen in corner cases when the consumer crashes. Here we mark it
524 // orphaned before remove it from producer.
525 OnConsumerOrphaned(channel);
526 }
527
528 if (BufferHubDefs::IsBufferReleased(buffer_state) ||
529 BufferHubDefs::IsBufferGained(buffer_state)) {
530 // The consumer is being close while it is suppose to signal a release
531 // fence. Signal the dummy fence here.
532 if (fence_state_->load() & channel->consumer_state_bit()) {
533 epoll_event event;
534 event.events = EPOLLIN;
535 event.data.u64 = channel->consumer_state_bit();
536 if (epoll_ctl(release_fence_fd_.Get(), EPOLL_CTL_MOD,
537 dummy_fence_fd_.Get(), &event) < 0) {
538 ALOGE(
539 "ProducerChannel::RemoveConsumer: Failed to modify the shared "
540 "release fence to include the dummy fence: %s",
541 strerror(errno));
542 return;
543 }
544 ALOGW(
545 "ProducerChannel::RemoveConsumer: signal dummy release fence "
546 "buffer_id=%d",
547 buffer_id());
548 eventfd_write(dummy_fence_fd_.Get(), 1);
549 }
550 }
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800551}
552
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800553// Returns true if the given parameters match the underlying buffer parameters.
Corey Tabakacd52dd92017-04-07 18:03:57 -0700554bool ProducerChannel::CheckParameters(uint32_t width, uint32_t height,
Hendrik Wagenaar108e84f2017-05-07 22:19:17 -0700555 uint32_t layer_count, uint32_t format,
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700556 uint64_t usage,
557 size_t user_metadata_size) {
558 return user_metadata_size == user_metadata_size_ &&
559 buffer_.width() == width && buffer_.height() == height &&
560 buffer_.layer_count() == layer_count && buffer_.format() == format &&
561 buffer_.usage() == usage;
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800562}
563
564} // namespace dvr
565} // namespace android