summaryrefslogtreecommitdiffstats
path: root/modules/input/evdev/InputHub.h
diff options
context:
space:
mode:
Diffstat (limited to 'modules/input/evdev/InputHub.h')
-rw-r--r--modules/input/evdev/InputHub.h204
1 files changed, 204 insertions, 0 deletions
diff --git a/modules/input/evdev/InputHub.h b/modules/input/evdev/InputHub.h
new file mode 100644
index 0000000..bec327a
--- /dev/null
+++ b/modules/input/evdev/InputHub.h
@@ -0,0 +1,204 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_INPUT_HUB_H_
+#define ANDROID_INPUT_HUB_H_
+
+#include <memory>
+#include <string>
+#include <unordered_map>
+
+#include <utils/String8.h>
+#include <utils/Timers.h>
+
+namespace android {
+
+/**
+ * InputEvent represents an event from the kernel. The fields largely mirror
+ * those found in linux/input.h.
+ */
+struct InputEvent {
+ nsecs_t when;
+
+ int32_t type;
+ int32_t code;
+ int32_t value;
+};
+
+/** Describes an absolute axis. */
+struct AbsoluteAxisInfo {
+ int32_t minValue = 0; // minimum value
+ int32_t maxValue = 0; // maximum value
+ int32_t flat = 0; // center flat position, e.g. flat == 8 means center is between -8 and 8
+ int32_t fuzz = 0; // error tolerance, e.g. fuzz == 4 means value is +/- 4 due to noise
+ int32_t resolution = 0; // resolution in units per mm or radians per mm
+};
+
+/**
+ * An InputDeviceNode represents a device node in the Linux system. It can be
+ * used to interact with the device, setting and getting property values.
+ *
+ * An InputDeviceNode should only be used on the same thread that is polling for
+ * input events.
+ */
+class InputDeviceNode {
+public:
+ virtual const std::string& getPath() const = 0;
+
+ virtual const std::string& getName() const = 0;
+ virtual const std::string& getLocation() const = 0;
+ virtual const std::string& getUniqueId() const = 0;
+
+ virtual uint16_t getBusType() const = 0;
+ virtual uint16_t getVendorId() const = 0;
+ virtual uint16_t getProductId() const = 0;
+ virtual uint16_t getVersion() const = 0;
+
+ virtual bool hasKey(int32_t key) const = 0;
+ virtual bool hasRelativeAxis(int axis) const = 0;
+ virtual const AbsoluteAxisInfo* getAbsoluteAxisInfo(int32_t axis) const = 0;
+ virtual bool hasInputProperty(int property) const = 0;
+
+ virtual int32_t getKeyState(int32_t key) const = 0;
+ virtual int32_t getSwitchState(int32_t sw) const = 0;
+ virtual status_t getAbsoluteAxisValue(int32_t axis, int32_t* outValue) const = 0;
+
+ virtual void vibrate(nsecs_t duration) = 0;
+ virtual void cancelVibrate(int32_t deviceId) = 0;
+
+ virtual void disableDriverKeyRepeat() = 0;
+
+protected:
+ InputDeviceNode() = default;
+ virtual ~InputDeviceNode() = default;
+};
+
+/** Callback interface for receiving input events, including device changes. */
+class InputCallbackInterface {
+public:
+ virtual void onInputEvent(std::shared_ptr<InputDeviceNode> node, InputEvent& event,
+ nsecs_t event_time) = 0;
+ virtual void onDeviceAdded(std::shared_ptr<InputDeviceNode> node) = 0;
+ virtual void onDeviceRemoved(std::shared_ptr<InputDeviceNode> node) = 0;
+
+protected:
+ InputCallbackInterface() = default;
+ virtual ~InputCallbackInterface() = default;
+};
+
+/**
+ * InputHubInterface is responsible for monitoring a set of device paths and
+ * executing callbacks when events occur. Before calling poll(), you should set
+ * the device and input callbacks, and register your device path(s).
+ */
+class InputHubInterface {
+public:
+ virtual status_t registerDevicePath(const std::string& path) = 0;
+ virtual status_t unregisterDevicePath(const std::string& path) = 0;
+
+ virtual status_t poll() = 0;
+ virtual status_t wake() = 0;
+
+ virtual void dump(String8& dump) = 0;
+
+protected:
+ InputHubInterface() = default;
+ virtual ~InputHubInterface() = default;
+};
+
+/**
+ * An implementation of InputHubInterface that uses epoll to wait for events.
+ *
+ * This class is not threadsafe. Any functions called on the InputHub should be
+ * called on the same thread that is used to call poll(). The only exception is
+ * wake(), which may be used to return from poll() before an input or device
+ * event occurs.
+ */
+class InputHub : public InputHubInterface {
+public:
+ explicit InputHub(std::shared_ptr<InputCallbackInterface> cb);
+ virtual ~InputHub() override;
+
+ virtual status_t registerDevicePath(const std::string& path) override;
+ virtual status_t unregisterDevicePath(const std::string& path) override;
+
+ virtual status_t poll() override;
+ virtual status_t wake() override;
+
+ virtual void dump(String8& dump) override;
+
+private:
+ status_t readNotify();
+ status_t scanDir(const std::string& path);
+ status_t openNode(const std::string& path, std::shared_ptr<InputDeviceNode>* outNode);
+ status_t closeNode(const std::shared_ptr<InputDeviceNode>& node);
+ status_t closeNodeByFd(int fd);
+ std::shared_ptr<InputDeviceNode> findNodeByPath(const std::string& path);
+
+ enum class WakeMechanism {
+ /**
+ * The kernel supports the EPOLLWAKEUP flag for epoll_ctl.
+ *
+ * When using this mechanism, epoll_wait will internally acquire a wake
+ * lock whenever one of the FDs it is monitoring becomes ready. The wake
+ * lock is held automatically by the kernel until the next call to
+ * epoll_wait.
+ *
+ * This mechanism only exists in Linux kernel 3.5+.
+ */
+ EPOLL_WAKEUP,
+ /**
+ * The kernel evdev driver supports the EVIOCSSUSPENDBLOCK ioctl.
+ *
+ * When using this mechanism, the InputHub asks evdev to acquire and
+ * hold a wake lock whenever its buffer is non-empty. We must take care
+ * to acquire our own userspace wake lock before draining the buffer to
+ * prevent actually going back into suspend before we have fully
+ * processed all of the events.
+ *
+ * This mechanism only exists in older Android Linux kernels.
+ */
+ LEGACY_EVDEV_SUSPENDBLOCK_IOCTL,
+ /**
+ * The kernel doesn't seem to support any special wake mechanism.
+ *
+ * We explicitly acquire and release wake locks when processing input
+ * events.
+ */
+ LEGACY_EVDEV_EXPLICIT_WAKE_LOCKS,
+ };
+ WakeMechanism mWakeupMechanism = WakeMechanism::LEGACY_EVDEV_EXPLICIT_WAKE_LOCKS;
+ bool manageWakeLocks() const;
+ bool mNeedToCheckSuspendBlockIoctl = true;
+
+ int mEpollFd;
+ int mINotifyFd;
+ int mWakeEventFd;
+ int mWakeReadPipeFd;
+ int mWakeWritePipeFd;
+
+ // Callback for input events
+ std::shared_ptr<InputCallbackInterface> mInputCallback;
+
+ // Map from watch descriptors to watched paths
+ std::unordered_map<int, std::string> mWatchedPaths;
+ // Map from file descriptors to InputDeviceNodes
+ std::unordered_map<int, std::shared_ptr<InputDeviceNode>> mDeviceNodes;
+};
+
+} // namespace android
+
+#endif // ANDROID_INPUT_HUB_H_