summaryrefslogtreecommitdiffstats
path: root/chrome/browser/policy/config_dir_policy_provider.cc
diff options
context:
space:
mode:
authormnissler@chromium.org <mnissler@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-10-29 13:09:55 +0000
committermnissler@chromium.org <mnissler@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-10-29 13:09:55 +0000
commit7c5972380d2432472b0bfe25fbd07db134731007 (patch)
tree06c7114340907eeb3abf5dc72053090c7160b95f /chrome/browser/policy/config_dir_policy_provider.cc
parent8127442bb787fcdfe6af0c40131d11103072af17 (diff)
downloadchromium_src-7c5972380d2432472b0bfe25fbd07db134731007.zip
chromium_src-7c5972380d2432472b0bfe25fbd07db134731007.tar.gz
chromium_src-7c5972380d2432472b0bfe25fbd07db134731007.tar.bz2
Dynamic policy refresh support for the Mac.
Adapt the file watching code we already had for ConfigDirPolicyProvider to support a loader delegate, make the old code use it and change the Mac policy provider to watch for changes to the plist file in /Library/Managed Preferences/<username>. BUG=52040 TEST=unit tests Review URL: http://codereview.chromium.org/4062002 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@64415 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser/policy/config_dir_policy_provider.cc')
-rw-r--r--chrome/browser/policy/config_dir_policy_provider.cc246
1 files changed, 26 insertions, 220 deletions
diff --git a/chrome/browser/policy/config_dir_policy_provider.cc b/chrome/browser/policy/config_dir_policy_provider.cc
index a3f3e04..6c1a4f3 100644
--- a/chrome/browser/policy/config_dir_policy_provider.cc
+++ b/chrome/browser/policy/config_dir_policy_provider.cc
@@ -7,116 +7,19 @@
#include <set>
#include "base/file_util.h"
-#include "base/logging.h"
-#include "base/message_loop.h"
-#include "base/task.h"
-#include "base/utf_string_conversions.h"
#include "base/values.h"
-#include "chrome/browser/browser_thread.h"
#include "chrome/common/json_value_serializer.h"
namespace policy {
-// Amount of time we wait for the files in the policy directory to settle before
-// trying to load it. This alleviates the problem of reading partially written
-// files and allows to batch quasi-simultaneous changes.
-const int kSettleIntervalSeconds = 5;
-
-// The time interval for rechecking policy. This is our fallback in case the
-// directory watch fails or doesn't report a change.
-const int kReloadIntervalMinutes = 15;
-
-// PolicyDirLoader implementation:
-
-PolicyDirLoader::PolicyDirLoader(
- base::WeakPtr<ConfigDirPolicyProvider> provider,
- const FilePath& config_dir,
- int settle_interval_seconds,
- int reload_interval_minutes)
- : provider_(provider),
- origin_loop_(MessageLoop::current()),
- config_dir_(config_dir),
- reload_task_(NULL),
- settle_interval_seconds_(settle_interval_seconds),
- reload_interval_minutes_(reload_interval_minutes) {
- // Force an initial load, so GetPolicy() works.
- policy_.reset(Load());
- DCHECK(policy_.get());
-}
-
-PolicyDirLoader::~PolicyDirLoader() {}
-
-void PolicyDirLoader::Stop() {
- if (!BrowserThread::CurrentlyOn(BrowserThread::FILE)) {
- BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
- NewRunnableMethod(this, &PolicyDirLoader::Stop));
- return;
- }
-
- if (reload_task_) {
- reload_task_->Cancel();
- reload_task_ = NULL;
- }
-}
-
-void PolicyDirLoader::Reload() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
-
- // Check the directory time in order to see whether a reload is required.
- base::TimeDelta delay;
- base::Time now = base::Time::Now();
- if (!IsSafeToReloadPolicy(now, &delay)) {
- ScheduleReloadTask(delay);
- return;
- }
-
- // Load the policy definitions.
- scoped_ptr<DictionaryValue> new_policy(Load());
-
- // Check again in case the directory has changed while reading it.
- if (!IsSafeToReloadPolicy(now, &delay)) {
- ScheduleReloadTask(delay);
- return;
- }
-
- // Replace policy definition.
- bool changed = false;
- {
- AutoLock lock(lock_);
- changed = !policy_->Equals(new_policy.get());
- policy_.reset(new_policy.release());
- }
-
- // There's a change, report it!
- if (changed) {
- VLOG(1) << "Policy reload from " << config_dir_.value() << " succeeded.";
- origin_loop_->PostTask(FROM_HERE,
- NewRunnableMethod(this, &PolicyDirLoader::NotifyPolicyChanged));
- }
-
- // As a safeguard in case the file watcher fails, schedule a reload task
- // that'll make us recheck after a reasonable interval.
- ScheduleReloadTask(base::TimeDelta::FromMinutes(reload_interval_minutes_));
-}
-
-DictionaryValue* PolicyDirLoader::GetPolicy() {
- AutoLock lock(lock_);
- return static_cast<DictionaryValue*>(policy_->DeepCopy());
+ConfigDirPolicyLoader::ConfigDirPolicyLoader(const FilePath& config_dir)
+ : FileBasedPolicyProvider::Delegate(config_dir) {
}
-void PolicyDirLoader::OnFilePathChanged(const FilePath& path) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
- Reload();
-}
-
-void PolicyDirLoader::OnError() {
- LOG(ERROR) << "FileWatcher on " << config_dir_.value() << " failed.";
-}
-
-DictionaryValue* PolicyDirLoader::Load() {
+DictionaryValue* ConfigDirPolicyLoader::Load() {
// Enumerate the files and sort them lexicographically.
std::set<FilePath> files;
- file_util::FileEnumerator file_enumerator(config_dir_, false,
+ file_util::FileEnumerator file_enumerator(config_file_path(), false,
file_util::FileEnumerator::FILES);
for (FilePath config_file_path = file_enumerator.Next();
!config_file_path.empty(); config_file_path = file_enumerator.Next())
@@ -146,135 +49,38 @@ DictionaryValue* PolicyDirLoader::Load() {
return policy;
}
-bool PolicyDirLoader::IsSafeToReloadPolicy(const base::Time& now,
- base::TimeDelta* delay) {
- DCHECK(delay);
- base::PlatformFileInfo dir_info;
+base::Time ConfigDirPolicyLoader::GetLastModification() {
+ base::Time last_modification = base::Time();
+ base::PlatformFileInfo file_info;
- // Reading an empty directory or a file is always safe.
- if (!file_util::GetFileInfo(config_dir_, &dir_info) ||
- !dir_info.is_directory) {
- last_modification_file_ = base::Time();
- return true;
+ // If the path does not exist or points to a directory, it's safe to load.
+ if (!file_util::GetFileInfo(config_file_path(), &file_info) ||
+ !file_info.is_directory) {
+ return last_modification;
}
- // If there was a change since the last recorded modification, wait some more.
- base::TimeDelta settleInterval(
- base::TimeDelta::FromSeconds(settle_interval_seconds_));
- if (dir_info.last_modified != last_modification_file_) {
- last_modification_file_ = dir_info.last_modified;
- last_modification_clock_ = now;
- *delay = settleInterval;
- return false;
- }
-
- // Check whether the settle interval has elapsed.
- base::TimeDelta age = now - last_modification_clock_;
- if (age < settleInterval) {
- *delay = settleInterval - age;
- return false;
- }
-
- return true;
-}
-
-void PolicyDirLoader::ScheduleReloadTask(const base::TimeDelta& delay) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
-
- if (reload_task_)
- reload_task_->Cancel();
-
- reload_task_ = NewRunnableMethod(this, &PolicyDirLoader::ReloadFromTask);
- BrowserThread::PostDelayedTask(BrowserThread::FILE, FROM_HERE, reload_task_,
- delay.InMilliseconds());
-}
-
-void PolicyDirLoader::NotifyPolicyChanged() {
- DCHECK_EQ(origin_loop_, MessageLoop::current());
- if (provider_)
- provider_->NotifyStoreOfPolicyChange();
-}
-
-void PolicyDirLoader::ReloadFromTask() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
-
- // Drop the reference to the reload task, since the task might be the only
- // referer that keeps us alive, so we should not Cancel() it.
- reload_task_ = NULL;
-
- Reload();
-}
-
-// PolicyDirWatcher implementation:
-
-PolicyDirWatcher::PolicyDirWatcher() {}
-
-void PolicyDirWatcher::Init(PolicyDirLoader* loader) {
- // Initialization can happen early when the file thread is not yet available.
- // So post a task to ourselves on the UI thread which will run after threading
- // is up and schedule watch initialization on the file thread.
- BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
- NewRunnableMethod(this,
- &PolicyDirWatcher::InitWatcher,
- scoped_refptr<PolicyDirLoader>(loader)));
-}
-
-PolicyDirWatcher::~PolicyDirWatcher() {}
-
-void PolicyDirWatcher::InitWatcher(
- const scoped_refptr<PolicyDirLoader>& loader) {
- if (!BrowserThread::CurrentlyOn(BrowserThread::FILE)) {
- BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
- NewRunnableMethod(this, &PolicyDirWatcher::InitWatcher, loader));
- return;
+ // Enumerate the files and find the most recent modification timestamp.
+ file_util::FileEnumerator file_enumerator(config_file_path(),
+ false,
+ file_util::FileEnumerator::FILES);
+ for (FilePath config_file = file_enumerator.Next();
+ !config_file.empty();
+ config_file = file_enumerator.Next()) {
+ if (file_util::GetFileInfo(config_file, &file_info) &&
+ !file_info.is_directory) {
+ last_modification = std::min(last_modification, file_info.last_modified);
+ }
}
- if (!watcher_.Watch(loader->config_dir(), loader.get()))
- loader->OnError();
-
- // There might have been changes to the directory in the time between
- // construction of the loader and initialization of the watcher. Call reload
- // to detect if that is the case.
- loader->Reload();
+ return last_modification;
}
-// ConfigDirPolicyProvider implementation:
-
ConfigDirPolicyProvider::ConfigDirPolicyProvider(
- const ConfigurationPolicyProvider::StaticPolicyValueMap& policy_map,
+ const ConfigurationPolicyProvider::PolicyDefinitionList* policy_list,
const FilePath& config_dir)
- : ConfigurationPolicyProvider(policy_map) {
- loader_ = new PolicyDirLoader(AsWeakPtr(), config_dir, kSettleIntervalSeconds,
- kReloadIntervalMinutes);
- watcher_ = new PolicyDirWatcher;
- watcher_->Init(loader_.get());
+ : FileBasedPolicyProvider(policy_list,
+ new ConfigDirPolicyLoader(config_dir)) {
}
-ConfigDirPolicyProvider::~ConfigDirPolicyProvider() {
- loader_->Stop();
-}
-
-bool ConfigDirPolicyProvider::Provide(ConfigurationPolicyStore* store) {
- scoped_ptr<DictionaryValue> policy(loader_->GetPolicy());
- DCHECK(policy.get());
- DecodePolicyValueTree(policy.get(), store);
- return true;
-}
-
-void ConfigDirPolicyProvider::DecodePolicyValueTree(
- DictionaryValue* policies,
- ConfigurationPolicyStore* store) {
- const PolicyValueMap& mapping(policy_value_map());
- for (PolicyValueMap::const_iterator i = mapping.begin();
- i != mapping.end(); ++i) {
- const PolicyValueMapEntry& entry(*i);
- Value* value;
- if (policies->Get(entry.name, &value) && value->IsType(entry.value_type))
- store->Apply(entry.policy_type, value->DeepCopy());
- }
-
- // TODO(mnissler): Handle preference overrides once |ConfigurationPolicyStore|
- // supports it.
-}
} // namespace policy