blob: 2ce60e57aca3eae402d19457059a1cb94d7c8fe1 [file] [log] [blame]
Alex Vakulenkoe4eec202017-01-27 14:41:04 -08001#include "buffer_hub.h"
2
Alex Vakulenko4fe60582017-02-02 11:35:59 -08003#include <log/log.h>
Alex Vakulenkoe4eec202017-01-27 14:41:04 -08004#include <poll.h>
5#include <utils/Trace.h>
6
7#include <iomanip>
8#include <sstream>
9#include <string>
10#include <thread>
11
12#include <pdx/default_transport/service_endpoint.h>
13#include <private/dvr/bufferhub_rpc.h>
14#include "consumer_channel.h"
15#include "producer_channel.h"
16#include "producer_queue_channel.h"
17
18using android::pdx::Channel;
Corey Tabaka1db8a5d2017-03-22 02:12:52 -070019using android::pdx::ErrorStatus;
Alex Vakulenkoe4eec202017-01-27 14:41:04 -080020using android::pdx::Message;
Corey Tabaka1db8a5d2017-03-22 02:12:52 -070021using android::pdx::Status;
Alex Vakulenkoe4eec202017-01-27 14:41:04 -080022using android::pdx::rpc::DispatchRemoteMethod;
23using android::pdx::default_transport::Endpoint;
24
25namespace android {
26namespace dvr {
27
28BufferHubService::BufferHubService()
29 : BASE("BufferHub", Endpoint::Create(BufferHubRPC::kClientPath)) {}
30
31BufferHubService::~BufferHubService() {}
32
Corey Tabaka1db8a5d2017-03-22 02:12:52 -070033bool BufferHubService::IsInitialized() const { return BASE::IsInitialized(); }
Alex Vakulenkoe4eec202017-01-27 14:41:04 -080034
35std::string BufferHubService::DumpState(size_t /*max_length*/) {
36 std::ostringstream stream;
37 auto channels = GetChannels<BufferHubChannel>();
38
39 std::sort(channels.begin(), channels.end(),
40 [](const std::shared_ptr<BufferHubChannel>& a,
41 const std::shared_ptr<BufferHubChannel>& b) {
42 return a->buffer_id() < b->buffer_id();
43 });
44
45 stream << "Active Producer Buffers:\n";
46 stream << std::right;
47 stream << std::setw(6) << "Id";
48 stream << " ";
49 stream << std::setw(9) << "Consumers";
50 stream << " ";
51 stream << std::setw(14) << "Geometry";
52 stream << " ";
53 stream << std::setw(6) << "Format";
54 stream << " ";
55 stream << std::setw(10) << "Usage";
56 stream << " ";
57 stream << "Name";
58 stream << std::endl;
59
60 for (const auto& channel : channels) {
61 if (channel->channel_type() == BufferHubChannel::kProducerType) {
62 BufferHubChannel::BufferInfo info = channel->GetBufferInfo();
63
64 stream << std::right;
65 stream << std::setw(6) << info.id;
66 stream << " ";
67 stream << std::setw(9) << info.consumer_count;
68 stream << " ";
69 if (info.format == HAL_PIXEL_FORMAT_BLOB) {
70 std::string size = std::to_string(info.width) + " B";
71 stream << std::setw(14) << size;
72 } else {
73 std::string dimensions = std::to_string(info.width) + "x" +
74 std::to_string(info.height) + "x" +
75 std::to_string(info.slice_count);
76 stream << std::setw(14) << dimensions;
77 }
78 stream << " ";
79 stream << std::setw(6) << info.format;
80 stream << " ";
81 stream << "0x" << std::hex << std::setfill('0');
82 stream << std::setw(8) << info.usage;
83 stream << std::dec << std::setfill(' ');
84 stream << " ";
85 stream << info.name;
86 stream << std::endl;
87 }
88 }
89
90 stream << "Active Consumer Buffers:\n";
91 stream << std::right;
92 stream << std::setw(6) << "Id";
93 stream << " ";
94 stream << std::setw(14) << "Geometry";
95 stream << " ";
96 stream << "Name";
97 stream << std::endl;
98
99 for (const auto& channel : channels) {
100 if (channel->channel_type() == BufferHubChannel::kConsumerType) {
101 BufferHubChannel::BufferInfo info = channel->GetBufferInfo();
102
103 stream << std::right;
104 stream << std::setw(6) << info.id;
105 stream << " ";
106
107 if (info.consumer_count == 0) {
108 // consumer_count is tracked by producer. When it's zero, producer must
109 // have already hung up and the consumer is orphaned.
110 stream << std::setw(14) << "Orphaned.";
Corey Tabaka3079cb72017-01-19 15:07:26 -0800111 stream << (" channel_id=" + std::to_string(channel->channel_id()));
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800112 stream << std::endl;
113 continue;
114 }
115
116 if (info.format == HAL_PIXEL_FORMAT_BLOB) {
117 std::string size = std::to_string(info.width) + " B";
118 stream << std::setw(14) << size;
119 } else {
120 std::string dimensions = std::to_string(info.width) + "x" +
121 std::to_string(info.height) + "x" +
122 std::to_string(info.slice_count);
123 stream << std::setw(14) << dimensions;
124 }
125 stream << " ";
126 stream << info.name;
127 stream << std::endl;
128 }
129 }
130
131 stream << std::endl;
132 stream << "Active Producer Queues:\n";
133 stream << std::right << std::setw(6) << "Id";
134 stream << std::right << std::setw(12) << " Allocated";
135 stream << std::right << std::setw(12) << " Consumers";
136 stream << " UsageSetMask";
137 stream << " UsageClearMask";
138 stream << " UsageDenySetMask";
139 stream << " UsageDenyClearMask";
140 stream << " ";
141 stream << std::endl;
142
143 for (const auto& channel : channels) {
144 if (channel->channel_type() == BufferHubChannel::kProducerQueueType) {
145 BufferHubChannel::BufferInfo info = channel->GetBufferInfo();
146
147 stream << std::dec << std::setfill(' ');
148 stream << std::right << std::setw(6) << info.id;
149 stream << std::right << std::setw(12) << info.capacity;
150 stream << std::right << std::setw(12) << info.consumer_count;
151 stream << std::setw(5) << std::setfill(' ') << "0x";
152 stream << std::hex << std::setfill('0');
153 stream << std::setw(8) << info.usage_set_mask;
154 stream << std::setw(7) << std::setfill(' ') << "0x";
155 stream << std::hex << std::setfill('0');
156 stream << std::setw(8) << info.usage_clear_mask;
157 stream << std::setw(9) << std::setfill(' ') << "0x";
158 stream << std::hex << std::setfill('0');
159 stream << std::setw(8) << info.usage_deny_set_mask;
160 stream << std::setw(11) << std::setfill(' ') << "0x";
161 stream << std::hex << std::setfill('0');
162 stream << std::setw(8) << info.usage_deny_clear_mask;
163 }
164 }
165
166 stream << std::endl;
167 stream << "Active Consumer Queues:\n";
168 stream << std::dec << std::setfill(' ');
169 stream << std::right << std::setw(6) << "Id";
170 stream << std::right << std::setw(12) << " Imported";
171 stream << " ";
172 stream << std::endl;
173
174 for (const auto& channel : channels) {
175 if (channel->channel_type() == BufferHubChannel::kConsumerQueueType) {
176 BufferHubChannel::BufferInfo info = channel->GetBufferInfo();
177
178 stream << std::right << std::setw(6) << info.id;
179 stream << std::right << std::setw(12) << info.capacity;
180 }
181 }
182
183 return stream.str();
184}
185
186void BufferHubService::HandleImpulse(Message& message) {
187 ATRACE_NAME("BufferHubService::HandleImpulse");
188 if (auto channel = message.GetChannel<BufferHubChannel>())
189 channel->HandleImpulse(message);
190}
191
Alex Vakulenkof0a7bd02017-03-31 18:06:19 -0700192pdx::Status<void> BufferHubService::HandleMessage(Message& message) {
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800193 ATRACE_NAME("BufferHubService::HandleMessage");
194 auto channel = message.GetChannel<BufferHubChannel>();
195
196 ALOGD_IF(
197 TRACE,
198 "BufferHubService::HandleMessage: channel=%p channel_id=%d opcode=%d",
199 channel.get(), message.GetChannelId(), message.GetOp());
200
201 // If the channel is already set up, let it handle the message.
202 if (channel && !channel->HandleMessage(message))
203 return DefaultHandleMessage(message);
204
205 // This channel has not been set up yet, the following are valid operations.
206 switch (message.GetOp()) {
207 case BufferHubRPC::CreateBuffer::Opcode:
208 DispatchRemoteMethod<BufferHubRPC::CreateBuffer>(
209 *this, &BufferHubService::OnCreateBuffer, message);
Alex Vakulenkof0a7bd02017-03-31 18:06:19 -0700210 return {};
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800211
212 case BufferHubRPC::CreatePersistentBuffer::Opcode:
213 DispatchRemoteMethod<BufferHubRPC::CreatePersistentBuffer>(
214 *this, &BufferHubService::OnCreatePersistentBuffer, message);
Alex Vakulenkof0a7bd02017-03-31 18:06:19 -0700215 return {};
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800216
217 case BufferHubRPC::GetPersistentBuffer::Opcode:
218 DispatchRemoteMethod<BufferHubRPC::GetPersistentBuffer>(
219 *this, &BufferHubService::OnGetPersistentBuffer, message);
Alex Vakulenkof0a7bd02017-03-31 18:06:19 -0700220 return {};
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800221
222 case BufferHubRPC::CreateProducerQueue::Opcode:
223 DispatchRemoteMethod<BufferHubRPC::CreateProducerQueue>(
224 *this, &BufferHubService::OnCreateProducerQueue, message);
Alex Vakulenkof0a7bd02017-03-31 18:06:19 -0700225 return {};
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800226
227 default:
228 return DefaultHandleMessage(message);
229 }
230}
231
232void BufferHubService::OnChannelClose(Message&,
233 const std::shared_ptr<Channel>& channel) {
234 if (auto buffer = std::static_pointer_cast<BufferHubChannel>(channel))
235 buffer->Detach();
236}
237
238int BufferHubService::OnCreateBuffer(Message& message, int width, int height,
239 int format, int usage,
240 size_t meta_size_bytes,
241 size_t slice_count) {
242 // Use the producer channel id as the global buffer id.
243 const int buffer_id = message.GetChannelId();
244 ALOGD_IF(TRACE,
245 "BufferHubService::OnCreateBuffer: buffer_id=%d width=%d height=%d "
246 "format=%d usage=%d meta_size_bytes=%zu slice_count=%zu",
247 buffer_id, width, height, format, usage, meta_size_bytes,
248 slice_count);
249
250 // See if this channel is already attached to a buffer.
251 if (const auto channel = message.GetChannel<BufferHubChannel>()) {
252 ALOGE("BufferHubService::OnCreateBuffer: Buffer already created: buffer=%d",
253 buffer_id);
254 return -EALREADY;
255 }
256
257 int error;
258 if (const auto producer_channel =
259 ProducerChannel::Create(this, buffer_id, width, height, format, usage,
260 meta_size_bytes, slice_count, &error)) {
261 message.SetChannel(producer_channel);
262 return 0;
263 } else {
264 ALOGE("BufferHubService::OnCreateBuffer: Failed to create producer!!");
265 return error;
266 }
267}
268
269int BufferHubService::OnCreatePersistentBuffer(
270 Message& message, const std::string& name, int user_id, int group_id,
271 int width, int height, int format, int usage, size_t meta_size_bytes,
272 size_t slice_count) {
273 const int channel_id = message.GetChannelId();
274 ALOGD_IF(TRACE,
275 "BufferHubService::OnCreatePersistentBuffer: channel_id=%d name=%s "
276 "user_id=%d group_id=%d width=%d height=%d format=%d usage=%d "
277 "meta_size_bytes=%zu slice_count=%zu",
278 channel_id, name.c_str(), user_id, group_id, width, height, format,
279 usage, meta_size_bytes, slice_count);
280
281 // See if this channel is already attached to a buffer.
282 if (const auto channel = message.GetChannel<BufferHubChannel>()) {
283 ALOGE(
284 "BufferHubService::OnCreatePersistentBuffer: Channel already attached "
285 "to buffer: channel_id=%d buffer_id=%d",
286 channel_id, channel->buffer_id());
287 return -EALREADY;
288 }
289
290 const int euid = message.GetEffectiveUserId();
291 const int egid = message.GetEffectiveGroupId();
292 int error;
293
294 if (auto buffer = GetNamedBuffer(name)) {
295 if (!buffer->CheckAccess(euid, egid)) {
296 ALOGE(
297 "BufferHubService::OnCreatePersistentBuffer: Requesting process does "
298 "not have permission to access named buffer: name=%s euid=%d egid=%d",
299 name.c_str(), euid, euid);
300 return -EPERM;
301 } else if (!buffer->CheckParameters(width, height, format, usage,
302 meta_size_bytes, slice_count)) {
303 ALOGE(
304 "BufferHubService::OnCreatePersistentBuffer: Requested an existing "
305 "buffer with different parameters: name=%s",
306 name.c_str());
307 return -EINVAL;
308 } else if (!buffer->IsDetached()) {
309 ALOGE(
310 "BufferHubService::OnCreatePersistentBuffer: Requesting a persistent "
311 "buffer that is already attached to a channel: name=%s",
312 name.c_str());
313 return -EINVAL;
314 } else {
315 buffer->Attach(channel_id);
316 message.SetChannel(buffer);
317 return 0;
318 }
319 } else if (auto buffer = ProducerChannel::Create(
320 this, channel_id, width, height, format, usage,
321 meta_size_bytes, slice_count, &error)) {
322 const int ret =
323 buffer->OnProducerMakePersistent(message, name, user_id, group_id);
324 if (!ret)
325 message.SetChannel(buffer);
326 return ret;
327 } else {
328 ALOGE("BufferHubService::OnCreateBuffer: Failed to create producer!!");
329 return error;
330 }
331}
332
333int BufferHubService::OnGetPersistentBuffer(Message& message,
334 const std::string& name) {
335 const int channel_id = message.GetChannelId();
336 ALOGD_IF(TRACE,
337 "BufferHubService::OnGetPersistentBuffer: channel_id=%d name=%s",
338 channel_id, name.c_str());
339
340 // See if this channel is already attached to a buffer.
341 if (const auto channel = message.GetChannel<BufferHubChannel>()) {
342 ALOGE(
343 "BufferHubService::OnGetPersistentBuffer: Channel already attached to "
344 "buffer: channel_id=%d buffer_id=%d",
345 channel_id, channel->buffer_id());
346 return -EALREADY;
347 }
348
349 const int euid = message.GetEffectiveUserId();
350 const int egid = message.GetEffectiveGroupId();
351
352 if (auto buffer = GetNamedBuffer(name)) {
353 if (!buffer->CheckAccess(euid, egid)) {
354 ALOGE(
355 "BufferHubService::OnGetPersistentBuffer: Requesting process does "
356 "not have permission to access named buffer: name=%s euid=%d egid=%d",
357 name.c_str(), euid, egid);
358 return -EPERM;
359 } else if (!buffer->IsDetached()) {
360 ALOGE(
361 "BufferHubService::OnGetPersistentBuffer: Requesting a persistent "
362 "buffer that is already attached to a channel: name=%s",
363 name.c_str());
364 return -EINVAL;
365 } else {
366 buffer->Attach(channel_id);
367 message.SetChannel(buffer);
368 return 0;
369 }
370 } else {
371 ALOGE("BufferHubService::OnGetPersistentBuffer: Buffer \"%s\" not found!",
372 name.c_str());
373 return -ENOENT;
374 }
375}
376
Corey Tabaka1db8a5d2017-03-22 02:12:52 -0700377Status<QueueInfo> BufferHubService::OnCreateProducerQueue(
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800378 pdx::Message& message, size_t meta_size_bytes, int usage_set_mask,
379 int usage_clear_mask, int usage_deny_set_mask, int usage_deny_clear_mask) {
380 // Use the producer channel id as the global queue id.
381 const int queue_id = message.GetChannelId();
382 ALOGD_IF(TRACE, "BufferHubService::OnCreateProducerQueue: queue_id=%d",
383 queue_id);
384
385 // See if this channel is already attached to another object.
386 if (const auto channel = message.GetChannel<BufferHubChannel>()) {
387 ALOGE("BufferHubService::OnCreateProducerQueue: already created: queue=%d",
388 queue_id);
Corey Tabaka1db8a5d2017-03-22 02:12:52 -0700389 return ErrorStatus(EALREADY);
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800390 }
391
392 int error;
393 if (const auto producer_channel = ProducerQueueChannel::Create(
394 this, queue_id, meta_size_bytes, usage_set_mask, usage_clear_mask,
395 usage_deny_set_mask, usage_deny_clear_mask, &error)) {
396 message.SetChannel(producer_channel);
Corey Tabaka1db8a5d2017-03-22 02:12:52 -0700397 return {{meta_size_bytes, queue_id}};
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800398 } else {
399 ALOGE("BufferHubService::OnCreateBuffer: Failed to create producer!!");
Corey Tabaka1db8a5d2017-03-22 02:12:52 -0700400 return ErrorStatus(-error);
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800401 }
402}
403
404bool BufferHubService::AddNamedBuffer(
405 const std::string& name, const std::shared_ptr<ProducerChannel>& buffer) {
406 auto search = named_buffers_.find(name);
407 if (search == named_buffers_.end()) {
408 named_buffers_.emplace(name, buffer);
409 return true;
410 } else {
411 return false;
412 }
413}
414
415std::shared_ptr<ProducerChannel> BufferHubService::GetNamedBuffer(
416 const std::string& name) {
417 auto search = named_buffers_.find(name);
418 if (search != named_buffers_.end())
419 return search->second;
420 else
421 return nullptr;
422}
423
424bool BufferHubService::RemoveNamedBuffer(const ProducerChannel& buffer) {
425 for (auto it = named_buffers_.begin(); it != named_buffers_.end();) {
426 if (it->second.get() == &buffer) {
427 named_buffers_.erase(it);
428 return true;
429 }
430 ++it;
431 }
432 return false;
433}
434
435void BufferHubChannel::SignalAvailable() {
436 ATRACE_NAME("BufferHubChannel::SignalAvailable");
Corey Tabaka3079cb72017-01-19 15:07:26 -0800437 ALOGD_IF(TRACE,
438 "BufferHubChannel::SignalAvailable: channel_id=%d buffer_id=%d",
439 channel_id(), buffer_id());
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800440 if (!IsDetached()) {
Alex Vakulenkof0a7bd02017-03-31 18:06:19 -0700441 const auto status = service_->ModifyChannelEvents(channel_id_, 0, POLLIN);
442 ALOGE_IF(!status,
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800443 "BufferHubChannel::SignalAvailable: failed to signal availability "
444 "channel_id=%d: %s",
Alex Vakulenkof0a7bd02017-03-31 18:06:19 -0700445 channel_id_, status.GetErrorMessage().c_str());
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800446 } else {
447 ALOGD_IF(TRACE, "BufferHubChannel::SignalAvailable: detached buffer.");
448 }
449}
450
451void BufferHubChannel::ClearAvailable() {
452 ATRACE_NAME("BufferHubChannel::ClearAvailable");
Corey Tabaka3079cb72017-01-19 15:07:26 -0800453 ALOGD_IF(TRACE,
454 "BufferHubChannel::ClearAvailable: channel_id=%d buffer_id=%d",
455 channel_id(), buffer_id());
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800456 if (!IsDetached()) {
Alex Vakulenkof0a7bd02017-03-31 18:06:19 -0700457 const auto status = service_->ModifyChannelEvents(channel_id_, POLLIN, 0);
458 ALOGE_IF(!status,
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800459 "BufferHubChannel::ClearAvailable: failed to clear availability "
460 "channel_id=%d: %s",
Alex Vakulenkof0a7bd02017-03-31 18:06:19 -0700461 channel_id_, status.GetErrorMessage().c_str());
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800462 } else {
463 ALOGD_IF(TRACE, "BufferHubChannel::ClearAvailable: detached buffer.");
464 }
465}
466
467void BufferHubChannel::Hangup() {
468 ATRACE_NAME("BufferHubChannel::Hangup");
Corey Tabaka3079cb72017-01-19 15:07:26 -0800469 ALOGD_IF(TRACE, "BufferHubChannel::Hangup: channel_id=%d buffer_id=%d",
470 channel_id(), buffer_id());
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800471 if (!IsDetached()) {
Alex Vakulenkof0a7bd02017-03-31 18:06:19 -0700472 const auto status = service_->ModifyChannelEvents(channel_id_, 0, POLLHUP);
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800473 ALOGE_IF(
Alex Vakulenkof0a7bd02017-03-31 18:06:19 -0700474 !status,
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800475 "BufferHubChannel::Hangup: failed to signal hangup channel_id=%d: %s",
Alex Vakulenkof0a7bd02017-03-31 18:06:19 -0700476 channel_id_, status.GetErrorMessage().c_str());
Alex Vakulenkoe4eec202017-01-27 14:41:04 -0800477 } else {
478 ALOGD_IF(TRACE, "BufferHubChannel::Hangup: detached buffer.");
479 }
480}
481
482} // namespace dvr
483} // namespace android