blob: d4f23c3351322a4c6175428483cb6ec31c729898 [file] [log] [blame]
// Copyright 2013 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 "chrome/browser/ui/sad_tab.h"
#include "base/metrics/histogram_macros.h"
#include "chrome/browser/net/referrer.h"
#include "chrome/browser/ui/browser_finder.h"
#include "chrome/browser/ui/chrome_pages.h"
#include "chrome/common/url_constants.h"
#include "chrome/grit/generated_resources.h"
#include "components/feedback/feedback_util.h"
#include "components/strings/grit/components_strings.h"
#include "content/public/browser/navigation_controller.h"
#include "content/public/browser/web_contents.h"
#include "ui/base/l10n/l10n_util.h"
#if defined(OS_CHROMEOS)
#include "chrome/browser/memory/oom_memory_details.h"
#endif
namespace {
// These stats should use the same counting approach and bucket size as tab
// discard events in memory::OomPriorityManager so they can be directly
// compared.
// This macro uses a static counter to track how many times it's hit in a
// session. See Tabs.SadTab.CrashCreated in histograms.xml for details.
#define UMA_SAD_TAB_COUNTER(histogram_name) \
{ \
static int count = 0; \
++count; \
UMA_HISTOGRAM_COUNTS_1000(histogram_name, count); \
}
// This enum backs an UMA histogram, so it should be treated as append-only.
enum SadTabEvent {
DISPLAYED,
BUTTON_CLICKED,
HELP_LINK_CLICKED,
MAX_SAD_TAB_EVENT
};
void RecordEvent(bool feedback, SadTabEvent event) {
if (feedback) {
UMA_HISTOGRAM_ENUMERATION("Tabs.SadTab.Feedback.Event", event,
SadTabEvent::MAX_SAD_TAB_EVENT);
} else {
UMA_HISTOGRAM_ENUMERATION("Tabs.SadTab.Reload.Event", event,
SadTabEvent::MAX_SAD_TAB_EVENT);
}
}
const char kCategoryTagCrash[] = "Crash";
bool ShouldShowFeedbackButton() {
#if defined(GOOGLE_CHROME_BUILD)
const int kCrashesBeforeFeedbackIsDisplayed = 1;
static int total_crashes = 0;
return ++total_crashes > kCrashesBeforeFeedbackIsDisplayed;
#else
return false;
#endif
}
} // namespace
namespace chrome {
// static
bool SadTab::ShouldShow(base::TerminationStatus status) {
switch (status) {
case base::TERMINATION_STATUS_ABNORMAL_TERMINATION:
case base::TERMINATION_STATUS_PROCESS_WAS_KILLED:
#if defined(OS_CHROMEOS)
case base::TERMINATION_STATUS_PROCESS_WAS_KILLED_BY_OOM:
#endif
case base::TERMINATION_STATUS_PROCESS_CRASHED:
case base::TERMINATION_STATUS_OOM:
return true;
case base::TERMINATION_STATUS_NORMAL_TERMINATION:
case base::TERMINATION_STATUS_STILL_RUNNING:
#if defined(OS_ANDROID)
case base::TERMINATION_STATUS_OOM_PROTECTED:
#endif
case base::TERMINATION_STATUS_LAUNCH_FAILED:
case base::TERMINATION_STATUS_MAX_ENUM:
return false;
}
NOTREACHED();
return false;
}
int SadTab::GetTitle() {
return IDS_SAD_TAB_TITLE;
}
int SadTab::GetMessage() {
switch (kind_) {
#if defined(OS_CHROMEOS)
case chrome::SAD_TAB_KIND_KILLED_BY_OOM:
return IDS_KILLED_TAB_BY_OOM_MESSAGE;
#endif
case chrome::SAD_TAB_KIND_OOM:
return IDS_SAD_TAB_OOM_MESSAGE;
case chrome::SAD_TAB_KIND_CRASHED:
case chrome::SAD_TAB_KIND_KILLED:
return IDS_SAD_TAB_MESSAGE;
}
NOTREACHED();
return 0;
}
int SadTab::GetButtonTitle() {
return show_feedback_button_ ? IDS_CRASHED_TAB_FEEDBACK_LINK
: IDS_SAD_TAB_RELOAD_LABEL;
}
int SadTab::GetHelpLinkTitle() {
return IDS_SAD_TAB_LEARN_MORE_LINK;
}
const char* SadTab::GetHelpLinkURL() {
return show_feedback_button_ ? chrome::kCrashReasonFeedbackDisplayedURL
: chrome::kCrashReasonURL;
}
void SadTab::RecordFirstPaint() {
DCHECK(!recorded_paint_);
recorded_paint_ = true;
switch (kind_) {
case chrome::SAD_TAB_KIND_CRASHED:
UMA_SAD_TAB_COUNTER("Tabs.SadTab.CrashDisplayed");
break;
case chrome::SAD_TAB_KIND_OOM:
UMA_SAD_TAB_COUNTER("Tabs.SadTab.OomDisplayed");
break;
#if defined(OS_CHROMEOS)
case chrome::SAD_TAB_KIND_KILLED_BY_OOM:
UMA_SAD_TAB_COUNTER("Tabs.SadTab.KillDisplayed.OOM");
#endif
// Fallthrough
case chrome::SAD_TAB_KIND_KILLED:
UMA_SAD_TAB_COUNTER("Tabs.SadTab.KillDisplayed");
break;
}
RecordEvent(show_feedback_button_, SadTabEvent::DISPLAYED);
}
void SadTab::PerformAction(SadTab::Action action) {
DCHECK(recorded_paint_);
switch (action) {
case Action::BUTTON:
RecordEvent(show_feedback_button_, SadTabEvent::BUTTON_CLICKED);
if (show_feedback_button_) {
chrome::ShowFeedbackPage(
chrome::FindBrowserWithWebContents(web_contents_),
l10n_util::GetStringUTF8(kind_ == chrome::SAD_TAB_KIND_CRASHED
? IDS_CRASHED_TAB_FEEDBACK_MESSAGE
: IDS_KILLED_TAB_FEEDBACK_MESSAGE),
std::string(kCategoryTagCrash));
} else {
web_contents_->GetController().Reload(true);
}
break;
case Action::HELP_LINK:
RecordEvent(show_feedback_button_, SadTabEvent::HELP_LINK_CLICKED);
content::OpenURLParams params(GURL(GetHelpLinkURL()), content::Referrer(),
WindowOpenDisposition::CURRENT_TAB,
ui::PAGE_TRANSITION_LINK, false);
web_contents_->OpenURL(params);
break;
}
}
SadTab::SadTab(content::WebContents* web_contents, SadTabKind kind)
: web_contents_(web_contents),
kind_(kind),
show_feedback_button_(ShouldShowFeedbackButton()),
recorded_paint_(false) {
switch (kind) {
case chrome::SAD_TAB_KIND_CRASHED:
UMA_SAD_TAB_COUNTER("Tabs.SadTab.CrashCreated");
break;
case chrome::SAD_TAB_KIND_OOM:
UMA_SAD_TAB_COUNTER("Tabs.SadTab.OomCreated");
break;
#if defined(OS_CHROMEOS)
case chrome::SAD_TAB_KIND_KILLED_BY_OOM:
UMA_SAD_TAB_COUNTER("Tabs.SadTab.KillCreated.OOM");
{
const std::string spec = web_contents->GetURL().GetOrigin().spec();
memory::OomMemoryDetails::Log(
"Tab OOM-Killed Memory details: " + spec + ", ", base::Closure());
}
#endif
// Fall through
case chrome::SAD_TAB_KIND_KILLED:
UMA_SAD_TAB_COUNTER("Tabs.SadTab.KillCreated");
LOG(WARNING) << "Tab Killed: "
<< web_contents->GetURL().GetOrigin().spec();
break;
}
}
} // namespace chrome