| // 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; |
| } |
| } |