network_metrics_provider.cc 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352
  1. // Copyright 2014 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. #include "components/metrics/net/network_metrics_provider.h"
  5. #include <stdint.h>
  6. #include <algorithm>
  7. #include <string>
  8. #include <utility>
  9. #include "base/bind.h"
  10. #include "base/callback_helpers.h"
  11. #include "base/compiler_specific.h"
  12. #include "base/metrics/histogram_macros.h"
  13. #include "base/metrics/sparse_histogram.h"
  14. #include "base/strings/string_number_conversions.h"
  15. #include "base/strings/string_split.h"
  16. #include "base/strings/string_util.h"
  17. #include "base/task/thread_pool.h"
  18. #include "base/threading/thread_task_runner_handle.h"
  19. #include "build/build_config.h"
  20. #include "net/base/net_errors.h"
  21. #include "net/nqe/effective_connection_type_observer.h"
  22. #include "net/nqe/network_quality_estimator.h"
  23. #if BUILDFLAG(IS_ANDROID)
  24. #include "services/network/public/cpp/network_connection_tracker.h"
  25. #endif
  26. namespace metrics {
  27. SystemProfileProto::Network::EffectiveConnectionType
  28. ConvertEffectiveConnectionType(
  29. net::EffectiveConnectionType effective_connection_type) {
  30. switch (effective_connection_type) {
  31. case net::EFFECTIVE_CONNECTION_TYPE_UNKNOWN:
  32. return SystemProfileProto::Network::EFFECTIVE_CONNECTION_TYPE_UNKNOWN;
  33. case net::EFFECTIVE_CONNECTION_TYPE_SLOW_2G:
  34. return SystemProfileProto::Network::EFFECTIVE_CONNECTION_TYPE_SLOW_2G;
  35. case net::EFFECTIVE_CONNECTION_TYPE_2G:
  36. return SystemProfileProto::Network::EFFECTIVE_CONNECTION_TYPE_2G;
  37. case net::EFFECTIVE_CONNECTION_TYPE_3G:
  38. return SystemProfileProto::Network::EFFECTIVE_CONNECTION_TYPE_3G;
  39. case net::EFFECTIVE_CONNECTION_TYPE_4G:
  40. return SystemProfileProto::Network::EFFECTIVE_CONNECTION_TYPE_4G;
  41. case net::EFFECTIVE_CONNECTION_TYPE_OFFLINE:
  42. return SystemProfileProto::Network::EFFECTIVE_CONNECTION_TYPE_OFFLINE;
  43. case net::EFFECTIVE_CONNECTION_TYPE_LAST:
  44. NOTREACHED();
  45. return SystemProfileProto::Network::EFFECTIVE_CONNECTION_TYPE_UNKNOWN;
  46. }
  47. NOTREACHED();
  48. return SystemProfileProto::Network::EFFECTIVE_CONNECTION_TYPE_UNKNOWN;
  49. }
  50. NetworkMetricsProvider::NetworkMetricsProvider(
  51. network::NetworkConnectionTrackerAsyncGetter
  52. network_connection_tracker_async_getter,
  53. std::unique_ptr<NetworkQualityEstimatorProvider>
  54. network_quality_estimator_provider)
  55. : network_connection_tracker_(nullptr),
  56. connection_type_is_ambiguous_(false),
  57. connection_type_(network::mojom::ConnectionType::CONNECTION_UNKNOWN),
  58. network_connection_tracker_initialized_(false),
  59. wifi_phy_layer_protocol_is_ambiguous_(false),
  60. wifi_phy_layer_protocol_(net::WIFI_PHY_LAYER_PROTOCOL_UNKNOWN),
  61. total_aborts_(0),
  62. total_codes_(0),
  63. network_quality_estimator_provider_(
  64. std::move(network_quality_estimator_provider)),
  65. effective_connection_type_(net::EFFECTIVE_CONNECTION_TYPE_UNKNOWN),
  66. min_effective_connection_type_(net::EFFECTIVE_CONNECTION_TYPE_UNKNOWN),
  67. max_effective_connection_type_(net::EFFECTIVE_CONNECTION_TYPE_UNKNOWN) {
  68. network_connection_tracker_async_getter.Run(
  69. base::BindOnce(&NetworkMetricsProvider::SetNetworkConnectionTracker,
  70. weak_ptr_factory_.GetWeakPtr()));
  71. ProbeWifiPHYLayerProtocol();
  72. if (network_quality_estimator_provider_) {
  73. // Use |network_quality_estimator_provider_| to get network quality
  74. // tracker.
  75. network_quality_estimator_provider_->PostReplyOnNetworkQualityChanged(
  76. base::BindRepeating(
  77. &NetworkMetricsProvider::OnEffectiveConnectionTypeChanged,
  78. weak_ptr_factory_.GetWeakPtr()));
  79. }
  80. }
  81. NetworkMetricsProvider::~NetworkMetricsProvider() {
  82. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  83. if (network_connection_tracker_)
  84. network_connection_tracker_->RemoveNetworkConnectionObserver(this);
  85. }
  86. void NetworkMetricsProvider::SetNetworkConnectionTracker(
  87. network::NetworkConnectionTracker* network_connection_tracker) {
  88. DCHECK(network_connection_tracker);
  89. network_connection_tracker_ = network_connection_tracker;
  90. network_connection_tracker_->AddNetworkConnectionObserver(this);
  91. network_connection_tracker_->GetConnectionType(
  92. &connection_type_,
  93. base::BindOnce(&NetworkMetricsProvider::OnConnectionChanged,
  94. weak_ptr_factory_.GetWeakPtr()));
  95. if (connection_type_ != network::mojom::ConnectionType::CONNECTION_UNKNOWN)
  96. network_connection_tracker_initialized_ = true;
  97. }
  98. void NetworkMetricsProvider::FinalizingMetricsLogRecord() {
  99. #if BUILDFLAG(IS_ANDROID)
  100. // Metrics logged here will be included in every metrics log record. It's not
  101. // yet clear if these metrics are generally useful enough to warrant being
  102. // added to the SystemProfile proto, so they are logged here as histograms for
  103. // now.
  104. if (network::NetworkConnectionTracker::IsConnectionCellular(
  105. connection_type_)) {
  106. UMA_HISTOGRAM_ENUMERATION(
  107. "NCN.CellularConnectionSubtype",
  108. net::NetworkChangeNotifier::GetConnectionSubtype(),
  109. net::NetworkChangeNotifier::ConnectionSubtype::SUBTYPE_LAST + 1);
  110. }
  111. #endif
  112. }
  113. void NetworkMetricsProvider::ProvideCurrentSessionData(
  114. ChromeUserMetricsExtension*) {
  115. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  116. // ProvideCurrentSessionData is called on the main thread, at the time a
  117. // metrics record is being finalized.
  118. FinalizingMetricsLogRecord();
  119. LogAggregatedMetrics();
  120. }
  121. void NetworkMetricsProvider::ProvideSystemProfileMetrics(
  122. SystemProfileProto* system_profile) {
  123. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  124. DCHECK(!connection_type_is_ambiguous_ ||
  125. network_connection_tracker_initialized_);
  126. SystemProfileProto::Network* network = system_profile->mutable_network();
  127. network->set_connection_type_is_ambiguous(connection_type_is_ambiguous_);
  128. network->set_connection_type(GetConnectionType());
  129. network->set_wifi_phy_layer_protocol_is_ambiguous(
  130. wifi_phy_layer_protocol_is_ambiguous_);
  131. network->set_wifi_phy_layer_protocol(GetWifiPHYLayerProtocol());
  132. network->set_min_effective_connection_type(
  133. ConvertEffectiveConnectionType(min_effective_connection_type_));
  134. network->set_max_effective_connection_type(
  135. ConvertEffectiveConnectionType(max_effective_connection_type_));
  136. // Note: We get the initial connection type when it becomes available and it
  137. // is handled at SetNetworkConnectionTracker() when GetConnectionType() is
  138. // called.
  139. //
  140. // Update the connection type. Note that this is necessary to set the network
  141. // type to "none" if there is no network connection for an entire UMA logging
  142. // window, since OnConnectionTypeChanged() ignores transitions to the "none"
  143. // state, and that is ok since it just deals with the current known state.
  144. if (network_connection_tracker_) {
  145. network_connection_tracker_->GetConnectionType(&connection_type_,
  146. base::DoNothing());
  147. }
  148. if (connection_type_ != network::mojom::ConnectionType::CONNECTION_UNKNOWN)
  149. network_connection_tracker_initialized_ = true;
  150. // Reset the "ambiguous" flags, since a new metrics log session has started.
  151. connection_type_is_ambiguous_ = false;
  152. wifi_phy_layer_protocol_is_ambiguous_ = false;
  153. min_effective_connection_type_ = effective_connection_type_;
  154. max_effective_connection_type_ = effective_connection_type_;
  155. }
  156. void NetworkMetricsProvider::OnConnectionChanged(
  157. network::mojom::ConnectionType type) {
  158. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  159. // To avoid reporting an ambiguous connection type for users on flaky
  160. // connections, ignore transitions to the "none" state. Note that the
  161. // connection type is refreshed in ProvideSystemProfileMetrics() each time a
  162. // new UMA logging window begins, so users who genuinely transition to offline
  163. // mode for an extended duration will still be at least partially represented
  164. // in the metrics logs.
  165. if (type == network::mojom::ConnectionType::CONNECTION_NONE) {
  166. network_connection_tracker_initialized_ = true;
  167. return;
  168. }
  169. DCHECK(network_connection_tracker_initialized_ ||
  170. connection_type_ ==
  171. network::mojom::ConnectionType::CONNECTION_UNKNOWN);
  172. if (type != connection_type_ &&
  173. connection_type_ != network::mojom::ConnectionType::CONNECTION_NONE &&
  174. network_connection_tracker_initialized_) {
  175. // If |network_connection_tracker_initialized_| is false, it implies that
  176. // this is the first connection change callback received from network
  177. // connection tracker, and the previous connection type was
  178. // CONNECTION_UNKNOWN. In that case, connection type should not be marked as
  179. // ambiguous since there was no actual change in the connection type.
  180. connection_type_is_ambiguous_ = true;
  181. }
  182. network_connection_tracker_initialized_ = true;
  183. connection_type_ = type;
  184. ProbeWifiPHYLayerProtocol();
  185. }
  186. SystemProfileProto::Network::ConnectionType
  187. NetworkMetricsProvider::GetConnectionType() const {
  188. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  189. switch (connection_type_) {
  190. case network::mojom::ConnectionType::CONNECTION_NONE:
  191. return SystemProfileProto::Network::CONNECTION_NONE;
  192. case network::mojom::ConnectionType::CONNECTION_UNKNOWN:
  193. return SystemProfileProto::Network::CONNECTION_UNKNOWN;
  194. case network::mojom::ConnectionType::CONNECTION_ETHERNET:
  195. return SystemProfileProto::Network::CONNECTION_ETHERNET;
  196. case network::mojom::ConnectionType::CONNECTION_WIFI:
  197. return SystemProfileProto::Network::CONNECTION_WIFI;
  198. case network::mojom::ConnectionType::CONNECTION_2G:
  199. return SystemProfileProto::Network::CONNECTION_2G;
  200. case network::mojom::ConnectionType::CONNECTION_3G:
  201. return SystemProfileProto::Network::CONNECTION_3G;
  202. case network::mojom::ConnectionType::CONNECTION_4G:
  203. return SystemProfileProto::Network::CONNECTION_4G;
  204. case network::mojom::ConnectionType::CONNECTION_5G:
  205. return SystemProfileProto::Network::CONNECTION_5G;
  206. case network::mojom::ConnectionType::CONNECTION_BLUETOOTH:
  207. return SystemProfileProto::Network::CONNECTION_BLUETOOTH;
  208. }
  209. NOTREACHED();
  210. return SystemProfileProto::Network::CONNECTION_UNKNOWN;
  211. }
  212. SystemProfileProto::Network::WifiPHYLayerProtocol
  213. NetworkMetricsProvider::GetWifiPHYLayerProtocol() const {
  214. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  215. switch (wifi_phy_layer_protocol_) {
  216. case net::WIFI_PHY_LAYER_PROTOCOL_NONE:
  217. return SystemProfileProto::Network::WIFI_PHY_LAYER_PROTOCOL_NONE;
  218. case net::WIFI_PHY_LAYER_PROTOCOL_ANCIENT:
  219. return SystemProfileProto::Network::WIFI_PHY_LAYER_PROTOCOL_ANCIENT;
  220. case net::WIFI_PHY_LAYER_PROTOCOL_A:
  221. return SystemProfileProto::Network::WIFI_PHY_LAYER_PROTOCOL_A;
  222. case net::WIFI_PHY_LAYER_PROTOCOL_B:
  223. return SystemProfileProto::Network::WIFI_PHY_LAYER_PROTOCOL_B;
  224. case net::WIFI_PHY_LAYER_PROTOCOL_G:
  225. return SystemProfileProto::Network::WIFI_PHY_LAYER_PROTOCOL_G;
  226. case net::WIFI_PHY_LAYER_PROTOCOL_N:
  227. return SystemProfileProto::Network::WIFI_PHY_LAYER_PROTOCOL_N;
  228. case net::WIFI_PHY_LAYER_PROTOCOL_AC:
  229. return SystemProfileProto::Network::WIFI_PHY_LAYER_PROTOCOL_AC;
  230. case net::WIFI_PHY_LAYER_PROTOCOL_AD:
  231. return SystemProfileProto::Network::WIFI_PHY_LAYER_PROTOCOL_AD;
  232. case net::WIFI_PHY_LAYER_PROTOCOL_AX:
  233. return SystemProfileProto::Network::WIFI_PHY_LAYER_PROTOCOL_AX;
  234. case net::WIFI_PHY_LAYER_PROTOCOL_UNKNOWN:
  235. return SystemProfileProto::Network::WIFI_PHY_LAYER_PROTOCOL_UNKNOWN;
  236. }
  237. NOTREACHED();
  238. return SystemProfileProto::Network::WIFI_PHY_LAYER_PROTOCOL_UNKNOWN;
  239. }
  240. void NetworkMetricsProvider::ProbeWifiPHYLayerProtocol() {
  241. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  242. base::ThreadPool::PostTaskAndReplyWithResult(
  243. FROM_HERE,
  244. {base::MayBlock(), base::TaskPriority::BEST_EFFORT,
  245. base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN},
  246. base::BindOnce(&net::GetWifiPHYLayerProtocol),
  247. base::BindOnce(&NetworkMetricsProvider::OnWifiPHYLayerProtocolResult,
  248. weak_ptr_factory_.GetWeakPtr()));
  249. }
  250. void NetworkMetricsProvider::OnWifiPHYLayerProtocolResult(
  251. net::WifiPHYLayerProtocol mode) {
  252. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  253. if (wifi_phy_layer_protocol_ != net::WIFI_PHY_LAYER_PROTOCOL_UNKNOWN &&
  254. mode != wifi_phy_layer_protocol_) {
  255. wifi_phy_layer_protocol_is_ambiguous_ = true;
  256. }
  257. wifi_phy_layer_protocol_ = mode;
  258. }
  259. void NetworkMetricsProvider::LogAggregatedMetrics() {
  260. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  261. base::HistogramBase* error_codes = base::SparseHistogram::FactoryGet(
  262. "Net.ErrorCodesForMainFrame4",
  263. base::HistogramBase::kUmaTargetedHistogramFlag);
  264. std::unique_ptr<base::HistogramSamples> samples =
  265. error_codes->SnapshotSamples();
  266. base::HistogramBase::Count new_aborts =
  267. samples->GetCount(-net::ERR_ABORTED) - total_aborts_;
  268. base::HistogramBase::Count new_codes = samples->TotalCount() - total_codes_;
  269. if (new_codes > 0) {
  270. UMA_HISTOGRAM_CUSTOM_COUNTS("Net.ErrAborted.CountPerUpload2", new_aborts, 1,
  271. 100000000, 50);
  272. UMA_HISTOGRAM_PERCENTAGE("Net.ErrAborted.ProportionPerUpload",
  273. (100 * new_aborts) / new_codes);
  274. total_codes_ += new_codes;
  275. total_aborts_ += new_aborts;
  276. }
  277. }
  278. void NetworkMetricsProvider::OnEffectiveConnectionTypeChanged(
  279. net::EffectiveConnectionType type) {
  280. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  281. effective_connection_type_ = type;
  282. if (effective_connection_type_ == net::EFFECTIVE_CONNECTION_TYPE_UNKNOWN ||
  283. effective_connection_type_ == net::EFFECTIVE_CONNECTION_TYPE_OFFLINE) {
  284. // The effective connection type may be reported as Unknown if there is a
  285. // change in the connection type. Disregard it since network requests can't
  286. // be send during the changes in connection type. Similarly, disregard
  287. // offline as the type since it may be reported as the effective connection
  288. // type for a short period when there is a change in the connection type.
  289. return;
  290. }
  291. if (min_effective_connection_type_ ==
  292. net::EFFECTIVE_CONNECTION_TYPE_UNKNOWN &&
  293. max_effective_connection_type_ ==
  294. net::EFFECTIVE_CONNECTION_TYPE_UNKNOWN) {
  295. min_effective_connection_type_ = type;
  296. max_effective_connection_type_ = type;
  297. return;
  298. }
  299. if (min_effective_connection_type_ ==
  300. net::EFFECTIVE_CONNECTION_TYPE_OFFLINE &&
  301. max_effective_connection_type_ ==
  302. net::EFFECTIVE_CONNECTION_TYPE_OFFLINE) {
  303. min_effective_connection_type_ = type;
  304. max_effective_connection_type_ = type;
  305. return;
  306. }
  307. min_effective_connection_type_ =
  308. std::min(min_effective_connection_type_, effective_connection_type_);
  309. max_effective_connection_type_ =
  310. std::max(max_effective_connection_type_, effective_connection_type_);
  311. DCHECK_EQ(
  312. min_effective_connection_type_ == net::EFFECTIVE_CONNECTION_TYPE_UNKNOWN,
  313. max_effective_connection_type_ == net::EFFECTIVE_CONNECTION_TYPE_UNKNOWN);
  314. DCHECK_EQ(
  315. min_effective_connection_type_ == net::EFFECTIVE_CONNECTION_TYPE_OFFLINE,
  316. max_effective_connection_type_ == net::EFFECTIVE_CONNECTION_TYPE_OFFLINE);
  317. }
  318. } // namespace metrics