/* * 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_