blob: 5829788569ee08e5ab3c5846fc4305b877179335 [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
6#include <private/dvr/platform_defines.h>
Corey Tabaka2251d822017-04-20 16:04:07 -07007#include <private/dvr/trusted_uids.h>
Alex Vakulenkoa8a92782017-01-27 14:41:57 -08008
9#include "display_service.h"
10#include "hardware_composer.h"
11
12#define LOCAL_TRACE 1
13
Corey Tabaka2251d822017-04-20 16:04:07 -070014using android::dvr::display::DisplayProtocol;
Alex Vakulenkoa8a92782017-01-27 14:41:57 -080015using android::pdx::BorrowedChannelHandle;
Corey Tabaka2251d822017-04-20 16:04:07 -070016using android::pdx::ErrorStatus;
Alex Vakulenkoa8a92782017-01-27 14:41:57 -080017using android::pdx::LocalChannelHandle;
Corey Tabaka2251d822017-04-20 16:04:07 -070018using android::pdx::LocalHandle;
Alex Vakulenkoa8a92782017-01-27 14:41:57 -080019using android::pdx::Message;
20using android::pdx::RemoteChannelHandle;
21using android::pdx::Status;
22using android::pdx::rpc::DispatchRemoteMethod;
23using android::pdx::rpc::IfAnyOf;
24
25namespace android {
26namespace dvr {
27
Corey Tabaka2251d822017-04-20 16:04:07 -070028DisplaySurface::DisplaySurface(DisplayService* service,
29 SurfaceType surface_type, int surface_id,
30 int process_id, int user_id,
31 const display::SurfaceAttributes& attributes)
32 : service_(service),
33 surface_type_(surface_type),
34 surface_id_(surface_id),
Alex Vakulenkoa8a92782017-01-27 14:41:57 -080035 process_id_(process_id),
Corey Tabaka2251d822017-04-20 16:04:07 -070036 user_id_(user_id),
37 attributes_(attributes),
38 update_flags_(display::SurfaceUpdateFlags::NewSurface) {}
Alex Vakulenkoa8a92782017-01-27 14:41:57 -080039
40DisplaySurface::~DisplaySurface() {
41 ALOGD_IF(LOCAL_TRACE,
42 "DisplaySurface::~DisplaySurface: surface_id=%d process_id=%d",
Corey Tabaka2251d822017-04-20 16:04:07 -070043 surface_id(), process_id());
Alex Vakulenkoa8a92782017-01-27 14:41:57 -080044}
45
Corey Tabaka2251d822017-04-20 16:04:07 -070046Status<void> DisplaySurface::HandleMessage(pdx::Message& message) {
47 switch (message.GetOp()) {
48 case DisplayProtocol::SetAttributes::Opcode:
49 DispatchRemoteMethod<DisplayProtocol::SetAttributes>(
50 *this, &DisplaySurface::OnSetAttributes, message);
51 break;
52
53 case DisplayProtocol::GetSurfaceInfo::Opcode:
54 DispatchRemoteMethod<DisplayProtocol::GetSurfaceInfo>(
55 *this, &DisplaySurface::OnGetSurfaceInfo, message);
56 break;
57
58 case DisplayProtocol::CreateQueue::Opcode:
59 DispatchRemoteMethod<DisplayProtocol::CreateQueue>(
60 *this, &DisplaySurface::OnCreateQueue, message);
61 break;
62 }
63
64 return {};
65}
66
67Status<void> DisplaySurface::OnSetAttributes(
68 pdx::Message& /*message*/, const display::SurfaceAttributes& attributes) {
69 display::SurfaceUpdateFlags update_flags;
70
71 for (const auto& attribute : attributes) {
72 const auto& key = attribute.first;
73 const auto* variant = &attribute.second;
74 bool invalid_value = false;
75 bool visibility_changed = false;
76
77 // Catch attributes that have significance to the display service.
78 switch (key) {
79 case display::SurfaceAttribute::ZOrder:
80 invalid_value = !IfAnyOf<int32_t, int64_t, float>::Call(
81 variant, [&](const auto& value) {
82 if (z_order_ != value) {
83 visibility_changed = true;
84 z_order_ = value;
85 }
86 });
87 break;
88 case display::SurfaceAttribute::Visible:
89 invalid_value = !IfAnyOf<int32_t, int64_t, bool>::Call(
90 variant, [&](const auto& value) {
91 if (visible_ != value) {
92 visibility_changed = true;
93 visible_ = value;
94 }
95 });
96 break;
97 }
98
99 if (invalid_value) {
100 ALOGW(
101 "DisplaySurface::OnClientSetAttributes: Failed to set display "
102 "surface attribute '%d' because of incompatible type: %d",
103 key, variant->index());
104 } else {
105 // Only update the attribute map with valid values.
106 attributes_[attribute.first] = attribute.second;
107
108 // All attribute changes generate a notification, even if the value
109 // doesn't change. Visibility attributes set a flag only if the value
110 // changes.
111 update_flags.Set(display::SurfaceUpdateFlags::AttributesChanged);
112 if (visibility_changed)
113 update_flags.Set(display::SurfaceUpdateFlags::VisibilityChanged);
114 }
115 }
116
117 SurfaceUpdated(update_flags);
118 return {};
119}
120
121void DisplaySurface::SurfaceUpdated(display::SurfaceUpdateFlags update_flags) {
122 ALOGD_IF(TRACE,
123 "DisplaySurface::SurfaceUpdated: surface_id=%d update_flags=0x%x",
124 surface_id(), update_flags.value());
125
126 update_flags_.Set(update_flags);
127 service()->SurfaceUpdated(surface_type(), update_flags_);
128}
129
130void DisplaySurface::ClearUpdate() {
131 ALOGD_IF(TRACE, "DisplaySurface::ClearUpdate: surface_id=%d", surface_id());
132 update_flags_ = display::SurfaceUpdateFlags::None;
133}
134
135Status<display::SurfaceInfo> DisplaySurface::OnGetSurfaceInfo(
136 Message& /*message*/) {
137 ALOGD_IF(
138 TRACE,
139 "DisplaySurface::OnGetSurfaceInfo: surface_id=%d visible=%d z_order=%d",
140 surface_id(), visible(), z_order());
141 return {{surface_id(), visible(), z_order()}};
142}
143
144Status<void> DisplaySurface::RegisterQueue(
145 const std::shared_ptr<ConsumerQueue>& consumer_queue) {
146 ALOGD_IF(TRACE, "DisplaySurface::RegisterQueue: surface_id=%d queue_id=%d",
147 surface_id(), consumer_queue->id());
148 // Capture references for the lambda to work around apparent clang bug.
149 // TODO(eieio): Figure out if there is a clang bug or C++11 ambiguity when
150 // capturing self and consumer_queue by copy in the following case:
151 // auto self = Self();
152 // [self, consumer_queue](int events) {
153 // self->OnQueueEvent(consuemr_queue, events); }
154 //
155 struct State {
156 std::shared_ptr<DisplaySurface> surface;
157 std::shared_ptr<ConsumerQueue> queue;
158 };
159 State state{Self(), consumer_queue};
160
161 return service()->AddEventHandler(
162 consumer_queue->queue_fd(), EPOLLIN | EPOLLHUP | EPOLLET,
163 [state](int events) {
164 state.surface->OnQueueEvent(state.queue, events);
165 });
166}
167
168Status<void> DisplaySurface::UnregisterQueue(
169 const std::shared_ptr<ConsumerQueue>& consumer_queue) {
170 ALOGD_IF(TRACE, "DisplaySurface::UnregisterQueue: surface_id=%d queue_id=%d",
171 surface_id(), consumer_queue->id());
172 return service()->RemoveEventHandler(consumer_queue->queue_fd());
173}
174
175void DisplaySurface::OnQueueEvent(
176 const std::shared_ptr<ConsumerQueue>& /*consumer_queue*/, int /*events*/) {
177 ALOGE(
178 "DisplaySurface::OnQueueEvent: ERROR base virtual method should not be "
179 "called!!!");
180}
181
182std::shared_ptr<ConsumerQueue> ApplicationDisplaySurface::GetQueue(
183 int32_t queue_id) {
184 ALOGD_IF(TRACE,
185 "ApplicationDisplaySurface::GetQueue: surface_id=%d queue_id=%d",
186 surface_id(), queue_id);
187
188 auto search = consumer_queues_.find(queue_id);
189 if (search != consumer_queues_.end())
190 return search->second;
191 else
192 return nullptr;
193}
194
195std::vector<int32_t> ApplicationDisplaySurface::GetQueueIds() const {
196 std::vector<int32_t> queue_ids;
197 for (const auto& entry : consumer_queues_)
198 queue_ids.push_back(entry.first);
199 return queue_ids;
200}
201
202Status<LocalChannelHandle> ApplicationDisplaySurface::OnCreateQueue(
203 Message& /*message*/, size_t meta_size_bytes) {
204 ATRACE_NAME("ApplicationDisplaySurface::OnCreateQueue");
205 ALOGD_IF(TRACE,
206 "ApplicationDisplaySurface::OnCreateQueue: surface_id=%d, "
207 "meta_size_bytes=%zu",
208 surface_id(), meta_size_bytes);
209
Alex Vakulenkoa8a92782017-01-27 14:41:57 -0800210 std::lock_guard<std::mutex> autolock(lock_);
Corey Tabaka2251d822017-04-20 16:04:07 -0700211 auto producer = ProducerQueue::Create(meta_size_bytes);
212 if (!producer) {
Jiwen 'Steve' Caia3613612017-03-08 17:41:48 -0800213 ALOGE(
Corey Tabaka2251d822017-04-20 16:04:07 -0700214 "ApplicationDisplaySurface::OnCreateQueue: Failed to create producer "
215 "queue!");
216 return ErrorStatus(ENOMEM);
217 }
218
219 std::shared_ptr<ConsumerQueue> consumer =
220 producer->CreateSilentConsumerQueue();
221 auto status = RegisterQueue(consumer);
222 if (!status) {
223 ALOGE(
224 "ApplicationDisplaySurface::OnCreateQueue: Failed to register consumer "
225 "queue: %s",
226 status.GetErrorMessage().c_str());
227 return status.error_status();
228 }
229
230 consumer_queues_[consumer->id()] = std::move(consumer);
231
232 SurfaceUpdated(display::SurfaceUpdateFlags::BuffersChanged);
233 return std::move(producer->GetChannelHandle());
234}
235
236void ApplicationDisplaySurface::OnQueueEvent(
237 const std::shared_ptr<ConsumerQueue>& consumer_queue, int events) {
238 ALOGD_IF(TRACE,
239 "ApplicationDisplaySurface::OnQueueEvent: queue_id=%d events=%x",
240 consumer_queue->id(), events);
241
242 // Always give the queue a chance to handle its internal bookkeeping.
243 consumer_queue->HandleQueueEvents();
244
245 // Check for hangup and remove a queue that is no longer needed.
246 std::lock_guard<std::mutex> autolock(lock_);
247 if (consumer_queue->hung_up()) {
248 ALOGD_IF(TRACE, "ApplicationDisplaySurface::OnQueueEvent: Removing queue.");
249 UnregisterQueue(consumer_queue);
250 auto search = consumer_queues_.find(consumer_queue->id());
251 if (search != consumer_queues_.end()) {
252 consumer_queues_.erase(search);
253 } else {
254 ALOGE(
255 "ApplicationDisplaySurface::OnQueueEvent: Failed to find queue_id=%d",
256 consumer_queue->id());
257 }
258 SurfaceUpdated(display::SurfaceUpdateFlags::BuffersChanged);
259 }
260}
261
262Status<LocalChannelHandle> DirectDisplaySurface::OnCreateQueue(
263 Message& /*message*/, size_t meta_size_bytes) {
264 ATRACE_NAME("DirectDisplaySurface::OnCreateQueue");
265 ALOGD_IF(
266 TRACE,
267 "DirectDisplaySurface::OnCreateQueue: surface_id=%d meta_size_bytes=%zu",
268 surface_id(), meta_size_bytes);
269
270 std::lock_guard<std::mutex> autolock(lock_);
271 if (!direct_queue_) {
272 auto producer = ProducerQueue::Create(meta_size_bytes);
273 if (!producer) {
274 ALOGE(
275 "DirectDisplaySurface::OnCreateQueue: Failed to create producer "
276 "queue!");
277 return ErrorStatus(ENOMEM);
278 }
279
280 direct_queue_ = producer->CreateConsumerQueue();
281 auto status = RegisterQueue(direct_queue_);
282 if (!status) {
283 ALOGE(
284 "DirectDisplaySurface::OnCreateQueue: Failed to register consumer "
285 "queue: %s",
286 status.GetErrorMessage().c_str());
287 return status.error_status();
288 }
289
290 return std::move(producer->GetChannelHandle());
291 } else {
292 return ErrorStatus(EALREADY);
293 }
294}
295
296void DirectDisplaySurface::OnQueueEvent(
297 const std::shared_ptr<ConsumerQueue>& consumer_queue, int events) {
298 ALOGD_IF(TRACE, "DirectDisplaySurface::OnQueueEvent: queue_id=%d events=%x",
299 consumer_queue->id(), events);
300
301 // Always give the queue a chance to handle its internal bookkeeping.
302 consumer_queue->HandleQueueEvents();
303
304 // Check for hangup and remove a queue that is no longer needed.
305 std::lock_guard<std::mutex> autolock(lock_);
306 if (consumer_queue->hung_up()) {
307 ALOGD_IF(TRACE, "DirectDisplaySurface::OnQueueEvent: Removing queue.");
308 UnregisterQueue(consumer_queue);
309 direct_queue_ = nullptr;
310 }
311}
312
313void DirectDisplaySurface::DequeueBuffersLocked() {
314 if (direct_queue_ == nullptr) {
315 ALOGE(
316 "DirectDisplaySurface::DequeueBuffersLocked: Consumer queue is not "
Jiwen 'Steve' Caia3613612017-03-08 17:41:48 -0800317 "initialized.");
318 return;
319 }
320
Jiwen 'Steve' Caia3613612017-03-08 17:41:48 -0800321 while (true) {
322 LocalHandle acquire_fence;
Corey Tabaka2251d822017-04-20 16:04:07 -0700323 size_t slot;
324 auto buffer_status = direct_queue_->Dequeue(0, &slot, &acquire_fence);
325 if (!buffer_status) {
326 ALOGD_IF(
327 TRACE && buffer_status.error() == ETIMEDOUT,
328 "DirectDisplaySurface::DequeueBuffersLocked: All buffers dequeued.");
329 ALOGE_IF(buffer_status.error() != ETIMEDOUT,
330 "DirectDisplaySurface::DequeueBuffersLocked: Failed to dequeue "
331 "buffer: %s",
332 buffer_status.GetErrorMessage().c_str());
Jiwen 'Steve' Caia3613612017-03-08 17:41:48 -0800333 return;
334 }
Corey Tabaka2251d822017-04-20 16:04:07 -0700335 auto buffer_consumer = buffer_status.take();
Jiwen 'Steve' Caia3613612017-03-08 17:41:48 -0800336
Corey Tabaka2251d822017-04-20 16:04:07 -0700337 if (!visible()) {
Jiwen 'Steve' Caia3613612017-03-08 17:41:48 -0800338 ATRACE_NAME("DropFrameOnInvisibleSurface");
339 ALOGD_IF(TRACE,
Corey Tabaka2251d822017-04-20 16:04:07 -0700340 "DirectDisplaySurface::DequeueBuffersLocked: Discarding "
341 "buffer_id=%d on invisible surface.",
Jiwen 'Steve' Caia3613612017-03-08 17:41:48 -0800342 buffer_consumer->id());
343 buffer_consumer->Discard();
344 continue;
345 }
346
347 if (acquired_buffers_.IsFull()) {
348 ALOGE(
Corey Tabaka2251d822017-04-20 16:04:07 -0700349 "DirectDisplaySurface::DequeueBuffersLocked: Posted buffers full, "
Jiwen 'Steve' Caia3613612017-03-08 17:41:48 -0800350 "overwriting.");
351 acquired_buffers_.PopBack();
352 }
353
354 acquired_buffers_.Append(
Corey Tabaka2251d822017-04-20 16:04:07 -0700355 AcquiredBuffer(buffer_consumer, std::move(acquire_fence)));
Jiwen 'Steve' Caia3613612017-03-08 17:41:48 -0800356 }
357}
358
Corey Tabaka2251d822017-04-20 16:04:07 -0700359AcquiredBuffer DirectDisplaySurface::AcquireCurrentBuffer() {
Jiwen 'Steve' Caia3613612017-03-08 17:41:48 -0800360 std::lock_guard<std::mutex> autolock(lock_);
361 DequeueBuffersLocked();
362
363 if (acquired_buffers_.IsEmpty()) {
364 ALOGE(
Corey Tabaka2251d822017-04-20 16:04:07 -0700365 "DirectDisplaySurface::AcquireCurrentBuffer: attempt to acquire buffer "
366 "when none are posted.");
Jiwen 'Steve' Caia3613612017-03-08 17:41:48 -0800367 return AcquiredBuffer();
368 }
369 AcquiredBuffer buffer = std::move(acquired_buffers_.Front());
370 acquired_buffers_.PopFront();
Corey Tabaka2251d822017-04-20 16:04:07 -0700371 ALOGD_IF(TRACE, "DirectDisplaySurface::AcquireCurrentBuffer: buffer: %p",
Jiwen 'Steve' Caia3613612017-03-08 17:41:48 -0800372 buffer.buffer().get());
373 return buffer;
374}
375
Corey Tabaka2251d822017-04-20 16:04:07 -0700376AcquiredBuffer DirectDisplaySurface::AcquireNewestAvailableBuffer(
Alex Vakulenkoa8a92782017-01-27 14:41:57 -0800377 AcquiredBuffer* skipped_buffer) {
378 std::lock_guard<std::mutex> autolock(lock_);
Jiwen 'Steve' Caia3613612017-03-08 17:41:48 -0800379 DequeueBuffersLocked();
380
Alex Vakulenkoa8a92782017-01-27 14:41:57 -0800381 AcquiredBuffer buffer;
382 int frames = 0;
383 // Basic latency stopgap for when the application misses a frame:
384 // If the application recovers on the 2nd or 3rd (etc) frame after
385 // missing, this code will skip frames to catch up by checking if
386 // the next frame is also available.
Jiwen 'Steve' Caia3613612017-03-08 17:41:48 -0800387 while (!acquired_buffers_.IsEmpty() &&
388 acquired_buffers_.Front().IsAvailable()) {
Alex Vakulenkoa8a92782017-01-27 14:41:57 -0800389 // Capture the skipped buffer into the result parameter.
390 // Note that this API only supports skipping one buffer per vsync.
391 if (frames > 0 && skipped_buffer)
392 *skipped_buffer = std::move(buffer);
393 ++frames;
Jiwen 'Steve' Caia3613612017-03-08 17:41:48 -0800394 buffer = std::move(acquired_buffers_.Front());
395 acquired_buffers_.PopFront();
Alex Vakulenkoa8a92782017-01-27 14:41:57 -0800396 if (frames == 2)
397 break;
398 }
Corey Tabaka2251d822017-04-20 16:04:07 -0700399 ALOGD_IF(TRACE,
400 "DirectDisplaySurface::AcquireNewestAvailableBuffer: buffer: %p",
Jiwen 'Steve' Caia3613612017-03-08 17:41:48 -0800401 buffer.buffer().get());
Alex Vakulenkoa8a92782017-01-27 14:41:57 -0800402 return buffer;
403}
404
Corey Tabaka2251d822017-04-20 16:04:07 -0700405bool DirectDisplaySurface::IsBufferAvailable() {
Alex Vakulenkoa8a92782017-01-27 14:41:57 -0800406 std::lock_guard<std::mutex> autolock(lock_);
Jiwen 'Steve' Caia3613612017-03-08 17:41:48 -0800407 DequeueBuffersLocked();
408
409 return !acquired_buffers_.IsEmpty() &&
410 acquired_buffers_.Front().IsAvailable();
Alex Vakulenkoa8a92782017-01-27 14:41:57 -0800411}
412
Corey Tabaka2251d822017-04-20 16:04:07 -0700413bool DirectDisplaySurface::IsBufferPosted() {
Alex Vakulenkoa8a92782017-01-27 14:41:57 -0800414 std::lock_guard<std::mutex> autolock(lock_);
Jiwen 'Steve' Caia3613612017-03-08 17:41:48 -0800415 DequeueBuffersLocked();
Alex Vakulenkoa8a92782017-01-27 14:41:57 -0800416
Jiwen 'Steve' Caia3613612017-03-08 17:41:48 -0800417 return !acquired_buffers_.IsEmpty();
Alex Vakulenkoa8a92782017-01-27 14:41:57 -0800418}
419
Corey Tabaka2251d822017-04-20 16:04:07 -0700420Status<std::shared_ptr<DisplaySurface>> DisplaySurface::Create(
421 DisplayService* service, int surface_id, int process_id, int user_id,
422 const display::SurfaceAttributes& attributes) {
423 bool direct = false;
424 auto search = attributes.find(display::SurfaceAttribute::Direct);
425 if (search != attributes.end()) {
426 if (!IfAnyOf<int32_t, int64_t, bool, float>::Get(&search->second,
427 &direct)) {
428 ALOGE(
429 "DisplaySurface::Create: Invalid type for SurfaceAttribute::Direct!");
430 return ErrorStatus(EINVAL);
Alex Vakulenkoa8a92782017-01-27 14:41:57 -0800431 }
432 }
433
Corey Tabaka2251d822017-04-20 16:04:07 -0700434 ALOGD_IF(TRACE,
435 "DisplaySurface::Create: surface_id=%d process_id=%d user_id=%d "
436 "direct=%d",
437 surface_id, process_id, user_id, direct);
Alex Vakulenkoa8a92782017-01-27 14:41:57 -0800438
Corey Tabaka2251d822017-04-20 16:04:07 -0700439 if (direct) {
440 const bool trusted = user_id == AID_ROOT || IsTrustedUid(user_id);
441 if (trusted) {
442 return {std::shared_ptr<DisplaySurface>{new DirectDisplaySurface(
443 service, surface_id, process_id, user_id, attributes)}};
Alex Vakulenkoa8a92782017-01-27 14:41:57 -0800444 } else {
Corey Tabaka2251d822017-04-20 16:04:07 -0700445 ALOGE(
446 "DisplaySurface::Create: Direct surfaces may only be created by "
447 "trusted UIDs: user_id=%d",
448 user_id);
449 return ErrorStatus(EPERM);
Alex Vakulenkoa8a92782017-01-27 14:41:57 -0800450 }
Corey Tabaka2251d822017-04-20 16:04:07 -0700451 } else {
452 return {std::shared_ptr<DisplaySurface>{new ApplicationDisplaySurface(
453 service, surface_id, process_id, user_id, attributes)}};
Alex Vakulenkoa8a92782017-01-27 14:41:57 -0800454 }
Alex Vakulenkoa8a92782017-01-27 14:41:57 -0800455}
456
457} // namespace dvr
458} // namespace android