blob: ffdb56a2a0bafa2c14f54a79c05dd07b183072e8 [file] [log] [blame]
// Copyright 2019 The ChromiumOS Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "crash-reporter/generic_failure_collector.h"
#include <memory>
#include <optional>
#include <string>
#include <base/files/file_path.h>
#include <base/files/file_util.h>
#include <base/functional/bind.h>
#include <base/logging.h>
#include <base/memory/ref_counted.h>
#include <base/memory/scoped_refptr.h>
#include <base/strings/stringprintf.h>
#include <metrics/metrics_library.h>
#include "crash-reporter/constants.h"
#include "crash-reporter/crash_collection_status.h"
#include "crash-reporter/crash_collector_names.h"
#include "crash-reporter/util.h"
namespace {
const char kSignatureKey[] = "sig";
} // namespace
using base::FilePath;
using base::StringPrintf;
const char* const GenericFailureCollector::kAuthFailure = "auth-failure";
const char* const GenericFailureCollector::kCryptohome = "cryptohome";
const char* const GenericFailureCollector::kSuspendFailure = "suspend-failure";
const char* const GenericFailureCollector::kServiceFailure = "service-failure";
const char* const GenericFailureCollector::kArcServiceFailure =
"arc-service-failure";
const char* const GenericFailureCollector::kModemFailure = "cellular-failure";
const char* const GenericFailureCollector::kModemfwdFailure =
"modemfwd_failure";
const char* const GenericFailureCollector::kGuestOomEvent = "guest-oom-event";
const char* const GenericFailureCollector::kHermesFailure = "hermes_failure";
const char* const GenericFailureCollector::kTetheringFailure =
"tethering-failure";
const char* const GenericFailureCollector::kBrowserHang = "browser_hang";
GenericFailureCollector::GenericFailureCollector(
const scoped_refptr<
base::RefCountedData<std::unique_ptr<MetricsLibraryInterface>>>&
metrics_lib)
: CrashCollector(CrashReporterCollector::kGenericFailure, metrics_lib),
failure_report_path_("/dev/stdin") {}
GenericFailureCollector::~GenericFailureCollector() {}
CrashCollectionStatus GenericFailureCollector::LoadGenericFailure(
std::string* content, std::string* signature) {
FilePath failure_report_path(failure_report_path_.c_str());
if (!base::ReadFileToString(failure_report_path, content)) {
LOG(ERROR) << "Could not open " << failure_report_path.value();
return CrashCollectionStatus::kFailureReadingGenericReport;
}
std::string::size_type end_position = content->find('\n');
if (end_position == std::string::npos) {
LOG(ERROR) << "unexpected generic failure format";
return CrashCollectionStatus::kBadGenericReportFormat;
}
*signature = content->substr(0, end_position);
return CrashCollectionStatus::kSuccess;
}
CrashCollectionStatus GenericFailureCollector::CollectFull(
const std::string& exec_name,
const std::string& log_key_name,
std::optional<int> weight,
bool use_log_conf_file) {
LOG(INFO) << "Processing generic failure";
std::string generic_failure;
std::string failure_signature;
CrashCollectionStatus status =
LoadGenericFailure(&generic_failure, &failure_signature);
if (!IsSuccessCode(status)) {
return status;
}
FilePath crash_directory;
status = GetCreatedCrashDirectoryByEuid(constants::kRootUid, &crash_directory,
nullptr);
if (!IsSuccessCode(status)) {
return status;
}
std::string dump_basename = FormatDumpBasename(exec_name, time(nullptr), 0);
FilePath log_path = GetCrashPath(crash_directory, dump_basename, "log");
FilePath meta_path = GetCrashPath(crash_directory, dump_basename, "meta");
if (weight) {
AddCrashMetaWeight(*weight);
}
AddCrashMetaData(kSignatureKey, failure_signature);
status = use_log_conf_file
? GetLogContents(log_config_path_, log_key_name, log_path)
: WriteLogContents(generic_failure, log_path);
// Unlike most collectors, in here failure to gather log files is considered a
// crash report generation failure. The logs are the payload, so if we don't
// generate logs, we don't have a valid crash report.
if (!IsSuccessCode(status)) {
return status;
}
return FinishCrash(meta_path, exec_name, log_path.BaseName().value());
}
CrashCollector::ComputedCrashSeverity GenericFailureCollector::ComputeSeverity(
const std::string& exec_name) {
ComputedCrashSeverity computed_severity{
.crash_severity = CrashSeverity::kUnspecified,
.product_group = Product::kPlatform,
};
if ((exec_name == kSuspendFailure) ||
base::StartsWith(exec_name, kServiceFailure)) {
computed_severity.crash_severity = CrashSeverity::kWarning;
}
return computed_severity;
}
// static
CollectorInfo GenericFailureCollector::GetHandlerInfo(
const HandlerInfoOptions& options,
const scoped_refptr<
base::RefCountedData<std::unique_ptr<MetricsLibraryInterface>>>&
metrics_lib) {
auto generic_failure_collector =
std::make_shared<GenericFailureCollector>(metrics_lib);
return {
.collector = generic_failure_collector,
.handlers = {
{
.should_handle = options.suspend_failure,
.cb = base::BindRepeating(
&GenericFailureCollector::CollectWithWeight,
generic_failure_collector, kSuspendFailure,
util::GetSuspendFailureWeight()),
},
{
.should_handle = options.auth_failure,
.cb =
base::BindRepeating(&GenericFailureCollector::Collect,
generic_failure_collector, kAuthFailure),
},
{
.should_handle = options.modem_failure,
.cb = base::BindRepeating(
&GenericFailureCollector::CollectWithWeight,
generic_failure_collector, kModemFailure, options.weight),
},
{
.should_handle = options.modemfwd_failure,
.cb = base::BindRepeating(
&GenericFailureCollector::CollectWithWeight,
generic_failure_collector, kModemfwdFailure, options.weight),
},
{
.should_handle = options.hermes_failure,
.cb = base::BindRepeating(
&GenericFailureCollector::CollectWithWeight,
generic_failure_collector, kHermesFailure, options.weight),
},
{
.should_handle = !options.arc_service_failure.empty(),
.cb = base::BindRepeating(
&GenericFailureCollector::CollectFull,
generic_failure_collector,
StringPrintf("%s-%s", kArcServiceFailure,
options.arc_service_failure.c_str()),
kArcServiceFailure, util::GetServiceFailureWeight(),
/*use_log_conf_file=*/true),
},
{
.should_handle = !options.service_failure.empty(),
.cb = base::BindRepeating(
&GenericFailureCollector::CollectFull,
generic_failure_collector,
StringPrintf("%s-%s", kServiceFailure,
options.service_failure.c_str()),
kServiceFailure, util::GetServiceFailureWeight(),
/*use_log_conf_file=*/true),
},
{.should_handle = options.guest_oom_event,
.should_check_appsync = true,
.cb = base::BindRepeating(&GenericFailureCollector::CollectFull,
generic_failure_collector, kGuestOomEvent,
"", util::GetOomEventWeight(),
/*use_log_conf_file=*/false)},
{
.should_handle = options.recovery_failure,
.cb = base::BindRepeating(
&GenericFailureCollector::CollectWithWeight,
generic_failure_collector, kCryptohome,
util::GetRecoveryFailureWeight()),
},
{
.should_handle = options.tethering_failure,
.cb = base::BindRepeating(
&GenericFailureCollector::CollectWithWeight,
generic_failure_collector, kTetheringFailure, options.weight),
},
{
.should_handle = options.browser_hang,
.cb = base::BindRepeating(
&GenericFailureCollector::CollectWithWeight,
generic_failure_collector, kBrowserHang, options.weight),
},
}};
}