Only grant permissions to new extensions from sync if they have the expected version
[chromium-blink-merge.git] / components / proximity_auth / cryptauth / sync_scheduler_impl.cc
blob6bf711b0d3e8d82207dc2204d3bc9b4afa659a6b
1 // Copyright 2015 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/proximity_auth/cryptauth/sync_scheduler_impl.h"
7 #include <algorithm>
8 #include <cmath>
9 #include <limits>
11 #include "base/bind.h"
12 #include "base/numerics/safe_conversions.h"
13 #include "base/rand_util.h"
14 #include "base/strings/stringprintf.h"
15 #include "components/proximity_auth/logging/logging.h"
17 namespace proximity_auth {
19 namespace {
21 // Returns a human readable string given a |time_delta|.
22 std::string TimeDeltaToString(const base::TimeDelta& time_delta) {
23 if (time_delta.InDays() > 0)
24 return base::StringPrintf("%d days", time_delta.InDays());
26 if (time_delta.InHours() > 0)
27 return base::StringPrintf("%d hours", time_delta.InHours());
29 if (time_delta.InMinutes() > 0)
30 return base::StringPrintf("%d minutes", time_delta.InMinutes());
32 return base::StringPrintf("%d seconds",
33 base::saturated_cast<int>(time_delta.InSeconds()));
36 } // namespace
38 SyncSchedulerImpl::SyncSchedulerImpl(Delegate* delegate,
39 base::TimeDelta refresh_period,
40 base::TimeDelta base_recovery_period,
41 double max_jitter_ratio,
42 const std::string& scheduler_name)
43 : delegate_(delegate),
44 refresh_period_(refresh_period),
45 base_recovery_period_(base_recovery_period),
46 max_jitter_ratio_(max_jitter_ratio),
47 scheduler_name_(scheduler_name),
48 strategy_(Strategy::PERIODIC_REFRESH),
49 sync_state_(SyncState::NOT_STARTED),
50 failure_count_(0),
51 weak_ptr_factory_(this) {
54 SyncSchedulerImpl::~SyncSchedulerImpl() {
57 void SyncSchedulerImpl::Start(
58 const base::TimeDelta& elapsed_time_since_last_sync,
59 Strategy strategy) {
60 strategy_ = strategy;
61 sync_state_ = SyncState::WAITING_FOR_REFRESH;
62 // We reset the failure backoff when the scheduler is started again, as the
63 // configuration that caused the previous attempts to fail most likely won't
64 // be present after a restart.
65 if (strategy_ == Strategy::AGGRESSIVE_RECOVERY)
66 failure_count_ = 1;
68 // To take into account the time waited when the system is powered off, we
69 // subtract the time elapsed with a normal sync period to the initial time
70 // to wait.
71 base::TimeDelta sync_delta =
72 GetJitteredPeriod() - elapsed_time_since_last_sync;
74 // The elapsed time may be negative if the system clock is changed. In this
75 // case, we immediately schedule a sync.
76 base::TimeDelta zero_delta = base::TimeDelta::FromSeconds(0);
77 if (elapsed_time_since_last_sync < zero_delta || sync_delta < zero_delta)
78 sync_delta = zero_delta;
80 ScheduleNextSync(sync_delta);
83 void SyncSchedulerImpl::ForceSync() {
84 OnTimerFired();
87 base::TimeDelta SyncSchedulerImpl::GetTimeToNextSync() const {
88 if (!timer_)
89 return base::TimeDelta::FromSeconds(0);
90 return timer_->GetCurrentDelay();
93 SyncScheduler::Strategy SyncSchedulerImpl::GetStrategy() const {
94 return strategy_;
97 SyncScheduler::SyncState SyncSchedulerImpl::GetSyncState() const {
98 return sync_state_;
101 void SyncSchedulerImpl::OnTimerFired() {
102 timer_.reset();
103 if (strategy_ == Strategy::PERIODIC_REFRESH) {
104 PA_LOG(INFO) << "Timer fired for periodic refresh, making request...";
105 sync_state_ = SyncState::SYNC_IN_PROGRESS;
106 } else if (strategy_ == Strategy::AGGRESSIVE_RECOVERY) {
107 PA_LOG(INFO) << "Timer fired for aggressive recovery, making request...";
108 sync_state_ = SyncState::SYNC_IN_PROGRESS;
109 } else {
110 NOTREACHED();
111 return;
114 delegate_->OnSyncRequested(
115 make_scoped_ptr(new SyncRequest(weak_ptr_factory_.GetWeakPtr())));
118 scoped_ptr<base::Timer> SyncSchedulerImpl::CreateTimer() {
119 bool retain_user_task = false;
120 bool is_repeating = false;
121 return make_scoped_ptr(new base::Timer(retain_user_task, is_repeating));
124 void SyncSchedulerImpl::ScheduleNextSync(const base::TimeDelta& sync_delta) {
125 if (sync_state_ != SyncState::WAITING_FOR_REFRESH) {
126 PA_LOG(ERROR) << "Unexpected state when scheduling next sync: sync_state="
127 << static_cast<int>(sync_state_);
128 return;
131 bool is_aggressive_recovery = (strategy_ == Strategy::AGGRESSIVE_RECOVERY);
132 PA_LOG(INFO) << "Scheduling next sync for " << scheduler_name_ << ":\n"
133 << " Strategy: " << (is_aggressive_recovery
134 ? "Aggressive Recovery"
135 : "Periodic Refresh") << "\n"
136 << " Time Delta: " << TimeDeltaToString(sync_delta)
137 << (is_aggressive_recovery
138 ? base::StringPrintf(
139 "\n Previous Failures: %d",
140 base::saturated_cast<int>(failure_count_))
141 : "");
143 timer_ = CreateTimer();
144 timer_->Start(FROM_HERE, sync_delta,
145 base::Bind(&SyncSchedulerImpl::OnTimerFired,
146 weak_ptr_factory_.GetWeakPtr()));
149 void SyncSchedulerImpl::OnSyncCompleted(bool success) {
150 if (sync_state_ != SyncState::SYNC_IN_PROGRESS) {
151 PA_LOG(ERROR) << "Unexpected state when sync completed: sync_state="
152 << static_cast<int>(sync_state_)
153 << ", strategy_=" << static_cast<int>(strategy_);
154 return;
156 sync_state_ = SyncState::WAITING_FOR_REFRESH;
158 if (success) {
159 strategy_ = Strategy::PERIODIC_REFRESH;
160 failure_count_ = 0;
161 } else {
162 strategy_ = Strategy::AGGRESSIVE_RECOVERY;
163 ++failure_count_;
166 ScheduleNextSync(GetJitteredPeriod());
169 base::TimeDelta SyncSchedulerImpl::GetJitteredPeriod() {
170 double jitter = 2 * max_jitter_ratio_ * (base::RandDouble() - 0.5);
171 base::TimeDelta period = GetPeriod();
172 base::TimeDelta jittered_time_delta = period + (period * jitter);
173 if (jittered_time_delta.InMilliseconds() < 0)
174 jittered_time_delta = base::TimeDelta::FromMilliseconds(0);
175 return jittered_time_delta;
178 base::TimeDelta SyncSchedulerImpl::GetPeriod() {
179 if (strategy_ == Strategy::PERIODIC_REFRESH) {
180 return refresh_period_;
181 } else if (strategy_ == Strategy::AGGRESSIVE_RECOVERY && failure_count_ > 0) {
182 // The backoff for each consecutive failure is exponentially doubled until
183 // it is equal to the normal refresh period.
184 // Note: |backoff_factor| may evaulate to INF if |failure_count_| is large,
185 // but multiplication operations for TimeDelta objects are saturated.
186 double backoff_factor = pow(2, failure_count_ - 1);
187 base::TimeDelta backoff_period = base_recovery_period_ * backoff_factor;
188 return backoff_period < refresh_period_ ? backoff_period : refresh_period_;
189 } else {
190 PA_LOG(ERROR) << "Error getting period for strategy: "
191 << static_cast<int>(strategy_);
192 return base::TimeDelta();
196 } // namespace proximity_auth