summaryrefslogtreecommitdiffstats
path: root/modules/input/evdev/InputHub.h
blob: bec327ac16b620557d188beb7155a4ed27009c7e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
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_