update_engine: Send UMA stats about kernel key versions

Adding the following UMA stats:
- UpdateEngine.KernelKey.MinVersion: Minimum kernel key version
  already set in the TPM.
- UpdateEngine.KernelKey.MaxRollforwardVersion: Maximum kernel key
  rollforward version set by update_engine.
- UpdateEngine.KernelKey.MaxRollforwardSetSuccess: Whether setting
  the maximum kernely key rollforward version succeeded.

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

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

Change-Id: I14192b5ff9c07f8a003e0589450202f488cccc01
Reviewed-on: https://chromium-review.googlesource.com/1078968
Commit-Ready: Zentaro Kavanagh <zentaro@chromium.org>
Tested-by: Zentaro Kavanagh <zentaro@chromium.org>
Reviewed-by: Amin Hassani <ahassani@chromium.org>
Reviewed-by: Zentaro Kavanagh <zentaro@chromium.org>
diff --git a/metrics_reporter_android.h b/metrics_reporter_android.h
index 06ad8c5..847e509 100644
--- a/metrics_reporter_android.h
+++ b/metrics_reporter_android.h
@@ -86,6 +86,10 @@
 
   void ReportInternalErrorCode(ErrorCode error_code) override {}
 
+  void ReportKeyVersionMetrics(int kernel_min_version,
+                               int kernel_max_rollforward_version,
+                               bool kernel_max_rollforward_success) override {}
+
  private:
   DISALLOW_COPY_AND_ASSIGN(MetricsReporterAndroid);
 };
diff --git a/metrics_reporter_interface.h b/metrics_reporter_interface.h
index 8a7c864..85ffb85 100644
--- a/metrics_reporter_interface.h
+++ b/metrics_reporter_interface.h
@@ -214,6 +214,16 @@
   //
   // |kMetricAttemptInternalErrorCode|
   virtual void ReportInternalErrorCode(ErrorCode error_code) = 0;
+
+  // Helper function to report metrics related to the verified boot key
+  // versions:
+  //
+  //  |kMetricKernelMinVersion|
+  //  |kMetricKernelMaxRollforwardVersion|
+  //  |kMetricKernelMaxRollforwardSetSuccess|
+  virtual void ReportKeyVersionMetrics(int kernel_min_version,
+                                       int kernel_max_rollforward_version,
+                                       bool kernel_max_rollforward_success) = 0;
 };
 
 }  // namespace chromeos_update_engine
diff --git a/metrics_reporter_omaha.cc b/metrics_reporter_omaha.cc
index 0a2b674..5e14cca 100644
--- a/metrics_reporter_omaha.cc
+++ b/metrics_reporter_omaha.cc
@@ -116,6 +116,13 @@
 const char kMetricCertificateCheckDownload[] =
     "UpdateEngine.CertificateCheck.Download";
 
+// UpdateEngine.KernelKey.* metrics.
+const char kMetricKernelMinVersion[] = "UpdateEngine.KernelKey.MinVersion";
+const char kMetricKernelMaxRollforwardVersion[] =
+    "UpdateEngine.KernelKey.MaxRollforwardVersion";
+const char kMetricKernelMaxRollforwardSetSuccess[] =
+    "UpdateEngine.KernelKey.MaxRollforwardSetSuccess";
+
 // UpdateEngine.* metrics.
 const char kMetricFailedUpdateCount[] = "UpdateEngine.FailedUpdateCount";
 const char kMetricInstallDateProvisioningSource[] =
@@ -577,4 +584,25 @@
                               static_cast<int>(ErrorCode::kUmaReportedMax));
 }
 
+void MetricsReporterOmaha::ReportKeyVersionMetrics(
+    int kernel_min_version,
+    int kernel_max_rollforward_version,
+    bool kernel_max_rollforward_success) {
+  int value = kernel_min_version;
+  string metric = metrics::kMetricKernelMinVersion;
+  LOG(INFO) << "Sending " << value << " for metric " << metric;
+  metrics_lib_->SendSparseToUMA(metric, value);
+
+  value = kernel_max_rollforward_version;
+  metric = metrics::kMetricKernelMaxRollforwardVersion;
+  LOG(INFO) << "Sending " << value << " for metric " << metric;
+  metrics_lib_->SendSparseToUMA(metric, value);
+
+  bool bool_value = kernel_max_rollforward_success;
+  metric = metrics::kMetricKernelMaxRollforwardSetSuccess;
+  LOG(INFO) << "Sending " << bool_value << " for metric " << metric
+            << " (bool)";
+  metrics_lib_->SendBoolToUMA(metric, bool_value);
+}
+
 }  // namespace chromeos_update_engine
diff --git a/metrics_reporter_omaha.h b/metrics_reporter_omaha.h
index 97b283d..d348cdc 100644
--- a/metrics_reporter_omaha.h
+++ b/metrics_reporter_omaha.h
@@ -87,6 +87,11 @@
 extern const char kMetricCertificateCheckUpdateCheck[];
 extern const char kMetricCertificateCheckDownload[];
 
+// UpdateEngine.KernelKey.* metrics.
+extern const char kMetricKernelMinVersion[];
+extern const char kMetricKernelMaxRollforwardVersion[];
+extern const char kMetricKernelMaxRollforwardSetSuccess[];
+
 // UpdateEngine.* metrics.
 extern const char kMetricFailedUpdateCount[];
 extern const char kMetricInstallDateProvisioningSource[];
@@ -155,6 +160,10 @@
 
   void ReportInternalErrorCode(ErrorCode error_code) override;
 
+  void ReportKeyVersionMetrics(int kernel_min_version,
+                               int kernel_max_rollforward_version,
+                               bool kernel_max_rollforward_success) override;
+
  private:
   friend class MetricsReporterOmahaTest;
 
diff --git a/metrics_reporter_omaha_unittest.cc b/metrics_reporter_omaha_unittest.cc
index c7641c0..ea72104 100644
--- a/metrics_reporter_omaha_unittest.cc
+++ b/metrics_reporter_omaha_unittest.cc
@@ -468,4 +468,26 @@
   reporter_.ReportInstallDateProvisioningSource(source, max);
 }
 
+TEST_F(MetricsReporterOmahaTest, ReportKeyVersionMetrics) {
+  int kernel_min_version = 0x00040002;
+  int kernel_max_rollforward_version = 0xfffffffe;
+  bool kernel_max_rollforward_success = true;
+  EXPECT_CALL(
+      *mock_metrics_lib_,
+      SendSparseToUMA(metrics::kMetricKernelMinVersion, kernel_min_version))
+      .Times(1);
+  EXPECT_CALL(*mock_metrics_lib_,
+              SendSparseToUMA(metrics::kMetricKernelMaxRollforwardVersion,
+                              kernel_max_rollforward_version))
+      .Times(1);
+  EXPECT_CALL(*mock_metrics_lib_,
+              SendBoolToUMA(metrics::kMetricKernelMaxRollforwardSetSuccess,
+                            kernel_max_rollforward_success))
+      .Times(1);
+
+  reporter_.ReportKeyVersionMetrics(kernel_min_version,
+                                    kernel_max_rollforward_version,
+                                    kernel_max_rollforward_success);
+}
+
 }  // namespace chromeos_update_engine
diff --git a/metrics_reporter_stub.h b/metrics_reporter_stub.h
index 8b559f3..7112385 100644
--- a/metrics_reporter_stub.h
+++ b/metrics_reporter_stub.h
@@ -84,6 +84,10 @@
 
   void ReportInstallDateProvisioningSource(int source, int max) override {}
 
+  void ReportKeyVersionMetrics(int kernel_min_version,
+                               int kernel_max_rollforward_version,
+                               bool kernel_max_rollforward_success) override {}
+
  private:
   DISALLOW_COPY_AND_ASSIGN(MetricsReporterStub);
 };
diff --git a/mock_metrics_reporter.h b/mock_metrics_reporter.h
index d080ce8..e3c1634 100644
--- a/mock_metrics_reporter.h
+++ b/mock_metrics_reporter.h
@@ -83,6 +83,11 @@
   MOCK_METHOD2(ReportInstallDateProvisioningSource, void(int source, int max));
 
   MOCK_METHOD1(ReportInternalErrorCode, void(ErrorCode error_code));
+
+  MOCK_METHOD3(ReportKeyVersionMetrics,
+               void(int kernel_min_version,
+                    int kernel_max_rollforward_version,
+                    bool kernel_max_rollforward_success));
 };
 
 }  // namespace chromeos_update_engine
diff --git a/omaha_request_action.cc b/omaha_request_action.cc
index 72a7d84..03288ff 100644
--- a/omaha_request_action.cc
+++ b/omaha_request_action.cc
@@ -1856,7 +1856,8 @@
 }
 
 void OmahaRequestAction::SetMaxKernelKeyVersionForRollback() const {
-  bool max_rollforward_set = false;
+  int max_kernel_rollforward;
+  int min_kernel_version = system_state_->hardware()->GetMinKernelKeyVersion();
   if (IsRollbackEnabled()) {
     // If rollback is enabled, set the max kernel key version to the current
     // kernel key version. This has the effect of freezing kernel key roll
@@ -1868,12 +1869,9 @@
     // the kernel key version from max_rollback_versions in the past. At that
     // point the max kernel key version will be set to that value, creating a
     // sliding window of versions that can be rolled back to.
-    int min_kernel_version =
-        system_state_->hardware()->GetMinKernelKeyVersion();
     LOG(INFO) << "Rollback is enabled. Setting kernel_max_rollforward to "
               << min_kernel_version;
-    max_rollforward_set = system_state_->hardware()->SetMaxKernelKeyRollforward(
-        min_kernel_version);
+    max_kernel_rollforward = min_kernel_version;
   } else {
     // For devices that are not rollback enabled (ie. consumer devices), the
     // max kernel key version is set to 0xfffffffe, which is logically
@@ -1881,13 +1879,18 @@
     // versions roll forward each time they are incremented.
     LOG(INFO) << "Rollback is disabled. Setting kernel_max_rollforward to "
               << kRollforwardInfinity;
-    max_rollforward_set = system_state_->hardware()->SetMaxKernelKeyRollforward(
-        kRollforwardInfinity);
+    max_kernel_rollforward = kRollforwardInfinity;
   }
 
+  bool max_rollforward_set =
+      system_state_->hardware()->SetMaxKernelKeyRollforward(
+          max_kernel_rollforward);
   if (!max_rollforward_set) {
     LOG(ERROR) << "Failed to set kernel_max_rollforward";
   }
+  // Report metrics
+  system_state_->metrics_reporter()->ReportKeyVersionMetrics(
+      min_kernel_version, max_kernel_rollforward, max_rollforward_set);
 }
 
 }  // namespace chromeos_update_engine
diff --git a/omaha_request_action_unittest.cc b/omaha_request_action_unittest.cc
index 0e5ffb0..f2a83f7 100644
--- a/omaha_request_action_unittest.cc
+++ b/omaha_request_action_unittest.cc
@@ -2797,6 +2797,11 @@
   EXPECT_EQ(min_kernel_version, fake_hw->GetMinKernelKeyVersion());
   EXPECT_EQ(kRollforwardInfinity, fake_hw->GetMaxKernelKeyRollforward());
 
+  EXPECT_CALL(
+      *fake_system_state_.mock_metrics_reporter(),
+      ReportKeyVersionMetrics(min_kernel_version, min_kernel_version, true))
+      .Times(1);
+
   TestRollbackCheck(false /* is_consumer_device */,
                     3 /* rollback_allowed_milestones */,
                     false /* is_policy_loaded */);
@@ -2824,6 +2829,11 @@
   EXPECT_EQ(min_kernel_version, fake_hw->GetMinKernelKeyVersion());
   EXPECT_EQ(kRollforwardInfinity, fake_hw->GetMaxKernelKeyRollforward());
 
+  EXPECT_CALL(
+      *fake_system_state_.mock_metrics_reporter(),
+      ReportKeyVersionMetrics(min_kernel_version, kRollforwardInfinity, true))
+      .Times(1);
+
   TestRollbackCheck(true /* is_consumer_device */,
                     3 /* rollback_allowed_milestones */,
                     false /* is_policy_loaded */);
@@ -2850,6 +2860,11 @@
   EXPECT_EQ(min_kernel_version, fake_hw->GetMinKernelKeyVersion());
   EXPECT_EQ(kRollforwardInfinity, fake_hw->GetMaxKernelKeyRollforward());
 
+  EXPECT_CALL(
+      *fake_system_state_.mock_metrics_reporter(),
+      ReportKeyVersionMetrics(min_kernel_version, min_kernel_version, true))
+      .Times(1);
+
   TestRollbackCheck(false /* is_consumer_device */,
                     allowed_milestones,
                     true /* is_policy_loaded */);
@@ -2877,6 +2892,11 @@
   EXPECT_EQ(min_kernel_version, fake_hw->GetMinKernelKeyVersion());
   EXPECT_EQ(kRollforwardInfinity, fake_hw->GetMaxKernelKeyRollforward());
 
+  EXPECT_CALL(
+      *fake_system_state_.mock_metrics_reporter(),
+      ReportKeyVersionMetrics(min_kernel_version, kRollforwardInfinity, true))
+      .Times(1);
+
   TestRollbackCheck(false /* is_consumer_device */,
                     allowed_milestones,
                     true /* is_policy_loaded */);