blob: c1ef22c996450c898d06cb2ddd0e69473aad7b8b [file] [log] [blame]
Alex Vakulenkoe4eec202017-01-27 14:41:04 -08001#include "producer_channel.h"
2
Alex Vakulenko4fe60582017-02-02 11:35:59 -08003#include <log/log.h>
Alex Vakulenkoe4eec202017-01-27 14:41:04 -08004#include <sync/sync.h>
5#include <sys/poll.h>
6#include <utils/Trace.h>
7
8#include <algorithm>
9#include <atomic>
10#include <thread>
11
Alex Vakulenkoe4eec202017-01-27 14:41:04 -080012#include <private/dvr/bufferhub_rpc.h>
13#include "consumer_channel.h"
14
15using android::pdx::BorrowedHandle;
16using android::pdx::Message;
17using android::pdx::RemoteChannelHandle;
18using android::pdx::rpc::BufferWrapper;
19using android::pdx::rpc::DispatchRemoteMethod;
20using android::pdx::rpc::WrapBuffer;
21
22namespace android {
23namespace dvr {
24
25ProducerChannel::ProducerChannel(BufferHubService* service, int channel_id,
26 int width, int height, int format, int usage,
27 size_t meta_size_bytes, size_t slice_count,
28 int* error)
29 : BufferHubChannel(service, channel_id, channel_id, kProducerType),
30 pending_consumers_(0),
31 slices_(std::max(static_cast<size_t>(1), slice_count)),
32 producer_owns_(true),
33 meta_size_bytes_(meta_size_bytes),
34 meta_(meta_size_bytes ? new uint8_t[meta_size_bytes] : nullptr) {
35 for (auto& ion_buffer : slices_) {
36 const int ret = ion_buffer.Alloc(width, height, format, usage);
37 if (ret < 0) {
38 ALOGE("ProducerChannel::ProducerChannel: Failed to allocate buffer: %s",
39 strerror(-ret));
40 *error = ret;
41 return;
42 }
43 }
44
45 // Success.
46 *error = 0;
47}
48
49std::shared_ptr<ProducerChannel> ProducerChannel::Create(
50 BufferHubService* service, int channel_id, int width, int height,
51 int format, int usage, size_t meta_size_bytes, size_t slice_count,
52 int* error) {
53 std::shared_ptr<ProducerChannel> producer(
54 new ProducerChannel(service, channel_id, width, height, format, usage,
55 meta_size_bytes, slice_count, error));
56 if (*error < 0)
57 return nullptr;
58 else
59 return producer;
60}
61
62ProducerChannel::~ProducerChannel() {
63 ALOGD_IF(TRACE, "ProducerChannel::~ProducerChannel: channel_id=%d",
64 channel_id());
65 for (auto consumer : consumer_channels_)
66 consumer->OnProducerClosed();
67}
68
69BufferHubChannel::BufferInfo ProducerChannel::GetBufferInfo() const {
70 return BufferInfo(buffer_id(), consumer_channels_.size(), slices_[0].width(),
71 slices_[0].height(), slices_[0].format(),
72 slices_[0].usage(), slices_.size(), name_);
73}
74
75void ProducerChannel::HandleImpulse(Message& message) {
76 ATRACE_NAME("ProducerChannel::HandleImpulse");
77 switch (message.GetOp()) {
78 case BufferHubRPC::ProducerGain::Opcode:
79 OnProducerGain(message);
80 break;
81 }
82}
83
84bool ProducerChannel::HandleMessage(Message& message) {
85 ATRACE_NAME("ProducerChannel::HandleMessage");
86 switch (message.GetOp()) {
87 case BufferHubRPC::GetBuffer::Opcode:
88 DispatchRemoteMethod<BufferHubRPC::GetBuffer>(
89 *this, &ProducerChannel::OnGetBuffer, message);
90 return true;
91
92 case BufferHubRPC::GetBuffers::Opcode:
93 DispatchRemoteMethod<BufferHubRPC::GetBuffers>(
94 *this, &ProducerChannel::OnGetBuffers, message);
95 return true;
96
97 case BufferHubRPC::NewConsumer::Opcode:
98 DispatchRemoteMethod<BufferHubRPC::NewConsumer>(
99 *this, &ProducerChannel::OnNewConsumer, message);
100 return true;
101
102 case BufferHubRPC::ProducerPost::Opcode:
103 DispatchRemoteMethod<BufferHubRPC::ProducerPost>(
104 *this, &ProducerChannel::OnProducerPost, message);
105 return true;
106
107 case BufferHubRPC::ProducerGain::Opcode:
108 DispatchRemoteMethod<BufferHubRPC::ProducerGain>(
109 *this, &ProducerChannel::OnProducerGain, message);
110 return true;
111
112 case BufferHubRPC::ProducerMakePersistent::Opcode:
113 DispatchRemoteMethod<BufferHubRPC::ProducerMakePersistent>(
114 *this, &ProducerChannel::OnProducerMakePersistent, message);
115 return true;
116
117 case BufferHubRPC::ProducerRemovePersistence::Opcode:
118 DispatchRemoteMethod<BufferHubRPC::ProducerRemovePersistence>(
119 *this, &ProducerChannel::OnRemovePersistence, message);
120 return true;
121
122 default:
123 return false;
124 }
125}
126
127NativeBufferHandle<BorrowedHandle> ProducerChannel::OnGetBuffer(
128 Message& message, unsigned index) {
129 ATRACE_NAME("ProducerChannel::OnGetBuffer");
130 ALOGD_IF(TRACE, "ProducerChannel::OnGetBuffer: buffer=%d", buffer_id());
131 if (index < slices_.size()) {
132 return NativeBufferHandle<BorrowedHandle>(slices_[index], buffer_id());
133 } else {
134 REPLY_ERROR_RETURN(message, EINVAL, NativeBufferHandle<BorrowedHandle>());
135 }
136}
137
138std::vector<NativeBufferHandle<BorrowedHandle>> ProducerChannel::OnGetBuffers(
139 Message&) {
140 ATRACE_NAME("ProducerChannel::OnGetBuffers");
141 ALOGD_IF(TRACE, "ProducerChannel::OnGetBuffers: buffer_id=%d", buffer_id());
142 std::vector<NativeBufferHandle<BorrowedHandle>> buffer_handles;
143 for (const auto& buffer : slices_)
144 buffer_handles.emplace_back(buffer, buffer_id());
145 return buffer_handles;
146}
147
148RemoteChannelHandle ProducerChannel::CreateConsumer(Message& message) {
149 ATRACE_NAME("ProducerChannel::CreateConsumer");
150 ALOGD_IF(TRACE, "ProducerChannel::CreateConsumer: buffer_id=%d", buffer_id());
151
152 int channel_id;
153 auto status = message.PushChannel(0, nullptr, &channel_id);
154 if (!status) {
155 ALOGE(
156 "ProducerChannel::CreateConsumer: failed to push consumer channel: %s",
157 status.GetErrorMessage().c_str());
158 return RemoteChannelHandle();
159 }
160
161 auto consumer = std::make_shared<ConsumerChannel>(
162 service(), buffer_id(), channel_id, shared_from_this());
163 const int ret = service()->SetChannel(channel_id, consumer);
164 if (ret < 0) {
165 ALOGE(
166 "ProducerChannel::CreateConsumer: failed to set new consumer channel: "
167 "%s",
168 strerror(-ret));
169 return RemoteChannelHandle();
170 }
171
172 if (!producer_owns_) {
173 // Signal the new consumer when adding it to a posted producer.
174 if (consumer->OnProducerPosted())
175 pending_consumers_++;
176 }
177
178 return status.take();
179}
180
181RemoteChannelHandle ProducerChannel::OnNewConsumer(Message& message) {
182 ATRACE_NAME("ProducerChannel::OnNewConsumer");
183 ALOGD_IF(TRACE, "ProducerChannel::OnNewConsumer: buffer_id=%d", buffer_id());
184
185 RemoteChannelHandle consumer_handle(CreateConsumer(message));
186
187 if (consumer_handle.valid())
188 return consumer_handle;
189 else
190 REPLY_ERROR_RETURN(message, ENOMEM, RemoteChannelHandle());
191}
192
193int ProducerChannel::OnProducerPost(
194 Message&, LocalFence acquire_fence,
195 BufferWrapper<std::vector<std::uint8_t>> metadata) {
196 ATRACE_NAME("ProducerChannel::OnProducerPost");
197 ALOGD_IF(TRACE, "ProducerChannel::OnProducerPost: buffer_id=%d", buffer_id());
198 if (!producer_owns_) {
199 ALOGE("ProducerChannel::OnProducerPost: Not in gained state!");
200 return -EBUSY;
201 }
202
203 if (meta_size_bytes_ != metadata.size())
204 return -EINVAL;
205 std::copy(metadata.begin(), metadata.end(), meta_.get());
206
207 post_fence_ = std::move(acquire_fence);
208 producer_owns_ = false;
209
210 // Signal any interested consumers. If there are none, automatically release
211 // the buffer.
212 pending_consumers_ = 0;
213 for (auto consumer : consumer_channels_) {
214 if (consumer->OnProducerPosted())
215 pending_consumers_++;
216 }
217 if (pending_consumers_ == 0)
218 SignalAvailable();
219 ALOGD_IF(TRACE, "ProducerChannel::OnProducerPost: %d pending consumers",
220 pending_consumers_);
221
222 return 0;
223}
224
225LocalFence ProducerChannel::OnProducerGain(Message& message) {
226 ATRACE_NAME("ProducerChannel::OnGain");
227 ALOGD_IF(TRACE, "ProducerChannel::OnGain: buffer_id=%d", buffer_id());
228 if (producer_owns_) {
229 ALOGE("ProducerChanneL::OnGain: Already in gained state: channel=%d",
230 channel_id());
231 REPLY_ERROR_RETURN(message, EALREADY, {});
232 }
233
234 // There are still pending consumers, return busy.
235 if (pending_consumers_ > 0)
236 REPLY_ERROR_RETURN(message, EBUSY, {});
237
238 ClearAvailable();
239 producer_owns_ = true;
240 post_fence_.get_fd();
241 return std::move(returned_fence_);
242}
243
244std::pair<BorrowedFence, BufferWrapper<std::uint8_t*>>
245ProducerChannel::OnConsumerAcquire(Message& message,
246 std::size_t metadata_size) {
247 ATRACE_NAME("ProducerChannel::OnConsumerAcquire");
248 ALOGD_IF(TRACE, "ProducerChannel::OnConsumerAcquire: buffer_id=%d",
249 buffer_id());
250 if (producer_owns_) {
251 ALOGE("ProducerChannel::OnConsumerAcquire: Not in posted state!");
252 REPLY_ERROR_RETURN(message, EBUSY, {});
253 }
254
255 // Return a borrowed fd to avoid unnecessary duplication of the underlying fd.
256 // Serialization just needs to read the handle.
257 if (metadata_size == 0)
258 return std::make_pair(post_fence_.borrow(),
259 WrapBuffer<std::uint8_t>(nullptr, 0));
260 else
261 return std::make_pair(post_fence_.borrow(),
262 WrapBuffer(meta_.get(), meta_size_bytes_));
263}
264
265int ProducerChannel::OnConsumerRelease(Message&, LocalFence release_fence) {
266 ATRACE_NAME("ProducerChannel::OnConsumerRelease");
267 ALOGD_IF(TRACE, "ProducerChannel::OnConsumerRelease: buffer_id=%d",
268 buffer_id());
269 if (producer_owns_) {
270 ALOGE("ProducerChannel::OnConsumerRelease: Not in acquired state!");
271 return -EBUSY;
272 }
273
274 // Attempt to merge the fences if necessary.
275 if (release_fence) {
276 if (returned_fence_) {
277 LocalFence merged_fence(sync_merge(
278 "bufferhub_merged", returned_fence_.get_fd(), release_fence.get_fd()));
279 const int error = errno;
280 if (!merged_fence) {
281 ALOGE("ProducerChannel::OnConsumerRelease: Failed to merge fences: %s",
282 strerror(error));
283 return -error;
284 }
285 returned_fence_ = std::move(merged_fence);
286 } else {
287 returned_fence_ = std::move(release_fence);
288 }
289 }
290
291 OnConsumerIgnored();
292 return 0;
293}
294
295void ProducerChannel::OnConsumerIgnored() {
296 if (!--pending_consumers_)
297 SignalAvailable();
298 ALOGD_IF(TRACE,
299 "ProducerChannel::OnConsumerIgnored: buffer_id=%d %d consumers left",
300 buffer_id(), pending_consumers_);
301}
302
303int ProducerChannel::OnProducerMakePersistent(Message& message,
304 const std::string& name,
305 int user_id, int group_id) {
306 ATRACE_NAME("ProducerChannel::OnProducerMakePersistent");
307 ALOGD_IF(TRACE,
308 "ProducerChannel::OnProducerMakePersistent: buffer_id=%d name=%s "
309 "user_id=%d group_id=%d",
310 buffer_id(), name.c_str(), user_id, group_id);
311
312 if (name.empty() || (user_id < 0 && user_id != kNoCheckId) ||
313 (group_id < 0 && group_id != kNoCheckId)) {
314 return -EINVAL;
315 }
316
317 // Try to add this buffer with the requested name.
318 if (service()->AddNamedBuffer(name, std::static_pointer_cast<ProducerChannel>(
319 shared_from_this()))) {
320 // If successful, set the requested permissions.
321
322 // A value of zero indicates that the ids from the sending process should be
323 // used.
324 if (user_id == kUseCallerId)
325 user_id = message.GetEffectiveUserId();
326 if (group_id == kUseCallerId)
327 group_id = message.GetEffectiveGroupId();
328
329 owner_user_id_ = user_id;
330 owner_group_id_ = group_id;
331 name_ = name;
332 return 0;
333 } else {
334 // Otherwise a buffer with that name already exists.
335 return -EALREADY;
336 }
337}
338
339int ProducerChannel::OnRemovePersistence(Message&) {
340 if (service()->RemoveNamedBuffer(*this))
341 return 0;
342 else
343 return -ENOENT;
344}
345
346void ProducerChannel::AddConsumer(ConsumerChannel* channel) {
347 consumer_channels_.push_back(channel);
348}
349
350void ProducerChannel::RemoveConsumer(ConsumerChannel* channel) {
351 consumer_channels_.erase(
352 std::find(consumer_channels_.begin(), consumer_channels_.end(), channel));
353}
354
355// Returns true if either the user or group ids match the owning ids or both
356// owning ids are not set, in which case access control does not apply.
357bool ProducerChannel::CheckAccess(int euid, int egid) {
358 const bool no_check =
359 owner_user_id_ == kNoCheckId && owner_group_id_ == kNoCheckId;
360 const bool euid_check = euid == owner_user_id_ || euid == kRootId;
361 const bool egid_check = egid == owner_group_id_ || egid == kRootId;
362 return no_check || euid_check || egid_check;
363}
364
365// Returns true if the given parameters match the underlying buffer parameters.
366bool ProducerChannel::CheckParameters(int width, int height, int format,
367 int usage, size_t meta_size_bytes,
368 size_t slice_count) {
369 return slices_.size() == slice_count &&
370 meta_size_bytes == meta_size_bytes_ && slices_[0].width() == width &&
371 slices_[0].height() == height && slices_[0].format() == format &&
372 slices_[0].usage() == usage;
373}
374
375} // namespace dvr
376} // namespace android