blob: 4005f7eed732d1e816c1d7518e7d356931e76b8c [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,
Hendrik Wagenaar4d3590f2017-05-06 22:36:04 -070030 size_t meta_size_bytes, int* error)
Alex Vakulenkoe4eec202017-01-27 14:41:04 -080031 : BufferHubChannel(service, channel_id, channel_id, kProducerType),
32 pending_consumers_(0),
Alex Vakulenkoe4eec202017-01-27 14:41:04 -080033 producer_owns_(true),
34 meta_size_bytes_(meta_size_bytes),
35 meta_(meta_size_bytes ? new uint8_t[meta_size_bytes] : nullptr) {
Hendrik Wagenaar4d3590f2017-05-06 22:36:04 -070036 const int ret = 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;
Alex Vakulenkoe4eec202017-01-27 14:41:04 -080042 }
43
44 // Success.
45 *error = 0;
46}
47
Corey Tabakacd52dd92017-04-07 18:03:57 -070048Status<std::shared_ptr<ProducerChannel>> ProducerChannel::Create(
49 BufferHubService* service, int channel_id, uint32_t width, uint32_t height,
Hendrik Wagenaar4d3590f2017-05-06 22:36:04 -070050 uint32_t format, uint64_t usage, size_t meta_size_bytes) {
Corey Tabakacd52dd92017-04-07 18:03:57 -070051 int error;
Jiwen 'Steve' Cai0057fdd2017-05-02 11:21:18 -070052 std::shared_ptr<ProducerChannel> producer(
53 new ProducerChannel(service, channel_id, width, height, format, usage,
Hendrik Wagenaar4d3590f2017-05-06 22:36:04 -070054 meta_size_bytes, &error));
Corey Tabakacd52dd92017-04-07 18:03:57 -070055 if (error < 0)
56 return ErrorStatus(-error);
Alex Vakulenkoe4eec202017-01-27 14:41:04 -080057 else
Corey Tabakacd52dd92017-04-07 18:03:57 -070058 return {std::move(producer)};
Alex Vakulenkoe4eec202017-01-27 14:41:04 -080059}
60
61ProducerChannel::~ProducerChannel() {
Corey Tabaka3079cb72017-01-19 15:07:26 -080062 ALOGD_IF(TRACE,
63 "ProducerChannel::~ProducerChannel: channel_id=%d buffer_id=%d",
64 channel_id(), buffer_id());
Alex Vakulenkoe4eec202017-01-27 14:41:04 -080065 for (auto consumer : consumer_channels_)
66 consumer->OnProducerClosed();
67}
68
69BufferHubChannel::BufferInfo ProducerChannel::GetBufferInfo() const {
Hendrik Wagenaar4d3590f2017-05-06 22:36:04 -070070 return BufferInfo(buffer_id(), consumer_channels_.size(), buffer_.width(),
71 buffer_.height(), buffer_.format(), buffer_.usage(), name_);
Alex Vakulenkoe4eec202017-01-27 14:41:04 -080072}
73
74void ProducerChannel::HandleImpulse(Message& message) {
75 ATRACE_NAME("ProducerChannel::HandleImpulse");
76 switch (message.GetOp()) {
77 case BufferHubRPC::ProducerGain::Opcode:
78 OnProducerGain(message);
79 break;
80 }
81}
82
83bool ProducerChannel::HandleMessage(Message& message) {
84 ATRACE_NAME("ProducerChannel::HandleMessage");
85 switch (message.GetOp()) {
86 case BufferHubRPC::GetBuffer::Opcode:
87 DispatchRemoteMethod<BufferHubRPC::GetBuffer>(
88 *this, &ProducerChannel::OnGetBuffer, message);
89 return true;
90
Alex Vakulenkoe4eec202017-01-27 14:41:04 -080091 case BufferHubRPC::NewConsumer::Opcode:
92 DispatchRemoteMethod<BufferHubRPC::NewConsumer>(
93 *this, &ProducerChannel::OnNewConsumer, message);
94 return true;
95
96 case BufferHubRPC::ProducerPost::Opcode:
97 DispatchRemoteMethod<BufferHubRPC::ProducerPost>(
98 *this, &ProducerChannel::OnProducerPost, message);
99 return true;
100
101 case BufferHubRPC::ProducerGain::Opcode:
102 DispatchRemoteMethod<BufferHubRPC::ProducerGain>(
103 *this, &ProducerChannel::OnProducerGain, message);
104 return true;
105
106 case BufferHubRPC::ProducerMakePersistent::Opcode:
107 DispatchRemoteMethod<BufferHubRPC::ProducerMakePersistent>(
108 *this, &ProducerChannel::OnProducerMakePersistent, message);
109 return true;
110
111 case BufferHubRPC::ProducerRemovePersistence::Opcode:
112 DispatchRemoteMethod<BufferHubRPC::ProducerRemovePersistence>(
113 *this, &ProducerChannel::OnRemovePersistence, message);
114 return true;
115
116 default:
117 return false;
118 }
119}
120
Corey Tabakacd52dd92017-04-07 18:03:57 -0700121Status<NativeBufferHandle<BorrowedHandle>> ProducerChannel::OnGetBuffer(
Hendrik Wagenaar4d3590f2017-05-06 22:36:04 -0700122 Message& message) {
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800123 ATRACE_NAME("ProducerChannel::OnGetBuffer");
124 ALOGD_IF(TRACE, "ProducerChannel::OnGetBuffer: buffer=%d", buffer_id());
Hendrik Wagenaar4d3590f2017-05-06 22:36:04 -0700125 return {NativeBufferHandle<BorrowedHandle>(buffer_, buffer_id())};
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800126}
127
Corey Tabakacd52dd92017-04-07 18:03:57 -0700128Status<RemoteChannelHandle> ProducerChannel::CreateConsumer(Message& message) {
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800129 ATRACE_NAME("ProducerChannel::CreateConsumer");
130 ALOGD_IF(TRACE, "ProducerChannel::CreateConsumer: buffer_id=%d", buffer_id());
131
132 int channel_id;
133 auto status = message.PushChannel(0, nullptr, &channel_id);
134 if (!status) {
135 ALOGE(
Corey Tabakacd52dd92017-04-07 18:03:57 -0700136 "ProducerChannel::CreateConsumer: Failed to push consumer channel: %s",
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800137 status.GetErrorMessage().c_str());
Corey Tabakacd52dd92017-04-07 18:03:57 -0700138 return ErrorStatus(ENOMEM);
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800139 }
140
141 auto consumer = std::make_shared<ConsumerChannel>(
142 service(), buffer_id(), channel_id, shared_from_this());
Alex Vakulenkof0a7bd02017-03-31 18:06:19 -0700143 const auto channel_status = service()->SetChannel(channel_id, consumer);
144 if (!channel_status) {
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800145 ALOGE(
146 "ProducerChannel::CreateConsumer: failed to set new consumer channel: "
147 "%s",
Alex Vakulenkof0a7bd02017-03-31 18:06:19 -0700148 channel_status.GetErrorMessage().c_str());
Corey Tabakacd52dd92017-04-07 18:03:57 -0700149 return ErrorStatus(ENOMEM);
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800150 }
151
152 if (!producer_owns_) {
153 // Signal the new consumer when adding it to a posted producer.
154 if (consumer->OnProducerPosted())
155 pending_consumers_++;
156 }
157
Corey Tabakacd52dd92017-04-07 18:03:57 -0700158 return {status.take()};
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800159}
160
Corey Tabakacd52dd92017-04-07 18:03:57 -0700161Status<RemoteChannelHandle> ProducerChannel::OnNewConsumer(Message& message) {
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800162 ATRACE_NAME("ProducerChannel::OnNewConsumer");
163 ALOGD_IF(TRACE, "ProducerChannel::OnNewConsumer: buffer_id=%d", buffer_id());
Corey Tabakacd52dd92017-04-07 18:03:57 -0700164 return CreateConsumer(message);
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800165}
166
Corey Tabakacd52dd92017-04-07 18:03:57 -0700167Status<void> ProducerChannel::OnProducerPost(
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800168 Message&, LocalFence acquire_fence,
169 BufferWrapper<std::vector<std::uint8_t>> metadata) {
170 ATRACE_NAME("ProducerChannel::OnProducerPost");
171 ALOGD_IF(TRACE, "ProducerChannel::OnProducerPost: buffer_id=%d", buffer_id());
172 if (!producer_owns_) {
173 ALOGE("ProducerChannel::OnProducerPost: Not in gained state!");
Corey Tabakacd52dd92017-04-07 18:03:57 -0700174 return ErrorStatus(EBUSY);
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800175 }
176
Corey Tabaka8a4e6a92017-04-20 13:42:02 -0700177 if (meta_size_bytes_ != metadata.size()) {
178 ALOGD_IF(TRACE,
179 "ProducerChannel::OnProducerPost: Expected meta_size_bytes=%zu "
180 "got size=%zu",
181 meta_size_bytes_, metadata.size());
Corey Tabakacd52dd92017-04-07 18:03:57 -0700182 return ErrorStatus(EINVAL);
Corey Tabaka8a4e6a92017-04-20 13:42:02 -0700183 }
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800184
Corey Tabaka8a4e6a92017-04-20 13:42:02 -0700185 std::copy(metadata.begin(), metadata.end(), meta_.get());
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800186 post_fence_ = std::move(acquire_fence);
187 producer_owns_ = false;
188
189 // Signal any interested consumers. If there are none, automatically release
190 // the buffer.
191 pending_consumers_ = 0;
192 for (auto consumer : consumer_channels_) {
193 if (consumer->OnProducerPosted())
194 pending_consumers_++;
195 }
196 if (pending_consumers_ == 0)
197 SignalAvailable();
198 ALOGD_IF(TRACE, "ProducerChannel::OnProducerPost: %d pending consumers",
199 pending_consumers_);
200
Corey Tabakacd52dd92017-04-07 18:03:57 -0700201 return {};
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800202}
203
Corey Tabakacd52dd92017-04-07 18:03:57 -0700204Status<LocalFence> ProducerChannel::OnProducerGain(Message& message) {
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800205 ATRACE_NAME("ProducerChannel::OnGain");
206 ALOGD_IF(TRACE, "ProducerChannel::OnGain: buffer_id=%d", buffer_id());
207 if (producer_owns_) {
208 ALOGE("ProducerChanneL::OnGain: Already in gained state: channel=%d",
209 channel_id());
Corey Tabakacd52dd92017-04-07 18:03:57 -0700210 return ErrorStatus(EALREADY);
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800211 }
212
213 // There are still pending consumers, return busy.
214 if (pending_consumers_ > 0)
Corey Tabakacd52dd92017-04-07 18:03:57 -0700215 return ErrorStatus(EBUSY);
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800216
217 ClearAvailable();
218 producer_owns_ = true;
Alex Vakulenko052f3ae2017-03-31 09:10:43 -0700219 post_fence_.close();
Corey Tabakacd52dd92017-04-07 18:03:57 -0700220 return {std::move(returned_fence_)};
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800221}
222
Corey Tabakacd52dd92017-04-07 18:03:57 -0700223Status<std::pair<BorrowedFence, BufferWrapper<std::uint8_t*>>>
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800224ProducerChannel::OnConsumerAcquire(Message& message,
225 std::size_t metadata_size) {
226 ATRACE_NAME("ProducerChannel::OnConsumerAcquire");
227 ALOGD_IF(TRACE, "ProducerChannel::OnConsumerAcquire: buffer_id=%d",
228 buffer_id());
229 if (producer_owns_) {
230 ALOGE("ProducerChannel::OnConsumerAcquire: Not in posted state!");
Corey Tabakacd52dd92017-04-07 18:03:57 -0700231 return ErrorStatus(EBUSY);
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800232 }
233
234 // Return a borrowed fd to avoid unnecessary duplication of the underlying fd.
235 // Serialization just needs to read the handle.
236 if (metadata_size == 0)
Corey Tabakacd52dd92017-04-07 18:03:57 -0700237 return {std::make_pair(post_fence_.borrow(),
238 WrapBuffer<std::uint8_t>(nullptr, 0))};
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800239 else
Corey Tabakacd52dd92017-04-07 18:03:57 -0700240 return {std::make_pair(post_fence_.borrow(),
241 WrapBuffer(meta_.get(), meta_size_bytes_))};
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800242}
243
Corey Tabakacd52dd92017-04-07 18:03:57 -0700244Status<void> ProducerChannel::OnConsumerRelease(Message&,
245 LocalFence release_fence) {
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800246 ATRACE_NAME("ProducerChannel::OnConsumerRelease");
247 ALOGD_IF(TRACE, "ProducerChannel::OnConsumerRelease: buffer_id=%d",
248 buffer_id());
249 if (producer_owns_) {
250 ALOGE("ProducerChannel::OnConsumerRelease: Not in acquired state!");
Corey Tabakacd52dd92017-04-07 18:03:57 -0700251 return ErrorStatus(EBUSY);
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800252 }
253
254 // Attempt to merge the fences if necessary.
255 if (release_fence) {
256 if (returned_fence_) {
Corey Tabaka3079cb72017-01-19 15:07:26 -0800257 LocalFence merged_fence(sync_merge("bufferhub_merged",
258 returned_fence_.get_fd(),
259 release_fence.get_fd()));
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800260 const int error = errno;
261 if (!merged_fence) {
262 ALOGE("ProducerChannel::OnConsumerRelease: Failed to merge fences: %s",
263 strerror(error));
Corey Tabakacd52dd92017-04-07 18:03:57 -0700264 return ErrorStatus(error);
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800265 }
266 returned_fence_ = std::move(merged_fence);
267 } else {
268 returned_fence_ = std::move(release_fence);
269 }
270 }
271
272 OnConsumerIgnored();
Corey Tabakacd52dd92017-04-07 18:03:57 -0700273 return {};
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800274}
275
276void ProducerChannel::OnConsumerIgnored() {
277 if (!--pending_consumers_)
278 SignalAvailable();
279 ALOGD_IF(TRACE,
280 "ProducerChannel::OnConsumerIgnored: buffer_id=%d %d consumers left",
281 buffer_id(), pending_consumers_);
282}
283
Corey Tabakacd52dd92017-04-07 18:03:57 -0700284Status<void> ProducerChannel::OnProducerMakePersistent(Message& message,
285 const std::string& name,
286 int user_id,
287 int group_id) {
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800288 ATRACE_NAME("ProducerChannel::OnProducerMakePersistent");
289 ALOGD_IF(TRACE,
290 "ProducerChannel::OnProducerMakePersistent: buffer_id=%d name=%s "
291 "user_id=%d group_id=%d",
292 buffer_id(), name.c_str(), user_id, group_id);
293
294 if (name.empty() || (user_id < 0 && user_id != kNoCheckId) ||
295 (group_id < 0 && group_id != kNoCheckId)) {
Corey Tabakacd52dd92017-04-07 18:03:57 -0700296 return ErrorStatus(EINVAL);
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800297 }
298
299 // Try to add this buffer with the requested name.
300 if (service()->AddNamedBuffer(name, std::static_pointer_cast<ProducerChannel>(
301 shared_from_this()))) {
302 // If successful, set the requested permissions.
303
304 // A value of zero indicates that the ids from the sending process should be
305 // used.
306 if (user_id == kUseCallerId)
307 user_id = message.GetEffectiveUserId();
308 if (group_id == kUseCallerId)
309 group_id = message.GetEffectiveGroupId();
310
311 owner_user_id_ = user_id;
312 owner_group_id_ = group_id;
313 name_ = name;
Corey Tabakacd52dd92017-04-07 18:03:57 -0700314 return {};
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800315 } else {
316 // Otherwise a buffer with that name already exists.
Corey Tabakacd52dd92017-04-07 18:03:57 -0700317 return ErrorStatus(EALREADY);
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800318 }
319}
320
Corey Tabakacd52dd92017-04-07 18:03:57 -0700321Status<void> ProducerChannel::OnRemovePersistence(Message&) {
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800322 if (service()->RemoveNamedBuffer(*this))
Corey Tabakacd52dd92017-04-07 18:03:57 -0700323 return {};
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800324 else
Corey Tabakacd52dd92017-04-07 18:03:57 -0700325 return ErrorStatus(ENOENT);
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800326}
327
328void ProducerChannel::AddConsumer(ConsumerChannel* channel) {
329 consumer_channels_.push_back(channel);
330}
331
332void ProducerChannel::RemoveConsumer(ConsumerChannel* channel) {
333 consumer_channels_.erase(
334 std::find(consumer_channels_.begin(), consumer_channels_.end(), channel));
335}
336
337// Returns true if either the user or group ids match the owning ids or both
338// owning ids are not set, in which case access control does not apply.
339bool ProducerChannel::CheckAccess(int euid, int egid) {
340 const bool no_check =
341 owner_user_id_ == kNoCheckId && owner_group_id_ == kNoCheckId;
342 const bool euid_check = euid == owner_user_id_ || euid == kRootId;
343 const bool egid_check = egid == owner_group_id_ || egid == kRootId;
344 return no_check || euid_check || egid_check;
345}
346
347// Returns true if the given parameters match the underlying buffer parameters.
Corey Tabakacd52dd92017-04-07 18:03:57 -0700348bool ProducerChannel::CheckParameters(uint32_t width, uint32_t height,
Jiwen 'Steve' Cai0057fdd2017-05-02 11:21:18 -0700349 uint32_t format, uint64_t usage,
Hendrik Wagenaar4d3590f2017-05-06 22:36:04 -0700350 size_t meta_size_bytes) {
351 return meta_size_bytes == meta_size_bytes_ && buffer_.width() == width &&
352 buffer_.height() == height && buffer_.format() == format &&
353 buffer_.usage() == usage;
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800354}
355
356} // namespace dvr
357} // namespace android