mirror of
https://github.com/citron-neo/emulator.git
synced 2026-07-05 15:21:57 -07:00
refactor: improve AOC title ID handling and logging in FSP_SRV and IAddOnContentManager
This commit is contained in:
@@ -267,10 +267,16 @@ void EmulationSession::RefreshContentSystem() {
|
||||
|
||||
bool EmulationSession::RefreshContentIfIdle(bool keys_loaded)
|
||||
{
|
||||
if (!keys_loaded || m_is_running)
|
||||
if (!keys_loaded) {
|
||||
return false;
|
||||
}
|
||||
|
||||
RefreshContentSystem();
|
||||
std::scoped_lock lock(m_mutex);
|
||||
if (m_is_running || m_load_result == Core::SystemResultStatus::Success) {
|
||||
return false;
|
||||
}
|
||||
|
||||
RefreshContentSystemUnlocked();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -58,6 +58,22 @@ static std::vector<u64> AccumulateAOCTitleIDs(Core::System& system) {
|
||||
return add_on_content;
|
||||
}
|
||||
|
||||
static std::vector<u64> GetAOCTitleIDsForBase(const std::vector<u64>& add_on_content, u64 base) {
|
||||
std::vector<u64> out;
|
||||
for (const auto title_id : add_on_content) {
|
||||
if (CheckAOCTitleIDMatchesBase(title_id, base)) {
|
||||
out.push_back(title_id);
|
||||
}
|
||||
}
|
||||
|
||||
std::sort(out.begin(), out.end());
|
||||
return out;
|
||||
}
|
||||
|
||||
static u32 GetGuestAOCIndex(std::size_t ordinal) {
|
||||
return static_cast<u32>(ordinal + 1);
|
||||
}
|
||||
|
||||
IAddOnContentManager::IAddOnContentManager(Core::System& system_)
|
||||
: ServiceFramework{system_, "aoc:u"}, add_on_content{AccumulateAOCTitleIDs(system)},
|
||||
service_context{system_, "aoc:u"} {
|
||||
@@ -108,9 +124,7 @@ Result IAddOnContentManager::CountAddOnContent(Out<u32> out_count, ClientProcess
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
*out_count = static_cast<u32>(
|
||||
std::count_if(add_on_content.begin(), add_on_content.end(),
|
||||
[current](u64 tid) { return CheckAOCTitleIDMatchesBase(tid, current); }));
|
||||
*out_count = static_cast<u32>(GetAOCTitleIDsForBase(add_on_content, current).size());
|
||||
LOG_WARNING(Service_AOC,
|
||||
"CountAddOnContent: program_id={:016X}, count={}",
|
||||
current, *out_count);
|
||||
@@ -126,20 +140,16 @@ Result IAddOnContentManager::ListAddOnContent(Out<u32> out_count,
|
||||
const auto current = FileSys::GetBaseTitleID(system.GetApplicationProcessProgramID());
|
||||
|
||||
std::vector<u32> out;
|
||||
const auto matching_aocs = GetAOCTitleIDsForBase(add_on_content, current);
|
||||
const auto& disabled = Settings::values.disabled_addons[current];
|
||||
if (std::find(disabled.begin(), disabled.end(), "DLC") == disabled.end()) {
|
||||
LOG_WARNING(Service_AOC, "Filtering AOCs for base title ID: {:016X}", current);
|
||||
for (u64 content_id : add_on_content) {
|
||||
const auto aoc_base = FileSys::GetBaseTitleID(content_id);
|
||||
if (aoc_base != current) {
|
||||
// LOG_WARNING(Service_AOC, "Skipping AOC {:016X} (Base: {:016X})", content_id,
|
||||
// aoc_base);
|
||||
continue;
|
||||
}
|
||||
|
||||
LOG_WARNING(Service_AOC, "Match! AOC {:016X} belongs to current app. Adding to list.",
|
||||
content_id);
|
||||
out.push_back(static_cast<u32>(FileSys::GetAOCID(content_id)));
|
||||
for (std::size_t i = 0; i < matching_aocs.size(); ++i) {
|
||||
const auto guest_index = GetGuestAOCIndex(i);
|
||||
LOG_WARNING(Service_AOC,
|
||||
"Match! AOC {:016X} belongs to current app. Adding guest_index={}.",
|
||||
matching_aocs[i], guest_index);
|
||||
out.push_back(guest_index);
|
||||
}
|
||||
} else {
|
||||
LOG_WARNING(Service_AOC, "DLCs are disabled for this title {:016X}", current);
|
||||
@@ -158,12 +168,11 @@ Result IAddOnContentManager::ListAddOnContent(Out<u32> out_count,
|
||||
|
||||
for (u32 i = 0; i < *out_count; ++i) {
|
||||
const auto addon_index = out[offset + i];
|
||||
const auto reconstructed_title_id =
|
||||
FileSys::GetAOCBaseTitleID(current) + addon_index;
|
||||
const auto physical_title_id = matching_aocs[addon_index - 1];
|
||||
|
||||
LOG_WARNING(Service_AOC,
|
||||
"ListAddOnContent output[{}]: addon_index={}, title_id={:016X}",
|
||||
i, addon_index, reconstructed_title_id);
|
||||
"ListAddOnContent output[{}]: addon_index={}, physical_title_id={:016X}",
|
||||
i, addon_index, physical_title_id);
|
||||
}
|
||||
|
||||
std::rotate(out.begin(), out.begin() + offset, out.end());
|
||||
@@ -185,9 +194,7 @@ Result IAddOnContentManager::CountAddOnContentByApplicationId(Out<u32> out_count
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
*out_count = static_cast<u32>(
|
||||
std::count_if(add_on_content.begin(), add_on_content.end(),
|
||||
[current](u64 tid) { return CheckAOCTitleIDMatchesBase(tid, current); }));
|
||||
*out_count = static_cast<u32>(GetAOCTitleIDsForBase(add_on_content, current).size());
|
||||
|
||||
R_SUCCEED();
|
||||
}
|
||||
@@ -201,18 +208,16 @@ Result IAddOnContentManager::ListAddOnContentByApplicationId(
|
||||
const auto current = FileSys::GetBaseTitleID(application_id);
|
||||
|
||||
std::vector<u32> out;
|
||||
const auto matching_aocs = GetAOCTitleIDsForBase(add_on_content, current);
|
||||
const auto& disabled = Settings::values.disabled_addons[current];
|
||||
if (std::find(disabled.begin(), disabled.end(), "DLC") == disabled.end()) {
|
||||
LOG_WARNING(Service_AOC, "Filtering AOCs for base title ID: {:016X}", current);
|
||||
for (u64 content_id : add_on_content) {
|
||||
const auto aoc_base = FileSys::GetBaseTitleID(content_id);
|
||||
if (aoc_base != current) {
|
||||
continue;
|
||||
}
|
||||
|
||||
LOG_WARNING(Service_AOC, "Match! AOC {:016X} belongs to current app. Adding to list.",
|
||||
content_id);
|
||||
out.push_back(static_cast<u32>(FileSys::GetAOCID(content_id)));
|
||||
for (std::size_t i = 0; i < matching_aocs.size(); ++i) {
|
||||
const auto guest_index = GetGuestAOCIndex(i);
|
||||
LOG_WARNING(Service_AOC,
|
||||
"Match! AOC {:016X} belongs to current app. Adding guest_index={}.",
|
||||
matching_aocs[i], guest_index);
|
||||
out.push_back(guest_index);
|
||||
}
|
||||
} else {
|
||||
LOG_WARNING(Service_AOC, "DLCs are disabled for this title {:016X}", current);
|
||||
@@ -231,13 +236,12 @@ Result IAddOnContentManager::ListAddOnContentByApplicationId(
|
||||
|
||||
for (u32 i = 0; i < *out_count; ++i) {
|
||||
const auto addon_index = out[offset + i];
|
||||
const auto reconstructed_title_id =
|
||||
FileSys::GetAOCBaseTitleID(current) + addon_index;
|
||||
const auto physical_title_id = matching_aocs[addon_index - 1];
|
||||
|
||||
LOG_WARNING(Service_AOC,
|
||||
"ListAddOnContentByApplicationId output[{}]: addon_index={}, "
|
||||
"title_id={:016X}",
|
||||
i, addon_index, reconstructed_title_id);
|
||||
"physical_title_id={:016X}",
|
||||
i, addon_index, physical_title_id);
|
||||
}
|
||||
|
||||
std::rotate(out.begin(), out.begin() + offset, out.end());
|
||||
@@ -275,13 +279,16 @@ Result IAddOnContentManager::GetAddOnContentBaseId(Out<u64> out_title_id,
|
||||
Result IAddOnContentManager::PrepareAddOnContent(s32 addon_index, ClientProcessId process_id) {
|
||||
const auto program_id = system.GetApplicationProcessProgramID();
|
||||
const auto aoc_base_id = FileSys::GetAOCBaseTitleID(program_id);
|
||||
const auto reconstructed_title_id =
|
||||
aoc_base_id + static_cast<u64>(static_cast<u32>(addon_index));
|
||||
const auto matching_aocs = GetAOCTitleIDsForBase(add_on_content, program_id);
|
||||
u64 physical_title_id = 0;
|
||||
if (addon_index > 0 && static_cast<std::size_t>(addon_index) <= matching_aocs.size()) {
|
||||
physical_title_id = matching_aocs[static_cast<std::size_t>(addon_index) - 1];
|
||||
}
|
||||
|
||||
LOG_WARNING(Service_AOC,
|
||||
"PrepareAddOnContent: program_id={:016X}, aoc_base={:016X}, "
|
||||
"addon_index={}, title_id={:016X}, process_id={}",
|
||||
program_id, aoc_base_id, addon_index, reconstructed_title_id,
|
||||
"addon_index={}, physical_title_id={:016X}, process_id={}",
|
||||
program_id, aoc_base_id, addon_index, physical_title_id,
|
||||
process_id.pid);
|
||||
|
||||
R_SUCCEED();
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2025 citron Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include <algorithm>
|
||||
#include <cinttypes>
|
||||
#include <cstring>
|
||||
#include <iterator>
|
||||
@@ -51,6 +52,21 @@
|
||||
|
||||
namespace Service::FileSystem {
|
||||
|
||||
static std::vector<u64> GetAOCPhysicalTitleIDsForBase(const FileSys::ContentProvider& content_provider,
|
||||
u64 base) {
|
||||
std::vector<u64> out;
|
||||
const auto entries =
|
||||
content_provider.ListEntriesFilter(FileSys::TitleType::AOC, FileSys::ContentRecordType::Data);
|
||||
for (const auto& entry : entries) {
|
||||
if (FileSys::GetBaseTitleID(entry.title_id) == base) {
|
||||
out.push_back(entry.title_id);
|
||||
}
|
||||
}
|
||||
|
||||
std::sort(out.begin(), out.end());
|
||||
return out;
|
||||
}
|
||||
|
||||
FSP_SRV::FSP_SRV(Core::System& system_)
|
||||
: ServiceFramework{system_, "fsp-srv"}, fsc{system.GetFileSystemController()},
|
||||
content_provider{system.GetContentProvider()}, reporter{system.GetReporter()} {
|
||||
@@ -497,7 +513,30 @@ Result FSP_SRV::OpenDataStorageByDataId(OutInterface<IStorage> out_interface,
|
||||
"title_id={:016X}",
|
||||
storage_id, unknown, title_id);
|
||||
|
||||
auto data = romfs_controller->OpenRomFS(title_id, storage_id, FileSys::ContentRecordType::Data);
|
||||
u64 resolved_title_id = title_id;
|
||||
const auto requested_base = FileSys::GetBaseTitleID(title_id);
|
||||
const auto requested_aoc_base = FileSys::GetAOCBaseTitleID(title_id);
|
||||
const auto requested_aoc_id = FileSys::GetAOCID(title_id);
|
||||
const auto requested_is_aoc =
|
||||
requested_aoc_id > 0 && title_id >= requested_aoc_base &&
|
||||
title_id <= requested_aoc_base + FileSys::AOC_TITLE_ID_MASK;
|
||||
std::vector<u64> matching_aocs;
|
||||
|
||||
if (requested_is_aoc) {
|
||||
matching_aocs = GetAOCPhysicalTitleIDsForBase(content_provider, requested_base);
|
||||
if (requested_aoc_id <= matching_aocs.size()) {
|
||||
resolved_title_id = matching_aocs[static_cast<std::size_t>(requested_aoc_id) - 1];
|
||||
if (resolved_title_id != title_id) {
|
||||
LOG_WARNING(Service_FS,
|
||||
"OpenDataStorageByDataId resolved AOC guest index: "
|
||||
"requested_title_id={:016X}, guest_index={}, physical_title_id={:016X}",
|
||||
title_id, requested_aoc_id, resolved_title_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto data =
|
||||
romfs_controller->OpenRomFS(resolved_title_id, storage_id, FileSys::ContentRecordType::Data);
|
||||
|
||||
if (!data) {
|
||||
const auto archive = FileSys::SystemArchive::SynthesizeSystemArchive(title_id);
|
||||
@@ -507,31 +546,22 @@ Result FSP_SRV::OpenDataStorageByDataId(OutInterface<IStorage> out_interface,
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
const auto requested_base = FileSys::GetBaseTitleID(title_id);
|
||||
const auto requested_aoc_base = FileSys::GetAOCBaseTitleID(title_id);
|
||||
const auto requested_aoc_id = FileSys::GetAOCID(title_id);
|
||||
if (title_id >= requested_aoc_base &&
|
||||
title_id <= requested_aoc_base + FileSys::AOC_TITLE_ID_MASK) {
|
||||
if (requested_is_aoc) {
|
||||
std::size_t matching_aoc_count = 0;
|
||||
const auto entries = content_provider.ListEntriesFilter(
|
||||
FileSys::TitleType::AOC, FileSys::ContentRecordType::Data);
|
||||
for (const auto& entry : entries) {
|
||||
if (FileSys::GetBaseTitleID(entry.title_id) != requested_base) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (const auto entry_title_id : matching_aocs) {
|
||||
++matching_aoc_count;
|
||||
LOG_WARNING(Service_FS,
|
||||
"OpenDataStorageByDataId miss context: installed_aoc_index={}, "
|
||||
"installed_title_id={:016X}",
|
||||
FileSys::GetAOCID(entry.title_id), entry.title_id);
|
||||
matching_aoc_count, entry_title_id);
|
||||
}
|
||||
|
||||
LOG_WARNING(Service_FS,
|
||||
"OpenDataStorageByDataId AOC miss: requested_base={:016X}, "
|
||||
"requested_aoc_base={:016X}, requested_aoc_index={}, "
|
||||
"matching_installed_aoc_count={}",
|
||||
requested_base, requested_aoc_base, requested_aoc_id, matching_aoc_count);
|
||||
"resolved_title_id={:016X}, matching_installed_aoc_count={}",
|
||||
requested_base, requested_aoc_base, requested_aoc_id, resolved_title_id,
|
||||
matching_aoc_count);
|
||||
}
|
||||
|
||||
LOG_ERROR(Service_FS,
|
||||
@@ -544,14 +574,15 @@ Result FSP_SRV::OpenDataStorageByDataId(OutInterface<IStorage> out_interface,
|
||||
if (title_id >= opened_aoc_base && title_id <= opened_aoc_base + FileSys::AOC_TITLE_ID_MASK) {
|
||||
LOG_WARNING(Service_FS,
|
||||
"OpenDataStorageByDataId opened AOC: base={:016X}, addon_index={}, "
|
||||
"title_id={:016X}",
|
||||
FileSys::GetBaseTitleID(title_id), FileSys::GetAOCID(title_id), title_id);
|
||||
"requested_title_id={:016X}, physical_title_id={:016X}",
|
||||
FileSys::GetBaseTitleID(title_id), FileSys::GetAOCID(title_id), title_id,
|
||||
resolved_title_id);
|
||||
}
|
||||
|
||||
const FileSys::PatchManager pm{title_id, fsc, content_provider};
|
||||
const FileSys::PatchManager pm{resolved_title_id, fsc, content_provider};
|
||||
|
||||
auto base =
|
||||
romfs_controller->OpenBaseNca(title_id, storage_id, FileSys::ContentRecordType::Data);
|
||||
romfs_controller->OpenBaseNca(resolved_title_id, storage_id, FileSys::ContentRecordType::Data);
|
||||
auto storage = std::make_shared<IStorage>(
|
||||
system, pm.PatchRomFS(base.get(), std::move(data), FileSys::ContentRecordType::Data));
|
||||
|
||||
|
||||
Reference in New Issue
Block a user