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..a92ea1a9a5a20d899cb7847286ee663067dc2885 |
--- /dev/null |
+++ b/content/browser/net/network_quality_observer_impl.cc |
@@ -0,0 +1,184 @@ |
+// 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 { |
+ registrar_.Remove(this, NOTIFICATION_RENDERER_PROCESS_CREATED, |
+ NotificationService::AllSources()); |
+ } |
+ |
+ void InitOnUIThread() { |
+ DCHECK_CURRENTLY_ON(BrowserThread::UI); |
+ registrar_.Add(this, NOTIFICATION_RENDERER_PROCESS_CREATED, |
+ 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 sent to the renderers. |
+ 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); |
+ |
+ DCHECK(ui_thread_observer_); |
+ |
+ // If possible, delete |ui_thread_observer_| on UI thread. |
+ UiThreadObserver* ui_thread_observer_ptr = ui_thread_observer_.release(); |
+ bool posted = BrowserThread::DeleteSoon(BrowserThread::UI, FROM_HERE, |
+ ui_thread_observer_ptr); |
+ |
+ if (!posted) |
+ delete ui_thread_observer_ptr; |
+} |
+ |
+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 |