Compare commits

..

9 Commits

Author SHA1 Message Date
Zach Hilman
d10fc2d727 glue: Correct missing bytes in ApplicationLaunchParameter 2019-06-25 22:25:10 -04:00
Zach Hilman
d40a38df8d core: Keep track of ARPManager and register current application on boot 2019-06-24 19:27:35 -04:00
Zach Hilman
ce21973022 glue: Implement arp:w and arp:r services
These keep track of running process' launch properties and control properties and allows for issuing and reading them by process and title ID.
2019-06-24 19:26:16 -04:00
Zach Hilman
df3ee4f444 glue: Add errors for glue/arp services 2019-06-24 19:20:28 -04:00
Zach Hilman
4fab0d392b glue: Add scaffolding for bgtc:t and bgtc:sc services 2019-06-24 19:20:06 -04:00
Zach Hilman
9003e19797 arp: Move to glue services
Glue is the name of the sysmodule that contains both arp and bgtc.
2019-06-24 19:17:48 -04:00
Zach Hilman
5f8d2a2044 glue: Add manager to keep track of application registry
Manages mapping between title IDs and application launch and control properties.
2019-06-24 19:17:13 -04:00
Zach Hilman
db2e5e5fa6 registered_cache: Add getter to determine source slot in content provider union
Used to determine StorageId source for application data.
2019-06-24 19:10:17 -04:00
Zach Hilman
a468273221 patch_manager: Add getter for title version 2019-06-24 19:05:50 -04:00
38 changed files with 856 additions and 984 deletions

View File

@@ -209,8 +209,6 @@ add_library(core STATIC
hle/service/apm/apm.h
hle/service/apm/interface.cpp
hle/service/apm/interface.h
hle/service/arp/arp.cpp
hle/service/arp/arp.h
hle/service/audio/audctl.cpp
hle/service/audio/audctl.h
hle/service/audio/auddbg.cpp
@@ -276,6 +274,15 @@ add_library(core STATIC
hle/service/friend/friend.h
hle/service/friend/interface.cpp
hle/service/friend/interface.h
hle/service/glue/arp.cpp
hle/service/glue/arp.h
hle/service/glue/bgtc.cpp
hle/service/glue/bgtc.h
hle/service/glue/errors.h
hle/service/glue/glue.cpp
hle/service/glue/glue.h
hle/service/glue/manager.cpp
hle/service/glue/manager.h
hle/service/grc/grc.cpp
hle/service/grc/grc.h
hle/service/hid/hid.cpp

View File

@@ -25,6 +25,7 @@
#include "core/hle/kernel/scheduler.h"
#include "core/hle/kernel/thread.h"
#include "core/hle/service/am/applets/applets.h"
#include "core/hle/service/glue/manager.h"
#include "core/hle/service/service.h"
#include "core/hle/service/sm/sm.h"
#include "core/loader/loader.h"
@@ -33,12 +34,37 @@
#include "core/settings.h"
#include "core/telemetry_session.h"
#include "file_sys/cheat_engine.h"
#include "file_sys/patch_manager.h"
#include "video_core/debug_utils/debug_utils.h"
#include "video_core/renderer_base.h"
#include "video_core/video_core.h"
namespace Core {
namespace {
FileSys::StorageId GetStorageIdForFrontendSlot(
std::optional<FileSys::ContentProviderUnionSlot> slot) {
if (!slot.has_value()) {
return FileSys::StorageId::None;
}
switch (*slot) {
case FileSys::ContentProviderUnionSlot::UserNAND:
return FileSys::StorageId::NandUser;
case FileSys::ContentProviderUnionSlot::SysNAND:
return FileSys::StorageId::NandSystem;
case FileSys::ContentProviderUnionSlot::SDMC:
return FileSys::StorageId::SdCard;
case FileSys::ContentProviderUnionSlot::FrontendManual:
return FileSys::StorageId::Host;
default:
return FileSys::StorageId::None;
}
}
} // Anonymous namespace
/*static*/ System System::s_instance;
FileSys::VirtualFile GetGameFileFromPath(const FileSys::VirtualFilesystem& vfs,
@@ -110,6 +136,9 @@ struct System::Impl {
/// Create default implementations of applets if one is not provided.
applet_manager.SetDefaultAppletsIfMissing();
/// Reset all glue registrations
arp_manager.ResetAll();
telemetry_session = std::make_unique<Core::TelemetrySession>();
service_manager = std::make_shared<Service::SM::ServiceManager>();
@@ -161,6 +190,7 @@ struct System::Impl {
return static_cast<ResultStatus>(static_cast<u32>(ResultStatus::ErrorLoader) +
static_cast<u32>(load_result));
}
AddGlueRegistrationForProcess(*app_loader, *main_process);
kernel.MakeCurrentProcess(main_process.get());
// Main process has been loaded and been made current.
@@ -219,6 +249,31 @@ struct System::Impl {
return app_loader->ReadTitle(out);
}
void AddGlueRegistrationForProcess(Loader::AppLoader& loader, Kernel::Process& process) {
std::vector<u8> nacp_data;
FileSys::NACP nacp;
if (loader.ReadControlData(nacp) == Loader::ResultStatus::Success) {
nacp_data = nacp.GetRawBytes();
} else {
nacp_data.resize(sizeof(FileSys::RawNACP));
}
Service::Glue::ApplicationLaunchProperty launch{};
launch.title_id = process.GetTitleID();
FileSys::PatchManager pm{launch.title_id};
launch.version = pm.GetGameVersion().value_or(0);
// TODO(DarkLordZach): When FSController/Game Card Support is added, if
// current_process_game_card use correct StorageId
launch.base_game_storage_id = GetStorageIdForFrontendSlot(content_provider->GetSlotForEntry(
launch.title_id, FileSys::ContentRecordType::Program));
launch.update_storage_id = GetStorageIdForFrontendSlot(content_provider->GetSlotForEntry(
FileSys::GetUpdateTitleID(launch.title_id), FileSys::ContentRecordType::Program));
arp_manager.Register(launch.title_id, launch, std::move(nacp_data));
}
void SetStatus(ResultStatus new_status, const char* details = nullptr) {
status = new_status;
if (details) {
@@ -249,6 +304,9 @@ struct System::Impl {
/// Frontend applets
Service::AM::Applets::AppletManager applet_manager;
/// Glue services
Service::Glue::ARPManager arp_manager;
/// Service manager
std::shared_ptr<Service::SM::ServiceManager> service_manager;
@@ -500,6 +558,14 @@ const Reporter& System::GetReporter() const {
return impl->reporter;
}
Service::Glue::ARPManager& System::GetARPManager() {
return impl->arp_manager;
}
const Service::Glue::ARPManager& System::GetARPManager() const {
return impl->arp_manager;
}
System::ResultStatus System::Init(Frontend::EmuWindow& emu_window) {
return impl->Init(*this, emu_window);
}

View File

@@ -43,6 +43,10 @@ struct AppletFrontendSet;
class AppletManager;
} // namespace AM::Applets
namespace Glue {
class ARPManager;
}
namespace SM {
class ServiceManager;
} // namespace SM
@@ -288,6 +292,10 @@ public:
const Reporter& GetReporter() const;
Service::Glue::ARPManager& GetARPManager();
const Service::Glue::ARPManager& GetARPManager() const;
private:
System();

View File

@@ -493,6 +493,16 @@ std::map<std::string, std::string, std::less<>> PatchManager::GetPatchVersionNam
return out;
}
std::optional<u32> PatchManager::GetGameVersion() const {
const auto& installed = Core::System::GetInstance().GetContentProvider();
const auto update_tid = GetUpdateTitleID(title_id);
if (installed.HasEntry(update_tid, ContentRecordType::Program)) {
return installed.GetEntryVersion(update_tid);
}
return installed.GetEntryVersion(title_id);
}
std::pair<std::unique_ptr<NACP>, VirtualFile> PatchManager::GetControlMetadata() const {
const auto& installed = Core::System::GetInstance().GetContentProvider();

View File

@@ -66,8 +66,13 @@ public:
std::map<std::string, std::string, std::less<>> GetPatchVersionNames(
VirtualFile update_raw = nullptr) const;
// Given title_id of the program, attempts to get the control data of the update and parse it,
// falling back to the base control data.
// If the game update exists, returns the u32 version field in its Meta-type NCA. If that fails,
// it will fallback to the Meta-type NCA of the base game. If that fails, the result will be
// std::nullopt
std::optional<u32> GetGameVersion() const;
// Given title_id of the program, attempts to get the control data of the update and parse
// it, falling back to the base control data.
std::pair<std::unique_ptr<NACP>, VirtualFile> GetControlMetadata() const;
// Version of GetControlMetadata that takes an arbitrary NCA

View File

@@ -645,6 +645,20 @@ ContentProviderUnion::ListEntriesFilterOrigin(std::optional<ContentProviderUnion
return out;
}
std::optional<ContentProviderUnionSlot> ContentProviderUnion::GetSlotForEntry(
u64 title_id, ContentRecordType type) const {
const auto iter =
std::find_if(providers.begin(), providers.end(), [title_id, type](const auto& provider) {
return provider.second != nullptr && provider.second->HasEntry(title_id, type);
});
if (iter == providers.end()) {
return std::nullopt;
}
return iter->first;
}
ManualContentProvider::~ManualContentProvider() = default;
void ManualContentProvider::AddEntry(TitleType title_type, ContentRecordType content_type,

View File

@@ -199,6 +199,9 @@ public:
std::optional<TitleType> title_type = {}, std::optional<ContentRecordType> record_type = {},
std::optional<u64> title_id = {}) const;
std::optional<ContentProviderUnionSlot> GetSlotForEntry(u64 title_id,
ContentRecordType type) const;
private:
std::map<ContentProviderUnionSlot, ContentProvider*> providers;
};

View File

@@ -7,38 +7,9 @@
namespace Core::Frontend {
ParentalControlsApplet::~ParentalControlsApplet() = default;
DefaultParentalControlsApplet::~DefaultParentalControlsApplet() = default;
void DefaultParentalControlsApplet::VerifyPIN(std::function<void(bool)> 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<void(bool)> finished) {
LOG_INFO(Service_AM,
"Application requested frontend to verify PIN (settings), verifying as correct.");
finished(true);
}
void DefaultParentalControlsApplet::RegisterPIN(std::function<void()> finished) {
LOG_INFO(Service_AM, "Application requested frontend to register new PIN");
finished();
}
void DefaultParentalControlsApplet::ChangePIN(std::function<void()> finished) {
LOG_INFO(Service_AM, "Application requested frontend to change PIN to new value");
finished();
}
PhotoViewerApplet::~PhotoViewerApplet() = default;
DefaultPhotoViewerApplet::~DefaultPhotoViewerApplet() = default;
DefaultPhotoViewerApplet::~DefaultPhotoViewerApplet() {}
void DefaultPhotoViewerApplet::ShowPhotosForApplication(u64 title_id,
std::function<void()> finished) const {
@@ -53,72 +24,4 @@ void DefaultPhotoViewerApplet::ShowAllPhotos(std::function<void()> finished) con
finished();
}
ECommerceApplet::~ECommerceApplet() = default;
DefaultECommerceApplet::~DefaultECommerceApplet() = default;
void DefaultECommerceApplet::ShowApplicationInformation(
std::function<void()> finished, u64 title_id, std::optional<u128> user_id,
std::optional<bool> full_display, std::optional<std::string> 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, value[1], value[0],
full_display.has_value() ? fmt::format("{}", *full_display) : "null",
extra_parameter.value_or("null"));
finished();
}
void DefaultECommerceApplet::ShowAddOnContentList(std::function<void()> finished, u64 title_id,
std::optional<u128> user_id,
std::optional<bool> 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, value[1], value[0],
full_display.has_value() ? fmt::format("{}", *full_display) : "null");
finished();
}
void DefaultECommerceApplet::ShowSubscriptionList(std::function<void()> finished, u64 title_id,
std::optional<u128> 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, value[1], value[0]);
finished();
}
void DefaultECommerceApplet::ShowConsumableItemList(std::function<void()> finished, u64 title_id,
std::optional<u128> 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, value[1], value[0]);
finished();
}
void DefaultECommerceApplet::ShowShopHome(std::function<void()> 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<void()> 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

View File

@@ -5,43 +5,10 @@
#pragma once
#include <functional>
#include <optional>
#include "common/common_types.h"
namespace Core::Frontend {
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<void(bool)> 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<void(bool)> finished) = 0;
// Prompts the user to create a new PIN for pctl and stores it with the service.
virtual void RegisterPIN(std::function<void()> finished) = 0;
// Prompts the user to verify the current PIN and then store a new one into pctl.
virtual void ChangePIN(std::function<void()> finished) = 0;
};
class DefaultParentalControlsApplet final : public ParentalControlsApplet {
public:
~DefaultParentalControlsApplet() override;
void VerifyPIN(std::function<void(bool)> finished,
bool suspend_future_verification_temporarily) override;
void VerifyPINForSettings(std::function<void(bool)> finished) override;
void RegisterPIN(std::function<void()> finished) override;
void ChangePIN(std::function<void()> finished) override;
};
class PhotoViewerApplet {
public:
virtual ~PhotoViewerApplet();
@@ -58,55 +25,4 @@ public:
void ShowAllPhotos(std::function<void()> finished) const override;
};
class ECommerceApplet {
public:
virtual ~ECommerceApplet();
// Shows a page with application icons, description, name, and price.
virtual void ShowApplicationInformation(std::function<void()> finished, u64 title_id,
std::optional<u128> user_id = {},
std::optional<bool> full_display = {},
std::optional<std::string> 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<void()> finished, u64 title_id,
std::optional<u128> user_id = {},
std::optional<bool> 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<void()> finished, u64 title_id,
std::optional<u128> 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<void()> finished, u64 title_id,
std::optional<u128> user_id = {}) = 0;
// Shows the home page of the shop.
virtual void ShowShopHome(std::function<void()> finished, u128 user_id, bool full_display) = 0;
// Shows the user settings page of the shop.
virtual void ShowSettings(std::function<void()> finished, u128 user_id, bool full_display) = 0;
};
class DefaultECommerceApplet : public ECommerceApplet {
public:
~DefaultECommerceApplet() override;
void ShowApplicationInformation(std::function<void()> finished, u64 title_id,
std::optional<u128> user_id, std::optional<bool> full_display,
std::optional<std::string> extra_parameter) override;
void ShowAddOnContentList(std::function<void()> finished, u64 title_id,
std::optional<u128> user_id,
std::optional<bool> full_display) override;
void ShowSubscriptionList(std::function<void()> finished, u64 title_id,
std::optional<u128> user_id) override;
void ShowConsumableItemList(std::function<void()> finished, u64 title_id,
std::optional<u128> user_id) override;
void ShowShopHome(std::function<void()> finished, u128 user_id, bool full_display) override;
void ShowSettings(std::function<void()> finished, u128 user_id, bool full_display) override;
};
} // namespace Core::Frontend

View File

@@ -11,9 +11,9 @@ WebBrowserApplet::~WebBrowserApplet() = default;
DefaultWebBrowserApplet::~DefaultWebBrowserApplet() = default;
void DefaultWebBrowserApplet::OpenPageLocal(std::string_view filename,
std::function<void()> unpack_romfs_callback,
std::function<void()> finished_callback) {
void DefaultWebBrowserApplet::OpenPage(std::string_view filename,
std::function<void()> unpack_romfs_callback,
std::function<void()> finished_callback) {
LOG_INFO(Service_AM,
"(STUBBED) called - No suitable web browser implementation found to open website page "
"at '{}'!",

View File

@@ -13,16 +13,16 @@ class WebBrowserApplet {
public:
virtual ~WebBrowserApplet();
virtual void OpenPageLocal(std::string_view url, std::function<void()> unpack_romfs_callback,
std::function<void()> finished_callback) = 0;
virtual void OpenPage(std::string_view url, std::function<void()> unpack_romfs_callback,
std::function<void()> finished_callback) = 0;
};
class DefaultWebBrowserApplet final : public WebBrowserApplet {
public:
~DefaultWebBrowserApplet() override;
void OpenPageLocal(std::string_view url, std::function<void()> unpack_romfs_callback,
std::function<void()> finished_callback) override;
void OpenPage(std::string_view url, std::function<void()> unpack_romfs_callback,
std::function<void()> finished_callback) override;
};
} // namespace Core::Frontend

View File

@@ -887,9 +887,7 @@ void IStorageAccessor::Read(Kernel::HLERequestContext& ctx) {
rb.Push(RESULT_SUCCESS);
}
ILibraryAppletCreator::ILibraryAppletCreator(u64 current_process_title_id)
: ServiceFramework("ILibraryAppletCreator"),
current_process_title_id(current_process_title_id) {
ILibraryAppletCreator::ILibraryAppletCreator() : ServiceFramework("ILibraryAppletCreator") {
static const FunctionInfo functions[] = {
{0, &ILibraryAppletCreator::CreateLibraryApplet, "CreateLibraryApplet"},
{1, nullptr, "TerminateAllLibraryApplets"},
@@ -912,7 +910,7 @@ void ILibraryAppletCreator::CreateLibraryApplet(Kernel::HLERequestContext& ctx)
static_cast<u32>(applet_id), applet_mode);
const auto& applet_manager{Core::System::GetInstance().GetAppletManager()};
const auto applet = applet_manager.GetApplet(applet_id, current_process_title_id);
const auto applet = applet_manager.GetApplet(applet_id);
if (applet == nullptr) {
LOG_ERROR(Service_AM, "Applet doesn't exist! applet_id={}", static_cast<u32>(applet_id));
@@ -1236,13 +1234,13 @@ void IApplicationFunctions::GetSaveDataSize(Kernel::HLERequestContext& ctx) {
}
void InstallInterfaces(SM::ServiceManager& service_manager,
std::shared_ptr<NVFlinger::NVFlinger> nvflinger, Core::System& system) {
std::shared_ptr<NVFlinger::NVFlinger> nvflinger) {
auto message_queue = std::make_shared<AppletMessageQueue>();
message_queue->PushMessage(AppletMessageQueue::AppletMessage::FocusStateChanged); // Needed on
// game boot
std::make_shared<AppletAE>(nvflinger, message_queue, system)->InstallAsService(service_manager);
std::make_shared<AppletOE>(nvflinger, message_queue, system)->InstallAsService(service_manager);
std::make_shared<AppletAE>(nvflinger, message_queue)->InstallAsService(service_manager);
std::make_shared<AppletOE>(nvflinger, message_queue)->InstallAsService(service_manager);
std::make_shared<IdleSys>()->InstallAsService(service_manager);
std::make_shared<OMM>()->InstallAsService(service_manager);
std::make_shared<SPSM>()->InstallAsService(service_manager);

View File

@@ -201,15 +201,13 @@ private:
class ILibraryAppletCreator final : public ServiceFramework<ILibraryAppletCreator> {
public:
ILibraryAppletCreator(u64 current_process_title_id);
ILibraryAppletCreator();
~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<IApplicationFunctions> {
@@ -266,7 +264,7 @@ public:
/// Registers all AM services with the specified service manager.
void InstallInterfaces(SM::ServiceManager& service_manager,
std::shared_ptr<NVFlinger::NVFlinger> nvflinger, Core::System& system);
std::shared_ptr<NVFlinger::NVFlinger> nvflinger);
} // namespace AM
} // namespace Service

View File

@@ -4,7 +4,6 @@
#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"
@@ -14,10 +13,9 @@ namespace Service::AM {
class ILibraryAppletProxy final : public ServiceFramework<ILibraryAppletProxy> {
public:
explicit ILibraryAppletProxy(std::shared_ptr<NVFlinger::NVFlinger> nvflinger,
std::shared_ptr<AppletMessageQueue> msg_queue,
Core::System& system)
std::shared_ptr<AppletMessageQueue> msg_queue)
: ServiceFramework("ILibraryAppletProxy"), nvflinger(std::move(nvflinger)),
msg_queue(std::move(msg_queue)), system(system) {
msg_queue(std::move(msg_queue)) {
// clang-format off
static const FunctionInfo functions[] = {
{0, &ILibraryAppletProxy::GetCommonStateGetter, "GetCommonStateGetter"},
@@ -98,7 +96,7 @@ private:
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<ILibraryAppletCreator>(system.CurrentProcess()->GetTitleID());
rb.PushIpcInterface<ILibraryAppletCreator>();
}
void GetApplicationFunctions(Kernel::HLERequestContext& ctx) {
@@ -111,15 +109,14 @@ private:
std::shared_ptr<NVFlinger::NVFlinger> nvflinger;
std::shared_ptr<AppletMessageQueue> msg_queue;
Core::System& system;
};
class ISystemAppletProxy final : public ServiceFramework<ISystemAppletProxy> {
public:
explicit ISystemAppletProxy(std::shared_ptr<NVFlinger::NVFlinger> nvflinger,
std::shared_ptr<AppletMessageQueue> msg_queue, Core::System& system)
std::shared_ptr<AppletMessageQueue> msg_queue)
: ServiceFramework("ISystemAppletProxy"), nvflinger(std::move(nvflinger)),
msg_queue(std::move(msg_queue)), system(system) {
msg_queue(std::move(msg_queue)) {
// clang-format off
static const FunctionInfo functions[] = {
{0, &ISystemAppletProxy::GetCommonStateGetter, "GetCommonStateGetter"},
@@ -194,7 +191,7 @@ private:
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<ILibraryAppletCreator>(system.CurrentProcess()->GetTitleID());
rb.PushIpcInterface<ILibraryAppletCreator>();
}
void GetHomeMenuFunctions(Kernel::HLERequestContext& ctx) {
@@ -222,7 +219,6 @@ private:
}
std::shared_ptr<NVFlinger::NVFlinger> nvflinger;
std::shared_ptr<AppletMessageQueue> msg_queue;
Core::System& system;
};
void AppletAE::OpenSystemAppletProxy(Kernel::HLERequestContext& ctx) {
@@ -230,7 +226,7 @@ void AppletAE::OpenSystemAppletProxy(Kernel::HLERequestContext& ctx) {
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<ISystemAppletProxy>(nvflinger, msg_queue, system);
rb.PushIpcInterface<ISystemAppletProxy>(nvflinger, msg_queue);
}
void AppletAE::OpenLibraryAppletProxy(Kernel::HLERequestContext& ctx) {
@@ -238,7 +234,7 @@ void AppletAE::OpenLibraryAppletProxy(Kernel::HLERequestContext& ctx) {
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<ILibraryAppletProxy>(nvflinger, msg_queue, system);
rb.PushIpcInterface<ILibraryAppletProxy>(nvflinger, msg_queue);
}
void AppletAE::OpenLibraryAppletProxyOld(Kernel::HLERequestContext& ctx) {
@@ -246,13 +242,13 @@ void AppletAE::OpenLibraryAppletProxyOld(Kernel::HLERequestContext& ctx) {
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<ILibraryAppletProxy>(nvflinger, msg_queue, system);
rb.PushIpcInterface<ILibraryAppletProxy>(nvflinger, msg_queue);
}
AppletAE::AppletAE(std::shared_ptr<NVFlinger::NVFlinger> nvflinger,
std::shared_ptr<AppletMessageQueue> msg_queue, Core::System& system)
std::shared_ptr<AppletMessageQueue> msg_queue)
: ServiceFramework("appletAE"), nvflinger(std::move(nvflinger)),
msg_queue(std::move(msg_queue)), system(system) {
msg_queue(std::move(msg_queue)) {
// clang-format off
static const FunctionInfo functions[] = {
{100, &AppletAE::OpenSystemAppletProxy, "OpenSystemAppletProxy"},

View File

@@ -18,7 +18,7 @@ namespace AM {
class AppletAE final : public ServiceFramework<AppletAE> {
public:
explicit AppletAE(std::shared_ptr<NVFlinger::NVFlinger> nvflinger,
std::shared_ptr<AppletMessageQueue> msg_queue, Core::System& system);
std::shared_ptr<AppletMessageQueue> msg_queue);
~AppletAE() override;
const std::shared_ptr<AppletMessageQueue>& GetMessageQueue() const;
@@ -30,7 +30,6 @@ private:
std::shared_ptr<NVFlinger::NVFlinger> nvflinger;
std::shared_ptr<AppletMessageQueue> msg_queue;
Core::System& system;
};
} // namespace AM

View File

@@ -4,7 +4,6 @@
#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"
@@ -14,9 +13,9 @@ namespace Service::AM {
class IApplicationProxy final : public ServiceFramework<IApplicationProxy> {
public:
explicit IApplicationProxy(std::shared_ptr<NVFlinger::NVFlinger> nvflinger,
std::shared_ptr<AppletMessageQueue> msg_queue, Core::System& system)
std::shared_ptr<AppletMessageQueue> msg_queue)
: ServiceFramework("IApplicationProxy"), nvflinger(std::move(nvflinger)),
msg_queue(std::move(msg_queue)), system(system) {
msg_queue(std::move(msg_queue)) {
// clang-format off
static const FunctionInfo functions[] = {
{0, &IApplicationProxy::GetCommonStateGetter, "GetCommonStateGetter"},
@@ -88,7 +87,7 @@ private:
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<ILibraryAppletCreator>(system.CurrentProcess()->GetTitleID());
rb.PushIpcInterface<ILibraryAppletCreator>();
}
void GetApplicationFunctions(Kernel::HLERequestContext& ctx) {
@@ -101,7 +100,6 @@ private:
std::shared_ptr<NVFlinger::NVFlinger> nvflinger;
std::shared_ptr<AppletMessageQueue> msg_queue;
Core::System& system;
};
void AppletOE::OpenApplicationProxy(Kernel::HLERequestContext& ctx) {
@@ -109,13 +107,13 @@ void AppletOE::OpenApplicationProxy(Kernel::HLERequestContext& ctx) {
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<IApplicationProxy>(nvflinger, msg_queue, system);
rb.PushIpcInterface<IApplicationProxy>(nvflinger, msg_queue);
}
AppletOE::AppletOE(std::shared_ptr<NVFlinger::NVFlinger> nvflinger,
std::shared_ptr<AppletMessageQueue> msg_queue, Core::System& system)
std::shared_ptr<AppletMessageQueue> msg_queue)
: ServiceFramework("appletOE"), nvflinger(std::move(nvflinger)),
msg_queue(std::move(msg_queue)), system(system) {
msg_queue(std::move(msg_queue)) {
static const FunctionInfo functions[] = {
{0, &AppletOE::OpenApplicationProxy, "OpenApplicationProxy"},
};

View File

@@ -18,7 +18,7 @@ namespace AM {
class AppletOE final : public ServiceFramework<AppletOE> {
public:
explicit AppletOE(std::shared_ptr<NVFlinger::NVFlinger> nvflinger,
std::shared_ptr<AppletMessageQueue> msg_queue, Core::System& system);
std::shared_ptr<AppletMessageQueue> msg_queue);
~AppletOE() override;
const std::shared_ptr<AppletMessageQueue>& GetMessageQueue() const;
@@ -28,7 +28,6 @@ private:
std::shared_ptr<NVFlinger::NVFlinger> nvflinger;
std::shared_ptr<AppletMessageQueue> msg_queue;
Core::System& system;
};
} // namespace AM

View File

@@ -139,14 +139,12 @@ void Applet::Initialize() {
AppletFrontendSet::AppletFrontendSet() = default;
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(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() = default;
@@ -159,8 +157,6 @@ 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)
@@ -171,21 +167,17 @@ 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() {
ClearAll();
SetDefaultAppletsIfMissing();
frontend.error = std::make_unique<Core::Frontend::DefaultErrorApplet>();
frontend.photo_viewer = std::make_unique<Core::Frontend::DefaultPhotoViewerApplet>();
frontend.profile_select = std::make_unique<Core::Frontend::DefaultProfileSelectApplet>();
frontend.software_keyboard = std::make_unique<Core::Frontend::DefaultSoftwareKeyboardApplet>();
frontend.web_browser = std::make_unique<Core::Frontend::DefaultWebBrowserApplet>();
}
void AppletManager::SetDefaultAppletsIfMissing() {
if (frontend.parental_controls == nullptr) {
frontend.parental_controls =
std::make_unique<Core::Frontend::DefaultParentalControlsApplet>();
}
if (frontend.error == nullptr) {
frontend.error = std::make_unique<Core::Frontend::DefaultErrorApplet>();
}
@@ -206,20 +198,14 @@ void AppletManager::SetDefaultAppletsIfMissing() {
if (frontend.web_browser == nullptr) {
frontend.web_browser = std::make_unique<Core::Frontend::DefaultWebBrowserApplet>();
}
if (frontend.e_commerce == nullptr) {
frontend.e_commerce = std::make_unique<Core::Frontend::DefaultECommerceApplet>();
}
}
void AppletManager::ClearAll() {
frontend = {};
}
std::shared_ptr<Applet> AppletManager::GetApplet(AppletId id, u64 current_process_title_id) const {
std::shared_ptr<Applet> AppletManager::GetApplet(AppletId id) const {
switch (id) {
case AppletId::Auth:
return std::make_shared<Auth>(*frontend.parental_controls);
case AppletId::Error:
return std::make_shared<Error>(*frontend.error);
case AppletId::ProfileSelect:
@@ -228,11 +214,8 @@ std::shared_ptr<Applet> AppletManager::GetApplet(AppletId id, u64 current_proces
return std::make_shared<SoftwareKeyboard>(*frontend.software_keyboard);
case AppletId::PhotoViewer:
return std::make_shared<PhotoViewer>(*frontend.photo_viewer);
case AppletId::LibAppletShop:
return std::make_shared<WebBrowser>(*frontend.web_browser, current_process_title_id,
frontend.e_commerce.get());
case AppletId::LibAppletOff:
return std::make_shared<WebBrowser>(*frontend.web_browser, current_process_title_id);
return std::make_shared<WebBrowser>(*frontend.web_browser);
default:
UNIMPLEMENTED_MSG(
"No backend implementation exists for applet_id={:02X}! Falling back to stub applet.",

View File

@@ -13,9 +13,7 @@
union ResultCode;
namespace Core::Frontend {
class ECommerceApplet;
class ErrorApplet;
class ParentalControlsApplet;
class PhotoViewerApplet;
class ProfileSelectApplet;
class SoftwareKeyboardApplet;
@@ -147,19 +145,15 @@ protected:
};
struct AppletFrontendSet {
using ParentalControlsApplet = std::unique_ptr<Core::Frontend::ParentalControlsApplet>;
using ErrorApplet = std::unique_ptr<Core::Frontend::ErrorApplet>;
using PhotoViewer = std::unique_ptr<Core::Frontend::PhotoViewerApplet>;
using ProfileSelect = std::unique_ptr<Core::Frontend::ProfileSelectApplet>;
using SoftwareKeyboard = std::unique_ptr<Core::Frontend::SoftwareKeyboardApplet>;
using WebBrowser = std::unique_ptr<Core::Frontend::WebBrowserApplet>;
using ECommerceApplet = std::unique_ptr<Core::Frontend::ECommerceApplet>;
AppletFrontendSet();
AppletFrontendSet(ParentalControlsApplet parental_controls, ErrorApplet error,
PhotoViewer photo_viewer, ProfileSelect profile_select,
SoftwareKeyboard software_keyboard, WebBrowser web_browser,
ECommerceApplet e_commerce);
AppletFrontendSet(ErrorApplet error, PhotoViewer photo_viewer, ProfileSelect profile_select,
SoftwareKeyboard software_keyboard, WebBrowser web_browser);
~AppletFrontendSet();
AppletFrontendSet(const AppletFrontendSet&) = delete;
@@ -168,13 +162,11 @@ 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 {
@@ -187,7 +179,7 @@ public:
void SetDefaultAppletsIfMissing();
void ClearAll();
std::shared_ptr<Applet> GetApplet(AppletId id, u64 current_process_title_id) const;
std::shared_ptr<Applet> GetApplet(AppletId id) const;
private:
AppletFrontendSet frontend;

View File

@@ -17,8 +17,6 @@
namespace Service::AM::Applets {
constexpr ResultCode ERROR_INVALID_PIN{ErrorModule::PCTL, 221};
static void LogCurrentStorage(AppletDataBroker& broker, std::string_view prefix) {
std::unique_ptr<IStorage> storage = broker.PopNormalDataToApplet();
for (; storage != nullptr; storage = broker.PopNormalDataToApplet()) {
@@ -37,120 +35,6 @@ 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<u32>(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<bool>(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<u8> 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;

View File

@@ -8,36 +8,6 @@
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,

View File

@@ -19,9 +19,7 @@
#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"
@@ -30,187 +28,74 @@
namespace Service::AM::Applets {
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,
};
// 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;
enum class ShimKind : u32 {
Shop = 1,
Login = 2,
Offline = 3,
Share = 4,
Web = 5,
Wifi = 6,
Lobby = 7,
};
enum class ShopWebTarget {
ApplicationInfo,
AddOnContentList,
SubscriptionList,
ConsumableItemList,
Home,
Settings,
};
namespace {
constexpr std::size_t SHIM_KIND_COUNT = 0x8;
struct WebArgHeader {
struct WebBufferHeader {
u16 count;
INSERT_PADDING_BYTES(2);
ShimKind kind;
INSERT_PADDING_BYTES(6);
};
static_assert(sizeof(WebArgHeader) == 0x8, "WebArgHeader has incorrect size.");
static_assert(sizeof(WebBufferHeader) == 0x8, "WebBufferHeader has incorrect size.");
struct WebArgTLV {
WebArgTLVType type;
struct WebArgumentHeader {
u16 type;
u16 size;
u32 offset;
};
static_assert(sizeof(WebArgTLV) == 0x8, "WebArgTLV has incorrect size.");
static_assert(sizeof(WebArgumentHeader) == 0x8, "WebArgumentHeader has incorrect size.");
struct WebCommonReturnValue {
struct WebArgumentResult {
u32 result_code;
INSERT_PADDING_BYTES(0x4);
std::array<char, 0x1000> last_url;
u64 last_url_size;
};
static_assert(sizeof(WebCommonReturnValue) == 0x1010, "WebCommonReturnValue has incorrect size.");
static_assert(sizeof(WebArgumentResult) == 0x1010, "WebArgumentResult has incorrect size.");
struct WebWifiPageArg {
INSERT_PADDING_BYTES(4);
std::array<char, 0x100> connection_test_url;
std::array<char, 0x400> initial_url;
std::array<u8, 0x10> nifm_network_uuid;
u32 nifm_requirement;
};
static_assert(sizeof(WebWifiPageArg) == 0x518, "WebWifiPageArg has incorrect size.");
static std::vector<u8> GetArgumentDataForTagType(const std::vector<u8>& data, u16 type) {
WebBufferHeader header;
ASSERT(sizeof(WebBufferHeader) <= data.size());
std::memcpy(&header, data.data(), sizeof(WebBufferHeader));
struct WebWifiReturnValue {
INSERT_PADDING_BYTES(4);
u32 result;
};
static_assert(sizeof(WebWifiReturnValue) == 0x8, "WebWifiReturnValue 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);
enum class OfflineWebSource : u32 {
OfflineHtmlPage = 0x1,
ApplicationLegalInformation = 0x2,
SystemDataPage = 0x3,
};
std::map<WebArgTLVType, std::vector<u8>> GetWebArguments(const std::vector<u8>& arg) {
if (arg.size() < sizeof(WebArgHeader))
return {};
WebArgHeader header{};
std::memcpy(&header, arg.data(), sizeof(WebArgHeader));
std::map<WebArgTLVType, std::vector<u8>> out;
u64 offset = sizeof(WebArgHeader);
for (std::size_t i = 0; i < header.count; ++i) {
if (arg.size() < (offset + sizeof(WebArgTLV)))
if (arg.type == type) {
std::vector<u8> out(arg.size);
offset += arg.offset;
ASSERT(offset + arg.size <= data.size());
std::memcpy(out.data(), data.data() + offset, out.size());
return out;
}
WebArgTLV tlv{};
std::memcpy(&tlv, arg.data() + offset, sizeof(WebArgTLV));
offset += sizeof(WebArgTLV);
offset += tlv.offset;
if (arg.size() < (offset + tlv.size))
return out;
std::vector<u8> data(tlv.size);
std::memcpy(data.data(), arg.data() + offset, tlv.size);
offset += tlv.size;
out.insert_or_assign(tlv.type, data);
offset += arg.offset + arg.size;
}
return out;
return {};
}
FileSys::VirtualFile GetApplicationRomFS(u64 title_id, FileSys::ContentRecordType type) {
static FileSys::VirtualFile GetManualRomFS() {
auto& loader{Core::System::GetInstance().GetAppLoader()};
FileSys::VirtualFile out;
if (loader.ReadManualRomFS(out) == Loader::ResultStatus::Success)
return out;
const auto& installed{Core::System::GetInstance().GetContentProvider()};
const auto res = installed.GetEntry(title_id, type);
const auto res = installed.GetEntry(Core::System::GetInstance().CurrentProcess()->GetTitleID(),
FileSys::ContentRecordType::Manual);
if (res != nullptr) {
if (res != nullptr)
return res->GetRomFS();
}
if (type == FileSys::ContentRecordType::Data) {
return FileSys::SystemArchive::SynthesizeSystemArchive(title_id);
}
return nullptr;
}
} // Anonymous namespace
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),
current_process_title_id(current_process_title_id) {}
WebBrowser::WebBrowser(Core::Frontend::WebBrowserApplet& frontend) : frontend(frontend) {}
WebBrowser::~WebBrowser() = default;
@@ -226,12 +111,24 @@ void WebBrowser::Initialize() {
ASSERT(web_arg_storage != nullptr);
const auto& web_arg = web_arg_storage->GetData();
ASSERT(web_arg.size() >= 0x8);
std::memcpy(&kind, web_arg.data() + 0x4, sizeof(ShimKind));
const auto url_data = GetArgumentDataForTagType(web_arg, WEB_ARGUMENT_URL_TYPE);
filename = Common::StringFromFixedZeroTerminatedBuffer(
reinterpret_cast<const char*>(url_data.data()), url_data.size());
args = GetWebArguments(web_arg);
temporary_dir = FileUtil::SanitizePath(FileUtil::GetUserPath(FileUtil::UserPath::CacheDir) +
"web_applet_manual",
FileUtil::DirectorySeparator::PlatformDefault);
FileUtil::DeleteDirRecursively(temporary_dir);
InitializeInternal();
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);
}
bool WebBrowser::TransactionComplete() const {
@@ -247,25 +144,24 @@ void WebBrowser::ExecuteInteractive() {
}
void WebBrowser::Execute() {
if (complete) {
if (complete)
return;
}
if (status != RESULT_SUCCESS) {
complete = true;
return;
}
ExecuteInternal();
frontend.OpenPage(filename, [this] { UnpackRomFS(); }, [this] { Finalize(); });
}
void WebBrowser::UnpackRomFS() {
if (unpacked)
return;
ASSERT(offline_romfs != nullptr);
ASSERT(manual_romfs != nullptr);
const auto dir =
FileSys::ExtractRomFS(offline_romfs, FileSys::RomFSExtractionType::SingleDiscard);
FileSys::ExtractRomFS(manual_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);
@@ -276,275 +172,17 @@ void WebBrowser::UnpackRomFS() {
void WebBrowser::Finalize() {
complete = true;
WebCommonReturnValue out{};
WebArgumentResult out{};
out.result_code = 0;
out.last_url_size = 0;
std::vector<u8> data(sizeof(WebCommonReturnValue));
std::memcpy(data.data(), &out, sizeof(WebCommonReturnValue));
std::vector<u8> data(sizeof(WebArgumentResult));
std::memcpy(data.data(), &out, sizeof(WebArgumentResult));
broker.PushNormalDataFromApplet(IStorage{data});
broker.SignalStateChanged();
if (!temporary_dir.empty() && FileUtil::IsDirectory(temporary_dir)) {
FileUtil::DeleteDirRecursively(temporary_dir);
}
}
void WebBrowser::InitializeInternal() {
using WebAppletInitializer = void (WebBrowser::*)();
constexpr std::array<WebAppletInitializer, SHIM_KIND_COUNT> functions{
nullptr, &WebBrowser::InitializeShop,
nullptr, &WebBrowser::InitializeOffline,
nullptr, nullptr,
nullptr, nullptr,
};
const auto index = static_cast<u32>(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<WebAppletExecutor, SHIM_KIND_COUNT> functions{
nullptr, &WebBrowser::ExecuteShop,
nullptr, &WebBrowser::ExecuteOffline,
nullptr, nullptr,
nullptr, nullptr,
};
const auto index = static_cast<u32>(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<std::string> split_query;
Common::SplitString(Common::StringFromFixedZeroTerminatedBuffer(
reinterpret_cast<const char*>(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<std::string> queries;
Common::SplitString(split_query[1], '&', queries);
const auto split_single_query =
[](const std::string& in) -> std::pair<std::string, std::string> {
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<std::string, ShopWebTarget, std::less<>> 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<const char*>(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<const char*, 3> WEB_SOURCE_NAMES{
"manual",
"legal",
"system",
};
temporary_dir =
FileUtil::SanitizePath(FileUtil::GetUserPath(FileUtil::UserPath::CacheDir) + "web_applet_" +
WEB_SOURCE_NAMES[static_cast<u32>(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 = current_process_title_id;
}
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).append("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

View File

@@ -4,22 +4,15 @@
#pragma once
#include <map>
#include "core/file_sys/vfs_types.h"
#include "core/hle/service/am/am.h"
#include "core/hle/service/am/applets/applets.h"
namespace Service::AM::Applets {
enum class ShimKind : u32;
enum class ShopWebTarget;
enum class WebArgTLVType : u16;
class WebBrowser final : public Applet {
public:
WebBrowser(Core::Frontend::WebBrowserApplet& frontend, u64 current_process_title_id,
Core::Frontend::ECommerceApplet* frontend_e_commerce = nullptr);
WebBrowser(Core::Frontend::WebBrowserApplet& frontend);
~WebBrowser() override;
void Initialize() override;
@@ -39,41 +32,15 @@ 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;
// Extra frontends for specialized functions
Core::Frontend::ECommerceApplet* frontend_e_commerce;
bool complete = false;
bool unpacked = false;
ResultCode status = RESULT_SUCCESS;
u64 current_process_title_id;
ShimKind kind;
std::map<WebArgTLVType, std::vector<u8>> args;
FileSys::VirtualFile offline_romfs;
FileSys::VirtualFile manual_romfs;
std::string temporary_dir;
std::string filename;
ShopWebTarget shop_web_target;
std::map<std::string, std::string, std::less<>> shop_query;
std::optional<u64> title_id = 0;
std::optional<u128> user_id;
std::optional<bool> shop_full_display;
std::string shop_extra_parameter;
};
} // namespace Service::AM::Applets

View File

@@ -1,75 +0,0 @@
// Copyright 2018 yuzu emulator team
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include <memory>
#include "common/logging/log.h"
#include "core/hle/ipc_helpers.h"
#include "core/hle/kernel/hle_ipc.h"
#include "core/hle/service/arp/arp.h"
#include "core/hle/service/service.h"
#include "core/hle/service/sm/sm.h"
namespace Service::ARP {
class ARP_R final : public ServiceFramework<ARP_R> {
public:
explicit ARP_R() : ServiceFramework{"arp:r"} {
// clang-format off
static const FunctionInfo functions[] = {
{0, nullptr, "GetApplicationLaunchProperty"},
{1, nullptr, "GetApplicationLaunchPropertyWithApplicationId"},
{2, nullptr, "GetApplicationControlProperty"},
{3, nullptr, "GetApplicationControlPropertyWithApplicationId"},
};
// clang-format on
RegisterHandlers(functions);
}
};
class IRegistrar final : public ServiceFramework<IRegistrar> {
public:
explicit IRegistrar() : ServiceFramework{"IRegistrar"} {
// clang-format off
static const FunctionInfo functions[] = {
{0, nullptr, "Issue"},
{1, nullptr, "SetApplicationLaunchProperty"},
{2, nullptr, "SetApplicationControlProperty"},
};
// clang-format on
RegisterHandlers(functions);
}
};
class ARP_W final : public ServiceFramework<ARP_W> {
public:
explicit ARP_W() : ServiceFramework{"arp:w"} {
// clang-format off
static const FunctionInfo functions[] = {
{0, &ARP_W::AcquireRegistrar, "AcquireRegistrar"},
{1, nullptr, "DeleteProperties"},
};
// clang-format on
RegisterHandlers(functions);
}
private:
void AcquireRegistrar(Kernel::HLERequestContext& ctx) {
LOG_DEBUG(Service_ARP, "called");
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<IRegistrar>();
}
};
void InstallInterfaces(SM::ServiceManager& sm) {
std::make_shared<ARP_R>()->InstallAsService(sm);
std::make_shared<ARP_W>()->InstallAsService(sm);
}
} // namespace Service::ARP

View File

@@ -1,16 +0,0 @@
// Copyright 2018 yuzu emulator team
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
namespace Service::SM {
class ServiceManager;
}
namespace Service::ARP {
/// Registers all ARP services with the specified service manager.
void InstallInterfaces(SM::ServiceManager& sm);
} // namespace Service::ARP

View File

@@ -0,0 +1,297 @@
// Copyright 2018 yuzu emulator team
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include <memory>
#include "common/logging/log.h"
#include "core/file_sys/control_metadata.h"
#include "core/hle/ipc_helpers.h"
#include "core/hle/kernel/hle_ipc.h"
#include "core/hle/kernel/kernel.h"
#include "core/hle/kernel/process.h"
#include "core/hle/service/glue/arp.h"
#include "core/hle/service/glue/errors.h"
#include "core/hle/service/glue/manager.h"
#include "core/hle/service/service.h"
namespace Service::Glue {
namespace {
std::optional<u64> GetTitleIDForProcessID(const Core::System& system, u64 process_id) {
const auto& list = system.Kernel().GetProcessList();
const auto iter = std::find_if(list.begin(), list.end(), [&process_id](const auto& process) {
return process->GetProcessID() == process_id;
});
if (iter == list.end()) {
return std::nullopt;
}
return (*iter)->GetTitleID();
}
} // Anonymous namespace
ARP_R::ARP_R(const Core::System& system, const ARPManager& manager)
: ServiceFramework{"arp:r"}, system(system), manager(manager) {
// clang-format off
static const FunctionInfo functions[] = {
{0, &ARP_R::GetApplicationLaunchProperty, "GetApplicationLaunchProperty"},
{1, &ARP_R::GetApplicationLaunchPropertyWithApplicationId, "GetApplicationLaunchPropertyWithApplicationId"},
{2, &ARP_R::GetApplicationControlProperty, "GetApplicationControlProperty"},
{3, &ARP_R::GetApplicationControlPropertyWithApplicationId, "GetApplicationControlPropertyWithApplicationId"},
};
// clang-format on
RegisterHandlers(functions);
}
ARP_R::~ARP_R() = default;
void ARP_R::GetApplicationLaunchProperty(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto process_id = rp.PopRaw<u64>();
LOG_DEBUG(Service_ARP, "called, process_id={:016X}", process_id);
const auto title_id = GetTitleIDForProcessID(system, process_id);
if (!title_id.has_value()) {
LOG_ERROR(Service_ARP, "Failed to get title ID for process ID!");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ERR_NOT_REGISTERED);
return;
}
const auto res = manager.GetLaunchProperty(*title_id);
if (res.Failed()) {
LOG_ERROR(Service_ARP, "Failed to get launch property!");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(res.Code());
return;
}
IPC::ResponseBuilder rb{ctx, 6};
rb.Push(RESULT_SUCCESS);
rb.PushRaw(*res);
}
void ARP_R::GetApplicationLaunchPropertyWithApplicationId(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto title_id = rp.PopRaw<u64>();
LOG_DEBUG(Service_ARP, "called, title_id={:016X}", title_id);
const auto res = manager.GetLaunchProperty(title_id);
if (res.Failed()) {
LOG_ERROR(Service_ARP, "Failed to get launch property!");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(res.Code());
return;
}
IPC::ResponseBuilder rb{ctx, 6};
rb.Push(RESULT_SUCCESS);
rb.PushRaw(*res);
}
void ARP_R::GetApplicationControlProperty(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto process_id = rp.PopRaw<u64>();
LOG_DEBUG(Service_ARP, "called, process_id={:016X}", process_id);
const auto title_id = GetTitleIDForProcessID(system, process_id);
if (!title_id.has_value()) {
LOG_ERROR(Service_ARP, "Failed to get title ID for process ID!");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ERR_NOT_REGISTERED);
return;
}
const auto res = manager.GetControlProperty(*title_id);
if (res.Failed()) {
LOG_ERROR(Service_ARP, "Failed to get control property!");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(res.Code());
return;
}
ctx.WriteBuffer(*res);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
}
void ARP_R::GetApplicationControlPropertyWithApplicationId(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto title_id = rp.PopRaw<u64>();
LOG_DEBUG(Service_ARP, "called, title_id={:016X}", title_id);
const auto res = manager.GetControlProperty(title_id);
if (res.Failed()) {
LOG_ERROR(Service_ARP, "Failed to get control property!");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(res.Code());
return;
}
ctx.WriteBuffer(*res);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
}
class IRegistrar final : public ServiceFramework<IRegistrar> {
friend class ARP_W;
public:
explicit IRegistrar(
std::function<ResultCode(u64, ApplicationLaunchProperty, std::vector<u8>)> issuer)
: ServiceFramework{"IRegistrar"}, issue_process_id(std::move(issuer)) {
// clang-format off
static const FunctionInfo functions[] = {
{0, &IRegistrar::Issue, "Issue"},
{1, &IRegistrar::SetApplicationLaunchProperty, "SetApplicationLaunchProperty"},
{2, &IRegistrar::SetApplicationControlProperty, "SetApplicationControlProperty"},
};
// clang-format on
RegisterHandlers(functions);
}
private:
void Issue(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto process_id = rp.PopRaw<u64>();
LOG_DEBUG(Service_ARP, "called, process_id={:016X}", process_id);
if (process_id == 0) {
LOG_ERROR(Service_ARP, "Must have non-zero process ID!");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ERR_INVALID_PROCESS_ID);
return;
}
if (issued) {
LOG_ERROR(Service_ARP,
"Attempted to issue registrar, but registrar is already issued!");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ERR_INVALID_ACCESS);
return;
}
issue_process_id(process_id, launch, std::move(control));
issued = true;
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
}
void SetApplicationLaunchProperty(Kernel::HLERequestContext& ctx) {
LOG_DEBUG(Service_ARP, "called");
if (issued) {
LOG_ERROR(
Service_ARP,
"Attempted to set application launch property, but registrar is already issued!");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ERR_INVALID_ACCESS);
return;
}
IPC::RequestParser rp{ctx};
launch = rp.PopRaw<ApplicationLaunchProperty>();
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
}
void SetApplicationControlProperty(Kernel::HLERequestContext& ctx) {
LOG_DEBUG(Service_ARP, "called");
if (issued) {
LOG_ERROR(
Service_ARP,
"Attempted to set application control property, but registrar is already issued!");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ERR_INVALID_ACCESS);
return;
}
control = ctx.ReadBuffer();
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
}
std::function<ResultCode(u64, ApplicationLaunchProperty, std::vector<u8>)> issue_process_id;
bool issued = false;
ApplicationLaunchProperty launch;
std::vector<u8> control;
};
ARP_W::ARP_W(const Core::System& system, ARPManager& manager)
: ServiceFramework{"arp:w"}, system(system), manager(manager) {
// clang-format off
static const FunctionInfo functions[] = {
{0, &ARP_W::AcquireRegistrar, "AcquireRegistrar"},
{1, &ARP_W::DeleteProperties, "DeleteProperties"},
};
// clang-format on
RegisterHandlers(functions);
}
ARP_W::~ARP_W() = default;
void ARP_W::AcquireRegistrar(Kernel::HLERequestContext& ctx) {
LOG_DEBUG(Service_ARP, "called");
registrar = std::make_shared<IRegistrar>(
[this](u64 process_id, ApplicationLaunchProperty launch, std::vector<u8> control) {
const auto res = GetTitleIDForProcessID(system, process_id);
if (!res.has_value()) {
return ERR_NOT_REGISTERED;
}
return manager.Register(*res, launch, std::move(control));
});
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface(registrar);
}
void ARP_W::DeleteProperties(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto process_id = rp.PopRaw<u64>();
LOG_DEBUG(Service_ARP, "called, process_id={:016X}", process_id);
if (process_id == 0) {
LOG_ERROR(Service_ARP, "Must have non-zero process ID!");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ERR_INVALID_PROCESS_ID);
return;
}
const auto title_id = GetTitleIDForProcessID(system, process_id);
if (!title_id.has_value()) {
LOG_ERROR(Service_ARP, "No title ID for process ID!");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ERR_NOT_REGISTERED);
return;
}
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(manager.Unregister(*title_id));
}
} // namespace Service::Glue

View File

@@ -0,0 +1,43 @@
// Copyright 2019 yuzu emulator team
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
#include "core/hle/service/service.h"
namespace Service::Glue {
class ARPManager;
class IRegistrar;
class ARP_R final : public ServiceFramework<ARP_R> {
public:
explicit ARP_R(const Core::System& system, const ARPManager& manager);
~ARP_R() override;
private:
void GetApplicationLaunchProperty(Kernel::HLERequestContext& ctx);
void GetApplicationLaunchPropertyWithApplicationId(Kernel::HLERequestContext& ctx);
void GetApplicationControlProperty(Kernel::HLERequestContext& ctx);
void GetApplicationControlPropertyWithApplicationId(Kernel::HLERequestContext& ctx);
const Core::System& system;
const ARPManager& manager;
};
class ARP_W final : public ServiceFramework<ARP_W> {
public:
explicit ARP_W(const Core::System& system, ARPManager& manager);
~ARP_W() override;
private:
void AcquireRegistrar(Kernel::HLERequestContext& ctx);
void DeleteProperties(Kernel::HLERequestContext& ctx);
const Core::System& system;
ARPManager& manager;
std::shared_ptr<IRegistrar> registrar;
};
} // namespace Service::Glue

View File

@@ -0,0 +1,50 @@
// Copyright 2019 yuzu emulator team
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include "core/hle/service/glue/bgtc.h"
namespace Service::Glue {
BGTC_T::BGTC_T() : ServiceFramework{"bgtc:t"} {
// clang-format off
static const FunctionInfo functions[] = {
{1, nullptr, "NotifyTaskStarting"},
{2, nullptr, "NotifyTaskFinished"},
{3, nullptr, "GetTriggerEvent"},
{4, nullptr, "IsInHalfAwake"},
{5, nullptr, "NotifyClientName"},
{6, nullptr, "IsInFullAwake"},
{11, nullptr, "ScheduleTask"},
{12, nullptr, "GetScheduledTaskInterval"},
{13, nullptr, "UnscheduleTask"},
{14, nullptr, "GetScheduleEvent"},
{15, nullptr, "SchedulePeriodicTask"},
{101, nullptr, "GetOperationMode"},
{102, nullptr, "WillDisconnectNetworkWhenEnteringSleep"},
{103, nullptr, "WillStayHalfAwakeInsteadSleep"},
};
// clang-format on
RegisterHandlers(functions);
}
BGTC_T::~BGTC_T() = default;
BGTC_SC::BGTC_SC() : ServiceFramework{"bgtc:sc"} {
// clang-format off
static const FunctionInfo functions[] = {
{1, nullptr, "GetState"},
{2, nullptr, "GetStateChangedEvent"},
{3, nullptr, "NotifyEnteringHalfAwake"},
{4, nullptr, "NotifyLeavingHalfAwake"},
{5, nullptr, "SetIsUsingSleepUnsupportedDevices"},
};
// clang-format on
RegisterHandlers(functions);
}
BGTC_SC::~BGTC_SC() = default;
} // namespace Service::Glue

View File

@@ -0,0 +1,23 @@
// Copyright 2019 yuzu emulator team
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
#include "core/hle/service/service.h"
namespace Service::Glue {
class BGTC_T final : public ServiceFramework<BGTC_T> {
public:
BGTC_T();
~BGTC_T() override;
};
class BGTC_SC final : public ServiceFramework<BGTC_SC> {
public:
BGTC_SC();
~BGTC_SC() override;
};
} // namespace Service::Glue

View File

@@ -0,0 +1,16 @@
// Copyright 2019 yuzu emulator team
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
#include "core/hle/result.h"
namespace Service::Glue {
constexpr ResultCode ERR_INVALID_RESOURCE{ErrorModule::ARP, 0x1E};
constexpr ResultCode ERR_INVALID_PROCESS_ID{ErrorModule::ARP, 0x1F};
constexpr ResultCode ERR_INVALID_ACCESS{ErrorModule::ARP, 0x2A};
constexpr ResultCode ERR_NOT_REGISTERED{ErrorModule::ARP, 0x66};
} // namespace Service::Glue

View File

@@ -0,0 +1,25 @@
// Copyright 2019 yuzu emulator team
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include <memory>
#include "core/core.h"
#include "core/hle/service/glue/arp.h"
#include "core/hle/service/glue/bgtc.h"
#include "core/hle/service/glue/glue.h"
namespace Service::Glue {
void InstallInterfaces(Core::System& system) {
// ARP
std::make_shared<ARP_R>(system, system.GetARPManager())
->InstallAsService(system.ServiceManager());
std::make_shared<ARP_W>(system, system.GetARPManager())
->InstallAsService(system.ServiceManager());
// BackGround Task Controller
std::make_shared<BGTC_T>()->InstallAsService(system.ServiceManager());
std::make_shared<BGTC_SC>()->InstallAsService(system.ServiceManager());
}
} // namespace Service::Glue

View File

@@ -0,0 +1,16 @@
// Copyright 2019 yuzu emulator team
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
namespace Core {
class System;
} // namespace Core
namespace Service::Glue {
/// Registers all Glue services with the specified service manager.
void InstallInterfaces(Core::System& system);
} // namespace Service::Glue

View File

@@ -0,0 +1,78 @@
// Copyright 2019 yuzu emulator team
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include "core/hle/service/glue/errors.h"
#include "core/hle/service/glue/manager.h"
namespace Service::Glue {
struct ARPManager::MapEntry {
ApplicationLaunchProperty launch;
std::vector<u8> control;
};
ARPManager::ARPManager() = default;
ARPManager::~ARPManager() = default;
ResultVal<ApplicationLaunchProperty> ARPManager::GetLaunchProperty(u64 title_id) const {
if (title_id == 0) {
return ERR_INVALID_PROCESS_ID;
}
const auto iter = entries.find(title_id);
if (iter == entries.end()) {
return ERR_NOT_REGISTERED;
}
return MakeResult<ApplicationLaunchProperty>(iter->second.launch);
}
ResultVal<std::vector<u8>> ARPManager::GetControlProperty(u64 title_id) const {
if (title_id == 0) {
return ERR_INVALID_PROCESS_ID;
}
const auto iter = entries.find(title_id);
if (iter == entries.end()) {
return ERR_NOT_REGISTERED;
}
return MakeResult<std::vector<u8>>(iter->second.control);
}
ResultCode ARPManager::Register(u64 title_id, ApplicationLaunchProperty launch,
std::vector<u8> control) {
if (title_id == 0) {
return ERR_INVALID_PROCESS_ID;
}
const auto iter = entries.find(title_id);
if (iter != entries.end()) {
return ERR_INVALID_ACCESS;
}
entries.insert_or_assign(title_id, MapEntry{launch, std::move(control)});
return RESULT_SUCCESS;
}
ResultCode ARPManager::Unregister(u64 title_id) {
if (title_id == 0) {
return ERR_INVALID_PROCESS_ID;
}
const auto iter = entries.find(title_id);
if (iter == entries.end()) {
return ERR_NOT_REGISTERED;
}
entries.erase(iter);
return RESULT_SUCCESS;
}
void ARPManager::ResetAll() {
entries.clear();
}
} // namespace Service::Glue

View File

@@ -0,0 +1,63 @@
// Copyright 2019 yuzu emulator team
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
#include <map>
#include <vector>
#include "common/common_types.h"
#include "core/file_sys/control_metadata.h"
#include "core/file_sys/romfs_factory.h"
#include "core/hle/result.h"
namespace Service::Glue {
struct ApplicationLaunchProperty {
u64 title_id;
u32 version;
FileSys::StorageId base_game_storage_id;
FileSys::StorageId update_storage_id;
u8 program_index;
u8 reserved;
};
static_assert(sizeof(ApplicationLaunchProperty) == 0x10,
"ApplicationLaunchProperty has incorrect size.");
// A class to manage state related to the arp:w and arp:r services, specifically the registration
// and unregistration of launch and control properties.
class ARPManager {
public:
ARPManager();
~ARPManager();
// Returns the ApplicationLaunchProperty corresponding to the provided title ID if it was
// previously registered, otherwise ERR_NOT_REGISTERED if it was never registered or
// ERR_INVALID_PROCESS_ID if the title ID is 0.
ResultVal<ApplicationLaunchProperty> GetLaunchProperty(u64 title_id) const;
// Returns a vector of the raw bytes of NACP data (necessarily 0x4000 in size) corresponding to
// the provided title ID if it was previously registered, otherwise ERR_NOT_REGISTERED if it was
// never registered or ERR_INVALID_PROCESS_ID if the title ID is 0.
ResultVal<std::vector<u8>> GetControlProperty(u64 title_id) const;
// Adds a new entry to the internal database with the provided parameters, returning
// ERR_INVALID_ACCESS if attempting to re-register a title ID without an intermediate Unregister
// step, and ERR_INVALID_PROCESS_ID if the title ID is 0.
ResultCode Register(u64 title_id, ApplicationLaunchProperty launch, std::vector<u8> control);
// Removes the registration for the provided title ID from the database, returning
// ERR_NOT_REGISTERED if it doesn't exist in the database and ERR_INVALID_PROCESS_ID if the
// title ID is 0.
ResultCode Unregister(u64 title_id);
// Removes all entries from the database, always succeeds. Should only be used when resetting
// system state.
void ResetAll();
private:
struct MapEntry;
std::map<u64, MapEntry> entries;
};
} // namespace Service::Glue

View File

@@ -19,7 +19,6 @@
#include "core/hle/service/am/am.h"
#include "core/hle/service/aoc/aoc_u.h"
#include "core/hle/service/apm/apm.h"
#include "core/hle/service/arp/arp.h"
#include "core/hle/service/audio/audio.h"
#include "core/hle/service/bcat/module.h"
#include "core/hle/service/bpc/bpc.h"
@@ -33,6 +32,7 @@
#include "core/hle/service/fgm/fgm.h"
#include "core/hle/service/filesystem/filesystem.h"
#include "core/hle/service/friend/friend.h"
#include "core/hle/service/glue/glue.h"
#include "core/hle/service/grc/grc.h"
#include "core/hle/service/hid/hid.h"
#include "core/hle/service/lbl/lbl.h"
@@ -204,10 +204,9 @@ void Init(std::shared_ptr<SM::ServiceManager>& sm, Core::System& system,
SM::ServiceManager::InstallInterfaces(sm);
Account::InstallInterfaces(system);
AM::InstallInterfaces(*sm, nv_flinger, system);
AM::InstallInterfaces(*sm, nv_flinger);
AOC::InstallInterfaces(*sm);
APM::InstallInterfaces(*sm);
ARP::InstallInterfaces(*sm);
Audio::InstallInterfaces(*sm);
BCAT::InstallInterfaces(*sm);
BPC::InstallInterfaces(*sm);
@@ -221,6 +220,7 @@ void Init(std::shared_ptr<SM::ServiceManager>& sm, Core::System& system,
FGM::InstallInterfaces(*sm);
FileSystem::InstallInterfaces(*sm, vfs);
Friend::InstallInterfaces(*sm);
Glue::InstallInterfaces(system);
GRC::InstallInterfaces(*sm);
HID::InstallInterfaces(*sm);
LBL::InstallInterfaces(*sm);

View File

@@ -87,8 +87,8 @@ QtWebBrowser::QtWebBrowser(GMainWindow& main_window) {
QtWebBrowser::~QtWebBrowser() = default;
void QtWebBrowser::OpenPageLocal(std::string_view url, std::function<void()> unpack_romfs_callback,
std::function<void()> finished_callback) {
void QtWebBrowser::OpenPage(std::string_view url, std::function<void()> unpack_romfs_callback,
std::function<void()> finished_callback) {
this->unpack_romfs_callback = std::move(unpack_romfs_callback);
this->finished_callback = std::move(finished_callback);

View File

@@ -37,8 +37,8 @@ public:
explicit QtWebBrowser(GMainWindow& main_window);
~QtWebBrowser() override;
void OpenPageLocal(std::string_view url, std::function<void()> unpack_romfs_callback,
std::function<void()> finished_callback) override;
void OpenPage(std::string_view url, std::function<void()> unpack_romfs_callback,
std::function<void()> finished_callback) override;
signals:
void MainWindowOpenPage(std::string_view filename, std::string_view additional_args) const;

View File

@@ -814,13 +814,11 @@ bool GMainWindow::LoadROM(const QString& filename) {
system.SetGPUDebugContext(debug_context);
system.SetAppletFrontendSet({
nullptr, // Parental Controls
std::make_unique<QtErrorDisplay>(*this), //
nullptr, // Photo Viewer
std::make_unique<QtProfileSelector>(*this), //
std::make_unique<QtSoftwareKeyboard>(*this), //
std::make_unique<QtWebBrowser>(*this), //
nullptr, // E-Commerce
std::make_unique<QtErrorDisplay>(*this),
nullptr,
std::make_unique<QtProfileSelector>(*this),
std::make_unique<QtSoftwareKeyboard>(*this),
std::make_unique<QtWebBrowser>(*this),
});
const Core::System::ResultStatus result{system.Load(*render_window, filename.toStdString())};