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