diff --git a/DEPS b/DEPS index f4a8d97a..52333980 100644 --- a/DEPS +++ b/DEPS @@ -25,7 +25,7 @@ deps = { '93cc6e2c23e4d5ebd179f388e67aa907d0dfd43d', 'crashpad/third_party/mini_chromium/mini_chromium': Var('chromium_git') + '/chromium/mini_chromium@' + - '438bd4f4d8d38dd5c31e78a0d605cc4cf6be5229', + '88e0a3e1a965c698d7ead8bcfc0cfb6aacdc3524', 'buildtools': Var('chromium_git') + '/chromium/buildtools.git@' + 'f8fc76ea5ce4a60cda2fa5d7df3d4a62935b3113', diff --git a/handler/mac/crash_report_exception_handler.cc b/handler/mac/crash_report_exception_handler.cc index 288148e9..2a115623 100644 --- a/handler/mac/crash_report_exception_handler.cc +++ b/handler/mac/crash_report_exception_handler.cc @@ -32,6 +32,7 @@ #include "util/mach/mach_message.h" #include "util/mach/scoped_task_suspend.h" #include "util/mach/symbolic_constants_mach.h" +#include "util/misc/metrics.h" #include "util/misc/tri_state.h" #include "util/misc/uuid.h" @@ -64,6 +65,8 @@ kern_return_t CrashReportExceptionHandler::CatchMachException( mach_msg_type_number_t* new_state_count, const mach_msg_trailer_t* trailer, bool* destroy_complex_request) { + Metrics::ExceptionEncountered(); + Metrics::ExceptionCode(exception); *destroy_complex_request = true; // The expected behavior is EXCEPTION_STATE_IDENTITY | MACH_EXCEPTION_CODES, @@ -74,6 +77,8 @@ kern_return_t CrashReportExceptionHandler::CatchMachException( "unexpected exception behavior %s, rejecting", ExceptionBehaviorToString( behavior, kUseFullName | kUnknownIsNumeric | kUseOr).c_str()); + Metrics::ExceptionCaptureResult( + Metrics::CaptureResult::kUnexpectedExceptionBehavior); return KERN_FAILURE; } else if (behavior != (EXCEPTION_STATE_IDENTITY | kMachExceptionCodes)) { LOG(WARNING) << base::StringPrintf( @@ -84,6 +89,8 @@ kern_return_t CrashReportExceptionHandler::CatchMachException( if (task == mach_task_self()) { LOG(ERROR) << "cannot suspend myself"; + Metrics::ExceptionCaptureResult( + Metrics::CaptureResult::kFailedDueToSuspendSelf); return KERN_FAILURE; } @@ -91,6 +98,7 @@ kern_return_t CrashReportExceptionHandler::CatchMachException( ProcessSnapshotMac process_snapshot; if (!process_snapshot.Initialize(task)) { + Metrics::ExceptionCaptureResult(Metrics::CaptureResult::kSnapshotFailed); return KERN_FAILURE; } @@ -126,6 +134,8 @@ kern_return_t CrashReportExceptionHandler::CatchMachException( *flavor, old_state, old_state_count)) { + Metrics::ExceptionCaptureResult( + Metrics::CaptureResult::kExceptionInitializationFailed); return KERN_FAILURE; } @@ -145,6 +155,8 @@ kern_return_t CrashReportExceptionHandler::CatchMachException( CrashReportDatabase::OperationStatus database_status = database_->PrepareNewCrashReport(&new_report); if (database_status != CrashReportDatabase::kNoError) { + Metrics::ExceptionCaptureResult( + Metrics::CaptureResult::kPrepareNewCrashReportFailed); return KERN_FAILURE; } @@ -158,6 +170,8 @@ kern_return_t CrashReportExceptionHandler::CatchMachException( MinidumpFileWriter minidump; minidump.InitializeFromSnapshot(&process_snapshot); if (!minidump.WriteEverything(&file_writer)) { + Metrics::ExceptionCaptureResult( + Metrics::CaptureResult::kMinidumpWriteFailed); return KERN_FAILURE; } @@ -166,6 +180,8 @@ kern_return_t CrashReportExceptionHandler::CatchMachException( UUID uuid; database_status = database_->FinishedWritingCrashReport(new_report, &uuid); if (database_status != CrashReportDatabase::kNoError) { + Metrics::ExceptionCaptureResult( + Metrics::CaptureResult::kFinishedWritingCrashReportFailed); return KERN_FAILURE; } @@ -223,6 +239,7 @@ kern_return_t CrashReportExceptionHandler::CatchMachException( ExcServerCopyState( behavior, old_state, old_state_count, new_state, new_state_count); + Metrics::ExceptionCaptureResult(Metrics::CaptureResult::kSuccess); return ExcServerSuccessfulReturnValue(exception, behavior, false); } diff --git a/handler/win/crash_report_exception_handler.cc b/handler/win/crash_report_exception_handler.cc index b9c6d111..80a996b0 100644 --- a/handler/win/crash_report_exception_handler.cc +++ b/handler/win/crash_report_exception_handler.cc @@ -20,6 +20,7 @@ #include "minidump/minidump_file_writer.h" #include "snapshot/win/process_snapshot_win.h" #include "util/file/file_writer.h" +#include "util/misc/metrics.h" #include "util/win/registration_protocol_win.h" #include "util/win/scoped_process_suspend.h" @@ -46,6 +47,8 @@ unsigned int CrashReportExceptionHandler::ExceptionHandlerServerException( WinVMAddress debug_critical_section_address) { const unsigned int kFailedTerminationCode = 0xffff7002; + Metrics::ExceptionEncountered(); + ScopedProcessSuspend suspend(process); ProcessSnapshotWin process_snapshot; @@ -54,6 +57,7 @@ unsigned int CrashReportExceptionHandler::ExceptionHandlerServerException( exception_information_address, debug_critical_section_address)) { LOG(WARNING) << "ProcessSnapshotWin::Initialize failed"; + Metrics::ExceptionCaptureResult(Metrics::CaptureResult::kSnapshotFailed); return kFailedTerminationCode; } @@ -62,6 +66,8 @@ unsigned int CrashReportExceptionHandler::ExceptionHandlerServerException( const unsigned int termination_code = process_snapshot.Exception()->Exception(); + Metrics::ExceptionCode(termination_code); + CrashpadInfoClientOptions client_options; process_snapshot.GetCrashpadOptions(&client_options); if (client_options.crashpad_handler_behavior != TriState::kDisabled) { @@ -82,6 +88,8 @@ unsigned int CrashReportExceptionHandler::ExceptionHandlerServerException( database_->PrepareNewCrashReport(&new_report); if (database_status != CrashReportDatabase::kNoError) { LOG(ERROR) << "PrepareNewCrashReport failed"; + Metrics::ExceptionCaptureResult( + Metrics::CaptureResult::kPrepareNewCrashReportFailed); return termination_code; } @@ -96,6 +104,8 @@ unsigned int CrashReportExceptionHandler::ExceptionHandlerServerException( minidump.InitializeFromSnapshot(&process_snapshot); if (!minidump.WriteEverything(&file_writer)) { LOG(ERROR) << "WriteEverything failed"; + Metrics::ExceptionCaptureResult( + Metrics::CaptureResult::kMinidumpWriteFailed); return termination_code; } @@ -105,12 +115,15 @@ unsigned int CrashReportExceptionHandler::ExceptionHandlerServerException( database_status = database_->FinishedWritingCrashReport(new_report, &uuid); if (database_status != CrashReportDatabase::kNoError) { LOG(ERROR) << "FinishedWritingCrashReport failed"; + Metrics::ExceptionCaptureResult( + Metrics::CaptureResult::kFinishedWritingCrashReportFailed); return termination_code; } upload_thread_->ReportPending(); } + Metrics::ExceptionCaptureResult(Metrics::CaptureResult::kSuccess); return termination_code; } diff --git a/util/misc/metrics.cc b/util/misc/metrics.cc index 6a363b13..0f2b326e 100644 --- a/util/misc/metrics.cc +++ b/util/misc/metrics.cc @@ -15,13 +15,32 @@ #include "util/misc/metrics.h" #include "base/metrics/histogram_macros.h" +#include "base/metrics/sparse_histogram.h" namespace crashpad { +// static void Metrics::CrashReportSize(FileHandle file) { const FileOffset size = LoggingFileSizeByHandle(file); UMA_HISTOGRAM_CUSTOM_COUNTS( "Crashpad.CrashReportSize", size, 0, 5 * 1024 * 1024, 50); } +// static +void Metrics::ExceptionCaptureResult(CaptureResult result) { + UMA_HISTOGRAM_ENUMERATION( + "Crashpad.ExceptionCaptureResult", result, CaptureResult::kMaxValue); +} + +// static +void Metrics::ExceptionCode(uint32_t code) { + UMA_HISTOGRAM_SPARSE_SLOWLY("Crashpad.ExceptionCode", + static_cast(code)); +} + +// static +void Metrics::ExceptionEncountered() { + UMA_HISTOGRAM_COUNTS("Crashpad.ExceptionEncountered", 1); +} + } // namespace crashpad diff --git a/util/misc/metrics.h b/util/misc/metrics.h index 315a122f..57f5d4ce 100644 --- a/util/misc/metrics.h +++ b/util/misc/metrics.h @@ -15,6 +15,8 @@ #ifndef CRASHPAD_UTIL_MISC_METRICS_H_ #define CRASHPAD_UTIL_MISC_METRICS_H_ +#include + #include "base/macros.h" #include "util/file/file_io.h" @@ -32,6 +34,55 @@ class Metrics { //! when a new report is written to disk. static void CrashReportSize(FileHandle file); + //! \brief The result of capturing an exception. These are used as metrics + //! enumeration values so new values should always be added at the end. + enum class CaptureResult : int { + //! \brief The exception capture succeeded normally. + kSuccess = 0, + + //! \brief Unexpected exception behavior. + //! + //! This value is only used on Mac OS X. + kUnexpectedExceptionBehavior = 1, + + //! \brief Failed due to attempt to suspend self. + //! + //! This value is only used on Mac OS X. + kFailedDueToSuspendSelf = 2, + + //! \brief The process snapshot could not be captured. + kSnapshotFailed = 3, + + //! \brief The exception could not be initialized. + kExceptionInitializationFailed = 4, + + //! \brief The attempt to prepare a new crash report in the crash database + //! failed. + kPrepareNewCrashReportFailed = 5, + + //! \brief Writing the minidump to disk failed. + kMinidumpWriteFailed = 6, + + //! \brief There was a database error in attempt to complete the report. + kFinishedWritingCrashReportFailed = 7, + + //! \brief The number of values in this enumeration; not a valid value. + kMaxValue + }; + + //! \brief Reports on the outcome of capturing a report in the exception + //! handler. + static void ExceptionCaptureResult(CaptureResult result); + + //! \brief The exception code for an exception was retrieved. + //! + //! These values are OS-specific, and correspond to + //! MINIDUMP_EXCEPTION::ExceptionCode. + static void ExceptionCode(uint32_t exception_code); + + //! \brief The exception handler server started capturing an exception. + static void ExceptionEncountered(); + private: DISALLOW_IMPLICIT_CONSTRUCTORS(Metrics); };