blob: cbe1ba2fd4dcb46a1aa6054be38874b1f903231b [file] [log] [blame]
jianli2dc910b02014-09-19 02:42:461// 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
avi26062922015-12-26 00:14:187#include <stdint.h>
8
jianli2dc910b02014-09-19 02:42:469#include "base/bind.h"
Jian Li74eadb02014-10-16 05:53:5610#include "base/command_line.h"
jianli2dc910b02014-09-19 02:42:4611#include "base/location.h"
12#include "base/logging.h"
jianli2dc910b02014-09-19 02:42:4613#include "base/rand_util.h"
skyostilb0daa012015-06-02 19:03:4814#include "base/single_thread_task_runner.h"
Jian Li74eadb02014-10-16 05:53:5615#include "base/strings/string_number_conversions.h"
gab7966d312016-05-11 20:35:0116#include "base/threading/thread_task_runner_handle.h"
jianli2dc910b02014-09-19 02:42:4617#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"
brettw066508682016-02-03 08:22:0220#include "components/prefs/pref_registry_simple.h"
21#include "components/prefs/pref_service.h"
jianli2dc910b02014-09-19 02:42:4622
23namespace gcm {
24
25namespace {
26
jianli2dc910b02014-09-19 02:42:4627// A small delay to avoid sending request at browser startup time for first-time
28// request.
29const int kFirstTimeDelaySeconds = 1 * 60; // 1 minute.
30
31// The fuzzing variation added to the polling delay.
32const int kGCMChannelRequestTimeJitterSeconds = 15 * 60; // 15 minues.
33
Jian Li74eadb02014-10-16 05:53:5634// The minimum poll interval that can be overridden to.
35const int kMinCustomPollIntervalMinutes = 2;
36
37// Custom poll interval could not be used more than the limit below.
38const int kMaxNumberToUseCustomPollInterval = 10;
39
jianli2dc910b02014-09-19 02:42:4640} // namespace
41
jianlife3a8bd2015-02-05 00:55:2542namespace prefs {
43
44// The GCM channel's enabled state.
45const char kGCMChannelStatus[] = "gcm.channel_status";
46
47// The GCM channel's polling interval (in seconds).
48const char kGCMChannelPollIntervalSeconds[] = "gcm.poll_interval";
49
50// Last time when checking with the GCM channel status server is done.
51const char kGCMChannelLastCheckTime[] = "gcm.check_time";
52
53} // namepsace prefs
54
Jian Li74eadb02014-10-16 05:53:5655namespace switches {
56
57// Override the default poll interval for testing purpose.
58const char kCustomPollIntervalMinutes[] = "gcm-channel-poll-interval";
59
60} // namepsace switches
61
jianli2dc910b02014-09-19 02:42:4662// static
63void GCMChannelStatusSyncer::RegisterPrefs(PrefRegistrySimple* registry) {
jianlife3a8bd2015-02-05 00:55:2564 registry->RegisterBooleanPref(prefs::kGCMChannelStatus, true);
jianli2dc910b02014-09-19 02:42:4665 registry->RegisterIntegerPref(
jianlife3a8bd2015-02-05 00:55:2566 prefs::kGCMChannelPollIntervalSeconds,
jianli2dc910b02014-09-19 02:42:4667 GCMChannelStatusRequest::default_poll_interval_seconds());
jianlife3a8bd2015-02-05 00:55:2568 registry->RegisterInt64Pref(prefs::kGCMChannelLastCheckTime, 0);
jianli2dc910b02014-09-19 02:42:4669}
70
71// static
72void GCMChannelStatusSyncer::RegisterProfilePrefs(
73 user_prefs::PrefRegistrySyncable* registry) {
raymesaa608722015-04-27 03:00:2574 registry->RegisterBooleanPref(prefs::kGCMChannelStatus, true);
jianli2dc910b02014-09-19 02:42:4675 registry->RegisterIntegerPref(
jianlife3a8bd2015-02-05 00:55:2576 prefs::kGCMChannelPollIntervalSeconds,
raymesaa608722015-04-27 03:00:2577 GCMChannelStatusRequest::default_poll_interval_seconds());
78 registry->RegisterInt64Pref(prefs::kGCMChannelLastCheckTime, 0);
jianli2dc910b02014-09-19 02:42:4679}
80
81// static
82int GCMChannelStatusSyncer::first_time_delay_seconds() {
83 return kFirstTimeDelaySeconds;
84}
85
86GCMChannelStatusSyncer::GCMChannelStatusSyncer(
87 GCMDriver* driver,
88 PrefService* prefs,
fgorski3f6b84cd2014-10-10 21:04:1889 const std::string& channel_status_request_url,
90 const std::string& user_agent,
jianli2dc910b02014-09-19 02:42:4691 const scoped_refptr<net::URLRequestContextGetter>& request_context)
92 : driver_(driver),
93 prefs_(prefs),
fgorski3f6b84cd2014-10-10 21:04:1894 channel_status_request_url_(channel_status_request_url),
95 user_agent_(user_agent),
jianli2dc910b02014-09-19 02:42:4696 request_context_(request_context),
Jian Li74eadb02014-10-16 05:53:5697 started_(false),
jianli2dc910b02014-09-19 02:42:4698 gcm_enabled_(true),
99 poll_interval_seconds_(
100 GCMChannelStatusRequest::default_poll_interval_seconds()),
Jian Li74eadb02014-10-16 05:53:56101 custom_poll_interval_use_count_(0),
jianli2dc910b02014-09-19 02:42:46102 delay_removed_for_testing_(false),
103 weak_ptr_factory_(this) {
jianlife3a8bd2015-02-05 00:55:25104 gcm_enabled_ = prefs_->GetBoolean(prefs::kGCMChannelStatus);
105 poll_interval_seconds_ = prefs_->GetInteger(
106 prefs::kGCMChannelPollIntervalSeconds);
jianli2dc910b02014-09-19 02:42:46107 if (poll_interval_seconds_ <
108 GCMChannelStatusRequest::min_poll_interval_seconds()) {
109 poll_interval_seconds_ =
110 GCMChannelStatusRequest::min_poll_interval_seconds();
111 }
kkosztyo.u-szegedb33617c2014-12-04 09:54:36112 const base::CommandLine& command_line =
113 *base::CommandLine::ForCurrentProcess();
114 if (command_line.HasSwitch(switches::kCustomPollIntervalMinutes)) {
115 std::string value(command_line.GetSwitchValueASCII(
Jian Li74eadb02014-10-16 05:53:56116 switches::kCustomPollIntervalMinutes));
117 int minutes = 0;
118 if (base::StringToInt(value, &minutes)) {
119 DCHECK_GE(minutes, kMinCustomPollIntervalMinutes);
120 if (minutes >= kMinCustomPollIntervalMinutes) {
121 poll_interval_seconds_ = minutes * 60;
122 custom_poll_interval_use_count_ = kMaxNumberToUseCustomPollInterval;
123 }
124 }
125 }
jianli2dc910b02014-09-19 02:42:46126 last_check_time_ = base::Time::FromInternalValue(
jianlife3a8bd2015-02-05 00:55:25127 prefs_->GetInt64(prefs::kGCMChannelLastCheckTime));
jianli2dc910b02014-09-19 02:42:46128}
129
130GCMChannelStatusSyncer::~GCMChannelStatusSyncer() {
131}
132
133void GCMChannelStatusSyncer::EnsureStarted() {
134 // Bail out if the request is already scheduled or started.
Jian Li74eadb02014-10-16 05:53:56135 if (started_)
jianli2dc910b02014-09-19 02:42:46136 return;
Jian Li74eadb02014-10-16 05:53:56137 started_ = true;
jianli2dc910b02014-09-19 02:42:46138
139 ScheduleRequest();
140}
141
142void GCMChannelStatusSyncer::Stop() {
Jian Li74eadb02014-10-16 05:53:56143 started_ = false;
jianli2dc910b02014-09-19 02:42:46144 request_.reset();
145 weak_ptr_factory_.InvalidateWeakPtrs();
146}
147
Jian Li74eadb02014-10-16 05:53:56148void GCMChannelStatusSyncer::OnRequestCompleted(bool update_received,
149 bool enabled,
jianli2dc910b02014-09-19 02:42:46150 int poll_interval_seconds) {
151 DCHECK(request_);
152 request_.reset();
153
154 // Persist the current time as the last request complete time.
155 last_check_time_ = base::Time::Now();
jianlife3a8bd2015-02-05 00:55:25156 prefs_->SetInt64(prefs::kGCMChannelLastCheckTime,
jianli2dc910b02014-09-19 02:42:46157 last_check_time_.ToInternalValue());
158
Jian Li74eadb02014-10-16 05:53:56159 if (update_received) {
160 if (gcm_enabled_ != enabled) {
161 gcm_enabled_ = enabled;
jianlife3a8bd2015-02-05 00:55:25162 prefs_->SetBoolean(prefs::kGCMChannelStatus, enabled);
Jian Li74eadb02014-10-16 05:53:56163 if (gcm_enabled_)
164 driver_->Enable();
165 else
166 driver_->Disable();
167 }
168
169 // Skip updating poll interval if the custom one is still in effect.
170 if (!custom_poll_interval_use_count_) {
171 DCHECK_GE(poll_interval_seconds,
172 GCMChannelStatusRequest::min_poll_interval_seconds());
173 if (poll_interval_seconds_ != poll_interval_seconds) {
174 poll_interval_seconds_ = poll_interval_seconds;
jianlife3a8bd2015-02-05 00:55:25175 prefs_->SetInteger(prefs::kGCMChannelPollIntervalSeconds,
Jian Li74eadb02014-10-16 05:53:56176 poll_interval_seconds_);
177 }
178 }
jianlicd886412014-10-14 23:16:14179 }
jianli2dc910b02014-09-19 02:42:46180
Jian Li74eadb02014-10-16 05:53:56181 // Do not schedule next request if syncer is stopped.
182 if (started_)
183 ScheduleRequest();
jianli2dc910b02014-09-19 02:42:46184}
185
186void GCMChannelStatusSyncer::ScheduleRequest() {
187 current_request_delay_interval_ = GetRequestDelayInterval();
skyostilb0daa012015-06-02 19:03:48188 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
189 FROM_HERE, base::Bind(&GCMChannelStatusSyncer::StartRequest,
190 weak_ptr_factory_.GetWeakPtr()),
jianli2dc910b02014-09-19 02:42:46191 current_request_delay_interval_);
Jian Li74eadb02014-10-16 05:53:56192
193 if (custom_poll_interval_use_count_)
194 custom_poll_interval_use_count_--;
jianli2dc910b02014-09-19 02:42:46195}
196
197void GCMChannelStatusSyncer::StartRequest() {
198 DCHECK(!request_);
199
200 request_.reset(new GCMChannelStatusRequest(
201 request_context_,
fgorski3f6b84cd2014-10-10 21:04:18202 channel_status_request_url_,
203 user_agent_,
jianli2dc910b02014-09-19 02:42:46204 base::Bind(&GCMChannelStatusSyncer::OnRequestCompleted,
205 weak_ptr_factory_.GetWeakPtr())));
206 request_->Start();
207}
208
209base::TimeDelta GCMChannelStatusSyncer::GetRequestDelayInterval() const {
210 // No delay during testing.
211 if (delay_removed_for_testing_)
212 return base::TimeDelta();
213
214 // Make sure that checking with server occurs at polling interval, regardless
215 // whether the browser restarts.
avi26062922015-12-26 00:14:18216 int64_t delay_seconds = poll_interval_seconds_ -
217 (base::Time::Now() - last_check_time_).InSeconds();
jianli2dc910b02014-09-19 02:42:46218 if (delay_seconds < 0)
219 delay_seconds = 0;
220
221 if (last_check_time_.is_null()) {
222 // For the first-time request, add a small delay to avoid sending request at
223 // browser startup time.
224 DCHECK(!delay_seconds);
225 delay_seconds = kFirstTimeDelaySeconds;
226 } else {
227 // Otherwise, add a fuzzing variation to the delay.
Jian Li74eadb02014-10-16 05:53:56228 // The fuzzing variation is off when the custom interval is used.
229 if (!custom_poll_interval_use_count_)
230 delay_seconds += base::RandInt(0, kGCMChannelRequestTimeJitterSeconds);
jianli2dc910b02014-09-19 02:42:46231 }
232
233 return base::TimeDelta::FromSeconds(delay_seconds);
234}
235
236} // namespace gcm