Chromium Code Reviews| Index: content/browser/net/network_quality_observer_impl.cc |
| diff --git a/content/browser/net/network_quality_observer_impl.cc b/content/browser/net/network_quality_observer_impl.cc |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..538553427d7e7b2b56fa7728f316c1388f270693 |
| --- /dev/null |
| +++ b/content/browser/net/network_quality_observer_impl.cc |
| @@ -0,0 +1,178 @@ |
| +// Copyright 2017 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 "content/browser/net/network_quality_observer_impl.h" |
| + |
| +#include "base/memory/ptr_util.h" |
| +#include "content/browser/renderer_host/render_process_host_impl.h" |
| +#include "content/common/view_messages.h" |
| +#include "content/public/browser/browser_thread.h" |
| +#include "content/public/browser/notification_observer.h" |
| +#include "content/public/browser/notification_registrar.h" |
| +#include "content/public/browser/notification_service.h" |
| +#include "content/public/browser/notification_types.h" |
| +#include "content/public/browser/render_process_host.h" |
| + |
| +namespace { |
| + |
| +// Returns true if the |current_value| is meaningfully different from the |
| +// |past_value|. |
| +bool MetricChangedMeaningfully(int32_t past_value, int32_t current_value) { |
| + if ((past_value == net::nqe::internal::INVALID_RTT_THROUGHPUT) != |
| + (current_value == net::nqe::internal::INVALID_RTT_THROUGHPUT)) { |
| + return true; |
| + } |
| + |
| + if (past_value == net::nqe::internal::INVALID_RTT_THROUGHPUT && |
| + current_value == net::nqe::internal::INVALID_RTT_THROUGHPUT) { |
| + return false; |
| + } |
| + |
| + // Metric has changed meaningfully only if (i) the difference between the two |
| + // values exceed the threshold; and, (ii) the ratio of the values also exceeds |
| + // the threshold. |
| + static const int kMinDifferenceInMetrics = 100; |
| + static const float kMinRatio = 1.2f; |
| + |
| + if (std::abs(past_value - current_value) < kMinDifferenceInMetrics) { |
| + // The absolute change in the value is not sufficient enough. |
| + return false; |
| + } |
| + |
| + if (past_value < (kMinRatio * current_value) && |
| + current_value < (kMinRatio * past_value)) { |
| + // The relative change in the value is not sufficient enough. |
| + return false; |
| + } |
| + |
| + return true; |
| +} |
| + |
| +} // namespace |
| + |
| +namespace content { |
| + |
| +// UiThreadObserver observes the changes to the network quality on the UI |
| +// thread, and notifies the renderers of the change in the network quality. |
| +class NetworkQualityObserverImpl::UiThreadObserver |
| + : public content::NotificationObserver { |
| + public: |
| + UiThreadObserver() {} |
| + |
| + ~UiThreadObserver() override {} |
| + |
| + void InitOnUIThread() { |
| + DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| + registrar_.Add(this, NOTIFICATION_RENDERER_PROCESS_CREATED, |
|
nasko
2017/05/09 20:27:47
Shouldn't there be a Remove couterpart of this cal
tbansal1
2017/05/09 21:37:18
Done.
|
| + NotificationService::AllSources()); |
| + } |
| + |
| + void OnRTTOrThroughputEstimatesComputed( |
| + const net::nqe::internal::NetworkQuality& network_quality) { |
| + DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| + |
| + last_notified_network_quality_ = network_quality; |
| + |
| + // Notify all the existing renderers of the change in the network quality. |
| + for (RenderProcessHost::iterator it(RenderProcessHost::AllHostsIterator()); |
| + !it.IsAtEnd(); it.Advance()) { |
| + it.GetCurrentValue()->GetRendererInterface()->OnNetworkQualityChanged( |
| + last_notified_network_quality_.http_rtt().InMilliseconds(), |
| + last_notified_network_quality_.transport_rtt().InMilliseconds(), |
| + last_notified_network_quality_.downstream_throughput_kbps()); |
| + } |
| + } |
| + |
| + private: |
| + // NotificationObserver implementation: |
| + void Observe(int type, |
| + const NotificationSource& source, |
| + const NotificationDetails& details) override { |
| + DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| + DCHECK_EQ(NOTIFICATION_RENDERER_PROCESS_CREATED, type); |
| + |
| + RenderProcessHost* rph = Source<RenderProcessHost>(source).ptr(); |
| + |
| + // Notify the newly created renderer of the current network quality. |
| + rph->GetRendererInterface()->OnNetworkQualityChanged( |
| + last_notified_network_quality_.http_rtt().InMilliseconds(), |
| + last_notified_network_quality_.transport_rtt().InMilliseconds(), |
| + last_notified_network_quality_.downstream_throughput_kbps()); |
| + } |
| + |
| + content::NotificationRegistrar registrar_; |
| + |
| + // The network quality that was last notified to the renderers. |
|
nasko
2017/05/09 20:27:47
nit: s/notified/sent/
tbansal1
2017/05/09 21:37:18
Done.
|
| + net::nqe::internal::NetworkQuality last_notified_network_quality_; |
| + |
| + DISALLOW_COPY_AND_ASSIGN(UiThreadObserver); |
| +}; |
| + |
| +NetworkQualityObserverImpl::NetworkQualityObserverImpl( |
| + net::NetworkQualityEstimator* network_quality_estimator) |
| + : network_quality_estimator_(network_quality_estimator) { |
| + network_quality_estimator_->AddRTTAndThroughputEstimatesObserver(this); |
| + |
| + ui_thread_observer_ = base::MakeUnique<UiThreadObserver>(); |
| + BrowserThread::PostTask( |
| + BrowserThread::UI, FROM_HERE, |
| + base::BindOnce(&UiThreadObserver::InitOnUIThread, |
| + base::Unretained(ui_thread_observer_.get()))); |
| +} |
| + |
| +NetworkQualityObserverImpl::~NetworkQualityObserverImpl() { |
| + DCHECK(thread_checker_.CalledOnValidThread()); |
| + network_quality_estimator_->RemoveRTTAndThroughputEstimatesObserver(this); |
| + |
| + if (!ui_thread_observer_) |
| + return; |
| + |
| + // |ui_thread_observer_| must be deleted on UI thread. |
| + BrowserThread::DeleteSoon(BrowserThread::UI, FROM_HERE, |
| + ui_thread_observer_.release()); |
|
nasko
2017/05/09 20:27:47
You probably want to check the return value of Del
tbansal1
2017/05/09 21:37:18
Done.
|
| +} |
| + |
| +void NetworkQualityObserverImpl::OnRTTOrThroughputEstimatesComputed( |
| + base::TimeDelta http_rtt, |
| + base::TimeDelta transport_rtt, |
| + int32_t downstream_throughput_kbps) { |
| + DCHECK(thread_checker_.CalledOnValidThread()); |
| + |
| + // Check if any of the network quality metrics changed meaningfully. |
| + bool http_rtt_changed = MetricChangedMeaningfully( |
| + last_notified_network_quality_.http_rtt().InMilliseconds(), |
| + http_rtt.InMilliseconds()); |
| + |
| + bool transport_rtt_changed = MetricChangedMeaningfully( |
| + last_notified_network_quality_.transport_rtt().InMilliseconds(), |
| + transport_rtt.InMilliseconds()); |
| + bool kbps_changed = MetricChangedMeaningfully( |
| + last_notified_network_quality_.downstream_throughput_kbps(), |
| + downstream_throughput_kbps); |
| + |
| + if (!http_rtt_changed && !transport_rtt_changed && !kbps_changed) { |
| + // Return since none of the metrics changed meaningfully. This reduces |
| + // the number of notifications to the different renderers every time |
| + // the network quality is recomputed. |
| + return; |
| + } |
| + |
| + last_notified_network_quality_ = net::nqe::internal::NetworkQuality( |
| + http_rtt, transport_rtt, downstream_throughput_kbps); |
| + |
| + BrowserThread::PostTask( |
| + BrowserThread::UI, FROM_HERE, |
| + base::BindOnce(&UiThreadObserver::OnRTTOrThroughputEstimatesComputed, |
| + base::Unretained(ui_thread_observer_.get()), |
| + last_notified_network_quality_)); |
| +} |
| + |
| +std::unique_ptr<net::NetworkQualityEstimator::RTTAndThroughputEstimatesObserver> |
| +CreateNetworkQualityObserver( |
| + net::NetworkQualityEstimator* network_quality_estimator) { |
| + return base::MakeUnique<NetworkQualityObserverImpl>( |
| + network_quality_estimator); |
| +} |
| + |
| +} // namespace content |