blob: c946a8d6b04f55bd6c5cc2e827c8774882b762f3 [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;
Corey Tabakacd52dd92017-04-07 18:03:57 -070016using android::pdx::ErrorStatus;
Alex Vakulenkoe4eec202017-01-27 14:41:04 -080017using android::pdx::Message;
18using android::pdx::RemoteChannelHandle;
Corey Tabakacd52dd92017-04-07 18:03:57 -070019using android::pdx::Status;
Alex Vakulenkoe4eec202017-01-27 14:41:04 -080020using android::pdx::rpc::BufferWrapper;
21using android::pdx::rpc::DispatchRemoteMethod;
22using android::pdx::rpc::WrapBuffer;
23
24namespace android {
25namespace dvr {
26
27ProducerChannel::ProducerChannel(BufferHubService* service, int channel_id,
Corey Tabakacd52dd92017-04-07 18:03:57 -070028 uint32_t width, uint32_t height,
29 uint32_t format, uint64_t producer_usage,
30 uint64_t consumer_usage,
Alex Vakulenkoe4eec202017-01-27 14:41:04 -080031 size_t meta_size_bytes, size_t slice_count,
32 int* error)
33 : BufferHubChannel(service, channel_id, channel_id, kProducerType),
34 pending_consumers_(0),
35 slices_(std::max(static_cast<size_t>(1), slice_count)),
36 producer_owns_(true),
37 meta_size_bytes_(meta_size_bytes),
38 meta_(meta_size_bytes ? new uint8_t[meta_size_bytes] : nullptr) {
39 for (auto& ion_buffer : slices_) {
Corey Tabakacd52dd92017-04-07 18:03:57 -070040 const int ret =
41 ion_buffer.Alloc(width, height, format, producer_usage, consumer_usage);
Alex Vakulenkoe4eec202017-01-27 14:41:04 -080042 if (ret < 0) {
43 ALOGE("ProducerChannel::ProducerChannel: Failed to allocate buffer: %s",
44 strerror(-ret));
45 *error = ret;
46 return;
47 }
48 }
49
50 // Success.
51 *error = 0;
52}
53
Corey Tabakacd52dd92017-04-07 18:03:57 -070054Status<std::shared_ptr<ProducerChannel>> ProducerChannel::Create(
55 BufferHubService* service, int channel_id, uint32_t width, uint32_t height,
56 uint32_t format, uint64_t producer_usage, uint64_t consumer_usage,
57 size_t meta_size_bytes, size_t slice_count) {
58 int error;
59 std::shared_ptr<ProducerChannel> producer(new ProducerChannel(
60 service, channel_id, width, height, format, producer_usage,
61 consumer_usage, meta_size_bytes, slice_count, &error));
62 if (error < 0)
63 return ErrorStatus(-error);
Alex Vakulenkoe4eec202017-01-27 14:41:04 -080064 else
Corey Tabakacd52dd92017-04-07 18:03:57 -070065 return {std::move(producer)};
Alex Vakulenkoe4eec202017-01-27 14:41:04 -080066}
67
68ProducerChannel::~ProducerChannel() {
Corey Tabaka3079cb72017-01-19 15:07:26 -080069 ALOGD_IF(TRACE,
70 "ProducerChannel::~ProducerChannel: channel_id=%d buffer_id=%d",
71 channel_id(), buffer_id());
Alex Vakulenkoe4eec202017-01-27 14:41:04 -080072 for (auto consumer : consumer_channels_)
73 consumer->OnProducerClosed();
74}
75
76BufferHubChannel::BufferInfo ProducerChannel::GetBufferInfo() const {
77 return BufferInfo(buffer_id(), consumer_channels_.size(), slices_[0].width(),
78 slices_[0].height(), slices_[0].format(),
Corey Tabakacd52dd92017-04-07 18:03:57 -070079 slices_[0].producer_usage(), slices_[0].consumer_usage(),
80 slices_.size(), name_);
Alex Vakulenkoe4eec202017-01-27 14:41:04 -080081}
82
83void ProducerChannel::HandleImpulse(Message& message) {
84 ATRACE_NAME("ProducerChannel::HandleImpulse");
85 switch (message.GetOp()) {
86 case BufferHubRPC::ProducerGain::Opcode:
87 OnProducerGain(message);
88 break;
89 }
90}
91
92bool ProducerChannel::HandleMessage(Message& message) {
93 ATRACE_NAME("ProducerChannel::HandleMessage");
94 switch (message.GetOp()) {
95 case BufferHubRPC::GetBuffer::Opcode:
96 DispatchRemoteMethod<BufferHubRPC::GetBuffer>(
97 *this, &ProducerChannel::OnGetBuffer, message);
98 return true;
99
100 case BufferHubRPC::GetBuffers::Opcode:
101 DispatchRemoteMethod<BufferHubRPC::GetBuffers>(
102 *this, &ProducerChannel::OnGetBuffers, message);
103 return true;
104
105 case BufferHubRPC::NewConsumer::Opcode:
106 DispatchRemoteMethod<BufferHubRPC::NewConsumer>(
107 *this, &ProducerChannel::OnNewConsumer, message);
108 return true;
109
110 case BufferHubRPC::ProducerPost::Opcode:
111 DispatchRemoteMethod<BufferHubRPC::ProducerPost>(
112 *this, &ProducerChannel::OnProducerPost, message);
113 return true;
114
115 case BufferHubRPC::ProducerGain::Opcode:
116 DispatchRemoteMethod<BufferHubRPC::ProducerGain>(
117 *this, &ProducerChannel::OnProducerGain, message);
118 return true;
119
120 case BufferHubRPC::ProducerMakePersistent::Opcode:
121 DispatchRemoteMethod<BufferHubRPC::ProducerMakePersistent>(
122 *this, &ProducerChannel::OnProducerMakePersistent, message);
123 return true;
124
125 case BufferHubRPC::ProducerRemovePersistence::Opcode:
126 DispatchRemoteMethod<BufferHubRPC::ProducerRemovePersistence>(
127 *this, &ProducerChannel::OnRemovePersistence, message);
128 return true;
129
130 default:
131 return false;
132 }
133}
134
Corey Tabakacd52dd92017-04-07 18:03:57 -0700135Status<NativeBufferHandle<BorrowedHandle>> ProducerChannel::OnGetBuffer(
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800136 Message& message, unsigned index) {
137 ATRACE_NAME("ProducerChannel::OnGetBuffer");
138 ALOGD_IF(TRACE, "ProducerChannel::OnGetBuffer: buffer=%d", buffer_id());
139 if (index < slices_.size()) {
Corey Tabakacd52dd92017-04-07 18:03:57 -0700140 return {NativeBufferHandle<BorrowedHandle>(slices_[index], buffer_id())};
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800141 } else {
Corey Tabakacd52dd92017-04-07 18:03:57 -0700142 return ErrorStatus(EINVAL);
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800143 }
144}
145
Corey Tabakacd52dd92017-04-07 18:03:57 -0700146Status<std::vector<NativeBufferHandle<BorrowedHandle>>>
147ProducerChannel::OnGetBuffers(Message&) {
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800148 ATRACE_NAME("ProducerChannel::OnGetBuffers");
149 ALOGD_IF(TRACE, "ProducerChannel::OnGetBuffers: buffer_id=%d", buffer_id());
150 std::vector<NativeBufferHandle<BorrowedHandle>> buffer_handles;
151 for (const auto& buffer : slices_)
152 buffer_handles.emplace_back(buffer, buffer_id());
Corey Tabakacd52dd92017-04-07 18:03:57 -0700153 return {std::move(buffer_handles)};
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800154}
155
Corey Tabakacd52dd92017-04-07 18:03:57 -0700156Status<RemoteChannelHandle> ProducerChannel::CreateConsumer(Message& message) {
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800157 ATRACE_NAME("ProducerChannel::CreateConsumer");
158 ALOGD_IF(TRACE, "ProducerChannel::CreateConsumer: buffer_id=%d", buffer_id());
159
160 int channel_id;
161 auto status = message.PushChannel(0, nullptr, &channel_id);
162 if (!status) {
163 ALOGE(
Corey Tabakacd52dd92017-04-07 18:03:57 -0700164 "ProducerChannel::CreateConsumer: Failed to push consumer channel: %s",
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800165 status.GetErrorMessage().c_str());
Corey Tabakacd52dd92017-04-07 18:03:57 -0700166 return ErrorStatus(ENOMEM);
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800167 }
168
169 auto consumer = std::make_shared<ConsumerChannel>(
170 service(), buffer_id(), channel_id, shared_from_this());
Alex Vakulenkof0a7bd02017-03-31 18:06:19 -0700171 const auto channel_status = service()->SetChannel(channel_id, consumer);
172 if (!channel_status) {
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800173 ALOGE(
174 "ProducerChannel::CreateConsumer: failed to set new consumer channel: "
175 "%s",
Alex Vakulenkof0a7bd02017-03-31 18:06:19 -0700176 channel_status.GetErrorMessage().c_str());
Corey Tabakacd52dd92017-04-07 18:03:57 -0700177 return ErrorStatus(ENOMEM);
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800178 }
179
180 if (!producer_owns_) {
181 // Signal the new consumer when adding it to a posted producer.
182 if (consumer->OnProducerPosted())
183 pending_consumers_++;
184 }
185
Corey Tabakacd52dd92017-04-07 18:03:57 -0700186 return {status.take()};
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800187}
188
Corey Tabakacd52dd92017-04-07 18:03:57 -0700189Status<RemoteChannelHandle> ProducerChannel::OnNewConsumer(Message& message) {
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800190 ATRACE_NAME("ProducerChannel::OnNewConsumer");
191 ALOGD_IF(TRACE, "ProducerChannel::OnNewConsumer: buffer_id=%d", buffer_id());
Corey Tabakacd52dd92017-04-07 18:03:57 -0700192 return CreateConsumer(message);
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800193}
194
Corey Tabakacd52dd92017-04-07 18:03:57 -0700195Status<void> ProducerChannel::OnProducerPost(
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800196 Message&, LocalFence acquire_fence,
197 BufferWrapper<std::vector<std::uint8_t>> metadata) {
198 ATRACE_NAME("ProducerChannel::OnProducerPost");
199 ALOGD_IF(TRACE, "ProducerChannel::OnProducerPost: buffer_id=%d", buffer_id());
200 if (!producer_owns_) {
201 ALOGE("ProducerChannel::OnProducerPost: Not in gained state!");
Corey Tabakacd52dd92017-04-07 18:03:57 -0700202 return ErrorStatus(EBUSY);
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800203 }
204
205 if (meta_size_bytes_ != metadata.size())
Corey Tabakacd52dd92017-04-07 18:03:57 -0700206 return ErrorStatus(EINVAL);
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800207 std::copy(metadata.begin(), metadata.end(), meta_.get());
208
209 post_fence_ = std::move(acquire_fence);
210 producer_owns_ = false;
211
212 // Signal any interested consumers. If there are none, automatically release
213 // the buffer.
214 pending_consumers_ = 0;
215 for (auto consumer : consumer_channels_) {
216 if (consumer->OnProducerPosted())
217 pending_consumers_++;
218 }
219 if (pending_consumers_ == 0)
220 SignalAvailable();
221 ALOGD_IF(TRACE, "ProducerChannel::OnProducerPost: %d pending consumers",
222 pending_consumers_);
223
Corey Tabakacd52dd92017-04-07 18:03:57 -0700224 return {};
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800225}
226
Corey Tabakacd52dd92017-04-07 18:03:57 -0700227Status<LocalFence> ProducerChannel::OnProducerGain(Message& message) {
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800228 ATRACE_NAME("ProducerChannel::OnGain");
229 ALOGD_IF(TRACE, "ProducerChannel::OnGain: buffer_id=%d", buffer_id());
230 if (producer_owns_) {
231 ALOGE("ProducerChanneL::OnGain: Already in gained state: channel=%d",
232 channel_id());
Corey Tabakacd52dd92017-04-07 18:03:57 -0700233 return ErrorStatus(EALREADY);
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800234 }
235
236 // There are still pending consumers, return busy.
237 if (pending_consumers_ > 0)
Corey Tabakacd52dd92017-04-07 18:03:57 -0700238 return ErrorStatus(EBUSY);
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800239
240 ClearAvailable();
241 producer_owns_ = true;
Alex Vakulenko052f3ae2017-03-31 09:10:43 -0700242 post_fence_.close();
Corey Tabakacd52dd92017-04-07 18:03:57 -0700243 return {std::move(returned_fence_)};
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800244}
245
Corey Tabakacd52dd92017-04-07 18:03:57 -0700246Status<std::pair<BorrowedFence, BufferWrapper<std::uint8_t*>>>
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800247ProducerChannel::OnConsumerAcquire(Message& message,
248 std::size_t metadata_size) {
249 ATRACE_NAME("ProducerChannel::OnConsumerAcquire");
250 ALOGD_IF(TRACE, "ProducerChannel::OnConsumerAcquire: buffer_id=%d",
251 buffer_id());
252 if (producer_owns_) {
253 ALOGE("ProducerChannel::OnConsumerAcquire: Not in posted state!");
Corey Tabakacd52dd92017-04-07 18:03:57 -0700254 return ErrorStatus(EBUSY);
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800255 }
256
257 // Return a borrowed fd to avoid unnecessary duplication of the underlying fd.
258 // Serialization just needs to read the handle.
259 if (metadata_size == 0)
Corey Tabakacd52dd92017-04-07 18:03:57 -0700260 return {std::make_pair(post_fence_.borrow(),
261 WrapBuffer<std::uint8_t>(nullptr, 0))};
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800262 else
Corey Tabakacd52dd92017-04-07 18:03:57 -0700263 return {std::make_pair(post_fence_.borrow(),
264 WrapBuffer(meta_.get(), meta_size_bytes_))};
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800265}
266
Corey Tabakacd52dd92017-04-07 18:03:57 -0700267Status<void> ProducerChannel::OnConsumerRelease(Message&,
268 LocalFence release_fence) {
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800269 ATRACE_NAME("ProducerChannel::OnConsumerRelease");
270 ALOGD_IF(TRACE, "ProducerChannel::OnConsumerRelease: buffer_id=%d",
271 buffer_id());
272 if (producer_owns_) {
273 ALOGE("ProducerChannel::OnConsumerRelease: Not in acquired state!");
Corey Tabakacd52dd92017-04-07 18:03:57 -0700274 return ErrorStatus(EBUSY);
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800275 }
276
277 // Attempt to merge the fences if necessary.
278 if (release_fence) {
279 if (returned_fence_) {
Corey Tabaka3079cb72017-01-19 15:07:26 -0800280 LocalFence merged_fence(sync_merge("bufferhub_merged",
281 returned_fence_.get_fd(),
282 release_fence.get_fd()));
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800283 const int error = errno;
284 if (!merged_fence) {
285 ALOGE("ProducerChannel::OnConsumerRelease: Failed to merge fences: %s",
286 strerror(error));
Corey Tabakacd52dd92017-04-07 18:03:57 -0700287 return ErrorStatus(error);
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800288 }
289 returned_fence_ = std::move(merged_fence);
290 } else {
291 returned_fence_ = std::move(release_fence);
292 }
293 }
294
295 OnConsumerIgnored();
Corey Tabakacd52dd92017-04-07 18:03:57 -0700296 return {};
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800297}
298
299void ProducerChannel::OnConsumerIgnored() {
300 if (!--pending_consumers_)
301 SignalAvailable();
302 ALOGD_IF(TRACE,
303 "ProducerChannel::OnConsumerIgnored: buffer_id=%d %d consumers left",
304 buffer_id(), pending_consumers_);
305}
306
Corey Tabakacd52dd92017-04-07 18:03:57 -0700307Status<void> ProducerChannel::OnProducerMakePersistent(Message& message,
308 const std::string& name,
309 int user_id,
310 int group_id) {
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800311 ATRACE_NAME("ProducerChannel::OnProducerMakePersistent");
312 ALOGD_IF(TRACE,
313 "ProducerChannel::OnProducerMakePersistent: buffer_id=%d name=%s "
314 "user_id=%d group_id=%d",
315 buffer_id(), name.c_str(), user_id, group_id);
316
317 if (name.empty() || (user_id < 0 && user_id != kNoCheckId) ||
318 (group_id < 0 && group_id != kNoCheckId)) {
Corey Tabakacd52dd92017-04-07 18:03:57 -0700319 return ErrorStatus(EINVAL);
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800320 }
321
322 // Try to add this buffer with the requested name.
323 if (service()->AddNamedBuffer(name, std::static_pointer_cast<ProducerChannel>(
324 shared_from_this()))) {
325 // If successful, set the requested permissions.
326
327 // A value of zero indicates that the ids from the sending process should be
328 // used.
329 if (user_id == kUseCallerId)
330 user_id = message.GetEffectiveUserId();
331 if (group_id == kUseCallerId)
332 group_id = message.GetEffectiveGroupId();
333
334 owner_user_id_ = user_id;
335 owner_group_id_ = group_id;
336 name_ = name;
Corey Tabakacd52dd92017-04-07 18:03:57 -0700337 return {};
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800338 } else {
339 // Otherwise a buffer with that name already exists.
Corey Tabakacd52dd92017-04-07 18:03:57 -0700340 return ErrorStatus(EALREADY);
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800341 }
342}
343
Corey Tabakacd52dd92017-04-07 18:03:57 -0700344Status<void> ProducerChannel::OnRemovePersistence(Message&) {
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800345 if (service()->RemoveNamedBuffer(*this))
Corey Tabakacd52dd92017-04-07 18:03:57 -0700346 return {};
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800347 else
Corey Tabakacd52dd92017-04-07 18:03:57 -0700348 return ErrorStatus(ENOENT);
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800349}
350
351void ProducerChannel::AddConsumer(ConsumerChannel* channel) {
352 consumer_channels_.push_back(channel);
353}
354
355void ProducerChannel::RemoveConsumer(ConsumerChannel* channel) {
356 consumer_channels_.erase(
357 std::find(consumer_channels_.begin(), consumer_channels_.end(), channel));
358}
359
360// Returns true if either the user or group ids match the owning ids or both
361// owning ids are not set, in which case access control does not apply.
362bool ProducerChannel::CheckAccess(int euid, int egid) {
363 const bool no_check =
364 owner_user_id_ == kNoCheckId && owner_group_id_ == kNoCheckId;
365 const bool euid_check = euid == owner_user_id_ || euid == kRootId;
366 const bool egid_check = egid == owner_group_id_ || egid == kRootId;
367 return no_check || euid_check || egid_check;
368}
369
370// Returns true if the given parameters match the underlying buffer parameters.
Corey Tabakacd52dd92017-04-07 18:03:57 -0700371bool ProducerChannel::CheckParameters(uint32_t width, uint32_t height,
372 uint32_t format, uint64_t producer_usage,
373 uint64_t consumer_usage,
374 size_t meta_size_bytes,
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800375 size_t slice_count) {
Corey Tabaka3079cb72017-01-19 15:07:26 -0800376 return slices_.size() == slice_count && meta_size_bytes == meta_size_bytes_ &&
377 slices_[0].width() == width && slices_[0].height() == height &&
Corey Tabakacd52dd92017-04-07 18:03:57 -0700378 slices_[0].format() == format &&
379 slices_[0].producer_usage() == producer_usage &&
380 slices_[0].consumer_usage() == consumer_usage;
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800381}
382
383} // namespace dvr
384} // namespace android