OLD | NEW |
---|---|
(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 // it. This alleviates the problem of reading partially written files and allows | |
Mattias Nissler (ping if slow)
2010/12/06 10:26:20
s/it/them/
danno
2010/12/06 14:05:12
Done.
| |
11 // 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_interval_(base::TimeDelta::FromMinutes(kReloadIntervalMinutes)), | |
28 settle_interval_(base::TimeDelta::FromSeconds(kSettleIntervalSeconds)) { | |
29 } | |
30 | |
31 class FileBasedPolicyWatcherDelegate : public FilePathWatcher::Delegate { | |
32 public: | |
33 explicit FileBasedPolicyWatcherDelegate( | |
34 scoped_refptr<FileBasedPolicyLoader> loader) | |
35 : loader_(loader) {} | |
36 virtual ~FileBasedPolicyWatcherDelegate() {} | |
37 | |
38 // FilePathWatcher::Delegate implementation: | |
39 void OnFilePathChanged(const FilePath& path) { | |
40 loader_->OnFilePathChanged(path); | |
41 } | |
42 | |
43 void OnError() { | |
44 loader_->OnError(); | |
45 } | |
46 | |
47 private: | |
48 scoped_refptr<FileBasedPolicyLoader> loader_; | |
49 DISALLOW_COPY_AND_ASSIGN(FileBasedPolicyWatcherDelegate); | |
50 }; | |
51 | |
52 void FileBasedPolicyLoader::Init() { | |
53 AsynchronousPolicyLoader::Init(); | |
54 | |
55 // Initialization can happen early when the file thread is not | |
56 // yet available. So post a task on the FILE thread which will run after | |
57 // threading is up and schedule watch initialization on the file thread. | |
Mattias Nissler (ping if slow)
2010/12/06 10:26:20
Didn't we post on the UI thread before? That was i
danno
2010/12/06 14:05:12
Done.
| |
58 BrowserThread::PostTask( | |
59 BrowserThread::FILE, FROM_HERE, | |
60 NewRunnableMethod(this, &FileBasedPolicyLoader::InitWatcher)); | |
61 | |
62 ScheduleFallbackReloadTask(); | |
63 } | |
64 | |
65 void FileBasedPolicyLoader::Stop() { | |
66 AsynchronousPolicyLoader::Stop(); | |
67 BrowserThread::PostTask( | |
68 BrowserThread::FILE, FROM_HERE, | |
69 NewRunnableMethod(this, &FileBasedPolicyLoader::StopOnFileThread)); | |
70 } | |
71 | |
72 void FileBasedPolicyLoader::OnFilePathChanged( | |
73 const FilePath& path) { | |
74 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); | |
75 Reload(); | |
76 } | |
77 | |
78 void FileBasedPolicyLoader::OnError() { | |
79 LOG(ERROR) << "FilePathWatcher on " << config_file_path().value() | |
80 << " failed."; | |
81 } | |
82 | |
83 void FileBasedPolicyLoader::Reload() { | |
84 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); | |
85 // Check the directory time in order to see whether a reload is required. | |
86 base::TimeDelta delay; | |
87 base::Time now = base::Time::Now(); | |
88 if (!IsSafeToReloadPolicy(now, &delay)) { | |
89 ScheduleReloadTask(delay); | |
90 return; | |
91 } | |
92 | |
93 // Load the policy definitions. | |
94 scoped_ptr<DictionaryValue> new_policy(delegate()->Load()); | |
95 | |
96 // Check again in case the directory has changed while reading it. | |
97 if (!IsSafeToReloadPolicy(now, &delay)) { | |
98 ScheduleReloadTask(delay); | |
99 return; | |
100 } | |
101 | |
102 PostUpdatePolicyTask(new_policy.release()); | |
103 | |
104 ScheduleFallbackReloadTask(); | |
105 } | |
106 | |
107 void FileBasedPolicyLoader::InitWatcher() { | |
108 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); | |
109 watcher_.reset(new FilePathWatcher); | |
110 if (!config_file_path().empty() && | |
111 !watcher_->Watch(config_file_path(), | |
112 new FileBasedPolicyWatcherDelegate(this))) | |
113 OnError(); | |
Mattias Nissler (ping if slow)
2010/12/06 10:26:20
need curlies here.
danno
2010/12/06 14:05:12
Done.
| |
114 | |
115 // There might have been changes to the directory in the time between | |
116 // construction of the loader and initialization of the watcher. Call reload | |
117 // to detect if that is the case. | |
118 Reload(); | |
119 } | |
120 | |
121 void FileBasedPolicyLoader::StopOnFileThread() { | |
122 watcher_.reset(); | |
123 if (reload_task_) { | |
124 reload_task_->Cancel(); | |
125 reload_task_ = NULL; | |
126 } | |
127 } | |
128 | |
129 void FileBasedPolicyLoader::ScheduleReloadTask( | |
130 const base::TimeDelta& delay) { | |
131 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); | |
132 | |
133 if (reload_task_) | |
134 reload_task_->Cancel(); | |
135 | |
136 reload_task_ = | |
137 NewRunnableMethod(this, &FileBasedPolicyLoader::ReloadFromTask); | |
138 BrowserThread::PostDelayedTask(BrowserThread::FILE, FROM_HERE, reload_task_, | |
139 delay.InMilliseconds()); | |
140 } | |
141 | |
142 void FileBasedPolicyLoader::ScheduleFallbackReloadTask() { | |
143 // As a safeguard in case that the load delegate failed to timely notice a | |
144 // change in policy, schedule a reload task that'll make us recheck after a | |
145 // reasonable interval. | |
146 ScheduleReloadTask(reload_interval_); | |
147 } | |
148 | |
149 void FileBasedPolicyLoader::ReloadFromTask() { | |
150 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); | |
151 | |
152 // Drop the reference to the reload task, since the task might be the only | |
153 // referer that keeps us alive, so we should not Cancel() it. | |
154 reload_task_ = NULL; | |
155 | |
156 Reload(); | |
157 } | |
158 | |
159 bool FileBasedPolicyLoader::IsSafeToReloadPolicy( | |
160 const base::Time& now, | |
161 base::TimeDelta* delay) { | |
162 DCHECK(delay); | |
163 | |
164 // A null modification time indicates there's no data. | |
165 base::Time last_modification(provider_delegate_->GetLastModification()); | |
166 if (last_modification.is_null()) | |
167 return true; | |
168 | |
169 // If there was a change since the last recorded modification, wait some more. | |
170 if (last_modification != last_modification_file_) { | |
171 last_modification_file_ = last_modification; | |
172 last_modification_clock_ = now; | |
173 *delay = settle_interval_; | |
174 return false; | |
175 } | |
176 | |
177 // Check whether the settle interval has elapsed. | |
178 base::TimeDelta age = now - last_modification_clock_; | |
179 if (age < settle_interval_) { | |
180 *delay = settle_interval_ - age; | |
181 return false; | |
182 } | |
183 | |
184 return true; | |
185 } | |
186 | |
187 } // namespace policy | |
OLD | NEW |