blob: b2db79571748965b54d57cb158a2ba0007455759 [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,
Hendrik Wagenaar108e84f2017-05-07 22:19:17 -070029 uint32_t layer_count, uint32_t format,
30 uint64_t usage, size_t meta_size_bytes,
31 int* error)
Alex Vakulenkoe4eec202017-01-27 14:41:04 -080032 : BufferHubChannel(service, channel_id, channel_id, kProducerType),
33 pending_consumers_(0),
Alex Vakulenkoe4eec202017-01-27 14:41:04 -080034 producer_owns_(true),
35 meta_size_bytes_(meta_size_bytes),
36 meta_(meta_size_bytes ? new uint8_t[meta_size_bytes] : nullptr) {
Hendrik Wagenaar108e84f2017-05-07 22:19:17 -070037 const int ret = buffer_.Alloc(width, height, layer_count, format, usage);
Hendrik Wagenaar4d3590f2017-05-06 22:36:04 -070038 if (ret < 0) {
39 ALOGE("ProducerChannel::ProducerChannel: Failed to allocate buffer: %s",
40 strerror(-ret));
41 *error = ret;
42 return;
Alex Vakulenkoe4eec202017-01-27 14:41:04 -080043 }
44
45 // Success.
46 *error = 0;
47}
48
Corey Tabakacd52dd92017-04-07 18:03:57 -070049Status<std::shared_ptr<ProducerChannel>> ProducerChannel::Create(
50 BufferHubService* service, int channel_id, uint32_t width, uint32_t height,
Hendrik Wagenaar108e84f2017-05-07 22:19:17 -070051 uint32_t layer_count, uint32_t format, uint64_t usage,
52 size_t meta_size_bytes) {
Corey Tabakacd52dd92017-04-07 18:03:57 -070053 int error;
Jiwen 'Steve' Cai0057fdd2017-05-02 11:21:18 -070054 std::shared_ptr<ProducerChannel> producer(
Hendrik Wagenaar108e84f2017-05-07 22:19:17 -070055 new ProducerChannel(service, channel_id, width, height, layer_count,
56 format, usage, meta_size_bytes, &error));
Corey Tabakacd52dd92017-04-07 18:03:57 -070057 if (error < 0)
58 return ErrorStatus(-error);
Alex Vakulenkoe4eec202017-01-27 14:41:04 -080059 else
Corey Tabakacd52dd92017-04-07 18:03:57 -070060 return {std::move(producer)};
Alex Vakulenkoe4eec202017-01-27 14:41:04 -080061}
62
63ProducerChannel::~ProducerChannel() {
Corey Tabaka3079cb72017-01-19 15:07:26 -080064 ALOGD_IF(TRACE,
65 "ProducerChannel::~ProducerChannel: channel_id=%d buffer_id=%d",
66 channel_id(), buffer_id());
Alex Vakulenkoe4eec202017-01-27 14:41:04 -080067 for (auto consumer : consumer_channels_)
68 consumer->OnProducerClosed();
69}
70
71BufferHubChannel::BufferInfo ProducerChannel::GetBufferInfo() const {
Hendrik Wagenaar4d3590f2017-05-06 22:36:04 -070072 return BufferInfo(buffer_id(), consumer_channels_.size(), buffer_.width(),
Hendrik Wagenaar108e84f2017-05-07 22:19:17 -070073 buffer_.height(), buffer_.layer_count(), buffer_.format(),
74 buffer_.usage(), name_);
Alex Vakulenkoe4eec202017-01-27 14:41:04 -080075}
76
77void ProducerChannel::HandleImpulse(Message& message) {
78 ATRACE_NAME("ProducerChannel::HandleImpulse");
79 switch (message.GetOp()) {
80 case BufferHubRPC::ProducerGain::Opcode:
81 OnProducerGain(message);
82 break;
83 }
84}
85
86bool ProducerChannel::HandleMessage(Message& message) {
87 ATRACE_NAME("ProducerChannel::HandleMessage");
88 switch (message.GetOp()) {
89 case BufferHubRPC::GetBuffer::Opcode:
90 DispatchRemoteMethod<BufferHubRPC::GetBuffer>(
91 *this, &ProducerChannel::OnGetBuffer, message);
92 return true;
93
Alex Vakulenkoe4eec202017-01-27 14:41:04 -080094 case BufferHubRPC::NewConsumer::Opcode:
95 DispatchRemoteMethod<BufferHubRPC::NewConsumer>(
96 *this, &ProducerChannel::OnNewConsumer, message);
97 return true;
98
99 case BufferHubRPC::ProducerPost::Opcode:
100 DispatchRemoteMethod<BufferHubRPC::ProducerPost>(
101 *this, &ProducerChannel::OnProducerPost, message);
102 return true;
103
104 case BufferHubRPC::ProducerGain::Opcode:
105 DispatchRemoteMethod<BufferHubRPC::ProducerGain>(
106 *this, &ProducerChannel::OnProducerGain, message);
107 return true;
108
109 case BufferHubRPC::ProducerMakePersistent::Opcode:
110 DispatchRemoteMethod<BufferHubRPC::ProducerMakePersistent>(
111 *this, &ProducerChannel::OnProducerMakePersistent, message);
112 return true;
113
114 case BufferHubRPC::ProducerRemovePersistence::Opcode:
115 DispatchRemoteMethod<BufferHubRPC::ProducerRemovePersistence>(
116 *this, &ProducerChannel::OnRemovePersistence, message);
117 return true;
118
119 default:
120 return false;
121 }
122}
123
Corey Tabakacd52dd92017-04-07 18:03:57 -0700124Status<NativeBufferHandle<BorrowedHandle>> ProducerChannel::OnGetBuffer(
Corey Tabakad53870c2017-07-06 18:04:27 -0700125 Message& /*message*/) {
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800126 ATRACE_NAME("ProducerChannel::OnGetBuffer");
127 ALOGD_IF(TRACE, "ProducerChannel::OnGetBuffer: buffer=%d", buffer_id());
Hendrik Wagenaar4d3590f2017-05-06 22:36:04 -0700128 return {NativeBufferHandle<BorrowedHandle>(buffer_, buffer_id())};
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800129}
130
Corey Tabakacd52dd92017-04-07 18:03:57 -0700131Status<RemoteChannelHandle> ProducerChannel::CreateConsumer(Message& message) {
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800132 ATRACE_NAME("ProducerChannel::CreateConsumer");
133 ALOGD_IF(TRACE, "ProducerChannel::CreateConsumer: buffer_id=%d", buffer_id());
134
135 int channel_id;
136 auto status = message.PushChannel(0, nullptr, &channel_id);
137 if (!status) {
138 ALOGE(
Corey Tabakacd52dd92017-04-07 18:03:57 -0700139 "ProducerChannel::CreateConsumer: Failed to push consumer channel: %s",
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800140 status.GetErrorMessage().c_str());
Corey Tabakacd52dd92017-04-07 18:03:57 -0700141 return ErrorStatus(ENOMEM);
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800142 }
143
144 auto consumer = std::make_shared<ConsumerChannel>(
145 service(), buffer_id(), channel_id, shared_from_this());
Alex Vakulenkof0a7bd02017-03-31 18:06:19 -0700146 const auto channel_status = service()->SetChannel(channel_id, consumer);
147 if (!channel_status) {
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800148 ALOGE(
149 "ProducerChannel::CreateConsumer: failed to set new consumer channel: "
150 "%s",
Alex Vakulenkof0a7bd02017-03-31 18:06:19 -0700151 channel_status.GetErrorMessage().c_str());
Corey Tabakacd52dd92017-04-07 18:03:57 -0700152 return ErrorStatus(ENOMEM);
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800153 }
154
155 if (!producer_owns_) {
156 // Signal the new consumer when adding it to a posted producer.
157 if (consumer->OnProducerPosted())
158 pending_consumers_++;
159 }
160
Corey Tabakacd52dd92017-04-07 18:03:57 -0700161 return {status.take()};
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800162}
163
Corey Tabakacd52dd92017-04-07 18:03:57 -0700164Status<RemoteChannelHandle> ProducerChannel::OnNewConsumer(Message& message) {
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800165 ATRACE_NAME("ProducerChannel::OnNewConsumer");
166 ALOGD_IF(TRACE, "ProducerChannel::OnNewConsumer: buffer_id=%d", buffer_id());
Corey Tabakacd52dd92017-04-07 18:03:57 -0700167 return CreateConsumer(message);
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800168}
169
Corey Tabakacd52dd92017-04-07 18:03:57 -0700170Status<void> ProducerChannel::OnProducerPost(
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800171 Message&, LocalFence acquire_fence,
172 BufferWrapper<std::vector<std::uint8_t>> metadata) {
173 ATRACE_NAME("ProducerChannel::OnProducerPost");
174 ALOGD_IF(TRACE, "ProducerChannel::OnProducerPost: buffer_id=%d", buffer_id());
175 if (!producer_owns_) {
176 ALOGE("ProducerChannel::OnProducerPost: Not in gained state!");
Corey Tabakacd52dd92017-04-07 18:03:57 -0700177 return ErrorStatus(EBUSY);
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800178 }
179
Corey Tabaka8a4e6a92017-04-20 13:42:02 -0700180 if (meta_size_bytes_ != metadata.size()) {
181 ALOGD_IF(TRACE,
182 "ProducerChannel::OnProducerPost: Expected meta_size_bytes=%zu "
183 "got size=%zu",
184 meta_size_bytes_, metadata.size());
Corey Tabakacd52dd92017-04-07 18:03:57 -0700185 return ErrorStatus(EINVAL);
Corey Tabaka8a4e6a92017-04-20 13:42:02 -0700186 }
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800187
Corey Tabaka8a4e6a92017-04-20 13:42:02 -0700188 std::copy(metadata.begin(), metadata.end(), meta_.get());
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800189 post_fence_ = std::move(acquire_fence);
190 producer_owns_ = false;
191
192 // Signal any interested consumers. If there are none, automatically release
193 // the buffer.
194 pending_consumers_ = 0;
195 for (auto consumer : consumer_channels_) {
196 if (consumer->OnProducerPosted())
197 pending_consumers_++;
198 }
199 if (pending_consumers_ == 0)
200 SignalAvailable();
201 ALOGD_IF(TRACE, "ProducerChannel::OnProducerPost: %d pending consumers",
202 pending_consumers_);
203
Corey Tabakacd52dd92017-04-07 18:03:57 -0700204 return {};
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800205}
206
Corey Tabakad53870c2017-07-06 18:04:27 -0700207Status<LocalFence> ProducerChannel::OnProducerGain(Message& /*message*/) {
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800208 ATRACE_NAME("ProducerChannel::OnGain");
209 ALOGD_IF(TRACE, "ProducerChannel::OnGain: buffer_id=%d", buffer_id());
210 if (producer_owns_) {
211 ALOGE("ProducerChanneL::OnGain: Already in gained state: channel=%d",
212 channel_id());
Corey Tabakacd52dd92017-04-07 18:03:57 -0700213 return ErrorStatus(EALREADY);
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800214 }
215
216 // There are still pending consumers, return busy.
217 if (pending_consumers_ > 0)
Corey Tabakacd52dd92017-04-07 18:03:57 -0700218 return ErrorStatus(EBUSY);
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800219
220 ClearAvailable();
221 producer_owns_ = true;
Alex Vakulenko052f3ae2017-03-31 09:10:43 -0700222 post_fence_.close();
Corey Tabakacd52dd92017-04-07 18:03:57 -0700223 return {std::move(returned_fence_)};
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800224}
225
Corey Tabakacd52dd92017-04-07 18:03:57 -0700226Status<std::pair<BorrowedFence, BufferWrapper<std::uint8_t*>>>
Corey Tabakad53870c2017-07-06 18:04:27 -0700227ProducerChannel::OnConsumerAcquire(Message& /*message*/,
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800228 std::size_t metadata_size) {
229 ATRACE_NAME("ProducerChannel::OnConsumerAcquire");
230 ALOGD_IF(TRACE, "ProducerChannel::OnConsumerAcquire: buffer_id=%d",
231 buffer_id());
232 if (producer_owns_) {
233 ALOGE("ProducerChannel::OnConsumerAcquire: Not in posted state!");
Corey Tabakacd52dd92017-04-07 18:03:57 -0700234 return ErrorStatus(EBUSY);
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800235 }
236
237 // Return a borrowed fd to avoid unnecessary duplication of the underlying fd.
238 // Serialization just needs to read the handle.
239 if (metadata_size == 0)
Corey Tabakacd52dd92017-04-07 18:03:57 -0700240 return {std::make_pair(post_fence_.borrow(),
241 WrapBuffer<std::uint8_t>(nullptr, 0))};
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800242 else
Corey Tabakacd52dd92017-04-07 18:03:57 -0700243 return {std::make_pair(post_fence_.borrow(),
244 WrapBuffer(meta_.get(), meta_size_bytes_))};
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800245}
246
Corey Tabakacd52dd92017-04-07 18:03:57 -0700247Status<void> ProducerChannel::OnConsumerRelease(Message&,
248 LocalFence release_fence) {
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800249 ATRACE_NAME("ProducerChannel::OnConsumerRelease");
250 ALOGD_IF(TRACE, "ProducerChannel::OnConsumerRelease: buffer_id=%d",
251 buffer_id());
252 if (producer_owns_) {
253 ALOGE("ProducerChannel::OnConsumerRelease: Not in acquired state!");
Corey Tabakacd52dd92017-04-07 18:03:57 -0700254 return ErrorStatus(EBUSY);
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800255 }
256
257 // Attempt to merge the fences if necessary.
258 if (release_fence) {
259 if (returned_fence_) {
Corey Tabaka3079cb72017-01-19 15:07:26 -0800260 LocalFence merged_fence(sync_merge("bufferhub_merged",
261 returned_fence_.get_fd(),
262 release_fence.get_fd()));
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800263 const int error = errno;
264 if (!merged_fence) {
265 ALOGE("ProducerChannel::OnConsumerRelease: Failed to merge fences: %s",
266 strerror(error));
Corey Tabakacd52dd92017-04-07 18:03:57 -0700267 return ErrorStatus(error);
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800268 }
269 returned_fence_ = std::move(merged_fence);
270 } else {
271 returned_fence_ = std::move(release_fence);
272 }
273 }
274
275 OnConsumerIgnored();
Corey Tabakacd52dd92017-04-07 18:03:57 -0700276 return {};
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800277}
278
279void ProducerChannel::OnConsumerIgnored() {
280 if (!--pending_consumers_)
281 SignalAvailable();
282 ALOGD_IF(TRACE,
283 "ProducerChannel::OnConsumerIgnored: buffer_id=%d %d consumers left",
284 buffer_id(), pending_consumers_);
285}
286
Corey Tabakacd52dd92017-04-07 18:03:57 -0700287Status<void> ProducerChannel::OnProducerMakePersistent(Message& message,
288 const std::string& name,
289 int user_id,
290 int group_id) {
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800291 ATRACE_NAME("ProducerChannel::OnProducerMakePersistent");
292 ALOGD_IF(TRACE,
293 "ProducerChannel::OnProducerMakePersistent: buffer_id=%d name=%s "
294 "user_id=%d group_id=%d",
295 buffer_id(), name.c_str(), user_id, group_id);
296
297 if (name.empty() || (user_id < 0 && user_id != kNoCheckId) ||
298 (group_id < 0 && group_id != kNoCheckId)) {
Corey Tabakacd52dd92017-04-07 18:03:57 -0700299 return ErrorStatus(EINVAL);
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800300 }
301
302 // Try to add this buffer with the requested name.
303 if (service()->AddNamedBuffer(name, std::static_pointer_cast<ProducerChannel>(
304 shared_from_this()))) {
305 // If successful, set the requested permissions.
306
307 // A value of zero indicates that the ids from the sending process should be
308 // used.
309 if (user_id == kUseCallerId)
310 user_id = message.GetEffectiveUserId();
311 if (group_id == kUseCallerId)
312 group_id = message.GetEffectiveGroupId();
313
314 owner_user_id_ = user_id;
315 owner_group_id_ = group_id;
316 name_ = name;
Corey Tabakacd52dd92017-04-07 18:03:57 -0700317 return {};
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800318 } else {
319 // Otherwise a buffer with that name already exists.
Corey Tabakacd52dd92017-04-07 18:03:57 -0700320 return ErrorStatus(EALREADY);
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800321 }
322}
323
Corey Tabakacd52dd92017-04-07 18:03:57 -0700324Status<void> ProducerChannel::OnRemovePersistence(Message&) {
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800325 if (service()->RemoveNamedBuffer(*this))
Corey Tabakacd52dd92017-04-07 18:03:57 -0700326 return {};
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800327 else
Corey Tabakacd52dd92017-04-07 18:03:57 -0700328 return ErrorStatus(ENOENT);
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800329}
330
331void ProducerChannel::AddConsumer(ConsumerChannel* channel) {
332 consumer_channels_.push_back(channel);
333}
334
335void ProducerChannel::RemoveConsumer(ConsumerChannel* channel) {
336 consumer_channels_.erase(
337 std::find(consumer_channels_.begin(), consumer_channels_.end(), channel));
338}
339
340// Returns true if either the user or group ids match the owning ids or both
341// owning ids are not set, in which case access control does not apply.
342bool ProducerChannel::CheckAccess(int euid, int egid) {
343 const bool no_check =
344 owner_user_id_ == kNoCheckId && owner_group_id_ == kNoCheckId;
345 const bool euid_check = euid == owner_user_id_ || euid == kRootId;
346 const bool egid_check = egid == owner_group_id_ || egid == kRootId;
347 return no_check || euid_check || egid_check;
348}
349
350// Returns true if the given parameters match the underlying buffer parameters.
Corey Tabakacd52dd92017-04-07 18:03:57 -0700351bool ProducerChannel::CheckParameters(uint32_t width, uint32_t height,
Hendrik Wagenaar108e84f2017-05-07 22:19:17 -0700352 uint32_t layer_count, uint32_t format,
353 uint64_t usage, size_t meta_size_bytes) {
Hendrik Wagenaar4d3590f2017-05-06 22:36:04 -0700354 return meta_size_bytes == meta_size_bytes_ && buffer_.width() == width &&
Hendrik Wagenaar108e84f2017-05-07 22:19:17 -0700355 buffer_.height() == height && buffer_.layer_count() == layer_count &&
356 buffer_.format() == format && buffer_.usage() == usage;
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800357}
358
359} // namespace dvr
360} // namespace android