1ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// Copyright (c) 2011 The Chromium Authors. All rights reserved.
221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen// Use of this source code is governed by a BSD-style license that can be
321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen// found in the LICENSE file.
421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen#include "chrome/browser/policy/file_based_policy_loader.h"
621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
7ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "base/compiler_specific.h"
8ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "content/browser/browser_thread.h"
9ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
10ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenusing ::base::files::FilePathWatcher;
11ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
1221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsennamespace {
1321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
1421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen// Amount of time we wait for the files on disk to settle before trying to load
1521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen// them. This alleviates the problem of reading partially written files and
1621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen// makes it possible to batch quasi-simultaneous changes.
1721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsenconst int kSettleIntervalSeconds = 5;
1821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
1921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen// The time interval for rechecking policy. This is our fallback in case the
2021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen// delegate never reports a change to the ReloadObserver.
2121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsenconst int kReloadIntervalMinutes = 15;
2221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
2321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen}  // namespace
2421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
2521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsennamespace policy {
2621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
2721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian MonsenFileBasedPolicyLoader::FileBasedPolicyLoader(
2821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    FileBasedPolicyProvider::ProviderDelegate* provider_delegate)
2921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    : AsynchronousPolicyLoader(provider_delegate,
3021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen                               kReloadIntervalMinutes),
3121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen      config_file_path_(provider_delegate->config_file_path()),
3221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen      settle_interval_(base::TimeDelta::FromSeconds(kSettleIntervalSeconds)) {
3321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen}
3421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
3521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian MonsenFileBasedPolicyLoader::~FileBasedPolicyLoader() {}
3621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
3721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsenclass FileBasedPolicyWatcherDelegate : public FilePathWatcher::Delegate {
3821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen public:
3921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  explicit FileBasedPolicyWatcherDelegate(
4021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen      scoped_refptr<FileBasedPolicyLoader> loader)
4121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen      : loader_(loader) {}
4221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  virtual ~FileBasedPolicyWatcherDelegate() {}
4321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
4421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  // FilePathWatcher::Delegate implementation:
45ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  virtual void OnFilePathChanged(const FilePath& path) OVERRIDE {
4621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    loader_->OnFilePathChanged(path);
4721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  }
4821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
49ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  virtual void OnFilePathError(const FilePath& path) OVERRIDE {
50ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    loader_->OnFilePathError(path);
5121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  }
5221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
5321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen private:
5421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  scoped_refptr<FileBasedPolicyLoader> loader_;
5521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  DISALLOW_COPY_AND_ASSIGN(FileBasedPolicyWatcherDelegate);
5621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen};
5721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
5821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsenvoid FileBasedPolicyLoader::OnFilePathChanged(
5921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    const FilePath& path) {
6021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
6121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  Reload();
6221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen}
6321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
64ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid FileBasedPolicyLoader::OnFilePathError(const FilePath& path) {
65ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  LOG(ERROR) << "FilePathWatcher on " << path.value()
6621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen             << " failed.";
6721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen}
6821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
6921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsenvoid FileBasedPolicyLoader::Reload() {
7021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
7121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
7221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  if (!delegate())
7321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    return;
7421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
7521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  // Check the directory time in order to see whether a reload is required.
7621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  base::TimeDelta delay;
7721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  base::Time now = base::Time::Now();
7821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  if (!IsSafeToReloadPolicy(now, &delay)) {
7921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    ScheduleReloadTask(delay);
8021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    return;
8121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  }
8221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
8321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  // Load the policy definitions.
8421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  scoped_ptr<DictionaryValue> new_policy(delegate()->Load());
8521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
8621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  // Check again in case the directory has changed while reading it.
8721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  if (!IsSafeToReloadPolicy(now, &delay)) {
8821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    ScheduleReloadTask(delay);
8921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    return;
9021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  }
9121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
9221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  PostUpdatePolicyTask(new_policy.release());
9321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
9421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  ScheduleFallbackReloadTask();
9521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen}
9621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
9721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsenvoid FileBasedPolicyLoader::InitOnFileThread() {
9821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
9921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  watcher_.reset(new FilePathWatcher);
100ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  const FilePath& path = config_file_path();
101ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (!path.empty() &&
102ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      !watcher_->Watch(path, new FileBasedPolicyWatcherDelegate(this))) {
103ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    OnFilePathError(path);
10421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  }
10521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
10621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  // There might have been changes to the directory in the time between
10721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  // construction of the loader and initialization of the watcher. Call reload
10821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  // to detect if that is the case.
10921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  Reload();
11021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
11121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  ScheduleFallbackReloadTask();
11221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen}
11321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
11421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsenvoid FileBasedPolicyLoader::StopOnFileThread() {
11521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  watcher_.reset();
11621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  AsynchronousPolicyLoader::StopOnFileThread();
11721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen}
11821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
11921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsenbool FileBasedPolicyLoader::IsSafeToReloadPolicy(
12021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    const base::Time& now,
12121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    base::TimeDelta* delay) {
12221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  DCHECK(delay);
12321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
12421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  // A null modification time indicates there's no data.
12521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  FileBasedPolicyProvider::ProviderDelegate* provider_delegate =
12621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen      static_cast<FileBasedPolicyProvider::ProviderDelegate*>(delegate());
12721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  base::Time last_modification(provider_delegate->GetLastModification());
12821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  if (last_modification.is_null())
12921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    return true;
13021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
13121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  // If there was a change since the last recorded modification, wait some more.
13221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  if (last_modification != last_modification_file_) {
13321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    last_modification_file_ = last_modification;
13421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    last_modification_clock_ = now;
13521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    *delay = settle_interval_;
13621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    return false;
13721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  }
13821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
13921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  // Check whether the settle interval has elapsed.
14021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  base::TimeDelta age = now - last_modification_clock_;
14121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  if (age < settle_interval_) {
14221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    *delay = settle_interval_ - age;
14321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    return false;
14421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  }
14521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
14621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  return true;
14721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen}
14821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
14921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen}  // namespace policy
150