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