summaryrefslogtreecommitdiff
path: root/chromium/components/blocked_content/popup_tracker.cc
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/components/blocked_content/popup_tracker.cc')
-rw-r--r--chromium/components/blocked_content/popup_tracker.cc174
1 files changed, 174 insertions, 0 deletions
diff --git a/chromium/components/blocked_content/popup_tracker.cc b/chromium/components/blocked_content/popup_tracker.cc
new file mode 100644
index 00000000000..2735f516abe
--- /dev/null
+++ b/chromium/components/blocked_content/popup_tracker.cc
@@ -0,0 +1,174 @@
+// 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 "components/blocked_content/popup_tracker.h"
+
+#include <algorithm>
+
+#include "base/check.h"
+#include "base/memory/ptr_util.h"
+#include "base/metrics/histogram_macros.h"
+#include "base/time/default_tick_clock.h"
+#include "components/blocked_content/popup_opener_tab_helper.h"
+#include "components/ukm/content/source_url_recorder.h"
+#include "content/public/browser/navigation_handle.h"
+#include "content/public/browser/web_contents.h"
+#include "services/metrics/public/cpp/metrics_utils.h"
+#include "services/metrics/public/cpp/ukm_builders.h"
+#include "services/metrics/public/cpp/ukm_recorder.h"
+
+namespace blocked_content {
+namespace {
+
+int CappedUserInteractions(int user_interactions, int max_interactions) {
+ return std::min(user_interactions, max_interactions);
+}
+
+} // namespace
+
+PopupTracker* PopupTracker::CreateForWebContents(
+ content::WebContents* contents,
+ content::WebContents* opener,
+ WindowOpenDisposition disposition) {
+ DCHECK(contents);
+ DCHECK(opener);
+ auto* tracker = FromWebContents(contents);
+ if (!tracker) {
+ tracker = new PopupTracker(contents, opener, disposition);
+ contents->SetUserData(UserDataKey(), base::WrapUnique(tracker));
+ }
+ return tracker;
+}
+
+PopupTracker::~PopupTracker() = default;
+
+PopupTracker::PopupTracker(content::WebContents* contents,
+ content::WebContents* opener,
+ WindowOpenDisposition disposition)
+ : content::WebContentsObserver(contents),
+ scoped_observer_(this),
+ visibility_tracker_(
+ base::DefaultTickClock::GetInstance(),
+ contents->GetVisibility() != content::Visibility::HIDDEN),
+ opener_source_id_(ukm::GetSourceIdForWebContentsDocument(opener)),
+ window_open_disposition_(disposition) {
+ if (auto* popup_opener = PopupOpenerTabHelper::FromWebContents(opener))
+ popup_opener->OnOpenedPopup(this);
+
+ auto* observer_manager =
+ subresource_filter::SubresourceFilterObserverManager::FromWebContents(
+ contents);
+ if (observer_manager) {
+ scoped_observer_.Add(observer_manager);
+ }
+}
+
+void PopupTracker::WebContentsDestroyed() {
+ base::TimeDelta total_foreground_duration =
+ visibility_tracker_.GetForegroundDuration();
+ if (first_load_visible_time_start_) {
+ base::TimeDelta first_load_visible_time =
+ first_load_visible_time_
+ ? *first_load_visible_time_
+ : total_foreground_duration - *first_load_visible_time_start_;
+ UMA_HISTOGRAM_LONG_TIMES(
+ "ContentSettings.Popups.FirstDocumentEngagementTime2",
+ first_load_visible_time);
+ }
+ UMA_HISTOGRAM_CUSTOM_TIMES(
+ "ContentSettings.Popups.EngagementTime", total_foreground_duration,
+ base::TimeDelta::FromMilliseconds(1), base::TimeDelta::FromHours(6), 50);
+ if (web_contents()->GetClosedByUserGesture()) {
+ UMA_HISTOGRAM_CUSTOM_TIMES(
+ "ContentSettings.Popups.EngagementTime.GestureClose",
+ total_foreground_duration, base::TimeDelta::FromMilliseconds(1),
+ base::TimeDelta::FromHours(6), 50);
+ }
+
+ if (opener_source_id_ != ukm::kInvalidSourceId) {
+ const int kMaxInteractions = 100;
+ const int kMaxSubcatagoryInteractions = 50;
+ ukm::builders::Popup_Closed(opener_source_id_)
+ .SetEngagementTime(ukm::GetExponentialBucketMinForUserTiming(
+ total_foreground_duration.InMilliseconds()))
+ .SetUserInitiatedClose(web_contents()->GetClosedByUserGesture())
+ .SetTrusted(is_trusted_)
+ .SetSafeBrowsingStatus(static_cast<int>(safe_browsing_status_))
+ .SetWindowOpenDisposition(static_cast<int>(window_open_disposition_))
+ .SetNumInteractions(
+ CappedUserInteractions(num_interactions_, kMaxInteractions))
+ .SetNumActivationInteractions(CappedUserInteractions(
+ num_activation_events_, kMaxSubcatagoryInteractions))
+ .SetNumGestureScrollBeginInteractions(CappedUserInteractions(
+ num_gesture_scroll_begin_events_, kMaxSubcatagoryInteractions))
+ .Record(ukm::UkmRecorder::Get());
+ }
+}
+
+void PopupTracker::DidFinishNavigation(
+ content::NavigationHandle* navigation_handle) {
+ if (!navigation_handle->HasCommitted() ||
+ navigation_handle->IsSameDocument()) {
+ return;
+ }
+
+ if (!first_load_visible_time_start_) {
+ first_load_visible_time_start_ =
+ visibility_tracker_.GetForegroundDuration();
+ } else if (!first_load_visible_time_) {
+ first_load_visible_time_ = visibility_tracker_.GetForegroundDuration() -
+ *first_load_visible_time_start_;
+ }
+}
+
+void PopupTracker::OnVisibilityChanged(content::Visibility visibility) {
+ // TODO(csharrison): Consider handling OCCLUDED tabs the same way as HIDDEN
+ // tabs.
+ if (visibility == content::Visibility::HIDDEN)
+ visibility_tracker_.OnHidden();
+ else
+ visibility_tracker_.OnShown();
+}
+
+void PopupTracker::DidGetUserInteraction(
+ const blink::WebInputEvent::Type type) {
+ // TODO(csharrison): It would be nice if ctrl-W could be filtered out here,
+ // but the initial ctrl key press is registered as a kRawKeyDown.
+ num_interactions_++;
+
+ if (type == blink::WebInputEvent::Type::kGestureScrollBegin) {
+ num_gesture_scroll_begin_events_++;
+ } else {
+ num_activation_events_++;
+ }
+}
+
+// This method will always be called before the DidFinishNavigation associated
+// with this handle.
+// The exception is a navigation restoring a page from back-forward cache --
+// in that case don't issue any requests, therefore we don't get any
+// safe browsing callbacks. See the comment above for the mitigation.
+void PopupTracker::OnSafeBrowsingChecksComplete(
+ content::NavigationHandle* navigation_handle,
+ const subresource_filter::SubresourceFilterSafeBrowsingClient::CheckResult&
+ result) {
+ DCHECK(navigation_handle->IsInMainFrame());
+ safe_browsing_status_ = PopupSafeBrowsingStatus::kSafe;
+ if (result.threat_type ==
+ safe_browsing::SBThreatType::SB_THREAT_TYPE_URL_PHISHING ||
+ result.threat_type == safe_browsing::SBThreatType::
+ SB_THREAT_TYPE_URL_CLIENT_SIDE_PHISHING ||
+ result.threat_type ==
+ safe_browsing::SBThreatType::SB_THREAT_TYPE_SUBRESOURCE_FILTER) {
+ safe_browsing_status_ = PopupSafeBrowsingStatus::kUnsafe;
+ }
+}
+
+void PopupTracker::OnSubresourceFilterGoingAway() {
+ scoped_observer_.RemoveAll();
+}
+
+WEB_CONTENTS_USER_DATA_KEY_IMPL(PopupTracker)
+
+} // namespace blocked_content