blob: babdc0e38dfe7cb884b88c124c573c0423c71eba [file] [log] [blame]
Alex Vakulenkoa8a92782017-01-27 14:41:57 -08001#include "display_surface.h"
2
Corey Tabaka2251d822017-04-20 16:04:07 -07003#include <private/android_filesystem_config.h>
Alex Vakulenkoa8a92782017-01-27 14:41:57 -08004#include <utils/Trace.h>
5
Corey Tabaka2251d822017-04-20 16:04:07 -07006#include <private/dvr/trusted_uids.h>
Alex Vakulenkoa8a92782017-01-27 14:41:57 -08007
8#include "display_service.h"
9#include "hardware_composer.h"
10
11#define LOCAL_TRACE 1
12
Corey Tabaka2251d822017-04-20 16:04:07 -070013using android::dvr::display::DisplayProtocol;
Alex Vakulenkoa8a92782017-01-27 14:41:57 -080014using android::pdx::BorrowedChannelHandle;
Corey Tabaka2251d822017-04-20 16:04:07 -070015using android::pdx::ErrorStatus;
Alex Vakulenkoa8a92782017-01-27 14:41:57 -080016using android::pdx::LocalChannelHandle;
Corey Tabaka2251d822017-04-20 16:04:07 -070017using android::pdx::LocalHandle;
Alex Vakulenkoa8a92782017-01-27 14:41:57 -080018using android::pdx::Message;
19using android::pdx::RemoteChannelHandle;
20using android::pdx::Status;
21using android::pdx::rpc::DispatchRemoteMethod;
22using android::pdx::rpc::IfAnyOf;
23
24namespace android {
25namespace dvr {
26
Corey Tabaka2251d822017-04-20 16:04:07 -070027DisplaySurface::DisplaySurface(DisplayService* service,
28 SurfaceType surface_type, int surface_id,
29 int process_id, int user_id,
30 const display::SurfaceAttributes& attributes)
31 : service_(service),
32 surface_type_(surface_type),
33 surface_id_(surface_id),
Alex Vakulenkoa8a92782017-01-27 14:41:57 -080034 process_id_(process_id),
Corey Tabaka2251d822017-04-20 16:04:07 -070035 user_id_(user_id),
36 attributes_(attributes),
37 update_flags_(display::SurfaceUpdateFlags::NewSurface) {}
Alex Vakulenkoa8a92782017-01-27 14:41:57 -080038
39DisplaySurface::~DisplaySurface() {
40 ALOGD_IF(LOCAL_TRACE,
41 "DisplaySurface::~DisplaySurface: surface_id=%d process_id=%d",
Corey Tabaka2251d822017-04-20 16:04:07 -070042 surface_id(), process_id());
Alex Vakulenkoa8a92782017-01-27 14:41:57 -080043}
44
Corey Tabaka2251d822017-04-20 16:04:07 -070045Status<void> DisplaySurface::HandleMessage(pdx::Message& message) {
46 switch (message.GetOp()) {
47 case DisplayProtocol::SetAttributes::Opcode:
48 DispatchRemoteMethod<DisplayProtocol::SetAttributes>(
49 *this, &DisplaySurface::OnSetAttributes, message);
50 break;
51
52 case DisplayProtocol::GetSurfaceInfo::Opcode:
53 DispatchRemoteMethod<DisplayProtocol::GetSurfaceInfo>(
54 *this, &DisplaySurface::OnGetSurfaceInfo, message);
55 break;
56
57 case DisplayProtocol::CreateQueue::Opcode:
58 DispatchRemoteMethod<DisplayProtocol::CreateQueue>(
59 *this, &DisplaySurface::OnCreateQueue, message);
60 break;
61 }
62
63 return {};
64}
65
66Status<void> DisplaySurface::OnSetAttributes(
67 pdx::Message& /*message*/, const display::SurfaceAttributes& attributes) {
68 display::SurfaceUpdateFlags update_flags;
69
70 for (const auto& attribute : attributes) {
71 const auto& key = attribute.first;
72 const auto* variant = &attribute.second;
73 bool invalid_value = false;
74 bool visibility_changed = false;
75
76 // Catch attributes that have significance to the display service.
77 switch (key) {
78 case display::SurfaceAttribute::ZOrder:
79 invalid_value = !IfAnyOf<int32_t, int64_t, float>::Call(
80 variant, [&](const auto& value) {
81 if (z_order_ != value) {
82 visibility_changed = true;
83 z_order_ = value;
84 }
85 });
86 break;
87 case display::SurfaceAttribute::Visible:
88 invalid_value = !IfAnyOf<int32_t, int64_t, bool>::Call(
89 variant, [&](const auto& value) {
90 if (visible_ != value) {
91 visibility_changed = true;
92 visible_ = value;
93 }
94 });
95 break;
96 }
97
98 if (invalid_value) {
99 ALOGW(
100 "DisplaySurface::OnClientSetAttributes: Failed to set display "
101 "surface attribute '%d' because of incompatible type: %d",
102 key, variant->index());
103 } else {
104 // Only update the attribute map with valid values.
105 attributes_[attribute.first] = attribute.second;
106
107 // All attribute changes generate a notification, even if the value
108 // doesn't change. Visibility attributes set a flag only if the value
109 // changes.
110 update_flags.Set(display::SurfaceUpdateFlags::AttributesChanged);
111 if (visibility_changed)
112 update_flags.Set(display::SurfaceUpdateFlags::VisibilityChanged);
113 }
114 }
115
116 SurfaceUpdated(update_flags);
117 return {};
118}
119
120void DisplaySurface::SurfaceUpdated(display::SurfaceUpdateFlags update_flags) {
121 ALOGD_IF(TRACE,
122 "DisplaySurface::SurfaceUpdated: surface_id=%d update_flags=0x%x",
123 surface_id(), update_flags.value());
124
125 update_flags_.Set(update_flags);
126 service()->SurfaceUpdated(surface_type(), update_flags_);
127}
128
129void DisplaySurface::ClearUpdate() {
130 ALOGD_IF(TRACE, "DisplaySurface::ClearUpdate: surface_id=%d", surface_id());
131 update_flags_ = display::SurfaceUpdateFlags::None;
132}
133
134Status<display::SurfaceInfo> DisplaySurface::OnGetSurfaceInfo(
135 Message& /*message*/) {
136 ALOGD_IF(
137 TRACE,
138 "DisplaySurface::OnGetSurfaceInfo: surface_id=%d visible=%d z_order=%d",
139 surface_id(), visible(), z_order());
140 return {{surface_id(), visible(), z_order()}};
141}
142
143Status<void> DisplaySurface::RegisterQueue(
144 const std::shared_ptr<ConsumerQueue>& consumer_queue) {
145 ALOGD_IF(TRACE, "DisplaySurface::RegisterQueue: surface_id=%d queue_id=%d",
146 surface_id(), consumer_queue->id());
147 // Capture references for the lambda to work around apparent clang bug.
148 // TODO(eieio): Figure out if there is a clang bug or C++11 ambiguity when
149 // capturing self and consumer_queue by copy in the following case:
150 // auto self = Self();
151 // [self, consumer_queue](int events) {
152 // self->OnQueueEvent(consuemr_queue, events); }
153 //
154 struct State {
155 std::shared_ptr<DisplaySurface> surface;
156 std::shared_ptr<ConsumerQueue> queue;
157 };
158 State state{Self(), consumer_queue};
159
160 return service()->AddEventHandler(
161 consumer_queue->queue_fd(), EPOLLIN | EPOLLHUP | EPOLLET,
162 [state](int events) {
163 state.surface->OnQueueEvent(state.queue, events);
164 });
165}
166
167Status<void> DisplaySurface::UnregisterQueue(
168 const std::shared_ptr<ConsumerQueue>& consumer_queue) {
169 ALOGD_IF(TRACE, "DisplaySurface::UnregisterQueue: surface_id=%d queue_id=%d",
170 surface_id(), consumer_queue->id());
171 return service()->RemoveEventHandler(consumer_queue->queue_fd());
172}
173
174void DisplaySurface::OnQueueEvent(
175 const std::shared_ptr<ConsumerQueue>& /*consumer_queue*/, int /*events*/) {
176 ALOGE(
177 "DisplaySurface::OnQueueEvent: ERROR base virtual method should not be "
178 "called!!!");
179}
180
181std::shared_ptr<ConsumerQueue> ApplicationDisplaySurface::GetQueue(
182 int32_t queue_id) {
183 ALOGD_IF(TRACE,
184 "ApplicationDisplaySurface::GetQueue: surface_id=%d queue_id=%d",
185 surface_id(), queue_id);
186
187 auto search = consumer_queues_.find(queue_id);
188 if (search != consumer_queues_.end())
189 return search->second;
190 else
191 return nullptr;
192}
193
194std::vector<int32_t> ApplicationDisplaySurface::GetQueueIds() const {
195 std::vector<int32_t> queue_ids;
196 for (const auto& entry : consumer_queues_)
197 queue_ids.push_back(entry.first);
198 return queue_ids;
199}
200
201Status<LocalChannelHandle> ApplicationDisplaySurface::OnCreateQueue(
202 Message& /*message*/, size_t meta_size_bytes) {
203 ATRACE_NAME("ApplicationDisplaySurface::OnCreateQueue");
204 ALOGD_IF(TRACE,
205 "ApplicationDisplaySurface::OnCreateQueue: surface_id=%d, "
206 "meta_size_bytes=%zu",
207 surface_id(), meta_size_bytes);
208
Alex Vakulenkoa8a92782017-01-27 14:41:57 -0800209 std::lock_guard<std::mutex> autolock(lock_);
Jiwen 'Steve' Cai6bffc672017-05-18 23:05:05 -0700210 auto config =
211 ProducerQueueConfigBuilder().SetMetadataSize(meta_size_bytes).Build();
212 auto producer = ProducerQueue::Create(config, UsagePolicy{});
Corey Tabaka2251d822017-04-20 16:04:07 -0700213 if (!producer) {
Jiwen 'Steve' Caia3613612017-03-08 17:41:48 -0800214 ALOGE(
Corey Tabaka2251d822017-04-20 16:04:07 -0700215 "ApplicationDisplaySurface::OnCreateQueue: Failed to create producer "
216 "queue!");
217 return ErrorStatus(ENOMEM);
218 }
219
220 std::shared_ptr<ConsumerQueue> consumer =
221 producer->CreateSilentConsumerQueue();
222 auto status = RegisterQueue(consumer);
223 if (!status) {
224 ALOGE(
225 "ApplicationDisplaySurface::OnCreateQueue: Failed to register consumer "
226 "queue: %s",
227 status.GetErrorMessage().c_str());
228 return status.error_status();
229 }
230
231 consumer_queues_[consumer->id()] = std::move(consumer);
232
233 SurfaceUpdated(display::SurfaceUpdateFlags::BuffersChanged);
234 return std::move(producer->GetChannelHandle());
235}
236
237void ApplicationDisplaySurface::OnQueueEvent(
238 const std::shared_ptr<ConsumerQueue>& consumer_queue, int events) {
239 ALOGD_IF(TRACE,
240 "ApplicationDisplaySurface::OnQueueEvent: queue_id=%d events=%x",
241 consumer_queue->id(), events);
242
243 // Always give the queue a chance to handle its internal bookkeeping.
244 consumer_queue->HandleQueueEvents();
245
246 // Check for hangup and remove a queue that is no longer needed.
247 std::lock_guard<std::mutex> autolock(lock_);
248 if (consumer_queue->hung_up()) {
249 ALOGD_IF(TRACE, "ApplicationDisplaySurface::OnQueueEvent: Removing queue.");
250 UnregisterQueue(consumer_queue);
251 auto search = consumer_queues_.find(consumer_queue->id());
252 if (search != consumer_queues_.end()) {
253 consumer_queues_.erase(search);
254 } else {
255 ALOGE(
256 "ApplicationDisplaySurface::OnQueueEvent: Failed to find queue_id=%d",
257 consumer_queue->id());
258 }
259 SurfaceUpdated(display::SurfaceUpdateFlags::BuffersChanged);
260 }
261}
262
263Status<LocalChannelHandle> DirectDisplaySurface::OnCreateQueue(
264 Message& /*message*/, size_t meta_size_bytes) {
265 ATRACE_NAME("DirectDisplaySurface::OnCreateQueue");
266 ALOGD_IF(
267 TRACE,
268 "DirectDisplaySurface::OnCreateQueue: surface_id=%d meta_size_bytes=%zu",
269 surface_id(), meta_size_bytes);
270
271 std::lock_guard<std::mutex> autolock(lock_);
272 if (!direct_queue_) {
Corey Tabakaa936f7a2017-05-18 17:28:07 -0700273 // Inject the hw composer usage flag to enable the display to read the
274 // buffers.
Jiwen 'Steve' Cai6bffc672017-05-18 23:05:05 -0700275 auto config =
276 ProducerQueueConfigBuilder().SetMetadataSize(meta_size_bytes).Build();
Corey Tabakaa936f7a2017-05-18 17:28:07 -0700277 auto producer = ProducerQueue::Create(
Jiwen 'Steve' Cai6bffc672017-05-18 23:05:05 -0700278 config, UsagePolicy{GraphicBuffer::USAGE_HW_COMPOSER, 0, 0, 0});
Corey Tabaka2251d822017-04-20 16:04:07 -0700279 if (!producer) {
280 ALOGE(
281 "DirectDisplaySurface::OnCreateQueue: Failed to create producer "
282 "queue!");
283 return ErrorStatus(ENOMEM);
284 }
285
286 direct_queue_ = producer->CreateConsumerQueue();
287 auto status = RegisterQueue(direct_queue_);
288 if (!status) {
289 ALOGE(
290 "DirectDisplaySurface::OnCreateQueue: Failed to register consumer "
291 "queue: %s",
292 status.GetErrorMessage().c_str());
293 return status.error_status();
294 }
295
296 return std::move(producer->GetChannelHandle());
297 } else {
298 return ErrorStatus(EALREADY);
299 }
300}
301
302void DirectDisplaySurface::OnQueueEvent(
303 const std::shared_ptr<ConsumerQueue>& consumer_queue, int events) {
304 ALOGD_IF(TRACE, "DirectDisplaySurface::OnQueueEvent: queue_id=%d events=%x",
305 consumer_queue->id(), events);
306
307 // Always give the queue a chance to handle its internal bookkeeping.
308 consumer_queue->HandleQueueEvents();
309
310 // Check for hangup and remove a queue that is no longer needed.
311 std::lock_guard<std::mutex> autolock(lock_);
312 if (consumer_queue->hung_up()) {
313 ALOGD_IF(TRACE, "DirectDisplaySurface::OnQueueEvent: Removing queue.");
314 UnregisterQueue(consumer_queue);
315 direct_queue_ = nullptr;
316 }
317}
318
319void DirectDisplaySurface::DequeueBuffersLocked() {
320 if (direct_queue_ == nullptr) {
321 ALOGE(
322 "DirectDisplaySurface::DequeueBuffersLocked: Consumer queue is not "
Jiwen 'Steve' Caia3613612017-03-08 17:41:48 -0800323 "initialized.");
324 return;
325 }
326
Jiwen 'Steve' Caia3613612017-03-08 17:41:48 -0800327 while (true) {
328 LocalHandle acquire_fence;
Corey Tabaka2251d822017-04-20 16:04:07 -0700329 size_t slot;
330 auto buffer_status = direct_queue_->Dequeue(0, &slot, &acquire_fence);
331 if (!buffer_status) {
332 ALOGD_IF(
333 TRACE && buffer_status.error() == ETIMEDOUT,
334 "DirectDisplaySurface::DequeueBuffersLocked: All buffers dequeued.");
335 ALOGE_IF(buffer_status.error() != ETIMEDOUT,
336 "DirectDisplaySurface::DequeueBuffersLocked: Failed to dequeue "
337 "buffer: %s",
338 buffer_status.GetErrorMessage().c_str());
Jiwen 'Steve' Caia3613612017-03-08 17:41:48 -0800339 return;
340 }
Corey Tabaka2251d822017-04-20 16:04:07 -0700341 auto buffer_consumer = buffer_status.take();
Jiwen 'Steve' Caia3613612017-03-08 17:41:48 -0800342
Corey Tabaka2251d822017-04-20 16:04:07 -0700343 if (!visible()) {
Jiwen 'Steve' Caia3613612017-03-08 17:41:48 -0800344 ATRACE_NAME("DropFrameOnInvisibleSurface");
345 ALOGD_IF(TRACE,
Corey Tabaka2251d822017-04-20 16:04:07 -0700346 "DirectDisplaySurface::DequeueBuffersLocked: Discarding "
347 "buffer_id=%d on invisible surface.",
Jiwen 'Steve' Caia3613612017-03-08 17:41:48 -0800348 buffer_consumer->id());
349 buffer_consumer->Discard();
350 continue;
351 }
352
353 if (acquired_buffers_.IsFull()) {
354 ALOGE(
Corey Tabaka2251d822017-04-20 16:04:07 -0700355 "DirectDisplaySurface::DequeueBuffersLocked: Posted buffers full, "
Jiwen 'Steve' Caia3613612017-03-08 17:41:48 -0800356 "overwriting.");
357 acquired_buffers_.PopBack();
358 }
359
360 acquired_buffers_.Append(
Corey Tabaka2251d822017-04-20 16:04:07 -0700361 AcquiredBuffer(buffer_consumer, std::move(acquire_fence)));
Jiwen 'Steve' Caia3613612017-03-08 17:41:48 -0800362 }
363}
364
Corey Tabaka2251d822017-04-20 16:04:07 -0700365AcquiredBuffer DirectDisplaySurface::AcquireCurrentBuffer() {
Jiwen 'Steve' Caia3613612017-03-08 17:41:48 -0800366 std::lock_guard<std::mutex> autolock(lock_);
367 DequeueBuffersLocked();
368
369 if (acquired_buffers_.IsEmpty()) {
370 ALOGE(
Corey Tabaka2251d822017-04-20 16:04:07 -0700371 "DirectDisplaySurface::AcquireCurrentBuffer: attempt to acquire buffer "
372 "when none are posted.");
Jiwen 'Steve' Caia3613612017-03-08 17:41:48 -0800373 return AcquiredBuffer();
374 }
375 AcquiredBuffer buffer = std::move(acquired_buffers_.Front());
376 acquired_buffers_.PopFront();
Corey Tabaka2251d822017-04-20 16:04:07 -0700377 ALOGD_IF(TRACE, "DirectDisplaySurface::AcquireCurrentBuffer: buffer: %p",
Jiwen 'Steve' Caia3613612017-03-08 17:41:48 -0800378 buffer.buffer().get());
379 return buffer;
380}
381
Corey Tabaka2251d822017-04-20 16:04:07 -0700382AcquiredBuffer DirectDisplaySurface::AcquireNewestAvailableBuffer(
Alex Vakulenkoa8a92782017-01-27 14:41:57 -0800383 AcquiredBuffer* skipped_buffer) {
384 std::lock_guard<std::mutex> autolock(lock_);
Jiwen 'Steve' Caia3613612017-03-08 17:41:48 -0800385 DequeueBuffersLocked();
386
Alex Vakulenkoa8a92782017-01-27 14:41:57 -0800387 AcquiredBuffer buffer;
388 int frames = 0;
389 // Basic latency stopgap for when the application misses a frame:
390 // If the application recovers on the 2nd or 3rd (etc) frame after
391 // missing, this code will skip frames to catch up by checking if
392 // the next frame is also available.
Jiwen 'Steve' Caia3613612017-03-08 17:41:48 -0800393 while (!acquired_buffers_.IsEmpty() &&
394 acquired_buffers_.Front().IsAvailable()) {
Alex Vakulenkoa8a92782017-01-27 14:41:57 -0800395 // Capture the skipped buffer into the result parameter.
396 // Note that this API only supports skipping one buffer per vsync.
397 if (frames > 0 && skipped_buffer)
398 *skipped_buffer = std::move(buffer);
399 ++frames;
Jiwen 'Steve' Caia3613612017-03-08 17:41:48 -0800400 buffer = std::move(acquired_buffers_.Front());
401 acquired_buffers_.PopFront();
Alex Vakulenkoa8a92782017-01-27 14:41:57 -0800402 if (frames == 2)
403 break;
404 }
Corey Tabaka2251d822017-04-20 16:04:07 -0700405 ALOGD_IF(TRACE,
406 "DirectDisplaySurface::AcquireNewestAvailableBuffer: buffer: %p",
Jiwen 'Steve' Caia3613612017-03-08 17:41:48 -0800407 buffer.buffer().get());
Alex Vakulenkoa8a92782017-01-27 14:41:57 -0800408 return buffer;
409}
410
Corey Tabaka2251d822017-04-20 16:04:07 -0700411bool DirectDisplaySurface::IsBufferAvailable() {
Alex Vakulenkoa8a92782017-01-27 14:41:57 -0800412 std::lock_guard<std::mutex> autolock(lock_);
Jiwen 'Steve' Caia3613612017-03-08 17:41:48 -0800413 DequeueBuffersLocked();
414
415 return !acquired_buffers_.IsEmpty() &&
416 acquired_buffers_.Front().IsAvailable();
Alex Vakulenkoa8a92782017-01-27 14:41:57 -0800417}
418
Corey Tabaka2251d822017-04-20 16:04:07 -0700419bool DirectDisplaySurface::IsBufferPosted() {
Alex Vakulenkoa8a92782017-01-27 14:41:57 -0800420 std::lock_guard<std::mutex> autolock(lock_);
Jiwen 'Steve' Caia3613612017-03-08 17:41:48 -0800421 DequeueBuffersLocked();
Alex Vakulenkoa8a92782017-01-27 14:41:57 -0800422
Jiwen 'Steve' Caia3613612017-03-08 17:41:48 -0800423 return !acquired_buffers_.IsEmpty();
Alex Vakulenkoa8a92782017-01-27 14:41:57 -0800424}
425
Corey Tabaka2251d822017-04-20 16:04:07 -0700426Status<std::shared_ptr<DisplaySurface>> DisplaySurface::Create(
427 DisplayService* service, int surface_id, int process_id, int user_id,
428 const display::SurfaceAttributes& attributes) {
429 bool direct = false;
430 auto search = attributes.find(display::SurfaceAttribute::Direct);
431 if (search != attributes.end()) {
432 if (!IfAnyOf<int32_t, int64_t, bool, float>::Get(&search->second,
433 &direct)) {
434 ALOGE(
435 "DisplaySurface::Create: Invalid type for SurfaceAttribute::Direct!");
436 return ErrorStatus(EINVAL);
Alex Vakulenkoa8a92782017-01-27 14:41:57 -0800437 }
438 }
439
Corey Tabaka2251d822017-04-20 16:04:07 -0700440 ALOGD_IF(TRACE,
441 "DisplaySurface::Create: surface_id=%d process_id=%d user_id=%d "
442 "direct=%d",
443 surface_id, process_id, user_id, direct);
Alex Vakulenkoa8a92782017-01-27 14:41:57 -0800444
Corey Tabaka2251d822017-04-20 16:04:07 -0700445 if (direct) {
446 const bool trusted = user_id == AID_ROOT || IsTrustedUid(user_id);
447 if (trusted) {
448 return {std::shared_ptr<DisplaySurface>{new DirectDisplaySurface(
449 service, surface_id, process_id, user_id, attributes)}};
Alex Vakulenkoa8a92782017-01-27 14:41:57 -0800450 } else {
Corey Tabaka2251d822017-04-20 16:04:07 -0700451 ALOGE(
452 "DisplaySurface::Create: Direct surfaces may only be created by "
453 "trusted UIDs: user_id=%d",
454 user_id);
455 return ErrorStatus(EPERM);
Alex Vakulenkoa8a92782017-01-27 14:41:57 -0800456 }
Corey Tabaka2251d822017-04-20 16:04:07 -0700457 } else {
458 return {std::shared_ptr<DisplaySurface>{new ApplicationDisplaySurface(
459 service, surface_id, process_id, user_id, attributes)}};
Alex Vakulenkoa8a92782017-01-27 14:41:57 -0800460 }
Alex Vakulenkoa8a92782017-01-27 14:41:57 -0800461}
462
463} // namespace dvr
464} // namespace android