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 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 29 HeartbeatManager::~HeartbeatManager() {} 30 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 44 void HeartbeatManager::Stop() { 45 heartbeat_timer_.Stop(); 46 waiting_for_ack_ = false; 47 } 48 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 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 70 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 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 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