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