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