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