[Local NTP] Fix fast icon NTP height.
[chromium-blink-merge.git] / google_apis / gcm / engine / heartbeat_manager.cc
blob53e0344aa726bafbbfef4ab5f1c7f9a84ef34582
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 "google_apis/gcm/engine/heartbeat_manager.h"
7 #include "base/callback.h"
8 #include "base/metrics/histogram.h"
9 #include "base/power_monitor/power_monitor.h"
10 #include "base/time/time.h"
11 #include "base/timer/timer.h"
12 #include "google_apis/gcm/protocol/mcs.pb.h"
13 #include "net/base/network_change_notifier.h"
15 namespace gcm {
17 namespace {
18 // The default heartbeat when on a mobile or unknown network .
19 const int64 kCellHeartbeatDefaultMs = 1000 * 60 * 28; // 28 minutes.
20 // The default heartbeat when on WiFi (also used for ethernet).
21 const int64 kWifiHeartbeatDefaultMs = 1000 * 60 * 15; // 15 minutes.
22 // The default heartbeat ack interval.
23 const int64 kHeartbeatAckDefaultMs = 1000 * 60 * 1; // 1 minute.
25 #if defined(OS_LINUX) && !defined(OS_CHROMEOS)
26 // The period at which to check if the heartbeat time has passed. Used to
27 // protect against platforms where the timer is delayed by the system being
28 // suspended. Only needed on linux because the other OSes provide a standard
29 // way to be notified of system suspend and resume events.
30 const int kHeartbeatMissedCheckMs = 1000 * 60 * 5; // 5 minutes.
31 #endif // defined(OS_LINUX) && !defined(OS_CHROMEOS)
33 } // namespace
35 HeartbeatManager::HeartbeatManager()
36 : waiting_for_ack_(false),
37 heartbeat_interval_ms_(0),
38 server_interval_ms_(0),
39 heartbeat_timer_(new base::Timer(true /* retain_user_task */,
40 false /* is_repeating */)),
41 weak_ptr_factory_(this) {
42 // Listen for system suspend and resume events.
43 base::PowerMonitor* monitor = base::PowerMonitor::Get();
44 if (monitor)
45 monitor->AddObserver(this);
48 HeartbeatManager::~HeartbeatManager() {
49 // Stop listening for system suspend and resume events.
50 base::PowerMonitor* monitor = base::PowerMonitor::Get();
51 if (monitor)
52 monitor->RemoveObserver(this);
55 void HeartbeatManager::Start(
56 const base::Closure& send_heartbeat_callback,
57 const base::Closure& trigger_reconnect_callback) {
58 DCHECK(!send_heartbeat_callback.is_null());
59 DCHECK(!trigger_reconnect_callback.is_null());
60 send_heartbeat_callback_ = send_heartbeat_callback;
61 trigger_reconnect_callback_ = trigger_reconnect_callback;
63 // Kicks off the timer.
64 waiting_for_ack_ = false;
65 RestartTimer();
68 void HeartbeatManager::Stop() {
69 heartbeat_expected_time_ = base::Time();
70 heartbeat_timer_->Stop();
71 waiting_for_ack_ = false;
74 void HeartbeatManager::OnHeartbeatAcked() {
75 if (!heartbeat_timer_->IsRunning())
76 return;
78 DCHECK(!send_heartbeat_callback_.is_null());
79 DCHECK(!trigger_reconnect_callback_.is_null());
80 waiting_for_ack_ = false;
81 RestartTimer();
84 void HeartbeatManager::UpdateHeartbeatConfig(
85 const mcs_proto::HeartbeatConfig& config) {
86 if (!config.IsInitialized() ||
87 !config.has_interval_ms() ||
88 config.interval_ms() <= 0) {
89 return;
91 DVLOG(1) << "Updating heartbeat interval to " << config.interval_ms();
92 server_interval_ms_ = config.interval_ms();
95 base::TimeTicks HeartbeatManager::GetNextHeartbeatTime() const {
96 if (heartbeat_timer_->IsRunning())
97 return heartbeat_timer_->desired_run_time();
98 else
99 return base::TimeTicks();
102 void HeartbeatManager::UpdateHeartbeatTimer(scoped_ptr<base::Timer> timer) {
103 bool was_running = heartbeat_timer_->IsRunning();
104 base::TimeDelta remaining_delay =
105 heartbeat_timer_->desired_run_time() - base::TimeTicks::Now();
106 base::Closure timer_task(heartbeat_timer_->user_task());
108 heartbeat_timer_->Stop();
109 heartbeat_timer_ = timer.Pass();
111 if (was_running)
112 heartbeat_timer_->Start(FROM_HERE, remaining_delay, timer_task);
115 void HeartbeatManager::OnResume() {
116 CheckForMissedHeartbeat();
119 void HeartbeatManager::OnHeartbeatTriggered() {
120 // Reset the weak pointers used for heartbeat checks.
121 weak_ptr_factory_.InvalidateWeakPtrs();
123 if (waiting_for_ack_) {
124 LOG(WARNING) << "Lost connection to MCS, reconnecting.";
125 Stop();
126 trigger_reconnect_callback_.Run();
127 return;
130 waiting_for_ack_ = true;
131 RestartTimer();
132 send_heartbeat_callback_.Run();
135 void HeartbeatManager::RestartTimer() {
136 if (!waiting_for_ack_) {
137 // Recalculate the timer interval based network type.
138 if (server_interval_ms_ != 0) {
139 // If a server interval is set, it overrides any local one.
140 heartbeat_interval_ms_ = server_interval_ms_;
141 } else if (net::NetworkChangeNotifier::GetConnectionType() ==
142 net::NetworkChangeNotifier::CONNECTION_WIFI ||
143 net::NetworkChangeNotifier::GetConnectionType() ==
144 net::NetworkChangeNotifier::CONNECTION_ETHERNET) {
145 heartbeat_interval_ms_ = kWifiHeartbeatDefaultMs;
146 } else {
147 // For unknown connections, use the longer cellular heartbeat interval.
148 heartbeat_interval_ms_ = kCellHeartbeatDefaultMs;
150 DVLOG(1) << "Sending next heartbeat in "
151 << heartbeat_interval_ms_ << " ms.";
152 } else {
153 heartbeat_interval_ms_ = kHeartbeatAckDefaultMs;
154 DVLOG(1) << "Resetting timer for ack with "
155 << heartbeat_interval_ms_ << " ms interval.";
158 heartbeat_expected_time_ =
159 base::Time::Now() +
160 base::TimeDelta::FromMilliseconds(heartbeat_interval_ms_);
161 heartbeat_timer_->Start(FROM_HERE,
162 base::TimeDelta::FromMilliseconds(
163 heartbeat_interval_ms_),
164 base::Bind(&HeartbeatManager::OnHeartbeatTriggered,
165 weak_ptr_factory_.GetWeakPtr()));
167 #if defined(OS_LINUX) && !defined(OS_CHROMEOS)
168 // Windows, Mac, Android, iOS, and Chrome OS all provide a way to be notified
169 // when the system is suspending or resuming. The only one that does not is
170 // Linux so we need to poll to check for missed heartbeats.
171 base::MessageLoop::current()->PostDelayedTask(
172 FROM_HERE,
173 base::Bind(&HeartbeatManager::CheckForMissedHeartbeat,
174 weak_ptr_factory_.GetWeakPtr()),
175 base::TimeDelta::FromMilliseconds(kHeartbeatMissedCheckMs));
176 #endif // defined(OS_LINUX) && !defined(OS_CHROMEOS)
179 void HeartbeatManager::CheckForMissedHeartbeat() {
180 // If there's no heartbeat pending, return without doing anything.
181 if (heartbeat_expected_time_.is_null())
182 return;
184 // If the heartbeat has been missed, manually trigger it.
185 if (base::Time::Now() > heartbeat_expected_time_) {
186 UMA_HISTOGRAM_LONG_TIMES("GCM.HeartbeatMissedDelta",
187 base::Time::Now() - heartbeat_expected_time_);
188 OnHeartbeatTriggered();
189 return;
192 #if defined(OS_LINUX) && !defined(OS_CHROMEOS)
193 // Otherwise check again later.
194 base::MessageLoop::current()->PostDelayedTask(
195 FROM_HERE,
196 base::Bind(&HeartbeatManager::CheckForMissedHeartbeat,
197 weak_ptr_factory_.GetWeakPtr()),
198 base::TimeDelta::FromMilliseconds(kHeartbeatMissedCheckMs));
199 #endif // defined(OS_LINUX) && !defined(OS_CHROMEOS)
202 } // namespace gcm