summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorsheckylin@chromium.org <sheckylin@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-06-20 02:38:56 +0000
committersheckylin@chromium.org <sheckylin@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-06-20 02:38:56 +0000
commit2a21916a362be898ccc9c8a63cd44b9ee99b7d92 (patch)
tree28f704b4224bed6bb410f8b25672c3e1c0ebaead
parente2713728a6f7b9c5275e1b390f17309f72e7804a (diff)
downloadchromium_src-2a21916a362be898ccc9c8a63cd44b9ee99b7d92.zip
chromium_src-2a21916a362be898ccc9c8a63cd44b9ee99b7d92.tar.gz
chromium_src-2a21916a362be898ccc9c8a63cd44b9ee99b7d92.tar.bz2
Add support for cros touchpad metrics gesture
The patch adds functions to parse the cros touchpad metrics gesture. We use metrics gestures to wrap interesting patterns that are found during the trackpad usage. Those instances are then reported in Chrome via the UMA system. We couldn't do this at the cros level due to the malloc/free deadlock problem in interrrupt handlers. To watch the metrics gestures, we add an observer class DeviceUMA and register it in ChromeBrowserMainPartsChromeos upon startup. The class would then catch the gestures and report them through UMA. Contributed by sheckylin@chromium.org BUG=237683 TEST=Tested on device. Change-Id: I5ff3e13663dc60115dced38fbd0d70c1caf3f3a7 Review URL: https://chromiumcodereview.appspot.com/16347008 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@207280 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--chrome/browser/chromeos/chrome_browser_main_chromeos.cc14
-rw-r--r--chrome/browser/chromeos/device_uma.cc111
-rw-r--r--chrome/browser/chromeos/device_uma.h53
-rw-r--r--chrome/chrome_browser_chromeos.gypi8
-rw-r--r--tools/metrics/histograms/histograms.xml17
-rw-r--r--ui/aura/root_window_host_x11.cc2
-rw-r--r--ui/base/events/event.cc1
-rw-r--r--ui/base/events/event_constants.h4
-rw-r--r--ui/base/x/device_data_manager.cc46
-rw-r--r--ui/base/x/device_data_manager.h19
-rw-r--r--ui/base/x/events_x.cc3
11 files changed, 277 insertions, 1 deletions
diff --git a/chrome/browser/chromeos/chrome_browser_main_chromeos.cc b/chrome/browser/chromeos/chrome_browser_main_chromeos.cc
index d34fd61..dd0ad54 100644
--- a/chrome/browser/chromeos/chrome_browser_main_chromeos.cc
+++ b/chrome/browser/chromeos/chrome_browser_main_chromeos.cc
@@ -120,6 +120,11 @@
#include "net/url_request/url_request.h"
#include "net/url_request/url_request_context_getter.h"
+// Exclude X11 dependents for ozone
+#if defined(USE_X11)
+#include "chrome/browser/chromeos/device_uma.h"
+#endif
+
namespace chromeos {
namespace {
@@ -721,6 +726,11 @@ void ChromeBrowserMainPartsChromeos::PreBrowserStart() {
// reasons, see http://crosbug.com/24833.
XInputHierarchyChangedEventListener::GetInstance();
+#if defined(USE_X11)
+ // Start the CrOS input device UMA watcher
+ DeviceUMA::GetInstance();
+#endif
+
// -- This used to be in ChromeBrowserMainParts::PreMainMessageLoopRun()
// -- immediately after ChildProcess::WaitForDebugger().
@@ -791,6 +801,10 @@ void ChromeBrowserMainPartsChromeos::PostMainMessageLoopRun() {
// Singletons are finally destroyed in AtExitManager.
XInputHierarchyChangedEventListener::GetInstance()->Stop();
+#if defined(USE_X11)
+ DeviceUMA::GetInstance()->Stop();
+#endif
+
// SystemKeyEventListener::Shutdown() is always safe to call,
// even if Initialize() wasn't called.
SystemKeyEventListener::Shutdown();
diff --git a/chrome/browser/chromeos/device_uma.cc b/chrome/browser/chromeos/device_uma.cc
new file mode 100644
index 0000000..2f852bb
--- /dev/null
+++ b/chrome/browser/chromeos/device_uma.cc
@@ -0,0 +1,111 @@
+// 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/chromeos/device_uma.h"
+
+#include <X11/extensions/XInput.h>
+#include <X11/extensions/XInput2.h>
+
+#include "base/logging.h"
+#include "base/memory/singleton.h"
+#include "base/metrics/histogram.h"
+#include "ui/base/events/event_constants.h"
+#include "ui/base/events/event_utils.h"
+#include "ui/base/x/device_data_manager.h"
+
+// Enum type for CrOS gesture lib UMA
+enum UMACrosGestureMetricsType{
+ // To give an estimated number of all interested events.
+ UMA_CROS_GESTURE_METRICS_ALL_EVENTS,
+ UMA_CROS_GESTURE_METRICS_NOISY_GROUND,
+ // NOTE: Add states only immediately above this line. Make sure to
+ // update the enum list in tools/metrics/histograms/histograms.xml
+ // accordingly.
+ UMA_CROS_GESTURE_METRICS_COUNT
+};
+
+namespace chromeos {
+
+DeviceUMA* DeviceUMA::GetInstance() {
+ return Singleton<DeviceUMA>::get();
+}
+
+DeviceUMA::DeviceUMA()
+ :is_observing_(false) {
+ AddMessageLoopObserver();
+}
+
+DeviceUMA::~DeviceUMA() {
+ RemoveMessageLoopObserver();
+}
+
+void DeviceUMA::Stop() {
+ RemoveMessageLoopObserver();
+}
+
+void DeviceUMA::AddMessageLoopObserver() {
+ if (!is_observing_) {
+ base::MessageLoopForUI::current()->AddObserver(this);
+ is_observing_ = true;
+ }
+}
+
+void DeviceUMA::RemoveMessageLoopObserver() {
+ if (is_observing_) {
+ base::MessageLoopForUI::current()->RemoveObserver(this);
+ is_observing_ = false;
+ }
+}
+
+base::EventStatus DeviceUMA::WillProcessEvent(
+ const base::NativeEvent& event) {
+ CheckIncomingEvent(event);
+ return base::EVENT_CONTINUE;
+}
+
+void DeviceUMA::DidProcessEvent(
+ const base::NativeEvent& event) {
+}
+
+void DeviceUMA::CheckTouchpadEvent(const base::NativeEvent& native_event) {
+ XIDeviceEvent* xiev =
+ static_cast<XIDeviceEvent*>(native_event->xcookie.data);
+ // We take only the slave event since there is no need to count twice.
+ if (xiev->deviceid != xiev->sourceid)
+ return;
+ UMA_HISTOGRAM_ENUMERATION("Touchpad.Metrics",
+ UMA_CROS_GESTURE_METRICS_ALL_EVENTS,
+ UMA_CROS_GESTURE_METRICS_COUNT);
+
+ // Check for the CrOS touchpad metrics gesture
+ ui::DeviceDataManager *manager = ui::DeviceDataManager::GetInstance();
+ if (manager->IsCMTMetricsEvent(native_event)) {
+ ui::GestureMetricsType type;
+ float data1, data2;
+ manager->GetMetricsData(native_event, &type, &data1, &data2);
+
+ // We currently track only the noisy ground issue. Please see
+ // http://crbug.com/237683.
+ if (type == ui::kGestureMetricsTypeNoisyGround) {
+ UMA_HISTOGRAM_ENUMERATION("Touchpad.Metrics",
+ UMA_CROS_GESTURE_METRICS_NOISY_GROUND,
+ UMA_CROS_GESTURE_METRICS_COUNT);
+ }
+ }
+}
+
+void DeviceUMA::CheckIncomingEvent(const base::NativeEvent& event) {
+ switch (event->type) {
+ case GenericEvent: {
+ if (ui::IsTouchpadEvent(event))
+ CheckTouchpadEvent(event);
+ break;
+ }
+ default:
+ break;
+ }
+ return;
+}
+
+} // namespace chromeos
diff --git a/chrome/browser/chromeos/device_uma.h b/chrome/browser/chromeos/device_uma.h
new file mode 100644
index 0000000..77f7543
--- /dev/null
+++ b/chrome/browser/chromeos/device_uma.h
@@ -0,0 +1,53 @@
+// 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.
+
+#ifndef CHROME_BROWSER_CHROMEOS_DEVICE_UMA_H_
+#define CHROME_BROWSER_CHROMEOS_DEVICE_UMA_H_
+
+#include "base/basictypes.h"
+#include "base/event_types.h"
+#include "base/message_loop.h"
+
+template <typename T> struct DefaultSingletonTraits;
+
+namespace chromeos {
+
+// A class to record devices' input event details via the UMA system
+class DeviceUMA : public base::MessageLoopForUI::Observer {
+ public:
+ // Getting instance starts the class automatically if it hasn't been
+ // started before.
+ static DeviceUMA* GetInstance();
+
+ void Stop();
+
+ private:
+ friend struct DefaultSingletonTraits<DeviceUMA>;
+
+ DeviceUMA();
+ virtual ~DeviceUMA();
+
+ // Start and stop observing events.
+ void AddMessageLoopObserver();
+ void RemoveMessageLoopObserver();
+
+ // MessageLoopForUI::Observer overrides.
+ virtual base::EventStatus WillProcessEvent(
+ const base::NativeEvent& event) OVERRIDE;
+ virtual void DidProcessEvent(const base::NativeEvent& event) OVERRIDE;
+
+ // Check CrOS touchpad events to see if the metrics gesture is present
+ void CheckTouchpadEvent(const base::NativeEvent& event);
+
+ // Check the incoming events for interesting patterns that we care about.
+ void CheckIncomingEvent(const base::NativeEvent& event);
+
+ bool is_observing_;
+
+ DISALLOW_COPY_AND_ASSIGN(DeviceUMA);
+};
+
+} // namespace chromeos
+
+#endif // CHROME_BROWSER_CHROMEOS_DEVICE_UMA_H_
diff --git a/chrome/chrome_browser_chromeos.gypi b/chrome/chrome_browser_chromeos.gypi
index 6872360..9bbfca7 100644
--- a/chrome/chrome_browser_chromeos.gypi
+++ b/chrome/chrome_browser_chromeos.gypi
@@ -211,6 +211,8 @@
'browser/chromeos/dbus/proxy_resolution_service_provider.cc',
'browser/chromeos/dbus/proxy_resolution_service_provider.h',
'browser/chromeos/device_hierarchy_observer.h',
+ 'browser/chromeos/device_uma.cc',
+ 'browser/chromeos/device_uma.h',
'browser/chromeos/drive/change_list_loader.cc',
'browser/chromeos/drive/change_list_loader.h',
'browser/chromeos/drive/change_list_loader_observer.h',
@@ -823,6 +825,12 @@
'browser/chromeos/extensions/wallpaper_private_api.h',
],
}],
+ ['use_x11==0', {
+ 'sources!': [
+ 'browser/chromeos/device_uma.cc',
+ 'browser/chromeos/device_uma.h',
+ ],
+ }],
['use_cras==1', {
'cflags': [
'<!@(<(pkg-config) --cflags libcras)',
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml
index 454e7c7..27b364f 100644
--- a/tools/metrics/histograms/histograms.xml
+++ b/tools/metrics/histograms/histograms.xml
@@ -11167,6 +11167,13 @@ other types of suffix sets.
<summary>Tracks touchpad device state.</summary>
</histogram>
+<histogram name="Touchpad.Metrics" enum="TouchpadProblemType">
+ <summary>
+ Tracks unusual CrOS touchpad operational states (e.g. running into the noisy
+ ground issue). This is sampled at every touchpad event.
+ </summary>
+</histogram>
+
<histogram name="Touchpad.NaturalScroll.Changed" enum="BooleanEnabled">
<summary>Tracks touchpad natural scroll setting changes by the user.</summary>
</histogram>
@@ -17882,6 +17889,16 @@ other types of suffix sets.
</int>
</enum>
+<enum name="TouchpadProblemType" type="int">
+ <int value="0" label="All events">
+ All observed input events from touchpad. Serves as a reference.
+ </int>
+ <int value="1" label="Noisy Ground">
+ The touchpad noise events (e.g. abrupt cursor jumps) caused by the noisy
+ ground.
+ </int>
+</enum>
+
<enum name="TranslateError" type="int">
<int value="0" label="No error"/>
<int value="1" label="Network error"/>
diff --git a/ui/aura/root_window_host_x11.cc b/ui/aura/root_window_host_x11.cc
index f827373..6606ea2 100644
--- a/ui/aura/root_window_host_x11.cc
+++ b/ui/aura/root_window_host_x11.cc
@@ -1027,6 +1027,8 @@ void RootWindowHostX11::DispatchXI2Event(const base::NativeEvent& event) {
delegate_->OnHostScrollEvent(&scrollev);
break;
}
+ case ui::ET_UMA_DATA:
+ break;
case ui::ET_UNKNOWN:
break;
default:
diff --git a/ui/base/events/event.cc b/ui/base/events/event.cc
index 40b5639..b69780c 100644
--- a/ui/base/events/event.cc
+++ b/ui/base/events/event.cc
@@ -95,6 +95,7 @@ std::string EventTypeName(ui::EventType type) {
CASE_TYPE(ET_SCROLL_FLING_START);
CASE_TYPE(ET_SCROLL_FLING_CANCEL);
CASE_TYPE(ET_CANCEL_MODE);
+ CASE_TYPE(ET_UMA_DATA);
case ui::ET_LAST: NOTREACHED(); return std::string();
// Don't include default, so that we get an error when new type is added.
}
diff --git a/ui/base/events/event_constants.h b/ui/base/events/event_constants.h
index e91c779..481579e 100644
--- a/ui/base/events/event_constants.h
+++ b/ui/base/events/event_constants.h
@@ -58,6 +58,10 @@ enum EventType {
// drop or menus, should stop.
ET_CANCEL_MODE,
+ // Sent by the CrOS gesture library for interesting patterns that we want
+ // to track with the UMA system.
+ ET_UMA_DATA,
+
// Must always be last. User namespace starts above this value.
// See ui::RegisterCustomEventType().
ET_LAST
diff --git a/ui/base/x/device_data_manager.cc b/ui/base/x/device_data_manager.cc
index 0332d75..7707518 100644
--- a/ui/base/x/device_data_manager.cc
+++ b/ui/base/x/device_data_manager.cc
@@ -41,6 +41,11 @@
#define AXIS_LABEL_PROP_ABS_FINGER_COUNT "Abs Finger Count"
+// Cros metrics gesture from touchpad
+#define AXIS_LABEL_PROP_ABS_METRICS_TYPE "Abs Metrics Type"
+#define AXIS_LABEL_PROP_ABS_DBL_METRICS_DATA1 "Abs Dbl Metrics Data 1"
+#define AXIS_LABEL_PROP_ABS_DBL_METRICS_DATA2 "Abs Dbl Metrics Data 2"
+
// Touchscreen multi-touch
#define AXIS_LABEL_ABS_MT_TOUCH_MAJOR "Abs MT Touch Major"
#define AXIS_LABEL_ABS_MT_TOUCH_MINOR "Abs MT Touch Minor"
@@ -63,6 +68,9 @@ const char* kCachedAtoms[] = {
AXIS_LABEL_PROP_ABS_DBL_FLING_VX,
AXIS_LABEL_PROP_ABS_DBL_FLING_VY,
AXIS_LABEL_PROP_ABS_FLING_STATE,
+ AXIS_LABEL_PROP_ABS_METRICS_TYPE,
+ AXIS_LABEL_PROP_ABS_DBL_METRICS_DATA1,
+ AXIS_LABEL_PROP_ABS_DBL_METRICS_DATA2,
AXIS_LABEL_PROP_ABS_FINGER_COUNT,
AXIS_LABEL_ABS_MT_TOUCH_MAJOR,
AXIS_LABEL_ABS_MT_TOUCH_MINOR,
@@ -285,7 +293,8 @@ bool DeviceDataManager::IsCMTDeviceEvent(
bool DeviceDataManager::IsCMTGestureEvent(
const base::NativeEvent& native_event) const {
return (IsScrollEvent(native_event) ||
- IsFlingEvent(native_event));
+ IsFlingEvent(native_event) ||
+ IsCMTMetricsEvent(native_event));
}
bool DeviceDataManager::HasEventData(
@@ -317,6 +326,18 @@ bool DeviceDataManager::IsFlingEvent(
HasEventData(xiev, DT_CMT_FLING_STATE));
}
+bool DeviceDataManager::IsCMTMetricsEvent(
+ const base::NativeEvent& native_event) const {
+ if (!IsCMTDeviceEvent(native_event))
+ return false;
+
+ XIDeviceEvent* xiev =
+ static_cast<XIDeviceEvent*>(native_event->xcookie.data);
+ return (HasEventData(xiev, DT_CMT_METRICS_TYPE) &&
+ HasEventData(xiev, DT_CMT_METRICS_DATA1) &&
+ HasEventData(xiev, DT_CMT_METRICS_DATA2));
+}
+
bool DeviceDataManager::HasGestureTimes(
const base::NativeEvent& native_event) const {
if (!IsCMTDeviceEvent(native_event))
@@ -385,6 +406,29 @@ void DeviceDataManager::GetFlingData(const base::NativeEvent& native_event,
*vy_ordinal = data[DT_CMT_ORDINAL_Y] * natural_scroll_factor;
}
+void DeviceDataManager::GetMetricsData(const base::NativeEvent& native_event,
+ GestureMetricsType* type,
+ float* data1, float* data2) {
+ *type = kGestureMetricsTypeUnknown;
+ *data1 = 0;
+ *data2 = 0;
+
+ EventData data;
+ GetEventRawData(*native_event, &data);
+
+ if (data.find(DT_CMT_METRICS_TYPE) != data.end()) {
+ int val = static_cast<int>(data[DT_CMT_METRICS_TYPE]);
+ if (val == 0)
+ *type = kGestureMetricsTypeNoisyGround;
+ else
+ *type = kGestureMetricsTypeUnknown;
+ }
+ if (data.find(DT_CMT_METRICS_DATA1) != data.end())
+ *data1 = data[DT_CMT_METRICS_DATA1];
+ if (data.find(DT_CMT_METRICS_DATA2) != data.end())
+ *data2 = data[DT_CMT_METRICS_DATA2];
+}
+
void DeviceDataManager::GetGestureTimes(const base::NativeEvent& native_event,
double* start_time,
double* end_time) {
diff --git a/ui/base/x/device_data_manager.h b/ui/base/x/device_data_manager.h
index 27f468a..950cca1 100644
--- a/ui/base/x/device_data_manager.h
+++ b/ui/base/x/device_data_manager.h
@@ -23,6 +23,12 @@ typedef union _XEvent XEvent;
namespace ui {
+// CrOS touchpad metrics gesture types
+enum GestureMetricsType {
+ kGestureMetricsTypeNoisyGround = 0,
+ kGestureMetricsTypeUnknown,
+};
+
// A class that extracts and tracks the input events data. It currently handles
// mouse, touchpad and touchscreen devices.
class UI_EXPORT DeviceDataManager {
@@ -47,6 +53,11 @@ class UI_EXPORT DeviceDataManager {
DT_CMT_FLING_Y, // Fling amount on the Y (vertical) direction.
DT_CMT_FLING_STATE, // The state of fling gesture (whether the user just
// start flinging or that he/she taps down).
+ DT_CMT_METRICS_TYPE, // Metrics type of the metrics gesture, which are
+ // used to wrap interesting patterns that we would
+ // like to track via the UMA system.
+ DT_CMT_METRICS_DATA1, // Complementary data 1 of the metrics gesture.
+ DT_CMT_METRICS_DATA2, // Complementary data 2 of the metrics gesture.
DT_CMT_FINGER_COUNT, // Finger counts in the current gesture. A same type
// of gesture can have very different meanings based
// on that (e.g. 2f scroll v.s. 3f swipe).
@@ -140,6 +151,7 @@ class UI_EXPORT DeviceDataManager {
// Returns true if the event is of the specific type, false if not.
bool IsScrollEvent(const base::NativeEvent& native_event) const;
bool IsFlingEvent(const base::NativeEvent& native_event) const;
+ bool IsCMTMetricsEvent(const base::NativeEvent& native_event) const;
// Returns true if the event has CMT start/end timestamps.
bool HasGestureTimes(const base::NativeEvent& native_event) const;
@@ -163,6 +175,13 @@ class UI_EXPORT DeviceDataManager {
float* vy_ordinal,
bool* is_cancel);
+ // Extract data from a CrOS metrics gesture event. User must first verify
+ // the event type with IsCMTMetricsEvent. Pointers shouldn't be NULL.
+ void GetMetricsData(const base::NativeEvent& native_event,
+ GestureMetricsType* type,
+ float* data1,
+ float* data2);
+
// Extract the start/end timestamps from CMT events. User must first verify
// the event with HasGestureTimes. Pointers shouldn't be NULL.
void GetGestureTimes(const base::NativeEvent& native_event,
diff --git a/ui/base/x/events_x.cc b/ui/base/x/events_x.cc
index c625ec9..ed26b93 100644
--- a/ui/base/x/events_x.cc
+++ b/ui/base/x/events_x.cc
@@ -344,6 +344,9 @@ EventType EventTypeFromNative(const base::NativeEvent& native_event) {
} else if (DeviceDataManager::GetInstance()->IsScrollEvent(
native_event)) {
return IsTouchpadEvent(native_event) ? ET_SCROLL : ET_MOUSEWHEEL;
+ } else if (DeviceDataManager::GetInstance()->IsCMTMetricsEvent(
+ native_event)) {
+ return ET_UMA_DATA;
} else if (GetButtonMaskForX2Event(xievent)) {
return ET_MOUSE_DRAGGED;
} else {