• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2011 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/ui/webui/chromeos/mobile_setup_ui.h"
6 
7 #include <algorithm>
8 #include <map>
9 #include <string>
10 
11 #include "base/callback.h"
12 #include "base/file_util.h"
13 #include "base/json/json_reader.h"
14 #include "base/json/json_writer.h"
15 #include "base/logging.h"
16 #include "base/memory/weak_ptr.h"
17 #include "base/metrics/histogram.h"
18 #include "base/string_piece.h"
19 #include "base/string_util.h"
20 #include "base/threading/thread_restrictions.h"
21 #include "base/timer.h"
22 #include "base/utf_string_conversions.h"
23 #include "base/values.h"
24 #include "chrome/browser/browser_process.h"
25 #include "chrome/browser/chromeos/cros/cros_library.h"
26 #include "chrome/browser/chromeos/cros/network_library.h"
27 #include "chrome/browser/prefs/pref_service.h"
28 #include "chrome/browser/profiles/profile.h"
29 #include "chrome/browser/ui/browser_list.h"
30 #include "chrome/browser/ui/webui/chrome_url_data_manager.h"
31 #include "chrome/common/jstemplate_builder.h"
32 #include "chrome/common/pref_names.h"
33 #include "chrome/common/url_constants.h"
34 #include "content/browser/browser_thread.h"
35 #include "content/browser/tab_contents/tab_contents.h"
36 #include "googleurl/src/gurl.h"
37 #include "grit/browser_resources.h"
38 #include "grit/chromium_strings.h"
39 #include "grit/generated_resources.h"
40 #include "grit/locale_settings.h"
41 #include "ui/base/l10n/l10n_util.h"
42 #include "ui/base/resource/resource_bundle.h"
43 
44 namespace {
45 
46 // Host page JS API function names.
47 const char kJsApiStartActivation[] = "startActivation";
48 const char kJsApiSetTransactionStatus[] = "setTransactionStatus";
49 
50 const char kJsDeviceStatusChangedHandler[] =
51     "mobile.MobileSetup.deviceStateChanged";
52 
53 // Error codes matching codes defined in the cellular config file.
54 const char kErrorDefault[] = "default";
55 const char kErrorBadConnectionPartial[] = "bad_connection_partial";
56 const char kErrorBadConnectionActivated[] = "bad_connection_activated";
57 const char kErrorRoamingOnConnection[] = "roaming_connection";
58 const char kErrorNoEVDO[] = "no_evdo";
59 const char kErrorRoamingActivation[] = "roaming_activation";
60 const char kErrorRoamingPartiallyActivated[] = "roaming_partially_activated";
61 const char kErrorNoService[] = "no_service";
62 const char kErrorDisabled[] = "disabled";
63 const char kErrorNoDevice[] = "no_device";
64 const char kFailedPaymentError[] = "failed_payment";
65 const char kFailedConnectivity[] = "connectivity";
66 const char kErrorAlreadyRunning[] = "already_running";
67 
68 // Cellular configuration file path.
69 const char kCellularConfigPath[] =
70     "/usr/share/chromeos-assets/mobile/mobile_config.json";
71 
72 // Cellular config file field names.
73 const char kVersionField[] = "version";
74 const char kErrorsField[] = "errors";
75 
76 // Number of times we will retry to restart the activation process in case
77 // there is no connectivity in the restricted pool.
78 const int kMaxActivationAttempt = 3;
79 // Number of times we will retry to reconnect if connection fails.
80 const int kMaxConnectionRetry = 10;
81 // Number of times we will retry to reconnect if connection fails.
82 const int kMaxConnectionRetryOTASP = 30;
83 // Number of times we will retry to reconnect after payment is processed.
84 const int kMaxReconnectAttemptOTASP = 30;
85 // Reconnect retry delay (after payment is processed).
86 const int kPostPaymentReconnectDelayMS = 30000;   // 30s.
87 // Connection timeout in seconds.
88 const int kConnectionTimeoutSeconds = 45;
89 // Reconnect delay.
90 const int kReconnectDelayMS = 3000;
91 // Reconnect timer delay.
92 const int kReconnectTimerDelayMS = 5000;
93 // Reconnect delay after previous failure.
94 const int kFailedReconnectDelayMS = 10000;
95 // Retry delay after failed OTASP attempt.
96 const int kOTASPRetryDelay = 20000;
97 
GetCellularNetwork()98 chromeos::CellularNetwork* GetCellularNetwork() {
99   chromeos::NetworkLibrary* lib = chromeos::CrosLibrary::Get()->
100       GetNetworkLibrary();
101   if (lib->cellular_networks().begin() != lib->cellular_networks().end()) {
102     return *(lib->cellular_networks().begin());
103   }
104   return NULL;
105 }
106 
GetCellularNetwork(const std::string & service_path)107 chromeos::CellularNetwork* GetCellularNetwork(
108     const std::string& service_path) {
109   return chromeos::CrosLibrary::Get()->
110       GetNetworkLibrary()->FindCellularNetworkByPath(service_path);
111 }
112 
113 }  // namespace
114 
115 class CellularConfigDocument {
116  public:
CellularConfigDocument()117   CellularConfigDocument() {}
118 
119   // Return error message for a given code.
120   std::string GetErrorMessage(const std::string& code);
version()121   const std::string& version() { return version_; }
122 
123   bool LoadFromFile(const FilePath& config_path);
124 
125  private:
126   std::string version_;
127   std::map<std::string, std::string> error_map_;
128 
129   DISALLOW_COPY_AND_ASSIGN(CellularConfigDocument);
130 };
131 
132 static std::map<std::string, std::string> error_messages_;
133 
134 class MobileSetupUIHTMLSource : public ChromeURLDataManager::DataSource {
135  public:
136   explicit MobileSetupUIHTMLSource(const std::string& service_path);
137 
138   // Called when the network layer has requested a resource underneath
139   // the path we registered.
140   virtual void StartDataRequest(const std::string& path,
141                                 bool is_incognito,
142                                 int request_id);
GetMimeType(const std::string &) const143   virtual std::string GetMimeType(const std::string&) const {
144     return "text/html";
145   }
146 
147  private:
~MobileSetupUIHTMLSource()148   virtual ~MobileSetupUIHTMLSource() {}
149 
150   std::string service_path_;
151   DISALLOW_COPY_AND_ASSIGN(MobileSetupUIHTMLSource);
152 };
153 
154 // The handler for Javascript messages related to the "register" view.
155 class MobileSetupHandler
156   : public WebUIMessageHandler,
157     public chromeos::NetworkLibrary::NetworkManagerObserver,
158     public chromeos::NetworkLibrary::NetworkObserver,
159     public base::SupportsWeakPtr<MobileSetupHandler> {
160  public:
161   explicit MobileSetupHandler(const std::string& service_path);
162   virtual ~MobileSetupHandler();
163 
164   // Init work after Attach.
165   void Init(TabContents* contents);
166 
167   // WebUIMessageHandler implementation.
168   virtual WebUIMessageHandler* Attach(WebUI* web_ui);
169   virtual void RegisterMessages();
170 
171   // NetworkLibrary::NetworkManagerObserver implementation.
172   virtual void OnNetworkManagerChanged(chromeos::NetworkLibrary* obj);
173   // NetworkLibrary::NetworkObserver implementation.
174   virtual void OnNetworkChanged(chromeos::NetworkLibrary* obj,
175                                 const chromeos::Network* network);
176 
177  private:
178   typedef enum PlanActivationState {
179     PLAN_ACTIVATION_PAGE_LOADING            = -1,
180     PLAN_ACTIVATION_START                   = 0,
181     PLAN_ACTIVATION_TRYING_OTASP            = 1,
182     PLAN_ACTIVATION_RECONNECTING_OTASP_TRY  = 2,
183     PLAN_ACTIVATION_INITIATING_ACTIVATION   = 3,
184     PLAN_ACTIVATION_RECONNECTING            = 4,
185     PLAN_ACTIVATION_SHOWING_PAYMENT         = 5,
186     PLAN_ACTIVATION_DELAY_OTASP             = 6,
187     PLAN_ACTIVATION_START_OTASP             = 7,
188     PLAN_ACTIVATION_OTASP                   = 8,
189     PLAN_ACTIVATION_RECONNECTING_OTASP      = 9,
190     PLAN_ACTIVATION_DONE                    = 10,
191     PLAN_ACTIVATION_ERROR                   = 0xFF,
192   } PlanActivationState;
193 
194   class TaskProxy : public base::RefCountedThreadSafe<TaskProxy> {
195    public:
TaskProxy(const base::WeakPtr<MobileSetupHandler> & handler,int delay)196     TaskProxy(const base::WeakPtr<MobileSetupHandler>& handler, int delay)
197         : handler_(handler), delay_(delay) {
198     }
TaskProxy(const base::WeakPtr<MobileSetupHandler> & handler,const std::string & status)199     TaskProxy(const base::WeakPtr<MobileSetupHandler>& handler,
200               const std::string& status)
201         : handler_(handler), status_(status) {
202     }
HandleStartActivation()203     void HandleStartActivation() {
204       if (handler_)
205         handler_->StartActivation();
206     }
HandleSetTransactionStatus()207     void HandleSetTransactionStatus() {
208       if (handler_)
209         handler_->SetTransactionStatus(status_);
210     }
ContinueConnecting()211     void ContinueConnecting() {
212       if (handler_)
213         handler_->ContinueConnecting(delay_);
214     }
RetryOTASP()215     void RetryOTASP() {
216       if (handler_)
217         handler_->RetryOTASP();
218     }
219    private:
220     base::WeakPtr<MobileSetupHandler> handler_;
221     std::string status_;
222     int delay_;
223     DISALLOW_COPY_AND_ASSIGN(TaskProxy);
224   };
225 
226   // Handlers for JS WebUI messages.
227   void HandleSetTransactionStatus(const ListValue* args);
228   void HandleStartActivation(const ListValue* args);
229   void SetTransactionStatus(const std::string& status);
230   // Schedules activation process via task proxy.
231   void InitiateActivation();
232   // Starts activation.
233   void StartActivation();
234   // Retried OTASP.
235   void RetryOTASP();
236   // Continues activation process. This method is called after we disconnect
237   // due to detected connectivity issue to kick off reconnection.
238   void ContinueConnecting(int delay);
239 
240   // Sends message to host registration page with system/user info data.
241   void SendDeviceInfo();
242 
243   // Callback for when |reconnect_timer_| fires.
244   void ReconnectTimerFired();
245   // Starts OTASP process.
246   void StartOTASP();
247   // Checks if we need to reconnect due to failed connection attempt.
248   bool NeedsReconnecting(chromeos::CellularNetwork* network,
249                          PlanActivationState* new_state,
250                          std::string* error_description);
251   // Disconnect from network.
252   void DisconnectFromNetwork(chromeos::CellularNetwork* network);
253   // Connects to cellular network, resets connection timer.
254   bool ConnectToNetwork(chromeos::CellularNetwork* network, int delay);
255   // Forces disconnect / reconnect when we detect portal connectivity issues.
256   void ForceReconnect(chromeos::CellularNetwork* network, int delay);
257   // Reports connection timeout.
258   bool ConnectionTimeout();
259   // Verify the state of cellular network and modify internal state.
260   void EvaluateCellularNetwork(chromeos::CellularNetwork* network);
261   // Check the current cellular network for error conditions.
262   bool GotActivationError(chromeos::CellularNetwork* network,
263                           std::string* error);
264   // Sends status updates to WebUI page.
265   void UpdatePage(chromeos::CellularNetwork* network,
266                   const std::string& error_description);
267   // Changes internal state.
268   void ChangeState(chromeos::CellularNetwork* network,
269                    PlanActivationState new_state,
270                    const std::string& error_description);
271   // Prepares network devices for cellular activation process.
272   void SetupActivationProcess(chromeos::CellularNetwork* network);
273   // Disables ethernet and wifi newtorks since they interefere with
274   // detection of restricted pool on cellular side.
275   void DisableOtherNetworks();
276   // Resets network devices after cellular activation process.
277   // |network| should be NULL if the activation process failed.
278   void CompleteActivation(chromeos::CellularNetwork* network);
279   // Control routines for handling other types of connections during
280   // cellular activation.
281   void ReEnableOtherConnections();
282 
283   // Converts the currently active CellularNetwork device into a JS object.
284   static void GetDeviceInfo(chromeos::CellularNetwork* network,
285                             DictionaryValue* value);
286   static bool ShouldReportDeviceState(std::string* state, std::string* error);
287 
288   // Performs activation state cellular device evaluation.
289   // Returns false if device activation failed. In this case |error|
290   // will contain error message to be reported to Web UI.
291   static bool EvaluateCellularDeviceState(bool* report_status,
292                                           std::string* state,
293                                           std::string* error);
294 
295   // Return error message for a given code.
296   static std::string GetErrorMessage(const std::string& code);
297   static void LoadCellularConfig();
298 
299   // Returns next reconnection state based on the current activation phase.
300   static PlanActivationState GetNextReconnectState(PlanActivationState state);
301   static const char* GetStateDescription(PlanActivationState state);
302 
303   static scoped_ptr<CellularConfigDocument> cellular_config_;
304 
305   TabContents* tab_contents_;
306   // Internal handler state.
307   PlanActivationState state_;
308   std::string service_path_;
309   // Flags that control if wifi and ethernet connection needs to be restored
310   // after the activation of cellular network.
311   bool reenable_wifi_;
312   bool reenable_ethernet_;
313   bool reenable_cert_check_;
314   bool evaluating_;
315   // True if we think that another tab is already running activation.
316   bool already_running_;
317   // Connection retry counter.
318   int connection_retry_count_;
319   // Post payment reconnect wait counters.
320   int reconnect_wait_count_;
321   // Activation retry attempt count;
322   int activation_attempt_;
323   // Connection start time.
324   base::Time connection_start_time_;
325   // Timer that monitors reconnection timeouts.
326   base::RepeatingTimer<MobileSetupHandler> reconnect_timer_;
327 
328   DISALLOW_COPY_AND_ASSIGN(MobileSetupHandler);
329 };
330 
331 scoped_ptr<CellularConfigDocument> MobileSetupHandler::cellular_config_;
332 
333 ////////////////////////////////////////////////////////////////////////////////
334 //
335 // CellularConfigDocument
336 //
337 ////////////////////////////////////////////////////////////////////////////////
338 
GetErrorMessage(const std::string & code)339 std::string CellularConfigDocument::GetErrorMessage(const std::string& code) {
340   std::map<std::string, std::string>::iterator iter = error_map_.find(code);
341   if (iter == error_map_.end())
342     return code;
343   return iter->second;
344 }
345 
LoadFromFile(const FilePath & config_path)346 bool CellularConfigDocument::LoadFromFile(const FilePath& config_path) {
347   error_map_.clear();
348 
349   std::string config;
350   {
351     // Reading config file causes us to do blocking IO on UI thread.
352     // Temporarily allow it until we fix http://crosbug.com/11535
353     base::ThreadRestrictions::ScopedAllowIO allow_io;
354     if (!file_util::ReadFileToString(config_path, &config))
355       return false;
356   }
357 
358   scoped_ptr<Value> root(base::JSONReader::Read(config, true));
359   DCHECK(root.get() != NULL);
360   if (!root.get() || root->GetType() != Value::TYPE_DICTIONARY) {
361     LOG(WARNING) << "Bad cellular config file";
362     return false;
363   }
364 
365   DictionaryValue* root_dict = static_cast<DictionaryValue*>(root.get());
366   if (!root_dict->GetString(kVersionField, &version_)) {
367     LOG(WARNING) << "Cellular config file missing version";
368     return false;
369   }
370   DictionaryValue* errors = NULL;
371   if (!root_dict->GetDictionary(kErrorsField, &errors))
372     return false;
373   for (DictionaryValue::key_iterator keys = errors->begin_keys();
374        keys != errors->end_keys();
375        ++keys) {
376     std::string value;
377     if (!errors->GetString(*keys, &value)) {
378       LOG(WARNING) << "Bad cellular config error value";
379       error_map_.clear();
380       return false;
381     }
382 
383     error_map_.insert(std::pair<std::string, std::string>(*keys, value));
384   }
385   return true;
386 }
387 
388 ////////////////////////////////////////////////////////////////////////////////
389 //
390 // MobileSetupUIHTMLSource
391 //
392 ////////////////////////////////////////////////////////////////////////////////
393 
MobileSetupUIHTMLSource(const std::string & service_path)394 MobileSetupUIHTMLSource::MobileSetupUIHTMLSource(
395     const std::string& service_path)
396     : DataSource(chrome::kChromeUIMobileSetupHost, MessageLoop::current()),
397       service_path_(service_path) {
398 }
399 
StartDataRequest(const std::string & path,bool is_incognito,int request_id)400 void MobileSetupUIHTMLSource::StartDataRequest(const std::string& path,
401                                                bool is_incognito,
402                                                int request_id) {
403   chromeos::CellularNetwork* network = GetCellularNetwork(service_path_);
404   DCHECK(network);
405   DictionaryValue strings;
406   strings.SetString("title", l10n_util::GetStringUTF16(IDS_MOBILE_SETUP_TITLE));
407   strings.SetString("connecting_header",
408                     l10n_util::GetStringFUTF16(IDS_MOBILE_CONNECTING_HEADER,
409                         network ? UTF8ToUTF16(network->name()) : string16()));
410   strings.SetString("error_header",
411                     l10n_util::GetStringUTF16(IDS_MOBILE_ERROR_HEADER));
412   strings.SetString("activating_header",
413                     l10n_util::GetStringUTF16(IDS_MOBILE_ACTIVATING_HEADER));
414   strings.SetString("completed_header",
415                     l10n_util::GetStringUTF16(IDS_MOBILE_COMPLETED_HEADER));
416   strings.SetString("please_wait",
417                     l10n_util::GetStringUTF16(IDS_MOBILE_PLEASE_WAIT));
418   strings.SetString("completed_text",
419                     l10n_util::GetStringUTF16(IDS_MOBILE_COMPLETED_TEXT));
420   strings.SetString("close_button",
421                     l10n_util::GetStringUTF16(IDS_CLOSE));
422   SetFontAndTextDirection(&strings);
423 
424   static const base::StringPiece html(
425       ResourceBundle::GetSharedInstance().GetRawDataResource(
426           IDR_MOBILE_SETUP_PAGE_HTML));
427 
428   const std::string full_html = jstemplate_builder::GetI18nTemplateHtml(
429       html, &strings);
430 
431   scoped_refptr<RefCountedBytes> html_bytes(new RefCountedBytes);
432   html_bytes->data.resize(full_html.size());
433   std::copy(full_html.begin(), full_html.end(), html_bytes->data.begin());
434 
435   SendResponse(request_id, html_bytes);
436 }
437 
438 ////////////////////////////////////////////////////////////////////////////////
439 //
440 // MobileSetupHandler
441 //
442 ////////////////////////////////////////////////////////////////////////////////
MobileSetupHandler(const std::string & service_path)443 MobileSetupHandler::MobileSetupHandler(const std::string& service_path)
444     : tab_contents_(NULL),
445       state_(PLAN_ACTIVATION_PAGE_LOADING),
446       service_path_(service_path),
447       reenable_wifi_(false),
448       reenable_ethernet_(false),
449       reenable_cert_check_(false),
450       evaluating_(false),
451       already_running_(false),
452       connection_retry_count_(0),
453       reconnect_wait_count_(0),
454       activation_attempt_(0) {
455 }
456 
~MobileSetupHandler()457 MobileSetupHandler::~MobileSetupHandler() {
458   reconnect_timer_.Stop();
459   chromeos::NetworkLibrary* lib =
460       chromeos::CrosLibrary::Get()->GetNetworkLibrary();
461   lib->RemoveNetworkManagerObserver(this);
462   lib->RemoveObserverForAllNetworks(this);
463   if (lib->IsLocked())
464     lib->Unlock();
465   ReEnableOtherConnections();
466 }
467 
Attach(WebUI * web_ui)468 WebUIMessageHandler* MobileSetupHandler::Attach(WebUI* web_ui) {
469   return WebUIMessageHandler::Attach(web_ui);
470 }
471 
Init(TabContents * contents)472 void MobileSetupHandler::Init(TabContents* contents) {
473   tab_contents_ = contents;
474   LoadCellularConfig();
475   if (!chromeos::CrosLibrary::Get()->GetNetworkLibrary()->IsLocked())
476     SetupActivationProcess(GetCellularNetwork(service_path_));
477   else
478     already_running_ = true;
479 }
480 
RegisterMessages()481 void MobileSetupHandler::RegisterMessages() {
482   web_ui_->RegisterMessageCallback(kJsApiStartActivation,
483       NewCallback(this, &MobileSetupHandler::HandleStartActivation));
484   web_ui_->RegisterMessageCallback(kJsApiSetTransactionStatus,
485       NewCallback(this, &MobileSetupHandler::HandleSetTransactionStatus));
486 }
487 
OnNetworkManagerChanged(chromeos::NetworkLibrary * cros)488 void MobileSetupHandler::OnNetworkManagerChanged(
489     chromeos::NetworkLibrary* cros) {
490   if (state_ == PLAN_ACTIVATION_PAGE_LOADING)
491     return;
492   // Note that even though we get here when the service has
493   // reappeared after disappearing earlier in the activation
494   // process, there's no need to re-establish the NetworkObserver,
495   // because the service path remains the same.
496   EvaluateCellularNetwork(GetCellularNetwork(service_path_));
497 }
498 
OnNetworkChanged(chromeos::NetworkLibrary * cros,const chromeos::Network * network)499 void MobileSetupHandler::OnNetworkChanged(chromeos::NetworkLibrary* cros,
500                                           const chromeos::Network* network) {
501   if (state_ == PLAN_ACTIVATION_PAGE_LOADING)
502     return;
503   DCHECK(network && network->type() == chromeos::TYPE_CELLULAR);
504   EvaluateCellularNetwork(GetCellularNetwork(network->service_path()));
505 }
506 
HandleStartActivation(const ListValue * args)507 void MobileSetupHandler::HandleStartActivation(const ListValue* args) {
508   InitiateActivation();
509   UMA_HISTOGRAM_COUNTS("Cellular.MobileSetupStart", 1);
510 }
511 
HandleSetTransactionStatus(const ListValue * args)512 void MobileSetupHandler::HandleSetTransactionStatus(const ListValue* args) {
513   const size_t kSetTransactionStatusParamCount = 1;
514   if (args->GetSize() != kSetTransactionStatusParamCount)
515     return;
516   // Get change callback function name.
517   std::string status;
518   if (!args->GetString(0, &status))
519     return;
520   scoped_refptr<TaskProxy> task = new TaskProxy(AsWeakPtr(), status);
521   BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
522       NewRunnableMethod(task.get(), &TaskProxy::HandleSetTransactionStatus));
523 }
524 
InitiateActivation()525 void MobileSetupHandler::InitiateActivation() {
526   scoped_refptr<TaskProxy> task = new TaskProxy(AsWeakPtr(), 0);
527   BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
528       NewRunnableMethod(task.get(), &TaskProxy::HandleStartActivation));
529 }
530 
StartActivation()531 void MobileSetupHandler::StartActivation() {
532   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
533   chromeos::NetworkLibrary* lib =
534       chromeos::CrosLibrary::Get()->GetNetworkLibrary();
535   chromeos::CellularNetwork* network = GetCellularNetwork(service_path_);
536   // Check if we can start activation process.
537   if (!network || already_running_) {
538     std::string error;
539     if (already_running_)
540       error = kErrorAlreadyRunning;
541     else if (!lib->cellular_available())
542       error = kErrorNoDevice;
543     else if (!lib->cellular_enabled())
544       error = kErrorDisabled;
545     else
546       error = kErrorNoService;
547     ChangeState(NULL, PLAN_ACTIVATION_ERROR, GetErrorMessage(error));
548     return;
549   }
550 
551   // Start monitoring network property changes.
552   lib->AddNetworkManagerObserver(this);
553   lib->RemoveObserverForAllNetworks(this);
554   lib->AddNetworkObserver(network->service_path(), this);
555   // Try to start with OTASP immediately if we have received payment recently.
556   state_ = lib->HasRecentCellularPlanPayment() ?
557                PLAN_ACTIVATION_START_OTASP :
558                PLAN_ACTIVATION_START;
559   EvaluateCellularNetwork(network);
560 }
561 
RetryOTASP()562 void MobileSetupHandler::RetryOTASP() {
563   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
564   DCHECK(state_ == PLAN_ACTIVATION_DELAY_OTASP);
565   StartOTASP();
566 }
567 
ContinueConnecting(int delay)568 void MobileSetupHandler::ContinueConnecting(int delay) {
569   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
570   chromeos::CellularNetwork* network = GetCellularNetwork(service_path_);
571   if (network && network->connecting_or_connected()) {
572     EvaluateCellularNetwork(network);
573   } else {
574     ConnectToNetwork(network, delay);
575   }
576 }
577 
SetTransactionStatus(const std::string & status)578 void MobileSetupHandler::SetTransactionStatus(const std::string& status) {
579   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
580   // The payment is received, try to reconnect and check the status all over
581   // again.
582   if (LowerCaseEqualsASCII(status, "ok") &&
583       state_ == PLAN_ACTIVATION_SHOWING_PAYMENT) {
584     chromeos::NetworkLibrary* lib =
585         chromeos::CrosLibrary::Get()->GetNetworkLibrary();
586     lib->SignalCellularPlanPayment();
587     UMA_HISTOGRAM_COUNTS("Cellular.PaymentReceived", 1);
588     StartOTASP();
589   } else {
590     UMA_HISTOGRAM_COUNTS("Cellular.PaymentFailed", 1);
591   }
592 }
593 
StartOTASP()594 void MobileSetupHandler::StartOTASP() {
595   state_ = PLAN_ACTIVATION_START_OTASP;
596   chromeos::CellularNetwork* network = GetCellularNetwork();
597   if (network &&
598       network->connected() &&
599       network->activation_state() == chromeos::ACTIVATION_STATE_ACTIVATED) {
600     chromeos::CrosLibrary::Get()->GetNetworkLibrary()->
601         DisconnectFromNetwork(network);
602   } else {
603     EvaluateCellularNetwork(network);
604   }
605 }
606 
ReconnectTimerFired()607 void MobileSetupHandler::ReconnectTimerFired() {
608   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
609   // Permit network connection changes only in reconnecting states.
610   if (state_ != PLAN_ACTIVATION_RECONNECTING_OTASP_TRY &&
611       state_ != PLAN_ACTIVATION_RECONNECTING &&
612       state_ != PLAN_ACTIVATION_RECONNECTING_OTASP)
613     return;
614   chromeos::CellularNetwork* network = GetCellularNetwork(service_path_);
615   if (!network) {
616     // No service, try again since this is probably just transient condition.
617     LOG(WARNING) << "Service not present at reconnect attempt.";
618   }
619   EvaluateCellularNetwork(network);
620 }
621 
DisconnectFromNetwork(chromeos::CellularNetwork * network)622 void MobileSetupHandler::DisconnectFromNetwork(
623     chromeos::CellularNetwork* network) {
624   DCHECK(network);
625   LOG(INFO) << "Disconnecting from: " << network->service_path();
626   chromeos::CrosLibrary::Get()->GetNetworkLibrary()->
627       DisconnectFromNetwork(network);
628   // Disconnect will force networks to be reevaluated, so
629   // we don't want to continue processing on this path anymore.
630   evaluating_ = false;
631 }
632 
NeedsReconnecting(chromeos::CellularNetwork * network,PlanActivationState * new_state,std::string * error_description)633 bool MobileSetupHandler::NeedsReconnecting(
634     chromeos::CellularNetwork* network,
635     PlanActivationState* new_state,
636     std::string* error_description) {
637   DCHECK(network);
638   if (!network->failed() && !ConnectionTimeout())
639     return false;
640 
641   // Try to reconnect again if reconnect failed, or if for some
642   // reasons we are still not connected after 45 seconds.
643   int max_retries = (state_ == PLAN_ACTIVATION_RECONNECTING_OTASP) ?
644                         kMaxConnectionRetryOTASP : kMaxConnectionRetry;
645   if (connection_retry_count_ < max_retries) {
646     UMA_HISTOGRAM_COUNTS("Cellular.ConnectionRetry", 1);
647     ConnectToNetwork(network, kFailedReconnectDelayMS);
648     return true;
649   }
650   // We simply can't connect anymore after all these tries.
651   UMA_HISTOGRAM_COUNTS("Cellular.ConnectionFailed", 1);
652   *new_state = PLAN_ACTIVATION_ERROR;
653   *error_description = GetErrorMessage(kFailedConnectivity);
654   return false;
655 }
656 
ConnectToNetwork(chromeos::CellularNetwork * network,int delay)657 bool MobileSetupHandler::ConnectToNetwork(
658     chromeos::CellularNetwork* network,
659     int delay) {
660   if (network && network->connecting_or_connected())
661     return true;
662   // Permit network connection changes only in reconnecting states.
663   if (state_ != PLAN_ACTIVATION_RECONNECTING_OTASP_TRY &&
664       state_ != PLAN_ACTIVATION_RECONNECTING &&
665       state_ != PLAN_ACTIVATION_RECONNECTING_OTASP)
666     return false;
667   if (network)
668     LOG(INFO) << "Connecting to: " << network->service_path();
669   connection_retry_count_++;
670   connection_start_time_ = base::Time::Now();
671   if (!network) {
672     LOG(WARNING) << "Connect failed."
673                  << (network ? network->service_path().c_str() : "no service");
674     // If we coudn't connect during reconnection phase, try to reconnect
675     // with a delay (and try to reconnect if needed).
676     scoped_refptr<TaskProxy> task = new TaskProxy(AsWeakPtr(),
677                                                   delay);
678     BrowserThread::PostDelayedTask(BrowserThread::UI, FROM_HERE,
679         NewRunnableMethod(task.get(), &TaskProxy::ContinueConnecting),
680         delay);
681     return false;
682   }
683   chromeos::CrosLibrary::Get()->GetNetworkLibrary()->
684       ConnectToCellularNetwork(network);
685   return true;
686 }
687 
ForceReconnect(chromeos::CellularNetwork * network,int delay)688 void MobileSetupHandler::ForceReconnect(
689     chromeos::CellularNetwork* network,
690     int delay) {
691   DCHECK(network);
692   UMA_HISTOGRAM_COUNTS("Cellular.ActivationRetry", 1);
693   // Reset reconnect metrics.
694   connection_retry_count_ = 0;
695   connection_start_time_ = base::Time();
696   // First, disconnect...
697   LOG(INFO) << "Disconnecting from " << network->service_path();
698   chromeos::CrosLibrary::Get()->GetNetworkLibrary()->
699       DisconnectFromNetwork(network);
700   // Check the network state 3s after we disconnect to make sure.
701   scoped_refptr<TaskProxy> task = new TaskProxy(AsWeakPtr(),
702                                                 delay);
703   BrowserThread::PostDelayedTask(BrowserThread::UI, FROM_HERE,
704       NewRunnableMethod(task.get(), &TaskProxy::ContinueConnecting),
705       delay);
706 }
707 
ConnectionTimeout()708 bool MobileSetupHandler::ConnectionTimeout() {
709   return (base::Time::Now() -
710             connection_start_time_).InSeconds() > kConnectionTimeoutSeconds;
711 }
712 
EvaluateCellularNetwork(chromeos::CellularNetwork * network)713 void MobileSetupHandler::EvaluateCellularNetwork(
714     chromeos::CellularNetwork* network) {
715   if (!web_ui_)
716     return;
717 
718   PlanActivationState new_state = state_;
719   if (!network) {
720     LOG(WARNING) << "Cellular service lost";
721     if (state_ == PLAN_ACTIVATION_RECONNECTING_OTASP_TRY ||
722         state_ == PLAN_ACTIVATION_RECONNECTING ||
723         state_ == PLAN_ACTIVATION_RECONNECTING_OTASP) {
724       // This might be the legit case when service is lost after activation.
725       // We need to make sure we force reconnection as soon as it shows up.
726       LOG(INFO) << "Force service reconnection";
727       connection_start_time_ = base::Time();
728     }
729     return;
730   }
731 
732   // Prevent this method from being called if it is already on the stack.
733   // This might happen on some state transitions (ie. connect, disconnect).
734   if (evaluating_)
735     return;
736   evaluating_ = true;
737   std::string error_description;
738 
739   LOG(WARNING) << "Cellular:\n  service=" << network->GetStateString().c_str()
740       << "\n  ui=" << GetStateDescription(state_)
741       << "\n  activation=" << network->GetActivationStateString().c_str()
742       << "\n  connectivity="
743       << network->GetConnectivityStateString().c_str()
744       << "\n  error=" << network->GetErrorString().c_str()
745       << "\n  setvice_path=" << network->service_path().c_str();
746   switch (state_) {
747     case PLAN_ACTIVATION_START: {
748       switch (network->activation_state()) {
749         case chromeos::ACTIVATION_STATE_ACTIVATED: {
750           if (network->failed_or_disconnected()) {
751             new_state = PLAN_ACTIVATION_RECONNECTING;
752           } else if (network->connected()) {
753             if (network->restricted_pool()) {
754               new_state = PLAN_ACTIVATION_SHOWING_PAYMENT;
755             } else {
756               new_state = PLAN_ACTIVATION_DONE;
757             }
758           }
759           break;
760         }
761         default: {
762           if (network->failed_or_disconnected() ||
763               network->state() == chromeos::STATE_ACTIVATION_FAILURE) {
764             new_state = (network->activation_state() ==
765                          chromeos::ACTIVATION_STATE_PARTIALLY_ACTIVATED) ?
766                             PLAN_ACTIVATION_TRYING_OTASP :
767                             PLAN_ACTIVATION_INITIATING_ACTIVATION;
768           } else if (network->connected()) {
769             DisconnectFromNetwork(network);
770             return;
771           }
772           break;
773         }
774       }
775       break;
776     }
777     case PLAN_ACTIVATION_START_OTASP: {
778       switch (network->activation_state()) {
779         case chromeos::ACTIVATION_STATE_PARTIALLY_ACTIVATED: {
780           if (network->failed_or_disconnected()) {
781             new_state = PLAN_ACTIVATION_OTASP;
782           } else if (network->connected()) {
783             DisconnectFromNetwork(network);
784             return;
785           }
786           break;
787         }
788         case chromeos::ACTIVATION_STATE_ACTIVATED:
789           new_state = PLAN_ACTIVATION_RECONNECTING_OTASP;
790           break;
791         default: {
792           LOG(WARNING) << "Unexpected activation state for device "
793                        << network->service_path().c_str();
794           break;
795         }
796       }
797       break;
798     }
799     case PLAN_ACTIVATION_DELAY_OTASP:
800       // Just ignore any changes until the OTASP retry timer kicks in.
801       evaluating_ = false;
802       return;
803     case PLAN_ACTIVATION_INITIATING_ACTIVATION:
804     case PLAN_ACTIVATION_OTASP:
805     case PLAN_ACTIVATION_TRYING_OTASP: {
806       switch (network->activation_state()) {
807         case chromeos::ACTIVATION_STATE_ACTIVATED:
808           if (network->failed_or_disconnected()) {
809             new_state = GetNextReconnectState(state_);
810           } else if (network->connected()) {
811             if (network->restricted_pool()) {
812               new_state = PLAN_ACTIVATION_SHOWING_PAYMENT;
813             } else {
814               new_state = PLAN_ACTIVATION_DONE;
815             }
816           }
817           break;
818         case chromeos::ACTIVATION_STATE_PARTIALLY_ACTIVATED:
819           if (network->connected()) {
820             if (network->restricted_pool())
821               new_state = PLAN_ACTIVATION_SHOWING_PAYMENT;
822           } else {
823             new_state = GetNextReconnectState(state_);
824           }
825           break;
826         case chromeos::ACTIVATION_STATE_NOT_ACTIVATED:
827         case chromeos::ACTIVATION_STATE_ACTIVATING:
828           // Wait in this state until activation state changes.
829           break;
830         default:
831           break;
832       }
833       break;
834     }
835     case PLAN_ACTIVATION_RECONNECTING_OTASP_TRY:
836     case PLAN_ACTIVATION_RECONNECTING: {
837       if (network->connected()) {
838         // Make sure other networks are not interfering with our detection of
839         // restricted pool.
840         DisableOtherNetworks();
841         // Wait until the service shows up and gets activated.
842         switch (network->activation_state()) {
843           case chromeos::ACTIVATION_STATE_PARTIALLY_ACTIVATED:
844           case chromeos::ACTIVATION_STATE_ACTIVATED:
845             if (network->connectivity_state() ==
846                          chromeos::CONN_STATE_NONE) {
847               LOG(WARNING) << "No connectivity for device "
848                            << network->service_path().c_str();
849               // If we are connected but there is no connectivity at all,
850               // restart the whole process again.
851               if (activation_attempt_ < kMaxActivationAttempt) {
852                 activation_attempt_++;
853                 LOG(WARNING) << "Reconnect attempt #"
854                              << activation_attempt_;
855                 ForceReconnect(network, kFailedReconnectDelayMS);
856                 evaluating_ = false;
857                 return;
858               } else {
859                 new_state = PLAN_ACTIVATION_ERROR;
860                 UMA_HISTOGRAM_COUNTS("Cellular.ActivationRetryFailure", 1);
861                 error_description = GetErrorMessage(kFailedConnectivity);
862               }
863             } else if (network->connectivity_state() ==
864                            chromeos::CONN_STATE_RESTRICTED) {
865               // If we have already received payment, don't show the payment
866               // page again. We should try to reconnect after some time instead.
867               new_state = PLAN_ACTIVATION_SHOWING_PAYMENT;
868             } else if (network->activation_state() ==
869                            chromeos::ACTIVATION_STATE_ACTIVATED) {
870               new_state = PLAN_ACTIVATION_DONE;
871             }
872             break;
873           default:
874             break;
875         }
876       } else if (NeedsReconnecting(network, &new_state, &error_description)) {
877         evaluating_ = false;
878         return;
879       }
880       break;
881     }
882     case PLAN_ACTIVATION_RECONNECTING_OTASP: {
883       if (network->connected()) {
884         // Make sure other networks are not interfering with our detection of
885         // restricted pool.
886         DisableOtherNetworks();
887         // Wait until the service shows up and gets activated.
888         switch (network->activation_state()) {
889           case chromeos::ACTIVATION_STATE_PARTIALLY_ACTIVATED:
890           case chromeos::ACTIVATION_STATE_ACTIVATED:
891             if (network->connectivity_state() == chromeos::CONN_STATE_NONE ||
892                 network->connectivity_state() ==
893                     chromeos::CONN_STATE_RESTRICTED) {
894               LOG(WARNING) << "Still no connectivity after OTASP for device "
895                            << network->service_path().c_str();
896               // If we have already received payment, don't show the payment
897               // page again. We should try to reconnect after some time instead.
898               if (reconnect_wait_count_ < kMaxReconnectAttemptOTASP) {
899                 reconnect_wait_count_++;
900                 LOG(WARNING) << "OTASP reconnect attempt #"
901                              << reconnect_wait_count_;
902                 ForceReconnect(network, kPostPaymentReconnectDelayMS);
903                 evaluating_ = false;
904                 return;
905               } else {
906                 new_state = PLAN_ACTIVATION_ERROR;
907                 UMA_HISTOGRAM_COUNTS("Cellular.PostPaymentConnectFailure", 1);
908                 error_description = GetErrorMessage(kFailedConnectivity);
909               }
910             } else if (network->connectivity_state() ==
911                            chromeos::CONN_STATE_UNRESTRICTED) {
912               new_state = PLAN_ACTIVATION_DONE;
913             }
914             break;
915           default:
916             break;
917         }
918       } else if (NeedsReconnecting(network, &new_state, &error_description)) {
919         evaluating_ = false;
920         return;
921       }
922       break;
923     }
924     case PLAN_ACTIVATION_PAGE_LOADING:
925       break;
926     // Just ignore all signals until the site confirms payment.
927     case PLAN_ACTIVATION_SHOWING_PAYMENT:
928       // Activation completed/failed, ignore network changes.
929     case PLAN_ACTIVATION_DONE:
930     case PLAN_ACTIVATION_ERROR:
931       break;
932   }
933 
934   if (new_state != PLAN_ACTIVATION_ERROR &&
935       GotActivationError(network, &error_description)) {
936     // Check for this special case when we try to do activate partially
937     // activated device. If that attempt failed, try to disconnect to clear the
938     // state and reconnect again.
939     if ((network->activation_state() ==
940             chromeos::ACTIVATION_STATE_PARTIALLY_ACTIVATED ||
941         network->activation_state() == chromeos::ACTIVATION_STATE_ACTIVATING) &&
942         (network->error() == chromeos::ERROR_NO_ERROR ||
943             network->error() == chromeos::ERROR_OTASP_FAILED) &&
944         network->state() == chromeos::STATE_ACTIVATION_FAILURE) {
945       LOG(WARNING) << "Activation failure detected "
946                    << network->service_path().c_str();
947       switch (state_) {
948         case PLAN_ACTIVATION_OTASP:
949         case PLAN_ACTIVATION_RECONNECTING_OTASP:
950           new_state = PLAN_ACTIVATION_DELAY_OTASP;
951           break;
952         case PLAN_ACTIVATION_TRYING_OTASP:
953           new_state = PLAN_ACTIVATION_RECONNECTING_OTASP_TRY;
954           break;
955         case PLAN_ACTIVATION_INITIATING_ACTIVATION:
956           new_state = PLAN_ACTIVATION_RECONNECTING;
957           break;
958         case PLAN_ACTIVATION_START:
959           // We are just starting, so this must be previous activation attempt
960           // failure.
961           new_state = PLAN_ACTIVATION_TRYING_OTASP;
962           break;
963         case PLAN_ACTIVATION_DELAY_OTASP:
964         case PLAN_ACTIVATION_RECONNECTING_OTASP_TRY:
965         case PLAN_ACTIVATION_RECONNECTING:
966           new_state = state_;
967           break;
968         default:
969           new_state = PLAN_ACTIVATION_ERROR;
970           break;
971       }
972     } else {
973       LOG(WARNING) << "Unexpected activation failure for "
974                    << network->service_path().c_str();
975       new_state = PLAN_ACTIVATION_ERROR;
976     }
977   }
978 
979   if (new_state == PLAN_ACTIVATION_ERROR && !error_description.length())
980     error_description = GetErrorMessage(kErrorDefault);
981 
982   ChangeState(network, new_state, error_description);
983   evaluating_ = false;
984 }
985 
986 MobileSetupHandler::PlanActivationState
GetNextReconnectState(MobileSetupHandler::PlanActivationState state)987     MobileSetupHandler::GetNextReconnectState(
988         MobileSetupHandler::PlanActivationState state) {
989   switch (state) {
990     case PLAN_ACTIVATION_INITIATING_ACTIVATION:
991       return PLAN_ACTIVATION_RECONNECTING;
992     case PLAN_ACTIVATION_OTASP:
993       return PLAN_ACTIVATION_RECONNECTING_OTASP;
994     case PLAN_ACTIVATION_TRYING_OTASP:
995       return PLAN_ACTIVATION_RECONNECTING_OTASP_TRY;
996     default:
997       return PLAN_ACTIVATION_RECONNECTING;
998   }
999 }
1000 
1001 // Debugging helper function, will take it out at the end.
GetStateDescription(PlanActivationState state)1002 const char* MobileSetupHandler::GetStateDescription(
1003     PlanActivationState state) {
1004   switch (state) {
1005     case PLAN_ACTIVATION_PAGE_LOADING:
1006       return "PAGE_LOADING";
1007     case PLAN_ACTIVATION_START:
1008       return "ACTIVATION_START";
1009     case PLAN_ACTIVATION_TRYING_OTASP:
1010       return "TRYING_OTASP";
1011     case PLAN_ACTIVATION_RECONNECTING_OTASP_TRY:
1012       return "RECONNECTING_OTASP_TRY";
1013     case PLAN_ACTIVATION_INITIATING_ACTIVATION:
1014       return "INITIATING_ACTIVATION";
1015     case PLAN_ACTIVATION_RECONNECTING:
1016       return "RECONNECTING";
1017     case PLAN_ACTIVATION_SHOWING_PAYMENT:
1018       return "SHOWING_PAYMENT";
1019     case PLAN_ACTIVATION_START_OTASP:
1020       return "START_OTASP";
1021     case PLAN_ACTIVATION_DELAY_OTASP:
1022       return "DELAY_OTASP";
1023     case PLAN_ACTIVATION_OTASP:
1024       return "OTASP";
1025     case PLAN_ACTIVATION_RECONNECTING_OTASP:
1026       return "RECONNECTING_OTASP";
1027     case PLAN_ACTIVATION_DONE:
1028       return "DONE";
1029     case PLAN_ACTIVATION_ERROR:
1030       return "ERROR";
1031   }
1032   return "UNKNOWN";
1033 }
1034 
1035 
CompleteActivation(chromeos::CellularNetwork * network)1036 void MobileSetupHandler::CompleteActivation(
1037     chromeos::CellularNetwork* network) {
1038   // Remove observers, we are done with this page.
1039   chromeos::NetworkLibrary* lib = chromeos::CrosLibrary::Get()->
1040       GetNetworkLibrary();
1041   lib->RemoveNetworkManagerObserver(this);
1042   lib->RemoveObserverForAllNetworks(this);
1043   if (lib->IsLocked())
1044     lib->Unlock();
1045   // If we have successfully activated the connection, set autoconnect flag.
1046   if (network)
1047     network->SetAutoConnect(true);
1048   // Reactivate other types of connections if we have
1049   // shut them down previously.
1050   ReEnableOtherConnections();
1051 }
1052 
UpdatePage(chromeos::CellularNetwork * network,const std::string & error_description)1053 void MobileSetupHandler::UpdatePage(
1054     chromeos::CellularNetwork* network,
1055     const std::string& error_description) {
1056   DictionaryValue device_dict;
1057   if (network)
1058     GetDeviceInfo(network, &device_dict);
1059   device_dict.SetInteger("state", state_);
1060   if (error_description.length())
1061     device_dict.SetString("error", error_description);
1062   web_ui_->CallJavascriptFunction(
1063       kJsDeviceStatusChangedHandler, device_dict);
1064 }
1065 
1066 
ChangeState(chromeos::CellularNetwork * network,PlanActivationState new_state,const std::string & error_description)1067 void MobileSetupHandler::ChangeState(chromeos::CellularNetwork* network,
1068                                      PlanActivationState new_state,
1069                                      const std::string& error_description) {
1070   static bool first_time = true;
1071   if (state_ == new_state && !first_time)
1072     return;
1073   LOG(WARNING) << "Activation state flip old = "
1074       << GetStateDescription(state_)
1075       << ", new = " << GetStateDescription(new_state);
1076   first_time = false;
1077 
1078   // Pick action that should happen on leaving the old state.
1079   switch (state_) {
1080     case PLAN_ACTIVATION_RECONNECTING_OTASP_TRY:
1081     case PLAN_ACTIVATION_RECONNECTING:
1082     case PLAN_ACTIVATION_RECONNECTING_OTASP:
1083       if (reconnect_timer_.IsRunning()) {
1084         reconnect_timer_.Stop();
1085       }
1086       break;
1087     default:
1088       break;
1089   }
1090   state_ = new_state;
1091 
1092   // Signal to JS layer that the state is changing.
1093   UpdatePage(network, error_description);
1094 
1095   // Pick action that should happen on entering the new state.
1096   switch (new_state) {
1097     case PLAN_ACTIVATION_START:
1098       break;
1099     case PLAN_ACTIVATION_DELAY_OTASP: {
1100       UMA_HISTOGRAM_COUNTS("Cellular.RetryOTASP", 1);
1101       scoped_refptr<TaskProxy> task = new TaskProxy(AsWeakPtr(), 0);
1102       BrowserThread::PostDelayedTask(BrowserThread::UI, FROM_HERE,
1103           NewRunnableMethod(task.get(), &TaskProxy::RetryOTASP),
1104           kOTASPRetryDelay);
1105       break;
1106     }
1107     case PLAN_ACTIVATION_INITIATING_ACTIVATION:
1108     case PLAN_ACTIVATION_TRYING_OTASP:
1109     case PLAN_ACTIVATION_OTASP:
1110       DCHECK(network);
1111       LOG(WARNING) << "Activating service " << network->service_path().c_str();
1112       UMA_HISTOGRAM_COUNTS("Cellular.ActivationTry", 1);
1113       if (!network->StartActivation()) {
1114         UMA_HISTOGRAM_COUNTS("Cellular.ActivationFailure", 1);
1115         if (new_state == PLAN_ACTIVATION_OTASP) {
1116           ChangeState(network, PLAN_ACTIVATION_DELAY_OTASP, std::string());
1117         } else {
1118           ChangeState(network, PLAN_ACTIVATION_ERROR,
1119                       GetErrorMessage(kFailedConnectivity));
1120         }
1121       }
1122       break;
1123     case PLAN_ACTIVATION_RECONNECTING_OTASP_TRY:
1124     case PLAN_ACTIVATION_RECONNECTING:
1125     case PLAN_ACTIVATION_RECONNECTING_OTASP: {
1126       // Start reconnect timer. This will ensure that we are not left in
1127       // limbo by the network library.
1128       if (!reconnect_timer_.IsRunning()) {
1129         reconnect_timer_.Start(
1130             base::TimeDelta::FromMilliseconds(kReconnectTimerDelayMS),
1131             this, &MobileSetupHandler::ReconnectTimerFired);
1132       }
1133       // Reset connection metrics and try to connect.
1134       reconnect_wait_count_ = 0;
1135       connection_retry_count_ = 0;
1136       connection_start_time_ = base::Time::Now();
1137       ConnectToNetwork(network, kReconnectDelayMS);
1138       break;
1139     }
1140     case PLAN_ACTIVATION_PAGE_LOADING:
1141       return;
1142     case PLAN_ACTIVATION_SHOWING_PAYMENT:
1143       // Fix for fix SSL for the walled gardens where cert chain verification
1144       // might not work.
1145       break;
1146     case PLAN_ACTIVATION_DONE:
1147       DCHECK(network);
1148       CompleteActivation(network);
1149       UMA_HISTOGRAM_COUNTS("Cellular.MobileSetupSucceeded", 1);
1150       break;
1151     case PLAN_ACTIVATION_ERROR:
1152       CompleteActivation(NULL);
1153       UMA_HISTOGRAM_COUNTS("Cellular.PlanFailed", 1);
1154       break;
1155     default:
1156       break;
1157   }
1158 }
1159 
ReEnableOtherConnections()1160 void MobileSetupHandler::ReEnableOtherConnections() {
1161   chromeos::NetworkLibrary* lib = chromeos::CrosLibrary::Get()->
1162       GetNetworkLibrary();
1163   if (reenable_ethernet_) {
1164     reenable_ethernet_ = false;
1165     lib->EnableEthernetNetworkDevice(true);
1166   }
1167   if (reenable_wifi_) {
1168     reenable_wifi_ = false;
1169     lib->EnableWifiNetworkDevice(true);
1170   }
1171 
1172   PrefService* prefs = g_browser_process->local_state();
1173   if (reenable_cert_check_) {
1174     prefs->SetBoolean(prefs::kCertRevocationCheckingEnabled,
1175                       true);
1176     reenable_cert_check_ = false;
1177   }
1178 }
1179 
SetupActivationProcess(chromeos::CellularNetwork * network)1180 void MobileSetupHandler::SetupActivationProcess(
1181     chromeos::CellularNetwork* network) {
1182   if (!network)
1183     return;
1184 
1185   // Disable SSL cert checks since we will be doing this in
1186   // restricted pool.
1187   PrefService* prefs = g_browser_process->local_state();
1188   if (!reenable_cert_check_ &&
1189       prefs->GetBoolean(
1190           prefs::kCertRevocationCheckingEnabled)) {
1191     reenable_cert_check_ = true;
1192     prefs->SetBoolean(prefs::kCertRevocationCheckingEnabled, false);
1193   }
1194 
1195   chromeos::NetworkLibrary* lib = chromeos::CrosLibrary::Get()->
1196       GetNetworkLibrary();
1197   // Disable autoconnect to cellular network.
1198   network->SetAutoConnect(false);
1199 
1200   // Prevent any other network interference.
1201   DisableOtherNetworks();
1202   lib->Lock();
1203 }
1204 
DisableOtherNetworks()1205 void MobileSetupHandler::DisableOtherNetworks() {
1206   chromeos::NetworkLibrary* lib = chromeos::CrosLibrary::Get()->
1207       GetNetworkLibrary();
1208   // Disable ethernet and wifi.
1209   if (lib->ethernet_enabled()) {
1210     reenable_ethernet_ = true;
1211     lib->EnableEthernetNetworkDevice(false);
1212   }
1213   if (lib->wifi_enabled()) {
1214     reenable_wifi_ = true;
1215     lib->EnableWifiNetworkDevice(false);
1216   }
1217 }
1218 
GotActivationError(chromeos::CellularNetwork * network,std::string * error)1219 bool MobileSetupHandler::GotActivationError(
1220     chromeos::CellularNetwork* network, std::string* error) {
1221   DCHECK(network);
1222   bool got_error = false;
1223   const char* error_code = kErrorDefault;
1224 
1225   // This is the magic for detection of errors in during activation process.
1226   if (network->state() == chromeos::STATE_FAILURE &&
1227       network->error() == chromeos::ERROR_AAA_FAILED) {
1228     if (network->activation_state() ==
1229             chromeos::ACTIVATION_STATE_PARTIALLY_ACTIVATED) {
1230       error_code = kErrorBadConnectionPartial;
1231     } else if (network->activation_state() ==
1232             chromeos::ACTIVATION_STATE_ACTIVATED) {
1233       if (network->roaming_state() == chromeos::ROAMING_STATE_HOME) {
1234         error_code = kErrorBadConnectionActivated;
1235       } else if (network->roaming_state() == chromeos::ROAMING_STATE_ROAMING) {
1236         error_code = kErrorRoamingOnConnection;
1237       }
1238     }
1239     got_error = true;
1240   } else if (network->state() == chromeos::STATE_ACTIVATION_FAILURE) {
1241     if (network->error() == chromeos::ERROR_NEED_EVDO) {
1242       if (network->activation_state() ==
1243               chromeos::ACTIVATION_STATE_PARTIALLY_ACTIVATED)
1244         error_code = kErrorNoEVDO;
1245     } else if (network->error() == chromeos::ERROR_NEED_HOME_NETWORK) {
1246       if (network->activation_state() ==
1247               chromeos::ACTIVATION_STATE_NOT_ACTIVATED) {
1248         error_code = kErrorRoamingActivation;
1249       } else if (network->activation_state() ==
1250                     chromeos::ACTIVATION_STATE_PARTIALLY_ACTIVATED) {
1251         error_code = kErrorRoamingPartiallyActivated;
1252       }
1253     }
1254     got_error = true;
1255   }
1256 
1257   if (got_error)
1258     *error = GetErrorMessage(error_code);
1259 
1260   return got_error;
1261 }
1262 
GetDeviceInfo(chromeos::CellularNetwork * network,DictionaryValue * value)1263 void MobileSetupHandler::GetDeviceInfo(chromeos::CellularNetwork* network,
1264                                        DictionaryValue* value) {
1265   DCHECK(network);
1266   chromeos::NetworkLibrary* cros =
1267       chromeos::CrosLibrary::Get()->GetNetworkLibrary();
1268   if (!cros)
1269     return;
1270   value->SetString("carrier", network->name());
1271   value->SetString("payment_url", network->payment_url());
1272   const chromeos::NetworkDevice* device =
1273       cros->FindNetworkDeviceByPath(network->device_path());
1274   if (device) {
1275     value->SetString("MEID", device->meid());
1276     value->SetString("IMEI", device->imei());
1277     value->SetString("MDN", device->mdn());
1278   }
1279 }
1280 
GetErrorMessage(const std::string & code)1281 std::string MobileSetupHandler::GetErrorMessage(const std::string& code) {
1282   if (!cellular_config_.get())
1283     return "";
1284   return cellular_config_->GetErrorMessage(code);
1285 }
1286 
LoadCellularConfig()1287 void MobileSetupHandler::LoadCellularConfig() {
1288   static bool config_loaded = false;
1289   if (config_loaded)
1290     return;
1291   config_loaded = true;
1292   // Load partner customization startup manifest if it is available.
1293   FilePath config_path(kCellularConfigPath);
1294   bool config_exists = false;
1295   {
1296     // Reading config file causes us to do blocking IO on UI thread.
1297     // Temporarily allow it until we fix http://crosbug.com/11535
1298     base::ThreadRestrictions::ScopedAllowIO allow_io;
1299     config_exists = file_util::PathExists(config_path);
1300   }
1301   if (config_exists) {
1302     scoped_ptr<CellularConfigDocument> config(new CellularConfigDocument());
1303     bool config_loaded = config->LoadFromFile(config_path);
1304     if (config_loaded) {
1305       LOG(INFO) << "Cellular config file loaded: " << kCellularConfigPath;
1306       // lock
1307       cellular_config_.reset(config.release());
1308     } else {
1309       LOG(ERROR) << "Error loading cellular config file: " <<
1310           kCellularConfigPath;
1311     }
1312   }
1313 }
1314 
1315 
1316 ////////////////////////////////////////////////////////////////////////////////
1317 //
1318 // MobileSetupUI
1319 //
1320 ////////////////////////////////////////////////////////////////////////////////
1321 
MobileSetupUI(TabContents * contents)1322 MobileSetupUI::MobileSetupUI(TabContents* contents) : WebUI(contents) {
1323   chromeos::CellularNetwork* network = GetCellularNetwork();
1324   std::string service_path = network ? network->service_path() : std::string();
1325   MobileSetupHandler* handler = new MobileSetupHandler(service_path);
1326   AddMessageHandler((handler)->Attach(this));
1327   handler->Init(contents);
1328   MobileSetupUIHTMLSource* html_source =
1329       new MobileSetupUIHTMLSource(service_path);
1330 
1331   // Set up the chrome://mobilesetup/ source.
1332   contents->profile()->GetChromeURLDataManager()->AddDataSource(html_source);
1333 }
1334