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.
5 #include "chrome/browser/chromeos/mobile/mobile_activator.h"
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"
41 using content::BrowserThread;
45 // Cellular configuration file path.
46 const char kCellularConfigPath[] =
47 "/usr/share/chromeos-assets/mobile/mobile_config.json";
49 // Cellular config file field names.
50 const char kVersionField[] = "version";
51 const char kErrorsField[] = "errors";
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;
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";
78 // Returns true if the device follows the simple activation flow.
79 bool IsSimpleActivationFlow(const chromeos::NetworkState* network) {
80 return (network->activation_type() == shill::kActivationTypeNonCellular ||
81 network->activation_type() == shill::kActivationTypeOTA);
88 ////////////////////////////////////////////////////////////////////////////////
90 // CellularConfigDocument
92 ////////////////////////////////////////////////////////////////////////////////
93 CellularConfigDocument::CellularConfigDocument() {}
95 std::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())
103 void 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))
110 if (LoadFromFile(config_path))
111 DVLOG(1) << "Cellular config file loaded: " << kCellularConfigPath;
113 LOG(ERROR) << "Error loading cellular config file: " << kCellularConfigPath;
116 CellularConfigDocument::~CellularConfigDocument() {}
118 void CellularConfigDocument::SetErrorMap(
119 const ErrorMap& map) {
120 base::AutoLock create(config_lock_);
122 error_map_.insert(map.begin(), map.end());
125 bool CellularConfigDocument::LoadFromFile(const base::FilePath& config_path) {
127 if (!base::ReadFileToString(config_path, &config))
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";
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";
145 base::DictionaryValue* errors = NULL;
146 if (!root_dict->GetDictionary(kErrorsField, &errors))
148 for (base::DictionaryValue::Iterator it(*errors);
149 !it.IsAtEnd(); it.Advance()) {
151 if (!it.value().GetAsString(&value)) {
152 LOG(WARNING) << "Bad cellular config error value";
155 error_map.insert(ErrorMap::value_type(it.key(), value));
157 SetErrorMap(error_map);
161 ////////////////////////////////////////////////////////////////////////////////
165 ////////////////////////////////////////////////////////////////////////////////
166 MobileActivator::MobileActivator()
167 : cellular_config_(new CellularConfigDocument()),
168 state_(PLAN_ACTIVATION_PAGE_LOADING),
169 reenable_cert_check_(false),
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) {
180 MobileActivator::~MobileActivator() {
181 TerminateActivation();
184 MobileActivator* MobileActivator::GetInstance() {
185 return Singleton<MobileActivator>::get();
188 void MobileActivator::TerminateActivation() {
189 state_duration_timer_.Stop();
190 continue_reconnect_timer_.Stop();
191 reconnect_timeout_timer_.Stop();
193 if (NetworkHandler::IsInitialized()) {
194 NetworkHandler::Get()->network_state_handler()->
195 RemoveObserver(this, FROM_HERE);
197 ReEnableCertRevocationChecking();
200 service_path_.clear();
201 device_path_.clear();
202 state_ = PLAN_ACTIVATION_PAGE_LOADING;
203 reenable_cert_check_ = false;
205 // Release the previous cellular config and setup a new empty one.
206 cellular_config_ = new CellularConfigDocument();
209 void MobileActivator::DefaultNetworkChanged(const NetworkState* network) {
210 RefreshCellularNetworks();
213 void MobileActivator::NetworkPropertiesUpdated(const NetworkState* network) {
214 if (state_ == PLAN_ACTIVATION_PAGE_LOADING)
217 if (!network || network->type() != shill::kTypeCellular)
220 const DeviceState* device = NetworkHandler::Get()->network_state_handler()->
221 GetDeviceState(network->device_path());
223 LOG(ERROR) << "Cellular device can't be found: " << network->device_path();
226 if (network->device_path() != device_path_) {
227 LOG(WARNING) << "Ignoring property update for cellular service "
229 << " on unknown device " << network->device_path()
230 << " (Stored device path = " << device_path_ << ")";
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();
238 EvaluateCellularNetwork(network);
241 void MobileActivator::AddObserver(MobileActivator::Observer* observer) {
242 DCHECK(content::BrowserThread::CurrentlyOn(BrowserThread::UI));
243 observers_.AddObserver(observer);
246 void MobileActivator::RemoveObserver(MobileActivator::Observer* observer) {
247 DCHECK(content::BrowserThread::CurrentlyOn(BrowserThread::UI));
248 observers_.RemoveObserver(observer);
251 void MobileActivator::InitiateActivation(const std::string& service_path) {
252 DCHECK(content::BrowserThread::CurrentlyOn(BrowserThread::UI));
253 const NetworkState* network = GetNetworkState(service_path);
255 LOG(WARNING) << "Cellular service can't be found: " << service_path;
258 const DeviceState* device = NetworkHandler::Get()->network_state_handler()->
259 GetDeviceState(network->device_path());
261 LOG(ERROR) << "Cellular device can't be found: " << network->device_path();
266 meid_ = device->meid();
267 iccid_ = device->iccid();
268 service_path_ = service_path;
269 device_path_ = network->device_path();
271 ChangeState(network, PLAN_ACTIVATION_PAGE_LOADING, "");
273 BrowserThread::PostTaskAndReply(BrowserThread::FILE, FROM_HERE,
274 base::Bind(&CellularConfigDocument::LoadCellularConfigFile,
275 cellular_config_.get()),
276 base::Bind(&MobileActivator::ContinueActivation, AsWeakPtr()));
279 void MobileActivator::ContinueActivation() {
280 NetworkHandler::Get()->network_configuration_handler()->GetProperties(
282 base::Bind(&MobileActivator::GetPropertiesAndContinueActivation,
283 weak_ptr_factory_.GetWeakPtr()),
284 base::Bind(&MobileActivator::GetPropertiesFailure,
285 weak_ptr_factory_.GetWeakPtr()));
288 void 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",
294 return; // Edge case; abort.
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_);
308 if (payment_url.empty() && usage_url.empty())
311 DisableCertRevocationChecking();
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(
318 auto_connect_property,
319 base::Bind(&base::DoNothing),
320 network_handler::ErrorCallback());
324 void MobileActivator::GetPropertiesFailure(
325 const std::string& error_name,
326 scoped_ptr<base::DictionaryValue> error_data) {
327 NET_LOG_ERROR("MobileActivator GetProperties Failed: " + error_name,
331 void MobileActivator::OnSetTransactionStatus(bool success) {
332 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
333 base::Bind(&MobileActivator::HandleSetTransactionStatus,
334 AsWeakPtr(), success));
337 void MobileActivator::HandleSetTransactionStatus(bool success) {
338 // The payment is received, try to reconnect and check the status all over
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());
354 UMA_HISTOGRAM_COUNTS("Cellular.PaymentFailed", 1);
358 void MobileActivator::OnPortalLoaded(bool success) {
359 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
360 base::Bind(&MobileActivator::HandlePortalLoaded,
361 AsWeakPtr(), success));
364 void MobileActivator::HandlePortalLoaded(bool success) {
365 const NetworkState* network = GetNetworkState(service_path_);
367 ChangeState(NULL, PLAN_ACTIVATION_ERROR,
368 GetErrorMessage(kErrorNoService));
371 if (state_ == PLAN_ACTIVATION_PAYMENT_PORTAL_LOADING ||
372 state_ == PLAN_ACTIVATION_SHOWING_PAYMENT) {
374 payment_reconnect_count_ = 0;
375 ChangeState(network, PLAN_ACTIVATION_SHOWING_PAYMENT, std::string());
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)
382 payment_reconnect_count_++;
383 if (payment_reconnect_count_ > kMaxPortalReconnectCount) {
384 ChangeState(NULL, PLAN_ACTIVATION_ERROR,
385 GetErrorMessage(kErrorNoService));
389 // Reconnect and try and load the frame again.
391 PLAN_ACTIVATION_RECONNECTING,
392 GetErrorMessage(kFailedPaymentError));
395 NOTREACHED() << "Called paymentPortalLoad while in unexpected state: "
396 << GetStateDescription(state_);
400 void MobileActivator::StartOTASPTimer() {
401 pending_activation_request_ = false;
402 state_duration_timer_.Start(
404 base::TimeDelta::FromMilliseconds(kOTASPRetryDelay),
405 this, &MobileActivator::HandleOTASPTimeout);
408 void MobileActivator::StartActivation() {
409 UMA_HISTOGRAM_COUNTS("Cellular.MobileSetupStart", 1);
410 const NetworkState* network = GetNetworkState(service_path_);
411 // Check if we can start activation process.
413 NetworkStateHandler::TechnologyState technology_state =
414 NetworkHandler::Get()->network_state_handler()->GetTechnologyState(
415 NetworkTypePattern::Cellular());
417 if (technology_state == NetworkStateHandler::TECHNOLOGY_UNAVAILABLE) {
418 error = kErrorNoDevice;
419 } else if (technology_state != NetworkStateHandler::TECHNOLOGY_ENABLED) {
420 error = kErrorDisabled;
422 error = kErrorNoService;
424 ChangeState(NULL, PLAN_ACTIVATION_ERROR, GetErrorMessage(error));
428 // Start monitoring network property changes.
429 NetworkHandler::Get()->network_state_handler()->AddObserver(this, FROM_HERE);
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();
439 void MobileActivator::StartActivationOverNonCellularNetwork() {
440 // Fast forward to payment portal loading.
441 const NetworkState* network = GetNetworkState(service_path_);
443 LOG(WARNING) << "Cellular service can't be found: " << service_path_;
449 (network->activation_state() == shill::kActivationStateActivated) ?
450 PLAN_ACTIVATION_DONE :
451 PLAN_ACTIVATION_PAYMENT_PORTAL_LOADING,
452 "" /* error_description */);
454 RefreshCellularNetworks();
457 void MobileActivator::StartActivationOTA() {
458 // Connect to the network if we don't currently have access.
459 const NetworkState* network = GetNetworkState(service_path_);
461 LOG(WARNING) << "Cellular service can't be found: " << service_path_;
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);
472 ChangeState(network, PLAN_ACTIVATION_PAYMENT_PORTAL_LOADING,
473 "" /* error_description */);
474 RefreshCellularNetworks();
477 void MobileActivator::StartActivationOTASP() {
478 const NetworkState* network = GetNetworkState(service_path_);
480 LOG(WARNING) << "Cellular service can't be found: " << service_path_;
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;
490 state_ = PLAN_ACTIVATION_START;
493 EvaluateCellularNetwork(network);
496 void MobileActivator::RetryOTASP() {
497 DCHECK(state_ == PLAN_ACTIVATION_DELAY_OTASP);
501 void MobileActivator::StartOTASP() {
502 const NetworkState* network = GetNetworkState(service_path_);
504 LOG(WARNING) << "Cellular service can't be found: " << service_path_;
508 ChangeState(network, PLAN_ACTIVATION_START_OTASP, std::string());
509 EvaluateCellularNetwork(network);
512 void MobileActivator::HandleOTASPTimeout() {
513 LOG(WARNING) << "OTASP seems to be taking too long.";
514 const NetworkState* network = GetNetworkState(service_path_);
516 LOG(WARNING) << "Cellular service can't be found: " << service_path_;
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) {
526 PLAN_ACTIVATION_RECONNECTING,
527 GetErrorMessage(kErrorDefault));
530 } else if (state_ == PLAN_ACTIVATION_TRYING_OTASP) {
531 ++trying_OTASP_attempts_;
532 if (trying_OTASP_attempts_ <= kMaxOTASPTries) {
534 PLAN_ACTIVATION_RECONNECTING,
535 GetErrorMessage(kErrorDefault));
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.
543 PLAN_ACTIVATION_DELAY_OTASP,
544 GetErrorMessage(kErrorDefault));
548 LOG(ERROR) << "OTASP timed out from a non-OTASP wait state?";
550 LOG(ERROR) << "OTASP failed too many times; aborting.";
552 PLAN_ACTIVATION_ERROR,
553 GetErrorMessage(kErrorDefault));
556 void MobileActivator::ConnectNetwork(const NetworkState* network) {
557 NetworkHandler::Get()->network_connection_handler()->ConnectToNetwork(
559 base::Bind(&base::DoNothing),
560 network_handler::ErrorCallback(),
561 false /* check_error_state */);
564 void MobileActivator::ForceReconnect(const NetworkState* network,
565 PlanActivationState next_state) {
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
575 NetworkHandler::Get()->network_connection_handler()->DisconnectNetwork(
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(
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(
589 base::TimeDelta::FromMilliseconds(kMaxReconnectTime),
590 this, &MobileActivator::ReconnectTimedOut);
593 void MobileActivator::ReconnectTimedOut() {
594 LOG(ERROR) << "Ending activation attempt after failing to reconnect.";
595 const NetworkState* network = GetNetworkState(service_path_);
597 LOG(WARNING) << "Cellular service can't be found: " << service_path_;
602 PLAN_ACTIVATION_ERROR,
603 GetErrorMessage(kFailedConnectivity));
606 void 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
614 NetworkHandler::Get()->network_connection_handler()->DisconnectNetwork(
616 base::Bind(&base::DoNothing),
617 network_handler::ErrorCallback());
620 // Stop this callback
621 continue_reconnect_timer_.Stop();
622 EvaluateCellularNetwork(network);
624 LOG(WARNING) << "Connect failed, will try again in a little bit.";
626 VLOG(1) << "Connecting to: " << network->path();
627 ash::network_connect::ConnectToNetwork(
628 network->path(), NULL /* no parent window */);
633 void MobileActivator::RefreshCellularNetworks() {
634 if (state_ == PLAN_ACTIVATION_PAGE_LOADING ||
635 state_ == PLAN_ACTIVATION_DONE ||
636 state_ == PLAN_ACTIVATION_ERROR) {
640 const NetworkState* network = GetNetworkState(service_path_);
642 LOG(WARNING) << "Cellular service can't be found: " << service_path_;
646 if (IsSimpleActivationFlow(network)) {
647 bool waiting = (state_ == PLAN_ACTIVATION_WAITING_FOR_CONNECTION);
648 // We're only interested in whether or not we have access to the payment
649 // portal (regardless of which network we use to access it), so check
650 // the default network connection state. The default network is the network
651 // used to route default traffic. Also, note that we can access the
652 // payment portal over a cellular network in the portalled state.
653 const NetworkState* default_network = GetDefaultNetwork();
654 bool is_online_or_portal = default_network &&
655 (default_network->connection_state() == shill::kStateOnline ||
656 (default_network->type() == shill::kTypeCellular &&
657 default_network->connection_state() == shill::kStatePortal));
658 if (waiting && is_online_or_portal) {
659 ChangeState(network, post_reconnect_state_, "");
660 } else if (!waiting && !is_online_or_portal) {
661 ChangeState(network, PLAN_ACTIVATION_WAITING_FOR_CONNECTION, "");
665 EvaluateCellularNetwork(network);
668 const NetworkState* MobileActivator::GetNetworkState(
669 const std::string& service_path) {
670 return NetworkHandler::Get()->network_state_handler()->GetNetworkState(
674 const NetworkState* MobileActivator::GetDefaultNetwork() {
675 return NetworkHandler::Get()->network_state_handler()->DefaultNetwork();
678 void MobileActivator::EvaluateCellularNetwork(const NetworkState* network) {
680 LOG(ERROR) << "Tried to run MobileActivator state machine while "
686 LOG(WARNING) << "Cellular service lost";
690 LOG(WARNING) << "Cellular:\n service state=" << network->connection_state()
691 << "\n ui=" << GetStateDescription(state_)
692 << "\n activation=" << network->activation_state()
693 << "\n error=" << network->error()
694 << "\n setvice_path=" << network->path()
695 << "\n connected=" << network->IsConnectedState();
697 // If the network is activated over non cellular network or OTA, the
698 // activator state does not depend on the network's own state.
699 if (IsSimpleActivationFlow(network))
702 std::string error_description;
703 PlanActivationState new_state = PickNextState(network, &error_description);
705 ChangeState(network, new_state, error_description);
708 MobileActivator::PlanActivationState MobileActivator::PickNextState(
709 const NetworkState* network, std::string* error_description) const {
710 PlanActivationState new_state = state_;
711 if (!network->IsConnectedState())
712 new_state = PickNextOfflineState(network);
714 new_state = PickNextOnlineState(network);
715 if (new_state != PLAN_ACTIVATION_ERROR &&
716 GotActivationError(network, error_description)) {
717 // Check for this special case when we try to do activate partially
718 // activated device. If that attempt failed, try to disconnect to clear the
719 // state and reconnect again.
720 const std::string& activation = network->activation_state();
721 if ((activation == shill::kActivationStatePartiallyActivated ||
722 activation == shill::kActivationStateActivating) &&
723 (network->error().empty() ||
724 network->error() == shill::kErrorOtaspFailed) &&
725 network->connection_state() == shill::kStateActivationFailure) {
726 NET_LOG_EVENT("Activation failure detected ", network->path());
728 case PLAN_ACTIVATION_OTASP:
729 new_state = PLAN_ACTIVATION_DELAY_OTASP;
731 case PLAN_ACTIVATION_INITIATING_ACTIVATION:
732 case PLAN_ACTIVATION_TRYING_OTASP:
733 new_state = PLAN_ACTIVATION_START;
735 case PLAN_ACTIVATION_START:
736 // We are just starting, so this must be previous activation attempt
738 new_state = PLAN_ACTIVATION_TRYING_OTASP;
740 case PLAN_ACTIVATION_DELAY_OTASP:
744 new_state = PLAN_ACTIVATION_ERROR;
748 LOG(WARNING) << "Unexpected activation failure for " << network->path();
749 new_state = PLAN_ACTIVATION_ERROR;
753 if (new_state == PLAN_ACTIVATION_ERROR && !error_description->length())
754 *error_description = GetErrorMessage(kErrorDefault);
758 MobileActivator::PlanActivationState MobileActivator::PickNextOfflineState(
759 const NetworkState* network) const {
760 PlanActivationState new_state = state_;
761 const std::string& activation = network->activation_state();
763 case PLAN_ACTIVATION_PAYMENT_PORTAL_LOADING:
764 case PLAN_ACTIVATION_SHOWING_PAYMENT:
765 if (!IsSimpleActivationFlow(network))
766 new_state = PLAN_ACTIVATION_RECONNECTING;
768 case PLAN_ACTIVATION_START:
769 if (activation == shill::kActivationStateActivated) {
770 if (network->connection_state() == shill::kStatePortal)
771 new_state = PLAN_ACTIVATION_PAYMENT_PORTAL_LOADING;
773 new_state = PLAN_ACTIVATION_DONE;
774 } else if (activation == shill::kActivationStatePartiallyActivated) {
775 new_state = PLAN_ACTIVATION_TRYING_OTASP;
777 new_state = PLAN_ACTIVATION_INITIATING_ACTIVATION;
781 VLOG(1) << "Waiting for cellular service to connect.";
787 MobileActivator::PlanActivationState MobileActivator::PickNextOnlineState(
788 const NetworkState* network) const {
789 PlanActivationState new_state = state_;
790 const std::string& activation = network->activation_state();
792 case PLAN_ACTIVATION_START:
793 if (activation == shill::kActivationStateActivated) {
794 if (network->connection_state() == shill::kStateOnline)
795 new_state = PLAN_ACTIVATION_DONE;
797 new_state = PLAN_ACTIVATION_PAYMENT_PORTAL_LOADING;
798 } else if (activation == shill::kActivationStatePartiallyActivated) {
799 new_state = PLAN_ACTIVATION_TRYING_OTASP;
801 new_state = PLAN_ACTIVATION_INITIATING_ACTIVATION;
804 case PLAN_ACTIVATION_START_OTASP: {
805 if (activation == shill::kActivationStatePartiallyActivated) {
806 new_state = PLAN_ACTIVATION_OTASP;
807 } else if (activation == shill::kActivationStateActivated) {
808 new_state = PLAN_ACTIVATION_RECONNECTING;
810 LOG(WARNING) << "Unexpected activation state for device "
815 case PLAN_ACTIVATION_DELAY_OTASP:
816 // Just ignore any changes until the OTASP retry timer kicks in.
818 case PLAN_ACTIVATION_INITIATING_ACTIVATION: {
819 if (pending_activation_request_) {
820 VLOG(1) << "Waiting for pending activation attempt to finish";
821 } else if (activation == shill::kActivationStateActivated ||
822 activation == shill::kActivationStatePartiallyActivated) {
823 new_state = PLAN_ACTIVATION_START;
824 } else if (activation == shill::kActivationStateNotActivated ||
825 activation == shill::kActivationStateActivating) {
826 // Wait in this state until activation state changes.
828 LOG(WARNING) << "Unknown transition";
832 case PLAN_ACTIVATION_OTASP:
833 case PLAN_ACTIVATION_TRYING_OTASP:
834 if (pending_activation_request_) {
835 VLOG(1) << "Waiting for pending activation attempt to finish";
836 } else if (activation == shill::kActivationStateNotActivated ||
837 activation == shill::kActivationStateActivating) {
838 VLOG(1) << "Waiting for the OTASP to finish and the service to "
839 << "come back online";
840 } else if (activation == shill::kActivationStateActivated) {
841 new_state = PLAN_ACTIVATION_DONE;
843 new_state = PLAN_ACTIVATION_PAYMENT_PORTAL_LOADING;
846 case PLAN_ACTIVATION_RECONNECTING_PAYMENT:
847 if (network->connection_state() != shill::kStatePortal &&
848 activation == shill::kActivationStateActivated)
849 // We're not portalled, and we're already activated, so we're online!
850 new_state = PLAN_ACTIVATION_DONE;
852 new_state = PLAN_ACTIVATION_PAYMENT_PORTAL_LOADING;
855 case PLAN_ACTIVATION_PAGE_LOADING:
857 // Just ignore all signals until the site confirms payment.
858 case PLAN_ACTIVATION_PAYMENT_PORTAL_LOADING:
859 case PLAN_ACTIVATION_SHOWING_PAYMENT:
860 case PLAN_ACTIVATION_WAITING_FOR_CONNECTION:
862 // Go where we decided earlier.
863 case PLAN_ACTIVATION_RECONNECTING:
864 new_state = post_reconnect_state_;
866 // Activation completed/failed, ignore network changes.
867 case PLAN_ACTIVATION_DONE:
868 case PLAN_ACTIVATION_ERROR:
875 // Debugging helper function, will take it out at the end.
876 const char* MobileActivator::GetStateDescription(PlanActivationState state) {
878 case PLAN_ACTIVATION_PAGE_LOADING:
879 return "PAGE_LOADING";
880 case PLAN_ACTIVATION_START:
881 return "ACTIVATION_START";
882 case PLAN_ACTIVATION_INITIATING_ACTIVATION:
883 return "INITIATING_ACTIVATION";
884 case PLAN_ACTIVATION_TRYING_OTASP:
885 return "TRYING_OTASP";
886 case PLAN_ACTIVATION_PAYMENT_PORTAL_LOADING:
887 return "PAYMENT_PORTAL_LOADING";
888 case PLAN_ACTIVATION_SHOWING_PAYMENT:
889 return "SHOWING_PAYMENT";
890 case PLAN_ACTIVATION_RECONNECTING_PAYMENT:
891 return "RECONNECTING_PAYMENT";
892 case PLAN_ACTIVATION_DELAY_OTASP:
893 return "DELAY_OTASP";
894 case PLAN_ACTIVATION_START_OTASP:
895 return "START_OTASP";
896 case PLAN_ACTIVATION_OTASP:
898 case PLAN_ACTIVATION_DONE:
900 case PLAN_ACTIVATION_ERROR:
902 case PLAN_ACTIVATION_RECONNECTING:
903 return "RECONNECTING";
904 case PLAN_ACTIVATION_WAITING_FOR_CONNECTION:
905 return "WAITING FOR CONNECTION";
911 void MobileActivator::CompleteActivation() {
912 // Remove observers, we are done with this page.
913 NetworkHandler::Get()->network_state_handler()->
914 RemoveObserver(this, FROM_HERE);
916 // Reactivate other types of connections if we have
917 // shut them down previously.
918 ReEnableCertRevocationChecking();
921 bool MobileActivator::RunningActivation() const {
922 return !(state_ == PLAN_ACTIVATION_DONE ||
923 state_ == PLAN_ACTIVATION_ERROR ||
924 state_ == PLAN_ACTIVATION_PAGE_LOADING);
927 void MobileActivator::HandleActivationFailure(
928 const std::string& service_path,
929 PlanActivationState new_state,
930 const std::string& error_name,
931 scoped_ptr<base::DictionaryValue> error_data) {
932 pending_activation_request_ = false;
933 const NetworkState* network = GetNetworkState(service_path);
935 NET_LOG_ERROR("Cellular service no longer exists", service_path);
938 UMA_HISTOGRAM_COUNTS("Cellular.ActivationFailure", 1);
939 NET_LOG_ERROR("Failed to call Activate() on service", service_path);
940 if (new_state == PLAN_ACTIVATION_OTASP) {
941 ChangeState(network, PLAN_ACTIVATION_DELAY_OTASP, std::string());
944 PLAN_ACTIVATION_ERROR,
945 GetErrorMessage(kFailedConnectivity));
949 void MobileActivator::RequestCellularActivation(
950 const NetworkState* network,
951 const base::Closure& success_callback,
952 const network_handler::ErrorCallback& error_callback) {
954 NET_LOG_EVENT("Activating cellular service", network->path());
955 UMA_HISTOGRAM_COUNTS("Cellular.ActivationTry", 1);
956 pending_activation_request_ = true;
957 NetworkHandler::Get()->network_activation_handler()->
958 Activate(network->path(),
964 void MobileActivator::ChangeState(const NetworkState* network,
965 PlanActivationState new_state,
966 std::string error_description) {
967 // Report an error, by transitioning into a PLAN_ACTIVATION_ERROR state with
968 // a "no service" error instead, if no network state is available (e.g. the
969 // cellular service no longer exists) when we are transitioning into certain
970 // plan activation state.
973 case PLAN_ACTIVATION_INITIATING_ACTIVATION:
974 case PLAN_ACTIVATION_TRYING_OTASP:
975 case PLAN_ACTIVATION_OTASP:
976 case PLAN_ACTIVATION_DONE:
977 new_state = PLAN_ACTIVATION_ERROR;
978 error_description = GetErrorMessage(kErrorNoService);
984 static bool first_time = true;
985 VLOG(1) << "Activation state flip old = "
986 << GetStateDescription(state_)
987 << ", new = " << GetStateDescription(new_state);
988 if (state_ == new_state && !first_time)
991 VLOG(1) << "Transitioning...";
993 // Kill all the possible timers and callbacks we might have outstanding.
994 state_duration_timer_.Stop();
995 continue_reconnect_timer_.Stop();
996 reconnect_timeout_timer_.Stop();
997 const PlanActivationState old_state = state_;
1000 // Signal to observers layer that the state is changing.
1001 FOR_EACH_OBSERVER(Observer, observers_,
1002 OnActivationStateChanged(network, state_, error_description));
1004 // Pick action that should happen on entering the new state.
1005 switch (new_state) {
1006 case PLAN_ACTIVATION_START:
1008 case PLAN_ACTIVATION_DELAY_OTASP: {
1009 UMA_HISTOGRAM_COUNTS("Cellular.RetryOTASP", 1);
1010 BrowserThread::PostDelayedTask(BrowserThread::UI, FROM_HERE,
1011 base::Bind(&MobileActivator::RetryOTASP, AsWeakPtr()),
1012 base::TimeDelta::FromMilliseconds(kOTASPRetryDelay));
1015 case PLAN_ACTIVATION_START_OTASP:
1017 case PLAN_ACTIVATION_INITIATING_ACTIVATION:
1018 case PLAN_ACTIVATION_TRYING_OTASP:
1019 case PLAN_ACTIVATION_OTASP: {
1021 network_handler::ErrorCallback on_activation_error =
1022 base::Bind(&MobileActivator::HandleActivationFailure, AsWeakPtr(),
1025 RequestCellularActivation(
1027 base::Bind(&MobileActivator::StartOTASPTimer, AsWeakPtr()),
1028 on_activation_error);
1031 case PLAN_ACTIVATION_PAGE_LOADING:
1033 case PLAN_ACTIVATION_PAYMENT_PORTAL_LOADING:
1034 case PLAN_ACTIVATION_SHOWING_PAYMENT:
1035 case PLAN_ACTIVATION_RECONNECTING_PAYMENT:
1036 // Fix for fix SSL for the walled gardens where cert chain verification
1039 case PLAN_ACTIVATION_WAITING_FOR_CONNECTION:
1040 post_reconnect_state_ = old_state;
1042 case PLAN_ACTIVATION_RECONNECTING: {
1043 PlanActivationState next_state = old_state;
1044 // Pick where we want to return to after we reconnect.
1045 switch (old_state) {
1046 case PLAN_ACTIVATION_PAYMENT_PORTAL_LOADING:
1047 case PLAN_ACTIVATION_SHOWING_PAYMENT:
1048 // We decide here what to do next based on the state of the modem.
1049 next_state = PLAN_ACTIVATION_RECONNECTING_PAYMENT;
1051 case PLAN_ACTIVATION_INITIATING_ACTIVATION:
1052 case PLAN_ACTIVATION_TRYING_OTASP:
1053 next_state = PLAN_ACTIVATION_START;
1055 case PLAN_ACTIVATION_START_OTASP:
1056 case PLAN_ACTIVATION_OTASP:
1057 if (!network || !network->IsConnectedState()) {
1058 next_state = PLAN_ACTIVATION_START_OTASP;
1060 // We're online, which means we've conspired with
1061 // PickNextOnlineState to reconnect after activation (that's the
1062 // only way we see this transition). Thus, after we reconnect, we
1064 next_state = PLAN_ACTIVATION_DONE;
1068 LOG(ERROR) << "Transitioned to RECONNECTING from an unexpected "
1073 ForceReconnect(network, next_state);
1076 case PLAN_ACTIVATION_DONE:
1078 CompleteActivation();
1079 UMA_HISTOGRAM_COUNTS("Cellular.MobileSetupSucceeded", 1);
1081 case PLAN_ACTIVATION_ERROR:
1082 CompleteActivation();
1083 UMA_HISTOGRAM_COUNTS("Cellular.PlanFailed", 1);
1090 void MobileActivator::ReEnableCertRevocationChecking() {
1091 // Check that both the browser process and prefs exist before trying to
1092 // use them, since this method can be called by the destructor while Chrome
1093 // is shutting down, during which either could be NULL.
1094 if (!g_browser_process)
1096 PrefService* prefs = g_browser_process->local_state();
1099 if (reenable_cert_check_) {
1100 prefs->SetBoolean(prefs::kCertRevocationCheckingEnabled,
1102 reenable_cert_check_ = false;
1106 void MobileActivator::DisableCertRevocationChecking() {
1107 // Disable SSL cert checks since we might be performing activation in the
1109 // TODO(rkc): We want to do this only if on Cellular.
1110 PrefService* prefs = g_browser_process->local_state();
1111 if (!reenable_cert_check_ &&
1113 prefs::kCertRevocationCheckingEnabled)) {
1114 reenable_cert_check_ = true;
1115 prefs->SetBoolean(prefs::kCertRevocationCheckingEnabled, false);
1119 bool MobileActivator::GotActivationError(
1120 const NetworkState* network, std::string* error) const {
1122 bool got_error = false;
1123 const char* error_code = kErrorDefault;
1124 const std::string& activation = network->activation_state();
1126 // This is the magic for detection of errors in during activation process.
1127 if (network->connection_state() == shill::kStateFailure &&
1128 network->error() == shill::kErrorAaaFailed) {
1129 if (activation == shill::kActivationStatePartiallyActivated) {
1130 error_code = kErrorBadConnectionPartial;
1131 } else if (activation == shill::kActivationStateActivated) {
1132 if (network->roaming() == shill::kRoamingStateHome)
1133 error_code = kErrorBadConnectionActivated;
1134 else if (network->roaming() == shill::kRoamingStateRoaming)
1135 error_code = kErrorRoamingOnConnection;
1138 } else if (network->connection_state() == shill::kStateActivationFailure) {
1139 if (network->error() == shill::kErrorNeedEvdo) {
1140 if (activation == shill::kActivationStatePartiallyActivated)
1141 error_code = kErrorNoEVDO;
1142 } else if (network->error() == shill::kErrorNeedHomeNetwork) {
1143 if (activation == shill::kActivationStateNotActivated) {
1144 error_code = kErrorRoamingActivation;
1145 } else if (activation == shill::kActivationStatePartiallyActivated) {
1146 error_code = kErrorRoamingPartiallyActivated;
1153 *error = GetErrorMessage(error_code);
1158 std::string MobileActivator::GetErrorMessage(const std::string& code) const {
1159 return cellular_config_->GetErrorMessage(code);
1162 void MobileActivator::SignalCellularPlanPayment() {
1163 DCHECK(!HasRecentCellularPlanPayment());
1164 cellular_plan_payment_time_ = base::Time::Now();
1167 bool MobileActivator::HasRecentCellularPlanPayment() const {
1168 const int kRecentPlanPaymentHours = 6;
1169 return (base::Time::Now() -
1170 cellular_plan_payment_time_).InHours() < kRecentPlanPaymentHours;
1173 } // namespace chromeos