sprofile: implement non-importer bgagent commands

This commit is contained in:
Michael Scire 2021-09-16 00:07:06 -07:00 committed by SciresM
parent 75d5e2aef0
commit ae54ec5981
9 changed files with 251 additions and 21 deletions

View file

@ -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)) {

View file

@ -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)

View file

@ -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)

View file

@ -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();
}
}

View file

@ -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:

View file

@ -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();
}
}

View file

@ -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();
};

View file

@ -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);
}

View file

@ -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);
}