Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit cb42b471 authored by Prabir Pradhan's avatar Prabir Pradhan
Browse files

Refactor AssociatedDevice initialization in EventHub

Since AssociatedDevice contains information from the sysfs classes of a
device that are loaded once when the device is connected, we change the
AssociatedDevice initialization logic to be more functional and easier
to read.

There should be no behaivor change in this CL.

Bug: 243005009
Test: atest inputflinger_tests
Change-Id: I753fb07af9558c844e0c4eb7b8558b4f78b58004
parent 51894782
Loading
Loading
Loading
Loading
+109 −96
Original line number Diff line number Diff line
@@ -52,6 +52,7 @@

#include <filesystem>
#include <regex>
#include <utility>

#include "EventHub.h"

@@ -193,8 +194,7 @@ static nsecs_t processEventTimestamp(const struct input_event& event) {
}

/**
 * Returns the sysfs root path of the input device
 *
 * Returns the sysfs root path of the input device.
 */
static std::optional<std::filesystem::path> getSysfsRootPath(const char* devicePath) {
    std::error_code errorCode;
@@ -301,6 +301,83 @@ static std::optional<std::array<LightColor, COLOR_NUM>> getColorIndexArray(
    return colors;
}

/**
 * Read information about batteries exposed through the sysfs path.
 */
static std::unordered_map<int32_t /*batteryId*/, RawBatteryInfo> readBatteryConfiguration(
        const std::filesystem::path& sysfsRootPath) {
    std::unordered_map<int32_t, RawBatteryInfo> batteryInfos;
    int32_t nextBatteryId = 0;
    // Check if device has any battery.
    const auto& paths = findSysfsNodes(sysfsRootPath, SysfsClass::POWER_SUPPLY);
    for (const auto& nodePath : paths) {
        RawBatteryInfo info;
        info.id = ++nextBatteryId;
        info.path = nodePath;
        info.name = nodePath.filename();

        // Scan the path for all the files
        // Refer to https://www.kernel.org/doc/Documentation/leds/leds-class.txt
        const auto& files = allFilesInPath(nodePath);
        for (const auto& file : files) {
            const auto it = BATTERY_CLASSES.find(file.filename().string());
            if (it != BATTERY_CLASSES.end()) {
                info.flags |= it->second;
            }
        }
        batteryInfos.insert_or_assign(info.id, info);
        ALOGD("configureBatteryLocked rawBatteryId %d name %s", info.id, info.name.c_str());
    }
    return batteryInfos;
}

/**
 *  Read information about lights exposed through the sysfs path.
 */
static std::unordered_map<int32_t /*lightId*/, RawLightInfo> readLightsConfiguration(
        const std::filesystem::path& sysfsRootPath) {
    std::unordered_map<int32_t, RawLightInfo> lightInfos;
    int32_t nextLightId = 0;
    // Check if device has any lights.
    const auto& paths = findSysfsNodes(sysfsRootPath, SysfsClass::LEDS);
    for (const auto& nodePath : paths) {
        RawLightInfo info;
        info.id = ++nextLightId;
        info.path = nodePath;
        info.name = nodePath.filename();
        info.maxBrightness = std::nullopt;
        size_t nameStart = info.name.rfind(":");
        if (nameStart != std::string::npos) {
            // Trim the name to color name
            info.name = info.name.substr(nameStart + 1);
            // Set InputLightClass flag for colors
            const auto it = LIGHT_CLASSES.find(info.name);
            if (it != LIGHT_CLASSES.end()) {
                info.flags |= it->second;
            }
        }
        // Scan the path for all the files
        // Refer to https://www.kernel.org/doc/Documentation/leds/leds-class.txt
        const auto& files = allFilesInPath(nodePath);
        for (const auto& file : files) {
            const auto it = LIGHT_CLASSES.find(file.filename().string());
            if (it != LIGHT_CLASSES.end()) {
                info.flags |= it->second;
                // If the node has maximum brightness, read it
                if (it->second == InputLightClass::MAX_BRIGHTNESS) {
                    std::string str;
                    if (base::ReadFileToString(file, &str)) {
                        info.maxBrightness = std::stoi(str);
                    }
                }
            }
        }
        lightInfos.insert_or_assign(info.id, info);
        ALOGD("configureLightsLocked rawLightId %d name %s", info.id, info.name.c_str());
    }
    return lightInfos;
}

// --- Global Functions ---

ftl::Flags<InputDeviceClass> getAbsAxisUsage(int32_t axis,
@@ -357,18 +434,18 @@ ftl::Flags<InputDeviceClass> getAbsAxisUsage(int32_t axis,

// --- EventHub::Device ---

EventHub::Device::Device(int fd, int32_t id, const std::string& path,
                         const InputDeviceIdentifier& identifier)
EventHub::Device::Device(int fd, int32_t id, std::string path, InputDeviceIdentifier identifier,
                         std::shared_ptr<const AssociatedDevice> assocDev)
      : fd(fd),
        id(id),
        path(path),
        identifier(identifier),
        path(std::move(path)),
        identifier(std::move(identifier)),
        classes(0),
        configuration(nullptr),
        virtualKeyMap(nullptr),
        ffEffectPlaying(false),
        ffEffectId(-1),
        associatedDevice(nullptr),
        associatedDevice(std::move(assocDev)),
        controllerNumber(0),
        enabled(true),
        isVirtual(fd < 0) {}
@@ -557,75 +634,6 @@ status_t EventHub::Device::mapLed(int32_t led, int32_t* outScanCode) const {
    return NAME_NOT_FOUND;
}

// Check the sysfs path for any input device batteries, returns true if battery found.
bool EventHub::AssociatedDevice::configureBatteryLocked() {
    nextBatteryId = 0;
    // Check if device has any battery.
    const auto& paths = findSysfsNodes(sysfsRootPath, SysfsClass::POWER_SUPPLY);
    for (const auto& nodePath : paths) {
        RawBatteryInfo info;
        info.id = ++nextBatteryId;
        info.path = nodePath;
        info.name = nodePath.filename();

        // Scan the path for all the files
        // Refer to https://www.kernel.org/doc/Documentation/leds/leds-class.txt
        const auto& files = allFilesInPath(nodePath);
        for (const auto& file : files) {
            const auto it = BATTERY_CLASSES.find(file.filename().string());
            if (it != BATTERY_CLASSES.end()) {
                info.flags |= it->second;
            }
        }
        batteryInfos.insert_or_assign(info.id, info);
        ALOGD("configureBatteryLocked rawBatteryId %d name %s", info.id, info.name.c_str());
    }
    return !batteryInfos.empty();
}

// Check the sysfs path for any input device lights, returns true if lights found.
bool EventHub::AssociatedDevice::configureLightsLocked() {
    nextLightId = 0;
    // Check if device has any lights.
    const auto& paths = findSysfsNodes(sysfsRootPath, SysfsClass::LEDS);
    for (const auto& nodePath : paths) {
        RawLightInfo info;
        info.id = ++nextLightId;
        info.path = nodePath;
        info.name = nodePath.filename();
        info.maxBrightness = std::nullopt;
        size_t nameStart = info.name.rfind(":");
        if (nameStart != std::string::npos) {
            // Trim the name to color name
            info.name = info.name.substr(nameStart + 1);
            // Set InputLightClass flag for colors
            const auto it = LIGHT_CLASSES.find(info.name);
            if (it != LIGHT_CLASSES.end()) {
                info.flags |= it->second;
            }
        }
        // Scan the path for all the files
        // Refer to https://www.kernel.org/doc/Documentation/leds/leds-class.txt
        const auto& files = allFilesInPath(nodePath);
        for (const auto& file : files) {
            const auto it = LIGHT_CLASSES.find(file.filename().string());
            if (it != LIGHT_CLASSES.end()) {
                info.flags |= it->second;
                // If the node has maximum brightness, read it
                if (it->second == InputLightClass::MAX_BRIGHTNESS) {
                    std::string str;
                    if (base::ReadFileToString(file, &str)) {
                        info.maxBrightness = std::stoi(str);
                    }
                }
            }
        }
        lightInfos.insert_or_assign(info.id, info);
        ALOGD("configureLightsLocked rawLightId %d name %s", info.id, info.name.c_str());
    }
    return !lightInfos.empty();
}

/**
 * Get the capabilities for the current process.
 * Crashes the system if unable to create / check / destroy the capabilities object.
@@ -1358,6 +1366,27 @@ void EventHub::assignDescriptorLocked(InputDeviceIdentifier& identifier) {
          identifier.descriptor.c_str());
}

std::shared_ptr<const EventHub::AssociatedDevice> EventHub::obtainAssociatedDeviceLocked(
        const std::filesystem::path& devicePath) const {
    const std::optional<std::filesystem::path> sysfsRootPathOpt =
            getSysfsRootPath(devicePath.c_str());
    if (!sysfsRootPathOpt) {
        return nullptr;
    }

    const auto& path = *sysfsRootPathOpt;
    for (const auto& [id, dev] : mDevices) {
        if (dev->associatedDevice && dev->associatedDevice->sysfsRootPath == path) {
            return dev->associatedDevice;
        }
    }

    return std::make_shared<AssociatedDevice>(
            AssociatedDevice{.sysfsRootPath = path,
                             .batteryInfos = readBatteryConfiguration(path),
                             .lightInfos = readLightsConfiguration(path)});
}

void EventHub::vibrate(int32_t deviceId, const VibrationElement& element) {
    std::scoped_lock _l(mLock);
    Device* device = getDeviceLocked(deviceId);
@@ -2024,7 +2053,9 @@ void EventHub::openDeviceLocked(const std::string& devicePath) {

    // Allocate device.  (The device object takes ownership of the fd at this point.)
    int32_t deviceId = mNextDeviceId++;
    std::unique_ptr<Device> device = std::make_unique<Device>(fd, deviceId, devicePath, identifier);
    std::unique_ptr<Device> device =
            std::make_unique<Device>(fd, deviceId, devicePath, identifier,
                                     obtainAssociatedDeviceLocked(devicePath));

    ALOGV("add device %d: %s\n", deviceId, devicePath.c_str());
    ALOGV("  bus:        %04x\n"
@@ -2042,24 +2073,6 @@ void EventHub::openDeviceLocked(const std::string& devicePath) {
    // Load the configuration file for the device.
    device->loadConfigurationLocked();

    // Check the sysfs root path
    const std::optional<std::filesystem::path> sysfsRootPath = getSysfsRootPath(devicePath.c_str());
    if (sysfsRootPath.has_value()) {
        std::shared_ptr<AssociatedDevice> associatedDevice;
        for (const auto& [id, dev] : mDevices) {
            if (dev->associatedDevice && dev->associatedDevice->sysfsRootPath == *sysfsRootPath) {
                associatedDevice = dev->associatedDevice;
            }
        }
        if (!associatedDevice) {
            associatedDevice = std::make_shared<AssociatedDevice>(sysfsRootPath.value());
            associatedDevice->configureBatteryLocked();
            associatedDevice->configureLightsLocked();
        }

        device->associatedDevice = associatedDevice;
    }

    // Figure out the kinds of events the device reports.
    device->readDeviceBitMask(EVIOCGBIT(EV_KEY, 0), device->keyBitmask);
    device->readDeviceBitMask(EVIOCGBIT(EV_ABS, 0), device->absBitmask);
@@ -2337,7 +2350,7 @@ void EventHub::createVirtualKeyboardLocked() {

    std::unique_ptr<Device> device =
            std::make_unique<Device>(-1, ReservedInputDeviceId::VIRTUAL_KEYBOARD_ID, "<virtual>",
                                     identifier);
                                     identifier, nullptr /*associatedDevice*/);
    device->classes = InputDeviceClass::KEYBOARD | InputDeviceClass::ALPHAKEY |
            InputDeviceClass::DPAD | InputDeviceClass::VIRTUAL;
    device->loadKeyMapLocked();
+8 −11
Original line number Diff line number Diff line
@@ -537,18 +537,13 @@ public:
    ~EventHub() override;

private:
    // Holds information about the sysfs device associated with the Device.
    struct AssociatedDevice {
        // The sysfs root path of the misc device.
        std::filesystem::path sysfsRootPath;

        int32_t nextBatteryId;
        int32_t nextLightId;
        std::unordered_map<int32_t, RawBatteryInfo> batteryInfos;
        std::unordered_map<int32_t, RawLightInfo> lightInfos;
        explicit AssociatedDevice(std::filesystem::path sysfsRootPath)
              : sysfsRootPath(sysfsRootPath), nextBatteryId(0), nextLightId(0) {}
        bool configureBatteryLocked();
        bool configureLightsLocked();
        std::unordered_map<int32_t /*batteryId*/, RawBatteryInfo> batteryInfos;
        std::unordered_map<int32_t /*lightId*/, RawLightInfo> lightInfos;
    };

    struct Device {
@@ -582,12 +577,12 @@ private:

        // A shared_ptr of a device associated with the input device.
        // The input devices that have the same sysfs path have the same associated device.
        std::shared_ptr<AssociatedDevice> associatedDevice;
        const std::shared_ptr<const AssociatedDevice> associatedDevice;

        int32_t controllerNumber;

        Device(int fd, int32_t id, const std::string& path,
               const InputDeviceIdentifier& identifier);
        Device(int fd, int32_t id, std::string path, InputDeviceIdentifier identifier,
               std::shared_ptr<const AssociatedDevice> assocDev);
        ~Device();

        void close();
@@ -632,6 +627,8 @@ private:
    void createVirtualKeyboardLocked() REQUIRES(mLock);
    void addDeviceLocked(std::unique_ptr<Device> device) REQUIRES(mLock);
    void assignDescriptorLocked(InputDeviceIdentifier& identifier) REQUIRES(mLock);
    std::shared_ptr<const AssociatedDevice> obtainAssociatedDeviceLocked(
            const std::filesystem::path& devicePath) const REQUIRES(mLock);

    void closeDeviceByPathLocked(const std::string& devicePath) REQUIRES(mLock);
    void closeVideoDeviceByPathLocked(const std::string& devicePath) REQUIRES(mLock);