shell_network_controller_chromeos.cc revision 1320f92c476a1ad9d19dba2a48c72b75566198e9
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 "extensions/shell/browser/shell_network_controller_chromeos.h" 6 7#include "base/bind.h" 8#include "base/location.h" 9#include "base/logging.h" 10#include "base/strings/stringprintf.h" 11#include "base/time/time.h" 12#include "chromeos/network/network_connection_handler.h" 13#include "chromeos/network/network_handler.h" 14#include "chromeos/network/network_handler_callbacks.h" 15#include "chromeos/network/network_state.h" 16#include "chromeos/network/network_state_handler.h" 17#include "third_party/cros_system_api/dbus/service_constants.h" 18 19namespace extensions { 20 21namespace { 22 23// Frequency at which networks should be scanned when not connected to a network 24// or when connected to a non-preferred network. 25const int kScanIntervalSec = 10; 26 27void HandleEnableWifiError(const std::string& error_name, 28 scoped_ptr<base::DictionaryValue> error_data) { 29 LOG(WARNING) << "Unable to enable wifi: " << error_name; 30} 31 32// Returns a human-readable name for the network described by |network|. 33std::string GetNetworkName(const chromeos::NetworkState& network) { 34 return !network.name().empty() 35 ? network.name() 36 : base::StringPrintf("[%s]", network.type().c_str()); 37} 38 39// Returns true if shill is either connected or connecting to a network. 40bool IsConnectedOrConnecting() { 41 chromeos::NetworkStateHandler* state_handler = 42 chromeos::NetworkHandler::Get()->network_state_handler(); 43 return state_handler->ConnectedNetworkByType( 44 chromeos::NetworkTypePattern::Default()) || 45 state_handler->ConnectingNetworkByType( 46 chromeos::NetworkTypePattern::Default()); 47} 48 49} // namespace 50 51ShellNetworkController::ShellNetworkController( 52 const std::string& preferred_network_name) 53 : state_(STATE_IDLE), 54 preferred_network_name_(preferred_network_name), 55 preferred_network_is_active_(false), 56 weak_ptr_factory_(this) { 57 chromeos::NetworkStateHandler* state_handler = 58 chromeos::NetworkHandler::Get()->network_state_handler(); 59 state_handler->AddObserver(this, FROM_HERE); 60 state_handler->SetTechnologyEnabled( 61 chromeos::NetworkTypePattern::Primitive(shill::kTypeWifi), 62 true, 63 base::Bind(&HandleEnableWifiError)); 64 65 // If we're unconnected, trigger a connection attempt and start scanning. 66 NetworkConnectionStateChanged(NULL); 67} 68 69ShellNetworkController::~ShellNetworkController() { 70 chromeos::NetworkHandler::Get()->network_state_handler()->RemoveObserver( 71 this, FROM_HERE); 72} 73 74void ShellNetworkController::NetworkListChanged() { 75 VLOG(1) << "Network list changed"; 76 ConnectIfUnconnected(); 77} 78 79void ShellNetworkController::NetworkConnectionStateChanged( 80 const chromeos::NetworkState* network) { 81 if (network) { 82 VLOG(1) << "Network connection state changed:" 83 << " name=" << GetNetworkName(*network) 84 << " type=" << network->type() << " path=" << network->path() 85 << " state=" << network->connection_state(); 86 } else { 87 VLOG(1) << "Network connection state changed: [none]"; 88 } 89 90 const chromeos::NetworkState* wifi_network = GetActiveWiFiNetwork(); 91 preferred_network_is_active_ = 92 wifi_network && wifi_network->name() == preferred_network_name_; 93 VLOG(2) << "Active WiFi network is " 94 << (wifi_network ? wifi_network->name() : std::string("[none]")); 95 96 if (preferred_network_is_active_ || 97 (preferred_network_name_.empty() && wifi_network)) { 98 SetScanningEnabled(false); 99 } else { 100 SetScanningEnabled(true); 101 ConnectIfUnconnected(); 102 } 103} 104 105const chromeos::NetworkState* ShellNetworkController::GetActiveWiFiNetwork() { 106 chromeos::NetworkStateHandler* state_handler = 107 chromeos::NetworkHandler::Get()->network_state_handler(); 108 const chromeos::NetworkState* network = state_handler->FirstNetworkByType( 109 chromeos::NetworkTypePattern::Primitive(shill::kTypeWifi)); 110 return network && 111 (network->IsConnectedState() || network->IsConnectingState()) 112 ? network 113 : NULL; 114} 115 116void ShellNetworkController::SetScanningEnabled(bool enabled) { 117 const bool currently_enabled = scan_timer_.IsRunning(); 118 if (enabled == currently_enabled) 119 return; 120 121 VLOG(1) << (enabled ? "Starting" : "Stopping") << " scanning"; 122 if (enabled) { 123 RequestScan(); 124 scan_timer_.Start(FROM_HERE, 125 base::TimeDelta::FromSeconds(kScanIntervalSec), 126 this, 127 &ShellNetworkController::RequestScan); 128 } else { 129 scan_timer_.Stop(); 130 } 131} 132 133void ShellNetworkController::RequestScan() { 134 VLOG(1) << "Requesting scan"; 135 chromeos::NetworkHandler::Get()->network_state_handler()->RequestScan(); 136} 137 138void ShellNetworkController::ConnectIfUnconnected() { 139 // Don't do anything if the default network is already the preferred one or if 140 // we have a pending request to connect to it. 141 if (preferred_network_is_active_ || 142 state_ == STATE_WAITING_FOR_PREFERRED_RESULT) 143 return; 144 145 const chromeos::NetworkState* best_network = NULL; 146 bool can_connect_to_preferred_network = false; 147 148 chromeos::NetworkHandler* handler = chromeos::NetworkHandler::Get(); 149 chromeos::NetworkStateHandler::NetworkStateList network_list; 150 handler->network_state_handler()->GetVisibleNetworkListByType( 151 chromeos::NetworkTypePattern::WiFi(), &network_list); 152 for (chromeos::NetworkStateHandler::NetworkStateList::const_iterator it = 153 network_list.begin(); 154 it != network_list.end(); 155 ++it) { 156 const chromeos::NetworkState* network = *it; 157 if (!network->connectable()) 158 continue; 159 160 if (!preferred_network_name_.empty() && 161 network->name() == preferred_network_name_) { 162 best_network = network; 163 can_connect_to_preferred_network = true; 164 break; 165 } else if (!best_network) { 166 best_network = network; 167 } 168 } 169 170 // Don't switch networks if we're already connecting/connected and wouldn't be 171 // switching to the preferred network. 172 if ((IsConnectedOrConnecting() || state_ != STATE_IDLE) && 173 !can_connect_to_preferred_network) 174 return; 175 176 if (!best_network) { 177 VLOG(1) << "Didn't find any connectable networks"; 178 return; 179 } 180 181 VLOG(1) << "Connecting to network " << GetNetworkName(*best_network) 182 << " with path " << best_network->path() << " and strength " 183 << best_network->signal_strength(); 184 state_ = can_connect_to_preferred_network 185 ? STATE_WAITING_FOR_PREFERRED_RESULT 186 : STATE_WAITING_FOR_NON_PREFERRED_RESULT; 187 handler->network_connection_handler()->ConnectToNetwork( 188 best_network->path(), 189 base::Bind(&ShellNetworkController::HandleConnectionSuccess, 190 weak_ptr_factory_.GetWeakPtr()), 191 base::Bind(&ShellNetworkController::HandleConnectionError, 192 weak_ptr_factory_.GetWeakPtr()), 193 false /* check_error_state */); 194} 195 196void ShellNetworkController::HandleConnectionSuccess() { 197 VLOG(1) << "Successfully connected to network"; 198 state_ = STATE_IDLE; 199} 200 201void ShellNetworkController::HandleConnectionError( 202 const std::string& error_name, 203 scoped_ptr<base::DictionaryValue> error_data) { 204 LOG(WARNING) << "Unable to connect to network: " << error_name; 205 state_ = STATE_IDLE; 206} 207 208} // namespace extensions 209