mirror of
https://github.com/skyline-emu/skyline.git
synced 2025-03-13 12:50:14 +03:00
275 lines
14 KiB
C++
275 lines
14 KiB
C++
// SPDX-License-Identifier: MPL-2.0
|
|
// Copyright © 2020 Skyline Team and Contributors (https://github.com/skyline-emu/)
|
|
|
|
#include <kernel/types/KProcess.h>
|
|
#include <common/trace.h>
|
|
#include "sm/IUserInterface.h"
|
|
#include "settings/ISettingsServer.h"
|
|
#include "settings/ISystemSettingsServer.h"
|
|
#include "apm/IManager.h"
|
|
#include "am/IApplicationProxyService.h"
|
|
#include "am/IAllSystemAppletProxiesService.h"
|
|
#include "audio/IAudioInManager.h"
|
|
#include "audio/IAudioOutManager.h"
|
|
#include "audio/IAudioRendererManager.h"
|
|
#include "bcat/IServiceCreator.h"
|
|
#include "codec/IHardwareOpusDecoderManager.h"
|
|
#include "fatalsrv/IService.h"
|
|
#include "hid/IHidServer.h"
|
|
#include "irs/IIrSensorServer.h"
|
|
#include "irs/iirsensor_core.h"
|
|
#include "timesrv/IStaticService.h"
|
|
#include "glue/IStaticService.h"
|
|
#include "glue/IWriterForSystem.h"
|
|
#include "services/timesrv/core.h"
|
|
#include "fssrv/IFileSystemProxy.h"
|
|
#include "nvdrv/INvDrvServices.h"
|
|
#include "nvdrv/driver.h"
|
|
#include "hosbinder/IHOSBinderDriver.h"
|
|
#include "visrv/IApplicationRootService.h"
|
|
#include "visrv/ISystemRootService.h"
|
|
#include "visrv/IManagerRootService.h"
|
|
#include "pl/IPlatformServiceManager.h"
|
|
#include "pl/shared_font_core.h"
|
|
#include "aocsrv/IAddOnContentManager.h"
|
|
#include "pctl/IParentalControlServiceFactory.h"
|
|
#include "lm/ILogService.h"
|
|
#include "ldn/IUserServiceCreator.h"
|
|
#include "account/IAccountServiceForApplication.h"
|
|
#include "friends/IServiceCreator.h"
|
|
#include "nfp/IUserManager.h"
|
|
#include "nifm/IStaticService.h"
|
|
#include "nim/IShopServiceAccessServerInterface.h"
|
|
#include "socket/bsd/IClient.h"
|
|
#include "socket/nsd/IManager.h"
|
|
#include "socket/sfdnsres/IResolver.h"
|
|
#include "spl/IRandomInterface.h"
|
|
#include "ssl/ISslService.h"
|
|
#include "prepo/IPrepoService.h"
|
|
#include "mmnv/IRequest.h"
|
|
#include "bt/IBluetoothUser.h"
|
|
#include "btm/IBtmUser.h"
|
|
#include "capsrv/IAlbumAccessorService.h"
|
|
#include "capsrv/ICaptureControllerService.h"
|
|
#include "capsrv/IAlbumApplicationService.h"
|
|
#include "ro/IRoInterface.h"
|
|
#include "serviceman.h"
|
|
|
|
#define SERVICE_CASE(class, name, ...) \
|
|
case util::MakeMagic<ServiceName>(name): { \
|
|
std::shared_ptr<BaseService> serviceObject{std::make_shared<class>(state, *this, ##__VA_ARGS__)}; \
|
|
serviceMap[util::MakeMagic<ServiceName>(name)] = serviceObject; \
|
|
return serviceObject; \
|
|
}
|
|
|
|
namespace skyline::service {
|
|
struct GlobalServiceState {
|
|
timesrv::core::TimeServiceObject timesrv;
|
|
pl::SharedFontCore sharedFontCore;
|
|
irs::SharedIirCore sharedIirCore;
|
|
nvdrv::Driver nvdrv;
|
|
|
|
explicit GlobalServiceState(const DeviceState &state) : timesrv(state), sharedFontCore(state), sharedIirCore(state), nvdrv(state) {}
|
|
};
|
|
|
|
ServiceManager::ServiceManager(const DeviceState &state) : state(state), smUserInterface(std::make_shared<sm::IUserInterface>(state, *this)), globalServiceState(std::make_shared<GlobalServiceState>(state)) {}
|
|
|
|
std::shared_ptr<BaseService> ServiceManager::CreateOrGetService(ServiceName name) {
|
|
auto serviceIter{serviceMap.find(name)};
|
|
if (serviceIter != serviceMap.end())
|
|
return (*serviceIter).second;
|
|
|
|
switch (name) {
|
|
SERVICE_CASE(fatalsrv::IService, "fatal:u")
|
|
SERVICE_CASE(settings::ISettingsServer, "set")
|
|
SERVICE_CASE(settings::ISystemSettingsServer, "set:sys")
|
|
SERVICE_CASE(apm::IManager, "apm")
|
|
SERVICE_CASE(am::IApplicationProxyService, "appletOE")
|
|
SERVICE_CASE(am::IAllSystemAppletProxiesService, "appletAE")
|
|
SERVICE_CASE(audio::IAudioInManager, "audin:u")
|
|
SERVICE_CASE(audio::IAudioOutManager, "audout:u")
|
|
SERVICE_CASE(audio::IAudioRendererManager, "audren:u")
|
|
SERVICE_CASE(codec::IHardwareOpusDecoderManager, "hwopus")
|
|
SERVICE_CASE(hid::IHidServer, "hid")
|
|
SERVICE_CASE(irs::IIrSensorServer, "irs", globalServiceState->sharedIirCore)
|
|
SERVICE_CASE(timesrv::IStaticService, "time:s", globalServiceState->timesrv, timesrv::constant::StaticServiceSystemPermissions) // Both of these would be registered after TimeServiceManager::Setup normally but we call that in the GlobalServiceState constructor so can just list them here directly
|
|
SERVICE_CASE(timesrv::IStaticService, "time:su", globalServiceState->timesrv, timesrv::constant::StaticServiceSystemUpdatePermissions)
|
|
SERVICE_CASE(glue::IStaticService, "time:a", globalServiceState->timesrv.managerServer.GetStaticServiceAsAdmin(state, *this), globalServiceState->timesrv, timesrv::constant::StaticServiceAdminPermissions)
|
|
SERVICE_CASE(glue::IStaticService, "time:r", globalServiceState->timesrv.managerServer.GetStaticServiceAsRepair(state, *this), globalServiceState->timesrv, timesrv::constant::StaticServiceRepairPermissions)
|
|
SERVICE_CASE(glue::IStaticService, "time:u", globalServiceState->timesrv.managerServer.GetStaticServiceAsUser(state, *this), globalServiceState->timesrv, timesrv::constant::StaticServiceUserPermissions)
|
|
SERVICE_CASE(glue::IWriterForSystem, "ectx:w")
|
|
SERVICE_CASE(glue::IWriterForSystem, "ectx:aw")
|
|
SERVICE_CASE(fssrv::IFileSystemProxy, "fsp-srv")
|
|
SERVICE_CASE(nvdrv::INvDrvServices, "nvdrv", globalServiceState->nvdrv, nvdrv::ApplicationSessionPermissions)
|
|
SERVICE_CASE(nvdrv::INvDrvServices, "nvdrv:a", globalServiceState->nvdrv, nvdrv::AppletSessionPermissions)
|
|
SERVICE_CASE(hosbinder::IHOSBinderDriver, "dispdrv", globalServiceState->nvdrv.core.nvMap)
|
|
SERVICE_CASE(visrv::IApplicationRootService, "vi:u")
|
|
SERVICE_CASE(visrv::ISystemRootService, "vi:s")
|
|
SERVICE_CASE(visrv::IManagerRootService, "vi:m")
|
|
SERVICE_CASE(pl::IPlatformServiceManager, "pl:u", globalServiceState->sharedFontCore)
|
|
SERVICE_CASE(aocsrv::IAddOnContentManager, "aoc:u")
|
|
SERVICE_CASE(pctl::IParentalControlServiceFactory, "pctl")
|
|
SERVICE_CASE(pctl::IParentalControlServiceFactory, "pctl:a")
|
|
SERVICE_CASE(pctl::IParentalControlServiceFactory, "pctl:s")
|
|
SERVICE_CASE(pctl::IParentalControlServiceFactory, "pctl:r")
|
|
SERVICE_CASE(lm::ILogService, "lm")
|
|
SERVICE_CASE(ldn::IUserServiceCreator, "ldn:u")
|
|
SERVICE_CASE(account::IAccountServiceForApplication, "acc:u0")
|
|
SERVICE_CASE(friends::IServiceCreator, "friend:u")
|
|
SERVICE_CASE(nfp::IUserManager, "nfp:user")
|
|
SERVICE_CASE(nifm::IStaticService, "nifm:u")
|
|
SERVICE_CASE(socket::IClient, "bsd:u")
|
|
SERVICE_CASE(socket::IManager, "nsd:u")
|
|
SERVICE_CASE(socket::IManager, "nsd:a")
|
|
SERVICE_CASE(socket::IResolver, "sfdnsres")
|
|
SERVICE_CASE(spl::IRandomInterface, "csrng")
|
|
SERVICE_CASE(ssl::ISslService, "ssl")
|
|
SERVICE_CASE(prepo::IPrepoService, "prepo:u")
|
|
SERVICE_CASE(mmnv::IRequest, "mm:u")
|
|
SERVICE_CASE(bcat::IServiceCreator, "bcat:u")
|
|
SERVICE_CASE(bt::IBluetoothUser, "bt")
|
|
SERVICE_CASE(btm::IBtmUser, "btm:u")
|
|
SERVICE_CASE(capsrv::IAlbumAccessorService, "caps:a")
|
|
SERVICE_CASE(capsrv::ICaptureControllerService, "caps:c")
|
|
SERVICE_CASE(capsrv::IAlbumApplicationService, "caps:u")
|
|
SERVICE_CASE(nim::IShopServiceAccessServerInterface, "nim:eca")
|
|
SERVICE_CASE(ro::IRoInterface, "ldr:ro")
|
|
default:
|
|
std::string_view nameString(span(reinterpret_cast<char *>(&name), sizeof(name)).as_string(true));
|
|
throw std::out_of_range(fmt::format("CreateService called with an unknown service name: {}", nameString));
|
|
}
|
|
}
|
|
|
|
std::shared_ptr<BaseService> ServiceManager::NewService(ServiceName name, type::KSession &session, ipc::IpcResponse &response) {
|
|
std::scoped_lock serviceGuard{mutex};
|
|
auto serviceObject{CreateOrGetService(name)};
|
|
KHandle handle{};
|
|
if (session.isDomain) {
|
|
session.domains.push_back(serviceObject);
|
|
response.domainObjects.push_back(session.handleIndex);
|
|
handle = session.handleIndex++;
|
|
} else {
|
|
handle = state.process->NewHandle<type::KSession>(serviceObject).handle;
|
|
response.moveHandles.push_back(handle);
|
|
}
|
|
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)
|
|
std::scoped_lock serviceGuard{mutex};
|
|
KHandle handle{};
|
|
|
|
if (session.isDomain) {
|
|
session.domains.push_back(serviceObject);
|
|
response.domainObjects.push_back(session.handleIndex);
|
|
handle = session.handleIndex++;
|
|
} else {
|
|
handle = state.process->NewHandle<type::KSession>(serviceObject).handle;
|
|
response.moveHandles.push_back(handle);
|
|
}
|
|
|
|
Logger::Debug("Service has been registered: \"{}\" (0x{:X})", serviceObject->GetName(), handle);
|
|
}
|
|
|
|
void ServiceManager::CloseSession(KHandle handle) {
|
|
std::scoped_lock serviceGuard{mutex};
|
|
auto session{state.process->GetHandle<type::KSession>(handle)};
|
|
if (session->isOpen) {
|
|
if (session->isDomain) {
|
|
for (const auto &domainService : session->domains)
|
|
std::erase_if(serviceMap, [domainService](const auto &entry) {
|
|
return entry.second == domainService;
|
|
});
|
|
} else {
|
|
std::erase_if(serviceMap, [session](const auto &entry) {
|
|
return entry.second == session->serviceObject;
|
|
});
|
|
}
|
|
session->isOpen = false;
|
|
}
|
|
}
|
|
|
|
void ServiceManager::SyncRequestHandler(KHandle handle) {
|
|
TRACE_EVENT("kernel", "ServiceManager::SyncRequestHandler");
|
|
auto session{state.process->GetHandle<type::KSession>(handle)};
|
|
Logger::Verbose("----IPC Start----");
|
|
Logger::Verbose("Handle is 0x{:X}", handle);
|
|
|
|
if (session->isOpen) {
|
|
ipc::IpcRequest request(session->isDomain, state);
|
|
ipc::IpcResponse response(state);
|
|
|
|
switch (request.header->type) {
|
|
case ipc::CommandType::Request:
|
|
case ipc::CommandType::RequestWithContext:
|
|
if (session->isDomain) {
|
|
try {
|
|
auto service{session->domains.at(request.domain->objectId)};
|
|
if (service == nullptr)
|
|
throw exception("Domain request used an expired handle");
|
|
switch (request.domain->command) {
|
|
case ipc::DomainCommand::SendMessage:
|
|
response.errorCode = service->HandleRequest(*session, request, response);
|
|
break;
|
|
|
|
case ipc::DomainCommand::CloseVHandle:
|
|
std::erase_if(serviceMap, [service](const auto &entry) {
|
|
return entry.second == service;
|
|
});
|
|
session->domains.at(request.domain->objectId).reset();
|
|
break;
|
|
}
|
|
} catch (std::out_of_range &) {
|
|
throw exception("Invalid object ID was used with domain request");
|
|
}
|
|
} else {
|
|
response.errorCode = session->serviceObject->HandleRequest(*session, request, response);
|
|
}
|
|
response.WriteResponse(session->isDomain);
|
|
break;
|
|
|
|
case ipc::CommandType::Control:
|
|
case ipc::CommandType::ControlWithContext:
|
|
Logger::Debug("Control IPC Message: 0x{:X}", request.payload->value);
|
|
switch (static_cast<ipc::ControlCommand>(request.payload->value)) {
|
|
case ipc::ControlCommand::ConvertCurrentObjectToDomain:
|
|
response.Push(session->ConvertDomain());
|
|
break;
|
|
|
|
case ipc::ControlCommand::CloneCurrentObject:
|
|
case ipc::ControlCommand::CloneCurrentObjectEx:
|
|
response.moveHandles.push_back(state.process->InsertItem(session));
|
|
break;
|
|
|
|
case ipc::ControlCommand::QueryPointerBufferSize:
|
|
response.Push<u32>(0x8000);
|
|
break;
|
|
|
|
default:
|
|
throw exception("Unknown Control Command: {}", request.payload->value);
|
|
}
|
|
response.WriteResponse(false);
|
|
break;
|
|
|
|
case ipc::CommandType::Close:
|
|
case ipc::CommandType::TipcCloseSession:
|
|
Logger::Debug("Closing Session");
|
|
CloseSession(handle);
|
|
break;
|
|
default:
|
|
// TIPC command ID is encoded in the request type
|
|
if (request.isTipc) {
|
|
response.errorCode = session->serviceObject->HandleRequest(*session, request, response);
|
|
response.WriteResponse(session->isDomain, true);
|
|
} else {
|
|
throw exception("Unimplemented IPC message type: {}", static_cast<u16>(request.header->type));
|
|
}
|
|
}
|
|
} else {
|
|
Logger::Warn("svcSendSyncRequest called on closed handle: 0x{:X}", handle);
|
|
}
|
|
Logger::Verbose("====IPC End====");
|
|
}
|
|
}
|