Index: components/metrics/net/network_metrics_provider.cc |
diff --git a/components/metrics/net/network_metrics_provider.cc b/components/metrics/net/network_metrics_provider.cc |
index aa83846b851b1f777fc90e409068af1cd730a265..e5124f48b8cf6f0fe1cbd459f3bc4feb6b269559 100644 |
--- a/components/metrics/net/network_metrics_provider.cc |
+++ b/components/metrics/net/network_metrics_provider.cc |
@@ -9,6 +9,8 @@ |
#include <string> |
#include <vector> |
+#include "base/bind_helpers.h" |
+#include "base/callback_forward.h" |
#include "base/compiler_specific.h" |
#include "base/metrics/histogram_macros.h" |
#include "base/metrics/sparse_histogram.h" |
@@ -18,6 +20,7 @@ |
#include "base/task_runner_util.h" |
#include "build/build_config.h" |
#include "net/base/net_errors.h" |
+#include "net/nqe/network_quality_estimator.h" |
#if defined(OS_CHROMEOS) |
#include "components/metrics/net/wifi_access_point_info_provider_chromeos.h" |
@@ -25,25 +28,131 @@ |
namespace metrics { |
+// Listens to the changes in the effective conection type. |
+class NetworkMetricsProvider::EffectiveConnectionTypeObserver |
+ : public net::NetworkQualityEstimator::EffectiveConnectionTypeObserver { |
+ public: |
+ // |network_quality_estimator| is used to provide the network quality |
+ // estimates. Guaranteed to be non-null. |callback| is run on |
+ // |callback_task_runner|, and provides notifications about the changes in the |
+ // effective connection type. |
+ EffectiveConnectionTypeObserver( |
+ base::Callback<void(net::EffectiveConnectionType)> callback, |
+ const scoped_refptr<base::SequencedTaskRunner>& callback_task_runner) |
+ : network_quality_estimator_(nullptr), |
+ callback_(callback), |
+ callback_task_runner_(callback_task_runner) { |
+ DCHECK(callback_); |
+ DCHECK(callback_task_runner_); |
+ // |this| is initialized and used on the IO thread using |
+ // |network_quality_task_runner_|. |
+ thread_checker_.DetachFromThread(); |
+ } |
+ |
+ ~EffectiveConnectionTypeObserver() override { |
+ DCHECK(thread_checker_.CalledOnValidThread()); |
+ if (network_quality_estimator_) |
+ network_quality_estimator_->RemoveEffectiveConnectionTypeObserver(this); |
+ } |
+ |
+ // Initializes |this| on IO thread using |network_quality_task_runner_|. This |
+ // is the same thread on which |network_quality_estimator| lives. |
+ void Init(net::NetworkQualityEstimator* network_quality_estimator) { |
+ network_quality_estimator_ = network_quality_estimator; |
+ if (network_quality_estimator_) |
+ network_quality_estimator_->AddEffectiveConnectionTypeObserver(this); |
+ } |
+ |
+ private: |
+ // net::EffectiveConnectionTypeObserver implementation: |
+ void OnEffectiveConnectionTypeChanged( |
+ net::EffectiveConnectionType type) override { |
+ DCHECK(thread_checker_.CalledOnValidThread()); |
+ callback_task_runner_->PostTask(FROM_HERE, base::Bind(callback_, type)); |
+ } |
+ |
+ // Notifies |this| when there is a change in the effective connection type. |
+ net::NetworkQualityEstimator* network_quality_estimator_; |
+ |
+ // Called when the effective connection type is changed. |
+ base::Callback<void(net::EffectiveConnectionType)> callback_; |
+ |
+ // Task runner on which |callback_| is run. |
+ scoped_refptr<base::SequencedTaskRunner> callback_task_runner_; |
+ |
+ base::ThreadChecker thread_checker_; |
+ |
+ DISALLOW_COPY_AND_ASSIGN(EffectiveConnectionTypeObserver); |
+}; |
+ |
NetworkMetricsProvider::NetworkMetricsProvider(base::TaskRunner* io_task_runner) |
+ : NetworkMetricsProvider(nullptr, io_task_runner) {} |
+ |
+NetworkMetricsProvider::NetworkMetricsProvider( |
+ std::unique_ptr<NetworkQualityEstimatorProvider> |
+ network_quality_estimator_provider, |
+ base::TaskRunner* io_task_runner) |
: io_task_runner_(io_task_runner), |
connection_type_is_ambiguous_(false), |
wifi_phy_layer_protocol_is_ambiguous_(false), |
wifi_phy_layer_protocol_(net::WIFI_PHY_LAYER_PROTOCOL_UNKNOWN), |
total_aborts_(0), |
total_codes_(0), |
+ network_quality_estimator_provider_( |
+ std::move(network_quality_estimator_provider)), |
+ effective_connection_type_(net::EFFECTIVE_CONNECTION_TYPE_UNKNOWN), |
+ effective_connection_type_is_ambiguous_(false), |
weak_ptr_factory_(this) { |
net::NetworkChangeNotifier::AddConnectionTypeObserver(this); |
connection_type_ = net::NetworkChangeNotifier::GetConnectionType(); |
ProbeWifiPHYLayerProtocol(); |
+ |
+ if (network_quality_estimator_provider_) { |
+ network_quality_task_runner_ = |
+ network_quality_estimator_provider_->GetTaskRunner(); |
+ DCHECK(network_quality_task_runner_); |
+ effective_connection_type_observer_.reset( |
+ new EffectiveConnectionTypeObserver( |
+ base::Bind( |
+ &NetworkMetricsProvider::OnEffectiveConnectionTypeChanged, |
+ base::Unretained(this)), |
+ base::ThreadTaskRunnerHandle::Get())); |
+ |
+ // Get the network quality estimator and initialize |
+ // |effective_connection_type_observer_| on the same task runner on which |
+ // the network quality estimator lives. It is safe to use base::Unretained |
+ // here since both |network_quality_estimator_provider_| and |
+ // |effective_connection_type_observer_| are owned by |this|, and are |
+ // deleted on the |network_quality_task_runner_|. |
+ network_quality_task_runner_->PostTask( |
+ FROM_HERE, |
+ base::Bind(&NetworkQualityEstimatorProvider::ProvideEstimator, |
+ base::Unretained(network_quality_estimator_provider_.get()), |
+ base::Bind(&EffectiveConnectionTypeObserver::Init, |
+ base::Unretained( |
+ effective_connection_type_observer_.get())))); |
+ } |
} |
NetworkMetricsProvider::~NetworkMetricsProvider() { |
+ DCHECK(thread_checker_.CalledOnValidThread()); |
net::NetworkChangeNotifier::RemoveConnectionTypeObserver(this); |
+ if (effective_connection_type_observer_ && |
+ !network_quality_task_runner_->DeleteSoon( |
+ FROM_HERE, effective_connection_type_observer_.release())) { |
+ NOTREACHED() << " ECT observer was not deleted successfully"; |
+ } |
+ if (network_quality_estimator_provider_ && |
+ !network_quality_task_runner_->DeleteSoon( |
+ FROM_HERE, network_quality_estimator_provider_.release())) { |
+ NOTREACHED() |
+ << " Network quality estimate provider was not deleted successfully"; |
+ } |
} |
void NetworkMetricsProvider::ProvideGeneralMetrics( |
ChromeUserMetricsExtension*) { |
+ DCHECK(thread_checker_.CalledOnValidThread()); |
// ProvideGeneralMetrics is called on the main thread, at the time a metrics |
// record is being finalized. |
net::NetworkChangeNotifier::FinalizingMetricsLogRecord(); |
@@ -52,12 +161,14 @@ void NetworkMetricsProvider::ProvideGeneralMetrics( |
void NetworkMetricsProvider::ProvideSystemProfileMetrics( |
SystemProfileProto* system_profile) { |
+ DCHECK(thread_checker_.CalledOnValidThread()); |
SystemProfileProto::Network* network = system_profile->mutable_network(); |
network->set_connection_type_is_ambiguous(connection_type_is_ambiguous_); |
network->set_connection_type(GetConnectionType()); |
network->set_wifi_phy_layer_protocol_is_ambiguous( |
wifi_phy_layer_protocol_is_ambiguous_); |
network->set_wifi_phy_layer_protocol(GetWifiPHYLayerProtocol()); |
+ network->set_effective_connection_type(GetEffectiveConnectionType()); |
// Update the connection type. Note that this is necessary to set the network |
// type to "none" if there is no network connection for an entire UMA logging |
@@ -67,6 +178,7 @@ void NetworkMetricsProvider::ProvideSystemProfileMetrics( |
// Reset the "ambiguous" flags, since a new metrics log session has started. |
connection_type_is_ambiguous_ = false; |
wifi_phy_layer_protocol_is_ambiguous_ = false; |
+ effective_connection_type_is_ambiguous_ = false; |
if (!wifi_access_point_info_provider_.get()) { |
#if defined(OS_CHROMEOS) |
@@ -86,6 +198,7 @@ void NetworkMetricsProvider::ProvideSystemProfileMetrics( |
void NetworkMetricsProvider::OnConnectionTypeChanged( |
net::NetworkChangeNotifier::ConnectionType type) { |
+ DCHECK(thread_checker_.CalledOnValidThread()); |
// To avoid reporting an ambiguous connection type for users on flaky |
// connections, ignore transitions to the "none" state. Note that the |
// connection type is refreshed in ProvideSystemProfileMetrics() each time a |
@@ -106,6 +219,7 @@ void NetworkMetricsProvider::OnConnectionTypeChanged( |
SystemProfileProto::Network::ConnectionType |
NetworkMetricsProvider::GetConnectionType() const { |
+ DCHECK(thread_checker_.CalledOnValidThread()); |
switch (connection_type_) { |
case net::NetworkChangeNotifier::CONNECTION_NONE: |
return SystemProfileProto::Network::CONNECTION_NONE; |
@@ -130,6 +244,7 @@ NetworkMetricsProvider::GetConnectionType() const { |
SystemProfileProto::Network::WifiPHYLayerProtocol |
NetworkMetricsProvider::GetWifiPHYLayerProtocol() const { |
+ DCHECK(thread_checker_.CalledOnValidThread()); |
switch (wifi_phy_layer_protocol_) { |
case net::WIFI_PHY_LAYER_PROTOCOL_NONE: |
return SystemProfileProto::Network::WIFI_PHY_LAYER_PROTOCOL_NONE; |
@@ -150,7 +265,36 @@ NetworkMetricsProvider::GetWifiPHYLayerProtocol() const { |
return SystemProfileProto::Network::WIFI_PHY_LAYER_PROTOCOL_UNKNOWN; |
} |
+SystemProfileProto::Network::EffectiveConnectionType |
+NetworkMetricsProvider::GetEffectiveConnectionType() const { |
+ DCHECK(thread_checker_.CalledOnValidThread()); |
+ |
+ if (effective_connection_type_is_ambiguous_) |
+ return SystemProfileProto::Network::EFFECTIVE_CONNECTION_TYPE_AMBIGUOUS; |
+ |
+ switch (effective_connection_type_) { |
+ case net::EFFECTIVE_CONNECTION_TYPE_UNKNOWN: |
+ return SystemProfileProto::Network::EFFECTIVE_CONNECTION_TYPE_UNKNOWN; |
+ case net::EFFECTIVE_CONNECTION_TYPE_OFFLINE: |
+ return SystemProfileProto::Network::EFFECTIVE_CONNECTION_TYPE_OFFLINE; |
+ case net::EFFECTIVE_CONNECTION_TYPE_SLOW_2G: |
+ return SystemProfileProto::Network::EFFECTIVE_CONNECTION_TYPE_SLOW_2G; |
+ case net::EFFECTIVE_CONNECTION_TYPE_2G: |
+ return SystemProfileProto::Network::EFFECTIVE_CONNECTION_TYPE_2G; |
+ case net::EFFECTIVE_CONNECTION_TYPE_3G: |
+ return SystemProfileProto::Network::EFFECTIVE_CONNECTION_TYPE_3G; |
+ case net::EFFECTIVE_CONNECTION_TYPE_4G: |
+ return SystemProfileProto::Network::EFFECTIVE_CONNECTION_TYPE_4G; |
+ case net::EFFECTIVE_CONNECTION_TYPE_LAST: |
+ NOTREACHED(); |
+ return SystemProfileProto::Network::EFFECTIVE_CONNECTION_TYPE_UNKNOWN; |
+ } |
+ NOTREACHED(); |
+ return SystemProfileProto::Network::EFFECTIVE_CONNECTION_TYPE_UNKNOWN; |
+} |
+ |
void NetworkMetricsProvider::ProbeWifiPHYLayerProtocol() { |
+ DCHECK(thread_checker_.CalledOnValidThread()); |
PostTaskAndReplyWithResult( |
io_task_runner_, |
FROM_HERE, |
@@ -161,6 +305,7 @@ void NetworkMetricsProvider::ProbeWifiPHYLayerProtocol() { |
void NetworkMetricsProvider::OnWifiPHYLayerProtocolResult( |
net::WifiPHYLayerProtocol mode) { |
+ DCHECK(thread_checker_.CalledOnValidThread()); |
if (wifi_phy_layer_protocol_ != net::WIFI_PHY_LAYER_PROTOCOL_UNKNOWN && |
mode != wifi_phy_layer_protocol_) { |
wifi_phy_layer_protocol_is_ambiguous_ = true; |
@@ -171,6 +316,7 @@ void NetworkMetricsProvider::OnWifiPHYLayerProtocolResult( |
void NetworkMetricsProvider::WriteWifiAccessPointProto( |
const WifiAccessPointInfoProvider::WifiAccessPointInfo& info, |
SystemProfileProto::Network* network_proto) { |
+ DCHECK(thread_checker_.CalledOnValidThread()); |
SystemProfileProto::Network::WifiAccessPoint* access_point_info = |
network_proto->mutable_access_point_info(); |
SystemProfileProto::Network::WifiAccessPoint::SecurityMode security = |
@@ -246,6 +392,7 @@ void NetworkMetricsProvider::WriteWifiAccessPointProto( |
} |
void NetworkMetricsProvider::LogAggregatedMetrics() { |
+ DCHECK(thread_checker_.CalledOnValidThread()); |
base::HistogramBase* error_codes = base::SparseHistogram::FactoryGet( |
"Net.ErrorCodesForMainFrame3", |
base::HistogramBase::kUmaTargetedHistogramFlag); |
@@ -263,4 +410,15 @@ void NetworkMetricsProvider::LogAggregatedMetrics() { |
} |
} |
+void NetworkMetricsProvider::OnEffectiveConnectionTypeChanged( |
+ net::EffectiveConnectionType type) { |
+ DCHECK(thread_checker_.CalledOnValidThread()); |
+ if (effective_connection_type_ != type && |
+ type != net::EFFECTIVE_CONNECTION_TYPE_UNKNOWN && |
+ effective_connection_type_ != net::EFFECTIVE_CONNECTION_TYPE_UNKNOWN) { |
+ effective_connection_type_is_ambiguous_ = true; |
+ } |
+ effective_connection_type_ = type; |
+} |
+ |
} // namespace metrics |