mirror of
https://github.com/Atmosphere-NX/Atmosphere
synced 2024-12-22 20:31:14 +00:00
pgl: Implement ProcessControlTask
This commit is contained in:
parent
cfe0597385
commit
469e3290f6
10 changed files with 311 additions and 16 deletions
|
@ -25,6 +25,8 @@ namespace ams::pm::shell {
|
|||
/* Shell API. */
|
||||
Result LaunchProgram(os::ProcessId *out, const ncm::ProgramLocation &loc, u32 launch_flags);
|
||||
Result TerminateProcess(os::ProcessId process_id);
|
||||
Result GetProcessEventEvent(os::SystemEvent *out);
|
||||
Result GetProcessEventInfo(ProcessEventInfo *out);
|
||||
Result GetApplicationProcessIdForShell(os::ProcessId *out);
|
||||
Result BoostSystemMemoryResourceLimit(u64 size);
|
||||
Result EnableApplicationExtraThread();
|
||||
|
|
|
@ -54,7 +54,7 @@ namespace ams::pm {
|
|||
|
||||
constexpr inline u32 LaunchFlagsMask = (1 << 6) - 1;
|
||||
|
||||
enum class ProcessEvent {
|
||||
enum class ProcessEvent : u32 {
|
||||
None = 0,
|
||||
Exited = 1,
|
||||
Started = 2,
|
||||
|
@ -63,7 +63,7 @@ namespace ams::pm {
|
|||
DebugBreak = 5,
|
||||
};
|
||||
|
||||
enum class ProcessEventDeprecated {
|
||||
enum class ProcessEventDeprecated : u32 {
|
||||
None = 0,
|
||||
Exception = 1,
|
||||
Exited = 2,
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
#include "settings/settings_types.hpp"
|
||||
#include "settings/settings_fwdbg_types.hpp"
|
||||
#include "settings/settings_fwdbg_api.hpp"
|
||||
#include "settings/system/settings_error_report.hpp"
|
||||
#include "settings/system/settings_firmware_version.hpp"
|
||||
#include "settings/system/settings_product_model.hpp"
|
||||
#include "settings/system/settings_region.hpp"
|
||||
|
|
|
@ -0,0 +1,31 @@
|
|||
/*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include <vapours.hpp>
|
||||
#include <stratosphere/settings/settings_types.hpp>
|
||||
|
||||
namespace ams::settings::system {
|
||||
|
||||
enum ErrorReportSharePermission {
|
||||
ErrorReportSharePermission_NotConfirmed = 0,
|
||||
ErrorReportSharePermission_Granted = 1,
|
||||
ErrorReportSharePermission_Denied = 2,
|
||||
};
|
||||
|
||||
ErrorReportSharePermission GetErrorReportSharePermission();
|
||||
|
||||
}
|
|
@ -28,19 +28,19 @@ namespace ams::lr {
|
|||
public:
|
||||
/* Actual commands. */
|
||||
virtual Result ResolveProgramPath(sf::Out<Path> out, ncm::ProgramId id) override {
|
||||
return lrLrResolveProgramPath(std::addressof(this->srv), static_cast<u64>(id), out->str);
|
||||
return lrLrResolveProgramPath(std::addressof(this->srv), id.value, out->str);
|
||||
}
|
||||
|
||||
virtual Result RedirectProgramPath(const Path &path, ncm::ProgramId id) override {
|
||||
return lrLrRedirectProgramPath(std::addressof(this->srv), static_cast<u64>(id), path.str);
|
||||
return lrLrRedirectProgramPath(std::addressof(this->srv), id.value, path.str);
|
||||
}
|
||||
|
||||
virtual Result ResolveApplicationControlPath(sf::Out<Path> out, ncm::ProgramId id) override {
|
||||
return lrLrResolveApplicationControlPath(std::addressof(this->srv), static_cast<u64>(id), out->str);
|
||||
return lrLrResolveApplicationControlPath(std::addressof(this->srv), id.value, out->str);
|
||||
}
|
||||
|
||||
virtual Result ResolveApplicationHtmlDocumentPath(sf::Out<Path> out, ncm::ProgramId id) override {
|
||||
return lrLrResolveApplicationHtmlDocumentPath(std::addressof(this->srv), static_cast<u64>(id), out->str);
|
||||
return lrLrResolveApplicationHtmlDocumentPath(std::addressof(this->srv), id.value, out->str);
|
||||
}
|
||||
|
||||
virtual Result ResolveDataPath(sf::Out<Path> out, ncm::DataId id) override {
|
||||
|
@ -48,31 +48,31 @@ namespace ams::lr {
|
|||
}
|
||||
|
||||
virtual Result RedirectApplicationControlPathDeprecated(const Path &path, ncm::ProgramId id) override {
|
||||
return lrLrRedirectApplicationControlPath(std::addressof(this->srv), static_cast<u64>(id), 0, path.str);
|
||||
return lrLrRedirectApplicationControlPath(std::addressof(this->srv), id.value, 0, path.str);
|
||||
}
|
||||
|
||||
virtual Result RedirectApplicationControlPath(const Path &path, ncm::ProgramId id, ncm::ProgramId owner_id) override {
|
||||
return lrLrRedirectApplicationControlPath(std::addressof(this->srv), static_cast<u64>(id), static_cast<u64>(owner_id), path.str);
|
||||
return lrLrRedirectApplicationControlPath(std::addressof(this->srv), id.value, owner_id.value, path.str);
|
||||
}
|
||||
|
||||
virtual Result RedirectApplicationHtmlDocumentPathDeprecated(const Path &path, ncm::ProgramId id) override {
|
||||
return lrLrRedirectApplicationHtmlDocumentPath(std::addressof(this->srv), static_cast<u64>(id), 0, path.str);
|
||||
return lrLrRedirectApplicationHtmlDocumentPath(std::addressof(this->srv), id.value, 0, path.str);
|
||||
}
|
||||
|
||||
virtual Result RedirectApplicationHtmlDocumentPath(const Path &path, ncm::ProgramId id, ncm::ProgramId owner_id) override {
|
||||
return lrLrRedirectApplicationHtmlDocumentPath(std::addressof(this->srv), static_cast<u64>(id), static_cast<u64>(owner_id), path.str);
|
||||
return lrLrRedirectApplicationHtmlDocumentPath(std::addressof(this->srv), id.value, owner_id.value, path.str);
|
||||
}
|
||||
|
||||
virtual Result ResolveApplicationLegalInformationPath(sf::Out<Path> out, ncm::ProgramId id) override {
|
||||
return lrLrResolveApplicationLegalInformationPath(std::addressof(this->srv), static_cast<u64>(id), out->str);
|
||||
return lrLrResolveApplicationLegalInformationPath(std::addressof(this->srv), id.value, out->str);
|
||||
}
|
||||
|
||||
virtual Result RedirectApplicationLegalInformationPathDeprecated(const Path &path, ncm::ProgramId id) override {
|
||||
return lrLrRedirectApplicationLegalInformationPath(std::addressof(this->srv), static_cast<u64>(id), 0, path.str);
|
||||
return lrLrRedirectApplicationLegalInformationPath(std::addressof(this->srv), id.value, 0, path.str);
|
||||
}
|
||||
|
||||
virtual Result RedirectApplicationLegalInformationPath(const Path &path, ncm::ProgramId id, ncm::ProgramId owner_id) override {
|
||||
return lrLrRedirectApplicationLegalInformationPath(std::addressof(this->srv), static_cast<u64>(id), static_cast<u64>(owner_id), path.str);
|
||||
return lrLrRedirectApplicationLegalInformationPath(std::addressof(this->srv), id.value, owner_id.value, path.str);
|
||||
}
|
||||
|
||||
virtual Result Refresh() override {
|
||||
|
@ -100,8 +100,7 @@ namespace ams::lr {
|
|||
}
|
||||
|
||||
virtual Result EraseProgramRedirection(ncm::ProgramId id) override {
|
||||
/* TODO: libnx bindings */
|
||||
AMS_ABORT();
|
||||
return lrLrEraseProgramRedirection(std::addressof(this->srv), id.value);
|
||||
}
|
||||
|
||||
virtual Result EraseApplicationControlRedirection(ncm::ProgramId id) override {
|
||||
|
|
|
@ -140,8 +140,182 @@ namespace ams::pgl::srv {
|
|||
return pm::shell::LaunchProgram(std::addressof(dummy_process_id), ncm::ProgramLocation::Make(ncm::SystemDebugAppletId::SnapShotDumper, ncm::StorageId::BuiltInSystem), pm::LaunchFlags_None);
|
||||
}
|
||||
|
||||
bool ShouldSnapShotAutoDump() {
|
||||
bool dump;
|
||||
const size_t sz = settings::fwdbg::GetSettingsItemValue(std::addressof(dump), sizeof(dump), "snap_shot_dump", "auto_dump");
|
||||
return sz == sizeof(dump) && dump;
|
||||
}
|
||||
|
||||
bool ShouldSnapShotFullDump() {
|
||||
bool dump;
|
||||
const size_t sz = settings::fwdbg::GetSettingsItemValue(std::addressof(dump), sizeof(dump), "snap_shot_dump", "full_dump");
|
||||
return sz == sizeof(dump) && dump;
|
||||
}
|
||||
|
||||
SnapShotDumpType GetSnapShotDumpType() {
|
||||
if (ShouldSnapShotAutoDump()) {
|
||||
if (ShouldSnapShotFullDump()) {
|
||||
return SnapShotDumpType::Full;
|
||||
} else {
|
||||
return SnapShotDumpType::Auto;
|
||||
}
|
||||
} else {
|
||||
return SnapShotDumpType::None;
|
||||
}
|
||||
}
|
||||
|
||||
void TriggerSnapShotDumper(os::ProcessId process_id) {
|
||||
TriggerSnapShotDumper(process_id, GetSnapShotDumpType(), nullptr);
|
||||
}
|
||||
|
||||
s32 GetCrashReportDetailedArgument(u32 data_flags) {
|
||||
if (((data_flags & ProcessDataFlag_DetailedCrashReportAllowed) != 0) && ((data_flags & ProcessDataFlag_DetailedCrashReportEnabled) != 0)) {
|
||||
return 1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
s32 GetCrashReportScreenShotArgument(u32 data_flags) {
|
||||
if (settings::system::GetErrorReportSharePermission() == settings::system::ErrorReportSharePermission_Granted) {
|
||||
return ((data_flags & ProcessDataFlag_EnableCrashReportScreenShot) != 0) ? 1 : 0;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
void TriggerCrashReport(os::ProcessId process_id) {
|
||||
static os::ProcessId s_crashed_process_id = os::InvalidProcessId;
|
||||
static os::ProcessId s_creport_process_id = os::InvalidProcessId;
|
||||
|
||||
/* If the program that crashed is creport, we should just terminate both processes and return. */
|
||||
if (process_id == s_creport_process_id) {
|
||||
TerminateProcess(s_crashed_process_id);
|
||||
TerminateProcess(s_creport_process_id);
|
||||
s_crashed_process_id = os::InvalidProcessId;
|
||||
s_creport_process_id = os::InvalidProcessId;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Get the data flags for the process. */
|
||||
u32 data_flags;
|
||||
{
|
||||
std::scoped_lock lk(g_process_data_mutex);
|
||||
if (auto *data = FindProcessData(process_id); data != nullptr) {
|
||||
data_flags = data->flags;
|
||||
} else {
|
||||
data_flags = ProcessDataFlag_None;
|
||||
}
|
||||
}
|
||||
|
||||
/* Generate arguments. */
|
||||
char arguments[0x40];
|
||||
const size_t len = std::snprintf(arguments, sizeof(arguments), "%ld %d %d", static_cast<s64>(static_cast<u64>(process_id)), GetCrashReportDetailedArgument(data_flags), GetCrashReportScreenShotArgument(data_flags));
|
||||
if (R_FAILED(ldr::SetProgramArgument(ncm::SystemProgramId::Creport, arguments, len + 1))) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Launch creport. */
|
||||
os::ProcessId creport_process_id;
|
||||
if (R_FAILED(pm::shell::LaunchProgram(std::addressof(creport_process_id), ncm::ProgramLocation::Make(ncm::SystemProgramId::Creport, ncm::StorageId::BuiltInSystem), pm::LaunchFlags_None))) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Set the globals. */
|
||||
s_crashed_process_id = process_id;
|
||||
s_creport_process_id = creport_process_id;
|
||||
}
|
||||
|
||||
void HandleException(os::ProcessId process_id) {
|
||||
if (g_enable_jit_debug) {
|
||||
/* If jit debug is enabled, we want to try to launch snap shot dumper. */
|
||||
ProcessData *data = nullptr;
|
||||
{
|
||||
std::scoped_lock lk(g_process_data_mutex);
|
||||
data = FindProcessData(process_id);
|
||||
}
|
||||
|
||||
/* If we're tracking the process, we can launch dumper. Otherwise we should just terminate. */
|
||||
if (data != nullptr) {
|
||||
TriggerSnapShotDumper(process_id);
|
||||
} else {
|
||||
TerminateProcess(process_id);
|
||||
}
|
||||
} else {
|
||||
/* Otherwise, we want to launch creport. */
|
||||
TriggerCrashReport(process_id);
|
||||
}
|
||||
}
|
||||
|
||||
void HandleExit(os::ProcessId process_id) {
|
||||
std::scoped_lock lk(g_process_data_mutex);
|
||||
if (auto *data = FindProcessData(process_id); data != nullptr) {
|
||||
data->process_id = os::InvalidProcessId;
|
||||
}
|
||||
}
|
||||
|
||||
void OnProcessEvent(const pm::ProcessEventInfo &event_info) {
|
||||
/* Determine if we're tracking the process. */
|
||||
ProcessData *data = nullptr;
|
||||
{
|
||||
std::scoped_lock lk(g_process_data_mutex);
|
||||
data = FindProcessData(event_info.process_id);
|
||||
}
|
||||
|
||||
/* If we are, we're going to want to notify our listeners. */
|
||||
if (data != nullptr) {
|
||||
/* If we closed the process, note that. */
|
||||
if (static_cast<pm::ProcessEvent>(event_info.event) == pm::ProcessEvent::Exited) {
|
||||
HandleExit(event_info.process_id);
|
||||
}
|
||||
|
||||
/* Notify all observers. */
|
||||
std::scoped_lock lk(g_observer_list_mutex);
|
||||
for (auto &observer : g_observer_list) {
|
||||
observer.Notify(event_info);
|
||||
}
|
||||
}
|
||||
|
||||
/* If the process crashed, handle that. */
|
||||
if (static_cast<pm::ProcessEvent>(event_info.event) == pm::ProcessEvent::Exception) {
|
||||
HandleException(event_info.process_id);
|
||||
}
|
||||
}
|
||||
|
||||
void ProcessControlTask(void *) {
|
||||
/* TODO */
|
||||
/* Get the process event event from pm. */
|
||||
os::SystemEvent process_event;
|
||||
R_ABORT_UNLESS(pm::shell::GetProcessEventEvent(std::addressof(process_event)));
|
||||
|
||||
while (true) {
|
||||
/* Wait for an event to come in, and clear our signal. */
|
||||
process_event.Wait();
|
||||
process_event.Signal();
|
||||
|
||||
bool continue_getting_event = true;
|
||||
while (continue_getting_event) {
|
||||
/* Try to get an event info. */
|
||||
pm::ProcessEventInfo event_info;
|
||||
if (R_FAILED(pm::shell::GetProcessEventInfo(std::addressof(event_info)))) {
|
||||
break;
|
||||
}
|
||||
|
||||
/* Process the event. */
|
||||
switch (static_cast<pm::ProcessEvent>(event_info.event)) {
|
||||
case pm::ProcessEvent::None:
|
||||
continue_getting_event = false;
|
||||
break;
|
||||
case pm::ProcessEvent::Exited:
|
||||
case pm::ProcessEvent::Started:
|
||||
case pm::ProcessEvent::Exception:
|
||||
case pm::ProcessEvent::DebugRunning:
|
||||
case pm::ProcessEvent::DebugBreak:
|
||||
OnProcessEvent(event_info);
|
||||
break;
|
||||
AMS_UNREACHABLE_DEFAULT_CASE();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -28,6 +28,18 @@ namespace ams::pm::shell {
|
|||
return ::pmshellTerminateProcess(static_cast<u64>(process_id));
|
||||
}
|
||||
|
||||
Result GetProcessEventEvent(os::SystemEvent *out) {
|
||||
::Event evt;
|
||||
R_TRY(::pmshellGetProcessEventHandle(std::addressof(evt)));
|
||||
out->Attach(evt.revent, true, svc::InvalidHandle, false, os::EventClearMode_ManualClear);
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
Result GetProcessEventInfo(ProcessEventInfo *out) {
|
||||
static_assert(sizeof(*out) == sizeof(::PmProcessEventInfo));
|
||||
return ::pmshellGetProcessEventInfo(reinterpret_cast<::PmProcessEventInfo *>(out));
|
||||
}
|
||||
|
||||
Result GetApplicationProcessIdForShell(os::ProcessId *out) {
|
||||
static_assert(sizeof(*out) == sizeof(u64));
|
||||
return ::pmshellGetApplicationProcessIdForShell(reinterpret_cast<u64 *>(out));
|
||||
|
|
|
@ -0,0 +1,26 @@
|
|||
/*
|
||||
* 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 "settings_error_report_impl.hpp"
|
||||
|
||||
namespace ams::settings::impl {
|
||||
|
||||
Result GetErrorReportSharePermission(s32 *out) {
|
||||
static_assert(sizeof(*out) == sizeof(::SetSysErrorReportSharePermission));
|
||||
return ::setsysGetErrorReportSharePermission(reinterpret_cast<::SetSysErrorReportSharePermission *>(out));
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
/*
|
||||
* 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/>.
|
||||
*/
|
||||
#pragma once
|
||||
#include <stratosphere.hpp>
|
||||
|
||||
namespace ams::settings::impl {
|
||||
|
||||
Result GetErrorReportSharePermission(s32 *out);
|
||||
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
/*
|
||||
* 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 "impl/settings_error_report_impl.hpp"
|
||||
|
||||
namespace ams::settings::system {
|
||||
|
||||
ErrorReportSharePermission GetErrorReportSharePermission() {
|
||||
s32 perm = 0;
|
||||
R_ABORT_UNLESS(settings::impl::GetErrorReportSharePermission(std::addressof(perm)));
|
||||
return static_cast<ErrorReportSharePermission>(model);
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in a new issue