Add Installer.UpdatesAbandonedCount metric

This patch adds a new metric Installer.UpdatesAbandonedCount to track
the number of update attempts that didn't complete because a newer
update was detected during the download. This is implemented by
counting the number of different responses seen since the last
successful update.

Updates are typically only abandoned if a device is suspended or
powered off while an update is happening. This can happen either
because the device was not turned on for a very long time or because
it had little or no connectivity to Omaha and/or the servers serving
the payload.

This metric will help show how many users run into this problem.

BUG=chromium:248800
TEST=New units tests + Unit tests pass + Manually tested

Change-Id: I524a380a931c2fb30916d033b7e5b0c700f57103
Reviewed-on: https://gerrit.chromium.org/gerrit/59098
Reviewed-by: Chris Sosa <sosa@chromium.org>
Tested-by: David Zeuthen <zeuthen@chromium.org>
Commit-Queue: David Zeuthen <zeuthen@chromium.org>
diff --git a/payload_state.cc b/payload_state.cc
index 0636f56..b804822 100644
--- a/payload_state.cc
+++ b/payload_state.cc
@@ -60,6 +60,7 @@
     LoadTotalBytesDownloaded(source);
   }
   LoadNumReboots();
+  LoadNumResponsesSeen();
   return true;
 }
 
@@ -82,6 +83,7 @@
   // clear away all the existing state.
   if (has_response_changed) {
     LOG(INFO) << "Resetting all persisted state as this is a new response";
+    SetNumResponsesSeen(num_responses_seen_ + 1);
     SetResponseSignature(new_response_signature);
     ResetPersistedState();
     return;
@@ -151,6 +153,11 @@
   ReportUpdateUrlSwitchesMetric();
   ReportRebootMetrics();
   ReportDurationMetrics();
+  ReportUpdatesAbandonedCountMetric();
+
+  // Reset the number of responses seen since it counts from the last
+  // successful update, e.g. now.
+  SetNumResponsesSeen(0);
 }
 
 void PayloadState::UpdateFailed(ErrorCode error) {
@@ -883,6 +890,30 @@
                     << GetTotalBytesDownloaded(source);
 }
 
+void PayloadState::LoadNumResponsesSeen() {
+  SetNumResponsesSeen(GetPersistedValue(kPrefsNumResponsesSeen));
+}
+
+void PayloadState::SetNumResponsesSeen(int num_responses_seen) {
+  CHECK(prefs_);
+  num_responses_seen_ = num_responses_seen;
+  LOG(INFO) << "Num Responses Seen = " << num_responses_seen_;
+  prefs_->SetInt64(kPrefsNumResponsesSeen, num_responses_seen_);
+}
+
+void PayloadState::ReportUpdatesAbandonedCountMetric() {
+  string metric = "Installer.UpdatesAbandonedCount";
+  int value = num_responses_seen_ - 1;
+
+  LOG(INFO) << "Uploading " << value << " (count) for metric " <<  metric;
+  system_state_->metrics_lib()->SendToUMA(
+       metric,
+       value,
+       0,    // min value
+       100,  // max value
+       kNumDefaultUmaBuckets);
+}
+
 void PayloadState::ComputeCandidateUrls() {
   bool http_url_ok = false;