Commit c2d77073 authored by spang@chromium.org's avatar spang@chromium.org

evdev: Fix crashing with touch devices

The touchscreen crashes because of BTN_TOUCH events that hit NOTREACHED.

The touchpad crashes for similar reasons. We don't have touchpad support
here at all, so ignore these devices.

NOTRY=true

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

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@233431 0039d316-1c4b-4281-b951-d872f2087c98
parent 3772282d
...@@ -79,6 +79,8 @@ ...@@ -79,6 +79,8 @@
'gestures/gesture_util.h', 'gestures/gesture_util.h',
'gestures/velocity_calculator.cc', 'gestures/velocity_calculator.cc',
'gestures/velocity_calculator.h', 'gestures/velocity_calculator.h',
'ozone/evdev/event_device_info.cc',
'ozone/evdev/event_device_info.h',
'ozone/evdev/event_factory.cc', 'ozone/evdev/event_factory.cc',
'ozone/evdev/event_factory.h', 'ozone/evdev/event_factory.h',
'ozone/evdev/event_modifiers.cc', 'ozone/evdev/event_modifiers.cc',
......
// 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 "ui/events/ozone/evdev/event_device_info.h"
#include <linux/input.h>
#include "base/logging.h"
#include "base/threading/thread_restrictions.h"
namespace ui {
namespace {
bool GetEventBits(int fd, unsigned int type, void* buf, unsigned int size) {
base::ThreadRestrictions::AssertIOAllowed();
if (ioctl(fd, EVIOCGBIT(type, size), buf) < 0) {
DLOG(ERROR) << "failed EVIOCGBIT(" << type << ", " << size << ") on fd "
<< fd;
return false;
}
return true;
}
bool GetPropBits(int fd, void* buf, unsigned int size) {
base::ThreadRestrictions::AssertIOAllowed();
if (ioctl(fd, EVIOCGPROP(size), buf) < 0) {
DLOG(ERROR) << "failed EVIOCGPROP(" << size << ") on fd " << fd;
return false;
}
return true;
}
bool BitIsSet(const unsigned long* bits, unsigned int bit) {
return (bits[bit / EVDEV_LONG_BITS] & (1UL << (bit % EVDEV_LONG_BITS)));
}
} // namespace
EventDeviceInfo::EventDeviceInfo() {
memset(ev_bits_, 0, sizeof(ev_bits_));
memset(key_bits_, 0, sizeof(key_bits_));
memset(rel_bits_, 0, sizeof(rel_bits_));
memset(abs_bits_, 0, sizeof(abs_bits_));
memset(msc_bits_, 0, sizeof(msc_bits_));
memset(sw_bits_, 0, sizeof(sw_bits_));
memset(led_bits_, 0, sizeof(led_bits_));
memset(prop_bits_, 0, sizeof(prop_bits_));
}
EventDeviceInfo::~EventDeviceInfo() {}
bool EventDeviceInfo::Initialize(int fd) {
if (!GetEventBits(fd, 0, ev_bits_, sizeof(ev_bits_)))
return false;
if (!GetEventBits(fd, EV_KEY, key_bits_, sizeof(key_bits_)))
return false;
if (!GetEventBits(fd, EV_REL, rel_bits_, sizeof(rel_bits_)))
return false;
if (!GetEventBits(fd, EV_ABS, abs_bits_, sizeof(abs_bits_)))
return false;
if (!GetEventBits(fd, EV_MSC, msc_bits_, sizeof(msc_bits_)))
return false;
if (!GetEventBits(fd, EV_SW, sw_bits_, sizeof(sw_bits_)))
return false;
if (!GetEventBits(fd, EV_LED, led_bits_, sizeof(led_bits_)))
return false;
if (!GetPropBits(fd, prop_bits_, sizeof(prop_bits_)))
return false;
return true;
}
bool EventDeviceInfo::HasEventType(unsigned int type) const {
if (type > EV_MAX)
return false;
return BitIsSet(ev_bits_, type);
}
bool EventDeviceInfo::HasKeyEvent(unsigned int code) const {
if (code > KEY_MAX)
return false;
return BitIsSet(key_bits_, code);
}
bool EventDeviceInfo::HasRelEvent(unsigned int code) const {
if (code > REL_MAX)
return false;
return BitIsSet(rel_bits_, code);
}
bool EventDeviceInfo::HasAbsEvent(unsigned int code) const {
if (code > ABS_MAX)
return false;
return BitIsSet(abs_bits_, code);
}
bool EventDeviceInfo::HasMscEvent(unsigned int code) const {
if (code > MSC_MAX)
return false;
return BitIsSet(msc_bits_, code);
}
bool EventDeviceInfo::HasSwEvent(unsigned int code) const {
if (code > SW_MAX)
return false;
return BitIsSet(sw_bits_, code);
}
bool EventDeviceInfo::HasLedEvent(unsigned int code) const {
if (code > LED_MAX)
return false;
return BitIsSet(led_bits_, code);
}
bool EventDeviceInfo::HasProp(unsigned int code) const {
if (code > INPUT_PROP_MAX)
return false;
return BitIsSet(prop_bits_, code);
}
} // namespace ui
// 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 UI_EVENTS_OZONE_EVDEV_EVENT_DEVICE_INFO_H_
#define UI_EVENTS_OZONE_EVDEV_EVENT_DEVICE_INFO_H_
#include <limits.h>
#include <linux/input.h>
#include "base/basictypes.h"
#define EVDEV_LONG_BITS (CHAR_BIT * sizeof(long))
#define EVDEV_BITS_TO_LONGS(x) (((x) + EVDEV_LONG_BITS - 1) / EVDEV_LONG_BITS)
namespace ui {
// Device information for Linux input devices
//
// This stores and queries information about input devices; in
// particular it knows which events the device can generate.
class EventDeviceInfo {
public:
EventDeviceInfo();
~EventDeviceInfo();
// Initialize device information from an open device.
bool Initialize(int fd);
// Check events this device can generate.
bool HasEventType(unsigned int type) const;
bool HasKeyEvent(unsigned int code) const;
bool HasRelEvent(unsigned int code) const;
bool HasAbsEvent(unsigned int code) const;
bool HasMscEvent(unsigned int code) const;
bool HasSwEvent(unsigned int code) const;
bool HasLedEvent(unsigned int code) const;
// Check input device properties.
bool HasProp(unsigned int code) const;
private:
unsigned long ev_bits_[EVDEV_BITS_TO_LONGS(EV_CNT)];
unsigned long key_bits_[EVDEV_BITS_TO_LONGS(KEY_CNT)];
unsigned long rel_bits_[EVDEV_BITS_TO_LONGS(REL_CNT)];
unsigned long abs_bits_[EVDEV_BITS_TO_LONGS(ABS_CNT)];
unsigned long msc_bits_[EVDEV_BITS_TO_LONGS(MSC_CNT)];
unsigned long sw_bits_[EVDEV_BITS_TO_LONGS(SW_CNT)];
unsigned long led_bits_[EVDEV_BITS_TO_LONGS(LED_CNT)];
unsigned long prop_bits_[EVDEV_BITS_TO_LONGS(INPUT_PROP_CNT)];
DISALLOW_COPY_AND_ASSIGN(EventDeviceInfo);
};
} // namspace ui
#endif // UI_EVENTS_OZONE_EVDEV_EVENT_DEVICE_INFO_H_
...@@ -11,12 +11,29 @@ ...@@ -11,12 +11,29 @@
#include <unistd.h> #include <unistd.h>
#include "base/strings/stringprintf.h" #include "base/strings/stringprintf.h"
#include "ui/events/ozone/evdev/event_device_info.h"
#include "ui/events/ozone/evdev/key_event_converter.h" #include "ui/events/ozone/evdev/key_event_converter.h"
#include "ui/events/ozone/evdev/touch_event_converter.h" #include "ui/events/ozone/evdev/touch_event_converter.h"
#include "ui/events/ozone/event_factory_ozone.h" #include "ui/events/ozone/event_factory_ozone.h"
namespace ui { namespace ui {
namespace {
bool IsTouchPad(const EventDeviceInfo& devinfo) {
if (!devinfo.HasEventType(EV_ABS))
return false;
return devinfo.HasKeyEvent(BTN_LEFT) || devinfo.HasKeyEvent(BTN_MIDDLE) ||
devinfo.HasKeyEvent(BTN_RIGHT) || devinfo.HasKeyEvent(BTN_TOOL_FINGER);
}
bool IsTouchScreen(const EventDeviceInfo& devinfo) {
return devinfo.HasEventType(EV_ABS) && !IsTouchPad(devinfo);
}
} // namespace
EventFactoryEvdev::EventFactoryEvdev() {} EventFactoryEvdev::EventFactoryEvdev() {}
EventFactoryEvdev::~EventFactoryEvdev() {} EventFactoryEvdev::~EventFactoryEvdev() {}
...@@ -34,19 +51,25 @@ void EventFactoryEvdev::StartProcessingEvents() { ...@@ -34,19 +51,25 @@ void EventFactoryEvdev::StartProcessingEvents() {
DLOG(ERROR) << "Cannot open '" << path << "': " << strerror(errno); DLOG(ERROR) << "Cannot open '" << path << "': " << strerror(errno);
break; break;
} }
size_t evtype = 0;
COMPILE_ASSERT(sizeof(evtype) * 8 >= EV_MAX, evtype_wide_enough); EventDeviceInfo devinfo;
if (ioctl(fd, EVIOCGBIT(0, sizeof(evtype)), &evtype) == -1) { if (!devinfo.Initialize(fd)) {
DLOG(ERROR) << "failed ioctl EVIOCGBIT 0" << path; DLOG(ERROR) << "failed to get device information for " << path;
close(fd);
continue;
}
if (IsTouchPad(devinfo)) {
LOG(WARNING) << "touchpad device not supported: " << path;
close(fd); close(fd);
continue; continue;
} }
scoped_ptr<EventConverterOzone> converter; scoped_ptr<EventConverterOzone> converter;
// TODO(rjkroege) Add more device types. Support hot-plugging. // TODO(rjkroege) Add more device types. Support hot-plugging.
if (evtype & (1 << EV_ABS)) if (IsTouchScreen(devinfo))
converter.reset(new TouchEventConverterEvdev(fd, id)); converter.reset(new TouchEventConverterEvdev(fd, id));
else if (evtype & (1 << EV_KEY)) else if (devinfo.HasEventType(EV_KEY))
converter.reset(new KeyEventConverterEvdev(&modifiers_)); converter.reset(new KeyEventConverterEvdev(&modifiers_));
if (converter) { if (converter) {
......
...@@ -146,7 +146,7 @@ void TouchEventConverterEvdev::OnFileCanReadWithoutBlocking(int fd) { ...@@ -146,7 +146,7 @@ void TouchEventConverterEvdev::OnFileCanReadWithoutBlocking(int fd) {
altered_slots_.set(current_slot_); altered_slots_.set(current_slot_);
break; break;
default: default:
NOTREACHED(); NOTREACHED() << "invalid code for EV_ABS: " << input.code;
} }
} else if (input.type == EV_SYN) { } else if (input.type == EV_SYN) {
switch (input.code) { switch (input.code) {
...@@ -178,11 +178,18 @@ void TouchEventConverterEvdev::OnFileCanReadWithoutBlocking(int fd) { ...@@ -178,11 +178,18 @@ void TouchEventConverterEvdev::OnFileCanReadWithoutBlocking(int fd) {
case SYN_MT_REPORT: case SYN_MT_REPORT:
case SYN_CONFIG: case SYN_CONFIG:
case SYN_DROPPED: case SYN_DROPPED:
NOTREACHED() << "SYN_MT events not supported."; NOTREACHED() << "invalid code for EV_SYN: " << input.code;
break; break;
} }
} else if (input.type == EV_KEY) {
switch (input.code) {
case BTN_TOUCH:
break;
default:
NOTREACHED() << "invalid code for EV_KEY: " << input.code;
}
} else { } else {
NOTREACHED(); NOTREACHED() << "invalid type: " << input.type;
} }
} }
} }
......
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