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/mobile/mobile_activator.h" 6 7 #include <algorithm> 8 #include <map> 9 #include <string> 10 11 #include "ash/system/chromeos/network/network_connect.h" 12 #include "base/bind.h" 13 #include "base/bind_helpers.h" 14 #include "base/files/file_util.h" 15 #include "base/json/json_reader.h" 16 #include "base/location.h" 17 #include "base/logging.h" 18 #include "base/memory/ref_counted_memory.h" 19 #include "base/message_loop/message_loop.h" 20 #include "base/metrics/histogram.h" 21 #include "base/observer_list_threadsafe.h" 22 #include "base/prefs/pref_service.h" 23 #include "base/strings/string_piece.h" 24 #include "base/strings/string_util.h" 25 #include "base/strings/utf_string_conversions.h" 26 #include "base/timer/timer.h" 27 #include "base/values.h" 28 #include "chrome/browser/browser_process.h" 29 #include "chrome/common/pref_names.h" 30 #include "chromeos/network/device_state.h" 31 #include "chromeos/network/network_activation_handler.h" 32 #include "chromeos/network/network_configuration_handler.h" 33 #include "chromeos/network/network_connection_handler.h" 34 #include "chromeos/network/network_event_log.h" 35 #include "chromeos/network/network_handler_callbacks.h" 36 #include "chromeos/network/network_state.h" 37 #include "chromeos/network/network_state_handler.h" 38 #include "content/public/browser/browser_thread.h" 39 #include "third_party/cros_system_api/dbus/service_constants.h" 40 41 using content::BrowserThread; 42 43 namespace { 44 45 // Cellular configuration file path. 46 const char kCellularConfigPath[] = 47 "/usr/share/chromeos-assets/mobile/mobile_config.json"; 48 49 // Cellular config file field names. 50 const char kVersionField[] = "version"; 51 const char kErrorsField[] = "errors"; 52 53 // Number of times we'll try an OTASP before failing the activation process. 54 const int kMaxOTASPTries = 3; 55 // Number of times we will retry to reconnect and reload payment portal page. 56 const int kMaxPortalReconnectCount = 2; 57 // Time between connection attempts when forcing a reconnect. 58 const int kReconnectDelayMS = 3000; 59 // Retry delay after failed OTASP attempt. 60 const int kOTASPRetryDelay = 40000; 61 // Maximum amount of time we'll wait for a service to reconnect. 62 const int kMaxReconnectTime = 30000; 63 64 // Error codes matching codes defined in the cellular config file. 65 const char kErrorDefault[] = "default"; 66 const char kErrorBadConnectionPartial[] = "bad_connection_partial"; 67 const char kErrorBadConnectionActivated[] = "bad_connection_activated"; 68 const char kErrorRoamingOnConnection[] = "roaming_connection"; 69 const char kErrorNoEVDO[] = "no_evdo"; 70 const char kErrorRoamingActivation[] = "roaming_activation"; 71 const char kErrorRoamingPartiallyActivated[] = "roaming_partially_activated"; 72 const char kErrorNoService[] = "no_service"; 73 const char kErrorDisabled[] = "disabled"; 74 const char kErrorNoDevice[] = "no_device"; 75 const char kFailedPaymentError[] = "failed_payment"; 76 const char kFailedConnectivity[] = "connectivity"; 77 78 // Returns true if the device follows the simple activation flow. 79 bool IsSimpleActivationFlow(const chromeos::NetworkState* network) { 80 return (network->activation_type() == shill::kActivationTypeNonCellular || 81 network->activation_type() == shill::kActivationTypeOTA); 82 } 83 84 } // namespace 85 86 namespace chromeos { 87 88 //////////////////////////////////////////////////////////////////////////////// 89 // 90 // CellularConfigDocument 91 // 92 //////////////////////////////////////////////////////////////////////////////// 93 CellularConfigDocument::CellularConfigDocument() {} 94 95 std::string CellularConfigDocument::GetErrorMessage(const std::string& code) { 96 base::AutoLock create(config_lock_); 97 ErrorMap::iterator iter = error_map_.find(code); 98 if (iter == error_map_.end()) 99 return code; 100 return iter->second; 101 } 102 103 void CellularConfigDocument::LoadCellularConfigFile() { 104 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); 105 // Load partner customization startup manifest if it is available. 106 base::FilePath config_path(kCellularConfigPath); 107 if (!base::PathExists(config_path)) 108 return; 109 110 if (LoadFromFile(config_path)) 111 DVLOG(1) << "Cellular config file loaded: " << kCellularConfigPath; 112 else 113 LOG(ERROR) << "Error loading cellular config file: " << kCellularConfigPath; 114 } 115 116 CellularConfigDocument::~CellularConfigDocument() {} 117 118 void CellularConfigDocument::SetErrorMap( 119 const ErrorMap& map) { 120 base::AutoLock create(config_lock_); 121 error_map_.clear(); 122 error_map_.insert(map.begin(), map.end()); 123 } 124 125 bool CellularConfigDocument::LoadFromFile(const base::FilePath& config_path) { 126 std::string config; 127 if (!base::ReadFileToString(config_path, &config)) 128 return false; 129 130 scoped_ptr<base::Value> root( 131 base::JSONReader::Read(config, base::JSON_ALLOW_TRAILING_COMMAS)); 132 DCHECK(root.get() != NULL); 133 if (!root.get() || root->GetType() != base::Value::TYPE_DICTIONARY) { 134 LOG(WARNING) << "Bad cellular config file"; 135 return false; 136 } 137 138 base::DictionaryValue* root_dict = 139 static_cast<base::DictionaryValue*>(root.get()); 140 if (!root_dict->GetString(kVersionField, &version_)) { 141 LOG(WARNING) << "Cellular config file missing version"; 142 return false; 143 } 144 ErrorMap error_map; 145 base::DictionaryValue* errors = NULL; 146 if (!root_dict->GetDictionary(kErrorsField, &errors)) 147 return false; 148 for (base::DictionaryValue::Iterator it(*errors); 149 !it.IsAtEnd(); it.Advance()) { 150 std::string value; 151 if (!it.value().GetAsString(&value)) { 152 LOG(WARNING) << "Bad cellular config error value"; 153 return false; 154 } 155 error_map.insert(ErrorMap::value_type(it.key(), value)); 156 } 157 SetErrorMap(error_map); 158 return true; 159 } 160 161 //////////////////////////////////////////////////////////////////////////////// 162 // 163 // MobileActivator 164 // 165 //////////////////////////////////////////////////////////////////////////////// 166 MobileActivator::MobileActivator() 167 : cellular_config_(new CellularConfigDocument()), 168 state_(PLAN_ACTIVATION_PAGE_LOADING), 169 reenable_cert_check_(false), 170 terminated_(true), 171 pending_activation_request_(false), 172 connection_retry_count_(0), 173 initial_OTASP_attempts_(0), 174 trying_OTASP_attempts_(0), 175 final_OTASP_attempts_(0), 176 payment_reconnect_count_(0), 177 weak_ptr_factory_(this) { 178 } 179 180 MobileActivator::~MobileActivator() { 181 TerminateActivation(); 182 } 183 184 MobileActivator* MobileActivator::GetInstance() { 185 return Singleton<MobileActivator>::get(); 186 } 187 188 void MobileActivator::TerminateActivation() { 189 state_duration_timer_.Stop(); 190 continue_reconnect_timer_.Stop(); 191 reconnect_timeout_timer_.Stop(); 192 193 if (NetworkHandler::IsInitialized()) { 194 NetworkHandler::Get()->network_state_handler()-> 195 RemoveObserver(this, FROM_HERE); 196 } 197 ReEnableCertRevocationChecking(); 198 meid_.clear(); 199 iccid_.clear(); 200 service_path_.clear(); 201 device_path_.clear(); 202 state_ = PLAN_ACTIVATION_PAGE_LOADING; 203 reenable_cert_check_ = false; 204 terminated_ = true; 205 // Release the previous cellular config and setup a new empty one. 206 cellular_config_ = new CellularConfigDocument(); 207 } 208 209 void MobileActivator::DefaultNetworkChanged(const NetworkState* network) { 210 RefreshCellularNetworks(); 211 } 212 213 void MobileActivator::NetworkPropertiesUpdated(const NetworkState* network) { 214 if (state_ == PLAN_ACTIVATION_PAGE_LOADING) 215 return; 216 217 if (!network || network->type() != shill::kTypeCellular) 218 return; 219 220 const DeviceState* device = NetworkHandler::Get()->network_state_handler()-> 221 GetDeviceState(network->device_path()); 222 if (!device) { 223 LOG(ERROR) << "Cellular device can't be found: " << network->device_path(); 224 return; 225 } 226 if (network->device_path() != device_path_) { 227 LOG(WARNING) << "Ignoring property update for cellular service " 228 << network->path() 229 << " on unknown device " << network->device_path() 230 << " (Stored device path = " << device_path_ << ")"; 231 return; 232 } 233 234 // A modem reset leads to a new service path. Since we have verified that we 235 // are a cellular service on a still valid stored device path, update it. 236 service_path_ = network->path(); 237 238 EvaluateCellularNetwork(network); 239 } 240 241 void MobileActivator::AddObserver(MobileActivator::Observer* observer) { 242 DCHECK(content::BrowserThread::CurrentlyOn(BrowserThread::UI)); 243 observers_.AddObserver(observer); 244 } 245 246 void MobileActivator::RemoveObserver(MobileActivator::Observer* observer) { 247 DCHECK(content::BrowserThread::CurrentlyOn(BrowserThread::UI)); 248 observers_.RemoveObserver(observer); 249 } 250 251 void MobileActivator::InitiateActivation(const std::string& service_path) { 252 DCHECK(content::BrowserThread::CurrentlyOn(BrowserThread::UI)); 253 const NetworkState* network = GetNetworkState(service_path); 254 if (!network) { 255 LOG(WARNING) << "Cellular service can't be found: " << service_path; 256 return; 257 } 258 const DeviceState* device = NetworkHandler::Get()->network_state_handler()-> 259 GetDeviceState(network->device_path()); 260 if (!device) { 261 LOG(ERROR) << "Cellular device can't be found: " << network->device_path(); 262 return; 263 } 264 265 terminated_ = false; 266 meid_ = device->meid(); 267 iccid_ = device->iccid(); 268 service_path_ = service_path; 269 device_path_ = network->device_path(); 270 271 ChangeState(network, PLAN_ACTIVATION_PAGE_LOADING, ""); 272 273 BrowserThread::PostTaskAndReply(BrowserThread::FILE, FROM_HERE, 274 base::Bind(&CellularConfigDocument::LoadCellularConfigFile, 275 cellular_config_.get()), 276 base::Bind(&MobileActivator::ContinueActivation, AsWeakPtr())); 277 } 278 279 void MobileActivator::ContinueActivation() { 280 NetworkHandler::Get()->network_configuration_handler()->GetProperties( 281 service_path_, 282 base::Bind(&MobileActivator::GetPropertiesAndContinueActivation, 283 weak_ptr_factory_.GetWeakPtr()), 284 base::Bind(&MobileActivator::GetPropertiesFailure, 285 weak_ptr_factory_.GetWeakPtr())); 286 } 287 288 void MobileActivator::GetPropertiesAndContinueActivation( 289 const std::string& service_path, 290 const base::DictionaryValue& properties) { 291 if (service_path != service_path_) { 292 NET_LOG_EVENT("MobileActivator::GetProperties received for stale network", 293 service_path); 294 return; // Edge case; abort. 295 } 296 const base::DictionaryValue* payment_dict; 297 std::string usage_url, payment_url; 298 if (!properties.GetStringWithoutPathExpansion( 299 shill::kUsageURLProperty, &usage_url) || 300 !properties.GetDictionaryWithoutPathExpansion( 301 shill::kPaymentPortalProperty, &payment_dict) || 302 !payment_dict->GetStringWithoutPathExpansion( 303 shill::kPaymentPortalURL, &payment_url)) { 304 NET_LOG_ERROR("MobileActivator missing properties", service_path_); 305 return; 306 } 307 308 if (payment_url.empty() && usage_url.empty()) 309 return; 310 311 DisableCertRevocationChecking(); 312 313 // We want shill to connect us after activations, so enable autoconnect. 314 base::DictionaryValue auto_connect_property; 315 auto_connect_property.SetBoolean(shill::kAutoConnectProperty, true); 316 NetworkHandler::Get()->network_configuration_handler()->SetProperties( 317 service_path_, 318 auto_connect_property, 319 base::Bind(&base::DoNothing), 320 network_handler::ErrorCallback()); 321 StartActivation(); 322 } 323 324 void MobileActivator::GetPropertiesFailure( 325 const std::string& error_name, 326 scoped_ptr<base::DictionaryValue> error_data) { 327 NET_LOG_ERROR("MobileActivator GetProperties Failed: " + error_name, 328 service_path_); 329 } 330 331 void MobileActivator::OnSetTransactionStatus(bool success) { 332 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, 333 base::Bind(&MobileActivator::HandleSetTransactionStatus, 334 AsWeakPtr(), success)); 335 } 336 337 void MobileActivator::HandleSetTransactionStatus(bool success) { 338 // The payment is received, try to reconnect and check the status all over 339 // again. 340 if (success && state_ == PLAN_ACTIVATION_SHOWING_PAYMENT) { 341 SignalCellularPlanPayment(); 342 UMA_HISTOGRAM_COUNTS("Cellular.PaymentReceived", 1); 343 const NetworkState* network = GetNetworkState(service_path_); 344 if (network && IsSimpleActivationFlow(network)) { 345 state_ = PLAN_ACTIVATION_DONE; 346 NetworkHandler::Get()->network_activation_handler()-> 347 CompleteActivation(network->path(), 348 base::Bind(&base::DoNothing), 349 network_handler::ErrorCallback()); 350 } else { 351 StartOTASP(); 352 } 353 } else { 354 UMA_HISTOGRAM_COUNTS("Cellular.PaymentFailed", 1); 355 } 356 } 357 358 void MobileActivator::OnPortalLoaded(bool success) { 359 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, 360 base::Bind(&MobileActivator::HandlePortalLoaded, 361 AsWeakPtr(), success)); 362 } 363 364 void MobileActivator::HandlePortalLoaded(bool success) { 365 const NetworkState* network = GetNetworkState(service_path_); 366 if (!network) { 367 ChangeState(NULL, PLAN_ACTIVATION_ERROR, 368 GetErrorMessage(kErrorNoService)); 369 return; 370 } 371 if (state_ == PLAN_ACTIVATION_PAYMENT_PORTAL_LOADING || 372 state_ == PLAN_ACTIVATION_SHOWING_PAYMENT) { 373 if (success) { 374 payment_reconnect_count_ = 0; 375 ChangeState(network, PLAN_ACTIVATION_SHOWING_PAYMENT, std::string()); 376 } else { 377 // There is no point in forcing reconnecting the cellular network if the 378 // activation should not be done over it. 379 if (network->activation_type() == shill::kActivationTypeNonCellular) 380 return; 381 382 payment_reconnect_count_++; 383 if (payment_reconnect_count_ > kMaxPortalReconnectCount) { 384 ChangeState(NULL, PLAN_ACTIVATION_ERROR, 385 GetErrorMessage(kErrorNoService)); 386 return; 387 } 388 389 // Reconnect and try and load the frame again. 390 ChangeState(network, 391 PLAN_ACTIVATION_RECONNECTING, 392 GetErrorMessage(kFailedPaymentError)); 393 } 394 } else { 395 NOTREACHED() << "Called paymentPortalLoad while in unexpected state: " 396 << GetStateDescription(state_); 397 } 398 } 399 400 void MobileActivator::StartOTASPTimer() { 401 pending_activation_request_ = false; 402 state_duration_timer_.Start( 403 FROM_HERE, 404 base::TimeDelta::FromMilliseconds(kOTASPRetryDelay), 405 this, &MobileActivator::HandleOTASPTimeout); 406 } 407 408 void MobileActivator::StartActivation() { 409 UMA_HISTOGRAM_COUNTS("Cellular.MobileSetupStart", 1); 410 const NetworkState* network = GetNetworkState(service_path_); 411 // Check if we can start activation process. 412 if (!network) { 413 NetworkStateHandler::TechnologyState technology_state = 414 NetworkHandler::Get()->network_state_handler()->GetTechnologyState( 415 NetworkTypePattern::Cellular()); 416 std::string error; 417 if (technology_state == NetworkStateHandler::TECHNOLOGY_UNAVAILABLE) { 418 error = kErrorNoDevice; 419 } else if (technology_state != NetworkStateHandler::TECHNOLOGY_ENABLED) { 420 error = kErrorDisabled; 421 } else { 422 error = kErrorNoService; 423 } 424 ChangeState(NULL, PLAN_ACTIVATION_ERROR, GetErrorMessage(error)); 425 return; 426 } 427 428 // Start monitoring network property changes. 429 NetworkHandler::Get()->network_state_handler()->AddObserver(this, FROM_HERE); 430 431 if (network->activation_type() == shill::kActivationTypeNonCellular) 432 StartActivationOverNonCellularNetwork(); 433 else if (network->activation_type() == shill::kActivationTypeOTA) 434 StartActivationOTA(); 435 else if (network->activation_type() == shill::kActivationTypeOTASP) 436 StartActivationOTASP(); 437 } 438 439 void MobileActivator::StartActivationOverNonCellularNetwork() { 440 // Fast forward to payment portal loading. 441 const NetworkState* network = GetNetworkState(service_path_); 442 if (!network) { 443 LOG(WARNING) << "Cellular service can't be found: " << service_path_; 444 return; 445 } 446 447 ChangeState( 448 network, 449 (network->activation_state() == shill::kActivationStateActivated) ? 450 PLAN_ACTIVATION_DONE : 451 PLAN_ACTIVATION_PAYMENT_PORTAL_LOADING, 452 "" /* error_description */); 453 454 RefreshCellularNetworks(); 455 } 456 457 void MobileActivator::StartActivationOTA() { 458 // Connect to the network if we don't currently have access. 459 const NetworkState* network = GetNetworkState(service_path_); 460 if (!network) { 461 LOG(WARNING) << "Cellular service can't be found: " << service_path_; 462 return; 463 } 464 465 const NetworkState* default_network = GetDefaultNetwork(); 466 bool is_online_or_portal = default_network && 467 (default_network->connection_state() == shill::kStateOnline || 468 default_network->connection_state() == shill::kStatePortal); 469 if (!is_online_or_portal) 470 ConnectNetwork(network); 471 472 ChangeState(network, PLAN_ACTIVATION_PAYMENT_PORTAL_LOADING, 473 "" /* error_description */); 474 RefreshCellularNetworks(); 475 } 476 477 void MobileActivator::StartActivationOTASP() { 478 const NetworkState* network = GetNetworkState(service_path_); 479 if (!network) { 480 LOG(WARNING) << "Cellular service can't be found: " << service_path_; 481 return; 482 } 483 484 if (HasRecentCellularPlanPayment() && 485 (network->activation_state() == 486 shill::kActivationStatePartiallyActivated)) { 487 // Try to start with OTASP immediately if we have received payment recently. 488 state_ = PLAN_ACTIVATION_START_OTASP; 489 } else { 490 state_ = PLAN_ACTIVATION_START; 491 } 492 493 EvaluateCellularNetwork(network); 494 } 495 496 void MobileActivator::RetryOTASP() { 497 DCHECK(state_ == PLAN_ACTIVATION_DELAY_OTASP); 498 StartOTASP(); 499 } 500 501 void MobileActivator::StartOTASP() { 502 const NetworkState* network = GetNetworkState(service_path_); 503 if (!network) { 504 LOG(WARNING) << "Cellular service can't be found: " << service_path_; 505 return; 506 } 507 508 ChangeState(network, PLAN_ACTIVATION_START_OTASP, std::string()); 509 EvaluateCellularNetwork(network); 510 } 511 512 void MobileActivator::HandleOTASPTimeout() { 513 LOG(WARNING) << "OTASP seems to be taking too long."; 514 const NetworkState* network = GetNetworkState(service_path_); 515 if (!network) { 516 LOG(WARNING) << "Cellular service can't be found: " << service_path_; 517 return; 518 } 519 520 // We're here because one of OTASP steps is taking too long to complete. 521 // Usually, this means something bad has happened below us. 522 if (state_ == PLAN_ACTIVATION_INITIATING_ACTIVATION) { 523 ++initial_OTASP_attempts_; 524 if (initial_OTASP_attempts_ <= kMaxOTASPTries) { 525 ChangeState(network, 526 PLAN_ACTIVATION_RECONNECTING, 527 GetErrorMessage(kErrorDefault)); 528 return; 529 } 530 } else if (state_ == PLAN_ACTIVATION_TRYING_OTASP) { 531 ++trying_OTASP_attempts_; 532 if (trying_OTASP_attempts_ <= kMaxOTASPTries) { 533 ChangeState(network, 534 PLAN_ACTIVATION_RECONNECTING, 535 GetErrorMessage(kErrorDefault)); 536 return; 537 } 538 } else if (state_ == PLAN_ACTIVATION_OTASP) { 539 ++final_OTASP_attempts_; 540 if (final_OTASP_attempts_ <= kMaxOTASPTries) { 541 // Give the portal time to propagate all those magic bits. 542 ChangeState(network, 543 PLAN_ACTIVATION_DELAY_OTASP, 544 GetErrorMessage(kErrorDefault)); 545 return; 546 } 547 } else { 548 LOG(ERROR) << "OTASP timed out from a non-OTASP wait state?"; 549 } 550 LOG(ERROR) << "OTASP failed too many times; aborting."; 551 ChangeState(network, 552 PLAN_ACTIVATION_ERROR, 553 GetErrorMessage(kErrorDefault)); 554 } 555 556 void MobileActivator::ConnectNetwork(const NetworkState* network) { 557 NetworkHandler::Get()->network_connection_handler()->ConnectToNetwork( 558 network->path(), 559 base::Bind(&base::DoNothing), 560 network_handler::ErrorCallback(), 561 false /* check_error_state */); 562 } 563 564 void MobileActivator::ForceReconnect(const NetworkState* network, 565 PlanActivationState next_state) { 566 DCHECK(network); 567 // Store away our next destination for when we complete. 568 post_reconnect_state_ = next_state; 569 UMA_HISTOGRAM_COUNTS("Cellular.ActivationRetry", 1); 570 // First, disconnect... 571 VLOG(1) << "Disconnecting from " << network->path(); 572 // Explicit service Disconnect()s disable autoconnect on the service until 573 // Connect() is called on the service again. Hence this dance to explicitly 574 // call Connect(). 575 NetworkHandler::Get()->network_connection_handler()->DisconnectNetwork( 576 network->path(), 577 base::Bind(&base::DoNothing), 578 network_handler::ErrorCallback()); 579 // Keep trying to connect until told otherwise. 580 continue_reconnect_timer_.Stop(); 581 continue_reconnect_timer_.Start( 582 FROM_HERE, 583 base::TimeDelta::FromMilliseconds(kReconnectDelayMS), 584 this, &MobileActivator::ContinueConnecting); 585 // If we don't ever connect again, we're going to call this a failure. 586 reconnect_timeout_timer_.Stop(); 587 reconnect_timeout_timer_.Start( 588 FROM_HERE, 589 base::TimeDelta::FromMilliseconds(kMaxReconnectTime), 590 this, &MobileActivator::ReconnectTimedOut); 591 } 592 593 void MobileActivator::ReconnectTimedOut() { 594 LOG(ERROR) << "Ending activation attempt after failing to reconnect."; 595 const NetworkState* network = GetNetworkState(service_path_); 596 if (!network) { 597 LOG(WARNING) << "Cellular service can't be found: " << service_path_; 598 return; 599 } 600 601 ChangeState(network, 602 PLAN_ACTIVATION_ERROR, 603 GetErrorMessage(kFailedConnectivity)); 604 } 605 606 void MobileActivator::ContinueConnecting() { 607 const NetworkState* network = GetNetworkState(service_path_); 608 if (network && network->IsConnectedState()) { 609 if (network->connection_state() == shill::kStatePortal && 610 network->error() == shill::kErrorDNSLookupFailed) { 611 // It isn't an error to be in a restricted pool, but if DNS doesn't work, 612 // then we're not getting traffic through at all. Just disconnect and 613 // try again. 614 NetworkHandler::Get()->network_connection_handler()->DisconnectNetwork( 615 network->path(), 616 base::Bind(&base::DoNothing), 617 network_handler::ErrorCallback()); 618 return; 619 } 620 // Stop this callback 621 continue_reconnect_timer_.Stop(); 622 EvaluateCellularNetwork(network); 623 } else { 624 LOG(WARNING) << "Connect failed, will try again in a little bit."; 625 if (network) { 626 VLOG(1) << "Connecting to: " << network->path(); 627 ash::network_connect::ConnectToNetwork(network->path()); 628 } 629 } 630 } 631 632 void MobileActivator::RefreshCellularNetworks() { 633 if (state_ == PLAN_ACTIVATION_PAGE_LOADING || 634 state_ == PLAN_ACTIVATION_DONE || 635 state_ == PLAN_ACTIVATION_ERROR) { 636 return; 637 } 638 639 const NetworkState* network = GetNetworkState(service_path_); 640 if (!network) { 641 LOG(WARNING) << "Cellular service can't be found: " << service_path_; 642 return; 643 } 644 645 if (IsSimpleActivationFlow(network)) { 646 bool waiting = (state_ == PLAN_ACTIVATION_WAITING_FOR_CONNECTION); 647 // We're only interested in whether or not we have access to the payment 648 // portal (regardless of which network we use to access it), so check 649 // the default network connection state. The default network is the network 650 // used to route default traffic. Also, note that we can access the 651 // payment portal over a cellular network in the portalled state. 652 const NetworkState* default_network = GetDefaultNetwork(); 653 bool is_online_or_portal = default_network && 654 (default_network->connection_state() == shill::kStateOnline || 655 (default_network->type() == shill::kTypeCellular && 656 default_network->connection_state() == shill::kStatePortal)); 657 if (waiting && is_online_or_portal) { 658 ChangeState(network, post_reconnect_state_, ""); 659 } else if (!waiting && !is_online_or_portal) { 660 ChangeState(network, PLAN_ACTIVATION_WAITING_FOR_CONNECTION, ""); 661 } 662 } 663 664 EvaluateCellularNetwork(network); 665 } 666 667 const NetworkState* MobileActivator::GetNetworkState( 668 const std::string& service_path) { 669 return NetworkHandler::Get()->network_state_handler()->GetNetworkState( 670 service_path); 671 } 672 673 const NetworkState* MobileActivator::GetDefaultNetwork() { 674 return NetworkHandler::Get()->network_state_handler()->DefaultNetwork(); 675 } 676 677 void MobileActivator::EvaluateCellularNetwork(const NetworkState* network) { 678 if (terminated_) { 679 LOG(ERROR) << "Tried to run MobileActivator state machine while " 680 << "terminated."; 681 return; 682 } 683 684 if (!network) { 685 LOG(WARNING) << "Cellular service lost"; 686 return; 687 } 688 689 LOG(WARNING) << "Cellular:\n service state=" << network->connection_state() 690 << "\n ui=" << GetStateDescription(state_) 691 << "\n activation=" << network->activation_state() 692 << "\n error=" << network->error() 693 << "\n setvice_path=" << network->path() 694 << "\n connected=" << network->IsConnectedState(); 695 696 // If the network is activated over non cellular network or OTA, the 697 // activator state does not depend on the network's own state. 698 if (IsSimpleActivationFlow(network)) 699 return; 700 701 std::string error_description; 702 PlanActivationState new_state = PickNextState(network, &error_description); 703 704 ChangeState(network, new_state, error_description); 705 } 706 707 MobileActivator::PlanActivationState MobileActivator::PickNextState( 708 const NetworkState* network, std::string* error_description) const { 709 PlanActivationState new_state = state_; 710 if (!network->IsConnectedState()) 711 new_state = PickNextOfflineState(network); 712 else 713 new_state = PickNextOnlineState(network); 714 if (new_state != PLAN_ACTIVATION_ERROR && 715 GotActivationError(network, error_description)) { 716 // Check for this special case when we try to do activate partially 717 // activated device. If that attempt failed, try to disconnect to clear the 718 // state and reconnect again. 719 const std::string& activation = network->activation_state(); 720 if ((activation == shill::kActivationStatePartiallyActivated || 721 activation == shill::kActivationStateActivating) && 722 (network->error().empty() || 723 network->error() == shill::kErrorOtaspFailed) && 724 network->connection_state() == shill::kStateActivationFailure) { 725 NET_LOG_EVENT("Activation failure detected ", network->path()); 726 switch (state_) { 727 case PLAN_ACTIVATION_OTASP: 728 new_state = PLAN_ACTIVATION_DELAY_OTASP; 729 break; 730 case PLAN_ACTIVATION_INITIATING_ACTIVATION: 731 case PLAN_ACTIVATION_TRYING_OTASP: 732 new_state = PLAN_ACTIVATION_START; 733 break; 734 case PLAN_ACTIVATION_START: 735 // We are just starting, so this must be previous activation attempt 736 // failure. 737 new_state = PLAN_ACTIVATION_TRYING_OTASP; 738 break; 739 case PLAN_ACTIVATION_DELAY_OTASP: 740 new_state = state_; 741 break; 742 default: 743 new_state = PLAN_ACTIVATION_ERROR; 744 break; 745 } 746 } else { 747 LOG(WARNING) << "Unexpected activation failure for " << network->path(); 748 new_state = PLAN_ACTIVATION_ERROR; 749 } 750 } 751 752 if (new_state == PLAN_ACTIVATION_ERROR && !error_description->length()) 753 *error_description = GetErrorMessage(kErrorDefault); 754 return new_state; 755 } 756 757 MobileActivator::PlanActivationState MobileActivator::PickNextOfflineState( 758 const NetworkState* network) const { 759 PlanActivationState new_state = state_; 760 const std::string& activation = network->activation_state(); 761 switch (state_) { 762 case PLAN_ACTIVATION_PAYMENT_PORTAL_LOADING: 763 case PLAN_ACTIVATION_SHOWING_PAYMENT: 764 if (!IsSimpleActivationFlow(network)) 765 new_state = PLAN_ACTIVATION_RECONNECTING; 766 break; 767 case PLAN_ACTIVATION_START: 768 if (activation == shill::kActivationStateActivated) { 769 if (network->connection_state() == shill::kStatePortal) 770 new_state = PLAN_ACTIVATION_PAYMENT_PORTAL_LOADING; 771 else 772 new_state = PLAN_ACTIVATION_DONE; 773 } else if (activation == shill::kActivationStatePartiallyActivated) { 774 new_state = PLAN_ACTIVATION_TRYING_OTASP; 775 } else { 776 new_state = PLAN_ACTIVATION_INITIATING_ACTIVATION; 777 } 778 break; 779 default: 780 VLOG(1) << "Waiting for cellular service to connect."; 781 break; 782 } 783 return new_state; 784 } 785 786 MobileActivator::PlanActivationState MobileActivator::PickNextOnlineState( 787 const NetworkState* network) const { 788 PlanActivationState new_state = state_; 789 const std::string& activation = network->activation_state(); 790 switch (state_) { 791 case PLAN_ACTIVATION_START: 792 if (activation == shill::kActivationStateActivated) { 793 if (network->connection_state() == shill::kStateOnline) 794 new_state = PLAN_ACTIVATION_DONE; 795 else 796 new_state = PLAN_ACTIVATION_PAYMENT_PORTAL_LOADING; 797 } else if (activation == shill::kActivationStatePartiallyActivated) { 798 new_state = PLAN_ACTIVATION_TRYING_OTASP; 799 } else { 800 new_state = PLAN_ACTIVATION_INITIATING_ACTIVATION; 801 } 802 break; 803 case PLAN_ACTIVATION_START_OTASP: { 804 if (activation == shill::kActivationStatePartiallyActivated) { 805 new_state = PLAN_ACTIVATION_OTASP; 806 } else if (activation == shill::kActivationStateActivated) { 807 new_state = PLAN_ACTIVATION_RECONNECTING; 808 } else { 809 LOG(WARNING) << "Unexpected activation state for device " 810 << network->path(); 811 } 812 break; 813 } 814 case PLAN_ACTIVATION_DELAY_OTASP: 815 // Just ignore any changes until the OTASP retry timer kicks in. 816 break; 817 case PLAN_ACTIVATION_INITIATING_ACTIVATION: { 818 if (pending_activation_request_) { 819 VLOG(1) << "Waiting for pending activation attempt to finish"; 820 } else if (activation == shill::kActivationStateActivated || 821 activation == shill::kActivationStatePartiallyActivated) { 822 new_state = PLAN_ACTIVATION_START; 823 } else if (activation == shill::kActivationStateNotActivated || 824 activation == shill::kActivationStateActivating) { 825 // Wait in this state until activation state changes. 826 } else { 827 LOG(WARNING) << "Unknown transition"; 828 } 829 break; 830 } 831 case PLAN_ACTIVATION_OTASP: 832 case PLAN_ACTIVATION_TRYING_OTASP: 833 if (pending_activation_request_) { 834 VLOG(1) << "Waiting for pending activation attempt to finish"; 835 } else if (activation == shill::kActivationStateNotActivated || 836 activation == shill::kActivationStateActivating) { 837 VLOG(1) << "Waiting for the OTASP to finish and the service to " 838 << "come back online"; 839 } else if (activation == shill::kActivationStateActivated) { 840 new_state = PLAN_ACTIVATION_DONE; 841 } else { 842 new_state = PLAN_ACTIVATION_PAYMENT_PORTAL_LOADING; 843 } 844 break; 845 case PLAN_ACTIVATION_RECONNECTING_PAYMENT: 846 if (network->connection_state() != shill::kStatePortal && 847 activation == shill::kActivationStateActivated) 848 // We're not portalled, and we're already activated, so we're online! 849 new_state = PLAN_ACTIVATION_DONE; 850 else 851 new_state = PLAN_ACTIVATION_PAYMENT_PORTAL_LOADING; 852 break; 853 // Initial state 854 case PLAN_ACTIVATION_PAGE_LOADING: 855 break; 856 // Just ignore all signals until the site confirms payment. 857 case PLAN_ACTIVATION_PAYMENT_PORTAL_LOADING: 858 case PLAN_ACTIVATION_SHOWING_PAYMENT: 859 case PLAN_ACTIVATION_WAITING_FOR_CONNECTION: 860 break; 861 // Go where we decided earlier. 862 case PLAN_ACTIVATION_RECONNECTING: 863 new_state = post_reconnect_state_; 864 break; 865 // Activation completed/failed, ignore network changes. 866 case PLAN_ACTIVATION_DONE: 867 case PLAN_ACTIVATION_ERROR: 868 break; 869 } 870 871 return new_state; 872 } 873 874 // Debugging helper function, will take it out at the end. 875 const char* MobileActivator::GetStateDescription(PlanActivationState state) { 876 switch (state) { 877 case PLAN_ACTIVATION_PAGE_LOADING: 878 return "PAGE_LOADING"; 879 case PLAN_ACTIVATION_START: 880 return "ACTIVATION_START"; 881 case PLAN_ACTIVATION_INITIATING_ACTIVATION: 882 return "INITIATING_ACTIVATION"; 883 case PLAN_ACTIVATION_TRYING_OTASP: 884 return "TRYING_OTASP"; 885 case PLAN_ACTIVATION_PAYMENT_PORTAL_LOADING: 886 return "PAYMENT_PORTAL_LOADING"; 887 case PLAN_ACTIVATION_SHOWING_PAYMENT: 888 return "SHOWING_PAYMENT"; 889 case PLAN_ACTIVATION_RECONNECTING_PAYMENT: 890 return "RECONNECTING_PAYMENT"; 891 case PLAN_ACTIVATION_DELAY_OTASP: 892 return "DELAY_OTASP"; 893 case PLAN_ACTIVATION_START_OTASP: 894 return "START_OTASP"; 895 case PLAN_ACTIVATION_OTASP: 896 return "OTASP"; 897 case PLAN_ACTIVATION_DONE: 898 return "DONE"; 899 case PLAN_ACTIVATION_ERROR: 900 return "ERROR"; 901 case PLAN_ACTIVATION_RECONNECTING: 902 return "RECONNECTING"; 903 case PLAN_ACTIVATION_WAITING_FOR_CONNECTION: 904 return "WAITING FOR CONNECTION"; 905 } 906 return "UNKNOWN"; 907 } 908 909 910 void MobileActivator::CompleteActivation() { 911 // Remove observers, we are done with this page. 912 NetworkHandler::Get()->network_state_handler()-> 913 RemoveObserver(this, FROM_HERE); 914 915 // Reactivate other types of connections if we have 916 // shut them down previously. 917 ReEnableCertRevocationChecking(); 918 } 919 920 bool MobileActivator::RunningActivation() const { 921 return !(state_ == PLAN_ACTIVATION_DONE || 922 state_ == PLAN_ACTIVATION_ERROR || 923 state_ == PLAN_ACTIVATION_PAGE_LOADING); 924 } 925 926 void MobileActivator::HandleActivationFailure( 927 const std::string& service_path, 928 PlanActivationState new_state, 929 const std::string& error_name, 930 scoped_ptr<base::DictionaryValue> error_data) { 931 pending_activation_request_ = false; 932 const NetworkState* network = GetNetworkState(service_path); 933 if (!network) { 934 NET_LOG_ERROR("Cellular service no longer exists", service_path); 935 return; 936 } 937 UMA_HISTOGRAM_COUNTS("Cellular.ActivationFailure", 1); 938 NET_LOG_ERROR("Failed to call Activate() on service", service_path); 939 if (new_state == PLAN_ACTIVATION_OTASP) { 940 ChangeState(network, PLAN_ACTIVATION_DELAY_OTASP, std::string()); 941 } else { 942 ChangeState(network, 943 PLAN_ACTIVATION_ERROR, 944 GetErrorMessage(kFailedConnectivity)); 945 } 946 } 947 948 void MobileActivator::RequestCellularActivation( 949 const NetworkState* network, 950 const base::Closure& success_callback, 951 const network_handler::ErrorCallback& error_callback) { 952 DCHECK(network); 953 NET_LOG_EVENT("Activating cellular service", network->path()); 954 UMA_HISTOGRAM_COUNTS("Cellular.ActivationTry", 1); 955 pending_activation_request_ = true; 956 NetworkHandler::Get()->network_activation_handler()-> 957 Activate(network->path(), 958 "", // carrier 959 success_callback, 960 error_callback); 961 } 962 963 void MobileActivator::ChangeState(const NetworkState* network, 964 PlanActivationState new_state, 965 std::string error_description) { 966 // Report an error, by transitioning into a PLAN_ACTIVATION_ERROR state with 967 // a "no service" error instead, if no network state is available (e.g. the 968 // cellular service no longer exists) when we are transitioning into certain 969 // plan activation state. 970 if (!network) { 971 switch (new_state) { 972 case PLAN_ACTIVATION_INITIATING_ACTIVATION: 973 case PLAN_ACTIVATION_TRYING_OTASP: 974 case PLAN_ACTIVATION_OTASP: 975 case PLAN_ACTIVATION_DONE: 976 new_state = PLAN_ACTIVATION_ERROR; 977 error_description = GetErrorMessage(kErrorNoService); 978 default: 979 break; 980 } 981 } 982 983 static bool first_time = true; 984 VLOG(1) << "Activation state flip old = " 985 << GetStateDescription(state_) 986 << ", new = " << GetStateDescription(new_state); 987 if (state_ == new_state && !first_time) 988 return; 989 first_time = false; 990 VLOG(1) << "Transitioning..."; 991 992 // Kill all the possible timers and callbacks we might have outstanding. 993 state_duration_timer_.Stop(); 994 continue_reconnect_timer_.Stop(); 995 reconnect_timeout_timer_.Stop(); 996 const PlanActivationState old_state = state_; 997 state_ = new_state; 998 999 // Signal to observers layer that the state is changing. 1000 FOR_EACH_OBSERVER(Observer, observers_, 1001 OnActivationStateChanged(network, state_, error_description)); 1002 1003 // Pick action that should happen on entering the new state. 1004 switch (new_state) { 1005 case PLAN_ACTIVATION_START: 1006 break; 1007 case PLAN_ACTIVATION_DELAY_OTASP: { 1008 UMA_HISTOGRAM_COUNTS("Cellular.RetryOTASP", 1); 1009 BrowserThread::PostDelayedTask(BrowserThread::UI, FROM_HERE, 1010 base::Bind(&MobileActivator::RetryOTASP, AsWeakPtr()), 1011 base::TimeDelta::FromMilliseconds(kOTASPRetryDelay)); 1012 break; 1013 } 1014 case PLAN_ACTIVATION_START_OTASP: 1015 break; 1016 case PLAN_ACTIVATION_INITIATING_ACTIVATION: 1017 case PLAN_ACTIVATION_TRYING_OTASP: 1018 case PLAN_ACTIVATION_OTASP: { 1019 DCHECK(network); 1020 network_handler::ErrorCallback on_activation_error = 1021 base::Bind(&MobileActivator::HandleActivationFailure, AsWeakPtr(), 1022 network->path(), 1023 new_state); 1024 RequestCellularActivation( 1025 network, 1026 base::Bind(&MobileActivator::StartOTASPTimer, AsWeakPtr()), 1027 on_activation_error); 1028 } 1029 break; 1030 case PLAN_ACTIVATION_PAGE_LOADING: 1031 return; 1032 case PLAN_ACTIVATION_PAYMENT_PORTAL_LOADING: 1033 case PLAN_ACTIVATION_SHOWING_PAYMENT: 1034 case PLAN_ACTIVATION_RECONNECTING_PAYMENT: 1035 // Fix for fix SSL for the walled gardens where cert chain verification 1036 // might not work. 1037 break; 1038 case PLAN_ACTIVATION_WAITING_FOR_CONNECTION: 1039 post_reconnect_state_ = old_state; 1040 break; 1041 case PLAN_ACTIVATION_RECONNECTING: { 1042 PlanActivationState next_state = old_state; 1043 // Pick where we want to return to after we reconnect. 1044 switch (old_state) { 1045 case PLAN_ACTIVATION_PAYMENT_PORTAL_LOADING: 1046 case PLAN_ACTIVATION_SHOWING_PAYMENT: 1047 // We decide here what to do next based on the state of the modem. 1048 next_state = PLAN_ACTIVATION_RECONNECTING_PAYMENT; 1049 break; 1050 case PLAN_ACTIVATION_INITIATING_ACTIVATION: 1051 case PLAN_ACTIVATION_TRYING_OTASP: 1052 next_state = PLAN_ACTIVATION_START; 1053 break; 1054 case PLAN_ACTIVATION_START_OTASP: 1055 case PLAN_ACTIVATION_OTASP: 1056 if (!network || !network->IsConnectedState()) { 1057 next_state = PLAN_ACTIVATION_START_OTASP; 1058 } else { 1059 // We're online, which means we've conspired with 1060 // PickNextOnlineState to reconnect after activation (that's the 1061 // only way we see this transition). Thus, after we reconnect, we 1062 // should be done. 1063 next_state = PLAN_ACTIVATION_DONE; 1064 } 1065 break; 1066 default: 1067 LOG(ERROR) << "Transitioned to RECONNECTING from an unexpected " 1068 << "state."; 1069 break; 1070 } 1071 if (network) 1072 ForceReconnect(network, next_state); 1073 break; 1074 } 1075 case PLAN_ACTIVATION_DONE: 1076 DCHECK(network); 1077 CompleteActivation(); 1078 UMA_HISTOGRAM_COUNTS("Cellular.MobileSetupSucceeded", 1); 1079 break; 1080 case PLAN_ACTIVATION_ERROR: 1081 CompleteActivation(); 1082 UMA_HISTOGRAM_COUNTS("Cellular.PlanFailed", 1); 1083 break; 1084 default: 1085 break; 1086 } 1087 } 1088 1089 void MobileActivator::ReEnableCertRevocationChecking() { 1090 // Check that both the browser process and prefs exist before trying to 1091 // use them, since this method can be called by the destructor while Chrome 1092 // is shutting down, during which either could be NULL. 1093 if (!g_browser_process) 1094 return; 1095 PrefService* prefs = g_browser_process->local_state(); 1096 if (!prefs) 1097 return; 1098 if (reenable_cert_check_) { 1099 prefs->SetBoolean(prefs::kCertRevocationCheckingEnabled, 1100 true); 1101 reenable_cert_check_ = false; 1102 } 1103 } 1104 1105 void MobileActivator::DisableCertRevocationChecking() { 1106 // Disable SSL cert checks since we might be performing activation in the 1107 // restricted pool. 1108 // TODO(rkc): We want to do this only if on Cellular. 1109 PrefService* prefs = g_browser_process->local_state(); 1110 if (!reenable_cert_check_ && 1111 prefs->GetBoolean( 1112 prefs::kCertRevocationCheckingEnabled)) { 1113 reenable_cert_check_ = true; 1114 prefs->SetBoolean(prefs::kCertRevocationCheckingEnabled, false); 1115 } 1116 } 1117 1118 bool MobileActivator::GotActivationError( 1119 const NetworkState* network, std::string* error) const { 1120 DCHECK(network); 1121 bool got_error = false; 1122 const char* error_code = kErrorDefault; 1123 const std::string& activation = network->activation_state(); 1124 1125 // This is the magic for detection of errors in during activation process. 1126 if (network->connection_state() == shill::kStateFailure && 1127 network->error() == shill::kErrorAaaFailed) { 1128 if (activation == shill::kActivationStatePartiallyActivated) { 1129 error_code = kErrorBadConnectionPartial; 1130 } else if (activation == shill::kActivationStateActivated) { 1131 if (network->roaming() == shill::kRoamingStateHome) 1132 error_code = kErrorBadConnectionActivated; 1133 else if (network->roaming() == shill::kRoamingStateRoaming) 1134 error_code = kErrorRoamingOnConnection; 1135 } 1136 got_error = true; 1137 } else if (network->connection_state() == shill::kStateActivationFailure) { 1138 if (network->error() == shill::kErrorNeedEvdo) { 1139 if (activation == shill::kActivationStatePartiallyActivated) 1140 error_code = kErrorNoEVDO; 1141 } else if (network->error() == shill::kErrorNeedHomeNetwork) { 1142 if (activation == shill::kActivationStateNotActivated) { 1143 error_code = kErrorRoamingActivation; 1144 } else if (activation == shill::kActivationStatePartiallyActivated) { 1145 error_code = kErrorRoamingPartiallyActivated; 1146 } 1147 } 1148 got_error = true; 1149 } 1150 1151 if (got_error) 1152 *error = GetErrorMessage(error_code); 1153 1154 return got_error; 1155 } 1156 1157 std::string MobileActivator::GetErrorMessage(const std::string& code) const { 1158 return cellular_config_->GetErrorMessage(code); 1159 } 1160 1161 void MobileActivator::SignalCellularPlanPayment() { 1162 DCHECK(!HasRecentCellularPlanPayment()); 1163 cellular_plan_payment_time_ = base::Time::Now(); 1164 } 1165 1166 bool MobileActivator::HasRecentCellularPlanPayment() const { 1167 const int kRecentPlanPaymentHours = 6; 1168 return (base::Time::Now() - 1169 cellular_plan_payment_time_).InHours() < kRecentPlanPaymentHours; 1170 } 1171 1172 } // namespace chromeos 1173