Commit bd489e77 authored by pmonette's avatar pmonette Committed by Commit bot

Add metrics to keep track of the tab activate/deactivate cycle

These metrics will be used to determine if the pinned state of a tab
matter when trying to determine its priority.

Review-Url: https://codereview.chromium.org/2335203003
Cr-Commit-Position: refs/heads/master@{#420755}
parent 13e84ff7
......@@ -2744,6 +2744,10 @@ split_static_library("browser") {
"memory/tab_stats.h",
"metrics/first_web_contents_profiler.cc",
"metrics/first_web_contents_profiler.h",
"metrics/tab_reactivation_tracker.cc",
"metrics/tab_reactivation_tracker.h",
"metrics/tab_usage_recorder.cc",
"metrics/tab_usage_recorder.h",
"net/firefox_proxy_settings.cc",
"net/firefox_proxy_settings.h",
"net/utility_process_mojo_proxy_resolver_factory.cc",
......
......@@ -32,6 +32,10 @@
#include <cpu-features.h>
#endif // defined(OS_ANDROID) && defined(__arm__)
#if !defined(OS_ANDROID)
#include "chrome/browser/metrics/tab_usage_recorder.h"
#endif // !defined(OS_ANDROID)
#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
#include <gnu/libc-version.h>
......@@ -362,6 +366,10 @@ void ChromeBrowserMainExtraPartsMetrics::PostBrowserStart() {
UMA_HISTOGRAM_COUNTS_100("Hardware.Display.Count.OnStartup", display_count_);
display::Screen::GetScreen()->AddObserver(this);
is_screen_observer_ = true;
#if !defined(OS_ANDROID)
metrics::TabUsageRecorder::Initialize();
#endif // !defined(OS_ANDROID)
}
void ChromeBrowserMainExtraPartsMetrics::OnDisplayAdded(
......
// Copyright 2016 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_reactivation_tracker.h"
#include "base/memory/ptr_util.h"
#include "base/stl_util.h"
#include "content/public/browser/web_contents_observer.h"
namespace metrics {
// This class is used to track the activation/deactivation cycle per
// WebContents.
class TabReactivationTracker::WebContentsHelper
: public content::WebContentsObserver {
public:
WebContentsHelper(TabReactivationTracker* tab_reactivation_tracker,
content::WebContents* contents);
~WebContentsHelper() override;
// content::WebContentsObserver:
void WebContentsDestroyed() override;
void OnTabActivating();
void OnTabDeactivating();
void OnTabClosing();
private:
// The owning TabReactivationTracker.
TabReactivationTracker* tab_reactivation_tracker_;
// Indicates if the tab has been deactivated before as to only count
// reactivations.
bool was_deactivated_once_;
// The deactivation metric is not recorded for closing tabs.
bool is_closing_;
DISALLOW_COPY_AND_ASSIGN(WebContentsHelper);
};
TabReactivationTracker::WebContentsHelper::WebContentsHelper(
TabReactivationTracker* tab_reactivation_tracker,
content::WebContents* contents)
: content::WebContentsObserver(contents),
tab_reactivation_tracker_(tab_reactivation_tracker),
was_deactivated_once_(false),
is_closing_(false) {}
TabReactivationTracker::WebContentsHelper::~WebContentsHelper() = default;
void TabReactivationTracker::WebContentsHelper::WebContentsDestroyed() {
tab_reactivation_tracker_->OnWebContentsDestroyed(web_contents());
}
void TabReactivationTracker::WebContentsHelper::OnTabActivating() {
if (was_deactivated_once_)
tab_reactivation_tracker_->NotifyTabReactivating(web_contents());
}
void TabReactivationTracker::WebContentsHelper::OnTabDeactivating() {
was_deactivated_once_ = true;
if (!is_closing_)
tab_reactivation_tracker_->NotifyTabDeactivating(web_contents());
}
void TabReactivationTracker::WebContentsHelper::OnTabClosing() {
is_closing_ = true;
}
TabReactivationTracker::TabReactivationTracker(Delegate* delegate)
: delegate_(delegate), browser_tab_strip_tracker_(this, nullptr, nullptr) {
browser_tab_strip_tracker_.Init(
BrowserTabStripTracker::InitWith::ALL_BROWERS);
}
TabReactivationTracker::~TabReactivationTracker() = default;
void TabReactivationTracker::TabInsertedAt(TabStripModel* tab_strip_model,
content::WebContents* contents,
int index,
bool foreground) {}
void TabReactivationTracker::TabClosingAt(TabStripModel* tab_strip_model,
content::WebContents* contents,
int index) {
GetHelper(contents)->OnTabClosing();
}
void TabReactivationTracker::ActiveTabChanged(
content::WebContents* old_contents,
content::WebContents* new_contents,
int index,
int reason) {
if (old_contents)
GetHelper(old_contents)->OnTabDeactivating();
GetHelper(new_contents)->OnTabActivating();
}
void TabReactivationTracker::NotifyTabDeactivating(
content::WebContents* contents) {
delegate_->OnTabDeactivated(contents);
}
void TabReactivationTracker::NotifyTabReactivating(
content::WebContents* contents) {
delegate_->OnTabReactivated(contents);
}
TabReactivationTracker::WebContentsHelper* TabReactivationTracker::GetHelper(
content::WebContents* contents) {
// Make sure it exists.
if (!base::ContainsKey(helper_map_, contents)) {
helper_map_.insert(std::make_pair(
contents, base::MakeUnique<WebContentsHelper>(this, contents)));
}
return helper_map_[contents].get();
}
void TabReactivationTracker::OnWebContentsDestroyed(
content::WebContents* contents) {
helper_map_.erase(contents);
}
} // namespace metrics
// Copyright 2016 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 CHROME_BROWSER_METRICS_TAB_REACTIVATION_TRACKER_H_
#define CHROME_BROWSER_METRICS_TAB_REACTIVATION_TRACKER_H_
#include <memory>
#include <unordered_map>
#include "base/macros.h"
#include "chrome/browser/ui/browser_tab_strip_tracker.h"
#include "chrome/browser/ui/tabs/tab_strip_model_observer.h"
namespace metrics {
// This class is used to track tab deactivation/reactivation cycle. A
// reactivation is defined as a tab that was hidden and then reshown.
//
// Note: A closing tab will not trigger a tab deactivation. Also worth noting
// that tab discarding disrupts the tracking and the discarded tab will be
// treated as a new tab.
class TabReactivationTracker : public TabStripModelObserver {
public:
class Delegate {
public:
virtual void OnTabDeactivated(content::WebContents* contents) = 0;
virtual void OnTabReactivated(content::WebContents* contents) = 0;
};
explicit TabReactivationTracker(Delegate* delegate);
~TabReactivationTracker() override;
// TabStripModelObserver:
void TabInsertedAt(TabStripModel* tab_strip_model,
content::WebContents* contents,
int index,
bool foreground) override;
void TabClosingAt(TabStripModel* tab_strip_model,
content::WebContents* contents,
int index) override;
void ActiveTabChanged(content::WebContents* old_contents,
content::WebContents* new_contents,
int index,
int reason) override;
void NotifyTabDeactivating(content::WebContents* contents);
void NotifyTabReactivating(content::WebContents* contents);
private:
class WebContentsHelper;
// Returns the helper for the |contents|, creating it if it doesn't exist.
WebContentsHelper* GetHelper(content::WebContents* contents);
// Called by the helper when |contents| is being destroyed.
void OnWebContentsDestroyed(content::WebContents* contents);
// The delegate must outlive this class.
Delegate* delegate_;
// A helper instance is managed per WebContents.
std::unordered_map<content::WebContents*, std::unique_ptr<WebContentsHelper>>
helper_map_;
BrowserTabStripTracker browser_tab_strip_tracker_;
DISALLOW_COPY_AND_ASSIGN(TabReactivationTracker);
};
} // namespace metrics
#endif // CHROME_BROWSER_METRICS_TAB_REACTIVATION_TRACKER_H_
// Copyright 2016 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_reactivation_tracker.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/tabs/tab_strip_model.h"
#include "chrome/common/url_constants.h"
#include "chrome/test/base/in_process_browser_test.h"
namespace metrics {
// Simple test fixture that just counts the notification received by a
// TabReactivationTracker.
class TabReactivationTrackerTest : public InProcessBrowserTest,
public TabReactivationTracker::Delegate {
public:
TabReactivationTrackerTest()
: tab_reactivation_count_(0), tab_deactivation_count_(0) {}
// TabReactivationTracker::Delegate:
void OnTabReactivated(content::WebContents* contents) override;
void OnTabDeactivated(content::WebContents* contents) override;
int tab_reactivation_count() { return tab_reactivation_count_; }
int tab_deactivation_count() { return tab_deactivation_count_; }
private:
int tab_reactivation_count_;
int tab_deactivation_count_;
};
void TabReactivationTrackerTest::OnTabReactivated(
content::WebContents* contents) {
tab_reactivation_count_++;
}
void TabReactivationTrackerTest::OnTabDeactivated(
content::WebContents* contents) {
tab_deactivation_count_++;
}
IN_PROC_BROWSER_TEST_F(TabReactivationTrackerTest, CorrectTracking) {
content::OpenURLParams open1(
GURL(chrome::kChromeUIAboutURL), content::Referrer(),
WindowOpenDisposition::CURRENT_TAB, ui::PAGE_TRANSITION_TYPED, false);
content::OpenURLParams open2(GURL(chrome::kChromeUIAboutURL),
content::Referrer(),
WindowOpenDisposition::NEW_FOREGROUND_TAB,
ui::PAGE_TRANSITION_TYPED, false);
TabReactivationTracker tab_reactivation_tracker(this);
EXPECT_EQ(0, tab_reactivation_count());
EXPECT_EQ(0, tab_deactivation_count());
// Open one tab.
browser()->OpenURL(open1);
ASSERT_EQ(1, browser()->tab_strip_model()->count());
EXPECT_EQ(0, tab_reactivation_count());
EXPECT_EQ(0, tab_deactivation_count());
// Open a second tab.
browser()->OpenURL(open2);
ASSERT_EQ(2, browser()->tab_strip_model()->count());
EXPECT_EQ(0, tab_reactivation_count());
EXPECT_EQ(1, tab_deactivation_count());
// Reactivate the first tab.
browser()->tab_strip_model()->ActivateTabAt(0, false);
EXPECT_EQ(1, tab_reactivation_count());
EXPECT_EQ(2, tab_deactivation_count());
// Closing a tab doesn't count as a deactivation.
browser()->tab_strip_model()->CloseWebContentsAt(1, 0);
ASSERT_EQ(1, browser()->tab_strip_model()->count());
EXPECT_EQ(1, tab_reactivation_count());
EXPECT_EQ(2, tab_deactivation_count());
}
} // namespace metrics
// Copyright 2016 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_usage_recorder.h"
#include "base/metrics/histogram_macros.h"
#include "chrome/browser/bookmarks/bookmark_model_factory.h"
#include "chrome/browser/ui/tabs/tab_strip_model.h"
#include "components/bookmarks/browser/bookmark_model.h"
#include "content/public/browser/web_contents_user_data.h"
#include "content/public/common/page_importance_signals.h"
DEFINE_WEB_CONTENTS_USER_DATA_KEY(metrics::TabUsageRecorder::WebContentsData);
namespace metrics {
namespace {
// This global is never freed.
TabUsageRecorder* g_tab_usage_recorder = nullptr;
} // namespace
// This class is responsible for recording the metrics. It also keeps track of
// the pinned state of the tab.
class TabUsageRecorder::WebContentsData
: public content::WebContentsUserData<WebContentsData> {
public:
~WebContentsData() override;
void RecordTabDeactivation();
void RecordTabReactivation();
void OnTabPinnedStateChanging(bool is_pinned);
private:
friend class content::WebContentsUserData<WebContentsData>;
explicit WebContentsData(content::WebContents* contents);
// Returns true if |contents_|'s URL is bookmarked.
bool IsBookmarked();
// The WebContents associated to this instance.
content::WebContents* contents_;
// Indicates if the tab is pinned to the tab strip.
bool is_pinned_;
DISALLOW_COPY_AND_ASSIGN(WebContentsData);
};
TabUsageRecorder::WebContentsData::~WebContentsData() = default;
void TabUsageRecorder::WebContentsData::OnTabPinnedStateChanging(
bool is_pinned) {
is_pinned_ = is_pinned;
}
TabUsageRecorder::WebContentsData::WebContentsData(
content::WebContents* contents)
: contents_(contents), is_pinned_(false) {}
bool TabUsageRecorder::WebContentsData::IsBookmarked() {
bookmarks::BookmarkModel* bookmark_model =
BookmarkModelFactory::GetForBrowserContextIfExists(
contents_->GetBrowserContext());
return bookmark_model &&
bookmark_model->IsBookmarked(contents_->GetLastCommittedURL());
}
void TabUsageRecorder::WebContentsData::RecordTabDeactivation() {
UMA_HISTOGRAM_BOOLEAN("Tab.Deactivation.Pinned", is_pinned_);
UMA_HISTOGRAM_BOOLEAN(
"Tab.Deactivation.HadFormInteraction",
contents_->GetPageImportanceSignals().had_form_interaction);
UMA_HISTOGRAM_BOOLEAN("Tab.Deactivation.Bookmarked", IsBookmarked());
}
void TabUsageRecorder::WebContentsData::RecordTabReactivation() {
UMA_HISTOGRAM_BOOLEAN("Tab.Reactivation.Pinned", is_pinned_);
UMA_HISTOGRAM_BOOLEAN(
"Tab.Reactivation.HadFormInteraction",
contents_->GetPageImportanceSignals().had_form_interaction);
UMA_HISTOGRAM_BOOLEAN("Tab.Reactivation.Bookmarked", IsBookmarked());
}
// static
void TabUsageRecorder::Initialize() {
DCHECK(!g_tab_usage_recorder);
g_tab_usage_recorder = new TabUsageRecorder();
}
void TabUsageRecorder::OnTabDeactivated(content::WebContents* contents) {
GetWebContentsData(contents)->RecordTabDeactivation();
}
void TabUsageRecorder::OnTabReactivated(content::WebContents* contents) {
GetWebContentsData(contents)->RecordTabReactivation();
}
void TabUsageRecorder::TabInsertedAt(TabStripModel* tab_strip_model,
content::WebContents* contents,
int index,
bool foreground) {
// Set the initial pinned value.
TabPinnedStateChanged(tab_strip_model, contents, index);
}
void TabUsageRecorder::TabPinnedStateChanged(TabStripModel* tab_strip_model,
content::WebContents* contents,
int index) {
GetWebContentsData(contents)->OnTabPinnedStateChanging(
tab_strip_model->IsTabPinned(index));
}
TabUsageRecorder::TabUsageRecorder()
: tab_reactivation_tracker_(this),
browser_tab_strip_tracker_(this, nullptr, nullptr) {
browser_tab_strip_tracker_.Init(
BrowserTabStripTracker::InitWith::ALL_BROWERS);
}
TabUsageRecorder::~TabUsageRecorder() = default;
TabUsageRecorder::WebContentsData* TabUsageRecorder::GetWebContentsData(
content::WebContents* contents) {
WebContentsData::CreateForWebContents(contents);
return WebContentsData::FromWebContents(contents);
}
} // namespace metrics
// Copyright 2016 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 CHROME_BROWSER_METRICS_TAB_USAGE_RECORDER_H_
#define CHROME_BROWSER_METRICS_TAB_USAGE_RECORDER_H_
#include "base/macros.h"
#include "chrome/browser/metrics/tab_reactivation_tracker.h"
#include "chrome/browser/ui/browser_tab_strip_tracker.h"
#include "chrome/browser/ui/tabs/tab_strip_model_observer.h"
namespace metrics {
// This class is used to record metrics about tab reactivation. Specifically,
// it records a histogram value everytime a tab is deactivated or reactivated.
// The ratio of both can be calculated for tabs with different properties (e.g.
// If the tab is pinned to the tab strip) to see if they are correlated with
// higher probability of tab reactivation.
class TabUsageRecorder : public TabReactivationTracker::Delegate,
public TabStripModelObserver {
public:
// Needs to be public for DEFINE_WEB_CONTENTS_USER_DATA_KEY.
class WebContentsData;
// Starts recording tab usage for all browsers.
static void Initialize();
// TabReactivationTracker::Delegate:
void OnTabDeactivated(content::WebContents* contents) override;
void OnTabReactivated(content::WebContents* contents) override;
// TabStripModelObserver:
void TabInsertedAt(TabStripModel* tab_strip_model,
content::WebContents* contents,
int index,
bool foreground) override;
void TabPinnedStateChanged(TabStripModel* tab_strip_model,
content::WebContents* contents,
int index) override;
private:
TabUsageRecorder();
~TabUsageRecorder() override;
// Returns the WebContentsData associated with |contents|, creating one if it
// doesn't exist.
WebContentsData* GetWebContentsData(content::WebContents* contents);
TabReactivationTracker tab_reactivation_tracker_;
BrowserTabStripTracker browser_tab_strip_tracker_;
DISALLOW_COPY_AND_ASSIGN(TabUsageRecorder);
};
} // namespace metrics
#endif // CHROME_BROWSER_METRICS_TAB_USAGE_RECORDER_H_
......@@ -1595,6 +1595,7 @@ test("browser_tests") {
"../browser/memory/tab_manager_observer_browsertest.cc",
"../browser/metrics/metrics_memory_details_browsertest.cc",
"../browser/metrics/metrics_service_browsertest.cc",
"../browser/metrics/tab_reactivation_tracker_browsertest.cc",
"../browser/net/cookie_policy_browsertest.cc",
"../browser/net/dns_probe_browsertest.cc",
"../browser/net/errorpage_browsertest.cc",
......
......@@ -61829,6 +61829,30 @@ http://cs/file:chrome/histograms.xml - but prefer this file for new entries.
</summary>
</histogram>
<histogram name="Tab.Deactivation.Bookmarked" enum="Boolean">
<owner>pmonette@chromium.org</owner>
<summary>
A tab was deactivated. Closing tabs are not included. This histogram also
records if the tab's URL was bookmarked.
</summary>
</histogram>
<histogram name="Tab.Deactivation.HadFormInteraction" enum="Boolean">
<owner>pmonette@chromium.org</owner>
<summary>
A tab was deactivated. Closing tabs are not included. This histogram also
records if the tab had any form interaction.
</summary>
</histogram>
<histogram name="Tab.Deactivation.Pinned" enum="Boolean">
<owner>pmonette@chromium.org</owner>
<summary>
A tab was deactivated. Closing tabs are not included. This histogram also
records if the tab was pinned to the tab strip or not.
</summary>
</histogram>
<histogram name="Tab.Discarding" enum="TabDiscardingEvents">
<obsolete>
Deprecated 10/2015, not needed anymore.
......@@ -61930,6 +61954,30 @@ http://cs/file:chrome/histograms.xml - but prefer this file for new entries.
</summary>
</histogram>
<histogram name="Tab.Reactivation.Bookmarked" enum="Boolean">
<owner>pmonette@chromium.org</owner>
<summary>
A tab was reactivated after being hidden. This histogram also records if the
tab's URL was bookmarked.
</summary>
</histogram>
<histogram name="Tab.Reactivation.HadFormInteraction" enum="Boolean">
<owner>pmonette@chromium.org</owner>
<summary>
A tab was reactivated after being hidden. This histogram also records if the
tab had any form interaction.
</summary>
</histogram>
<histogram name="Tab.Reactivation.Pinned" enum="Boolean">
<owner>pmonette@chromium.org</owner>
<summary>
A tab was reactivated after being hidden. This histogram also records if the
tab was pinned to the tab strip.
</summary>
</histogram>
<histogram name="Tab.RendererCrashStatus" enum="TabRendererCrashStatus">
<owner>jaekyun@chromium.org</owner>
<summary>
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment