1 // Copyright (c) 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "chrome/browser/chromeos/net/network_portal_detector_impl.h"
10 #include "base/command_line.h"
11 #include "base/logging.h"
12 #include "base/message_loop/message_loop.h"
13 #include "base/metrics/histogram.h"
14 #include "base/strings/stringprintf.h"
15 #include "chrome/browser/chrome_notification_types.h"
16 #include "chromeos/dbus/dbus_thread_manager.h"
17 #include "chromeos/dbus/shill_profile_client.h"
18 #include "chromeos/login/login_state.h"
19 #include "chromeos/network/network_state.h"
20 #include "chromeos/network/network_state_handler.h"
21 #include "components/device_event_log/device_event_log.h"
22 #include "content/public/browser/notification_service.h"
23 #include "content/public/common/content_switches.h"
24 #include "net/http/http_status_code.h"
25 #include "third_party/cros_system_api/dbus/service_constants.h"
27 using base::StringPrintf
;
28 using captive_portal::CaptivePortalDetector
;
34 // Delay before portal detection caused by changes in proxy settings.
35 const int kProxyChangeDelaySec
= 1;
37 // Maximum number of reports from captive portal detector about
38 // offline state in a row before notification is sent to observers.
39 const int kMaxOfflineResultsBeforeReport
= 3;
41 // Delay before portal detection attempt after !ONLINE -> !ONLINE
43 const int kShortInitialDelayBetweenAttemptsMs
= 600;
45 // Maximum timeout before portal detection attempts after !ONLINE ->
46 // !ONLINE transition.
47 const int kShortMaximumDelayBetweenAttemptsMs
= 2 * 60 * 1000;
49 // Delay before portal detection attempt after !ONLINE -> ONLINE
51 const int kLongInitialDelayBetweenAttemptsMs
= 30 * 1000;
53 // Maximum timeout before portal detection attempts after !ONLINE ->
55 const int kLongMaximumDelayBetweenAttemptsMs
= 5 * 60 * 1000;
57 const NetworkState
* DefaultNetwork() {
58 return NetworkHandler::Get()->network_state_handler()->DefaultNetwork();
62 return LoginState::IsInitialized() && LoginState::Get()->IsUserLoggedIn();
65 void RecordDetectionResult(NetworkPortalDetector::CaptivePortalStatus status
) {
67 UMA_HISTOGRAM_ENUMERATION(
68 NetworkPortalDetectorImpl::kSessionDetectionResultHistogram
,
70 NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_COUNT
);
72 UMA_HISTOGRAM_ENUMERATION(
73 NetworkPortalDetectorImpl::kOobeDetectionResultHistogram
,
75 NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_COUNT
);
79 void RecordDetectionDuration(const base::TimeDelta
& duration
) {
81 UMA_HISTOGRAM_MEDIUM_TIMES(
82 NetworkPortalDetectorImpl::kSessionDetectionDurationHistogram
,
85 UMA_HISTOGRAM_MEDIUM_TIMES(
86 NetworkPortalDetectorImpl::kOobeDetectionDurationHistogram
, duration
);
90 void RecordDiscrepancyWithShill(
91 const NetworkState
* network
,
92 const NetworkPortalDetector::CaptivePortalStatus status
) {
94 if (network
->connection_state() == shill::kStateOnline
) {
95 UMA_HISTOGRAM_ENUMERATION(
96 NetworkPortalDetectorImpl::kSessionShillOnlineHistogram
,
98 NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_COUNT
);
99 } else if (network
->is_captive_portal()) {
100 UMA_HISTOGRAM_ENUMERATION(
101 NetworkPortalDetectorImpl::kSessionShillPortalHistogram
,
103 NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_COUNT
);
104 } else if (network
->connection_state() == shill::kStateOffline
) {
105 UMA_HISTOGRAM_ENUMERATION(
106 NetworkPortalDetectorImpl::kSessionShillOfflineHistogram
,
108 NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_COUNT
);
111 if (network
->connection_state() == shill::kStateOnline
) {
112 UMA_HISTOGRAM_ENUMERATION(
113 NetworkPortalDetectorImpl::kOobeShillOnlineHistogram
,
115 NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_COUNT
);
116 } else if (network
->is_captive_portal()) {
117 UMA_HISTOGRAM_ENUMERATION(
118 NetworkPortalDetectorImpl::kOobeShillPortalHistogram
,
120 NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_COUNT
);
121 } else if (network
->connection_state() == shill::kStateOffline
) {
122 UMA_HISTOGRAM_ENUMERATION(
123 NetworkPortalDetectorImpl::kOobeShillOfflineHistogram
,
125 NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_COUNT
);
130 void RecordPortalToOnlineTransition(const base::TimeDelta
& duration
) {
132 UMA_HISTOGRAM_LONG_TIMES(
133 NetworkPortalDetectorImpl::kSessionPortalToOnlineHistogram
,
136 UMA_HISTOGRAM_LONG_TIMES(
137 NetworkPortalDetectorImpl::kOobePortalToOnlineHistogram
,
144 ////////////////////////////////////////////////////////////////////////////////
145 // NetworkPortalDetectorImpl::DetectionAttemptCompletedLogState
147 NetworkPortalDetectorImpl::DetectionAttemptCompletedReport::
148 DetectionAttemptCompletedReport()
149 : result(captive_portal::RESULT_COUNT
), response_code(-1) {
152 NetworkPortalDetectorImpl::DetectionAttemptCompletedReport::
153 DetectionAttemptCompletedReport(const std::string network_name
,
154 const std::string network_id
,
155 captive_portal::CaptivePortalResult result
,
157 : network_name(network_name
),
158 network_id(network_id
),
160 response_code(response_code
) {
163 void NetworkPortalDetectorImpl::DetectionAttemptCompletedReport::Report()
165 // To see NET_LOG output, use '--vmodule=device_event_log*=1'
166 NET_LOG(EVENT
) << "Detection attempt completed: "
167 << "name=" << network_name
<< ", "
168 << "id=" << network_id
<< ", "
170 << captive_portal::CaptivePortalResultToString(result
) << ", "
171 << "response_code=" << response_code
;
174 bool NetworkPortalDetectorImpl::DetectionAttemptCompletedReport::Equals(
175 const DetectionAttemptCompletedReport
& o
) const {
176 return network_name
== o
.network_name
&& network_id
== o
.network_id
&&
177 result
== o
.result
&& response_code
== o
.response_code
;
180 ////////////////////////////////////////////////////////////////////////////////
181 // NetworkPortalDetectorImpl, public:
183 const char NetworkPortalDetectorImpl::kOobeDetectionResultHistogram
[] =
184 "CaptivePortal.OOBE.DetectionResult";
185 const char NetworkPortalDetectorImpl::kOobeDetectionDurationHistogram
[] =
186 "CaptivePortal.OOBE.DetectionDuration";
187 const char NetworkPortalDetectorImpl::kOobeShillOnlineHistogram
[] =
188 "CaptivePortal.OOBE.DiscrepancyWithShill_Online";
189 const char NetworkPortalDetectorImpl::kOobeShillPortalHistogram
[] =
190 "CaptivePortal.OOBE.DiscrepancyWithShill_RestrictedPool";
191 const char NetworkPortalDetectorImpl::kOobeShillOfflineHistogram
[] =
192 "CaptivePortal.OOBE.DiscrepancyWithShill_Offline";
193 const char NetworkPortalDetectorImpl::kOobePortalToOnlineHistogram
[] =
194 "CaptivePortal.OOBE.PortalToOnlineTransition";
196 const char NetworkPortalDetectorImpl::kSessionDetectionResultHistogram
[] =
197 "CaptivePortal.Session.DetectionResult";
198 const char NetworkPortalDetectorImpl::kSessionDetectionDurationHistogram
[] =
199 "CaptivePortal.Session.DetectionDuration";
200 const char NetworkPortalDetectorImpl::kSessionShillOnlineHistogram
[] =
201 "CaptivePortal.Session.DiscrepancyWithShill_Online";
202 const char NetworkPortalDetectorImpl::kSessionShillPortalHistogram
[] =
203 "CaptivePortal.Session.DiscrepancyWithShill_RestrictedPool";
204 const char NetworkPortalDetectorImpl::kSessionShillOfflineHistogram
[] =
205 "CaptivePortal.Session.DiscrepancyWithShill_Offline";
206 const char NetworkPortalDetectorImpl::kSessionPortalToOnlineHistogram
[] =
207 "CaptivePortal.Session.PortalToOnlineTransition";
210 void NetworkPortalDetectorImpl::Initialize(
211 net::URLRequestContextGetter
* url_context
) {
212 if (NetworkPortalDetector::set_for_testing())
214 CHECK(!NetworkPortalDetector::network_portal_detector())
215 << "NetworkPortalDetector was initialized twice.";
216 NET_LOG(EVENT
) << "NetworkPortalDetectorImpl::Initialize()";
217 if (base::CommandLine::ForCurrentProcess()->HasSwitch(::switches::kTestType
))
218 set_network_portal_detector(new NetworkPortalDetectorStubImpl());
220 set_network_portal_detector(new NetworkPortalDetectorImpl(url_context
));
223 NetworkPortalDetectorImpl::NetworkPortalDetectorImpl(
224 const scoped_refptr
<net::URLRequestContextGetter
>& request_context
)
225 : state_(STATE_IDLE
),
226 test_url_(CaptivePortalDetector::kDefaultURL
),
228 strategy_(PortalDetectorStrategy::CreateById(
229 PortalDetectorStrategy::STRATEGY_ID_LOGIN_SCREEN
,
231 last_detection_result_(CAPTIVE_PORTAL_STATUS_UNKNOWN
),
232 same_detection_result_count_(0),
233 no_response_result_count_(0),
234 weak_factory_(this) {
235 NET_LOG(EVENT
) << "NetworkPortalDetectorImpl::NetworkPortalDetectorImpl()";
236 captive_portal_detector_
.reset(new CaptivePortalDetector(request_context
));
238 notification_controller_
.set_retry_detection_callback(base::Bind(
239 &NetworkPortalDetectorImpl::RetryDetection
, base::Unretained(this)));
242 chrome::NOTIFICATION_LOGIN_PROXY_CHANGED
,
243 content::NotificationService::AllSources());
245 chrome::NOTIFICATION_AUTH_SUPPLIED
,
246 content::NotificationService::AllSources());
248 chrome::NOTIFICATION_AUTH_CANCELLED
,
249 content::NotificationService::AllSources());
251 NetworkHandler::Get()->network_state_handler()->AddObserver(this, FROM_HERE
);
252 StartDetectionIfIdle();
255 NetworkPortalDetectorImpl::~NetworkPortalDetectorImpl() {
256 NET_LOG(EVENT
) << "NetworkPortalDetectorImpl::~NetworkPortalDetectorImpl()";
257 DCHECK(CalledOnValidThread());
259 attempt_task_
.Cancel();
260 attempt_timeout_
.Cancel();
262 captive_portal_detector_
->Cancel();
263 captive_portal_detector_
.reset();
265 if (NetworkHandler::IsInitialized()) {
266 NetworkHandler::Get()->network_state_handler()->RemoveObserver(this,
271 void NetworkPortalDetectorImpl::AddObserver(Observer
* observer
) {
272 DCHECK(CalledOnValidThread());
273 if (observer
&& !observers_
.HasObserver(observer
))
274 observers_
.AddObserver(observer
);
277 void NetworkPortalDetectorImpl::AddAndFireObserver(Observer
* observer
) {
278 DCHECK(CalledOnValidThread());
281 AddObserver(observer
);
282 CaptivePortalState portal_state
;
283 const NetworkState
* network
= DefaultNetwork();
285 portal_state
= GetCaptivePortalState(network
->guid());
286 observer
->OnPortalDetectionCompleted(network
, portal_state
);
289 void NetworkPortalDetectorImpl::RemoveObserver(Observer
* observer
) {
290 DCHECK(CalledOnValidThread());
292 observers_
.RemoveObserver(observer
);
295 bool NetworkPortalDetectorImpl::IsEnabled() { return enabled_
; }
297 void NetworkPortalDetectorImpl::Enable(bool start_detection
) {
298 DCHECK(CalledOnValidThread());
305 const NetworkState
* network
= DefaultNetwork();
306 if (!start_detection
|| !network
)
308 NET_LOG(EVENT
) << "Starting detection attempt:"
309 << " name=" << network
->name() << " id=" << network
->guid();
310 portal_state_map_
.erase(network
->guid());
314 NetworkPortalDetectorImpl::CaptivePortalState
315 NetworkPortalDetectorImpl::GetCaptivePortalState(const std::string
& guid
) {
316 DCHECK(CalledOnValidThread());
317 CaptivePortalStateMap::const_iterator it
= portal_state_map_
.find(guid
);
318 if (it
== portal_state_map_
.end())
319 return CaptivePortalState();
323 bool NetworkPortalDetectorImpl::StartDetectionIfIdle() {
330 void NetworkPortalDetectorImpl::SetStrategy(
331 PortalDetectorStrategy::StrategyId id
) {
332 if (id
== strategy_
->Id())
334 strategy_
= PortalDetectorStrategy::CreateById(id
, this).Pass();
336 StartDetectionIfIdle();
339 void NetworkPortalDetectorImpl::OnLockScreenRequest() {
340 notification_controller_
.CloseDialog();
343 void NetworkPortalDetectorImpl::DefaultNetworkChanged(
344 const NetworkState
* default_network
) {
345 DCHECK(CalledOnValidThread());
347 notification_controller_
.DefaultNetworkChanged(default_network
);
348 if (!default_network
) {
349 NET_LOG(EVENT
) << "Default network changed: None";
351 default_network_name_
.clear();
355 CaptivePortalState state
;
356 state
.status
= CAPTIVE_PORTAL_STATUS_OFFLINE
;
357 OnDetectionCompleted(NULL
, state
);
361 default_network_name_
= default_network
->name();
363 bool network_changed
= (default_network_id_
!= default_network
->guid());
364 default_network_id_
= default_network
->guid();
366 bool connection_state_changed
=
367 (default_connection_state_
!= default_network
->connection_state());
368 default_connection_state_
= default_network
->connection_state();
370 NET_LOG(EVENT
) << "Default network changed:"
371 << " name=" << default_network_name_
372 << " id=" << default_network_id_
373 << " state=" << default_connection_state_
374 << " changed=" << network_changed
375 << " state_changed=" << connection_state_changed
;
377 if (network_changed
|| connection_state_changed
)
380 if (is_idle() && NetworkState::StateIsConnected(default_connection_state_
)) {
381 // Initiate Captive Portal detection if network's captive
382 // portal state is unknown (e.g. for freshly created networks),
383 // offline or if network connection state was changed.
384 CaptivePortalState state
= GetCaptivePortalState(default_network
->guid());
385 if (state
.status
== CAPTIVE_PORTAL_STATUS_UNKNOWN
||
386 state
.status
== CAPTIVE_PORTAL_STATUS_OFFLINE
||
387 (!network_changed
&& connection_state_changed
)) {
388 ScheduleAttempt(base::TimeDelta());
393 int NetworkPortalDetectorImpl::NoResponseResultCount() {
394 return no_response_result_count_
;
397 base::TimeTicks
NetworkPortalDetectorImpl::AttemptStartTime() {
398 return attempt_start_time_
;
401 base::TimeTicks
NetworkPortalDetectorImpl::NowTicks() {
402 if (time_ticks_for_testing_
.is_null())
403 return base::TimeTicks::Now();
404 return time_ticks_for_testing_
;
408 ////////////////////////////////////////////////////////////////////////////////
409 // NetworkPortalDetectorImpl, private:
411 void NetworkPortalDetectorImpl::StartDetection() {
414 ResetStrategyAndCounters();
415 detection_start_time_
= NowTicks();
416 ScheduleAttempt(base::TimeDelta());
419 void NetworkPortalDetectorImpl::StopDetection() {
420 attempt_task_
.Cancel();
421 attempt_timeout_
.Cancel();
422 captive_portal_detector_
->Cancel();
424 ResetStrategyAndCounters();
427 void NetworkPortalDetectorImpl::RetryDetection() {
432 void NetworkPortalDetectorImpl::ScheduleAttempt(const base::TimeDelta
& delay
) {
438 attempt_task_
.Cancel();
439 attempt_timeout_
.Cancel();
440 state_
= STATE_PORTAL_CHECK_PENDING
;
442 next_attempt_delay_
= std::max(delay
, strategy_
->GetDelayTillNextAttempt());
443 attempt_task_
.Reset(base::Bind(&NetworkPortalDetectorImpl::StartAttempt
,
444 weak_factory_
.GetWeakPtr()));
445 base::MessageLoop::current()->PostDelayedTask(
446 FROM_HERE
, attempt_task_
.callback(), next_attempt_delay_
);
449 void NetworkPortalDetectorImpl::StartAttempt() {
450 DCHECK(is_portal_check_pending());
452 state_
= STATE_CHECKING_FOR_PORTAL
;
453 attempt_start_time_
= NowTicks();
455 captive_portal_detector_
->DetectCaptivePortal(
457 base::Bind(&NetworkPortalDetectorImpl::OnAttemptCompleted
,
458 weak_factory_
.GetWeakPtr()));
459 attempt_timeout_
.Reset(
460 base::Bind(&NetworkPortalDetectorImpl::OnAttemptTimeout
,
461 weak_factory_
.GetWeakPtr()));
463 base::MessageLoop::current()->PostDelayedTask(
465 attempt_timeout_
.callback(),
466 strategy_
->GetNextAttemptTimeout());
469 void NetworkPortalDetectorImpl::OnAttemptTimeout() {
470 DCHECK(CalledOnValidThread());
471 DCHECK(is_checking_for_portal());
473 NET_LOG(ERROR
) << "Portal detection timeout: "
474 << " name=" << default_network_name_
475 << " id=" << default_network_id_
;
477 captive_portal_detector_
->Cancel();
478 CaptivePortalDetector::Results results
;
479 results
.result
= captive_portal::RESULT_NO_RESPONSE
;
480 OnAttemptCompleted(results
);
483 void NetworkPortalDetectorImpl::OnAttemptCompleted(
484 const CaptivePortalDetector::Results
& results
) {
485 DCHECK(CalledOnValidThread());
486 DCHECK(is_checking_for_portal());
488 captive_portal::CaptivePortalResult result
= results
.result
;
489 int response_code
= results
.response_code
;
491 const NetworkState
* network
= DefaultNetwork();
493 // If using a fake profile client, also fake being behind a captive portal
494 // if the default network is in portal state.
495 if (result
!= captive_portal::RESULT_NO_RESPONSE
&&
496 DBusThreadManager::Get()->GetShillProfileClient()->GetTestInterface() &&
497 network
&& network
->is_captive_portal()) {
498 result
= captive_portal::RESULT_BEHIND_CAPTIVE_PORTAL
;
502 DetectionAttemptCompletedReport
attempt_completed_report(
503 default_network_name_
, default_network_id_
, result
, response_code
);
504 if (!attempt_completed_report_
.Equals(attempt_completed_report
)) {
505 attempt_completed_report_
= attempt_completed_report
;
506 attempt_completed_report_
.Report();
510 attempt_timeout_
.Cancel();
512 CaptivePortalState state
;
513 state
.response_code
= response_code
;
514 state
.time
= NowTicks();
516 case captive_portal::RESULT_NO_RESPONSE
:
517 if (state
.response_code
== net::HTTP_PROXY_AUTHENTICATION_REQUIRED
) {
518 state
.status
= CAPTIVE_PORTAL_STATUS_PROXY_AUTH_REQUIRED
;
519 } else if (network
&& network
->is_captive_portal()) {
520 // Take into account shill's detection results.
521 state
.status
= CAPTIVE_PORTAL_STATUS_PORTAL
;
523 state
.status
= CAPTIVE_PORTAL_STATUS_OFFLINE
;
526 case captive_portal::RESULT_INTERNET_CONNECTED
:
527 state
.status
= CAPTIVE_PORTAL_STATUS_ONLINE
;
529 case captive_portal::RESULT_BEHIND_CAPTIVE_PORTAL
:
530 state
.status
= CAPTIVE_PORTAL_STATUS_PORTAL
;
536 if (last_detection_result_
!= state
.status
) {
537 last_detection_result_
= state
.status
;
538 same_detection_result_count_
= 1;
539 net::BackoffEntry::Policy policy
= strategy_
->policy();
540 if (state
.status
== CAPTIVE_PORTAL_STATUS_ONLINE
) {
541 policy
.initial_delay_ms
= kLongInitialDelayBetweenAttemptsMs
;
542 policy
.maximum_backoff_ms
= kLongMaximumDelayBetweenAttemptsMs
;
544 policy
.initial_delay_ms
= kShortInitialDelayBetweenAttemptsMs
;
545 policy
.maximum_backoff_ms
= kShortMaximumDelayBetweenAttemptsMs
;
547 strategy_
->SetPolicyAndReset(policy
);
549 ++same_detection_result_count_
;
551 strategy_
->OnDetectionCompleted();
553 if (result
== captive_portal::RESULT_NO_RESPONSE
)
554 ++no_response_result_count_
;
556 no_response_result_count_
= 0;
558 if (state
.status
!= CAPTIVE_PORTAL_STATUS_OFFLINE
||
559 same_detection_result_count_
>= kMaxOfflineResultsBeforeReport
) {
560 OnDetectionCompleted(network
, state
);
562 ScheduleAttempt(results
.retry_after_delta
);
565 void NetworkPortalDetectorImpl::Observe(
567 const content::NotificationSource
& source
,
568 const content::NotificationDetails
& details
) {
569 if (type
== chrome::NOTIFICATION_LOGIN_PROXY_CHANGED
||
570 type
== chrome::NOTIFICATION_AUTH_SUPPLIED
||
571 type
== chrome::NOTIFICATION_AUTH_CANCELLED
) {
572 NET_LOG(EVENT
) << "Restarting portal detection due to proxy change"
573 << " name=" << default_network_name_
;
575 ScheduleAttempt(base::TimeDelta::FromSeconds(kProxyChangeDelaySec
));
579 void NetworkPortalDetectorImpl::OnDetectionCompleted(
580 const NetworkState
* network
,
581 const CaptivePortalState
& state
) {
583 NotifyDetectionCompleted(network
, state
);
587 CaptivePortalStateMap::const_iterator it
=
588 portal_state_map_
.find(network
->guid());
589 if (it
== portal_state_map_
.end() || it
->second
.status
!= state
.status
||
590 it
->second
.response_code
!= state
.response_code
) {
591 // Record detection duration iff detection result differs from the
592 // previous one for this network. The reason is to record all stats
593 // only when network changes it's state.
594 RecordDetectionStats(network
, state
.status
);
595 if (it
!= portal_state_map_
.end() &&
596 it
->second
.status
== CAPTIVE_PORTAL_STATUS_PORTAL
&&
597 state
.status
== CAPTIVE_PORTAL_STATUS_ONLINE
) {
598 RecordPortalToOnlineTransition(state
.time
- it
->second
.time
);
601 portal_state_map_
[network
->guid()] = state
;
603 NotifyDetectionCompleted(network
, state
);
606 void NetworkPortalDetectorImpl::NotifyDetectionCompleted(
607 const NetworkState
* network
,
608 const CaptivePortalState
& state
) {
610 Observer
, observers_
, OnPortalDetectionCompleted(network
, state
));
611 notification_controller_
.OnPortalDetectionCompleted(network
, state
);
614 bool NetworkPortalDetectorImpl::AttemptTimeoutIsCancelledForTesting() const {
615 return attempt_timeout_
.IsCancelled();
618 void NetworkPortalDetectorImpl::RecordDetectionStats(
619 const NetworkState
* network
,
620 CaptivePortalStatus status
) {
621 // Don't record stats for offline state.
625 if (!detection_start_time_
.is_null())
626 RecordDetectionDuration(NowTicks() - detection_start_time_
);
627 RecordDetectionResult(status
);
630 case NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_UNKNOWN
:
633 case NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_OFFLINE
:
634 if (network
->IsConnectedState())
635 RecordDiscrepancyWithShill(network
, status
);
637 case NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_ONLINE
:
638 if (network
->connection_state() != shill::kStateOnline
)
639 RecordDiscrepancyWithShill(network
, status
);
641 case NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_PORTAL
:
642 if (!network
->is_captive_portal())
643 RecordDiscrepancyWithShill(network
, status
);
645 case NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_PROXY_AUTH_REQUIRED
:
646 if (network
->connection_state() != shill::kStateOnline
)
647 RecordDiscrepancyWithShill(network
, status
);
649 case NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_COUNT
:
655 void NetworkPortalDetectorImpl::ResetStrategyAndCounters() {
656 last_detection_result_
= CAPTIVE_PORTAL_STATUS_UNKNOWN
;
657 same_detection_result_count_
= 0;
658 no_response_result_count_
= 0;
662 } // namespace chromeos