Roll leveldb 3f7758:803d69 (v1.17 -> v1.18)
[chromium-blink-merge.git] / components / gcm_driver / gcm_channel_status_syncer.cc
blob958d3c39d4d1e8cac85737b7209fe0f24fa9eee9
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 // The GCM channel's enabled state.
25 const char kGCMChannelStatus[] = "gcm.channel_status";
27 // The GCM channel's polling interval (in seconds).
28 const char kGCMChannelPollIntervalSeconds[] = "gcm.poll_interval";
30 // Last time when checking with the GCM channel status server is done.
31 const char kGCMChannelLastCheckTime[] = "gcm.check_time";
33 // A small delay to avoid sending request at browser startup time for first-time
34 // request.
35 const int kFirstTimeDelaySeconds = 1 * 60; // 1 minute.
37 // The fuzzing variation added to the polling delay.
38 const int kGCMChannelRequestTimeJitterSeconds = 15 * 60; // 15 minues.
40 // The minimum poll interval that can be overridden to.
41 const int kMinCustomPollIntervalMinutes = 2;
43 // Custom poll interval could not be used more than the limit below.
44 const int kMaxNumberToUseCustomPollInterval = 10;
46 } // namespace
48 namespace switches {
50 // Override the default poll interval for testing purpose.
51 const char kCustomPollIntervalMinutes[] = "gcm-channel-poll-interval";
53 } // namepsace switches
55 // static
56 void GCMChannelStatusSyncer::RegisterPrefs(PrefRegistrySimple* registry) {
57 registry->RegisterBooleanPref(kGCMChannelStatus, true);
58 registry->RegisterIntegerPref(
59 kGCMChannelPollIntervalSeconds,
60 GCMChannelStatusRequest::default_poll_interval_seconds());
61 registry->RegisterInt64Pref(kGCMChannelLastCheckTime, 0);
64 // static
65 void GCMChannelStatusSyncer::RegisterProfilePrefs(
66 user_prefs::PrefRegistrySyncable* registry) {
67 registry->RegisterBooleanPref(
68 kGCMChannelStatus,
69 true,
70 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
71 registry->RegisterIntegerPref(
72 kGCMChannelPollIntervalSeconds,
73 GCMChannelStatusRequest::default_poll_interval_seconds(),
74 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
75 registry->RegisterInt64Pref(
76 kGCMChannelLastCheckTime,
78 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
81 // static
82 int GCMChannelStatusSyncer::first_time_delay_seconds() {
83 return kFirstTimeDelaySeconds;
86 GCMChannelStatusSyncer::GCMChannelStatusSyncer(
87 GCMDriver* driver,
88 PrefService* prefs,
89 const std::string& channel_status_request_url,
90 const std::string& user_agent,
91 const scoped_refptr<net::URLRequestContextGetter>& request_context)
92 : driver_(driver),
93 prefs_(prefs),
94 channel_status_request_url_(channel_status_request_url),
95 user_agent_(user_agent),
96 request_context_(request_context),
97 started_(false),
98 gcm_enabled_(true),
99 poll_interval_seconds_(
100 GCMChannelStatusRequest::default_poll_interval_seconds()),
101 custom_poll_interval_use_count_(0),
102 delay_removed_for_testing_(false),
103 weak_ptr_factory_(this) {
104 gcm_enabled_ = prefs_->GetBoolean(kGCMChannelStatus);
105 poll_interval_seconds_ = prefs_->GetInteger(kGCMChannelPollIntervalSeconds);
106 if (poll_interval_seconds_ <
107 GCMChannelStatusRequest::min_poll_interval_seconds()) {
108 poll_interval_seconds_ =
109 GCMChannelStatusRequest::min_poll_interval_seconds();
111 if (CommandLine::ForCurrentProcess()->HasSwitch(
112 switches::kCustomPollIntervalMinutes)) {
113 std::string value(CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
114 switches::kCustomPollIntervalMinutes));
115 int minutes = 0;
116 if (base::StringToInt(value, &minutes)) {
117 DCHECK_GE(minutes, kMinCustomPollIntervalMinutes);
118 if (minutes >= kMinCustomPollIntervalMinutes) {
119 poll_interval_seconds_ = minutes * 60;
120 custom_poll_interval_use_count_ = kMaxNumberToUseCustomPollInterval;
124 last_check_time_ = base::Time::FromInternalValue(
125 prefs_->GetInt64(kGCMChannelLastCheckTime));
128 GCMChannelStatusSyncer::~GCMChannelStatusSyncer() {
131 void GCMChannelStatusSyncer::EnsureStarted() {
132 // Bail out if the request is already scheduled or started.
133 if (started_)
134 return;
135 started_ = true;
137 ScheduleRequest();
140 void GCMChannelStatusSyncer::Stop() {
141 started_ = false;
142 request_.reset();
143 weak_ptr_factory_.InvalidateWeakPtrs();
146 void GCMChannelStatusSyncer::OnRequestCompleted(bool update_received,
147 bool enabled,
148 int poll_interval_seconds) {
149 DCHECK(request_);
150 request_.reset();
152 // Persist the current time as the last request complete time.
153 last_check_time_ = base::Time::Now();
154 prefs_->SetInt64(kGCMChannelLastCheckTime,
155 last_check_time_.ToInternalValue());
157 if (update_received) {
158 if (gcm_enabled_ != enabled) {
159 gcm_enabled_ = enabled;
160 prefs_->SetBoolean(kGCMChannelStatus, enabled);
161 if (gcm_enabled_)
162 driver_->Enable();
163 else
164 driver_->Disable();
167 // Skip updating poll interval if the custom one is still in effect.
168 if (!custom_poll_interval_use_count_) {
169 DCHECK_GE(poll_interval_seconds,
170 GCMChannelStatusRequest::min_poll_interval_seconds());
171 if (poll_interval_seconds_ != poll_interval_seconds) {
172 poll_interval_seconds_ = poll_interval_seconds;
173 prefs_->SetInteger(kGCMChannelPollIntervalSeconds,
174 poll_interval_seconds_);
179 // Do not schedule next request if syncer is stopped.
180 if (started_)
181 ScheduleRequest();
184 void GCMChannelStatusSyncer::ScheduleRequest() {
185 current_request_delay_interval_ = GetRequestDelayInterval();
186 base::MessageLoop::current()->PostDelayedTask(
187 FROM_HERE,
188 base::Bind(&GCMChannelStatusSyncer::StartRequest,
189 weak_ptr_factory_.GetWeakPtr()),
190 current_request_delay_interval_);
192 if (custom_poll_interval_use_count_)
193 custom_poll_interval_use_count_--;
196 void GCMChannelStatusSyncer::StartRequest() {
197 DCHECK(!request_);
199 request_.reset(new GCMChannelStatusRequest(
200 request_context_,
201 channel_status_request_url_,
202 user_agent_,
203 base::Bind(&GCMChannelStatusSyncer::OnRequestCompleted,
204 weak_ptr_factory_.GetWeakPtr())));
205 request_->Start();
208 base::TimeDelta GCMChannelStatusSyncer::GetRequestDelayInterval() const {
209 // No delay during testing.
210 if (delay_removed_for_testing_)
211 return base::TimeDelta();
213 // Make sure that checking with server occurs at polling interval, regardless
214 // whether the browser restarts.
215 int64 delay_seconds = poll_interval_seconds_ -
216 (base::Time::Now() - last_check_time_).InSeconds();
217 if (delay_seconds < 0)
218 delay_seconds = 0;
220 if (last_check_time_.is_null()) {
221 // For the first-time request, add a small delay to avoid sending request at
222 // browser startup time.
223 DCHECK(!delay_seconds);
224 delay_seconds = kFirstTimeDelaySeconds;
225 } else {
226 // Otherwise, add a fuzzing variation to the delay.
227 // The fuzzing variation is off when the custom interval is used.
228 if (!custom_poll_interval_use_count_)
229 delay_seconds += base::RandInt(0, kGCMChannelRequestTimeJitterSeconds);
232 return base::TimeDelta::FromSeconds(delay_seconds);
235 } // namespace gcm