xref: /aosp_15_r20/frameworks/native/services/inputflinger/reader/EventHub.cpp (revision 38e8c45f13ce32b0dcecb25141ffecaf386fa17f)
1*38e8c45fSAndroid Build Coastguard Worker /*
2*38e8c45fSAndroid Build Coastguard Worker  * Copyright (C) 2005 The Android Open Source Project
3*38e8c45fSAndroid Build Coastguard Worker  *
4*38e8c45fSAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*38e8c45fSAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*38e8c45fSAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*38e8c45fSAndroid Build Coastguard Worker  *
8*38e8c45fSAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*38e8c45fSAndroid Build Coastguard Worker  *
10*38e8c45fSAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*38e8c45fSAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*38e8c45fSAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*38e8c45fSAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*38e8c45fSAndroid Build Coastguard Worker  * limitations under the License.
15*38e8c45fSAndroid Build Coastguard Worker  */
16*38e8c45fSAndroid Build Coastguard Worker 
17*38e8c45fSAndroid Build Coastguard Worker #include <assert.h>
18*38e8c45fSAndroid Build Coastguard Worker #include <dirent.h>
19*38e8c45fSAndroid Build Coastguard Worker #include <errno.h>
20*38e8c45fSAndroid Build Coastguard Worker #include <fcntl.h>
21*38e8c45fSAndroid Build Coastguard Worker #include <inttypes.h>
22*38e8c45fSAndroid Build Coastguard Worker #include <linux/ioctl.h>
23*38e8c45fSAndroid Build Coastguard Worker #include <memory.h>
24*38e8c45fSAndroid Build Coastguard Worker #include <stdint.h>
25*38e8c45fSAndroid Build Coastguard Worker #include <stdio.h>
26*38e8c45fSAndroid Build Coastguard Worker #include <stdlib.h>
27*38e8c45fSAndroid Build Coastguard Worker #include <string.h>
28*38e8c45fSAndroid Build Coastguard Worker #include <sys/capability.h>
29*38e8c45fSAndroid Build Coastguard Worker #include <sys/epoll.h>
30*38e8c45fSAndroid Build Coastguard Worker #include <sys/inotify.h>
31*38e8c45fSAndroid Build Coastguard Worker #include <sys/ioctl.h>
32*38e8c45fSAndroid Build Coastguard Worker #include <sys/stat.h>
33*38e8c45fSAndroid Build Coastguard Worker #include <sys/sysmacros.h>
34*38e8c45fSAndroid Build Coastguard Worker #include <unistd.h>
35*38e8c45fSAndroid Build Coastguard Worker 
36*38e8c45fSAndroid Build Coastguard Worker #include <android_companion_virtualdevice_flags.h>
37*38e8c45fSAndroid Build Coastguard Worker 
38*38e8c45fSAndroid Build Coastguard Worker #define LOG_TAG "EventHub"
39*38e8c45fSAndroid Build Coastguard Worker 
40*38e8c45fSAndroid Build Coastguard Worker // #define LOG_NDEBUG 0
41*38e8c45fSAndroid Build Coastguard Worker #include <android-base/file.h>
42*38e8c45fSAndroid Build Coastguard Worker #include <android-base/stringprintf.h>
43*38e8c45fSAndroid Build Coastguard Worker #include <android-base/strings.h>
44*38e8c45fSAndroid Build Coastguard Worker #include <cutils/properties.h>
45*38e8c45fSAndroid Build Coastguard Worker #include <ftl/enum.h>
46*38e8c45fSAndroid Build Coastguard Worker #include <input/InputEventLabels.h>
47*38e8c45fSAndroid Build Coastguard Worker #include <input/KeyCharacterMap.h>
48*38e8c45fSAndroid Build Coastguard Worker #include <input/KeyLayoutMap.h>
49*38e8c45fSAndroid Build Coastguard Worker #include <input/PrintTools.h>
50*38e8c45fSAndroid Build Coastguard Worker #include <input/VirtualKeyMap.h>
51*38e8c45fSAndroid Build Coastguard Worker #include <openssl/sha.h>
52*38e8c45fSAndroid Build Coastguard Worker #include <statslog.h>
53*38e8c45fSAndroid Build Coastguard Worker #include <utils/Errors.h>
54*38e8c45fSAndroid Build Coastguard Worker #include <utils/Log.h>
55*38e8c45fSAndroid Build Coastguard Worker #include <utils/Timers.h>
56*38e8c45fSAndroid Build Coastguard Worker 
57*38e8c45fSAndroid Build Coastguard Worker #include <filesystem>
58*38e8c45fSAndroid Build Coastguard Worker #include <optional>
59*38e8c45fSAndroid Build Coastguard Worker #include <regex>
60*38e8c45fSAndroid Build Coastguard Worker #include <utility>
61*38e8c45fSAndroid Build Coastguard Worker 
62*38e8c45fSAndroid Build Coastguard Worker #include "EventHub.h"
63*38e8c45fSAndroid Build Coastguard Worker 
64*38e8c45fSAndroid Build Coastguard Worker #include "KeyCodeClassifications.h"
65*38e8c45fSAndroid Build Coastguard Worker 
66*38e8c45fSAndroid Build Coastguard Worker #define INDENT "  "
67*38e8c45fSAndroid Build Coastguard Worker #define INDENT2 "    "
68*38e8c45fSAndroid Build Coastguard Worker #define INDENT3 "      "
69*38e8c45fSAndroid Build Coastguard Worker 
70*38e8c45fSAndroid Build Coastguard Worker using android::base::StringPrintf;
71*38e8c45fSAndroid Build Coastguard Worker 
72*38e8c45fSAndroid Build Coastguard Worker namespace android {
73*38e8c45fSAndroid Build Coastguard Worker 
74*38e8c45fSAndroid Build Coastguard Worker namespace vd_flags = android::companion::virtualdevice::flags;
75*38e8c45fSAndroid Build Coastguard Worker 
76*38e8c45fSAndroid Build Coastguard Worker using namespace ftl::flag_operators;
77*38e8c45fSAndroid Build Coastguard Worker 
78*38e8c45fSAndroid Build Coastguard Worker static const char* DEVICE_INPUT_PATH = "/dev/input";
79*38e8c45fSAndroid Build Coastguard Worker // v4l2 devices go directly into /dev
80*38e8c45fSAndroid Build Coastguard Worker static const char* DEVICE_PATH = "/dev";
81*38e8c45fSAndroid Build Coastguard Worker 
82*38e8c45fSAndroid Build Coastguard Worker static constexpr size_t OBFUSCATED_LENGTH = 8;
83*38e8c45fSAndroid Build Coastguard Worker 
84*38e8c45fSAndroid Build Coastguard Worker static constexpr int32_t FF_STRONG_MAGNITUDE_CHANNEL_IDX = 0;
85*38e8c45fSAndroid Build Coastguard Worker static constexpr int32_t FF_WEAK_MAGNITUDE_CHANNEL_IDX = 1;
86*38e8c45fSAndroid Build Coastguard Worker 
87*38e8c45fSAndroid Build Coastguard Worker static constexpr size_t EVENT_BUFFER_SIZE = 256;
88*38e8c45fSAndroid Build Coastguard Worker 
89*38e8c45fSAndroid Build Coastguard Worker // Mapping for input battery class node IDs lookup.
90*38e8c45fSAndroid Build Coastguard Worker // https://www.kernel.org/doc/Documentation/power/power_supply_class.txt
91*38e8c45fSAndroid Build Coastguard Worker static const std::unordered_map<std::string, InputBatteryClass> BATTERY_CLASSES =
92*38e8c45fSAndroid Build Coastguard Worker         {{"capacity", InputBatteryClass::CAPACITY},
93*38e8c45fSAndroid Build Coastguard Worker          {"capacity_level", InputBatteryClass::CAPACITY_LEVEL},
94*38e8c45fSAndroid Build Coastguard Worker          {"status", InputBatteryClass::STATUS}};
95*38e8c45fSAndroid Build Coastguard Worker 
96*38e8c45fSAndroid Build Coastguard Worker // Mapping for input battery class node names lookup.
97*38e8c45fSAndroid Build Coastguard Worker // https://www.kernel.org/doc/Documentation/power/power_supply_class.txt
98*38e8c45fSAndroid Build Coastguard Worker static const std::unordered_map<InputBatteryClass, std::string> BATTERY_NODES =
99*38e8c45fSAndroid Build Coastguard Worker         {{InputBatteryClass::CAPACITY, "capacity"},
100*38e8c45fSAndroid Build Coastguard Worker          {InputBatteryClass::CAPACITY_LEVEL, "capacity_level"},
101*38e8c45fSAndroid Build Coastguard Worker          {InputBatteryClass::STATUS, "status"}};
102*38e8c45fSAndroid Build Coastguard Worker 
103*38e8c45fSAndroid Build Coastguard Worker // must be kept in sync with definitions in kernel /drivers/power/supply/power_supply_sysfs.c
104*38e8c45fSAndroid Build Coastguard Worker static const std::unordered_map<std::string, int32_t> BATTERY_STATUS =
105*38e8c45fSAndroid Build Coastguard Worker         {{"Unknown", BATTERY_STATUS_UNKNOWN},
106*38e8c45fSAndroid Build Coastguard Worker          {"Charging", BATTERY_STATUS_CHARGING},
107*38e8c45fSAndroid Build Coastguard Worker          {"Discharging", BATTERY_STATUS_DISCHARGING},
108*38e8c45fSAndroid Build Coastguard Worker          {"Not charging", BATTERY_STATUS_NOT_CHARGING},
109*38e8c45fSAndroid Build Coastguard Worker          {"Full", BATTERY_STATUS_FULL}};
110*38e8c45fSAndroid Build Coastguard Worker 
111*38e8c45fSAndroid Build Coastguard Worker // Mapping taken from
112*38e8c45fSAndroid Build Coastguard Worker // https://gitlab.freedesktop.org/upower/upower/-/blob/master/src/linux/up-device-supply.c#L484
113*38e8c45fSAndroid Build Coastguard Worker static const std::unordered_map<std::string, int32_t> BATTERY_LEVEL = {{"Critical", 5},
114*38e8c45fSAndroid Build Coastguard Worker                                                                        {"Low", 10},
115*38e8c45fSAndroid Build Coastguard Worker                                                                        {"Normal", 55},
116*38e8c45fSAndroid Build Coastguard Worker                                                                        {"High", 70},
117*38e8c45fSAndroid Build Coastguard Worker                                                                        {"Full", 100},
118*38e8c45fSAndroid Build Coastguard Worker                                                                        {"Unknown", 50}};
119*38e8c45fSAndroid Build Coastguard Worker 
120*38e8c45fSAndroid Build Coastguard Worker // Mapping for input led class node names lookup.
121*38e8c45fSAndroid Build Coastguard Worker // https://www.kernel.org/doc/html/latest/leds/leds-class.html
122*38e8c45fSAndroid Build Coastguard Worker static const std::unordered_map<std::string, InputLightClass> LIGHT_CLASSES =
123*38e8c45fSAndroid Build Coastguard Worker         {{"red", InputLightClass::RED},
124*38e8c45fSAndroid Build Coastguard Worker          {"green", InputLightClass::GREEN},
125*38e8c45fSAndroid Build Coastguard Worker          {"blue", InputLightClass::BLUE},
126*38e8c45fSAndroid Build Coastguard Worker          {"global", InputLightClass::GLOBAL},
127*38e8c45fSAndroid Build Coastguard Worker          {"brightness", InputLightClass::BRIGHTNESS},
128*38e8c45fSAndroid Build Coastguard Worker          {"multi_index", InputLightClass::MULTI_INDEX},
129*38e8c45fSAndroid Build Coastguard Worker          {"multi_intensity", InputLightClass::MULTI_INTENSITY},
130*38e8c45fSAndroid Build Coastguard Worker          {"max_brightness", InputLightClass::MAX_BRIGHTNESS},
131*38e8c45fSAndroid Build Coastguard Worker          {"kbd_backlight", InputLightClass::KEYBOARD_BACKLIGHT},
132*38e8c45fSAndroid Build Coastguard Worker          {"mic_mute", InputLightClass::KEYBOARD_MIC_MUTE},
133*38e8c45fSAndroid Build Coastguard Worker          {"mute", InputLightClass::KEYBOARD_VOLUME_MUTE}};
134*38e8c45fSAndroid Build Coastguard Worker 
135*38e8c45fSAndroid Build Coastguard Worker // Mapping for input multicolor led class node names.
136*38e8c45fSAndroid Build Coastguard Worker // https://www.kernel.org/doc/html/latest/leds/leds-class-multicolor.html
137*38e8c45fSAndroid Build Coastguard Worker static const std::unordered_map<InputLightClass, std::string> LIGHT_NODES =
138*38e8c45fSAndroid Build Coastguard Worker         {{InputLightClass::BRIGHTNESS, "brightness"},
139*38e8c45fSAndroid Build Coastguard Worker          {InputLightClass::MULTI_INDEX, "multi_index"},
140*38e8c45fSAndroid Build Coastguard Worker          {InputLightClass::MULTI_INTENSITY, "multi_intensity"}};
141*38e8c45fSAndroid Build Coastguard Worker 
142*38e8c45fSAndroid Build Coastguard Worker // Mapping for light color name and the light color
143*38e8c45fSAndroid Build Coastguard Worker const std::unordered_map<std::string, LightColor> LIGHT_COLORS = {{"red", LightColor::RED},
144*38e8c45fSAndroid Build Coastguard Worker                                                                   {"green", LightColor::GREEN},
145*38e8c45fSAndroid Build Coastguard Worker                                                                   {"blue", LightColor::BLUE}};
146*38e8c45fSAndroid Build Coastguard Worker 
147*38e8c45fSAndroid Build Coastguard Worker // Mapping for country code to Layout info.
148*38e8c45fSAndroid Build Coastguard Worker // See bCountryCode in 6.2.1 of https://usb.org/sites/default/files/hid1_11.pdf.
149*38e8c45fSAndroid Build Coastguard Worker const std::unordered_map<std::int32_t, RawLayoutInfo> LAYOUT_INFOS =
150*38e8c45fSAndroid Build Coastguard Worker         {{0, RawLayoutInfo{.languageTag = "", .layoutType = ""}},             // NOT_SUPPORTED
151*38e8c45fSAndroid Build Coastguard Worker          {1, RawLayoutInfo{.languageTag = "ar-Arab", .layoutType = ""}},      // ARABIC
152*38e8c45fSAndroid Build Coastguard Worker          {2, RawLayoutInfo{.languageTag = "fr-BE", .layoutType = ""}},        // BELGIAN
153*38e8c45fSAndroid Build Coastguard Worker          {3, RawLayoutInfo{.languageTag = "fr-CA", .layoutType = ""}},        // CANADIAN_BILINGUAL
154*38e8c45fSAndroid Build Coastguard Worker          {4, RawLayoutInfo{.languageTag = "fr-CA", .layoutType = ""}},        // CANADIAN_FRENCH
155*38e8c45fSAndroid Build Coastguard Worker          {5, RawLayoutInfo{.languageTag = "cs", .layoutType = ""}},           // CZECH_REPUBLIC
156*38e8c45fSAndroid Build Coastguard Worker          {6, RawLayoutInfo{.languageTag = "da", .layoutType = ""}},           // DANISH
157*38e8c45fSAndroid Build Coastguard Worker          {7, RawLayoutInfo{.languageTag = "fi", .layoutType = ""}},           // FINNISH
158*38e8c45fSAndroid Build Coastguard Worker          {8, RawLayoutInfo{.languageTag = "fr-FR", .layoutType = ""}},        // FRENCH
159*38e8c45fSAndroid Build Coastguard Worker          {9, RawLayoutInfo{.languageTag = "de", .layoutType = ""}},           // GERMAN
160*38e8c45fSAndroid Build Coastguard Worker          {10, RawLayoutInfo{.languageTag = "el", .layoutType = ""}},          // GREEK
161*38e8c45fSAndroid Build Coastguard Worker          {11, RawLayoutInfo{.languageTag = "iw", .layoutType = ""}},          // HEBREW
162*38e8c45fSAndroid Build Coastguard Worker          {12, RawLayoutInfo{.languageTag = "hu", .layoutType = ""}},          // HUNGARY
163*38e8c45fSAndroid Build Coastguard Worker          {13, RawLayoutInfo{.languageTag = "en", .layoutType = "extended"}},  // INTERNATIONAL (ISO)
164*38e8c45fSAndroid Build Coastguard Worker          {14, RawLayoutInfo{.languageTag = "it", .layoutType = ""}},          // ITALIAN
165*38e8c45fSAndroid Build Coastguard Worker          {15, RawLayoutInfo{.languageTag = "ja", .layoutType = ""}},          // JAPAN
166*38e8c45fSAndroid Build Coastguard Worker          {16, RawLayoutInfo{.languageTag = "ko", .layoutType = ""}},          // KOREAN
167*38e8c45fSAndroid Build Coastguard Worker          {17, RawLayoutInfo{.languageTag = "es-419", .layoutType = ""}},      // LATIN_AMERICA
168*38e8c45fSAndroid Build Coastguard Worker          {18, RawLayoutInfo{.languageTag = "nl", .layoutType = ""}},          // DUTCH
169*38e8c45fSAndroid Build Coastguard Worker          {19, RawLayoutInfo{.languageTag = "nb", .layoutType = ""}},          // NORWEGIAN
170*38e8c45fSAndroid Build Coastguard Worker          {20, RawLayoutInfo{.languageTag = "fa", .layoutType = ""}},          // PERSIAN
171*38e8c45fSAndroid Build Coastguard Worker          {21, RawLayoutInfo{.languageTag = "pl", .layoutType = ""}},          // POLAND
172*38e8c45fSAndroid Build Coastguard Worker          {22, RawLayoutInfo{.languageTag = "pt", .layoutType = ""}},          // PORTUGUESE
173*38e8c45fSAndroid Build Coastguard Worker          {23, RawLayoutInfo{.languageTag = "ru", .layoutType = ""}},          // RUSSIA
174*38e8c45fSAndroid Build Coastguard Worker          {24, RawLayoutInfo{.languageTag = "sk", .layoutType = ""}},          // SLOVAKIA
175*38e8c45fSAndroid Build Coastguard Worker          {25, RawLayoutInfo{.languageTag = "es-ES", .layoutType = ""}},       // SPANISH
176*38e8c45fSAndroid Build Coastguard Worker          {26, RawLayoutInfo{.languageTag = "sv", .layoutType = ""}},          // SWEDISH
177*38e8c45fSAndroid Build Coastguard Worker          {27, RawLayoutInfo{.languageTag = "fr-CH", .layoutType = ""}},       // SWISS_FRENCH
178*38e8c45fSAndroid Build Coastguard Worker          {28, RawLayoutInfo{.languageTag = "de-CH", .layoutType = ""}},       // SWISS_GERMAN
179*38e8c45fSAndroid Build Coastguard Worker          {29, RawLayoutInfo{.languageTag = "de-CH", .layoutType = ""}},       // SWITZERLAND
180*38e8c45fSAndroid Build Coastguard Worker          {30, RawLayoutInfo{.languageTag = "zh-TW", .layoutType = ""}},       // TAIWAN
181*38e8c45fSAndroid Build Coastguard Worker          {31, RawLayoutInfo{.languageTag = "tr", .layoutType = "turkish_q"}}, // TURKISH_Q
182*38e8c45fSAndroid Build Coastguard Worker          {32, RawLayoutInfo{.languageTag = "en-GB", .layoutType = ""}},       // UK
183*38e8c45fSAndroid Build Coastguard Worker          {33, RawLayoutInfo{.languageTag = "en-US", .layoutType = ""}},       // US
184*38e8c45fSAndroid Build Coastguard Worker          {34, RawLayoutInfo{.languageTag = "", .layoutType = ""}},            // YUGOSLAVIA
185*38e8c45fSAndroid Build Coastguard Worker          {35, RawLayoutInfo{.languageTag = "tr", .layoutType = "turkish_f"}}}; // TURKISH_F
186*38e8c45fSAndroid Build Coastguard Worker 
sha1(const std::string & in)187*38e8c45fSAndroid Build Coastguard Worker static std::string sha1(const std::string& in) {
188*38e8c45fSAndroid Build Coastguard Worker     SHA_CTX ctx;
189*38e8c45fSAndroid Build Coastguard Worker     SHA1_Init(&ctx);
190*38e8c45fSAndroid Build Coastguard Worker     SHA1_Update(&ctx, reinterpret_cast<const u_char*>(in.c_str()), in.size());
191*38e8c45fSAndroid Build Coastguard Worker     u_char digest[SHA_DIGEST_LENGTH];
192*38e8c45fSAndroid Build Coastguard Worker     SHA1_Final(digest, &ctx);
193*38e8c45fSAndroid Build Coastguard Worker 
194*38e8c45fSAndroid Build Coastguard Worker     std::string out;
195*38e8c45fSAndroid Build Coastguard Worker     for (size_t i = 0; i < SHA_DIGEST_LENGTH; i++) {
196*38e8c45fSAndroid Build Coastguard Worker         out += StringPrintf("%02x", digest[i]);
197*38e8c45fSAndroid Build Coastguard Worker     }
198*38e8c45fSAndroid Build Coastguard Worker     return out;
199*38e8c45fSAndroid Build Coastguard Worker }
200*38e8c45fSAndroid Build Coastguard Worker 
201*38e8c45fSAndroid Build Coastguard Worker /**
202*38e8c45fSAndroid Build Coastguard Worker  * Return true if name matches "v4l-touch*"
203*38e8c45fSAndroid Build Coastguard Worker  */
isV4lTouchNode(std::string name)204*38e8c45fSAndroid Build Coastguard Worker static bool isV4lTouchNode(std::string name) {
205*38e8c45fSAndroid Build Coastguard Worker     return name.find("v4l-touch") != std::string::npos;
206*38e8c45fSAndroid Build Coastguard Worker }
207*38e8c45fSAndroid Build Coastguard Worker 
208*38e8c45fSAndroid Build Coastguard Worker /**
209*38e8c45fSAndroid Build Coastguard Worker  * Returns true if V4L devices should be scanned.
210*38e8c45fSAndroid Build Coastguard Worker  *
211*38e8c45fSAndroid Build Coastguard Worker  * The system property ro.input.video_enabled can be used to control whether
212*38e8c45fSAndroid Build Coastguard Worker  * EventHub scans and opens V4L devices. As V4L does not support multiple
213*38e8c45fSAndroid Build Coastguard Worker  * clients, EventHub effectively blocks access to these devices when it opens
214*38e8c45fSAndroid Build Coastguard Worker  * them.
215*38e8c45fSAndroid Build Coastguard Worker  *
216*38e8c45fSAndroid Build Coastguard Worker  * Setting this to "false" would prevent any video devices from being discovered and
217*38e8c45fSAndroid Build Coastguard Worker  * associated with input devices.
218*38e8c45fSAndroid Build Coastguard Worker  *
219*38e8c45fSAndroid Build Coastguard Worker  * This property can be used as follows:
220*38e8c45fSAndroid Build Coastguard Worker  * 1. To turn off features that are dependent on video device presence.
221*38e8c45fSAndroid Build Coastguard Worker  * 2. During testing and development, to allow other clients to read video devices
222*38e8c45fSAndroid Build Coastguard Worker  * directly from /dev.
223*38e8c45fSAndroid Build Coastguard Worker  */
isV4lScanningEnabled()224*38e8c45fSAndroid Build Coastguard Worker static bool isV4lScanningEnabled() {
225*38e8c45fSAndroid Build Coastguard Worker     return property_get_bool("ro.input.video_enabled", /*default_value=*/true);
226*38e8c45fSAndroid Build Coastguard Worker }
227*38e8c45fSAndroid Build Coastguard Worker 
processEventTimestamp(const struct input_event & event)228*38e8c45fSAndroid Build Coastguard Worker static nsecs_t processEventTimestamp(const struct input_event& event) {
229*38e8c45fSAndroid Build Coastguard Worker     // Use the time specified in the event instead of the current time
230*38e8c45fSAndroid Build Coastguard Worker     // so that downstream code can get more accurate estimates of
231*38e8c45fSAndroid Build Coastguard Worker     // event dispatch latency from the time the event is enqueued onto
232*38e8c45fSAndroid Build Coastguard Worker     // the evdev client buffer.
233*38e8c45fSAndroid Build Coastguard Worker     //
234*38e8c45fSAndroid Build Coastguard Worker     // The event's timestamp fortuitously uses the same monotonic clock
235*38e8c45fSAndroid Build Coastguard Worker     // time base as the rest of Android. The kernel event device driver
236*38e8c45fSAndroid Build Coastguard Worker     // (drivers/input/evdev.c) obtains timestamps using ktime_get_ts().
237*38e8c45fSAndroid Build Coastguard Worker     // The systemTime(SYSTEM_TIME_MONOTONIC) function we use everywhere
238*38e8c45fSAndroid Build Coastguard Worker     // calls clock_gettime(CLOCK_MONOTONIC) which is implemented as a
239*38e8c45fSAndroid Build Coastguard Worker     // system call that also queries ktime_get_ts().
240*38e8c45fSAndroid Build Coastguard Worker 
241*38e8c45fSAndroid Build Coastguard Worker     const nsecs_t inputEventTime = seconds_to_nanoseconds(event.input_event_sec) +
242*38e8c45fSAndroid Build Coastguard Worker             microseconds_to_nanoseconds(event.input_event_usec);
243*38e8c45fSAndroid Build Coastguard Worker     return inputEventTime;
244*38e8c45fSAndroid Build Coastguard Worker }
245*38e8c45fSAndroid Build Coastguard Worker 
246*38e8c45fSAndroid Build Coastguard Worker /**
247*38e8c45fSAndroid Build Coastguard Worker  * Returns the sysfs root path of the input device.
248*38e8c45fSAndroid Build Coastguard Worker  */
getSysfsRootPath(const char * devicePath)249*38e8c45fSAndroid Build Coastguard Worker static std::optional<std::filesystem::path> getSysfsRootPath(const char* devicePath) {
250*38e8c45fSAndroid Build Coastguard Worker     std::error_code errorCode;
251*38e8c45fSAndroid Build Coastguard Worker 
252*38e8c45fSAndroid Build Coastguard Worker     // Stat the device path to get the major and minor number of the character file
253*38e8c45fSAndroid Build Coastguard Worker     struct stat statbuf;
254*38e8c45fSAndroid Build Coastguard Worker     if (stat(devicePath, &statbuf) == -1) {
255*38e8c45fSAndroid Build Coastguard Worker         ALOGE("Could not stat device %s due to error: %s.", devicePath, std::strerror(errno));
256*38e8c45fSAndroid Build Coastguard Worker         return std::nullopt;
257*38e8c45fSAndroid Build Coastguard Worker     }
258*38e8c45fSAndroid Build Coastguard Worker 
259*38e8c45fSAndroid Build Coastguard Worker     unsigned int major_num = major(statbuf.st_rdev);
260*38e8c45fSAndroid Build Coastguard Worker     unsigned int minor_num = minor(statbuf.st_rdev);
261*38e8c45fSAndroid Build Coastguard Worker 
262*38e8c45fSAndroid Build Coastguard Worker     // Realpath "/sys/dev/char/{major}:{minor}" to get the sysfs path to the input event
263*38e8c45fSAndroid Build Coastguard Worker     auto sysfsPath = std::filesystem::path("/sys/dev/char/");
264*38e8c45fSAndroid Build Coastguard Worker     sysfsPath /= std::to_string(major_num) + ":" + std::to_string(minor_num);
265*38e8c45fSAndroid Build Coastguard Worker     sysfsPath = std::filesystem::canonical(sysfsPath, errorCode);
266*38e8c45fSAndroid Build Coastguard Worker 
267*38e8c45fSAndroid Build Coastguard Worker     // Make sure nothing went wrong in call to canonical()
268*38e8c45fSAndroid Build Coastguard Worker     if (errorCode) {
269*38e8c45fSAndroid Build Coastguard Worker         ALOGW("Could not run filesystem::canonical() due to error %d : %s.", errorCode.value(),
270*38e8c45fSAndroid Build Coastguard Worker               errorCode.message().c_str());
271*38e8c45fSAndroid Build Coastguard Worker         return std::nullopt;
272*38e8c45fSAndroid Build Coastguard Worker     }
273*38e8c45fSAndroid Build Coastguard Worker 
274*38e8c45fSAndroid Build Coastguard Worker     // Continue to go up a directory until we reach a directory named "input"
275*38e8c45fSAndroid Build Coastguard Worker     while (sysfsPath != "/" && sysfsPath.filename() != "input") {
276*38e8c45fSAndroid Build Coastguard Worker         sysfsPath = sysfsPath.parent_path();
277*38e8c45fSAndroid Build Coastguard Worker     }
278*38e8c45fSAndroid Build Coastguard Worker 
279*38e8c45fSAndroid Build Coastguard Worker     // Then go up one more and you will be at the sysfs root of the device
280*38e8c45fSAndroid Build Coastguard Worker     sysfsPath = sysfsPath.parent_path();
281*38e8c45fSAndroid Build Coastguard Worker 
282*38e8c45fSAndroid Build Coastguard Worker     // Make sure we didn't reach root path and that directory actually exists
283*38e8c45fSAndroid Build Coastguard Worker     if (sysfsPath == "/" || !std::filesystem::exists(sysfsPath, errorCode)) {
284*38e8c45fSAndroid Build Coastguard Worker         if (errorCode) {
285*38e8c45fSAndroid Build Coastguard Worker             ALOGW("Could not run filesystem::exists() due to error %d : %s.", errorCode.value(),
286*38e8c45fSAndroid Build Coastguard Worker                   errorCode.message().c_str());
287*38e8c45fSAndroid Build Coastguard Worker         }
288*38e8c45fSAndroid Build Coastguard Worker 
289*38e8c45fSAndroid Build Coastguard Worker         // Not found
290*38e8c45fSAndroid Build Coastguard Worker         return std::nullopt;
291*38e8c45fSAndroid Build Coastguard Worker     }
292*38e8c45fSAndroid Build Coastguard Worker 
293*38e8c45fSAndroid Build Coastguard Worker     return sysfsPath;
294*38e8c45fSAndroid Build Coastguard Worker }
295*38e8c45fSAndroid Build Coastguard Worker 
296*38e8c45fSAndroid Build Coastguard Worker /**
297*38e8c45fSAndroid Build Coastguard Worker  * Returns the list of files under a specified path.
298*38e8c45fSAndroid Build Coastguard Worker  */
allFilesInPath(const std::filesystem::path & path)299*38e8c45fSAndroid Build Coastguard Worker static std::vector<std::filesystem::path> allFilesInPath(const std::filesystem::path& path) {
300*38e8c45fSAndroid Build Coastguard Worker     std::vector<std::filesystem::path> nodes;
301*38e8c45fSAndroid Build Coastguard Worker     std::error_code errorCode;
302*38e8c45fSAndroid Build Coastguard Worker     auto iter = std::filesystem::directory_iterator(path, errorCode);
303*38e8c45fSAndroid Build Coastguard Worker     while (!errorCode && iter != std::filesystem::directory_iterator()) {
304*38e8c45fSAndroid Build Coastguard Worker         nodes.push_back(iter->path());
305*38e8c45fSAndroid Build Coastguard Worker         iter++;
306*38e8c45fSAndroid Build Coastguard Worker     }
307*38e8c45fSAndroid Build Coastguard Worker     return nodes;
308*38e8c45fSAndroid Build Coastguard Worker }
309*38e8c45fSAndroid Build Coastguard Worker 
310*38e8c45fSAndroid Build Coastguard Worker /**
311*38e8c45fSAndroid Build Coastguard Worker  * Returns the list of files under a specified directory in a sysfs path.
312*38e8c45fSAndroid Build Coastguard Worker  * Example:
313*38e8c45fSAndroid Build Coastguard Worker  * findSysfsNodes(sysfsRootPath, SysfsClass::LEDS) will return all led nodes under "leds" directory
314*38e8c45fSAndroid Build Coastguard Worker  * in the sysfs path.
315*38e8c45fSAndroid Build Coastguard Worker  */
findSysfsNodes(const std::filesystem::path & sysfsRoot,SysfsClass clazz)316*38e8c45fSAndroid Build Coastguard Worker static std::vector<std::filesystem::path> findSysfsNodes(const std::filesystem::path& sysfsRoot,
317*38e8c45fSAndroid Build Coastguard Worker                                                          SysfsClass clazz) {
318*38e8c45fSAndroid Build Coastguard Worker     std::string nodeStr = ftl::enum_string(clazz);
319*38e8c45fSAndroid Build Coastguard Worker     std::for_each(nodeStr.begin(), nodeStr.end(),
320*38e8c45fSAndroid Build Coastguard Worker                   [](char& c) { c = std::tolower(static_cast<unsigned char>(c)); });
321*38e8c45fSAndroid Build Coastguard Worker     std::vector<std::filesystem::path> nodes;
322*38e8c45fSAndroid Build Coastguard Worker     for (auto path = sysfsRoot; path != "/" && nodes.empty(); path = path.parent_path()) {
323*38e8c45fSAndroid Build Coastguard Worker         nodes = allFilesInPath(path / nodeStr);
324*38e8c45fSAndroid Build Coastguard Worker     }
325*38e8c45fSAndroid Build Coastguard Worker     return nodes;
326*38e8c45fSAndroid Build Coastguard Worker }
327*38e8c45fSAndroid Build Coastguard Worker 
getColorIndexArray(std::filesystem::path path)328*38e8c45fSAndroid Build Coastguard Worker static std::optional<std::array<LightColor, COLOR_NUM>> getColorIndexArray(
329*38e8c45fSAndroid Build Coastguard Worker         std::filesystem::path path) {
330*38e8c45fSAndroid Build Coastguard Worker     std::string indexStr;
331*38e8c45fSAndroid Build Coastguard Worker     if (!base::ReadFileToString(path, &indexStr)) {
332*38e8c45fSAndroid Build Coastguard Worker         return std::nullopt;
333*38e8c45fSAndroid Build Coastguard Worker     }
334*38e8c45fSAndroid Build Coastguard Worker 
335*38e8c45fSAndroid Build Coastguard Worker     // Parse the multi color LED index file, refer to kernel docs
336*38e8c45fSAndroid Build Coastguard Worker     // leds/leds-class-multicolor.html
337*38e8c45fSAndroid Build Coastguard Worker     std::regex indexPattern("(red|green|blue)\\s(red|green|blue)\\s(red|green|blue)[\\n]");
338*38e8c45fSAndroid Build Coastguard Worker     std::smatch results;
339*38e8c45fSAndroid Build Coastguard Worker     std::array<LightColor, COLOR_NUM> colors;
340*38e8c45fSAndroid Build Coastguard Worker     if (!std::regex_match(indexStr, results, indexPattern)) {
341*38e8c45fSAndroid Build Coastguard Worker         return std::nullopt;
342*38e8c45fSAndroid Build Coastguard Worker     }
343*38e8c45fSAndroid Build Coastguard Worker 
344*38e8c45fSAndroid Build Coastguard Worker     for (size_t i = 1; i < results.size(); i++) {
345*38e8c45fSAndroid Build Coastguard Worker         const auto it = LIGHT_COLORS.find(results[i].str());
346*38e8c45fSAndroid Build Coastguard Worker         if (it != LIGHT_COLORS.end()) {
347*38e8c45fSAndroid Build Coastguard Worker             // intensities.emplace(it->second, 0);
348*38e8c45fSAndroid Build Coastguard Worker             colors[i - 1] = it->second;
349*38e8c45fSAndroid Build Coastguard Worker         }
350*38e8c45fSAndroid Build Coastguard Worker     }
351*38e8c45fSAndroid Build Coastguard Worker     return colors;
352*38e8c45fSAndroid Build Coastguard Worker }
353*38e8c45fSAndroid Build Coastguard Worker 
354*38e8c45fSAndroid Build Coastguard Worker /**
355*38e8c45fSAndroid Build Coastguard Worker  * Read country code information exposed through the sysfs path and convert it to Layout info.
356*38e8c45fSAndroid Build Coastguard Worker  */
readLayoutConfiguration(const std::filesystem::path & sysfsRootPath)357*38e8c45fSAndroid Build Coastguard Worker static std::optional<RawLayoutInfo> readLayoutConfiguration(
358*38e8c45fSAndroid Build Coastguard Worker         const std::filesystem::path& sysfsRootPath) {
359*38e8c45fSAndroid Build Coastguard Worker     // Check the sysfs root path
360*38e8c45fSAndroid Build Coastguard Worker     int32_t hidCountryCode = -1;
361*38e8c45fSAndroid Build Coastguard Worker     std::string str;
362*38e8c45fSAndroid Build Coastguard Worker     if (base::ReadFileToString(sysfsRootPath / "country", &str)) {
363*38e8c45fSAndroid Build Coastguard Worker         hidCountryCode = std::stoi(str, nullptr, 16);
364*38e8c45fSAndroid Build Coastguard Worker         // Update this condition if new supported country codes are added to HID spec.
365*38e8c45fSAndroid Build Coastguard Worker         if (hidCountryCode > 35 || hidCountryCode < 0) {
366*38e8c45fSAndroid Build Coastguard Worker             ALOGE("HID country code should be in range [0, 35], but for sysfs path %s it was %d",
367*38e8c45fSAndroid Build Coastguard Worker                   sysfsRootPath.c_str(), hidCountryCode);
368*38e8c45fSAndroid Build Coastguard Worker         }
369*38e8c45fSAndroid Build Coastguard Worker     }
370*38e8c45fSAndroid Build Coastguard Worker     const auto it = LAYOUT_INFOS.find(hidCountryCode);
371*38e8c45fSAndroid Build Coastguard Worker     if (it != LAYOUT_INFOS.end()) {
372*38e8c45fSAndroid Build Coastguard Worker         return it->second;
373*38e8c45fSAndroid Build Coastguard Worker     }
374*38e8c45fSAndroid Build Coastguard Worker 
375*38e8c45fSAndroid Build Coastguard Worker     return std::nullopt;
376*38e8c45fSAndroid Build Coastguard Worker }
377*38e8c45fSAndroid Build Coastguard Worker 
378*38e8c45fSAndroid Build Coastguard Worker /**
379*38e8c45fSAndroid Build Coastguard Worker  * Read information about batteries exposed through the sysfs path.
380*38e8c45fSAndroid Build Coastguard Worker  */
readBatteryConfiguration(const std::filesystem::path & sysfsRootPath)381*38e8c45fSAndroid Build Coastguard Worker static std::unordered_map<int32_t /*batteryId*/, RawBatteryInfo> readBatteryConfiguration(
382*38e8c45fSAndroid Build Coastguard Worker         const std::filesystem::path& sysfsRootPath) {
383*38e8c45fSAndroid Build Coastguard Worker     std::unordered_map<int32_t, RawBatteryInfo> batteryInfos;
384*38e8c45fSAndroid Build Coastguard Worker     int32_t nextBatteryId = 0;
385*38e8c45fSAndroid Build Coastguard Worker     // Check if device has any battery.
386*38e8c45fSAndroid Build Coastguard Worker     const auto& paths = findSysfsNodes(sysfsRootPath, SysfsClass::POWER_SUPPLY);
387*38e8c45fSAndroid Build Coastguard Worker     for (const auto& nodePath : paths) {
388*38e8c45fSAndroid Build Coastguard Worker         RawBatteryInfo info;
389*38e8c45fSAndroid Build Coastguard Worker         info.id = ++nextBatteryId;
390*38e8c45fSAndroid Build Coastguard Worker         info.path = nodePath;
391*38e8c45fSAndroid Build Coastguard Worker         info.name = nodePath.filename();
392*38e8c45fSAndroid Build Coastguard Worker 
393*38e8c45fSAndroid Build Coastguard Worker         // Scan the path for all the files
394*38e8c45fSAndroid Build Coastguard Worker         // Refer to https://www.kernel.org/doc/Documentation/leds/leds-class.txt
395*38e8c45fSAndroid Build Coastguard Worker         const auto& files = allFilesInPath(nodePath);
396*38e8c45fSAndroid Build Coastguard Worker         for (const auto& file : files) {
397*38e8c45fSAndroid Build Coastguard Worker             const auto it = BATTERY_CLASSES.find(file.filename().string());
398*38e8c45fSAndroid Build Coastguard Worker             if (it != BATTERY_CLASSES.end()) {
399*38e8c45fSAndroid Build Coastguard Worker                 info.flags |= it->second;
400*38e8c45fSAndroid Build Coastguard Worker             }
401*38e8c45fSAndroid Build Coastguard Worker         }
402*38e8c45fSAndroid Build Coastguard Worker         batteryInfos.insert_or_assign(info.id, info);
403*38e8c45fSAndroid Build Coastguard Worker         ALOGD("configureBatteryLocked rawBatteryId %d name %s", info.id, info.name.c_str());
404*38e8c45fSAndroid Build Coastguard Worker     }
405*38e8c45fSAndroid Build Coastguard Worker     return batteryInfos;
406*38e8c45fSAndroid Build Coastguard Worker }
407*38e8c45fSAndroid Build Coastguard Worker 
408*38e8c45fSAndroid Build Coastguard Worker /**
409*38e8c45fSAndroid Build Coastguard Worker  *  Read information about lights exposed through the sysfs path.
410*38e8c45fSAndroid Build Coastguard Worker  */
readLightsConfiguration(const std::filesystem::path & sysfsRootPath)411*38e8c45fSAndroid Build Coastguard Worker static std::unordered_map<int32_t /*lightId*/, RawLightInfo> readLightsConfiguration(
412*38e8c45fSAndroid Build Coastguard Worker         const std::filesystem::path& sysfsRootPath) {
413*38e8c45fSAndroid Build Coastguard Worker     std::unordered_map<int32_t, RawLightInfo> lightInfos;
414*38e8c45fSAndroid Build Coastguard Worker     int32_t nextLightId = 0;
415*38e8c45fSAndroid Build Coastguard Worker     // Check if device has any lights.
416*38e8c45fSAndroid Build Coastguard Worker     const auto& paths = findSysfsNodes(sysfsRootPath, SysfsClass::LEDS);
417*38e8c45fSAndroid Build Coastguard Worker     for (const auto& nodePath : paths) {
418*38e8c45fSAndroid Build Coastguard Worker         RawLightInfo info;
419*38e8c45fSAndroid Build Coastguard Worker         info.id = ++nextLightId;
420*38e8c45fSAndroid Build Coastguard Worker         info.path = nodePath;
421*38e8c45fSAndroid Build Coastguard Worker         info.name = nodePath.filename();
422*38e8c45fSAndroid Build Coastguard Worker         info.maxBrightness = std::nullopt;
423*38e8c45fSAndroid Build Coastguard Worker 
424*38e8c45fSAndroid Build Coastguard Worker         // Light name should follow the naming pattern <name>:<color>:<function>
425*38e8c45fSAndroid Build Coastguard Worker         // Refer kernel docs /leds/leds-class.html for valid supported LED names.
426*38e8c45fSAndroid Build Coastguard Worker         std::regex indexPattern("([a-zA-Z0-9_.:]*:)?([a-zA-Z0-9_.]*):([a-zA-Z0-9_.]*)");
427*38e8c45fSAndroid Build Coastguard Worker         std::smatch results;
428*38e8c45fSAndroid Build Coastguard Worker 
429*38e8c45fSAndroid Build Coastguard Worker         if (std::regex_match(info.name, results, indexPattern)) {
430*38e8c45fSAndroid Build Coastguard Worker             // regex_match will return full match at index 0 and <name> at index 1. For RawLightInfo
431*38e8c45fSAndroid Build Coastguard Worker             // we only care about sections <color> and <function> which will be at index 2 and 3.
432*38e8c45fSAndroid Build Coastguard Worker             for (int i = 2; i <= 3; i++) {
433*38e8c45fSAndroid Build Coastguard Worker                 const auto it = LIGHT_CLASSES.find(results.str(i));
434*38e8c45fSAndroid Build Coastguard Worker                 if (it != LIGHT_CLASSES.end()) {
435*38e8c45fSAndroid Build Coastguard Worker                     info.flags |= it->second;
436*38e8c45fSAndroid Build Coastguard Worker                 }
437*38e8c45fSAndroid Build Coastguard Worker             }
438*38e8c45fSAndroid Build Coastguard Worker 
439*38e8c45fSAndroid Build Coastguard Worker             // Set name of the raw light to <function> which represents playerIDs for LEDs that
440*38e8c45fSAndroid Build Coastguard Worker             // turn on/off based on the current player ID (Refer to PeripheralController.cpp for
441*38e8c45fSAndroid Build Coastguard Worker             // player ID logic)
442*38e8c45fSAndroid Build Coastguard Worker             info.name = results.str(3);
443*38e8c45fSAndroid Build Coastguard Worker         }
444*38e8c45fSAndroid Build Coastguard Worker         // Scan the path for all the files
445*38e8c45fSAndroid Build Coastguard Worker         // Refer to https://www.kernel.org/doc/Documentation/leds/leds-class.txt
446*38e8c45fSAndroid Build Coastguard Worker         const auto& files = allFilesInPath(nodePath);
447*38e8c45fSAndroid Build Coastguard Worker         for (const auto& file : files) {
448*38e8c45fSAndroid Build Coastguard Worker             const auto it = LIGHT_CLASSES.find(file.filename().string());
449*38e8c45fSAndroid Build Coastguard Worker             if (it != LIGHT_CLASSES.end()) {
450*38e8c45fSAndroid Build Coastguard Worker                 info.flags |= it->second;
451*38e8c45fSAndroid Build Coastguard Worker                 // If the node has maximum brightness, read it
452*38e8c45fSAndroid Build Coastguard Worker                 if (it->second == InputLightClass::MAX_BRIGHTNESS) {
453*38e8c45fSAndroid Build Coastguard Worker                     std::string str;
454*38e8c45fSAndroid Build Coastguard Worker                     if (base::ReadFileToString(file, &str)) {
455*38e8c45fSAndroid Build Coastguard Worker                         info.maxBrightness = std::stoi(str);
456*38e8c45fSAndroid Build Coastguard Worker                     }
457*38e8c45fSAndroid Build Coastguard Worker                 }
458*38e8c45fSAndroid Build Coastguard Worker             }
459*38e8c45fSAndroid Build Coastguard Worker         }
460*38e8c45fSAndroid Build Coastguard Worker         lightInfos.insert_or_assign(info.id, info);
461*38e8c45fSAndroid Build Coastguard Worker         ALOGD("configureLightsLocked rawLightId %d name %s", info.id, info.name.c_str());
462*38e8c45fSAndroid Build Coastguard Worker     }
463*38e8c45fSAndroid Build Coastguard Worker     return lightInfos;
464*38e8c45fSAndroid Build Coastguard Worker }
465*38e8c45fSAndroid Build Coastguard Worker 
466*38e8c45fSAndroid Build Coastguard Worker // --- Global Functions ---
467*38e8c45fSAndroid Build Coastguard Worker 
getAbsAxisUsage(int32_t axis,ftl::Flags<InputDeviceClass> deviceClasses)468*38e8c45fSAndroid Build Coastguard Worker ftl::Flags<InputDeviceClass> getAbsAxisUsage(int32_t axis,
469*38e8c45fSAndroid Build Coastguard Worker                                              ftl::Flags<InputDeviceClass> deviceClasses) {
470*38e8c45fSAndroid Build Coastguard Worker     // Touch devices get dibs on touch-related axes.
471*38e8c45fSAndroid Build Coastguard Worker     if (deviceClasses.test(InputDeviceClass::TOUCH)) {
472*38e8c45fSAndroid Build Coastguard Worker         switch (axis) {
473*38e8c45fSAndroid Build Coastguard Worker             case ABS_X:
474*38e8c45fSAndroid Build Coastguard Worker             case ABS_Y:
475*38e8c45fSAndroid Build Coastguard Worker             case ABS_PRESSURE:
476*38e8c45fSAndroid Build Coastguard Worker             case ABS_TOOL_WIDTH:
477*38e8c45fSAndroid Build Coastguard Worker             case ABS_DISTANCE:
478*38e8c45fSAndroid Build Coastguard Worker             case ABS_TILT_X:
479*38e8c45fSAndroid Build Coastguard Worker             case ABS_TILT_Y:
480*38e8c45fSAndroid Build Coastguard Worker             case ABS_MT_SLOT:
481*38e8c45fSAndroid Build Coastguard Worker             case ABS_MT_TOUCH_MAJOR:
482*38e8c45fSAndroid Build Coastguard Worker             case ABS_MT_TOUCH_MINOR:
483*38e8c45fSAndroid Build Coastguard Worker             case ABS_MT_WIDTH_MAJOR:
484*38e8c45fSAndroid Build Coastguard Worker             case ABS_MT_WIDTH_MINOR:
485*38e8c45fSAndroid Build Coastguard Worker             case ABS_MT_ORIENTATION:
486*38e8c45fSAndroid Build Coastguard Worker             case ABS_MT_POSITION_X:
487*38e8c45fSAndroid Build Coastguard Worker             case ABS_MT_POSITION_Y:
488*38e8c45fSAndroid Build Coastguard Worker             case ABS_MT_TOOL_TYPE:
489*38e8c45fSAndroid Build Coastguard Worker             case ABS_MT_BLOB_ID:
490*38e8c45fSAndroid Build Coastguard Worker             case ABS_MT_TRACKING_ID:
491*38e8c45fSAndroid Build Coastguard Worker             case ABS_MT_PRESSURE:
492*38e8c45fSAndroid Build Coastguard Worker             case ABS_MT_DISTANCE:
493*38e8c45fSAndroid Build Coastguard Worker                 return InputDeviceClass::TOUCH;
494*38e8c45fSAndroid Build Coastguard Worker         }
495*38e8c45fSAndroid Build Coastguard Worker     }
496*38e8c45fSAndroid Build Coastguard Worker 
497*38e8c45fSAndroid Build Coastguard Worker     if (deviceClasses.test(InputDeviceClass::SENSOR)) {
498*38e8c45fSAndroid Build Coastguard Worker         switch (axis) {
499*38e8c45fSAndroid Build Coastguard Worker             case ABS_X:
500*38e8c45fSAndroid Build Coastguard Worker             case ABS_Y:
501*38e8c45fSAndroid Build Coastguard Worker             case ABS_Z:
502*38e8c45fSAndroid Build Coastguard Worker             case ABS_RX:
503*38e8c45fSAndroid Build Coastguard Worker             case ABS_RY:
504*38e8c45fSAndroid Build Coastguard Worker             case ABS_RZ:
505*38e8c45fSAndroid Build Coastguard Worker                 return InputDeviceClass::SENSOR;
506*38e8c45fSAndroid Build Coastguard Worker         }
507*38e8c45fSAndroid Build Coastguard Worker     }
508*38e8c45fSAndroid Build Coastguard Worker 
509*38e8c45fSAndroid Build Coastguard Worker     // External stylus gets the pressure axis
510*38e8c45fSAndroid Build Coastguard Worker     if (deviceClasses.test(InputDeviceClass::EXTERNAL_STYLUS)) {
511*38e8c45fSAndroid Build Coastguard Worker         if (axis == ABS_PRESSURE) {
512*38e8c45fSAndroid Build Coastguard Worker             return InputDeviceClass::EXTERNAL_STYLUS;
513*38e8c45fSAndroid Build Coastguard Worker         }
514*38e8c45fSAndroid Build Coastguard Worker     }
515*38e8c45fSAndroid Build Coastguard Worker 
516*38e8c45fSAndroid Build Coastguard Worker     // Joystick devices get the rest.
517*38e8c45fSAndroid Build Coastguard Worker     return deviceClasses & InputDeviceClass::JOYSTICK;
518*38e8c45fSAndroid Build Coastguard Worker }
519*38e8c45fSAndroid Build Coastguard Worker 
520*38e8c45fSAndroid Build Coastguard Worker // --- RawAbsoluteAxisInfo ---
521*38e8c45fSAndroid Build Coastguard Worker 
operator <<(std::ostream & out,const std::optional<RawAbsoluteAxisInfo> & info)522*38e8c45fSAndroid Build Coastguard Worker std::ostream& operator<<(std::ostream& out, const std::optional<RawAbsoluteAxisInfo>& info) {
523*38e8c45fSAndroid Build Coastguard Worker     if (info) {
524*38e8c45fSAndroid Build Coastguard Worker         out << "min=" << info->minValue << ", max=" << info->maxValue << ", flat=" << info->flat
525*38e8c45fSAndroid Build Coastguard Worker             << ", fuzz=" << info->fuzz << ", resolution=" << info->resolution;
526*38e8c45fSAndroid Build Coastguard Worker     } else {
527*38e8c45fSAndroid Build Coastguard Worker         out << "unknown range";
528*38e8c45fSAndroid Build Coastguard Worker     }
529*38e8c45fSAndroid Build Coastguard Worker     return out;
530*38e8c45fSAndroid Build Coastguard Worker }
531*38e8c45fSAndroid Build Coastguard Worker 
532*38e8c45fSAndroid Build Coastguard Worker // --- EventHub::Device ---
533*38e8c45fSAndroid Build Coastguard Worker 
Device(int fd,int32_t id,std::string path,InputDeviceIdentifier identifier,std::shared_ptr<const AssociatedDevice> assocDev)534*38e8c45fSAndroid Build Coastguard Worker EventHub::Device::Device(int fd, int32_t id, std::string path, InputDeviceIdentifier identifier,
535*38e8c45fSAndroid Build Coastguard Worker                          std::shared_ptr<const AssociatedDevice> assocDev)
536*38e8c45fSAndroid Build Coastguard Worker       : fd(fd),
537*38e8c45fSAndroid Build Coastguard Worker         id(id),
538*38e8c45fSAndroid Build Coastguard Worker         path(std::move(path)),
539*38e8c45fSAndroid Build Coastguard Worker         identifier(std::move(identifier)),
540*38e8c45fSAndroid Build Coastguard Worker         classes(0),
541*38e8c45fSAndroid Build Coastguard Worker         configuration(nullptr),
542*38e8c45fSAndroid Build Coastguard Worker         virtualKeyMap(nullptr),
543*38e8c45fSAndroid Build Coastguard Worker         ffEffectPlaying(false),
544*38e8c45fSAndroid Build Coastguard Worker         ffEffectId(-1),
545*38e8c45fSAndroid Build Coastguard Worker         associatedDevice(std::move(assocDev)),
546*38e8c45fSAndroid Build Coastguard Worker         controllerNumber(0),
547*38e8c45fSAndroid Build Coastguard Worker         enabled(true),
548*38e8c45fSAndroid Build Coastguard Worker         isVirtual(fd < 0),
549*38e8c45fSAndroid Build Coastguard Worker         currentFrameDropped(false) {}
550*38e8c45fSAndroid Build Coastguard Worker 
~Device()551*38e8c45fSAndroid Build Coastguard Worker EventHub::Device::~Device() {
552*38e8c45fSAndroid Build Coastguard Worker     close();
553*38e8c45fSAndroid Build Coastguard Worker }
554*38e8c45fSAndroid Build Coastguard Worker 
close()555*38e8c45fSAndroid Build Coastguard Worker void EventHub::Device::close() {
556*38e8c45fSAndroid Build Coastguard Worker     if (fd >= 0) {
557*38e8c45fSAndroid Build Coastguard Worker         ::close(fd);
558*38e8c45fSAndroid Build Coastguard Worker         fd = -1;
559*38e8c45fSAndroid Build Coastguard Worker     }
560*38e8c45fSAndroid Build Coastguard Worker }
561*38e8c45fSAndroid Build Coastguard Worker 
enable()562*38e8c45fSAndroid Build Coastguard Worker status_t EventHub::Device::enable() {
563*38e8c45fSAndroid Build Coastguard Worker     fd = open(path.c_str(), O_RDWR | O_CLOEXEC | O_NONBLOCK);
564*38e8c45fSAndroid Build Coastguard Worker     if (fd < 0) {
565*38e8c45fSAndroid Build Coastguard Worker         ALOGE("could not open %s, %s\n", path.c_str(), strerror(errno));
566*38e8c45fSAndroid Build Coastguard Worker         return -errno;
567*38e8c45fSAndroid Build Coastguard Worker     }
568*38e8c45fSAndroid Build Coastguard Worker     enabled = true;
569*38e8c45fSAndroid Build Coastguard Worker     return OK;
570*38e8c45fSAndroid Build Coastguard Worker }
571*38e8c45fSAndroid Build Coastguard Worker 
disable()572*38e8c45fSAndroid Build Coastguard Worker status_t EventHub::Device::disable() {
573*38e8c45fSAndroid Build Coastguard Worker     close();
574*38e8c45fSAndroid Build Coastguard Worker     enabled = false;
575*38e8c45fSAndroid Build Coastguard Worker     return OK;
576*38e8c45fSAndroid Build Coastguard Worker }
577*38e8c45fSAndroid Build Coastguard Worker 
hasValidFd() const578*38e8c45fSAndroid Build Coastguard Worker bool EventHub::Device::hasValidFd() const {
579*38e8c45fSAndroid Build Coastguard Worker     return !isVirtual && enabled;
580*38e8c45fSAndroid Build Coastguard Worker }
581*38e8c45fSAndroid Build Coastguard Worker 
getKeyCharacterMap() const582*38e8c45fSAndroid Build Coastguard Worker const std::shared_ptr<KeyCharacterMap> EventHub::Device::getKeyCharacterMap() const {
583*38e8c45fSAndroid Build Coastguard Worker     return keyMap.keyCharacterMap;
584*38e8c45fSAndroid Build Coastguard Worker }
585*38e8c45fSAndroid Build Coastguard Worker 
586*38e8c45fSAndroid Build Coastguard Worker template <std::size_t N>
readDeviceBitMask(unsigned long ioctlCode,BitArray<N> & bitArray)587*38e8c45fSAndroid Build Coastguard Worker status_t EventHub::Device::readDeviceBitMask(unsigned long ioctlCode, BitArray<N>& bitArray) {
588*38e8c45fSAndroid Build Coastguard Worker     if (!hasValidFd()) {
589*38e8c45fSAndroid Build Coastguard Worker         return BAD_VALUE;
590*38e8c45fSAndroid Build Coastguard Worker     }
591*38e8c45fSAndroid Build Coastguard Worker     if ((_IOC_SIZE(ioctlCode) == 0)) {
592*38e8c45fSAndroid Build Coastguard Worker         ioctlCode |= _IOC(0, 0, 0, bitArray.bytes());
593*38e8c45fSAndroid Build Coastguard Worker     }
594*38e8c45fSAndroid Build Coastguard Worker 
595*38e8c45fSAndroid Build Coastguard Worker     typename BitArray<N>::Buffer buffer;
596*38e8c45fSAndroid Build Coastguard Worker     status_t ret = ioctl(fd, ioctlCode, buffer.data());
597*38e8c45fSAndroid Build Coastguard Worker     bitArray.loadFromBuffer(buffer);
598*38e8c45fSAndroid Build Coastguard Worker     return ret;
599*38e8c45fSAndroid Build Coastguard Worker }
600*38e8c45fSAndroid Build Coastguard Worker 
configureFd()601*38e8c45fSAndroid Build Coastguard Worker void EventHub::Device::configureFd() {
602*38e8c45fSAndroid Build Coastguard Worker     // Set fd parameters with ioctl, such as key repeat, suspend block, and clock type
603*38e8c45fSAndroid Build Coastguard Worker     if (classes.test(InputDeviceClass::KEYBOARD)) {
604*38e8c45fSAndroid Build Coastguard Worker         // Disable kernel key repeat since we handle it ourselves
605*38e8c45fSAndroid Build Coastguard Worker         unsigned int repeatRate[] = {0, 0};
606*38e8c45fSAndroid Build Coastguard Worker         if (ioctl(fd, EVIOCSREP, repeatRate)) {
607*38e8c45fSAndroid Build Coastguard Worker             ALOGW("Unable to disable kernel key repeat for %s: %s", path.c_str(), strerror(errno));
608*38e8c45fSAndroid Build Coastguard Worker         }
609*38e8c45fSAndroid Build Coastguard Worker     }
610*38e8c45fSAndroid Build Coastguard Worker 
611*38e8c45fSAndroid Build Coastguard Worker     // Tell the kernel that we want to use the monotonic clock for reporting timestamps
612*38e8c45fSAndroid Build Coastguard Worker     // associated with input events.  This is important because the input system
613*38e8c45fSAndroid Build Coastguard Worker     // uses the timestamps extensively and assumes they were recorded using the monotonic
614*38e8c45fSAndroid Build Coastguard Worker     // clock.
615*38e8c45fSAndroid Build Coastguard Worker     int clockId = CLOCK_MONOTONIC;
616*38e8c45fSAndroid Build Coastguard Worker     if (classes.test(InputDeviceClass::SENSOR)) {
617*38e8c45fSAndroid Build Coastguard Worker         // Each new sensor event should use the same time base as
618*38e8c45fSAndroid Build Coastguard Worker         // SystemClock.elapsedRealtimeNanos().
619*38e8c45fSAndroid Build Coastguard Worker         clockId = CLOCK_BOOTTIME;
620*38e8c45fSAndroid Build Coastguard Worker     }
621*38e8c45fSAndroid Build Coastguard Worker     bool usingClockIoctl = !ioctl(fd, EVIOCSCLOCKID, &clockId);
622*38e8c45fSAndroid Build Coastguard Worker     ALOGI("usingClockIoctl=%s", toString(usingClockIoctl));
623*38e8c45fSAndroid Build Coastguard Worker 
624*38e8c45fSAndroid Build Coastguard Worker     // Query the initial state of keys and switches, which is tracked by EventHub.
625*38e8c45fSAndroid Build Coastguard Worker     readDeviceState();
626*38e8c45fSAndroid Build Coastguard Worker }
627*38e8c45fSAndroid Build Coastguard Worker 
readDeviceState()628*38e8c45fSAndroid Build Coastguard Worker void EventHub::Device::readDeviceState() {
629*38e8c45fSAndroid Build Coastguard Worker     if (readDeviceBitMask(EVIOCGKEY(0), keyState) < 0) {
630*38e8c45fSAndroid Build Coastguard Worker         ALOGD("Unable to query the global key state for %s: %s", path.c_str(), strerror(errno));
631*38e8c45fSAndroid Build Coastguard Worker     }
632*38e8c45fSAndroid Build Coastguard Worker     if (readDeviceBitMask(EVIOCGSW(0), swState) < 0) {
633*38e8c45fSAndroid Build Coastguard Worker         ALOGD("Unable to query the global switch state for %s: %s", path.c_str(), strerror(errno));
634*38e8c45fSAndroid Build Coastguard Worker     }
635*38e8c45fSAndroid Build Coastguard Worker 
636*38e8c45fSAndroid Build Coastguard Worker     // Read absolute axis info and values for all available axes for the device.
637*38e8c45fSAndroid Build Coastguard Worker     populateAbsoluteAxisStates();
638*38e8c45fSAndroid Build Coastguard Worker }
639*38e8c45fSAndroid Build Coastguard Worker 
populateAbsoluteAxisStates()640*38e8c45fSAndroid Build Coastguard Worker void EventHub::Device::populateAbsoluteAxisStates() {
641*38e8c45fSAndroid Build Coastguard Worker     absState.clear();
642*38e8c45fSAndroid Build Coastguard Worker 
643*38e8c45fSAndroid Build Coastguard Worker     for (int axis = 0; axis <= ABS_MAX; axis++) {
644*38e8c45fSAndroid Build Coastguard Worker         if (!absBitmask.test(axis)) {
645*38e8c45fSAndroid Build Coastguard Worker             continue;
646*38e8c45fSAndroid Build Coastguard Worker         }
647*38e8c45fSAndroid Build Coastguard Worker         struct input_absinfo info {};
648*38e8c45fSAndroid Build Coastguard Worker         if (ioctl(fd, EVIOCGABS(axis), &info)) {
649*38e8c45fSAndroid Build Coastguard Worker             ALOGE("Error reading absolute controller %d for device %s fd %d: %s", axis,
650*38e8c45fSAndroid Build Coastguard Worker                   identifier.name.c_str(), fd, strerror(errno));
651*38e8c45fSAndroid Build Coastguard Worker             continue;
652*38e8c45fSAndroid Build Coastguard Worker         }
653*38e8c45fSAndroid Build Coastguard Worker         auto& [axisInfo, value] = absState[axis];
654*38e8c45fSAndroid Build Coastguard Worker         axisInfo.minValue = info.minimum;
655*38e8c45fSAndroid Build Coastguard Worker         axisInfo.maxValue = info.maximum;
656*38e8c45fSAndroid Build Coastguard Worker         axisInfo.flat = info.flat;
657*38e8c45fSAndroid Build Coastguard Worker         axisInfo.fuzz = info.fuzz;
658*38e8c45fSAndroid Build Coastguard Worker         axisInfo.resolution = info.resolution;
659*38e8c45fSAndroid Build Coastguard Worker         value = info.value;
660*38e8c45fSAndroid Build Coastguard Worker     }
661*38e8c45fSAndroid Build Coastguard Worker }
662*38e8c45fSAndroid Build Coastguard Worker 
hasKeycodeLocked(int keycode) const663*38e8c45fSAndroid Build Coastguard Worker bool EventHub::Device::hasKeycodeLocked(int keycode) const {
664*38e8c45fSAndroid Build Coastguard Worker     if (hasKeycodeInternalLocked(keycode)) {
665*38e8c45fSAndroid Build Coastguard Worker         return true;
666*38e8c45fSAndroid Build Coastguard Worker     }
667*38e8c45fSAndroid Build Coastguard Worker     if (!keyMap.haveKeyCharacterMap()) {
668*38e8c45fSAndroid Build Coastguard Worker         return false;
669*38e8c45fSAndroid Build Coastguard Worker     }
670*38e8c45fSAndroid Build Coastguard Worker     for (auto& fromKey : getKeyCharacterMap()->findKeyCodesMappedToKeyCode(keycode)) {
671*38e8c45fSAndroid Build Coastguard Worker         if (hasKeycodeInternalLocked(fromKey)) {
672*38e8c45fSAndroid Build Coastguard Worker             return true;
673*38e8c45fSAndroid Build Coastguard Worker         }
674*38e8c45fSAndroid Build Coastguard Worker     }
675*38e8c45fSAndroid Build Coastguard Worker     return false;
676*38e8c45fSAndroid Build Coastguard Worker }
677*38e8c45fSAndroid Build Coastguard Worker 
hasKeycodeInternalLocked(int keycode) const678*38e8c45fSAndroid Build Coastguard Worker bool EventHub::Device::hasKeycodeInternalLocked(int keycode) const {
679*38e8c45fSAndroid Build Coastguard Worker     if (!keyMap.haveKeyLayout()) {
680*38e8c45fSAndroid Build Coastguard Worker         return false;
681*38e8c45fSAndroid Build Coastguard Worker     }
682*38e8c45fSAndroid Build Coastguard Worker 
683*38e8c45fSAndroid Build Coastguard Worker     std::vector<int32_t> scanCodes = keyMap.keyLayoutMap->findScanCodesForKey(keycode);
684*38e8c45fSAndroid Build Coastguard Worker     const size_t N = scanCodes.size();
685*38e8c45fSAndroid Build Coastguard Worker     for (size_t i = 0; i < N && i <= KEY_MAX; i++) {
686*38e8c45fSAndroid Build Coastguard Worker         int32_t sc = scanCodes[i];
687*38e8c45fSAndroid Build Coastguard Worker         if (sc >= 0 && sc <= KEY_MAX && keyBitmask.test(sc)) {
688*38e8c45fSAndroid Build Coastguard Worker             return true;
689*38e8c45fSAndroid Build Coastguard Worker         }
690*38e8c45fSAndroid Build Coastguard Worker     }
691*38e8c45fSAndroid Build Coastguard Worker 
692*38e8c45fSAndroid Build Coastguard Worker     std::vector<int32_t> usageCodes = keyMap.keyLayoutMap->findUsageCodesForKey(keycode);
693*38e8c45fSAndroid Build Coastguard Worker     if (usageCodes.size() > 0 && mscBitmask.test(MSC_SCAN)) {
694*38e8c45fSAndroid Build Coastguard Worker         return true;
695*38e8c45fSAndroid Build Coastguard Worker     }
696*38e8c45fSAndroid Build Coastguard Worker     return false;
697*38e8c45fSAndroid Build Coastguard Worker }
698*38e8c45fSAndroid Build Coastguard Worker 
loadConfigurationLocked()699*38e8c45fSAndroid Build Coastguard Worker void EventHub::Device::loadConfigurationLocked() {
700*38e8c45fSAndroid Build Coastguard Worker     configurationFile =
701*38e8c45fSAndroid Build Coastguard Worker             getInputDeviceConfigurationFilePathByDeviceIdentifier(identifier,
702*38e8c45fSAndroid Build Coastguard Worker                                                                   InputDeviceConfigurationFileType::
703*38e8c45fSAndroid Build Coastguard Worker                                                                           CONFIGURATION);
704*38e8c45fSAndroid Build Coastguard Worker     if (configurationFile.empty()) {
705*38e8c45fSAndroid Build Coastguard Worker         ALOGD("No input device configuration file found for device '%s'.", identifier.name.c_str());
706*38e8c45fSAndroid Build Coastguard Worker     } else {
707*38e8c45fSAndroid Build Coastguard Worker         android::base::Result<std::unique_ptr<PropertyMap>> propertyMap =
708*38e8c45fSAndroid Build Coastguard Worker                 PropertyMap::load(configurationFile.c_str());
709*38e8c45fSAndroid Build Coastguard Worker         if (!propertyMap.ok()) {
710*38e8c45fSAndroid Build Coastguard Worker             ALOGE("Error loading input device configuration file for device '%s'.  "
711*38e8c45fSAndroid Build Coastguard Worker                   "Using default configuration.",
712*38e8c45fSAndroid Build Coastguard Worker                   identifier.name.c_str());
713*38e8c45fSAndroid Build Coastguard Worker         } else {
714*38e8c45fSAndroid Build Coastguard Worker             configuration = std::move(*propertyMap);
715*38e8c45fSAndroid Build Coastguard Worker         }
716*38e8c45fSAndroid Build Coastguard Worker     }
717*38e8c45fSAndroid Build Coastguard Worker }
718*38e8c45fSAndroid Build Coastguard Worker 
loadVirtualKeyMapLocked()719*38e8c45fSAndroid Build Coastguard Worker bool EventHub::Device::loadVirtualKeyMapLocked() {
720*38e8c45fSAndroid Build Coastguard Worker     // The virtual key map is supplied by the kernel as a system board property file.
721*38e8c45fSAndroid Build Coastguard Worker     std::string propPath = "/sys/board_properties/virtualkeys.";
722*38e8c45fSAndroid Build Coastguard Worker     propPath += identifier.getCanonicalName();
723*38e8c45fSAndroid Build Coastguard Worker     if (access(propPath.c_str(), R_OK)) {
724*38e8c45fSAndroid Build Coastguard Worker         return false;
725*38e8c45fSAndroid Build Coastguard Worker     }
726*38e8c45fSAndroid Build Coastguard Worker     virtualKeyMap = VirtualKeyMap::load(propPath);
727*38e8c45fSAndroid Build Coastguard Worker     return virtualKeyMap != nullptr;
728*38e8c45fSAndroid Build Coastguard Worker }
729*38e8c45fSAndroid Build Coastguard Worker 
loadKeyMapLocked()730*38e8c45fSAndroid Build Coastguard Worker status_t EventHub::Device::loadKeyMapLocked() {
731*38e8c45fSAndroid Build Coastguard Worker     return keyMap.load(identifier, configuration.get());
732*38e8c45fSAndroid Build Coastguard Worker }
733*38e8c45fSAndroid Build Coastguard Worker 
isExternalDeviceLocked()734*38e8c45fSAndroid Build Coastguard Worker bool EventHub::Device::isExternalDeviceLocked() {
735*38e8c45fSAndroid Build Coastguard Worker     if (configuration) {
736*38e8c45fSAndroid Build Coastguard Worker         std::optional<bool> isInternal = configuration->getBool("device.internal");
737*38e8c45fSAndroid Build Coastguard Worker         if (isInternal.has_value()) {
738*38e8c45fSAndroid Build Coastguard Worker             return !isInternal.value();
739*38e8c45fSAndroid Build Coastguard Worker         }
740*38e8c45fSAndroid Build Coastguard Worker     }
741*38e8c45fSAndroid Build Coastguard Worker     return identifier.bus == BUS_USB || identifier.bus == BUS_BLUETOOTH;
742*38e8c45fSAndroid Build Coastguard Worker }
743*38e8c45fSAndroid Build Coastguard Worker 
deviceHasMicLocked()744*38e8c45fSAndroid Build Coastguard Worker bool EventHub::Device::deviceHasMicLocked() {
745*38e8c45fSAndroid Build Coastguard Worker     if (configuration) {
746*38e8c45fSAndroid Build Coastguard Worker         std::optional<bool> hasMic = configuration->getBool("audio.mic");
747*38e8c45fSAndroid Build Coastguard Worker         if (hasMic.has_value()) {
748*38e8c45fSAndroid Build Coastguard Worker             return hasMic.value();
749*38e8c45fSAndroid Build Coastguard Worker         }
750*38e8c45fSAndroid Build Coastguard Worker     }
751*38e8c45fSAndroid Build Coastguard Worker     return false;
752*38e8c45fSAndroid Build Coastguard Worker }
753*38e8c45fSAndroid Build Coastguard Worker 
setLedStateLocked(int32_t led,bool on)754*38e8c45fSAndroid Build Coastguard Worker void EventHub::Device::setLedStateLocked(int32_t led, bool on) {
755*38e8c45fSAndroid Build Coastguard Worker     int32_t sc;
756*38e8c45fSAndroid Build Coastguard Worker     if (hasValidFd() && mapLed(led, &sc) != NAME_NOT_FOUND) {
757*38e8c45fSAndroid Build Coastguard Worker         struct input_event ev;
758*38e8c45fSAndroid Build Coastguard Worker         ev.input_event_sec = 0;
759*38e8c45fSAndroid Build Coastguard Worker         ev.input_event_usec = 0;
760*38e8c45fSAndroid Build Coastguard Worker         ev.type = EV_LED;
761*38e8c45fSAndroid Build Coastguard Worker         ev.code = sc;
762*38e8c45fSAndroid Build Coastguard Worker         ev.value = on ? 1 : 0;
763*38e8c45fSAndroid Build Coastguard Worker 
764*38e8c45fSAndroid Build Coastguard Worker         ssize_t nWrite;
765*38e8c45fSAndroid Build Coastguard Worker         do {
766*38e8c45fSAndroid Build Coastguard Worker             nWrite = write(fd, &ev, sizeof(struct input_event));
767*38e8c45fSAndroid Build Coastguard Worker         } while (nWrite == -1 && errno == EINTR);
768*38e8c45fSAndroid Build Coastguard Worker     }
769*38e8c45fSAndroid Build Coastguard Worker }
770*38e8c45fSAndroid Build Coastguard Worker 
setLedForControllerLocked()771*38e8c45fSAndroid Build Coastguard Worker void EventHub::Device::setLedForControllerLocked() {
772*38e8c45fSAndroid Build Coastguard Worker     for (int i = 0; i < MAX_CONTROLLER_LEDS; i++) {
773*38e8c45fSAndroid Build Coastguard Worker         setLedStateLocked(ALED_CONTROLLER_1 + i, controllerNumber == i + 1);
774*38e8c45fSAndroid Build Coastguard Worker     }
775*38e8c45fSAndroid Build Coastguard Worker }
776*38e8c45fSAndroid Build Coastguard Worker 
mapLed(int32_t led,int32_t * outScanCode) const777*38e8c45fSAndroid Build Coastguard Worker status_t EventHub::Device::mapLed(int32_t led, int32_t* outScanCode) const {
778*38e8c45fSAndroid Build Coastguard Worker     if (!keyMap.haveKeyLayout()) {
779*38e8c45fSAndroid Build Coastguard Worker         return NAME_NOT_FOUND;
780*38e8c45fSAndroid Build Coastguard Worker     }
781*38e8c45fSAndroid Build Coastguard Worker 
782*38e8c45fSAndroid Build Coastguard Worker     std::optional<int32_t> scanCode = keyMap.keyLayoutMap->findScanCodeForLed(led);
783*38e8c45fSAndroid Build Coastguard Worker     if (scanCode.has_value()) {
784*38e8c45fSAndroid Build Coastguard Worker         if (*scanCode >= 0 && *scanCode <= LED_MAX && ledBitmask.test(*scanCode)) {
785*38e8c45fSAndroid Build Coastguard Worker             *outScanCode = *scanCode;
786*38e8c45fSAndroid Build Coastguard Worker             return NO_ERROR;
787*38e8c45fSAndroid Build Coastguard Worker         }
788*38e8c45fSAndroid Build Coastguard Worker     }
789*38e8c45fSAndroid Build Coastguard Worker     return NAME_NOT_FOUND;
790*38e8c45fSAndroid Build Coastguard Worker }
791*38e8c45fSAndroid Build Coastguard Worker 
trackInputEvent(const struct input_event & event)792*38e8c45fSAndroid Build Coastguard Worker void EventHub::Device::trackInputEvent(const struct input_event& event) {
793*38e8c45fSAndroid Build Coastguard Worker     switch (event.type) {
794*38e8c45fSAndroid Build Coastguard Worker         case EV_KEY: {
795*38e8c45fSAndroid Build Coastguard Worker             LOG_ALWAYS_FATAL_IF(!currentFrameDropped &&
796*38e8c45fSAndroid Build Coastguard Worker                                         !keyState.set(static_cast<size_t>(event.code),
797*38e8c45fSAndroid Build Coastguard Worker                                                       event.value != 0),
798*38e8c45fSAndroid Build Coastguard Worker                                 "%s: device '%s' received invalid EV_KEY event code: %s value: %d",
799*38e8c45fSAndroid Build Coastguard Worker                                 __func__, identifier.name.c_str(),
800*38e8c45fSAndroid Build Coastguard Worker                                 InputEventLookup::getLinuxEvdevLabel(EV_KEY, event.code, 1)
801*38e8c45fSAndroid Build Coastguard Worker                                         .code.c_str(),
802*38e8c45fSAndroid Build Coastguard Worker                                 event.value);
803*38e8c45fSAndroid Build Coastguard Worker             break;
804*38e8c45fSAndroid Build Coastguard Worker         }
805*38e8c45fSAndroid Build Coastguard Worker         case EV_SW: {
806*38e8c45fSAndroid Build Coastguard Worker             LOG_ALWAYS_FATAL_IF(!currentFrameDropped &&
807*38e8c45fSAndroid Build Coastguard Worker                                         !swState.set(static_cast<size_t>(event.code),
808*38e8c45fSAndroid Build Coastguard Worker                                                      event.value != 0),
809*38e8c45fSAndroid Build Coastguard Worker                                 "%s: device '%s' received invalid EV_SW event code: %s value: %d",
810*38e8c45fSAndroid Build Coastguard Worker                                 __func__, identifier.name.c_str(),
811*38e8c45fSAndroid Build Coastguard Worker                                 InputEventLookup::getLinuxEvdevLabel(EV_SW, event.code, 1)
812*38e8c45fSAndroid Build Coastguard Worker                                         .code.c_str(),
813*38e8c45fSAndroid Build Coastguard Worker                                 event.value);
814*38e8c45fSAndroid Build Coastguard Worker             break;
815*38e8c45fSAndroid Build Coastguard Worker         }
816*38e8c45fSAndroid Build Coastguard Worker         case EV_ABS: {
817*38e8c45fSAndroid Build Coastguard Worker             if (currentFrameDropped) {
818*38e8c45fSAndroid Build Coastguard Worker                 break;
819*38e8c45fSAndroid Build Coastguard Worker             }
820*38e8c45fSAndroid Build Coastguard Worker             auto it = absState.find(event.code);
821*38e8c45fSAndroid Build Coastguard Worker             LOG_ALWAYS_FATAL_IF(it == absState.end(),
822*38e8c45fSAndroid Build Coastguard Worker                                 "%s: device '%s' received invalid EV_ABS event code: %s value: %d",
823*38e8c45fSAndroid Build Coastguard Worker                                 __func__, identifier.name.c_str(),
824*38e8c45fSAndroid Build Coastguard Worker                                 InputEventLookup::getLinuxEvdevLabel(EV_ABS, event.code, 0)
825*38e8c45fSAndroid Build Coastguard Worker                                         .code.c_str(),
826*38e8c45fSAndroid Build Coastguard Worker                                 event.value);
827*38e8c45fSAndroid Build Coastguard Worker             it->second.value = event.value;
828*38e8c45fSAndroid Build Coastguard Worker             break;
829*38e8c45fSAndroid Build Coastguard Worker         }
830*38e8c45fSAndroid Build Coastguard Worker         case EV_SYN: {
831*38e8c45fSAndroid Build Coastguard Worker             switch (event.code) {
832*38e8c45fSAndroid Build Coastguard Worker                 case SYN_REPORT:
833*38e8c45fSAndroid Build Coastguard Worker                     if (currentFrameDropped) {
834*38e8c45fSAndroid Build Coastguard Worker                         // To recover after a SYN_DROPPED, we need to query the state of the device
835*38e8c45fSAndroid Build Coastguard Worker                         // to synchronize our device state with the kernel's to account for the
836*38e8c45fSAndroid Build Coastguard Worker                         // dropped events on receiving the next SYN_REPORT.
837*38e8c45fSAndroid Build Coastguard Worker                         // Note we don't drop the SYN_REPORT at this point but it is used by the
838*38e8c45fSAndroid Build Coastguard Worker                         // InputDevice to reset and repopulate mapper state
839*38e8c45fSAndroid Build Coastguard Worker                         readDeviceState();
840*38e8c45fSAndroid Build Coastguard Worker                         currentFrameDropped = false;
841*38e8c45fSAndroid Build Coastguard Worker                     }
842*38e8c45fSAndroid Build Coastguard Worker                     break;
843*38e8c45fSAndroid Build Coastguard Worker                 case SYN_DROPPED:
844*38e8c45fSAndroid Build Coastguard Worker                     // When we receive SYN_DROPPED, all events in the current frame should be
845*38e8c45fSAndroid Build Coastguard Worker                     // dropped up to and including next SYN_REPORT
846*38e8c45fSAndroid Build Coastguard Worker                     currentFrameDropped = true;
847*38e8c45fSAndroid Build Coastguard Worker                     break;
848*38e8c45fSAndroid Build Coastguard Worker                 default:
849*38e8c45fSAndroid Build Coastguard Worker                     break;
850*38e8c45fSAndroid Build Coastguard Worker             }
851*38e8c45fSAndroid Build Coastguard Worker             break;
852*38e8c45fSAndroid Build Coastguard Worker         }
853*38e8c45fSAndroid Build Coastguard Worker         default:
854*38e8c45fSAndroid Build Coastguard Worker             break;
855*38e8c45fSAndroid Build Coastguard Worker     }
856*38e8c45fSAndroid Build Coastguard Worker }
857*38e8c45fSAndroid Build Coastguard Worker 
858*38e8c45fSAndroid Build Coastguard Worker /**
859*38e8c45fSAndroid Build Coastguard Worker  * Get the capabilities for the current process.
860*38e8c45fSAndroid Build Coastguard Worker  * Crashes the system if unable to create / check / destroy the capabilities object.
861*38e8c45fSAndroid Build Coastguard Worker  */
862*38e8c45fSAndroid Build Coastguard Worker class Capabilities final {
863*38e8c45fSAndroid Build Coastguard Worker public:
Capabilities()864*38e8c45fSAndroid Build Coastguard Worker     explicit Capabilities() {
865*38e8c45fSAndroid Build Coastguard Worker         mCaps = cap_get_proc();
866*38e8c45fSAndroid Build Coastguard Worker         LOG_ALWAYS_FATAL_IF(mCaps == nullptr, "Could not get capabilities of the current process");
867*38e8c45fSAndroid Build Coastguard Worker     }
868*38e8c45fSAndroid Build Coastguard Worker 
869*38e8c45fSAndroid Build Coastguard Worker     /**
870*38e8c45fSAndroid Build Coastguard Worker      * Check whether the current process has a specific capability
871*38e8c45fSAndroid Build Coastguard Worker      * in the set of effective capabilities.
872*38e8c45fSAndroid Build Coastguard Worker      * Return CAP_SET if the process has the requested capability
873*38e8c45fSAndroid Build Coastguard Worker      * Return CAP_CLEAR otherwise.
874*38e8c45fSAndroid Build Coastguard Worker      */
checkEffectiveCapability(cap_value_t capability)875*38e8c45fSAndroid Build Coastguard Worker     cap_flag_value_t checkEffectiveCapability(cap_value_t capability) {
876*38e8c45fSAndroid Build Coastguard Worker         cap_flag_value_t value;
877*38e8c45fSAndroid Build Coastguard Worker         const int result = cap_get_flag(mCaps, capability, CAP_EFFECTIVE, &value);
878*38e8c45fSAndroid Build Coastguard Worker         LOG_ALWAYS_FATAL_IF(result == -1, "Could not obtain the requested capability");
879*38e8c45fSAndroid Build Coastguard Worker         return value;
880*38e8c45fSAndroid Build Coastguard Worker     }
881*38e8c45fSAndroid Build Coastguard Worker 
~Capabilities()882*38e8c45fSAndroid Build Coastguard Worker     ~Capabilities() {
883*38e8c45fSAndroid Build Coastguard Worker         const int result = cap_free(mCaps);
884*38e8c45fSAndroid Build Coastguard Worker         LOG_ALWAYS_FATAL_IF(result == -1, "Could not release the capabilities structure");
885*38e8c45fSAndroid Build Coastguard Worker     }
886*38e8c45fSAndroid Build Coastguard Worker 
887*38e8c45fSAndroid Build Coastguard Worker private:
888*38e8c45fSAndroid Build Coastguard Worker     cap_t mCaps;
889*38e8c45fSAndroid Build Coastguard Worker };
890*38e8c45fSAndroid Build Coastguard Worker 
ensureProcessCanBlockSuspend()891*38e8c45fSAndroid Build Coastguard Worker static void ensureProcessCanBlockSuspend() {
892*38e8c45fSAndroid Build Coastguard Worker     Capabilities capabilities;
893*38e8c45fSAndroid Build Coastguard Worker     const bool canBlockSuspend =
894*38e8c45fSAndroid Build Coastguard Worker             capabilities.checkEffectiveCapability(CAP_BLOCK_SUSPEND) == CAP_SET;
895*38e8c45fSAndroid Build Coastguard Worker     LOG_ALWAYS_FATAL_IF(!canBlockSuspend,
896*38e8c45fSAndroid Build Coastguard Worker                         "Input must be able to block suspend to properly process events");
897*38e8c45fSAndroid Build Coastguard Worker }
898*38e8c45fSAndroid Build Coastguard Worker 
899*38e8c45fSAndroid Build Coastguard Worker // --- EventHub ---
900*38e8c45fSAndroid Build Coastguard Worker 
901*38e8c45fSAndroid Build Coastguard Worker const int EventHub::EPOLL_MAX_EVENTS;
902*38e8c45fSAndroid Build Coastguard Worker 
EventHub(void)903*38e8c45fSAndroid Build Coastguard Worker EventHub::EventHub(void)
904*38e8c45fSAndroid Build Coastguard Worker       : mBuiltInKeyboardId(NO_BUILT_IN_KEYBOARD),
905*38e8c45fSAndroid Build Coastguard Worker         mNextDeviceId(1),
906*38e8c45fSAndroid Build Coastguard Worker         mControllerNumbers(),
907*38e8c45fSAndroid Build Coastguard Worker         mNeedToReopenDevices(false),
908*38e8c45fSAndroid Build Coastguard Worker         mNeedToScanDevices(true),
909*38e8c45fSAndroid Build Coastguard Worker         mPendingEventCount(0),
910*38e8c45fSAndroid Build Coastguard Worker         mPendingEventIndex(0),
911*38e8c45fSAndroid Build Coastguard Worker         mPendingINotify(false) {
912*38e8c45fSAndroid Build Coastguard Worker     ensureProcessCanBlockSuspend();
913*38e8c45fSAndroid Build Coastguard Worker 
914*38e8c45fSAndroid Build Coastguard Worker     mEpollFd = epoll_create1(EPOLL_CLOEXEC);
915*38e8c45fSAndroid Build Coastguard Worker     LOG_ALWAYS_FATAL_IF(mEpollFd < 0, "Could not create epoll instance: %s", strerror(errno));
916*38e8c45fSAndroid Build Coastguard Worker 
917*38e8c45fSAndroid Build Coastguard Worker     mINotifyFd = inotify_init1(IN_CLOEXEC);
918*38e8c45fSAndroid Build Coastguard Worker     LOG_ALWAYS_FATAL_IF(mINotifyFd < 0, "Could not create inotify instance: %s", strerror(errno));
919*38e8c45fSAndroid Build Coastguard Worker 
920*38e8c45fSAndroid Build Coastguard Worker     std::error_code errorCode;
921*38e8c45fSAndroid Build Coastguard Worker     bool isDeviceInotifyAdded = false;
922*38e8c45fSAndroid Build Coastguard Worker     if (std::filesystem::exists(DEVICE_INPUT_PATH, errorCode)) {
923*38e8c45fSAndroid Build Coastguard Worker         addDeviceInputInotify();
924*38e8c45fSAndroid Build Coastguard Worker     } else {
925*38e8c45fSAndroid Build Coastguard Worker         addDeviceInotify();
926*38e8c45fSAndroid Build Coastguard Worker         isDeviceInotifyAdded = true;
927*38e8c45fSAndroid Build Coastguard Worker         if (errorCode) {
928*38e8c45fSAndroid Build Coastguard Worker             ALOGW("Could not run filesystem::exists() due to error %d : %s.", errorCode.value(),
929*38e8c45fSAndroid Build Coastguard Worker                   errorCode.message().c_str());
930*38e8c45fSAndroid Build Coastguard Worker         }
931*38e8c45fSAndroid Build Coastguard Worker     }
932*38e8c45fSAndroid Build Coastguard Worker 
933*38e8c45fSAndroid Build Coastguard Worker     if (isV4lScanningEnabled() && !isDeviceInotifyAdded) {
934*38e8c45fSAndroid Build Coastguard Worker         addDeviceInotify();
935*38e8c45fSAndroid Build Coastguard Worker     } else {
936*38e8c45fSAndroid Build Coastguard Worker         ALOGI("Video device scanning disabled");
937*38e8c45fSAndroid Build Coastguard Worker     }
938*38e8c45fSAndroid Build Coastguard Worker 
939*38e8c45fSAndroid Build Coastguard Worker     struct epoll_event eventItem = {};
940*38e8c45fSAndroid Build Coastguard Worker     eventItem.events = EPOLLIN | EPOLLWAKEUP;
941*38e8c45fSAndroid Build Coastguard Worker     eventItem.data.fd = mINotifyFd;
942*38e8c45fSAndroid Build Coastguard Worker     int result = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mINotifyFd, &eventItem);
943*38e8c45fSAndroid Build Coastguard Worker     LOG_ALWAYS_FATAL_IF(result != 0, "Could not add INotify to epoll instance.  errno=%d", errno);
944*38e8c45fSAndroid Build Coastguard Worker 
945*38e8c45fSAndroid Build Coastguard Worker     int wakeFds[2];
946*38e8c45fSAndroid Build Coastguard Worker     result = pipe2(wakeFds, O_CLOEXEC);
947*38e8c45fSAndroid Build Coastguard Worker     LOG_ALWAYS_FATAL_IF(result != 0, "Could not create wake pipe.  errno=%d", errno);
948*38e8c45fSAndroid Build Coastguard Worker 
949*38e8c45fSAndroid Build Coastguard Worker     mWakeReadPipeFd = wakeFds[0];
950*38e8c45fSAndroid Build Coastguard Worker     mWakeWritePipeFd = wakeFds[1];
951*38e8c45fSAndroid Build Coastguard Worker 
952*38e8c45fSAndroid Build Coastguard Worker     result = fcntl(mWakeReadPipeFd, F_SETFL, O_NONBLOCK);
953*38e8c45fSAndroid Build Coastguard Worker     LOG_ALWAYS_FATAL_IF(result != 0, "Could not make wake read pipe non-blocking.  errno=%d",
954*38e8c45fSAndroid Build Coastguard Worker                         errno);
955*38e8c45fSAndroid Build Coastguard Worker 
956*38e8c45fSAndroid Build Coastguard Worker     result = fcntl(mWakeWritePipeFd, F_SETFL, O_NONBLOCK);
957*38e8c45fSAndroid Build Coastguard Worker     LOG_ALWAYS_FATAL_IF(result != 0, "Could not make wake write pipe non-blocking.  errno=%d",
958*38e8c45fSAndroid Build Coastguard Worker                         errno);
959*38e8c45fSAndroid Build Coastguard Worker 
960*38e8c45fSAndroid Build Coastguard Worker     eventItem.data.fd = mWakeReadPipeFd;
961*38e8c45fSAndroid Build Coastguard Worker     result = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mWakeReadPipeFd, &eventItem);
962*38e8c45fSAndroid Build Coastguard Worker     LOG_ALWAYS_FATAL_IF(result != 0, "Could not add wake read pipe to epoll instance.  errno=%d",
963*38e8c45fSAndroid Build Coastguard Worker                         errno);
964*38e8c45fSAndroid Build Coastguard Worker }
965*38e8c45fSAndroid Build Coastguard Worker 
~EventHub(void)966*38e8c45fSAndroid Build Coastguard Worker EventHub::~EventHub(void) {
967*38e8c45fSAndroid Build Coastguard Worker     closeAllDevicesLocked();
968*38e8c45fSAndroid Build Coastguard Worker 
969*38e8c45fSAndroid Build Coastguard Worker     ::close(mEpollFd);
970*38e8c45fSAndroid Build Coastguard Worker     ::close(mINotifyFd);
971*38e8c45fSAndroid Build Coastguard Worker     ::close(mWakeReadPipeFd);
972*38e8c45fSAndroid Build Coastguard Worker     ::close(mWakeWritePipeFd);
973*38e8c45fSAndroid Build Coastguard Worker }
974*38e8c45fSAndroid Build Coastguard Worker 
975*38e8c45fSAndroid Build Coastguard Worker /**
976*38e8c45fSAndroid Build Coastguard Worker  * On devices that don't have any input devices (like some development boards), the /dev/input
977*38e8c45fSAndroid Build Coastguard Worker  * directory will be absent. However, the user may still plug in an input device at a later time.
978*38e8c45fSAndroid Build Coastguard Worker  * Add watch for contents of /dev/input only when /dev/input appears.
979*38e8c45fSAndroid Build Coastguard Worker  */
addDeviceInputInotify()980*38e8c45fSAndroid Build Coastguard Worker void EventHub::addDeviceInputInotify() {
981*38e8c45fSAndroid Build Coastguard Worker     mDeviceInputWd = inotify_add_watch(mINotifyFd, DEVICE_INPUT_PATH, IN_DELETE | IN_CREATE);
982*38e8c45fSAndroid Build Coastguard Worker     LOG_ALWAYS_FATAL_IF(mDeviceInputWd < 0, "Could not register INotify for %s: %s",
983*38e8c45fSAndroid Build Coastguard Worker                         DEVICE_INPUT_PATH, strerror(errno));
984*38e8c45fSAndroid Build Coastguard Worker }
985*38e8c45fSAndroid Build Coastguard Worker 
addDeviceInotify()986*38e8c45fSAndroid Build Coastguard Worker void EventHub::addDeviceInotify() {
987*38e8c45fSAndroid Build Coastguard Worker     mDeviceWd = inotify_add_watch(mINotifyFd, DEVICE_PATH, IN_DELETE | IN_CREATE);
988*38e8c45fSAndroid Build Coastguard Worker     LOG_ALWAYS_FATAL_IF(mDeviceWd < 0, "Could not register INotify for %s: %s", DEVICE_PATH,
989*38e8c45fSAndroid Build Coastguard Worker                         strerror(errno));
990*38e8c45fSAndroid Build Coastguard Worker }
991*38e8c45fSAndroid Build Coastguard Worker 
getDeviceIdentifier(int32_t deviceId) const992*38e8c45fSAndroid Build Coastguard Worker InputDeviceIdentifier EventHub::getDeviceIdentifier(int32_t deviceId) const {
993*38e8c45fSAndroid Build Coastguard Worker     std::scoped_lock _l(mLock);
994*38e8c45fSAndroid Build Coastguard Worker     Device* device = getDeviceLocked(deviceId);
995*38e8c45fSAndroid Build Coastguard Worker     return device != nullptr ? device->identifier : InputDeviceIdentifier();
996*38e8c45fSAndroid Build Coastguard Worker }
997*38e8c45fSAndroid Build Coastguard Worker 
getDeviceClasses(int32_t deviceId) const998*38e8c45fSAndroid Build Coastguard Worker ftl::Flags<InputDeviceClass> EventHub::getDeviceClasses(int32_t deviceId) const {
999*38e8c45fSAndroid Build Coastguard Worker     std::scoped_lock _l(mLock);
1000*38e8c45fSAndroid Build Coastguard Worker     Device* device = getDeviceLocked(deviceId);
1001*38e8c45fSAndroid Build Coastguard Worker     return device != nullptr ? device->classes : ftl::Flags<InputDeviceClass>(0);
1002*38e8c45fSAndroid Build Coastguard Worker }
1003*38e8c45fSAndroid Build Coastguard Worker 
getDeviceControllerNumber(int32_t deviceId) const1004*38e8c45fSAndroid Build Coastguard Worker int32_t EventHub::getDeviceControllerNumber(int32_t deviceId) const {
1005*38e8c45fSAndroid Build Coastguard Worker     std::scoped_lock _l(mLock);
1006*38e8c45fSAndroid Build Coastguard Worker     Device* device = getDeviceLocked(deviceId);
1007*38e8c45fSAndroid Build Coastguard Worker     return device != nullptr ? device->controllerNumber : 0;
1008*38e8c45fSAndroid Build Coastguard Worker }
1009*38e8c45fSAndroid Build Coastguard Worker 
getConfiguration(int32_t deviceId) const1010*38e8c45fSAndroid Build Coastguard Worker std::optional<PropertyMap> EventHub::getConfiguration(int32_t deviceId) const {
1011*38e8c45fSAndroid Build Coastguard Worker     std::scoped_lock _l(mLock);
1012*38e8c45fSAndroid Build Coastguard Worker     Device* device = getDeviceLocked(deviceId);
1013*38e8c45fSAndroid Build Coastguard Worker     if (device == nullptr || device->configuration == nullptr) {
1014*38e8c45fSAndroid Build Coastguard Worker         return {};
1015*38e8c45fSAndroid Build Coastguard Worker     }
1016*38e8c45fSAndroid Build Coastguard Worker     return *device->configuration;
1017*38e8c45fSAndroid Build Coastguard Worker }
1018*38e8c45fSAndroid Build Coastguard Worker 
getAbsoluteAxisInfo(int32_t deviceId,int axis) const1019*38e8c45fSAndroid Build Coastguard Worker std::optional<RawAbsoluteAxisInfo> EventHub::getAbsoluteAxisInfo(int32_t deviceId, int axis) const {
1020*38e8c45fSAndroid Build Coastguard Worker     if (axis < 0 || axis > ABS_MAX) {
1021*38e8c45fSAndroid Build Coastguard Worker         return std::nullopt;
1022*38e8c45fSAndroid Build Coastguard Worker     }
1023*38e8c45fSAndroid Build Coastguard Worker     std::scoped_lock _l(mLock);
1024*38e8c45fSAndroid Build Coastguard Worker     const Device* device = getDeviceLocked(deviceId);
1025*38e8c45fSAndroid Build Coastguard Worker     if (device == nullptr) {
1026*38e8c45fSAndroid Build Coastguard Worker         ALOGE("Couldn't find device with ID %d, so returning null axis info for axis %s", deviceId,
1027*38e8c45fSAndroid Build Coastguard Worker               InputEventLookup::getLinuxEvdevLabel(EV_ABS, axis, 0).code.c_str());
1028*38e8c45fSAndroid Build Coastguard Worker         return std::nullopt;
1029*38e8c45fSAndroid Build Coastguard Worker     }
1030*38e8c45fSAndroid Build Coastguard Worker     // We can read the RawAbsoluteAxisInfo even if the device is disabled and doesn't have a valid
1031*38e8c45fSAndroid Build Coastguard Worker     // fd, because the info is populated once when the device is first opened, and it doesn't change
1032*38e8c45fSAndroid Build Coastguard Worker     // throughout the device lifecycle.
1033*38e8c45fSAndroid Build Coastguard Worker     auto it = device->absState.find(axis);
1034*38e8c45fSAndroid Build Coastguard Worker     if (it == device->absState.end()) {
1035*38e8c45fSAndroid Build Coastguard Worker         return std::nullopt;
1036*38e8c45fSAndroid Build Coastguard Worker     }
1037*38e8c45fSAndroid Build Coastguard Worker     return it->second.info;
1038*38e8c45fSAndroid Build Coastguard Worker }
1039*38e8c45fSAndroid Build Coastguard Worker 
hasRelativeAxis(int32_t deviceId,int axis) const1040*38e8c45fSAndroid Build Coastguard Worker bool EventHub::hasRelativeAxis(int32_t deviceId, int axis) const {
1041*38e8c45fSAndroid Build Coastguard Worker     if (axis >= 0 && axis <= REL_MAX) {
1042*38e8c45fSAndroid Build Coastguard Worker         std::scoped_lock _l(mLock);
1043*38e8c45fSAndroid Build Coastguard Worker         Device* device = getDeviceLocked(deviceId);
1044*38e8c45fSAndroid Build Coastguard Worker         return device != nullptr ? device->relBitmask.test(axis) : false;
1045*38e8c45fSAndroid Build Coastguard Worker     }
1046*38e8c45fSAndroid Build Coastguard Worker     return false;
1047*38e8c45fSAndroid Build Coastguard Worker }
1048*38e8c45fSAndroid Build Coastguard Worker 
hasInputProperty(int32_t deviceId,int property) const1049*38e8c45fSAndroid Build Coastguard Worker bool EventHub::hasInputProperty(int32_t deviceId, int property) const {
1050*38e8c45fSAndroid Build Coastguard Worker     std::scoped_lock _l(mLock);
1051*38e8c45fSAndroid Build Coastguard Worker 
1052*38e8c45fSAndroid Build Coastguard Worker     Device* device = getDeviceLocked(deviceId);
1053*38e8c45fSAndroid Build Coastguard Worker     return property >= 0 && property <= INPUT_PROP_MAX && device != nullptr
1054*38e8c45fSAndroid Build Coastguard Worker             ? device->propBitmask.test(property)
1055*38e8c45fSAndroid Build Coastguard Worker             : false;
1056*38e8c45fSAndroid Build Coastguard Worker }
1057*38e8c45fSAndroid Build Coastguard Worker 
hasMscEvent(int32_t deviceId,int mscEvent) const1058*38e8c45fSAndroid Build Coastguard Worker bool EventHub::hasMscEvent(int32_t deviceId, int mscEvent) const {
1059*38e8c45fSAndroid Build Coastguard Worker     std::scoped_lock _l(mLock);
1060*38e8c45fSAndroid Build Coastguard Worker 
1061*38e8c45fSAndroid Build Coastguard Worker     Device* device = getDeviceLocked(deviceId);
1062*38e8c45fSAndroid Build Coastguard Worker     return mscEvent >= 0 && mscEvent <= MSC_MAX && device != nullptr
1063*38e8c45fSAndroid Build Coastguard Worker             ? device->mscBitmask.test(mscEvent)
1064*38e8c45fSAndroid Build Coastguard Worker             : false;
1065*38e8c45fSAndroid Build Coastguard Worker }
1066*38e8c45fSAndroid Build Coastguard Worker 
getScanCodeState(int32_t deviceId,int32_t scanCode) const1067*38e8c45fSAndroid Build Coastguard Worker int32_t EventHub::getScanCodeState(int32_t deviceId, int32_t scanCode) const {
1068*38e8c45fSAndroid Build Coastguard Worker     if (scanCode < 0 || scanCode > KEY_MAX) {
1069*38e8c45fSAndroid Build Coastguard Worker         return AKEY_STATE_UNKNOWN;
1070*38e8c45fSAndroid Build Coastguard Worker     }
1071*38e8c45fSAndroid Build Coastguard Worker     std::scoped_lock _l(mLock);
1072*38e8c45fSAndroid Build Coastguard Worker     const Device* device = getDeviceLocked(deviceId);
1073*38e8c45fSAndroid Build Coastguard Worker     if (device == nullptr || !device->hasValidFd() || !device->keyBitmask.test(scanCode)) {
1074*38e8c45fSAndroid Build Coastguard Worker         return AKEY_STATE_UNKNOWN;
1075*38e8c45fSAndroid Build Coastguard Worker     }
1076*38e8c45fSAndroid Build Coastguard Worker     return device->keyState.test(scanCode) ? AKEY_STATE_DOWN : AKEY_STATE_UP;
1077*38e8c45fSAndroid Build Coastguard Worker }
1078*38e8c45fSAndroid Build Coastguard Worker 
getKeyCodeState(int32_t deviceId,int32_t keyCode) const1079*38e8c45fSAndroid Build Coastguard Worker int32_t EventHub::getKeyCodeState(int32_t deviceId, int32_t keyCode) const {
1080*38e8c45fSAndroid Build Coastguard Worker     std::scoped_lock _l(mLock);
1081*38e8c45fSAndroid Build Coastguard Worker     const Device* device = getDeviceLocked(deviceId);
1082*38e8c45fSAndroid Build Coastguard Worker     if (device == nullptr || !device->hasValidFd() || !device->keyMap.haveKeyLayout()) {
1083*38e8c45fSAndroid Build Coastguard Worker         return AKEY_STATE_UNKNOWN;
1084*38e8c45fSAndroid Build Coastguard Worker     }
1085*38e8c45fSAndroid Build Coastguard Worker     const std::vector<int32_t> scanCodes =
1086*38e8c45fSAndroid Build Coastguard Worker             device->keyMap.keyLayoutMap->findScanCodesForKey(keyCode);
1087*38e8c45fSAndroid Build Coastguard Worker     if (scanCodes.empty()) {
1088*38e8c45fSAndroid Build Coastguard Worker         return AKEY_STATE_UNKNOWN;
1089*38e8c45fSAndroid Build Coastguard Worker     }
1090*38e8c45fSAndroid Build Coastguard Worker     return std::any_of(scanCodes.begin(), scanCodes.end(),
1091*38e8c45fSAndroid Build Coastguard Worker                        [&device](const int32_t sc) {
1092*38e8c45fSAndroid Build Coastguard Worker                            return sc >= 0 && sc <= KEY_MAX && device->keyState.test(sc);
1093*38e8c45fSAndroid Build Coastguard Worker                        })
1094*38e8c45fSAndroid Build Coastguard Worker             ? AKEY_STATE_DOWN
1095*38e8c45fSAndroid Build Coastguard Worker             : AKEY_STATE_UP;
1096*38e8c45fSAndroid Build Coastguard Worker }
1097*38e8c45fSAndroid Build Coastguard Worker 
getKeyCodeForKeyLocation(int32_t deviceId,int32_t locationKeyCode) const1098*38e8c45fSAndroid Build Coastguard Worker int32_t EventHub::getKeyCodeForKeyLocation(int32_t deviceId, int32_t locationKeyCode) const {
1099*38e8c45fSAndroid Build Coastguard Worker     std::scoped_lock _l(mLock);
1100*38e8c45fSAndroid Build Coastguard Worker 
1101*38e8c45fSAndroid Build Coastguard Worker     Device* device = getDeviceLocked(deviceId);
1102*38e8c45fSAndroid Build Coastguard Worker     if (device == nullptr || !device->hasValidFd() || device->keyMap.keyCharacterMap == nullptr ||
1103*38e8c45fSAndroid Build Coastguard Worker         device->keyMap.keyLayoutMap == nullptr) {
1104*38e8c45fSAndroid Build Coastguard Worker         return AKEYCODE_UNKNOWN;
1105*38e8c45fSAndroid Build Coastguard Worker     }
1106*38e8c45fSAndroid Build Coastguard Worker     std::vector<int32_t> scanCodes =
1107*38e8c45fSAndroid Build Coastguard Worker             device->keyMap.keyLayoutMap->findScanCodesForKey(locationKeyCode);
1108*38e8c45fSAndroid Build Coastguard Worker     if (scanCodes.empty()) {
1109*38e8c45fSAndroid Build Coastguard Worker         ALOGW("Failed to get key code for key location: no scan code maps to key code %d for input"
1110*38e8c45fSAndroid Build Coastguard Worker               "device %d",
1111*38e8c45fSAndroid Build Coastguard Worker               locationKeyCode, deviceId);
1112*38e8c45fSAndroid Build Coastguard Worker         return AKEYCODE_UNKNOWN;
1113*38e8c45fSAndroid Build Coastguard Worker     }
1114*38e8c45fSAndroid Build Coastguard Worker     if (scanCodes.size() > 1) {
1115*38e8c45fSAndroid Build Coastguard Worker         ALOGW("Multiple scan codes map to the same key code %d, returning only the first match",
1116*38e8c45fSAndroid Build Coastguard Worker               locationKeyCode);
1117*38e8c45fSAndroid Build Coastguard Worker     }
1118*38e8c45fSAndroid Build Coastguard Worker     int32_t outKeyCode;
1119*38e8c45fSAndroid Build Coastguard Worker     status_t mapKeyRes =
1120*38e8c45fSAndroid Build Coastguard Worker             device->getKeyCharacterMap()->mapKey(scanCodes[0], /*usageCode=*/0, &outKeyCode);
1121*38e8c45fSAndroid Build Coastguard Worker     switch (mapKeyRes) {
1122*38e8c45fSAndroid Build Coastguard Worker         case OK:
1123*38e8c45fSAndroid Build Coastguard Worker             break;
1124*38e8c45fSAndroid Build Coastguard Worker         case NAME_NOT_FOUND:
1125*38e8c45fSAndroid Build Coastguard Worker             // key character map doesn't re-map this scanCode, hence the keyCode remains the same
1126*38e8c45fSAndroid Build Coastguard Worker             outKeyCode = locationKeyCode;
1127*38e8c45fSAndroid Build Coastguard Worker             break;
1128*38e8c45fSAndroid Build Coastguard Worker         default:
1129*38e8c45fSAndroid Build Coastguard Worker             ALOGW("Failed to get key code for key location: Key character map returned error %s",
1130*38e8c45fSAndroid Build Coastguard Worker                   statusToString(mapKeyRes).c_str());
1131*38e8c45fSAndroid Build Coastguard Worker             outKeyCode = AKEYCODE_UNKNOWN;
1132*38e8c45fSAndroid Build Coastguard Worker             break;
1133*38e8c45fSAndroid Build Coastguard Worker     }
1134*38e8c45fSAndroid Build Coastguard Worker     // Remap if there is a Key remapping added to the KCM and return the remapped key
1135*38e8c45fSAndroid Build Coastguard Worker     return device->getKeyCharacterMap()->applyKeyRemapping(outKeyCode);
1136*38e8c45fSAndroid Build Coastguard Worker }
1137*38e8c45fSAndroid Build Coastguard Worker 
getSwitchState(int32_t deviceId,int32_t sw) const1138*38e8c45fSAndroid Build Coastguard Worker int32_t EventHub::getSwitchState(int32_t deviceId, int32_t sw) const {
1139*38e8c45fSAndroid Build Coastguard Worker     if (sw < 0 || sw > SW_MAX) {
1140*38e8c45fSAndroid Build Coastguard Worker         return AKEY_STATE_UNKNOWN;
1141*38e8c45fSAndroid Build Coastguard Worker     }
1142*38e8c45fSAndroid Build Coastguard Worker     std::scoped_lock _l(mLock);
1143*38e8c45fSAndroid Build Coastguard Worker     const Device* device = getDeviceLocked(deviceId);
1144*38e8c45fSAndroid Build Coastguard Worker     if (device == nullptr || !device->hasValidFd() || !device->swBitmask.test(sw)) {
1145*38e8c45fSAndroid Build Coastguard Worker         return AKEY_STATE_UNKNOWN;
1146*38e8c45fSAndroid Build Coastguard Worker     }
1147*38e8c45fSAndroid Build Coastguard Worker     return device->swState.test(sw) ? AKEY_STATE_DOWN : AKEY_STATE_UP;
1148*38e8c45fSAndroid Build Coastguard Worker }
1149*38e8c45fSAndroid Build Coastguard Worker 
getAbsoluteAxisValue(int32_t deviceId,int32_t axis) const1150*38e8c45fSAndroid Build Coastguard Worker std::optional<int32_t> EventHub::getAbsoluteAxisValue(int32_t deviceId, int32_t axis) const {
1151*38e8c45fSAndroid Build Coastguard Worker     if (axis < 0 || axis > ABS_MAX) {
1152*38e8c45fSAndroid Build Coastguard Worker         return std::nullopt;
1153*38e8c45fSAndroid Build Coastguard Worker     }
1154*38e8c45fSAndroid Build Coastguard Worker     std::scoped_lock _l(mLock);
1155*38e8c45fSAndroid Build Coastguard Worker     const Device* device = getDeviceLocked(deviceId);
1156*38e8c45fSAndroid Build Coastguard Worker     if (device == nullptr || !device->hasValidFd()) {
1157*38e8c45fSAndroid Build Coastguard Worker         return std::nullopt;
1158*38e8c45fSAndroid Build Coastguard Worker     }
1159*38e8c45fSAndroid Build Coastguard Worker     const auto it = device->absState.find(axis);
1160*38e8c45fSAndroid Build Coastguard Worker     if (it == device->absState.end()) {
1161*38e8c45fSAndroid Build Coastguard Worker         return std::nullopt;
1162*38e8c45fSAndroid Build Coastguard Worker     }
1163*38e8c45fSAndroid Build Coastguard Worker     return it->second.value;
1164*38e8c45fSAndroid Build Coastguard Worker }
1165*38e8c45fSAndroid Build Coastguard Worker 
getMtSlotValues(int32_t deviceId,int32_t axis,size_t slotCount) const1166*38e8c45fSAndroid Build Coastguard Worker base::Result<std::vector<int32_t>> EventHub::getMtSlotValues(int32_t deviceId, int32_t axis,
1167*38e8c45fSAndroid Build Coastguard Worker                                                              size_t slotCount) const {
1168*38e8c45fSAndroid Build Coastguard Worker     std::scoped_lock _l(mLock);
1169*38e8c45fSAndroid Build Coastguard Worker     const Device* device = getDeviceLocked(deviceId);
1170*38e8c45fSAndroid Build Coastguard Worker     if (device == nullptr || !device->hasValidFd() || !device->absBitmask.test(axis)) {
1171*38e8c45fSAndroid Build Coastguard Worker         return base::ResultError("device problem or axis not supported", NAME_NOT_FOUND);
1172*38e8c45fSAndroid Build Coastguard Worker     }
1173*38e8c45fSAndroid Build Coastguard Worker     std::vector<int32_t> outValues(slotCount + 1);
1174*38e8c45fSAndroid Build Coastguard Worker     outValues[0] = axis;
1175*38e8c45fSAndroid Build Coastguard Worker     const size_t bufferSize = outValues.size() * sizeof(int32_t);
1176*38e8c45fSAndroid Build Coastguard Worker     if (ioctl(device->fd, EVIOCGMTSLOTS(bufferSize), outValues.data()) != OK) {
1177*38e8c45fSAndroid Build Coastguard Worker         return base::ErrnoError();
1178*38e8c45fSAndroid Build Coastguard Worker     }
1179*38e8c45fSAndroid Build Coastguard Worker     return std::move(outValues);
1180*38e8c45fSAndroid Build Coastguard Worker }
1181*38e8c45fSAndroid Build Coastguard Worker 
markSupportedKeyCodes(int32_t deviceId,const std::vector<int32_t> & keyCodes,uint8_t * outFlags) const1182*38e8c45fSAndroid Build Coastguard Worker bool EventHub::markSupportedKeyCodes(int32_t deviceId, const std::vector<int32_t>& keyCodes,
1183*38e8c45fSAndroid Build Coastguard Worker                                      uint8_t* outFlags) const {
1184*38e8c45fSAndroid Build Coastguard Worker     std::scoped_lock _l(mLock);
1185*38e8c45fSAndroid Build Coastguard Worker 
1186*38e8c45fSAndroid Build Coastguard Worker     Device* device = getDeviceLocked(deviceId);
1187*38e8c45fSAndroid Build Coastguard Worker     if (device != nullptr && device->keyMap.haveKeyLayout()) {
1188*38e8c45fSAndroid Build Coastguard Worker         for (size_t codeIndex = 0; codeIndex < keyCodes.size(); codeIndex++) {
1189*38e8c45fSAndroid Build Coastguard Worker             if (device->hasKeycodeLocked(keyCodes[codeIndex])) {
1190*38e8c45fSAndroid Build Coastguard Worker                 outFlags[codeIndex] = 1;
1191*38e8c45fSAndroid Build Coastguard Worker             }
1192*38e8c45fSAndroid Build Coastguard Worker         }
1193*38e8c45fSAndroid Build Coastguard Worker         return true;
1194*38e8c45fSAndroid Build Coastguard Worker     }
1195*38e8c45fSAndroid Build Coastguard Worker     return false;
1196*38e8c45fSAndroid Build Coastguard Worker }
1197*38e8c45fSAndroid Build Coastguard Worker 
setKeyRemapping(int32_t deviceId,const std::map<int32_t,int32_t> & keyRemapping) const1198*38e8c45fSAndroid Build Coastguard Worker void EventHub::setKeyRemapping(int32_t deviceId,
1199*38e8c45fSAndroid Build Coastguard Worker                                const std::map<int32_t, int32_t>& keyRemapping) const {
1200*38e8c45fSAndroid Build Coastguard Worker     std::scoped_lock _l(mLock);
1201*38e8c45fSAndroid Build Coastguard Worker     Device* device = getDeviceLocked(deviceId);
1202*38e8c45fSAndroid Build Coastguard Worker     if (device == nullptr) {
1203*38e8c45fSAndroid Build Coastguard Worker         return;
1204*38e8c45fSAndroid Build Coastguard Worker     }
1205*38e8c45fSAndroid Build Coastguard Worker     const std::shared_ptr<KeyCharacterMap> kcm = device->getKeyCharacterMap();
1206*38e8c45fSAndroid Build Coastguard Worker     if (kcm) {
1207*38e8c45fSAndroid Build Coastguard Worker         kcm->setKeyRemapping(keyRemapping);
1208*38e8c45fSAndroid Build Coastguard Worker     }
1209*38e8c45fSAndroid Build Coastguard Worker }
1210*38e8c45fSAndroid Build Coastguard Worker 
mapKey(int32_t deviceId,int32_t scanCode,int32_t usageCode,int32_t metaState,int32_t * outKeycode,int32_t * outMetaState,uint32_t * outFlags) const1211*38e8c45fSAndroid Build Coastguard Worker status_t EventHub::mapKey(int32_t deviceId, int32_t scanCode, int32_t usageCode, int32_t metaState,
1212*38e8c45fSAndroid Build Coastguard Worker                           int32_t* outKeycode, int32_t* outMetaState, uint32_t* outFlags) const {
1213*38e8c45fSAndroid Build Coastguard Worker     std::scoped_lock _l(mLock);
1214*38e8c45fSAndroid Build Coastguard Worker     Device* device = getDeviceLocked(deviceId);
1215*38e8c45fSAndroid Build Coastguard Worker     status_t status = NAME_NOT_FOUND;
1216*38e8c45fSAndroid Build Coastguard Worker 
1217*38e8c45fSAndroid Build Coastguard Worker     if (device != nullptr) {
1218*38e8c45fSAndroid Build Coastguard Worker         // Check the key character map first.
1219*38e8c45fSAndroid Build Coastguard Worker         const std::shared_ptr<KeyCharacterMap> kcm = device->getKeyCharacterMap();
1220*38e8c45fSAndroid Build Coastguard Worker         if (kcm) {
1221*38e8c45fSAndroid Build Coastguard Worker             if (!kcm->mapKey(scanCode, usageCode, outKeycode)) {
1222*38e8c45fSAndroid Build Coastguard Worker                 *outFlags = 0;
1223*38e8c45fSAndroid Build Coastguard Worker                 status = NO_ERROR;
1224*38e8c45fSAndroid Build Coastguard Worker             }
1225*38e8c45fSAndroid Build Coastguard Worker         }
1226*38e8c45fSAndroid Build Coastguard Worker 
1227*38e8c45fSAndroid Build Coastguard Worker         // Check the key layout next.
1228*38e8c45fSAndroid Build Coastguard Worker         if (status != NO_ERROR && device->keyMap.haveKeyLayout()) {
1229*38e8c45fSAndroid Build Coastguard Worker             if (!device->keyMap.keyLayoutMap->mapKey(scanCode, usageCode, outKeycode, outFlags)) {
1230*38e8c45fSAndroid Build Coastguard Worker                 status = NO_ERROR;
1231*38e8c45fSAndroid Build Coastguard Worker             }
1232*38e8c45fSAndroid Build Coastguard Worker         }
1233*38e8c45fSAndroid Build Coastguard Worker 
1234*38e8c45fSAndroid Build Coastguard Worker         if (status == NO_ERROR) {
1235*38e8c45fSAndroid Build Coastguard Worker             if (kcm) {
1236*38e8c45fSAndroid Build Coastguard Worker                 // Remap keys based on user-defined key remappings and key behavior defined in the
1237*38e8c45fSAndroid Build Coastguard Worker                 // corresponding kcm file
1238*38e8c45fSAndroid Build Coastguard Worker                 *outKeycode = kcm->applyKeyRemapping(*outKeycode);
1239*38e8c45fSAndroid Build Coastguard Worker 
1240*38e8c45fSAndroid Build Coastguard Worker                 // Remap keys based on Key behavior defined in KCM file
1241*38e8c45fSAndroid Build Coastguard Worker                 std::tie(*outKeycode, *outMetaState) =
1242*38e8c45fSAndroid Build Coastguard Worker                         kcm->applyKeyBehavior(*outKeycode, metaState);
1243*38e8c45fSAndroid Build Coastguard Worker             } else {
1244*38e8c45fSAndroid Build Coastguard Worker                 *outMetaState = metaState;
1245*38e8c45fSAndroid Build Coastguard Worker             }
1246*38e8c45fSAndroid Build Coastguard Worker         }
1247*38e8c45fSAndroid Build Coastguard Worker     }
1248*38e8c45fSAndroid Build Coastguard Worker 
1249*38e8c45fSAndroid Build Coastguard Worker     if (status != NO_ERROR) {
1250*38e8c45fSAndroid Build Coastguard Worker         *outKeycode = 0;
1251*38e8c45fSAndroid Build Coastguard Worker         *outFlags = 0;
1252*38e8c45fSAndroid Build Coastguard Worker         *outMetaState = metaState;
1253*38e8c45fSAndroid Build Coastguard Worker     }
1254*38e8c45fSAndroid Build Coastguard Worker 
1255*38e8c45fSAndroid Build Coastguard Worker     return status;
1256*38e8c45fSAndroid Build Coastguard Worker }
1257*38e8c45fSAndroid Build Coastguard Worker 
mapAxis(int32_t deviceId,int32_t scanCode,AxisInfo * outAxisInfo) const1258*38e8c45fSAndroid Build Coastguard Worker status_t EventHub::mapAxis(int32_t deviceId, int32_t scanCode, AxisInfo* outAxisInfo) const {
1259*38e8c45fSAndroid Build Coastguard Worker     std::scoped_lock _l(mLock);
1260*38e8c45fSAndroid Build Coastguard Worker     Device* device = getDeviceLocked(deviceId);
1261*38e8c45fSAndroid Build Coastguard Worker 
1262*38e8c45fSAndroid Build Coastguard Worker     if (device == nullptr || !device->keyMap.haveKeyLayout()) {
1263*38e8c45fSAndroid Build Coastguard Worker         return NAME_NOT_FOUND;
1264*38e8c45fSAndroid Build Coastguard Worker     }
1265*38e8c45fSAndroid Build Coastguard Worker     std::optional<AxisInfo> info = device->keyMap.keyLayoutMap->mapAxis(scanCode);
1266*38e8c45fSAndroid Build Coastguard Worker     if (!info.has_value()) {
1267*38e8c45fSAndroid Build Coastguard Worker         return NAME_NOT_FOUND;
1268*38e8c45fSAndroid Build Coastguard Worker     }
1269*38e8c45fSAndroid Build Coastguard Worker     *outAxisInfo = *info;
1270*38e8c45fSAndroid Build Coastguard Worker     return NO_ERROR;
1271*38e8c45fSAndroid Build Coastguard Worker }
1272*38e8c45fSAndroid Build Coastguard Worker 
mapSensor(int32_t deviceId,int32_t absCode) const1273*38e8c45fSAndroid Build Coastguard Worker base::Result<std::pair<InputDeviceSensorType, int32_t>> EventHub::mapSensor(int32_t deviceId,
1274*38e8c45fSAndroid Build Coastguard Worker                                                                             int32_t absCode) const {
1275*38e8c45fSAndroid Build Coastguard Worker     std::scoped_lock _l(mLock);
1276*38e8c45fSAndroid Build Coastguard Worker     Device* device = getDeviceLocked(deviceId);
1277*38e8c45fSAndroid Build Coastguard Worker 
1278*38e8c45fSAndroid Build Coastguard Worker     if (device != nullptr && device->keyMap.haveKeyLayout()) {
1279*38e8c45fSAndroid Build Coastguard Worker         return device->keyMap.keyLayoutMap->mapSensor(absCode);
1280*38e8c45fSAndroid Build Coastguard Worker     }
1281*38e8c45fSAndroid Build Coastguard Worker     return Errorf("Device not found or device has no key layout.");
1282*38e8c45fSAndroid Build Coastguard Worker }
1283*38e8c45fSAndroid Build Coastguard Worker 
1284*38e8c45fSAndroid Build Coastguard Worker // Gets the battery info map from battery ID to RawBatteryInfo of the miscellaneous device
1285*38e8c45fSAndroid Build Coastguard Worker // associated with the device ID. Returns an empty map if no miscellaneous device found.
getBatteryInfoLocked(int32_t deviceId) const1286*38e8c45fSAndroid Build Coastguard Worker const std::unordered_map<int32_t, RawBatteryInfo>& EventHub::getBatteryInfoLocked(
1287*38e8c45fSAndroid Build Coastguard Worker         int32_t deviceId) const {
1288*38e8c45fSAndroid Build Coastguard Worker     static const std::unordered_map<int32_t, RawBatteryInfo> EMPTY_BATTERY_INFO = {};
1289*38e8c45fSAndroid Build Coastguard Worker     Device* device = getDeviceLocked(deviceId);
1290*38e8c45fSAndroid Build Coastguard Worker     if (device == nullptr || !device->associatedDevice) {
1291*38e8c45fSAndroid Build Coastguard Worker         return EMPTY_BATTERY_INFO;
1292*38e8c45fSAndroid Build Coastguard Worker     }
1293*38e8c45fSAndroid Build Coastguard Worker     return device->associatedDevice->batteryInfos;
1294*38e8c45fSAndroid Build Coastguard Worker }
1295*38e8c45fSAndroid Build Coastguard Worker 
getRawBatteryIds(int32_t deviceId) const1296*38e8c45fSAndroid Build Coastguard Worker std::vector<int32_t> EventHub::getRawBatteryIds(int32_t deviceId) const {
1297*38e8c45fSAndroid Build Coastguard Worker     std::scoped_lock _l(mLock);
1298*38e8c45fSAndroid Build Coastguard Worker     std::vector<int32_t> batteryIds;
1299*38e8c45fSAndroid Build Coastguard Worker 
1300*38e8c45fSAndroid Build Coastguard Worker     for (const auto& [id, info] : getBatteryInfoLocked(deviceId)) {
1301*38e8c45fSAndroid Build Coastguard Worker         batteryIds.push_back(id);
1302*38e8c45fSAndroid Build Coastguard Worker     }
1303*38e8c45fSAndroid Build Coastguard Worker 
1304*38e8c45fSAndroid Build Coastguard Worker     return batteryIds;
1305*38e8c45fSAndroid Build Coastguard Worker }
1306*38e8c45fSAndroid Build Coastguard Worker 
getRawBatteryInfo(int32_t deviceId,int32_t batteryId) const1307*38e8c45fSAndroid Build Coastguard Worker std::optional<RawBatteryInfo> EventHub::getRawBatteryInfo(int32_t deviceId,
1308*38e8c45fSAndroid Build Coastguard Worker                                                           int32_t batteryId) const {
1309*38e8c45fSAndroid Build Coastguard Worker     std::scoped_lock _l(mLock);
1310*38e8c45fSAndroid Build Coastguard Worker 
1311*38e8c45fSAndroid Build Coastguard Worker     const auto infos = getBatteryInfoLocked(deviceId);
1312*38e8c45fSAndroid Build Coastguard Worker 
1313*38e8c45fSAndroid Build Coastguard Worker     auto it = infos.find(batteryId);
1314*38e8c45fSAndroid Build Coastguard Worker     if (it != infos.end()) {
1315*38e8c45fSAndroid Build Coastguard Worker         return it->second;
1316*38e8c45fSAndroid Build Coastguard Worker     }
1317*38e8c45fSAndroid Build Coastguard Worker 
1318*38e8c45fSAndroid Build Coastguard Worker     return std::nullopt;
1319*38e8c45fSAndroid Build Coastguard Worker }
1320*38e8c45fSAndroid Build Coastguard Worker 
1321*38e8c45fSAndroid Build Coastguard Worker // Gets the light info map from light ID to RawLightInfo of the miscellaneous device associated
1322*38e8c45fSAndroid Build Coastguard Worker // with the device ID. Returns an empty map if no miscellaneous device found.
getLightInfoLocked(int32_t deviceId) const1323*38e8c45fSAndroid Build Coastguard Worker const std::unordered_map<int32_t, RawLightInfo>& EventHub::getLightInfoLocked(
1324*38e8c45fSAndroid Build Coastguard Worker         int32_t deviceId) const {
1325*38e8c45fSAndroid Build Coastguard Worker     static const std::unordered_map<int32_t, RawLightInfo> EMPTY_LIGHT_INFO = {};
1326*38e8c45fSAndroid Build Coastguard Worker     Device* device = getDeviceLocked(deviceId);
1327*38e8c45fSAndroid Build Coastguard Worker     if (device == nullptr || !device->associatedDevice) {
1328*38e8c45fSAndroid Build Coastguard Worker         return EMPTY_LIGHT_INFO;
1329*38e8c45fSAndroid Build Coastguard Worker     }
1330*38e8c45fSAndroid Build Coastguard Worker     return device->associatedDevice->lightInfos;
1331*38e8c45fSAndroid Build Coastguard Worker }
1332*38e8c45fSAndroid Build Coastguard Worker 
getRawLightIds(int32_t deviceId) const1333*38e8c45fSAndroid Build Coastguard Worker std::vector<int32_t> EventHub::getRawLightIds(int32_t deviceId) const {
1334*38e8c45fSAndroid Build Coastguard Worker     std::scoped_lock _l(mLock);
1335*38e8c45fSAndroid Build Coastguard Worker     std::vector<int32_t> lightIds;
1336*38e8c45fSAndroid Build Coastguard Worker 
1337*38e8c45fSAndroid Build Coastguard Worker     for (const auto& [id, info] : getLightInfoLocked(deviceId)) {
1338*38e8c45fSAndroid Build Coastguard Worker         lightIds.push_back(id);
1339*38e8c45fSAndroid Build Coastguard Worker     }
1340*38e8c45fSAndroid Build Coastguard Worker 
1341*38e8c45fSAndroid Build Coastguard Worker     return lightIds;
1342*38e8c45fSAndroid Build Coastguard Worker }
1343*38e8c45fSAndroid Build Coastguard Worker 
getRawLightInfo(int32_t deviceId,int32_t lightId) const1344*38e8c45fSAndroid Build Coastguard Worker std::optional<RawLightInfo> EventHub::getRawLightInfo(int32_t deviceId, int32_t lightId) const {
1345*38e8c45fSAndroid Build Coastguard Worker     std::scoped_lock _l(mLock);
1346*38e8c45fSAndroid Build Coastguard Worker 
1347*38e8c45fSAndroid Build Coastguard Worker     const auto infos = getLightInfoLocked(deviceId);
1348*38e8c45fSAndroid Build Coastguard Worker 
1349*38e8c45fSAndroid Build Coastguard Worker     auto it = infos.find(lightId);
1350*38e8c45fSAndroid Build Coastguard Worker     if (it != infos.end()) {
1351*38e8c45fSAndroid Build Coastguard Worker         return it->second;
1352*38e8c45fSAndroid Build Coastguard Worker     }
1353*38e8c45fSAndroid Build Coastguard Worker 
1354*38e8c45fSAndroid Build Coastguard Worker     return std::nullopt;
1355*38e8c45fSAndroid Build Coastguard Worker }
1356*38e8c45fSAndroid Build Coastguard Worker 
getLightBrightness(int32_t deviceId,int32_t lightId) const1357*38e8c45fSAndroid Build Coastguard Worker std::optional<int32_t> EventHub::getLightBrightness(int32_t deviceId, int32_t lightId) const {
1358*38e8c45fSAndroid Build Coastguard Worker     std::scoped_lock _l(mLock);
1359*38e8c45fSAndroid Build Coastguard Worker 
1360*38e8c45fSAndroid Build Coastguard Worker     const auto infos = getLightInfoLocked(deviceId);
1361*38e8c45fSAndroid Build Coastguard Worker     auto it = infos.find(lightId);
1362*38e8c45fSAndroid Build Coastguard Worker     if (it == infos.end()) {
1363*38e8c45fSAndroid Build Coastguard Worker         return std::nullopt;
1364*38e8c45fSAndroid Build Coastguard Worker     }
1365*38e8c45fSAndroid Build Coastguard Worker     std::string buffer;
1366*38e8c45fSAndroid Build Coastguard Worker     if (!base::ReadFileToString(it->second.path / LIGHT_NODES.at(InputLightClass::BRIGHTNESS),
1367*38e8c45fSAndroid Build Coastguard Worker                                 &buffer)) {
1368*38e8c45fSAndroid Build Coastguard Worker         return std::nullopt;
1369*38e8c45fSAndroid Build Coastguard Worker     }
1370*38e8c45fSAndroid Build Coastguard Worker     return std::stoi(buffer);
1371*38e8c45fSAndroid Build Coastguard Worker }
1372*38e8c45fSAndroid Build Coastguard Worker 
getLightIntensities(int32_t deviceId,int32_t lightId) const1373*38e8c45fSAndroid Build Coastguard Worker std::optional<std::unordered_map<LightColor, int32_t>> EventHub::getLightIntensities(
1374*38e8c45fSAndroid Build Coastguard Worker         int32_t deviceId, int32_t lightId) const {
1375*38e8c45fSAndroid Build Coastguard Worker     std::scoped_lock _l(mLock);
1376*38e8c45fSAndroid Build Coastguard Worker 
1377*38e8c45fSAndroid Build Coastguard Worker     const auto infos = getLightInfoLocked(deviceId);
1378*38e8c45fSAndroid Build Coastguard Worker     auto lightIt = infos.find(lightId);
1379*38e8c45fSAndroid Build Coastguard Worker     if (lightIt == infos.end()) {
1380*38e8c45fSAndroid Build Coastguard Worker         return std::nullopt;
1381*38e8c45fSAndroid Build Coastguard Worker     }
1382*38e8c45fSAndroid Build Coastguard Worker 
1383*38e8c45fSAndroid Build Coastguard Worker     auto ret =
1384*38e8c45fSAndroid Build Coastguard Worker             getColorIndexArray(lightIt->second.path / LIGHT_NODES.at(InputLightClass::MULTI_INDEX));
1385*38e8c45fSAndroid Build Coastguard Worker 
1386*38e8c45fSAndroid Build Coastguard Worker     if (!ret.has_value()) {
1387*38e8c45fSAndroid Build Coastguard Worker         return std::nullopt;
1388*38e8c45fSAndroid Build Coastguard Worker     }
1389*38e8c45fSAndroid Build Coastguard Worker     std::array<LightColor, COLOR_NUM> colors = ret.value();
1390*38e8c45fSAndroid Build Coastguard Worker 
1391*38e8c45fSAndroid Build Coastguard Worker     std::string intensityStr;
1392*38e8c45fSAndroid Build Coastguard Worker     if (!base::ReadFileToString(lightIt->second.path /
1393*38e8c45fSAndroid Build Coastguard Worker                                         LIGHT_NODES.at(InputLightClass::MULTI_INTENSITY),
1394*38e8c45fSAndroid Build Coastguard Worker                                 &intensityStr)) {
1395*38e8c45fSAndroid Build Coastguard Worker         return std::nullopt;
1396*38e8c45fSAndroid Build Coastguard Worker     }
1397*38e8c45fSAndroid Build Coastguard Worker 
1398*38e8c45fSAndroid Build Coastguard Worker     // Intensity node outputs 3 color values
1399*38e8c45fSAndroid Build Coastguard Worker     std::regex intensityPattern("([0-9]+)\\s([0-9]+)\\s([0-9]+)[\\n]");
1400*38e8c45fSAndroid Build Coastguard Worker     std::smatch results;
1401*38e8c45fSAndroid Build Coastguard Worker 
1402*38e8c45fSAndroid Build Coastguard Worker     if (!std::regex_match(intensityStr, results, intensityPattern)) {
1403*38e8c45fSAndroid Build Coastguard Worker         return std::nullopt;
1404*38e8c45fSAndroid Build Coastguard Worker     }
1405*38e8c45fSAndroid Build Coastguard Worker     std::unordered_map<LightColor, int32_t> intensities;
1406*38e8c45fSAndroid Build Coastguard Worker     for (size_t i = 1; i < results.size(); i++) {
1407*38e8c45fSAndroid Build Coastguard Worker         int value = std::stoi(results[i].str());
1408*38e8c45fSAndroid Build Coastguard Worker         intensities.emplace(colors[i - 1], value);
1409*38e8c45fSAndroid Build Coastguard Worker     }
1410*38e8c45fSAndroid Build Coastguard Worker     return intensities;
1411*38e8c45fSAndroid Build Coastguard Worker }
1412*38e8c45fSAndroid Build Coastguard Worker 
setLightBrightness(int32_t deviceId,int32_t lightId,int32_t brightness)1413*38e8c45fSAndroid Build Coastguard Worker void EventHub::setLightBrightness(int32_t deviceId, int32_t lightId, int32_t brightness) {
1414*38e8c45fSAndroid Build Coastguard Worker     std::scoped_lock _l(mLock);
1415*38e8c45fSAndroid Build Coastguard Worker 
1416*38e8c45fSAndroid Build Coastguard Worker     const auto infos = getLightInfoLocked(deviceId);
1417*38e8c45fSAndroid Build Coastguard Worker     auto lightIt = infos.find(lightId);
1418*38e8c45fSAndroid Build Coastguard Worker     if (lightIt == infos.end()) {
1419*38e8c45fSAndroid Build Coastguard Worker         ALOGE("%s lightId %d not found ", __func__, lightId);
1420*38e8c45fSAndroid Build Coastguard Worker         return;
1421*38e8c45fSAndroid Build Coastguard Worker     }
1422*38e8c45fSAndroid Build Coastguard Worker 
1423*38e8c45fSAndroid Build Coastguard Worker     if (!base::WriteStringToFile(std::to_string(brightness),
1424*38e8c45fSAndroid Build Coastguard Worker                                  lightIt->second.path /
1425*38e8c45fSAndroid Build Coastguard Worker                                          LIGHT_NODES.at(InputLightClass::BRIGHTNESS))) {
1426*38e8c45fSAndroid Build Coastguard Worker         ALOGE("Can not write to file, error: %s", strerror(errno));
1427*38e8c45fSAndroid Build Coastguard Worker     }
1428*38e8c45fSAndroid Build Coastguard Worker }
1429*38e8c45fSAndroid Build Coastguard Worker 
setLightIntensities(int32_t deviceId,int32_t lightId,std::unordered_map<LightColor,int32_t> intensities)1430*38e8c45fSAndroid Build Coastguard Worker void EventHub::setLightIntensities(int32_t deviceId, int32_t lightId,
1431*38e8c45fSAndroid Build Coastguard Worker                                    std::unordered_map<LightColor, int32_t> intensities) {
1432*38e8c45fSAndroid Build Coastguard Worker     std::scoped_lock _l(mLock);
1433*38e8c45fSAndroid Build Coastguard Worker 
1434*38e8c45fSAndroid Build Coastguard Worker     const auto infos = getLightInfoLocked(deviceId);
1435*38e8c45fSAndroid Build Coastguard Worker     auto lightIt = infos.find(lightId);
1436*38e8c45fSAndroid Build Coastguard Worker     if (lightIt == infos.end()) {
1437*38e8c45fSAndroid Build Coastguard Worker         ALOGE("Light Id %d does not exist.", lightId);
1438*38e8c45fSAndroid Build Coastguard Worker         return;
1439*38e8c45fSAndroid Build Coastguard Worker     }
1440*38e8c45fSAndroid Build Coastguard Worker 
1441*38e8c45fSAndroid Build Coastguard Worker     auto ret =
1442*38e8c45fSAndroid Build Coastguard Worker             getColorIndexArray(lightIt->second.path / LIGHT_NODES.at(InputLightClass::MULTI_INDEX));
1443*38e8c45fSAndroid Build Coastguard Worker 
1444*38e8c45fSAndroid Build Coastguard Worker     if (!ret.has_value()) {
1445*38e8c45fSAndroid Build Coastguard Worker         return;
1446*38e8c45fSAndroid Build Coastguard Worker     }
1447*38e8c45fSAndroid Build Coastguard Worker     std::array<LightColor, COLOR_NUM> colors = ret.value();
1448*38e8c45fSAndroid Build Coastguard Worker 
1449*38e8c45fSAndroid Build Coastguard Worker     std::string rgbStr;
1450*38e8c45fSAndroid Build Coastguard Worker     for (size_t i = 0; i < COLOR_NUM; i++) {
1451*38e8c45fSAndroid Build Coastguard Worker         auto it = intensities.find(colors[i]);
1452*38e8c45fSAndroid Build Coastguard Worker         if (it != intensities.end()) {
1453*38e8c45fSAndroid Build Coastguard Worker             rgbStr += std::to_string(it->second);
1454*38e8c45fSAndroid Build Coastguard Worker             // Insert space between colors
1455*38e8c45fSAndroid Build Coastguard Worker             if (i < COLOR_NUM - 1) {
1456*38e8c45fSAndroid Build Coastguard Worker                 rgbStr += " ";
1457*38e8c45fSAndroid Build Coastguard Worker             }
1458*38e8c45fSAndroid Build Coastguard Worker         }
1459*38e8c45fSAndroid Build Coastguard Worker     }
1460*38e8c45fSAndroid Build Coastguard Worker     // Append new line
1461*38e8c45fSAndroid Build Coastguard Worker     rgbStr += "\n";
1462*38e8c45fSAndroid Build Coastguard Worker 
1463*38e8c45fSAndroid Build Coastguard Worker     if (!base::WriteStringToFile(rgbStr,
1464*38e8c45fSAndroid Build Coastguard Worker                                  lightIt->second.path /
1465*38e8c45fSAndroid Build Coastguard Worker                                          LIGHT_NODES.at(InputLightClass::MULTI_INTENSITY))) {
1466*38e8c45fSAndroid Build Coastguard Worker         ALOGE("Can not write to file, error: %s", strerror(errno));
1467*38e8c45fSAndroid Build Coastguard Worker     }
1468*38e8c45fSAndroid Build Coastguard Worker }
1469*38e8c45fSAndroid Build Coastguard Worker 
getRawLayoutInfo(int32_t deviceId) const1470*38e8c45fSAndroid Build Coastguard Worker std::optional<RawLayoutInfo> EventHub::getRawLayoutInfo(int32_t deviceId) const {
1471*38e8c45fSAndroid Build Coastguard Worker     std::scoped_lock _l(mLock);
1472*38e8c45fSAndroid Build Coastguard Worker     Device* device = getDeviceLocked(deviceId);
1473*38e8c45fSAndroid Build Coastguard Worker     if (device == nullptr || !device->associatedDevice) {
1474*38e8c45fSAndroid Build Coastguard Worker         return std::nullopt;
1475*38e8c45fSAndroid Build Coastguard Worker     }
1476*38e8c45fSAndroid Build Coastguard Worker     return device->associatedDevice->layoutInfo;
1477*38e8c45fSAndroid Build Coastguard Worker }
1478*38e8c45fSAndroid Build Coastguard Worker 
setExcludedDevices(const std::vector<std::string> & devices)1479*38e8c45fSAndroid Build Coastguard Worker void EventHub::setExcludedDevices(const std::vector<std::string>& devices) {
1480*38e8c45fSAndroid Build Coastguard Worker     std::scoped_lock _l(mLock);
1481*38e8c45fSAndroid Build Coastguard Worker 
1482*38e8c45fSAndroid Build Coastguard Worker     mExcludedDevices = devices;
1483*38e8c45fSAndroid Build Coastguard Worker }
1484*38e8c45fSAndroid Build Coastguard Worker 
hasScanCode(int32_t deviceId,int32_t scanCode) const1485*38e8c45fSAndroid Build Coastguard Worker bool EventHub::hasScanCode(int32_t deviceId, int32_t scanCode) const {
1486*38e8c45fSAndroid Build Coastguard Worker     std::scoped_lock _l(mLock);
1487*38e8c45fSAndroid Build Coastguard Worker     Device* device = getDeviceLocked(deviceId);
1488*38e8c45fSAndroid Build Coastguard Worker     if (device != nullptr && scanCode >= 0 && scanCode <= KEY_MAX) {
1489*38e8c45fSAndroid Build Coastguard Worker         return device->keyBitmask.test(scanCode);
1490*38e8c45fSAndroid Build Coastguard Worker     }
1491*38e8c45fSAndroid Build Coastguard Worker     return false;
1492*38e8c45fSAndroid Build Coastguard Worker }
1493*38e8c45fSAndroid Build Coastguard Worker 
hasKeyCode(int32_t deviceId,int32_t keyCode) const1494*38e8c45fSAndroid Build Coastguard Worker bool EventHub::hasKeyCode(int32_t deviceId, int32_t keyCode) const {
1495*38e8c45fSAndroid Build Coastguard Worker     std::scoped_lock _l(mLock);
1496*38e8c45fSAndroid Build Coastguard Worker     Device* device = getDeviceLocked(deviceId);
1497*38e8c45fSAndroid Build Coastguard Worker     if (device != nullptr) {
1498*38e8c45fSAndroid Build Coastguard Worker         return device->hasKeycodeLocked(keyCode);
1499*38e8c45fSAndroid Build Coastguard Worker     }
1500*38e8c45fSAndroid Build Coastguard Worker     return false;
1501*38e8c45fSAndroid Build Coastguard Worker }
1502*38e8c45fSAndroid Build Coastguard Worker 
hasLed(int32_t deviceId,int32_t led) const1503*38e8c45fSAndroid Build Coastguard Worker bool EventHub::hasLed(int32_t deviceId, int32_t led) const {
1504*38e8c45fSAndroid Build Coastguard Worker     std::scoped_lock _l(mLock);
1505*38e8c45fSAndroid Build Coastguard Worker     Device* device = getDeviceLocked(deviceId);
1506*38e8c45fSAndroid Build Coastguard Worker     int32_t sc;
1507*38e8c45fSAndroid Build Coastguard Worker     if (device != nullptr && device->mapLed(led, &sc) == NO_ERROR) {
1508*38e8c45fSAndroid Build Coastguard Worker         return device->ledBitmask.test(sc);
1509*38e8c45fSAndroid Build Coastguard Worker     }
1510*38e8c45fSAndroid Build Coastguard Worker     return false;
1511*38e8c45fSAndroid Build Coastguard Worker }
1512*38e8c45fSAndroid Build Coastguard Worker 
setLedState(int32_t deviceId,int32_t led,bool on)1513*38e8c45fSAndroid Build Coastguard Worker void EventHub::setLedState(int32_t deviceId, int32_t led, bool on) {
1514*38e8c45fSAndroid Build Coastguard Worker     std::scoped_lock _l(mLock);
1515*38e8c45fSAndroid Build Coastguard Worker     Device* device = getDeviceLocked(deviceId);
1516*38e8c45fSAndroid Build Coastguard Worker     if (device != nullptr && device->hasValidFd()) {
1517*38e8c45fSAndroid Build Coastguard Worker         device->setLedStateLocked(led, on);
1518*38e8c45fSAndroid Build Coastguard Worker     }
1519*38e8c45fSAndroid Build Coastguard Worker }
1520*38e8c45fSAndroid Build Coastguard Worker 
getVirtualKeyDefinitions(int32_t deviceId,std::vector<VirtualKeyDefinition> & outVirtualKeys) const1521*38e8c45fSAndroid Build Coastguard Worker void EventHub::getVirtualKeyDefinitions(int32_t deviceId,
1522*38e8c45fSAndroid Build Coastguard Worker                                         std::vector<VirtualKeyDefinition>& outVirtualKeys) const {
1523*38e8c45fSAndroid Build Coastguard Worker     outVirtualKeys.clear();
1524*38e8c45fSAndroid Build Coastguard Worker 
1525*38e8c45fSAndroid Build Coastguard Worker     std::scoped_lock _l(mLock);
1526*38e8c45fSAndroid Build Coastguard Worker     Device* device = getDeviceLocked(deviceId);
1527*38e8c45fSAndroid Build Coastguard Worker     if (device != nullptr && device->virtualKeyMap) {
1528*38e8c45fSAndroid Build Coastguard Worker         const std::vector<VirtualKeyDefinition> virtualKeys =
1529*38e8c45fSAndroid Build Coastguard Worker                 device->virtualKeyMap->getVirtualKeys();
1530*38e8c45fSAndroid Build Coastguard Worker         outVirtualKeys.insert(outVirtualKeys.end(), virtualKeys.begin(), virtualKeys.end());
1531*38e8c45fSAndroid Build Coastguard Worker     }
1532*38e8c45fSAndroid Build Coastguard Worker }
1533*38e8c45fSAndroid Build Coastguard Worker 
getKeyCharacterMap(int32_t deviceId) const1534*38e8c45fSAndroid Build Coastguard Worker const std::shared_ptr<KeyCharacterMap> EventHub::getKeyCharacterMap(int32_t deviceId) const {
1535*38e8c45fSAndroid Build Coastguard Worker     std::scoped_lock _l(mLock);
1536*38e8c45fSAndroid Build Coastguard Worker     Device* device = getDeviceLocked(deviceId);
1537*38e8c45fSAndroid Build Coastguard Worker     if (device != nullptr) {
1538*38e8c45fSAndroid Build Coastguard Worker         return device->getKeyCharacterMap();
1539*38e8c45fSAndroid Build Coastguard Worker     }
1540*38e8c45fSAndroid Build Coastguard Worker     return nullptr;
1541*38e8c45fSAndroid Build Coastguard Worker }
1542*38e8c45fSAndroid Build Coastguard Worker 
1543*38e8c45fSAndroid Build Coastguard Worker // If provided map is null, it will reset key character map to default KCM.
setKeyboardLayoutOverlay(int32_t deviceId,std::shared_ptr<KeyCharacterMap> map)1544*38e8c45fSAndroid Build Coastguard Worker bool EventHub::setKeyboardLayoutOverlay(int32_t deviceId, std::shared_ptr<KeyCharacterMap> map) {
1545*38e8c45fSAndroid Build Coastguard Worker     std::scoped_lock _l(mLock);
1546*38e8c45fSAndroid Build Coastguard Worker     Device* device = getDeviceLocked(deviceId);
1547*38e8c45fSAndroid Build Coastguard Worker     if (device == nullptr || device->keyMap.keyCharacterMap == nullptr) {
1548*38e8c45fSAndroid Build Coastguard Worker         return false;
1549*38e8c45fSAndroid Build Coastguard Worker     }
1550*38e8c45fSAndroid Build Coastguard Worker     if (map == nullptr) {
1551*38e8c45fSAndroid Build Coastguard Worker         device->keyMap.keyCharacterMap->clearLayoutOverlay();
1552*38e8c45fSAndroid Build Coastguard Worker         return true;
1553*38e8c45fSAndroid Build Coastguard Worker     }
1554*38e8c45fSAndroid Build Coastguard Worker     device->keyMap.keyCharacterMap->combine(*map);
1555*38e8c45fSAndroid Build Coastguard Worker     return true;
1556*38e8c45fSAndroid Build Coastguard Worker }
1557*38e8c45fSAndroid Build Coastguard Worker 
generateDescriptor(InputDeviceIdentifier & identifier)1558*38e8c45fSAndroid Build Coastguard Worker static std::string generateDescriptor(InputDeviceIdentifier& identifier) {
1559*38e8c45fSAndroid Build Coastguard Worker     std::string rawDescriptor;
1560*38e8c45fSAndroid Build Coastguard Worker     rawDescriptor += StringPrintf(":%04x:%04x:", identifier.vendor, identifier.product);
1561*38e8c45fSAndroid Build Coastguard Worker     // TODO add handling for USB devices to not uniqueify kbs that show up twice
1562*38e8c45fSAndroid Build Coastguard Worker     if (!identifier.uniqueId.empty()) {
1563*38e8c45fSAndroid Build Coastguard Worker         rawDescriptor += "uniqueId:";
1564*38e8c45fSAndroid Build Coastguard Worker         rawDescriptor += identifier.uniqueId;
1565*38e8c45fSAndroid Build Coastguard Worker     }
1566*38e8c45fSAndroid Build Coastguard Worker     if (identifier.nonce != 0) {
1567*38e8c45fSAndroid Build Coastguard Worker         rawDescriptor += StringPrintf("nonce:%04x", identifier.nonce);
1568*38e8c45fSAndroid Build Coastguard Worker     }
1569*38e8c45fSAndroid Build Coastguard Worker 
1570*38e8c45fSAndroid Build Coastguard Worker     if (identifier.vendor == 0 && identifier.product == 0) {
1571*38e8c45fSAndroid Build Coastguard Worker         // If we don't know the vendor and product id, then the device is probably
1572*38e8c45fSAndroid Build Coastguard Worker         // built-in so we need to rely on other information to uniquely identify
1573*38e8c45fSAndroid Build Coastguard Worker         // the input device.  Usually we try to avoid relying on the device name or
1574*38e8c45fSAndroid Build Coastguard Worker         // location but for built-in input device, they are unlikely to ever change.
1575*38e8c45fSAndroid Build Coastguard Worker         if (!identifier.name.empty()) {
1576*38e8c45fSAndroid Build Coastguard Worker             rawDescriptor += "name:";
1577*38e8c45fSAndroid Build Coastguard Worker             rawDescriptor += identifier.name;
1578*38e8c45fSAndroid Build Coastguard Worker         } else if (!identifier.location.empty()) {
1579*38e8c45fSAndroid Build Coastguard Worker             rawDescriptor += "location:";
1580*38e8c45fSAndroid Build Coastguard Worker             rawDescriptor += identifier.location;
1581*38e8c45fSAndroid Build Coastguard Worker         }
1582*38e8c45fSAndroid Build Coastguard Worker     }
1583*38e8c45fSAndroid Build Coastguard Worker     identifier.descriptor = sha1(rawDescriptor);
1584*38e8c45fSAndroid Build Coastguard Worker     return rawDescriptor;
1585*38e8c45fSAndroid Build Coastguard Worker }
1586*38e8c45fSAndroid Build Coastguard Worker 
assignDescriptorLocked(InputDeviceIdentifier & identifier)1587*38e8c45fSAndroid Build Coastguard Worker void EventHub::assignDescriptorLocked(InputDeviceIdentifier& identifier) {
1588*38e8c45fSAndroid Build Coastguard Worker     // Compute a device descriptor that uniquely identifies the device.
1589*38e8c45fSAndroid Build Coastguard Worker     // The descriptor is assumed to be a stable identifier.  Its value should not
1590*38e8c45fSAndroid Build Coastguard Worker     // change between reboots, reconnections, firmware updates or new releases
1591*38e8c45fSAndroid Build Coastguard Worker     // of Android. In practice we sometimes get devices that cannot be uniquely
1592*38e8c45fSAndroid Build Coastguard Worker     // identified. In this case we enforce uniqueness between connected devices.
1593*38e8c45fSAndroid Build Coastguard Worker     // Ideally, we also want the descriptor to be short and relatively opaque.
1594*38e8c45fSAndroid Build Coastguard Worker     // Note that we explicitly do not use the path or location for external devices
1595*38e8c45fSAndroid Build Coastguard Worker     // as their path or location will change as they are plugged/unplugged or moved
1596*38e8c45fSAndroid Build Coastguard Worker     // to different ports. We do fallback to using name and location in the case of
1597*38e8c45fSAndroid Build Coastguard Worker     // internal devices which are detected by the vendor and product being 0 in
1598*38e8c45fSAndroid Build Coastguard Worker     // generateDescriptor. If two identical descriptors are detected we will fallback
1599*38e8c45fSAndroid Build Coastguard Worker     // to using a 'nonce' and incrementing it until the new descriptor no longer has
1600*38e8c45fSAndroid Build Coastguard Worker     // a match with any existing descriptors.
1601*38e8c45fSAndroid Build Coastguard Worker 
1602*38e8c45fSAndroid Build Coastguard Worker     identifier.nonce = 0;
1603*38e8c45fSAndroid Build Coastguard Worker     std::string rawDescriptor = generateDescriptor(identifier);
1604*38e8c45fSAndroid Build Coastguard Worker     // Enforce that the generated descriptor is unique.
1605*38e8c45fSAndroid Build Coastguard Worker     while (hasDeviceWithDescriptorLocked(identifier.descriptor)) {
1606*38e8c45fSAndroid Build Coastguard Worker         identifier.nonce++;
1607*38e8c45fSAndroid Build Coastguard Worker         rawDescriptor = generateDescriptor(identifier);
1608*38e8c45fSAndroid Build Coastguard Worker     }
1609*38e8c45fSAndroid Build Coastguard Worker     ALOGV("Created descriptor: raw=%s, cooked=%s", rawDescriptor.c_str(),
1610*38e8c45fSAndroid Build Coastguard Worker           identifier.descriptor.c_str());
1611*38e8c45fSAndroid Build Coastguard Worker }
1612*38e8c45fSAndroid Build Coastguard Worker 
obtainAssociatedDeviceLocked(const std::filesystem::path & devicePath) const1613*38e8c45fSAndroid Build Coastguard Worker std::shared_ptr<const EventHub::AssociatedDevice> EventHub::obtainAssociatedDeviceLocked(
1614*38e8c45fSAndroid Build Coastguard Worker         const std::filesystem::path& devicePath) const {
1615*38e8c45fSAndroid Build Coastguard Worker     const std::optional<std::filesystem::path> sysfsRootPathOpt =
1616*38e8c45fSAndroid Build Coastguard Worker             getSysfsRootPath(devicePath.c_str());
1617*38e8c45fSAndroid Build Coastguard Worker     if (!sysfsRootPathOpt) {
1618*38e8c45fSAndroid Build Coastguard Worker         return nullptr;
1619*38e8c45fSAndroid Build Coastguard Worker     }
1620*38e8c45fSAndroid Build Coastguard Worker 
1621*38e8c45fSAndroid Build Coastguard Worker     const auto& path = *sysfsRootPathOpt;
1622*38e8c45fSAndroid Build Coastguard Worker 
1623*38e8c45fSAndroid Build Coastguard Worker     std::shared_ptr<const AssociatedDevice> associatedDevice = std::make_shared<AssociatedDevice>(
1624*38e8c45fSAndroid Build Coastguard Worker             AssociatedDevice{.sysfsRootPath = path,
1625*38e8c45fSAndroid Build Coastguard Worker                              .batteryInfos = readBatteryConfiguration(path),
1626*38e8c45fSAndroid Build Coastguard Worker                              .lightInfos = readLightsConfiguration(path),
1627*38e8c45fSAndroid Build Coastguard Worker                              .layoutInfo = readLayoutConfiguration(path)});
1628*38e8c45fSAndroid Build Coastguard Worker 
1629*38e8c45fSAndroid Build Coastguard Worker     bool associatedDeviceChanged = false;
1630*38e8c45fSAndroid Build Coastguard Worker     for (const auto& [id, dev] : mDevices) {
1631*38e8c45fSAndroid Build Coastguard Worker         if (dev->associatedDevice && dev->associatedDevice->sysfsRootPath == path) {
1632*38e8c45fSAndroid Build Coastguard Worker             if (*associatedDevice != *dev->associatedDevice) {
1633*38e8c45fSAndroid Build Coastguard Worker                 associatedDeviceChanged = true;
1634*38e8c45fSAndroid Build Coastguard Worker                 dev->associatedDevice = associatedDevice;
1635*38e8c45fSAndroid Build Coastguard Worker             }
1636*38e8c45fSAndroid Build Coastguard Worker             associatedDevice = dev->associatedDevice;
1637*38e8c45fSAndroid Build Coastguard Worker         }
1638*38e8c45fSAndroid Build Coastguard Worker     }
1639*38e8c45fSAndroid Build Coastguard Worker     ALOGI_IF(associatedDeviceChanged,
1640*38e8c45fSAndroid Build Coastguard Worker              "The AssociatedDevice changed for path '%s'. Using new AssociatedDevice: %s",
1641*38e8c45fSAndroid Build Coastguard Worker              path.c_str(), associatedDevice->dump().c_str());
1642*38e8c45fSAndroid Build Coastguard Worker 
1643*38e8c45fSAndroid Build Coastguard Worker     return associatedDevice;
1644*38e8c45fSAndroid Build Coastguard Worker }
1645*38e8c45fSAndroid Build Coastguard Worker 
isChanged() const1646*38e8c45fSAndroid Build Coastguard Worker bool EventHub::AssociatedDevice::isChanged() const {
1647*38e8c45fSAndroid Build Coastguard Worker     std::unordered_map<int32_t, RawBatteryInfo> newBatteryInfos =
1648*38e8c45fSAndroid Build Coastguard Worker             readBatteryConfiguration(sysfsRootPath);
1649*38e8c45fSAndroid Build Coastguard Worker     std::unordered_map<int32_t, RawLightInfo> newLightInfos =
1650*38e8c45fSAndroid Build Coastguard Worker             readLightsConfiguration(sysfsRootPath);
1651*38e8c45fSAndroid Build Coastguard Worker     std::optional<RawLayoutInfo> newLayoutInfo = readLayoutConfiguration(sysfsRootPath);
1652*38e8c45fSAndroid Build Coastguard Worker 
1653*38e8c45fSAndroid Build Coastguard Worker     if (newBatteryInfos == batteryInfos && newLightInfos == lightInfos &&
1654*38e8c45fSAndroid Build Coastguard Worker         newLayoutInfo == layoutInfo) {
1655*38e8c45fSAndroid Build Coastguard Worker         return false;
1656*38e8c45fSAndroid Build Coastguard Worker     }
1657*38e8c45fSAndroid Build Coastguard Worker     return true;
1658*38e8c45fSAndroid Build Coastguard Worker }
1659*38e8c45fSAndroid Build Coastguard Worker 
vibrate(int32_t deviceId,const VibrationElement & element)1660*38e8c45fSAndroid Build Coastguard Worker void EventHub::vibrate(int32_t deviceId, const VibrationElement& element) {
1661*38e8c45fSAndroid Build Coastguard Worker     std::scoped_lock _l(mLock);
1662*38e8c45fSAndroid Build Coastguard Worker     Device* device = getDeviceLocked(deviceId);
1663*38e8c45fSAndroid Build Coastguard Worker     if (device != nullptr && device->hasValidFd()) {
1664*38e8c45fSAndroid Build Coastguard Worker         ff_effect effect;
1665*38e8c45fSAndroid Build Coastguard Worker         memset(&effect, 0, sizeof(effect));
1666*38e8c45fSAndroid Build Coastguard Worker         effect.type = FF_RUMBLE;
1667*38e8c45fSAndroid Build Coastguard Worker         effect.id = device->ffEffectId;
1668*38e8c45fSAndroid Build Coastguard Worker         // evdev FF_RUMBLE effect only supports two channels of vibration.
1669*38e8c45fSAndroid Build Coastguard Worker         effect.u.rumble.strong_magnitude = element.getMagnitude(FF_STRONG_MAGNITUDE_CHANNEL_IDX);
1670*38e8c45fSAndroid Build Coastguard Worker         effect.u.rumble.weak_magnitude = element.getMagnitude(FF_WEAK_MAGNITUDE_CHANNEL_IDX);
1671*38e8c45fSAndroid Build Coastguard Worker         effect.replay.length = element.duration.count();
1672*38e8c45fSAndroid Build Coastguard Worker         effect.replay.delay = 0;
1673*38e8c45fSAndroid Build Coastguard Worker         if (ioctl(device->fd, EVIOCSFF, &effect)) {
1674*38e8c45fSAndroid Build Coastguard Worker             ALOGW("Could not upload force feedback effect to device %s due to error %d.",
1675*38e8c45fSAndroid Build Coastguard Worker                   device->identifier.name.c_str(), errno);
1676*38e8c45fSAndroid Build Coastguard Worker             return;
1677*38e8c45fSAndroid Build Coastguard Worker         }
1678*38e8c45fSAndroid Build Coastguard Worker         device->ffEffectId = effect.id;
1679*38e8c45fSAndroid Build Coastguard Worker 
1680*38e8c45fSAndroid Build Coastguard Worker         struct input_event ev;
1681*38e8c45fSAndroid Build Coastguard Worker         ev.input_event_sec = 0;
1682*38e8c45fSAndroid Build Coastguard Worker         ev.input_event_usec = 0;
1683*38e8c45fSAndroid Build Coastguard Worker         ev.type = EV_FF;
1684*38e8c45fSAndroid Build Coastguard Worker         ev.code = device->ffEffectId;
1685*38e8c45fSAndroid Build Coastguard Worker         ev.value = 1;
1686*38e8c45fSAndroid Build Coastguard Worker         if (write(device->fd, &ev, sizeof(ev)) != sizeof(ev)) {
1687*38e8c45fSAndroid Build Coastguard Worker             ALOGW("Could not start force feedback effect on device %s due to error %d.",
1688*38e8c45fSAndroid Build Coastguard Worker                   device->identifier.name.c_str(), errno);
1689*38e8c45fSAndroid Build Coastguard Worker             return;
1690*38e8c45fSAndroid Build Coastguard Worker         }
1691*38e8c45fSAndroid Build Coastguard Worker         device->ffEffectPlaying = true;
1692*38e8c45fSAndroid Build Coastguard Worker     }
1693*38e8c45fSAndroid Build Coastguard Worker }
1694*38e8c45fSAndroid Build Coastguard Worker 
cancelVibrate(int32_t deviceId)1695*38e8c45fSAndroid Build Coastguard Worker void EventHub::cancelVibrate(int32_t deviceId) {
1696*38e8c45fSAndroid Build Coastguard Worker     std::scoped_lock _l(mLock);
1697*38e8c45fSAndroid Build Coastguard Worker     Device* device = getDeviceLocked(deviceId);
1698*38e8c45fSAndroid Build Coastguard Worker     if (device != nullptr && device->hasValidFd()) {
1699*38e8c45fSAndroid Build Coastguard Worker         if (device->ffEffectPlaying) {
1700*38e8c45fSAndroid Build Coastguard Worker             device->ffEffectPlaying = false;
1701*38e8c45fSAndroid Build Coastguard Worker 
1702*38e8c45fSAndroid Build Coastguard Worker             struct input_event ev;
1703*38e8c45fSAndroid Build Coastguard Worker             ev.input_event_sec = 0;
1704*38e8c45fSAndroid Build Coastguard Worker             ev.input_event_usec = 0;
1705*38e8c45fSAndroid Build Coastguard Worker             ev.type = EV_FF;
1706*38e8c45fSAndroid Build Coastguard Worker             ev.code = device->ffEffectId;
1707*38e8c45fSAndroid Build Coastguard Worker             ev.value = 0;
1708*38e8c45fSAndroid Build Coastguard Worker             if (write(device->fd, &ev, sizeof(ev)) != sizeof(ev)) {
1709*38e8c45fSAndroid Build Coastguard Worker                 ALOGW("Could not stop force feedback effect on device %s due to error %d.",
1710*38e8c45fSAndroid Build Coastguard Worker                       device->identifier.name.c_str(), errno);
1711*38e8c45fSAndroid Build Coastguard Worker                 return;
1712*38e8c45fSAndroid Build Coastguard Worker             }
1713*38e8c45fSAndroid Build Coastguard Worker         }
1714*38e8c45fSAndroid Build Coastguard Worker     }
1715*38e8c45fSAndroid Build Coastguard Worker }
1716*38e8c45fSAndroid Build Coastguard Worker 
getVibratorIds(int32_t deviceId) const1717*38e8c45fSAndroid Build Coastguard Worker std::vector<int32_t> EventHub::getVibratorIds(int32_t deviceId) const {
1718*38e8c45fSAndroid Build Coastguard Worker     std::scoped_lock _l(mLock);
1719*38e8c45fSAndroid Build Coastguard Worker     std::vector<int32_t> vibrators;
1720*38e8c45fSAndroid Build Coastguard Worker     Device* device = getDeviceLocked(deviceId);
1721*38e8c45fSAndroid Build Coastguard Worker     if (device != nullptr && device->hasValidFd() &&
1722*38e8c45fSAndroid Build Coastguard Worker         device->classes.test(InputDeviceClass::VIBRATOR)) {
1723*38e8c45fSAndroid Build Coastguard Worker         vibrators.push_back(FF_STRONG_MAGNITUDE_CHANNEL_IDX);
1724*38e8c45fSAndroid Build Coastguard Worker         vibrators.push_back(FF_WEAK_MAGNITUDE_CHANNEL_IDX);
1725*38e8c45fSAndroid Build Coastguard Worker     }
1726*38e8c45fSAndroid Build Coastguard Worker     return vibrators;
1727*38e8c45fSAndroid Build Coastguard Worker }
1728*38e8c45fSAndroid Build Coastguard Worker 
1729*38e8c45fSAndroid Build Coastguard Worker /**
1730*38e8c45fSAndroid Build Coastguard Worker  * Checks both mDevices and mOpeningDevices for a device with the descriptor passed.
1731*38e8c45fSAndroid Build Coastguard Worker  */
hasDeviceWithDescriptorLocked(const std::string & descriptor) const1732*38e8c45fSAndroid Build Coastguard Worker bool EventHub::hasDeviceWithDescriptorLocked(const std::string& descriptor) const {
1733*38e8c45fSAndroid Build Coastguard Worker     for (const auto& device : mOpeningDevices) {
1734*38e8c45fSAndroid Build Coastguard Worker         if (descriptor == device->identifier.descriptor) {
1735*38e8c45fSAndroid Build Coastguard Worker             return true;
1736*38e8c45fSAndroid Build Coastguard Worker         }
1737*38e8c45fSAndroid Build Coastguard Worker     }
1738*38e8c45fSAndroid Build Coastguard Worker 
1739*38e8c45fSAndroid Build Coastguard Worker     for (const auto& [id, device] : mDevices) {
1740*38e8c45fSAndroid Build Coastguard Worker         if (descriptor == device->identifier.descriptor) {
1741*38e8c45fSAndroid Build Coastguard Worker             return true;
1742*38e8c45fSAndroid Build Coastguard Worker         }
1743*38e8c45fSAndroid Build Coastguard Worker     }
1744*38e8c45fSAndroid Build Coastguard Worker     return false;
1745*38e8c45fSAndroid Build Coastguard Worker }
1746*38e8c45fSAndroid Build Coastguard Worker 
getDeviceLocked(int32_t deviceId) const1747*38e8c45fSAndroid Build Coastguard Worker EventHub::Device* EventHub::getDeviceLocked(int32_t deviceId) const {
1748*38e8c45fSAndroid Build Coastguard Worker     if (deviceId == ReservedInputDeviceId::BUILT_IN_KEYBOARD_ID) {
1749*38e8c45fSAndroid Build Coastguard Worker         deviceId = mBuiltInKeyboardId;
1750*38e8c45fSAndroid Build Coastguard Worker     }
1751*38e8c45fSAndroid Build Coastguard Worker     const auto& it = mDevices.find(deviceId);
1752*38e8c45fSAndroid Build Coastguard Worker     return it != mDevices.end() ? it->second.get() : nullptr;
1753*38e8c45fSAndroid Build Coastguard Worker }
1754*38e8c45fSAndroid Build Coastguard Worker 
getDeviceByPathLocked(const std::string & devicePath) const1755*38e8c45fSAndroid Build Coastguard Worker EventHub::Device* EventHub::getDeviceByPathLocked(const std::string& devicePath) const {
1756*38e8c45fSAndroid Build Coastguard Worker     for (const auto& [id, device] : mDevices) {
1757*38e8c45fSAndroid Build Coastguard Worker         if (device->path == devicePath) {
1758*38e8c45fSAndroid Build Coastguard Worker             return device.get();
1759*38e8c45fSAndroid Build Coastguard Worker         }
1760*38e8c45fSAndroid Build Coastguard Worker     }
1761*38e8c45fSAndroid Build Coastguard Worker     return nullptr;
1762*38e8c45fSAndroid Build Coastguard Worker }
1763*38e8c45fSAndroid Build Coastguard Worker 
1764*38e8c45fSAndroid Build Coastguard Worker /**
1765*38e8c45fSAndroid Build Coastguard Worker  * The file descriptor could be either input device, or a video device (associated with a
1766*38e8c45fSAndroid Build Coastguard Worker  * specific input device). Check both cases here, and return the device that this event
1767*38e8c45fSAndroid Build Coastguard Worker  * belongs to. Caller can compare the fd's once more to determine event type.
1768*38e8c45fSAndroid Build Coastguard Worker  * Looks through all input devices, and only attached video devices. Unattached video
1769*38e8c45fSAndroid Build Coastguard Worker  * devices are ignored.
1770*38e8c45fSAndroid Build Coastguard Worker  */
getDeviceByFdLocked(int fd) const1771*38e8c45fSAndroid Build Coastguard Worker EventHub::Device* EventHub::getDeviceByFdLocked(int fd) const {
1772*38e8c45fSAndroid Build Coastguard Worker     for (const auto& [id, device] : mDevices) {
1773*38e8c45fSAndroid Build Coastguard Worker         if (device->fd == fd) {
1774*38e8c45fSAndroid Build Coastguard Worker             // This is an input device event
1775*38e8c45fSAndroid Build Coastguard Worker             return device.get();
1776*38e8c45fSAndroid Build Coastguard Worker         }
1777*38e8c45fSAndroid Build Coastguard Worker         if (device->videoDevice && device->videoDevice->getFd() == fd) {
1778*38e8c45fSAndroid Build Coastguard Worker             // This is a video device event
1779*38e8c45fSAndroid Build Coastguard Worker             return device.get();
1780*38e8c45fSAndroid Build Coastguard Worker         }
1781*38e8c45fSAndroid Build Coastguard Worker     }
1782*38e8c45fSAndroid Build Coastguard Worker     // We do not check mUnattachedVideoDevices here because they should not participate in epoll,
1783*38e8c45fSAndroid Build Coastguard Worker     // and therefore should never be looked up by fd.
1784*38e8c45fSAndroid Build Coastguard Worker     return nullptr;
1785*38e8c45fSAndroid Build Coastguard Worker }
1786*38e8c45fSAndroid Build Coastguard Worker 
getBatteryCapacity(int32_t deviceId,int32_t batteryId) const1787*38e8c45fSAndroid Build Coastguard Worker std::optional<int32_t> EventHub::getBatteryCapacity(int32_t deviceId, int32_t batteryId) const {
1788*38e8c45fSAndroid Build Coastguard Worker     std::filesystem::path batteryPath;
1789*38e8c45fSAndroid Build Coastguard Worker     {
1790*38e8c45fSAndroid Build Coastguard Worker         // Do not read the sysfs node to get the battery state while holding
1791*38e8c45fSAndroid Build Coastguard Worker         // the EventHub lock. For some peripheral devices, reading battery state
1792*38e8c45fSAndroid Build Coastguard Worker         // can be broken and take 5+ seconds. Holding the lock in this case would
1793*38e8c45fSAndroid Build Coastguard Worker         // block all other event processing during this time. For now, we assume this
1794*38e8c45fSAndroid Build Coastguard Worker         // call never happens on the InputReader thread and read the sysfs node outside
1795*38e8c45fSAndroid Build Coastguard Worker         // the lock to prevent event processing from being blocked by this call.
1796*38e8c45fSAndroid Build Coastguard Worker         std::scoped_lock _l(mLock);
1797*38e8c45fSAndroid Build Coastguard Worker 
1798*38e8c45fSAndroid Build Coastguard Worker         const auto& infos = getBatteryInfoLocked(deviceId);
1799*38e8c45fSAndroid Build Coastguard Worker         auto it = infos.find(batteryId);
1800*38e8c45fSAndroid Build Coastguard Worker         if (it == infos.end()) {
1801*38e8c45fSAndroid Build Coastguard Worker             return std::nullopt;
1802*38e8c45fSAndroid Build Coastguard Worker         }
1803*38e8c45fSAndroid Build Coastguard Worker         batteryPath = it->second.path;
1804*38e8c45fSAndroid Build Coastguard Worker     } // release lock
1805*38e8c45fSAndroid Build Coastguard Worker 
1806*38e8c45fSAndroid Build Coastguard Worker     std::string buffer;
1807*38e8c45fSAndroid Build Coastguard Worker 
1808*38e8c45fSAndroid Build Coastguard Worker     // Some devices report battery capacity as an integer through the "capacity" file
1809*38e8c45fSAndroid Build Coastguard Worker     if (base::ReadFileToString(batteryPath / BATTERY_NODES.at(InputBatteryClass::CAPACITY),
1810*38e8c45fSAndroid Build Coastguard Worker                                &buffer)) {
1811*38e8c45fSAndroid Build Coastguard Worker         return std::stoi(base::Trim(buffer));
1812*38e8c45fSAndroid Build Coastguard Worker     }
1813*38e8c45fSAndroid Build Coastguard Worker 
1814*38e8c45fSAndroid Build Coastguard Worker     // Other devices report capacity as an enum value POWER_SUPPLY_CAPACITY_LEVEL_XXX
1815*38e8c45fSAndroid Build Coastguard Worker     // These values are taken from kernel source code include/linux/power_supply.h
1816*38e8c45fSAndroid Build Coastguard Worker     if (base::ReadFileToString(batteryPath / BATTERY_NODES.at(InputBatteryClass::CAPACITY_LEVEL),
1817*38e8c45fSAndroid Build Coastguard Worker                                &buffer)) {
1818*38e8c45fSAndroid Build Coastguard Worker         // Remove any white space such as trailing new line
1819*38e8c45fSAndroid Build Coastguard Worker         const auto levelIt = BATTERY_LEVEL.find(base::Trim(buffer));
1820*38e8c45fSAndroid Build Coastguard Worker         if (levelIt != BATTERY_LEVEL.end()) {
1821*38e8c45fSAndroid Build Coastguard Worker             return levelIt->second;
1822*38e8c45fSAndroid Build Coastguard Worker         }
1823*38e8c45fSAndroid Build Coastguard Worker     }
1824*38e8c45fSAndroid Build Coastguard Worker 
1825*38e8c45fSAndroid Build Coastguard Worker     return std::nullopt;
1826*38e8c45fSAndroid Build Coastguard Worker }
1827*38e8c45fSAndroid Build Coastguard Worker 
getBatteryStatus(int32_t deviceId,int32_t batteryId) const1828*38e8c45fSAndroid Build Coastguard Worker std::optional<int32_t> EventHub::getBatteryStatus(int32_t deviceId, int32_t batteryId) const {
1829*38e8c45fSAndroid Build Coastguard Worker     std::filesystem::path batteryPath;
1830*38e8c45fSAndroid Build Coastguard Worker     {
1831*38e8c45fSAndroid Build Coastguard Worker         // Do not read the sysfs node to get the battery state while holding
1832*38e8c45fSAndroid Build Coastguard Worker         // the EventHub lock. For some peripheral devices, reading battery state
1833*38e8c45fSAndroid Build Coastguard Worker         // can be broken and take 5+ seconds. Holding the lock in this case would
1834*38e8c45fSAndroid Build Coastguard Worker         // block all other event processing during this time. For now, we assume this
1835*38e8c45fSAndroid Build Coastguard Worker         // call never happens on the InputReader thread and read the sysfs node outside
1836*38e8c45fSAndroid Build Coastguard Worker         // the lock to prevent event processing from being blocked by this call.
1837*38e8c45fSAndroid Build Coastguard Worker         std::scoped_lock _l(mLock);
1838*38e8c45fSAndroid Build Coastguard Worker 
1839*38e8c45fSAndroid Build Coastguard Worker         const auto& infos = getBatteryInfoLocked(deviceId);
1840*38e8c45fSAndroid Build Coastguard Worker         auto it = infos.find(batteryId);
1841*38e8c45fSAndroid Build Coastguard Worker         if (it == infos.end()) {
1842*38e8c45fSAndroid Build Coastguard Worker             return std::nullopt;
1843*38e8c45fSAndroid Build Coastguard Worker         }
1844*38e8c45fSAndroid Build Coastguard Worker         batteryPath = it->second.path;
1845*38e8c45fSAndroid Build Coastguard Worker     } // release lock
1846*38e8c45fSAndroid Build Coastguard Worker 
1847*38e8c45fSAndroid Build Coastguard Worker     std::string buffer;
1848*38e8c45fSAndroid Build Coastguard Worker 
1849*38e8c45fSAndroid Build Coastguard Worker     if (!base::ReadFileToString(batteryPath / BATTERY_NODES.at(InputBatteryClass::STATUS),
1850*38e8c45fSAndroid Build Coastguard Worker                                 &buffer)) {
1851*38e8c45fSAndroid Build Coastguard Worker         ALOGE("Failed to read sysfs battery info: %s", strerror(errno));
1852*38e8c45fSAndroid Build Coastguard Worker         return std::nullopt;
1853*38e8c45fSAndroid Build Coastguard Worker     }
1854*38e8c45fSAndroid Build Coastguard Worker 
1855*38e8c45fSAndroid Build Coastguard Worker     // Remove white space like trailing new line
1856*38e8c45fSAndroid Build Coastguard Worker     const auto statusIt = BATTERY_STATUS.find(base::Trim(buffer));
1857*38e8c45fSAndroid Build Coastguard Worker     if (statusIt != BATTERY_STATUS.end()) {
1858*38e8c45fSAndroid Build Coastguard Worker         return statusIt->second;
1859*38e8c45fSAndroid Build Coastguard Worker     }
1860*38e8c45fSAndroid Build Coastguard Worker 
1861*38e8c45fSAndroid Build Coastguard Worker     return std::nullopt;
1862*38e8c45fSAndroid Build Coastguard Worker }
1863*38e8c45fSAndroid Build Coastguard Worker 
getEvents(int timeoutMillis)1864*38e8c45fSAndroid Build Coastguard Worker std::vector<RawEvent> EventHub::getEvents(int timeoutMillis) {
1865*38e8c45fSAndroid Build Coastguard Worker     std::scoped_lock _l(mLock);
1866*38e8c45fSAndroid Build Coastguard Worker 
1867*38e8c45fSAndroid Build Coastguard Worker     std::array<input_event, EVENT_BUFFER_SIZE> readBuffer;
1868*38e8c45fSAndroid Build Coastguard Worker 
1869*38e8c45fSAndroid Build Coastguard Worker     std::vector<RawEvent> events;
1870*38e8c45fSAndroid Build Coastguard Worker     bool awoken = false;
1871*38e8c45fSAndroid Build Coastguard Worker     for (;;) {
1872*38e8c45fSAndroid Build Coastguard Worker         nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
1873*38e8c45fSAndroid Build Coastguard Worker 
1874*38e8c45fSAndroid Build Coastguard Worker         // Reopen input devices if needed.
1875*38e8c45fSAndroid Build Coastguard Worker         if (mNeedToReopenDevices) {
1876*38e8c45fSAndroid Build Coastguard Worker             mNeedToReopenDevices = false;
1877*38e8c45fSAndroid Build Coastguard Worker 
1878*38e8c45fSAndroid Build Coastguard Worker             ALOGI("Reopening all input devices due to a configuration change.");
1879*38e8c45fSAndroid Build Coastguard Worker 
1880*38e8c45fSAndroid Build Coastguard Worker             closeAllDevicesLocked();
1881*38e8c45fSAndroid Build Coastguard Worker             mNeedToScanDevices = true;
1882*38e8c45fSAndroid Build Coastguard Worker             break; // return to the caller before we actually rescan
1883*38e8c45fSAndroid Build Coastguard Worker         }
1884*38e8c45fSAndroid Build Coastguard Worker 
1885*38e8c45fSAndroid Build Coastguard Worker         // Report any devices that had last been added/removed.
1886*38e8c45fSAndroid Build Coastguard Worker         for (auto it = mClosingDevices.begin(); it != mClosingDevices.end();) {
1887*38e8c45fSAndroid Build Coastguard Worker             std::unique_ptr<Device> device = std::move(*it);
1888*38e8c45fSAndroid Build Coastguard Worker             ALOGV("Reporting device closed: id=%d, name=%s\n", device->id, device->path.c_str());
1889*38e8c45fSAndroid Build Coastguard Worker             const int32_t deviceId = (device->id == mBuiltInKeyboardId)
1890*38e8c45fSAndroid Build Coastguard Worker                     ? ReservedInputDeviceId::BUILT_IN_KEYBOARD_ID
1891*38e8c45fSAndroid Build Coastguard Worker                     : device->id;
1892*38e8c45fSAndroid Build Coastguard Worker             events.push_back({
1893*38e8c45fSAndroid Build Coastguard Worker                     .when = now,
1894*38e8c45fSAndroid Build Coastguard Worker                     .deviceId = deviceId,
1895*38e8c45fSAndroid Build Coastguard Worker                     .type = DEVICE_REMOVED,
1896*38e8c45fSAndroid Build Coastguard Worker             });
1897*38e8c45fSAndroid Build Coastguard Worker             it = mClosingDevices.erase(it);
1898*38e8c45fSAndroid Build Coastguard Worker             if (events.size() == EVENT_BUFFER_SIZE) {
1899*38e8c45fSAndroid Build Coastguard Worker                 break;
1900*38e8c45fSAndroid Build Coastguard Worker             }
1901*38e8c45fSAndroid Build Coastguard Worker         }
1902*38e8c45fSAndroid Build Coastguard Worker 
1903*38e8c45fSAndroid Build Coastguard Worker         if (mNeedToScanDevices) {
1904*38e8c45fSAndroid Build Coastguard Worker             mNeedToScanDevices = false;
1905*38e8c45fSAndroid Build Coastguard Worker             scanDevicesLocked();
1906*38e8c45fSAndroid Build Coastguard Worker         }
1907*38e8c45fSAndroid Build Coastguard Worker 
1908*38e8c45fSAndroid Build Coastguard Worker         while (!mOpeningDevices.empty()) {
1909*38e8c45fSAndroid Build Coastguard Worker             std::unique_ptr<Device> device = std::move(*mOpeningDevices.rbegin());
1910*38e8c45fSAndroid Build Coastguard Worker             mOpeningDevices.pop_back();
1911*38e8c45fSAndroid Build Coastguard Worker             ALOGV("Reporting device opened: id=%d, name=%s\n", device->id, device->path.c_str());
1912*38e8c45fSAndroid Build Coastguard Worker             const int32_t deviceId = device->id == mBuiltInKeyboardId ? 0 : device->id;
1913*38e8c45fSAndroid Build Coastguard Worker             events.push_back({
1914*38e8c45fSAndroid Build Coastguard Worker                     .when = now,
1915*38e8c45fSAndroid Build Coastguard Worker                     .deviceId = deviceId,
1916*38e8c45fSAndroid Build Coastguard Worker                     .type = DEVICE_ADDED,
1917*38e8c45fSAndroid Build Coastguard Worker             });
1918*38e8c45fSAndroid Build Coastguard Worker 
1919*38e8c45fSAndroid Build Coastguard Worker             // Try to find a matching video device by comparing device names
1920*38e8c45fSAndroid Build Coastguard Worker             for (auto it = mUnattachedVideoDevices.begin(); it != mUnattachedVideoDevices.end();
1921*38e8c45fSAndroid Build Coastguard Worker                  it++) {
1922*38e8c45fSAndroid Build Coastguard Worker                 std::unique_ptr<TouchVideoDevice>& videoDevice = *it;
1923*38e8c45fSAndroid Build Coastguard Worker                 if (tryAddVideoDeviceLocked(*device, videoDevice)) {
1924*38e8c45fSAndroid Build Coastguard Worker                     // videoDevice was transferred to 'device'
1925*38e8c45fSAndroid Build Coastguard Worker                     it = mUnattachedVideoDevices.erase(it);
1926*38e8c45fSAndroid Build Coastguard Worker                     break;
1927*38e8c45fSAndroid Build Coastguard Worker                 }
1928*38e8c45fSAndroid Build Coastguard Worker             }
1929*38e8c45fSAndroid Build Coastguard Worker 
1930*38e8c45fSAndroid Build Coastguard Worker             auto [dev_it, inserted] = mDevices.insert_or_assign(device->id, std::move(device));
1931*38e8c45fSAndroid Build Coastguard Worker             if (!inserted) {
1932*38e8c45fSAndroid Build Coastguard Worker                 ALOGW("Device id %d exists, replaced.", device->id);
1933*38e8c45fSAndroid Build Coastguard Worker             }
1934*38e8c45fSAndroid Build Coastguard Worker             if (events.size() == EVENT_BUFFER_SIZE) {
1935*38e8c45fSAndroid Build Coastguard Worker                 break;
1936*38e8c45fSAndroid Build Coastguard Worker             }
1937*38e8c45fSAndroid Build Coastguard Worker         }
1938*38e8c45fSAndroid Build Coastguard Worker 
1939*38e8c45fSAndroid Build Coastguard Worker         // Grab the next input event.
1940*38e8c45fSAndroid Build Coastguard Worker         bool deviceChanged = false;
1941*38e8c45fSAndroid Build Coastguard Worker         while (mPendingEventIndex < mPendingEventCount) {
1942*38e8c45fSAndroid Build Coastguard Worker             const struct epoll_event& eventItem = mPendingEventItems[mPendingEventIndex++];
1943*38e8c45fSAndroid Build Coastguard Worker             if (eventItem.data.fd == mINotifyFd) {
1944*38e8c45fSAndroid Build Coastguard Worker                 if (eventItem.events & EPOLLIN) {
1945*38e8c45fSAndroid Build Coastguard Worker                     mPendingINotify = true;
1946*38e8c45fSAndroid Build Coastguard Worker                 } else {
1947*38e8c45fSAndroid Build Coastguard Worker                     ALOGW("Received unexpected epoll event 0x%08x for INotify.", eventItem.events);
1948*38e8c45fSAndroid Build Coastguard Worker                 }
1949*38e8c45fSAndroid Build Coastguard Worker                 continue;
1950*38e8c45fSAndroid Build Coastguard Worker             }
1951*38e8c45fSAndroid Build Coastguard Worker 
1952*38e8c45fSAndroid Build Coastguard Worker             if (eventItem.data.fd == mWakeReadPipeFd) {
1953*38e8c45fSAndroid Build Coastguard Worker                 if (eventItem.events & EPOLLIN) {
1954*38e8c45fSAndroid Build Coastguard Worker                     ALOGV("awoken after wake()");
1955*38e8c45fSAndroid Build Coastguard Worker                     awoken = true;
1956*38e8c45fSAndroid Build Coastguard Worker                     char wakeReadBuffer[16];
1957*38e8c45fSAndroid Build Coastguard Worker                     ssize_t nRead;
1958*38e8c45fSAndroid Build Coastguard Worker                     do {
1959*38e8c45fSAndroid Build Coastguard Worker                         nRead = read(mWakeReadPipeFd, wakeReadBuffer, sizeof(wakeReadBuffer));
1960*38e8c45fSAndroid Build Coastguard Worker                     } while ((nRead == -1 && errno == EINTR) || nRead == sizeof(wakeReadBuffer));
1961*38e8c45fSAndroid Build Coastguard Worker                 } else {
1962*38e8c45fSAndroid Build Coastguard Worker                     ALOGW("Received unexpected epoll event 0x%08x for wake read pipe.",
1963*38e8c45fSAndroid Build Coastguard Worker                           eventItem.events);
1964*38e8c45fSAndroid Build Coastguard Worker                 }
1965*38e8c45fSAndroid Build Coastguard Worker                 continue;
1966*38e8c45fSAndroid Build Coastguard Worker             }
1967*38e8c45fSAndroid Build Coastguard Worker 
1968*38e8c45fSAndroid Build Coastguard Worker             Device* device = getDeviceByFdLocked(eventItem.data.fd);
1969*38e8c45fSAndroid Build Coastguard Worker             if (device == nullptr) {
1970*38e8c45fSAndroid Build Coastguard Worker                 ALOGE("Received unexpected epoll event 0x%08x for unknown fd %d.", eventItem.events,
1971*38e8c45fSAndroid Build Coastguard Worker                       eventItem.data.fd);
1972*38e8c45fSAndroid Build Coastguard Worker                 ALOG_ASSERT(!DEBUG);
1973*38e8c45fSAndroid Build Coastguard Worker                 continue;
1974*38e8c45fSAndroid Build Coastguard Worker             }
1975*38e8c45fSAndroid Build Coastguard Worker             if (device->videoDevice && eventItem.data.fd == device->videoDevice->getFd()) {
1976*38e8c45fSAndroid Build Coastguard Worker                 if (eventItem.events & EPOLLIN) {
1977*38e8c45fSAndroid Build Coastguard Worker                     size_t numFrames = device->videoDevice->readAndQueueFrames();
1978*38e8c45fSAndroid Build Coastguard Worker                     if (numFrames == 0) {
1979*38e8c45fSAndroid Build Coastguard Worker                         ALOGE("Received epoll event for video device %s, but could not read frame",
1980*38e8c45fSAndroid Build Coastguard Worker                               device->videoDevice->getName().c_str());
1981*38e8c45fSAndroid Build Coastguard Worker                     }
1982*38e8c45fSAndroid Build Coastguard Worker                 } else if (eventItem.events & EPOLLHUP) {
1983*38e8c45fSAndroid Build Coastguard Worker                     // TODO(b/121395353) - consider adding EPOLLRDHUP
1984*38e8c45fSAndroid Build Coastguard Worker                     ALOGI("Removing video device %s due to epoll hang-up event.",
1985*38e8c45fSAndroid Build Coastguard Worker                           device->videoDevice->getName().c_str());
1986*38e8c45fSAndroid Build Coastguard Worker                     unregisterVideoDeviceFromEpollLocked(*device->videoDevice);
1987*38e8c45fSAndroid Build Coastguard Worker                     device->videoDevice = nullptr;
1988*38e8c45fSAndroid Build Coastguard Worker                 } else {
1989*38e8c45fSAndroid Build Coastguard Worker                     ALOGW("Received unexpected epoll event 0x%08x for device %s.", eventItem.events,
1990*38e8c45fSAndroid Build Coastguard Worker                           device->videoDevice->getName().c_str());
1991*38e8c45fSAndroid Build Coastguard Worker                     ALOG_ASSERT(!DEBUG);
1992*38e8c45fSAndroid Build Coastguard Worker                 }
1993*38e8c45fSAndroid Build Coastguard Worker                 continue;
1994*38e8c45fSAndroid Build Coastguard Worker             }
1995*38e8c45fSAndroid Build Coastguard Worker             // This must be an input event
1996*38e8c45fSAndroid Build Coastguard Worker             if (eventItem.events & EPOLLIN) {
1997*38e8c45fSAndroid Build Coastguard Worker                 int32_t readSize =
1998*38e8c45fSAndroid Build Coastguard Worker                         read(device->fd, readBuffer.data(),
1999*38e8c45fSAndroid Build Coastguard Worker                              sizeof(decltype(readBuffer)::value_type) * readBuffer.size());
2000*38e8c45fSAndroid Build Coastguard Worker                 if (readSize == 0 || (readSize < 0 && errno == ENODEV)) {
2001*38e8c45fSAndroid Build Coastguard Worker                     // Device was removed before INotify noticed.
2002*38e8c45fSAndroid Build Coastguard Worker                     ALOGW("could not get event, removed? (fd: %d size: %" PRId32
2003*38e8c45fSAndroid Build Coastguard Worker                           " capacity: %zu errno: %d)\n",
2004*38e8c45fSAndroid Build Coastguard Worker                           device->fd, readSize, readBuffer.size(), errno);
2005*38e8c45fSAndroid Build Coastguard Worker                     deviceChanged = true;
2006*38e8c45fSAndroid Build Coastguard Worker                     closeDeviceLocked(*device);
2007*38e8c45fSAndroid Build Coastguard Worker                 } else if (readSize < 0) {
2008*38e8c45fSAndroid Build Coastguard Worker                     if (errno != EAGAIN && errno != EINTR) {
2009*38e8c45fSAndroid Build Coastguard Worker                         ALOGW("could not get event (errno=%d)", errno);
2010*38e8c45fSAndroid Build Coastguard Worker                     }
2011*38e8c45fSAndroid Build Coastguard Worker                 } else if ((readSize % sizeof(struct input_event)) != 0) {
2012*38e8c45fSAndroid Build Coastguard Worker                     ALOGE("could not get event (wrong size: %d)", readSize);
2013*38e8c45fSAndroid Build Coastguard Worker                 } else {
2014*38e8c45fSAndroid Build Coastguard Worker                     const int32_t deviceId = device->id == mBuiltInKeyboardId ? 0 : device->id;
2015*38e8c45fSAndroid Build Coastguard Worker 
2016*38e8c45fSAndroid Build Coastguard Worker                     const size_t count = size_t(readSize) / sizeof(struct input_event);
2017*38e8c45fSAndroid Build Coastguard Worker                     for (size_t i = 0; i < count; i++) {
2018*38e8c45fSAndroid Build Coastguard Worker                         struct input_event& iev = readBuffer[i];
2019*38e8c45fSAndroid Build Coastguard Worker                         device->trackInputEvent(iev);
2020*38e8c45fSAndroid Build Coastguard Worker                         events.push_back({
2021*38e8c45fSAndroid Build Coastguard Worker                                 .when = processEventTimestamp(iev),
2022*38e8c45fSAndroid Build Coastguard Worker                                 .readTime = systemTime(SYSTEM_TIME_MONOTONIC),
2023*38e8c45fSAndroid Build Coastguard Worker                                 .deviceId = deviceId,
2024*38e8c45fSAndroid Build Coastguard Worker                                 .type = iev.type,
2025*38e8c45fSAndroid Build Coastguard Worker                                 .code = iev.code,
2026*38e8c45fSAndroid Build Coastguard Worker                                 .value = iev.value,
2027*38e8c45fSAndroid Build Coastguard Worker                         });
2028*38e8c45fSAndroid Build Coastguard Worker                     }
2029*38e8c45fSAndroid Build Coastguard Worker                     if (events.size() >= EVENT_BUFFER_SIZE) {
2030*38e8c45fSAndroid Build Coastguard Worker                         // The result buffer is full.  Reset the pending event index
2031*38e8c45fSAndroid Build Coastguard Worker                         // so we will try to read the device again on the next iteration.
2032*38e8c45fSAndroid Build Coastguard Worker                         mPendingEventIndex -= 1;
2033*38e8c45fSAndroid Build Coastguard Worker                         break;
2034*38e8c45fSAndroid Build Coastguard Worker                     }
2035*38e8c45fSAndroid Build Coastguard Worker                 }
2036*38e8c45fSAndroid Build Coastguard Worker             } else if (eventItem.events & EPOLLHUP) {
2037*38e8c45fSAndroid Build Coastguard Worker                 ALOGI("Removing device %s due to epoll hang-up event.",
2038*38e8c45fSAndroid Build Coastguard Worker                       device->identifier.name.c_str());
2039*38e8c45fSAndroid Build Coastguard Worker                 deviceChanged = true;
2040*38e8c45fSAndroid Build Coastguard Worker                 closeDeviceLocked(*device);
2041*38e8c45fSAndroid Build Coastguard Worker             } else {
2042*38e8c45fSAndroid Build Coastguard Worker                 ALOGW("Received unexpected epoll event 0x%08x for device %s.", eventItem.events,
2043*38e8c45fSAndroid Build Coastguard Worker                       device->identifier.name.c_str());
2044*38e8c45fSAndroid Build Coastguard Worker             }
2045*38e8c45fSAndroid Build Coastguard Worker         }
2046*38e8c45fSAndroid Build Coastguard Worker 
2047*38e8c45fSAndroid Build Coastguard Worker         // readNotify() will modify the list of devices so this must be done after
2048*38e8c45fSAndroid Build Coastguard Worker         // processing all other events to ensure that we read all remaining events
2049*38e8c45fSAndroid Build Coastguard Worker         // before closing the devices.
2050*38e8c45fSAndroid Build Coastguard Worker         if (mPendingINotify && mPendingEventIndex >= mPendingEventCount) {
2051*38e8c45fSAndroid Build Coastguard Worker             mPendingINotify = false;
2052*38e8c45fSAndroid Build Coastguard Worker             const auto res = readNotifyLocked();
2053*38e8c45fSAndroid Build Coastguard Worker             if (!res.ok()) {
2054*38e8c45fSAndroid Build Coastguard Worker                 ALOGW("Failed to read from inotify: %s", res.error().message().c_str());
2055*38e8c45fSAndroid Build Coastguard Worker             }
2056*38e8c45fSAndroid Build Coastguard Worker             deviceChanged = true;
2057*38e8c45fSAndroid Build Coastguard Worker         }
2058*38e8c45fSAndroid Build Coastguard Worker 
2059*38e8c45fSAndroid Build Coastguard Worker         // Report added or removed devices immediately.
2060*38e8c45fSAndroid Build Coastguard Worker         if (deviceChanged) {
2061*38e8c45fSAndroid Build Coastguard Worker             continue;
2062*38e8c45fSAndroid Build Coastguard Worker         }
2063*38e8c45fSAndroid Build Coastguard Worker 
2064*38e8c45fSAndroid Build Coastguard Worker         // Return now if we have collected any events or if we were explicitly awoken.
2065*38e8c45fSAndroid Build Coastguard Worker         if (!events.empty() || awoken) {
2066*38e8c45fSAndroid Build Coastguard Worker             break;
2067*38e8c45fSAndroid Build Coastguard Worker         }
2068*38e8c45fSAndroid Build Coastguard Worker 
2069*38e8c45fSAndroid Build Coastguard Worker         // Poll for events.
2070*38e8c45fSAndroid Build Coastguard Worker         // When a device driver has pending (unread) events, it acquires
2071*38e8c45fSAndroid Build Coastguard Worker         // a kernel wake lock.  Once the last pending event has been read, the device
2072*38e8c45fSAndroid Build Coastguard Worker         // driver will release the kernel wake lock, but the epoll will hold the wakelock,
2073*38e8c45fSAndroid Build Coastguard Worker         // since we are using EPOLLWAKEUP. The wakelock is released by the epoll when epoll_wait
2074*38e8c45fSAndroid Build Coastguard Worker         // is called again for the same fd that produced the event.
2075*38e8c45fSAndroid Build Coastguard Worker         // Thus the system can only sleep if there are no events pending or
2076*38e8c45fSAndroid Build Coastguard Worker         // currently being processed.
2077*38e8c45fSAndroid Build Coastguard Worker         //
2078*38e8c45fSAndroid Build Coastguard Worker         // The timeout is advisory only.  If the device is asleep, it will not wake just to
2079*38e8c45fSAndroid Build Coastguard Worker         // service the timeout.
2080*38e8c45fSAndroid Build Coastguard Worker         mPendingEventIndex = 0;
2081*38e8c45fSAndroid Build Coastguard Worker 
2082*38e8c45fSAndroid Build Coastguard Worker         mLock.unlock(); // release lock before poll
2083*38e8c45fSAndroid Build Coastguard Worker 
2084*38e8c45fSAndroid Build Coastguard Worker         int pollResult = epoll_wait(mEpollFd, mPendingEventItems, EPOLL_MAX_EVENTS, timeoutMillis);
2085*38e8c45fSAndroid Build Coastguard Worker 
2086*38e8c45fSAndroid Build Coastguard Worker         mLock.lock(); // reacquire lock after poll
2087*38e8c45fSAndroid Build Coastguard Worker 
2088*38e8c45fSAndroid Build Coastguard Worker         if (pollResult == 0) {
2089*38e8c45fSAndroid Build Coastguard Worker             // Timed out.
2090*38e8c45fSAndroid Build Coastguard Worker             mPendingEventCount = 0;
2091*38e8c45fSAndroid Build Coastguard Worker             break;
2092*38e8c45fSAndroid Build Coastguard Worker         }
2093*38e8c45fSAndroid Build Coastguard Worker 
2094*38e8c45fSAndroid Build Coastguard Worker         if (pollResult < 0) {
2095*38e8c45fSAndroid Build Coastguard Worker             // An error occurred.
2096*38e8c45fSAndroid Build Coastguard Worker             mPendingEventCount = 0;
2097*38e8c45fSAndroid Build Coastguard Worker 
2098*38e8c45fSAndroid Build Coastguard Worker             // Sleep after errors to avoid locking up the system.
2099*38e8c45fSAndroid Build Coastguard Worker             // Hopefully the error is transient.
2100*38e8c45fSAndroid Build Coastguard Worker             if (errno != EINTR) {
2101*38e8c45fSAndroid Build Coastguard Worker                 ALOGW("poll failed (errno=%d)\n", errno);
2102*38e8c45fSAndroid Build Coastguard Worker                 usleep(100000);
2103*38e8c45fSAndroid Build Coastguard Worker             }
2104*38e8c45fSAndroid Build Coastguard Worker         } else {
2105*38e8c45fSAndroid Build Coastguard Worker             // Some events occurred.
2106*38e8c45fSAndroid Build Coastguard Worker             mPendingEventCount = size_t(pollResult);
2107*38e8c45fSAndroid Build Coastguard Worker         }
2108*38e8c45fSAndroid Build Coastguard Worker     }
2109*38e8c45fSAndroid Build Coastguard Worker 
2110*38e8c45fSAndroid Build Coastguard Worker     // All done, return the number of events we read.
2111*38e8c45fSAndroid Build Coastguard Worker     return events;
2112*38e8c45fSAndroid Build Coastguard Worker }
2113*38e8c45fSAndroid Build Coastguard Worker 
getVideoFrames(int32_t deviceId)2114*38e8c45fSAndroid Build Coastguard Worker std::vector<TouchVideoFrame> EventHub::getVideoFrames(int32_t deviceId) {
2115*38e8c45fSAndroid Build Coastguard Worker     std::scoped_lock _l(mLock);
2116*38e8c45fSAndroid Build Coastguard Worker 
2117*38e8c45fSAndroid Build Coastguard Worker     Device* device = getDeviceLocked(deviceId);
2118*38e8c45fSAndroid Build Coastguard Worker     if (device == nullptr || !device->videoDevice) {
2119*38e8c45fSAndroid Build Coastguard Worker         return {};
2120*38e8c45fSAndroid Build Coastguard Worker     }
2121*38e8c45fSAndroid Build Coastguard Worker     return device->videoDevice->consumeFrames();
2122*38e8c45fSAndroid Build Coastguard Worker }
2123*38e8c45fSAndroid Build Coastguard Worker 
wake()2124*38e8c45fSAndroid Build Coastguard Worker void EventHub::wake() {
2125*38e8c45fSAndroid Build Coastguard Worker     ALOGV("wake() called");
2126*38e8c45fSAndroid Build Coastguard Worker 
2127*38e8c45fSAndroid Build Coastguard Worker     ssize_t nWrite;
2128*38e8c45fSAndroid Build Coastguard Worker     do {
2129*38e8c45fSAndroid Build Coastguard Worker         nWrite = write(mWakeWritePipeFd, "W", 1);
2130*38e8c45fSAndroid Build Coastguard Worker     } while (nWrite == -1 && errno == EINTR);
2131*38e8c45fSAndroid Build Coastguard Worker 
2132*38e8c45fSAndroid Build Coastguard Worker     if (nWrite != 1 && errno != EAGAIN) {
2133*38e8c45fSAndroid Build Coastguard Worker         ALOGW("Could not write wake signal: %s", strerror(errno));
2134*38e8c45fSAndroid Build Coastguard Worker     }
2135*38e8c45fSAndroid Build Coastguard Worker }
2136*38e8c45fSAndroid Build Coastguard Worker 
scanDevicesLocked()2137*38e8c45fSAndroid Build Coastguard Worker void EventHub::scanDevicesLocked() {
2138*38e8c45fSAndroid Build Coastguard Worker     status_t result;
2139*38e8c45fSAndroid Build Coastguard Worker     std::error_code errorCode;
2140*38e8c45fSAndroid Build Coastguard Worker 
2141*38e8c45fSAndroid Build Coastguard Worker     if (std::filesystem::exists(DEVICE_INPUT_PATH, errorCode)) {
2142*38e8c45fSAndroid Build Coastguard Worker         result = scanDirLocked(DEVICE_INPUT_PATH);
2143*38e8c45fSAndroid Build Coastguard Worker         if (result < 0) {
2144*38e8c45fSAndroid Build Coastguard Worker             ALOGE("scan dir failed for %s", DEVICE_INPUT_PATH);
2145*38e8c45fSAndroid Build Coastguard Worker         }
2146*38e8c45fSAndroid Build Coastguard Worker     } else {
2147*38e8c45fSAndroid Build Coastguard Worker         if (errorCode) {
2148*38e8c45fSAndroid Build Coastguard Worker             ALOGW("Could not run filesystem::exists() due to error %d : %s.", errorCode.value(),
2149*38e8c45fSAndroid Build Coastguard Worker                   errorCode.message().c_str());
2150*38e8c45fSAndroid Build Coastguard Worker         }
2151*38e8c45fSAndroid Build Coastguard Worker     }
2152*38e8c45fSAndroid Build Coastguard Worker     if (isV4lScanningEnabled()) {
2153*38e8c45fSAndroid Build Coastguard Worker         result = scanVideoDirLocked(DEVICE_PATH);
2154*38e8c45fSAndroid Build Coastguard Worker         if (result != OK) {
2155*38e8c45fSAndroid Build Coastguard Worker             ALOGE("scan video dir failed for %s", DEVICE_PATH);
2156*38e8c45fSAndroid Build Coastguard Worker         }
2157*38e8c45fSAndroid Build Coastguard Worker     }
2158*38e8c45fSAndroid Build Coastguard Worker     if (mDevices.find(ReservedInputDeviceId::VIRTUAL_KEYBOARD_ID) == mDevices.end()) {
2159*38e8c45fSAndroid Build Coastguard Worker         createVirtualKeyboardLocked();
2160*38e8c45fSAndroid Build Coastguard Worker     }
2161*38e8c45fSAndroid Build Coastguard Worker }
2162*38e8c45fSAndroid Build Coastguard Worker 
2163*38e8c45fSAndroid Build Coastguard Worker // ----------------------------------------------------------------------------
2164*38e8c45fSAndroid Build Coastguard Worker 
registerFdForEpoll(int fd)2165*38e8c45fSAndroid Build Coastguard Worker status_t EventHub::registerFdForEpoll(int fd) {
2166*38e8c45fSAndroid Build Coastguard Worker     // TODO(b/121395353) - consider adding EPOLLRDHUP
2167*38e8c45fSAndroid Build Coastguard Worker     struct epoll_event eventItem = {};
2168*38e8c45fSAndroid Build Coastguard Worker     eventItem.events = EPOLLIN | EPOLLWAKEUP;
2169*38e8c45fSAndroid Build Coastguard Worker     eventItem.data.fd = fd;
2170*38e8c45fSAndroid Build Coastguard Worker     if (epoll_ctl(mEpollFd, EPOLL_CTL_ADD, fd, &eventItem)) {
2171*38e8c45fSAndroid Build Coastguard Worker         ALOGE("Could not add fd to epoll instance: %s", strerror(errno));
2172*38e8c45fSAndroid Build Coastguard Worker         return -errno;
2173*38e8c45fSAndroid Build Coastguard Worker     }
2174*38e8c45fSAndroid Build Coastguard Worker     return OK;
2175*38e8c45fSAndroid Build Coastguard Worker }
2176*38e8c45fSAndroid Build Coastguard Worker 
unregisterFdFromEpoll(int fd)2177*38e8c45fSAndroid Build Coastguard Worker status_t EventHub::unregisterFdFromEpoll(int fd) {
2178*38e8c45fSAndroid Build Coastguard Worker     if (epoll_ctl(mEpollFd, EPOLL_CTL_DEL, fd, nullptr)) {
2179*38e8c45fSAndroid Build Coastguard Worker         ALOGW("Could not remove fd from epoll instance: %s", strerror(errno));
2180*38e8c45fSAndroid Build Coastguard Worker         return -errno;
2181*38e8c45fSAndroid Build Coastguard Worker     }
2182*38e8c45fSAndroid Build Coastguard Worker     return OK;
2183*38e8c45fSAndroid Build Coastguard Worker }
2184*38e8c45fSAndroid Build Coastguard Worker 
registerDeviceForEpollLocked(Device & device)2185*38e8c45fSAndroid Build Coastguard Worker status_t EventHub::registerDeviceForEpollLocked(Device& device) {
2186*38e8c45fSAndroid Build Coastguard Worker     status_t result = registerFdForEpoll(device.fd);
2187*38e8c45fSAndroid Build Coastguard Worker     if (result != OK) {
2188*38e8c45fSAndroid Build Coastguard Worker         ALOGE("Could not add input device fd to epoll for device %" PRId32, device.id);
2189*38e8c45fSAndroid Build Coastguard Worker         return result;
2190*38e8c45fSAndroid Build Coastguard Worker     }
2191*38e8c45fSAndroid Build Coastguard Worker     if (device.videoDevice) {
2192*38e8c45fSAndroid Build Coastguard Worker         registerVideoDeviceForEpollLocked(*device.videoDevice);
2193*38e8c45fSAndroid Build Coastguard Worker     }
2194*38e8c45fSAndroid Build Coastguard Worker     return result;
2195*38e8c45fSAndroid Build Coastguard Worker }
2196*38e8c45fSAndroid Build Coastguard Worker 
registerVideoDeviceForEpollLocked(const TouchVideoDevice & videoDevice)2197*38e8c45fSAndroid Build Coastguard Worker void EventHub::registerVideoDeviceForEpollLocked(const TouchVideoDevice& videoDevice) {
2198*38e8c45fSAndroid Build Coastguard Worker     status_t result = registerFdForEpoll(videoDevice.getFd());
2199*38e8c45fSAndroid Build Coastguard Worker     if (result != OK) {
2200*38e8c45fSAndroid Build Coastguard Worker         ALOGE("Could not add video device %s to epoll", videoDevice.getName().c_str());
2201*38e8c45fSAndroid Build Coastguard Worker     }
2202*38e8c45fSAndroid Build Coastguard Worker }
2203*38e8c45fSAndroid Build Coastguard Worker 
unregisterDeviceFromEpollLocked(Device & device)2204*38e8c45fSAndroid Build Coastguard Worker status_t EventHub::unregisterDeviceFromEpollLocked(Device& device) {
2205*38e8c45fSAndroid Build Coastguard Worker     if (device.hasValidFd()) {
2206*38e8c45fSAndroid Build Coastguard Worker         status_t result = unregisterFdFromEpoll(device.fd);
2207*38e8c45fSAndroid Build Coastguard Worker         if (result != OK) {
2208*38e8c45fSAndroid Build Coastguard Worker             ALOGW("Could not remove input device fd from epoll for device %" PRId32, device.id);
2209*38e8c45fSAndroid Build Coastguard Worker             return result;
2210*38e8c45fSAndroid Build Coastguard Worker         }
2211*38e8c45fSAndroid Build Coastguard Worker     }
2212*38e8c45fSAndroid Build Coastguard Worker     if (device.videoDevice) {
2213*38e8c45fSAndroid Build Coastguard Worker         unregisterVideoDeviceFromEpollLocked(*device.videoDevice);
2214*38e8c45fSAndroid Build Coastguard Worker     }
2215*38e8c45fSAndroid Build Coastguard Worker     return OK;
2216*38e8c45fSAndroid Build Coastguard Worker }
2217*38e8c45fSAndroid Build Coastguard Worker 
unregisterVideoDeviceFromEpollLocked(const TouchVideoDevice & videoDevice)2218*38e8c45fSAndroid Build Coastguard Worker void EventHub::unregisterVideoDeviceFromEpollLocked(const TouchVideoDevice& videoDevice) {
2219*38e8c45fSAndroid Build Coastguard Worker     if (videoDevice.hasValidFd()) {
2220*38e8c45fSAndroid Build Coastguard Worker         status_t result = unregisterFdFromEpoll(videoDevice.getFd());
2221*38e8c45fSAndroid Build Coastguard Worker         if (result != OK) {
2222*38e8c45fSAndroid Build Coastguard Worker             ALOGW("Could not remove video device fd from epoll for device: %s",
2223*38e8c45fSAndroid Build Coastguard Worker                   videoDevice.getName().c_str());
2224*38e8c45fSAndroid Build Coastguard Worker         }
2225*38e8c45fSAndroid Build Coastguard Worker     }
2226*38e8c45fSAndroid Build Coastguard Worker }
2227*38e8c45fSAndroid Build Coastguard Worker 
reportDeviceAddedForStatisticsLocked(const InputDeviceIdentifier & identifier,ftl::Flags<InputDeviceClass> classes)2228*38e8c45fSAndroid Build Coastguard Worker void EventHub::reportDeviceAddedForStatisticsLocked(const InputDeviceIdentifier& identifier,
2229*38e8c45fSAndroid Build Coastguard Worker                                                     ftl::Flags<InputDeviceClass> classes) {
2230*38e8c45fSAndroid Build Coastguard Worker     SHA256_CTX ctx;
2231*38e8c45fSAndroid Build Coastguard Worker     SHA256_Init(&ctx);
2232*38e8c45fSAndroid Build Coastguard Worker     SHA256_Update(&ctx, reinterpret_cast<const uint8_t*>(identifier.uniqueId.c_str()),
2233*38e8c45fSAndroid Build Coastguard Worker                   identifier.uniqueId.size());
2234*38e8c45fSAndroid Build Coastguard Worker     std::array<uint8_t, SHA256_DIGEST_LENGTH> digest;
2235*38e8c45fSAndroid Build Coastguard Worker     SHA256_Final(digest.data(), &ctx);
2236*38e8c45fSAndroid Build Coastguard Worker 
2237*38e8c45fSAndroid Build Coastguard Worker     std::string obfuscatedId;
2238*38e8c45fSAndroid Build Coastguard Worker     for (size_t i = 0; i < OBFUSCATED_LENGTH; i++) {
2239*38e8c45fSAndroid Build Coastguard Worker         obfuscatedId += StringPrintf("%02x", digest[i]);
2240*38e8c45fSAndroid Build Coastguard Worker     }
2241*38e8c45fSAndroid Build Coastguard Worker 
2242*38e8c45fSAndroid Build Coastguard Worker     android::util::stats_write(android::util::INPUTDEVICE_REGISTERED, identifier.name.c_str(),
2243*38e8c45fSAndroid Build Coastguard Worker                                identifier.vendor, identifier.product, identifier.version,
2244*38e8c45fSAndroid Build Coastguard Worker                                identifier.bus, obfuscatedId.c_str(), classes.get());
2245*38e8c45fSAndroid Build Coastguard Worker }
2246*38e8c45fSAndroid Build Coastguard Worker 
openDeviceLocked(const std::string & devicePath)2247*38e8c45fSAndroid Build Coastguard Worker void EventHub::openDeviceLocked(const std::string& devicePath) {
2248*38e8c45fSAndroid Build Coastguard Worker     // If an input device happens to register around the time when EventHub's constructor runs, it
2249*38e8c45fSAndroid Build Coastguard Worker     // is possible that the same input event node (for example, /dev/input/event3) will be noticed
2250*38e8c45fSAndroid Build Coastguard Worker     // in both 'inotify' callback and also in the 'scanDirLocked' pass. To prevent duplicate devices
2251*38e8c45fSAndroid Build Coastguard Worker     // from getting registered, ensure that this path is not already covered by an existing device.
2252*38e8c45fSAndroid Build Coastguard Worker     for (const auto& [deviceId, device] : mDevices) {
2253*38e8c45fSAndroid Build Coastguard Worker         if (device->path == devicePath) {
2254*38e8c45fSAndroid Build Coastguard Worker             return; // device was already registered
2255*38e8c45fSAndroid Build Coastguard Worker         }
2256*38e8c45fSAndroid Build Coastguard Worker     }
2257*38e8c45fSAndroid Build Coastguard Worker 
2258*38e8c45fSAndroid Build Coastguard Worker     char buffer[80];
2259*38e8c45fSAndroid Build Coastguard Worker 
2260*38e8c45fSAndroid Build Coastguard Worker     ALOGV("Opening device: %s", devicePath.c_str());
2261*38e8c45fSAndroid Build Coastguard Worker 
2262*38e8c45fSAndroid Build Coastguard Worker     int fd = open(devicePath.c_str(), O_RDWR | O_CLOEXEC | O_NONBLOCK);
2263*38e8c45fSAndroid Build Coastguard Worker     if (fd < 0) {
2264*38e8c45fSAndroid Build Coastguard Worker         ALOGE("could not open %s, %s\n", devicePath.c_str(), strerror(errno));
2265*38e8c45fSAndroid Build Coastguard Worker         return;
2266*38e8c45fSAndroid Build Coastguard Worker     }
2267*38e8c45fSAndroid Build Coastguard Worker 
2268*38e8c45fSAndroid Build Coastguard Worker     InputDeviceIdentifier identifier;
2269*38e8c45fSAndroid Build Coastguard Worker 
2270*38e8c45fSAndroid Build Coastguard Worker     // Get device name.
2271*38e8c45fSAndroid Build Coastguard Worker     if (ioctl(fd, EVIOCGNAME(sizeof(buffer) - 1), &buffer) < 1) {
2272*38e8c45fSAndroid Build Coastguard Worker         ALOGE("Could not get device name for %s: %s", devicePath.c_str(), strerror(errno));
2273*38e8c45fSAndroid Build Coastguard Worker     } else {
2274*38e8c45fSAndroid Build Coastguard Worker         buffer[sizeof(buffer) - 1] = '\0';
2275*38e8c45fSAndroid Build Coastguard Worker         identifier.name = buffer;
2276*38e8c45fSAndroid Build Coastguard Worker     }
2277*38e8c45fSAndroid Build Coastguard Worker 
2278*38e8c45fSAndroid Build Coastguard Worker     // Check to see if the device is on our excluded list
2279*38e8c45fSAndroid Build Coastguard Worker     for (size_t i = 0; i < mExcludedDevices.size(); i++) {
2280*38e8c45fSAndroid Build Coastguard Worker         const std::string& item = mExcludedDevices[i];
2281*38e8c45fSAndroid Build Coastguard Worker         if (identifier.name == item) {
2282*38e8c45fSAndroid Build Coastguard Worker             ALOGI("ignoring event id %s driver %s\n", devicePath.c_str(), item.c_str());
2283*38e8c45fSAndroid Build Coastguard Worker             close(fd);
2284*38e8c45fSAndroid Build Coastguard Worker             return;
2285*38e8c45fSAndroid Build Coastguard Worker         }
2286*38e8c45fSAndroid Build Coastguard Worker     }
2287*38e8c45fSAndroid Build Coastguard Worker 
2288*38e8c45fSAndroid Build Coastguard Worker     // Get device driver version.
2289*38e8c45fSAndroid Build Coastguard Worker     int driverVersion;
2290*38e8c45fSAndroid Build Coastguard Worker     if (ioctl(fd, EVIOCGVERSION, &driverVersion)) {
2291*38e8c45fSAndroid Build Coastguard Worker         ALOGE("could not get driver version for %s, %s\n", devicePath.c_str(), strerror(errno));
2292*38e8c45fSAndroid Build Coastguard Worker         close(fd);
2293*38e8c45fSAndroid Build Coastguard Worker         return;
2294*38e8c45fSAndroid Build Coastguard Worker     }
2295*38e8c45fSAndroid Build Coastguard Worker 
2296*38e8c45fSAndroid Build Coastguard Worker     // Get device identifier.
2297*38e8c45fSAndroid Build Coastguard Worker     struct input_id inputId;
2298*38e8c45fSAndroid Build Coastguard Worker     if (ioctl(fd, EVIOCGID, &inputId)) {
2299*38e8c45fSAndroid Build Coastguard Worker         ALOGE("could not get device input id for %s, %s\n", devicePath.c_str(), strerror(errno));
2300*38e8c45fSAndroid Build Coastguard Worker         close(fd);
2301*38e8c45fSAndroid Build Coastguard Worker         return;
2302*38e8c45fSAndroid Build Coastguard Worker     }
2303*38e8c45fSAndroid Build Coastguard Worker     identifier.bus = inputId.bustype;
2304*38e8c45fSAndroid Build Coastguard Worker     identifier.product = inputId.product;
2305*38e8c45fSAndroid Build Coastguard Worker     identifier.vendor = inputId.vendor;
2306*38e8c45fSAndroid Build Coastguard Worker     identifier.version = inputId.version;
2307*38e8c45fSAndroid Build Coastguard Worker 
2308*38e8c45fSAndroid Build Coastguard Worker     // Get device physical location.
2309*38e8c45fSAndroid Build Coastguard Worker     if (ioctl(fd, EVIOCGPHYS(sizeof(buffer) - 1), &buffer) < 1) {
2310*38e8c45fSAndroid Build Coastguard Worker         // fprintf(stderr, "could not get location for %s, %s\n", devicePath, strerror(errno));
2311*38e8c45fSAndroid Build Coastguard Worker     } else {
2312*38e8c45fSAndroid Build Coastguard Worker         buffer[sizeof(buffer) - 1] = '\0';
2313*38e8c45fSAndroid Build Coastguard Worker         identifier.location = buffer;
2314*38e8c45fSAndroid Build Coastguard Worker     }
2315*38e8c45fSAndroid Build Coastguard Worker 
2316*38e8c45fSAndroid Build Coastguard Worker     // Get device unique id.
2317*38e8c45fSAndroid Build Coastguard Worker     if (ioctl(fd, EVIOCGUNIQ(sizeof(buffer) - 1), &buffer) < 1) {
2318*38e8c45fSAndroid Build Coastguard Worker         // fprintf(stderr, "could not get idstring for %s, %s\n", devicePath, strerror(errno));
2319*38e8c45fSAndroid Build Coastguard Worker     } else {
2320*38e8c45fSAndroid Build Coastguard Worker         buffer[sizeof(buffer) - 1] = '\0';
2321*38e8c45fSAndroid Build Coastguard Worker         identifier.uniqueId = buffer;
2322*38e8c45fSAndroid Build Coastguard Worker     }
2323*38e8c45fSAndroid Build Coastguard Worker 
2324*38e8c45fSAndroid Build Coastguard Worker     // Attempt to get the bluetooth address of an input device from the uniqueId.
2325*38e8c45fSAndroid Build Coastguard Worker     if (identifier.bus == BUS_BLUETOOTH &&
2326*38e8c45fSAndroid Build Coastguard Worker         std::regex_match(identifier.uniqueId,
2327*38e8c45fSAndroid Build Coastguard Worker                          std::regex("^[A-Fa-f0-9]{2}(?::[A-Fa-f0-9]{2}){5}$"))) {
2328*38e8c45fSAndroid Build Coastguard Worker         identifier.bluetoothAddress = identifier.uniqueId;
2329*38e8c45fSAndroid Build Coastguard Worker         // The Bluetooth stack requires alphabetic characters to be uppercase in a valid address.
2330*38e8c45fSAndroid Build Coastguard Worker         for (auto& c : *identifier.bluetoothAddress) {
2331*38e8c45fSAndroid Build Coastguard Worker             c = ::toupper(c);
2332*38e8c45fSAndroid Build Coastguard Worker         }
2333*38e8c45fSAndroid Build Coastguard Worker     }
2334*38e8c45fSAndroid Build Coastguard Worker 
2335*38e8c45fSAndroid Build Coastguard Worker     // Fill in the descriptor.
2336*38e8c45fSAndroid Build Coastguard Worker     assignDescriptorLocked(identifier);
2337*38e8c45fSAndroid Build Coastguard Worker 
2338*38e8c45fSAndroid Build Coastguard Worker     // Allocate device.  (The device object takes ownership of the fd at this point.)
2339*38e8c45fSAndroid Build Coastguard Worker     int32_t deviceId = mNextDeviceId++;
2340*38e8c45fSAndroid Build Coastguard Worker     std::unique_ptr<Device> device =
2341*38e8c45fSAndroid Build Coastguard Worker             std::make_unique<Device>(fd, deviceId, devicePath, identifier,
2342*38e8c45fSAndroid Build Coastguard Worker                                      obtainAssociatedDeviceLocked(devicePath));
2343*38e8c45fSAndroid Build Coastguard Worker 
2344*38e8c45fSAndroid Build Coastguard Worker     ALOGV("add device %d: %s\n", deviceId, devicePath.c_str());
2345*38e8c45fSAndroid Build Coastguard Worker     ALOGV("  bus:        %04x\n"
2346*38e8c45fSAndroid Build Coastguard Worker           "  vendor      %04x\n"
2347*38e8c45fSAndroid Build Coastguard Worker           "  product     %04x\n"
2348*38e8c45fSAndroid Build Coastguard Worker           "  version     %04x\n",
2349*38e8c45fSAndroid Build Coastguard Worker           identifier.bus, identifier.vendor, identifier.product, identifier.version);
2350*38e8c45fSAndroid Build Coastguard Worker     ALOGV("  name:       \"%s\"\n", identifier.name.c_str());
2351*38e8c45fSAndroid Build Coastguard Worker     ALOGV("  location:   \"%s\"\n", identifier.location.c_str());
2352*38e8c45fSAndroid Build Coastguard Worker     ALOGV("  unique id:  \"%s\"\n", identifier.uniqueId.c_str());
2353*38e8c45fSAndroid Build Coastguard Worker     ALOGV("  descriptor: \"%s\"\n", identifier.descriptor.c_str());
2354*38e8c45fSAndroid Build Coastguard Worker     ALOGV("  driver:     v%d.%d.%d\n", driverVersion >> 16, (driverVersion >> 8) & 0xff,
2355*38e8c45fSAndroid Build Coastguard Worker           driverVersion & 0xff);
2356*38e8c45fSAndroid Build Coastguard Worker 
2357*38e8c45fSAndroid Build Coastguard Worker     // Load the configuration file for the device.
2358*38e8c45fSAndroid Build Coastguard Worker     device->loadConfigurationLocked();
2359*38e8c45fSAndroid Build Coastguard Worker 
2360*38e8c45fSAndroid Build Coastguard Worker     // Figure out the kinds of events the device reports.
2361*38e8c45fSAndroid Build Coastguard Worker     device->readDeviceBitMask(EVIOCGBIT(EV_KEY, 0), device->keyBitmask);
2362*38e8c45fSAndroid Build Coastguard Worker     device->readDeviceBitMask(EVIOCGBIT(EV_ABS, 0), device->absBitmask);
2363*38e8c45fSAndroid Build Coastguard Worker     device->readDeviceBitMask(EVIOCGBIT(EV_REL, 0), device->relBitmask);
2364*38e8c45fSAndroid Build Coastguard Worker     device->readDeviceBitMask(EVIOCGBIT(EV_SW, 0), device->swBitmask);
2365*38e8c45fSAndroid Build Coastguard Worker     device->readDeviceBitMask(EVIOCGBIT(EV_LED, 0), device->ledBitmask);
2366*38e8c45fSAndroid Build Coastguard Worker     device->readDeviceBitMask(EVIOCGBIT(EV_FF, 0), device->ffBitmask);
2367*38e8c45fSAndroid Build Coastguard Worker     device->readDeviceBitMask(EVIOCGBIT(EV_MSC, 0), device->mscBitmask);
2368*38e8c45fSAndroid Build Coastguard Worker     device->readDeviceBitMask(EVIOCGPROP(0), device->propBitmask);
2369*38e8c45fSAndroid Build Coastguard Worker 
2370*38e8c45fSAndroid Build Coastguard Worker     // See if this is a device with keys. This could be full keyboard, or other devices like
2371*38e8c45fSAndroid Build Coastguard Worker     // gamepads, joysticks, and styluses with buttons that should generate key presses.
2372*38e8c45fSAndroid Build Coastguard Worker     bool haveKeyboardKeys =
2373*38e8c45fSAndroid Build Coastguard Worker             device->keyBitmask.any(0, BTN_MISC) || device->keyBitmask.any(BTN_WHEEL, KEY_MAX + 1);
2374*38e8c45fSAndroid Build Coastguard Worker     bool haveGamepadButtons = device->keyBitmask.any(BTN_MISC, BTN_MOUSE) ||
2375*38e8c45fSAndroid Build Coastguard Worker             device->keyBitmask.any(BTN_JOYSTICK, BTN_DIGI);
2376*38e8c45fSAndroid Build Coastguard Worker     bool haveStylusButtons = device->keyBitmask.test(BTN_STYLUS) ||
2377*38e8c45fSAndroid Build Coastguard Worker             device->keyBitmask.test(BTN_STYLUS2) || device->keyBitmask.test(BTN_STYLUS3);
2378*38e8c45fSAndroid Build Coastguard Worker     if (haveKeyboardKeys || haveGamepadButtons || haveStylusButtons) {
2379*38e8c45fSAndroid Build Coastguard Worker         device->classes |= InputDeviceClass::KEYBOARD;
2380*38e8c45fSAndroid Build Coastguard Worker     }
2381*38e8c45fSAndroid Build Coastguard Worker 
2382*38e8c45fSAndroid Build Coastguard Worker     // See if this is a cursor device such as a trackball or mouse.
2383*38e8c45fSAndroid Build Coastguard Worker     if (device->keyBitmask.test(BTN_MOUSE) && device->relBitmask.test(REL_X) &&
2384*38e8c45fSAndroid Build Coastguard Worker         device->relBitmask.test(REL_Y)) {
2385*38e8c45fSAndroid Build Coastguard Worker         device->classes |= InputDeviceClass::CURSOR;
2386*38e8c45fSAndroid Build Coastguard Worker     }
2387*38e8c45fSAndroid Build Coastguard Worker 
2388*38e8c45fSAndroid Build Coastguard Worker     // See if the device is specially configured to be of a certain type.
2389*38e8c45fSAndroid Build Coastguard Worker     if (device->configuration) {
2390*38e8c45fSAndroid Build Coastguard Worker         std::string deviceType = device->configuration->getString("device.type").value_or("");
2391*38e8c45fSAndroid Build Coastguard Worker         if (deviceType == "rotaryEncoder") {
2392*38e8c45fSAndroid Build Coastguard Worker             device->classes |= InputDeviceClass::ROTARY_ENCODER;
2393*38e8c45fSAndroid Build Coastguard Worker         } else if (deviceType == "externalStylus") {
2394*38e8c45fSAndroid Build Coastguard Worker             device->classes |= InputDeviceClass::EXTERNAL_STYLUS;
2395*38e8c45fSAndroid Build Coastguard Worker         }
2396*38e8c45fSAndroid Build Coastguard Worker     }
2397*38e8c45fSAndroid Build Coastguard Worker 
2398*38e8c45fSAndroid Build Coastguard Worker     // See if this is a touch pad.
2399*38e8c45fSAndroid Build Coastguard Worker     // Is this a new modern multi-touch driver?
2400*38e8c45fSAndroid Build Coastguard Worker     if (device->absBitmask.test(ABS_MT_POSITION_X) && device->absBitmask.test(ABS_MT_POSITION_Y)) {
2401*38e8c45fSAndroid Build Coastguard Worker         // Some joysticks such as the PS3 controller report axes that conflict
2402*38e8c45fSAndroid Build Coastguard Worker         // with the ABS_MT range.  Try to confirm that the device really is
2403*38e8c45fSAndroid Build Coastguard Worker         // a touch screen.
2404*38e8c45fSAndroid Build Coastguard Worker         if (device->keyBitmask.test(BTN_TOUCH) || !haveGamepadButtons) {
2405*38e8c45fSAndroid Build Coastguard Worker             device->classes |= (InputDeviceClass::TOUCH | InputDeviceClass::TOUCH_MT);
2406*38e8c45fSAndroid Build Coastguard Worker             if (device->propBitmask.test(INPUT_PROP_POINTER) &&
2407*38e8c45fSAndroid Build Coastguard Worker                 !device->keyBitmask.any(BTN_TOOL_PEN, BTN_TOOL_FINGER) && !haveStylusButtons) {
2408*38e8c45fSAndroid Build Coastguard Worker                 device->classes |= InputDeviceClass::TOUCHPAD;
2409*38e8c45fSAndroid Build Coastguard Worker             }
2410*38e8c45fSAndroid Build Coastguard Worker         }
2411*38e8c45fSAndroid Build Coastguard Worker         // Is this an old style single-touch driver?
2412*38e8c45fSAndroid Build Coastguard Worker     } else if (device->keyBitmask.test(BTN_TOUCH) && device->absBitmask.test(ABS_X) &&
2413*38e8c45fSAndroid Build Coastguard Worker                device->absBitmask.test(ABS_Y)) {
2414*38e8c45fSAndroid Build Coastguard Worker         device->classes |= InputDeviceClass::TOUCH;
2415*38e8c45fSAndroid Build Coastguard Worker         // Is this a stylus that reports contact/pressure independently of touch coordinates?
2416*38e8c45fSAndroid Build Coastguard Worker     } else if ((device->absBitmask.test(ABS_PRESSURE) || device->keyBitmask.test(BTN_TOUCH)) &&
2417*38e8c45fSAndroid Build Coastguard Worker                !device->absBitmask.test(ABS_X) && !device->absBitmask.test(ABS_Y)) {
2418*38e8c45fSAndroid Build Coastguard Worker         device->classes |= InputDeviceClass::EXTERNAL_STYLUS;
2419*38e8c45fSAndroid Build Coastguard Worker     }
2420*38e8c45fSAndroid Build Coastguard Worker 
2421*38e8c45fSAndroid Build Coastguard Worker     // See if this device is a joystick.
2422*38e8c45fSAndroid Build Coastguard Worker     // Assumes that joysticks always have gamepad buttons in order to distinguish them
2423*38e8c45fSAndroid Build Coastguard Worker     // from other devices such as accelerometers that also have absolute axes.
2424*38e8c45fSAndroid Build Coastguard Worker     if (haveGamepadButtons) {
2425*38e8c45fSAndroid Build Coastguard Worker         auto assumedClasses = device->classes | InputDeviceClass::JOYSTICK;
2426*38e8c45fSAndroid Build Coastguard Worker         for (int i = 0; i <= ABS_MAX; i++) {
2427*38e8c45fSAndroid Build Coastguard Worker             if (device->absBitmask.test(i) &&
2428*38e8c45fSAndroid Build Coastguard Worker                 (getAbsAxisUsage(i, assumedClasses).test(InputDeviceClass::JOYSTICK))) {
2429*38e8c45fSAndroid Build Coastguard Worker                 device->classes = assumedClasses;
2430*38e8c45fSAndroid Build Coastguard Worker                 break;
2431*38e8c45fSAndroid Build Coastguard Worker             }
2432*38e8c45fSAndroid Build Coastguard Worker         }
2433*38e8c45fSAndroid Build Coastguard Worker     }
2434*38e8c45fSAndroid Build Coastguard Worker 
2435*38e8c45fSAndroid Build Coastguard Worker     // Check whether this device is an accelerometer.
2436*38e8c45fSAndroid Build Coastguard Worker     if (device->propBitmask.test(INPUT_PROP_ACCELEROMETER)) {
2437*38e8c45fSAndroid Build Coastguard Worker         device->classes |= InputDeviceClass::SENSOR;
2438*38e8c45fSAndroid Build Coastguard Worker     }
2439*38e8c45fSAndroid Build Coastguard Worker 
2440*38e8c45fSAndroid Build Coastguard Worker     // Check whether this device has switches.
2441*38e8c45fSAndroid Build Coastguard Worker     for (int i = 0; i <= SW_MAX; i++) {
2442*38e8c45fSAndroid Build Coastguard Worker         if (device->swBitmask.test(i)) {
2443*38e8c45fSAndroid Build Coastguard Worker             device->classes |= InputDeviceClass::SWITCH;
2444*38e8c45fSAndroid Build Coastguard Worker             break;
2445*38e8c45fSAndroid Build Coastguard Worker         }
2446*38e8c45fSAndroid Build Coastguard Worker     }
2447*38e8c45fSAndroid Build Coastguard Worker 
2448*38e8c45fSAndroid Build Coastguard Worker     // Check whether this device supports the vibrator.
2449*38e8c45fSAndroid Build Coastguard Worker     if (device->ffBitmask.test(FF_RUMBLE)) {
2450*38e8c45fSAndroid Build Coastguard Worker         device->classes |= InputDeviceClass::VIBRATOR;
2451*38e8c45fSAndroid Build Coastguard Worker     }
2452*38e8c45fSAndroid Build Coastguard Worker 
2453*38e8c45fSAndroid Build Coastguard Worker     // Configure virtual keys.
2454*38e8c45fSAndroid Build Coastguard Worker     if ((device->classes.test(InputDeviceClass::TOUCH))) {
2455*38e8c45fSAndroid Build Coastguard Worker         // Load the virtual keys for the touch screen, if any.
2456*38e8c45fSAndroid Build Coastguard Worker         // We do this now so that we can make sure to load the keymap if necessary.
2457*38e8c45fSAndroid Build Coastguard Worker         bool success = device->loadVirtualKeyMapLocked();
2458*38e8c45fSAndroid Build Coastguard Worker         if (success) {
2459*38e8c45fSAndroid Build Coastguard Worker             device->classes |= InputDeviceClass::KEYBOARD;
2460*38e8c45fSAndroid Build Coastguard Worker         }
2461*38e8c45fSAndroid Build Coastguard Worker     }
2462*38e8c45fSAndroid Build Coastguard Worker 
2463*38e8c45fSAndroid Build Coastguard Worker     // Load the key map.
2464*38e8c45fSAndroid Build Coastguard Worker     // We need to do this for joysticks too because the key layout may specify axes, and for
2465*38e8c45fSAndroid Build Coastguard Worker     // sensor as well because the key layout may specify the axes to sensor data mapping.
2466*38e8c45fSAndroid Build Coastguard Worker     status_t keyMapStatus = NAME_NOT_FOUND;
2467*38e8c45fSAndroid Build Coastguard Worker     if (device->classes.any(InputDeviceClass::KEYBOARD | InputDeviceClass::JOYSTICK |
2468*38e8c45fSAndroid Build Coastguard Worker                             InputDeviceClass::SENSOR)) {
2469*38e8c45fSAndroid Build Coastguard Worker         // Load the keymap for the device.
2470*38e8c45fSAndroid Build Coastguard Worker         keyMapStatus = device->loadKeyMapLocked();
2471*38e8c45fSAndroid Build Coastguard Worker     }
2472*38e8c45fSAndroid Build Coastguard Worker 
2473*38e8c45fSAndroid Build Coastguard Worker     // Configure the keyboard, gamepad or virtual keyboard.
2474*38e8c45fSAndroid Build Coastguard Worker     if (device->classes.test(InputDeviceClass::KEYBOARD)) {
2475*38e8c45fSAndroid Build Coastguard Worker         // Register the keyboard as a built-in keyboard if it is eligible.
2476*38e8c45fSAndroid Build Coastguard Worker         if (!keyMapStatus && mBuiltInKeyboardId == NO_BUILT_IN_KEYBOARD &&
2477*38e8c45fSAndroid Build Coastguard Worker             isEligibleBuiltInKeyboard(device->identifier, device->configuration.get(),
2478*38e8c45fSAndroid Build Coastguard Worker                                       &device->keyMap)) {
2479*38e8c45fSAndroid Build Coastguard Worker             mBuiltInKeyboardId = device->id;
2480*38e8c45fSAndroid Build Coastguard Worker         }
2481*38e8c45fSAndroid Build Coastguard Worker 
2482*38e8c45fSAndroid Build Coastguard Worker         // 'Q' key support = cheap test of whether this is an alpha-capable kbd
2483*38e8c45fSAndroid Build Coastguard Worker         if (device->hasKeycodeLocked(AKEYCODE_Q)) {
2484*38e8c45fSAndroid Build Coastguard Worker             device->classes |= InputDeviceClass::ALPHAKEY;
2485*38e8c45fSAndroid Build Coastguard Worker         }
2486*38e8c45fSAndroid Build Coastguard Worker 
2487*38e8c45fSAndroid Build Coastguard Worker         // See if this device has a D-pad.
2488*38e8c45fSAndroid Build Coastguard Worker         if (std::all_of(DPAD_REQUIRED_KEYCODES.begin(), DPAD_REQUIRED_KEYCODES.end(),
2489*38e8c45fSAndroid Build Coastguard Worker                         [&](int32_t keycode) { return device->hasKeycodeLocked(keycode); })) {
2490*38e8c45fSAndroid Build Coastguard Worker             device->classes |= InputDeviceClass::DPAD;
2491*38e8c45fSAndroid Build Coastguard Worker         }
2492*38e8c45fSAndroid Build Coastguard Worker 
2493*38e8c45fSAndroid Build Coastguard Worker         // See if this device has a gamepad.
2494*38e8c45fSAndroid Build Coastguard Worker         if (std::any_of(GAMEPAD_KEYCODES.begin(), GAMEPAD_KEYCODES.end(),
2495*38e8c45fSAndroid Build Coastguard Worker                         [&](int32_t keycode) { return device->hasKeycodeLocked(keycode); })) {
2496*38e8c45fSAndroid Build Coastguard Worker             device->classes |= InputDeviceClass::GAMEPAD;
2497*38e8c45fSAndroid Build Coastguard Worker         }
2498*38e8c45fSAndroid Build Coastguard Worker 
2499*38e8c45fSAndroid Build Coastguard Worker         // See if this device has any stylus buttons that we would want to fuse with touch data.
2500*38e8c45fSAndroid Build Coastguard Worker         if (!device->classes.any(InputDeviceClass::TOUCH | InputDeviceClass::TOUCH_MT) &&
2501*38e8c45fSAndroid Build Coastguard Worker             !device->classes.any(InputDeviceClass::ALPHAKEY) &&
2502*38e8c45fSAndroid Build Coastguard Worker             std::any_of(STYLUS_BUTTON_KEYCODES.begin(), STYLUS_BUTTON_KEYCODES.end(),
2503*38e8c45fSAndroid Build Coastguard Worker                         [&](int32_t keycode) { return device->hasKeycodeLocked(keycode); })) {
2504*38e8c45fSAndroid Build Coastguard Worker             device->classes |= InputDeviceClass::EXTERNAL_STYLUS;
2505*38e8c45fSAndroid Build Coastguard Worker         }
2506*38e8c45fSAndroid Build Coastguard Worker     }
2507*38e8c45fSAndroid Build Coastguard Worker 
2508*38e8c45fSAndroid Build Coastguard Worker     // See if the device is a rotary encoder with a single scroll axis and nothing else.
2509*38e8c45fSAndroid Build Coastguard Worker     if (vd_flags::virtual_rotary() && device->classes == ftl::Flags<InputDeviceClass>(0) &&
2510*38e8c45fSAndroid Build Coastguard Worker         device->relBitmask.test(REL_WHEEL) && !device->relBitmask.test(REL_HWHEEL)) {
2511*38e8c45fSAndroid Build Coastguard Worker         device->classes |= InputDeviceClass::ROTARY_ENCODER;
2512*38e8c45fSAndroid Build Coastguard Worker     }
2513*38e8c45fSAndroid Build Coastguard Worker 
2514*38e8c45fSAndroid Build Coastguard Worker     // If the device isn't recognized as something we handle, don't monitor it.
2515*38e8c45fSAndroid Build Coastguard Worker     if (device->classes == ftl::Flags<InputDeviceClass>(0)) {
2516*38e8c45fSAndroid Build Coastguard Worker         ALOGV("Dropping device: id=%d, path='%s', name='%s'", deviceId, devicePath.c_str(),
2517*38e8c45fSAndroid Build Coastguard Worker               device->identifier.name.c_str());
2518*38e8c45fSAndroid Build Coastguard Worker         return;
2519*38e8c45fSAndroid Build Coastguard Worker     }
2520*38e8c45fSAndroid Build Coastguard Worker 
2521*38e8c45fSAndroid Build Coastguard Worker     // Classify InputDeviceClass::BATTERY.
2522*38e8c45fSAndroid Build Coastguard Worker     if (device->associatedDevice && !device->associatedDevice->batteryInfos.empty()) {
2523*38e8c45fSAndroid Build Coastguard Worker         device->classes |= InputDeviceClass::BATTERY;
2524*38e8c45fSAndroid Build Coastguard Worker     }
2525*38e8c45fSAndroid Build Coastguard Worker 
2526*38e8c45fSAndroid Build Coastguard Worker     // Classify InputDeviceClass::LIGHT.
2527*38e8c45fSAndroid Build Coastguard Worker     if (device->associatedDevice && !device->associatedDevice->lightInfos.empty()) {
2528*38e8c45fSAndroid Build Coastguard Worker         device->classes |= InputDeviceClass::LIGHT;
2529*38e8c45fSAndroid Build Coastguard Worker     }
2530*38e8c45fSAndroid Build Coastguard Worker 
2531*38e8c45fSAndroid Build Coastguard Worker     // Determine whether the device has a mic.
2532*38e8c45fSAndroid Build Coastguard Worker     if (device->deviceHasMicLocked()) {
2533*38e8c45fSAndroid Build Coastguard Worker         device->classes |= InputDeviceClass::MIC;
2534*38e8c45fSAndroid Build Coastguard Worker     }
2535*38e8c45fSAndroid Build Coastguard Worker 
2536*38e8c45fSAndroid Build Coastguard Worker     // Determine whether the device is external or internal.
2537*38e8c45fSAndroid Build Coastguard Worker     if (device->isExternalDeviceLocked()) {
2538*38e8c45fSAndroid Build Coastguard Worker         device->classes |= InputDeviceClass::EXTERNAL;
2539*38e8c45fSAndroid Build Coastguard Worker     }
2540*38e8c45fSAndroid Build Coastguard Worker 
2541*38e8c45fSAndroid Build Coastguard Worker     if (device->classes.any(InputDeviceClass::JOYSTICK | InputDeviceClass::DPAD) &&
2542*38e8c45fSAndroid Build Coastguard Worker         device->classes.test(InputDeviceClass::GAMEPAD)) {
2543*38e8c45fSAndroid Build Coastguard Worker         device->controllerNumber = getNextControllerNumberLocked(device->identifier.name);
2544*38e8c45fSAndroid Build Coastguard Worker         device->setLedForControllerLocked();
2545*38e8c45fSAndroid Build Coastguard Worker     }
2546*38e8c45fSAndroid Build Coastguard Worker 
2547*38e8c45fSAndroid Build Coastguard Worker     if (registerDeviceForEpollLocked(*device) != OK) {
2548*38e8c45fSAndroid Build Coastguard Worker         return;
2549*38e8c45fSAndroid Build Coastguard Worker     }
2550*38e8c45fSAndroid Build Coastguard Worker 
2551*38e8c45fSAndroid Build Coastguard Worker     device->configureFd();
2552*38e8c45fSAndroid Build Coastguard Worker 
2553*38e8c45fSAndroid Build Coastguard Worker     ALOGI("New device: id=%d, fd=%d, path='%s', name='%s', classes=%s, "
2554*38e8c45fSAndroid Build Coastguard Worker           "configuration='%s', keyLayout='%s', keyCharacterMap='%s', builtinKeyboard=%s, ",
2555*38e8c45fSAndroid Build Coastguard Worker           deviceId, fd, devicePath.c_str(), device->identifier.name.c_str(),
2556*38e8c45fSAndroid Build Coastguard Worker           device->classes.string().c_str(), device->configurationFile.c_str(),
2557*38e8c45fSAndroid Build Coastguard Worker           device->keyMap.keyLayoutFile.c_str(), device->keyMap.keyCharacterMapFile.c_str(),
2558*38e8c45fSAndroid Build Coastguard Worker           toString(mBuiltInKeyboardId == deviceId));
2559*38e8c45fSAndroid Build Coastguard Worker 
2560*38e8c45fSAndroid Build Coastguard Worker     addDeviceLocked(std::move(device));
2561*38e8c45fSAndroid Build Coastguard Worker }
2562*38e8c45fSAndroid Build Coastguard Worker 
openVideoDeviceLocked(const std::string & devicePath)2563*38e8c45fSAndroid Build Coastguard Worker void EventHub::openVideoDeviceLocked(const std::string& devicePath) {
2564*38e8c45fSAndroid Build Coastguard Worker     std::unique_ptr<TouchVideoDevice> videoDevice = TouchVideoDevice::create(devicePath);
2565*38e8c45fSAndroid Build Coastguard Worker     if (!videoDevice) {
2566*38e8c45fSAndroid Build Coastguard Worker         ALOGE("Could not create touch video device for %s. Ignoring", devicePath.c_str());
2567*38e8c45fSAndroid Build Coastguard Worker         return;
2568*38e8c45fSAndroid Build Coastguard Worker     }
2569*38e8c45fSAndroid Build Coastguard Worker     // Transfer ownership of this video device to a matching input device
2570*38e8c45fSAndroid Build Coastguard Worker     for (const auto& [id, device] : mDevices) {
2571*38e8c45fSAndroid Build Coastguard Worker         if (tryAddVideoDeviceLocked(*device, videoDevice)) {
2572*38e8c45fSAndroid Build Coastguard Worker             return; // 'device' now owns 'videoDevice'
2573*38e8c45fSAndroid Build Coastguard Worker         }
2574*38e8c45fSAndroid Build Coastguard Worker     }
2575*38e8c45fSAndroid Build Coastguard Worker 
2576*38e8c45fSAndroid Build Coastguard Worker     // Couldn't find a matching input device, so just add it to a temporary holding queue.
2577*38e8c45fSAndroid Build Coastguard Worker     // A matching input device may appear later.
2578*38e8c45fSAndroid Build Coastguard Worker     ALOGI("Adding video device %s to list of unattached video devices",
2579*38e8c45fSAndroid Build Coastguard Worker           videoDevice->getName().c_str());
2580*38e8c45fSAndroid Build Coastguard Worker     mUnattachedVideoDevices.push_back(std::move(videoDevice));
2581*38e8c45fSAndroid Build Coastguard Worker }
2582*38e8c45fSAndroid Build Coastguard Worker 
tryAddVideoDeviceLocked(EventHub::Device & device,std::unique_ptr<TouchVideoDevice> & videoDevice)2583*38e8c45fSAndroid Build Coastguard Worker bool EventHub::tryAddVideoDeviceLocked(EventHub::Device& device,
2584*38e8c45fSAndroid Build Coastguard Worker                                        std::unique_ptr<TouchVideoDevice>& videoDevice) {
2585*38e8c45fSAndroid Build Coastguard Worker     if (videoDevice->getName() != device.identifier.name) {
2586*38e8c45fSAndroid Build Coastguard Worker         return false;
2587*38e8c45fSAndroid Build Coastguard Worker     }
2588*38e8c45fSAndroid Build Coastguard Worker     device.videoDevice = std::move(videoDevice);
2589*38e8c45fSAndroid Build Coastguard Worker     if (device.enabled) {
2590*38e8c45fSAndroid Build Coastguard Worker         registerVideoDeviceForEpollLocked(*device.videoDevice);
2591*38e8c45fSAndroid Build Coastguard Worker     }
2592*38e8c45fSAndroid Build Coastguard Worker     return true;
2593*38e8c45fSAndroid Build Coastguard Worker }
2594*38e8c45fSAndroid Build Coastguard Worker 
isDeviceEnabled(int32_t deviceId) const2595*38e8c45fSAndroid Build Coastguard Worker bool EventHub::isDeviceEnabled(int32_t deviceId) const {
2596*38e8c45fSAndroid Build Coastguard Worker     std::scoped_lock _l(mLock);
2597*38e8c45fSAndroid Build Coastguard Worker     Device* device = getDeviceLocked(deviceId);
2598*38e8c45fSAndroid Build Coastguard Worker     if (device == nullptr) {
2599*38e8c45fSAndroid Build Coastguard Worker         ALOGE("Invalid device id=%" PRId32 " provided to %s", deviceId, __func__);
2600*38e8c45fSAndroid Build Coastguard Worker         return false;
2601*38e8c45fSAndroid Build Coastguard Worker     }
2602*38e8c45fSAndroid Build Coastguard Worker     return device->enabled;
2603*38e8c45fSAndroid Build Coastguard Worker }
2604*38e8c45fSAndroid Build Coastguard Worker 
enableDevice(int32_t deviceId)2605*38e8c45fSAndroid Build Coastguard Worker status_t EventHub::enableDevice(int32_t deviceId) {
2606*38e8c45fSAndroid Build Coastguard Worker     std::scoped_lock _l(mLock);
2607*38e8c45fSAndroid Build Coastguard Worker     Device* device = getDeviceLocked(deviceId);
2608*38e8c45fSAndroid Build Coastguard Worker     if (device == nullptr) {
2609*38e8c45fSAndroid Build Coastguard Worker         ALOGE("Invalid device id=%" PRId32 " provided to %s", deviceId, __func__);
2610*38e8c45fSAndroid Build Coastguard Worker         return BAD_VALUE;
2611*38e8c45fSAndroid Build Coastguard Worker     }
2612*38e8c45fSAndroid Build Coastguard Worker     if (device->enabled) {
2613*38e8c45fSAndroid Build Coastguard Worker         ALOGW("Duplicate call to %s, input device %" PRId32 " already enabled", __func__, deviceId);
2614*38e8c45fSAndroid Build Coastguard Worker         return OK;
2615*38e8c45fSAndroid Build Coastguard Worker     }
2616*38e8c45fSAndroid Build Coastguard Worker     status_t result = device->enable();
2617*38e8c45fSAndroid Build Coastguard Worker     if (result != OK) {
2618*38e8c45fSAndroid Build Coastguard Worker         ALOGE("Failed to enable device %" PRId32, deviceId);
2619*38e8c45fSAndroid Build Coastguard Worker         return result;
2620*38e8c45fSAndroid Build Coastguard Worker     }
2621*38e8c45fSAndroid Build Coastguard Worker 
2622*38e8c45fSAndroid Build Coastguard Worker     device->configureFd();
2623*38e8c45fSAndroid Build Coastguard Worker 
2624*38e8c45fSAndroid Build Coastguard Worker     return registerDeviceForEpollLocked(*device);
2625*38e8c45fSAndroid Build Coastguard Worker }
2626*38e8c45fSAndroid Build Coastguard Worker 
disableDevice(int32_t deviceId)2627*38e8c45fSAndroid Build Coastguard Worker status_t EventHub::disableDevice(int32_t deviceId) {
2628*38e8c45fSAndroid Build Coastguard Worker     std::scoped_lock _l(mLock);
2629*38e8c45fSAndroid Build Coastguard Worker     Device* device = getDeviceLocked(deviceId);
2630*38e8c45fSAndroid Build Coastguard Worker     if (device == nullptr) {
2631*38e8c45fSAndroid Build Coastguard Worker         ALOGE("Invalid device id=%" PRId32 " provided to %s", deviceId, __func__);
2632*38e8c45fSAndroid Build Coastguard Worker         return BAD_VALUE;
2633*38e8c45fSAndroid Build Coastguard Worker     }
2634*38e8c45fSAndroid Build Coastguard Worker     if (!device->enabled) {
2635*38e8c45fSAndroid Build Coastguard Worker         ALOGW("Duplicate call to %s, input device already disabled", __func__);
2636*38e8c45fSAndroid Build Coastguard Worker         return OK;
2637*38e8c45fSAndroid Build Coastguard Worker     }
2638*38e8c45fSAndroid Build Coastguard Worker     unregisterDeviceFromEpollLocked(*device);
2639*38e8c45fSAndroid Build Coastguard Worker     return device->disable();
2640*38e8c45fSAndroid Build Coastguard Worker }
2641*38e8c45fSAndroid Build Coastguard Worker 
2642*38e8c45fSAndroid Build Coastguard Worker // TODO(b/274755573): Shift to uevent handling on native side and remove this method
2643*38e8c45fSAndroid Build Coastguard Worker // Currently using Java UEventObserver to trigger this which uses UEvent infrastructure that uses a
2644*38e8c45fSAndroid Build Coastguard Worker // NETLINK socket to observe UEvents. We can create similar infrastructure on Eventhub side to
2645*38e8c45fSAndroid Build Coastguard Worker // directly observe UEvents instead of triggering from Java side.
sysfsNodeChanged(const std::string & sysfsNodePath)2646*38e8c45fSAndroid Build Coastguard Worker void EventHub::sysfsNodeChanged(const std::string& sysfsNodePath) {
2647*38e8c45fSAndroid Build Coastguard Worker     std::scoped_lock _l(mLock);
2648*38e8c45fSAndroid Build Coastguard Worker 
2649*38e8c45fSAndroid Build Coastguard Worker     // Check in opening devices
2650*38e8c45fSAndroid Build Coastguard Worker     for (auto it = mOpeningDevices.begin(); it != mOpeningDevices.end(); it++) {
2651*38e8c45fSAndroid Build Coastguard Worker         std::unique_ptr<Device>& device = *it;
2652*38e8c45fSAndroid Build Coastguard Worker         if (device->associatedDevice &&
2653*38e8c45fSAndroid Build Coastguard Worker             sysfsNodePath.find(device->associatedDevice->sysfsRootPath.string()) !=
2654*38e8c45fSAndroid Build Coastguard Worker                     std::string::npos &&
2655*38e8c45fSAndroid Build Coastguard Worker             device->associatedDevice->isChanged()) {
2656*38e8c45fSAndroid Build Coastguard Worker             it = mOpeningDevices.erase(it);
2657*38e8c45fSAndroid Build Coastguard Worker             openDeviceLocked(device->path);
2658*38e8c45fSAndroid Build Coastguard Worker         }
2659*38e8c45fSAndroid Build Coastguard Worker     }
2660*38e8c45fSAndroid Build Coastguard Worker 
2661*38e8c45fSAndroid Build Coastguard Worker     // Check in already added device
2662*38e8c45fSAndroid Build Coastguard Worker     std::vector<Device*> devicesToReopen;
2663*38e8c45fSAndroid Build Coastguard Worker     for (const auto& [id, device] : mDevices) {
2664*38e8c45fSAndroid Build Coastguard Worker         if (device->associatedDevice &&
2665*38e8c45fSAndroid Build Coastguard Worker             sysfsNodePath.find(device->associatedDevice->sysfsRootPath.string()) !=
2666*38e8c45fSAndroid Build Coastguard Worker                     std::string::npos &&
2667*38e8c45fSAndroid Build Coastguard Worker             device->associatedDevice->isChanged()) {
2668*38e8c45fSAndroid Build Coastguard Worker             devicesToReopen.push_back(device.get());
2669*38e8c45fSAndroid Build Coastguard Worker         }
2670*38e8c45fSAndroid Build Coastguard Worker     }
2671*38e8c45fSAndroid Build Coastguard Worker     for (const auto& device : devicesToReopen) {
2672*38e8c45fSAndroid Build Coastguard Worker         closeDeviceLocked(*device);
2673*38e8c45fSAndroid Build Coastguard Worker         openDeviceLocked(device->path);
2674*38e8c45fSAndroid Build Coastguard Worker     }
2675*38e8c45fSAndroid Build Coastguard Worker     devicesToReopen.clear();
2676*38e8c45fSAndroid Build Coastguard Worker }
2677*38e8c45fSAndroid Build Coastguard Worker 
createVirtualKeyboardLocked()2678*38e8c45fSAndroid Build Coastguard Worker void EventHub::createVirtualKeyboardLocked() {
2679*38e8c45fSAndroid Build Coastguard Worker     InputDeviceIdentifier identifier;
2680*38e8c45fSAndroid Build Coastguard Worker     identifier.name = "Virtual";
2681*38e8c45fSAndroid Build Coastguard Worker     identifier.uniqueId = "<virtual>";
2682*38e8c45fSAndroid Build Coastguard Worker     assignDescriptorLocked(identifier);
2683*38e8c45fSAndroid Build Coastguard Worker 
2684*38e8c45fSAndroid Build Coastguard Worker     std::unique_ptr<Device> device =
2685*38e8c45fSAndroid Build Coastguard Worker             std::make_unique<Device>(-1, ReservedInputDeviceId::VIRTUAL_KEYBOARD_ID, "<virtual>",
2686*38e8c45fSAndroid Build Coastguard Worker                                      identifier, /*associatedDevice=*/nullptr);
2687*38e8c45fSAndroid Build Coastguard Worker     device->classes = InputDeviceClass::KEYBOARD | InputDeviceClass::ALPHAKEY |
2688*38e8c45fSAndroid Build Coastguard Worker             InputDeviceClass::DPAD | InputDeviceClass::VIRTUAL;
2689*38e8c45fSAndroid Build Coastguard Worker     device->loadKeyMapLocked();
2690*38e8c45fSAndroid Build Coastguard Worker     addDeviceLocked(std::move(device));
2691*38e8c45fSAndroid Build Coastguard Worker }
2692*38e8c45fSAndroid Build Coastguard Worker 
addDeviceLocked(std::unique_ptr<Device> device)2693*38e8c45fSAndroid Build Coastguard Worker void EventHub::addDeviceLocked(std::unique_ptr<Device> device) {
2694*38e8c45fSAndroid Build Coastguard Worker     reportDeviceAddedForStatisticsLocked(device->identifier, device->classes);
2695*38e8c45fSAndroid Build Coastguard Worker     mOpeningDevices.push_back(std::move(device));
2696*38e8c45fSAndroid Build Coastguard Worker }
2697*38e8c45fSAndroid Build Coastguard Worker 
getNextControllerNumberLocked(const std::string & name)2698*38e8c45fSAndroid Build Coastguard Worker int32_t EventHub::getNextControllerNumberLocked(const std::string& name) {
2699*38e8c45fSAndroid Build Coastguard Worker     if (mControllerNumbers.isFull()) {
2700*38e8c45fSAndroid Build Coastguard Worker         ALOGI("Maximum number of controllers reached, assigning controller number 0 to device %s",
2701*38e8c45fSAndroid Build Coastguard Worker               name.c_str());
2702*38e8c45fSAndroid Build Coastguard Worker         return 0;
2703*38e8c45fSAndroid Build Coastguard Worker     }
2704*38e8c45fSAndroid Build Coastguard Worker     // Since the controller number 0 is reserved for non-controllers, translate all numbers up by
2705*38e8c45fSAndroid Build Coastguard Worker     // one
2706*38e8c45fSAndroid Build Coastguard Worker     return static_cast<int32_t>(mControllerNumbers.markFirstUnmarkedBit() + 1);
2707*38e8c45fSAndroid Build Coastguard Worker }
2708*38e8c45fSAndroid Build Coastguard Worker 
releaseControllerNumberLocked(int32_t num)2709*38e8c45fSAndroid Build Coastguard Worker void EventHub::releaseControllerNumberLocked(int32_t num) {
2710*38e8c45fSAndroid Build Coastguard Worker     if (num > 0) {
2711*38e8c45fSAndroid Build Coastguard Worker         mControllerNumbers.clearBit(static_cast<uint32_t>(num - 1));
2712*38e8c45fSAndroid Build Coastguard Worker     }
2713*38e8c45fSAndroid Build Coastguard Worker }
2714*38e8c45fSAndroid Build Coastguard Worker 
closeDeviceByPathLocked(const std::string & devicePath)2715*38e8c45fSAndroid Build Coastguard Worker void EventHub::closeDeviceByPathLocked(const std::string& devicePath) {
2716*38e8c45fSAndroid Build Coastguard Worker     Device* device = getDeviceByPathLocked(devicePath);
2717*38e8c45fSAndroid Build Coastguard Worker     if (device != nullptr) {
2718*38e8c45fSAndroid Build Coastguard Worker         closeDeviceLocked(*device);
2719*38e8c45fSAndroid Build Coastguard Worker         return;
2720*38e8c45fSAndroid Build Coastguard Worker     }
2721*38e8c45fSAndroid Build Coastguard Worker     ALOGV("Remove device: %s not found, device may already have been removed.", devicePath.c_str());
2722*38e8c45fSAndroid Build Coastguard Worker }
2723*38e8c45fSAndroid Build Coastguard Worker 
2724*38e8c45fSAndroid Build Coastguard Worker /**
2725*38e8c45fSAndroid Build Coastguard Worker  * Find the video device by filename, and close it.
2726*38e8c45fSAndroid Build Coastguard Worker  * The video device is closed by path during an inotify event, where we don't have the
2727*38e8c45fSAndroid Build Coastguard Worker  * additional context about the video device fd, or the associated input device.
2728*38e8c45fSAndroid Build Coastguard Worker  */
closeVideoDeviceByPathLocked(const std::string & devicePath)2729*38e8c45fSAndroid Build Coastguard Worker void EventHub::closeVideoDeviceByPathLocked(const std::string& devicePath) {
2730*38e8c45fSAndroid Build Coastguard Worker     // A video device may be owned by an existing input device, or it may be stored in
2731*38e8c45fSAndroid Build Coastguard Worker     // the mUnattachedVideoDevices queue. Check both locations.
2732*38e8c45fSAndroid Build Coastguard Worker     for (const auto& [id, device] : mDevices) {
2733*38e8c45fSAndroid Build Coastguard Worker         if (device->videoDevice && device->videoDevice->getPath() == devicePath) {
2734*38e8c45fSAndroid Build Coastguard Worker             unregisterVideoDeviceFromEpollLocked(*device->videoDevice);
2735*38e8c45fSAndroid Build Coastguard Worker             device->videoDevice = nullptr;
2736*38e8c45fSAndroid Build Coastguard Worker             return;
2737*38e8c45fSAndroid Build Coastguard Worker         }
2738*38e8c45fSAndroid Build Coastguard Worker     }
2739*38e8c45fSAndroid Build Coastguard Worker     std::erase_if(mUnattachedVideoDevices,
2740*38e8c45fSAndroid Build Coastguard Worker                   [&devicePath](const std::unique_ptr<TouchVideoDevice>& videoDevice) {
2741*38e8c45fSAndroid Build Coastguard Worker                       return videoDevice->getPath() == devicePath;
2742*38e8c45fSAndroid Build Coastguard Worker                   });
2743*38e8c45fSAndroid Build Coastguard Worker }
2744*38e8c45fSAndroid Build Coastguard Worker 
closeAllDevicesLocked()2745*38e8c45fSAndroid Build Coastguard Worker void EventHub::closeAllDevicesLocked() {
2746*38e8c45fSAndroid Build Coastguard Worker     mUnattachedVideoDevices.clear();
2747*38e8c45fSAndroid Build Coastguard Worker     while (!mDevices.empty()) {
2748*38e8c45fSAndroid Build Coastguard Worker         closeDeviceLocked(*(mDevices.begin()->second));
2749*38e8c45fSAndroid Build Coastguard Worker     }
2750*38e8c45fSAndroid Build Coastguard Worker }
2751*38e8c45fSAndroid Build Coastguard Worker 
closeDeviceLocked(Device & device)2752*38e8c45fSAndroid Build Coastguard Worker void EventHub::closeDeviceLocked(Device& device) {
2753*38e8c45fSAndroid Build Coastguard Worker     ALOGI("Removed device: path=%s name=%s id=%d fd=%d classes=%s", device.path.c_str(),
2754*38e8c45fSAndroid Build Coastguard Worker           device.identifier.name.c_str(), device.id, device.fd, device.classes.string().c_str());
2755*38e8c45fSAndroid Build Coastguard Worker 
2756*38e8c45fSAndroid Build Coastguard Worker     if (device.id == mBuiltInKeyboardId) {
2757*38e8c45fSAndroid Build Coastguard Worker         ALOGW("built-in keyboard device %s (id=%d) is closing! the apps will not like this",
2758*38e8c45fSAndroid Build Coastguard Worker               device.path.c_str(), mBuiltInKeyboardId);
2759*38e8c45fSAndroid Build Coastguard Worker         mBuiltInKeyboardId = NO_BUILT_IN_KEYBOARD;
2760*38e8c45fSAndroid Build Coastguard Worker     }
2761*38e8c45fSAndroid Build Coastguard Worker 
2762*38e8c45fSAndroid Build Coastguard Worker     unregisterDeviceFromEpollLocked(device);
2763*38e8c45fSAndroid Build Coastguard Worker     if (device.videoDevice) {
2764*38e8c45fSAndroid Build Coastguard Worker         // This must be done after the video device is removed from epoll
2765*38e8c45fSAndroid Build Coastguard Worker         mUnattachedVideoDevices.push_back(std::move(device.videoDevice));
2766*38e8c45fSAndroid Build Coastguard Worker     }
2767*38e8c45fSAndroid Build Coastguard Worker 
2768*38e8c45fSAndroid Build Coastguard Worker     releaseControllerNumberLocked(device.controllerNumber);
2769*38e8c45fSAndroid Build Coastguard Worker     device.controllerNumber = 0;
2770*38e8c45fSAndroid Build Coastguard Worker     device.close();
2771*38e8c45fSAndroid Build Coastguard Worker     mClosingDevices.push_back(std::move(mDevices[device.id]));
2772*38e8c45fSAndroid Build Coastguard Worker 
2773*38e8c45fSAndroid Build Coastguard Worker     mDevices.erase(device.id);
2774*38e8c45fSAndroid Build Coastguard Worker }
2775*38e8c45fSAndroid Build Coastguard Worker 
readNotifyLocked()2776*38e8c45fSAndroid Build Coastguard Worker base::Result<void> EventHub::readNotifyLocked() {
2777*38e8c45fSAndroid Build Coastguard Worker     static constexpr auto EVENT_SIZE = static_cast<ssize_t>(sizeof(inotify_event));
2778*38e8c45fSAndroid Build Coastguard Worker     uint8_t eventBuffer[512];
2779*38e8c45fSAndroid Build Coastguard Worker     ssize_t sizeRead;
2780*38e8c45fSAndroid Build Coastguard Worker 
2781*38e8c45fSAndroid Build Coastguard Worker     ALOGV("EventHub::readNotify nfd: %d\n", mINotifyFd);
2782*38e8c45fSAndroid Build Coastguard Worker     do {
2783*38e8c45fSAndroid Build Coastguard Worker         sizeRead = read(mINotifyFd, eventBuffer, sizeof(eventBuffer));
2784*38e8c45fSAndroid Build Coastguard Worker     } while (sizeRead < 0 && errno == EINTR);
2785*38e8c45fSAndroid Build Coastguard Worker 
2786*38e8c45fSAndroid Build Coastguard Worker     if (sizeRead < EVENT_SIZE) return Errorf("could not get event, %s", strerror(errno));
2787*38e8c45fSAndroid Build Coastguard Worker 
2788*38e8c45fSAndroid Build Coastguard Worker     for (ssize_t eventPos = 0; sizeRead >= EVENT_SIZE;) {
2789*38e8c45fSAndroid Build Coastguard Worker         const inotify_event* event;
2790*38e8c45fSAndroid Build Coastguard Worker         event = (const inotify_event*)(eventBuffer + eventPos);
2791*38e8c45fSAndroid Build Coastguard Worker         if (event->len == 0) continue;
2792*38e8c45fSAndroid Build Coastguard Worker 
2793*38e8c45fSAndroid Build Coastguard Worker         handleNotifyEventLocked(*event);
2794*38e8c45fSAndroid Build Coastguard Worker 
2795*38e8c45fSAndroid Build Coastguard Worker         const ssize_t eventSize = EVENT_SIZE + event->len;
2796*38e8c45fSAndroid Build Coastguard Worker         sizeRead -= eventSize;
2797*38e8c45fSAndroid Build Coastguard Worker         eventPos += eventSize;
2798*38e8c45fSAndroid Build Coastguard Worker     }
2799*38e8c45fSAndroid Build Coastguard Worker     return {};
2800*38e8c45fSAndroid Build Coastguard Worker }
2801*38e8c45fSAndroid Build Coastguard Worker 
handleNotifyEventLocked(const inotify_event & event)2802*38e8c45fSAndroid Build Coastguard Worker void EventHub::handleNotifyEventLocked(const inotify_event& event) {
2803*38e8c45fSAndroid Build Coastguard Worker     if (event.wd == mDeviceInputWd) {
2804*38e8c45fSAndroid Build Coastguard Worker         std::string filename = std::string(DEVICE_INPUT_PATH) + "/" + event.name;
2805*38e8c45fSAndroid Build Coastguard Worker         if (event.mask & IN_CREATE) {
2806*38e8c45fSAndroid Build Coastguard Worker             openDeviceLocked(filename);
2807*38e8c45fSAndroid Build Coastguard Worker         } else {
2808*38e8c45fSAndroid Build Coastguard Worker             ALOGI("Removing device '%s' due to inotify event\n", filename.c_str());
2809*38e8c45fSAndroid Build Coastguard Worker             closeDeviceByPathLocked(filename);
2810*38e8c45fSAndroid Build Coastguard Worker         }
2811*38e8c45fSAndroid Build Coastguard Worker     } else if (event.wd == mDeviceWd) {
2812*38e8c45fSAndroid Build Coastguard Worker         if (isV4lTouchNode(event.name)) {
2813*38e8c45fSAndroid Build Coastguard Worker             std::string filename = std::string(DEVICE_PATH) + "/" + event.name;
2814*38e8c45fSAndroid Build Coastguard Worker             if (event.mask & IN_CREATE) {
2815*38e8c45fSAndroid Build Coastguard Worker                 openVideoDeviceLocked(filename);
2816*38e8c45fSAndroid Build Coastguard Worker             } else {
2817*38e8c45fSAndroid Build Coastguard Worker                 ALOGI("Removing video device '%s' due to inotify event", filename.c_str());
2818*38e8c45fSAndroid Build Coastguard Worker                 closeVideoDeviceByPathLocked(filename);
2819*38e8c45fSAndroid Build Coastguard Worker             }
2820*38e8c45fSAndroid Build Coastguard Worker         } else if (strcmp(event.name, "input") == 0 && event.mask & IN_CREATE) {
2821*38e8c45fSAndroid Build Coastguard Worker             addDeviceInputInotify();
2822*38e8c45fSAndroid Build Coastguard Worker         }
2823*38e8c45fSAndroid Build Coastguard Worker     } else {
2824*38e8c45fSAndroid Build Coastguard Worker         LOG_ALWAYS_FATAL("Unexpected inotify event, wd = %i", event.wd);
2825*38e8c45fSAndroid Build Coastguard Worker     }
2826*38e8c45fSAndroid Build Coastguard Worker }
2827*38e8c45fSAndroid Build Coastguard Worker 
scanDirLocked(const std::string & dirname)2828*38e8c45fSAndroid Build Coastguard Worker status_t EventHub::scanDirLocked(const std::string& dirname) {
2829*38e8c45fSAndroid Build Coastguard Worker     for (const auto& entry : std::filesystem::directory_iterator(dirname)) {
2830*38e8c45fSAndroid Build Coastguard Worker         openDeviceLocked(entry.path());
2831*38e8c45fSAndroid Build Coastguard Worker     }
2832*38e8c45fSAndroid Build Coastguard Worker     return 0;
2833*38e8c45fSAndroid Build Coastguard Worker }
2834*38e8c45fSAndroid Build Coastguard Worker 
2835*38e8c45fSAndroid Build Coastguard Worker /**
2836*38e8c45fSAndroid Build Coastguard Worker  * Look for all dirname/v4l-touch* devices, and open them.
2837*38e8c45fSAndroid Build Coastguard Worker  */
scanVideoDirLocked(const std::string & dirname)2838*38e8c45fSAndroid Build Coastguard Worker status_t EventHub::scanVideoDirLocked(const std::string& dirname) {
2839*38e8c45fSAndroid Build Coastguard Worker     for (const auto& entry : std::filesystem::directory_iterator(dirname)) {
2840*38e8c45fSAndroid Build Coastguard Worker         if (isV4lTouchNode(entry.path())) {
2841*38e8c45fSAndroid Build Coastguard Worker             ALOGI("Found touch video device %s", entry.path().c_str());
2842*38e8c45fSAndroid Build Coastguard Worker             openVideoDeviceLocked(entry.path());
2843*38e8c45fSAndroid Build Coastguard Worker         }
2844*38e8c45fSAndroid Build Coastguard Worker     }
2845*38e8c45fSAndroid Build Coastguard Worker     return OK;
2846*38e8c45fSAndroid Build Coastguard Worker }
2847*38e8c45fSAndroid Build Coastguard Worker 
requestReopenDevices()2848*38e8c45fSAndroid Build Coastguard Worker void EventHub::requestReopenDevices() {
2849*38e8c45fSAndroid Build Coastguard Worker     ALOGV("requestReopenDevices() called");
2850*38e8c45fSAndroid Build Coastguard Worker 
2851*38e8c45fSAndroid Build Coastguard Worker     std::scoped_lock _l(mLock);
2852*38e8c45fSAndroid Build Coastguard Worker     mNeedToReopenDevices = true;
2853*38e8c45fSAndroid Build Coastguard Worker }
2854*38e8c45fSAndroid Build Coastguard Worker 
setKernelWakeEnabled(int32_t deviceId,bool enabled)2855*38e8c45fSAndroid Build Coastguard Worker bool EventHub::setKernelWakeEnabled(int32_t deviceId, bool enabled) {
2856*38e8c45fSAndroid Build Coastguard Worker     std::scoped_lock _l(mLock);
2857*38e8c45fSAndroid Build Coastguard Worker     std::string enabledStr = enabled ? "enabled" : "disabled";
2858*38e8c45fSAndroid Build Coastguard Worker     Device* device = getDeviceLocked(deviceId);
2859*38e8c45fSAndroid Build Coastguard Worker     if (device == nullptr) {
2860*38e8c45fSAndroid Build Coastguard Worker         ALOGE("Device Id %d does not exist for setting power wakeup", deviceId);
2861*38e8c45fSAndroid Build Coastguard Worker         return false;
2862*38e8c45fSAndroid Build Coastguard Worker     }
2863*38e8c45fSAndroid Build Coastguard Worker     if (device->associatedDevice == nullptr) {
2864*38e8c45fSAndroid Build Coastguard Worker         return false;
2865*38e8c45fSAndroid Build Coastguard Worker     }
2866*38e8c45fSAndroid Build Coastguard Worker     std::filesystem::path currentPath = device->associatedDevice->sysfsRootPath;
2867*38e8c45fSAndroid Build Coastguard Worker     while (!currentPath.empty() && currentPath != "/") {
2868*38e8c45fSAndroid Build Coastguard Worker         std::string nodePath = currentPath / "power/wakeup";
2869*38e8c45fSAndroid Build Coastguard Worker         if (std::filesystem::exists(nodePath)) {
2870*38e8c45fSAndroid Build Coastguard Worker             if (base::WriteStringToFile(enabledStr, nodePath)) {
2871*38e8c45fSAndroid Build Coastguard Worker                 return true;
2872*38e8c45fSAndroid Build Coastguard Worker 
2873*38e8c45fSAndroid Build Coastguard Worker             }
2874*38e8c45fSAndroid Build Coastguard Worker             // No need to continue searching in parent directories as power/wakeup nodes
2875*38e8c45fSAndroid Build Coastguard Worker             // higher up may control other subdevices.
2876*38e8c45fSAndroid Build Coastguard Worker             ALOGW("Failed to set power/wakeup node at %s", nodePath.c_str());
2877*38e8c45fSAndroid Build Coastguard Worker             return false;
2878*38e8c45fSAndroid Build Coastguard Worker         }
2879*38e8c45fSAndroid Build Coastguard Worker         currentPath = currentPath.parent_path();
2880*38e8c45fSAndroid Build Coastguard Worker     }
2881*38e8c45fSAndroid Build Coastguard Worker     return false;
2882*38e8c45fSAndroid Build Coastguard Worker }
2883*38e8c45fSAndroid Build Coastguard Worker 
dump(std::string & dump) const2884*38e8c45fSAndroid Build Coastguard Worker void EventHub::dump(std::string& dump) const {
2885*38e8c45fSAndroid Build Coastguard Worker     dump += "Event Hub State:\n";
2886*38e8c45fSAndroid Build Coastguard Worker 
2887*38e8c45fSAndroid Build Coastguard Worker     { // acquire lock
2888*38e8c45fSAndroid Build Coastguard Worker         std::scoped_lock _l(mLock);
2889*38e8c45fSAndroid Build Coastguard Worker 
2890*38e8c45fSAndroid Build Coastguard Worker         dump += StringPrintf(INDENT "BuiltInKeyboardId: %d\n", mBuiltInKeyboardId);
2891*38e8c45fSAndroid Build Coastguard Worker 
2892*38e8c45fSAndroid Build Coastguard Worker         dump += INDENT "Devices:\n";
2893*38e8c45fSAndroid Build Coastguard Worker 
2894*38e8c45fSAndroid Build Coastguard Worker         for (const auto& [id, device] : mDevices) {
2895*38e8c45fSAndroid Build Coastguard Worker             if (mBuiltInKeyboardId == device->id) {
2896*38e8c45fSAndroid Build Coastguard Worker                 dump += StringPrintf(INDENT2 "%d: %s (aka device 0 - built-in keyboard)\n",
2897*38e8c45fSAndroid Build Coastguard Worker                                      device->id, device->identifier.name.c_str());
2898*38e8c45fSAndroid Build Coastguard Worker             } else {
2899*38e8c45fSAndroid Build Coastguard Worker                 dump += StringPrintf(INDENT2 "%d: %s\n", device->id,
2900*38e8c45fSAndroid Build Coastguard Worker                                      device->identifier.name.c_str());
2901*38e8c45fSAndroid Build Coastguard Worker             }
2902*38e8c45fSAndroid Build Coastguard Worker             dump += StringPrintf(INDENT3 "Classes: %s\n", device->classes.string().c_str());
2903*38e8c45fSAndroid Build Coastguard Worker             dump += StringPrintf(INDENT3 "Path: %s\n", device->path.c_str());
2904*38e8c45fSAndroid Build Coastguard Worker             dump += StringPrintf(INDENT3 "Enabled: %s\n", toString(device->enabled));
2905*38e8c45fSAndroid Build Coastguard Worker             dump += StringPrintf(INDENT3 "Descriptor: %s\n", device->identifier.descriptor.c_str());
2906*38e8c45fSAndroid Build Coastguard Worker             dump += StringPrintf(INDENT3 "Location: %s\n", device->identifier.location.c_str());
2907*38e8c45fSAndroid Build Coastguard Worker             dump += StringPrintf(INDENT3 "ControllerNumber: %d\n", device->controllerNumber);
2908*38e8c45fSAndroid Build Coastguard Worker             dump += StringPrintf(INDENT3 "UniqueId: %s\n", device->identifier.uniqueId.c_str());
2909*38e8c45fSAndroid Build Coastguard Worker             dump += StringPrintf(INDENT3 "Identifier: bus=0x%04x, vendor=0x%04x, "
2910*38e8c45fSAndroid Build Coastguard Worker                                          "product=0x%04x, version=0x%04x, bluetoothAddress=%s\n",
2911*38e8c45fSAndroid Build Coastguard Worker                                  device->identifier.bus, device->identifier.vendor,
2912*38e8c45fSAndroid Build Coastguard Worker                                  device->identifier.product, device->identifier.version,
2913*38e8c45fSAndroid Build Coastguard Worker                                  toString(device->identifier.bluetoothAddress).c_str());
2914*38e8c45fSAndroid Build Coastguard Worker             dump += StringPrintf(INDENT3 "KeyLayoutFile: %s\n",
2915*38e8c45fSAndroid Build Coastguard Worker                                  device->keyMap.keyLayoutFile.c_str());
2916*38e8c45fSAndroid Build Coastguard Worker             dump += StringPrintf(INDENT3 "KeyCharacterMapFile: %s\n",
2917*38e8c45fSAndroid Build Coastguard Worker                                  device->keyMap.keyCharacterMapFile.c_str());
2918*38e8c45fSAndroid Build Coastguard Worker             if (device->associatedDevice && device->associatedDevice->layoutInfo) {
2919*38e8c45fSAndroid Build Coastguard Worker                 dump += StringPrintf(INDENT3 "LanguageTag: %s\n",
2920*38e8c45fSAndroid Build Coastguard Worker                                      device->associatedDevice->layoutInfo->languageTag.c_str());
2921*38e8c45fSAndroid Build Coastguard Worker                 dump += StringPrintf(INDENT3 "LayoutType: %s\n",
2922*38e8c45fSAndroid Build Coastguard Worker                                      device->associatedDevice->layoutInfo->layoutType.c_str());
2923*38e8c45fSAndroid Build Coastguard Worker             }
2924*38e8c45fSAndroid Build Coastguard Worker             dump += StringPrintf(INDENT3 "ConfigurationFile: %s\n",
2925*38e8c45fSAndroid Build Coastguard Worker                                  device->configurationFile.c_str());
2926*38e8c45fSAndroid Build Coastguard Worker             dump += StringPrintf(INDENT3 "VideoDevice: %s\n",
2927*38e8c45fSAndroid Build Coastguard Worker                                  device->videoDevice ? device->videoDevice->dump().c_str()
2928*38e8c45fSAndroid Build Coastguard Worker                                                      : "<none>");
2929*38e8c45fSAndroid Build Coastguard Worker             dump += StringPrintf(INDENT3 "SysfsDevicePath: %s\n",
2930*38e8c45fSAndroid Build Coastguard Worker                                  device->associatedDevice
2931*38e8c45fSAndroid Build Coastguard Worker                                          ? device->associatedDevice->sysfsRootPath.c_str()
2932*38e8c45fSAndroid Build Coastguard Worker                                          : "<none>");
2933*38e8c45fSAndroid Build Coastguard Worker             if (device->keyBitmask.any(0, KEY_MAX + 1)) {
2934*38e8c45fSAndroid Build Coastguard Worker                 const auto pressedKeys = device->keyState.dumpSetIndices(", ", [](int i) {
2935*38e8c45fSAndroid Build Coastguard Worker                     return InputEventLookup::getLinuxEvdevLabel(EV_KEY, i, 1).code;
2936*38e8c45fSAndroid Build Coastguard Worker                 });
2937*38e8c45fSAndroid Build Coastguard Worker                 dump += StringPrintf(INDENT3 "KeyState (pressed): %s\n", pressedKeys.c_str());
2938*38e8c45fSAndroid Build Coastguard Worker             }
2939*38e8c45fSAndroid Build Coastguard Worker             if (device->swBitmask.any(0, SW_MAX + 1)) {
2940*38e8c45fSAndroid Build Coastguard Worker                 const auto pressedSwitches = device->swState.dumpSetIndices(", ", [](int i) {
2941*38e8c45fSAndroid Build Coastguard Worker                     return InputEventLookup::getLinuxEvdevLabel(EV_SW, i, 1).code;
2942*38e8c45fSAndroid Build Coastguard Worker                 });
2943*38e8c45fSAndroid Build Coastguard Worker                 dump += StringPrintf(INDENT3 "SwState (pressed): %s\n", pressedSwitches.c_str());
2944*38e8c45fSAndroid Build Coastguard Worker             }
2945*38e8c45fSAndroid Build Coastguard Worker             if (!device->absState.empty()) {
2946*38e8c45fSAndroid Build Coastguard Worker                 std::string axisValues;
2947*38e8c45fSAndroid Build Coastguard Worker                 for (const auto& [axis, state] : device->absState) {
2948*38e8c45fSAndroid Build Coastguard Worker                     if (!axisValues.empty()) {
2949*38e8c45fSAndroid Build Coastguard Worker                         axisValues += ", ";
2950*38e8c45fSAndroid Build Coastguard Worker                     }
2951*38e8c45fSAndroid Build Coastguard Worker                     axisValues += StringPrintf("%s=%d",
2952*38e8c45fSAndroid Build Coastguard Worker                                                InputEventLookup::getLinuxEvdevLabel(EV_ABS, axis, 0)
2953*38e8c45fSAndroid Build Coastguard Worker                                                        .code.c_str(),
2954*38e8c45fSAndroid Build Coastguard Worker                                                state.value);
2955*38e8c45fSAndroid Build Coastguard Worker                 }
2956*38e8c45fSAndroid Build Coastguard Worker                 dump += INDENT3 "AbsState: " + axisValues + "\n";
2957*38e8c45fSAndroid Build Coastguard Worker             }
2958*38e8c45fSAndroid Build Coastguard Worker         }
2959*38e8c45fSAndroid Build Coastguard Worker 
2960*38e8c45fSAndroid Build Coastguard Worker         dump += INDENT "Unattached video devices:\n";
2961*38e8c45fSAndroid Build Coastguard Worker         for (const std::unique_ptr<TouchVideoDevice>& videoDevice : mUnattachedVideoDevices) {
2962*38e8c45fSAndroid Build Coastguard Worker             dump += INDENT2 + videoDevice->dump() + "\n";
2963*38e8c45fSAndroid Build Coastguard Worker         }
2964*38e8c45fSAndroid Build Coastguard Worker         if (mUnattachedVideoDevices.empty()) {
2965*38e8c45fSAndroid Build Coastguard Worker             dump += INDENT2 "<none>\n";
2966*38e8c45fSAndroid Build Coastguard Worker         }
2967*38e8c45fSAndroid Build Coastguard Worker     } // release lock
2968*38e8c45fSAndroid Build Coastguard Worker }
2969*38e8c45fSAndroid Build Coastguard Worker 
monitor() const2970*38e8c45fSAndroid Build Coastguard Worker void EventHub::monitor() const {
2971*38e8c45fSAndroid Build Coastguard Worker     // Acquire and release the lock to ensure that the event hub has not deadlocked.
2972*38e8c45fSAndroid Build Coastguard Worker     std::unique_lock<std::mutex> lock(mLock);
2973*38e8c45fSAndroid Build Coastguard Worker }
2974*38e8c45fSAndroid Build Coastguard Worker 
dump() const2975*38e8c45fSAndroid Build Coastguard Worker std::string EventHub::AssociatedDevice::dump() const {
2976*38e8c45fSAndroid Build Coastguard Worker     return StringPrintf("path=%s, numBatteries=%zu, numLight=%zu", sysfsRootPath.c_str(),
2977*38e8c45fSAndroid Build Coastguard Worker                         batteryInfos.size(), lightInfos.size());
2978*38e8c45fSAndroid Build Coastguard Worker }
2979*38e8c45fSAndroid Build Coastguard Worker 
2980*38e8c45fSAndroid Build Coastguard Worker } // namespace android
2981