summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--libs/input/input_flags.aconfig7
-rw-r--r--services/inputflinger/include/InputReaderBase.h10
-rw-r--r--services/inputflinger/reader/EventHub.cpp29
-rw-r--r--services/inputflinger/reader/InputDevice.cpp8
-rw-r--r--services/inputflinger/reader/InputReader.cpp10
-rw-r--r--services/inputflinger/reader/include/EventHub.h9
-rw-r--r--services/inputflinger/reader/include/InputDevice.h5
-rw-r--r--services/inputflinger/reader/include/InputReader.h2
-rw-r--r--services/inputflinger/tests/FakeEventHub.cpp21
-rw-r--r--services/inputflinger/tests/FakeEventHub.h4
-rw-r--r--services/inputflinger/tests/InputReader_test.cpp14
-rw-r--r--services/inputflinger/tests/InterfaceMocks.h1
-rw-r--r--services/inputflinger/tests/fuzzers/InputReaderFuzzer.cpp4
-rw-r--r--services/inputflinger/tests/fuzzers/MapperHelpers.h3
14 files changed, 127 insertions, 0 deletions
diff --git a/libs/input/input_flags.aconfig b/libs/input/input_flags.aconfig
index 701fb43c1f..e93c04df6d 100644
--- a/libs/input/input_flags.aconfig
+++ b/libs/input/input_flags.aconfig
@@ -214,3 +214,10 @@ flag {
description: "Enable telemetry for rotary input"
bug: "370353565"
}
+
+flag {
+ name: "set_input_device_kernel_wake"
+ namespace: "input"
+ description: "Set input device's power/wakeup sysfs node"
+ bug: "372812925"
+}
diff --git a/services/inputflinger/include/InputReaderBase.h b/services/inputflinger/include/InputReaderBase.h
index 756a29b754..6093c91e34 100644
--- a/services/inputflinger/include/InputReaderBase.h
+++ b/services/inputflinger/include/InputReaderBase.h
@@ -426,6 +426,16 @@ public:
/* Notifies that mouse cursor faded due to typing. */
virtual void notifyMouseCursorFadedOnTyping() = 0;
+
+ /* Set whether the given input device can wake up the kernel from sleep
+ * when it generates input events. By default, usually only internal (built-in)
+ * input devices can wake the kernel from sleep. For an external input device
+ * that supports remote wakeup to be able to wake the kernel, this must be called
+ * after each time the device is connected/added.
+ *
+ * Returns true if setting power wakeup was successful.
+ */
+ virtual bool setKernelWakeEnabled(int32_t deviceId, bool enabled) = 0;
};
// --- TouchAffineTransformation ---
diff --git a/services/inputflinger/reader/EventHub.cpp b/services/inputflinger/reader/EventHub.cpp
index f8cd9733b0..8dec9e5f40 100644
--- a/services/inputflinger/reader/EventHub.cpp
+++ b/services/inputflinger/reader/EventHub.cpp
@@ -2848,6 +2848,35 @@ void EventHub::requestReopenDevices() {
mNeedToReopenDevices = true;
}
+bool EventHub::setKernelWakeEnabled(int32_t deviceId, bool enabled) {
+ std::scoped_lock _l(mLock);
+ std::string enabledStr = enabled ? "enabled" : "disabled";
+ Device* device = getDeviceLocked(deviceId);
+ if (device == nullptr) {
+ ALOGE("Device Id %d does not exist for setting power wakeup", deviceId);
+ return false;
+ }
+ if (device->associatedDevice == nullptr) {
+ return false;
+ }
+ std::filesystem::path currentPath = device->associatedDevice->sysfsRootPath;
+ while (!currentPath.empty() && currentPath != "/") {
+ std::string nodePath = currentPath / "power/wakeup";
+ if (std::filesystem::exists(nodePath)) {
+ if (base::WriteStringToFile(enabledStr, nodePath)) {
+ return true;
+
+ }
+ // No need to continue searching in parent directories as power/wakeup nodes
+ // higher up may control other subdevices.
+ ALOGW("Failed to set power/wakeup node at %s", nodePath.c_str());
+ return false;
+ }
+ currentPath = currentPath.parent_path();
+ }
+ return false;
+}
+
void EventHub::dump(std::string& dump) const {
dump += "Event Hub State:\n";
diff --git a/services/inputflinger/reader/InputDevice.cpp b/services/inputflinger/reader/InputDevice.cpp
index 02eeb0a8de..5e42d57f06 100644
--- a/services/inputflinger/reader/InputDevice.cpp
+++ b/services/inputflinger/reader/InputDevice.cpp
@@ -745,6 +745,14 @@ void InputDevice::setKeyboardType(KeyboardType keyboardType) {
}
}
+bool InputDevice::setKernelWakeEnabled(bool enabled) {
+ bool success = false;
+ for_each_subdevice([&enabled, &success](InputDeviceContext& context) {
+ success |= context.setKernelWakeEnabled(enabled);
+ });
+ return success;
+}
+
InputDeviceContext::InputDeviceContext(InputDevice& device, int32_t eventHubId)
: mDevice(device),
mContext(device.getContext()),
diff --git a/services/inputflinger/reader/InputReader.cpp b/services/inputflinger/reader/InputReader.cpp
index ab2704237f..a2b7e82154 100644
--- a/services/inputflinger/reader/InputReader.cpp
+++ b/services/inputflinger/reader/InputReader.cpp
@@ -901,6 +901,16 @@ void InputReader::notifyMouseCursorFadedOnTyping() {
mPreventingTouchpadTaps = true;
}
+bool InputReader::setKernelWakeEnabled(int32_t deviceId, bool enabled) {
+ std::scoped_lock _l(mLock);
+
+ InputDevice* device = findInputDeviceLocked(deviceId);
+ if (device) {
+ return device->setKernelWakeEnabled(enabled);
+ }
+ return false;
+}
+
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 dffd8e3c7a..4336945e96 100644
--- a/services/inputflinger/reader/include/EventHub.h
+++ b/services/inputflinger/reader/include/EventHub.h
@@ -396,6 +396,13 @@ public:
/* 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;
+
+ /* Set whether the given input device can wake up the kernel from sleep
+ * when it generates input events. By default, usually only internal (built-in)
+ * input devices can wake the kernel from sleep. For an external input device
+ * that supports remote wakeup to be able to wake the kernel, this must be called
+ * after each time the device is connected/added. */
+ virtual bool setKernelWakeEnabled(int32_t deviceId, bool enabled) = 0;
};
template <std::size_t BITS>
@@ -603,6 +610,8 @@ public:
void sysfsNodeChanged(const std::string& sysfsNodePath) override final;
+ bool setKernelWakeEnabled(int32_t deviceId, bool enabled) override final;
+
~EventHub() override;
private:
diff --git a/services/inputflinger/reader/include/InputDevice.h b/services/inputflinger/reader/include/InputDevice.h
index 8958d9ec0b..abe7a5fa6e 100644
--- a/services/inputflinger/reader/include/InputDevice.h
+++ b/services/inputflinger/reader/include/InputDevice.h
@@ -139,6 +139,8 @@ public:
std::optional<HardwareProperties> getTouchpadHardwareProperties();
+ bool setKernelWakeEnabled(bool enabled);
+
// construct and add a mapper to the input device
template <class T, typename... Args>
T& addMapper(int32_t eventHubId, Args... args) {
@@ -469,6 +471,9 @@ public:
inline void setKeyboardType(KeyboardType keyboardType) {
return mDevice.setKeyboardType(keyboardType);
}
+ inline bool setKernelWakeEnabled(bool enabled) {
+ return mEventHub->setKernelWakeEnabled(mId, enabled);
+ }
private:
InputDevice& mDevice;
diff --git a/services/inputflinger/reader/include/InputReader.h b/services/inputflinger/reader/include/InputReader.h
index 100387195a..7614a05470 100644
--- a/services/inputflinger/reader/include/InputReader.h
+++ b/services/inputflinger/reader/include/InputReader.h
@@ -120,6 +120,8 @@ public:
void notifyMouseCursorFadedOnTyping() override;
+ bool setKernelWakeEnabled(int32_t deviceId, bool enabled) override;
+
protected:
// These members are protected so they can be instrumented by test cases.
virtual std::shared_ptr<InputDevice> createDeviceLocked(nsecs_t when, int32_t deviceId,
diff --git a/services/inputflinger/tests/FakeEventHub.cpp b/services/inputflinger/tests/FakeEventHub.cpp
index 943de6e3cf..e72c440480 100644
--- a/services/inputflinger/tests/FakeEventHub.cpp
+++ b/services/inputflinger/tests/FakeEventHub.cpp
@@ -650,4 +650,25 @@ void FakeEventHub::sysfsNodeChanged(const std::string& sysfsNodePath) {
}
}
+bool FakeEventHub::setKernelWakeEnabled(int32_t deviceId, bool enabled) {
+ Device* device = getDevice(deviceId);
+ if (device == nullptr) {
+ return false;
+ }
+ mKernelWakeup.emplace(deviceId, enabled);
+ return true;
+}
+
+bool FakeEventHub::fakeReadKernelWakeup(int32_t deviceId) const {
+ Device* device = getDevice(deviceId);
+ if (device == nullptr) {
+ return false;
+ }
+ auto it = mKernelWakeup.find(deviceId);
+ if (it == mKernelWakeup.end()) {
+ return false;
+ }
+ return it->second;
+}
+
} // namespace android
diff --git a/services/inputflinger/tests/FakeEventHub.h b/services/inputflinger/tests/FakeEventHub.h
index 2dfbb2388a..143b93b245 100644
--- a/services/inputflinger/tests/FakeEventHub.h
+++ b/services/inputflinger/tests/FakeEventHub.h
@@ -94,6 +94,8 @@ class FakeEventHub : public EventHubInterface {
// Simulates a device light intensities, from light id to light intensities map.
std::unordered_map<int32_t /* lightId */, std::unordered_map<LightColor, int32_t>>
mLightIntensities;
+ // fake sysfs node path and value.
+ std::unordered_map<int32_t /*deviceId*/, bool /* wakeupNode*/> mKernelWakeup;
public:
static constexpr int32_t DEFAULT_BATTERY = 1;
@@ -158,6 +160,8 @@ public:
void setMtSlotValues(int32_t deviceId, int32_t axis, const std::vector<int32_t>& values);
base::Result<std::vector<int32_t>> getMtSlotValues(int32_t deviceId, int32_t axis,
size_t slotCount) const override;
+ bool setKernelWakeEnabled(int32_t deviceId, bool enabled) override;
+ bool fakeReadKernelWakeup(int32_t deviceId) const;
private:
Device* getDevice(int32_t deviceId) const;
diff --git a/services/inputflinger/tests/InputReader_test.cpp b/services/inputflinger/tests/InputReader_test.cpp
index 6c8b65c018..19b738ea9d 100644
--- a/services/inputflinger/tests/InputReader_test.cpp
+++ b/services/inputflinger/tests/InputReader_test.cpp
@@ -1392,6 +1392,20 @@ TEST_F(InputReaderTest, LightGetColor) {
ASSERT_EQ(mReader->getLightColor(deviceId, /*lightId=*/1), LIGHT_BRIGHTNESS);
}
+TEST_F(InputReaderTest, SetPowerWakeUp) {
+ ASSERT_NO_FATAL_FAILURE(addDevice(1, "1st", InputDeviceClass::KEYBOARD, nullptr));
+ ASSERT_NO_FATAL_FAILURE(addDevice(2, "2nd", InputDeviceClass::KEYBOARD, nullptr));
+ ASSERT_NO_FATAL_FAILURE(addDevice(3, "3rd", InputDeviceClass::KEYBOARD, nullptr));
+
+ ASSERT_EQ(mFakeEventHub->fakeReadKernelWakeup(1), false);
+
+ ASSERT_TRUE(mFakeEventHub->setKernelWakeEnabled(2, true));
+ ASSERT_EQ(mFakeEventHub->fakeReadKernelWakeup(2), true);
+
+ ASSERT_TRUE(mFakeEventHub->setKernelWakeEnabled(3, false));
+ ASSERT_EQ(mFakeEventHub->fakeReadKernelWakeup(3), false);
+}
+
// --- InputReaderIntegrationTest ---
// These tests create and interact with the InputReader only through its interface.
diff --git a/services/inputflinger/tests/InterfaceMocks.h b/services/inputflinger/tests/InterfaceMocks.h
index a43e4e4d80..25e2b4557e 100644
--- a/services/inputflinger/tests/InterfaceMocks.h
+++ b/services/inputflinger/tests/InterfaceMocks.h
@@ -180,6 +180,7 @@ public:
MOCK_METHOD(status_t, enableDevice, (int32_t deviceId), (override));
MOCK_METHOD(status_t, disableDevice, (int32_t deviceId), (override));
MOCK_METHOD(void, sysfsNodeChanged, (const std::string& sysfsNodePath), (override));
+ MOCK_METHOD(bool, setKernelWakeEnabled, (int32_t deviceId, bool enabled), (override));
};
class MockPointerChoreographerPolicyInterface : public PointerChoreographerPolicyInterface {
diff --git a/services/inputflinger/tests/fuzzers/InputReaderFuzzer.cpp b/services/inputflinger/tests/fuzzers/InputReaderFuzzer.cpp
index 5442a65f2f..64f3c279a6 100644
--- a/services/inputflinger/tests/fuzzers/InputReaderFuzzer.cpp
+++ b/services/inputflinger/tests/fuzzers/InputReaderFuzzer.cpp
@@ -171,6 +171,10 @@ public:
void notifyMouseCursorFadedOnTyping() override { reader->notifyMouseCursorFadedOnTyping(); }
+ bool setKernelWakeEnabled(int32_t deviceId, bool enabled) override {
+ return reader->setKernelWakeEnabled(deviceId, enabled);
+ }
+
private:
std::unique_ptr<InputReaderInterface> reader;
};
diff --git a/services/inputflinger/tests/fuzzers/MapperHelpers.h b/services/inputflinger/tests/fuzzers/MapperHelpers.h
index fa8270a3d9..60c676da58 100644
--- a/services/inputflinger/tests/fuzzers/MapperHelpers.h
+++ b/services/inputflinger/tests/fuzzers/MapperHelpers.h
@@ -269,6 +269,9 @@ public:
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 {}
+ bool setKernelWakeEnabled(int32_t deviceId, bool enabled) override {
+ return mFdp->ConsumeBool();
+ }
};
class FuzzInputReaderPolicy : public InputReaderPolicyInterface {