1// Copyright (c) 2012 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "chrome/browser/ui/webui/metrics_handler.h"
6
7#include "base/bind.h"
8#include "base/bind_helpers.h"
9#include "base/logging.h"
10#include "base/metrics/histogram.h"
11#include "base/strings/utf_string_conversions.h"
12#include "base/values.h"
13#include "chrome/browser/chrome_notification_types.h"
14#include "chrome/browser/metrics/metric_event_duration_details.h"
15#include "chrome/browser/ui/tab_contents/core_tab_helper.h"
16#include "chrome/browser/ui/webui/ntp/ntp_user_data_logger.h"
17#include "chrome/common/ntp_logging_events.h"
18#include "content/public/browser/notification_service.h"
19#include "content/public/browser/user_metrics.h"
20#include "content/public/browser/web_contents.h"
21#include "content/public/browser/web_ui.h"
22
23using base::ListValue;
24using base::UserMetricsAction;
25using content::WebContents;
26
27MetricsHandler::MetricsHandler() {}
28MetricsHandler::~MetricsHandler() {}
29
30void MetricsHandler::RegisterMessages() {
31  web_ui()->RegisterMessageCallback(
32      "metricsHandler:recordAction",
33      base::Bind(&MetricsHandler::HandleRecordAction, base::Unretained(this)));
34  web_ui()->RegisterMessageCallback(
35      "metricsHandler:recordInHistogram",
36      base::Bind(&MetricsHandler::HandleRecordInHistogram,
37                 base::Unretained(this)));
38  web_ui()->RegisterMessageCallback(
39      "metricsHandler:logEventTime",
40      base::Bind(&MetricsHandler::HandleLogEventTime, base::Unretained(this)));
41  web_ui()->RegisterMessageCallback(
42      "metricsHandler:logMouseover",
43      base::Bind(&MetricsHandler::HandleLogMouseover, base::Unretained(this)));
44}
45
46void MetricsHandler::HandleRecordAction(const base::ListValue* args) {
47  std::string string_action = base::UTF16ToUTF8(ExtractStringValue(args));
48  content::RecordComputedAction(string_action);
49}
50
51void MetricsHandler::HandleRecordInHistogram(const base::ListValue* args) {
52  std::string histogram_name;
53  double value;
54  double boundary_value;
55  if (!args->GetString(0, &histogram_name) ||
56      !args->GetDouble(1, &value) ||
57      !args->GetDouble(2, &boundary_value)) {
58    NOTREACHED();
59    return;
60  }
61
62  int int_value = static_cast<int>(value);
63  int int_boundary_value = static_cast<int>(boundary_value);
64  if (int_boundary_value >= 4000 ||
65      int_value > int_boundary_value ||
66      int_value < 0) {
67    NOTREACHED();
68    return;
69  }
70
71  int bucket_count = int_boundary_value;
72  while (bucket_count >= 100) {
73    bucket_count /= 10;
74  }
75
76  // As |histogram_name| may change between calls, the UMA_HISTOGRAM_ENUMERATION
77  // macro cannot be used here.
78  base::HistogramBase* counter =
79      base::LinearHistogram::FactoryGet(
80          histogram_name, 1, int_boundary_value, bucket_count + 1,
81          base::HistogramBase::kUmaTargetedHistogramFlag);
82  counter->Add(int_value);
83}
84
85void MetricsHandler::HandleLogEventTime(const base::ListValue* args) {
86  std::string event_name = base::UTF16ToUTF8(ExtractStringValue(args));
87  WebContents* tab = web_ui()->GetWebContents();
88
89  // Not all new tab pages get timed. In those cases, we don't have a
90  // new_tab_start_time_.
91  CoreTabHelper* core_tab_helper = CoreTabHelper::FromWebContents(tab);
92  if (core_tab_helper->new_tab_start_time().is_null())
93    return;
94
95  base::TimeDelta duration =
96      base::TimeTicks::Now() - core_tab_helper->new_tab_start_time();
97  MetricEventDurationDetails details(event_name,
98      static_cast<int>(duration.InMilliseconds()));
99
100  if (event_name == "Tab.NewTabScriptStart") {
101    UMA_HISTOGRAM_TIMES("Tab.NewTabScriptStart", duration);
102  } else if (event_name == "Tab.NewTabDOMContentLoaded") {
103    UMA_HISTOGRAM_TIMES("Tab.NewTabDOMContentLoaded", duration);
104  } else if (event_name == "Tab.NewTabOnload") {
105    UMA_HISTOGRAM_TIMES("Tab.NewTabOnload", duration);
106    // The new tab page has finished loading; reset it.
107    CoreTabHelper* core_tab_helper = CoreTabHelper::FromWebContents(tab);
108    core_tab_helper->set_new_tab_start_time(base::TimeTicks());
109  } else {
110    NOTREACHED();
111  }
112  content::NotificationService::current()->Notify(
113      chrome::NOTIFICATION_METRIC_EVENT_DURATION,
114      content::Source<WebContents>(tab),
115      content::Details<MetricEventDurationDetails>(&details));
116}
117
118void MetricsHandler::HandleLogMouseover(const base::ListValue* args) {
119#if !defined(OS_ANDROID)
120  // Android uses native UI for NTP.
121  NTPUserDataLogger::GetOrCreateFromWebContents(
122      web_ui()->GetWebContents())->LogEvent(NTP_MOUSEOVER);
123#endif  // !defined(OS_ANDROID)
124}
125