Policy for AndroidThings

Adds a separate Policy implementation for AndroidThings, which is not
dependent on the ChromeOSPolicy implementation. It uses some new policy
implementation fragments (policy features) which were in ChromeOSPolicy.
ChromeOSPolicy will be separately refactored to use the policy
implementation fragments.

The AndroidThingsPolicy and ChromeOSPolicy classes (and dependencies)
are compiled in as needed, based on the platform.  Both classes and
dependencies are compiled into the unit test binary to ensure the proper
behavior of both.

Some unit tests are slightly duplicated across the Policy and policy
implementation fragments to confirm that the policy fragments are
consulted in the proper order/precedence.

Bug: 66016687
Test: Unit tests, manual OTA
Change-Id: I220e5720e0077309931eda70155523b3c0507567
(cherry picked from commit cd0d7bda708a44c2d839d0497e1791b42ed06e3d)
diff --git a/Android.mk b/Android.mk
index 6a23168..2470865 100644
--- a/Android.mk
+++ b/Android.mk
@@ -305,10 +305,14 @@
     proxy_resolver.cc \
     real_system_state.cc \
     update_attempter.cc \
+    update_manager/android_things_policy.cc \
     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/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/policy.cc \
     update_manager/real_config_provider.cc \
     update_manager/real_device_policy_provider.cc \
@@ -969,10 +973,14 @@
     payload_state_unittest.cc \
     parcelable_update_engine_status_unittest.cc \
     update_attempter_unittest.cc \
+    update_manager/android_things_policy_unittest.cc \
     update_manager/boxed_value_unittest.cc \
+    update_manager/chromeos_policy.cc \
     update_manager/chromeos_policy_unittest.cc \
     update_manager/evaluation_context_unittest.cc \
     update_manager/generic_variables_unittest.cc \
+    update_manager/next_update_check_policy_impl_unittest.cc \
+    update_manager/policy_test_utils.cc \
     update_manager/prng_unittest.cc \
     update_manager/real_device_policy_provider_unittest.cc \
     update_manager/real_random_provider_unittest.cc \
diff --git a/update_manager/android_things_policy.cc b/update_manager/android_things_policy.cc
new file mode 100644
index 0000000..2304f12
--- /dev/null
+++ b/update_manager/android_things_policy.cc
@@ -0,0 +1,152 @@
+//
+// 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/android_things_policy.h"
+
+#include <string>
+#include <vector>
+
+#include <base/logging.h>
+#include <base/time/time.h>
+
+#include "update_engine/update_manager/enough_slots_ab_updates_policy_impl.h"
+#include "update_engine/update_manager/interactive_update_policy_impl.h"
+#include "update_engine/update_manager/official_build_check_policy_impl.h"
+
+using base::Time;
+using chromeos_update_engine::ErrorCode;
+using std::string;
+using std::vector;
+
+namespace chromeos_update_manager {
+
+const NextUpdateCheckPolicyConstants
+    AndroidThingsPolicy::kNextUpdateCheckPolicyConstants = {
+        .timeout_initial_interval = 7 * 60,
+        .timeout_periodic_interval = 5 * 60 * 60,
+        .timeout_max_backoff_interval = 26 * 60 * 60,
+        .timeout_regular_fuzz = 10 * 60,
+        .attempt_backoff_max_interval_in_days = 16,
+        .attempt_backoff_fuzz_in_hours = 12,
+};
+
+EvalStatus AndroidThingsPolicy::UpdateCheckAllowed(
+    EvaluationContext* ec,
+    State* state,
+    string* error,
+    UpdateCheckParams* result) const {
+  // Set the default return values.
+  result->updates_enabled = true;
+  result->target_channel.clear();
+  result->target_version_prefix.clear();
+  result->is_interactive = false;
+
+  // Build a list of policies to consult.  Note that each policy may modify the
+  // result structure, even if it signals kContinue.
+  EnoughSlotsAbUpdatesPolicyImpl enough_slots_ab_updates_policy;
+  OnlyUpdateOfficialBuildsPolicyImpl only_update_official_builds_policy;
+  InteractiveUpdatePolicyImpl interactive_update_policy;
+  NextUpdateCheckTimePolicyImpl next_update_check_time_policy(
+      kNextUpdateCheckPolicyConstants);
+
+  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,
+
+      // Unofficial builds should not perform periodic update checks.
+      &only_update_official_builds_policy,
+
+      // Check to see if an interactive update was requested.
+      &interactive_update_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,
+  // as been setup, do that.  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 (status != EvalStatus::kContinue) {
+    return status;
+  } else {
+    // It is time to check for an update.
+    LOG(INFO) << "Allowing update check.";
+    return EvalStatus::kSucceeded;
+  }
+}
+
+// Always returns |EvalStatus::kSucceeded|
+EvalStatus AndroidThingsPolicy::UpdateCanBeApplied(
+    EvaluationContext* ec,
+    State* state,
+    string* error,
+    chromeos_update_engine::ErrorCode* result,
+    chromeos_update_engine::InstallPlan* install_plan) const {
+  *result = ErrorCode::kSuccess;
+  return EvalStatus::kSucceeded;
+}
+
+// Always returns |EvalStatus::kSucceeded|
+EvalStatus AndroidThingsPolicy::UpdateCanStart(EvaluationContext* ec,
+                                               State* state,
+                                               string* error,
+                                               UpdateDownloadParams* result,
+                                               UpdateState update_state) const {
+  // Update is good to go.
+  result->update_can_start = true;
+  return EvalStatus::kSucceeded;
+}
+
+// Always returns |EvalStatus::kSucceeded|
+EvalStatus AndroidThingsPolicy::UpdateDownloadAllowed(EvaluationContext* ec,
+                                                      State* state,
+                                                      string* error,
+                                                      bool* result) const {
+  // By default, we allow updates.
+  *result = true;
+  return EvalStatus::kSucceeded;
+}
+
+// P2P is always disabled.  Returns |result|==|false| and
+// |EvalStatus::kSucceeded|
+EvalStatus AndroidThingsPolicy::P2PEnabled(EvaluationContext* ec,
+                                           State* state,
+                                           string* error,
+                                           bool* result) const {
+  *result = false;
+  return EvalStatus::kSucceeded;
+}
+
+// This will return immediately with |EvalStatus::kSucceeded| and set
+// |result|==|false|
+EvalStatus AndroidThingsPolicy::P2PEnabledChanged(EvaluationContext* ec,
+                                                  State* state,
+                                                  string* error,
+                                                  bool* result,
+                                                  bool prev_result) const {
+  *result = false;
+  return EvalStatus::kSucceeded;
+}
+
+}  // namespace chromeos_update_manager
diff --git a/update_manager/android_things_policy.h b/update_manager/android_things_policy.h
new file mode 100644
index 0000000..6f8f4ad
--- /dev/null
+++ b/update_manager/android_things_policy.h
@@ -0,0 +1,91 @@
+//
+// 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_ANDROID_THINGS_POLICY_H_
+#define UPDATE_ENGINE_UPDATE_MANAGER_ANDROID_THINGS_POLICY_H_
+
+#include <string>
+
+#include "update_engine/update_manager/next_update_check_policy_impl.h"
+#include "update_engine/update_manager/policy_utils.h"
+
+namespace chromeos_update_manager {
+
+// AndroidThingsPolicy implements the policy-related logic used in
+// AndroidThings.
+class AndroidThingsPolicy : public Policy {
+ public:
+  AndroidThingsPolicy() = default;
+  ~AndroidThingsPolicy() override = default;
+
+  // Policy overrides.
+  EvalStatus UpdateCheckAllowed(EvaluationContext* ec,
+                                State* state,
+                                std::string* error,
+                                UpdateCheckParams* result) const override;
+
+  // Always returns |EvalStatus::kSucceeded|
+  EvalStatus UpdateCanBeApplied(
+      EvaluationContext* ec,
+      State* state,
+      std::string* error,
+      chromeos_update_engine::ErrorCode* result,
+      chromeos_update_engine::InstallPlan* install_plan) const override;
+
+  // Always returns |EvalStatus::kSucceeded|
+  EvalStatus UpdateCanStart(EvaluationContext* ec,
+                            State* state,
+                            std::string* error,
+                            UpdateDownloadParams* result,
+                            UpdateState update_state) const override;
+
+  // Always returns |EvalStatus::kSucceeded|
+  EvalStatus UpdateDownloadAllowed(EvaluationContext* ec,
+                                   State* state,
+                                   std::string* error,
+                                   bool* result) const override;
+
+  // P2P is always disabled.  Returns |result|==|false| and
+  // |EvalStatus::kSucceeded|
+  virtual EvalStatus P2PEnabled(EvaluationContext* ec,
+                                State* state,
+                                std::string* error,
+                                bool* result) const override;
+
+  // This will return immediately with |EvalStatus::kSucceeded| and set
+  // |result|==|false|
+  virtual EvalStatus P2PEnabledChanged(EvaluationContext* ec,
+                                       State* state,
+                                       std::string* error,
+                                       bool* result,
+                                       bool prev_result) const override;
+
+ protected:
+  // Policy override.
+  std::string PolicyName() const override { return "AndroidThingsPolicy"; }
+
+ private:
+  friend class UmAndroidThingsPolicyTest;
+  FRIEND_TEST(UmAndroidThingsPolicyTest, UpdateCheckAllowedWaitsForTheTimeout);
+
+  static const NextUpdateCheckPolicyConstants kNextUpdateCheckPolicyConstants;
+
+  DISALLOW_COPY_AND_ASSIGN(AndroidThingsPolicy);
+};
+
+}  // namespace chromeos_update_manager
+
+#endif  // UPDATE_ENGINE_UPDATE_MANAGER_ANDROID_THINGS_POLICY_H_
diff --git a/update_manager/android_things_policy_unittest.cc b/update_manager/android_things_policy_unittest.cc
new file mode 100644
index 0000000..8b7d128
--- /dev/null
+++ b/update_manager/android_things_policy_unittest.cc
@@ -0,0 +1,156 @@
+//
+// 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/android_things_policy.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;
+
+namespace chromeos_update_manager {
+
+class UmAndroidThingsPolicyTest : public UmPolicyTestBase {
+ protected:
+  UmAndroidThingsPolicyTest() {
+    policy_ = std::make_unique<AndroidThingsPolicy>();
+  }
+
+  void SetUpDefaultState() override {
+    UmPolicyTestBase::SetUpDefaultState();
+
+    // For the purpose of the tests, this is an official build
+    fake_state_.system_provider()->var_is_official_build()->reset(
+        new bool(true));
+    fake_state_.system_provider()->var_num_slots()->reset(new unsigned int(2));
+  }
+
+  // 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.
+  virtual void SetUpdateCheckAllowed(bool allow_check) {
+    Time next_update_check;
+    CallMethodWithContext(&NextUpdateCheckTimePolicyImpl::NextUpdateCheckTime,
+                          &next_update_check,
+                          AndroidThingsPolicy::kNextUpdateCheckPolicyConstants);
+    SetUpDefaultState();
+    Time curr_time = next_update_check;
+    if (allow_check)
+      curr_time += TimeDelta::FromSeconds(1);
+    else
+      curr_time -= TimeDelta::FromSeconds(1);
+    fake_clock_.SetWallclockTime(curr_time);
+  }
+};
+
+TEST_F(UmAndroidThingsPolicyTest, 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
+  // case.
+  Time next_update_check;
+  Time last_checked_time =
+      fake_clock_.GetWallclockTime() + TimeDelta::FromMinutes(1234);
+
+  LOG(INFO) << "last_checked_time: " << last_checked_time;
+  fake_state_.updater_provider()->var_last_checked_time()->reset(
+      new Time(last_checked_time));
+  CallMethodWithContext(&NextUpdateCheckTimePolicyImpl::NextUpdateCheckTime,
+                        &next_update_check,
+                        AndroidThingsPolicy::kNextUpdateCheckPolicyConstants);
+  LOG(INFO) << "Next check allowed at: " << next_update_check;
+
+  // Check that the policy blocks until the next_update_check is reached.
+  SetUpDefaultClock();
+  SetUpDefaultState();
+  fake_state_.updater_provider()->var_last_checked_time()->reset(
+      new Time(last_checked_time));
+  fake_clock_.SetWallclockTime(next_update_check - TimeDelta::FromSeconds(1));
+
+  UpdateCheckParams result;
+  ExpectPolicyStatus(
+      EvalStatus::kAskMeAgainLater, &Policy::UpdateCheckAllowed, &result);
+
+  SetUpDefaultClock();
+  SetUpDefaultState();
+  fake_state_.updater_provider()->var_last_checked_time()->reset(
+      new Time(last_checked_time));
+  fake_clock_.SetWallclockTime(next_update_check + TimeDelta::FromSeconds(1));
+  ExpectPolicyStatus(
+      EvalStatus::kSucceeded, &Policy::UpdateCheckAllowed, &result);
+  EXPECT_TRUE(result.updates_enabled);
+  EXPECT_FALSE(result.is_interactive);
+}
+
+TEST_F(UmAndroidThingsPolicyTest,
+       UpdateCheckAllowedUpdatesDisabledForUnofficialBuilds) {
+  // UpdateCheckAllowed should return kAskMeAgainLater if this is an unofficial
+  // build; we don't want periodic update checks on developer images.
+
+  fake_state_.system_provider()->var_is_official_build()->reset(
+      new bool(false));
+
+  UpdateCheckParams result;
+  ExpectPolicyStatus(
+      EvalStatus::kAskMeAgainLater, &Policy::UpdateCheckAllowed, &result);
+}
+
+TEST_F(UmAndroidThingsPolicyTest,
+       UpdateCheckAllowedUpdatesDisabledWhenNotEnoughSlotsAbUpdates) {
+  // UpdateCheckAllowed should return false (kSucceeded) if the image booted
+  // without enough slots to do A/B updates.
+
+  fake_state_.system_provider()->var_num_slots()->reset(new unsigned int(1));
+
+  UpdateCheckParams result;
+  ExpectPolicyStatus(
+      EvalStatus::kSucceeded, &Policy::UpdateCheckAllowed, &result);
+  EXPECT_FALSE(result.updates_enabled);
+}
+
+TEST_F(UmAndroidThingsPolicyTest,
+       UpdateCheckAllowedForcedUpdateRequestedInteractive) {
+  // UpdateCheckAllowed should return true because a forced update request was
+  // signaled for an interactive update.
+
+  SetUpdateCheckAllowed(true);
+  fake_state_.updater_provider()->var_forced_update_requested()->reset(
+      new UpdateRequestStatus(UpdateRequestStatus::kInteractive));
+
+  UpdateCheckParams result;
+  ExpectPolicyStatus(
+      EvalStatus::kSucceeded, &Policy::UpdateCheckAllowed, &result);
+  EXPECT_TRUE(result.updates_enabled);
+  EXPECT_TRUE(result.is_interactive);
+}
+
+TEST_F(UmAndroidThingsPolicyTest,
+       UpdateCheckAllowedForcedUpdateRequestedPeriodic) {
+  // UpdateCheckAllowed should return true because a forced update request was
+  // signaled for a periodic check.
+
+  SetUpdateCheckAllowed(true);
+  fake_state_.updater_provider()->var_forced_update_requested()->reset(
+      new UpdateRequestStatus(UpdateRequestStatus::kPeriodic));
+
+  UpdateCheckParams result;
+  ExpectPolicyStatus(
+      EvalStatus::kSucceeded, &Policy::UpdateCheckAllowed, &result);
+  EXPECT_TRUE(result.updates_enabled);
+  EXPECT_FALSE(result.is_interactive);
+}
+
+}  // namespace chromeos_update_manager
diff --git a/update_manager/chromeos_policy_unittest.cc b/update_manager/chromeos_policy_unittest.cc
index 0c38700..2cd2aa6 100644
--- a/update_manager/chromeos_policy_unittest.cc
+++ b/update_manager/chromeos_policy_unittest.cc
@@ -418,9 +418,9 @@
 }
 
 TEST_F(UmChromeOSPolicyTest,
-       UpdateCheckAllowedUpdatesDisabledForRemovableBootDevice) {
+       UpdateCheckAllowedUpdatesDisabledWhenNotEnoughSlotsAbUpdates) {
   // UpdateCheckAllowed should return false (kSucceeded) if the image booted
-  // from a removable device.
+  // without enough slots to do A/B updates.
 
   fake_state_.system_provider()->var_num_slots()->reset(new unsigned int(1));
 
diff --git a/update_manager/enough_slots_ab_updates_policy_impl.cc b/update_manager/enough_slots_ab_updates_policy_impl.cc
new file mode 100644
index 0000000..70f15d4
--- /dev/null
+++ b/update_manager/enough_slots_ab_updates_policy_impl.cc
@@ -0,0 +1,38 @@
+//
+// 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/enough_slots_ab_updates_policy_impl.h"
+
+namespace chromeos_update_manager {
+
+// Do not perform any updates if booted from removable device. This decision
+// is final.
+EvalStatus EnoughSlotsAbUpdatesPolicyImpl::UpdateCheckAllowed(
+    EvaluationContext* ec,
+    State* state,
+    std::string* error,
+    UpdateCheckParams* result) const {
+  const auto* num_slots_p =
+      ec->GetValue(state->system_provider()->var_num_slots());
+  if (num_slots_p == nullptr || *num_slots_p < 2) {
+    LOG(INFO) << "Not enough slots for A/B updates, disabling update checks.";
+    result->updates_enabled = false;
+    return EvalStatus::kSucceeded;
+  }
+  return EvalStatus::kContinue;
+}
+
+}  // namespace chromeos_update_manager
diff --git a/update_manager/enough_slots_ab_updates_policy_impl.h b/update_manager/enough_slots_ab_updates_policy_impl.h
new file mode 100644
index 0000000..c0701f8
--- /dev/null
+++ b/update_manager/enough_slots_ab_updates_policy_impl.h
@@ -0,0 +1,49 @@
+//
+// 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_ENOUGH_SLOTS_AB_UPDATES_POLICY_IMPL_H_
+#define UPDATE_ENGINE_UPDATE_MANAGER_ENOUGH_SLOTS_AB_UPDATES_POLICY_IMPL_H_
+
+#include <string>
+
+#include "update_engine/update_manager/policy_utils.h"
+
+namespace chromeos_update_manager {
+
+// Do not perform any updates if booted from removable device.
+class EnoughSlotsAbUpdatesPolicyImpl : public PolicyImplBase {
+ public:
+  EnoughSlotsAbUpdatesPolicyImpl() = default;
+  ~EnoughSlotsAbUpdatesPolicyImpl() override = default;
+
+  // Policy overrides.
+  EvalStatus UpdateCheckAllowed(EvaluationContext* ec,
+                                State* state,
+                                std::string* error,
+                                UpdateCheckParams* result) const override;
+
+ protected:
+  std::string PolicyName() const override {
+    return "EnoughSlotsAbUpdatesPolicyImpl";
+  }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(EnoughSlotsAbUpdatesPolicyImpl);
+};
+
+}  // namespace chromeos_update_manager
+
+#endif  // UPDATE_ENGINE_UPDATE_MANAGER_ENOUGH_SLOTS_AB_UPDATES_POLICY_IMPL_H_
\ No newline at end of file
diff --git a/update_manager/interactive_update_policy_impl.cc b/update_manager/interactive_update_policy_impl.cc
new file mode 100644
index 0000000..df7f17b
--- /dev/null
+++ b/update_manager/interactive_update_policy_impl.cc
@@ -0,0 +1,44 @@
+//
+// 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/interactive_update_policy_impl.h"
+
+namespace chromeos_update_manager {
+
+// Check to see if an interactive update was requested.
+EvalStatus InteractiveUpdatePolicyImpl::UpdateCheckAllowed(
+    EvaluationContext* ec,
+    State* state,
+    std::string* error,
+    UpdateCheckParams* result) const {
+  UpdaterProvider* const updater_provider = state->updater_provider();
+
+  // 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 != nullptr &&
+      *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;
+  }
+  return EvalStatus::kContinue;
+}
+
+}  // namespace chromeos_update_manager
diff --git a/update_manager/interactive_update_policy_impl.h b/update_manager/interactive_update_policy_impl.h
new file mode 100644
index 0000000..fc68ea3
--- /dev/null
+++ b/update_manager/interactive_update_policy_impl.h
@@ -0,0 +1,49 @@
+//
+// 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_INTERACTIVE_UPDATE_POLICY_IMPL_H_
+#define UPDATE_ENGINE_UPDATE_MANAGER_INTERACTIVE_UPDATE_POLICY_IMPL_H_
+
+#include <string>
+
+#include "update_engine/update_manager/policy_utils.h"
+
+namespace chromeos_update_manager {
+
+// Check to see if an interactive update was requested.
+class InteractiveUpdatePolicyImpl : public PolicyImplBase {
+ public:
+  InteractiveUpdatePolicyImpl() = default;
+  ~InteractiveUpdatePolicyImpl() override = default;
+
+  // Policy overrides.
+  EvalStatus UpdateCheckAllowed(EvaluationContext* ec,
+                                State* state,
+                                std::string* error,
+                                UpdateCheckParams* result) const override;
+
+ protected:
+  std::string PolicyName() const override {
+    return "InteractiveUpdatePolicyImpl";
+  }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(InteractiveUpdatePolicyImpl);
+};
+
+}  // namespace chromeos_update_manager
+
+#endif  // UPDATE_ENGINE_UPDATE_MANAGER_OFFICIAL_BUILD_CHECK_POLICY_IMPL_H_
\ No newline at end of file
diff --git a/update_manager/next_update_check_policy_impl.cc b/update_manager/next_update_check_policy_impl.cc
new file mode 100644
index 0000000..6f9748e
--- /dev/null
+++ b/update_manager/next_update_check_policy_impl.cc
@@ -0,0 +1,150 @@
+//
+// 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/next_update_check_policy_impl.h"
+
+#include <algorithm>
+
+#include "update_engine/common/utils.h"
+
+using base::Time;
+using base::TimeDelta;
+using std::max;
+using std::string;
+
+namespace chromeos_update_manager {
+
+NextUpdateCheckTimePolicyImpl::NextUpdateCheckTimePolicyImpl(
+    const NextUpdateCheckPolicyConstants& constants)
+    : policy_constants_(constants) {}
+
+EvalStatus NextUpdateCheckTimePolicyImpl::UpdateCheckAllowed(
+    EvaluationContext* ec,
+    State* state,
+    string* error,
+    UpdateCheckParams* result) const {
+  // Ensure that periodic update checks are timed properly.
+  Time next_update_check;
+
+  if (NextUpdateCheckTime(
+          ec, state, error, &next_update_check, policy_constants_) !=
+      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;
+  }
+
+  return EvalStatus::kContinue;
+}
+
+EvalStatus NextUpdateCheckTimePolicyImpl::NextUpdateCheckTime(
+    EvaluationContext* ec,
+    State* state,
+    string* error,
+    Time* next_update_check,
+    const NextUpdateCheckPolicyConstants& constants) {
+  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 auto* 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 == nullptr ||
+      *last_checked_time < *updater_started_time) {
+    *next_update_check = *updater_started_time +
+                         FuzzedInterval(&prng,
+                                        constants.timeout_initial_interval,
+                                        constants.timeout_regular_fuzz);
+    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 = constants.timeout_periodic_interval;
+    unsigned int num_failures = *consecutive_failed_update_checks;
+    while (interval < constants.timeout_max_backoff_interval && num_failures) {
+      interval *= 2;
+      num_failures--;
+    }
+  }
+
+  // We cannot back off longer than the predetermined maximum interval.
+  if (interval > constants.timeout_max_backoff_interval)
+    interval = constants.timeout_max_backoff_interval;
+
+  // We cannot back off shorter than the predetermined periodic interval. Also,
+  // in this case set the fuzz to a predetermined regular value.
+  if (interval <= constants.timeout_periodic_interval) {
+    interval = constants.timeout_periodic_interval;
+    fuzz = constants.timeout_regular_fuzz;
+  }
+
+  // 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 NextUpdateCheckTimePolicyImpl::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));
+}
+
+}  // namespace chromeos_update_manager
diff --git a/update_manager/next_update_check_policy_impl.h b/update_manager/next_update_check_policy_impl.h
new file mode 100644
index 0000000..d9f3c3b
--- /dev/null
+++ b/update_manager/next_update_check_policy_impl.h
@@ -0,0 +1,98 @@
+//
+// 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_NEXT_UPDATE_CHECK_POLICY_IMPL_H_
+#define UPDATE_ENGINE_UPDATE_MANAGER_NEXT_UPDATE_CHECK_POLICY_IMPL_H_
+
+#include <string>
+
+#include <base/time/time.h>
+
+#include "update_engine/update_manager/policy_utils.h"
+#include "update_engine/update_manager/prng.h"
+
+namespace chromeos_update_manager {
+
+// Constants that are provided to the policy implementation.
+struct NextUpdateCheckPolicyConstants {
+  // Default update check timeout interval/fuzz values used to compute the
+  // NextUpdateCheckTime(), in seconds. Actual fuzz is within +/- half of the
+  // indicated value.
+  int timeout_initial_interval;
+  int timeout_periodic_interval;
+  int timeout_max_backoff_interval;
+  int timeout_regular_fuzz;
+
+  // Maximum update attempt backoff interval and fuzz.
+  int attempt_backoff_max_interval_in_days;
+  int attempt_backoff_fuzz_in_hours;
+};
+
+// Ensure that periodic update checks are timed properly.
+class NextUpdateCheckTimePolicyImpl : public PolicyImplBase {
+ public:
+  explicit NextUpdateCheckTimePolicyImpl(
+      const NextUpdateCheckPolicyConstants& constants);
+
+  // Policy overrides.
+  EvalStatus UpdateCheckAllowed(EvaluationContext* ec,
+                                State* state,
+                                std::string* error,
+                                UpdateCheckParams* result) const override;
+
+  // 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.
+  //
+  // NOTE:
+  // Exposed as a public static so that it's logic can be used to test
+  // Policy implementations that utilize this fragment for their
+  // timing, without needing to list them all with FRIEND_TEST (so that
+  // those Policy implementations can exist without modifying this
+  // class's definition.
+  //
+  // The output value from this method (|next_update_check|), isn't
+  // available via the UpdateCheckParams |result| of the Policy
+  // method, and so this timing logic needs to be otherwise exposed.
+  static EvalStatus NextUpdateCheckTime(
+      EvaluationContext* ec,
+      State* state,
+      std::string* error,
+      base::Time* next_update_check,
+      const NextUpdateCheckPolicyConstants& constants);
+
+  // 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);
+
+ protected:
+  std::string PolicyName() const override {
+    return "NextUpdateCheckTimePolicyImpl";
+  }
+
+ private:
+  const NextUpdateCheckPolicyConstants policy_constants_;
+
+  DISALLOW_COPY_AND_ASSIGN(NextUpdateCheckTimePolicyImpl);
+};
+
+}  // namespace chromeos_update_manager
+
+#endif  // UPDATE_ENGINE_UPDATE_MANAGER_NEXT_UPDATE_CHECK_POLICY_IMPL_H_
\ No newline at end of file
diff --git a/update_manager/next_update_check_policy_impl_unittest.cc b/update_manager/next_update_check_policy_impl_unittest.cc
new file mode 100644
index 0000000..ddc88e7
--- /dev/null
+++ b/update_manager/next_update_check_policy_impl_unittest.cc
@@ -0,0 +1,161 @@
+//
+// 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/next_update_check_policy_impl.h"
+
+#include "update_engine/update_manager/policy_test_utils.h"
+
+using base::Time;
+using base::TimeDelta;
+using std::string;
+
+namespace chromeos_update_manager {
+
+const NextUpdateCheckPolicyConstants policy_test_constants = {
+    // these are specifically NOT the values used by real Policy
+    // implementations.
+    .timeout_initial_interval = 3 * 60,
+    .timeout_periodic_interval = 2 * 60 * 60,
+    .timeout_max_backoff_interval = 8 * 60 * 60,
+    .timeout_regular_fuzz = 5 * 60,
+    .attempt_backoff_max_interval_in_days = 12,
+    .attempt_backoff_fuzz_in_hours = 10,
+};
+
+class UmNextUpdateCheckTimePolicyImplTest : public UmPolicyTestBase {
+ protected:
+  UmNextUpdateCheckTimePolicyImplTest() {
+    policy_ =
+        std::make_unique<NextUpdateCheckTimePolicyImpl>(policy_test_constants);
+  }
+};
+
+TEST_F(UmNextUpdateCheckTimePolicyImplTest,
+       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)));
+
+  CallMethodWithContext(&NextUpdateCheckTimePolicyImpl::NextUpdateCheckTime,
+                        &next_update_check,
+                        policy_test_constants);
+
+  EXPECT_LE(fake_clock_.GetWallclockTime(), next_update_check);
+  EXPECT_GE(fake_clock_.GetWallclockTime() +
+                TimeDelta::FromSeconds(
+                    policy_test_constants.timeout_initial_interval +
+                    policy_test_constants.timeout_regular_fuzz / 2),
+            next_update_check);
+}
+
+TEST_F(UmNextUpdateCheckTimePolicyImplTest, RecurringCheckBaseIntervalAndFuzz) {
+  // Ensure that we're using the correct interval (kPeriodicInterval) and fuzz
+  // (ktimeout_regular_fuzz) as base values for period updates.
+  Time next_update_check;
+
+  CallMethodWithContext(&NextUpdateCheckTimePolicyImpl::NextUpdateCheckTime,
+                        &next_update_check,
+                        policy_test_constants);
+
+  EXPECT_LE(fake_clock_.GetWallclockTime() +
+                TimeDelta::FromSeconds(
+                    policy_test_constants.timeout_periodic_interval -
+                    policy_test_constants.timeout_regular_fuzz / 2),
+            next_update_check);
+  EXPECT_GE(fake_clock_.GetWallclockTime() +
+                TimeDelta::FromSeconds(
+                    policy_test_constants.timeout_periodic_interval +
+                    policy_test_constants.timeout_regular_fuzz / 2),
+            next_update_check);
+}
+
+TEST_F(UmNextUpdateCheckTimePolicyImplTest,
+       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));
+
+  ExpectStatus(EvalStatus::kSucceeded,
+               NextUpdateCheckTimePolicyImpl::NextUpdateCheckTime,
+               &next_update_check,
+               policy_test_constants);
+
+  int expected_interval = policy_test_constants.timeout_periodic_interval * 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(UmNextUpdateCheckTimePolicyImplTest,
+       RecurringCheckServerDictatedPollInterval) {
+  // Policy honors the server provided check poll interval.
+  Time next_update_check;
+
+  const auto kInterval = policy_test_constants.timeout_periodic_interval * 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));
+
+  ExpectStatus(EvalStatus::kSucceeded,
+               &NextUpdateCheckTimePolicyImpl::NextUpdateCheckTime,
+               &next_update_check,
+               policy_test_constants);
+
+  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(UmNextUpdateCheckTimePolicyImplTest, ExponentialBackoffIsCapped) {
+  Time next_update_check;
+
+  fake_state_.updater_provider()->var_consecutive_failed_update_checks()->reset(
+      new unsigned int(100));
+
+  ExpectStatus(EvalStatus::kSucceeded,
+               &NextUpdateCheckTimePolicyImpl::NextUpdateCheckTime,
+               &next_update_check,
+               policy_test_constants);
+
+  EXPECT_LE(fake_clock_.GetWallclockTime() +
+                TimeDelta::FromSeconds(
+                    policy_test_constants.timeout_max_backoff_interval -
+                    policy_test_constants.timeout_max_backoff_interval / 2),
+            next_update_check);
+  EXPECT_GE(fake_clock_.GetWallclockTime() +
+                TimeDelta::FromSeconds(
+                    policy_test_constants.timeout_max_backoff_interval +
+                    policy_test_constants.timeout_max_backoff_interval / 2),
+            next_update_check);
+}
+
+}  // namespace chromeos_update_manager
\ No newline at end of file
diff --git a/update_manager/official_build_check_policy_impl.cc b/update_manager/official_build_check_policy_impl.cc
new file mode 100644
index 0000000..096f7bf
--- /dev/null
+++ b/update_manager/official_build_check_policy_impl.cc
@@ -0,0 +1,36 @@
+//
+// 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/official_build_check_policy_impl.h"
+
+namespace chromeos_update_manager {
+
+// Unofficial builds should not perform periodic update checks.
+EvalStatus OnlyUpdateOfficialBuildsPolicyImpl::UpdateCheckAllowed(
+    EvaluationContext* ec,
+    State* state,
+    std::string* error,
+    UpdateCheckParams* result) const {
+  const bool* is_official_build_p =
+      ec->GetValue(state->system_provider()->var_is_official_build());
+  if (is_official_build_p != nullptr && !(*is_official_build_p)) {
+    LOG(INFO) << "Unofficial build, blocking periodic update checks.";
+    return EvalStatus::kAskMeAgainLater;
+  }
+  return EvalStatus::kContinue;
+}
+
+}  // namespace chromeos_update_manager
diff --git a/update_manager/official_build_check_policy_impl.h b/update_manager/official_build_check_policy_impl.h
new file mode 100644
index 0000000..deb81c3
--- /dev/null
+++ b/update_manager/official_build_check_policy_impl.h
@@ -0,0 +1,49 @@
+//
+// 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_OFFICIAL_BUILD_CHECK_POLICY_IMPL_H_
+#define UPDATE_ENGINE_UPDATE_MANAGER_OFFICIAL_BUILD_CHECK_POLICY_IMPL_H_
+
+#include <string>
+
+#include "update_engine/update_manager/policy_utils.h"
+
+namespace chromeos_update_manager {
+
+// Unofficial builds should not perform periodic update checks.
+class OnlyUpdateOfficialBuildsPolicyImpl : public PolicyImplBase {
+ public:
+  OnlyUpdateOfficialBuildsPolicyImpl() = default;
+  ~OnlyUpdateOfficialBuildsPolicyImpl() override = default;
+
+  // Policy overrides.
+  EvalStatus UpdateCheckAllowed(EvaluationContext* ec,
+                                State* state,
+                                std::string* error,
+                                UpdateCheckParams* result) const override;
+
+ protected:
+  std::string PolicyName() const override {
+    return "OnlyUpdateOfficialBuildsPolicyImpl";
+  }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(OnlyUpdateOfficialBuildsPolicyImpl);
+};
+
+}  // namespace chromeos_update_manager
+
+#endif  // UPDATE_ENGINE_UPDATE_MANAGER_OFFICIAL_BUILD_CHECK_POLICY_IMPL_H_
\ No newline at end of file
diff --git a/update_manager/policy.cc b/update_manager/policy.cc
index 151c225..5f79a68 100644
--- a/update_manager/policy.cc
+++ b/update_manager/policy.cc
@@ -30,6 +30,8 @@
       return "kSucceeded";
     case EvalStatus::kAskMeAgainLater:
       return "kAskMeAgainLater";
+    case EvalStatus::kContinue:
+      return "kContinue";
   }
   return "Invalid";
 }
diff --git a/update_manager/policy.h b/update_manager/policy.h
index c2fc358..b60c4da 100644
--- a/update_manager/policy.h
+++ b/update_manager/policy.h
@@ -33,6 +33,7 @@
   kFailed,
   kSucceeded,
   kAskMeAgainLater,
+  kContinue,
 };
 
 std::string ToString(EvalStatus status);
diff --git a/update_manager/policy_test_utils.cc b/update_manager/policy_test_utils.cc
new file mode 100644
index 0000000..dfeb2d4
--- /dev/null
+++ b/update_manager/policy_test_utils.cc
@@ -0,0 +1,109 @@
+//
+// 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/policy_test_utils.h"
+
+#include <tuple>
+#include <vector>
+
+#include "update_engine/update_manager/next_update_check_policy_impl.h"
+
+using base::Time;
+using base::TimeDelta;
+using chromeos_update_engine::ErrorCode;
+using std::string;
+using std::tuple;
+using std::vector;
+
+namespace chromeos_update_manager {
+
+void UmPolicyTestBase::SetUp() {
+  loop_.SetAsCurrent();
+  SetUpDefaultClock();
+  eval_ctx_ = new EvaluationContext(&fake_clock_, TimeDelta::FromSeconds(5));
+  SetUpDefaultState();
+}
+
+void UmPolicyTestBase::TearDown() {
+  EXPECT_FALSE(loop_.PendingTasks());
+}
+
+// Sets the clock to fixed values.
+void UmPolicyTestBase::SetUpDefaultClock() {
+  fake_clock_.SetMonotonicTime(Time::FromInternalValue(12345678L));
+  fake_clock_.SetWallclockTime(Time::FromInternalValue(12345678901234L));
+}
+
+void UmPolicyTestBase::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});
+
+  // Chosen by fair dice roll.  Guaranteed to be random.
+  fake_state_.random_provider()->var_seed()->reset(new uint64_t(4));
+}
+
+// Returns a default UpdateState structure:
+UpdateState UmPolicyTestBase::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;
+}
+
+}  // namespace chromeos_update_manager
\ No newline at end of file
diff --git a/update_manager/policy_test_utils.h b/update_manager/policy_test_utils.h
new file mode 100644
index 0000000..09b2550
--- /dev/null
+++ b/update_manager/policy_test_utils.h
@@ -0,0 +1,98 @@
+//
+// 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_POLICY_TEST_UTILS_H_
+#define UPDATE_ENGINE_UPDATE_MANAGER_POLICY_TEST_UTILS_H_
+
+#include <string>
+
+#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/policy_utils.h"
+
+namespace chromeos_update_manager {
+
+class UmPolicyTestBase : public ::testing::Test {
+ protected:
+  explicit UmPolicyTestBase() = default;
+
+  void SetUp() override;
+
+  void TearDown() override;
+
+  // Sets the clock to fixed values.
+  virtual void SetUpDefaultClock();
+
+  // Sets up the default state in fake_state_.  override to add Policy-specific
+  // items, but only after calling this class's implementation.
+  virtual void SetUpDefaultState();
+
+  // Returns a default UpdateState structure:
+  virtual UpdateState GetDefaultUpdateState(base::TimeDelta first_seen_period);
+
+  // Runs the passed |method| after resetting the EvaluationContext and expects
+  // it to return the |expected| return value.
+  template <typename T, typename R, typename... Args>
+  void ExpectStatus(EvalStatus expected, T method, R* result, Args... args) {
+    std::string error = "<None>";
+    eval_ctx_->ResetEvaluation();
+    EXPECT_EQ(expected,
+              (*method)(eval_ctx_.get(), &fake_state_, &error, result, args...))
+        << "Returned error: " << error
+        << "\nEvaluation context: " << eval_ctx_->DumpContext();
+  }
+
+  // Runs the passed |method| after resetting the EvaluationContext, in order
+  // to use the method to get a value for other testing (doesn't validate the
+  // return value, just returns it).
+  template <typename T, typename R, typename... Args>
+  EvalStatus CallMethodWithContext(T method, R* result, Args... args) {
+    std::string error = "<None>";
+    eval_ctx_->ResetEvaluation();
+    return (*method)(eval_ctx_.get(), &fake_state_, &error, result, args...);
+  }
+
+  // Runs the passed |policy_method| on the framework 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) {
+    std::string error = "<None>";
+    eval_ctx_->ResetEvaluation();
+    EXPECT_EQ(expected,
+              (policy_.get()->*policy_method)(
+                  eval_ctx_.get(), &fake_state_, &error, result, args...))
+        << "Returned error: " << error
+        << "\nEvaluation context: " << eval_ctx_->DumpContext();
+  }
+
+  brillo::FakeMessageLoop loop_{nullptr};
+  chromeos_update_engine::FakeClock fake_clock_;
+  FakeState fake_state_;
+  scoped_refptr<EvaluationContext> eval_ctx_;
+  std::unique_ptr<Policy> policy_;
+};
+
+}  // namespace chromeos_update_manager
+
+#endif  // UPDATE_ENGINE_UPDATE_MANAGER_POLICY_TEST_UTILS_H_
\ No newline at end of file
diff --git a/update_manager/policy_utils.h b/update_manager/policy_utils.h
index 960987e..e448022 100644
--- a/update_manager/policy_utils.h
+++ b/update_manager/policy_utils.h
@@ -35,4 +35,84 @@
       } \
     } while (false)
 
+namespace chromeos_update_manager {
+
+// Call the passed-in Policy method on a series of Policy implementations, until
+// one of them renders a decision by returning a value other than
+// |EvalStatus::kContinue|.
+template <typename T, typename R, typename... Args>
+EvalStatus ConsultPolicies(const std::vector<Policy const*> policies,
+                           T policy_method,
+                           EvaluationContext* ec,
+                           State* state,
+                           std::string* error,
+                           R* result,
+                           Args... args) {
+  for (auto policy : policies) {
+    EvalStatus status =
+        (policy->*policy_method)(ec, state, error, result, args...);
+    if (status != EvalStatus::kContinue) {
+      LOG(INFO) << "decision by " << policy->PolicyRequestName(policy_method);
+      return status;
+    }
+  }
+  return EvalStatus::kContinue;
+};
+
+// Base class implementation that returns |EvalStatus::kContinue| for all
+// decisions, to be used as a base-class for various Policy facets that only
+// pertain to certain situations. This might be better folded into Policy
+// instead of using pure-virtual methods on that class.
+class PolicyImplBase : public Policy {
+ public:
+  // Policy overrides.
+  EvalStatus UpdateCheckAllowed(EvaluationContext* ec,
+                                State* state,
+                                std::string* error,
+                                UpdateCheckParams* result) const override {
+    return EvalStatus::kContinue;
+  };
+
+  EvalStatus UpdateCanBeApplied(
+      EvaluationContext* ec,
+      State* state,
+      std::string* error,
+      chromeos_update_engine::ErrorCode* result,
+      chromeos_update_engine::InstallPlan* install_plan) const override {
+    return EvalStatus::kContinue;
+  };
+
+  EvalStatus UpdateCanStart(EvaluationContext* ec,
+                            State* state,
+                            std::string* error,
+                            UpdateDownloadParams* result,
+                            UpdateState update_state) const override {
+    return EvalStatus::kContinue;
+  };
+
+  EvalStatus UpdateDownloadAllowed(EvaluationContext* ec,
+                                   State* state,
+                                   std::string* error,
+                                   bool* result) const override {
+    return EvalStatus::kContinue;
+  };
+
+  EvalStatus P2PEnabled(EvaluationContext* ec,
+                        State* state,
+                        std::string* error,
+                        bool* result) const override {
+    return EvalStatus::kContinue;
+  };
+
+  EvalStatus P2PEnabledChanged(EvaluationContext* ec,
+                               State* state,
+                               std::string* error,
+                               bool* result,
+                               bool prev_result) const override {
+    return EvalStatus::kContinue;
+  };
+};
+
+}  // namespace chromeos_update_manager
+
 #endif  // UPDATE_ENGINE_UPDATE_MANAGER_POLICY_UTILS_H_
diff --git a/update_manager/update_manager.cc b/update_manager/update_manager.cc
index 8e9b221..25f3216 100644
--- a/update_manager/update_manager.cc
+++ b/update_manager/update_manager.cc
@@ -16,7 +16,11 @@
 
 #include "update_engine/update_manager/update_manager.h"
 
+#ifdef __ANDROID__
+#include "update_engine/update_manager/android_things_policy.h"
+#else
 #include "update_engine/update_manager/chromeos_policy.h"
+#endif  // __ANDROID__
 #include "update_engine/update_manager/state.h"
 
 namespace chromeos_update_manager {
@@ -28,9 +32,11 @@
         evaluation_timeout_(evaluation_timeout),
         expiration_timeout_(expiration_timeout),
         weak_ptr_factory_(this) {
-  // TODO(deymo): Make it possible to replace this policy with a different
-  // implementation with a build-time flag.
+#ifdef __ANDROID__
+  policy_.reset(new AndroidThingsPolicy());
+#else
   policy_.reset(new ChromeOSPolicy());
+#endif  // __ANDROID__
 }
 
 UpdateManager::~UpdateManager() {