summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Treehugger Robot <android-test-infra-autosubmit@system.gserviceaccount.com> 2025-03-18 13:23:23 -0700
committer Android (Google) Code Review <android-gerrit@google.com> 2025-03-18 13:23:23 -0700
commit5dde97f25480ede06c6dfb54e75d31586c70b6cc (patch)
tree9ac8ab08578900770bd7ff0c8e9f8bc54ada4f4b
parentbcbec20c069ccb1f3d2faa34aec1857aec06bc8f (diff)
parent523b461f296f6841e60ef43eb9577ec0833b6e12 (diff)
Merge "Add support for search modifier fallbacks" into main
-rw-r--r--services/inputflinger/dispatcher/Entry.h7
-rw-r--r--services/inputflinger/dispatcher/InputDispatcher.cpp67
-rw-r--r--services/inputflinger/dispatcher/InputDispatcher.h4
-rw-r--r--services/inputflinger/dispatcher/LatencyTracker.cpp9
-rw-r--r--services/inputflinger/dispatcher/LatencyTracker.h9
-rw-r--r--services/inputflinger/tests/InputDispatcher_test.cpp69
-rw-r--r--services/inputflinger/tests/LatencyTracker_test.cpp19
-rw-r--r--services/inputflinger/tests/fuzzers/LatencyTrackerFuzzer.cpp5
8 files changed, 169 insertions, 20 deletions
diff --git a/services/inputflinger/dispatcher/Entry.h b/services/inputflinger/dispatcher/Entry.h
index becfb05f67..9cd76c7d11 100644
--- a/services/inputflinger/dispatcher/Entry.h
+++ b/services/inputflinger/dispatcher/Entry.h
@@ -125,10 +125,17 @@ struct KeyEntry : EventEntry {
bool syntheticRepeat; // set to true for synthetic key repeats
enum class InterceptKeyResult {
+ // The interception result is unknown.
UNKNOWN,
+ // The event should be skipped and not sent to the application.
SKIP,
+ // The event should be sent to the application.
CONTINUE,
+ // The event should eventually be sent to the application, after a delay.
TRY_AGAIN_LATER,
+ // The event should not be initially sent to the application, but instead go through
+ // post-processing to generate a fallback key event and then sent to the application.
+ FALLBACK,
};
// These are special fields that may need to be modified while the event is being dispatched.
mutable InterceptKeyResult interceptKeyResult; // set based on the interception result
diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp
index 95e1c06615..391703d506 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.cpp
+++ b/services/inputflinger/dispatcher/InputDispatcher.cpp
@@ -952,7 +952,7 @@ InputDispatcher::InputDispatcher(InputDispatcherPolicyInterface& policy,
new LatencyAggregatorWithHistograms()))
: std::move(std::unique_ptr<InputEventTimelineProcessor>(
new LatencyAggregator()))),
- mLatencyTracker(*mInputEventTimelineProcessor) {
+ mLatencyTracker(*mInputEventTimelineProcessor, mInputDevices) {
mReporter = createInputReporter();
mWindowInfoListener = sp<DispatcherWindowListener>::make(*this);
@@ -1961,11 +1961,74 @@ bool InputDispatcher::dispatchKeyLocked(nsecs_t currentTime, std::shared_ptr<con
}
}
+ if (entry->interceptKeyResult == KeyEntry::InterceptKeyResult::FALLBACK) {
+ findAndDispatchFallbackEvent(currentTime, entry, inputTargets);
+ // Drop the key.
+ return true;
+ }
+
// Dispatch the key.
dispatchEventLocked(currentTime, entry, inputTargets);
return true;
}
+void InputDispatcher::findAndDispatchFallbackEvent(nsecs_t currentTime,
+ std::shared_ptr<const KeyEntry> entry,
+ std::vector<InputTarget>& inputTargets) {
+ // Find the fallback associated with the incoming key event and dispatch it.
+ KeyEvent event = createKeyEvent(*entry);
+ const int32_t originalKeyCode = entry->keyCode;
+
+ // Fetch the fallback event.
+ KeyCharacterMap::FallbackAction fallback;
+ for (const InputDeviceInfo& deviceInfo : mInputDevices) {
+ if (deviceInfo.getId() == entry->deviceId) {
+ const KeyCharacterMap* map = deviceInfo.getKeyCharacterMap();
+
+ LOG_ALWAYS_FATAL_IF(map == nullptr, "No KeyCharacterMap for device %d",
+ entry->deviceId);
+ map->getFallbackAction(entry->keyCode, entry->metaState, &fallback);
+ break;
+ }
+ }
+
+ if (fallback.keyCode == AKEYCODE_UNKNOWN) {
+ // No fallback detected.
+ return;
+ }
+
+ std::unique_ptr<KeyEntry> fallbackKeyEntry =
+ std::make_unique<KeyEntry>(mIdGenerator.nextId(), entry->injectionState,
+ event.getEventTime(), event.getDeviceId(), event.getSource(),
+ event.getDisplayId(), entry->policyFlags, entry->action,
+ event.getFlags() | AKEY_EVENT_FLAG_FALLBACK,
+ fallback.keyCode, event.getScanCode(), /*metaState=*/0,
+ event.getRepeatCount(), event.getDownTime());
+
+ if (mTracer) {
+ fallbackKeyEntry->traceTracker =
+ mTracer->traceDerivedEvent(*fallbackKeyEntry, *entry->traceTracker);
+ }
+
+ for (const InputTarget& inputTarget : inputTargets) {
+ std::shared_ptr<Connection> connection = inputTarget.connection;
+ if (!connection->responsive || (connection->status != Connection::Status::NORMAL)) {
+ return;
+ }
+
+ connection->inputState.setFallbackKey(originalKeyCode, fallback.keyCode);
+ if (entry->action == AKEY_EVENT_ACTION_UP) {
+ connection->inputState.removeFallbackKey(originalKeyCode);
+ }
+
+ if (mTracer) {
+ mTracer->dispatchToTargetHint(*fallbackKeyEntry->traceTracker, inputTarget);
+ }
+ enqueueDispatchEntryAndStartDispatchCycleLocked(currentTime, connection,
+ std::move(fallbackKeyEntry), inputTarget);
+ }
+}
+
void InputDispatcher::logOutboundKeyDetails(const char* prefix, const KeyEntry& entry) {
LOG_IF(INFO, DEBUG_OUTBOUND_EVENT_DETAILS)
<< prefix << "eventTime=" << entry.eventTime << ", deviceId=" << entry.deviceId
@@ -4346,7 +4409,7 @@ void InputDispatcher::notifyInputDevicesChanged(const NotifyInputDevicesChangedA
std::scoped_lock _l(mLock);
// Reset key repeating in case a keyboard device was added or removed or something.
resetKeyRepeatLocked();
- mLatencyTracker.setInputDevices(args.inputDeviceInfos);
+ mInputDevices = args.inputDeviceInfos;
}
void InputDispatcher::notifyKey(const NotifyKeyArgs& args) {
diff --git a/services/inputflinger/dispatcher/InputDispatcher.h b/services/inputflinger/dispatcher/InputDispatcher.h
index 38f782573a..ad7e87e192 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.h
+++ b/services/inputflinger/dispatcher/InputDispatcher.h
@@ -918,10 +918,14 @@ private:
std::unique_ptr<const KeyEntry> afterKeyEventLockedInterruptable(
const std::shared_ptr<Connection>& connection, DispatchEntry* dispatchEntry,
bool handled) REQUIRES(mLock);
+ void findAndDispatchFallbackEvent(nsecs_t currentTime, std::shared_ptr<const KeyEntry> entry,
+ std::vector<InputTarget>& inputTargets) REQUIRES(mLock);
// Statistics gathering.
nsecs_t mLastStatisticPushTime = 0;
std::unique_ptr<InputEventTimelineProcessor> mInputEventTimelineProcessor GUARDED_BY(mLock);
+ // Must outlive `mLatencyTracker`.
+ std::vector<InputDeviceInfo> mInputDevices;
LatencyTracker mLatencyTracker GUARDED_BY(mLock);
void traceInboundQueueLengthLocked() REQUIRES(mLock);
void traceOutboundQueueLength(const Connection& connection);
diff --git a/services/inputflinger/dispatcher/LatencyTracker.cpp b/services/inputflinger/dispatcher/LatencyTracker.cpp
index 0921e37d03..7c23694fbd 100644
--- a/services/inputflinger/dispatcher/LatencyTracker.cpp
+++ b/services/inputflinger/dispatcher/LatencyTracker.cpp
@@ -67,8 +67,9 @@ static void eraseByValue(std::multimap<K, V>& map, const V& value) {
} // namespace
-LatencyTracker::LatencyTracker(InputEventTimelineProcessor& processor)
- : mTimelineProcessor(&processor) {}
+LatencyTracker::LatencyTracker(InputEventTimelineProcessor& processor,
+ std::vector<InputDeviceInfo>& inputDevices)
+ : mTimelineProcessor(&processor), mInputDevices(inputDevices) {}
void LatencyTracker::trackListener(const NotifyArgs& args) {
if (const NotifyKeyArgs* keyArgs = std::get_if<NotifyKeyArgs>(&args)) {
@@ -248,8 +249,4 @@ std::string LatencyTracker::dump(const char* prefix) const {
StringPrintf("%s mEventTimes.size() = %zu\n", prefix, mEventTimes.size());
}
-void LatencyTracker::setInputDevices(const std::vector<InputDeviceInfo>& inputDevices) {
- mInputDevices = inputDevices;
-}
-
} // namespace android::inputdispatcher
diff --git a/services/inputflinger/dispatcher/LatencyTracker.h b/services/inputflinger/dispatcher/LatencyTracker.h
index 79ea14c4fb..7e2cc79249 100644
--- a/services/inputflinger/dispatcher/LatencyTracker.h
+++ b/services/inputflinger/dispatcher/LatencyTracker.h
@@ -20,9 +20,11 @@
#include <map>
#include <unordered_map>
+#include <vector>
#include <binder/IBinder.h>
#include <input/Input.h>
+#include <input/InputDevice.h>
#include "InputEventTimeline.h"
#include "NotifyArgs.h"
@@ -41,8 +43,10 @@ public:
/**
* Create a LatencyTracker.
* param reportingFunction: the function that will be called in order to report full latency.
+ * param inputDevices: input devices relevant for tracking.
*/
- LatencyTracker(InputEventTimelineProcessor& processor);
+ LatencyTracker(InputEventTimelineProcessor& processor,
+ std::vector<InputDeviceInfo>& inputDevices);
/**
* Start keeping track of an event identified by the args. This must be called first.
* If duplicate events are encountered (events that have the same eventId), none of them will be
@@ -60,7 +64,6 @@ public:
std::array<nsecs_t, GraphicsTimeline::SIZE> timeline);
std::string dump(const char* prefix) const;
- void setInputDevices(const std::vector<InputDeviceInfo>& inputDevices);
private:
/**
@@ -81,7 +84,7 @@ private:
std::multimap<nsecs_t /*eventTime*/, int32_t /*inputEventId*/> mEventTimes;
InputEventTimelineProcessor* mTimelineProcessor;
- std::vector<InputDeviceInfo> mInputDevices;
+ std::vector<InputDeviceInfo>& mInputDevices;
void trackListener(int32_t inputEventId, nsecs_t eventTime, nsecs_t readTime, DeviceId deviceId,
const std::set<InputDeviceUsageSource>& sources, int32_t inputEventAction,
diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp
index 835b677e1e..f7dcd6c6e3 100644
--- a/services/inputflinger/tests/InputDispatcher_test.cpp
+++ b/services/inputflinger/tests/InputDispatcher_test.cpp
@@ -37,6 +37,7 @@
#include <input/BlockingQueue.h>
#include <input/Input.h>
#include <input/InputConsumer.h>
+#include <input/KeyCharacterMap.h>
#include <input/PrintTools.h>
#include <linux/input.h>
#include <sys/epoll.h>
@@ -139,6 +140,30 @@ static KeyEvent getTestKeyEvent() {
return event;
}
+InputDeviceInfo generateTestDeviceInfo(uint16_t vendorId, uint16_t productId, DeviceId deviceId) {
+ InputDeviceIdentifier identifier;
+ identifier.vendor = vendorId;
+ identifier.product = productId;
+ auto info = InputDeviceInfo();
+ info.initialize(deviceId, /*generation=*/1, /*controllerNumber=*/1, identifier, "Test Device",
+ /*isExternal=*/false, /*hasMic=*/false, ui::LogicalDisplayId::INVALID);
+ return info;
+}
+
+std::unique_ptr<KeyCharacterMap> loadKeyCharacterMap(const char* name) {
+ InputDeviceIdentifier identifier;
+ identifier.name = name;
+ std::string path = getInputDeviceConfigurationFilePathByName(identifier.getCanonicalName(),
+ InputDeviceConfigurationFileType::
+ KEY_CHARACTER_MAP);
+
+ if (path.empty()) {
+ return nullptr;
+ }
+
+ return *KeyCharacterMap::load(path, KeyCharacterMap::Format::BASE);
+}
+
} // namespace
// --- InputDispatcherTest ---
@@ -7480,6 +7505,50 @@ TEST_F(InputDispatcherTest, FocusedWindow_PolicyConsumedKeyIgnoresDisableUserAct
mFakePolicy->assertUserActivityPoked();
}
+TEST_F(InputDispatcherTest, FocusedWindow_DoesNotReceivePolicyFallbackKey) {
+#if !defined(__ANDROID__)
+ GTEST_SKIP() << "b/253299089 Generic files are currently read directly from device.";
+#endif
+ InputDeviceInfo testDevice = generateTestDeviceInfo(/*vendorId=*/0,
+ /*productId=*/0, /*deviceId=*/1);
+ std::unique_ptr<KeyCharacterMap> kcm = loadKeyCharacterMap("Generic");
+ ASSERT_NE(nullptr, kcm);
+
+ testDevice.setKeyCharacterMap(std::move(kcm));
+ mDispatcher->notifyInputDevicesChanged(NotifyInputDevicesChangedArgs(/*id=*/1, {testDevice}));
+
+ std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
+ sp<FakeWindowHandle> window =
+ sp<FakeWindowHandle>::make(application, mDispatcher, "Fake Window",
+ ui::LogicalDisplayId::DEFAULT);
+
+ window->setFocusable(true);
+ mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
+ setFocusedWindow(window);
+
+ window->consumeFocusEvent(true);
+
+ mFakePolicy->setInterceptKeyBeforeDispatchingResult(
+ inputdispatcher::KeyEntry::InterceptKeyResult::FALLBACK);
+
+ // In the Generic KCM fallbacks, Meta + Space => SEARCH.
+ mDispatcher->notifyKey(KeyArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_KEYBOARD)
+ .keyCode(AKEYCODE_SPACE)
+ .metaState(AMETA_META_ON)
+ .build());
+ mDispatcher->waitForIdle();
+
+ // Should have poked user activity
+ mFakePolicy->assertUserActivityPoked();
+
+ // Fallback is generated and sent instead.
+ std::unique_ptr<KeyEvent> consumedEvent = window->consumeKey(/*handled=*/false);
+ ASSERT_NE(nullptr, consumedEvent);
+ ASSERT_THAT(*consumedEvent,
+ AllOf(WithKeyAction(ACTION_DOWN), WithKeyCode(AKEYCODE_SEARCH),
+ WithFlags(AKEY_EVENT_FLAG_FALLBACK)));
+}
+
class DisableUserActivityInputDispatcherTest : public InputDispatcherTest,
public ::testing::WithParamInterface<bool> {};
diff --git a/services/inputflinger/tests/LatencyTracker_test.cpp b/services/inputflinger/tests/LatencyTracker_test.cpp
index d8c5eac3c4..b7ca24bb61 100644
--- a/services/inputflinger/tests/LatencyTracker_test.cpp
+++ b/services/inputflinger/tests/LatencyTracker_test.cpp
@@ -19,10 +19,13 @@
#include "NotifyArgsBuilders.h"
#include "android/input.h"
+#include <vector>
+
#include <android-base/logging.h>
#include <android-base/properties.h>
#include <binder/Binder.h>
#include <gtest/gtest.h>
+#include <input/InputDevice.h>
#include <input/PrintTools.h>
#include <inttypes.h>
#include <linux/input.h>
@@ -51,11 +54,6 @@ static InputDeviceInfo generateTestDeviceInfo(uint16_t vendorId, uint16_t produc
return info;
}
-void setDefaultInputDeviceInfo(LatencyTracker& tracker) {
- InputDeviceInfo deviceInfo = generateTestDeviceInfo(/*vendorId=*/0, /*productId=*/0, DEVICE_ID);
- tracker.setInputDevices({deviceInfo});
-}
-
const auto FIRST_TOUCH_POINTER = PointerBuilder(/*id=*/0, ToolType::FINGER).x(100).y(200);
const auto FIRST_MOUSE_POINTER = PointerBuilder(/*id=*/1, ToolType::MOUSE);
@@ -120,13 +118,14 @@ protected:
std::unique_ptr<LatencyTracker> mTracker;
sp<IBinder> connection1;
sp<IBinder> connection2;
+ std::vector<InputDeviceInfo> inputDevices;
void SetUp() override {
connection1 = sp<BBinder>::make();
connection2 = sp<BBinder>::make();
- mTracker = std::make_unique<LatencyTracker>(*this);
- setDefaultInputDeviceInfo(*mTracker);
+ inputDevices.push_back(generateTestDeviceInfo(/*vendorId=*/0, /*productId=*/0, DEVICE_ID));
+ mTracker = std::make_unique<LatencyTracker>(*this, inputDevices);
}
void TearDown() override {}
@@ -140,6 +139,10 @@ protected:
*/
void assertReceivedTimelines(const std::vector<InputEventTimeline>& timelines);
+ void updateInputDevices(const std::vector<InputDeviceInfo>& inputDevicesUpdated) {
+ inputDevices = inputDevicesUpdated;
+ }
+
private:
void processTimeline(const InputEventTimeline& timeline) override {
mReceivedTimelines.push_back(timeline);
@@ -448,7 +451,7 @@ TEST_F(LatencyTrackerTest, TrackListenerCheck_DeviceInfoFieldsInputEventTimeline
deviceInfo2.addSource(AINPUT_SOURCE_TOUCHSCREEN);
deviceInfo2.addSource(AINPUT_SOURCE_STYLUS);
- mTracker->setInputDevices({deviceInfo1, deviceInfo2});
+ updateInputDevices({deviceInfo1, deviceInfo2});
mTracker->trackListener(
MotionArgsBuilder(AMOTION_EVENT_ACTION_CANCEL,
AINPUT_SOURCE_TOUCHSCREEN | AINPUT_SOURCE_STYLUS, inputEventId)
diff --git a/services/inputflinger/tests/fuzzers/LatencyTrackerFuzzer.cpp b/services/inputflinger/tests/fuzzers/LatencyTrackerFuzzer.cpp
index 157a3338da..9c027fa00c 100644
--- a/services/inputflinger/tests/fuzzers/LatencyTrackerFuzzer.cpp
+++ b/services/inputflinger/tests/fuzzers/LatencyTrackerFuzzer.cpp
@@ -17,6 +17,8 @@
#include <fuzzer/FuzzedDataProvider.h>
#include <linux/input.h>
+#include <vector>
+
#include "../../InputDeviceMetricsSource.h"
#include "../InputEventTimeline.h"
#include "NotifyArgsBuilders.h"
@@ -58,7 +60,8 @@ extern "C" int LLVMFuzzerTestOneInput(uint8_t* data, size_t size) {
FuzzedDataProvider fdp(data, size);
EmptyProcessor emptyProcessor;
- LatencyTracker tracker(emptyProcessor);
+ std::vector<InputDeviceInfo> emptyDevices;
+ LatencyTracker tracker(emptyProcessor, emptyDevices);
// Make some pre-defined tokens to ensure that some timelines are complete.
std::array<sp<IBinder> /*token*/, 10> predefinedTokens;