| 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 "chrome/browser/policy/policy_bundle.h" |
| 10 #include "content/public/browser/browser_thread.h" |
| 11 |
| 12 using base::Time; |
| 13 using base::TimeDelta; |
| 14 using content::BrowserThread; |
| 15 |
| 16 namespace policy { |
| 17 |
| 18 namespace { |
| 19 |
| 20 // Amount of time to wait for the files on disk to settle before trying to load |
| 21 // them. This alleviates the problem of reading partially written files and |
| 22 // makes it possible to batch quasi-simultaneous changes. |
| 23 const int kSettleIntervalSeconds = 5; |
| 24 |
| 25 // The time interval for rechecking policy. This is the fallback in case the |
| 26 // implementation never detects changes. |
| 27 const int kReloadIntervalSeconds = 15 * 60; |
| 28 |
| 29 } // namespace |
| 30 |
| 31 AsyncPolicyLoader::AsyncPolicyLoader() |
| 32 : ALLOW_THIS_IN_INITIALIZER_LIST(weak_factory_(this)) {} |
| 33 |
| 34 AsyncPolicyLoader::~AsyncPolicyLoader() { |
| 35 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); |
| 36 } |
| 37 |
| 38 base::Time AsyncPolicyLoader::LastModificationTime() { |
| 39 return base::Time(); |
| 40 } |
| 41 |
| 42 void AsyncPolicyLoader::Reload(bool force) { |
| 43 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); |
| 44 |
| 45 TimeDelta delay; |
| 46 Time now = Time::Now(); |
| 47 // Check if there was a recent modification to the underlying files. |
| 48 if (!force && !IsSafeToReload(now, &delay)) { |
| 49 ScheduleNextReload(delay); |
| 50 return; |
| 51 } |
| 52 |
| 53 scoped_ptr<PolicyBundle> bundle(Load()); |
| 54 |
| 55 // Check if there was a modification while reading. |
| 56 if (!force && !IsSafeToReload(now, &delay)) { |
| 57 ScheduleNextReload(delay); |
| 58 return; |
| 59 } |
| 60 |
| 61 provider_loop_->PostTask(FROM_HERE, |
| 62 base::Bind(update_callback_, base::Passed(&bundle))); |
| 63 ScheduleNextReload(TimeDelta::FromSeconds(kReloadIntervalSeconds)); |
| 64 } |
| 65 |
| 66 scoped_ptr<PolicyBundle> AsyncPolicyLoader::InitialLoad() { |
| 67 // This is the first load, early during startup. Use this to record the |
| 68 // initial |last_modification_time_|, so that potential changes made before |
| 69 // installing the watches can be detected. |
| 70 last_modification_time_ = LastModificationTime(); |
| 71 return Load(); |
| 72 } |
| 73 |
| 74 void AsyncPolicyLoader::Init( |
| 75 scoped_refptr<base::MessageLoopProxy> provider_loop, |
| 76 const UpdateCallback& update_callback) { |
| 77 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); |
| 78 DCHECK(update_callback_.is_null()); |
| 79 DCHECK(!update_callback.is_null()); |
| 80 update_callback_ = update_callback; |
| 81 provider_loop_ = provider_loop; |
| 82 |
| 83 InitOnFile(); |
| 84 |
| 85 // There might have been changes to the underlying files since the initial |
| 86 // load and before the watchers have been created. |
| 87 if (LastModificationTime() != last_modification_time_) |
| 88 Reload(false); |
| 89 |
| 90 // Start periodic refreshes. |
| 91 ScheduleNextReload(TimeDelta::FromSeconds(kReloadIntervalSeconds)); |
| 92 } |
| 93 |
| 94 void AsyncPolicyLoader::ScheduleNextReload(TimeDelta delay) { |
| 95 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); |
| 96 weak_factory_.InvalidateWeakPtrs(); |
| 97 BrowserThread::PostDelayedTask( |
| 98 BrowserThread::FILE, FROM_HERE, |
| 99 base::Bind(&AsyncPolicyLoader::Reload, |
| 100 weak_factory_.GetWeakPtr(), |
| 101 false /* force */), |
| 102 delay); |
| 103 } |
| 104 |
| 105 bool AsyncPolicyLoader::IsSafeToReload(const Time& now, TimeDelta* delay) { |
| 106 Time last_modification = LastModificationTime(); |
| 107 if (last_modification.is_null()) |
| 108 return true; |
| 109 |
| 110 // If there was a change since the last recorded modification, wait some more. |
| 111 const TimeDelta kSettleInterval( |
| 112 TimeDelta::FromSeconds(kSettleIntervalSeconds)); |
| 113 if (last_modification != last_modification_time_) { |
| 114 last_modification_time_ = last_modification; |
| 115 last_modification_clock_ = now; |
| 116 *delay = kSettleInterval; |
| 117 return false; |
| 118 } |
| 119 |
| 120 // Check whether the settle interval has elapsed. |
| 121 const base::TimeDelta age = now - last_modification_clock_; |
| 122 if (age < kSettleInterval) { |
| 123 *delay = kSettleInterval - age; |
| 124 return false; |
| 125 } |
| 126 |
| 127 return true; |
| 128 } |
| 129 |
| 130 } // namespace policy |
| OLD | NEW |