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