| OLD | NEW |
| (Empty) |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 #include "chrome/browser/policy/file_based_policy_loader.h" | |
| 6 | |
| 7 #include "base/files/file_path_watcher.h" | |
| 8 #include "base/memory/ref_counted.h" | |
| 9 #include "chrome/browser/policy/policy_bundle.h" | |
| 10 #include "content/public/browser/browser_thread.h" | |
| 11 | |
| 12 using ::base::files::FilePathWatcher; | |
| 13 using content::BrowserThread; | |
| 14 | |
| 15 namespace { | |
| 16 | |
| 17 // Amount of time we wait for the files on disk to settle before trying to load | |
| 18 // them. This alleviates the problem of reading partially written files and | |
| 19 // makes it possible to batch quasi-simultaneous changes. | |
| 20 const int kSettleIntervalSeconds = 5; | |
| 21 | |
| 22 // The time interval for rechecking policy. This is our fallback in case the | |
| 23 // delegate never reports a change to the ReloadObserver. | |
| 24 const int kReloadIntervalMinutes = 15; | |
| 25 | |
| 26 } // namespace | |
| 27 | |
| 28 namespace policy { | |
| 29 | |
| 30 FileBasedPolicyLoader::FileBasedPolicyLoader( | |
| 31 FileBasedPolicyProvider::ProviderDelegate* provider_delegate) | |
| 32 : AsynchronousPolicyLoader(provider_delegate, | |
| 33 kReloadIntervalMinutes), | |
| 34 config_file_path_(provider_delegate->config_file_path()), | |
| 35 settle_interval_(base::TimeDelta::FromSeconds(kSettleIntervalSeconds)) { | |
| 36 } | |
| 37 | |
| 38 FileBasedPolicyLoader::~FileBasedPolicyLoader() {} | |
| 39 | |
| 40 class FileBasedPolicyWatcherDelegate : public FilePathWatcher::Delegate { | |
| 41 public: | |
| 42 explicit FileBasedPolicyWatcherDelegate( | |
| 43 scoped_refptr<FileBasedPolicyLoader> loader) | |
| 44 : loader_(loader) {} | |
| 45 | |
| 46 // FilePathWatcher::Delegate implementation: | |
| 47 virtual void OnFilePathChanged(const FilePath& path) OVERRIDE { | |
| 48 loader_->OnFilePathChanged(path); | |
| 49 } | |
| 50 | |
| 51 virtual void OnFilePathError(const FilePath& path) OVERRIDE { | |
| 52 loader_->OnFilePathError(path); | |
| 53 } | |
| 54 | |
| 55 private: | |
| 56 virtual ~FileBasedPolicyWatcherDelegate() {} | |
| 57 | |
| 58 scoped_refptr<FileBasedPolicyLoader> loader_; | |
| 59 DISALLOW_COPY_AND_ASSIGN(FileBasedPolicyWatcherDelegate); | |
| 60 }; | |
| 61 | |
| 62 void FileBasedPolicyLoader::OnFilePathChanged( | |
| 63 const FilePath& path) { | |
| 64 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); | |
| 65 Reload(false); | |
| 66 } | |
| 67 | |
| 68 void FileBasedPolicyLoader::OnFilePathError(const FilePath& path) { | |
| 69 LOG(ERROR) << "FilePathWatcher on " << path.value() | |
| 70 << " failed."; | |
| 71 } | |
| 72 | |
| 73 void FileBasedPolicyLoader::Reload(bool force) { | |
| 74 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); | |
| 75 | |
| 76 if (!delegate()) { | |
| 77 scoped_ptr<PolicyBundle> empty_bundle; | |
| 78 PostUpdatePolicyTask(empty_bundle.Pass()); | |
| 79 return; | |
| 80 } | |
| 81 | |
| 82 // Check the directory time in order to see whether a reload is required. | |
| 83 base::TimeDelta delay; | |
| 84 base::Time now = base::Time::Now(); | |
| 85 if (!force && !IsSafeToReloadPolicy(now, &delay)) { | |
| 86 ScheduleReloadTask(delay); | |
| 87 return; | |
| 88 } | |
| 89 | |
| 90 // Load the policy definitions. | |
| 91 scoped_ptr<PolicyBundle> bundle(delegate()->Load()); | |
| 92 | |
| 93 // Check again in case the directory has changed while reading it. | |
| 94 if (!force && !IsSafeToReloadPolicy(now, &delay)) { | |
| 95 ScheduleReloadTask(delay); | |
| 96 return; | |
| 97 } | |
| 98 | |
| 99 PostUpdatePolicyTask(bundle.Pass()); | |
| 100 | |
| 101 ScheduleFallbackReloadTask(); | |
| 102 } | |
| 103 | |
| 104 void FileBasedPolicyLoader::InitOnFileThread() { | |
| 105 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); | |
| 106 watcher_.reset(new FilePathWatcher); | |
| 107 const FilePath& path = config_file_path(); | |
| 108 if (!path.empty() && | |
| 109 !watcher_->Watch(path, new FileBasedPolicyWatcherDelegate(this))) { | |
| 110 OnFilePathError(path); | |
| 111 } | |
| 112 | |
| 113 // There might have been changes to the directory in the time between | |
| 114 // construction of the loader and initialization of the watcher. Call reload | |
| 115 // to detect if that is the case. | |
| 116 Reload(false); | |
| 117 | |
| 118 ScheduleFallbackReloadTask(); | |
| 119 } | |
| 120 | |
| 121 void FileBasedPolicyLoader::StopOnFileThread() { | |
| 122 watcher_.reset(); | |
| 123 AsynchronousPolicyLoader::StopOnFileThread(); | |
| 124 } | |
| 125 | |
| 126 bool FileBasedPolicyLoader::IsSafeToReloadPolicy( | |
| 127 const base::Time& now, | |
| 128 base::TimeDelta* delay) { | |
| 129 DCHECK(delay); | |
| 130 | |
| 131 // A null modification time indicates there's no data. | |
| 132 FileBasedPolicyProvider::ProviderDelegate* provider_delegate = | |
| 133 static_cast<FileBasedPolicyProvider::ProviderDelegate*>(delegate()); | |
| 134 base::Time last_modification(provider_delegate->GetLastModification()); | |
| 135 if (last_modification.is_null()) | |
| 136 return true; | |
| 137 | |
| 138 // If there was a change since the last recorded modification, wait some more. | |
| 139 if (last_modification != last_modification_file_) { | |
| 140 last_modification_file_ = last_modification; | |
| 141 last_modification_clock_ = now; | |
| 142 *delay = settle_interval_; | |
| 143 return false; | |
| 144 } | |
| 145 | |
| 146 // Check whether the settle interval has elapsed. | |
| 147 base::TimeDelta age = now - last_modification_clock_; | |
| 148 if (age < settle_interval_) { | |
| 149 *delay = settle_interval_ - age; | |
| 150 return false; | |
| 151 } | |
| 152 | |
| 153 return true; | |
| 154 } | |
| 155 | |
| 156 } // namespace policy | |
| OLD | NEW |