blob: 398aa1252bdd08bbe872dcb3f958fae070e4b2e8 [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
Corey Tabaka8a4e6a92017-04-20 13:42:02 -0700202 if (meta_size_bytes_ != metadata.size()) {
203 ALOGD_IF(TRACE,
204 "ProducerChannel::OnProducerPost: Expected meta_size_bytes=%zu "
205 "got size=%zu",
206 meta_size_bytes_, metadata.size());
Corey Tabakacd52dd92017-04-07 18:03:57 -0700207 return ErrorStatus(EINVAL);
Corey Tabaka8a4e6a92017-04-20 13:42:02 -0700208 }
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800209
Corey Tabaka8a4e6a92017-04-20 13:42:02 -0700210 std::copy(metadata.begin(), metadata.end(), meta_.get());
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800211 post_fence_ = std::move(acquire_fence);
212 producer_owns_ = false;
213
214 // Signal any interested consumers. If there are none, automatically release
215 // the buffer.
216 pending_consumers_ = 0;
217 for (auto consumer : consumer_channels_) {
218 if (consumer->OnProducerPosted())
219 pending_consumers_++;
220 }
221 if (pending_consumers_ == 0)
222 SignalAvailable();
223 ALOGD_IF(TRACE, "ProducerChannel::OnProducerPost: %d pending consumers",
224 pending_consumers_);
225
Corey Tabakacd52dd92017-04-07 18:03:57 -0700226 return {};
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800227}
228
Corey Tabakacd52dd92017-04-07 18:03:57 -0700229Status<LocalFence> ProducerChannel::OnProducerGain(Message& message) {
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800230 ATRACE_NAME("ProducerChannel::OnGain");
231 ALOGD_IF(TRACE, "ProducerChannel::OnGain: buffer_id=%d", buffer_id());
232 if (producer_owns_) {
233 ALOGE("ProducerChanneL::OnGain: Already in gained state: channel=%d",
234 channel_id());
Corey Tabakacd52dd92017-04-07 18:03:57 -0700235 return ErrorStatus(EALREADY);
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800236 }
237
238 // There are still pending consumers, return busy.
239 if (pending_consumers_ > 0)
Corey Tabakacd52dd92017-04-07 18:03:57 -0700240 return ErrorStatus(EBUSY);
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800241
242 ClearAvailable();
243 producer_owns_ = true;
Alex Vakulenko052f3ae2017-03-31 09:10:43 -0700244 post_fence_.close();
Corey Tabakacd52dd92017-04-07 18:03:57 -0700245 return {std::move(returned_fence_)};
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800246}
247
Corey Tabakacd52dd92017-04-07 18:03:57 -0700248Status<std::pair<BorrowedFence, BufferWrapper<std::uint8_t*>>>
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800249ProducerChannel::OnConsumerAcquire(Message& message,
250 std::size_t metadata_size) {
251 ATRACE_NAME("ProducerChannel::OnConsumerAcquire");
252 ALOGD_IF(TRACE, "ProducerChannel::OnConsumerAcquire: buffer_id=%d",
253 buffer_id());
254 if (producer_owns_) {
255 ALOGE("ProducerChannel::OnConsumerAcquire: Not in posted state!");
Corey Tabakacd52dd92017-04-07 18:03:57 -0700256 return ErrorStatus(EBUSY);
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800257 }
258
259 // Return a borrowed fd to avoid unnecessary duplication of the underlying fd.
260 // Serialization just needs to read the handle.
261 if (metadata_size == 0)
Corey Tabakacd52dd92017-04-07 18:03:57 -0700262 return {std::make_pair(post_fence_.borrow(),
263 WrapBuffer<std::uint8_t>(nullptr, 0))};
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800264 else
Corey Tabakacd52dd92017-04-07 18:03:57 -0700265 return {std::make_pair(post_fence_.borrow(),
266 WrapBuffer(meta_.get(), meta_size_bytes_))};
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800267}
268
Corey Tabakacd52dd92017-04-07 18:03:57 -0700269Status<void> ProducerChannel::OnConsumerRelease(Message&,
270 LocalFence release_fence) {
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800271 ATRACE_NAME("ProducerChannel::OnConsumerRelease");
272 ALOGD_IF(TRACE, "ProducerChannel::OnConsumerRelease: buffer_id=%d",
273 buffer_id());
274 if (producer_owns_) {
275 ALOGE("ProducerChannel::OnConsumerRelease: Not in acquired state!");
Corey Tabakacd52dd92017-04-07 18:03:57 -0700276 return ErrorStatus(EBUSY);
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800277 }
278
279 // Attempt to merge the fences if necessary.
280 if (release_fence) {
281 if (returned_fence_) {
Corey Tabaka3079cb72017-01-19 15:07:26 -0800282 LocalFence merged_fence(sync_merge("bufferhub_merged",
283 returned_fence_.get_fd(),
284 release_fence.get_fd()));
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800285 const int error = errno;
286 if (!merged_fence) {
287 ALOGE("ProducerChannel::OnConsumerRelease: Failed to merge fences: %s",
288 strerror(error));
Corey Tabakacd52dd92017-04-07 18:03:57 -0700289 return ErrorStatus(error);
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800290 }
291 returned_fence_ = std::move(merged_fence);
292 } else {
293 returned_fence_ = std::move(release_fence);
294 }
295 }
296
297 OnConsumerIgnored();
Corey Tabakacd52dd92017-04-07 18:03:57 -0700298 return {};
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800299}
300
301void ProducerChannel::OnConsumerIgnored() {
302 if (!--pending_consumers_)
303 SignalAvailable();
304 ALOGD_IF(TRACE,
305 "ProducerChannel::OnConsumerIgnored: buffer_id=%d %d consumers left",
306 buffer_id(), pending_consumers_);
307}
308
Corey Tabakacd52dd92017-04-07 18:03:57 -0700309Status<void> ProducerChannel::OnProducerMakePersistent(Message& message,
310 const std::string& name,
311 int user_id,
312 int group_id) {
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800313 ATRACE_NAME("ProducerChannel::OnProducerMakePersistent");
314 ALOGD_IF(TRACE,
315 "ProducerChannel::OnProducerMakePersistent: buffer_id=%d name=%s "
316 "user_id=%d group_id=%d",
317 buffer_id(), name.c_str(), user_id, group_id);
318
319 if (name.empty() || (user_id < 0 && user_id != kNoCheckId) ||
320 (group_id < 0 && group_id != kNoCheckId)) {
Corey Tabakacd52dd92017-04-07 18:03:57 -0700321 return ErrorStatus(EINVAL);
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800322 }
323
324 // Try to add this buffer with the requested name.
325 if (service()->AddNamedBuffer(name, std::static_pointer_cast<ProducerChannel>(
326 shared_from_this()))) {
327 // If successful, set the requested permissions.
328
329 // A value of zero indicates that the ids from the sending process should be
330 // used.
331 if (user_id == kUseCallerId)
332 user_id = message.GetEffectiveUserId();
333 if (group_id == kUseCallerId)
334 group_id = message.GetEffectiveGroupId();
335
336 owner_user_id_ = user_id;
337 owner_group_id_ = group_id;
338 name_ = name;
Corey Tabakacd52dd92017-04-07 18:03:57 -0700339 return {};
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800340 } else {
341 // Otherwise a buffer with that name already exists.
Corey Tabakacd52dd92017-04-07 18:03:57 -0700342 return ErrorStatus(EALREADY);
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800343 }
344}
345
Corey Tabakacd52dd92017-04-07 18:03:57 -0700346Status<void> ProducerChannel::OnRemovePersistence(Message&) {
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800347 if (service()->RemoveNamedBuffer(*this))
Corey Tabakacd52dd92017-04-07 18:03:57 -0700348 return {};
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800349 else
Corey Tabakacd52dd92017-04-07 18:03:57 -0700350 return ErrorStatus(ENOENT);
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800351}
352
353void ProducerChannel::AddConsumer(ConsumerChannel* channel) {
354 consumer_channels_.push_back(channel);
355}
356
357void ProducerChannel::RemoveConsumer(ConsumerChannel* channel) {
358 consumer_channels_.erase(
359 std::find(consumer_channels_.begin(), consumer_channels_.end(), channel));
360}
361
362// Returns true if either the user or group ids match the owning ids or both
363// owning ids are not set, in which case access control does not apply.
364bool ProducerChannel::CheckAccess(int euid, int egid) {
365 const bool no_check =
366 owner_user_id_ == kNoCheckId && owner_group_id_ == kNoCheckId;
367 const bool euid_check = euid == owner_user_id_ || euid == kRootId;
368 const bool egid_check = egid == owner_group_id_ || egid == kRootId;
369 return no_check || euid_check || egid_check;
370}
371
372// Returns true if the given parameters match the underlying buffer parameters.
Corey Tabakacd52dd92017-04-07 18:03:57 -0700373bool ProducerChannel::CheckParameters(uint32_t width, uint32_t height,
Jiwen 'Steve' Cai0057fdd2017-05-02 11:21:18 -0700374 uint32_t format, uint64_t usage,
Corey Tabakacd52dd92017-04-07 18:03:57 -0700375 size_t meta_size_bytes,
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800376 size_t slice_count) {
Corey Tabaka3079cb72017-01-19 15:07:26 -0800377 return slices_.size() == slice_count && meta_size_bytes == meta_size_bytes_ &&
378 slices_[0].width() == width && slices_[0].height() == height &&
Jiwen 'Steve' Cai0057fdd2017-05-02 11:21:18 -0700379 slices_[0].format() == format && slices_[0].usage() == usage;
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800380}
381
382} // namespace dvr
383} // namespace android