1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197
|
// Copyright 2012 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/ui/uma_browsing_activity_observer.h"
#include <algorithm>
#include "base/metrics/histogram_functions.h"
#include "base/metrics/histogram_macros.h"
#include "base/metrics/user_metrics.h"
#include "base/strings/stringprintf.h"
#include "base/time/time.h"
#include "chrome/browser/lifetime/termination_notification.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/search_engines/template_url_service_factory.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_finder.h"
#include "chrome/browser/ui/browser_list.h"
#include "chrome/browser/ui/browser_window.h"
#include "chrome/browser/ui/tabs/tab_group_model.h"
#include "chrome/browser/ui/tabs/tab_strip_model.h"
#include "chrome/browser/upgrade_detector/upgrade_detector.h"
#include "components/search_engines/template_url_service.h"
#include "components/tab_groups/tab_group_visual_data.h"
#include "components/tabs/public/tab_group.h"
#include "content/public/browser/navigation_details.h"
#include "content/public/browser/navigation_entry.h"
#include "content/public/browser/web_contents.h"
#include "content/public/browser/web_contents_user_data.h"
#include "ui/gfx/range/range.h"
namespace {
UMABrowsingActivityObserver* g_uma_browsing_activity_observer_instance =
nullptr;
} // namespace
// static
void UMABrowsingActivityObserver::Init() {
DCHECK(!g_uma_browsing_activity_observer_instance);
// Must be created before any Browsers are.
DCHECK_EQ(0U, chrome::GetTotalBrowserCount());
g_uma_browsing_activity_observer_instance = new UMABrowsingActivityObserver;
}
UMABrowsingActivityObserver::UMABrowsingActivityObserver() {
subscription_ = browser_shutdown::AddAppTerminatingCallback(base::BindOnce(
&UMABrowsingActivityObserver::OnAppTerminating, base::Unretained(this)));
}
UMABrowsingActivityObserver::~UMABrowsingActivityObserver() = default;
void UMABrowsingActivityObserver::OnNavigationEntryCommitted(
content::WebContents* web_contents,
const content::LoadCommittedDetails& load_details) const {
// Track whether the page loaded is a search results page (SRP). Track
// the non-SRP navigations as well so there is a control.
base::RecordAction(base::UserMetricsAction("NavEntryCommitted"));
if (!load_details.is_navigation_to_different_page()) {
// Don't log for subframes or other trivial types.
return;
}
LogBrowserTabCount();
}
void UMABrowsingActivityObserver::OnAppTerminating() const {
LogTimeBeforeUpdate();
DCHECK_EQ(this, g_uma_browsing_activity_observer_instance);
delete g_uma_browsing_activity_observer_instance;
g_uma_browsing_activity_observer_instance = nullptr;
}
void UMABrowsingActivityObserver::LogTimeBeforeUpdate() const {
const base::Time upgrade_detected_time =
UpgradeDetector::GetInstance()->upgrade_detected_time();
if (upgrade_detected_time.is_null()) {
return;
}
const base::TimeDelta time_since_upgrade =
base::Time::Now() - upgrade_detected_time;
constexpr int kMaxDays = 30;
base::UmaHistogramExactLinear("UpgradeDetector.DaysBeforeUpgrade",
base::TimeDelta(time_since_upgrade).InDays(),
kMaxDays);
base::UmaHistogramCounts1000("UpgradeDetector.HoursBeforeUpgrade",
base::TimeDelta(time_since_upgrade).InHours());
}
void UMABrowsingActivityObserver::LogBrowserTabCount() const {
int tab_count = 0;
int tab_group_count = 0;
int collapsed_tab_group_count = 0;
int customized_tab_group_count = 0;
int pinned_tab_count = 0;
for (Browser* browser : *BrowserList::GetInstance()) {
// Record how many tabs each window has open.
UMA_HISTOGRAM_CUSTOM_COUNTS("Tabs.TabCountPerWindow",
browser->tab_strip_model()->count(), 1, 200,
50);
TabStripModel* const tab_strip_model = browser->tab_strip_model();
tab_count += tab_strip_model->count();
for (int i = 0; i < tab_strip_model->count(); ++i) {
if (tab_strip_model->IsTabPinned(i)) {
pinned_tab_count++;
}
}
if (tab_strip_model->group_model()) {
const std::vector<tab_groups::TabGroupId>& groups =
tab_strip_model->group_model()->ListTabGroups();
tab_group_count += groups.size();
for (const tab_groups::TabGroupId& group_id : groups) {
const TabGroup* const tab_group =
tab_strip_model->group_model()->GetTabGroup(group_id);
if (tab_group->IsCustomized() ||
!tab_group->visual_data()->title().empty()) {
++customized_tab_group_count;
}
if (tab_group->visual_data()->is_collapsed()) {
++collapsed_tab_group_count;
}
}
}
if (browser->IsActive()) {
// Record how many tabs the active window has open.
UMA_HISTOGRAM_CUSTOM_COUNTS("Tabs.TabCountActiveWindow",
browser->tab_strip_model()->count(), 1, 200,
50);
}
}
// Record how many tabs total are open (across all windows).
UMA_HISTOGRAM_CUSTOM_COUNTS("Tabs.TabCountPerLoad", tab_count, 1, 200, 50);
// Record how many tab groups (including zero) are open across all windows.
UMA_HISTOGRAM_COUNTS_100("TabGroups.UserGroupCountPerLoad", tab_group_count);
UMA_HISTOGRAM_COUNTS_100("TabGroups.UserPinnedTabCountPerLoad",
std::min(pinned_tab_count, 100));
// Record how many tabs are in the current group. Records 0 if the active tab
// is not in a group.
const Browser* current_browser = BrowserList::GetInstance()->GetLastActive();
if (current_browser) {
TabStripModel* const tab_strip_model = current_browser->tab_strip_model();
if (tab_strip_model->group_model()) {
const std::optional<tab_groups::TabGroupId> active_group =
tab_strip_model->GetTabGroupForTab(tab_strip_model->active_index());
UMA_HISTOGRAM_COUNTS_100("Tabs.TabCountInGroupPerLoad",
active_group.has_value()
? tab_strip_model->group_model()
->GetTabGroup(active_group.value())
->ListTabs()
.length()
: 0);
}
}
// Record how many tab groups with a user-set name or color are open across
// all windows.
UMA_HISTOGRAM_COUNTS_100("TabGroups.UserCustomizedGroupCountPerLoad",
customized_tab_group_count);
// Record how many tab groups are collapsed across all windows.
UMA_HISTOGRAM_COUNTS_100("TabGroups.CollapsedGroupCountPerLoad",
collapsed_tab_group_count);
}
UMABrowsingActivityObserver::TabHelper::TabHelper(
content::WebContents* web_contents)
: content::WebContentsObserver(web_contents),
content::WebContentsUserData<TabHelper>(*web_contents) {}
UMABrowsingActivityObserver::TabHelper::~TabHelper() = default;
void UMABrowsingActivityObserver::TabHelper::NavigationEntryCommitted(
const content::LoadCommittedDetails& load_details) {
// This is null in unit tests. Crash reports suggest it's possible for it to
// be null in production. See https://crbug.com/1510023 and
// https://crbug.com/1523758
if (!g_uma_browsing_activity_observer_instance) {
return;
}
g_uma_browsing_activity_observer_instance->OnNavigationEntryCommitted(
web_contents(), load_details);
}
WEB_CONTENTS_USER_DATA_KEY_IMPL(UMABrowsingActivityObserver::TabHelper);
|