LogManager: implement system module, client api, logging api (#1617)
Some notes: * Unless `atmosphere!enable_log_manager` is true, Nintendo's log manager will be used instead. * This prevents paying memory costs for LM when not enabling logging. * To facilitate this, Atmosphere's log manager has a different program id from Nintendo's. * `atmosphere!enable_htc` implies `atmosphere!enable_log_manager`. * LogManager logs to tma, and the SD card (if `lm!enable_sd_card_logging` is true, which it is by default). * Binary logs are saved to `lm!sd_card_log_output_directory`, which is `atmosphere/binlogs` by default.
This commit is contained in:
145
libraries/libstratosphere/source/lm/srv/lm_ipc_server.cpp
Normal file
145
libraries/libstratosphere/source/lm/srv/lm_ipc_server.cpp
Normal file
@@ -0,0 +1,145 @@
|
||||
/*
|
||||
* 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/>.
|
||||
*/
|
||||
#include <stratosphere.hpp>
|
||||
#include "../lm_service_name.hpp"
|
||||
#include "lm_log_service_impl.hpp"
|
||||
#include "lm_log_getter.hpp"
|
||||
|
||||
namespace ams::lm::srv {
|
||||
|
||||
namespace {
|
||||
|
||||
constexpr inline size_t LogSessionCountMax = 42;
|
||||
constexpr inline size_t LogGetterSessionCountMax = 1;
|
||||
|
||||
constexpr inline size_t SessionCountMax = LogSessionCountMax + LogGetterSessionCountMax;
|
||||
|
||||
constexpr inline size_t PortCountMax = 2;
|
||||
|
||||
struct ServerManagerOptions {
|
||||
static constexpr size_t PointerBufferSize = 0x400;
|
||||
static constexpr size_t MaxDomains = 31;
|
||||
static constexpr size_t MaxDomainObjects = 61;
|
||||
};
|
||||
|
||||
using ServerManager = sf::hipc::ServerManager<PortCountMax, ServerManagerOptions, SessionCountMax>;
|
||||
|
||||
constinit util::TypedStorage<ServerManager> g_server_manager_storage;
|
||||
constinit ServerManager *g_server_manager = nullptr;
|
||||
|
||||
constinit util::TypedStorage<psc::PmModule> g_pm_module_storage;
|
||||
constinit psc::PmModule *g_pm_module;
|
||||
constinit os::WaitableHolderType g_pm_module_holder;
|
||||
|
||||
constexpr const psc::PmModuleId PmModuleDependencies[] = { psc::PmModuleId_TmaHostIo, psc::PmModuleId_Fs };
|
||||
|
||||
/* Service objects. */
|
||||
constinit sf::UnmanagedServiceObject<lm::ILogService, lm::srv::LogServiceImpl> g_log_service_object;
|
||||
constinit sf::UnmanagedServiceObject<lm::ILogGetter, lm::srv::LogGetter> g_log_getter_service_object;
|
||||
|
||||
constinit std::atomic<bool> g_is_sleeping = false;
|
||||
|
||||
}
|
||||
|
||||
bool IsSleeping() {
|
||||
return g_is_sleeping;
|
||||
}
|
||||
|
||||
void InitializeIpcServer() {
|
||||
/* Check that we're not already initialized. */
|
||||
AMS_ABORT_UNLESS(g_server_manager == nullptr);
|
||||
AMS_ABORT_UNLESS(g_pm_module == nullptr);
|
||||
|
||||
/* Create and initialize the psc module. */
|
||||
g_pm_module = util::ConstructAt(g_pm_module_storage);
|
||||
R_ABORT_UNLESS(g_pm_module->Initialize(psc::PmModuleId_Lm, PmModuleDependencies, util::size(PmModuleDependencies), os::EventClearMode_ManualClear));
|
||||
|
||||
/* Create the psc module waitable holder. */
|
||||
os::InitializeWaitableHolder(std::addressof(g_pm_module_holder), g_pm_module->GetEventPointer()->GetBase());
|
||||
os::SetWaitableHolderUserData(std::addressof(g_pm_module_holder), psc::PmModuleId_Lm);
|
||||
|
||||
/* Create the server manager. */
|
||||
g_server_manager = util::ConstructAt(g_server_manager_storage);
|
||||
|
||||
/* Add the pm module holder. */
|
||||
g_server_manager->AddUserWaitableHolder(std::addressof(g_pm_module_holder));
|
||||
|
||||
/* Create services. */
|
||||
R_ABORT_UNLESS(g_server_manager->RegisterObjectForServer(g_log_service_object.GetShared(), LogServiceName, LogSessionCountMax));
|
||||
R_ABORT_UNLESS(g_server_manager->RegisterObjectForServer(g_log_getter_service_object.GetShared(), LogGetterServiceName, LogGetterSessionCountMax));
|
||||
|
||||
/* Start the server manager. */
|
||||
g_server_manager->ResumeProcessing();
|
||||
}
|
||||
|
||||
void LoopIpcServer() {
|
||||
/* Check that we're initialized. */
|
||||
AMS_ABORT_UNLESS(g_server_manager != nullptr);
|
||||
|
||||
/* Loop forever, servicing the server. */
|
||||
auto prev_state = psc::PmState_Unknown;
|
||||
while (true) {
|
||||
/* Get the next signaled holder. */
|
||||
auto *signaled_holder = g_server_manager->WaitSignaled();
|
||||
if (signaled_holder != std::addressof(g_pm_module_holder)) {
|
||||
/* If ipc, process. */
|
||||
R_ABORT_UNLESS(g_server_manager->Process(signaled_holder));
|
||||
} else {
|
||||
/* If pm module, clear the event. */
|
||||
g_pm_module->GetEventPointer()->Clear();
|
||||
g_server_manager->AddUserWaitableHolder(signaled_holder);
|
||||
|
||||
/* Get the power state. */
|
||||
psc::PmState pm_state;
|
||||
psc::PmFlagSet pm_flags;
|
||||
R_ABORT_UNLESS(g_pm_module->GetRequest(std::addressof(pm_state), std::addressof(pm_flags)));
|
||||
|
||||
/* Handle the power state. */
|
||||
if (prev_state == psc::PmState_EssentialServicesAwake && pm_state == psc::PmState_MinimumAwake) {
|
||||
g_is_sleeping = false;
|
||||
} else if (prev_state == psc::PmState_MinimumAwake && pm_state == psc::PmState_SleepReady) {
|
||||
g_is_sleeping = true;
|
||||
} else if (pm_state == psc::PmState_ShutdownReady) {
|
||||
g_is_sleeping = true;
|
||||
}
|
||||
|
||||
/* Set the previous state. */
|
||||
prev_state = pm_state;
|
||||
|
||||
/* Acknowledge the state transition. */
|
||||
R_ABORT_UNLESS(g_pm_module->Acknowledge(pm_state, ResultSuccess()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void StopIpcServer() {
|
||||
/* Check that we're initialized. */
|
||||
AMS_ABORT_UNLESS(g_server_manager != nullptr);
|
||||
|
||||
/* Stop the server manager. */
|
||||
g_server_manager->RequestStopProcessing();
|
||||
}
|
||||
|
||||
void FinalizeIpcServer() {
|
||||
/* Check that we're initialized. */
|
||||
AMS_ABORT_UNLESS(g_server_manager != nullptr);
|
||||
|
||||
/* Destroy the server manager. */
|
||||
std::destroy_at(g_server_manager);
|
||||
g_server_manager = nullptr;
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user