blob: 7618dcb1c50373877ae77d0bf8b6e48502f41fe8 [file] [log] [blame]
// Copyright 2020 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "crash-reporter/arcvm_native_collector.h"
#include <utility>
#include <base/files/file.h>
#include <base/files/file_path.h>
#include <base/files/file_util.h>
#include <base/strings/stringprintf.h>
#include <brillo/syslog_logging.h>
#include "crash-reporter/arc_util.h"
#include "crash-reporter/constants.h"
#include "crash-reporter/util.h"
namespace {
constexpr char kArcvmNativeCollectorName[] = "ARCVM_native";
constexpr char kArcvmNativeCrashType[] = "native_crash";
} // namespace
ArcvmNativeCollector::ArcvmNativeCollector()
: CrashCollector(kArcvmNativeCollectorName,
kAlwaysUseUserCrashDirectory,
kNormalCrashSendMode) {}
ArcvmNativeCollector::~ArcvmNativeCollector() = default;
bool ArcvmNativeCollector::HandleCrash(
const arc_util::BuildProperty& build_property,
const CrashInfo& crash_info) {
return HandleCrashWithMinidumpFD(build_property, crash_info,
base::ScopedFD(STDIN_FILENO));
}
bool ArcvmNativeCollector::HandleCrashWithMinidumpFD(
const arc_util::BuildProperty& build_property,
const CrashInfo& crash_info,
base::ScopedFD minidump_fd) {
const std::string message =
"Received crash notification for " + crash_info.exec_name;
LogCrash(message, "handling");
bool out_of_capacity = false;
base::FilePath crash_dir;
if (!GetCreatedCrashDirectoryByEuid(geteuid(), &crash_dir,
&out_of_capacity)) {
LOG(ERROR) << "Failed to create or find crash directory";
if (!out_of_capacity)
EnqueueCollectionErrorLog(kErrorSystemIssue, crash_info.exec_name);
return false;
}
AddArcMetadata(build_property, crash_info);
const std::string basename_without_ext =
FormatDumpBasename(crash_info.exec_name, crash_info.time, crash_info.pid);
const base::FilePath minidump_path = GetCrashPath(
crash_dir, basename_without_ext, constants::kMinidumpExtension);
if (!DumpFdToFile(std::move(minidump_fd), minidump_path)) {
LOG(ERROR) << "Failed to write minidump file";
return false;
}
const base::FilePath metadata_path =
GetCrashPath(crash_dir, basename_without_ext, "meta");
FinishCrash(metadata_path, crash_info.exec_name,
minidump_path.BaseName().value());
return true;
}
void ArcvmNativeCollector::AddArcMetadata(
const arc_util::BuildProperty& build_property,
const CrashInfo& crash_info) {
AddCrashMetaUploadData(arc_util::kProductField, arc_util::kArcProduct);
AddCrashMetaUploadData(arc_util::kProcessField, crash_info.exec_name);
AddCrashMetaUploadData(arc_util::kCrashTypeField, kArcvmNativeCrashType);
AddCrashMetaUploadData(arc_util::kChromeOsVersionField,
CrashCollector::GetOsVersion());
for (auto metadata : arc_util::ListMetadataForBuildProperty(build_property)) {
AddCrashMetaUploadData(metadata.first, metadata.second);
}
}
bool ArcvmNativeCollector::DumpFdToFile(base::ScopedFD src_fd,
const base::FilePath& dst_path) {
base::ScopedFD dst_fd = GetNewFileHandle(dst_path);
if (!dst_fd.is_valid())
return false;
base::File src_file(src_fd.release());
constexpr size_t kBufferSize = 4096;
char buffer[kBufferSize];
while (true) {
ssize_t bytes_written =
src_file.ReadAtCurrentPosNoBestEffort(buffer, kBufferSize);
if (bytes_written < 0)
return false;
if (bytes_written == 0)
return true;
if (!base::WriteFileDescriptor(dst_fd.get(), buffer, bytes_written))
return false;
}
}