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"
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"
22 // The GCM channel's enabled state.
23 const char kGCMChannelStatus
[] = "gcm.channel_status";
25 // The GCM channel's polling interval (in seconds).
26 const char kGCMChannelPollIntervalSeconds
[] = "gcm.poll_interval";
28 // Last time when checking with the GCM channel status server is done.
29 const char kGCMChannelLastCheckTime
[] = "gcm.check_time";
31 // A small delay to avoid sending request at browser startup time for first-time
33 const int kFirstTimeDelaySeconds
= 1 * 60; // 1 minute.
35 // The fuzzing variation added to the polling delay.
36 const int kGCMChannelRequestTimeJitterSeconds
= 15 * 60; // 15 minues.
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);
50 void GCMChannelStatusSyncer::RegisterProfilePrefs(
51 user_prefs::PrefRegistrySyncable
* registry
) {
52 registry
->RegisterBooleanPref(
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
,
63 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF
);
67 int GCMChannelStatusSyncer::first_time_delay_seconds() {
68 return kFirstTimeDelaySeconds
;
71 GCMChannelStatusSyncer::GCMChannelStatusSyncer(
74 const std::string
& channel_status_request_url
,
75 const std::string
& user_agent
,
76 const scoped_refptr
<net::URLRequestContextGetter
>& request_context
)
79 channel_status_request_url_(channel_status_request_url
),
80 user_agent_(user_agent
),
81 request_context_(request_context
),
83 poll_interval_seconds_(
84 GCMChannelStatusRequest::default_poll_interval_seconds()),
85 delay_removed_for_testing_(false),
86 weak_ptr_factory_(this) {
87 gcm_enabled_
= prefs_
->GetBoolean(kGCMChannelStatus
);
88 poll_interval_seconds_
= prefs_
->GetInteger(kGCMChannelPollIntervalSeconds
);
89 if (poll_interval_seconds_
<
90 GCMChannelStatusRequest::min_poll_interval_seconds()) {
91 poll_interval_seconds_
=
92 GCMChannelStatusRequest::min_poll_interval_seconds();
94 last_check_time_
= base::Time::FromInternalValue(
95 prefs_
->GetInt64(kGCMChannelLastCheckTime
));
98 GCMChannelStatusSyncer::~GCMChannelStatusSyncer() {
101 void GCMChannelStatusSyncer::EnsureStarted() {
102 // Bail out if the request is already scheduled or started.
103 if (weak_ptr_factory_
.HasWeakPtrs() || request_
)
109 void GCMChannelStatusSyncer::Stop() {
111 weak_ptr_factory_
.InvalidateWeakPtrs();
114 void GCMChannelStatusSyncer::OnRequestCompleted(bool enabled
,
115 int poll_interval_seconds
) {
119 // Persist the current time as the last request complete time.
120 last_check_time_
= base::Time::Now();
121 prefs_
->SetInt64(kGCMChannelLastCheckTime
,
122 last_check_time_
.ToInternalValue());
124 if (gcm_enabled_
!= enabled
) {
125 gcm_enabled_
= enabled
;
126 prefs_
->SetBoolean(kGCMChannelStatus
, enabled
);
133 DCHECK_GE(poll_interval_seconds
,
134 GCMChannelStatusRequest::min_poll_interval_seconds());
135 if (poll_interval_seconds_
!= poll_interval_seconds
) {
136 poll_interval_seconds_
= poll_interval_seconds
;
137 prefs_
->SetInteger(kGCMChannelPollIntervalSeconds
, poll_interval_seconds_
);
143 void GCMChannelStatusSyncer::ScheduleRequest() {
144 current_request_delay_interval_
= GetRequestDelayInterval();
145 base::MessageLoop::current()->PostDelayedTask(
147 base::Bind(&GCMChannelStatusSyncer::StartRequest
,
148 weak_ptr_factory_
.GetWeakPtr()),
149 current_request_delay_interval_
);
152 void GCMChannelStatusSyncer::StartRequest() {
155 request_
.reset(new GCMChannelStatusRequest(
157 channel_status_request_url_
,
159 base::Bind(&GCMChannelStatusSyncer::OnRequestCompleted
,
160 weak_ptr_factory_
.GetWeakPtr())));
164 base::TimeDelta
GCMChannelStatusSyncer::GetRequestDelayInterval() const {
165 // No delay during testing.
166 if (delay_removed_for_testing_
)
167 return base::TimeDelta();
169 // Make sure that checking with server occurs at polling interval, regardless
170 // whether the browser restarts.
171 int64 delay_seconds
= poll_interval_seconds_
-
172 (base::Time::Now() - last_check_time_
).InSeconds();
173 if (delay_seconds
< 0)
176 if (last_check_time_
.is_null()) {
177 // For the first-time request, add a small delay to avoid sending request at
178 // browser startup time.
179 DCHECK(!delay_seconds
);
180 delay_seconds
= kFirstTimeDelaySeconds
;
182 // Otherwise, add a fuzzing variation to the delay.
183 delay_seconds
+= base::RandInt(0, kGCMChannelRequestTimeJitterSeconds
);
186 return base::TimeDelta::FromSeconds(delay_seconds
);