blob: a753168750736382ac0c876ce657b1c6d1a48220 [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 }
138 Hangup();
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800139}
140
141BufferHubChannel::BufferInfo ProducerChannel::GetBufferInfo() const {
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700142 // Derive the mask of signaled buffers in this producer / consumer set.
143 uint64_t signaled_mask = signaled() ? BufferHubDefs::kProducerStateBit : 0;
144 for (const ConsumerChannel* consumer : consumer_channels_) {
145 signaled_mask |= consumer->signaled() ? consumer->consumer_state_bit() : 0;
146 }
147
Hendrik Wagenaar4d3590f2017-05-06 22:36:04 -0700148 return BufferInfo(buffer_id(), consumer_channels_.size(), buffer_.width(),
Hendrik Wagenaar108e84f2017-05-07 22:19:17 -0700149 buffer_.height(), buffer_.layer_count(), buffer_.format(),
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700150 buffer_.usage(), pending_consumers_, buffer_state_->load(),
Jiwen 'Steve' Cai2f260332018-02-15 18:39:47 -0800151 signaled_mask, metadata_header_->queue_index);
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800152}
153
154void ProducerChannel::HandleImpulse(Message& message) {
155 ATRACE_NAME("ProducerChannel::HandleImpulse");
156 switch (message.GetOp()) {
157 case BufferHubRPC::ProducerGain::Opcode:
158 OnProducerGain(message);
159 break;
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700160 case BufferHubRPC::ProducerPost::Opcode:
161 OnProducerPost(message, {});
162 break;
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800163 }
164}
165
166bool ProducerChannel::HandleMessage(Message& message) {
167 ATRACE_NAME("ProducerChannel::HandleMessage");
168 switch (message.GetOp()) {
169 case BufferHubRPC::GetBuffer::Opcode:
170 DispatchRemoteMethod<BufferHubRPC::GetBuffer>(
171 *this, &ProducerChannel::OnGetBuffer, message);
172 return true;
173
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800174 case BufferHubRPC::NewConsumer::Opcode:
175 DispatchRemoteMethod<BufferHubRPC::NewConsumer>(
176 *this, &ProducerChannel::OnNewConsumer, message);
177 return true;
178
179 case BufferHubRPC::ProducerPost::Opcode:
180 DispatchRemoteMethod<BufferHubRPC::ProducerPost>(
181 *this, &ProducerChannel::OnProducerPost, message);
182 return true;
183
184 case BufferHubRPC::ProducerGain::Opcode:
185 DispatchRemoteMethod<BufferHubRPC::ProducerGain>(
186 *this, &ProducerChannel::OnProducerGain, message);
187 return true;
188
Jiwen 'Steve' Cai23c1a732018-03-12 12:16:47 -0700189 case BufferHubRPC::ProducerBufferDetach::Opcode:
190 DispatchRemoteMethod<BufferHubRPC::ProducerBufferDetach>(
191 *this, &ProducerChannel::OnProducerDetach, message);
192 return true;
193
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800194 default:
195 return false;
196 }
197}
198
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700199BufferDescription<BorrowedHandle> ProducerChannel::GetBuffer(
200 uint64_t buffer_state_bit) {
201 return {
202 buffer_, metadata_buffer_, buffer_id(),
203 buffer_state_bit, acquire_fence_fd_.Borrow(), release_fence_fd_.Borrow()};
204}
205
206Status<BufferDescription<BorrowedHandle>> ProducerChannel::OnGetBuffer(
Corey Tabakad53870c2017-07-06 18:04:27 -0700207 Message& /*message*/) {
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800208 ATRACE_NAME("ProducerChannel::OnGetBuffer");
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700209 ALOGD_IF(TRACE, "ProducerChannel::OnGetBuffer: buffer=%d, state=%" PRIx64 ".",
210 buffer_id(), buffer_state_->load());
211 return {GetBuffer(BufferHubDefs::kProducerStateBit)};
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800212}
213
Corey Tabakacd52dd92017-04-07 18:03:57 -0700214Status<RemoteChannelHandle> ProducerChannel::CreateConsumer(Message& message) {
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800215 ATRACE_NAME("ProducerChannel::CreateConsumer");
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700216 ALOGD_IF(TRACE,
217 "ProducerChannel::CreateConsumer: buffer_id=%d, producer_owns=%d",
218 buffer_id(), producer_owns_);
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800219
220 int channel_id;
221 auto status = message.PushChannel(0, nullptr, &channel_id);
222 if (!status) {
223 ALOGE(
Corey Tabakacd52dd92017-04-07 18:03:57 -0700224 "ProducerChannel::CreateConsumer: Failed to push consumer channel: %s",
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800225 status.GetErrorMessage().c_str());
Corey Tabakacd52dd92017-04-07 18:03:57 -0700226 return ErrorStatus(ENOMEM);
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800227 }
228
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700229 // Try find the next consumer state bit which has not been claimed by any
230 // consumer yet.
231 uint64_t consumer_state_bit = FindNextClearedBit(
232 active_consumer_bit_mask_ | orphaned_consumer_bit_mask_ |
233 BufferHubDefs::kProducerStateBit);
234 if (consumer_state_bit == 0ULL) {
235 ALOGE(
236 "ProducerChannel::CreateConsumer: reached the maximum mumber of "
237 "consumers per producer: 63.");
238 return ErrorStatus(E2BIG);
239 }
240
241 auto consumer =
242 std::make_shared<ConsumerChannel>(service(), buffer_id(), channel_id,
243 consumer_state_bit, shared_from_this());
Alex Vakulenkof0a7bd02017-03-31 18:06:19 -0700244 const auto channel_status = service()->SetChannel(channel_id, consumer);
245 if (!channel_status) {
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800246 ALOGE(
247 "ProducerChannel::CreateConsumer: failed to set new consumer channel: "
248 "%s",
Alex Vakulenkof0a7bd02017-03-31 18:06:19 -0700249 channel_status.GetErrorMessage().c_str());
Corey Tabakacd52dd92017-04-07 18:03:57 -0700250 return ErrorStatus(ENOMEM);
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800251 }
252
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700253 if (!producer_owns_ &&
254 !BufferHubDefs::IsBufferReleased(buffer_state_->load())) {
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800255 // Signal the new consumer when adding it to a posted producer.
256 if (consumer->OnProducerPosted())
257 pending_consumers_++;
258 }
259
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700260 active_consumer_bit_mask_ |= consumer_state_bit;
Corey Tabakacd52dd92017-04-07 18:03:57 -0700261 return {status.take()};
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800262}
263
Corey Tabakacd52dd92017-04-07 18:03:57 -0700264Status<RemoteChannelHandle> ProducerChannel::OnNewConsumer(Message& message) {
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800265 ATRACE_NAME("ProducerChannel::OnNewConsumer");
266 ALOGD_IF(TRACE, "ProducerChannel::OnNewConsumer: buffer_id=%d", buffer_id());
Corey Tabakacd52dd92017-04-07 18:03:57 -0700267 return CreateConsumer(message);
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800268}
269
Corey Tabakacd52dd92017-04-07 18:03:57 -0700270Status<void> ProducerChannel::OnProducerPost(
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700271 Message&, LocalFence acquire_fence) {
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800272 ATRACE_NAME("ProducerChannel::OnProducerPost");
273 ALOGD_IF(TRACE, "ProducerChannel::OnProducerPost: buffer_id=%d", buffer_id());
274 if (!producer_owns_) {
275 ALOGE("ProducerChannel::OnProducerPost: Not in gained state!");
Corey Tabakacd52dd92017-04-07 18:03:57 -0700276 return ErrorStatus(EBUSY);
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800277 }
278
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700279 epoll_event event;
280 event.events = 0;
281 event.data.u64 = 0ULL;
282 int ret = epoll_ctl(release_fence_fd_.Get(), EPOLL_CTL_MOD,
283 dummy_fence_fd_.Get(), &event);
284 ALOGE_IF(ret < 0,
285 "ProducerChannel::OnProducerPost: Failed to modify the shared "
286 "release fence to include the dummy fence: %s",
287 strerror(errno));
288
289 eventfd_t dummy_fence_count = 0ULL;
290 if (eventfd_read(dummy_fence_fd_.Get(), &dummy_fence_count) < 0) {
291 const int error = errno;
292 if (error != EAGAIN) {
293 ALOGE(
294 "ProducerChannel::ProducerChannel: Failed to read dummy fence, "
295 "error: %s",
296 strerror(error));
297 return ErrorStatus(error);
298 }
Corey Tabaka8a4e6a92017-04-20 13:42:02 -0700299 }
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800300
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700301 ALOGW_IF(dummy_fence_count > 0,
302 "ProducerChannel::ProducerChannel: %" PRIu64
303 " dummy fence(s) was signaled during last release/gain cycle "
304 "buffer_id=%d.",
305 dummy_fence_count, buffer_id());
306
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800307 post_fence_ = std::move(acquire_fence);
308 producer_owns_ = false;
309
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700310 // Signal any interested consumers. If there are none, the buffer will stay
311 // in posted state until a consumer comes online. This behavior guarantees
312 // that no frame is silently dropped.
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800313 pending_consumers_ = 0;
314 for (auto consumer : consumer_channels_) {
315 if (consumer->OnProducerPosted())
316 pending_consumers_++;
317 }
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800318 ALOGD_IF(TRACE, "ProducerChannel::OnProducerPost: %d pending consumers",
319 pending_consumers_);
320
Corey Tabakacd52dd92017-04-07 18:03:57 -0700321 return {};
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800322}
323
Corey Tabakad53870c2017-07-06 18:04:27 -0700324Status<LocalFence> ProducerChannel::OnProducerGain(Message& /*message*/) {
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800325 ATRACE_NAME("ProducerChannel::OnGain");
326 ALOGD_IF(TRACE, "ProducerChannel::OnGain: buffer_id=%d", buffer_id());
327 if (producer_owns_) {
328 ALOGE("ProducerChanneL::OnGain: Already in gained state: channel=%d",
329 channel_id());
Corey Tabakacd52dd92017-04-07 18:03:57 -0700330 return ErrorStatus(EALREADY);
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800331 }
332
333 // There are still pending consumers, return busy.
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700334 if (pending_consumers_ > 0) {
335 ALOGE(
336 "ProducerChannel::OnGain: Producer (id=%d) is gaining a buffer that "
337 "still has %d pending consumer(s).",
338 buffer_id(), pending_consumers_);
Corey Tabakacd52dd92017-04-07 18:03:57 -0700339 return ErrorStatus(EBUSY);
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700340 }
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800341
342 ClearAvailable();
343 producer_owns_ = true;
Alex Vakulenko052f3ae2017-03-31 09:10:43 -0700344 post_fence_.close();
Corey Tabakacd52dd92017-04-07 18:03:57 -0700345 return {std::move(returned_fence_)};
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800346}
347
Jiwen 'Steve' Cai23c1a732018-03-12 12:16:47 -0700348Status<RemoteChannelHandle> ProducerChannel::OnProducerDetach(
349 Message& message) {
350 ATRACE_NAME("ProducerChannel::OnProducerDetach");
351 ALOGD_IF(TRACE, "ProducerChannel::OnProducerDetach: buffer_id=%d",
352 buffer_id());
353
354 uint64_t buffer_state = buffer_state_->load();
355 if (!BufferHubDefs::IsBufferGained(buffer_state)) {
356 // Can only detach a BufferProducer when it's in gained state.
357 ALOGW(
358 "ProducerChannel::OnProducerDetach: The buffer (id=%d, state=0x%" PRIx64
359 ") is not in gained state.",
360 buffer_id(), buffer_state);
361 return {};
362 }
363
364 int channel_id;
365 auto status = message.PushChannel(0, nullptr, &channel_id);
366 if (!status) {
367 ALOGE(
368 "ProducerChannel::OnProducerDetach: Failed to push detached buffer "
369 "channel: %s",
370 status.GetErrorMessage().c_str());
371 return ErrorStatus(ENOMEM);
372 }
373
374 // Make sure we unlock the buffer.
375 if (int ret = metadata_buffer_.Unlock()) {
376 ALOGE("ProducerChannel::OnProducerDetach: Failed to unlock metadata.");
377 return ErrorStatus(-ret);
378 };
379
Jiwen 'Steve' Caia8049a22018-03-28 15:14:02 -0700380 std::unique_ptr<DetachedBufferChannel> channel =
381 DetachedBufferChannel::Create(
382 service(), buffer_id(), channel_id, std::move(buffer_),
383 std::move(metadata_buffer_), user_metadata_size_);
384 if (!channel) {
385 ALOGE("ProducerChannel::OnProducerDetach: Invalid buffer.");
386 return ErrorStatus(EINVAL);
387 }
Jiwen 'Steve' Cai23c1a732018-03-12 12:16:47 -0700388
Jiwen 'Steve' Caia8049a22018-03-28 15:14:02 -0700389 const auto channel_status =
390 service()->SetChannel(channel_id, std::move(channel));
Jiwen 'Steve' Cai23c1a732018-03-12 12:16:47 -0700391 if (!channel_status) {
392 // Technically, this should never fail, as we just pushed the channel. Note
393 // that LOG_FATAL will be stripped out in non-debug build.
394 LOG_FATAL(
395 "ProducerChannel::OnProducerDetach: Failed to set new detached buffer "
396 "channel: %s.",
397 channel_status.GetErrorMessage().c_str());
398 }
399
400 return status;
401}
402
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700403Status<LocalFence> ProducerChannel::OnConsumerAcquire(Message& /*message*/) {
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800404 ATRACE_NAME("ProducerChannel::OnConsumerAcquire");
405 ALOGD_IF(TRACE, "ProducerChannel::OnConsumerAcquire: buffer_id=%d",
406 buffer_id());
407 if (producer_owns_) {
408 ALOGE("ProducerChannel::OnConsumerAcquire: Not in posted state!");
Corey Tabakacd52dd92017-04-07 18:03:57 -0700409 return ErrorStatus(EBUSY);
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800410 }
411
412 // Return a borrowed fd to avoid unnecessary duplication of the underlying fd.
413 // Serialization just needs to read the handle.
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700414 return {std::move(post_fence_)};
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800415}
416
Corey Tabakacd52dd92017-04-07 18:03:57 -0700417Status<void> ProducerChannel::OnConsumerRelease(Message&,
418 LocalFence release_fence) {
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800419 ATRACE_NAME("ProducerChannel::OnConsumerRelease");
420 ALOGD_IF(TRACE, "ProducerChannel::OnConsumerRelease: buffer_id=%d",
421 buffer_id());
422 if (producer_owns_) {
423 ALOGE("ProducerChannel::OnConsumerRelease: Not in acquired state!");
Corey Tabakacd52dd92017-04-07 18:03:57 -0700424 return ErrorStatus(EBUSY);
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800425 }
426
427 // Attempt to merge the fences if necessary.
428 if (release_fence) {
429 if (returned_fence_) {
Corey Tabaka3079cb72017-01-19 15:07:26 -0800430 LocalFence merged_fence(sync_merge("bufferhub_merged",
431 returned_fence_.get_fd(),
432 release_fence.get_fd()));
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800433 const int error = errno;
434 if (!merged_fence) {
435 ALOGE("ProducerChannel::OnConsumerRelease: Failed to merge fences: %s",
436 strerror(error));
Corey Tabakacd52dd92017-04-07 18:03:57 -0700437 return ErrorStatus(error);
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800438 }
439 returned_fence_ = std::move(merged_fence);
440 } else {
441 returned_fence_ = std::move(release_fence);
442 }
443 }
444
445 OnConsumerIgnored();
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700446 if (pending_consumers_ == 0) {
447 // Clear the producer bit atomically to transit into released state. This
448 // has to done by BufferHub as it requries synchronization among all
449 // consumers.
450 BufferHubDefs::ModifyBufferState(buffer_state_,
451 BufferHubDefs::kProducerStateBit, 0ULL);
452 ALOGD_IF(TRACE,
453 "ProducerChannel::OnConsumerRelease: releasing last consumer: "
454 "buffer_id=%d state=%" PRIx64 ".",
455 buffer_id(), buffer_state_->load());
456
457 if (orphaned_consumer_bit_mask_) {
458 ALOGW(
459 "ProducerChannel::OnConsumerRelease: orphaned buffer detected "
460 "during the this acquire/release cycle: id=%d orphaned=0x%" PRIx64
461 " queue_index=%" PRIu64 ".",
462 buffer_id(), orphaned_consumer_bit_mask_,
463 metadata_header_->queue_index);
464 orphaned_consumer_bit_mask_ = 0;
465 }
466
467 SignalAvailable();
468 }
469
470 ALOGE_IF(pending_consumers_ &&
471 BufferHubDefs::IsBufferReleased(buffer_state_->load()),
472 "ProducerChannel::OnConsumerRelease: buffer state inconsistent: "
473 "pending_consumers=%d, buffer buffer is in releaed state.",
474 pending_consumers_);
Corey Tabakacd52dd92017-04-07 18:03:57 -0700475 return {};
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800476}
477
478void ProducerChannel::OnConsumerIgnored() {
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700479 if (pending_consumers_ == 0) {
480 ALOGE("ProducerChannel::OnConsumerIgnored: no pending consumer.");
481 return;
482 }
483
484 --pending_consumers_;
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800485 ALOGD_IF(TRACE,
486 "ProducerChannel::OnConsumerIgnored: buffer_id=%d %d consumers left",
487 buffer_id(), pending_consumers_);
488}
489
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700490void ProducerChannel::OnConsumerOrphaned(ConsumerChannel* channel) {
491 // Ignore the orphaned consumer.
492 OnConsumerIgnored();
493
494 const uint64_t consumer_state_bit = channel->consumer_state_bit();
495 ALOGE_IF(orphaned_consumer_bit_mask_ & consumer_state_bit,
496 "ProducerChannel::OnConsumerOrphaned: Consumer "
497 "(consumer_state_bit=%" PRIx64 ") is already orphaned.",
498 consumer_state_bit);
499 orphaned_consumer_bit_mask_ |= consumer_state_bit;
500
501 // Atomically clear the fence state bit as an orphaned consumer will never
502 // signal a release fence. Also clear the buffer state as it won't be released
503 // as well.
504 fence_state_->fetch_and(~consumer_state_bit);
505 BufferHubDefs::ModifyBufferState(buffer_state_, consumer_state_bit, 0ULL);
506
507 ALOGW(
508 "ProducerChannel::OnConsumerOrphaned: detected new orphaned consumer "
509 "buffer_id=%d consumer_state_bit=%" PRIx64 " queue_index=%" PRIu64
510 " buffer_state=%" PRIx64 " fence_state=%" PRIx64 ".",
511 buffer_id(), consumer_state_bit, metadata_header_->queue_index,
512 buffer_state_->load(), fence_state_->load());
513}
514
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800515void ProducerChannel::AddConsumer(ConsumerChannel* channel) {
516 consumer_channels_.push_back(channel);
517}
518
519void ProducerChannel::RemoveConsumer(ConsumerChannel* channel) {
520 consumer_channels_.erase(
521 std::find(consumer_channels_.begin(), consumer_channels_.end(), channel));
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700522 active_consumer_bit_mask_ &= ~channel->consumer_state_bit();
523
524 const uint64_t buffer_state = buffer_state_->load();
525 if (BufferHubDefs::IsBufferPosted(buffer_state) ||
526 BufferHubDefs::IsBufferAcquired(buffer_state)) {
527 // The consumer client is being destoryed without releasing. This could
528 // happen in corner cases when the consumer crashes. Here we mark it
529 // orphaned before remove it from producer.
530 OnConsumerOrphaned(channel);
531 }
532
533 if (BufferHubDefs::IsBufferReleased(buffer_state) ||
534 BufferHubDefs::IsBufferGained(buffer_state)) {
535 // The consumer is being close while it is suppose to signal a release
536 // fence. Signal the dummy fence here.
537 if (fence_state_->load() & channel->consumer_state_bit()) {
538 epoll_event event;
539 event.events = EPOLLIN;
540 event.data.u64 = channel->consumer_state_bit();
541 if (epoll_ctl(release_fence_fd_.Get(), EPOLL_CTL_MOD,
542 dummy_fence_fd_.Get(), &event) < 0) {
543 ALOGE(
544 "ProducerChannel::RemoveConsumer: Failed to modify the shared "
545 "release fence to include the dummy fence: %s",
546 strerror(errno));
547 return;
548 }
549 ALOGW(
550 "ProducerChannel::RemoveConsumer: signal dummy release fence "
551 "buffer_id=%d",
552 buffer_id());
553 eventfd_write(dummy_fence_fd_.Get(), 1);
554 }
555 }
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800556}
557
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800558// Returns true if the given parameters match the underlying buffer parameters.
Corey Tabakacd52dd92017-04-07 18:03:57 -0700559bool ProducerChannel::CheckParameters(uint32_t width, uint32_t height,
Hendrik Wagenaar108e84f2017-05-07 22:19:17 -0700560 uint32_t layer_count, uint32_t format,
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700561 uint64_t usage,
562 size_t user_metadata_size) {
563 return user_metadata_size == user_metadata_size_ &&
564 buffer_.width() == width && buffer_.height() == height &&
565 buffer_.layer_count() == layer_count && buffer_.format() == format &&
566 buffer_.usage() == usage;
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800567}
568
569} // namespace dvr
570} // namespace android