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