Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(79)

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

Issue 4062002: Dynamic policy refresh support for the Mac. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: s/map/list/, nits. Created 10 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | 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_provider.h"
6
7 #include <set>
8
9 #include "base/logging.h"
10 #include "base/message_loop.h"
11 #include "base/task.h"
12 #include "base/utf_string_conversions.h"
13 #include "base/values.h"
14 #include "chrome/browser/browser_thread.h"
15 #include "chrome/common/json_value_serializer.h"
16
17 namespace policy {
18
19 // Amount of time we wait for the files on disk to settle before trying to load
20 // it. This alleviates the problem of reading partially written files and allows
21 // to batch quasi-simultaneous changes.
22 const int kSettleIntervalSeconds = 5;
23
24 // The time interval for rechecking policy. This is our fallback in case the
25 // file path watch fails or doesn't report a change.
26 const int kReloadIntervalMinutes = 15;
27
28 // FileBasedPolicyProvider implementation:
29
30 FileBasedPolicyProvider::Delegate::~Delegate() {
31 }
32
33 FileBasedPolicyProvider::Delegate::Delegate(const FilePath& config_file_path)
34 : config_file_path_(config_file_path) {
35 }
36
37 FileBasedPolicyProvider::FileBasedPolicyProvider(
38 const ConfigurationPolicyProvider::PolicyDefinitionList* policy_list,
39 FileBasedPolicyProvider::Delegate* delegate)
40 : ConfigurationPolicyProvider(policy_list) {
41 loader_ = new FileBasedPolicyLoader(AsWeakPtr(),
42 delegate,
43 kSettleIntervalSeconds,
44 kReloadIntervalMinutes);
45 watcher_ = new FileBasedPolicyWatcher;
46 watcher_->Init(loader_.get());
47 }
48
49 FileBasedPolicyProvider::~FileBasedPolicyProvider() {
50 loader_->Stop();
51 }
52
53 bool FileBasedPolicyProvider::Provide(ConfigurationPolicyStore* store) {
54 scoped_ptr<DictionaryValue> policy(loader_->GetPolicy());
55 DCHECK(policy.get());
56 DecodePolicyValueTree(policy.get(), store);
57 return true;
58 }
59
60 void FileBasedPolicyProvider::DecodePolicyValueTree(
61 DictionaryValue* policies,
62 ConfigurationPolicyStore* store) {
63 const PolicyDefinitionList* policy_list(policy_definition_list());
64 for (const PolicyDefinitionList::Entry* i = policy_list->begin;
65 i != policy_list->end; ++i) {
66 Value* value;
67 if (policies->Get(i->name, &value) && value->IsType(i->value_type))
68 store->Apply(i->policy_type, value->DeepCopy());
69 }
70
71 // TODO(mnissler): Handle preference overrides once |ConfigurationPolicyStore|
72 // supports it.
73 }
74
75 // FileBasedPolicyLoader implementation:
76
77 FileBasedPolicyLoader::FileBasedPolicyLoader(
78 base::WeakPtr<ConfigurationPolicyProvider> provider,
79 FileBasedPolicyProvider::Delegate* delegate,
80 int settle_interval_seconds,
81 int reload_interval_minutes)
82 : delegate_(delegate),
83 provider_(provider),
84 origin_loop_(MessageLoop::current()),
85 reload_task_(NULL),
86 settle_interval_seconds_(settle_interval_seconds),
87 reload_interval_minutes_(reload_interval_minutes) {
88 // Force an initial load, so GetPolicy() works.
89 policy_.reset(delegate_->Load());
90 DCHECK(policy_.get());
91 }
92
93 void FileBasedPolicyLoader::Stop() {
94 if (!BrowserThread::CurrentlyOn(BrowserThread::FILE)) {
95 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
96 NewRunnableMethod(this, &FileBasedPolicyLoader::Stop));
97 return;
98 }
99
100 if (reload_task_) {
101 reload_task_->Cancel();
102 reload_task_ = NULL;
103 }
104 }
105
106 void FileBasedPolicyLoader::Reload() {
107 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
108
109 // Check the directory time in order to see whether a reload is required.
110 base::TimeDelta delay;
111 base::Time now = base::Time::Now();
112 if (!IsSafeToReloadPolicy(now, &delay)) {
113 ScheduleReloadTask(delay);
114 return;
115 }
116
117 // Load the policy definitions.
118 scoped_ptr<DictionaryValue> new_policy(delegate_->Load());
119
120 // Check again in case the directory has changed while reading it.
121 if (!IsSafeToReloadPolicy(now, &delay)) {
122 ScheduleReloadTask(delay);
123 return;
124 }
125
126 // Replace policy definition.
127 bool changed = false;
128 {
129 AutoLock lock(lock_);
130 changed = !policy_->Equals(new_policy.get());
131 policy_.reset(new_policy.release());
132 }
133
134 // There's a change, report it!
135 if (changed) {
136 VLOG(0) << "Policy reload from " << config_file_path().value()
137 << " succeeded.";
138 origin_loop_->PostTask(FROM_HERE,
139 NewRunnableMethod(this, &FileBasedPolicyLoader::NotifyPolicyChanged));
140 }
141
142 // As a safeguard in case the file watcher fails, schedule a reload task
143 // that'll make us recheck after a reasonable interval.
144 ScheduleReloadTask(base::TimeDelta::FromMinutes(reload_interval_minutes_));
145 }
146
147 DictionaryValue* FileBasedPolicyLoader::GetPolicy() {
148 AutoLock lock(lock_);
149 return static_cast<DictionaryValue*>(policy_->DeepCopy());
150 }
151
152 void FileBasedPolicyLoader::OnFilePathChanged(const FilePath& path) {
153 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
154 Reload();
155 }
156
157 void FileBasedPolicyLoader::OnError() {
158 LOG(ERROR) << "FilePathWatcher on " << config_file_path().value()
159 << " failed.";
160 }
161
162 FileBasedPolicyLoader::~FileBasedPolicyLoader() {
163 }
164
165 bool FileBasedPolicyLoader::IsSafeToReloadPolicy(const base::Time& now,
166 base::TimeDelta* delay) {
167 DCHECK(delay);
168
169 // A null modification time indicates there's no data.
170 base::Time last_modification(delegate_->GetLastModification());
171 if (last_modification.is_null())
172 return true;
173
174 // If there was a change since the last recorded modification, wait some more.
175 base::TimeDelta settleInterval(
176 base::TimeDelta::FromSeconds(settle_interval_seconds_));
177 if (last_modification != last_modification_file_) {
178 last_modification_file_ = last_modification;
179 last_modification_clock_ = now;
180 *delay = settleInterval;
181 return false;
182 }
183
184 // Check whether the settle interval has elapsed.
185 base::TimeDelta age = now - last_modification_clock_;
186 if (age < settleInterval) {
187 *delay = settleInterval - age;
188 return false;
189 }
190
191 return true;
192 }
193
194 void FileBasedPolicyLoader::ScheduleReloadTask(const base::TimeDelta& delay) {
195 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
196
197 if (reload_task_)
198 reload_task_->Cancel();
199
200 reload_task_ =
201 NewRunnableMethod(this, &FileBasedPolicyLoader::ReloadFromTask);
202 BrowserThread::PostDelayedTask(BrowserThread::FILE, FROM_HERE, reload_task_,
203 delay.InMilliseconds());
204 }
205
206 void FileBasedPolicyLoader::NotifyPolicyChanged() {
207 DCHECK_EQ(origin_loop_, MessageLoop::current());
208 if (provider_)
209 provider_->NotifyStoreOfPolicyChange();
210 }
211
212 void FileBasedPolicyLoader::ReloadFromTask() {
213 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
214
215 // Drop the reference to the reload task, since the task might be the only
216 // referer that keeps us alive, so we should not Cancel() it.
217 reload_task_ = NULL;
218
219 Reload();
220 }
221
222 // FileBasedPolicyWatcher implementation:
223
224 FileBasedPolicyWatcher::FileBasedPolicyWatcher() {
225 }
226
227 void FileBasedPolicyWatcher::Init(FileBasedPolicyLoader* loader) {
228 // Initialization can happen early when the file thread is not yet available.
229 // So post a task to ourselves on the UI thread which will run after threading
230 // is up and schedule watch initialization on the file thread.
231 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
232 NewRunnableMethod(this,
233 &FileBasedPolicyWatcher::InitWatcher,
234 scoped_refptr<FileBasedPolicyLoader>(loader)));
235 }
236
237 FileBasedPolicyWatcher::~FileBasedPolicyWatcher() {
238 }
239
240 void FileBasedPolicyWatcher::InitWatcher(
241 const scoped_refptr<FileBasedPolicyLoader>& loader) {
242 if (!BrowserThread::CurrentlyOn(BrowserThread::FILE)) {
243 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
244 NewRunnableMethod(this, &FileBasedPolicyWatcher::InitWatcher, loader));
245 return;
246 }
247
248 if (!loader->config_file_path().empty() &&
249 !watcher_.Watch(loader->config_file_path(), loader.get()))
250 loader->OnError();
251
252 // There might have been changes to the directory in the time between
253 // construction of the loader and initialization of the watcher. Call reload
254 // to detect if that is the case.
255 loader->Reload();
256 }
257
258 } // namespace policy
OLDNEW
« no previous file with comments | « chrome/browser/policy/file_based_policy_provider.h ('k') | chrome/browser/policy/file_based_policy_provider_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698