mirror of
https://github.com/Atmosphere-NX/Atmosphere
synced 2024-11-09 22:56:35 +00:00
sprofile: implement non-importer bgagent commands
This commit is contained in:
parent
75d5e2aef0
commit
ae54ec5981
9 changed files with 251 additions and 21 deletions
|
@ -18,6 +18,24 @@
|
|||
|
||||
namespace ams::sprofile::srv {
|
||||
|
||||
Result ReadFile(const char *path, void *dst, size_t size, s64 offset) {
|
||||
/* Open the file. */
|
||||
fs::FileHandle file;
|
||||
R_TRY_CATCH(fs::OpenFile(std::addressof(file), path, fs::OpenMode_Read)) {
|
||||
R_CATCH_RETHROW(fs::ResultPathNotFound) /* It's okay if the file doesn't exist. */
|
||||
} R_END_TRY_CATCH_WITH_ABORT_UNLESS;
|
||||
ON_SCOPE_EXIT { fs::CloseFile(file); };
|
||||
|
||||
/* Read the file. */
|
||||
size_t read_size;
|
||||
R_TRY(fs::ReadFile(std::addressof(read_size), file, offset, dst, size));
|
||||
|
||||
/* Check the size was correct. */
|
||||
AMS_ABORT_UNLESS(size == read_size);
|
||||
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
Result WriteFile(const char *path, const void *src, size_t size) {
|
||||
/* Create the file. */
|
||||
R_TRY_CATCH(fs::CreateFile(path, size)) {
|
||||
|
|
|
@ -15,11 +15,11 @@
|
|||
*/
|
||||
#pragma once
|
||||
#include <stratosphere.hpp>
|
||||
#include "sprofile_srv_types.hpp"
|
||||
|
||||
/* TODO: sf::LargeData types, not buffers */
|
||||
#define AMS_SPROFILE_I_PROFILE_IMPORTER_INTERFACE_INFO(C, H) \
|
||||
AMS_SF_METHOD_INFO(C, H, 0, Result, ImportProfile, (const sf::InBuffer &data), (data)) \
|
||||
AMS_SF_METHOD_INFO(C, H, 1, Result, Commit, (), ()) \
|
||||
AMS_SF_METHOD_INFO(C, H, 0, Result, ImportMetadata, (const sf::InBuffer &data), (data)) \
|
||||
AMS_SF_METHOD_INFO(C, H, 0, Result, ImportProfile, (const sprofile::srv::ProfileDataForImportData &data), (data)) \
|
||||
AMS_SF_METHOD_INFO(C, H, 1, Result, Commit, (), ()) \
|
||||
AMS_SF_METHOD_INFO(C, H, 0, Result, ImportMetadata, (const sprofile::srv::ProfileMetadataForImportMetadata &data), (data)) \
|
||||
|
||||
AMS_SF_DEFINE_INTERFACE(ams::sprofile, IProfileImporter, AMS_SPROFILE_I_PROFILE_IMPORTER_INTERFACE_INFO)
|
||||
|
|
|
@ -17,11 +17,10 @@
|
|||
#include <stratosphere.hpp>
|
||||
#include "sprofile_srv_i_profile_importer.hpp"
|
||||
|
||||
/* TODO: sf::LargeData types, not buffers */
|
||||
#define AMS_SPROFILE_I_SPROFILE_SERVICE_FOR_BG_AGENT_INTERFACE_INFO(C, H) \
|
||||
AMS_SF_METHOD_INFO(C, H, 100, Result, OpenProfileImporter, (sf::Out<sf::SharedPointer<::ams::sprofile::IProfileImporter>> out), (out)) \
|
||||
AMS_SF_METHOD_INFO(C, H, 200, Result, ReadMetadata, (sf::Out<u32> out_count, const sf::OutBuffer &out_buf, const sf::InBuffer &meta), (out_count, out_buf, meta)) \
|
||||
AMS_SF_METHOD_INFO(C, H, 201, Result, IsUpdateNeeded, (sf::Out<bool> out, sprofile::Identifier revision_key), (out, revision_key)) \
|
||||
AMS_SF_METHOD_INFO(C, H, 2000, Result, Reset, (), ())
|
||||
AMS_SF_METHOD_INFO(C, H, 100, Result, OpenProfileImporter, (sf::Out<sf::SharedPointer<::ams::sprofile::IProfileImporter>> out), (out)) \
|
||||
AMS_SF_METHOD_INFO(C, H, 200, Result, ReadMetadata, (sf::Out<u32> out_count, const sf::OutArray<sprofile::srv::ReadMetadataEntry> &out, const sprofile::srv::ReadMetadataArgument &arg), (out_count, out, arg)) \
|
||||
AMS_SF_METHOD_INFO(C, H, 201, Result, IsUpdateNeeded, (sf::Out<bool> out, sprofile::Identifier revision_key), (out, revision_key)) \
|
||||
AMS_SF_METHOD_INFO(C, H, 2000, Result, Reset, (), ())
|
||||
|
||||
AMS_SF_DEFINE_INTERFACE(ams::sprofile, ISprofileServiceForBgAgent, AMS_SPROFILE_I_SPROFILE_SERVICE_FOR_BG_AGENT_INTERFACE_INFO)
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
*/
|
||||
#include <stratosphere.hpp>
|
||||
#include "sprofile_srv_profile_manager.hpp"
|
||||
#include "sprofile_srv_fs_utils.hpp"
|
||||
|
||||
namespace ams::sprofile::srv {
|
||||
|
||||
|
@ -30,8 +31,8 @@ namespace ams::sprofile::srv {
|
|||
}
|
||||
|
||||
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()
|
||||
: m_save_data_info(save_data_info), m_save_file_mounted(false),
|
||||
m_profile_metadata(util::nullopt), m_update_observer_manager()
|
||||
{
|
||||
/* ... */
|
||||
}
|
||||
|
@ -50,4 +51,57 @@ namespace ams::sprofile::srv {
|
|||
}
|
||||
}
|
||||
|
||||
Result ProfileManager::ResetSaveData() {
|
||||
/* Acquire locks. */
|
||||
std::scoped_lock lk1(m_service_profile_mutex);
|
||||
std::scoped_lock lk2(m_profile_metadata_mutex);
|
||||
std::scoped_lock lk3(m_general_mutex);
|
||||
std::scoped_lock lk4(m_fs_mutex);
|
||||
|
||||
/* Unmount save file. */
|
||||
fs::Unmount(m_save_data_info.mount_name);
|
||||
m_save_file_mounted = false;
|
||||
|
||||
/* Delete save file. */
|
||||
R_TRY(fs::DeleteSystemSaveData(fs::SaveDataSpaceId::System, m_save_data_info.id, fs::InvalidUserId));
|
||||
|
||||
/* Unload profile. */
|
||||
m_profile_metadata = util::nullopt;
|
||||
/* TODO m_service_profile = util::nullopt; */
|
||||
|
||||
/* Create the save data. */
|
||||
R_TRY(CreateSaveData(m_save_data_info));
|
||||
|
||||
/* Try to mount the save file. */
|
||||
const auto result = fs::MountSystemSaveData(m_save_data_info.mount_name, m_save_data_info.id);
|
||||
m_save_file_mounted = R_SUCCEEDED(result);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
Result ProfileManager::LoadPrimaryMetadata(ProfileMetadata *out) {
|
||||
/* Acquire locks. */
|
||||
std::scoped_lock lk1(m_profile_metadata_mutex);
|
||||
std::scoped_lock lk2(m_general_mutex);
|
||||
|
||||
/* If we don't have metadata, load it. */
|
||||
if (!m_profile_metadata.has_value()) {
|
||||
/* Emplace our metadata. */
|
||||
m_profile_metadata.emplace();
|
||||
auto meta_guard = SCOPE_GUARD { m_profile_metadata = util::nullopt; };
|
||||
|
||||
/* Read profile metadata. */
|
||||
char path[0x30];
|
||||
AMS_ABORT_UNLESS(util::TSNPrintf(path, sizeof(path), "%s:/%s/metadata", m_save_data_info.mount_name, "primary") < static_cast<int>(sizeof(path)));
|
||||
R_TRY(ReadFile(path, std::addressof(*m_profile_metadata), sizeof(*m_profile_metadata), 0));
|
||||
|
||||
/* We read the metadata successfully. */
|
||||
meta_guard.Cancel();
|
||||
}
|
||||
|
||||
/* Set the output. */
|
||||
*out = *m_profile_metadata;
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
*/
|
||||
#pragma once
|
||||
#include <stratosphere.hpp>
|
||||
#include "sprofile_srv_types.hpp"
|
||||
#include "sprofile_srv_profile_update_observer_impl.hpp"
|
||||
|
||||
namespace ams::sprofile::srv {
|
||||
|
@ -30,18 +31,24 @@ namespace ams::sprofile::srv {
|
|||
};
|
||||
private:
|
||||
private:
|
||||
os::SdkMutex m_general_mutex;
|
||||
os::SdkMutex m_fs_mutex;
|
||||
os::SdkMutex m_general_mutex{};
|
||||
os::SdkMutex m_fs_mutex{};
|
||||
SaveDataInfo m_save_data_info;
|
||||
bool m_save_file_mounted;
|
||||
/* TODO: util::optional<ProfileImporter> m_profile_importer; */
|
||||
/* TODO: util::optional<ProfileMetadata> m_profile_metadata; */
|
||||
os::SdkMutex m_profile_importer_mutex{};
|
||||
util::optional<ProfileMetadata> m_profile_metadata;
|
||||
os::SdkMutex m_profile_metadata_mutex{};
|
||||
/* TODO: util::optional<ServiceProfile> m_service_profile; */
|
||||
os::SdkMutex m_service_profile_mutex{};
|
||||
ProfileUpdateObserverManager m_update_observer_manager;
|
||||
public:
|
||||
ProfileManager(const SaveDataInfo &save_data_info);
|
||||
public:
|
||||
void InitializeSaveData();
|
||||
Result ResetSaveData();
|
||||
|
||||
Result LoadPrimaryMetadata(ProfileMetadata *out);
|
||||
|
||||
ProfileUpdateObserverManager &GetUpdateObserverManager() { return m_update_observer_manager; }
|
||||
private:
|
||||
|
|
|
@ -24,17 +24,58 @@ namespace ams::sprofile::srv {
|
|||
AMS_ABORT("TODO: OpenProfileImporter");
|
||||
}
|
||||
|
||||
Result ServiceForBgAgent::ReadMetadata(sf::Out<u32> 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::ReadMetadata(sf::Out<u32> out_count, const sf::OutArray<sprofile::srv::ReadMetadataEntry> &out, const sprofile::srv::ReadMetadataArgument &arg) {
|
||||
/* Check size. */
|
||||
R_UNLESS(out.GetSize() >= arg.metadata.num_entries, sprofile::ResultInvalidArgument());
|
||||
|
||||
/* Load primary metadata. */
|
||||
sprofile::srv::ProfileMetadata primary_metadata;
|
||||
R_TRY_CATCH(m_profile_manager->LoadPrimaryMetadata(std::addressof(primary_metadata))) {
|
||||
R_CATCH(fs::ResultPathNotFound) {
|
||||
/* If we have no metadata, we can't get any entries. */
|
||||
*out_count = 0;
|
||||
return ResultSuccess();
|
||||
}
|
||||
} R_END_TRY_CATCH;
|
||||
|
||||
/* Copy matching entries. */
|
||||
u32 count = 0;
|
||||
for (u32 i = 0; i < arg.metadata.num_entries; ++i) {
|
||||
const auto &arg_entry = arg.metadata.entries[i];
|
||||
|
||||
for (u32 j = 0; j < primary_metadata.num_entries; ++j) {
|
||||
const auto &pri_entry = primary_metadata.entries[j];
|
||||
|
||||
if (pri_entry.identifier_0 == arg_entry.identifier_0 && pri_entry.identifier_1 == arg_entry.identifier_1) {
|
||||
out[count++] = arg.entries[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Set output count. */
|
||||
*out_count = count;
|
||||
return ResultSuccess();
|
||||
|
||||
}
|
||||
Result ServiceForBgAgent::IsUpdateNeeded(sf::Out<bool> out, Identifier revision_key) {
|
||||
WriteFile("sprof-dbg:/sprof/revision_key.bin", std::addressof(revision_key), sizeof(revision_key));
|
||||
AMS_ABORT("TODO: IsUpdateNeeded");
|
||||
/* Load primary metadata. */
|
||||
bool loaded_metadata = true;
|
||||
sprofile::srv::ProfileMetadata primary_metadata;
|
||||
R_TRY_CATCH(m_profile_manager->LoadPrimaryMetadata(std::addressof(primary_metadata))) {
|
||||
R_CATCH(fs::ResultPathNotFound) {
|
||||
/* If we have no metadata, we don't have a revision key. */
|
||||
loaded_metadata = false;
|
||||
}
|
||||
} R_END_TRY_CATCH;
|
||||
|
||||
/* Determine if update is needed. */
|
||||
*out = !(loaded_metadata && revision_key == primary_metadata.revision_key);
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
Result ServiceForBgAgent::Reset() {
|
||||
AMS_ABORT("TODO: Reset");
|
||||
return m_profile_manager->ResetSaveData();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -29,7 +29,7 @@ namespace ams::sprofile::srv {
|
|||
constexpr ServiceForBgAgent(MemoryResource *mr, ProfileManager *pm) : m_memory_resource(mr), m_profile_manager(pm) { /* ... */ }
|
||||
public:
|
||||
Result OpenProfileImporter(sf::Out<sf::SharedPointer<::ams::sprofile::IProfileImporter>> out);
|
||||
Result ReadMetadata(sf::Out<u32> out_count, const sf::OutBuffer &out_buf, const sf::InBuffer &meta);
|
||||
Result ReadMetadata(sf::Out<u32> out_count, const sf::OutArray<sprofile::srv::ReadMetadataEntry> &out, const sprofile::srv::ReadMetadataArgument &arg);
|
||||
Result IsUpdateNeeded(sf::Out<bool> out, Identifier revision_key);
|
||||
Result Reset();
|
||||
};
|
||||
|
|
|
@ -0,0 +1,106 @@
|
|||
/*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
#include <stratosphere.hpp>
|
||||
|
||||
namespace ams::sprofile::srv {
|
||||
|
||||
struct ProfileMetadataEntry {
|
||||
Identifier identifier_0;
|
||||
Identifier identifier_1;
|
||||
u8 unk_0E[0x32];
|
||||
};
|
||||
static_assert(util::is_pod<ProfileMetadataEntry>::value);
|
||||
static_assert(sizeof(ProfileMetadataEntry) == 0x40);
|
||||
|
||||
constexpr inline const u32 ProfileMetadataVersion = 0;
|
||||
|
||||
struct ProfileMetadata {
|
||||
u32 version;
|
||||
u32 num_entries;
|
||||
Identifier revision_key;
|
||||
u8 unk_10[0x30];
|
||||
ProfileMetadataEntry entries[50];
|
||||
};
|
||||
static_assert(util::is_pod<ProfileMetadata>::value);
|
||||
static_assert(sizeof(ProfileMetadata) == 0xCC0);
|
||||
|
||||
struct ProfileMetadataForImportMetadata : public sf::LargeData, public sf::PrefersMapAliasTransferMode {
|
||||
ProfileMetadata metadata;
|
||||
u8 unk[0x8000 - sizeof(metadata)];
|
||||
};
|
||||
static_assert(util::is_pod<ProfileMetadataForImportMetadata>::value);
|
||||
static_assert(sizeof(ProfileMetadataForImportMetadata) == 0x8000);
|
||||
|
||||
constexpr inline const u32 ProfileDataVersion = 0;
|
||||
|
||||
enum ValueType : u8 {
|
||||
ValueType_Byte = 0,
|
||||
ValueType_U32 = 1,
|
||||
ValueType_S32 = 2,
|
||||
ValueType_U64 = 3,
|
||||
ValueType_S64 = 4,
|
||||
};
|
||||
|
||||
struct ProfileDataEntry {
|
||||
Identifier key;
|
||||
ValueType type;
|
||||
union {
|
||||
s64 value_s64;
|
||||
u64 value_u64;
|
||||
s32 value_s32;
|
||||
u32 value_u32;
|
||||
u8 value_u8;
|
||||
};
|
||||
};
|
||||
static_assert(util::is_pod<ProfileDataEntry>::value);
|
||||
static_assert(sizeof(ProfileDataEntry) == 0x10);
|
||||
|
||||
struct ProfileData {
|
||||
u32 version;
|
||||
u32 num_entries;
|
||||
u8 unk_08[0x28];
|
||||
ProfileDataEntry entries[(0x4000 - 0x30) / sizeof(ProfileDataEntry)];
|
||||
};
|
||||
static_assert(util::is_pod<ProfileData>::value);
|
||||
static_assert(sizeof(ProfileData) == 0x4000);
|
||||
|
||||
struct ProfileDataForImportData : public sf::LargeData, public sf::PrefersMapAliasTransferMode {
|
||||
Identifier identifier_0;
|
||||
Identifier identifier_1;
|
||||
u8 unk_0E[2];
|
||||
ProfileData data;
|
||||
u8 unk_4010[0x4400 - 0x4010];
|
||||
};
|
||||
static_assert(util::is_pod<ProfileDataForImportData>::value);
|
||||
static_assert(sizeof(ProfileDataForImportData) == 0x4400);
|
||||
|
||||
struct ReadMetadataEntry {
|
||||
u8 unk[0x100];
|
||||
};
|
||||
static_assert(util::is_pod<ReadMetadataEntry>::value);
|
||||
static_assert(sizeof(ReadMetadataEntry) == 0x100);
|
||||
|
||||
struct ReadMetadataArgument : public sf::LargeData, public sf::PrefersMapAliasTransferMode {
|
||||
ProfileMetadata metadata;
|
||||
ReadMetadataEntry entries[(0x8000 - sizeof(metadata)) / sizeof(ReadMetadataEntry)];
|
||||
u8 unk_7FC0[0x40];
|
||||
};
|
||||
static_assert(util::is_pod<ReadMetadataArgument>::value);
|
||||
static_assert(sizeof(ReadMetadataArgument) == 0x8000);
|
||||
|
||||
|
||||
}
|
|
@ -21,6 +21,9 @@ namespace ams::sprofile {
|
|||
|
||||
R_DEFINE_NAMESPACE_RESULT_MODULE(246);
|
||||
|
||||
R_DEFINE_ERROR_RESULT(InvalidArgument, 100);
|
||||
R_DEFINE_ERROR_RESULT(InvalidState, 101);
|
||||
|
||||
R_DEFINE_ERROR_RESULT(AllocationFailed, 401);
|
||||
|
||||
R_DEFINE_ERROR_RESULT(MaxListeners, 620);
|
||||
|
@ -28,4 +31,6 @@ namespace ams::sprofile {
|
|||
R_DEFINE_ERROR_RESULT(NotListening, 622);
|
||||
R_DEFINE_ERROR_RESULT(MaxObservers, 623);
|
||||
|
||||
R_DEFINE_ERROR_RESULT(InvalidMetadataVersion, 3210);
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue