1 // Copyright 2019 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 "chromeos/components/sync_wifi/synced_network_metrics_logger.h"
6 
7 #include "base/bind.h"
8 #include "base/metrics/histogram_functions.h"
9 #include "chromeos/network/network_configuration_handler.h"
10 #include "chromeos/network/network_connection_handler.h"
11 #include "chromeos/network/network_metadata_store.h"
12 #include "chromeos/network/network_state_handler.h"
13 #include "third_party/cros_system_api/dbus/service_constants.h"
14 #include "third_party/cros_system_api/dbus/shill/dbus-constants.h"
15 
16 namespace chromeos {
17 
18 namespace sync_wifi {
19 
20 // static
21 ConnectionFailureReason
ConnectionFailureReasonToEnum(const std::string & reason)22 SyncedNetworkMetricsLogger::ConnectionFailureReasonToEnum(
23     const std::string& reason) {
24   if (reason == shill::kErrorBadPassphrase)
25     return ConnectionFailureReason::kBadPassphrase;
26   else if (reason == shill::kErrorBadWEPKey)
27     return ConnectionFailureReason::kBadWepKey;
28   else if (reason == shill::kErrorConnectFailed)
29     return ConnectionFailureReason::kFailedToConnect;
30   else if (reason == shill::kErrorDhcpFailed)
31     return ConnectionFailureReason::kDhcpFailure;
32   else if (reason == shill::kErrorDNSLookupFailed)
33     return ConnectionFailureReason::kDnsLookupFailure;
34   else if (reason == shill::kErrorEapAuthenticationFailed)
35     return ConnectionFailureReason::kEapAuthentication;
36   else if (reason == shill::kErrorEapLocalTlsFailed)
37     return ConnectionFailureReason::kEapLocalTls;
38   else if (reason == shill::kErrorEapRemoteTlsFailed)
39     return ConnectionFailureReason::kEapRemoteTls;
40   else if (reason == shill::kErrorOutOfRange)
41     return ConnectionFailureReason::kOutOfRange;
42   else if (reason == shill::kErrorPinMissing)
43     return ConnectionFailureReason::kPinMissing;
44   else if (reason == shill::kErrorNoFailure)
45     return ConnectionFailureReason::kNoFailure;
46   else if (reason == shill::kErrorNotAssociated)
47     return ConnectionFailureReason::kNotAssociated;
48   else if (reason == shill::kErrorNotAuthenticated)
49     return ConnectionFailureReason::kNotAuthenticated;
50   else if (reason == shill::kErrorTooManySTAs)
51     return ConnectionFailureReason::kTooManySTAs;
52   else
53     return ConnectionFailureReason::kUnknown;
54 }
55 
56 // static
ApplyFailureReasonToEnum(const std::string & reason)57 ApplyNetworkFailureReason SyncedNetworkMetricsLogger::ApplyFailureReasonToEnum(
58     const std::string& reason) {
59   if (reason == shill::kErrorResultAlreadyExists) {
60     return ApplyNetworkFailureReason::kAlreadyExists;
61   } else if (reason == shill::kErrorResultInProgress) {
62     return ApplyNetworkFailureReason::kInProgress;
63   } else if (reason == shill::kErrorInternal ||
64              reason == shill::kErrorResultInternalError) {
65     return ApplyNetworkFailureReason::kInternalError;
66   } else if (reason == shill::kErrorResultInvalidArguments) {
67     return ApplyNetworkFailureReason::kInvalidArguments;
68   } else if (reason == shill::kErrorResultInvalidNetworkName) {
69     return ApplyNetworkFailureReason::kInvalidNetworkName;
70   } else if (reason == shill::kErrorResultInvalidPassphrase ||
71              reason == shill::kErrorBadPassphrase) {
72     return ApplyNetworkFailureReason::kInvalidPassphrase;
73   } else if (reason == shill::kErrorResultInvalidProperty) {
74     return ApplyNetworkFailureReason::kInvalidProperty;
75   } else if (reason == shill::kErrorResultNotSupported) {
76     return ApplyNetworkFailureReason::kNotSupported;
77   } else if (reason == shill::kErrorResultPassphraseRequired) {
78     return ApplyNetworkFailureReason::kPassphraseRequired;
79   } else if (reason == shill::kErrorResultPermissionDenied) {
80     return ApplyNetworkFailureReason::kPermissionDenied;
81   } else {
82     return ApplyNetworkFailureReason::kUnknown;
83   }
84 }
85 
SyncedNetworkMetricsLogger(NetworkStateHandler * network_state_handler,NetworkConnectionHandler * network_connection_handler)86 SyncedNetworkMetricsLogger::SyncedNetworkMetricsLogger(
87     NetworkStateHandler* network_state_handler,
88     NetworkConnectionHandler* network_connection_handler) {
89   if (network_state_handler) {
90     network_state_handler_ = network_state_handler;
91     network_state_handler_->AddObserver(this, FROM_HERE);
92   }
93 
94   if (network_connection_handler) {
95     network_connection_handler_ = network_connection_handler;
96     network_connection_handler_->AddObserver(this);
97   }
98 }
99 
~SyncedNetworkMetricsLogger()100 SyncedNetworkMetricsLogger::~SyncedNetworkMetricsLogger() {
101   OnShuttingDown();
102 }
103 
OnShuttingDown()104 void SyncedNetworkMetricsLogger::OnShuttingDown() {
105   if (network_state_handler_) {
106     network_state_handler_->RemoveObserver(this, FROM_HERE);
107     network_state_handler_ = nullptr;
108   }
109 
110   if (network_connection_handler_) {
111     network_connection_handler_->RemoveObserver(this);
112     network_connection_handler_ = nullptr;
113   }
114 }
115 
ConnectSucceeded(const std::string & service_path)116 void SyncedNetworkMetricsLogger::ConnectSucceeded(
117     const std::string& service_path) {
118   const NetworkState* network =
119       network_state_handler_->GetNetworkState(service_path);
120   if (!IsEligible(network))
121     return;
122 
123   base::UmaHistogramBoolean(kConnectionResultManualHistogram, true);
124 }
125 
ConnectFailed(const std::string & service_path,const std::string & error_name)126 void SyncedNetworkMetricsLogger::ConnectFailed(const std::string& service_path,
127                                                const std::string& error_name) {
128   const NetworkState* network =
129       network_state_handler_->GetNetworkState(service_path);
130   if (!IsEligible(network))
131     return;
132 
133   // Get the the current state and error info.
134   NetworkHandler::Get()->network_configuration_handler()->GetShillProperties(
135       service_path,
136       base::BindOnce(&SyncedNetworkMetricsLogger::OnConnectErrorGetProperties,
137                      weak_ptr_factory_.GetWeakPtr(), error_name));
138 }
139 
NetworkConnectionStateChanged(const NetworkState * network)140 void SyncedNetworkMetricsLogger::NetworkConnectionStateChanged(
141     const NetworkState* network) {
142   if (!IsEligible(network)) {
143     return;
144   }
145 
146   if (network->IsConnectingState()) {
147     if (!connecting_guids_.contains(network->guid())) {
148       connecting_guids_.insert(network->guid());
149     }
150     return;
151   }
152 
153   if (!connecting_guids_.contains(network->guid())) {
154     return;
155   }
156 
157   if (network->connection_state() == shill::kStateFailure) {
158     base::UmaHistogramBoolean(kConnectionResultAllHistogram, false);
159     base::UmaHistogramEnumeration(
160         kConnectionFailureReasonAllHistogram,
161         ConnectionFailureReasonToEnum(network->GetError()));
162   } else if (network->IsConnectedState()) {
163     base::UmaHistogramBoolean(kConnectionResultAllHistogram, true);
164   }
165   connecting_guids_.erase(network->guid());
166 }
167 
IsEligible(const NetworkState * network)168 bool SyncedNetworkMetricsLogger::IsEligible(const NetworkState* network) {
169   // Only non-tether Wi-Fi networks are eligible for logging.
170   if (!network || network->type() != shill::kTypeWifi ||
171       !network->tether_guid().empty()) {
172     return false;
173   }
174 
175   NetworkMetadataStore* metadata_store =
176       NetworkHandler::Get()->network_metadata_store();
177   if (!metadata_store) {
178     return false;
179   }
180 
181   return metadata_store->GetIsConfiguredBySync(network->guid());
182 }
183 
OnConnectErrorGetProperties(const std::string & error_name,const std::string & service_path,base::Optional<base::Value> shill_properties)184 void SyncedNetworkMetricsLogger::OnConnectErrorGetProperties(
185     const std::string& error_name,
186     const std::string& service_path,
187     base::Optional<base::Value> shill_properties) {
188   if (!shill_properties) {
189     base::UmaHistogramBoolean(kConnectionResultManualHistogram, false);
190     base::UmaHistogramEnumeration(kConnectionFailureReasonManualHistogram,
191                                   ConnectionFailureReasonToEnum(error_name));
192     return;
193   }
194   const std::string* state =
195       shill_properties->FindStringKey(shill::kStateProperty);
196   if (state && (NetworkState::StateIsConnected(*state) ||
197                 NetworkState::StateIsConnecting(*state))) {
198     // If network is no longer in an error state, don't record it.
199     return;
200   }
201 
202   const std::string* shill_error =
203       shill_properties->FindStringKey(shill::kErrorProperty);
204   if (!shill_error || !NetworkState::ErrorIsValid(*shill_error)) {
205     shill_error =
206         shill_properties->FindStringKey(shill::kPreviousErrorProperty);
207     if (!shill_error || !NetworkState::ErrorIsValid(*shill_error))
208       shill_error = &error_name;
209   }
210   base::UmaHistogramBoolean(kConnectionResultManualHistogram, false);
211   base::UmaHistogramEnumeration(kConnectionFailureReasonManualHistogram,
212                                 ConnectionFailureReasonToEnum(*shill_error));
213 }
214 
RecordApplyNetworkSuccess()215 void SyncedNetworkMetricsLogger::RecordApplyNetworkSuccess() {
216   base::UmaHistogramBoolean(kApplyResultHistogram, true);
217 }
RecordApplyNetworkFailed()218 void SyncedNetworkMetricsLogger::RecordApplyNetworkFailed() {
219   base::UmaHistogramBoolean(kApplyResultHistogram, false);
220 }
221 
RecordApplyNetworkFailureReason(ApplyNetworkFailureReason error_enum,const std::string & error_string)222 void SyncedNetworkMetricsLogger::RecordApplyNetworkFailureReason(
223     ApplyNetworkFailureReason error_enum,
224     const std::string& error_string) {
225   // Get a specific error from the |error_string| if available.
226   ApplyNetworkFailureReason reason = ApplyFailureReasonToEnum(error_string);
227   if (reason == ApplyNetworkFailureReason::kUnknown) {
228     // Fallback on the provided enum.
229     reason = error_enum;
230   }
231 
232   base::UmaHistogramEnumeration(kApplyFailureReasonHistogram, reason);
233 }
234 
RecordTotalCount(int count)235 void SyncedNetworkMetricsLogger::RecordTotalCount(int count) {
236   base::UmaHistogramCounts1000(kTotalCountHistogram, count);
237 }
238 
239 }  // namespace sync_wifi
240 
241 }  // namespace chromeos
242