1 #include <private/dvr/consumer_buffer.h>
2 
3 using android::pdx::LocalChannelHandle;
4 using android::pdx::LocalHandle;
5 using android::pdx::Status;
6 
7 namespace android {
8 namespace dvr {
9 
ConsumerBuffer(LocalChannelHandle channel)10 ConsumerBuffer::ConsumerBuffer(LocalChannelHandle channel)
11     : BASE(std::move(channel)) {
12   const int ret = ImportBuffer();
13   if (ret < 0) {
14     ALOGE("ConsumerBuffer::ConsumerBuffer: Failed to import buffer: %s",
15           strerror(-ret));
16     Close(ret);
17   }
18 }
19 
Import(LocalChannelHandle channel)20 std::unique_ptr<ConsumerBuffer> ConsumerBuffer::Import(
21     LocalChannelHandle channel) {
22   ATRACE_NAME("ConsumerBuffer::Import");
23   ALOGD_IF(TRACE, "ConsumerBuffer::Import: channel=%d", channel.value());
24   return ConsumerBuffer::Create(std::move(channel));
25 }
26 
Import(Status<LocalChannelHandle> status)27 std::unique_ptr<ConsumerBuffer> ConsumerBuffer::Import(
28     Status<LocalChannelHandle> status) {
29   return Import(status ? status.take()
30                        : LocalChannelHandle{nullptr, -status.error()});
31 }
32 
LocalAcquire(DvrNativeBufferMetadata * out_meta,LocalHandle * out_fence)33 int ConsumerBuffer::LocalAcquire(DvrNativeBufferMetadata* out_meta,
34                                  LocalHandle* out_fence) {
35   if (!out_meta)
36     return -EINVAL;
37 
38   // The buffer can be acquired iff the buffer state for this client is posted.
39   uint32_t current_buffer_state =
40       buffer_state_->load(std::memory_order_acquire);
41   if (!BufferHubDefs::isClientPosted(current_buffer_state,
42                                      client_state_mask())) {
43     ALOGE(
44         "%s: Failed to acquire the buffer. The buffer is not posted, id=%d "
45         "state=%" PRIx32 " client_state_mask=%" PRIx32 ".",
46         __FUNCTION__, id(), current_buffer_state, client_state_mask());
47     return -EBUSY;
48   }
49 
50   // Change the buffer state for this consumer from posted to acquired.
51   uint32_t updated_buffer_state = current_buffer_state ^ client_state_mask();
52   while (!buffer_state_->compare_exchange_weak(
53       current_buffer_state, updated_buffer_state, std::memory_order_acq_rel,
54       std::memory_order_acquire)) {
55     ALOGD(
56         "%s Failed to acquire the buffer. Current buffer state was changed to "
57         "%" PRIx32
58         " when trying to acquire the buffer and modify the buffer state to "
59         "%" PRIx32 ". About to try again if the buffer is still posted.",
60         __FUNCTION__, current_buffer_state, updated_buffer_state);
61     if (!BufferHubDefs::isClientPosted(current_buffer_state,
62                                        client_state_mask())) {
63       ALOGE(
64           "%s: Failed to acquire the buffer. The buffer is no longer posted, "
65           "id=%d state=%" PRIx32 " client_state_mask=%" PRIx32 ".",
66           __FUNCTION__, id(), current_buffer_state, client_state_mask());
67       return -EBUSY;
68     }
69     // The failure of compare_exchange_weak updates current_buffer_state.
70     updated_buffer_state = current_buffer_state ^ client_state_mask();
71   }
72 
73   // Copy the canonical metadata.
74   void* metadata_ptr = reinterpret_cast<void*>(&metadata_header_->metadata);
75   memcpy(out_meta, metadata_ptr, sizeof(DvrNativeBufferMetadata));
76   // Fill in the user_metadata_ptr in address space of the local process.
77   if (out_meta->user_metadata_size) {
78     out_meta->user_metadata_ptr =
79         reinterpret_cast<uint64_t>(user_metadata_ptr_);
80   } else {
81     out_meta->user_metadata_ptr = 0;
82   }
83 
84   uint32_t fence_state = fence_state_->load(std::memory_order_acquire);
85   // If there is an acquire fence from producer, we need to return it.
86   // The producer state bit mask is kFirstClientBitMask for now.
87   if (fence_state & BufferHubDefs::kFirstClientBitMask) {
88     *out_fence = shared_acquire_fence_.Duplicate();
89   }
90 
91   return 0;
92 }
93 
Acquire(LocalHandle * ready_fence)94 int ConsumerBuffer::Acquire(LocalHandle* ready_fence) {
95   return Acquire(ready_fence, nullptr, 0);
96 }
97 
Acquire(LocalHandle * ready_fence,void * meta,size_t user_metadata_size)98 int ConsumerBuffer::Acquire(LocalHandle* ready_fence, void* meta,
99                             size_t user_metadata_size) {
100   ATRACE_NAME("ConsumerBuffer::Acquire");
101 
102   if (const int error = CheckMetadata(user_metadata_size))
103     return error;
104 
105   DvrNativeBufferMetadata canonical_meta;
106   if (const int error = LocalAcquire(&canonical_meta, ready_fence))
107     return error;
108 
109   if (meta && user_metadata_size) {
110     void* metadata_src =
111         reinterpret_cast<void*>(canonical_meta.user_metadata_ptr);
112     if (metadata_src) {
113       memcpy(meta, metadata_src, user_metadata_size);
114     } else {
115       ALOGW("ConsumerBuffer::Acquire: no user-defined metadata.");
116     }
117   }
118 
119   auto status = InvokeRemoteMethod<BufferHubRPC::ConsumerAcquire>();
120   if (!status)
121     return -status.error();
122   return 0;
123 }
124 
AcquireAsync(DvrNativeBufferMetadata * out_meta,LocalHandle * out_fence)125 int ConsumerBuffer::AcquireAsync(DvrNativeBufferMetadata* out_meta,
126                                  LocalHandle* out_fence) {
127   ATRACE_NAME("ConsumerBuffer::AcquireAsync");
128 
129   if (const int error = LocalAcquire(out_meta, out_fence))
130     return error;
131 
132   auto status = SendImpulse(BufferHubRPC::ConsumerAcquire::Opcode);
133   if (!status)
134     return -status.error();
135   return 0;
136 }
137 
LocalRelease(const DvrNativeBufferMetadata * meta,const LocalHandle & release_fence)138 int ConsumerBuffer::LocalRelease(const DvrNativeBufferMetadata* meta,
139                                  const LocalHandle& release_fence) {
140   if (const int error = CheckMetadata(meta->user_metadata_size))
141     return error;
142 
143   // Set the buffer state of this client to released if it is not already in
144   // released state.
145   uint32_t current_buffer_state =
146       buffer_state_->load(std::memory_order_acquire);
147   if (BufferHubDefs::isClientReleased(current_buffer_state,
148                                       client_state_mask())) {
149     return 0;
150   }
151   uint32_t updated_buffer_state = current_buffer_state & (~client_state_mask());
152   while (!buffer_state_->compare_exchange_weak(
153       current_buffer_state, updated_buffer_state, std::memory_order_acq_rel,
154       std::memory_order_acquire)) {
155     ALOGD(
156         "%s: Failed to release the buffer. Current buffer state was changed to "
157         "%" PRIx32
158         " when trying to release the buffer and modify the buffer state to "
159         "%" PRIx32 ". About to try again.",
160         __FUNCTION__, current_buffer_state, updated_buffer_state);
161     // The failure of compare_exchange_weak updates current_buffer_state.
162     updated_buffer_state = current_buffer_state & (~client_state_mask());
163   }
164 
165   // On release, only the user requested metadata is copied back into the shared
166   // memory for metadata. Since there are multiple consumers, it doesn't make
167   // sense to send the canonical metadata back to the producer. However, one of
168   // the consumer can still choose to write up to user_metadata_size bytes of
169   // data into user_metadata_ptr.
170   if (meta->user_metadata_ptr && meta->user_metadata_size) {
171     void* metadata_src = reinterpret_cast<void*>(meta->user_metadata_ptr);
172     memcpy(user_metadata_ptr_, metadata_src, meta->user_metadata_size);
173   }
174 
175   // Send out the release fence through the shared epoll fd. Note that during
176   // releasing the producer is not expected to be polling on the fence.
177   if (const int error = UpdateSharedFence(release_fence, shared_release_fence_))
178     return error;
179 
180   return 0;
181 }
182 
Release(const LocalHandle & release_fence)183 int ConsumerBuffer::Release(const LocalHandle& release_fence) {
184   ATRACE_NAME("ConsumerBuffer::Release");
185 
186   DvrNativeBufferMetadata meta;
187   if (const int error = LocalRelease(&meta, release_fence))
188     return error;
189 
190   return ReturnStatusOrError(InvokeRemoteMethod<BufferHubRPC::ConsumerRelease>(
191       BorrowedFence(release_fence.Borrow())));
192 }
193 
ReleaseAsync()194 int ConsumerBuffer::ReleaseAsync() {
195   DvrNativeBufferMetadata meta;
196   return ReleaseAsync(&meta, LocalHandle());
197 }
198 
ReleaseAsync(const DvrNativeBufferMetadata * meta,const LocalHandle & release_fence)199 int ConsumerBuffer::ReleaseAsync(const DvrNativeBufferMetadata* meta,
200                                  const LocalHandle& release_fence) {
201   ATRACE_NAME("ConsumerBuffer::ReleaseAsync");
202 
203   if (const int error = LocalRelease(meta, release_fence))
204     return error;
205 
206   return ReturnStatusOrError(
207       SendImpulse(BufferHubRPC::ConsumerRelease::Opcode));
208 }
209 
Discard()210 int ConsumerBuffer::Discard() { return Release(LocalHandle()); }
211 
212 }  // namespace dvr
213 }  // namespace android
214