Add # daily crashes metrics and separate kernel crashes out.

BUG=5340

Review URL: http://codereview.chromium.org/3181015
diff --git a/metrics/counter.cc b/metrics/counter.cc
index b81a0d1..4de1db1 100644
--- a/metrics/counter.cc
+++ b/metrics/counter.cc
@@ -183,4 +183,32 @@
   }
 }
 
+FrequencyCounter::FrequencyCounter() : cycle_duration_(1) {
+}
+
+FrequencyCounter::~FrequencyCounter() {
+}
+
+void FrequencyCounter::Init(const char* filename,
+                            TaggedCounterInterface::Reporter reporter,
+                            void* reporter_handle,
+                            time_t cycle_duration) {
+  // Allow tests to inject tagged_counter_ dependency.
+  if (tagged_counter_.get() == NULL) {
+    tagged_counter_.reset(new TaggedCounter());
+  }
+  tagged_counter_->Init(filename, reporter, reporter_handle);
+  DCHECK(cycle_duration > 0);
+  cycle_duration_ = cycle_duration;
+}
+
+void FrequencyCounter::UpdateInternal(int32 count, time_t now) {
+  DCHECK(tagged_counter_.get() != NULL);
+  tagged_counter_->Update(GetCycleNumber(now), count);
+}
+
+int32 FrequencyCounter::GetCycleNumber(time_t now) {
+  return now / cycle_duration_;
+}
+
 }  // namespace chromeos_metrics
diff --git a/metrics/counter.h b/metrics/counter.h
index 1cfcb51..a5e5302 100644
--- a/metrics/counter.h
+++ b/metrics/counter.h
@@ -5,11 +5,18 @@
 #ifndef METRICS_COUNTER_H_
 #define METRICS_COUNTER_H_
 
+#include <time.h>
+
 #include <base/basictypes.h>
+#include <base/scoped_ptr.h>
 #include <gtest/gtest_prod.h>  // for FRIEND_TEST
 
 namespace chromeos_metrics {
 
+// Constants useful for frequency statistics.
+const int kSecondsPerDay = 60 * 60 * 24;
+const int kSecondsPerWeek = kSecondsPerDay * 7;
+
 // TaggedCounter maintains a persistent storage (i.e., a file)
 // aggregation counter for a given tag (e.g., day, hour) that survives
 // system shutdowns, reboots and crashes, as well as daemon process
@@ -152,6 +159,45 @@
   RecordState record_state_;
 };
 
+// FrequencyCounter uses TaggedCounter to maintain a persistent
+// storage of the number of events that occur in a given cycle
+// duration (in other words, a frequency count).  For example, to
+// count the number of blips per day, initialize |cycle_duration| to
+// chromeos_metrics::kSecondsPerDay, and call Update with the number
+// of blips that happen concurrently (usually 1).  Reporting of the
+// value is done through TaggedCounter's reporter function.
+class FrequencyCounter {
+ public:
+  // Create a new frequency counter.
+  FrequencyCounter();
+  virtual ~FrequencyCounter();
+
+  // Initialize a frequency counter, which is necessary before first use.
+  // |filename|, |reporter|, and |reporter_handle| are used as in
+  // TaggedCounter::Init.  |cycle_duration| is the number of seconds
+  // in a cycle.
+  virtual void Init(const char* filename,
+                    TaggedCounterInterface::Reporter reporter,
+                    void* reporter_handle,
+                    time_t cycle_duration);
+  // Record that an event occurred.  |count| is the number of concurrent
+  // events that have occurred.  The time is implicitly assumed to be the
+  // time of the call.
+  virtual void Update(int32 count) {
+    UpdateInternal(count, time(NULL));
+  }
+
+ private:
+  friend class FrequencyCounterTest;
+  FRIEND_TEST(FrequencyCounterTest, UpdateInternal);
+
+  void UpdateInternal(int32 count, time_t now);
+  int32 GetCycleNumber(time_t now);
+
+  time_t cycle_duration_;
+  scoped_ptr<TaggedCounterInterface> tagged_counter_;
+};
+
 }  // namespace chromeos_metrics
 
 #endif  // METRICS_COUNTER_H_
diff --git a/metrics/counter_mock.h b/metrics/counter_mock.h
index baa97b0..701cce4 100644
--- a/metrics/counter_mock.h
+++ b/metrics/counter_mock.h
@@ -21,7 +21,15 @@
   MOCK_METHOD0(Flush, void());
 };
 
+class FrequencyCounterMock : public FrequencyCounter {
+ public:
+  MOCK_METHOD4(Init, void(const char* filename,
+                          TaggedCounterInterface::Reporter reporter,
+                          void* reporter_handle,
+                          time_t cycle_duration));
+  MOCK_METHOD1(Update, void(int32 count));
+};
+
 }  // namespace chromeos_metrics
 
 #endif  // METRICS_COUNTER_MOCK_H_
-
diff --git a/metrics/counter_test.cc b/metrics/counter_test.cc
index fd5a389..eb68b2a 100644
--- a/metrics/counter_test.cc
+++ b/metrics/counter_test.cc
@@ -12,6 +12,7 @@
 #include <gtest/gtest.h>
 
 #include "counter.h"
+#include "counter_mock.h"  // For TaggedCounterMock.
 
 using ::testing::_;
 using ::testing::MockFunction;
@@ -255,6 +256,64 @@
   EXPECT_EQ(TaggedCounter::kRecordValid, counter_.record_state_);
 }
 
+class FrequencyCounterTest : public testing::Test {
+ protected:
+  virtual void SetUp() {
+    tagged_counter_ = new StrictMock<TaggedCounterMock>;
+    frequency_counter_.tagged_counter_.reset(tagged_counter_);
+  }
+
+  static void FakeReporter(void *, int32, int32) {
+  }
+
+  void CheckInit(int32 cycle_duration);
+  void CheckCycleNumber(int32 cycle_duration);
+
+  FrequencyCounter frequency_counter_;
+  StrictMock<TaggedCounterMock>* tagged_counter_;
+
+  TaggedCounter::Reporter reporter_;
+};
+
+void FrequencyCounterTest::CheckInit(int32 cycle_duration) {
+  EXPECT_CALL(*tagged_counter_, Init(kTestRecordFile, FakeReporter, this))
+      .Times(1)
+      .RetiresOnSaturation();
+  frequency_counter_.Init(kTestRecordFile,
+                          FakeReporter,
+                          this,
+                          cycle_duration);
+  EXPECT_EQ(cycle_duration, frequency_counter_.cycle_duration_);
+}
+
+TEST_F(FrequencyCounterTest, Init) {
+  CheckInit(100);
+}
+
+void FrequencyCounterTest::CheckCycleNumber(int32 cycle_duration) {
+  CheckInit(cycle_duration);
+  EXPECT_EQ(150, frequency_counter_.GetCycleNumber(cycle_duration * 150));
+  EXPECT_EQ(150, frequency_counter_.GetCycleNumber(cycle_duration * 150 +
+                                                   cycle_duration - 1));
+  EXPECT_EQ(151, frequency_counter_.GetCycleNumber(cycle_duration * 151 + 1));
+  EXPECT_EQ(0, frequency_counter_.GetCycleNumber(0));
+}
+
+
+TEST_F(FrequencyCounterTest, GetCycleNumberForWeek) {
+  CheckCycleNumber(kSecondsPerWeek);
+}
+
+TEST_F(FrequencyCounterTest, GetCycleNumberForDay) {
+  CheckCycleNumber(kSecondsPerDay);
+}
+
+TEST_F(FrequencyCounterTest, UpdateInternal) {
+  CheckInit(kSecondsPerWeek);
+  EXPECT_CALL(*tagged_counter_, Update(150, 2));
+  frequency_counter_.UpdateInternal(2, kSecondsPerWeek * 150);
+}
+
 }  // namespace chromeos_metrics
 
 int main(int argc, char** argv) {
diff --git a/metrics/metrics_daemon.cc b/metrics/metrics_daemon.cc
index 30d3da8..0171fde 100644
--- a/metrics/metrics_daemon.cc
+++ b/metrics/metrics_daemon.cc
@@ -39,6 +39,10 @@
 static const int kUseMonitorIntervalInit = 1 * kSecondsPerMinute;
 static const int kUseMonitorIntervalMax = 10 * kSecondsPerMinute;
 
+const char kKernelCrashDetectedFile[] = "/tmp/kernel-crash-detected";
+static const char kUncleanShutdownDetectedFile[] =
+      "/tmp/unclean-shutdown-detected";
+
 // static metrics parameters.
 const char MetricsDaemon::kMetricDailyUseTimeName[] =
     "Logging.DailyUseTime";
@@ -46,12 +50,6 @@
 const int MetricsDaemon::kMetricDailyUseTimeMax = kMinutesPerDay;
 const int MetricsDaemon::kMetricDailyUseTimeBuckets = 50;
 
-const char MetricsDaemon::kMetricKernelCrashIntervalName[] =
-    "Logging.KernelCrashInterval";
-const int MetricsDaemon::kMetricKernelCrashIntervalMin = 1;
-const int MetricsDaemon::kMetricKernelCrashIntervalMax = 4 * kSecondsPerWeek;
-const int MetricsDaemon::kMetricKernelCrashIntervalBuckets = 50;
-
 const char MetricsDaemon::kMetricTimeToNetworkDropName[] =
     "Network.TimeToDrop";
 const int MetricsDaemon::kMetricTimeToNetworkDropMin = 1;
@@ -59,11 +57,33 @@
     8 /* hours */ * kMinutesPerHour * kSecondsPerMinute;
 const int MetricsDaemon::kMetricTimeToNetworkDropBuckets = 50;
 
+// crash interval metrics
+const char MetricsDaemon::kMetricKernelCrashIntervalName[] =
+    "Logging.KernelCrashInterval";
+const char MetricsDaemon::kMetricUncleanShutdownIntervalName[] =
+    "Logging.UncleanShutdownInterval";
 const char MetricsDaemon::kMetricUserCrashIntervalName[] =
     "Logging.UserCrashInterval";
-const int MetricsDaemon::kMetricUserCrashIntervalMin = 1;
-const int MetricsDaemon::kMetricUserCrashIntervalMax = 4 * kSecondsPerWeek;
-const int MetricsDaemon::kMetricUserCrashIntervalBuckets = 50;
+
+const int MetricsDaemon::kMetricCrashIntervalMin = 1;
+const int MetricsDaemon::kMetricCrashIntervalMax =
+    4 * kSecondsPerWeek;
+const int MetricsDaemon::kMetricCrashIntervalBuckets = 50;
+
+// crash frequency metrics
+const char MetricsDaemon::kMetricAnyCrashesDailyName[] =
+    "Logging.AnyCrashesDaily";
+const char MetricsDaemon::kMetricKernelCrashesDailyName[] =
+    "Logging.KernelCrashesDaily";
+const char MetricsDaemon::kMetricUncleanShutdownsDailyName[] =
+    "Logging.UncleanShutdownsDaily";
+const char MetricsDaemon::kMetricUserCrashesDailyName[] =
+    "Logging.UserCrashesDaily";
+const char MetricsDaemon::kMetricCrashesDailyMin = 1;
+const char MetricsDaemon::kMetricCrashesDailyMax = 100;
+const char MetricsDaemon::kMetricCrashesDailyBuckets = 50;
+
+
 
 // static
 const char* MetricsDaemon::kDBusMatches_[] = {
@@ -168,8 +188,14 @@
   if (run_as_daemon && daemon(0, 0) != 0)
     return;
 
-  static const char kKernelCrashDetectedFile[] = "/tmp/kernel-crash-detected";
-  CheckKernelCrash(kKernelCrashDetectedFile);
+  if (CheckSystemCrash(kKernelCrashDetectedFile)) {
+    ProcessKernelCrash();
+  }
+
+  if (CheckSystemCrash(kUncleanShutdownDetectedFile)) {
+    ProcessUncleanShutdown();
+  }
+
   Loop();
 }
 
@@ -180,19 +206,57 @@
 
   static const char kDailyUseRecordFile[] = "/var/log/metrics/daily-usage";
   daily_use_.reset(new chromeos_metrics::TaggedCounter());
-  daily_use_->Init(kDailyUseRecordFile, &DailyUseReporter, this);
+  daily_use_->Init(kDailyUseRecordFile, &ReportDailyUse, this);
 
   static const char kUserCrashIntervalRecordFile[] =
       "/var/log/metrics/user-crash-interval";
   user_crash_interval_.reset(new chromeos_metrics::TaggedCounter());
   user_crash_interval_->Init(kUserCrashIntervalRecordFile,
-                             &UserCrashIntervalReporter, this);
+                             &ReportUserCrashInterval, this);
 
   static const char kKernelCrashIntervalRecordFile[] =
       "/var/log/metrics/kernel-crash-interval";
   kernel_crash_interval_.reset(new chromeos_metrics::TaggedCounter());
   kernel_crash_interval_->Init(kKernelCrashIntervalRecordFile,
-                               &KernelCrashIntervalReporter, this);
+                               &ReportKernelCrashInterval, this);
+
+  static const char kUncleanShutdownDetectedFile[] =
+      "/var/log/metrics/unclean-shutdown-interval";
+  unclean_shutdown_interval_.reset(new chromeos_metrics::TaggedCounter());
+  unclean_shutdown_interval_->Init(kUncleanShutdownDetectedFile,
+                                   &ReportUncleanShutdownInterval, this);
+
+  static const char kUserCrashesDailyRecordFile[] =
+      "/var/log/metrics/user-crashes-daily";
+  user_crashes_daily_.reset(new chromeos_metrics::FrequencyCounter());
+  user_crashes_daily_->Init(kUserCrashesDailyRecordFile,
+                            &ReportUserCrashesDaily,
+                            this,
+                            chromeos_metrics::kSecondsPerDay);
+
+  static const char kKernelCrashesDailyRecordFile[] =
+      "/var/log/metrics/kernel-crashes-daily";
+  kernel_crashes_daily_.reset(new chromeos_metrics::FrequencyCounter());
+  kernel_crashes_daily_->Init(kKernelCrashesDailyRecordFile,
+                              &ReportKernelCrashesDaily,
+                              this,
+                              chromeos_metrics::kSecondsPerDay);
+
+  static const char kUncleanShutdownsDailyRecordFile[] =
+      "/var/log/metrics/unclean-shutdowns-daily";
+  unclean_shutdowns_daily_.reset(new chromeos_metrics::FrequencyCounter());
+  unclean_shutdowns_daily_->Init(kUncleanShutdownsDailyRecordFile,
+                                 &ReportUncleanShutdownsDaily,
+                                 this,
+                                 chromeos_metrics::kSecondsPerDay);
+
+  static const char kAnyCrashesUserCrashDailyRecordFile[] =
+      "/var/log/metrics/any-crashes-daily";
+  any_crashes_daily_.reset(new chromeos_metrics::FrequencyCounter());
+  any_crashes_daily_->Init(kAnyCrashesUserCrashDailyRecordFile,
+                           &ReportAnyCrashesDaily,
+                           this,
+                           chromeos_metrics::kSecondsPerDay);
 
   // Don't setup D-Bus and GLib in test mode.
   if (testing)
@@ -408,6 +472,9 @@
 
   // Reports the active use time since the last crash and resets it.
   user_crash_interval_->Flush();
+
+  user_crashes_daily_->Update(1);
+  any_crashes_daily_->Update(1);
 }
 
 void MetricsDaemon::ProcessKernelCrash() {
@@ -416,19 +483,32 @@
 
   // Reports the active use time since the last crash and resets it.
   kernel_crash_interval_->Flush();
+
+  kernel_crashes_daily_->Update(1);
+  any_crashes_daily_->Update(1);
 }
 
-void MetricsDaemon::CheckKernelCrash(const std::string& crash_file) {
+void MetricsDaemon::ProcessUncleanShutdown() {
+  // Counts the active use time up to now.
+  SetUserActiveState(user_active_, Time::Now());
+
+  // Reports the active use time since the last crash and resets it.
+  unclean_shutdown_interval_->Flush();
+
+  unclean_shutdowns_daily_->Update(1);
+  any_crashes_daily_->Update(1);
+}
+
+bool MetricsDaemon::CheckSystemCrash(const std::string& crash_file) {
   FilePath crash_detected(crash_file);
   if (!file_util::PathExists(crash_detected))
-    return;
-
-  ProcessKernelCrash();
+    return false;
 
   // Deletes the crash-detected file so that the daemon doesn't report
   // another kernel crash in case it's restarted.
   file_util::Delete(crash_detected,
                     false);  // recursive
+  return true;
 }
 
 // static
@@ -492,7 +572,7 @@
 }
 
 // static
-void MetricsDaemon::DailyUseReporter(void* handle, int tag, int count) {
+void MetricsDaemon::ReportDailyUse(void* handle, int tag, int count) {
   if (count <= 0)
     return;
 
@@ -505,25 +585,68 @@
 }
 
 // static
-void MetricsDaemon::UserCrashIntervalReporter(void* handle,
-                                              int tag, int count) {
+void MetricsDaemon::ReportCrashInterval(const char* histogram_name,
+                                        void* handle, int count) {
   MetricsDaemon* daemon = static_cast<MetricsDaemon*>(handle);
-  daemon->SendMetric(kMetricUserCrashIntervalName, count,
-                     kMetricUserCrashIntervalMin,
-                     kMetricUserCrashIntervalMax,
-                     kMetricUserCrashIntervalBuckets);
+  daemon->SendMetric(histogram_name, count,
+                     kMetricCrashIntervalMin,
+                     kMetricCrashIntervalMax,
+                     kMetricCrashIntervalBuckets);
 }
 
 // static
-void MetricsDaemon::KernelCrashIntervalReporter(void* handle,
-                                                int tag, int count) {
-  MetricsDaemon* daemon = static_cast<MetricsDaemon*>(handle);
-  daemon->SendMetric(kMetricKernelCrashIntervalName, count,
-                     kMetricKernelCrashIntervalMin,
-                     kMetricKernelCrashIntervalMax,
-                     kMetricKernelCrashIntervalBuckets);
+void MetricsDaemon::ReportUserCrashInterval(void* handle,
+                                            int tag, int count) {
+  ReportCrashInterval(kMetricUserCrashIntervalName, handle, count);
 }
 
+// static
+void MetricsDaemon::ReportKernelCrashInterval(void* handle,
+                                                int tag, int count) {
+  ReportCrashInterval(kMetricKernelCrashIntervalName, handle, count);
+}
+
+// static
+void MetricsDaemon::ReportUncleanShutdownInterval(void* handle,
+                                                    int tag, int count) {
+  ReportCrashInterval(kMetricUncleanShutdownIntervalName, handle, count);
+}
+
+// static
+void MetricsDaemon::ReportCrashesDailyFrequency(const char* histogram_name,
+                                                void* handle,
+                                                int count) {
+  MetricsDaemon* daemon = static_cast<MetricsDaemon*>(handle);
+  daemon->SendMetric(histogram_name, count,
+                     kMetricCrashesDailyMin,
+                     kMetricCrashesDailyMax,
+                     kMetricCrashesDailyBuckets);
+}
+
+// static
+void MetricsDaemon::ReportUserCrashesDaily(void* handle,
+                                           int tag, int count) {
+  ReportCrashesDailyFrequency(kMetricUserCrashesDailyName, handle, count);
+}
+
+// static
+void MetricsDaemon::ReportKernelCrashesDaily(void* handle,
+                                             int tag, int count) {
+  ReportCrashesDailyFrequency(kMetricKernelCrashesDailyName, handle, count);
+}
+
+// static
+void MetricsDaemon::ReportUncleanShutdownsDaily(void* handle,
+                                                int tag, int count) {
+  ReportCrashesDailyFrequency(kMetricUncleanShutdownsDailyName, handle, count);
+}
+
+// static
+void MetricsDaemon::ReportAnyCrashesDaily(void* handle, int tag, int count) {
+  ReportCrashesDailyFrequency(kMetricAnyCrashesDailyName, handle, count);
+}
+
+
 void MetricsDaemon::SendMetric(const string& name, int sample,
                                int min, int max, int nbuckets) {
   DLOG(INFO) << "received metric: " << name << " " << sample << " "
diff --git a/metrics/metrics_daemon.h b/metrics/metrics_daemon.h
index 437cafd..f98c34c 100644
--- a/metrics/metrics_daemon.h
+++ b/metrics/metrics_daemon.h
@@ -14,7 +14,10 @@
 
 #include "metrics_library.h"
 
-namespace chromeos_metrics { class TaggedCounterInterface; }
+namespace chromeos_metrics {
+class FrequencyCounter;
+class TaggedCounterInterface;
+}
 
 class MetricsDaemon {
 
@@ -31,9 +34,7 @@
 
  private:
   friend class MetricsDaemonTest;
-  FRIEND_TEST(MetricsDaemonTest, CheckKernelCrash);
-  FRIEND_TEST(MetricsDaemonTest, DailyUseReporter);
-  FRIEND_TEST(MetricsDaemonTest, KernelCrashIntervalReporter);
+  FRIEND_TEST(MetricsDaemonTest, CheckSystemCrash);
   FRIEND_TEST(MetricsDaemonTest, LookupNetworkState);
   FRIEND_TEST(MetricsDaemonTest, LookupPowerState);
   FRIEND_TEST(MetricsDaemonTest, LookupScreenSaverState);
@@ -43,13 +44,18 @@
   FRIEND_TEST(MetricsDaemonTest, NetStateChangedSuspend);
   FRIEND_TEST(MetricsDaemonTest, PowerStateChanged);
   FRIEND_TEST(MetricsDaemonTest, ProcessKernelCrash);
+  FRIEND_TEST(MetricsDaemonTest, ProcessUncleanShutdown);
   FRIEND_TEST(MetricsDaemonTest, ProcessUserCrash);
+  FRIEND_TEST(MetricsDaemonTest, ReportCrashesDailyFrequency);
+  FRIEND_TEST(MetricsDaemonTest, ReportDailyUse);
+  FRIEND_TEST(MetricsDaemonTest, ReportKernelCrashInterval);
+  FRIEND_TEST(MetricsDaemonTest, ReportUncleanShutdownInterval);
+  FRIEND_TEST(MetricsDaemonTest, ReportUserCrashInterval);
   FRIEND_TEST(MetricsDaemonTest, ScreenSaverStateChanged);
   FRIEND_TEST(MetricsDaemonTest, SendMetric);
   FRIEND_TEST(MetricsDaemonTest, SessionStateChanged);
   FRIEND_TEST(MetricsDaemonTest, SetUserActiveState);
   FRIEND_TEST(MetricsDaemonTest, SetUserActiveStateTimeJump);
-  FRIEND_TEST(MetricsDaemonTest, UserCrashIntervalReporter);
 
   // The network states (see network_states.h).
   enum NetworkState {
@@ -84,22 +90,27 @@
   };
 
   // Metric parameters.
+  static const char kMetricAnyCrashesDailyName[];
+  static const char kMetricCrashesDailyBuckets;
+  static const char kMetricCrashesDailyMax;
+  static const char kMetricCrashesDailyMin;
+  static const int  kMetricCrashIntervalBuckets;
+  static const int  kMetricCrashIntervalMax;
+  static const int  kMetricCrashIntervalMin;
+  static const int  kMetricDailyUseTimeBuckets;
+  static const int  kMetricDailyUseTimeMax;
+  static const int  kMetricDailyUseTimeMin;
   static const char kMetricDailyUseTimeName[];
-  static const int kMetricDailyUseTimeMin;
-  static const int kMetricDailyUseTimeMax;
-  static const int kMetricDailyUseTimeBuckets;
+  static const char kMetricKernelCrashesDailyName[];
   static const char kMetricKernelCrashIntervalName[];
-  static const int kMetricKernelCrashIntervalMin;
-  static const int kMetricKernelCrashIntervalMax;
-  static const int kMetricKernelCrashIntervalBuckets;
+  static const int  kMetricTimeToNetworkDropBuckets;
+  static const int  kMetricTimeToNetworkDropMax;
+  static const int  kMetricTimeToNetworkDropMin;
   static const char kMetricTimeToNetworkDropName[];
-  static const int kMetricTimeToNetworkDropMin;
-  static const int kMetricTimeToNetworkDropMax;
-  static const int kMetricTimeToNetworkDropBuckets;
+  static const char kMetricUncleanShutdownIntervalName[];
+  static const char kMetricUncleanShutdownsDailyName[];
+  static const char kMetricUserCrashesDailyName[];
   static const char kMetricUserCrashIntervalName[];
-  static const int kMetricUserCrashIntervalMin;
-  static const int kMetricUserCrashIntervalMax;
-  static const int kMetricUserCrashIntervalBuckets;
 
   // D-Bus message match strings.
   static const char* kDBusMatches_[];
@@ -162,10 +173,14 @@
   // Updates the active use time and logs time between kernel crashes.
   void ProcessKernelCrash();
 
-  // Checks if a kernel crash has been detected and processes if so.
-  // The method assumes that a kernel crash has happened if
-  // |crash_file| exists.
-  void CheckKernelCrash(const std::string& crash_file);
+  // Updates the active use time and logs time between unclean shutdowns.
+  void ProcessUncleanShutdown();
+
+  // Checks if a kernel crash has been detected and returns true if
+  // so.  The method assumes that a kernel crash has happened if
+  // |crash_file| exists.  It removes the file immediately if it
+  // exists, so it must not be called more than once.
+  bool CheckSystemCrash(const std::string& crash_file);
 
   // Callbacks for the daily use monitor. The daily use monitor uses
   // LogDailyUseRecord to aggregate current usage data and send it to
@@ -196,15 +211,39 @@
 
   // TaggedCounter callback to process aggregated daily usage data and
   // send to UMA.
-  static void DailyUseReporter(void* data, int tag, int count);
+  static void ReportDailyUse(void* data, int tag, int count);
+
+  // Helper to report a crash interval to UMA.
+  static void ReportCrashInterval(const char* histogram_name,
+                                  void* handle, int count);
 
   // TaggedCounter callback to process time between user-space process
   // crashes and send to UMA.
-  static void UserCrashIntervalReporter(void* data, int tag, int count);
+  static void ReportUserCrashInterval(void* data, int tag, int count);
 
   // TaggedCounter callback to process time between kernel crashes and
   // send to UMA.
-  static void KernelCrashIntervalReporter(void* data, int tag, int count);
+  static void ReportKernelCrashInterval(void* data, int tag, int count);
+
+  // TaggedCounter callback to process time between unclean shutdowns and
+  // send to UMA.
+  static void ReportUncleanShutdownInterval(void* data, int tag, int count);
+
+  // Helper to report a daily crash frequency to UMA.
+  static void ReportCrashesDailyFrequency(const char* histogram_name,
+                                          void* handle, int count);
+
+  // TaggedCounter callback to report daily crash frequency to UMA.
+  static void ReportUserCrashesDaily(void* handle, int tag, int count);
+
+  // TaggedCounter callback to report kernel crash frequency to UMA.
+  static void ReportKernelCrashesDaily(void* handle, int tag, int count);
+
+  // TaggedCounter callback to report unclean shutdown frequency to UMA.
+  static void ReportUncleanShutdownsDaily(void* handle, int tag, int count);
+
+  // TaggedCounter callback to report frequency of any crashes to UMA.
+  static void ReportAnyCrashesDaily(void* handle, int tag, int count);
 
   // Test mode.
   bool testing_;
@@ -244,6 +283,23 @@
   // Active use time between kernel crashes.
   scoped_ptr<chromeos_metrics::TaggedCounterInterface> kernel_crash_interval_;
 
+  // Active use time between unclean shutdowns crashes.
+  scoped_ptr<chromeos_metrics::TaggedCounterInterface>
+      unclean_shutdown_interval_;
+
+  // Daily count of user-space process crashes.
+  scoped_ptr<chromeos_metrics::FrequencyCounter> user_crashes_daily_;
+
+  // Daily count of kernel crashes.
+  scoped_ptr<chromeos_metrics::FrequencyCounter> kernel_crashes_daily_;
+
+  // Daily count of unclean shutdowns.
+  scoped_ptr<chromeos_metrics::FrequencyCounter> unclean_shutdowns_daily_;
+
+  // Daily count of any crashes (user-space processes, kernel, or
+  // unclean shutdowns).
+  scoped_ptr<chromeos_metrics::FrequencyCounter> any_crashes_daily_;
+
   // Sleep period until the next daily usage aggregation performed by
   // the daily use monitor (see ScheduleUseMonitor).
   int usemon_interval_;
diff --git a/metrics/metrics_daemon_test.cc b/metrics/metrics_daemon_test.cc
index e75c161..e551cf9 100644
--- a/metrics/metrics_daemon_test.cc
+++ b/metrics/metrics_daemon_test.cc
@@ -11,6 +11,7 @@
 
 using base::Time;
 using base::TimeTicks;
+using chromeos_metrics::FrequencyCounterMock;
 using chromeos_metrics::TaggedCounterMock;
 using ::testing::_;
 using ::testing::Return;
@@ -59,6 +60,16 @@
     daemon_.kernel_crash_interval_.reset(kernel_crash_interval_);
     user_crash_interval_ = new StrictMock<TaggedCounterMock>();
     daemon_.user_crash_interval_.reset(user_crash_interval_);
+    unclean_shutdown_interval_ = new StrictMock<TaggedCounterMock>();
+    daemon_.unclean_shutdown_interval_.reset(unclean_shutdown_interval_);
+    kernel_crashes_daily_ = new StrictMock<FrequencyCounterMock>();
+    daemon_.kernel_crashes_daily_.reset(kernel_crashes_daily_);
+    user_crashes_daily_ = new StrictMock<FrequencyCounterMock>();
+    daemon_.user_crashes_daily_.reset(user_crashes_daily_);
+    unclean_shutdowns_daily_ = new StrictMock<FrequencyCounterMock>();
+    daemon_.unclean_shutdowns_daily_.reset(unclean_shutdowns_daily_);
+    any_crashes_daily_ = new StrictMock<FrequencyCounterMock>();
+    daemon_.any_crashes_daily_.reset(any_crashes_daily_);
 
     EXPECT_FALSE(daemon_.user_active_);
     EXPECT_TRUE(daemon_.user_active_last_.is_null());
@@ -172,40 +183,54 @@
   StrictMock<TaggedCounterMock>* daily_use_;
   StrictMock<TaggedCounterMock>* kernel_crash_interval_;
   StrictMock<TaggedCounterMock>* user_crash_interval_;
+  StrictMock<TaggedCounterMock>* unclean_shutdown_interval_;
+
+  StrictMock<FrequencyCounterMock>* kernel_crashes_daily_;
+  StrictMock<FrequencyCounterMock>* user_crashes_daily_;
+  StrictMock<FrequencyCounterMock>* unclean_shutdowns_daily_;
+  StrictMock<FrequencyCounterMock>* any_crashes_daily_;
 };
 
-TEST_F(MetricsDaemonTest, CheckKernelCrash) {
+TEST_F(MetricsDaemonTest, CheckSystemCrash) {
   static const char kKernelCrashDetected[] = "test-kernel-crash-detected";
-  daemon_.CheckKernelCrash(kKernelCrashDetected);
+  EXPECT_FALSE(daemon_.CheckSystemCrash(kKernelCrashDetected));
 
   FilePath crash_detected(kKernelCrashDetected);
   file_util::WriteFile(crash_detected, "", 0);
-  IgnoreActiveUseUpdate();
-  EXPECT_CALL(*kernel_crash_interval_, Flush())
-      .Times(1)
-      .RetiresOnSaturation();
-  daemon_.CheckKernelCrash(kKernelCrashDetected);
+  EXPECT_TRUE(file_util::PathExists(crash_detected));
+  EXPECT_TRUE(daemon_.CheckSystemCrash(kKernelCrashDetected));
+  EXPECT_FALSE(file_util::PathExists(crash_detected));
+  EXPECT_FALSE(daemon_.CheckSystemCrash(kKernelCrashDetected));
+  EXPECT_FALSE(file_util::PathExists(crash_detected));
   file_util::Delete(crash_detected, false);
 }
 
-TEST_F(MetricsDaemonTest, DailyUseReporter) {
+TEST_F(MetricsDaemonTest, ReportDailyUse) {
   ExpectDailyUseTimeMetric(/* sample */ 2);
-  MetricsDaemon::DailyUseReporter(&daemon_, /* tag */ 20, /* count */ 90);
+  MetricsDaemon::ReportDailyUse(&daemon_, /* tag */ 20, /* count */ 90);
 
   ExpectDailyUseTimeMetric(/* sample */ 1);
-  MetricsDaemon::DailyUseReporter(&daemon_, /* tag */ 23, /* count */ 89);
+  MetricsDaemon::ReportDailyUse(&daemon_, /* tag */ 23, /* count */ 89);
 
   // There should be no metrics generated for the calls below.
-  MetricsDaemon::DailyUseReporter(&daemon_, /* tag */ 50, /* count */ 0);
-  MetricsDaemon::DailyUseReporter(&daemon_, /* tag */ 60, /* count */ -5);
+  MetricsDaemon::ReportDailyUse(&daemon_, /* tag */ 50, /* count */ 0);
+  MetricsDaemon::ReportDailyUse(&daemon_, /* tag */ 60, /* count */ -5);
 }
 
-TEST_F(MetricsDaemonTest, KernelCrashIntervalReporter) {
+TEST_F(MetricsDaemonTest, ReportKernelCrashInterval) {
   ExpectMetric(MetricsDaemon::kMetricKernelCrashIntervalName, 50,
-               MetricsDaemon::kMetricKernelCrashIntervalMin,
-               MetricsDaemon::kMetricKernelCrashIntervalMax,
-               MetricsDaemon::kMetricKernelCrashIntervalBuckets);
-  MetricsDaemon::KernelCrashIntervalReporter(&daemon_, 0, 50);
+               MetricsDaemon::kMetricCrashIntervalMin,
+               MetricsDaemon::kMetricCrashIntervalMax,
+               MetricsDaemon::kMetricCrashIntervalBuckets);
+  MetricsDaemon::ReportKernelCrashInterval(&daemon_, 0, 50);
+}
+
+TEST_F(MetricsDaemonTest, ReportUncleanShutdownInterval) {
+  ExpectMetric(MetricsDaemon::kMetricUncleanShutdownIntervalName, 50,
+               MetricsDaemon::kMetricCrashIntervalMin,
+               MetricsDaemon::kMetricCrashIntervalMax,
+               MetricsDaemon::kMetricCrashIntervalBuckets);
+  MetricsDaemon::ReportUncleanShutdownInterval(&daemon_, 0, 50);
 }
 
 TEST_F(MetricsDaemonTest, LookupNetworkState) {
@@ -246,6 +271,12 @@
   EXPECT_CALL(*user_crash_interval_, Flush())
       .Times(1)
       .RetiresOnSaturation();
+  EXPECT_CALL(*user_crashes_daily_, Update(1))
+      .Times(1)
+      .RetiresOnSaturation();
+  EXPECT_CALL(*any_crashes_daily_, Update(1))
+      .Times(1)
+      .RetiresOnSaturation();
   msg = NewDBusSignalString("/",
                             "org.chromium.CrashReporter",
                             "UserCrash",
@@ -379,14 +410,28 @@
   EXPECT_CALL(*kernel_crash_interval_, Flush())
       .Times(1)
       .RetiresOnSaturation();
+  EXPECT_CALL(*kernel_crashes_daily_, Update(1));
+  EXPECT_CALL(*any_crashes_daily_, Update(1));
   daemon_.ProcessKernelCrash();
 }
 
+TEST_F(MetricsDaemonTest, ProcessUncleanShutdown) {
+  IgnoreActiveUseUpdate();
+  EXPECT_CALL(*unclean_shutdown_interval_, Flush())
+      .Times(1)
+      .RetiresOnSaturation();
+  EXPECT_CALL(*unclean_shutdowns_daily_, Update(1));
+  EXPECT_CALL(*any_crashes_daily_, Update(1));
+  daemon_.ProcessUncleanShutdown();
+}
+
 TEST_F(MetricsDaemonTest, ProcessUserCrash) {
   IgnoreActiveUseUpdate();
   EXPECT_CALL(*user_crash_interval_, Flush())
       .Times(1)
       .RetiresOnSaturation();
+  EXPECT_CALL(*user_crashes_daily_, Update(1));
+  EXPECT_CALL(*any_crashes_daily_, Update(1));
   daemon_.ProcessUserCrash();
 }
 
@@ -469,12 +514,20 @@
   EXPECT_EQ(TestTime(10 * kSecondsPerDay + 1000), daemon_.user_active_last_);
 }
 
-TEST_F(MetricsDaemonTest, UserCrashIntervalReporter) {
+TEST_F(MetricsDaemonTest, ReportUserCrashInterval) {
   ExpectMetric(MetricsDaemon::kMetricUserCrashIntervalName, 50,
-               MetricsDaemon::kMetricUserCrashIntervalMin,
-               MetricsDaemon::kMetricUserCrashIntervalMax,
-               MetricsDaemon::kMetricUserCrashIntervalBuckets);
-  MetricsDaemon::UserCrashIntervalReporter(&daemon_, 0, 50);
+               MetricsDaemon::kMetricCrashIntervalMin,
+               MetricsDaemon::kMetricCrashIntervalMax,
+               MetricsDaemon::kMetricCrashIntervalBuckets);
+  MetricsDaemon::ReportUserCrashInterval(&daemon_, 0, 50);
+}
+
+TEST_F(MetricsDaemonTest, ReportCrashesDailyFrequency) {
+  ExpectMetric("foobar", 50,
+               MetricsDaemon::kMetricCrashesDailyMin,
+               MetricsDaemon::kMetricCrashesDailyMax,
+               MetricsDaemon::kMetricCrashesDailyBuckets);
+  MetricsDaemon::ReportCrashesDailyFrequency("foobar", &daemon_, 50);
 }
 
 int main(int argc, char** argv) {