diff --git a/chrome/browser/resource_coordinator/resource_coordinator_web_contents_observer.cc b/chrome/browser/resource_coordinator/resource_coordinator_web_contents_observer.cc index eddc0f56dd07..c209e4845dfd 100644 --- a/chrome/browser/resource_coordinator/resource_coordinator_web_contents_observer.cc +++ b/chrome/browser/resource_coordinator/resource_coordinator_web_contents_observer.cc @@ -28,10 +28,6 @@ DEFINE_WEB_CONTENTS_USER_DATA_KEY(ResourceCoordinatorWebContentsObserver); -// We delay the sending of favicon/title update signal to GRC for 5 minutes -// after the main frame navigation is committed. -const base::TimeDelta kFaviconAndTitleUpdateIgnoredTimeout = - base::TimeDelta::FromMinutes(5); bool ResourceCoordinatorWebContentsObserver::ukm_recorder_initialized = false; ResourceCoordinatorWebContentsObserver::ResourceCoordinatorWebContentsObserver( @@ -149,7 +145,8 @@ void ResourceCoordinatorWebContentsObserver::DidFinishNavigation( if (navigation_handle->IsInMainFrame()) { UpdateUkmRecorder(navigation_handle); ResetFlag(); - navigation_finished_time_ = base::TimeTicks::Now(); + tab_resource_coordinator_->SendEvent( + resource_coordinator::mojom::Event::kNavigationCommitted); } content::RenderFrameHost* render_frame_host = @@ -171,13 +168,6 @@ void ResourceCoordinatorWebContentsObserver::TitleWasSet( first_time_title_set_ = true; return; } - // Ignore update when the tab is in foreground or the update happens within 5 - // minutes after the main frame is committed. - if (web_contents()->IsVisible() || - base::TimeTicks::Now() - navigation_finished_time_ < - kFaviconAndTitleUpdateIgnoredTimeout) { - return; - } tab_resource_coordinator_->SendEvent( resource_coordinator::mojom::Event::kTitleUpdated); } @@ -188,13 +178,6 @@ void ResourceCoordinatorWebContentsObserver::DidUpdateFaviconURL( first_time_favicon_set_ = true; return; } - // Ignore update when the tab is in foreground or the update happens within 5 - // minutes after the main frame is committed. - if (web_contents()->IsVisible() || - base::TimeTicks::Now() - navigation_finished_time_ < - kFaviconAndTitleUpdateIgnoredTimeout) { - return; - } tab_resource_coordinator_->SendEvent( resource_coordinator::mojom::Event::kFaviconUpdated); } diff --git a/chrome/browser/resource_coordinator/resource_coordinator_web_contents_observer.h b/chrome/browser/resource_coordinator/resource_coordinator_web_contents_observer.h index 08512bc64277..3365c8e5a8be 100644 --- a/chrome/browser/resource_coordinator/resource_coordinator_web_contents_observer.h +++ b/chrome/browser/resource_coordinator/resource_coordinator_web_contents_observer.h @@ -61,12 +61,6 @@ class ResourceCoordinatorWebContentsObserver tab_resource_coordinator_; ukm::SourceId ukm_source_id_; - // We only want to send signals to GRC 5 minutes after the main frame is - // committed. Thus we record the time when navigation of main frame is - // finished, when title/favicon is changed, we check whether it's already more - // than 5 minutes from the time navigation of main frame is finished. - base::TimeTicks navigation_finished_time_; - // Favicon and title are set when a page is loaded, we only want to send // signals to GRC about title and favicon update from the previous title and // favicon, thus we want to ignore the very first update since it is always diff --git a/services/resource_coordinator/BUILD.gn b/services/resource_coordinator/BUILD.gn index 757fb909c11a..6e363bd1fdab 100644 --- a/services/resource_coordinator/BUILD.gn +++ b/services/resource_coordinator/BUILD.gn @@ -12,6 +12,7 @@ import("//services/service_manager/public/tools/test/service_test.gni") source_set("lib") { sources = [ + "coordination_unit/background_metrics_reporter.h", "coordination_unit/coordination_unit_graph_observer.cc", "coordination_unit/coordination_unit_graph_observer.h", "coordination_unit/coordination_unit_impl.cc", diff --git a/services/resource_coordinator/coordination_unit/background_metrics_reporter.h b/services/resource_coordinator/coordination_unit/background_metrics_reporter.h new file mode 100644 index 000000000000..a2692a6496da --- /dev/null +++ b/services/resource_coordinator/coordination_unit/background_metrics_reporter.h @@ -0,0 +1,136 @@ +// 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. + +#ifndef SERVICES_RESOURCE_COORDINATOR_COORDINATION_UNIT_BACKGROUND_METRICS_REPORTER_H_ +#define SERVICES_RESOURCE_COORDINATOR_COORDINATION_UNIT_BACKGROUND_METRICS_REPORTER_H_ + +#include "base/macros.h" +#include "base/metrics/histogram_macros.h" +#include "base/time/time.h" +#include "services/metrics/public/cpp/ukm_builders.h" + +// Tabs can be kept in the background for a long time, metrics show 75th +// percentile of time spent in background is 2.5 hours, and the 95th is 24 hour. +// In order to guide the selection of an appropriate observation window we are +// proposing using a CUSTOM_TIMES histogram from 1s to 48h, with 100 buckets. +#define HEURISTICS_HISTOGRAM(name, sample) \ + UMA_HISTOGRAM_CUSTOM_TIMES(name, sample, base::TimeDelta::FromSeconds(1), \ + base::TimeDelta::FromHours(48), 100) + +namespace ukm { +class MojoUkmRecorder; +} // namespace ukm + +namespace resource_coordinator { + +namespace internal { + +enum UKMFrameReportType : uint8_t { + kMainFrameOnly = 0, + kMainFrameAndChildFrame +}; + +template +class UKMReportDelegate {}; + +template +class UKMReportDelegate { + public: + void ReportUKM(int64_t ukm_source_id, + bool is_main_frame, + int64_t duration_in_ms, + ukm::MojoUkmRecorder* ukm_recorder) { + UKMBuilderClass ukm_builder(ukm_source_id); + ukm_builder.SetTimeFromBackgrounded(duration_in_ms).Record(ukm_recorder); + } +}; + +template +class UKMReportDelegate { + public: + void ReportUKM(int64_t ukm_source_id, + bool is_main_frame, + int64_t duration_in_ms, + ukm::MojoUkmRecorder* ukm_recorder) { + UKMBuilderClass ukm_builder(ukm_source_id); + ukm_builder.SetIsMainFrame(is_main_frame) + .SetTimeFromBackgrounded(duration_in_ms) + .Record(ukm_recorder); + } +}; + +} // namespace internal + +template +class BackgroundMetricsReporter { + public: + BackgroundMetricsReporter() + : ukm_source_id_(-1), + uma_reported_(false), + ukm_reported_(false), + child_frame_ukm_reported_(false) {} + + void Reset() { + uma_reported_ = false; + ukm_reported_ = false; + child_frame_ukm_reported_ = false; + } + + void SetUKMSourceID(int64_t ukm_source_id) { ukm_source_id_ = ukm_source_id; } + + void OnSignalReceived(bool is_main_frame, + base::TimeDelta duration, + ukm::MojoUkmRecorder* ukm_recorder) { + if (!uma_reported_) { + uma_reported_ = true; + HEURISTICS_HISTOGRAM(kMetricName, duration); + } + + ReportUKMIfNeeded(is_main_frame, duration, ukm_recorder); + } + + private: + void ReportUKMIfNeeded(bool is_main_frame, + base::TimeDelta duration, + ukm::MojoUkmRecorder* ukm_recorder) { + if (ukm_source_id_ == -1 || + (!kShouldReportChildFrameUkm && ukm_reported_) || + (kShouldReportChildFrameUkm && + !ShouldReportMainFrameUKM(is_main_frame) && + !ShouldReportChildFrameUKM(is_main_frame))) { + return; + } + + ukm_reporter_.ReportUKM(ukm_source_id_, is_main_frame, + duration.InMilliseconds(), ukm_recorder); + + if (is_main_frame) { + ukm_reported_ = true; + } else { + child_frame_ukm_reported_ = true; + } + } + + bool ShouldReportMainFrameUKM(bool is_main_frame) const { + return is_main_frame && !ukm_reported_; + } + + bool ShouldReportChildFrameUKM(bool is_main_frame) const { + return !is_main_frame && !child_frame_ukm_reported_; + } + + int64_t ukm_source_id_; + bool uma_reported_; + bool ukm_reported_; + bool child_frame_ukm_reported_; + internal::UKMReportDelegate + ukm_reporter_; +}; + +} // namespace resource_coordinator + +#endif // SERVICES_RESOURCE_COORDINATOR_COORDINATION_UNIT_BACKGROUND_METRICS_REPORTER_H_ diff --git a/services/resource_coordinator/coordination_unit/coordination_unit_impl.cc b/services/resource_coordinator/coordination_unit/coordination_unit_impl.cc index 69c23850dc45..f1a61a1df2fd 100644 --- a/services/resource_coordinator/coordination_unit/coordination_unit_impl.cc +++ b/services/resource_coordinator/coordination_unit/coordination_unit_impl.cc @@ -43,6 +43,14 @@ CoordinationUnitImpl::ToWebContentsCoordinationUnit( return static_cast(coordination_unit); } +// static +const WebContentsCoordinationUnitImpl* +CoordinationUnitImpl::ToWebContentsCoordinationUnit( + const CoordinationUnitImpl* cu) { + DCHECK(cu->id().type == CoordinationUnitType::kWebContents); + return static_cast(cu); +} + // static std::vector CoordinationUnitImpl::GetCoordinationUnitsOfType(CoordinationUnitType type) { diff --git a/services/resource_coordinator/coordination_unit/coordination_unit_impl.h b/services/resource_coordinator/coordination_unit/coordination_unit_impl.h index b12959c740b5..4bac3b53ac5d 100644 --- a/services/resource_coordinator/coordination_unit/coordination_unit_impl.h +++ b/services/resource_coordinator/coordination_unit/coordination_unit_impl.h @@ -38,6 +38,8 @@ class CoordinationUnitImpl : public mojom::CoordinationUnit { const CoordinationUnitImpl* coordination_unit); static WebContentsCoordinationUnitImpl* ToWebContentsCoordinationUnit( CoordinationUnitImpl* coordination_unit); + static const WebContentsCoordinationUnitImpl* ToWebContentsCoordinationUnit( + const CoordinationUnitImpl* coordination_unit); static std::vector GetCoordinationUnitsOfType( CoordinationUnitType type); diff --git a/services/resource_coordinator/coordination_unit/metrics_collector.cc b/services/resource_coordinator/coordination_unit/metrics_collector.cc index 155d4360b963..d0ec87e53833 100644 --- a/services/resource_coordinator/coordination_unit/metrics_collector.cc +++ b/services/resource_coordinator/coordination_unit/metrics_collector.cc @@ -5,7 +5,6 @@ #include "services/resource_coordinator/coordination_unit/metrics_collector.h" #include "base/metrics/histogram_macros.h" -#include "base/strings/string_number_conversions.h" #include "services/resource_coordinator/coordination_unit/coordination_unit_impl.h" #include "services/resource_coordinator/coordination_unit/coordination_unit_manager.h" #include "services/resource_coordinator/coordination_unit/frame_coordination_unit_impl.h" @@ -25,7 +24,13 @@ namespace resource_coordinator { const size_t kDefaultMaxCPUUsageMeasurements = 30u; -constexpr base::TimeDelta kMaxAudioSlientTime = base::TimeDelta::FromMinutes(1); +// Audio is considered to have started playing if the tab has never +// previously played audio, or has been silent for at least one minute. +const base::TimeDelta kMaxAudioSlientTimeout = base::TimeDelta::FromMinutes(1); +// Delay the metrics report from GRC to UMA/UKM for 5 minutes from when the main +// frame navigation is committed. +const base::TimeDelta kMetricsReportDelayTimeout = + base::TimeDelta::FromMinutes(5); const char kTabFromBackgroundedToFirstAlertFiredUMA[] = "TabManager.Heuristics.FromBackgroundedToFirstAlertFired"; @@ -71,6 +76,14 @@ bool MetricsCollector::ShouldObserve( coordination_unit->id().type == CoordinationUnitType::kWebContents; } +void MetricsCollector::OnCoordinationUnitCreated( + const CoordinationUnitImpl* coordination_unit) { + if (coordination_unit->id().type == CoordinationUnitType::kWebContents) { + metrics_report_record_map_.emplace(coordination_unit->id(), + MetricsReportRecord()); + } +} + void MetricsCollector::OnBeforeCoordinationUnitDestroyed( const CoordinationUnitImpl* coordination_unit) { if (coordination_unit->id().type == CoordinationUnitType::kFrame) { @@ -96,31 +109,22 @@ void MetricsCollector::OnFramePropertyChanged( } auto* web_contents_cu = frame_cu->GetWebContentsCoordinationUnit(); // Only record metrics while it is backgrounded. - if (!web_contents_cu || web_contents_cu->IsVisible()) + if (!web_contents_cu || web_contents_cu->IsVisible() || + !ShouldReportMetrics(web_contents_cu)) { return; + } // Audio is considered to have started playing if the tab has never // previously played audio, or has been silent for at least one minute. auto now = clock_->NowTicks(); - if (frame_data.last_audible_time + kMaxAudioSlientTime < now) { + if (frame_data.last_audible_time + kMaxAudioSlientTimeout < now) { MetricsReportRecord& record = - metrics_report_record_map_[web_contents_cu->id()]; + metrics_report_record_map_.find(web_contents_cu->id())->second; auto duration = now - web_contents_data_map_[web_contents_cu->id()].last_invisible_time; - - if (!record.first_audible_after_backgrounded_reported) { - HEURISTICS_HISTOGRAM(kTabFromBackgroundedToFirstAudioStartsUMA, - duration); - record.first_audible_after_backgrounded_reported = true; - } - - bool is_main_frame = frame_cu->IsMainFrame(); - ReportAudibilityUKMIfNeeded( - web_contents_cu, - is_main_frame - ? &record.main_frame_first_audible_after_backgrounded_reported - : &record.child_frame_first_audible_after_backgrounded_reported, - is_main_frame, duration); + record.first_audible.OnSignalReceived( + frame_cu->IsMainFrame(), duration, + coordination_unit_manager().ukm_recorder()); } } } @@ -147,8 +151,10 @@ void MetricsCollector::OnWebContentsPropertyChanged( } } else if (property_type == mojom::PropertyType::kUKMSourceId) { ukm::SourceId ukm_source_id = value; - UpdateUkmSourceIdForWebContents(web_contents_cu_id, ukm_source_id); + MetricsReportRecord& record = + metrics_report_record_map_.find(web_contents_cu_id)->second; + record.UpdateUKMSourceID(ukm_source_id); } } @@ -158,37 +164,33 @@ void MetricsCollector::OnFrameEventReceived( if (event == mojom::Event::kAlertFired) { auto* web_contents_cu = frame_cu->GetWebContentsCoordinationUnit(); // Only record metrics while it is backgrounded. - if (!web_contents_cu || web_contents_cu->IsVisible()) + if (!web_contents_cu || web_contents_cu->IsVisible() || + !ShouldReportMetrics(web_contents_cu)) { return; - auto now = clock_->NowTicks(); - MetricsReportRecord& record = - metrics_report_record_map_[web_contents_cu->id()]; - if (!record.first_alert_fired_after_backgrounded_reported) { - const WebContentsData& web_contents_data = - web_contents_data_map_[web_contents_cu->id()]; - HEURISTICS_HISTOGRAM(kTabFromBackgroundedToFirstAlertFiredUMA, - now - web_contents_data.last_invisible_time); - record.first_alert_fired_after_backgrounded_reported = true; } + auto duration = + clock_->NowTicks() - + web_contents_data_map_[web_contents_cu->id()].last_invisible_time; + MetricsReportRecord& record = + metrics_report_record_map_.find(web_contents_cu->id())->second; + record.first_alert_fired.OnSignalReceived( + frame_cu->IsMainFrame(), duration, + coordination_unit_manager().ukm_recorder()); } else if (event == mojom::Event::kNonPersistentNotificationCreated) { auto* web_contents_cu = frame_cu->GetWebContentsCoordinationUnit(); // Only record metrics while it is backgrounded. - if (!web_contents_cu || web_contents_cu->IsVisible()) + if (!web_contents_cu || web_contents_cu->IsVisible() || + !ShouldReportMetrics(web_contents_cu)) { return; - auto now = clock_->NowTicks(); - MetricsReportRecord& record = - metrics_report_record_map_[web_contents_cu->id()]; - if (!record - .first_non_persistent_notification_created_after_backgrounded_reported) { - const WebContentsData web_contents_data = - web_contents_data_map_[web_contents_cu->id()]; - HEURISTICS_HISTOGRAM( - kTabFromBackgroundedToFirstNonPersistentNotificationCreatedUMA, - now - web_contents_data.last_invisible_time); - record - .first_non_persistent_notification_created_after_backgrounded_reported = - true; } + auto duration = + clock_->NowTicks() - + web_contents_data_map_[web_contents_cu->id()].last_invisible_time; + MetricsReportRecord& record = + metrics_report_record_map_.find(web_contents_cu->id())->second; + record.first_non_persistent_notification_created.OnSignalReceived( + frame_cu->IsMainFrame(), duration, + coordination_unit_manager().ukm_recorder()); } } @@ -197,35 +199,39 @@ void MetricsCollector::OnWebContentsEventReceived( const mojom::Event event) { if (event == mojom::Event::kTitleUpdated) { // Only record metrics while it is backgrounded. - if (web_contents_cu->IsVisible()) + if (web_contents_cu->IsVisible() || !ShouldReportMetrics(web_contents_cu)) return; - auto now = clock_->NowTicks(); + auto duration = + clock_->NowTicks() - + web_contents_data_map_[web_contents_cu->id()].last_invisible_time; MetricsReportRecord& record = - metrics_report_record_map_[web_contents_cu->id()]; - if (!record.first_title_updated_after_backgrounded_reported) { - const WebContentsData& web_contents_data = - web_contents_data_map_[web_contents_cu->id()]; - HEURISTICS_HISTOGRAM(kTabFromBackgroundedToFirstTitleUpdatedUMA, - now - web_contents_data.last_invisible_time); - record.first_title_updated_after_backgrounded_reported = true; - } + metrics_report_record_map_.find(web_contents_cu->id())->second; + record.first_title_updated.OnSignalReceived( + true, duration, coordination_unit_manager().ukm_recorder()); } else if (event == mojom::Event::kFaviconUpdated) { // Only record metrics while it is backgrounded. - if (web_contents_cu->IsVisible()) + if (web_contents_cu->IsVisible() || !ShouldReportMetrics(web_contents_cu)) return; - auto now = clock_->NowTicks(); + auto duration = + clock_->NowTicks() - + web_contents_data_map_[web_contents_cu->id()].last_invisible_time; MetricsReportRecord& record = - metrics_report_record_map_[web_contents_cu->id()]; - if (!record.first_favicon_updated_after_backgrounded_reported) { - const WebContentsData& web_contents_data = - web_contents_data_map_[web_contents_cu->id()]; - HEURISTICS_HISTOGRAM(kTabFromBackgroundedToFirstFaviconUpdatedUMA, - now - web_contents_data.last_invisible_time); - record.first_favicon_updated_after_backgrounded_reported = true; - } + metrics_report_record_map_.find(web_contents_cu->id())->second; + record.first_favicon_updated.OnSignalReceived( + true, duration, coordination_unit_manager().ukm_recorder()); + } else if (event == mojom::Event::kNavigationCommitted) { + web_contents_data_map_[web_contents_cu->id()].navigation_finished_time = + clock_->NowTicks(); } } +bool MetricsCollector::ShouldReportMetrics( + const WebContentsCoordinationUnitImpl* web_contents_cu) { + return clock_->NowTicks() - web_contents_data_map_[web_contents_cu->id()] + .navigation_finished_time > + kMetricsReportDelayTimeout; +} + bool MetricsCollector::IsCollectingCPUUsageForUkm( const CoordinationUnitID& web_contents_cu_id) { UkmCPUUsageCollectionState& state = @@ -249,25 +255,6 @@ void MetricsCollector::RecordCPUUsageForUkm( .Record(coordination_unit_manager().ukm_recorder()); } -void MetricsCollector::ReportAudibilityUKMIfNeeded( - const WebContentsCoordinationUnitImpl* web_contents_cu, - bool* reported, - bool is_main_frame, - base::TimeDelta duration) { - if (*reported) - return; - int64_t ukm_source_id = -1; - if (!web_contents_cu->GetProperty(mojom::PropertyType::kUKMSourceId, - &ukm_source_id)) { - return; - } - ukm::builders::TabManager_Background_FirstAudioStarts(ukm_source_id) - .SetIsMainFrame(is_main_frame) - .SetTimeFromBackgrounded(duration.InMilliseconds()) - .Record(coordination_unit_manager().ukm_recorder()); - *reported = true; -} - void MetricsCollector::UpdateUkmSourceIdForWebContents( const CoordinationUnitID& web_contents_cu_id, ukm::SourceId ukm_source_id) { @@ -290,30 +277,31 @@ void MetricsCollector::UpdateWithFieldTrialParams() { } void MetricsCollector::ResetMetricsReportRecord(CoordinationUnitID cu_id) { - auto metrics_report_record_iter = metrics_report_record_map_.find(cu_id); - if (metrics_report_record_iter == metrics_report_record_map_.end()) - return; - metrics_report_record_iter->second.Reset(); + DCHECK(metrics_report_record_map_.find(cu_id) != + metrics_report_record_map_.end()); + metrics_report_record_map_.find(cu_id)->second.Reset(); } -MetricsCollector::MetricsReportRecord::MetricsReportRecord() - : first_alert_fired_after_backgrounded_reported(false), - first_audible_after_backgrounded_reported(false), - first_favicon_updated_after_backgrounded_reported(false), - first_non_persistent_notification_created_after_backgrounded_reported( - false), - first_title_updated_after_backgrounded_reported(false), - main_frame_first_audible_after_backgrounded_reported(false), - child_frame_first_audible_after_backgrounded_reported(false) {} +MetricsCollector::MetricsReportRecord::MetricsReportRecord() = default; + +MetricsCollector::MetricsReportRecord::MetricsReportRecord( + const MetricsReportRecord& other) = default; + +void MetricsCollector::MetricsReportRecord::UpdateUKMSourceID( + int64_t ukm_source_id) { + first_alert_fired.SetUKMSourceID(ukm_source_id); + first_audible.SetUKMSourceID(ukm_source_id); + first_favicon_updated.SetUKMSourceID(ukm_source_id); + first_non_persistent_notification_created.SetUKMSourceID(ukm_source_id); + first_title_updated.SetUKMSourceID(ukm_source_id); +} void MetricsCollector::MetricsReportRecord::Reset() { - first_alert_fired_after_backgrounded_reported = false; - first_audible_after_backgrounded_reported = false; - first_favicon_updated_after_backgrounded_reported = false; - first_non_persistent_notification_created_after_backgrounded_reported = false; - first_title_updated_after_backgrounded_reported = false; - main_frame_first_audible_after_backgrounded_reported = false; - child_frame_first_audible_after_backgrounded_reported = false; + first_alert_fired.Reset(); + first_audible.Reset(); + first_favicon_updated.Reset(); + first_non_persistent_notification_created.Reset(); + first_title_updated.Reset(); } } // namespace resource_coordinator diff --git a/services/resource_coordinator/coordination_unit/metrics_collector.h b/services/resource_coordinator/coordination_unit/metrics_collector.h index d9a11a525c95..16c6eed29bc9 100644 --- a/services/resource_coordinator/coordination_unit/metrics_collector.h +++ b/services/resource_coordinator/coordination_unit/metrics_collector.h @@ -6,9 +6,11 @@ #define SERVICES_RESOURCE_COORDINATOR_COORDINATION_UNIT_METRICS_COLLECTOR_H_ #include "base/macros.h" +#include "base/metrics/histogram_macros.h" #include "base/time/default_tick_clock.h" #include "base/time/time.h" #include "services/metrics/public/cpp/ukm_builders.h" +#include "services/resource_coordinator/coordination_unit/background_metrics_reporter.h" #include "services/resource_coordinator/coordination_unit/coordination_unit_graph_observer.h" namespace resource_coordinator { @@ -23,6 +25,8 @@ extern const char kTabFromBackgroundedToFirstFaviconUpdatedUMA[]; extern const char kTabFromBackgroundedToFirstTitleUpdatedUMA[]; extern const char kTabFromBackgroundedToFirstNonPersistentNotificationCreatedUMA[]; +extern const base::TimeDelta kMaxAudioSlientTimeout; +extern const base::TimeDelta kMetricsReportDelayTimeout; // A MetricsCollector observes changes happened inside CoordinationUnit Graph, // and reports UMA/UKM. @@ -33,6 +37,8 @@ class MetricsCollector : public CoordinationUnitGraphObserver { // CoordinationUnitGraphObserver implementation. bool ShouldObserve(const CoordinationUnitImpl* coordination_unit) override; + void OnCoordinationUnitCreated( + const CoordinationUnitImpl* coordination_unit) override; void OnBeforeCoordinationUnitDestroyed( const CoordinationUnitImpl* coordination_unit) override; void OnFramePropertyChanged(const FrameCoordinationUnitImpl* frame_cu, @@ -53,17 +59,35 @@ class MetricsCollector : public CoordinationUnitGraphObserver { struct MetricsReportRecord { MetricsReportRecord(); + MetricsReportRecord(const MetricsReportRecord& other); + void UpdateUKMSourceID(int64_t ukm_source_id); void Reset(); - // UMA histograms report. - bool first_alert_fired_after_backgrounded_reported; - bool first_audible_after_backgrounded_reported; - bool first_favicon_updated_after_backgrounded_reported; - bool first_non_persistent_notification_created_after_backgrounded_reported; - bool first_title_updated_after_backgrounded_reported; - - // UKM collection report. - bool main_frame_first_audible_after_backgrounded_reported; - bool child_frame_first_audible_after_backgrounded_reported; + BackgroundMetricsReporter< + ukm::builders::TabManager_Background_FirstAlertFired, + kTabFromBackgroundedToFirstAlertFiredUMA, + internal::UKMFrameReportType::kMainFrameAndChildFrame> + first_alert_fired; + BackgroundMetricsReporter< + ukm::builders::TabManager_Background_FirstAudioStarts, + kTabFromBackgroundedToFirstAudioStartsUMA, + internal::UKMFrameReportType::kMainFrameAndChildFrame> + first_audible; + BackgroundMetricsReporter< + ukm::builders::TabManager_Background_FirstFaviconUpdated, + kTabFromBackgroundedToFirstFaviconUpdatedUMA, + internal::UKMFrameReportType::kMainFrameOnly> + first_favicon_updated; + BackgroundMetricsReporter< + ukm::builders:: + TabManager_Background_FirstNonPersistentNotificationCreated, + kTabFromBackgroundedToFirstNonPersistentNotificationCreatedUMA, + internal::UKMFrameReportType::kMainFrameAndChildFrame> + first_non_persistent_notification_created; + BackgroundMetricsReporter< + ukm::builders::TabManager_Background_FirstTitleUpdated, + kTabFromBackgroundedToFirstTitleUpdatedUMA, + internal::UKMFrameReportType::kMainFrameOnly> + first_title_updated; }; struct FrameData { @@ -72,6 +96,7 @@ class MetricsCollector : public CoordinationUnitGraphObserver { struct WebContentsData { base::TimeTicks last_invisible_time; + base::TimeTicks navigation_finished_time; }; struct UkmCPUUsageCollectionState { @@ -81,15 +106,12 @@ class MetricsCollector : public CoordinationUnitGraphObserver { ukm::SourceId ukm_source_id = -1; }; + bool ShouldReportMetrics( + const WebContentsCoordinationUnitImpl* web_contents_cu); bool IsCollectingCPUUsageForUkm(const CoordinationUnitID& web_contents_cu_id); void RecordCPUUsageForUkm(const CoordinationUnitID& web_contents_cu_id, double cpu_usage, size_t num_coresident_tabs); - void ReportAudibilityUKMIfNeeded( - const WebContentsCoordinationUnitImpl* web_contents_cu, - bool* reported, - bool is_main_frame, - base::TimeDelta duration); void UpdateUkmSourceIdForWebContents( const CoordinationUnitID& web_contents_cu_id, ukm::SourceId ukm_source_id); diff --git a/services/resource_coordinator/coordination_unit/metrics_collector_unittest.cc b/services/resource_coordinator/coordination_unit/metrics_collector_unittest.cc index 1dca002508af..9c6a70f267e6 100644 --- a/services/resource_coordinator/coordination_unit/metrics_collector_unittest.cc +++ b/services/resource_coordinator/coordination_unit/metrics_collector_unittest.cc @@ -4,16 +4,22 @@ #include "services/resource_coordinator/coordination_unit/metrics_collector.h" -#include - #include "base/test/histogram_tester.h" #include "base/test/simple_test_tick_clock.h" +#include "build/build_config.h" #include "services/resource_coordinator/coordination_unit/coordination_unit_impl_unittest_util.h" namespace resource_coordinator { +const base::TimeDelta kTestMetricsReportDelayTimeout = + kMetricsReportDelayTimeout + base::TimeDelta::FromSeconds(1); +const base::TimeDelta kTestMaxAudioSlientTimeout = + kMaxAudioSlientTimeout + base::TimeDelta::FromSeconds(1); + class MetricsCollectorTest : public CoordinationUnitImplTestBase { public: + MetricsCollectorTest() : CoordinationUnitImplTestBase() {} + void SetUp() override { MetricsCollector* metrics_collector = new MetricsCollector(); const_cast(metrics_collector->clock_) = &clock_; @@ -26,20 +32,31 @@ class MetricsCollectorTest : public CoordinationUnitImplTestBase { base::HistogramTester histogram_tester_; base::SimpleTestTickClock clock_; -}; -TEST_F(MetricsCollectorTest, FromBackgroundedToFirstAudioStartsUMA) { - CoordinationUnitID tab_cu_id(CoordinationUnitType::kWebContents, - std::string()); - CoordinationUnitID frame_cu_id(CoordinationUnitType::kFrame, std::string()); + private: + DISALLOW_COPY_AND_ASSIGN(MetricsCollectorTest); +}; - auto web_contents_cu = CreateCoordinationUnit(tab_cu_id); - auto frame_cu = CreateCoordinationUnit(frame_cu_id); +// TODO(crbug.com/759905) Enable on Windows once this bug is fixed. +#if defined(OS_WIN) +#define MAYBE_FromBackgroundedToFirstAudioStartsUMA \ + DISABLED_FromBackgroundedToFirstAudioStartsUMA +#else +#define MAYBE_FromBackgroundedToFirstAudioStartsUMA \ + FromBackgroundedToFirstAudioStartsUMA +#endif +TEST_F(MetricsCollectorTest, MAYBE_FromBackgroundedToFirstAudioStartsUMA) { + auto web_contents_cu = + CreateCoordinationUnit(CoordinationUnitType::kWebContents); + auto frame_cu = CreateCoordinationUnit(CoordinationUnitType::kFrame); coordination_unit_manager().OnCoordinationUnitCreated(web_contents_cu.get()); coordination_unit_manager().OnCoordinationUnitCreated(frame_cu.get()); web_contents_cu->AddChild(frame_cu->id()); + web_contents_cu->SendEvent(mojom::Event::kNavigationCommitted); + AdvanceClock(kTestMetricsReportDelayTimeout); + web_contents_cu->SetProperty(mojom::PropertyType::kVisible, true); frame_cu->SetProperty(mojom::PropertyType::kAudible, true); // The tab is not backgrounded, thus no metrics recorded. @@ -54,7 +71,7 @@ TEST_F(MetricsCollectorTest, FromBackgroundedToFirstAudioStartsUMA) { 0); frame_cu->SetProperty(mojom::PropertyType::kAudible, false); - AdvanceClock(base::TimeDelta::FromMinutes(1)); + AdvanceClock(kTestMaxAudioSlientTimeout); web_contents_cu->SetProperty(mojom::PropertyType::kVisible, true); frame_cu->SetProperty(mojom::PropertyType::kAudible, true); // The tab was not recently audible but it is not backgrounded, thus no @@ -64,60 +81,71 @@ TEST_F(MetricsCollectorTest, FromBackgroundedToFirstAudioStartsUMA) { frame_cu->SetProperty(mojom::PropertyType::kAudible, false); web_contents_cu->SetProperty(mojom::PropertyType::kVisible, false); - AdvanceClock(base::TimeDelta::FromSeconds(61)); + AdvanceClock(kTestMaxAudioSlientTimeout); frame_cu->SetProperty(mojom::PropertyType::kAudible, true); // The tab was not recently audible and it is backgrounded, thus metrics // recorded. histogram_tester_.ExpectTotalCount(kTabFromBackgroundedToFirstAudioStartsUMA, 1); -} + frame_cu->SetProperty(mojom::PropertyType::kAudible, false); -TEST_F(MetricsCollectorTest, ReportMetricsOneTimeOnlyPerBackgrounded) { - CoordinationUnitID tab_cu_id(CoordinationUnitType::kWebContents, - std::string()); - CoordinationUnitID frame_cu_id(CoordinationUnitType::kFrame, std::string()); + web_contents_cu->SetProperty(mojom::PropertyType::kVisible, true); + web_contents_cu->SetProperty(mojom::PropertyType::kVisible, false); + AdvanceClock(kTestMaxAudioSlientTimeout); + frame_cu->SetProperty(mojom::PropertyType::kAudible, true); + // The tab becomes visible and then invisible again, thus metrics recorded. + histogram_tester_.ExpectTotalCount(kTabFromBackgroundedToFirstAudioStartsUMA, + 2); +} - auto web_contents_cu = CreateCoordinationUnit(tab_cu_id); - auto frame_cu = CreateCoordinationUnit(frame_cu_id); +// TODO(crbug.com/759905) Enable on Windows once this bug is fixed. +#if defined(OS_WIN) +#define MAYBE_FromBackgroundedToFirstAudioStartsUMA5MinutesTimeout \ + DISABLED_FromBackgroundedToFirstAudioStartsUMA5MinutesTimeout +#else +#define MAYBE_FromBackgroundedToFirstAudioStartsUMA5MinutesTimeout \ + FromBackgroundedToFirstAudioStartsUMA5MinutesTimeout +#endif +TEST_F(MetricsCollectorTest, + MAYBE_FromBackgroundedToFirstAudioStartsUMA5MinutesTimeout) { + auto web_contents_cu = + CreateCoordinationUnit(CoordinationUnitType::kWebContents); + auto frame_cu = CreateCoordinationUnit(CoordinationUnitType::kFrame); coordination_unit_manager().OnCoordinationUnitCreated(web_contents_cu.get()); coordination_unit_manager().OnCoordinationUnitCreated(frame_cu.get()); web_contents_cu->AddChild(frame_cu->id()); web_contents_cu->SetProperty(mojom::PropertyType::kVisible, false); - - frame_cu->SetProperty(mojom::PropertyType::kAudible, false); - AdvanceClock(base::TimeDelta::FromSeconds(61)); + web_contents_cu->SendEvent(mojom::Event::kNavigationCommitted); frame_cu->SetProperty(mojom::PropertyType::kAudible, true); - // The tab was not recently audible and it is backgrounded, thus metrics - // recorded. + // The tab is within 5 minutes after main frame navigation was committed, thus + // no metrics recorded. histogram_tester_.ExpectTotalCount(kTabFromBackgroundedToFirstAudioStartsUMA, - 1); - + 0); frame_cu->SetProperty(mojom::PropertyType::kAudible, false); - AdvanceClock(base::TimeDelta::FromSeconds(61)); + AdvanceClock(kTestMetricsReportDelayTimeout); frame_cu->SetProperty(mojom::PropertyType::kAudible, true); - // Only record the metrics once. histogram_tester_.ExpectTotalCount(kTabFromBackgroundedToFirstAudioStartsUMA, 1); - - web_contents_cu->SetProperty(mojom::PropertyType::kVisible, true); - web_contents_cu->SetProperty(mojom::PropertyType::kVisible, false); - frame_cu->SetProperty(mojom::PropertyType::kAudible, false); - AdvanceClock(base::TimeDelta::FromSeconds(61)); - frame_cu->SetProperty(mojom::PropertyType::kAudible, true); - // The tab becomes visible and then invisible again, thus metrics recorded. - histogram_tester_.ExpectTotalCount(kTabFromBackgroundedToFirstAudioStartsUMA, - 2); } -TEST_F(MetricsCollectorTest, FromBackgroundedToFirstTitleUpdatedUMA) { - CoordinationUnitID tab_cu_id(CoordinationUnitType::kWebContents, - std::string()); - - auto web_contents_cu = CreateCoordinationUnit(tab_cu_id); +// TODO(crbug.com/759905) Enable on Windows once this bug is fixed. +#if defined(OS_WIN) +#define MAYBE_FromBackgroundedToFirstTitleUpdatedUMA \ + DISABLED_FromBackgroundedToFirstTitleUpdatedUMA +#else +#define MAYBE_FromBackgroundedToFirstTitleUpdatedUMA \ + FromBackgroundedToFirstTitleUpdatedUMA +#endif +TEST_F(MetricsCollectorTest, MAYBE_FromBackgroundedToFirstTitleUpdatedUMA) { + auto web_contents_cu = + CreateCoordinationUnit(CoordinationUnitType::kWebContents); coordination_unit_manager().OnCoordinationUnitCreated(web_contents_cu.get()); + web_contents_cu->SendEvent(mojom::Event::kNavigationCommitted); + AdvanceClock(kTestMetricsReportDelayTimeout); + web_contents_cu->SetProperty(mojom::PropertyType::kVisible, true); web_contents_cu->SendEvent(mojom::Event::kTitleUpdated); // The tab is not backgrounded, thus no metrics recorded. @@ -143,17 +171,52 @@ TEST_F(MetricsCollectorTest, FromBackgroundedToFirstTitleUpdatedUMA) { 2); } -TEST_F(MetricsCollectorTest, FromBackgroundedToFirstAlertFiredUMA) { - CoordinationUnitID tab_cu_id(CoordinationUnitType::kWebContents, - std::string()); - CoordinationUnitID frame_cu_id(CoordinationUnitType::kFrame, std::string()); +// TODO(crbug.com/759905) Enable on Windows once this bug is fixed. +#if defined(OS_WIN) +#define MAYBE_FromBackgroundedToFirstTitleUpdatedUMA5MinutesTimeout \ + DISABLED_FromBackgroundedToFirstTitleUpdatedUMA5MinutesTimeout +#else +#define MAYBE_FromBackgroundedToFirstTitleUpdatedUMA5MinutesTimeout \ + FromBackgroundedToFirstTitleUpdatedUMA5MinutesTimeout +#endif +TEST_F(MetricsCollectorTest, + MAYBE_FromBackgroundedToFirstTitleUpdatedUMA5MinutesTimeout) { + auto web_contents_cu = + CreateCoordinationUnit(CoordinationUnitType::kWebContents); + coordination_unit_manager().OnCoordinationUnitCreated(web_contents_cu.get()); + + web_contents_cu->SendEvent(mojom::Event::kNavigationCommitted); + web_contents_cu->SetProperty(mojom::PropertyType::kVisible, false); + web_contents_cu->SendEvent(mojom::Event::kTitleUpdated); + // The tab is within 5 minutes after main frame navigation was committed, thus + // no metrics recorded. + histogram_tester_.ExpectTotalCount(kTabFromBackgroundedToFirstTitleUpdatedUMA, + 0); + AdvanceClock(kTestMetricsReportDelayTimeout); + web_contents_cu->SendEvent(mojom::Event::kTitleUpdated); + histogram_tester_.ExpectTotalCount(kTabFromBackgroundedToFirstTitleUpdatedUMA, + 1); +} - auto web_contents_cu = CreateCoordinationUnit(tab_cu_id); - auto frame_cu = CreateCoordinationUnit(frame_cu_id); +// TODO(crbug.com/759905) Enable on Windows once this bug is fixed. +#if defined(OS_WIN) +#define MAYBE_FromBackgroundedToFirstAlertFiredUMA \ + DISABLED_FromBackgroundedToFirstAlertFiredUMA +#else +#define MAYBE_FromBackgroundedToFirstAlertFiredUMA \ + FromBackgroundedToFirstAlertFiredUMA +#endif +TEST_F(MetricsCollectorTest, MAYBE_FromBackgroundedToFirstAlertFiredUMA) { + auto web_contents_cu = + CreateCoordinationUnit(CoordinationUnitType::kWebContents); + auto frame_cu = CreateCoordinationUnit(CoordinationUnitType::kFrame); coordination_unit_manager().OnCoordinationUnitCreated(web_contents_cu.get()); coordination_unit_manager().OnCoordinationUnitCreated(frame_cu.get()); web_contents_cu->AddChild(frame_cu->id()); + web_contents_cu->SendEvent(mojom::Event::kNavigationCommitted); + AdvanceClock(kTestMetricsReportDelayTimeout); + web_contents_cu->SetProperty(mojom::PropertyType::kVisible, true); frame_cu->SendEvent(mojom::Event::kAlertFired); // The tab is not backgrounded, thus no metrics recorded. @@ -179,18 +242,56 @@ TEST_F(MetricsCollectorTest, FromBackgroundedToFirstAlertFiredUMA) { 2); } +// TODO(crbug.com/759905) Enable on Windows once this bug is fixed. +#if defined(OS_WIN) +#define MAYBE_FromBackgroundedToFirstAlertFiredUMA5MinutesTimeout \ + DISABLED_FromBackgroundedToFirstAlertFiredUMA5MinutesTimeout +#else +#define MAYBE_FromBackgroundedToFirstAlertFiredUMA5MinutesTimeout \ + FromBackgroundedToFirstAlertFiredUMA5MinutesTimeout +#endif TEST_F(MetricsCollectorTest, - FromBackgroundedToFirstNonPersistentNotificationCreatedUMA) { - CoordinationUnitID tab_cu_id(CoordinationUnitType::kWebContents, - std::string()); - CoordinationUnitID frame_cu_id(CoordinationUnitType::kFrame, std::string()); + MAYBE_FromBackgroundedToFirstAlertFiredUMA5MinutesTimeout) { + auto web_contents_cu = + CreateCoordinationUnit(CoordinationUnitType::kWebContents); + auto frame_cu = CreateCoordinationUnit(CoordinationUnitType::kFrame); + coordination_unit_manager().OnCoordinationUnitCreated(web_contents_cu.get()); + coordination_unit_manager().OnCoordinationUnitCreated(frame_cu.get()); + web_contents_cu->AddChild(frame_cu->id()); - auto web_contents_cu = CreateCoordinationUnit(tab_cu_id); - auto frame_cu = CreateCoordinationUnit(frame_cu_id); + web_contents_cu->SendEvent(mojom::Event::kNavigationCommitted); + web_contents_cu->SetProperty(mojom::PropertyType::kVisible, false); + frame_cu->SendEvent(mojom::Event::kAlertFired); + // The tab is within 5 minutes after main frame navigation was committed, thus + // no metrics recorded. + histogram_tester_.ExpectTotalCount(kTabFromBackgroundedToFirstAlertFiredUMA, + 0); + AdvanceClock(kTestMetricsReportDelayTimeout); + frame_cu->SendEvent(mojom::Event::kAlertFired); + histogram_tester_.ExpectTotalCount(kTabFromBackgroundedToFirstAlertFiredUMA, + 1); +} + +// TODO(crbug.com/759905) Enable on Windows once this bug is fixed. +#if defined(OS_WIN) +#define MAYBE_FromBackgroundedToFirstNonPersistentNotificationCreatedUMA \ + DISABLED_FromBackgroundedToFirstNonPersistentNotificationCreatedUMA +#else +#define MAYBE_FromBackgroundedToFirstNonPersistentNotificationCreatedUMA \ + FromBackgroundedToFirstNonPersistentNotificationCreatedUMA +#endif +TEST_F(MetricsCollectorTest, + MAYBE_FromBackgroundedToFirstNonPersistentNotificationCreatedUMA) { + auto web_contents_cu = + CreateCoordinationUnit(CoordinationUnitType::kWebContents); + auto frame_cu = CreateCoordinationUnit(CoordinationUnitType::kFrame); coordination_unit_manager().OnCoordinationUnitCreated(web_contents_cu.get()); coordination_unit_manager().OnCoordinationUnitCreated(frame_cu.get()); web_contents_cu->AddChild(frame_cu->id()); + web_contents_cu->SendEvent(mojom::Event::kNavigationCommitted); + AdvanceClock(kTestMetricsReportDelayTimeout); + web_contents_cu->SetProperty(mojom::PropertyType::kVisible, true); frame_cu->SendEvent(mojom::Event::kNonPersistentNotificationCreated); // The tab is not backgrounded, thus no metrics recorded. @@ -216,13 +317,53 @@ TEST_F(MetricsCollectorTest, kTabFromBackgroundedToFirstNonPersistentNotificationCreatedUMA, 2); } -TEST_F(MetricsCollectorTest, FromBackgroundedToFirstFaviconUpdatedUMA) { - CoordinationUnitID tab_cu_id(CoordinationUnitType::kWebContents, - std::string()); +// TODO(crbug.com/759905) Enable on Windows once this bug is fixed. +#if defined(OS_WIN) +#define MAYBE_FromBackgroundedToFirstNonPersistentNotificationCreatedUMA5MinutesTimeout \ + DISABLED_FromBackgroundedToFirstNonPersistentNotificationCreatedUMA5MinutesTimeout +#else +#define MAYBE_FromBackgroundedToFirstNonPersistentNotificationCreatedUMA5MinutesTimeout \ + FromBackgroundedToFirstNonPersistentNotificationCreatedUMA5MinutesTimeout +#endif +TEST_F( + MetricsCollectorTest, + MAYBE_FromBackgroundedToFirstNonPersistentNotificationCreatedUMA5MinutesTimeout) { + auto web_contents_cu = + CreateCoordinationUnit(CoordinationUnitType::kWebContents); + auto frame_cu = CreateCoordinationUnit(CoordinationUnitType::kFrame); + coordination_unit_manager().OnCoordinationUnitCreated(web_contents_cu.get()); + coordination_unit_manager().OnCoordinationUnitCreated(frame_cu.get()); + web_contents_cu->AddChild(frame_cu->id()); + + web_contents_cu->SendEvent(mojom::Event::kNavigationCommitted); + web_contents_cu->SetProperty(mojom::PropertyType::kVisible, false); + frame_cu->SendEvent(mojom::Event::kNonPersistentNotificationCreated); + // The tab is within 5 minutes after main frame navigation was committed, thus + // no metrics recorded. + histogram_tester_.ExpectTotalCount( + kTabFromBackgroundedToFirstNonPersistentNotificationCreatedUMA, 0); + AdvanceClock(kTestMetricsReportDelayTimeout); + frame_cu->SendEvent(mojom::Event::kNonPersistentNotificationCreated); + histogram_tester_.ExpectTotalCount( + kTabFromBackgroundedToFirstNonPersistentNotificationCreatedUMA, 1); +} - auto web_contents_cu = CreateCoordinationUnit(tab_cu_id); +// TODO(crbug.com/759905) Enable on Windows once this bug is fixed. +#if defined(OS_WIN) +#define MAYBE_FromBackgroundedToFirstFaviconUpdatedUMA \ + DISABLED_FromBackgroundedToFirstFaviconUpdatedUMA +#else +#define MAYBE_FromBackgroundedToFirstFaviconUpdatedUMA \ + FromBackgroundedToFirstFaviconUpdatedUMA +#endif +TEST_F(MetricsCollectorTest, MAYBE_FromBackgroundedToFirstFaviconUpdatedUMA) { + auto web_contents_cu = + CreateCoordinationUnit(CoordinationUnitType::kWebContents); coordination_unit_manager().OnCoordinationUnitCreated(web_contents_cu.get()); + web_contents_cu->SendEvent(mojom::Event::kNavigationCommitted); + AdvanceClock(kTestMetricsReportDelayTimeout); + web_contents_cu->SetProperty(mojom::PropertyType::kVisible, true); web_contents_cu->SendEvent(mojom::Event::kFaviconUpdated); // The tab is not backgrounded, thus no metrics recorded. @@ -248,4 +389,31 @@ TEST_F(MetricsCollectorTest, FromBackgroundedToFirstFaviconUpdatedUMA) { kTabFromBackgroundedToFirstFaviconUpdatedUMA, 2); } +// TODO(crbug.com/759905) Enable on Windows once this bug is fixed. +#if defined(OS_WIN) +#define MAYBE_FromBackgroundedToFirstFaviconUpdatedUMA5MinutesTimeout \ + DISABLED_FromBackgroundedToFirstFaviconUpdatedUMA5MinutesTimeout +#else +#define MAYBE_FromBackgroundedToFirstFaviconUpdatedUMA5MinutesTimeout \ + FromBackgroundedToFirstFaviconUpdatedUMA5MinutesTimeout +#endif +TEST_F(MetricsCollectorTest, + MAYBE_FromBackgroundedToFirstFaviconUpdatedUMA5MinutesTimeout) { + auto web_contents_cu = + CreateCoordinationUnit(CoordinationUnitType::kWebContents); + coordination_unit_manager().OnCoordinationUnitCreated(web_contents_cu.get()); + + web_contents_cu->SendEvent(mojom::Event::kNavigationCommitted); + web_contents_cu->SetProperty(mojom::PropertyType::kVisible, false); + web_contents_cu->SendEvent(mojom::Event::kFaviconUpdated); + // The tab is within 5 minutes after main frame navigation was committed, thus + // no metrics recorded. + histogram_tester_.ExpectTotalCount( + kTabFromBackgroundedToFirstFaviconUpdatedUMA, 0); + AdvanceClock(kTestMetricsReportDelayTimeout); + web_contents_cu->SendEvent(mojom::Event::kFaviconUpdated); + histogram_tester_.ExpectTotalCount( + kTabFromBackgroundedToFirstFaviconUpdatedUMA, 1); +} + } // namespace resource_coordinator diff --git a/services/resource_coordinator/public/interfaces/signals.mojom b/services/resource_coordinator/public/interfaces/signals.mojom index 295d4b6e7664..bf8aec85e320 100644 --- a/services/resource_coordinator/public/interfaces/signals.mojom +++ b/services/resource_coordinator/public/interfaces/signals.mojom @@ -8,6 +8,8 @@ enum Event { kTestEvent, kAlertFired, kFaviconUpdated, + // This event signal is received when main frame navigation is committed. + kNavigationCommitted, // Only care about non-persistent notifications, notifications launched from // ServiceWorker are persistent and compatible with LifeCycle. kNonPersistentNotificationCreated, diff --git a/tools/metrics/ukm/ukm.xml b/tools/metrics/ukm/ukm.xml index 63eeffb290c8..141af5106297 100644 --- a/tools/metrics/ukm/ukm.xml +++ b/tools/metrics/ukm/ukm.xml @@ -1245,6 +1245,25 @@ be describing additional metrics about the same event. + + chrisha@chromium.org + lpy@chromium.org + + Collects the duration in MS from when the tab is backgrounded to when a + JavaScript alert is fired. Only recorded when the tab is in the background. + + + + Indicates whether the alert is fired from main frame. + + + + + Duration in MS from when the tab is backgrounded to when alert is fired. + + + + chrisha@chromium.org lpy@chromium.org @@ -1254,13 +1273,60 @@ be describing additional metrics about the same event. - Indicates whether the the audio stream belongs to the main frame. + Indicates whether the audio stream belongs to the main frame. Duration in MS from when the tab is backgrounded to when audio starts to - play. Only recorded when the tab is in the background. + play. + + + + + + chrisha@chromium.org + lpy@chromium.org + + Collects the duration in MS from when the tab is backgrounded to when the + favicon is updated. Only recorded when the tab is in the background. + + + + Duration in MS from when the tab is backgrounded to when the favicon is + updated. + + + + + + chrisha@chromium.org + lpy@chromium.org + + + + Indicates whether the notification creation is from the main frame. + + + + + Duration in MS from when the tab is backgrounded to when a non-persistent + notification is created. + + + + + + chrisha@chromium.org + lpy@chromium.org + + Collects the duration in MS from when the tab is backgrounded to when the + title is updated. Only recorded when the tab is in the background. + + + + Duration in MS from when the tab is backgrounded to when the title is + updated.