From 6f691e71bfa30de8789327a969cb7c2fdd1669f2 Mon Sep 17 00:00:00 2001 From: David Marcec Date: Wed, 8 Aug 2018 22:26:42 +1000 Subject: [PATCH] began initial implementation of "ProfileManager" --- src/core/CMakeLists.txt | 2 + src/core/hle/service/acc/acc.cpp | 17 ++-- src/core/hle/service/acc/acc.h | 41 +-------- src/core/hle/service/acc/profile_manager.cpp | 89 ++++++++++++++++++ src/core/hle/service/acc/profile_manager.h | 97 ++++++++++++++++++++ 5 files changed, 202 insertions(+), 44 deletions(-) create mode 100644 src/core/hle/service/acc/profile_manager.cpp create mode 100644 src/core/hle/service/acc/profile_manager.h diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index cceb1564b2..4d39ba4090 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -114,6 +114,8 @@ add_library(core STATIC hle/service/acc/acc_u0.h hle/service/acc/acc_u1.cpp hle/service/acc/acc_u1.h + hle/service/acc/profile_manager.cpp + hle/service/acc/profile_manager.h hle/service/am/am.cpp hle/service/am/am.h hle/service/am/applet_ae.cpp diff --git a/src/core/hle/service/acc/acc.cpp b/src/core/hle/service/acc/acc.cpp index 1fb3d96f69..8efaf61714 100644 --- a/src/core/hle/service/acc/acc.cpp +++ b/src/core/hle/service/acc/acc.cpp @@ -28,7 +28,7 @@ struct UserData { static_assert(sizeof(UserData) == 0x80, "UserData structure has incorrect size"); struct ProfileBase { - u128 user_id; + UUID user_id; u64 timestamp; std::array username; }; @@ -53,7 +53,7 @@ private: void Get(Kernel::HLERequestContext& ctx) { LOG_WARNING(Service_ACC, "(STUBBED) called"); ProfileBase profile_base{}; - profile_base.user_id = user_id.uuid; + profile_base.user_id = user_id; if (Settings::values.username.size() > profile_base.username.size()) { std::copy_n(Settings::values.username.begin(), profile_base.username.size(), profile_base.username.begin()); @@ -72,7 +72,7 @@ private: // TODO(Subv): Retrieve this information from somewhere. ProfileBase profile_base{}; - profile_base.user_id = user_id.uuid; + profile_base.user_id = user_id; if (Settings::values.username.size() > profile_base.username.size()) { std::copy_n(Settings::values.username.begin(), profile_base.username.size(), profile_base.username.begin()); @@ -122,17 +122,20 @@ private: }; void Module::Interface::GetUserCount(Kernel::HLERequestContext& ctx) { - LOG_WARNING(Service_ACC, "(STUBBED) called"); + LOG_INFO(Service_ACC, "called"); IPC::ResponseBuilder rb{ctx, 3}; rb.Push(RESULT_SUCCESS); - rb.Push(1); + rb.Push(static_cast(profile_manager->GetUserCount())); } void Module::Interface::GetUserExistence(Kernel::HLERequestContext& ctx) { - LOG_WARNING(Service_ACC, "(STUBBED) called"); + IPC::RequestParser rp{ctx}; + UUID user_id = rp.PopRaw(); + LOG_INFO(Service_ACC, "called user_id={}", user_id.Format()); + IPC::ResponseBuilder rb{ctx, 3}; rb.Push(RESULT_SUCCESS); - rb.Push(true); // TODO: Check when this is supposed to return true and when not + rb.Push(profile_manager->UserExists(user_id)); } void Module::Interface::ListAllUsers(Kernel::HLERequestContext& ctx) { diff --git a/src/core/hle/service/acc/acc.h b/src/core/hle/service/acc/acc.h index e392b3557b..a9bea77cee 100644 --- a/src/core/hle/service/acc/acc.h +++ b/src/core/hle/service/acc/acc.h @@ -5,46 +5,10 @@ #pragma once #include "core/hle/service/service.h" +#include "profile_manager.h" namespace Service::Account { -struct UUID { - // UUIDs which are 0 are considered invalid! - u128 uuid{0, 0}; - UUID() = default; - explicit UUID(const u128& id) { - uuid[0] = id[0]; - uuid[1] = id[1]; - }; - explicit UUID(const u64& lo, const u64& hi) { - uuid[0] = lo; - uuid[1] = hi; - }; - operator bool() const { - return uuid[0] != 0x0 && uuid[1] != 0x0; - } - - bool operator==(const UUID& rhs) { - return uuid[0] == rhs.uuid[0] && uuid[1] == rhs.uuid[1]; - } - - bool operator!=(const UUID& rhs) { - return uuid[0] != rhs.uuid[0] || uuid[1] != rhs.uuid[1]; - } - - // TODO(ogniK): Properly generate uuids based on RFC-4122 - const UUID& Generate() { - uuid[0] = (static_cast(std::rand()) << 32) | std::rand(); - uuid[1] = (static_cast(std::rand()) << 32) | std::rand(); - return *this; - } - - std::string Format() { - return fmt::format("0x{:016X}{:016X}", uuid[1], uuid[0]); - } -}; -static_assert(sizeof(UUID) == 16, "UUID is an invalid size!"); - class Module final { public: class Interface : public ServiceFramework { @@ -60,6 +24,9 @@ public: void InitializeApplicationInfo(Kernel::HLERequestContext& ctx); void GetBaasAccountManagerForApplication(Kernel::HLERequestContext& ctx); + private: + std::unique_ptr profile_manager{}; + protected: std::shared_ptr module; }; diff --git a/src/core/hle/service/acc/profile_manager.cpp b/src/core/hle/service/acc/profile_manager.cpp new file mode 100644 index 0000000000..8819c57037 --- /dev/null +++ b/src/core/hle/service/acc/profile_manager.cpp @@ -0,0 +1,89 @@ +#include "profile_manager.h" + +namespace Service::Account { +// TODO(ogniK): Get actual error codes +constexpr ResultCode ERROR_TOO_MANY_USERS(ErrorModule::Account, -1); +constexpr ResultCode ERROR_ARGUMENT_IS_NULL(ErrorModule::Account, 20); + +size_t ProfileManager::AddToProfiles(const ProfileInfo& user) { + if (user_count >= MAX_USERS) { + return -1; + } + profiles[user_count] = std::move(user); + return user_count++; +} + +bool ProfileManager::RemoveProfileAtIdx(size_t index) { + if (index >= MAX_USERS || index < 0 || index >= user_count) + return false; + profiles[index] = ProfileInfo{}; + if (index < user_count - 1) + for (size_t i = index; i < user_count - 1; i++) + profiles[i] = profiles[i + 1]; // Shift upper profiles down + user_count--; + return true; +} + +ResultCode ProfileManager::AddUser(ProfileInfo user) { + if (AddToProfiles(user) == -1) { + return ERROR_TOO_MANY_USERS; + } + return RESULT_SUCCESS; +} + +ResultCode ProfileManager::CreateNewUser(UUID uuid, std::array username) { + if (user_count == MAX_USERS) + return ERROR_TOO_MANY_USERS; + if (!uuid) + return ERROR_ARGUMENT_IS_NULL; + if (username[0] == 0x0) + return ERROR_ARGUMENT_IS_NULL; + ProfileInfo prof_inf; + prof_inf.user_uuid = uuid; + prof_inf.username = username; + prof_inf.data = std::array(); + prof_inf.creation_time = 0x0; + return AddUser(prof_inf); +} + +size_t ProfileManager::GetUserIndex(UUID uuid) { + for (unsigned i = 0; i < user_count; i++) + if (profiles[i].user_uuid == uuid) + return i; + return -1; +} + +size_t ProfileManager::GetUserIndex(ProfileInfo user) { + return GetUserIndex(user.user_uuid); +} + +bool ProfileManager::GetProfileBase(size_t index, ProfileBase& profile) { + if (index >= MAX_USERS) { + profile.Invalidate(); + return false; + } + auto prof_info = profiles[index]; + profile.user_uuid = prof_info.user_uuid; + profile.username = prof_info.username; + profile.timestamp = prof_info.creation_time; + return true; +} + +bool ProfileManager::GetProfileBase(UUID uuid, ProfileBase& profile) { + auto idx = GetUserIndex(uuid); + return GetProfileBase(idx, profile); +} + +bool ProfileManager::GetProfileBase(ProfileInfo user, ProfileBase& profile) { + return GetProfileBase(user.user_uuid, profile); +} + +size_t ProfileManager::GetUserCount() { + return user_count; +} + +bool ProfileManager::UserExists(UUID uuid) { + return (GetUserIndex(uuid) != -1); +} + +}; // namespace Service::Account diff --git a/src/core/hle/service/acc/profile_manager.h b/src/core/hle/service/acc/profile_manager.h new file mode 100644 index 0000000000..5aa73a0302 --- /dev/null +++ b/src/core/hle/service/acc/profile_manager.h @@ -0,0 +1,97 @@ +#pragma once +#include +#include "common/common_types.h" +#include "common/swap.h" +#include "core/hle/result.h" + +namespace Service::Account { +constexpr size_t MAX_USERS = 8; +constexpr size_t MAX_DATA = 128; + +struct UUID { + // UUIDs which are 0 are considered invalid! + u128 uuid{0, 0}; + UUID() = default; + explicit UUID(const u128& id) { + uuid[0] = id[0]; + uuid[1] = id[1]; + }; + explicit UUID(const u64& lo, const u64& hi) { + uuid[0] = lo; + uuid[1] = hi; + }; + operator bool() const { + return uuid[0] != 0x0 && uuid[1] != 0x0; + } + + bool operator==(const UUID& rhs) { + return uuid[0] == rhs.uuid[0] && uuid[1] == rhs.uuid[1]; + } + + bool operator!=(const UUID& rhs) { + return uuid[0] != rhs.uuid[0] || uuid[1] != rhs.uuid[1]; + } + + // TODO(ogniK): Properly generate uuids based on RFC-4122 + const UUID& Generate() { + uuid[0] = (static_cast(std::rand()) << 32) | std::rand(); + uuid[1] = (static_cast(std::rand()) << 32) | std::rand(); + return *this; + } + void Invalidate() { + uuid[0] = 0; + uuid[1] = 0; + } + std::string Format() { + return fmt::format("0x{:016X}{:016X}", uuid[1], uuid[0]); + } +}; +static_assert(sizeof(UUID) == 16, "UUID is an invalid size!"); + +/// This holds general information about a users profile. This is where we store all the information +/// based on a specific user +struct ProfileInfo { + UUID user_uuid; + std::array username; + u64 creation_time; + std::array data; +}; + +struct ProfileBase { + UUID user_uuid; + u64_le timestamp; + std::array username; + + const void Invalidate() { + user_uuid.Invalidate(); + timestamp = 0; + username.fill(0); + } +}; +static_assert(sizeof(ProfileBase) == 0x38, "ProfileBase is an invalid size"); + +/// The profile manager is used for handling multiple user profiles at once. It keeps track of open +/// users, all the accounts registered on the "system" as well as fetching individual "ProfileInfo" +/// objects +class ProfileManager { +public: + ProfileManager() = default; // TODO(ogniK): Load from system save + ResultCode AddUser(ProfileInfo user); + ResultCode CreateNewUser(UUID uuid, std::array username); + size_t GetUserIndex(UUID uuid); + size_t GetUserIndex(ProfileInfo user); + bool GetProfileBase(size_t index, ProfileBase& profile); + bool GetProfileBase(UUID uuid, ProfileBase& profile); + bool GetProfileBase(ProfileInfo user, ProfileBase& profile); + size_t GetUserCount(); + bool UserExists(UUID uuid); + +private: + std::array profiles{}; + size_t user_count = 0; + size_t AddToProfiles(const ProfileInfo& profile); + bool RemoveProfileAtIdx(size_t index); +}; +using ProfileManagerPtr = std::unique_ptr; + +}; // namespace Service::Account