PolicyManager: New DevicePolicy provider.
This provider gives access to the members of the DevicePolicy
protobuf using the libpolicy to access it. The libpolicy doesn't
provide a way to get a notification when the policy was updated, but
that could be fixed on the future monitoring the file on disk. This
patch attempts to refresh the device policy every hour and updates
all the variables accordingly.
The variables exposed by this provider are only those used by the
update_engine code currently. If new variables need to be exposed
this can easily extended.
To achieve this, a new generic Variable class is introduce, named
AsyncCopyVariable, that allows you to Set or Unset the current value
of the variable and notify the subscribed observers while doing that.
BUG=chromium:358326
TEST=Unit tests added and pass.
Change-Id: Ieee6c9b33160f7dfe40c033db685a79d8fd57fe7
Reviewed-on: https://chromium-review.googlesource.com/194179
Reviewed-by: Alex Deymo <[email protected]>
Tested-by: Alex Deymo <[email protected]>
Commit-Queue: Alex Deymo <[email protected]>
diff --git a/SConstruct b/SConstruct
index 720c281..7a3b2ef 100644
--- a/SConstruct
+++ b/SConstruct
@@ -237,6 +237,7 @@
policy_manager/evaluation_context.cc
policy_manager/event_loop.cc
policy_manager/policy_manager.cc
+ policy_manager/real_device_policy_provider.cc
policy_manager/real_random_provider.cc
policy_manager/real_shill_provider.cc
policy_manager/real_system_provider.cc
@@ -299,6 +300,7 @@
policy_manager/fake_state.cc
policy_manager/generic_variables_unittest.cc
policy_manager/policy_manager_unittest.cc
+ policy_manager/real_device_policy_provider_unittest.cc
policy_manager/real_random_provider_unittest.cc
policy_manager/real_shill_provider_unittest.cc
policy_manager/real_system_provider_unittest.cc
diff --git a/policy_manager/device_policy_provider.h b/policy_manager/device_policy_provider.h
new file mode 100644
index 0000000..24a3f1f
--- /dev/null
+++ b/policy_manager/device_policy_provider.h
@@ -0,0 +1,62 @@
+// Copyright (c) 2014 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROMEOS_PLATFORM_UPDATE_ENGINE_POLICY_MANAGER_DEVICE_POLICY_PROVIDER_H_
+#define CHROMEOS_PLATFORM_UPDATE_ENGINE_POLICY_MANAGER_DEVICE_POLICY_PROVIDER_H_
+
+#include <set>
+#include <string>
+
+#include <policy/libpolicy.h>
+#include <base/time/time.h>
+
+#include "update_engine/policy_manager/provider.h"
+#include "update_engine/policy_manager/shill_provider.h"
+#include "update_engine/policy_manager/variable.h"
+
+namespace chromeos_policy_manager {
+
+// Provides access to the current DevicePolicy.
+class DevicePolicyProvider : public Provider {
+ public:
+ virtual ~DevicePolicyProvider() {}
+
+ // Variable stating whether the DevicePolicy was loaded.
+ virtual Variable<bool>* var_device_policy_is_loaded() = 0;
+
+ // Variables mapping the information received on the DevicePolicy protobuf.
+ virtual Variable<std::string>* var_release_channel() = 0;
+
+ virtual Variable<bool>* var_release_channel_delegated() = 0;
+
+ virtual Variable<bool>* var_update_disabled() = 0;
+
+ virtual Variable<std::string>* var_target_version_prefix() = 0;
+
+ virtual Variable<base::TimeDelta>* var_scatter_factor() = 0;
+
+ // Variable returing the set of connection types allowed for updates. The
+ // identifiers returned are consistent with the ones returned by the
+ // ShillProvider.
+ virtual Variable<std::set<ConnectionType>>*
+ var_allowed_connection_types_for_update() = 0;
+
+ // Variable stating the name of the device owner. For enterprise enrolled
+ // devices, this will be an empty string.
+ virtual Variable<std::string>* var_get_owner() = 0;
+
+ virtual Variable<bool>* var_http_downloads_enabled() = 0;
+
+ virtual Variable<bool>* var_au_p2p_enabled() = 0;
+
+ protected:
+ DevicePolicyProvider() {}
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(DevicePolicyProvider);
+};
+
+} // namespace chromeos_policy_manager
+
+#endif // CHROMEOS_PLATFORM_UPDATE_ENGINE_POLICY_MANAGER_DEVICE_POLICY_PROVIDER_H_
diff --git a/policy_manager/fake_device_policy_provider.h b/policy_manager/fake_device_policy_provider.h
new file mode 100644
index 0000000..4863ae5
--- /dev/null
+++ b/policy_manager/fake_device_policy_provider.h
@@ -0,0 +1,92 @@
+// 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_DEVICE_POLICY_PROVIDER_H_
+#define CHROMEOS_PLATFORM_UPDATE_ENGINE_POLICY_MANAGER_FAKE_DEVICE_POLICY_PROVIDER_H_
+
+#include <set>
+#include <string>
+
+#include "update_engine/policy_manager/device_policy_provider.h"
+#include "update_engine/policy_manager/fake_variable.h"
+
+namespace chromeos_policy_manager {
+
+// Fake implementation of the DevicePolicyProvider base class.
+class FakeDevicePolicyProvider : public DevicePolicyProvider {
+ public:
+ FakeDevicePolicyProvider() {}
+
+ virtual FakeVariable<bool>* var_device_policy_is_loaded() override {
+ return &var_device_policy_is_loaded_;
+ }
+
+ virtual FakeVariable<std::string>* var_release_channel() override {
+ return &var_release_channel_;
+ }
+
+ virtual FakeVariable<bool>* var_release_channel_delegated() override {
+ return &var_release_channel_delegated_;
+ }
+
+ virtual FakeVariable<bool>* var_update_disabled() override {
+ return &var_update_disabled_;
+ }
+
+ virtual FakeVariable<std::string>* var_target_version_prefix() override {
+ return &var_target_version_prefix_;
+ }
+
+ virtual FakeVariable<base::TimeDelta>* var_scatter_factor() override {
+ return &var_scatter_factor_;
+ }
+
+ virtual FakeVariable<std::set<ConnectionType>>*
+ var_allowed_connection_types_for_update() override {
+ return &var_allowed_connection_types_for_update_;
+ }
+
+ virtual FakeVariable<std::string>* var_get_owner() override {
+ return &var_get_owner_;
+ }
+
+ virtual FakeVariable<bool>* var_http_downloads_enabled() override {
+ return &var_http_downloads_enabled_;
+ }
+
+ virtual FakeVariable<bool>* var_au_p2p_enabled() override {
+ return &var_au_p2p_enabled_;
+ }
+
+ private:
+ virtual bool DoInit() override {
+ return true;
+ }
+
+ FakeVariable<bool> var_device_policy_is_loaded_{
+ "policy_is_loaded", kVariableModePoll};
+ FakeVariable<std::string> var_release_channel_{
+ "release_channel", kVariableModePoll};
+ FakeVariable<bool> var_release_channel_delegated_{
+ "release_channel_delegated", kVariableModePoll};
+ FakeVariable<bool> var_update_disabled_{
+ "update_disabled", kVariableModePoll};
+ FakeVariable<std::string> var_target_version_prefix_{
+ "target_version_prefix", kVariableModePoll};
+ FakeVariable<base::TimeDelta> var_scatter_factor_{
+ "scatter_factor", kVariableModePoll};
+ FakeVariable<std::set<ConnectionType>>
+ var_allowed_connection_types_for_update_{
+ "allowed_connection_types_for_update", kVariableModePoll};
+ FakeVariable<std::string> var_get_owner_{"get_owner", kVariableModePoll};
+ FakeVariable<bool> var_http_downloads_enabled_{
+ "http_downloads_enabled", kVariableModePoll};
+ FakeVariable<bool> var_au_p2p_enabled_{"au_p2p_enabled", kVariableModePoll};
+
+ DISALLOW_COPY_AND_ASSIGN(FakeDevicePolicyProvider);
+};
+
+} // namespace chromeos_policy_manager
+
+#endif // CHROMEOS_PLATFORM_UPDATE_ENGINE_POLICY_MANAGER_FAKE_DEVICE_POLICY_PROVIDER_H_
diff --git a/policy_manager/fake_state.cc b/policy_manager/fake_state.cc
index 0f0b5f1..2af8de0 100644
--- a/policy_manager/fake_state.cc
+++ b/policy_manager/fake_state.cc
@@ -8,7 +8,8 @@
namespace chromeos_policy_manager {
-FakeState::FakeState() : State(new FakeRandomProvider(),
+FakeState::FakeState() : State(new FakeDevicePolicyProvider(),
+ new FakeRandomProvider(),
new FakeShillProvider(),
new FakeSystemProvider(),
new FakeTimeProvider(),
@@ -17,7 +18,8 @@
FakeState* FakeState::Construct() {
scoped_ptr<FakeState> fake_state(new FakeState());
- if (!(fake_state->random_provider()->Init() &&
+ if (!(fake_state->device_policy_provider()->Init() &&
+ fake_state->random_provider()->Init() &&
fake_state->shill_provider()->Init() &&
fake_state->system_provider()->Init() &&
fake_state->time_provider()->Init() &&
diff --git a/policy_manager/fake_state.h b/policy_manager/fake_state.h
index 4e4ead6..edad4aa 100644
--- a/policy_manager/fake_state.h
+++ b/policy_manager/fake_state.h
@@ -5,6 +5,7 @@
#ifndef CHROMEOS_PLATFORM_UPDATE_ENGINE_POLICY_MANAGER_FAKE_STATE_H_
#define CHROMEOS_PLATFORM_UPDATE_ENGINE_POLICY_MANAGER_FAKE_STATE_H_
+#include "update_engine/policy_manager/fake_device_policy_provider.h"
#include "update_engine/policy_manager/fake_random_provider.h"
#include "update_engine/policy_manager/fake_shill_provider.h"
#include "update_engine/policy_manager/fake_system_provider.h"
@@ -24,6 +25,10 @@
virtual ~FakeState() {}
// Downcasted getters, to allow access to the fake instances during testing.
+ virtual FakeDevicePolicyProvider* device_policy_provider() override {
+ return reinterpret_cast<FakeDevicePolicyProvider*>(
+ State::device_policy_provider());
+ }
virtual FakeRandomProvider* random_provider() override {
return reinterpret_cast<FakeRandomProvider*>(State::random_provider());
}
diff --git a/policy_manager/generic_variables.h b/policy_manager/generic_variables.h
index 261b96c..9110c9a 100644
--- a/policy_manager/generic_variables.h
+++ b/policy_manager/generic_variables.h
@@ -123,6 +123,63 @@
const T obj_;
};
+// A Variable class to implement simple Async variables. It provides two methods
+// SetValue and UnsetValue to modify the current value of the variable and
+// notify the registered observers whenever the value changed.
+//
+// The type T needs to be copy-constructable, default-constructable and have an
+// operator== (to determine if the value changed), which makes this class
+// suitable for basic types.
+template<typename T>
+class AsyncCopyVariable : public Variable<T> {
+ public:
+ explicit AsyncCopyVariable(const std::string& name)
+ : Variable<T>(name, kVariableModeAsync), has_value_(false) {}
+
+ AsyncCopyVariable(const std::string& name, const T value)
+ : Variable<T>(name, kVariableModeAsync),
+ has_value_(true), value_(value) {}
+
+ void SetValue(const T& new_value) {
+ bool should_notify = !(has_value_ && new_value == value_);
+ value_ = new_value;
+ has_value_ = true;
+ if (should_notify)
+ this->NotifyValueChanged();
+ }
+
+ void UnsetValue() {
+ if (has_value_) {
+ has_value_ = false;
+ this->NotifyValueChanged();
+ }
+ }
+
+ protected:
+ friend class PmAsyncCopyVariableTest;
+ FRIEND_TEST(PmAsyncCopyVariableTest, ConstructorTest);
+ FRIEND_TEST(PmAsyncCopyVariableTest, SetValueTest);
+ FRIEND_TEST(PmAsyncCopyVariableTest, UnsetValueTest);
+
+ // Variable override.
+ virtual const T* GetValue(base::TimeDelta /* timeout */,
+ std::string* errmsg) {
+ if (!has_value_) {
+ if (errmsg)
+ *errmsg = "No value set for " + this->GetName();
+ return nullptr;
+ }
+ return new T(value_);
+ }
+
+ private:
+ // Whether the variable has a value set.
+ bool has_value_;
+
+ // Copy of the object to be returned by GetValue().
+ T value_;
+};
+
} // namespace chromeos_policy_manager
#endif // CHROMEOS_PLATFORM_UPDATE_ENGINE_POLICY_MANAGER_GENERIC_VARIABLES_H_
diff --git a/policy_manager/generic_variables_unittest.cc b/policy_manager/generic_variables_unittest.cc
index 7783e9f..490f949 100644
--- a/policy_manager/generic_variables_unittest.cc
+++ b/policy_manager/generic_variables_unittest.cc
@@ -8,8 +8,10 @@
#include <gtest/gtest.h>
#include "update_engine/policy_manager/pmtest_utils.h"
+#include "update_engine/test_utils.h"
using base::TimeDelta;
+using chromeos_update_engine::RunGMainLoopMaxIterations;
namespace chromeos_policy_manager {
@@ -101,4 +103,78 @@
EXPECT_EQ(5, *copy);
}
+
+class PmAsyncCopyVariableTest : public ::testing::Test {
+ public:
+ void TearDown() {
+ // No remaining event on the main loop.
+ EXPECT_EQ(0, RunGMainLoopMaxIterations(1));
+ }
+
+ protected:
+ TimeDelta default_timeout_ = TimeDelta::FromSeconds(1);
+};
+
+TEST_F(PmAsyncCopyVariableTest, ConstructorTest) {
+ AsyncCopyVariable<int> var("var");
+ PMTEST_EXPECT_NULL(var.GetValue(default_timeout_, NULL));
+ EXPECT_EQ(kVariableModeAsync, var.GetMode());
+}
+
+TEST_F(PmAsyncCopyVariableTest, SetValueTest) {
+ AsyncCopyVariable<int> var("var");
+ var.SetValue(5);
+ scoped_ptr<const int> copy(var.GetValue(default_timeout_, NULL));
+ PMTEST_ASSERT_NOT_NULL(copy.get());
+ EXPECT_EQ(5, *copy);
+ // Execute all the pending observers.
+ RunGMainLoopMaxIterations(100);
+}
+
+TEST_F(PmAsyncCopyVariableTest, UnsetValueTest) {
+ AsyncCopyVariable<int> var("var", 42);
+ var.UnsetValue();
+ PMTEST_EXPECT_NULL(var.GetValue(default_timeout_, NULL));
+ // Execute all the pending observers.
+ RunGMainLoopMaxIterations(100);
+}
+
+class CallCounterObserver : public BaseVariable::ObserverInterface {
+ public:
+ void ValueChanged(BaseVariable* variable) {
+ calls_count_++;
+ }
+
+ int calls_count_ = 0;
+};
+
+TEST_F(PmAsyncCopyVariableTest, ObserverCalledTest) {
+ AsyncCopyVariable<int> var("var", 42);
+ CallCounterObserver observer;
+ var.AddObserver(&observer);
+ EXPECT_EQ(0, observer.calls_count_);
+
+ // Check that a different value fires the notification.
+ var.SetValue(5);
+ RunGMainLoopMaxIterations(100);
+ EXPECT_EQ(1, observer.calls_count_);
+
+ // Check the same value doesn't.
+ var.SetValue(5);
+ RunGMainLoopMaxIterations(100);
+ EXPECT_EQ(1, observer.calls_count_);
+
+ // Check that unsetting a previously set value fires the notification.
+ var.UnsetValue();
+ RunGMainLoopMaxIterations(100);
+ EXPECT_EQ(2, observer.calls_count_);
+
+ // Check that unsetting again doesn't.
+ var.UnsetValue();
+ RunGMainLoopMaxIterations(100);
+ EXPECT_EQ(2, observer.calls_count_);
+
+ var.RemoveObserver(&observer);
+}
+
} // namespace chromeos_policy_manager
diff --git a/policy_manager/real_device_policy_provider.cc b/policy_manager/real_device_policy_provider.cc
new file mode 100644
index 0000000..4e192a0
--- /dev/null
+++ b/policy_manager/real_device_policy_provider.cc
@@ -0,0 +1,135 @@
+// Copyright (c) 2014 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "update_engine/policy_manager/real_device_policy_provider.h"
+
+#include <base/logging.h>
+#include <base/time/time.h>
+#include <policy/device_policy.h>
+
+#include "update_engine/policy_manager/generic_variables.h"
+#include "update_engine/policy_manager/real_shill_provider.h"
+#include "update_engine/utils.h"
+
+using base::TimeDelta;
+using policy::DevicePolicy;
+using std::set;
+using std::string;
+
+namespace {
+
+const int kDevicePolicyRefreshRateInMinutes = 60;
+
+} // namespace
+
+namespace chromeos_policy_manager {
+
+RealDevicePolicyProvider::~RealDevicePolicyProvider() {
+ CancelMainLoopEvent(scheduled_refresh_);
+}
+
+bool RealDevicePolicyProvider::DoInit() {
+ CHECK(policy_provider_ != nullptr);
+
+ // On Init() we try to get the device policy and keep updating it.
+ RefreshDevicePolicyAndReschedule();
+
+ return true;
+}
+
+void RealDevicePolicyProvider::RefreshDevicePolicyAndReschedule() {
+ RefreshDevicePolicy();
+ scheduled_refresh_ = RunFromMainLoopAfterTimeout(
+ base::Bind(&RealDevicePolicyProvider::RefreshDevicePolicyAndReschedule,
+ base::Unretained(this)),
+ TimeDelta::FromMinutes(kDevicePolicyRefreshRateInMinutes));
+}
+
+template<typename T>
+void RealDevicePolicyProvider::UpdateVariable(
+ AsyncCopyVariable<T>* var,
+ bool (policy::DevicePolicy::*getter_method)(T*) const) {
+ T new_value;
+ if (policy_provider_->device_policy_is_loaded() &&
+ (policy_provider_->GetDevicePolicy().*getter_method)(&new_value)) {
+ var->SetValue(new_value);
+ } else {
+ var->UnsetValue();
+ }
+}
+
+template<typename T>
+void RealDevicePolicyProvider::UpdateVariable(
+ AsyncCopyVariable<T>* var,
+ bool (RealDevicePolicyProvider::*getter_method)(T*) const) {
+ T new_value;
+ if (policy_provider_->device_policy_is_loaded() &&
+ (this->*getter_method)(&new_value)) {
+ var->SetValue(new_value);
+ } else {
+ var->UnsetValue();
+ }
+}
+
+bool RealDevicePolicyProvider::ConvertAllowedConnectionTypesForUpdate(
+ set<ConnectionType>* allowed_types) const {
+ set<string> allowed_types_str;
+ if (!policy_provider_->GetDevicePolicy()
+ .GetAllowedConnectionTypesForUpdate(&allowed_types_str)) {
+ return false;
+ }
+ allowed_types->clear();
+ for (auto& type_str : allowed_types_str) {
+ ConnectionType type = ShillConnector::ParseConnectionType(type_str.c_str());
+ if (type != ConnectionType::kUnknown) {
+ allowed_types->insert(type);
+ } else {
+ LOG(WARNING) << "Policy includes unknown connection type: " << type_str;
+ }
+ }
+ return true;
+}
+
+bool RealDevicePolicyProvider::ConvertScatterFactor(
+ base::TimeDelta* scatter_factor) const {
+ int64 scatter_factor_in_seconds;
+ if (!policy_provider_->GetDevicePolicy().GetScatterFactorInSeconds(
+ &scatter_factor_in_seconds)) {
+ return false;
+ }
+ if (scatter_factor_in_seconds < 0) {
+ LOG(WARNING) << "Ignoring negative scatter factor: "
+ << scatter_factor_in_seconds;
+ return false;
+ }
+ *scatter_factor = base::TimeDelta::FromSeconds(scatter_factor_in_seconds);
+ return true;
+}
+
+void RealDevicePolicyProvider::RefreshDevicePolicy() {
+ if (!policy_provider_->Reload()) {
+ LOG(INFO) << "No device policies/settings present.";
+ }
+
+ var_device_policy_is_loaded_.SetValue(
+ policy_provider_->device_policy_is_loaded());
+
+ UpdateVariable(&var_release_channel_, &DevicePolicy::GetReleaseChannel);
+ UpdateVariable(&var_release_channel_delegated_,
+ &DevicePolicy::GetReleaseChannelDelegated);
+ UpdateVariable(&var_update_disabled_, &DevicePolicy::GetUpdateDisabled);
+ UpdateVariable(&var_target_version_prefix_,
+ &DevicePolicy::GetTargetVersionPrefix);
+ UpdateVariable(&var_scatter_factor_,
+ &RealDevicePolicyProvider::ConvertScatterFactor);
+ UpdateVariable(
+ &var_allowed_connection_types_for_update_,
+ &RealDevicePolicyProvider::ConvertAllowedConnectionTypesForUpdate);
+ UpdateVariable(&var_get_owner_, &DevicePolicy::GetOwner);
+ UpdateVariable(&var_http_downloads_enabled_,
+ &DevicePolicy::GetHttpDownloadsEnabled);
+ UpdateVariable(&var_au_p2p_enabled_, &DevicePolicy::GetAuP2PEnabled);
+}
+
+} // namespace chromeos_policy_manager
diff --git a/policy_manager/real_device_policy_provider.h b/policy_manager/real_device_policy_provider.h
new file mode 100644
index 0000000..cb0eb2b
--- /dev/null
+++ b/policy_manager/real_device_policy_provider.h
@@ -0,0 +1,136 @@
+// Copyright (c) 2014 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROMEOS_PLATFORM_UPDATE_ENGINE_POLICY_MANAGER_REAL_DEVICE_POLICY_PROVIDER_H_
+#define CHROMEOS_PLATFORM_UPDATE_ENGINE_POLICY_MANAGER_REAL_DEVICE_POLICY_PROVIDER_H_
+
+#include <set>
+#include <string>
+
+#include <gtest/gtest_prod.h> // for FRIEND_TEST
+#include <policy/libpolicy.h>
+
+#include "update_engine/policy_manager/device_policy_provider.h"
+#include "update_engine/policy_manager/event_loop.h"
+#include "update_engine/policy_manager/generic_variables.h"
+
+namespace chromeos_policy_manager {
+
+// DevicePolicyProvider concrete implementation.
+class RealDevicePolicyProvider : public DevicePolicyProvider {
+ public:
+ explicit RealDevicePolicyProvider(policy::PolicyProvider* policy_provider)
+ : policy_provider_(policy_provider) {}
+ ~RealDevicePolicyProvider();
+
+ virtual Variable<bool>* var_device_policy_is_loaded() override {
+ return &var_device_policy_is_loaded_;
+ }
+
+ virtual Variable<std::string>* var_release_channel() override {
+ return &var_release_channel_;
+ }
+
+ virtual Variable<bool>* var_release_channel_delegated() override {
+ return &var_release_channel_delegated_;
+ }
+
+ virtual Variable<bool>* var_update_disabled() override {
+ return &var_update_disabled_;
+ }
+
+ virtual Variable<std::string>* var_target_version_prefix() override {
+ return &var_target_version_prefix_;
+ }
+
+ virtual Variable<base::TimeDelta>* var_scatter_factor() override {
+ return &var_scatter_factor_;
+ }
+
+ virtual Variable<std::set<ConnectionType>>*
+ var_allowed_connection_types_for_update() override {
+ return &var_allowed_connection_types_for_update_;
+ }
+
+ virtual Variable<std::string>* var_get_owner() override {
+ return &var_get_owner_;
+ }
+
+ virtual Variable<bool>* var_http_downloads_enabled() override {
+ return &var_http_downloads_enabled_;
+ }
+
+ virtual Variable<bool>* var_au_p2p_enabled() override {
+ return &var_au_p2p_enabled_;
+ }
+
+ private:
+ friend class PmRealDevicePolicyProviderTest;
+ FRIEND_TEST(PmRealDevicePolicyProviderTest, RefreshScheduledTest);
+ FRIEND_TEST(PmRealDevicePolicyProviderTest, NonExistentDevicePolicyReloaded);
+ FRIEND_TEST(PmRealDevicePolicyProviderTest, ValuesUpdated);
+
+ // Provider override.
+ bool DoInit() override;
+
+ // Schedules a call to periodically refresh the device policy.
+ void RefreshDevicePolicyAndReschedule();
+
+ // Reloads the device policy and updates all the exposed variables.
+ void RefreshDevicePolicy();
+
+ // Updates the async variable |var| based on the result value of the method
+ // passed, which is a DevicePolicy getter method.
+ template<typename T>
+ void UpdateVariable(AsyncCopyVariable<T>* var,
+ bool (policy::DevicePolicy::*getter_method)(T*) const);
+
+ // Updates the async variable |var| based on the result value of the getter
+ // method passed, which is a wrapper getter on this class.
+ template<typename T>
+ void UpdateVariable(
+ AsyncCopyVariable<T>* var,
+ bool (RealDevicePolicyProvider::*getter_method)(T*) const);
+
+ // Wrapper for DevicePolicy::GetScatterFactorInSeconds() that converts the
+ // result to a base::TimeDelta. It returns the same value as
+ // GetScatterFactorInSeconds().
+ bool ConvertScatterFactor(base::TimeDelta* scatter_factor) const;
+
+ // Wrapper for DevicePolicy::GetAllowedConnectionTypesForUpdate() that
+ // converts the result to a set of ConnectionType elements instead of strings.
+ bool ConvertAllowedConnectionTypesForUpdate(
+ std::set<ConnectionType>* allowed_types) const;
+
+ // Used for fetching information about the device policy.
+ policy::PolicyProvider* policy_provider_;
+
+ // Used to schedule refreshes of the device policy.
+ EventId scheduled_refresh_ = kEventIdNull;
+
+ // Variable exposing whether the policy is loaded.
+ AsyncCopyVariable<bool> var_device_policy_is_loaded_{
+ "policy_is_loaded", false};
+
+ // Variables mapping the exposed methods from the policy::DevicePolicy.
+ AsyncCopyVariable<std::string> var_release_channel_{"release_channel"};
+ AsyncCopyVariable<bool> var_release_channel_delegated_{
+ "release_channel_delegated"};
+ AsyncCopyVariable<bool> var_update_disabled_{"update_disabled"};
+ AsyncCopyVariable<std::string> var_target_version_prefix_{
+ "target_version_prefix"};
+ AsyncCopyVariable<base::TimeDelta> var_scatter_factor_{"scatter_factor"};
+ AsyncCopyVariable<std::set<ConnectionType>>
+ var_allowed_connection_types_for_update_{
+ "allowed_connection_types_for_update"};
+ AsyncCopyVariable<std::string> var_get_owner_{"get_owner"};
+ AsyncCopyVariable<bool> var_http_downloads_enabled_{"http_downloads_enabled"};
+ AsyncCopyVariable<bool> var_au_p2p_enabled_{"au_p2p_enabled"};
+
+ DISALLOW_COPY_AND_ASSIGN(RealDevicePolicyProvider);
+};
+
+} // namespace chromeos_policy_manager
+
+#endif // CHROMEOS_PLATFORM_UPDATE_ENGINE_POLICY_MANAGER_REAL_DEVICE_POLICY_PROVIDER_H_
diff --git a/policy_manager/real_device_policy_provider_unittest.cc b/policy_manager/real_device_policy_provider_unittest.cc
new file mode 100644
index 0000000..2d14bbc
--- /dev/null
+++ b/policy_manager/real_device_policy_provider_unittest.cc
@@ -0,0 +1,176 @@
+// 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_device_policy_provider.h"
+
+#include <base/memory/scoped_ptr.h>
+#include <gtest/gtest.h>
+#include <policy/mock_device_policy.h>
+#include <policy/mock_libpolicy.h>
+
+#include "update_engine/policy_manager/pmtest_utils.h"
+#include "update_engine/test_utils.h"
+
+using base::TimeDelta;
+using chromeos_update_engine::RunGMainLoopMaxIterations;
+using std::set;
+using std::string;
+using testing::AtLeast;
+using testing::DoAll;
+using testing::Mock;
+using testing::Return;
+using testing::ReturnRef;
+using testing::SetArgumentPointee;
+using testing::_;
+
+namespace chromeos_policy_manager {
+
+class PmRealDevicePolicyProviderTest : public ::testing::Test {
+ protected:
+ virtual void SetUp() {
+ provider_.reset(new RealDevicePolicyProvider(&mock_policy_provider_));
+ // By default, we have a device policy loaded. Tests can call
+ // SetUpNonExistentDevicePolicy() to override this.
+ SetUpExistentDevicePolicy();
+ }
+
+ virtual void TearDown() {
+ // Check for leaked callbacks on the main loop.
+ EXPECT_EQ(0, RunGMainLoopMaxIterations(100));
+ }
+
+ void SetUpNonExistentDevicePolicy() {
+ ON_CALL(mock_policy_provider_, Reload())
+ .WillByDefault(Return(false));
+ ON_CALL(mock_policy_provider_, device_policy_is_loaded())
+ .WillByDefault(Return(false));
+ EXPECT_CALL(mock_policy_provider_, GetDevicePolicy()).Times(0);
+ }
+
+ void SetUpExistentDevicePolicy() {
+ // Setup the default behavior of the mocked PolicyProvider.
+ ON_CALL(mock_policy_provider_, Reload())
+ .WillByDefault(Return(true));
+ ON_CALL(mock_policy_provider_, device_policy_is_loaded())
+ .WillByDefault(Return(true));
+ ON_CALL(mock_policy_provider_, GetDevicePolicy())
+ .WillByDefault(ReturnRef(mock_device_policy_));
+ }
+
+ // Calls GetValue and expects its result to be the passed one.
+ template<typename T>
+ void ExpectVariableValue(const T& expected, Variable<T>* variable) {
+ scoped_ptr<const T> value(variable->GetValue(default_timeout_, nullptr));
+ PMTEST_ASSERT_NOT_NULL(value.get()) << "Variable: " << variable->GetName();
+ EXPECT_EQ(expected, *value) << "Variable: " << variable->GetName();
+ }
+
+ // Calls GetValue and expects its result to be NULL.
+ template<typename T>
+ void ExpectVariableNotSet(Variable<T>* variable) {
+ scoped_ptr<const T> value(variable->GetValue(default_timeout_, nullptr));
+ PMTEST_EXPECT_NULL(value.get()) << "Variable: " << variable->GetName();
+ }
+
+ TimeDelta default_timeout_ = TimeDelta::FromSeconds(1);
+ testing::NiceMock<policy::MockDevicePolicy> mock_device_policy_;
+ testing::NiceMock<policy::MockPolicyProvider> mock_policy_provider_;
+ scoped_ptr<RealDevicePolicyProvider> provider_;
+};
+
+TEST_F(PmRealDevicePolicyProviderTest, RefreshScheduledTest) {
+ // Check that the RefreshPolicy gets scheduled by checking the EventId.
+ EXPECT_TRUE(provider_->Init());
+ EXPECT_NE(kEventIdNull, provider_->scheduled_refresh_);
+}
+
+TEST_F(PmRealDevicePolicyProviderTest, FirstReload) {
+ // Checks that the policy is reloaded and the DevicePolicy is consulted.
+ EXPECT_CALL(mock_policy_provider_, Reload());
+ EXPECT_TRUE(provider_->Init());
+}
+
+TEST_F(PmRealDevicePolicyProviderTest, NonExistentDevicePolicyReloaded) {
+ // Checks that the policy is reloaded by RefreshDevicePolicy().
+ SetUpNonExistentDevicePolicy();
+ EXPECT_CALL(mock_policy_provider_, Reload()).Times(2);
+ EXPECT_TRUE(provider_->Init());
+ // Force the policy refresh.
+ provider_->RefreshDevicePolicy();
+}
+
+TEST_F(PmRealDevicePolicyProviderTest, NonExistentDevicePolicyEmptyVariables) {
+ SetUpNonExistentDevicePolicy();
+ EXPECT_CALL(mock_policy_provider_, GetDevicePolicy()).Times(0);
+ EXPECT_TRUE(provider_->Init());
+
+ ExpectVariableValue(false, provider_->var_device_policy_is_loaded());
+
+ ExpectVariableNotSet(provider_->var_release_channel());
+ ExpectVariableNotSet(provider_->var_release_channel_delegated());
+ ExpectVariableNotSet(provider_->var_update_disabled());
+ ExpectVariableNotSet(provider_->var_target_version_prefix());
+ ExpectVariableNotSet(provider_->var_scatter_factor());
+ ExpectVariableNotSet(provider_->var_allowed_connection_types_for_update());
+ ExpectVariableNotSet(provider_->var_get_owner());
+ ExpectVariableNotSet(provider_->var_http_downloads_enabled());
+ ExpectVariableNotSet(provider_->var_au_p2p_enabled());
+}
+
+TEST_F(PmRealDevicePolicyProviderTest, ValuesUpdated) {
+ SetUpNonExistentDevicePolicy();
+ EXPECT_TRUE(provider_->Init());
+ Mock::VerifyAndClearExpectations(&mock_policy_provider_);
+
+ // Reload the policy with a good one and set some values as present. The
+ // remaining values are false.
+ SetUpExistentDevicePolicy();
+ EXPECT_CALL(mock_device_policy_, GetReleaseChannel(_))
+ .WillOnce(DoAll(SetArgumentPointee<0>(string("mychannel")),
+ Return(true)));
+ EXPECT_CALL(mock_device_policy_, GetAllowedConnectionTypesForUpdate(_))
+ .WillOnce(Return(false));
+
+ provider_->RefreshDevicePolicy();
+
+ ExpectVariableValue(true, provider_->var_device_policy_is_loaded());
+
+ // Test that at least one variable is set, to ensure the refresh ocurred.
+ ExpectVariableValue(string("mychannel"), provider_->var_release_channel());
+ ExpectVariableNotSet(provider_->var_allowed_connection_types_for_update());
+}
+
+TEST_F(PmRealDevicePolicyProviderTest, ScatterFactorConverted) {
+ SetUpExistentDevicePolicy();
+ EXPECT_CALL(mock_device_policy_, GetScatterFactorInSeconds(_))
+ .WillOnce(DoAll(SetArgumentPointee<0>(1234), Return(true)));
+ EXPECT_TRUE(provider_->Init());
+
+ ExpectVariableValue(base::TimeDelta::FromSeconds(1234),
+ provider_->var_scatter_factor());
+}
+
+TEST_F(PmRealDevicePolicyProviderTest, NegativeScatterFactorIgnored) {
+ SetUpExistentDevicePolicy();
+ EXPECT_CALL(mock_device_policy_, GetScatterFactorInSeconds(_))
+ .WillOnce(DoAll(SetArgumentPointee<0>(-1), Return(true)));
+ EXPECT_TRUE(provider_->Init());
+
+ ExpectVariableNotSet(provider_->var_scatter_factor());
+}
+
+TEST_F(PmRealDevicePolicyProviderTest, AllowedTypesConverted) {
+ SetUpExistentDevicePolicy();
+ EXPECT_CALL(mock_device_policy_, GetAllowedConnectionTypesForUpdate(_))
+ .WillOnce(DoAll(SetArgumentPointee<0>(
+ set<string>{"bluetooth", "wifi", "not-a-type"}),
+ Return(true)));
+ EXPECT_TRUE(provider_->Init());
+
+ ExpectVariableValue(set<ConnectionType>{ConnectionType::kWifi,
+ ConnectionType::kBluetooth},
+ provider_->var_allowed_connection_types_for_update());
+}
+
+} // namespace chromeos_policy_manager
diff --git a/policy_manager/real_shill_provider.cc b/policy_manager/real_shill_provider.cc
index a503bc2..03e7f18 100644
--- a/policy_manager/real_shill_provider.cc
+++ b/policy_manager/real_shill_provider.cc
@@ -94,7 +94,7 @@
}
if (type_str) {
success = true;
- *conn_type_p = ParseConnType(type_str);
+ *conn_type_p = ParseConnectionType(type_str);
}
g_hash_table_unref(hash_table);
}
@@ -114,7 +114,7 @@
path, interface);
}
-ConnectionType ShillConnector::ParseConnType(const char* str) {
+ConnectionType ShillConnector::ParseConnectionType(const char* str) {
for (unsigned i = 0; i < arraysize(shill_conn_str_to_type); i++)
if (!strcmp(str, shill_conn_str_to_type[i].str))
return shill_conn_str_to_type[i].type;
diff --git a/policy_manager/real_shill_provider.h b/policy_manager/real_shill_provider.h
index a0619e2..13f0fe4 100644
--- a/policy_manager/real_shill_provider.h
+++ b/policy_manager/real_shill_provider.h
@@ -51,6 +51,9 @@
return GetProperties(manager_proxy_, result_p);
}
+ // Converts a shill connection type string into a symbolic value.
+ static ConnectionType ParseConnectionType(const char* str);
+
private:
// Issues a GetProperties call through a given |proxy|, storing the result to
// |*result_p|. Returns |true| on success.
@@ -79,9 +82,6 @@
// Return a DBus proxy for a given |path| and |interface| within shill.
DBusGProxy* GetProxy(const char* path, const char* interface);
- // Converts a shill connection type string into a symbolic value.
- ConnectionType ParseConnType(const char* str);
-
DISALLOW_COPY_AND_ASSIGN(ShillConnector);
};
diff --git a/policy_manager/state.h b/policy_manager/state.h
index 09f1b3d..b81a88e 100644
--- a/policy_manager/state.h
+++ b/policy_manager/state.h
@@ -5,6 +5,7 @@
#ifndef CHROMEOS_PLATFORM_UPDATE_ENGINE_POLICY_MANAGER_STATE_H_
#define CHROMEOS_PLATFORM_UPDATE_ENGINE_POLICY_MANAGER_STATE_H_
+#include "update_engine/policy_manager/device_policy_provider.h"
#include "update_engine/policy_manager/random_provider.h"
#include "update_engine/policy_manager/shill_provider.h"
#include "update_engine/policy_manager/system_provider.h"
@@ -18,9 +19,11 @@
class State {
public:
virtual ~State() {}
- State(RandomProvider* random_provider, ShillProvider* shill_provider,
+ State(DevicePolicyProvider* device_policy_provider,
+ RandomProvider* random_provider, ShillProvider* shill_provider,
SystemProvider* system_provider, TimeProvider* time_provider,
UpdaterProvider* updater_provider) :
+ device_policy_provider_(device_policy_provider),
random_provider_(random_provider),
shill_provider_(shill_provider),
system_provider_(system_provider),
@@ -28,6 +31,9 @@
updater_provider_(updater_provider) {}
// These methods return the given provider.
+ virtual DevicePolicyProvider* device_policy_provider() {
+ return device_policy_provider_.get();
+ }
virtual RandomProvider* random_provider() { return random_provider_.get(); }
virtual ShillProvider* shill_provider() { return shill_provider_.get(); }
virtual SystemProvider* system_provider() { return system_provider_.get(); }
@@ -38,6 +44,7 @@
private:
// Instances of the providers.
+ scoped_ptr<DevicePolicyProvider> device_policy_provider_;
scoped_ptr<RandomProvider> random_provider_;
scoped_ptr<ShillProvider> shill_provider_;
scoped_ptr<SystemProvider> system_provider_;
diff --git a/policy_manager/state_factory.cc b/policy_manager/state_factory.cc
index a5f0df9..b5bfb7f 100644
--- a/policy_manager/state_factory.cc
+++ b/policy_manager/state_factory.cc
@@ -7,6 +7,7 @@
#include <base/logging.h>
#include "update_engine/clock_interface.h"
+#include "update_engine/policy_manager/real_device_policy_provider.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"
@@ -15,9 +16,12 @@
namespace chromeos_policy_manager {
-State* DefaultStateFactory(chromeos_update_engine::DBusWrapperInterface* dbus,
+State* DefaultStateFactory(policy::PolicyProvider* policy_provider,
+ chromeos_update_engine::DBusWrapperInterface* dbus,
chromeos_update_engine::SystemState* system_state) {
chromeos_update_engine::ClockInterface* const clock = system_state->clock();
+ scoped_ptr<RealDevicePolicyProvider> device_policy_provider(
+ new RealDevicePolicyProvider(policy_provider));
scoped_ptr<RealRandomProvider> random_provider(new RealRandomProvider());
scoped_ptr<RealShillProvider> shill_provider(
new RealShillProvider(dbus, clock));
@@ -26,7 +30,8 @@
scoped_ptr<RealUpdaterProvider> updater_provider(
new RealUpdaterProvider(system_state));
- if (!(random_provider->Init() &&
+ if (!(device_policy_provider->Init() &&
+ random_provider->Init() &&
shill_provider->Init() &&
system_provider->Init() &&
time_provider->Init() &&
@@ -35,7 +40,8 @@
return NULL;
}
- return new State(random_provider.release(),
+ return new State(device_policy_provider.release(),
+ random_provider.release(),
shill_provider.release(),
system_provider.release(),
time_provider.release(),
diff --git a/policy_manager/state_factory.h b/policy_manager/state_factory.h
index 4272258..bc60ba1 100644
--- a/policy_manager/state_factory.h
+++ b/policy_manager/state_factory.h
@@ -16,8 +16,10 @@
// 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);
+State* DefaultStateFactory(
+ policy::PolicyProvider* policy_provider,
+ chromeos_update_engine::DBusWrapperInterface* dbus,
+ chromeos_update_engine::SystemState* system_state);
} // namespace chromeos_policy_manager
diff --git a/policy_manager/variable.h b/policy_manager/variable.h
index bf610c1..ae2b99e 100644
--- a/policy_manager/variable.h
+++ b/policy_manager/variable.h
@@ -57,6 +57,8 @@
LOG(WARNING) << "Variable " << name_ << " deleted with "
<< observer_list_.size() << " observers.";
}
+ DCHECK(observer_list_.empty()) << "Don't destroy the variable without "
+ "removing the observers.";
}
// Returns the variable name as a string.
@@ -172,6 +174,9 @@
// directly from the variable.
friend class EvaluationContext;
+ friend class PmRealDevicePolicyProviderTest;
+ FRIEND_TEST(PmRealDevicePolicyProviderTest,
+ NonExistentDevicePolicyEmptyVariables);
friend class PmRealRandomProviderTest;
FRIEND_TEST(PmRealRandomProviderTest, GetRandomValues);
friend class PmRealShillProviderTest;
diff --git a/real_system_state.cc b/real_system_state.cc
index 9964155..9384228 100644
--- a/real_system_state.cc
+++ b/real_system_state.cc
@@ -45,8 +45,8 @@
kMaxP2PFilesToKeep));
// Initialize the PolicyManager using the default State Factory.
- if (!policy_manager_.Init(
- chromeos_policy_manager::DefaultStateFactory(&dbus_, this))) {
+ if (!policy_manager_.Init(chromeos_policy_manager::DefaultStateFactory(
+ &policy_provider_, &dbus_, this))) {
LOG(ERROR) << "Failed to initialize the policy manager.";
return false;
}
diff --git a/real_system_state.h b/real_system_state.h
index b9c0a26..32d972b 100644
--- a/real_system_state.h
+++ b/real_system_state.h
@@ -8,8 +8,8 @@
#include "update_engine/system_state.h"
#include <policy/device_policy.h>
+#include <metrics/metrics_library.h>
-#include "metrics/metrics_library.h"
#include "update_engine/clock.h"
#include "update_engine/connection_manager.h"
#include "update_engine/gpio_handler.h"
@@ -144,6 +144,8 @@
chromeos_policy_manager::PolicyManager policy_manager_;
+ policy::PolicyProvider policy_provider_;
+
// If true, this is the first instance of the update engine since the system
// rebooted. Important for tracking whether you are running instance of the
// update engine on first boot or due to a crash/restart.