metrics: Emit kAbnormalTermination if last update attempt failed.

This allows us to track how many update attempts terminates
abnormally, for example if the device is rebooted in the middle of an
update or if update_engine crashes. We use a marker state variable
(aka a "prefs" file) to keep track of this.

Note that we don't currently report any of the other metrics in the
UpdateEngine.Attempt.* namespace. If necessary, this can be changed in
the future - I left a TODO item in the code with more details.

BUG=chromium:357676
TEST=New unit tests + Unit tests pass + Manual tests.

Change-Id: I83fe284c7c46917c0c55b92314c58098e2fd1789
Reviewed-on: https://chromium-review.googlesource.com/197175
Reviewed-by: Alex Deymo <deymo@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 c176238..975ba15 100644
--- a/payload_state.cc
+++ b/payload_state.cc
@@ -162,6 +162,9 @@
 }
 
 void PayloadState::AttemptStarted(AttemptType attempt_type) {
+  // Flush previous state from abnormal attempt failure, if any.
+  ReportAndClearPersistedAttemptMetrics();
+
   attempt_type_ = attempt_type;
 
   ClockInterface *clock = system_state_->clock();
@@ -183,6 +186,9 @@
     type = utils::GetConnectionType(network_connection_type, tethering);
   }
   attempt_connection_type_ = type;
+
+  if (attempt_type == AttemptType::kUpdate)
+    PersistAttemptMetrics();
 }
 
 void PayloadState::UpdateResumed() {
@@ -207,6 +213,7 @@
     case AttemptType::kUpdate:
       CollectAndReportAttemptMetrics(kErrorCodeSuccess);
       CollectAndReportSuccessfulUpdateMetrics();
+      ClearPersistedAttemptMetrics();
       break;
 
     case AttemptType::kRollback:
@@ -238,6 +245,7 @@
   switch (attempt_type_) {
     case AttemptType::kUpdate:
       CollectAndReportAttemptMetrics(base_error);
+      ClearPersistedAttemptMetrics();
       break;
 
     case AttemptType::kRollback:
@@ -629,6 +637,33 @@
                                       attempt_connection_type_);
 }
 
+void PayloadState::PersistAttemptMetrics() {
+  // TODO(zeuthen): For now we only persist whether an attempt was in
+  // progress and not values/metrics related to the attempt. This
+  // means that when this happens, of all the UpdateEngine.Attempt.*
+  // metrics, only UpdateEngine.Attempt.Result is reported (with the
+  // value |kAbnormalTermination|). In the future we might want to
+  // persist more data so we can report other metrics in the
+  // UpdateEngine.Attempt.* namespace when this happens.
+  prefs_->SetBoolean(kPrefsAttemptInProgress, true);
+}
+
+void PayloadState::ClearPersistedAttemptMetrics() {
+  prefs_->Delete(kPrefsAttemptInProgress);
+}
+
+void PayloadState::ReportAndClearPersistedAttemptMetrics() {
+  bool attempt_in_progress = false;
+  if (!prefs_->GetBoolean(kPrefsAttemptInProgress, &attempt_in_progress))
+    return;
+  if (!attempt_in_progress)
+    return;
+
+  metrics::ReportAbnormallyTerminatedUpdateAttemptMetrics(system_state_);
+
+  ClearPersistedAttemptMetrics();
+}
+
 void PayloadState::CollectAndReportSuccessfulUpdateMetrics() {
   string metric;
 
@@ -1316,6 +1351,9 @@
 }
 
 void PayloadState::UpdateEngineStarted() {
+  // Flush previous state from abnormal attempt failure, if any.
+  ReportAndClearPersistedAttemptMetrics();
+
   // Avoid the UpdateEngineStarted actions if this is not the first time we
   // run the update engine since reboot.
   if (!system_state_->system_rebooted())