| OLD | NEW |
| (Empty) |
| 1 // Copyright (c) 2012 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 "chrome/browser/chromeos/net/network_change_notifier_chromeos.h" | |
| 6 | |
| 7 #include <vector> | |
| 8 | |
| 9 #include "base/bind.h" | |
| 10 #include "chrome/browser/chromeos/cros/cros_library.h" | |
| 11 #include "chromeos/dbus/dbus_thread_manager.h" | |
| 12 #include "chromeos/dbus/root_power_manager_client.h" | |
| 13 #include "content/public/browser/browser_thread.h" | |
| 14 #include "net/dns/dns_config_service_posix.h" | |
| 15 | |
| 16 using content::BrowserThread; | |
| 17 | |
| 18 namespace { | |
| 19 | |
| 20 // Delay for online change notification reporting. | |
| 21 const int kOnlineNotificationDelayMS = 500; | |
| 22 const int kInitialNotificationCheckDelayMS = 1000; | |
| 23 | |
| 24 bool IsOnline(chromeos::ConnectionState state) { | |
| 25 return state == chromeos::STATE_ONLINE || | |
| 26 state == chromeos::STATE_PORTAL; | |
| 27 } | |
| 28 | |
| 29 } | |
| 30 | |
| 31 namespace chromeos { | |
| 32 | |
| 33 class NetworkChangeNotifierChromeos::DnsConfigServiceChromeos | |
| 34 : public net::internal::DnsConfigServicePosix { | |
| 35 public: | |
| 36 DnsConfigServiceChromeos() {} | |
| 37 | |
| 38 virtual ~DnsConfigServiceChromeos() {} | |
| 39 | |
| 40 // net::DnsConfigServicePosix: | |
| 41 virtual bool StartWatching() OVERRIDE { | |
| 42 // Notifications from NetworkLibrary are sent to | |
| 43 // NetworkChangeNotifierChromeos. | |
| 44 return true; | |
| 45 } | |
| 46 | |
| 47 void OnNetworkChange() { | |
| 48 InvalidateConfig(); | |
| 49 InvalidateHosts(); | |
| 50 ReadNow(); | |
| 51 } | |
| 52 }; | |
| 53 | |
| 54 NetworkChangeNotifierChromeos::NetworkChangeNotifierChromeos() | |
| 55 : NetworkChangeNotifier(NetworkChangeCalculatorParamsChromeos()), | |
| 56 has_active_network_(false), | |
| 57 connection_state_(chromeos::STATE_UNKNOWN), | |
| 58 connection_type_(CONNECTION_NONE), | |
| 59 ALLOW_THIS_IN_INITIALIZER_LIST(weak_factory_(this)) { | |
| 60 BrowserThread::PostDelayedTask( | |
| 61 BrowserThread::UI, FROM_HERE, | |
| 62 base::Bind( | |
| 63 &NetworkChangeNotifierChromeos::UpdateInitialState, this), | |
| 64 base::TimeDelta::FromMilliseconds(kInitialNotificationCheckDelayMS)); | |
| 65 } | |
| 66 | |
| 67 NetworkChangeNotifierChromeos::~NetworkChangeNotifierChromeos() { | |
| 68 } | |
| 69 | |
| 70 void NetworkChangeNotifierChromeos::Init() { | |
| 71 chromeos::NetworkLibrary* network_library = | |
| 72 chromeos::CrosLibrary::Get()->GetNetworkLibrary(); | |
| 73 network_library->AddNetworkManagerObserver(this); | |
| 74 | |
| 75 DBusThreadManager::Get()->GetRootPowerManagerClient()->AddObserver(this); | |
| 76 | |
| 77 dns_config_service_.reset(new DnsConfigServiceChromeos()); | |
| 78 dns_config_service_->WatchConfig( | |
| 79 base::Bind(NetworkChangeNotifier::SetDnsConfig)); | |
| 80 | |
| 81 UpdateNetworkState(network_library); | |
| 82 } | |
| 83 | |
| 84 void NetworkChangeNotifierChromeos::Shutdown() { | |
| 85 weak_factory_.InvalidateWeakPtrs(); | |
| 86 | |
| 87 dns_config_service_.reset(); | |
| 88 | |
| 89 if (!chromeos::CrosLibrary::Get()) | |
| 90 return; | |
| 91 | |
| 92 chromeos::NetworkLibrary* lib = | |
| 93 chromeos::CrosLibrary::Get()->GetNetworkLibrary(); | |
| 94 lib->RemoveNetworkManagerObserver(this); | |
| 95 lib->RemoveObserverForAllNetworks(this); | |
| 96 | |
| 97 DBusThreadManager::Get()->GetRootPowerManagerClient()->RemoveObserver(this); | |
| 98 } | |
| 99 | |
| 100 void NetworkChangeNotifierChromeos::OnResume( | |
| 101 const base::TimeDelta& sleep_duration) { | |
| 102 // Force invalidation of various net resources on system resume. | |
| 103 BrowserThread::PostTask( | |
| 104 BrowserThread::IO, FROM_HERE, | |
| 105 base::Bind( | |
| 106 &NetworkChangeNotifier::NotifyObserversOfIPAddressChange)); | |
| 107 } | |
| 108 | |
| 109 | |
| 110 void NetworkChangeNotifierChromeos::OnNetworkManagerChanged( | |
| 111 chromeos::NetworkLibrary* cros) { | |
| 112 UpdateNetworkState(cros); | |
| 113 } | |
| 114 | |
| 115 net::NetworkChangeNotifier::ConnectionType | |
| 116 NetworkChangeNotifierChromeos::GetCurrentConnectionType() const { | |
| 117 return connection_type_; | |
| 118 } | |
| 119 | |
| 120 void NetworkChangeNotifierChromeos::OnNetworkChanged( | |
| 121 chromeos::NetworkLibrary* cros, | |
| 122 const chromeos::Network* network) { | |
| 123 CHECK(network); | |
| 124 | |
| 125 // Active network changed? | |
| 126 if (network->service_path() != service_path_) | |
| 127 UpdateNetworkState(cros); | |
| 128 else | |
| 129 UpdateConnectivityState(network); | |
| 130 } | |
| 131 | |
| 132 void NetworkChangeNotifierChromeos::UpdateNetworkState( | |
| 133 chromeos::NetworkLibrary* lib) { | |
| 134 const chromeos::Network* network = lib->active_network(); | |
| 135 if (network) { | |
| 136 lib->GetIPConfigs( | |
| 137 network->device_path(), | |
| 138 chromeos::NetworkLibrary::FORMAT_COLON_SEPARATED_HEX, | |
| 139 base::Bind(&NetworkChangeNotifierChromeos::UpdateNetworkStateCallback, | |
| 140 weak_factory_.GetWeakPtr(), | |
| 141 lib)); | |
| 142 } else { | |
| 143 // If we don't have a network, then we can't fetch ipconfigs, but we still | |
| 144 // need to process state updates when we lose a network (i.e. when | |
| 145 // has_active_network_ is still set, but we don't have one anymore). | |
| 146 NetworkIPConfigVector empty_ipconfigs; | |
| 147 UpdateNetworkStateCallback(lib, empty_ipconfigs, ""); | |
| 148 } | |
| 149 } | |
| 150 | |
| 151 void NetworkChangeNotifierChromeos::UpdateNetworkStateCallback( | |
| 152 chromeos::NetworkLibrary* lib, | |
| 153 const NetworkIPConfigVector& ipconfigs, | |
| 154 const std::string& hardware_address) { | |
| 155 const chromeos::Network* network = lib->active_network(); | |
| 156 | |
| 157 if (network) { | |
| 158 VLOG(1) << "UpdateNetworkStateCallback: " << network->name() | |
| 159 << ", type= " << network->type() | |
| 160 << ", device= " << network->device_path() | |
| 161 << ", state= " << network->state(); | |
| 162 } | |
| 163 | |
| 164 // Find the DNS servers currently in use. This code assumes that the order of | |
| 165 // the |ipconfigs| is stable. | |
| 166 std::vector<std::string> ipconfig_name_servers; | |
| 167 for (chromeos::NetworkIPConfigVector::const_iterator it = ipconfigs.begin(); | |
| 168 it != ipconfigs.end(); ++it) { | |
| 169 const chromeos::NetworkIPConfig& ipconfig = *it; | |
| 170 if (!ipconfig.name_servers.empty()) | |
| 171 ipconfig_name_servers.push_back(ipconfig.name_servers); | |
| 172 } | |
| 173 | |
| 174 // Did we loose the active network? | |
| 175 bool lost_active_network = !network && has_active_network_; | |
| 176 | |
| 177 // Did we have a change on the current active network? | |
| 178 bool changed_active_network = network && ( | |
| 179 !has_active_network_ || | |
| 180 network->service_path() != service_path_ || | |
| 181 ipconfig_name_servers != name_servers_ || | |
| 182 network->ip_address() != ip_address_); | |
| 183 | |
| 184 // If just the current active network's state changed, update it if necessary. | |
| 185 if (!lost_active_network && !changed_active_network && | |
| 186 network && network->state() != connection_state_) { | |
| 187 UpdateConnectivityState(network); | |
| 188 } | |
| 189 | |
| 190 if (lost_active_network || changed_active_network) { | |
| 191 if (has_active_network_) | |
| 192 lib->RemoveObserverForAllNetworks(this); | |
| 193 if (!network) { | |
| 194 has_active_network_ = false; | |
| 195 service_path_.clear(); | |
| 196 ip_address_.clear(); | |
| 197 name_servers_.clear(); | |
| 198 } else { | |
| 199 has_active_network_ = true; | |
| 200 service_path_ = network->service_path(); | |
| 201 ip_address_ = network->ip_address(); | |
| 202 name_servers_.swap(ipconfig_name_servers); | |
| 203 } | |
| 204 dns_config_service_->OnNetworkChange(); | |
| 205 UpdateConnectivityState(network); | |
| 206 // If there is an active network, add observer to track its changes. | |
| 207 if (network) | |
| 208 lib->AddNetworkObserver(network->service_path(), this); | |
| 209 | |
| 210 BrowserThread::PostTask( | |
| 211 BrowserThread::IO, FROM_HERE, | |
| 212 base::Bind( | |
| 213 &NetworkChangeNotifier::NotifyObserversOfIPAddressChange)); | |
| 214 } | |
| 215 } | |
| 216 | |
| 217 void NetworkChangeNotifierChromeos::UpdateConnectivityState( | |
| 218 const chromeos::Network* network) { | |
| 219 if (network) { | |
| 220 VLOG(1) << "UpdateConnectivityState: " << network->name() | |
| 221 << ", type= " << network->type() | |
| 222 << ", device= " << network->device_path() | |
| 223 << ", state= " << network->state() | |
| 224 << ", connect= " << connection_state_ | |
| 225 << ", type= " << connection_type_; | |
| 226 } | |
| 227 | |
| 228 // We don't care about all transitions of ConnectionState. OnlineStateChange | |
| 229 // notification should trigger if ConnectionType is changed. | |
| 230 chromeos::ConnectionState new_connection_state = | |
| 231 network ? network->connection_state() : chromeos::STATE_UNKNOWN; | |
| 232 | |
| 233 ConnectionType prev_connection_type = connection_type_; | |
| 234 ConnectionType new_connection_type = GetNetworkConnectionType(network); | |
| 235 | |
| 236 bool is_online = (new_connection_state == chromeos::STATE_ONLINE); | |
| 237 bool was_online = (connection_state_ == chromeos::STATE_ONLINE); | |
| 238 bool is_portal = (new_connection_state == chromeos::STATE_PORTAL); | |
| 239 bool was_portal = (connection_state_ == chromeos::STATE_PORTAL); | |
| 240 VLOG(2) << " UpdateConnectivityState2: " | |
| 241 << "new_cs = " << new_connection_state | |
| 242 << ", is_online = " << is_online | |
| 243 << ", was_online = " << was_online | |
| 244 << ", is_portal = " << is_portal | |
| 245 << ", was_portal = " << was_portal; | |
| 246 connection_state_ = new_connection_state; | |
| 247 connection_type_ = new_connection_type; | |
| 248 if (new_connection_type != prev_connection_type) { | |
| 249 VLOG(1) << "UpdateConnectivityState3: " | |
| 250 << "prev_connection_type = " << prev_connection_type | |
| 251 << ", new_connection_type = " << new_connection_type; | |
| 252 ReportConnectionChange(); | |
| 253 } | |
| 254 VLOG(2) << " UpdateConnectivityState4: " | |
| 255 << "new_cs = " << new_connection_state | |
| 256 << ", end_cs_ = " << connection_state_ | |
| 257 << "prev_type = " << prev_connection_type | |
| 258 << ", new_type_ = " << new_connection_type; | |
| 259 } | |
| 260 | |
| 261 void NetworkChangeNotifierChromeos::ReportConnectionChange() { | |
| 262 if (weak_factory_.HasWeakPtrs()) { | |
| 263 // If we have a pending task, cancel it. | |
| 264 DVLOG(1) << "ReportConnectionChange: has pending task"; | |
| 265 weak_factory_.InvalidateWeakPtrs(); | |
| 266 DVLOG(1) << "ReportConnectionChange: canceled pending task"; | |
| 267 } | |
| 268 // Posting task with delay allows us to cancel it when connection type is | |
| 269 // changed frequently. This should help us avoid transient edge reporting | |
| 270 // while switching between connection types (e.g. ethernet->wifi). | |
| 271 BrowserThread::PostDelayedTask( | |
| 272 BrowserThread::UI, FROM_HERE, | |
| 273 base::Bind( | |
| 274 &NetworkChangeNotifierChromeos::ReportConnectionChangeOnUIThread, | |
| 275 weak_factory_.GetWeakPtr()), | |
| 276 base::TimeDelta::FromMilliseconds(kOnlineNotificationDelayMS)); | |
| 277 } | |
| 278 | |
| 279 void NetworkChangeNotifierChromeos::ReportConnectionChangeOnUIThread() { | |
| 280 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
| 281 | |
| 282 BrowserThread::PostTask( | |
| 283 BrowserThread::IO, FROM_HERE, | |
| 284 base::Bind( | |
| 285 &NetworkChangeNotifierChromeos:: | |
| 286 NotifyObserversOfConnectionTypeChange)); | |
| 287 } | |
| 288 | |
| 289 // static | |
| 290 void NetworkChangeNotifierChromeos::UpdateInitialState( | |
| 291 NetworkChangeNotifierChromeos* self) { | |
| 292 chromeos::NetworkLibrary* net = | |
| 293 chromeos::CrosLibrary::Get()->GetNetworkLibrary(); | |
| 294 self->UpdateNetworkState(net); | |
| 295 } | |
| 296 | |
| 297 // static | |
| 298 net::NetworkChangeNotifier::ConnectionType | |
| 299 NetworkChangeNotifierChromeos::GetNetworkConnectionType( | |
| 300 const chromeos::Network* network) { | |
| 301 if (!network || !IsOnline(network->connection_state())) | |
| 302 return net::NetworkChangeNotifier::CONNECTION_NONE; | |
| 303 | |
| 304 switch (network->type()) { | |
| 305 case chromeos::TYPE_ETHERNET: | |
| 306 return CONNECTION_ETHERNET; | |
| 307 case chromeos::TYPE_WIFI: | |
| 308 return CONNECTION_WIFI; | |
| 309 case chromeos::TYPE_WIMAX: | |
| 310 return CONNECTION_4G; | |
| 311 case chromeos::TYPE_CELLULAR: | |
| 312 switch (static_cast<const chromeos::CellularNetwork*>( | |
| 313 network)->network_technology()) { | |
| 314 case chromeos::NETWORK_TECHNOLOGY_UNKNOWN: | |
| 315 case chromeos::NETWORK_TECHNOLOGY_1XRTT: | |
| 316 case chromeos::NETWORK_TECHNOLOGY_GPRS: | |
| 317 case chromeos::NETWORK_TECHNOLOGY_EDGE: | |
| 318 return CONNECTION_2G; | |
| 319 case chromeos::NETWORK_TECHNOLOGY_GSM: | |
| 320 case chromeos::NETWORK_TECHNOLOGY_UMTS: | |
| 321 case chromeos::NETWORK_TECHNOLOGY_EVDO: | |
| 322 case chromeos::NETWORK_TECHNOLOGY_HSPA: | |
| 323 return CONNECTION_3G; | |
| 324 case chromeos::NETWORK_TECHNOLOGY_HSPA_PLUS: | |
| 325 case chromeos::NETWORK_TECHNOLOGY_LTE: | |
| 326 case chromeos::NETWORK_TECHNOLOGY_LTE_ADVANCED: | |
| 327 return CONNECTION_4G; | |
| 328 } | |
| 329 case chromeos::TYPE_BLUETOOTH: | |
| 330 case chromeos::TYPE_VPN: | |
| 331 case chromeos::TYPE_UNKNOWN: | |
| 332 break; | |
| 333 } | |
| 334 return net::NetworkChangeNotifier::CONNECTION_UNKNOWN; | |
| 335 } | |
| 336 | |
| 337 // static | |
| 338 net::NetworkChangeNotifier::NetworkChangeCalculatorParams | |
| 339 NetworkChangeNotifierChromeos::NetworkChangeCalculatorParamsChromeos() { | |
| 340 NetworkChangeCalculatorParams params; | |
| 341 // Delay values arrived at by simple experimentation and adjusted so as to | |
| 342 // produce a single signal when switching between network connections. | |
| 343 params.ip_address_offline_delay_ = base::TimeDelta::FromMilliseconds(4000); | |
| 344 params.ip_address_online_delay_ = base::TimeDelta::FromMilliseconds(1000); | |
| 345 params.connection_type_offline_delay_ = base::TimeDelta::FromMilliseconds(0); | |
| 346 params.connection_type_online_delay_ = base::TimeDelta::FromMilliseconds(0); | |
| 347 return params; | |
| 348 } | |
| 349 | |
| 350 } // namespace chromeos | |
| OLD | NEW |