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

Side by Side Diff: remoting/host/policy_hack/policy_watcher_linux.cc

Issue 10804040: [Chromoting] Refactor the host policy watcher so that policies can easily be added. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Fix for Windows. Created 8 years, 5 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) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 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 // Most of this code is copied from various classes in 5 // Most of this code is copied from various classes in
6 // src/chrome/browser/policy. In particular, look at 6 // src/chrome/browser/policy. In particular, look at
7 // 7 //
8 // file_based_policy_loader.{h,cc} 8 // file_based_policy_loader.{h,cc}
9 // config_dir_policy_provider.{h,cc} 9 // config_dir_policy_provider.{h,cc}
10 // 10 //
11 // This is a reduction of the functionality in those classes. 11 // This is a reduction of the functionality in those classes.
12 12
13 #include <set> 13 #include <set>
14 14
15 #include "remoting/host/policy_hack/nat_policy.h" 15 #include "remoting/host/policy_hack/policy_watcher.h"
16 16
17 #include "base/bind.h" 17 #include "base/bind.h"
18 #include "base/compiler_specific.h" 18 #include "base/compiler_specific.h"
19 #include "base/file_path.h" 19 #include "base/file_path.h"
20 #include "base/file_util.h" 20 #include "base/file_util.h"
21 #include "base/files/file_path_watcher.h" 21 #include "base/files/file_path_watcher.h"
22 #include "base/json/json_file_value_serializer.h" 22 #include "base/json/json_file_value_serializer.h"
23 #include "base/memory/scoped_ptr.h" 23 #include "base/memory/scoped_ptr.h"
24 #include "base/memory/weak_ptr.h" 24 #include "base/memory/weak_ptr.h"
25 #include "base/single_thread_task_runner.h" 25 #include "base/single_thread_task_runner.h"
26 #include "base/synchronization/waitable_event.h" 26 #include "base/synchronization/waitable_event.h"
27 #include "base/time.h" 27 #include "base/time.h"
28 #include "base/values.h" 28 #include "base/values.h"
29 29
30 namespace remoting { 30 namespace remoting {
31 namespace policy_hack { 31 namespace policy_hack {
32 32
33 namespace { 33 namespace {
34 34
35 const FilePath::CharType kPolicyDir[] = 35 const FilePath::CharType kPolicyDir[] =
36 FILE_PATH_LITERAL("/etc/opt/chrome/policies/managed"); 36 FILE_PATH_LITERAL("/etc/opt/chrome/policies/managed");
37 37
38 // Amount of time we wait for the files on disk to settle before trying to load 38 // Amount of time we wait for the files on disk to settle before trying to load
39 // them. This alleviates the problem of reading partially written files and 39 // them. This alleviates the problem of reading partially written files and
40 // makes it possible to batch quasi-simultaneous changes. 40 // makes it possible to batch quasi-simultaneous changes.
41 const int kSettleIntervalSeconds = 5; 41 const int kSettleIntervalSeconds = 5;
42 42
43 } // namespace 43 } // namespace
44 44
45 class NatPolicyLinux : public NatPolicy { 45 class PolicyWatcherLinux : public PolicyWatcher {
46 public: 46 public:
47 NatPolicyLinux(scoped_refptr<base::SingleThreadTaskRunner> task_runner, 47 PolicyWatcherLinux(scoped_refptr<base::SingleThreadTaskRunner> task_runner,
48 const FilePath& config_dir) 48 const FilePath& config_dir)
49 : NatPolicy(task_runner), 49 : PolicyWatcher(task_runner),
50 config_dir_(config_dir), 50 config_dir_(config_dir),
51 ALLOW_THIS_IN_INITIALIZER_LIST(weak_factory_(this)) { 51 ALLOW_THIS_IN_INITIALIZER_LIST(weak_factory_(this)) {
52 // Detach the factory because we ensure that only the policy thread ever 52 // Detach the factory because we ensure that only the policy thread ever
53 // calls methods on this. Also, the API contract of having to call 53 // calls methods on this. Also, the API contract of having to call
54 // StopWatching() (which signals completion) after StartWatching() 54 // StopWatching() (which signals completion) after StartWatching()
55 // before this object can be destructed ensures there are no users of 55 // before this object can be destructed ensures there are no users of
56 // this object before it is destructed. 56 // this object before it is destructed.
57 weak_factory_.DetachFromThread(); 57 weak_factory_.DetachFromThread();
58 } 58 }
59 59
60 virtual ~NatPolicyLinux() {} 60 virtual ~PolicyWatcherLinux() {}
61 61
62 protected: 62 protected:
63 virtual void StartWatchingInternal() OVERRIDE { 63 virtual void StartWatchingInternal() OVERRIDE {
64 DCHECK(OnPolicyThread()); 64 DCHECK(OnPolicyWatcherThread());
65 watcher_.reset(new base::files::FilePathWatcher()); 65 watcher_.reset(new base::files::FilePathWatcher());
66 66
67 if (!config_dir_.empty() && 67 if (!config_dir_.empty() &&
68 !watcher_->Watch( 68 !watcher_->Watch(
69 config_dir_, 69 config_dir_,
70 new FilePathWatcherDelegate(weak_factory_.GetWeakPtr()))) { 70 new FilePathWatcherDelegate(weak_factory_.GetWeakPtr()))) {
71 OnFilePathError(config_dir_); 71 OnFilePathError(config_dir_);
72 } 72 }
73 73
74 // There might have been changes to the directory in the time between 74 // There might have been changes to the directory in the time between
75 // construction of the loader and initialization of the watcher. Call reload 75 // construction of the loader and initialization of the watcher. Call reload
76 // to detect if that is the case. 76 // to detect if that is the case.
77 Reload(); 77 Reload();
78 78
79 ScheduleFallbackReloadTask(); 79 ScheduleFallbackReloadTask();
80 } 80 }
81 81
82 virtual void StopWatchingInternal() OVERRIDE { 82 virtual void StopWatchingInternal() OVERRIDE {
83 DCHECK(OnPolicyThread()); 83 DCHECK(OnPolicyWatcherThread());
84 // Cancel any inflight requests. 84 // Cancel any inflight requests.
85 watcher_.reset(); 85 watcher_.reset();
86 } 86 }
87 87
88 // Called by FilePathWatcherDelegate. 88 // Called by FilePathWatcherDelegate.
89 virtual void OnFilePathError(const FilePath& path) { 89 virtual void OnFilePathError(const FilePath& path) {
90 LOG(ERROR) << "NatPolicyLinux on " << path.value() 90 LOG(ERROR) << "PolicyWatcherLinux on " << path.value()
91 << " failed."; 91 << " failed.";
92 } 92 }
93 93
94 // Called by FilePathWatcherDelegate. 94 // Called by FilePathWatcherDelegate.
95 virtual void OnFilePathChanged(const FilePath& path) { 95 virtual void OnFilePathChanged(const FilePath& path) {
96 DCHECK(OnPolicyThread()); 96 DCHECK(OnPolicyWatcherThread());
97 97
98 Reload(); 98 Reload();
99 } 99 }
100 100
101 private: 101 private:
102 // Needed to avoid refcounting NatPolicyLinux. 102 // Needed to avoid refcounting PolicyWatcherLinux.
103 class FilePathWatcherDelegate : 103 class FilePathWatcherDelegate :
104 public base::files::FilePathWatcher::Delegate { 104 public base::files::FilePathWatcher::Delegate {
105 public: 105 public:
106 FilePathWatcherDelegate(base::WeakPtr<NatPolicyLinux> policy_watcher) 106 FilePathWatcherDelegate(base::WeakPtr<PolicyWatcherLinux> policy_watcher)
107 : policy_watcher_(policy_watcher) { 107 : policy_watcher_(policy_watcher) {
108 } 108 }
109 109
110 virtual void OnFilePathError(const FilePath& path) { 110 virtual void OnFilePathError(const FilePath& path) {
111 if (policy_watcher_) { 111 if (policy_watcher_) {
112 policy_watcher_->OnFilePathError(path); 112 policy_watcher_->OnFilePathError(path);
113 } 113 }
114 } 114 }
115 115
116 virtual void OnFilePathChanged(const FilePath& path) { 116 virtual void OnFilePathChanged(const FilePath& path) {
117 if (policy_watcher_) { 117 if (policy_watcher_) {
118 policy_watcher_->OnFilePathChanged(path); 118 policy_watcher_->OnFilePathChanged(path);
119 } 119 }
120 } 120 }
121 121
122 protected: 122 protected:
123 virtual ~FilePathWatcherDelegate() {} 123 virtual ~FilePathWatcherDelegate() {}
124 124
125 private: 125 private:
126 base::WeakPtr<NatPolicyLinux> policy_watcher_; 126 base::WeakPtr<PolicyWatcherLinux> policy_watcher_;
127 }; 127 };
128 128
129 base::Time GetLastModification() { 129 base::Time GetLastModification() {
130 DCHECK(OnPolicyThread()); 130 DCHECK(OnPolicyWatcherThread());
131 base::Time last_modification = base::Time(); 131 base::Time last_modification = base::Time();
132 base::PlatformFileInfo file_info; 132 base::PlatformFileInfo file_info;
133 133
134 // If the path does not exist or points to a directory, it's safe to load. 134 // If the path does not exist or points to a directory, it's safe to load.
135 if (!file_util::GetFileInfo(config_dir_, &file_info) || 135 if (!file_util::GetFileInfo(config_dir_, &file_info) ||
136 !file_info.is_directory) { 136 !file_info.is_directory) {
137 return last_modification; 137 return last_modification;
138 } 138 }
139 139
140 // Enumerate the files and find the most recent modification timestamp. 140 // Enumerate the files and find the most recent modification timestamp.
141 file_util::FileEnumerator file_enumerator(config_dir_, 141 file_util::FileEnumerator file_enumerator(config_dir_,
142 false, 142 false,
143 file_util::FileEnumerator::FILES); 143 file_util::FileEnumerator::FILES);
144 for (FilePath config_file = file_enumerator.Next(); 144 for (FilePath config_file = file_enumerator.Next();
145 !config_file.empty(); 145 !config_file.empty();
146 config_file = file_enumerator.Next()) { 146 config_file = file_enumerator.Next()) {
147 if (file_util::GetFileInfo(config_file, &file_info) && 147 if (file_util::GetFileInfo(config_file, &file_info) &&
148 !file_info.is_directory) { 148 !file_info.is_directory) {
149 last_modification = std::max(last_modification, 149 last_modification = std::max(last_modification,
150 file_info.last_modified); 150 file_info.last_modified);
151 } 151 }
152 } 152 }
153 153
154 return last_modification; 154 return last_modification;
155 } 155 }
156 156
157 // Caller owns the value. 157 // Caller owns the value.
158 DictionaryValue* Load() { 158 DictionaryValue* Load() {
159 DCHECK(OnPolicyThread()); 159 DCHECK(OnPolicyWatcherThread());
160 // Enumerate the files and sort them lexicographically. 160 // Enumerate the files and sort them lexicographically.
161 std::set<FilePath> files; 161 std::set<FilePath> files;
162 file_util::FileEnumerator file_enumerator(config_dir_, false, 162 file_util::FileEnumerator file_enumerator(config_dir_, false,
163 file_util::FileEnumerator::FILES); 163 file_util::FileEnumerator::FILES);
164 for (FilePath config_file_path = file_enumerator.Next(); 164 for (FilePath config_file_path = file_enumerator.Next();
165 !config_file_path.empty(); config_file_path = file_enumerator.Next()) 165 !config_file_path.empty(); config_file_path = file_enumerator.Next())
166 files.insert(config_file_path); 166 files.insert(config_file_path);
167 167
168 // Start with an empty dictionary and merge the files' contents. 168 // Start with an empty dictionary and merge the files' contents.
169 DictionaryValue* policy = new DictionaryValue(); 169 DictionaryValue* policy = new DictionaryValue();
(...skipping 15 matching lines...) Expand all
185 << config_file_iter->value(); 185 << config_file_iter->value();
186 continue; 186 continue;
187 } 187 }
188 policy->MergeDictionary(static_cast<DictionaryValue*>(value.get())); 188 policy->MergeDictionary(static_cast<DictionaryValue*>(value.get()));
189 } 189 }
190 190
191 return policy; 191 return policy;
192 } 192 }
193 193
194 void Reload() { 194 void Reload() {
195 DCHECK(OnPolicyThread()); 195 DCHECK(OnPolicyWatcherThread());
196 // Check the directory time in order to see whether a reload is required. 196 // Check the directory time in order to see whether a reload is required.
197 base::TimeDelta delay; 197 base::TimeDelta delay;
198 base::Time now = base::Time::Now(); 198 base::Time now = base::Time::Now();
199 if (!IsSafeToReloadPolicy(now, &delay)) { 199 if (!IsSafeToReloadPolicy(now, &delay)) {
200 ScheduleReloadTask(delay); 200 ScheduleReloadTask(delay);
201 return; 201 return;
202 } 202 }
203 203
204 // Check again in case the directory has changed while reading it. 204 // Check again in case the directory has changed while reading it.
205 if (!IsSafeToReloadPolicy(now, &delay)) { 205 if (!IsSafeToReloadPolicy(now, &delay)) {
206 ScheduleReloadTask(delay); 206 ScheduleReloadTask(delay);
207 return; 207 return;
208 } 208 }
209 209
210 // Load the policy definitions. 210 // Load the policy definitions.
211 scoped_ptr<DictionaryValue> new_policy(Load()); 211 scoped_ptr<DictionaryValue> new_policy(Load());
212 UpdateNatPolicy(new_policy.get()); 212 UpdatePolicies(new_policy.get());
213 213
214 ScheduleFallbackReloadTask(); 214 ScheduleFallbackReloadTask();
215 } 215 }
216 216
217 bool IsSafeToReloadPolicy(const base::Time& now, base::TimeDelta* delay) { 217 bool IsSafeToReloadPolicy(const base::Time& now, base::TimeDelta* delay) {
218 DCHECK(OnPolicyThread()); 218 DCHECK(OnPolicyWatcherThread());
219 DCHECK(delay); 219 DCHECK(delay);
220 const base::TimeDelta kSettleInterval = 220 const base::TimeDelta kSettleInterval =
221 base::TimeDelta::FromSeconds(kSettleIntervalSeconds); 221 base::TimeDelta::FromSeconds(kSettleIntervalSeconds);
222 222
223 base::Time last_modification = GetLastModification(); 223 base::Time last_modification = GetLastModification();
224 if (last_modification.is_null()) 224 if (last_modification.is_null())
225 return true; 225 return true;
226 226
227 if (last_modification_file_.is_null()) 227 if (last_modification_file_.is_null())
228 last_modification_file_ = last_modification; 228 last_modification_file_ = last_modification;
(...skipping 11 matching lines...) Expand all
240 base::TimeDelta age = now - last_modification_clock_; 240 base::TimeDelta age = now - last_modification_clock_;
241 if (age < kSettleInterval) { 241 if (age < kSettleInterval) {
242 *delay = kSettleInterval - age; 242 *delay = kSettleInterval - age;
243 return false; 243 return false;
244 } 244 }
245 245
246 return true; 246 return true;
247 } 247 }
248 248
249 // Managed with a scoped_ptr rather than being declared as an inline member to 249 // Managed with a scoped_ptr rather than being declared as an inline member to
250 // decouple the watcher's life cycle from the NatPolicyLinux. This decoupling 250 // decouple the watcher's life cycle from the PolicyWatcherLinux. This
251 // makes it possible to destroy the watcher before the loader's destructor is 251 // decoupling makes it possible to destroy the watcher before the loader's
252 // called (e.g. during Stop), since |watcher_| internally holds a reference to 252 // destructor is called (e.g. during Stop), since |watcher_| internally holds
253 // the loader and keeps it alive. 253 // a reference to the loader and keeps it alive.
254 scoped_ptr<base::files::FilePathWatcher> watcher_; 254 scoped_ptr<base::files::FilePathWatcher> watcher_;
255 255
256 // Records last known modification timestamp of |config_dir_|. 256 // Records last known modification timestamp of |config_dir_|.
257 base::Time last_modification_file_; 257 base::Time last_modification_file_;
258 258
259 // The wall clock time at which the last modification timestamp was 259 // The wall clock time at which the last modification timestamp was
260 // recorded. It's better to not assume the file notification time and the 260 // recorded. It's better to not assume the file notification time and the
261 // wall clock times come from the same source, just in case there is some 261 // wall clock times come from the same source, just in case there is some
262 // non-local filesystem involved. 262 // non-local filesystem involved.
263 base::Time last_modification_clock_; 263 base::Time last_modification_clock_;
264 264
265 const FilePath config_dir_; 265 const FilePath config_dir_;
266 266
267 // Allows us to cancel any inflight FileWatcher events or scheduled reloads. 267 // Allows us to cancel any inflight FileWatcher events or scheduled reloads.
268 base::WeakPtrFactory<NatPolicyLinux> weak_factory_; 268 base::WeakPtrFactory<PolicyWatcherLinux> weak_factory_;
269 }; 269 };
270 270
271 NatPolicy* NatPolicy::Create( 271 PolicyWatcher* PolicyWatcher::Create(
272 scoped_refptr<base::SingleThreadTaskRunner> task_runner) { 272 scoped_refptr<base::SingleThreadTaskRunner> task_runner) {
273 FilePath policy_dir(kPolicyDir); 273 FilePath policy_dir(kPolicyDir);
274 return new NatPolicyLinux(task_runner, policy_dir); 274 return new PolicyWatcherLinux(task_runner, policy_dir);
275 } 275 }
276 276
277 } // namespace policy_hack 277 } // namespace policy_hack
278 } // namespace remoting 278 } // namespace remoting
OLDNEW
« no previous file with comments | « remoting/host/policy_hack/policy_watcher.cc ('k') | remoting/host/policy_hack/policy_watcher_mac.mm » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698