diff options
author | zelidrag@chromium.org <zelidrag@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-06-06 01:18:09 +0000 |
---|---|---|
committer | zelidrag@chromium.org <zelidrag@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-06-06 01:18:09 +0000 |
commit | b2e87adc76ba5044838c70bc6d97975c2ef09119 (patch) | |
tree | d0cc2418adfe38340211e50ecc7c6e813254d0ab /chrome/browser | |
parent | 68074500d44d19ffd03779c8073c9dfad118f14a (diff) | |
download | chromium_src-b2e87adc76ba5044838c70bc6d97975c2ef09119.zip chromium_src-b2e87adc76ba5044838c70bc6d97975c2ef09119.tar.gz chromium_src-b2e87adc76ba5044838c70bc6d97975c2ef09119.tar.bz2 |
Refactored mobile activation engine outside of WebUI handler in order to expose its state to other layer of UI (i.e. dialog, background activation process...).
BUG=130420
TEST=manual regression test for mobile device activation
Review URL: https://chromiumcodereview.appspot.com/10456045
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@140686 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser')
14 files changed, 1473 insertions, 1210 deletions
diff --git a/chrome/browser/chromeos/cros/network_library_impl_stub.cc b/chrome/browser/chromeos/cros/network_library_impl_stub.cc index 660b5b5..90030b4 100644 --- a/chrome/browser/chromeos/cros/network_library_impl_stub.cc +++ b/chrome/browser/chromeos/cros/network_library_impl_stub.cc @@ -170,12 +170,14 @@ void NetworkLibraryImplStub::Init() { cellular1->set_network_technology(NETWORK_TECHNOLOGY_EVDO); AddStubNetwork(cellular1, PROFILE_NONE); - CellularNetwork* cellular2 = new CellularNetwork("cellular2"); + CellularNetwork* cellular2 = new CellularNetwork("/cellular2"); cellular2->set_name("Fake Cellular 2"); cellular2->set_strength(50); cellular2->set_activation_state(ACTIVATION_STATE_NOT_ACTIVATED); cellular2->set_network_technology(NETWORK_TECHNOLOGY_UMTS); cellular2->set_roaming_state(ROAMING_STATE_ROAMING); + cellular2->set_payment_url(std::string("http://www.google.com")); + cellular2->set_usage_url(std::string("http://www.google.com")); AddStubNetwork(cellular2, PROFILE_NONE); CellularNetwork* cellular3 = new CellularNetwork("cellular3"); diff --git a/chrome/browser/chromeos/mobile/mobile_activator.cc b/chrome/browser/chromeos/mobile/mobile_activator.cc new file mode 100644 index 0000000..ade7d3a --- /dev/null +++ b/chrome/browser/chromeos/mobile/mobile_activator.cc @@ -0,0 +1,1089 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/chromeos/mobile/mobile_activator.h" + +#include <algorithm> +#include <map> +#include <string> + +#include "base/bind.h" +#include "base/bind_helpers.h" +#include "base/file_util.h" +#include "base/json/json_reader.h" +#include "base/logging.h" +#include "base/memory/ref_counted_memory.h" +#include "base/message_loop.h" +#include "base/metrics/histogram.h" +#include "base/observer_list_threadsafe.h" +#include "base/string_piece.h" +#include "base/string_util.h" +#include "base/timer.h" +#include "base/utf_string_conversions.h" +#include "base/values.h" +#include "chrome/browser/browser_process.h" +#include "chrome/browser/chromeos/cros/cros_library.h" +#include "chrome/browser/chromeos/cros/network_library.h" +#include "chrome/browser/prefs/pref_service.h" +#include "chrome/common/pref_names.h" +#include "content/public/browser/browser_thread.h" + +using content::BrowserThread; + +namespace { + +// Cellular configuration file path. +const char kCellularConfigPath[] = + "/usr/share/chromeos-assets/mobile/mobile_config.json"; + +// Cellular config file field names. +const char kVersionField[] = "version"; +const char kErrorsField[] = "errors"; + +// Number of times we will retry to restart the activation process in case +// there is no connectivity in the restricted pool. +const int kMaxActivationAttempt = 3; +// Number of times we will retry to reconnect if connection fails. +const int kMaxConnectionRetry = 10; +// Number of times we will retry to reconnect and reload payment portal page. +const int kMaxPortalReconnectCount = 5; +// Number of times we will retry to reconnect if connection fails. +const int kMaxConnectionRetryOTASP = 30; +// Number of times we will retry to reconnect after payment is processed. +const int kMaxReconnectAttemptOTASP = 30; +// Reconnect retry delay (after payment is processed). +const int kPostPaymentReconnectDelayMS = 30000; // 30s. +// Connection timeout in seconds. +const int kConnectionTimeoutSeconds = 45; +// Reconnect delay. +const int kReconnectDelayMS = 3000; +// Reconnect timer delay. +const int kReconnectTimerDelayMS = 5000; +// Reconnect delay after previous failure. +const int kFailedReconnectDelayMS = 10000; +// Retry delay after failed OTASP attempt. +const int kOTASPRetryDelay = 20000; + +// Error codes matching codes defined in the cellular config file. +const char kErrorDefault[] = "default"; +const char kErrorBadConnectionPartial[] = "bad_connection_partial"; +const char kErrorBadConnectionActivated[] = "bad_connection_activated"; +const char kErrorRoamingOnConnection[] = "roaming_connection"; +const char kErrorNoEVDO[] = "no_evdo"; +const char kErrorRoamingActivation[] = "roaming_activation"; +const char kErrorRoamingPartiallyActivated[] = "roaming_partially_activated"; +const char kErrorNoService[] = "no_service"; +const char kErrorDisabled[] = "disabled"; +const char kErrorNoDevice[] = "no_device"; +const char kFailedPaymentError[] = "failed_payment"; +const char kFailedConnectivity[] = "connectivity"; + +} // namespace + +namespace chromeos { + +//////////////////////////////////////////////////////////////////////////////// +// +// CellularConfigDocument +// +//////////////////////////////////////////////////////////////////////////////// +CellularConfigDocument::CellularConfigDocument() { +} + +CellularConfigDocument::~CellularConfigDocument() { +} + +std::string CellularConfigDocument::GetErrorMessage(const std::string& code) { + base::AutoLock create(config_lock_); + ErrorMap::iterator iter = error_map_.find(code); + if (iter == error_map_.end()) + return code; + return iter->second; +} + +void CellularConfigDocument::LoadCellularConfigFile() { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); + // Load partner customization startup manifest if it is available. + FilePath config_path(kCellularConfigPath); + if (!file_util::PathExists(config_path)) + return; + + if (LoadFromFile(config_path)) { + DVLOG(1) << "Cellular config file loaded: " << kCellularConfigPath; + } else { + LOG(ERROR) << "Error loading cellular config file: " << + kCellularConfigPath; + } +} + +bool CellularConfigDocument::LoadFromFile(const FilePath& config_path) { + std::string config; + if (!file_util::ReadFileToString(config_path, &config)) + return false; + + scoped_ptr<Value> root( + base::JSONReader::Read(config, base::JSON_ALLOW_TRAILING_COMMAS)); + DCHECK(root.get() != NULL); + if (!root.get() || root->GetType() != Value::TYPE_DICTIONARY) { + LOG(WARNING) << "Bad cellular config file"; + return false; + } + + DictionaryValue* root_dict = static_cast<DictionaryValue*>(root.get()); + if (!root_dict->GetString(kVersionField, &version_)) { + LOG(WARNING) << "Cellular config file missing version"; + return false; + } + ErrorMap error_map; + DictionaryValue* errors = NULL; + if (!root_dict->GetDictionary(kErrorsField, &errors)) + return false; + for (DictionaryValue::key_iterator keys = errors->begin_keys(); + keys != errors->end_keys(); + ++keys) { + std::string value; + if (!errors->GetString(*keys, &value)) { + LOG(WARNING) << "Bad cellular config error value"; + return false; + } + error_map.insert(ErrorMap::value_type(*keys, value)); + } + SetErrorMap(error_map); + return true; +} + +void CellularConfigDocument::SetErrorMap( + const ErrorMap& map) { + base::AutoLock create(config_lock_); + error_map_.clear(); + error_map_.insert(map.begin(), map.end()); +} + +//////////////////////////////////////////////////////////////////////////////// +// +// MobileActivator +// +//////////////////////////////////////////////////////////////////////////////// +MobileActivator::MobileActivator() + : cellular_config_(new CellularConfigDocument()), + state_(PLAN_ACTIVATION_PAGE_LOADING), + reenable_wifi_(false), + reenable_ethernet_(false), + reenable_cert_check_(false), + evaluating_(false), + terminated_(true), + connection_retry_count_(0), + reconnect_wait_count_(0), + payment_reconnect_count_(0), + activation_attempt_(0) { +} + +MobileActivator::~MobileActivator() { + TerminateActivation(); +} + +MobileActivator* MobileActivator::GetInstance() { + return Singleton<MobileActivator>::get(); +} + +void MobileActivator::TerminateActivation() { + reconnect_timer_.Stop(); + NetworkLibrary* lib = + CrosLibrary::Get()->GetNetworkLibrary(); + lib->RemoveNetworkManagerObserver(this); + lib->RemoveObserverForAllNetworks(this); + if (lib->IsLocked()) + lib->Unlock(); + ReEnableOtherConnections(); + meid_.clear(); + service_path_.clear(); + state_ = PLAN_ACTIVATION_PAGE_LOADING; + reconnect_wait_count_ = 0; + evaluating_ = false; + reenable_wifi_ = false; + reenable_ethernet_ = false; + reenable_cert_check_ = false; + terminated_ = true; + cellular_config_ = NULL; +} + +void MobileActivator::OnNetworkManagerChanged(NetworkLibrary* cros) { + if (state_ == PLAN_ACTIVATION_PAGE_LOADING) + return; + EvaluateCellularNetwork(FindCellularNetworkByMeid(meid_, true)); +} + +void MobileActivator::OnNetworkChanged(NetworkLibrary* cros, + const Network* network) { + if (state_ == PLAN_ACTIVATION_PAGE_LOADING) + return; + + if (!network || network->type() != TYPE_CELLULAR) { + NOTREACHED(); + return; + } + + EvaluateCellularNetwork( + static_cast<CellularNetwork*>(const_cast<Network*>(network))); +} + +void MobileActivator::AddObserver(MobileActivator::Observer* observer) { + observers_.AddObserver(observer); +} + +void MobileActivator::RemoveObserver(MobileActivator::Observer* observer) { + observers_.RemoveObserver(observer); +} + +void MobileActivator::InitiateActivation(const std::string& service_path) { + NetworkLibrary* lib = CrosLibrary::Get()->GetNetworkLibrary(); + CellularNetwork* network = lib->FindCellularNetworkByPath(service_path); + if (!network) { + LOG(ERROR) << "Cellular service can't be found: " << service_path; + return; + } + + const chromeos::NetworkDevice* device = + lib->FindNetworkDeviceByPath(network->device_path()); + if (!device) { + LOG(ERROR) << "Cellular device can't be found: " << network->device_path(); + return; + } + + terminated_ = false; + meid_ = device->meid(); + service_path_ = service_path; + BrowserThread::PostTaskAndReply(BrowserThread::FILE, FROM_HERE, + base::Bind(&CellularConfigDocument::LoadCellularConfigFile, + cellular_config_.get()), + base::Bind(&MobileActivator::ContinueActivation, AsWeakPtr())); +} + +void MobileActivator::ContinueActivation() { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + CellularNetwork* network = FindCellularNetworkByMeid(meid_, false); + if (!network || !network->SupportsActivation()) + return; + + DCHECK(!CrosLibrary::Get()->GetNetworkLibrary()->IsLocked()); + SetupActivationProcess(network); + + StartActivation(); +} + +void MobileActivator::OnSetTransactionStatus(bool success) { + BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, + base::Bind(&MobileActivator::SetTransactionStatus, + AsWeakPtr(), success)); +} + +void MobileActivator::OnPortalLoaded(bool success) { + CellularNetwork* network = FindCellularNetworkByMeid(meid_, true); + if (!network) { + ChangeState(NULL, PLAN_ACTIVATION_ERROR, + GetErrorMessage(kErrorNoService)); + return; + } + if (state_ == PLAN_ACTIVATION_PAYMENT_PORTAL_LOADING || + state_ == PLAN_ACTIVATION_SHOWING_PAYMENT) { + if (success) { + payment_reconnect_count_ = 0; + ChangeState(network, PLAN_ACTIVATION_SHOWING_PAYMENT, std::string()); + } else { + payment_reconnect_count_++; + if (payment_reconnect_count_ > kMaxPortalReconnectCount) { + ChangeState(NULL, PLAN_ACTIVATION_ERROR, + GetErrorMessage(kErrorNoService)); + return; + } + // Disconnect now, this should force reconnection and we will retry to + // load the frame containing payment portal again. + DisconnectFromNetwork(network); + } + } else { + NOTREACHED() << "Called paymentPortalLoad while in unexpected state: " + << GetStateDescription(state_); + } +} + +CellularNetwork* MobileActivator::FindCellularNetworkByMeid( + const std::string& meid, bool reattach_observer) { + NetworkLibrary* lib = CrosLibrary::Get()->GetNetworkLibrary(); + for (CellularNetworkVector::const_iterator it = + lib->cellular_networks().begin(); + it != lib->cellular_networks().end(); ++it) { + const chromeos::NetworkDevice* device = + lib->FindNetworkDeviceByPath((*it)->device_path()); + if (device && meid == device->meid()) { + CellularNetwork* network = *it; + // If service path has changed, reattach the event observer for this + // network service. + if (reattach_observer && service_path_ != network->service_path()) { + lib->RemoveObserverForAllNetworks(this); + lib->AddNetworkObserver(network->service_path(), this); + service_path_ = network->service_path(); + } + return network; + } + } + return NULL; +} + +void MobileActivator::StartActivation() { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + UMA_HISTOGRAM_COUNTS("Cellular.MobileSetupStart", 1); + NetworkLibrary* lib = + CrosLibrary::Get()->GetNetworkLibrary(); + CellularNetwork* network = FindCellularNetworkByMeid(meid_, true); + // Check if we can start activation process. + if (!network) { + std::string error; + if (!lib->cellular_available()) + error = kErrorNoDevice; + else if (!lib->cellular_enabled()) + error = kErrorDisabled; + else + error = kErrorNoService; + ChangeState(NULL, PLAN_ACTIVATION_ERROR, GetErrorMessage(error)); + return; + } + + // Start monitoring network property changes. + lib->AddNetworkManagerObserver(this); + lib->RemoveObserverForAllNetworks(this); + lib->AddNetworkObserver(network->service_path(), this); + // Try to start with OTASP immediately if we have received payment recently. + state_ = lib->HasRecentCellularPlanPayment() ? + PLAN_ACTIVATION_START_OTASP : + PLAN_ACTIVATION_START; + EvaluateCellularNetwork(network); +} + +void MobileActivator::RetryOTASP() { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + DCHECK(state_ == PLAN_ACTIVATION_DELAY_OTASP); + StartOTASP(); +} + +void MobileActivator::ContinueConnecting(int delay) { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + CellularNetwork* network = FindCellularNetworkByMeid(meid_, true); + if (network && network->connecting_or_connected()) { + EvaluateCellularNetwork(network); + } else { + ConnectToNetwork(network, delay); + } +} + +void MobileActivator::SetTransactionStatus(bool success) { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + // The payment is received, try to reconnect and check the status all over + // again. + if (success && state_ == PLAN_ACTIVATION_SHOWING_PAYMENT) { + NetworkLibrary* lib = + CrosLibrary::Get()->GetNetworkLibrary(); + lib->SignalCellularPlanPayment(); + UMA_HISTOGRAM_COUNTS("Cellular.PaymentReceived", 1); + StartOTASP(); + } else { + UMA_HISTOGRAM_COUNTS("Cellular.PaymentFailed", 1); + } +} + +void MobileActivator::StartOTASP() { + state_ = PLAN_ACTIVATION_START_OTASP; + CellularNetwork* network = FindCellularNetworkByMeid(meid_, true); + if (network && + network->connected() && + network->activation_state() == ACTIVATION_STATE_ACTIVATED) { + CrosLibrary::Get()->GetNetworkLibrary()-> + DisconnectFromNetwork(network); + } else { + EvaluateCellularNetwork(network); + } +} + +void MobileActivator::ReconnectTimerFired() { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + // Permit network connection changes only in reconnecting states. + if (state_ != PLAN_ACTIVATION_RECONNECTING_OTASP_TRY && + state_ != PLAN_ACTIVATION_RECONNECTING && + state_ != PLAN_ACTIVATION_RECONNECTING_PAYMENT && + state_ != PLAN_ACTIVATION_RECONNECTING_OTASP) + return; + CellularNetwork* network = FindCellularNetworkByMeid(meid_, true); + if (!network) { + // No service, try again since this is probably just transient condition. + LOG(WARNING) << "Service not present at reconnect attempt."; + } + EvaluateCellularNetwork(network); +} + +void MobileActivator::DisconnectFromNetwork(CellularNetwork* network) { + DCHECK(network); + LOG(INFO) << "Disconnecting from: " << network->service_path(); + CrosLibrary::Get()->GetNetworkLibrary()-> + DisconnectFromNetwork(network); + // Disconnect will force networks to be reevaluated, so + // we don't want to continue processing on this path anymore. + evaluating_ = false; +} + +bool MobileActivator::NeedsReconnecting(CellularNetwork* network, + PlanActivationState* new_state, + std::string* error_description) { + DCHECK(network); + if (!network->failed() && !ConnectionTimeout()) + return false; + + // Try to reconnect again if reconnect failed, or if for some + // reasons we are still not connected after 45 seconds. + int max_retries = (state_ == PLAN_ACTIVATION_RECONNECTING_OTASP) ? + kMaxConnectionRetryOTASP : kMaxConnectionRetry; + if (connection_retry_count_ < max_retries) { + UMA_HISTOGRAM_COUNTS("Cellular.ConnectionRetry", 1); + ConnectToNetwork(network, kFailedReconnectDelayMS); + return true; + } + // We simply can't connect anymore after all these tries. + UMA_HISTOGRAM_COUNTS("Cellular.ConnectionFailed", 1); + *new_state = PLAN_ACTIVATION_ERROR; + *error_description = GetErrorMessage(kFailedConnectivity); + return false; +} + +bool MobileActivator::ConnectToNetwork(CellularNetwork* network, int delay) { + if (network && network->connecting_or_connected()) + return true; + // Permit network connection changes only in reconnecting states. + if (state_ != PLAN_ACTIVATION_RECONNECTING_OTASP_TRY && + state_ != PLAN_ACTIVATION_RECONNECTING && + state_ != PLAN_ACTIVATION_RECONNECTING_PAYMENT && + state_ != PLAN_ACTIVATION_RECONNECTING_OTASP) return false; + if (network) + LOG(INFO) << "Connecting to: " << network->service_path(); + connection_retry_count_++; + connection_start_time_ = base::Time::Now(); + if (!network || state_ == PLAN_ACTIVATION_RECONNECTING_OTASP) { + LOG(WARNING) << "Delaying reconnect to " + << (network ? network->service_path().c_str() : "no service"); + // If we coudn't connect during reconnection phase, try to reconnect + // with a delay (and try to reconnect if needed). + BrowserThread::PostDelayedTask(BrowserThread::UI, FROM_HERE, + base::Bind(&MobileActivator::ContinueConnecting, AsWeakPtr(), delay), + base::TimeDelta::FromMilliseconds(delay)); + return false; + } + CrosLibrary::Get()->GetNetworkLibrary()-> + ConnectToCellularNetwork(network); + return true; +} + +void MobileActivator::ForceReconnect(CellularNetwork* network, int delay) { + DCHECK(network); + UMA_HISTOGRAM_COUNTS("Cellular.ActivationRetry", 1); + // Reset reconnect metrics. + connection_retry_count_ = 0; + connection_start_time_ = base::Time(); + // First, disconnect... + LOG(INFO) << "Disconnecting from " << network->service_path(); + CrosLibrary::Get()->GetNetworkLibrary()-> + DisconnectFromNetwork(network); + // Check the network state 3s after we disconnect to make sure. + BrowserThread::PostDelayedTask(BrowserThread::UI, FROM_HERE, + base::Bind(&MobileActivator::ContinueConnecting, AsWeakPtr(), delay), + base::TimeDelta::FromMilliseconds(delay)); +} + +bool MobileActivator::ConnectionTimeout() { + return (base::Time::Now() - + connection_start_time_).InSeconds() > kConnectionTimeoutSeconds; +} + +void MobileActivator::EvaluateCellularNetwork(CellularNetwork* network) { + if (terminated_) + return; + + PlanActivationState new_state = state_; + if (!network) { + LOG(WARNING) << "Cellular service lost"; + if (state_ == PLAN_ACTIVATION_RECONNECTING_OTASP_TRY || + state_ == PLAN_ACTIVATION_RECONNECTING || + state_ == PLAN_ACTIVATION_RECONNECTING_PAYMENT || + state_ == PLAN_ACTIVATION_RECONNECTING_OTASP) { + // This might be the legit case when service is lost after activation. + // We need to make sure we force reconnection as soon as it shows up. + LOG(INFO) << "Force service reconnection"; + connection_start_time_ = base::Time(); + } + return; + } + + // Prevent this method from being called if it is already on the stack. + // This might happen on some state transitions (ie. connect, disconnect). + if (evaluating_) + return; + evaluating_ = true; + std::string error_description; + + LOG(WARNING) << "Cellular:\n service=" << network->GetStateString().c_str() + << "\n ui=" << GetStateDescription(state_) + << "\n activation=" << network->GetActivationStateString().c_str() + << "\n error=" << network->GetErrorString().c_str() + << "\n setvice_path=" << network->service_path().c_str(); + switch (state_) { + case PLAN_ACTIVATION_START: { + switch (network->activation_state()) { + case ACTIVATION_STATE_ACTIVATED: { + if (network->disconnected()) { + new_state = PLAN_ACTIVATION_RECONNECTING; + } else if (network->connected()) { + if (network->restricted_pool()) { + new_state = PLAN_ACTIVATION_PAYMENT_PORTAL_LOADING; + } else { + new_state = PLAN_ACTIVATION_DONE; + } + } + break; + } + default: { + if (network->disconnected() || + network->state() == STATE_ACTIVATION_FAILURE) { + new_state = (network->activation_state() == + ACTIVATION_STATE_PARTIALLY_ACTIVATED) ? + PLAN_ACTIVATION_TRYING_OTASP : + PLAN_ACTIVATION_INITIATING_ACTIVATION; + } else if (network->connected()) { + DisconnectFromNetwork(network); + return; + } + break; + } + } + break; + } + case PLAN_ACTIVATION_START_OTASP: { + switch (network->activation_state()) { + case ACTIVATION_STATE_PARTIALLY_ACTIVATED: { + if (network->disconnected()) { + new_state = PLAN_ACTIVATION_OTASP; + } else if (network->connected()) { + DisconnectFromNetwork(network); + return; + } + break; + } + case ACTIVATION_STATE_ACTIVATED: + new_state = PLAN_ACTIVATION_RECONNECTING_OTASP; + break; + default: { + LOG(WARNING) << "Unexpected activation state for device " + << network->service_path().c_str(); + break; + } + } + break; + } + case PLAN_ACTIVATION_DELAY_OTASP: + // Just ignore any changes until the OTASP retry timer kicks in. + evaluating_ = false; + return; + case PLAN_ACTIVATION_INITIATING_ACTIVATION: { + switch (network->activation_state()) { + case ACTIVATION_STATE_ACTIVATED: + case ACTIVATION_STATE_PARTIALLY_ACTIVATED: + new_state = PLAN_ACTIVATION_START; + break; + case ACTIVATION_STATE_NOT_ACTIVATED: + case ACTIVATION_STATE_ACTIVATING: + // Wait in this state until activation state changes. + break; + default: + break; + } + break; + } + case PLAN_ACTIVATION_OTASP: + case PLAN_ACTIVATION_TRYING_OTASP: { + switch (network->activation_state()) { + case ACTIVATION_STATE_ACTIVATED: + if (network->disconnected()) { + new_state = GetNextReconnectState(state_); + } else if (network->connected()) { + if (network->restricted_pool()) { + new_state = PLAN_ACTIVATION_PAYMENT_PORTAL_LOADING; + } else { + new_state = PLAN_ACTIVATION_DONE; + } + } + break; + case ACTIVATION_STATE_PARTIALLY_ACTIVATED: + if (network->connected()) { + if (network->restricted_pool()) + new_state = PLAN_ACTIVATION_PAYMENT_PORTAL_LOADING; + } else { + new_state = GetNextReconnectState(state_); + } + break; + case ACTIVATION_STATE_NOT_ACTIVATED: + case ACTIVATION_STATE_ACTIVATING: + // Wait in this state until activation state changes. + break; + default: + break; + } + break; + } + case PLAN_ACTIVATION_RECONNECTING_OTASP_TRY: + case PLAN_ACTIVATION_RECONNECTING_PAYMENT: + case PLAN_ACTIVATION_RECONNECTING: { + if (network->connected()) { + // Make sure other networks are not interfering with our detection of + // restricted pool. + DisableOtherNetworks(); + // Wait until the service shows up and gets activated. + switch (network->activation_state()) { + case ACTIVATION_STATE_PARTIALLY_ACTIVATED: + case ACTIVATION_STATE_ACTIVATED: + if (network->restricted_pool()) { + if (network->error() == ERROR_DNS_LOOKUP_FAILED) { + LOG(WARNING) << "No connectivity for device " + << network->service_path().c_str(); + // If we are connected but there is no connectivity at all, + // restart the whole process again. + if (activation_attempt_ < kMaxActivationAttempt) { + activation_attempt_++; + LOG(WARNING) << "Reconnect attempt #" + << activation_attempt_; + ForceReconnect(network, kFailedReconnectDelayMS); + evaluating_ = false; + return; + } else { + new_state = PLAN_ACTIVATION_ERROR; + UMA_HISTOGRAM_COUNTS("Cellular.ActivationRetryFailure", 1); + error_description = GetErrorMessage(kFailedConnectivity); + } + } else { + // If we have already received payment, don't show the payment + // page again. We should try to reconnect after some + // time instead. + new_state = PLAN_ACTIVATION_PAYMENT_PORTAL_LOADING; + } + } else if (network->activation_state() == + ACTIVATION_STATE_ACTIVATED) { + new_state = PLAN_ACTIVATION_DONE; + } + break; + default: + break; + } + } else if (NeedsReconnecting(network, &new_state, &error_description)) { + evaluating_ = false; + return; + } + break; + } + case PLAN_ACTIVATION_RECONNECTING_OTASP: { + if (network->connected()) { + // Make sure other networks are not interfering with our detection of + // restricted pool. + DisableOtherNetworks(); + // Wait until the service shows up and gets activated. + switch (network->activation_state()) { + case ACTIVATION_STATE_PARTIALLY_ACTIVATED: + case ACTIVATION_STATE_ACTIVATED: + if (network->restricted_pool()) { + LOG(WARNING) << "Still no connectivity after OTASP for device " + << network->service_path().c_str(); + // If we have already received payment, don't show the payment + // page again. We should try to reconnect after some time instead. + if (reconnect_wait_count_ < kMaxReconnectAttemptOTASP) { + reconnect_wait_count_++; + LOG(WARNING) << "OTASP reconnect attempt #" + << reconnect_wait_count_; + ForceReconnect(network, kPostPaymentReconnectDelayMS); + evaluating_ = false; + return; + } else { + new_state = PLAN_ACTIVATION_ERROR; + UMA_HISTOGRAM_COUNTS("Cellular.PostPaymentConnectFailure", 1); + error_description = GetErrorMessage(kFailedConnectivity); + } + } else if (network->online()) { + new_state = PLAN_ACTIVATION_DONE; + } + break; + default: + break; + } + } else if (NeedsReconnecting(network, &new_state, &error_description)) { + evaluating_ = false; + return; + } + break; + } + case PLAN_ACTIVATION_PAGE_LOADING: + break; + // Just ignore all signals until the site confirms payment. + case PLAN_ACTIVATION_PAYMENT_PORTAL_LOADING: + case PLAN_ACTIVATION_SHOWING_PAYMENT: { + if (network->disconnected()) + new_state = PLAN_ACTIVATION_RECONNECTING_PAYMENT; + break; + } + // Activation completed/failed, ignore network changes. + case PLAN_ACTIVATION_DONE: + case PLAN_ACTIVATION_ERROR: + break; + } + + if (new_state != PLAN_ACTIVATION_ERROR && + GotActivationError(network, &error_description)) { + // Check for this special case when we try to do activate partially + // activated device. If that attempt failed, try to disconnect to clear the + // state and reconnect again. + if ((network->activation_state() == + ACTIVATION_STATE_PARTIALLY_ACTIVATED || + network->activation_state() == ACTIVATION_STATE_ACTIVATING) && + (network->error() == ERROR_NO_ERROR || + network->error() == ERROR_OTASP_FAILED) && + network->state() == STATE_ACTIVATION_FAILURE) { + LOG(WARNING) << "Activation failure detected " + << network->service_path().c_str(); + switch (state_) { + case PLAN_ACTIVATION_OTASP: + case PLAN_ACTIVATION_RECONNECTING_OTASP: + new_state = PLAN_ACTIVATION_DELAY_OTASP; + break; + case PLAN_ACTIVATION_TRYING_OTASP: + new_state = PLAN_ACTIVATION_RECONNECTING_OTASP_TRY; + break; + case PLAN_ACTIVATION_INITIATING_ACTIVATION: + new_state = PLAN_ACTIVATION_RECONNECTING; + break; + case PLAN_ACTIVATION_START: + // We are just starting, so this must be previous activation attempt + // failure. + new_state = PLAN_ACTIVATION_TRYING_OTASP; + break; + case PLAN_ACTIVATION_DELAY_OTASP: + case PLAN_ACTIVATION_RECONNECTING_OTASP_TRY: + case PLAN_ACTIVATION_RECONNECTING: + new_state = state_; + break; + default: + new_state = PLAN_ACTIVATION_ERROR; + break; + } + } else { + LOG(WARNING) << "Unexpected activation failure for " + << network->service_path().c_str(); + new_state = PLAN_ACTIVATION_ERROR; + } + } + + if (new_state == PLAN_ACTIVATION_ERROR && !error_description.length()) + error_description = GetErrorMessage(kErrorDefault); + + ChangeState(network, new_state, error_description); + evaluating_ = false; +} + +MobileActivator::PlanActivationState MobileActivator::GetNextReconnectState( + MobileActivator::PlanActivationState state) { + switch (state) { + case PLAN_ACTIVATION_INITIATING_ACTIVATION: + return PLAN_ACTIVATION_RECONNECTING; + case PLAN_ACTIVATION_OTASP: + return PLAN_ACTIVATION_RECONNECTING_OTASP; + case PLAN_ACTIVATION_TRYING_OTASP: + return PLAN_ACTIVATION_RECONNECTING_OTASP_TRY; + default: + return PLAN_ACTIVATION_RECONNECTING; + } +} + +// Debugging helper function, will take it out at the end. +const char* MobileActivator::GetStateDescription(PlanActivationState state) { + switch (state) { + case PLAN_ACTIVATION_PAGE_LOADING: + return "PAGE_LOADING"; + case PLAN_ACTIVATION_START: + return "ACTIVATION_START"; + case PLAN_ACTIVATION_TRYING_OTASP: + return "TRYING_OTASP"; + case PLAN_ACTIVATION_RECONNECTING_OTASP_TRY: + return "RECONNECTING_OTASP_TRY"; + case PLAN_ACTIVATION_INITIATING_ACTIVATION: + return "INITIATING_ACTIVATION"; + case PLAN_ACTIVATION_RECONNECTING: + return "RECONNECTING"; + case PLAN_ACTIVATION_PAYMENT_PORTAL_LOADING: + return "PAYMENT_PORTAL_LOADING"; + case PLAN_ACTIVATION_SHOWING_PAYMENT: + return "SHOWING_PAYMENT"; + case PLAN_ACTIVATION_RECONNECTING_PAYMENT: + return "RECONNECTING_PAYMENT"; + case PLAN_ACTIVATION_START_OTASP: + return "START_OTASP"; + case PLAN_ACTIVATION_DELAY_OTASP: + return "DELAY_OTASP"; + case PLAN_ACTIVATION_OTASP: + return "OTASP"; + case PLAN_ACTIVATION_RECONNECTING_OTASP: + return "RECONNECTING_OTASP"; + case PLAN_ACTIVATION_DONE: + return "DONE"; + case PLAN_ACTIVATION_ERROR: + return "ERROR"; + } + return "UNKNOWN"; +} + + +void MobileActivator::CompleteActivation( + CellularNetwork* network) { + // Remove observers, we are done with this page. + NetworkLibrary* lib = CrosLibrary::Get()-> + GetNetworkLibrary(); + lib->RemoveNetworkManagerObserver(this); + lib->RemoveObserverForAllNetworks(this); + if (lib->IsLocked()) + lib->Unlock(); + // If we have successfully activated the connection, set autoconnect flag. + if (network) + network->SetAutoConnect(true); + // Reactivate other types of connections if we have + // shut them down previously. + ReEnableOtherConnections(); +} + +bool MobileActivator::RunningActivation() const { + return !(state_ == PLAN_ACTIVATION_DONE || + state_ == PLAN_ACTIVATION_ERROR || + state_ == PLAN_ACTIVATION_PAGE_LOADING); +} + +void MobileActivator::ChangeState(CellularNetwork* network, + PlanActivationState new_state, + const std::string& error_description) { + static bool first_time = true; + if (state_ == new_state && !first_time) + return; + LOG(WARNING) << "Activation state flip old = " + << GetStateDescription(state_) + << ", new = " << GetStateDescription(new_state); + first_time = false; + + // Pick action that should happen on leaving the old state. + switch (state_) { + case PLAN_ACTIVATION_RECONNECTING_OTASP_TRY: + case PLAN_ACTIVATION_RECONNECTING: + case PLAN_ACTIVATION_RECONNECTING_OTASP: + if (reconnect_timer_.IsRunning()) { + reconnect_timer_.Stop(); + } + break; + default: + break; + } + state_ = new_state; + + // Signal to observers layer that the state is changing. + FOR_EACH_OBSERVER(Observer, observers_, + OnActivationStateChanged(network, state_, error_description)); + + // Pick action that should happen on entering the new state. + switch (new_state) { + case PLAN_ACTIVATION_START: + break; + case PLAN_ACTIVATION_DELAY_OTASP: { + UMA_HISTOGRAM_COUNTS("Cellular.RetryOTASP", 1); + BrowserThread::PostDelayedTask(BrowserThread::UI, FROM_HERE, + base::Bind(&MobileActivator::RetryOTASP, AsWeakPtr()), + base::TimeDelta::FromMilliseconds(kOTASPRetryDelay)); + break; + } + case PLAN_ACTIVATION_INITIATING_ACTIVATION: + case PLAN_ACTIVATION_TRYING_OTASP: + case PLAN_ACTIVATION_OTASP: + DCHECK(network); + LOG(WARNING) << "Activating service " << network->service_path().c_str(); + UMA_HISTOGRAM_COUNTS("Cellular.ActivationTry", 1); + if (!network->StartActivation()) { + UMA_HISTOGRAM_COUNTS("Cellular.ActivationFailure", 1); + if (new_state == PLAN_ACTIVATION_OTASP) { + ChangeState(network, PLAN_ACTIVATION_DELAY_OTASP, std::string()); + } else { + ChangeState(network, PLAN_ACTIVATION_ERROR, + GetErrorMessage(kFailedConnectivity)); + } + } + break; + case PLAN_ACTIVATION_RECONNECTING_OTASP_TRY: + case PLAN_ACTIVATION_RECONNECTING: + case PLAN_ACTIVATION_RECONNECTING_PAYMENT: + case PLAN_ACTIVATION_RECONNECTING_OTASP: { + // Start reconnect timer. This will ensure that we are not left in + // limbo by the network library. + if (!reconnect_timer_.IsRunning()) { + reconnect_timer_.Start( + FROM_HERE, + base::TimeDelta::FromMilliseconds(kReconnectTimerDelayMS), + this, &MobileActivator::ReconnectTimerFired); + } + // Reset connection metrics and try to connect. + reconnect_wait_count_ = 0; + connection_retry_count_ = 0; + connection_start_time_ = base::Time::Now(); + ConnectToNetwork(network, kReconnectDelayMS); + break; + } + case PLAN_ACTIVATION_PAGE_LOADING: + return; + case PLAN_ACTIVATION_PAYMENT_PORTAL_LOADING: + case PLAN_ACTIVATION_SHOWING_PAYMENT: + // Fix for fix SSL for the walled gardens where cert chain verification + // might not work. + break; + case PLAN_ACTIVATION_DONE: + DCHECK(network); + CompleteActivation(network); + UMA_HISTOGRAM_COUNTS("Cellular.MobileSetupSucceeded", 1); + break; + case PLAN_ACTIVATION_ERROR: + CompleteActivation(NULL); + UMA_HISTOGRAM_COUNTS("Cellular.PlanFailed", 1); + break; + default: + break; + } +} + +void MobileActivator::ReEnableOtherConnections() { + NetworkLibrary* lib = CrosLibrary::Get()->GetNetworkLibrary(); + if (reenable_ethernet_) { + reenable_ethernet_ = false; + lib->EnableEthernetNetworkDevice(true); + } + if (reenable_wifi_) { + reenable_wifi_ = false; + lib->EnableWifiNetworkDevice(true); + } + + PrefService* prefs = g_browser_process->local_state(); + if (reenable_cert_check_) { + prefs->SetBoolean(prefs::kCertRevocationCheckingEnabled, + true); + reenable_cert_check_ = false; + } +} + +void MobileActivator::SetupActivationProcess(CellularNetwork* network) { + if (!network) + return; + + // Disable SSL cert checks since we will be doing this in + // restricted pool. + PrefService* prefs = g_browser_process->local_state(); + if (!reenable_cert_check_ && + prefs->GetBoolean( + prefs::kCertRevocationCheckingEnabled)) { + reenable_cert_check_ = true; + prefs->SetBoolean(prefs::kCertRevocationCheckingEnabled, false); + } + + NetworkLibrary* lib = CrosLibrary::Get()-> + GetNetworkLibrary(); + // Disable autoconnect to cellular network. + network->SetAutoConnect(false); + + // Prevent any other network interference. + DisableOtherNetworks(); + lib->Lock(); +} + +void MobileActivator::DisableOtherNetworks() { + NetworkLibrary* lib = CrosLibrary::Get()->GetNetworkLibrary(); + // Disable ethernet and wifi. + if (lib->ethernet_enabled()) { + reenable_ethernet_ = true; + lib->EnableEthernetNetworkDevice(false); + } + if (lib->wifi_enabled()) { + reenable_wifi_ = true; + lib->EnableWifiNetworkDevice(false); + } +} + +bool MobileActivator::GotActivationError( + CellularNetwork* network, std::string* error) { + DCHECK(network); + bool got_error = false; + const char* error_code = kErrorDefault; + + // This is the magic for detection of errors in during activation process. + if (network->state() == STATE_FAILURE && + network->error() == ERROR_AAA_FAILED) { + if (network->activation_state() == + ACTIVATION_STATE_PARTIALLY_ACTIVATED) { + error_code = kErrorBadConnectionPartial; + } else if (network->activation_state() == + ACTIVATION_STATE_ACTIVATED) { + if (network->roaming_state() == ROAMING_STATE_HOME) { + error_code = kErrorBadConnectionActivated; + } else if (network->roaming_state() == ROAMING_STATE_ROAMING) { + error_code = kErrorRoamingOnConnection; + } + } + got_error = true; + } else if (network->state() == STATE_ACTIVATION_FAILURE) { + if (network->error() == ERROR_NEED_EVDO) { + if (network->activation_state() == + ACTIVATION_STATE_PARTIALLY_ACTIVATED) + error_code = kErrorNoEVDO; + } else if (network->error() == ERROR_NEED_HOME_NETWORK) { + if (network->activation_state() == + ACTIVATION_STATE_NOT_ACTIVATED) { + error_code = kErrorRoamingActivation; + } else if (network->activation_state() == + ACTIVATION_STATE_PARTIALLY_ACTIVATED) { + error_code = kErrorRoamingPartiallyActivated; + } + } + got_error = true; + } + + if (got_error) + *error = GetErrorMessage(error_code); + + return got_error; +} + +void MobileActivator::GetDeviceInfo(CellularNetwork* network, + DictionaryValue* value) { + DCHECK(network); + NetworkLibrary* cros = + CrosLibrary::Get()->GetNetworkLibrary(); + if (!cros) + return; + value->SetString("carrier", network->name()); + value->SetString("payment_url", network->payment_url()); + if (network->using_post() && network->post_data().length()) + value->SetString("post_data", network->post_data()); + + const NetworkDevice* device = + cros->FindNetworkDeviceByPath(network->device_path()); + if (device) { + value->SetString("MEID", device->meid()); + value->SetString("IMEI", device->imei()); + value->SetString("MDN", device->mdn()); + } +} + +std::string MobileActivator::GetErrorMessage(const std::string& code) { + return cellular_config_->GetErrorMessage(code); +} + +} // namespace chromeos diff --git a/chrome/browser/chromeos/mobile/mobile_activator.h b/chrome/browser/chromeos/mobile/mobile_activator.h new file mode 100644 index 0000000..a69a2d6 --- /dev/null +++ b/chrome/browser/chromeos/mobile/mobile_activator.h @@ -0,0 +1,246 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_CHROMEOS_MOBILE_MOBILE_ACTIVATOR_H_ +#define CHROME_BROWSER_CHROMEOS_MOBILE_MOBILE_ACTIVATOR_H_ +#pragma once + +#include <map> +#include <string> + +#include "base/file_path.h" +#include "base/memory/singleton.h" +#include "base/memory/weak_ptr.h" +#include "base/observer_list.h" +#include "chrome/browser/chromeos/cros/network_library.h" + +namespace chromeos { + +// Cellular plan config document. +class CellularConfigDocument + : public base::RefCountedThreadSafe<CellularConfigDocument> { + public: + CellularConfigDocument(); + virtual ~CellularConfigDocument(); + + // Return error message for a given code. + std::string GetErrorMessage(const std::string& code); + void LoadCellularConfigFile(); + const std::string& version() { return version_; } + + private: + typedef std::map<std::string, std::string> ErrorMap; + + void SetErrorMap(const ErrorMap& map); + bool LoadFromFile(const FilePath& config_path); + + std::string version_; + ErrorMap error_map_; + base::Lock config_lock_; + + DISALLOW_COPY_AND_ASSIGN(CellularConfigDocument); +}; + +// This class performs mobile plan activation process. +class MobileActivator + : public NetworkLibrary::NetworkManagerObserver, + public NetworkLibrary::NetworkObserver, + public base::SupportsWeakPtr<MobileActivator> { + public: + // Activation state. + enum PlanActivationState { + // Activation WebUI page is loading, activation not started. + PLAN_ACTIVATION_PAGE_LOADING = -1, + // Activation process started. + PLAN_ACTIVATION_START = 0, + // Initial over the air activation attempt. + PLAN_ACTIVATION_TRYING_OTASP = 1, + // Reconnection after the initial activation attempt. + PLAN_ACTIVATION_RECONNECTING_OTASP_TRY = 2, + // Performing pre-activation process. + PLAN_ACTIVATION_INITIATING_ACTIVATION = 3, + // Reconnecting to network. + PLAN_ACTIVATION_RECONNECTING = 4, + // Loading payment portal page. + PLAN_ACTIVATION_PAYMENT_PORTAL_LOADING = 5, + // Showing payment portal page. + PLAN_ACTIVATION_SHOWING_PAYMENT = 6, + // Reconnecting after successful plan payment. + PLAN_ACTIVATION_RECONNECTING_PAYMENT = 7, + // Delaying activation until payment portal catches up. + PLAN_ACTIVATION_DELAY_OTASP = 8, + // Starting post-payment activation attempt. + PLAN_ACTIVATION_START_OTASP = 9, + // Attempting activation. + PLAN_ACTIVATION_OTASP = 10, + // Reconnecting after activation attempt. + PLAN_ACTIVATION_RECONNECTING_OTASP = 11, + // Finished activation. + PLAN_ACTIVATION_DONE = 12, + // Error occured during activation process. + PLAN_ACTIVATION_ERROR = 0xFF, + }; + + // Activation process observer. + class Observer { + public: + // Signals activation |state| change for given |network|. + virtual void OnActivationStateChanged( + CellularNetwork* network, + PlanActivationState state, + const std::string& error_description) = 0; + + protected: + Observer() {} + virtual ~Observer() {} + }; + + static MobileActivator* GetInstance(); + + // Add/remove activation process observer. + void AddObserver(Observer* observer); + void RemoveObserver(Observer* observer); + + // Activation is in process. + bool RunningActivation() const; + // Activation state. + PlanActivationState state() const { return state_; } + // Initiates activation process. + void InitiateActivation(const std::string& service_path); + // Terminates activation process if already started. + void TerminateActivation(); + // Process portal load attempt status. + void OnPortalLoaded(bool success); + // Process payment transaction status. + void OnSetTransactionStatus(bool success); + + private: + friend struct DefaultSingletonTraits<MobileActivator>; + + MobileActivator(); + virtual ~MobileActivator(); + + // NetworkLibrary::NetworkManagerObserver overrides. + virtual void OnNetworkManagerChanged(NetworkLibrary* obj) OVERRIDE; + // NetworkLibrary::NetworkObserver overrides. + virtual void OnNetworkChanged(NetworkLibrary* obj, + const Network* network) OVERRIDE; + + // Continue activation after inital setup (config load). + void ContinueActivation(); + // Process payment transaction results. + void SetTransactionStatus(bool success); + // Starts activation. + void StartActivation(); + // Retried OTASP. + void RetryOTASP(); + // Continues activation process. This method is called after we disconnect + // due to detected connectivity issue to kick off reconnection. + void ContinueConnecting(int delay); + + // Sends message to host registration page with system/user info data. + void SendDeviceInfo(); + + // Callback for when |reconnect_timer_| fires. + void ReconnectTimerFired(); + // Starts OTASP process. + void StartOTASP(); + // Checks if we need to reconnect due to failed connection attempt. + bool NeedsReconnecting(CellularNetwork* network, + PlanActivationState* new_state, + std::string* error_description); + // Disconnect from network. + void DisconnectFromNetwork(CellularNetwork* network); + // Connects to cellular network, resets connection timer. + bool ConnectToNetwork(CellularNetwork* network, int delay); + // Forces disconnect / reconnect when we detect portal connectivity issues. + void ForceReconnect(CellularNetwork* network, int delay); + // Reports connection timeout. + bool ConnectionTimeout(); + // Verify the state of cellular network and modify internal state. + void EvaluateCellularNetwork(CellularNetwork* network); + // Check the current cellular network for error conditions. + bool GotActivationError(CellularNetwork* network, + std::string* error); + // Sends status updates to WebUI page. + void UpdatePage(CellularNetwork* network, + const std::string& error_description); + // Changes internal state. + void ChangeState(CellularNetwork* network, + PlanActivationState new_state, + const std::string& error_description); + // Prepares network devices for cellular activation process. + void SetupActivationProcess(CellularNetwork* network); + // Disables ethernet and wifi newtorks since they interefere with + // detection of restricted pool on cellular side. + void DisableOtherNetworks(); + // Resets network devices after cellular activation process. + // |network| should be NULL if the activation process failed. + void CompleteActivation(CellularNetwork* network); + // Control routines for handling other types of connections during + // cellular activation. + void ReEnableOtherConnections(); + // Return error message for a given code. + std::string GetErrorMessage(const std::string& code); + + // Converts the currently active CellularNetwork device into a JS object. + static void GetDeviceInfo(CellularNetwork* network, + DictionaryValue* value); + static bool ShouldReportDeviceState(std::string* state, std::string* error); + + // Performs activation state cellular device evaluation. + // Returns false if device activation failed. In this case |error| + // will contain error message to be reported to Web UI. + static bool EvaluateCellularDeviceState(bool* report_status, + std::string* state, + std::string* error); + // Finds cellular network given device |meid|, reattach network change + // observer if |reattach_observer| flag is set. + CellularNetwork* FindCellularNetworkByMeid(const std::string& meid, + bool reattach_observer); + + // Returns next reconnection state based on the current activation phase. + static PlanActivationState GetNextReconnectState(PlanActivationState state); + static const char* GetStateDescription(PlanActivationState state); + + scoped_refptr<CellularConfigDocument> cellular_config_; + // Internal handler state. + PlanActivationState state_; + // MEID of cellular device to activate. + std::string meid_; + // Service path of network begin activated. Please note that the path can + // change during the activation process even though it is still representing + // the same service. + std::string service_path_; + // Flags that control if wifi and ethernet connection needs to be restored + // after the activation of cellular network. + bool reenable_wifi_; + bool reenable_ethernet_; + bool reenable_cert_check_; + bool evaluating_; + // True if we think that another tab is already running activation. + bool already_running_; + // True activation process had been terminated. + bool terminated_; + // Connection retry counter. + int connection_retry_count_; + // Post payment reconnect wait counters. + int reconnect_wait_count_; + // Payment portal reload/reconnect attempt count. + int payment_reconnect_count_; + // Activation retry attempt count; + int activation_attempt_; + // Connection start time. + base::Time connection_start_time_; + // Timer that monitors reconnection timeouts. + base::RepeatingTimer<MobileActivator> reconnect_timer_; + + ObserverList<Observer> observers_; + + DISALLOW_COPY_AND_ASSIGN(MobileActivator); +}; + +} // namespace chromeos + +#endif // CHROME_BROWSER_CHROMEOS_MOBILE_MOBILE_ACTIVATOR_H_ diff --git a/chrome/browser/chromeos/network_message_observer.cc b/chrome/browser/chromeos/network_message_observer.cc index 501ddb55..e659b77 100644 --- a/chrome/browser/chromeos/network_message_observer.cc +++ b/chrome/browser/chromeos/network_message_observer.cc @@ -175,8 +175,9 @@ bool NetworkMessageObserver::IsApplicableBackupPlan( return has_data && will_apply; } -void NetworkMessageObserver::OpenMobileSetupPage(const ListValue* args) { - ash::Shell::GetInstance()->delegate()->OpenMobileSetup(); +void NetworkMessageObserver::OpenMobileSetupPage( + const std::string& service_path, const ListValue* args) { + ash::Shell::GetInstance()->delegate()->OpenMobileSetup(service_path); } void NetworkMessageObserver::OpenMoreInfoPage(const ListValue* args) { @@ -220,11 +221,14 @@ void NetworkMessageObserver::ShowNeedsPlanNotification( IDS_NETWORK_NO_DATA_PLAN_MESSAGE, UTF8ToUTF16(cellular->name())), l10n_util::GetStringUTF16(IDS_NETWORK_PURCHASE_MORE_MESSAGE), - base::Bind(&NetworkMessageObserver::OpenMobileSetupPage, AsWeakPtr()), + base::Bind(&NetworkMessageObserver::OpenMobileSetupPage, + AsWeakPtr(), + cellular->service_path()), false, false); } void NetworkMessageObserver::ShowNoDataNotification( + const CellularNetwork* cellular, CellularDataPlanType plan_type) { notification_low_data_->Hide(); // Hide previous low data notification. string16 message = plan_type == CELLULAR_DATA_PLAN_UNLIMITED ? @@ -233,7 +237,9 @@ void NetworkMessageObserver::ShowNoDataNotification( ASCIIToUTF16("0")); notification_no_data_->Show(message, l10n_util::GetStringUTF16(IDS_NETWORK_PURCHASE_MORE_MESSAGE), - base::Bind(&NetworkMessageObserver::OpenMobileSetupPage, AsWeakPtr()), + base::Bind(&NetworkMessageObserver::OpenMobileSetupPage, + AsWeakPtr(), + cellular->service_path()), false, false); } @@ -325,7 +331,7 @@ void NetworkMessageObserver::OnCellularDataPlanChanged(NetworkLibrary* cros) { // If previously, we had low data, we know that a plan was near expiring. // In that case, because the plan disappeared, we assume that it expired. if (cellular_data_left_ == CellularNetwork::DATA_LOW) { - ShowNoDataNotification(cellular_data_plan_type_); + ShowNoDataNotification(cellular, cellular_data_plan_type_); } else if (cellular->needs_new_plan()) { ShowNeedsPlanNotification(cellular); } @@ -356,7 +362,7 @@ void NetworkMessageObserver::OnCellularDataPlanChanged(NetworkLibrary* cros) { } if (cellular->data_left() == CellularNetwork::DATA_NONE) { - ShowNoDataNotification(current_plan->plan_type); + ShowNoDataNotification(cellular, current_plan->plan_type); } else if (cellular->data_left() == CellularNetwork::DATA_VERY_LOW) { // Only show low data notification if we transition to very low data // and we are on the same plan. This is so that users don't get a diff --git a/chrome/browser/chromeos/network_message_observer.h b/chrome/browser/chromeos/network_message_observer.h index 53264b6..e340dd1 100644 --- a/chrome/browser/chromeos/network_message_observer.h +++ b/chrome/browser/chromeos/network_message_observer.h @@ -35,11 +35,13 @@ class NetworkMessageObserver static bool IsApplicableBackupPlan(const CellularDataPlan* plan, const CellularDataPlan* other_plan); private: - virtual void OpenMobileSetupPage(const base::ListValue* args); + virtual void OpenMobileSetupPage(const std::string& service_path, + const base::ListValue* args); virtual void OpenMoreInfoPage(const base::ListValue* args); virtual void InitNewPlan(const CellularDataPlan* plan); virtual void ShowNeedsPlanNotification(const CellularNetwork* cellular); - virtual void ShowNoDataNotification(CellularDataPlanType plan_type); + virtual void ShowNoDataNotification(const CellularNetwork* cellular, + CellularDataPlanType plan_type); virtual void ShowLowDataNotification(const CellularDataPlan* plan); // NetworkLibrary::NetworkManagerObserver implementation. diff --git a/chrome/browser/chromeos/offline/offline_load_page.cc b/chrome/browser/chromeos/offline/offline_load_page.cc index 59bcf8e..ab9ca2d 100644 --- a/chrome/browser/chromeos/offline/offline_load_page.cc +++ b/chrome/browser/chromeos/offline/offline_load_page.cc @@ -188,8 +188,6 @@ void OfflineLoadPage::CommandReceived(const std::string& cmd) { interstitial_page_->DontProceed(); } else if (command == "open_network_settings") { ash::Shell::GetInstance()->tray_delegate()->ShowNetworkSettings(); - } else if (command == "open_activate_broadband") { - ash::Shell::GetInstance()->delegate()->OpenMobileSetup(); } else { LOG(WARNING) << "Unknown command:" << cmd; } diff --git a/chrome/browser/chromeos/status/network_menu.cc b/chrome/browser/chromeos/status/network_menu.cc index d73691f..cd47df5 100644 --- a/chrome/browser/chromeos/status/network_menu.cc +++ b/chrome/browser/chromeos/status/network_menu.cc @@ -95,7 +95,8 @@ void ActivateCellular(const chromeos::CellularNetwork* cellular) { if (!chromeos::UserManager::Get()->IsSessionStarted()) return; - ash::Shell::GetInstance()->delegate()->OpenMobileSetup(); + ash::Shell::GetInstance()->delegate()->OpenMobileSetup( + cellular->service_path()); } // Decides whether a network should be highlighted in the UI. diff --git a/chrome/browser/resources/options2/chromeos/internet_detail.js b/chrome/browser/resources/options2/chromeos/internet_detail.js index da131d5..3d71534 100644 --- a/chrome/browser/resources/options2/chromeos/internet_detail.js +++ b/chrome/browser/resources/options2/chromeos/internet_detail.js @@ -81,16 +81,16 @@ cr.define('options.internet', function() { initializePage: function() { OptionsPage.prototype.initializePage.call(this); options.internet.CellularPlanElement.decorate($('plan-list')); - this.initializePageContents_(); - this.showNetworkDetails_(); + var params = parseQueryParams(window.location); + this.initializePageContents_(params); + this.showNetworkDetails_(params); }, /** * Auto-activates the network details dialog if network information * is included in the URL. */ - showNetworkDetails_: function() { - var params = parseQueryParams(window.location); + showNetworkDetails_: function(params) { var servicePath = params.servicePath; var networkType = params.networkType; if (!servicePath || !servicePath.length || @@ -103,7 +103,7 @@ cr.define('options.internet', function() { /** * Initializes the contents of the page. */ - initializePageContents_: function() { + initializePageContents_: function(params) { $('details-internet-dismiss').addEventListener('click', function(event) { DetailsInternetPage.setDetails(); }); @@ -124,7 +124,7 @@ cr.define('options.internet', function() { }); $('buyplan-details').addEventListener('click', function(event) { - chrome.send('buyDataPlan'); + chrome.send('buyDataPlan', [params.servicePath]); OptionsPage.closeOverlay(); }); diff --git a/chrome/browser/ui/views/ash/chrome_shell_delegate.cc b/chrome/browser/ui/views/ash/chrome_shell_delegate.cc index 0d4cea9..cf68170 100644 --- a/chrome/browser/ui/views/ash/chrome_shell_delegate.cc +++ b/chrome/browser/ui/views/ash/chrome_shell_delegate.cc @@ -186,16 +186,18 @@ void ChromeShellDelegate::OpenCrosh() { #endif } -void ChromeShellDelegate::OpenMobileSetup() { +void ChromeShellDelegate::OpenMobileSetup(const std::string& service_path) { #if defined(OS_CHROMEOS) Browser* browser = browser::FindOrCreateTabbedBrowser( ProfileManager::GetDefaultProfileOrOffTheRecord()); if (CommandLine::ForCurrentProcess()->HasSwitch( switches::kEnableMobileSetupDialog)) { - MobileSetupDialog::Show(); + MobileSetupDialog::Show(service_path); } else { + std::string url(chrome::kChromeUIMobileSetupURL); + url.append(service_path); browser->OpenURL( - content::OpenURLParams(GURL(chrome::kChromeUIMobileSetupURL), + content::OpenURLParams(GURL(url), content::Referrer(), NEW_FOREGROUND_TAB, content::PAGE_TRANSITION_LINK, diff --git a/chrome/browser/ui/views/ash/chrome_shell_delegate.h b/chrome/browser/ui/views/ash/chrome_shell_delegate.h index ee0de4d..8d1c9a5 100644 --- a/chrome/browser/ui/views/ash/chrome_shell_delegate.h +++ b/chrome/browser/ui/views/ash/chrome_shell_delegate.h @@ -42,7 +42,7 @@ class ChromeShellDelegate : public ash::ShellDelegate, virtual void Search() OVERRIDE; virtual void OpenFileManager() OVERRIDE; virtual void OpenCrosh() OVERRIDE; - virtual void OpenMobileSetup() OVERRIDE; + virtual void OpenMobileSetup(const std::string& service_path) OVERRIDE; virtual void RestoreTab() OVERRIDE; virtual void ShowKeyboardOverlay() OVERRIDE; virtual void ShowTaskManager() OVERRIDE; diff --git a/chrome/browser/ui/webui/chromeos/mobile_setup_dialog.cc b/chrome/browser/ui/webui/chromeos/mobile_setup_dialog.cc index 4217979..12e1adf 100644 --- a/chrome/browser/ui/webui/chromeos/mobile_setup_dialog.cc +++ b/chrome/browser/ui/webui/chromeos/mobile_setup_dialog.cc @@ -7,6 +7,7 @@ #include "base/bind.h" #include "base/memory/singleton.h" #include "base/utf_string_conversions.h" +#include "chrome/browser/chromeos/mobile/mobile_activator.h" #include "chrome/browser/platform_util.h" #include "chrome/browser/profiles/profile_manager.h" #include "chrome/browser/ui/browser_dialogs.h" @@ -19,15 +20,18 @@ #include "ui/views/widget/widget.h" #include "ui/web_dialogs/web_dialog_delegate.h" +using chromeos::CellularNetwork; +using chromeos::MobileActivator; using content::BrowserThread; using content::WebContents; using content::WebUIMessageHandler; using ui::WebDialogDelegate; -class MobileSetupDialogDelegate : public WebDialogDelegate { +class MobileSetupDialogDelegate : public WebDialogDelegate, + public MobileActivator::Observer { public: static MobileSetupDialogDelegate* GetInstance(); - void ShowDialog(); + void ShowDialog(const std::string& service_path); protected: friend struct DefaultSingletonTraits<MobileSetupDialogDelegate>; @@ -45,6 +49,9 @@ class MobileSetupDialogDelegate : public WebDialogDelegate { std::vector<WebUIMessageHandler*>* handlers) const OVERRIDE; virtual void GetDialogSize(gfx::Size* size) const OVERRIDE; virtual std::string GetDialogArgs() const OVERRIDE; + virtual void OnDialogShown( + content::WebUI* webui, + content::RenderViewHost* render_view_host) OVERRIDE; virtual void OnDialogClosed(const std::string& json_retval) OVERRIDE; virtual void OnCloseContents(WebContents* source, bool* out_close_dialog) OVERRIDE; @@ -52,16 +59,23 @@ class MobileSetupDialogDelegate : public WebDialogDelegate { virtual bool HandleContextMenu( const content::ContextMenuParams& params) OVERRIDE; + // MobileActivator::Observer overrides. + virtual void OnActivationStateChanged( + CellularNetwork* network, + MobileActivator::PlanActivationState state, + const std::string& error_description) OVERRIDE; + private: gfx::NativeWindow dialog_window_; - + // Cellular network service path. + std::string service_path_; DISALLOW_COPY_AND_ASSIGN(MobileSetupDialogDelegate); }; // static -void MobileSetupDialog::Show() { +void MobileSetupDialog::Show(const std::string& service_path) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); - MobileSetupDialogDelegate::GetInstance()->ShowDialog(); + MobileSetupDialogDelegate::GetInstance()->ShowDialog(service_path); } // static @@ -74,9 +88,11 @@ MobileSetupDialogDelegate::MobileSetupDialogDelegate() : dialog_window_(NULL) { } MobileSetupDialogDelegate::~MobileSetupDialogDelegate() { + MobileActivator::GetInstance()->RemoveObserver(this); } -void MobileSetupDialogDelegate::ShowDialog() { +void MobileSetupDialogDelegate::ShowDialog(const std::string& service_path) { + service_path_ = service_path; dialog_window_ = browser::ShowWebDialog( NULL, ProfileManager::GetDefaultProfileOrOffTheRecord(), @@ -93,11 +109,13 @@ string16 MobileSetupDialogDelegate::GetDialogTitle() const { } GURL MobileSetupDialogDelegate::GetDialogContentURL() const { - return GURL(chrome::kChromeUIMobileSetupURL); + std::string url(chrome::kChromeUIMobileSetupURL); + url.append(service_path_); + return GURL(url); } void MobileSetupDialogDelegate::GetWebUIMessageHandlers( - std::vector<WebUIMessageHandler*>* handlers) const{ + std::vector<WebUIMessageHandler*>* handlers) const { } void MobileSetupDialogDelegate::GetDialogSize(gfx::Size* size) const { @@ -108,13 +126,20 @@ std::string MobileSetupDialogDelegate::GetDialogArgs() const { return std::string(); } +void MobileSetupDialogDelegate::OnDialogShown( + content::WebUI* webui, content::RenderViewHost* render_view_host) { + MobileActivator::GetInstance()->AddObserver(this); +} + + void MobileSetupDialogDelegate::OnDialogClosed(const std::string& json_retval) { + MobileActivator::GetInstance()->RemoveObserver(this); dialog_window_ = NULL; } void MobileSetupDialogDelegate::OnCloseContents(WebContents* source, bool* out_close_dialog) { - if (!dialog_window_) { + if (!dialog_window_ || !MobileActivator::GetInstance()->RunningActivation()) { *out_close_dialog = true; return; } @@ -133,3 +158,9 @@ bool MobileSetupDialogDelegate::HandleContextMenu( const content::ContextMenuParams& params) { return true; } + +void MobileSetupDialogDelegate::OnActivationStateChanged( + CellularNetwork* network, + MobileActivator::PlanActivationState state, + const std::string& error_description) { +} diff --git a/chrome/browser/ui/webui/chromeos/mobile_setup_dialog.h b/chrome/browser/ui/webui/chromeos/mobile_setup_dialog.h index 0d39e6a..611b685 100644 --- a/chrome/browser/ui/webui/chromeos/mobile_setup_dialog.h +++ b/chrome/browser/ui/webui/chromeos/mobile_setup_dialog.h @@ -13,7 +13,7 @@ class MobileSetupDialog { public: - static void Show(); + static void Show(const std::string& service_path); private: DISALLOW_COPY_AND_ASSIGN(MobileSetupDialog); diff --git a/chrome/browser/ui/webui/chromeos/mobile_setup_ui.cc b/chrome/browser/ui/webui/chromeos/mobile_setup_ui.cc index 3158f64..952defd 100644 --- a/chrome/browser/ui/webui/chromeos/mobile_setup_ui.cc +++ b/chrome/browser/ui/webui/chromeos/mobile_setup_ui.cc @@ -11,7 +11,6 @@ #include "base/bind.h" #include "base/bind_helpers.h" #include "base/file_util.h" -#include "base/json/json_reader.h" #include "base/json/json_writer.h" #include "base/logging.h" #include "base/memory/ref_counted_memory.h" @@ -19,13 +18,11 @@ #include "base/metrics/histogram.h" #include "base/string_piece.h" #include "base/string_util.h" -#include "base/timer.h" #include "base/utf_string_conversions.h" #include "base/values.h" -#include "chrome/browser/browser_process.h" #include "chrome/browser/chromeos/cros/cros_library.h" #include "chrome/browser/chromeos/cros/network_library.h" -#include "chrome/browser/prefs/pref_service.h" +#include "chrome/browser/chromeos/mobile/mobile_activator.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/ui/browser_list.h" #include "chrome/browser/ui/webui/chrome_url_data_manager.h" @@ -47,6 +44,9 @@ #include "ui/base/layout.h" #include "ui/base/resource/resource_bundle.h" +using chromeos::CellularNetwork; +using chromeos::CrosLibrary; +using chromeos::MobileActivator; using content::BrowserThread; using content::RenderViewHost; using content::WebContents; @@ -67,62 +67,6 @@ const char kJsPortalFrameLoadFailedCallback[] = const char kJsPortalFrameLoadCompletedCallback[] = "mobile.MobileSetup.portalFrameLoadCompleted"; -// Error codes matching codes defined in the cellular config file. -const char kErrorDefault[] = "default"; -const char kErrorBadConnectionPartial[] = "bad_connection_partial"; -const char kErrorBadConnectionActivated[] = "bad_connection_activated"; -const char kErrorRoamingOnConnection[] = "roaming_connection"; -const char kErrorNoEVDO[] = "no_evdo"; -const char kErrorRoamingActivation[] = "roaming_activation"; -const char kErrorRoamingPartiallyActivated[] = "roaming_partially_activated"; -const char kErrorNoService[] = "no_service"; -const char kErrorDisabled[] = "disabled"; -const char kErrorNoDevice[] = "no_device"; -const char kFailedPaymentError[] = "failed_payment"; -const char kFailedConnectivity[] = "connectivity"; -const char kErrorAlreadyRunning[] = "already_running"; - -// Cellular configuration file path. -const char kCellularConfigPath[] = - "/usr/share/chromeos-assets/mobile/mobile_config.json"; - -// Cellular config file field names. -const char kVersionField[] = "version"; -const char kErrorsField[] = "errors"; - -// Number of times we will retry to restart the activation process in case -// there is no connectivity in the restricted pool. -const int kMaxActivationAttempt = 3; -// Number of times we will retry to reconnect if connection fails. -const int kMaxConnectionRetry = 10; -// Number of times we will retry to reconnect and reload payment portal page. -const int kMaxPortalReconnectCount = 5; -// Number of times we will retry to reconnect if connection fails. -const int kMaxConnectionRetryOTASP = 30; -// Number of times we will retry to reconnect after payment is processed. -const int kMaxReconnectAttemptOTASP = 30; -// Reconnect retry delay (after payment is processed). -const int kPostPaymentReconnectDelayMS = 30000; // 30s. -// Connection timeout in seconds. -const int kConnectionTimeoutSeconds = 45; -// Reconnect delay. -const int kReconnectDelayMS = 3000; -// Reconnect timer delay. -const int kReconnectTimerDelayMS = 5000; -// Reconnect delay after previous failure. -const int kFailedReconnectDelayMS = 10000; -// Retry delay after failed OTASP attempt. -const int kOTASPRetryDelay = 20000; - -chromeos::CellularNetwork* GetCellularNetwork() { - chromeos::NetworkLibrary* lib = chromeos::CrosLibrary::Get()-> - GetNetworkLibrary(); - if (lib->cellular_networks().begin() != lib->cellular_networks().end()) { - return *(lib->cellular_networks().begin()); - } - return NULL; -} - } // namespace // Observes IPC messages from the rederer and notifies JS if frame loading error @@ -170,32 +114,9 @@ class PortalFrameLoadObserver : public content::RenderViewHostObserver { DISALLOW_COPY_AND_ASSIGN(PortalFrameLoadObserver); }; -class CellularConfigDocument - : public base::RefCountedThreadSafe<CellularConfigDocument> { - public: - CellularConfigDocument() {} - - // Return error message for a given code. - std::string GetErrorMessage(const std::string& code); - void LoadCellularConfigFile(); - const std::string& version() { return version_; } - - private: - typedef std::map<std::string, std::string> ErrorMap; - - void SetErrorMap(const ErrorMap& map); - bool LoadFromFile(const FilePath& config_path); - - std::string version_; - ErrorMap error_map_; - base::Lock config_lock_; - - DISALLOW_COPY_AND_ASSIGN(CellularConfigDocument); -}; - class MobileSetupUIHTMLSource : public ChromeURLDataManager::DataSource { public: - explicit MobileSetupUIHTMLSource(const std::string& service_path); + MobileSetupUIHTMLSource(); // Called when the network layer has requested a resource underneath // the path we registered. @@ -209,256 +130,66 @@ class MobileSetupUIHTMLSource : public ChromeURLDataManager::DataSource { private: virtual ~MobileSetupUIHTMLSource() {} - std::string service_path_; DISALLOW_COPY_AND_ASSIGN(MobileSetupUIHTMLSource); }; // The handler for Javascript messages related to the "register" view. class MobileSetupHandler : public WebUIMessageHandler, - public chromeos::NetworkLibrary::NetworkManagerObserver, - public chromeos::NetworkLibrary::NetworkObserver, + public MobileActivator::Observer, public base::SupportsWeakPtr<MobileSetupHandler> { public: - explicit MobileSetupHandler(const std::string& service_path); + MobileSetupHandler(); virtual ~MobileSetupHandler(); - // Init work after Attach. - void StartActivationOnUIThread(); - // WebUIMessageHandler implementation. virtual void RegisterMessages() OVERRIDE; - // NetworkLibrary::NetworkManagerObserver implementation. - virtual void OnNetworkManagerChanged(chromeos::NetworkLibrary* obj) OVERRIDE; - // NetworkLibrary::NetworkObserver implementation. - virtual void OnNetworkChanged(chromeos::NetworkLibrary* obj, - const chromeos::Network* network) OVERRIDE; - private: - typedef enum PlanActivationState { - PLAN_ACTIVATION_PAGE_LOADING = -1, - PLAN_ACTIVATION_START = 0, - PLAN_ACTIVATION_TRYING_OTASP = 1, - PLAN_ACTIVATION_RECONNECTING_OTASP_TRY = 2, - PLAN_ACTIVATION_INITIATING_ACTIVATION = 3, - PLAN_ACTIVATION_RECONNECTING = 4, - PLAN_ACTIVATION_PAYMENT_PORTAL_LOADING = 5, - PLAN_ACTIVATION_SHOWING_PAYMENT = 6, - PLAN_ACTIVATION_RECONNECTING_PAYMENT = 7, - PLAN_ACTIVATION_DELAY_OTASP = 8, - PLAN_ACTIVATION_START_OTASP = 9, - PLAN_ACTIVATION_OTASP = 10, - PLAN_ACTIVATION_RECONNECTING_OTASP = 11, - PLAN_ACTIVATION_DONE = 12, - PLAN_ACTIVATION_ERROR = 0xFF, - } PlanActivationState; + // Changes internal state. + void OnActivationStateChanged(CellularNetwork* network, + MobileActivator::PlanActivationState new_state, + const std::string& error_description); // Handlers for JS WebUI messages. void HandleSetTransactionStatus(const ListValue* args); void HandleStartActivation(const ListValue* args); void HandlePaymentPortalLoad(const ListValue* args); - void SetTransactionStatus(const std::string& status); - // Starts activation. - void StartActivation(); - // Retried OTASP. - void RetryOTASP(); - // Continues activation process. This method is called after we disconnect - // due to detected connectivity issue to kick off reconnection. - void ContinueConnecting(int delay); // Sends message to host registration page with system/user info data. void SendDeviceInfo(); - // Callback for when |reconnect_timer_| fires. - void ReconnectTimerFired(); - // Starts OTASP process. - void StartOTASP(); - // Checks if we need to reconnect due to failed connection attempt. - bool NeedsReconnecting(chromeos::CellularNetwork* network, - PlanActivationState* new_state, - std::string* error_description); - // Disconnect from network. - void DisconnectFromNetwork(chromeos::CellularNetwork* network); - // Connects to cellular network, resets connection timer. - bool ConnectToNetwork(chromeos::CellularNetwork* network, int delay); - // Forces disconnect / reconnect when we detect portal connectivity issues. - void ForceReconnect(chromeos::CellularNetwork* network, int delay); - // Reports connection timeout. - bool ConnectionTimeout(); - // Verify the state of cellular network and modify internal state. - void EvaluateCellularNetwork(chromeos::CellularNetwork* network); - // Finds cellular network given device |meid|, reattach network change - // observer if |reattach_observer| flag is set. - chromeos::CellularNetwork* FindCellularNetworkByMeid(const std::string& meid, - bool reattach_observer); - // Check the current cellular network for error conditions. - bool GotActivationError(chromeos::CellularNetwork* network, - std::string* error); - // Sends status updates to WebUI page. - void UpdatePage(chromeos::CellularNetwork* network, - const std::string& error_description); - // Changes internal state. - void ChangeState(chromeos::CellularNetwork* network, - PlanActivationState new_state, - const std::string& error_description); - // Prepares network devices for cellular activation process. - void SetupActivationProcess(chromeos::CellularNetwork* network); - // Disables ethernet and wifi newtorks since they interefere with - // detection of restricted pool on cellular side. - void DisableOtherNetworks(); - // Resets network devices after cellular activation process. - // |network| should be NULL if the activation process failed. - void CompleteActivation(chromeos::CellularNetwork* network); - // Control routines for handling other types of connections during - // cellular activation. - void ReEnableOtherConnections(); - // Return error message for a given code. - std::string GetErrorMessage(const std::string& code); - // Converts the currently active CellularNetwork device into a JS object. - static void GetDeviceInfo(chromeos::CellularNetwork* network, + static void GetDeviceInfo(CellularNetwork* network, DictionaryValue* value); - static bool ShouldReportDeviceState(std::string* state, std::string* error); - - // Performs activation state cellular device evaluation. - // Returns false if device activation failed. In this case |error| - // will contain error message to be reported to Web UI. - static bool EvaluateCellularDeviceState(bool* report_status, - std::string* state, - std::string* error); - - // Returns next reconnection state based on the current activation phase. - static PlanActivationState GetNextReconnectState(PlanActivationState state); - static const char* GetStateDescription(PlanActivationState state); - - scoped_refptr<CellularConfigDocument> cellular_config_; - // Internal handler state. - PlanActivationState state_; - std::string meid_; - std::string service_path_; - // Flags that control if wifi and ethernet connection needs to be restored - // after the activation of cellular network. - bool reenable_wifi_; - bool reenable_ethernet_; - bool reenable_cert_check_; - bool evaluating_; - // True if we think that another tab is already running activation. - bool already_running_; - // Connection retry counter. - int connection_retry_count_; - // Post payment reconnect wait counters. - int reconnect_wait_count_; - // Payment portal reload/reconnect attempt count. - int payment_reconnect_count_; - // Activation retry attempt count; - int activation_attempt_; - // Connection start time. - base::Time connection_start_time_; - // Timer that monitors reconnection timeouts. - base::RepeatingTimer<MobileSetupHandler> reconnect_timer_; DISALLOW_COPY_AND_ASSIGN(MobileSetupHandler); }; //////////////////////////////////////////////////////////////////////////////// // -// CellularConfigDocument -// -//////////////////////////////////////////////////////////////////////////////// - -std::string CellularConfigDocument::GetErrorMessage(const std::string& code) { - base::AutoLock create(config_lock_); - ErrorMap::iterator iter = error_map_.find(code); - if (iter == error_map_.end()) - return code; - return iter->second; -} - -void CellularConfigDocument::LoadCellularConfigFile() { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); - // Load partner customization startup manifest if it is available. - FilePath config_path(kCellularConfigPath); - if (!file_util::PathExists(config_path)) - return; - - if (LoadFromFile(config_path)) { - DVLOG(1) << "Cellular config file loaded: " << kCellularConfigPath; - } else { - LOG(ERROR) << "Error loading cellular config file: " << - kCellularConfigPath; - } -} - -bool CellularConfigDocument::LoadFromFile(const FilePath& config_path) { - std::string config; - if (!file_util::ReadFileToString(config_path, &config)) - return false; - - scoped_ptr<Value> root( - base::JSONReader::Read(config, base::JSON_ALLOW_TRAILING_COMMAS)); - DCHECK(root.get() != NULL); - if (!root.get() || root->GetType() != Value::TYPE_DICTIONARY) { - LOG(WARNING) << "Bad cellular config file"; - return false; - } - - DictionaryValue* root_dict = static_cast<DictionaryValue*>(root.get()); - if (!root_dict->GetString(kVersionField, &version_)) { - LOG(WARNING) << "Cellular config file missing version"; - return false; - } - ErrorMap error_map; - DictionaryValue* errors = NULL; - if (!root_dict->GetDictionary(kErrorsField, &errors)) - return false; - for (DictionaryValue::key_iterator keys = errors->begin_keys(); - keys != errors->end_keys(); - ++keys) { - std::string value; - if (!errors->GetString(*keys, &value)) { - LOG(WARNING) << "Bad cellular config error value"; - return false; - } - error_map.insert(ErrorMap::value_type(*keys, value)); - } - SetErrorMap(error_map); - return true; -} - -void CellularConfigDocument::SetErrorMap( - const ErrorMap& map) { - base::AutoLock create(config_lock_); - error_map_.clear(); - error_map_.insert(map.begin(), map.end()); -} - -//////////////////////////////////////////////////////////////////////////////// -// // MobileSetupUIHTMLSource // //////////////////////////////////////////////////////////////////////////////// -MobileSetupUIHTMLSource::MobileSetupUIHTMLSource( - const std::string& service_path) - : DataSource(chrome::kChromeUIMobileSetupHost, MessageLoop::current()), - service_path_(service_path) { +MobileSetupUIHTMLSource::MobileSetupUIHTMLSource() + : DataSource(chrome::kChromeUIMobileSetupHost, MessageLoop::current()) { } void MobileSetupUIHTMLSource::StartDataRequest(const std::string& path, bool is_incognito, int request_id) { - chromeos::CellularNetwork* network = - chromeos::CrosLibrary::Get()->GetNetworkLibrary()-> - FindCellularNetworkByPath(service_path_); - - // If we are activating, shutting down, or logging in, |network| may not - // be available. + CellularNetwork* network = !path.size() ? NULL : + CrosLibrary::Get()-> + GetNetworkLibrary()->FindCellularNetworkByPath(path); if (!network || !network->SupportsActivation()) { + LOG(WARNING) << "Can't find device to activate for service path " << path; scoped_refptr<base::RefCountedBytes> html_bytes(new base::RefCountedBytes); SendResponse(request_id, html_bytes); return; } + + LOG(WARNING) << "Activating mobile service " << path; DictionaryValue strings; strings.SetString("title", l10n_util::GetStringUTF16(IDS_MOBILE_SETUP_TITLE)); strings.SetString("connecting_header", @@ -497,30 +228,30 @@ void MobileSetupUIHTMLSource::StartDataRequest(const std::string& path, // MobileSetupHandler // //////////////////////////////////////////////////////////////////////////////// -MobileSetupHandler::MobileSetupHandler(const std::string& service_path) - : cellular_config_(new CellularConfigDocument()), - state_(PLAN_ACTIVATION_PAGE_LOADING), - service_path_(service_path), - reenable_wifi_(false), - reenable_ethernet_(false), - reenable_cert_check_(false), - evaluating_(false), - already_running_(false), - connection_retry_count_(0), - reconnect_wait_count_(0), - payment_reconnect_count_(0), - activation_attempt_(0) { +MobileSetupHandler::MobileSetupHandler() { + MobileActivator::GetInstance()->AddObserver(this); } MobileSetupHandler::~MobileSetupHandler() { - reconnect_timer_.Stop(); - chromeos::NetworkLibrary* lib = - chromeos::CrosLibrary::Get()->GetNetworkLibrary(); - lib->RemoveNetworkManagerObserver(this); - lib->RemoveObserverForAllNetworks(this); - if (lib->IsLocked()) - lib->Unlock(); - ReEnableOtherConnections(); + MobileActivator::GetInstance()->RemoveObserver(this); + MobileActivator::GetInstance()->TerminateActivation(); +} + +void MobileSetupHandler::OnActivationStateChanged( + CellularNetwork* network, + MobileActivator::PlanActivationState state, + const std::string& error_description) { + if (!web_ui()) + return; + + DictionaryValue device_dict; + if (network) + GetDeviceInfo(network, &device_dict); + device_dict.SetInteger("state", state); + if (error_description.length()) + device_dict.SetString("error", error_description); + web_ui()->CallJavascriptFunction( + kJsDeviceStatusChangedCallback, device_dict); } void MobileSetupHandler::RegisterMessages() { @@ -535,32 +266,17 @@ void MobileSetupHandler::RegisterMessages() { base::Unretained(this))); } -void MobileSetupHandler::OnNetworkManagerChanged( - chromeos::NetworkLibrary* cros) { - if (state_ == PLAN_ACTIVATION_PAGE_LOADING) +void MobileSetupHandler::HandleStartActivation(const ListValue* args) { + if (!web_ui()) return; - // Note that even though we get here when the service has - // reappeared after disappearing earlier in the activation - // process, there's no need to re-establish the NetworkObserver, - // because the service path remains the same. - EvaluateCellularNetwork(FindCellularNetworkByMeid(meid_, true)); -} -void MobileSetupHandler::OnNetworkChanged(chromeos::NetworkLibrary* cros, - const chromeos::Network* network) { - if (state_ == PLAN_ACTIVATION_PAGE_LOADING) + std::string path = web_ui()->GetWebContents()->GetURL().path(); + if (!path.size()) return; - DCHECK(network && network->type() == chromeos::TYPE_CELLULAR); - EvaluateCellularNetwork( - static_cast<chromeos::CellularNetwork*>( - const_cast<chromeos::Network*>(network))); -} -void MobileSetupHandler::HandleStartActivation(const ListValue* args) { - BrowserThread::PostTaskAndReply(BrowserThread::FILE, FROM_HERE, - base::Bind(&CellularConfigDocument::LoadCellularConfigFile, - cellular_config_.get()), - base::Bind(&MobileSetupHandler::StartActivationOnUIThread, AsWeakPtr())); + LOG(WARNING) << "Starting activation for service " << path; + + MobileActivator::GetInstance()->InitiateActivation(path.substr(1)); } void MobileSetupHandler::HandleSetTransactionStatus(const ListValue* args) { @@ -571,9 +287,9 @@ void MobileSetupHandler::HandleSetTransactionStatus(const ListValue* args) { std::string status; if (!args->GetString(0, &status)) return; - BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, - base::Bind(&MobileSetupHandler::SetTransactionStatus, AsWeakPtr(), - status)); + + MobileActivator::GetInstance()->OnSetTransactionStatus( + LowerCaseEqualsASCII(status, kJsApiResultOK)); } void MobileSetupHandler::HandlePaymentPortalLoad(const ListValue* args) { @@ -584,812 +300,12 @@ void MobileSetupHandler::HandlePaymentPortalLoad(const ListValue* args) { std::string result; if (!args->GetString(0, &result)) return; - chromeos::CellularNetwork* network = FindCellularNetworkByMeid(meid_, true); - if (!network) { - ChangeState(NULL, PLAN_ACTIVATION_ERROR, - GetErrorMessage(kErrorNoService)); - return; - } - if (state_ == PLAN_ACTIVATION_PAYMENT_PORTAL_LOADING || - state_ == PLAN_ACTIVATION_SHOWING_PAYMENT) { - if (LowerCaseEqualsASCII(result, kJsApiResultOK)) { - payment_reconnect_count_ = 0; - ChangeState(network, PLAN_ACTIVATION_SHOWING_PAYMENT, std::string()); - } else { - payment_reconnect_count_++; - if (payment_reconnect_count_ > kMaxPortalReconnectCount) { - ChangeState(NULL, PLAN_ACTIVATION_ERROR, - GetErrorMessage(kErrorNoService)); - return; - } - // Disconnect now, this should force reconnection and we will retry to - // load the frame containing payment portal again. - DisconnectFromNetwork(network); - } - } else { - NOTREACHED() << "Called paymentPortalLoad while in unexpected state: " - << GetStateDescription(state_); - } -} - -chromeos::CellularNetwork* MobileSetupHandler::FindCellularNetworkByMeid( - const std::string& meid, bool reattach_observer) { - chromeos::NetworkLibrary* lib = - chromeos::CrosLibrary::Get()->GetNetworkLibrary(); - for (chromeos::CellularNetworkVector::const_iterator it = - lib->cellular_networks().begin(); - it != lib->cellular_networks().end(); ++it) { - const chromeos::NetworkDevice* device = - lib->FindNetworkDeviceByPath((*it)->device_path()); - if (device && meid == device->meid()) { - chromeos::CellularNetwork* network = *it; - // If service path has changed, reattach the event observer for this - // network service. - if (reattach_observer && service_path_ != network->service_path()) { - lib->RemoveObserverForAllNetworks(this); - lib->AddNetworkObserver(network->service_path(), this); - service_path_ = network->service_path(); - } - return network; - } - } - return NULL; -} - -void MobileSetupHandler::StartActivation() { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); - UMA_HISTOGRAM_COUNTS("Cellular.MobileSetupStart", 1); - chromeos::NetworkLibrary* lib = - chromeos::CrosLibrary::Get()->GetNetworkLibrary(); - chromeos::CellularNetwork* network = FindCellularNetworkByMeid(meid_, true); - // Check if we can start activation process. - if (!network || already_running_) { - std::string error; - if (already_running_) - error = kErrorAlreadyRunning; - else if (!lib->cellular_available()) - error = kErrorNoDevice; - else if (!lib->cellular_enabled()) - error = kErrorDisabled; - else - error = kErrorNoService; - ChangeState(NULL, PLAN_ACTIVATION_ERROR, GetErrorMessage(error)); - return; - } - - // Start monitoring network property changes. - lib->AddNetworkManagerObserver(this); - lib->RemoveObserverForAllNetworks(this); - lib->AddNetworkObserver(network->service_path(), this); - // Try to start with OTASP immediately if we have received payment recently. - state_ = lib->HasRecentCellularPlanPayment() ? - PLAN_ACTIVATION_START_OTASP : - PLAN_ACTIVATION_START; - EvaluateCellularNetwork(network); -} - -void MobileSetupHandler::RetryOTASP() { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); - DCHECK(state_ == PLAN_ACTIVATION_DELAY_OTASP); - StartOTASP(); -} - -void MobileSetupHandler::ContinueConnecting(int delay) { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); - chromeos::CellularNetwork* network = FindCellularNetworkByMeid(meid_, true); - if (network && network->connecting_or_connected()) { - EvaluateCellularNetwork(network); - } else { - ConnectToNetwork(network, delay); - } -} - -void MobileSetupHandler::SetTransactionStatus(const std::string& status) { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); - // The payment is received, try to reconnect and check the status all over - // again. - if (LowerCaseEqualsASCII(status, kJsApiResultOK) && - state_ == PLAN_ACTIVATION_SHOWING_PAYMENT) { - chromeos::NetworkLibrary* lib = - chromeos::CrosLibrary::Get()->GetNetworkLibrary(); - lib->SignalCellularPlanPayment(); - UMA_HISTOGRAM_COUNTS("Cellular.PaymentReceived", 1); - StartOTASP(); - } else { - UMA_HISTOGRAM_COUNTS("Cellular.PaymentFailed", 1); - } -} - -void MobileSetupHandler::StartOTASP() { - state_ = PLAN_ACTIVATION_START_OTASP; - chromeos::CellularNetwork* network = FindCellularNetworkByMeid(meid_, true); - if (network && - network->connected() && - network->activation_state() == chromeos::ACTIVATION_STATE_ACTIVATED) { - chromeos::CrosLibrary::Get()->GetNetworkLibrary()-> - DisconnectFromNetwork(network); - } else { - EvaluateCellularNetwork(network); - } -} - -void MobileSetupHandler::ReconnectTimerFired() { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); - // Permit network connection changes only in reconnecting states. - if (state_ != PLAN_ACTIVATION_RECONNECTING_OTASP_TRY && - state_ != PLAN_ACTIVATION_RECONNECTING && - state_ != PLAN_ACTIVATION_RECONNECTING_PAYMENT && - state_ != PLAN_ACTIVATION_RECONNECTING_OTASP) - return; - chromeos::CellularNetwork* network = FindCellularNetworkByMeid(meid_, true); - if (!network) { - // No service, try again since this is probably just transient condition. - LOG(WARNING) << "Service not present at reconnect attempt."; - } - EvaluateCellularNetwork(network); -} - -void MobileSetupHandler::DisconnectFromNetwork( - chromeos::CellularNetwork* network) { - DCHECK(network); - LOG(INFO) << "Disconnecting from: " << network->service_path(); - chromeos::CrosLibrary::Get()->GetNetworkLibrary()-> - DisconnectFromNetwork(network); - // Disconnect will force networks to be reevaluated, so - // we don't want to continue processing on this path anymore. - evaluating_ = false; -} - -bool MobileSetupHandler::NeedsReconnecting( - chromeos::CellularNetwork* network, - PlanActivationState* new_state, - std::string* error_description) { - DCHECK(network); - if (!network->failed() && !ConnectionTimeout()) - return false; - - // Try to reconnect again if reconnect failed, or if for some - // reasons we are still not connected after 45 seconds. - int max_retries = (state_ == PLAN_ACTIVATION_RECONNECTING_OTASP) ? - kMaxConnectionRetryOTASP : kMaxConnectionRetry; - if (connection_retry_count_ < max_retries) { - UMA_HISTOGRAM_COUNTS("Cellular.ConnectionRetry", 1); - ConnectToNetwork(network, kFailedReconnectDelayMS); - return true; - } - // We simply can't connect anymore after all these tries. - UMA_HISTOGRAM_COUNTS("Cellular.ConnectionFailed", 1); - *new_state = PLAN_ACTIVATION_ERROR; - *error_description = GetErrorMessage(kFailedConnectivity); - return false; -} - -bool MobileSetupHandler::ConnectToNetwork( - chromeos::CellularNetwork* network, - int delay) { - if (network && network->connecting_or_connected()) - return true; - // Permit network connection changes only in reconnecting states. - if (state_ != PLAN_ACTIVATION_RECONNECTING_OTASP_TRY && - state_ != PLAN_ACTIVATION_RECONNECTING && - state_ != PLAN_ACTIVATION_RECONNECTING_PAYMENT && - state_ != PLAN_ACTIVATION_RECONNECTING_OTASP) return false; - if (network) - LOG(INFO) << "Connecting to: " << network->service_path(); - connection_retry_count_++; - connection_start_time_ = base::Time::Now(); - if (!network) { - LOG(WARNING) << "Connect failed." - << (network ? network->service_path().c_str() : "no service"); - // If we coudn't connect during reconnection phase, try to reconnect - // with a delay (and try to reconnect if needed). - BrowserThread::PostDelayedTask(BrowserThread::UI, FROM_HERE, - base::Bind(&MobileSetupHandler::ContinueConnecting, AsWeakPtr(), delay), - base::TimeDelta::FromMilliseconds(delay)); - return false; - } - chromeos::CrosLibrary::Get()->GetNetworkLibrary()-> - ConnectToCellularNetwork(network); - return true; -} - -void MobileSetupHandler::ForceReconnect( - chromeos::CellularNetwork* network, - int delay) { - DCHECK(network); - UMA_HISTOGRAM_COUNTS("Cellular.ActivationRetry", 1); - // Reset reconnect metrics. - connection_retry_count_ = 0; - connection_start_time_ = base::Time(); - // First, disconnect... - LOG(INFO) << "Disconnecting from " << network->service_path(); - chromeos::CrosLibrary::Get()->GetNetworkLibrary()-> - DisconnectFromNetwork(network); - // Check the network state 3s after we disconnect to make sure. - BrowserThread::PostDelayedTask(BrowserThread::UI, FROM_HERE, - base::Bind(&MobileSetupHandler::ContinueConnecting, AsWeakPtr(), delay), - base::TimeDelta::FromMilliseconds(delay)); -} - -bool MobileSetupHandler::ConnectionTimeout() { - return (base::Time::Now() - - connection_start_time_).InSeconds() > kConnectionTimeoutSeconds; -} - -void MobileSetupHandler::EvaluateCellularNetwork( - chromeos::CellularNetwork* network) { - if (!web_ui()) - return; - - PlanActivationState new_state = state_; - if (!network) { - LOG(WARNING) << "Cellular service lost"; - if (state_ == PLAN_ACTIVATION_RECONNECTING_OTASP_TRY || - state_ == PLAN_ACTIVATION_RECONNECTING || - state_ == PLAN_ACTIVATION_RECONNECTING_PAYMENT || - state_ == PLAN_ACTIVATION_RECONNECTING_OTASP) { - // This might be the legit case when service is lost after activation. - // We need to make sure we force reconnection as soon as it shows up. - LOG(INFO) << "Force service reconnection"; - connection_start_time_ = base::Time(); - } - return; - } - - // Prevent this method from being called if it is already on the stack. - // This might happen on some state transitions (ie. connect, disconnect). - if (evaluating_) - return; - evaluating_ = true; - std::string error_description; - - LOG(WARNING) << "Cellular:\n service=" << network->GetStateString().c_str() - << "\n ui=" << GetStateDescription(state_) - << "\n activation=" << network->GetActivationStateString().c_str() - << "\n error=" << network->GetErrorString().c_str() - << "\n setvice_path=" << network->service_path().c_str(); - switch (state_) { - case PLAN_ACTIVATION_START: { - switch (network->activation_state()) { - case chromeos::ACTIVATION_STATE_ACTIVATED: { - if (network->disconnected()) { - new_state = PLAN_ACTIVATION_RECONNECTING; - } else if (network->connected()) { - if (network->restricted_pool()) { - new_state = PLAN_ACTIVATION_PAYMENT_PORTAL_LOADING; - } else { - new_state = PLAN_ACTIVATION_DONE; - } - } - break; - } - default: { - if (network->disconnected() || - network->state() == chromeos::STATE_ACTIVATION_FAILURE) { - new_state = (network->activation_state() == - chromeos::ACTIVATION_STATE_PARTIALLY_ACTIVATED) ? - PLAN_ACTIVATION_TRYING_OTASP : - PLAN_ACTIVATION_INITIATING_ACTIVATION; - } else if (network->connected()) { - DisconnectFromNetwork(network); - return; - } - break; - } - } - break; - } - case PLAN_ACTIVATION_START_OTASP: { - switch (network->activation_state()) { - case chromeos::ACTIVATION_STATE_PARTIALLY_ACTIVATED: { - if (network->disconnected()) { - new_state = PLAN_ACTIVATION_OTASP; - } else if (network->connected()) { - DisconnectFromNetwork(network); - return; - } - break; - } - case chromeos::ACTIVATION_STATE_ACTIVATED: - new_state = PLAN_ACTIVATION_RECONNECTING_OTASP; - break; - default: { - LOG(WARNING) << "Unexpected activation state for device " - << network->service_path().c_str(); - break; - } - } - break; - } - case PLAN_ACTIVATION_DELAY_OTASP: - // Just ignore any changes until the OTASP retry timer kicks in. - evaluating_ = false; - return; - case PLAN_ACTIVATION_INITIATING_ACTIVATION: { - switch (network->activation_state()) { - case chromeos::ACTIVATION_STATE_ACTIVATED: - case chromeos::ACTIVATION_STATE_PARTIALLY_ACTIVATED: - new_state = PLAN_ACTIVATION_START; - break; - case chromeos::ACTIVATION_STATE_NOT_ACTIVATED: - case chromeos::ACTIVATION_STATE_ACTIVATING: - // Wait in this state until activation state changes. - break; - default: - break; - } - break; - } - case PLAN_ACTIVATION_OTASP: - case PLAN_ACTIVATION_TRYING_OTASP: { - switch (network->activation_state()) { - case chromeos::ACTIVATION_STATE_ACTIVATED: - if (network->disconnected()) { - new_state = GetNextReconnectState(state_); - } else if (network->connected()) { - if (network->restricted_pool()) { - new_state = PLAN_ACTIVATION_PAYMENT_PORTAL_LOADING; - } else { - new_state = PLAN_ACTIVATION_DONE; - } - } - break; - case chromeos::ACTIVATION_STATE_PARTIALLY_ACTIVATED: - if (network->connected()) { - if (network->restricted_pool()) - new_state = PLAN_ACTIVATION_PAYMENT_PORTAL_LOADING; - } else { - new_state = GetNextReconnectState(state_); - } - break; - case chromeos::ACTIVATION_STATE_NOT_ACTIVATED: - case chromeos::ACTIVATION_STATE_ACTIVATING: - // Wait in this state until activation state changes. - break; - default: - break; - } - break; - } - case PLAN_ACTIVATION_RECONNECTING_OTASP_TRY: - case PLAN_ACTIVATION_RECONNECTING_PAYMENT: - case PLAN_ACTIVATION_RECONNECTING: { - if (network->connected()) { - // Make sure other networks are not interfering with our detection of - // restricted pool. - DisableOtherNetworks(); - // Wait until the service shows up and gets activated. - switch (network->activation_state()) { - case chromeos::ACTIVATION_STATE_PARTIALLY_ACTIVATED: - case chromeos::ACTIVATION_STATE_ACTIVATED: - if (network->restricted_pool()) { - if (network->error() == chromeos::ERROR_DNS_LOOKUP_FAILED) { - LOG(WARNING) << "No connectivity for device " - << network->service_path().c_str(); - // If we are connected but there is no connectivity at all, - // restart the whole process again. - if (activation_attempt_ < kMaxActivationAttempt) { - activation_attempt_++; - LOG(WARNING) << "Reconnect attempt #" - << activation_attempt_; - ForceReconnect(network, kFailedReconnectDelayMS); - evaluating_ = false; - return; - } else { - new_state = PLAN_ACTIVATION_ERROR; - UMA_HISTOGRAM_COUNTS("Cellular.ActivationRetryFailure", 1); - error_description = GetErrorMessage(kFailedConnectivity); - } - } else { - // If we have already received payment, don't show the payment - // page again. We should try to reconnect after some - // time instead. - new_state = PLAN_ACTIVATION_PAYMENT_PORTAL_LOADING; - } - } else if (network->activation_state() == - chromeos::ACTIVATION_STATE_ACTIVATED) { - new_state = PLAN_ACTIVATION_DONE; - } - break; - default: - break; - } - } else if (NeedsReconnecting(network, &new_state, &error_description)) { - evaluating_ = false; - return; - } - break; - } - case PLAN_ACTIVATION_RECONNECTING_OTASP: { - if (network->connected()) { - // Make sure other networks are not interfering with our detection of - // restricted pool. - DisableOtherNetworks(); - // Wait until the service shows up and gets activated. - switch (network->activation_state()) { - case chromeos::ACTIVATION_STATE_PARTIALLY_ACTIVATED: - case chromeos::ACTIVATION_STATE_ACTIVATED: - if (network->restricted_pool()) { - LOG(WARNING) << "Still no connectivity after OTASP for device " - << network->service_path().c_str(); - // If we have already received payment, don't show the payment - // page again. We should try to reconnect after some time instead. - if (reconnect_wait_count_ < kMaxReconnectAttemptOTASP) { - reconnect_wait_count_++; - LOG(WARNING) << "OTASP reconnect attempt #" - << reconnect_wait_count_; - ForceReconnect(network, kPostPaymentReconnectDelayMS); - evaluating_ = false; - return; - } else { - new_state = PLAN_ACTIVATION_ERROR; - UMA_HISTOGRAM_COUNTS("Cellular.PostPaymentConnectFailure", 1); - error_description = GetErrorMessage(kFailedConnectivity); - } - } else if (network->online()) { - new_state = PLAN_ACTIVATION_DONE; - } - break; - default: - break; - } - } else if (NeedsReconnecting(network, &new_state, &error_description)) { - evaluating_ = false; - return; - } - break; - } - case PLAN_ACTIVATION_PAGE_LOADING: - break; - // Just ignore all signals until the site confirms payment. - case PLAN_ACTIVATION_PAYMENT_PORTAL_LOADING: - case PLAN_ACTIVATION_SHOWING_PAYMENT: { - if (network->disconnected()) - new_state = PLAN_ACTIVATION_RECONNECTING_PAYMENT; - break; - } - // Activation completed/failed, ignore network changes. - case PLAN_ACTIVATION_DONE: - case PLAN_ACTIVATION_ERROR: - break; - } - - if (new_state != PLAN_ACTIVATION_ERROR && - GotActivationError(network, &error_description)) { - // Check for this special case when we try to do activate partially - // activated device. If that attempt failed, try to disconnect to clear the - // state and reconnect again. - if ((network->activation_state() == - chromeos::ACTIVATION_STATE_PARTIALLY_ACTIVATED || - network->activation_state() == chromeos::ACTIVATION_STATE_ACTIVATING) && - (network->error() == chromeos::ERROR_NO_ERROR || - network->error() == chromeos::ERROR_OTASP_FAILED) && - network->state() == chromeos::STATE_ACTIVATION_FAILURE) { - LOG(WARNING) << "Activation failure detected " - << network->service_path().c_str(); - switch (state_) { - case PLAN_ACTIVATION_OTASP: - case PLAN_ACTIVATION_RECONNECTING_OTASP: - new_state = PLAN_ACTIVATION_DELAY_OTASP; - break; - case PLAN_ACTIVATION_TRYING_OTASP: - new_state = PLAN_ACTIVATION_RECONNECTING_OTASP_TRY; - break; - case PLAN_ACTIVATION_INITIATING_ACTIVATION: - new_state = PLAN_ACTIVATION_RECONNECTING; - break; - case PLAN_ACTIVATION_START: - // We are just starting, so this must be previous activation attempt - // failure. - new_state = PLAN_ACTIVATION_TRYING_OTASP; - break; - case PLAN_ACTIVATION_DELAY_OTASP: - case PLAN_ACTIVATION_RECONNECTING_OTASP_TRY: - case PLAN_ACTIVATION_RECONNECTING: - new_state = state_; - break; - default: - new_state = PLAN_ACTIVATION_ERROR; - break; - } - } else { - LOG(WARNING) << "Unexpected activation failure for " - << network->service_path().c_str(); - new_state = PLAN_ACTIVATION_ERROR; - } - } - - if (new_state == PLAN_ACTIVATION_ERROR && !error_description.length()) - error_description = GetErrorMessage(kErrorDefault); - ChangeState(network, new_state, error_description); - evaluating_ = false; -} - -MobileSetupHandler::PlanActivationState - MobileSetupHandler::GetNextReconnectState( - MobileSetupHandler::PlanActivationState state) { - switch (state) { - case PLAN_ACTIVATION_INITIATING_ACTIVATION: - return PLAN_ACTIVATION_RECONNECTING; - case PLAN_ACTIVATION_OTASP: - return PLAN_ACTIVATION_RECONNECTING_OTASP; - case PLAN_ACTIVATION_TRYING_OTASP: - return PLAN_ACTIVATION_RECONNECTING_OTASP_TRY; - default: - return PLAN_ACTIVATION_RECONNECTING; - } + MobileActivator::GetInstance()->OnPortalLoaded( + LowerCaseEqualsASCII(result, kJsApiResultOK)); } -// Debugging helper function, will take it out at the end. -const char* MobileSetupHandler::GetStateDescription( - PlanActivationState state) { - switch (state) { - case PLAN_ACTIVATION_PAGE_LOADING: - return "PAGE_LOADING"; - case PLAN_ACTIVATION_START: - return "ACTIVATION_START"; - case PLAN_ACTIVATION_TRYING_OTASP: - return "TRYING_OTASP"; - case PLAN_ACTIVATION_RECONNECTING_OTASP_TRY: - return "RECONNECTING_OTASP_TRY"; - case PLAN_ACTIVATION_INITIATING_ACTIVATION: - return "INITIATING_ACTIVATION"; - case PLAN_ACTIVATION_RECONNECTING: - return "RECONNECTING"; - case PLAN_ACTIVATION_PAYMENT_PORTAL_LOADING: - return "PAYMENT_PORTAL_LOADING"; - case PLAN_ACTIVATION_SHOWING_PAYMENT: - return "SHOWING_PAYMENT"; - case PLAN_ACTIVATION_RECONNECTING_PAYMENT: - return "RECONNECTING_PAYMENT"; - case PLAN_ACTIVATION_START_OTASP: - return "START_OTASP"; - case PLAN_ACTIVATION_DELAY_OTASP: - return "DELAY_OTASP"; - case PLAN_ACTIVATION_OTASP: - return "OTASP"; - case PLAN_ACTIVATION_RECONNECTING_OTASP: - return "RECONNECTING_OTASP"; - case PLAN_ACTIVATION_DONE: - return "DONE"; - case PLAN_ACTIVATION_ERROR: - return "ERROR"; - } - return "UNKNOWN"; -} - - -void MobileSetupHandler::CompleteActivation( - chromeos::CellularNetwork* network) { - // Remove observers, we are done with this page. - chromeos::NetworkLibrary* lib = chromeos::CrosLibrary::Get()-> - GetNetworkLibrary(); - lib->RemoveNetworkManagerObserver(this); - lib->RemoveObserverForAllNetworks(this); - if (lib->IsLocked()) - lib->Unlock(); - // If we have successfully activated the connection, set autoconnect flag. - if (network) - network->SetAutoConnect(true); - // Reactivate other types of connections if we have - // shut them down previously. - ReEnableOtherConnections(); -} - -void MobileSetupHandler::UpdatePage( - chromeos::CellularNetwork* network, - const std::string& error_description) { - DictionaryValue device_dict; - if (network) - GetDeviceInfo(network, &device_dict); - device_dict.SetInteger("state", state_); - if (error_description.length()) - device_dict.SetString("error", error_description); - web_ui()->CallJavascriptFunction( - kJsDeviceStatusChangedCallback, device_dict); -} - - -void MobileSetupHandler::ChangeState(chromeos::CellularNetwork* network, - PlanActivationState new_state, - const std::string& error_description) { - static bool first_time = true; - if (state_ == new_state && !first_time) - return; - LOG(WARNING) << "Activation state flip old = " - << GetStateDescription(state_) - << ", new = " << GetStateDescription(new_state); - first_time = false; - - // Pick action that should happen on leaving the old state. - switch (state_) { - case PLAN_ACTIVATION_RECONNECTING_OTASP_TRY: - case PLAN_ACTIVATION_RECONNECTING: - case PLAN_ACTIVATION_RECONNECTING_OTASP: - if (reconnect_timer_.IsRunning()) { - reconnect_timer_.Stop(); - } - break; - default: - break; - } - state_ = new_state; - - // Signal to JS layer that the state is changing. - UpdatePage(network, error_description); - - // Pick action that should happen on entering the new state. - switch (new_state) { - case PLAN_ACTIVATION_START: - break; - case PLAN_ACTIVATION_DELAY_OTASP: { - UMA_HISTOGRAM_COUNTS("Cellular.RetryOTASP", 1); - BrowserThread::PostDelayedTask(BrowserThread::UI, FROM_HERE, - base::Bind(&MobileSetupHandler::RetryOTASP, AsWeakPtr()), - base::TimeDelta::FromMilliseconds(kOTASPRetryDelay)); - break; - } - case PLAN_ACTIVATION_INITIATING_ACTIVATION: - case PLAN_ACTIVATION_TRYING_OTASP: - case PLAN_ACTIVATION_OTASP: - DCHECK(network); - LOG(WARNING) << "Activating service " << network->service_path().c_str(); - UMA_HISTOGRAM_COUNTS("Cellular.ActivationTry", 1); - if (!network->StartActivation()) { - UMA_HISTOGRAM_COUNTS("Cellular.ActivationFailure", 1); - if (new_state == PLAN_ACTIVATION_OTASP) { - ChangeState(network, PLAN_ACTIVATION_DELAY_OTASP, std::string()); - } else { - ChangeState(network, PLAN_ACTIVATION_ERROR, - GetErrorMessage(kFailedConnectivity)); - } - } - break; - case PLAN_ACTIVATION_RECONNECTING_OTASP_TRY: - case PLAN_ACTIVATION_RECONNECTING: - case PLAN_ACTIVATION_RECONNECTING_PAYMENT: - case PLAN_ACTIVATION_RECONNECTING_OTASP: { - // Start reconnect timer. This will ensure that we are not left in - // limbo by the network library. - if (!reconnect_timer_.IsRunning()) { - reconnect_timer_.Start( - FROM_HERE, - base::TimeDelta::FromMilliseconds(kReconnectTimerDelayMS), - this, &MobileSetupHandler::ReconnectTimerFired); - } - // Reset connection metrics and try to connect. - reconnect_wait_count_ = 0; - connection_retry_count_ = 0; - connection_start_time_ = base::Time::Now(); - ConnectToNetwork(network, kReconnectDelayMS); - break; - } - case PLAN_ACTIVATION_PAGE_LOADING: - return; - case PLAN_ACTIVATION_PAYMENT_PORTAL_LOADING: - case PLAN_ACTIVATION_SHOWING_PAYMENT: - // Fix for fix SSL for the walled gardens where cert chain verification - // might not work. - break; - case PLAN_ACTIVATION_DONE: - DCHECK(network); - CompleteActivation(network); - UMA_HISTOGRAM_COUNTS("Cellular.MobileSetupSucceeded", 1); - break; - case PLAN_ACTIVATION_ERROR: - CompleteActivation(NULL); - UMA_HISTOGRAM_COUNTS("Cellular.PlanFailed", 1); - break; - default: - break; - } -} - -void MobileSetupHandler::ReEnableOtherConnections() { - chromeos::NetworkLibrary* lib = chromeos::CrosLibrary::Get()-> - GetNetworkLibrary(); - if (reenable_ethernet_) { - reenable_ethernet_ = false; - lib->EnableEthernetNetworkDevice(true); - } - if (reenable_wifi_) { - reenable_wifi_ = false; - lib->EnableWifiNetworkDevice(true); - } - - PrefService* prefs = g_browser_process->local_state(); - if (reenable_cert_check_) { - prefs->SetBoolean(prefs::kCertRevocationCheckingEnabled, - true); - reenable_cert_check_ = false; - } -} - -void MobileSetupHandler::SetupActivationProcess( - chromeos::CellularNetwork* network) { - if (!network) - return; - - // Disable SSL cert checks since we will be doing this in - // restricted pool. - PrefService* prefs = g_browser_process->local_state(); - if (!reenable_cert_check_ && - prefs->GetBoolean( - prefs::kCertRevocationCheckingEnabled)) { - reenable_cert_check_ = true; - prefs->SetBoolean(prefs::kCertRevocationCheckingEnabled, false); - } - - chromeos::NetworkLibrary* lib = chromeos::CrosLibrary::Get()-> - GetNetworkLibrary(); - // Disable autoconnect to cellular network. - network->SetAutoConnect(false); - - // Prevent any other network interference. - DisableOtherNetworks(); - lib->Lock(); -} - -void MobileSetupHandler::DisableOtherNetworks() { - chromeos::NetworkLibrary* lib = chromeos::CrosLibrary::Get()-> - GetNetworkLibrary(); - // Disable ethernet and wifi. - if (lib->ethernet_enabled()) { - reenable_ethernet_ = true; - lib->EnableEthernetNetworkDevice(false); - } - if (lib->wifi_enabled()) { - reenable_wifi_ = true; - lib->EnableWifiNetworkDevice(false); - } -} - -bool MobileSetupHandler::GotActivationError( - chromeos::CellularNetwork* network, std::string* error) { - DCHECK(network); - bool got_error = false; - const char* error_code = kErrorDefault; - - // This is the magic for detection of errors in during activation process. - if (network->state() == chromeos::STATE_FAILURE && - network->error() == chromeos::ERROR_AAA_FAILED) { - if (network->activation_state() == - chromeos::ACTIVATION_STATE_PARTIALLY_ACTIVATED) { - error_code = kErrorBadConnectionPartial; - } else if (network->activation_state() == - chromeos::ACTIVATION_STATE_ACTIVATED) { - if (network->roaming_state() == chromeos::ROAMING_STATE_HOME) { - error_code = kErrorBadConnectionActivated; - } else if (network->roaming_state() == chromeos::ROAMING_STATE_ROAMING) { - error_code = kErrorRoamingOnConnection; - } - } - got_error = true; - } else if (network->state() == chromeos::STATE_ACTIVATION_FAILURE) { - if (network->error() == chromeos::ERROR_NEED_EVDO) { - if (network->activation_state() == - chromeos::ACTIVATION_STATE_PARTIALLY_ACTIVATED) - error_code = kErrorNoEVDO; - } else if (network->error() == chromeos::ERROR_NEED_HOME_NETWORK) { - if (network->activation_state() == - chromeos::ACTIVATION_STATE_NOT_ACTIVATED) { - error_code = kErrorRoamingActivation; - } else if (network->activation_state() == - chromeos::ACTIVATION_STATE_PARTIALLY_ACTIVATED) { - error_code = kErrorRoamingPartiallyActivated; - } - } - got_error = true; - } - - if (got_error) - *error = GetErrorMessage(error_code); - - return got_error; -} - -void MobileSetupHandler::GetDeviceInfo(chromeos::CellularNetwork* network, +void MobileSetupHandler::GetDeviceInfo(CellularNetwork* network, DictionaryValue* value) { DCHECK(network); chromeos::NetworkLibrary* cros = @@ -1410,39 +326,6 @@ void MobileSetupHandler::GetDeviceInfo(chromeos::CellularNetwork* network, } } -std::string MobileSetupHandler::GetErrorMessage(const std::string& code) { - return cellular_config_->GetErrorMessage(code); -} - -void MobileSetupHandler::StartActivationOnUIThread() { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); - chromeos::NetworkLibrary* lib = - chromeos::CrosLibrary::Get()->GetNetworkLibrary(); - - chromeos::CellularNetwork* network = - lib->FindCellularNetworkByPath(service_path_); - - if (!network || !network->SupportsActivation()) { - LOG(ERROR) << "Cellular service can't be found: " << service_path_; - return; - } - - const chromeos::NetworkDevice* device = - lib->FindNetworkDeviceByPath(network->device_path()); - if (!device) { - LOG(ERROR) << "Cellular device can't be found: " << network->device_path(); - return; - } - - meid_ = device->meid(); - if (!chromeos::CrosLibrary::Get()->GetNetworkLibrary()->IsLocked()) - SetupActivationProcess(network); - else - already_running_ = true; - - StartActivation(); -} - //////////////////////////////////////////////////////////////////////////////// // // MobileSetupUI @@ -1451,11 +334,8 @@ void MobileSetupHandler::StartActivationOnUIThread() { MobileSetupUI::MobileSetupUI(content::WebUI* web_ui) : WebUIController(web_ui) { - chromeos::CellularNetwork* network = GetCellularNetwork(); - std::string service_path = network ? network->service_path() : std::string(); - web_ui->AddMessageHandler(new MobileSetupHandler(service_path)); - MobileSetupUIHTMLSource* html_source = - new MobileSetupUIHTMLSource(service_path); + web_ui->AddMessageHandler(new MobileSetupHandler()); + MobileSetupUIHTMLSource* html_source = new MobileSetupUIHTMLSource(); // Set up the chrome://mobilesetup/ source. Profile* profile = Profile::FromWebUI(web_ui); diff --git a/chrome/browser/ui/webui/options2/chromeos/internet_options_handler2.cc b/chrome/browser/ui/webui/options2/chromeos/internet_options_handler2.cc index 983a2d7..ef11169 100644 --- a/chrome/browser/ui/webui/options2/chromeos/internet_options_handler2.cc +++ b/chrome/browser/ui/webui/options2/chromeos/internet_options_handler2.cc @@ -592,7 +592,13 @@ void InternetOptionsHandler::ShowMorePlanInfoCallback(const ListValue* args) { void InternetOptionsHandler::BuyDataPlanCallback(const ListValue* args) { if (!web_ui()) return; - ash::Shell::GetInstance()->delegate()->OpenMobileSetup(); + + std::string service_path; + if (args->GetSize() != 1 || !args->GetString(0, &service_path)) { + NOTREACHED(); + return; + } + ash::Shell::GetInstance()->delegate()->OpenMobileSetup(service_path); } void InternetOptionsHandler::SetApnCallback(const ListValue* args) { @@ -1231,7 +1237,7 @@ void InternetOptionsHandler::HandleCellularButtonClick( } else if (command == "disconnect") { cros_->DisconnectFromNetwork(cellular); } else if (command == "activate") { - ash::Shell::GetInstance()->delegate()->OpenMobileSetup(); + ash::Shell::GetInstance()->delegate()->OpenMobileSetup(service_path); } else if (command == "options") { PopulateDictionaryDetails(cellular); } |