summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--chrome/app/policy/policy_templates.json11
-rw-r--r--chrome/browser/policy/config_dir_policy_provider_unittest.cc5
-rw-r--r--chrome/browser/policy/configuration_policy_pref_store.cc4
-rw-r--r--chrome/browser/policy/configuration_policy_pref_store_unittest.cc4
-rw-r--r--chrome/browser/policy/configuration_policy_provider.cc4
-rw-r--r--chrome/browser/policy/configuration_policy_provider_mac_unittest.cc5
-rw-r--r--chrome/browser/policy/configuration_policy_provider_win_unittest.cc5
-rw-r--r--chrome/browser/policy/configuration_policy_store_interface.h3
-rw-r--r--chrome/browser/policy/device_management_policy_cache.cc16
-rw-r--r--chrome/browser/policy/device_management_policy_cache.h2
-rw-r--r--chrome/browser/policy/device_management_policy_provider.cc363
-rw-r--r--chrome/browser/policy/device_management_policy_provider.h63
-rw-r--r--chrome/browser/policy/device_management_policy_provider_unittest.cc183
-rw-r--r--chrome/browser/policy/device_token_fetcher.cc7
-rw-r--r--chrome/browser/policy/device_token_fetcher_unittest.cc24
-rw-r--r--chrome/browser/policy/profile_policy_context.cc44
-rw-r--r--chrome/browser/policy/profile_policy_context.h21
-rw-r--r--chrome/browser/prefs/browser_prefs.cc8
-rw-r--r--chrome/common/policy_constants.cc1
-rw-r--r--chrome/common/policy_constants.h1
-rw-r--r--chrome/common/pref_names.cc5
-rw-r--r--chrome/common/pref_names.h1
22 files changed, 493 insertions, 287 deletions
diff --git a/chrome/app/policy/policy_templates.json b/chrome/app/policy/policy_templates.json
index 0061797..b6114d3 100644
--- a/chrome/app/policy/policy_templates.json
+++ b/chrome/app/policy/policy_templates.json
@@ -959,6 +959,17 @@
Disabling this setting potentially allows web pages to use the WebGL API and plugins to use the Pepper 3D API. The default settings of the browser may still require command line arguments to be passed in order to use these APIs.''',
},
{
+ 'name': 'PolicyRefreshRate',
+ 'type': 'int',
+ 'supported_on': ['chrome_os:1.0.0.0-'],
+ 'features': {'dynamic_refresh': 1},
+ 'example_value': 3600000,
+ 'caption': '''Policy refresh rate''',
+ 'desc': '''Specifies the period in milliseconds at which the device management service is queried for policy information.
+
+ Setting this policy overrides the default value of 3 hours. Valid values for this policy are in the range from 30 minutes to 1 day. Any values not in this range will be clamped to the respective boundary.''',
+ },
+ {
'name': 'ChromeFrameRendererSettings',
'type': 'group',
'caption': '''Default HTML renderer for <ph name="PRODUCT_FRAME_NAME">$3<ex>Google Chrome Frame</ex></ph>''',
diff --git a/chrome/browser/policy/config_dir_policy_provider_unittest.cc b/chrome/browser/policy/config_dir_policy_provider_unittest.cc
index 30c2189..67ac917 100644
--- a/chrome/browser/policy/config_dir_policy_provider_unittest.cc
+++ b/chrome/browser/policy/config_dir_policy_provider_unittest.cc
@@ -320,6 +320,9 @@ INSTANTIATE_TEST_CASE_P(
key::kShowHomeButton),
ValueTestParams::ForBooleanPolicy(
kPolicyPrintingEnabled,
- key::kPrintingEnabled)));
+ key::kPrintingEnabled),
+ ValueTestParams::ForIntegerPolicy(
+ kPolicyPolicyRefreshRate,
+ key::kPolicyRefreshRate)));
} // namespace policy
diff --git a/chrome/browser/policy/configuration_policy_pref_store.cc b/chrome/browser/policy/configuration_policy_pref_store.cc
index 58b5cac..80e0dea 100644
--- a/chrome/browser/policy/configuration_policy_pref_store.cc
+++ b/chrome/browser/policy/configuration_policy_pref_store.cc
@@ -223,6 +223,8 @@ const ConfigurationPolicyPrefKeeper::PolicyToPreferenceMapEntry
prefs::kGSSAPILibraryName },
{ Value::TYPE_BOOLEAN, kPolicyDisable3DAPIs,
prefs::kDisable3DAPIs },
+ { Value::TYPE_INTEGER, kPolicyPolicyRefreshRate,
+ prefs::kPolicyRefreshRate },
#if defined(OS_CHROMEOS)
{ Value::TYPE_BOOLEAN, kPolicyChromeOsLockOnIdleSuspend,
@@ -834,6 +836,8 @@ ConfigurationPolicyPrefStore::GetChromePolicyDefinitionList() {
key::kGSSAPILibraryName },
{ kPolicyDisable3DAPIs, Value::TYPE_BOOLEAN,
key::kDisable3DAPIs },
+ { kPolicyPolicyRefreshRate, Value::TYPE_INTEGER,
+ key::kPolicyRefreshRate },
#if defined(OS_CHROMEOS)
{ kPolicyChromeOsLockOnIdleSuspend, Value::TYPE_BOOLEAN,
diff --git a/chrome/browser/policy/configuration_policy_pref_store_unittest.cc b/chrome/browser/policy/configuration_policy_pref_store_unittest.cc
index d81ff91..e133bc9 100644
--- a/chrome/browser/policy/configuration_policy_pref_store_unittest.cc
+++ b/chrome/browser/policy/configuration_policy_pref_store_unittest.cc
@@ -220,7 +220,9 @@ INSTANTIATE_TEST_CASE_P(
ConfigurationPolicyPrefStoreIntegerTest,
testing::Values(
TypeAndName(kPolicyRestoreOnStartup,
- prefs::kRestoreOnStartup)));
+ prefs::kRestoreOnStartup),
+ TypeAndName(kPolicyPolicyRefreshRate,
+ prefs::kPolicyRefreshRate)));
// Test cases for the proxy policy settings.
class ConfigurationPolicyPrefStoreProxyTest : public testing::Test {
diff --git a/chrome/browser/policy/configuration_policy_provider.cc b/chrome/browser/policy/configuration_policy_provider.cc
index 3b82134..5282eae 100644
--- a/chrome/browser/policy/configuration_policy_provider.cc
+++ b/chrome/browser/policy/configuration_policy_provider.cc
@@ -34,7 +34,9 @@ void ConfigurationPolicyProvider::DecodePolicyValueTree(
// Class ConfigurationPolicyObserverRegistrar.
-ConfigurationPolicyObserverRegistrar::ConfigurationPolicyObserverRegistrar() {}
+ConfigurationPolicyObserverRegistrar::ConfigurationPolicyObserverRegistrar()
+ : provider_(NULL),
+ observer_(NULL) {}
ConfigurationPolicyObserverRegistrar::~ConfigurationPolicyObserverRegistrar() {
if (provider_)
diff --git a/chrome/browser/policy/configuration_policy_provider_mac_unittest.cc b/chrome/browser/policy/configuration_policy_provider_mac_unittest.cc
index 11d04a7..d221f9a 100644
--- a/chrome/browser/policy/configuration_policy_provider_mac_unittest.cc
+++ b/chrome/browser/policy/configuration_policy_provider_mac_unittest.cc
@@ -294,6 +294,9 @@ INSTANTIATE_TEST_CASE_P(
key::kShowHomeButton),
PolicyTestParams::ForBooleanPolicy(
kPolicyPrintingEnabled,
- key::kPrintingEnabled)));
+ key::kPrintingEnabled),
+ PolicyTestParams::ForIntegerPolicy(
+ kPolicyPolicyRefreshRate,
+ key::kPolicyRefreshRate)));
} // namespace policy
diff --git a/chrome/browser/policy/configuration_policy_provider_win_unittest.cc b/chrome/browser/policy/configuration_policy_provider_win_unittest.cc
index 481e1d8..1d2a9ee 100644
--- a/chrome/browser/policy/configuration_policy_provider_win_unittest.cc
+++ b/chrome/browser/policy/configuration_policy_provider_win_unittest.cc
@@ -449,6 +449,9 @@ INSTANTIATE_TEST_CASE_P(
key::kShowHomeButton),
PolicyTestParams::ForBooleanPolicy(
kPolicyPrintingEnabled,
- key::kPrintingEnabled)));
+ key::kPrintingEnabled),
+ PolicyTestParams::ForIntegerPolicy(
+ kPolicyPolicyRefreshRate,
+ key::kPolicyRefreshRate)));
} // namespace policy
diff --git a/chrome/browser/policy/configuration_policy_store_interface.h b/chrome/browser/policy/configuration_policy_store_interface.h
index b7f2f05..e697ed1 100644
--- a/chrome/browser/policy/configuration_policy_store_interface.h
+++ b/chrome/browser/policy/configuration_policy_store_interface.h
@@ -68,7 +68,8 @@ enum ConfigurationPolicyType {
kPolicyAuthServerWhitelist,
kPolicyAuthNegotiateDelegateWhitelist,
kPolicyGSSAPILibraryName,
- kPolicyDisable3DAPIs
+ kPolicyDisable3DAPIs,
+ kPolicyPolicyRefreshRate,
};
diff --git a/chrome/browser/policy/device_management_policy_cache.cc b/chrome/browser/policy/device_management_policy_cache.cc
index ff072eb..75f72bf 100644
--- a/chrome/browser/policy/device_management_policy_cache.cc
+++ b/chrome/browser/policy/device_management_policy_cache.cc
@@ -138,26 +138,18 @@ DictionaryValue* DeviceManagementPolicyCache::GetPolicy() {
return policy_->DeepCopy();
}
-void DeviceManagementPolicyCache::SetDeviceUnmanaged(bool is_device_unmanaged) {
- if (is_device_unmanaged_ == is_device_unmanaged)
- return;
-
- is_device_unmanaged_ = is_device_unmanaged;
+void DeviceManagementPolicyCache::SetDeviceUnmanaged() {
+ is_device_unmanaged_ = true;
base::Time now(base::Time::NowFromSystemTime());
- DictionaryValue* empty = new DictionaryValue();
{
AutoLock lock(lock_);
- policy_.reset(empty);
+ policy_.reset(new DictionaryValue);
last_policy_refresh_time_ = now;
}
BrowserThread::PostTask(
BrowserThread::FILE,
FROM_HERE,
- new PersistPolicyTask(backing_file_path_,
- (is_device_unmanaged ? NULL
- : new em::DevicePolicyResponse()),
- now,
- is_device_unmanaged_));
+ new PersistPolicyTask(backing_file_path_, NULL, now, true));
}
// static
diff --git a/chrome/browser/policy/device_management_policy_cache.h b/chrome/browser/policy/device_management_policy_cache.h
index 9c09a07..3ec13ed 100644
--- a/chrome/browser/policy/device_management_policy_cache.h
+++ b/chrome/browser/policy/device_management_policy_cache.h
@@ -42,7 +42,7 @@ class DeviceManagementPolicyCache {
// to the caller.
DictionaryValue* GetPolicy();
- void SetDeviceUnmanaged(bool is_device_unmanaged);
+ void SetDeviceUnmanaged();
bool is_device_unmanaged() const {
return is_device_unmanaged_;
}
diff --git a/chrome/browser/policy/device_management_policy_provider.cc b/chrome/browser/policy/device_management_policy_provider.cc
index 8b9d9b4..315a6d2 100644
--- a/chrome/browser/policy/device_management_policy_provider.cc
+++ b/chrome/browser/policy/device_management_policy_provider.cc
@@ -12,6 +12,7 @@
#include "chrome/browser/browser_thread.h"
#include "chrome/browser/policy/device_management_backend.h"
#include "chrome/browser/policy/device_management_policy_cache.h"
+#include "chrome/browser/policy/profile_policy_context.h"
#include "chrome/browser/policy/proto/device_management_constants.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/common/chrome_paths.h"
@@ -23,8 +24,13 @@ namespace policy {
namespace em = enterprise_management;
-const int64 kPolicyRefreshRateInMilliseconds = 3 * 60 * 60 * 1000; // 3 hours
-const int64 kPolicyRefreshMaxEarlierInMilliseconds = 20 * 60 * 1000; // 20 mins
+// The maximum ratio in percent of the policy refresh rate we use for adjusting
+// the policy refresh time instant. The rationale is to avoid load spikes from
+// many devices that were set up in sync for some reason.
+const int kPolicyRefreshDeviationFactorPercent = 10;
+// Maximum deviation we are willing to accept.
+const int64 kPolicyRefreshDeviationMaxInMilliseconds = 30 * 60 * 1000;
+
// These are the base values for delays before retrying after an error. They
// will be doubled each time they are used.
const int64 kPolicyRefreshErrorDelayInMilliseconds = 3 * 1000; // 3 seconds
@@ -35,44 +41,25 @@ const int64 kPolicyRefreshUnmanagedDeviceInMilliseconds = 24 * 60 * 60 * 1000;
const FilePath::StringType kDeviceTokenFilename = FILE_PATH_LITERAL("Token");
const FilePath::StringType kPolicyFilename = FILE_PATH_LITERAL("Policy");
-// Ensures that the portion of the policy provider implementation that requires
-// the IOThread is deferred until the IOThread is fully initialized. The policy
-// provider posts this task on the UI thread during its constructor, thereby
-// guaranteeing that the code won't get executed until after the UI and IO
-// threads are fully constructed.
-class DeviceManagementPolicyProvider::InitializeAfterIOThreadExistsTask
- : public Task {
+// Calls back into the provider to refresh policy.
+class DeviceManagementPolicyProvider::RefreshTask : public CancelableTask {
public:
- explicit InitializeAfterIOThreadExistsTask(
- base::WeakPtr<DeviceManagementPolicyProvider> provider)
- : provider_(provider) {
- }
+ explicit RefreshTask(DeviceManagementPolicyProvider* provider)
+ : provider_(provider) {}
// Task implementation:
virtual void Run() {
- DeviceManagementPolicyProvider* provider = provider_.get();
- if (provider)
- provider->InitializeAfterIOThreadExists();
+ if (provider_)
+ provider_->RefreshTaskExecute();
}
- private:
- base::WeakPtr<DeviceManagementPolicyProvider> provider_;
-};
-
-class DeviceManagementPolicyProvider::RefreshTask : public Task {
- public:
- explicit RefreshTask(base::WeakPtr<DeviceManagementPolicyProvider> provider)
- : provider_(provider) {}
-
- // Task implementation:
- virtual void Run() {
- DeviceManagementPolicyProvider* provider = provider_.get();
- if (provider)
- provider->RefreshTaskExecute();
+ // CancelableTask implementation:
+ virtual void Cancel() {
+ provider_ = NULL;
}
private:
- base::WeakPtr<DeviceManagementPolicyProvider> provider_;
+ DeviceManagementPolicyProvider* provider_;
};
DeviceManagementPolicyProvider::DeviceManagementPolicyProvider(
@@ -82,36 +69,19 @@ DeviceManagementPolicyProvider::DeviceManagementPolicyProvider(
: ConfigurationPolicyProvider(policy_list) {
Initialize(backend,
profile,
- kPolicyRefreshRateInMilliseconds,
- kPolicyRefreshMaxEarlierInMilliseconds,
+ ProfilePolicyContext::kDefaultPolicyRefreshRateInMilliseconds,
+ kPolicyRefreshDeviationFactorPercent,
+ kPolicyRefreshDeviationMaxInMilliseconds,
kPolicyRefreshErrorDelayInMilliseconds,
kDeviceTokenRefreshErrorDelayInMilliseconds,
kPolicyRefreshUnmanagedDeviceInMilliseconds);
}
-DeviceManagementPolicyProvider::DeviceManagementPolicyProvider(
- const PolicyDefinitionList* policy_list,
- DeviceManagementBackend* backend,
- Profile* profile,
- int64 policy_refresh_rate_ms,
- int64 policy_refresh_max_earlier_ms,
- int64 policy_refresh_error_delay_ms,
- int64 token_fetch_error_delay_ms,
- int64 unmanaged_device_refresh_rate_ms)
- : ConfigurationPolicyProvider(policy_list) {
- Initialize(backend,
- profile,
- policy_refresh_rate_ms,
- policy_refresh_max_earlier_ms,
- policy_refresh_error_delay_ms,
- token_fetch_error_delay_ms,
- unmanaged_device_refresh_rate_ms);
-}
-
DeviceManagementPolicyProvider::~DeviceManagementPolicyProvider() {
FOR_EACH_OBSERVER(ConfigurationPolicyProvider::Observer,
observer_list_,
OnProviderGoingAway());
+ CancelRefreshTask();
}
bool DeviceManagementPolicyProvider::Provide(
@@ -122,156 +92,140 @@ bool DeviceManagementPolicyProvider::Provide(
}
bool DeviceManagementPolicyProvider::IsInitializationComplete() const {
- return !waiting_for_initial_policies_;
+ return !cache_->last_policy_refresh_time().is_null();
}
void DeviceManagementPolicyProvider::HandlePolicyResponse(
const em::DevicePolicyResponse& response) {
- if (cache_->SetPolicy(response))
+ DCHECK(TokenAvailable());
+ if (cache_->SetPolicy(response)) {
+ initial_fetch_done_ = true;
NotifyCloudPolicyUpdate();
- policy_request_pending_ = false;
- // Reset the error delay since policy fetching succeeded this time.
- policy_refresh_error_delay_ms_ = kPolicyRefreshErrorDelayInMilliseconds;
- ScheduleRefreshTask(GetRefreshTaskDelay());
- // Update this provider's internal waiting state, but don't notify anyone
- // else yet (that's done by the PrefValueStore that receives the policy).
- waiting_for_initial_policies_ = false;
+ }
+ SetState(STATE_POLICY_VALID);
}
void DeviceManagementPolicyProvider::OnError(
DeviceManagementBackend::ErrorCode code) {
- policy_request_pending_ = false;
+ DCHECK(TokenAvailable());
if (code == DeviceManagementBackend::kErrorServiceDeviceNotFound ||
code == DeviceManagementBackend::kErrorServiceManagementTokenInvalid) {
LOG(WARNING) << "The device token was either invalid or unknown to the "
<< "device manager, re-registering device.";
- token_fetcher_->Restart();
+ SetState(STATE_TOKEN_RESET);
} else if (code ==
DeviceManagementBackend::kErrorServiceManagementNotSupported) {
VLOG(1) << "The device is no longer managed, resetting device token.";
- token_fetcher_->Restart();
+ SetState(STATE_TOKEN_RESET);
} else {
LOG(WARNING) << "Could not provide policy from the device manager (error = "
<< code << "), will retry in "
- << (policy_refresh_error_delay_ms_/1000) << " seconds.";
- ScheduleRefreshTask(policy_refresh_error_delay_ms_);
- policy_refresh_error_delay_ms_ *= 2;
- if (policy_refresh_rate_ms_ &&
- policy_refresh_rate_ms_ < policy_refresh_error_delay_ms_) {
- policy_refresh_error_delay_ms_ = policy_refresh_rate_ms_;
- }
+ << (effective_policy_refresh_error_delay_ms_ / 1000)
+ << " seconds.";
+ SetState(STATE_POLICY_ERROR);
}
- StopWaitingForInitialPolicies();
}
void DeviceManagementPolicyProvider::OnTokenSuccess() {
- if (policy_request_pending_)
- return;
- cache_->SetDeviceUnmanaged(false);
- SendPolicyRequest();
+ DCHECK(!TokenAvailable());
+ SetState(STATE_TOKEN_VALID);
}
void DeviceManagementPolicyProvider::OnTokenError() {
+ DCHECK(!TokenAvailable());
LOG(WARNING) << "Could not retrieve device token.";
- ScheduleRefreshTask(token_fetch_error_delay_ms_);
- token_fetch_error_delay_ms_ *= 2;
- if (token_fetch_error_delay_ms_ > policy_refresh_rate_ms_)
- token_fetch_error_delay_ms_ = policy_refresh_rate_ms_;
- StopWaitingForInitialPolicies();
+ SetState(STATE_TOKEN_ERROR);
}
void DeviceManagementPolicyProvider::OnNotManaged() {
+ DCHECK(!TokenAvailable());
VLOG(1) << "This device is not managed.";
- cache_->SetDeviceUnmanaged(true);
- ScheduleRefreshTask(unmanaged_device_refresh_rate_ms_);
- StopWaitingForInitialPolicies();
+ cache_->SetDeviceUnmanaged();
+ SetState(STATE_UNMANAGED);
}
-void DeviceManagementPolicyProvider::AddObserver(
- ConfigurationPolicyProvider::Observer* observer) {
- observer_list_.AddObserver(observer);
-}
+void DeviceManagementPolicyProvider::SetRefreshRate(
+ int64 refresh_rate_milliseconds) {
+ policy_refresh_rate_ms_ = refresh_rate_milliseconds;
-void DeviceManagementPolicyProvider::RemoveObserver(
- ConfigurationPolicyProvider::Observer* observer) {
- observer_list_.RemoveObserver(observer);
+ // Reschedule the refresh task if necessary.
+ if (state_ == STATE_POLICY_VALID)
+ SetState(STATE_POLICY_VALID);
}
-void DeviceManagementPolicyProvider::NotifyCloudPolicyUpdate() {
- FOR_EACH_OBSERVER(ConfigurationPolicyProvider::Observer,
- observer_list_,
- OnUpdatePolicy());
+DeviceManagementPolicyProvider::DeviceManagementPolicyProvider(
+ const PolicyDefinitionList* policy_list,
+ DeviceManagementBackend* backend,
+ Profile* profile,
+ int64 policy_refresh_rate_ms,
+ int policy_refresh_deviation_factor_percent,
+ int64 policy_refresh_deviation_max_ms,
+ int64 policy_refresh_error_delay_ms,
+ int64 token_fetch_error_delay_ms,
+ int64 unmanaged_device_refresh_rate_ms)
+ : ConfigurationPolicyProvider(policy_list) {
+ Initialize(backend,
+ profile,
+ policy_refresh_rate_ms,
+ policy_refresh_deviation_factor_percent,
+ policy_refresh_deviation_max_ms,
+ policy_refresh_error_delay_ms,
+ token_fetch_error_delay_ms,
+ unmanaged_device_refresh_rate_ms);
}
void DeviceManagementPolicyProvider::Initialize(
DeviceManagementBackend* backend,
Profile* profile,
int64 policy_refresh_rate_ms,
- int64 policy_refresh_max_earlier_ms,
+ int policy_refresh_deviation_factor_percent,
+ int64 policy_refresh_deviation_max_ms,
int64 policy_refresh_error_delay_ms,
int64 token_fetch_error_delay_ms,
int64 unmanaged_device_refresh_rate_ms) {
+ DCHECK(profile);
backend_.reset(backend);
profile_ = profile;
storage_dir_ = GetOrCreateDeviceManagementDir(profile_->GetPath());
- policy_request_pending_ = false;
- refresh_task_pending_ = false;
- waiting_for_initial_policies_ = true;
+ state_ = STATE_INITIALIZING;
+ initial_fetch_done_ = false;
+ refresh_task_ = NULL;
policy_refresh_rate_ms_ = policy_refresh_rate_ms;
- policy_refresh_max_earlier_ms_ = policy_refresh_max_earlier_ms;
+ policy_refresh_deviation_factor_percent_ =
+ policy_refresh_deviation_factor_percent;
+ policy_refresh_deviation_max_ms_ = policy_refresh_deviation_max_ms;
policy_refresh_error_delay_ms_ = policy_refresh_error_delay_ms;
+ effective_policy_refresh_error_delay_ms_ = policy_refresh_error_delay_ms;
token_fetch_error_delay_ms_ = token_fetch_error_delay_ms;
+ effective_token_fetch_error_delay_ms_ = token_fetch_error_delay_ms;
unmanaged_device_refresh_rate_ms_ = unmanaged_device_refresh_rate_ms;
const FilePath policy_path = storage_dir_.Append(kPolicyFilename);
cache_.reset(new DeviceManagementPolicyCache(policy_path));
cache_->LoadPolicyFromFile();
+ SetDeviceTokenFetcher(new DeviceTokenFetcher(backend_.get(), profile,
+ GetTokenPath()));
+
if (cache_->is_device_unmanaged()) {
// This is a non-first login on an unmanaged device.
- waiting_for_initial_policies_ = false;
- // Defer token_fetcher_ initialization until this device should ask for
- // a device token again.
- base::Time unmanaged_timestamp = cache_->last_policy_refresh_time();
- int64 delay = unmanaged_device_refresh_rate_ms_ -
- (base::Time::NowFromSystemTime().ToInternalValue() -
- unmanaged_timestamp.ToInternalValue());
- if (delay < 0)
- delay = 0;
- BrowserThread::PostDelayedTask(
- BrowserThread::UI, FROM_HERE,
- new InitializeAfterIOThreadExistsTask(AsWeakPtr()),
- delay);
+ SetState(STATE_UNMANAGED);
} else {
- if (file_util::PathExists(
- storage_dir_.Append(kDeviceTokenFilename))) {
- // This is a non-first login on a managed device.
- waiting_for_initial_policies_ = false;
- }
- // Defer initialization that requires the IOThread until after the IOThread
- // has been initialized.
- BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
- new InitializeAfterIOThreadExistsTask(AsWeakPtr()));
+ SetState(STATE_INITIALIZING);
}
}
-void DeviceManagementPolicyProvider::InitializeAfterIOThreadExists() {
- if (profile_) {
- if (!token_fetcher_) {
- token_fetcher_ = new DeviceTokenFetcher(
- backend_.get(), profile_, GetTokenPath());
- }
- registrar_.Init(token_fetcher_);
- registrar_.AddObserver(this);
- token_fetcher_->StartFetching();
- }
+void DeviceManagementPolicyProvider::AddObserver(
+ ConfigurationPolicyProvider::Observer* observer) {
+ observer_list_.AddObserver(observer);
}
-void DeviceManagementPolicyProvider::SendPolicyRequest() {
- if (policy_request_pending_)
- return;
+void DeviceManagementPolicyProvider::RemoveObserver(
+ ConfigurationPolicyProvider::Observer* observer) {
+ observer_list_.RemoveObserver(observer);
+}
- policy_request_pending_ = true;
+void DeviceManagementPolicyProvider::SendPolicyRequest() {
em::DevicePolicyRequest policy_request;
policy_request.set_policy_scope(kChromePolicyScope);
em::DevicePolicySettingRequest* setting =
@@ -284,40 +238,39 @@ void DeviceManagementPolicyProvider::SendPolicyRequest() {
}
void DeviceManagementPolicyProvider::RefreshTaskExecute() {
- DCHECK(refresh_task_pending_);
- refresh_task_pending_ = false;
- // If there is no valid device token, the token_fetcher_ apparently failed,
- // so it must be restarted.
- if (!token_fetcher_->IsTokenValid()) {
- if (token_fetcher_->IsTokenPending()) {
- NOTREACHED();
+ DCHECK(refresh_task_);
+ refresh_task_ = NULL;
+
+ switch (state_) {
+ case STATE_INITIALIZING:
+ token_fetcher_->StartFetching();
+ return;
+ case STATE_TOKEN_VALID:
+ case STATE_POLICY_VALID:
+ case STATE_POLICY_ERROR:
+ SendPolicyRequest();
+ return;
+ case STATE_UNMANAGED:
+ case STATE_TOKEN_ERROR:
+ case STATE_TOKEN_RESET:
+ token_fetcher_->Restart();
return;
- }
- token_fetcher_->Restart();
- return;
}
- // If there is a device token, just refresh policies.
- SendPolicyRequest();
+
+ NOTREACHED() << "Unhandled state";
}
-void DeviceManagementPolicyProvider::ScheduleRefreshTask(
- int64 delay_in_milliseconds) {
- // This check is simply a safeguard, the situation currently cannot happen.
- if (refresh_task_pending_) {
- NOTREACHED();
- return;
+void DeviceManagementPolicyProvider::CancelRefreshTask() {
+ if (refresh_task_) {
+ refresh_task_->Cancel();
+ refresh_task_ = NULL;
}
- refresh_task_pending_ = true;
- BrowserThread::PostDelayedTask(BrowserThread::UI, FROM_HERE,
- new RefreshTask(AsWeakPtr()),
- delay_in_milliseconds);
}
-int64 DeviceManagementPolicyProvider::GetRefreshTaskDelay() {
- int64 delay = policy_refresh_rate_ms_;
- if (policy_refresh_max_earlier_ms_)
- delay -= base::RandGenerator(policy_refresh_max_earlier_ms_);
- return delay;
+void DeviceManagementPolicyProvider::NotifyCloudPolicyUpdate() {
+ FOR_EACH_OBSERVER(ConfigurationPolicyProvider::Observer,
+ observer_list_,
+ OnUpdatePolicy());
}
FilePath DeviceManagementPolicyProvider::GetTokenPath() {
@@ -326,14 +279,88 @@ FilePath DeviceManagementPolicyProvider::GetTokenPath() {
void DeviceManagementPolicyProvider::SetDeviceTokenFetcher(
DeviceTokenFetcher* token_fetcher) {
- DCHECK(!token_fetcher_);
+ registrar_.Init(token_fetcher);
+ registrar_.AddObserver(this);
token_fetcher_ = token_fetcher;
}
-void DeviceManagementPolicyProvider::StopWaitingForInitialPolicies() {
- waiting_for_initial_policies_ = false;
- // Notify observers that initial policy fetch is complete.
- NotifyCloudPolicyUpdate();
+void DeviceManagementPolicyProvider::SetState(
+ DeviceManagementPolicyProvider::ProviderState new_state) {
+ state_ = new_state;
+
+ // If this state transition completes the initial policy fetch, let the
+ // observers now.
+ if (!initial_fetch_done_ &&
+ new_state != STATE_INITIALIZING &&
+ new_state != STATE_TOKEN_VALID) {
+ initial_fetch_done_ = true;
+ NotifyCloudPolicyUpdate();
+ }
+
+ base::Time now(base::Time::NowFromSystemTime());
+ base::Time refresh_at;
+ base::Time last_refresh(cache_->last_policy_refresh_time());
+ if (last_refresh.is_null())
+ last_refresh = now;
+
+ // Determine when to take the next step.
+ switch (state_) {
+ case STATE_INITIALIZING:
+ refresh_at = now;
+ break;
+ case STATE_TOKEN_VALID:
+ effective_token_fetch_error_delay_ms_ = token_fetch_error_delay_ms_;
+ refresh_at = now;
+ break;
+ case STATE_TOKEN_RESET:
+ refresh_at = now;
+ break;
+ case STATE_UNMANAGED:
+ refresh_at = last_refresh +
+ base::TimeDelta::FromMilliseconds(unmanaged_device_refresh_rate_ms_);
+ break;
+ case STATE_POLICY_VALID:
+ effective_policy_refresh_error_delay_ms_ = policy_refresh_error_delay_ms_;
+ refresh_at =
+ last_refresh + base::TimeDelta::FromMilliseconds(GetRefreshDelay());
+ break;
+ case STATE_TOKEN_ERROR:
+ refresh_at = now + base::TimeDelta::FromMilliseconds(
+ effective_token_fetch_error_delay_ms_);
+ effective_token_fetch_error_delay_ms_ *= 2;
+ if (effective_token_fetch_error_delay_ms_ > policy_refresh_rate_ms_)
+ effective_token_fetch_error_delay_ms_ = policy_refresh_rate_ms_;
+ break;
+ case STATE_POLICY_ERROR:
+ refresh_at = now + base::TimeDelta::FromMilliseconds(
+ effective_policy_refresh_error_delay_ms_);
+ effective_policy_refresh_error_delay_ms_ *= 2;
+ if (effective_policy_refresh_error_delay_ms_ > policy_refresh_rate_ms_)
+ effective_policy_refresh_error_delay_ms_ = policy_refresh_rate_ms_;
+ break;
+ }
+
+ // Update the refresh task.
+ CancelRefreshTask();
+ if (!refresh_at.is_null()) {
+ refresh_task_ = new RefreshTask(this);
+ int64 delay = std::max<int64>((refresh_at - now).InMilliseconds(), 0);
+ BrowserThread::PostDelayedTask(BrowserThread::UI, FROM_HERE, refresh_task_,
+ delay);
+ }
+}
+
+int64 DeviceManagementPolicyProvider::GetRefreshDelay() {
+ int64 deviation = (policy_refresh_deviation_factor_percent_ *
+ policy_refresh_rate_ms_) / 100;
+ deviation = std::min(deviation, policy_refresh_deviation_max_ms_);
+ return policy_refresh_rate_ms_ - base::RandGenerator(deviation + 1);
+}
+
+bool DeviceManagementPolicyProvider::TokenAvailable() const {
+ return state_ == STATE_TOKEN_VALID ||
+ state_ == STATE_POLICY_VALID ||
+ state_ == STATE_POLICY_ERROR;
}
// static
diff --git a/chrome/browser/policy/device_management_policy_provider.h b/chrome/browser/policy/device_management_policy_provider.h
index fd18bc3..592df9b 100644
--- a/chrome/browser/policy/device_management_policy_provider.h
+++ b/chrome/browser/policy/device_management_policy_provider.h
@@ -12,7 +12,6 @@
#include "base/observer_list.h"
#include "base/scoped_ptr.h"
#include "base/time.h"
-#include "base/weak_ptr.h"
#include "chrome/browser/policy/configuration_policy_provider.h"
#include "chrome/browser/policy/device_management_backend.h"
#include "chrome/browser/policy/device_token_fetcher.h"
@@ -31,7 +30,6 @@ class DeviceManagementPolicyCache;
class DeviceManagementPolicyProvider
: public ConfigurationPolicyProvider,
public DeviceManagementBackend::DevicePolicyResponseDelegate,
- public base::SupportsWeakPtr<DeviceManagementPolicyProvider>,
public DeviceTokenFetcher::Observer {
public:
DeviceManagementPolicyProvider(const PolicyDefinitionList* policy_list,
@@ -54,8 +52,28 @@ class DeviceManagementPolicyProvider
virtual void OnTokenError();
virtual void OnNotManaged();
+ // Sets the refresh rate at which to re-fetch policy information.
+ void SetRefreshRate(int64 refresh_rate_milliseconds);
+
private:
- class InitializeAfterIOThreadExistsTask;
+ // Indicates the current state the provider is in.
+ enum ProviderState {
+ // The provider is initializing, policy information not yet available.
+ STATE_INITIALIZING,
+ // This device is not managed through policy.
+ STATE_UNMANAGED,
+ // The token is valid, but policy is yet to be fetched.
+ STATE_TOKEN_VALID,
+ // Policy information is available and valid.
+ STATE_POLICY_VALID,
+ // The token was found to be invalid and needs to be obtained again.
+ STATE_TOKEN_RESET,
+ // There has been an error fetching the token, retry later.
+ STATE_TOKEN_ERROR,
+ // The service returned an error when requesting policy, ask again later.
+ STATE_POLICY_ERROR,
+ };
+
class RefreshTask;
friend class DeviceManagementPolicyProviderTest;
@@ -65,7 +83,8 @@ class DeviceManagementPolicyProvider
DeviceManagementBackend* backend,
Profile* profile,
int64 policy_refresh_rate_ms,
- int64 policy_refresh_max_earlier_ms,
+ int policy_refresh_deviation_factor_percent,
+ int64 policy_refresh_deviation_max_ms,
int64 policy_refresh_error_delay_ms,
int64 token_fetch_error_delay_ms,
int64 unmanaged_device_refresh_rate_ms);
@@ -77,15 +96,12 @@ class DeviceManagementPolicyProvider
void Initialize(DeviceManagementBackend* backend,
Profile* profile,
int64 policy_refresh_rate_ms,
- int64 policy_refresh_max_earlier_ms,
+ int policy_refresh_deviation_factor_percent,
+ int64 policy_refresh_deviation_max_ms,
int64 policy_refresh_error_delay_ms,
int64 token_fetch_error_delay_ms,
int64 unmanaged_device_refresh_rate_ms);
- // Called by a deferred task posted to the UI thread to complete the portion
- // of initialization that requires the IOThread.
- void InitializeAfterIOThreadExists();
-
// ConfigurationPolicyProvider overrides:
virtual void AddObserver(ConfigurationPolicyProvider::Observer* observer);
virtual void RemoveObserver(ConfigurationPolicyProvider::Observer* observer);
@@ -98,13 +114,8 @@ class DeviceManagementPolicyProvider
// as necessary.
void RefreshTaskExecute();
- // Schedules a new RefreshTask.
- void ScheduleRefreshTask(int64 delay_in_milliseconds);
-
- // Calculates when the next RefreshTask shall be executed.
- int64 GetRefreshTaskDelay();
-
- void StopWaitingForInitialPolicies();
+ // Cancels the refresh task.
+ void CancelRefreshTask();
// Notify observers about a policy update.
void NotifyCloudPolicyUpdate();
@@ -115,6 +126,15 @@ class DeviceManagementPolicyProvider
// Used only by tests.
void SetDeviceTokenFetcher(DeviceTokenFetcher* token_fetcher);
+ // Switches to a new state and triggers any appropriate actions.
+ void SetState(ProviderState new_state);
+
+ // Check whether the current state is one in which the token is available.
+ bool TokenAvailable() const;
+
+ // Computes the refresh delay to use.
+ int64 GetRefreshDelay();
+
// Provides the URL at which requests are sent to from the device management
// backend.
static std::string GetDeviceManagementURL();
@@ -131,13 +151,16 @@ class DeviceManagementPolicyProvider
DeviceTokenFetcher::ObserverRegistrar registrar_;
ObserverList<ConfigurationPolicyProvider::Observer, true> observer_list_;
FilePath storage_dir_;
- bool policy_request_pending_;
- bool refresh_task_pending_;
- bool waiting_for_initial_policies_;
+ ProviderState state_;
+ bool initial_fetch_done_;
+ RefreshTask* refresh_task_;
int64 policy_refresh_rate_ms_;
- int64 policy_refresh_max_earlier_ms_;
+ int policy_refresh_deviation_factor_percent_;
+ int64 policy_refresh_deviation_max_ms_;
int64 policy_refresh_error_delay_ms_;
+ int64 effective_policy_refresh_error_delay_ms_;
int64 token_fetch_error_delay_ms_;
+ int64 effective_token_fetch_error_delay_ms_;
int64 unmanaged_device_refresh_rate_ms_;
DISALLOW_COPY_AND_ASSIGN(DeviceManagementPolicyProvider);
diff --git a/chrome/browser/policy/device_management_policy_provider_unittest.cc b/chrome/browser/policy/device_management_policy_provider_unittest.cc
index eac2c5b..55ba883 100644
--- a/chrome/browser/policy/device_management_policy_provider_unittest.cc
+++ b/chrome/browser/policy/device_management_policy_provider_unittest.cc
@@ -27,6 +27,7 @@ const char kTestToken[] = "device_policy_provider_test_auth_token";
namespace policy {
using ::testing::_;
+using ::testing::AtLeast;
using ::testing::InSequence;
using ::testing::Mock;
@@ -65,7 +66,8 @@ class DeviceManagementPolicyProviderTest : public testing::Test {
}
void CreateNewProvider(int64 policy_refresh_rate_ms,
- int64 policy_refresh_max_earlier_ms,
+ int policy_refresh_fuzz_factor_percent,
+ int64 policy_refresh_fuzz_max,
int64 policy_refresh_error_delay_ms,
int64 token_fetch_error_delay_ms,
int64 unmanaged_device_refresh_rate_ms) {
@@ -75,7 +77,8 @@ class DeviceManagementPolicyProviderTest : public testing::Test {
backend_,
profile_.get(),
policy_refresh_rate_ms,
- policy_refresh_max_earlier_ms,
+ policy_refresh_fuzz_factor_percent,
+ policy_refresh_fuzz_max,
policy_refresh_error_delay_ms,
token_fetch_error_delay_ms,
unmanaged_device_refresh_rate_ms));
@@ -90,6 +93,12 @@ class DeviceManagementPolicyProviderTest : public testing::Test {
}
void SimulateSuccessfulLoginAndRunPending() {
+ // Make sure the notification for the initial policy fetch is generated.
+ MockConfigurationPolicyObserver observer;
+ ConfigurationPolicyObserverRegistrar registrar;
+ registrar.Init(provider_.get(), &observer);
+ EXPECT_CALL(observer, OnUpdatePolicy()).Times(AtLeast(1));
+
loop_.RunAllPending();
profile_->GetTokenService()->IssueAuthTokenForTest(
GaiaConstants::kDeviceManagementService, kTestToken);
@@ -117,11 +126,12 @@ class DeviceManagementPolicyProviderTest : public testing::Test {
}
virtual void TearDown() {
+ provider_.reset();
loop_.RunAllPending();
}
bool waiting_for_initial_policies() const {
- return provider_->waiting_for_initial_policies_;
+ return !provider_->IsInitializationComplete();
}
MockDeviceManagementBackend* backend_; // weak
@@ -196,7 +206,6 @@ TEST_F(DeviceManagementPolicyProviderTest, SecondProvide) {
EXPECT_CALL(*backend_, ProcessPolicyRequest(_, _, _, _)).WillOnce(
MockDeviceManagementBackendFailPolicy(
DeviceManagementBackend::kErrorRequestFailed));
- loop_.RunAllPending();
SimulateSuccessfulLoginAndRunPending();
EXPECT_CALL(store, Apply(kPolicyDisableSpdy, _)).Times(1);
provider_->Provide(&store);
@@ -214,90 +223,108 @@ TEST_F(DeviceManagementPolicyProviderTest, FetchTriggersRefresh) {
}
TEST_F(DeviceManagementPolicyProviderTest, ErrorCausesNewRequest) {
- InSequence s;
- CreateNewProvider(1000 * 1000, 0, 0, 0, 0);
- EXPECT_CALL(*backend_, ProcessRegisterRequest(_, _, _, _)).WillOnce(
- MockDeviceManagementBackendFailRegister(
- DeviceManagementBackend::kErrorRequestFailed));
- EXPECT_CALL(*backend_, ProcessRegisterRequest(_, _, _, _)).WillOnce(
- MockDeviceManagementBackendSucceedRegister());
- EXPECT_CALL(*backend_, ProcessPolicyRequest(_, _, _, _)).WillOnce(
- MockDeviceManagementBackendFailPolicy(
- DeviceManagementBackend::kErrorRequestFailed));
- EXPECT_CALL(*backend_, ProcessPolicyRequest(_, _, _, _)).WillOnce(
- MockDeviceManagementBackendFailPolicy(
- DeviceManagementBackend::kErrorRequestFailed));
- EXPECT_CALL(*backend_, ProcessPolicyRequest(_, _, _, _)).WillOnce(
- MockDeviceManagementBackendSucceedBooleanPolicy(key::kDisableSpdy, true));
+ { // Scoping so SimulateSuccessfulLoginAndRunPending doesn't see the sequence.
+ InSequence s;
+ CreateNewProvider(1000 * 1000, 0, 0, 0, 0, 0);
+ EXPECT_CALL(*backend_, ProcessRegisterRequest(_, _, _, _)).WillOnce(
+ MockDeviceManagementBackendFailRegister(
+ DeviceManagementBackend::kErrorRequestFailed));
+ EXPECT_CALL(*backend_, ProcessRegisterRequest(_, _, _, _)).WillOnce(
+ MockDeviceManagementBackendSucceedRegister());
+ EXPECT_CALL(*backend_, ProcessPolicyRequest(_, _, _, _)).WillOnce(
+ MockDeviceManagementBackendFailPolicy(
+ DeviceManagementBackend::kErrorRequestFailed));
+ EXPECT_CALL(*backend_, ProcessPolicyRequest(_, _, _, _)).WillOnce(
+ MockDeviceManagementBackendFailPolicy(
+ DeviceManagementBackend::kErrorRequestFailed));
+ EXPECT_CALL(*backend_, ProcessPolicyRequest(_, _, _, _)).WillOnce(
+ MockDeviceManagementBackendSucceedBooleanPolicy(key::kDisableSpdy,
+ true));
+ }
SimulateSuccessfulLoginAndRunPending();
}
TEST_F(DeviceManagementPolicyProviderTest, RefreshPolicies) {
- InSequence s;
- CreateNewProvider(0, 0, 1000 * 1000, 1000, 0);
- EXPECT_CALL(*backend_, ProcessRegisterRequest(_, _, _, _)).WillOnce(
- MockDeviceManagementBackendSucceedRegister());
- EXPECT_CALL(*backend_, ProcessPolicyRequest(_, _, _, _)).WillOnce(
- MockDeviceManagementBackendSucceedBooleanPolicy(key::kDisableSpdy, true));
- EXPECT_CALL(*backend_, ProcessPolicyRequest(_, _, _, _)).WillOnce(
- MockDeviceManagementBackendSucceedBooleanPolicy(key::kDisableSpdy, true));
- EXPECT_CALL(*backend_, ProcessPolicyRequest(_, _, _, _)).WillOnce(
- MockDeviceManagementBackendSucceedBooleanPolicy(key::kDisableSpdy, true));
- EXPECT_CALL(*backend_, ProcessPolicyRequest(_, _, _, _)).WillOnce(
- MockDeviceManagementBackendFailPolicy(
- DeviceManagementBackend::kErrorRequestFailed));
+ { // Scoping so SimulateSuccessfulLoginAndRunPending doesn't see the sequence.
+ InSequence s;
+ CreateNewProvider(0, 0, 0, 1000 * 1000, 1000, 0);
+ EXPECT_CALL(*backend_, ProcessRegisterRequest(_, _, _, _)).WillOnce(
+ MockDeviceManagementBackendSucceedRegister());
+ EXPECT_CALL(*backend_, ProcessPolicyRequest(_, _, _, _)).WillOnce(
+ MockDeviceManagementBackendSucceedBooleanPolicy(key::kDisableSpdy,
+ true));
+ EXPECT_CALL(*backend_, ProcessPolicyRequest(_, _, _, _)).WillOnce(
+ MockDeviceManagementBackendSucceedBooleanPolicy(key::kDisableSpdy,
+ true));
+ EXPECT_CALL(*backend_, ProcessPolicyRequest(_, _, _, _)).WillOnce(
+ MockDeviceManagementBackendSucceedBooleanPolicy(key::kDisableSpdy,
+ true));
+ EXPECT_CALL(*backend_, ProcessPolicyRequest(_, _, _, _)).WillOnce(
+ MockDeviceManagementBackendFailPolicy(
+ DeviceManagementBackend::kErrorRequestFailed));
+ }
SimulateSuccessfulLoginAndRunPending();
}
// The client should try to re-register the device if the device server reports
// back that it doesn't recognize the device token on a policy request.
TEST_F(DeviceManagementPolicyProviderTest, DeviceNotFound) {
- InSequence s;
- EXPECT_CALL(*backend_, ProcessRegisterRequest(_, _, _, _)).WillOnce(
- MockDeviceManagementBackendSucceedRegister());
- EXPECT_CALL(*backend_, ProcessPolicyRequest(_, _, _, _)).WillOnce(
- MockDeviceManagementBackendFailPolicy(
- DeviceManagementBackend::kErrorServiceDeviceNotFound));
- EXPECT_CALL(*backend_, ProcessRegisterRequest(_, _, _, _)).WillOnce(
- MockDeviceManagementBackendSucceedRegister());
- EXPECT_CALL(*backend_, ProcessPolicyRequest(_, _, _, _)).WillOnce(
- MockDeviceManagementBackendSucceedBooleanPolicy(key::kDisableSpdy, true));
+ { // Scoping so SimulateSuccessfulLoginAndRunPending doesn't see the sequence.
+ InSequence s;
+ EXPECT_CALL(*backend_, ProcessRegisterRequest(_, _, _, _)).WillOnce(
+ MockDeviceManagementBackendSucceedRegister());
+ EXPECT_CALL(*backend_, ProcessPolicyRequest(_, _, _, _)).WillOnce(
+ MockDeviceManagementBackendFailPolicy(
+ DeviceManagementBackend::kErrorServiceDeviceNotFound));
+ EXPECT_CALL(*backend_, ProcessRegisterRequest(_, _, _, _)).WillOnce(
+ MockDeviceManagementBackendSucceedRegister());
+ EXPECT_CALL(*backend_, ProcessPolicyRequest(_, _, _, _)).WillOnce(
+ MockDeviceManagementBackendSucceedBooleanPolicy(key::kDisableSpdy,
+ true));
+ }
SimulateSuccessfulLoginAndRunPending();
}
// The client should try to re-register the device if the device server reports
// back that the device token is invalid on a policy request.
TEST_F(DeviceManagementPolicyProviderTest, InvalidTokenOnPolicyRequest) {
- InSequence s;
- EXPECT_CALL(*backend_, ProcessRegisterRequest(_, _, _, _)).WillOnce(
- MockDeviceManagementBackendSucceedRegister());
- EXPECT_CALL(*backend_, ProcessPolicyRequest(_, _, _, _)).WillOnce(
- MockDeviceManagementBackendFailPolicy(
- DeviceManagementBackend::kErrorServiceManagementTokenInvalid));
- EXPECT_CALL(*backend_, ProcessRegisterRequest(_, _, _, _)).WillOnce(
- MockDeviceManagementBackendSucceedRegister());
- EXPECT_CALL(*backend_, ProcessPolicyRequest(_, _, _, _)).WillOnce(
- MockDeviceManagementBackendSucceedBooleanPolicy(key::kDisableSpdy, true));
+ { // Scoping so SimulateSuccessfulLoginAndRunPending doesn't see the sequence.
+ InSequence s;
+ EXPECT_CALL(*backend_, ProcessRegisterRequest(_, _, _, _)).WillOnce(
+ MockDeviceManagementBackendSucceedRegister());
+ EXPECT_CALL(*backend_, ProcessPolicyRequest(_, _, _, _)).WillOnce(
+ MockDeviceManagementBackendFailPolicy(
+ DeviceManagementBackend::kErrorServiceManagementTokenInvalid));
+ EXPECT_CALL(*backend_, ProcessRegisterRequest(_, _, _, _)).WillOnce(
+ MockDeviceManagementBackendSucceedRegister());
+ EXPECT_CALL(*backend_, ProcessPolicyRequest(_, _, _, _)).WillOnce(
+ MockDeviceManagementBackendSucceedBooleanPolicy(key::kDisableSpdy,
+ true));
+ }
SimulateSuccessfulLoginAndRunPending();
}
// If the client is successfully managed, but the admin stops managing the
// device, the client should notice and throw away the device token and id.
TEST_F(DeviceManagementPolicyProviderTest, DeviceNoLongerManaged) {
- InSequence s;
- CreateNewProvider(0, 0, 0, 0, 1000 * 1000);
- EXPECT_CALL(*backend_, ProcessRegisterRequest(_, _, _, _)).WillOnce(
- MockDeviceManagementBackendSucceedRegister());
- EXPECT_CALL(*backend_, ProcessPolicyRequest(_, _, _, _)).WillOnce(
- MockDeviceManagementBackendSucceedBooleanPolicy(key::kDisableSpdy, true));
- EXPECT_CALL(*backend_, ProcessPolicyRequest(_, _, _, _)).WillOnce(
- MockDeviceManagementBackendSucceedBooleanPolicy(key::kDisableSpdy, true));
- EXPECT_CALL(*backend_, ProcessPolicyRequest(_, _, _, _)).WillOnce(
- MockDeviceManagementBackendFailPolicy(
- DeviceManagementBackend::kErrorServiceManagementNotSupported));
- EXPECT_CALL(*backend_, ProcessRegisterRequest(_, _, _, _)).WillOnce(
- MockDeviceManagementBackendFailRegister(
- DeviceManagementBackend::kErrorServiceManagementNotSupported));
+ { // Scoping so SimulateSuccessfulLoginAndRunPending doesn't see the sequence.
+ InSequence s;
+ CreateNewProvider(0, 0, 0, 0, 0, 1000 * 1000);
+ EXPECT_CALL(*backend_, ProcessRegisterRequest(_, _, _, _)).WillOnce(
+ MockDeviceManagementBackendSucceedRegister());
+ EXPECT_CALL(*backend_, ProcessPolicyRequest(_, _, _, _)).WillOnce(
+ MockDeviceManagementBackendSucceedBooleanPolicy(key::kDisableSpdy,
+ true));
+ EXPECT_CALL(*backend_, ProcessPolicyRequest(_, _, _, _)).WillOnce(
+ MockDeviceManagementBackendSucceedBooleanPolicy(key::kDisableSpdy,
+ true));
+ EXPECT_CALL(*backend_, ProcessPolicyRequest(_, _, _, _)).WillOnce(
+ MockDeviceManagementBackendFailPolicy(
+ DeviceManagementBackend::kErrorServiceManagementNotSupported));
+ EXPECT_CALL(*backend_, ProcessRegisterRequest(_, _, _, _)).WillOnce(
+ MockDeviceManagementBackendFailRegister(
+ DeviceManagementBackend::kErrorServiceManagementNotSupported));
+ }
SimulateSuccessfulLoginAndRunPending();
FilePath token_path(GetTokenPath());
EXPECT_FALSE(file_util::PathExists(token_path));
@@ -305,22 +332,28 @@ TEST_F(DeviceManagementPolicyProviderTest, DeviceNoLongerManaged) {
// This test tests three things (see numbered comments below):
TEST_F(DeviceManagementPolicyProviderTest, UnmanagedDevice) {
- InSequence s;
- EXPECT_CALL(*backend_, ProcessRegisterRequest(_, _, _, _)).WillOnce(
- MockDeviceManagementBackendFailRegister(
- DeviceManagementBackend::kErrorServiceManagementNotSupported));
+ { // Scoping so SimulateSuccessfulLoginAndRunPending doesn't see the sequence.
+ InSequence s;
+ EXPECT_CALL(*backend_, ProcessRegisterRequest(_, _, _, _)).WillOnce(
+ MockDeviceManagementBackendFailRegister(
+ DeviceManagementBackend::kErrorServiceManagementNotSupported));
+ }
SimulateSuccessfulLoginAndRunPending();
// (1) The provider's DMPolicyCache should know that the device is not
// managed.
EXPECT_TRUE(cache(provider_.get())->is_device_unmanaged());
// (2) On restart, the provider should detect that this is not the first
// login.
- CreateNewProvider(1000*1000, 0, 0, 0, 0);
+ CreateNewProvider(1000 * 1000, 0, 0, 0, 0, 0);
EXPECT_FALSE(waiting_for_initial_policies());
- EXPECT_CALL(*backend_, ProcessRegisterRequest(_, _, _, _)).WillOnce(
- MockDeviceManagementBackendSucceedRegister());
- EXPECT_CALL(*backend_, ProcessPolicyRequest(_, _, _, _)).WillOnce(
- MockDeviceManagementBackendSucceedBooleanPolicy(key::kDisableSpdy, true));
+ { // Scoping so SimulateSuccessfulLoginAndRunPending doesn't see the sequence.
+ InSequence s;
+ EXPECT_CALL(*backend_, ProcessRegisterRequest(_, _, _, _)).WillOnce(
+ MockDeviceManagementBackendSucceedRegister());
+ EXPECT_CALL(*backend_, ProcessPolicyRequest(_, _, _, _)).WillOnce(
+ MockDeviceManagementBackendSucceedBooleanPolicy(key::kDisableSpdy,
+ true));
+ }
SimulateSuccessfulLoginAndRunPending();
// (3) Since the backend call this time returned a device id, the "unmanaged"
// marker should have been deleted.
diff --git a/chrome/browser/policy/device_token_fetcher.cc b/chrome/browser/policy/device_token_fetcher.cc
index 2d514b6..3f977c1 100644
--- a/chrome/browser/policy/device_token_fetcher.cc
+++ b/chrome/browser/policy/device_token_fetcher.cc
@@ -65,6 +65,7 @@ DeviceTokenFetcher::ObserverRegistrar::~ObserverRegistrar() {
void DeviceTokenFetcher::ObserverRegistrar::Init(
DeviceTokenFetcher* token_fetcher) {
+ RemoveAll();
token_fetcher_ = token_fetcher;
}
@@ -192,7 +193,11 @@ void DeviceTokenFetcher::OnError(DeviceManagementBackend::ErrorCode code) {
}
void DeviceTokenFetcher::Restart() {
- DCHECK(!IsTokenPending());
+ // Complain if there's currently an asynchronous operation going on.
+ DCHECK(state_ == kStateNotStarted ||
+ state_ == kStateHasDeviceToken ||
+ state_ == kStateFailure ||
+ state_ == kStateNotManaged);
device_token_.clear();
device_token_load_complete_event_.Reset();
MakeReadyToRequestDeviceToken();
diff --git a/chrome/browser/policy/device_token_fetcher_unittest.cc b/chrome/browser/policy/device_token_fetcher_unittest.cc
index f4a7e23..28d11b0 100644
--- a/chrome/browser/policy/device_token_fetcher_unittest.cc
+++ b/chrome/browser/policy/device_token_fetcher_unittest.cc
@@ -224,4 +224,28 @@ TEST_F(DeviceTokenFetcherTest, FetchWithNonManagedUsername) {
ASSERT_FALSE(fetcher_->IsTokenValid());
}
+TEST_F(DeviceTokenFetcherTest, RestartImmediately) {
+ // Create a token.
+ EXPECT_CALL(*backend_, ProcessRegisterRequest(_, _, _, _)).WillOnce(
+ MockDeviceManagementBackendSucceedRegister());
+ SimulateSuccessfulLoginAndRunPending(kTestManagedDomainUsername);
+ ASSERT_FALSE(fetcher_->IsTokenPending());
+ std::string device_token = fetcher_->GetDeviceToken();
+
+ // Restart a new fetcher immediately without calling StartFetching(). The
+ // existing token should not be loaded, but rather a new token generated.
+ FilePath token_path;
+ GetDeviceTokenPath(fetcher_, &token_path);
+ scoped_refptr<TestingDeviceTokenFetcher> fetcher2(
+ new TestingDeviceTokenFetcher(
+ backend_.get(), profile_.get(), token_path));
+ fetcher2->Restart();
+ EXPECT_CALL(*backend_, ProcessRegisterRequest(_, _, _, _)).WillOnce(
+ MockDeviceManagementBackendSucceedRegister());
+ fetcher2->SimulateLogin(kTestManagedDomainUsername);
+ loop_.RunAllPending();
+ ASSERT_FALSE(fetcher2->IsTokenPending());
+ ASSERT_NE(device_token, fetcher2->GetDeviceToken());
+}
+
} // namespace policy
diff --git a/chrome/browser/policy/profile_policy_context.cc b/chrome/browser/policy/profile_policy_context.cc
index c221529..7adffd3 100644
--- a/chrome/browser/policy/profile_policy_context.cc
+++ b/chrome/browser/policy/profile_policy_context.cc
@@ -7,8 +7,20 @@
#include "chrome/browser/policy/device_management_policy_provider.h"
#include "chrome/browser/policy/device_management_service.h"
#include "chrome/browser/policy/profile_policy_context.h"
+#include "chrome/browser/prefs/pref_service.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/common/chrome_switches.h"
+#include "chrome/common/notification_details.h"
+#include "chrome/common/notification_source.h"
+#include "chrome/common/pref_names.h"
+
+namespace {
+
+// Refresh rate sanity interval bounds.
+const int64 kPolicyRefreshRateMinMs = 30 * 60 * 1000; // 30 minutes
+const int64 kPolicyRefreshRateMaxMs = 24 * 60 * 60 * 1000; // 1 day
+
+}
namespace policy {
@@ -34,6 +46,10 @@ ProfilePolicyContext::~ProfilePolicyContext() {
void ProfilePolicyContext::Initialize() {
if (device_management_service_.get())
device_management_service_->Initialize(profile_->GetRequestContext());
+
+ policy_refresh_rate_.Init(prefs::kPolicyRefreshRate, profile_->GetPrefs(),
+ this);
+ UpdatePolicyRefreshRate();
}
void ProfilePolicyContext::Shutdown() {
@@ -46,4 +62,32 @@ ProfilePolicyContext::GetDeviceManagementPolicyProvider() {
return device_management_policy_provider_.get();
}
+// static
+void ProfilePolicyContext::RegisterUserPrefs(PrefService* user_prefs) {
+ user_prefs->RegisterIntegerPref(prefs::kPolicyRefreshRate,
+ kDefaultPolicyRefreshRateInMilliseconds);
+}
+
+void ProfilePolicyContext::UpdatePolicyRefreshRate() {
+ if (device_management_policy_provider_.get()) {
+ // Clamp to sane values.
+ int64 refresh_rate = policy_refresh_rate_.GetValue();
+ refresh_rate = std::max(kPolicyRefreshRateMinMs, refresh_rate);
+ refresh_rate = std::min(kPolicyRefreshRateMaxMs, refresh_rate);
+ device_management_policy_provider_->SetRefreshRate(refresh_rate);
+ }
+}
+
+void ProfilePolicyContext::Observe(NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details) {
+ if (type == NotificationType::PREF_CHANGED &&
+ prefs::kPolicyRefreshRate == *(Details<std::string>(details).ptr()) &&
+ profile_->GetPrefs() == Source<PrefService>(source).ptr()) {
+ UpdatePolicyRefreshRate();
+ } else {
+ NOTREACHED();
+ }
+}
+
} // namespace policy
diff --git a/chrome/browser/policy/profile_policy_context.h b/chrome/browser/policy/profile_policy_context.h
index b343e15..8650ec5 100644
--- a/chrome/browser/policy/profile_policy_context.h
+++ b/chrome/browser/policy/profile_policy_context.h
@@ -7,6 +7,8 @@
#pragma once
#include "base/scoped_ptr.h"
+#include "chrome/browser/prefs/pref_member.h"
+#include "chrome/common/notification_observer.h"
class Profile;
@@ -19,7 +21,7 @@ class DeviceManagementService;
// profile. Since the context owns the policy provider, it's vital that it gets
// initialized before the profile's prefs and destroyed after the prefs are
// gone.
-class ProfilePolicyContext {
+class ProfilePolicyContext : public NotificationObserver {
public:
explicit ProfilePolicyContext(Profile* profile);
~ProfilePolicyContext();
@@ -35,10 +37,27 @@ class ProfilePolicyContext {
// Get the policy provider.
DeviceManagementPolicyProvider* GetDeviceManagementPolicyProvider();
+ // Register preferences.
+ static void RegisterUserPrefs(PrefService* user_prefs);
+
+ static const int kDefaultPolicyRefreshRateInMilliseconds =
+ 3 * 60 * 60 * 1000; // 3 hours.
+
private:
+ // Updates the policy provider with a new refresh rate value.
+ void UpdatePolicyRefreshRate();
+
+ // NotificationObserver overrides.
+ virtual void Observe(NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details);
+
// The profile this context is associated with.
Profile* profile_;
+ // Tracks the pref value for the policy refresh rate.
+ IntegerPrefMember policy_refresh_rate_;
+
// The device management service.
scoped_ptr<DeviceManagementService> device_management_service_;
diff --git a/chrome/browser/prefs/browser_prefs.cc b/chrome/browser/prefs/browser_prefs.cc
index 88e4b13..e098659 100644
--- a/chrome/browser/prefs/browser_prefs.cc
+++ b/chrome/browser/prefs/browser_prefs.cc
@@ -27,17 +27,18 @@
#include "chrome/browser/geolocation/geolocation_prefs.h"
#include "chrome/browser/google/google_url_tracker.h"
#include "chrome/browser/host_zoom_map.h"
-#include "chrome/browser/intranet_redirect_detector.h"
#include "chrome/browser/instant/instant_controller.h"
+#include "chrome/browser/intranet_redirect_detector.h"
#include "chrome/browser/metrics/metrics_log.h"
#include "chrome/browser/metrics/metrics_service.h"
+#include "chrome/browser/net/net_pref_observer.h"
#include "chrome/browser/net/predictor_api.h"
#include "chrome/browser/net/pref_proxy_config_service.h"
-#include "chrome/browser/net/net_pref_observer.h"
-#include "chrome/browser/notifications/notification_ui_manager.h"
#include "chrome/browser/notifications/desktop_notification_service.h"
+#include "chrome/browser/notifications/notification_ui_manager.h"
#include "chrome/browser/page_info_model.h"
#include "chrome/browser/password_manager/password_manager.h"
+#include "chrome/browser/policy/profile_policy_context.h"
#include "chrome/browser/prefs/session_startup_pref.h"
#include "chrome/browser/profiles/profile_impl.h"
#include "chrome/browser/renderer_host/browser_render_process_host.h"
@@ -155,6 +156,7 @@ void RegisterUserPrefs(PrefService* user_prefs) {
TemplateURLModel::RegisterUserPrefs(user_prefs);
InstantController::RegisterUserPrefs(user_prefs);
NetPrefObserver::RegisterPrefs(user_prefs);
+ policy::ProfilePolicyContext::RegisterUserPrefs(user_prefs);
}
} // namespace browser
diff --git a/chrome/common/policy_constants.cc b/chrome/common/policy_constants.cc
index 032c07a..f02264c 100644
--- a/chrome/common/policy_constants.cc
+++ b/chrome/common/policy_constants.cc
@@ -76,6 +76,7 @@ const char kAuthServerWhitelist[] = "AuthServerWhitelist";
const char kAuthNegotiateDelegateWhitelist[] = "AuthNegotiateDelegateWhitelist";
const char kGSSAPILibraryName[] = "GSSAPILibraryName";
const char kDisable3DAPIs[] = "Disable3DAPIs";
+const char kPolicyRefreshRate[] = "PolicyRefreshRate";
// Chrome Frame specific policy constants
const char kChromeFrameRendererSettings[] = "ChromeFrameRendererSettings";
diff --git a/chrome/common/policy_constants.h b/chrome/common/policy_constants.h
index fae7c8b..22a41ba 100644
--- a/chrome/common/policy_constants.h
+++ b/chrome/common/policy_constants.h
@@ -70,6 +70,7 @@ extern const char kAuthServerWhitelist[];
extern const char kAuthNegotiateDelegateWhitelist[];
extern const char kGSSAPILibraryName[];
extern const char kDisable3DAPIs[];
+extern const char kPolicyRefreshRate[];
// Chrome Frame specific policy constants
extern const char kChromeFrameRendererSettings[];
diff --git a/chrome/common/pref_names.cc b/chrome/common/pref_names.cc
index b5c04be..e93d7af 100644
--- a/chrome/common/pref_names.cc
+++ b/chrome/common/pref_names.cc
@@ -635,6 +635,11 @@ const char kEnableTranslate[] = "translate.enabled";
const char kPinnedTabs[] = "pinned_tabs";
+// Integer that specifies the policy refresh rate in milliseconds. Not all
+// values are meaningful, so it is clamped to a sane range by the policy
+// provider.
+const char kPolicyRefreshRate[] = "policy.refresh_rate";
+
// Integer containing the default Geolocation content setting.
const char kGeolocationDefaultContentSetting[] =
"geolocation.default_content_setting";
diff --git a/chrome/common/pref_names.h b/chrome/common/pref_names.h
index 930e69a..846e6e9 100644
--- a/chrome/common/pref_names.h
+++ b/chrome/common/pref_names.h
@@ -234,6 +234,7 @@ extern const char kAutoFillPersonalDataManagerFirstRun[];
extern const char kUseVerticalTabs[];
extern const char kEnableTranslate[];
extern const char kPinnedTabs[];
+extern const char kPolicyRefreshRate[];
// Local state
extern const char kMetricsClientID[];