erpt: Implement 12.0.0 AppletTotalActiveTime tracking

This commit is contained in:
Michael Scire 2021-04-29 21:48:47 -07:00
parent 0dc308d92a
commit ef0c15b764
7 changed files with 291 additions and 206 deletions

View file

@ -126,4 +126,13 @@ namespace ams::erpt::srv {
return ResultSuccess(); return ResultSuccess();
} }
Result Context::ClearContext(CategoryId cat) {
/* Make an empty record for the category. */
auto record = std::make_unique<ContextRecord>(cat);
R_UNLESS(record != nullptr, erpt::ResultOutOfMemory());
/* Submit the context record. */
return SubmitContextRecord(std::move(record));
}
} }

View file

@ -40,6 +40,7 @@ namespace ams::erpt::srv {
static Result SubmitContext(const ContextEntry *entry, const u8 *data, u32 data_size); static Result SubmitContext(const ContextEntry *entry, const u8 *data, u32 data_size);
static Result SubmitContextRecord(std::unique_ptr<ContextRecord> record); static Result SubmitContextRecord(std::unique_ptr<ContextRecord> record);
static Result WriteContextsToReport(Report *report); static Result WriteContextsToReport(Report *report);
static Result ClearContext(CategoryId cat);
}; };
} }

View file

@ -47,8 +47,7 @@ namespace ams::erpt::srv {
R_UNLESS(ctx_size == sizeof(ContextEntry), erpt::ResultInvalidArgument()); R_UNLESS(ctx_size == sizeof(ContextEntry), erpt::ResultInvalidArgument());
R_UNLESS(meta_size == 0 || meta_size == sizeof(ReportMetaData), erpt::ResultInvalidArgument()); R_UNLESS(meta_size == 0 || meta_size == sizeof(ReportMetaData), erpt::ResultInvalidArgument());
Reporter reporter(report_type, ctx, data, data_size, meta_size != 0 ? meta : nullptr, nullptr, 0, result); R_TRY(Reporter::CreateReport(report_type, result, ctx, data, data_size, meta_size != 0 ? meta : nullptr, nullptr, 0));
R_TRY(reporter.CreateReport());
ManagerImpl::NotifyAll(); ManagerImpl::NotifyAll();
@ -70,12 +69,12 @@ namespace ams::erpt::srv {
} }
Result ContextImpl::UpdatePowerOnTime() { Result ContextImpl::UpdatePowerOnTime() {
Reporter::UpdatePowerOnTime(); /* NOTE: Prior to 12.0.0, this set the power on time, but now erpt does it during initialization. */
return ResultSuccess(); return ResultSuccess();
} }
Result ContextImpl::UpdateAwakeTime() { Result ContextImpl::UpdateAwakeTime() {
Reporter::UpdateAwakeTime(); /* NOTE: Prior to 12.0.0, this set the power on time, but now erpt does it during initialization. */
return ResultSuccess(); return ResultSuccess();
} }
@ -148,8 +147,7 @@ namespace ams::erpt::srv {
R_UNLESS(ctx_size == sizeof(ContextEntry), erpt::ResultInvalidArgument()); R_UNLESS(ctx_size == sizeof(ContextEntry), erpt::ResultInvalidArgument());
R_UNLESS(num_attachments <= AttachmentsPerReportMax, erpt::ResultInvalidArgument()); R_UNLESS(num_attachments <= AttachmentsPerReportMax, erpt::ResultInvalidArgument());
Reporter reporter(report_type, ctx, data, data_size, nullptr, attachments, num_attachments, result); R_TRY(Reporter::CreateReport(report_type, result, ctx, data, data_size, nullptr, attachments, num_attachments));
R_TRY(reporter.CreateReport());
ManagerImpl::NotifyAll(); ManagerImpl::NotifyAll();
@ -161,18 +159,15 @@ namespace ams::erpt::srv {
} }
Result ContextImpl::RegisterRunningApplet(ncm::ProgramId program_id) { Result ContextImpl::RegisterRunningApplet(ncm::ProgramId program_id) {
/* TODO: For greater accuracy, we should support the active applet time list feature added in 12.0.0. */ return Reporter::RegisterRunningApplet(program_id);
return ResultSuccess();
} }
Result ContextImpl::UnregisterRunningApplet(ncm::ProgramId program_id) { Result ContextImpl::UnregisterRunningApplet(ncm::ProgramId program_id) {
/* TODO: For greater accuracy, we should support the active applet time list feature added in 12.0.0. */ return Reporter::UnregisterRunningApplet(program_id);
return ResultSuccess();
} }
Result ContextImpl::UpdateAppletSuspendedDuration(ncm::ProgramId program_id, TimeSpanType duration) { Result ContextImpl::UpdateAppletSuspendedDuration(ncm::ProgramId program_id, TimeSpanType duration) {
/* TODO: For greater accuracy, we should support the active applet time list feature added in 12.0.0. */ return Reporter::UpdateAppletSuspendedDuration(program_id, duration);
return ResultSuccess();
} }
Result ContextImpl::InvalidateForcedShutdownDetection() { Result ContextImpl::InvalidateForcedShutdownDetection() {

View file

@ -38,6 +38,10 @@ namespace ams::erpt::srv {
explicit ContextRecord(CategoryId category, u32 array_buf_size = ArrayBufferSizeDefault); explicit ContextRecord(CategoryId category, u32 array_buf_size = ArrayBufferSizeDefault);
~ContextRecord(); ~ContextRecord();
const ContextEntry *GetContextEntryPtr() const {
return std::addressof(this->ctx);
}
Result Initialize(const ContextEntry *ctx_ptr, const u8 *data, u32 data_size); Result Initialize(const ContextEntry *ctx_ptr, const u8 *data, u32 data_size);
Result Add(FieldId field_id, bool value_bool); Result Add(FieldId field_id, bool value_bool);

View file

@ -89,10 +89,8 @@ namespace ams::erpt::srv {
Journal::Restore(); Journal::Restore();
if (hos::GetVersion() >= hos::Version_12_0_0) {
Reporter::UpdatePowerOnTime(); Reporter::UpdatePowerOnTime();
Reporter::UpdateAwakeTime(); Reporter::UpdateAwakeTime();
}
return ResultSuccess(); return ResultSuccess();
} }

View file

@ -225,31 +225,11 @@ namespace ams::erpt::srv {
} }
} }
} Result ValidateCreateReportContext(const ContextEntry *ctx) {
R_UNLESS(ctx->category == CategoryId_ErrorInfo, erpt::ResultRequiredContextMissing());
R_UNLESS(ctx->field_count <= FieldsPerContext, erpt::ResultInvalidArgument());
Reporter::Reporter(ReportType type, const ContextEntry *ctx, const u8 *data, u32 data_size, const ReportMetaData *meta, const AttachmentId *attachments, u32 num_attachments, Result ctx_r) const bool found_error_code = util::range::any_of(MakeSpan(ctx->fields, ctx->field_count), [] (const FieldEntry &entry) {
: type(type), ctx(ctx), data(data), data_size(data_size), meta(meta), attachments(attachments), num_attachments(num_attachments), occurrence_tick(), ctx_result(ctx_r)
{
/* ... */
}
Result Reporter::CreateReport() {
R_TRY(this->ValidateReportContext());
R_TRY(this->CollectUniqueReportFields());
R_TRY(this->SubmitReportDefaults());
R_TRY(this->SubmitReportContexts());
R_TRY(this->LinkAttachments());
R_TRY(this->CreateReportFile());
this->SaveSyslogReportIfRequired();
return ResultSuccess();
}
Result Reporter::ValidateReportContext() {
R_UNLESS(this->ctx->category == CategoryId_ErrorInfo, erpt::ResultRequiredContextMissing());
R_UNLESS(this->ctx->field_count <= FieldsPerContext, erpt::ResultInvalidArgument());
const bool found_error_code = util::range::any_of(MakeSpan(this->ctx->fields, this->ctx->field_count), [] (const FieldEntry &entry) {
return entry.id == FieldId_ErrorCode; return entry.id == FieldId_ErrorCode;
}); });
R_UNLESS(found_error_code, erpt::ResultRequiredFieldMissing()); R_UNLESS(found_error_code, erpt::ResultRequiredFieldMissing());
@ -257,33 +237,18 @@ namespace ams::erpt::srv {
return ResultSuccess(); return ResultSuccess();
} }
Result Reporter::CollectUniqueReportFields() { Result SubmitReportDefaults(const ContextEntry *ctx) {
this->occurrence_tick = os::GetSystemTick(); AMS_ASSERT(ctx->category == CategoryId_ErrorInfo);
if (hos::GetVersion() >= hos::Version_5_0_0) {
this->steady_clock_internal_offset_seconds = time::GetStandardSteadyClockInternalOffset().GetSeconds();
} else {
this->steady_clock_internal_offset_seconds = 0;
}
this->report_id.uuid = util::GenerateUuid();
this->report_id.uuid.ToString(this->identifier_str, sizeof(this->identifier_str));
if (R_FAILED(time::StandardNetworkSystemClock::GetCurrentTime(std::addressof(this->timestamp_network)))) {
this->timestamp_network = {0};
}
R_ABORT_UNLESS(time::GetStandardSteadyClockCurrentTimePoint(std::addressof(this->steady_clock_current_timepoint)));
R_TRY(time::StandardUserSystemClock::GetCurrentTime(std::addressof(this->timestamp_user)));
return ResultSuccess();
}
Result Reporter::SubmitReportDefaults() {
auto record = std::make_unique<ContextRecord>(CategoryId_ErrorInfoDefaults); auto record = std::make_unique<ContextRecord>(CategoryId_ErrorInfoDefaults);
R_UNLESS(record != nullptr, erpt::ResultOutOfMemory()); R_UNLESS(record != nullptr, erpt::ResultOutOfMemory());
bool found_abort_flag = false, found_syslog_flag = false; bool found_abort_flag = false, found_syslog_flag = false;
for (u32 i = 0; i < this->ctx->field_count; i++) { for (u32 i = 0; i < ctx->field_count; i++) {
if (this->ctx->fields[i].id == FieldId_AbortFlag) { if (ctx->fields[i].id == FieldId_AbortFlag) {
found_abort_flag = true; found_abort_flag = true;
} }
if (this->ctx->fields[i].id == FieldId_HasSyslogFlag) { if (ctx->fields[i].id == FieldId_HasSyslogFlag) {
found_syslog_flag = true; found_syslog_flag = true;
} }
if (found_abort_flag && found_syslog_flag) { if (found_abort_flag && found_syslog_flag) {
@ -304,65 +269,77 @@ namespace ams::erpt::srv {
return ResultSuccess(); return ResultSuccess();
} }
Result Reporter::SubmitReportContexts() { void SaveSyslogReportIfRequired(const ContextEntry *ctx, const ReportId &report_id) {
auto record = std::make_unique<ContextRecord>(CategoryId_ErrorInfoAuto); bool needs_save_syslog = true;
R_UNLESS(record != nullptr, erpt::ResultOutOfMemory()); for (u32 i = 0; i < ctx->field_count; i++) {
static_assert(FieldToTypeMap[FieldId_HasSyslogFlag] == FieldType_Bool);
/* Handle error context. */ if (ctx->fields[i].id == FieldId_HasSyslogFlag && !ctx->fields[i].value_bool) {
if (R_FAILED(this->ctx_result)) { needs_save_syslog = false;
SubmitErrorContext(record.get(), this->ctx_result); break;
}
record->Add(FieldId_OsVersion, s_os_version, util::Strnlen(s_os_version, sizeof(s_os_version)));
record->Add(FieldId_PrivateOsVersion, s_private_os_version, util::Strnlen(s_private_os_version, sizeof(s_private_os_version)));
record->Add(FieldId_SerialNumber, s_serial_number, util::Strnlen(s_serial_number, sizeof(s_serial_number)));
record->Add(FieldId_ReportIdentifier, this->identifier_str, sizeof(this->identifier_str));
record->Add(FieldId_OccurrenceTimestamp, this->timestamp_user.value);
record->Add(FieldId_OccurrenceTimestampNet, this->timestamp_network.value);
record->Add(FieldId_ReportVisibilityFlag, this->type == ReportType_Visible);
record->Add(FieldId_OccurrenceTick, this->occurrence_tick.GetInt64Value());
record->Add(FieldId_SteadyClockInternalOffset, this->steady_clock_internal_offset_seconds);
record->Add(FieldId_SteadyClockCurrentTimePointValue, this->steady_clock_current_timepoint.value);
if (s_initial_launch_settings_completion_time) {
s64 elapsed_seconds;
if (R_SUCCEEDED(time::GetElapsedSecondsBetween(std::addressof(elapsed_seconds), *s_initial_launch_settings_completion_time, this->steady_clock_current_timepoint))) {
record->Add(FieldId_ElapsedTimeSinceInitialLaunch, elapsed_seconds);
} }
} }
if (s_power_on_time) { if (needs_save_syslog) {
record->Add(FieldId_ElapsedTimeSincePowerOn, (this->occurrence_tick - *s_power_on_time).ToTimeSpan().GetSeconds()); /* Here nintendo sends a report to srepo:u (vtable offset 0xE8) with data report_id. */
/* We will not send report ids to srepo:u. */
}
} }
if (s_awake_time) { void SubmitAppletActiveDurationForCrashReport(const ContextEntry *error_info_ctx, const void *data, u32 data_size, ContextRecord *error_info_auto_record) {
record->Add(FieldId_ElapsedTimeSinceLastAwake, (this->occurrence_tick - *s_awake_time).ToTimeSpan().GetSeconds()); /* Check pre-conditions. */
AMS_ASSERT(error_info_ctx != nullptr);
AMS_ASSERT(error_info_ctx->category == CategoryId_ErrorInfo);
AMS_ASSERT(data != nullptr);
AMS_ASSERT(error_info_auto_record != nullptr);
/* Find the program id entry. */
const auto fields_span = MakeSpan(error_info_ctx->fields, error_info_ctx->field_count);
const auto program_id_entry = util::range::find_if(fields_span, [](const FieldEntry &entry) { return entry.id == FieldId_ProgramId; });
if (program_id_entry == fields_span.end()) {
return;
} }
if (s_application_launch_time) { /* Check that the report has abort flag set. */
record->Add(FieldId_ApplicationAliveTime, (this->occurrence_tick - *s_application_launch_time).ToTimeSpan().GetSeconds()); AMS_ASSERT(util::range::any_of(fields_span, [](const FieldEntry &entry) { return entry.id == FieldId_AbortFlag && entry.value_bool; }));
/* Check that the program id's value is a string. */
AMS_ASSERT(program_id_entry->type == FieldType_String);
/* Check that the program id's length is valid/in bounds. */
const auto program_id_ofs = program_id_entry->value_array.start_idx;
const auto program_id_len = program_id_entry->value_array.size;
AMS_ASSERT(16 <= program_id_len && program_id_len <= 17);
AMS_ASSERT(program_id_ofs + program_id_len <= data_size);
/* Get the program id string. */
char program_id_str[17];
std::memcpy(program_id_str, static_cast<const u8 *>(data) + program_id_ofs, std::min<size_t>(program_id_len, sizeof(program_id_str)));
program_id_str[sizeof(program_id_str) - 1] = '\x00';
/* Convert the string to an integer. */
char *end_ptr = nullptr;
const ncm::ProgramId program_id = { std::strtoull(program_id_str, std::addressof(end_ptr), 16) };
AMS_ASSERT(*end_ptr == '\x00');
/* Get the active duration. */
const auto active_duration = g_applet_active_time_info_list.GetActiveDuration(program_id);
if (!active_duration.has_value()) {
return;
} }
/* TODO: Add FieldId_AppletTotalActiveTime. */ /* Add the active applet time. */
const auto result = error_info_auto_record->Add(FieldId_AppletTotalActiveTime, (*active_duration).GetSeconds());
R_TRY(Context::SubmitContextRecord(std::move(record))); R_ASSERT(result);
R_TRY(Context::SubmitContext(this->ctx, this->data, this->data_size));
/* Submit context for resource limits. */
SubmitResourceLimitContexts();
return ResultSuccess();
} }
Result Reporter::LinkAttachments() { Result LinkAttachments(const ReportId &report_id, const AttachmentId *attachments, u32 num_attachments) {
for (u32 i = 0; i < this->num_attachments; i++) { for (u32 i = 0; i < num_attachments; i++) {
R_TRY(JournalForAttachments::SetOwner(this->attachments[i], this->report_id)); R_TRY(JournalForAttachments::SetOwner(attachments[i], report_id));
} }
return ResultSuccess(); return ResultSuccess();
} }
Result Reporter::CreateReportFile() { Result CreateReportFile(const ReportId &report_id, ReportType type, const ReportMetaData *meta, u32 num_attachments, const time::PosixTime &timestamp_user, const time::PosixTime &timestamp_network, bool redirect_new_reports) {
/* Define journal record deleter. */ /* Define journal record deleter. */
struct JournalRecordDeleter { struct JournalRecordDeleter {
void operator()(JournalRecord<ReportInfo> *record) { void operator()(JournalRecord<ReportInfo> *record) {
@ -379,32 +356,32 @@ namespace ams::erpt::srv {
R_UNLESS(record != nullptr, erpt::ResultOutOfMemory()); R_UNLESS(record != nullptr, erpt::ResultOutOfMemory());
record->AddReference(); record->AddReference();
record->info.type = this->type; record->info.type = type;
record->info.id = this->report_id; record->info.id = report_id;
record->info.flags = erpt::srv::MakeNoReportFlags(); record->info.flags = erpt::srv::MakeNoReportFlags();
record->info.timestamp_user = this->timestamp_user; record->info.timestamp_user = timestamp_user;
record->info.timestamp_network = this->timestamp_network; record->info.timestamp_network = timestamp_network;
if (this->meta != nullptr) { if (meta != nullptr) {
record->info.meta_data = *this->meta; record->info.meta_data = *meta;
} }
if (this->num_attachments > 0) { if (num_attachments > 0) {
record->info.flags.Set<ReportFlag::HasAttachment>(); record->info.flags.Set<ReportFlag::HasAttachment>();
} }
auto report = std::make_unique<Report>(record.get(), s_redirect_new_reports); auto report = std::make_unique<Report>(record.get(), redirect_new_reports);
R_UNLESS(report != nullptr, erpt::ResultOutOfMemory()); R_UNLESS(report != nullptr, erpt::ResultOutOfMemory());
auto report_guard = SCOPE_GUARD { report->Delete(); }; auto report_guard = SCOPE_GUARD { report->Delete(); };
R_TRY(Context::WriteContextsToReport(report.get())); R_TRY(Context::WriteContextsToReport(report.get()));
R_TRY(report->GetSize(std::addressof(record->info.report_size))); R_TRY(report->GetSize(std::addressof(record->info.report_size)));
if (!s_redirect_new_reports) { if (!redirect_new_reports) {
/* If we're not redirecting new reports, then we want to store the report in the journal. */ /* If we're not redirecting new reports, then we want to store the report in the journal. */
R_TRY(Journal::Store(record.get())); R_TRY(Journal::Store(record.get()));
} else { } else {
/* If we are redirecting new reports, we don't want to store the report in the journal. */ /* If we are redirecting new reports, we don't want to store the report in the journal. */
/* We should take this opportunity to delete any attachments associated with the report. */ /* We should take this opportunity to delete any attachments associated with the report. */
R_ABORT_UNLESS(JournalForAttachments::DeleteAttachments(this->report_id)); R_ABORT_UNLESS(JournalForAttachments::DeleteAttachments(report_id));
} }
R_TRY(Journal::Commit()); R_TRY(Journal::Commit());
@ -413,19 +390,139 @@ namespace ams::erpt::srv {
return ResultSuccess(); return ResultSuccess();
} }
void Reporter::SaveSyslogReportIfRequired() {
bool needs_save_syslog = true;
for (u32 i = 0; i < this->ctx->field_count; i++) {
static_assert(FieldToTypeMap[FieldId_HasSyslogFlag] == FieldType_Bool);
if (this->ctx->fields[i].id == FieldId_HasSyslogFlag && (this->ctx->fields[i].value_bool == false)) {
needs_save_syslog = false;
break;
} }
Result Reporter::RegisterRunningApplet(ncm::ProgramId program_id) {
g_applet_active_time_info_list.Register(program_id);
return ResultSuccess();
} }
if (needs_save_syslog) {
/* Here nintendo sends a report to srepo:u (vtable offset 0xE8) with data this->report_id. */ Result Reporter::UnregisterRunningApplet(ncm::ProgramId program_id) {
/* We will not send report ids to srepo:u. */ g_applet_active_time_info_list.Unregister(program_id);
return ResultSuccess();
}
Result Reporter::UpdateAppletSuspendedDuration(ncm::ProgramId program_id, TimeSpan duration) {
g_applet_active_time_info_list.UpdateSuspendedDuration(program_id, duration);
return ResultSuccess();
}
Result Reporter::CreateReport(ReportType type, Result ctx_result, const ContextEntry *ctx, const u8 *data, u32 data_size, const ReportMetaData *meta, const AttachmentId *attachments, u32 num_attachments) {
/* Create a context record for the report. */
auto record = std::make_unique<ContextRecord>(CategoryId_ErrorInfoAuto);
R_UNLESS(record != nullptr, erpt::ResultOutOfMemory());
/* Initialize the record. */
R_TRY(record->Initialize(ctx, data, data_size));
/* Create the report. */
return CreateReport(type, ctx_result, std::move(record), meta, attachments, num_attachments);
}
Result Reporter::CreateReport(ReportType type, Result ctx_result, std::unique_ptr<ContextRecord> record, const ReportMetaData *meta, const AttachmentId *attachments, u32 num_attachments) {
/* Clear the automatic categories, when we're done with our report. */
ON_SCOPE_EXIT {
Context::ClearContext(CategoryId_ErrorInfo);
Context::ClearContext(CategoryId_ErrorInfoAuto);
Context::ClearContext(CategoryId_ErrorInfoDefaults);
};
/* Get the context entry pointer. */
const ContextEntry *ctx = record->GetContextEntryPtr();
/* Validate the context. */
R_TRY(ValidateCreateReportContext(ctx));
/* Submit report defaults. */
R_TRY(SubmitReportDefaults(ctx));
/* Generate report id. */
const ReportId report_id = { .uuid = util::GenerateUuid() };
/* Get posix timestamps. */
time::PosixTime timestamp_user;
time::PosixTime timestamp_network;
R_TRY(time::StandardUserSystemClock::GetCurrentTime(std::addressof(timestamp_user)));
if (R_FAILED(time::StandardNetworkSystemClock::GetCurrentTime(std::addressof(timestamp_network)))) {
timestamp_network = {};
}
/* Save syslog report, if required. */
SaveSyslogReportIfRequired(ctx, report_id);
/* Submit report contexts. */
R_TRY(SubmitReportContexts(report_id, type, ctx_result, std::move(record), timestamp_user, timestamp_network));
/* Link attachments to the report. */
R_TRY(LinkAttachments(report_id, attachments, num_attachments));
/* Create the report file. */
R_TRY(CreateReportFile(report_id, type, meta, num_attachments, timestamp_user, timestamp_network, s_redirect_new_reports));
return ResultSuccess();
}
Result Reporter::SubmitReportContexts(const ReportId &report_id, ReportType type, Result ctx_result, std::unique_ptr<ContextRecord> record, const time::PosixTime &timestamp_user, const time::PosixTime &timestamp_network) {
/* Create automatic record. */
auto auto_record = std::make_unique<ContextRecord>(CategoryId_ErrorInfoAuto, 0x300);
R_UNLESS(auto_record != nullptr, erpt::ResultOutOfMemory());
/* Handle error context. */
if (R_FAILED(ctx_result)) {
SubmitErrorContext(auto_record.get(), ctx_result);
}
/* Collect unique report fields. */
char identifier_str[0x40];
report_id.uuid.ToString(identifier_str, sizeof(identifier_str));
const auto occurrence_tick = os::GetSystemTick();
const s64 steady_clock_internal_offset_seconds = (hos::GetVersion() >= hos::Version_5_0_0) ? time::GetStandardSteadyClockInternalOffset().GetSeconds() : 0;
time::SteadyClockTimePoint steady_clock_current_timepoint;
R_ABORT_UNLESS(time::GetStandardSteadyClockCurrentTimePoint(std::addressof(steady_clock_current_timepoint)));
/* Add automatic fields. */
auto_record->Add(FieldId_OsVersion, s_os_version, util::Strnlen(s_os_version, sizeof(s_os_version)));
auto_record->Add(FieldId_PrivateOsVersion, s_private_os_version, util::Strnlen(s_private_os_version, sizeof(s_private_os_version)));
auto_record->Add(FieldId_SerialNumber, s_serial_number, util::Strnlen(s_serial_number, sizeof(s_serial_number)));
auto_record->Add(FieldId_ReportIdentifier, identifier_str, util::Strnlen(identifier_str, sizeof(identifier_str)));
auto_record->Add(FieldId_OccurrenceTimestamp, timestamp_user.value);
auto_record->Add(FieldId_OccurrenceTimestampNet, timestamp_network.value);
auto_record->Add(FieldId_ReportVisibilityFlag, type == ReportType_Visible);
auto_record->Add(FieldId_OccurrenceTick, occurrence_tick.GetInt64Value());
auto_record->Add(FieldId_SteadyClockInternalOffset, steady_clock_internal_offset_seconds);
auto_record->Add(FieldId_SteadyClockCurrentTimePointValue, steady_clock_current_timepoint.value);
auto_record->Add(FieldId_ElapsedTimeSincePowerOn, (occurrence_tick - *s_power_on_time).ToTimeSpan().GetSeconds());
auto_record->Add(FieldId_ElapsedTimeSinceLastAwake, (occurrence_tick - *s_awake_time).ToTimeSpan().GetSeconds());
if (s_initial_launch_settings_completion_time) {
s64 elapsed_seconds;
if (R_SUCCEEDED(time::GetElapsedSecondsBetween(std::addressof(elapsed_seconds), *s_initial_launch_settings_completion_time, steady_clock_current_timepoint))) {
auto_record->Add(FieldId_ElapsedTimeSinceInitialLaunch, elapsed_seconds);
} }
} }
if (s_application_launch_time) {
auto_record->Add(FieldId_ApplicationAliveTime, (occurrence_tick - *s_application_launch_time).ToTimeSpan().GetSeconds());
}
/* Submit applet active duration information. */
{
const auto *error_info_ctx = record->GetContextEntryPtr();
SubmitAppletActiveDurationForCrashReport(error_info_ctx, error_info_ctx->array_buffer, error_info_ctx->array_buffer_size - error_info_ctx->array_free_count, auto_record.get());
}
/* Submit the auto record. */
R_TRY(Context::SubmitContextRecord(std::move(auto_record)));
/* Submit the info record. */
R_TRY(Context::SubmitContextRecord(std::move(record)));
/* Submit context for resource limits. */
SubmitResourceLimitContexts();
return ResultSuccess();
}
} }

View file

@ -15,6 +15,7 @@
*/ */
#pragma once #pragma once
#include <stratosphere.hpp> #include <stratosphere.hpp>
#include "erpt_srv_context_record.hpp"
namespace ams::erpt::srv { namespace ams::erpt::srv {
@ -28,22 +29,6 @@ namespace ams::erpt::srv {
static std::optional<os::Tick> s_awake_time; static std::optional<os::Tick> s_awake_time;
static std::optional<os::Tick> s_power_on_time; static std::optional<os::Tick> s_power_on_time;
static std::optional<time::SteadyClockTimePoint> s_initial_launch_settings_completion_time; static std::optional<time::SteadyClockTimePoint> s_initial_launch_settings_completion_time;
private:
const ReportType type;
const ContextEntry * const ctx;
const u8 * const data;
const u32 data_size;
const ReportMetaData * const meta;
const AttachmentId * const attachments;
const u32 num_attachments;
char identifier_str[0x40];
time::PosixTime timestamp_user;
time::PosixTime timestamp_network;
os::Tick occurrence_tick;
s64 steady_clock_internal_offset_seconds;
ReportId report_id;
Result ctx_result;
time::SteadyClockTimePoint steady_clock_current_timepoint;
public: public:
static void ClearApplicationLaunchTime() { s_application_launch_time = std::nullopt; } static void ClearApplicationLaunchTime() { s_application_launch_time = std::nullopt; }
static void ClearInitialLaunchSettingsCompletionTime() { s_initial_launch_settings_completion_time = std::nullopt; } static void ClearInitialLaunchSettingsCompletionTime() { s_initial_launch_settings_completion_time = std::nullopt; }
@ -65,20 +50,16 @@ namespace ams::erpt::srv {
return ResultSuccess(); return ResultSuccess();
} }
static Result RegisterRunningApplet(ncm::ProgramId program_id);
static Result UnregisterRunningApplet(ncm::ProgramId program_id);
static Result UpdateAppletSuspendedDuration(ncm::ProgramId program_id, TimeSpan duration);
static void SetRedirectNewReportsToSdCard(bool en) { s_redirect_new_reports = en; } static void SetRedirectNewReportsToSdCard(bool en) { s_redirect_new_reports = en; }
private: private:
Result ValidateReportContext(); static Result SubmitReportContexts(const ReportId &report_id, ReportType type, Result ctx_result, std::unique_ptr<ContextRecord> record, const time::PosixTime &user_timestamp, const time::PosixTime &network_timestamp);
Result CollectUniqueReportFields();
Result SubmitReportDefaults();
Result SubmitReportContexts();
Result LinkAttachments();
Result CreateReportFile();
void SaveSyslogReportIfRequired();
void SaveSyslogReport();
public: public:
Reporter(ReportType type, const ContextEntry *ctx, const u8 *data, u32 data_size, const ReportMetaData *meta, const AttachmentId *attachments, u32 num_attachments, Result ctx_result); static Result CreateReport(ReportType type, Result ctx_result, const ContextEntry *ctx, const u8 *data, u32 data_size, const ReportMetaData *meta, const AttachmentId *attachments, u32 num_attachments);
static Result CreateReport(ReportType type, Result ctx_result, std::unique_ptr<ContextRecord> record, const ReportMetaData *meta, const AttachmentId *attachments, u32 num_attachments);
Result CreateReport();
}; };
} }