blob: 116ed2c930e78500e8e79b47e6d574099aa22dd3 [file] [log] [blame]
// 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 "chrome/browser/metrics/tab_stats_tracker.h"
#include <algorithm>
#include "base/metrics/histogram_macros.h"
#include "base/power_monitor/power_monitor.h"
#include "chrome/browser/background/background_mode_manager.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_list.h"
#include "chrome/browser/ui/tabs/tab_strip_model.h"
#include "components/metrics/metrics_pref_names.h"
#include "components/prefs/pref_service.h"
namespace metrics {
namespace {
// The interval at which the DailyEvent::CheckInterval function should be
// called.
constexpr base::TimeDelta kDailyEventIntervalTimeDelta =
base::TimeDelta::FromMilliseconds(60 * 30);
// The global TabStatsTracker instance.
TabStatsTracker* g_instance = nullptr;
} // namespace
// static
const char TabStatsTracker::kTabStatsDailyEventHistogramName[] =
"Tabs.TabsStatsDailyEventInteral";
const char TabStatsTracker::UmaStatsReportingDelegate::
kNumberOfTabsOnResumeHistogramName[] = "Tabs.NumberOfTabsOnResume";
const char
TabStatsTracker::UmaStatsReportingDelegate::kMaxTabsInADayHistogramName[] =
"Tabs.MaxTabsInADay";
const char TabStatsTracker::UmaStatsReportingDelegate::
kMaxTabsPerWindowInADayHistogramName[] = "Tabs.MaxTabsPerWindowInADay";
const char TabStatsTracker::UmaStatsReportingDelegate::
kMaxWindowsInADayHistogramName[] = "Tabs.MaxWindowsInADay";
const TabStatsDataStore::TabsStats& TabStatsTracker::tab_stats() const {
return tab_stats_data_store_->tab_stats();
}
TabStatsTracker::TabStatsTracker(PrefService* pref_service)
: reporting_delegate_(base::MakeUnique<UmaStatsReportingDelegate>()),
tab_stats_data_store_(base::MakeUnique<TabStatsDataStore>(pref_service)),
daily_event_(
base::MakeUnique<DailyEvent>(pref_service,
prefs::kTabStatsDailySample,
kTabStatsDailyEventHistogramName)) {
DCHECK(pref_service != nullptr);
// Get the list of existing windows/tabs. There shouldn't be any if this is
// initialized at startup but this will ensure that the counts stay accurate
// if the initialization gets moved to after the creation of the first tab.
BrowserList* browser_list = BrowserList::GetInstance();
for (Browser* browser : *browser_list) {
browser->tab_strip_model()->AddObserver(this);
tab_stats_data_store_->OnWindowAdded();
tab_stats_data_store_->OnTabsAdded(browser->tab_strip_model()->count());
tab_stats_data_store_->UpdateMaxTabsPerWindowIfNeeded(
static_cast<size_t>(browser->tab_strip_model()->count()));
}
browser_list->AddObserver(this);
base::PowerMonitor* power_monitor = base::PowerMonitor::Get();
if (power_monitor != nullptr)
power_monitor->AddObserver(this);
daily_event_->AddObserver(base::MakeUnique<TabStatsDailyObserver>(
reporting_delegate_.get(), tab_stats_data_store_.get()));
// Call the CheckInterval method to see if the data need to be immediately
// reported.
daily_event_->CheckInterval();
timer_.Start(FROM_HERE, kDailyEventIntervalTimeDelta, daily_event_.get(),
&DailyEvent::CheckInterval);
}
TabStatsTracker::~TabStatsTracker() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
BrowserList* browser_list = BrowserList::GetInstance();
for (Browser* browser : *browser_list)
browser->tab_strip_model()->RemoveObserver(this);
browser_list->RemoveObserver(this);
base::PowerMonitor* power_monitor = base::PowerMonitor::Get();
if (power_monitor != nullptr)
power_monitor->RemoveObserver(this);
}
// static
void TabStatsTracker::SetInstance(std::unique_ptr<TabStatsTracker> instance) {
DCHECK_EQ(nullptr, g_instance);
g_instance = instance.release();
}
TabStatsTracker* TabStatsTracker::GetInstance() {
return g_instance;
}
void TabStatsTracker::TabStatsDailyObserver::OnDailyEvent() {
reporting_delegate_->ReportDailyMetrics(data_store_->tab_stats());
data_store_->ResetMaximumsToCurrentState();
}
void TabStatsTracker::OnBrowserAdded(Browser* browser) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
tab_stats_data_store_->OnWindowAdded();
browser->tab_strip_model()->AddObserver(this);
}
void TabStatsTracker::OnBrowserRemoved(Browser* browser) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
tab_stats_data_store_->OnWindowRemoved();
browser->tab_strip_model()->RemoveObserver(this);
}
void TabStatsTracker::TabInsertedAt(TabStripModel* model,
content::WebContents* web_contents,
int index,
bool foreground) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
tab_stats_data_store_->OnTabsAdded(1);
tab_stats_data_store_->UpdateMaxTabsPerWindowIfNeeded(
static_cast<size_t>(model->count()));
}
void TabStatsTracker::TabClosingAt(TabStripModel* model,
content::WebContents* web_contents,
int index) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
tab_stats_data_store_->OnTabsRemoved(1);
}
void TabStatsTracker::OnResume() {
reporting_delegate_->ReportTabCountOnResume(
tab_stats_data_store_->tab_stats().total_tab_count);
}
void TabStatsTracker::UmaStatsReportingDelegate::ReportTabCountOnResume(
size_t tab_count) {
// Don't report the number of tabs on resume if Chrome is running in
// background with no visible window.
if (g_browser_process && g_browser_process->background_mode_manager()
->IsBackgroundWithoutWindows()) {
return;
}
UMA_HISTOGRAM_COUNTS_10000(kNumberOfTabsOnResumeHistogramName, tab_count);
}
void TabStatsTracker::UmaStatsReportingDelegate::ReportDailyMetrics(
const TabStatsDataStore::TabsStats& tab_stats) {
UMA_HISTOGRAM_COUNTS_10000(kMaxTabsInADayHistogramName,
tab_stats.total_tab_count_max);
UMA_HISTOGRAM_COUNTS_10000(kMaxTabsPerWindowInADayHistogramName,
tab_stats.max_tab_per_window);
UMA_HISTOGRAM_COUNTS_10000(kMaxWindowsInADayHistogramName,
tab_stats.window_count_max);
}
} // namespace metrics