diff options
author | cthomp@chromium.org <cthomp@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-08-16 01:10:16 +0000 |
---|---|---|
committer | cthomp@chromium.org <cthomp@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-08-16 01:10:16 +0000 |
commit | 07c973f756ff41198cab01f7d2abd2ff8a123eae (patch) | |
tree | 9bce76d9e36667070459520cede6447f086a8215 | |
parent | 9af1231d969ee9b215d1a02f0155f9aae9e18910 (diff) | |
download | chromium_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
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); }; |