Home | History | Annotate | Download | only in engine
      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