Refactor ChromeOSPolicy into policy and utilities

Building on the policy fragments that have been previously extracted
from ChromeOSPolicy, this extracts a few more pieces of logic and
replaces sections of ChromeOSPolicy with calls to the extracted
methods.

Bug: 66016687
Test: unit tests, manually triggered OTA updates

Change-Id: I3bc608065f8ab89982f71b8490ebd66ed2266aa3
diff --git a/Android.mk b/Android.mk
index d79d89b..d2a83bc 100644
--- a/Android.mk
+++ b/Android.mk
@@ -978,9 +978,11 @@
     update_manager/boxed_value_unittest.cc \
     update_manager/chromeos_policy.cc \
     update_manager/chromeos_policy_unittest.cc \
+    update_manager/enterprise_device_policy_impl.cc \
     update_manager/evaluation_context_unittest.cc \
     update_manager/generic_variables_unittest.cc \
     update_manager/next_update_check_policy_impl_unittest.cc \
+    update_manager/out_of_box_experience_policy_impl.cc \
     update_manager/policy_test_utils.cc \
     update_manager/prng_unittest.cc \
     update_manager/real_device_policy_provider_unittest.cc \
diff --git a/update_engine.gyp b/update_engine.gyp
index f72ca14..8111100 100644
--- a/update_engine.gyp
+++ b/update_engine.gyp
@@ -274,8 +274,15 @@
         'update_manager/boxed_value.cc',
         'update_manager/chromeos_policy.cc',
         'update_manager/default_policy.cc',
+        'update_manager/enough_slots_ab_updates_policy_impl.cc',
+        'update_manager/enterprise_device_policy_impl.cc',
         'update_manager/evaluation_context.cc',
+        'update_manager/interactive_update_policy_impl.cc',
+        'update_manager/next_update_check_policy_impl.cc',
+        'update_manager/official_build_check_policy_impl.cc',
+        'update_manager/out_of_box_experience_policy_impl.cc',
         'update_manager/policy.cc',
+        'update_manager/policy_test_utils.cc',
         'update_manager/real_config_provider.cc',
         'update_manager/real_device_policy_provider.cc',
         'update_manager/real_random_provider.cc',
diff --git a/update_manager/chromeos_policy.cc b/update_manager/chromeos_policy.cc
index 12f417c..842839a 100644
--- a/update_manager/chromeos_policy.cc
+++ b/update_manager/chromeos_policy.cc
@@ -19,6 +19,7 @@
 #include <algorithm>
 #include <set>
 #include <string>
+#include <vector>
 
 #include <base/logging.h>
 #include <base/strings/string_util.h>
@@ -28,6 +29,11 @@
 #include "update_engine/common/error_code_utils.h"
 #include "update_engine/common/utils.h"
 #include "update_engine/update_manager/device_policy_provider.h"
+#include "update_engine/update_manager/enough_slots_ab_updates_policy_impl.h"
+#include "update_engine/update_manager/enterprise_device_policy_impl.h"
+#include "update_engine/update_manager/interactive_update_policy_impl.h"
+#include "update_engine/update_manager/official_build_check_policy_impl.h"
+#include "update_engine/update_manager/out_of_box_experience_policy_impl.h"
 #include "update_engine/update_manager/policy_utils.h"
 #include "update_engine/update_manager/shill_provider.h"
 
@@ -38,10 +44,10 @@
 using chromeos_update_engine::ErrorCode;
 using chromeos_update_engine::InstallPlan;
 using std::get;
-using std::max;
 using std::min;
 using std::set;
 using std::string;
+using std::vector;
 
 namespace {
 
@@ -172,21 +178,16 @@
 
 namespace chromeos_update_manager {
 
-const int ChromeOSPolicy::kTimeoutInitialInterval =  7 * 60;
+const NextUpdateCheckPolicyConstants
+    ChromeOSPolicy::kNextUpdateCheckPolicyConstants = {
+        .timeout_initial_interval = 7 * 60,
+        .timeout_periodic_interval = 45 * 60,
+        .timeout_max_backoff_interval = 4 * 60 * 60,
+        .timeout_regular_fuzz = 10 * 60,
+        .attempt_backoff_max_interval_in_days = 16,
+        .attempt_backoff_fuzz_in_hours = 12,
+};
 
-// TODO(deymo): Split the update_manager policies for Brillo and ChromeOS and
-// make the update check periodic interval configurable.
-#ifdef __ANDROID__
-const int ChromeOSPolicy::kTimeoutPeriodicInterval = 5 * 60 * 60;
-const int ChromeOSPolicy::kTimeoutMaxBackoffInterval = 26 * 60 * 60;
-#else
-const int ChromeOSPolicy::kTimeoutPeriodicInterval = 45 * 60;
-const int ChromeOSPolicy::kTimeoutMaxBackoffInterval = 4 * 60 * 60;
-#endif  // __ANDROID__
-
-const int ChromeOSPolicy::kTimeoutRegularFuzz = 10 * 60;
-const int ChromeOSPolicy::kAttemptBackoffMaxIntervalInDays = 16;
-const int ChromeOSPolicy::kAttemptBackoffFuzzInHours = 12;
 const int ChromeOSPolicy::kMaxP2PAttempts = 10;
 const int ChromeOSPolicy::kMaxP2PAttemptsPeriodInSeconds = 5 * 24 * 60 * 60;
 
@@ -199,130 +200,53 @@
   result->target_version_prefix.clear();
   result->is_interactive = false;
 
-  DevicePolicyProvider* const dp_provider = state->device_policy_provider();
-  UpdaterProvider* const updater_provider = state->updater_provider();
-  SystemProvider* const system_provider = state->system_provider();
+  EnoughSlotsAbUpdatesPolicyImpl enough_slots_ab_updates_policy;
+  EnterpriseDevicePolicyImpl enterprise_device_policy;
+  OnlyUpdateOfficialBuildsPolicyImpl only_update_official_builds_policy;
+  InteractiveUpdatePolicyImpl interactive_update_policy;
+  OobePolicyImpl oobe_policy;
+  NextUpdateCheckTimePolicyImpl next_update_check_time_policy(
+      kNextUpdateCheckPolicyConstants);
 
-  // Do not perform any updates if booted from removable device. This decision
-  // is final.
-  const unsigned int* num_slots_p = ec->GetValue(
-      system_provider->var_num_slots());
-  if (!num_slots_p || *num_slots_p < 2) {
-    LOG(INFO) << "Not enough slots for A/B updates, disabling update checks.";
-    result->updates_enabled = false;
+  vector<Policy const*> policies_to_consult = {
+      // Do not perform any updates if there are not enough slots to do A/B
+      // updates.
+      &enough_slots_ab_updates_policy,
+
+      // Check to see if Enterprise-managed (has DevicePolicy) and/or
+      // Kiosk-mode.  If so, then defer to those settings.
+      &enterprise_device_policy,
+
+      // Check to see if an interactive update was requested.
+      &interactive_update_policy,
+
+      // Unofficial builds should not perform periodic update checks.
+      &only_update_official_builds_policy,
+
+      // If OOBE is enabled, wait until it is completed.
+      &oobe_policy,
+
+      // Ensure that periodic update checks are timed properly.
+      &next_update_check_time_policy,
+  };
+
+  // Now that the list of policy implementations, and the order to consult them,
+  // has been setup, consult the policies. If none of the policies make a
+  // definitive decisions about whether or not to check for updates, then allow
+  // the update check to happen.
+  EvalStatus status = ConsultPolicies(policies_to_consult,
+                                      &Policy::UpdateCheckAllowed,
+                                      ec,
+                                      state,
+                                      error,
+                                      result);
+  if (EvalStatus::kContinue != status) {
+    return status;
+  } else {
+    // It is time to check for an update.
+    LOG(INFO) << "Allowing update check.";
     return EvalStatus::kSucceeded;
   }
-
-  const bool* device_policy_is_loaded_p = ec->GetValue(
-      dp_provider->var_device_policy_is_loaded());
-  if (device_policy_is_loaded_p && *device_policy_is_loaded_p) {
-    bool kiosk_app_control_chrome_version = false;
-
-    // Check whether updates are disabled by policy.
-    const bool* update_disabled_p = ec->GetValue(
-        dp_provider->var_update_disabled());
-    if (update_disabled_p && *update_disabled_p) {
-      // Check whether allow kiosk app to control chrome version policy. This
-      // policy is only effective when AU is disabled by admin.
-      const bool* allow_kiosk_app_control_chrome_version_p = ec->GetValue(
-          dp_provider->var_allow_kiosk_app_control_chrome_version());
-      kiosk_app_control_chrome_version =
-          allow_kiosk_app_control_chrome_version_p &&
-          *allow_kiosk_app_control_chrome_version_p;
-      if (!kiosk_app_control_chrome_version) {
-        // No kiosk pin chrome version policy. AU is really disabled.
-        LOG(INFO) << "Updates disabled by policy, blocking update checks.";
-        return EvalStatus::kAskMeAgainLater;
-      }
-    }
-
-    if (kiosk_app_control_chrome_version) {
-      // Get the required platform version from Chrome.
-      const string* kiosk_required_platform_version_p =
-          ec->GetValue(system_provider->var_kiosk_required_platform_version());
-      if (!kiosk_required_platform_version_p) {
-        LOG(INFO) << "Kiosk app required platform version is not fetched, "
-                     "blocking update checks";
-        return EvalStatus::kAskMeAgainLater;
-      }
-
-      result->target_version_prefix = *kiosk_required_platform_version_p;
-      LOG(INFO) << "Allow kiosk app to control Chrome version policy is set, "
-                << "target version is "
-                << (!kiosk_required_platform_version_p->empty()
-                        ? *kiosk_required_platform_version_p
-                        : std::string("latest"));
-    } else {
-      // Determine whether a target version prefix is dictated by policy.
-      const string* target_version_prefix_p = ec->GetValue(
-          dp_provider->var_target_version_prefix());
-      if (target_version_prefix_p)
-        result->target_version_prefix = *target_version_prefix_p;
-    }
-
-    // Determine whether a target channel is dictated by policy.
-    const bool* release_channel_delegated_p = ec->GetValue(
-        dp_provider->var_release_channel_delegated());
-    if (release_channel_delegated_p && !(*release_channel_delegated_p)) {
-      const string* release_channel_p = ec->GetValue(
-          dp_provider->var_release_channel());
-      if (release_channel_p)
-        result->target_channel = *release_channel_p;
-    }
-  }
-
-  // First, check to see if an interactive update was requested.
-  const UpdateRequestStatus* forced_update_requested_p = ec->GetValue(
-      updater_provider->var_forced_update_requested());
-  if (forced_update_requested_p &&
-      *forced_update_requested_p != UpdateRequestStatus::kNone) {
-    result->is_interactive =
-        (*forced_update_requested_p == UpdateRequestStatus::kInteractive);
-    LOG(INFO) << "Forced update signaled ("
-              << (result->is_interactive ?  "interactive" : "periodic")
-              << "), allowing update check.";
-    return EvalStatus::kSucceeded;
-  }
-
-  // The logic thereafter applies to periodic updates. Bear in mind that we
-  // should not return a final "no" if any of these criteria are not satisfied,
-  // because the system may still update due to an interactive update request.
-
-  // Unofficial builds should not perform periodic update checks.
-  const bool* is_official_build_p = ec->GetValue(
-      system_provider->var_is_official_build());
-  if (is_official_build_p && !(*is_official_build_p)) {
-    LOG(INFO) << "Unofficial build, blocking periodic update checks.";
-    return EvalStatus::kAskMeAgainLater;
-  }
-
-  // If OOBE is enabled, wait until it is completed.
-  const bool* is_oobe_enabled_p = ec->GetValue(
-      state->config_provider()->var_is_oobe_enabled());
-  if (is_oobe_enabled_p && *is_oobe_enabled_p) {
-    const bool* is_oobe_complete_p = ec->GetValue(
-        system_provider->var_is_oobe_complete());
-    if (is_oobe_complete_p && !(*is_oobe_complete_p)) {
-      LOG(INFO) << "OOBE not completed, blocking update checks.";
-      return EvalStatus::kAskMeAgainLater;
-    }
-  }
-
-  // Ensure that periodic update checks are timed properly.
-  Time next_update_check;
-  if (NextUpdateCheckTime(ec, state, error, &next_update_check) !=
-      EvalStatus::kSucceeded) {
-    return EvalStatus::kFailed;
-  }
-  if (!ec->IsWallclockTimeGreaterThan(next_update_check)) {
-    LOG(INFO) << "Periodic check interval not satisfied, blocking until "
-              << chromeos_update_engine::utils::ToString(next_update_check);
-    return EvalStatus::kAskMeAgainLater;
-  }
-
-  // It is time to check for an update.
-  LOG(INFO) << "Allowing update check.";
-  return EvalStatus::kSucceeded;
 }
 
 EvalStatus ChromeOSPolicy::UpdateCanBeApplied(EvaluationContext* ec,
@@ -626,92 +550,6 @@
   return status;
 }
 
-EvalStatus ChromeOSPolicy::NextUpdateCheckTime(EvaluationContext* ec,
-                                               State* state, string* error,
-                                               Time* next_update_check) const {
-  UpdaterProvider* const updater_provider = state->updater_provider();
-
-  // Don't check for updates too often. We limit the update checks to once every
-  // some interval. The interval is kTimeoutInitialInterval the first time and
-  // kTimeoutPeriodicInterval for the subsequent update checks. If the update
-  // check fails, we increase the interval between the update checks
-  // exponentially until kTimeoutMaxBackoffInterval. Finally, to avoid having
-  // many chromebooks running update checks at the exact same time, we add some
-  // fuzz to the interval.
-  const Time* updater_started_time =
-      ec->GetValue(updater_provider->var_updater_started_time());
-  POLICY_CHECK_VALUE_AND_FAIL(updater_started_time, error);
-
-  const Time* last_checked_time =
-      ec->GetValue(updater_provider->var_last_checked_time());
-
-  const uint64_t* seed = ec->GetValue(state->random_provider()->var_seed());
-  POLICY_CHECK_VALUE_AND_FAIL(seed, error);
-
-  PRNG prng(*seed);
-
-  // If this is the first attempt, compute and return an initial value.
-  if (!last_checked_time || *last_checked_time < *updater_started_time) {
-    *next_update_check = *updater_started_time + FuzzedInterval(
-        &prng, kTimeoutInitialInterval, kTimeoutRegularFuzz);
-    return EvalStatus::kSucceeded;
-  }
-
-  // Check whether the server is enforcing a poll interval; if not, this value
-  // will be zero.
-  const unsigned int* server_dictated_poll_interval = ec->GetValue(
-      updater_provider->var_server_dictated_poll_interval());
-  POLICY_CHECK_VALUE_AND_FAIL(server_dictated_poll_interval, error);
-
-  int interval = *server_dictated_poll_interval;
-  int fuzz = 0;
-
-  // If no poll interval was dictated by server compute a back-off period,
-  // starting from a predetermined base periodic interval and increasing
-  // exponentially by the number of consecutive failed attempts.
-  if (interval == 0) {
-    const unsigned int* consecutive_failed_update_checks = ec->GetValue(
-        updater_provider->var_consecutive_failed_update_checks());
-    POLICY_CHECK_VALUE_AND_FAIL(consecutive_failed_update_checks, error);
-
-    interval = kTimeoutPeriodicInterval;
-    unsigned int num_failures = *consecutive_failed_update_checks;
-    while (interval < kTimeoutMaxBackoffInterval && num_failures) {
-      interval *= 2;
-      num_failures--;
-    }
-  }
-
-  // We cannot back off longer than the predetermined maximum interval.
-  if (interval > kTimeoutMaxBackoffInterval)
-    interval = kTimeoutMaxBackoffInterval;
-
-  // We cannot back off shorter than the predetermined periodic interval. Also,
-  // in this case set the fuzz to a predetermined regular value.
-  if (interval <= kTimeoutPeriodicInterval) {
-    interval = kTimeoutPeriodicInterval;
-    fuzz = kTimeoutRegularFuzz;
-  }
-
-  // If not otherwise determined, defer to a fuzz of +/-(interval / 2).
-  if (fuzz == 0)
-    fuzz = interval;
-
-  *next_update_check = *last_checked_time + FuzzedInterval(
-      &prng, interval, fuzz);
-  return EvalStatus::kSucceeded;
-}
-
-TimeDelta ChromeOSPolicy::FuzzedInterval(PRNG* prng, int interval, int fuzz) {
-  DCHECK_GE(interval, 0);
-  DCHECK_GE(fuzz, 0);
-  int half_fuzz = fuzz / 2;
-  // This guarantees the output interval is non negative.
-  int interval_min = max(interval - half_fuzz, 0);
-  int interval_max = interval + half_fuzz;
-  return TimeDelta::FromSeconds(prng->RandMinMax(interval_min, interval_max));
-}
-
 EvalStatus ChromeOSPolicy::UpdateBackoffAndDownloadUrl(
     EvaluationContext* ec, State* state, string* error,
     UpdateBackoffAndDownloadUrlResult* result,
@@ -883,11 +721,13 @@
     PRNG prng(*seed);
     int exp = min(update_state.num_failures,
                        static_cast<int>(sizeof(int)) * 8 - 2);
-    TimeDelta backoff_interval = TimeDelta::FromDays(
-        min(1 << exp, kAttemptBackoffMaxIntervalInDays));
-    TimeDelta backoff_fuzz = TimeDelta::FromHours(kAttemptBackoffFuzzInHours);
-    TimeDelta wait_period = FuzzedInterval(&prng, backoff_interval.InSeconds(),
-                                           backoff_fuzz.InSeconds());
+    TimeDelta backoff_interval = TimeDelta::FromDays(min(
+        1 << exp,
+        kNextUpdateCheckPolicyConstants.attempt_backoff_max_interval_in_days));
+    TimeDelta backoff_fuzz = TimeDelta::FromHours(
+        kNextUpdateCheckPolicyConstants.attempt_backoff_fuzz_in_hours);
+    TimeDelta wait_period = NextUpdateCheckTimePolicyImpl::FuzzedInterval(
+        &prng, backoff_interval.InSeconds(), backoff_fuzz.InSeconds());
     backoff_expiry = err_time + wait_period;
 
     // If the newly computed backoff already expired, nullify it.
diff --git a/update_manager/chromeos_policy.h b/update_manager/chromeos_policy.h
index 283bedc..67c0d15 100644
--- a/update_manager/chromeos_policy.h
+++ b/update_manager/chromeos_policy.h
@@ -20,10 +20,9 @@
 #include <string>
 
 #include <base/time/time.h>
-#include <gtest/gtest_prod.h>  // for FRIEND_TEST
 
-#include "update_engine/update_manager/policy.h"
-#include "update_engine/update_manager/prng.h"
+#include "update_engine/update_manager/next_update_check_policy_impl.h"
+#include "update_engine/update_manager/policy_utils.h"
 
 namespace chromeos_update_manager {
 
@@ -98,12 +97,6 @@
 
  private:
   friend class UmChromeOSPolicyTest;
-  FRIEND_TEST(UmChromeOSPolicyTest,
-              FirstCheckIsAtMostInitialIntervalAfterStart);
-  FRIEND_TEST(UmChromeOSPolicyTest, RecurringCheckBaseIntervalAndFuzz);
-  FRIEND_TEST(UmChromeOSPolicyTest, RecurringCheckBackoffIntervalAndFuzz);
-  FRIEND_TEST(UmChromeOSPolicyTest, RecurringCheckServerDictatedPollInterval);
-  FRIEND_TEST(UmChromeOSPolicyTest, ExponentialBackoffIsCapped);
   FRIEND_TEST(UmChromeOSPolicyTest, UpdateCheckAllowedWaitsForTheTimeout);
   FRIEND_TEST(UmChromeOSPolicyTest, UpdateCheckAllowedWaitsForOOBE);
   FRIEND_TEST(UmChromeOSPolicyTest,
@@ -125,38 +118,13 @@
   // Auxiliary constant (zero by default).
   const base::TimeDelta kZeroInterval;
 
-  // Default update check timeout interval/fuzz values used to compute the
-  // NextUpdateCheckTime(), in seconds. Actual fuzz is within +/- half of the
-  // indicated value.
-  static const int kTimeoutInitialInterval;
-  static const int kTimeoutPeriodicInterval;
-  static const int kTimeoutMaxBackoffInterval;
-  static const int kTimeoutRegularFuzz;
-
-  // Maximum update attempt backoff interval and fuzz.
-  static const int kAttemptBackoffMaxIntervalInDays;
-  static const int kAttemptBackoffFuzzInHours;
+  static const NextUpdateCheckPolicyConstants kNextUpdateCheckPolicyConstants;
 
   // Maximum number of times we'll allow using P2P for the same update payload.
   static const int kMaxP2PAttempts;
   // Maximum period of time allowed for download a payload via P2P, in seconds.
   static const int kMaxP2PAttemptsPeriodInSeconds;
 
-  // A private policy implementation returning the wallclock timestamp when
-  // the next update check should happen.
-  // TODO(garnold) We should probably change that to infer a monotonic
-  // timestamp, which will make the update check intervals more resilient to
-  // clock skews. Might require switching some of the variables exported by the
-  // UpdaterProvider to report monotonic time, as well.
-  EvalStatus NextUpdateCheckTime(EvaluationContext* ec, State* state,
-                                 std::string* error,
-                                 base::Time* next_update_check) const;
-
-  // Returns a TimeDelta based on the provided |interval| seconds +/- half
-  // |fuzz| seconds. The return value is guaranteed to be a non-negative
-  // TimeDelta.
-  static base::TimeDelta FuzzedInterval(PRNG* prng, int interval, int fuzz);
-
   // A private policy for determining backoff and the download URL to use.
   // Within |update_state|, |backoff_expiry| and |is_backoff_disabled| are used
   // for determining whether backoff is still in effect; if not,
diff --git a/update_manager/chromeos_policy_unittest.cc b/update_manager/chromeos_policy_unittest.cc
index 63fa0f7..df29e8c 100644
--- a/update_manager/chromeos_policy_unittest.cc
+++ b/update_manager/chromeos_policy_unittest.cc
@@ -16,72 +16,35 @@
 
 #include "update_engine/update_manager/chromeos_policy.h"
 
+#include <memory>
 #include <set>
-#include <string>
-#include <tuple>
-#include <vector>
 
-#include <base/time/time.h>
-#include <brillo/message_loops/fake_message_loop.h>
-#include <gtest/gtest.h>
-
-#include "update_engine/common/fake_clock.h"
-#include "update_engine/update_manager/evaluation_context.h"
-#include "update_engine/update_manager/fake_state.h"
-#include "update_engine/update_manager/umtest_utils.h"
+#include "update_engine/update_manager/next_update_check_policy_impl.h"
+#include "update_engine/update_manager/policy_test_utils.h"
 
 using base::Time;
 using base::TimeDelta;
 using chromeos_update_engine::ConnectionTethering;
 using chromeos_update_engine::ConnectionType;
 using chromeos_update_engine::ErrorCode;
-using chromeos_update_engine::FakeClock;
 using std::set;
 using std::string;
-using std::tuple;
-using std::vector;
 
 namespace chromeos_update_manager {
 
-class UmChromeOSPolicyTest : public ::testing::Test {
+class UmChromeOSPolicyTest : public UmPolicyTestBase {
  protected:
+  UmChromeOSPolicyTest() : UmPolicyTestBase() {
+    policy_ = std::make_unique<ChromeOSPolicy>();
+  }
+
   void SetUp() override {
-    loop_.SetAsCurrent();
-    SetUpDefaultClock();
-    eval_ctx_ = new EvaluationContext(&fake_clock_, TimeDelta::FromSeconds(5));
-    SetUpDefaultState();
+    UmPolicyTestBase::SetUp();
     SetUpDefaultDevicePolicy();
   }
 
-  void TearDown() override {
-    EXPECT_FALSE(loop_.PendingTasks());
-  }
-
-  // Sets the clock to fixed values.
-  void SetUpDefaultClock() {
-    fake_clock_.SetMonotonicTime(Time::FromInternalValue(12345678L));
-    fake_clock_.SetWallclockTime(Time::FromInternalValue(12345678901234L));
-  }
-
-  void SetUpDefaultState() {
-    fake_state_.updater_provider()->var_updater_started_time()->reset(
-        new Time(fake_clock_.GetWallclockTime()));
-    fake_state_.updater_provider()->var_last_checked_time()->reset(
-        new Time(fake_clock_.GetWallclockTime()));
-    fake_state_.updater_provider()->var_consecutive_failed_update_checks()->
-        reset(new unsigned int{0});
-    fake_state_.updater_provider()->var_server_dictated_poll_interval()->
-        reset(new unsigned int{0});
-    fake_state_.updater_provider()->var_forced_update_requested()->
-        reset(new UpdateRequestStatus{UpdateRequestStatus::kNone});
-
-    fake_state_.random_provider()->var_seed()->reset(
-        new uint64_t(4));  // chosen by fair dice roll.
-                           // guaranteed to be random.
-
-    // No device policy loaded by default.
-    fake_state_.device_policy_provider()->var_device_policy_is_loaded()->reset(
-        new bool(false));
+  void SetUpDefaultState() override {
+    UmPolicyTestBase::SetUpDefaultState();
 
     // OOBE is enabled by default.
     fake_state_.config_provider()->var_is_oobe_enabled()->reset(
@@ -122,14 +85,17 @@
         reset(new bool(true));
   }
 
-  // Configures the UpdateCheckAllowed policy to return a desired value by
+  // Configures the policy to return a desired value from UpdateCheckAllowed by
   // faking the current wall clock time as needed. Restores the default state.
   // This is used when testing policies that depend on this one.
-  void SetUpdateCheckAllowed(bool allow_check) {
+  //
+  // Note that the default implementation relies on NextUpdateCheckPolicyImpl to
+  // set the FakeClock to the appropriate time.
+  virtual void SetUpdateCheckAllowed(bool allow_check) {
     Time next_update_check;
-    ExpectPolicyStatus(EvalStatus::kSucceeded,
-                       &ChromeOSPolicy::NextUpdateCheckTime,
-                       &next_update_check);
+    CallMethodWithContext(&NextUpdateCheckTimePolicyImpl::NextUpdateCheckTime,
+                          &next_update_check,
+                          ChromeOSPolicy::kNextUpdateCheckPolicyConstants);
     SetUpDefaultState();
     SetUpDefaultDevicePolicy();
     Time curr_time = next_update_check;
@@ -139,178 +105,8 @@
       curr_time -= TimeDelta::FromSeconds(1);
     fake_clock_.SetWallclockTime(curr_time);
   }
-
-  // Returns a default UpdateState structure:
-  UpdateState GetDefaultUpdateState(TimeDelta first_seen_period) {
-    Time first_seen_time = fake_clock_.GetWallclockTime() - first_seen_period;
-    UpdateState update_state = UpdateState();
-
-    // This is a non-interactive check returning a delta payload, seen for the
-    // first time (|first_seen_period| ago). Clearly, there were no failed
-    // attempts so far.
-    update_state.is_interactive = false;
-    update_state.is_delta_payload = false;
-    update_state.first_seen = first_seen_time;
-    update_state.num_checks = 1;
-    update_state.num_failures = 0;
-    update_state.failures_last_updated = Time();  // Needs to be zero.
-    // There's a single HTTP download URL with a maximum of 10 retries.
-    update_state.download_urls = vector<string>{"http://fake/url/"};
-    update_state.download_errors_max = 10;
-    // Download was never attempted.
-    update_state.last_download_url_idx = -1;
-    update_state.last_download_url_num_errors = 0;
-    // There were no download errors.
-    update_state.download_errors = vector<tuple<int, ErrorCode, Time>>();
-    // P2P is not disabled by Omaha.
-    update_state.p2p_downloading_disabled = false;
-    update_state.p2p_sharing_disabled = false;
-    // P2P was not attempted.
-    update_state.p2p_num_attempts = 0;
-    update_state.p2p_first_attempted = Time();
-    // No active backoff period, backoff is not disabled by Omaha.
-    update_state.backoff_expiry = Time();
-    update_state.is_backoff_disabled = false;
-    // There is no active scattering wait period (max 7 days allowed) nor check
-    // threshold (none allowed).
-    update_state.scatter_wait_period = TimeDelta();
-    update_state.scatter_check_threshold = 0;
-    update_state.scatter_wait_period_max = TimeDelta::FromDays(7);
-    update_state.scatter_check_threshold_min = 0;
-    update_state.scatter_check_threshold_max = 0;
-
-    return update_state;
-  }
-
-  // Runs the passed |policy_method| policy and expects it to return the
-  // |expected| return value.
-  template<typename T, typename R, typename... Args>
-  void ExpectPolicyStatus(
-      EvalStatus expected,
-      T policy_method,
-      R* result, Args... args) {
-    string error = "<None>";
-    eval_ctx_->ResetEvaluation();
-    EXPECT_EQ(expected,
-              (policy_.*policy_method)(eval_ctx_.get(), &fake_state_, &error,
-                                       result, args...))
-        << "Returned error: " << error
-        << "\nEvaluation context: " << eval_ctx_->DumpContext();
-  }
-
-  brillo::FakeMessageLoop loop_{nullptr};
-  FakeClock fake_clock_;
-  FakeState fake_state_;
-  scoped_refptr<EvaluationContext> eval_ctx_;
-  ChromeOSPolicy policy_;  // ChromeOSPolicy under test.
 };
 
-TEST_F(UmChromeOSPolicyTest, FirstCheckIsAtMostInitialIntervalAfterStart) {
-  Time next_update_check;
-
-  // Set the last update time so it'll appear as if this is a first update check
-  // in the lifetime of the current updater.
-  fake_state_.updater_provider()->var_last_checked_time()->reset(
-      new Time(fake_clock_.GetWallclockTime() - TimeDelta::FromMinutes(10)));
-
-  ExpectPolicyStatus(EvalStatus::kSucceeded,
-                     &ChromeOSPolicy::NextUpdateCheckTime, &next_update_check);
-
-  EXPECT_LE(fake_clock_.GetWallclockTime(), next_update_check);
-  EXPECT_GE(
-      fake_clock_.GetWallclockTime() + TimeDelta::FromSeconds(
-          ChromeOSPolicy::kTimeoutInitialInterval +
-          ChromeOSPolicy::kTimeoutRegularFuzz / 2),
-      next_update_check);
-}
-
-TEST_F(UmChromeOSPolicyTest, RecurringCheckBaseIntervalAndFuzz) {
-  // Ensure that we're using the correct interval (kPeriodicInterval) and fuzz
-  // (kTimeoutRegularFuzz) as base values for period updates.
-  Time next_update_check;
-
-  ExpectPolicyStatus(EvalStatus::kSucceeded,
-                     &ChromeOSPolicy::NextUpdateCheckTime, &next_update_check);
-
-  EXPECT_LE(
-      fake_clock_.GetWallclockTime() + TimeDelta::FromSeconds(
-          ChromeOSPolicy::kTimeoutPeriodicInterval -
-          ChromeOSPolicy::kTimeoutRegularFuzz / 2),
-      next_update_check);
-  EXPECT_GE(
-      fake_clock_.GetWallclockTime() + TimeDelta::FromSeconds(
-          ChromeOSPolicy::kTimeoutPeriodicInterval +
-          ChromeOSPolicy::kTimeoutRegularFuzz / 2),
-      next_update_check);
-}
-
-TEST_F(UmChromeOSPolicyTest, RecurringCheckBackoffIntervalAndFuzz) {
-  // Ensure that we're properly backing off and fuzzing in the presence of
-  // failed updates attempts.
-  Time next_update_check;
-
-  fake_state_.updater_provider()->var_consecutive_failed_update_checks()->
-      reset(new unsigned int{2});
-
-  ExpectPolicyStatus(EvalStatus::kSucceeded,
-                     &ChromeOSPolicy::NextUpdateCheckTime, &next_update_check);
-
-  int expected_interval = ChromeOSPolicy::kTimeoutPeriodicInterval * 4;
-  EXPECT_LE(
-      fake_clock_.GetWallclockTime() + TimeDelta::FromSeconds(
-          expected_interval - expected_interval / 2),
-      next_update_check);
-  EXPECT_GE(
-      fake_clock_.GetWallclockTime() + TimeDelta::FromSeconds(
-          expected_interval + expected_interval / 2),
-      next_update_check);
-}
-
-TEST_F(UmChromeOSPolicyTest, RecurringCheckServerDictatedPollInterval) {
-  // Policy honors the server provided check poll interval.
-  Time next_update_check;
-
-  const unsigned int kInterval = ChromeOSPolicy::kTimeoutPeriodicInterval * 4;
-  fake_state_.updater_provider()->var_server_dictated_poll_interval()->
-      reset(new unsigned int{kInterval});
-  // We should not be backing off in this case.
-  fake_state_.updater_provider()->var_consecutive_failed_update_checks()->
-      reset(new unsigned int{2});
-
-  ExpectPolicyStatus(EvalStatus::kSucceeded,
-                     &ChromeOSPolicy::NextUpdateCheckTime, &next_update_check);
-
-  EXPECT_LE(
-      fake_clock_.GetWallclockTime() + TimeDelta::FromSeconds(
-          kInterval - kInterval / 2),
-      next_update_check);
-  EXPECT_GE(
-      fake_clock_.GetWallclockTime() + TimeDelta::FromSeconds(
-          kInterval + kInterval / 2),
-      next_update_check);
-}
-
-TEST_F(UmChromeOSPolicyTest, ExponentialBackoffIsCapped) {
-  Time next_update_check;
-
-  fake_state_.updater_provider()->var_consecutive_failed_update_checks()->
-      reset(new unsigned int{100});
-
-  ExpectPolicyStatus(EvalStatus::kSucceeded,
-                     &ChromeOSPolicy::NextUpdateCheckTime, &next_update_check);
-
-  EXPECT_LE(
-      fake_clock_.GetWallclockTime() + TimeDelta::FromSeconds(
-          ChromeOSPolicy::kTimeoutMaxBackoffInterval -
-          ChromeOSPolicy::kTimeoutMaxBackoffInterval / 2),
-      next_update_check);
-  EXPECT_GE(
-      fake_clock_.GetWallclockTime() + TimeDelta::FromSeconds(
-          ChromeOSPolicy::kTimeoutMaxBackoffInterval +
-          ChromeOSPolicy::kTimeoutMaxBackoffInterval /2),
-      next_update_check);
-}
-
 TEST_F(UmChromeOSPolicyTest, UpdateCheckAllowedWaitsForTheTimeout) {
   // We get the next update_check timestamp from the policy's private method
   // and then we check the public method respects that value on the normal
@@ -321,8 +117,9 @@
 
   fake_state_.updater_provider()->var_last_checked_time()->reset(
       new Time(last_checked_time));
-  ExpectPolicyStatus(EvalStatus::kSucceeded,
-                     &ChromeOSPolicy::NextUpdateCheckTime, &next_update_check);
+  CallMethodWithContext(&NextUpdateCheckTimePolicyImpl::NextUpdateCheckTime,
+                        &next_update_check,
+                        ChromeOSPolicy::kNextUpdateCheckPolicyConstants);
 
   UpdateCheckParams result;
 
@@ -356,8 +153,9 @@
 
   fake_state_.updater_provider()->var_last_checked_time()->reset(
       new Time(last_checked_time));
-  ExpectPolicyStatus(EvalStatus::kSucceeded,
-                     &ChromeOSPolicy::NextUpdateCheckTime, &next_update_check);
+  CallMethodWithContext(&NextUpdateCheckTimePolicyImpl::NextUpdateCheckTime,
+                        &next_update_check,
+                        ChromeOSPolicy::kNextUpdateCheckPolicyConstants);
 
   SetUpDefaultClock();
   SetUpDefaultState();
diff --git a/update_manager/enterprise_device_policy_impl.cc b/update_manager/enterprise_device_policy_impl.cc
new file mode 100644
index 0000000..94518a1
--- /dev/null
+++ b/update_manager/enterprise_device_policy_impl.cc
@@ -0,0 +1,95 @@
+//
+// Copyright (C) 2017 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#include "update_engine/update_manager/enterprise_device_policy_impl.h"
+
+#include "update_engine/common/utils.h"
+
+using std::string;
+
+namespace chromeos_update_manager {
+
+// Check to see if Enterprise-managed (has DevicePolicy) and/or Kiosk-mode.  If
+// so, then defer to those settings.
+EvalStatus EnterpriseDevicePolicyImpl::UpdateCheckAllowed(
+    EvaluationContext* ec,
+    State* state,
+    std::string* error,
+    UpdateCheckParams* result) const {
+  DevicePolicyProvider* const dp_provider = state->device_policy_provider();
+  SystemProvider* const system_provider = state->system_provider();
+
+  const bool* device_policy_is_loaded_p =
+      ec->GetValue(dp_provider->var_device_policy_is_loaded());
+  if (device_policy_is_loaded_p && *device_policy_is_loaded_p) {
+    bool kiosk_app_control_chrome_version = false;
+
+    // Check whether updates are disabled by policy.
+    const bool* update_disabled_p =
+        ec->GetValue(dp_provider->var_update_disabled());
+    if (update_disabled_p && *update_disabled_p) {
+      // Check whether allow kiosk app to control chrome version policy. This
+      // policy is only effective when AU is disabled by admin.
+      const bool* allow_kiosk_app_control_chrome_version_p = ec->GetValue(
+          dp_provider->var_allow_kiosk_app_control_chrome_version());
+      kiosk_app_control_chrome_version =
+          allow_kiosk_app_control_chrome_version_p &&
+          *allow_kiosk_app_control_chrome_version_p;
+      if (!kiosk_app_control_chrome_version) {
+        // No kiosk pin chrome version policy. AU is really disabled.
+        LOG(INFO) << "Updates disabled by policy, blocking update checks.";
+        return EvalStatus::kAskMeAgainLater;
+      }
+    }
+
+    if (kiosk_app_control_chrome_version) {
+      // Get the required platform version from Chrome.
+      const string* kiosk_required_platform_version_p =
+          ec->GetValue(system_provider->var_kiosk_required_platform_version());
+      if (!kiosk_required_platform_version_p) {
+        LOG(INFO) << "Kiosk app required platform version is not fetched, "
+                     "blocking update checks";
+        return EvalStatus::kAskMeAgainLater;
+      }
+
+      result->target_version_prefix = *kiosk_required_platform_version_p;
+      LOG(INFO) << "Allow kiosk app to control Chrome version policy is set,"
+                << ", target version is "
+                << (kiosk_required_platform_version_p
+                        ? *kiosk_required_platform_version_p
+                        : std::string("latest"));
+    } else {
+      // Determine whether a target version prefix is dictated by policy.
+      const string* target_version_prefix_p =
+          ec->GetValue(dp_provider->var_target_version_prefix());
+      if (target_version_prefix_p)
+        result->target_version_prefix = *target_version_prefix_p;
+    }
+
+    // Determine whether a target channel is dictated by policy.
+    const bool* release_channel_delegated_p =
+        ec->GetValue(dp_provider->var_release_channel_delegated());
+    if (release_channel_delegated_p && !(*release_channel_delegated_p)) {
+      const string* release_channel_p =
+          ec->GetValue(dp_provider->var_release_channel());
+      if (release_channel_p)
+        result->target_channel = *release_channel_p;
+    }
+  }
+  return EvalStatus::kContinue;
+}
+
+}  // namespace chromeos_update_manager
diff --git a/update_manager/enterprise_device_policy_impl.h b/update_manager/enterprise_device_policy_impl.h
new file mode 100644
index 0000000..4b97fda
--- /dev/null
+++ b/update_manager/enterprise_device_policy_impl.h
@@ -0,0 +1,48 @@
+//
+// Copyright (C) 2017 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#ifndef UPDATE_ENGINE_UPDATE_MANAGER_ENTERPRISE_DEVICE_POLICY_IMPL_H_
+#define UPDATE_ENGINE_UPDATE_MANAGER_ENTERPRISE_DEVICE_POLICY_IMPL_H_
+
+#include <string>
+
+#include "update_engine/update_manager/policy_utils.h"
+
+namespace chromeos_update_manager {
+
+// Check to see if Enterprise-managed (has DevicePolicy) and/or Kiosk-mode.  If
+// so, then defer to those settings.
+class EnterpriseDevicePolicyImpl : public PolicyImplBase {
+ public:
+  EnterpriseDevicePolicyImpl() = default;
+  ~EnterpriseDevicePolicyImpl() override = default;
+
+  std::string PolicyName() const override {
+    return "EnterpriseDevicePolicyImpl";
+  }
+  // Policy overrides.
+  EvalStatus UpdateCheckAllowed(EvaluationContext* ec,
+                                State* state,
+                                std::string* error,
+                                UpdateCheckParams* result) const override;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(EnterpriseDevicePolicyImpl);
+};
+
+}  // namespace chromeos_update_manager
+
+#endif  // UPDATE_ENGINE_UPDATE_MANAGER_ENTERPRISE_DEVICE_POLICY_IMPL_H_
diff --git a/update_manager/out_of_box_experience_policy_impl.cc b/update_manager/out_of_box_experience_policy_impl.cc
new file mode 100644
index 0000000..8dcb560
--- /dev/null
+++ b/update_manager/out_of_box_experience_policy_impl.cc
@@ -0,0 +1,43 @@
+//
+// Copyright (C) 2017 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#include "update_engine/update_manager/out_of_box_experience_policy_impl.h"
+
+#include "update_engine/common/utils.h"
+
+namespace chromeos_update_manager {
+
+EvalStatus OobePolicyImpl::UpdateCheckAllowed(EvaluationContext* ec,
+                                              State* state,
+                                              std::string* error,
+                                              UpdateCheckParams* result) const {
+  SystemProvider* const system_provider = state->system_provider();
+
+  // If OOBE is enabled, wait until it is completed.
+  const bool* is_oobe_enabled_p =
+      ec->GetValue(state->config_provider()->var_is_oobe_enabled());
+  if (is_oobe_enabled_p && *is_oobe_enabled_p) {
+    const bool* is_oobe_complete_p =
+        ec->GetValue(system_provider->var_is_oobe_complete());
+    if (is_oobe_complete_p && !(*is_oobe_complete_p)) {
+      LOG(INFO) << "OOBE not completed, blocking update checks.";
+      return EvalStatus::kAskMeAgainLater;
+    }
+  }
+  return EvalStatus::kContinue;
+}
+
+}  // namespace chromeos_update_manager
diff --git a/update_manager/out_of_box_experience_policy_impl.h b/update_manager/out_of_box_experience_policy_impl.h
new file mode 100644
index 0000000..ec1997b
--- /dev/null
+++ b/update_manager/out_of_box_experience_policy_impl.h
@@ -0,0 +1,46 @@
+//
+// Copyright (C) 2017 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#ifndef UPDATE_ENGINE_UPDATE_MANAGER_OUT_OF_BOX_EXPERIENCE_POLICY_IMPL_H_
+#define UPDATE_ENGINE_UPDATE_MANAGER_OUT_OF_BOX_EXPERIENCE_POLICY_IMPL_H_
+
+#include <string>
+
+#include "update_engine/update_manager/policy_utils.h"
+
+namespace chromeos_update_manager {
+
+// If OOBE is enabled, wait until it is completed.
+class OobePolicyImpl : public PolicyImplBase {
+ public:
+  OobePolicyImpl() = default;
+  ~OobePolicyImpl() override = default;
+
+  std::string PolicyName() const override { return "OobePolicyImpl"; }
+
+  // Policy overrides.
+  EvalStatus UpdateCheckAllowed(EvaluationContext* ec,
+                                State* state,
+                                std::string* error,
+                                UpdateCheckParams* result) const override;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(OobePolicyImpl);
+};
+
+}  // namespace chromeos_update_manager
+
+#endif  // UPDATE_ENGINE_UPDATE_MANAGER_OUT_OF_BOX_EXPERIENCE_POLICY_IMPL_H_