#include "display_surface.h" #include #include #include #include "display_service.h" #include "hardware_composer.h" #define LOCAL_TRACE 1 using android::dvr::display::DisplayProtocol; using android::pdx::BorrowedChannelHandle; using android::pdx::ErrorStatus; using android::pdx::LocalChannelHandle; using android::pdx::LocalHandle; using android::pdx::Message; using android::pdx::RemoteChannelHandle; using android::pdx::Status; using android::pdx::rpc::DispatchRemoteMethod; using android::pdx::rpc::IfAnyOf; namespace android { namespace dvr { DisplaySurface::DisplaySurface(DisplayService* service, SurfaceType surface_type, int surface_id, int process_id, int user_id) : service_(service), surface_type_(surface_type), surface_id_(surface_id), process_id_(process_id), user_id_(user_id), update_flags_(display::SurfaceUpdateFlags::NewSurface) {} DisplaySurface::~DisplaySurface() { ALOGD_IF(LOCAL_TRACE, "DisplaySurface::~DisplaySurface: surface_id=%d process_id=%d", surface_id(), process_id()); } Status DisplaySurface::HandleMessage(pdx::Message& message) { switch (message.GetOp()) { case DisplayProtocol::SetAttributes::Opcode: DispatchRemoteMethod( *this, &DisplaySurface::OnSetAttributes, message); break; case DisplayProtocol::GetSurfaceInfo::Opcode: DispatchRemoteMethod( *this, &DisplaySurface::OnGetSurfaceInfo, message); break; case DisplayProtocol::CreateQueue::Opcode: DispatchRemoteMethod( *this, &DisplaySurface::OnCreateQueue, message); break; } return {}; } Status DisplaySurface::OnSetAttributes( pdx::Message& /*message*/, const display::SurfaceAttributes& attributes) { display::SurfaceUpdateFlags update_flags; for (const auto& attribute : attributes) { const auto key = attribute.first; const auto* variant = &attribute.second; bool invalid_value = false; bool visibility_changed = false; // Catch attributes that have significance to the display service. switch (key) { case display::SurfaceAttribute::ZOrder: invalid_value = !IfAnyOf::Call( variant, [&](const auto& value) { if (z_order_ != value) { visibility_changed = true; z_order_ = value; } }); break; case display::SurfaceAttribute::Visible: invalid_value = !IfAnyOf::Call( variant, [&](const auto& value) { if (visible_ != value) { visibility_changed = true; visible_ = value; } }); break; } // Only update the attribute map with valid values. This check also has the // effect of preventing special attributes handled above from being deleted // by an empty value. if (invalid_value) { ALOGW( "DisplaySurface::OnClientSetAttributes: Failed to set display " "surface attribute '%d' because of incompatible type: %d", key, variant->index()); } else { // An empty value indicates the attribute should be deleted. if (variant->empty()) { auto search = attributes_.find(key); if (search != attributes_.end()) attributes_.erase(search); } else { attributes_[key] = *variant; } // All attribute changes generate a notification, even if the value // doesn't change. Visibility attributes set a flag only if the value // changes. update_flags.Set(display::SurfaceUpdateFlags::AttributesChanged); if (visibility_changed) update_flags.Set(display::SurfaceUpdateFlags::VisibilityChanged); } } SurfaceUpdated(update_flags); return {}; } void DisplaySurface::SurfaceUpdated(display::SurfaceUpdateFlags update_flags) { ALOGD_IF(TRACE, "DisplaySurface::SurfaceUpdated: surface_id=%d update_flags=0x%x", surface_id(), update_flags.value()); update_flags_.Set(update_flags); service()->SurfaceUpdated(surface_type(), update_flags_); } void DisplaySurface::ClearUpdate() { ALOGD_IF(TRACE > 1, "DisplaySurface::ClearUpdate: surface_id=%d", surface_id()); update_flags_ = display::SurfaceUpdateFlags::None; } Status DisplaySurface::OnGetSurfaceInfo( Message& /*message*/) { ALOGD_IF( TRACE, "DisplaySurface::OnGetSurfaceInfo: surface_id=%d visible=%d z_order=%d", surface_id(), visible(), z_order()); return {{surface_id(), visible(), z_order()}}; } Status DisplaySurface::RegisterQueue( const std::shared_ptr& consumer_queue) { ALOGD_IF(TRACE, "DisplaySurface::RegisterQueue: surface_id=%d queue_id=%d", surface_id(), consumer_queue->id()); // Capture references for the lambda to work around apparent clang bug. // TODO(eieio): Figure out if there is a clang bug or C++11 ambiguity when // capturing self and consumer_queue by copy in the following case: // auto self = Self(); // [self, consumer_queue](int events) { // self->OnQueueEvent(consuemr_queue, events); } // struct State { std::shared_ptr surface; std::shared_ptr queue; }; State state{Self(), consumer_queue}; return service()->AddEventHandler( consumer_queue->queue_fd(), EPOLLIN | EPOLLHUP | EPOLLET, [state](int events) { state.surface->OnQueueEvent(state.queue, events); }); } Status DisplaySurface::UnregisterQueue( const std::shared_ptr& consumer_queue) { ALOGD_IF(TRACE, "DisplaySurface::UnregisterQueue: surface_id=%d queue_id=%d", surface_id(), consumer_queue->id()); return service()->RemoveEventHandler(consumer_queue->queue_fd()); } void DisplaySurface::OnQueueEvent( const std::shared_ptr& /*consumer_queue*/, int /*events*/) { ALOGE( "DisplaySurface::OnQueueEvent: ERROR base virtual method should not be " "called!!!"); } std::shared_ptr ApplicationDisplaySurface::GetQueue( int32_t queue_id) { ALOGD_IF(TRACE, "ApplicationDisplaySurface::GetQueue: surface_id=%d queue_id=%d", surface_id(), queue_id); std::lock_guard autolock(lock_); auto search = consumer_queues_.find(queue_id); if (search != consumer_queues_.end()) return search->second; else return nullptr; } std::vector ApplicationDisplaySurface::GetQueueIds() const { std::lock_guard autolock(lock_); std::vector queue_ids; for (const auto& entry : consumer_queues_) queue_ids.push_back(entry.first); return queue_ids; } Status ApplicationDisplaySurface::OnCreateQueue( Message& /*message*/, const ProducerQueueConfig& config) { ATRACE_NAME("ApplicationDisplaySurface::OnCreateQueue"); ALOGD_IF(TRACE, "ApplicationDisplaySurface::OnCreateQueue: surface_id=%d, " "user_metadata_size=%zu", surface_id(), config.user_metadata_size); std::lock_guard autolock(lock_); auto producer = ProducerQueue::Create(config, UsagePolicy{}); if (!producer) { ALOGE( "ApplicationDisplaySurface::OnCreateQueue: Failed to create producer " "queue!"); return ErrorStatus(ENOMEM); } std::shared_ptr consumer = producer->CreateSilentConsumerQueue(); auto status = RegisterQueue(consumer); if (!status) { ALOGE( "ApplicationDisplaySurface::OnCreateQueue: Failed to register consumer " "queue: %s", status.GetErrorMessage().c_str()); return status.error_status(); } consumer_queues_[consumer->id()] = std::move(consumer); SurfaceUpdated(display::SurfaceUpdateFlags::BuffersChanged); return std::move(producer->GetChannelHandle()); } void ApplicationDisplaySurface::OnQueueEvent( const std::shared_ptr& consumer_queue, int events) { ALOGD_IF(TRACE, "ApplicationDisplaySurface::OnQueueEvent: queue_id=%d events=%x", consumer_queue->id(), events); std::lock_guard autolock(lock_); // Always give the queue a chance to handle its internal bookkeeping. consumer_queue->HandleQueueEvents(); // Check for hangup and remove a queue that is no longer needed. if (consumer_queue->hung_up()) { ALOGD_IF(TRACE, "ApplicationDisplaySurface::OnQueueEvent: Removing queue."); UnregisterQueue(consumer_queue); auto search = consumer_queues_.find(consumer_queue->id()); if (search != consumer_queues_.end()) { consumer_queues_.erase(search); } else { ALOGE( "ApplicationDisplaySurface::OnQueueEvent: Failed to find queue_id=%d", consumer_queue->id()); } SurfaceUpdated(display::SurfaceUpdateFlags::BuffersChanged); } } std::vector DirectDisplaySurface::GetQueueIds() const { std::lock_guard autolock(lock_); std::vector queue_ids; if (direct_queue_) queue_ids.push_back(direct_queue_->id()); return queue_ids; } Status DirectDisplaySurface::OnCreateQueue( Message& /*message*/, const ProducerQueueConfig& config) { ATRACE_NAME("DirectDisplaySurface::OnCreateQueue"); ALOGD_IF(TRACE, "DirectDisplaySurface::OnCreateQueue: surface_id=%d " "user_metadata_size=%zu", surface_id(), config.user_metadata_size); std::lock_guard autolock(lock_); if (!direct_queue_) { // Inject the hw composer usage flag to enable the display to read the // buffers. auto producer = ProducerQueue::Create( config, UsagePolicy{GraphicBuffer::USAGE_HW_COMPOSER, 0, 0, 0}); if (!producer) { ALOGE( "DirectDisplaySurface::OnCreateQueue: Failed to create producer " "queue!"); return ErrorStatus(ENOMEM); } direct_queue_ = producer->CreateConsumerQueue(); if (direct_queue_->metadata_size() > 0) { metadata_.reset(new uint8_t[direct_queue_->metadata_size()]); } auto status = RegisterQueue(direct_queue_); if (!status) { ALOGE( "DirectDisplaySurface::OnCreateQueue: Failed to register consumer " "queue: %s", status.GetErrorMessage().c_str()); return status.error_status(); } return std::move(producer->GetChannelHandle()); } else { return ErrorStatus(EALREADY); } } void DirectDisplaySurface::OnQueueEvent( const std::shared_ptr& consumer_queue, int events) { ALOGD_IF(TRACE, "DirectDisplaySurface::OnQueueEvent: queue_id=%d events=%x", consumer_queue->id(), events); std::lock_guard autolock(lock_); // Always give the queue a chance to handle its internal bookkeeping. consumer_queue->HandleQueueEvents(); // Check for hangup and remove a queue that is no longer needed. if (consumer_queue->hung_up()) { ALOGD_IF(TRACE, "DirectDisplaySurface::OnQueueEvent: Removing queue."); UnregisterQueue(consumer_queue); direct_queue_ = nullptr; } } void DirectDisplaySurface::DequeueBuffersLocked() { if (direct_queue_ == nullptr) { ALOGE( "DirectDisplaySurface::DequeueBuffersLocked: Consumer queue is not " "initialized."); return; } while (true) { LocalHandle acquire_fence; size_t slot; auto buffer_status = direct_queue_->Dequeue( 0, &slot, metadata_.get(), direct_queue_->metadata_size(), &acquire_fence); ALOGD_IF(TRACE, "DirectDisplaySurface::DequeueBuffersLocked: Dequeue with metadata_size: %zu", direct_queue_->metadata_size()); if (!buffer_status) { ALOGD_IF( TRACE > 1 && buffer_status.error() == ETIMEDOUT, "DirectDisplaySurface::DequeueBuffersLocked: All buffers dequeued."); ALOGE_IF(buffer_status.error() != ETIMEDOUT, "DirectDisplaySurface::DequeueBuffersLocked: Failed to dequeue " "buffer: %s", buffer_status.GetErrorMessage().c_str()); return; } auto buffer_consumer = buffer_status.take(); if (!visible()) { ATRACE_NAME("DropFrameOnInvisibleSurface"); ALOGD_IF(TRACE, "DirectDisplaySurface::DequeueBuffersLocked: Discarding " "buffer_id=%d on invisible surface.", buffer_consumer->id()); buffer_consumer->Discard(); continue; } if (acquired_buffers_.IsFull()) { ALOGE( "DirectDisplaySurface::DequeueBuffersLocked: Posted buffers full, " "overwriting."); acquired_buffers_.PopBack(); } acquired_buffers_.Append( AcquiredBuffer(buffer_consumer, std::move(acquire_fence), slot)); } } AcquiredBuffer DirectDisplaySurface::AcquireCurrentBuffer() { std::lock_guard autolock(lock_); DequeueBuffersLocked(); if (acquired_buffers_.IsEmpty()) { ALOGE( "DirectDisplaySurface::AcquireCurrentBuffer: attempt to acquire buffer " "when none are posted."); return AcquiredBuffer(); } AcquiredBuffer buffer = std::move(acquired_buffers_.Front()); acquired_buffers_.PopFront(); ALOGD_IF(TRACE, "DirectDisplaySurface::AcquireCurrentBuffer: buffer_id=%d", buffer.buffer()->id()); return buffer; } AcquiredBuffer DirectDisplaySurface::AcquireNewestAvailableBuffer( AcquiredBuffer* skipped_buffer) { std::lock_guard autolock(lock_); DequeueBuffersLocked(); AcquiredBuffer buffer; int frames = 0; // Basic latency stopgap for when the application misses a frame: // If the application recovers on the 2nd or 3rd (etc) frame after // missing, this code will skip frames to catch up by checking if // the next frame is also available. while (!acquired_buffers_.IsEmpty() && acquired_buffers_.Front().IsAvailable()) { // Capture the skipped buffer into the result parameter. // Note that this API only supports skipping one buffer per vsync. if (frames > 0 && skipped_buffer) *skipped_buffer = std::move(buffer); ++frames; buffer = std::move(acquired_buffers_.Front()); acquired_buffers_.PopFront(); if (frames == 2) break; } ALOGD_IF(TRACE, "DirectDisplaySurface::AcquireNewestAvailableBuffer: buffer_id=%d", buffer.buffer()->id()); return buffer; } bool DirectDisplaySurface::IsBufferAvailable() { std::lock_guard autolock(lock_); DequeueBuffersLocked(); return !acquired_buffers_.IsEmpty() && acquired_buffers_.Front().IsAvailable(); } bool DirectDisplaySurface::IsBufferPosted() { std::lock_guard autolock(lock_); DequeueBuffersLocked(); return !acquired_buffers_.IsEmpty(); } Status> DisplaySurface::Create( DisplayService* service, int surface_id, int process_id, int user_id, const display::SurfaceAttributes& attributes) { bool direct = false; auto search = attributes.find(display::SurfaceAttribute::Direct); if (search != attributes.end()) { if (!IfAnyOf::Get(&search->second, &direct)) { ALOGE( "DisplaySurface::Create: Invalid type for SurfaceAttribute::Direct!"); return ErrorStatus(EINVAL); } } ALOGD_IF(TRACE, "DisplaySurface::Create: surface_id=%d process_id=%d user_id=%d " "direct=%d", surface_id, process_id, user_id, direct); if (direct) { const bool trusted = user_id == AID_ROOT || IsTrustedUid(user_id); if (trusted) { return {std::shared_ptr{ new DirectDisplaySurface(service, surface_id, process_id, user_id)}}; } else { ALOGE( "DisplaySurface::Create: Direct surfaces may only be created by " "trusted UIDs: user_id=%d", user_id); return ErrorStatus(EPERM); } } else { return {std::shared_ptr{new ApplicationDisplaySurface( service, surface_id, process_id, user_id)}}; } } } // namespace dvr } // namespace android