blob: 162065bb80c64db89d36ab10b09325a946dcb155 [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);
Tianyu67053492018-10-04 14:00:22 -0700100 active_clients_bit_mask_ =
101 new (&metadata_header_->active_clients_bit_mask) std::atomic<uint64_t>(0);
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700102
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 ".",
Tianyu Jiange2cdec92018-10-30 17:40:58 -0700164 channel_id(), buffer_id(),
165 buffer_state_->load(std::memory_order_acquire));
Jiwen 'Steve' Cai23c1a732018-03-12 12:16:47 -0700166 for (auto consumer : consumer_channels_) {
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800167 consumer->OnProducerClosed();
Jiwen 'Steve' Cai23c1a732018-03-12 12:16:47 -0700168 }
169 Hangup();
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800170}
171
172BufferHubChannel::BufferInfo ProducerChannel::GetBufferInfo() const {
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700173 // Derive the mask of signaled buffers in this producer / consumer set.
174 uint64_t signaled_mask = signaled() ? BufferHubDefs::kProducerStateBit : 0;
175 for (const ConsumerChannel* consumer : consumer_channels_) {
Tianyu Jiang83a991f2018-10-30 16:59:29 -0700176 signaled_mask |= consumer->signaled() ? consumer->client_state_mask() : 0;
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700177 }
178
Hendrik Wagenaar4d3590f2017-05-06 22:36:04 -0700179 return BufferInfo(buffer_id(), consumer_channels_.size(), buffer_.width(),
Hendrik Wagenaar108e84f2017-05-07 22:19:17 -0700180 buffer_.height(), buffer_.layer_count(), buffer_.format(),
Tianyu Jiange2cdec92018-10-30 17:40:58 -0700181 buffer_.usage(), pending_consumers_,
182 buffer_state_->load(std::memory_order_acquire),
Jiwen 'Steve' Cai2f260332018-02-15 18:39:47 -0800183 signaled_mask, metadata_header_->queue_index);
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800184}
185
186void ProducerChannel::HandleImpulse(Message& message) {
187 ATRACE_NAME("ProducerChannel::HandleImpulse");
188 switch (message.GetOp()) {
189 case BufferHubRPC::ProducerGain::Opcode:
190 OnProducerGain(message);
191 break;
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700192 case BufferHubRPC::ProducerPost::Opcode:
193 OnProducerPost(message, {});
194 break;
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800195 }
196}
197
198bool ProducerChannel::HandleMessage(Message& message) {
199 ATRACE_NAME("ProducerChannel::HandleMessage");
200 switch (message.GetOp()) {
201 case BufferHubRPC::GetBuffer::Opcode:
202 DispatchRemoteMethod<BufferHubRPC::GetBuffer>(
203 *this, &ProducerChannel::OnGetBuffer, message);
204 return true;
205
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800206 case BufferHubRPC::NewConsumer::Opcode:
207 DispatchRemoteMethod<BufferHubRPC::NewConsumer>(
208 *this, &ProducerChannel::OnNewConsumer, message);
209 return true;
210
211 case BufferHubRPC::ProducerPost::Opcode:
212 DispatchRemoteMethod<BufferHubRPC::ProducerPost>(
213 *this, &ProducerChannel::OnProducerPost, message);
214 return true;
215
216 case BufferHubRPC::ProducerGain::Opcode:
217 DispatchRemoteMethod<BufferHubRPC::ProducerGain>(
218 *this, &ProducerChannel::OnProducerGain, message);
219 return true;
220
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800221 default:
222 return false;
223 }
224}
225
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700226BufferDescription<BorrowedHandle> ProducerChannel::GetBuffer(
Tianyu Jiang7e204b72018-10-26 15:39:18 -0700227 uint64_t client_state_mask) {
Jiwen 'Steve' Cai57ae3ee2018-05-03 17:51:52 -0700228 return {buffer_,
229 metadata_buffer_,
230 buffer_id(),
231 channel_id(),
Tianyu Jiang7e204b72018-10-26 15:39:18 -0700232 client_state_mask,
Jiwen 'Steve' Cai57ae3ee2018-05-03 17:51:52 -0700233 acquire_fence_fd_.Borrow(),
234 release_fence_fd_.Borrow()};
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700235}
236
237Status<BufferDescription<BorrowedHandle>> ProducerChannel::OnGetBuffer(
Corey Tabakad53870c2017-07-06 18:04:27 -0700238 Message& /*message*/) {
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800239 ATRACE_NAME("ProducerChannel::OnGetBuffer");
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700240 ALOGD_IF(TRACE, "ProducerChannel::OnGetBuffer: buffer=%d, state=%" PRIx64 ".",
Tianyu Jiange2cdec92018-10-30 17:40:58 -0700241 buffer_id(), buffer_state_->load(std::memory_order_acquire));
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700242 return {GetBuffer(BufferHubDefs::kProducerStateBit)};
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800243}
244
Corey Tabakacd52dd92017-04-07 18:03:57 -0700245Status<RemoteChannelHandle> ProducerChannel::CreateConsumer(Message& message) {
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800246 ATRACE_NAME("ProducerChannel::CreateConsumer");
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700247 ALOGD_IF(TRACE,
248 "ProducerChannel::CreateConsumer: buffer_id=%d, producer_owns=%d",
249 buffer_id(), producer_owns_);
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800250
251 int channel_id;
252 auto status = message.PushChannel(0, nullptr, &channel_id);
253 if (!status) {
254 ALOGE(
Corey Tabakacd52dd92017-04-07 18:03:57 -0700255 "ProducerChannel::CreateConsumer: Failed to push consumer channel: %s",
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800256 status.GetErrorMessage().c_str());
Corey Tabakacd52dd92017-04-07 18:03:57 -0700257 return ErrorStatus(ENOMEM);
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800258 }
259
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700260 // Try find the next consumer state bit which has not been claimed by any
261 // consumer yet.
Tianyu67053492018-10-04 14:00:22 -0700262 // memory_order_acquire is chosen here because all writes in other threads
263 // that release active_clients_bit_mask_ need to be visible here.
264 uint64_t current_active_clients_bit_mask =
265 active_clients_bit_mask_->load(std::memory_order_acquire);
Tianyu Jiang83a991f2018-10-30 16:59:29 -0700266 uint64_t client_state_mask = BufferHubDefs::FindNextAvailableClientStateMask(
Tianyu67053492018-10-04 14:00:22 -0700267 current_active_clients_bit_mask | orphaned_consumer_bit_mask_ |
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700268 BufferHubDefs::kProducerStateBit);
Tianyu Jiang83a991f2018-10-30 16:59:29 -0700269 if (client_state_mask == 0ULL) {
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700270 ALOGE(
271 "ProducerChannel::CreateConsumer: reached the maximum mumber of "
272 "consumers per producer: 63.");
273 return ErrorStatus(E2BIG);
274 }
275
Tianyu67053492018-10-04 14:00:22 -0700276 uint64_t updated_active_clients_bit_mask =
Tianyu Jiang83a991f2018-10-30 16:59:29 -0700277 current_active_clients_bit_mask | client_state_mask;
Tianyu67053492018-10-04 14:00:22 -0700278 // Set the updated value only if the current value stays the same as what was
279 // read before. If the comparison succeeds, update the value without
280 // reordering anything before or after this read-modify-write in the current
281 // thread, and the modification will be visible in other threads that acquire
282 // active_clients_bit_mask_. If the comparison fails, load the result of
283 // all writes from all threads to updated_active_clients_bit_mask.
284 if (!active_clients_bit_mask_->compare_exchange_weak(
285 current_active_clients_bit_mask, updated_active_clients_bit_mask,
286 std::memory_order_acq_rel, std::memory_order_acquire)) {
287 ALOGE("Current active clients bit mask is changed to %" PRIu64
288 ", which was expected to be %" PRIu64 ".",
289 updated_active_clients_bit_mask, current_active_clients_bit_mask);
290 return ErrorStatus(EBUSY);
291 }
292
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700293 auto consumer =
294 std::make_shared<ConsumerChannel>(service(), buffer_id(), channel_id,
Tianyu Jiang83a991f2018-10-30 16:59:29 -0700295 client_state_mask, shared_from_this());
Alex Vakulenkof0a7bd02017-03-31 18:06:19 -0700296 const auto channel_status = service()->SetChannel(channel_id, consumer);
297 if (!channel_status) {
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800298 ALOGE(
299 "ProducerChannel::CreateConsumer: failed to set new consumer channel: "
300 "%s",
Alex Vakulenkof0a7bd02017-03-31 18:06:19 -0700301 channel_status.GetErrorMessage().c_str());
Tianyu67053492018-10-04 14:00:22 -0700302 // Restore the consumer state bit and make it visible in other threads that
303 // acquire the active_clients_bit_mask_.
Tianyu Jiang83a991f2018-10-30 16:59:29 -0700304 active_clients_bit_mask_->fetch_and(~client_state_mask,
Tianyu67053492018-10-04 14:00:22 -0700305 std::memory_order_release);
Corey Tabakacd52dd92017-04-07 18:03:57 -0700306 return ErrorStatus(ENOMEM);
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800307 }
308
Tianyu Jiange2cdec92018-10-30 17:40:58 -0700309 if (!producer_owns_ && !BufferHubDefs::IsBufferReleased(
310 buffer_state_->load(std::memory_order_acquire))) {
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800311 // Signal the new consumer when adding it to a posted producer.
312 if (consumer->OnProducerPosted())
313 pending_consumers_++;
314 }
315
Corey Tabakacd52dd92017-04-07 18:03:57 -0700316 return {status.take()};
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800317}
318
Corey Tabakacd52dd92017-04-07 18:03:57 -0700319Status<RemoteChannelHandle> ProducerChannel::OnNewConsumer(Message& message) {
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800320 ATRACE_NAME("ProducerChannel::OnNewConsumer");
321 ALOGD_IF(TRACE, "ProducerChannel::OnNewConsumer: buffer_id=%d", buffer_id());
Corey Tabakacd52dd92017-04-07 18:03:57 -0700322 return CreateConsumer(message);
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800323}
324
Tianyu0c6b7ff2018-10-03 11:30:04 -0700325Status<void> ProducerChannel::OnProducerPost(Message&,
326 LocalFence acquire_fence) {
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800327 ATRACE_NAME("ProducerChannel::OnProducerPost");
328 ALOGD_IF(TRACE, "ProducerChannel::OnProducerPost: buffer_id=%d", buffer_id());
329 if (!producer_owns_) {
330 ALOGE("ProducerChannel::OnProducerPost: Not in gained state!");
Corey Tabakacd52dd92017-04-07 18:03:57 -0700331 return ErrorStatus(EBUSY);
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800332 }
333
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700334 epoll_event event;
335 event.events = 0;
336 event.data.u64 = 0ULL;
337 int ret = epoll_ctl(release_fence_fd_.Get(), EPOLL_CTL_MOD,
338 dummy_fence_fd_.Get(), &event);
339 ALOGE_IF(ret < 0,
Tianyu0c6b7ff2018-10-03 11:30:04 -0700340 "ProducerChannel::OnProducerPost: Failed to modify the shared "
341 "release fence to include the dummy fence: %s",
342 strerror(errno));
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700343
344 eventfd_t dummy_fence_count = 0ULL;
345 if (eventfd_read(dummy_fence_fd_.Get(), &dummy_fence_count) < 0) {
346 const int error = errno;
347 if (error != EAGAIN) {
348 ALOGE(
349 "ProducerChannel::ProducerChannel: Failed to read dummy fence, "
350 "error: %s",
351 strerror(error));
352 return ErrorStatus(error);
353 }
Corey Tabaka8a4e6a92017-04-20 13:42:02 -0700354 }
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800355
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700356 ALOGW_IF(dummy_fence_count > 0,
357 "ProducerChannel::ProducerChannel: %" PRIu64
358 " dummy fence(s) was signaled during last release/gain cycle "
359 "buffer_id=%d.",
360 dummy_fence_count, buffer_id());
361
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800362 post_fence_ = std::move(acquire_fence);
363 producer_owns_ = false;
364
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700365 // Signal any interested consumers. If there are none, the buffer will stay
366 // in posted state until a consumer comes online. This behavior guarantees
367 // that no frame is silently dropped.
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800368 pending_consumers_ = 0;
369 for (auto consumer : consumer_channels_) {
370 if (consumer->OnProducerPosted())
371 pending_consumers_++;
372 }
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800373 ALOGD_IF(TRACE, "ProducerChannel::OnProducerPost: %d pending consumers",
374 pending_consumers_);
375
Corey Tabakacd52dd92017-04-07 18:03:57 -0700376 return {};
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800377}
378
Corey Tabakad53870c2017-07-06 18:04:27 -0700379Status<LocalFence> ProducerChannel::OnProducerGain(Message& /*message*/) {
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800380 ATRACE_NAME("ProducerChannel::OnGain");
381 ALOGD_IF(TRACE, "ProducerChannel::OnGain: buffer_id=%d", buffer_id());
382 if (producer_owns_) {
383 ALOGE("ProducerChanneL::OnGain: Already in gained state: channel=%d",
384 channel_id());
Corey Tabakacd52dd92017-04-07 18:03:57 -0700385 return ErrorStatus(EALREADY);
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800386 }
387
388 // There are still pending consumers, return busy.
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700389 if (pending_consumers_ > 0) {
390 ALOGE(
391 "ProducerChannel::OnGain: Producer (id=%d) is gaining a buffer that "
392 "still has %d pending consumer(s).",
393 buffer_id(), pending_consumers_);
Corey Tabakacd52dd92017-04-07 18:03:57 -0700394 return ErrorStatus(EBUSY);
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700395 }
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800396
397 ClearAvailable();
398 producer_owns_ = true;
Alex Vakulenko052f3ae2017-03-31 09:10:43 -0700399 post_fence_.close();
Corey Tabakacd52dd92017-04-07 18:03:57 -0700400 return {std::move(returned_fence_)};
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800401}
402
Fan Xub0eec512018-10-30 11:33:15 -0700403// TODO(b/112338294) Keep here for reference. Remove it after new logic is
404// written.
405/* Status<RemoteChannelHandle> ProducerChannel::OnProducerDetach(
Jiwen 'Steve' Cai23c1a732018-03-12 12:16:47 -0700406 Message& message) {
407 ATRACE_NAME("ProducerChannel::OnProducerDetach");
408 ALOGD_IF(TRACE, "ProducerChannel::OnProducerDetach: buffer_id=%d",
409 buffer_id());
410
Tianyu Jiange2cdec92018-10-30 17:40:58 -0700411 uint64_t buffer_state = buffer_state_->load(std::memory_order_acquire);
Jiwen 'Steve' Cai23c1a732018-03-12 12:16:47 -0700412 if (!BufferHubDefs::IsBufferGained(buffer_state)) {
413 // Can only detach a BufferProducer when it's in gained state.
414 ALOGW(
415 "ProducerChannel::OnProducerDetach: The buffer (id=%d, state=0x%" PRIx64
416 ") is not in gained state.",
417 buffer_id(), buffer_state);
418 return {};
419 }
420
421 int channel_id;
422 auto status = message.PushChannel(0, nullptr, &channel_id);
423 if (!status) {
424 ALOGE(
425 "ProducerChannel::OnProducerDetach: Failed to push detached buffer "
426 "channel: %s",
427 status.GetErrorMessage().c_str());
428 return ErrorStatus(ENOMEM);
429 }
430
431 // Make sure we unlock the buffer.
432 if (int ret = metadata_buffer_.Unlock()) {
433 ALOGE("ProducerChannel::OnProducerDetach: Failed to unlock metadata.");
434 return ErrorStatus(-ret);
435 };
436
Jiwen 'Steve' Cai9004b8c2018-10-03 18:52:23 -0700437 std::unique_ptr<BufferChannel> channel =
438 BufferChannel::Create(service(), buffer_id(), channel_id,
439 std::move(buffer_), user_metadata_size_);
Jiwen 'Steve' Caia8049a22018-03-28 15:14:02 -0700440 if (!channel) {
441 ALOGE("ProducerChannel::OnProducerDetach: Invalid buffer.");
442 return ErrorStatus(EINVAL);
443 }
Jiwen 'Steve' Cai23c1a732018-03-12 12:16:47 -0700444
Jiwen 'Steve' Caia8049a22018-03-28 15:14:02 -0700445 const auto channel_status =
446 service()->SetChannel(channel_id, std::move(channel));
Jiwen 'Steve' Cai23c1a732018-03-12 12:16:47 -0700447 if (!channel_status) {
448 // Technically, this should never fail, as we just pushed the channel. Note
449 // that LOG_FATAL will be stripped out in non-debug build.
450 LOG_FATAL(
451 "ProducerChannel::OnProducerDetach: Failed to set new detached buffer "
452 "channel: %s.",
453 channel_status.GetErrorMessage().c_str());
454 }
455
456 return status;
Fan Xub0eec512018-10-30 11:33:15 -0700457} */
Jiwen 'Steve' Cai23c1a732018-03-12 12:16:47 -0700458
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700459Status<LocalFence> ProducerChannel::OnConsumerAcquire(Message& /*message*/) {
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800460 ATRACE_NAME("ProducerChannel::OnConsumerAcquire");
461 ALOGD_IF(TRACE, "ProducerChannel::OnConsumerAcquire: buffer_id=%d",
462 buffer_id());
463 if (producer_owns_) {
464 ALOGE("ProducerChannel::OnConsumerAcquire: Not in posted state!");
Corey Tabakacd52dd92017-04-07 18:03:57 -0700465 return ErrorStatus(EBUSY);
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800466 }
467
468 // Return a borrowed fd to avoid unnecessary duplication of the underlying fd.
469 // Serialization just needs to read the handle.
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700470 return {std::move(post_fence_)};
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800471}
472
Corey Tabakacd52dd92017-04-07 18:03:57 -0700473Status<void> ProducerChannel::OnConsumerRelease(Message&,
474 LocalFence release_fence) {
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800475 ATRACE_NAME("ProducerChannel::OnConsumerRelease");
476 ALOGD_IF(TRACE, "ProducerChannel::OnConsumerRelease: buffer_id=%d",
477 buffer_id());
478 if (producer_owns_) {
479 ALOGE("ProducerChannel::OnConsumerRelease: Not in acquired state!");
Corey Tabakacd52dd92017-04-07 18:03:57 -0700480 return ErrorStatus(EBUSY);
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800481 }
482
483 // Attempt to merge the fences if necessary.
484 if (release_fence) {
485 if (returned_fence_) {
Corey Tabaka3079cb72017-01-19 15:07:26 -0800486 LocalFence merged_fence(sync_merge("bufferhub_merged",
487 returned_fence_.get_fd(),
488 release_fence.get_fd()));
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800489 const int error = errno;
490 if (!merged_fence) {
491 ALOGE("ProducerChannel::OnConsumerRelease: Failed to merge fences: %s",
492 strerror(error));
Corey Tabakacd52dd92017-04-07 18:03:57 -0700493 return ErrorStatus(error);
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800494 }
495 returned_fence_ = std::move(merged_fence);
496 } else {
497 returned_fence_ = std::move(release_fence);
498 }
499 }
500
Tianyu0c6b7ff2018-10-03 11:30:04 -0700501 DecrementPendingConsumers();
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700502 if (pending_consumers_ == 0) {
503 // Clear the producer bit atomically to transit into released state. This
504 // has to done by BufferHub as it requries synchronization among all
505 // consumers.
506 BufferHubDefs::ModifyBufferState(buffer_state_,
507 BufferHubDefs::kProducerStateBit, 0ULL);
508 ALOGD_IF(TRACE,
509 "ProducerChannel::OnConsumerRelease: releasing last consumer: "
510 "buffer_id=%d state=%" PRIx64 ".",
Tianyu Jiange2cdec92018-10-30 17:40:58 -0700511 buffer_id(), buffer_state_->load(std::memory_order_acquire));
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700512
513 if (orphaned_consumer_bit_mask_) {
514 ALOGW(
515 "ProducerChannel::OnConsumerRelease: orphaned buffer detected "
516 "during the this acquire/release cycle: id=%d orphaned=0x%" PRIx64
517 " queue_index=%" PRIu64 ".",
518 buffer_id(), orphaned_consumer_bit_mask_,
519 metadata_header_->queue_index);
520 orphaned_consumer_bit_mask_ = 0;
521 }
522
523 SignalAvailable();
524 }
525
Tianyu Jiange2cdec92018-10-30 17:40:58 -0700526 ALOGE_IF(
527 pending_consumers_ && BufferHubDefs::IsBufferReleased(
528 buffer_state_->load(std::memory_order_acquire)),
529 "ProducerChannel::OnConsumerRelease: buffer state inconsistent: "
530 "pending_consumers=%d, buffer buffer is in releaed state.",
531 pending_consumers_);
Corey Tabakacd52dd92017-04-07 18:03:57 -0700532 return {};
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800533}
534
Tianyu0c6b7ff2018-10-03 11:30:04 -0700535void ProducerChannel::DecrementPendingConsumers() {
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700536 if (pending_consumers_ == 0) {
Tianyu0c6b7ff2018-10-03 11:30:04 -0700537 ALOGE("ProducerChannel::DecrementPendingConsumers: no pending consumer.");
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700538 return;
539 }
540
541 --pending_consumers_;
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800542 ALOGD_IF(TRACE,
Tianyu0c6b7ff2018-10-03 11:30:04 -0700543 "ProducerChannel::DecrementPendingConsumers: buffer_id=%d %d "
544 "consumers left",
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800545 buffer_id(), pending_consumers_);
546}
547
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700548void ProducerChannel::OnConsumerOrphaned(ConsumerChannel* channel) {
549 // Ignore the orphaned consumer.
Tianyu0c6b7ff2018-10-03 11:30:04 -0700550 DecrementPendingConsumers();
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700551
Tianyu Jiang83a991f2018-10-30 16:59:29 -0700552 const uint64_t client_state_mask = channel->client_state_mask();
553 ALOGE_IF(orphaned_consumer_bit_mask_ & client_state_mask,
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700554 "ProducerChannel::OnConsumerOrphaned: Consumer "
Tianyu Jiang83a991f2018-10-30 16:59:29 -0700555 "(client_state_mask=%" PRIx64 ") is already orphaned.",
556 client_state_mask);
557 orphaned_consumer_bit_mask_ |= client_state_mask;
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700558
559 // Atomically clear the fence state bit as an orphaned consumer will never
560 // signal a release fence. Also clear the buffer state as it won't be released
561 // as well.
Tianyu Jiang83a991f2018-10-30 16:59:29 -0700562 fence_state_->fetch_and(~client_state_mask);
563 BufferHubDefs::ModifyBufferState(buffer_state_, client_state_mask, 0ULL);
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700564
565 ALOGW(
566 "ProducerChannel::OnConsumerOrphaned: detected new orphaned consumer "
Tianyu Jiang83a991f2018-10-30 16:59:29 -0700567 "buffer_id=%d client_state_mask=%" PRIx64 " queue_index=%" PRIu64
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700568 " buffer_state=%" PRIx64 " fence_state=%" PRIx64 ".",
Tianyu Jiang83a991f2018-10-30 16:59:29 -0700569 buffer_id(), client_state_mask, metadata_header_->queue_index,
Tianyu Jiange2cdec92018-10-30 17:40:58 -0700570 buffer_state_->load(std::memory_order_acquire),
571 fence_state_->load(std::memory_order_acquire));
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700572}
573
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800574void ProducerChannel::AddConsumer(ConsumerChannel* channel) {
575 consumer_channels_.push_back(channel);
576}
577
578void ProducerChannel::RemoveConsumer(ConsumerChannel* channel) {
579 consumer_channels_.erase(
580 std::find(consumer_channels_.begin(), consumer_channels_.end(), channel));
Tianyu67053492018-10-04 14:00:22 -0700581 // Restore the consumer state bit and make it visible in other threads that
582 // acquire the active_clients_bit_mask_.
Tianyu Jiang83a991f2018-10-30 16:59:29 -0700583 active_clients_bit_mask_->fetch_and(~channel->client_state_mask(),
Tianyu67053492018-10-04 14:00:22 -0700584 std::memory_order_release);
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700585
Tianyu Jiange2cdec92018-10-30 17:40:58 -0700586 const uint64_t buffer_state = buffer_state_->load(std::memory_order_acquire);
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700587 if (BufferHubDefs::IsBufferPosted(buffer_state) ||
588 BufferHubDefs::IsBufferAcquired(buffer_state)) {
589 // The consumer client is being destoryed without releasing. This could
590 // happen in corner cases when the consumer crashes. Here we mark it
591 // orphaned before remove it from producer.
592 OnConsumerOrphaned(channel);
593 }
594
595 if (BufferHubDefs::IsBufferReleased(buffer_state) ||
596 BufferHubDefs::IsBufferGained(buffer_state)) {
597 // The consumer is being close while it is suppose to signal a release
598 // fence. Signal the dummy fence here.
Tianyu Jiange2cdec92018-10-30 17:40:58 -0700599 if (fence_state_->load(std::memory_order_acquire) &
600 channel->client_state_mask()) {
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700601 epoll_event event;
602 event.events = EPOLLIN;
Tianyu Jiang83a991f2018-10-30 16:59:29 -0700603 event.data.u64 = channel->client_state_mask();
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700604 if (epoll_ctl(release_fence_fd_.Get(), EPOLL_CTL_MOD,
605 dummy_fence_fd_.Get(), &event) < 0) {
606 ALOGE(
607 "ProducerChannel::RemoveConsumer: Failed to modify the shared "
608 "release fence to include the dummy fence: %s",
609 strerror(errno));
610 return;
611 }
612 ALOGW(
613 "ProducerChannel::RemoveConsumer: signal dummy release fence "
614 "buffer_id=%d",
615 buffer_id());
616 eventfd_write(dummy_fence_fd_.Get(), 1);
617 }
618 }
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800619}
620
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800621// Returns true if the given parameters match the underlying buffer parameters.
Corey Tabakacd52dd92017-04-07 18:03:57 -0700622bool ProducerChannel::CheckParameters(uint32_t width, uint32_t height,
Hendrik Wagenaar108e84f2017-05-07 22:19:17 -0700623 uint32_t layer_count, uint32_t format,
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700624 uint64_t usage,
625 size_t user_metadata_size) {
626 return user_metadata_size == user_metadata_size_ &&
627 buffer_.width() == width && buffer_.height() == height &&
628 buffer_.layer_count() == layer_count && buffer_.format() == format &&
629 buffer_.usage() == usage;
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800630}
631
632} // namespace dvr
633} // namespace android