Rename the PolicyManager to UpdateManager.

This change renames the PolicyManager class, directory, tests, etc,
to avoid confusion with libpolicy and its classes.

BUG=chromium:373551
TEST=emerged on link.
CQ-DEPEND=CL:I43081673c7ba409f02273197da7915537bde39c6

Change-Id: Iffa76caa3b95ecbbdba87ab01006d1d8ce35a27f
Reviewed-on: https://chromium-review.googlesource.com/201876
Tested-by: Alex Deymo <deymo@chromium.org>
Reviewed-by: David Zeuthen <zeuthen@chromium.org>
Commit-Queue: Alex Deymo <deymo@chromium.org>
diff --git a/update_manager/boxed_value.cc b/update_manager/boxed_value.cc
new file mode 100644
index 0000000..512f7a8
--- /dev/null
+++ b/update_manager/boxed_value.cc
@@ -0,0 +1,163 @@
+// Copyright (c) 2014 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <set>
+#include <string>
+
+#include <base/strings/string_number_conversions.h>
+#include <base/time/time.h>
+
+#include "update_engine/update_manager/boxed_value.h"
+#include "update_engine/update_manager/shill_provider.h"
+#include "update_engine/update_manager/updater_provider.h"
+#include "update_engine/utils.h"
+
+using std::set;
+using std::string;
+
+namespace chromeos_update_manager {
+
+// Template instantiation for common types; used in BoxedValue::ToString().
+// Keep in sync with boxed_value_unitttest.cc.
+
+template<>
+string BoxedValue::ValuePrinter<string>(const void *value) {
+  const string* val = reinterpret_cast<const string*>(value);
+  return *val;
+}
+
+template<>
+string BoxedValue::ValuePrinter<int>(const void *value) {
+  const int* val = reinterpret_cast<const int*>(value);
+  return base::IntToString(*val);
+}
+
+template<>
+string BoxedValue::ValuePrinter<unsigned int>(const void *value) {
+  const unsigned int* val = reinterpret_cast<const unsigned int*>(value);
+  return base::UintToString(*val);
+}
+
+template<>
+string BoxedValue::ValuePrinter<int64_t>(const void *value) {
+  const int64_t* val = reinterpret_cast<const int64_t*>(value);
+  return base::Int64ToString(*val);
+}
+
+template<>
+string BoxedValue::ValuePrinter<uint64_t>(const void *value) {
+  const uint64_t* val =
+    reinterpret_cast<const uint64_t*>(value);
+  return base::Uint64ToString(static_cast<uint64>(*val));
+}
+
+template<>
+string BoxedValue::ValuePrinter<bool>(const void *value) {
+  const bool* val = reinterpret_cast<const bool*>(value);
+  return *val ? "true" : "false";
+}
+
+template<>
+string BoxedValue::ValuePrinter<double>(const void *value) {
+  const double* val = reinterpret_cast<const double*>(value);
+  return base::DoubleToString(*val);
+}
+
+template<>
+string BoxedValue::ValuePrinter<base::Time>(const void *value) {
+  const base::Time* val = reinterpret_cast<const base::Time*>(value);
+  return chromeos_update_engine::utils::ToString(*val);
+}
+
+template<>
+string BoxedValue::ValuePrinter<base::TimeDelta>(const void *value) {
+  const base::TimeDelta* val = reinterpret_cast<const base::TimeDelta*>(value);
+  return chromeos_update_engine::utils::FormatTimeDelta(*val);
+}
+
+static std::string ConnectionTypeToString(ConnectionType type) {
+  switch (type) {
+    case ConnectionType::kEthernet:
+      return "Ethernet";
+    case ConnectionType::kWifi:
+      return "Wifi";
+    case ConnectionType::kWimax:
+      return "Wimax";
+    case ConnectionType::kBluetooth:
+      return "Bluetooth";
+    case ConnectionType::kCellular:
+      return "Cellular";
+    case ConnectionType::kUnknown:
+      return "Unknown";
+  }
+  NOTREACHED();
+  return "Unknown";
+}
+
+template<>
+string BoxedValue::ValuePrinter<ConnectionType>(const void *value) {
+  const ConnectionType* val = reinterpret_cast<const ConnectionType*>(value);
+  return ConnectionTypeToString(*val);
+}
+
+template<>
+string BoxedValue::ValuePrinter<set<ConnectionType>>(const void *value) {
+  string ret = "";
+  const set<ConnectionType>* val =
+      reinterpret_cast<const set<ConnectionType>*>(value);
+  for (auto& it : *val) {
+    ConnectionType type = it;
+    if (ret.size() > 0)
+      ret += ",";
+    ret += ConnectionTypeToString(type);
+  }
+  return ret;
+}
+
+template<>
+string BoxedValue::ValuePrinter<ConnectionTethering>(const void *value) {
+  const ConnectionTethering* val =
+      reinterpret_cast<const ConnectionTethering*>(value);
+  switch (*val) {
+    case ConnectionTethering::kNotDetected:
+      return "Not Detected";
+    case ConnectionTethering::kSuspected:
+      return "Suspected";
+    case ConnectionTethering::kConfirmed:
+      return "Confirmed";
+    case ConnectionTethering::kUnknown:
+      return "Unknown";
+  }
+  NOTREACHED();
+  return "Unknown";
+}
+
+template<>
+string BoxedValue::ValuePrinter<Stage>(const void *value) {
+  const Stage* val = reinterpret_cast<const Stage*>(value);
+  switch (*val) {
+   case Stage::kIdle:
+      return "Idle";
+    case Stage::kCheckingForUpdate:
+      return "Checking For Update";
+    case Stage::kUpdateAvailable:
+      return "Update Available";
+    case Stage::kDownloading:
+      return "Downloading";
+    case Stage::kVerifying:
+      return "Verifying";
+    case Stage::kFinalizing:
+      return "Finalizing";
+    case Stage::kUpdatedNeedReboot:
+      return "Updated, Need Reboot";
+    case Stage::kReportingErrorEvent:
+      return "Reporting Error Event";
+    case Stage::kAttemptingRollback:
+      return "Attempting Rollback";
+  }
+  NOTREACHED();
+  return "Unknown";
+}
+
+}  // namespace chromeos_update_manager
diff --git a/update_manager/boxed_value.h b/update_manager/boxed_value.h
new file mode 100644
index 0000000..69ad0a4
--- /dev/null
+++ b/update_manager/boxed_value.h
@@ -0,0 +1,111 @@
+// Copyright (c) 2014 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROMEOS_PLATFORM_UPDATE_ENGINE_UPDATE_MANAGER_BOXED_VALUE_H_
+#define CHROMEOS_PLATFORM_UPDATE_ENGINE_UPDATE_MANAGER_BOXED_VALUE_H_
+
+#include <string>
+
+#include <base/basictypes.h>
+
+namespace chromeos_update_manager {
+
+// BoxedValue is a class to hold pointers of a given type that deletes them when
+// the instance goes out of scope, as scoped_ptr<T> does. The main difference
+// with it is that the type T is not part of the class, i.e., this isn't a
+// parametric class. The class has a parametric contructor that accepts a
+// const T* which will define the type of the object passed on delete.
+//
+// It is safe to use this class in linked containers such as std::list and
+// std::map but the object can't be copied. This means that you need to
+// construct the BoxedValue inplace using a container method like emplace()
+// or move it with std::move().
+//
+//   list<BoxedValue> lst;
+//   lst.emplace_back(new const int(42));
+//   lst.emplace_back(new const string("Hello world!"));
+//
+//   map<int, BoxedValue> m;
+//   m.emplace(123, std::move(BoxedValue(new const string("Hola mundo!"))));
+//
+//   auto it = m.find(42);
+//   if (it != m.end())
+//     cout << "m[42] points to " << it->second.value() << endl;
+//   cout << "m[33] points to " << m[33].value() << endl;
+//
+// Since copy and assign are not allowed, you can't create a copy of the
+// BoxedValue which means that you can only use a reference to it.
+//
+
+class BoxedValue {
+ public:
+  // Creates an empty BoxedValue. Since the pointer can't be assigned from other
+  // BoxedValues or pointers, this is only useful in places where a default
+  // constructor is required, such as std::map::operator[].
+  BoxedValue() : value_(NULL), deleter_(NULL), printer_(NULL) {}
+
+  // Creates a BoxedValue for the passed pointer |value|. The BoxedValue keeps
+  // the ownership of this pointer and can't be released.
+  template<typename T>
+  explicit BoxedValue(const T* value)
+    : value_(static_cast<const void*>(value)), deleter_(ValueDeleter<T>),
+      printer_(ValuePrinter<T>) {}
+
+  // The move constructor takes ownership of the pointer since the semantics of
+  // it allows to render the passed BoxedValue undefined. You need to use the
+  // move constructor explictly preventing it from accidental references,
+  // like in:
+  //   BoxedValue new_box(std::move(other_box));
+  BoxedValue(BoxedValue&& other)
+      : value_(other.value_), deleter_(other.deleter_),
+        printer_(other.printer_) {
+    other.value_ = NULL;
+    other.deleter_ = NULL;
+    other.printer_ = NULL;
+  }
+
+  // Deletes the |value| passed on construction using the delete for the passed
+  // type.
+  ~BoxedValue() {
+    if (deleter_)
+      deleter_(value_);
+  }
+
+  const void* value() const { return value_; }
+
+  std::string ToString() const {
+    if (!printer_)
+      return "(no printer)";
+    if (!value_)
+      return "(no value)";
+    return printer_(value_);
+  }
+
+  // Static method to call the destructor of the right type.
+  template<typename T>
+  static void ValueDeleter(const void* value) {
+    delete reinterpret_cast<const T*>(value);
+  }
+
+  // Static method to print a type. See boxed_value.cc for common
+  // instantiations.
+  template<typename T>
+  static std::string ValuePrinter(const void* value);
+
+ private:
+  // A pointer to the cached value.
+  const void* value_;
+
+  // A function that calls delete for the right type of value_.
+  void (*deleter_)(const void*);
+
+  // A function that converts value_ to a string.
+  std::string (*printer_)(const void*);
+
+  DISALLOW_COPY_AND_ASSIGN(BoxedValue);
+};
+
+}  // namespace chromeos_update_manager
+
+#endif  // CHROMEOS_PLATFORM_UPDATE_ENGINE_UPDATE_MANAGER_BOXED_VALUE_H_
diff --git a/update_manager/boxed_value_unittest.cc b/update_manager/boxed_value_unittest.cc
new file mode 100644
index 0000000..b42b361
--- /dev/null
+++ b/update_manager/boxed_value_unittest.cc
@@ -0,0 +1,218 @@
+// Copyright (c) 2014 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <gtest/gtest.h>
+#include <list>
+#include <map>
+#include <set>
+#include <string>
+
+#include <base/strings/stringprintf.h>
+#include <base/time/time.h>
+
+#include "update_engine/update_manager/boxed_value.h"
+#include "update_engine/update_manager/shill_provider.h"
+#include "update_engine/update_manager/umtest_utils.h"
+#include "update_engine/update_manager/updater_provider.h"
+
+using base::Time;
+using base::TimeDelta;
+using std::list;
+using std::map;
+using std::set;
+using std::string;
+
+namespace chromeos_update_manager {
+
+// The DeleterMarker flags a bool variable when the class is destroyed.
+class DeleterMarker {
+ public:
+  DeleterMarker(bool* marker) : marker_(marker) { *marker_ = false; }
+
+  ~DeleterMarker() { *marker_ = true; }
+
+ private:
+  friend string BoxedValue::ValuePrinter<DeleterMarker>(const void *);
+
+  // Pointer to the bool marker.
+  bool* marker_;
+};
+
+template<>
+string BoxedValue::ValuePrinter<DeleterMarker>(const void *value) {
+  const DeleterMarker* val = reinterpret_cast<const DeleterMarker*>(value);
+  return base::StringPrintf("DeleterMarker:%s",
+                            *val->marker_ ? "true" : "false");
+}
+
+TEST(UmBoxedValueTest, Deleted) {
+  bool marker = true;
+  const DeleterMarker* deleter_marker = new DeleterMarker(&marker);
+
+  EXPECT_FALSE(marker);
+  BoxedValue* box = new BoxedValue(deleter_marker);
+  EXPECT_FALSE(marker);
+  delete box;
+  EXPECT_TRUE(marker);
+}
+
+TEST(UmBoxedValueTest, MoveConstructor) {
+  bool marker = true;
+  const DeleterMarker* deleter_marker = new DeleterMarker(&marker);
+
+  BoxedValue* box = new BoxedValue(deleter_marker);
+  BoxedValue* new_box = new BoxedValue(std::move(*box));
+  // box is now undefined but valid.
+  delete box;
+  EXPECT_FALSE(marker);
+  // The deleter_marker gets deleted at this point.
+  delete new_box;
+  EXPECT_TRUE(marker);
+}
+
+TEST(UmBoxedValueTest, MixedList) {
+  list<BoxedValue> lst;
+  // This is mostly a compile test.
+  lst.emplace_back(new const int(42));
+  lst.emplace_back(new const string("Hello world!"));
+  bool marker;
+  lst.emplace_back(new const DeleterMarker(&marker));
+  EXPECT_FALSE(marker);
+  lst.clear();
+  EXPECT_TRUE(marker);
+}
+
+TEST(UmBoxedValueTest, MixedMap) {
+  map<int, BoxedValue> m;
+  m.emplace(42, std::move(BoxedValue(new const string("Hola mundo!"))));
+
+  auto it = m.find(42);
+  ASSERT_NE(it, m.end());
+  UMTEST_EXPECT_NOT_NULL(it->second.value());
+  UMTEST_EXPECT_NULL(m[33].value());
+}
+
+TEST(UmBoxedValueTest, StringToString) {
+  EXPECT_EQ("Hej Verden!",
+            BoxedValue(new string("Hej Verden!")).ToString());
+}
+
+TEST(UmBoxedValueTest, IntToString) {
+  EXPECT_EQ("42", BoxedValue(new int(42)).ToString());
+}
+
+TEST(UmBoxedValueTest, Int64ToString) {
+  // -123456789012345 doensn't fit in 32-bit integers.
+  EXPECT_EQ("-123456789012345", BoxedValue(
+      new int64_t(-123456789012345LL)).ToString());
+}
+
+TEST(UmBoxedValueTest, UnsignedIntToString) {
+  // 4294967295 is the biggest possible 32-bit unsigned integer.
+  EXPECT_EQ("4294967295", BoxedValue(new unsigned int(4294967295U)).ToString());
+}
+
+TEST(UmBoxedValueTest, UnsignedInt64ToString) {
+  // 18446744073709551615 is the biggest possible 64-bit unsigned integer.
+  EXPECT_EQ("18446744073709551615", BoxedValue(
+      new uint64_t(18446744073709551615ULL)).ToString());
+}
+
+TEST(UmBoxedValueTest, BoolToString) {
+  EXPECT_EQ("false", BoxedValue(new bool(false)).ToString());
+  EXPECT_EQ("true", BoxedValue(new bool(true)).ToString());
+}
+
+TEST(UmBoxedValueTest, DoubleToString) {
+  EXPECT_EQ("1.501", BoxedValue(new double(1.501)).ToString());
+}
+
+TEST(UmBoxedValueTest, TimeToString) {
+  // Tue Apr 29 22:30:55 UTC 2014 is 1398810655 seconds since the Unix Epoch.
+  EXPECT_EQ("4/29/2014 22:30:55 GMT",
+            BoxedValue(new Time(Time::FromTimeT(1398810655))).ToString());
+}
+
+TEST(UmBoxedValueTest, TimeDeltaToString) {
+  // 12345 seconds is 3 hours, 25 minutes and 45 seconds.
+  EXPECT_EQ("3h25m45s",
+            BoxedValue(new TimeDelta(TimeDelta::FromSeconds(12345)))
+            .ToString());
+}
+
+TEST(UmBoxedValueTest, ConnectionTypeToString) {
+  EXPECT_EQ("Ethernet",
+            BoxedValue(new ConnectionType(ConnectionType::kEthernet))
+            .ToString());
+  EXPECT_EQ("Wifi",
+            BoxedValue(new ConnectionType(ConnectionType::kWifi)).ToString());
+  EXPECT_EQ("Wimax",
+            BoxedValue(new ConnectionType(ConnectionType::kWimax)).ToString());
+  EXPECT_EQ("Bluetooth",
+            BoxedValue(new ConnectionType(ConnectionType::kBluetooth))
+            .ToString());
+  EXPECT_EQ("Cellular",
+            BoxedValue(new ConnectionType(ConnectionType::kCellular))
+            .ToString());
+  EXPECT_EQ("Unknown",
+            BoxedValue(new ConnectionType(ConnectionType::kUnknown))
+            .ToString());
+}
+
+TEST(UmBoxedValueTest, ConnectionTetheringToString) {
+  EXPECT_EQ("Not Detected",
+            BoxedValue(new ConnectionTethering(
+                ConnectionTethering::kNotDetected)).ToString());
+  EXPECT_EQ("Suspected",
+            BoxedValue(new ConnectionTethering(ConnectionTethering::kSuspected))
+            .ToString());
+  EXPECT_EQ("Confirmed",
+            BoxedValue(new ConnectionTethering(ConnectionTethering::kConfirmed))
+            .ToString());
+  EXPECT_EQ("Unknown",
+            BoxedValue(new ConnectionTethering(ConnectionTethering::kUnknown))
+            .ToString());
+}
+
+TEST(UmBoxedValueTest, SetConnectionTypeToString) {
+  set<ConnectionType>* set1 = new set<ConnectionType>;
+  set1->insert(ConnectionType::kWimax);
+  set1->insert(ConnectionType::kEthernet);
+  EXPECT_EQ("Ethernet,Wimax", BoxedValue(set1).ToString());
+
+  set<ConnectionType>* set2 = new set<ConnectionType>;
+  set2->insert(ConnectionType::kWifi);
+  EXPECT_EQ("Wifi", BoxedValue(set2).ToString());
+}
+
+TEST(UmBoxedValueTest, StageToString) {
+  EXPECT_EQ("Idle",
+            BoxedValue(new Stage(Stage::kIdle)).ToString());
+  EXPECT_EQ("Checking For Update",
+            BoxedValue(new Stage(Stage::kCheckingForUpdate)).ToString());
+  EXPECT_EQ("Update Available",
+            BoxedValue(new Stage(Stage::kUpdateAvailable)).ToString());
+  EXPECT_EQ("Downloading",
+            BoxedValue(new Stage(Stage::kDownloading)).ToString());
+  EXPECT_EQ("Verifying",
+            BoxedValue(new Stage(Stage::kVerifying)).ToString());
+  EXPECT_EQ("Finalizing",
+            BoxedValue(new Stage(Stage::kFinalizing)).ToString());
+  EXPECT_EQ("Updated, Need Reboot",
+            BoxedValue(new Stage(Stage::kUpdatedNeedReboot)).ToString());
+  EXPECT_EQ("Reporting Error Event",
+            BoxedValue(new Stage(Stage::kReportingErrorEvent)).ToString());
+  EXPECT_EQ("Attempting Rollback",
+            BoxedValue(new Stage(Stage::kAttemptingRollback)).ToString());
+}
+
+TEST(UmBoxedValueTest, DeleterMarkerToString) {
+  bool marker = false;
+  BoxedValue value = BoxedValue(new DeleterMarker(&marker));
+  EXPECT_EQ("DeleterMarker:false", value.ToString());
+  marker = true;
+  EXPECT_EQ("DeleterMarker:true", value.ToString());
+}
+
+}  // namespace chromeos_update_manager
diff --git a/update_manager/chromeos_policy.cc b/update_manager/chromeos_policy.cc
new file mode 100644
index 0000000..6cf1fd1
--- /dev/null
+++ b/update_manager/chromeos_policy.cc
@@ -0,0 +1,396 @@
+// Copyright (c) 2014 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "update_engine/update_manager/chromeos_policy.h"
+
+#include <algorithm>
+#include <set>
+#include <string>
+
+#include <base/logging.h>
+#include <base/time/time.h>
+
+#include "update_engine/update_manager/device_policy_provider.h"
+#include "update_engine/update_manager/policy_utils.h"
+#include "update_engine/update_manager/shill_provider.h"
+
+using base::Time;
+using base::TimeDelta;
+using std::min;
+using std::set;
+using std::string;
+
+namespace chromeos_update_manager {
+
+EvalStatus ChromeOSPolicy::UpdateCheckAllowed(
+    EvaluationContext* ec, State* state, string* error,
+    UpdateCheckParams* result) const {
+  Time next_update_check;
+  if (NextUpdateCheckTime(ec, state, error, &next_update_check) !=
+      EvalStatus::kSucceeded) {
+    return EvalStatus::kFailed;
+  }
+
+  if (!ec->IsTimeGreaterThan(next_update_check))
+    return EvalStatus::kAskMeAgainLater;
+
+  // It is time to check for an update.
+  result->updates_enabled = true;
+  return EvalStatus::kSucceeded;
+}
+
+EvalStatus ChromeOSPolicy::UpdateCanStart(
+    EvaluationContext* ec,
+    State* state,
+    string* error,
+    UpdateCanStartResult* result,
+    const bool interactive,
+    const UpdateState& update_state) const {
+  // Set the default return values.
+  result->update_can_start = true;
+  result->http_allowed = true;
+  result->p2p_allowed = false;
+  result->target_channel.clear();
+  result->cannot_start_reason = UpdateCannotStartReason::kUndefined;
+  result->scatter_wait_period = kZeroInterval;
+  result->scatter_check_threshold = 0;
+
+  // Make sure that we're not due for an update check.
+  UpdateCheckParams check_result;
+  EvalStatus check_status = UpdateCheckAllowed(ec, state, error, &check_result);
+  if (check_status == EvalStatus::kFailed)
+    return EvalStatus::kFailed;
+  if (check_status == EvalStatus::kSucceeded &&
+      check_result.updates_enabled == true) {
+    result->update_can_start = false;
+    result->cannot_start_reason = UpdateCannotStartReason::kCheckDue;
+    return EvalStatus::kSucceeded;
+  }
+
+  DevicePolicyProvider* const dp_provider = state->device_policy_provider();
+  SystemProvider* const system_provider = state->system_provider();
+
+  const bool* device_policy_is_loaded_p = ec->GetValue(
+      dp_provider->var_device_policy_is_loaded());
+  if (device_policy_is_loaded_p && *device_policy_is_loaded_p) {
+    // Ensure that update is enabled.
+    const bool* update_disabled_p = ec->GetValue(
+        dp_provider->var_update_disabled());
+    if (update_disabled_p && *update_disabled_p) {
+      result->update_can_start = false;
+      result->cannot_start_reason = UpdateCannotStartReason::kDisabledByPolicy;
+      return EvalStatus::kAskMeAgainLater;
+    }
+
+    // Check whether scattering applies to this update attempt. We should not be
+    // scattering if this is an interactive update check, or if OOBE is enabled
+    // but not completed.
+    //
+    // Note: current code further suppresses scattering if a "deadline"
+    // attribute is found in the Omaha response. However, it appears that the
+    // presence of this attribute is merely indicative of an OOBE update, during
+    // which we suppress scattering anyway.
+    bool scattering_applies = false;
+    if (!interactive) {
+      const bool* is_oobe_enabled_p = ec->GetValue(
+          state->config_provider()->var_is_oobe_enabled());
+      if (is_oobe_enabled_p && !(*is_oobe_enabled_p)) {
+        scattering_applies = true;
+      } else {
+        const bool* is_oobe_complete_p = ec->GetValue(
+            system_provider->var_is_oobe_complete());
+        scattering_applies = (is_oobe_complete_p && *is_oobe_complete_p);
+      }
+    }
+
+    // Compute scattering values.
+    if (scattering_applies) {
+      UpdateScatteringResult scatter_result;
+      EvalStatus scattering_status = UpdateScattering(
+          ec, state, error, &scatter_result, update_state);
+      if (scattering_status != EvalStatus::kSucceeded ||
+          scatter_result.is_scattering) {
+        if (scattering_status != EvalStatus::kFailed) {
+          result->update_can_start = false;
+          result->cannot_start_reason = UpdateCannotStartReason::kScattering;
+          result->scatter_wait_period = scatter_result.wait_period;
+          result->scatter_check_threshold = scatter_result.check_threshold;
+        }
+        return scattering_status;
+      }
+    }
+
+    // Determine whether HTTP downloads are forbidden by policy. This only
+    // applies to official system builds; otherwise, HTTP is always enabled.
+    const bool* is_official_build_p = ec->GetValue(
+        system_provider->var_is_official_build());
+    if (is_official_build_p && *is_official_build_p) {
+      const bool* policy_http_downloads_enabled_p = ec->GetValue(
+          dp_provider->var_http_downloads_enabled());
+      result->http_allowed =
+          !policy_http_downloads_enabled_p || *policy_http_downloads_enabled_p;
+    }
+
+    // Determine whether use of P2P is allowed by policy.
+    const bool* policy_au_p2p_enabled_p = ec->GetValue(
+        dp_provider->var_au_p2p_enabled());
+    result->p2p_allowed = policy_au_p2p_enabled_p && *policy_au_p2p_enabled_p;
+
+    // Determine whether a target channel is dictated by policy.
+    const bool* release_channel_delegated_p = ec->GetValue(
+        dp_provider->var_release_channel_delegated());
+    if (release_channel_delegated_p && !(*release_channel_delegated_p)) {
+      const string* release_channel_p = ec->GetValue(
+          dp_provider->var_release_channel());
+      if (release_channel_p)
+        result->target_channel = *release_channel_p;
+    }
+  }
+
+  // Enable P2P, if so mandated by the updater configuration.
+  if (!result->p2p_allowed) {
+    const bool* updater_p2p_enabled_p = ec->GetValue(
+        state->updater_provider()->var_p2p_enabled());
+    result->p2p_allowed = updater_p2p_enabled_p && *updater_p2p_enabled_p;
+  }
+
+  return EvalStatus::kSucceeded;
+}
+
+EvalStatus ChromeOSPolicy::NextUpdateCheckTime(EvaluationContext* ec,
+                                               State* state, string* error,
+                                               Time* next_update_check) const {
+  // 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(state->updater_provider()->var_updater_started_time());
+  POLICY_CHECK_VALUE_AND_FAIL(updater_started_time, error);
+
+  const base::Time* last_checked_time =
+      ec->GetValue(state->updater_provider()->var_last_checked_time());
+
+  const uint64_t* seed = ec->GetValue(state->random_provider()->var_seed());
+  POLICY_CHECK_VALUE_AND_FAIL(seed, error);
+
+  PRNG prng(*seed);
+
+  if (!last_checked_time || *last_checked_time < *updater_started_time) {
+    // First attempt.
+    *next_update_check = *updater_started_time + FuzzedInterval(
+        &prng, kTimeoutInitialInterval, kTimeoutRegularFuzz);
+    return EvalStatus::kSucceeded;
+  }
+  // Check for previous failed attempts to implement the exponential backoff.
+  const unsigned int* consecutive_failed_update_checks = ec->GetValue(
+      state->updater_provider()->var_consecutive_failed_update_checks());
+  POLICY_CHECK_VALUE_AND_FAIL(consecutive_failed_update_checks, error);
+
+  int interval = kTimeoutInitialInterval;
+  for (unsigned int i = 0; i < *consecutive_failed_update_checks; ++i) {
+    interval *= 2;
+    if (interval > kTimeoutMaxBackoffInterval) {
+      interval = kTimeoutMaxBackoffInterval;
+      break;
+    }
+  }
+
+  *next_update_check = *last_checked_time + FuzzedInterval(
+      &prng, interval, kTimeoutRegularFuzz);
+  return EvalStatus::kSucceeded;
+}
+
+TimeDelta ChromeOSPolicy::FuzzedInterval(PRNG* prng, int interval, int fuzz) {
+  DCHECK_GE(interval, 0);
+  DCHECK_GE(fuzz, 0);
+  int half_fuzz = fuzz / 2;
+  // This guarantees the output interval is non negative.
+  int interval_min = std::max(interval - half_fuzz, 0);
+  int interval_max = interval + half_fuzz;
+  return TimeDelta::FromSeconds(prng->RandMinMax(interval_min, interval_max));
+}
+
+EvalStatus ChromeOSPolicy::UpdateScattering(
+    EvaluationContext* ec,
+    State* state,
+    string* error,
+    UpdateScatteringResult* result,
+    const UpdateState& update_state) const {
+  // Preconditions. These stem from the postconditions and usage contract.
+  DCHECK(update_state.scatter_wait_period >= kZeroInterval);
+  DCHECK_GE(update_state.scatter_check_threshold, 0);
+
+  // Set default result values.
+  result->is_scattering = false;
+  result->wait_period = kZeroInterval;
+  result->check_threshold = 0;
+
+  DevicePolicyProvider* const dp_provider = state->device_policy_provider();
+
+  // Ensure that a device policy is loaded.
+  const bool* device_policy_is_loaded_p = ec->GetValue(
+      dp_provider->var_device_policy_is_loaded());
+  if (!(device_policy_is_loaded_p && *device_policy_is_loaded_p))
+    return EvalStatus::kSucceeded;
+
+  // Is scattering enabled by policy?
+  const TimeDelta* scatter_factor_p = ec->GetValue(
+      dp_provider->var_scatter_factor());
+  if (!scatter_factor_p || *scatter_factor_p == kZeroInterval)
+    return EvalStatus::kSucceeded;
+
+  // Obtain a pseudo-random number generator.
+  const uint64_t* seed = ec->GetValue(state->random_provider()->var_seed());
+  POLICY_CHECK_VALUE_AND_FAIL(seed, error);
+  PRNG prng(*seed);
+
+  // Step 1: Maintain the scattering wait period.
+  //
+  // If no wait period was previously determined, or it no longer fits in the
+  // scatter factor, then generate a new one. Otherwise, keep the one we have.
+  TimeDelta wait_period = update_state.scatter_wait_period;
+  if (wait_period == kZeroInterval || wait_period > *scatter_factor_p) {
+    wait_period = TimeDelta::FromSeconds(
+        prng.RandMinMax(1, scatter_factor_p->InSeconds()));
+  }
+
+  // If we surpass the wait period or the max scatter period associated with
+  // the update, then no wait is needed.
+  Time wait_expires = (update_state.first_seen +
+                       min(wait_period, update_state.scatter_wait_period_max));
+  if (ec->IsTimeGreaterThan(wait_expires))
+    wait_period = kZeroInterval;
+
+  // Step 2: Maintain the update check threshold count.
+  //
+  // If an update check threshold is not specified then generate a new
+  // one.
+  int check_threshold = update_state.scatter_check_threshold;
+  if (check_threshold == 0) {
+    check_threshold = prng.RandMinMax(
+        update_state.scatter_check_threshold_min,
+        update_state.scatter_check_threshold_max);
+  }
+
+  // If the update check threshold is not within allowed range then nullify it.
+  // TODO(garnold) This is compliant with current logic found in
+  // OmahaRequestAction::IsUpdateCheckCountBasedWaitingSatisfied(). We may want
+  // to change it so that it behaves similarly to the wait period case, namely
+  // if the current value exceeds the maximum, we set a new one within range.
+  if (check_threshold > update_state.scatter_check_threshold_max)
+    check_threshold = 0;
+
+  // If the update check threshold is non-zero and satisfied, then nullify it.
+  if (check_threshold > 0 && update_state.num_checks >= check_threshold)
+    check_threshold = 0;
+
+  bool is_scattering = (wait_period != kZeroInterval || check_threshold);
+  EvalStatus ret = EvalStatus::kSucceeded;
+  if (is_scattering && wait_period == update_state.scatter_wait_period &&
+      check_threshold == update_state.scatter_check_threshold)
+    ret = EvalStatus::kAskMeAgainLater;
+  result->is_scattering = is_scattering;
+  result->wait_period = wait_period;
+  result->check_threshold = check_threshold;
+  return ret;
+}
+
+// TODO(garnold) Logic in this method is based on
+// ConnectionManager::IsUpdateAllowedOver(); be sure to deprecate the latter.
+//
+// TODO(garnold) The current logic generally treats the list of allowed
+// connections coming from the device policy as a whitelist, meaning that it
+// can only be used for enabling connections, but not disable them. Further,
+// certain connection types (like Bluetooth) cannot be enabled even by policy.
+// In effect, the only thing that device policy can change is to enable
+// updates over a cellular network (disabled by default). We may want to
+// revisit this semantics, allowing greater flexibility in defining specific
+// permissions over all types of networks.
+EvalStatus ChromeOSPolicy::UpdateCurrentConnectionAllowed(
+    EvaluationContext* ec,
+    State* state,
+    string* error,
+    bool* result) const {
+  // Get the current connection type.
+  ShillProvider* const shill_provider = state->shill_provider();
+  const ConnectionType* conn_type_p = ec->GetValue(
+      shill_provider->var_conn_type());
+  POLICY_CHECK_VALUE_AND_FAIL(conn_type_p, error);
+  ConnectionType conn_type = *conn_type_p;
+
+  // If we're tethering, treat it as a cellular connection.
+  if (conn_type != ConnectionType::kCellular) {
+    const ConnectionTethering* conn_tethering_p = ec->GetValue(
+        shill_provider->var_conn_tethering());
+    POLICY_CHECK_VALUE_AND_FAIL(conn_tethering_p, error);
+    if (*conn_tethering_p == ConnectionTethering::kConfirmed)
+      conn_type = ConnectionType::kCellular;
+  }
+
+  // By default, we allow updates for all connection types, with exceptions as
+  // noted below. This also determines whether a device policy can override the
+  // default.
+  *result = true;
+  bool device_policy_can_override = false;
+  switch (conn_type) {
+    case ConnectionType::kBluetooth:
+      *result = false;
+      break;
+
+    case ConnectionType::kCellular:
+      *result = false;
+      device_policy_can_override = true;
+      break;
+
+    case ConnectionType::kUnknown:
+      if (error)
+        *error = "Unknown connection type";
+      return EvalStatus::kFailed;
+
+    default:
+      break;  // Nothing to do.
+  }
+
+  // If update is allowed, we're done.
+  if (*result)
+    return EvalStatus::kSucceeded;
+
+  // Check whether the device policy specifically allows this connection.
+  bool user_settings_can_override = false;
+  if (device_policy_can_override) {
+    DevicePolicyProvider* const dp_provider = state->device_policy_provider();
+    const bool* device_policy_is_loaded_p = ec->GetValue(
+        dp_provider->var_device_policy_is_loaded());
+    if (device_policy_is_loaded_p && *device_policy_is_loaded_p) {
+      const set<ConnectionType>* allowed_conn_types_p = ec->GetValue(
+          dp_provider->var_allowed_connection_types_for_update());
+      if (allowed_conn_types_p) {
+        if (allowed_conn_types_p->count(conn_type)) {
+          *result = true;
+          return EvalStatus::kSucceeded;
+        }
+      } else {
+        user_settings_can_override = true;
+      }
+    }
+  }
+
+  // Local user settings can allow updates iff a policy was loaded but no
+  // allowed connections were specified in it. In all other cases, we either
+  // stick with the default or use the values determined by the policy.
+  if (user_settings_can_override) {
+    const bool* update_over_cellular_allowed_p = ec->GetValue(
+        state->updater_provider()->var_cellular_enabled());
+    if (update_over_cellular_allowed_p && *update_over_cellular_allowed_p)
+      *result = true;
+  }
+
+  return EvalStatus::kSucceeded;
+}
+
+}  // namespace chromeos_update_manager
diff --git a/update_manager/chromeos_policy.h b/update_manager/chromeos_policy.h
new file mode 100644
index 0000000..3c47c60
--- /dev/null
+++ b/update_manager/chromeos_policy.h
@@ -0,0 +1,111 @@
+// Copyright (c) 2014 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROMEOS_PLATFORM_UPDATE_ENGINE_UPDATE_MANAGER_CHROMEOS_POLICY_H_
+#define CHROMEOS_PLATFORM_UPDATE_ENGINE_UPDATE_MANAGER_CHROMEOS_POLICY_H_
+
+#include <base/time/time.h>
+#include <gtest/gtest_prod.h>  // for FRIEND_TEST
+
+#include "update_engine/update_manager/policy.h"
+#include "update_engine/update_manager/prng.h"
+
+namespace chromeos_update_manager {
+
+// Parameters for update scattering, as determined by UpdateNotScattering.
+struct UpdateScatteringResult {
+  bool is_scattering;
+  base::TimeDelta wait_period;
+  int check_threshold;
+};
+
+// ChromeOSPolicy implements the policy-related logic used in ChromeOS.
+class ChromeOSPolicy : public Policy {
+ public:
+  ChromeOSPolicy() {}
+  virtual ~ChromeOSPolicy() {}
+
+  // Policy overrides.
+  virtual EvalStatus UpdateCheckAllowed(
+      EvaluationContext* ec, State* state, std::string* error,
+      UpdateCheckParams* result) const override;
+
+  virtual EvalStatus UpdateCanStart(
+      EvaluationContext* ec,
+      State* state,
+      std::string* error,
+      UpdateCanStartResult* result,
+      const bool interactive,
+      const UpdateState& update_state) const override;
+
+  virtual EvalStatus UpdateCurrentConnectionAllowed(
+      EvaluationContext* ec,
+      State* state,
+      std::string* error,
+      bool* result) const override;
+
+ private:
+  friend class UmChromeOSPolicyTest;
+  FRIEND_TEST(UmChromeOSPolicyTest,
+              FirstCheckIsAtMostInitialIntervalAfterStart);
+  FRIEND_TEST(UmChromeOSPolicyTest, ExponentialBackoffIsCapped);
+  FRIEND_TEST(UmChromeOSPolicyTest, UpdateCheckAllowedWaitsForTheTimeout);
+  FRIEND_TEST(UmChromeOSPolicyTest,
+              UpdateCanStartNotAllowedScatteringNewWaitPeriodApplies);
+  FRIEND_TEST(UmChromeOSPolicyTest,
+              UpdateCanStartNotAllowedScatteringPrevWaitPeriodStillApplies);
+  FRIEND_TEST(UmChromeOSPolicyTest,
+              UpdateCanStartNotAllowedScatteringNewCountThresholdApplies);
+  FRIEND_TEST(UmChromeOSPolicyTest,
+              UpdateCanStartNotAllowedScatteringPrevCountThresholdStillApplies);
+  FRIEND_TEST(UmChromeOSPolicyTest, UpdateCanStartAllowedScatteringSatisfied);
+  FRIEND_TEST(UmChromeOSPolicyTest,
+              UpdateCanStartAllowedInteractivePreventsScattering);
+
+  // Auxiliary constant (zero by default).
+  const base::TimeDelta kZeroInterval;
+
+  // Default update check timeout interval/fuzz values used to compute the
+  // NextUpdateCheckTime(), in seconds. Actual fuzz is within +/- half of the
+  // indicated value.
+  static const int kTimeoutInitialInterval    =  7 * 60;
+  static const int kTimeoutPeriodicInterval   = 45 * 60;
+  static const int kTimeoutQuickInterval      =  1 * 60;
+  static const int kTimeoutMaxBackoffInterval =  4 * 60 * 60;
+  static const int kTimeoutRegularFuzz        = 10 * 60;
+
+  // A private policy implementation returning the wallclock timestamp when
+  // the next update check should happen.
+  EvalStatus NextUpdateCheckTime(EvaluationContext* ec, State* state,
+                                 std::string* error,
+                                 base::Time* next_update_check) const;
+
+  // Returns a TimeDelta based on the provided |interval| seconds +/- half
+  // |fuzz| seconds. The return value is guaranteed to be a non-negative
+  // TimeDelta.
+  static base::TimeDelta FuzzedInterval(PRNG* prng, int interval, int fuzz);
+
+  // A private policy for checking whether scattering is due. Writes in |result|
+  // the decision as to whether or not to scatter; a wallclock-based scatter
+  // wait period, which ranges from zero (do not wait) and no greater than the
+  // current scatter factor provided by the device policy (if available) or the
+  // maximum wait period determined by Omaha; and an update check-based
+  // threshold between zero (no threshold) and the maximum number determined by
+  // the update engine. Within |update_state|, |wait_period| should contain the
+  // last scattering period returned by this function, or zero if no wait period
+  // is known; |check_threshold| is the last update check threshold, or zero if
+  // no such threshold is known. If not scattering, or if any of the scattering
+  // values has changed, returns |EvalStatus::kSucceeded|; otherwise,
+  // |EvalStatus::kAskMeAgainLater|.
+  EvalStatus UpdateScattering(EvaluationContext* ec, State* state,
+                              std::string* error,
+                              UpdateScatteringResult* result,
+                              const UpdateState& update_state) const;
+
+  DISALLOW_COPY_AND_ASSIGN(ChromeOSPolicy);
+};
+
+}  // namespace chromeos_update_manager
+
+#endif  // CHROMEOS_PLATFORM_UPDATE_ENGINE_UPDATE_MANAGER_CHROMEOS_POLICY_H_
diff --git a/update_manager/chromeos_policy_unittest.cc b/update_manager/chromeos_policy_unittest.cc
new file mode 100644
index 0000000..0fa96b3
--- /dev/null
+++ b/update_manager/chromeos_policy_unittest.cc
@@ -0,0 +1,701 @@
+// Copyright (c) 2014 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "update_engine/update_manager/chromeos_policy.h"
+
+#include <set>
+#include <string>
+
+#include <base/time/time.h>
+#include <gtest/gtest.h>
+
+#include "update_engine/fake_clock.h"
+#include "update_engine/update_manager/evaluation_context.h"
+#include "update_engine/update_manager/fake_state.h"
+#include "update_engine/update_manager/umtest_utils.h"
+
+using base::Time;
+using base::TimeDelta;
+using chromeos_update_engine::FakeClock;
+using std::set;
+using std::string;
+
+namespace chromeos_update_manager {
+
+class UmChromeOSPolicyTest : public ::testing::Test {
+ protected:
+  virtual void SetUp() {
+    SetUpDefaultClock();
+    eval_ctx_ = new EvaluationContext(&fake_clock_);
+    SetUpDefaultState();
+    SetUpDefaultDevicePolicy();
+  }
+
+  // Sets the clock to fixed values.
+  void SetUpDefaultClock() {
+    fake_clock_.SetMonotonicTime(Time::FromInternalValue(12345678L));
+    fake_clock_.SetWallclockTime(Time::FromInternalValue(12345678901234L));
+  }
+
+  void SetUpDefaultState() {
+    fake_state_.updater_provider()->var_updater_started_time()->reset(
+        new Time(fake_clock_.GetWallclockTime()));
+    fake_state_.updater_provider()->var_last_checked_time()->reset(
+        new Time(fake_clock_.GetWallclockTime()));
+    fake_state_.updater_provider()->var_consecutive_failed_update_checks()->
+        reset(new unsigned int(0));
+
+    fake_state_.random_provider()->var_seed()->reset(
+        new uint64_t(4));  // chosen by fair dice roll.
+                           // guaranteed to be random.
+
+    // No device policy loaded by default.
+    fake_state_.device_policy_provider()->var_device_policy_is_loaded()->reset(
+        new bool(false));
+
+    // For the purpose of the tests, this is an official build and OOBE was
+    // completed.
+    fake_state_.system_provider()->var_is_official_build()->reset(
+        new bool(true));
+    fake_state_.system_provider()->var_is_oobe_complete()->reset(
+        new bool(true));
+
+    // Connection is wifi, untethered.
+    fake_state_.shill_provider()->var_conn_type()->
+        reset(new ConnectionType(ConnectionType::kWifi));
+    fake_state_.shill_provider()->var_conn_tethering()->
+        reset(new ConnectionTethering(ConnectionTethering::kNotDetected));
+  }
+
+  // Sets up a default device policy that does not impose any restrictions, nor
+  // enables any features (HTTP, P2P).
+  void SetUpDefaultDevicePolicy() {
+    fake_state_.device_policy_provider()->var_device_policy_is_loaded()->reset(
+        new bool(true));
+    fake_state_.device_policy_provider()->var_update_disabled()->reset(
+        new bool(false));
+    fake_state_.device_policy_provider()->
+        var_allowed_connection_types_for_update()->reset(nullptr);
+    fake_state_.device_policy_provider()->var_scatter_factor()->reset(
+        new TimeDelta());
+    fake_state_.device_policy_provider()->var_http_downloads_enabled()->reset(
+        new bool(false));
+    fake_state_.device_policy_provider()->var_au_p2p_enabled()->reset(
+        new bool(false));
+    fake_state_.device_policy_provider()->var_release_channel_delegated()->
+        reset(new bool(true));
+  }
+
+  // Configures the UpdateCheckAllowed policy to return a desired value by
+  // faking the current wall clock time as needed. Restores the default state.
+  // This is used when testing policies that depend on this one.
+  void SetUpdateCheckAllowed(bool allow_check) {
+    Time next_update_check;
+    ExpectPolicyStatus(EvalStatus::kSucceeded,
+                       &ChromeOSPolicy::NextUpdateCheckTime,
+                       &next_update_check);
+    SetUpDefaultState();
+    SetUpDefaultDevicePolicy();
+    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);
+  }
+
+  // Returns a default UpdateState structure: first seen time is calculated
+  // backward from the current wall clock time, update was seen just once, there
+  // is no scattering wait period and the max allowed is 7 days, there is no
+  // check threshold and none is allowed.
+  UpdateState GetDefaultUpdateState(TimeDelta update_first_seen_period) {
+    UpdateState update_state = {
+      fake_clock_.GetWallclockTime() - update_first_seen_period, 1,
+      TimeDelta(), TimeDelta::FromDays(7), 0, 0, 0
+    };
+    return update_state;
+  }
+
+  // Runs the passed |policy_method| policy and expects it to return the
+  // |expected| return value.
+  template<typename T, typename R, typename... Args>
+  void ExpectPolicyStatus(
+      EvalStatus expected,
+      T policy_method,
+      R* result, Args... args) {
+    string error = "<None>";
+    eval_ctx_->ResetEvaluation();
+    EXPECT_EQ(expected,
+              (policy_.*policy_method)(eval_ctx_, &fake_state_, &error, result,
+                                       args...))
+        << "Returned error: " << error
+        << "\nEvaluation context: " << eval_ctx_->DumpContext();
+  }
+
+  FakeClock fake_clock_;
+  FakeState fake_state_;
+  scoped_refptr<EvaluationContext> eval_ctx_;
+  ChromeOSPolicy policy_;  // ChromeOSPolicy under test.
+};
+
+TEST_F(UmChromeOSPolicyTest, FirstCheckIsAtMostInitialIntervalAfterStart) {
+  Time next_update_check;
+
+  ExpectPolicyStatus(EvalStatus::kSucceeded,
+                     &ChromeOSPolicy::NextUpdateCheckTime, &next_update_check);
+
+  EXPECT_LE(fake_clock_.GetWallclockTime(), next_update_check);
+  EXPECT_GE(fake_clock_.GetWallclockTime() + TimeDelta::FromSeconds(
+      ChromeOSPolicy::kTimeoutInitialInterval +
+      ChromeOSPolicy::kTimeoutRegularFuzz), next_update_check);
+}
+
+TEST_F(UmChromeOSPolicyTest, ExponentialBackoffIsCapped) {
+  Time next_update_check;
+
+  fake_state_.updater_provider()->var_consecutive_failed_update_checks()->
+      reset(new unsigned int(100));
+  ExpectPolicyStatus(EvalStatus::kSucceeded,
+                     &ChromeOSPolicy::NextUpdateCheckTime, &next_update_check);
+
+  EXPECT_LE(fake_clock_.GetWallclockTime() + TimeDelta::FromSeconds(
+      ChromeOSPolicy::kTimeoutMaxBackoffInterval -
+      ChromeOSPolicy::kTimeoutRegularFuzz - 1), next_update_check);
+  EXPECT_GE(fake_clock_.GetWallclockTime() + TimeDelta::FromSeconds(
+      ChromeOSPolicy::kTimeoutMaxBackoffInterval +
+      ChromeOSPolicy::kTimeoutRegularFuzz), next_update_check);
+}
+
+TEST_F(UmChromeOSPolicyTest, UpdateCheckAllowedWaitsForTheTimeout) {
+  // We get the next update_check timestamp from the policy's private method
+  // and then we check the public method respects that value on the normal
+  // case.
+  Time next_update_check;
+  Time last_checked_time =
+      fake_clock_.GetWallclockTime() + TimeDelta::FromMinutes(1234);
+
+  fake_state_.updater_provider()->var_last_checked_time()->reset(
+      new Time(last_checked_time));
+  ExpectPolicyStatus(EvalStatus::kSucceeded,
+                     &ChromeOSPolicy::NextUpdateCheckTime, &next_update_check);
+
+  UpdateCheckParams result;
+
+  // 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));
+  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);
+}
+
+TEST_F(UmChromeOSPolicyTest, UpdateCanStartFailsCheckAllowedError) {
+  // The UpdateCanStart policy fails, not being able to query
+  // UpdateCheckAllowed.
+
+  // Configure the UpdateCheckAllowed policy to fail.
+  fake_state_.updater_provider()->var_updater_started_time()->reset(nullptr);
+
+  // Check that the UpdateCanStart fails.
+  UpdateState update_state = GetDefaultUpdateState(TimeDelta::FromMinutes(10));
+  UpdateCanStartResult result;
+  ExpectPolicyStatus(EvalStatus::kFailed,
+                     &Policy::UpdateCanStart, &result, false, update_state);
+}
+
+TEST_F(UmChromeOSPolicyTest, UpdateCanStartNotAllowedCheckDue) {
+  // The UpdateCanStart policy returns false because we are due for another
+  // update check.
+
+  SetUpdateCheckAllowed(true);
+
+  // Check that the UpdateCanStart returns false.
+  UpdateState update_state = GetDefaultUpdateState(TimeDelta::FromMinutes(10));
+  UpdateCanStartResult result;
+  ExpectPolicyStatus(EvalStatus::kSucceeded,
+                     &Policy::UpdateCanStart, &result, false, update_state);
+  EXPECT_FALSE(result.update_can_start);
+  EXPECT_EQ(UpdateCannotStartReason::kCheckDue, result.cannot_start_reason);
+}
+
+TEST_F(UmChromeOSPolicyTest, UpdateCanStartAllowedNoDevicePolicy) {
+  // The UpdateCanStart policy returns true; no device policy is loaded.
+
+  SetUpdateCheckAllowed(false);
+  fake_state_.device_policy_provider()->var_device_policy_is_loaded()->reset(
+      new bool(false));
+
+  // Check that the UpdateCanStart returns true with no further attributes.
+  UpdateState update_state = GetDefaultUpdateState(TimeDelta::FromMinutes(10));
+  UpdateCanStartResult result;
+  ExpectPolicyStatus(EvalStatus::kSucceeded,
+                     &Policy::UpdateCanStart, &result, false, update_state);
+  EXPECT_TRUE(result.update_can_start);
+  EXPECT_TRUE(result.http_allowed);
+  EXPECT_FALSE(result.p2p_allowed);
+  EXPECT_TRUE(result.target_channel.empty());
+}
+
+TEST_F(UmChromeOSPolicyTest, UpdateCanStartAllowedBlankPolicy) {
+  // The UpdateCanStart policy returns true; device policy is loaded but imposes
+  // no restrictions on updating.
+
+  SetUpdateCheckAllowed(false);
+
+  // Check that the UpdateCanStart returns true.
+  UpdateState update_state = GetDefaultUpdateState(TimeDelta::FromMinutes(10));
+  UpdateCanStartResult result;
+  ExpectPolicyStatus(EvalStatus::kSucceeded,
+                     &Policy::UpdateCanStart, &result, false, update_state);
+  EXPECT_TRUE(result.update_can_start);
+  EXPECT_FALSE(result.http_allowed);
+  EXPECT_FALSE(result.p2p_allowed);
+  EXPECT_TRUE(result.target_channel.empty());
+}
+
+TEST_F(UmChromeOSPolicyTest, UpdateCanStartNotAllowedUpdatesDisabled) {
+  // The UpdateCanStart should return false (kAskMeAgainlater) because a device
+  // policy is loaded and prohibits updates.
+
+  SetUpdateCheckAllowed(false);
+  fake_state_.device_policy_provider()->var_update_disabled()->reset(
+      new bool(true));
+
+  // Check that the UpdateCanStart returns false.
+  UpdateState update_state = GetDefaultUpdateState(TimeDelta::FromMinutes(10));
+  UpdateCanStartResult result;
+  ExpectPolicyStatus(EvalStatus::kAskMeAgainLater,
+                     &Policy::UpdateCanStart, &result, false, update_state);
+  EXPECT_FALSE(result.update_can_start);
+  EXPECT_EQ(UpdateCannotStartReason::kDisabledByPolicy,
+            result.cannot_start_reason);
+}
+
+TEST_F(UmChromeOSPolicyTest, UpdateCanStartFailsScatteringFailed) {
+  // The UpdateCanStart policy fails because the UpdateScattering policy it
+  // depends on fails (unset variable).
+
+  SetUpdateCheckAllowed(false);
+
+  // Override the default seed variable with a null value so that the policy
+  // request would fail.
+  fake_state_.random_provider()->var_seed()->reset(nullptr);
+
+  // Check that the UpdateCanStart fails.
+  UpdateState update_state = GetDefaultUpdateState(TimeDelta::FromSeconds(1));
+  UpdateCanStartResult result;
+  ExpectPolicyStatus(EvalStatus::kFailed,
+                     &Policy::UpdateCanStart, &result, false, update_state);
+}
+
+TEST_F(UmChromeOSPolicyTest,
+       UpdateCanStartNotAllowedScatteringNewWaitPeriodApplies) {
+  // The UpdateCanStart policy returns false; device policy is loaded and
+  // scattering applies due to an unsatisfied wait period, which was newly
+  // generated.
+
+  SetUpdateCheckAllowed(false);
+  fake_state_.device_policy_provider()->var_scatter_factor()->reset(
+      new TimeDelta(TimeDelta::FromMinutes(2)));
+
+
+  UpdateState update_state = GetDefaultUpdateState(TimeDelta::FromSeconds(1));
+
+  // Check that the UpdateCanStart returns false and a new wait period
+  // generated.
+  UpdateCanStartResult result;
+  ExpectPolicyStatus(EvalStatus::kSucceeded, &Policy::UpdateCanStart, &result,
+                     false, update_state);
+  EXPECT_FALSE(result.update_can_start);
+  EXPECT_EQ(UpdateCannotStartReason::kScattering, result.cannot_start_reason);
+  EXPECT_LT(TimeDelta(), result.scatter_wait_period);
+  EXPECT_EQ(0, result.scatter_check_threshold);
+}
+
+TEST_F(UmChromeOSPolicyTest,
+       UpdateCanStartNotAllowedScatteringPrevWaitPeriodStillApplies) {
+  // The UpdateCanStart policy returns false w/ kAskMeAgainLater; device policy
+  // is loaded and a previously generated scattering period still applies, none
+  // of the scattering values has changed.
+
+  SetUpdateCheckAllowed(false);
+  fake_state_.device_policy_provider()->var_scatter_factor()->reset(
+      new TimeDelta(TimeDelta::FromMinutes(2)));
+
+  UpdateState update_state = GetDefaultUpdateState(TimeDelta::FromSeconds(1));
+  update_state.scatter_wait_period = TimeDelta::FromSeconds(35);
+
+  // Check that the UpdateCanStart returns false and a new wait period
+  // generated.
+  UpdateCanStartResult result;
+  ExpectPolicyStatus(EvalStatus::kAskMeAgainLater, &Policy::UpdateCanStart,
+                     &result, false, update_state);
+  EXPECT_FALSE(result.update_can_start);
+  EXPECT_EQ(UpdateCannotStartReason::kScattering, result.cannot_start_reason);
+  EXPECT_EQ(TimeDelta::FromSeconds(35), result.scatter_wait_period);
+  EXPECT_EQ(0, result.scatter_check_threshold);
+}
+
+TEST_F(UmChromeOSPolicyTest,
+       UpdateCanStartNotAllowedScatteringNewCountThresholdApplies) {
+  // The UpdateCanStart policy returns false; device policy is loaded and
+  // scattering applies due to an unsatisfied update check count threshold.
+  //
+  // This ensures a non-zero check threshold, which may or may not be combined
+  // with a non-zero wait period (for which we cannot reliably control).
+
+  SetUpdateCheckAllowed(false);
+  fake_state_.device_policy_provider()->var_scatter_factor()->reset(
+      new TimeDelta(TimeDelta::FromSeconds(1)));
+
+  UpdateState update_state = GetDefaultUpdateState(TimeDelta::FromSeconds(1));
+  update_state.scatter_check_threshold_min = 2;
+  update_state.scatter_check_threshold_max = 5;
+
+  // Check that the UpdateCanStart returns false.
+  UpdateCanStartResult result;
+  ExpectPolicyStatus(EvalStatus::kSucceeded, &Policy::UpdateCanStart, &result,
+                     false, update_state);
+  EXPECT_FALSE(result.update_can_start);
+  EXPECT_EQ(UpdateCannotStartReason::kScattering, result.cannot_start_reason);
+  EXPECT_LE(2, result.scatter_check_threshold);
+  EXPECT_GE(5, result.scatter_check_threshold);
+}
+
+TEST_F(UmChromeOSPolicyTest,
+       UpdateCanStartNotAllowedScatteringPrevCountThresholdStillApplies) {
+  // The UpdateCanStart policy returns false; device policy is loaded and
+  // scattering due to a previously generated count threshold still applies.
+
+  SetUpdateCheckAllowed(false);
+  fake_state_.device_policy_provider()->var_scatter_factor()->reset(
+      new TimeDelta(TimeDelta::FromSeconds(1)));
+
+  UpdateState update_state = GetDefaultUpdateState(TimeDelta::FromSeconds(1));
+  update_state.scatter_check_threshold = 3;
+  update_state.scatter_check_threshold_min = 2;
+  update_state.scatter_check_threshold_max = 5;
+
+  // Check that the UpdateCanStart returns false.
+  UpdateCanStartResult result;
+  ExpectPolicyStatus(EvalStatus::kSucceeded, &Policy::UpdateCanStart, &result,
+                     false, update_state);
+  EXPECT_FALSE(result.update_can_start);
+  EXPECT_EQ(UpdateCannotStartReason::kScattering, result.cannot_start_reason);
+  EXPECT_EQ(3, result.scatter_check_threshold);
+}
+
+TEST_F(UmChromeOSPolicyTest, UpdateCanStartAllowedScatteringSatisfied) {
+  // The UpdateCanStart policy returns true; device policy is loaded and
+  // scattering is enabled, but both wait period and check threshold are
+  // satisfied.
+
+  SetUpdateCheckAllowed(false);
+  fake_state_.device_policy_provider()->var_scatter_factor()->reset(
+      new TimeDelta(TimeDelta::FromSeconds(120)));
+
+  UpdateState update_state = GetDefaultUpdateState(TimeDelta::FromSeconds(75));
+  update_state.num_checks = 4;
+  update_state.scatter_wait_period = TimeDelta::FromSeconds(60);
+  update_state.scatter_check_threshold = 3;
+  update_state.scatter_check_threshold_min = 2;
+  update_state.scatter_check_threshold_max = 5;
+
+  // Check that the UpdateCanStart returns true.
+  UpdateCanStartResult result;
+  ExpectPolicyStatus(EvalStatus::kSucceeded, &Policy::UpdateCanStart, &result,
+                     false, update_state);
+  EXPECT_TRUE(result.update_can_start);
+  EXPECT_EQ(TimeDelta(), result.scatter_wait_period);
+  EXPECT_EQ(0, result.scatter_check_threshold);
+}
+
+TEST_F(UmChromeOSPolicyTest,
+       UpdateCanStartAllowedInteractivePreventsScattering) {
+  // The UpdateCanStart policy returns true; device policy is loaded and
+  // scattering would have applied, except that the update check is interactive
+  // and so it is suppressed.
+
+  SetUpdateCheckAllowed(false);
+  fake_state_.device_policy_provider()->var_scatter_factor()->reset(
+      new TimeDelta(TimeDelta::FromSeconds(1)));
+
+  UpdateState update_state = GetDefaultUpdateState(TimeDelta::FromSeconds(1));
+  update_state.scatter_check_threshold = 0;
+  update_state.scatter_check_threshold_min = 2;
+  update_state.scatter_check_threshold_max = 5;
+
+  // Check that the UpdateCanStart returns true.
+  UpdateCanStartResult result;
+  ExpectPolicyStatus(EvalStatus::kSucceeded, &Policy::UpdateCanStart, &result,
+                     true, update_state);
+  EXPECT_TRUE(result.update_can_start);
+  EXPECT_EQ(TimeDelta(), result.scatter_wait_period);
+  EXPECT_EQ(0, result.scatter_check_threshold);
+}
+
+TEST_F(UmChromeOSPolicyTest,
+       UpdateCanStartAllowedOobePreventsScattering) {
+  // The UpdateCanStart policy returns true; device policy is loaded and
+  // scattering would have applied, except that OOBE was not completed and so it
+  // is suppressed.
+
+  SetUpdateCheckAllowed(false);
+  fake_state_.device_policy_provider()->var_scatter_factor()->reset(
+      new TimeDelta(TimeDelta::FromSeconds(1)));
+  fake_state_.system_provider()->var_is_oobe_complete()->reset(new bool(false));
+
+  UpdateState update_state = GetDefaultUpdateState(TimeDelta::FromSeconds(1));
+  update_state.scatter_check_threshold = 0;
+  update_state.scatter_check_threshold_min = 2;
+  update_state.scatter_check_threshold_max = 5;
+
+  // Check that the UpdateCanStart returns true.
+  UpdateCanStartResult result;
+  ExpectPolicyStatus(EvalStatus::kSucceeded, &Policy::UpdateCanStart, &result,
+                     true, update_state);
+  EXPECT_TRUE(result.update_can_start);
+  EXPECT_EQ(TimeDelta(), result.scatter_wait_period);
+  EXPECT_EQ(0, result.scatter_check_threshold);
+}
+
+TEST_F(UmChromeOSPolicyTest, UpdateCanStartAllowedWithAttributes) {
+  // The UpdateCanStart policy returns true; device policy permits both HTTP and
+  // P2P updates, as well as a non-empty target channel string.
+
+  SetUpdateCheckAllowed(false);
+
+  // Override specific device policy attributes.
+  fake_state_.device_policy_provider()->var_http_downloads_enabled()->reset(
+      new bool(true));
+  fake_state_.device_policy_provider()->var_au_p2p_enabled()->reset(
+      new bool(true));
+  fake_state_.device_policy_provider()->var_release_channel_delegated()->
+      reset(new bool(false));
+  fake_state_.device_policy_provider()->var_release_channel()->
+      reset(new string("foo-channel"));
+
+  // Check that the UpdateCanStart returns true.
+  UpdateState update_state = GetDefaultUpdateState(TimeDelta::FromMinutes(10));
+  UpdateCanStartResult result;
+  ExpectPolicyStatus(EvalStatus::kSucceeded, &Policy::UpdateCanStart, &result,
+                     false, update_state);
+  EXPECT_TRUE(result.update_can_start);
+  EXPECT_TRUE(result.http_allowed);
+  EXPECT_TRUE(result.p2p_allowed);
+  EXPECT_EQ("foo-channel", result.target_channel);
+}
+
+TEST_F(UmChromeOSPolicyTest, UpdateCanStartAllowedWithP2PFromUpdater) {
+  // The UpdateCanStart policy returns true; device policy forbids both HTTP and
+  // P2P updates, but the updater is configured to allow P2P and overrules the
+  // setting.
+
+  SetUpdateCheckAllowed(false);
+
+  // Override specific device policy attributes.
+  fake_state_.device_policy_provider()->var_release_channel_delegated()->
+      reset(new bool(false));
+  fake_state_.device_policy_provider()->var_release_channel()->
+      reset(new string("foo-channel"));
+  fake_state_.updater_provider()->var_p2p_enabled()->reset(new bool(true));
+
+  // Check that the UpdateCanStart returns true.
+  UpdateState update_state = GetDefaultUpdateState(TimeDelta::FromMinutes(10));
+  UpdateCanStartResult result;
+  ExpectPolicyStatus(EvalStatus::kSucceeded, &Policy::UpdateCanStart, &result,
+                     false, update_state);
+  EXPECT_TRUE(result.update_can_start);
+  EXPECT_FALSE(result.http_allowed);
+  EXPECT_TRUE(result.p2p_allowed);
+  EXPECT_EQ("foo-channel", result.target_channel);
+}
+
+TEST_F(UmChromeOSPolicyTest, UpdateCanStartAllowedWithHttpForUnofficialBuild) {
+  // The UpdateCanStart policy returns true; device policy forbids both HTTP and
+  // P2P updates, but marking this an unofficial build overrules the HTTP
+  // setting.
+
+  SetUpdateCheckAllowed(false);
+
+  // Override specific device policy attributes.
+  fake_state_.device_policy_provider()->var_release_channel_delegated()->
+      reset(new bool(false));
+  fake_state_.device_policy_provider()->var_release_channel()->
+      reset(new string("foo-channel"));
+  fake_state_.system_provider()->var_is_official_build()->
+      reset(new bool(false));
+
+  // Check that the UpdateCanStart returns true.
+  UpdateState update_state = GetDefaultUpdateState(TimeDelta::FromMinutes(10));
+  UpdateCanStartResult result;
+  ExpectPolicyStatus(EvalStatus::kSucceeded, &Policy::UpdateCanStart, &result,
+                     false, update_state);
+  EXPECT_TRUE(result.update_can_start);
+  EXPECT_TRUE(result.http_allowed);
+  EXPECT_FALSE(result.p2p_allowed);
+  EXPECT_EQ("foo-channel", result.target_channel);
+}
+
+TEST_F(UmChromeOSPolicyTest, UpdateCurrentConnectionAllowedEthernetDefault) {
+  // Ethernet is always allowed.
+
+  fake_state_.shill_provider()->var_conn_type()->
+      reset(new ConnectionType(ConnectionType::kEthernet));
+
+  bool result;
+  ExpectPolicyStatus(EvalStatus::kSucceeded,
+                     &Policy::UpdateCurrentConnectionAllowed, &result);
+  EXPECT_TRUE(result);
+}
+
+TEST_F(UmChromeOSPolicyTest, UpdateCurrentConnectionAllowedWifiDefault) {
+  // Wifi is allowed if not tethered.
+
+  fake_state_.shill_provider()->var_conn_type()->
+      reset(new ConnectionType(ConnectionType::kWifi));
+
+  bool result;
+  ExpectPolicyStatus(EvalStatus::kSucceeded,
+                     &Policy::UpdateCurrentConnectionAllowed, &result);
+  EXPECT_TRUE(result);
+}
+
+TEST_F(UmChromeOSPolicyTest,
+       UpdateCurrentConnectionNotAllowedWifiTetheredDefault) {
+  // Tethered wifi is not allowed by default.
+
+  fake_state_.shill_provider()->var_conn_type()->
+      reset(new ConnectionType(ConnectionType::kWifi));
+  fake_state_.shill_provider()->var_conn_tethering()->
+      reset(new ConnectionTethering(ConnectionTethering::kConfirmed));
+
+  bool result;
+  ExpectPolicyStatus(EvalStatus::kSucceeded,
+                     &Policy::UpdateCurrentConnectionAllowed, &result);
+  EXPECT_FALSE(result);
+}
+
+TEST_F(UmChromeOSPolicyTest,
+       UpdateCurrentConnectionAllowedWifiTetheredPolicyOverride) {
+  // Tethered wifi can be allowed by policy.
+
+  fake_state_.shill_provider()->var_conn_type()->
+      reset(new ConnectionType(ConnectionType::kWifi));
+  fake_state_.shill_provider()->var_conn_tethering()->
+      reset(new ConnectionTethering(ConnectionTethering::kConfirmed));
+  set<ConnectionType> allowed_connections;
+  allowed_connections.insert(ConnectionType::kCellular);
+  fake_state_.device_policy_provider()->
+      var_allowed_connection_types_for_update()->
+      reset(new set<ConnectionType>(allowed_connections));
+
+  bool result;
+  ExpectPolicyStatus(EvalStatus::kSucceeded,
+                     &Policy::UpdateCurrentConnectionAllowed, &result);
+  EXPECT_TRUE(result);
+}
+
+TEST_F(UmChromeOSPolicyTest, UpdateCurrentConnectionAllowedWimaxDefault) {
+  // Wimax is always allowed.
+
+  fake_state_.shill_provider()->var_conn_type()->
+      reset(new ConnectionType(ConnectionType::kWifi));
+
+  bool result;
+  ExpectPolicyStatus(EvalStatus::kSucceeded,
+                     &Policy::UpdateCurrentConnectionAllowed, &result);
+  EXPECT_TRUE(result);
+}
+
+TEST_F(UmChromeOSPolicyTest,
+       UpdateCurrentConnectionNotAllowedBluetoothDefault) {
+  // Bluetooth is never allowed.
+
+  fake_state_.shill_provider()->var_conn_type()->
+      reset(new ConnectionType(ConnectionType::kBluetooth));
+
+  bool result;
+  ExpectPolicyStatus(EvalStatus::kSucceeded,
+                     &Policy::UpdateCurrentConnectionAllowed, &result);
+  EXPECT_FALSE(result);
+}
+
+TEST_F(UmChromeOSPolicyTest,
+       UpdateCurrentConnectionNotAllowedBluetoothPolicyCannotOverride) {
+  // Bluetooth cannot be allowed even by policy.
+
+  fake_state_.shill_provider()->var_conn_type()->
+      reset(new ConnectionType(ConnectionType::kBluetooth));
+  set<ConnectionType> allowed_connections;
+  allowed_connections.insert(ConnectionType::kBluetooth);
+  fake_state_.device_policy_provider()->
+      var_allowed_connection_types_for_update()->
+      reset(new set<ConnectionType>(allowed_connections));
+
+  bool result;
+  ExpectPolicyStatus(EvalStatus::kSucceeded,
+                     &Policy::UpdateCurrentConnectionAllowed, &result);
+  EXPECT_FALSE(result);
+}
+
+TEST_F(UmChromeOSPolicyTest, UpdateCurrentConnectionNotAllowedCellularDefault) {
+  // Cellular is not allowed by default.
+
+  fake_state_.shill_provider()->var_conn_type()->
+      reset(new ConnectionType(ConnectionType::kCellular));
+
+  bool result;
+  ExpectPolicyStatus(EvalStatus::kSucceeded,
+                     &Policy::UpdateCurrentConnectionAllowed, &result);
+  EXPECT_FALSE(result);
+}
+
+TEST_F(UmChromeOSPolicyTest,
+       UpdateCurrentConnectionAllowedCellularPolicyOverride) {
+  // Update over cellular can be enabled by policy.
+
+  fake_state_.shill_provider()->var_conn_type()->
+      reset(new ConnectionType(ConnectionType::kCellular));
+  set<ConnectionType> allowed_connections;
+  allowed_connections.insert(ConnectionType::kCellular);
+  fake_state_.device_policy_provider()->
+      var_allowed_connection_types_for_update()->
+      reset(new set<ConnectionType>(allowed_connections));
+
+  bool result;
+  ExpectPolicyStatus(EvalStatus::kSucceeded,
+                     &Policy::UpdateCurrentConnectionAllowed, &result);
+  EXPECT_TRUE(result);
+}
+
+TEST_F(UmChromeOSPolicyTest,
+       UpdateCurrentConnectionAllowedCellularUserOverride) {
+  // Update over cellular can be enabled by user settings, but only if policy
+  // is present and does not determine allowed connections.
+
+  fake_state_.shill_provider()->var_conn_type()->
+      reset(new ConnectionType(ConnectionType::kCellular));
+  set<ConnectionType> allowed_connections;
+  allowed_connections.insert(ConnectionType::kCellular);
+  fake_state_.updater_provider()->var_cellular_enabled()->
+      reset(new bool(true));
+
+  bool result;
+  ExpectPolicyStatus(EvalStatus::kSucceeded,
+                     &Policy::UpdateCurrentConnectionAllowed, &result);
+  EXPECT_TRUE(result);
+}
+
+}  // namespace chromeos_update_manager
diff --git a/update_manager/config_provider.h b/update_manager/config_provider.h
new file mode 100644
index 0000000..55a4d7a
--- /dev/null
+++ b/update_manager/config_provider.h
@@ -0,0 +1,31 @@
+// Copyright (c) 2014 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROMEOS_PLATFORM_UPDATE_ENGINE_UPDATE_MANAGER_CONFIG_PROVIDER_H_
+#define CHROMEOS_PLATFORM_UPDATE_ENGINE_UPDATE_MANAGER_CONFIG_PROVIDER_H_
+
+#include "update_engine/update_manager/provider.h"
+#include "update_engine/update_manager/variable.h"
+
+namespace chromeos_update_manager {
+
+// Provider for const system configurations. This provider reads the
+// configuration from a file on /etc.
+class ConfigProvider : public Provider {
+ public:
+  // Returns a variable stating whether the out of the box experience (OOBE) is
+  // enabled on this device. A value of false means that the device doesn't have
+  // an OOBE workflow.
+  virtual Variable<bool>* var_is_oobe_enabled() = 0;
+
+ protected:
+  ConfigProvider() {}
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(ConfigProvider);
+};
+
+}  // namespace chromeos_update_manager
+
+#endif  // CHROMEOS_PLATFORM_UPDATE_ENGINE_UPDATE_MANAGER_CONFIG_PROVIDER_H_
diff --git a/update_manager/default_policy.h b/update_manager/default_policy.h
new file mode 100644
index 0000000..b3767dc
--- /dev/null
+++ b/update_manager/default_policy.h
@@ -0,0 +1,62 @@
+// Copyright (c) 2014 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROMEOS_PLATFORM_UPDATE_ENGINE_UPDATE_MANAGER_DEFAULT_POLICY_H_
+#define CHROMEOS_PLATFORM_UPDATE_ENGINE_UPDATE_MANAGER_DEFAULT_POLICY_H_
+
+#include <base/time/time.h>
+
+#include "update_engine/update_manager/policy.h"
+
+namespace chromeos_update_manager {
+
+// The DefaultPolicy is a safe Policy implementation that doesn't fail. The
+// values returned by this policy are safe default in case of failure of the
+// actual policy being used by the UpdateManager.
+class DefaultPolicy : public Policy {
+ public:
+  DefaultPolicy() {}
+  virtual ~DefaultPolicy() {}
+
+  // Policy overrides.
+  virtual EvalStatus UpdateCheckAllowed(
+      EvaluationContext* ec, State* state, std::string* error,
+      UpdateCheckParams* result) const override {
+    result->updates_enabled = true;
+    return EvalStatus::kSucceeded;
+  }
+
+  virtual EvalStatus UpdateCanStart(
+      EvaluationContext* ec,
+      State* state,
+      std::string* error,
+      UpdateCanStartResult* result,
+      const bool interactive,
+      const UpdateState& update_state) const override {
+    result->update_can_start = true;
+    result->http_allowed = false;
+    result->p2p_allowed = false;
+    result->target_channel.clear();
+    result->cannot_start_reason = UpdateCannotStartReason::kUndefined;
+    result->scatter_wait_period = base::TimeDelta();
+    result->scatter_check_threshold = 0;
+    return EvalStatus::kSucceeded;
+  }
+
+  virtual EvalStatus UpdateCurrentConnectionAllowed(
+      EvaluationContext* ec,
+      State* state,
+      std::string* error,
+      bool* result) const override {
+    *result = true;
+    return EvalStatus::kSucceeded;
+  }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(DefaultPolicy);
+};
+
+}  // namespace chromeos_update_manager
+
+#endif  // CHROMEOS_PLATFORM_UPDATE_ENGINE_UPDATE_MANAGER_DEFAULT_POLICY_H_
diff --git a/update_manager/device_policy_provider.h b/update_manager/device_policy_provider.h
new file mode 100644
index 0000000..f612d55
--- /dev/null
+++ b/update_manager/device_policy_provider.h
@@ -0,0 +1,63 @@
+// Copyright (c) 2014 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROMEOS_PLATFORM_UPDATE_ENGINE_UPDATE_MANAGER_DEVICE_POLICY_PROVIDER_H_
+#define CHROMEOS_PLATFORM_UPDATE_ENGINE_UPDATE_MANAGER_DEVICE_POLICY_PROVIDER_H_
+
+#include <set>
+#include <string>
+
+#include <base/time/time.h>
+#include <policy/libpolicy.h>
+
+#include "update_engine/update_manager/provider.h"
+#include "update_engine/update_manager/shill_provider.h"
+#include "update_engine/update_manager/variable.h"
+
+namespace chromeos_update_manager {
+
+// Provides access to the current DevicePolicy.
+class DevicePolicyProvider : public Provider {
+ public:
+  virtual ~DevicePolicyProvider() {}
+
+  // Variable stating whether the DevicePolicy was loaded.
+  virtual Variable<bool>* var_device_policy_is_loaded() = 0;
+
+  // Variables mapping the information received on the DevicePolicy protobuf.
+  virtual Variable<std::string>* var_release_channel() = 0;
+
+  virtual Variable<bool>* var_release_channel_delegated() = 0;
+
+  virtual Variable<bool>* var_update_disabled() = 0;
+
+  virtual Variable<std::string>* var_target_version_prefix() = 0;
+
+  // Returns a non-negative scatter interval used for updates.
+  virtual Variable<base::TimeDelta>* var_scatter_factor() = 0;
+
+  // Variable returing the set of connection types allowed for updates. The
+  // identifiers returned are consistent with the ones returned by the
+  // ShillProvider.
+  virtual Variable<std::set<ConnectionType>>*
+      var_allowed_connection_types_for_update() = 0;
+
+  // Variable stating the name of the device owner. For enterprise enrolled
+  // devices, this will be an empty string.
+  virtual Variable<std::string>* var_get_owner() = 0;
+
+  virtual Variable<bool>* var_http_downloads_enabled() = 0;
+
+  virtual Variable<bool>* var_au_p2p_enabled() = 0;
+
+ protected:
+  DevicePolicyProvider() {}
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(DevicePolicyProvider);
+};
+
+}  // namespace chromeos_update_manager
+
+#endif  // CHROMEOS_PLATFORM_UPDATE_ENGINE_UPDATE_MANAGER_DEVICE_POLICY_PROVIDER_H_
diff --git a/update_manager/evaluation_context-inl.h b/update_manager/evaluation_context-inl.h
new file mode 100644
index 0000000..962d0e9
--- /dev/null
+++ b/update_manager/evaluation_context-inl.h
@@ -0,0 +1,41 @@
+// Copyright (c) 2014 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROMEOS_PLATFORM_UPDATE_ENGINE_UPDATE_MANAGER_EVALUATION_CONTEXT_INL_H_
+#define CHROMEOS_PLATFORM_UPDATE_ENGINE_UPDATE_MANAGER_EVALUATION_CONTEXT_INL_H_
+
+#include <base/logging.h>
+
+namespace chromeos_update_manager {
+
+template<typename T>
+const T* EvaluationContext::GetValue(Variable<T>* var) {
+  if (var == nullptr) {
+    LOG(ERROR) << "GetValue received an uninitialized variable.";
+    return nullptr;
+  }
+
+  // Search for the value on the cache first.
+  ValueCacheMap::iterator it = value_cache_.find(var);
+  if (it != value_cache_.end())
+    return reinterpret_cast<const T*>(it->second.value());
+
+  // Get the value from the variable if not found on the cache.
+  std::string errmsg;
+  const T* result = var->GetValue(RemainingTime(), &errmsg);
+  if (result == nullptr) {
+    LOG(WARNING) << "Error reading Variable " << var->GetName() << ": \""
+        << errmsg << "\"";
+  }
+  // Cache the value for the next time. The map of CachedValues keeps the
+  // ownership of the pointer until the map is destroyed.
+  value_cache_.emplace(
+    static_cast<BaseVariable*>(var),
+    std::move(BoxedValue(result)));
+  return result;
+}
+
+}  // namespace chromeos_update_manager
+
+#endif  // CHROMEOS_PLATFORM_UPDATE_ENGINE_UPDATE_MANAGER_EVALUATION_CONTEXT_INL_H_
diff --git a/update_manager/evaluation_context.cc b/update_manager/evaluation_context.cc
new file mode 100644
index 0000000..4fc9a16
--- /dev/null
+++ b/update_manager/evaluation_context.cc
@@ -0,0 +1,163 @@
+// Copyright (c) 2014 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "update_engine/update_manager/evaluation_context.h"
+
+#include <string>
+
+#include <base/bind.h>
+#include <base/json/json_writer.h>
+#include <base/values.h>
+
+#include "update_engine/utils.h"
+
+using base::Closure;
+using base::Time;
+using base::TimeDelta;
+using chromeos_update_engine::ClockInterface;
+using std::string;
+
+namespace chromeos_update_manager {
+
+EvaluationContext::EvaluationContext(ClockInterface* clock)
+    : clock_(clock),
+      weak_ptr_factory_(this) {
+  ResetEvaluation();
+}
+
+EvaluationContext::~EvaluationContext() {
+  RemoveObserversAndTimeout();
+}
+
+void EvaluationContext::RemoveObserversAndTimeout() {
+  for (auto& it : value_cache_) {
+    if (it.first->GetMode() == kVariableModeAsync)
+      it.first->RemoveObserver(this);
+  }
+  CancelMainLoopEvent(poll_timeout_event_);
+  poll_timeout_event_ = kEventIdNull;
+}
+
+TimeDelta EvaluationContext::RemainingTime() const {
+  return evaluation_monotonic_deadline_ - clock_->GetMonotonicTime();
+}
+
+void EvaluationContext::ValueChanged(BaseVariable* var) {
+  DLOG(INFO) << "ValueChanged for variable " << var->GetName();
+  OnValueChangedOrPollTimeout();
+}
+
+void EvaluationContext::OnPollTimeout() {
+  DLOG(INFO) << "OnPollTimeout() called.";
+  poll_timeout_event_ = kEventIdNull;
+  OnValueChangedOrPollTimeout();
+}
+
+void EvaluationContext::OnValueChangedOrPollTimeout() {
+  RemoveObserversAndTimeout();
+
+  if (value_changed_callback_.get() != NULL) {
+    value_changed_callback_->Run();
+    value_changed_callback_.reset();
+  }
+}
+
+bool EvaluationContext::IsTimeGreaterThan(base::Time timestamp) {
+  if (evaluation_start_ > timestamp)
+    return true;
+  // We need to keep track of these calls to trigger a reevaluation.
+  if (reevaluation_time_ > timestamp)
+    reevaluation_time_ = timestamp;
+  return false;
+}
+
+void EvaluationContext::ResetEvaluation() {
+  // It is not important if these two values are not in sync. The first value is
+  // a reference in time when the evaluation started, to device time-based
+  // values for the current evaluation. The second is a deadline for the
+  // evaluation which required a monotonic source of time.
+  evaluation_start_ = clock_->GetWallclockTime();
+  evaluation_monotonic_deadline_ =
+      clock_->GetMonotonicTime() + evaluation_timeout_;
+  reevaluation_time_ = Time::Max();
+
+  // Remove the cached values of non-const variables
+  for (auto it = value_cache_.begin(); it != value_cache_.end(); ) {
+    if (it->first->GetMode() == kVariableModeConst) {
+      ++it;
+    } else {
+      it = value_cache_.erase(it);
+    }
+  }
+}
+
+bool EvaluationContext::RunOnValueChangeOrTimeout(Closure callback) {
+  TimeDelta reeval_timeout;
+  bool reeval_timeout_set = false;
+  bool waiting_for_value_change = false;
+
+  // Check if a reevaluation should be triggered due to a IsTimeGreaterThan()
+  // call.
+  if (reevaluation_time_ != Time::Max()) {
+    reeval_timeout = reevaluation_time_ - evaluation_start_;
+    reeval_timeout_set = true;
+  }
+
+  if (value_changed_callback_.get() != NULL) {
+    LOG(ERROR) << "RunOnValueChangeOrTimeout called more than once.";
+    return false;
+  }
+
+  for (auto& it : value_cache_) {
+    switch (it.first->GetMode()) {
+      case kVariableModeAsync:
+        waiting_for_value_change = true;
+        DLOG(INFO) << "Waiting for value on " << it.first->GetName();
+        it.first->AddObserver(this);
+        break;
+      case kVariableModePoll:
+        if (!reeval_timeout_set || reeval_timeout > it.first->GetPollInterval())
+          reeval_timeout = it.first->GetPollInterval();
+        reeval_timeout_set = true;
+        break;
+      case kVariableModeConst:
+        // Ignored.
+        break;
+    }
+  }
+  // Check if the re-evaluation is actually being scheduled. If there are no
+  // events waited for, this function should return false.
+  if (!waiting_for_value_change && !reeval_timeout_set)
+    return false;
+  if (reeval_timeout_set) {
+    poll_timeout_event_ = RunFromMainLoopAfterTimeout(
+        base::Bind(&EvaluationContext::OnPollTimeout,
+                   weak_ptr_factory_.GetWeakPtr()),
+        reeval_timeout);
+  }
+
+  value_changed_callback_.reset(new Closure(callback));
+  return true;
+}
+
+string EvaluationContext::DumpContext() const {
+  base::DictionaryValue* variables = new base::DictionaryValue();
+  for (auto& it : value_cache_) {
+    variables->SetString(it.first->GetName(), it.second.ToString());
+  }
+
+  base::DictionaryValue value;
+  value.Set("variables", variables);  // Adopts |variables|.
+  value.SetString("evaluation_start",
+                  chromeos_update_engine::utils::ToString(evaluation_start_));
+
+  string json_str;
+  base::JSONWriter::WriteWithOptions(&value,
+                                     base::JSONWriter::OPTIONS_PRETTY_PRINT,
+                                     &json_str);
+
+  return json_str;
+}
+
+}  // namespace chromeos_update_manager
diff --git a/update_manager/evaluation_context.h b/update_manager/evaluation_context.h
new file mode 100644
index 0000000..97e5b97
--- /dev/null
+++ b/update_manager/evaluation_context.h
@@ -0,0 +1,159 @@
+// Copyright (c) 2014 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROMEOS_PLATFORM_UPDATE_ENGINE_UPDATE_MANAGER_EVALUATION_CONTEXT_H_
+#define CHROMEOS_PLATFORM_UPDATE_ENGINE_UPDATE_MANAGER_EVALUATION_CONTEXT_H_
+
+#include <map>
+
+#include <base/callback.h>
+#include <base/memory/ref_counted.h>
+#include <base/memory/scoped_ptr.h>
+#include <base/memory/weak_ptr.h>
+#include <base/time/time.h>
+
+#include "update_engine/clock_interface.h"
+#include "update_engine/update_manager/boxed_value.h"
+#include "update_engine/update_manager/event_loop.h"
+#include "update_engine/update_manager/variable.h"
+
+namespace chromeos_update_manager {
+
+// The EvaluationContext class is the interface between a policy implementation
+// and the state. The EvaluationContext tracks the variables used by a policy
+// request and caches the returned values, owning those cached values.
+// The same EvaluationContext should be re-used for all the evaluations of the
+// same policy request (an AsyncPolicyRequest might involve several
+// re-evaluations). Each evaluation of the EvaluationContext is run at a given
+// point in time, which is used as a reference for the evaluation timeout and
+// the time based queries of the policy, such as IsTimeGreaterThan().
+//
+// Example:
+//
+//   scoped_refptr<EvaluationContext> ec = new EvaluationContext;
+//
+//   ...
+//   // The following call to ResetEvaluation() is optional. Use it to reset the
+//   // evaluation time if the EvaluationContext isn't used right after its
+//   // construction.
+//   ec->ResetEvaluation();
+//   EvalStatus status = policy->SomeMethod(ec, state, &result, args...);
+//
+//   ...
+//   // Run a closure when any of the used async variables changes its value or
+//   // the timeout for requery the values happens again.
+//   ec->RunOnValueChangeOrTimeout(closure);
+//   // If the provided |closure| wants to re-evaluate the policy, it should
+//   // call ec->ResetEvaluation() to start a new evaluation.
+//
+class EvaluationContext :
+    public base::RefCounted<EvaluationContext>,
+    private BaseVariable::ObserverInterface {
+ public:
+  explicit EvaluationContext(chromeos_update_engine::ClockInterface* clock);
+  ~EvaluationContext();
+
+  // Returns a pointer to the value returned by the passed variable |var|. The
+  // EvaluationContext instance keeps the ownership of the returned object. The
+  // returned object is valid during the life of the evaluation, even if the
+  // passed Variable changes it.
+  //
+  // In case of error, a NULL value is returned.
+  template<typename T>
+  const T* GetValue(Variable<T>* var);
+
+  // Returns whether the passed |timestamp| is greater than the evaluation
+  // time. The |timestamp| value should be in the same scale as the values
+  // returned by ClockInterface::GetWallclockTime().
+  bool IsTimeGreaterThan(base::Time timestamp);
+
+  // TODO(deymo): Move the following methods to an interface only visible by the
+  // UpdateManager class and not the policy implementations.
+
+  // Resets the EvaluationContext to its initial state removing all the
+  // non-const cached variables and re-setting the evaluation time. This should
+  // be called right before any new evaluation starts.
+  void ResetEvaluation();
+
+  // Schedules the passed |callback| closure to be called when a cached
+  // variable changes its value or a polling interval passes. If none of these
+  // events can happen, for example if there's no cached variable, this method
+  // returns false.
+  //
+  // Right before the passed closure is called the EvaluationContext is
+  // reseted, removing all the non-const cached values.
+  bool RunOnValueChangeOrTimeout(base::Closure callback);
+
+  // Returns a textual representation of the evaluation context,
+  // including the variables and their values. This is intended only
+  // to help with debugging and the format may change in the future.
+  std::string DumpContext() const;
+
+ private:
+  // Removes all the Observers and timeout callbacks scheduled by
+  // RunOnValueChangeOrTimeout(). This method is idempotent.
+  void RemoveObserversAndTimeout();
+
+  // BaseVariable::ObserverInterface override.
+  void ValueChanged(BaseVariable* var);
+
+  // Called from the main loop when the scheduled poll timeout has passed.
+  void OnPollTimeout();
+
+  // Removes the observers from the used Variables and cancels the poll timeout
+  // and executes the scheduled callback, if any.
+  void OnValueChangedOrPollTimeout();
+
+  // The remaining time for the current evaluation.
+  base::TimeDelta RemainingTime() const;
+
+  // A map to hold the cached values for every variable.
+  typedef std::map<BaseVariable*, BoxedValue> ValueCacheMap;
+
+  // The cached values of the called Variables.
+  ValueCacheMap value_cache_;
+
+  // A pointer to a copy of the closure passed to RunOnValueChangeOrTimeout().
+  scoped_ptr<base::Closure> value_changed_callback_;
+
+  // The EventId returned by the event loop identifying the timeout callback.
+  // Used to cancel the timeout callback.
+  EventId poll_timeout_event_ = kEventIdNull;
+
+  // Pointer to the mockable clock interface;
+  chromeos_update_engine::ClockInterface* clock_;
+
+  // The timestamp when the evaluation of this EvaluationContext started. This
+  // value is reset every time ResetEvaluation() is called. The time source
+  // used is the ClockInterface::GetWallclockTime().
+  base::Time evaluation_start_;
+
+  // The timestamp measured on the GetWallclockTime() scale, when a reevaluation
+  // should be triggered due to IsTimeGreaterThan() calls value changes. This
+  // timestamp is greater or equal to |evaluation_start_| since it is a
+  // timestamp in the future, but it can be lower than the current
+  // GetWallclockTime() at some point of the evaluation.
+  base::Time reevaluation_time_;
+
+  // The timeout of an evaluation, used to compute the RemainingTime() of an
+  // evaluation.
+  // TODO(deymo): Receive the timeout from the UpdateManager. crbug.com/363790
+  base::TimeDelta evaluation_timeout_ = base::TimeDelta::FromSeconds(5);
+
+  // The timestamp in the ClockInterface::GetMonotonicTime() scale at which the
+  // current evaluation should finish. This is used to compute the
+  // RemainingTime().
+  base::Time evaluation_monotonic_deadline_;
+
+  base::WeakPtrFactory<EvaluationContext> weak_ptr_factory_;
+
+  DISALLOW_COPY_AND_ASSIGN(EvaluationContext);
+};
+
+}  // namespace chromeos_update_manager
+
+// Include the implementation of the template methods.
+#include "update_engine/update_manager/evaluation_context-inl.h"
+
+#endif  // CHROMEOS_PLATFORM_UPDATE_ENGINE_UPDATE_MANAGER_EVALUATION_CONTEXT_H_
diff --git a/update_manager/evaluation_context_unittest.cc b/update_manager/evaluation_context_unittest.cc
new file mode 100644
index 0000000..33d91a4
--- /dev/null
+++ b/update_manager/evaluation_context_unittest.cc
@@ -0,0 +1,335 @@
+// Copyright (c) 2014 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <string>
+
+#include <base/bind.h>
+#include <gtest/gtest.h>
+
+#include "update_engine/fake_clock.h"
+#include "update_engine/test_utils.h"
+#include "update_engine/update_manager/evaluation_context.h"
+#include "update_engine/update_manager/fake_variable.h"
+#include "update_engine/update_manager/generic_variables.h"
+#include "update_engine/update_manager/mock_variable.h"
+#include "update_engine/update_manager/umtest_utils.h"
+
+using base::Bind;
+using base::Time;
+using base::TimeDelta;
+using chromeos_update_engine::FakeClock;
+using chromeos_update_engine::RunGMainLoopMaxIterations;
+using chromeos_update_engine::RunGMainLoopUntil;
+using std::string;
+using testing::Return;
+using testing::StrictMock;
+using testing::_;
+
+namespace {
+
+void DoNothing() {}
+
+// Sets the value of the passed pointer to true.
+void SetTrue(bool* value) {
+  *value = true;
+}
+
+bool GetBoolean(bool* value) {
+  return *value;
+}
+
+}  // namespace
+
+namespace chromeos_update_manager {
+
+class UmEvaluationContextTest : public ::testing::Test {
+ protected:
+  virtual void SetUp() {
+    // Set the clock to a fixed values.
+    fake_clock_.SetMonotonicTime(Time::FromInternalValue(12345678L));
+    // Mar 2, 2006 1:23:45 UTC is 1141262625 since the Unix Epoch.
+    fake_clock_.SetWallclockTime(Time::FromTimeT(1141262625));
+    eval_ctx_ = new EvaluationContext(&fake_clock_);
+  }
+
+  virtual void TearDown() {
+    eval_ctx_ = NULL;
+    // Check that the evaluation context removed all the observers.
+    EXPECT_TRUE(fake_int_var_.observer_list_.empty());
+    EXPECT_TRUE(fake_async_var_.observer_list_.empty());
+    EXPECT_TRUE(fake_const_var_.observer_list_.empty());
+    EXPECT_TRUE(fake_poll_var_.observer_list_.empty());
+  }
+
+  // TODO(deymo): Update the default timeout to the one passed on construction.
+  // See crbug.com/363790
+  base::TimeDelta default_timeout_ = base::TimeDelta::FromSeconds(5);
+
+  FakeClock fake_clock_;
+  scoped_refptr<EvaluationContext> eval_ctx_;
+
+  // FakeVariables used for testing the EvaluationContext. These are required
+  // here to prevent them from going away *before* the EvaluationContext under
+  // test does, which keeps a reference to them.
+  FakeVariable<bool> fail_var_ = {"fail_var", kVariableModePoll};
+  FakeVariable<int> fake_int_var_ = {"fake_int", kVariableModePoll};
+  FakeVariable<string> fake_async_var_ = {"fake_async", kVariableModeAsync};
+  FakeVariable<string> fake_const_var_ = {"fake_const", kVariableModeConst};
+  FakeVariable<string> fake_poll_var_ = {"fake_poll",
+                                         TimeDelta::FromSeconds(1)};
+  StrictMock<MockVariable<string>> mock_var_async_{"mock_var_async",
+                                                   kVariableModeAsync};
+  StrictMock<MockVariable<string>> mock_var_poll_{"mock_var_poll",
+                                                  kVariableModePoll};
+};
+
+TEST_F(UmEvaluationContextTest, GetValueFails) {
+  // FakeVariable is initialized as returning NULL.
+  UMTEST_EXPECT_NULL(eval_ctx_->GetValue(&fake_int_var_));
+}
+
+TEST_F(UmEvaluationContextTest, GetValueFailsWithInvalidVar) {
+  UMTEST_EXPECT_NULL(eval_ctx_->GetValue(
+      reinterpret_cast<Variable<int>*>(NULL)));
+}
+
+TEST_F(UmEvaluationContextTest, GetValueReturns) {
+  const int* p_fake_int;
+
+  fake_int_var_.reset(new int(42));
+  p_fake_int = eval_ctx_->GetValue(&fake_int_var_);
+  UMTEST_ASSERT_NOT_NULL(p_fake_int);
+  EXPECT_EQ(42, *p_fake_int);
+}
+
+TEST_F(UmEvaluationContextTest, GetValueCached) {
+  const int* p_fake_int;
+
+  fake_int_var_.reset(new int(42));
+  p_fake_int = eval_ctx_->GetValue(&fake_int_var_);
+
+  // Check that if the variable changes, the EvaluationContext keeps returning
+  // the cached value.
+  fake_int_var_.reset(new int(5));
+
+  p_fake_int = eval_ctx_->GetValue(&fake_int_var_);
+  UMTEST_ASSERT_NOT_NULL(p_fake_int);
+  EXPECT_EQ(42, *p_fake_int);
+}
+
+TEST_F(UmEvaluationContextTest, GetValueCachesNull) {
+  const int* p_fake_int = eval_ctx_->GetValue(&fake_int_var_);
+  UMTEST_EXPECT_NULL(p_fake_int);
+
+  fake_int_var_.reset(new int(42));
+  // A second attempt to read the variable should not work because this
+  // EvaluationContext already got a NULL value.
+  p_fake_int = eval_ctx_->GetValue(&fake_int_var_);
+  UMTEST_EXPECT_NULL(p_fake_int);
+}
+
+TEST_F(UmEvaluationContextTest, GetValueMixedTypes) {
+  const int* p_fake_int;
+  const string* p_fake_string;
+
+  fake_int_var_.reset(new int(42));
+  fake_poll_var_.reset(new string("Hello world!"));
+  // Check that the EvaluationContext can handle multiple Variable types. This
+  // is mostly a compile-time check due to the template nature of this method.
+  p_fake_int = eval_ctx_->GetValue(&fake_int_var_);
+  p_fake_string = eval_ctx_->GetValue(&fake_poll_var_);
+
+  UMTEST_ASSERT_NOT_NULL(p_fake_int);
+  EXPECT_EQ(42, *p_fake_int);
+
+  UMTEST_ASSERT_NOT_NULL(p_fake_string);
+  EXPECT_EQ("Hello world!", *p_fake_string);
+}
+
+// Test that we don't schedule an event if there's no variable to wait for.
+TEST_F(UmEvaluationContextTest, RunOnValueChangeOrTimeoutWithoutVariablesTest) {
+  fake_const_var_.reset(new string("Hello world!"));
+  EXPECT_EQ(*eval_ctx_->GetValue(&fake_const_var_), "Hello world!");
+
+  EXPECT_FALSE(eval_ctx_->RunOnValueChangeOrTimeout(Bind(&DoNothing)));
+}
+
+// Test that we don't schedule an event if there's no variable to wait for.
+TEST_F(UmEvaluationContextTest, RunOnValueChangeOrTimeoutWithVariablesTest) {
+  fake_async_var_.reset(new string("Async value"));
+  eval_ctx_->GetValue(&fake_async_var_);
+
+  bool value = false;
+  EXPECT_TRUE(eval_ctx_->RunOnValueChangeOrTimeout(Bind(&SetTrue, &value)));
+  // Check that the scheduled callback isn't run until we signal a ValueChaged.
+  RunGMainLoopMaxIterations(100);
+  EXPECT_FALSE(value);
+
+  fake_async_var_.NotifyValueChanged();
+  EXPECT_FALSE(value);
+  // Ensure that the scheduled callback isn't run until we are back on the main
+  // loop.
+  RunGMainLoopMaxIterations(100);
+  EXPECT_TRUE(value);
+}
+
+// Test that we don't re-schedule the events if we are attending one.
+TEST_F(UmEvaluationContextTest, RunOnValueChangeOrTimeoutCalledTwiceTest) {
+  fake_async_var_.reset(new string("Async value"));
+  eval_ctx_->GetValue(&fake_async_var_);
+
+  bool value = false;
+  EXPECT_TRUE(eval_ctx_->RunOnValueChangeOrTimeout(Bind(&SetTrue, &value)));
+  EXPECT_FALSE(eval_ctx_->RunOnValueChangeOrTimeout(Bind(&SetTrue, &value)));
+
+  // The scheduled event should still work.
+  fake_async_var_.NotifyValueChanged();
+  RunGMainLoopMaxIterations(100);
+  EXPECT_TRUE(value);
+}
+
+// Test that we clear the events when destroying the EvaluationContext.
+TEST_F(UmEvaluationContextTest, RemoveObserversAndTimeoutTest) {
+  fake_async_var_.reset(new string("Async value"));
+  eval_ctx_->GetValue(&fake_async_var_);
+
+  bool value = false;
+  EXPECT_TRUE(eval_ctx_->RunOnValueChangeOrTimeout(Bind(&SetTrue, &value)));
+  eval_ctx_ = NULL;
+
+  // This should not trigger the callback since the EvaluationContext waiting
+  // for it is gone, and it should have remove all its observers.
+  fake_async_var_.NotifyValueChanged();
+  RunGMainLoopMaxIterations(100);
+  EXPECT_FALSE(value);
+}
+
+// Test that we don't schedule an event if there's no variable to wait for.
+TEST_F(UmEvaluationContextTest, RunOnValueChangeOrTimeoutRunsFromTimeoutTest) {
+  fake_poll_var_.reset(new string("Polled value"));
+  eval_ctx_->GetValue(&fake_poll_var_);
+
+  bool value = false;
+  EXPECT_TRUE(eval_ctx_->RunOnValueChangeOrTimeout(Bind(&SetTrue, &value)));
+  // Check that the scheduled callback isn't run until the timeout occurs.
+  RunGMainLoopMaxIterations(10);
+  EXPECT_FALSE(value);
+  RunGMainLoopUntil(10000, Bind(&GetBoolean, &value));
+  EXPECT_TRUE(value);
+}
+
+// Test that we can delete the EvaluationContext while having pending events.
+TEST_F(UmEvaluationContextTest, ObjectDeletedWithPendingEventsTest) {
+  fake_async_var_.reset(new string("Async value"));
+  fake_poll_var_.reset(new string("Polled value"));
+  eval_ctx_->GetValue(&fake_async_var_);
+  eval_ctx_->GetValue(&fake_poll_var_);
+  EXPECT_TRUE(eval_ctx_->RunOnValueChangeOrTimeout(Bind(&DoNothing)));
+  // TearDown() checks for leaked observers on this async_variable, which means
+  // that our object is still alive after removing its reference.
+}
+
+// Test that timed events fired after removal of the EvaluationContext don't
+// crash.
+TEST_F(UmEvaluationContextTest, TimeoutEventAfterDeleteTest) {
+  FakeVariable<string> fake_short_poll_var = {"fake_short_poll", TimeDelta()};
+  fake_short_poll_var.reset(new string("Polled value"));
+  eval_ctx_->GetValue(&fake_short_poll_var);
+  bool value = false;
+  EXPECT_TRUE(eval_ctx_->RunOnValueChangeOrTimeout(Bind(&SetTrue, &value)));
+  // Remove the last reference to the EvaluationContext and run the loop for
+  // 1 second to give time to the main loop to trigger the timeout Event (of 0
+  // seconds). Our callback should not be called because the EvaluationContext
+  // was removed before the timeout event is attended.
+  eval_ctx_ = NULL;
+  RunGMainLoopUntil(1000, Bind(&GetBoolean, &value));
+  EXPECT_FALSE(value);
+}
+
+TEST_F(UmEvaluationContextTest, DefaultTimeout) {
+  // Test that the RemainingTime() uses the default timeout on setup.
+  EXPECT_CALL(mock_var_async_, GetValue(default_timeout_, _))
+      .WillOnce(Return(nullptr));
+  UMTEST_EXPECT_NULL(eval_ctx_->GetValue(&mock_var_async_));
+}
+
+TEST_F(UmEvaluationContextTest, TimeoutUpdatesWithMonotonicTime) {
+  fake_clock_.SetMonotonicTime(
+      fake_clock_.GetMonotonicTime() + TimeDelta::FromSeconds(1));
+
+  TimeDelta timeout = default_timeout_ - TimeDelta::FromSeconds(1);
+
+  EXPECT_CALL(mock_var_async_, GetValue(timeout, _))
+      .WillOnce(Return(nullptr));
+  UMTEST_EXPECT_NULL(eval_ctx_->GetValue(&mock_var_async_));
+}
+
+TEST_F(UmEvaluationContextTest, ResetEvaluationResetsTimes) {
+  base::Time cur_time = fake_clock_.GetWallclockTime();
+  // Advance the time on the clock but don't call ResetEvaluation yet.
+  fake_clock_.SetWallclockTime(cur_time + TimeDelta::FromSeconds(4));
+
+  EXPECT_TRUE(eval_ctx_->IsTimeGreaterThan(cur_time -
+                                           TimeDelta::FromSeconds(1)));
+  EXPECT_FALSE(eval_ctx_->IsTimeGreaterThan(cur_time));
+  EXPECT_FALSE(eval_ctx_->IsTimeGreaterThan(cur_time +
+                                            TimeDelta::FromSeconds(1)));
+  // Call ResetEvaluation now, which should use the new evaluation time.
+  eval_ctx_->ResetEvaluation();
+
+  cur_time = fake_clock_.GetWallclockTime();
+  EXPECT_TRUE(eval_ctx_->IsTimeGreaterThan(cur_time -
+                                           TimeDelta::FromSeconds(1)));
+  EXPECT_FALSE(eval_ctx_->IsTimeGreaterThan(cur_time));
+  EXPECT_FALSE(eval_ctx_->IsTimeGreaterThan(cur_time +
+                                            TimeDelta::FromSeconds(1)));
+}
+
+TEST_F(UmEvaluationContextTest, IsTimeGreaterThanSignalsTriggerReevaluation) {
+  EXPECT_FALSE(eval_ctx_->IsTimeGreaterThan(
+      fake_clock_.GetWallclockTime() + TimeDelta::FromSeconds(1)));
+
+  // The "false" from IsTimeGreaterThan means that's not that timestamp yet, so
+  // this should schedule a callback for when that happens.
+  EXPECT_TRUE(eval_ctx_->RunOnValueChangeOrTimeout(Bind(&DoNothing)));
+}
+
+TEST_F(UmEvaluationContextTest, IsTimeGreaterThanDoesntRecordPastTimestamps) {
+  // IsTimeGreaterThan() should ignore timestamps on the past for reevaluation.
+  EXPECT_TRUE(eval_ctx_->IsTimeGreaterThan(
+      fake_clock_.GetWallclockTime() - TimeDelta::FromSeconds(20)));
+  EXPECT_TRUE(eval_ctx_->IsTimeGreaterThan(
+      fake_clock_.GetWallclockTime() - TimeDelta::FromSeconds(1)));
+
+  // Callback should not be scheduled.
+  EXPECT_FALSE(eval_ctx_->RunOnValueChangeOrTimeout(Bind(&DoNothing)));
+}
+
+TEST_F(UmEvaluationContextTest, DumpContext) {
+  // |fail_var_| yield "(no value)" since it is unset.
+  eval_ctx_->GetValue(&fail_var_);
+
+  // Check that this is included.
+  fake_int_var_.reset(new int(42));
+  eval_ctx_->GetValue(&fake_int_var_);
+
+  // Check that double-quotes are escaped properly.
+  fake_poll_var_.reset(new string("Hello \"world\"!"));
+  eval_ctx_->GetValue(&fake_poll_var_);
+
+  // Note that the variables are printed in alphabetical order. Also
+  // see UmEvaluationContextText::SetUp() where the value used for
+  // |evaluation_start| is set.
+  EXPECT_EQ("{\n"
+            "   \"evaluation_start\": \"3/2/2006 1:23:45 GMT\",\n"
+            "   \"variables\": {\n"
+            "      \"fail_var\": \"(no value)\",\n"
+            "      \"fake_int\": \"42\",\n"
+            "      \"fake_poll\": \"Hello \\\"world\\\"!\"\n"
+            "   }\n"
+            "}\n",
+            eval_ctx_->DumpContext());
+}
+
+}  // namespace chromeos_update_manager
diff --git a/update_manager/event_loop.cc b/update_manager/event_loop.cc
new file mode 100644
index 0000000..6ae6d36
--- /dev/null
+++ b/update_manager/event_loop.cc
@@ -0,0 +1,51 @@
+// Copyright (c) 2014 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "update_engine/update_manager/event_loop.h"
+
+#include <cmath>
+
+using base::Closure;
+
+namespace {
+
+// Called by the GLib's main loop when is time to call the callback scheduled
+// with RunFromMainLopp() and similar functions. The pointer to the callback
+// passed when scheduling it is passed to this functions as a gpointer on
+// |user_data|.
+gboolean OnRanFromMainLoop(gpointer user_data) {
+  Closure* callback_p = reinterpret_cast<Closure*>(user_data);
+  callback_p->Run();
+  delete callback_p;
+  return FALSE;  // Removes the source since a callback can only be called once.
+}
+
+}  // namespace
+
+namespace chromeos_update_manager {
+
+EventId RunFromMainLoop(const Closure& callback) {
+  Closure* callback_p = new Closure(callback);
+  return g_idle_add_full(G_PRIORITY_DEFAULT,
+                         OnRanFromMainLoop,
+                         reinterpret_cast<gpointer>(callback_p),
+                         NULL);
+}
+
+EventId RunFromMainLoopAfterTimeout(
+    const Closure& callback,
+    base::TimeDelta timeout) {
+  Closure* callback_p = new Closure(callback);
+  return g_timeout_add_seconds(static_cast<guint>(ceil(timeout.InSecondsF())),
+                               OnRanFromMainLoop,
+                               reinterpret_cast<gpointer>(callback_p));
+}
+
+bool CancelMainLoopEvent(EventId event) {
+  if (event != kEventIdNull)
+    return g_source_remove(event);
+  return false;
+}
+
+}  // namespace chromeos_update_manager
diff --git a/update_manager/event_loop.h b/update_manager/event_loop.h
new file mode 100644
index 0000000..a24e0b7
--- /dev/null
+++ b/update_manager/event_loop.h
@@ -0,0 +1,37 @@
+// Copyright (c) 2014 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// TODO(deymo): These functions interact with the glib's main loop. This should
+// be replaced by the libbase main loop once the process is migrated to that
+// main loop.
+
+#ifndef CHROMEOS_PLATFORM_UPDATE_ENGINE_UPDATE_MANAGER_EVENT_LOOP_H_
+#define CHROMEOS_PLATFORM_UPDATE_ENGINE_UPDATE_MANAGER_EVENT_LOOP_H_
+
+#include <glib.h>
+
+#include <base/callback.h>
+#include <base/time/time.h>
+
+namespace chromeos_update_manager {
+
+typedef guint EventId;
+
+// A null EventId doesn't idenify any valid event.
+static constexpr EventId kEventIdNull = 0;
+
+// Schedules the passed |callback| to run from the GLib's main loop after a
+// timeout if it is given.
+EventId RunFromMainLoop(const base::Closure& callback);
+EventId RunFromMainLoopAfterTimeout(const base::Closure& callback,
+                                    base::TimeDelta timeout);
+
+// Removes the pending call |event| from the main loop. The value passed is the
+// one returned by the functions RunFromMainLoop*() when the call was scheduled.
+// Returns whether the event was found and removed.
+bool CancelMainLoopEvent(EventId event);
+
+}  // namespace chromeos_update_manager
+
+#endif  // CHROMEOS_PLATFORM_UPDATE_ENGINE_UPDATE_MANAGER_EVENT_LOOP_H_
diff --git a/update_manager/event_loop_unittest.cc b/update_manager/event_loop_unittest.cc
new file mode 100644
index 0000000..69325fe
--- /dev/null
+++ b/update_manager/event_loop_unittest.cc
@@ -0,0 +1,62 @@
+// Copyright (c) 2014 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "update_engine/update_manager/event_loop.h"
+
+#include <base/bind.h>
+#include <gtest/gtest.h>
+
+#include "update_engine/test_utils.h"
+
+using base::Bind;
+using base::TimeDelta;
+using chromeos_update_engine::RunGMainLoopMaxIterations;
+using chromeos_update_engine::RunGMainLoopUntil;
+
+namespace {
+
+// Sets the value of the passed pointer to true.
+void SetTrue(bool* value) {
+  *value = true;
+}
+
+bool GetBoolean(bool* value) {
+  return *value;
+}
+
+}  // namespace
+
+namespace chromeos_update_manager {
+
+class EventLoopTest : public ::testing::Test {};
+
+TEST(EventLoopTest, RunFromMainLoopTest) {
+  bool called = false;
+  EventId ev = RunFromMainLoop(Bind(SetTrue, &called));
+  EXPECT_NE(0, ev);
+  RunGMainLoopMaxIterations(100);
+  EXPECT_TRUE(called);
+}
+
+// Tests that we can cancel events right after we schedule them.
+TEST(EventLoopTest, RunFromMainLoopCancelTest) {
+  bool called = false;
+  EventId ev = RunFromMainLoop(Bind(SetTrue, &called));
+  EXPECT_NE(0, ev);
+  EXPECT_TRUE(CancelMainLoopEvent(ev));
+  RunGMainLoopMaxIterations(100);
+  EXPECT_FALSE(called);
+}
+
+TEST(EventLoopTest, RunFromMainLoopAfterTimeoutTest) {
+  bool called = false;
+  EventId ev = RunFromMainLoopAfterTimeout(Bind(SetTrue, &called),
+                                           TimeDelta::FromSeconds(1));
+  EXPECT_NE(0, ev);
+  RunGMainLoopUntil(10000, Bind(GetBoolean, &called));
+  // Check that the main loop finished before the 10 seconds timeout.
+  EXPECT_TRUE(called);
+}
+
+}  // namespace chromeos_update_manager
diff --git a/update_manager/fake_config_provider.h b/update_manager/fake_config_provider.h
new file mode 100644
index 0000000..84a1794
--- /dev/null
+++ b/update_manager/fake_config_provider.h
@@ -0,0 +1,32 @@
+// Copyright 2014 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROMEOS_PLATFORM_UPDATE_ENGINE_UPDATE_MANAGER_FAKE_CONFIG_PROVIDER_H_
+#define CHROMEOS_PLATFORM_UPDATE_ENGINE_UPDATE_MANAGER_FAKE_CONFIG_PROVIDER_H_
+
+#include "update_engine/update_manager/config_provider.h"
+#include "update_engine/update_manager/fake_variable.h"
+
+namespace chromeos_update_manager {
+
+// Fake implementation of the ConfigProvider base class.
+class FakeConfigProvider : public ConfigProvider {
+ public:
+  FakeConfigProvider() {}
+
+ protected:
+  virtual FakeVariable<bool>* var_is_oobe_enabled() override {
+    return &var_is_oobe_enabled_;
+  }
+
+ private:
+  FakeVariable<bool> var_is_oobe_enabled_{
+      "is_oobe_enabled", kVariableModeConst};
+
+  DISALLOW_COPY_AND_ASSIGN(FakeConfigProvider);
+};
+
+}  // namespace chromeos_update_manager
+
+#endif  // CHROMEOS_PLATFORM_UPDATE_ENGINE_UPDATE_MANAGER_FAKE_CONFIG_PROVIDER_H_
diff --git a/update_manager/fake_device_policy_provider.h b/update_manager/fake_device_policy_provider.h
new file mode 100644
index 0000000..665d2bb
--- /dev/null
+++ b/update_manager/fake_device_policy_provider.h
@@ -0,0 +1,88 @@
+// Copyright (c) 2014 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROMEOS_PLATFORM_UPDATE_ENGINE_UPDATE_MANAGER_FAKE_DEVICE_POLICY_PROVIDER_H_
+#define CHROMEOS_PLATFORM_UPDATE_ENGINE_UPDATE_MANAGER_FAKE_DEVICE_POLICY_PROVIDER_H_
+
+#include <set>
+#include <string>
+
+#include "update_engine/update_manager/device_policy_provider.h"
+#include "update_engine/update_manager/fake_variable.h"
+
+namespace chromeos_update_manager {
+
+// Fake implementation of the DevicePolicyProvider base class.
+class FakeDevicePolicyProvider : public DevicePolicyProvider {
+ public:
+  FakeDevicePolicyProvider() {}
+
+  virtual FakeVariable<bool>* var_device_policy_is_loaded() override {
+    return &var_device_policy_is_loaded_;
+  }
+
+  virtual FakeVariable<std::string>* var_release_channel() override {
+    return &var_release_channel_;
+  }
+
+  virtual FakeVariable<bool>* var_release_channel_delegated() override {
+    return &var_release_channel_delegated_;
+  }
+
+  virtual FakeVariable<bool>* var_update_disabled() override {
+    return &var_update_disabled_;
+  }
+
+  virtual FakeVariable<std::string>* var_target_version_prefix() override {
+    return &var_target_version_prefix_;
+  }
+
+  virtual FakeVariable<base::TimeDelta>* var_scatter_factor() override {
+    return &var_scatter_factor_;
+  }
+
+  virtual FakeVariable<std::set<ConnectionType>>*
+      var_allowed_connection_types_for_update() override {
+    return &var_allowed_connection_types_for_update_;
+  }
+
+  virtual FakeVariable<std::string>* var_get_owner() override {
+    return &var_get_owner_;
+  }
+
+  virtual FakeVariable<bool>* var_http_downloads_enabled() override {
+    return &var_http_downloads_enabled_;
+  }
+
+  virtual FakeVariable<bool>* var_au_p2p_enabled() override {
+    return &var_au_p2p_enabled_;
+  }
+
+ private:
+  FakeVariable<bool> var_device_policy_is_loaded_{
+      "policy_is_loaded", kVariableModePoll};
+  FakeVariable<std::string> var_release_channel_{
+      "release_channel", kVariableModePoll};
+  FakeVariable<bool> var_release_channel_delegated_{
+      "release_channel_delegated", kVariableModePoll};
+  FakeVariable<bool> var_update_disabled_{
+      "update_disabled", kVariableModePoll};
+  FakeVariable<std::string> var_target_version_prefix_{
+      "target_version_prefix", kVariableModePoll};
+  FakeVariable<base::TimeDelta> var_scatter_factor_{
+      "scatter_factor", kVariableModePoll};
+  FakeVariable<std::set<ConnectionType>>
+      var_allowed_connection_types_for_update_{
+          "allowed_connection_types_for_update", kVariableModePoll};
+  FakeVariable<std::string> var_get_owner_{"get_owner", kVariableModePoll};
+  FakeVariable<bool> var_http_downloads_enabled_{
+      "http_downloads_enabled", kVariableModePoll};
+  FakeVariable<bool> var_au_p2p_enabled_{"au_p2p_enabled", kVariableModePoll};
+
+  DISALLOW_COPY_AND_ASSIGN(FakeDevicePolicyProvider);
+};
+
+}  // namespace chromeos_update_manager
+
+#endif  // CHROMEOS_PLATFORM_UPDATE_ENGINE_UPDATE_MANAGER_FAKE_DEVICE_POLICY_PROVIDER_H_
diff --git a/update_manager/fake_random_provider.h b/update_manager/fake_random_provider.h
new file mode 100644
index 0000000..2cf847c
--- /dev/null
+++ b/update_manager/fake_random_provider.h
@@ -0,0 +1,28 @@
+// Copyright (c) 2014 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROMEOS_PLATFORM_UPDATE_ENGINE_UPDATE_MANAGER_FAKE_RANDOM_PROVIDER_H_
+#define CHROMEOS_PLATFORM_UPDATE_ENGINE_UPDATE_MANAGER_FAKE_RANDOM_PROVIDER_H_
+
+#include "update_engine/update_manager/fake_variable.h"
+#include "update_engine/update_manager/random_provider.h"
+
+namespace chromeos_update_manager {
+
+// Fake implementation of the RandomProvider base class.
+class FakeRandomProvider : public RandomProvider {
+ public:
+  FakeRandomProvider() {}
+
+  virtual FakeVariable<uint64_t>* var_seed() override { return &var_seed_; }
+
+ private:
+  FakeVariable<uint64_t> var_seed_{"seed", kVariableModePoll};
+
+  DISALLOW_COPY_AND_ASSIGN(FakeRandomProvider);
+};
+
+}  // namespace chromeos_update_manager
+
+#endif  // CHROMEOS_PLATFORM_UPDATE_ENGINE_UPDATE_MANAGER_FAKE_RANDOM_PROVIDER_H_
diff --git a/update_manager/fake_shill_provider.h b/update_manager/fake_shill_provider.h
new file mode 100644
index 0000000..7528cc4
--- /dev/null
+++ b/update_manager/fake_shill_provider.h
@@ -0,0 +1,48 @@
+// Copyright (c) 2014 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROMEOS_PLATFORM_UPDATE_ENGINE_UPDATE_MANAGER_FAKE_SHILL_PROVIDER_H_
+#define CHROMEOS_PLATFORM_UPDATE_ENGINE_UPDATE_MANAGER_FAKE_SHILL_PROVIDER_H_
+
+#include "update_engine/update_manager/fake_variable.h"
+#include "update_engine/update_manager/shill_provider.h"
+
+namespace chromeos_update_manager {
+
+// Fake implementation of the ShillProvider base class.
+class FakeShillProvider : public ShillProvider {
+ public:
+  FakeShillProvider() {}
+
+  virtual FakeVariable<bool>* var_is_connected() override {
+    return &var_is_connected_;
+  }
+
+  virtual FakeVariable<ConnectionType>* var_conn_type() override {
+    return &var_conn_type_;
+  }
+
+  virtual FakeVariable<ConnectionTethering>*
+      var_conn_tethering() override {
+    return &var_conn_tethering_;
+  }
+
+  virtual FakeVariable<base::Time>* var_conn_last_changed() override {
+    return &var_conn_last_changed_;
+  }
+
+ private:
+  FakeVariable<bool> var_is_connected_{"is_connected", kVariableModePoll};
+  FakeVariable<ConnectionType> var_conn_type_{"conn_type", kVariableModePoll};
+  FakeVariable<ConnectionTethering> var_conn_tethering_{
+      "conn_tethering", kVariableModePoll};
+  FakeVariable<base::Time> var_conn_last_changed_{
+      "conn_last_changed", kVariableModePoll};
+
+  DISALLOW_COPY_AND_ASSIGN(FakeShillProvider);
+};
+
+}  // namespace chromeos_update_manager
+
+#endif  // CHROMEOS_PLATFORM_UPDATE_ENGINE_UPDATE_MANAGER_FAKE_SHILL_PROVIDER_H_
diff --git a/update_manager/fake_state.h b/update_manager/fake_state.h
new file mode 100644
index 0000000..2af8fe8
--- /dev/null
+++ b/update_manager/fake_state.h
@@ -0,0 +1,79 @@
+// Copyright (c) 2014 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROMEOS_PLATFORM_UPDATE_ENGINE_UPDATE_MANAGER_FAKE_STATE_H_
+#define CHROMEOS_PLATFORM_UPDATE_ENGINE_UPDATE_MANAGER_FAKE_STATE_H_
+
+#include "update_engine/update_manager/fake_config_provider.h"
+#include "update_engine/update_manager/fake_device_policy_provider.h"
+#include "update_engine/update_manager/fake_random_provider.h"
+#include "update_engine/update_manager/fake_shill_provider.h"
+#include "update_engine/update_manager/fake_system_provider.h"
+#include "update_engine/update_manager/fake_time_provider.h"
+#include "update_engine/update_manager/fake_updater_provider.h"
+#include "update_engine/update_manager/state.h"
+
+namespace chromeos_update_manager {
+
+// A fake State class that creates fake providers for all the providers.
+// This fake can be used in unit testing of Policy subclasses. To fake out the
+// value a variable is exposing, just call FakeVariable<T>::SetValue() on the
+// variable you fake out. For example:
+//
+//   FakeState fake_state_;
+//   fake_state_.random_provider_->var_seed()->SetValue(new uint64_t(12345));
+//
+// You can call SetValue more than once and the FakeVariable will take care of
+// the memory, but only the last value will remain.
+class FakeState : public State {
+ public:
+  // Creates and initializes the FakeState using fake providers.
+  FakeState() {}
+
+  virtual ~FakeState() {}
+
+  // Downcasted detters to access the fake instances during testing.
+  virtual FakeConfigProvider* config_provider() override {
+    return &config_provider_;
+  }
+
+  virtual FakeDevicePolicyProvider* device_policy_provider() override {
+    return &device_policy_provider_;
+  }
+
+  virtual FakeRandomProvider* random_provider() override {
+    return &random_provider_;
+  }
+
+  virtual FakeShillProvider* shill_provider() override {
+    return &shill_provider_;
+  }
+
+  virtual FakeSystemProvider* system_provider() override {
+    return &system_provider_;
+  }
+
+  virtual FakeTimeProvider* time_provider() override {
+    return &time_provider_;
+  }
+
+  virtual FakeUpdaterProvider* updater_provider() override {
+    return &updater_provider_;
+  }
+
+ private:
+  FakeConfigProvider config_provider_;
+  FakeDevicePolicyProvider device_policy_provider_;
+  FakeRandomProvider random_provider_;
+  FakeShillProvider shill_provider_;
+  FakeSystemProvider system_provider_;
+  FakeTimeProvider time_provider_;
+  FakeUpdaterProvider updater_provider_;
+
+  DISALLOW_COPY_AND_ASSIGN(FakeState);
+};
+
+}  // namespace chromeos_update_manager
+
+#endif  // CHROMEOS_PLATFORM_UPDATE_ENGINE_UPDATE_MANAGER_FAKE_STATE_H_
diff --git a/update_manager/fake_system_provider.h b/update_manager/fake_system_provider.h
new file mode 100644
index 0000000..6a6b474
--- /dev/null
+++ b/update_manager/fake_system_provider.h
@@ -0,0 +1,43 @@
+// Copyright (c) 2014 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROMEOS_PLATFORM_UPDATE_ENGINE_UPDATE_MANAGER_FAKE_SYSTEM_PROVIDER_H_
+#define CHROMEOS_PLATFORM_UPDATE_ENGINE_UPDATE_MANAGER_FAKE_SYSTEM_PROVIDER_H_
+
+#include "update_engine/update_manager/fake_variable.h"
+#include "update_engine/update_manager/system_provider.h"
+
+namespace chromeos_update_manager {
+
+// Fake implementation of the SystemProvider base class.
+class FakeSystemProvider : public SystemProvider {
+ public:
+  FakeSystemProvider() {}
+
+  virtual FakeVariable<bool>* var_is_normal_boot_mode() override {
+    return &var_is_normal_boot_mode_;
+  }
+
+  virtual FakeVariable<bool>* var_is_official_build() override {
+    return &var_is_official_build_;
+  }
+
+  virtual FakeVariable<bool>* var_is_oobe_complete() override {
+    return &var_is_oobe_complete_;
+  }
+
+ private:
+  FakeVariable<bool> var_is_normal_boot_mode_{
+      "is_normal_boot_mode", kVariableModeConst};
+  FakeVariable<bool> var_is_official_build_{
+      "is_official_build", kVariableModeConst};
+  FakeVariable<bool> var_is_oobe_complete_{
+      "is_oobe_complete", kVariableModePoll};
+
+  DISALLOW_COPY_AND_ASSIGN(FakeSystemProvider);
+};
+
+}  // namespace chromeos_update_manager
+
+#endif  // CHROMEOS_PLATFORM_UPDATE_ENGINE_UPDATE_MANAGER_FAKE_SYSTEM_PROVIDER_H_
diff --git a/update_manager/fake_time_provider.h b/update_manager/fake_time_provider.h
new file mode 100644
index 0000000..861b70a
--- /dev/null
+++ b/update_manager/fake_time_provider.h
@@ -0,0 +1,35 @@
+// Copyright (c) 2014 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROMEOS_PLATFORM_UPDATE_ENGINE_UPDATE_MANAGER_FAKE_TIME_PROVIDER_H_
+#define CHROMEOS_PLATFORM_UPDATE_ENGINE_UPDATE_MANAGER_FAKE_TIME_PROVIDER_H_
+
+#include "update_engine/update_manager/fake_variable.h"
+#include "update_engine/update_manager/time_provider.h"
+
+namespace chromeos_update_manager {
+
+// Fake implementation of the TimeProvider base class.
+class FakeTimeProvider : public TimeProvider {
+ public:
+  FakeTimeProvider() {}
+
+  virtual FakeVariable<base::Time>* var_curr_date() override {
+    return &var_curr_date_;
+  }
+
+  virtual FakeVariable<int>* var_curr_hour() override {
+    return &var_curr_hour_;
+  }
+
+ private:
+  FakeVariable<base::Time> var_curr_date_{"curr_date", kVariableModePoll};
+  FakeVariable<int> var_curr_hour_{"curr_hour", kVariableModePoll};
+
+  DISALLOW_COPY_AND_ASSIGN(FakeTimeProvider);
+};
+
+}  // namespace chromeos_update_manager
+
+#endif  // CHROMEOS_PLATFORM_UPDATE_ENGINE_UPDATE_MANAGER_FAKE_TIME_PROVIDER_H_
diff --git a/update_manager/fake_update_manager.h b/update_manager/fake_update_manager.h
new file mode 100644
index 0000000..0831b2e
--- /dev/null
+++ b/update_manager/fake_update_manager.h
@@ -0,0 +1,36 @@
+// Copyright (c) 2014 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROMEOS_PLATFORM_UPDATE_ENGINE_UPDATE_MANAGER_FAKE_UPDATE_MANAGER_H_
+#define CHROMEOS_PLATFORM_UPDATE_ENGINE_UPDATE_MANAGER_FAKE_UPDATE_MANAGER_H_
+
+#include "update_engine/update_manager/update_manager.h"
+
+#include "update_engine/update_manager/default_policy.h"
+#include "update_engine/update_manager/fake_state.h"
+
+namespace chromeos_update_manager {
+
+class FakeUpdateManager : public UpdateManager {
+ public:
+  explicit FakeUpdateManager(chromeos_update_engine::ClockInterface* clock)
+      : UpdateManager(clock, new FakeState()) {
+    // The FakeUpdateManager uses a DefaultPolicy.
+    set_policy(new DefaultPolicy());
+  }
+
+  // UpdateManager overrides.
+  using UpdateManager::set_policy;
+
+  FakeState* state() {
+    return reinterpret_cast<FakeState*>(UpdateManager::state());
+  }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(FakeUpdateManager);
+};
+
+}  // namespace chromeos_update_manager
+
+#endif  // CHROMEOS_PLATFORM_UPDATE_ENGINE_UPDATE_MANAGER_FAKE_UPDATE_MANAGER_H_
diff --git a/update_manager/fake_updater_provider.h b/update_manager/fake_updater_provider.h
new file mode 100644
index 0000000..22cb9bf
--- /dev/null
+++ b/update_manager/fake_updater_provider.h
@@ -0,0 +1,94 @@
+// Copyright (c) 2014 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROMEOS_PLATFORM_UPDATE_ENGINE_UPDATE_MANAGER_FAKE_UPDATER_PROVIDER_H_
+#define CHROMEOS_PLATFORM_UPDATE_ENGINE_UPDATE_MANAGER_FAKE_UPDATER_PROVIDER_H_
+
+#include <string>
+
+#include "update_engine/update_manager/fake_variable.h"
+#include "update_engine/update_manager/updater_provider.h"
+
+namespace chromeos_update_manager {
+
+// Fake implementation of the UpdaterProvider base class.
+class FakeUpdaterProvider : public UpdaterProvider {
+ public:
+  FakeUpdaterProvider() {}
+
+  virtual FakeVariable<base::Time>* var_updater_started_time() override {
+    return &var_updater_started_time_;
+  }
+
+  virtual FakeVariable<base::Time>* var_last_checked_time() override {
+    return &var_last_checked_time_;
+  }
+
+  virtual FakeVariable<base::Time>* var_update_completed_time() override {
+    return &var_update_completed_time_;
+  }
+
+  virtual FakeVariable<double>* var_progress() override {
+    return &var_progress_;
+  }
+
+  virtual FakeVariable<Stage>* var_stage() override {
+    return &var_stage_;
+  }
+
+  virtual FakeVariable<std::string>* var_new_version() override {
+    return &var_new_version_;
+  }
+
+  virtual FakeVariable<int64_t>* var_payload_size() override {
+    return &var_payload_size_;
+  }
+
+  virtual FakeVariable<std::string>* var_curr_channel() override {
+    return &var_curr_channel_;
+  }
+
+  virtual FakeVariable<std::string>* var_new_channel() override {
+    return &var_new_channel_;
+  }
+
+  virtual FakeVariable<bool>* var_p2p_enabled() override {
+    return &var_p2p_enabled_;
+  }
+
+  virtual FakeVariable<bool>* var_cellular_enabled() override {
+    return &var_cellular_enabled_;
+  }
+
+  virtual FakeVariable<unsigned int>*
+      var_consecutive_failed_update_checks() override {
+    return &var_consecutive_failed_update_checks_;
+  }
+
+ private:
+  FakeVariable<base::Time> var_updater_started_time_{
+      "updater_started_time", kVariableModePoll};
+  FakeVariable<base::Time> var_last_checked_time_{
+      "last_checked_time", kVariableModePoll};
+  FakeVariable<base::Time> var_update_completed_time_{
+      "update_completed_time", kVariableModePoll};
+  FakeVariable<double> var_progress_{"progress", kVariableModePoll};
+  FakeVariable<Stage> var_stage_{"stage", kVariableModePoll};
+  FakeVariable<std::string> var_new_version_{"new_version", kVariableModePoll};
+  FakeVariable<int64_t> var_payload_size_{"payload_size", kVariableModePoll};
+  FakeVariable<std::string> var_curr_channel_{
+      "curr_channel", kVariableModePoll};
+  FakeVariable<std::string> var_new_channel_{"new_channel", kVariableModePoll};
+  FakeVariable<bool> var_p2p_enabled_{"p2p_enabled", kVariableModePoll};
+  FakeVariable<bool> var_cellular_enabled_{
+      "cellular_enabled", kVariableModePoll};
+  FakeVariable<unsigned int> var_consecutive_failed_update_checks_{
+      "consecutive_failed_update_checks", kVariableModePoll};
+
+  DISALLOW_COPY_AND_ASSIGN(FakeUpdaterProvider);
+};
+
+}  // namespace chromeos_update_manager
+
+#endif  // CHROMEOS_PLATFORM_UPDATE_ENGINE_UPDATE_MANAGER_FAKE_UPDATER_PROVIDER_H_
diff --git a/update_manager/fake_variable.h b/update_manager/fake_variable.h
new file mode 100644
index 0000000..0f976e3
--- /dev/null
+++ b/update_manager/fake_variable.h
@@ -0,0 +1,62 @@
+// Copyright (c) 2014 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROMEOS_PLATFORM_UPDATE_ENGINE_UPDATE_MANAGER_FAKE_VARIABLE_H_
+#define CHROMEOS_PLATFORM_UPDATE_ENGINE_UPDATE_MANAGER_FAKE_VARIABLE_H_
+
+#include <string>
+
+#include <base/memory/scoped_ptr.h>
+
+#include "update_engine/update_manager/variable.h"
+
+namespace chromeos_update_manager {
+
+// A fake typed variable to use while testing policy implementations. The
+// variable can be instructed to return any object of its type.
+template<typename T>
+class FakeVariable : public Variable<T> {
+ public:
+  FakeVariable(const std::string& name, VariableMode mode)
+      : Variable<T>(name, mode) {}
+  FakeVariable(const std::string& name, base::TimeDelta poll_interval)
+      : Variable<T>(name, poll_interval) {}
+  virtual ~FakeVariable() {}
+
+  // Sets the next value of this variable to the passed |p_value| pointer. Once
+  // returned by GetValue(), the pointer is released and has to be set again.
+  // A value of NULL means that the GetValue() call will fail and return NULL.
+  void reset(const T* p_value) {
+    ptr_.reset(p_value);
+  }
+
+  // Make the NotifyValueChanged() public for FakeVariables.
+  void NotifyValueChanged() {
+    Variable<T>::NotifyValueChanged();
+  }
+
+ protected:
+  // Variable<T> overrides.
+  // Returns the pointer set with reset(). The ownership of the object is passed
+  // to the caller and the pointer is release from the FakeVariable. A second
+  // call to GetValue() without reset() will return NULL and set the error
+  // message.
+  virtual const T* GetValue(base::TimeDelta /* timeout */,
+                            std::string* errmsg) {
+    if (ptr_ == NULL && errmsg != NULL)
+      *errmsg = this->GetName() + " is an empty FakeVariable";
+    // Passes the pointer ownership to the caller.
+    return ptr_.release();
+  }
+
+ private:
+  // The pointer returned by GetValue().
+  scoped_ptr<const T> ptr_;
+
+  DISALLOW_COPY_AND_ASSIGN(FakeVariable);
+};
+
+}  // namespace chromeos_update_manager
+
+#endif  // CHROMEOS_PLATFORM_UPDATE_ENGINE_UPDATE_MANAGER_FAKE_VARIABLE_H_
diff --git a/update_manager/generic_variables.h b/update_manager/generic_variables.h
new file mode 100644
index 0000000..5831463
--- /dev/null
+++ b/update_manager/generic_variables.h
@@ -0,0 +1,206 @@
+// Copyright (c) 2014 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Generic and provider-independent Variable subclasses. These variables can be
+// used by any state provider to implement simple variables to avoid repeat the
+// same common code on different state providers.
+
+#ifndef CHROMEOS_PLATFORM_UPDATE_ENGINE_UPDATE_MANAGER_GENERIC_VARIABLES_H_
+#define CHROMEOS_PLATFORM_UPDATE_ENGINE_UPDATE_MANAGER_GENERIC_VARIABLES_H_
+
+#include <string>
+
+#include <base/callback.h>
+
+#include "update_engine/update_manager/variable.h"
+
+namespace chromeos_update_manager {
+
+// Variable class returning a copy of a given object using the copy constructor.
+// This template class can be used to define variables that expose as a variable
+// any fixed object, such as the a provider's private member. The variable will
+// create copies of the provided object using the copy constructor of that
+// class.
+//
+// For example, a state provider exposing a private member as a variable can
+// implement this as follows:
+//
+//   class SomethingProvider {
+//    public:
+//      SomethingProvider(...) {
+//        var_something_foo = new PollCopyVariable<MyType>(foo_);
+//      }
+//      ...
+//    private:
+//     MyType foo_;
+//   };
+template<typename T>
+class PollCopyVariable : public Variable<T> {
+ public:
+  // Creates the variable returning copies of the passed |ref|. The reference to
+  // this object is kept and it should be available whenever the GetValue()
+  // method is called. If |is_set_p| is not null, then this flag will be
+  // consulted prior to returning the value, and an |errmsg| will be returned if
+  // it is not set.
+  PollCopyVariable(const std::string& name, const T& ref, const bool* is_set_p,
+                   const std::string& errmsg)
+      : Variable<T>(name, kVariableModePoll), ref_(ref), is_set_p_(is_set_p),
+        errmsg_(errmsg) {}
+  PollCopyVariable(const std::string& name, const T& ref, const bool* is_set_p)
+      : PollCopyVariable(name, ref, is_set_p, std::string()) {}
+  PollCopyVariable(const std::string& name, const T& ref)
+      : PollCopyVariable(name, ref, nullptr) {}
+
+  PollCopyVariable(const std::string& name, const base::TimeDelta poll_interval,
+                   const T& ref, const bool* is_set_p,
+                   const std::string& errmsg)
+      : Variable<T>(name, poll_interval), ref_(ref), is_set_p_(is_set_p),
+        errmsg_(errmsg) {}
+  PollCopyVariable(const std::string& name, const base::TimeDelta poll_interval,
+                   const T& ref, const bool* is_set_p)
+      : PollCopyVariable(name, poll_interval, ref, is_set_p, std::string()) {}
+  PollCopyVariable(const std::string& name, const base::TimeDelta poll_interval,
+                   const T& ref)
+      : PollCopyVariable(name, poll_interval, ref, nullptr) {}
+
+ protected:
+  FRIEND_TEST(UmPollCopyVariableTest, SimpleTest);
+  FRIEND_TEST(UmPollCopyVariableTest, UseCopyConstructorTest);
+
+  // Variable override.
+  virtual inline const T* GetValue(base::TimeDelta /* timeout */,
+                                   std::string* errmsg) {
+    if (is_set_p_ && !(*is_set_p_)) {
+      if (errmsg) {
+        if (errmsg_.empty())
+          *errmsg = "No value set for " + this->GetName();
+        else
+          *errmsg = errmsg_;
+      }
+      return nullptr;
+    }
+    return new T(ref_);
+  }
+
+ private:
+  // Reference to the object to be copied by GetValue().
+  const T& ref_;
+
+  // A pointer to a flag indicating whether the value is set. If null, then the
+  // value is assumed to be set.
+  const bool* const is_set_p_;
+
+  // An error message to be returned when attempting to get an unset value.
+  const std::string errmsg_;
+};
+
+// Variable class returning a constant value that is cached on the variable when
+// it is created.
+template<typename T>
+class ConstCopyVariable : public Variable<T> {
+ public:
+  // Creates the variable returning copies of the passed |obj|. The value passed
+  // is copied in this variable, and new copies of it will be returned by
+  // GetValue().
+  ConstCopyVariable(const std::string& name, const T& obj)
+      : Variable<T>(name, kVariableModeConst), obj_(obj) {}
+
+ protected:
+  // Variable override.
+  virtual const T* GetValue(base::TimeDelta /* timeout */,
+                            std::string* /* errmsg */) {
+    return new T(obj_);
+  }
+
+ private:
+  // Value to be copied by GetValue().
+  const T obj_;
+};
+
+// Variable class returning a copy of a value returned by a given function. The
+// function is called every time the variable is being polled.
+template<typename T>
+class CallCopyVariable : public Variable<T> {
+ public:
+  CallCopyVariable(const std::string& name, base::Callback<T(void)> func)
+      : Variable<T>(name, kVariableModePoll), func_(func) {}
+  CallCopyVariable(const std::string& name,
+                   const base::TimeDelta poll_interval,
+                   base::Callback<T(void)> func)
+      : Variable<T>(name, poll_interval), func_(func) {}
+
+ protected:
+  // Variable override.
+  virtual const T* GetValue(base::TimeDelta /* timeout */,
+                            std::string* /* errmsg */) {
+    if (func_.is_null())
+      return nullptr;
+    return new T(func_.Run());
+  }
+
+ private:
+  FRIEND_TEST(UmCallCopyVariableTest, SimpleTest);
+
+  // The function to be called, stored as a base::Callback.
+  base::Callback<T(void)> func_;
+
+  DISALLOW_COPY_AND_ASSIGN(CallCopyVariable);
+};
+
+
+// A Variable class to implement simple Async variables. It provides two methods
+// SetValue and UnsetValue to modify the current value of the variable and
+// notify the registered observers whenever the value changed.
+//
+// The type T needs to be copy-constructable, default-constructable and have an
+// operator== (to determine if the value changed), which makes this class
+// suitable for basic types.
+template<typename T>
+class AsyncCopyVariable : public Variable<T> {
+ public:
+  explicit AsyncCopyVariable(const std::string& name)
+      : Variable<T>(name, kVariableModeAsync), has_value_(false) {}
+
+  AsyncCopyVariable(const std::string& name, const T value)
+      : Variable<T>(name, kVariableModeAsync),
+        has_value_(true), value_(value) {}
+
+  void SetValue(const T& new_value) {
+    bool should_notify = !(has_value_ && new_value == value_);
+    value_ = new_value;
+    has_value_ = true;
+    if (should_notify)
+      this->NotifyValueChanged();
+  }
+
+  void UnsetValue() {
+    if (has_value_) {
+      has_value_ = false;
+      this->NotifyValueChanged();
+    }
+  }
+
+ protected:
+  // Variable override.
+  virtual const T* GetValue(base::TimeDelta /* timeout */,
+                            std::string* errmsg) {
+    if (!has_value_) {
+      if (errmsg)
+        *errmsg = "No value set for " + this->GetName();
+      return nullptr;
+    }
+    return new T(value_);
+  }
+
+ private:
+  // Whether the variable has a value set.
+  bool has_value_;
+
+  // Copy of the object to be returned by GetValue().
+  T value_;
+};
+
+}  // namespace chromeos_update_manager
+
+#endif  // CHROMEOS_PLATFORM_UPDATE_ENGINE_UPDATE_MANAGER_GENERIC_VARIABLES_H_
diff --git a/update_manager/generic_variables_unittest.cc b/update_manager/generic_variables_unittest.cc
new file mode 100644
index 0000000..51ae4bd
--- /dev/null
+++ b/update_manager/generic_variables_unittest.cc
@@ -0,0 +1,201 @@
+// Copyright (c) 2014 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "update_engine/update_manager/generic_variables.h"
+
+#include <base/callback.h>
+#include <base/memory/scoped_ptr.h>
+#include <gtest/gtest.h>
+
+#include "update_engine/test_utils.h"
+#include "update_engine/update_manager/umtest_utils.h"
+
+using base::TimeDelta;
+using chromeos_update_engine::RunGMainLoopMaxIterations;
+
+namespace chromeos_update_manager {
+
+class UmPollCopyVariableTest : public ::testing::Test {};
+
+
+TEST_F(UmPollCopyVariableTest, SimpleTest) {
+  // Tests that copies are generated as intended.
+  int source = 5;
+  PollCopyVariable<int> var("var", source);
+
+  // Generate and validate a copy.
+  scoped_ptr<const int> copy_1(var.GetValue(
+          UmTestUtils::DefaultTimeout(), NULL));
+  UMTEST_ASSERT_NOT_NULL(copy_1.get());
+  EXPECT_EQ(5, *copy_1);
+
+  // Assign a different value to the source variable.
+  source = 42;
+
+  // Check that the content of the copy was not affected (distinct instance).
+  EXPECT_EQ(5, *copy_1);
+
+  // Generate and validate a second copy.
+  UmTestUtils::ExpectVariableHasValue(42, &var);
+}
+
+TEST_F(UmPollCopyVariableTest, SetFlagTest) {
+  // Tests that the set flag is being referred to as expected.
+  int source = 5;
+  bool is_set = false;
+  PollCopyVariable<int> var("var", source, &is_set);
+
+  // Flag marked unset, nothing should be returned.
+  UmTestUtils::ExpectVariableNotSet(&var);
+
+  // Flag marked set, we should be getting a value.
+  is_set = true;
+  UmTestUtils::ExpectVariableHasValue(5, &var);
+}
+
+
+class CopyConstructorTestClass {
+ public:
+  CopyConstructorTestClass(void) : copied_(false) {}
+  CopyConstructorTestClass(const CopyConstructorTestClass& other)
+      : copied_(true), val_(other.val_ * 2) {}
+
+  // Tells if the instance was constructed using the copy-constructor.
+  const bool copied_;
+
+  // An auxiliary internal value.
+  int val_ = 0;
+};
+
+
+TEST_F(UmPollCopyVariableTest, UseCopyConstructorTest) {
+  // Ensures that CopyVariables indeed uses the copy contructor.
+  const CopyConstructorTestClass source;
+  ASSERT_FALSE(source.copied_);
+
+  PollCopyVariable<CopyConstructorTestClass> var("var", source);
+  scoped_ptr<const CopyConstructorTestClass> copy(
+      var.GetValue(UmTestUtils::DefaultTimeout(), NULL));
+  UMTEST_ASSERT_NOT_NULL(copy.get());
+  EXPECT_TRUE(copy->copied_);
+}
+
+
+class UmConstCopyVariableTest : public ::testing::Test {};
+
+TEST_F(UmConstCopyVariableTest, SimpleTest) {
+  int source = 5;
+  ConstCopyVariable<int> var("var", source);
+  UmTestUtils::ExpectVariableHasValue(5, &var);
+
+  // Ensure the value is cached.
+  source = 42;
+  UmTestUtils::ExpectVariableHasValue(5, &var);
+}
+
+
+class UmCallCopyVariableTest : public ::testing::Test {};
+
+CopyConstructorTestClass test_func(CopyConstructorTestClass* obj) {
+  obj->val_++;  // So we can check that the function was called.
+  return *obj;
+}
+
+TEST_F(UmCallCopyVariableTest, SimpleTest) {
+  // Tests that the returned value is generated by copying the value returned by
+  // the function call.
+
+  CopyConstructorTestClass test_obj;
+  ASSERT_FALSE(test_obj.copied_);
+  test_obj.val_ = 5;
+
+  base::Callback<CopyConstructorTestClass(void)> cb = base::Bind(
+      test_func, &test_obj);
+  CallCopyVariable<CopyConstructorTestClass> var("var", cb);
+
+  scoped_ptr<const CopyConstructorTestClass> copy(
+      var.GetValue(UmTestUtils::DefaultTimeout(), nullptr));
+  EXPECT_EQ(6, test_obj.val_);  // Check that the function was called.
+  UMTEST_ASSERT_NOT_NULL(copy.get());
+  EXPECT_TRUE(copy->copied_);
+  EXPECT_EQ(12, copy->val_);  // Check that copying occurred once.
+}
+
+TEST_F(UmCallCopyVariableTest, NullTest) {
+  // Ensures that the variable returns null when the callback is null.
+
+  base::Callback<bool(void)> cb;
+  CallCopyVariable<bool> var("var", cb);
+  UmTestUtils::ExpectVariableNotSet(&var);
+}
+
+class UmAsyncCopyVariableTest : public ::testing::Test {
+ public:
+  void TearDown() {
+    // No remaining event on the main loop.
+    EXPECT_EQ(0, RunGMainLoopMaxIterations(1));
+  }
+};
+
+TEST_F(UmAsyncCopyVariableTest, ConstructorTest) {
+  AsyncCopyVariable<int> var("var");
+  UmTestUtils::ExpectVariableNotSet(&var);
+  EXPECT_EQ(kVariableModeAsync, var.GetMode());
+}
+
+TEST_F(UmAsyncCopyVariableTest, SetValueTest) {
+  AsyncCopyVariable<int> var("var");
+  var.SetValue(5);
+  UmTestUtils::ExpectVariableHasValue(5, &var);
+  // Execute all the pending observers.
+  RunGMainLoopMaxIterations(100);
+}
+
+TEST_F(UmAsyncCopyVariableTest, UnsetValueTest) {
+  AsyncCopyVariable<int> var("var", 42);
+  var.UnsetValue();
+  UmTestUtils::ExpectVariableNotSet(&var);
+  // Execute all the pending observers.
+  RunGMainLoopMaxIterations(100);
+}
+
+class CallCounterObserver : public BaseVariable::ObserverInterface {
+ public:
+  void ValueChanged(BaseVariable* variable) {
+    calls_count_++;
+  }
+
+  int calls_count_ = 0;
+};
+
+TEST_F(UmAsyncCopyVariableTest, ObserverCalledTest) {
+  AsyncCopyVariable<int> var("var", 42);
+  CallCounterObserver observer;
+  var.AddObserver(&observer);
+  EXPECT_EQ(0, observer.calls_count_);
+
+  // Check that a different value fires the notification.
+  var.SetValue(5);
+  RunGMainLoopMaxIterations(100);
+  EXPECT_EQ(1, observer.calls_count_);
+
+  // Check the same value doesn't.
+  var.SetValue(5);
+  RunGMainLoopMaxIterations(100);
+  EXPECT_EQ(1, observer.calls_count_);
+
+  // Check that unsetting a previously set value fires the notification.
+  var.UnsetValue();
+  RunGMainLoopMaxIterations(100);
+  EXPECT_EQ(2, observer.calls_count_);
+
+  // Check that unsetting again doesn't.
+  var.UnsetValue();
+  RunGMainLoopMaxIterations(100);
+  EXPECT_EQ(2, observer.calls_count_);
+
+  var.RemoveObserver(&observer);
+}
+
+}  // namespace chromeos_update_manager
diff --git a/update_manager/mock_policy.h b/update_manager/mock_policy.h
new file mode 100644
index 0000000..262b246
--- /dev/null
+++ b/update_manager/mock_policy.h
@@ -0,0 +1,40 @@
+// Copyright (c) 2014 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROMEOS_PLATFORM_UPDATE_ENGINE_UPDATE_MANAGER_MOCK_POLICY_H_
+#define CHROMEOS_PLATFORM_UPDATE_ENGINE_UPDATE_MANAGER_MOCK_POLICY_H_
+
+#include <gmock/gmock.h>
+
+#include "update_engine/update_manager/policy.h"
+
+namespace chromeos_update_manager {
+
+// A mocked implementation of Policy.
+class MockPolicy : public Policy {
+ public:
+  MockPolicy() {}
+  virtual ~MockPolicy() {}
+
+  // Policy overrides.
+  MOCK_CONST_METHOD4(UpdateCheckAllowed,
+                     EvalStatus(EvaluationContext*, State*, std::string*,
+                                UpdateCheckParams*));
+
+  MOCK_CONST_METHOD6(UpdateCanStart,
+                     EvalStatus(EvaluationContext*, State*, std::string*,
+                                UpdateCanStartResult*,
+                                const bool, const UpdateState&));
+
+  MOCK_CONST_METHOD4(UpdateCanStart,
+                     EvalStatus(EvaluationContext*, State*, std::string*,
+                                bool*));
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(MockPolicy);
+};
+
+}  // namespace chromeos_update_manager
+
+#endif  // CHROMEOS_PLATFORM_UPDATE_ENGINE_UPDATE_MANAGER_MOCK_POLICY_H_
diff --git a/update_manager/mock_variable.h b/update_manager/mock_variable.h
new file mode 100644
index 0000000..c2ba375
--- /dev/null
+++ b/update_manager/mock_variable.h
@@ -0,0 +1,28 @@
+// Copyright 2014 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROMEOS_PLATFORM_UPDATE_ENGINE_UPDATE_MANAGER_MOCK_VARIABLE_H_
+#define CHROMEOS_PLATFORM_UPDATE_ENGINE_UPDATE_MANAGER_MOCK_VARIABLE_H_
+
+#include <gmock/gmock.h>
+
+#include "update_engine/update_manager/variable.h"
+
+namespace chromeos_update_manager {
+
+// This is a generic mock of the Variable class.
+template<typename T>
+class MockVariable : public Variable<T> {
+ public:
+  using Variable<T>::Variable;
+
+  MOCK_METHOD2_T(GetValue, const T*(base::TimeDelta, std::string*));
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(MockVariable);
+};
+
+}  // namespace chromeos_update_manager
+
+#endif  // CHROMEOS_PLATFORM_UPDATE_ENGINE_UPDATE_MANAGER_MOCK_VARIABLE_H_
diff --git a/update_manager/policy.cc b/update_manager/policy.cc
new file mode 100644
index 0000000..41ff8c1
--- /dev/null
+++ b/update_manager/policy.cc
@@ -0,0 +1,25 @@
+// Copyright (c) 2014 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "update_engine/update_manager/policy.h"
+
+#include <string>
+
+using std::string;
+
+namespace chromeos_update_manager {
+
+string ToString(EvalStatus status) {
+  switch (status) {
+    case EvalStatus::kFailed:
+      return "kFailed";
+    case EvalStatus::kSucceeded:
+      return "kSucceeded";
+    case EvalStatus::kAskMeAgainLater:
+      return "kAskMeAgainLater";
+  }
+  return "Invalid";
+}
+
+}  // namespace chromeos_update_engine
diff --git a/update_manager/policy.h b/update_manager/policy.h
new file mode 100644
index 0000000..65f236c
--- /dev/null
+++ b/update_manager/policy.h
@@ -0,0 +1,137 @@
+// Copyright (c) 2014 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROMEOS_PLATFORM_UPDATE_ENGINE_UPDATE_MANAGER_POLICY_H_
+#define CHROMEOS_PLATFORM_UPDATE_ENGINE_UPDATE_MANAGER_POLICY_H_
+
+#include <string>
+
+#include "update_engine/update_manager/evaluation_context.h"
+#include "update_engine/update_manager/state.h"
+
+namespace chromeos_update_manager {
+
+// The three different results of a policy request.
+enum class EvalStatus {
+  kFailed,
+  kSucceeded,
+  kAskMeAgainLater,
+};
+
+std::string ToString(EvalStatus status);
+
+// Parameters of an update check. These parameters are determined by the
+// UpdateCheckAllowed policy.
+struct UpdateCheckParams {
+  bool updates_enabled;  // Whether the auto-updates are enabled on this build.
+};
+
+// Input arguments to UpdateCanStart.
+//
+// A snapshot of the state of the current update process.
+struct UpdateState {
+  // Time when update was first offered by Omaha.
+  base::Time first_seen;
+  // Number of update checks returning the current update.
+  int num_checks;
+  // Scattering wallclock-based wait period, as returned by the policy.
+  base::TimeDelta scatter_wait_period;
+  // Maximum wait period allowed for this update, as determined by Omaha.
+  base::TimeDelta scatter_wait_period_max;
+  // Scattering update check threshold, as returned by the policy.
+  int scatter_check_threshold;
+  // Minimum/maximum check threshold values.
+  // TODO(garnold) These appear to not be related to the current update and so
+  // should probably be obtained as variables via UpdaterProvider.
+  int scatter_check_threshold_min;
+  int scatter_check_threshold_max;
+};
+
+// Results regarding the downloading and applying of an update, as determined by
+// UpdateCanStart.
+//
+// An enumerator for the reasons of not allowing an update to start.
+enum class UpdateCannotStartReason {
+  kUndefined,
+  kCheckDue,
+  kDisabledByPolicy,
+  kScattering,
+};
+
+struct UpdateCanStartResult {
+  // Whether the update attempt is allowed to proceed.
+  bool update_can_start;
+  // Attributes pertaining to the case where update is allowed. The update
+  // engine uses them to choose the means for downloading and applying an
+  // update.
+  bool http_allowed;
+  bool p2p_allowed;
+  std::string target_channel;
+  // Attributes pertaining to the case where update is not allowed. Some are
+  // needed for storing values to persistent storage, others for
+  // logging/metrics.
+  UpdateCannotStartReason cannot_start_reason;
+  base::TimeDelta scatter_wait_period;  // Needs to be persisted.
+  int scatter_check_threshold;  // Needs to be persisted.
+};
+
+// The Policy class is an interface to the ensemble of policy requests that the
+// client can make. A derived class includes the policy implementations of
+// these.
+//
+// When compile-time selection of the policy is required due to missing or extra
+// parts in a given platform, a different Policy subclass can be used.
+class Policy {
+ public:
+  virtual ~Policy() {}
+
+  // List of policy requests. A policy request takes an EvaluationContext as the
+  // first argument, a State instance, a returned error message, a returned
+  // value and optionally followed by one or more arbitrary constant arguments.
+  //
+  // When the implementation fails, the method returns EvalStatus::kFailed and
+  // sets the |error| string.
+
+  // UpdateCheckAllowed returns whether it is allowed to request an update check
+  // to Omaha.
+  virtual EvalStatus UpdateCheckAllowed(
+      EvaluationContext* ec, State* state, std::string* error,
+      UpdateCheckParams* result) const = 0;
+
+  // Returns EvalStatus::kSucceeded if either an update can start being
+  // processed, or the attempt needs to be aborted. In cases where the update
+  // needs to wait for some condition to be satisfied, but none of the values
+  // that need to be persisted has changed, returns
+  // EvalStatus::kAskMeAgainLater. Arguments include an |interactive| flag that
+  // tells whether the update is user initiated, and an |update_state| that
+  // encapsulates data pertaining to the currnet ongoing update process.
+  virtual EvalStatus UpdateCanStart(
+      EvaluationContext* ec,
+      State* state,
+      std::string* error,
+      UpdateCanStartResult* result,
+      const bool interactive,
+      const UpdateState& update_state) const = 0;
+
+  // Checks whether updating is allowed over the current network connection
+  // Consults the shill provider as well as the device policy (if available).
+  // Returns |EvalStatus::kSucceeded|, setting |result| according to whether or
+  // not the current connection can be used; on failure, returns
+  // |EvalStatus::kFailed| and sets |error| accordingly.
+  virtual EvalStatus UpdateCurrentConnectionAllowed(
+      EvaluationContext* ec,
+      State* state,
+      std::string* error,
+      bool* result) const = 0;
+
+ protected:
+  Policy() {}
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(Policy);
+};
+
+}  // namespace chromeos_update_manager
+
+#endif  // CHROMEOS_PLATFORM_UPDATE_ENGINE_UPDATE_MANAGER_POLICY_H_
diff --git a/update_manager/policy_utils.h b/update_manager/policy_utils.h
new file mode 100644
index 0000000..9e60167
--- /dev/null
+++ b/update_manager/policy_utils.h
@@ -0,0 +1,26 @@
+// Copyright (c) 2014 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROMEOS_PLATFORM_UPDATE_ENGINE_UPDATE_MANAGER_POLICY_UTILS_H_
+#define CHROMEOS_PLATFORM_UPDATE_ENGINE_UPDATE_MANAGER_POLICY_UTILS_H_
+
+#include "update_engine/update_manager/policy.h"
+
+// Checks that the passed pointer value is not null, returning kFailed on the
+// current context and setting the *error description when it is null. The
+// intended use is to validate variable failures while using
+// EvaluationContext::GetValue, for example:
+//
+//   const int* my_value = ec->GetValue(state->my_provider()->var_my_value());
+//   POLICY_CHECK_VALUE_AND_FAIL(my_value, error);
+//
+#define POLICY_CHECK_VALUE_AND_FAIL(ptr, error) \
+    do { \
+      if ((ptr) == nullptr) { \
+        *(error) = #ptr " is required but is null."; \
+        return EvalStatus::kFailed; \
+      } \
+    } while (false)
+
+#endif  // CHROMEOS_PLATFORM_UPDATE_ENGINE_UPDATE_MANAGER_POLICY_UTILS_H_
diff --git a/update_manager/prng.h b/update_manager/prng.h
new file mode 100644
index 0000000..ca07e5e
--- /dev/null
+++ b/update_manager/prng.h
@@ -0,0 +1,39 @@
+// Copyright (c) 2014 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROMEOS_PLATFORM_UPDATE_ENGINE_UPDATE_MANAGER_PRNG_H_
+#define CHROMEOS_PLATFORM_UPDATE_ENGINE_UPDATE_MANAGER_PRNG_H_
+
+#include <random>
+
+#include <base/logging.h>
+
+namespace chromeos_update_manager {
+
+// A thread-safe, unsecure, 32-bit pseudo-random number generator based on
+// std::mt19937.
+class PRNG {
+ public:
+  // Initializes the generator with the passed |seed| value.
+  explicit PRNG(uint32_t seed) : gen_(seed) {}
+
+  // Returns a random unsigned 32-bit integer.
+  uint32_t Rand() { return gen_(); }
+
+  // Returns a random integer uniformly distributed in the range [min, max].
+  int RandMinMax(int min, int max) {
+    DCHECK_LE(min, max);
+    return std::uniform_int_distribution<>(min, max)(gen_);
+  }
+
+ private:
+  // A pseudo-random number generator.
+  std::mt19937 gen_;
+
+  DISALLOW_COPY_AND_ASSIGN(PRNG);
+};
+
+}  // namespace chromeos_update_manager
+
+#endif  // CHROMEOS_PLATFORM_UPDATE_ENGINE_UPDATE_MANAGER_PRNG_H_
diff --git a/update_manager/prng_unittest.cc b/update_manager/prng_unittest.cc
new file mode 100644
index 0000000..4d165b3
--- /dev/null
+++ b/update_manager/prng_unittest.cc
@@ -0,0 +1,67 @@
+// Copyright (c) 2014 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "update_engine/update_manager/prng.h"
+
+#include <vector>
+
+#include <gtest/gtest.h>
+
+using std::vector;
+
+namespace chromeos_update_manager {
+
+TEST(UmPRNGTest, ShouldBeDeterministic) {
+  PRNG a(42);
+  PRNG b(42);
+
+  for (int i = 0; i < 1000; ++i) {
+    EXPECT_EQ(a.Rand(), b.Rand()) << "Iteration i=" << i;
+  }
+}
+
+TEST(UmPRNGTest, SeedChangesGeneratedSequence) {
+  PRNG a(42);
+  PRNG b(5);
+
+  vector<uint32_t> values_a;
+  vector<uint32_t> values_b;
+
+  for (int i = 0; i < 100; ++i) {
+    values_a.push_back(a.Rand());
+    values_b.push_back(b.Rand());
+  }
+  EXPECT_NE(values_a, values_b);
+}
+
+TEST(UmPRNGTest, IsNotConstant) {
+  PRNG prng(5);
+
+  uint32_t initial_value = prng.Rand();
+  bool prng_is_constant = true;
+  for (int i = 0; i < 100; ++i) {
+    if (prng.Rand() != initial_value) {
+      prng_is_constant = false;
+      break;
+    }
+  }
+  EXPECT_FALSE(prng_is_constant) << "After 100 iterations.";
+}
+
+TEST(UmPRNGTest, RandCoversRange) {
+  PRNG a(42);
+  int hits[11] = { 0 };
+
+  for (int i = 0; i < 1000; i++) {
+    int r = a.RandMinMax(0, 10);
+    ASSERT_LE(0, r);
+    ASSERT_GE(10, r);
+    hits[r]++;
+  }
+
+  for (auto& hit : hits)
+    EXPECT_LT(0, hit);
+}
+
+}  // namespace chromeos_update_manager
diff --git a/update_manager/provider.h b/update_manager/provider.h
new file mode 100644
index 0000000..3fb1d90
--- /dev/null
+++ b/update_manager/provider.h
@@ -0,0 +1,26 @@
+// Copyright (c) 2014 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROMEOS_PLATFORM_UPDATE_ENGINE_UPDATE_MANAGER_PROVIDER_H_
+#define CHROMEOS_PLATFORM_UPDATE_ENGINE_UPDATE_MANAGER_PROVIDER_H_
+
+#include <base/basictypes.h>
+
+namespace chromeos_update_manager {
+
+// Abstract base class for a policy provider.
+class Provider {
+ public:
+  virtual ~Provider() {}
+
+ protected:
+  Provider() {}
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(Provider);
+};
+
+}  // namespace chromeos_update_manager
+
+#endif  // CHROMEOS_PLATFORM_UPDATE_ENGINE_UPDATE_MANAGER_PROVIDER_H_
diff --git a/update_manager/random_provider.h b/update_manager/random_provider.h
new file mode 100644
index 0000000..dede41c
--- /dev/null
+++ b/update_manager/random_provider.h
@@ -0,0 +1,33 @@
+// Copyright (c) 2014 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROMEOS_PLATFORM_UPDATE_ENGINE_UPDATE_MANAGER_RANDOM_PROVIDER_H_
+#define CHROMEOS_PLATFORM_UPDATE_ENGINE_UPDATE_MANAGER_RANDOM_PROVIDER_H_
+
+#include "update_engine/update_manager/provider.h"
+#include "update_engine/update_manager/variable.h"
+
+namespace chromeos_update_manager {
+
+// Provider of random values.
+class RandomProvider : public Provider {
+ public:
+  virtual ~RandomProvider() {}
+
+  // Return a random number every time it is requested. Note that values
+  // returned by the variables are cached by the EvaluationContext, so the
+  // returned value will be the same during the same policy request. If more
+  // random values are needed use a PRNG seeded with this value.
+  virtual Variable<uint64_t>* var_seed() = 0;
+
+ protected:
+  RandomProvider() {}
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(RandomProvider);
+};
+
+}  // namespace chromeos_update_manager
+
+#endif  // CHROMEOS_PLATFORM_UPDATE_ENGINE_UPDATE_MANAGER_RANDOM_PROVIDER_H_
diff --git a/update_manager/real_config_provider.cc b/update_manager/real_config_provider.cc
new file mode 100644
index 0000000..0e76b73
--- /dev/null
+++ b/update_manager/real_config_provider.cc
@@ -0,0 +1,51 @@
+// Copyright 2014 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "update_engine/update_manager/real_config_provider.h"
+
+#include <base/logging.h>
+
+#include "update_engine/constants.h"
+#include "update_engine/simple_key_value_store.h"
+#include "update_engine/update_manager/generic_variables.h"
+#include "update_engine/utils.h"
+
+using chromeos_update_engine::KeyValueStore;
+using std::string;
+
+namespace {
+
+const char* kConfigFilePath = "/etc/update_manager.conf";
+
+// Config options:
+const char* kConfigOptsIsOOBEEnabled = "is_oobe_enabled";
+
+}  // namespace
+
+namespace chromeos_update_manager {
+
+bool RealConfigProvider::Init() {
+  KeyValueStore store;
+
+  if (hardware_->IsNormalBootMode()) {
+    store.Load(root_prefix_ + kConfigFilePath);
+  } else {
+    if (store.Load(root_prefix_ + chromeos_update_engine::kStatefulPartition +
+                   kConfigFilePath)) {
+      LOG(INFO) << "UpdateManager Config loaded from stateful partition.";
+    } else {
+      store.Load(root_prefix_ + kConfigFilePath);
+    }
+  }
+
+  bool is_oobe_enabled;
+  if (!store.GetBoolean(kConfigOptsIsOOBEEnabled, &is_oobe_enabled))
+    is_oobe_enabled = true;  // Default value.
+  var_is_oobe_enabled_.reset(
+      new ConstCopyVariable<bool>(kConfigOptsIsOOBEEnabled, is_oobe_enabled));
+
+  return true;
+}
+
+}  // namespace chromeos_update_manager
diff --git a/update_manager/real_config_provider.h b/update_manager/real_config_provider.h
new file mode 100644
index 0000000..e525e38
--- /dev/null
+++ b/update_manager/real_config_provider.h
@@ -0,0 +1,54 @@
+// Copyright 2014 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROMEOS_PLATFORM_UPDATE_ENGINE_UPDATE_MANAGER_REAL_CONFIG_PROVIDER_H_
+#define CHROMEOS_PLATFORM_UPDATE_ENGINE_UPDATE_MANAGER_REAL_CONFIG_PROVIDER_H_
+
+#include <string>
+
+#include <base/memory/scoped_ptr.h>
+
+#include "update_engine/hardware_interface.h"
+#include "update_engine/update_manager/config_provider.h"
+#include "update_engine/update_manager/generic_variables.h"
+
+namespace chromeos_update_manager {
+
+// ConfigProvider concrete implementation.
+class RealConfigProvider : public ConfigProvider {
+ public:
+  explicit RealConfigProvider(
+      chromeos_update_engine::HardwareInterface* hardware)
+      : hardware_(hardware) {}
+
+  // Initializes the provider and returns whether it succeeded.
+  bool Init();
+
+  Variable<bool>* var_is_oobe_enabled() override {
+    return var_is_oobe_enabled_.get();
+  }
+
+ private:
+  friend class UmRealConfigProviderTest;
+
+  // Used for testing. Sets the root prefix, which is by default "". Call this
+  // method before calling Init() in order to mock out the place where the files
+  // are being read from.
+  void SetRootPrefix(const std::string& prefix) {
+    root_prefix_ = prefix;
+  }
+
+  scoped_ptr<ConstCopyVariable<bool>> var_is_oobe_enabled_;
+
+  chromeos_update_engine::HardwareInterface* hardware_;
+
+  // Prefix to prepend to the file paths. Useful for testing.
+  std::string root_prefix_;
+
+  DISALLOW_COPY_AND_ASSIGN(RealConfigProvider);
+};
+
+}  // namespace chromeos_update_manager
+
+#endif  // CHROMEOS_PLATFORM_UPDATE_ENGINE_UPDATE_MANAGER_REAL_CONFIG_PROVIDER_H_
diff --git a/update_manager/real_config_provider_unittest.cc b/update_manager/real_config_provider_unittest.cc
new file mode 100644
index 0000000..fc20e36
--- /dev/null
+++ b/update_manager/real_config_provider_unittest.cc
@@ -0,0 +1,88 @@
+// Copyright 2014 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "update_engine/update_manager/real_config_provider.h"
+
+#include <base/file_util.h>
+#include <base/files/scoped_temp_dir.h>
+#include <base/memory/scoped_ptr.h>
+#include <gtest/gtest.h>
+
+#include "update_engine/constants.h"
+#include "update_engine/fake_hardware.h"
+#include "update_engine/test_utils.h"
+#include "update_engine/update_manager/umtest_utils.h"
+
+using base::TimeDelta;
+using chromeos_update_engine::WriteFileString;
+using std::string;
+
+namespace chromeos_update_manager {
+
+class UmRealConfigProviderTest : public ::testing::Test {
+ protected:
+  virtual void SetUp() {
+    ASSERT_TRUE(root_dir_.CreateUniqueTempDir());
+    provider_.reset(new RealConfigProvider(&fake_hardware_));
+    provider_->SetRootPrefix(root_dir_.path().value());
+  }
+
+  void WriteStatefulConfig(const string& config) {
+    base::FilePath kFile(root_dir_.path().value()
+                         + chromeos_update_engine::kStatefulPartition
+                         + "/etc/update_manager.conf");
+    ASSERT_TRUE(base::CreateDirectory(kFile.DirName()));
+    ASSERT_TRUE(WriteFileString(kFile.value(), config));
+  }
+
+  void WriteRootfsConfig(const string& config) {
+    base::FilePath kFile(root_dir_.path().value()
+                         + "/etc/update_manager.conf");
+    ASSERT_TRUE(base::CreateDirectory(kFile.DirName()));
+    ASSERT_TRUE(WriteFileString(kFile.value(), config));
+  }
+
+  scoped_ptr<RealConfigProvider> provider_;
+  chromeos_update_engine::FakeHardware fake_hardware_;
+  TimeDelta default_timeout_ = TimeDelta::FromSeconds(1);
+  base::ScopedTempDir root_dir_;
+};
+
+TEST_F(UmRealConfigProviderTest, InitTest) {
+  EXPECT_TRUE(provider_->Init());
+  UMTEST_EXPECT_NOT_NULL(provider_->var_is_oobe_enabled());
+}
+
+TEST_F(UmRealConfigProviderTest, NoFileFoundReturnsDefault) {
+  EXPECT_TRUE(provider_->Init());
+  UmTestUtils::ExpectVariableHasValue(true, provider_->var_is_oobe_enabled());
+}
+
+TEST_F(UmRealConfigProviderTest, DontReadStatefulInNormalMode) {
+  fake_hardware_.SetIsNormalBootMode(true);
+  WriteStatefulConfig("is_oobe_enabled=false");
+
+  EXPECT_TRUE(provider_->Init());
+  UmTestUtils::ExpectVariableHasValue(true, provider_->var_is_oobe_enabled());
+}
+
+TEST_F(UmRealConfigProviderTest, ReadStatefulInDevMode) {
+  fake_hardware_.SetIsNormalBootMode(false);
+  WriteRootfsConfig("is_oobe_enabled=true");
+  // Since the stateful is present, this should read that one.
+  WriteStatefulConfig("is_oobe_enabled=false");
+
+  EXPECT_TRUE(provider_->Init());
+  UmTestUtils::ExpectVariableHasValue(false, provider_->var_is_oobe_enabled());
+}
+
+TEST_F(UmRealConfigProviderTest, ReadRootfsIfStatefulNotFound) {
+  fake_hardware_.SetIsNormalBootMode(false);
+  WriteRootfsConfig("is_oobe_enabled=false");
+
+  EXPECT_TRUE(provider_->Init());
+  UmTestUtils::ExpectVariableHasValue(false, provider_->var_is_oobe_enabled());
+}
+
+}  // namespace chromeos_update_manager
diff --git a/update_manager/real_device_policy_provider.cc b/update_manager/real_device_policy_provider.cc
new file mode 100644
index 0000000..e26ffe0
--- /dev/null
+++ b/update_manager/real_device_policy_provider.cc
@@ -0,0 +1,136 @@
+// Copyright (c) 2014 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "update_engine/update_manager/real_device_policy_provider.h"
+
+#include <base/logging.h>
+#include <base/time/time.h>
+#include <policy/device_policy.h>
+
+#include "update_engine/update_manager/generic_variables.h"
+#include "update_engine/update_manager/real_shill_provider.h"
+#include "update_engine/utils.h"
+
+using base::TimeDelta;
+using policy::DevicePolicy;
+using std::set;
+using std::string;
+
+namespace {
+
+const int kDevicePolicyRefreshRateInMinutes = 60;
+
+}  // namespace
+
+namespace chromeos_update_manager {
+
+RealDevicePolicyProvider::~RealDevicePolicyProvider() {
+  CancelMainLoopEvent(scheduled_refresh_);
+}
+
+bool RealDevicePolicyProvider::Init() {
+  CHECK(policy_provider_ != nullptr);
+
+  // On Init() we try to get the device policy and keep updating it.
+  RefreshDevicePolicyAndReschedule();
+
+  return true;
+}
+
+void RealDevicePolicyProvider::RefreshDevicePolicyAndReschedule() {
+  RefreshDevicePolicy();
+  scheduled_refresh_ = RunFromMainLoopAfterTimeout(
+      base::Bind(&RealDevicePolicyProvider::RefreshDevicePolicyAndReschedule,
+                 base::Unretained(this)),
+      TimeDelta::FromMinutes(kDevicePolicyRefreshRateInMinutes));
+}
+
+template<typename T>
+void RealDevicePolicyProvider::UpdateVariable(
+    AsyncCopyVariable<T>* var,
+    bool (policy::DevicePolicy::*getter_method)(T*) const) {
+  T new_value;
+  if (policy_provider_->device_policy_is_loaded() &&
+      (policy_provider_->GetDevicePolicy().*getter_method)(&new_value)) {
+    var->SetValue(new_value);
+  } else {
+    var->UnsetValue();
+  }
+}
+
+template<typename T>
+void RealDevicePolicyProvider::UpdateVariable(
+    AsyncCopyVariable<T>* var,
+    bool (RealDevicePolicyProvider::*getter_method)(T*) const) {
+  T new_value;
+  if (policy_provider_->device_policy_is_loaded() &&
+      (this->*getter_method)(&new_value)) {
+    var->SetValue(new_value);
+  } else {
+    var->UnsetValue();
+  }
+}
+
+bool RealDevicePolicyProvider::ConvertAllowedConnectionTypesForUpdate(
+      set<ConnectionType>* allowed_types) const {
+  set<string> allowed_types_str;
+  if (!policy_provider_->GetDevicePolicy()
+      .GetAllowedConnectionTypesForUpdate(&allowed_types_str)) {
+    return false;
+  }
+  allowed_types->clear();
+  for (auto& type_str : allowed_types_str) {
+    ConnectionType type =
+        RealShillProvider::ParseConnectionType(type_str.c_str());
+    if (type != ConnectionType::kUnknown) {
+      allowed_types->insert(type);
+    } else {
+      LOG(WARNING) << "Policy includes unknown connection type: " << type_str;
+    }
+  }
+  return true;
+}
+
+bool RealDevicePolicyProvider::ConvertScatterFactor(
+    base::TimeDelta* scatter_factor) const {
+  int64 scatter_factor_in_seconds;
+  if (!policy_provider_->GetDevicePolicy().GetScatterFactorInSeconds(
+      &scatter_factor_in_seconds)) {
+    return false;
+  }
+  if (scatter_factor_in_seconds < 0) {
+    LOG(WARNING) << "Ignoring negative scatter factor: "
+                 << scatter_factor_in_seconds;
+    return false;
+  }
+  *scatter_factor = base::TimeDelta::FromSeconds(scatter_factor_in_seconds);
+  return true;
+}
+
+void RealDevicePolicyProvider::RefreshDevicePolicy() {
+  if (!policy_provider_->Reload()) {
+    LOG(INFO) << "No device policies/settings present.";
+  }
+
+  var_device_policy_is_loaded_.SetValue(
+      policy_provider_->device_policy_is_loaded());
+
+  UpdateVariable(&var_release_channel_, &DevicePolicy::GetReleaseChannel);
+  UpdateVariable(&var_release_channel_delegated_,
+                 &DevicePolicy::GetReleaseChannelDelegated);
+  UpdateVariable(&var_update_disabled_, &DevicePolicy::GetUpdateDisabled);
+  UpdateVariable(&var_target_version_prefix_,
+                 &DevicePolicy::GetTargetVersionPrefix);
+  UpdateVariable(&var_scatter_factor_,
+                 &RealDevicePolicyProvider::ConvertScatterFactor);
+  UpdateVariable(
+      &var_allowed_connection_types_for_update_,
+      &RealDevicePolicyProvider::ConvertAllowedConnectionTypesForUpdate);
+  UpdateVariable(&var_get_owner_, &DevicePolicy::GetOwner);
+  UpdateVariable(&var_http_downloads_enabled_,
+                 &DevicePolicy::GetHttpDownloadsEnabled);
+  UpdateVariable(&var_au_p2p_enabled_, &DevicePolicy::GetAuP2PEnabled);
+}
+
+}  // namespace chromeos_update_manager
diff --git a/update_manager/real_device_policy_provider.h b/update_manager/real_device_policy_provider.h
new file mode 100644
index 0000000..fdbfcd9
--- /dev/null
+++ b/update_manager/real_device_policy_provider.h
@@ -0,0 +1,135 @@
+// Copyright (c) 2014 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROMEOS_PLATFORM_UPDATE_ENGINE_UPDATE_MANAGER_REAL_DEVICE_POLICY_PROVIDER_H_
+#define CHROMEOS_PLATFORM_UPDATE_ENGINE_UPDATE_MANAGER_REAL_DEVICE_POLICY_PROVIDER_H_
+
+#include <set>
+#include <string>
+
+#include <gtest/gtest_prod.h>  // for FRIEND_TEST
+#include <policy/libpolicy.h>
+
+#include "update_engine/update_manager/device_policy_provider.h"
+#include "update_engine/update_manager/event_loop.h"
+#include "update_engine/update_manager/generic_variables.h"
+
+namespace chromeos_update_manager {
+
+// DevicePolicyProvider concrete implementation.
+class RealDevicePolicyProvider : public DevicePolicyProvider {
+ public:
+  explicit RealDevicePolicyProvider(policy::PolicyProvider* policy_provider)
+      : policy_provider_(policy_provider) {}
+  ~RealDevicePolicyProvider();
+
+  // Initializes the provider and returns whether it succeeded.
+  bool Init();
+
+  virtual Variable<bool>* var_device_policy_is_loaded() override {
+    return &var_device_policy_is_loaded_;
+  }
+
+  virtual Variable<std::string>* var_release_channel() override {
+    return &var_release_channel_;
+  }
+
+  virtual Variable<bool>* var_release_channel_delegated() override {
+    return &var_release_channel_delegated_;
+  }
+
+  virtual Variable<bool>* var_update_disabled() override {
+    return &var_update_disabled_;
+  }
+
+  virtual Variable<std::string>* var_target_version_prefix() override {
+    return &var_target_version_prefix_;
+  }
+
+  virtual Variable<base::TimeDelta>* var_scatter_factor() override {
+    return &var_scatter_factor_;
+  }
+
+  virtual Variable<std::set<ConnectionType>>*
+      var_allowed_connection_types_for_update() override {
+    return &var_allowed_connection_types_for_update_;
+  }
+
+  virtual Variable<std::string>* var_get_owner() override {
+    return &var_get_owner_;
+  }
+
+  virtual Variable<bool>* var_http_downloads_enabled() override {
+    return &var_http_downloads_enabled_;
+  }
+
+  virtual Variable<bool>* var_au_p2p_enabled() override {
+    return &var_au_p2p_enabled_;
+  }
+
+ private:
+  FRIEND_TEST(UmRealDevicePolicyProviderTest, RefreshScheduledTest);
+  FRIEND_TEST(UmRealDevicePolicyProviderTest, NonExistentDevicePolicyReloaded);
+  FRIEND_TEST(UmRealDevicePolicyProviderTest, ValuesUpdated);
+
+  // Schedules a call to periodically refresh the device policy.
+  void RefreshDevicePolicyAndReschedule();
+
+  // Reloads the device policy and updates all the exposed variables.
+  void RefreshDevicePolicy();
+
+  // Updates the async variable |var| based on the result value of the method
+  // passed, which is a DevicePolicy getter method.
+  template<typename T>
+  void UpdateVariable(AsyncCopyVariable<T>* var,
+                      bool (policy::DevicePolicy::*getter_method)(T*) const);
+
+  // Updates the async variable |var| based on the result value of the getter
+  // method passed, which is a wrapper getter on this class.
+  template<typename T>
+  void UpdateVariable(
+      AsyncCopyVariable<T>* var,
+      bool (RealDevicePolicyProvider::*getter_method)(T*) const);
+
+  // Wrapper for DevicePolicy::GetScatterFactorInSeconds() that converts the
+  // result to a base::TimeDelta. It returns the same value as
+  // GetScatterFactorInSeconds().
+  bool ConvertScatterFactor(base::TimeDelta* scatter_factor) const;
+
+  // Wrapper for DevicePolicy::GetAllowedConnectionTypesForUpdate() that
+  // converts the result to a set of ConnectionType elements instead of strings.
+  bool ConvertAllowedConnectionTypesForUpdate(
+      std::set<ConnectionType>* allowed_types) const;
+
+  // Used for fetching information about the device policy.
+  policy::PolicyProvider* policy_provider_;
+
+  // Used to schedule refreshes of the device policy.
+  EventId scheduled_refresh_ = kEventIdNull;
+
+  // Variable exposing whether the policy is loaded.
+  AsyncCopyVariable<bool> var_device_policy_is_loaded_{
+      "policy_is_loaded", false};
+
+  // Variables mapping the exposed methods from the policy::DevicePolicy.
+  AsyncCopyVariable<std::string> var_release_channel_{"release_channel"};
+  AsyncCopyVariable<bool> var_release_channel_delegated_{
+      "release_channel_delegated"};
+  AsyncCopyVariable<bool> var_update_disabled_{"update_disabled"};
+  AsyncCopyVariable<std::string> var_target_version_prefix_{
+      "target_version_prefix"};
+  AsyncCopyVariable<base::TimeDelta> var_scatter_factor_{"scatter_factor"};
+  AsyncCopyVariable<std::set<ConnectionType>>
+      var_allowed_connection_types_for_update_{
+          "allowed_connection_types_for_update"};
+  AsyncCopyVariable<std::string> var_get_owner_{"get_owner"};
+  AsyncCopyVariable<bool> var_http_downloads_enabled_{"http_downloads_enabled"};
+  AsyncCopyVariable<bool> var_au_p2p_enabled_{"au_p2p_enabled"};
+
+  DISALLOW_COPY_AND_ASSIGN(RealDevicePolicyProvider);
+};
+
+}  // namespace chromeos_update_manager
+
+#endif  // CHROMEOS_PLATFORM_UPDATE_ENGINE_UPDATE_MANAGER_REAL_DEVICE_POLICY_PROVIDER_H_
diff --git a/update_manager/real_device_policy_provider_unittest.cc b/update_manager/real_device_policy_provider_unittest.cc
new file mode 100644
index 0000000..3b3d3e9
--- /dev/null
+++ b/update_manager/real_device_policy_provider_unittest.cc
@@ -0,0 +1,165 @@
+// Copyright (c) 2014 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "update_engine/update_manager/real_device_policy_provider.h"
+
+#include <base/memory/scoped_ptr.h>
+#include <gtest/gtest.h>
+#include <policy/mock_device_policy.h>
+#include <policy/mock_libpolicy.h>
+
+#include "update_engine/test_utils.h"
+#include "update_engine/update_manager/umtest_utils.h"
+
+using base::TimeDelta;
+using chromeos_update_engine::RunGMainLoopMaxIterations;
+using std::set;
+using std::string;
+using testing::AtLeast;
+using testing::DoAll;
+using testing::Mock;
+using testing::Return;
+using testing::ReturnRef;
+using testing::SetArgumentPointee;
+using testing::_;
+
+namespace chromeos_update_manager {
+
+class UmRealDevicePolicyProviderTest : public ::testing::Test {
+ protected:
+  virtual void SetUp() {
+    provider_.reset(new RealDevicePolicyProvider(&mock_policy_provider_));
+    // By default, we have a device policy loaded. Tests can call
+    // SetUpNonExistentDevicePolicy() to override this.
+    SetUpExistentDevicePolicy();
+  }
+
+  virtual void TearDown() {
+    // Check for leaked callbacks on the main loop.
+    EXPECT_EQ(0, RunGMainLoopMaxIterations(100));
+  }
+
+  void SetUpNonExistentDevicePolicy() {
+    ON_CALL(mock_policy_provider_, Reload())
+        .WillByDefault(Return(false));
+    ON_CALL(mock_policy_provider_, device_policy_is_loaded())
+        .WillByDefault(Return(false));
+    EXPECT_CALL(mock_policy_provider_, GetDevicePolicy()).Times(0);
+  }
+
+  void SetUpExistentDevicePolicy() {
+    // Setup the default behavior of the mocked PolicyProvider.
+    ON_CALL(mock_policy_provider_, Reload())
+        .WillByDefault(Return(true));
+    ON_CALL(mock_policy_provider_, device_policy_is_loaded())
+        .WillByDefault(Return(true));
+    ON_CALL(mock_policy_provider_, GetDevicePolicy())
+        .WillByDefault(ReturnRef(mock_device_policy_));
+  }
+
+  testing::NiceMock<policy::MockDevicePolicy> mock_device_policy_;
+  testing::NiceMock<policy::MockPolicyProvider> mock_policy_provider_;
+  scoped_ptr<RealDevicePolicyProvider> provider_;
+};
+
+TEST_F(UmRealDevicePolicyProviderTest, RefreshScheduledTest) {
+  // Check that the RefreshPolicy gets scheduled by checking the EventId.
+  EXPECT_TRUE(provider_->Init());
+  EXPECT_NE(kEventIdNull, provider_->scheduled_refresh_);
+}
+
+TEST_F(UmRealDevicePolicyProviderTest, FirstReload) {
+  // Checks that the policy is reloaded and the DevicePolicy is consulted.
+  EXPECT_CALL(mock_policy_provider_, Reload());
+  EXPECT_TRUE(provider_->Init());
+}
+
+TEST_F(UmRealDevicePolicyProviderTest, NonExistentDevicePolicyReloaded) {
+  // Checks that the policy is reloaded by RefreshDevicePolicy().
+  SetUpNonExistentDevicePolicy();
+  EXPECT_CALL(mock_policy_provider_, Reload()).Times(2);
+  EXPECT_TRUE(provider_->Init());
+  // Force the policy refresh.
+  provider_->RefreshDevicePolicy();
+}
+
+TEST_F(UmRealDevicePolicyProviderTest, NonExistentDevicePolicyEmptyVariables) {
+  SetUpNonExistentDevicePolicy();
+  EXPECT_CALL(mock_policy_provider_, GetDevicePolicy()).Times(0);
+  EXPECT_TRUE(provider_->Init());
+
+  UmTestUtils::ExpectVariableHasValue(false,
+                                      provider_->var_device_policy_is_loaded());
+
+  UmTestUtils::ExpectVariableNotSet(provider_->var_release_channel());
+  UmTestUtils::ExpectVariableNotSet(provider_->var_release_channel_delegated());
+  UmTestUtils::ExpectVariableNotSet(provider_->var_update_disabled());
+  UmTestUtils::ExpectVariableNotSet(provider_->var_target_version_prefix());
+  UmTestUtils::ExpectVariableNotSet(provider_->var_scatter_factor());
+  UmTestUtils::ExpectVariableNotSet(
+      provider_->var_allowed_connection_types_for_update());
+  UmTestUtils::ExpectVariableNotSet(provider_->var_get_owner());
+  UmTestUtils::ExpectVariableNotSet(provider_->var_http_downloads_enabled());
+  UmTestUtils::ExpectVariableNotSet(provider_->var_au_p2p_enabled());
+}
+
+TEST_F(UmRealDevicePolicyProviderTest, ValuesUpdated) {
+  SetUpNonExistentDevicePolicy();
+  EXPECT_TRUE(provider_->Init());
+  Mock::VerifyAndClearExpectations(&mock_policy_provider_);
+
+  // Reload the policy with a good one and set some values as present. The
+  // remaining values are false.
+  SetUpExistentDevicePolicy();
+  EXPECT_CALL(mock_device_policy_, GetReleaseChannel(_))
+      .WillOnce(DoAll(SetArgumentPointee<0>(string("mychannel")),
+                      Return(true)));
+  EXPECT_CALL(mock_device_policy_, GetAllowedConnectionTypesForUpdate(_))
+      .WillOnce(Return(false));
+
+  provider_->RefreshDevicePolicy();
+
+  UmTestUtils::ExpectVariableHasValue(true,
+                                      provider_->var_device_policy_is_loaded());
+
+  // Test that at least one variable is set, to ensure the refresh ocurred.
+  UmTestUtils::ExpectVariableHasValue(string("mychannel"),
+                                      provider_->var_release_channel());
+  UmTestUtils::ExpectVariableNotSet(
+      provider_->var_allowed_connection_types_for_update());
+}
+
+TEST_F(UmRealDevicePolicyProviderTest, ScatterFactorConverted) {
+  SetUpExistentDevicePolicy();
+  EXPECT_CALL(mock_device_policy_, GetScatterFactorInSeconds(_))
+      .WillOnce(DoAll(SetArgumentPointee<0>(1234), Return(true)));
+  EXPECT_TRUE(provider_->Init());
+
+  UmTestUtils::ExpectVariableHasValue(base::TimeDelta::FromSeconds(1234),
+                                      provider_->var_scatter_factor());
+}
+
+TEST_F(UmRealDevicePolicyProviderTest, NegativeScatterFactorIgnored) {
+  SetUpExistentDevicePolicy();
+  EXPECT_CALL(mock_device_policy_, GetScatterFactorInSeconds(_))
+      .WillOnce(DoAll(SetArgumentPointee<0>(-1), Return(true)));
+  EXPECT_TRUE(provider_->Init());
+
+  UmTestUtils::ExpectVariableNotSet(provider_->var_scatter_factor());
+}
+
+TEST_F(UmRealDevicePolicyProviderTest, AllowedTypesConverted) {
+  SetUpExistentDevicePolicy();
+  EXPECT_CALL(mock_device_policy_, GetAllowedConnectionTypesForUpdate(_))
+      .WillOnce(DoAll(SetArgumentPointee<0>(
+                          set<string>{"bluetooth", "wifi", "not-a-type"}),
+                      Return(true)));
+  EXPECT_TRUE(provider_->Init());
+
+  UmTestUtils::ExpectVariableHasValue(
+      set<ConnectionType>{ConnectionType::kWifi, ConnectionType::kBluetooth},
+      provider_->var_allowed_connection_types_for_update());
+}
+
+}  // namespace chromeos_update_manager
diff --git a/update_manager/real_random_provider.cc b/update_manager/real_random_provider.cc
new file mode 100644
index 0000000..c151c4f
--- /dev/null
+++ b/update_manager/real_random_provider.cc
@@ -0,0 +1,74 @@
+// Copyright (c) 2014 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <stdio.h>
+#include <unistd.h>
+
+#include <base/files/file_path.h>
+#include <base/files/scoped_file.h>
+#include <base/strings/stringprintf.h>
+
+#include "update_engine/update_manager/real_random_provider.h"
+#include "update_engine/update_manager/variable.h"
+
+using std::string;
+
+namespace {
+
+// The device providing randomness.
+const char* kRandomDevice = "/dev/urandom";
+
+}  // namespace
+
+namespace chromeos_update_manager {
+
+// A random seed variable.
+class RandomSeedVariable : public Variable<uint64_t> {
+ public:
+  // RandomSeedVariable is initialized as kVariableModeConst to let the
+  // EvaluationContext cache the value between different evaluations of the same
+  // policy request.
+  RandomSeedVariable(const string& name, FILE* fp)
+      : Variable<uint64_t>(name, kVariableModeConst), fp_(fp) {}
+  virtual ~RandomSeedVariable() {}
+
+ protected:
+  virtual const uint64_t* GetValue(base::TimeDelta /* timeout */,
+                                   string* errmsg) {
+    uint64_t result;
+    // Aliasing via char pointer abides by the C/C++ strict-aliasing rules.
+    char* const buf = reinterpret_cast<char*>(&result);
+    unsigned int buf_rd = 0;
+
+    while (buf_rd < sizeof(result)) {
+      int rd = fread(buf + buf_rd, 1, sizeof(result) - buf_rd, fp_.get());
+      if (rd == 0 || ferror(fp_.get())) {
+        // Either EOF on fp or read failed.
+        if (errmsg) {
+          *errmsg = base::StringPrintf(
+              "Error reading from the random device: %s", kRandomDevice);
+        }
+        return NULL;
+      }
+      buf_rd += rd;
+    }
+
+    return new uint64_t(result);
+  }
+
+ private:
+  base::ScopedFILE fp_;
+
+  DISALLOW_COPY_AND_ASSIGN(RandomSeedVariable);
+};
+
+bool RealRandomProvider::Init(void) {
+  FILE* fp = fopen(kRandomDevice, "r");
+  if (!fp)
+    return false;
+  var_seed_.reset(new RandomSeedVariable("seed", fp));
+  return true;
+}
+
+}  // namespace chromeos_update_manager
diff --git a/update_manager/real_random_provider.h b/update_manager/real_random_provider.h
new file mode 100644
index 0000000..d1de79e
--- /dev/null
+++ b/update_manager/real_random_provider.h
@@ -0,0 +1,33 @@
+// Copyright (c) 2014 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROMEOS_PLATFORM_UPDATE_ENGINE_UPDATE_MANAGER_REAL_RANDOM_PROVIDER_H_
+#define CHROMEOS_PLATFORM_UPDATE_ENGINE_UPDATE_MANAGER_REAL_RANDOM_PROVIDER_H_
+
+#include <base/memory/scoped_ptr.h>
+
+#include "update_engine/update_manager/random_provider.h"
+
+namespace chromeos_update_manager {
+
+// RandomProvider implementation class.
+class RealRandomProvider : public RandomProvider {
+ public:
+  RealRandomProvider() {}
+
+  virtual Variable<uint64_t>* var_seed() override { return var_seed_.get(); }
+
+  // Initializes the provider and returns whether it succeeded.
+  bool Init();
+
+ private:
+  // The seed() scoped variable.
+  scoped_ptr<Variable<uint64_t>> var_seed_;
+
+  DISALLOW_COPY_AND_ASSIGN(RealRandomProvider);
+};
+
+}  // namespace chromeos_update_manager
+
+#endif  // CHROMEOS_PLATFORM_UPDATE_ENGINE_UPDATE_MANAGER_REAL_RANDOM_PROVIDER_H_
diff --git a/update_manager/real_random_provider_unittest.cc b/update_manager/real_random_provider_unittest.cc
new file mode 100644
index 0000000..55e17fa
--- /dev/null
+++ b/update_manager/real_random_provider_unittest.cc
@@ -0,0 +1,53 @@
+// Copyright (c) 2014 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <base/memory/scoped_ptr.h>
+#include <gtest/gtest.h>
+
+#include "update_engine/update_manager/real_random_provider.h"
+#include "update_engine/update_manager/umtest_utils.h"
+
+using base::TimeDelta;
+
+namespace chromeos_update_manager {
+
+class UmRealRandomProviderTest : public ::testing::Test {
+ protected:
+  virtual void SetUp() {
+    // The provider initializes correctly.
+    provider_.reset(new RealRandomProvider());
+    UMTEST_ASSERT_NOT_NULL(provider_.get());
+    ASSERT_TRUE(provider_->Init());
+
+    provider_->var_seed();
+  }
+
+  scoped_ptr<RealRandomProvider> provider_;
+};
+
+TEST_F(UmRealRandomProviderTest, InitFinalize) {
+  // The provider initializes all variables with valid objects.
+  UMTEST_EXPECT_NOT_NULL(provider_->var_seed());
+}
+
+TEST_F(UmRealRandomProviderTest, GetRandomValues) {
+  // Should not return the same random seed repeatedly.
+  scoped_ptr<const uint64_t> value(
+      provider_->var_seed()->GetValue(UmTestUtils::DefaultTimeout(), nullptr));
+  UMTEST_ASSERT_NOT_NULL(value.get());
+
+  // Test that at least the returned values are different. This test fails,
+  // by design, once every 2^320 runs.
+  bool is_same_value = true;
+  for (int i = 0; i < 5; i++) {
+    scoped_ptr<const uint64_t> other_value(
+        provider_->var_seed()->GetValue(UmTestUtils::DefaultTimeout(),
+                                        nullptr));
+    UMTEST_ASSERT_NOT_NULL(other_value.get());
+    is_same_value = is_same_value && *other_value == *value;
+  }
+  EXPECT_FALSE(is_same_value);
+}
+
+}  // namespace chromeos_update_manager
diff --git a/update_manager/real_shill_provider.cc b/update_manager/real_shill_provider.cc
new file mode 100644
index 0000000..b7a36d5
--- /dev/null
+++ b/update_manager/real_shill_provider.cc
@@ -0,0 +1,191 @@
+// Copyright (c) 2014 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "update_engine/update_manager/real_shill_provider.h"
+
+#include <string>
+
+#include <base/logging.h>
+#include <base/strings/stringprintf.h>
+#include <chromeos/dbus/service_constants.h>
+
+#include "update_engine/utils.h"
+
+using std::string;
+
+namespace {
+
+// Looks up a |key| in a GLib |hash_table| and returns the unboxed string from
+// the corresponding GValue, if found.
+const char* GetStrProperty(GHashTable* hash_table, const char* key) {
+  auto gval = reinterpret_cast<GValue*>(g_hash_table_lookup(hash_table, key));
+  return (gval ? g_value_get_string(gval) : NULL);
+}
+
+};  // namespace
+
+
+namespace chromeos_update_manager {
+
+RealShillProvider::~RealShillProvider() {
+  // Detach signal handler, free manager proxy.
+  dbus_->ProxyDisconnectSignal(manager_proxy_, shill::kMonitorPropertyChanged,
+                               G_CALLBACK(HandlePropertyChangedStatic),
+                               this);
+  dbus_->ProxyUnref(manager_proxy_);
+}
+
+ConnectionType RealShillProvider::ParseConnectionType(const char* type_str) {
+  if (!strcmp(type_str, shill::kTypeEthernet))
+    return ConnectionType::kEthernet;
+  if (!strcmp(type_str, shill::kTypeWifi))
+    return ConnectionType::kWifi;
+  if (!strcmp(type_str, shill::kTypeWimax))
+    return ConnectionType::kWimax;
+  if (!strcmp(type_str, shill::kTypeBluetooth))
+    return ConnectionType::kBluetooth;
+  if (!strcmp(type_str, shill::kTypeCellular))
+    return ConnectionType::kCellular;
+
+  return ConnectionType::kUnknown;
+}
+
+ConnectionTethering RealShillProvider::ParseConnectionTethering(
+    const char* tethering_str) {
+  if (!strcmp(tethering_str, shill::kTetheringNotDetectedState))
+    return ConnectionTethering::kNotDetected;
+  if (!strcmp(tethering_str, shill::kTetheringSuspectedState))
+    return ConnectionTethering::kSuspected;
+  if (!strcmp(tethering_str, shill::kTetheringConfirmedState))
+    return ConnectionTethering::kConfirmed;
+
+  return ConnectionTethering::kUnknown;
+}
+
+bool RealShillProvider::Init() {
+  // Obtain a DBus connection.
+  GError* error = NULL;
+  connection_ = dbus_->BusGet(DBUS_BUS_SYSTEM, &error);
+  if (!connection_) {
+    LOG(ERROR) << "Failed to initialize DBus connection: "
+               << chromeos_update_engine::utils::GetAndFreeGError(&error);
+    return false;
+  }
+
+  // Allocate a shill manager proxy.
+  manager_proxy_ = GetProxy(shill::kFlimflamServicePath,
+                            shill::kFlimflamManagerInterface);
+
+  // Subscribe to the manager's PropertyChanged signal.
+  dbus_->ProxyAddSignal_2(manager_proxy_, shill::kMonitorPropertyChanged,
+                          G_TYPE_STRING, G_TYPE_VALUE);
+  dbus_->ProxyConnectSignal(manager_proxy_, shill::kMonitorPropertyChanged,
+                            G_CALLBACK(HandlePropertyChangedStatic),
+                            this, NULL);
+
+  // Attempt to read initial connection status. Even if this fails because shill
+  // is not responding (e.g. it is down) we'll be notified via "PropertyChanged"
+  // signal as soon as it comes up, so this is not a critical step.
+  GHashTable* hash_table = NULL;
+  if (GetProperties(manager_proxy_, &hash_table)) {
+    GValue* value = reinterpret_cast<GValue*>(
+        g_hash_table_lookup(hash_table, shill::kDefaultServiceProperty));
+    ProcessDefaultService(value);
+    g_hash_table_unref(hash_table);
+  }
+
+  return true;
+}
+
+DBusGProxy* RealShillProvider::GetProxy(const char* path,
+                                        const char* interface) {
+  return dbus_->ProxyNewForName(connection_, shill::kFlimflamServiceName,
+                                path, interface);
+}
+
+bool RealShillProvider::GetProperties(DBusGProxy* proxy,
+                                      GHashTable** result_p) {
+  GError* error = NULL;
+  if (!dbus_->ProxyCall_0_1(proxy, shill::kGetPropertiesFunction, &error,
+                            result_p)) {
+    LOG(ERROR) << "Calling shill via DBus proxy failed: "
+               << chromeos_update_engine::utils::GetAndFreeGError(&error);
+    return false;
+  }
+  return true;
+}
+
+bool RealShillProvider::ProcessDefaultService(GValue* value) {
+  // Decode the string from the boxed value.
+  const char* default_service_path_str = NULL;
+  if (!(value && (default_service_path_str = g_value_get_string(value))))
+    return false;
+
+  // Anything changed?
+  if (default_service_path_ == default_service_path_str)
+    return true;
+
+  // Update the connection status.
+  default_service_path_ = default_service_path_str;
+  bool is_connected = (default_service_path_ != "/");
+  var_is_connected_.SetValue(is_connected);
+  var_conn_last_changed_.SetValue(clock_->GetWallclockTime());
+
+  // Update the connection attributes.
+  if (is_connected) {
+    DBusGProxy* service_proxy = GetProxy(default_service_path_.c_str(),
+                                         shill::kFlimflamServiceInterface);
+    GHashTable* hash_table = NULL;
+    if (GetProperties(service_proxy, &hash_table)) {
+      // Get the connection type.
+      const char* type_str = GetStrProperty(hash_table, shill::kTypeProperty);
+      if (type_str && !strcmp(type_str, shill::kTypeVPN)) {
+        type_str = GetStrProperty(hash_table,
+                                  shill::kPhysicalTechnologyProperty);
+      }
+      if (type_str) {
+        var_conn_type_.SetValue(ParseConnectionType(type_str));
+      } else {
+        var_conn_type_.UnsetValue();
+        LOG(ERROR) << "Could not find connection type ("
+                   << default_service_path_ << ")";
+      }
+
+      // Get the connection tethering mode.
+      const char* tethering_str = GetStrProperty(hash_table,
+                                                 shill::kTetheringProperty);
+      if (tethering_str) {
+        var_conn_tethering_.SetValue(ParseConnectionTethering(tethering_str));
+      } else {
+        var_conn_tethering_.UnsetValue();
+        LOG(ERROR) << "Could not find connection tethering mode ("
+                   << default_service_path_ << ")";
+      }
+
+      g_hash_table_unref(hash_table);
+    }
+    dbus_->ProxyUnref(service_proxy);
+  } else {
+    var_conn_type_.UnsetValue();
+    var_conn_tethering_.UnsetValue();
+  }
+
+  return true;
+}
+
+void RealShillProvider::HandlePropertyChanged(DBusGProxy* proxy,
+                                              const char* name, GValue* value) {
+  if (!strcmp(name, shill::kDefaultServiceProperty))
+    ProcessDefaultService(value);
+}
+
+void RealShillProvider::HandlePropertyChangedStatic(DBusGProxy* proxy,
+                                                    const char* name,
+                                                    GValue* value,
+                                                    void* data) {
+  auto obj = reinterpret_cast<RealShillProvider*>(data);
+  obj->HandlePropertyChanged(proxy, name, value);
+}
+
+}  // namespace chromeos_update_manager
diff --git a/update_manager/real_shill_provider.h b/update_manager/real_shill_provider.h
new file mode 100644
index 0000000..df4f622
--- /dev/null
+++ b/update_manager/real_shill_provider.h
@@ -0,0 +1,97 @@
+// Copyright (c) 2014 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROMEOS_PLATFORM_UPDATE_ENGINE_UPDATE_MANAGER_REAL_SHILL_PROVIDER_H_
+#define CHROMEOS_PLATFORM_UPDATE_ENGINE_UPDATE_MANAGER_REAL_SHILL_PROVIDER_H_
+
+// TODO(garnold) Much of the functionality in this module was adapted from the
+// update engine's connection_manager.  We need to make sure to deprecate use of
+// connection manager when the time comes.
+
+#include <string>
+
+#include <base/time/time.h>
+
+#include "update_engine/clock_interface.h"
+#include "update_engine/dbus_wrapper_interface.h"
+#include "update_engine/update_manager/generic_variables.h"
+#include "update_engine/update_manager/shill_provider.h"
+
+using chromeos_update_engine::ClockInterface;
+using chromeos_update_engine::DBusWrapperInterface;
+
+namespace chromeos_update_manager {
+
+// ShillProvider concrete implementation.
+class RealShillProvider : public ShillProvider {
+ public:
+  RealShillProvider(DBusWrapperInterface* dbus, ClockInterface* clock)
+      : dbus_(dbus), clock_(clock) {}
+
+  virtual ~RealShillProvider();
+
+  // Initializes the provider and returns whether it succeeded.
+  bool Init();
+
+  virtual Variable<bool>* var_is_connected() override {
+    return &var_is_connected_;
+  }
+
+  virtual Variable<ConnectionType>* var_conn_type() override {
+    return &var_conn_type_;
+  }
+
+  virtual Variable<ConnectionTethering>* var_conn_tethering() override {
+    return &var_conn_tethering_;
+  }
+
+  virtual Variable<base::Time>* var_conn_last_changed() override {
+    return &var_conn_last_changed_;
+  }
+
+  // Helper methods for converting shill strings into symbolic values.
+  static ConnectionType ParseConnectionType(const char* type_str);
+  static ConnectionTethering ParseConnectionTethering(
+      const char* tethering_str);
+
+ private:
+  // Return a DBus proxy for a given |path| and |interface| within shill.
+  DBusGProxy* GetProxy(const char* path, const char* interface);
+
+  // Issues a GetProperties call through a given |proxy|, storing the result to
+  // |*result_p|. Returns true on success.
+  bool GetProperties(DBusGProxy* proxy, GHashTable** result_p);
+
+  // Process a default connection value, update last change time as needed.
+  bool ProcessDefaultService(GValue* value);
+
+  // A handler for manager PropertyChanged signal, and a static version.
+  void HandlePropertyChanged(DBusGProxy* proxy, const char *name,
+                             GValue* value);
+  static void HandlePropertyChangedStatic(DBusGProxy* proxy, const char* name,
+                                          GValue* value, void* data);
+
+  // The current default service path, if connected.
+  std::string default_service_path_;
+
+  // The DBus interface (mockable), connection, and a shill manager proxy.
+  DBusWrapperInterface* const dbus_;
+  DBusGConnection* connection_ = NULL;
+  DBusGProxy* manager_proxy_ = NULL;
+
+  // A clock abstraction (mockable).
+  ClockInterface* const clock_;
+
+  // The provider's variables.
+  AsyncCopyVariable<bool> var_is_connected_{"is_connected"};
+  AsyncCopyVariable<ConnectionType> var_conn_type_{"conn_type"};
+  AsyncCopyVariable<ConnectionTethering> var_conn_tethering_{"conn_tethering"};
+  AsyncCopyVariable<base::Time> var_conn_last_changed_{"conn_last_changed"};
+
+  DISALLOW_COPY_AND_ASSIGN(RealShillProvider);
+};
+
+}  // namespace chromeos_update_manager
+
+#endif  // CHROMEOS_PLATFORM_UPDATE_ENGINE_UPDATE_MANAGER_REAL_SHILL_PROVIDER_H_
diff --git a/update_manager/real_shill_provider_unittest.cc b/update_manager/real_shill_provider_unittest.cc
new file mode 100644
index 0000000..faa6e05
--- /dev/null
+++ b/update_manager/real_shill_provider_unittest.cc
@@ -0,0 +1,540 @@
+// Copyright (c) 2014 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <utility>
+
+#include <base/memory/scoped_ptr.h>
+#include <base/time/time.h>
+#include <chromeos/dbus/service_constants.h>
+#include <glib.h>
+#include <gtest/gtest.h>
+
+#include "update_engine/fake_clock.h"
+#include "update_engine/mock_dbus_wrapper.h"
+#include "update_engine/test_utils.h"
+#include "update_engine/update_manager/real_shill_provider.h"
+#include "update_engine/update_manager/umtest_utils.h"
+
+using base::Time;
+using base::TimeDelta;
+using chromeos_update_engine::FakeClock;
+using chromeos_update_engine::GValueFree;
+using chromeos_update_engine::GValueNewString;
+using chromeos_update_engine::MockDBusWrapper;
+using std::pair;
+using testing::Eq;
+using testing::Mock;
+using testing::NiceMock;
+using testing::Return;
+using testing::SaveArg;
+using testing::SetArgPointee;
+using testing::StrEq;
+using testing::StrictMock;
+using testing::_;
+
+namespace {
+
+// Fake dbus-glib objects. These should be different values, to ease diagnosis
+// of errors.
+DBusGConnection* const kFakeConnection = reinterpret_cast<DBusGConnection*>(1);
+DBusGProxy* const kFakeManagerProxy = reinterpret_cast<DBusGProxy*>(2);
+DBusGProxy* const kFakeEthernetServiceProxy = reinterpret_cast<DBusGProxy*>(3);
+DBusGProxy* const kFakeWifiServiceProxy = reinterpret_cast<DBusGProxy*>(4);
+DBusGProxy* const kFakeWimaxServiceProxy = reinterpret_cast<DBusGProxy*>(5);
+DBusGProxy* const kFakeBluetoothServiceProxy = reinterpret_cast<DBusGProxy*>(6);
+DBusGProxy* const kFakeCellularServiceProxy = reinterpret_cast<DBusGProxy*>(7);
+DBusGProxy* const kFakeVpnServiceProxy = reinterpret_cast<DBusGProxy*>(8);
+DBusGProxy* const kFakeUnknownServiceProxy = reinterpret_cast<DBusGProxy*>(9);
+
+// Fake service paths.
+const char* const kFakeEthernetServicePath = "/fake-ethernet-service";
+const char* const kFakeWifiServicePath = "/fake-wifi-service";
+const char* const kFakeWimaxServicePath = "/fake-wimax-service";
+const char* const kFakeBluetoothServicePath = "/fake-bluetooth-service";
+const char* const kFakeCellularServicePath = "/fake-cellular-service";
+const char* const kFakeVpnServicePath = "/fake-vpn-service";
+const char* const kFakeUnknownServicePath = "/fake-unknown-service";
+
+}  // namespace
+
+namespace chromeos_update_manager {
+
+class UmRealShillProviderTest : public ::testing::Test {
+ protected:
+  virtual void SetUp() {
+    // By default, initialize the provider so that it gets an initial connection
+    // status from shill. This simulates the common case where shill is
+    // available and respoding during RealShillProvider initialization.
+    Init(true);
+  }
+
+  virtual void TearDown() {
+    Shutdown();
+  }
+
+  // Initialize the RealShillProvider under test. If |do_init_conn_status| is
+  // true, configure mocks to respond to the initial connection status check
+  // with shill. Otherwise, the initial check will fail.
+  void Init(bool do_init_conn_status) {
+    // Properly shutdown a previously initialized provider.
+    if (provider_.get())
+      Shutdown();
+
+    provider_.reset(new RealShillProvider(&mock_dbus_, &fake_clock_));
+    UMTEST_ASSERT_NOT_NULL(provider_.get());
+    fake_clock_.SetWallclockTime(InitTime());
+
+    // A DBus connection should only be obtained once.
+    EXPECT_CALL(mock_dbus_, BusGet(_, _)).WillOnce(
+        Return(kFakeConnection));
+
+    // A manager proxy should only be obtained once.
+    EXPECT_CALL(mock_dbus_, ProxyNewForName(
+            kFakeConnection, StrEq(shill::kFlimflamServiceName),
+            StrEq(shill::kFlimflamServicePath),
+            StrEq(shill::kFlimflamManagerInterface)))
+        .WillOnce(Return(kFakeManagerProxy));
+
+    // The PropertyChanged signal should be subscribed to.
+    EXPECT_CALL(mock_dbus_, ProxyAddSignal_2(
+            kFakeManagerProxy, StrEq(shill::kMonitorPropertyChanged),
+            G_TYPE_STRING, G_TYPE_VALUE))
+        .WillOnce(Return());
+    EXPECT_CALL(mock_dbus_, ProxyConnectSignal(
+            kFakeManagerProxy, StrEq(shill::kMonitorPropertyChanged),
+            _, _, _))
+        .WillOnce(
+            DoAll(SaveArg<2>(reinterpret_cast<void (**)()>(&signal_handler_)),
+                  SaveArg<3>(&signal_data_),
+                  Return()));
+
+    // Mock a response to an initial connection check (optional).
+    GHashTable* manager_properties = nullptr;
+    if (do_init_conn_status) {
+      pair<const char*, const char*> manager_pairs[] = {
+        {shill::kDefaultServiceProperty, "/"},
+      };
+      manager_properties = SetupGetPropertiesOkay(
+          kFakeManagerProxy, arraysize(manager_pairs), manager_pairs);
+    } else {
+      SetupGetPropertiesFail(kFakeManagerProxy);
+    }
+
+    // Check that provider initializes corrrectly.
+    ASSERT_TRUE(provider_->Init());
+
+    // All mocked calls should have been exercised by now.
+    Mock::VerifyAndClear(&mock_dbus_);
+
+    // Release properties hash table (if provided).
+    if (manager_properties)
+      g_hash_table_unref(manager_properties);
+  }
+
+  // Deletes the RealShillProvider under test.
+  void Shutdown() {
+    // Make sure that DBus resources get freed.
+    EXPECT_CALL(mock_dbus_, ProxyDisconnectSignal(
+            kFakeManagerProxy, StrEq(shill::kMonitorPropertyChanged),
+            Eq(reinterpret_cast<void (*)()>(signal_handler_)),
+            Eq(signal_data_)))
+        .WillOnce(Return());
+    EXPECT_CALL(mock_dbus_, ProxyUnref(kFakeManagerProxy)).WillOnce(Return());
+    provider_.reset();
+
+    // All mocked calls should have been exercised by now.
+    Mock::VerifyAndClear(&mock_dbus_);
+  }
+
+  // These methods generate fixed timestamps for use in faking the current time.
+  Time InitTime() {
+    Time::Exploded now_exp;
+    now_exp.year = 2014;
+    now_exp.month = 3;
+    now_exp.day_of_week = 2;
+    now_exp.day_of_month = 18;
+    now_exp.hour = 8;
+    now_exp.minute = 5;
+    now_exp.second = 33;
+    now_exp.millisecond = 675;
+    return Time::FromLocalExploded(now_exp);
+  }
+
+  Time ConnChangedTime() {
+    return InitTime() + TimeDelta::FromSeconds(10);
+  }
+
+  // Sets up a successful mock "GetProperties" call on |proxy|, writing a hash
+  // table containing |num_entries| entries formed by key/value pairs from
+  // |key_val_pairs| and returning true. Keys and values are plain C strings
+  // (const char*). The proxy call is expected to be made exactly once. Returns
+  // a pointer to a newly allocated hash table, which should be unreffed with
+  // g_hash_table_unref() when done.
+  GHashTable* SetupGetPropertiesOkay(
+      DBusGProxy* proxy, size_t num_entries,
+      pair<const char*, const char*>* key_val_pairs) {
+    // Allocate and populate the hash table.
+    GHashTable* properties = g_hash_table_new_full(g_str_hash, g_str_equal,
+                                                   free, GValueFree);
+    for (size_t i = 0; i < num_entries; i++) {
+      g_hash_table_insert(properties, strdup(key_val_pairs[i].first),
+                          GValueNewString(key_val_pairs[i].second));
+    }
+
+    // Set mock expectations.
+    EXPECT_CALL(mock_dbus_,
+                ProxyCall_0_1(proxy, StrEq(shill::kGetPropertiesFunction),
+                              _, _))
+        .WillOnce(DoAll(SetArgPointee<3>(g_hash_table_ref(properties)),
+                        Return(true)));
+
+    return properties;
+  }
+
+  // Sets up a failing mock "GetProperties" call on |proxy|, returning false.
+  // The proxy call is expected to be made exactly once.
+  void SetupGetPropertiesFail(DBusGProxy* proxy) {
+    EXPECT_CALL(mock_dbus_,
+                ProxyCall_0_1(proxy, StrEq(shill::kGetPropertiesFunction),
+                              _, _))
+      .WillOnce(Return(false));
+  }
+
+  // Sends a signal informing the provider about a default connection
+  // |service_path|. Returns the fake connection change time.
+  Time SendDefaultServiceSignal(const char* service_path) {
+    auto default_service_gval = GValueNewString(service_path);
+    const Time conn_change_time = ConnChangedTime();
+    fake_clock_.SetWallclockTime(conn_change_time);
+    signal_handler_(kFakeManagerProxy, shill::kDefaultServiceProperty,
+                    default_service_gval, signal_data_);
+    fake_clock_.SetWallclockTime(conn_change_time + TimeDelta::FromSeconds(5));
+    GValueFree(default_service_gval);
+    return conn_change_time;
+  }
+
+  // Sets up expectations for detection of a connection |service_path| with type
+  // |shill_type_str| and tethering mode |shill_tethering_str|. Ensures that the
+  // new connection status and change time are properly detected by the
+  // provider. Writes the fake connection change time to |conn_change_time_p|,
+  // if provided.
+  void SetupConnectionAndAttrs(const char* service_path,
+                               DBusGProxy* service_proxy,
+                               const char* shill_type_str,
+                               const char* shill_tethering_str,
+                               Time* conn_change_time_p) {
+    // Mock logic for querying the default service attributes.
+    EXPECT_CALL(mock_dbus_,
+                ProxyNewForName(
+                    kFakeConnection, StrEq(shill::kFlimflamServiceName),
+                    StrEq(service_path),
+                    StrEq(shill::kFlimflamServiceInterface)))
+        .WillOnce(Return(service_proxy));
+    EXPECT_CALL(mock_dbus_, ProxyUnref(service_proxy)).WillOnce(Return());
+    pair<const char*, const char*> service_pairs[] = {
+      {shill::kTypeProperty, shill_type_str},
+      {shill::kTetheringProperty, shill_tethering_str},
+    };
+    auto service_properties = SetupGetPropertiesOkay(
+        service_proxy, arraysize(service_pairs), service_pairs);
+
+    // Send a signal about a new default service.
+    auto conn_change_time = SendDefaultServiceSignal(service_path);
+
+    // Release the service properties hash tables.
+    g_hash_table_unref(service_properties);
+
+    // Query the connection status, ensure last change time reported correctly.
+    UmTestUtils::ExpectVariableHasValue(true, provider_->var_is_connected());
+    UmTestUtils::ExpectVariableHasValue(conn_change_time,
+                                        provider_->var_conn_last_changed());
+
+    // Write the connection change time to the output argument.
+    if (conn_change_time_p)
+      *conn_change_time_p = conn_change_time;
+  }
+
+  // Sets up a connection and tests that its type is being properly detected by
+  // the provider.
+  void SetupConnectionAndTestType(const char* service_path,
+                                  DBusGProxy* service_proxy,
+                                  const char* shill_type_str,
+                                  ConnectionType expected_conn_type) {
+    // Set up and test the connection, record the change time.
+    Time conn_change_time;
+    SetupConnectionAndAttrs(service_path, service_proxy, shill_type_str,
+                            shill::kTetheringNotDetectedState,
+                            &conn_change_time);
+
+    // Query the connection type, ensure last change time did not change.
+    UmTestUtils::ExpectVariableHasValue(expected_conn_type,
+                                        provider_->var_conn_type());
+    UmTestUtils::ExpectVariableHasValue(conn_change_time,
+                                        provider_->var_conn_last_changed());
+  }
+
+  // Sets up a connection and tests that its tethering mode is being properly
+  // detected by the provider.
+  void SetupConnectionAndTestTethering(
+      const char* service_path, DBusGProxy* service_proxy,
+      const char* shill_tethering_str,
+      ConnectionTethering expected_conn_tethering) {
+    // Set up and test the connection, record the change time.
+    Time conn_change_time;
+    SetupConnectionAndAttrs(service_path, service_proxy, shill::kTypeEthernet,
+                            shill_tethering_str, &conn_change_time);
+
+    // Query the connection tethering, ensure last change time did not change.
+    UmTestUtils::ExpectVariableHasValue(expected_conn_tethering,
+                                        provider_->var_conn_tethering());
+    UmTestUtils::ExpectVariableHasValue(conn_change_time,
+                                        provider_->var_conn_last_changed());
+  }
+
+  StrictMock<MockDBusWrapper> mock_dbus_;
+  FakeClock fake_clock_;
+  scoped_ptr<RealShillProvider> provider_;
+  void (*signal_handler_)(DBusGProxy*, const char*, GValue*, void*);
+  void* signal_data_;
+};
+
+// Query the connection status, type and time last changed, as they were set
+// during initialization (no signals).
+TEST_F(UmRealShillProviderTest, ReadBaseValues) {
+  // Query the provider variables.
+  UmTestUtils::ExpectVariableHasValue(false, provider_->var_is_connected());
+  UmTestUtils::ExpectVariableNotSet(provider_->var_conn_type());
+  UmTestUtils::ExpectVariableHasValue(InitTime(),
+                                      provider_->var_conn_last_changed());
+}
+
+// Test that Ethernet connection is identified correctly.
+TEST_F(UmRealShillProviderTest, ReadConnTypeEthernet) {
+  SetupConnectionAndTestType(kFakeEthernetServicePath,
+                             kFakeEthernetServiceProxy,
+                             shill::kTypeEthernet,
+                             ConnectionType::kEthernet);
+}
+
+// Test that Wifi connection is identified correctly.
+TEST_F(UmRealShillProviderTest, ReadConnTypeWifi) {
+  SetupConnectionAndTestType(kFakeWifiServicePath,
+                             kFakeWifiServiceProxy,
+                             shill::kTypeWifi,
+                             ConnectionType::kWifi);
+}
+
+// Test that Wimax connection is identified correctly.
+TEST_F(UmRealShillProviderTest, ReadConnTypeWimax) {
+  SetupConnectionAndTestType(kFakeWimaxServicePath,
+                             kFakeWimaxServiceProxy,
+                             shill::kTypeWimax,
+                             ConnectionType::kWimax);
+}
+
+// Test that Bluetooth connection is identified correctly.
+TEST_F(UmRealShillProviderTest, ReadConnTypeBluetooth) {
+  SetupConnectionAndTestType(kFakeBluetoothServicePath,
+                             kFakeBluetoothServiceProxy,
+                             shill::kTypeBluetooth,
+                             ConnectionType::kBluetooth);
+}
+
+// Test that Cellular connection is identified correctly.
+TEST_F(UmRealShillProviderTest, ReadConnTypeCellular) {
+  SetupConnectionAndTestType(kFakeCellularServicePath,
+                             kFakeCellularServiceProxy,
+                             shill::kTypeCellular,
+                             ConnectionType::kCellular);
+}
+
+// Test that an unknown connection is identified as such.
+TEST_F(UmRealShillProviderTest, ReadConnTypeUnknown) {
+  SetupConnectionAndTestType(kFakeUnknownServicePath,
+                             kFakeUnknownServiceProxy,
+                             "FooConnectionType",
+                             ConnectionType::kUnknown);
+}
+
+// Tests that VPN connection is identified correctly.
+TEST_F(UmRealShillProviderTest, ReadConnTypeVpn) {
+  // Mock logic for returning a default service path and its type.
+  EXPECT_CALL(mock_dbus_, ProxyNewForName(
+          kFakeConnection, StrEq(shill::kFlimflamServiceName),
+          StrEq(kFakeVpnServicePath), StrEq(shill::kFlimflamServiceInterface)))
+      .WillOnce(Return(kFakeVpnServiceProxy));
+  EXPECT_CALL(mock_dbus_, ProxyUnref(kFakeVpnServiceProxy)).WillOnce(Return());
+  pair<const char*, const char*> service_pairs[] = {
+    {shill::kTypeProperty, shill::kTypeVPN},
+    {shill::kPhysicalTechnologyProperty, shill::kTypeWifi},
+  };
+  auto service_properties = SetupGetPropertiesOkay(kFakeVpnServiceProxy,
+                                                   arraysize(service_pairs),
+                                                   service_pairs);
+
+  // Send a signal about a new default service.
+  Time conn_change_time = SendDefaultServiceSignal(kFakeVpnServicePath);
+
+  // Query the connection type, ensure last change time reported correctly.
+  UmTestUtils::ExpectVariableHasValue(ConnectionType::kWifi,
+                                      provider_->var_conn_type());
+  UmTestUtils::ExpectVariableHasValue(conn_change_time,
+                                      provider_->var_conn_last_changed());
+
+  // Release properties hash tables.
+  g_hash_table_unref(service_properties);
+}
+
+// Ensure that the connection type is properly cached in the provider through
+// subsequent variable readings.
+TEST_F(UmRealShillProviderTest, ConnTypeCacheUsed) {
+  SetupConnectionAndTestType(kFakeEthernetServicePath,
+                             kFakeEthernetServiceProxy,
+                             shill::kTypeEthernet,
+                             ConnectionType::kEthernet);
+
+  UmTestUtils::ExpectVariableHasValue(ConnectionType::kEthernet,
+                                      provider_->var_conn_type());
+}
+
+// Ensure that the cached connection type remains valid even when a default
+// connection signal occurs but the connection is not changed.
+TEST_F(UmRealShillProviderTest, ConnTypeCacheRemainsValid) {
+  SetupConnectionAndTestType(kFakeEthernetServicePath,
+                             kFakeEthernetServiceProxy,
+                             shill::kTypeEthernet,
+                             ConnectionType::kEthernet);
+
+  SendDefaultServiceSignal(kFakeEthernetServicePath);
+
+  UmTestUtils::ExpectVariableHasValue(ConnectionType::kEthernet,
+                                      provider_->var_conn_type());
+}
+
+// Ensure that the cached connection type is invalidated and re-read when the
+// default connection changes.
+TEST_F(UmRealShillProviderTest, ConnTypeCacheInvalidated) {
+  SetupConnectionAndTestType(kFakeEthernetServicePath,
+                             kFakeEthernetServiceProxy,
+                             shill::kTypeEthernet,
+                             ConnectionType::kEthernet);
+
+  SetupConnectionAndTestType(kFakeWifiServicePath,
+                             kFakeWifiServiceProxy,
+                             shill::kTypeWifi,
+                             ConnectionType::kWifi);
+}
+
+// Test that a non-tethering mode is identified correctly.
+TEST_F(UmRealShillProviderTest, ReadConnTetheringNotDetected) {
+  SetupConnectionAndTestTethering(kFakeWifiServicePath,
+                                  kFakeWifiServiceProxy,
+                                  shill::kTetheringNotDetectedState,
+                                  ConnectionTethering::kNotDetected);
+}
+
+// Test that a suspected tethering mode is identified correctly.
+TEST_F(UmRealShillProviderTest, ReadConnTetheringSuspected) {
+  SetupConnectionAndTestTethering(kFakeWifiServicePath,
+                                  kFakeWifiServiceProxy,
+                                  shill::kTetheringSuspectedState,
+                                  ConnectionTethering::kSuspected);
+}
+
+// Test that a confirmed tethering mode is identified correctly.
+TEST_F(UmRealShillProviderTest, ReadConnTetheringConfirmed) {
+  SetupConnectionAndTestTethering(kFakeWifiServicePath,
+                                  kFakeWifiServiceProxy,
+                                  shill::kTetheringConfirmedState,
+                                  ConnectionTethering::kConfirmed);
+}
+
+// Test that an unknown tethering mode is identified as such.
+TEST_F(UmRealShillProviderTest, ReadConnTetheringUnknown) {
+  SetupConnectionAndTestTethering(kFakeWifiServicePath,
+                                  kFakeWifiServiceProxy,
+                                  "FooConnTethering",
+                                  ConnectionTethering::kUnknown);
+}
+
+// Ensure that the connection tethering mode is properly cached in the provider.
+TEST_F(UmRealShillProviderTest, ConnTetheringCacheUsed) {
+  SetupConnectionAndTestTethering(kFakeEthernetServicePath,
+                                  kFakeEthernetServiceProxy,
+                                  shill::kTetheringNotDetectedState,
+                                  ConnectionTethering::kNotDetected);
+
+  UmTestUtils::ExpectVariableHasValue(ConnectionTethering::kNotDetected,
+                                      provider_->var_conn_tethering());
+}
+
+// Ensure that the cached connection tethering mode remains valid even when a
+// default connection signal occurs but the connection is not changed.
+TEST_F(UmRealShillProviderTest, ConnTetheringCacheRemainsValid) {
+  SetupConnectionAndTestTethering(kFakeEthernetServicePath,
+                                  kFakeEthernetServiceProxy,
+                                  shill::kTetheringNotDetectedState,
+                                  ConnectionTethering::kNotDetected);
+
+  SendDefaultServiceSignal(kFakeEthernetServicePath);
+
+  UmTestUtils::ExpectVariableHasValue(ConnectionTethering::kNotDetected,
+                                      provider_->var_conn_tethering());
+}
+
+// Ensure that the cached connection tethering mode is invalidated and re-read
+// when the default connection changes.
+TEST_F(UmRealShillProviderTest, ConnTetheringCacheInvalidated) {
+  SetupConnectionAndTestTethering(kFakeEthernetServicePath,
+                                  kFakeEthernetServiceProxy,
+                                  shill::kTetheringNotDetectedState,
+                                  ConnectionTethering::kNotDetected);
+
+  SetupConnectionAndTestTethering(kFakeWifiServicePath,
+                                  kFakeWifiServiceProxy,
+                                  shill::kTetheringConfirmedState,
+                                  ConnectionTethering::kConfirmed);
+}
+
+// Fake two DBus signals prompting a default connection change, but otherwise
+// give the same service path. Check connection status and the time it was last
+// changed, making sure that it is the time when the first signal was sent (and
+// not the second).
+TEST_F(UmRealShillProviderTest, ReadLastChangedTimeTwoSignals) {
+  // Send a default service signal twice, advancing the clock in between.
+  Time conn_change_time;
+  SetupConnectionAndAttrs(kFakeEthernetServicePath, kFakeEthernetServiceProxy,
+                          shill::kTypeEthernet,
+                          shill::kTetheringNotDetectedState, &conn_change_time);
+  SendDefaultServiceSignal(kFakeEthernetServicePath);
+
+  // Query the connection status, ensure last change time reported correctly.
+  UmTestUtils::ExpectVariableHasValue(true, provider_->var_is_connected());
+  UmTestUtils::ExpectVariableHasValue(conn_change_time,
+                                      provider_->var_conn_last_changed());
+}
+
+// Make sure that the provider initializes correctly even if shill is not
+// responding, that variables can be obtained, and that they all return a null
+// value (indicating that the underlying values were not set).
+TEST_F(UmRealShillProviderTest, NoInitConnStatusReadBaseValues) {
+  // Re-initialize the provider, no initial connection status response.
+  Init(false);
+  UmTestUtils::ExpectVariableNotSet(provider_->var_is_connected());
+  UmTestUtils::ExpectVariableNotSet(provider_->var_conn_type());
+  UmTestUtils::ExpectVariableNotSet(provider_->var_conn_last_changed());
+}
+
+// Test that, once a signal is received, the connection status and other info
+// can be read correctly.
+TEST_F(UmRealShillProviderTest, NoInitConnStatusReadConnTypeEthernet) {
+  // Re-initialize the provider, no initial connection status response.
+  Init(false);
+  SetupConnectionAndTestType(kFakeEthernetServicePath,
+                             kFakeEthernetServiceProxy,
+                             shill::kTypeEthernet,
+                             ConnectionType::kEthernet);
+}
+
+}  // namespace chromeos_update_manager
diff --git a/update_manager/real_state.h b/update_manager/real_state.h
new file mode 100644
index 0000000..0f74214
--- /dev/null
+++ b/update_manager/real_state.h
@@ -0,0 +1,70 @@
+// Copyright (c) 2014 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROMEOS_PLATFORM_UPDATE_ENGINE_UPDATE_MANAGER_REAL_STATE_H_
+#define CHROMEOS_PLATFORM_UPDATE_ENGINE_UPDATE_MANAGER_REAL_STATE_H_
+
+#include <base/memory/scoped_ptr.h>
+
+#include "update_engine/update_manager/state.h"
+
+namespace chromeos_update_manager {
+
+// State concrete implementation.
+class RealState : public State {
+ public:
+  virtual ~RealState() {}
+
+  RealState(ConfigProvider* config_provider,
+            DevicePolicyProvider* device_policy_provider,
+            RandomProvider* random_provider,
+            ShillProvider* shill_provider,
+            SystemProvider* system_provider,
+            TimeProvider* time_provider,
+            UpdaterProvider* updater_provider) :
+      config_provider_(config_provider),
+      device_policy_provider_(device_policy_provider),
+      random_provider_(random_provider),
+      shill_provider_(shill_provider),
+      system_provider_(system_provider),
+      time_provider_(time_provider),
+      updater_provider_(updater_provider) {}
+
+  // These methods return the given provider.
+  virtual ConfigProvider* config_provider() override {
+    return config_provider_.get();
+  }
+  virtual DevicePolicyProvider* device_policy_provider() override {
+    return device_policy_provider_.get();
+  }
+  virtual RandomProvider* random_provider() override {
+    return random_provider_.get();
+  }
+  virtual ShillProvider* shill_provider() override {
+    return shill_provider_.get();
+  }
+  virtual SystemProvider* system_provider() override {
+    return system_provider_.get();
+  }
+  virtual TimeProvider* time_provider() override {
+    return time_provider_.get();
+  }
+  virtual UpdaterProvider* updater_provider() override {
+    return updater_provider_.get();
+  }
+
+ private:
+  // Instances of the providers.
+  scoped_ptr<ConfigProvider> config_provider_;
+  scoped_ptr<DevicePolicyProvider> device_policy_provider_;
+  scoped_ptr<RandomProvider> random_provider_;
+  scoped_ptr<ShillProvider> shill_provider_;
+  scoped_ptr<SystemProvider> system_provider_;
+  scoped_ptr<TimeProvider> time_provider_;
+  scoped_ptr<UpdaterProvider> updater_provider_;
+};
+
+}  // namespace chromeos_update_manager
+
+#endif  // CHROMEOS_PLATFORM_UPDATE_ENGINE_UPDATE_MANAGER_REAL_STATE_H_
diff --git a/update_manager/real_system_provider.cc b/update_manager/real_system_provider.cc
new file mode 100644
index 0000000..c397027
--- /dev/null
+++ b/update_manager/real_system_provider.cc
@@ -0,0 +1,49 @@
+// Copyright (c) 2014 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "update_engine/update_manager/real_system_provider.h"
+
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <string>
+#include <vector>
+
+#include <base/logging.h>
+#include <base/strings/stringprintf.h>
+#include <base/time/time.h>
+#include <vboot/crossystem.h>
+
+#include "update_engine/update_manager/generic_variables.h"
+#include "update_engine/utils.h"
+
+using base::StringPrintf;
+using base::Time;
+using base::TimeDelta;
+using std::string;
+using std::vector;
+
+namespace chromeos_update_manager {
+
+bool RealSystemProvider::Init() {
+  var_is_normal_boot_mode_.reset(
+      new ConstCopyVariable<bool>("is_normal_boot_mode",
+                                  VbGetSystemPropertyInt("devsw_boot") != 0));
+
+  var_is_official_build_.reset(
+      new ConstCopyVariable<bool>("is_official_build",
+                                  VbGetSystemPropertyInt("debug_build") == 0));
+
+  var_is_oobe_complete_.reset(
+      new CallCopyVariable<bool>(
+          "is_oobe_complete",
+          base::Bind(&chromeos_update_engine::HardwareInterface::IsOOBEComplete,
+                     base::Unretained(hardware_), nullptr)));
+
+  return true;
+}
+
+}  // namespace chromeos_update_manager
diff --git a/update_manager/real_system_provider.h b/update_manager/real_system_provider.h
new file mode 100644
index 0000000..b4c401e
--- /dev/null
+++ b/update_manager/real_system_provider.h
@@ -0,0 +1,51 @@
+// Copyright (c) 2014 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROMEOS_PLATFORM_UPDATE_ENGINE_UPDATE_MANAGER_REAL_SYSTEM_PROVIDER_H_
+#define CHROMEOS_PLATFORM_UPDATE_ENGINE_UPDATE_MANAGER_REAL_SYSTEM_PROVIDER_H_
+
+#include <base/memory/scoped_ptr.h>
+
+#include <string>
+
+#include "update_engine/hardware_interface.h"
+#include "update_engine/update_manager/system_provider.h"
+
+namespace chromeos_update_manager {
+
+// SystemProvider concrete implementation.
+class RealSystemProvider : public SystemProvider {
+ public:
+  explicit RealSystemProvider(
+      chromeos_update_engine::HardwareInterface* hardware)
+      : hardware_(hardware) {}
+
+  // Initializes the provider and returns whether it succeeded.
+  bool Init();
+
+  virtual Variable<bool>* var_is_normal_boot_mode() override {
+    return var_is_normal_boot_mode_.get();
+  }
+
+  virtual Variable<bool>* var_is_official_build() override {
+    return var_is_official_build_.get();
+  }
+
+  virtual Variable<bool>* var_is_oobe_complete() override {
+    return var_is_oobe_complete_.get();
+  }
+
+ private:
+  scoped_ptr<Variable<bool>> var_is_normal_boot_mode_;
+  scoped_ptr<Variable<bool>> var_is_official_build_;
+  scoped_ptr<Variable<bool>> var_is_oobe_complete_;
+
+  chromeos_update_engine::HardwareInterface* hardware_;
+
+  DISALLOW_COPY_AND_ASSIGN(RealSystemProvider);
+};
+
+}  // namespace chromeos_update_manager
+
+#endif  // CHROMEOS_PLATFORM_UPDATE_ENGINE_UPDATE_MANAGER_REAL_SYSTEM_PROVIDER_H_
diff --git a/update_manager/real_system_provider_unittest.cc b/update_manager/real_system_provider_unittest.cc
new file mode 100644
index 0000000..d744671
--- /dev/null
+++ b/update_manager/real_system_provider_unittest.cc
@@ -0,0 +1,43 @@
+// Copyright (c) 2014 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "update_engine/update_manager/real_system_provider.h"
+
+#include <base/memory/scoped_ptr.h>
+#include <base/time/time.h>
+#include <gtest/gtest.h>
+
+#include "update_engine/fake_hardware.h"
+#include "update_engine/update_manager/umtest_utils.h"
+
+namespace chromeos_update_manager {
+
+class UmRealSystemProviderTest : public ::testing::Test {
+ protected:
+  virtual void SetUp() {
+    provider_.reset(new RealSystemProvider(&fake_hardware_));
+    EXPECT_TRUE(provider_->Init());
+  }
+
+  chromeos_update_engine::FakeHardware fake_hardware_;
+  scoped_ptr<RealSystemProvider> provider_;
+};
+
+TEST_F(UmRealSystemProviderTest, InitTest) {
+  UMTEST_EXPECT_NOT_NULL(provider_->var_is_normal_boot_mode());
+  UMTEST_EXPECT_NOT_NULL(provider_->var_is_official_build());
+  UMTEST_EXPECT_NOT_NULL(provider_->var_is_oobe_complete());
+}
+
+TEST_F(UmRealSystemProviderTest, IsOOBECompleteTrue) {
+  fake_hardware_.SetIsOOBEComplete(base::Time());
+  UmTestUtils::ExpectVariableHasValue(true, provider_->var_is_oobe_complete());
+}
+
+TEST_F(UmRealSystemProviderTest, IsOOBECompleteFalse) {
+  fake_hardware_.UnsetIsOOBEComplete();
+  UmTestUtils::ExpectVariableHasValue(false, provider_->var_is_oobe_complete());
+}
+
+}  // namespace chromeos_update_manager
diff --git a/update_manager/real_time_provider.cc b/update_manager/real_time_provider.cc
new file mode 100644
index 0000000..9067bdd
--- /dev/null
+++ b/update_manager/real_time_provider.cc
@@ -0,0 +1,69 @@
+// Copyright (c) 2014 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "update_engine/update_manager/real_time_provider.h"
+
+#include <base/time/time.h>
+
+#include "update_engine/clock_interface.h"
+
+using base::Time;
+using base::TimeDelta;
+using chromeos_update_engine::ClockInterface;
+using std::string;
+
+namespace chromeos_update_manager {
+
+// A variable returning the current date.
+class CurrDateVariable : public Variable<Time> {
+ public:
+  // TODO(garnold) Turn this into an async variable with the needed callback
+  // logic for when it value changes.
+  CurrDateVariable(const string& name, ClockInterface* clock)
+      : Variable<Time>(name, TimeDelta::FromHours(1)), clock_(clock) {}
+
+ protected:
+  virtual const Time* GetValue(base::TimeDelta /* timeout */,
+                               string* /* errmsg */) {
+    Time::Exploded now_exp;
+    clock_->GetWallclockTime().LocalExplode(&now_exp);
+    now_exp.hour = now_exp.minute = now_exp.second = now_exp.millisecond = 0;
+    return new Time(Time::FromLocalExploded(now_exp));
+  }
+
+ private:
+  ClockInterface* clock_;
+
+  DISALLOW_COPY_AND_ASSIGN(CurrDateVariable);
+};
+
+// A variable returning the current hour in local time.
+class CurrHourVariable : public Variable<int> {
+ public:
+  // TODO(garnold) Turn this into an async variable with the needed callback
+  // logic for when it value changes.
+  CurrHourVariable(const string& name, ClockInterface* clock)
+      : Variable<int>(name, TimeDelta::FromMinutes(5)), clock_(clock) {}
+
+ protected:
+  virtual const int* GetValue(base::TimeDelta /* timeout */,
+                              string* /* errmsg */) {
+    Time::Exploded exploded;
+    clock_->GetWallclockTime().LocalExplode(&exploded);
+    return new int(exploded.hour);
+  }
+
+ private:
+  ClockInterface* clock_;
+
+  DISALLOW_COPY_AND_ASSIGN(CurrHourVariable);
+};
+
+bool RealTimeProvider::Init() {
+  var_curr_date_.reset(new CurrDateVariable("curr_date", clock_));
+  var_curr_hour_.reset(new CurrHourVariable("curr_hour", clock_));
+  return true;
+}
+
+}  // namespace chromeos_update_manager
diff --git a/update_manager/real_time_provider.h b/update_manager/real_time_provider.h
new file mode 100644
index 0000000..ac60336
--- /dev/null
+++ b/update_manager/real_time_provider.h
@@ -0,0 +1,45 @@
+// Copyright (c) 2014 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROMEOS_PLATFORM_UPDATE_ENGINE_UPDATE_MANAGER_REAL_TIME_PROVIDER_H_
+#define CHROMEOS_PLATFORM_UPDATE_ENGINE_UPDATE_MANAGER_REAL_TIME_PROVIDER_H_
+
+#include <base/memory/scoped_ptr.h>
+#include <base/time/time.h>
+
+#include "update_engine/clock_interface.h"
+#include "update_engine/update_manager/time_provider.h"
+
+namespace chromeos_update_manager {
+
+// TimeProvider concrete implementation.
+class RealTimeProvider : public TimeProvider {
+ public:
+  explicit RealTimeProvider(chromeos_update_engine::ClockInterface* clock)
+      : clock_(clock) {}
+
+  // Initializes the provider and returns whether it succeeded.
+  bool Init();
+
+  virtual Variable<base::Time>* var_curr_date() override {
+    return var_curr_date_.get();
+  }
+
+  virtual Variable<int>* var_curr_hour() override {
+    return var_curr_hour_.get();
+  }
+
+ private:
+  // A clock abstraction (fakeable).
+  chromeos_update_engine::ClockInterface* const clock_;
+
+  scoped_ptr<Variable<base::Time>> var_curr_date_;
+  scoped_ptr<Variable<int>> var_curr_hour_;
+
+  DISALLOW_COPY_AND_ASSIGN(RealTimeProvider);
+};
+
+}  // namespace chromeos_update_manager
+
+#endif  // CHROMEOS_PLATFORM_UPDATE_ENGINE_UPDATE_MANAGER_REAL_TIME_PROVIDER_H_
diff --git a/update_manager/real_time_provider_unittest.cc b/update_manager/real_time_provider_unittest.cc
new file mode 100644
index 0000000..6b236db
--- /dev/null
+++ b/update_manager/real_time_provider_unittest.cc
@@ -0,0 +1,70 @@
+// Copyright (c) 2014 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <base/logging.h>
+#include <base/memory/scoped_ptr.h>
+#include <base/time/time.h>
+#include <gtest/gtest.h>
+
+#include "update_engine/fake_clock.h"
+#include "update_engine/update_manager/real_time_provider.h"
+#include "update_engine/update_manager/umtest_utils.h"
+
+using base::Time;
+using base::TimeDelta;
+using chromeos_update_engine::FakeClock;
+
+namespace chromeos_update_manager {
+
+class UmRealTimeProviderTest : public ::testing::Test {
+ protected:
+  virtual void SetUp() {
+    // The provider initializes correctly.
+    provider_.reset(new RealTimeProvider(&fake_clock_));
+    UMTEST_ASSERT_NOT_NULL(provider_.get());
+    ASSERT_TRUE(provider_->Init());
+  }
+
+  // Generates a fixed timestamp for use in faking the current time.
+  Time CurrTime() {
+    Time::Exploded now_exp;
+    now_exp.year = 2014;
+    now_exp.month = 3;
+    now_exp.day_of_week = 2;
+    now_exp.day_of_month = 18;
+    now_exp.hour = 8;
+    now_exp.minute = 5;
+    now_exp.second = 33;
+    now_exp.millisecond = 675;
+    return Time::FromLocalExploded(now_exp);
+  }
+
+  FakeClock fake_clock_;
+  scoped_ptr<RealTimeProvider> provider_;
+};
+
+TEST_F(UmRealTimeProviderTest, CurrDateValid) {
+  const Time now = CurrTime();
+  Time::Exploded exploded;
+  now.LocalExplode(&exploded);
+  exploded.hour = 0;
+  exploded.minute = 0;
+  exploded.second = 0;
+  exploded.millisecond = 0;
+  const Time expected = Time::FromLocalExploded(exploded);
+
+  fake_clock_.SetWallclockTime(now);
+  UmTestUtils::ExpectVariableHasValue(expected, provider_->var_curr_date());
+}
+
+TEST_F(UmRealTimeProviderTest, CurrHourValid) {
+  const Time now = CurrTime();
+  Time::Exploded expected;
+  now.LocalExplode(&expected);
+  fake_clock_.SetWallclockTime(now);
+  UmTestUtils::ExpectVariableHasValue(expected.hour,
+                                      provider_->var_curr_hour());
+}
+
+}  // namespace chromeos_update_manager
diff --git a/update_manager/real_updater_provider.cc b/update_manager/real_updater_provider.cc
new file mode 100644
index 0000000..7863019
--- /dev/null
+++ b/update_manager/real_updater_provider.cc
@@ -0,0 +1,358 @@
+// Copyright (c) 2014 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "update_engine/update_manager/real_updater_provider.h"
+
+#include <inttypes.h>
+
+#include <string>
+
+#include <base/strings/stringprintf.h>
+#include <base/time/time.h>
+#include <chromeos/dbus/service_constants.h>
+
+#include "update_engine/clock_interface.h"
+#include "update_engine/omaha_request_params.h"
+#include "update_engine/prefs.h"
+#include "update_engine/update_attempter.h"
+
+using base::StringPrintf;
+using base::Time;
+using base::TimeDelta;
+using chromeos_update_engine::OmahaRequestParams;
+using chromeos_update_engine::SystemState;
+using std::string;
+
+namespace chromeos_update_manager {
+
+// A templated base class for all update related variables. Provides uniform
+// construction and a system state handle.
+template<typename T>
+class UpdaterVariableBase : public Variable<T> {
+ public:
+  UpdaterVariableBase(const string& name, SystemState* system_state)
+      : Variable<T>(name, kVariableModePoll), system_state_(system_state) {}
+
+ protected:
+  // The system state used for pulling information from the updater.
+  inline SystemState* system_state() const { return system_state_; }
+
+ private:
+  SystemState* const system_state_;
+};
+
+// Helper class for issuing a GetStatus() to the UpdateAttempter.
+class GetStatusHelper {
+ public:
+  GetStatusHelper(SystemState* system_state, string* errmsg) {
+    is_success_ = system_state->update_attempter()->GetStatus(
+        &last_checked_time_, &progress_, &update_status_, &new_version_,
+        &payload_size_);
+    if (!is_success_ && errmsg)
+      *errmsg = "Failed to get a status update from the update engine";
+  }
+
+  inline bool is_success() { return is_success_; }
+  inline int64_t last_checked_time() { return last_checked_time_; }
+  inline double progress() { return progress_; }
+  inline const string& update_status() { return update_status_; }
+  inline const string& new_version() { return new_version_; }
+  inline int64_t payload_size() { return payload_size_; }
+
+ private:
+  bool is_success_;
+  int64_t last_checked_time_;
+  double progress_;
+  string update_status_;
+  string new_version_;
+  int64_t payload_size_;
+};
+
+// A variable reporting the time when a last update check was issued.
+class LastCheckedTimeVariable : public UpdaterVariableBase<Time> {
+ public:
+  using UpdaterVariableBase<Time>::UpdaterVariableBase;
+
+ private:
+  virtual const Time* GetValue(TimeDelta /* timeout */,
+                               string* errmsg) override {
+    GetStatusHelper raw(system_state(), errmsg);
+    if (!raw.is_success())
+      return NULL;
+
+    return new Time(Time::FromTimeT(raw.last_checked_time()));
+  }
+
+  DISALLOW_COPY_AND_ASSIGN(LastCheckedTimeVariable);
+};
+
+// A variable reporting the update (download) progress as a decimal fraction
+// between 0.0 and 1.0.
+class ProgressVariable : public UpdaterVariableBase<double> {
+ public:
+  using UpdaterVariableBase<double>::UpdaterVariableBase;
+
+ private:
+  virtual const double* GetValue(TimeDelta /* timeout */,
+                                 string* errmsg) override {
+    GetStatusHelper raw(system_state(), errmsg);
+    if (!raw.is_success())
+      return NULL;
+
+    if (raw.progress() < 0.0 || raw.progress() > 1.0) {
+      if (errmsg) {
+        *errmsg = StringPrintf("Invalid progress value received: %f",
+                               raw.progress());
+      }
+      return NULL;
+    }
+
+    return new double(raw.progress());
+  }
+
+  DISALLOW_COPY_AND_ASSIGN(ProgressVariable);
+};
+
+// A variable reporting the stage in which the update process is.
+class StageVariable : public UpdaterVariableBase<Stage> {
+ public:
+  using UpdaterVariableBase<Stage>::UpdaterVariableBase;
+
+ private:
+  struct CurrOpStrToStage {
+    const char* str;
+    Stage stage;
+  };
+  static const CurrOpStrToStage curr_op_str_to_stage[];
+
+  // Note: the method is defined outside the class so arraysize can work.
+  virtual const Stage* GetValue(TimeDelta /* timeout */,
+                                string* errmsg) override;
+
+  DISALLOW_COPY_AND_ASSIGN(StageVariable);
+};
+
+const StageVariable::CurrOpStrToStage StageVariable::curr_op_str_to_stage[] = {
+  {update_engine::kUpdateStatusIdle, Stage::kIdle},
+  {update_engine::kUpdateStatusCheckingForUpdate, Stage::kCheckingForUpdate},
+  {update_engine::kUpdateStatusUpdateAvailable, Stage::kUpdateAvailable},
+  {update_engine::kUpdateStatusDownloading, Stage::kDownloading},
+  {update_engine::kUpdateStatusVerifying, Stage::kVerifying},
+  {update_engine::kUpdateStatusFinalizing, Stage::kFinalizing},
+  {update_engine::kUpdateStatusUpdatedNeedReboot, Stage::kUpdatedNeedReboot},
+  {update_engine::kUpdateStatusReportingErrorEvent,
+   Stage::kReportingErrorEvent},
+  {update_engine::kUpdateStatusAttemptingRollback, Stage::kAttemptingRollback},
+};
+
+const Stage* StageVariable::GetValue(TimeDelta /* timeout */,
+                                     string* errmsg) {
+  GetStatusHelper raw(system_state(), errmsg);
+  if (!raw.is_success())
+    return NULL;
+
+  for (auto& key_val : curr_op_str_to_stage)
+    if (raw.update_status() == key_val.str)
+      return new Stage(key_val.stage);
+
+  if (errmsg)
+    *errmsg = string("Unknown update status: ") + raw.update_status();
+  return NULL;
+}
+
+// A variable reporting the version number that an update is updating to.
+class NewVersionVariable : public UpdaterVariableBase<string> {
+ public:
+  using UpdaterVariableBase<string>::UpdaterVariableBase;
+
+ private:
+  virtual const string* GetValue(TimeDelta /* timeout */,
+                                 string* errmsg) override {
+    GetStatusHelper raw(system_state(), errmsg);
+    if (!raw.is_success())
+      return NULL;
+
+    return new string(raw.new_version());
+  }
+
+  DISALLOW_COPY_AND_ASSIGN(NewVersionVariable);
+};
+
+// A variable reporting the size of the update being processed in bytes.
+class PayloadSizeVariable : public UpdaterVariableBase<int64_t> {
+ public:
+  using UpdaterVariableBase<int64_t>::UpdaterVariableBase;
+
+ private:
+  virtual const int64_t* GetValue(TimeDelta /* timeout */,
+                                 string* errmsg) override {
+    GetStatusHelper raw(system_state(), errmsg);
+    if (!raw.is_success())
+      return NULL;
+
+    if (raw.payload_size() < 0) {
+      if (errmsg)
+        *errmsg = string("Invalid payload size: %" PRId64, raw.payload_size());
+      return NULL;
+    }
+
+    return new int64_t(raw.payload_size());
+  }
+
+  DISALLOW_COPY_AND_ASSIGN(PayloadSizeVariable);
+};
+
+// A variable reporting the point in time an update last completed in the
+// current boot cycle.
+//
+// TODO(garnold) In general, both the current boottime and wallclock time
+// readings should come from the time provider and be moderated by the
+// evaluation context, so that they are uniform throughout the evaluation of a
+// policy request.
+class UpdateCompletedTimeVariable : public UpdaterVariableBase<Time> {
+ public:
+  using UpdaterVariableBase<Time>::UpdaterVariableBase;
+
+ private:
+  virtual const Time* GetValue(TimeDelta /* timeout */,
+                               string* errmsg) override {
+    Time update_boottime;
+    if (!system_state()->update_attempter()->GetBootTimeAtUpdate(
+            &update_boottime)) {
+      if (errmsg)
+        *errmsg = "Update completed time could not be read";
+      return NULL;
+    }
+
+    chromeos_update_engine::ClockInterface* clock = system_state()->clock();
+    Time curr_boottime = clock->GetBootTime();
+    if (curr_boottime < update_boottime) {
+      if (errmsg)
+        *errmsg = "Update completed time more recent than current time";
+      return NULL;
+    }
+    TimeDelta duration_since_update = curr_boottime - update_boottime;
+    return new Time(clock->GetWallclockTime() - duration_since_update);
+  }
+
+  DISALLOW_COPY_AND_ASSIGN(UpdateCompletedTimeVariable);
+};
+
+// Variables reporting the current image channel.
+class CurrChannelVariable : public UpdaterVariableBase<string> {
+ public:
+  using UpdaterVariableBase<string>::UpdaterVariableBase;
+
+ private:
+  virtual const string* GetValue(TimeDelta /* timeout */,
+                                 string* errmsg) override {
+    OmahaRequestParams* request_params = system_state()->request_params();
+    string channel = request_params->current_channel();
+    if (channel.empty()) {
+      if (errmsg)
+        *errmsg = "No current channel";
+      return NULL;
+    }
+    return new string(channel);
+  }
+
+  DISALLOW_COPY_AND_ASSIGN(CurrChannelVariable);
+};
+
+// Variables reporting the new image channel.
+class NewChannelVariable : public UpdaterVariableBase<string> {
+ public:
+  using UpdaterVariableBase<string>::UpdaterVariableBase;
+
+ private:
+  virtual const string* GetValue(TimeDelta /* timeout */,
+                                 string* errmsg) override {
+    OmahaRequestParams* request_params = system_state()->request_params();
+    string channel = request_params->target_channel();
+    if (channel.empty()) {
+      if (errmsg)
+        *errmsg = "No new channel";
+      return NULL;
+    }
+    return new string(channel);
+  }
+
+  DISALLOW_COPY_AND_ASSIGN(NewChannelVariable);
+};
+
+// A variable class for reading Boolean prefs values.
+class BooleanPrefVariable : public UpdaterVariableBase<bool> {
+ public:
+  BooleanPrefVariable(const string& name, SystemState* system_state,
+                      const char* key, bool default_val)
+      : UpdaterVariableBase<bool>(name, system_state),
+        key_(key), default_val_(default_val) {}
+
+ private:
+  virtual const bool* GetValue(TimeDelta /* timeout */,
+                               string* errmsg) override {
+    bool result = default_val_;
+    chromeos_update_engine::PrefsInterface* prefs = system_state()->prefs();
+    if (prefs && prefs->Exists(key_) && !prefs->GetBoolean(key_, &result)) {
+      if (errmsg)
+        *errmsg = string("Could not read boolean pref ") + key_;
+      return NULL;
+    }
+    return new bool(result);
+  }
+
+  // The Boolean preference key and default value.
+  const char* const key_;
+  const bool default_val_;
+
+  DISALLOW_COPY_AND_ASSIGN(BooleanPrefVariable);
+};
+
+// A variable returning the number of consecutive failed update checks.
+class ConsecutiveFailedUpdateChecksVariable :
+    public UpdaterVariableBase<unsigned int> {
+ public:
+  using UpdaterVariableBase<unsigned int>::UpdaterVariableBase;
+
+ private:
+  virtual const unsigned int* GetValue(TimeDelta /* timeout */,
+                                       string* /* errmsg */) override {
+    return new unsigned int(
+        system_state()->update_attempter()->consecutive_failed_update_checks());
+  }
+
+  DISALLOW_COPY_AND_ASSIGN(ConsecutiveFailedUpdateChecksVariable);
+};
+
+// RealUpdaterProvider methods.
+
+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_,
+                                chromeos_update_engine::kPrefsP2PEnabled,
+                                false)),
+    var_cellular_enabled_(
+        new BooleanPrefVariable(
+            "cellular_enabled", system_state_,
+            chromeos_update_engine::kPrefsUpdateOverCellularPermission,
+            false)),
+    var_consecutive_failed_update_checks_(
+        new ConsecutiveFailedUpdateChecksVariable(
+            "consecutive_failed_update_checks", system_state_)) {}
+
+}  // namespace chromeos_update_manager
diff --git a/update_manager/real_updater_provider.h b/update_manager/real_updater_provider.h
new file mode 100644
index 0000000..d7e3f06
--- /dev/null
+++ b/update_manager/real_updater_provider.h
@@ -0,0 +1,102 @@
+// Copyright (c) 2014 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROMEOS_PLATFORM_UPDATE_ENGINE_UPDATE_MANAGER_REAL_UPDATER_PROVIDER_H_
+#define CHROMEOS_PLATFORM_UPDATE_ENGINE_UPDATE_MANAGER_REAL_UPDATER_PROVIDER_H_
+
+#include <base/memory/scoped_ptr.h>
+
+#include "update_engine/system_state.h"
+#include "update_engine/update_manager/generic_variables.h"
+#include "update_engine/update_manager/updater_provider.h"
+
+namespace chromeos_update_manager {
+
+// A concrete UpdaterProvider implementation using local (in-process) bindings.
+class RealUpdaterProvider : public UpdaterProvider {
+ public:
+  // We assume that any other object handle we get from the system state is
+  // "volatile", and so must be re-acquired whenever access is needed; this
+  // guarantees that parts of the system state can be mocked out at any time
+  // during testing. We further assume that, by the time Init() is called, the
+  // system state object is fully populated and usable.
+  explicit RealUpdaterProvider(
+      chromeos_update_engine::SystemState* system_state);
+
+  // Initializes the provider and returns whether it succeeded.
+  bool Init() { return true; }
+
+  virtual Variable<base::Time>* var_updater_started_time() override {
+    return &var_updater_started_time_;
+  }
+
+  virtual Variable<base::Time>* var_last_checked_time() override {
+    return var_last_checked_time_.get();
+  }
+
+  virtual Variable<base::Time>* var_update_completed_time() override {
+    return var_update_completed_time_.get();
+  }
+
+  virtual Variable<double>* var_progress() override {
+    return var_progress_.get();
+  }
+
+  virtual Variable<Stage>* var_stage() override {
+    return var_stage_.get();
+  }
+
+  virtual Variable<std::string>* var_new_version() override {
+    return var_new_version_.get();
+  }
+
+  virtual Variable<int64_t>* var_payload_size() override {
+    return var_payload_size_.get();
+  }
+
+  virtual Variable<std::string>* var_curr_channel() override {
+    return var_curr_channel_.get();
+  }
+
+  virtual Variable<std::string>* var_new_channel() override {
+    return var_new_channel_.get();
+  }
+
+  virtual Variable<bool>* var_p2p_enabled() override {
+    return var_p2p_enabled_.get();
+  }
+
+  virtual Variable<bool>* var_cellular_enabled() override {
+    return var_cellular_enabled_.get();
+  }
+
+  virtual Variable<unsigned int>*
+      var_consecutive_failed_update_checks() override {
+    return var_consecutive_failed_update_checks_.get();
+  }
+
+ private:
+  // A pointer to the update engine's system state aggregator.
+  chromeos_update_engine::SystemState* system_state_;
+
+  // Variable implementations.
+  ConstCopyVariable<base::Time> var_updater_started_time_;
+  scoped_ptr<Variable<base::Time>> var_last_checked_time_;
+  scoped_ptr<Variable<base::Time>> var_update_completed_time_;
+  scoped_ptr<Variable<double>> var_progress_;
+  scoped_ptr<Variable<Stage>> var_stage_;
+  scoped_ptr<Variable<std::string>> var_new_version_;
+  scoped_ptr<Variable<int64_t>> var_payload_size_;
+  scoped_ptr<Variable<std::string>> var_curr_channel_;
+  scoped_ptr<Variable<std::string>> var_new_channel_;
+  scoped_ptr<Variable<bool>> var_p2p_enabled_;
+  scoped_ptr<Variable<bool>> var_cellular_enabled_;
+  scoped_ptr<Variable<unsigned int>> var_consecutive_failed_update_checks_;
+
+  DISALLOW_COPY_AND_ASSIGN(RealUpdaterProvider);
+};
+
+}  // namespace chromeos_update_manager
+
+#endif  // CHROMEOS_PLATFORM_UPDATE_ENGINE_UPDATE_MANAGER_REAL_UPDATER_PROVIDER_H_
diff --git a/update_manager/real_updater_provider_unittest.cc b/update_manager/real_updater_provider_unittest.cc
new file mode 100644
index 0000000..7bea777
--- /dev/null
+++ b/update_manager/real_updater_provider_unittest.cc
@@ -0,0 +1,457 @@
+// Copyright (c) 2014 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "update_engine/update_manager/real_updater_provider.h"
+
+#include <string>
+
+#include <base/memory/scoped_ptr.h>
+#include <base/time/time.h>
+#include <chromeos/dbus/service_constants.h>
+#include <gtest/gtest.h>
+
+#include "update_engine/fake_clock.h"
+#include "update_engine/fake_system_state.h"
+#include "update_engine/omaha_request_params.h"
+#include "update_engine/prefs_mock.h"
+#include "update_engine/update_attempter_mock.h"
+#include "update_engine/update_manager/umtest_utils.h"
+
+using base::Time;
+using base::TimeDelta;
+using chromeos_update_engine::FakeClock;
+using chromeos_update_engine::FakeSystemState;
+using chromeos_update_engine::OmahaRequestParams;
+using chromeos_update_engine::PrefsMock;
+using chromeos_update_engine::UpdateAttempterMock;
+using std::string;
+using testing::Return;
+using testing::SetArgPointee;
+using testing::StrEq;
+using testing::_;
+
+namespace {
+
+// Generates a fixed timestamp for use in faking the current time.
+Time FixedTime() {
+  Time::Exploded now_exp;
+  now_exp.year = 2014;
+  now_exp.month = 3;
+  now_exp.day_of_week = 2;
+  now_exp.day_of_month = 18;
+  now_exp.hour = 8;
+  now_exp.minute = 5;
+  now_exp.second = 33;
+  now_exp.millisecond = 675;
+  return Time::FromLocalExploded(now_exp);
+}
+
+// Rounds down a timestamp to the nearest second. This is useful when faking
+// times that are converted to time_t (no sub-second resolution).
+Time RoundedToSecond(Time time) {
+  Time::Exploded exp;
+  time.LocalExplode(&exp);
+  exp.millisecond = 0;
+  return Time::FromLocalExploded(exp);
+}
+
+}  // namespace
+
+namespace chromeos_update_manager {
+
+class UmRealUpdaterProviderTest : public ::testing::Test {
+ protected:
+  virtual void SetUp() {
+    fake_clock_ = fake_sys_state_.fake_clock();
+    provider_.reset(new RealUpdaterProvider(&fake_sys_state_));
+    UMTEST_ASSERT_NOT_NULL(provider_.get());
+    // Check that provider initializes corrrectly.
+    ASSERT_TRUE(provider_->Init());
+  }
+
+  // Sets up mock expectations for testing a variable that reads a Boolean pref
+  // |key|. |key_exists| determines whether the key is present. If it is, then
+  // |get_boolean_success| determines whether reading it is successful, and if
+  // so |output| is the value being read.
+  void SetupReadBooleanPref(const char* key, bool key_exists,
+                            bool get_boolean_success, bool output) {
+    PrefsMock* const mock_prefs = fake_sys_state_.mock_prefs();
+    EXPECT_CALL(*mock_prefs, Exists(StrEq(key))).WillOnce(Return(key_exists));
+    if (key_exists) {
+      auto& get_boolean = EXPECT_CALL(
+          *fake_sys_state_.mock_prefs(), GetBoolean(StrEq(key), _));
+      if (get_boolean_success)
+        get_boolean.WillOnce(DoAll(SetArgPointee<1>(output), Return(true)));
+      else
+        get_boolean.WillOnce(Return(false));
+    }
+  }
+
+  // Sets up mock expectations for testing the update completed time reporting.
+  // |valid| determines whether the returned time is valid. Returns the expected
+  // update completed time value.
+  Time SetupUpdateCompletedTime(bool valid) {
+    const TimeDelta kDurationSinceUpdate = TimeDelta::FromMinutes(7);
+    const Time kUpdateBootTime = Time() + kDurationSinceUpdate * 2;
+    const Time kCurrBootTime = (valid ?
+                                kUpdateBootTime + kDurationSinceUpdate :
+                                kUpdateBootTime - kDurationSinceUpdate);
+    const Time kCurrWallclockTime = FixedTime();
+    EXPECT_CALL(*fake_sys_state_.mock_update_attempter(),
+                GetBootTimeAtUpdate(_))
+        .WillOnce(DoAll(SetArgPointee<0>(kUpdateBootTime), Return(true)));
+    fake_clock_->SetBootTime(kCurrBootTime);
+    fake_clock_->SetWallclockTime(kCurrWallclockTime);
+    return kCurrWallclockTime - kDurationSinceUpdate;
+  }
+
+  FakeSystemState fake_sys_state_;
+  FakeClock* fake_clock_;  // Short for fake_sys_state_.fake_clock()
+  scoped_ptr<RealUpdaterProvider> provider_;
+};
+
+TEST_F(UmRealUpdaterProviderTest, UpdaterStartedTimeIsWallclockTime) {
+  fake_clock_->SetWallclockTime(Time::FromDoubleT(123.456));
+  fake_clock_->SetMonotonicTime(Time::FromDoubleT(456.123));
+  // Run SetUp again to re-setup the provider under test to use these values.
+  SetUp();
+  UmTestUtils::ExpectVariableHasValue(Time::FromDoubleT(123.456),
+                                      provider_->var_updater_started_time());
+}
+
+TEST_F(UmRealUpdaterProviderTest, GetLastCheckedTimeOkay) {
+  EXPECT_CALL(*fake_sys_state_.mock_update_attempter(),
+              GetStatus(_, _, _, _, _))
+      .WillOnce(DoAll(SetArgPointee<0>(FixedTime().ToTimeT()), Return(true)));
+  UmTestUtils::ExpectVariableHasValue(RoundedToSecond(FixedTime()),
+                                      provider_->var_last_checked_time());
+}
+
+TEST_F(UmRealUpdaterProviderTest, GetLastCheckedTimeFailNoValue) {
+  EXPECT_CALL(*fake_sys_state_.mock_update_attempter(),
+              GetStatus(_, _, _, _, _))
+      .WillOnce(Return(false));
+  UmTestUtils::ExpectVariableNotSet(provider_->var_last_checked_time());
+}
+
+TEST_F(UmRealUpdaterProviderTest, GetProgressOkayMin) {
+  EXPECT_CALL(*fake_sys_state_.mock_update_attempter(),
+              GetStatus(_, _, _, _, _))
+      .WillOnce(DoAll(SetArgPointee<1>(0.0), Return(true)));
+  UmTestUtils::ExpectVariableHasValue(0.0, provider_->var_progress());
+}
+
+TEST_F(UmRealUpdaterProviderTest, GetProgressOkayMid) {
+  EXPECT_CALL(*fake_sys_state_.mock_update_attempter(),
+              GetStatus(_, _, _, _, _))
+      .WillOnce(DoAll(SetArgPointee<1>(0.3), Return(true)));
+  UmTestUtils::ExpectVariableHasValue(0.3, provider_->var_progress());
+}
+
+TEST_F(UmRealUpdaterProviderTest, GetProgressOkayMax) {
+  EXPECT_CALL(*fake_sys_state_.mock_update_attempter(),
+              GetStatus(_, _, _, _, _))
+      .WillOnce(DoAll(SetArgPointee<1>(1.0), Return(true)));
+  UmTestUtils::ExpectVariableHasValue(1.0, provider_->var_progress());
+}
+
+TEST_F(UmRealUpdaterProviderTest, GetProgressFailNoValue) {
+  EXPECT_CALL(*fake_sys_state_.mock_update_attempter(),
+              GetStatus(_, _, _, _, _))
+      .WillOnce(Return(false));
+  UmTestUtils::ExpectVariableNotSet(provider_->var_progress());
+}
+
+TEST_F(UmRealUpdaterProviderTest, GetProgressFailTooSmall) {
+  EXPECT_CALL(*fake_sys_state_.mock_update_attempter(),
+              GetStatus(_, _, _, _, _))
+      .WillOnce(DoAll(SetArgPointee<1>(-2.0), Return(true)));
+  UmTestUtils::ExpectVariableNotSet(provider_->var_progress());
+}
+
+TEST_F(UmRealUpdaterProviderTest, GetProgressFailTooBig) {
+  EXPECT_CALL(*fake_sys_state_.mock_update_attempter(),
+              GetStatus(_, _, _, _, _))
+      .WillOnce(DoAll(SetArgPointee<1>(2.0), Return(true)));
+  UmTestUtils::ExpectVariableNotSet(provider_->var_progress());
+}
+
+TEST_F(UmRealUpdaterProviderTest, GetStageOkayIdle) {
+  EXPECT_CALL(*fake_sys_state_.mock_update_attempter(),
+              GetStatus(_, _, _, _, _))
+      .WillOnce(DoAll(SetArgPointee<2>(update_engine::kUpdateStatusIdle),
+                      Return(true)));
+  UmTestUtils::ExpectVariableHasValue(Stage::kIdle, provider_->var_stage());
+}
+
+TEST_F(UmRealUpdaterProviderTest, GetStageOkayCheckingForUpdate) {
+  EXPECT_CALL(*fake_sys_state_.mock_update_attempter(),
+              GetStatus(_, _, _, _, _))
+      .WillOnce(DoAll(
+              SetArgPointee<2>(update_engine::kUpdateStatusCheckingForUpdate),
+              Return(true)));
+  UmTestUtils::ExpectVariableHasValue(Stage::kCheckingForUpdate,
+                                      provider_->var_stage());
+}
+
+TEST_F(UmRealUpdaterProviderTest, GetStageOkayUpdateAvailable) {
+  EXPECT_CALL(*fake_sys_state_.mock_update_attempter(),
+              GetStatus(_, _, _, _, _))
+      .WillOnce(DoAll(
+              SetArgPointee<2>(update_engine::kUpdateStatusUpdateAvailable),
+              Return(true)));
+  UmTestUtils::ExpectVariableHasValue(Stage::kUpdateAvailable,
+                                      provider_->var_stage());
+}
+
+TEST_F(UmRealUpdaterProviderTest, GetStageOkayDownloading) {
+  EXPECT_CALL(*fake_sys_state_.mock_update_attempter(),
+              GetStatus(_, _, _, _, _))
+      .WillOnce(DoAll(SetArgPointee<2>(update_engine::kUpdateStatusDownloading),
+                      Return(true)));
+  UmTestUtils::ExpectVariableHasValue(Stage::kDownloading,
+                                      provider_->var_stage());
+}
+
+TEST_F(UmRealUpdaterProviderTest, GetStageOkayVerifying) {
+  EXPECT_CALL(*fake_sys_state_.mock_update_attempter(),
+              GetStatus(_, _, _, _, _))
+      .WillOnce(DoAll(SetArgPointee<2>(update_engine::kUpdateStatusVerifying),
+                      Return(true)));
+  UmTestUtils::ExpectVariableHasValue(Stage::kVerifying,
+                                      provider_->var_stage());
+}
+
+TEST_F(UmRealUpdaterProviderTest, GetStageOkayFinalizing) {
+  EXPECT_CALL(*fake_sys_state_.mock_update_attempter(),
+              GetStatus(_, _, _, _, _))
+      .WillOnce(DoAll(SetArgPointee<2>(update_engine::kUpdateStatusFinalizing),
+                      Return(true)));
+  UmTestUtils::ExpectVariableHasValue(Stage::kFinalizing,
+                                      provider_->var_stage());
+}
+
+TEST_F(UmRealUpdaterProviderTest, GetStageOkayUpdatedNeedReboot) {
+  EXPECT_CALL(*fake_sys_state_.mock_update_attempter(),
+              GetStatus(_, _, _, _, _))
+      .WillOnce(DoAll(
+              SetArgPointee<2>(update_engine::kUpdateStatusUpdatedNeedReboot),
+              Return(true)));
+  UmTestUtils::ExpectVariableHasValue(Stage::kUpdatedNeedReboot,
+                                      provider_->var_stage());
+}
+
+TEST_F(UmRealUpdaterProviderTest, GetStageOkayReportingErrorEvent) {
+  EXPECT_CALL(*fake_sys_state_.mock_update_attempter(),
+              GetStatus(_, _, _, _, _))
+      .WillOnce(DoAll(
+              SetArgPointee<2>(update_engine::kUpdateStatusReportingErrorEvent),
+              Return(true)));
+  UmTestUtils::ExpectVariableHasValue(Stage::kReportingErrorEvent,
+                                      provider_->var_stage());
+}
+
+TEST_F(UmRealUpdaterProviderTest, GetStageOkayAttemptingRollback) {
+  EXPECT_CALL(*fake_sys_state_.mock_update_attempter(),
+              GetStatus(_, _, _, _, _))
+      .WillOnce(DoAll(
+              SetArgPointee<2>(update_engine::kUpdateStatusAttemptingRollback),
+              Return(true)));
+  UmTestUtils::ExpectVariableHasValue(Stage::kAttemptingRollback,
+                                      provider_->var_stage());
+}
+
+TEST_F(UmRealUpdaterProviderTest, GetStageFailNoValue) {
+  EXPECT_CALL(*fake_sys_state_.mock_update_attempter(),
+              GetStatus(_, _, _, _, _))
+      .WillOnce(Return(false));
+  UmTestUtils::ExpectVariableNotSet(provider_->var_stage());
+}
+
+TEST_F(UmRealUpdaterProviderTest, GetStageFailUnknown) {
+  EXPECT_CALL(*fake_sys_state_.mock_update_attempter(),
+              GetStatus(_, _, _, _, _))
+      .WillOnce(DoAll(SetArgPointee<2>("FooUpdateEngineState"),
+                      Return(true)));
+  UmTestUtils::ExpectVariableNotSet(provider_->var_stage());
+}
+
+TEST_F(UmRealUpdaterProviderTest, GetStageFailEmpty) {
+  EXPECT_CALL(*fake_sys_state_.mock_update_attempter(),
+              GetStatus(_, _, _, _, _))
+      .WillOnce(DoAll(SetArgPointee<2>(""), Return(true)));
+  UmTestUtils::ExpectVariableNotSet(provider_->var_stage());
+}
+
+TEST_F(UmRealUpdaterProviderTest, GetNewVersionOkay) {
+  EXPECT_CALL(*fake_sys_state_.mock_update_attempter(),
+              GetStatus(_, _, _, _, _))
+      .WillOnce(DoAll(SetArgPointee<3>("1.2.0"), Return(true)));
+  UmTestUtils::ExpectVariableHasValue(string("1.2.0"),
+                                      provider_->var_new_version());
+}
+
+TEST_F(UmRealUpdaterProviderTest, GetNewVersionFailNoValue) {
+  EXPECT_CALL(*fake_sys_state_.mock_update_attempter(),
+              GetStatus(_, _, _, _, _))
+      .WillOnce(Return(false));
+  UmTestUtils::ExpectVariableNotSet(provider_->var_new_version());
+}
+
+TEST_F(UmRealUpdaterProviderTest, GetPayloadSizeOkayZero) {
+  EXPECT_CALL(*fake_sys_state_.mock_update_attempter(),
+              GetStatus(_, _, _, _, _))
+      .WillOnce(DoAll(SetArgPointee<4>(static_cast<int64_t>(0)), Return(true)));
+  UmTestUtils::ExpectVariableHasValue(static_cast<int64_t>(0),
+                                      provider_->var_payload_size());
+}
+
+TEST_F(UmRealUpdaterProviderTest, GetPayloadSizeOkayArbitrary) {
+  EXPECT_CALL(*fake_sys_state_.mock_update_attempter(),
+              GetStatus(_, _, _, _, _))
+      .WillOnce(DoAll(SetArgPointee<4>(static_cast<int64_t>(567890)),
+                      Return(true)));
+  UmTestUtils::ExpectVariableHasValue(static_cast<int64_t>(567890),
+                                      provider_->var_payload_size());
+}
+
+TEST_F(UmRealUpdaterProviderTest, GetPayloadSizeOkayTwoGigabytes) {
+  EXPECT_CALL(*fake_sys_state_.mock_update_attempter(),
+              GetStatus(_, _, _, _, _))
+      .WillOnce(DoAll(SetArgPointee<4>(static_cast<int64_t>(1) << 31),
+                      Return(true)));
+  UmTestUtils::ExpectVariableHasValue(static_cast<int64_t>(1) << 31,
+                                      provider_->var_payload_size());
+}
+
+TEST_F(UmRealUpdaterProviderTest, GetPayloadSizeFailNoValue) {
+  EXPECT_CALL(*fake_sys_state_.mock_update_attempter(),
+              GetStatus(_, _, _, _, _))
+      .WillOnce(Return(false));
+  UmTestUtils::ExpectVariableNotSet(provider_->var_payload_size());
+}
+
+TEST_F(UmRealUpdaterProviderTest, GetPayloadSizeFailNegative) {
+  EXPECT_CALL(*fake_sys_state_.mock_update_attempter(),
+              GetStatus(_, _, _, _, _))
+      .WillOnce(DoAll(SetArgPointee<4>(static_cast<int64_t>(-1024)),
+                      Return(true)));
+  UmTestUtils::ExpectVariableNotSet(provider_->var_payload_size());
+}
+
+TEST_F(UmRealUpdaterProviderTest, GetCurrChannelOkay) {
+  const string kChannelName("foo-channel");
+  OmahaRequestParams request_params(&fake_sys_state_);
+  request_params.Init("", "", false);
+  request_params.set_current_channel(kChannelName);
+  fake_sys_state_.set_request_params(&request_params);
+  UmTestUtils::ExpectVariableHasValue(kChannelName,
+                                      provider_->var_curr_channel());
+}
+
+TEST_F(UmRealUpdaterProviderTest, GetCurrChannelFailEmpty) {
+  OmahaRequestParams request_params(&fake_sys_state_);
+  request_params.Init("", "", false);
+  request_params.set_current_channel("");
+  fake_sys_state_.set_request_params(&request_params);
+  UmTestUtils::ExpectVariableNotSet(provider_->var_curr_channel());
+}
+
+TEST_F(UmRealUpdaterProviderTest, GetNewChannelOkay) {
+  const string kChannelName("foo-channel");
+  OmahaRequestParams request_params(&fake_sys_state_);
+  request_params.Init("", "", false);
+  request_params.set_target_channel(kChannelName);
+  fake_sys_state_.set_request_params(&request_params);
+  UmTestUtils::ExpectVariableHasValue(kChannelName,
+                                      provider_->var_new_channel());
+}
+
+TEST_F(UmRealUpdaterProviderTest, GetNewChannelFailEmpty) {
+  OmahaRequestParams request_params(&fake_sys_state_);
+  request_params.Init("", "", false);
+  request_params.set_target_channel("");
+  fake_sys_state_.set_request_params(&request_params);
+  UmTestUtils::ExpectVariableNotSet(provider_->var_new_channel());
+}
+
+TEST_F(UmRealUpdaterProviderTest, GetP2PEnabledOkayPrefDoesntExist) {
+  SetupReadBooleanPref(chromeos_update_engine::kPrefsP2PEnabled,
+                       false, false, false);
+  UmTestUtils::ExpectVariableHasValue(false, provider_->var_p2p_enabled());
+}
+
+TEST_F(UmRealUpdaterProviderTest, GetP2PEnabledOkayPrefReadsFalse) {
+  SetupReadBooleanPref(chromeos_update_engine::kPrefsP2PEnabled,
+                       true, true, false);
+  UmTestUtils::ExpectVariableHasValue(false, provider_->var_p2p_enabled());
+}
+
+TEST_F(UmRealUpdaterProviderTest, GetP2PEnabledOkayPrefReadsTrue) {
+  SetupReadBooleanPref(chromeos_update_engine::kPrefsP2PEnabled,
+                       true, true, true);
+  UmTestUtils::ExpectVariableHasValue(true, provider_->var_p2p_enabled());
+}
+
+TEST_F(UmRealUpdaterProviderTest, GetP2PEnabledFailCannotReadPref) {
+  SetupReadBooleanPref(chromeos_update_engine::kPrefsP2PEnabled,
+                       true, false, false);
+  UmTestUtils::ExpectVariableNotSet(provider_->var_p2p_enabled());
+}
+
+TEST_F(UmRealUpdaterProviderTest, GetCellularEnabledOkayPrefDoesntExist) {
+  SetupReadBooleanPref(
+      chromeos_update_engine::kPrefsUpdateOverCellularPermission,
+      false, false, false);
+  UmTestUtils::ExpectVariableHasValue(false, provider_->var_cellular_enabled());
+}
+
+TEST_F(UmRealUpdaterProviderTest, GetCellularEnabledOkayPrefReadsFalse) {
+  SetupReadBooleanPref(
+      chromeos_update_engine::kPrefsUpdateOverCellularPermission,
+      true, true, false);
+  UmTestUtils::ExpectVariableHasValue(false, provider_->var_cellular_enabled());
+}
+
+TEST_F(UmRealUpdaterProviderTest, GetCellularEnabledOkayPrefReadsTrue) {
+  SetupReadBooleanPref(
+      chromeos_update_engine::kPrefsUpdateOverCellularPermission,
+      true, true, true);
+  UmTestUtils::ExpectVariableHasValue(true, provider_->var_cellular_enabled());
+}
+
+TEST_F(UmRealUpdaterProviderTest, GetCellularEnabledFailCannotReadPref) {
+  SetupReadBooleanPref(
+      chromeos_update_engine::kPrefsUpdateOverCellularPermission,
+      true, false, false);
+  UmTestUtils::ExpectVariableNotSet(provider_->var_cellular_enabled());
+}
+
+TEST_F(UmRealUpdaterProviderTest, GetUpdateCompletedTimeOkay) {
+  Time expected = SetupUpdateCompletedTime(true);
+  UmTestUtils::ExpectVariableHasValue(expected,
+                                      provider_->var_update_completed_time());
+}
+
+TEST_F(UmRealUpdaterProviderTest, GetUpdateCompletedTimeFailNoValue) {
+  EXPECT_CALL(*fake_sys_state_.mock_update_attempter(), GetBootTimeAtUpdate(_))
+      .WillOnce(Return(false));
+  UmTestUtils::ExpectVariableNotSet(provider_->var_update_completed_time());
+}
+
+TEST_F(UmRealUpdaterProviderTest, GetUpdateCompletedTimeFailInvalidValue) {
+  SetupUpdateCompletedTime(false);
+  UmTestUtils::ExpectVariableNotSet(provider_->var_update_completed_time());
+}
+
+TEST_F(UmRealUpdaterProviderTest, GetConsecutiveFailedUpdateChecks) {
+  const unsigned int kNumFailedChecks = 3;
+  EXPECT_CALL(*fake_sys_state_.mock_update_attempter(),
+              consecutive_failed_update_checks())
+      .WillRepeatedly(Return(kNumFailedChecks));
+  UmTestUtils::ExpectVariableHasValue(
+      kNumFailedChecks, provider_->var_consecutive_failed_update_checks());
+}
+
+}  // namespace chromeos_update_manager
diff --git a/update_manager/shill_provider.h b/update_manager/shill_provider.h
new file mode 100644
index 0000000..51180fa
--- /dev/null
+++ b/update_manager/shill_provider.h
@@ -0,0 +1,60 @@
+// Copyright (c) 2014 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROMEOS_PLATFORM_UPDATE_ENGINE_UPDATE_MANAGER_SHILL_PROVIDER_H_
+#define CHROMEOS_PLATFORM_UPDATE_ENGINE_UPDATE_MANAGER_SHILL_PROVIDER_H_
+
+#include <base/time/time.h>
+
+#include "update_engine/update_manager/provider.h"
+#include "update_engine/update_manager/variable.h"
+
+namespace chromeos_update_manager {
+
+enum class ConnectionType {
+  kEthernet,
+  kWifi,
+  kWimax,
+  kBluetooth,
+  kCellular,
+  kUnknown
+};
+
+enum class ConnectionTethering {
+  kNotDetected,
+  kSuspected,
+  kConfirmed,
+  kUnknown,
+};
+
+// Provider for networking related information.
+class ShillProvider : public Provider {
+ public:
+  virtual ~ShillProvider() {}
+
+  // A variable returning whether we currently have network connectivity.
+  virtual Variable<bool>* var_is_connected() = 0;
+
+  // A variable returning the current network connection type. Unknown if not
+  // connected.
+  virtual Variable<ConnectionType>* var_conn_type() = 0;
+
+  // A variable returning the tethering mode of a network connection. Unknown if
+  // not connected.
+  virtual Variable<ConnectionTethering>* var_conn_tethering() = 0;
+
+  // A variable retruning the time when network connection last changed.
+  // Initialized to current time.
+  virtual Variable<base::Time>* var_conn_last_changed() = 0;
+
+ protected:
+  ShillProvider() {}
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(ShillProvider);
+};
+
+}  // namespace chromeos_update_manager
+
+#endif  // CHROMEOS_PLATFORM_UPDATE_ENGINE_UPDATE_MANAGER_SHILL_PROVIDER_H_
diff --git a/update_manager/state.h b/update_manager/state.h
new file mode 100644
index 0000000..0fe4116
--- /dev/null
+++ b/update_manager/state.h
@@ -0,0 +1,42 @@
+// Copyright (c) 2014 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROMEOS_PLATFORM_UPDATE_ENGINE_UPDATE_MANAGER_STATE_H_
+#define CHROMEOS_PLATFORM_UPDATE_ENGINE_UPDATE_MANAGER_STATE_H_
+
+#include "update_engine/update_manager/config_provider.h"
+#include "update_engine/update_manager/device_policy_provider.h"
+#include "update_engine/update_manager/random_provider.h"
+#include "update_engine/update_manager/shill_provider.h"
+#include "update_engine/update_manager/system_provider.h"
+#include "update_engine/update_manager/time_provider.h"
+#include "update_engine/update_manager/updater_provider.h"
+
+namespace chromeos_update_manager {
+
+// The State class is an interface to the ensemble of providers. This class
+// gives visibility of the state providers to policy implementations.
+class State {
+ public:
+  virtual ~State() {}
+
+  // These methods return the given provider.
+  virtual ConfigProvider* config_provider() = 0;
+  virtual DevicePolicyProvider* device_policy_provider() = 0;
+  virtual RandomProvider* random_provider() = 0;
+  virtual ShillProvider* shill_provider() = 0;
+  virtual SystemProvider* system_provider() = 0;
+  virtual TimeProvider* time_provider() = 0;
+  virtual UpdaterProvider* updater_provider() = 0;
+
+ protected:
+  State() {}
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(State);
+};
+
+}  // namespace chromeos_update_manager
+
+#endif  // CHROMEOS_PLATFORM_UPDATE_ENGINE_UPDATE_MANAGER_STATE_H_
diff --git a/update_manager/state_factory.cc b/update_manager/state_factory.cc
new file mode 100644
index 0000000..6aa1761
--- /dev/null
+++ b/update_manager/state_factory.cc
@@ -0,0 +1,59 @@
+// Copyright (c) 2014 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "update_engine/update_manager/state_factory.h"
+
+#include <base/logging.h>
+#include <base/memory/scoped_ptr.h>
+
+#include "update_engine/clock_interface.h"
+#include "update_engine/update_manager/real_config_provider.h"
+#include "update_engine/update_manager/real_device_policy_provider.h"
+#include "update_engine/update_manager/real_random_provider.h"
+#include "update_engine/update_manager/real_shill_provider.h"
+#include "update_engine/update_manager/real_state.h"
+#include "update_engine/update_manager/real_system_provider.h"
+#include "update_engine/update_manager/real_time_provider.h"
+#include "update_engine/update_manager/real_updater_provider.h"
+
+namespace chromeos_update_manager {
+
+State* DefaultStateFactory(policy::PolicyProvider* policy_provider,
+                           chromeos_update_engine::DBusWrapperInterface* dbus,
+                           chromeos_update_engine::SystemState* system_state) {
+  chromeos_update_engine::ClockInterface* const clock = system_state->clock();
+  scoped_ptr<RealConfigProvider> config_provider(
+      new RealConfigProvider(system_state->hardware()));
+  scoped_ptr<RealDevicePolicyProvider> device_policy_provider(
+      new RealDevicePolicyProvider(policy_provider));
+  scoped_ptr<RealRandomProvider> random_provider(new RealRandomProvider());
+  scoped_ptr<RealShillProvider> shill_provider(
+      new RealShillProvider(dbus, clock));
+  scoped_ptr<RealSystemProvider> system_provider(
+      new RealSystemProvider(system_state->hardware()));
+  scoped_ptr<RealTimeProvider> time_provider(new RealTimeProvider(clock));
+  scoped_ptr<RealUpdaterProvider> updater_provider(
+      new RealUpdaterProvider(system_state));
+
+  if (!(config_provider->Init() &&
+        device_policy_provider->Init() &&
+        random_provider->Init() &&
+        shill_provider->Init() &&
+        system_provider->Init() &&
+        time_provider->Init() &&
+        updater_provider->Init())) {
+    LOG(ERROR) << "Error initializing providers";
+    return NULL;
+  }
+
+  return new RealState(config_provider.release(),
+                       device_policy_provider.release(),
+                       random_provider.release(),
+                       shill_provider.release(),
+                       system_provider.release(),
+                       time_provider.release(),
+                       updater_provider.release());
+}
+
+}  // namespace chromeos_update_manager
diff --git a/update_manager/state_factory.h b/update_manager/state_factory.h
new file mode 100644
index 0000000..8e97554
--- /dev/null
+++ b/update_manager/state_factory.h
@@ -0,0 +1,26 @@
+// Copyright (c) 2014 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROMEOS_PLATFORM_UPDATE_ENGINE_UPDATE_MANAGER_STATE_FACTORY_H_
+#define CHROMEOS_PLATFORM_UPDATE_ENGINE_UPDATE_MANAGER_STATE_FACTORY_H_
+
+#include "update_engine/dbus_wrapper_interface.h"
+#include "update_engine/system_state.h"
+#include "update_engine/update_manager/state.h"
+
+namespace chromeos_update_manager {
+
+// Creates and initializes a new UpdateManager State instance containing real
+// providers instantiated using the passed interfaces. The State doesn't take
+// ownership of the passed interfaces, which need to remain available during the
+// life of this instance.  Returns null if one of the underlying providers fails
+// to initialize.
+State* DefaultStateFactory(
+    policy::PolicyProvider* policy_provider,
+    chromeos_update_engine::DBusWrapperInterface* dbus,
+    chromeos_update_engine::SystemState* system_state);
+
+}  // namespace chromeos_update_manager
+
+#endif  // CHROMEOS_PLATFORM_UPDATE_ENGINE_UPDATE_MANAGER_STATE_FACTORY_H_
diff --git a/update_manager/system_provider.h b/update_manager/system_provider.h
new file mode 100644
index 0000000..831f377
--- /dev/null
+++ b/update_manager/system_provider.h
@@ -0,0 +1,39 @@
+// Copyright (c) 2014 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROMEOS_PLATFORM_UPDATE_ENGINE_UPDATE_MANAGER_SYSTEM_PROVIDER_H_
+#define CHROMEOS_PLATFORM_UPDATE_ENGINE_UPDATE_MANAGER_SYSTEM_PROVIDER_H_
+
+#include "update_engine/update_manager/provider.h"
+#include "update_engine/update_manager/variable.h"
+
+namespace chromeos_update_manager {
+
+// Provider for system information, mostly constant, such as the information
+// reported by crossystem, the kernel boot command line and the partition table.
+class SystemProvider : public Provider {
+ public:
+  virtual ~SystemProvider() {}
+
+  // Returns true if the boot mode is normal or if it's unable to
+  // determine the boot mode. Returns false if the boot mode is
+  // developer.
+  virtual Variable<bool>* var_is_normal_boot_mode() = 0;
+
+  // Returns whether this is an official Chrome OS build.
+  virtual Variable<bool>* var_is_official_build() = 0;
+
+  // Returns a variable that tells whether OOBE was completed.
+  virtual Variable<bool>* var_is_oobe_complete() = 0;
+
+ protected:
+  SystemProvider() {}
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(SystemProvider);
+};
+
+}  // namespace chromeos_update_manager
+
+#endif  // CHROMEOS_PLATFORM_UPDATE_ENGINE_UPDATE_MANAGER_SYSTEM_PROVIDER_H_
diff --git a/update_manager/time_provider.h b/update_manager/time_provider.h
new file mode 100644
index 0000000..146d250
--- /dev/null
+++ b/update_manager/time_provider.h
@@ -0,0 +1,36 @@
+// Copyright (c) 2014 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROMEOS_PLATFORM_UPDATE_ENGINE_UPDATE_MANAGER_TIME_PROVIDER_H_
+#define CHROMEOS_PLATFORM_UPDATE_ENGINE_UPDATE_MANAGER_TIME_PROVIDER_H_
+
+#include <base/time/time.h>
+
+#include "update_engine/update_manager/provider.h"
+#include "update_engine/update_manager/variable.h"
+
+namespace chromeos_update_manager {
+
+// Provider for time related information.
+class TimeProvider : public Provider {
+ public:
+  virtual ~TimeProvider() {}
+
+  // Returns the current date. The time of day component will be zero.
+  virtual Variable<base::Time>* var_curr_date() = 0;
+
+  // Returns the current hour (0 to 23) in local time. The type is int to keep
+  // consistent with base::Time.
+  virtual Variable<int>* var_curr_hour() = 0;
+
+ protected:
+  TimeProvider() {}
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(TimeProvider);
+};
+
+}  // namespace chromeos_update_manager
+
+#endif  // CHROMEOS_PLATFORM_UPDATE_ENGINE_UPDATE_MANAGER_TIME_PROVIDER_H_
diff --git a/update_manager/umtest_utils.cc b/update_manager/umtest_utils.cc
new file mode 100644
index 0000000..41dc0a6
--- /dev/null
+++ b/update_manager/umtest_utils.cc
@@ -0,0 +1,17 @@
+// Copyright (c) 2014 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <base/time/time.h>
+
+#include "update_engine/update_manager/umtest_utils.h"
+
+namespace chromeos_update_manager {
+
+const unsigned UmTestUtils::kDefaultTimeoutInSeconds = 1;
+
+void PrintTo(const EvalStatus& status, ::std::ostream* os) {
+  *os << ToString(status);
+}
+
+}  // namespace chromeos_update_manager
diff --git a/update_manager/umtest_utils.h b/update_manager/umtest_utils.h
new file mode 100644
index 0000000..bd8da8c
--- /dev/null
+++ b/update_manager/umtest_utils.h
@@ -0,0 +1,70 @@
+// Copyright (c) 2014 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROMEOS_PLATFORM_UPDATE_ENGINE_UPDATE_MANAGER_UMTEST_UTILS_H_
+#define CHROMEOS_PLATFORM_UPDATE_ENGINE_UPDATE_MANAGER_UMTEST_UTILS_H_
+
+#include <iostream>
+
+#include <base/memory/scoped_ptr.h>
+#include <base/time/time.h>
+#include <gtest/gtest.h>
+
+#include "update_engine/update_manager/policy.h"
+#include "update_engine/update_manager/variable.h"
+
+// Convenience macros for checking null-ness of pointers.
+//
+// Purportedly, gtest should support pointer comparison when the first argument
+// is a pointer (e.g. NULL). It is therefore appropriate to use
+// {ASSERT,EXPECT}_{EQ,NE} for our purposes. However, gtest fails to realize
+// that NULL is a pointer when used with the _NE variants, unless we explicitly
+// cast it to a pointer type, and so we inject this casting.
+//
+// Note that checking nullness of the content of a scoped_ptr requires getting
+// the inner pointer value via get().
+#define UMTEST_ASSERT_NULL(p) ASSERT_EQ(NULL, p)
+#define UMTEST_ASSERT_NOT_NULL(p) ASSERT_NE(reinterpret_cast<void*>(NULL), p)
+#define UMTEST_EXPECT_NULL(p) EXPECT_EQ(NULL, p)
+#define UMTEST_EXPECT_NOT_NULL(p) EXPECT_NE(reinterpret_cast<void*>(NULL), p)
+
+
+namespace chromeos_update_manager {
+
+// A help class with common functionality for use in Update Manager testing.
+class UmTestUtils {
+ public:
+  // A default timeout to use when making various queries.
+  static const base::TimeDelta DefaultTimeout() {
+    return base::TimeDelta::FromSeconds(kDefaultTimeoutInSeconds);
+  }
+
+  // Calls GetValue on |variable| and expects its result to be |expected|.
+  template<typename T>
+  static void ExpectVariableHasValue(const T& expected, Variable<T>* variable) {
+    UMTEST_ASSERT_NOT_NULL(variable);
+    scoped_ptr<const T> value(variable->GetValue(DefaultTimeout(), nullptr));
+    UMTEST_ASSERT_NOT_NULL(value.get()) << "Variable: " << variable->GetName();
+    EXPECT_EQ(expected, *value) << "Variable: " << variable->GetName();
+  }
+
+  // Calls GetValue on |variable| and expects its result to be null.
+  template<typename T>
+  static void ExpectVariableNotSet(Variable<T>* variable) {
+    UMTEST_ASSERT_NOT_NULL(variable);
+    scoped_ptr<const T> value(variable->GetValue(DefaultTimeout(), nullptr));
+    UMTEST_EXPECT_NULL(value.get()) << "Variable: " << variable->GetName();
+  }
+
+ private:
+  static const unsigned kDefaultTimeoutInSeconds;
+};
+
+// PrintTo() functions are used by gtest to print these values. They need to be
+// defined on the same namespace where the type was defined.
+void PrintTo(const EvalStatus& status, ::std::ostream* os);
+
+}  // namespace chromeos_update_manager
+
+#endif  // CHROMEOS_PLATFORM_UPDATE_ENGINE_UPDATE_MANAGER_UMTEST_UTILS_H_
diff --git a/update_manager/update_manager-inl.h b/update_manager/update_manager-inl.h
new file mode 100644
index 0000000..1b1dc49
--- /dev/null
+++ b/update_manager/update_manager-inl.h
@@ -0,0 +1,111 @@
+// Copyright (c) 2014 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROMEOS_PLATFORM_UPDATE_ENGINE_UPDATE_MANAGER_UPDATE_MANAGER_INL_H_
+#define CHROMEOS_PLATFORM_UPDATE_ENGINE_UPDATE_MANAGER_UPDATE_MANAGER_INL_H_
+
+#include <string>
+
+#include <base/bind.h>
+
+#include "update_engine/update_manager/evaluation_context.h"
+#include "update_engine/update_manager/event_loop.h"
+
+namespace chromeos_update_manager {
+
+template<typename R, typename... Args>
+EvalStatus UpdateManager::EvaluatePolicy(
+    EvaluationContext* ec,
+    EvalStatus (Policy::*policy_method)(EvaluationContext*, State*,
+                                        std::string*, R*,
+                                        Args...) const,
+    R* result, Args... args) {
+  std::string error;
+
+  // First try calling the actual policy.
+  EvalStatus status = (policy_.get()->*policy_method)(ec, state_.get(), &error,
+                                                      result, args...);
+
+  if (status == EvalStatus::kFailed) {
+    LOG(WARNING) << "PolicyRequest() failed with error: " << error;
+    error.clear();
+    status = (default_policy_.*policy_method)(ec, state_.get(), &error,
+                                              result, args...);
+
+    if (status == EvalStatus::kFailed) {
+      LOG(WARNING) << "Request to DefaultPolicy also failed, passing error.";
+    }
+  }
+  // TODO(deymo): Log the actual state used from the EvaluationContext.
+  return status;
+}
+
+template<typename R, typename... Args>
+void UpdateManager::OnPolicyReadyToEvaluate(
+    scoped_refptr<EvaluationContext> ec,
+    base::Callback<void(EvalStatus status, const R& result)> callback,
+    EvalStatus (Policy::*policy_method)(EvaluationContext*, State*,
+                                        std::string*, R*,
+                                        Args...) const,
+    Args... args) {
+  ec->ResetEvaluation();
+  R result;
+  EvalStatus status = EvaluatePolicy(ec, policy_method, &result, args...);
+
+  if (status != EvalStatus::kAskMeAgainLater) {
+    // AsyncPolicyRequest finished.
+    callback.Run(status, result);
+    return;
+  }
+  // Re-schedule the policy request based on used variables.
+  base::Closure closure = base::Bind(
+      &UpdateManager::OnPolicyReadyToEvaluate<R, Args...>,
+      base::Unretained(this), ec, callback, policy_method, args...);
+
+  if (!ec->RunOnValueChangeOrTimeout(closure)) {
+    // The policy method didn't use any non-const variable nor there's any
+    // time-based event that will change the status of evaluation. We call the
+    // callback with EvalStatus::kAskMeAgainLater.
+    LOG(ERROR) << "Policy implementation didn't use any non-const variable "
+                  "but returned kAskMeAgainLater.";
+    callback.Run(EvalStatus::kAskMeAgainLater, result);
+    return;
+  }
+}
+
+template<typename R, typename... ActualArgs, typename... ExpectedArgs>
+EvalStatus UpdateManager::PolicyRequest(
+    EvalStatus (Policy::*policy_method)(EvaluationContext*, State*,
+                                        std::string*, R*,
+                                        ExpectedArgs...) const,
+    R* result, ActualArgs... args) {
+  scoped_refptr<EvaluationContext> ec(new EvaluationContext(clock_));
+  // A PolicyRequest allways consists on a single evaluation on a new
+  // EvaluationContext.
+  // IMPORTANT: To ensure that ActualArgs can be converted to ExpectedArgs, we
+  // explicitly instantiate EvaluatePolicy with the latter in lieu of the
+  // former.
+  return EvaluatePolicy<R, ExpectedArgs...>(ec, policy_method, result, args...);
+}
+
+template<typename R, typename... ActualArgs, typename... ExpectedArgs>
+void UpdateManager::AsyncPolicyRequest(
+    base::Callback<void(EvalStatus, const R& result)> callback,
+    EvalStatus (Policy::*policy_method)(EvaluationContext*, State*,
+                                        std::string*, R*,
+                                        ExpectedArgs...) const,
+    ActualArgs... args) {
+  scoped_refptr<EvaluationContext> ec = new EvaluationContext(clock_);
+  // IMPORTANT: To ensure that ActualArgs can be converted to ExpectedArgs, we
+  // explicitly instantiate UpdateManager::OnPolicyReadyToEvaluate with the
+  // latter in lieu of the former.
+  base::Closure closure = base::Bind(
+      &UpdateManager::OnPolicyReadyToEvaluate<R, ExpectedArgs...>,
+      base::Unretained(this), ec, callback, policy_method, args...);
+  RunFromMainLoop(closure);
+}
+
+}  // namespace chromeos_update_manager
+
+#endif  // CHROMEOS_PLATFORM_UPDATE_ENGINE_UPDATE_MANAGER_UPDATE_MANAGER_INL_H_
diff --git a/update_manager/update_manager.cc b/update_manager/update_manager.cc
new file mode 100644
index 0000000..d3281fd
--- /dev/null
+++ b/update_manager/update_manager.cc
@@ -0,0 +1,20 @@
+// Copyright (c) 2014 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "update_engine/update_manager/update_manager.h"
+
+#include "update_engine/update_manager/chromeos_policy.h"
+#include "update_engine/update_manager/state.h"
+
+namespace chromeos_update_manager {
+
+UpdateManager::UpdateManager(chromeos_update_engine::ClockInterface* clock,
+                             State* state)
+      : state_(state), clock_(clock) {
+  // TODO(deymo): Make it possible to replace this policy with a different
+  // implementation with a build-time flag.
+  policy_.reset(new ChromeOSPolicy());
+}
+
+}  // namespace chromeos_update_manager
diff --git a/update_manager/update_manager.conf.example b/update_manager/update_manager.conf.example
new file mode 100644
index 0000000..2d77974
--- /dev/null
+++ b/update_manager/update_manager.conf.example
@@ -0,0 +1,18 @@
+# Configuration file for the update-manager component of update_engine.
+#
+# Normally this file is loaded from /etc/update_manager.conf. If
+# running update_engine in developer mode (and only if running in
+# developer mode), we attempt to load
+#
+#  /mnt/stateful_partition/etc/update_manager.conf
+#
+# and use it if it exists. If it doesn't exist, we fall back to
+# /etc/update_manager.conf.
+#
+# Note: changes to this file are not automatically applied. Use the
+# command "restart update-engine" from a root shell to make your
+# changes take effect.
+
+# Set to true if the device supports the concept of OOBE
+# (Out-Of-the-Box-Experience), false if it doesn't.
+is_oobe_enabled=true
diff --git a/update_manager/update_manager.h b/update_manager/update_manager.h
new file mode 100644
index 0000000..b3dfc7f
--- /dev/null
+++ b/update_manager/update_manager.h
@@ -0,0 +1,131 @@
+// Copyright (c) 2014 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROMEOS_PLATFORM_UPDATE_ENGINE_UPDATE_MANAGER_UPDATE_MANAGER_H_
+#define CHROMEOS_PLATFORM_UPDATE_ENGINE_UPDATE_MANAGER_UPDATE_MANAGER_H_
+
+#include <base/callback.h>
+#include <base/memory/ref_counted.h>
+#include <base/memory/scoped_ptr.h>
+
+#include "update_engine/clock_interface.h"
+#include "update_engine/update_manager/default_policy.h"
+#include "update_engine/update_manager/policy.h"
+#include "update_engine/update_manager/state.h"
+
+namespace chromeos_update_manager {
+
+// The main Update Manager singleton class.
+class UpdateManager {
+ public:
+  // Creates the UpdateManager instance, assuming ownership on the provided
+  // |state|.
+  UpdateManager(chromeos_update_engine::ClockInterface* clock,
+                State* state);
+
+  virtual ~UpdateManager() {}
+
+  // PolicyRequest() evaluates the given policy with the provided arguments and
+  // returns the result. The |policy_method| is the pointer-to-method of the
+  // Policy class for the policy request to call. The UpdateManager will call
+  // this method on the right policy. The pointer |result| must not be NULL and
+  // the remaining |args| depend on the arguments required by the passed
+  // |policy_method|.
+  //
+  // When the policy request succeeds, the |result| is set and the method
+  // returns EvalStatus::kSucceeded, otherwise, the |result| may not be set.
+  // Also, if the policy implementation should block, this method returns
+  // immediately with EvalStatus::kAskMeAgainLater. In case of failure
+  // EvalStatus::kFailed is returned and the |error| message is set, which must
+  // not be NULL.
+  //
+  // An example call to this method is:
+  //   um.PolicyRequest(&Policy::SomePolicyMethod, &bool_result, arg1, arg2);
+  template<typename R, typename... ActualArgs, typename... ExpectedArgs>
+  EvalStatus PolicyRequest(
+      EvalStatus (Policy::*policy_method)(EvaluationContext*, State*,
+                                          std::string*, R*,
+                                          ExpectedArgs...) const,
+      R* result, ActualArgs...);
+
+  // Evaluates the given |policy_method| policy with the provided |args|
+  // arguments and calls the |callback| callback with the result when done.
+  //
+  // If the policy implementation should block, returning a
+  // EvalStatus::kAskMeAgainLater status the Update Manager will re-evaluate the
+  // policy until another status is returned. If the policy implementation based
+  // its return value solely on const variables, the callback will be called
+  // with the EvalStatus::kAskMeAgainLater status.
+  template<typename R, typename... ActualArgs, typename... ExpectedArgs>
+  void AsyncPolicyRequest(
+      base::Callback<void(EvalStatus, const R& result)> callback,
+      EvalStatus (Policy::*policy_method)(EvaluationContext*, State*,
+                                          std::string*, R*,
+                                          ExpectedArgs...) const,
+      ActualArgs... args);
+
+ protected:
+  // The UpdateManager receives ownership of the passed Policy instance.
+  void set_policy(const Policy* policy) {
+    policy_.reset(policy);
+  }
+
+  // State getter used for testing.
+  State* state() { return state_.get(); }
+
+ private:
+  FRIEND_TEST(UmUpdateManagerTest, PolicyRequestCallsPolicy);
+  FRIEND_TEST(UmUpdateManagerTest, PolicyRequestCallsDefaultOnError);
+  FRIEND_TEST(UmUpdateManagerTest, PolicyRequestDoesntBlock);
+  FRIEND_TEST(UmUpdateManagerTest, AsyncPolicyRequestDelaysEvaluation);
+
+  // EvaluatePolicy() evaluates the passed |policy_method| method on the current
+  // policy with the given |args| arguments. If the method fails, the default
+  // policy is used instead.
+  template<typename R, typename... Args>
+  EvalStatus EvaluatePolicy(
+      EvaluationContext* ec,
+      EvalStatus (Policy::*policy_method)(EvaluationContext*, State*,
+                                          std::string*, R*,
+                                          Args...) const,
+      R* result, Args... args);
+
+  // OnPolicyReadyToEvaluate() is called by the main loop when the evaluation
+  // of the given |policy_method| should be executed. If the evaluation finishes
+  // the |callback| callback is called passing the |result| and the |status|
+  // returned by the policy. If the evaluation returns an
+  // EvalStatus::kAskMeAgainLater state, the |callback| will NOT be called and
+  // the evaluation will be re-scheduled to be called later.
+  template<typename R, typename... Args>
+  void OnPolicyReadyToEvaluate(
+      scoped_refptr<EvaluationContext> ec,
+      base::Callback<void(EvalStatus status, const R& result)> callback,
+      EvalStatus (Policy::*policy_method)(EvaluationContext*, State*,
+                                          std::string*, R*,
+                                          Args...) const,
+      Args... args);
+
+  // The policy used by the UpdateManager. Note that since it is a const Policy,
+  // policy implementations are not allowed to persist state on this class.
+  scoped_ptr<const Policy> policy_;
+
+  // A safe default value to the current policy. This policy is used whenever
+  // a policy implementation fails with EvalStatus::kFailed.
+  const DefaultPolicy default_policy_;
+
+  // State Providers.
+  scoped_ptr<State> state_;
+
+  // Pointer to the mockable clock interface;
+  chromeos_update_engine::ClockInterface* clock_;
+
+  DISALLOW_COPY_AND_ASSIGN(UpdateManager);
+};
+
+}  // namespace chromeos_update_manager
+
+// Include the implementation of the template methods.
+#include "update_engine/update_manager/update_manager-inl.h"
+
+#endif  // CHROMEOS_PLATFORM_UPDATE_ENGINE_UPDATE_MANAGER_UPDATE_MANAGER_H_
diff --git a/update_manager/update_manager_unittest.cc b/update_manager/update_manager_unittest.cc
new file mode 100644
index 0000000..39427b3
--- /dev/null
+++ b/update_manager/update_manager_unittest.cc
@@ -0,0 +1,158 @@
+// Copyright (c) 2014 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <algorithm>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include <base/bind.h>
+#include <base/memory/scoped_ptr.h>
+#include <base/time/time.h>
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+#include "update_engine/fake_clock.h"
+#include "update_engine/test_utils.h"
+#include "update_engine/update_manager/default_policy.h"
+#include "update_engine/update_manager/fake_state.h"
+#include "update_engine/update_manager/mock_policy.h"
+#include "update_engine/update_manager/umtest_utils.h"
+#include "update_engine/update_manager/update_manager.h"
+
+using base::Bind;
+using base::Callback;
+using base::Time;
+using base::TimeDelta;
+using chromeos_update_engine::FakeClock;
+using std::pair;
+using std::string;
+using std::vector;
+using testing::Return;
+using testing::StrictMock;
+using testing::_;
+
+namespace {
+
+// Generates a fixed timestamp for use in faking the current time.
+Time FixedTime() {
+  Time::Exploded now_exp;
+  now_exp.year = 2014;
+  now_exp.month = 3;
+  now_exp.day_of_week = 2;
+  now_exp.day_of_month = 18;
+  now_exp.hour = 8;
+  now_exp.minute = 5;
+  now_exp.second = 33;
+  now_exp.millisecond = 675;
+  return Time::FromLocalExploded(now_exp);
+}
+
+}  // namespace
+
+namespace chromeos_update_manager {
+
+class UmUpdateManagerTest : public ::testing::Test {
+ protected:
+  virtual void SetUp() {
+    fake_state_ = new FakeState();
+    umut_.reset(new UpdateManager(&fake_clock_, fake_state_));
+  }
+
+  FakeState* fake_state_;  // Owned by the umut_.
+  FakeClock fake_clock_;
+  scoped_ptr<UpdateManager> umut_;
+};
+
+// The FailingPolicy implements a single method and make it always fail. This
+// class extends the DefaultPolicy class to allow extensions of the Policy
+// class without extending nor changing this test.
+class FailingPolicy : public DefaultPolicy {
+  virtual EvalStatus UpdateCheckAllowed(EvaluationContext* ec, State* state,
+                                        string* error,
+                                        UpdateCheckParams* result) const {
+    *error = "FailingPolicy failed.";
+    return EvalStatus::kFailed;
+  }
+};
+
+// The LazyPolicy always returns EvalStatus::kAskMeAgainLater.
+class LazyPolicy : public DefaultPolicy {
+  virtual EvalStatus UpdateCheckAllowed(EvaluationContext* ec, State* state,
+                                        string* error,
+                                        UpdateCheckParams* result) const {
+    return EvalStatus::kAskMeAgainLater;
+  }
+};
+
+// AccumulateCallsCallback() adds to the passed |acc| accumulator vector pairs
+// of EvalStatus and T instances. This allows to create a callback that keeps
+// track of when it is called and the arguments passed to it, to be used with
+// the UpdateManager::AsyncPolicyRequest().
+template<typename T>
+static void AccumulateCallsCallback(vector<pair<EvalStatus, T>>* acc,
+                                    EvalStatus status, const T& result) {
+  acc->push_back(std::make_pair(status, result));
+}
+
+// Tests that policy requests are completed successfully. It is important that
+// this tests cover all policy requests as defined in Policy.
+TEST_F(UmUpdateManagerTest, PolicyRequestCallUpdateCheckAllowed) {
+  UpdateCheckParams result;
+  EXPECT_EQ(EvalStatus::kSucceeded, umut_->PolicyRequest(
+      &Policy::UpdateCheckAllowed, &result));
+}
+
+TEST_F(UmUpdateManagerTest, PolicyRequestCallUpdateCanStart) {
+  const UpdateState update_state = {
+    FixedTime(), 1, TimeDelta::FromSeconds(15), TimeDelta::FromSeconds(60),
+    4, 2, 8
+  };
+  UpdateCanStartResult result;
+  EXPECT_EQ(EvalStatus::kSucceeded,
+            umut_->PolicyRequest(&Policy::UpdateCanStart, &result, true,
+                                 update_state));
+}
+
+TEST_F(UmUpdateManagerTest, PolicyRequestCallsDefaultOnError) {
+  umut_->set_policy(new FailingPolicy());
+
+  // Tests that the DefaultPolicy instance is called when the method fails,
+  // which will set this as true.
+  UpdateCheckParams result;
+  result.updates_enabled = false;
+  EvalStatus status = umut_->PolicyRequest(
+      &Policy::UpdateCheckAllowed, &result);
+  EXPECT_EQ(EvalStatus::kSucceeded, status);
+  EXPECT_TRUE(result.updates_enabled);
+}
+
+TEST_F(UmUpdateManagerTest, PolicyRequestDoesntBlock) {
+  UpdateCheckParams result;
+  umut_->set_policy(new LazyPolicy());
+
+  EvalStatus status = umut_->PolicyRequest(
+      &Policy::UpdateCheckAllowed, &result);
+  EXPECT_EQ(EvalStatus::kAskMeAgainLater, status);
+}
+
+TEST_F(UmUpdateManagerTest, AsyncPolicyRequestDelaysEvaluation) {
+  // To avoid differences in code execution order between an AsyncPolicyRequest
+  // call on a policy that returns AskMeAgainLater the first time and one that
+  // succeeds the first time, we ensure that the passed callback is called from
+  // the main loop in both cases even when we could evaluate it right now.
+  umut_->set_policy(new FailingPolicy());
+
+  vector<pair<EvalStatus, UpdateCheckParams>> calls;
+  Callback<void(EvalStatus, const UpdateCheckParams& result)> callback =
+      Bind(AccumulateCallsCallback<UpdateCheckParams>, &calls);
+
+  umut_->AsyncPolicyRequest(callback, &Policy::UpdateCheckAllowed);
+  // The callback should wait until we run the main loop for it to be executed.
+  EXPECT_EQ(0, calls.size());
+  chromeos_update_engine::RunGMainLoopMaxIterations(100);
+  EXPECT_EQ(1, calls.size());
+}
+
+}  // namespace chromeos_update_manager
diff --git a/update_manager/updater_provider.h b/update_manager/updater_provider.h
new file mode 100644
index 0000000..051ad3a
--- /dev/null
+++ b/update_manager/updater_provider.h
@@ -0,0 +1,91 @@
+// Copyright (c) 2014 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROMEOS_PLATFORM_UPDATE_ENGINE_UPDATE_MANAGER_UPDATER_PROVIDER_H_
+#define CHROMEOS_PLATFORM_UPDATE_ENGINE_UPDATE_MANAGER_UPDATER_PROVIDER_H_
+
+#include <string>
+
+#include <base/time/time.h>
+
+#include "update_engine/update_manager/provider.h"
+#include "update_engine/update_manager/variable.h"
+
+namespace chromeos_update_manager {
+
+enum class Stage {
+  kIdle,
+  kCheckingForUpdate,
+  kUpdateAvailable,
+  kDownloading,
+  kVerifying,
+  kFinalizing,
+  kUpdatedNeedReboot,
+  kReportingErrorEvent,
+  kAttemptingRollback,
+};
+
+// Provider for Chrome OS update related information.
+class UpdaterProvider : public Provider {
+ public:
+  virtual ~UpdaterProvider() {}
+
+  // A variable returning the timestamp when the update engine was started in
+  // wallclock time.
+  virtual Variable<base::Time>* var_updater_started_time() = 0;
+
+  // A variable returning the last update check time.
+  virtual Variable<base::Time>* var_last_checked_time() = 0;
+
+  // A variable reporting the time when an update was last completed in the
+  // current boot cycle. Returns an error if an update completed time could not
+  // be read (e.g. no update was completed in the current boot cycle) or is
+  // invalid.
+  //
+  // IMPORTANT: The time reported is not the wallclock time reading at the time
+  // of the update, rather it is the point in time when the update completed
+  // relative to the current wallclock time reading. Therefore, the gap between
+  // the reported value and the current wallclock time is guaranteed to be
+  // monotonically increasing.
+  virtual Variable<base::Time>* var_update_completed_time() = 0;
+
+  // A variable returning the update progress (0.0 to 1.0).
+  virtual Variable<double>* var_progress() = 0;
+
+  // A variable returning the current update status.
+  virtual Variable<Stage>* var_stage() = 0;
+
+  // A variable returning the update target version.
+  virtual Variable<std::string>* var_new_version() = 0;
+
+  // A variable returning the update payload size. The payload size is
+  // guaranteed to be non-negative.
+  virtual Variable<int64_t>* var_payload_size() = 0;
+
+  // A variable returning the current channel.
+  virtual Variable<std::string>* var_curr_channel() = 0;
+
+  // A variable returning the update target channel.
+  virtual Variable<std::string>* var_new_channel() = 0;
+
+  // A variable indicating whether user settings allow P2P updates.
+  virtual Variable<bool>* var_p2p_enabled() = 0;
+
+  // A variable indicating whether user settings allow updates over a cellular
+  // network.
+  virtual Variable<bool>* var_cellular_enabled() = 0;
+
+  // A variable returning the number of consecutive failed update checks.
+  virtual Variable<unsigned int>* var_consecutive_failed_update_checks() = 0;
+
+ protected:
+  UpdaterProvider() {}
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(UpdaterProvider);
+};
+
+}  // namespace chromeos_update_manager
+
+#endif  // CHROMEOS_PLATFORM_UPDATE_ENGINE_UPDATE_MANAGER_UPDATER_PROVIDER_H_
diff --git a/update_manager/variable.h b/update_manager/variable.h
new file mode 100644
index 0000000..3b77d0a
--- /dev/null
+++ b/update_manager/variable.h
@@ -0,0 +1,203 @@
+// Copyright (c) 2014 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROMEOS_PLATFORM_UPDATE_ENGINE_UPDATE_MANAGER_VARIABLE_H_
+#define CHROMEOS_PLATFORM_UPDATE_ENGINE_UPDATE_MANAGER_VARIABLE_H_
+
+#include <algorithm>
+#include <list>
+#include <string>
+
+#include <base/bind.h>
+#include <base/logging.h>
+#include <base/time/time.h>
+#include <gtest/gtest_prod.h>  // for FRIEND_TEST
+
+#include "update_engine/update_manager/event_loop.h"
+
+namespace chromeos_update_manager {
+
+// The VariableMode specifies important behavior of the variable in terms of
+// whether, how and when the value of the variable changes.
+enum VariableMode {
+  // Const variables never changes during the life of a policy request, so the
+  // EvaluationContext caches the value even between different evaluations of
+  // the same policy request.
+  kVariableModeConst,
+
+  // Poll variables, or synchronous variables, represent a variable with a value
+  // that can be queried at any time, but it is not known when the value
+  // changes on the source of information. In order to detect if the value of
+  // the variable changes, it has to be queried again.
+  kVariableModePoll,
+
+  // Async variables are able to produce a signal or callback whenever the
+  // value changes. This means that it's not required to poll the value to
+  // detect when it changes, instead, you should register an observer to get
+  // a notification when that happens.
+  kVariableModeAsync,
+};
+
+// This class is a base class with the common functionality that doesn't
+// deppend on the variable's type, implemented by all the variables.
+class BaseVariable {
+ public:
+  // Interface for observing changes on variable value.
+  class ObserverInterface {
+   public:
+    virtual ~ObserverInterface() {}
+
+    // Called when the value on the variable changes.
+    virtual void ValueChanged(BaseVariable* variable) = 0;
+  };
+
+  virtual ~BaseVariable() {
+    if (!observer_list_.empty()) {
+      LOG(WARNING) << "Variable " << name_ << " deleted with "
+                   << observer_list_.size() << " observers.";
+    }
+    DCHECK(observer_list_.empty()) << "Don't destroy the variable without "
+                                      "removing the observers.";
+  }
+
+  // Returns the variable name as a string.
+  const std::string& GetName() const {
+    return name_;
+  }
+
+  // Returns the variable mode.
+  VariableMode GetMode() const {
+    return mode_;
+  }
+
+  // For VariableModePoll variables, it returns the polling interval of this
+  // variable. In other case, it returns 0.
+  base::TimeDelta GetPollInterval() const {
+    return poll_interval_;
+  }
+
+  // Adds and removes observers for value changes on the variable. This only
+  // works for kVariableAsync variables since the other modes don't track value
+  // changes. Adding the same observer twice has no effect.
+  virtual void AddObserver(BaseVariable::ObserverInterface* observer) {
+    if (std::find(observer_list_.begin(), observer_list_.end(), observer) ==
+        observer_list_.end()) {
+      observer_list_.push_back(observer);
+    }
+  }
+
+  virtual void RemoveObserver(BaseVariable::ObserverInterface* observer) {
+    observer_list_.remove(observer);
+  }
+
+ protected:
+  // Creates a BaseVariable using the default polling interval (5 minutes).
+  BaseVariable(const std::string& name, VariableMode mode)
+      : BaseVariable(name, mode,
+                     base::TimeDelta::FromMinutes(kDefaultPollMinutes)) {}
+
+  // Creates a BaseVariable with mode kVariableModePoll and the provided
+  // polling interval.
+  BaseVariable(const std::string& name, base::TimeDelta poll_interval)
+      : BaseVariable(name, kVariableModePoll, poll_interval) {}
+
+  // Calls ValueChanged on all the observers.
+  void NotifyValueChanged() {
+    // Fire all the observer methods from the main loop as single call. In order
+    // to avoid scheduling these callbacks when it is not needed, we check
+    // first the list of observers.
+    if (!observer_list_.empty()) {
+        RunFromMainLoop(base::Bind(&BaseVariable::OnValueChangedNotification,
+                                  base::Unretained(this)));
+    }
+  }
+
+ private:
+  friend class UmEvaluationContextTest;
+  FRIEND_TEST(UmBaseVariableTest, RepeatedObserverTest);
+  FRIEND_TEST(UmBaseVariableTest, NotifyValueChangedTest);
+  FRIEND_TEST(UmBaseVariableTest, NotifyValueRemovesObserversTest);
+
+  BaseVariable(const std::string& name, VariableMode mode,
+               base::TimeDelta poll_interval)
+    : name_(name), mode_(mode),
+      poll_interval_(mode == kVariableModePoll ?
+                     poll_interval : base::TimeDelta()) {}
+
+  void OnValueChangedNotification() {
+    // A ValueChanged() method can change the list of observers, for example
+    // removing itself and invalidating the iterator, so we create a snapshot
+    // of the observers first. Also, to support the case when *another* observer
+    // is removed, we check for them.
+    std::list<BaseVariable::ObserverInterface*> observer_list_copy(
+        observer_list_);
+
+    for (auto& observer : observer_list_copy) {
+      if (std::find(observer_list_.begin(), observer_list_.end(), observer) !=
+          observer_list_.end()) {
+        observer->ValueChanged(this);
+      }
+    }
+  }
+
+  // The default PollInterval in minutes.
+  static constexpr int kDefaultPollMinutes = 5;
+
+  // The variable's name as a string.
+  const std::string name_;
+
+  // The variable's mode.
+  const VariableMode mode_;
+
+  // The variable's polling interval for VariableModePoll variable and 0 for
+  // other modes.
+  const base::TimeDelta poll_interval_;
+
+  // The list of value changes observers.
+  std::list<BaseVariable::ObserverInterface*> observer_list_;
+
+  DISALLOW_COPY_AND_ASSIGN(BaseVariable);
+};
+
+// Interface to an Update Manager variable of a given type. Implementation
+// internals are hidden as protected members, since policies should not be
+// using them directly.
+template<typename T>
+class Variable : public BaseVariable {
+ public:
+  virtual ~Variable() {}
+
+ protected:
+  // Only allow to get values through the EvaluationContext class and not
+  // directly from the variable.
+  friend class EvaluationContext;
+
+  // Needed to be able to verify variable contents during unit testing.
+  friend class UmTestUtils;
+  FRIEND_TEST(UmRealRandomProviderTest, GetRandomValues);
+
+  Variable(const std::string& name, VariableMode mode)
+      : BaseVariable(name, mode) {}
+
+  Variable(const std::string& name, const base::TimeDelta poll_interval)
+      : BaseVariable(name, poll_interval) {}
+
+  // Gets the current value of the variable. The current value is copied to a
+  // new object and returned. The caller of this method owns the object and
+  // should delete it.
+  //
+  // In case of and error getting the current value or the |timeout| timeout is
+  // exceeded, a NULL value is returned and the |errmsg| is set.
+  //
+  // The caller can pass a NULL value for |errmsg|, in which case the error
+  // message won't be set.
+  virtual const T* GetValue(base::TimeDelta timeout, std::string* errmsg) = 0;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(Variable);
+};
+
+}  // namespace chromeos_update_manager
+
+#endif  // CHROMEOS_PLATFORM_UPDATE_ENGINE_UPDATE_MANAGER_VARIABLE_H_
diff --git a/update_manager/variable_unittest.cc b/update_manager/variable_unittest.cc
new file mode 100644
index 0000000..09c7649
--- /dev/null
+++ b/update_manager/variable_unittest.cc
@@ -0,0 +1,158 @@
+// Copyright (c) 2014 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "update_engine/update_manager/variable.h"
+
+#include <vector>
+
+#include <gtest/gtest.h>
+
+#include "update_engine/test_utils.h"
+
+using base::TimeDelta;
+using chromeos_update_engine::RunGMainLoopMaxIterations;
+using std::string;
+using std::vector;
+
+namespace chromeos_update_manager {
+
+// Variable class that returns a value constructed with the default value.
+template <typename T>
+class DefaultVariable : public Variable<T> {
+ public:
+  DefaultVariable(const string& name, VariableMode mode)
+      : Variable<T>(name, mode) {}
+  DefaultVariable(const string& name, const TimeDelta& poll_interval)
+      : Variable<T>(name, poll_interval) {}
+  virtual ~DefaultVariable() {}
+
+ protected:
+  virtual const T* GetValue(TimeDelta /* timeout */,
+                            string* /* errmsg */) {
+    return new T();
+  }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(DefaultVariable);
+};
+
+TEST(UmBaseVariableTest, GetNameTest) {
+  DefaultVariable<int> var("var", kVariableModeConst);
+  EXPECT_EQ(var.GetName(), string("var"));
+}
+
+TEST(UmBaseVariableTest, GetModeTest) {
+  DefaultVariable<int> var("var", kVariableModeConst);
+  EXPECT_EQ(var.GetMode(), kVariableModeConst);
+  DefaultVariable<int> other_var("other_var", kVariableModePoll);
+  EXPECT_EQ(other_var.GetMode(), kVariableModePoll);
+}
+
+TEST(UmBaseVariableTest, DefaultPollIntervalTest) {
+  DefaultVariable<int> const_var("const_var", kVariableModeConst);
+  EXPECT_EQ(const_var.GetPollInterval(), TimeDelta());
+  DefaultVariable<int> poll_var("poll_var", kVariableModePoll);
+  EXPECT_EQ(poll_var.GetPollInterval(), TimeDelta::FromMinutes(5));
+}
+
+TEST(UmBaseVariableTest, GetPollIntervalTest) {
+  DefaultVariable<int> var("var", TimeDelta::FromMinutes(3));
+  EXPECT_EQ(var.GetMode(), kVariableModePoll);
+  EXPECT_EQ(var.GetPollInterval(), TimeDelta::FromMinutes(3));
+}
+
+class BaseVariableObserver : public BaseVariable::ObserverInterface {
+ public:
+  void ValueChanged(BaseVariable* variable) {
+    calls_.push_back(variable);
+  }
+
+  // List of called functions.
+  vector<BaseVariable*> calls_;
+};
+
+TEST(UmBaseVariableTest, RepeatedObserverTest) {
+  DefaultVariable<int> var("var", kVariableModeAsync);
+  BaseVariableObserver observer;
+  var.AddObserver(&observer);
+  EXPECT_EQ(var.observer_list_.size(), 1);
+  var.AddObserver(&observer);
+  EXPECT_EQ(var.observer_list_.size(), 1);
+  var.RemoveObserver(&observer);
+  EXPECT_EQ(var.observer_list_.size(), 0);
+  var.RemoveObserver(&observer);
+  EXPECT_EQ(var.observer_list_.size(), 0);
+}
+
+TEST(UmBaseVariableTest, NotifyValueChangedTest) {
+  DefaultVariable<int> var("var", kVariableModeAsync);
+  BaseVariableObserver observer1;
+  var.AddObserver(&observer1);
+  // Simulate a value change on the variable's implementation.
+  var.NotifyValueChanged();
+  ASSERT_EQ(0, observer1.calls_.size());
+  RunGMainLoopMaxIterations(100);
+
+  ASSERT_EQ(1, observer1.calls_.size());
+  // Check that the observer is called with the right argument.
+  EXPECT_EQ(&var, observer1.calls_[0]);
+
+  BaseVariableObserver observer2;
+  var.AddObserver(&observer2);
+  var.NotifyValueChanged();
+  RunGMainLoopMaxIterations(100);
+
+  // Check that all the observers are called.
+  EXPECT_EQ(2, observer1.calls_.size());
+  EXPECT_EQ(1, observer2.calls_.size());
+
+  var.RemoveObserver(&observer1);
+  var.RemoveObserver(&observer2);
+}
+
+class BaseVariableObserverRemover : public BaseVariable::ObserverInterface {
+ public:
+  BaseVariableObserverRemover() : calls_(0) {}
+
+  void ValueChanged(BaseVariable* variable) override {
+    for (auto& observer : remove_observers_) {
+      variable->RemoveObserver(observer);
+    }
+    calls_++;
+  }
+
+  void OnCallRemoveObserver(BaseVariable::ObserverInterface* observer) {
+    remove_observers_.push_back(observer);
+  }
+
+  int get_calls() { return calls_; }
+
+ private:
+  vector<BaseVariable::ObserverInterface*> remove_observers_;
+  int calls_;
+};
+
+// Tests that we can remove an observer from a Variable on the ValueChanged()
+// call to that observer.
+TEST(UmBaseVariableTest, NotifyValueRemovesObserversTest) {
+  DefaultVariable<int> var("var", kVariableModeAsync);
+  BaseVariableObserverRemover observer1;
+  BaseVariableObserverRemover observer2;
+
+  var.AddObserver(&observer1);
+  var.AddObserver(&observer2);
+
+  // Make each observer remove both observers on ValueChanged.
+  observer1.OnCallRemoveObserver(&observer1);
+  observer1.OnCallRemoveObserver(&observer2);
+  observer2.OnCallRemoveObserver(&observer1);
+  observer2.OnCallRemoveObserver(&observer2);
+
+  var.NotifyValueChanged();
+  RunGMainLoopMaxIterations(100);
+
+  EXPECT_EQ(1, observer1.get_calls() + observer2.get_calls());
+}
+
+}  // namespace chromeos_update_manager