1 // Copyright 2013 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.
5 #include "components/policy/core/common/async_policy_loader.h"
8 #include "base/location.h"
9 #include "base/sequenced_task_runner.h"
10 #include "components/policy/core/common/policy_bundle.h"
13 using base::TimeDelta
;
19 // Amount of time to wait for the files on disk to settle before trying to load
20 // them. This alleviates the problem of reading partially written files and
21 // makes it possible to batch quasi-simultaneous changes.
22 const int kSettleIntervalSeconds
= 5;
24 // The time interval for rechecking policy. This is the fallback in case the
25 // implementation never detects changes.
26 const int kReloadIntervalSeconds
= 15 * 60;
30 AsyncPolicyLoader::AsyncPolicyLoader(
31 const scoped_refptr
<base::SequencedTaskRunner
>& task_runner
)
32 : task_runner_(task_runner
),
33 weak_factory_(this) {}
35 AsyncPolicyLoader::~AsyncPolicyLoader() {}
37 Time
AsyncPolicyLoader::LastModificationTime() {
41 void AsyncPolicyLoader::Reload(bool force
) {
42 DCHECK(task_runner_
->RunsTasksOnCurrentThread());
45 Time now
= Time::Now();
46 // Check if there was a recent modification to the underlying files.
47 if (!force
&& !IsSafeToReload(now
, &delay
)) {
48 ScheduleNextReload(delay
);
52 scoped_ptr
<PolicyBundle
> bundle(Load());
54 // Check if there was a modification while reading.
55 if (!force
&& !IsSafeToReload(now
, &delay
)) {
56 ScheduleNextReload(delay
);
60 // Filter out mismatching policies.
61 schema_map_
->FilterBundle(bundle
.get());
63 update_callback_
.Run(bundle
.Pass());
64 ScheduleNextReload(TimeDelta::FromSeconds(kReloadIntervalSeconds
));
67 scoped_ptr
<PolicyBundle
> AsyncPolicyLoader::InitialLoad(
68 const scoped_refptr
<SchemaMap
>& schema_map
) {
69 // This is the first load, early during startup. Use this to record the
70 // initial |last_modification_time_|, so that potential changes made before
71 // installing the watches can be detected.
72 last_modification_time_
= LastModificationTime();
73 schema_map_
= schema_map
;
74 scoped_ptr
<PolicyBundle
> bundle(Load());
75 // Filter out mismatching policies.
76 schema_map_
->FilterBundle(bundle
.get());
80 void AsyncPolicyLoader::Init(const UpdateCallback
& update_callback
) {
81 DCHECK(task_runner_
->RunsTasksOnCurrentThread());
82 DCHECK(update_callback_
.is_null());
83 DCHECK(!update_callback
.is_null());
84 update_callback_
= update_callback
;
86 InitOnBackgroundThread();
88 // There might have been changes to the underlying files since the initial
89 // load and before the watchers have been created.
90 if (LastModificationTime() != last_modification_time_
)
93 // Start periodic refreshes.
94 ScheduleNextReload(TimeDelta::FromSeconds(kReloadIntervalSeconds
));
97 void AsyncPolicyLoader::RefreshPolicies(scoped_refptr
<SchemaMap
> schema_map
) {
98 DCHECK(task_runner_
->RunsTasksOnCurrentThread());
99 schema_map_
= schema_map
;
103 void AsyncPolicyLoader::ScheduleNextReload(TimeDelta delay
) {
104 DCHECK(task_runner_
->RunsTasksOnCurrentThread());
105 weak_factory_
.InvalidateWeakPtrs();
106 task_runner_
->PostDelayedTask(FROM_HERE
,
107 base::Bind(&AsyncPolicyLoader::Reload
,
108 weak_factory_
.GetWeakPtr(),
113 bool AsyncPolicyLoader::IsSafeToReload(const Time
& now
, TimeDelta
* delay
) {
114 Time last_modification
= LastModificationTime();
115 if (last_modification
.is_null())
118 // If there was a change since the last recorded modification, wait some more.
119 const TimeDelta
kSettleInterval(
120 TimeDelta::FromSeconds(kSettleIntervalSeconds
));
121 if (last_modification
!= last_modification_time_
) {
122 last_modification_time_
= last_modification
;
123 last_modification_clock_
= now
;
124 *delay
= kSettleInterval
;
128 // Check whether the settle interval has elapsed.
129 const TimeDelta age
= now
- last_modification_clock_
;
130 if (age
< kSettleInterval
) {
131 *delay
= kSettleInterval
- age
;
138 } // namespace policy