service: time: Update current time with changes to RTC setting.

- This can be used to advance time, e.g. for Pokemon Sword/Shield pokejobs.
master
bunnei 2020-10-12 18:09:15 +07:00
parent 4c348f4069
commit 62c6c9f6a6
9 changed files with 353 additions and 210 deletions

@ -40,6 +40,7 @@
#include "core/hle/service/lm/manager.h" #include "core/hle/service/lm/manager.h"
#include "core/hle/service/service.h" #include "core/hle/service/service.h"
#include "core/hle/service/sm/sm.h" #include "core/hle/service/sm/sm.h"
#include "core/hle/service/time/time_manager.h"
#include "core/loader/loader.h" #include "core/loader/loader.h"
#include "core/memory.h" #include "core/memory.h"
#include "core/memory/cheat_engine.h" #include "core/memory/cheat_engine.h"
@ -121,7 +122,7 @@ FileSys::VirtualFile GetGameFileFromPath(const FileSys::VirtualFilesystem& vfs,
struct System::Impl { struct System::Impl {
explicit Impl(System& system) explicit Impl(System& system)
: kernel{system}, fs_controller{system}, memory{system}, : kernel{system}, fs_controller{system}, memory{system},
cpu_manager{system}, reporter{system}, applet_manager{system} {} cpu_manager{system}, reporter{system}, applet_manager{system}, time_manager{system} {}
ResultStatus Run() { ResultStatus Run() {
status = ResultStatus::Success; status = ResultStatus::Success;
@ -189,6 +190,9 @@ struct System::Impl {
return ResultStatus::ErrorVideoCore; return ResultStatus::ErrorVideoCore;
} }
// Initialize time manager, which must happen after kernel is created
time_manager.Initialize();
is_powered_on = true; is_powered_on = true;
exit_lock = false; exit_lock = false;
@ -387,6 +391,7 @@ struct System::Impl {
/// Service State /// Service State
Service::Glue::ARPManager arp_manager; Service::Glue::ARPManager arp_manager;
Service::LM::Manager lm_manager{reporter}; Service::LM::Manager lm_manager{reporter};
Service::Time::TimeManager time_manager;
/// Service manager /// Service manager
std::shared_ptr<Service::SM::ServiceManager> service_manager; std::shared_ptr<Service::SM::ServiceManager> service_manager;
@ -717,6 +722,14 @@ const Service::LM::Manager& System::GetLogManager() const {
return impl->lm_manager; return impl->lm_manager;
} }
Service::Time::TimeManager& System::GetTimeManager() {
return impl->time_manager;
}
const Service::Time::TimeManager& System::GetTimeManager() const {
return impl->time_manager;
}
void System::SetExitLock(bool locked) { void System::SetExitLock(bool locked) {
impl->exit_lock = locked; impl->exit_lock = locked;
} }

@ -69,6 +69,10 @@ namespace SM {
class ServiceManager; class ServiceManager;
} // namespace SM } // namespace SM
namespace Time {
class TimeManager;
} // namespace Time
} // namespace Service } // namespace Service
namespace Tegra { namespace Tegra {
@ -361,6 +365,10 @@ public:
const Service::LM::Manager& GetLogManager() const; const Service::LM::Manager& GetLogManager() const;
Service::Time::TimeManager& GetTimeManager();
const Service::Time::TimeManager& GetTimeManager() const;
void SetExitLock(bool locked); void SetExitLock(bool locked);
bool GetExitLock() const; bool GetExitLock() const;

@ -10,6 +10,7 @@
#include "core/hle/ipc_helpers.h" #include "core/hle/ipc_helpers.h"
#include "core/hle/kernel/client_port.h" #include "core/hle/kernel/client_port.h"
#include "core/hle/kernel/client_session.h" #include "core/hle/kernel/client_session.h"
#include "core/hle/kernel/kernel.h"
#include "core/hle/kernel/scheduler.h" #include "core/hle/kernel/scheduler.h"
#include "core/hle/service/time/interface.h" #include "core/hle/service/time/interface.h"
#include "core/hle/service/time/time.h" #include "core/hle/service/time/time.h"
@ -125,7 +126,7 @@ ResultCode Module::Interface::GetClockSnapshotFromSystemClockContextInternal(
Kernel::Thread* thread, Clock::SystemClockContext user_context, Kernel::Thread* thread, Clock::SystemClockContext user_context,
Clock::SystemClockContext network_context, u8 type, Clock::ClockSnapshot& clock_snapshot) { Clock::SystemClockContext network_context, u8 type, Clock::ClockSnapshot& clock_snapshot) {
auto& time_manager{module->GetTimeManager()}; auto& time_manager{system.GetTimeManager()};
clock_snapshot.is_automatic_correction_enabled = clock_snapshot.is_automatic_correction_enabled =
time_manager.GetStandardUserSystemClockCore().IsAutomaticCorrectionEnabled(); time_manager.GetStandardUserSystemClockCore().IsAutomaticCorrectionEnabled();
@ -182,7 +183,7 @@ void Module::Interface::GetStandardUserSystemClock(Kernel::HLERequestContext& ct
LOG_DEBUG(Service_Time, "called"); LOG_DEBUG(Service_Time, "called");
IPC::ResponseBuilder rb{ctx, 2, 0, 1}; IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS); rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<ISystemClock>(module->GetTimeManager().GetStandardUserSystemClockCore(), rb.PushIpcInterface<ISystemClock>(system.GetTimeManager().GetStandardUserSystemClockCore(),
system); system);
} }
@ -190,7 +191,7 @@ void Module::Interface::GetStandardNetworkSystemClock(Kernel::HLERequestContext&
LOG_DEBUG(Service_Time, "called"); LOG_DEBUG(Service_Time, "called");
IPC::ResponseBuilder rb{ctx, 2, 0, 1}; IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS); rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<ISystemClock>(module->GetTimeManager().GetStandardNetworkSystemClockCore(), rb.PushIpcInterface<ISystemClock>(system.GetTimeManager().GetStandardNetworkSystemClockCore(),
system); system);
} }
@ -198,29 +199,28 @@ void Module::Interface::GetStandardSteadyClock(Kernel::HLERequestContext& ctx) {
LOG_DEBUG(Service_Time, "called"); LOG_DEBUG(Service_Time, "called");
IPC::ResponseBuilder rb{ctx, 2, 0, 1}; IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS); rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<ISteadyClock>(module->GetTimeManager().GetStandardSteadyClockCore(), rb.PushIpcInterface<ISteadyClock>(system.GetTimeManager().GetStandardSteadyClockCore(), system);
system);
} }
void Module::Interface::GetTimeZoneService(Kernel::HLERequestContext& ctx) { void Module::Interface::GetTimeZoneService(Kernel::HLERequestContext& ctx) {
LOG_DEBUG(Service_Time, "called"); LOG_DEBUG(Service_Time, "called");
IPC::ResponseBuilder rb{ctx, 2, 0, 1}; IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS); rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<ITimeZoneService>(module->GetTimeManager().GetTimeZoneContentManager()); rb.PushIpcInterface<ITimeZoneService>(system.GetTimeManager().GetTimeZoneContentManager());
} }
void Module::Interface::GetStandardLocalSystemClock(Kernel::HLERequestContext& ctx) { void Module::Interface::GetStandardLocalSystemClock(Kernel::HLERequestContext& ctx) {
LOG_DEBUG(Service_Time, "called"); LOG_DEBUG(Service_Time, "called");
IPC::ResponseBuilder rb{ctx, 2, 0, 1}; IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS); rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<ISystemClock>(module->GetTimeManager().GetStandardLocalSystemClockCore(), rb.PushIpcInterface<ISystemClock>(system.GetTimeManager().GetStandardLocalSystemClockCore(),
system); system);
} }
void Module::Interface::IsStandardNetworkSystemClockAccuracySufficient( void Module::Interface::IsStandardNetworkSystemClockAccuracySufficient(
Kernel::HLERequestContext& ctx) { Kernel::HLERequestContext& ctx) {
LOG_DEBUG(Service_Time, "called"); LOG_DEBUG(Service_Time, "called");
auto& clock_core{module->GetTimeManager().GetStandardNetworkSystemClockCore()}; auto& clock_core{system.GetTimeManager().GetStandardNetworkSystemClockCore()};
IPC::ResponseBuilder rb{ctx, 3}; IPC::ResponseBuilder rb{ctx, 3};
rb.Push(RESULT_SUCCESS); rb.Push(RESULT_SUCCESS);
rb.Push<u32>(clock_core.IsStandardNetworkSystemClockAccuracySufficient(system)); rb.Push<u32>(clock_core.IsStandardNetworkSystemClockAccuracySufficient(system));
@ -229,7 +229,7 @@ void Module::Interface::IsStandardNetworkSystemClockAccuracySufficient(
void Module::Interface::CalculateMonotonicSystemClockBaseTimePoint(Kernel::HLERequestContext& ctx) { void Module::Interface::CalculateMonotonicSystemClockBaseTimePoint(Kernel::HLERequestContext& ctx) {
LOG_DEBUG(Service_Time, "called"); LOG_DEBUG(Service_Time, "called");
auto& steady_clock_core{module->GetTimeManager().GetStandardSteadyClockCore()}; auto& steady_clock_core{system.GetTimeManager().GetStandardSteadyClockCore()};
if (!steady_clock_core.IsInitialized()) { if (!steady_clock_core.IsInitialized()) {
IPC::ResponseBuilder rb{ctx, 2}; IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ERROR_UNINITIALIZED_CLOCK); rb.Push(ERROR_UNINITIALIZED_CLOCK);
@ -262,8 +262,8 @@ void Module::Interface::GetClockSnapshot(Kernel::HLERequestContext& ctx) {
Clock::SystemClockContext user_context{}; Clock::SystemClockContext user_context{};
if (const ResultCode result{ if (const ResultCode result{
module->GetTimeManager().GetStandardUserSystemClockCore().GetClockContext( system.GetTimeManager().GetStandardUserSystemClockCore().GetClockContext(system,
system, user_context)}; user_context)};
result.IsError()) { result.IsError()) {
IPC::ResponseBuilder rb{ctx, 2}; IPC::ResponseBuilder rb{ctx, 2};
rb.Push(result); rb.Push(result);
@ -271,7 +271,7 @@ void Module::Interface::GetClockSnapshot(Kernel::HLERequestContext& ctx) {
} }
Clock::SystemClockContext network_context{}; Clock::SystemClockContext network_context{};
if (const ResultCode result{ if (const ResultCode result{
module->GetTimeManager().GetStandardNetworkSystemClockCore().GetClockContext( system.GetTimeManager().GetStandardNetworkSystemClockCore().GetClockContext(
system, network_context)}; system, network_context)};
result.IsError()) { result.IsError()) {
IPC::ResponseBuilder rb{ctx, 2}; IPC::ResponseBuilder rb{ctx, 2};
@ -372,7 +372,7 @@ void Module::Interface::GetSharedMemoryNativeHandle(Kernel::HLERequestContext& c
LOG_DEBUG(Service_Time, "called"); LOG_DEBUG(Service_Time, "called");
IPC::ResponseBuilder rb{ctx, 2, 1}; IPC::ResponseBuilder rb{ctx, 2, 1};
rb.Push(RESULT_SUCCESS); rb.Push(RESULT_SUCCESS);
rb.PushCopyObjects(module->GetTimeManager().GetSharedMemory().GetSharedMemoryHolder()); rb.PushCopyObjects(SharedFrom(&system.Kernel().GetTimeSharedMem()));
} }
Module::Interface::Interface(std::shared_ptr<Module> module, Core::System& system, const char* name) Module::Interface::Interface(std::shared_ptr<Module> module, Core::System& system, const char* name)
@ -381,7 +381,7 @@ Module::Interface::Interface(std::shared_ptr<Module> module, Core::System& syste
Module::Interface::~Interface() = default; Module::Interface::~Interface() = default;
void InstallInterfaces(Core::System& system) { void InstallInterfaces(Core::System& system) {
auto module{std::make_shared<Module>(system)}; auto module{std::make_shared<Module>()};
std::make_shared<Time>(module, system, "time:a")->InstallAsService(system.ServiceManager()); std::make_shared<Time>(module, system, "time:a")->InstallAsService(system.ServiceManager());
std::make_shared<Time>(module, system, "time:s")->InstallAsService(system.ServiceManager()); std::make_shared<Time>(module, system, "time:s")->InstallAsService(system.ServiceManager());
std::make_shared<Time>(module, system, "time:u")->InstallAsService(system.ServiceManager()); std::make_shared<Time>(module, system, "time:u")->InstallAsService(system.ServiceManager());

@ -16,7 +16,7 @@ namespace Service::Time {
class Module final { class Module final {
public: public:
Module(Core::System& system) : time_manager{system} {} Module() = default;
class Interface : public ServiceFramework<Interface> { class Interface : public ServiceFramework<Interface> {
public: public:
@ -46,13 +46,6 @@ public:
std::shared_ptr<Module> module; std::shared_ptr<Module> module;
Core::System& system; Core::System& system;
}; };
TimeManager& GetTimeManager() {
return time_manager;
}
private:
TimeManager time_manager;
}; };
/// Registers all Time services with the specified service manager. /// Registers all Time services with the specified service manager.

@ -22,7 +22,277 @@ static std::chrono::seconds GetSecondsSinceEpoch() {
Settings::values.custom_rtc_differential; Settings::values.custom_rtc_differential;
} }
static s64 GetExternalTimeZoneOffset() { static s64 GetExternalRtcValue() {
return GetSecondsSinceEpoch().count() + TimeManager::GetExternalTimeZoneOffset();
}
struct TimeManager::Impl final {
explicit Impl(Core::System& system)
: shared_memory{system}, standard_local_system_clock_core{standard_steady_clock_core},
standard_network_system_clock_core{standard_steady_clock_core},
standard_user_system_clock_core{standard_local_system_clock_core,
standard_network_system_clock_core, system},
ephemeral_network_system_clock_core{tick_based_steady_clock_core},
local_system_clock_context_writer{
std::make_shared<Clock::LocalSystemClockContextWriter>(shared_memory)},
network_system_clock_context_writer{
std::make_shared<Clock::NetworkSystemClockContextWriter>(shared_memory)},
ephemeral_network_system_clock_context_writer{
std::make_shared<Clock::EphemeralNetworkSystemClockContextWriter>()},
time_zone_content_manager{system} {
const auto system_time{Clock::TimeSpanType::FromSeconds(GetExternalRtcValue())};
SetupStandardSteadyClock(system, Common::UUID::Generate(), system_time, {}, {});
SetupStandardLocalSystemClock(system, {}, system_time.ToSeconds());
SetupStandardNetworkSystemClock({}, standard_network_clock_accuracy);
SetupStandardUserSystemClock(system, {}, Clock::SteadyClockTimePoint::GetRandom());
SetupEphemeralNetworkSystemClock();
}
~Impl() = default;
Clock::StandardSteadyClockCore& GetStandardSteadyClockCore() {
return standard_steady_clock_core;
}
const Clock::StandardSteadyClockCore& GetStandardSteadyClockCore() const {
return standard_steady_clock_core;
}
Clock::StandardLocalSystemClockCore& GetStandardLocalSystemClockCore() {
return standard_local_system_clock_core;
}
const Clock::StandardLocalSystemClockCore& GetStandardLocalSystemClockCore() const {
return standard_local_system_clock_core;
}
Clock::StandardNetworkSystemClockCore& GetStandardNetworkSystemClockCore() {
return standard_network_system_clock_core;
}
const Clock::StandardNetworkSystemClockCore& GetStandardNetworkSystemClockCore() const {
return standard_network_system_clock_core;
}
Clock::StandardUserSystemClockCore& GetStandardUserSystemClockCore() {
return standard_user_system_clock_core;
}
const Clock::StandardUserSystemClockCore& GetStandardUserSystemClockCore() const {
return standard_user_system_clock_core;
}
TimeZone::TimeZoneContentManager& GetTimeZoneContentManager() {
return time_zone_content_manager;
}
const TimeZone::TimeZoneContentManager& GetTimeZoneContentManager() const {
return time_zone_content_manager;
}
SharedMemory& GetSharedMemory() {
return shared_memory;
}
const SharedMemory& GetSharedMemory() const {
return shared_memory;
}
void SetupTimeZoneManager(std::string location_name,
Clock::SteadyClockTimePoint time_zone_updated_time_point,
std::size_t total_location_name_count, u128 time_zone_rule_version,
FileSys::VirtualFile& vfs_file) {
if (time_zone_content_manager.GetTimeZoneManager().SetDeviceLocationNameWithTimeZoneRule(
location_name, vfs_file) != RESULT_SUCCESS) {
UNREACHABLE();
return;
}
time_zone_content_manager.GetTimeZoneManager().SetUpdatedTime(time_zone_updated_time_point);
time_zone_content_manager.GetTimeZoneManager().SetTotalLocationNameCount(
total_location_name_count);
time_zone_content_manager.GetTimeZoneManager().SetTimeZoneRuleVersion(
time_zone_rule_version);
time_zone_content_manager.GetTimeZoneManager().MarkAsInitialized();
}
static s64 GetExternalTimeZoneOffset() {
// With "auto" timezone setting, we use the external system's timezone offset
if (Settings::GetTimeZoneString() == "auto") {
return Common::TimeZone::GetCurrentOffsetSeconds().count();
}
return 0;
}
void SetupStandardSteadyClock(Core::System& system, Common::UUID clock_source_id,
Clock::TimeSpanType setup_value,
Clock::TimeSpanType internal_offset, bool is_rtc_reset_detected) {
standard_steady_clock_core.SetClockSourceId(clock_source_id);
standard_steady_clock_core.SetSetupValue(setup_value);
standard_steady_clock_core.SetInternalOffset(internal_offset);
standard_steady_clock_core.MarkAsInitialized();
const auto current_time_point{standard_steady_clock_core.GetCurrentRawTimePoint(system)};
shared_memory.SetupStandardSteadyClock(system, clock_source_id, current_time_point);
}
void SetupStandardLocalSystemClock(Core::System& system,
Clock::SystemClockContext clock_context, s64 posix_time) {
standard_local_system_clock_core.SetUpdateCallbackInstance(
local_system_clock_context_writer);
const auto current_time_point{
standard_local_system_clock_core.GetSteadyClockCore().GetCurrentTimePoint(system)};
if (current_time_point.clock_source_id == clock_context.steady_time_point.clock_source_id) {
standard_local_system_clock_core.SetSystemClockContext(clock_context);
} else {
if (standard_local_system_clock_core.SetCurrentTime(system, posix_time) !=
RESULT_SUCCESS) {
UNREACHABLE();
return;
}
}
standard_local_system_clock_core.MarkAsInitialized();
}
void SetupStandardNetworkSystemClock(Clock::SystemClockContext clock_context,
Clock::TimeSpanType sufficient_accuracy) {
standard_network_system_clock_core.SetUpdateCallbackInstance(
network_system_clock_context_writer);
if (standard_network_system_clock_core.SetSystemClockContext(clock_context) !=
RESULT_SUCCESS) {
UNREACHABLE();
return;
}
standard_network_system_clock_core.SetStandardNetworkClockSufficientAccuracy(
sufficient_accuracy);
standard_network_system_clock_core.MarkAsInitialized();
}
void SetupStandardUserSystemClock(Core::System& system, bool is_automatic_correction_enabled,
Clock::SteadyClockTimePoint steady_clock_time_point) {
if (standard_user_system_clock_core.SetAutomaticCorrectionEnabled(
system, is_automatic_correction_enabled) != RESULT_SUCCESS) {
UNREACHABLE();
return;
}
standard_user_system_clock_core.SetAutomaticCorrectionUpdatedTime(steady_clock_time_point);
standard_user_system_clock_core.MarkAsInitialized();
shared_memory.SetAutomaticCorrectionEnabled(is_automatic_correction_enabled);
}
void SetupEphemeralNetworkSystemClock() {
ephemeral_network_system_clock_core.SetUpdateCallbackInstance(
ephemeral_network_system_clock_context_writer);
ephemeral_network_system_clock_core.MarkAsInitialized();
}
void UpdateLocalSystemClockTime(Core::System& system, s64 posix_time) {
const auto timespan{Service::Time::Clock::TimeSpanType::FromSeconds(posix_time)};
if (GetStandardLocalSystemClockCore()
.SetCurrentTime(system, timespan.ToSeconds())
.IsError()) {
UNREACHABLE();
return;
}
}
SharedMemory shared_memory;
Clock::StandardSteadyClockCore standard_steady_clock_core;
Clock::TickBasedSteadyClockCore tick_based_steady_clock_core;
Clock::StandardLocalSystemClockCore standard_local_system_clock_core;
Clock::StandardNetworkSystemClockCore standard_network_system_clock_core;
Clock::StandardUserSystemClockCore standard_user_system_clock_core;
Clock::EphemeralNetworkSystemClockCore ephemeral_network_system_clock_core;
std::shared_ptr<Clock::LocalSystemClockContextWriter> local_system_clock_context_writer;
std::shared_ptr<Clock::NetworkSystemClockContextWriter> network_system_clock_context_writer;
std::shared_ptr<Clock::EphemeralNetworkSystemClockContextWriter>
ephemeral_network_system_clock_context_writer;
TimeZone::TimeZoneContentManager time_zone_content_manager;
};
TimeManager::TimeManager(Core::System& system) : system{system} {}
TimeManager::~TimeManager() = default;
void TimeManager::Initialize() {
impl = std::make_unique<Impl>(system);
// Time zones can only be initialized after impl is valid
impl->time_zone_content_manager.Initialize(*this);
}
Clock::StandardSteadyClockCore& TimeManager::GetStandardSteadyClockCore() {
return impl->standard_steady_clock_core;
}
const Clock::StandardSteadyClockCore& TimeManager::GetStandardSteadyClockCore() const {
return impl->standard_steady_clock_core;
}
Clock::StandardLocalSystemClockCore& TimeManager::GetStandardLocalSystemClockCore() {
return impl->standard_local_system_clock_core;
}
const Clock::StandardLocalSystemClockCore& TimeManager::GetStandardLocalSystemClockCore() const {
return impl->standard_local_system_clock_core;
}
Clock::StandardNetworkSystemClockCore& TimeManager::GetStandardNetworkSystemClockCore() {
return impl->standard_network_system_clock_core;
}
const Clock::StandardNetworkSystemClockCore& TimeManager::GetStandardNetworkSystemClockCore()
const {
return impl->standard_network_system_clock_core;
}
Clock::StandardUserSystemClockCore& TimeManager::GetStandardUserSystemClockCore() {
return impl->standard_user_system_clock_core;
}
const Clock::StandardUserSystemClockCore& TimeManager::GetStandardUserSystemClockCore() const {
return impl->standard_user_system_clock_core;
}
TimeZone::TimeZoneContentManager& TimeManager::GetTimeZoneContentManager() {
return impl->time_zone_content_manager;
}
const TimeZone::TimeZoneContentManager& TimeManager::GetTimeZoneContentManager() const {
return impl->time_zone_content_manager;
}
SharedMemory& TimeManager::GetSharedMemory() {
return impl->shared_memory;
}
const SharedMemory& TimeManager::GetSharedMemory() const {
return impl->shared_memory;
}
void TimeManager::UpdateLocalSystemClockTime(s64 posix_time) {
impl->UpdateLocalSystemClockTime(system, posix_time);
}
void TimeManager::SetupTimeZoneManager(std::string location_name,
Clock::SteadyClockTimePoint time_zone_updated_time_point,
std::size_t total_location_name_count,
u128 time_zone_rule_version,
FileSys::VirtualFile& vfs_file) {
impl->SetupTimeZoneManager(location_name, time_zone_updated_time_point,
total_location_name_count, time_zone_rule_version, vfs_file);
}
/*static*/ s64 TimeManager::GetExternalTimeZoneOffset() {
// With "auto" timezone setting, we use the external system's timezone offset // With "auto" timezone setting, we use the external system's timezone offset
if (Settings::GetTimeZoneString() == "auto") { if (Settings::GetTimeZoneString() == "auto") {
return Common::TimeZone::GetCurrentOffsetSeconds().count(); return Common::TimeZone::GetCurrentOffsetSeconds().count();
@ -30,117 +300,4 @@ static s64 GetExternalTimeZoneOffset() {
return 0; return 0;
} }
static s64 GetExternalRtcValue() {
return GetSecondsSinceEpoch().count() + GetExternalTimeZoneOffset();
}
TimeManager::TimeManager(Core::System& system)
: shared_memory{system}, standard_local_system_clock_core{standard_steady_clock_core},
standard_network_system_clock_core{standard_steady_clock_core},
standard_user_system_clock_core{standard_local_system_clock_core,
standard_network_system_clock_core, system},
ephemeral_network_system_clock_core{tick_based_steady_clock_core},
local_system_clock_context_writer{
std::make_shared<Clock::LocalSystemClockContextWriter>(shared_memory)},
network_system_clock_context_writer{
std::make_shared<Clock::NetworkSystemClockContextWriter>(shared_memory)},
ephemeral_network_system_clock_context_writer{
std::make_shared<Clock::EphemeralNetworkSystemClockContextWriter>()},
time_zone_content_manager{*this, system} {
const auto system_time{Clock::TimeSpanType::FromSeconds(GetExternalRtcValue())};
SetupStandardSteadyClock(system, Common::UUID::Generate(), system_time, {}, {});
SetupStandardLocalSystemClock(system, {}, system_time.ToSeconds());
SetupStandardNetworkSystemClock({}, standard_network_clock_accuracy);
SetupStandardUserSystemClock(system, {}, Clock::SteadyClockTimePoint::GetRandom());
SetupEphemeralNetworkSystemClock();
}
TimeManager::~TimeManager() = default;
void TimeManager::SetupTimeZoneManager(std::string location_name,
Clock::SteadyClockTimePoint time_zone_updated_time_point,
std::size_t total_location_name_count,
u128 time_zone_rule_version,
FileSys::VirtualFile& vfs_file) {
if (time_zone_content_manager.GetTimeZoneManager().SetDeviceLocationNameWithTimeZoneRule(
location_name, vfs_file) != RESULT_SUCCESS) {
UNREACHABLE();
return;
}
time_zone_content_manager.GetTimeZoneManager().SetUpdatedTime(time_zone_updated_time_point);
time_zone_content_manager.GetTimeZoneManager().SetTotalLocationNameCount(
total_location_name_count);
time_zone_content_manager.GetTimeZoneManager().SetTimeZoneRuleVersion(time_zone_rule_version);
time_zone_content_manager.GetTimeZoneManager().MarkAsInitialized();
}
void TimeManager::SetupStandardSteadyClock(Core::System& system, Common::UUID clock_source_id,
Clock::TimeSpanType setup_value,
Clock::TimeSpanType internal_offset,
bool is_rtc_reset_detected) {
standard_steady_clock_core.SetClockSourceId(clock_source_id);
standard_steady_clock_core.SetSetupValue(setup_value);
standard_steady_clock_core.SetInternalOffset(internal_offset);
standard_steady_clock_core.MarkAsInitialized();
const auto current_time_point{standard_steady_clock_core.GetCurrentRawTimePoint(system)};
shared_memory.SetupStandardSteadyClock(system, clock_source_id, current_time_point);
}
void TimeManager::SetupStandardLocalSystemClock(Core::System& system,
Clock::SystemClockContext clock_context,
s64 posix_time) {
standard_local_system_clock_core.SetUpdateCallbackInstance(local_system_clock_context_writer);
const auto current_time_point{
standard_local_system_clock_core.GetSteadyClockCore().GetCurrentTimePoint(system)};
if (current_time_point.clock_source_id == clock_context.steady_time_point.clock_source_id) {
standard_local_system_clock_core.SetSystemClockContext(clock_context);
} else {
if (standard_local_system_clock_core.SetCurrentTime(system, posix_time) != RESULT_SUCCESS) {
UNREACHABLE();
return;
}
}
standard_local_system_clock_core.MarkAsInitialized();
}
void TimeManager::SetupStandardNetworkSystemClock(Clock::SystemClockContext clock_context,
Clock::TimeSpanType sufficient_accuracy) {
standard_network_system_clock_core.SetUpdateCallbackInstance(
network_system_clock_context_writer);
if (standard_network_system_clock_core.SetSystemClockContext(clock_context) != RESULT_SUCCESS) {
UNREACHABLE();
return;
}
standard_network_system_clock_core.SetStandardNetworkClockSufficientAccuracy(
sufficient_accuracy);
standard_network_system_clock_core.MarkAsInitialized();
}
void TimeManager::SetupStandardUserSystemClock(
Core::System& system, bool is_automatic_correction_enabled,
Clock::SteadyClockTimePoint steady_clock_time_point) {
if (standard_user_system_clock_core.SetAutomaticCorrectionEnabled(
system, is_automatic_correction_enabled) != RESULT_SUCCESS) {
UNREACHABLE();
return;
}
standard_user_system_clock_core.SetAutomaticCorrectionUpdatedTime(steady_clock_time_point);
standard_user_system_clock_core.MarkAsInitialized();
shared_memory.SetAutomaticCorrectionEnabled(is_automatic_correction_enabled);
}
void TimeManager::SetupEphemeralNetworkSystemClock() {
ephemeral_network_system_clock_core.SetUpdateCallbackInstance(
ephemeral_network_system_clock_context_writer);
ephemeral_network_system_clock_core.MarkAsInitialized();
}
} // namespace Service::Time } // namespace Service::Time

@ -5,6 +5,7 @@
#pragma once #pragma once
#include "common/common_types.h" #include "common/common_types.h"
#include "common/time_zone.h"
#include "core/file_sys/vfs_types.h" #include "core/file_sys/vfs_types.h"
#include "core/hle/service/time/clock_types.h" #include "core/hle/service/time/clock_types.h"
#include "core/hle/service/time/ephemeral_network_system_clock_core.h" #include "core/hle/service/time/ephemeral_network_system_clock_core.h"
@ -32,86 +33,46 @@ public:
explicit TimeManager(Core::System& system); explicit TimeManager(Core::System& system);
~TimeManager(); ~TimeManager();
Clock::StandardSteadyClockCore& GetStandardSteadyClockCore() { void Initialize();
return standard_steady_clock_core;
}
const Clock::StandardSteadyClockCore& GetStandardSteadyClockCore() const { Clock::StandardSteadyClockCore& GetStandardSteadyClockCore();
return standard_steady_clock_core;
}
Clock::StandardLocalSystemClockCore& GetStandardLocalSystemClockCore() { const Clock::StandardSteadyClockCore& GetStandardSteadyClockCore() const;
return standard_local_system_clock_core;
}
const Clock::StandardLocalSystemClockCore& GetStandardLocalSystemClockCore() const { Clock::StandardLocalSystemClockCore& GetStandardLocalSystemClockCore();
return standard_local_system_clock_core;
}
Clock::StandardNetworkSystemClockCore& GetStandardNetworkSystemClockCore() { const Clock::StandardLocalSystemClockCore& GetStandardLocalSystemClockCore() const;
return standard_network_system_clock_core;
}
const Clock::StandardNetworkSystemClockCore& GetStandardNetworkSystemClockCore() const { Clock::StandardNetworkSystemClockCore& GetStandardNetworkSystemClockCore();
return standard_network_system_clock_core;
}
Clock::StandardUserSystemClockCore& GetStandardUserSystemClockCore() { const Clock::StandardNetworkSystemClockCore& GetStandardNetworkSystemClockCore() const;
return standard_user_system_clock_core;
}
const Clock::StandardUserSystemClockCore& GetStandardUserSystemClockCore() const { Clock::StandardUserSystemClockCore& GetStandardUserSystemClockCore();
return standard_user_system_clock_core;
}
TimeZone::TimeZoneContentManager& GetTimeZoneContentManager() { const Clock::StandardUserSystemClockCore& GetStandardUserSystemClockCore() const;
return time_zone_content_manager;
}
const TimeZone::TimeZoneContentManager& GetTimeZoneContentManager() const { TimeZone::TimeZoneContentManager& GetTimeZoneContentManager();
return time_zone_content_manager;
}
SharedMemory& GetSharedMemory() { const TimeZone::TimeZoneContentManager& GetTimeZoneContentManager() const;
return shared_memory;
}
const SharedMemory& GetSharedMemory() const { void UpdateLocalSystemClockTime(s64 posix_time);
return shared_memory;
} SharedMemory& GetSharedMemory();
const SharedMemory& GetSharedMemory() const;
void SetupTimeZoneManager(std::string location_name, void SetupTimeZoneManager(std::string location_name,
Clock::SteadyClockTimePoint time_zone_updated_time_point, Clock::SteadyClockTimePoint time_zone_updated_time_point,
std::size_t total_location_name_count, u128 time_zone_rule_version, std::size_t total_location_name_count, u128 time_zone_rule_version,
FileSys::VirtualFile& vfs_file); FileSys::VirtualFile& vfs_file);
static s64 GetExternalTimeZoneOffset();
private: private:
void SetupStandardSteadyClock(Core::System& system, Common::UUID clock_source_id, Core::System& system;
Clock::TimeSpanType setup_value,
Clock::TimeSpanType internal_offset, bool is_rtc_reset_detected);
void SetupStandardLocalSystemClock(Core::System& system,
Clock::SystemClockContext clock_context, s64 posix_time);
void SetupStandardNetworkSystemClock(Clock::SystemClockContext clock_context,
Clock::TimeSpanType sufficient_accuracy);
void SetupStandardUserSystemClock(Core::System& system, bool is_automatic_correction_enabled,
Clock::SteadyClockTimePoint steady_clock_time_point);
void SetupEphemeralNetworkSystemClock();
SharedMemory shared_memory; struct Impl;
std::unique_ptr<Impl> impl;
Clock::StandardSteadyClockCore standard_steady_clock_core;
Clock::TickBasedSteadyClockCore tick_based_steady_clock_core;
Clock::StandardLocalSystemClockCore standard_local_system_clock_core;
Clock::StandardNetworkSystemClockCore standard_network_system_clock_core;
Clock::StandardUserSystemClockCore standard_user_system_clock_core;
Clock::EphemeralNetworkSystemClockCore ephemeral_network_system_clock_core;
std::shared_ptr<Clock::LocalSystemClockContextWriter> local_system_clock_context_writer;
std::shared_ptr<Clock::NetworkSystemClockContextWriter> network_system_clock_context_writer;
std::shared_ptr<Clock::EphemeralNetworkSystemClockContextWriter>
ephemeral_network_system_clock_context_writer;
TimeZone::TimeZoneContentManager time_zone_content_manager;
}; };
} // namespace Service::Time } // namespace Service::Time

@ -68,9 +68,10 @@ static std::vector<std::string> BuildLocationNameCache(Core::System& system) {
return location_name_cache; return location_name_cache;
} }
TimeZoneContentManager::TimeZoneContentManager(TimeManager& time_manager, Core::System& system) TimeZoneContentManager::TimeZoneContentManager(Core::System& system)
: system{system}, location_name_cache{BuildLocationNameCache(system)} { : system{system}, location_name_cache{BuildLocationNameCache(system)} {}
void TimeZoneContentManager::Initialize(TimeManager& time_manager) {
std::string location_name; std::string location_name;
const auto timezone_setting = Settings::GetTimeZoneString(); const auto timezone_setting = Settings::GetTimeZoneString();
if (timezone_setting == "auto" || timezone_setting == "default") { if (timezone_setting == "auto" || timezone_setting == "default") {

@ -21,7 +21,9 @@ namespace Service::Time::TimeZone {
class TimeZoneContentManager final { class TimeZoneContentManager final {
public: public:
TimeZoneContentManager(TimeManager& time_manager, Core::System& system); TimeZoneContentManager(Core::System& system);
void Initialize(TimeManager& time_manager);
TimeZoneManager& GetTimeZoneManager() { TimeZoneManager& GetTimeZoneManager() {
return time_zone_manager; return time_zone_manager;

@ -12,6 +12,7 @@
#include "common/assert.h" #include "common/assert.h"
#include "common/file_util.h" #include "common/file_util.h"
#include "core/core.h" #include "core/core.h"
#include "core/hle/service/time/time.h"
#include "core/settings.h" #include "core/settings.h"
#include "ui_configure_system.h" #include "ui_configure_system.h"
#include "yuzu/configuration/configuration_shared.h" #include "yuzu/configuration/configuration_shared.h"
@ -104,6 +105,22 @@ void ConfigureSystem::SetConfiguration() {
void ConfigureSystem::ReadSystemSettings() {} void ConfigureSystem::ReadSystemSettings() {}
void ConfigureSystem::ApplyConfiguration() { void ConfigureSystem::ApplyConfiguration() {
// Allow setting custom RTC even if system is powered on, to allow in-game time to be fast
// forwared
if (Settings::values.custom_rtc.UsingGlobal()) {
if (ui->custom_rtc_checkbox->isChecked()) {
Settings::values.custom_rtc.SetValue(
std::chrono::seconds(ui->custom_rtc_edit->dateTime().toSecsSinceEpoch()));
if (Core::System::GetInstance().IsPoweredOn()) {
const s64 posix_time{Settings::values.custom_rtc.GetValue()->count() +
Service::Time::TimeManager::GetExternalTimeZoneOffset()};
Core::System::GetInstance().GetTimeManager().UpdateLocalSystemClockTime(posix_time);
}
} else {
Settings::values.custom_rtc.SetValue(std::nullopt);
}
}
if (!enabled) { if (!enabled) {
return; return;
} }
@ -131,15 +148,6 @@ void ConfigureSystem::ApplyConfiguration() {
Settings::values.rng_seed.SetValue(std::nullopt); Settings::values.rng_seed.SetValue(std::nullopt);
} }
} }
if (Settings::values.custom_rtc.UsingGlobal()) {
if (ui->custom_rtc_checkbox->isChecked()) {
Settings::values.custom_rtc.SetValue(
std::chrono::seconds(ui->custom_rtc_edit->dateTime().toSecsSinceEpoch()));
} else {
Settings::values.custom_rtc.SetValue(std::nullopt);
}
}
} else { } else {
ConfigurationShared::ApplyPerGameSetting(&Settings::values.language_index, ConfigurationShared::ApplyPerGameSetting(&Settings::values.language_index,
ui->combo_language); ui->combo_language);