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 "base/bind.h"
12 #include "base/bind_helpers.h"
13 #include "base/files/file_util.h"
14 #include "base/json/json_reader.h"
15 #include "base/location.h"
16 #include "base/logging.h"
17 #include "base/memory/ref_counted_memory.h"
18 #include "base/message_loop/message_loop.h"
19 #include "base/metrics/histogram.h"
20 #include "base/observer_list_threadsafe.h"
21 #include "base/prefs/pref_service.h"
22 #include "base/strings/string_piece.h"
23 #include "base/strings/string_util.h"
24 #include "base/strings/utf_string_conversions.h"
25 #include "base/timer/timer.h"
26 #include "base/values.h"
27 #include "chrome/browser/browser_process.h"
28 #include "chrome/common/pref_names.h"
29 #include "chromeos/network/device_state.h"
30 #include "chromeos/network/network_activation_handler.h"
31 #include "chromeos/network/network_configuration_handler.h"
32 #include "chromeos/network/network_connection_handler.h"
33 #include "chromeos/network/network_event_log.h"
34 #include "chromeos/network/network_handler_callbacks.h"
35 #include "chromeos/network/network_state.h"
36 #include "chromeos/network/network_state_handler.h"
37 #include "content/public/browser/browser_thread.h"
38 #include "third_party/cros_system_api/dbus/service_constants.h"
39 #include "ui/chromeos/network/network_connect.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_CURRENTLY_ON(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 base::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_CURRENTLY_ON(BrowserThread::UI
);
243 observers_
.AddObserver(observer
);
246 void MobileActivator::RemoveObserver(MobileActivator::Observer
* observer
) {
247 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
248 observers_
.RemoveObserver(observer
);
251 void MobileActivator::InitiateActivation(const std::string
& service_path
) {
252 DCHECK_CURRENTLY_ON(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()->GetShillProperties(
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()->SetShillProperties(
317 service_path_
, auto_connect_property
,
318 // Activation is triggered by the UI.
319 NetworkConfigurationObserver::SOURCE_USER_ACTION
,
320 base::Bind(&base::DoNothing
), 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 ui::NetworkConnect::Get()->ConnectToNetwork(network
->path());
632 void MobileActivator::RefreshCellularNetworks() {
633 if (state_
== PLAN_ACTIVATION_PAGE_LOADING
||
634 state_
== PLAN_ACTIVATION_DONE
||
635 state_
== PLAN_ACTIVATION_ERROR
) {
639 const NetworkState
* network
= GetNetworkState(service_path_
);
641 LOG(WARNING
) << "Cellular service can't be found: " << service_path_
;
645 if (IsSimpleActivationFlow(network
)) {
646 bool waiting
= (state_
== PLAN_ACTIVATION_WAITING_FOR_CONNECTION
);
647 // We're only interested in whether or not we have access to the payment
648 // portal (regardless of which network we use to access it), so check
649 // the default network connection state. The default network is the network
650 // used to route default traffic. Also, note that we can access the
651 // payment portal over a cellular network in the portalled state.
652 const NetworkState
* default_network
= GetDefaultNetwork();
653 bool is_online_or_portal
= default_network
&&
654 (default_network
->connection_state() == shill::kStateOnline
||
655 (default_network
->type() == shill::kTypeCellular
&&
656 default_network
->connection_state() == shill::kStatePortal
));
657 if (waiting
&& is_online_or_portal
) {
658 ChangeState(network
, post_reconnect_state_
, "");
659 } else if (!waiting
&& !is_online_or_portal
) {
660 ChangeState(network
, PLAN_ACTIVATION_WAITING_FOR_CONNECTION
, "");
664 EvaluateCellularNetwork(network
);
667 const NetworkState
* MobileActivator::GetNetworkState(
668 const std::string
& service_path
) {
669 return NetworkHandler::Get()->network_state_handler()->GetNetworkState(
673 const NetworkState
* MobileActivator::GetDefaultNetwork() {
674 return NetworkHandler::Get()->network_state_handler()->DefaultNetwork();
677 void MobileActivator::EvaluateCellularNetwork(const NetworkState
* network
) {
679 LOG(ERROR
) << "Tried to run MobileActivator state machine while "
685 LOG(WARNING
) << "Cellular service lost";
689 LOG(WARNING
) << "Cellular:\n service state=" << network
->connection_state()
690 << "\n ui=" << GetStateDescription(state_
)
691 << "\n activation=" << network
->activation_state()
692 << "\n error=" << network
->error()
693 << "\n setvice_path=" << network
->path()
694 << "\n connected=" << network
->IsConnectedState();
696 // If the network is activated over non cellular network or OTA, the
697 // activator state does not depend on the network's own state.
698 if (IsSimpleActivationFlow(network
))
701 std::string error_description
;
702 PlanActivationState new_state
= PickNextState(network
, &error_description
);
704 ChangeState(network
, new_state
, error_description
);
707 MobileActivator::PlanActivationState
MobileActivator::PickNextState(
708 const NetworkState
* network
, std::string
* error_description
) const {
709 PlanActivationState new_state
= state_
;
710 if (!network
->IsConnectedState())
711 new_state
= PickNextOfflineState(network
);
713 new_state
= PickNextOnlineState(network
);
714 if (new_state
!= PLAN_ACTIVATION_ERROR
&&
715 GotActivationError(network
, error_description
)) {
716 // Check for this special case when we try to do activate partially
717 // activated device. If that attempt failed, try to disconnect to clear the
718 // state and reconnect again.
719 const std::string
& activation
= network
->activation_state();
720 if ((activation
== shill::kActivationStatePartiallyActivated
||
721 activation
== shill::kActivationStateActivating
) &&
722 (network
->error().empty() ||
723 network
->error() == shill::kErrorOtaspFailed
) &&
724 network
->connection_state() == shill::kStateActivationFailure
) {
725 NET_LOG_EVENT("Activation failure detected ", network
->path());
727 case PLAN_ACTIVATION_OTASP
:
728 new_state
= PLAN_ACTIVATION_DELAY_OTASP
;
730 case PLAN_ACTIVATION_INITIATING_ACTIVATION
:
731 case PLAN_ACTIVATION_TRYING_OTASP
:
732 new_state
= PLAN_ACTIVATION_START
;
734 case PLAN_ACTIVATION_START
:
735 // We are just starting, so this must be previous activation attempt
737 new_state
= PLAN_ACTIVATION_TRYING_OTASP
;
739 case PLAN_ACTIVATION_DELAY_OTASP
:
743 new_state
= PLAN_ACTIVATION_ERROR
;
747 LOG(WARNING
) << "Unexpected activation failure for " << network
->path();
748 new_state
= PLAN_ACTIVATION_ERROR
;
752 if (new_state
== PLAN_ACTIVATION_ERROR
&& !error_description
->length())
753 *error_description
= GetErrorMessage(kErrorDefault
);
757 MobileActivator::PlanActivationState
MobileActivator::PickNextOfflineState(
758 const NetworkState
* network
) const {
759 PlanActivationState new_state
= state_
;
760 const std::string
& activation
= network
->activation_state();
762 case PLAN_ACTIVATION_PAYMENT_PORTAL_LOADING
:
763 case PLAN_ACTIVATION_SHOWING_PAYMENT
:
764 if (!IsSimpleActivationFlow(network
))
765 new_state
= PLAN_ACTIVATION_RECONNECTING
;
767 case PLAN_ACTIVATION_START
:
768 if (activation
== shill::kActivationStateActivated
) {
769 if (network
->connection_state() == shill::kStatePortal
)
770 new_state
= PLAN_ACTIVATION_PAYMENT_PORTAL_LOADING
;
772 new_state
= PLAN_ACTIVATION_DONE
;
773 } else if (activation
== shill::kActivationStatePartiallyActivated
) {
774 new_state
= PLAN_ACTIVATION_TRYING_OTASP
;
776 new_state
= PLAN_ACTIVATION_INITIATING_ACTIVATION
;
780 VLOG(1) << "Waiting for cellular service to connect.";
786 MobileActivator::PlanActivationState
MobileActivator::PickNextOnlineState(
787 const NetworkState
* network
) const {
788 PlanActivationState new_state
= state_
;
789 const std::string
& activation
= network
->activation_state();
791 case PLAN_ACTIVATION_START
:
792 if (activation
== shill::kActivationStateActivated
) {
793 if (network
->connection_state() == shill::kStateOnline
)
794 new_state
= PLAN_ACTIVATION_DONE
;
796 new_state
= PLAN_ACTIVATION_PAYMENT_PORTAL_LOADING
;
797 } else if (activation
== shill::kActivationStatePartiallyActivated
) {
798 new_state
= PLAN_ACTIVATION_TRYING_OTASP
;
800 new_state
= PLAN_ACTIVATION_INITIATING_ACTIVATION
;
803 case PLAN_ACTIVATION_START_OTASP
: {
804 if (activation
== shill::kActivationStatePartiallyActivated
) {
805 new_state
= PLAN_ACTIVATION_OTASP
;
806 } else if (activation
== shill::kActivationStateActivated
) {
807 new_state
= PLAN_ACTIVATION_RECONNECTING
;
809 LOG(WARNING
) << "Unexpected activation state for device "
814 case PLAN_ACTIVATION_DELAY_OTASP
:
815 // Just ignore any changes until the OTASP retry timer kicks in.
817 case PLAN_ACTIVATION_INITIATING_ACTIVATION
: {
818 if (pending_activation_request_
) {
819 VLOG(1) << "Waiting for pending activation attempt to finish";
820 } else if (activation
== shill::kActivationStateActivated
||
821 activation
== shill::kActivationStatePartiallyActivated
) {
822 new_state
= PLAN_ACTIVATION_START
;
823 } else if (activation
== shill::kActivationStateNotActivated
||
824 activation
== shill::kActivationStateActivating
) {
825 // Wait in this state until activation state changes.
827 LOG(WARNING
) << "Unknown transition";
831 case PLAN_ACTIVATION_OTASP
:
832 case PLAN_ACTIVATION_TRYING_OTASP
:
833 if (pending_activation_request_
) {
834 VLOG(1) << "Waiting for pending activation attempt to finish";
835 } else if (activation
== shill::kActivationStateNotActivated
||
836 activation
== shill::kActivationStateActivating
) {
837 VLOG(1) << "Waiting for the OTASP to finish and the service to "
838 << "come back online";
839 } else if (activation
== shill::kActivationStateActivated
) {
840 new_state
= PLAN_ACTIVATION_DONE
;
842 new_state
= PLAN_ACTIVATION_PAYMENT_PORTAL_LOADING
;
845 case PLAN_ACTIVATION_RECONNECTING_PAYMENT
:
846 if (network
->connection_state() != shill::kStatePortal
&&
847 activation
== shill::kActivationStateActivated
)
848 // We're not portalled, and we're already activated, so we're online!
849 new_state
= PLAN_ACTIVATION_DONE
;
851 new_state
= PLAN_ACTIVATION_PAYMENT_PORTAL_LOADING
;
854 case PLAN_ACTIVATION_PAGE_LOADING
:
856 // Just ignore all signals until the site confirms payment.
857 case PLAN_ACTIVATION_PAYMENT_PORTAL_LOADING
:
858 case PLAN_ACTIVATION_SHOWING_PAYMENT
:
859 case PLAN_ACTIVATION_WAITING_FOR_CONNECTION
:
861 // Go where we decided earlier.
862 case PLAN_ACTIVATION_RECONNECTING
:
863 new_state
= post_reconnect_state_
;
865 // Activation completed/failed, ignore network changes.
866 case PLAN_ACTIVATION_DONE
:
867 case PLAN_ACTIVATION_ERROR
:
874 // Debugging helper function, will take it out at the end.
875 const char* MobileActivator::GetStateDescription(PlanActivationState state
) {
877 case PLAN_ACTIVATION_PAGE_LOADING
:
878 return "PAGE_LOADING";
879 case PLAN_ACTIVATION_START
:
880 return "ACTIVATION_START";
881 case PLAN_ACTIVATION_INITIATING_ACTIVATION
:
882 return "INITIATING_ACTIVATION";
883 case PLAN_ACTIVATION_TRYING_OTASP
:
884 return "TRYING_OTASP";
885 case PLAN_ACTIVATION_PAYMENT_PORTAL_LOADING
:
886 return "PAYMENT_PORTAL_LOADING";
887 case PLAN_ACTIVATION_SHOWING_PAYMENT
:
888 return "SHOWING_PAYMENT";
889 case PLAN_ACTIVATION_RECONNECTING_PAYMENT
:
890 return "RECONNECTING_PAYMENT";
891 case PLAN_ACTIVATION_DELAY_OTASP
:
892 return "DELAY_OTASP";
893 case PLAN_ACTIVATION_START_OTASP
:
894 return "START_OTASP";
895 case PLAN_ACTIVATION_OTASP
:
897 case PLAN_ACTIVATION_DONE
:
899 case PLAN_ACTIVATION_ERROR
:
901 case PLAN_ACTIVATION_RECONNECTING
:
902 return "RECONNECTING";
903 case PLAN_ACTIVATION_WAITING_FOR_CONNECTION
:
904 return "WAITING FOR CONNECTION";
910 void MobileActivator::CompleteActivation() {
911 // Remove observers, we are done with this page.
912 NetworkHandler::Get()->network_state_handler()->
913 RemoveObserver(this, FROM_HERE
);
915 // Reactivate other types of connections if we have
916 // shut them down previously.
917 ReEnableCertRevocationChecking();
920 bool MobileActivator::RunningActivation() const {
921 return !(state_
== PLAN_ACTIVATION_DONE
||
922 state_
== PLAN_ACTIVATION_ERROR
||
923 state_
== PLAN_ACTIVATION_PAGE_LOADING
);
926 void MobileActivator::HandleActivationFailure(
927 const std::string
& service_path
,
928 PlanActivationState new_state
,
929 const std::string
& error_name
,
930 scoped_ptr
<base::DictionaryValue
> error_data
) {
931 pending_activation_request_
= false;
932 const NetworkState
* network
= GetNetworkState(service_path
);
934 NET_LOG_ERROR("Cellular service no longer exists", service_path
);
937 UMA_HISTOGRAM_COUNTS("Cellular.ActivationFailure", 1);
938 NET_LOG_ERROR("Failed to call Activate() on service", service_path
);
939 if (new_state
== PLAN_ACTIVATION_OTASP
) {
940 ChangeState(network
, PLAN_ACTIVATION_DELAY_OTASP
, std::string());
943 PLAN_ACTIVATION_ERROR
,
944 GetErrorMessage(kFailedConnectivity
));
948 void MobileActivator::RequestCellularActivation(
949 const NetworkState
* network
,
950 const base::Closure
& success_callback
,
951 const network_handler::ErrorCallback
& error_callback
) {
953 NET_LOG_EVENT("Activating cellular service", network
->path());
954 UMA_HISTOGRAM_COUNTS("Cellular.ActivationTry", 1);
955 pending_activation_request_
= true;
956 NetworkHandler::Get()->network_activation_handler()->
957 Activate(network
->path(),
963 void MobileActivator::ChangeState(const NetworkState
* network
,
964 PlanActivationState new_state
,
965 std::string error_description
) {
966 // Report an error, by transitioning into a PLAN_ACTIVATION_ERROR state with
967 // a "no service" error instead, if no network state is available (e.g. the
968 // cellular service no longer exists) when we are transitioning into certain
969 // plan activation state.
972 case PLAN_ACTIVATION_INITIATING_ACTIVATION
:
973 case PLAN_ACTIVATION_TRYING_OTASP
:
974 case PLAN_ACTIVATION_OTASP
:
975 case PLAN_ACTIVATION_DONE
:
976 new_state
= PLAN_ACTIVATION_ERROR
;
977 error_description
= GetErrorMessage(kErrorNoService
);
983 static bool first_time
= true;
984 VLOG(1) << "Activation state flip old = "
985 << GetStateDescription(state_
)
986 << ", new = " << GetStateDescription(new_state
);
987 if (state_
== new_state
&& !first_time
)
990 VLOG(1) << "Transitioning...";
992 // Kill all the possible timers and callbacks we might have outstanding.
993 state_duration_timer_
.Stop();
994 continue_reconnect_timer_
.Stop();
995 reconnect_timeout_timer_
.Stop();
996 const PlanActivationState old_state
= state_
;
999 // Signal to observers layer that the state is changing.
1000 FOR_EACH_OBSERVER(Observer
, observers_
,
1001 OnActivationStateChanged(network
, state_
, error_description
));
1003 // Pick action that should happen on entering the new state.
1004 switch (new_state
) {
1005 case PLAN_ACTIVATION_START
:
1007 case PLAN_ACTIVATION_DELAY_OTASP
: {
1008 UMA_HISTOGRAM_COUNTS("Cellular.RetryOTASP", 1);
1009 BrowserThread::PostDelayedTask(BrowserThread::UI
, FROM_HERE
,
1010 base::Bind(&MobileActivator::RetryOTASP
, AsWeakPtr()),
1011 base::TimeDelta::FromMilliseconds(kOTASPRetryDelay
));
1014 case PLAN_ACTIVATION_START_OTASP
:
1016 case PLAN_ACTIVATION_INITIATING_ACTIVATION
:
1017 case PLAN_ACTIVATION_TRYING_OTASP
:
1018 case PLAN_ACTIVATION_OTASP
: {
1020 network_handler::ErrorCallback on_activation_error
=
1021 base::Bind(&MobileActivator::HandleActivationFailure
, AsWeakPtr(),
1024 RequestCellularActivation(
1026 base::Bind(&MobileActivator::StartOTASPTimer
, AsWeakPtr()),
1027 on_activation_error
);
1030 case PLAN_ACTIVATION_PAGE_LOADING
:
1032 case PLAN_ACTIVATION_PAYMENT_PORTAL_LOADING
:
1033 case PLAN_ACTIVATION_SHOWING_PAYMENT
:
1034 case PLAN_ACTIVATION_RECONNECTING_PAYMENT
:
1035 // Fix for fix SSL for the walled gardens where cert chain verification
1038 case PLAN_ACTIVATION_WAITING_FOR_CONNECTION
:
1039 post_reconnect_state_
= old_state
;
1041 case PLAN_ACTIVATION_RECONNECTING
: {
1042 PlanActivationState next_state
= old_state
;
1043 // Pick where we want to return to after we reconnect.
1044 switch (old_state
) {
1045 case PLAN_ACTIVATION_PAYMENT_PORTAL_LOADING
:
1046 case PLAN_ACTIVATION_SHOWING_PAYMENT
:
1047 // We decide here what to do next based on the state of the modem.
1048 next_state
= PLAN_ACTIVATION_RECONNECTING_PAYMENT
;
1050 case PLAN_ACTIVATION_INITIATING_ACTIVATION
:
1051 case PLAN_ACTIVATION_TRYING_OTASP
:
1052 next_state
= PLAN_ACTIVATION_START
;
1054 case PLAN_ACTIVATION_START_OTASP
:
1055 case PLAN_ACTIVATION_OTASP
:
1056 if (!network
|| !network
->IsConnectedState()) {
1057 next_state
= PLAN_ACTIVATION_START_OTASP
;
1059 // We're online, which means we've conspired with
1060 // PickNextOnlineState to reconnect after activation (that's the
1061 // only way we see this transition). Thus, after we reconnect, we
1063 next_state
= PLAN_ACTIVATION_DONE
;
1067 LOG(ERROR
) << "Transitioned to RECONNECTING from an unexpected "
1072 ForceReconnect(network
, next_state
);
1075 case PLAN_ACTIVATION_DONE
:
1077 CompleteActivation();
1078 UMA_HISTOGRAM_COUNTS("Cellular.MobileSetupSucceeded", 1);
1080 case PLAN_ACTIVATION_ERROR
:
1081 CompleteActivation();
1082 UMA_HISTOGRAM_COUNTS("Cellular.PlanFailed", 1);
1089 void MobileActivator::ReEnableCertRevocationChecking() {
1090 // Check that both the browser process and prefs exist before trying to
1091 // use them, since this method can be called by the destructor while Chrome
1092 // is shutting down, during which either could be NULL.
1093 if (!g_browser_process
)
1095 PrefService
* prefs
= g_browser_process
->local_state();
1098 if (reenable_cert_check_
) {
1099 prefs
->SetBoolean(prefs::kCertRevocationCheckingEnabled
,
1101 reenable_cert_check_
= false;
1105 void MobileActivator::DisableCertRevocationChecking() {
1106 // Disable SSL cert checks since we might be performing activation in the
1108 // TODO(rkc): We want to do this only if on Cellular.
1109 PrefService
* prefs
= g_browser_process
->local_state();
1110 if (!reenable_cert_check_
&&
1112 prefs::kCertRevocationCheckingEnabled
)) {
1113 reenable_cert_check_
= true;
1114 prefs
->SetBoolean(prefs::kCertRevocationCheckingEnabled
, false);
1118 bool MobileActivator::GotActivationError(
1119 const NetworkState
* network
, std::string
* error
) const {
1121 bool got_error
= false;
1122 const char* error_code
= kErrorDefault
;
1123 const std::string
& activation
= network
->activation_state();
1125 // This is the magic for detection of errors in during activation process.
1126 if (network
->connection_state() == shill::kStateFailure
&&
1127 network
->error() == shill::kErrorAaaFailed
) {
1128 if (activation
== shill::kActivationStatePartiallyActivated
) {
1129 error_code
= kErrorBadConnectionPartial
;
1130 } else if (activation
== shill::kActivationStateActivated
) {
1131 if (network
->roaming() == shill::kRoamingStateHome
)
1132 error_code
= kErrorBadConnectionActivated
;
1133 else if (network
->roaming() == shill::kRoamingStateRoaming
)
1134 error_code
= kErrorRoamingOnConnection
;
1137 } else if (network
->connection_state() == shill::kStateActivationFailure
) {
1138 if (network
->error() == shill::kErrorNeedEvdo
) {
1139 if (activation
== shill::kActivationStatePartiallyActivated
)
1140 error_code
= kErrorNoEVDO
;
1141 } else if (network
->error() == shill::kErrorNeedHomeNetwork
) {
1142 if (activation
== shill::kActivationStateNotActivated
) {
1143 error_code
= kErrorRoamingActivation
;
1144 } else if (activation
== shill::kActivationStatePartiallyActivated
) {
1145 error_code
= kErrorRoamingPartiallyActivated
;
1152 *error
= GetErrorMessage(error_code
);
1157 std::string
MobileActivator::GetErrorMessage(const std::string
& code
) const {
1158 return cellular_config_
->GetErrorMessage(code
);
1161 void MobileActivator::SignalCellularPlanPayment() {
1162 DCHECK(!HasRecentCellularPlanPayment());
1163 cellular_plan_payment_time_
= base::Time::Now();
1166 bool MobileActivator::HasRecentCellularPlanPayment() const {
1167 const int kRecentPlanPaymentHours
= 6;
1168 return (base::Time::Now() -
1169 cellular_plan_payment_time_
).InHours() < kRecentPlanPaymentHours
;
1172 } // namespace chromeos