blob: 057d4f486a2a6a4ab53b3760021a7c41ec8f0a89 [file] [log] [blame]
Corey Tabaka52ea25c2017-09-13 18:02:48 -07001#include <sys/epoll.h>
2#include <sys/eventfd.h>
Alex Vakulenkoe4eec202017-01-27 14:41:04 -08003#include <sys/poll.h>
Alex Vakulenkoe4eec202017-01-27 14:41:04 -08004
5#include <algorithm>
6#include <atomic>
7#include <thread>
8
Fan Xu74df4902018-09-20 16:40:51 -07009#include <log/log.h>
Alex Vakulenkoe4eec202017-01-27 14:41:04 -080010#include <private/dvr/bufferhub_rpc.h>
Fan Xu74df4902018-09-20 16:40:51 -070011#include <private/dvr/buffer_channel.h>
12#include <private/dvr/consumer_channel.h>
13#include <private/dvr/producer_channel.h>
14#include <sync/sync.h>
15#include <utils/Trace.h>
Alex Vakulenkoe4eec202017-01-27 14:41:04 -080016
17using android::pdx::BorrowedHandle;
Corey Tabakacd52dd92017-04-07 18:03:57 -070018using android::pdx::ErrorStatus;
Alex Vakulenkoe4eec202017-01-27 14:41:04 -080019using android::pdx::Message;
20using android::pdx::RemoteChannelHandle;
Corey Tabakacd52dd92017-04-07 18:03:57 -070021using android::pdx::Status;
Alex Vakulenkoe4eec202017-01-27 14:41:04 -080022using android::pdx::rpc::BufferWrapper;
23using android::pdx::rpc::DispatchRemoteMethod;
24using android::pdx::rpc::WrapBuffer;
25
26namespace android {
27namespace dvr {
28
Jiwen 'Steve' Cai0728fa92018-04-24 19:03:14 -070029ProducerChannel::ProducerChannel(BufferHubService* service, int buffer_id,
30 int channel_id, IonBuffer buffer,
31 IonBuffer metadata_buffer,
32 size_t user_metadata_size, int* error)
33 : BufferHubChannel(service, buffer_id, channel_id, kProducerType),
34 buffer_(std::move(buffer)),
35 metadata_buffer_(std::move(metadata_buffer)),
36 user_metadata_size_(user_metadata_size),
37 metadata_buf_size_(BufferHubDefs::kMetadataHeaderSize +
38 user_metadata_size) {
39 if (!buffer_.IsValid()) {
40 ALOGE("ProducerChannel::ProducerChannel: Invalid buffer.");
41 *error = -EINVAL;
42 return;
43 }
44 if (!metadata_buffer_.IsValid()) {
45 ALOGE("ProducerChannel::ProducerChannel: Invalid metadata buffer.");
46 *error = -EINVAL;
47 return;
48 }
49
50 *error = InitializeBuffer();
51}
52
Alex Vakulenkoe4eec202017-01-27 14:41:04 -080053ProducerChannel::ProducerChannel(BufferHubService* service, int channel_id,
Corey Tabakacd52dd92017-04-07 18:03:57 -070054 uint32_t width, uint32_t height,
Hendrik Wagenaar108e84f2017-05-07 22:19:17 -070055 uint32_t layer_count, uint32_t format,
Corey Tabaka52ea25c2017-09-13 18:02:48 -070056 uint64_t usage, size_t user_metadata_size,
Hendrik Wagenaar108e84f2017-05-07 22:19:17 -070057 int* error)
Alex Vakulenkoe4eec202017-01-27 14:41:04 -080058 : BufferHubChannel(service, channel_id, channel_id, kProducerType),
59 pending_consumers_(0),
Alex Vakulenkoe4eec202017-01-27 14:41:04 -080060 producer_owns_(true),
Corey Tabaka52ea25c2017-09-13 18:02:48 -070061 user_metadata_size_(user_metadata_size),
62 metadata_buf_size_(BufferHubDefs::kMetadataHeaderSize +
63 user_metadata_size) {
64 if (int ret = buffer_.Alloc(width, height, layer_count, format, usage)) {
Hendrik Wagenaar4d3590f2017-05-06 22:36:04 -070065 ALOGE("ProducerChannel::ProducerChannel: Failed to allocate buffer: %s",
66 strerror(-ret));
67 *error = ret;
68 return;
Alex Vakulenkoe4eec202017-01-27 14:41:04 -080069 }
70
Corey Tabaka52ea25c2017-09-13 18:02:48 -070071 if (int ret = metadata_buffer_.Alloc(metadata_buf_size_, /*height=*/1,
72 /*layer_count=*/1,
73 BufferHubDefs::kMetadataFormat,
74 BufferHubDefs::kMetadataUsage)) {
75 ALOGE("ProducerChannel::ProducerChannel: Failed to allocate metadata: %s",
76 strerror(-ret));
77 *error = ret;
78 return;
79 }
80
Jiwen 'Steve' Cai0728fa92018-04-24 19:03:14 -070081 *error = InitializeBuffer();
82}
83
84int ProducerChannel::InitializeBuffer() {
Corey Tabaka52ea25c2017-09-13 18:02:48 -070085 void* metadata_ptr = nullptr;
86 if (int ret = metadata_buffer_.Lock(BufferHubDefs::kMetadataUsage, /*x=*/0,
87 /*y=*/0, metadata_buf_size_,
88 /*height=*/1, &metadata_ptr)) {
89 ALOGE("ProducerChannel::ProducerChannel: Failed to lock metadata.");
Jiwen 'Steve' Cai0728fa92018-04-24 19:03:14 -070090 return ret;
Corey Tabaka52ea25c2017-09-13 18:02:48 -070091 }
92 metadata_header_ =
93 reinterpret_cast<BufferHubDefs::MetadataHeader*>(metadata_ptr);
94
95 // Using placement new here to reuse shared memory instead of new allocation
96 // and also initialize the value to zero.
97 buffer_state_ =
98 new (&metadata_header_->buffer_state) std::atomic<uint64_t>(0);
99 fence_state_ =
100 new (&metadata_header_->fence_state) std::atomic<uint64_t>(0);
101
102 acquire_fence_fd_.Reset(epoll_create1(EPOLL_CLOEXEC));
103 release_fence_fd_.Reset(epoll_create1(EPOLL_CLOEXEC));
104 if (!acquire_fence_fd_ || !release_fence_fd_) {
105 ALOGE("ProducerChannel::ProducerChannel: Failed to create shared fences.");
Jiwen 'Steve' Cai0728fa92018-04-24 19:03:14 -0700106 return -EIO;
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700107 }
108
109 dummy_fence_fd_.Reset(eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK));
110 if (!dummy_fence_fd_) {
111 ALOGE("ProducerChannel::ProducerChannel: Failed to create dummy fences.");
Jiwen 'Steve' Cai0728fa92018-04-24 19:03:14 -0700112 return EIO;
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700113 }
114
115 epoll_event event;
116 event.events = 0;
117 event.data.u64 = 0ULL;
118 if (epoll_ctl(release_fence_fd_.Get(), EPOLL_CTL_ADD, dummy_fence_fd_.Get(),
119 &event) < 0) {
120 ALOGE(
121 "ProducerChannel::ProducerChannel: Failed to modify the shared "
122 "release fence to include the dummy fence: %s",
123 strerror(errno));
Jiwen 'Steve' Cai0728fa92018-04-24 19:03:14 -0700124 return -EIO;
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700125 }
126
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800127 // Success.
Jiwen 'Steve' Cai0728fa92018-04-24 19:03:14 -0700128 return 0;
129}
130
131std::unique_ptr<ProducerChannel> ProducerChannel::Create(
132 BufferHubService* service, int buffer_id, int channel_id, IonBuffer buffer,
133 IonBuffer metadata_buffer, size_t user_metadata_size) {
134 int error = 0;
135 std::unique_ptr<ProducerChannel> producer(new ProducerChannel(
136 service, buffer_id, channel_id, std::move(buffer),
137 std::move(metadata_buffer), user_metadata_size, &error));
138
139 if (error < 0)
140 return nullptr;
141 else
142 return producer;
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800143}
144
Corey Tabakacd52dd92017-04-07 18:03:57 -0700145Status<std::shared_ptr<ProducerChannel>> ProducerChannel::Create(
146 BufferHubService* service, int channel_id, uint32_t width, uint32_t height,
Hendrik Wagenaar108e84f2017-05-07 22:19:17 -0700147 uint32_t layer_count, uint32_t format, uint64_t usage,
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700148 size_t user_metadata_size) {
Corey Tabakacd52dd92017-04-07 18:03:57 -0700149 int error;
Jiwen 'Steve' Cai0057fdd2017-05-02 11:21:18 -0700150 std::shared_ptr<ProducerChannel> producer(
Hendrik Wagenaar108e84f2017-05-07 22:19:17 -0700151 new ProducerChannel(service, channel_id, width, height, layer_count,
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700152 format, usage, user_metadata_size, &error));
Corey Tabakacd52dd92017-04-07 18:03:57 -0700153 if (error < 0)
154 return ErrorStatus(-error);
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800155 else
Corey Tabakacd52dd92017-04-07 18:03:57 -0700156 return {std::move(producer)};
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800157}
158
159ProducerChannel::~ProducerChannel() {
Corey Tabaka3079cb72017-01-19 15:07:26 -0800160 ALOGD_IF(TRACE,
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700161 "ProducerChannel::~ProducerChannel: channel_id=%d buffer_id=%d "
162 "state=%" PRIx64 ".",
163 channel_id(), buffer_id(), buffer_state_->load());
Jiwen 'Steve' Cai23c1a732018-03-12 12:16:47 -0700164 for (auto consumer : consumer_channels_) {
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800165 consumer->OnProducerClosed();
Jiwen 'Steve' Cai23c1a732018-03-12 12:16:47 -0700166 }
167 Hangup();
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800168}
169
170BufferHubChannel::BufferInfo ProducerChannel::GetBufferInfo() const {
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700171 // Derive the mask of signaled buffers in this producer / consumer set.
172 uint64_t signaled_mask = signaled() ? BufferHubDefs::kProducerStateBit : 0;
173 for (const ConsumerChannel* consumer : consumer_channels_) {
174 signaled_mask |= consumer->signaled() ? consumer->consumer_state_bit() : 0;
175 }
176
Hendrik Wagenaar4d3590f2017-05-06 22:36:04 -0700177 return BufferInfo(buffer_id(), consumer_channels_.size(), buffer_.width(),
Hendrik Wagenaar108e84f2017-05-07 22:19:17 -0700178 buffer_.height(), buffer_.layer_count(), buffer_.format(),
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700179 buffer_.usage(), pending_consumers_, buffer_state_->load(),
Jiwen 'Steve' Cai2f260332018-02-15 18:39:47 -0800180 signaled_mask, metadata_header_->queue_index);
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800181}
182
183void ProducerChannel::HandleImpulse(Message& message) {
184 ATRACE_NAME("ProducerChannel::HandleImpulse");
185 switch (message.GetOp()) {
186 case BufferHubRPC::ProducerGain::Opcode:
187 OnProducerGain(message);
188 break;
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700189 case BufferHubRPC::ProducerPost::Opcode:
190 OnProducerPost(message, {});
191 break;
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800192 }
193}
194
195bool ProducerChannel::HandleMessage(Message& message) {
196 ATRACE_NAME("ProducerChannel::HandleMessage");
197 switch (message.GetOp()) {
198 case BufferHubRPC::GetBuffer::Opcode:
199 DispatchRemoteMethod<BufferHubRPC::GetBuffer>(
200 *this, &ProducerChannel::OnGetBuffer, message);
201 return true;
202
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800203 case BufferHubRPC::NewConsumer::Opcode:
204 DispatchRemoteMethod<BufferHubRPC::NewConsumer>(
205 *this, &ProducerChannel::OnNewConsumer, message);
206 return true;
207
208 case BufferHubRPC::ProducerPost::Opcode:
209 DispatchRemoteMethod<BufferHubRPC::ProducerPost>(
210 *this, &ProducerChannel::OnProducerPost, message);
211 return true;
212
213 case BufferHubRPC::ProducerGain::Opcode:
214 DispatchRemoteMethod<BufferHubRPC::ProducerGain>(
215 *this, &ProducerChannel::OnProducerGain, message);
216 return true;
217
Jiwen 'Steve' Cai23c1a732018-03-12 12:16:47 -0700218 case BufferHubRPC::ProducerBufferDetach::Opcode:
219 DispatchRemoteMethod<BufferHubRPC::ProducerBufferDetach>(
220 *this, &ProducerChannel::OnProducerDetach, message);
221 return true;
222
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800223 default:
224 return false;
225 }
226}
227
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700228BufferDescription<BorrowedHandle> ProducerChannel::GetBuffer(
229 uint64_t buffer_state_bit) {
Jiwen 'Steve' Cai57ae3ee2018-05-03 17:51:52 -0700230 return {buffer_,
231 metadata_buffer_,
232 buffer_id(),
233 channel_id(),
234 buffer_state_bit,
235 acquire_fence_fd_.Borrow(),
236 release_fence_fd_.Borrow()};
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700237}
238
239Status<BufferDescription<BorrowedHandle>> ProducerChannel::OnGetBuffer(
Corey Tabakad53870c2017-07-06 18:04:27 -0700240 Message& /*message*/) {
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800241 ATRACE_NAME("ProducerChannel::OnGetBuffer");
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700242 ALOGD_IF(TRACE, "ProducerChannel::OnGetBuffer: buffer=%d, state=%" PRIx64 ".",
243 buffer_id(), buffer_state_->load());
244 return {GetBuffer(BufferHubDefs::kProducerStateBit)};
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800245}
246
Corey Tabakacd52dd92017-04-07 18:03:57 -0700247Status<RemoteChannelHandle> ProducerChannel::CreateConsumer(Message& message) {
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800248 ATRACE_NAME("ProducerChannel::CreateConsumer");
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700249 ALOGD_IF(TRACE,
250 "ProducerChannel::CreateConsumer: buffer_id=%d, producer_owns=%d",
251 buffer_id(), producer_owns_);
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800252
253 int channel_id;
254 auto status = message.PushChannel(0, nullptr, &channel_id);
255 if (!status) {
256 ALOGE(
Corey Tabakacd52dd92017-04-07 18:03:57 -0700257 "ProducerChannel::CreateConsumer: Failed to push consumer channel: %s",
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800258 status.GetErrorMessage().c_str());
Corey Tabakacd52dd92017-04-07 18:03:57 -0700259 return ErrorStatus(ENOMEM);
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800260 }
261
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700262 // Try find the next consumer state bit which has not been claimed by any
263 // consumer yet.
Jiwen 'Steve' Cai2e06c1c2018-07-30 21:35:32 -0700264 uint64_t consumer_state_bit = BufferHubDefs::FindNextClearedBit(
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700265 active_consumer_bit_mask_ | orphaned_consumer_bit_mask_ |
266 BufferHubDefs::kProducerStateBit);
267 if (consumer_state_bit == 0ULL) {
268 ALOGE(
269 "ProducerChannel::CreateConsumer: reached the maximum mumber of "
270 "consumers per producer: 63.");
271 return ErrorStatus(E2BIG);
272 }
273
274 auto consumer =
275 std::make_shared<ConsumerChannel>(service(), buffer_id(), channel_id,
276 consumer_state_bit, shared_from_this());
Alex Vakulenkof0a7bd02017-03-31 18:06:19 -0700277 const auto channel_status = service()->SetChannel(channel_id, consumer);
278 if (!channel_status) {
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800279 ALOGE(
280 "ProducerChannel::CreateConsumer: failed to set new consumer channel: "
281 "%s",
Alex Vakulenkof0a7bd02017-03-31 18:06:19 -0700282 channel_status.GetErrorMessage().c_str());
Corey Tabakacd52dd92017-04-07 18:03:57 -0700283 return ErrorStatus(ENOMEM);
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800284 }
285
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700286 if (!producer_owns_ &&
287 !BufferHubDefs::IsBufferReleased(buffer_state_->load())) {
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800288 // Signal the new consumer when adding it to a posted producer.
289 if (consumer->OnProducerPosted())
290 pending_consumers_++;
291 }
292
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700293 active_consumer_bit_mask_ |= consumer_state_bit;
Corey Tabakacd52dd92017-04-07 18:03:57 -0700294 return {status.take()};
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800295}
296
Corey Tabakacd52dd92017-04-07 18:03:57 -0700297Status<RemoteChannelHandle> ProducerChannel::OnNewConsumer(Message& message) {
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800298 ATRACE_NAME("ProducerChannel::OnNewConsumer");
299 ALOGD_IF(TRACE, "ProducerChannel::OnNewConsumer: buffer_id=%d", buffer_id());
Corey Tabakacd52dd92017-04-07 18:03:57 -0700300 return CreateConsumer(message);
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800301}
302
Corey Tabakacd52dd92017-04-07 18:03:57 -0700303Status<void> ProducerChannel::OnProducerPost(
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700304 Message&, LocalFence acquire_fence) {
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800305 ATRACE_NAME("ProducerChannel::OnProducerPost");
306 ALOGD_IF(TRACE, "ProducerChannel::OnProducerPost: buffer_id=%d", buffer_id());
307 if (!producer_owns_) {
308 ALOGE("ProducerChannel::OnProducerPost: Not in gained state!");
Corey Tabakacd52dd92017-04-07 18:03:57 -0700309 return ErrorStatus(EBUSY);
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800310 }
311
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700312 epoll_event event;
313 event.events = 0;
314 event.data.u64 = 0ULL;
315 int ret = epoll_ctl(release_fence_fd_.Get(), EPOLL_CTL_MOD,
316 dummy_fence_fd_.Get(), &event);
317 ALOGE_IF(ret < 0,
318 "ProducerChannel::OnProducerPost: Failed to modify the shared "
319 "release fence to include the dummy fence: %s",
320 strerror(errno));
321
322 eventfd_t dummy_fence_count = 0ULL;
323 if (eventfd_read(dummy_fence_fd_.Get(), &dummy_fence_count) < 0) {
324 const int error = errno;
325 if (error != EAGAIN) {
326 ALOGE(
327 "ProducerChannel::ProducerChannel: Failed to read dummy fence, "
328 "error: %s",
329 strerror(error));
330 return ErrorStatus(error);
331 }
Corey Tabaka8a4e6a92017-04-20 13:42:02 -0700332 }
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800333
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700334 ALOGW_IF(dummy_fence_count > 0,
335 "ProducerChannel::ProducerChannel: %" PRIu64
336 " dummy fence(s) was signaled during last release/gain cycle "
337 "buffer_id=%d.",
338 dummy_fence_count, buffer_id());
339
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800340 post_fence_ = std::move(acquire_fence);
341 producer_owns_ = false;
342
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700343 // Signal any interested consumers. If there are none, the buffer will stay
344 // in posted state until a consumer comes online. This behavior guarantees
345 // that no frame is silently dropped.
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800346 pending_consumers_ = 0;
347 for (auto consumer : consumer_channels_) {
348 if (consumer->OnProducerPosted())
349 pending_consumers_++;
350 }
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800351 ALOGD_IF(TRACE, "ProducerChannel::OnProducerPost: %d pending consumers",
352 pending_consumers_);
353
Corey Tabakacd52dd92017-04-07 18:03:57 -0700354 return {};
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800355}
356
Corey Tabakad53870c2017-07-06 18:04:27 -0700357Status<LocalFence> ProducerChannel::OnProducerGain(Message& /*message*/) {
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800358 ATRACE_NAME("ProducerChannel::OnGain");
359 ALOGD_IF(TRACE, "ProducerChannel::OnGain: buffer_id=%d", buffer_id());
360 if (producer_owns_) {
361 ALOGE("ProducerChanneL::OnGain: Already in gained state: channel=%d",
362 channel_id());
Corey Tabakacd52dd92017-04-07 18:03:57 -0700363 return ErrorStatus(EALREADY);
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800364 }
365
366 // There are still pending consumers, return busy.
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700367 if (pending_consumers_ > 0) {
368 ALOGE(
369 "ProducerChannel::OnGain: Producer (id=%d) is gaining a buffer that "
370 "still has %d pending consumer(s).",
371 buffer_id(), pending_consumers_);
Corey Tabakacd52dd92017-04-07 18:03:57 -0700372 return ErrorStatus(EBUSY);
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700373 }
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800374
375 ClearAvailable();
376 producer_owns_ = true;
Alex Vakulenko052f3ae2017-03-31 09:10:43 -0700377 post_fence_.close();
Corey Tabakacd52dd92017-04-07 18:03:57 -0700378 return {std::move(returned_fence_)};
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800379}
380
Jiwen 'Steve' Cai23c1a732018-03-12 12:16:47 -0700381Status<RemoteChannelHandle> ProducerChannel::OnProducerDetach(
382 Message& message) {
383 ATRACE_NAME("ProducerChannel::OnProducerDetach");
384 ALOGD_IF(TRACE, "ProducerChannel::OnProducerDetach: buffer_id=%d",
385 buffer_id());
386
387 uint64_t buffer_state = buffer_state_->load();
388 if (!BufferHubDefs::IsBufferGained(buffer_state)) {
389 // Can only detach a BufferProducer when it's in gained state.
390 ALOGW(
391 "ProducerChannel::OnProducerDetach: The buffer (id=%d, state=0x%" PRIx64
392 ") is not in gained state.",
393 buffer_id(), buffer_state);
394 return {};
395 }
396
397 int channel_id;
398 auto status = message.PushChannel(0, nullptr, &channel_id);
399 if (!status) {
400 ALOGE(
401 "ProducerChannel::OnProducerDetach: Failed to push detached buffer "
402 "channel: %s",
403 status.GetErrorMessage().c_str());
404 return ErrorStatus(ENOMEM);
405 }
406
407 // Make sure we unlock the buffer.
408 if (int ret = metadata_buffer_.Unlock()) {
409 ALOGE("ProducerChannel::OnProducerDetach: Failed to unlock metadata.");
410 return ErrorStatus(-ret);
411 };
412
Jiwen 'Steve' Cai2e06c1c2018-07-30 21:35:32 -0700413 std::unique_ptr<BufferChannel> channel = BufferChannel::Create(
414 service(), buffer_id(), channel_id, std::move(buffer_),
415 std::move(metadata_buffer_), user_metadata_size_);
Jiwen 'Steve' Caia8049a22018-03-28 15:14:02 -0700416 if (!channel) {
417 ALOGE("ProducerChannel::OnProducerDetach: Invalid buffer.");
418 return ErrorStatus(EINVAL);
419 }
Jiwen 'Steve' Cai23c1a732018-03-12 12:16:47 -0700420
Jiwen 'Steve' Caia8049a22018-03-28 15:14:02 -0700421 const auto channel_status =
422 service()->SetChannel(channel_id, std::move(channel));
Jiwen 'Steve' Cai23c1a732018-03-12 12:16:47 -0700423 if (!channel_status) {
424 // Technically, this should never fail, as we just pushed the channel. Note
425 // that LOG_FATAL will be stripped out in non-debug build.
426 LOG_FATAL(
427 "ProducerChannel::OnProducerDetach: Failed to set new detached buffer "
428 "channel: %s.",
429 channel_status.GetErrorMessage().c_str());
430 }
431
432 return status;
433}
434
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700435Status<LocalFence> ProducerChannel::OnConsumerAcquire(Message& /*message*/) {
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800436 ATRACE_NAME("ProducerChannel::OnConsumerAcquire");
437 ALOGD_IF(TRACE, "ProducerChannel::OnConsumerAcquire: buffer_id=%d",
438 buffer_id());
439 if (producer_owns_) {
440 ALOGE("ProducerChannel::OnConsumerAcquire: Not in posted state!");
Corey Tabakacd52dd92017-04-07 18:03:57 -0700441 return ErrorStatus(EBUSY);
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800442 }
443
444 // Return a borrowed fd to avoid unnecessary duplication of the underlying fd.
445 // Serialization just needs to read the handle.
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700446 return {std::move(post_fence_)};
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800447}
448
Corey Tabakacd52dd92017-04-07 18:03:57 -0700449Status<void> ProducerChannel::OnConsumerRelease(Message&,
450 LocalFence release_fence) {
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800451 ATRACE_NAME("ProducerChannel::OnConsumerRelease");
452 ALOGD_IF(TRACE, "ProducerChannel::OnConsumerRelease: buffer_id=%d",
453 buffer_id());
454 if (producer_owns_) {
455 ALOGE("ProducerChannel::OnConsumerRelease: Not in acquired state!");
Corey Tabakacd52dd92017-04-07 18:03:57 -0700456 return ErrorStatus(EBUSY);
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800457 }
458
459 // Attempt to merge the fences if necessary.
460 if (release_fence) {
461 if (returned_fence_) {
Corey Tabaka3079cb72017-01-19 15:07:26 -0800462 LocalFence merged_fence(sync_merge("bufferhub_merged",
463 returned_fence_.get_fd(),
464 release_fence.get_fd()));
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800465 const int error = errno;
466 if (!merged_fence) {
467 ALOGE("ProducerChannel::OnConsumerRelease: Failed to merge fences: %s",
468 strerror(error));
Corey Tabakacd52dd92017-04-07 18:03:57 -0700469 return ErrorStatus(error);
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800470 }
471 returned_fence_ = std::move(merged_fence);
472 } else {
473 returned_fence_ = std::move(release_fence);
474 }
475 }
476
477 OnConsumerIgnored();
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700478 if (pending_consumers_ == 0) {
479 // Clear the producer bit atomically to transit into released state. This
480 // has to done by BufferHub as it requries synchronization among all
481 // consumers.
482 BufferHubDefs::ModifyBufferState(buffer_state_,
483 BufferHubDefs::kProducerStateBit, 0ULL);
484 ALOGD_IF(TRACE,
485 "ProducerChannel::OnConsumerRelease: releasing last consumer: "
486 "buffer_id=%d state=%" PRIx64 ".",
487 buffer_id(), buffer_state_->load());
488
489 if (orphaned_consumer_bit_mask_) {
490 ALOGW(
491 "ProducerChannel::OnConsumerRelease: orphaned buffer detected "
492 "during the this acquire/release cycle: id=%d orphaned=0x%" PRIx64
493 " queue_index=%" PRIu64 ".",
494 buffer_id(), orphaned_consumer_bit_mask_,
495 metadata_header_->queue_index);
496 orphaned_consumer_bit_mask_ = 0;
497 }
498
499 SignalAvailable();
500 }
501
502 ALOGE_IF(pending_consumers_ &&
503 BufferHubDefs::IsBufferReleased(buffer_state_->load()),
504 "ProducerChannel::OnConsumerRelease: buffer state inconsistent: "
505 "pending_consumers=%d, buffer buffer is in releaed state.",
506 pending_consumers_);
Corey Tabakacd52dd92017-04-07 18:03:57 -0700507 return {};
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800508}
509
510void ProducerChannel::OnConsumerIgnored() {
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700511 if (pending_consumers_ == 0) {
512 ALOGE("ProducerChannel::OnConsumerIgnored: no pending consumer.");
513 return;
514 }
515
516 --pending_consumers_;
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800517 ALOGD_IF(TRACE,
518 "ProducerChannel::OnConsumerIgnored: buffer_id=%d %d consumers left",
519 buffer_id(), pending_consumers_);
520}
521
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700522void ProducerChannel::OnConsumerOrphaned(ConsumerChannel* channel) {
523 // Ignore the orphaned consumer.
524 OnConsumerIgnored();
525
526 const uint64_t consumer_state_bit = channel->consumer_state_bit();
527 ALOGE_IF(orphaned_consumer_bit_mask_ & consumer_state_bit,
528 "ProducerChannel::OnConsumerOrphaned: Consumer "
529 "(consumer_state_bit=%" PRIx64 ") is already orphaned.",
530 consumer_state_bit);
531 orphaned_consumer_bit_mask_ |= consumer_state_bit;
532
533 // Atomically clear the fence state bit as an orphaned consumer will never
534 // signal a release fence. Also clear the buffer state as it won't be released
535 // as well.
536 fence_state_->fetch_and(~consumer_state_bit);
537 BufferHubDefs::ModifyBufferState(buffer_state_, consumer_state_bit, 0ULL);
538
539 ALOGW(
540 "ProducerChannel::OnConsumerOrphaned: detected new orphaned consumer "
541 "buffer_id=%d consumer_state_bit=%" PRIx64 " queue_index=%" PRIu64
542 " buffer_state=%" PRIx64 " fence_state=%" PRIx64 ".",
543 buffer_id(), consumer_state_bit, metadata_header_->queue_index,
544 buffer_state_->load(), fence_state_->load());
545}
546
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800547void ProducerChannel::AddConsumer(ConsumerChannel* channel) {
548 consumer_channels_.push_back(channel);
549}
550
551void ProducerChannel::RemoveConsumer(ConsumerChannel* channel) {
552 consumer_channels_.erase(
553 std::find(consumer_channels_.begin(), consumer_channels_.end(), channel));
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700554 active_consumer_bit_mask_ &= ~channel->consumer_state_bit();
555
556 const uint64_t buffer_state = buffer_state_->load();
557 if (BufferHubDefs::IsBufferPosted(buffer_state) ||
558 BufferHubDefs::IsBufferAcquired(buffer_state)) {
559 // The consumer client is being destoryed without releasing. This could
560 // happen in corner cases when the consumer crashes. Here we mark it
561 // orphaned before remove it from producer.
562 OnConsumerOrphaned(channel);
563 }
564
565 if (BufferHubDefs::IsBufferReleased(buffer_state) ||
566 BufferHubDefs::IsBufferGained(buffer_state)) {
567 // The consumer is being close while it is suppose to signal a release
568 // fence. Signal the dummy fence here.
569 if (fence_state_->load() & channel->consumer_state_bit()) {
570 epoll_event event;
571 event.events = EPOLLIN;
572 event.data.u64 = channel->consumer_state_bit();
573 if (epoll_ctl(release_fence_fd_.Get(), EPOLL_CTL_MOD,
574 dummy_fence_fd_.Get(), &event) < 0) {
575 ALOGE(
576 "ProducerChannel::RemoveConsumer: Failed to modify the shared "
577 "release fence to include the dummy fence: %s",
578 strerror(errno));
579 return;
580 }
581 ALOGW(
582 "ProducerChannel::RemoveConsumer: signal dummy release fence "
583 "buffer_id=%d",
584 buffer_id());
585 eventfd_write(dummy_fence_fd_.Get(), 1);
586 }
587 }
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800588}
589
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800590// Returns true if the given parameters match the underlying buffer parameters.
Corey Tabakacd52dd92017-04-07 18:03:57 -0700591bool ProducerChannel::CheckParameters(uint32_t width, uint32_t height,
Hendrik Wagenaar108e84f2017-05-07 22:19:17 -0700592 uint32_t layer_count, uint32_t format,
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700593 uint64_t usage,
594 size_t user_metadata_size) {
595 return user_metadata_size == user_metadata_size_ &&
596 buffer_.width() == width && buffer_.height() == height &&
597 buffer_.layer_count() == layer_count && buffer_.format() == format &&
598 buffer_.usage() == usage;
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800599}
600
601} // namespace dvr
602} // namespace android