• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 #include "producer_channel.h"
2 
3 #include <log/log.h>
4 #include <sync/sync.h>
5 #include <sys/epoll.h>
6 #include <sys/eventfd.h>
7 #include <sys/poll.h>
8 #include <utils/Trace.h>
9 
10 #include <algorithm>
11 #include <atomic>
12 #include <thread>
13 
14 #include <private/dvr/bufferhub_rpc.h>
15 #include "consumer_channel.h"
16 
17 using android::pdx::BorrowedHandle;
18 using android::pdx::ErrorStatus;
19 using android::pdx::Message;
20 using android::pdx::RemoteChannelHandle;
21 using android::pdx::Status;
22 using android::pdx::rpc::BufferWrapper;
23 using android::pdx::rpc::DispatchRemoteMethod;
24 using android::pdx::rpc::WrapBuffer;
25 
26 namespace android {
27 namespace dvr {
28 
29 namespace {
30 
FindNextClearedBit(uint64_t bits)31 static inline uint64_t FindNextClearedBit(uint64_t bits) {
32   return ~bits - (~bits & (~bits - 1));
33 }
34 
35 }  // namespace
36 
ProducerChannel(BufferHubService * service,int channel_id,uint32_t width,uint32_t height,uint32_t layer_count,uint32_t format,uint64_t usage,size_t user_metadata_size,int * error)37 ProducerChannel::ProducerChannel(BufferHubService* service, int channel_id,
38                                  uint32_t width, uint32_t height,
39                                  uint32_t layer_count, uint32_t format,
40                                  uint64_t usage, size_t user_metadata_size,
41                                  int* error)
42     : BufferHubChannel(service, channel_id, channel_id, kProducerType),
43       pending_consumers_(0),
44       producer_owns_(true),
45       user_metadata_size_(user_metadata_size),
46       metadata_buf_size_(BufferHubDefs::kMetadataHeaderSize +
47                          user_metadata_size) {
48   if (int ret = buffer_.Alloc(width, height, layer_count, format, usage)) {
49     ALOGE("ProducerChannel::ProducerChannel: Failed to allocate buffer: %s",
50           strerror(-ret));
51     *error = ret;
52     return;
53   }
54 
55   if (int ret = metadata_buffer_.Alloc(metadata_buf_size_, /*height=*/1,
56                                        /*layer_count=*/1,
57                                        BufferHubDefs::kMetadataFormat,
58                                        BufferHubDefs::kMetadataUsage)) {
59     ALOGE("ProducerChannel::ProducerChannel: Failed to allocate metadata: %s",
60           strerror(-ret));
61     *error = ret;
62     return;
63   }
64 
65   void* metadata_ptr = nullptr;
66   if (int ret = metadata_buffer_.Lock(BufferHubDefs::kMetadataUsage, /*x=*/0,
67                                       /*y=*/0, metadata_buf_size_,
68                                       /*height=*/1, &metadata_ptr)) {
69     ALOGE("ProducerChannel::ProducerChannel: Failed to lock metadata.");
70     *error = -ret;
71     return;
72   }
73   metadata_header_ =
74       reinterpret_cast<BufferHubDefs::MetadataHeader*>(metadata_ptr);
75 
76   // Using placement new here to reuse shared memory instead of new allocation
77   // and also initialize the value to zero.
78   buffer_state_ =
79       new (&metadata_header_->buffer_state) std::atomic<uint64_t>(0);
80   fence_state_ =
81       new (&metadata_header_->fence_state) std::atomic<uint64_t>(0);
82 
83   acquire_fence_fd_.Reset(epoll_create1(EPOLL_CLOEXEC));
84   release_fence_fd_.Reset(epoll_create1(EPOLL_CLOEXEC));
85   if (!acquire_fence_fd_ || !release_fence_fd_) {
86     ALOGE("ProducerChannel::ProducerChannel: Failed to create shared fences.");
87     *error = -EIO;
88     return;
89   }
90 
91   dummy_fence_fd_.Reset(eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK));
92   if (!dummy_fence_fd_) {
93     ALOGE("ProducerChannel::ProducerChannel: Failed to create dummy fences.");
94     *error = -EIO;
95     return;
96   }
97 
98   epoll_event event;
99   event.events = 0;
100   event.data.u64 = 0ULL;
101   if (epoll_ctl(release_fence_fd_.Get(), EPOLL_CTL_ADD, dummy_fence_fd_.Get(),
102                 &event) < 0) {
103     ALOGE(
104         "ProducerChannel::ProducerChannel: Failed to modify the shared "
105         "release fence to include the dummy fence: %s",
106         strerror(errno));
107     *error = -EIO;
108     return;
109   }
110 
111   // Success.
112   *error = 0;
113 }
114 
Create(BufferHubService * service,int channel_id,uint32_t width,uint32_t height,uint32_t layer_count,uint32_t format,uint64_t usage,size_t user_metadata_size)115 Status<std::shared_ptr<ProducerChannel>> ProducerChannel::Create(
116     BufferHubService* service, int channel_id, uint32_t width, uint32_t height,
117     uint32_t layer_count, uint32_t format, uint64_t usage,
118     size_t user_metadata_size) {
119   int error;
120   std::shared_ptr<ProducerChannel> producer(
121       new ProducerChannel(service, channel_id, width, height, layer_count,
122                           format, usage, user_metadata_size, &error));
123   if (error < 0)
124     return ErrorStatus(-error);
125   else
126     return {std::move(producer)};
127 }
128 
~ProducerChannel()129 ProducerChannel::~ProducerChannel() {
130   ALOGD_IF(TRACE,
131            "ProducerChannel::~ProducerChannel: channel_id=%d buffer_id=%d "
132            "state=%" PRIx64 ".",
133            channel_id(), buffer_id(), buffer_state_->load());
134   for (auto consumer : consumer_channels_)
135     consumer->OnProducerClosed();
136 }
137 
GetBufferInfo() const138 BufferHubChannel::BufferInfo ProducerChannel::GetBufferInfo() const {
139   // Derive the mask of signaled buffers in this producer / consumer set.
140   uint64_t signaled_mask = signaled() ? BufferHubDefs::kProducerStateBit : 0;
141   for (const ConsumerChannel* consumer : consumer_channels_) {
142     signaled_mask |= consumer->signaled() ? consumer->consumer_state_bit() : 0;
143   }
144 
145   return BufferInfo(buffer_id(), consumer_channels_.size(), buffer_.width(),
146                     buffer_.height(), buffer_.layer_count(), buffer_.format(),
147                     buffer_.usage(), pending_consumers_, buffer_state_->load(),
148                     signaled_mask, metadata_header_->queue_index, name_);
149 }
150 
HandleImpulse(Message & message)151 void ProducerChannel::HandleImpulse(Message& message) {
152   ATRACE_NAME("ProducerChannel::HandleImpulse");
153   switch (message.GetOp()) {
154     case BufferHubRPC::ProducerGain::Opcode:
155       OnProducerGain(message);
156       break;
157     case BufferHubRPC::ProducerPost::Opcode:
158       OnProducerPost(message, {});
159       break;
160   }
161 }
162 
HandleMessage(Message & message)163 bool ProducerChannel::HandleMessage(Message& message) {
164   ATRACE_NAME("ProducerChannel::HandleMessage");
165   switch (message.GetOp()) {
166     case BufferHubRPC::GetBuffer::Opcode:
167       DispatchRemoteMethod<BufferHubRPC::GetBuffer>(
168           *this, &ProducerChannel::OnGetBuffer, message);
169       return true;
170 
171     case BufferHubRPC::NewConsumer::Opcode:
172       DispatchRemoteMethod<BufferHubRPC::NewConsumer>(
173           *this, &ProducerChannel::OnNewConsumer, message);
174       return true;
175 
176     case BufferHubRPC::ProducerPost::Opcode:
177       DispatchRemoteMethod<BufferHubRPC::ProducerPost>(
178           *this, &ProducerChannel::OnProducerPost, message);
179       return true;
180 
181     case BufferHubRPC::ProducerGain::Opcode:
182       DispatchRemoteMethod<BufferHubRPC::ProducerGain>(
183           *this, &ProducerChannel::OnProducerGain, message);
184       return true;
185 
186     case BufferHubRPC::ProducerMakePersistent::Opcode:
187       DispatchRemoteMethod<BufferHubRPC::ProducerMakePersistent>(
188           *this, &ProducerChannel::OnProducerMakePersistent, message);
189       return true;
190 
191     case BufferHubRPC::ProducerRemovePersistence::Opcode:
192       DispatchRemoteMethod<BufferHubRPC::ProducerRemovePersistence>(
193           *this, &ProducerChannel::OnRemovePersistence, message);
194       return true;
195 
196     default:
197       return false;
198   }
199 }
200 
GetBuffer(uint64_t buffer_state_bit)201 BufferDescription<BorrowedHandle> ProducerChannel::GetBuffer(
202     uint64_t buffer_state_bit) {
203   return {
204       buffer_,          metadata_buffer_,           buffer_id(),
205       buffer_state_bit, acquire_fence_fd_.Borrow(), release_fence_fd_.Borrow()};
206 }
207 
OnGetBuffer(Message &)208 Status<BufferDescription<BorrowedHandle>> ProducerChannel::OnGetBuffer(
209     Message& /*message*/) {
210   ATRACE_NAME("ProducerChannel::OnGetBuffer");
211   ALOGD_IF(TRACE, "ProducerChannel::OnGetBuffer: buffer=%d, state=%" PRIx64 ".",
212            buffer_id(), buffer_state_->load());
213   return {GetBuffer(BufferHubDefs::kProducerStateBit)};
214 }
215 
CreateConsumer(Message & message)216 Status<RemoteChannelHandle> ProducerChannel::CreateConsumer(Message& message) {
217   ATRACE_NAME("ProducerChannel::CreateConsumer");
218   ALOGD_IF(TRACE,
219            "ProducerChannel::CreateConsumer: buffer_id=%d, producer_owns=%d",
220            buffer_id(), producer_owns_);
221 
222   int channel_id;
223   auto status = message.PushChannel(0, nullptr, &channel_id);
224   if (!status) {
225     ALOGE(
226         "ProducerChannel::CreateConsumer: Failed to push consumer channel: %s",
227         status.GetErrorMessage().c_str());
228     return ErrorStatus(ENOMEM);
229   }
230 
231   // Try find the next consumer state bit which has not been claimed by any
232   // consumer yet.
233   uint64_t consumer_state_bit = FindNextClearedBit(
234       active_consumer_bit_mask_ | orphaned_consumer_bit_mask_ |
235       BufferHubDefs::kProducerStateBit);
236   if (consumer_state_bit == 0ULL) {
237     ALOGE(
238         "ProducerChannel::CreateConsumer: reached the maximum mumber of "
239         "consumers per producer: 63.");
240     return ErrorStatus(E2BIG);
241   }
242 
243   auto consumer =
244       std::make_shared<ConsumerChannel>(service(), buffer_id(), channel_id,
245                                         consumer_state_bit, shared_from_this());
246   const auto channel_status = service()->SetChannel(channel_id, consumer);
247   if (!channel_status) {
248     ALOGE(
249         "ProducerChannel::CreateConsumer: failed to set new consumer channel: "
250         "%s",
251         channel_status.GetErrorMessage().c_str());
252     return ErrorStatus(ENOMEM);
253   }
254 
255   if (!producer_owns_ &&
256       !BufferHubDefs::IsBufferReleased(buffer_state_->load())) {
257     // Signal the new consumer when adding it to a posted producer.
258     if (consumer->OnProducerPosted())
259       pending_consumers_++;
260   }
261 
262   active_consumer_bit_mask_ |= consumer_state_bit;
263   return {status.take()};
264 }
265 
OnNewConsumer(Message & message)266 Status<RemoteChannelHandle> ProducerChannel::OnNewConsumer(Message& message) {
267   ATRACE_NAME("ProducerChannel::OnNewConsumer");
268   ALOGD_IF(TRACE, "ProducerChannel::OnNewConsumer: buffer_id=%d", buffer_id());
269   return CreateConsumer(message);
270 }
271 
OnProducerPost(Message &,LocalFence acquire_fence)272 Status<void> ProducerChannel::OnProducerPost(
273     Message&, LocalFence acquire_fence) {
274   ATRACE_NAME("ProducerChannel::OnProducerPost");
275   ALOGD_IF(TRACE, "ProducerChannel::OnProducerPost: buffer_id=%d", buffer_id());
276   if (!producer_owns_) {
277     ALOGE("ProducerChannel::OnProducerPost: Not in gained state!");
278     return ErrorStatus(EBUSY);
279   }
280 
281   epoll_event event;
282   event.events = 0;
283   event.data.u64 = 0ULL;
284   int ret = epoll_ctl(release_fence_fd_.Get(), EPOLL_CTL_MOD,
285                       dummy_fence_fd_.Get(), &event);
286   ALOGE_IF(ret < 0,
287       "ProducerChannel::OnProducerPost: Failed to modify the shared "
288       "release fence to include the dummy fence: %s",
289       strerror(errno));
290 
291   eventfd_t dummy_fence_count = 0ULL;
292   if (eventfd_read(dummy_fence_fd_.Get(), &dummy_fence_count) < 0) {
293     const int error = errno;
294     if (error != EAGAIN) {
295       ALOGE(
296           "ProducerChannel::ProducerChannel: Failed to read dummy fence, "
297           "error: %s",
298           strerror(error));
299       return ErrorStatus(error);
300     }
301   }
302 
303   ALOGW_IF(dummy_fence_count > 0,
304            "ProducerChannel::ProducerChannel: %" PRIu64
305            " dummy fence(s) was signaled during last release/gain cycle "
306            "buffer_id=%d.",
307            dummy_fence_count, buffer_id());
308 
309   post_fence_ = std::move(acquire_fence);
310   producer_owns_ = false;
311 
312   // Signal any interested consumers. If there are none, the buffer will stay
313   // in posted state until a consumer comes online. This behavior guarantees
314   // that no frame is silently dropped.
315   pending_consumers_ = 0;
316   for (auto consumer : consumer_channels_) {
317     if (consumer->OnProducerPosted())
318       pending_consumers_++;
319   }
320   ALOGD_IF(TRACE, "ProducerChannel::OnProducerPost: %d pending consumers",
321            pending_consumers_);
322 
323   return {};
324 }
325 
OnProducerGain(Message &)326 Status<LocalFence> ProducerChannel::OnProducerGain(Message& /*message*/) {
327   ATRACE_NAME("ProducerChannel::OnGain");
328   ALOGD_IF(TRACE, "ProducerChannel::OnGain: buffer_id=%d", buffer_id());
329   if (producer_owns_) {
330     ALOGE("ProducerChanneL::OnGain: Already in gained state: channel=%d",
331           channel_id());
332     return ErrorStatus(EALREADY);
333   }
334 
335   // There are still pending consumers, return busy.
336   if (pending_consumers_ > 0) {
337     ALOGE(
338         "ProducerChannel::OnGain: Producer (id=%d) is gaining a buffer that "
339         "still has %d pending consumer(s).",
340         buffer_id(), pending_consumers_);
341     return ErrorStatus(EBUSY);
342   }
343 
344   ClearAvailable();
345   producer_owns_ = true;
346   post_fence_.close();
347   return {std::move(returned_fence_)};
348 }
349 
OnConsumerAcquire(Message &)350 Status<LocalFence> ProducerChannel::OnConsumerAcquire(Message& /*message*/) {
351   ATRACE_NAME("ProducerChannel::OnConsumerAcquire");
352   ALOGD_IF(TRACE, "ProducerChannel::OnConsumerAcquire: buffer_id=%d",
353            buffer_id());
354   if (producer_owns_) {
355     ALOGE("ProducerChannel::OnConsumerAcquire: Not in posted state!");
356     return ErrorStatus(EBUSY);
357   }
358 
359   // Return a borrowed fd to avoid unnecessary duplication of the underlying fd.
360   // Serialization just needs to read the handle.
361   return {std::move(post_fence_)};
362 }
363 
OnConsumerRelease(Message &,LocalFence release_fence)364 Status<void> ProducerChannel::OnConsumerRelease(Message&,
365                                                 LocalFence release_fence) {
366   ATRACE_NAME("ProducerChannel::OnConsumerRelease");
367   ALOGD_IF(TRACE, "ProducerChannel::OnConsumerRelease: buffer_id=%d",
368            buffer_id());
369   if (producer_owns_) {
370     ALOGE("ProducerChannel::OnConsumerRelease: Not in acquired state!");
371     return ErrorStatus(EBUSY);
372   }
373 
374   // Attempt to merge the fences if necessary.
375   if (release_fence) {
376     if (returned_fence_) {
377       LocalFence merged_fence(sync_merge("bufferhub_merged",
378                                          returned_fence_.get_fd(),
379                                          release_fence.get_fd()));
380       const int error = errno;
381       if (!merged_fence) {
382         ALOGE("ProducerChannel::OnConsumerRelease: Failed to merge fences: %s",
383               strerror(error));
384         return ErrorStatus(error);
385       }
386       returned_fence_ = std::move(merged_fence);
387     } else {
388       returned_fence_ = std::move(release_fence);
389     }
390   }
391 
392   OnConsumerIgnored();
393   if (pending_consumers_ == 0) {
394     // Clear the producer bit atomically to transit into released state. This
395     // has to done by BufferHub as it requries synchronization among all
396     // consumers.
397     BufferHubDefs::ModifyBufferState(buffer_state_,
398                                      BufferHubDefs::kProducerStateBit, 0ULL);
399     ALOGD_IF(TRACE,
400              "ProducerChannel::OnConsumerRelease: releasing last consumer: "
401              "buffer_id=%d state=%" PRIx64 ".",
402              buffer_id(), buffer_state_->load());
403 
404     if (orphaned_consumer_bit_mask_) {
405       ALOGW(
406           "ProducerChannel::OnConsumerRelease: orphaned buffer detected "
407           "during the this acquire/release cycle: id=%d orphaned=0x%" PRIx64
408           " queue_index=%" PRIu64 ".",
409           buffer_id(), orphaned_consumer_bit_mask_,
410           metadata_header_->queue_index);
411       orphaned_consumer_bit_mask_ = 0;
412     }
413 
414     SignalAvailable();
415   }
416 
417   ALOGE_IF(pending_consumers_ &&
418                BufferHubDefs::IsBufferReleased(buffer_state_->load()),
419            "ProducerChannel::OnConsumerRelease: buffer state inconsistent: "
420            "pending_consumers=%d, buffer buffer is in releaed state.",
421            pending_consumers_);
422   return {};
423 }
424 
OnConsumerIgnored()425 void ProducerChannel::OnConsumerIgnored() {
426   if (pending_consumers_ == 0) {
427     ALOGE("ProducerChannel::OnConsumerIgnored: no pending consumer.");
428     return;
429   }
430 
431   --pending_consumers_;
432   ALOGD_IF(TRACE,
433            "ProducerChannel::OnConsumerIgnored: buffer_id=%d %d consumers left",
434            buffer_id(), pending_consumers_);
435 }
436 
OnConsumerOrphaned(ConsumerChannel * channel)437 void ProducerChannel::OnConsumerOrphaned(ConsumerChannel* channel) {
438   // Ignore the orphaned consumer.
439   OnConsumerIgnored();
440 
441   const uint64_t consumer_state_bit = channel->consumer_state_bit();
442   ALOGE_IF(orphaned_consumer_bit_mask_ & consumer_state_bit,
443            "ProducerChannel::OnConsumerOrphaned: Consumer "
444            "(consumer_state_bit=%" PRIx64 ") is already orphaned.",
445            consumer_state_bit);
446   orphaned_consumer_bit_mask_ |= consumer_state_bit;
447 
448   // Atomically clear the fence state bit as an orphaned consumer will never
449   // signal a release fence. Also clear the buffer state as it won't be released
450   // as well.
451   fence_state_->fetch_and(~consumer_state_bit);
452   BufferHubDefs::ModifyBufferState(buffer_state_, consumer_state_bit, 0ULL);
453 
454   ALOGW(
455       "ProducerChannel::OnConsumerOrphaned: detected new orphaned consumer "
456       "buffer_id=%d consumer_state_bit=%" PRIx64 " queue_index=%" PRIu64
457       " buffer_state=%" PRIx64 " fence_state=%" PRIx64 ".",
458       buffer_id(), consumer_state_bit, metadata_header_->queue_index,
459       buffer_state_->load(), fence_state_->load());
460 }
461 
OnProducerMakePersistent(Message & message,const std::string & name,int user_id,int group_id)462 Status<void> ProducerChannel::OnProducerMakePersistent(Message& message,
463                                                        const std::string& name,
464                                                        int user_id,
465                                                        int group_id) {
466   ATRACE_NAME("ProducerChannel::OnProducerMakePersistent");
467   ALOGD_IF(TRACE,
468            "ProducerChannel::OnProducerMakePersistent: buffer_id=%d name=%s "
469            "user_id=%d group_id=%d",
470            buffer_id(), name.c_str(), user_id, group_id);
471 
472   if (name.empty() || (user_id < 0 && user_id != kNoCheckId) ||
473       (group_id < 0 && group_id != kNoCheckId)) {
474     return ErrorStatus(EINVAL);
475   }
476 
477   // Try to add this buffer with the requested name.
478   if (service()->AddNamedBuffer(name, std::static_pointer_cast<ProducerChannel>(
479                                           shared_from_this()))) {
480     // If successful, set the requested permissions.
481 
482     // A value of zero indicates that the ids from the sending process should be
483     // used.
484     if (user_id == kUseCallerId)
485       user_id = message.GetEffectiveUserId();
486     if (group_id == kUseCallerId)
487       group_id = message.GetEffectiveGroupId();
488 
489     owner_user_id_ = user_id;
490     owner_group_id_ = group_id;
491     name_ = name;
492     return {};
493   } else {
494     // Otherwise a buffer with that name already exists.
495     return ErrorStatus(EALREADY);
496   }
497 }
498 
OnRemovePersistence(Message &)499 Status<void> ProducerChannel::OnRemovePersistence(Message&) {
500   if (service()->RemoveNamedBuffer(*this))
501     return {};
502   else
503     return ErrorStatus(ENOENT);
504 }
505 
AddConsumer(ConsumerChannel * channel)506 void ProducerChannel::AddConsumer(ConsumerChannel* channel) {
507   consumer_channels_.push_back(channel);
508 }
509 
RemoveConsumer(ConsumerChannel * channel)510 void ProducerChannel::RemoveConsumer(ConsumerChannel* channel) {
511   consumer_channels_.erase(
512       std::find(consumer_channels_.begin(), consumer_channels_.end(), channel));
513   active_consumer_bit_mask_ &= ~channel->consumer_state_bit();
514 
515   const uint64_t buffer_state = buffer_state_->load();
516   if (BufferHubDefs::IsBufferPosted(buffer_state) ||
517       BufferHubDefs::IsBufferAcquired(buffer_state)) {
518     // The consumer client is being destoryed without releasing. This could
519     // happen in corner cases when the consumer crashes. Here we mark it
520     // orphaned before remove it from producer.
521     OnConsumerOrphaned(channel);
522   }
523 
524   if (BufferHubDefs::IsBufferReleased(buffer_state) ||
525       BufferHubDefs::IsBufferGained(buffer_state)) {
526     // The consumer is being close while it is suppose to signal a release
527     // fence. Signal the dummy fence here.
528     if (fence_state_->load() & channel->consumer_state_bit()) {
529       epoll_event event;
530       event.events = EPOLLIN;
531       event.data.u64 = channel->consumer_state_bit();
532       if (epoll_ctl(release_fence_fd_.Get(), EPOLL_CTL_MOD,
533                     dummy_fence_fd_.Get(), &event) < 0) {
534         ALOGE(
535             "ProducerChannel::RemoveConsumer: Failed to modify the shared "
536             "release fence to include the dummy fence: %s",
537             strerror(errno));
538         return;
539       }
540       ALOGW(
541           "ProducerChannel::RemoveConsumer: signal dummy release fence "
542           "buffer_id=%d",
543           buffer_id());
544       eventfd_write(dummy_fence_fd_.Get(), 1);
545     }
546   }
547 }
548 
549 // Returns true if either the user or group ids match the owning ids or both
550 // owning ids are not set, in which case access control does not apply.
CheckAccess(int euid,int egid)551 bool ProducerChannel::CheckAccess(int euid, int egid) {
552   const bool no_check =
553       owner_user_id_ == kNoCheckId && owner_group_id_ == kNoCheckId;
554   const bool euid_check = euid == owner_user_id_ || euid == kRootId;
555   const bool egid_check = egid == owner_group_id_ || egid == kRootId;
556   return no_check || euid_check || egid_check;
557 }
558 
559 // Returns true if the given parameters match the underlying buffer parameters.
CheckParameters(uint32_t width,uint32_t height,uint32_t layer_count,uint32_t format,uint64_t usage,size_t user_metadata_size)560 bool ProducerChannel::CheckParameters(uint32_t width, uint32_t height,
561                                       uint32_t layer_count, uint32_t format,
562                                       uint64_t usage,
563                                       size_t user_metadata_size) {
564   return user_metadata_size == user_metadata_size_ &&
565          buffer_.width() == width && buffer_.height() == height &&
566          buffer_.layer_count() == layer_count && buffer_.format() == format &&
567          buffer_.usage() == usage;
568 }
569 
570 }  // namespace dvr
571 }  // namespace android
572