diff options
| -rw-r--r-- | services/inputflinger/include/InputReaderBase.h | 3 | ||||
| -rw-r--r-- | services/inputflinger/reader/EventHub.cpp | 50 | ||||
| -rw-r--r-- | services/inputflinger/reader/InputReader.cpp | 4 | ||||
| -rw-r--r-- | services/inputflinger/reader/include/EventHub.h | 7 | ||||
| -rw-r--r-- | services/inputflinger/reader/include/InputReader.h | 2 | ||||
| -rw-r--r-- | services/inputflinger/tests/FakeEventHub.cpp | 29 | ||||
| -rw-r--r-- | services/inputflinger/tests/FakeEventHub.h | 4 | ||||
| -rw-r--r-- | services/inputflinger/tests/InputReader_test.cpp | 24 | ||||
| -rw-r--r-- | services/inputflinger/tests/fuzzers/InputReaderFuzzer.cpp | 4 | ||||
| -rw-r--r-- | services/inputflinger/tests/fuzzers/MapperHelpers.h | 1 |
10 files changed, 127 insertions, 1 deletions
diff --git a/services/inputflinger/include/InputReaderBase.h b/services/inputflinger/include/InputReaderBase.h index 841c914d60..1750c64eca 100644 --- a/services/inputflinger/include/InputReaderBase.h +++ b/services/inputflinger/include/InputReaderBase.h @@ -149,6 +149,9 @@ public: /* Get the Bluetooth address of an input device, if known. */ virtual std::optional<std::string> getBluetoothAddress(int32_t deviceId) const = 0; + + /* Sysfs node change reported. Recreate device if required to incorporate the new sysfs nodes */ + virtual void sysfsNodeChanged(const std::string& sysfsNodePath) = 0; }; // --- InputReaderConfiguration --- diff --git a/services/inputflinger/reader/EventHub.cpp b/services/inputflinger/reader/EventHub.cpp index e65f3af107..ee8dde1d32 100644 --- a/services/inputflinger/reader/EventHub.cpp +++ b/services/inputflinger/reader/EventHub.cpp @@ -1531,6 +1531,20 @@ std::shared_ptr<const EventHub::AssociatedDevice> EventHub::obtainAssociatedDevi return associatedDevice; } +bool EventHub::AssociatedDevice::isChanged() const { + std::unordered_map<int32_t, RawBatteryInfo> newBatteryInfos = + readBatteryConfiguration(sysfsRootPath); + std::unordered_map<int32_t, RawLightInfo> newLightInfos = + readLightsConfiguration(sysfsRootPath); + std::optional<RawLayoutInfo> newLayoutInfo = readLayoutConfiguration(sysfsRootPath); + + if (newBatteryInfos == batteryInfos && newLightInfos == lightInfos && + newLayoutInfo == layoutInfo) { + return false; + } + return true; +} + void EventHub::vibrate(int32_t deviceId, const VibrationElement& element) { std::scoped_lock _l(mLock); Device* device = getDeviceLocked(deviceId); @@ -2536,6 +2550,42 @@ status_t EventHub::disableDevice(int32_t deviceId) { return device->disable(); } +// TODO(b/274755573): Shift to uevent handling on native side and remove this method +// Currently using Java UEventObserver to trigger this which uses UEvent infrastructure that uses a +// NETLINK socket to observe UEvents. We can create similar infrastructure on Eventhub side to +// directly observe UEvents instead of triggering from Java side. +void EventHub::sysfsNodeChanged(const std::string& sysfsNodePath) { + std::scoped_lock _l(mLock); + + // Check in opening devices + for (auto it = mOpeningDevices.begin(); it != mOpeningDevices.end(); it++) { + std::unique_ptr<Device>& device = *it; + if (device->associatedDevice && + sysfsNodePath.find(device->associatedDevice->sysfsRootPath.string()) != + std::string::npos && + device->associatedDevice->isChanged()) { + it = mOpeningDevices.erase(it); + openDeviceLocked(device->path); + } + } + + // Check in already added device + std::vector<Device*> devicesToReopen; + for (const auto& [id, device] : mDevices) { + if (device->associatedDevice && + sysfsNodePath.find(device->associatedDevice->sysfsRootPath.string()) != + std::string::npos && + device->associatedDevice->isChanged()) { + devicesToReopen.push_back(device.get()); + } + } + for (const auto& device : devicesToReopen) { + closeDeviceLocked(*device); + openDeviceLocked(device->path); + } + devicesToReopen.clear(); +} + void EventHub::createVirtualKeyboardLocked() { InputDeviceIdentifier identifier; identifier.name = "Virtual"; diff --git a/services/inputflinger/reader/InputReader.cpp b/services/inputflinger/reader/InputReader.cpp index 9080cc1d26..81ac03b7b3 100644 --- a/services/inputflinger/reader/InputReader.cpp +++ b/services/inputflinger/reader/InputReader.cpp @@ -928,6 +928,10 @@ bool InputReader::canDispatchToDisplay(int32_t deviceId, int32_t displayId) { return *associatedDisplayId == displayId; } +void InputReader::sysfsNodeChanged(const std::string& sysfsNodePath) { + mEventHub->sysfsNodeChanged(sysfsNodePath); +} + void InputReader::dump(std::string& dump) { std::scoped_lock _l(mLock); diff --git a/services/inputflinger/reader/include/EventHub.h b/services/inputflinger/reader/include/EventHub.h index 0b15efed12..20612c767c 100644 --- a/services/inputflinger/reader/include/EventHub.h +++ b/services/inputflinger/reader/include/EventHub.h @@ -388,6 +388,10 @@ public: /* Disable an input device. Closes file descriptor to that device. */ virtual status_t disableDevice(int32_t deviceId) = 0; + + /* Sysfs node changed. Reopen the Eventhub device if any new Peripheral like Light, Battery, + * etc. is detected. */ + virtual void sysfsNodeChanged(const std::string& sysfsNodePath) = 0; }; template <std::size_t BITS> @@ -567,6 +571,8 @@ public: status_t disableDevice(int32_t deviceId) override final; + void sysfsNodeChanged(const std::string& sysfsNodePath) override final; + ~EventHub() override; private: @@ -578,6 +584,7 @@ private: std::unordered_map<int32_t /*lightId*/, RawLightInfo> lightInfos; std::optional<RawLayoutInfo> layoutInfo; + bool isChanged() const; bool operator==(const AssociatedDevice&) const = default; bool operator!=(const AssociatedDevice&) const = default; std::string dump() const; diff --git a/services/inputflinger/reader/include/InputReader.h b/services/inputflinger/reader/include/InputReader.h index e9c989a224..120e15070c 100644 --- a/services/inputflinger/reader/include/InputReader.h +++ b/services/inputflinger/reader/include/InputReader.h @@ -117,6 +117,8 @@ public: std::optional<std::string> getBluetoothAddress(int32_t deviceId) const override; + void sysfsNodeChanged(const std::string& sysfsNodePath) override; + protected: // These members are protected so they can be instrumented by test cases. virtual std::shared_ptr<InputDevice> createDeviceLocked(int32_t deviceId, diff --git a/services/inputflinger/tests/FakeEventHub.cpp b/services/inputflinger/tests/FakeEventHub.cpp index ff6d584007..4626f5add7 100644 --- a/services/inputflinger/tests/FakeEventHub.cpp +++ b/services/inputflinger/tests/FakeEventHub.cpp @@ -594,4 +594,33 @@ std::optional<std::unordered_map<LightColor, int32_t>> FakeEventHub::getLightInt return lightIt->second; }; +void FakeEventHub::setSysfsRootPath(int32_t deviceId, std::string sysfsRootPath) const { + Device* device = getDevice(deviceId); + if (device == nullptr) { + return; + } + device->sysfsRootPath = sysfsRootPath; +} + +void FakeEventHub::sysfsNodeChanged(const std::string& sysfsNodePath) { + int32_t foundDeviceId = -1; + Device* foundDevice = nullptr; + for (size_t i = 0; i < mDevices.size(); i++) { + Device* d = mDevices.valueAt(i); + if (sysfsNodePath.find(d->sysfsRootPath) != std::string::npos) { + foundDeviceId = mDevices.keyAt(i); + foundDevice = d; + } + } + if (foundDevice == nullptr) { + return; + } + // If device sysfs changed -> reopen the device + if (!mRawLightInfos.empty() && !foundDevice->classes.test(InputDeviceClass::LIGHT)) { + removeDevice(foundDeviceId); + addDevice(foundDeviceId, foundDevice->identifier.name, + foundDevice->classes | InputDeviceClass::LIGHT, foundDevice->identifier.bus); + } +} + } // namespace android diff --git a/services/inputflinger/tests/FakeEventHub.h b/services/inputflinger/tests/FakeEventHub.h index e0a3f9eee1..8e06940aec 100644 --- a/services/inputflinger/tests/FakeEventHub.h +++ b/services/inputflinger/tests/FakeEventHub.h @@ -64,6 +64,7 @@ class FakeEventHub : public EventHubInterface { std::vector<VirtualKeyDefinition> virtualKeys; bool enabled; std::optional<RawLayoutInfo> layoutInfo; + std::string sysfsRootPath; status_t enable() { enabled = true; @@ -152,6 +153,7 @@ public: void enqueueEvent(nsecs_t when, nsecs_t readTime, int32_t deviceId, int32_t type, int32_t code, int32_t value); void assertQueueIsEmpty(); + void setSysfsRootPath(int32_t deviceId, std::string sysfsRootPath) const; private: Device* getDevice(int32_t deviceId) const; @@ -212,7 +214,7 @@ private: std::optional<int32_t> getLightBrightness(int32_t deviceId, int32_t lightId) const override; std::optional<std::unordered_map<LightColor, int32_t>> getLightIntensities( int32_t deviceId, int32_t lightId) const override; - + void sysfsNodeChanged(const std::string& sysfsNodePath) override; void dump(std::string&) const override {} void monitor() const override {} void requestReopenDevices() override {} diff --git a/services/inputflinger/tests/InputReader_test.cpp b/services/inputflinger/tests/InputReader_test.cpp index 92d5357d8e..3d0fbb4455 100644 --- a/services/inputflinger/tests/InputReader_test.cpp +++ b/services/inputflinger/tests/InputReader_test.cpp @@ -644,6 +644,30 @@ TEST_F(InputReaderTest, PolicyGetInputDevices) { ASSERT_EQ(0U, inputDevices[0].getMotionRanges().size()); } +TEST_F(InputReaderTest, InputDeviceRecreatedOnSysfsNodeChanged) { + ASSERT_NO_FATAL_FAILURE(addDevice(1, "keyboard", InputDeviceClass::KEYBOARD, nullptr)); + mFakeEventHub->setSysfsRootPath(1, "xyz"); + + // Should also have received a notification describing the new input device. + ASSERT_EQ(1U, mFakePolicy->getInputDevices().size()); + InputDeviceInfo inputDevice = mFakePolicy->getInputDevices()[0]; + ASSERT_EQ(0U, inputDevice.getLights().size()); + + RawLightInfo infoMonolight = {.id = 123, + .name = "mono_keyboard_backlight", + .maxBrightness = 255, + .flags = InputLightClass::BRIGHTNESS, + .path = ""}; + mFakeEventHub->addRawLightInfo(/*rawId=*/123, std::move(infoMonolight)); + mReader->sysfsNodeChanged("xyz"); + mReader->loopOnce(); + + // Should also have received a notification describing the new recreated input device. + ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertInputDevicesChanged()); + inputDevice = mFakePolicy->getInputDevices()[0]; + ASSERT_EQ(1U, inputDevice.getLights().size()); +} + TEST_F(InputReaderTest, GetMergedInputDevices) { constexpr int32_t deviceId = END_RESERVED_ID + 1000; constexpr int32_t eventHubIds[2] = {END_RESERVED_ID, END_RESERVED_ID + 1}; diff --git a/services/inputflinger/tests/fuzzers/InputReaderFuzzer.cpp b/services/inputflinger/tests/fuzzers/InputReaderFuzzer.cpp index 20242b1c15..baece3c110 100644 --- a/services/inputflinger/tests/fuzzers/InputReaderFuzzer.cpp +++ b/services/inputflinger/tests/fuzzers/InputReaderFuzzer.cpp @@ -165,6 +165,10 @@ public: return reader->getBluetoothAddress(deviceId); } + void sysfsNodeChanged(const std::string& sysfsNodePath) { + reader->sysfsNodeChanged(sysfsNodePath); + } + private: std::unique_ptr<InputReaderInterface> reader; }; diff --git a/services/inputflinger/tests/fuzzers/MapperHelpers.h b/services/inputflinger/tests/fuzzers/MapperHelpers.h index d9a07b96d5..9f4aa5cd5e 100644 --- a/services/inputflinger/tests/fuzzers/MapperHelpers.h +++ b/services/inputflinger/tests/fuzzers/MapperHelpers.h @@ -225,6 +225,7 @@ public: bool isDeviceEnabled(int32_t deviceId) const override { return mFdp->ConsumeBool(); } status_t enableDevice(int32_t deviceId) override { return mFdp->ConsumeIntegral<status_t>(); } status_t disableDevice(int32_t deviceId) override { return mFdp->ConsumeIntegral<status_t>(); } + void sysfsNodeChanged(const std::string& sysfsNodePath) override {} }; class FuzzPointerController : public PointerControllerInterface { |