blob: 97af660e5dc82e3ecc1220cacddb3858e832783b [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
Jiwen 'Steve' Cai0728fa92018-04-24 19:03:14 -070038ProducerChannel::ProducerChannel(BufferHubService* service, int buffer_id,
39 int channel_id, IonBuffer buffer,
40 IonBuffer metadata_buffer,
41 size_t user_metadata_size, int* error)
42 : BufferHubChannel(service, buffer_id, channel_id, kProducerType),
43 buffer_(std::move(buffer)),
44 metadata_buffer_(std::move(metadata_buffer)),
45 user_metadata_size_(user_metadata_size),
46 metadata_buf_size_(BufferHubDefs::kMetadataHeaderSize +
47 user_metadata_size) {
48 if (!buffer_.IsValid()) {
49 ALOGE("ProducerChannel::ProducerChannel: Invalid buffer.");
50 *error = -EINVAL;
51 return;
52 }
53 if (!metadata_buffer_.IsValid()) {
54 ALOGE("ProducerChannel::ProducerChannel: Invalid metadata buffer.");
55 *error = -EINVAL;
56 return;
57 }
58
59 *error = InitializeBuffer();
60}
61
Alex Vakulenkoe4eec202017-01-27 14:41:04 -080062ProducerChannel::ProducerChannel(BufferHubService* service, int channel_id,
Corey Tabakacd52dd92017-04-07 18:03:57 -070063 uint32_t width, uint32_t height,
Hendrik Wagenaar108e84f2017-05-07 22:19:17 -070064 uint32_t layer_count, uint32_t format,
Corey Tabaka52ea25c2017-09-13 18:02:48 -070065 uint64_t usage, size_t user_metadata_size,
Hendrik Wagenaar108e84f2017-05-07 22:19:17 -070066 int* error)
Alex Vakulenkoe4eec202017-01-27 14:41:04 -080067 : BufferHubChannel(service, channel_id, channel_id, kProducerType),
68 pending_consumers_(0),
Alex Vakulenkoe4eec202017-01-27 14:41:04 -080069 producer_owns_(true),
Corey Tabaka52ea25c2017-09-13 18:02:48 -070070 user_metadata_size_(user_metadata_size),
71 metadata_buf_size_(BufferHubDefs::kMetadataHeaderSize +
72 user_metadata_size) {
73 if (int ret = buffer_.Alloc(width, height, layer_count, format, usage)) {
Hendrik Wagenaar4d3590f2017-05-06 22:36:04 -070074 ALOGE("ProducerChannel::ProducerChannel: Failed to allocate buffer: %s",
75 strerror(-ret));
76 *error = ret;
77 return;
Alex Vakulenkoe4eec202017-01-27 14:41:04 -080078 }
79
Corey Tabaka52ea25c2017-09-13 18:02:48 -070080 if (int ret = metadata_buffer_.Alloc(metadata_buf_size_, /*height=*/1,
81 /*layer_count=*/1,
82 BufferHubDefs::kMetadataFormat,
83 BufferHubDefs::kMetadataUsage)) {
84 ALOGE("ProducerChannel::ProducerChannel: Failed to allocate metadata: %s",
85 strerror(-ret));
86 *error = ret;
87 return;
88 }
89
Jiwen 'Steve' Cai0728fa92018-04-24 19:03:14 -070090 *error = InitializeBuffer();
91}
92
93int ProducerChannel::InitializeBuffer() {
Corey Tabaka52ea25c2017-09-13 18:02:48 -070094 void* metadata_ptr = nullptr;
95 if (int ret = metadata_buffer_.Lock(BufferHubDefs::kMetadataUsage, /*x=*/0,
96 /*y=*/0, metadata_buf_size_,
97 /*height=*/1, &metadata_ptr)) {
98 ALOGE("ProducerChannel::ProducerChannel: Failed to lock metadata.");
Jiwen 'Steve' Cai0728fa92018-04-24 19:03:14 -070099 return ret;
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700100 }
101 metadata_header_ =
102 reinterpret_cast<BufferHubDefs::MetadataHeader*>(metadata_ptr);
103
104 // Using placement new here to reuse shared memory instead of new allocation
105 // and also initialize the value to zero.
106 buffer_state_ =
107 new (&metadata_header_->buffer_state) std::atomic<uint64_t>(0);
108 fence_state_ =
109 new (&metadata_header_->fence_state) std::atomic<uint64_t>(0);
110
111 acquire_fence_fd_.Reset(epoll_create1(EPOLL_CLOEXEC));
112 release_fence_fd_.Reset(epoll_create1(EPOLL_CLOEXEC));
113 if (!acquire_fence_fd_ || !release_fence_fd_) {
114 ALOGE("ProducerChannel::ProducerChannel: Failed to create shared fences.");
Jiwen 'Steve' Cai0728fa92018-04-24 19:03:14 -0700115 return -EIO;
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700116 }
117
118 dummy_fence_fd_.Reset(eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK));
119 if (!dummy_fence_fd_) {
120 ALOGE("ProducerChannel::ProducerChannel: Failed to create dummy fences.");
Jiwen 'Steve' Cai0728fa92018-04-24 19:03:14 -0700121 return EIO;
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700122 }
123
124 epoll_event event;
125 event.events = 0;
126 event.data.u64 = 0ULL;
127 if (epoll_ctl(release_fence_fd_.Get(), EPOLL_CTL_ADD, dummy_fence_fd_.Get(),
128 &event) < 0) {
129 ALOGE(
130 "ProducerChannel::ProducerChannel: Failed to modify the shared "
131 "release fence to include the dummy fence: %s",
132 strerror(errno));
Jiwen 'Steve' Cai0728fa92018-04-24 19:03:14 -0700133 return -EIO;
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700134 }
135
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800136 // Success.
Jiwen 'Steve' Cai0728fa92018-04-24 19:03:14 -0700137 return 0;
138}
139
140std::unique_ptr<ProducerChannel> ProducerChannel::Create(
141 BufferHubService* service, int buffer_id, int channel_id, IonBuffer buffer,
142 IonBuffer metadata_buffer, size_t user_metadata_size) {
143 int error = 0;
144 std::unique_ptr<ProducerChannel> producer(new ProducerChannel(
145 service, buffer_id, channel_id, std::move(buffer),
146 std::move(metadata_buffer), user_metadata_size, &error));
147
148 if (error < 0)
149 return nullptr;
150 else
151 return producer;
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800152}
153
Corey Tabakacd52dd92017-04-07 18:03:57 -0700154Status<std::shared_ptr<ProducerChannel>> ProducerChannel::Create(
155 BufferHubService* service, int channel_id, uint32_t width, uint32_t height,
Hendrik Wagenaar108e84f2017-05-07 22:19:17 -0700156 uint32_t layer_count, uint32_t format, uint64_t usage,
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700157 size_t user_metadata_size) {
Corey Tabakacd52dd92017-04-07 18:03:57 -0700158 int error;
Jiwen 'Steve' Cai0057fdd2017-05-02 11:21:18 -0700159 std::shared_ptr<ProducerChannel> producer(
Hendrik Wagenaar108e84f2017-05-07 22:19:17 -0700160 new ProducerChannel(service, channel_id, width, height, layer_count,
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700161 format, usage, user_metadata_size, &error));
Corey Tabakacd52dd92017-04-07 18:03:57 -0700162 if (error < 0)
163 return ErrorStatus(-error);
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800164 else
Corey Tabakacd52dd92017-04-07 18:03:57 -0700165 return {std::move(producer)};
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800166}
167
168ProducerChannel::~ProducerChannel() {
Corey Tabaka3079cb72017-01-19 15:07:26 -0800169 ALOGD_IF(TRACE,
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700170 "ProducerChannel::~ProducerChannel: channel_id=%d buffer_id=%d "
171 "state=%" PRIx64 ".",
172 channel_id(), buffer_id(), buffer_state_->load());
Jiwen 'Steve' Cai23c1a732018-03-12 12:16:47 -0700173 for (auto consumer : consumer_channels_) {
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800174 consumer->OnProducerClosed();
Jiwen 'Steve' Cai23c1a732018-03-12 12:16:47 -0700175 }
176 Hangup();
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800177}
178
179BufferHubChannel::BufferInfo ProducerChannel::GetBufferInfo() const {
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700180 // Derive the mask of signaled buffers in this producer / consumer set.
181 uint64_t signaled_mask = signaled() ? BufferHubDefs::kProducerStateBit : 0;
182 for (const ConsumerChannel* consumer : consumer_channels_) {
183 signaled_mask |= consumer->signaled() ? consumer->consumer_state_bit() : 0;
184 }
185
Hendrik Wagenaar4d3590f2017-05-06 22:36:04 -0700186 return BufferInfo(buffer_id(), consumer_channels_.size(), buffer_.width(),
Hendrik Wagenaar108e84f2017-05-07 22:19:17 -0700187 buffer_.height(), buffer_.layer_count(), buffer_.format(),
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700188 buffer_.usage(), pending_consumers_, buffer_state_->load(),
Jiwen 'Steve' Cai2f260332018-02-15 18:39:47 -0800189 signaled_mask, metadata_header_->queue_index);
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800190}
191
192void ProducerChannel::HandleImpulse(Message& message) {
193 ATRACE_NAME("ProducerChannel::HandleImpulse");
194 switch (message.GetOp()) {
195 case BufferHubRPC::ProducerGain::Opcode:
196 OnProducerGain(message);
197 break;
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700198 case BufferHubRPC::ProducerPost::Opcode:
199 OnProducerPost(message, {});
200 break;
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800201 }
202}
203
204bool ProducerChannel::HandleMessage(Message& message) {
205 ATRACE_NAME("ProducerChannel::HandleMessage");
206 switch (message.GetOp()) {
207 case BufferHubRPC::GetBuffer::Opcode:
208 DispatchRemoteMethod<BufferHubRPC::GetBuffer>(
209 *this, &ProducerChannel::OnGetBuffer, message);
210 return true;
211
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800212 case BufferHubRPC::NewConsumer::Opcode:
213 DispatchRemoteMethod<BufferHubRPC::NewConsumer>(
214 *this, &ProducerChannel::OnNewConsumer, message);
215 return true;
216
217 case BufferHubRPC::ProducerPost::Opcode:
218 DispatchRemoteMethod<BufferHubRPC::ProducerPost>(
219 *this, &ProducerChannel::OnProducerPost, message);
220 return true;
221
222 case BufferHubRPC::ProducerGain::Opcode:
223 DispatchRemoteMethod<BufferHubRPC::ProducerGain>(
224 *this, &ProducerChannel::OnProducerGain, message);
225 return true;
226
Jiwen 'Steve' Cai23c1a732018-03-12 12:16:47 -0700227 case BufferHubRPC::ProducerBufferDetach::Opcode:
228 DispatchRemoteMethod<BufferHubRPC::ProducerBufferDetach>(
229 *this, &ProducerChannel::OnProducerDetach, message);
230 return true;
231
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800232 default:
233 return false;
234 }
235}
236
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700237BufferDescription<BorrowedHandle> ProducerChannel::GetBuffer(
238 uint64_t buffer_state_bit) {
Jiwen 'Steve' Cai57ae3ee2018-05-03 17:51:52 -0700239 return {buffer_,
240 metadata_buffer_,
241 buffer_id(),
242 channel_id(),
243 buffer_state_bit,
244 acquire_fence_fd_.Borrow(),
245 release_fence_fd_.Borrow()};
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700246}
247
248Status<BufferDescription<BorrowedHandle>> ProducerChannel::OnGetBuffer(
Corey Tabakad53870c2017-07-06 18:04:27 -0700249 Message& /*message*/) {
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800250 ATRACE_NAME("ProducerChannel::OnGetBuffer");
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700251 ALOGD_IF(TRACE, "ProducerChannel::OnGetBuffer: buffer=%d, state=%" PRIx64 ".",
252 buffer_id(), buffer_state_->load());
253 return {GetBuffer(BufferHubDefs::kProducerStateBit)};
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800254}
255
Corey Tabakacd52dd92017-04-07 18:03:57 -0700256Status<RemoteChannelHandle> ProducerChannel::CreateConsumer(Message& message) {
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800257 ATRACE_NAME("ProducerChannel::CreateConsumer");
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700258 ALOGD_IF(TRACE,
259 "ProducerChannel::CreateConsumer: buffer_id=%d, producer_owns=%d",
260 buffer_id(), producer_owns_);
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800261
262 int channel_id;
263 auto status = message.PushChannel(0, nullptr, &channel_id);
264 if (!status) {
265 ALOGE(
Corey Tabakacd52dd92017-04-07 18:03:57 -0700266 "ProducerChannel::CreateConsumer: Failed to push consumer channel: %s",
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800267 status.GetErrorMessage().c_str());
Corey Tabakacd52dd92017-04-07 18:03:57 -0700268 return ErrorStatus(ENOMEM);
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800269 }
270
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700271 // Try find the next consumer state bit which has not been claimed by any
272 // consumer yet.
273 uint64_t consumer_state_bit = FindNextClearedBit(
274 active_consumer_bit_mask_ | orphaned_consumer_bit_mask_ |
275 BufferHubDefs::kProducerStateBit);
276 if (consumer_state_bit == 0ULL) {
277 ALOGE(
278 "ProducerChannel::CreateConsumer: reached the maximum mumber of "
279 "consumers per producer: 63.");
280 return ErrorStatus(E2BIG);
281 }
282
283 auto consumer =
284 std::make_shared<ConsumerChannel>(service(), buffer_id(), channel_id,
285 consumer_state_bit, shared_from_this());
Alex Vakulenkof0a7bd02017-03-31 18:06:19 -0700286 const auto channel_status = service()->SetChannel(channel_id, consumer);
287 if (!channel_status) {
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800288 ALOGE(
289 "ProducerChannel::CreateConsumer: failed to set new consumer channel: "
290 "%s",
Alex Vakulenkof0a7bd02017-03-31 18:06:19 -0700291 channel_status.GetErrorMessage().c_str());
Corey Tabakacd52dd92017-04-07 18:03:57 -0700292 return ErrorStatus(ENOMEM);
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800293 }
294
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700295 if (!producer_owns_ &&
296 !BufferHubDefs::IsBufferReleased(buffer_state_->load())) {
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800297 // Signal the new consumer when adding it to a posted producer.
298 if (consumer->OnProducerPosted())
299 pending_consumers_++;
300 }
301
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700302 active_consumer_bit_mask_ |= consumer_state_bit;
Corey Tabakacd52dd92017-04-07 18:03:57 -0700303 return {status.take()};
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800304}
305
Corey Tabakacd52dd92017-04-07 18:03:57 -0700306Status<RemoteChannelHandle> ProducerChannel::OnNewConsumer(Message& message) {
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800307 ATRACE_NAME("ProducerChannel::OnNewConsumer");
308 ALOGD_IF(TRACE, "ProducerChannel::OnNewConsumer: buffer_id=%d", buffer_id());
Corey Tabakacd52dd92017-04-07 18:03:57 -0700309 return CreateConsumer(message);
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800310}
311
Corey Tabakacd52dd92017-04-07 18:03:57 -0700312Status<void> ProducerChannel::OnProducerPost(
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700313 Message&, LocalFence acquire_fence) {
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800314 ATRACE_NAME("ProducerChannel::OnProducerPost");
315 ALOGD_IF(TRACE, "ProducerChannel::OnProducerPost: buffer_id=%d", buffer_id());
316 if (!producer_owns_) {
317 ALOGE("ProducerChannel::OnProducerPost: Not in gained state!");
Corey Tabakacd52dd92017-04-07 18:03:57 -0700318 return ErrorStatus(EBUSY);
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800319 }
320
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700321 epoll_event event;
322 event.events = 0;
323 event.data.u64 = 0ULL;
324 int ret = epoll_ctl(release_fence_fd_.Get(), EPOLL_CTL_MOD,
325 dummy_fence_fd_.Get(), &event);
326 ALOGE_IF(ret < 0,
327 "ProducerChannel::OnProducerPost: Failed to modify the shared "
328 "release fence to include the dummy fence: %s",
329 strerror(errno));
330
331 eventfd_t dummy_fence_count = 0ULL;
332 if (eventfd_read(dummy_fence_fd_.Get(), &dummy_fence_count) < 0) {
333 const int error = errno;
334 if (error != EAGAIN) {
335 ALOGE(
336 "ProducerChannel::ProducerChannel: Failed to read dummy fence, "
337 "error: %s",
338 strerror(error));
339 return ErrorStatus(error);
340 }
Corey Tabaka8a4e6a92017-04-20 13:42:02 -0700341 }
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800342
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700343 ALOGW_IF(dummy_fence_count > 0,
344 "ProducerChannel::ProducerChannel: %" PRIu64
345 " dummy fence(s) was signaled during last release/gain cycle "
346 "buffer_id=%d.",
347 dummy_fence_count, buffer_id());
348
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800349 post_fence_ = std::move(acquire_fence);
350 producer_owns_ = false;
351
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700352 // Signal any interested consumers. If there are none, the buffer will stay
353 // in posted state until a consumer comes online. This behavior guarantees
354 // that no frame is silently dropped.
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800355 pending_consumers_ = 0;
356 for (auto consumer : consumer_channels_) {
357 if (consumer->OnProducerPosted())
358 pending_consumers_++;
359 }
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800360 ALOGD_IF(TRACE, "ProducerChannel::OnProducerPost: %d pending consumers",
361 pending_consumers_);
362
Corey Tabakacd52dd92017-04-07 18:03:57 -0700363 return {};
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800364}
365
Corey Tabakad53870c2017-07-06 18:04:27 -0700366Status<LocalFence> ProducerChannel::OnProducerGain(Message& /*message*/) {
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800367 ATRACE_NAME("ProducerChannel::OnGain");
368 ALOGD_IF(TRACE, "ProducerChannel::OnGain: buffer_id=%d", buffer_id());
369 if (producer_owns_) {
370 ALOGE("ProducerChanneL::OnGain: Already in gained state: channel=%d",
371 channel_id());
Corey Tabakacd52dd92017-04-07 18:03:57 -0700372 return ErrorStatus(EALREADY);
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800373 }
374
375 // There are still pending consumers, return busy.
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700376 if (pending_consumers_ > 0) {
377 ALOGE(
378 "ProducerChannel::OnGain: Producer (id=%d) is gaining a buffer that "
379 "still has %d pending consumer(s).",
380 buffer_id(), pending_consumers_);
Corey Tabakacd52dd92017-04-07 18:03:57 -0700381 return ErrorStatus(EBUSY);
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700382 }
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800383
384 ClearAvailable();
385 producer_owns_ = true;
Alex Vakulenko052f3ae2017-03-31 09:10:43 -0700386 post_fence_.close();
Corey Tabakacd52dd92017-04-07 18:03:57 -0700387 return {std::move(returned_fence_)};
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800388}
389
Jiwen 'Steve' Cai23c1a732018-03-12 12:16:47 -0700390Status<RemoteChannelHandle> ProducerChannel::OnProducerDetach(
391 Message& message) {
392 ATRACE_NAME("ProducerChannel::OnProducerDetach");
393 ALOGD_IF(TRACE, "ProducerChannel::OnProducerDetach: buffer_id=%d",
394 buffer_id());
395
396 uint64_t buffer_state = buffer_state_->load();
397 if (!BufferHubDefs::IsBufferGained(buffer_state)) {
398 // Can only detach a BufferProducer when it's in gained state.
399 ALOGW(
400 "ProducerChannel::OnProducerDetach: The buffer (id=%d, state=0x%" PRIx64
401 ") is not in gained state.",
402 buffer_id(), buffer_state);
403 return {};
404 }
405
406 int channel_id;
407 auto status = message.PushChannel(0, nullptr, &channel_id);
408 if (!status) {
409 ALOGE(
410 "ProducerChannel::OnProducerDetach: Failed to push detached buffer "
411 "channel: %s",
412 status.GetErrorMessage().c_str());
413 return ErrorStatus(ENOMEM);
414 }
415
416 // Make sure we unlock the buffer.
417 if (int ret = metadata_buffer_.Unlock()) {
418 ALOGE("ProducerChannel::OnProducerDetach: Failed to unlock metadata.");
419 return ErrorStatus(-ret);
420 };
421
Jiwen 'Steve' Caia8049a22018-03-28 15:14:02 -0700422 std::unique_ptr<DetachedBufferChannel> channel =
423 DetachedBufferChannel::Create(
424 service(), buffer_id(), channel_id, std::move(buffer_),
425 std::move(metadata_buffer_), user_metadata_size_);
426 if (!channel) {
427 ALOGE("ProducerChannel::OnProducerDetach: Invalid buffer.");
428 return ErrorStatus(EINVAL);
429 }
Jiwen 'Steve' Cai23c1a732018-03-12 12:16:47 -0700430
Jiwen 'Steve' Caia8049a22018-03-28 15:14:02 -0700431 const auto channel_status =
432 service()->SetChannel(channel_id, std::move(channel));
Jiwen 'Steve' Cai23c1a732018-03-12 12:16:47 -0700433 if (!channel_status) {
434 // Technically, this should never fail, as we just pushed the channel. Note
435 // that LOG_FATAL will be stripped out in non-debug build.
436 LOG_FATAL(
437 "ProducerChannel::OnProducerDetach: Failed to set new detached buffer "
438 "channel: %s.",
439 channel_status.GetErrorMessage().c_str());
440 }
441
442 return status;
443}
444
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700445Status<LocalFence> ProducerChannel::OnConsumerAcquire(Message& /*message*/) {
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800446 ATRACE_NAME("ProducerChannel::OnConsumerAcquire");
447 ALOGD_IF(TRACE, "ProducerChannel::OnConsumerAcquire: buffer_id=%d",
448 buffer_id());
449 if (producer_owns_) {
450 ALOGE("ProducerChannel::OnConsumerAcquire: Not in posted state!");
Corey Tabakacd52dd92017-04-07 18:03:57 -0700451 return ErrorStatus(EBUSY);
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800452 }
453
454 // Return a borrowed fd to avoid unnecessary duplication of the underlying fd.
455 // Serialization just needs to read the handle.
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700456 return {std::move(post_fence_)};
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800457}
458
Corey Tabakacd52dd92017-04-07 18:03:57 -0700459Status<void> ProducerChannel::OnConsumerRelease(Message&,
460 LocalFence release_fence) {
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800461 ATRACE_NAME("ProducerChannel::OnConsumerRelease");
462 ALOGD_IF(TRACE, "ProducerChannel::OnConsumerRelease: buffer_id=%d",
463 buffer_id());
464 if (producer_owns_) {
465 ALOGE("ProducerChannel::OnConsumerRelease: Not in acquired state!");
Corey Tabakacd52dd92017-04-07 18:03:57 -0700466 return ErrorStatus(EBUSY);
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800467 }
468
469 // Attempt to merge the fences if necessary.
470 if (release_fence) {
471 if (returned_fence_) {
Corey Tabaka3079cb72017-01-19 15:07:26 -0800472 LocalFence merged_fence(sync_merge("bufferhub_merged",
473 returned_fence_.get_fd(),
474 release_fence.get_fd()));
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800475 const int error = errno;
476 if (!merged_fence) {
477 ALOGE("ProducerChannel::OnConsumerRelease: Failed to merge fences: %s",
478 strerror(error));
Corey Tabakacd52dd92017-04-07 18:03:57 -0700479 return ErrorStatus(error);
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800480 }
481 returned_fence_ = std::move(merged_fence);
482 } else {
483 returned_fence_ = std::move(release_fence);
484 }
485 }
486
487 OnConsumerIgnored();
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700488 if (pending_consumers_ == 0) {
489 // Clear the producer bit atomically to transit into released state. This
490 // has to done by BufferHub as it requries synchronization among all
491 // consumers.
492 BufferHubDefs::ModifyBufferState(buffer_state_,
493 BufferHubDefs::kProducerStateBit, 0ULL);
494 ALOGD_IF(TRACE,
495 "ProducerChannel::OnConsumerRelease: releasing last consumer: "
496 "buffer_id=%d state=%" PRIx64 ".",
497 buffer_id(), buffer_state_->load());
498
499 if (orphaned_consumer_bit_mask_) {
500 ALOGW(
501 "ProducerChannel::OnConsumerRelease: orphaned buffer detected "
502 "during the this acquire/release cycle: id=%d orphaned=0x%" PRIx64
503 " queue_index=%" PRIu64 ".",
504 buffer_id(), orphaned_consumer_bit_mask_,
505 metadata_header_->queue_index);
506 orphaned_consumer_bit_mask_ = 0;
507 }
508
509 SignalAvailable();
510 }
511
512 ALOGE_IF(pending_consumers_ &&
513 BufferHubDefs::IsBufferReleased(buffer_state_->load()),
514 "ProducerChannel::OnConsumerRelease: buffer state inconsistent: "
515 "pending_consumers=%d, buffer buffer is in releaed state.",
516 pending_consumers_);
Corey Tabakacd52dd92017-04-07 18:03:57 -0700517 return {};
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800518}
519
520void ProducerChannel::OnConsumerIgnored() {
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700521 if (pending_consumers_ == 0) {
522 ALOGE("ProducerChannel::OnConsumerIgnored: no pending consumer.");
523 return;
524 }
525
526 --pending_consumers_;
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800527 ALOGD_IF(TRACE,
528 "ProducerChannel::OnConsumerIgnored: buffer_id=%d %d consumers left",
529 buffer_id(), pending_consumers_);
530}
531
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700532void ProducerChannel::OnConsumerOrphaned(ConsumerChannel* channel) {
533 // Ignore the orphaned consumer.
534 OnConsumerIgnored();
535
536 const uint64_t consumer_state_bit = channel->consumer_state_bit();
537 ALOGE_IF(orphaned_consumer_bit_mask_ & consumer_state_bit,
538 "ProducerChannel::OnConsumerOrphaned: Consumer "
539 "(consumer_state_bit=%" PRIx64 ") is already orphaned.",
540 consumer_state_bit);
541 orphaned_consumer_bit_mask_ |= consumer_state_bit;
542
543 // Atomically clear the fence state bit as an orphaned consumer will never
544 // signal a release fence. Also clear the buffer state as it won't be released
545 // as well.
546 fence_state_->fetch_and(~consumer_state_bit);
547 BufferHubDefs::ModifyBufferState(buffer_state_, consumer_state_bit, 0ULL);
548
549 ALOGW(
550 "ProducerChannel::OnConsumerOrphaned: detected new orphaned consumer "
551 "buffer_id=%d consumer_state_bit=%" PRIx64 " queue_index=%" PRIu64
552 " buffer_state=%" PRIx64 " fence_state=%" PRIx64 ".",
553 buffer_id(), consumer_state_bit, metadata_header_->queue_index,
554 buffer_state_->load(), fence_state_->load());
555}
556
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800557void ProducerChannel::AddConsumer(ConsumerChannel* channel) {
558 consumer_channels_.push_back(channel);
559}
560
561void ProducerChannel::RemoveConsumer(ConsumerChannel* channel) {
562 consumer_channels_.erase(
563 std::find(consumer_channels_.begin(), consumer_channels_.end(), channel));
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700564 active_consumer_bit_mask_ &= ~channel->consumer_state_bit();
565
566 const uint64_t buffer_state = buffer_state_->load();
567 if (BufferHubDefs::IsBufferPosted(buffer_state) ||
568 BufferHubDefs::IsBufferAcquired(buffer_state)) {
569 // The consumer client is being destoryed without releasing. This could
570 // happen in corner cases when the consumer crashes. Here we mark it
571 // orphaned before remove it from producer.
572 OnConsumerOrphaned(channel);
573 }
574
575 if (BufferHubDefs::IsBufferReleased(buffer_state) ||
576 BufferHubDefs::IsBufferGained(buffer_state)) {
577 // The consumer is being close while it is suppose to signal a release
578 // fence. Signal the dummy fence here.
579 if (fence_state_->load() & channel->consumer_state_bit()) {
580 epoll_event event;
581 event.events = EPOLLIN;
582 event.data.u64 = channel->consumer_state_bit();
583 if (epoll_ctl(release_fence_fd_.Get(), EPOLL_CTL_MOD,
584 dummy_fence_fd_.Get(), &event) < 0) {
585 ALOGE(
586 "ProducerChannel::RemoveConsumer: Failed to modify the shared "
587 "release fence to include the dummy fence: %s",
588 strerror(errno));
589 return;
590 }
591 ALOGW(
592 "ProducerChannel::RemoveConsumer: signal dummy release fence "
593 "buffer_id=%d",
594 buffer_id());
595 eventfd_write(dummy_fence_fd_.Get(), 1);
596 }
597 }
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800598}
599
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800600// Returns true if the given parameters match the underlying buffer parameters.
Corey Tabakacd52dd92017-04-07 18:03:57 -0700601bool ProducerChannel::CheckParameters(uint32_t width, uint32_t height,
Hendrik Wagenaar108e84f2017-05-07 22:19:17 -0700602 uint32_t layer_count, uint32_t format,
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700603 uint64_t usage,
604 size_t user_metadata_size) {
605 return user_metadata_size == user_metadata_size_ &&
606 buffer_.width() == width && buffer_.height() == height &&
607 buffer_.layer_count() == layer_count && buffer_.format() == format &&
608 buffer_.usage() == usage;
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800609}
610
611} // namespace dvr
612} // namespace android