Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 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 | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 #include "chrome/browser/policy/async_policy_loader.h" | |
| 6 | |
| 7 #include "base/bind.h" | |
| 8 #include "base/bind_helpers.h" | |
| 9 #include "base/file_path.h" | |
| 10 #include "base/files/file_path_watcher.h" | |
| 11 #include "chrome/browser/policy/policy_bundle.h" | |
| 12 #include "content/public/browser/browser_thread.h" | |
| 13 | |
| 14 using base::Time; | |
| 15 using base::TimeDelta; | |
| 16 using content::BrowserThread; | |
| 17 | |
| 18 namespace policy { | |
| 19 | |
| 20 namespace { | |
| 21 | |
| 22 // Amount of time to wait for the files on disk to settle before trying to load | |
| 23 // them. This alleviates the problem of reading partially written files and | |
| 24 // makes it possible to batch quasi-simultaneous changes. | |
| 25 const int kSettleIntervalSeconds = 5; | |
| 26 | |
| 27 // The time interval for rechecking policy. This is the fallback in case the | |
| 28 // implementation never detects changes. | |
| 29 const int kReloadIntervalSeconds = 15 * 60; | |
| 30 | |
| 31 // This delegate is owned by the FilePathWatcher. It lives in FILE and notifies | |
| 32 // the AsyncPolicyLoader through the |reload_callback|, which is invalidated | |
| 33 // when the AsyncPolicyLoader is deleted. | |
|
Mattias Nissler (ping if slow)
2012/06/04 08:48:26
Note: net/dns/file_path_watcher_wrapper.h does mos
Joao da Silva
2012/06/04 14:05:06
Moved this to FilePathWatcher in another CL.
| |
| 34 class FilePathWatcherDelegate : public base::files::FilePathWatcher::Delegate { | |
| 35 public: | |
| 36 explicit FilePathWatcherDelegate(const base::Closure& reload_callback) | |
| 37 : reload_callback_(reload_callback) {} | |
| 38 | |
| 39 // FilePathWatcher::Delegate implementation. | |
| 40 virtual void OnFilePathChanged(const FilePath& path) OVERRIDE { | |
| 41 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); | |
| 42 reload_callback_.Run(); | |
| 43 } | |
| 44 | |
| 45 virtual void OnFilePathError(const FilePath& path) OVERRIDE { | |
| 46 DLOG(ERROR) << "FilePathWatcher error: " << path.value(); | |
| 47 } | |
| 48 | |
| 49 private: | |
| 50 virtual ~FilePathWatcherDelegate() {} | |
| 51 | |
| 52 base::Closure reload_callback_; | |
| 53 | |
| 54 DISALLOW_COPY_AND_ASSIGN(FilePathWatcherDelegate); | |
| 55 }; | |
| 56 | |
| 57 } // namespace | |
| 58 | |
| 59 AsyncPolicyLoader::AsyncPolicyLoader() | |
| 60 : ALLOW_THIS_IN_INITIALIZER_LIST(reload_weak_factory_(this)), | |
| 61 ALLOW_THIS_IN_INITIALIZER_LIST(watchers_weak_factory_(this)) {} | |
| 62 | |
| 63 AsyncPolicyLoader::~AsyncPolicyLoader() { | |
| 64 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); | |
| 65 } | |
| 66 | |
| 67 base::Time AsyncPolicyLoader::LastModificationTime() { | |
| 68 return base::Time(); | |
| 69 } | |
| 70 | |
| 71 void AsyncPolicyLoader::Reload(bool force) { | |
| 72 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); | |
| 73 | |
| 74 TimeDelta delay; | |
| 75 Time now = Time::Now(); | |
| 76 // Check if there was a recent modification to the underlying files. | |
| 77 if (!force && !IsSafeToReload(now, &delay)) { | |
| 78 ScheduleNextReload(delay); | |
| 79 return; | |
| 80 } | |
| 81 | |
| 82 scoped_ptr<PolicyBundle> bundle(Load()); | |
| 83 | |
| 84 // Check if there was a modification while reading. | |
| 85 if (!force && !IsSafeToReload(now, &delay)) { | |
| 86 ScheduleNextReload(delay); | |
| 87 return; | |
| 88 } | |
| 89 | |
| 90 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, | |
| 91 base::Bind(update_callback_, base::Passed(&bundle))); | |
| 92 ScheduleNextReload(TimeDelta::FromSeconds(kReloadIntervalSeconds)); | |
| 93 } | |
| 94 | |
| 95 void AsyncPolicyLoader::WatchPath(const FilePath& path) { | |
| 96 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); | |
| 97 base::files::FilePathWatcher* watcher = new base::files::FilePathWatcher(); | |
| 98 base::Closure reload_callback = | |
| 99 base::Bind(&AsyncPolicyLoader::Reload, | |
| 100 watchers_weak_factory_.GetWeakPtr(), | |
| 101 false /* force */); | |
| 102 if (watcher->Watch(path, new FilePathWatcherDelegate(reload_callback))) { | |
|
Mattias Nissler (ping if slow)
2012/06/04 08:48:26
no need for curlies
Joao da Silva
2012/06/04 14:05:06
Done.
| |
| 103 watchers_.push_back(watcher); | |
| 104 } else { | |
| 105 DLOG(ERROR) << "FilePathWatcher error adding watch: " << path.value(); | |
| 106 } | |
| 107 } | |
| 108 | |
| 109 scoped_ptr<PolicyBundle> AsyncPolicyLoader::InitialLoad() { | |
| 110 // This is the first load, early during startup. Use this to record the | |
| 111 // initial |last_modification_time_|, so that potential changes made before | |
| 112 // installing the watches can be detected. | |
| 113 last_modification_time_ = LastModificationTime(); | |
| 114 return Load(); | |
| 115 } | |
| 116 | |
| 117 void AsyncPolicyLoader::Init( | |
| 118 const UpdateCallback& update_callback) { | |
|
Mattias Nissler (ping if slow)
2012/06/04 08:48:26
fits previous line
Joao da Silva
2012/06/04 14:05:06
Done.
| |
| 119 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); | |
| 120 DCHECK(update_callback_.is_null()); | |
| 121 DCHECK(!update_callback.is_null()); | |
| 122 update_callback_ = update_callback; | |
| 123 | |
| 124 InitOnFile(); | |
| 125 | |
| 126 // There might have been changes to the underlying files since the initial | |
| 127 // load and before the watchers have been created. | |
| 128 if (LastModificationTime() != last_modification_time_) | |
| 129 Reload(false); | |
| 130 | |
| 131 // Start periodic refreshes. | |
| 132 ScheduleNextReload(TimeDelta::FromSeconds(kReloadIntervalSeconds)); | |
| 133 } | |
| 134 | |
| 135 void AsyncPolicyLoader::ScheduleNextReload(TimeDelta delay) { | |
| 136 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); | |
| 137 reload_weak_factory_.InvalidateWeakPtrs(); | |
| 138 BrowserThread::PostDelayedTask( | |
| 139 BrowserThread::FILE, FROM_HERE, | |
| 140 base::Bind(&AsyncPolicyLoader::Reload, | |
| 141 reload_weak_factory_.GetWeakPtr(), | |
|
Mattias Nissler (ping if slow)
2012/06/04 08:48:26
indentation
Joao da Silva
2012/06/04 14:05:06
Done.
| |
| 142 false /* force */), | |
| 143 delay); | |
| 144 } | |
| 145 | |
| 146 bool AsyncPolicyLoader::IsSafeToReload(const Time& now, TimeDelta* delay) { | |
| 147 Time last_modification = LastModificationTime(); | |
| 148 if (last_modification.is_null()) | |
| 149 return true; | |
| 150 | |
| 151 // If there was a change since the last recorded modification, wait some more. | |
| 152 TimeDelta kSettleInterval(TimeDelta::FromSeconds(kSettleIntervalSeconds)); | |
|
Mattias Nissler (ping if slow)
2012/06/04 08:48:26
const
Joao da Silva
2012/06/04 14:05:06
Done.
| |
| 153 if (last_modification != last_modification_time_) { | |
| 154 last_modification_time_ = last_modification; | |
| 155 last_modification_clock_ = now; | |
| 156 *delay = kSettleInterval; | |
| 157 return false; | |
| 158 } | |
| 159 | |
| 160 // Check whether the settle interval has elapsed. | |
| 161 base::TimeDelta age = now - last_modification_clock_; | |
| 162 if (age < kSettleInterval) { | |
| 163 *delay = kSettleInterval - age; | |
| 164 return false; | |
| 165 } | |
| 166 | |
| 167 return true; | |
| 168 } | |
| 169 | |
| 170 } // namespace policy | |
| OLD | NEW |