update_engine: Add UMA stats for rollback

Adding the following UMA stats:
- UpdateEngine.Check.TargetVersion: first section of the Chrome OS
  target version set by device policy. Sent during update checks if
  target version policy is set.
- UpdateEngine.Check.RollbackTargetVersion: first section of the
  Chrome OS target version if rollback is also allowed. Sent during
  update checks if both policies are set.
- UpdateEngine.EnterpriseRollback.Success: first section of the
  Chrome OS version to which rollback succeeded. Sent after
  successful installation of the rollback image.
- UpdateEngine.EnterpriseRollback.Failure: first section of the
  Chrome OS version to which rollback failed. Sent after
  installation of the rollback image failed.

Chromium CL of the new histograms: crrev.com/c/1069129

BUG=chromium:843622
TEST='cros_run_unit_tests --board=caroline --packages update_engine'

Change-Id: I0b76fa286498ae0a1830a90034734ed9aa5efd3d
Reviewed-on: https://chromium-review.googlesource.com/1062033
Commit-Ready: ChromeOS CL Exonerator Bot <[email protected]>
Tested-by: Marton Hunyady <[email protected]>
Reviewed-by: Amin Hassani <[email protected]>
Reviewed-by: Jesse Doherty <[email protected]>
diff --git a/common/utils.cc b/common/utils.cc
index f651823..68cad51 100644
--- a/common/utils.cc
+++ b/common/utils.cc
@@ -291,7 +291,10 @@
   return true;
 }
 
-bool PReadAll(const FileDescriptorPtr& fd, void* buf, size_t count, off_t offset,
+bool PReadAll(const FileDescriptorPtr& fd,
+              void* buf,
+              size_t count,
+              off_t offset,
               ssize_t* out_bytes_read) {
   TEST_AND_RETURN_FALSE_ERRNO(fd->Seek(offset, SEEK_SET) !=
                               static_cast<off_t>(-1));
@@ -1067,6 +1070,18 @@
   return true;
 }
 
+int VersionPrefix(const std::string& version) {
+  if (version.empty()) {
+    return 0;
+  }
+  vector<string> tokens = base::SplitString(
+      version, ".", base::KEEP_WHITESPACE, base::SPLIT_WANT_ALL);
+  int value;
+  if (tokens.empty() || !base::StringToInt(tokens[0], &value))
+    return -1;  // Target version is invalid.
+  return value;
+}
+
 }  // namespace utils
 
 }  // namespace chromeos_update_engine
diff --git a/common/utils.h b/common/utils.h
index c102a16..8db0cf8 100644
--- a/common/utils.h
+++ b/common/utils.h
@@ -317,6 +317,11 @@
 // reboot. Returns whether it succeeded getting the boot_id.
 bool GetBootId(std::string* boot_id);
 
+// Returns the integer value of the first section of |version|. E.g. for
+//  "10575.39." returns 10575. Returns 0 if |version| is empty, returns -1 if
+// first section of |version| is invalid (e.g. not a number).
+int VersionPrefix(const std::string& version);
+
 }  // namespace utils
 
 
diff --git a/common/utils_unittest.cc b/common/utils_unittest.cc
index 033702b..16fa481 100644
--- a/common/utils_unittest.cc
+++ b/common/utils_unittest.cc
@@ -511,4 +511,16 @@
   EXPECT_FALSE(utils::IsMountpoint(file.value()));
 }
 
+TEST(UtilsTest, VersionPrefix) {
+  EXPECT_EQ(10575, utils::VersionPrefix("10575.39."));
+  EXPECT_EQ(10575, utils::VersionPrefix("10575.39"));
+  EXPECT_EQ(10575, utils::VersionPrefix("10575.x"));
+  EXPECT_EQ(10575, utils::VersionPrefix("10575."));
+  EXPECT_EQ(10575, utils::VersionPrefix("10575"));
+  EXPECT_EQ(0, utils::VersionPrefix(""));
+  EXPECT_EQ(-1, utils::VersionPrefix("x"));
+  EXPECT_EQ(-1, utils::VersionPrefix("1x"));
+  EXPECT_EQ(-1, utils::VersionPrefix("x.1"));
+}
+
 }  // namespace chromeos_update_engine
diff --git a/metrics_reporter_android.h b/metrics_reporter_android.h
index 44f770e..06ad8c5 100644
--- a/metrics_reporter_android.h
+++ b/metrics_reporter_android.h
@@ -17,6 +17,8 @@
 #ifndef UPDATE_ENGINE_METRICS_REPORTER_ANDROID_H_
 #define UPDATE_ENGINE_METRICS_REPORTER_ANDROID_H_
 
+#include <string>
+
 #include "update_engine/common/error_code.h"
 #include "update_engine/metrics_constants.h"
 #include "update_engine/metrics_reporter_interface.h"
@@ -33,6 +35,9 @@
 
   void ReportRollbackMetrics(metrics::RollbackResult result) override {}
 
+  void ReportEnterpriseRollbackMetrics(
+      bool success, const std::string& rollback_version) override {}
+
   void ReportDailyMetrics(base::TimeDelta os_age) override {}
 
   void ReportUpdateCheckMetrics(
diff --git a/metrics_reporter_interface.h b/metrics_reporter_interface.h
index 13f5a54..8a7c864 100644
--- a/metrics_reporter_interface.h
+++ b/metrics_reporter_interface.h
@@ -18,6 +18,7 @@
 #define UPDATE_ENGINE_METRICS_REPORTER_INTERFACE_H_
 
 #include <memory>
+#include <string>
 
 #include <base/time/time.h>
 
@@ -43,12 +44,20 @@
 
   virtual void Initialize() = 0;
 
-  // Helper function to report metrics related to rollback. The
+  // Helper function to report metrics related to user-initiated rollback. The
   // following metrics are reported:
   //
   //  |kMetricRollbackResult|
   virtual void ReportRollbackMetrics(metrics::RollbackResult result) = 0;
 
+  // Helper function to report metrics related to enterprise (admin-initiated)
+  // rollback:
+  //
+  //  |kMetricEnterpriseRollbackSuccess|
+  //  |kMetricEnterpriseRollbackFailure|
+  virtual void ReportEnterpriseRollbackMetrics(
+      bool success, const std::string& rollback_version) = 0;
+
   // Helper function to report metrics reported once a day. The
   // following metrics are reported:
   //
@@ -64,6 +73,8 @@
   //  |kMetricCheckDownloadErrorCode|
   //  |kMetricCheckTimeSinceLastCheckMinutes|
   //  |kMetricCheckTimeSinceLastCheckUptimeMinutes|
+  //  |kMetricCheckTargetVersion|
+  //  |kMetricCheckRollbackTargetVersion|
   //
   // The |kMetricCheckResult| metric will only be reported if |result|
   // is not |kUnset|.
@@ -78,6 +89,10 @@
   // |kMetricCheckTimeSinceLastCheckUptimeMinutes| metrics are
   // automatically reported and calculated by maintaining persistent
   // and process-local state variables.
+  //
+  // |kMetricCheckTargetVersion| reports the first section of the target version
+  // if it's set, |kMetricCheckRollbackTargetVersion| reports the same, but only
+  // if rollback is also allowed using enterprise policy.
   virtual void ReportUpdateCheckMetrics(
       SystemState* system_state,
       metrics::CheckResult result,
diff --git a/metrics_reporter_omaha.cc b/metrics_reporter_omaha.cc
index 9c81088..0a2b674 100644
--- a/metrics_reporter_omaha.cc
+++ b/metrics_reporter_omaha.cc
@@ -17,9 +17,9 @@
 #include "update_engine/metrics_reporter_omaha.h"
 
 #include <memory>
-#include <string>
 
 #include <base/logging.h>
+#include <base/strings/string_number_conversions.h>
 #include <metrics/metrics_library.h>
 
 #include "update_engine/common/clock_interface.h"
@@ -27,6 +27,7 @@
 #include "update_engine/common/prefs_interface.h"
 #include "update_engine/common/utils.h"
 #include "update_engine/metrics_utils.h"
+#include "update_engine/omaha_request_params.h"
 #include "update_engine/system_state.h"
 
 using std::string;
@@ -43,6 +44,9 @@
     "UpdateEngine.Check.DownloadErrorCode";
 const char kMetricCheckReaction[] = "UpdateEngine.Check.Reaction";
 const char kMetricCheckResult[] = "UpdateEngine.Check.Result";
+const char kMetricCheckTargetVersion[] = "UpdateEngine.Check.TargetVersion";
+const char kMetricCheckRollbackTargetVersion[] =
+    "UpdateEngine.Check.RollbackTargetVersion";
 const char kMetricCheckTimeSinceLastCheckMinutes[] =
     "UpdateEngine.Check.TimeSinceLastCheckMinutes";
 const char kMetricCheckTimeSinceLastCheckUptimeMinutes[] =
@@ -100,6 +104,12 @@
 // UpdateEngine.Rollback.* metric.
 const char kMetricRollbackResult[] = "UpdateEngine.Rollback.Result";
 
+// UpdateEngine.EnterpriseRollback.* metrics.
+const char kMetricEnterpriseRollbackFailure[] =
+    "UpdateEngine.EnterpriseRollback.Failure";
+const char kMetricEnterpriseRollbackSuccess[] =
+    "UpdateEngine.EnterpriseRollback.Success";
+
 // UpdateEngine.CertificateCheck.* metrics.
 const char kMetricCertificateCheckUpdateCheck[] =
     "UpdateEngine.CertificateCheck.UpdateCheck";
@@ -194,6 +204,25 @@
                             30 * 24 * 60,  // max: 30 days
                             50);           // num_buckets
   }
+
+  // First section of target version specified for the update.
+  if (system_state && system_state->request_params()) {
+    string target_version =
+        system_state->request_params()->target_version_prefix();
+    value = utils::VersionPrefix(target_version);
+    if (value != 0) {
+      metric = metrics::kMetricCheckTargetVersion;
+      LOG(INFO) << "Sending " << value << " for metric " << metric
+                << " (sparse)";
+      metrics_lib_->SendSparseToUMA(metric, value);
+      if (system_state->request_params()->rollback_allowed()) {
+        metric = metrics::kMetricCheckRollbackTargetVersion;
+        LOG(INFO) << "Sending " << value << " for metric " << metric
+                  << " (sparse)";
+        metrics_lib_->SendSparseToUMA(metric, value);
+      }
+    }
+  }
 }
 
 void MetricsReporterOmaha::ReportAbnormallyTerminatedUpdateAttemptMetrics() {
@@ -478,6 +507,16 @@
       metric, value, static_cast<int>(metrics::RollbackResult::kNumConstants));
 }
 
+void MetricsReporterOmaha::ReportEnterpriseRollbackMetrics(
+    bool success, const string& rollback_version) {
+  int value = utils::VersionPrefix(rollback_version);
+  string metric = metrics::kMetricEnterpriseRollbackSuccess;
+  if (!success)
+    metric = metrics::kMetricEnterpriseRollbackFailure;
+  LOG(INFO) << "Sending " << value << " for metric " << metric;
+  metrics_lib_->SendSparseToUMA(metric, value);
+}
+
 void MetricsReporterOmaha::ReportCertificateCheckMetrics(
     ServerToCheck server_to_check, CertificateCheckResult result) {
   string metric;
diff --git a/metrics_reporter_omaha.h b/metrics_reporter_omaha.h
index 344cff8..97b283d 100644
--- a/metrics_reporter_omaha.h
+++ b/metrics_reporter_omaha.h
@@ -18,6 +18,7 @@
 #define UPDATE_ENGINE_METRICS_REPORTER_OMAHA_H_
 
 #include <memory>
+#include <string>
 
 #include <base/time/time.h>
 #include <metrics/metrics_library.h>
@@ -42,6 +43,8 @@
 extern const char kMetricCheckDownloadErrorCode[];
 extern const char kMetricCheckReaction[];
 extern const char kMetricCheckResult[];
+extern const char kMetricCheckTargetVersion[];
+extern const char kMetricCheckRollbackTargetVersion[];
 extern const char kMetricCheckTimeSinceLastCheckMinutes[];
 extern const char kMetricCheckTimeSinceLastCheckUptimeMinutes[];
 
@@ -76,6 +79,10 @@
 // UpdateEngine.Rollback.* metric.
 extern const char kMetricRollbackResult[];
 
+// UpdateEngine.EnterpriseRollback.* metrics.
+extern const char kMetricEnterpriseRollbackFailure[];
+extern const char kMetricEnterpriseRollbackSuccess[];
+
 // UpdateEngine.CertificateCheck.* metrics.
 extern const char kMetricCertificateCheckUpdateCheck[];
 extern const char kMetricCertificateCheckDownload[];
@@ -97,6 +104,9 @@
 
   void ReportRollbackMetrics(metrics::RollbackResult result) override;
 
+  void ReportEnterpriseRollbackMetrics(
+      bool success, const std::string& rollback_version) override;
+
   void ReportDailyMetrics(base::TimeDelta os_age) override;
 
   void ReportUpdateCheckMetrics(
diff --git a/metrics_reporter_omaha_unittest.cc b/metrics_reporter_omaha_unittest.cc
index 76e33c6..c7641c0 100644
--- a/metrics_reporter_omaha_unittest.cc
+++ b/metrics_reporter_omaha_unittest.cc
@@ -29,8 +29,9 @@
 #include "update_engine/fake_system_state.h"
 
 using base::TimeDelta;
-using testing::AnyNumber;
 using testing::_;
+using testing::AnyNumber;
+using testing::Return;
 
 namespace chromeos_update_engine {
 class MetricsReporterOmahaTest : public ::testing::Test {
@@ -85,6 +86,14 @@
                               static_cast<int>(error_code)))
       .Times(2);
 
+  // Not pinned nor rollback
+  EXPECT_CALL(*mock_metrics_lib_,
+              SendSparseToUMA(metrics::kMetricCheckTargetVersion, _))
+      .Times(0);
+  EXPECT_CALL(*mock_metrics_lib_,
+              SendSparseToUMA(metrics::kMetricCheckRollbackTargetVersion, _))
+      .Times(0);
+
   EXPECT_CALL(
       *mock_metrics_lib_,
       SendToUMA(metrics::kMetricCheckTimeSinceLastCheckMinutes, 1, _, _, _))
@@ -101,6 +110,62 @@
   // Advance the clock by 1 minute and report the same metrics again.
   fake_clock.SetWallclockTime(base::Time::FromInternalValue(61000000));
   fake_clock.SetMonotonicTime(base::Time::FromInternalValue(61000000));
+  // Allow rollback
+  reporter_.ReportUpdateCheckMetrics(
+      &fake_system_state, result, reaction, error_code);
+}
+
+TEST_F(MetricsReporterOmahaTest, ReportUpdateCheckMetricsPinned) {
+  FakeSystemState fake_system_state;
+
+  OmahaRequestParams params(&fake_system_state);
+  params.set_target_version_prefix("10575.");
+  params.set_rollback_allowed(false);
+  fake_system_state.set_request_params(&params);
+
+  metrics::CheckResult result = metrics::CheckResult::kUpdateAvailable;
+  metrics::CheckReaction reaction = metrics::CheckReaction::kIgnored;
+  metrics::DownloadErrorCode error_code =
+      metrics::DownloadErrorCode::kHttpStatus200;
+
+  EXPECT_CALL(*mock_metrics_lib_,
+              SendSparseToUMA(metrics::kMetricCheckDownloadErrorCode, _));
+  // Target version set, but not a rollback.
+  EXPECT_CALL(*mock_metrics_lib_,
+              SendSparseToUMA(metrics::kMetricCheckTargetVersion, 10575))
+      .Times(1);
+  EXPECT_CALL(*mock_metrics_lib_,
+              SendSparseToUMA(metrics::kMetricCheckRollbackTargetVersion, _))
+      .Times(0);
+
+  reporter_.ReportUpdateCheckMetrics(
+      &fake_system_state, result, reaction, error_code);
+}
+
+TEST_F(MetricsReporterOmahaTest, ReportUpdateCheckMetricsRollback) {
+  FakeSystemState fake_system_state;
+
+  OmahaRequestParams params(&fake_system_state);
+  params.set_target_version_prefix("10575.");
+  params.set_rollback_allowed(true);
+  fake_system_state.set_request_params(&params);
+
+  metrics::CheckResult result = metrics::CheckResult::kUpdateAvailable;
+  metrics::CheckReaction reaction = metrics::CheckReaction::kIgnored;
+  metrics::DownloadErrorCode error_code =
+      metrics::DownloadErrorCode::kHttpStatus200;
+
+  EXPECT_CALL(*mock_metrics_lib_,
+              SendSparseToUMA(metrics::kMetricCheckDownloadErrorCode, _));
+  // Rollback.
+  EXPECT_CALL(*mock_metrics_lib_,
+              SendSparseToUMA(metrics::kMetricCheckTargetVersion, 10575))
+      .Times(1);
+  EXPECT_CALL(
+      *mock_metrics_lib_,
+      SendSparseToUMA(metrics::kMetricCheckRollbackTargetVersion, 10575))
+      .Times(1);
+
   reporter_.ReportUpdateCheckMetrics(
       &fake_system_state, result, reaction, error_code);
 }
@@ -347,6 +412,18 @@
   reporter_.ReportRollbackMetrics(result);
 }
 
+TEST_F(MetricsReporterOmahaTest, ReportEnterpriseRollbackMetrics) {
+  EXPECT_CALL(*mock_metrics_lib_,
+              SendSparseToUMA(metrics::kMetricEnterpriseRollbackSuccess, 10575))
+      .Times(1);
+  EXPECT_CALL(*mock_metrics_lib_,
+              SendSparseToUMA(metrics::kMetricEnterpriseRollbackFailure, 10323))
+      .Times(1);
+
+  reporter_.ReportEnterpriseRollbackMetrics(/*success=*/true, "10575.39.2");
+  reporter_.ReportEnterpriseRollbackMetrics(/*success=*/false, "10323.67.7");
+}
+
 TEST_F(MetricsReporterOmahaTest, ReportCertificateCheckMetrics) {
   ServerToCheck server_to_check = ServerToCheck::kUpdate;
   CertificateCheckResult result = CertificateCheckResult::kValid;
diff --git a/metrics_reporter_stub.h b/metrics_reporter_stub.h
index d0f75ab..8b559f3 100644
--- a/metrics_reporter_stub.h
+++ b/metrics_reporter_stub.h
@@ -17,6 +17,8 @@
 #ifndef UPDATE_ENGINE_METRICS_REPORTER_STUB_H_
 #define UPDATE_ENGINE_METRICS_REPORTER_STUB_H_
 
+#include <string>
+
 #include "update_engine/common/error_code.h"
 #include "update_engine/metrics_constants.h"
 #include "update_engine/metrics_reporter_interface.h"
@@ -33,6 +35,9 @@
 
   void ReportRollbackMetrics(metrics::RollbackResult result) override {}
 
+  void ReportEnterpriseRollbackMetrics(
+      bool success, const std::string& rollback_version) override {}
+
   void ReportDailyMetrics(base::TimeDelta os_age) override {}
 
   void ReportUpdateCheckMetrics(
diff --git a/mock_metrics_reporter.h b/mock_metrics_reporter.h
index a4e0a12..d080ce8 100644
--- a/mock_metrics_reporter.h
+++ b/mock_metrics_reporter.h
@@ -17,6 +17,8 @@
 #ifndef UPDATE_ENGINE_MOCK_METRICS_REPORTER_H
 #define UPDATE_ENGINE_MOCK_METRICS_REPORTER_H
 
+#include <string>
+
 #include <gmock/gmock.h>
 
 #include "update_engine/metrics_reporter_interface.h"
@@ -29,6 +31,9 @@
 
   MOCK_METHOD1(ReportRollbackMetrics, void(metrics::RollbackResult result));
 
+  MOCK_METHOD2(ReportEnterpriseRollbackMetrics,
+               void(bool success, const std::string& rollback_version));
+
   MOCK_METHOD1(ReportDailyMetrics, void(base::TimeDelta os_age));
 
   MOCK_METHOD4(ReportUpdateCheckMetrics,
diff --git a/mock_omaha_request_params.h b/mock_omaha_request_params.h
index 6d8d3d8..2fe5e01 100644
--- a/mock_omaha_request_params.h
+++ b/mock_omaha_request_params.h
@@ -50,6 +50,7 @@
   MOCK_METHOD3(SetTargetChannel, bool(const std::string& channel,
                                       bool is_powerwash_allowed,
                                       std::string* error));
+  MOCK_CONST_METHOD0(target_version_prefix, std::string(void));
   MOCK_METHOD0(UpdateDownloadChannel, void(void));
   MOCK_CONST_METHOD0(IsUpdateUrlOfficial, bool(void));
   MOCK_CONST_METHOD0(ShouldPowerwash, bool(void));
diff --git a/omaha_response_handler_action.h b/omaha_response_handler_action.h
index e868b53..f5cc1a6 100644
--- a/omaha_response_handler_action.h
+++ b/omaha_response_handler_action.h
@@ -89,6 +89,10 @@
   friend class OmahaResponseHandlerActionTest;
 
   FRIEND_TEST(UpdateAttempterTest, CreatePendingErrorEventResumedTest);
+  FRIEND_TEST(UpdateAttempterTest, RollbackMetricsNotRollbackFailure);
+  FRIEND_TEST(UpdateAttempterTest, RollbackMetricsNotRollbackSuccess);
+  FRIEND_TEST(UpdateAttempterTest, RollbackMetricsRollbackFailure);
+  FRIEND_TEST(UpdateAttempterTest, RollbackMetricsRollbackSuccess);
   FRIEND_TEST(UpdateAttempterTest, SetRollbackHappenedNotRollback);
   FRIEND_TEST(UpdateAttempterTest, SetRollbackHappenedRollback);
   FRIEND_TEST(UpdateAttempterTest, UpdateDeferredByPolicyTest);
diff --git a/update_attempter.cc b/update_attempter.cc
index 4a71e4d..67391a3 100644
--- a/update_attempter.cc
+++ b/update_attempter.cc
@@ -1007,6 +1007,8 @@
       // over the following powerwash.
       if (install_plan.is_rollback) {
         system_state_->payload_state()->SetRollbackHappened(true);
+        system_state_->metrics_reporter()->ReportEnterpriseRollbackMetrics(
+            /*success=*/true, install_plan.version);
       }
 
       // Expect to reboot into the new version to send the proper metric during
@@ -1377,6 +1379,15 @@
   LOG(ERROR) << "Update failed.";
   system_state_->payload_state()->UpdateFailed(error_event_->error_code);
 
+  // Send metrics if it was a rollback.
+  if (response_handler_action_) {
+    const InstallPlan& install_plan = response_handler_action_->install_plan();
+    if (install_plan.is_rollback) {
+      system_state_->metrics_reporter()->ReportEnterpriseRollbackMetrics(
+          /*success=*/false, install_plan.version);
+    }
+  }
+
   // Send it to Omaha.
   LOG(INFO) << "Reporting the error event";
   shared_ptr<OmahaRequestAction> error_event_action(
diff --git a/update_attempter.h b/update_attempter.h
index a3e2b30..9504f88 100644
--- a/update_attempter.h
+++ b/update_attempter.h
@@ -270,6 +270,10 @@
   FRIEND_TEST(UpdateAttempterTest, RollbackNotAllowed);
   FRIEND_TEST(UpdateAttempterTest, RollbackAllowed);
   FRIEND_TEST(UpdateAttempterTest, RollbackAllowedSetAndReset);
+  FRIEND_TEST(UpdateAttempterTest, RollbackMetricsNotRollbackFailure);
+  FRIEND_TEST(UpdateAttempterTest, RollbackMetricsNotRollbackSuccess);
+  FRIEND_TEST(UpdateAttempterTest, RollbackMetricsRollbackFailure);
+  FRIEND_TEST(UpdateAttempterTest, RollbackMetricsRollbackSuccess);
   FRIEND_TEST(UpdateAttempterTest, ScheduleErrorEventActionNoEventTest);
   FRIEND_TEST(UpdateAttempterTest, ScheduleErrorEventActionTest);
   FRIEND_TEST(UpdateAttempterTest, SetRollbackHappenedNotRollback);
diff --git a/update_attempter_unittest.cc b/update_attempter_unittest.cc
index 3936404..29c1971 100644
--- a/update_attempter_unittest.cc
+++ b/update_attempter_unittest.cc
@@ -74,6 +74,8 @@
 
 namespace chromeos_update_engine {
 
+const char kRollbackVersion[] = "10575.39.2";
+
 // Test a subclass rather than the main class directly so that we can mock out
 // methods within the class. There're explicit unit tests for the mocked out
 // methods.
@@ -1267,4 +1269,60 @@
   attempter_.ProcessingDone(nullptr, ErrorCode::kSuccess);
 }
 
+TEST_F(UpdateAttempterTest, RollbackMetricsRollbackSuccess) {
+  OmahaResponseHandlerAction* response_action =
+      new OmahaResponseHandlerAction(&fake_system_state_);
+  response_action->install_plan_.is_rollback = true;
+  response_action->install_plan_.version = kRollbackVersion;
+  attempter_.response_handler_action_.reset(response_action);
+
+  EXPECT_CALL(*fake_system_state_.mock_metrics_reporter(),
+              ReportEnterpriseRollbackMetrics(true, kRollbackVersion))
+      .Times(1);
+  attempter_.ProcessingDone(nullptr, ErrorCode::kSuccess);
+}
+
+TEST_F(UpdateAttempterTest, RollbackMetricsNotRollbackSuccess) {
+  OmahaResponseHandlerAction* response_action =
+      new OmahaResponseHandlerAction(&fake_system_state_);
+  response_action->install_plan_.is_rollback = false;
+  response_action->install_plan_.version = kRollbackVersion;
+  attempter_.response_handler_action_.reset(response_action);
+
+  EXPECT_CALL(*fake_system_state_.mock_metrics_reporter(),
+              ReportEnterpriseRollbackMetrics(_, _))
+      .Times(0);
+  attempter_.ProcessingDone(nullptr, ErrorCode::kSuccess);
+}
+
+TEST_F(UpdateAttempterTest, RollbackMetricsRollbackFailure) {
+  OmahaResponseHandlerAction* response_action =
+      new OmahaResponseHandlerAction(&fake_system_state_);
+  response_action->install_plan_.is_rollback = true;
+  response_action->install_plan_.version = kRollbackVersion;
+  attempter_.response_handler_action_.reset(response_action);
+
+  EXPECT_CALL(*fake_system_state_.mock_metrics_reporter(),
+              ReportEnterpriseRollbackMetrics(false, kRollbackVersion))
+      .Times(1);
+  MockAction action;
+  attempter_.CreatePendingErrorEvent(&action, ErrorCode::kRollbackNotPossible);
+  attempter_.ProcessingDone(nullptr, ErrorCode::kRollbackNotPossible);
+}
+
+TEST_F(UpdateAttempterTest, RollbackMetricsNotRollbackFailure) {
+  OmahaResponseHandlerAction* response_action =
+      new OmahaResponseHandlerAction(&fake_system_state_);
+  response_action->install_plan_.is_rollback = false;
+  response_action->install_plan_.version = kRollbackVersion;
+  attempter_.response_handler_action_.reset(response_action);
+
+  EXPECT_CALL(*fake_system_state_.mock_metrics_reporter(),
+              ReportEnterpriseRollbackMetrics(_, _))
+      .Times(0);
+  MockAction action;
+  attempter_.CreatePendingErrorEvent(&action, ErrorCode::kRollbackNotPossible);
+  attempter_.ProcessingDone(nullptr, ErrorCode::kRollbackNotPossible);
+}
+
 }  // namespace chromeos_update_engine