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

Commit e2b1e5c7 authored by Chris Ye's avatar Chris Ye
Browse files

Introduce Device Controller to InputReader

Introduce Device Controller to manage non-evdev devices associated with
the input device kernel interface. These devices doesn't interact with
inputflinger with input events which requires a mapper to process the
raw event with assoicated input sources.

Bug: 180342233
Test: atest inputflinger_tests
Change-Id: Ib492bb3de889db180c05367bb6a7e7a2e0d78ce7
parent 6368475d
Loading
Loading
Loading
Loading
+11 −0
Original line number Diff line number Diff line
@@ -177,6 +177,14 @@ struct InputDeviceLightInfo {
    int32_t ordinal;
};

struct InputDeviceBatteryInfo {
    explicit InputDeviceBatteryInfo(std::string name, int32_t id) : name(name), id(id) {}
    // Name string of the battery.
    std::string name;
    // Battery id
    int32_t id;
};

/*
 * Describes the characteristics and capabilities of an input device.
 */
@@ -219,6 +227,7 @@ public:
            float min, float max, float flat, float fuzz, float resolution);
    void addMotionRange(const MotionRange& range);
    void addSensorInfo(const InputDeviceSensorInfo& info);
    void addBatteryInfo(const InputDeviceBatteryInfo& info);
    void addLightInfo(const InputDeviceLightInfo& info);

    inline void setKeyboardType(int32_t keyboardType) { mKeyboardType = keyboardType; }
@@ -276,6 +285,8 @@ private:
    std::unordered_map<InputDeviceSensorType, InputDeviceSensorInfo> mSensors;
    /* Map from light ID to light info */
    std::unordered_map<int32_t, InputDeviceLightInfo> mLights;
    /* Map from battery ID to battery info */
    std::unordered_map<int32_t, InputDeviceBatteryInfo> mBatteries;
};

/* Types of input device configuration files. */
+7 −0
Original line number Diff line number Diff line
@@ -231,6 +231,13 @@ void InputDeviceInfo::addSensorInfo(const InputDeviceSensorInfo& info) {
    mSensors.insert_or_assign(info.type, info);
}

void InputDeviceInfo::addBatteryInfo(const InputDeviceBatteryInfo& info) {
    if (mBatteries.find(info.id) != mBatteries.end()) {
        ALOGW("Battery id %d already exists, will be replaced by new battery added.", info.id);
    }
    mBatteries.insert_or_assign(info.id, info);
}

void InputDeviceInfo::addLightInfo(const InputDeviceLightInfo& info) {
    if (mLights.find(info.id) != mLights.end()) {
        ALOGW("Light id %d already exists, will be replaced by new light added.", info.id);
+2 −2
Original line number Diff line number Diff line
@@ -24,6 +24,7 @@ package {
cc_library_headers {
    name: "libinputreader_headers",
    export_include_dirs: [
        "controller",
        "include",
        "mapper",
        "mapper/accumulator",
@@ -35,17 +36,16 @@ filegroup {
    srcs: [
        "EventHub.cpp",
        "InputDevice.cpp",
        "controller/InputController.cpp",
        "mapper/accumulator/CursorButtonAccumulator.cpp",
        "mapper/accumulator/CursorScrollAccumulator.cpp",
        "mapper/accumulator/SingleTouchMotionAccumulator.cpp",
        "mapper/accumulator/TouchButtonAccumulator.cpp",
        "mapper/BatteryInputMapper.cpp",
        "mapper/CursorInputMapper.cpp",
        "mapper/ExternalStylusInputMapper.cpp",
        "mapper/InputMapper.cpp",
        "mapper/JoystickInputMapper.cpp",
        "mapper/KeyboardInputMapper.cpp",
        "mapper/LightInputMapper.cpp",
        "mapper/MultiTouchInputMapper.cpp",
        "mapper/RotaryEncoderInputMapper.cpp",
        "mapper/SensorInputMapper.cpp",
+167 −86
Original line number Diff line number Diff line
@@ -70,6 +70,20 @@ 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;

// Mapping for input battery class node IDs lookup.
// https://www.kernel.org/doc/Documentation/power/power_supply_class.txt
static const std::unordered_map<std::string, InputBatteryClass> BATTERY_CLASSES =
        {{"capacity", InputBatteryClass::CAPACITY},
         {"capacity_level", InputBatteryClass::CAPACITY_LEVEL},
         {"status", InputBatteryClass::STATUS}};

// Mapping for input battery class node names lookup.
// https://www.kernel.org/doc/Documentation/power/power_supply_class.txt
static const std::unordered_map<InputBatteryClass, std::string> BATTERY_NODES =
        {{InputBatteryClass::CAPACITY, "capacity"},
         {InputBatteryClass::CAPACITY_LEVEL, "capacity_level"},
         {InputBatteryClass::STATUS, "status"}};

// 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},
@@ -349,7 +363,7 @@ EventHub::Device::Device(int fd, int32_t id, const std::string& path,
        virtualKeyMap(nullptr),
        ffEffectPlaying(false),
        ffEffectId(-1),
        nextLightId(0),
        miscDevice(nullptr),
        controllerNumber(0),
        enabled(true),
        isVirtual(fd < 0) {}
@@ -540,32 +554,36 @@ status_t EventHub::Device::mapLed(int32_t led, int32_t* outScanCode) const {
}

// Check the sysfs path for any input device batteries, returns true if battery found.
bool EventHub::Device::configureBatteryLocked() {
    if (!sysfsRootPath.has_value()) {
        return false;
bool EventHub::MiscDevice::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;
            }
    // Check if device has any batteries.
    std::vector<std::filesystem::path> batteryPaths =
            findSysfsNodes(sysfsRootPath.value(), SysfsClass::POWER_SUPPLY);
    // We only support single battery for an input device, if multiple batteries exist only the
    // first one is supported.
    if (batteryPaths.empty()) {
        // Set path to be empty
        sysfsBatteryPath = std::nullopt;
        return false;
        }
    // If a battery exists
    sysfsBatteryPath = batteryPaths[0];
    return true;
        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::Device::configureLightsLocked() {
    if (!sysfsRootPath.has_value()) {
        return false;
    }
bool EventHub::MiscDevice::configureLightsLocked() {
    nextLightId = 0;
    // Check if device has any lights.
    const auto& paths = findSysfsNodes(sysfsRootPath.value(), SysfsClass::LEDS);
    const auto& paths = findSysfsNodes(sysfsRootPath, SysfsClass::LEDS);
    for (const auto& nodePath : paths) {
        RawLightInfo info;
        info.id = ++nextLightId;
@@ -599,6 +617,7 @@ bool EventHub::Device::configureLightsLocked() {
            }
        }
        lightInfos.insert_or_assign(info.id, info);
        ALOGD("configureLightsLocked rawLightId %d name %s", info.id, info.name.c_str());
    }
    return !lightInfos.empty();
}
@@ -963,42 +982,92 @@ base::Result<std::pair<InputDeviceSensorType, int32_t>> EventHub::mapSensor(int3
    return Errorf("Device not found or device has no key layout.");
}

const std::vector<int32_t> EventHub::getRawLightIds(int32_t deviceId) {
// Gets the battery info map from battery ID to RawBatteryInfo of the miscellaneous device
// associated with the device ID. Returns an empty map if no miscellaneous device found.
const std::unordered_map<int32_t, RawBatteryInfo>& EventHub::getBatteryInfoLocked(
        int32_t deviceId) const {
    static const std::unordered_map<int32_t, RawBatteryInfo> EMPTY_BATTERY_INFO = {};
    Device* device = getDeviceLocked(deviceId);
    if (device == nullptr) {
        return EMPTY_BATTERY_INFO;
    }
    auto it = mMiscDevices.find(device->identifier.descriptor);
    if (it == mMiscDevices.end()) {
        return EMPTY_BATTERY_INFO;
    }
    return it->second->batteryInfos;
}

const std::vector<int32_t> EventHub::getRawBatteryIds(int32_t deviceId) {
    std::scoped_lock _l(mLock);
    std::vector<int32_t> batteryIds;

    for (const auto [id, info] : getBatteryInfoLocked(deviceId)) {
        batteryIds.push_back(id);
    }

    return batteryIds;
}

std::optional<RawBatteryInfo> EventHub::getRawBatteryInfo(int32_t deviceId, int32_t batteryId) {
    std::scoped_lock _l(mLock);

    const auto infos = getBatteryInfoLocked(deviceId);

    auto it = infos.find(batteryId);
    if (it != infos.end()) {
        return it->second;
    }

    return std::nullopt;
}

// Gets the light info map from light ID to RawLightInfo of the miscellaneous device associated
// with the deivice ID. Returns an empty map if no miscellaneous device found.
const std::unordered_map<int32_t, RawLightInfo>& EventHub::getLightInfoLocked(
        int32_t deviceId) const {
    static const std::unordered_map<int32_t, RawLightInfo> EMPTY_LIGHT_INFO = {};
    Device* device = getDeviceLocked(deviceId);
    if (device == nullptr) {
        return EMPTY_LIGHT_INFO;
    }
    auto it = mMiscDevices.find(device->identifier.descriptor);
    if (it == mMiscDevices.end()) {
        return EMPTY_LIGHT_INFO;
    }
    return it->second->lightInfos;
}

const std::vector<int32_t> EventHub::getRawLightIds(int32_t deviceId) {
    std::scoped_lock _l(mLock);
    std::vector<int32_t> lightIds;

    if (device != nullptr) {
        for (const auto [id, info] : device->lightInfos) {
    for (const auto [id, info] : getLightInfoLocked(deviceId)) {
        lightIds.push_back(id);
    }
    }

    return lightIds;
}

std::optional<RawLightInfo> EventHub::getRawLightInfo(int32_t deviceId, int32_t lightId) {
    std::scoped_lock _l(mLock);
    Device* device = getDeviceLocked(deviceId);

    if (device != nullptr) {
        auto it = device->lightInfos.find(lightId);
        if (it != device->lightInfos.end()) {
    const auto infos = getLightInfoLocked(deviceId);

    auto it = infos.find(lightId);
    if (it != infos.end()) {
        return it->second;
    }
    }

    return std::nullopt;
}

std::optional<int32_t> EventHub::getLightBrightness(int32_t deviceId, int32_t lightId) {
    std::scoped_lock _l(mLock);

    Device* device = getDeviceLocked(deviceId);
    if (device == nullptr) {
        return std::nullopt;
    }

    auto it = device->lightInfos.find(lightId);
    if (it == device->lightInfos.end()) {
    const auto infos = getLightInfoLocked(deviceId);
    auto it = infos.find(lightId);
    if (it == infos.end()) {
        return std::nullopt;
    }
    std::string buffer;
@@ -1013,13 +1082,9 @@ std::optional<std::unordered_map<LightColor, int32_t>> EventHub::getLightIntensi
        int32_t deviceId, int32_t lightId) {
    std::scoped_lock _l(mLock);

    Device* device = getDeviceLocked(deviceId);
    if (device == nullptr) {
        return std::nullopt;
    }

    auto lightIt = device->lightInfos.find(lightId);
    if (lightIt == device->lightInfos.end()) {
    const auto infos = getLightInfoLocked(deviceId);
    auto lightIt = infos.find(lightId);
    if (lightIt == infos.end()) {
        return std::nullopt;
    }

@@ -1056,14 +1121,10 @@ std::optional<std::unordered_map<LightColor, int32_t>> EventHub::getLightIntensi
void EventHub::setLightBrightness(int32_t deviceId, int32_t lightId, int32_t brightness) {
    std::scoped_lock _l(mLock);

    Device* device = getDeviceLocked(deviceId);
    if (device == nullptr) {
        ALOGE("Device Id %d does not exist", deviceId);
        return;
    }
    auto lightIt = device->lightInfos.find(lightId);
    if (lightIt == device->lightInfos.end()) {
        ALOGE("Light Id %d does not exist.", lightId);
    const auto infos = getLightInfoLocked(deviceId);
    auto lightIt = infos.find(lightId);
    if (lightIt == infos.end()) {
        ALOGE("%s lightId %d not found ", __func__, lightId);
        return;
    }

@@ -1078,13 +1139,9 @@ void EventHub::setLightIntensities(int32_t deviceId, int32_t lightId,
                                   std::unordered_map<LightColor, int32_t> intensities) {
    std::scoped_lock _l(mLock);

    Device* device = getDeviceLocked(deviceId);
    if (device == nullptr) {
        ALOGE("Device Id %d does not exist", deviceId);
        return;
    }
    auto lightIt = device->lightInfos.find(lightId);
    if (lightIt == device->lightInfos.end()) {
    const auto infos = getLightInfoLocked(deviceId);
    auto lightIt = infos.find(lightId);
    if (lightIt == infos.end()) {
        ALOGE("Light Id %d does not exist.", lightId);
        return;
    }
@@ -1352,51 +1409,56 @@ EventHub::Device* EventHub::getDeviceByFdLocked(int fd) const {
    return nullptr;
}

std::optional<int32_t> EventHub::getBatteryCapacity(int32_t deviceId) const {
std::optional<int32_t> EventHub::getBatteryCapacity(int32_t deviceId, int32_t batteryId) const {
    std::scoped_lock _l(mLock);
    Device* device = getDeviceLocked(deviceId);
    std::string buffer;

    if (device == nullptr || !device->sysfsBatteryPath.has_value()) {
    const auto infos = getBatteryInfoLocked(deviceId);
    auto it = infos.find(batteryId);
    if (it == infos.end()) {
        return std::nullopt;
    }
    std::string buffer;

    // Some devices report battery capacity as an integer through the "capacity" file
    if (base::ReadFileToString(device->sysfsBatteryPath.value() / "capacity", &buffer)) {
    if (base::ReadFileToString(it->second.path / BATTERY_NODES.at(InputBatteryClass::CAPACITY),
                               &buffer)) {
        return std::stoi(base::Trim(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.value() / "capacity_level", &buffer)) {
    if (base::ReadFileToString(it->second.path /
                                       BATTERY_NODES.at(InputBatteryClass::CAPACITY_LEVEL),
                               &buffer)) {
        // Remove any white space such as trailing new line
        const auto it = BATTERY_LEVEL.find(base::Trim(buffer));
        if (it != BATTERY_LEVEL.end()) {
            return it->second;
        const auto levelIt = BATTERY_LEVEL.find(base::Trim(buffer));
        if (levelIt != BATTERY_LEVEL.end()) {
            return levelIt->second;
        }
    }

    return std::nullopt;
}

std::optional<int32_t> EventHub::getBatteryStatus(int32_t deviceId) const {
std::optional<int32_t> EventHub::getBatteryStatus(int32_t deviceId, int32_t batteryId) const {
    std::scoped_lock _l(mLock);
    Device* device = getDeviceLocked(deviceId);
    std::string buffer;

    if (device == nullptr || !device->sysfsBatteryPath.has_value()) {
    const auto infos = getBatteryInfoLocked(deviceId);
    auto it = infos.find(batteryId);
    if (it == infos.end()) {
        return std::nullopt;
    }
    std::string buffer;

    if (!base::ReadFileToString(device->sysfsBatteryPath.value() / "status", &buffer)) {
    if (!base::ReadFileToString(it->second.path / BATTERY_NODES.at(InputBatteryClass::STATUS),
                                &buffer)) {
        ALOGE("Failed to read sysfs battery info: %s", strerror(errno));
        return std::nullopt;
    }

    // Remove white space like trailing new line
    const auto it = BATTERY_STATUS.find(base::Trim(buffer));

    if (it != BATTERY_STATUS.end()) {
        return it->second;
    const auto statusIt = BATTERY_STATUS.find(base::Trim(buffer));
    if (statusIt != BATTERY_STATUS.end()) {
        return statusIt->second;
    }

    return std::nullopt;
@@ -1879,11 +1941,24 @@ void EventHub::openDeviceLocked(const std::string& devicePath) {
    // Load the configuration file for the device.
    device->loadConfigurationLocked();

    // Grab the device's sysfs path
    device->sysfsRootPath = getSysfsRootPath(devicePath.c_str());
    // find related components
    bool hasBattery = device->configureBatteryLocked();
    bool hasLights = device->configureLightsLocked();
    bool hasBattery = false;
    bool hasLights = false;
    // Check the sysfs root path
    std::optional<std::filesystem::path> sysfsRootPath = getSysfsRootPath(devicePath.c_str());
    if (sysfsRootPath.has_value()) {
        std::shared_ptr<MiscDevice> miscDevice;
        auto it = mMiscDevices.find(device->identifier.descriptor);
        if (it == mMiscDevices.end()) {
            miscDevice = std::make_shared<MiscDevice>(sysfsRootPath.value());
        } else {
            miscDevice = it->second;
        }
        hasBattery = miscDevice->configureBatteryLocked();
        hasLights = miscDevice->configureLightsLocked();

        device->miscDevice = miscDevice;
        mMiscDevices.insert_or_assign(device->identifier.descriptor, std::move(miscDevice));
    }

    // Figure out the kinds of events the device reports.
    device->readDeviceBitMask(EVIOCGBIT(EV_KEY, 0), device->keyBitmask);
@@ -2254,6 +2329,12 @@ void EventHub::closeDeviceLocked(Device& device) {
    mClosingDevices.push_back(std::move(mDevices[device.id]));

    mDevices.erase(device.id);
    // If all devices with the descriptor have been removed then the miscellaneous device should
    // be removed too.
    std::string descriptor = device.identifier.descriptor;
    if (getDeviceByDescriptorLocked(descriptor) == nullptr) {
        mMiscDevices.erase(descriptor);
    }
}

status_t EventHub::readNotifyLocked() {
+20 −35
Original line number Diff line number Diff line
@@ -21,13 +21,12 @@
#include <input/Flags.h>
#include <algorithm>

#include "BatteryInputMapper.h"
#include "CursorInputMapper.h"
#include "ExternalStylusInputMapper.h"
#include "InputController.h"
#include "InputReaderContext.h"
#include "JoystickInputMapper.h"
#include "KeyboardInputMapper.h"
#include "LightInputMapper.h"
#include "MultiTouchInputMapper.h"
#include "RotaryEncoderInputMapper.h"
#include "SensorInputMapper.h"
@@ -131,6 +130,9 @@ void InputDevice::dump(std::string& dump, const std::string& eventHubDevStr) {
    }

    for_each_mapper([&dump](InputMapper& mapper) { mapper.dump(dump); });
    if (mController) {
        mController->dump(dump);
    }
}

void InputDevice::addEventHubDevice(int32_t eventHubId, bool populateMappers) {
@@ -162,22 +164,10 @@ void InputDevice::addEventHubDevice(int32_t eventHubId, bool populateMappers) {
        mappers.push_back(std::make_unique<VibratorInputMapper>(*contextPtr));
    }

    // Battery-like devices. Only one battery mapper for each EventHub device.
    if (classes.test(InputDeviceClass::BATTERY)) {
        InputDeviceInfo deviceInfo;
        getDeviceInfo(&deviceInfo);
        if (!deviceInfo.hasBattery()) {
            mappers.push_back(std::make_unique<BatteryInputMapper>(*contextPtr));
        }
    }

    // Light-containing devices. Only one light mapper for each EventHub device.
    if (classes.test(InputDeviceClass::LIGHT)) {
        InputDeviceInfo deviceInfo;
        getDeviceInfo(&deviceInfo);
        if (deviceInfo.getLightIds().empty()) {
            mappers.push_back(std::make_unique<LightInputMapper>(*contextPtr));
        }
    // Battery-like devices or light-containing devices.
    // InputController will be created with associated EventHub device.
    if (classes.test(InputDeviceClass::BATTERY) || classes.test(InputDeviceClass::LIGHT)) {
        mController = std::make_unique<InputController>(*contextPtr);
    }

    // Keyboard-like devices.
@@ -409,6 +399,10 @@ void InputDevice::getDeviceInfo(InputDeviceInfo* outDeviceInfo) {
                              mHasMic);
    for_each_mapper(
            [outDeviceInfo](InputMapper& mapper) { mapper.populateDeviceInfo(outDeviceInfo); });

    if (mController) {
        mController->populateDeviceInfo(outDeviceInfo);
    }
}

int32_t InputDevice::getKeyCodeState(uint32_t sourceMask, int32_t keyCode) {
@@ -510,39 +504,30 @@ void InputDevice::cancelTouch(nsecs_t when, nsecs_t readTime) {
    for_each_mapper([when, readTime](InputMapper& mapper) { mapper.cancelTouch(when, readTime); });
}

// TODO b/180733860 support multiple battery in API and remove this.
constexpr int32_t DEFAULT_BATTERY_ID = 1;
std::optional<int32_t> InputDevice::getBatteryCapacity() {
    return first_in_mappers<int32_t>(
            [](InputMapper& mapper) { return mapper.getBatteryCapacity(); });
    return mController ? mController->getBatteryCapacity(DEFAULT_BATTERY_ID) : std::nullopt;
}

std::optional<int32_t> InputDevice::getBatteryStatus() {
    return first_in_mappers<int32_t>([](InputMapper& mapper) { return mapper.getBatteryStatus(); });
    return mController ? mController->getBatteryStatus(DEFAULT_BATTERY_ID) : std::nullopt;
}

bool InputDevice::setLightColor(int32_t lightId, int32_t color) {
    bool success = true;
    for_each_mapper([&success, lightId, color](InputMapper& mapper) {
        success &= mapper.setLightColor(lightId, color);
    });
    return success;
    return mController ? mController->setLightColor(lightId, color) : false;
}

bool InputDevice::setLightPlayerId(int32_t lightId, int32_t playerId) {
    bool success = true;
    for_each_mapper([&success, lightId, playerId](InputMapper& mapper) {
        success &= mapper.setLightPlayerId(lightId, playerId);
    });
    return success;
    return mController ? mController->setLightPlayerId(lightId, playerId) : false;
}

std::optional<int32_t> InputDevice::getLightColor(int32_t lightId) {
    return first_in_mappers<int32_t>(
            [lightId](InputMapper& mapper) { return mapper.getLightColor(lightId); });
    return mController ? mController->getLightColor(lightId) : std::nullopt;
}

std::optional<int32_t> InputDevice::getLightPlayerId(int32_t lightId) {
    return first_in_mappers<int32_t>(
            [lightId](InputMapper& mapper) { return mapper.getLightPlayerId(lightId); });
    return mController ? mController->getLightPlayerId(lightId) : std::nullopt;
}

int32_t InputDevice::getMetaState() {
Loading