From a9de99357bc2eab3d13a4ee7d5bbe3e96acc5b7e Mon Sep 17 00:00:00 2001 From: PixelyIon Date: Sun, 4 Jul 2021 05:21:19 +0530 Subject: [PATCH] Rework VI + IHOSBinder VI/IHOSBinder suffered from major inaccuracies in their function due to being quickly thrown together initially with little concern for accuracy, this has now been fixed with them being substantially more accurate now. --- app/CMakeLists.txt | 4 +- app/src/main/cpp/skyline/kernel/ipc.h | 13 +- .../am/controller/ISelfController.cpp | 16 +- .../services/am/controller/ISelfController.h | 5 + .../hosbinder/GraphicBufferProducer.cpp | 29 +--- .../hosbinder/GraphicBufferProducer.h | 35 +--- .../services/hosbinder/IHOSBinderDriver.cpp | 155 ++++++++++++++++-- .../services/hosbinder/IHOSBinderDriver.h | 69 +++++++- .../services/{common => hosbinder}/parcel.cpp | 2 +- .../services/{common => hosbinder}/parcel.h | 2 +- .../main/cpp/skyline/services/serviceman.cpp | 14 +- .../main/cpp/skyline/services/serviceman.h | 21 +-- .../visrv/IApplicationDisplayService.cpp | 68 +++----- .../visrv/IApplicationDisplayService.h | 34 ++-- .../services/visrv/IApplicationRootService.h | 20 +++ .../services/visrv/IDisplayService.cpp | 37 ++--- .../skyline/services/visrv/IDisplayService.h | 19 +-- .../services/visrv/IManagerDisplayService.cpp | 24 +-- .../services/visrv/IManagerRootService.cpp | 14 -- .../services/visrv/IManagerRootService.h | 20 +-- .../skyline/services/visrv/IRootService.cpp | 19 +++ .../cpp/skyline/services/visrv/IRootService.h | 37 +++++ .../services/visrv/ISystemRootService.h | 20 +++ .../main/cpp/skyline/services/visrv/results.h | 10 ++ 24 files changed, 425 insertions(+), 262 deletions(-) rename app/src/main/cpp/skyline/services/{common => hosbinder}/parcel.cpp (97%) rename app/src/main/cpp/skyline/services/{common => hosbinder}/parcel.h (99%) create mode 100644 app/src/main/cpp/skyline/services/visrv/IApplicationRootService.h delete mode 100644 app/src/main/cpp/skyline/services/visrv/IManagerRootService.cpp create mode 100644 app/src/main/cpp/skyline/services/visrv/IRootService.cpp create mode 100644 app/src/main/cpp/skyline/services/visrv/IRootService.h create mode 100644 app/src/main/cpp/skyline/services/visrv/ISystemRootService.h create mode 100644 app/src/main/cpp/skyline/services/visrv/results.h diff --git a/app/CMakeLists.txt b/app/CMakeLists.txt index 4f5c449d..e8ce8702 100644 --- a/app/CMakeLists.txt +++ b/app/CMakeLists.txt @@ -121,7 +121,6 @@ add_library(skyline SHARED ${source_DIR}/skyline/vfs/ticket.cpp ${source_DIR}/skyline/services/serviceman.cpp ${source_DIR}/skyline/services/base_service.cpp - ${source_DIR}/skyline/services/common/parcel.cpp ${source_DIR}/skyline/services/sm/IUserInterface.cpp ${source_DIR}/skyline/services/fatalsrv/IService.cpp ${source_DIR}/skyline/services/audio/IAudioOutManager.cpp @@ -182,12 +181,13 @@ add_library(skyline SHARED ${source_DIR}/skyline/services/nvdrv/devices/nvhost_channel.cpp ${source_DIR}/skyline/services/nvdrv/devices/nvhost_as_gpu.cpp ${source_DIR}/skyline/services/nvdrv/devices/nvhost_syncpoint.cpp + ${source_DIR}/skyline/services/hosbinder/parcel.cpp ${source_DIR}/skyline/services/hosbinder/IHOSBinderDriver.cpp ${source_DIR}/skyline/services/hosbinder/GraphicBufferProducer.cpp ${source_DIR}/skyline/services/visrv/IDisplayService.cpp ${source_DIR}/skyline/services/visrv/IApplicationDisplayService.cpp ${source_DIR}/skyline/services/visrv/IManagerDisplayService.cpp - ${source_DIR}/skyline/services/visrv/IManagerRootService.cpp + ${source_DIR}/skyline/services/visrv/IRootService.cpp ${source_DIR}/skyline/services/visrv/ISystemDisplayService.cpp ${source_DIR}/skyline/services/pl/IPlatformServiceManager.cpp ${source_DIR}/skyline/services/aocsrv/IAddOnContentManager.cpp diff --git a/app/src/main/cpp/skyline/kernel/ipc.h b/app/src/main/cpp/skyline/kernel/ipc.h index c86e1cca..21248e8d 100644 --- a/app/src/main/cpp/skyline/kernel/ipc.h +++ b/app/src/main/cpp/skyline/kernel/ipc.h @@ -218,11 +218,16 @@ namespace skyline { /** * @brief Returns a std::string_view from the payload - * @param size The length of the string (0 means the string is null terminated) + * @param size The length of the string (0 should only be used with nullTerminated and automatically determines size) + * @param nullTerminated If the returned view should only encapsulate a null terminated substring */ - std::string_view PopString(size_t size = 0) { - auto view{size ? std::string_view(reinterpret_cast(payloadOffset), size) : std::string_view(reinterpret_cast(payloadOffset))}; - payloadOffset += view.length(); + std::string_view PopString(size_t size = 0, bool nullTerminated = true) { + size = size ? size : cmdArgSz - reinterpret_cast(payloadOffset); + auto view{span(payloadOffset, size).as_string(nullTerminated)}; + if (nullTerminated) + payloadOffset += size; + else + payloadOffset += view.length(); return view; } diff --git a/app/src/main/cpp/skyline/services/am/controller/ISelfController.cpp b/app/src/main/cpp/skyline/services/am/controller/ISelfController.cpp index 70e6e70e..7f829c33 100644 --- a/app/src/main/cpp/skyline/services/am/controller/ISelfController.cpp +++ b/app/src/main/cpp/skyline/services/am/controller/ISelfController.cpp @@ -2,11 +2,11 @@ // Copyright © 2020 Skyline Team and Contributors (https://github.com/skyline-emu/) #include -#include +#include #include "ISelfController.h" namespace skyline::service::am { - ISelfController::ISelfController(const DeviceState &state, ServiceManager &manager) : libraryAppletLaunchableEvent(std::make_shared(state, false)), accumulatedSuspendedTickChangedEvent(std::make_shared(state, false)), BaseService(state, manager) {} + ISelfController::ISelfController(const DeviceState &state, ServiceManager &manager) : libraryAppletLaunchableEvent(std::make_shared(state, false)), accumulatedSuspendedTickChangedEvent(std::make_shared(state, false)), hosbinder(manager.CreateOrGetService("dispdrv")), BaseService(state, manager) {} Result ISelfController::LockExit(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { return {}; @@ -47,18 +47,12 @@ namespace skyline::service::am { } Result ISelfController::CreateManagedDisplayLayer(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { - state.logger->Debug("Creating Managed Layer on Default Display"); - - auto producer{hosbinder::producer.lock()}; - if (producer->layerStatus != hosbinder::LayerStatus::Uninitialized) - throw exception("The application is creating more than one layer"); - producer->layerStatus = hosbinder::LayerStatus::Managed; - - response.Push(0); + auto layerId{hosbinder->CreateLayer(hosbinder::DisplayId::Default)}; + state.logger->Debug("Creating Managed Layer #{} on 'Default' Display", layerId); + response.Push(layerId); return {}; } - Result ISelfController::GetAccumulatedSuspendedTickValue(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { // TODO: Properly handle this after we implement game suspending response.Push(0); diff --git a/app/src/main/cpp/skyline/services/am/controller/ISelfController.h b/app/src/main/cpp/skyline/services/am/controller/ISelfController.h index 7fd4fe02..fc7f200e 100644 --- a/app/src/main/cpp/skyline/services/am/controller/ISelfController.h +++ b/app/src/main/cpp/skyline/services/am/controller/ISelfController.h @@ -5,6 +5,10 @@ #include +namespace skyline::service::hosbinder { + class IHOSBinderDriver; +} + namespace skyline::service::am { /** * @brief This has functions relating to an application's own current status @@ -14,6 +18,7 @@ namespace skyline::service::am { private: std::shared_ptr libraryAppletLaunchableEvent; //!< This KEvent is triggered when the library applet is launchable std::shared_ptr accumulatedSuspendedTickChangedEvent; //!< This KEvent is triggered when the time the system has spent in suspend is updated + std::shared_ptr hosbinder; //!< IHOSBinder service for managed display layers public: ISelfController(const DeviceState &state, ServiceManager &manager); diff --git a/app/src/main/cpp/skyline/services/hosbinder/GraphicBufferProducer.cpp b/app/src/main/cpp/skyline/services/hosbinder/GraphicBufferProducer.cpp index d581a0c7..c9710c13 100644 --- a/app/src/main/cpp/skyline/services/hosbinder/GraphicBufferProducer.cpp +++ b/app/src/main/cpp/skyline/services/hosbinder/GraphicBufferProducer.cpp @@ -70,7 +70,7 @@ namespace skyline::service::hosbinder { } else { size_t index{}; std::string bufferString; - for (auto& bufferSlot : queue) + for (auto &bufferSlot : queue) bufferString += util::Format("\n#{} - State: {}, Has Graphic Buffer: {}, Frame Number: {}", ++index, ToString(bufferSlot.state), static_cast(bufferSlot.graphicBuffer), bufferSlot.frameNumber); state.logger->Warn("Cannot find any free buffers to dequeue:{}", bufferString); return AndroidStatus::InvalidOperation; @@ -489,31 +489,4 @@ namespace skyline::service::hosbinder { throw exception("An unimplemented transaction was called: {}", static_cast(code)); } } - - static frz::unordered_map DisplayTypeMap{ - {"Default", DisplayId::Default}, - {"External", DisplayId::External}, - {"Edid", DisplayId::Edid}, - {"Internal", DisplayId::Internal}, - {"Null", DisplayId::Null}, - }; - - void GraphicBufferProducer::SetDisplay(const std::string &name) { - try { - if (displayId == DisplayId::Null) - displayId = DisplayTypeMap.at(frz::string(name.data(), name.size())); - else - throw exception("Trying to change display type from non-null type"); - } catch (const std::out_of_range &) { - throw exception("The display with name: '{}' doesn't exist", name); - } - } - - void GraphicBufferProducer::CloseDisplay() { - if (displayId == DisplayId::Null) - state.logger->Warn("Trying to close uninitiated display"); - displayId = DisplayId::Null; - } - - std::weak_ptr producer{}; } diff --git a/app/src/main/cpp/skyline/services/hosbinder/GraphicBufferProducer.h b/app/src/main/cpp/skyline/services/hosbinder/GraphicBufferProducer.h index f4f5276c..06fa143b 100644 --- a/app/src/main/cpp/skyline/services/hosbinder/GraphicBufferProducer.h +++ b/app/src/main/cpp/skyline/services/hosbinder/GraphicBufferProducer.h @@ -6,7 +6,7 @@ #pragma once #include -#include +#include "parcel.h" #include "android_types.h" #include "native_window.h" @@ -43,24 +43,6 @@ namespace skyline::service::hosbinder { std::unique_ptr graphicBuffer{}; }; - /** - * @brief An enumeration of all the possible display IDs - * @url https://switchbrew.org/wiki/Display_services#DisplayName - */ - enum class DisplayId : u64 { - Default, //!< Refers to the default display used by most applications - External, //!< Refers to an external display - Edid, //!< Refers to an external display with EDID capabilities - Internal, //!< Refers to the the internal display - Null, //!< Refers to the null display which is used for discarding data - }; - - enum class LayerStatus { - Uninitialized, //!< The layer hasn't been initialized - Stray, //!< The layer has been initialized as a stray layer - Managed, //!< The layer has been initialized as a managed layer - }; - /** * @brief An endpoint for the GraphicBufferProducer interface, it approximately implements BufferQueueProducer but also implements the functionality of interfaces called into by it such as GraphicBufferConsumer, Gralloc and so on * @url https://cs.android.com/android/platform/superproject/+/android-5.1.1_r38:frameworks/native/include/gui/IGraphicBufferProducer.h @@ -147,8 +129,6 @@ namespace skyline::service::hosbinder { public: std::shared_ptr bufferEvent; //!< Signalled every time a buffer in the queue is freed - DisplayId displayId{DisplayId::Null}; //!< The ID of this display - LayerStatus layerStatus{LayerStatus::Uninitialized}; //!< The status of the single layer the display has /** * @brief The transactions supported by android.gui.IGraphicBufferProducer @@ -178,18 +158,5 @@ namespace skyline::service::hosbinder { * @url https://cs.android.com/android/platform/superproject/+/android-5.1.1_r38:frameworks/native/libs/gui/IGraphicBufferProducer.cpp;l=277-426 */ void OnTransact(TransactionCode code, Parcel &in, Parcel &out); - - /** - * @brief Sets displayId to a specific display type - * @note displayId has to be DisplayId::Null or this will throw an exception - */ - void SetDisplay(const std::string &name); - - /** - * @brief Closes the display by setting displayId to DisplayId::Null - */ - void CloseDisplay(); }; - - extern std::weak_ptr producer; //!< A globally shared instance of the GraphicsBufferProducer } diff --git a/app/src/main/cpp/skyline/services/hosbinder/IHOSBinderDriver.cpp b/app/src/main/cpp/skyline/services/hosbinder/IHOSBinderDriver.cpp index 9868eb33..659f1758 100644 --- a/app/src/main/cpp/skyline/services/hosbinder/IHOSBinderDriver.cpp +++ b/app/src/main/cpp/skyline/services/hosbinder/IHOSBinderDriver.cpp @@ -7,43 +7,166 @@ #include "GraphicBufferProducer.h" namespace skyline::service::hosbinder { - IHOSBinderDriver::IHOSBinderDriver(const DeviceState &state, ServiceManager &manager) : producer(hosbinder::producer.expired() ? std::make_shared(state) : hosbinder::producer.lock()), BaseService(state, manager) { - if (hosbinder::producer.expired()) - hosbinder::producer = producer; - } + IHOSBinderDriver::IHOSBinderDriver(const DeviceState &state, ServiceManager &manager) : BaseService(state, manager) {} Result IHOSBinderDriver::TransactParcel(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { - auto layerId{request.Pop()}; + // We opted for just supporting a single layer and display as it's what basically all games use and wasting cycles on it is pointless + // If this was not done then we would need to maintain an array of GraphicBufferProducer objects for each layer and send the request for it specifically + // There would also need to be an external compositor which composites all the graphics buffers submitted to every GraphicBufferProducer + + auto binderHandle{request.Pop()}; + if (binderHandle != DefaultBinderLayerHandle) + throw exception("Transaction on unknown binder object: #{}", binderHandle); + auto code{request.Pop()}; Parcel in(request.inputBuf.at(0), state, true); Parcel out(state); - // We opted for just supporting a single layer and display as it's what basically all games use and wasting cycles on it is pointless - // If this was not done then we would need to maintain an array of GraphicBufferProducer objects for each layer and send the request for it specifically - // There would also need to be an external compositor which composites all the graphics buffers submitted to every GraphicBufferProducer - - state.logger->Debug("Layer ID: {}, Code: {}", layerId, code); - producer->OnTransact(code, in, out); + if (!layer) + throw exception("Transacting parcel with non-existant layer"); + layer->OnTransact(code, in, out); out.WriteParcel(request.outputBuf.at(0)); return {}; } Result IHOSBinderDriver::AdjustRefcount(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { - request.Skip(); - auto addVal{request.Pop()}; - auto type{request.Pop()}; - state.logger->Debug("Reference Change: {} {} reference", addVal, type ? "strong" : "weak"); + auto binderHandle{request.Pop()}; + if (binderHandle != DefaultBinderLayerHandle) + throw exception("Adjusting Binder object reference count for unknown object: #{}", binderHandle); + + auto value{request.Pop()}; + bool isStrong{static_cast(request.Pop())}; + if (isStrong) { + if (layerStrongReferenceCount != InitialStrongReferenceCount) + layerStrongReferenceCount += value; + else + layerStrongReferenceCount = value; + + if (layerStrongReferenceCount < 0) { + state.logger->Warn("Strong reference count is lower than 0: {} + {} = {}", (layerStrongReferenceCount - value), value, layerStrongReferenceCount); + layerStrongReferenceCount = 0; + } + + if (layerStrongReferenceCount == 0) + layer.reset(); + } else { + layerWeakReferenceCount += value; + + if (layerWeakReferenceCount < 0) { + state.logger->Warn("Weak reference count is lower than 0: {} + {} = {}", (layerWeakReferenceCount - value), value, layerWeakReferenceCount); + layerWeakReferenceCount = 0; + } + + if (layerWeakReferenceCount == 0 && layerStrongReferenceCount < 1) + layer.reset(); + } + + state.logger->Debug("Reference Change: {} {} reference (S{} W{})", value, isStrong ? "strong" : "weak", layerStrongReferenceCount, layerWeakReferenceCount); return {}; } Result IHOSBinderDriver::GetNativeHandle(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { - KHandle handle{state.process->InsertItem(producer->bufferEvent)}; + auto binderHandle{request.Pop()}; + if (binderHandle != DefaultBinderLayerHandle) + throw exception("Getting handle from unknown binder object: #{}", binderHandle); + + constexpr u32 BufferEventHandleId{0xF}; //!< The ID of the buffer event handle in the layer object + auto handleId{request.Pop()}; + if (handleId != BufferEventHandleId) + throw exception("Getting unknown handle from binder object: 0x{:X}", handleId); + + KHandle handle{state.process->InsertItem(layer->bufferEvent)}; state.logger->Debug("Display Buffer Event Handle: 0x{:X}", handle); response.copyHandles.push_back(handle); return {}; } + + DisplayId IHOSBinderDriver::OpenDisplay(std::string_view name) { + if (name.length() > sizeof(u64)) + throw exception("Opening display with name larger than sizeof(u64): '{}' ({})", name, name.length()); + + auto newDisplayId{[&]() -> DisplayId { + #define DISPLAY_CASE(id) case util::MakeMagic(#id): { return DisplayId::id; } + switch (util::MakeMagic(name)) { + DISPLAY_CASE(Default) + DISPLAY_CASE(External) + DISPLAY_CASE(Edid) + DISPLAY_CASE(Internal) + DISPLAY_CASE(Null) + default: + throw exception("Opening non-existent display: '{}'", name); + } + #undef DISPLAY_CASE + }()}; + if (displayId != DisplayId::Null && displayId != newDisplayId) + throw exception("Opening a new display ({}) prior to closing opened display ({})", name, ToString(displayId)); + + return displayId = newDisplayId; + } + + void IHOSBinderDriver::CloseDisplay(DisplayId id) { + if (displayId != id) + throw exception("Closing an unopened display: {} (Currently open display: {})", ToString(id), ToString(displayId)); + displayId = DisplayId::Null; + } + + u64 IHOSBinderDriver::CreateLayer(DisplayId pDisplayId) { + if (pDisplayId != displayId) + throw exception("Creating layer on unopened display: '{}'", ToString(pDisplayId)); + else if (layer) + throw exception("Creation of multiple layers is not supported"); + + layerStrongReferenceCount = InitialStrongReferenceCount; + layerWeakReferenceCount = 0; + layer.emplace(state); + + return DefaultLayerId; + } + + Parcel IHOSBinderDriver::OpenLayer(DisplayId pDisplayId, u64 layerId) { + if (pDisplayId != displayId) + throw exception("Opening layer #{} with unopened display: '{}'", layerId, ToString(pDisplayId)); + else if (layerId != DefaultLayerId) + throw exception("Attempting to open unrecognized layer #{}", layerId); + else if (!layer) + throw exception("Opening layer #{} prior to creation or after destruction", layerId); + + Parcel parcel(state); + // Flat Binder with the layer's IGraphicBufferProducer + // https://cs.android.com/android/platform/superproject/+/android-5.1.1_r38:bionic/libc/kernel/uapi/linux/binder.h;l=47-57 + parcel.Push(0x2); // Type of the IBinder + parcel.Push(0); // Flags + parcel.Push(DefaultBinderLayerHandle); // Handle + parcel.Push(0); // Cookie + // Unknown HOS-specific layer properties + parcel.Push(util::MakeMagic("dispdrv\0")); + parcel.Push({}); // Unknown + + parcel.PushObject(0); // Offset of flattened IBinder relative to Parcel data + + layerWeakReferenceCount++; // IBinder represents a weak reference to the layer + + return parcel; + } + + void IHOSBinderDriver::CloseLayer(u64 layerId) { + if (layerId != DefaultLayerId) + throw exception("Closing non-existent layer #{}", layerId); + else if (layerWeakReferenceCount == 0) + throw exception("Closing layer #{} which has no weak references to it", layerId); + + if (--layerWeakReferenceCount == 0 && layerStrongReferenceCount < 1) + layer.reset(); + } + + void IHOSBinderDriver::DestroyLayer(u64 layerId) { + if (layerId != DefaultLayerId) + throw exception("Destroying non-existent layer #{}", layerId); + else if (layer) + throw exception("Destroying layer #{} which hasn't been closed: Weak References: {}, Strong References: {}", layerWeakReferenceCount, layerStrongReferenceCount); + } } diff --git a/app/src/main/cpp/skyline/services/hosbinder/IHOSBinderDriver.h b/app/src/main/cpp/skyline/services/hosbinder/IHOSBinderDriver.h index b28ef62b..af423490 100644 --- a/app/src/main/cpp/skyline/services/hosbinder/IHOSBinderDriver.h +++ b/app/src/main/cpp/skyline/services/hosbinder/IHOSBinderDriver.h @@ -3,17 +3,46 @@ #pragma once -#include +#include +#include "GraphicBufferProducer.h" namespace skyline::service::hosbinder { - class GraphicBufferProducer; + /** + * @brief A display identifier specific to HOS, translated to a corresponding Android display internally + * @url https://switchbrew.org/wiki/Display_services#DisplayName + */ + enum class DisplayId : u64 { + Default, //!< Automatically determines the default display + External, //!< Refers to an external display, if any + Edid, //!< Refers to an external display with EDID capabilities + Internal, //!< Refers to the internal display on the Switch + Null, //!< A placeholder display which doesn't refer to any display + }; + + ENUM_STRING(DisplayId, { + ENUM_CASE(Default); + ENUM_CASE(External); + ENUM_CASE(Edid); + ENUM_CASE(Internal); + ENUM_CASE(Null); + }) /** * @brief nvnflinger:dispdrv or nns::hosbinder::IHOSBinderDriver is a translation layer between Android Binder IPC and HOS IPC to communicate with the Android display stack */ class IHOSBinderDriver : public BaseService { private: - std::shared_ptr producer; + DisplayId displayId{DisplayId::Null}; //!< The ID of the display that the layer is connected to + constexpr static u64 DefaultLayerId{1}; //!< The VI ID of the default (and only) layer in our surface stack + constexpr static u32 DefaultBinderLayerHandle{1}; //!< The handle as assigned by SurfaceFlinger of the default layer + constexpr static i32 InitialStrongReferenceCount{std::numeric_limits::min()}; //!< Initial value for the strong reference count, weak references will keep the object alive till the strong reference count is first mutated + i32 layerStrongReferenceCount; //!< The amount of strong references to the layer object + i32 layerWeakReferenceCount; //!< The amount of weak references to the layer object + std::optional layer; //!< The IGraphicBufferProducer backing the layer (NativeWindow) + + void AddWeakLayerReference(u32 count = 1) { + + } public: IHOSBinderDriver(const DeviceState &state, ServiceManager &manager); @@ -25,7 +54,7 @@ namespace skyline::service::hosbinder { Result TransactParcel(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response); /** - * @brief Adjusts the reference counts to the underlying binder, it's stubbed as we aren't using the real symbols + * @brief Adjusts the reference counts to the underlying Android reference counted object * @url https://switchbrew.org/wiki/Nvnflinger_services#AdjustRefcount */ Result AdjustRefcount(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response); @@ -36,6 +65,38 @@ namespace skyline::service::hosbinder { */ Result GetNativeHandle(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response); + /** + * @note This will throw an exception if another display was opened and not closed + */ + DisplayId OpenDisplay(std::string_view name); + + /** + * @note This **must** be called prior to opening a different Display + */ + void CloseDisplay(DisplayId id); + + /** + * @return An ID that can be utilized to refer to the layer + * @note This will throw an exception if the specified display has not been opened + */ + u64 CreateLayer(DisplayId displayId); + + /** + * @return A parcel with a flattened IBinder to the IGraphicBufferProducer of the layer + * @note This will throw an exception if the specified display has not been opened + */ + Parcel OpenLayer(DisplayId displayId, u64 layerId); + + /** + * @note This **must** be called prior to destroying the layer + */ + void CloseLayer(u64 layerId); + + /** + * @note This **must** be called prior to opening a different Display + */ + void DestroyLayer(u64 layerId); + SERVICE_DECL( SFUNC(0x0, IHOSBinderDriver, TransactParcel), SFUNC(0x1, IHOSBinderDriver, AdjustRefcount), diff --git a/app/src/main/cpp/skyline/services/common/parcel.cpp b/app/src/main/cpp/skyline/services/hosbinder/parcel.cpp similarity index 97% rename from app/src/main/cpp/skyline/services/common/parcel.cpp rename to app/src/main/cpp/skyline/services/hosbinder/parcel.cpp index 15c71484..fcc7b108 100644 --- a/app/src/main/cpp/skyline/services/common/parcel.cpp +++ b/app/src/main/cpp/skyline/services/hosbinder/parcel.cpp @@ -3,7 +3,7 @@ #include "parcel.h" -namespace skyline::service { +namespace skyline::service::hosbinder { Parcel::Parcel(span buffer, const DeviceState &state, bool hasToken) : state(state) { header = buffer.as(); diff --git a/app/src/main/cpp/skyline/services/common/parcel.h b/app/src/main/cpp/skyline/services/hosbinder/parcel.h similarity index 99% rename from app/src/main/cpp/skyline/services/common/parcel.h rename to app/src/main/cpp/skyline/services/hosbinder/parcel.h index a6615100..09dce4da 100644 --- a/app/src/main/cpp/skyline/services/common/parcel.h +++ b/app/src/main/cpp/skyline/services/hosbinder/parcel.h @@ -5,7 +5,7 @@ #include -namespace skyline::service { +namespace skyline::service::hosbinder { /** * @brief This allows easy access and efficient serialization of an Android Parcel object * @url https://switchbrew.org/wiki/Display_services#Parcel diff --git a/app/src/main/cpp/skyline/services/serviceman.cpp b/app/src/main/cpp/skyline/services/serviceman.cpp index 8b955941..2a848cfe 100644 --- a/app/src/main/cpp/skyline/services/serviceman.cpp +++ b/app/src/main/cpp/skyline/services/serviceman.cpp @@ -18,6 +18,9 @@ #include "services/timesrv/core.h" #include "fssrv/IFileSystemProxy.h" #include "services/nvdrv/INvDrvServices.h" +#include "hosbinder/IHOSBinderDriver.h" +#include "visrv/IApplicationRootService.h" +#include "visrv/ISystemRootService.h" #include "visrv/IManagerRootService.h" #include "pl/IPlatformServiceManager.h" #include "aocsrv/IAddOnContentManager.h" @@ -35,7 +38,7 @@ #define SERVICE_CASE(class, name, ...) \ case util::MakeMagic(name): { \ - std::shared_ptr serviceObject = std::make_shared(state, *this __VA_OPT__(,) __VA_ARGS__); \ + std::shared_ptr serviceObject{std::make_shared(state, *this, ##__VA_ARGS__)}; \ serviceMap[util::MakeMagic(name)] = serviceObject; \ return serviceObject; \ } @@ -49,7 +52,7 @@ namespace skyline::service { ServiceManager::ServiceManager(const DeviceState &state) : state(state), smUserInterface(std::make_shared(state, *this)), globalServiceState(std::make_shared(state)) {} - std::shared_ptr ServiceManager::CreateService(ServiceName name) { + std::shared_ptr ServiceManager::CreateOrGetService(ServiceName name) { auto serviceIter{serviceMap.find(name)}; if (serviceIter != serviceMap.end()) return (*serviceIter).second; @@ -74,9 +77,10 @@ namespace skyline::service { SERVICE_CASE(nvdrv::INvDrvServices, "nvdrv:a") SERVICE_CASE(nvdrv::INvDrvServices, "nvdrv:s") SERVICE_CASE(nvdrv::INvDrvServices, "nvdrv:t") + SERVICE_CASE(hosbinder::IHOSBinderDriver, "dispdrv") + SERVICE_CASE(visrv::IApplicationRootService, "vi:u") + SERVICE_CASE(visrv::ISystemRootService, "vi:s") SERVICE_CASE(visrv::IManagerRootService, "vi:m") - SERVICE_CASE(visrv::IManagerRootService, "vi:u") - SERVICE_CASE(visrv::IManagerRootService, "vi:s") SERVICE_CASE(pl::IPlatformServiceManager, "pl:u") SERVICE_CASE(aocsrv::IAddOnContentManager, "aoc:u") SERVICE_CASE(pctl::IParentalControlServiceFactory, "pctl") @@ -100,7 +104,7 @@ namespace skyline::service { std::shared_ptr ServiceManager::NewService(ServiceName name, type::KSession &session, ipc::IpcResponse &response) { std::lock_guard serviceGuard(mutex); - auto serviceObject{CreateService(name)}; + auto serviceObject{CreateOrGetService(name)}; KHandle handle{}; if (session.isDomain) { session.domains.push_back(serviceObject); diff --git a/app/src/main/cpp/skyline/services/serviceman.h b/app/src/main/cpp/skyline/services/serviceman.h index f6e74c54..0690b0a9 100644 --- a/app/src/main/cpp/skyline/services/serviceman.h +++ b/app/src/main/cpp/skyline/services/serviceman.h @@ -21,13 +21,6 @@ namespace skyline::service { std::unordered_map> serviceMap; //!< A mapping from a Service to the underlying object std::mutex mutex; //!< Synchronizes concurrent access to services to prevent crashes - /** - * @brief Creates an instance of the service if it doesn't already exist, otherwise returns an existing instance - * @param name The name of the service to create - * @return A shared pointer to an instance of the service - */ - std::shared_ptr CreateService(ServiceName name); - public: std::shared_ptr smUserInterface; //!< Used by applications to open connections to services std::shared_ptr globalServiceState; @@ -58,19 +51,13 @@ namespace skyline::service { } /** - * @param serviceType The type of the service - * @tparam The class of the service - * @return A shared pointer to an instance of the service - * @note This only works for services created with `NewService` as sub-interfaces used with `RegisterService` can have multiple instances + * @brief Creates an instance of the service if it doesn't already exist, otherwise returns an existing instance */ - template - std::shared_ptr GetService(ServiceName name) { - return std::static_pointer_cast(serviceMap.at(name)); - } + std::shared_ptr CreateOrGetService(ServiceName name); template - constexpr std::shared_ptr GetService(std::string_view name) { - return GetService(util::MakeMagic(name)); + constexpr std::shared_ptr CreateOrGetService(std::string_view name) { + return std::static_pointer_cast(CreateOrGetService(util::MakeMagic(name))); } /** diff --git a/app/src/main/cpp/skyline/services/visrv/IApplicationDisplayService.cpp b/app/src/main/cpp/skyline/services/visrv/IApplicationDisplayService.cpp index 4a7a9ab2..86562a74 100644 --- a/app/src/main/cpp/skyline/services/visrv/IApplicationDisplayService.cpp +++ b/app/src/main/cpp/skyline/services/visrv/IApplicationDisplayService.cpp @@ -3,101 +3,85 @@ #include #include +#include #include -#include #include "IApplicationDisplayService.h" #include "ISystemDisplayService.h" #include "IManagerDisplayService.h" +#include "results.h" namespace skyline::service::visrv { - IApplicationDisplayService::IApplicationDisplayService(const DeviceState &state, ServiceManager &manager) : IDisplayService(state, manager) {} + IApplicationDisplayService::IApplicationDisplayService(const DeviceState &state, ServiceManager &manager, PrivilegeLevel level) : level(level), IDisplayService(state, manager) {} Result IApplicationDisplayService::GetRelayService(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { - manager.RegisterService(SRVREG(hosbinder::IHOSBinderDriver), session, response); + manager.RegisterService(hosbinder, session, response); return {}; } Result IApplicationDisplayService::GetIndirectDisplayTransactionService(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { - manager.RegisterService(SRVREG(hosbinder::IHOSBinderDriver), session, response); + if (level < PrivilegeLevel::System) + return result::IllegalOperation; + manager.RegisterService(hosbinder, session, response); return {}; } Result IApplicationDisplayService::GetSystemDisplayService(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { + if (level < PrivilegeLevel::System) + return result::IllegalOperation; manager.RegisterService(SRVREG(ISystemDisplayService), session, response); return {}; } Result IApplicationDisplayService::GetManagerDisplayService(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { + if (level < PrivilegeLevel::Manager) + return result::IllegalOperation; manager.RegisterService(SRVREG(IManagerDisplayService), session, response); return {}; } Result IApplicationDisplayService::OpenDisplay(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { - std::string displayName(request.PopString()); - state.logger->Debug("Setting display as: {}", displayName); - - auto producer{hosbinder::producer.lock()}; - producer->SetDisplay(displayName); - - response.Push(0); // There's only one display + auto displayName(request.PopString()); + state.logger->Debug("Opening display: {}", displayName); + response.Push(hosbinder->OpenDisplay(displayName)); return {}; } Result IApplicationDisplayService::CloseDisplay(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { - state.logger->Debug("Closing the display"); - auto producer{hosbinder::producer.lock()}; - producer->CloseDisplay(); + auto displayId{request.Pop()}; + state.logger->Debug("Closing display: {}", hosbinder::ToString(displayId)); + hosbinder->CloseDisplay(displayId); return {}; } Result IApplicationDisplayService::OpenLayer(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { - struct InputStruct { - char displayName[0x40]; - u64 layerId; - u64 userId; - } input = request.Pop(); - state.logger->Debug("Opening Layer: Display Name: {}, Layer ID: {}, User ID: {}", input.displayName, input.layerId, input.userId); - - std::string name(input.displayName); - - Parcel parcel(state); - LayerParcel data{ - .type = 0x2, - .pid = 0, - .bufferId = 0, // As we only have one layer and buffer - .string = "dispdrv" - }; - parcel.Push(data); - parcel.objects.resize(4); + auto displayName{request.PopString(0x40)}; + auto layerId{request.Pop()}; + state.logger->Debug("Opening layer #{} on display: {}", layerId, displayName); + auto displayId{hosbinder->OpenDisplay(displayName)}; + auto parcel{hosbinder->OpenLayer(displayId, layerId)}; response.Push(parcel.WriteParcel(request.outputBuf.at(0))); + return {}; } Result IApplicationDisplayService::CloseLayer(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { u64 layerId{request.Pop()}; - state.logger->Debug("Closing Layer: {}", layerId); - - auto producer{hosbinder::producer.lock()}; - if (producer->layerStatus == hosbinder::LayerStatus::Uninitialized) - state.logger->Warn("The application is destroying an uninitialized layer"); - producer->layerStatus = hosbinder::LayerStatus::Uninitialized; - + state.logger->Debug("Closing layer #{}", layerId); + hosbinder->CloseLayer(layerId); return {}; } Result IApplicationDisplayService::SetLayerScalingMode(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { auto scalingMode{request.Pop()}; auto layerId{request.Pop()}; - state.logger->Debug("Setting Layer Scaling mode to '{}' for layer {}", scalingMode, layerId); return {}; } Result IApplicationDisplayService::GetDisplayVsyncEvent(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { KHandle handle{state.process->InsertItem(state.gpu->presentation.vsyncEvent)}; - state.logger->Debug("VSync Event Handle: 0x{:X}", handle); - + state.logger->Debug("V-Sync Event Handle: 0x{:X}", handle); response.copyHandles.push_back(handle); return {}; } diff --git a/app/src/main/cpp/skyline/services/visrv/IApplicationDisplayService.h b/app/src/main/cpp/skyline/services/visrv/IApplicationDisplayService.h index a6313a41..da567c8e 100644 --- a/app/src/main/cpp/skyline/services/visrv/IApplicationDisplayService.h +++ b/app/src/main/cpp/skyline/services/visrv/IApplicationDisplayService.h @@ -4,6 +4,7 @@ #pragma once #include "IDisplayService.h" +#include "IRootService.h" namespace skyline::service::visrv { /** @@ -11,8 +12,11 @@ namespace skyline::service::visrv { * @url https://switchbrew.org/wiki/Display_services#IApplicationDisplayService */ class IApplicationDisplayService : public IDisplayService { + private: + PrivilegeLevel level; + public: - IApplicationDisplayService(const DeviceState &state, ServiceManager &manager); + IApplicationDisplayService(const DeviceState &state, ServiceManager &manager, PrivilegeLevel level); /** * @brief Returns an handle to the 'nvnflinger' service @@ -74,19 +78,19 @@ namespace skyline::service::visrv { */ Result GetDisplayVsyncEvent(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response); - SERVICE_DECL( - SFUNC(0x64, IApplicationDisplayService, GetRelayService), - SFUNC(0x65, IApplicationDisplayService, GetSystemDisplayService), - SFUNC(0x66, IApplicationDisplayService, GetManagerDisplayService), - SFUNC(0x67, IApplicationDisplayService, GetIndirectDisplayTransactionService), - SFUNC(0x3F2, IApplicationDisplayService, OpenDisplay), - SFUNC(0x3FC, IApplicationDisplayService, CloseDisplay), - SFUNC(0x7E4, IApplicationDisplayService, OpenLayer), - SFUNC(0x7E5, IApplicationDisplayService, CloseLayer), - SFUNC_BASE(0x7EE, IApplicationDisplayService, IDisplayService, CreateStrayLayer), - SFUNC_BASE(0x7EF, IApplicationDisplayService, IDisplayService, DestroyStrayLayer), - SFUNC(0x835, IApplicationDisplayService, SetLayerScalingMode), - SFUNC(0x1452, IApplicationDisplayService, GetDisplayVsyncEvent) - ) + SERVICE_DECL( + SFUNC(0x64, IApplicationDisplayService, GetRelayService), + SFUNC(0x65, IApplicationDisplayService, GetSystemDisplayService), + SFUNC(0x66, IApplicationDisplayService, GetManagerDisplayService), + SFUNC(0x67, IApplicationDisplayService, GetIndirectDisplayTransactionService), + SFUNC(0x3F2, IApplicationDisplayService, OpenDisplay), + SFUNC(0x3FC, IApplicationDisplayService, CloseDisplay), + SFUNC(0x7E4, IApplicationDisplayService, OpenLayer), + SFUNC(0x7E5, IApplicationDisplayService, CloseLayer), + SFUNC_BASE(0x7EE, IApplicationDisplayService, IDisplayService, CreateStrayLayer), + SFUNC_BASE(0x7EF, IApplicationDisplayService, IDisplayService, DestroyStrayLayer), + SFUNC(0x835, IApplicationDisplayService, SetLayerScalingMode), + SFUNC(0x1452, IApplicationDisplayService, GetDisplayVsyncEvent) + ) }; } diff --git a/app/src/main/cpp/skyline/services/visrv/IApplicationRootService.h b/app/src/main/cpp/skyline/services/visrv/IApplicationRootService.h new file mode 100644 index 00000000..d4ee4b25 --- /dev/null +++ b/app/src/main/cpp/skyline/services/visrv/IApplicationRootService.h @@ -0,0 +1,20 @@ +// SPDX-License-Identifier: MPL-2.0 +// Copyright © 2021 Skyline Team and Contributors (https://github.com/skyline-emu/) + +#pragma once + +#include "IRootService.h" + +namespace skyline::service::visrv { + /** + * @url https://switchbrew.org/wiki/Display_services#vi:u + */ + class IApplicationRootService : public IRootService { + public: + IApplicationRootService(const DeviceState &state, ServiceManager &manager) : IRootService(state, manager, PrivilegeLevel::Application) {} + + SERVICE_DECL( + SFUNC_BASE(0x0, IApplicationRootService, IRootService, GetDisplayService) + ) + }; +} diff --git a/app/src/main/cpp/skyline/services/visrv/IDisplayService.cpp b/app/src/main/cpp/skyline/services/visrv/IDisplayService.cpp index 6d6b0e31..0873f0e1 100644 --- a/app/src/main/cpp/skyline/services/visrv/IDisplayService.cpp +++ b/app/src/main/cpp/skyline/services/visrv/IDisplayService.cpp @@ -1,46 +1,33 @@ // SPDX-License-Identifier: MPL-2.0 // Copyright © 2020 Skyline Team and Contributors (https://github.com/skyline-emu/) -#include +#include +#include #include "IDisplayService.h" namespace skyline::service::visrv { - IDisplayService::IDisplayService(const DeviceState &state, ServiceManager &manager) : BaseService(state, manager) {} + IDisplayService::IDisplayService(const DeviceState &state, ServiceManager &manager) : hosbinder(manager.CreateOrGetService("dispdrv")), BaseService(state, manager) {} Result IDisplayService::CreateStrayLayer(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { - request.Skip(); - auto displayId{request.Pop()}; + request.Skip(); // VI Layer flags + auto displayId{request.Pop()}; - state.logger->Debug("Creating Stray Layer on Display: {}", displayId); + auto layerId{hosbinder->CreateLayer(displayId)}; + response.Push(layerId); - auto producer{hosbinder::producer.lock()}; - if (producer->layerStatus == hosbinder::LayerStatus::Stray) - throw exception("The application is creating more than one stray layer"); - producer->layerStatus = hosbinder::LayerStatus::Stray; - - response.Push(0); // There's only one layer - - Parcel parcel(state); - LayerParcel data{ - .type = 0x2, - .pid = 0, - .bufferId = 0, // As we only have one layer and buffer - .string = "dispdrv" - }; - parcel.Push(data); + state.logger->Debug("Creating Stray Layer #{} on Display: {}", layerId, hosbinder::ToString(displayId)); + auto parcel{hosbinder->OpenLayer(displayId, layerId)}; response.Push(parcel.WriteParcel(request.outputBuf.at(0))); + return {}; } Result IDisplayService::DestroyStrayLayer(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { auto layerId{request.Pop()}; - state.logger->Debug("Destroying Stray Layer: {}", layerId); + state.logger->Debug("Destroying Stray Layer #{}", layerId); - auto producer{hosbinder::producer.lock()}; - if (producer->layerStatus == hosbinder::LayerStatus::Uninitialized) - state.logger->Warn("The application is destroying an uninitialized layer"); - producer->layerStatus = hosbinder::LayerStatus::Uninitialized; + hosbinder->CloseLayer(layerId); return {}; } diff --git a/app/src/main/cpp/skyline/services/visrv/IDisplayService.h b/app/src/main/cpp/skyline/services/visrv/IDisplayService.h index c16856dd..608bbfe6 100644 --- a/app/src/main/cpp/skyline/services/visrv/IDisplayService.h +++ b/app/src/main/cpp/skyline/services/visrv/IDisplayService.h @@ -3,7 +3,11 @@ #pragma once -#include +#include + +namespace skyline::service::hosbinder { + class IHOSBinderDriver; +} namespace skyline::service::visrv { /** @@ -11,18 +15,7 @@ namespace skyline::service::visrv { */ class IDisplayService : public BaseService { protected: - /** - * @brief This is the parcel used in OpenLayer/CreateStrayLayer - */ - struct LayerParcel { - u32 type; //!< The type of the layer - u32 pid; //!< The PID that the layer belongs to - u32 bufferId; //!< The buffer ID of the layer - u32 _pad0_[3]; - u8 string[0x8]; //!< "dispdrv" - u64 _pad1_; - }; - static_assert(sizeof(LayerParcel) == 0x28); + std::shared_ptr hosbinder; //!< The IHOSBinder relayed via this display class public: IDisplayService(const DeviceState &state, ServiceManager &manager); diff --git a/app/src/main/cpp/skyline/services/visrv/IManagerDisplayService.cpp b/app/src/main/cpp/skyline/services/visrv/IManagerDisplayService.cpp index 15e6a0c2..0d47787d 100644 --- a/app/src/main/cpp/skyline/services/visrv/IManagerDisplayService.cpp +++ b/app/src/main/cpp/skyline/services/visrv/IManagerDisplayService.cpp @@ -1,35 +1,27 @@ // SPDX-License-Identifier: MPL-2.0 // Copyright © 2020 Skyline Team and Contributors (https://github.com/skyline-emu/) -#include +#include #include "IManagerDisplayService.h" namespace skyline::service::visrv { IManagerDisplayService::IManagerDisplayService(const DeviceState &state, ServiceManager &manager) : IDisplayService(state, manager) {} Result IManagerDisplayService::CreateManagedLayer(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { - request.Skip(); - auto displayId{request.Pop()}; - state.logger->Debug("Creating Managed Layer on Display: {}", displayId); + request.Skip(); // VI Layer flags + auto displayId{request.Pop()}; - auto producer{hosbinder::producer.lock()}; - if (producer->layerStatus != hosbinder::LayerStatus::Uninitialized) - throw exception("The application is creating more than one layer"); - producer->layerStatus = hosbinder::LayerStatus::Managed; + auto layerId{hosbinder->CreateLayer(displayId)}; + state.logger->Debug("Creating Managed Layer #{} on Display: {}", layerId, hosbinder::ToString(displayId)); + response.Push(layerId); - response.Push(0); // There's only one layer return {}; } Result IManagerDisplayService::DestroyManagedLayer(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { auto layerId{request.Pop()}; - state.logger->Debug("Destroying Managed Layer: {}", layerId); - - auto producer{hosbinder::producer.lock()}; - if (producer->layerStatus == hosbinder::LayerStatus::Uninitialized) - state.logger->Warn("The application is destroying an uninitialized layer"); - producer->layerStatus = hosbinder::LayerStatus::Uninitialized; - + state.logger->Debug("Destroying Managed Layer #{}", layerId); + hosbinder->DestroyLayer(layerId); return {}; } diff --git a/app/src/main/cpp/skyline/services/visrv/IManagerRootService.cpp b/app/src/main/cpp/skyline/services/visrv/IManagerRootService.cpp deleted file mode 100644 index 54cd4ffa..00000000 --- a/app/src/main/cpp/skyline/services/visrv/IManagerRootService.cpp +++ /dev/null @@ -1,14 +0,0 @@ -// SPDX-License-Identifier: MPL-2.0 -// Copyright © 2020 Skyline Team and Contributors (https://github.com/skyline-emu/) - -#include "IManagerRootService.h" -#include "IApplicationDisplayService.h" - -namespace skyline::service::visrv { - IManagerRootService::IManagerRootService(const DeviceState &state, ServiceManager &manager) : BaseService(state, manager) {} - - Result IManagerRootService::GetDisplayService(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { - manager.RegisterService(SRVREG(IApplicationDisplayService), session, response); - return {}; - } -} diff --git a/app/src/main/cpp/skyline/services/visrv/IManagerRootService.h b/app/src/main/cpp/skyline/services/visrv/IManagerRootService.h index a4e6f432..482f8d45 100644 --- a/app/src/main/cpp/skyline/services/visrv/IManagerRootService.h +++ b/app/src/main/cpp/skyline/services/visrv/IManagerRootService.h @@ -3,26 +3,18 @@ #pragma once -#include -#include +#include "IRootService.h" namespace skyline::service::visrv { /** - * @brief This service is used to get an handle to #IApplicationDisplayService * @url https://switchbrew.org/wiki/Display_services#vi:m */ - class IManagerRootService : public BaseService { + class IManagerRootService : public IRootService { public: - IManagerRootService(const DeviceState &state, ServiceManager &manager); + IManagerRootService(const DeviceState &state, ServiceManager &manager) : IRootService(state, manager, PrivilegeLevel::Manager) {} - /** - * @brief Returns an handle to #IApplicationDisplayService - * @url https://switchbrew.org/wiki/Display_services#GetDisplayService - */ - Result GetDisplayService(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response); - - SERVICE_DECL( - SFUNC(0x2, IManagerRootService, GetDisplayService) - ) + SERVICE_DECL( + SFUNC_BASE(0x2, IManagerRootService, IRootService, GetDisplayService) + ) }; } diff --git a/app/src/main/cpp/skyline/services/visrv/IRootService.cpp b/app/src/main/cpp/skyline/services/visrv/IRootService.cpp new file mode 100644 index 00000000..3289f780 --- /dev/null +++ b/app/src/main/cpp/skyline/services/visrv/IRootService.cpp @@ -0,0 +1,19 @@ +// SPDX-License-Identifier: MPL-2.0 +// Copyright © 2021 Skyline Team and Contributors (https://github.com/skyline-emu/) + +#include +#include "IRootService.h" +#include "IApplicationDisplayService.h" +#include "results.h" + +namespace skyline::service::visrv { + IRootService::IRootService(const DeviceState &state, ServiceManager &manager, PrivilegeLevel level) : level(level), BaseService(state, manager) {} + + Result IRootService::GetDisplayService(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { + auto requestedPrivileges{request.Pop()}; //!< A boolean indicating if the returned service should have higher privileges or not + if (requestedPrivileges && level < PrivilegeLevel::System) + return result::IllegalOperation; + manager.RegisterService(SRVREG(IApplicationDisplayService, level), session, response); + return {}; + } +} diff --git a/app/src/main/cpp/skyline/services/visrv/IRootService.h b/app/src/main/cpp/skyline/services/visrv/IRootService.h new file mode 100644 index 00000000..51d3e9b9 --- /dev/null +++ b/app/src/main/cpp/skyline/services/visrv/IRootService.h @@ -0,0 +1,37 @@ +// SPDX-License-Identifier: MPL-2.0 +// Copyright © 2021 Skyline Team and Contributors (https://github.com/skyline-emu/) + +#pragma once + +#include + +namespace skyline::service::visrv { + /** + * @brief All privilege-based variants that a single service can have + */ + enum class PrivilegeLevel { + Application, //!< The service used by user applications (Lowest) + System, //!< The service used by system applications (Higher) + Manager, //!< The service used by system services internally (Highest) + }; + + /** + * @brief Manages allocation of VI to display services + * @url https://switchbrew.org/wiki/Display_services#vi:u + * @url https://switchbrew.org/wiki/Display_services#vi:s + * @url https://switchbrew.org/wiki/Display_services#vi:m + */ + class IRootService : public BaseService { + private: + PrivilegeLevel level; + + public: + IRootService(const DeviceState &state, ServiceManager &manager, PrivilegeLevel level); + + /** + * @brief Returns an handle to #IApplicationDisplayService + * @url https://switchbrew.org/wiki/Display_services#GetDisplayService + */ + Result GetDisplayService(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response); + }; +} diff --git a/app/src/main/cpp/skyline/services/visrv/ISystemRootService.h b/app/src/main/cpp/skyline/services/visrv/ISystemRootService.h new file mode 100644 index 00000000..08a8aa68 --- /dev/null +++ b/app/src/main/cpp/skyline/services/visrv/ISystemRootService.h @@ -0,0 +1,20 @@ +// SPDX-License-Identifier: MPL-2.0 +// Copyright © 2021 Skyline Team and Contributors (https://github.com/skyline-emu/) + +#pragma once + +#include "IRootService.h" + +namespace skyline::service::visrv { + /** + * @url https://switchbrew.org/wiki/Display_services#vi:s + */ + class ISystemRootService : public IRootService { + public: + ISystemRootService(const DeviceState &state, ServiceManager &manager) : IRootService(state, manager, PrivilegeLevel::System) {} + + SERVICE_DECL( + SFUNC_BASE(0x3, ISystemRootService, IRootService, GetDisplayService) + ) + }; +} diff --git a/app/src/main/cpp/skyline/services/visrv/results.h b/app/src/main/cpp/skyline/services/visrv/results.h new file mode 100644 index 00000000..9dcd28fd --- /dev/null +++ b/app/src/main/cpp/skyline/services/visrv/results.h @@ -0,0 +1,10 @@ +// SPDX-License-Identifier: MPL-2.0 +// Copyright © 2021 Skyline Team and Contributors (https://github.com/skyline-emu/) + +#pragma once + +#include + +namespace skyline::service::visrv::result { + constexpr Result IllegalOperation(114, 6); +}