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 "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"
42 using content::BrowserThread;
46 // Cellular configuration file path.
47 const char kCellularConfigPath[] =
48 "/usr/share/chromeos-assets/mobile/mobile_config.json";
50 // Cellular config file field names.
51 const char kVersionField[] = "version";
52 const char kErrorsField[] = "errors";
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;
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";
83 ////////////////////////////////////////////////////////////////////////////////
85 // CellularConfigDocument
87 ////////////////////////////////////////////////////////////////////////////////
88 CellularConfigDocument::CellularConfigDocument() {}
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())
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))
105 if (LoadFromFile(config_path))
106 DVLOG(1) << "Cellular config file loaded: " << kCellularConfigPath;
108 LOG(ERROR) << "Error loading cellular config file: " << kCellularConfigPath;
111 CellularConfigDocument::~CellularConfigDocument() {}
113 void CellularConfigDocument::SetErrorMap(
114 const ErrorMap& map) {
115 base::AutoLock create(config_lock_);
117 error_map_.insert(map.begin(), map.end());
120 bool CellularConfigDocument::LoadFromFile(const base::FilePath& config_path) {
122 if (!base::ReadFileToString(config_path, &config))
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";
133 DictionaryValue* root_dict = static_cast<DictionaryValue*>(root.get());
134 if (!root_dict->GetString(kVersionField, &version_)) {
135 LOG(WARNING) << "Cellular config file missing version";
139 DictionaryValue* errors = NULL;
140 if (!root_dict->GetDictionary(kErrorsField, &errors))
142 for (DictionaryValue::Iterator it(*errors); !it.IsAtEnd(); it.Advance()) {
144 if (!it.value().GetAsString(&value)) {
145 LOG(WARNING) << "Bad cellular config error value";
148 error_map.insert(ErrorMap::value_type(it.key(), value));
150 SetErrorMap(error_map);
154 ////////////////////////////////////////////////////////////////////////////////
158 ////////////////////////////////////////////////////////////////////////////////
159 MobileActivator::MobileActivator()
160 : cellular_config_(new CellularConfigDocument()),
161 state_(PLAN_ACTIVATION_PAGE_LOADING),
162 reenable_cert_check_(false),
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) {
173 MobileActivator::~MobileActivator() {
174 TerminateActivation();
177 MobileActivator* MobileActivator::GetInstance() {
178 return Singleton<MobileActivator>::get();
181 void MobileActivator::TerminateActivation() {
182 state_duration_timer_.Stop();
183 continue_reconnect_timer_.Stop();
184 reconnect_timeout_timer_.Stop();
186 if (NetworkHandler::IsInitialized())
187 NetworkHandler::Get()->network_state_handler()->RemoveObserver(this,
189 ReEnableCertRevocationChecking();
192 service_path_.clear();
193 device_path_.clear();
194 state_ = PLAN_ACTIVATION_PAGE_LOADING;
195 reenable_cert_check_ = false;
197 // Release the previous cellular config and setup a new empty one.
198 cellular_config_ = new CellularConfigDocument();
201 void MobileActivator::DefaultNetworkChanged(const NetworkState* network) {
202 RefreshCellularNetworks();
205 void MobileActivator::NetworkPropertiesUpdated(const NetworkState* network) {
206 if (state_ == PLAN_ACTIVATION_PAGE_LOADING)
209 if (!network || network->type() != shill::kTypeCellular)
212 const DeviceState* device = NetworkHandler::Get()->network_state_handler()->
213 GetDeviceState(network->device_path());
215 LOG(ERROR) << "Cellular device can't be found: " << network->device_path();
218 if (network->device_path() != device_path_) {
219 LOG(WARNING) << "Ignoring property update for cellular service "
221 << " on unknown device " << network->device_path()
222 << " (Stored device path = " << device_path_ << ")";
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();
230 EvaluateCellularNetwork(network);
233 void MobileActivator::AddObserver(MobileActivator::Observer* observer) {
234 DCHECK(content::BrowserThread::CurrentlyOn(BrowserThread::UI));
235 observers_.AddObserver(observer);
238 void MobileActivator::RemoveObserver(MobileActivator::Observer* observer) {
239 DCHECK(content::BrowserThread::CurrentlyOn(BrowserThread::UI));
240 observers_.RemoveObserver(observer);
243 void MobileActivator::InitiateActivation(const std::string& service_path) {
244 DCHECK(content::BrowserThread::CurrentlyOn(BrowserThread::UI));
245 const NetworkState* network = GetNetworkState(service_path);
247 LOG(ERROR) << "Cellular service can't be found: " << service_path;
251 const DeviceState* device = NetworkHandler::Get()->network_state_handler()->
252 GetDeviceState(network->device_path());
254 LOG(ERROR) << "Cellular device can't be found: " << network->device_path();
259 meid_ = device->meid();
260 iccid_ = device->iccid();
261 service_path_ = service_path;
262 device_path_ = network->device_path();
264 ChangeState(network, PLAN_ACTIVATION_PAGE_LOADING, "");
266 BrowserThread::PostTaskAndReply(BrowserThread::FILE, FROM_HERE,
267 base::Bind(&CellularConfigDocument::LoadCellularConfigFile,
268 cellular_config_.get()),
269 base::Bind(&MobileActivator::ContinueActivation, AsWeakPtr()));
272 void MobileActivator::ContinueActivation() {
273 NetworkHandler::Get()->network_configuration_handler()->GetProperties(
275 base::Bind(&MobileActivator::GetPropertiesAndContinueActivation,
276 weak_ptr_factory_.GetWeakPtr()),
277 base::Bind(&MobileActivator::GetPropertiesFailure,
278 weak_ptr_factory_.GetWeakPtr()));
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",
287 return; // Edge case; abort.
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_);
301 if (payment_url.empty() && usage_url.empty())
304 DisableCertRevocationChecking();
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(
311 auto_connect_property,
312 base::Bind(&base::DoNothing),
313 network_handler::ErrorCallback());
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,
324 void MobileActivator::OnSetTransactionStatus(bool success) {
325 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
326 base::Bind(&MobileActivator::HandleSetTransactionStatus,
327 AsWeakPtr(), success));
330 void MobileActivator::HandleSetTransactionStatus(bool success) {
331 // The payment is received, try to reconnect and check the status all over
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());
347 UMA_HISTOGRAM_COUNTS("Cellular.PaymentFailed", 1);
351 void MobileActivator::OnPortalLoaded(bool success) {
352 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
353 base::Bind(&MobileActivator::HandlePortalLoaded,
354 AsWeakPtr(), success));
357 void MobileActivator::HandlePortalLoaded(bool success) {
358 const NetworkState* network = GetNetworkState(service_path_);
360 ChangeState(NULL, PLAN_ACTIVATION_ERROR,
361 GetErrorMessage(kErrorNoService));
364 if (state_ == PLAN_ACTIVATION_PAYMENT_PORTAL_LOADING ||
365 state_ == PLAN_ACTIVATION_SHOWING_PAYMENT) {
367 payment_reconnect_count_ = 0;
368 ChangeState(network, PLAN_ACTIVATION_SHOWING_PAYMENT, std::string());
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())
375 payment_reconnect_count_++;
376 if (payment_reconnect_count_ > kMaxPortalReconnectCount) {
377 ChangeState(NULL, PLAN_ACTIVATION_ERROR,
378 GetErrorMessage(kErrorNoService));
382 // Reconnect and try and load the frame again.
384 PLAN_ACTIVATION_RECONNECTING,
385 GetErrorMessage(kFailedPaymentError));
388 NOTREACHED() << "Called paymentPortalLoad while in unexpected state: "
389 << GetStateDescription(state_);
393 void MobileActivator::StartOTASPTimer() {
394 pending_activation_request_ = false;
395 state_duration_timer_.Start(
397 base::TimeDelta::FromMilliseconds(kOTASPRetryDelay),
398 this, &MobileActivator::HandleOTASPTimeout);
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.
406 NetworkStateHandler::TechnologyState technology_state =
407 NetworkHandler::Get()->network_state_handler()->GetTechnologyState(
408 NetworkTypePattern::Cellular());
410 if (technology_state == NetworkStateHandler::TECHNOLOGY_UNAVAILABLE) {
411 error = kErrorNoDevice;
412 } else if (technology_state != NetworkStateHandler::TECHNOLOGY_ENABLED) {
413 error = kErrorDisabled;
415 error = kErrorNoService;
417 ChangeState(NULL, PLAN_ACTIVATION_ERROR, GetErrorMessage(error));
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.
428 (network->activation_state() == shill::kActivationStateActivated) ?
429 PLAN_ACTIVATION_DONE :
430 PLAN_ACTIVATION_PAYMENT_PORTAL_LOADING,
432 // Verify that there is no need to wait for the connection. This will also
433 // evaluate the network.
434 RefreshCellularNetworks();
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;
444 state_ = PLAN_ACTIVATION_START;
447 EvaluateCellularNetwork(network);
450 void MobileActivator::RetryOTASP() {
451 DCHECK(state_ == PLAN_ACTIVATION_DELAY_OTASP);
455 void MobileActivator::StartOTASP() {
456 const NetworkState* network = GetNetworkState(service_path_);
457 ChangeState(network, PLAN_ACTIVATION_START_OTASP, std::string());
458 EvaluateCellularNetwork(network);
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) {
470 PLAN_ACTIVATION_RECONNECTING,
471 GetErrorMessage(kErrorDefault));
474 } else if (state_ == PLAN_ACTIVATION_TRYING_OTASP) {
475 ++trying_OTASP_attempts_;
476 if (trying_OTASP_attempts_ <= kMaxOTASPTries) {
478 PLAN_ACTIVATION_RECONNECTING,
479 GetErrorMessage(kErrorDefault));
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.
487 PLAN_ACTIVATION_DELAY_OTASP,
488 GetErrorMessage(kErrorDefault));
492 LOG(ERROR) << "OTASP timed out from a non-OTASP wait state?";
494 LOG(ERROR) << "OTASP failed too many times; aborting.";
496 PLAN_ACTIVATION_ERROR,
497 GetErrorMessage(kErrorDefault));
500 void MobileActivator::ForceReconnect(const NetworkState* network,
501 PlanActivationState next_state) {
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
511 NetworkHandler::Get()->network_connection_handler()->DisconnectNetwork(
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(
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(
525 base::TimeDelta::FromMilliseconds(kMaxReconnectTime),
526 this, &MobileActivator::ReconnectTimedOut);
529 void MobileActivator::ReconnectTimedOut() {
530 LOG(ERROR) << "Ending activation attempt after failing to reconnect.";
531 const NetworkState* network = GetNetworkState(service_path_);
533 PLAN_ACTIVATION_ERROR,
534 GetErrorMessage(kFailedConnectivity));
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
545 NetworkHandler::Get()->network_connection_handler()->DisconnectNetwork(
547 base::Bind(&base::DoNothing),
548 network_handler::ErrorCallback());
551 // Stop this callback
552 continue_reconnect_timer_.Stop();
553 EvaluateCellularNetwork(network);
555 LOG(WARNING) << "Connect failed, will try again in a little bit.";
557 LOG(INFO) << "Connecting to: " << network->path();
558 ash::network_connect::ConnectToNetwork(
559 network->path(), NULL /* no parent window */);
564 void MobileActivator::RefreshCellularNetworks() {
565 if (state_ == PLAN_ACTIVATION_PAGE_LOADING ||
566 state_ == PLAN_ACTIVATION_DONE ||
567 state_ == PLAN_ACTIVATION_ERROR) {
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, "");
584 EvaluateCellularNetwork(network);
587 const NetworkState* MobileActivator::GetNetworkState(
588 const std::string& service_path) {
589 return NetworkHandler::Get()->network_state_handler()->GetNetworkState(
593 void MobileActivator::EvaluateCellularNetwork(const NetworkState* network) {
595 LOG(ERROR) << "Tried to run MobileActivator state machine while "
601 LOG(WARNING) << "Cellular service lost";
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();
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())
617 std::string error_description;
618 PlanActivationState new_state = PickNextState(network, &error_description);
620 ChangeState(network, new_state, error_description);
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);
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());
643 case PLAN_ACTIVATION_OTASP:
644 new_state = PLAN_ACTIVATION_DELAY_OTASP;
646 case PLAN_ACTIVATION_INITIATING_ACTIVATION:
647 case PLAN_ACTIVATION_TRYING_OTASP:
648 new_state = PLAN_ACTIVATION_START;
650 case PLAN_ACTIVATION_START:
651 // We are just starting, so this must be previous activation attempt
653 new_state = PLAN_ACTIVATION_TRYING_OTASP;
655 case PLAN_ACTIVATION_DELAY_OTASP:
659 new_state = PLAN_ACTIVATION_ERROR;
663 LOG(WARNING) << "Unexpected activation failure for " << network->path();
664 new_state = PLAN_ACTIVATION_ERROR;
668 if (new_state == PLAN_ACTIVATION_ERROR && !error_description->length())
669 *error_description = GetErrorMessage(kErrorDefault);
673 MobileActivator::PlanActivationState MobileActivator::PickNextOfflineState(
674 const NetworkState* network) const {
675 PlanActivationState new_state = state_;
676 const std::string& activation = network->activation_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;
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;
688 new_state = PLAN_ACTIVATION_DONE;
689 } else if (activation == shill::kActivationStatePartiallyActivated) {
690 new_state = PLAN_ACTIVATION_TRYING_OTASP;
692 new_state = PLAN_ACTIVATION_INITIATING_ACTIVATION;
696 LOG(INFO) << "Waiting for cellular service to connect.";
702 MobileActivator::PlanActivationState MobileActivator::PickNextOnlineState(
703 const NetworkState* network) const {
704 PlanActivationState new_state = state_;
705 const std::string& activation = network->activation_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;
712 new_state = PLAN_ACTIVATION_DONE;
713 } else if (activation == shill::kActivationStatePartiallyActivated) {
714 new_state = PLAN_ACTIVATION_TRYING_OTASP;
716 new_state = PLAN_ACTIVATION_INITIATING_ACTIVATION;
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;
725 LOG(WARNING) << "Unexpected activation state for device "
730 case PLAN_ACTIVATION_DELAY_OTASP:
731 // Just ignore any changes until the OTASP retry timer kicks in.
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.
743 LOG(WARNING) << "Unknown transition";
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;
758 new_state = PLAN_ACTIVATION_PAYMENT_PORTAL_LOADING;
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;
767 new_state = PLAN_ACTIVATION_PAYMENT_PORTAL_LOADING;
770 case PLAN_ACTIVATION_PAGE_LOADING:
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:
777 // Go where we decided earlier.
778 case PLAN_ACTIVATION_RECONNECTING:
779 new_state = post_reconnect_state_;
781 // Activation completed/failed, ignore network changes.
782 case PLAN_ACTIVATION_DONE:
783 case PLAN_ACTIVATION_ERROR:
790 // Debugging helper function, will take it out at the end.
791 const char* MobileActivator::GetStateDescription(PlanActivationState 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:
813 case PLAN_ACTIVATION_DONE:
815 case PLAN_ACTIVATION_ERROR:
817 case PLAN_ACTIVATION_RECONNECTING:
818 return "RECONNECTING";
819 case PLAN_ACTIVATION_WAITING_FOR_CONNECTION:
820 return "WAITING FOR CONNECTION";
826 void MobileActivator::CompleteActivation() {
827 // Remove observers, we are done with this page.
828 NetworkHandler::Get()->network_state_handler()->RemoveObserver(
831 // Reactivate other types of connections if we have
832 // shut them down previously.
833 ReEnableCertRevocationChecking();
836 bool MobileActivator::RunningActivation() const {
837 return !(state_ == PLAN_ACTIVATION_DONE ||
838 state_ == PLAN_ACTIVATION_ERROR ||
839 state_ == PLAN_ACTIVATION_PAGE_LOADING);
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);
850 NET_LOG_ERROR("Cellular service no longer exists", service_path);
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());
859 PLAN_ACTIVATION_ERROR,
860 GetErrorMessage(kFailedConnectivity));
864 void MobileActivator::RequestCellularActivation(
865 const NetworkState* network,
866 const base::Closure& success_callback,
867 const network_handler::ErrorCallback& error_callback) {
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(),
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)
889 LOG(INFO) << "Transitioning...";
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_;
898 // Signal to observers layer that the state is changing.
899 FOR_EACH_OBSERVER(Observer, observers_,
900 OnActivationStateChanged(network, state_, error_description));
902 // Pick action that should happen on entering the new state.
904 case PLAN_ACTIVATION_START:
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));
913 case PLAN_ACTIVATION_START_OTASP:
915 case PLAN_ACTIVATION_INITIATING_ACTIVATION:
916 case PLAN_ACTIVATION_TRYING_OTASP:
917 case PLAN_ACTIVATION_OTASP: {
919 network_handler::ErrorCallback on_activation_error =
920 base::Bind(&MobileActivator::HandleActivationFailure, AsWeakPtr(),
923 RequestCellularActivation(
925 base::Bind(&MobileActivator::StartOTASPTimer, AsWeakPtr()),
926 on_activation_error);
929 case PLAN_ACTIVATION_PAGE_LOADING:
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
937 case PLAN_ACTIVATION_WAITING_FOR_CONNECTION:
938 post_reconnect_state_ = old_state;
940 case PLAN_ACTIVATION_RECONNECTING: {
941 PlanActivationState next_state = old_state;
942 // Pick where we want to return to after we reconnect.
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;
949 case PLAN_ACTIVATION_INITIATING_ACTIVATION:
950 case PLAN_ACTIVATION_TRYING_OTASP:
951 next_state = PLAN_ACTIVATION_START;
953 case PLAN_ACTIVATION_START_OTASP:
954 case PLAN_ACTIVATION_OTASP:
955 if (!network || !network->IsConnectedState()) {
956 next_state = PLAN_ACTIVATION_START_OTASP;
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
962 next_state = PLAN_ACTIVATION_DONE;
966 LOG(ERROR) << "Transitioned to RECONNECTING from an unexpected "
970 ForceReconnect(network, next_state);
973 case PLAN_ACTIVATION_DONE:
975 CompleteActivation();
976 UMA_HISTOGRAM_COUNTS("Cellular.MobileSetupSucceeded", 1);
978 case PLAN_ACTIVATION_ERROR:
979 CompleteActivation();
980 UMA_HISTOGRAM_COUNTS("Cellular.PlanFailed", 1);
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)
993 PrefService* prefs = g_browser_process->local_state();
996 if (reenable_cert_check_) {
997 prefs->SetBoolean(prefs::kCertRevocationCheckingEnabled,
999 reenable_cert_check_ = false;
1003 void MobileActivator::DisableCertRevocationChecking() {
1004 // Disable SSL cert checks since we might be performing activation in the
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_ &&
1010 prefs::kCertRevocationCheckingEnabled)) {
1011 reenable_cert_check_ = true;
1012 prefs->SetBoolean(prefs::kCertRevocationCheckingEnabled, false);
1016 bool MobileActivator::GotActivationError(
1017 const NetworkState* network, std::string* error) const {
1019 bool got_error = false;
1020 const char* error_code = kErrorDefault;
1021 const std::string& activation = network->activation_state();
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;
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;
1050 *error = GetErrorMessage(error_code);
1055 std::string MobileActivator::GetErrorMessage(const std::string& code) const {
1056 return cellular_config_->GetErrorMessage(code);
1059 void MobileActivator::SignalCellularPlanPayment() {
1060 DCHECK(!HasRecentCellularPlanPayment());
1061 cellular_plan_payment_time_ = base::Time::Now();
1064 bool MobileActivator::HasRecentCellularPlanPayment() const {
1065 const int kRecentPlanPaymentHours = 6;
1066 return (base::Time::Now() -
1067 cellular_plan_payment_time_).InHours() < kRecentPlanPaymentHours;
1070 } // namespace chromeos