Chromium Code Reviews

Side by Side Diff: chrome/browser/policy/file_based_policy_loader.cc

Issue 5562002: Refactor FileBasedPolicyProvider, introduce AsynchronousPolicyProvider. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: review feedback Created 10 years ago
Use n/p to move between diff chunks; N/P to move between comments.
Jump to:
View unified diff | | Annotate | Revision Log
OLDNEW
(Empty)
1 // Copyright (c) 2010 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 namespace {
8
9 // Amount of time we wait for the files on disk to settle before trying to load
10 // them. This alleviates the problem of reading partially written files and
11 // makes it possible to batch quasi-simultaneous changes.
12 const int kSettleIntervalSeconds = 5;
13
14 // The time interval for rechecking policy. This is our fallback in case the
15 // delegate never reports a change to the ReloadObserver.
16 const int kReloadIntervalMinutes = 15;
17
18 }
19
20 namespace policy {
21
22 FileBasedPolicyLoader::FileBasedPolicyLoader(
23 FileBasedPolicyProvider::ProviderDelegate* provider_delegate)
24 : AsynchronousPolicyLoader(provider_delegate),
25 provider_delegate_(provider_delegate),
26 config_file_path_(provider_delegate->config_file_path()),
27 reload_task_(NULL),
28 reload_interval_(base::TimeDelta::FromMinutes(kReloadIntervalMinutes)),
29 settle_interval_(base::TimeDelta::FromSeconds(kSettleIntervalSeconds)) {
30 }
31
32 class FileBasedPolicyWatcherDelegate : public FilePathWatcher::Delegate {
33 public:
34 explicit FileBasedPolicyWatcherDelegate(
35 scoped_refptr<FileBasedPolicyLoader> loader)
36 : loader_(loader) {}
37 virtual ~FileBasedPolicyWatcherDelegate() {}
38
39 // FilePathWatcher::Delegate implementation:
40 void OnFilePathChanged(const FilePath& path) {
41 loader_->OnFilePathChanged(path);
42 }
43
44 void OnError() {
45 loader_->OnError();
46 }
47
48 private:
49 scoped_refptr<FileBasedPolicyLoader> loader_;
50 DISALLOW_COPY_AND_ASSIGN(FileBasedPolicyWatcherDelegate);
51 };
52
53 void FileBasedPolicyLoader::Init() {
54 AsynchronousPolicyLoader::Init();
55
56 // Initialization can happen early when the file thread is not yet available,
57 // but the watcher's initialization must be done on the file thread. Posting
58 // to a to the file directly before the file thread is initialized will cause
59 // the task to be forgotten. Instead, post a task to the ui thread to delay
60 // the remainder of initialization until threading is fully initialized.
61 BrowserThread::PostTask(
62 BrowserThread::FILE, FROM_HERE,
63 NewRunnableMethod(this,
64 &FileBasedPolicyLoader::InitAfterIOThreadAvailable));
65 }
66
67 void FileBasedPolicyLoader::Stop() {
68 AsynchronousPolicyLoader::Stop();
69 BrowserThread::PostTask(
70 BrowserThread::FILE, FROM_HERE,
71 NewRunnableMethod(this, &FileBasedPolicyLoader::StopOnFileThread));
72 }
73
74 void FileBasedPolicyLoader::OnFilePathChanged(
75 const FilePath& path) {
76 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
77 Reload();
78 }
79
80 void FileBasedPolicyLoader::OnError() {
81 LOG(ERROR) << "FilePathWatcher on " << config_file_path().value()
82 << " failed.";
83 }
84
85 void FileBasedPolicyLoader::Reload() {
86 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
87 // Check the directory time in order to see whether a reload is required.
88 base::TimeDelta delay;
89 base::Time now = base::Time::Now();
90 if (!IsSafeToReloadPolicy(now, &delay)) {
91 ScheduleReloadTask(delay);
92 return;
93 }
94
95 // Load the policy definitions.
96 scoped_ptr<DictionaryValue> new_policy(delegate()->Load());
97
98 // Check again in case the directory has changed while reading it.
99 if (!IsSafeToReloadPolicy(now, &delay)) {
100 ScheduleReloadTask(delay);
101 return;
102 }
103
104 PostUpdatePolicyTask(new_policy.release());
105
106 ScheduleFallbackReloadTask();
107 }
108
109 void FileBasedPolicyLoader::InitAfterIOThreadAvailable() {
110 BrowserThread::PostTask(
111 BrowserThread::FILE, FROM_HERE,
112 NewRunnableMethod(this, &FileBasedPolicyLoader::InitWatcher));
113
114 ScheduleFallbackReloadTask();
115 }
116
117 void FileBasedPolicyLoader::InitWatcher() {
118 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
119 watcher_.reset(new FilePathWatcher);
120 if (!config_file_path().empty() &&
121 !watcher_->Watch(config_file_path(),
122 new FileBasedPolicyWatcherDelegate(this))) {
123 OnError();
124 }
125
126 // There might have been changes to the directory in the time between
127 // construction of the loader and initialization of the watcher. Call reload
128 // to detect if that is the case.
129 Reload();
130 }
131
132 void FileBasedPolicyLoader::StopOnFileThread() {
133 watcher_.reset();
134 if (reload_task_) {
135 reload_task_->Cancel();
136 reload_task_ = NULL;
137 }
138 }
139
140 void FileBasedPolicyLoader::ScheduleReloadTask(
141 const base::TimeDelta& delay) {
142 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
143
144 if (reload_task_)
145 reload_task_->Cancel();
146
147 reload_task_ =
148 NewRunnableMethod(this, &FileBasedPolicyLoader::ReloadFromTask);
149 BrowserThread::PostDelayedTask(BrowserThread::FILE, FROM_HERE, reload_task_,
150 delay.InMilliseconds());
151 }
152
153 void FileBasedPolicyLoader::ScheduleFallbackReloadTask() {
154 // As a safeguard in case that the load delegate failed to timely notice a
155 // change in policy, schedule a reload task that'll make us recheck after a
156 // reasonable interval.
157 ScheduleReloadTask(reload_interval_);
158 }
159
160 void FileBasedPolicyLoader::ReloadFromTask() {
161 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
162
163 // Drop the reference to the reload task, since the task might be the only
164 // referer that keeps us alive, so we should not Cancel() it.
165 reload_task_ = NULL;
166
167 Reload();
168 }
169
170 bool FileBasedPolicyLoader::IsSafeToReloadPolicy(
171 const base::Time& now,
172 base::TimeDelta* delay) {
173 DCHECK(delay);
174
175 // A null modification time indicates there's no data.
176 base::Time last_modification(provider_delegate_->GetLastModification());
177 if (last_modification.is_null())
178 return true;
179
180 // If there was a change since the last recorded modification, wait some more.
181 if (last_modification != last_modification_file_) {
182 last_modification_file_ = last_modification;
183 last_modification_clock_ = now;
184 *delay = settle_interval_;
185 return false;
186 }
187
188 // Check whether the settle interval has elapsed.
189 base::TimeDelta age = now - last_modification_clock_;
190 if (age < settle_interval_) {
191 *delay = settle_interval_ - age;
192 return false;
193 }
194
195 return true;
196 }
197
198 } // namespace policy
OLDNEW

Powered by Google App Engine