Index: crash_reporter.cc |
diff --git a/crash_reporter.cc b/crash_reporter.cc |
index 0930cea447e19927f893193b6a02db7eaa7cfaaf..e850e3070800555db1818cec65a20b04a30e4244 100644 |
--- a/crash_reporter.cc |
+++ b/crash_reporter.cc |
@@ -7,7 +7,9 @@ |
#include "base/file_util.h" |
#include "base/logging.h" |
#include "base/string_util.h" |
+#include "crash-reporter/kernel_collector.h" |
#include "crash-reporter/system_logging.h" |
+#include "crash-reporter/unclean_shutdown_collector.h" |
#include "crash-reporter/user_collector.h" |
#include "gflags/gflags.h" |
#include "metrics/metrics_library.h" |
@@ -22,69 +24,52 @@ DEFINE_bool(unclean_check, true, "Check for unclean shutdown"); |
#pragma GCC diagnostic error "-Wstrict-aliasing" |
static const char kCrashCounterHistogram[] = "Logging.CrashCounter"; |
-static const char kEmpty[] = ""; |
+static const char kUserCrashSignal[] = |
+ "org.chromium.CrashReporter.UserCrash"; |
static const char kUncleanShutdownFile[] = |
"/var/lib/crash_reporter/pending_clean_shutdown"; |
// Enumeration of kinds of crashes to be used in the CrashCounter histogram. |
enum CrashKinds { |
- kCrashKindKernel = 1, |
- kCrashKindUser = 2, |
+ kCrashKindUncleanShutdown = 1, |
+ kCrashKindUser = 2, |
+ kCrashKindKernel = 3, |
kCrashKindMax |
}; |
static MetricsLibrary s_metrics_lib; |
static SystemLoggingImpl s_system_log; |
-static bool IsMetricsCollectionAllowed() { |
- // TODO(kmixter): Eventually check system tainted state and |
- // move this down in metrics library where it would be explicitly |
- // checked when asked to send stats. |
+static bool IsFeedbackAllowed() { |
+ // Once crosbug.com/5814 is fixed, call the is opted in function |
+ // here. |
return true; |
} |
-static void CheckUncleanShutdown() { |
- FilePath unclean_file_path(kUncleanShutdownFile); |
- if (!file_util::PathExists(unclean_file_path)) { |
- return; |
- } |
- s_system_log.LogWarning("Last shutdown was not clean"); |
- if (IsMetricsCollectionAllowed()) { |
- s_metrics_lib.SendEnumToUMA(std::string(kCrashCounterHistogram), |
- kCrashKindKernel, |
- kCrashKindMax); |
- } |
- if (!file_util::Delete(unclean_file_path, false)) { |
- s_system_log.LogError("Failed to delete unclean shutdown file %s", |
- kUncleanShutdownFile); |
- } |
- |
- // Touch a file to notify the metrics daemon that a kernel crash has |
- // been detected so that it can log the time since the last kernel |
- // crash. |
- static const char kKernelCrashDetectedFile[] = "/tmp/kernel-crash-detected"; |
- FilePath crash_detected(kKernelCrashDetectedFile); |
- file_util::WriteFile(crash_detected, kEmpty, 0); |
+static bool TouchFile(const FilePath &file_path) { |
+ return file_util::WriteFile(file_path, "", 0) == 0; |
} |
-static bool PrepareUncleanShutdownCheck() { |
- FilePath file_path(kUncleanShutdownFile); |
- file_util::CreateDirectory(file_path.DirName()); |
- return file_util::WriteFile(file_path, kEmpty, 0) == 0; |
+static void CountKernelCrash() { |
+ s_metrics_lib.SendEnumToUMA(std::string(kCrashCounterHistogram), |
+ kCrashKindKernel, |
+ kCrashKindMax); |
} |
-static void SignalCleanShutdown() { |
- s_system_log.LogInfo("Clean shutdown signalled"); |
- file_util::Delete(FilePath(kUncleanShutdownFile), false); |
+static void CountUncleanShutdown() { |
+ s_metrics_lib.SendEnumToUMA(std::string(kCrashCounterHistogram), |
+ kCrashKindUncleanShutdown, |
+ kCrashKindMax); |
} |
static void CountUserCrash() { |
- CHECK(IsMetricsCollectionAllowed()); |
s_metrics_lib.SendEnumToUMA(std::string(kCrashCounterHistogram), |
kCrashKindUser, |
kCrashKindMax); |
- |
+ std::string command = StringPrintf( |
+ "/usr/bin/dbus-send --type=signal --system / \"%s\"", |
+ kUserCrashSignal); |
// Announce through D-Bus whenever a user crash happens. This is |
// used by the metrics daemon to log active use time between |
// crashes. |
@@ -93,42 +78,47 @@ static void CountUserCrash() { |
// using a dbus library directly. However, this should run |
// relatively rarely and longer term we may need to implement a |
// better way to do this that doesn't rely on D-Bus. |
- int status __attribute__((unused)) = |
- system("/usr/bin/dbus-send --type=signal --system / " |
- "org.chromium.CrashReporter.UserCrash"); |
+ |
+ int status __attribute__((unused)) = system(command.c_str()); |
} |
-int main(int argc, char *argv[]) { |
- google::ParseCommandLineFlags(&argc, &argv, true); |
- FilePath my_path(argv[0]); |
- file_util::AbsolutePath(&my_path); |
- s_metrics_lib.Init(); |
- s_system_log.Initialize(my_path.BaseName().value().c_str()); |
- UserCollector user_collector; |
- user_collector.Initialize(CountUserCrash, |
- my_path.value(), |
- IsMetricsCollectionAllowed, |
- &s_system_log, |
- true); // generate_diagnostics |
+static int Initialize(KernelCollector *kernel_collector, |
+ UserCollector *user_collector, |
+ UncleanShutdownCollector *unclean_shutdown_collector) { |
+ CHECK(!FLAGS_clean_shutdown) << "Incompatible options"; |
- if (FLAGS_init) { |
- CHECK(!FLAGS_clean_shutdown) << "Incompatible options"; |
- user_collector.Enable(); |
- if (FLAGS_unclean_check) { |
- CheckUncleanShutdown(); |
- if (!PrepareUncleanShutdownCheck()) { |
- s_system_log.LogError("Unable to create shutdown check file"); |
- } |
- } |
- return 0; |
+ bool was_kernel_crash = false; |
+ bool was_unclean_shutdown = false; |
+ if (kernel_collector->IsEnabled()) { |
+ was_kernel_crash = kernel_collector->Collect(); |
} |
- if (FLAGS_clean_shutdown) { |
- SignalCleanShutdown(); |
- user_collector.Disable(); |
- return 0; |
+ if (FLAGS_unclean_check) { |
+ was_unclean_shutdown = unclean_shutdown_collector->Collect(); |
+ } |
+ |
+ // Touch a file to notify the metrics daemon that a kernel |
+ // crash has been detected so that it can log the time since |
+ // the last kernel crash. |
+ if (IsFeedbackAllowed()) { |
+ if (was_kernel_crash) { |
+ TouchFile(FilePath("/tmp/kernel-crash-detected")); |
+ } else if (was_unclean_shutdown) { |
+ // We only count an unclean shutdown if it did not come with |
+ // an associated kernel crash. |
+ TouchFile(FilePath("/tmp/unclean-shutdown-detected")); |
+ } |
} |
+ // Must enable the unclean shutdown collector *after* collecting. |
+ kernel_collector->Enable(); |
+ unclean_shutdown_collector->Enable(); |
+ user_collector->Enable(); |
+ |
+ return 0; |
+} |
+ |
+static int HandleUserCrash(UserCollector *user_collector) { |
// Handle a specific user space crash. |
CHECK(FLAGS_signal != -1) << "Signal must be set"; |
CHECK(FLAGS_pid != -1) << "PID must be set"; |
@@ -141,9 +131,45 @@ int main(int argc, char *argv[]) { |
} |
// Handle the crash, get the name of the process from procfs. |
- if (!user_collector.HandleCrash(FLAGS_signal, FLAGS_pid, NULL)) { |
+ if (!user_collector->HandleCrash(FLAGS_signal, FLAGS_pid, NULL)) { |
return 1; |
} |
- |
return 0; |
} |
+ |
+ |
+int main(int argc, char *argv[]) { |
+ google::ParseCommandLineFlags(&argc, &argv, true); |
+ FilePath my_path(argv[0]); |
+ file_util::AbsolutePath(&my_path); |
+ s_metrics_lib.Init(); |
+ s_system_log.Initialize(my_path.BaseName().value().c_str()); |
+ KernelCollector kernel_collector; |
+ kernel_collector.Initialize(CountKernelCrash, |
+ IsFeedbackAllowed, |
+ &s_system_log); |
+ UserCollector user_collector; |
+ user_collector.Initialize(CountUserCrash, |
+ my_path.value(), |
+ IsFeedbackAllowed, |
+ &s_system_log, |
+ true); // generate_diagnostics |
+ UncleanShutdownCollector unclean_shutdown_collector; |
+ unclean_shutdown_collector.Initialize(CountUncleanShutdown, |
+ IsFeedbackAllowed, |
+ &s_system_log); |
+ |
+ if (FLAGS_init) { |
+ return Initialize(&kernel_collector, |
+ &user_collector, |
+ &unclean_shutdown_collector); |
+ } |
+ |
+ if (FLAGS_clean_shutdown) { |
+ unclean_shutdown_collector.Disable(); |
+ user_collector.Disable(); |
+ return 0; |
+ } |
+ |
+ return HandleUserCrash(&user_collector); |
+} |