Roll src/third_party/WebKit f36d5e0:68b67cd (svn 193299:193303)
[chromium-blink-merge.git] / components / gcm_driver / gcm_channel_status_syncer.cc
blob852922d0ceb87e22cb90f4c66891336dc0b3dbbc
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.
5 #include "components/gcm_driver/gcm_channel_status_syncer.h"
7 #include "base/bind.h"
8 #include "base/command_line.h"
9 #include "base/location.h"
10 #include "base/logging.h"
11 #include "base/message_loop/message_loop.h"
12 #include "base/prefs/pref_registry_simple.h"
13 #include "base/prefs/pref_service.h"
14 #include "base/rand_util.h"
15 #include "base/strings/string_number_conversions.h"
16 #include "components/gcm_driver/gcm_channel_status_request.h"
17 #include "components/gcm_driver/gcm_driver.h"
18 #include "components/pref_registry/pref_registry_syncable.h"
20 namespace gcm {
22 namespace {
24 // A small delay to avoid sending request at browser startup time for first-time
25 // request.
26 const int kFirstTimeDelaySeconds = 1 * 60; // 1 minute.
28 // The fuzzing variation added to the polling delay.
29 const int kGCMChannelRequestTimeJitterSeconds = 15 * 60; // 15 minues.
31 // The minimum poll interval that can be overridden to.
32 const int kMinCustomPollIntervalMinutes = 2;
34 // Custom poll interval could not be used more than the limit below.
35 const int kMaxNumberToUseCustomPollInterval = 10;
37 } // namespace
39 namespace prefs {
41 // The GCM channel's enabled state.
42 const char kGCMChannelStatus[] = "gcm.channel_status";
44 // The GCM channel's polling interval (in seconds).
45 const char kGCMChannelPollIntervalSeconds[] = "gcm.poll_interval";
47 // Last time when checking with the GCM channel status server is done.
48 const char kGCMChannelLastCheckTime[] = "gcm.check_time";
50 } // namepsace prefs
52 namespace switches {
54 // Override the default poll interval for testing purpose.
55 const char kCustomPollIntervalMinutes[] = "gcm-channel-poll-interval";
57 } // namepsace switches
59 // static
60 void GCMChannelStatusSyncer::RegisterPrefs(PrefRegistrySimple* registry) {
61 registry->RegisterBooleanPref(prefs::kGCMChannelStatus, true);
62 registry->RegisterIntegerPref(
63 prefs::kGCMChannelPollIntervalSeconds,
64 GCMChannelStatusRequest::default_poll_interval_seconds());
65 registry->RegisterInt64Pref(prefs::kGCMChannelLastCheckTime, 0);
68 // static
69 void GCMChannelStatusSyncer::RegisterProfilePrefs(
70 user_prefs::PrefRegistrySyncable* registry) {
71 registry->RegisterBooleanPref(
72 prefs::kGCMChannelStatus,
73 true,
74 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
75 registry->RegisterIntegerPref(
76 prefs::kGCMChannelPollIntervalSeconds,
77 GCMChannelStatusRequest::default_poll_interval_seconds(),
78 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
79 registry->RegisterInt64Pref(
80 prefs::kGCMChannelLastCheckTime,
82 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
85 // static
86 int GCMChannelStatusSyncer::first_time_delay_seconds() {
87 return kFirstTimeDelaySeconds;
90 GCMChannelStatusSyncer::GCMChannelStatusSyncer(
91 GCMDriver* driver,
92 PrefService* prefs,
93 const std::string& channel_status_request_url,
94 const std::string& user_agent,
95 const scoped_refptr<net::URLRequestContextGetter>& request_context)
96 : driver_(driver),
97 prefs_(prefs),
98 channel_status_request_url_(channel_status_request_url),
99 user_agent_(user_agent),
100 request_context_(request_context),
101 started_(false),
102 gcm_enabled_(true),
103 poll_interval_seconds_(
104 GCMChannelStatusRequest::default_poll_interval_seconds()),
105 custom_poll_interval_use_count_(0),
106 delay_removed_for_testing_(false),
107 weak_ptr_factory_(this) {
108 gcm_enabled_ = prefs_->GetBoolean(prefs::kGCMChannelStatus);
109 poll_interval_seconds_ = prefs_->GetInteger(
110 prefs::kGCMChannelPollIntervalSeconds);
111 if (poll_interval_seconds_ <
112 GCMChannelStatusRequest::min_poll_interval_seconds()) {
113 poll_interval_seconds_ =
114 GCMChannelStatusRequest::min_poll_interval_seconds();
116 const base::CommandLine& command_line =
117 *base::CommandLine::ForCurrentProcess();
118 if (command_line.HasSwitch(switches::kCustomPollIntervalMinutes)) {
119 std::string value(command_line.GetSwitchValueASCII(
120 switches::kCustomPollIntervalMinutes));
121 int minutes = 0;
122 if (base::StringToInt(value, &minutes)) {
123 DCHECK_GE(minutes, kMinCustomPollIntervalMinutes);
124 if (minutes >= kMinCustomPollIntervalMinutes) {
125 poll_interval_seconds_ = minutes * 60;
126 custom_poll_interval_use_count_ = kMaxNumberToUseCustomPollInterval;
130 last_check_time_ = base::Time::FromInternalValue(
131 prefs_->GetInt64(prefs::kGCMChannelLastCheckTime));
134 GCMChannelStatusSyncer::~GCMChannelStatusSyncer() {
137 void GCMChannelStatusSyncer::EnsureStarted() {
138 // Bail out if the request is already scheduled or started.
139 if (started_)
140 return;
141 started_ = true;
143 ScheduleRequest();
146 void GCMChannelStatusSyncer::Stop() {
147 started_ = false;
148 request_.reset();
149 weak_ptr_factory_.InvalidateWeakPtrs();
152 void GCMChannelStatusSyncer::OnRequestCompleted(bool update_received,
153 bool enabled,
154 int poll_interval_seconds) {
155 DCHECK(request_);
156 request_.reset();
158 // Persist the current time as the last request complete time.
159 last_check_time_ = base::Time::Now();
160 prefs_->SetInt64(prefs::kGCMChannelLastCheckTime,
161 last_check_time_.ToInternalValue());
163 if (update_received) {
164 if (gcm_enabled_ != enabled) {
165 gcm_enabled_ = enabled;
166 prefs_->SetBoolean(prefs::kGCMChannelStatus, enabled);
167 if (gcm_enabled_)
168 driver_->Enable();
169 else
170 driver_->Disable();
173 // Skip updating poll interval if the custom one is still in effect.
174 if (!custom_poll_interval_use_count_) {
175 DCHECK_GE(poll_interval_seconds,
176 GCMChannelStatusRequest::min_poll_interval_seconds());
177 if (poll_interval_seconds_ != poll_interval_seconds) {
178 poll_interval_seconds_ = poll_interval_seconds;
179 prefs_->SetInteger(prefs::kGCMChannelPollIntervalSeconds,
180 poll_interval_seconds_);
185 // Do not schedule next request if syncer is stopped.
186 if (started_)
187 ScheduleRequest();
190 void GCMChannelStatusSyncer::ScheduleRequest() {
191 current_request_delay_interval_ = GetRequestDelayInterval();
192 base::MessageLoop::current()->PostDelayedTask(
193 FROM_HERE,
194 base::Bind(&GCMChannelStatusSyncer::StartRequest,
195 weak_ptr_factory_.GetWeakPtr()),
196 current_request_delay_interval_);
198 if (custom_poll_interval_use_count_)
199 custom_poll_interval_use_count_--;
202 void GCMChannelStatusSyncer::StartRequest() {
203 DCHECK(!request_);
205 request_.reset(new GCMChannelStatusRequest(
206 request_context_,
207 channel_status_request_url_,
208 user_agent_,
209 base::Bind(&GCMChannelStatusSyncer::OnRequestCompleted,
210 weak_ptr_factory_.GetWeakPtr())));
211 request_->Start();
214 base::TimeDelta GCMChannelStatusSyncer::GetRequestDelayInterval() const {
215 // No delay during testing.
216 if (delay_removed_for_testing_)
217 return base::TimeDelta();
219 // Make sure that checking with server occurs at polling interval, regardless
220 // whether the browser restarts.
221 int64 delay_seconds = poll_interval_seconds_ -
222 (base::Time::Now() - last_check_time_).InSeconds();
223 if (delay_seconds < 0)
224 delay_seconds = 0;
226 if (last_check_time_.is_null()) {
227 // For the first-time request, add a small delay to avoid sending request at
228 // browser startup time.
229 DCHECK(!delay_seconds);
230 delay_seconds = kFirstTimeDelaySeconds;
231 } else {
232 // Otherwise, add a fuzzing variation to the delay.
233 // The fuzzing variation is off when the custom interval is used.
234 if (!custom_poll_interval_use_count_)
235 delay_seconds += base::RandInt(0, kGCMChannelRequestTimeJitterSeconds);
238 return base::TimeDelta::FromSeconds(delay_seconds);
241 } // namespace gcm