blob: 6730ba8cd09476388ada28bd970beb1681c588f8 [file] [log] [blame]
#include "display_manager_service.h"
#include <pdx/channel_handle.h>
#include <pdx/default_transport/service_endpoint.h>
#include <private/dvr/display_rpc.h>
#include <sys/poll.h>
#include <array>
using android::pdx::Channel;
using android::pdx::LocalChannelHandle;
using android::pdx::Message;
using android::pdx::default_transport::Endpoint;
using android::pdx::rpc::DispatchRemoteMethod;
using android::pdx::rpc::IfAnyOf;
namespace {
// As a first line of defense, the display manager endpoint is only accessible
// to the user and group.
// TODO(dnicoara): Remove read/write permission for others. This is in here just
// to allow us to experiment with cast functionality from a plain old app.
constexpr mode_t kDisplayManagerEndpointFileMode =
S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH;
constexpr size_t kMaxSurfacesPerRequest = 32;
} // anonymous namespace
namespace android {
namespace dvr {
void DisplayManager::SetNotificationsPending(bool pending) {
int ret = service_->ModifyChannelEvents(channel_id_, pending ? 0 : POLLIN,
pending ? POLLIN : 0);
ALOGE_IF(ret < 0,
"DisplayManager::SetNotificationPending: Failed to modify channel "
"events: %s",
strerror(-ret));
}
DisplayManagerService::DisplayManagerService(
const std::shared_ptr<DisplayService>& display_service)
: BASE("DisplayManagerService",
Endpoint::Create(DisplayManagerRPC::kClientPath,
kDisplayManagerEndpointFileMode)),
display_service_(display_service) {
display_service_->SetDisplayConfigurationUpdateNotifier(
std::bind(&DisplayManagerService::OnDisplaySurfaceChange, this));
}
std::shared_ptr<pdx::Channel> DisplayManagerService::OnChannelOpen(
pdx::Message& message) {
// Prevent more than one display manager from registering at a time.
if (display_manager_)
REPLY_ERROR_RETURN(message, EPERM, nullptr);
display_manager_ =
std::make_shared<DisplayManager>(this, message.GetChannelId());
return display_manager_;
}
void DisplayManagerService::OnChannelClose(
pdx::Message& /*message*/, const std::shared_ptr<pdx::Channel>& channel) {
// Unregister the display manager when the channel closes.
if (display_manager_ == channel)
display_manager_ = nullptr;
}
int DisplayManagerService::HandleMessage(pdx::Message& message) {
auto channel = std::static_pointer_cast<DisplayManager>(message.GetChannel());
switch (message.GetOp()) {
case DisplayManagerRPC::GetSurfaceList::Opcode:
DispatchRemoteMethod<DisplayManagerRPC::GetSurfaceList>(
*this, &DisplayManagerService::OnGetSurfaceList, message);
return 0;
case DisplayManagerRPC::GetSurfaceBuffers::Opcode:
DispatchRemoteMethod<DisplayManagerRPC::GetSurfaceBuffers>(
*this, &DisplayManagerService::OnGetSurfaceBuffers, message);
return 0;
case DisplayManagerRPC::UpdateSurfaces::Opcode:
DispatchRemoteMethod<DisplayManagerRPC::UpdateSurfaces>(
*this, &DisplayManagerService::OnUpdateSurfaces, message);
return 0;
default:
return Service::DefaultHandleMessage(message);
}
}
std::vector<DisplaySurfaceInfo> DisplayManagerService::OnGetSurfaceList(
pdx::Message& /*message*/) {
std::vector<DisplaySurfaceInfo> items;
display_service_->ForEachDisplaySurface([&items](
const std::shared_ptr<DisplaySurface>& surface) mutable {
DisplaySurfaceInfo item;
item.surface_id = surface->surface_id();
item.process_id = surface->process_id();
item.type = surface->type();
item.flags = 0; // TODO(eieio)
item.client_attributes = DisplaySurfaceAttributes{
{DisplaySurfaceAttributeEnum::Visible,
DisplaySurfaceAttributeValue{surface->client_visible()}},
{DisplaySurfaceAttributeEnum::ZOrder,
DisplaySurfaceAttributeValue{surface->client_z_order()}},
{DisplaySurfaceAttributeEnum::Blur, DisplaySurfaceAttributeValue{0.f}}};
item.manager_attributes = DisplaySurfaceAttributes{
{DisplaySurfaceAttributeEnum::Visible,
DisplaySurfaceAttributeValue{surface->manager_visible()}},
{DisplaySurfaceAttributeEnum::ZOrder,
DisplaySurfaceAttributeValue{surface->manager_z_order()}},
{DisplaySurfaceAttributeEnum::Blur,
DisplaySurfaceAttributeValue{surface->manager_blur()}}};
items.push_back(item);
});
// The fact that we're in the message handler implies that display_manager_ is
// not nullptr. No check required, unless this service becomes multi-threaded.
display_manager_->SetNotificationsPending(false);
return items;
}
std::vector<LocalChannelHandle> DisplayManagerService::OnGetSurfaceBuffers(
pdx::Message& message, int surface_id) {
std::shared_ptr<DisplaySurface> surface =
display_service_->GetDisplaySurface(surface_id);
if (!surface)
REPLY_ERROR_RETURN(message, ENOENT, {});
std::vector<LocalChannelHandle> consumers;
int ret = surface->GetConsumers(&consumers);
if (ret < 0) {
ALOGE(
"DisplayManagerService::OnGetDisplaySurfaceBuffers: Failed to get "
"consumers for surface %d: %s",
surface_id, strerror(-ret));
REPLY_ERROR_RETURN(message, -ret, {});
}
return consumers;
}
int DisplayManagerService::OnUpdateSurfaces(
pdx::Message& /*message*/,
const std::map<int, DisplaySurfaceAttributes>& updates) {
for (const auto& surface_update : updates) {
const int surface_id = surface_update.first;
const DisplaySurfaceAttributes& attributes = surface_update.second;
std::shared_ptr<DisplaySurface> surface =
display_service_->GetDisplaySurface(surface_id);
if (!surface)
return -ENOENT;
for (const auto& attribute : attributes) {
const auto& key = attribute.first;
const auto* variant = &attribute.second;
bool invalid_value = false;
switch (key) {
case DisplaySurfaceAttributeEnum::ZOrder:
invalid_value =
!IfAnyOf<int32_t>::Call(variant, [&surface](const auto& value) {
surface->ManagerSetZOrder(value);
});
break;
case DisplaySurfaceAttributeEnum::Visible:
invalid_value = !IfAnyOf<int32_t, int64_t, bool>::Call(
variant, [&surface](const auto& value) {
surface->ManagerSetVisible(value);
});
break;
case DisplaySurfaceAttributeEnum::Blur:
invalid_value = !IfAnyOf<int32_t, int64_t, float>::Call(
variant, [&surface](const auto& value) {
surface->ManagerSetBlur(value);
});
break;
default:
ALOGW(
"DisplayManagerService::OnUpdateSurfaces: Attempt to set invalid "
"attribute %u on surface %d",
key, surface_id);
break;
}
if (invalid_value) {
ALOGW(
"DisplayManagerService::OnUpdateSurfaces: Failed to set display "
"surface attribute '%s' because of incompatible type: %d",
DisplaySurfaceAttributeEnum::ToString(key).c_str(),
variant->index());
}
}
}
// Reconfigure the display layers for any active surface changes.
display_service_->UpdateActiveDisplaySurfaces();
return 0;
}
void DisplayManagerService::OnDisplaySurfaceChange() {
if (display_manager_) {
display_manager_->SetNotificationsPending(true);
} else {
// If there isn't a display manager registered, default all display surfaces
// to visible.
display_service_->ForEachDisplaySurface(
[](const std::shared_ptr<DisplaySurface>& surface) {
surface->ManagerSetVisible(true);
});
display_service_->UpdateActiveDisplaySurfaces();
}
}
} // namespace dvr
} // namespace android