shell_network_controller_chromeos.cc revision 5f1c94371a64b3196d4be9466099bb892df9b88e
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::NetworkHandler::Initialize(); 58 chromeos::NetworkStateHandler* state_handler = 59 chromeos::NetworkHandler::Get()->network_state_handler(); 60 state_handler->AddObserver(this, FROM_HERE); 61 state_handler->SetTechnologyEnabled( 62 chromeos::NetworkTypePattern::Primitive(shill::kTypeWifi), 63 true, 64 base::Bind(&HandleEnableWifiError)); 65 66 // If we're unconnected, trigger a connection attempt and start scanning. 67 NetworkConnectionStateChanged(NULL); 68} 69 70ShellNetworkController::~ShellNetworkController() { 71 chromeos::NetworkHandler::Get()->network_state_handler()->RemoveObserver( 72 this, FROM_HERE); 73 chromeos::NetworkHandler::Shutdown(); 74} 75 76void ShellNetworkController::NetworkListChanged() { 77 VLOG(1) << "Network list changed"; 78 ConnectIfUnconnected(); 79} 80 81void ShellNetworkController::NetworkConnectionStateChanged( 82 const chromeos::NetworkState* network) { 83 if (network) { 84 VLOG(1) << "Network connection state changed:" 85 << " name=" << GetNetworkName(*network) 86 << " type=" << network->type() << " path=" << network->path() 87 << " state=" << network->connection_state(); 88 } else { 89 VLOG(1) << "Network connection state changed: [none]"; 90 } 91 92 const chromeos::NetworkState* wifi_network = GetActiveWiFiNetwork(); 93 preferred_network_is_active_ = 94 wifi_network && wifi_network->name() == preferred_network_name_; 95 VLOG(2) << "Active WiFi network is " 96 << (wifi_network ? wifi_network->name() : std::string("[none]")); 97 98 if (preferred_network_is_active_ || 99 (preferred_network_name_.empty() && wifi_network)) { 100 SetScanningEnabled(false); 101 } else { 102 SetScanningEnabled(true); 103 ConnectIfUnconnected(); 104 } 105} 106 107const chromeos::NetworkState* ShellNetworkController::GetActiveWiFiNetwork() { 108 chromeos::NetworkStateHandler* state_handler = 109 chromeos::NetworkHandler::Get()->network_state_handler(); 110 const chromeos::NetworkState* network = state_handler->FirstNetworkByType( 111 chromeos::NetworkTypePattern::Primitive(shill::kTypeWifi)); 112 return network && 113 (network->IsConnectedState() || network->IsConnectingState()) 114 ? network 115 : NULL; 116} 117 118void ShellNetworkController::SetScanningEnabled(bool enabled) { 119 const bool currently_enabled = scan_timer_.IsRunning(); 120 if (enabled == currently_enabled) 121 return; 122 123 VLOG(1) << (enabled ? "Starting" : "Stopping") << " scanning"; 124 if (enabled) { 125 RequestScan(); 126 scan_timer_.Start(FROM_HERE, 127 base::TimeDelta::FromSeconds(kScanIntervalSec), 128 this, 129 &ShellNetworkController::RequestScan); 130 } else { 131 scan_timer_.Stop(); 132 } 133} 134 135void ShellNetworkController::RequestScan() { 136 VLOG(1) << "Requesting scan"; 137 chromeos::NetworkHandler::Get()->network_state_handler()->RequestScan(); 138} 139 140void ShellNetworkController::ConnectIfUnconnected() { 141 // Don't do anything if the default network is already the preferred one or if 142 // we have a pending request to connect to it. 143 if (preferred_network_is_active_ || 144 state_ == STATE_WAITING_FOR_PREFERRED_RESULT) 145 return; 146 147 const chromeos::NetworkState* best_network = NULL; 148 bool can_connect_to_preferred_network = false; 149 150 chromeos::NetworkHandler* handler = chromeos::NetworkHandler::Get(); 151 chromeos::NetworkStateHandler::NetworkStateList network_list; 152 handler->network_state_handler()->GetVisibleNetworkListByType( 153 chromeos::NetworkTypePattern::WiFi(), &network_list); 154 for (chromeos::NetworkStateHandler::NetworkStateList::const_iterator it = 155 network_list.begin(); 156 it != network_list.end(); 157 ++it) { 158 const chromeos::NetworkState* network = *it; 159 if (!network->connectable()) 160 continue; 161 162 if (!preferred_network_name_.empty() && 163 network->name() == preferred_network_name_) { 164 best_network = network; 165 can_connect_to_preferred_network = true; 166 break; 167 } else if (!best_network) { 168 best_network = network; 169 } 170 } 171 172 // Don't switch networks if we're already connecting/connected and wouldn't be 173 // switching to the preferred network. 174 if ((IsConnectedOrConnecting() || state_ != STATE_IDLE) && 175 !can_connect_to_preferred_network) 176 return; 177 178 if (!best_network) { 179 VLOG(1) << "Didn't find any connectable networks"; 180 return; 181 } 182 183 VLOG(1) << "Connecting to network " << GetNetworkName(*best_network) 184 << " with path " << best_network->path() << " and strength " 185 << best_network->signal_strength(); 186 state_ = can_connect_to_preferred_network 187 ? STATE_WAITING_FOR_PREFERRED_RESULT 188 : STATE_WAITING_FOR_NON_PREFERRED_RESULT; 189 handler->network_connection_handler()->ConnectToNetwork( 190 best_network->path(), 191 base::Bind(&ShellNetworkController::HandleConnectionSuccess, 192 weak_ptr_factory_.GetWeakPtr()), 193 base::Bind(&ShellNetworkController::HandleConnectionError, 194 weak_ptr_factory_.GetWeakPtr()), 195 false /* check_error_state */); 196} 197 198void ShellNetworkController::HandleConnectionSuccess() { 199 VLOG(1) << "Successfully connected to network"; 200 state_ = STATE_IDLE; 201} 202 203void ShellNetworkController::HandleConnectionError( 204 const std::string& error_name, 205 scoped_ptr<base::DictionaryValue> error_data) { 206 LOG(WARNING) << "Unable to connect to network: " << error_name; 207 state_ = STATE_IDLE; 208} 209 210} // namespace extensions 211