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 41using content::BrowserThread; 42 43namespace { 44 45// Cellular configuration file path. 46const char kCellularConfigPath[] = 47 "/usr/share/chromeos-assets/mobile/mobile_config.json"; 48 49// Cellular config file field names. 50const char kVersionField[] = "version"; 51const char kErrorsField[] = "errors"; 52 53// Number of times we'll try an OTASP before failing the activation process. 54const int kMaxOTASPTries = 3; 55// Number of times we will retry to reconnect and reload payment portal page. 56const int kMaxPortalReconnectCount = 2; 57// Time between connection attempts when forcing a reconnect. 58const int kReconnectDelayMS = 3000; 59// Retry delay after failed OTASP attempt. 60const int kOTASPRetryDelay = 40000; 61// Maximum amount of time we'll wait for a service to reconnect. 62const int kMaxReconnectTime = 30000; 63 64// Error codes matching codes defined in the cellular config file. 65const char kErrorDefault[] = "default"; 66const char kErrorBadConnectionPartial[] = "bad_connection_partial"; 67const char kErrorBadConnectionActivated[] = "bad_connection_activated"; 68const char kErrorRoamingOnConnection[] = "roaming_connection"; 69const char kErrorNoEVDO[] = "no_evdo"; 70const char kErrorRoamingActivation[] = "roaming_activation"; 71const char kErrorRoamingPartiallyActivated[] = "roaming_partially_activated"; 72const char kErrorNoService[] = "no_service"; 73const char kErrorDisabled[] = "disabled"; 74const char kErrorNoDevice[] = "no_device"; 75const char kFailedPaymentError[] = "failed_payment"; 76const char kFailedConnectivity[] = "connectivity"; 77 78// Returns true if the device follows the simple activation flow. 79bool IsSimpleActivationFlow(const chromeos::NetworkState* network) { 80 return (network->activation_type() == shill::kActivationTypeNonCellular || 81 network->activation_type() == shill::kActivationTypeOTA); 82} 83 84} // namespace 85 86namespace chromeos { 87 88//////////////////////////////////////////////////////////////////////////////// 89// 90// CellularConfigDocument 91// 92//////////////////////////////////////////////////////////////////////////////// 93CellularConfigDocument::CellularConfigDocument() {} 94 95std::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 103void 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 116CellularConfigDocument::~CellularConfigDocument() {} 117 118void 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 125bool 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//////////////////////////////////////////////////////////////////////////////// 166MobileActivator::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 180MobileActivator::~MobileActivator() { 181 TerminateActivation(); 182} 183 184MobileActivator* MobileActivator::GetInstance() { 185 return Singleton<MobileActivator>::get(); 186} 187 188void 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 209void MobileActivator::DefaultNetworkChanged(const NetworkState* network) { 210 RefreshCellularNetworks(); 211} 212 213void 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 241void MobileActivator::AddObserver(MobileActivator::Observer* observer) { 242 DCHECK(content::BrowserThread::CurrentlyOn(BrowserThread::UI)); 243 observers_.AddObserver(observer); 244} 245 246void MobileActivator::RemoveObserver(MobileActivator::Observer* observer) { 247 DCHECK(content::BrowserThread::CurrentlyOn(BrowserThread::UI)); 248 observers_.RemoveObserver(observer); 249} 250 251void 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 279void 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 288void 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 324void 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 331void MobileActivator::OnSetTransactionStatus(bool success) { 332 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, 333 base::Bind(&MobileActivator::HandleSetTransactionStatus, 334 AsWeakPtr(), success)); 335} 336 337void 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 358void MobileActivator::OnPortalLoaded(bool success) { 359 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, 360 base::Bind(&MobileActivator::HandlePortalLoaded, 361 AsWeakPtr(), success)); 362} 363 364void 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 400void 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 408void 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 439void 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 457void 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 477void 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 496void MobileActivator::RetryOTASP() { 497 DCHECK(state_ == PLAN_ACTIVATION_DELAY_OTASP); 498 StartOTASP(); 499} 500 501void 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 512void 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 556void 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 564void 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 593void 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 606void 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 632void 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 667const NetworkState* MobileActivator::GetNetworkState( 668 const std::string& service_path) { 669 return NetworkHandler::Get()->network_state_handler()->GetNetworkState( 670 service_path); 671} 672 673const NetworkState* MobileActivator::GetDefaultNetwork() { 674 return NetworkHandler::Get()->network_state_handler()->DefaultNetwork(); 675} 676 677void 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 707MobileActivator::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 757MobileActivator::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 786MobileActivator::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. 875const 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 910void 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 920bool MobileActivator::RunningActivation() const { 921 return !(state_ == PLAN_ACTIVATION_DONE || 922 state_ == PLAN_ACTIVATION_ERROR || 923 state_ == PLAN_ACTIVATION_PAGE_LOADING); 924} 925 926void 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 948void 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 963void 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 1089void 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 1105void 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 1118bool 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 1157std::string MobileActivator::GetErrorMessage(const std::string& code) const { 1158 return cellular_config_->GetErrorMessage(code); 1159} 1160 1161void MobileActivator::SignalCellularPlanPayment() { 1162 DCHECK(!HasRecentCellularPlanPayment()); 1163 cellular_plan_payment_time_ = base::Time::Now(); 1164} 1165 1166bool 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