blob: 0b5257d57c7810ba5948ade1b527a94814afde58 [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>
Fan Xu74df4902018-09-20 16:40:51 -070010#include <private/dvr/buffer_channel.h>
Tianyu0c6b7ff2018-10-03 11:30:04 -070011#include <private/dvr/bufferhub_rpc.h>
Fan Xu74df4902018-09-20 16:40:51 -070012#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);
Tianyu0c6b7ff2018-10-03 11:30:04 -070099 fence_state_ = new (&metadata_header_->fence_state) std::atomic<uint64_t>(0);
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700100
101 acquire_fence_fd_.Reset(epoll_create1(EPOLL_CLOEXEC));
102 release_fence_fd_.Reset(epoll_create1(EPOLL_CLOEXEC));
103 if (!acquire_fence_fd_ || !release_fence_fd_) {
104 ALOGE("ProducerChannel::ProducerChannel: Failed to create shared fences.");
Jiwen 'Steve' Cai0728fa92018-04-24 19:03:14 -0700105 return -EIO;
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700106 }
107
108 dummy_fence_fd_.Reset(eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK));
109 if (!dummy_fence_fd_) {
110 ALOGE("ProducerChannel::ProducerChannel: Failed to create dummy fences.");
Jiwen 'Steve' Cai0728fa92018-04-24 19:03:14 -0700111 return EIO;
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700112 }
113
114 epoll_event event;
115 event.events = 0;
116 event.data.u64 = 0ULL;
117 if (epoll_ctl(release_fence_fd_.Get(), EPOLL_CTL_ADD, dummy_fence_fd_.Get(),
118 &event) < 0) {
119 ALOGE(
120 "ProducerChannel::ProducerChannel: Failed to modify the shared "
121 "release fence to include the dummy fence: %s",
122 strerror(errno));
Jiwen 'Steve' Cai0728fa92018-04-24 19:03:14 -0700123 return -EIO;
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700124 }
125
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800126 // Success.
Jiwen 'Steve' Cai0728fa92018-04-24 19:03:14 -0700127 return 0;
128}
129
130std::unique_ptr<ProducerChannel> ProducerChannel::Create(
131 BufferHubService* service, int buffer_id, int channel_id, IonBuffer buffer,
132 IonBuffer metadata_buffer, size_t user_metadata_size) {
133 int error = 0;
134 std::unique_ptr<ProducerChannel> producer(new ProducerChannel(
135 service, buffer_id, channel_id, std::move(buffer),
136 std::move(metadata_buffer), user_metadata_size, &error));
137
138 if (error < 0)
139 return nullptr;
140 else
141 return producer;
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800142}
143
Corey Tabakacd52dd92017-04-07 18:03:57 -0700144Status<std::shared_ptr<ProducerChannel>> ProducerChannel::Create(
145 BufferHubService* service, int channel_id, uint32_t width, uint32_t height,
Hendrik Wagenaar108e84f2017-05-07 22:19:17 -0700146 uint32_t layer_count, uint32_t format, uint64_t usage,
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700147 size_t user_metadata_size) {
Corey Tabakacd52dd92017-04-07 18:03:57 -0700148 int error;
Jiwen 'Steve' Cai0057fdd2017-05-02 11:21:18 -0700149 std::shared_ptr<ProducerChannel> producer(
Hendrik Wagenaar108e84f2017-05-07 22:19:17 -0700150 new ProducerChannel(service, channel_id, width, height, layer_count,
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700151 format, usage, user_metadata_size, &error));
Corey Tabakacd52dd92017-04-07 18:03:57 -0700152 if (error < 0)
153 return ErrorStatus(-error);
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800154 else
Corey Tabakacd52dd92017-04-07 18:03:57 -0700155 return {std::move(producer)};
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800156}
157
158ProducerChannel::~ProducerChannel() {
Corey Tabaka3079cb72017-01-19 15:07:26 -0800159 ALOGD_IF(TRACE,
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700160 "ProducerChannel::~ProducerChannel: channel_id=%d buffer_id=%d "
161 "state=%" PRIx64 ".",
162 channel_id(), buffer_id(), buffer_state_->load());
Jiwen 'Steve' Cai23c1a732018-03-12 12:16:47 -0700163 for (auto consumer : consumer_channels_) {
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800164 consumer->OnProducerClosed();
Jiwen 'Steve' Cai23c1a732018-03-12 12:16:47 -0700165 }
166 Hangup();
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800167}
168
169BufferHubChannel::BufferInfo ProducerChannel::GetBufferInfo() const {
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700170 // Derive the mask of signaled buffers in this producer / consumer set.
171 uint64_t signaled_mask = signaled() ? BufferHubDefs::kProducerStateBit : 0;
172 for (const ConsumerChannel* consumer : consumer_channels_) {
173 signaled_mask |= consumer->signaled() ? consumer->consumer_state_bit() : 0;
174 }
175
Hendrik Wagenaar4d3590f2017-05-06 22:36:04 -0700176 return BufferInfo(buffer_id(), consumer_channels_.size(), buffer_.width(),
Hendrik Wagenaar108e84f2017-05-07 22:19:17 -0700177 buffer_.height(), buffer_.layer_count(), buffer_.format(),
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700178 buffer_.usage(), pending_consumers_, buffer_state_->load(),
Jiwen 'Steve' Cai2f260332018-02-15 18:39:47 -0800179 signaled_mask, metadata_header_->queue_index);
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800180}
181
182void ProducerChannel::HandleImpulse(Message& message) {
183 ATRACE_NAME("ProducerChannel::HandleImpulse");
184 switch (message.GetOp()) {
185 case BufferHubRPC::ProducerGain::Opcode:
186 OnProducerGain(message);
187 break;
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700188 case BufferHubRPC::ProducerPost::Opcode:
189 OnProducerPost(message, {});
190 break;
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800191 }
192}
193
194bool ProducerChannel::HandleMessage(Message& message) {
195 ATRACE_NAME("ProducerChannel::HandleMessage");
196 switch (message.GetOp()) {
197 case BufferHubRPC::GetBuffer::Opcode:
198 DispatchRemoteMethod<BufferHubRPC::GetBuffer>(
199 *this, &ProducerChannel::OnGetBuffer, message);
200 return true;
201
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800202 case BufferHubRPC::NewConsumer::Opcode:
203 DispatchRemoteMethod<BufferHubRPC::NewConsumer>(
204 *this, &ProducerChannel::OnNewConsumer, message);
205 return true;
206
207 case BufferHubRPC::ProducerPost::Opcode:
208 DispatchRemoteMethod<BufferHubRPC::ProducerPost>(
209 *this, &ProducerChannel::OnProducerPost, message);
210 return true;
211
212 case BufferHubRPC::ProducerGain::Opcode:
213 DispatchRemoteMethod<BufferHubRPC::ProducerGain>(
214 *this, &ProducerChannel::OnProducerGain, message);
215 return true;
216
Jiwen 'Steve' Cai23c1a732018-03-12 12:16:47 -0700217 case BufferHubRPC::ProducerBufferDetach::Opcode:
218 DispatchRemoteMethod<BufferHubRPC::ProducerBufferDetach>(
219 *this, &ProducerChannel::OnProducerDetach, message);
220 return true;
221
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800222 default:
223 return false;
224 }
225}
226
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700227BufferDescription<BorrowedHandle> ProducerChannel::GetBuffer(
228 uint64_t buffer_state_bit) {
Jiwen 'Steve' Cai57ae3ee2018-05-03 17:51:52 -0700229 return {buffer_,
230 metadata_buffer_,
231 buffer_id(),
232 channel_id(),
233 buffer_state_bit,
234 acquire_fence_fd_.Borrow(),
235 release_fence_fd_.Borrow()};
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700236}
237
238Status<BufferDescription<BorrowedHandle>> ProducerChannel::OnGetBuffer(
Corey Tabakad53870c2017-07-06 18:04:27 -0700239 Message& /*message*/) {
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800240 ATRACE_NAME("ProducerChannel::OnGetBuffer");
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700241 ALOGD_IF(TRACE, "ProducerChannel::OnGetBuffer: buffer=%d, state=%" PRIx64 ".",
242 buffer_id(), buffer_state_->load());
243 return {GetBuffer(BufferHubDefs::kProducerStateBit)};
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800244}
245
Corey Tabakacd52dd92017-04-07 18:03:57 -0700246Status<RemoteChannelHandle> ProducerChannel::CreateConsumer(Message& message) {
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800247 ATRACE_NAME("ProducerChannel::CreateConsumer");
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700248 ALOGD_IF(TRACE,
249 "ProducerChannel::CreateConsumer: buffer_id=%d, producer_owns=%d",
250 buffer_id(), producer_owns_);
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800251
252 int channel_id;
253 auto status = message.PushChannel(0, nullptr, &channel_id);
254 if (!status) {
255 ALOGE(
Corey Tabakacd52dd92017-04-07 18:03:57 -0700256 "ProducerChannel::CreateConsumer: Failed to push consumer channel: %s",
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800257 status.GetErrorMessage().c_str());
Corey Tabakacd52dd92017-04-07 18:03:57 -0700258 return ErrorStatus(ENOMEM);
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800259 }
260
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700261 // Try find the next consumer state bit which has not been claimed by any
262 // consumer yet.
Jiwen 'Steve' Cai2e06c1c2018-07-30 21:35:32 -0700263 uint64_t consumer_state_bit = BufferHubDefs::FindNextClearedBit(
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700264 active_consumer_bit_mask_ | orphaned_consumer_bit_mask_ |
265 BufferHubDefs::kProducerStateBit);
266 if (consumer_state_bit == 0ULL) {
267 ALOGE(
268 "ProducerChannel::CreateConsumer: reached the maximum mumber of "
269 "consumers per producer: 63.");
270 return ErrorStatus(E2BIG);
271 }
272
273 auto consumer =
274 std::make_shared<ConsumerChannel>(service(), buffer_id(), channel_id,
275 consumer_state_bit, shared_from_this());
Alex Vakulenkof0a7bd02017-03-31 18:06:19 -0700276 const auto channel_status = service()->SetChannel(channel_id, consumer);
277 if (!channel_status) {
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800278 ALOGE(
279 "ProducerChannel::CreateConsumer: failed to set new consumer channel: "
280 "%s",
Alex Vakulenkof0a7bd02017-03-31 18:06:19 -0700281 channel_status.GetErrorMessage().c_str());
Corey Tabakacd52dd92017-04-07 18:03:57 -0700282 return ErrorStatus(ENOMEM);
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800283 }
284
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700285 if (!producer_owns_ &&
286 !BufferHubDefs::IsBufferReleased(buffer_state_->load())) {
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800287 // Signal the new consumer when adding it to a posted producer.
288 if (consumer->OnProducerPosted())
289 pending_consumers_++;
290 }
291
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700292 active_consumer_bit_mask_ |= consumer_state_bit;
Corey Tabakacd52dd92017-04-07 18:03:57 -0700293 return {status.take()};
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800294}
295
Corey Tabakacd52dd92017-04-07 18:03:57 -0700296Status<RemoteChannelHandle> ProducerChannel::OnNewConsumer(Message& message) {
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800297 ATRACE_NAME("ProducerChannel::OnNewConsumer");
298 ALOGD_IF(TRACE, "ProducerChannel::OnNewConsumer: buffer_id=%d", buffer_id());
Corey Tabakacd52dd92017-04-07 18:03:57 -0700299 return CreateConsumer(message);
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800300}
301
Tianyu0c6b7ff2018-10-03 11:30:04 -0700302Status<void> ProducerChannel::OnProducerPost(Message&,
303 LocalFence acquire_fence) {
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800304 ATRACE_NAME("ProducerChannel::OnProducerPost");
305 ALOGD_IF(TRACE, "ProducerChannel::OnProducerPost: buffer_id=%d", buffer_id());
306 if (!producer_owns_) {
307 ALOGE("ProducerChannel::OnProducerPost: Not in gained state!");
Corey Tabakacd52dd92017-04-07 18:03:57 -0700308 return ErrorStatus(EBUSY);
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800309 }
310
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700311 epoll_event event;
312 event.events = 0;
313 event.data.u64 = 0ULL;
314 int ret = epoll_ctl(release_fence_fd_.Get(), EPOLL_CTL_MOD,
315 dummy_fence_fd_.Get(), &event);
316 ALOGE_IF(ret < 0,
Tianyu0c6b7ff2018-10-03 11:30:04 -0700317 "ProducerChannel::OnProducerPost: Failed to modify the shared "
318 "release fence to include the dummy fence: %s",
319 strerror(errno));
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700320
321 eventfd_t dummy_fence_count = 0ULL;
322 if (eventfd_read(dummy_fence_fd_.Get(), &dummy_fence_count) < 0) {
323 const int error = errno;
324 if (error != EAGAIN) {
325 ALOGE(
326 "ProducerChannel::ProducerChannel: Failed to read dummy fence, "
327 "error: %s",
328 strerror(error));
329 return ErrorStatus(error);
330 }
Corey Tabaka8a4e6a92017-04-20 13:42:02 -0700331 }
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800332
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700333 ALOGW_IF(dummy_fence_count > 0,
334 "ProducerChannel::ProducerChannel: %" PRIu64
335 " dummy fence(s) was signaled during last release/gain cycle "
336 "buffer_id=%d.",
337 dummy_fence_count, buffer_id());
338
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800339 post_fence_ = std::move(acquire_fence);
340 producer_owns_ = false;
341
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700342 // Signal any interested consumers. If there are none, the buffer will stay
343 // in posted state until a consumer comes online. This behavior guarantees
344 // that no frame is silently dropped.
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800345 pending_consumers_ = 0;
346 for (auto consumer : consumer_channels_) {
347 if (consumer->OnProducerPosted())
348 pending_consumers_++;
349 }
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800350 ALOGD_IF(TRACE, "ProducerChannel::OnProducerPost: %d pending consumers",
351 pending_consumers_);
352
Corey Tabakacd52dd92017-04-07 18:03:57 -0700353 return {};
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800354}
355
Corey Tabakad53870c2017-07-06 18:04:27 -0700356Status<LocalFence> ProducerChannel::OnProducerGain(Message& /*message*/) {
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800357 ATRACE_NAME("ProducerChannel::OnGain");
358 ALOGD_IF(TRACE, "ProducerChannel::OnGain: buffer_id=%d", buffer_id());
359 if (producer_owns_) {
360 ALOGE("ProducerChanneL::OnGain: Already in gained state: channel=%d",
361 channel_id());
Corey Tabakacd52dd92017-04-07 18:03:57 -0700362 return ErrorStatus(EALREADY);
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800363 }
364
365 // There are still pending consumers, return busy.
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700366 if (pending_consumers_ > 0) {
367 ALOGE(
368 "ProducerChannel::OnGain: Producer (id=%d) is gaining a buffer that "
369 "still has %d pending consumer(s).",
370 buffer_id(), pending_consumers_);
Corey Tabakacd52dd92017-04-07 18:03:57 -0700371 return ErrorStatus(EBUSY);
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700372 }
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800373
374 ClearAvailable();
375 producer_owns_ = true;
Alex Vakulenko052f3ae2017-03-31 09:10:43 -0700376 post_fence_.close();
Corey Tabakacd52dd92017-04-07 18:03:57 -0700377 return {std::move(returned_fence_)};
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800378}
379
Jiwen 'Steve' Cai23c1a732018-03-12 12:16:47 -0700380Status<RemoteChannelHandle> ProducerChannel::OnProducerDetach(
381 Message& message) {
382 ATRACE_NAME("ProducerChannel::OnProducerDetach");
383 ALOGD_IF(TRACE, "ProducerChannel::OnProducerDetach: buffer_id=%d",
384 buffer_id());
385
386 uint64_t buffer_state = buffer_state_->load();
387 if (!BufferHubDefs::IsBufferGained(buffer_state)) {
388 // Can only detach a BufferProducer when it's in gained state.
389 ALOGW(
390 "ProducerChannel::OnProducerDetach: The buffer (id=%d, state=0x%" PRIx64
391 ") is not in gained state.",
392 buffer_id(), buffer_state);
393 return {};
394 }
395
396 int channel_id;
397 auto status = message.PushChannel(0, nullptr, &channel_id);
398 if (!status) {
399 ALOGE(
400 "ProducerChannel::OnProducerDetach: Failed to push detached buffer "
401 "channel: %s",
402 status.GetErrorMessage().c_str());
403 return ErrorStatus(ENOMEM);
404 }
405
406 // Make sure we unlock the buffer.
407 if (int ret = metadata_buffer_.Unlock()) {
408 ALOGE("ProducerChannel::OnProducerDetach: Failed to unlock metadata.");
409 return ErrorStatus(-ret);
410 };
411
Jiwen 'Steve' Cai2e06c1c2018-07-30 21:35:32 -0700412 std::unique_ptr<BufferChannel> channel = BufferChannel::Create(
413 service(), buffer_id(), channel_id, std::move(buffer_),
414 std::move(metadata_buffer_), user_metadata_size_);
Jiwen 'Steve' Caia8049a22018-03-28 15:14:02 -0700415 if (!channel) {
416 ALOGE("ProducerChannel::OnProducerDetach: Invalid buffer.");
417 return ErrorStatus(EINVAL);
418 }
Jiwen 'Steve' Cai23c1a732018-03-12 12:16:47 -0700419
Jiwen 'Steve' Caia8049a22018-03-28 15:14:02 -0700420 const auto channel_status =
421 service()->SetChannel(channel_id, std::move(channel));
Jiwen 'Steve' Cai23c1a732018-03-12 12:16:47 -0700422 if (!channel_status) {
423 // Technically, this should never fail, as we just pushed the channel. Note
424 // that LOG_FATAL will be stripped out in non-debug build.
425 LOG_FATAL(
426 "ProducerChannel::OnProducerDetach: Failed to set new detached buffer "
427 "channel: %s.",
428 channel_status.GetErrorMessage().c_str());
429 }
430
431 return status;
432}
433
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700434Status<LocalFence> ProducerChannel::OnConsumerAcquire(Message& /*message*/) {
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800435 ATRACE_NAME("ProducerChannel::OnConsumerAcquire");
436 ALOGD_IF(TRACE, "ProducerChannel::OnConsumerAcquire: buffer_id=%d",
437 buffer_id());
438 if (producer_owns_) {
439 ALOGE("ProducerChannel::OnConsumerAcquire: Not in posted state!");
Corey Tabakacd52dd92017-04-07 18:03:57 -0700440 return ErrorStatus(EBUSY);
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800441 }
442
443 // Return a borrowed fd to avoid unnecessary duplication of the underlying fd.
444 // Serialization just needs to read the handle.
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700445 return {std::move(post_fence_)};
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800446}
447
Corey Tabakacd52dd92017-04-07 18:03:57 -0700448Status<void> ProducerChannel::OnConsumerRelease(Message&,
449 LocalFence release_fence) {
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800450 ATRACE_NAME("ProducerChannel::OnConsumerRelease");
451 ALOGD_IF(TRACE, "ProducerChannel::OnConsumerRelease: buffer_id=%d",
452 buffer_id());
453 if (producer_owns_) {
454 ALOGE("ProducerChannel::OnConsumerRelease: Not in acquired state!");
Corey Tabakacd52dd92017-04-07 18:03:57 -0700455 return ErrorStatus(EBUSY);
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800456 }
457
458 // Attempt to merge the fences if necessary.
459 if (release_fence) {
460 if (returned_fence_) {
Corey Tabaka3079cb72017-01-19 15:07:26 -0800461 LocalFence merged_fence(sync_merge("bufferhub_merged",
462 returned_fence_.get_fd(),
463 release_fence.get_fd()));
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800464 const int error = errno;
465 if (!merged_fence) {
466 ALOGE("ProducerChannel::OnConsumerRelease: Failed to merge fences: %s",
467 strerror(error));
Corey Tabakacd52dd92017-04-07 18:03:57 -0700468 return ErrorStatus(error);
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800469 }
470 returned_fence_ = std::move(merged_fence);
471 } else {
472 returned_fence_ = std::move(release_fence);
473 }
474 }
475
Tianyu0c6b7ff2018-10-03 11:30:04 -0700476 DecrementPendingConsumers();
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700477 if (pending_consumers_ == 0) {
478 // Clear the producer bit atomically to transit into released state. This
479 // has to done by BufferHub as it requries synchronization among all
480 // consumers.
481 BufferHubDefs::ModifyBufferState(buffer_state_,
482 BufferHubDefs::kProducerStateBit, 0ULL);
483 ALOGD_IF(TRACE,
484 "ProducerChannel::OnConsumerRelease: releasing last consumer: "
485 "buffer_id=%d state=%" PRIx64 ".",
486 buffer_id(), buffer_state_->load());
487
488 if (orphaned_consumer_bit_mask_) {
489 ALOGW(
490 "ProducerChannel::OnConsumerRelease: orphaned buffer detected "
491 "during the this acquire/release cycle: id=%d orphaned=0x%" PRIx64
492 " queue_index=%" PRIu64 ".",
493 buffer_id(), orphaned_consumer_bit_mask_,
494 metadata_header_->queue_index);
495 orphaned_consumer_bit_mask_ = 0;
496 }
497
498 SignalAvailable();
499 }
500
501 ALOGE_IF(pending_consumers_ &&
502 BufferHubDefs::IsBufferReleased(buffer_state_->load()),
503 "ProducerChannel::OnConsumerRelease: buffer state inconsistent: "
504 "pending_consumers=%d, buffer buffer is in releaed state.",
505 pending_consumers_);
Corey Tabakacd52dd92017-04-07 18:03:57 -0700506 return {};
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800507}
508
Tianyu0c6b7ff2018-10-03 11:30:04 -0700509void ProducerChannel::DecrementPendingConsumers() {
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700510 if (pending_consumers_ == 0) {
Tianyu0c6b7ff2018-10-03 11:30:04 -0700511 ALOGE("ProducerChannel::DecrementPendingConsumers: no pending consumer.");
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700512 return;
513 }
514
515 --pending_consumers_;
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800516 ALOGD_IF(TRACE,
Tianyu0c6b7ff2018-10-03 11:30:04 -0700517 "ProducerChannel::DecrementPendingConsumers: buffer_id=%d %d "
518 "consumers left",
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800519 buffer_id(), pending_consumers_);
520}
521
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700522void ProducerChannel::OnConsumerOrphaned(ConsumerChannel* channel) {
523 // Ignore the orphaned consumer.
Tianyu0c6b7ff2018-10-03 11:30:04 -0700524 DecrementPendingConsumers();
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700525
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