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