Commit 7ab2a1e9 authored by Justin Miron's avatar Justin Miron Committed by Commit Bot

Window disposition tracking for popups in UKM.

This adds a new boolean to the Popup.Closed UKM: WindowOpenDisposition.
This records the disposition used to create the popup, recorded
at the time the pop-up tracker is created.

This will be used to better understand how pop-ups are opened and
perceived by users in order to identify more abusive pop-up
experiences and improve the pop up blocker.

BUG=1044601

Change-Id: Ie32bff8f5753eb4210054569058e6df75d5f5258
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2075138
Commit-Queue: Justin Miron <justinmiron@google.com>
Reviewed-by: default avatarRobert Kaplow <rkaplow@chromium.org>
Reviewed-by: default avatarTed Choc <tedchoc@chromium.org>
Reviewed-by: default avatarCharlie Harrison <csharrison@chromium.org>
Reviewed-by: default avatarPeter Kasting <pkasting@chromium.org>
Cr-Commit-Position: refs/heads/master@{#748252}
parent b284ea99
...@@ -402,7 +402,7 @@ void TabWebContentsDelegateAndroid::AddNewContents( ...@@ -402,7 +402,7 @@ void TabWebContentsDelegateAndroid::AddNewContents(
// At this point the |new_contents| is beyond the popup blocker, but we use // At this point the |new_contents| is beyond the popup blocker, but we use
// the same logic for determining if the popup tracker needs to be attached. // the same logic for determining if the popup tracker needs to be attached.
if (source && ConsiderForPopupBlocking(disposition)) if (source && ConsiderForPopupBlocking(disposition))
PopupTracker::CreateForWebContents(new_contents.get(), source); PopupTracker::CreateForWebContents(new_contents.get(), source, disposition);
TabHelpers::AttachTabHelpers(new_contents.get()); TabHelpers::AttachTabHelpers(new_contents.get());
......
...@@ -141,7 +141,8 @@ void PopupBlockerTabHelper::ShowBlockedPopup( ...@@ -141,7 +141,8 @@ void PopupBlockerTabHelper::ShowBlockedPopup(
#endif #endif
if (popup->params.navigated_or_inserted_contents) { if (popup->params.navigated_or_inserted_contents) {
auto* tracker = PopupTracker::CreateForWebContents( auto* tracker = PopupTracker::CreateForWebContents(
popup->params.navigated_or_inserted_contents, web_contents()); popup->params.navigated_or_inserted_contents, web_contents(),
popup->params.disposition);
tracker->set_is_trusted(true); tracker->set_is_trusted(true);
if (popup->params.disposition == WindowOpenDisposition::NEW_POPUP) { if (popup->params.disposition == WindowOpenDisposition::NEW_POPUP) {
......
...@@ -35,6 +35,7 @@ ...@@ -35,6 +35,7 @@
#include "services/metrics/public/cpp/ukm_builders.h" #include "services/metrics/public/cpp/ukm_builders.h"
#include "services/metrics/public/cpp/ukm_source.h" #include "services/metrics/public/cpp/ukm_source.h"
#include "testing/gtest/include/gtest/gtest.h" #include "testing/gtest/include/gtest/gtest.h"
#include "ui/base/window_open_disposition.h"
#include "url/gurl.h" #include "url/gurl.h"
#if defined(OS_ANDROID) #if defined(OS_ANDROID)
...@@ -96,7 +97,8 @@ class PopupOpenerTabHelperTest : public ChromeRenderViewHostTestHarness { ...@@ -96,7 +97,8 @@ class PopupOpenerTabHelperTest : public ChromeRenderViewHostTestHarness {
content::WebContents* raw_popup = popup.get(); content::WebContents* raw_popup = popup.get();
popups_.push_back(std::move(popup)); popups_.push_back(std::move(popup));
PopupTracker::CreateForWebContents(raw_popup, web_contents() /* opener */); PopupTracker::CreateForWebContents(raw_popup, web_contents() /* opener */,
WindowOpenDisposition::NEW_POPUP);
web_contents()->WasHidden(); web_contents()->WasHidden();
raw_popup->WasShown(); raw_popup->WasShown();
return raw_popup; return raw_popup;
......
...@@ -16,13 +16,15 @@ ...@@ -16,13 +16,15 @@
#include "services/metrics/public/cpp/ukm_builders.h" #include "services/metrics/public/cpp/ukm_builders.h"
#include "services/metrics/public/cpp/ukm_recorder.h" #include "services/metrics/public/cpp/ukm_recorder.h"
PopupTracker* PopupTracker::CreateForWebContents(content::WebContents* contents, PopupTracker* PopupTracker::CreateForWebContents(
content::WebContents* opener) { content::WebContents* contents,
content::WebContents* opener,
WindowOpenDisposition disposition) {
DCHECK(contents); DCHECK(contents);
DCHECK(opener); DCHECK(opener);
auto* tracker = FromWebContents(contents); auto* tracker = FromWebContents(contents);
if (!tracker) { if (!tracker) {
tracker = new PopupTracker(contents, opener); tracker = new PopupTracker(contents, opener, disposition);
contents->SetUserData(UserDataKey(), base::WrapUnique(tracker)); contents->SetUserData(UserDataKey(), base::WrapUnique(tracker));
} }
return tracker; return tracker;
...@@ -31,13 +33,15 @@ PopupTracker* PopupTracker::CreateForWebContents(content::WebContents* contents, ...@@ -31,13 +33,15 @@ PopupTracker* PopupTracker::CreateForWebContents(content::WebContents* contents,
PopupTracker::~PopupTracker() = default; PopupTracker::~PopupTracker() = default;
PopupTracker::PopupTracker(content::WebContents* contents, PopupTracker::PopupTracker(content::WebContents* contents,
content::WebContents* opener) content::WebContents* opener,
WindowOpenDisposition disposition)
: content::WebContentsObserver(contents), : content::WebContentsObserver(contents),
scoped_observer_(this), scoped_observer_(this),
visibility_tracker_( visibility_tracker_(
base::DefaultTickClock::GetInstance(), base::DefaultTickClock::GetInstance(),
contents->GetVisibility() != content::Visibility::HIDDEN), contents->GetVisibility() != content::Visibility::HIDDEN),
opener_source_id_(ukm::GetSourceIdForWebContentsDocument(opener)) { opener_source_id_(ukm::GetSourceIdForWebContentsDocument(opener)),
window_open_disposition_(disposition) {
if (auto* popup_opener = PopupOpenerTabHelper::FromWebContents(opener)) if (auto* popup_opener = PopupOpenerTabHelper::FromWebContents(opener))
popup_opener->OnOpenedPopup(this); popup_opener->OnOpenedPopup(this);
...@@ -83,6 +87,7 @@ void PopupTracker::WebContentsDestroyed() { ...@@ -83,6 +87,7 @@ void PopupTracker::WebContentsDestroyed() {
.SetTrusted(is_trusted_) .SetTrusted(is_trusted_)
.SetNumInteractions(capped_interactions) .SetNumInteractions(capped_interactions)
.SetSafeBrowsingStatus(static_cast<int>(safe_browsing_status_)) .SetSafeBrowsingStatus(static_cast<int>(safe_browsing_status_))
.SetWindowOpenDisposition(static_cast<int>(window_open_disposition_))
.Record(ukm::UkmRecorder::Get()); .Record(ukm::UkmRecorder::Get());
} }
} }
......
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
#include "content/public/browser/web_contents_user_data.h" #include "content/public/browser/web_contents_user_data.h"
#include "services/metrics/public/cpp/ukm_source_id.h" #include "services/metrics/public/cpp/ukm_source_id.h"
#include "ui/base/scoped_visibility_tracker.h" #include "ui/base/scoped_visibility_tracker.h"
#include "ui/base/window_open_disposition.h"
namespace content { namespace content {
class WebContents; class WebContents;
...@@ -38,7 +39,8 @@ class PopupTracker : public content::WebContentsObserver, ...@@ -38,7 +39,8 @@ class PopupTracker : public content::WebContentsObserver,
}; };
static PopupTracker* CreateForWebContents(content::WebContents* contents, static PopupTracker* CreateForWebContents(content::WebContents* contents,
content::WebContents* opener); content::WebContents* opener,
WindowOpenDisposition disposition);
~PopupTracker() override; ~PopupTracker() override;
void set_is_trusted(bool is_trusted) { is_trusted_ = is_trusted; } void set_is_trusted(bool is_trusted) { is_trusted_ = is_trusted; }
...@@ -46,7 +48,9 @@ class PopupTracker : public content::WebContentsObserver, ...@@ -46,7 +48,9 @@ class PopupTracker : public content::WebContentsObserver,
private: private:
friend class content::WebContentsUserData<PopupTracker>; friend class content::WebContentsUserData<PopupTracker>;
PopupTracker(content::WebContents* contents, content::WebContents* opener); PopupTracker(content::WebContents* contents,
content::WebContents* opener,
WindowOpenDisposition disposition);
// content::WebContentsObserver: // content::WebContentsObserver:
void WebContentsDestroyed() override; void WebContentsDestroyed() override;
...@@ -89,6 +93,9 @@ class PopupTracker : public content::WebContentsObserver, ...@@ -89,6 +93,9 @@ class PopupTracker : public content::WebContentsObserver,
PopupSafeBrowsingStatus safe_browsing_status_ = PopupSafeBrowsingStatus safe_browsing_status_ =
PopupSafeBrowsingStatus::kNoValue; PopupSafeBrowsingStatus::kNoValue;
// The window open disposition used when creating the popup.
const WindowOpenDisposition window_open_disposition_;
WEB_CONTENTS_USER_DATA_KEY_DECL(); WEB_CONTENTS_USER_DATA_KEY_DECL();
DISALLOW_COPY_AND_ASSIGN(PopupTracker); DISALLOW_COPY_AND_ASSIGN(PopupTracker);
......
...@@ -50,6 +50,7 @@ const char kUkmUserInitiatedClose[] = "UserInitiatedClose"; ...@@ -50,6 +50,7 @@ const char kUkmUserInitiatedClose[] = "UserInitiatedClose";
const char kUkmTrusted[] = "Trusted"; const char kUkmTrusted[] = "Trusted";
const char kUkmNumInteractions[] = "NumInteractions"; const char kUkmNumInteractions[] = "NumInteractions";
const char kUkmSafeBrowsingStatus[] = "SafeBrowsingStatus"; const char kUkmSafeBrowsingStatus[] = "SafeBrowsingStatus";
const char kUkmWindowOpenDisposition[] = "WindowOpenDisposition";
} // namespace } // namespace
using UkmEntry = ukm::builders::Popup_Closed; using UkmEntry = ukm::builders::Popup_Closed;
...@@ -476,3 +477,66 @@ IN_PROC_BROWSER_TEST_F(SafeBrowsingPopupTrackerBrowserTest, ...@@ -476,3 +477,66 @@ IN_PROC_BROWSER_TEST_F(SafeBrowsingPopupTrackerBrowserTest,
static_cast<int>(PopupTracker::PopupSafeBrowsingStatus::kUnsafe)); static_cast<int>(PopupTracker::PopupSafeBrowsingStatus::kUnsafe));
} }
} }
IN_PROC_BROWSER_TEST_F(PopupTrackerBrowserTest, PopupInTab_IsWindowFalse) {
const GURL first_url = embedded_test_server()->GetURL("/title1.html");
ui_test_utils::NavigateToURL(browser(), first_url);
content::TestNavigationObserver navigation_observer(nullptr, 1);
navigation_observer.StartWatchingNewWebContents();
EXPECT_TRUE(
content::ExecJs(browser()->tab_strip_model()->GetActiveWebContents(),
"window.open('/title1.html')"));
navigation_observer.Wait();
EXPECT_EQ(2, browser()->tab_strip_model()->count());
content::WebContents* popup =
browser()->tab_strip_model()->GetActiveWebContents();
EXPECT_TRUE(PopupTracker::FromWebContents(popup));
// Close the popup and check metric.
int active_index = browser()->tab_strip_model()->active_index();
content::WebContentsDestroyedWatcher destroyed_watcher(popup);
browser()->tab_strip_model()->CloseWebContentsAt(
active_index, TabStripModel::CLOSE_USER_GESTURE);
destroyed_watcher.Wait();
auto* entry = ExpectAndGetEntry(first_url);
test_ukm_recorder_->ExpectEntryMetric(
entry, kUkmWindowOpenDisposition,
static_cast<int>(WindowOpenDisposition::NEW_FOREGROUND_TAB));
}
IN_PROC_BROWSER_TEST_F(PopupTrackerBrowserTest, PopupInWindow_IsWindowTrue) {
const GURL first_url = embedded_test_server()->GetURL("/title1.html");
ui_test_utils::NavigateToURL(browser(), first_url);
content::TestNavigationObserver navigation_observer(nullptr, 1);
navigation_observer.StartWatchingNewWebContents();
EXPECT_TRUE(content::ExecJs(
browser()->tab_strip_model()->GetActiveWebContents(),
"window.open('/title1.html', 'new_window', "
"'location=yes,height=570,width=520,scrollbars=yes,status=yes')"));
navigation_observer.Wait();
EXPECT_EQ(2u, chrome::GetTotalBrowserCount());
Browser* created_browser = chrome::FindLastActive();
EXPECT_EQ(1, created_browser->tab_strip_model()->count());
content::WebContents* popup =
created_browser->tab_strip_model()->GetActiveWebContents();
EXPECT_TRUE(PopupTracker::FromWebContents(popup));
// Close the popup and check metric.
int active_index = created_browser->tab_strip_model()->active_index();
content::WebContentsDestroyedWatcher destroyed_watcher(popup);
created_browser->tab_strip_model()->CloseWebContentsAt(
active_index, TabStripModel::CLOSE_USER_GESTURE);
destroyed_watcher.Wait();
auto* entry = ExpectAndGetEntry(first_url);
test_ukm_recorder_->ExpectEntryMetric(
entry, kUkmWindowOpenDisposition,
static_cast<int>(WindowOpenDisposition::NEW_POPUP));
}
...@@ -1663,7 +1663,7 @@ WebContents* Browser::OpenURLFromTab(WebContents* source, ...@@ -1663,7 +1663,7 @@ WebContents* Browser::OpenURLFromTab(WebContents* source,
if (is_popup && nav_params.navigated_or_inserted_contents) { if (is_popup && nav_params.navigated_or_inserted_contents) {
auto* tracker = PopupTracker::CreateForWebContents( auto* tracker = PopupTracker::CreateForWebContents(
nav_params.navigated_or_inserted_contents, source); nav_params.navigated_or_inserted_contents, source, params.disposition);
tracker->set_is_trusted(params.triggering_event_info != tracker->set_is_trusted(params.triggering_event_info !=
blink::TriggeringEventInfo::kFromUntrustedEvent); blink::TriggeringEventInfo::kFromUntrustedEvent);
} }
...@@ -1725,7 +1725,7 @@ void Browser::AddNewContents(WebContents* source, ...@@ -1725,7 +1725,7 @@ void Browser::AddNewContents(WebContents* source,
// At this point the |new_contents| is beyond the popup blocker, but we use // At this point the |new_contents| is beyond the popup blocker, but we use
// the same logic for determining if the popup tracker needs to be attached. // the same logic for determining if the popup tracker needs to be attached.
if (source && ConsiderForPopupBlocking(disposition)) if (source && ConsiderForPopupBlocking(disposition))
PopupTracker::CreateForWebContents(new_contents.get(), source); PopupTracker::CreateForWebContents(new_contents.get(), source, disposition);
chrome::AddWebContents(this, source, std::move(new_contents), disposition, chrome::AddWebContents(this, source, std::move(new_contents), disposition,
initial_rect); initial_rect);
......
...@@ -8375,6 +8375,12 @@ be describing additional metrics about the same event. ...@@ -8375,6 +8375,12 @@ be describing additional metrics about the same event.
Boolean value to represent whether the popup was closed by user gesture. Boolean value to represent whether the popup was closed by user gesture.
</summary> </summary>
</metric> </metric>
<metric name="WindowOpenDisposition" enum="WindowOpenDisposition">
<summary>
The UI window open disposition used when creating the web contents of the
pop-up. Set by the browser process when the pop up tracker is created.
</summary>
</metric>
</event> </event>
<event name="Popup.Page"> <event name="Popup.Page">
......
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