You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
438 lines
15 KiB
438 lines
15 KiB
4 months ago
|
#include "display_service.h"
|
||
|
|
||
|
#include <unistd.h>
|
||
|
|
||
|
#include <algorithm>
|
||
|
#include <sstream>
|
||
|
#include <string>
|
||
|
#include <vector>
|
||
|
|
||
|
#include <android-base/file.h>
|
||
|
#include <android-base/properties.h>
|
||
|
#include <dvr/dvr_display_types.h>
|
||
|
#include <pdx/default_transport/service_endpoint.h>
|
||
|
#include <pdx/rpc/remote_method.h>
|
||
|
#include <private/android_filesystem_config.h>
|
||
|
#include <private/dvr/display_protocol.h>
|
||
|
#include <private/dvr/numeric.h>
|
||
|
#include <private/dvr/trusted_uids.h>
|
||
|
#include <private/dvr/types.h>
|
||
|
|
||
|
#include "DisplayHardware/DisplayIdentification.h"
|
||
|
|
||
|
using android::dvr::display::DisplayProtocol;
|
||
|
using android::pdx::Channel;
|
||
|
using android::pdx::ErrorStatus;
|
||
|
using android::pdx::Message;
|
||
|
using android::pdx::Status;
|
||
|
using android::pdx::default_transport::Endpoint;
|
||
|
using android::pdx::rpc::DispatchRemoteMethod;
|
||
|
|
||
|
namespace {
|
||
|
|
||
|
const char kDvrLensMetricsProperty[] = "ro.dvr.lens_metrics";
|
||
|
const char kDvrDeviceMetricsProperty[] = "ro.dvr.device_metrics";
|
||
|
const char kDvrDeviceConfigProperty[] = "ro.dvr.device_configuration";
|
||
|
|
||
|
} // namespace
|
||
|
|
||
|
namespace android {
|
||
|
namespace dvr {
|
||
|
|
||
|
DisplayService::DisplayService(Hwc2::Composer* hidl,
|
||
|
hwc2_display_t primary_display_id,
|
||
|
RequestDisplayCallback request_display_callback)
|
||
|
: BASE("DisplayService",
|
||
|
Endpoint::Create(display::DisplayProtocol::kClientPath)) {
|
||
|
hardware_composer_.Initialize(
|
||
|
hidl, primary_display_id, request_display_callback);
|
||
|
}
|
||
|
|
||
|
bool DisplayService::IsInitialized() const {
|
||
|
return BASE::IsInitialized() && hardware_composer_.IsInitialized();
|
||
|
}
|
||
|
|
||
|
std::string DisplayService::DumpState(size_t /*max_length*/) {
|
||
|
std::ostringstream stream;
|
||
|
|
||
|
auto surfaces = GetDisplaySurfaces();
|
||
|
std::sort(surfaces.begin(), surfaces.end(), [](const auto& a, const auto& b) {
|
||
|
return a->surface_id() < b->surface_id();
|
||
|
});
|
||
|
|
||
|
stream << "Application Surfaces:" << std::endl;
|
||
|
|
||
|
size_t count = 0;
|
||
|
for (const auto& surface : surfaces) {
|
||
|
if (surface->surface_type() == SurfaceType::Application) {
|
||
|
stream << "Surface " << count++ << ":";
|
||
|
stream << " surface_id=" << surface->surface_id()
|
||
|
<< " process_id=" << surface->process_id()
|
||
|
<< " user_id=" << surface->user_id()
|
||
|
<< " visible=" << surface->visible()
|
||
|
<< " z_order=" << surface->z_order();
|
||
|
|
||
|
stream << " queue_ids=";
|
||
|
auto queue_ids = surface->GetQueueIds();
|
||
|
std::sort(queue_ids.begin(), queue_ids.end());
|
||
|
for (int32_t id : queue_ids) {
|
||
|
if (id != queue_ids[0])
|
||
|
stream << ",";
|
||
|
stream << id;
|
||
|
}
|
||
|
stream << std::endl;
|
||
|
}
|
||
|
}
|
||
|
stream << std::endl;
|
||
|
|
||
|
stream << "Direct Surfaces:" << std::endl;
|
||
|
|
||
|
count = 0;
|
||
|
for (const auto& surface : surfaces) {
|
||
|
if (surface->surface_type() == SurfaceType::Direct) {
|
||
|
stream << "Surface " << count++ << ":";
|
||
|
stream << " surface_id=" << surface->surface_id()
|
||
|
<< " process_id=" << surface->process_id()
|
||
|
<< " user_id=" << surface->user_id()
|
||
|
<< " visible=" << surface->visible()
|
||
|
<< " z_order=" << surface->z_order();
|
||
|
|
||
|
stream << " queue_ids=";
|
||
|
auto queue_ids = surface->GetQueueIds();
|
||
|
std::sort(queue_ids.begin(), queue_ids.end());
|
||
|
for (int32_t id : queue_ids) {
|
||
|
if (id != queue_ids[0])
|
||
|
stream << ",";
|
||
|
stream << id;
|
||
|
}
|
||
|
stream << std::endl;
|
||
|
}
|
||
|
}
|
||
|
stream << std::endl;
|
||
|
|
||
|
stream << hardware_composer_.Dump();
|
||
|
return stream.str();
|
||
|
}
|
||
|
|
||
|
void DisplayService::OnChannelClose(pdx::Message& message,
|
||
|
const std::shared_ptr<Channel>& channel) {
|
||
|
if (auto surface = std::static_pointer_cast<DisplaySurface>(channel)) {
|
||
|
surface->OnSetAttributes(message,
|
||
|
{{display::SurfaceAttribute::Visible,
|
||
|
display::SurfaceAttributeValue{false}}});
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// First-level dispatch for display service messages. Directly handles messages
|
||
|
// that are independent of the display surface (metrics, creation) and routes
|
||
|
// surface-specific messages to the per-instance handlers.
|
||
|
Status<void> DisplayService::HandleMessage(pdx::Message& message) {
|
||
|
ALOGD_IF(TRACE, "DisplayService::HandleMessage: opcode=%d", message.GetOp());
|
||
|
ATRACE_NAME("DisplayService::HandleMessage");
|
||
|
|
||
|
switch (message.GetOp()) {
|
||
|
case DisplayProtocol::GetMetrics::Opcode:
|
||
|
DispatchRemoteMethod<DisplayProtocol::GetMetrics>(
|
||
|
*this, &DisplayService::OnGetMetrics, message);
|
||
|
return {};
|
||
|
|
||
|
case DisplayProtocol::GetConfigurationData::Opcode:
|
||
|
DispatchRemoteMethod<DisplayProtocol::GetConfigurationData>(
|
||
|
*this, &DisplayService::OnGetConfigurationData, message);
|
||
|
return {};
|
||
|
|
||
|
case DisplayProtocol::GetDisplayIdentificationPort::Opcode:
|
||
|
DispatchRemoteMethod<DisplayProtocol::GetDisplayIdentificationPort>(
|
||
|
*this, &DisplayService::OnGetDisplayIdentificationPort, message);
|
||
|
return {};
|
||
|
|
||
|
case DisplayProtocol::CreateSurface::Opcode:
|
||
|
DispatchRemoteMethod<DisplayProtocol::CreateSurface>(
|
||
|
*this, &DisplayService::OnCreateSurface, message);
|
||
|
return {};
|
||
|
|
||
|
case DisplayProtocol::SetupGlobalBuffer::Opcode:
|
||
|
DispatchRemoteMethod<DisplayProtocol::SetupGlobalBuffer>(
|
||
|
*this, &DisplayService::OnSetupGlobalBuffer, message);
|
||
|
return {};
|
||
|
|
||
|
case DisplayProtocol::DeleteGlobalBuffer::Opcode:
|
||
|
DispatchRemoteMethod<DisplayProtocol::DeleteGlobalBuffer>(
|
||
|
*this, &DisplayService::OnDeleteGlobalBuffer, message);
|
||
|
return {};
|
||
|
|
||
|
case DisplayProtocol::GetGlobalBuffer::Opcode:
|
||
|
DispatchRemoteMethod<DisplayProtocol::GetGlobalBuffer>(
|
||
|
*this, &DisplayService::OnGetGlobalBuffer, message);
|
||
|
return {};
|
||
|
|
||
|
case DisplayProtocol::IsVrAppRunning::Opcode:
|
||
|
DispatchRemoteMethod<DisplayProtocol::IsVrAppRunning>(
|
||
|
*this, &DisplayService::IsVrAppRunning, message);
|
||
|
return {};
|
||
|
|
||
|
// Direct the surface specific messages to the surface instance.
|
||
|
case DisplayProtocol::SetAttributes::Opcode:
|
||
|
case DisplayProtocol::CreateQueue::Opcode:
|
||
|
case DisplayProtocol::GetSurfaceInfo::Opcode:
|
||
|
return HandleSurfaceMessage(message);
|
||
|
|
||
|
default:
|
||
|
return Service::HandleMessage(message);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
Status<display::Metrics> DisplayService::OnGetMetrics(
|
||
|
pdx::Message& /*message*/) {
|
||
|
const auto& params = hardware_composer_.GetPrimaryDisplayParams();
|
||
|
return {{static_cast<uint32_t>(params.width),
|
||
|
static_cast<uint32_t>(params.height),
|
||
|
static_cast<uint32_t>(params.dpi.x),
|
||
|
static_cast<uint32_t>(params.dpi.y),
|
||
|
static_cast<uint32_t>(params.vsync_period_ns),
|
||
|
0,
|
||
|
0,
|
||
|
0,
|
||
|
0.0,
|
||
|
{},
|
||
|
{}}};
|
||
|
}
|
||
|
|
||
|
pdx::Status<std::string> DisplayService::OnGetConfigurationData(
|
||
|
pdx::Message& /*message*/, display::ConfigFileType config_type) {
|
||
|
std::string property_name;
|
||
|
DisplayIdentificationData display_identification_data;
|
||
|
switch (config_type) {
|
||
|
case display::ConfigFileType::kLensMetrics:
|
||
|
property_name = kDvrLensMetricsProperty;
|
||
|
break;
|
||
|
case display::ConfigFileType::kDeviceMetrics:
|
||
|
property_name = kDvrDeviceMetricsProperty;
|
||
|
break;
|
||
|
case display::ConfigFileType::kDeviceConfiguration:
|
||
|
property_name = kDvrDeviceConfigProperty;
|
||
|
break;
|
||
|
case display::ConfigFileType::kDeviceEdid:
|
||
|
display_identification_data =
|
||
|
hardware_composer_.GetCurrentDisplayIdentificationData();
|
||
|
if (display_identification_data.size() == 0) {
|
||
|
return ErrorStatus(ENOENT);
|
||
|
}
|
||
|
return std::string(display_identification_data.begin(),
|
||
|
display_identification_data.end());
|
||
|
default:
|
||
|
return ErrorStatus(EINVAL);
|
||
|
}
|
||
|
std::string file_path = base::GetProperty(property_name, "");
|
||
|
if (file_path.empty()) {
|
||
|
return ErrorStatus(ENOENT);
|
||
|
}
|
||
|
|
||
|
std::string data;
|
||
|
if (!base::ReadFileToString(file_path, &data)) {
|
||
|
return ErrorStatus(errno);
|
||
|
}
|
||
|
|
||
|
return std::move(data);
|
||
|
}
|
||
|
|
||
|
pdx::Status<uint8_t> DisplayService::OnGetDisplayIdentificationPort(
|
||
|
pdx::Message& /*message*/) {
|
||
|
return hardware_composer_.GetCurrentDisplayPort();
|
||
|
}
|
||
|
|
||
|
// Creates a new DisplaySurface and associates it with this channel. This may
|
||
|
// only be done once per channel.
|
||
|
Status<display::SurfaceInfo> DisplayService::OnCreateSurface(
|
||
|
pdx::Message& message, const display::SurfaceAttributes& attributes) {
|
||
|
// A surface may only be created once per channel.
|
||
|
if (message.GetChannel())
|
||
|
return ErrorStatus(EINVAL);
|
||
|
|
||
|
ALOGI_IF(TRACE, "DisplayService::OnCreateSurface: cid=%d",
|
||
|
message.GetChannelId());
|
||
|
|
||
|
// Use the channel id as the unique surface id.
|
||
|
const int surface_id = message.GetChannelId();
|
||
|
const int process_id = message.GetProcessId();
|
||
|
const int user_id = message.GetEffectiveUserId();
|
||
|
|
||
|
ALOGI_IF(TRACE,
|
||
|
"DisplayService::OnCreateSurface: surface_id=%d process_id=%d",
|
||
|
surface_id, process_id);
|
||
|
|
||
|
auto surface_status =
|
||
|
DisplaySurface::Create(this, surface_id, process_id, user_id, attributes);
|
||
|
if (!surface_status) {
|
||
|
ALOGE("DisplayService::OnCreateSurface: Failed to create surface: %s",
|
||
|
surface_status.GetErrorMessage().c_str());
|
||
|
return ErrorStatus(surface_status.error());
|
||
|
}
|
||
|
auto surface = surface_status.take();
|
||
|
message.SetChannel(surface);
|
||
|
|
||
|
// Update the surface with the attributes supplied with the create call. For
|
||
|
// application surfaces this has the side effect of notifying the display
|
||
|
// manager of the new surface. For direct surfaces, this may trigger a mode
|
||
|
// change, depending on the value of the visible attribute.
|
||
|
surface->OnSetAttributes(message, attributes);
|
||
|
|
||
|
return {{surface->surface_id(), surface->visible(), surface->z_order()}};
|
||
|
}
|
||
|
|
||
|
void DisplayService::SurfaceUpdated(SurfaceType surface_type,
|
||
|
display::SurfaceUpdateFlags update_flags) {
|
||
|
ALOGD_IF(TRACE, "DisplayService::SurfaceUpdated: update_flags=%x",
|
||
|
update_flags.value());
|
||
|
if (update_flags.value() != 0) {
|
||
|
if (surface_type == SurfaceType::Application)
|
||
|
NotifyDisplayConfigurationUpdate();
|
||
|
else
|
||
|
UpdateActiveDisplaySurfaces();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
pdx::Status<BorrowedNativeBufferHandle> DisplayService::OnSetupGlobalBuffer(
|
||
|
pdx::Message& message, DvrGlobalBufferKey key, size_t size,
|
||
|
uint64_t usage) {
|
||
|
const int user_id = message.GetEffectiveUserId();
|
||
|
const bool trusted = user_id == AID_ROOT || IsTrustedUid(user_id);
|
||
|
|
||
|
if (!trusted) {
|
||
|
ALOGE(
|
||
|
"DisplayService::OnSetupGlobalBuffer: Permission denied for user_id=%d",
|
||
|
user_id);
|
||
|
return ErrorStatus(EPERM);
|
||
|
}
|
||
|
return SetupGlobalBuffer(key, size, usage);
|
||
|
}
|
||
|
|
||
|
pdx::Status<void> DisplayService::OnDeleteGlobalBuffer(pdx::Message& message,
|
||
|
DvrGlobalBufferKey key) {
|
||
|
const int user_id = message.GetEffectiveUserId();
|
||
|
const bool trusted = (user_id == AID_ROOT) || IsTrustedUid(user_id);
|
||
|
|
||
|
if (!trusted) {
|
||
|
ALOGE(
|
||
|
"DisplayService::OnDeleteGlobalBuffer: Permission denied for "
|
||
|
"user_id=%d",
|
||
|
user_id);
|
||
|
return ErrorStatus(EPERM);
|
||
|
}
|
||
|
return DeleteGlobalBuffer(key);
|
||
|
}
|
||
|
|
||
|
pdx::Status<BorrowedNativeBufferHandle> DisplayService::OnGetGlobalBuffer(
|
||
|
pdx::Message& /* message */, DvrGlobalBufferKey key) {
|
||
|
ALOGD_IF(TRACE, "DisplayService::OnGetGlobalBuffer: key=%d", key);
|
||
|
auto global_buffer = global_buffers_.find(key);
|
||
|
if (global_buffer != global_buffers_.end())
|
||
|
return {BorrowedNativeBufferHandle(*global_buffer->second, 0)};
|
||
|
else
|
||
|
return pdx::ErrorStatus(EINVAL);
|
||
|
}
|
||
|
|
||
|
// Calls the message handler for the DisplaySurface associated with this
|
||
|
// channel.
|
||
|
Status<void> DisplayService::HandleSurfaceMessage(pdx::Message& message) {
|
||
|
auto surface = std::static_pointer_cast<DisplaySurface>(message.GetChannel());
|
||
|
ALOGW_IF(!surface,
|
||
|
"DisplayService::HandleSurfaceMessage: surface is nullptr!");
|
||
|
|
||
|
if (surface)
|
||
|
return surface->HandleMessage(message);
|
||
|
else
|
||
|
return ErrorStatus(EINVAL);
|
||
|
}
|
||
|
|
||
|
std::shared_ptr<DisplaySurface> DisplayService::GetDisplaySurface(
|
||
|
int surface_id) const {
|
||
|
return std::static_pointer_cast<DisplaySurface>(GetChannel(surface_id));
|
||
|
}
|
||
|
|
||
|
std::vector<std::shared_ptr<DisplaySurface>>
|
||
|
DisplayService::GetDisplaySurfaces() const {
|
||
|
return GetChannels<DisplaySurface>();
|
||
|
}
|
||
|
|
||
|
std::vector<std::shared_ptr<DirectDisplaySurface>>
|
||
|
DisplayService::GetVisibleDisplaySurfaces() const {
|
||
|
std::vector<std::shared_ptr<DirectDisplaySurface>> visible_surfaces;
|
||
|
|
||
|
ForEachDisplaySurface(
|
||
|
SurfaceType::Direct,
|
||
|
[&](const std::shared_ptr<DisplaySurface>& surface) mutable {
|
||
|
if (surface->visible()) {
|
||
|
visible_surfaces.push_back(
|
||
|
std::static_pointer_cast<DirectDisplaySurface>(surface));
|
||
|
surface->ClearUpdate();
|
||
|
}
|
||
|
});
|
||
|
|
||
|
return visible_surfaces;
|
||
|
}
|
||
|
|
||
|
void DisplayService::UpdateActiveDisplaySurfaces() {
|
||
|
auto visible_surfaces = GetVisibleDisplaySurfaces();
|
||
|
ALOGD_IF(TRACE,
|
||
|
"DisplayService::UpdateActiveDisplaySurfaces: %zd visible surfaces",
|
||
|
visible_surfaces.size());
|
||
|
hardware_composer_.SetDisplaySurfaces(std::move(visible_surfaces));
|
||
|
}
|
||
|
|
||
|
pdx::Status<BorrowedNativeBufferHandle> DisplayService::SetupGlobalBuffer(
|
||
|
DvrGlobalBufferKey key, size_t size, uint64_t usage) {
|
||
|
auto global_buffer = global_buffers_.find(key);
|
||
|
if (global_buffer == global_buffers_.end()) {
|
||
|
auto ion_buffer = std::make_unique<IonBuffer>(static_cast<int>(size), 1,
|
||
|
HAL_PIXEL_FORMAT_BLOB, usage);
|
||
|
|
||
|
// Some buffers are used internally. If they were configured with an
|
||
|
// invalid size or format, this will fail.
|
||
|
int result = hardware_composer_.OnNewGlobalBuffer(key, *ion_buffer.get());
|
||
|
if (result < 0)
|
||
|
return ErrorStatus(result);
|
||
|
global_buffer =
|
||
|
global_buffers_.insert(std::make_pair(key, std::move(ion_buffer)))
|
||
|
.first;
|
||
|
}
|
||
|
|
||
|
return {BorrowedNativeBufferHandle(*global_buffer->second, 0)};
|
||
|
}
|
||
|
|
||
|
pdx::Status<void> DisplayService::DeleteGlobalBuffer(DvrGlobalBufferKey key) {
|
||
|
auto global_buffer = global_buffers_.find(key);
|
||
|
if (global_buffer != global_buffers_.end()) {
|
||
|
// Some buffers are used internally.
|
||
|
hardware_composer_.OnDeletedGlobalBuffer(key);
|
||
|
global_buffers_.erase(global_buffer);
|
||
|
}
|
||
|
|
||
|
return {0};
|
||
|
}
|
||
|
|
||
|
void DisplayService::SetDisplayConfigurationUpdateNotifier(
|
||
|
DisplayConfigurationUpdateNotifier update_notifier) {
|
||
|
update_notifier_ = update_notifier;
|
||
|
}
|
||
|
|
||
|
void DisplayService::NotifyDisplayConfigurationUpdate() {
|
||
|
if (update_notifier_)
|
||
|
update_notifier_();
|
||
|
}
|
||
|
|
||
|
Status<bool> DisplayService::IsVrAppRunning(pdx::Message& /*message*/) {
|
||
|
bool visible = false;
|
||
|
ForEachDisplaySurface(
|
||
|
SurfaceType::Application,
|
||
|
[&visible](const std::shared_ptr<DisplaySurface>& surface) {
|
||
|
if (surface->visible())
|
||
|
visible = true;
|
||
|
});
|
||
|
|
||
|
return {visible};
|
||
|
}
|
||
|
|
||
|
} // namespace dvr
|
||
|
} // namespace android
|