File: uma_browsing_activity_observer.cc

package info (click to toggle)
chromium 139.0.7258.127-1
  • links: PTS, VCS
  • area: main
  • in suites:
  • size: 6,122,068 kB
  • sloc: cpp: 35,100,771; ansic: 7,163,530; javascript: 4,103,002; python: 1,436,920; asm: 946,517; xml: 746,709; pascal: 187,653; perl: 88,691; sh: 88,436; objc: 79,953; sql: 51,488; cs: 44,583; fortran: 24,137; makefile: 22,147; tcl: 15,277; php: 13,980; yacc: 8,984; ruby: 7,485; awk: 3,720; lisp: 3,096; lex: 1,327; ada: 727; jsp: 228; sed: 36
file content (197 lines) | stat: -rw-r--r-- 7,765 bytes parent folder | download | duplicates (5)
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);