PM: UpdaterProvider reports the number of consecutive failed update checks.

This adds a new variable to UpdaterProvider, along with the necessary
bits of implementation in UpdateAttempter, to track and report this
number.

BUG=chromium:367006
TEST=Unit tests.

Change-Id: I819dc5c9d4d351e5bfe1373dba0993e3f622b0e0
Reviewed-on: https://chromium-review.googlesource.com/197092
Tested-by: Gilad Arnold <garnold@chromium.org>
Reviewed-by: Alex Deymo <deymo@chromium.org>
Commit-Queue: Gilad Arnold <garnold@chromium.org>
diff --git a/policy_manager/fake_updater_provider.h b/policy_manager/fake_updater_provider.h
index 0413eb5..c9fbdc6 100644
--- a/policy_manager/fake_updater_provider.h
+++ b/policy_manager/fake_updater_provider.h
@@ -61,23 +61,30 @@
     return &var_cellular_enabled_;
   }
 
+  virtual FakeVariable<unsigned int>*
+      var_consecutive_failed_update_checks() override {
+    return &var_consecutive_failed_update_checks_;
+  }
+
  private:
   FakeVariable<base::Time> var_updater_started_time_{
       "updater_started_time", kVariableModePoll};
   FakeVariable<base::Time> var_last_checked_time_{
-    "last_checked_time", kVariableModePoll};
+      "last_checked_time", kVariableModePoll};
   FakeVariable<base::Time> var_update_completed_time_{
-    "update_completed_time", kVariableModePoll};
+      "update_completed_time", kVariableModePoll};
   FakeVariable<double> var_progress_{"progress", kVariableModePoll};
   FakeVariable<Stage> var_stage_{"stage", kVariableModePoll};
   FakeVariable<std::string> var_new_version_{"new_version", kVariableModePoll};
   FakeVariable<size_t> var_payload_size_{"payload_size", kVariableModePoll};
   FakeVariable<std::string> var_curr_channel_{
-    "curr_channel", kVariableModePoll};
+      "curr_channel", kVariableModePoll};
   FakeVariable<std::string> var_new_channel_{"new_channel", kVariableModePoll};
   FakeVariable<bool> var_p2p_enabled_{"p2p_enabled", kVariableModePoll};
   FakeVariable<bool> var_cellular_enabled_{
-    "cellular_enabled", kVariableModePoll};
+      "cellular_enabled", kVariableModePoll};
+  FakeVariable<unsigned int> var_consecutive_failed_update_checks_{
+      "consecutive_failed_update_checks", kVariableModePoll};
 
   DISALLOW_COPY_AND_ASSIGN(FakeUpdaterProvider);
 };
diff --git a/policy_manager/real_updater_provider.cc b/policy_manager/real_updater_provider.cc
index 9bdb45a..bc1350b 100644
--- a/policy_manager/real_updater_provider.cc
+++ b/policy_manager/real_updater_provider.cc
@@ -309,6 +309,21 @@
   DISALLOW_COPY_AND_ASSIGN(BooleanPrefVariable);
 };
 
+// A variable returning the number of consecutive failed update checks.
+class ConsecutiveFailedUpdateChecksVariable :
+    public UpdaterVariableBase<unsigned int> {
+ public:
+  using UpdaterVariableBase<unsigned int>::UpdaterVariableBase;
+
+ private:
+  virtual const unsigned int* GetValue(TimeDelta /* timeout */,
+                                       string* /* errmsg */) override {
+    return new unsigned int(
+        system_state()->update_attempter()->consecutive_failed_update_checks());
+  }
+
+  DISALLOW_COPY_AND_ASSIGN(ConsecutiveFailedUpdateChecksVariable);
+};
 
 // RealUpdaterProvider methods.
 
@@ -335,6 +350,9 @@
         new BooleanPrefVariable(
             "cellular_enabled", system_state_,
             chromeos_update_engine::kPrefsUpdateOverCellularPermission,
-            false)) {}
+            false)),
+    var_consecutive_failed_update_checks_(
+        new ConsecutiveFailedUpdateChecksVariable(
+            "consecutive_failed_update_checks", system_state_)) {}
 
 }  // namespace chromeos_policy_manager
diff --git a/policy_manager/real_updater_provider.h b/policy_manager/real_updater_provider.h
index 619d5ab..22b9e0f 100644
--- a/policy_manager/real_updater_provider.h
+++ b/policy_manager/real_updater_provider.h
@@ -71,6 +71,11 @@
     return var_cellular_enabled_.get();
   }
 
+  virtual Variable<unsigned int>*
+      var_consecutive_failed_update_checks() override {
+    return var_consecutive_failed_update_checks_.get();
+  }
+
  private:
   // A pointer to the update engine's system state aggregator.
   chromeos_update_engine::SystemState* system_state_;
@@ -87,6 +92,7 @@
   scoped_ptr<Variable<std::string>> var_new_channel_;
   scoped_ptr<Variable<bool>> var_p2p_enabled_;
   scoped_ptr<Variable<bool>> var_cellular_enabled_;
+  scoped_ptr<Variable<unsigned int>> var_consecutive_failed_update_checks_;
 
   DISALLOW_COPY_AND_ASSIGN(RealUpdaterProvider);
 };
diff --git a/policy_manager/real_updater_provider_unittest.cc b/policy_manager/real_updater_provider_unittest.cc
index e779456..dd6fb57 100644
--- a/policy_manager/real_updater_provider_unittest.cc
+++ b/policy_manager/real_updater_provider_unittest.cc
@@ -445,4 +445,13 @@
   PmTestUtils::ExpectVariableNotSet(provider_->var_update_completed_time());
 }
 
+TEST_F(PmRealUpdaterProviderTest, GetConsecutiveFailedUpdateChecks) {
+  const unsigned int kNumFailedChecks = 3;
+  EXPECT_CALL(*fake_sys_state_.mock_update_attempter(),
+              consecutive_failed_update_checks())
+      .WillRepeatedly(Return(kNumFailedChecks));
+  PmTestUtils::ExpectVariableHasValue(
+      kNumFailedChecks, provider_->var_consecutive_failed_update_checks());
+}
+
 }  // namespace chromeos_policy_manager
diff --git a/policy_manager/updater_provider.h b/policy_manager/updater_provider.h
index f9a4bff..fa5f48a 100644
--- a/policy_manager/updater_provider.h
+++ b/policy_manager/updater_provider.h
@@ -74,6 +74,9 @@
   // A variable indicating whether updates are allowed over a cellular network.
   virtual Variable<bool>* var_cellular_enabled() = 0;
 
+  // A variable returning the number of consecutive failed update checks.
+  virtual Variable<unsigned int>* var_consecutive_failed_update_checks() = 0;
+
  protected:
   UpdaterProvider() {}
 
diff --git a/update_attempter.cc b/update_attempter.cc
index 891cc96..7df18b1 100644
--- a/update_attempter.cc
+++ b/update_attempter.cc
@@ -978,6 +978,15 @@
     // If the request is not an event, then it's the update-check.
     if (!omaha_request_action->IsEvent()) {
       http_response_code_ = omaha_request_action->GetHTTPResponseCode();
+
+      // Record the number of consecutive failed update checks.
+      if (http_response_code_ == kHttpResponseInternalServerError ||
+          http_response_code_ == kHttpResponseServiceUnavailable) {
+        consecutive_failed_update_checks_++;
+      } else {
+        consecutive_failed_update_checks_ = 0;
+      }
+
       // Forward the server-dictated poll interval to the update check
       // scheduler, if any.
       if (update_check_scheduler_) {
diff --git a/update_attempter.h b/update_attempter.h
index 311a918..c83f121 100644
--- a/update_attempter.h
+++ b/update_attempter.h
@@ -202,6 +202,11 @@
   // This will return an empty string otherwise.
   std::string const& GetPrevVersion() const { return prev_version_; }
 
+  // Returns the nubmer of consecutive failed update checks.
+  virtual unsigned int consecutive_failed_update_checks() const {
+    return consecutive_failed_update_checks_;
+  }
+
  private:
   // Update server URL for automated lab test.
   static const char* const kTestUpdateUrl;
@@ -457,6 +462,10 @@
   // ignored (nor is it being written), which is useful for testing situations.
   std::string update_completed_marker_;
 
+  // The number of consecutive failed update checks. Needed for calculating the
+  // next update check interval.
+  unsigned int consecutive_failed_update_checks_ = 0;
+
   DISALLOW_COPY_AND_ASSIGN(UpdateAttempter);
 };
 
diff --git a/update_attempter_mock.h b/update_attempter_mock.h
index 29e46bc..d2bc447 100644
--- a/update_attempter_mock.h
+++ b/update_attempter_mock.h
@@ -28,6 +28,8 @@
                                int64_t* new_size));
 
   MOCK_METHOD1(GetBootTimeAtUpdate, bool(base::Time* out_boot_time));
+
+  MOCK_CONST_METHOD0(consecutive_failed_update_checks, unsigned int(void));
 };
 
 }  // namespace chromeos_update_engine