Fix AfterTyping experiment for Android.
[chromium-blink-merge.git] / components / gcm_driver / gcm_channel_status_syncer.cc
blobea1abb84e877eaf0f7bbdea95a8b9b67bc48e41b
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/prefs/pref_registry_simple.h"
12 #include "base/prefs/pref_service.h"
13 #include "base/rand_util.h"
14 #include "base/single_thread_task_runner.h"
15 #include "base/strings/string_number_conversions.h"
16 #include "base/thread_task_runner_handle.h"
17 #include "components/gcm_driver/gcm_channel_status_request.h"
18 #include "components/gcm_driver/gcm_driver.h"
19 #include "components/pref_registry/pref_registry_syncable.h"
21 namespace gcm {
23 namespace {
25 // A small delay to avoid sending request at browser startup time for first-time
26 // request.
27 const int kFirstTimeDelaySeconds = 1 * 60; // 1 minute.
29 // The fuzzing variation added to the polling delay.
30 const int kGCMChannelRequestTimeJitterSeconds = 15 * 60; // 15 minues.
32 // The minimum poll interval that can be overridden to.
33 const int kMinCustomPollIntervalMinutes = 2;
35 // Custom poll interval could not be used more than the limit below.
36 const int kMaxNumberToUseCustomPollInterval = 10;
38 } // namespace
40 namespace prefs {
42 // The GCM channel's enabled state.
43 const char kGCMChannelStatus[] = "gcm.channel_status";
45 // The GCM channel's polling interval (in seconds).
46 const char kGCMChannelPollIntervalSeconds[] = "gcm.poll_interval";
48 // Last time when checking with the GCM channel status server is done.
49 const char kGCMChannelLastCheckTime[] = "gcm.check_time";
51 } // namepsace prefs
53 namespace switches {
55 // Override the default poll interval for testing purpose.
56 const char kCustomPollIntervalMinutes[] = "gcm-channel-poll-interval";
58 } // namepsace switches
60 // static
61 void GCMChannelStatusSyncer::RegisterPrefs(PrefRegistrySimple* registry) {
62 registry->RegisterBooleanPref(prefs::kGCMChannelStatus, true);
63 registry->RegisterIntegerPref(
64 prefs::kGCMChannelPollIntervalSeconds,
65 GCMChannelStatusRequest::default_poll_interval_seconds());
66 registry->RegisterInt64Pref(prefs::kGCMChannelLastCheckTime, 0);
69 // static
70 void GCMChannelStatusSyncer::RegisterProfilePrefs(
71 user_prefs::PrefRegistrySyncable* registry) {
72 registry->RegisterBooleanPref(prefs::kGCMChannelStatus, true);
73 registry->RegisterIntegerPref(
74 prefs::kGCMChannelPollIntervalSeconds,
75 GCMChannelStatusRequest::default_poll_interval_seconds());
76 registry->RegisterInt64Pref(prefs::kGCMChannelLastCheckTime, 0);
79 // static
80 int GCMChannelStatusSyncer::first_time_delay_seconds() {
81 return kFirstTimeDelaySeconds;
84 GCMChannelStatusSyncer::GCMChannelStatusSyncer(
85 GCMDriver* driver,
86 PrefService* prefs,
87 const std::string& channel_status_request_url,
88 const std::string& user_agent,
89 const scoped_refptr<net::URLRequestContextGetter>& request_context)
90 : driver_(driver),
91 prefs_(prefs),
92 channel_status_request_url_(channel_status_request_url),
93 user_agent_(user_agent),
94 request_context_(request_context),
95 started_(false),
96 gcm_enabled_(true),
97 poll_interval_seconds_(
98 GCMChannelStatusRequest::default_poll_interval_seconds()),
99 custom_poll_interval_use_count_(0),
100 delay_removed_for_testing_(false),
101 weak_ptr_factory_(this) {
102 gcm_enabled_ = prefs_->GetBoolean(prefs::kGCMChannelStatus);
103 poll_interval_seconds_ = prefs_->GetInteger(
104 prefs::kGCMChannelPollIntervalSeconds);
105 if (poll_interval_seconds_ <
106 GCMChannelStatusRequest::min_poll_interval_seconds()) {
107 poll_interval_seconds_ =
108 GCMChannelStatusRequest::min_poll_interval_seconds();
110 const base::CommandLine& command_line =
111 *base::CommandLine::ForCurrentProcess();
112 if (command_line.HasSwitch(switches::kCustomPollIntervalMinutes)) {
113 std::string value(command_line.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(prefs::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(prefs::kGCMChannelLastCheckTime,
155 last_check_time_.ToInternalValue());
157 if (update_received) {
158 if (gcm_enabled_ != enabled) {
159 gcm_enabled_ = enabled;
160 prefs_->SetBoolean(prefs::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(prefs::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::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
187 FROM_HERE, base::Bind(&GCMChannelStatusSyncer::StartRequest,
188 weak_ptr_factory_.GetWeakPtr()),
189 current_request_delay_interval_);
191 if (custom_poll_interval_use_count_)
192 custom_poll_interval_use_count_--;
195 void GCMChannelStatusSyncer::StartRequest() {
196 DCHECK(!request_);
198 request_.reset(new GCMChannelStatusRequest(
199 request_context_,
200 channel_status_request_url_,
201 user_agent_,
202 base::Bind(&GCMChannelStatusSyncer::OnRequestCompleted,
203 weak_ptr_factory_.GetWeakPtr())));
204 request_->Start();
207 base::TimeDelta GCMChannelStatusSyncer::GetRequestDelayInterval() const {
208 // No delay during testing.
209 if (delay_removed_for_testing_)
210 return base::TimeDelta();
212 // Make sure that checking with server occurs at polling interval, regardless
213 // whether the browser restarts.
214 int64 delay_seconds = poll_interval_seconds_ -
215 (base::Time::Now() - last_check_time_).InSeconds();
216 if (delay_seconds < 0)
217 delay_seconds = 0;
219 if (last_check_time_.is_null()) {
220 // For the first-time request, add a small delay to avoid sending request at
221 // browser startup time.
222 DCHECK(!delay_seconds);
223 delay_seconds = kFirstTimeDelaySeconds;
224 } else {
225 // Otherwise, add a fuzzing variation to the delay.
226 // The fuzzing variation is off when the custom interval is used.
227 if (!custom_poll_interval_use_count_)
228 delay_seconds += base::RandInt(0, kGCMChannelRequestTimeJitterSeconds);
231 return base::TimeDelta::FromSeconds(delay_seconds);
234 } // namespace gcm