OLD | NEW |
---|---|
(Empty) | |
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. | |
4 | |
5 #include "components/password_manager/core/browser/affiliation_fetch_throttler.h " | |
6 | |
7 #include <stdint.h> | |
8 | |
9 #include "base/logging.h" | |
10 #include "base/rand_util.h" | |
11 #include "base/thread_task_runner_handle.h" | |
12 #include "base/time/tick_clock.h" | |
13 #include "base/time/time.h" | |
14 #include "components/password_manager/core/browser/affiliation_fetch_throttler_d elegate.h" | |
15 #include "net/base/backoff_entry.h" | |
16 | |
17 namespace password_manager { | |
18 | |
19 namespace { | |
20 | |
21 const net::BackoffEntry::Policy kAffiliationBackoffParameters = { | |
22 // Number of initial errors (in sequence) to ignore before going into | |
23 // exponential backoff. | |
24 0, | |
25 | |
26 // Initial delay (in ms) once backoff starts. | |
27 10 * 1000, // 10 seconds | |
28 | |
29 // Factor by which the delay will be multiplied on each subsequent failure. | |
30 4, | |
31 | |
32 // Fuzzing percentage: 50% will spread delays randomly between 50%--100% of | |
33 // the nominal time. | |
34 .5, // 50% | |
35 | |
36 // Maximum delay (in ms) during exponential backoff. | |
37 6 * 3600 * 1000, // 6 hours | |
38 | |
39 // Time to keep an entry from being discarded even when it has no | |
40 // significant state, -1 to never discard. (Not applicable.) | |
41 -1, | |
42 | |
43 // False means that initial_delay_ms is the first delay once we start | |
44 // exponential backoff, i.e., there is no delay after subsequent successful | |
45 // requests. | |
46 false, | |
47 }; | |
48 | |
49 // Grace period before the first request is sent after network connectivity is | |
50 // restored. The fuzzing factor from above applies. | |
51 const int64_t kGracePeriodAfterNetworkRestoredInMs = 10 * 1000; // 10 seconds | |
52 | |
53 // Implementation of net::BackoffEntry that allows mocking its tick source. | |
54 class BackoffEntryImpl : public net::BackoffEntry { | |
55 public: | |
56 explicit BackoffEntryImpl(base::TickClock* tick_clock) | |
57 : BackoffEntry(&kAffiliationBackoffParameters), tick_clock_(tick_clock) {} | |
58 ~BackoffEntryImpl() override {} | |
59 | |
60 private: | |
61 // net::BackoffEntry: | |
62 base::TimeTicks ImplGetTimeNow() const override { | |
63 return tick_clock_->NowTicks(); | |
64 } | |
65 | |
66 // Must outlive this instance. | |
67 base::TickClock* tick_clock_; | |
68 | |
69 DISALLOW_COPY_AND_ASSIGN(BackoffEntryImpl); | |
70 }; | |
71 | |
72 } // namespace | |
73 | |
74 AffiliationFetchThrottler::AffiliationFetchThrottler( | |
75 AffiliationFetchThrottlerDelegate* delegate, | |
76 const scoped_refptr<base::SingleThreadTaskRunner>& task_runner, | |
77 scoped_ptr<base::TickClock> tick_clock) | |
78 : delegate_(delegate), | |
79 task_runner_(task_runner), | |
80 state_(IDLE), | |
81 has_network_connectivity_(false), | |
82 is_fetch_scheduled_(false), | |
83 tick_clock_(tick_clock.Pass()), | |
84 exponential_backoff_(new BackoffEntryImpl(tick_clock_.get())), | |
85 weak_ptr_factory_(this) { | |
86 DCHECK(delegate); | |
87 // Start observing before querying the current connectivity state, so that if | |
88 // the state changes concurrently in-between, it will not go unnoticed. | |
89 net::NetworkChangeNotifier::AddConnectionTypeObserver(this); | |
90 has_network_connectivity_ = !net::NetworkChangeNotifier::IsOffline(); | |
91 } | |
92 | |
93 AffiliationFetchThrottler::~AffiliationFetchThrottler() { | |
94 net::NetworkChangeNotifier::RemoveConnectionTypeObserver(this); | |
95 } | |
96 | |
97 void AffiliationFetchThrottler::SignalNetworkRequestNeeded() { | |
98 if (state_ != IDLE) | |
99 return; | |
100 | |
101 state_ = FETCH_NEEDED; | |
102 if (has_network_connectivity_) | |
103 EnsureCallbackIsScheduled(); | |
104 } | |
105 | |
106 void AffiliationFetchThrottler::InformOfNetworkRequestComplete(bool success) { | |
107 DCHECK_EQ(state_, FETCH_IN_FLIGHT); | |
108 state_ = IDLE; | |
109 exponential_backoff_->InformOfRequest(success); | |
110 } | |
111 | |
112 void AffiliationFetchThrottler::EnsureCallbackIsScheduled() { | |
113 DCHECK_EQ(state_, FETCH_NEEDED); | |
114 DCHECK(has_network_connectivity_); | |
115 | |
116 if (is_fetch_scheduled_) | |
117 return; | |
118 | |
119 is_fetch_scheduled_ = true; | |
120 task_runner_->PostDelayedTask( | |
121 FROM_HERE, | |
122 base::Bind(&AffiliationFetchThrottler::OnBackoffDelayExpiredCallback, | |
123 weak_ptr_factory_.GetWeakPtr()), | |
mmenke
2015/01/21 17:18:52
Don't think we have any test that fails if this us
engedy
2015/01/23 22:09:43
Done.
| |
124 exponential_backoff_->GetTimeUntilRelease()); | |
125 } | |
126 | |
127 void AffiliationFetchThrottler::OnBackoffDelayExpiredCallback() { | |
128 DCHECK_EQ(state_, FETCH_NEEDED); | |
129 DCHECK(is_fetch_scheduled_); | |
130 is_fetch_scheduled_ = false; | |
131 | |
132 // Do nothing if network connectivity was lost while this callback was in the | |
133 // task queue. The callback will be posted in the OnConnectionTypeChanged | |
134 // handler once again. | |
135 if (!has_network_connectivity_) | |
136 return; | |
137 | |
138 // The release time might have been increased if network connectivity was lost | |
139 // and restored while this callback was in the task queue. If so, reschedule. | |
140 if (exponential_backoff_->ShouldRejectRequest()) | |
141 EnsureCallbackIsScheduled(); | |
142 else | |
143 state_ = delegate_->OnCanSendNetworkRequest() ? FETCH_IN_FLIGHT : IDLE; | |
144 } | |
145 | |
146 void AffiliationFetchThrottler::OnConnectionTypeChanged( | |
147 net::NetworkChangeNotifier::ConnectionType type) { | |
148 bool old_has_network_connectivity = has_network_connectivity_; | |
149 has_network_connectivity_ = | |
150 (type != net::NetworkChangeNotifier::CONNECTION_NONE); | |
151 | |
152 // Only react when network connectivity has been reestablished. | |
153 if (!has_network_connectivity_ || old_has_network_connectivity) | |
154 return; | |
155 | |
156 double grace_ms = | |
157 kGracePeriodAfterNetworkRestoredInMs * | |
158 (1 - base::RandDouble() * kAffiliationBackoffParameters.jitter_factor); | |
159 base::TimeTicks release_time = std::max( | |
160 exponential_backoff_->GetReleaseTime(), | |
161 tick_clock_->NowTicks() + base::TimeDelta::FromMillisecondsD(grace_ms)); | |
162 // Note that SetCustomReleaseTime() takes the maximum of the current release | |
163 // time and the supplied |release_time|. | |
164 exponential_backoff_->SetCustomReleaseTime(release_time); | |
165 | |
166 if (state_ == FETCH_NEEDED) | |
167 EnsureCallbackIsScheduled(); | |
168 } | |
169 | |
170 } // namespace password_manager | |
OLD | NEW |