Loading include/input/InputDevice.h +4 −0 Original line number Diff line number Diff line Loading @@ -213,6 +213,9 @@ public: inline void setVibrator(bool hasVibrator) { mHasVibrator = hasVibrator; } inline bool hasVibrator() const { return mHasVibrator; } inline void setHasBattery(bool hasBattery) { mHasBattery = hasBattery; } inline bool hasBattery() const { return mHasBattery; } inline void setButtonUnderPad(bool hasButton) { mHasButtonUnderPad = hasButton; } inline bool hasButtonUnderPad() const { return mHasButtonUnderPad; } Loading @@ -239,6 +242,7 @@ private: int32_t mKeyboardType; std::shared_ptr<KeyCharacterMap> mKeyCharacterMap; bool mHasVibrator; bool mHasBattery; bool mHasButtonUnderPad; bool mHasSensor; Loading libs/input/InputDevice.cpp +2 −0 Original line number Diff line number Diff line Loading @@ -166,6 +166,7 @@ InputDeviceInfo::InputDeviceInfo(const InputDeviceInfo& other) mKeyboardType(other.mKeyboardType), mKeyCharacterMap(other.mKeyCharacterMap), mHasVibrator(other.mHasVibrator), mHasBattery(other.mHasBattery), mHasButtonUnderPad(other.mHasButtonUnderPad), mHasSensor(other.mHasSensor), mMotionRanges(other.mMotionRanges), Loading @@ -187,6 +188,7 @@ void InputDeviceInfo::initialize(int32_t id, int32_t generation, int32_t control mSources = 0; mKeyboardType = AINPUT_KEYBOARD_TYPE_NONE; mHasVibrator = false; mHasBattery = false; mHasButtonUnderPad = false; mHasSensor = false; mMotionRanges.clear(); Loading services/inputflinger/include/InputReaderBase.h +4 −0 Original line number Diff line number Diff line Loading @@ -108,6 +108,10 @@ public: virtual bool isVibrating(int32_t deviceId) = 0; virtual std::vector<int32_t> getVibratorIds(int32_t deviceId) = 0; /* Get battery level of a particular input device. */ virtual std::optional<int32_t> getBatteryCapacity(int32_t deviceId) = 0; /* Get battery status of a particular input device. */ virtual std::optional<int32_t> getBatteryStatus(int32_t deviceId) = 0; /* Return true if the device can send input events to the specified display. */ virtual bool canDispatchToDisplay(int32_t deviceId, int32_t displayId) = 0; Loading services/inputflinger/reader/Android.bp +5 −0 Original line number Diff line number Diff line Loading @@ -30,6 +30,7 @@ filegroup { "mapper/accumulator/CursorScrollAccumulator.cpp", "mapper/accumulator/SingleTouchMotionAccumulator.cpp", "mapper/accumulator/TouchButtonAccumulator.cpp", "mapper/BatteryInputMapper.cpp", "mapper/CursorInputMapper.cpp", "mapper/ExternalStylusInputMapper.cpp", "mapper/InputMapper.cpp", Loading Loading @@ -60,7 +61,11 @@ cc_defaults { "libui", "libutils", ], static_libs: [ "libc++fs", ], header_libs: [ "libbatteryservice_headers", "libinputreader_headers", ], } Loading services/inputflinger/reader/EventHub.cpp +149 −0 Original line number Diff line number Diff line Loading @@ -29,11 +29,14 @@ #include <sys/inotify.h> #include <sys/ioctl.h> #include <sys/limits.h> #include <sys/stat.h> #include <sys/sysmacros.h> #include <unistd.h> #define LOG_TAG "EventHub" // #define LOG_NDEBUG 0 #include <android-base/file.h> #include <android-base/stringprintf.h> #include <cutils/properties.h> #include <input/KeyCharacterMap.h> Loading Loading @@ -64,6 +67,23 @@ static const char* VIDEO_DEVICE_PATH = "/dev"; static constexpr int32_t FF_STRONG_MAGNITUDE_CHANNEL_IDX = 0; static constexpr int32_t FF_WEAK_MAGNITUDE_CHANNEL_IDX = 1; // must be kept in sync with definitions in kernel /drivers/power/supply/power_supply_sysfs.c static const std::unordered_map<std::string, int32_t> BATTERY_STATUS = {{"Unknown", BATTERY_STATUS_UNKNOWN}, {"Charging", BATTERY_STATUS_CHARGING}, {"Discharging", BATTERY_STATUS_DISCHARGING}, {"Not charging", BATTERY_STATUS_NOT_CHARGING}, {"Full", BATTERY_STATUS_FULL}}; // Mapping taken from // https://gitlab.freedesktop.org/upower/upower/-/blob/master/src/linux/up-device-supply.c#L484 static const std::unordered_map<std::string, int32_t> BATTERY_LEVEL = {{"Critical", 5}, {"Low", 10}, {"Normal", 55}, {"High", 70}, {"Full", 100}, {"Unknown", 50}}; static inline const char* toString(bool value) { return value ? "true" : "false"; } Loading Loading @@ -127,6 +147,73 @@ static nsecs_t processEventTimestamp(const struct input_event& event) { return inputEventTime; } /** * Returns the sysfs root path of the input device * */ static std::filesystem::path getSysfsRootPath(const char* devicePath) { std::error_code errorCode; // Stat the device path to get the major and minor number of the character file struct stat statbuf; if (stat(devicePath, &statbuf) == -1) { ALOGE("Could not stat device %s due to error: %s.", devicePath, std::strerror(errno)); return std::filesystem::path(); } unsigned int major_num = major(statbuf.st_rdev); unsigned int minor_num = minor(statbuf.st_rdev); // Realpath "/sys/dev/char/{major}:{minor}" to get the sysfs path to the input event auto sysfsPath = std::filesystem::path("/sys/dev/char/"); sysfsPath /= std::to_string(major_num) + ":" + std::to_string(minor_num); sysfsPath = std::filesystem::canonical(sysfsPath, errorCode); // Make sure nothing went wrong in call to canonical() if (errorCode) { ALOGW("Could not run filesystem::canonical() due to error %d : %s.", errorCode.value(), errorCode.message().c_str()); return std::filesystem::path(); } // Continue to go up a directory until we reach a directory named "input" while (sysfsPath != "/" && sysfsPath.filename() != "input") { sysfsPath = sysfsPath.parent_path(); } // Then go up one more and you will be at the sysfs root of the device sysfsPath = sysfsPath.parent_path(); // Make sure we didn't reach root path and that directory actually exists if (sysfsPath == "/" || !std::filesystem::exists(sysfsPath, errorCode)) { if (errorCode) { ALOGW("Could not run filesystem::exists() due to error %d : %s.", errorCode.value(), errorCode.message().c_str()); } // Not found return std::filesystem::path(); } return sysfsPath; } /** * Returns the power supply node in sys fs * */ static std::filesystem::path findPowerSupplyNode(const std::filesystem::path& sysfsRootPath) { for (auto path = sysfsRootPath; path != "/"; path = path.parent_path()) { std::error_code errorCode; auto iter = std::filesystem::directory_iterator(path / "power_supply", errorCode); if (!errorCode && iter != std::filesystem::directory_iterator()) { return iter->path(); } } // Not found return std::filesystem::path(); } // --- Global Functions --- Flags<InputDeviceClass> getAbsAxisUsage(int32_t axis, Flags<InputDeviceClass> deviceClasses) { Loading Loading @@ -976,6 +1063,56 @@ EventHub::Device* EventHub::getDeviceByFdLocked(int fd) const { return nullptr; } std::optional<int32_t> EventHub::getBatteryCapacity(int32_t deviceId) const { std::scoped_lock _l(mLock); Device* device = getDeviceLocked(deviceId); std::string buffer; if (!device || (device->sysfsBatteryPath.empty())) { return std::nullopt; } // Some devices report battery capacity as an integer through the "capacity" file if (base::ReadFileToString(device->sysfsBatteryPath / "capacity", &buffer)) { return std::stoi(buffer); } // Other devices report capacity as an enum value POWER_SUPPLY_CAPACITY_LEVEL_XXX // These values are taken from kernel source code include/linux/power_supply.h if (base::ReadFileToString(device->sysfsBatteryPath / "capacity_level", &buffer)) { const auto it = BATTERY_LEVEL.find(buffer); if (it != BATTERY_LEVEL.end()) { return it->second; } } return std::nullopt; } std::optional<int32_t> EventHub::getBatteryStatus(int32_t deviceId) const { std::scoped_lock _l(mLock); Device* device = getDeviceLocked(deviceId); std::string buffer; if (!device || (device->sysfsBatteryPath.empty())) { return std::nullopt; } if (!base::ReadFileToString(device->sysfsBatteryPath / "status", &buffer)) { ALOGE("Failed to read sysfs battery info: %s", strerror(errno)); return std::nullopt; } // Remove trailing new line buffer.erase(std::remove(buffer.begin(), buffer.end(), '\n'), buffer.end()); const auto it = BATTERY_STATUS.find(buffer); if (it != BATTERY_STATUS.end()) { return it->second; } return std::nullopt; } size_t EventHub::getEvents(int timeoutMillis, RawEvent* buffer, size_t bufferSize) { ALOG_ASSERT(bufferSize >= 1); Loading Loading @@ -1584,6 +1721,18 @@ status_t EventHub::openDeviceLocked(const std::string& devicePath) { return -1; } // Grab the device's sysfs path device->sysfsRootPath = getSysfsRootPath(devicePath.c_str()); if (!device->sysfsRootPath.empty()) { device->sysfsBatteryPath = findPowerSupplyNode(device->sysfsRootPath); // Check if a battery exists if (!device->sysfsBatteryPath.empty()) { device->classes |= InputDeviceClass::BATTERY; } } // Determine whether the device has a mic. if (device->deviceHasMicLocked()) { device->classes |= InputDeviceClass::MIC; Loading Loading
include/input/InputDevice.h +4 −0 Original line number Diff line number Diff line Loading @@ -213,6 +213,9 @@ public: inline void setVibrator(bool hasVibrator) { mHasVibrator = hasVibrator; } inline bool hasVibrator() const { return mHasVibrator; } inline void setHasBattery(bool hasBattery) { mHasBattery = hasBattery; } inline bool hasBattery() const { return mHasBattery; } inline void setButtonUnderPad(bool hasButton) { mHasButtonUnderPad = hasButton; } inline bool hasButtonUnderPad() const { return mHasButtonUnderPad; } Loading @@ -239,6 +242,7 @@ private: int32_t mKeyboardType; std::shared_ptr<KeyCharacterMap> mKeyCharacterMap; bool mHasVibrator; bool mHasBattery; bool mHasButtonUnderPad; bool mHasSensor; Loading
libs/input/InputDevice.cpp +2 −0 Original line number Diff line number Diff line Loading @@ -166,6 +166,7 @@ InputDeviceInfo::InputDeviceInfo(const InputDeviceInfo& other) mKeyboardType(other.mKeyboardType), mKeyCharacterMap(other.mKeyCharacterMap), mHasVibrator(other.mHasVibrator), mHasBattery(other.mHasBattery), mHasButtonUnderPad(other.mHasButtonUnderPad), mHasSensor(other.mHasSensor), mMotionRanges(other.mMotionRanges), Loading @@ -187,6 +188,7 @@ void InputDeviceInfo::initialize(int32_t id, int32_t generation, int32_t control mSources = 0; mKeyboardType = AINPUT_KEYBOARD_TYPE_NONE; mHasVibrator = false; mHasBattery = false; mHasButtonUnderPad = false; mHasSensor = false; mMotionRanges.clear(); Loading
services/inputflinger/include/InputReaderBase.h +4 −0 Original line number Diff line number Diff line Loading @@ -108,6 +108,10 @@ public: virtual bool isVibrating(int32_t deviceId) = 0; virtual std::vector<int32_t> getVibratorIds(int32_t deviceId) = 0; /* Get battery level of a particular input device. */ virtual std::optional<int32_t> getBatteryCapacity(int32_t deviceId) = 0; /* Get battery status of a particular input device. */ virtual std::optional<int32_t> getBatteryStatus(int32_t deviceId) = 0; /* Return true if the device can send input events to the specified display. */ virtual bool canDispatchToDisplay(int32_t deviceId, int32_t displayId) = 0; Loading
services/inputflinger/reader/Android.bp +5 −0 Original line number Diff line number Diff line Loading @@ -30,6 +30,7 @@ filegroup { "mapper/accumulator/CursorScrollAccumulator.cpp", "mapper/accumulator/SingleTouchMotionAccumulator.cpp", "mapper/accumulator/TouchButtonAccumulator.cpp", "mapper/BatteryInputMapper.cpp", "mapper/CursorInputMapper.cpp", "mapper/ExternalStylusInputMapper.cpp", "mapper/InputMapper.cpp", Loading Loading @@ -60,7 +61,11 @@ cc_defaults { "libui", "libutils", ], static_libs: [ "libc++fs", ], header_libs: [ "libbatteryservice_headers", "libinputreader_headers", ], } Loading
services/inputflinger/reader/EventHub.cpp +149 −0 Original line number Diff line number Diff line Loading @@ -29,11 +29,14 @@ #include <sys/inotify.h> #include <sys/ioctl.h> #include <sys/limits.h> #include <sys/stat.h> #include <sys/sysmacros.h> #include <unistd.h> #define LOG_TAG "EventHub" // #define LOG_NDEBUG 0 #include <android-base/file.h> #include <android-base/stringprintf.h> #include <cutils/properties.h> #include <input/KeyCharacterMap.h> Loading Loading @@ -64,6 +67,23 @@ static const char* VIDEO_DEVICE_PATH = "/dev"; static constexpr int32_t FF_STRONG_MAGNITUDE_CHANNEL_IDX = 0; static constexpr int32_t FF_WEAK_MAGNITUDE_CHANNEL_IDX = 1; // must be kept in sync with definitions in kernel /drivers/power/supply/power_supply_sysfs.c static const std::unordered_map<std::string, int32_t> BATTERY_STATUS = {{"Unknown", BATTERY_STATUS_UNKNOWN}, {"Charging", BATTERY_STATUS_CHARGING}, {"Discharging", BATTERY_STATUS_DISCHARGING}, {"Not charging", BATTERY_STATUS_NOT_CHARGING}, {"Full", BATTERY_STATUS_FULL}}; // Mapping taken from // https://gitlab.freedesktop.org/upower/upower/-/blob/master/src/linux/up-device-supply.c#L484 static const std::unordered_map<std::string, int32_t> BATTERY_LEVEL = {{"Critical", 5}, {"Low", 10}, {"Normal", 55}, {"High", 70}, {"Full", 100}, {"Unknown", 50}}; static inline const char* toString(bool value) { return value ? "true" : "false"; } Loading Loading @@ -127,6 +147,73 @@ static nsecs_t processEventTimestamp(const struct input_event& event) { return inputEventTime; } /** * Returns the sysfs root path of the input device * */ static std::filesystem::path getSysfsRootPath(const char* devicePath) { std::error_code errorCode; // Stat the device path to get the major and minor number of the character file struct stat statbuf; if (stat(devicePath, &statbuf) == -1) { ALOGE("Could not stat device %s due to error: %s.", devicePath, std::strerror(errno)); return std::filesystem::path(); } unsigned int major_num = major(statbuf.st_rdev); unsigned int minor_num = minor(statbuf.st_rdev); // Realpath "/sys/dev/char/{major}:{minor}" to get the sysfs path to the input event auto sysfsPath = std::filesystem::path("/sys/dev/char/"); sysfsPath /= std::to_string(major_num) + ":" + std::to_string(minor_num); sysfsPath = std::filesystem::canonical(sysfsPath, errorCode); // Make sure nothing went wrong in call to canonical() if (errorCode) { ALOGW("Could not run filesystem::canonical() due to error %d : %s.", errorCode.value(), errorCode.message().c_str()); return std::filesystem::path(); } // Continue to go up a directory until we reach a directory named "input" while (sysfsPath != "/" && sysfsPath.filename() != "input") { sysfsPath = sysfsPath.parent_path(); } // Then go up one more and you will be at the sysfs root of the device sysfsPath = sysfsPath.parent_path(); // Make sure we didn't reach root path and that directory actually exists if (sysfsPath == "/" || !std::filesystem::exists(sysfsPath, errorCode)) { if (errorCode) { ALOGW("Could not run filesystem::exists() due to error %d : %s.", errorCode.value(), errorCode.message().c_str()); } // Not found return std::filesystem::path(); } return sysfsPath; } /** * Returns the power supply node in sys fs * */ static std::filesystem::path findPowerSupplyNode(const std::filesystem::path& sysfsRootPath) { for (auto path = sysfsRootPath; path != "/"; path = path.parent_path()) { std::error_code errorCode; auto iter = std::filesystem::directory_iterator(path / "power_supply", errorCode); if (!errorCode && iter != std::filesystem::directory_iterator()) { return iter->path(); } } // Not found return std::filesystem::path(); } // --- Global Functions --- Flags<InputDeviceClass> getAbsAxisUsage(int32_t axis, Flags<InputDeviceClass> deviceClasses) { Loading Loading @@ -976,6 +1063,56 @@ EventHub::Device* EventHub::getDeviceByFdLocked(int fd) const { return nullptr; } std::optional<int32_t> EventHub::getBatteryCapacity(int32_t deviceId) const { std::scoped_lock _l(mLock); Device* device = getDeviceLocked(deviceId); std::string buffer; if (!device || (device->sysfsBatteryPath.empty())) { return std::nullopt; } // Some devices report battery capacity as an integer through the "capacity" file if (base::ReadFileToString(device->sysfsBatteryPath / "capacity", &buffer)) { return std::stoi(buffer); } // Other devices report capacity as an enum value POWER_SUPPLY_CAPACITY_LEVEL_XXX // These values are taken from kernel source code include/linux/power_supply.h if (base::ReadFileToString(device->sysfsBatteryPath / "capacity_level", &buffer)) { const auto it = BATTERY_LEVEL.find(buffer); if (it != BATTERY_LEVEL.end()) { return it->second; } } return std::nullopt; } std::optional<int32_t> EventHub::getBatteryStatus(int32_t deviceId) const { std::scoped_lock _l(mLock); Device* device = getDeviceLocked(deviceId); std::string buffer; if (!device || (device->sysfsBatteryPath.empty())) { return std::nullopt; } if (!base::ReadFileToString(device->sysfsBatteryPath / "status", &buffer)) { ALOGE("Failed to read sysfs battery info: %s", strerror(errno)); return std::nullopt; } // Remove trailing new line buffer.erase(std::remove(buffer.begin(), buffer.end(), '\n'), buffer.end()); const auto it = BATTERY_STATUS.find(buffer); if (it != BATTERY_STATUS.end()) { return it->second; } return std::nullopt; } size_t EventHub::getEvents(int timeoutMillis, RawEvent* buffer, size_t bufferSize) { ALOG_ASSERT(bufferSize >= 1); Loading Loading @@ -1584,6 +1721,18 @@ status_t EventHub::openDeviceLocked(const std::string& devicePath) { return -1; } // Grab the device's sysfs path device->sysfsRootPath = getSysfsRootPath(devicePath.c_str()); if (!device->sysfsRootPath.empty()) { device->sysfsBatteryPath = findPowerSupplyNode(device->sysfsRootPath); // Check if a battery exists if (!device->sysfsBatteryPath.empty()) { device->classes |= InputDeviceClass::BATTERY; } } // Determine whether the device has a mic. if (device->deviceHasMicLocked()) { device->classes |= InputDeviceClass::MIC; Loading