OLD | NEW |
| (Empty) |
1 // Copyright 2014 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/gcm_driver/gcm_channel_status_syncer.h" | |
6 | |
7 #include "base/bind.h" | |
8 #include "base/location.h" | |
9 #include "base/logging.h" | |
10 #include "base/message_loop/message_loop.h" | |
11 #include "base/prefs/pref_registry_simple.h" | |
12 #include "base/prefs/pref_service.h" | |
13 #include "base/rand_util.h" | |
14 #include "components/gcm_driver/gcm_channel_status_request.h" | |
15 #include "components/gcm_driver/gcm_driver.h" | |
16 #include "components/pref_registry/pref_registry_syncable.h" | |
17 | |
18 namespace gcm { | |
19 | |
20 namespace { | |
21 | |
22 // The GCM channel's enabled state. | |
23 const char kGCMChannelStatus[] = "gcm.channel_status"; | |
24 | |
25 // The GCM channel's polling interval (in seconds). | |
26 const char kGCMChannelPollIntervalSeconds[] = "gcm.poll_interval"; | |
27 | |
28 // Last time when checking with the GCM channel status server is done. | |
29 const char kGCMChannelLastCheckTime[] = "gcm.check_time"; | |
30 | |
31 // A small delay to avoid sending request at browser startup time for first-time | |
32 // request. | |
33 const int kFirstTimeDelaySeconds = 1 * 60; // 1 minute. | |
34 | |
35 // The fuzzing variation added to the polling delay. | |
36 const int kGCMChannelRequestTimeJitterSeconds = 15 * 60; // 15 minues. | |
37 | |
38 } // namespace | |
39 | |
40 // static | |
41 void GCMChannelStatusSyncer::RegisterPrefs(PrefRegistrySimple* registry) { | |
42 registry->RegisterBooleanPref(kGCMChannelStatus, true); | |
43 registry->RegisterIntegerPref( | |
44 kGCMChannelPollIntervalSeconds, | |
45 GCMChannelStatusRequest::default_poll_interval_seconds()); | |
46 registry->RegisterInt64Pref(kGCMChannelLastCheckTime, 0); | |
47 } | |
48 | |
49 // static | |
50 void GCMChannelStatusSyncer::RegisterProfilePrefs( | |
51 user_prefs::PrefRegistrySyncable* registry) { | |
52 registry->RegisterBooleanPref( | |
53 kGCMChannelStatus, | |
54 true, | |
55 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF); | |
56 registry->RegisterIntegerPref( | |
57 kGCMChannelPollIntervalSeconds, | |
58 GCMChannelStatusRequest::default_poll_interval_seconds(), | |
59 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF); | |
60 registry->RegisterInt64Pref( | |
61 kGCMChannelLastCheckTime, | |
62 0, | |
63 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF); | |
64 } | |
65 | |
66 // static | |
67 int GCMChannelStatusSyncer::first_time_delay_seconds() { | |
68 return kFirstTimeDelaySeconds; | |
69 } | |
70 | |
71 GCMChannelStatusSyncer::GCMChannelStatusSyncer( | |
72 GCMDriver* driver, | |
73 PrefService* prefs, | |
74 const scoped_refptr<net::URLRequestContextGetter>& request_context) | |
75 : driver_(driver), | |
76 prefs_(prefs), | |
77 request_context_(request_context), | |
78 gcm_enabled_(true), | |
79 poll_interval_seconds_( | |
80 GCMChannelStatusRequest::default_poll_interval_seconds()), | |
81 delay_removed_for_testing_(false), | |
82 weak_ptr_factory_(this) { | |
83 gcm_enabled_ = prefs_->GetBoolean(kGCMChannelStatus); | |
84 poll_interval_seconds_ = prefs_->GetInteger(kGCMChannelPollIntervalSeconds); | |
85 if (poll_interval_seconds_ < | |
86 GCMChannelStatusRequest::min_poll_interval_seconds()) { | |
87 poll_interval_seconds_ = | |
88 GCMChannelStatusRequest::min_poll_interval_seconds(); | |
89 } | |
90 last_check_time_ = base::Time::FromInternalValue( | |
91 prefs_->GetInt64(kGCMChannelLastCheckTime)); | |
92 } | |
93 | |
94 GCMChannelStatusSyncer::~GCMChannelStatusSyncer() { | |
95 } | |
96 | |
97 void GCMChannelStatusSyncer::EnsureStarted() { | |
98 // Bail out if the request is already scheduled or started. | |
99 if (weak_ptr_factory_.HasWeakPtrs() || request_) | |
100 return; | |
101 | |
102 ScheduleRequest(); | |
103 } | |
104 | |
105 void GCMChannelStatusSyncer::Stop() { | |
106 request_.reset(); | |
107 weak_ptr_factory_.InvalidateWeakPtrs(); | |
108 } | |
109 | |
110 void GCMChannelStatusSyncer::OnRequestCompleted(bool enabled, | |
111 int poll_interval_seconds) { | |
112 DCHECK(request_); | |
113 request_.reset(); | |
114 | |
115 // Persist the current time as the last request complete time. | |
116 last_check_time_ = base::Time::Now(); | |
117 prefs_->SetInt64(kGCMChannelLastCheckTime, | |
118 last_check_time_.ToInternalValue()); | |
119 | |
120 if (gcm_enabled_ != enabled) { | |
121 gcm_enabled_ = enabled; | |
122 prefs_->SetBoolean(kGCMChannelStatus, enabled); | |
123 if (gcm_enabled_) | |
124 driver_->Enable(); | |
125 else | |
126 driver_->Disable(); | |
127 } | |
128 | |
129 DCHECK_GE(poll_interval_seconds, | |
130 GCMChannelStatusRequest::min_poll_interval_seconds()); | |
131 if (poll_interval_seconds_ != poll_interval_seconds) { | |
132 poll_interval_seconds_ = poll_interval_seconds; | |
133 prefs_->SetInteger(kGCMChannelPollIntervalSeconds, poll_interval_seconds_); | |
134 } | |
135 | |
136 ScheduleRequest(); | |
137 } | |
138 | |
139 void GCMChannelStatusSyncer::ScheduleRequest() { | |
140 current_request_delay_interval_ = GetRequestDelayInterval(); | |
141 base::MessageLoop::current()->PostDelayedTask( | |
142 FROM_HERE, | |
143 base::Bind(&GCMChannelStatusSyncer::StartRequest, | |
144 weak_ptr_factory_.GetWeakPtr()), | |
145 current_request_delay_interval_); | |
146 } | |
147 | |
148 void GCMChannelStatusSyncer::StartRequest() { | |
149 DCHECK(!request_); | |
150 | |
151 request_.reset(new GCMChannelStatusRequest( | |
152 request_context_, | |
153 base::Bind(&GCMChannelStatusSyncer::OnRequestCompleted, | |
154 weak_ptr_factory_.GetWeakPtr()))); | |
155 request_->Start(); | |
156 } | |
157 | |
158 base::TimeDelta GCMChannelStatusSyncer::GetRequestDelayInterval() const { | |
159 // No delay during testing. | |
160 if (delay_removed_for_testing_) | |
161 return base::TimeDelta(); | |
162 | |
163 // Make sure that checking with server occurs at polling interval, regardless | |
164 // whether the browser restarts. | |
165 int64 delay_seconds = poll_interval_seconds_ - | |
166 (base::Time::Now() - last_check_time_).InSeconds(); | |
167 if (delay_seconds < 0) | |
168 delay_seconds = 0; | |
169 | |
170 if (last_check_time_.is_null()) { | |
171 // For the first-time request, add a small delay to avoid sending request at | |
172 // browser startup time. | |
173 DCHECK(!delay_seconds); | |
174 delay_seconds = kFirstTimeDelaySeconds; | |
175 } else { | |
176 // Otherwise, add a fuzzing variation to the delay. | |
177 delay_seconds += base::RandInt(0, kGCMChannelRequestTimeJitterSeconds); | |
178 } | |
179 | |
180 return base::TimeDelta::FromSeconds(delay_seconds); | |
181 } | |
182 | |
183 } // namespace gcm | |
OLD | NEW |