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