• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.
4 
5 #include "google_apis/gcm/engine/heartbeat_manager.h"
6 
7 #include "google_apis/gcm/protocol/mcs.pb.h"
8 #include "net/base/network_change_notifier.h"
9 
10 namespace gcm {
11 
12 namespace {
13 // The default heartbeat when on a mobile or unknown network .
14 const int64 kCellHeartbeatDefaultMs = 1000 * 60 * 28;  // 28 minutes.
15 // The default heartbeat when on WiFi (also used for ethernet).
16 const int64 kWifiHeartbeatDefaultMs = 1000 * 60 * 15;  // 15 minutes.
17 // The default heartbeat ack interval.
18 const int64 kHeartbeatAckDefaultMs = 1000 * 60 * 1;  // 1 minute.
19 }  // namespace
20 
HeartbeatManager()21 HeartbeatManager::HeartbeatManager()
22     : waiting_for_ack_(false),
23       heartbeat_interval_ms_(0),
24       server_interval_ms_(0),
25       heartbeat_timer_(true  /* retain user task */,
26                        false  /* not repeating */),
27       weak_ptr_factory_(this) {}
28 
~HeartbeatManager()29 HeartbeatManager::~HeartbeatManager() {}
30 
Start(const base::Closure & send_heartbeat_callback,const base::Closure & trigger_reconnect_callback)31 void HeartbeatManager::Start(
32     const base::Closure& send_heartbeat_callback,
33     const base::Closure& trigger_reconnect_callback) {
34   DCHECK(!send_heartbeat_callback.is_null());
35   DCHECK(!trigger_reconnect_callback.is_null());
36   send_heartbeat_callback_ = send_heartbeat_callback;
37   trigger_reconnect_callback_ = trigger_reconnect_callback;
38 
39   // Kicks off the timer.
40   waiting_for_ack_ = false;
41   RestartTimer();
42 }
43 
Stop()44 void HeartbeatManager::Stop() {
45   heartbeat_timer_.Stop();
46   waiting_for_ack_ = false;
47 }
48 
OnHeartbeatAcked()49 void HeartbeatManager::OnHeartbeatAcked() {
50   if (!heartbeat_timer_.IsRunning())
51     return;
52 
53   DCHECK(!send_heartbeat_callback_.is_null());
54   DCHECK(!trigger_reconnect_callback_.is_null());
55   waiting_for_ack_ = false;
56   RestartTimer();
57 }
58 
UpdateHeartbeatConfig(const mcs_proto::HeartbeatConfig & config)59 void HeartbeatManager::UpdateHeartbeatConfig(
60     const mcs_proto::HeartbeatConfig& config) {
61   if (!config.IsInitialized() ||
62       !config.has_interval_ms() ||
63       config.interval_ms() <= 0) {
64     return;
65   }
66   DVLOG(1) << "Updating heartbeat interval to " << config.interval_ms();
67   server_interval_ms_ = config.interval_ms();
68 }
69 
GetNextHeartbeatTime() const70 base::TimeTicks HeartbeatManager::GetNextHeartbeatTime() const {
71   if (heartbeat_timer_.IsRunning())
72     return heartbeat_timer_.desired_run_time();
73   else
74     return base::TimeTicks();
75 }
76 
OnHeartbeatTriggered()77 void HeartbeatManager::OnHeartbeatTriggered() {
78   if (waiting_for_ack_) {
79     LOG(WARNING) << "Lost connection to MCS, reconnecting.";
80     Stop();
81     trigger_reconnect_callback_.Run();
82     return;
83   }
84 
85   waiting_for_ack_ = true;
86   RestartTimer();
87   send_heartbeat_callback_.Run();
88 }
89 
RestartTimer()90 void HeartbeatManager::RestartTimer() {
91   if (!waiting_for_ack_) {
92     // Recalculate the timer interval based network type.
93     if (server_interval_ms_ != 0) {
94       // If a server interval is set, it overrides any local one.
95       heartbeat_interval_ms_ = server_interval_ms_;
96     } else if (net::NetworkChangeNotifier::GetConnectionType() ==
97                    net::NetworkChangeNotifier::CONNECTION_WIFI ||
98                net::NetworkChangeNotifier::GetConnectionType() ==
99                    net::NetworkChangeNotifier::CONNECTION_ETHERNET) {
100       heartbeat_interval_ms_ = kWifiHeartbeatDefaultMs;
101     } else {
102       // For unknown connections, use the longer cellular heartbeat interval.
103       heartbeat_interval_ms_ = kCellHeartbeatDefaultMs;
104     }
105     DVLOG(1) << "Sending next heartbeat in "
106              << heartbeat_interval_ms_ << " ms.";
107   } else {
108     heartbeat_interval_ms_ = kHeartbeatAckDefaultMs;
109     DVLOG(1) << "Resetting timer for ack with "
110              << heartbeat_interval_ms_ << " ms interval.";
111   }
112   heartbeat_timer_.Start(FROM_HERE,
113                          base::TimeDelta::FromMilliseconds(
114                              heartbeat_interval_ms_),
115                          base::Bind(&HeartbeatManager::OnHeartbeatTriggered,
116                                     weak_ptr_factory_.GetWeakPtr()));
117 }
118 
119 }  // namespace gcm
120