diff options
Diffstat (limited to 'modules/input/evdev/InputHub.h')
-rw-r--r-- | modules/input/evdev/InputHub.h | 204 |
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_ |