summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorcthomp@chromium.org <cthomp@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-08-16 01:10:16 +0000
committercthomp@chromium.org <cthomp@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-08-16 01:10:16 +0000
commit07c973f756ff41198cab01f7d2abd2ff8a123eae (patch)
tree9bce76d9e36667070459520cede6447f086a8215
parent9af1231d969ee9b215d1a02f0155f9aae9e18910 (diff)
downloadchromium_src-07c973f756ff41198cab01f7d2abd2ff8a123eae.zip
chromium_src-07c973f756ff41198cab01f7d2abd2ff8a123eae.tar.gz
chromium_src-07c973f756ff41198cab01f7d2abd2ff8a123eae.tar.bz2
Experience sampling instrumentation for dangerous downloads warnings
BUG=384635 Review URL: https://codereview.chromium.org/402293002 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@290076 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--chrome/browser/download/download_danger_prompt.cc19
-rw-r--r--chrome/browser/download/download_danger_prompt_browsertest.cc10
-rw-r--r--chrome/browser/extensions/api/experience_sampling_private/experience_sampling.cc7
-rw-r--r--chrome/browser/extensions/api/experience_sampling_private/experience_sampling.h4
-rw-r--r--chrome/browser/ui/cocoa/download/download_item_controller.h8
-rw-r--r--chrome/browser/ui/cocoa/download/download_item_controller.mm25
-rw-r--r--chrome/browser/ui/views/download/download_danger_prompt_views.cc19
-rw-r--r--chrome/browser/ui/views/download/download_item_view.cc35
-rw-r--r--chrome/browser/ui/views/download/download_item_view.h8
9 files changed, 135 insertions, 0 deletions
diff --git a/chrome/browser/download/download_danger_prompt.cc b/chrome/browser/download/download_danger_prompt.cc
index 4ec23bc..13d623b 100644
--- a/chrome/browser/download/download_danger_prompt.cc
+++ b/chrome/browser/download/download_danger_prompt.cc
@@ -9,6 +9,7 @@
#include "chrome/browser/chrome_notification_types.h"
#include "chrome/browser/download/chrome_download_manager_delegate.h"
#include "chrome/browser/download/download_stats.h"
+#include "chrome/browser/extensions/api/experience_sampling_private/experience_sampling.h"
#include "chrome/browser/ui/tab_modal_confirm_dialog.h"
#include "chrome/browser/ui/tab_modal_confirm_dialog_delegate.h"
#include "content/public/browser/download_danger_type.h"
@@ -17,6 +18,8 @@
#include "grit/generated_resources.h"
#include "ui/base/l10n/l10n_util.h"
+using extensions::ExperienceSamplingEvent;
+
namespace {
// TODO(wittman): Create a native web contents modal dialog implementation of
@@ -56,6 +59,8 @@ class DownloadDangerPromptImpl : public DownloadDangerPrompt,
bool show_context_;
OnDone done_;
+ scoped_ptr<ExperienceSamplingEvent> sampling_event_;
+
DISALLOW_COPY_AND_ASSIGN(DownloadDangerPromptImpl);
};
@@ -71,6 +76,14 @@ DownloadDangerPromptImpl::DownloadDangerPromptImpl(
DCHECK(!done_.is_null());
download_->AddObserver(this);
RecordOpenedDangerousConfirmDialog(download_->GetDangerType());
+
+ // ExperienceSampling: A malicious download warning is being shown to the
+ // user, so we start a new SamplingEvent and track it.
+ sampling_event_.reset(new ExperienceSamplingEvent(
+ ExperienceSamplingEvent::kDownloadDangerPrompt,
+ download->GetURL(),
+ download->GetReferrerUrl(),
+ download->GetBrowserContext()));
}
DownloadDangerPromptImpl::~DownloadDangerPromptImpl() {
@@ -203,14 +216,20 @@ base::string16 DownloadDangerPromptImpl::GetCancelButtonTitle() {
}
void DownloadDangerPromptImpl::OnAccepted() {
+ // ExperienceSampling: User proceeded through the warning.
+ sampling_event_->CreateUserDecisionEvent(ExperienceSamplingEvent::kProceed);
RunDone(ACCEPT);
}
void DownloadDangerPromptImpl::OnCanceled() {
+ // ExperienceSampling: User canceled the warning.
+ sampling_event_->CreateUserDecisionEvent(ExperienceSamplingEvent::kDeny);
RunDone(CANCEL);
}
void DownloadDangerPromptImpl::OnClosed() {
+ // ExperienceSampling: User canceled the warning.
+ sampling_event_->CreateUserDecisionEvent(ExperienceSamplingEvent::kDeny);
RunDone(DISMISS);
}
diff --git a/chrome/browser/download/download_danger_prompt_browsertest.cc b/chrome/browser/download/download_danger_prompt_browsertest.cc
index 731075d..2b2b57c 100644
--- a/chrome/browser/download/download_danger_prompt_browsertest.cc
+++ b/chrome/browser/download/download_danger_prompt_browsertest.cc
@@ -5,6 +5,7 @@
#include "base/bind.h"
#include "base/files/file_path.h"
#include "chrome/browser/download/download_danger_prompt.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_commands.h"
#include "chrome/browser/ui/browser_tabstrip.h"
@@ -14,11 +15,13 @@
#include "content/public/test/mock_download_item.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
+#include "url/gurl.h"
using ::testing::_;
using ::testing::ByRef;
using ::testing::Eq;
using ::testing::Return;
+using ::testing::ReturnRef;
using ::testing::SaveArg;
class DownloadDangerPromptTest : public InProcessBrowserTest {
@@ -100,6 +103,13 @@ class DownloadDangerPromptTest : public InProcessBrowserTest {
};
IN_PROC_BROWSER_TEST_F(DownloadDangerPromptTest, TestAll) {
+ // ExperienceSampling: Set default actions for DownloadItem methods we need.
+ ON_CALL(download(), GetURL()).WillByDefault(ReturnRef(GURL::EmptyGURL()));
+ ON_CALL(download(), GetReferrerUrl())
+ .WillByDefault(ReturnRef(GURL::EmptyGURL()));
+ ON_CALL(download(), GetBrowserContext())
+ .WillByDefault(Return(browser()->profile()));
+
OpenNewTab();
// Clicking the Accept button should invoke the ACCEPT action.
diff --git a/chrome/browser/extensions/api/experience_sampling_private/experience_sampling.cc b/chrome/browser/extensions/api/experience_sampling_private/experience_sampling.cc
index bda78e1..3bc4371 100644
--- a/chrome/browser/extensions/api/experience_sampling_private/experience_sampling.cc
+++ b/chrome/browser/extensions/api/experience_sampling_private/experience_sampling.cc
@@ -17,10 +17,17 @@ namespace extensions {
// static
const char ExperienceSamplingEvent::kProceed[] = "proceed";
const char ExperienceSamplingEvent::kDeny[] = "deny";
+const char ExperienceSamplingEvent::kIgnore[] = "ignore";
const char ExperienceSamplingEvent::kCancel[] = "cancel";
const char ExperienceSamplingEvent::kReload[] = "reload";
// static
+const char ExperienceSamplingEvent::kMaliciousDownload[] =
+ "download_warning_malicious";
+const char ExperienceSamplingEvent::kDangerousDownload[] =
+ "download_warning_dangerous";
+const char ExperienceSamplingEvent::kDownloadDangerPrompt[] =
+ "download_danger_prompt";
const char ExperienceSamplingEvent::kExtensionInstallDialog[] =
"extension_install_dialog_";
diff --git a/chrome/browser/extensions/api/experience_sampling_private/experience_sampling.h b/chrome/browser/extensions/api/experience_sampling_private/experience_sampling.h
index 3079643..df2f3fc 100644
--- a/chrome/browser/extensions/api/experience_sampling_private/experience_sampling.h
+++ b/chrome/browser/extensions/api/experience_sampling_private/experience_sampling.h
@@ -22,10 +22,14 @@ class ExperienceSamplingEvent {
// String constants for user decision events.
static const char kProceed[];
static const char kDeny[];
+ static const char kIgnore[];
static const char kCancel[];
static const char kReload[];
// String constants for event names.
+ static const char kMaliciousDownload[];
+ static const char kDangerousDownload[];
+ static const char kDownloadDangerPrompt[];
static const char kExtensionInstallDialog[];
// The Create() functions can return an empty scoped_ptr if they cannot find
diff --git a/chrome/browser/ui/cocoa/download/download_item_controller.h b/chrome/browser/ui/cocoa/download/download_item_controller.h
index 78010b6..e9373f3 100644
--- a/chrome/browser/ui/cocoa/download/download_item_controller.h
+++ b/chrome/browser/ui/cocoa/download/download_item_controller.h
@@ -21,6 +21,10 @@ class DownloadItem;
class PageNavigator;
}
+namespace extensions {
+class ExperienceSamplingEvent;
+}
+
namespace gfx {
class FontList;
}
@@ -71,6 +75,10 @@ class MenuModel;
kNormal,
kDangerous
} state_;
+
+ // ExperienceSampling: This tracks dangerous/malicious downloads warning UI
+ // and the user's decisions about it.
+ scoped_ptr<extensions::ExperienceSamplingEvent> sampling_event_;
};
// Initialize controller for |downloadItem|.
diff --git a/chrome/browser/ui/cocoa/download/download_item_controller.mm b/chrome/browser/ui/cocoa/download/download_item_controller.mm
index 430ecbc..3d4a8e6 100644
--- a/chrome/browser/ui/cocoa/download/download_item_controller.mm
+++ b/chrome/browser/ui/cocoa/download/download_item_controller.mm
@@ -14,6 +14,7 @@
#include "chrome/browser/download/chrome_download_manager_delegate.h"
#include "chrome/browser/download/download_item_model.h"
#include "chrome/browser/download/download_shelf_context_menu.h"
+#include "chrome/browser/extensions/api/experience_sampling_private/experience_sampling.h"
#import "chrome/browser/themes/theme_properties.h"
#import "chrome/browser/themes/theme_service.h"
#import "chrome/browser/ui/cocoa/download/download_item_button.h"
@@ -35,6 +36,7 @@
#include "ui/gfx/image/image.h"
using content::DownloadItem;
+using extensions::ExperienceSamplingEvent;
namespace {
@@ -117,6 +119,8 @@ class DownloadShelfContextMenuMac : public DownloadShelfContextMenu {
}
- (void)dealloc {
+ if (sampling_event_.get())
+ sampling_event_->CreateUserDecisionEvent(ExperienceSamplingEvent::kIgnore);
[[NSNotificationCenter defaultCenter] removeObserver:self];
[progressView_ setController:nil];
[[self view] removeFromSuperview];
@@ -144,6 +148,17 @@ class DownloadShelfContextMenuMac : public DownloadShelfContextMenu {
[self setState:kDangerous];
+ // ExperienceSampling: Dangerous or malicious download warning is being shown
+ // to the user, so we start a new SamplingEvent and track it.
+ std::string event_name = downloadModel->MightBeMalicious()
+ ? ExperienceSamplingEvent::kMaliciousDownload
+ : ExperienceSamplingEvent::kDangerousDownload;
+ sampling_event_.reset(new ExperienceSamplingEvent(
+ event_name,
+ downloadModel->download()->GetURL(),
+ downloadModel->download()->GetReferrerUrl(),
+ downloadModel->download()->GetBrowserContext()));
+
ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
NSImage* alertIcon;
@@ -320,6 +335,11 @@ class DownloadShelfContextMenuMac : public DownloadShelfContextMenu {
// user did this to detect whether we're being clickjacked.
UMA_HISTOGRAM_LONG_TIMES("clickjacking.save_download",
base::Time::Now() - creationTime_);
+ // ExperienceSampling: User chose to proceed with dangerous download.
+ if (sampling_event_.get()) {
+ sampling_event_->CreateUserDecisionEvent(ExperienceSamplingEvent::kProceed);
+ sampling_event_.reset(NULL);
+ }
// This will change the state and notify us.
bridge_->download_model()->download()->ValidateDangerousDownload();
}
@@ -333,6 +353,11 @@ class DownloadShelfContextMenuMac : public DownloadShelfContextMenu {
}
- (IBAction)dismissMaliciousDownload:(id)sender {
+ // ExperienceSampling: User dismissed the dangerous download.
+ if (sampling_event_.get()) {
+ sampling_event_->CreateUserDecisionEvent(ExperienceSamplingEvent::kDeny);
+ sampling_event_.reset(NULL);
+ }
[self remove];
// WARNING: we are deleted at this point.
}
diff --git a/chrome/browser/ui/views/download/download_danger_prompt_views.cc b/chrome/browser/ui/views/download/download_danger_prompt_views.cc
index 31f1441..6008dc0 100644
--- a/chrome/browser/ui/views/download/download_danger_prompt_views.cc
+++ b/chrome/browser/ui/views/download/download_danger_prompt_views.cc
@@ -5,6 +5,7 @@
#include "base/compiler_specific.h"
#include "chrome/browser/download/download_danger_prompt.h"
#include "chrome/browser/download/download_stats.h"
+#include "chrome/browser/extensions/api/experience_sampling_private/experience_sampling.h"
#include "chrome/browser/ui/views/constrained_window_views.h"
#include "chrome/grit/chromium_strings.h"
#include "chrome/grit/generated_resources.h"
@@ -21,6 +22,8 @@
#include "ui/views/window/dialog_client_view.h"
#include "ui/views/window/dialog_delegate.h"
+using extensions::ExperienceSamplingEvent;
+
namespace {
const int kMessageWidth = 320;
@@ -69,6 +72,8 @@ class DownloadDangerPromptViews : public DownloadDangerPrompt,
bool show_context_;
OnDone done_;
+ scoped_ptr<ExperienceSamplingEvent> sampling_event_;
+
views::View* contents_view_;
};
@@ -117,6 +122,14 @@ DownloadDangerPromptViews::DownloadDangerPromptViews(
layout->AddView(message_body_label);
RecordOpenedDangerousConfirmDialog(download_->GetDangerType());
+
+ // ExperienceSampling: A malicious download warning is being shown to the
+ // user, so we start a new SamplingEvent and track it.
+ sampling_event_.reset(new ExperienceSamplingEvent(
+ ExperienceSamplingEvent::kDownloadDangerPrompt,
+ item->GetURL(),
+ item->GetReferrerUrl(),
+ item->GetBrowserContext()));
}
// DownloadDangerPrompt methods:
@@ -170,18 +183,24 @@ ui::ModalType DownloadDangerPromptViews::GetModalType() const {
bool DownloadDangerPromptViews::Cancel() {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+ // ExperienceSampling: User canceled the warning.
+ sampling_event_->CreateUserDecisionEvent(ExperienceSamplingEvent::kDeny);
RunDone(CANCEL);
return true;
}
bool DownloadDangerPromptViews::Accept() {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+ // ExperienceSampling: User proceeded through the warning.
+ sampling_event_->CreateUserDecisionEvent(ExperienceSamplingEvent::kProceed);
RunDone(ACCEPT);
return true;
}
bool DownloadDangerPromptViews::Close() {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+ // ExperienceSampling: User canceled the warning.
+ sampling_event_->CreateUserDecisionEvent(ExperienceSamplingEvent::kDeny);
RunDone(DISMISS);
return true;
}
diff --git a/chrome/browser/ui/views/download/download_item_view.cc b/chrome/browser/ui/views/download/download_item_view.cc
index d1f91a1e..3a27c7a 100644
--- a/chrome/browser/ui/views/download/download_item_view.cc
+++ b/chrome/browser/ui/views/download/download_item_view.cc
@@ -23,6 +23,7 @@
#include "chrome/browser/download/download_item_model.h"
#include "chrome/browser/download/download_stats.h"
#include "chrome/browser/download/drag_download_item.h"
+#include "chrome/browser/extensions/api/experience_sampling_private/experience_sampling.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/safe_browsing/download_feedback_service.h"
#include "chrome/browser/safe_browsing/download_protection_service.h"
@@ -54,6 +55,7 @@
#include "ui/views/widget/widget.h"
using content::DownloadItem;
+using extensions::ExperienceSamplingEvent;
// TODO(paulg): These may need to be adjusted when download progress
// animation is added, and also possibly to take into account
@@ -230,6 +232,12 @@ DownloadItemView::DownloadItemView(DownloadItem* download_item,
DownloadItemView::~DownloadItemView() {
StopDownloadProgress();
download()->RemoveObserver(this);
+
+ // ExperienceSampling: If the user took no action to remove the warning
+ // before it disappeared, then the user effectively dismissed the download
+ // without keeping it.
+ if (sampling_event_.get())
+ sampling_event_->CreateUserDecisionEvent(ExperienceSamplingEvent::kIgnore);
}
// Progress animation handlers.
@@ -550,6 +558,12 @@ void DownloadItemView::ButtonPressed(views::Button* sender,
// The user has confirmed a dangerous download. We'd record how quickly the
// user did this to detect whether we're being clickjacked.
UMA_HISTOGRAM_LONG_TIMES("clickjacking.save_download", warning_duration);
+ // ExperienceSampling: User chose to proceed with a dangerous download.
+ if (sampling_event_.get()) {
+ sampling_event_->CreateUserDecisionEvent(
+ ExperienceSamplingEvent::kProceed);
+ sampling_event_.reset(NULL);
+ }
// This will change the state and notify us.
download()->ValidateDangerousDownload();
return;
@@ -559,6 +573,11 @@ void DownloadItemView::ButtonPressed(views::Button* sender,
DCHECK_EQ(discard_button_, sender);
if (model_.IsMalicious()) {
UMA_HISTOGRAM_LONG_TIMES("clickjacking.dismiss_download", warning_duration);
+ // ExperienceSampling: User chose to dismiss the dangerous download.
+ if (sampling_event_.get()) {
+ sampling_event_->CreateUserDecisionEvent(ExperienceSamplingEvent::kDeny);
+ sampling_event_.reset(NULL);
+ }
shelf_->RemoveDownloadView(this);
return;
}
@@ -1127,6 +1146,11 @@ void DownloadItemView::ClearWarningDialog() {
body_state_ = NORMAL;
drop_down_state_ = NORMAL;
+ // ExperienceSampling: User proceeded through the warning.
+ if (sampling_event_.get()) {
+ sampling_event_->CreateUserDecisionEvent(ExperienceSamplingEvent::kProceed);
+ sampling_event_.reset(NULL);
+ }
// Remove the views used by the warning dialog.
if (save_button_) {
RemoveChildView(save_button_);
@@ -1170,6 +1194,17 @@ void DownloadItemView::ShowWarningDialog() {
#endif
mode_ = model_.MightBeMalicious() ? MALICIOUS_MODE : DANGEROUS_MODE;
+ // ExperienceSampling: Dangerous or malicious download warning is being shown
+ // to the user, so we start a new SamplingEvent and track it.
+ std::string event_name = model_.MightBeMalicious()
+ ? ExperienceSamplingEvent::kMaliciousDownload
+ : ExperienceSamplingEvent::kDangerousDownload;
+ sampling_event_.reset(
+ new ExperienceSamplingEvent(event_name,
+ download()->GetURL(),
+ download()->GetReferrerUrl(),
+ download()->GetBrowserContext()));
+
body_state_ = NORMAL;
drop_down_state_ = NORMAL;
if (mode_ == DANGEROUS_MODE) {
diff --git a/chrome/browser/ui/views/download/download_item_view.h b/chrome/browser/ui/views/download/download_item_view.h
index 9920bc4..2dce52f 100644
--- a/chrome/browser/ui/views/download/download_item_view.h
+++ b/chrome/browser/ui/views/download/download_item_view.h
@@ -38,6 +38,10 @@
class DownloadShelfView;
class DownloadShelfContextMenuView;
+namespace extensions {
+class ExperienceSamplingEvent;
+}
+
namespace gfx {
class Image;
class ImageSkia;
@@ -339,6 +343,10 @@ class DownloadItemView : public views::ButtonListener,
// and reload the icon.
base::FilePath last_download_item_path_;
+ // ExperienceSampling: This tracks dangerous/malicious downloads warning UI
+ // and the user's decisions about it.
+ scoped_ptr<extensions::ExperienceSamplingEvent> sampling_event_;
+
DISALLOW_COPY_AND_ASSIGN(DownloadItemView);
};