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

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

Issue 3161035: Revert 56832 - Support change detection and reloading in ConfigDirPolicyProvi... (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: Created 10 years, 4 months 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
1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/browser/policy/config_dir_policy_provider.h" 5 #include "chrome/browser/policy/config_dir_policy_provider.h"
6 6
7 #include <set> 7 #include <set>
8 8
9 #include "base/file_util.h" 9 #include "base/file_util.h"
10 #include "base/logging.h" 10 #include "base/logging.h"
11 #include "base/scoped_ptr.h"
11 #include "base/utf_string_conversions.h" 12 #include "base/utf_string_conversions.h"
12 #include "base/values.h" 13 #include "base/values.h"
13 #include "chrome/common/json_value_serializer.h" 14 #include "chrome/common/json_value_serializer.h"
14 15
15 namespace { 16 ConfigDirPolicyProvider::ConfigDirPolicyProvider(const FilePath& config_dir)
16 17 : config_dir_(config_dir) {
17 // Amount of time we wait for the files in the policy directory to settle before
18 // trying to load it. This alleviates the problem of reading partially written
19 // files and allows 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 // directory watch fails or doesn't report a change.
24 const int kReloadIntervalMinutes = 15;
25
26 } // namespace
27
28 // PolicyDirLoader implementation:
29
30 PolicyDirLoader::PolicyDirLoader(
31 base::WeakPtr<ConfigDirPolicyProvider> provider,
32 const FilePath& config_dir,
33 int settle_interval_seconds,
34 int reload_interval_minutes)
35 : provider_(provider),
36 origin_loop_(MessageLoop::current()),
37 config_dir_(config_dir),
38 reload_task_(NULL),
39 settle_interval_seconds_(settle_interval_seconds),
40 reload_interval_minutes_(reload_interval_minutes) {
41 // Force an initial load, so GetPolicy() works.
42 policy_.reset(Load());
43 DCHECK(policy_.get());
44 } 18 }
45 19
46 void PolicyDirLoader::Stop() { 20 bool ConfigDirPolicyProvider::Provide(ConfigurationPolicyStore* store) {
47 if (!ChromeThread::CurrentlyOn(ChromeThread::FILE)) { 21 scoped_ptr<DictionaryValue> policy(ReadPolicies());
48 ChromeThread::PostTask(ChromeThread::FILE, FROM_HERE, 22 DecodePolicyValueTree(policy.get(), store);
49 NewRunnableMethod(this, &PolicyDirLoader::Stop)); 23 return true;
50 return;
51 }
52
53 if (reload_task_) {
54 reload_task_->Cancel();
55 reload_task_ = NULL;
56 }
57 } 24 }
58 25
59 void PolicyDirLoader::Reload() { 26 DictionaryValue* ConfigDirPolicyProvider::ReadPolicies() {
60 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE));
61
62 // Check the directory time in order to see whether a reload is required.
63 base::Time now = base::Time::Now();
64 base::TimeDelta delay;
65 if (!IsSafeToReloadPolicy(now, &delay)) {
66 ScheduleReloadTask(delay);
67 return;
68 }
69
70 // Load the policy definitions.
71 scoped_ptr<DictionaryValue> new_policy(Load());
72
73 // Check again in case the directory has changed while reading it.
74 if (!IsSafeToReloadPolicy(now, &delay)) {
75 ScheduleReloadTask(delay);
76 return;
77 }
78
79 // Replace policy definition.
80 bool changed = false;
81 {
82 AutoLock lock(lock_);
83 changed = !policy_->Equals(new_policy.get());
84 policy_.reset(new_policy.release());
85 }
86
87 // There's a change, report it!
88 if (changed) {
89 LOG(INFO) << "Policy reload from " << config_dir_.value() << " succeeded.";
90 origin_loop_->PostTask(FROM_HERE,
91 NewRunnableMethod(this, &PolicyDirLoader::NotifyPolicyChanged));
92 }
93
94 // As a safeguard in case the file watcher fails, schedule a reload task
95 // that'll make us recheck after a reasonable interval.
96 ScheduleReloadTask(base::TimeDelta::FromMinutes(reload_interval_minutes_));
97 }
98
99 DictionaryValue* PolicyDirLoader::GetPolicy() {
100 AutoLock lock(lock_);
101 return static_cast<DictionaryValue*>(policy_->DeepCopy());
102 }
103
104 void PolicyDirLoader::OnFilePathChanged(const FilePath& path) {
105 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE));
106 Reload();
107 }
108
109 void PolicyDirLoader::OnError() {
110 LOG(ERROR) << "FileWatcher on " << config_dir_.value() << " failed.";
111 }
112
113 DictionaryValue* PolicyDirLoader::Load() {
114 // Enumerate the files and sort them lexicographically. 27 // Enumerate the files and sort them lexicographically.
115 std::set<FilePath> files; 28 std::set<FilePath> files;
116 file_util::FileEnumerator file_enumerator(config_dir_, false, 29 file_util::FileEnumerator file_enumerator(config_dir_, false,
117 file_util::FileEnumerator::FILES); 30 file_util::FileEnumerator::FILES);
118 for (FilePath config_file_path = file_enumerator.Next(); 31 for (FilePath config_file_path = file_enumerator.Next();
119 !config_file_path.empty(); config_file_path = file_enumerator.Next()) 32 !config_file_path.empty(); config_file_path = file_enumerator.Next())
120 files.insert(config_file_path); 33 files.insert(config_file_path);
121 34
122 // Start with an empty dictionary and merge the files' contents. 35 // Start with an empty dictionary and merge the files' contents.
123 DictionaryValue* policy = new DictionaryValue; 36 DictionaryValue* policy = new DictionaryValue;
(...skipping 12 matching lines...) Expand all
136 LOG(WARNING) << "Expected JSON dictionary in configuration file " 49 LOG(WARNING) << "Expected JSON dictionary in configuration file "
137 << config_file_iter->value(); 50 << config_file_iter->value();
138 continue; 51 continue;
139 } 52 }
140 policy->MergeDictionary(static_cast<DictionaryValue*>(value.get())); 53 policy->MergeDictionary(static_cast<DictionaryValue*>(value.get()));
141 } 54 }
142 55
143 return policy; 56 return policy;
144 } 57 }
145 58
146 bool PolicyDirLoader::IsSafeToReloadPolicy(const base::Time& now,
147 base::TimeDelta* delay) {
148 DCHECK(delay);
149 file_util::FileInfo dir_info;
150
151 // Reading an empty directory or a file is always safe.
152 if (!file_util::GetFileInfo(config_dir_, &dir_info) ||
153 !dir_info.is_directory) {
154 return true;
155 }
156
157 // Check for too recent changes.
158 base::TimeDelta settleInterval(
159 base::TimeDelta::FromSeconds(settle_interval_seconds_));
160 base::TimeDelta age = now - dir_info.last_modified;
161 if (age < settleInterval) {
162 *delay = settleInterval - age;
163 return false;
164 }
165
166 return true;
167 }
168
169 void PolicyDirLoader::ScheduleReloadTask(const base::TimeDelta& delay) {
170 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE));
171
172 if (reload_task_)
173 reload_task_->Cancel();
174
175 reload_task_ = NewRunnableMethod(this, &PolicyDirLoader::ReloadFromTask);
176 ChromeThread::PostDelayedTask(ChromeThread::FILE, FROM_HERE, reload_task_,
177 delay.InMilliseconds());
178 }
179
180 void PolicyDirLoader::NotifyPolicyChanged() {
181 DCHECK_EQ(origin_loop_, MessageLoop::current());
182 if (provider_)
183 provider_->NotifyStoreOfPolicyChange();
184 }
185
186 void PolicyDirLoader::ReloadFromTask() {
187 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE));
188
189 // Drop the reference to the reload task, since the task might be the only
190 // referer that keeps us alive, so we should not Cancel() it.
191 reload_task_ = NULL;
192
193 Reload();
194 }
195
196 // PolicyDirWatcher implementation:
197
198 void PolicyDirWatcher::Init(PolicyDirLoader* loader) {
199 // Initialization can happen early when the file thread is not yet available.
200 // So post a task to ourselves on th UI thread which will run after threading
201 // is up and schedule watch initialization on the file thread.
202 ChromeThread::PostTask(ChromeThread::UI, FROM_HERE,
203 NewRunnableMethod(this,
204 &PolicyDirWatcher::InitWatcher,
205 scoped_refptr<PolicyDirLoader>(loader)));
206 }
207
208 void PolicyDirWatcher::InitWatcher(
209 const scoped_refptr<PolicyDirLoader>& loader) {
210 if (!ChromeThread::CurrentlyOn(ChromeThread::FILE)) {
211 ChromeThread::PostTask(ChromeThread::FILE, FROM_HERE,
212 NewRunnableMethod(this, &PolicyDirWatcher::InitWatcher, loader));
213 return;
214 }
215
216 if (!Watch(loader->config_dir(), loader.get()))
217 loader->OnError();
218
219 // There might have been changes to the directory in the time between
220 // construction of the loader and initialization of the watcher. Call reload
221 // to detect if that is the case.
222 loader->Reload();
223 }
224
225 // ConfigDirPolicyProvider implementation:
226
227 ConfigDirPolicyProvider::ConfigDirPolicyProvider(const FilePath& config_dir) {
228 loader_ = new PolicyDirLoader(AsWeakPtr(), config_dir, kSettleIntervalSeconds,
229 kReloadIntervalMinutes);
230 watcher_ = new PolicyDirWatcher;
231 watcher_->Init(loader_.get());
232 }
233
234 ConfigDirPolicyProvider::~ConfigDirPolicyProvider() {
235 loader_->Stop();
236 }
237
238 bool ConfigDirPolicyProvider::Provide(ConfigurationPolicyStore* store) {
239 scoped_ptr<DictionaryValue> policy(loader_->GetPolicy());
240 DCHECK(policy.get());
241 DecodePolicyValueTree(policy.get(), store);
242 return true;
243 }
244
245 void ConfigDirPolicyProvider::DecodePolicyValueTree( 59 void ConfigDirPolicyProvider::DecodePolicyValueTree(
246 DictionaryValue* policies, 60 DictionaryValue* policies,
247 ConfigurationPolicyStore* store) { 61 ConfigurationPolicyStore* store) {
248 const PolicyValueMap* mapping = PolicyValueMapping(); 62 const PolicyValueMap* mapping = PolicyValueMapping();
249 for (PolicyValueMap::const_iterator i = mapping->begin(); 63 for (PolicyValueMap::const_iterator i = mapping->begin();
250 i != mapping->end(); ++i) { 64 i != mapping->end(); ++i) {
251 const PolicyValueMapEntry& entry(*i); 65 const PolicyValueMapEntry& entry(*i);
252 Value* value; 66 Value* value;
253 if (policies->Get(entry.name, &value) && value->IsType(entry.value_type)) 67 if (policies->Get(entry.name, &value) && value->IsType(entry.value_type))
254 store->Apply(entry.policy_type, value->DeepCopy()); 68 store->Apply(entry.policy_type, value->DeepCopy());
255 } 69 }
256 70
257 // TODO(mnissler): Handle preference overrides once |ConfigurationPolicyStore| 71 // TODO(mnissler): Handle preference overrides once |ConfigurationPolicyStore|
258 // supports it. 72 // supports it.
259 } 73 }
74
OLDNEW
« no previous file with comments | « chrome/browser/policy/config_dir_policy_provider.h ('k') | chrome/browser/policy/config_dir_policy_provider_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698