From 9d2d349d7b0d30784b13260844deec500b5a50c8 Mon Sep 17 00:00:00 2001 From: Zach Hilman Date: Wed, 5 Jun 2019 12:10:23 -0400 Subject: [PATCH 01/12] applets: Implement Auth applet backend This is responsible for parental controls and supports verifying, changing, and registering PIN codes. --- .../service/am/applets/general_backend.cpp | 116 ++++++++++++++++++ .../hle/service/am/applets/general_backend.h | 30 +++++ 2 files changed, 146 insertions(+) diff --git a/src/core/hle/service/am/applets/general_backend.cpp b/src/core/hle/service/am/applets/general_backend.cpp index 54c155dd8e..e0def8dffd 100644 --- a/src/core/hle/service/am/applets/general_backend.cpp +++ b/src/core/hle/service/am/applets/general_backend.cpp @@ -17,6 +17,8 @@ namespace Service::AM::Applets { +constexpr ResultCode ERROR_INVALID_PIN{ErrorModule::PCTL, 221}; + static void LogCurrentStorage(AppletDataBroker& broker, std::string_view prefix) { std::unique_ptr storage = broker.PopNormalDataToApplet(); for (; storage != nullptr; storage = broker.PopNormalDataToApplet()) { @@ -35,6 +37,120 @@ static void LogCurrentStorage(AppletDataBroker& broker, std::string_view prefix) } } +Auth::Auth(Core::Frontend::ParentalControlsApplet& frontend) : frontend(frontend) {} + +Auth::~Auth() = default; + +void Auth::Initialize() { + Applet::Initialize(); + complete = false; + + const auto storage = broker.PopNormalDataToApplet(); + ASSERT(storage != nullptr); + const auto data = storage->GetData(); + ASSERT(data.size() >= 0xC); + + struct Arg { + INSERT_PADDING_BYTES(4); + AuthAppletType type; + u8 arg0; + u8 arg1; + u8 arg2; + INSERT_PADDING_BYTES(1); + }; + static_assert(sizeof(Arg) == 0xC, "Arg (AuthApplet) has incorrect size."); + + Arg arg{}; + std::memcpy(&arg, data.data(), sizeof(Arg)); + + type = arg.type; + arg0 = arg.arg0; + arg1 = arg.arg1; + arg2 = arg.arg2; +} + +bool Auth::TransactionComplete() const { + return complete; +} + +ResultCode Auth::GetStatus() const { + return successful ? RESULT_SUCCESS : ERROR_INVALID_PIN; +} + +void Auth::ExecuteInteractive() { + UNREACHABLE_MSG("Unexpected interactive applet data."); +} + +void Auth::Execute() { + if (complete) { + return; + } + + const auto unimplemented_log = [this] { + UNIMPLEMENTED_MSG("Unimplemented Auth applet type for type={:08X}, arg0={:02X}, " + "arg1={:02X}, arg2={:02X}", + static_cast(type), arg0, arg1, arg2); + }; + + switch (type) { + case AuthAppletType::ShowParentalAuthentication: { + const auto callback = [this](bool successful) { AuthFinished(successful); }; + + if (arg0 == 1 && arg1 == 0 && arg2 == 1) { + // ShowAuthenticatorForConfiguration + frontend.VerifyPINForSettings(callback); + } else if (arg1 == 0 && arg2 == 0) { + // ShowParentalAuthentication(bool) + frontend.VerifyPIN(callback, static_cast(arg0)); + } else { + unimplemented_log(); + } + break; + } + case AuthAppletType::RegisterParentalPasscode: { + const auto callback = [this] { AuthFinished(true); }; + + if (arg0 == 0 && arg1 == 0 && arg2 == 0) { + // RegisterParentalPasscode + frontend.RegisterPIN(callback); + } else { + unimplemented_log(); + } + break; + } + case AuthAppletType::ChangeParentalPasscode: { + const auto callback = [this] { AuthFinished(true); }; + + if (arg0 == 0 && arg1 == 0 && arg2 == 0) { + // ChangeParentalPasscode + frontend.ChangePIN(callback); + } else { + unimplemented_log(); + } + break; + } + default: + unimplemented_log(); + } +} + +void Auth::AuthFinished(bool successful) { + this->successful = successful; + + struct Return { + ResultCode result_code; + }; + static_assert(sizeof(Return) == 0x4, "Return (AuthApplet) has incorrect size."); + + Return return_{GetStatus()}; + + std::vector out(sizeof(Return)); + std::memcpy(out.data(), &return_, sizeof(Return)); + + broker.PushNormalDataFromApplet(IStorage{out}); + broker.SignalStateChanged(); +} + PhotoViewer::PhotoViewer(const Core::Frontend::PhotoViewerApplet& frontend) : frontend(frontend) {} PhotoViewer::~PhotoViewer() = default; diff --git a/src/core/hle/service/am/applets/general_backend.h b/src/core/hle/service/am/applets/general_backend.h index fb68a2543e..0da252044b 100644 --- a/src/core/hle/service/am/applets/general_backend.h +++ b/src/core/hle/service/am/applets/general_backend.h @@ -8,6 +8,36 @@ namespace Service::AM::Applets { +enum class AuthAppletType : u32 { + ShowParentalAuthentication, + RegisterParentalPasscode, + ChangeParentalPasscode, +}; + +class Auth final : public Applet { +public: + explicit Auth(Core::Frontend::ParentalControlsApplet& frontend); + ~Auth() override; + + void Initialize() override; + bool TransactionComplete() const override; + ResultCode GetStatus() const override; + void ExecuteInteractive() override; + void Execute() override; + + void AuthFinished(bool successful = true); + +private: + Core::Frontend::ParentalControlsApplet& frontend; + bool complete = false; + bool successful = false; + + AuthAppletType type = AuthAppletType::ShowParentalAuthentication; + u8 arg0 = 0; + u8 arg1 = 0; + u8 arg2 = 0; +}; + enum class PhotoViewerAppletMode : u8 { CurrentApp = 0, AllApps = 1, From c96450f6e248ce0cd8dc69d91c691e70ede984e0 Mon Sep 17 00:00:00 2001 From: Zach Hilman Date: Wed, 5 Jun 2019 12:11:24 -0400 Subject: [PATCH 02/12] frontend: Add base class and default impl of parent controls applet frontend --- .../frontend/applets/general_frontend.cpp | 31 ++++++++++++++++++- src/core/frontend/applets/general_frontend.h | 22 +++++++++++++ 2 files changed, 52 insertions(+), 1 deletion(-) diff --git a/src/core/frontend/applets/general_frontend.cpp b/src/core/frontend/applets/general_frontend.cpp index b974f22895..7483ffb763 100644 --- a/src/core/frontend/applets/general_frontend.cpp +++ b/src/core/frontend/applets/general_frontend.cpp @@ -7,9 +7,38 @@ namespace Core::Frontend { +ParentalControlsApplet::~ParentalControlsApplet() = default; + +DefaultParentalControlsApplet::~DefaultParentalControlsApplet() = default; + +void DefaultParentalControlsApplet::VerifyPIN(std::function finished, + bool suspend_future_verification_temporarily) { + LOG_INFO(Service_AM, + "Application requested frontend to verify PIN (normal), " + "suspend_future_verification_temporarily={}, verifying as correct.", + suspend_future_verification_temporarily); + finished(true); +} + +void DefaultParentalControlsApplet::VerifyPINForSettings(std::function finished) { + LOG_INFO(Service_AM, + "Application requested frontend to verify PIN (settings), verifying as correct."); + finished(true); +} + +void DefaultParentalControlsApplet::RegisterPIN(std::function finished) { + LOG_INFO(Service_AM, "Application requested frontend to register new PIN"); + finished(); +} + +void DefaultParentalControlsApplet::ChangePIN(std::function finished) { + LOG_INFO(Service_AM, "Application requested frontend to change PIN to new value"); + finished(); +} + PhotoViewerApplet::~PhotoViewerApplet() = default; -DefaultPhotoViewerApplet::~DefaultPhotoViewerApplet() {} +DefaultPhotoViewerApplet::~DefaultPhotoViewerApplet() = default; void DefaultPhotoViewerApplet::ShowPhotosForApplication(u64 title_id, std::function finished) const { diff --git a/src/core/frontend/applets/general_frontend.h b/src/core/frontend/applets/general_frontend.h index d4506c9990..48e3ce6513 100644 --- a/src/core/frontend/applets/general_frontend.h +++ b/src/core/frontend/applets/general_frontend.h @@ -9,6 +9,28 @@ namespace Core::Frontend { +class ParentalControlsApplet { +public: + virtual ~ParentalControlsApplet(); + + virtual void VerifyPIN(std::function finished, + bool suspend_future_verification_temporarily) = 0; + virtual void VerifyPINForSettings(std::function finished) = 0; + virtual void RegisterPIN(std::function finished) = 0; + virtual void ChangePIN(std::function finished) = 0; +}; + +class DefaultParentalControlsApplet final : public ParentalControlsApplet { +public: + ~DefaultParentalControlsApplet() override; + + void VerifyPIN(std::function finished, + bool suspend_future_verification_temporarily) override; + void VerifyPINForSettings(std::function finished) override; + void RegisterPIN(std::function finished) override; + void ChangePIN(std::function finished) override; +}; + class PhotoViewerApplet { public: virtual ~PhotoViewerApplet(); From 6ff90082306c3bb5341c0ac2bc3beeb4177dc8a4 Mon Sep 17 00:00:00 2001 From: Zach Hilman Date: Wed, 5 Jun 2019 12:13:15 -0400 Subject: [PATCH 03/12] web_browser: Rename OpenPage to OpenPageLocal This is more representative of what actually occurs, as web does support remote URLs which wouldn't need a romfs callback. This paves for easy future support of this with a call like 'OpenPageRemote' or similar. --- src/core/frontend/applets/web_browser.cpp | 6 +++--- src/core/frontend/applets/web_browser.h | 8 ++++---- src/yuzu/applets/web_browser.cpp | 4 ++-- src/yuzu/applets/web_browser.h | 4 ++-- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/core/frontend/applets/web_browser.cpp b/src/core/frontend/applets/web_browser.cpp index 3a3d3d0bf5..528295ffcd 100644 --- a/src/core/frontend/applets/web_browser.cpp +++ b/src/core/frontend/applets/web_browser.cpp @@ -11,9 +11,9 @@ WebBrowserApplet::~WebBrowserApplet() = default; DefaultWebBrowserApplet::~DefaultWebBrowserApplet() = default; -void DefaultWebBrowserApplet::OpenPage(std::string_view filename, - std::function unpack_romfs_callback, - std::function finished_callback) { +void DefaultWebBrowserApplet::OpenPageLocal(std::string_view filename, + std::function unpack_romfs_callback, + std::function finished_callback) { LOG_INFO(Service_AM, "(STUBBED) called - No suitable web browser implementation found to open website page " "at '{}'!", diff --git a/src/core/frontend/applets/web_browser.h b/src/core/frontend/applets/web_browser.h index f952856af1..110e33bc49 100644 --- a/src/core/frontend/applets/web_browser.h +++ b/src/core/frontend/applets/web_browser.h @@ -13,16 +13,16 @@ class WebBrowserApplet { public: virtual ~WebBrowserApplet(); - virtual void OpenPage(std::string_view url, std::function unpack_romfs_callback, - std::function finished_callback) = 0; + virtual void OpenPageLocal(std::string_view url, std::function unpack_romfs_callback, + std::function finished_callback) = 0; }; class DefaultWebBrowserApplet final : public WebBrowserApplet { public: ~DefaultWebBrowserApplet() override; - void OpenPage(std::string_view url, std::function unpack_romfs_callback, - std::function finished_callback) override; + void OpenPageLocal(std::string_view url, std::function unpack_romfs_callback, + std::function finished_callback) override; }; } // namespace Core::Frontend diff --git a/src/yuzu/applets/web_browser.cpp b/src/yuzu/applets/web_browser.cpp index ac80b2fa20..33f1c385d1 100644 --- a/src/yuzu/applets/web_browser.cpp +++ b/src/yuzu/applets/web_browser.cpp @@ -87,8 +87,8 @@ QtWebBrowser::QtWebBrowser(GMainWindow& main_window) { QtWebBrowser::~QtWebBrowser() = default; -void QtWebBrowser::OpenPage(std::string_view url, std::function unpack_romfs_callback, - std::function finished_callback) { +void QtWebBrowser::OpenPageLocal(std::string_view url, std::function unpack_romfs_callback, + std::function finished_callback) { this->unpack_romfs_callback = std::move(unpack_romfs_callback); this->finished_callback = std::move(finished_callback); diff --git a/src/yuzu/applets/web_browser.h b/src/yuzu/applets/web_browser.h index 1a3d67353f..b38437e460 100644 --- a/src/yuzu/applets/web_browser.h +++ b/src/yuzu/applets/web_browser.h @@ -37,8 +37,8 @@ public: explicit QtWebBrowser(GMainWindow& main_window); ~QtWebBrowser() override; - void OpenPage(std::string_view url, std::function unpack_romfs_callback, - std::function finished_callback) override; + void OpenPageLocal(std::string_view url, std::function unpack_romfs_callback, + std::function finished_callback) override; signals: void MainWindowOpenPage(std::string_view filename, std::string_view additional_args) const; From e447d8aafa4e49bbd7a06945b4653bc43141f423 Mon Sep 17 00:00:00 2001 From: Zach Hilman Date: Wed, 5 Jun 2019 12:13:59 -0400 Subject: [PATCH 04/12] applets: Track ECommerce and Parental Control applet frontends --- src/core/hle/service/am/applets/applets.cpp | 24 ++++++++++++++++----- src/core/hle/service/am/applets/applets.h | 12 +++++++++-- 2 files changed, 29 insertions(+), 7 deletions(-) diff --git a/src/core/hle/service/am/applets/applets.cpp b/src/core/hle/service/am/applets/applets.cpp index e3e4ead03f..5532061779 100644 --- a/src/core/hle/service/am/applets/applets.cpp +++ b/src/core/hle/service/am/applets/applets.cpp @@ -157,6 +157,8 @@ AppletManager::AppletManager() = default; AppletManager::~AppletManager() = default; void AppletManager::SetAppletFrontendSet(AppletFrontendSet set) { + if (set.parental_controls != nullptr) + frontend.parental_controls = std::move(set.parental_controls); if (set.error != nullptr) frontend.error = std::move(set.error); if (set.photo_viewer != nullptr) @@ -167,17 +169,21 @@ void AppletManager::SetAppletFrontendSet(AppletFrontendSet set) { frontend.software_keyboard = std::move(set.software_keyboard); if (set.web_browser != nullptr) frontend.web_browser = std::move(set.web_browser); + if (set.e_commerce != nullptr) + frontend.e_commerce = std::move(set.e_commerce); } void AppletManager::SetDefaultAppletFrontendSet() { - frontend.error = std::make_unique(); - frontend.photo_viewer = std::make_unique(); - frontend.profile_select = std::make_unique(); - frontend.software_keyboard = std::make_unique(); - frontend.web_browser = std::make_unique(); + ClearAll(); + SetDefaultAppletsIfMissing(); } void AppletManager::SetDefaultAppletsIfMissing() { + if (frontend.parental_controls == nullptr) { + frontend.parental_controls = + std::make_unique(); + } + if (frontend.error == nullptr) { frontend.error = std::make_unique(); } @@ -198,6 +204,10 @@ void AppletManager::SetDefaultAppletsIfMissing() { if (frontend.web_browser == nullptr) { frontend.web_browser = std::make_unique(); } + + if (frontend.e_commerce == nullptr) { + frontend.e_commerce = std::make_unique(); + } } void AppletManager::ClearAll() { @@ -206,6 +216,8 @@ void AppletManager::ClearAll() { std::shared_ptr AppletManager::GetApplet(AppletId id) const { switch (id) { + case AppletId::Auth: + return std::make_shared(*frontend.parental_controls); case AppletId::Error: return std::make_shared(*frontend.error); case AppletId::ProfileSelect: @@ -214,6 +226,8 @@ std::shared_ptr AppletManager::GetApplet(AppletId id) const { return std::make_shared(*frontend.software_keyboard); case AppletId::PhotoViewer: return std::make_shared(*frontend.photo_viewer); + case AppletId::LibAppletShop: + return std::make_shared(*frontend.web_browser, frontend.e_commerce.get()); case AppletId::LibAppletOff: return std::make_shared(*frontend.web_browser); default: diff --git a/src/core/hle/service/am/applets/applets.h b/src/core/hle/service/am/applets/applets.h index 05ae739ca4..ef37918654 100644 --- a/src/core/hle/service/am/applets/applets.h +++ b/src/core/hle/service/am/applets/applets.h @@ -13,7 +13,9 @@ union ResultCode; namespace Core::Frontend { +class ECommerceApplet; class ErrorApplet; +class ParentalControlsApplet; class PhotoViewerApplet; class ProfileSelectApplet; class SoftwareKeyboardApplet; @@ -145,15 +147,19 @@ protected: }; struct AppletFrontendSet { + using ParentalControlsApplet = std::unique_ptr; using ErrorApplet = std::unique_ptr; using PhotoViewer = std::unique_ptr; using ProfileSelect = std::unique_ptr; using SoftwareKeyboard = std::unique_ptr; using WebBrowser = std::unique_ptr; + using ECommerceApplet = std::unique_ptr; AppletFrontendSet(); - AppletFrontendSet(ErrorApplet error, PhotoViewer photo_viewer, ProfileSelect profile_select, - SoftwareKeyboard software_keyboard, WebBrowser web_browser); + AppletFrontendSet(ParentalControlsApplet parental_controls, ErrorApplet error, + PhotoViewer photo_viewer, ProfileSelect profile_select, + SoftwareKeyboard software_keyboard, WebBrowser web_browser, + ECommerceApplet e_commerce); ~AppletFrontendSet(); AppletFrontendSet(const AppletFrontendSet&) = delete; @@ -162,11 +168,13 @@ struct AppletFrontendSet { AppletFrontendSet(AppletFrontendSet&&) noexcept; AppletFrontendSet& operator=(AppletFrontendSet&&) noexcept; + ParentalControlsApplet parental_controls; ErrorApplet error; PhotoViewer photo_viewer; ProfileSelect profile_select; SoftwareKeyboard software_keyboard; WebBrowser web_browser; + ECommerceApplet e_commerce; }; class AppletManager { From b889167b2cb2613ed05b2edc8d2cf547ac24d500 Mon Sep 17 00:00:00 2001 From: Zach Hilman Date: Wed, 5 Jun 2019 12:14:24 -0400 Subject: [PATCH 05/12] yuzu: Accept default applets for Parental Controls and ECommerce --- src/yuzu/main.cpp | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index 66a7080c91..d1813e8345 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp @@ -814,11 +814,13 @@ bool GMainWindow::LoadROM(const QString& filename) { system.SetGPUDebugContext(debug_context); system.SetAppletFrontendSet({ - std::make_unique(*this), - nullptr, - std::make_unique(*this), - std::make_unique(*this), - std::make_unique(*this), + nullptr, ///< Parental Controls + std::make_unique(*this), ///< + nullptr, ///< Photo Viewer + std::make_unique(*this), ///< + std::make_unique(*this), ///< + std::make_unique(*this), ///< + nullptr, ///< E-Commerce }); const Core::System::ResultStatus result{system.Load(*render_window, filename.toStdString())}; From 675aa5f71929466d5aa214f00b76f436d53c2a0b Mon Sep 17 00:00:00 2001 From: Zach Hilman Date: Wed, 5 Jun 2019 12:16:02 -0400 Subject: [PATCH 06/12] web_browser: Correct structures and properly parse TLVs/ShimKind Much, much more HW-accurate and allows us to easily support all of the different web 'shim' types. --- .../hle/service/am/applets/web_browser.cpp | 220 +++++++++++++----- src/core/hle/service/am/applets/web_browser.h | 7 +- 2 files changed, 167 insertions(+), 60 deletions(-) diff --git a/src/core/hle/service/am/applets/web_browser.cpp b/src/core/hle/service/am/applets/web_browser.cpp index 7878f51361..6918bda021 100644 --- a/src/core/hle/service/am/applets/web_browser.cpp +++ b/src/core/hle/service/am/applets/web_browser.cpp @@ -19,7 +19,9 @@ #include "core/file_sys/nca_metadata.h" #include "core/file_sys/registered_cache.h" #include "core/file_sys/romfs.h" +#include "core/file_sys/system_archive/system_archive.h" #include "core/file_sys/vfs_types.h" +#include "core/frontend/applets/general_frontend.h" #include "core/frontend/applets/web_browser.h" #include "core/hle/kernel/process.h" #include "core/hle/service/am/applets/web_browser.h" @@ -28,74 +30,186 @@ namespace Service::AM::Applets { -// TODO(DarkLordZach): There are other arguments in the WebBuffer structure that are currently not -// parsed, for example footer mode and left stick mode. Some of these are not particularly relevant, -// but some may be worth an implementation. -constexpr u16 WEB_ARGUMENT_URL_TYPE = 0x6; - -struct WebBufferHeader { - u16 count; - INSERT_PADDING_BYTES(6); +enum class WebArgTLVType : u16 { + InitialURL = 0x1, + ShopArgumentsURL = 0x2, ///< TODO(DarkLordZach): This is not the official name. + CallbackURL = 0x3, + CallbackableURL = 0x4, + ApplicationID = 0x5, + DocumentPath = 0x6, + DocumentKind = 0x7, + SystemDataID = 0x8, + ShareStartPage = 0x9, + Whitelist = 0xA, + News = 0xB, + UserID = 0xE, + AlbumEntry0 = 0xF, + ScreenShotEnabled = 0x10, + EcClientCertEnabled = 0x11, + Unk12 = 0x12, + PlayReportEnabled = 0x13, + Unk14 = 0x14, + Unk15 = 0x15, + BootDisplayKind = 0x17, + BackgroundKind = 0x18, + FooterEnabled = 0x19, + PointerEnabled = 0x1A, + LeftStickMode = 0x1B, + KeyRepeatFrame1 = 0x1C, + KeyRepeatFrame2 = 0x1D, + BootAsMediaPlayerInv = 0x1E, + DisplayUrlKind = 0x1F, + BootAsMediaPlayer = 0x21, + ShopJumpEnabled = 0x22, + MediaAutoPlayEnabled = 0x23, + LobbyParameter = 0x24, + ApplicationAlbumEntry = 0x26, + JsExtensionEnabled = 0x27, + AdditionalCommentText = 0x28, + TouchEnabledOnContents = 0x29, + UserAgentAdditionalString = 0x2A, + AdditionalMediaData0 = 0x2B, + MediaPlayerAutoCloseEnabled = 0x2C, + PageCacheEnabled = 0x2D, + WebAudioEnabled = 0x2E, + Unk2F = 0x2F, + YouTubeVideoWhitelist = 0x31, + FooterFixedKind = 0x32, + PageFadeEnabled = 0x33, + MediaCreatorApplicationRatingAge = 0x34, + BootLoadingIconEnabled = 0x35, + PageScrollIndicationEnabled = 0x36, + MediaPlayerSpeedControlEnabled = 0x37, + AlbumEntry1 = 0x38, + AlbumEntry2 = 0x39, + AlbumEntry3 = 0x3A, + AdditionalMediaData1 = 0x3B, + AdditionalMediaData2 = 0x3C, + AdditionalMediaData3 = 0x3D, + BootFooterButton = 0x3E, + OverrideWebAudioVolume = 0x3F, + OverrideMediaAudioVolume = 0x40, + BootMode = 0x41, + WebSessionEnabled = 0x42, }; -static_assert(sizeof(WebBufferHeader) == 0x8, "WebBufferHeader has incorrect size."); -struct WebArgumentHeader { - u16 type; +enum class ShimKind : u32 { + Shop = 1, + Login = 2, + Offline = 3, + Share = 4, + Web = 5, + Wifi = 6, + Lobby = 7, +}; + +constexpr std::size_t SHIM_KIND_COUNT = 0x8; + +struct WebArgHeader { + u16 count; + INSERT_PADDING_BYTES(2); + ShimKind kind; +}; +static_assert(sizeof(WebArgHeader) == 0x8, "WebArgHeader has incorrect size."); + +struct WebArgTLV { + WebArgTLVType type; u16 size; u32 offset; }; -static_assert(sizeof(WebArgumentHeader) == 0x8, "WebArgumentHeader has incorrect size."); +static_assert(sizeof(WebArgTLV) == 0x8, "WebArgTLV has incorrect size."); -struct WebArgumentResult { +struct WebCommonReturnValue { u32 result_code; + INSERT_PADDING_BYTES(0x4); std::array last_url; u64 last_url_size; }; -static_assert(sizeof(WebArgumentResult) == 0x1010, "WebArgumentResult has incorrect size."); +static_assert(sizeof(WebCommonReturnValue) == 0x1010, "WebCommonReturnValue has incorrect size."); -static std::vector GetArgumentDataForTagType(const std::vector& data, u16 type) { - WebBufferHeader header; - ASSERT(sizeof(WebBufferHeader) <= data.size()); - std::memcpy(&header, data.data(), sizeof(WebBufferHeader)); +struct WebWifiPageArg { + INSERT_PADDING_BYTES(4); + std::array connection_test_url; + std::array initial_url; + std::array nifm_network_uuid; + u32 nifm_requirement; +}; +static_assert(sizeof(WebWifiPageArg) == 0x518, "WebWifiPageArg has incorrect size."); - u64 offset = sizeof(WebBufferHeader); - for (u16 i = 0; i < header.count; ++i) { - WebArgumentHeader arg; - ASSERT(offset + sizeof(WebArgumentHeader) <= data.size()); - std::memcpy(&arg, data.data() + offset, sizeof(WebArgumentHeader)); - offset += sizeof(WebArgumentHeader); +struct WebWifiReturnValue { + INSERT_PADDING_BYTES(4); + u32 result; +}; +static_assert(sizeof(WebWifiReturnValue) == 0x8, "WebWifiReturnValue has incorrect size."); - if (arg.type == type) { - std::vector out(arg.size); - offset += arg.offset; - ASSERT(offset + arg.size <= data.size()); - std::memcpy(out.data(), data.data() + offset, out.size()); +enum class OfflineWebSource : u32 { + OfflineHtmlPage = 0x1, + ApplicationLegalInformation = 0x2, + SystemDataPage = 0x3, +}; + +enum class ShopWebTarget { + ApplicationInfo, + AddOnContentList, + SubscriptionList, + ConsumableItemList, + Home, + Settings, +}; + +namespace { + +std::map> GetWebArguments(const std::vector& arg) { + WebArgHeader header{}; + if (arg.size() < sizeof(WebArgHeader)) + return {}; + + std::memcpy(&header, arg.data(), sizeof(WebArgHeader)); + + std::map> out; + u64 offset = sizeof(WebArgHeader); + for (std::size_t i = 0; i < header.count; ++i) { + WebArgTLV tlv{}; + if (arg.size() < (offset + sizeof(WebArgTLV))) return out; - } - offset += arg.offset + arg.size; + std::memcpy(&tlv, arg.data() + offset, sizeof(WebArgTLV)); + offset += sizeof(WebArgTLV); + + offset += tlv.offset; + if (arg.size() < (offset + tlv.size)) + return out; + + std::vector data(tlv.size); + std::memcpy(data.data(), arg.data() + offset, tlv.size); + offset += tlv.size; + + out.insert_or_assign(tlv.type, data); } - return {}; + return out; } -static FileSys::VirtualFile GetManualRomFS() { - auto& loader{Core::System::GetInstance().GetAppLoader()}; - - FileSys::VirtualFile out; - if (loader.ReadManualRomFS(out) == Loader::ResultStatus::Success) - return out; - +FileSys::VirtualFile GetApplicationRomFS(u64 title_id, FileSys::ContentRecordType type) { const auto& installed{Core::System::GetInstance().GetContentProvider()}; - const auto res = installed.GetEntry(Core::System::GetInstance().CurrentProcess()->GetTitleID(), - FileSys::ContentRecordType::Manual); + const auto res = installed.GetEntry(title_id, type); - if (res != nullptr) + if (res != nullptr) { return res->GetRomFS(); + } + + if (type == FileSys::ContentRecordType::Data) { + return FileSys::SystemArchive::SynthesizeSystemArchive(title_id); + } + return nullptr; } -WebBrowser::WebBrowser(Core::Frontend::WebBrowserApplet& frontend) : frontend(frontend) {} +} // Anonymous namespace + +WebBrowser::WebBrowser(Core::Frontend::WebBrowserApplet& frontend, + Core::Frontend::ECommerceApplet* frontend_e_commerce) + : frontend(frontend), frontend_e_commerce(frontend_e_commerce) {} WebBrowser::~WebBrowser() = default; @@ -111,24 +225,12 @@ void WebBrowser::Initialize() { ASSERT(web_arg_storage != nullptr); const auto& web_arg = web_arg_storage->GetData(); - const auto url_data = GetArgumentDataForTagType(web_arg, WEB_ARGUMENT_URL_TYPE); - filename = Common::StringFromFixedZeroTerminatedBuffer( - reinterpret_cast(url_data.data()), url_data.size()); + ASSERT(web_arg.size() >= 0x8); + std::memcpy(&kind, web_arg.data() + 0x4, sizeof(ShimKind)); - temporary_dir = FileUtil::SanitizePath(FileUtil::GetUserPath(FileUtil::UserPath::CacheDir) + - "web_applet_manual", - FileUtil::DirectorySeparator::PlatformDefault); - FileUtil::DeleteDirRecursively(temporary_dir); + args = GetWebArguments(web_arg); - manual_romfs = GetManualRomFS(); - if (manual_romfs == nullptr) { - status = ResultCode(-1); - LOG_ERROR(Service_AM, "Failed to find manual for current process!"); - } - - filename = - FileUtil::SanitizePath(temporary_dir + DIR_SEP + "html-document" + DIR_SEP + filename, - FileUtil::DirectorySeparator::PlatformDefault); + InitializeInternal(); } bool WebBrowser::TransactionComplete() const { diff --git a/src/core/hle/service/am/applets/web_browser.h b/src/core/hle/service/am/applets/web_browser.h index 7e0f34c7dd..2474675dec 100644 --- a/src/core/hle/service/am/applets/web_browser.h +++ b/src/core/hle/service/am/applets/web_browser.h @@ -10,6 +10,9 @@ namespace Service::AM::Applets { +enum class ShimKind : u32; +enum class WebArgTLVType : u16; + class WebBrowser final : public Applet { public: WebBrowser(Core::Frontend::WebBrowserApplet& frontend); @@ -38,7 +41,9 @@ private: bool unpacked = false; ResultCode status = RESULT_SUCCESS; - FileSys::VirtualFile manual_romfs; + ShimKind kind; + std::map> args; + std::string temporary_dir; std::string filename; }; From 3898c3903e0d73be1e227e8cc109651299f3d05e Mon Sep 17 00:00:00 2001 From: Zach Hilman Date: Wed, 5 Jun 2019 12:17:31 -0400 Subject: [PATCH 07/12] web_browser: Use function tables for execute and initialize Allows easy handling of multiple shim types, as they have enough in common to be the same backend but not enough to share init/exec. --- .../hle/service/am/applets/web_browser.cpp | 271 +++++++++++++++++- src/core/hle/service/am/applets/web_browser.h | 21 ++ 2 files changed, 285 insertions(+), 7 deletions(-) diff --git a/src/core/hle/service/am/applets/web_browser.cpp b/src/core/hle/service/am/applets/web_browser.cpp index 6918bda021..58efebf06a 100644 --- a/src/core/hle/service/am/applets/web_browser.cpp +++ b/src/core/hle/service/am/applets/web_browser.cpp @@ -246,24 +246,25 @@ void WebBrowser::ExecuteInteractive() { } void WebBrowser::Execute() { - if (complete) + if (complete) { return; + } if (status != RESULT_SUCCESS) { complete = true; return; } - frontend.OpenPage(filename, [this] { UnpackRomFS(); }, [this] { Finalize(); }); + ExecuteInternal(); } void WebBrowser::UnpackRomFS() { if (unpacked) return; - ASSERT(manual_romfs != nullptr); + ASSERT(offline_romfs != nullptr); const auto dir = - FileSys::ExtractRomFS(manual_romfs, FileSys::RomFSExtractionType::SingleDiscard); + FileSys::ExtractRomFS(offline_romfs, FileSys::RomFSExtractionType::SingleDiscard); const auto& vfs{Core::System::GetInstance().GetFilesystem()}; const auto temp_dir = vfs->CreateDirectory(temporary_dir, FileSys::Mode::ReadWrite); FileSys::VfsRawCopyD(dir, temp_dir); @@ -274,12 +275,12 @@ void WebBrowser::UnpackRomFS() { void WebBrowser::Finalize() { complete = true; - WebArgumentResult out{}; + WebCommonReturnValue out{}; out.result_code = 0; out.last_url_size = 0; - std::vector data(sizeof(WebArgumentResult)); - std::memcpy(data.data(), &out, sizeof(WebArgumentResult)); + std::vector data(sizeof(WebCommonReturnValue)); + std::memcpy(data.data(), &out, sizeof(WebCommonReturnValue)); broker.PushNormalDataFromApplet(IStorage{data}); broker.SignalStateChanged(); @@ -287,4 +288,260 @@ void WebBrowser::Finalize() { FileUtil::DeleteDirRecursively(temporary_dir); } +void WebBrowser::InitializeInternal() { + using WebAppletInitializer = void (WebBrowser::*)(); + + constexpr std::array functions{ + nullptr, &WebBrowser::InitializeShop, + nullptr, &WebBrowser::InitializeOffline, + nullptr, nullptr, + nullptr, nullptr, + }; + + const auto index = static_cast(kind); + + if (index > functions.size() || functions[index] == nullptr) { + LOG_ERROR(Service_AM, "Invalid shim_kind={:08X}", index); + return; + } + + const auto function = functions[index]; + (this->*function)(); +} + +void WebBrowser::ExecuteInternal() { + using WebAppletExecutor = void (WebBrowser::*)(); + + constexpr std::array functions{ + nullptr, &WebBrowser::ExecuteShop, + nullptr, &WebBrowser::ExecuteOffline, + nullptr, nullptr, + nullptr, nullptr, + }; + + const auto index = static_cast(kind); + + if (index > functions.size() || functions[index] == nullptr) { + LOG_ERROR(Service_AM, "Invalid shim_kind={:08X}", index); + return; + } + + const auto function = functions[index]; + (this->*function)(); +} + +void WebBrowser::InitializeShop() { + if (frontend_e_commerce == nullptr) { + LOG_ERROR(Service_AM, "Missing ECommerce Applet frontend!"); + status = ResultCode(-1); + return; + } + + const auto user_id_data = args.find(WebArgTLVType::UserID); + + user_id = std::nullopt; + if (user_id_data != args.end()) { + user_id = u128{}; + std::memcpy(user_id->data(), user_id_data->second.data(), sizeof(u128)); + } + + const auto url = args.find(WebArgTLVType::ShopArgumentsURL); + + if (url == args.end()) { + LOG_ERROR(Service_AM, "Missing EShop Arguments URL for initialization!"); + status = ResultCode(-1); + return; + } + + std::vector split_query; + Common::SplitString(Common::StringFromFixedZeroTerminatedBuffer( + reinterpret_cast(url->second.data()), url->second.size()), + '?', split_query); + + // 2 -> Main URL '?' Query Parameters + // Less is missing info, More is malformed + if (split_query.size() != 2) { + LOG_ERROR(Service_AM, "EShop Arguments has more than one question mark, malformed"); + status = ResultCode(-1); + return; + } + + std::vector queries; + Common::SplitString(split_query[1], '&', queries); + + const auto split_single_query = + [](const std::string& in) -> std::pair { + const auto index = in.find('='); + if (index == std::string::npos || index == in.size() - 1) { + return {in, ""}; + } + + return {in.substr(0, index), in.substr(index + 1)}; + }; + + std::transform(queries.begin(), queries.end(), + std::inserter(shop_query, std::next(shop_query.begin())), split_single_query); + + const auto scene = shop_query.find("scene"); + + if (scene == shop_query.end()) { + LOG_ERROR(Service_AM, "No scene parameter was passed via shop query!"); + status = ResultCode(-1); + return; + } + + const std::map target_map{ + {"product_detail", ShopWebTarget::ApplicationInfo}, + {"aocs", ShopWebTarget::AddOnContentList}, + {"subscriptions", ShopWebTarget::SubscriptionList}, + {"consumption", ShopWebTarget::ConsumableItemList}, + {"settings", ShopWebTarget::Settings}, + {"top", ShopWebTarget::Home}, + }; + + const auto target = target_map.find(scene->second); + if (target == target_map.end()) { + LOG_ERROR(Service_AM, "Scene for shop query is invalid! (scene={})", scene->second); + status = ResultCode(-1); + return; + } + + shop_web_target = target->second; + + const auto title_id_data = shop_query.find("dst_app_id"); + if (title_id_data != shop_query.end()) { + title_id = std::stoull(title_id_data->second, nullptr, 0x10); + } + + const auto mode_data = shop_query.find("mode"); + if (mode_data != shop_query.end()) { + shop_full_display = mode_data->second == "full"; + } +} + +void WebBrowser::InitializeOffline() { + if (args.find(WebArgTLVType::DocumentPath) == args.end() || + args.find(WebArgTLVType::DocumentKind) == args.end() || + args.find(WebArgTLVType::ApplicationID) == args.end()) { + status = ResultCode(-1); + LOG_ERROR(Service_AM, "Missing necessary parameters for initialization!"); + } + + const auto url_data = args[WebArgTLVType::DocumentPath]; + filename = Common::StringFromFixedZeroTerminatedBuffer( + reinterpret_cast(url_data.data()), url_data.size()); + + OfflineWebSource source; + ASSERT(args[WebArgTLVType::DocumentKind].size() >= 4); + std::memcpy(&source, args[WebArgTLVType::DocumentKind].data(), sizeof(OfflineWebSource)); + + constexpr std::array WEB_SOURCE_NAMES{ + "manual", + "legal", + "system", + }; + + temporary_dir = + FileUtil::SanitizePath(FileUtil::GetUserPath(FileUtil::UserPath::CacheDir) + "web_applet_" + + WEB_SOURCE_NAMES[static_cast(source) - 1], + FileUtil::DirectorySeparator::PlatformDefault); + FileUtil::DeleteDirRecursively(temporary_dir); + + u64 title_id = 0; // 0 corresponds to current process + ASSERT(args[WebArgTLVType::ApplicationID].size() >= 0x8); + std::memcpy(&title_id, args[WebArgTLVType::ApplicationID].data(), sizeof(u64)); + FileSys::ContentRecordType type = FileSys::ContentRecordType::Data; + + switch (source) { + case OfflineWebSource::OfflineHtmlPage: + // While there is an AppID TLV field, in official SW this is always ignored. + title_id = 0; + type = FileSys::ContentRecordType::Manual; + break; + case OfflineWebSource::ApplicationLegalInformation: + type = FileSys::ContentRecordType::Legal; + break; + case OfflineWebSource::SystemDataPage: + type = FileSys::ContentRecordType::Data; + break; + } + + if (title_id == 0) { + title_id = Core::System::GetInstance().CurrentProcess()->GetTitleID(); + } + + offline_romfs = GetApplicationRomFS(title_id, type); + if (offline_romfs == nullptr) { + status = ResultCode(-1); + LOG_ERROR(Service_AM, "Failed to find offline data for request!"); + } + + std::string path_additional_directory; + if (source == OfflineWebSource::OfflineHtmlPage) { + path_additional_directory = std::string(DIR_SEP) + "html-document"; + } + + filename = + FileUtil::SanitizePath(temporary_dir + path_additional_directory + DIR_SEP + filename, + FileUtil::DirectorySeparator::PlatformDefault); +} + +void WebBrowser::ExecuteShop() { + const auto callback = [this]() { Finalize(); }; + + const auto check_optional_parameter = [this](const auto& p) { + if (!p.has_value()) { + LOG_ERROR(Service_AM, "Missing one or more necessary parameters for execution!"); + status = ResultCode(-1); + return false; + } + + return true; + }; + + switch (shop_web_target) { + case ShopWebTarget::ApplicationInfo: + if (!check_optional_parameter(title_id)) + return; + frontend_e_commerce->ShowApplicationInformation(callback, *title_id, user_id, + shop_full_display, shop_extra_parameter); + break; + case ShopWebTarget::AddOnContentList: + if (!check_optional_parameter(title_id)) + return; + frontend_e_commerce->ShowAddOnContentList(callback, *title_id, user_id, shop_full_display); + break; + case ShopWebTarget::ConsumableItemList: + if (!check_optional_parameter(title_id)) + return; + frontend_e_commerce->ShowConsumableItemList(callback, *title_id, user_id); + break; + case ShopWebTarget::Home: + if (!check_optional_parameter(user_id)) + return; + if (!check_optional_parameter(shop_full_display)) + return; + frontend_e_commerce->ShowShopHome(callback, *user_id, *shop_full_display); + break; + case ShopWebTarget::Settings: + if (!check_optional_parameter(user_id)) + return; + if (!check_optional_parameter(shop_full_display)) + return; + frontend_e_commerce->ShowSettings(callback, *user_id, *shop_full_display); + break; + case ShopWebTarget::SubscriptionList: + if (!check_optional_parameter(title_id)) + return; + frontend_e_commerce->ShowSubscriptionList(callback, *title_id, user_id); + break; + default: + UNREACHABLE(); + } +} + +void WebBrowser::ExecuteOffline() { + frontend.OpenPageLocal(filename, [this] { UnpackRomFS(); }, [this] { Finalize(); }); +} + } // namespace Service::AM::Applets diff --git a/src/core/hle/service/am/applets/web_browser.h b/src/core/hle/service/am/applets/web_browser.h index 2474675dec..a3d2627f4d 100644 --- a/src/core/hle/service/am/applets/web_browser.h +++ b/src/core/hle/service/am/applets/web_browser.h @@ -4,6 +4,7 @@ #pragma once +#include #include "core/file_sys/vfs_types.h" #include "core/hle/service/am/am.h" #include "core/hle/service/am/applets/applets.h" @@ -11,6 +12,7 @@ namespace Service::AM::Applets { enum class ShimKind : u32; +enum class ShopWebTarget; enum class WebArgTLVType : u16; class WebBrowser final : public Applet { @@ -35,6 +37,17 @@ public: void Finalize(); private: + void InitializeInternal(); + void ExecuteInternal(); + + // Specific initializers for the types of web applets + void InitializeShop(); + void InitializeOffline(); + + // Specific executors for the types of web applets + void ExecuteShop(); + void ExecuteOffline(); + Core::Frontend::WebBrowserApplet& frontend; bool complete = false; @@ -44,8 +57,16 @@ private: ShimKind kind; std::map> args; + FileSys::VirtualFile offline_romfs; std::string temporary_dir; std::string filename; + + ShopWebTarget shop_web_target; + std::map shop_query; + std::optional title_id = 0; + std::optional user_id; + std::optional shop_full_display; + std::string shop_extra_parameter; }; } // namespace Service::AM::Applets From 54684feffa8518fc8cbc361e460114f810ba2a0e Mon Sep 17 00:00:00 2001 From: Zach Hilman Date: Wed, 5 Jun 2019 12:18:10 -0400 Subject: [PATCH 08/12] frontend: Add base class and default impl for ECommerce applet frontend --- .../frontend/applets/general_frontend.cpp | 64 +++++++++++++++++++ src/core/frontend/applets/general_frontend.h | 38 +++++++++++ 2 files changed, 102 insertions(+) diff --git a/src/core/frontend/applets/general_frontend.cpp b/src/core/frontend/applets/general_frontend.cpp index 7483ffb763..e6cb59b648 100644 --- a/src/core/frontend/applets/general_frontend.cpp +++ b/src/core/frontend/applets/general_frontend.cpp @@ -53,4 +53,68 @@ void DefaultPhotoViewerApplet::ShowAllPhotos(std::function finished) con finished(); } +ECommerceApplet::~ECommerceApplet() = default; + +DefaultECommerceApplet::~DefaultECommerceApplet() = default; + +void DefaultECommerceApplet::ShowApplicationInformation( + std::function finished, u64 title_id, std::optional user_id, + std::optional full_display, std::optional extra_parameter) { + LOG_INFO(Service_AM, + "Application requested frontend show application information for EShop, " + "title_id={:016X}, user_id={:016X}{:016X}, full_display={}, extra_parameter={}", + title_id, user_id.value_or(u128{})[1], user_id.value_or(u128{})[0], + full_display.has_value() ? fmt::format("{}", *full_display) : "null", + extra_parameter.value_or("null")); + finished(); +} + +void DefaultECommerceApplet::ShowAddOnContentList(std::function finished, u64 title_id, + std::optional user_id, + std::optional full_display) { + LOG_INFO(Service_AM, + "Application requested frontend show add on content list for EShop, " + "title_id={:016X}, user_id={:016X}{:016X}, full_display={}", + title_id, user_id.value_or(u128{})[1], user_id.value_or(u128{})[0], + full_display.has_value() ? fmt::format("{}", *full_display) : "null"); + finished(); +} + +void DefaultECommerceApplet::ShowSubscriptionList(std::function finished, u64 title_id, + std::optional user_id) { + LOG_INFO(Service_AM, + "Application requested frontend show subscription list for EShop, title_id={:016X}, " + "user_id={:016X}{:016X}", + title_id, user_id.value_or(u128{})[1], user_id.value_or(u128{})[0]); + finished(); +} + +void DefaultECommerceApplet::ShowConsumableItemList(std::function finished, u64 title_id, + std::optional user_id) { + LOG_INFO( + Service_AM, + "Application requested frontend show consumable item list for EShop, title_id={:016X}, " + "user_id={:016X}{:016X}", + title_id, user_id.value_or(u128{})[1], user_id.value_or(u128{})[0]); + finished(); +} + +void DefaultECommerceApplet::ShowShopHome(std::function finished, u128 user_id, + bool full_display) { + LOG_INFO(Service_AM, + "Application requested frontend show home menu for EShop, user_id={:016X}{:016X}, " + "full_display={}", + user_id[1], user_id[0], full_display); + finished(); +} + +void DefaultECommerceApplet::ShowSettings(std::function finished, u128 user_id, + bool full_display) { + LOG_INFO(Service_AM, + "Application requested frontend show settings menu for EShop, user_id={:016X}{:016X}, " + "full_display={}", + user_id[1], user_id[0], full_display); + finished(); +} + } // namespace Core::Frontend diff --git a/src/core/frontend/applets/general_frontend.h b/src/core/frontend/applets/general_frontend.h index 48e3ce6513..616112cfcf 100644 --- a/src/core/frontend/applets/general_frontend.h +++ b/src/core/frontend/applets/general_frontend.h @@ -5,6 +5,7 @@ #pragma once #include +#include #include "common/common_types.h" namespace Core::Frontend { @@ -47,4 +48,41 @@ public: void ShowAllPhotos(std::function finished) const override; }; +class ECommerceApplet { +public: + virtual ~ECommerceApplet(); + + virtual void ShowApplicationInformation(std::function finished, u64 title_id, + std::optional user_id = {}, + std::optional full_display = {}, + std::optional extra_parameter = {}) = 0; + virtual void ShowAddOnContentList(std::function finished, u64 title_id, + std::optional user_id = {}, + std::optional full_display = {}) = 0; + virtual void ShowSubscriptionList(std::function finished, u64 title_id, + std::optional user_id = {}) = 0; + virtual void ShowConsumableItemList(std::function finished, u64 title_id, + std::optional user_id = {}) = 0; + virtual void ShowShopHome(std::function finished, u128 user_id, bool full_display) = 0; + virtual void ShowSettings(std::function finished, u128 user_id, bool full_display) = 0; +}; + +class DefaultECommerceApplet : public ECommerceApplet { +public: + ~DefaultECommerceApplet() override; + + void ShowApplicationInformation(std::function finished, u64 title_id, + std::optional user_id, std::optional full_display, + std::optional extra_parameter) override; + void ShowAddOnContentList(std::function finished, u64 title_id, + std::optional user_id, + std::optional full_display) override; + void ShowSubscriptionList(std::function finished, u64 title_id, + std::optional user_id) override; + void ShowConsumableItemList(std::function finished, u64 title_id, + std::optional user_id) override; + void ShowShopHome(std::function finished, u128 user_id, bool full_display) override; + void ShowSettings(std::function finished, u128 user_id, bool full_display) override; +}; + } // namespace Core::Frontend From d018ac2c605f99c825971ee4156e643b02f618e7 Mon Sep 17 00:00:00 2001 From: Zach Hilman Date: Wed, 5 Jun 2019 12:18:53 -0400 Subject: [PATCH 09/12] web_browser: Take ECommerce applet frontend optionally in constructor If it is needed but wasn't passed (or passed nullptr), the Shop handling code will alert and throw an error. --- src/core/hle/service/am/applets/web_browser.h | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/core/hle/service/am/applets/web_browser.h b/src/core/hle/service/am/applets/web_browser.h index a3d2627f4d..42f0a3e8aa 100644 --- a/src/core/hle/service/am/applets/web_browser.h +++ b/src/core/hle/service/am/applets/web_browser.h @@ -17,7 +17,9 @@ enum class WebArgTLVType : u16; class WebBrowser final : public Applet { public: - WebBrowser(Core::Frontend::WebBrowserApplet& frontend); + WebBrowser(Core::Frontend::WebBrowserApplet& frontend, + Core::Frontend::ECommerceApplet* frontend_e_commerce = nullptr); + ~WebBrowser() override; void Initialize() override; @@ -50,6 +52,9 @@ private: Core::Frontend::WebBrowserApplet& frontend; + // Extra frontends for specialized functions + Core::Frontend::ECommerceApplet* frontend_e_commerce; + bool complete = false; bool unpacked = false; ResultCode status = RESULT_SUCCESS; From 73dcb13619fc6603be628a7eea275ea02818c1ce Mon Sep 17 00:00:00 2001 From: Zach Hilman Date: Thu, 6 Jun 2019 18:39:34 -0400 Subject: [PATCH 10/12] web_browser: Only delete temporary directory if it was created Prevents crashes with ShopN applet occasionally. --- src/core/hle/service/am/applets/web_browser.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/core/hle/service/am/applets/web_browser.cpp b/src/core/hle/service/am/applets/web_browser.cpp index 58efebf06a..3c3af476c4 100644 --- a/src/core/hle/service/am/applets/web_browser.cpp +++ b/src/core/hle/service/am/applets/web_browser.cpp @@ -285,7 +285,9 @@ void WebBrowser::Finalize() { broker.PushNormalDataFromApplet(IStorage{data}); broker.SignalStateChanged(); - FileUtil::DeleteDirRecursively(temporary_dir); + if (!temporary_dir.empty() && FileUtil::IsDirectory(temporary_dir)) { + FileUtil::DeleteDirRecursively(temporary_dir); + } } void WebBrowser::InitializeInternal() { From 01ff38cca80c5cf7e64494b129dde8d7c8ebbee5 Mon Sep 17 00:00:00 2001 From: Zach Hilman Date: Thu, 6 Jun 2019 18:40:59 -0400 Subject: [PATCH 11/12] general_frontend: Add documentation for parental controls and ecommerce applets --- .../frontend/applets/general_frontend.cpp | 12 +++++--- src/core/frontend/applets/general_frontend.h | 24 +++++++++++++++ .../hle/service/am/applets/web_browser.cpp | 30 +++++++++---------- src/core/hle/service/am/applets/web_browser.h | 2 +- src/yuzu/main.cpp | 14 ++++----- 5 files changed, 55 insertions(+), 27 deletions(-) diff --git a/src/core/frontend/applets/general_frontend.cpp b/src/core/frontend/applets/general_frontend.cpp index e6cb59b648..c30b36de77 100644 --- a/src/core/frontend/applets/general_frontend.cpp +++ b/src/core/frontend/applets/general_frontend.cpp @@ -60,10 +60,11 @@ DefaultECommerceApplet::~DefaultECommerceApplet() = default; void DefaultECommerceApplet::ShowApplicationInformation( std::function finished, u64 title_id, std::optional user_id, std::optional full_display, std::optional extra_parameter) { + const auto value = user_id.value_or(u128{}); LOG_INFO(Service_AM, "Application requested frontend show application information for EShop, " "title_id={:016X}, user_id={:016X}{:016X}, full_display={}, extra_parameter={}", - title_id, user_id.value_or(u128{})[1], user_id.value_or(u128{})[0], + title_id, value[1], value[0], full_display.has_value() ? fmt::format("{}", *full_display) : "null", extra_parameter.value_or("null")); finished(); @@ -72,30 +73,33 @@ void DefaultECommerceApplet::ShowApplicationInformation( void DefaultECommerceApplet::ShowAddOnContentList(std::function finished, u64 title_id, std::optional user_id, std::optional full_display) { + const auto value = user_id.value_or(u128{}); LOG_INFO(Service_AM, "Application requested frontend show add on content list for EShop, " "title_id={:016X}, user_id={:016X}{:016X}, full_display={}", - title_id, user_id.value_or(u128{})[1], user_id.value_or(u128{})[0], + title_id, value[1], value[0], full_display.has_value() ? fmt::format("{}", *full_display) : "null"); finished(); } void DefaultECommerceApplet::ShowSubscriptionList(std::function finished, u64 title_id, std::optional user_id) { + const auto value = user_id.value_or(u128{}); LOG_INFO(Service_AM, "Application requested frontend show subscription list for EShop, title_id={:016X}, " "user_id={:016X}{:016X}", - title_id, user_id.value_or(u128{})[1], user_id.value_or(u128{})[0]); + title_id, value[1], value[0]); finished(); } void DefaultECommerceApplet::ShowConsumableItemList(std::function finished, u64 title_id, std::optional user_id) { + const auto value = user_id.value_or(u128{}); LOG_INFO( Service_AM, "Application requested frontend show consumable item list for EShop, title_id={:016X}, " "user_id={:016X}{:016X}", - title_id, user_id.value_or(u128{})[1], user_id.value_or(u128{})[0]); + title_id, value[1], value[0]); finished(); } diff --git a/src/core/frontend/applets/general_frontend.h b/src/core/frontend/applets/general_frontend.h index 616112cfcf..4b63f828eb 100644 --- a/src/core/frontend/applets/general_frontend.h +++ b/src/core/frontend/applets/general_frontend.h @@ -14,10 +14,20 @@ class ParentalControlsApplet { public: virtual ~ParentalControlsApplet(); + // Prompts the user to enter a PIN and calls the callback with whether or not it matches the + // correct PIN. If the bool is passed, and the PIN was recently entered correctly, the frontend + // should not prompt and simply return true. virtual void VerifyPIN(std::function finished, bool suspend_future_verification_temporarily) = 0; + + // Prompts the user to enter a PIN and calls the callback for correctness. Frontends can + // optionally alert the user that this is to change parental controls settings. virtual void VerifyPINForSettings(std::function finished) = 0; + + // Prompts the user to create a new PIN for pctl and stores it with the service. virtual void RegisterPIN(std::function finished) = 0; + + // Prompts the user to verify the current PIN and then store a new one into pctl. virtual void ChangePIN(std::function finished) = 0; }; @@ -52,18 +62,32 @@ class ECommerceApplet { public: virtual ~ECommerceApplet(); + // Shows a page with application icons, description, name, and price. virtual void ShowApplicationInformation(std::function finished, u64 title_id, std::optional user_id = {}, std::optional full_display = {}, std::optional extra_parameter = {}) = 0; + + // Shows a page with all of the add on content available for a game, with name, description, and + // price. virtual void ShowAddOnContentList(std::function finished, u64 title_id, std::optional user_id = {}, std::optional full_display = {}) = 0; + + // Shows a page with all of the subscriptions (recurring payments) for a game, with name, + // description, price, and renewal period. virtual void ShowSubscriptionList(std::function finished, u64 title_id, std::optional user_id = {}) = 0; + + // Shows a page with a list of any additional game related purchasable items (DLC, + // subscriptions, etc) for a particular game, with name, description, type, and price. virtual void ShowConsumableItemList(std::function finished, u64 title_id, std::optional user_id = {}) = 0; + + // Shows the home page of the shop. virtual void ShowShopHome(std::function finished, u128 user_id, bool full_display) = 0; + + // Shows the user settings page of the shop. virtual void ShowSettings(std::function finished, u128 user_id, bool full_display) = 0; }; diff --git a/src/core/hle/service/am/applets/web_browser.cpp b/src/core/hle/service/am/applets/web_browser.cpp index 3c3af476c4..3aa8f24688 100644 --- a/src/core/hle/service/am/applets/web_browser.cpp +++ b/src/core/hle/service/am/applets/web_browser.cpp @@ -103,6 +103,17 @@ enum class ShimKind : u32 { Lobby = 7, }; +enum class ShopWebTarget { + ApplicationInfo, + AddOnContentList, + SubscriptionList, + ConsumableItemList, + Home, + Settings, +}; + +namespace { + constexpr std::size_t SHIM_KIND_COUNT = 0x8; struct WebArgHeader { @@ -148,31 +159,20 @@ enum class OfflineWebSource : u32 { SystemDataPage = 0x3, }; -enum class ShopWebTarget { - ApplicationInfo, - AddOnContentList, - SubscriptionList, - ConsumableItemList, - Home, - Settings, -}; - -namespace { - std::map> GetWebArguments(const std::vector& arg) { - WebArgHeader header{}; if (arg.size() < sizeof(WebArgHeader)) return {}; + WebArgHeader header{}; std::memcpy(&header, arg.data(), sizeof(WebArgHeader)); std::map> out; u64 offset = sizeof(WebArgHeader); for (std::size_t i = 0; i < header.count; ++i) { - WebArgTLV tlv{}; if (arg.size() < (offset + sizeof(WebArgTLV))) return out; + WebArgTLV tlv{}; std::memcpy(&tlv, arg.data() + offset, sizeof(WebArgTLV)); offset += sizeof(WebArgTLV); @@ -392,7 +392,7 @@ void WebBrowser::InitializeShop() { return; } - const std::map target_map{ + const std::map> target_map{ {"product_detail", ShopWebTarget::ApplicationInfo}, {"aocs", ShopWebTarget::AddOnContentList}, {"subscriptions", ShopWebTarget::SubscriptionList}, @@ -480,7 +480,7 @@ void WebBrowser::InitializeOffline() { std::string path_additional_directory; if (source == OfflineWebSource::OfflineHtmlPage) { - path_additional_directory = std::string(DIR_SEP) + "html-document"; + path_additional_directory = std::string(DIR_SEP).append("html-document"); } filename = diff --git a/src/core/hle/service/am/applets/web_browser.h b/src/core/hle/service/am/applets/web_browser.h index 42f0a3e8aa..9667dcf6f1 100644 --- a/src/core/hle/service/am/applets/web_browser.h +++ b/src/core/hle/service/am/applets/web_browser.h @@ -67,7 +67,7 @@ private: std::string filename; ShopWebTarget shop_web_target; - std::map shop_query; + std::map> shop_query; std::optional title_id = 0; std::optional user_id; std::optional shop_full_display; diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index d1813e8345..47e46f574c 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp @@ -814,13 +814,13 @@ bool GMainWindow::LoadROM(const QString& filename) { system.SetGPUDebugContext(debug_context); system.SetAppletFrontendSet({ - nullptr, ///< Parental Controls - std::make_unique(*this), ///< - nullptr, ///< Photo Viewer - std::make_unique(*this), ///< - std::make_unique(*this), ///< - std::make_unique(*this), ///< - nullptr, ///< E-Commerce + nullptr, // Parental Controls + std::make_unique(*this), // + nullptr, // Photo Viewer + std::make_unique(*this), // + std::make_unique(*this), // + std::make_unique(*this), // + nullptr, // E-Commerce }); const Core::System::ResultStatus result{system.Load(*render_window, filename.toStdString())}; From 3c4238657d326a7d85cbc9152ca16483383c20e7 Mon Sep 17 00:00:00 2001 From: Zach Hilman Date: Thu, 6 Jun 2019 19:46:36 -0400 Subject: [PATCH 12/12] applets: Pass current process title ID to applets Avoids using system accessor to get current process in applet code. --- src/core/hle/service/am/am.cpp | 12 +++++---- src/core/hle/service/am/am.h | 6 +++-- src/core/hle/service/am/applet_ae.cpp | 26 +++++++++++-------- src/core/hle/service/am/applet_ae.h | 3 ++- src/core/hle/service/am/applet_oe.cpp | 14 +++++----- src/core/hle/service/am/applet_oe.h | 3 ++- src/core/hle/service/am/applets/applets.cpp | 21 ++++++++------- src/core/hle/service/am/applets/applets.h | 2 +- .../hle/service/am/applets/web_browser.cpp | 7 ++--- src/core/hle/service/am/applets/web_browser.h | 4 ++- src/core/hle/service/service.cpp | 2 +- 11 files changed, 59 insertions(+), 41 deletions(-) diff --git a/src/core/hle/service/am/am.cpp b/src/core/hle/service/am/am.cpp index 4a7bf4acb3..33cebb48b8 100644 --- a/src/core/hle/service/am/am.cpp +++ b/src/core/hle/service/am/am.cpp @@ -887,7 +887,9 @@ void IStorageAccessor::Read(Kernel::HLERequestContext& ctx) { rb.Push(RESULT_SUCCESS); } -ILibraryAppletCreator::ILibraryAppletCreator() : ServiceFramework("ILibraryAppletCreator") { +ILibraryAppletCreator::ILibraryAppletCreator(u64 current_process_title_id) + : ServiceFramework("ILibraryAppletCreator"), + current_process_title_id(current_process_title_id) { static const FunctionInfo functions[] = { {0, &ILibraryAppletCreator::CreateLibraryApplet, "CreateLibraryApplet"}, {1, nullptr, "TerminateAllLibraryApplets"}, @@ -910,7 +912,7 @@ void ILibraryAppletCreator::CreateLibraryApplet(Kernel::HLERequestContext& ctx) static_cast(applet_id), applet_mode); const auto& applet_manager{Core::System::GetInstance().GetAppletManager()}; - const auto applet = applet_manager.GetApplet(applet_id); + const auto applet = applet_manager.GetApplet(applet_id, current_process_title_id); if (applet == nullptr) { LOG_ERROR(Service_AM, "Applet doesn't exist! applet_id={}", static_cast(applet_id)); @@ -1234,13 +1236,13 @@ void IApplicationFunctions::GetSaveDataSize(Kernel::HLERequestContext& ctx) { } void InstallInterfaces(SM::ServiceManager& service_manager, - std::shared_ptr nvflinger) { + std::shared_ptr nvflinger, Core::System& system) { auto message_queue = std::make_shared(); message_queue->PushMessage(AppletMessageQueue::AppletMessage::FocusStateChanged); // Needed on // game boot - std::make_shared(nvflinger, message_queue)->InstallAsService(service_manager); - std::make_shared(nvflinger, message_queue)->InstallAsService(service_manager); + std::make_shared(nvflinger, message_queue, system)->InstallAsService(service_manager); + std::make_shared(nvflinger, message_queue, system)->InstallAsService(service_manager); std::make_shared()->InstallAsService(service_manager); std::make_shared()->InstallAsService(service_manager); std::make_shared()->InstallAsService(service_manager); diff --git a/src/core/hle/service/am/am.h b/src/core/hle/service/am/am.h index 1fa069e560..4ea609d23b 100644 --- a/src/core/hle/service/am/am.h +++ b/src/core/hle/service/am/am.h @@ -201,13 +201,15 @@ private: class ILibraryAppletCreator final : public ServiceFramework { public: - ILibraryAppletCreator(); + ILibraryAppletCreator(u64 current_process_title_id); ~ILibraryAppletCreator() override; private: void CreateLibraryApplet(Kernel::HLERequestContext& ctx); void CreateStorage(Kernel::HLERequestContext& ctx); void CreateTransferMemoryStorage(Kernel::HLERequestContext& ctx); + + u64 current_process_title_id; }; class IApplicationFunctions final : public ServiceFramework { @@ -264,7 +266,7 @@ public: /// Registers all AM services with the specified service manager. void InstallInterfaces(SM::ServiceManager& service_manager, - std::shared_ptr nvflinger); + std::shared_ptr nvflinger, Core::System& system); } // namespace AM } // namespace Service diff --git a/src/core/hle/service/am/applet_ae.cpp b/src/core/hle/service/am/applet_ae.cpp index 488add8e75..fe5beb8f9a 100644 --- a/src/core/hle/service/am/applet_ae.cpp +++ b/src/core/hle/service/am/applet_ae.cpp @@ -4,6 +4,7 @@ #include "common/logging/log.h" #include "core/hle/ipc_helpers.h" +#include "core/hle/kernel/process.h" #include "core/hle/service/am/am.h" #include "core/hle/service/am/applet_ae.h" #include "core/hle/service/nvflinger/nvflinger.h" @@ -13,9 +14,10 @@ namespace Service::AM { class ILibraryAppletProxy final : public ServiceFramework { public: explicit ILibraryAppletProxy(std::shared_ptr nvflinger, - std::shared_ptr msg_queue) + std::shared_ptr msg_queue, + Core::System& system) : ServiceFramework("ILibraryAppletProxy"), nvflinger(std::move(nvflinger)), - msg_queue(std::move(msg_queue)) { + msg_queue(std::move(msg_queue)), system(system) { // clang-format off static const FunctionInfo functions[] = { {0, &ILibraryAppletProxy::GetCommonStateGetter, "GetCommonStateGetter"}, @@ -96,7 +98,7 @@ private: IPC::ResponseBuilder rb{ctx, 2, 0, 1}; rb.Push(RESULT_SUCCESS); - rb.PushIpcInterface(); + rb.PushIpcInterface(system.CurrentProcess()->GetTitleID()); } void GetApplicationFunctions(Kernel::HLERequestContext& ctx) { @@ -109,14 +111,15 @@ private: std::shared_ptr nvflinger; std::shared_ptr msg_queue; + Core::System& system; }; class ISystemAppletProxy final : public ServiceFramework { public: explicit ISystemAppletProxy(std::shared_ptr nvflinger, - std::shared_ptr msg_queue) + std::shared_ptr msg_queue, Core::System& system) : ServiceFramework("ISystemAppletProxy"), nvflinger(std::move(nvflinger)), - msg_queue(std::move(msg_queue)) { + msg_queue(std::move(msg_queue)), system(system) { // clang-format off static const FunctionInfo functions[] = { {0, &ISystemAppletProxy::GetCommonStateGetter, "GetCommonStateGetter"}, @@ -191,7 +194,7 @@ private: IPC::ResponseBuilder rb{ctx, 2, 0, 1}; rb.Push(RESULT_SUCCESS); - rb.PushIpcInterface(); + rb.PushIpcInterface(system.CurrentProcess()->GetTitleID()); } void GetHomeMenuFunctions(Kernel::HLERequestContext& ctx) { @@ -219,6 +222,7 @@ private: } std::shared_ptr nvflinger; std::shared_ptr msg_queue; + Core::System& system; }; void AppletAE::OpenSystemAppletProxy(Kernel::HLERequestContext& ctx) { @@ -226,7 +230,7 @@ void AppletAE::OpenSystemAppletProxy(Kernel::HLERequestContext& ctx) { IPC::ResponseBuilder rb{ctx, 2, 0, 1}; rb.Push(RESULT_SUCCESS); - rb.PushIpcInterface(nvflinger, msg_queue); + rb.PushIpcInterface(nvflinger, msg_queue, system); } void AppletAE::OpenLibraryAppletProxy(Kernel::HLERequestContext& ctx) { @@ -234,7 +238,7 @@ void AppletAE::OpenLibraryAppletProxy(Kernel::HLERequestContext& ctx) { IPC::ResponseBuilder rb{ctx, 2, 0, 1}; rb.Push(RESULT_SUCCESS); - rb.PushIpcInterface(nvflinger, msg_queue); + rb.PushIpcInterface(nvflinger, msg_queue, system); } void AppletAE::OpenLibraryAppletProxyOld(Kernel::HLERequestContext& ctx) { @@ -242,13 +246,13 @@ void AppletAE::OpenLibraryAppletProxyOld(Kernel::HLERequestContext& ctx) { IPC::ResponseBuilder rb{ctx, 2, 0, 1}; rb.Push(RESULT_SUCCESS); - rb.PushIpcInterface(nvflinger, msg_queue); + rb.PushIpcInterface(nvflinger, msg_queue, system); } AppletAE::AppletAE(std::shared_ptr nvflinger, - std::shared_ptr msg_queue) + std::shared_ptr msg_queue, Core::System& system) : ServiceFramework("appletAE"), nvflinger(std::move(nvflinger)), - msg_queue(std::move(msg_queue)) { + msg_queue(std::move(msg_queue)), system(system) { // clang-format off static const FunctionInfo functions[] = { {100, &AppletAE::OpenSystemAppletProxy, "OpenSystemAppletProxy"}, diff --git a/src/core/hle/service/am/applet_ae.h b/src/core/hle/service/am/applet_ae.h index 902db26658..9e006cd9d8 100644 --- a/src/core/hle/service/am/applet_ae.h +++ b/src/core/hle/service/am/applet_ae.h @@ -18,7 +18,7 @@ namespace AM { class AppletAE final : public ServiceFramework { public: explicit AppletAE(std::shared_ptr nvflinger, - std::shared_ptr msg_queue); + std::shared_ptr msg_queue, Core::System& system); ~AppletAE() override; const std::shared_ptr& GetMessageQueue() const; @@ -30,6 +30,7 @@ private: std::shared_ptr nvflinger; std::shared_ptr msg_queue; + Core::System& system; }; } // namespace AM diff --git a/src/core/hle/service/am/applet_oe.cpp b/src/core/hle/service/am/applet_oe.cpp index d3a0a15689..6e255fe95b 100644 --- a/src/core/hle/service/am/applet_oe.cpp +++ b/src/core/hle/service/am/applet_oe.cpp @@ -4,6 +4,7 @@ #include "common/logging/log.h" #include "core/hle/ipc_helpers.h" +#include "core/hle/kernel/process.h" #include "core/hle/service/am/am.h" #include "core/hle/service/am/applet_oe.h" #include "core/hle/service/nvflinger/nvflinger.h" @@ -13,9 +14,9 @@ namespace Service::AM { class IApplicationProxy final : public ServiceFramework { public: explicit IApplicationProxy(std::shared_ptr nvflinger, - std::shared_ptr msg_queue) + std::shared_ptr msg_queue, Core::System& system) : ServiceFramework("IApplicationProxy"), nvflinger(std::move(nvflinger)), - msg_queue(std::move(msg_queue)) { + msg_queue(std::move(msg_queue)), system(system) { // clang-format off static const FunctionInfo functions[] = { {0, &IApplicationProxy::GetCommonStateGetter, "GetCommonStateGetter"}, @@ -87,7 +88,7 @@ private: IPC::ResponseBuilder rb{ctx, 2, 0, 1}; rb.Push(RESULT_SUCCESS); - rb.PushIpcInterface(); + rb.PushIpcInterface(system.CurrentProcess()->GetTitleID()); } void GetApplicationFunctions(Kernel::HLERequestContext& ctx) { @@ -100,6 +101,7 @@ private: std::shared_ptr nvflinger; std::shared_ptr msg_queue; + Core::System& system; }; void AppletOE::OpenApplicationProxy(Kernel::HLERequestContext& ctx) { @@ -107,13 +109,13 @@ void AppletOE::OpenApplicationProxy(Kernel::HLERequestContext& ctx) { IPC::ResponseBuilder rb{ctx, 2, 0, 1}; rb.Push(RESULT_SUCCESS); - rb.PushIpcInterface(nvflinger, msg_queue); + rb.PushIpcInterface(nvflinger, msg_queue, system); } AppletOE::AppletOE(std::shared_ptr nvflinger, - std::shared_ptr msg_queue) + std::shared_ptr msg_queue, Core::System& system) : ServiceFramework("appletOE"), nvflinger(std::move(nvflinger)), - msg_queue(std::move(msg_queue)) { + msg_queue(std::move(msg_queue)), system(system) { static const FunctionInfo functions[] = { {0, &AppletOE::OpenApplicationProxy, "OpenApplicationProxy"}, }; diff --git a/src/core/hle/service/am/applet_oe.h b/src/core/hle/service/am/applet_oe.h index bbd0108eff..22c05419d7 100644 --- a/src/core/hle/service/am/applet_oe.h +++ b/src/core/hle/service/am/applet_oe.h @@ -18,7 +18,7 @@ namespace AM { class AppletOE final : public ServiceFramework { public: explicit AppletOE(std::shared_ptr nvflinger, - std::shared_ptr msg_queue); + std::shared_ptr msg_queue, Core::System& system); ~AppletOE() override; const std::shared_ptr& GetMessageQueue() const; @@ -28,6 +28,7 @@ private: std::shared_ptr nvflinger; std::shared_ptr msg_queue; + Core::System& system; }; } // namespace AM diff --git a/src/core/hle/service/am/applets/applets.cpp b/src/core/hle/service/am/applets/applets.cpp index 5532061779..6bdba2468b 100644 --- a/src/core/hle/service/am/applets/applets.cpp +++ b/src/core/hle/service/am/applets/applets.cpp @@ -139,12 +139,14 @@ void Applet::Initialize() { AppletFrontendSet::AppletFrontendSet() = default; -AppletFrontendSet::AppletFrontendSet(ErrorApplet error, PhotoViewer photo_viewer, - ProfileSelect profile_select, - SoftwareKeyboard software_keyboard, WebBrowser web_browser) - : error{std::move(error)}, photo_viewer{std::move(photo_viewer)}, profile_select{std::move( - profile_select)}, - software_keyboard{std::move(software_keyboard)}, web_browser{std::move(web_browser)} {} +AppletFrontendSet::AppletFrontendSet(ParentalControlsApplet parental_controls, ErrorApplet error, + PhotoViewer photo_viewer, ProfileSelect profile_select, + SoftwareKeyboard software_keyboard, WebBrowser web_browser, + ECommerceApplet e_commerce) + : parental_controls{std::move(parental_controls)}, error{std::move(error)}, + photo_viewer{std::move(photo_viewer)}, profile_select{std::move(profile_select)}, + software_keyboard{std::move(software_keyboard)}, web_browser{std::move(web_browser)}, + e_commerce{std::move(e_commerce)} {} AppletFrontendSet::~AppletFrontendSet() = default; @@ -214,7 +216,7 @@ void AppletManager::ClearAll() { frontend = {}; } -std::shared_ptr AppletManager::GetApplet(AppletId id) const { +std::shared_ptr AppletManager::GetApplet(AppletId id, u64 current_process_title_id) const { switch (id) { case AppletId::Auth: return std::make_shared(*frontend.parental_controls); @@ -227,9 +229,10 @@ std::shared_ptr AppletManager::GetApplet(AppletId id) const { case AppletId::PhotoViewer: return std::make_shared(*frontend.photo_viewer); case AppletId::LibAppletShop: - return std::make_shared(*frontend.web_browser, frontend.e_commerce.get()); + return std::make_shared(*frontend.web_browser, current_process_title_id, + frontend.e_commerce.get()); case AppletId::LibAppletOff: - return std::make_shared(*frontend.web_browser); + return std::make_shared(*frontend.web_browser, current_process_title_id); default: UNIMPLEMENTED_MSG( "No backend implementation exists for applet_id={:02X}! Falling back to stub applet.", diff --git a/src/core/hle/service/am/applets/applets.h b/src/core/hle/service/am/applets/applets.h index ef37918654..adc973dad0 100644 --- a/src/core/hle/service/am/applets/applets.h +++ b/src/core/hle/service/am/applets/applets.h @@ -187,7 +187,7 @@ public: void SetDefaultAppletsIfMissing(); void ClearAll(); - std::shared_ptr GetApplet(AppletId id) const; + std::shared_ptr GetApplet(AppletId id, u64 current_process_title_id) const; private: AppletFrontendSet frontend; diff --git a/src/core/hle/service/am/applets/web_browser.cpp b/src/core/hle/service/am/applets/web_browser.cpp index 3aa8f24688..2762e0653b 100644 --- a/src/core/hle/service/am/applets/web_browser.cpp +++ b/src/core/hle/service/am/applets/web_browser.cpp @@ -207,9 +207,10 @@ FileSys::VirtualFile GetApplicationRomFS(u64 title_id, FileSys::ContentRecordTyp } // Anonymous namespace -WebBrowser::WebBrowser(Core::Frontend::WebBrowserApplet& frontend, +WebBrowser::WebBrowser(Core::Frontend::WebBrowserApplet& frontend, u64 current_process_title_id, Core::Frontend::ECommerceApplet* frontend_e_commerce) - : frontend(frontend), frontend_e_commerce(frontend_e_commerce) {} + : frontend(frontend), frontend_e_commerce(frontend_e_commerce), + current_process_title_id(current_process_title_id) {} WebBrowser::~WebBrowser() = default; @@ -469,7 +470,7 @@ void WebBrowser::InitializeOffline() { } if (title_id == 0) { - title_id = Core::System::GetInstance().CurrentProcess()->GetTitleID(); + title_id = current_process_title_id; } offline_romfs = GetApplicationRomFS(title_id, type); diff --git a/src/core/hle/service/am/applets/web_browser.h b/src/core/hle/service/am/applets/web_browser.h index 9667dcf6f1..870f57b645 100644 --- a/src/core/hle/service/am/applets/web_browser.h +++ b/src/core/hle/service/am/applets/web_browser.h @@ -17,7 +17,7 @@ enum class WebArgTLVType : u16; class WebBrowser final : public Applet { public: - WebBrowser(Core::Frontend::WebBrowserApplet& frontend, + WebBrowser(Core::Frontend::WebBrowserApplet& frontend, u64 current_process_title_id, Core::Frontend::ECommerceApplet* frontend_e_commerce = nullptr); ~WebBrowser() override; @@ -59,6 +59,8 @@ private: bool unpacked = false; ResultCode status = RESULT_SUCCESS; + u64 current_process_title_id; + ShimKind kind; std::map> args; diff --git a/src/core/hle/service/service.cpp b/src/core/hle/service/service.cpp index b2954eb343..dfffcb5109 100644 --- a/src/core/hle/service/service.cpp +++ b/src/core/hle/service/service.cpp @@ -204,7 +204,7 @@ void Init(std::shared_ptr& sm, Core::System& system, SM::ServiceManager::InstallInterfaces(sm); Account::InstallInterfaces(system); - AM::InstallInterfaces(*sm, nv_flinger); + AM::InstallInterfaces(*sm, nv_flinger, system); AOC::InstallInterfaces(*sm); APM::InstallInterfaces(*sm); ARP::InstallInterfaces(*sm);