blob: 9acccb699a9012c20be2b8518408bd879bcde47b [file] [log] [blame]
// Copyright 2015 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/sessions/session_restore_stats_collector.h"
#include <string>
#include "base/metrics/histogram_macros.h"
#include "base/strings/stringprintf.h"
#include "content/public/browser/render_widget_host_view.h"
#include "content/public/browser/web_contents.h"
namespace {
using content::RenderWidgetHost;
using content::RenderWidgetHostView;
using content::WebContents;
SessionRestoreStatsCollector* g_instance = nullptr;
// Returns the RenderWidgetHost associated with a WebContents.
RenderWidgetHost* GetRenderWidgetHost(WebContents* web_contents) {
content::RenderWidgetHostView* render_widget_host_view =
web_contents->GetRenderWidgetHostView();
if (render_widget_host_view)
return render_widget_host_view->GetRenderWidgetHost();
return nullptr;
}
} // namespace
SessionRestoreStatsCollector::TabLoaderStats::TabLoaderStats()
: tab_count(0u),
tab_first_paint_reason(PAINT_FINISHED_UMA_MAX) {}
SessionRestoreStatsCollector::SessionRestoreStatsCollector(
const base::TimeTicks& restore_started,
std::unique_ptr<StatsReportingDelegate> reporting_delegate)
: non_restored_tab_painted_first_(false),
hidden_or_occluded_tab_ignored_(false),
restore_started_(restore_started),
reporting_delegate_(std::move(reporting_delegate)) {
DCHECK(!g_instance);
g_instance = this;
}
SessionRestoreStatsCollector::~SessionRestoreStatsCollector() {
DCHECK_EQ(g_instance, this);
g_instance = nullptr;
}
// static
SessionRestoreStatsCollector* SessionRestoreStatsCollector::GetOrCreateInstance(
base::TimeTicks restore_started,
std::unique_ptr<StatsReportingDelegate> reporting_delegate) {
if (g_instance)
return g_instance;
return new SessionRestoreStatsCollector(restore_started,
std::move(reporting_delegate));
}
void SessionRestoreStatsCollector::TrackTabs(
const std::vector<SessionRestoreDelegate::RestoredTab>& tabs) {
tab_loader_stats_.tab_count += tabs.size();
for (const auto& tab : tabs) {
RegisterObserverForTab(tab.contents());
}
// If we were not able to register observers for any tab, report stats.
if (tracked_tabs_occluded_map_.empty())
ReportStatsAndSelfDestroy();
}
void SessionRestoreStatsCollector::RenderWidgetHostVisibilityChanged(
content::RenderWidgetHost* widget_host,
bool became_visible) {
if (became_visible)
return;
auto host_and_occluded_it = tracked_tabs_occluded_map_.find(widget_host);
if (host_and_occluded_it == tracked_tabs_occluded_map_.end())
return;
host_and_occluded_it->second = true;
}
void SessionRestoreStatsCollector::RenderWidgetHostDidUpdateVisualProperties(
content::RenderWidgetHost* widget_host) {
// Only process this event if first paint hasn't been seen and this is a
// paint of a tab that has not been hidden or occluded.
if (!widget_host->GetView() || !widget_host->GetView()->IsShowing())
return;
auto host_and_occluded_it = tracked_tabs_occluded_map_.find(widget_host);
if (host_and_occluded_it != tracked_tabs_occluded_map_.end()) {
// Ignore first paint of a restored tab that was hidden or occluded
// before first paint. If another restored tab is painted, its paint
// time will be recorded.
if (host_and_occluded_it->second) {
hidden_or_occluded_tab_ignored_ = true;
return;
}
// This is a paint for a tab that is explicitly being tracked so
// update the statistics. Otherwise the host is for a tab that's not
// being tracked. Thus some other tab has visibility and has rendered
// and there's no point in tracking the time to first paint. This can
// happen because the user opened a different tab or restored tabs
// to an already existing browser and an existing tab was in the
// foreground.
base::TimeDelta time_to_paint = base::TimeTicks::Now() - restore_started_;
tab_loader_stats_.foreground_tab_first_paint = time_to_paint;
} else {
non_restored_tab_painted_first_ = true;
}
ReportStatsAndSelfDestroy();
}
void SessionRestoreStatsCollector::RenderWidgetHostDestroyed(
content::RenderWidgetHost* widget_host) {
render_widget_host_observations_.RemoveObservation(widget_host);
tracked_tabs_occluded_map_.erase(widget_host);
if (tracked_tabs_occluded_map_.empty())
ReportStatsAndSelfDestroy();
}
void SessionRestoreStatsCollector::RegisterObserverForTab(WebContents* tab) {
content::RenderWidgetHost* rwh = GetRenderWidgetHost(tab);
// If we don't have a RenderWidgetHost, we can't track paints for the tab so
// ignore it.
if (!rwh)
return;
// Assume that tabs do not start out hidden or occluded.
auto result = tracked_tabs_occluded_map_.emplace(rwh, false);
DCHECK(result.second);
render_widget_host_observations_.AddObservation(rwh);
}
void SessionRestoreStatsCollector::ReportStatsAndSelfDestroy() {
if (!tab_loader_stats_.foreground_tab_first_paint.is_zero()) {
tab_loader_stats_.tab_first_paint_reason = PAINT_FINISHED_UMA_DONE;
} else if (non_restored_tab_painted_first_) {
tab_loader_stats_.tab_first_paint_reason =
PAINT_FINISHED_NON_RESTORED_TAB_PAINTED_FIRST;
} else if (hidden_or_occluded_tab_ignored_) {
tab_loader_stats_.tab_first_paint_reason =
PAINT_FINISHED_UMA_NO_COMPLETELY_VISIBLE_TABS;
} else {
tab_loader_stats_.tab_first_paint_reason = PAINT_FINISHED_UMA_NO_PAINT;
}
reporting_delegate_->ReportTabLoaderStats(tab_loader_stats_);
delete this;
}
SessionRestoreStatsCollector::UmaStatsReportingDelegate::
UmaStatsReportingDelegate() = default;
void SessionRestoreStatsCollector::UmaStatsReportingDelegate::
ReportTabLoaderStats(const TabLoaderStats& tab_loader_stats) {
if (!tab_loader_stats.foreground_tab_first_paint.is_zero()) {
UMA_HISTOGRAM_CUSTOM_TIMES("SessionRestore.ForegroundTabFirstPaint4",
tab_loader_stats.foreground_tab_first_paint,
base::Milliseconds(100), base::Minutes(16), 50);
std::string time_for_count = base::StringPrintf(
"SessionRestore.ForegroundTabFirstPaint4_%u",
static_cast<unsigned int>(tab_loader_stats.tab_count));
base::HistogramBase* counter_for_count = base::Histogram::FactoryTimeGet(
time_for_count, base::Milliseconds(100), base::Minutes(16), 50,
base::Histogram::kUmaTargetedHistogramFlag);
counter_for_count->AddTime(tab_loader_stats.foreground_tab_first_paint);
}
UMA_HISTOGRAM_ENUMERATION(
"SessionRestore.ForegroundTabFirstPaint4.FinishReason",
tab_loader_stats.tab_first_paint_reason, PAINT_FINISHED_UMA_MAX);
}