blob: 4b4301fef9541a7d286ba7f919ee4f96c19cc70e [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),
Corey Tabaka52ea25c2017-09-13 18:02:48 -070060 user_metadata_size_(user_metadata_size),
61 metadata_buf_size_(BufferHubDefs::kMetadataHeaderSize +
62 user_metadata_size) {
63 if (int ret = buffer_.Alloc(width, height, layer_count, format, usage)) {
Hendrik Wagenaar4d3590f2017-05-06 22:36:04 -070064 ALOGE("ProducerChannel::ProducerChannel: Failed to allocate buffer: %s",
65 strerror(-ret));
66 *error = ret;
67 return;
Alex Vakulenkoe4eec202017-01-27 14:41:04 -080068 }
69
Corey Tabaka52ea25c2017-09-13 18:02:48 -070070 if (int ret = metadata_buffer_.Alloc(metadata_buf_size_, /*height=*/1,
71 /*layer_count=*/1,
72 BufferHubDefs::kMetadataFormat,
73 BufferHubDefs::kMetadataUsage)) {
74 ALOGE("ProducerChannel::ProducerChannel: Failed to allocate metadata: %s",
75 strerror(-ret));
76 *error = ret;
77 return;
78 }
79
Jiwen 'Steve' Cai0728fa92018-04-24 19:03:14 -070080 *error = InitializeBuffer();
81}
82
83int ProducerChannel::InitializeBuffer() {
Corey Tabaka52ea25c2017-09-13 18:02:48 -070084 void* metadata_ptr = nullptr;
85 if (int ret = metadata_buffer_.Lock(BufferHubDefs::kMetadataUsage, /*x=*/0,
86 /*y=*/0, metadata_buf_size_,
87 /*height=*/1, &metadata_ptr)) {
88 ALOGE("ProducerChannel::ProducerChannel: Failed to lock metadata.");
Jiwen 'Steve' Cai0728fa92018-04-24 19:03:14 -070089 return ret;
Corey Tabaka52ea25c2017-09-13 18:02:48 -070090 }
91 metadata_header_ =
92 reinterpret_cast<BufferHubDefs::MetadataHeader*>(metadata_ptr);
93
94 // Using placement new here to reuse shared memory instead of new allocation
95 // and also initialize the value to zero.
96 buffer_state_ =
97 new (&metadata_header_->buffer_state) std::atomic<uint64_t>(0);
Tianyu0c6b7ff2018-10-03 11:30:04 -070098 fence_state_ = new (&metadata_header_->fence_state) std::atomic<uint64_t>(0);
Tianyu67053492018-10-04 14:00:22 -070099 active_clients_bit_mask_ =
100 new (&metadata_header_->active_clients_bit_mask) std::atomic<uint64_t>(0);
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700101
Tianyu Jiang63dd7c32018-10-30 18:35:06 -0700102 // Producer channel is never created after consumer channel, and one buffer
103 // only have one fixed producer for now. Thus, it is correct to assume
104 // producer state bit is kFirstClientBitMask for now.
105 active_clients_bit_mask_->store(BufferHubDefs::kFirstClientBitMask,
106 std::memory_order_release);
107
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700108 acquire_fence_fd_.Reset(epoll_create1(EPOLL_CLOEXEC));
109 release_fence_fd_.Reset(epoll_create1(EPOLL_CLOEXEC));
110 if (!acquire_fence_fd_ || !release_fence_fd_) {
111 ALOGE("ProducerChannel::ProducerChannel: Failed to create shared fences.");
Jiwen 'Steve' Cai0728fa92018-04-24 19:03:14 -0700112 return -EIO;
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700113 }
114
115 dummy_fence_fd_.Reset(eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK));
116 if (!dummy_fence_fd_) {
117 ALOGE("ProducerChannel::ProducerChannel: Failed to create dummy fences.");
Jiwen 'Steve' Cai0728fa92018-04-24 19:03:14 -0700118 return EIO;
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700119 }
120
121 epoll_event event;
122 event.events = 0;
123 event.data.u64 = 0ULL;
124 if (epoll_ctl(release_fence_fd_.Get(), EPOLL_CTL_ADD, dummy_fence_fd_.Get(),
125 &event) < 0) {
126 ALOGE(
127 "ProducerChannel::ProducerChannel: Failed to modify the shared "
128 "release fence to include the dummy fence: %s",
129 strerror(errno));
Jiwen 'Steve' Cai0728fa92018-04-24 19:03:14 -0700130 return -EIO;
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700131 }
132
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800133 // Success.
Jiwen 'Steve' Cai0728fa92018-04-24 19:03:14 -0700134 return 0;
135}
136
137std::unique_ptr<ProducerChannel> ProducerChannel::Create(
138 BufferHubService* service, int buffer_id, int channel_id, IonBuffer buffer,
139 IonBuffer metadata_buffer, size_t user_metadata_size) {
140 int error = 0;
141 std::unique_ptr<ProducerChannel> producer(new ProducerChannel(
142 service, buffer_id, channel_id, std::move(buffer),
143 std::move(metadata_buffer), user_metadata_size, &error));
144
145 if (error < 0)
146 return nullptr;
147 else
148 return producer;
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800149}
150
Corey Tabakacd52dd92017-04-07 18:03:57 -0700151Status<std::shared_ptr<ProducerChannel>> ProducerChannel::Create(
152 BufferHubService* service, int channel_id, uint32_t width, uint32_t height,
Hendrik Wagenaar108e84f2017-05-07 22:19:17 -0700153 uint32_t layer_count, uint32_t format, uint64_t usage,
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700154 size_t user_metadata_size) {
Corey Tabakacd52dd92017-04-07 18:03:57 -0700155 int error;
Jiwen 'Steve' Cai0057fdd2017-05-02 11:21:18 -0700156 std::shared_ptr<ProducerChannel> producer(
Hendrik Wagenaar108e84f2017-05-07 22:19:17 -0700157 new ProducerChannel(service, channel_id, width, height, layer_count,
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700158 format, usage, user_metadata_size, &error));
Corey Tabakacd52dd92017-04-07 18:03:57 -0700159 if (error < 0)
160 return ErrorStatus(-error);
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800161 else
Corey Tabakacd52dd92017-04-07 18:03:57 -0700162 return {std::move(producer)};
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800163}
164
165ProducerChannel::~ProducerChannel() {
Corey Tabaka3079cb72017-01-19 15:07:26 -0800166 ALOGD_IF(TRACE,
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700167 "ProducerChannel::~ProducerChannel: channel_id=%d buffer_id=%d "
168 "state=%" PRIx64 ".",
Tianyu Jiange2cdec92018-10-30 17:40:58 -0700169 channel_id(), buffer_id(),
170 buffer_state_->load(std::memory_order_acquire));
Jiwen 'Steve' Cai23c1a732018-03-12 12:16:47 -0700171 for (auto consumer : consumer_channels_) {
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800172 consumer->OnProducerClosed();
Jiwen 'Steve' Cai23c1a732018-03-12 12:16:47 -0700173 }
174 Hangup();
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800175}
176
177BufferHubChannel::BufferInfo ProducerChannel::GetBufferInfo() const {
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700178 // Derive the mask of signaled buffers in this producer / consumer set.
Tianyu Jiang63dd7c32018-10-30 18:35:06 -0700179 uint64_t signaled_mask = signaled() ? BufferHubDefs::kFirstClientBitMask : 0;
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700180 for (const ConsumerChannel* consumer : consumer_channels_) {
Tianyu Jiang83a991f2018-10-30 16:59:29 -0700181 signaled_mask |= consumer->signaled() ? consumer->client_state_mask() : 0;
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700182 }
183
Hendrik Wagenaar4d3590f2017-05-06 22:36:04 -0700184 return BufferInfo(buffer_id(), consumer_channels_.size(), buffer_.width(),
Hendrik Wagenaar108e84f2017-05-07 22:19:17 -0700185 buffer_.height(), buffer_.layer_count(), buffer_.format(),
Tianyu Jiange2cdec92018-10-30 17:40:58 -0700186 buffer_.usage(), pending_consumers_,
187 buffer_state_->load(std::memory_order_acquire),
Jiwen 'Steve' Cai2f260332018-02-15 18:39:47 -0800188 signaled_mask, metadata_header_->queue_index);
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800189}
190
191void ProducerChannel::HandleImpulse(Message& message) {
192 ATRACE_NAME("ProducerChannel::HandleImpulse");
193 switch (message.GetOp()) {
194 case BufferHubRPC::ProducerGain::Opcode:
195 OnProducerGain(message);
196 break;
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700197 case BufferHubRPC::ProducerPost::Opcode:
198 OnProducerPost(message, {});
199 break;
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800200 }
201}
202
203bool ProducerChannel::HandleMessage(Message& message) {
204 ATRACE_NAME("ProducerChannel::HandleMessage");
205 switch (message.GetOp()) {
206 case BufferHubRPC::GetBuffer::Opcode:
207 DispatchRemoteMethod<BufferHubRPC::GetBuffer>(
208 *this, &ProducerChannel::OnGetBuffer, message);
209 return true;
210
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800211 case BufferHubRPC::NewConsumer::Opcode:
212 DispatchRemoteMethod<BufferHubRPC::NewConsumer>(
213 *this, &ProducerChannel::OnNewConsumer, message);
214 return true;
215
216 case BufferHubRPC::ProducerPost::Opcode:
217 DispatchRemoteMethod<BufferHubRPC::ProducerPost>(
218 *this, &ProducerChannel::OnProducerPost, message);
219 return true;
220
221 case BufferHubRPC::ProducerGain::Opcode:
222 DispatchRemoteMethod<BufferHubRPC::ProducerGain>(
223 *this, &ProducerChannel::OnProducerGain, message);
224 return true;
225
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800226 default:
227 return false;
228 }
229}
230
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700231BufferDescription<BorrowedHandle> ProducerChannel::GetBuffer(
Tianyu Jiang7e204b72018-10-26 15:39:18 -0700232 uint64_t client_state_mask) {
Jiwen 'Steve' Cai57ae3ee2018-05-03 17:51:52 -0700233 return {buffer_,
234 metadata_buffer_,
235 buffer_id(),
236 channel_id(),
Tianyu Jiang7e204b72018-10-26 15:39:18 -0700237 client_state_mask,
Jiwen 'Steve' Cai57ae3ee2018-05-03 17:51:52 -0700238 acquire_fence_fd_.Borrow(),
239 release_fence_fd_.Borrow()};
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700240}
241
242Status<BufferDescription<BorrowedHandle>> ProducerChannel::OnGetBuffer(
Corey Tabakad53870c2017-07-06 18:04:27 -0700243 Message& /*message*/) {
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800244 ATRACE_NAME("ProducerChannel::OnGetBuffer");
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700245 ALOGD_IF(TRACE, "ProducerChannel::OnGetBuffer: buffer=%d, state=%" PRIx64 ".",
Tianyu Jiange2cdec92018-10-30 17:40:58 -0700246 buffer_id(), buffer_state_->load(std::memory_order_acquire));
Tianyu Jiang63dd7c32018-10-30 18:35:06 -0700247 return {GetBuffer(BufferHubDefs::kFirstClientBitMask)};
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800248}
249
Tianyu Jiang50f7ad12018-11-08 11:13:35 -0800250Status<uint64_t> ProducerChannel::CreateConsumerStateMask() {
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700251 // Try find the next consumer state bit which has not been claimed by any
252 // consumer yet.
Tianyu67053492018-10-04 14:00:22 -0700253 // memory_order_acquire is chosen here because all writes in other threads
254 // that release active_clients_bit_mask_ need to be visible here.
255 uint64_t current_active_clients_bit_mask =
256 active_clients_bit_mask_->load(std::memory_order_acquire);
Tianyuf669f6a2018-10-10 15:34:32 -0700257 uint64_t consumer_state_mask =
258 BufferHubDefs::FindNextAvailableClientStateMask(
259 current_active_clients_bit_mask | orphaned_consumer_bit_mask_);
260 if (consumer_state_mask == 0ULL) {
261 ALOGE("%s: reached the maximum mumber of consumers per producer: 63.",
262 __FUNCTION__);
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700263 return ErrorStatus(E2BIG);
264 }
Tianyu67053492018-10-04 14:00:22 -0700265 uint64_t updated_active_clients_bit_mask =
Tianyuf669f6a2018-10-10 15:34:32 -0700266 current_active_clients_bit_mask | consumer_state_mask;
Tianyu67053492018-10-04 14:00:22 -0700267 // Set the updated value only if the current value stays the same as what was
268 // read before. If the comparison succeeds, update the value without
269 // reordering anything before or after this read-modify-write in the current
270 // thread, and the modification will be visible in other threads that acquire
271 // active_clients_bit_mask_. If the comparison fails, load the result of
272 // all writes from all threads to updated_active_clients_bit_mask.
Tianyu Jiang50f7ad12018-11-08 11:13:35 -0800273 // Keep on finding the next available slient state mask until succeed or out
274 // of memory.
275 while (!active_clients_bit_mask_->compare_exchange_weak(
276 current_active_clients_bit_mask, updated_active_clients_bit_mask,
277 std::memory_order_acq_rel, std::memory_order_acquire)) {
Tianyuf669f6a2018-10-10 15:34:32 -0700278 ALOGE("%s: Current active clients bit mask is changed to %" PRIx64
Tianyu Jiang50f7ad12018-11-08 11:13:35 -0800279 ", which was expected to be %" PRIx64
280 ". Trying to generate a new client state mask to resolve race "
281 "condition.",
Tianyuf669f6a2018-10-10 15:34:32 -0700282 __FUNCTION__, updated_active_clients_bit_mask,
283 current_active_clients_bit_mask);
284 consumer_state_mask = BufferHubDefs::FindNextAvailableClientStateMask(
Tianyu Jiang50f7ad12018-11-08 11:13:35 -0800285 current_active_clients_bit_mask | orphaned_consumer_bit_mask_);
Tianyuf669f6a2018-10-10 15:34:32 -0700286 if (consumer_state_mask == 0ULL) {
287 ALOGE("%s: reached the maximum mumber of consumers per producer: %d.",
288 __FUNCTION__, (BufferHubDefs::kMaxNumberOfClients - 1));
Tianyu Jiang50f7ad12018-11-08 11:13:35 -0800289 return ErrorStatus(E2BIG);
290 }
291 updated_active_clients_bit_mask =
Tianyuf669f6a2018-10-10 15:34:32 -0700292 current_active_clients_bit_mask | consumer_state_mask;
Tianyu67053492018-10-04 14:00:22 -0700293 }
294
Tianyuf669f6a2018-10-10 15:34:32 -0700295 return {consumer_state_mask};
Tianyu Jiang50f7ad12018-11-08 11:13:35 -0800296}
297
298void ProducerChannel::RemoveConsumerClientMask(uint64_t consumer_state_mask) {
299 // Clear up the buffer state and fence state in case there is already
300 // something there due to possible race condition between producer post and
301 // consumer failed to create channel.
302 buffer_state_->fetch_and(~consumer_state_mask, std::memory_order_release);
303 fence_state_->fetch_and(~consumer_state_mask, std::memory_order_release);
304
305 // Restore the consumer state bit and make it visible in other threads that
306 // acquire the active_clients_bit_mask_.
307 active_clients_bit_mask_->fetch_and(~consumer_state_mask,
308 std::memory_order_release);
309}
310
311Status<RemoteChannelHandle> ProducerChannel::CreateConsumer(
312 Message& message, uint64_t consumer_state_mask) {
Tianyuf669f6a2018-10-10 15:34:32 -0700313 ATRACE_NAME(__FUNCTION__);
Tianyu Jiang49824322018-11-14 16:42:51 -0800314 ALOGD_IF(TRACE, "%s: buffer_id=%d", __FUNCTION__, buffer_id());
Tianyu Jiang50f7ad12018-11-08 11:13:35 -0800315
316 int channel_id;
317 auto status = message.PushChannel(0, nullptr, &channel_id);
318 if (!status) {
Tianyuf669f6a2018-10-10 15:34:32 -0700319 ALOGE("%s: Failed to push consumer channel: %s", __FUNCTION__,
320 status.GetErrorMessage().c_str());
Tianyu Jiang50f7ad12018-11-08 11:13:35 -0800321 RemoveConsumerClientMask(consumer_state_mask);
322 return ErrorStatus(ENOMEM);
323 }
324
325 auto consumer = std::make_shared<ConsumerChannel>(
326 service(), buffer_id(), channel_id, consumer_state_mask,
327 shared_from_this());
Alex Vakulenkof0a7bd02017-03-31 18:06:19 -0700328 const auto channel_status = service()->SetChannel(channel_id, consumer);
329 if (!channel_status) {
Tianyuf669f6a2018-10-10 15:34:32 -0700330 ALOGE("%s: failed to set new consumer channel: %s.", __FUNCTION__,
331 channel_status.GetErrorMessage().c_str());
Tianyu Jiang50f7ad12018-11-08 11:13:35 -0800332 RemoveConsumerClientMask(consumer_state_mask);
Corey Tabakacd52dd92017-04-07 18:03:57 -0700333 return ErrorStatus(ENOMEM);
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800334 }
335
Tianyu Jiangca9201a2018-11-06 12:40:33 -0800336 uint64_t current_buffer_state =
337 buffer_state_->load(std::memory_order_acquire);
Tianyuf669f6a2018-10-10 15:34:32 -0700338 if (BufferHubDefs::IsBufferReleased(current_buffer_state) ||
339 BufferHubDefs::AnyClientGained(current_buffer_state)) {
340 return {status.take()};
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800341 }
342
Tianyuf669f6a2018-10-10 15:34:32 -0700343 // Signal the new consumer when adding it to a posted producer.
344 bool update_buffer_state = true;
345 if (!BufferHubDefs::IsClientPosted(current_buffer_state,
346 consumer_state_mask)) {
347 uint64_t updated_buffer_state =
348 current_buffer_state ^
349 (consumer_state_mask & BufferHubDefs::kHighBitsMask);
350 while (!buffer_state_->compare_exchange_weak(
351 current_buffer_state, updated_buffer_state, std::memory_order_acq_rel,
352 std::memory_order_acquire)) {
353 ALOGI(
354 "%s: Failed to post to the new consumer. "
355 "Current buffer state was changed to %" PRIx64
356 " when trying to acquire the buffer and modify the buffer state to "
357 "%" PRIx64
358 ". About to try again if the buffer is still not gained nor fully "
359 "released.",
360 __FUNCTION__, current_buffer_state, updated_buffer_state);
361 if (BufferHubDefs::IsBufferReleased(current_buffer_state) ||
362 BufferHubDefs::AnyClientGained(current_buffer_state)) {
363 ALOGI("%s: buffer is gained or fully released, state=%" PRIx64 ".",
364 __FUNCTION__, current_buffer_state);
365 update_buffer_state = false;
366 break;
367 }
368 updated_buffer_state =
369 current_buffer_state ^
370 (consumer_state_mask & BufferHubDefs::kHighBitsMask);
371 }
372 }
373 if (update_buffer_state && consumer->OnProducerPosted())
374 pending_consumers_++;
375
Corey Tabakacd52dd92017-04-07 18:03:57 -0700376 return {status.take()};
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800377}
378
Corey Tabakacd52dd92017-04-07 18:03:57 -0700379Status<RemoteChannelHandle> ProducerChannel::OnNewConsumer(Message& message) {
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800380 ATRACE_NAME("ProducerChannel::OnNewConsumer");
381 ALOGD_IF(TRACE, "ProducerChannel::OnNewConsumer: buffer_id=%d", buffer_id());
Tianyu Jiang50f7ad12018-11-08 11:13:35 -0800382 auto status = CreateConsumerStateMask();
383 if (!status.ok()) {
384 return status.error_status();
385 }
386 return CreateConsumer(message, /*consumer_state_mask=*/status.get());
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800387}
388
Tianyu0c6b7ff2018-10-03 11:30:04 -0700389Status<void> ProducerChannel::OnProducerPost(Message&,
390 LocalFence acquire_fence) {
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800391 ATRACE_NAME("ProducerChannel::OnProducerPost");
392 ALOGD_IF(TRACE, "ProducerChannel::OnProducerPost: buffer_id=%d", buffer_id());
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800393
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700394 epoll_event event;
395 event.events = 0;
396 event.data.u64 = 0ULL;
397 int ret = epoll_ctl(release_fence_fd_.Get(), EPOLL_CTL_MOD,
398 dummy_fence_fd_.Get(), &event);
399 ALOGE_IF(ret < 0,
Tianyu0c6b7ff2018-10-03 11:30:04 -0700400 "ProducerChannel::OnProducerPost: Failed to modify the shared "
401 "release fence to include the dummy fence: %s",
402 strerror(errno));
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700403
404 eventfd_t dummy_fence_count = 0ULL;
405 if (eventfd_read(dummy_fence_fd_.Get(), &dummy_fence_count) < 0) {
406 const int error = errno;
407 if (error != EAGAIN) {
408 ALOGE(
409 "ProducerChannel::ProducerChannel: Failed to read dummy fence, "
410 "error: %s",
411 strerror(error));
412 return ErrorStatus(error);
413 }
Corey Tabaka8a4e6a92017-04-20 13:42:02 -0700414 }
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800415
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700416 ALOGW_IF(dummy_fence_count > 0,
417 "ProducerChannel::ProducerChannel: %" PRIu64
418 " dummy fence(s) was signaled during last release/gain cycle "
419 "buffer_id=%d.",
420 dummy_fence_count, buffer_id());
421
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800422 post_fence_ = std::move(acquire_fence);
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800423
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700424 // Signal any interested consumers. If there are none, the buffer will stay
425 // in posted state until a consumer comes online. This behavior guarantees
426 // that no frame is silently dropped.
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800427 pending_consumers_ = 0;
428 for (auto consumer : consumer_channels_) {
429 if (consumer->OnProducerPosted())
430 pending_consumers_++;
431 }
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800432 ALOGD_IF(TRACE, "ProducerChannel::OnProducerPost: %d pending consumers",
433 pending_consumers_);
434
Corey Tabakacd52dd92017-04-07 18:03:57 -0700435 return {};
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800436}
437
Corey Tabakad53870c2017-07-06 18:04:27 -0700438Status<LocalFence> ProducerChannel::OnProducerGain(Message& /*message*/) {
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800439 ATRACE_NAME("ProducerChannel::OnGain");
440 ALOGD_IF(TRACE, "ProducerChannel::OnGain: buffer_id=%d", buffer_id());
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800441
442 // There are still pending consumers, return busy.
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700443 if (pending_consumers_ > 0) {
444 ALOGE(
445 "ProducerChannel::OnGain: Producer (id=%d) is gaining a buffer that "
446 "still has %d pending consumer(s).",
447 buffer_id(), pending_consumers_);
Tianyuf669f6a2018-10-10 15:34:32 -0700448 // TODO(b/77153033): add gain_posted_buffer to the impulse args, and
449 // return busy if the function does not allow gaining posted buffer.
450 // TODO(b/119331650): remove this if check if pending_consumers_ is removed.
451 // return ErrorStatus(EBUSY);
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700452 }
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800453
454 ClearAvailable();
Alex Vakulenko052f3ae2017-03-31 09:10:43 -0700455 post_fence_.close();
Corey Tabakacd52dd92017-04-07 18:03:57 -0700456 return {std::move(returned_fence_)};
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800457}
458
Fan Xub0eec512018-10-30 11:33:15 -0700459// TODO(b/112338294) Keep here for reference. Remove it after new logic is
460// written.
461/* Status<RemoteChannelHandle> ProducerChannel::OnProducerDetach(
Jiwen 'Steve' Cai23c1a732018-03-12 12:16:47 -0700462 Message& message) {
463 ATRACE_NAME("ProducerChannel::OnProducerDetach");
464 ALOGD_IF(TRACE, "ProducerChannel::OnProducerDetach: buffer_id=%d",
465 buffer_id());
466
Tianyu Jiange2cdec92018-10-30 17:40:58 -0700467 uint64_t buffer_state = buffer_state_->load(std::memory_order_acquire);
Tianyuf669f6a2018-10-10 15:34:32 -0700468 if (!BufferHubDefs::IsClientGained(
469 buffer_state, BufferHubDefs::kFirstClientStateMask)) {
Jiwen 'Steve' Cai23c1a732018-03-12 12:16:47 -0700470 // Can only detach a BufferProducer when it's in gained state.
471 ALOGW(
Tianyuf669f6a2018-10-10 15:34:32 -0700472 "ProducerChannel::OnProducerDetach: The buffer (id=%d, state=%"
473 PRIx64
Jiwen 'Steve' Cai23c1a732018-03-12 12:16:47 -0700474 ") is not in gained state.",
475 buffer_id(), buffer_state);
476 return {};
477 }
478
479 int channel_id;
480 auto status = message.PushChannel(0, nullptr, &channel_id);
481 if (!status) {
482 ALOGE(
483 "ProducerChannel::OnProducerDetach: Failed to push detached buffer "
484 "channel: %s",
485 status.GetErrorMessage().c_str());
486 return ErrorStatus(ENOMEM);
487 }
488
489 // Make sure we unlock the buffer.
490 if (int ret = metadata_buffer_.Unlock()) {
491 ALOGE("ProducerChannel::OnProducerDetach: Failed to unlock metadata.");
492 return ErrorStatus(-ret);
493 };
494
Jiwen 'Steve' Cai9004b8c2018-10-03 18:52:23 -0700495 std::unique_ptr<BufferChannel> channel =
496 BufferChannel::Create(service(), buffer_id(), channel_id,
497 std::move(buffer_), user_metadata_size_);
Jiwen 'Steve' Caia8049a22018-03-28 15:14:02 -0700498 if (!channel) {
499 ALOGE("ProducerChannel::OnProducerDetach: Invalid buffer.");
500 return ErrorStatus(EINVAL);
501 }
Jiwen 'Steve' Cai23c1a732018-03-12 12:16:47 -0700502
Jiwen 'Steve' Caia8049a22018-03-28 15:14:02 -0700503 const auto channel_status =
504 service()->SetChannel(channel_id, std::move(channel));
Jiwen 'Steve' Cai23c1a732018-03-12 12:16:47 -0700505 if (!channel_status) {
Tianyuf669f6a2018-10-10 15:34:32 -0700506 // Technically, this should never fail, as we just pushed the channel.
507 // Note that LOG_FATAL will be stripped out in non-debug build.
Jiwen 'Steve' Cai23c1a732018-03-12 12:16:47 -0700508 LOG_FATAL(
Tianyuf669f6a2018-10-10 15:34:32 -0700509 "ProducerChannel::OnProducerDetach: Failed to set new detached "
510 "buffer channel: %s.", channel_status.GetErrorMessage().c_str());
Jiwen 'Steve' Cai23c1a732018-03-12 12:16:47 -0700511 }
512
513 return status;
Fan Xub0eec512018-10-30 11:33:15 -0700514} */
Jiwen 'Steve' Cai23c1a732018-03-12 12:16:47 -0700515
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700516Status<LocalFence> ProducerChannel::OnConsumerAcquire(Message& /*message*/) {
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800517 ATRACE_NAME("ProducerChannel::OnConsumerAcquire");
518 ALOGD_IF(TRACE, "ProducerChannel::OnConsumerAcquire: buffer_id=%d",
519 buffer_id());
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800520
Tianyuf669f6a2018-10-10 15:34:32 -0700521 // Return a borrowed fd to avoid unnecessary duplication of the underlying
522 // fd. Serialization just needs to read the handle.
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700523 return {std::move(post_fence_)};
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800524}
525
Corey Tabakacd52dd92017-04-07 18:03:57 -0700526Status<void> ProducerChannel::OnConsumerRelease(Message&,
527 LocalFence release_fence) {
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800528 ATRACE_NAME("ProducerChannel::OnConsumerRelease");
529 ALOGD_IF(TRACE, "ProducerChannel::OnConsumerRelease: buffer_id=%d",
530 buffer_id());
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800531
532 // Attempt to merge the fences if necessary.
533 if (release_fence) {
534 if (returned_fence_) {
Corey Tabaka3079cb72017-01-19 15:07:26 -0800535 LocalFence merged_fence(sync_merge("bufferhub_merged",
536 returned_fence_.get_fd(),
537 release_fence.get_fd()));
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800538 const int error = errno;
539 if (!merged_fence) {
540 ALOGE("ProducerChannel::OnConsumerRelease: Failed to merge fences: %s",
541 strerror(error));
Corey Tabakacd52dd92017-04-07 18:03:57 -0700542 return ErrorStatus(error);
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800543 }
544 returned_fence_ = std::move(merged_fence);
545 } else {
546 returned_fence_ = std::move(release_fence);
547 }
548 }
549
Tianyu0c6b7ff2018-10-03 11:30:04 -0700550 DecrementPendingConsumers();
Tianyuf669f6a2018-10-10 15:34:32 -0700551 if (pending_consumers_ == 0 && orphaned_consumer_bit_mask_) {
552 ALOGW(
553 "%s: orphaned buffer detected during the this acquire/release cycle: "
554 "id=%d orphaned=0x%" PRIx64 " queue_index=%" PRIx64 ".",
555 __FUNCTION__, buffer_id(), orphaned_consumer_bit_mask_,
556 metadata_header_->queue_index);
557 orphaned_consumer_bit_mask_ = 0;
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700558 }
559
Tianyu Jiange2cdec92018-10-30 17:40:58 -0700560 ALOGE_IF(
561 pending_consumers_ && BufferHubDefs::IsBufferReleased(
562 buffer_state_->load(std::memory_order_acquire)),
563 "ProducerChannel::OnConsumerRelease: buffer state inconsistent: "
564 "pending_consumers=%d, buffer buffer is in releaed state.",
565 pending_consumers_);
Corey Tabakacd52dd92017-04-07 18:03:57 -0700566 return {};
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800567}
568
Tianyu0c6b7ff2018-10-03 11:30:04 -0700569void ProducerChannel::DecrementPendingConsumers() {
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700570 if (pending_consumers_ == 0) {
Tianyu0c6b7ff2018-10-03 11:30:04 -0700571 ALOGE("ProducerChannel::DecrementPendingConsumers: no pending consumer.");
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700572 return;
573 }
574
575 --pending_consumers_;
Tianyuf669f6a2018-10-10 15:34:32 -0700576 ALOGD_IF(TRACE, "%s: buffer_id=%d %d consumers left", __FUNCTION__,
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800577 buffer_id(), pending_consumers_);
Tianyuf669f6a2018-10-10 15:34:32 -0700578
579 if (pending_consumers_ == 0) {
580 ALOGD_IF(TRACE,
581 "%s: releasing last consumer: buffer_id=%d state=%" PRIx64 ".",
582 __FUNCTION__, buffer_id(),
583 buffer_state_->load(std::memory_order_acquire));
584 SignalAvailable();
585 }
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800586}
587
Tianyuf669f6a2018-10-10 15:34:32 -0700588void ProducerChannel::OnConsumerOrphaned(const uint64_t& consumer_state_mask) {
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700589 // Ignore the orphaned consumer.
Tianyu0c6b7ff2018-10-03 11:30:04 -0700590 DecrementPendingConsumers();
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700591
Tianyuf669f6a2018-10-10 15:34:32 -0700592 // Remember the ignored consumer so that newly added consumer won't be
593 // taking the same state mask as this orphaned consumer.
594 ALOGE_IF(orphaned_consumer_bit_mask_ & consumer_state_mask,
595 "%s: Consumer (consumer_state_mask=%" PRIx64
596 ") is already orphaned.",
597 __FUNCTION__, consumer_state_mask);
598 orphaned_consumer_bit_mask_ |= consumer_state_mask;
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700599
600 // Atomically clear the fence state bit as an orphaned consumer will never
Tianyuf669f6a2018-10-10 15:34:32 -0700601 // signal a release fence.
602 fence_state_->fetch_and(~consumer_state_mask, std::memory_order_release);
603
604 // Atomically set the buffer state of this consumer to released state.
605 buffer_state_->fetch_and(~consumer_state_mask, std::memory_order_release);
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700606
607 ALOGW(
Tianyuf669f6a2018-10-10 15:34:32 -0700608 "%s: detected new orphaned consumer buffer_id=%d "
609 "consumer_state_mask=%" PRIx64 " queue_index=%" PRIx64
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700610 " buffer_state=%" PRIx64 " fence_state=%" PRIx64 ".",
Tianyuf669f6a2018-10-10 15:34:32 -0700611 __FUNCTION__, buffer_id(), consumer_state_mask,
612 metadata_header_->queue_index,
Tianyu Jiange2cdec92018-10-30 17:40:58 -0700613 buffer_state_->load(std::memory_order_acquire),
614 fence_state_->load(std::memory_order_acquire));
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700615}
616
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800617void ProducerChannel::AddConsumer(ConsumerChannel* channel) {
618 consumer_channels_.push_back(channel);
619}
620
621void ProducerChannel::RemoveConsumer(ConsumerChannel* channel) {
622 consumer_channels_.erase(
623 std::find(consumer_channels_.begin(), consumer_channels_.end(), channel));
Tianyu67053492018-10-04 14:00:22 -0700624 // Restore the consumer state bit and make it visible in other threads that
625 // acquire the active_clients_bit_mask_.
Tianyuf669f6a2018-10-10 15:34:32 -0700626 uint64_t consumer_state_mask = channel->client_state_mask();
627 uint64_t current_active_clients_bit_mask =
628 active_clients_bit_mask_->load(std::memory_order_acquire);
629 uint64_t updated_active_clients_bit_mask =
630 current_active_clients_bit_mask & (~consumer_state_mask);
631 while (!active_clients_bit_mask_->compare_exchange_weak(
632 current_active_clients_bit_mask, updated_active_clients_bit_mask,
633 std::memory_order_acq_rel, std::memory_order_acquire)) {
634 ALOGI(
635 "%s: Failed to remove consumer state mask. Current active clients bit "
636 "mask is changed to %" PRIu64
637 " when trying to acquire and modify it to %" PRIu64
638 ". About to try again.",
639 __FUNCTION__, current_active_clients_bit_mask,
640 updated_active_clients_bit_mask);
641 updated_active_clients_bit_mask =
642 current_active_clients_bit_mask & (~consumer_state_mask);
643 }
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700644
Tianyuf669f6a2018-10-10 15:34:32 -0700645 const uint64_t current_buffer_state =
646 buffer_state_->load(std::memory_order_acquire);
647 if (BufferHubDefs::IsClientPosted(current_buffer_state,
648 consumer_state_mask) ||
649 BufferHubDefs::IsClientAcquired(current_buffer_state,
650 consumer_state_mask)) {
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700651 // The consumer client is being destoryed without releasing. This could
652 // happen in corner cases when the consumer crashes. Here we mark it
653 // orphaned before remove it from producer.
Tianyuf669f6a2018-10-10 15:34:32 -0700654 OnConsumerOrphaned(consumer_state_mask);
655 return;
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700656 }
657
Tianyuf669f6a2018-10-10 15:34:32 -0700658 if (BufferHubDefs::IsClientReleased(current_buffer_state,
659 consumer_state_mask) ||
660 BufferHubDefs::AnyClientGained(current_buffer_state)) {
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700661 // The consumer is being close while it is suppose to signal a release
662 // fence. Signal the dummy fence here.
Tianyuf669f6a2018-10-10 15:34:32 -0700663 if (fence_state_->load(std::memory_order_acquire) & consumer_state_mask) {
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700664 epoll_event event;
665 event.events = EPOLLIN;
Tianyuf669f6a2018-10-10 15:34:32 -0700666 event.data.u64 = consumer_state_mask;
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700667 if (epoll_ctl(release_fence_fd_.Get(), EPOLL_CTL_MOD,
668 dummy_fence_fd_.Get(), &event) < 0) {
669 ALOGE(
Tianyuf669f6a2018-10-10 15:34:32 -0700670 "%s: Failed to modify the shared release fence to include the "
671 "dummy fence: %s",
672 __FUNCTION__, strerror(errno));
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700673 return;
674 }
Tianyuf669f6a2018-10-10 15:34:32 -0700675 ALOGW("%s: signal dummy release fence buffer_id=%d", __FUNCTION__,
676 buffer_id());
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700677 eventfd_write(dummy_fence_fd_.Get(), 1);
678 }
679 }
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800680}
681
Tianyuf669f6a2018-10-10 15:34:32 -0700682// Returns true if the given parameters match the underlying buffer
683// parameters.
Corey Tabakacd52dd92017-04-07 18:03:57 -0700684bool ProducerChannel::CheckParameters(uint32_t width, uint32_t height,
Hendrik Wagenaar108e84f2017-05-07 22:19:17 -0700685 uint32_t layer_count, uint32_t format,
Corey Tabaka52ea25c2017-09-13 18:02:48 -0700686 uint64_t usage,
687 size_t user_metadata_size) {
688 return user_metadata_size == user_metadata_size_ &&
689 buffer_.width() == width && buffer_.height() == height &&
690 buffer_.layer_count() == layer_count && buffer_.format() == format &&
691 buffer_.usage() == usage;
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800692}
693
694} // namespace dvr
695} // namespace android