refactor: improve AOC title ID handling and logging in FSP_SRV and IAddOnContentManager

This commit is contained in:
bdm
2026-06-28 18:59:24 +08:00
parent 32f21c8e71
commit fb234d8196
3 changed files with 104 additions and 60 deletions
+8 -2
View File
@@ -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();
+51 -20
View File
@@ -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));