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) {}