blob: efe35a7d3d4ac9d1b82f30599edf64bffb4f43dc [file] [log] [blame]
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "services/network/public/cpp/network_quality_tracker.h"
#include <limits>
#include <utility>
#include "base/bind.h"
#include "base/check_op.h"
#include "mojo/public/cpp/bindings/remote.h"
#include "services/network/public/mojom/network_service.mojom.h"
namespace network {
NetworkQualityTracker::NetworkQualityTracker(
base::RepeatingCallback<network::mojom::NetworkService*()> callback)
: get_network_service_callback_(callback),
effective_connection_type_(net::EFFECTIVE_CONNECTION_TYPE_UNKNOWN),
downlink_bandwidth_kbps_(std::numeric_limits<int32_t>::max()),
network_quality_overridden_for_testing_(false) {
InitializeMojoChannel();
DCHECK(receiver_.is_bound());
}
NetworkQualityTracker::~NetworkQualityTracker() {}
net::EffectiveConnectionType NetworkQualityTracker::GetEffectiveConnectionType()
const {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
return effective_connection_type_;
}
base::TimeDelta NetworkQualityTracker::GetHttpRTT() const {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
return http_rtt_;
}
base::TimeDelta NetworkQualityTracker::GetTransportRTT() const {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
return transport_rtt_;
}
int32_t NetworkQualityTracker::GetDownstreamThroughputKbps() const {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
return downlink_bandwidth_kbps_;
}
void NetworkQualityTracker::AddEffectiveConnectionTypeObserver(
EffectiveConnectionTypeObserver* observer) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
effective_connection_type_observer_list_.AddObserver(observer);
if (effective_connection_type_ != net::EFFECTIVE_CONNECTION_TYPE_UNKNOWN)
observer->OnEffectiveConnectionTypeChanged(effective_connection_type_);
}
void NetworkQualityTracker::RemoveEffectiveConnectionTypeObserver(
EffectiveConnectionTypeObserver* observer) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
effective_connection_type_observer_list_.RemoveObserver(observer);
}
void NetworkQualityTracker::AddRTTAndThroughputEstimatesObserver(
RTTAndThroughputEstimatesObserver* observer) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
rtt_and_throughput_observer_list_.AddObserver(observer);
observer->OnRTTOrThroughputEstimatesComputed(http_rtt_, transport_rtt_,
downlink_bandwidth_kbps_);
}
void NetworkQualityTracker::RemoveRTTAndThroughputEstimatesObserver(
RTTAndThroughputEstimatesObserver* observer) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
rtt_and_throughput_observer_list_.RemoveObserver(observer);
}
void NetworkQualityTracker::ReportEffectiveConnectionTypeForTesting(
net::EffectiveConnectionType effective_connection_type) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
network_quality_overridden_for_testing_ = true;
effective_connection_type_ = effective_connection_type;
for (auto& observer : effective_connection_type_observer_list_) {
observer.OnEffectiveConnectionTypeChanged(effective_connection_type);
}
}
void NetworkQualityTracker::ReportRTTsAndThroughputForTesting(
base::TimeDelta http_rtt,
int32_t downstream_throughput_kbps) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
network_quality_overridden_for_testing_ = true;
http_rtt_ = http_rtt;
downlink_bandwidth_kbps_ = downstream_throughput_kbps;
for (auto& observer : rtt_and_throughput_observer_list_) {
observer.OnRTTOrThroughputEstimatesComputed(http_rtt_, http_rtt_,
downlink_bandwidth_kbps_);
}
}
// For testing only.
NetworkQualityTracker::NetworkQualityTracker()
: effective_connection_type_(net::EFFECTIVE_CONNECTION_TYPE_UNKNOWN),
downlink_bandwidth_kbps_(std::numeric_limits<int32_t>::max()) {}
void NetworkQualityTracker::OnNetworkQualityChanged(
net::EffectiveConnectionType effective_connection_type,
base::TimeDelta http_rtt,
base::TimeDelta transport_rtt,
int32_t bandwidth_kbps) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (network_quality_overridden_for_testing_)
return;
// If the RTT values are unavailable, set them to value 0.
if (http_rtt < base::TimeDelta())
http_rtt = base::TimeDelta();
if (transport_rtt < base::TimeDelta())
transport_rtt = base::TimeDelta();
// If the bandwidth value is unavailable, set it to the maximum possible
// value.
if (bandwidth_kbps < 0)
bandwidth_kbps = std::numeric_limits<int32_t>::max();
if (http_rtt_ != http_rtt || transport_rtt_ != transport_rtt ||
downlink_bandwidth_kbps_ != bandwidth_kbps) {
http_rtt_ = http_rtt;
transport_rtt_ = transport_rtt;
downlink_bandwidth_kbps_ = bandwidth_kbps;
for (auto& observer : rtt_and_throughput_observer_list_) {
observer.OnRTTOrThroughputEstimatesComputed(http_rtt_, transport_rtt_,
downlink_bandwidth_kbps_);
}
}
if (effective_connection_type != effective_connection_type_) {
effective_connection_type_ = effective_connection_type;
for (auto& observer : effective_connection_type_observer_list_)
observer.OnEffectiveConnectionTypeChanged(effective_connection_type_);
}
}
void NetworkQualityTracker::InitializeMojoChannel() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DCHECK(!receiver_.is_bound());
network::mojom::NetworkService* network_service =
get_network_service_callback_.Run();
DCHECK(network_service);
// Get mojo::Remote<NetworkQualityEstimatorManager>.
mojo::Remote<network::mojom::NetworkQualityEstimatorManager> manager;
network_service->GetNetworkQualityEstimatorManager(
manager.BindNewPipeAndPassReceiver());
manager->RequestNotifications(receiver_.BindNewPipeAndPassRemote());
// base::Unretained is safe as destruction of the
// NetworkQualityTracker will also destroy the |receiver_|.
receiver_.set_disconnect_handler(
base::BindOnce(&NetworkQualityTracker::HandleNetworkServicePipeBroken,
base::Unretained(this)));
}
void NetworkQualityTracker::HandleNetworkServicePipeBroken() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
receiver_.reset();
InitializeMojoChannel();
}
} // namespace network