xref: /aosp_15_r20/external/cronet/net/base/backoff_entry_serializer.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1*6777b538SAndroid Build Coastguard Worker // Copyright 2015 The Chromium Authors
2*6777b538SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*6777b538SAndroid Build Coastguard Worker // found in the LICENSE file.
4*6777b538SAndroid Build Coastguard Worker 
5*6777b538SAndroid Build Coastguard Worker #include "net/base/backoff_entry_serializer.h"
6*6777b538SAndroid Build Coastguard Worker 
7*6777b538SAndroid Build Coastguard Worker #include <algorithm>
8*6777b538SAndroid Build Coastguard Worker #include <ostream>
9*6777b538SAndroid Build Coastguard Worker #include <utility>
10*6777b538SAndroid Build Coastguard Worker 
11*6777b538SAndroid Build Coastguard Worker #include "base/notreached.h"
12*6777b538SAndroid Build Coastguard Worker #include "base/strings/string_number_conversions.h"
13*6777b538SAndroid Build Coastguard Worker #include "base/time/tick_clock.h"
14*6777b538SAndroid Build Coastguard Worker #include "base/values.h"
15*6777b538SAndroid Build Coastguard Worker #include "net/base/backoff_entry.h"
16*6777b538SAndroid Build Coastguard Worker 
17*6777b538SAndroid Build Coastguard Worker namespace {
18*6777b538SAndroid Build Coastguard Worker // This max defines how many times we are willing to call
19*6777b538SAndroid Build Coastguard Worker // |BackoffEntry::InformOfRequest| in |DeserializeFromList|.
20*6777b538SAndroid Build Coastguard Worker //
21*6777b538SAndroid Build Coastguard Worker // This value is meant to large enough that the computed backoff duration can
22*6777b538SAndroid Build Coastguard Worker // still be saturated. Given that the duration is an int64 and assuming 1.01 as
23*6777b538SAndroid Build Coastguard Worker // a conservative lower bound for BackoffEntry::Policy::multiply_factor,
24*6777b538SAndroid Build Coastguard Worker // ceil(log(2**63-1, 1.01)) = 4389.
25*6777b538SAndroid Build Coastguard Worker const int kMaxFailureCount = 4389;
26*6777b538SAndroid Build Coastguard Worker 
27*6777b538SAndroid Build Coastguard Worker // This function returns true iff |duration| is finite and can be serialized and
28*6777b538SAndroid Build Coastguard Worker // deserialized without becoming infinite. This function is aligned with the
29*6777b538SAndroid Build Coastguard Worker // latest version.
BackoffDurationSafeToSerialize(const base::TimeDelta & duration)30*6777b538SAndroid Build Coastguard Worker bool BackoffDurationSafeToSerialize(const base::TimeDelta& duration) {
31*6777b538SAndroid Build Coastguard Worker   return !duration.is_inf() &&
32*6777b538SAndroid Build Coastguard Worker          !base::Microseconds(duration.InMicroseconds()).is_inf();
33*6777b538SAndroid Build Coastguard Worker }
34*6777b538SAndroid Build Coastguard Worker }  // namespace
35*6777b538SAndroid Build Coastguard Worker 
36*6777b538SAndroid Build Coastguard Worker namespace net {
37*6777b538SAndroid Build Coastguard Worker 
SerializeToList(const BackoffEntry & entry,base::Time time_now)38*6777b538SAndroid Build Coastguard Worker base::Value::List BackoffEntrySerializer::SerializeToList(
39*6777b538SAndroid Build Coastguard Worker     const BackoffEntry& entry,
40*6777b538SAndroid Build Coastguard Worker     base::Time time_now) {
41*6777b538SAndroid Build Coastguard Worker   base::Value::List serialized;
42*6777b538SAndroid Build Coastguard Worker   serialized.Append(SerializationFormatVersion::kVersion2);
43*6777b538SAndroid Build Coastguard Worker 
44*6777b538SAndroid Build Coastguard Worker   serialized.Append(entry.failure_count());
45*6777b538SAndroid Build Coastguard Worker 
46*6777b538SAndroid Build Coastguard Worker   // Convert both |base::TimeTicks| values into |base::TimeDelta| values by
47*6777b538SAndroid Build Coastguard Worker   // subtracting |kZeroTicks. This way, the top-level subtraction uses
48*6777b538SAndroid Build Coastguard Worker   // |base::TimeDelta::operator-|, which has clamping semantics.
49*6777b538SAndroid Build Coastguard Worker   const base::TimeTicks kZeroTicks;
50*6777b538SAndroid Build Coastguard Worker   const base::TimeDelta kReleaseTime = entry.GetReleaseTime() - kZeroTicks;
51*6777b538SAndroid Build Coastguard Worker   const base::TimeDelta kTimeTicksNow = entry.GetTimeTicksNow() - kZeroTicks;
52*6777b538SAndroid Build Coastguard Worker   base::TimeDelta backoff_duration;
53*6777b538SAndroid Build Coastguard Worker   if (!kReleaseTime.is_inf() && !kTimeTicksNow.is_inf()) {
54*6777b538SAndroid Build Coastguard Worker     backoff_duration = kReleaseTime - kTimeTicksNow;
55*6777b538SAndroid Build Coastguard Worker   }
56*6777b538SAndroid Build Coastguard Worker   if (!BackoffDurationSafeToSerialize(backoff_duration)) {
57*6777b538SAndroid Build Coastguard Worker     backoff_duration = base::TimeDelta();
58*6777b538SAndroid Build Coastguard Worker   }
59*6777b538SAndroid Build Coastguard Worker 
60*6777b538SAndroid Build Coastguard Worker   base::Time absolute_release_time = backoff_duration + time_now;
61*6777b538SAndroid Build Coastguard Worker   // If the computed release time is infinite, default to zero. The deserializer
62*6777b538SAndroid Build Coastguard Worker   // should pick up on this.
63*6777b538SAndroid Build Coastguard Worker   if (absolute_release_time.is_inf()) {
64*6777b538SAndroid Build Coastguard Worker     absolute_release_time = base::Time();
65*6777b538SAndroid Build Coastguard Worker   }
66*6777b538SAndroid Build Coastguard Worker 
67*6777b538SAndroid Build Coastguard Worker   // Redundantly stores both the remaining time delta and the absolute time.
68*6777b538SAndroid Build Coastguard Worker   // The delta is used to work around some cases where wall clock time changes.
69*6777b538SAndroid Build Coastguard Worker   serialized.Append(base::NumberToString(backoff_duration.InMicroseconds()));
70*6777b538SAndroid Build Coastguard Worker   serialized.Append(
71*6777b538SAndroid Build Coastguard Worker       base::NumberToString(absolute_release_time.ToInternalValue()));
72*6777b538SAndroid Build Coastguard Worker 
73*6777b538SAndroid Build Coastguard Worker   return serialized;
74*6777b538SAndroid Build Coastguard Worker }
75*6777b538SAndroid Build Coastguard Worker 
DeserializeFromList(const base::Value::List & serialized,const BackoffEntry::Policy * policy,const base::TickClock * tick_clock,base::Time time_now)76*6777b538SAndroid Build Coastguard Worker std::unique_ptr<BackoffEntry> BackoffEntrySerializer::DeserializeFromList(
77*6777b538SAndroid Build Coastguard Worker     const base::Value::List& serialized,
78*6777b538SAndroid Build Coastguard Worker     const BackoffEntry::Policy* policy,
79*6777b538SAndroid Build Coastguard Worker     const base::TickClock* tick_clock,
80*6777b538SAndroid Build Coastguard Worker     base::Time time_now) {
81*6777b538SAndroid Build Coastguard Worker   if (serialized.size() != 4)
82*6777b538SAndroid Build Coastguard Worker     return nullptr;
83*6777b538SAndroid Build Coastguard Worker 
84*6777b538SAndroid Build Coastguard Worker   if (!serialized[0].is_int())
85*6777b538SAndroid Build Coastguard Worker     return nullptr;
86*6777b538SAndroid Build Coastguard Worker   int version_number = serialized[0].GetInt();
87*6777b538SAndroid Build Coastguard Worker   if (version_number != kVersion1 && version_number != kVersion2)
88*6777b538SAndroid Build Coastguard Worker     return nullptr;
89*6777b538SAndroid Build Coastguard Worker 
90*6777b538SAndroid Build Coastguard Worker   if (!serialized[1].is_int())
91*6777b538SAndroid Build Coastguard Worker     return nullptr;
92*6777b538SAndroid Build Coastguard Worker   int failure_count = serialized[1].GetInt();
93*6777b538SAndroid Build Coastguard Worker   if (failure_count < 0) {
94*6777b538SAndroid Build Coastguard Worker     return nullptr;
95*6777b538SAndroid Build Coastguard Worker   }
96*6777b538SAndroid Build Coastguard Worker   failure_count = std::min(failure_count, kMaxFailureCount);
97*6777b538SAndroid Build Coastguard Worker 
98*6777b538SAndroid Build Coastguard Worker   base::TimeDelta original_backoff_duration;
99*6777b538SAndroid Build Coastguard Worker   switch (version_number) {
100*6777b538SAndroid Build Coastguard Worker     case kVersion1: {
101*6777b538SAndroid Build Coastguard Worker       if (!serialized[2].is_double())
102*6777b538SAndroid Build Coastguard Worker         return nullptr;
103*6777b538SAndroid Build Coastguard Worker       double original_backoff_duration_double = serialized[2].GetDouble();
104*6777b538SAndroid Build Coastguard Worker       original_backoff_duration =
105*6777b538SAndroid Build Coastguard Worker           base::Seconds(original_backoff_duration_double);
106*6777b538SAndroid Build Coastguard Worker       break;
107*6777b538SAndroid Build Coastguard Worker     }
108*6777b538SAndroid Build Coastguard Worker     case kVersion2: {
109*6777b538SAndroid Build Coastguard Worker       if (!serialized[2].is_string())
110*6777b538SAndroid Build Coastguard Worker         return nullptr;
111*6777b538SAndroid Build Coastguard Worker       std::string original_backoff_duration_string = serialized[2].GetString();
112*6777b538SAndroid Build Coastguard Worker       int64_t original_backoff_duration_us;
113*6777b538SAndroid Build Coastguard Worker       if (!base::StringToInt64(original_backoff_duration_string,
114*6777b538SAndroid Build Coastguard Worker                                &original_backoff_duration_us)) {
115*6777b538SAndroid Build Coastguard Worker         return nullptr;
116*6777b538SAndroid Build Coastguard Worker       }
117*6777b538SAndroid Build Coastguard Worker       original_backoff_duration =
118*6777b538SAndroid Build Coastguard Worker           base::Microseconds(original_backoff_duration_us);
119*6777b538SAndroid Build Coastguard Worker       break;
120*6777b538SAndroid Build Coastguard Worker     }
121*6777b538SAndroid Build Coastguard Worker     default:
122*6777b538SAndroid Build Coastguard Worker       NOTREACHED() << "Unexpected version_number: " << version_number;
123*6777b538SAndroid Build Coastguard Worker   }
124*6777b538SAndroid Build Coastguard Worker 
125*6777b538SAndroid Build Coastguard Worker   if (!serialized[3].is_string())
126*6777b538SAndroid Build Coastguard Worker     return nullptr;
127*6777b538SAndroid Build Coastguard Worker   std::string absolute_release_time_string = serialized[3].GetString();
128*6777b538SAndroid Build Coastguard Worker 
129*6777b538SAndroid Build Coastguard Worker   int64_t absolute_release_time_us;
130*6777b538SAndroid Build Coastguard Worker   if (!base::StringToInt64(absolute_release_time_string,
131*6777b538SAndroid Build Coastguard Worker                            &absolute_release_time_us)) {
132*6777b538SAndroid Build Coastguard Worker     return nullptr;
133*6777b538SAndroid Build Coastguard Worker   }
134*6777b538SAndroid Build Coastguard Worker 
135*6777b538SAndroid Build Coastguard Worker   auto entry = std::make_unique<BackoffEntry>(policy, tick_clock);
136*6777b538SAndroid Build Coastguard Worker 
137*6777b538SAndroid Build Coastguard Worker   for (int n = 0; n < failure_count; n++)
138*6777b538SAndroid Build Coastguard Worker     entry->InformOfRequest(false);
139*6777b538SAndroid Build Coastguard Worker 
140*6777b538SAndroid Build Coastguard Worker   base::Time absolute_release_time =
141*6777b538SAndroid Build Coastguard Worker       base::Time::FromInternalValue(absolute_release_time_us);
142*6777b538SAndroid Build Coastguard Worker 
143*6777b538SAndroid Build Coastguard Worker   base::TimeDelta backoff_duration;
144*6777b538SAndroid Build Coastguard Worker   if (absolute_release_time == base::Time()) {
145*6777b538SAndroid Build Coastguard Worker     // When the serializer cannot compute a finite release time, it uses zero.
146*6777b538SAndroid Build Coastguard Worker     // When we see this, fall back to the redundant original_backoff_duration.
147*6777b538SAndroid Build Coastguard Worker     backoff_duration = original_backoff_duration;
148*6777b538SAndroid Build Coastguard Worker   } else {
149*6777b538SAndroid Build Coastguard Worker     // Before computing |backoff_duration|, throw out +/- infinity values for
150*6777b538SAndroid Build Coastguard Worker     // either operand. This way, we can use base::TimeDelta's saturated math.
151*6777b538SAndroid Build Coastguard Worker     if (absolute_release_time.is_inf() || time_now.is_inf())
152*6777b538SAndroid Build Coastguard Worker       return nullptr;
153*6777b538SAndroid Build Coastguard Worker 
154*6777b538SAndroid Build Coastguard Worker     backoff_duration = absolute_release_time.ToDeltaSinceWindowsEpoch() -
155*6777b538SAndroid Build Coastguard Worker                        time_now.ToDeltaSinceWindowsEpoch();
156*6777b538SAndroid Build Coastguard Worker 
157*6777b538SAndroid Build Coastguard Worker     // In cases where the system wall clock is rewound, use the redundant
158*6777b538SAndroid Build Coastguard Worker     // original_backoff_duration to ensure the backoff duration isn't longer
159*6777b538SAndroid Build Coastguard Worker     // than it was before serializing (note that it's not possible to protect
160*6777b538SAndroid Build Coastguard Worker     // against the clock being wound forward).
161*6777b538SAndroid Build Coastguard Worker     if (backoff_duration > original_backoff_duration)
162*6777b538SAndroid Build Coastguard Worker       backoff_duration = original_backoff_duration;
163*6777b538SAndroid Build Coastguard Worker   }
164*6777b538SAndroid Build Coastguard Worker   if (!BackoffDurationSafeToSerialize(backoff_duration))
165*6777b538SAndroid Build Coastguard Worker     return nullptr;
166*6777b538SAndroid Build Coastguard Worker 
167*6777b538SAndroid Build Coastguard Worker   const base::TimeTicks release_time =
168*6777b538SAndroid Build Coastguard Worker       entry->BackoffDurationToReleaseTime(backoff_duration);
169*6777b538SAndroid Build Coastguard Worker   if (release_time.is_inf())
170*6777b538SAndroid Build Coastguard Worker     return nullptr;
171*6777b538SAndroid Build Coastguard Worker   entry->SetCustomReleaseTime(release_time);
172*6777b538SAndroid Build Coastguard Worker 
173*6777b538SAndroid Build Coastguard Worker   return entry;
174*6777b538SAndroid Build Coastguard Worker }
175*6777b538SAndroid Build Coastguard Worker 
176*6777b538SAndroid Build Coastguard Worker }  // namespace net
177