Allow Policies to defer updates am: 23bd339a82 am: f8be59e442
am: 8c6f4e7fff  -s ours

Change-Id: If22912c04984cc7f9a73425ac649b7015e822780
diff --git a/Android.mk b/Android.mk
index 6a23168..8f1de53 100644
--- a/Android.mk
+++ b/Android.mk
@@ -305,10 +305,15 @@
     proxy_resolver.cc \
     real_system_state.cc \
     update_attempter.cc \
+    update_manager/android_things_policy.cc \
+    update_manager/api_restricted_downloads_policy_impl.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 +974,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/binder_bindings/android/brillo/IUpdateEngine.aidl b/binder_bindings/android/brillo/IUpdateEngine.aidl
index b1a1b4f..e549a4d 100644
--- a/binder_bindings/android/brillo/IUpdateEngine.aidl
+++ b/binder_bindings/android/brillo/IUpdateEngine.aidl
@@ -20,7 +20,8 @@
 import android.brillo.ParcelableUpdateEngineStatus;
 
 interface IUpdateEngine {
-  void AttemptUpdate(in String app_version, in String omaha_url, in int flags);
+  void SetUpdateAttemptFlags(in int flags);
+  boolean AttemptUpdate(in String app_version, in String omaha_url, in int flags);
   void AttemptRollback(in boolean powerwash);
   boolean CanRollback();
   void ResetStatus();
diff --git a/binder_service_brillo.cc b/binder_service_brillo.cc
index 74803c4..3f01e42 100644
--- a/binder_service_brillo.cc
+++ b/binder_service_brillo.cc
@@ -58,12 +58,20 @@
   return ToStatus(&error);
 }
 
+Status BinderUpdateEngineBrilloService::SetUpdateAttemptFlags(int flags) {
+  return CallCommonHandler(&UpdateEngineService::SetUpdateAttemptFlags, flags);
+}
+
 Status BinderUpdateEngineBrilloService::AttemptUpdate(
-    const String16& app_version, const String16& omaha_url, int flags) {
+    const String16& app_version,
+    const String16& omaha_url,
+    int flags,
+    bool* out_result) {
   return CallCommonHandler(&UpdateEngineService::AttemptUpdate,
                            NormalString(app_version),
                            NormalString(omaha_url),
-                           flags);
+                           flags,
+                           out_result);
 }
 
 Status BinderUpdateEngineBrilloService::AttemptRollback(bool powerwash) {
diff --git a/binder_service_brillo.h b/binder_service_brillo.h
index 51f0fab..c802fca 100644
--- a/binder_service_brillo.h
+++ b/binder_service_brillo.h
@@ -51,9 +51,11 @@
   void SendPayloadApplicationComplete(ErrorCode error_code) override {}
 
   // android::brillo::BnUpdateEngine overrides.
+  android::binder::Status SetUpdateAttemptFlags(int flags) override;
   android::binder::Status AttemptUpdate(const android::String16& app_version,
                                         const android::String16& omaha_url,
-                                        int flags) override;
+                                        int flags,
+                                        bool* out_result) override;
   android::binder::Status AttemptRollback(bool powerwash) override;
   android::binder::Status CanRollback(bool* out_can_rollback) override;
   android::binder::Status ResetStatus() override;
diff --git a/client_library/client_binder.cc b/client_library/client_binder.cc
index fecd9a3..54b33ed 100644
--- a/client_library/client_binder.cc
+++ b/client_library/client_binder.cc
@@ -25,15 +25,15 @@
 #include "update_engine/parcelable_update_engine_status.h"
 #include "update_engine/update_status_utils.h"
 
-using android::OK;
-using android::String16;
-using android::String8;
 using android::binder::Status;
 using android::brillo::ParcelableUpdateEngineStatus;
 using android::getService;
+using android::OK;
+using android::String16;
+using android::String8;
 using chromeos_update_engine::StringToUpdateStatus;
-using chromeos_update_engine::UpdateEngineService;
 using std::string;
+using update_engine::UpdateAttemptFlags;
 
 namespace update_engine {
 namespace internal {
@@ -48,10 +48,14 @@
 bool BinderUpdateEngineClient::AttemptUpdate(const string& in_app_version,
                                              const string& in_omaha_url,
                                              bool at_user_request) {
-  return service_->AttemptUpdate(String16{in_app_version.c_str()},
-      String16{in_omaha_url.c_str()},
-      at_user_request ? 0 :
-          UpdateEngineService::kAttemptUpdateFlagNonInteractive).isOk();
+  bool started;
+  return service_
+      ->AttemptUpdate(
+          String16{in_app_version.c_str()},
+          String16{in_omaha_url.c_str()},
+          at_user_request ? 0 : UpdateAttemptFlags::kFlagNonInteractive,
+          &started)
+      .isOk();
 }
 
 bool BinderUpdateEngineClient::GetStatus(int64_t* out_last_checked_time,
diff --git a/client_library/include/update_engine/update_status.h b/client_library/include/update_engine/update_status.h
index 76dd865..d93ca91 100644
--- a/client_library/include/update_engine/update_status.h
+++ b/client_library/include/update_engine/update_status.h
@@ -34,6 +34,32 @@
   DISABLED,
 };
 
+// Enum of bit-wise flags for controlling how updates are attempted.
+enum UpdateAttemptFlags : int32_t {
+  kNone = 0,
+  // Treat the update like a non-interactive update, even when being triggered
+  // by the interactive APIs.
+  kFlagNonInteractive = (1 << 0),
+  // Restrict (disallow) downloading of updates.
+  kFlagRestrictDownload = (1 << 1),
+};
+
+// These bit-wise operators for the above flags allow for standard bit-wise
+// operations to return values in an expected manner, with the need to
+// continually cast the results back to UpdateAttemptFlags after the implicit
+// conversion to int from enum to perform the bitwise comparison using the
+// underlying type.
+inline UpdateAttemptFlags operator|(const UpdateAttemptFlags& l,
+                                    const UpdateAttemptFlags& r) {
+  return static_cast<UpdateAttemptFlags>(static_cast<const int32_t&>(l) |
+                                         static_cast<const int32_t&>(r));
+}
+inline UpdateAttemptFlags operator&(const UpdateAttemptFlags& l,
+                                    const UpdateAttemptFlags& r) {
+  return static_cast<UpdateAttemptFlags>(static_cast<const int32_t&>(l) &
+                                         static_cast<const int32_t&>(r));
+}
+
 struct UpdateEngineStatus {
   // When the update_engine last checked for updates (ms since Epoch)
   int64_t last_checked_time_ms;
diff --git a/common_service.cc b/common_service.cc
index 15feca7..370587b 100644
--- a/common_service.cc
+++ b/common_service.cc
@@ -43,6 +43,7 @@
 using brillo::string_utils::ToString;
 using std::set;
 using std::string;
+using update_engine::UpdateAttemptFlags;
 using update_engine::UpdateEngineStatus;
 
 namespace chromeos_update_engine {
@@ -72,19 +73,35 @@
 
 // org::chromium::UpdateEngineInterfaceInterface methods implementation.
 
+bool UpdateEngineService::SetUpdateAttemptFlags(ErrorPtr* /* error */,
+                                                int32_t in_flags_as_int) {
+  auto flags = static_cast<UpdateAttemptFlags>(in_flags_as_int);
+  LOG(INFO) << "Setting Update Attempt Flags: "
+            << "flags=0x" << std::hex << flags << " "
+            << "RestrictDownload="
+            << ((flags & UpdateAttemptFlags::kFlagRestrictDownload) ? "yes"
+                                                                    : "no");
+  system_state_->update_attempter()->SetUpdateAttemptFlags(flags);
+  return true;
+}
+
 bool UpdateEngineService::AttemptUpdate(ErrorPtr* /* error */,
                                         const string& in_app_version,
                                         const string& in_omaha_url,
-                                        int32_t in_flags_as_int) {
-  AttemptUpdateFlags flags = static_cast<AttemptUpdateFlags>(in_flags_as_int);
-  bool interactive = !(flags & kAttemptUpdateFlagNonInteractive);
+                                        int32_t in_flags_as_int,
+                                        bool* out_result) {
+  auto flags = static_cast<UpdateAttemptFlags>(in_flags_as_int);
+  bool interactive = !(flags & UpdateAttemptFlags::kFlagNonInteractive);
+  bool restrict_downloads = (flags & UpdateAttemptFlags::kFlagRestrictDownload);
 
   LOG(INFO) << "Attempt update: app_version=\"" << in_app_version << "\" "
             << "omaha_url=\"" << in_omaha_url << "\" "
             << "flags=0x" << std::hex << flags << " "
-            << "interactive=" << (interactive ? "yes" : "no");
-  system_state_->update_attempter()->CheckForUpdate(
-      in_app_version, in_omaha_url, interactive);
+            << "interactive=" << (interactive ? "yes " : "no ")
+            << "RestrictDownload=" << (restrict_downloads ? "yes " : "no ");
+
+  *out_result = system_state_->update_attempter()->CheckForUpdate(
+      in_app_version, in_omaha_url, flags);
   return true;
 }
 
diff --git a/common_service.h b/common_service.h
index 7e7fea8..544dd93 100644
--- a/common_service.h
+++ b/common_service.h
@@ -31,11 +31,6 @@
 
 class UpdateEngineService {
  public:
-  // Flags used in the AttemptUpdateWithFlags() D-Bus method.
-  typedef enum {
-    kAttemptUpdateFlagNonInteractive = (1<<0)
-  } AttemptUpdateFlags;
-
   // Error domain for all the service errors.
   static const char* const kErrorDomain;
 
@@ -45,10 +40,17 @@
   explicit UpdateEngineService(SystemState* system_state);
   virtual ~UpdateEngineService() = default;
 
+  // Set flags that influence how updates and checks are performed.  These
+  // influence all future checks and updates until changed or the device
+  // reboots.  The |in_flags_as_int| values are a union of values from
+  // |UpdateAttemptFlags|
+  bool SetUpdateAttemptFlags(brillo::ErrorPtr* error, int32_t in_flags_as_int);
+
   bool AttemptUpdate(brillo::ErrorPtr* error,
                      const std::string& in_app_version,
                      const std::string& in_omaha_url,
-                     int32_t in_flags_as_int);
+                     int32_t in_flags_as_int,
+                     bool* out_result);
 
   bool AttemptRollback(brillo::ErrorPtr* error, bool in_powerwash);
 
diff --git a/common_service_unittest.cc b/common_service_unittest.cc
index 0a7bfc3..c124466 100644
--- a/common_service_unittest.cc
+++ b/common_service_unittest.cc
@@ -28,9 +28,10 @@
 #include "update_engine/omaha_utils.h"
 
 using std::string;
+using testing::_;
 using testing::Return;
 using testing::SetArgumentPointee;
-using testing::_;
+using update_engine::UpdateAttemptFlags;
 
 namespace chromeos_update_engine {
 
@@ -56,13 +57,32 @@
 };
 
 TEST_F(UpdateEngineServiceTest, AttemptUpdate) {
-  EXPECT_CALL(*mock_update_attempter_, CheckForUpdate(
-      "app_ver", "url", false /* interactive */));
-  // The update is non-interactive when we pass the non-interactive flag.
-  EXPECT_TRUE(common_service_.AttemptUpdate(
-      &error_, "app_ver", "url",
-      UpdateEngineService::kAttemptUpdateFlagNonInteractive));
+  EXPECT_CALL(
+      *mock_update_attempter_,
+      CheckForUpdate("app_ver", "url", UpdateAttemptFlags::kFlagNonInteractive))
+      .WillOnce(Return(true));
+
+  // The non-interactive flag needs to be passed through to CheckForUpdate.
+  bool result = false;
+  EXPECT_TRUE(
+      common_service_.AttemptUpdate(&error_,
+                                    "app_ver",
+                                    "url",
+                                    UpdateAttemptFlags::kFlagNonInteractive,
+                                    &result));
   EXPECT_EQ(nullptr, error_);
+  EXPECT_TRUE(result);
+}
+
+TEST_F(UpdateEngineServiceTest, AttemptUpdateReturnsFalse) {
+  EXPECT_CALL(*mock_update_attempter_,
+              CheckForUpdate("app_ver", "url", UpdateAttemptFlags::kNone))
+      .WillOnce(Return(false));
+  bool result = true;
+  EXPECT_TRUE(common_service_.AttemptUpdate(
+      &error_, "app_ver", "url", UpdateAttemptFlags::kNone, &result));
+  EXPECT_EQ(nullptr, error_);
+  EXPECT_FALSE(result);
 }
 
 // SetChannel is allowed when there's no device policy (the device is not
diff --git a/mock_update_attempter.h b/mock_update_attempter.h
index 9634bab..d88b840 100644
--- a/mock_update_attempter.h
+++ b/mock_update_attempter.h
@@ -42,9 +42,12 @@
 
   MOCK_METHOD0(ResetStatus, bool(void));
 
-  MOCK_METHOD3(CheckForUpdate, void(const std::string& app_version,
-                                    const std::string& omaha_url,
-                                    bool is_interactive));
+  MOCK_METHOD0(GetCurrentUpdateAttemptFlags, UpdateAttemptFlags(void));
+
+  MOCK_METHOD3(CheckForUpdate,
+               bool(const std::string& app_version,
+                    const std::string& omaha_url,
+                    UpdateAttemptFlags flags));
 
   MOCK_METHOD0(RefreshDevicePolicy, void(void));
 
diff --git a/update_attempter.cc b/update_attempter.cc
index c7c0177..a6f9fa5 100644
--- a/update_attempter.cc
+++ b/update_attempter.cc
@@ -78,6 +78,7 @@
 using std::shared_ptr;
 using std::string;
 using std::vector;
+using update_engine::UpdateAttemptFlags;
 using update_engine::UpdateEngineStatus;
 
 namespace chromeos_update_engine {
@@ -772,9 +773,20 @@
   return BootControlInterface::kInvalidSlot;
 }
 
-void UpdateAttempter::CheckForUpdate(const string& app_version,
+bool UpdateAttempter::CheckForUpdate(const string& app_version,
                                      const string& omaha_url,
-                                     bool interactive) {
+                                     UpdateAttemptFlags flags) {
+  bool interactive = !(flags & UpdateAttemptFlags::kFlagNonInteractive);
+
+  if (interactive && status_ != UpdateStatus::IDLE) {
+    // An update check is either in-progress, or an update has completed and the
+    // system is in UPDATED_NEED_REBOOT.  Either way, don't do an interactive
+    // update at this time
+    LOG(INFO) << "Refusing to do an interactive update with an update already "
+                 "in progress";
+    return false;
+  }
+
   LOG(INFO) << "Forced update check requested.";
   forced_app_version_.clear();
   forced_omaha_url_.clear();
@@ -796,12 +808,22 @@
     forced_omaha_url_ = constants::kOmahaDefaultAUTestURL;
   }
 
+  if (interactive) {
+    // Use the passed-in update attempt flags for this update attempt instead
+    // of the previously set ones.
+    current_update_attempt_flags_ = flags;
+    // Note: The caching for non-interactive update checks happens in
+    // OnUpdateScheduled().
+  }
+
   if (forced_update_pending_callback_.get()) {
     // Make sure that a scheduling request is made prior to calling the forced
     // update pending callback.
     ScheduleUpdates();
     forced_update_pending_callback_->Run(true, interactive);
   }
+
+  return true;
 }
 
 bool UpdateAttempter::RebootIfNeeded() {
@@ -859,6 +881,15 @@
               << (params.is_interactive ? "interactive" : "periodic")
               << " update.";
 
+    if (!params.is_interactive) {
+      // Cache the update attempt flags that will be used by this update attempt
+      // so that they can't be changed mid-way through.
+      current_update_attempt_flags_ = update_attempt_flags_;
+    }
+
+    LOG(INFO) << "Update attempt flags in use = 0x" << std::hex
+              << current_update_attempt_flags_;
+
     Update(forced_app_version_, forced_omaha_url_, params.target_channel,
            params.target_version_prefix, false, params.is_interactive);
     // Always clear the forced app_version and omaha_url after an update attempt
@@ -892,6 +923,9 @@
   // Reset cpu shares back to normal.
   cpu_limiter_.StopLimiter();
 
+  // reset the state that's only valid for a single update pass
+  current_update_attempt_flags_ = UpdateAttemptFlags::kNone;
+
   if (status_ == UpdateStatus::REPORTING_ERROR_EVENT) {
     LOG(INFO) << "Error event sent.";
 
diff --git a/update_attempter.h b/update_attempter.h
index 6b2a7a7..d2fe3ec 100644
--- a/update_attempter.h
+++ b/update_attempter.h
@@ -66,6 +66,7 @@
                         public PostinstallRunnerAction::DelegateInterface {
  public:
   using UpdateStatus = update_engine::UpdateStatus;
+  using UpdateAttemptFlags = update_engine::UpdateAttemptFlags;
   static const int kMaxDeltaUpdateFailures;
 
   UpdateAttempter(SystemState* system_state,
@@ -130,12 +131,28 @@
   int http_response_code() const { return http_response_code_; }
   void set_http_response_code(int code) { http_response_code_ = code; }
 
+  // Set flags that influence how updates and checks are performed.  These
+  // influence all future checks and updates until changed or the device
+  // reboots.
+  void SetUpdateAttemptFlags(UpdateAttemptFlags flags) {
+    update_attempt_flags_ = flags;
+  }
+
+  // Returns the update attempt flags that are in place for the current update
+  // attempt.  These are cached at the start of an update attempt so that they
+  // remain constant throughout the process.
+  virtual UpdateAttemptFlags GetCurrentUpdateAttemptFlags() {
+    return current_update_attempt_flags_;
+  }
+
   // This is the internal entry point for going through an
   // update. If the current status is idle invokes Update.
   // This is called by the DBus implementation.
-  virtual void CheckForUpdate(const std::string& app_version,
+  // This returns true if an update check was started, false if a check or an
+  // update was already in progress.
+  virtual bool CheckForUpdate(const std::string& app_version,
                               const std::string& omaha_url,
-                              bool is_interactive);
+                              UpdateAttemptFlags flags);
 
   // This is the internal entry point for going through a rollback. This will
   // attempt to run the postinstall on the non-active partition and set it as
@@ -259,6 +276,7 @@
   FRIEND_TEST(UpdateAttempterTest, ScheduleErrorEventActionNoEventTest);
   FRIEND_TEST(UpdateAttempterTest, ScheduleErrorEventActionTest);
   FRIEND_TEST(UpdateAttempterTest, TargetVersionPrefixSetAndReset);
+  FRIEND_TEST(UpdateAttempterTest, UpdateAttemptFlagsCachedAtUpdateStart);
   FRIEND_TEST(UpdateAttempterTest, UpdateDeferredByPolicyTest);
   FRIEND_TEST(UpdateAttempterTest, UpdateIsNotRunningWhenUpdateAvailable);
   FRIEND_TEST(UpdateAttempterTest, UpdateTest);
@@ -439,6 +457,11 @@
   std::string new_version_ = "0.0.0.0";
   std::string new_system_version_;
   uint64_t new_payload_size_ = 0;
+  // Flags influencing all periodic update checks
+  UpdateAttemptFlags update_attempt_flags_ = UpdateAttemptFlags::kNone;
+  // Flags influencing the currently in-progress check (cached at the start of
+  // the update check).
+  UpdateAttemptFlags current_update_attempt_flags_ = UpdateAttemptFlags::kNone;
 
   // Common parameters for all Omaha requests.
   OmahaRequestParams* omaha_request_params_ = nullptr;
diff --git a/update_attempter_unittest.cc b/update_attempter_unittest.cc
index 7ecc5a6..bdc0196 100644
--- a/update_attempter_unittest.cc
+++ b/update_attempter_unittest.cc
@@ -62,10 +62,17 @@
 
 using base::Time;
 using base::TimeDelta;
+using chromeos_update_manager::EvalStatus;
+using chromeos_update_manager::UpdateCheckParams;
 using org::chromium::NetworkProxyServiceInterfaceProxyInterface;
 using org::chromium::NetworkProxyServiceInterfaceProxyMock;
+#if USE_LIBCROS
+using org::chromium::LibCrosServiceInterfaceProxyMock;
+using org::chromium::UpdateEngineLibcrosProxyResolvedInterfaceProxyMock;
+#endif // USE_LIBCROS
 using std::string;
 using std::unique_ptr;
+using testing::_;
 using testing::DoAll;
 using testing::Field;
 using testing::InSequence;
@@ -76,7 +83,7 @@
 using testing::ReturnPointee;
 using testing::SaveArg;
 using testing::SetArgumentPointee;
-using testing::_;
+using update_engine::UpdateAttemptFlags;
 using update_engine::UpdateEngineStatus;
 using update_engine::UpdateStatus;
 
@@ -1042,14 +1049,14 @@
 TEST_F(UpdateAttempterTest, CheckForUpdateAUTest) {
   fake_system_state_.fake_hardware()->SetIsOfficialBuild(true);
   fake_system_state_.fake_hardware()->SetAreDevFeaturesEnabled(false);
-  attempter_.CheckForUpdate("", "autest", true);
+  attempter_.CheckForUpdate("", "autest", UpdateAttemptFlags::kNone);
   EXPECT_EQ(constants::kOmahaDefaultAUTestURL, attempter_.forced_omaha_url());
 }
 
 TEST_F(UpdateAttempterTest, CheckForUpdateScheduledAUTest) {
   fake_system_state_.fake_hardware()->SetIsOfficialBuild(true);
   fake_system_state_.fake_hardware()->SetAreDevFeaturesEnabled(false);
-  attempter_.CheckForUpdate("", "autest-scheduled", true);
+  attempter_.CheckForUpdate("", "autest-scheduled", UpdateAttemptFlags::kNone);
   EXPECT_EQ(constants::kOmahaDefaultAUTestURL, attempter_.forced_omaha_url());
 }
 
@@ -1118,4 +1125,35 @@
   EXPECT_TRUE(attempter_.IsUpdateRunningOrScheduled());
 }
 
+TEST_F(UpdateAttempterTest, UpdateAttemptFlagsCachedAtUpdateStart) {
+  attempter_.SetUpdateAttemptFlags(UpdateAttemptFlags::kFlagRestrictDownload);
+
+  UpdateCheckParams params = {.updates_enabled = true};
+  attempter_.OnUpdateScheduled(EvalStatus::kSucceeded, params);
+
+  EXPECT_EQ(UpdateAttemptFlags::kFlagRestrictDownload,
+            attempter_.GetCurrentUpdateAttemptFlags());
+}
+
+TEST_F(UpdateAttempterTest, InteractiveUpdateUsesPassedRestrictions) {
+  attempter_.SetUpdateAttemptFlags(UpdateAttemptFlags::kFlagRestrictDownload);
+
+  attempter_.CheckForUpdate("", "", UpdateAttemptFlags::kNone);
+  EXPECT_EQ(UpdateAttemptFlags::kNone,
+            attempter_.GetCurrentUpdateAttemptFlags());
+}
+
+TEST_F(UpdateAttempterTest, NonInteractiveUpdateUsesSetRestrictions) {
+  attempter_.SetUpdateAttemptFlags(UpdateAttemptFlags::kNone);
+
+  // This tests that when CheckForUpdate() is called with the non-interactive
+  // flag set, that it doesn't change the current UpdateAttemptFlags.
+  attempter_.CheckForUpdate("",
+                            "",
+                            UpdateAttemptFlags::kFlagNonInteractive |
+                                UpdateAttemptFlags::kFlagRestrictDownload);
+  EXPECT_EQ(UpdateAttemptFlags::kNone,
+            attempter_.GetCurrentUpdateAttemptFlags());
+}
+
 }  // namespace chromeos_update_engine
diff --git a/update_manager/android_things_policy.cc b/update_manager/android_things_policy.cc
new file mode 100644
index 0000000..3af93cc
--- /dev/null
+++ b/update_manager/android_things_policy.cc
@@ -0,0 +1,181 @@
+//
+// 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/api_restricted_downloads_policy_impl.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;
+  }
+}
+
+// Uses the |UpdateRestrictions| to determine if the download and apply can
+// occur at this time.
+EvalStatus AndroidThingsPolicy::UpdateCanBeApplied(
+    EvaluationContext* ec,
+    State* state,
+    string* error,
+    ErrorCode* result,
+    chromeos_update_engine::InstallPlan* install_plan) const {
+  // Build a list of policies to consult.  Note that each policy may modify the
+  // result structure, even if it signals kContinue.
+  ApiRestrictedDownloadsPolicyImpl api_restricted_downloads_policy;
+
+  vector<Policy const*> policies_to_consult = {
+
+      // Do not apply the update if all updates are restricted by the API.
+      &api_restricted_downloads_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::UpdateCanBeApplied,
+                                      ec,
+                                      state,
+                                      error,
+                                      result,
+                                      install_plan);
+  if (EvalStatus::kContinue != status) {
+    return status;
+  } else {
+    // The update can proceed.
+    LOG(INFO) << "Allowing update to be applied.";
+    *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..b45e955
--- /dev/null
+++ b/update_manager/android_things_policy.h
@@ -0,0 +1,92 @@
+//
+// 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;
+
+  // Uses the |UpdateRestrictions| to determine if the download and apply can
+  // occur at this time.
+  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..04b0e0e
--- /dev/null
+++ b/update_manager/android_things_policy_unittest.cc
@@ -0,0 +1,184 @@
+//
+// 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;
+using chromeos_update_engine::ErrorCode;
+using chromeos_update_engine::InstallPlan;
+
+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);
+}
+
+TEST_F(UmAndroidThingsPolicyTest, UpdateCanBeAppliedOk) {
+  // UpdateCanBeApplied should return kSucceeded in the base case
+
+  InstallPlan plan;
+  ErrorCode result;
+  ExpectPolicyStatus(
+      EvalStatus::kSucceeded, &Policy::UpdateCanBeApplied, &result, &plan);
+
+  EXPECT_EQ(ErrorCode::kSuccess, result);
+}
+
+TEST_F(UmAndroidThingsPolicyTest, UpdateCanBeAppliedRestricted) {
+  // UpdateCanBeApplied should return kOmahaUpdateDeferredPerPolicy in
+  // when the restricted flag is set in the Updater.
+
+  fake_state_.updater_provider()->var_update_restrictions()->reset(
+      new UpdateRestrictions(UpdateRestrictions::kRestrictDownloading));
+
+  InstallPlan plan;
+  ErrorCode result;
+  ExpectPolicyStatus(
+      EvalStatus::kSucceeded, &Policy::UpdateCanBeApplied, &result, &plan);
+
+  EXPECT_EQ(ErrorCode::kOmahaUpdateDeferredPerPolicy, result);
+}
+
+}  // namespace chromeos_update_manager
diff --git a/update_manager/api_restricted_downloads_policy_impl.cc b/update_manager/api_restricted_downloads_policy_impl.cc
new file mode 100644
index 0000000..d413cca
--- /dev/null
+++ b/update_manager/api_restricted_downloads_policy_impl.cc
@@ -0,0 +1,47 @@
+//
+// 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/api_restricted_downloads_policy_impl.h"
+
+using chromeos_update_engine::ErrorCode;
+using std::string;
+using std::vector;
+
+namespace chromeos_update_manager {
+
+// Allow the API to restrict the downloading of updates.
+EvalStatus ApiRestrictedDownloadsPolicyImpl::UpdateCanBeApplied(
+    EvaluationContext* ec,
+    State* state,
+    std::string* error,
+    ErrorCode* result,
+    chromeos_update_engine::InstallPlan* install_plan) const {
+  // Next, check to see if updates can be applied (in general).
+  const UpdateRestrictions* update_restrictions_p =
+      ec->GetValue(state->updater_provider()->var_update_restrictions());
+  if (update_restrictions_p) {
+    if (*update_restrictions_p & UpdateRestrictions::kRestrictDownloading) {
+      *result = ErrorCode::kOmahaUpdateDeferredPerPolicy;
+      return EvalStatus::kSucceeded;
+    }
+  }
+
+  // The API isn't restricting downloads, so implicitly allow them to happen
+  // but don't explicitly return success from this policy implementation.
+  return EvalStatus::kContinue;
+}
+
+}  // namespace chromeos_update_manager
diff --git a/update_manager/api_restricted_downloads_policy_impl.h b/update_manager/api_restricted_downloads_policy_impl.h
new file mode 100644
index 0000000..69686d6
--- /dev/null
+++ b/update_manager/api_restricted_downloads_policy_impl.h
@@ -0,0 +1,51 @@
+//
+// 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_API_RESTRICTED_DOWNLOADS_POLICY_IMPL_H_
+#define UPDATE_ENGINE_UPDATE_MANAGER_API_RESTRICTED_DOWNLOADS_POLICY_IMPL_H_
+
+#include <string>
+
+#include "update_engine/update_manager/policy_utils.h"
+
+namespace chromeos_update_manager {
+
+// Allow the API to restrict the downloading of updates.
+class ApiRestrictedDownloadsPolicyImpl : public PolicyImplBase {
+ public:
+  ApiRestrictedDownloadsPolicyImpl() = default;
+  ~ApiRestrictedDownloadsPolicyImpl() override = default;
+
+  // Policy overrides.
+  EvalStatus UpdateCanBeApplied(
+      EvaluationContext* ec,
+      State* state,
+      std::string* error,
+      chromeos_update_engine::ErrorCode* result,
+      chromeos_update_engine::InstallPlan* install_plan) const override;
+
+ protected:
+  std::string PolicyName() const override {
+    return "ApiRestrictedDownloadsPolicyImpl";
+  }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(ApiRestrictedDownloadsPolicyImpl);
+};
+
+}  // namespace chromeos_update_manager
+
+#endif  // UPDATE_ENGINE_UPDATE_MANAGER_API_RESTRICTED_DOWNLOADS_POLICY_IMPL_H_
\ No newline at end of file
diff --git a/update_manager/boxed_value.cc b/update_manager/boxed_value.cc
index 9758d33..a437c02 100644
--- a/update_manager/boxed_value.cc
+++ b/update_manager/boxed_value.cc
@@ -176,4 +176,19 @@
   return "Unknown";
 }
 
+template <>
+string BoxedValue::ValuePrinter<UpdateRestrictions>(const void* value) {
+  const UpdateRestrictions* val =
+      reinterpret_cast<const UpdateRestrictions*>(value);
+
+  if (*val == UpdateRestrictions::kNone) {
+    return "None";
+  }
+  string retval = "Flags:";
+  if (*val & kRestrictDownloading) {
+    retval += " RestrictDownloading";
+  }
+  return retval;
+}
+
 }  // namespace chromeos_update_manager
diff --git a/update_manager/boxed_value_unittest.cc b/update_manager/boxed_value_unittest.cc
index 2a086a6..83d8de7 100644
--- a/update_manager/boxed_value_unittest.cc
+++ b/update_manager/boxed_value_unittest.cc
@@ -231,4 +231,14 @@
   EXPECT_EQ("DeleterMarker:true", value.ToString());
 }
 
+TEST(UmBoxedValueTest, UpdateRestrictionsToString) {
+  EXPECT_EQ(
+      "None",
+      BoxedValue(new UpdateRestrictions(UpdateRestrictions::kNone)).ToString());
+  EXPECT_EQ("Flags: RestrictDownloading",
+            BoxedValue(new UpdateRestrictions(
+                           UpdateRestrictions::kRestrictDownloading))
+                .ToString());
+}
+
 }  // 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/fake_updater_provider.h b/update_manager/fake_updater_provider.h
index a7c15b5..3e03d43 100644
--- a/update_manager/fake_updater_provider.h
+++ b/update_manager/fake_updater_provider.h
@@ -85,6 +85,10 @@
     return &var_forced_update_requested_;
   }
 
+  FakeVariable<UpdateRestrictions>* var_update_restrictions() override {
+    return &var_update_restrictions_;
+  }
+
  private:
   FakeVariable<base::Time>
       var_updater_started_time_{  // NOLINT(whitespace/braces)
@@ -121,6 +125,10 @@
   FakeVariable<UpdateRequestStatus>
       var_forced_update_requested_{  // NOLINT(whitespace/braces)
     "forced_update_requested", kVariableModeAsync};
+  FakeVariable<UpdateRestrictions> var_update_restrictions_{
+      // NOLINT(whitespace/braces)
+      "update_restrictions",
+      kVariableModePoll};
 
   DISALLOW_COPY_AND_ASSIGN(FakeUpdaterProvider);
 };
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/real_updater_provider.cc b/update_manager/real_updater_provider.cc
index a085f42..efa3609 100644
--- a/update_manager/real_updater_provider.cc
+++ b/update_manager/real_updater_provider.cc
@@ -38,6 +38,7 @@
 using chromeos_update_engine::OmahaRequestParams;
 using chromeos_update_engine::SystemState;
 using std::string;
+using update_engine::UpdateAttemptFlags;
 using update_engine::UpdateEngineStatus;
 
 namespace chromeos_update_manager {
@@ -416,40 +417,66 @@
   DISALLOW_COPY_AND_ASSIGN(ForcedUpdateRequestedVariable);
 };
 
+// A variable returning the current update restrictions that are in effect.
+class UpdateRestrictionsVariable
+    : public UpdaterVariableBase<UpdateRestrictions> {
+ public:
+  UpdateRestrictionsVariable(const string& name, SystemState* system_state)
+      : UpdaterVariableBase<UpdateRestrictions>(
+            name, kVariableModePoll, system_state) {}
+
+ private:
+  const UpdateRestrictions* GetValue(TimeDelta /* timeout */,
+                                     string* /* errmsg */) override {
+    UpdateAttemptFlags attempt_flags =
+        system_state()->update_attempter()->GetCurrentUpdateAttemptFlags();
+    UpdateRestrictions restriction_flags = UpdateRestrictions::kNone;
+    // Don't blindly copy the whole value, test and set bits that should
+    // transfer from one set of flags to the other.
+    if (attempt_flags & UpdateAttemptFlags::kFlagRestrictDownload) {
+      restriction_flags = static_cast<UpdateRestrictions>(
+          restriction_flags | UpdateRestrictions::kRestrictDownloading);
+    }
+
+    return new UpdateRestrictions(restriction_flags);
+  }
+
+  DISALLOW_COPY_AND_ASSIGN(UpdateRestrictionsVariable);
+};
+
 // RealUpdaterProvider methods.
 
 RealUpdaterProvider::RealUpdaterProvider(SystemState* system_state)
-  : system_state_(system_state),
-    var_updater_started_time_("updater_started_time",
-                              system_state->clock()->GetWallclockTime()),
-    var_last_checked_time_(
-        new LastCheckedTimeVariable("last_checked_time", system_state_)),
-    var_update_completed_time_(
-        new UpdateCompletedTimeVariable("update_completed_time",
-                                        system_state_)),
-    var_progress_(new ProgressVariable("progress", system_state_)),
-    var_stage_(new StageVariable("stage", system_state_)),
-    var_new_version_(new NewVersionVariable("new_version", system_state_)),
-    var_payload_size_(new PayloadSizeVariable("payload_size", system_state_)),
-    var_curr_channel_(new CurrChannelVariable("curr_channel", system_state_)),
-    var_new_channel_(new NewChannelVariable("new_channel", system_state_)),
-    var_p2p_enabled_(
-        new BooleanPrefVariable("p2p_enabled", system_state_->prefs(),
-                                chromeos_update_engine::kPrefsP2PEnabled,
-                                false)),
-    var_cellular_enabled_(
-        new BooleanPrefVariable(
-            "cellular_enabled", system_state_->prefs(),
-            chromeos_update_engine::kPrefsUpdateOverCellularPermission,
-            false)),
-    var_consecutive_failed_update_checks_(
-        new ConsecutiveFailedUpdateChecksVariable(
-            "consecutive_failed_update_checks", system_state_)),
-    var_server_dictated_poll_interval_(
-        new ServerDictatedPollIntervalVariable(
-            "server_dictated_poll_interval", system_state_)),
-    var_forced_update_requested_(
-        new ForcedUpdateRequestedVariable(
-            "forced_update_requested", system_state_)) {}
-
+    : system_state_(system_state),
+      var_updater_started_time_("updater_started_time",
+                                system_state->clock()->GetWallclockTime()),
+      var_last_checked_time_(
+          new LastCheckedTimeVariable("last_checked_time", system_state_)),
+      var_update_completed_time_(new UpdateCompletedTimeVariable(
+          "update_completed_time", system_state_)),
+      var_progress_(new ProgressVariable("progress", system_state_)),
+      var_stage_(new StageVariable("stage", system_state_)),
+      var_new_version_(new NewVersionVariable("new_version", system_state_)),
+      var_payload_size_(new PayloadSizeVariable("payload_size", system_state_)),
+      var_curr_channel_(new CurrChannelVariable("curr_channel", system_state_)),
+      var_new_channel_(new NewChannelVariable("new_channel", system_state_)),
+      var_p2p_enabled_(
+          new BooleanPrefVariable("p2p_enabled",
+                                  system_state_->prefs(),
+                                  chromeos_update_engine::kPrefsP2PEnabled,
+                                  false)),
+      var_cellular_enabled_(new BooleanPrefVariable(
+          "cellular_enabled",
+          system_state_->prefs(),
+          chromeos_update_engine::kPrefsUpdateOverCellularPermission,
+          false)),
+      var_consecutive_failed_update_checks_(
+          new ConsecutiveFailedUpdateChecksVariable(
+              "consecutive_failed_update_checks", system_state_)),
+      var_server_dictated_poll_interval_(new ServerDictatedPollIntervalVariable(
+          "server_dictated_poll_interval", system_state_)),
+      var_forced_update_requested_(new ForcedUpdateRequestedVariable(
+          "forced_update_requested", system_state_)),
+      var_update_restrictions_(new UpdateRestrictionsVariable(
+          "update_restrictions", system_state_)) {}
 }  // namespace chromeos_update_manager
diff --git a/update_manager/real_updater_provider.h b/update_manager/real_updater_provider.h
index eb8b8e6..5e3e27b 100644
--- a/update_manager/real_updater_provider.h
+++ b/update_manager/real_updater_provider.h
@@ -96,6 +96,10 @@
     return var_forced_update_requested_.get();
   }
 
+  Variable<UpdateRestrictions>* var_update_restrictions() override {
+    return var_update_restrictions_.get();
+  }
+
  private:
   // A pointer to the update engine's system state aggregator.
   chromeos_update_engine::SystemState* system_state_;
@@ -115,6 +119,7 @@
   std::unique_ptr<Variable<unsigned int>> var_consecutive_failed_update_checks_;
   std::unique_ptr<Variable<unsigned int>> var_server_dictated_poll_interval_;
   std::unique_ptr<Variable<UpdateRequestStatus>> var_forced_update_requested_;
+  std::unique_ptr<Variable<UpdateRestrictions>> var_update_restrictions_;
 
   DISALLOW_COPY_AND_ASSIGN(RealUpdaterProvider);
 };
diff --git a/update_manager/real_updater_provider_unittest.cc b/update_manager/real_updater_provider_unittest.cc
index f128c77..72e664b 100644
--- a/update_manager/real_updater_provider_unittest.cc
+++ b/update_manager/real_updater_provider_unittest.cc
@@ -38,10 +38,11 @@
 using chromeos_update_engine::OmahaRequestParams;
 using std::string;
 using std::unique_ptr;
+using testing::_;
 using testing::DoAll;
 using testing::Return;
 using testing::SetArgPointee;
-using testing::_;
+using update_engine::UpdateAttemptFlags;
 
 namespace {
 
@@ -425,4 +426,20 @@
       kPollInterval, provider_->var_server_dictated_poll_interval());
 }
 
+TEST_F(UmRealUpdaterProviderTest, GetUpdateRestrictions) {
+  EXPECT_CALL(*fake_sys_state_.mock_update_attempter(),
+              GetCurrentUpdateAttemptFlags())
+      .WillRepeatedly(Return(UpdateAttemptFlags::kFlagRestrictDownload |
+                             UpdateAttemptFlags::kFlagNonInteractive));
+  UmTestUtils::ExpectVariableHasValue(UpdateRestrictions::kRestrictDownloading,
+                                      provider_->var_update_restrictions());
+}
+
+TEST_F(UmRealUpdaterProviderTest, GetUpdateRestrictionsNone) {
+  EXPECT_CALL(*fake_sys_state_.mock_update_attempter(),
+              GetCurrentUpdateAttemptFlags())
+      .WillRepeatedly(Return(UpdateAttemptFlags::kNone));
+  UmTestUtils::ExpectVariableHasValue(UpdateRestrictions::kNone,
+                                      provider_->var_update_restrictions());
+}
 }  // namespace chromeos_update_manager
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() {
diff --git a/update_manager/updater_provider.h b/update_manager/updater_provider.h
index 549aea9..cb62623 100644
--- a/update_manager/updater_provider.h
+++ b/update_manager/updater_provider.h
@@ -44,6 +44,12 @@
   kPeriodic,
 };
 
+// These enum values are a bit-field.
+enum UpdateRestrictions : int {
+  kNone,
+  kRestrictDownloading = (1 << 0),
+};
+
 // Provider for Chrome OS update related information.
 class UpdaterProvider : public Provider {
  public:
@@ -105,6 +111,10 @@
   // scheduled update.
   virtual Variable<UpdateRequestStatus>* var_forced_update_requested() = 0;
 
+  // A variable that returns the update restriction flags that are set
+  // for all updates.
+  virtual Variable<UpdateRestrictions>* var_update_restrictions() = 0;
+
  protected:
   UpdaterProvider() {}