Chromium Code Reviews| Index: chrome/browser/policy/file_based_policy_loader.cc |
| diff --git a/chrome/browser/policy/file_based_policy_loader.cc b/chrome/browser/policy/file_based_policy_loader.cc |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..3f0aea7bb59db748461c836b25f3c295146e1036 |
| --- /dev/null |
| +++ b/chrome/browser/policy/file_based_policy_loader.cc |
| @@ -0,0 +1,187 @@ |
| +// Copyright (c) 2010 The Chromium 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 "chrome/browser/policy/file_based_policy_loader.h" |
| + |
| +namespace { |
| + |
| +// Amount of time we wait for the files on disk to settle before trying to load |
| +// it. This alleviates the problem of reading partially written files and allows |
|
Mattias Nissler (ping if slow)
2010/12/06 10:26:20
s/it/them/
danno
2010/12/06 14:05:12
Done.
|
| +// to batch quasi-simultaneous changes. |
| +const int kSettleIntervalSeconds = 5; |
| + |
| +// The time interval for rechecking policy. This is our fallback in case the |
| +// delegate never reports a change to the ReloadObserver. |
| +const int kReloadIntervalMinutes = 15; |
| + |
| +} |
| + |
| +namespace policy { |
| + |
| +FileBasedPolicyLoader::FileBasedPolicyLoader( |
| + FileBasedPolicyProvider::ProviderDelegate* provider_delegate) |
| + : AsynchronousPolicyLoader(provider_delegate), |
| + provider_delegate_(provider_delegate), |
| + config_file_path_(provider_delegate->config_file_path()), |
| + reload_interval_(base::TimeDelta::FromMinutes(kReloadIntervalMinutes)), |
| + settle_interval_(base::TimeDelta::FromSeconds(kSettleIntervalSeconds)) { |
| +} |
| + |
| +class FileBasedPolicyWatcherDelegate : public FilePathWatcher::Delegate { |
| + public: |
| + explicit FileBasedPolicyWatcherDelegate( |
| + scoped_refptr<FileBasedPolicyLoader> loader) |
| + : loader_(loader) {} |
| + virtual ~FileBasedPolicyWatcherDelegate() {} |
| + |
| + // FilePathWatcher::Delegate implementation: |
| + void OnFilePathChanged(const FilePath& path) { |
| + loader_->OnFilePathChanged(path); |
| + } |
| + |
| + void OnError() { |
| + loader_->OnError(); |
| + } |
| + |
| + private: |
| + scoped_refptr<FileBasedPolicyLoader> loader_; |
| + DISALLOW_COPY_AND_ASSIGN(FileBasedPolicyWatcherDelegate); |
| +}; |
| + |
| +void FileBasedPolicyLoader::Init() { |
| + AsynchronousPolicyLoader::Init(); |
| + |
| + // Initialization can happen early when the file thread is not |
| + // yet available. So post a task on the FILE thread which will run after |
| + // threading is up and schedule watch initialization on the file thread. |
|
Mattias Nissler (ping if slow)
2010/12/06 10:26:20
Didn't we post on the UI thread before? That was i
danno
2010/12/06 14:05:12
Done.
|
| + BrowserThread::PostTask( |
| + BrowserThread::FILE, FROM_HERE, |
| + NewRunnableMethod(this, &FileBasedPolicyLoader::InitWatcher)); |
| + |
| + ScheduleFallbackReloadTask(); |
| +} |
| + |
| +void FileBasedPolicyLoader::Stop() { |
| + AsynchronousPolicyLoader::Stop(); |
| + BrowserThread::PostTask( |
| + BrowserThread::FILE, FROM_HERE, |
| + NewRunnableMethod(this, &FileBasedPolicyLoader::StopOnFileThread)); |
| +} |
| + |
| +void FileBasedPolicyLoader::OnFilePathChanged( |
| + const FilePath& path) { |
| + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); |
| + Reload(); |
| +} |
| + |
| +void FileBasedPolicyLoader::OnError() { |
| + LOG(ERROR) << "FilePathWatcher on " << config_file_path().value() |
| + << " failed."; |
| +} |
| + |
| +void FileBasedPolicyLoader::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(delegate()->Load()); |
| + |
| + // Check again in case the directory has changed while reading it. |
| + if (!IsSafeToReloadPolicy(now, &delay)) { |
| + ScheduleReloadTask(delay); |
| + return; |
| + } |
| + |
| + PostUpdatePolicyTask(new_policy.release()); |
| + |
| + ScheduleFallbackReloadTask(); |
| +} |
| + |
| +void FileBasedPolicyLoader::InitWatcher() { |
| + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); |
| + watcher_.reset(new FilePathWatcher); |
| + if (!config_file_path().empty() && |
| + !watcher_->Watch(config_file_path(), |
| + new FileBasedPolicyWatcherDelegate(this))) |
| + OnError(); |
|
Mattias Nissler (ping if slow)
2010/12/06 10:26:20
need curlies here.
danno
2010/12/06 14:05:12
Done.
|
| + |
| + // 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. |
| + Reload(); |
| +} |
| + |
| +void FileBasedPolicyLoader::StopOnFileThread() { |
| + watcher_.reset(); |
| + if (reload_task_) { |
| + reload_task_->Cancel(); |
| + reload_task_ = NULL; |
| + } |
| +} |
| + |
| +void FileBasedPolicyLoader::ScheduleReloadTask( |
| + const base::TimeDelta& delay) { |
| + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); |
| + |
| + if (reload_task_) |
| + reload_task_->Cancel(); |
| + |
| + reload_task_ = |
| + NewRunnableMethod(this, &FileBasedPolicyLoader::ReloadFromTask); |
| + BrowserThread::PostDelayedTask(BrowserThread::FILE, FROM_HERE, reload_task_, |
| + delay.InMilliseconds()); |
| +} |
| + |
| +void FileBasedPolicyLoader::ScheduleFallbackReloadTask() { |
| + // As a safeguard in case that the load delegate failed to timely notice a |
| + // change in policy, schedule a reload task that'll make us recheck after a |
| + // reasonable interval. |
| + ScheduleReloadTask(reload_interval_); |
| +} |
| + |
| +void FileBasedPolicyLoader::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(); |
| +} |
| + |
| +bool FileBasedPolicyLoader::IsSafeToReloadPolicy( |
| + const base::Time& now, |
| + base::TimeDelta* delay) { |
| + DCHECK(delay); |
| + |
| + // A null modification time indicates there's no data. |
| + base::Time last_modification(provider_delegate_->GetLastModification()); |
| + if (last_modification.is_null()) |
| + return true; |
| + |
| + // If there was a change since the last recorded modification, wait some more. |
| + if (last_modification != last_modification_file_) { |
| + last_modification_file_ = last_modification; |
| + last_modification_clock_ = now; |
| + *delay = settle_interval_; |
| + return false; |
| + } |
| + |
| + // Check whether the settle interval has elapsed. |
| + base::TimeDelta age = now - last_modification_clock_; |
| + if (age < settle_interval_) { |
| + *delay = settle_interval_ - age; |
| + return false; |
| + } |
| + |
| + return true; |
| +} |
| + |
| +} // namespace policy |