PM: Add an update engine provider.

The UpdaterProvider exports variables for querying the status of an
update process and related settings. Includes a concrete implementation
(RealUpdaterProvider), which currently links directly with update engine
code and pulls information through the SystemState object.  Also
included is a fake implementation (FakeUpdaterProvider) for testing
purposes.

BUG=chromium:346914
TEST=Unit tests.

Change-Id: I6ed5b40f21e43537e78aebf4217d811e149f745b
Reviewed-on: https://chromium-review.googlesource.com/192232
Reviewed-by: Gilad Arnold <garnold@chromium.org>
Commit-Queue: Gilad Arnold <garnold@chromium.org>
Tested-by: Gilad Arnold <garnold@chromium.org>
diff --git a/policy_manager/fake_state.cc b/policy_manager/fake_state.cc
index 4f4c787..0f0b5f1 100644
--- a/policy_manager/fake_state.cc
+++ b/policy_manager/fake_state.cc
@@ -11,7 +11,8 @@
 FakeState::FakeState() : State(new FakeRandomProvider(),
                                new FakeShillProvider(),
                                new FakeSystemProvider(),
-                               new FakeTimeProvider()) {
+                               new FakeTimeProvider(),
+                               new FakeUpdaterProvider()) {
 }
 
 FakeState* FakeState::Construct() {
@@ -19,7 +20,8 @@
   if (!(fake_state->random_provider()->Init() &&
         fake_state->shill_provider()->Init() &&
         fake_state->system_provider()->Init() &&
-        fake_state->time_provider()->Init())) {
+        fake_state->time_provider()->Init() &&
+        fake_state->updater_provider()->Init())) {
     return NULL;
   }
   return fake_state.release();
diff --git a/policy_manager/fake_state.h b/policy_manager/fake_state.h
index 2d5b9c9..4e4ead6 100644
--- a/policy_manager/fake_state.h
+++ b/policy_manager/fake_state.h
@@ -9,6 +9,7 @@
 #include "update_engine/policy_manager/fake_shill_provider.h"
 #include "update_engine/policy_manager/fake_system_provider.h"
 #include "update_engine/policy_manager/fake_time_provider.h"
+#include "update_engine/policy_manager/fake_updater_provider.h"
 #include "update_engine/policy_manager/state.h"
 
 namespace chromeos_policy_manager {
@@ -26,14 +27,21 @@
   virtual FakeRandomProvider* random_provider() override {
     return reinterpret_cast<FakeRandomProvider*>(State::random_provider());
   }
+
   virtual FakeShillProvider* shill_provider() override {
     return reinterpret_cast<FakeShillProvider*>(State::shill_provider());
   }
+
+  virtual FakeSystemProvider* system_provider() override {
+    return reinterpret_cast<FakeSystemProvider*>(State::system_provider());
+  }
+
   virtual FakeTimeProvider* time_provider() override {
     return reinterpret_cast<FakeTimeProvider*>(State::time_provider());
   }
-  virtual FakeSystemProvider* system_provider() override {
-    return reinterpret_cast<FakeSystemProvider*>(State::system_provider());
+
+  virtual FakeUpdaterProvider* updater_provider() override {
+    return reinterpret_cast<FakeUpdaterProvider*>(State::updater_provider());
   }
 
  private:
diff --git a/policy_manager/fake_updater_provider.h b/policy_manager/fake_updater_provider.h
new file mode 100644
index 0000000..d208574
--- /dev/null
+++ b/policy_manager/fake_updater_provider.h
@@ -0,0 +1,82 @@
+// 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_POLICY_MANAGER_FAKE_UPDATER_PROVIDER_H_
+#define CHROMEOS_PLATFORM_UPDATE_ENGINE_POLICY_MANAGER_FAKE_UPDATER_PROVIDER_H_
+
+#include "update_engine/policy_manager/fake_variable.h"
+#include "update_engine/policy_manager/updater_provider.h"
+
+namespace chromeos_policy_manager {
+
+// Fake implementation of the UpdaterProvider base class.
+class FakeUpdaterProvider : public UpdaterProvider {
+ public:
+  FakeUpdaterProvider() {}
+
+  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<size_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_;
+  }
+
+ protected:
+  virtual bool DoInit() { return true; }
+
+ private:
+  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<size_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};
+
+  DISALLOW_COPY_AND_ASSIGN(FakeUpdaterProvider);
+};
+
+}  // namespace chromeos_policy_manager
+
+#endif  // CHROMEOS_PLATFORM_UPDATE_ENGINE_POLICY_MANAGER_FAKE_UPDATER_PROVIDER_H_
diff --git a/policy_manager/real_shill_provider.h b/policy_manager/real_shill_provider.h
index f50f2ac..ffb6b0c 100644
--- a/policy_manager/real_shill_provider.h
+++ b/policy_manager/real_shill_provider.h
@@ -56,10 +56,10 @@
   // |*result_p|. Returns |true| on success.
   bool GetProperties(DBusGProxy* proxy, GHashTable** result_p);
 
-  typedef struct {
+  struct ConnStrToType {
     const char *str;
     ConnectionType type;
-  } ConnStrToType;
+  };
 
   // A mapping from shill connection type strings to enum values.
   static const ConnStrToType shill_conn_str_to_type[];
diff --git a/policy_manager/real_updater_provider.cc b/policy_manager/real_updater_provider.cc
new file mode 100644
index 0000000..dbfae87
--- /dev/null
+++ b/policy_manager/real_updater_provider.cc
@@ -0,0 +1,338 @@
+// 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/policy_manager/real_updater_provider.h"
+
+#include <inttypes.h>
+
+#include <string>
+
+#include <base/time/time.h>
+#include <base/strings/stringprintf.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_policy_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<size_t> {
+ public:
+  using UpdaterVariableBase<size_t>::UpdaterVariableBase;
+
+ private:
+  virtual const size_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 size_t(static_cast<size_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);
+};
+
+
+// RealUpdaterProvider methods.
+
+RealUpdaterProvider::RealUpdaterProvider(SystemState* system_state)
+  : system_state_(system_state),
+    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)) {}
+
+}  // namespace chromeos_policy_manager
diff --git a/policy_manager/real_updater_provider.h b/policy_manager/real_updater_provider.h
new file mode 100644
index 0000000..1b24e16
--- /dev/null
+++ b/policy_manager/real_updater_provider.h
@@ -0,0 +1,89 @@
+// 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_POLICY_MANAGER_REAL_UPDATER_PROVIDER_H_
+#define CHROMEOS_PLATFORM_UPDATE_ENGINE_POLICY_MANAGER_REAL_UPDATER_PROVIDER_H_
+
+#include "update_engine/policy_manager/updater_provider.h"
+
+#include "update_engine/system_state.h"
+
+namespace chromeos_policy_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);
+
+  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<size_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();
+  }
+
+ protected:
+  virtual bool DoInit() { return true; }
+
+ private:
+  // A pointer to the update engine's system state aggregator.
+  chromeos_update_engine::SystemState* system_state_;
+
+  // Pointers to all variable implementations.
+  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<size_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_;
+
+  DISALLOW_COPY_AND_ASSIGN(RealUpdaterProvider);
+};
+
+}  // namespace chromeos_policy_manager
+
+#endif  // CHROMEOS_PLATFORM_UPDATE_ENGINE_POLICY_MANAGER_REAL_UPDATER_PROVIDER_H_
diff --git a/policy_manager/real_updater_provider_unittest.cc b/policy_manager/real_updater_provider_unittest.cc
new file mode 100644
index 0000000..ac21566
--- /dev/null
+++ b/policy_manager/real_updater_provider_unittest.cc
@@ -0,0 +1,415 @@
+// 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/policy_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/mock_system_state.h"
+#include "update_engine/omaha_request_params.h"
+#include "update_engine/policy_manager/pmtest_utils.h"
+#include "update_engine/prefs_mock.h"
+#include "update_engine/update_attempter_mock.h"
+
+using base::Time;
+using base::TimeDelta;
+using chromeos_update_engine::FakeClock;
+using chromeos_update_engine::MockSystemState;
+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_policy_manager {
+
+class PmRealUpdaterProviderTest : public ::testing::Test {
+ protected:
+  virtual void SetUp() {
+    mock_sys_state_.set_clock(&fake_clock_);
+    provider_.reset(new RealUpdaterProvider(&mock_sys_state_));
+    PMTEST_ASSERT_NOT_NULL(provider_.get());
+    // Check that provider initializes corrrectly.
+    ASSERT_TRUE(provider_->Init());
+  }
+
+  // Tests that the GetValue() method of variable |var| succeeds and the
+  // returned value equals |expected|.
+  template<typename T>
+  void TestGetValueOkay(Variable<T>* var, T expected) {
+    PMTEST_ASSERT_NOT_NULL(var);
+    scoped_ptr<const T> actual(var->GetValue(default_timeout_, NULL));
+    PMTEST_ASSERT_NOT_NULL(actual.get());
+    EXPECT_EQ(expected, *actual);
+  }
+
+  // Tests that the GetValue() method of variable |var| fails, returning null.
+  template<typename T>
+  void TestGetValueFail(Variable<T>* var) {
+    PMTEST_ASSERT_NOT_NULL(var);
+    scoped_ptr<const T> actual(var->GetValue(default_timeout_, NULL));
+    PMTEST_EXPECT_NULL(actual.get());
+  }
+
+  // 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 = mock_sys_state_.mock_prefs();
+    EXPECT_CALL(*mock_prefs, Exists(StrEq(key))).WillOnce(Return(key_exists));
+    if (key_exists) {
+      auto& get_boolean = EXPECT_CALL(
+          *mock_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(*mock_sys_state_.update_attempter(), GetBootTimeAtUpdate(_))
+        .WillOnce(DoAll(SetArgPointee<0>(kUpdateBootTime), Return(true)));
+    fake_clock_.SetBootTime(kCurrBootTime);
+    fake_clock_.SetWallclockTime(kCurrWallclockTime);
+    return kCurrWallclockTime - kDurationSinceUpdate;
+  }
+
+  const TimeDelta default_timeout_ = TimeDelta::FromSeconds(1);
+  MockSystemState mock_sys_state_;
+  FakeClock fake_clock_;
+  scoped_ptr<RealUpdaterProvider> provider_;
+};
+
+TEST_F(PmRealUpdaterProviderTest, GetLastCheckedTimeOkay) {
+  EXPECT_CALL(*mock_sys_state_.update_attempter(), GetStatus(_, _, _, _, _))
+      .WillOnce(DoAll(SetArgPointee<0>(FixedTime().ToTimeT()), Return(true)));
+  TestGetValueOkay(provider_->var_last_checked_time(),
+                   RoundedToSecond(FixedTime()));
+}
+
+TEST_F(PmRealUpdaterProviderTest, GetLastCheckedTimeFailNoValue) {
+  EXPECT_CALL(*mock_sys_state_.update_attempter(), GetStatus(_, _, _, _, _))
+      .WillOnce(Return(false));
+  TestGetValueFail(provider_->var_last_checked_time());
+}
+
+TEST_F(PmRealUpdaterProviderTest, GetProgressOkayMin) {
+  EXPECT_CALL(*mock_sys_state_.update_attempter(), GetStatus(_, _, _, _, _))
+      .WillOnce(DoAll(SetArgPointee<1>(0.0), Return(true)));
+  TestGetValueOkay(provider_->var_progress(), 0.0);
+}
+
+TEST_F(PmRealUpdaterProviderTest, GetProgressOkayMid) {
+  EXPECT_CALL(*mock_sys_state_.update_attempter(), GetStatus(_, _, _, _, _))
+      .WillOnce(DoAll(SetArgPointee<1>(0.3), Return(true)));
+  TestGetValueOkay(provider_->var_progress(), 0.3);
+}
+
+TEST_F(PmRealUpdaterProviderTest, GetProgressOkayMax) {
+  EXPECT_CALL(*mock_sys_state_.update_attempter(), GetStatus(_, _, _, _, _))
+      .WillOnce(DoAll(SetArgPointee<1>(1.0), Return(true)));
+  TestGetValueOkay(provider_->var_progress(), 1.0);
+}
+
+TEST_F(PmRealUpdaterProviderTest, GetProgressFailNoValue) {
+  EXPECT_CALL(*mock_sys_state_.update_attempter(), GetStatus(_, _, _, _, _))
+      .WillOnce(Return(false));
+  TestGetValueFail(provider_->var_progress());
+}
+
+TEST_F(PmRealUpdaterProviderTest, GetProgressFailTooSmall) {
+  EXPECT_CALL(*mock_sys_state_.update_attempter(), GetStatus(_, _, _, _, _))
+      .WillOnce(DoAll(SetArgPointee<1>(-2.0), Return(true)));
+  TestGetValueFail(provider_->var_progress());
+}
+
+TEST_F(PmRealUpdaterProviderTest, GetProgressFailTooBig) {
+  EXPECT_CALL(*mock_sys_state_.update_attempter(), GetStatus(_, _, _, _, _))
+      .WillOnce(DoAll(SetArgPointee<1>(2.0), Return(true)));
+  TestGetValueFail(provider_->var_progress());
+}
+
+TEST_F(PmRealUpdaterProviderTest, GetStageOkayIdle) {
+  EXPECT_CALL(*mock_sys_state_.update_attempter(), GetStatus(_, _, _, _, _))
+      .WillOnce(DoAll(SetArgPointee<2>(update_engine::kUpdateStatusIdle),
+                      Return(true)));
+  TestGetValueOkay(provider_->var_stage(), Stage::kIdle);
+}
+
+TEST_F(PmRealUpdaterProviderTest, GetStageOkayCheckingForUpdate) {
+  EXPECT_CALL(*mock_sys_state_.update_attempter(), GetStatus(_, _, _, _, _))
+      .WillOnce(DoAll(
+              SetArgPointee<2>(update_engine::kUpdateStatusCheckingForUpdate),
+              Return(true)));
+  TestGetValueOkay(provider_->var_stage(), Stage::kCheckingForUpdate);
+}
+
+TEST_F(PmRealUpdaterProviderTest, GetStageOkayUpdateAvailable) {
+  EXPECT_CALL(*mock_sys_state_.update_attempter(), GetStatus(_, _, _, _, _))
+      .WillOnce(DoAll(
+              SetArgPointee<2>(update_engine::kUpdateStatusUpdateAvailable),
+              Return(true)));
+  TestGetValueOkay(provider_->var_stage(), Stage::kUpdateAvailable);
+}
+
+TEST_F(PmRealUpdaterProviderTest, GetStageOkayDownloading) {
+  EXPECT_CALL(*mock_sys_state_.update_attempter(), GetStatus(_, _, _, _, _))
+      .WillOnce(DoAll(SetArgPointee<2>(update_engine::kUpdateStatusDownloading),
+                      Return(true)));
+  TestGetValueOkay(provider_->var_stage(), Stage::kDownloading);
+}
+
+TEST_F(PmRealUpdaterProviderTest, GetStageOkayVerifying) {
+  EXPECT_CALL(*mock_sys_state_.update_attempter(), GetStatus(_, _, _, _, _))
+      .WillOnce(DoAll(SetArgPointee<2>(update_engine::kUpdateStatusVerifying),
+                      Return(true)));
+  TestGetValueOkay(provider_->var_stage(), Stage::kVerifying);
+}
+
+TEST_F(PmRealUpdaterProviderTest, GetStageOkayFinalizing) {
+  EXPECT_CALL(*mock_sys_state_.update_attempter(), GetStatus(_, _, _, _, _))
+      .WillOnce(DoAll(SetArgPointee<2>(update_engine::kUpdateStatusFinalizing),
+                      Return(true)));
+  TestGetValueOkay(provider_->var_stage(), Stage::kFinalizing);
+}
+
+TEST_F(PmRealUpdaterProviderTest, GetStageOkayUpdatedNeedReboot) {
+  EXPECT_CALL(*mock_sys_state_.update_attempter(), GetStatus(_, _, _, _, _))
+      .WillOnce(DoAll(
+              SetArgPointee<2>(update_engine::kUpdateStatusUpdatedNeedReboot),
+              Return(true)));
+  TestGetValueOkay(provider_->var_stage(), Stage::kUpdatedNeedReboot);
+}
+
+TEST_F(PmRealUpdaterProviderTest, GetStageOkayReportingErrorEvent) {
+  EXPECT_CALL(*mock_sys_state_.update_attempter(), GetStatus(_, _, _, _, _))
+      .WillOnce(DoAll(
+              SetArgPointee<2>(update_engine::kUpdateStatusReportingErrorEvent),
+              Return(true)));
+  TestGetValueOkay(provider_->var_stage(), Stage::kReportingErrorEvent);
+}
+
+TEST_F(PmRealUpdaterProviderTest, GetStageOkayAttemptingRollback) {
+  EXPECT_CALL(*mock_sys_state_.update_attempter(), GetStatus(_, _, _, _, _))
+      .WillOnce(DoAll(
+              SetArgPointee<2>(update_engine::kUpdateStatusAttemptingRollback),
+              Return(true)));
+  TestGetValueOkay(provider_->var_stage(), Stage::kAttemptingRollback);
+}
+
+TEST_F(PmRealUpdaterProviderTest, GetStageFailNoValue) {
+  EXPECT_CALL(*mock_sys_state_.update_attempter(), GetStatus(_, _, _, _, _))
+      .WillOnce(Return(false));
+  TestGetValueFail(provider_->var_stage());
+}
+
+TEST_F(PmRealUpdaterProviderTest, GetStageFailUnknown) {
+  EXPECT_CALL(*mock_sys_state_.update_attempter(), GetStatus(_, _, _, _, _))
+      .WillOnce(DoAll(SetArgPointee<2>("FooUpdateEngineState"),
+                      Return(true)));
+  TestGetValueFail(provider_->var_stage());
+}
+
+TEST_F(PmRealUpdaterProviderTest, GetStageFailEmpty) {
+  EXPECT_CALL(*mock_sys_state_.update_attempter(), GetStatus(_, _, _, _, _))
+      .WillOnce(DoAll(SetArgPointee<2>(""), Return(true)));
+  TestGetValueFail(provider_->var_stage());
+}
+
+TEST_F(PmRealUpdaterProviderTest, GetNewVersionOkay) {
+  EXPECT_CALL(*mock_sys_state_.update_attempter(), GetStatus(_, _, _, _, _))
+      .WillOnce(DoAll(SetArgPointee<3>("1.2.0"), Return(true)));
+  TestGetValueOkay(provider_->var_new_version(), string("1.2.0"));
+}
+
+TEST_F(PmRealUpdaterProviderTest, GetNewVersionFailNoValue) {
+  EXPECT_CALL(*mock_sys_state_.update_attempter(), GetStatus(_, _, _, _, _))
+      .WillOnce(Return(false));
+  TestGetValueFail(provider_->var_new_version());
+}
+
+TEST_F(PmRealUpdaterProviderTest, GetPayloadSizeOkayZero) {
+  EXPECT_CALL(*mock_sys_state_.update_attempter(), GetStatus(_, _, _, _, _))
+      .WillOnce(DoAll(SetArgPointee<4>(static_cast<int64_t>(0)), Return(true)));
+  TestGetValueOkay(provider_->var_payload_size(), static_cast<size_t>(0));
+}
+
+TEST_F(PmRealUpdaterProviderTest, GetPayloadSizeOkayArbitrary) {
+  EXPECT_CALL(*mock_sys_state_.update_attempter(), GetStatus(_, _, _, _, _))
+      .WillOnce(DoAll(SetArgPointee<4>(static_cast<int64_t>(567890)),
+                      Return(true)));
+  TestGetValueOkay(provider_->var_payload_size(), static_cast<size_t>(567890));
+}
+
+TEST_F(PmRealUpdaterProviderTest, GetPayloadSizeOkayTwoGigabytes) {
+  EXPECT_CALL(*mock_sys_state_.update_attempter(), GetStatus(_, _, _, _, _))
+      .WillOnce(DoAll(SetArgPointee<4>(static_cast<int64_t>(1) << 31),
+                      Return(true)));
+  TestGetValueOkay(provider_->var_payload_size(), static_cast<size_t>(1) << 31);
+}
+
+TEST_F(PmRealUpdaterProviderTest, GetPayloadSizeFailNoValue) {
+  EXPECT_CALL(*mock_sys_state_.update_attempter(), GetStatus(_, _, _, _, _))
+      .WillOnce(Return(false));
+  TestGetValueFail(provider_->var_payload_size());
+}
+
+TEST_F(PmRealUpdaterProviderTest, GetPayloadSizeFailNegative) {
+  EXPECT_CALL(*mock_sys_state_.update_attempter(), GetStatus(_, _, _, _, _))
+      .WillOnce(DoAll(SetArgPointee<4>(static_cast<int64_t>(-1024)),
+                      Return(true)));
+  TestGetValueFail(provider_->var_payload_size());
+}
+
+TEST_F(PmRealUpdaterProviderTest, GetCurrChannelOkay) {
+  const string kChannelName("foo-channel");
+  OmahaRequestParams request_params(&mock_sys_state_);
+  request_params.Init("", "", false);
+  request_params.set_current_channel(kChannelName);
+  mock_sys_state_.set_request_params(&request_params);
+  TestGetValueOkay(provider_->var_curr_channel(), kChannelName);
+}
+
+TEST_F(PmRealUpdaterProviderTest, GetCurrChannelFailEmpty) {
+  OmahaRequestParams request_params(&mock_sys_state_);
+  request_params.Init("", "", false);
+  request_params.set_current_channel("");
+  mock_sys_state_.set_request_params(&request_params);
+  TestGetValueFail(provider_->var_curr_channel());
+}
+
+TEST_F(PmRealUpdaterProviderTest, GetNewChannelOkay) {
+  const string kChannelName("foo-channel");
+  OmahaRequestParams request_params(&mock_sys_state_);
+  request_params.Init("", "", false);
+  request_params.set_target_channel(kChannelName);
+  mock_sys_state_.set_request_params(&request_params);
+  TestGetValueOkay(provider_->var_new_channel(), kChannelName);
+}
+
+TEST_F(PmRealUpdaterProviderTest, GetNewChannelFailEmpty) {
+  OmahaRequestParams request_params(&mock_sys_state_);
+  request_params.Init("", "", false);
+  request_params.set_target_channel("");
+  mock_sys_state_.set_request_params(&request_params);
+  TestGetValueFail(provider_->var_new_channel());
+}
+
+TEST_F(PmRealUpdaterProviderTest, GetP2PEnabledOkayPrefDoesntExist) {
+  SetupReadBooleanPref(chromeos_update_engine::kPrefsP2PEnabled,
+                       false, false, false);
+  TestGetValueOkay(provider_->var_p2p_enabled(), false);
+}
+
+TEST_F(PmRealUpdaterProviderTest, GetP2PEnabledOkayPrefReadsFalse) {
+  SetupReadBooleanPref(chromeos_update_engine::kPrefsP2PEnabled,
+                       true, true, false);
+  TestGetValueOkay(provider_->var_p2p_enabled(), false);
+}
+
+TEST_F(PmRealUpdaterProviderTest, GetP2PEnabledOkayPrefReadsTrue) {
+  SetupReadBooleanPref(chromeos_update_engine::kPrefsP2PEnabled,
+                       true, true, true);
+  TestGetValueOkay(provider_->var_p2p_enabled(), true);
+}
+
+TEST_F(PmRealUpdaterProviderTest, GetP2PEnabledFailCannotReadPref) {
+  SetupReadBooleanPref(chromeos_update_engine::kPrefsP2PEnabled,
+                       true, false, false);
+  TestGetValueFail(provider_->var_p2p_enabled());
+}
+
+TEST_F(PmRealUpdaterProviderTest, GetCellularEnabledOkayPrefDoesntExist) {
+  SetupReadBooleanPref(
+      chromeos_update_engine::kPrefsUpdateOverCellularPermission,
+      false, false, false);
+  TestGetValueOkay(provider_->var_cellular_enabled(), false);
+}
+
+TEST_F(PmRealUpdaterProviderTest, GetCellularEnabledOkayPrefReadsFalse) {
+  SetupReadBooleanPref(
+      chromeos_update_engine::kPrefsUpdateOverCellularPermission,
+      true, true, false);
+  TestGetValueOkay(provider_->var_cellular_enabled(), false);
+}
+
+TEST_F(PmRealUpdaterProviderTest, GetCellularEnabledOkayPrefReadsTrue) {
+  SetupReadBooleanPref(
+      chromeos_update_engine::kPrefsUpdateOverCellularPermission,
+      true, true, true);
+  TestGetValueOkay(provider_->var_cellular_enabled(), true);
+}
+
+TEST_F(PmRealUpdaterProviderTest, GetCellularEnabledFailCannotReadPref) {
+  SetupReadBooleanPref(
+      chromeos_update_engine::kPrefsUpdateOverCellularPermission,
+      true, false, false);
+  TestGetValueFail(provider_->var_cellular_enabled());
+}
+
+TEST_F(PmRealUpdaterProviderTest, GetUpdateCompletedTimeOkay) {
+  Time expected = SetupUpdateCompletedTime(true);
+  TestGetValueOkay(provider_->var_update_completed_time(), expected);
+}
+
+TEST_F(PmRealUpdaterProviderTest, GetUpdateCompletedTimeFailNoValue) {
+  EXPECT_CALL(*mock_sys_state_.update_attempter(), GetBootTimeAtUpdate(_))
+      .WillOnce(Return(false));
+  TestGetValueFail(provider_->var_update_completed_time());
+}
+
+TEST_F(PmRealUpdaterProviderTest, GetUpdateCompletedTimeFailInvalidValue) {
+  SetupUpdateCompletedTime(false);
+  TestGetValueFail(provider_->var_update_completed_time());
+}
+
+}  // namespace chromeos_policy_manager
diff --git a/policy_manager/state.h b/policy_manager/state.h
index 8d93dea..09f1b3d 100644
--- a/policy_manager/state.h
+++ b/policy_manager/state.h
@@ -9,6 +9,7 @@
 #include "update_engine/policy_manager/shill_provider.h"
 #include "update_engine/policy_manager/system_provider.h"
 #include "update_engine/policy_manager/time_provider.h"
+#include "update_engine/policy_manager/updater_provider.h"
 
 namespace chromeos_policy_manager {
 
@@ -18,17 +19,22 @@
  public:
   virtual ~State() {}
   State(RandomProvider* random_provider, ShillProvider* shill_provider,
-        SystemProvider* system_provider, TimeProvider* time_provider) :
+        SystemProvider* system_provider, TimeProvider* time_provider,
+        UpdaterProvider* updater_provider) :
       random_provider_(random_provider),
       shill_provider_(shill_provider),
       system_provider_(system_provider),
-      time_provider_(time_provider) {}
+      time_provider_(time_provider),
+      updater_provider_(updater_provider) {}
 
   // These methods return the given provider.
   virtual RandomProvider* random_provider() { return random_provider_.get(); }
   virtual ShillProvider* shill_provider() { return shill_provider_.get(); }
-  virtual TimeProvider* time_provider() { return time_provider_.get(); }
   virtual SystemProvider* system_provider() { return system_provider_.get(); }
+  virtual TimeProvider* time_provider() { return time_provider_.get(); }
+  virtual UpdaterProvider* updater_provider() {
+    return updater_provider_.get();
+  }
 
  private:
   // Instances of the providers.
@@ -36,6 +42,7 @@
   scoped_ptr<ShillProvider> shill_provider_;
   scoped_ptr<SystemProvider> system_provider_;
   scoped_ptr<TimeProvider> time_provider_;
+  scoped_ptr<UpdaterProvider> updater_provider_;
 };
 
 }  // namespace chromeos_policy_manager
diff --git a/policy_manager/state_factory.cc b/policy_manager/state_factory.cc
index cab9d5e..a5f0df9 100644
--- a/policy_manager/state_factory.cc
+++ b/policy_manager/state_factory.cc
@@ -6,26 +6,31 @@
 
 #include <base/logging.h>
 
+#include "update_engine/clock_interface.h"
 #include "update_engine/policy_manager/real_random_provider.h"
 #include "update_engine/policy_manager/real_shill_provider.h"
 #include "update_engine/policy_manager/real_system_provider.h"
 #include "update_engine/policy_manager/real_time_provider.h"
+#include "update_engine/policy_manager/real_updater_provider.h"
 
 namespace chromeos_policy_manager {
 
-State* DefaultStateFactory(
-    chromeos_update_engine::DBusWrapperInterface* dbus,
-    chromeos_update_engine::ClockInterface* clock) {
+State* DefaultStateFactory(chromeos_update_engine::DBusWrapperInterface* dbus,
+                           chromeos_update_engine::SystemState* system_state) {
+  chromeos_update_engine::ClockInterface* const clock = system_state->clock();
   scoped_ptr<RealRandomProvider> random_provider(new RealRandomProvider());
   scoped_ptr<RealShillProvider> shill_provider(
       new RealShillProvider(dbus, clock));
   scoped_ptr<RealSystemProvider> system_provider(new RealSystemProvider());
   scoped_ptr<RealTimeProvider> time_provider(new RealTimeProvider(clock));
+  scoped_ptr<RealUpdaterProvider> updater_provider(
+      new RealUpdaterProvider(system_state));
 
   if (!(random_provider->Init() &&
         shill_provider->Init() &&
         system_provider->Init() &&
-        time_provider->Init())) {
+        time_provider->Init() &&
+        updater_provider->Init())) {
     LOG(ERROR) << "Error initializing providers";
     return NULL;
   }
@@ -33,7 +38,8 @@
   return new State(random_provider.release(),
                    shill_provider.release(),
                    system_provider.release(),
-                   time_provider.release());
+                   time_provider.release(),
+                   updater_provider.release());
 }
 
 }  // namespace chromeos_policy_manager
diff --git a/policy_manager/state_factory.h b/policy_manager/state_factory.h
index d0b93a1..58e6813 100644
--- a/policy_manager/state_factory.h
+++ b/policy_manager/state_factory.h
@@ -5,21 +5,18 @@
 #ifndef CHROMEOS_PLATFORM_UPDATE_ENGINE_POLICY_MANAGER_STATE_FACTORY_H_
 #define CHROMEOS_PLATFORM_UPDATE_ENGINE_POLICY_MANAGER_STATE_FACTORY_H_
 
-#include "update_engine/clock_interface.h"
-#include "update_engine/dbus_wrapper_interface.h"
 #include "update_engine/policy_manager/state.h"
+#include "update_engine/system_state.h"
 
 namespace chromeos_policy_manager {
 
-// Creates and initializes a new State instance using the real providers
-// instantiated using the passed interfaces when needed. The State doesn't
-// take ownership of the passed interfaces, which need to remain available
-// during the life of this instance.
-// If one of the underlying providers fails to initialize, this function returns
-// NULL.
-State* DefaultStateFactory(
-    chromeos_update_engine::DBusWrapperInterface* dbus,
-    chromeos_update_engine::ClockInterface* clock);
+// Creates and initializes a new PolicyManager 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(chromeos_update_engine::DBusWrapperInterface* dbus,
+                           chromeos_update_engine::SystemState* system_state);
 
 }  // namespace chromeos_policy_manager
 
diff --git a/policy_manager/updater_provider.h b/policy_manager/updater_provider.h
new file mode 100644
index 0000000..fa2382f
--- /dev/null
+++ b/policy_manager/updater_provider.h
@@ -0,0 +1,75 @@
+// 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_POLICY_MANAGER_UPDATER_PROVIDER_H_
+#define CHROMEOS_PLATFORM_UPDATE_ENGINE_POLICY_MANAGER_UPDATER_PROVIDER_H_
+
+#include <string>
+
+#include <base/memory/scoped_ptr.h>
+#include <base/time/time.h>
+
+#include "update_engine/policy_manager/provider.h"
+#include "update_engine/policy_manager/variable.h"
+
+namespace chromeos_policy_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:
+  // 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.
+  virtual Variable<size_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 P2P updates are allowed.
+  virtual Variable<bool>* var_p2p_enabled() = 0;
+
+  // A variable indicating whether updates are allowed over a cellular network.
+  virtual Variable<bool>* var_cellular_enabled() = 0;
+};
+
+}  // namespace chromeos_policy_manager
+
+#endif  // CHROMEOS_PLATFORM_UPDATE_ENGINE_POLICY_MANAGER_UPDATER_PROVIDER_H_
diff --git a/policy_manager/variable.h b/policy_manager/variable.h
index ab19f72..da8eee9 100644
--- a/policy_manager/variable.h
+++ b/policy_manager/variable.h
@@ -177,6 +177,7 @@
   friend class PmRealTimeProviderTest;
   FRIEND_TEST(PmRealTimeProviderTest, CurrDateValid);
   FRIEND_TEST(PmRealTimeProviderTest, CurrHourValid);
+  friend class PmRealUpdaterProviderTest;
 
   Variable(const std::string& name, VariableMode mode)
       : BaseVariable(name, mode) {}