199 lines
9.3 KiB
C++
199 lines
9.3 KiB
C++
#include "serviceman.h"
|
|
#include <kernel/types/KProcess.h>
|
|
#include "sm/sm.h"
|
|
#include "set/sys.h"
|
|
#include "apm/apm.h"
|
|
#include "am/appletOE.h"
|
|
#include "fatal/fatal.h"
|
|
#include "hid/hid.h"
|
|
#include "time/timesrv.h"
|
|
#include "fs/fs.h"
|
|
|
|
namespace skyline::kernel::service {
|
|
ServiceManager::ServiceManager(const DeviceState &state) : state(state) {}
|
|
|
|
std::shared_ptr<BaseService> ServiceManager::GetService(const Service serviceType) {
|
|
std::shared_ptr<BaseService> serviceObj;
|
|
switch (serviceType) {
|
|
case Service::sm:
|
|
serviceObj = std::make_shared<sm::sm>(state, *this);
|
|
break;
|
|
case Service::fatal_u:
|
|
serviceObj = std::make_shared<fatal::fatalU>(state, *this);
|
|
break;
|
|
case Service::set_sys:
|
|
serviceObj = std::make_shared<set::sys>(state, *this);
|
|
break;
|
|
case Service::apm:
|
|
serviceObj = std::make_shared<apm::apm>(state, *this);
|
|
break;
|
|
case Service::apm_ISession:
|
|
serviceObj = std::make_shared<apm::ISession>(state, *this);
|
|
break;
|
|
case Service::am_appletOE:
|
|
serviceObj = std::make_shared<am::appletOE>(state, *this);
|
|
break;
|
|
case Service::am_IApplicationProxy:
|
|
serviceObj = std::make_shared<am::IApplicationProxy>(state, *this);
|
|
break;
|
|
case Service::am_ICommonStateGetter:
|
|
serviceObj = std::make_shared<am::ICommonStateGetter>(state, *this);
|
|
break;
|
|
case Service::am_IWindowController:
|
|
serviceObj = std::make_shared<am::IWindowController>(state, *this);
|
|
break;
|
|
case Service::am_IAudioController:
|
|
serviceObj = std::make_shared<am::IAudioController>(state, *this);
|
|
break;
|
|
case Service::am_IDisplayController:
|
|
serviceObj = std::make_shared<am::IDisplayController>(state, *this);
|
|
break;
|
|
case Service::am_ISelfController:
|
|
serviceObj = std::make_shared<am::ISelfController>(state, *this);
|
|
break;
|
|
case Service::am_ILibraryAppletCreator:
|
|
serviceObj = std::make_shared<am::ILibraryAppletCreator>(state, *this);
|
|
break;
|
|
case Service::am_IApplicationFunctions:
|
|
serviceObj = std::make_shared<am::IApplicationFunctions>(state, *this);
|
|
break;
|
|
case Service::am_IDebugFunctions:
|
|
serviceObj = std::make_shared<am::IDebugFunctions>(state, *this);
|
|
break;
|
|
case Service::hid:
|
|
serviceObj = std::make_shared<hid::hid>(state, *this);
|
|
break;
|
|
case Service::hid_IAppletResource:
|
|
serviceObj = std::make_shared<hid::IAppletResource>(state, *this);
|
|
break;
|
|
case Service::time:
|
|
serviceObj = std::make_shared<time::time>(state, *this);
|
|
break;
|
|
case Service::fs_fsp:
|
|
serviceObj = std::make_shared<fs::fsp>(state, *this);
|
|
break;
|
|
default:
|
|
throw exception("GetService called on missing object");
|
|
}
|
|
serviceVec.push_back(serviceObj);
|
|
return serviceObj;
|
|
}
|
|
|
|
handle_t ServiceManager::NewSession(const Service serviceType) {
|
|
return state.thisProcess->NewHandle<type::KSession>(GetService(serviceType)).handle;
|
|
}
|
|
|
|
std::shared_ptr<BaseService> ServiceManager::NewService(const Service serviceType, type::KSession &session, ipc::IpcResponse &response) {
|
|
auto serviceObject = GetService(serviceType);
|
|
handle_t handle{};
|
|
if (response.isDomain) {
|
|
session.domainTable[++session.handleIndex] = serviceObject;
|
|
response.domainObjects.push_back(session.handleIndex);
|
|
handle = session.handleIndex;
|
|
} else {
|
|
handle = state.thisProcess->NewHandle<type::KSession>(serviceObject).handle;
|
|
response.moveHandles.push_back(handle);
|
|
}
|
|
state.logger->Write(Logger::Debug, "Service has been created: \"{}\" (0x{:X})", serviceObject->getName(), handle);
|
|
return serviceObject;
|
|
}
|
|
|
|
void ServiceManager::RegisterService(std::shared_ptr<BaseService> serviceObject, type::KSession &session, ipc::IpcResponse &response) { // NOLINT(performance-unnecessary-value-param)
|
|
serviceVec.push_back(serviceObject);
|
|
handle_t handle{};
|
|
if (response.isDomain) {
|
|
session.domainTable[++session.handleIndex] = serviceObject;
|
|
response.domainObjects.push_back(session.handleIndex);
|
|
handle = session.handleIndex;
|
|
} else {
|
|
handle = state.thisProcess->NewHandle<type::KSession>(serviceObject).handle;
|
|
response.moveHandles.push_back(handle);
|
|
}
|
|
state.logger->Write(Logger::Debug, "Service has been registered: \"{}\" (0x{:X})", serviceObject->getName(), handle);
|
|
}
|
|
|
|
void ServiceManager::CloseSession(const handle_t handle) {
|
|
auto session = state.thisProcess->GetHandle<type::KSession>(handle);
|
|
if (session->serviceStatus == type::KSession::ServiceStatus::Open) {
|
|
if (session->isDomain) {
|
|
for (const auto &[objectId, service] : session->domainTable)
|
|
serviceVec.erase(std::remove(serviceVec.begin(), serviceVec.end(), service), serviceVec.end());
|
|
} else
|
|
serviceVec.erase(std::remove(serviceVec.begin(), serviceVec.end(), session->serviceObject), serviceVec.end());
|
|
session->serviceStatus = type::KSession::ServiceStatus::Closed;
|
|
}
|
|
};
|
|
|
|
void ServiceManager::Loop() {
|
|
for (auto &service : serviceVec)
|
|
if (service->hasLoop)
|
|
service->Loop();
|
|
}
|
|
|
|
void ServiceManager::SyncRequestHandler(const handle_t handle) {
|
|
auto session = state.thisProcess->GetHandle<type::KSession>(handle);
|
|
state.logger->Write(Logger::Debug, "----Start----");
|
|
state.logger->Write(Logger::Debug, "Handle is 0x{:X}", handle);
|
|
|
|
if (session->serviceStatus == type::KSession::ServiceStatus::Open) {
|
|
ipc::IpcRequest request(session->isDomain, state);
|
|
ipc::IpcResponse response(session->isDomain, state);
|
|
|
|
switch (static_cast<ipc::CommandType>(request.header->type)) {
|
|
case ipc::CommandType::Request:
|
|
case ipc::CommandType::RequestWithContext:
|
|
if (session->isDomain) {
|
|
try {
|
|
auto service = session->domainTable.at(request.domain->object_id);
|
|
switch (static_cast<ipc::DomainCommand>(request.domain->command)) {
|
|
case ipc::DomainCommand::SendMessage:
|
|
service->HandleRequest(*session, request, response);
|
|
break;
|
|
case ipc::DomainCommand::CloseVHandle:
|
|
serviceVec.erase(std::remove(serviceVec.begin(), serviceVec.end(), service), serviceVec.end());
|
|
session->domainTable.erase(request.domain->object_id);
|
|
break;
|
|
}
|
|
} catch (std::out_of_range&) {
|
|
throw exception("Invalid object ID was used with domain request");
|
|
}
|
|
} else
|
|
session->serviceObject->HandleRequest(*session, request, response);
|
|
response.WriteTls();
|
|
break;
|
|
|
|
case ipc::CommandType::Control:
|
|
case ipc::CommandType::ControlWithContext:
|
|
state.logger->Write(Logger::Debug, "Control IPC Message: {}", request.payload->value);
|
|
switch (static_cast<ipc::ControlCommand>(request.payload->value)) {
|
|
case ipc::ControlCommand::ConvertCurrentObjectToDomain:
|
|
response.WriteValue(session->ConvertDomain());
|
|
break;
|
|
case ipc::ControlCommand::CloneCurrentObject:
|
|
case ipc::ControlCommand::CloneCurrentObjectEx:
|
|
CloneSession(*session, request, response);
|
|
break;
|
|
default:
|
|
throw exception(fmt::format("Unknown Control Command: {}", request.payload->value));
|
|
}
|
|
response.WriteTls();
|
|
break;
|
|
|
|
case ipc::CommandType::Close:
|
|
state.logger->Write(Logger::Debug, "Closing Session");
|
|
CloseSession(handle);
|
|
break;
|
|
|
|
default:
|
|
throw exception(fmt::format("Unimplemented IPC message type: {}", u16(request.header->type)));
|
|
}
|
|
} else
|
|
state.logger->Write(Logger::Warn, "svcSendSyncRequest called on closed handle: 0x{:X}", handle);
|
|
state.logger->Write(Logger::Debug, "====End====");
|
|
}
|
|
|
|
void ServiceManager::CloneSession(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
|
|
NewService(session.serviceType, session, response);
|
|
}
|
|
}
|