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