service: vi: Implement missing IApplicationDisplayService functions

Implements missing functions and improves permission handling in the VI
(Visual Interface) IApplicationDisplayService based on official documentation.

Key changes:
- Add session type enum to properly handle vi:u/vi:s/vi:m permissions
- Implement GetIndirectLayerImageCropMap for handling cropped layer images
- Implement GetDisplayVsyncEventForDebug for debug vsync event handling
- Add proper permission checks for GetSystemDisplayService and GetManagerDisplayService
- Improve AppletResourceUserId validation in OpenLayer
- Clean up logging and error handling

The changes follow the official documentation for permission handling:
- vi:u sessions can only use GetRelayService
- vi:s sessions can use everything except GetManagerDisplayService
- vi:m sessions can use all commands

REFS: switchbrew.org/wiki/Display_services#IApplicationDisplayService
This commit is contained in:
Zephyron 2025-01-26 13:27:06 +10:00
parent 924c06d88f
commit a6063bbd64
2 changed files with 75 additions and 8 deletions

View file

@ -14,9 +14,11 @@
namespace Service::VI {
IApplicationDisplayService::IApplicationDisplayService(Core::System& system_,
std::shared_ptr<Container> container)
std::shared_ptr<Container> container,
SessionType type)
: ServiceFramework{system_, "IApplicationDisplayService"},
m_container{std::move(container)}, m_context{system, "IApplicationDisplayService"} {
m_container{std::move(container)}, m_context{system, "IApplicationDisplayService"},
m_session_type{type} {
// clang-format off
static const FunctionInfo functions[] = {
{100, C<&IApplicationDisplayService::GetRelayService>, "GetRelayService"},
@ -36,10 +38,10 @@ IApplicationDisplayService::IApplicationDisplayService(Core::System& system_,
{2101, C<&IApplicationDisplayService::SetLayerScalingMode>, "SetLayerScalingMode"},
{2102, C<&IApplicationDisplayService::ConvertScalingMode>, "ConvertScalingMode"},
{2450, C<&IApplicationDisplayService::GetIndirectLayerImageMap>, "GetIndirectLayerImageMap"},
{2451, nullptr, "GetIndirectLayerImageCropMap"},
{2451, C<&IApplicationDisplayService::GetIndirectLayerImageCropMap>, "GetIndirectLayerImageCropMap"},
{2460, C<&IApplicationDisplayService::GetIndirectLayerImageRequiredMemoryInfo>, "GetIndirectLayerImageRequiredMemoryInfo"},
{5202, C<&IApplicationDisplayService::GetDisplayVsyncEvent>, "GetDisplayVsyncEvent"},
{5203, nullptr, "GetDisplayVsyncEventForDebug"},
{5203, C<&IApplicationDisplayService::GetDisplayVsyncEventForDebug>, "GetDisplayVsyncEventForDebug"},
};
// clang-format on
@ -60,13 +62,19 @@ IApplicationDisplayService::~IApplicationDisplayService() {
Result IApplicationDisplayService::GetRelayService(
Out<SharedPointer<Nvnflinger::IHOSBinderDriver>> out_relay_service) {
LOG_WARNING(Service_VI, "(STUBBED) called");
LOG_DEBUG(Service_VI, "called");
R_RETURN(m_container->GetBinderDriver(out_relay_service));
}
Result IApplicationDisplayService::GetSystemDisplayService(
Out<SharedPointer<ISystemDisplayService>> out_system_display_service) {
LOG_WARNING(Service_VI, "(STUBBED) called");
LOG_DEBUG(Service_VI, "called");
// vi:u is not allowed to use this command
if (m_session_type == SessionType::User) {
R_THROW(ResultPermissionDenied);
}
*out_system_display_service = std::make_shared<ISystemDisplayService>(system, m_container);
R_SUCCEED();
}
@ -74,6 +82,12 @@ Result IApplicationDisplayService::GetSystemDisplayService(
Result IApplicationDisplayService::GetManagerDisplayService(
Out<SharedPointer<IManagerDisplayService>> out_manager_display_service) {
LOG_DEBUG(Service_VI, "called");
// Only vi:m is allowed to use this command
if (m_session_type != SessionType::Manager) {
R_THROW(ResultPermissionDenied);
}
*out_manager_display_service = std::make_shared<IManagerDisplayService>(system, m_container);
R_SUCCEED();
}
@ -162,6 +176,12 @@ Result IApplicationDisplayService::OpenLayer(Out<u64> out_size,
LOG_DEBUG(Service_VI, "called. layer_id={}, aruid={:#x}", layer_id, aruid.pid);
// Check if AppletResourceUserId is valid
if (aruid.pid == 0) {
LOG_ERROR(Service_VI, "Invalid AppletResourceUserId");
R_THROW(ResultOperationFailed);
}
u64 display_id;
R_TRY(m_container->OpenDisplay(&display_id, display_name));
@ -299,4 +319,35 @@ Result IApplicationDisplayService::GetIndirectLayerImageRequiredMemoryInfo(Out<s
R_SUCCEED();
}
Result IApplicationDisplayService::GetIndirectLayerImageCropMap(
Out<u64> out_size,
Out<u64> out_stride,
OutBuffer<BufferAttr_HipcMapTransferAllowsNonSecure | BufferAttr_HipcMapAlias> out_buffer,
float x1, float y1, float x2, float y2,
u64 indirect_layer_consumer_handle,
ClientAppletResourceUserId aruid) {
LOG_WARNING(Service_VI,
"(STUBBED) called, crop_params={{{}, {}, {}, {}}}, indirect_layer_consumer_handle={}, "
"aruid={:#x}",
x1, y1, x2, y2, indirect_layer_consumer_handle, aruid.pid);
*out_size = 0;
*out_stride = 0;
R_SUCCEED();
}
Result IApplicationDisplayService::GetDisplayVsyncEventForDebug(
OutCopyHandle<Kernel::KReadableEvent> out_vsync_event, u64 display_id) {
LOG_DEBUG(Service_VI, "called. display_id={}", display_id);
std::scoped_lock lk{m_lock};
auto [it, created] = m_display_vsync_events.emplace(display_id, m_context);
R_UNLESS(created, VI::ResultPermissionDenied);
m_container->LinkVsyncEvent(display_id, &it->second);
*out_vsync_event = it->second.GetHandle();
R_SUCCEED();
}
} // namespace Service::VI

View file

@ -26,7 +26,14 @@ class ISystemDisplayService;
class IApplicationDisplayService final : public ServiceFramework<IApplicationDisplayService> {
public:
IApplicationDisplayService(Core::System& system_, std::shared_ptr<Container> container);
enum class SessionType {
User, // vi:u
System, // vi:s
Manager, // vi:m
};
IApplicationDisplayService(Core::System& system_, std::shared_ptr<Container> container,
SessionType type = SessionType::Manager);
~IApplicationDisplayService() override;
std::shared_ptr<Container> GetContainer() const {
@ -64,13 +71,22 @@ public:
OutBuffer<BufferAttr_HipcMapTransferAllowsNonSecure | BufferAttr_HipcMapAlias> out_buffer,
s64 width, s64 height, u64 indirect_layer_consumer_handle,
ClientAppletResourceUserId aruid);
Result GetIndirectLayerImageCropMap(
Out<u64> out_size, Out<u64> out_stride,
OutBuffer<BufferAttr_HipcMapTransferAllowsNonSecure | BufferAttr_HipcMapAlias> out_buffer,
float x1, float y1, float x2, float y2,
u64 indirect_layer_consumer_handle,
ClientAppletResourceUserId aruid);
Result GetIndirectLayerImageRequiredMemoryInfo(Out<s64> out_size, Out<s64> out_alignment,
s64 width, s64 height);
Result GetDisplayVsyncEventForDebug(OutCopyHandle<Kernel::KReadableEvent> out_vsync_event,
u64 display_id);
private:
const std::shared_ptr<Container> m_container;
KernelHelpers::ServiceContext m_context;
const SessionType m_session_type;
std::mutex m_lock{};
std::set<u64> m_open_layer_ids{};
std::set<u64> m_stray_layer_ids{};