blob: 19d48f2b68a0611fa4043c7b85bfd56115e173f5 [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>
Jiwen 'Steve' Cai2e06c1c2018-07-30 21:35:32 -070015#include "buffer_channel.h"
Alex Vakulenkoe4eec202017-01-27 14:41:04 -080016#include "consumer_channel.h"
17
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
Jiwen 'Steve' Cai0728fa92018-04-24 19:03:14 -070030ProducerChannel::ProducerChannel(BufferHubService* service, int buffer_id,
31 int channel_id, IonBuffer buffer,
32 IonBuffer metadata_buffer,
33 size_t user_metadata_size, int* error)
34 : BufferHubChannel(service, buffer_id, channel_id, kProducerType),
35 buffer_(std::move(buffer)),
36 metadata_buffer_(std::move(metadata_buffer)),
37 user_metadata_size_(user_metadata_size),
38 metadata_buf_size_(BufferHubDefs::kMetadataHeaderSize +
39 user_metadata_size) {
40 if (!buffer_.IsValid()) {
41 ALOGE("ProducerChannel::ProducerChannel: Invalid buffer.");
42 *error = -EINVAL;
43 return;
44 }
45 if (!metadata_buffer_.IsValid()) {
46 ALOGE("ProducerChannel::ProducerChannel: Invalid metadata buffer.");
47 *error = -EINVAL;
48 return;
49 }
50
51 *error = InitializeBuffer();
52}
53
Alex Vakulenkoe4eec202017-01-27 14:41:04 -080054ProducerChannel::ProducerChannel(BufferHubService* service, int channel_id,
Corey Tabakacd52dd92017-04-07 18:03:57 -070055 uint32_t width, uint32_t height,
Hendrik Wagenaar108e84f2017-05-07 22:19:17 -070056 uint32_t layer_count, uint32_t format,
Corey Tabaka52ea25c2017-09-13 18:02:48 -070057 uint64_t usage, size_t user_metadata_size,
Hendrik Wagenaar108e84f2017-05-07 22:19:17 -070058 int* error)
Alex Vakulenkoe4eec202017-01-27 14:41:04 -080059 : BufferHubChannel(service, channel_id, channel_id, kProducerType),
60 pending_consumers_(0),
Alex Vakulenkoe4eec202017-01-27 14:41:04 -080061 producer_owns_(true),
Corey Tabaka52ea25c2017-09-13 18:02:48 -070062 user_metadata_size_(user_metadata_size),
63 metadata_buf_size_(BufferHubDefs::kMetadataHeaderSize +
64 user_metadata_size) {
65 if (int ret = buffer_.Alloc(width, height, layer_count, format, usage)) {
Hendrik Wagenaar4d3590f2017-05-06 22:36:04 -070066 ALOGE("ProducerChannel::ProducerChannel: Failed to allocate buffer: %s",
67 strerror(-ret));
68 *error = ret;
69 return;
Alex Vakulenkoe4eec202017-01-27 14:41:04 -080070 }
71
Corey Tabaka52ea25c2017-09-13 18:02:48 -070072 if (int ret = metadata_buffer_.Alloc(metadata_buf_size_, /*height=*/1,
73 /*layer_count=*/1,
74 BufferHubDefs::kMetadataFormat,
75 BufferHubDefs::kMetadataUsage)) {
76 ALOGE("ProducerChannel::ProducerChannel: Failed to allocate metadata: %s",
77 strerror(-ret));
78 *error = ret;
79 return;
80 }
81
Jiwen 'Steve' Cai0728fa92018-04-24 19:03:14 -070082 *error = InitializeBuffer();
83}
84
85int ProducerChannel::InitializeBuffer() {
Corey Tabaka52ea25c2017-09-13 18:02:48 -070086 void* metadata_ptr = nullptr;
87 if (int ret = metadata_buffer_.Lock(BufferHubDefs::kMetadataUsage, /*x=*/0,
88 /*y=*/0, metadata_buf_size_,
89 /*height=*/1, &metadata_ptr)) {
90 ALOGE("ProducerChannel::ProducerChannel: Failed to lock metadata.");
Jiwen 'Steve' Cai0728fa92018-04-24 19:03:14 -070091 return ret;
Corey Tabaka52ea25c2017-09-13 18:02:48 -070092 }
93 metadata_header_ =
94 reinterpret_cast<BufferHubDefs::MetadataHeader*>(metadata_ptr);
95
96 // Using placement new here to reuse shared memory instead of new allocation
97 // and also initialize the value to zero.
98 buffer_state_ =
99 new (&metadata_header_->buffer_state) std::atomic<uint64_t>(0);
100 fence_state_ =
101 new (&metadata_header_->fence_state) std::atomic<uint64_t>(0);
102
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.
Jiwen 'Steve' Cai2e06c1c2018-07-30 21:35:32 -0700265 uint64_t consumer_state_bit = BufferHubDefs::FindNextClearedBit(
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700266 active_consumer_bit_mask_ | orphaned_consumer_bit_mask_ |
267 BufferHubDefs::kProducerStateBit);
268 if (consumer_state_bit == 0ULL) {
269 ALOGE(
270 "ProducerChannel::CreateConsumer: reached the maximum mumber of "
271 "consumers per producer: 63.");
272 return ErrorStatus(E2BIG);
273 }
274
275 auto consumer =
276 std::make_shared<ConsumerChannel>(service(), buffer_id(), channel_id,
277 consumer_state_bit, shared_from_this());
Alex Vakulenkof0a7bd02017-03-31 18:06:19 -0700278 const auto channel_status = service()->SetChannel(channel_id, consumer);
279 if (!channel_status) {
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800280 ALOGE(
281 "ProducerChannel::CreateConsumer: failed to set new consumer channel: "
282 "%s",
Alex Vakulenkof0a7bd02017-03-31 18:06:19 -0700283 channel_status.GetErrorMessage().c_str());
Corey Tabakacd52dd92017-04-07 18:03:57 -0700284 return ErrorStatus(ENOMEM);
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800285 }
286
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700287 if (!producer_owns_ &&
288 !BufferHubDefs::IsBufferReleased(buffer_state_->load())) {
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800289 // Signal the new consumer when adding it to a posted producer.
290 if (consumer->OnProducerPosted())
291 pending_consumers_++;
292 }
293
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700294 active_consumer_bit_mask_ |= consumer_state_bit;
Corey Tabakacd52dd92017-04-07 18:03:57 -0700295 return {status.take()};
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800296}
297
Corey Tabakacd52dd92017-04-07 18:03:57 -0700298Status<RemoteChannelHandle> ProducerChannel::OnNewConsumer(Message& message) {
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800299 ATRACE_NAME("ProducerChannel::OnNewConsumer");
300 ALOGD_IF(TRACE, "ProducerChannel::OnNewConsumer: buffer_id=%d", buffer_id());
Corey Tabakacd52dd92017-04-07 18:03:57 -0700301 return CreateConsumer(message);
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800302}
303
Corey Tabakacd52dd92017-04-07 18:03:57 -0700304Status<void> ProducerChannel::OnProducerPost(
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700305 Message&, LocalFence acquire_fence) {
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800306 ATRACE_NAME("ProducerChannel::OnProducerPost");
307 ALOGD_IF(TRACE, "ProducerChannel::OnProducerPost: buffer_id=%d", buffer_id());
308 if (!producer_owns_) {
309 ALOGE("ProducerChannel::OnProducerPost: Not in gained state!");
Corey Tabakacd52dd92017-04-07 18:03:57 -0700310 return ErrorStatus(EBUSY);
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800311 }
312
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700313 epoll_event event;
314 event.events = 0;
315 event.data.u64 = 0ULL;
316 int ret = epoll_ctl(release_fence_fd_.Get(), EPOLL_CTL_MOD,
317 dummy_fence_fd_.Get(), &event);
318 ALOGE_IF(ret < 0,
319 "ProducerChannel::OnProducerPost: Failed to modify the shared "
320 "release fence to include the dummy fence: %s",
321 strerror(errno));
322
323 eventfd_t dummy_fence_count = 0ULL;
324 if (eventfd_read(dummy_fence_fd_.Get(), &dummy_fence_count) < 0) {
325 const int error = errno;
326 if (error != EAGAIN) {
327 ALOGE(
328 "ProducerChannel::ProducerChannel: Failed to read dummy fence, "
329 "error: %s",
330 strerror(error));
331 return ErrorStatus(error);
332 }
Corey Tabaka8a4e6a92017-04-20 13:42:02 -0700333 }
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800334
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700335 ALOGW_IF(dummy_fence_count > 0,
336 "ProducerChannel::ProducerChannel: %" PRIu64
337 " dummy fence(s) was signaled during last release/gain cycle "
338 "buffer_id=%d.",
339 dummy_fence_count, buffer_id());
340
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800341 post_fence_ = std::move(acquire_fence);
342 producer_owns_ = false;
343
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700344 // Signal any interested consumers. If there are none, the buffer will stay
345 // in posted state until a consumer comes online. This behavior guarantees
346 // that no frame is silently dropped.
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800347 pending_consumers_ = 0;
348 for (auto consumer : consumer_channels_) {
349 if (consumer->OnProducerPosted())
350 pending_consumers_++;
351 }
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800352 ALOGD_IF(TRACE, "ProducerChannel::OnProducerPost: %d pending consumers",
353 pending_consumers_);
354
Corey Tabakacd52dd92017-04-07 18:03:57 -0700355 return {};
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800356}
357
Corey Tabakad53870c2017-07-06 18:04:27 -0700358Status<LocalFence> ProducerChannel::OnProducerGain(Message& /*message*/) {
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800359 ATRACE_NAME("ProducerChannel::OnGain");
360 ALOGD_IF(TRACE, "ProducerChannel::OnGain: buffer_id=%d", buffer_id());
361 if (producer_owns_) {
362 ALOGE("ProducerChanneL::OnGain: Already in gained state: channel=%d",
363 channel_id());
Corey Tabakacd52dd92017-04-07 18:03:57 -0700364 return ErrorStatus(EALREADY);
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800365 }
366
367 // There are still pending consumers, return busy.
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700368 if (pending_consumers_ > 0) {
369 ALOGE(
370 "ProducerChannel::OnGain: Producer (id=%d) is gaining a buffer that "
371 "still has %d pending consumer(s).",
372 buffer_id(), pending_consumers_);
Corey Tabakacd52dd92017-04-07 18:03:57 -0700373 return ErrorStatus(EBUSY);
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700374 }
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800375
376 ClearAvailable();
377 producer_owns_ = true;
Alex Vakulenko052f3ae2017-03-31 09:10:43 -0700378 post_fence_.close();
Corey Tabakacd52dd92017-04-07 18:03:57 -0700379 return {std::move(returned_fence_)};
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800380}
381
Jiwen 'Steve' Cai23c1a732018-03-12 12:16:47 -0700382Status<RemoteChannelHandle> ProducerChannel::OnProducerDetach(
383 Message& message) {
384 ATRACE_NAME("ProducerChannel::OnProducerDetach");
385 ALOGD_IF(TRACE, "ProducerChannel::OnProducerDetach: buffer_id=%d",
386 buffer_id());
387
388 uint64_t buffer_state = buffer_state_->load();
389 if (!BufferHubDefs::IsBufferGained(buffer_state)) {
390 // Can only detach a BufferProducer when it's in gained state.
391 ALOGW(
392 "ProducerChannel::OnProducerDetach: The buffer (id=%d, state=0x%" PRIx64
393 ") is not in gained state.",
394 buffer_id(), buffer_state);
395 return {};
396 }
397
398 int channel_id;
399 auto status = message.PushChannel(0, nullptr, &channel_id);
400 if (!status) {
401 ALOGE(
402 "ProducerChannel::OnProducerDetach: Failed to push detached buffer "
403 "channel: %s",
404 status.GetErrorMessage().c_str());
405 return ErrorStatus(ENOMEM);
406 }
407
408 // Make sure we unlock the buffer.
409 if (int ret = metadata_buffer_.Unlock()) {
410 ALOGE("ProducerChannel::OnProducerDetach: Failed to unlock metadata.");
411 return ErrorStatus(-ret);
412 };
413
Jiwen 'Steve' Cai2e06c1c2018-07-30 21:35:32 -0700414 std::unique_ptr<BufferChannel> channel = BufferChannel::Create(
415 service(), buffer_id(), channel_id, std::move(buffer_),
416 std::move(metadata_buffer_), user_metadata_size_);
Jiwen 'Steve' Caia8049a22018-03-28 15:14:02 -0700417 if (!channel) {
418 ALOGE("ProducerChannel::OnProducerDetach: Invalid buffer.");
419 return ErrorStatus(EINVAL);
420 }
Jiwen 'Steve' Cai23c1a732018-03-12 12:16:47 -0700421
Jiwen 'Steve' Caia8049a22018-03-28 15:14:02 -0700422 const auto channel_status =
423 service()->SetChannel(channel_id, std::move(channel));
Jiwen 'Steve' Cai23c1a732018-03-12 12:16:47 -0700424 if (!channel_status) {
425 // Technically, this should never fail, as we just pushed the channel. Note
426 // that LOG_FATAL will be stripped out in non-debug build.
427 LOG_FATAL(
428 "ProducerChannel::OnProducerDetach: Failed to set new detached buffer "
429 "channel: %s.",
430 channel_status.GetErrorMessage().c_str());
431 }
432
433 return status;
434}
435
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700436Status<LocalFence> ProducerChannel::OnConsumerAcquire(Message& /*message*/) {
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800437 ATRACE_NAME("ProducerChannel::OnConsumerAcquire");
438 ALOGD_IF(TRACE, "ProducerChannel::OnConsumerAcquire: buffer_id=%d",
439 buffer_id());
440 if (producer_owns_) {
441 ALOGE("ProducerChannel::OnConsumerAcquire: Not in posted state!");
Corey Tabakacd52dd92017-04-07 18:03:57 -0700442 return ErrorStatus(EBUSY);
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800443 }
444
445 // Return a borrowed fd to avoid unnecessary duplication of the underlying fd.
446 // Serialization just needs to read the handle.
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700447 return {std::move(post_fence_)};
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800448}
449
Corey Tabakacd52dd92017-04-07 18:03:57 -0700450Status<void> ProducerChannel::OnConsumerRelease(Message&,
451 LocalFence release_fence) {
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800452 ATRACE_NAME("ProducerChannel::OnConsumerRelease");
453 ALOGD_IF(TRACE, "ProducerChannel::OnConsumerRelease: buffer_id=%d",
454 buffer_id());
455 if (producer_owns_) {
456 ALOGE("ProducerChannel::OnConsumerRelease: Not in acquired state!");
Corey Tabakacd52dd92017-04-07 18:03:57 -0700457 return ErrorStatus(EBUSY);
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800458 }
459
460 // Attempt to merge the fences if necessary.
461 if (release_fence) {
462 if (returned_fence_) {
Corey Tabaka3079cb72017-01-19 15:07:26 -0800463 LocalFence merged_fence(sync_merge("bufferhub_merged",
464 returned_fence_.get_fd(),
465 release_fence.get_fd()));
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800466 const int error = errno;
467 if (!merged_fence) {
468 ALOGE("ProducerChannel::OnConsumerRelease: Failed to merge fences: %s",
469 strerror(error));
Corey Tabakacd52dd92017-04-07 18:03:57 -0700470 return ErrorStatus(error);
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800471 }
472 returned_fence_ = std::move(merged_fence);
473 } else {
474 returned_fence_ = std::move(release_fence);
475 }
476 }
477
478 OnConsumerIgnored();
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700479 if (pending_consumers_ == 0) {
480 // Clear the producer bit atomically to transit into released state. This
481 // has to done by BufferHub as it requries synchronization among all
482 // consumers.
483 BufferHubDefs::ModifyBufferState(buffer_state_,
484 BufferHubDefs::kProducerStateBit, 0ULL);
485 ALOGD_IF(TRACE,
486 "ProducerChannel::OnConsumerRelease: releasing last consumer: "
487 "buffer_id=%d state=%" PRIx64 ".",
488 buffer_id(), buffer_state_->load());
489
490 if (orphaned_consumer_bit_mask_) {
491 ALOGW(
492 "ProducerChannel::OnConsumerRelease: orphaned buffer detected "
493 "during the this acquire/release cycle: id=%d orphaned=0x%" PRIx64
494 " queue_index=%" PRIu64 ".",
495 buffer_id(), orphaned_consumer_bit_mask_,
496 metadata_header_->queue_index);
497 orphaned_consumer_bit_mask_ = 0;
498 }
499
500 SignalAvailable();
501 }
502
503 ALOGE_IF(pending_consumers_ &&
504 BufferHubDefs::IsBufferReleased(buffer_state_->load()),
505 "ProducerChannel::OnConsumerRelease: buffer state inconsistent: "
506 "pending_consumers=%d, buffer buffer is in releaed state.",
507 pending_consumers_);
Corey Tabakacd52dd92017-04-07 18:03:57 -0700508 return {};
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800509}
510
511void ProducerChannel::OnConsumerIgnored() {
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700512 if (pending_consumers_ == 0) {
513 ALOGE("ProducerChannel::OnConsumerIgnored: no pending consumer.");
514 return;
515 }
516
517 --pending_consumers_;
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800518 ALOGD_IF(TRACE,
519 "ProducerChannel::OnConsumerIgnored: buffer_id=%d %d consumers left",
520 buffer_id(), pending_consumers_);
521}
522
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700523void ProducerChannel::OnConsumerOrphaned(ConsumerChannel* channel) {
524 // Ignore the orphaned consumer.
525 OnConsumerIgnored();
526
527 const uint64_t consumer_state_bit = channel->consumer_state_bit();
528 ALOGE_IF(orphaned_consumer_bit_mask_ & consumer_state_bit,
529 "ProducerChannel::OnConsumerOrphaned: Consumer "
530 "(consumer_state_bit=%" PRIx64 ") is already orphaned.",
531 consumer_state_bit);
532 orphaned_consumer_bit_mask_ |= consumer_state_bit;
533
534 // Atomically clear the fence state bit as an orphaned consumer will never
535 // signal a release fence. Also clear the buffer state as it won't be released
536 // as well.
537 fence_state_->fetch_and(~consumer_state_bit);
538 BufferHubDefs::ModifyBufferState(buffer_state_, consumer_state_bit, 0ULL);
539
540 ALOGW(
541 "ProducerChannel::OnConsumerOrphaned: detected new orphaned consumer "
542 "buffer_id=%d consumer_state_bit=%" PRIx64 " queue_index=%" PRIu64
543 " buffer_state=%" PRIx64 " fence_state=%" PRIx64 ".",
544 buffer_id(), consumer_state_bit, metadata_header_->queue_index,
545 buffer_state_->load(), fence_state_->load());
546}
547
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800548void ProducerChannel::AddConsumer(ConsumerChannel* channel) {
549 consumer_channels_.push_back(channel);
550}
551
552void ProducerChannel::RemoveConsumer(ConsumerChannel* channel) {
553 consumer_channels_.erase(
554 std::find(consumer_channels_.begin(), consumer_channels_.end(), channel));
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700555 active_consumer_bit_mask_ &= ~channel->consumer_state_bit();
556
557 const uint64_t buffer_state = buffer_state_->load();
558 if (BufferHubDefs::IsBufferPosted(buffer_state) ||
559 BufferHubDefs::IsBufferAcquired(buffer_state)) {
560 // The consumer client is being destoryed without releasing. This could
561 // happen in corner cases when the consumer crashes. Here we mark it
562 // orphaned before remove it from producer.
563 OnConsumerOrphaned(channel);
564 }
565
566 if (BufferHubDefs::IsBufferReleased(buffer_state) ||
567 BufferHubDefs::IsBufferGained(buffer_state)) {
568 // The consumer is being close while it is suppose to signal a release
569 // fence. Signal the dummy fence here.
570 if (fence_state_->load() & channel->consumer_state_bit()) {
571 epoll_event event;
572 event.events = EPOLLIN;
573 event.data.u64 = channel->consumer_state_bit();
574 if (epoll_ctl(release_fence_fd_.Get(), EPOLL_CTL_MOD,
575 dummy_fence_fd_.Get(), &event) < 0) {
576 ALOGE(
577 "ProducerChannel::RemoveConsumer: Failed to modify the shared "
578 "release fence to include the dummy fence: %s",
579 strerror(errno));
580 return;
581 }
582 ALOGW(
583 "ProducerChannel::RemoveConsumer: signal dummy release fence "
584 "buffer_id=%d",
585 buffer_id());
586 eventfd_write(dummy_fence_fd_.Get(), 1);
587 }
588 }
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800589}
590
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800591// Returns true if the given parameters match the underlying buffer parameters.
Corey Tabakacd52dd92017-04-07 18:03:57 -0700592bool ProducerChannel::CheckParameters(uint32_t width, uint32_t height,
Hendrik Wagenaar108e84f2017-05-07 22:19:17 -0700593 uint32_t layer_count, uint32_t format,
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700594 uint64_t usage,
595 size_t user_metadata_size) {
596 return user_metadata_size == user_metadata_size_ &&
597 buffer_.width() == width && buffer_.height() == height &&
598 buffer_.layer_count() == layer_count && buffer_.format() == format &&
599 buffer_.usage() == usage;
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800600}
601
602} // namespace dvr
603} // namespace android