blob: e452d0422351a9c4a4d462d19c9beec0de9c726d [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,
Jiwen 'Steve' Cai0057fdd2017-05-02 11:21:18 -070029 uint32_t format, uint64_t usage,
Alex Vakulenkoe4eec202017-01-27 14:41:04 -080030 size_t meta_size_bytes, size_t slice_count,
31 int* error)
32 : BufferHubChannel(service, channel_id, channel_id, kProducerType),
33 pending_consumers_(0),
34 slices_(std::max(static_cast<size_t>(1), slice_count)),
35 producer_owns_(true),
36 meta_size_bytes_(meta_size_bytes),
37 meta_(meta_size_bytes ? new uint8_t[meta_size_bytes] : nullptr) {
38 for (auto& ion_buffer : slices_) {
Jiwen 'Steve' Cai0057fdd2017-05-02 11:21:18 -070039 const int ret = ion_buffer.Alloc(width, height, format, usage);
Alex Vakulenkoe4eec202017-01-27 14:41:04 -080040 if (ret < 0) {
41 ALOGE("ProducerChannel::ProducerChannel: Failed to allocate buffer: %s",
42 strerror(-ret));
43 *error = ret;
44 return;
45 }
46 }
47
48 // Success.
49 *error = 0;
50}
51
Corey Tabakacd52dd92017-04-07 18:03:57 -070052Status<std::shared_ptr<ProducerChannel>> ProducerChannel::Create(
53 BufferHubService* service, int channel_id, uint32_t width, uint32_t height,
Jiwen 'Steve' Cai0057fdd2017-05-02 11:21:18 -070054 uint32_t format, uint64_t usage, size_t meta_size_bytes,
55 size_t slice_count) {
Corey Tabakacd52dd92017-04-07 18:03:57 -070056 int error;
Jiwen 'Steve' Cai0057fdd2017-05-02 11:21:18 -070057 std::shared_ptr<ProducerChannel> producer(
58 new ProducerChannel(service, channel_id, width, height, format, usage,
59 meta_size_bytes, slice_count, &error));
Corey Tabakacd52dd92017-04-07 18:03:57 -070060 if (error < 0)
61 return ErrorStatus(-error);
Alex Vakulenkoe4eec202017-01-27 14:41:04 -080062 else
Corey Tabakacd52dd92017-04-07 18:03:57 -070063 return {std::move(producer)};
Alex Vakulenkoe4eec202017-01-27 14:41:04 -080064}
65
66ProducerChannel::~ProducerChannel() {
Corey Tabaka3079cb72017-01-19 15:07:26 -080067 ALOGD_IF(TRACE,
68 "ProducerChannel::~ProducerChannel: channel_id=%d buffer_id=%d",
69 channel_id(), buffer_id());
Alex Vakulenkoe4eec202017-01-27 14:41:04 -080070 for (auto consumer : consumer_channels_)
71 consumer->OnProducerClosed();
72}
73
74BufferHubChannel::BufferInfo ProducerChannel::GetBufferInfo() const {
75 return BufferInfo(buffer_id(), consumer_channels_.size(), slices_[0].width(),
76 slices_[0].height(), slices_[0].format(),
Jiwen 'Steve' Cai0057fdd2017-05-02 11:21:18 -070077 slices_[0].usage(), slices_.size(), name_);
Alex Vakulenkoe4eec202017-01-27 14:41:04 -080078}
79
80void ProducerChannel::HandleImpulse(Message& message) {
81 ATRACE_NAME("ProducerChannel::HandleImpulse");
82 switch (message.GetOp()) {
83 case BufferHubRPC::ProducerGain::Opcode:
84 OnProducerGain(message);
85 break;
86 }
87}
88
89bool ProducerChannel::HandleMessage(Message& message) {
90 ATRACE_NAME("ProducerChannel::HandleMessage");
91 switch (message.GetOp()) {
92 case BufferHubRPC::GetBuffer::Opcode:
93 DispatchRemoteMethod<BufferHubRPC::GetBuffer>(
94 *this, &ProducerChannel::OnGetBuffer, message);
95 return true;
96
97 case BufferHubRPC::GetBuffers::Opcode:
98 DispatchRemoteMethod<BufferHubRPC::GetBuffers>(
99 *this, &ProducerChannel::OnGetBuffers, message);
100 return true;
101
102 case BufferHubRPC::NewConsumer::Opcode:
103 DispatchRemoteMethod<BufferHubRPC::NewConsumer>(
104 *this, &ProducerChannel::OnNewConsumer, message);
105 return true;
106
107 case BufferHubRPC::ProducerPost::Opcode:
108 DispatchRemoteMethod<BufferHubRPC::ProducerPost>(
109 *this, &ProducerChannel::OnProducerPost, message);
110 return true;
111
112 case BufferHubRPC::ProducerGain::Opcode:
113 DispatchRemoteMethod<BufferHubRPC::ProducerGain>(
114 *this, &ProducerChannel::OnProducerGain, message);
115 return true;
116
117 case BufferHubRPC::ProducerMakePersistent::Opcode:
118 DispatchRemoteMethod<BufferHubRPC::ProducerMakePersistent>(
119 *this, &ProducerChannel::OnProducerMakePersistent, message);
120 return true;
121
122 case BufferHubRPC::ProducerRemovePersistence::Opcode:
123 DispatchRemoteMethod<BufferHubRPC::ProducerRemovePersistence>(
124 *this, &ProducerChannel::OnRemovePersistence, message);
125 return true;
126
127 default:
128 return false;
129 }
130}
131
Corey Tabakacd52dd92017-04-07 18:03:57 -0700132Status<NativeBufferHandle<BorrowedHandle>> ProducerChannel::OnGetBuffer(
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800133 Message& message, unsigned index) {
134 ATRACE_NAME("ProducerChannel::OnGetBuffer");
135 ALOGD_IF(TRACE, "ProducerChannel::OnGetBuffer: buffer=%d", buffer_id());
136 if (index < slices_.size()) {
Corey Tabakacd52dd92017-04-07 18:03:57 -0700137 return {NativeBufferHandle<BorrowedHandle>(slices_[index], buffer_id())};
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800138 } else {
Corey Tabakacd52dd92017-04-07 18:03:57 -0700139 return ErrorStatus(EINVAL);
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800140 }
141}
142
Corey Tabakacd52dd92017-04-07 18:03:57 -0700143Status<std::vector<NativeBufferHandle<BorrowedHandle>>>
144ProducerChannel::OnGetBuffers(Message&) {
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800145 ATRACE_NAME("ProducerChannel::OnGetBuffers");
146 ALOGD_IF(TRACE, "ProducerChannel::OnGetBuffers: buffer_id=%d", buffer_id());
147 std::vector<NativeBufferHandle<BorrowedHandle>> buffer_handles;
148 for (const auto& buffer : slices_)
149 buffer_handles.emplace_back(buffer, buffer_id());
Corey Tabakacd52dd92017-04-07 18:03:57 -0700150 return {std::move(buffer_handles)};
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800151}
152
Corey Tabakacd52dd92017-04-07 18:03:57 -0700153Status<RemoteChannelHandle> ProducerChannel::CreateConsumer(Message& message) {
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800154 ATRACE_NAME("ProducerChannel::CreateConsumer");
155 ALOGD_IF(TRACE, "ProducerChannel::CreateConsumer: buffer_id=%d", buffer_id());
156
157 int channel_id;
158 auto status = message.PushChannel(0, nullptr, &channel_id);
159 if (!status) {
160 ALOGE(
Corey Tabakacd52dd92017-04-07 18:03:57 -0700161 "ProducerChannel::CreateConsumer: Failed to push consumer channel: %s",
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800162 status.GetErrorMessage().c_str());
Corey Tabakacd52dd92017-04-07 18:03:57 -0700163 return ErrorStatus(ENOMEM);
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800164 }
165
166 auto consumer = std::make_shared<ConsumerChannel>(
167 service(), buffer_id(), channel_id, shared_from_this());
Alex Vakulenkof0a7bd02017-03-31 18:06:19 -0700168 const auto channel_status = service()->SetChannel(channel_id, consumer);
169 if (!channel_status) {
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800170 ALOGE(
171 "ProducerChannel::CreateConsumer: failed to set new consumer channel: "
172 "%s",
Alex Vakulenkof0a7bd02017-03-31 18:06:19 -0700173 channel_status.GetErrorMessage().c_str());
Corey Tabakacd52dd92017-04-07 18:03:57 -0700174 return ErrorStatus(ENOMEM);
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800175 }
176
177 if (!producer_owns_) {
178 // Signal the new consumer when adding it to a posted producer.
179 if (consumer->OnProducerPosted())
180 pending_consumers_++;
181 }
182
Corey Tabakacd52dd92017-04-07 18:03:57 -0700183 return {status.take()};
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800184}
185
Corey Tabakacd52dd92017-04-07 18:03:57 -0700186Status<RemoteChannelHandle> ProducerChannel::OnNewConsumer(Message& message) {
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800187 ATRACE_NAME("ProducerChannel::OnNewConsumer");
188 ALOGD_IF(TRACE, "ProducerChannel::OnNewConsumer: buffer_id=%d", buffer_id());
Corey Tabakacd52dd92017-04-07 18:03:57 -0700189 return CreateConsumer(message);
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800190}
191
Corey Tabakacd52dd92017-04-07 18:03:57 -0700192Status<void> ProducerChannel::OnProducerPost(
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800193 Message&, LocalFence acquire_fence,
194 BufferWrapper<std::vector<std::uint8_t>> metadata) {
195 ATRACE_NAME("ProducerChannel::OnProducerPost");
196 ALOGD_IF(TRACE, "ProducerChannel::OnProducerPost: buffer_id=%d", buffer_id());
197 if (!producer_owns_) {
198 ALOGE("ProducerChannel::OnProducerPost: Not in gained state!");
Corey Tabakacd52dd92017-04-07 18:03:57 -0700199 return ErrorStatus(EBUSY);
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800200 }
201
202 if (meta_size_bytes_ != metadata.size())
Corey Tabakacd52dd92017-04-07 18:03:57 -0700203 return ErrorStatus(EINVAL);
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800204 std::copy(metadata.begin(), metadata.end(), meta_.get());
205
206 post_fence_ = std::move(acquire_fence);
207 producer_owns_ = false;
208
209 // Signal any interested consumers. If there are none, automatically release
210 // the buffer.
211 pending_consumers_ = 0;
212 for (auto consumer : consumer_channels_) {
213 if (consumer->OnProducerPosted())
214 pending_consumers_++;
215 }
216 if (pending_consumers_ == 0)
217 SignalAvailable();
218 ALOGD_IF(TRACE, "ProducerChannel::OnProducerPost: %d pending consumers",
219 pending_consumers_);
220
Corey Tabakacd52dd92017-04-07 18:03:57 -0700221 return {};
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800222}
223
Corey Tabakacd52dd92017-04-07 18:03:57 -0700224Status<LocalFence> ProducerChannel::OnProducerGain(Message& message) {
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800225 ATRACE_NAME("ProducerChannel::OnGain");
226 ALOGD_IF(TRACE, "ProducerChannel::OnGain: buffer_id=%d", buffer_id());
227 if (producer_owns_) {
228 ALOGE("ProducerChanneL::OnGain: Already in gained state: channel=%d",
229 channel_id());
Corey Tabakacd52dd92017-04-07 18:03:57 -0700230 return ErrorStatus(EALREADY);
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800231 }
232
233 // There are still pending consumers, return busy.
234 if (pending_consumers_ > 0)
Corey Tabakacd52dd92017-04-07 18:03:57 -0700235 return ErrorStatus(EBUSY);
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800236
237 ClearAvailable();
238 producer_owns_ = true;
Alex Vakulenko052f3ae2017-03-31 09:10:43 -0700239 post_fence_.close();
Corey Tabakacd52dd92017-04-07 18:03:57 -0700240 return {std::move(returned_fence_)};
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800241}
242
Corey Tabakacd52dd92017-04-07 18:03:57 -0700243Status<std::pair<BorrowedFence, BufferWrapper<std::uint8_t*>>>
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800244ProducerChannel::OnConsumerAcquire(Message& message,
245 std::size_t metadata_size) {
246 ATRACE_NAME("ProducerChannel::OnConsumerAcquire");
247 ALOGD_IF(TRACE, "ProducerChannel::OnConsumerAcquire: buffer_id=%d",
248 buffer_id());
249 if (producer_owns_) {
250 ALOGE("ProducerChannel::OnConsumerAcquire: Not in posted state!");
Corey Tabakacd52dd92017-04-07 18:03:57 -0700251 return ErrorStatus(EBUSY);
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800252 }
253
254 // Return a borrowed fd to avoid unnecessary duplication of the underlying fd.
255 // Serialization just needs to read the handle.
256 if (metadata_size == 0)
Corey Tabakacd52dd92017-04-07 18:03:57 -0700257 return {std::make_pair(post_fence_.borrow(),
258 WrapBuffer<std::uint8_t>(nullptr, 0))};
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800259 else
Corey Tabakacd52dd92017-04-07 18:03:57 -0700260 return {std::make_pair(post_fence_.borrow(),
261 WrapBuffer(meta_.get(), meta_size_bytes_))};
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800262}
263
Corey Tabakacd52dd92017-04-07 18:03:57 -0700264Status<void> ProducerChannel::OnConsumerRelease(Message&,
265 LocalFence release_fence) {
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800266 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!");
Corey Tabakacd52dd92017-04-07 18:03:57 -0700271 return ErrorStatus(EBUSY);
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800272 }
273
274 // Attempt to merge the fences if necessary.
275 if (release_fence) {
276 if (returned_fence_) {
Corey Tabaka3079cb72017-01-19 15:07:26 -0800277 LocalFence merged_fence(sync_merge("bufferhub_merged",
278 returned_fence_.get_fd(),
279 release_fence.get_fd()));
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800280 const int error = errno;
281 if (!merged_fence) {
282 ALOGE("ProducerChannel::OnConsumerRelease: Failed to merge fences: %s",
283 strerror(error));
Corey Tabakacd52dd92017-04-07 18:03:57 -0700284 return ErrorStatus(error);
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800285 }
286 returned_fence_ = std::move(merged_fence);
287 } else {
288 returned_fence_ = std::move(release_fence);
289 }
290 }
291
292 OnConsumerIgnored();
Corey Tabakacd52dd92017-04-07 18:03:57 -0700293 return {};
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800294}
295
296void ProducerChannel::OnConsumerIgnored() {
297 if (!--pending_consumers_)
298 SignalAvailable();
299 ALOGD_IF(TRACE,
300 "ProducerChannel::OnConsumerIgnored: buffer_id=%d %d consumers left",
301 buffer_id(), pending_consumers_);
302}
303
Corey Tabakacd52dd92017-04-07 18:03:57 -0700304Status<void> ProducerChannel::OnProducerMakePersistent(Message& message,
305 const std::string& name,
306 int user_id,
307 int group_id) {
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800308 ATRACE_NAME("ProducerChannel::OnProducerMakePersistent");
309 ALOGD_IF(TRACE,
310 "ProducerChannel::OnProducerMakePersistent: buffer_id=%d name=%s "
311 "user_id=%d group_id=%d",
312 buffer_id(), name.c_str(), user_id, group_id);
313
314 if (name.empty() || (user_id < 0 && user_id != kNoCheckId) ||
315 (group_id < 0 && group_id != kNoCheckId)) {
Corey Tabakacd52dd92017-04-07 18:03:57 -0700316 return ErrorStatus(EINVAL);
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800317 }
318
319 // Try to add this buffer with the requested name.
320 if (service()->AddNamedBuffer(name, std::static_pointer_cast<ProducerChannel>(
321 shared_from_this()))) {
322 // If successful, set the requested permissions.
323
324 // A value of zero indicates that the ids from the sending process should be
325 // used.
326 if (user_id == kUseCallerId)
327 user_id = message.GetEffectiveUserId();
328 if (group_id == kUseCallerId)
329 group_id = message.GetEffectiveGroupId();
330
331 owner_user_id_ = user_id;
332 owner_group_id_ = group_id;
333 name_ = name;
Corey Tabakacd52dd92017-04-07 18:03:57 -0700334 return {};
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800335 } else {
336 // Otherwise a buffer with that name already exists.
Corey Tabakacd52dd92017-04-07 18:03:57 -0700337 return ErrorStatus(EALREADY);
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800338 }
339}
340
Corey Tabakacd52dd92017-04-07 18:03:57 -0700341Status<void> ProducerChannel::OnRemovePersistence(Message&) {
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800342 if (service()->RemoveNamedBuffer(*this))
Corey Tabakacd52dd92017-04-07 18:03:57 -0700343 return {};
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800344 else
Corey Tabakacd52dd92017-04-07 18:03:57 -0700345 return ErrorStatus(ENOENT);
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800346}
347
348void ProducerChannel::AddConsumer(ConsumerChannel* channel) {
349 consumer_channels_.push_back(channel);
350}
351
352void ProducerChannel::RemoveConsumer(ConsumerChannel* channel) {
353 consumer_channels_.erase(
354 std::find(consumer_channels_.begin(), consumer_channels_.end(), channel));
355}
356
357// Returns true if either the user or group ids match the owning ids or both
358// owning ids are not set, in which case access control does not apply.
359bool ProducerChannel::CheckAccess(int euid, int egid) {
360 const bool no_check =
361 owner_user_id_ == kNoCheckId && owner_group_id_ == kNoCheckId;
362 const bool euid_check = euid == owner_user_id_ || euid == kRootId;
363 const bool egid_check = egid == owner_group_id_ || egid == kRootId;
364 return no_check || euid_check || egid_check;
365}
366
367// Returns true if the given parameters match the underlying buffer parameters.
Corey Tabakacd52dd92017-04-07 18:03:57 -0700368bool ProducerChannel::CheckParameters(uint32_t width, uint32_t height,
Jiwen 'Steve' Cai0057fdd2017-05-02 11:21:18 -0700369 uint32_t format, uint64_t usage,
Corey Tabakacd52dd92017-04-07 18:03:57 -0700370 size_t meta_size_bytes,
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800371 size_t slice_count) {
Corey Tabaka3079cb72017-01-19 15:07:26 -0800372 return slices_.size() == slice_count && meta_size_bytes == meta_size_bytes_ &&
373 slices_[0].width() == width && slices_[0].height() == height &&
Jiwen 'Steve' Cai0057fdd2017-05-02 11:21:18 -0700374 slices_[0].format() == format && slices_[0].usage() == usage;
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800375}
376
377} // namespace dvr
378} // namespace android