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

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

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

Powered by Google App Engine
This is Rietveld 408576698