1 #include <private/dvr/buffer_hub_client.h>
2 
3 #include <log/log.h>
4 #include <poll.h>
5 #include <sys/epoll.h>
6 #include <utils/Trace.h>
7 
8 #include <mutex>
9 
10 #include <pdx/default_transport/client_channel.h>
11 #include <pdx/default_transport/client_channel_factory.h>
12 
13 #include "include/private/dvr/bufferhub_rpc.h"
14 
15 using android::pdx::LocalChannelHandle;
16 using android::pdx::LocalHandle;
17 using android::pdx::Status;
18 using android::pdx::default_transport::ClientChannel;
19 using android::pdx::default_transport::ClientChannelFactory;
20 
21 namespace android {
22 namespace dvr {
23 
BufferHubClient()24 BufferHubClient::BufferHubClient()
25     : Client(ClientChannelFactory::Create(BufferHubRPC::kClientPath)) {}
26 
BufferHubClient(LocalChannelHandle channel_handle)27 BufferHubClient::BufferHubClient(LocalChannelHandle channel_handle)
28     : Client(ClientChannel::Create(std::move(channel_handle))) {}
29 
IsValid() const30 bool BufferHubClient::IsValid() const {
31   return IsConnected() && GetChannelHandle().valid();
32 }
33 
TakeChannelHandle()34 LocalChannelHandle BufferHubClient::TakeChannelHandle() {
35   if (IsConnected()) {
36     return std::move(GetChannelHandle());
37   } else {
38     return {};
39   }
40 }
41 
BufferHubBuffer(LocalChannelHandle channel_handle)42 BufferHubBuffer::BufferHubBuffer(LocalChannelHandle channel_handle)
43     : Client{pdx::default_transport::ClientChannel::Create(
44           std::move(channel_handle))},
45       id_(-1) {}
BufferHubBuffer(const std::string & endpoint_path)46 BufferHubBuffer::BufferHubBuffer(const std::string& endpoint_path)
47     : Client{pdx::default_transport::ClientChannelFactory::Create(
48           endpoint_path)},
49       id_(-1) {}
50 
~BufferHubBuffer()51 BufferHubBuffer::~BufferHubBuffer() {
52   if (metadata_header_ != nullptr) {
53     metadata_buffer_.Unlock();
54   }
55 }
56 
CreateConsumer()57 Status<LocalChannelHandle> BufferHubBuffer::CreateConsumer() {
58   Status<LocalChannelHandle> status =
59       InvokeRemoteMethod<BufferHubRPC::NewConsumer>();
60   ALOGE_IF(!status,
61            "BufferHub::CreateConsumer: Failed to create consumer channel: %s",
62            status.GetErrorMessage().c_str());
63   return status;
64 }
65 
ImportBuffer()66 int BufferHubBuffer::ImportBuffer() {
67   ATRACE_NAME("BufferHubBuffer::ImportBuffer");
68 
69   Status<BufferDescription<LocalHandle>> status =
70       InvokeRemoteMethod<BufferHubRPC::GetBuffer>();
71   if (!status) {
72     ALOGE("BufferHubBuffer::ImportBuffer: Failed to get buffer: %s",
73           status.GetErrorMessage().c_str());
74     return -status.error();
75   } else if (status.get().id() < 0) {
76     ALOGE("BufferHubBuffer::ImportBuffer: Received an invalid id!");
77     return -EIO;
78   }
79 
80   auto buffer_desc = status.take();
81 
82   // Stash the buffer id to replace the value in id_.
83   const int new_id = buffer_desc.id();
84 
85   // Import the buffer.
86   IonBuffer ion_buffer;
87   ALOGD_IF(TRACE, "BufferHubBuffer::ImportBuffer: id=%d.", buffer_desc.id());
88 
89   if (const int ret = buffer_desc.ImportBuffer(&ion_buffer))
90     return ret;
91 
92   // Import the metadata.
93   IonBuffer metadata_buffer;
94   if (const int ret = buffer_desc.ImportMetadata(&metadata_buffer)) {
95     ALOGE("Failed to import metadata buffer, error=%d", ret);
96     return ret;
97   }
98   size_t metadata_buf_size = metadata_buffer.width();
99   if (metadata_buf_size < BufferHubDefs::kMetadataHeaderSize) {
100     ALOGE("BufferHubBuffer::ImportBuffer: metadata buffer too small: %zu",
101           metadata_buf_size);
102     return -ENOMEM;
103   }
104 
105   // If all imports succee, replace the previous buffer and id.
106   buffer_ = std::move(ion_buffer);
107   metadata_buffer_ = std::move(metadata_buffer);
108   metadata_buf_size_ = metadata_buf_size;
109   user_metadata_size_ = metadata_buf_size_ - BufferHubDefs::kMetadataHeaderSize;
110 
111   void* metadata_ptr = nullptr;
112   if (const int ret =
113           metadata_buffer_.Lock(BufferHubDefs::kMetadataUsage, /*x=*/0,
114                                 /*y=*/0, metadata_buf_size_,
115                                 /*height=*/1, &metadata_ptr)) {
116     ALOGE("BufferHubBuffer::ImportBuffer: Failed to lock metadata.");
117     return ret;
118   }
119 
120   // Set up shared fences.
121   shared_acquire_fence_ = buffer_desc.take_acquire_fence();
122   shared_release_fence_ = buffer_desc.take_release_fence();
123   if (!shared_acquire_fence_ || !shared_release_fence_) {
124     ALOGE("BufferHubBuffer::ImportBuffer: Failed to import shared fences.");
125     return -EIO;
126   }
127 
128   metadata_header_ =
129       reinterpret_cast<BufferHubDefs::MetadataHeader*>(metadata_ptr);
130   if (user_metadata_size_) {
131     user_metadata_ptr_ =
132         reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(metadata_ptr) +
133                                 BufferHubDefs::kMetadataHeaderSize);
134   } else {
135     user_metadata_ptr_ = nullptr;
136   }
137 
138   id_ = new_id;
139   buffer_state_bit_ = buffer_desc.buffer_state_bit();
140 
141   // Note that here the buffer state is mapped from shared memory as an atomic
142   // object. The std::atomic's constructor will not be called so that the
143   // original value stored in the memory region will be preserved.
144   buffer_state_ = &metadata_header_->buffer_state;
145   ALOGD_IF(TRACE,
146            "BufferHubBuffer::ImportBuffer: id=%d, buffer_state=%" PRIx64 ".",
147            id(), buffer_state_->load());
148   fence_state_ = &metadata_header_->fence_state;
149   ALOGD_IF(TRACE,
150            "BufferHubBuffer::ImportBuffer: id=%d, fence_state=%" PRIx64 ".",
151            id(), fence_state_->load());
152 
153   return 0;
154 }
155 
CheckMetadata(size_t user_metadata_size) const156 inline int BufferHubBuffer::CheckMetadata(size_t user_metadata_size) const {
157   if (user_metadata_size && !user_metadata_ptr_) {
158     ALOGE("BufferHubBuffer::CheckMetadata: doesn't support custom metadata.");
159     return -EINVAL;
160   }
161   if (user_metadata_size > user_metadata_size_) {
162     ALOGE("BufferHubBuffer::CheckMetadata: too big: %zu, maximum: %zu.",
163           user_metadata_size, user_metadata_size_);
164     return -E2BIG;
165   }
166   return 0;
167 }
168 
UpdateSharedFence(const LocalHandle & new_fence,const LocalHandle & shared_fence)169 int BufferHubBuffer::UpdateSharedFence(const LocalHandle& new_fence,
170                                        const LocalHandle& shared_fence) {
171   if (pending_fence_fd_.Get() != new_fence.Get()) {
172     // First, replace the old fd if there was already one. Skipping if the new
173     // one is the same as the old.
174     if (pending_fence_fd_.IsValid()) {
175       const int ret = epoll_ctl(shared_fence.Get(), EPOLL_CTL_DEL,
176                                 pending_fence_fd_.Get(), nullptr);
177       ALOGW_IF(ret,
178                "BufferHubBuffer::UpdateSharedFence: failed to remove old fence "
179                "fd from epoll set, error: %s.",
180                strerror(errno));
181     }
182 
183     if (new_fence.IsValid()) {
184       // If ready fence is valid, we put that into the epoll set.
185       epoll_event event;
186       event.events = EPOLLIN;
187       event.data.u64 = buffer_state_bit();
188       pending_fence_fd_ = new_fence.Duplicate();
189       if (epoll_ctl(shared_fence.Get(), EPOLL_CTL_ADD, pending_fence_fd_.Get(),
190                     &event) < 0) {
191         const int error = errno;
192         ALOGE(
193             "BufferHubBuffer::UpdateSharedFence: failed to add new fence fd "
194             "into epoll set, error: %s.",
195             strerror(error));
196         return -error;
197       }
198       // Set bit in fence state to indicate that there is a fence from this
199       // producer or consumer.
200       fence_state_->fetch_or(buffer_state_bit());
201     } else {
202       // Unset bit in fence state to indicate that there is no fence, so that
203       // when consumer to acquire or producer to acquire, it knows no need to
204       // check fence for this buffer.
205       fence_state_->fetch_and(~buffer_state_bit());
206     }
207   }
208 
209   return 0;
210 }
211 
Poll(int timeout_ms)212 int BufferHubBuffer::Poll(int timeout_ms) {
213   ATRACE_NAME("BufferHubBuffer::Poll");
214   pollfd p = {event_fd(), POLLIN, 0};
215   return poll(&p, 1, timeout_ms);
216 }
217 
Lock(int usage,int x,int y,int width,int height,void ** address)218 int BufferHubBuffer::Lock(int usage, int x, int y, int width, int height,
219                           void** address) {
220   return buffer_.Lock(usage, x, y, width, height, address);
221 }
222 
Unlock()223 int BufferHubBuffer::Unlock() { return buffer_.Unlock(); }
224 
GetBlobReadWritePointer(size_t size,void ** addr)225 int BufferHubBuffer::GetBlobReadWritePointer(size_t size, void** addr) {
226   int width = static_cast<int>(size);
227   int height = 1;
228   int ret = Lock(usage(), 0, 0, width, height, addr);
229   if (ret == 0)
230     Unlock();
231   return ret;
232 }
233 
GetBlobReadOnlyPointer(size_t size,void ** addr)234 int BufferHubBuffer::GetBlobReadOnlyPointer(size_t size, void** addr) {
235   return GetBlobReadWritePointer(size, addr);
236 }
237 
GetBlobFds(int * fds,size_t * fds_count,size_t max_fds_count) const238 void BufferHubBuffer::GetBlobFds(int* fds, size_t* fds_count,
239                                  size_t max_fds_count) const {
240   size_t numFds = static_cast<size_t>(native_handle()->numFds);
241   *fds_count = std::min(max_fds_count, numFds);
242   std::copy(native_handle()->data, native_handle()->data + *fds_count, fds);
243 }
244 
BufferConsumer(LocalChannelHandle channel)245 BufferConsumer::BufferConsumer(LocalChannelHandle channel)
246     : BASE(std::move(channel)) {
247   const int ret = ImportBuffer();
248   if (ret < 0) {
249     ALOGE("BufferConsumer::BufferConsumer: Failed to import buffer: %s",
250           strerror(-ret));
251     Close(ret);
252   }
253 }
254 
Import(LocalChannelHandle channel)255 std::unique_ptr<BufferConsumer> BufferConsumer::Import(
256     LocalChannelHandle channel) {
257   ATRACE_NAME("BufferConsumer::Import");
258   ALOGD_IF(TRACE, "BufferConsumer::Import: channel=%d", channel.value());
259   return BufferConsumer::Create(std::move(channel));
260 }
261 
Import(Status<LocalChannelHandle> status)262 std::unique_ptr<BufferConsumer> BufferConsumer::Import(
263     Status<LocalChannelHandle> status) {
264   return Import(status ? status.take()
265                        : LocalChannelHandle{nullptr, -status.error()});
266 }
267 
LocalAcquire(DvrNativeBufferMetadata * out_meta,LocalHandle * out_fence)268 int BufferConsumer::LocalAcquire(DvrNativeBufferMetadata* out_meta,
269                                  LocalHandle* out_fence) {
270   if (!out_meta)
271     return -EINVAL;
272 
273   // Only check producer bit and this consumer buffer's particular consumer bit.
274   // The buffer is can be acquired iff: 1) producer bit is set; 2) consumer bit
275   // is not set.
276   uint64_t buffer_state = buffer_state_->load();
277   if (!BufferHubDefs::IsBufferPosted(buffer_state, buffer_state_bit())) {
278     ALOGE("BufferConsumer::LocalAcquire: not posted, id=%d state=%" PRIx64
279           " buffer_state_bit=%" PRIx64 ".",
280           id(), buffer_state, buffer_state_bit());
281     return -EBUSY;
282   }
283 
284   // Copy the canonical metadata.
285   void* metadata_ptr = reinterpret_cast<void*>(&metadata_header_->metadata);
286   memcpy(out_meta, metadata_ptr, sizeof(DvrNativeBufferMetadata));
287   // Fill in the user_metadata_ptr in address space of the local process.
288   if (out_meta->user_metadata_size) {
289     out_meta->user_metadata_ptr =
290         reinterpret_cast<uint64_t>(user_metadata_ptr_);
291   } else {
292     out_meta->user_metadata_ptr = 0;
293   }
294 
295   uint64_t fence_state = fence_state_->load();
296   // If there is an acquire fence from producer, we need to return it.
297   if (fence_state & BufferHubDefs::kProducerStateBit) {
298     *out_fence = shared_acquire_fence_.Duplicate();
299   }
300 
301   // Set the consumer bit unique to this consumer.
302   BufferHubDefs::ModifyBufferState(buffer_state_, 0ULL, buffer_state_bit());
303   return 0;
304 }
305 
Acquire(LocalHandle * ready_fence)306 int BufferConsumer::Acquire(LocalHandle* ready_fence) {
307   return Acquire(ready_fence, nullptr, 0);
308 }
309 
Acquire(LocalHandle * ready_fence,void * meta,size_t user_metadata_size)310 int BufferConsumer::Acquire(LocalHandle* ready_fence, void* meta,
311                             size_t user_metadata_size) {
312   ATRACE_NAME("BufferConsumer::Acquire");
313 
314   if (const int error = CheckMetadata(user_metadata_size))
315     return error;
316 
317   DvrNativeBufferMetadata canonical_meta;
318   if (const int error = LocalAcquire(&canonical_meta, ready_fence))
319     return error;
320 
321   if (meta && user_metadata_size) {
322     void* metadata_src =
323         reinterpret_cast<void*>(canonical_meta.user_metadata_ptr);
324     if (metadata_src) {
325       memcpy(meta, metadata_src, user_metadata_size);
326     } else {
327       ALOGW("BufferConsumer::Acquire: no user-defined metadata.");
328     }
329   }
330 
331   auto status = InvokeRemoteMethod<BufferHubRPC::ConsumerAcquire>();
332   if (!status)
333     return -status.error();
334   return 0;
335 }
336 
AcquireAsync(DvrNativeBufferMetadata * out_meta,LocalHandle * out_fence)337 int BufferConsumer::AcquireAsync(DvrNativeBufferMetadata* out_meta,
338                                  LocalHandle* out_fence) {
339   ATRACE_NAME("BufferConsumer::AcquireAsync");
340 
341   if (const int error = LocalAcquire(out_meta, out_fence))
342     return error;
343 
344   auto status = SendImpulse(BufferHubRPC::ConsumerAcquire::Opcode);
345   if (!status)
346     return -status.error();
347   return 0;
348 }
349 
LocalRelease(const DvrNativeBufferMetadata * meta,const LocalHandle & release_fence)350 int BufferConsumer::LocalRelease(const DvrNativeBufferMetadata* meta,
351                                  const LocalHandle& release_fence) {
352   if (const int error = CheckMetadata(meta->user_metadata_size))
353     return error;
354 
355   // Check invalid state transition.
356   uint64_t buffer_state = buffer_state_->load();
357   if (!BufferHubDefs::IsBufferAcquired(buffer_state)) {
358     ALOGE("BufferConsumer::LocalRelease: not acquired id=%d state=%" PRIx64 ".",
359           id(), buffer_state);
360     return -EBUSY;
361   }
362 
363   // On release, only the user requested metadata is copied back into the shared
364   // memory for metadata. Since there are multiple consumers, it doesn't make
365   // sense to send the canonical metadata back to the producer. However, one of
366   // the consumer can still choose to write up to user_metadata_size bytes of
367   // data into user_metadata_ptr.
368   if (meta->user_metadata_ptr && meta->user_metadata_size) {
369     void* metadata_src = reinterpret_cast<void*>(meta->user_metadata_ptr);
370     memcpy(user_metadata_ptr_, metadata_src, meta->user_metadata_size);
371   }
372 
373   // Send out the release fence through the shared epoll fd. Note that during
374   // releasing the producer is not expected to be polling on the fence.
375   if (const int error = UpdateSharedFence(release_fence, shared_release_fence_))
376     return error;
377 
378   // For release operation, the client don't need to change the state as it's
379   // bufferhubd's job to flip the produer bit once all consumers are released.
380   return 0;
381 }
382 
Release(const LocalHandle & release_fence)383 int BufferConsumer::Release(const LocalHandle& release_fence) {
384   ATRACE_NAME("BufferConsumer::Release");
385 
386   DvrNativeBufferMetadata meta;
387   if (const int error = LocalRelease(&meta, release_fence))
388     return error;
389 
390   return ReturnStatusOrError(InvokeRemoteMethod<BufferHubRPC::ConsumerRelease>(
391       BorrowedFence(release_fence.Borrow())));
392 }
393 
ReleaseAsync()394 int BufferConsumer::ReleaseAsync() {
395   DvrNativeBufferMetadata meta;
396   return ReleaseAsync(&meta, LocalHandle());
397 }
398 
ReleaseAsync(const DvrNativeBufferMetadata * meta,const LocalHandle & release_fence)399 int BufferConsumer::ReleaseAsync(const DvrNativeBufferMetadata* meta,
400                                  const LocalHandle& release_fence) {
401   ATRACE_NAME("BufferConsumer::ReleaseAsync");
402 
403   if (const int error = LocalRelease(meta, release_fence))
404     return error;
405 
406   return ReturnStatusOrError(
407       SendImpulse(BufferHubRPC::ConsumerRelease::Opcode));
408 }
409 
Discard()410 int BufferConsumer::Discard() { return Release(LocalHandle()); }
411 
SetIgnore(bool ignore)412 int BufferConsumer::SetIgnore(bool ignore) {
413   return ReturnStatusOrError(
414       InvokeRemoteMethod<BufferHubRPC::ConsumerSetIgnore>(ignore));
415 }
416 
BufferProducer(uint32_t width,uint32_t height,uint32_t format,uint64_t usage,size_t user_metadata_size)417 BufferProducer::BufferProducer(uint32_t width, uint32_t height, uint32_t format,
418                                uint64_t usage, size_t user_metadata_size)
419     : BASE(BufferHubRPC::kClientPath) {
420   ATRACE_NAME("BufferProducer::BufferProducer");
421   ALOGD_IF(TRACE,
422            "BufferProducer::BufferProducer: fd=%d width=%u height=%u format=%u "
423            "usage=%" PRIx64 " user_metadata_size=%zu",
424            event_fd(), width, height, format, usage, user_metadata_size);
425 
426   auto status = InvokeRemoteMethod<BufferHubRPC::CreateBuffer>(
427       width, height, format, usage, user_metadata_size);
428   if (!status) {
429     ALOGE(
430         "BufferProducer::BufferProducer: Failed to create producer buffer: %s",
431         status.GetErrorMessage().c_str());
432     Close(-status.error());
433     return;
434   }
435 
436   const int ret = ImportBuffer();
437   if (ret < 0) {
438     ALOGE(
439         "BufferProducer::BufferProducer: Failed to import producer buffer: %s",
440         strerror(-ret));
441     Close(ret);
442   }
443 }
444 
BufferProducer(uint64_t usage,size_t size)445 BufferProducer::BufferProducer(uint64_t usage, size_t size)
446     : BASE(BufferHubRPC::kClientPath) {
447   ATRACE_NAME("BufferProducer::BufferProducer");
448   ALOGD_IF(TRACE, "BufferProducer::BufferProducer: usage=%" PRIx64 " size=%zu",
449            usage, size);
450   const int width = static_cast<int>(size);
451   const int height = 1;
452   const int format = HAL_PIXEL_FORMAT_BLOB;
453   const size_t user_metadata_size = 0;
454 
455   auto status = InvokeRemoteMethod<BufferHubRPC::CreateBuffer>(
456       width, height, format, usage, user_metadata_size);
457   if (!status) {
458     ALOGE("BufferProducer::BufferProducer: Failed to create blob: %s",
459           status.GetErrorMessage().c_str());
460     Close(-status.error());
461     return;
462   }
463 
464   const int ret = ImportBuffer();
465   if (ret < 0) {
466     ALOGE(
467         "BufferProducer::BufferProducer: Failed to import producer buffer: %s",
468         strerror(-ret));
469     Close(ret);
470   }
471 }
472 
BufferProducer(LocalChannelHandle channel)473 BufferProducer::BufferProducer(LocalChannelHandle channel)
474     : BASE(std::move(channel)) {
475   const int ret = ImportBuffer();
476   if (ret < 0) {
477     ALOGE(
478         "BufferProducer::BufferProducer: Failed to import producer buffer: %s",
479         strerror(-ret));
480     Close(ret);
481   }
482 }
483 
LocalPost(const DvrNativeBufferMetadata * meta,const LocalHandle & ready_fence)484 int BufferProducer::LocalPost(const DvrNativeBufferMetadata* meta,
485                               const LocalHandle& ready_fence) {
486   if (const int error = CheckMetadata(meta->user_metadata_size))
487     return error;
488 
489   // Check invalid state transition.
490   uint64_t buffer_state = buffer_state_->load();
491   if (!BufferHubDefs::IsBufferGained(buffer_state)) {
492     ALOGE("BufferProducer::LocalPost: not gained, id=%d state=%" PRIx64 ".",
493           id(), buffer_state);
494     return -EBUSY;
495   }
496 
497   // Copy the canonical metadata.
498   void* metadata_ptr = reinterpret_cast<void*>(&metadata_header_->metadata);
499   memcpy(metadata_ptr, meta, sizeof(DvrNativeBufferMetadata));
500   // Copy extra user requested metadata.
501   if (meta->user_metadata_ptr && meta->user_metadata_size) {
502     void* metadata_src = reinterpret_cast<void*>(meta->user_metadata_ptr);
503     memcpy(user_metadata_ptr_, metadata_src, meta->user_metadata_size);
504   }
505 
506   // Send out the acquire fence through the shared epoll fd. Note that during
507   // posting no consumer is not expected to be polling on the fence.
508   if (const int error = UpdateSharedFence(ready_fence, shared_acquire_fence_))
509     return error;
510 
511   // Set the producer bit atomically to transit into posted state.
512   BufferHubDefs::ModifyBufferState(buffer_state_, 0ULL,
513                                    BufferHubDefs::kProducerStateBit);
514   return 0;
515 }
516 
Post(const LocalHandle & ready_fence,const void * meta,size_t user_metadata_size)517 int BufferProducer::Post(const LocalHandle& ready_fence, const void* meta,
518                          size_t user_metadata_size) {
519   ATRACE_NAME("BufferProducer::Post");
520 
521   // Populate cononical metadata for posting.
522   DvrNativeBufferMetadata canonical_meta;
523   canonical_meta.user_metadata_ptr = reinterpret_cast<uint64_t>(meta);
524   canonical_meta.user_metadata_size = user_metadata_size;
525 
526   if (const int error = LocalPost(&canonical_meta, ready_fence))
527     return error;
528 
529   return ReturnStatusOrError(InvokeRemoteMethod<BufferHubRPC::ProducerPost>(
530       BorrowedFence(ready_fence.Borrow())));
531 }
532 
PostAsync(const DvrNativeBufferMetadata * meta,const LocalHandle & ready_fence)533 int BufferProducer::PostAsync(const DvrNativeBufferMetadata* meta,
534                               const LocalHandle& ready_fence) {
535   ATRACE_NAME("BufferProducer::PostAsync");
536 
537   if (const int error = LocalPost(meta, ready_fence))
538     return error;
539 
540   return ReturnStatusOrError(SendImpulse(BufferHubRPC::ProducerPost::Opcode));
541 }
542 
LocalGain(DvrNativeBufferMetadata * out_meta,LocalHandle * out_fence)543 int BufferProducer::LocalGain(DvrNativeBufferMetadata* out_meta,
544                               LocalHandle* out_fence) {
545   uint64_t buffer_state = buffer_state_->load();
546   ALOGD_IF(TRACE, "BufferProducer::LocalGain: buffer=%d, state=%" PRIx64 ".",
547            id(), buffer_state);
548 
549   if (!out_meta)
550     return -EINVAL;
551 
552   if (!BufferHubDefs::IsBufferReleased(buffer_state)) {
553     if (BufferHubDefs::IsBufferGained(buffer_state)) {
554       // We don't want to log error when gaining a newly allocated
555       // buffer.
556       ALOGI("BufferProducer::LocalGain: already gained id=%d.", id());
557       return -EALREADY;
558     }
559     ALOGE("BufferProducer::LocalGain: not released id=%d state=%" PRIx64 ".",
560           id(), buffer_state);
561     return -EBUSY;
562   }
563 
564   // Canonical metadata is undefined on Gain. Except for user_metadata and
565   // release_fence_mask. Fill in the user_metadata_ptr in address space of the
566   // local process.
567   if (metadata_header_->metadata.user_metadata_size && user_metadata_ptr_) {
568     out_meta->user_metadata_size =
569         metadata_header_->metadata.user_metadata_size;
570     out_meta->user_metadata_ptr =
571         reinterpret_cast<uint64_t>(user_metadata_ptr_);
572   } else {
573     out_meta->user_metadata_size = 0;
574     out_meta->user_metadata_ptr = 0;
575   }
576 
577   uint64_t fence_state = fence_state_->load();
578   // If there is an release fence from consumer, we need to return it.
579   if (fence_state & BufferHubDefs::kConsumerStateMask) {
580     *out_fence = shared_release_fence_.Duplicate();
581     out_meta->release_fence_mask =
582         fence_state & BufferHubDefs::kConsumerStateMask;
583   }
584 
585   // Clear out all bits and the buffer is now back to gained state.
586   buffer_state_->store(0ULL);
587   return 0;
588 }
589 
Gain(LocalHandle * release_fence)590 int BufferProducer::Gain(LocalHandle* release_fence) {
591   ATRACE_NAME("BufferProducer::Gain");
592 
593   DvrNativeBufferMetadata meta;
594   if (const int error = LocalGain(&meta, release_fence))
595     return error;
596 
597   auto status = InvokeRemoteMethod<BufferHubRPC::ProducerGain>();
598   if (!status)
599     return -status.error();
600   return 0;
601 }
602 
GainAsync(DvrNativeBufferMetadata * out_meta,LocalHandle * release_fence)603 int BufferProducer::GainAsync(DvrNativeBufferMetadata* out_meta,
604                               LocalHandle* release_fence) {
605   ATRACE_NAME("BufferProducer::GainAsync");
606 
607   if (const int error = LocalGain(out_meta, release_fence))
608     return error;
609 
610   return ReturnStatusOrError(SendImpulse(BufferHubRPC::ProducerGain::Opcode));
611 }
612 
GainAsync()613 int BufferProducer::GainAsync() {
614   DvrNativeBufferMetadata meta;
615   LocalHandle fence;
616   return GainAsync(&meta, &fence);
617 }
618 
Import(LocalChannelHandle channel)619 std::unique_ptr<BufferProducer> BufferProducer::Import(
620     LocalChannelHandle channel) {
621   ALOGD_IF(TRACE, "BufferProducer::Import: channel=%d", channel.value());
622   return BufferProducer::Create(std::move(channel));
623 }
624 
Import(Status<LocalChannelHandle> status)625 std::unique_ptr<BufferProducer> BufferProducer::Import(
626     Status<LocalChannelHandle> status) {
627   return Import(status ? status.take()
628                        : LocalChannelHandle{nullptr, -status.error()});
629 }
630 
Detach()631 Status<LocalChannelHandle> BufferProducer::Detach() {
632   uint64_t buffer_state = buffer_state_->load();
633   if (!BufferHubDefs::IsBufferGained(buffer_state)) {
634     // Can only detach a BufferProducer when it's in gained state.
635     ALOGW("BufferProducer::Detach: The buffer (id=%d, state=0x%" PRIx64
636           ") is not in gained state.",
637           id(), buffer_state);
638     return {};
639   }
640 
641   Status<LocalChannelHandle> status =
642       InvokeRemoteMethod<BufferHubRPC::ProducerBufferDetach>();
643   ALOGE_IF(!status,
644            "BufferProducer::Detach: Failed to detach buffer (id=%d): %s.", id(),
645            status.GetErrorMessage().c_str());
646   return status;
647 }
648 
649 }  // namespace dvr
650 }  // namespace android
651