diff --git a/libraries/libstratosphere/source/sprofile/srv/sprofile_srv_api.cpp b/libraries/libstratosphere/source/sprofile/srv/sprofile_srv_api.cpp
index 5fc1e5100..c856399dc 100644
--- a/libraries/libstratosphere/source/sprofile/srv/sprofile_srv_api.cpp
+++ b/libraries/libstratosphere/source/sprofile/srv/sprofile_srv_api.cpp
@@ -86,6 +86,9 @@ namespace ams::sprofile::srv {
/* Create the profile manager. */
util::ConstructAt(g_profile_manager, SaveDataInfo);
+ /* Process profile manager savedata. */
+ util::GetReference(g_profile_manager).InitializeSaveData();
+
/* Create the service objects. */
util::ConstructAt(g_bg_service_object, std::addressof(g_sf_memory_resource), util::GetPointer(g_profile_manager));
util::ConstructAt(g_sp_service_object, std::addressof(g_sf_memory_resource), util::GetPointer(g_profile_manager));
diff --git a/libraries/libstratosphere/source/sprofile/srv/sprofile_srv_fs_utils.cpp b/libraries/libstratosphere/source/sprofile/srv/sprofile_srv_fs_utils.cpp
new file mode 100644
index 000000000..6f3a11a95
--- /dev/null
+++ b/libraries/libstratosphere/source/sprofile/srv/sprofile_srv_fs_utils.cpp
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2018-2020 Atmosphère-NX
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+#include
+#include "sprofile_srv_profile_manager.hpp"
+
+namespace ams::sprofile::srv {
+
+ Result WriteFile(const char *path, const void *src, size_t size) {
+ /* Create the file. */
+ R_TRY_CATCH(fs::CreateFile(path, size)) {
+ R_CATCH(fs::ResultPathAlreadyExists) { /* It's okay if the file already exists. */ }
+ } R_END_TRY_CATCH_WITH_ABORT_UNLESS;
+
+ /* Open the file. */
+ fs::FileHandle file;
+ R_ABORT_UNLESS(fs::OpenFile(std::addressof(file), path, fs::OpenMode_Write));
+ ON_SCOPE_EXIT { fs::CloseFile(file); };
+
+ /* Set the file size. */
+ R_ABORT_UNLESS(fs::SetFileSize(file, size));
+
+ /* Write the file. */
+ return fs::WriteFile(file, 0, src, size, fs::WriteOption::Flush);
+ }
+
+}
diff --git a/libraries/libstratosphere/source/sprofile/srv/sprofile_srv_fs_utils.hpp b/libraries/libstratosphere/source/sprofile/srv/sprofile_srv_fs_utils.hpp
new file mode 100644
index 000000000..19bb8229c
--- /dev/null
+++ b/libraries/libstratosphere/source/sprofile/srv/sprofile_srv_fs_utils.hpp
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2018-2020 Atmosphère-NX
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+#pragma once
+#include
+
+namespace ams::sprofile::srv {
+
+ Result ReadFile(const char *path, void *dst, size_t size, s64 offset);
+ Result WriteFile(const char *path, const void *src, size_t size);
+ Result MoveFile(const char *dst_path, const char *src_path);
+
+}
\ No newline at end of file
diff --git a/libraries/libstratosphere/source/sprofile/srv/sprofile_srv_profile_manager.cpp b/libraries/libstratosphere/source/sprofile/srv/sprofile_srv_profile_manager.cpp
new file mode 100644
index 000000000..684ce7715
--- /dev/null
+++ b/libraries/libstratosphere/source/sprofile/srv/sprofile_srv_profile_manager.cpp
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2018-2020 Atmosphère-NX
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+#include
+#include "sprofile_srv_profile_manager.hpp"
+
+namespace ams::sprofile::srv {
+
+ namespace {
+
+ Result CreateSaveData(const ProfileManager::SaveDataInfo &save_data_info) {
+ R_TRY_CATCH(fs::CreateSystemSaveData(save_data_info.id, save_data_info.size, save_data_info.journal_size, save_data_info.flags)) {
+ R_CATCH(fs::ResultPathAlreadyExists) { /* Nintendo accepts already-existing savedata here. */ }
+ } R_END_TRY_CATCH;
+ return ResultSuccess();
+ }
+
+ }
+
+ ProfileManager::ProfileManager(const SaveDataInfo &save_data_info)
+ : m_general_mutex(), m_fs_mutex(), m_save_data_info(save_data_info), m_save_file_mounted(false),
+ m_update_observer_manager()
+ {
+ /* ... */
+ }
+
+ void ProfileManager::InitializeSaveData() {
+ /* Acquire locks. */
+ std::scoped_lock lk1(m_general_mutex);
+ std::scoped_lock lk2(m_fs_mutex);
+
+ /* Ensure the savedata exists. */
+ if (R_SUCCEEDED(CreateSaveData(m_save_data_info))) {
+ m_save_file_mounted = R_SUCCEEDED(fs::MountSystemSaveData(m_save_data_info.mount_name, m_save_data_info.id));
+
+ /* TODO: Remove this after implementation, as it's for debugging. */
+ R_ABORT_UNLESS(fs::MountSdCard("sprof-dbg"));
+ }
+ }
+
+}
diff --git a/libraries/libstratosphere/source/sprofile/srv/sprofile_srv_profile_manager.hpp b/libraries/libstratosphere/source/sprofile/srv/sprofile_srv_profile_manager.hpp
index 803fc906e..c800134c1 100644
--- a/libraries/libstratosphere/source/sprofile/srv/sprofile_srv_profile_manager.hpp
+++ b/libraries/libstratosphere/source/sprofile/srv/sprofile_srv_profile_manager.hpp
@@ -15,6 +15,7 @@
*/
#pragma once
#include
+#include "sprofile_srv_profile_update_observer_impl.hpp"
namespace ams::sprofile::srv {
@@ -28,19 +29,21 @@ namespace ams::sprofile::srv {
u32 flags;
};
private:
- class UpdateObserverManager;
private:
os::SdkMutex m_general_mutex;
os::SdkMutex m_fs_mutex;
SaveDataInfo m_save_data_info;
+ bool m_save_file_mounted;
/* TODO: util::optional m_profile_importer; */
/* TODO: util::optional m_profile_metadata; */
/* TODO: util::optional m_service_profile; */
- UpdateObserverManager *m_update_observer_manager;
+ ProfileUpdateObserverManager m_update_observer_manager;
public:
ProfileManager(const SaveDataInfo &save_data_info);
public:
- /* TODO */
+ void InitializeSaveData();
+
+ ProfileUpdateObserverManager &GetUpdateObserverManager() { return m_update_observer_manager; }
private:
/* TODO */
};
diff --git a/libraries/libstratosphere/source/sprofile/srv/sprofile_srv_profile_update_observer_impl.cpp b/libraries/libstratosphere/source/sprofile/srv/sprofile_srv_profile_update_observer_impl.cpp
new file mode 100644
index 000000000..e5b4a66ee
--- /dev/null
+++ b/libraries/libstratosphere/source/sprofile/srv/sprofile_srv_profile_update_observer_impl.cpp
@@ -0,0 +1,115 @@
+/*
+ * Copyright (c) 2018-2020 Atmosphère-NX
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+#include
+#include "sprofile_srv_profile_manager.hpp"
+#include "sprofile_srv_profile_update_observer_impl.hpp"
+
+namespace ams::sprofile::srv {
+
+ namespace {
+
+ class AutoUnregisterObserver : public ProfileUpdateObserverImpl {
+ public:
+ static constexpr auto MaxProfiles = 4;
+ private:
+ Identifier m_profiles[MaxProfiles];
+ int m_profile_count;
+ os::SdkMutex m_mutex;
+ ProfileUpdateObserverManager *m_manager;
+ public:
+ AutoUnregisterObserver(ProfileUpdateObserverManager *manager) : m_profile_count(0), m_mutex(), m_manager(manager) { /* ... */ }
+ virtual ~AutoUnregisterObserver() { m_manager->CloseObserver(this); }
+ public:
+ Result Listen(Identifier profile) {
+ /* Lock ourselves. */
+ std::scoped_lock lk(m_mutex);
+
+ /* Check if we can listen. */
+ R_UNLESS(m_profile_count < MaxProfiles, sprofile::ResultMaxListeners());
+
+ /* Check if we're already listening. */
+ for (auto i = 0; i < m_profile_count; ++i) {
+ R_UNLESS(m_profiles[i] != profile, sprofile::ResultAlreadyListening());
+ }
+
+ /* Add the profile. */
+ m_profiles[m_profile_count++] = profile;
+ return ResultSuccess();
+ }
+
+ Result Unlisten(Identifier profile) {
+ /* Check that we're listening. */
+ for (auto i = 0; i < m_profile_count; ++i) {
+ if (m_profiles[i] == profile) {
+ m_profiles[i] = m_profiles[--m_profile_count];
+ AMS_ABORT_UNLESS(m_profile_count >= 0);
+ return ResultSuccess();
+ }
+ }
+
+ return sprofile::ResultNotListening();
+ }
+
+ Result GetEventHandle(sf::OutCopyHandle out) {
+ out.SetValue(this->GetEvent().GetReadableHandle());
+ return ResultSuccess();
+ }
+ };
+ static_assert(sprofile::IsIProfileUpdateObserver);
+
+ }
+
+ Result ProfileUpdateObserverManager::OpenObserver(sf::Out> &out, MemoryResource *memory_resource) {
+ /* Lock ourselves. */
+ std::scoped_lock lk(m_mutex);
+
+ /* Check that we can allocate. */
+ R_UNLESS(m_observer_count < MaxObservers, sprofile::ResultMaxObservers());
+
+ /* Allocate an object. */
+ auto obj = sf::ObjectFactory::CreateSharedEmplaced(memory_resource, this);
+ R_UNLESS(obj != nullptr, sprofile::ResultAllocationFailed());
+
+ /* Register the observer. */
+ m_observers[m_observer_count++] = std::addressof(obj.GetImpl());
+
+ /* Return the object. */
+ *out = std::move(obj);
+ return ResultSuccess();
+ }
+
+ void ProfileUpdateObserverManager::CloseObserver(ProfileUpdateObserverImpl *observer) {
+ /* Lock ourselves. */
+ std::scoped_lock lk(m_mutex);
+
+ /* Find the observer. */
+ int index = -1;
+ for (auto i = 0; i < m_observer_count; ++i) {
+ if (m_observers[i] == observer) {
+ index = i;
+ break;
+ }
+ }
+ AMS_ABORT_UNLESS(index != -1);
+
+ /* Remove from our list. */
+ m_observers[index] = m_observers[--m_observer_count];
+
+ /* Sanity check. */
+ AMS_ABORT_UNLESS(m_observer_count >= 0);
+ }
+
+}
diff --git a/libraries/libstratosphere/source/sprofile/srv/sprofile_srv_profile_update_observer_impl.hpp b/libraries/libstratosphere/source/sprofile/srv/sprofile_srv_profile_update_observer_impl.hpp
new file mode 100644
index 000000000..6a1810630
--- /dev/null
+++ b/libraries/libstratosphere/source/sprofile/srv/sprofile_srv_profile_update_observer_impl.hpp
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2018-2020 Atmosphère-NX
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+#pragma once
+#include
+#include "sprofile_srv_i_profile_update_observer.hpp"
+
+namespace ams::sprofile::srv {
+
+ class ProfileUpdateObserverImpl {
+ private:
+ os::SystemEvent m_event;
+ public:
+ ProfileUpdateObserverImpl() : m_event(os::EventClearMode_ManualClear, true) { /* ... */ }
+ virtual ~ProfileUpdateObserverImpl() { /* ... */ }
+ public:
+ os::SystemEvent &GetEvent() { return m_event; }
+ const os::SystemEvent &GetEvent() const { return m_event; }
+ };
+
+ class ProfileUpdateObserverManager {
+ public:
+ static constexpr auto MaxObservers = 10;
+ private:
+ ProfileUpdateObserverImpl *m_observers[MaxObservers];
+ int m_observer_count;
+ os::SdkMutex m_mutex;
+ public:
+ ProfileUpdateObserverManager() : m_observer_count(0), m_mutex() { /* ... */ }
+ public:
+ Result OpenObserver(sf::Out> &out, MemoryResource *memory_resource);
+ void CloseObserver(ProfileUpdateObserverImpl *observer);
+ };
+
+}
diff --git a/libraries/libstratosphere/source/sprofile/srv/sprofile_srv_service_for_bg_agent.cpp b/libraries/libstratosphere/source/sprofile/srv/sprofile_srv_service_for_bg_agent.cpp
new file mode 100644
index 000000000..cd9a19ad1
--- /dev/null
+++ b/libraries/libstratosphere/source/sprofile/srv/sprofile_srv_service_for_bg_agent.cpp
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2018-2020 Atmosphère-NX
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+#include
+#include "sprofile_srv_profile_manager.hpp"
+#include "sprofile_srv_service_for_bg_agent.hpp"
+#include "sprofile_srv_fs_utils.hpp"
+
+namespace ams::sprofile::srv {
+
+ Result ServiceForBgAgent::OpenProfileImporter(sf::Out> out) {
+ AMS_ABORT("TODO: OpenProfileImporter");
+ }
+
+ Result ServiceForBgAgent::ReadMetadata(sf::Out out_count, const sf::OutBuffer &out_buf, const sf::InBuffer &meta) {
+ WriteFile("sprof-dbg:/sprof/meta.bin", meta.GetPointer(), meta.GetSize());
+ AMS_ABORT("TODO: ReadMetadata");
+ }
+ Result ServiceForBgAgent::IsUpdateNeeded(sf::Out out, Identifier revision_key) {
+ WriteFile("sprof-dbg:/sprof/revision_key.bin", std::addressof(revision_key), sizeof(revision_key));
+ AMS_ABORT("TODO: IsUpdateNeeded");
+ }
+
+ Result ServiceForBgAgent::Reset() {
+ AMS_ABORT("TODO: Reset");
+ }
+
+}
diff --git a/libraries/libstratosphere/source/sprofile/srv/sprofile_srv_service_for_system_process.cpp b/libraries/libstratosphere/source/sprofile/srv/sprofile_srv_service_for_system_process.cpp
new file mode 100644
index 000000000..f0844e4f9
--- /dev/null
+++ b/libraries/libstratosphere/source/sprofile/srv/sprofile_srv_service_for_system_process.cpp
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2018-2020 Atmosphère-NX
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+#include
+#include "sprofile_srv_profile_manager.hpp"
+#include "sprofile_srv_service_for_system_process.hpp"
+
+namespace ams::sprofile::srv {
+
+ Result ServiceForSystemProcess::OpenProfileReader(sf::Out> out) {
+ /* TODO */
+ AMS_ABORT("TODO: OpenProfileReader");
+ }
+
+ Result ServiceForSystemProcess::OpenProfileUpdateObserver(sf::Out> out) {
+ return m_profile_manager->GetUpdateObserverManager().OpenObserver(out, m_memory_resource);
+ }
+
+ Result ServiceForSystemProcess::OpenProfileControllerForDebug(sf::Out> out) {
+ /* TODO */
+ AMS_ABORT("TODO: OpenProfileControllerForDebug");
+ }
+
+}
diff --git a/libraries/libvapours/include/vapours/results.hpp b/libraries/libvapours/include/vapours/results.hpp
index a9534855f..49aa3f4a7 100644
--- a/libraries/libvapours/include/vapours/results.hpp
+++ b/libraries/libvapours/include/vapours/results.hpp
@@ -64,6 +64,7 @@
#include
#include
#include
+#include
#include
#include
#include
diff --git a/libraries/libvapours/include/vapours/results/sprofile_results.hpp b/libraries/libvapours/include/vapours/results/sprofile_results.hpp
new file mode 100644
index 000000000..81eb78ab1
--- /dev/null
+++ b/libraries/libvapours/include/vapours/results/sprofile_results.hpp
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2018-2020 Atmosphère-NX
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+#pragma once
+#include
+
+namespace ams::sprofile {
+
+ R_DEFINE_NAMESPACE_RESULT_MODULE(246);
+
+ R_DEFINE_ERROR_RESULT(AllocationFailed, 401);
+
+ R_DEFINE_ERROR_RESULT(MaxListeners, 620);
+ R_DEFINE_ERROR_RESULT(AlreadyListening, 621);
+ R_DEFINE_ERROR_RESULT(NotListening, 622);
+ R_DEFINE_ERROR_RESULT(MaxObservers, 623);
+
+}