• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/files/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 // Returns true if the device follows the simple activation flow.
IsSimpleActivationFlow(const chromeos::NetworkState * network)79 bool IsSimpleActivationFlow(const chromeos::NetworkState* network) {
80   return (network->activation_type() == shill::kActivationTypeNonCellular ||
81           network->activation_type() == shill::kActivationTypeOTA);
82 }
83 
84 }  // namespace
85 
86 namespace chromeos {
87 
88 ////////////////////////////////////////////////////////////////////////////////
89 //
90 // CellularConfigDocument
91 //
92 ////////////////////////////////////////////////////////////////////////////////
CellularConfigDocument()93 CellularConfigDocument::CellularConfigDocument() {}
94 
GetErrorMessage(const std::string & code)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())
99     return code;
100   return iter->second;
101 }
102 
LoadCellularConfigFile()103 void CellularConfigDocument::LoadCellularConfigFile() {
104   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
105   // Load partner customization startup manifest if it is available.
106   base::FilePath config_path(kCellularConfigPath);
107   if (!base::PathExists(config_path))
108     return;
109 
110   if (LoadFromFile(config_path))
111     DVLOG(1) << "Cellular config file loaded: " << kCellularConfigPath;
112   else
113     LOG(ERROR) << "Error loading cellular config file: " << kCellularConfigPath;
114 }
115 
~CellularConfigDocument()116 CellularConfigDocument::~CellularConfigDocument() {}
117 
SetErrorMap(const ErrorMap & map)118 void CellularConfigDocument::SetErrorMap(
119     const ErrorMap& map) {
120   base::AutoLock create(config_lock_);
121   error_map_.clear();
122   error_map_.insert(map.begin(), map.end());
123 }
124 
LoadFromFile(const base::FilePath & config_path)125 bool CellularConfigDocument::LoadFromFile(const base::FilePath& config_path) {
126   std::string config;
127   if (!base::ReadFileToString(config_path, &config))
128     return false;
129 
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";
135     return false;
136   }
137 
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";
142     return false;
143   }
144   ErrorMap error_map;
145   base::DictionaryValue* errors = NULL;
146   if (!root_dict->GetDictionary(kErrorsField, &errors))
147     return false;
148   for (base::DictionaryValue::Iterator it(*errors);
149       !it.IsAtEnd(); it.Advance()) {
150     std::string value;
151     if (!it.value().GetAsString(&value)) {
152       LOG(WARNING) << "Bad cellular config error value";
153       return false;
154     }
155     error_map.insert(ErrorMap::value_type(it.key(), value));
156   }
157   SetErrorMap(error_map);
158   return true;
159 }
160 
161 ////////////////////////////////////////////////////////////////////////////////
162 //
163 // MobileActivator
164 //
165 ////////////////////////////////////////////////////////////////////////////////
MobileActivator()166 MobileActivator::MobileActivator()
167     : cellular_config_(new CellularConfigDocument()),
168       state_(PLAN_ACTIVATION_PAGE_LOADING),
169       reenable_cert_check_(false),
170       terminated_(true),
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) {
178 }
179 
~MobileActivator()180 MobileActivator::~MobileActivator() {
181   TerminateActivation();
182 }
183 
GetInstance()184 MobileActivator* MobileActivator::GetInstance() {
185   return Singleton<MobileActivator>::get();
186 }
187 
TerminateActivation()188 void MobileActivator::TerminateActivation() {
189   state_duration_timer_.Stop();
190   continue_reconnect_timer_.Stop();
191   reconnect_timeout_timer_.Stop();
192 
193   if (NetworkHandler::IsInitialized()) {
194     NetworkHandler::Get()->network_state_handler()->
195         RemoveObserver(this, FROM_HERE);
196   }
197   ReEnableCertRevocationChecking();
198   meid_.clear();
199   iccid_.clear();
200   service_path_.clear();
201   device_path_.clear();
202   state_ = PLAN_ACTIVATION_PAGE_LOADING;
203   reenable_cert_check_ = false;
204   terminated_ = true;
205   // Release the previous cellular config and setup a new empty one.
206   cellular_config_ = new CellularConfigDocument();
207 }
208 
DefaultNetworkChanged(const NetworkState * network)209 void MobileActivator::DefaultNetworkChanged(const NetworkState* network) {
210   RefreshCellularNetworks();
211 }
212 
NetworkPropertiesUpdated(const NetworkState * network)213 void MobileActivator::NetworkPropertiesUpdated(const NetworkState* network) {
214   if (state_ == PLAN_ACTIVATION_PAGE_LOADING)
215     return;
216 
217   if (!network || network->type() != shill::kTypeCellular)
218     return;
219 
220   const DeviceState* device = NetworkHandler::Get()->network_state_handler()->
221       GetDeviceState(network->device_path());
222   if (!device) {
223     LOG(ERROR) << "Cellular device can't be found: " << network->device_path();
224     return;
225   }
226   if (network->device_path() != device_path_) {
227     LOG(WARNING) << "Ignoring property update for cellular service "
228                  << network->path()
229                  << " on unknown device " << network->device_path()
230                  << " (Stored device path = " << device_path_ << ")";
231     return;
232   }
233 
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();
237 
238   EvaluateCellularNetwork(network);
239 }
240 
AddObserver(MobileActivator::Observer * observer)241 void MobileActivator::AddObserver(MobileActivator::Observer* observer) {
242   DCHECK(content::BrowserThread::CurrentlyOn(BrowserThread::UI));
243   observers_.AddObserver(observer);
244 }
245 
RemoveObserver(MobileActivator::Observer * observer)246 void MobileActivator::RemoveObserver(MobileActivator::Observer* observer) {
247   DCHECK(content::BrowserThread::CurrentlyOn(BrowserThread::UI));
248   observers_.RemoveObserver(observer);
249 }
250 
InitiateActivation(const std::string & service_path)251 void MobileActivator::InitiateActivation(const std::string& service_path) {
252   DCHECK(content::BrowserThread::CurrentlyOn(BrowserThread::UI));
253   const NetworkState* network =  GetNetworkState(service_path);
254   if (!network) {
255     LOG(WARNING) << "Cellular service can't be found: " << service_path;
256     return;
257   }
258   const DeviceState* device = NetworkHandler::Get()->network_state_handler()->
259       GetDeviceState(network->device_path());
260   if (!device) {
261     LOG(ERROR) << "Cellular device can't be found: " << network->device_path();
262     return;
263   }
264 
265   terminated_ = false;
266   meid_ = device->meid();
267   iccid_ = device->iccid();
268   service_path_ = service_path;
269   device_path_ = network->device_path();
270 
271   ChangeState(network, PLAN_ACTIVATION_PAGE_LOADING, "");
272 
273   BrowserThread::PostTaskAndReply(BrowserThread::FILE, FROM_HERE,
274       base::Bind(&CellularConfigDocument::LoadCellularConfigFile,
275                  cellular_config_.get()),
276       base::Bind(&MobileActivator::ContinueActivation, AsWeakPtr()));
277 }
278 
ContinueActivation()279 void MobileActivator::ContinueActivation() {
280   NetworkHandler::Get()->network_configuration_handler()->GetProperties(
281       service_path_,
282       base::Bind(&MobileActivator::GetPropertiesAndContinueActivation,
283                  weak_ptr_factory_.GetWeakPtr()),
284       base::Bind(&MobileActivator::GetPropertiesFailure,
285                  weak_ptr_factory_.GetWeakPtr()));
286 }
287 
GetPropertiesAndContinueActivation(const std::string & service_path,const base::DictionaryValue & properties)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",
293                   service_path);
294     return;  // Edge case; abort.
295   }
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_);
305     return;
306   }
307 
308   if (payment_url.empty() && usage_url.empty())
309     return;
310 
311   DisableCertRevocationChecking();
312 
313   // We want shill to connect us after activations, so enable autoconnect.
314   base::DictionaryValue auto_connect_property;
315   auto_connect_property.SetBoolean(shill::kAutoConnectProperty, true);
316   NetworkHandler::Get()->network_configuration_handler()->SetProperties(
317       service_path_,
318       auto_connect_property,
319       base::Bind(&base::DoNothing),
320       network_handler::ErrorCallback());
321   StartActivation();
322 }
323 
GetPropertiesFailure(const std::string & error_name,scoped_ptr<base::DictionaryValue> error_data)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,
328                 service_path_);
329 }
330 
OnSetTransactionStatus(bool success)331 void MobileActivator::OnSetTransactionStatus(bool success) {
332   BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
333       base::Bind(&MobileActivator::HandleSetTransactionStatus,
334                  AsWeakPtr(), success));
335 }
336 
HandleSetTransactionStatus(bool success)337 void MobileActivator::HandleSetTransactionStatus(bool success) {
338   // The payment is received, try to reconnect and check the status all over
339   // again.
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());
350     } else {
351       StartOTASP();
352     }
353   } else {
354     UMA_HISTOGRAM_COUNTS("Cellular.PaymentFailed", 1);
355   }
356 }
357 
OnPortalLoaded(bool success)358 void MobileActivator::OnPortalLoaded(bool success) {
359   BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
360       base::Bind(&MobileActivator::HandlePortalLoaded,
361                  AsWeakPtr(), success));
362 }
363 
HandlePortalLoaded(bool success)364 void MobileActivator::HandlePortalLoaded(bool success) {
365   const NetworkState* network = GetNetworkState(service_path_);
366   if (!network) {
367     ChangeState(NULL, PLAN_ACTIVATION_ERROR,
368                 GetErrorMessage(kErrorNoService));
369     return;
370   }
371   if (state_ == PLAN_ACTIVATION_PAYMENT_PORTAL_LOADING ||
372       state_ == PLAN_ACTIVATION_SHOWING_PAYMENT) {
373     if (success) {
374       payment_reconnect_count_ = 0;
375       ChangeState(network, PLAN_ACTIVATION_SHOWING_PAYMENT, std::string());
376     } else {
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)
380         return;
381 
382       payment_reconnect_count_++;
383       if (payment_reconnect_count_ > kMaxPortalReconnectCount) {
384         ChangeState(NULL, PLAN_ACTIVATION_ERROR,
385                     GetErrorMessage(kErrorNoService));
386         return;
387       }
388 
389       // Reconnect and try and load the frame again.
390       ChangeState(network,
391                   PLAN_ACTIVATION_RECONNECTING,
392                   GetErrorMessage(kFailedPaymentError));
393     }
394   } else {
395     NOTREACHED() << "Called paymentPortalLoad while in unexpected state: "
396                  << GetStateDescription(state_);
397   }
398 }
399 
StartOTASPTimer()400 void MobileActivator::StartOTASPTimer() {
401   pending_activation_request_ = false;
402   state_duration_timer_.Start(
403       FROM_HERE,
404       base::TimeDelta::FromMilliseconds(kOTASPRetryDelay),
405       this, &MobileActivator::HandleOTASPTimeout);
406 }
407 
StartActivation()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.
412   if (!network) {
413     NetworkStateHandler::TechnologyState technology_state =
414         NetworkHandler::Get()->network_state_handler()->GetTechnologyState(
415             NetworkTypePattern::Cellular());
416     std::string error;
417     if (technology_state == NetworkStateHandler::TECHNOLOGY_UNAVAILABLE) {
418       error = kErrorNoDevice;
419     } else if (technology_state != NetworkStateHandler::TECHNOLOGY_ENABLED) {
420       error = kErrorDisabled;
421     } else {
422       error = kErrorNoService;
423     }
424     ChangeState(NULL, PLAN_ACTIVATION_ERROR, GetErrorMessage(error));
425     return;
426   }
427 
428   // Start monitoring network property changes.
429   NetworkHandler::Get()->network_state_handler()->AddObserver(this, FROM_HERE);
430 
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();
437 }
438 
StartActivationOverNonCellularNetwork()439 void MobileActivator::StartActivationOverNonCellularNetwork() {
440   // Fast forward to payment portal loading.
441   const NetworkState* network = GetNetworkState(service_path_);
442   if (!network) {
443     LOG(WARNING) << "Cellular service can't be found: " << service_path_;
444     return;
445   }
446 
447   ChangeState(
448       network,
449       (network->activation_state() == shill::kActivationStateActivated) ?
450       PLAN_ACTIVATION_DONE :
451       PLAN_ACTIVATION_PAYMENT_PORTAL_LOADING,
452       "" /* error_description */);
453 
454   RefreshCellularNetworks();
455 }
456 
StartActivationOTA()457 void MobileActivator::StartActivationOTA() {
458   // Connect to the network if we don't currently have access.
459   const NetworkState* network = GetNetworkState(service_path_);
460   if (!network) {
461     LOG(WARNING) << "Cellular service can't be found: " << service_path_;
462     return;
463   }
464 
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);
471 
472   ChangeState(network, PLAN_ACTIVATION_PAYMENT_PORTAL_LOADING,
473               "" /* error_description */);
474   RefreshCellularNetworks();
475 }
476 
StartActivationOTASP()477 void MobileActivator::StartActivationOTASP() {
478   const NetworkState* network = GetNetworkState(service_path_);
479   if (!network) {
480     LOG(WARNING) << "Cellular service can't be found: " << service_path_;
481     return;
482   }
483 
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;
489   } else {
490     state_ =  PLAN_ACTIVATION_START;
491   }
492 
493   EvaluateCellularNetwork(network);
494 }
495 
RetryOTASP()496 void MobileActivator::RetryOTASP() {
497   DCHECK(state_ == PLAN_ACTIVATION_DELAY_OTASP);
498   StartOTASP();
499 }
500 
StartOTASP()501 void MobileActivator::StartOTASP() {
502   const NetworkState* network = GetNetworkState(service_path_);
503   if (!network) {
504     LOG(WARNING) << "Cellular service can't be found: " << service_path_;
505     return;
506   }
507 
508   ChangeState(network, PLAN_ACTIVATION_START_OTASP, std::string());
509   EvaluateCellularNetwork(network);
510 }
511 
HandleOTASPTimeout()512 void MobileActivator::HandleOTASPTimeout() {
513   LOG(WARNING) << "OTASP seems to be taking too long.";
514   const NetworkState* network = GetNetworkState(service_path_);
515   if (!network) {
516     LOG(WARNING) << "Cellular service can't be found: " << service_path_;
517     return;
518   }
519 
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) {
525       ChangeState(network,
526                   PLAN_ACTIVATION_RECONNECTING,
527                   GetErrorMessage(kErrorDefault));
528       return;
529     }
530   } else if (state_ == PLAN_ACTIVATION_TRYING_OTASP) {
531     ++trying_OTASP_attempts_;
532     if (trying_OTASP_attempts_ <= kMaxOTASPTries) {
533       ChangeState(network,
534                   PLAN_ACTIVATION_RECONNECTING,
535                   GetErrorMessage(kErrorDefault));
536       return;
537     }
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.
542       ChangeState(network,
543                   PLAN_ACTIVATION_DELAY_OTASP,
544                   GetErrorMessage(kErrorDefault));
545       return;
546     }
547   } else {
548     LOG(ERROR) << "OTASP timed out from a non-OTASP wait state?";
549   }
550   LOG(ERROR) << "OTASP failed too many times; aborting.";
551   ChangeState(network,
552               PLAN_ACTIVATION_ERROR,
553               GetErrorMessage(kErrorDefault));
554 }
555 
ConnectNetwork(const NetworkState * network)556 void MobileActivator::ConnectNetwork(const NetworkState* network) {
557   NetworkHandler::Get()->network_connection_handler()->ConnectToNetwork(
558       network->path(),
559       base::Bind(&base::DoNothing),
560       network_handler::ErrorCallback(),
561       false /* check_error_state */);
562 }
563 
ForceReconnect(const NetworkState * network,PlanActivationState next_state)564 void MobileActivator::ForceReconnect(const NetworkState* network,
565                                      PlanActivationState next_state) {
566   DCHECK(network);
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
574   // call Connect().
575   NetworkHandler::Get()->network_connection_handler()->DisconnectNetwork(
576       network->path(),
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(
582       FROM_HERE,
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(
588       FROM_HERE,
589       base::TimeDelta::FromMilliseconds(kMaxReconnectTime),
590       this, &MobileActivator::ReconnectTimedOut);
591 }
592 
ReconnectTimedOut()593 void MobileActivator::ReconnectTimedOut() {
594   LOG(ERROR) << "Ending activation attempt after failing to reconnect.";
595   const NetworkState* network = GetNetworkState(service_path_);
596   if (!network) {
597     LOG(WARNING) << "Cellular service can't be found: " << service_path_;
598     return;
599   }
600 
601   ChangeState(network,
602               PLAN_ACTIVATION_ERROR,
603               GetErrorMessage(kFailedConnectivity));
604 }
605 
ContinueConnecting()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
613       // try again.
614       NetworkHandler::Get()->network_connection_handler()->DisconnectNetwork(
615           network->path(),
616           base::Bind(&base::DoNothing),
617           network_handler::ErrorCallback());
618       return;
619     }
620     // Stop this callback
621     continue_reconnect_timer_.Stop();
622     EvaluateCellularNetwork(network);
623   } else {
624     LOG(WARNING) << "Connect failed, will try again in a little bit.";
625     if (network) {
626       VLOG(1) << "Connecting to: " << network->path();
627       ash::network_connect::ConnectToNetwork(network->path());
628     }
629   }
630 }
631 
RefreshCellularNetworks()632 void MobileActivator::RefreshCellularNetworks() {
633   if (state_ == PLAN_ACTIVATION_PAGE_LOADING ||
634       state_ == PLAN_ACTIVATION_DONE ||
635       state_ == PLAN_ACTIVATION_ERROR) {
636     return;
637   }
638 
639   const NetworkState* network = GetNetworkState(service_path_);
640   if (!network) {
641     LOG(WARNING) << "Cellular service can't be found: " << service_path_;
642     return;
643   }
644 
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, "");
661     }
662   }
663 
664   EvaluateCellularNetwork(network);
665 }
666 
GetNetworkState(const std::string & service_path)667 const NetworkState* MobileActivator::GetNetworkState(
668     const std::string& service_path) {
669   return NetworkHandler::Get()->network_state_handler()->GetNetworkState(
670       service_path);
671 }
672 
GetDefaultNetwork()673 const NetworkState* MobileActivator::GetDefaultNetwork() {
674   return NetworkHandler::Get()->network_state_handler()->DefaultNetwork();
675 }
676 
EvaluateCellularNetwork(const NetworkState * network)677 void MobileActivator::EvaluateCellularNetwork(const NetworkState* network) {
678   if (terminated_) {
679     LOG(ERROR) << "Tried to run MobileActivator state machine while "
680                << "terminated.";
681     return;
682   }
683 
684   if (!network) {
685     LOG(WARNING) << "Cellular service lost";
686     return;
687   }
688 
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();
695 
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))
699     return;
700 
701   std::string error_description;
702   PlanActivationState new_state = PickNextState(network, &error_description);
703 
704   ChangeState(network, new_state, error_description);
705 }
706 
PickNextState(const NetworkState * network,std::string * error_description) const707 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);
712   else
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());
726       switch (state_) {
727         case PLAN_ACTIVATION_OTASP:
728           new_state = PLAN_ACTIVATION_DELAY_OTASP;
729           break;
730         case PLAN_ACTIVATION_INITIATING_ACTIVATION:
731         case PLAN_ACTIVATION_TRYING_OTASP:
732           new_state = PLAN_ACTIVATION_START;
733           break;
734         case PLAN_ACTIVATION_START:
735           // We are just starting, so this must be previous activation attempt
736           // failure.
737           new_state = PLAN_ACTIVATION_TRYING_OTASP;
738           break;
739         case PLAN_ACTIVATION_DELAY_OTASP:
740           new_state = state_;
741           break;
742         default:
743           new_state = PLAN_ACTIVATION_ERROR;
744           break;
745       }
746     } else {
747       LOG(WARNING) << "Unexpected activation failure for " << network->path();
748       new_state = PLAN_ACTIVATION_ERROR;
749     }
750   }
751 
752   if (new_state == PLAN_ACTIVATION_ERROR && !error_description->length())
753     *error_description = GetErrorMessage(kErrorDefault);
754   return new_state;
755 }
756 
PickNextOfflineState(const NetworkState * network) const757 MobileActivator::PlanActivationState MobileActivator::PickNextOfflineState(
758     const NetworkState* network) const {
759   PlanActivationState new_state = state_;
760   const std::string& activation = network->activation_state();
761   switch (state_) {
762     case PLAN_ACTIVATION_PAYMENT_PORTAL_LOADING:
763     case PLAN_ACTIVATION_SHOWING_PAYMENT:
764       if (!IsSimpleActivationFlow(network))
765         new_state = PLAN_ACTIVATION_RECONNECTING;
766       break;
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;
771         else
772           new_state = PLAN_ACTIVATION_DONE;
773       } else if (activation == shill::kActivationStatePartiallyActivated) {
774         new_state = PLAN_ACTIVATION_TRYING_OTASP;
775       } else {
776         new_state = PLAN_ACTIVATION_INITIATING_ACTIVATION;
777       }
778       break;
779     default:
780       VLOG(1) << "Waiting for cellular service to connect.";
781       break;
782   }
783   return new_state;
784 }
785 
PickNextOnlineState(const NetworkState * network) const786 MobileActivator::PlanActivationState MobileActivator::PickNextOnlineState(
787     const NetworkState* network) const {
788   PlanActivationState new_state = state_;
789   const std::string& activation = network->activation_state();
790   switch (state_) {
791     case PLAN_ACTIVATION_START:
792       if (activation == shill::kActivationStateActivated) {
793         if (network->connection_state() == shill::kStateOnline)
794           new_state = PLAN_ACTIVATION_DONE;
795         else
796           new_state = PLAN_ACTIVATION_PAYMENT_PORTAL_LOADING;
797       } else if (activation == shill::kActivationStatePartiallyActivated) {
798         new_state = PLAN_ACTIVATION_TRYING_OTASP;
799       } else {
800         new_state = PLAN_ACTIVATION_INITIATING_ACTIVATION;
801       }
802       break;
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;
808       } else {
809         LOG(WARNING) << "Unexpected activation state for device "
810                      << network->path();
811       }
812       break;
813     }
814     case PLAN_ACTIVATION_DELAY_OTASP:
815       // Just ignore any changes until the OTASP retry timer kicks in.
816       break;
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.
826       } else {
827         LOG(WARNING) << "Unknown transition";
828       }
829       break;
830     }
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;
841       } else {
842         new_state = PLAN_ACTIVATION_PAYMENT_PORTAL_LOADING;
843       }
844       break;
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;
850       else
851         new_state = PLAN_ACTIVATION_PAYMENT_PORTAL_LOADING;
852       break;
853     // Initial state
854     case PLAN_ACTIVATION_PAGE_LOADING:
855       break;
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:
860       break;
861     // Go where we decided earlier.
862     case PLAN_ACTIVATION_RECONNECTING:
863       new_state = post_reconnect_state_;
864       break;
865     // Activation completed/failed, ignore network changes.
866     case PLAN_ACTIVATION_DONE:
867     case PLAN_ACTIVATION_ERROR:
868       break;
869   }
870 
871   return new_state;
872 }
873 
874 // Debugging helper function, will take it out at the end.
GetStateDescription(PlanActivationState state)875 const char* MobileActivator::GetStateDescription(PlanActivationState state) {
876   switch (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:
896       return "OTASP";
897     case PLAN_ACTIVATION_DONE:
898       return "DONE";
899     case PLAN_ACTIVATION_ERROR:
900       return "ERROR";
901     case PLAN_ACTIVATION_RECONNECTING:
902       return "RECONNECTING";
903     case PLAN_ACTIVATION_WAITING_FOR_CONNECTION:
904       return "WAITING FOR CONNECTION";
905   }
906   return "UNKNOWN";
907 }
908 
909 
CompleteActivation()910 void MobileActivator::CompleteActivation() {
911   // Remove observers, we are done with this page.
912   NetworkHandler::Get()->network_state_handler()->
913       RemoveObserver(this, FROM_HERE);
914 
915   // Reactivate other types of connections if we have
916   // shut them down previously.
917   ReEnableCertRevocationChecking();
918 }
919 
RunningActivation() const920 bool MobileActivator::RunningActivation() const {
921   return !(state_ == PLAN_ACTIVATION_DONE ||
922            state_ == PLAN_ACTIVATION_ERROR ||
923            state_ == PLAN_ACTIVATION_PAGE_LOADING);
924 }
925 
HandleActivationFailure(const std::string & service_path,PlanActivationState new_state,const std::string & error_name,scoped_ptr<base::DictionaryValue> error_data)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);
933   if (!network) {
934     NET_LOG_ERROR("Cellular service no longer exists", service_path);
935     return;
936   }
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());
941   } else {
942     ChangeState(network,
943                 PLAN_ACTIVATION_ERROR,
944                 GetErrorMessage(kFailedConnectivity));
945   }
946 }
947 
RequestCellularActivation(const NetworkState * network,const base::Closure & success_callback,const network_handler::ErrorCallback & error_callback)948 void MobileActivator::RequestCellularActivation(
949     const NetworkState* network,
950     const base::Closure& success_callback,
951     const network_handler::ErrorCallback& error_callback) {
952   DCHECK(network);
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(),
958                "",  // carrier
959                success_callback,
960                error_callback);
961 }
962 
ChangeState(const NetworkState * network,PlanActivationState new_state,std::string error_description)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.
970   if (!network) {
971     switch (new_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);
978       default:
979         break;
980     }
981   }
982 
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)
988     return;
989   first_time = false;
990   VLOG(1) << "Transitioning...";
991 
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_;
997   state_ = new_state;
998 
999   // Signal to observers layer that the state is changing.
1000   FOR_EACH_OBSERVER(Observer, observers_,
1001       OnActivationStateChanged(network, state_, error_description));
1002 
1003   // Pick action that should happen on entering the new state.
1004   switch (new_state) {
1005     case PLAN_ACTIVATION_START:
1006       break;
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));
1012       break;
1013     }
1014     case PLAN_ACTIVATION_START_OTASP:
1015       break;
1016     case PLAN_ACTIVATION_INITIATING_ACTIVATION:
1017     case PLAN_ACTIVATION_TRYING_OTASP:
1018     case PLAN_ACTIVATION_OTASP: {
1019       DCHECK(network);
1020       network_handler::ErrorCallback on_activation_error =
1021           base::Bind(&MobileActivator::HandleActivationFailure, AsWeakPtr(),
1022                      network->path(),
1023                      new_state);
1024       RequestCellularActivation(
1025           network,
1026           base::Bind(&MobileActivator::StartOTASPTimer, AsWeakPtr()),
1027           on_activation_error);
1028       }
1029       break;
1030     case PLAN_ACTIVATION_PAGE_LOADING:
1031       return;
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
1036       // might not work.
1037       break;
1038     case PLAN_ACTIVATION_WAITING_FOR_CONNECTION:
1039       post_reconnect_state_ = old_state;
1040       break;
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;
1049           break;
1050         case PLAN_ACTIVATION_INITIATING_ACTIVATION:
1051         case PLAN_ACTIVATION_TRYING_OTASP:
1052           next_state = PLAN_ACTIVATION_START;
1053           break;
1054         case PLAN_ACTIVATION_START_OTASP:
1055         case PLAN_ACTIVATION_OTASP:
1056           if (!network || !network->IsConnectedState()) {
1057             next_state = PLAN_ACTIVATION_START_OTASP;
1058           } else {
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
1062             // should be done.
1063             next_state = PLAN_ACTIVATION_DONE;
1064           }
1065           break;
1066         default:
1067           LOG(ERROR) << "Transitioned to RECONNECTING from an unexpected "
1068                      << "state.";
1069           break;
1070       }
1071       if (network)
1072         ForceReconnect(network, next_state);
1073       break;
1074     }
1075     case PLAN_ACTIVATION_DONE:
1076       DCHECK(network);
1077       CompleteActivation();
1078       UMA_HISTOGRAM_COUNTS("Cellular.MobileSetupSucceeded", 1);
1079       break;
1080     case PLAN_ACTIVATION_ERROR:
1081       CompleteActivation();
1082       UMA_HISTOGRAM_COUNTS("Cellular.PlanFailed", 1);
1083       break;
1084     default:
1085       break;
1086   }
1087 }
1088 
ReEnableCertRevocationChecking()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)
1094     return;
1095   PrefService* prefs = g_browser_process->local_state();
1096   if (!prefs)
1097     return;
1098   if (reenable_cert_check_) {
1099     prefs->SetBoolean(prefs::kCertRevocationCheckingEnabled,
1100                       true);
1101     reenable_cert_check_ = false;
1102   }
1103 }
1104 
DisableCertRevocationChecking()1105 void MobileActivator::DisableCertRevocationChecking() {
1106   // Disable SSL cert checks since we might be performing activation in the
1107   // restricted pool.
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_ &&
1111       prefs->GetBoolean(
1112           prefs::kCertRevocationCheckingEnabled)) {
1113     reenable_cert_check_ = true;
1114     prefs->SetBoolean(prefs::kCertRevocationCheckingEnabled, false);
1115   }
1116 }
1117 
GotActivationError(const NetworkState * network,std::string * error) const1118 bool MobileActivator::GotActivationError(
1119     const NetworkState* network, std::string* error) const {
1120   DCHECK(network);
1121   bool got_error = false;
1122   const char* error_code = kErrorDefault;
1123   const std::string& activation = network->activation_state();
1124 
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;
1135     }
1136     got_error = true;
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;
1146       }
1147     }
1148     got_error = true;
1149   }
1150 
1151   if (got_error)
1152     *error = GetErrorMessage(error_code);
1153 
1154   return got_error;
1155 }
1156 
GetErrorMessage(const std::string & code) const1157 std::string MobileActivator::GetErrorMessage(const std::string& code) const {
1158   return cellular_config_->GetErrorMessage(code);
1159 }
1160 
SignalCellularPlanPayment()1161 void MobileActivator::SignalCellularPlanPayment() {
1162   DCHECK(!HasRecentCellularPlanPayment());
1163   cellular_plan_payment_time_ = base::Time::Now();
1164 }
1165 
HasRecentCellularPlanPayment() const1166 bool MobileActivator::HasRecentCellularPlanPayment() const {
1167   const int kRecentPlanPaymentHours = 6;
1168   return (base::Time::Now() -
1169           cellular_plan_payment_time_).InHours() < kRecentPlanPaymentHours;
1170 }
1171 
1172 }  // namespace chromeos
1173