Commit 74893ffe authored by cthomp@chromium.org's avatar cthomp@chromium.org

Experience sampling instrumentation for SSL and Safe Browsing interstitials

This CL instruments the interstitial pages to generate the experience sampling API onDecision event.

BUG=384635

Review URL: https://codereview.chromium.org/399773002

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@288177 0039d316-1c4b-4281-b951-d872f2087c98
parent 546e2e69
...@@ -61,7 +61,7 @@ void ExperienceSamplingEvent::CreateUserDecisionEvent( ...@@ -61,7 +61,7 @@ void ExperienceSamplingEvent::CreateUserDecisionEvent(
const std::string& decision_name) { const std::string& decision_name) {
// Check if this is from an incognito context. If it is, don't create and send // Check if this is from an incognito context. If it is, don't create and send
// any events. // any events.
if (browser_context_->IsOffTheRecord()) if (browser_context_ && browser_context_->IsOffTheRecord())
return; return;
api::experience_sampling_private::UserDecision decision; api::experience_sampling_private::UserDecision decision;
decision.name = decision_name; decision.name = decision_name;
...@@ -74,19 +74,23 @@ void ExperienceSamplingEvent::CreateUserDecisionEvent( ...@@ -74,19 +74,23 @@ void ExperienceSamplingEvent::CreateUserDecisionEvent(
args->Append(decision.ToValue().release()); args->Append(decision.ToValue().release());
scoped_ptr<Event> event(new Event( scoped_ptr<Event> event(new Event(
api::experience_sampling_private::OnDecision::kEventName, args.Pass())); api::experience_sampling_private::OnDecision::kEventName, args.Pass()));
EventRouter::Get(browser_context_)->BroadcastEvent(event.Pass()); EventRouter* router = EventRouter::Get(browser_context_);
if (router)
router->BroadcastEvent(event.Pass());
} }
void ExperienceSamplingEvent::CreateOnDisplayedEvent() { void ExperienceSamplingEvent::CreateOnDisplayedEvent() {
// Check if this is from an incognito context. If it is, don't create and send // Check if this is from an incognito context. If it is, don't create and send
// any events. // any events.
if (browser_context_->IsOffTheRecord()) if (browser_context_ && browser_context_->IsOffTheRecord())
return; return;
scoped_ptr<base::ListValue> args(new base::ListValue()); scoped_ptr<base::ListValue> args(new base::ListValue());
args->Append(ui_element_.ToValue().release()); args->Append(ui_element_.ToValue().release());
scoped_ptr<Event> event(new Event( scoped_ptr<Event> event(new Event(
api::experience_sampling_private::OnDisplayed::kEventName, args.Pass())); api::experience_sampling_private::OnDisplayed::kEventName, args.Pass()));
EventRouter::Get(browser_context_)->BroadcastEvent(event.Pass()); EventRouter* router = EventRouter::Get(browser_context_);
if (router)
router->BroadcastEvent(event.Pass());
} }
} // namespace extensions } // namespace extensions
...@@ -47,6 +47,10 @@ ...@@ -47,6 +47,10 @@
#include "ui/base/webui/jstemplate_builder.h" #include "ui/base/webui/jstemplate_builder.h"
#include "ui/base/webui/web_ui_util.h" #include "ui/base/webui/web_ui_util.h"
#if defined(ENABLE_EXTENSIONS)
#include "chrome/browser/extensions/api/experience_sampling_private/experience_sampling.h"
#endif
using base::UserMetricsAction; using base::UserMetricsAction;
using content::BrowserThread; using content::BrowserThread;
using content::InterstitialPage; using content::InterstitialPage;
...@@ -54,6 +58,10 @@ using content::OpenURLParams; ...@@ -54,6 +58,10 @@ using content::OpenURLParams;
using content::Referrer; using content::Referrer;
using content::WebContents; using content::WebContents;
#if defined(ENABLE_EXTENSIONS)
using extensions::ExperienceSamplingEvent;
#endif
namespace { namespace {
// For malware interstitial pages, we link the problematic URL to Google's // For malware interstitial pages, we link the problematic URL to Google's
...@@ -104,6 +112,15 @@ const char kNavigatedAwayMetaCommand[] = "closed"; ...@@ -104,6 +112,15 @@ const char kNavigatedAwayMetaCommand[] = "closed";
const char kBoxChecked[] = "boxchecked"; const char kBoxChecked[] = "boxchecked";
const char kDisplayCheckBox[] = "displaycheckbox"; const char kDisplayCheckBox[] = "displaycheckbox";
// Constants for the Experience Sampling instrumentation.
#if defined(ENABLE_EXTENSIONS)
const char kEventNameMalware[] = "safebrowsing_interstitial_";
const char kEventNamePhishing[] = "phishing_interstitial_";
const char kEventNameMalwareAndPhishing[] =
"malware_and_phishing_interstitial_";
const char kEventNameOther[] = "safebrowsing_other_interstitial_";
#endif
base::LazyInstance<SafeBrowsingBlockingPage::UnsafeResourceMap> base::LazyInstance<SafeBrowsingBlockingPage::UnsafeResourceMap>
g_unsafe_resource_map = LAZY_INSTANCE_INITIALIZER; g_unsafe_resource_map = LAZY_INSTANCE_INITIALIZER;
...@@ -295,6 +312,32 @@ SafeBrowsingBlockingPage::SafeBrowsingBlockingPage( ...@@ -295,6 +312,32 @@ SafeBrowsingBlockingPage::SafeBrowsingBlockingPage(
malware_details_ = MalwareDetails::NewMalwareDetails( malware_details_ = MalwareDetails::NewMalwareDetails(
ui_manager_, web_contents, unsafe_resources[0]); ui_manager_, web_contents, unsafe_resources[0]);
} }
#if defined(ENABLE_EXTENSIONS)
// ExperienceSampling: Set up new sampling event for this interstitial.
// This needs to handle all types of warnings this interstitial can show.
std::string event_name;
switch (interstitial_type_) {
case TYPE_MALWARE_AND_PHISHING:
event_name = kEventNameMalwareAndPhishing;
break;
case TYPE_MALWARE:
event_name = kEventNameMalware;
break;
case TYPE_PHISHING:
event_name = kEventNamePhishing;
break;
default:
event_name = kEventNameOther;
break;
}
sampling_event_.reset(new ExperienceSamplingEvent(
event_name,
url_,
web_contents_->GetLastCommittedURL(),
web_contents_->GetBrowserContext()));
#endif
// Creating interstitial_page_ without showing it leaks memory, so don't // Creating interstitial_page_ without showing it leaks memory, so don't
// create it here. // create it here.
} }
...@@ -328,6 +371,10 @@ void SafeBrowsingBlockingPage::CommandReceived(const std::string& cmd) { ...@@ -328,6 +371,10 @@ void SafeBrowsingBlockingPage::CommandReceived(const std::string& cmd) {
// User pressed "Learn more". // User pressed "Learn more".
GURL url(interstitial_type_ == TYPE_PHISHING ? GURL url(interstitial_type_ == TYPE_PHISHING ?
kLearnMorePhishingUrlV2 : kLearnMoreMalwareUrlV2); kLearnMorePhishingUrlV2 : kLearnMoreMalwareUrlV2);
#if defined(ENABLE_EXTENSIONS)
if (sampling_event_.get())
sampling_event_->set_has_viewed_learn_more(true);
#endif
OpenURLParams params( OpenURLParams params(
url, Referrer(), CURRENT_TAB, content::PAGE_TRANSITION_LINK, false); url, Referrer(), CURRENT_TAB, content::PAGE_TRANSITION_LINK, false);
web_contents_->OpenURL(params); web_contents_->OpenURL(params);
...@@ -441,6 +488,12 @@ void SafeBrowsingBlockingPage::CommandReceived(const std::string& cmd) { ...@@ -441,6 +488,12 @@ void SafeBrowsingBlockingPage::CommandReceived(const std::string& cmd) {
// User expanded the "see more info" section of the page. We don't actually // User expanded the "see more info" section of the page. We don't actually
// do any action based on this, it's just so that RecordUserReactionTime can // do any action based on this, it's just so that RecordUserReactionTime can
// track it. // track it.
#if defined(ENABLE_EXTENSIONS)
// ExperienceSampling: We track that the user expanded the details.
if (sampling_event_.get())
sampling_event_->set_has_viewed_details(true);
#endif
return; return;
} }
...@@ -504,6 +557,12 @@ void SafeBrowsingBlockingPage::OnProceed() { ...@@ -504,6 +557,12 @@ void SafeBrowsingBlockingPage::OnProceed() {
unsafe_resource_map->erase(iter); unsafe_resource_map->erase(iter);
} }
#if defined(ENABLE_EXTENSIONS)
// ExperienceSampling: Notify that user decided to proceed.
if (sampling_event_.get())
sampling_event_->CreateUserDecisionEvent(ExperienceSamplingEvent::kProceed);
#endif
// Now that this interstitial is gone, we can show the new one. // Now that this interstitial is gone, we can show the new one.
if (blocking_page) if (blocking_page)
blocking_page->Show(); blocking_page->Show();
...@@ -560,6 +619,13 @@ void SafeBrowsingBlockingPage::OnDontProceed() { ...@@ -560,6 +619,13 @@ void SafeBrowsingBlockingPage::OnDontProceed() {
navigation_entry_index_to_remove_)); navigation_entry_index_to_remove_));
navigation_entry_index_to_remove_ = -1; navigation_entry_index_to_remove_ = -1;
} }
#if defined(ENABLE_EXTENSIONS)
// ExperienceSampling: Notify that user decided to go back.
// This also occurs if the user navigates away or closes the tab.
if (sampling_event_.get())
sampling_event_->CreateUserDecisionEvent(ExperienceSamplingEvent::kDeny);
#endif
} }
void SafeBrowsingBlockingPage::OnGotHistoryCount(bool success, void SafeBrowsingBlockingPage::OnGotHistoryCount(bool success,
......
...@@ -53,6 +53,12 @@ class InterstitialPage; ...@@ -53,6 +53,12 @@ class InterstitialPage;
class WebContents; class WebContents;
} }
#if defined(ENABLE_EXTENSIONS)
namespace extensions {
class ExperienceSamplingEvent;
}
#endif
class SafeBrowsingBlockingPage : public content::InterstitialPageDelegate { class SafeBrowsingBlockingPage : public content::InterstitialPageDelegate {
public: public:
typedef SafeBrowsingUIManager::UnsafeResource UnsafeResource; typedef SafeBrowsingUIManager::UnsafeResource UnsafeResource;
...@@ -233,6 +239,11 @@ class SafeBrowsingBlockingPage : public content::InterstitialPageDelegate { ...@@ -233,6 +239,11 @@ class SafeBrowsingBlockingPage : public content::InterstitialPageDelegate {
int num_visits_; int num_visits_;
base::CancelableTaskTracker request_tracker_; base::CancelableTaskTracker request_tracker_;
private:
#if defined(ENABLE_EXTENSIONS)
scoped_ptr<extensions::ExperienceSamplingEvent> sampling_event_;
#endif
DISALLOW_COPY_AND_ASSIGN(SafeBrowsingBlockingPage); DISALLOW_COPY_AND_ASSIGN(SafeBrowsingBlockingPage);
}; };
......
...@@ -51,6 +51,10 @@ ...@@ -51,6 +51,10 @@
#include "chrome/browser/captive_portal/captive_portal_service_factory.h" #include "chrome/browser/captive_portal/captive_portal_service_factory.h"
#endif #endif
#if defined(ENABLE_EXTENSIONS)
#include "chrome/browser/extensions/api/experience_sampling_private/experience_sampling.h"
#endif
#if defined(OS_WIN) #if defined(OS_WIN)
#include "base/base_paths_win.h" #include "base/base_paths_win.h"
#include "base/path_service.h" #include "base/path_service.h"
...@@ -70,8 +74,19 @@ using content::InterstitialPage; ...@@ -70,8 +74,19 @@ using content::InterstitialPage;
using content::NavigationController; using content::NavigationController;
using content::NavigationEntry; using content::NavigationEntry;
#if defined(ENABLE_EXTENSIONS)
using extensions::ExperienceSamplingEvent;
#endif
namespace { namespace {
// Constants for the Experience Sampling instrumentation.
#if defined(ENABLE_EXTENSIONS)
const char kEventNameBase[] = "ssl_interstitial_";
const char kEventNotOverridable[] = "notoverridable_";
const char kEventOverridable[] = "overridable_";
#endif
// Events for UMA. Do not reorder or change! // Events for UMA. Do not reorder or change!
enum SSLBlockingPageEvent { enum SSLBlockingPageEvent {
SHOW_ALL, SHOW_ALL,
...@@ -329,6 +344,21 @@ SSLBlockingPage::SSLBlockingPage( ...@@ -329,6 +344,21 @@ SSLBlockingPage::SSLBlockingPage(
content::Source<Profile>(profile)); content::Source<Profile>(profile));
#endif #endif
#if defined(ENABLE_EXTENSIONS)
// ExperienceSampling: Set up new sampling event for this interstitial.
std::string event_name(kEventNameBase);
if (overridable_ && !strict_enforcement_)
event_name.append(kEventOverridable);
else
event_name.append(kEventNotOverridable);
event_name.append(net::ErrorToString(cert_error_));
sampling_event_.reset(new ExperienceSamplingEvent(
event_name,
request_url_,
web_contents_->GetLastCommittedURL(),
web_contents_->GetBrowserContext()));
#endif
// Creating an interstitial without showing (e.g. from chrome://interstitials) // Creating an interstitial without showing (e.g. from chrome://interstitials)
// it leaks memory, so don't create it here. // it leaks memory, so don't create it here.
} }
...@@ -486,6 +516,10 @@ void SSLBlockingPage::CommandReceived(const std::string& command) { ...@@ -486,6 +516,10 @@ void SSLBlockingPage::CommandReceived(const std::string& command) {
} }
case CMD_MORE: { case CMD_MORE: {
RecordSSLBlockingPageEventStats(MORE); RecordSSLBlockingPageEventStats(MORE);
#if defined(ENABLE_EXTENSIONS)
if (sampling_event_.get())
sampling_event_->set_has_viewed_details(true);
#endif
break; break;
} }
case CMD_RELOAD: { case CMD_RELOAD: {
...@@ -496,6 +530,10 @@ void SSLBlockingPage::CommandReceived(const std::string& command) { ...@@ -496,6 +530,10 @@ void SSLBlockingPage::CommandReceived(const std::string& command) {
case CMD_HELP: { case CMD_HELP: {
content::NavigationController::LoadURLParams help_page_params(GURL( content::NavigationController::LoadURLParams help_page_params(GURL(
"https://support.google.com/chrome/answer/4454607")); "https://support.google.com/chrome/answer/4454607"));
#if defined(ENABLE_EXTENSIONS)
if (sampling_event_.get())
sampling_event_->set_has_viewed_learn_more(true);
#endif
web_contents_->GetController().LoadURLWithParams(help_page_params); web_contents_->GetController().LoadURLWithParams(help_page_params);
break; break;
} }
...@@ -526,6 +564,11 @@ void SSLBlockingPage::OnProceed() { ...@@ -526,6 +564,11 @@ void SSLBlockingPage::OnProceed() {
captive_portal_probe_completed_, captive_portal_probe_completed_,
captive_portal_no_response_, captive_portal_no_response_,
captive_portal_detected_); captive_portal_detected_);
#if defined(ENABLE_EXTENSIONS)
// ExperienceSampling: Notify that user decided to proceed.
if (sampling_event_.get())
sampling_event_->CreateUserDecisionEvent(ExperienceSamplingEvent::kProceed);
#endif
// Accepting the certificate resumes the loading of the page. // Accepting the certificate resumes the loading of the page.
NotifyAllowCertificate(); NotifyAllowCertificate();
} }
...@@ -540,6 +583,12 @@ void SSLBlockingPage::OnDontProceed() { ...@@ -540,6 +583,12 @@ void SSLBlockingPage::OnDontProceed() {
captive_portal_probe_completed_, captive_portal_probe_completed_,
captive_portal_no_response_, captive_portal_no_response_,
captive_portal_detected_); captive_portal_detected_);
#if defined(ENABLE_EXTENSIONS)
// ExperienceSampling: Notify that user decided to not proceed.
// This also occurs if the user navigates away or closes the tab.
if (sampling_event_.get())
sampling_event_->CreateUserDecisionEvent(ExperienceSamplingEvent::kDeny);
#endif
NotifyDenyCertificate(); NotifyDenyCertificate();
} }
......
...@@ -26,6 +26,12 @@ class InterstitialPage; ...@@ -26,6 +26,12 @@ class InterstitialPage;
class WebContents; class WebContents;
} }
#if defined(ENABLE_EXTENSIONS)
namespace extensions {
class ExperienceSamplingEvent;
}
#endif
// This class is responsible for showing/hiding the interstitial page that is // This class is responsible for showing/hiding the interstitial page that is
// shown when a certificate error happens. // shown when a certificate error happens.
// It deletes itself when the interstitial page is closed. // It deletes itself when the interstitial page is closed.
...@@ -121,6 +127,14 @@ class SSLBlockingPage : public content::InterstitialPageDelegate, ...@@ -121,6 +127,14 @@ class SSLBlockingPage : public content::InterstitialPageDelegate,
// Was a captive portal detected? // Was a captive portal detected?
bool captive_portal_detected_; bool captive_portal_detected_;
// For the FieldTrial: this contains the name of the condition.
std::string trial_condition_;
#if defined(ENABLE_EXTENSIONS)
// For Chrome Experience Sampling Platform: this maintains event state.
scoped_ptr<extensions::ExperienceSamplingEvent> sampling_event_;
#endif
content::NotificationRegistrar registrar_; content::NotificationRegistrar registrar_;
DISALLOW_COPY_AND_ASSIGN(SSLBlockingPage); DISALLOW_COPY_AND_ASSIGN(SSLBlockingPage);
......
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