InputTracer: Trace an event being dispatched to a window
Bug: 210460522
Test: manual with perfetto
Change-Id: Ie161726da294bc5c660d5062af85c9cd621c1b4c
diff --git a/services/inputflinger/dispatcher/Entry.cpp b/services/inputflinger/dispatcher/Entry.cpp
index 2153d8a..bc090cf 100644
--- a/services/inputflinger/dispatcher/Entry.cpp
+++ b/services/inputflinger/dispatcher/Entry.cpp
@@ -284,7 +284,8 @@
DispatchEntry::DispatchEntry(std::shared_ptr<const EventEntry> eventEntry,
ftl::Flags<InputTarget::Flags> targetFlags,
const ui::Transform& transform, const ui::Transform& rawTransform,
- float globalScaleFactor)
+ float globalScaleFactor, gui::Uid targetUid, int64_t vsyncId,
+ std::optional<int32_t> windowId)
: seq(nextSeq()),
eventEntry(std::move(eventEntry)),
targetFlags(targetFlags),
@@ -292,7 +293,10 @@
rawTransform(rawTransform),
globalScaleFactor(globalScaleFactor),
deliveryTime(0),
- resolvedFlags(0) {
+ resolvedFlags(0),
+ targetUid(targetUid),
+ vsyncId(vsyncId),
+ windowId(windowId) {
switch (this->eventEntry->type) {
case EventEntry::Type::KEY: {
const KeyEntry& keyEntry = static_cast<const KeyEntry&>(*this->eventEntry);
diff --git a/services/inputflinger/dispatcher/Entry.h b/services/inputflinger/dispatcher/Entry.h
index a915805..9e5d346 100644
--- a/services/inputflinger/dispatcher/Entry.h
+++ b/services/inputflinger/dispatcher/Entry.h
@@ -227,9 +227,19 @@
int32_t resolvedFlags;
+ // Information about the dispatch window used for tracing. We avoid holding a window handle
+ // here because information in a window handle may be dynamically updated within the lifespan
+ // of this dispatch entry.
+ gui::Uid targetUid;
+ int64_t vsyncId;
+ // The window that this event is targeting. The only case when this windowId is not populated
+ // is when dispatching an event to a global monitor.
+ std::optional<int32_t> windowId;
+
DispatchEntry(std::shared_ptr<const EventEntry> eventEntry,
ftl::Flags<InputTarget::Flags> targetFlags, const ui::Transform& transform,
- const ui::Transform& rawTransform, float globalScaleFactor);
+ const ui::Transform& rawTransform, float globalScaleFactor, gui::Uid targetUid,
+ int64_t vsyncId, std::optional<int32_t> windowId);
DispatchEntry(const DispatchEntry&) = delete;
DispatchEntry& operator=(const DispatchEntry&) = delete;
diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp
index efc9b3a..da3b032 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.cpp
+++ b/services/inputflinger/dispatcher/InputDispatcher.cpp
@@ -35,6 +35,7 @@
#include <input/PrintTools.h>
#include <input/TraceTools.h>
#include <openssl/mem.h>
+#include <private/android_filesystem_config.h>
#include <unistd.h>
#include <utils/Trace.h>
@@ -369,14 +370,22 @@
return i;
}
-std::unique_ptr<DispatchEntry> createDispatchEntry(
- const InputTarget& inputTarget, std::shared_ptr<const EventEntry> eventEntry,
- ftl::Flags<InputTarget::Flags> inputTargetFlags) {
+std::unique_ptr<DispatchEntry> createDispatchEntry(const InputTarget& inputTarget,
+ std::shared_ptr<const EventEntry> eventEntry,
+ ftl::Flags<InputTarget::Flags> inputTargetFlags,
+ int64_t vsyncId) {
+ const sp<WindowInfoHandle> win = inputTarget.windowHandle;
+ const std::optional<int32_t> windowId =
+ win ? std::make_optional(win->getInfo()->id) : std::nullopt;
+ // Assume the only targets that are not associated with a window are global monitors, and use
+ // the system UID for global monitors for tracing purposes.
+ const gui::Uid uid = win ? win->getInfo()->ownerUid : gui::Uid(AID_SYSTEM);
if (inputTarget.useDefaultPointerTransform()) {
const ui::Transform& transform = inputTarget.getDefaultPointerTransform();
return std::make_unique<DispatchEntry>(eventEntry, inputTargetFlags, transform,
inputTarget.displayTransform,
- inputTarget.globalScaleFactor);
+ inputTarget.globalScaleFactor, uid, vsyncId,
+ windowId);
}
ALOG_ASSERT(eventEntry->type == EventEntry::Type::MOTION);
@@ -423,7 +432,7 @@
std::unique_ptr<DispatchEntry> dispatchEntry =
std::make_unique<DispatchEntry>(std::move(combinedMotionEntry), inputTargetFlags,
firstPointerTransform, inputTarget.displayTransform,
- inputTarget.globalScaleFactor);
+ inputTarget.globalScaleFactor, uid, vsyncId, windowId);
return dispatchEntry;
}
@@ -3345,10 +3354,11 @@
void InputDispatcher::enqueueDispatchEntryLocked(const std::shared_ptr<Connection>& connection,
std::shared_ptr<const EventEntry> eventEntry,
const InputTarget& inputTarget) {
+ // TODO(b/210460522): Verify all targets excluding global monitors are associated with a window.
// This is a new event.
// Enqueue a new dispatch entry onto the outbound queue for this connection.
std::unique_ptr<DispatchEntry> dispatchEntry =
- createDispatchEntry(inputTarget, eventEntry, inputTarget.flags);
+ createDispatchEntry(inputTarget, eventEntry, inputTarget.flags, mWindowInfosVsyncId);
// Use the eventEntry from dispatchEntry since the entry may have changed and can now be a
// different EventEntry than what was passed in.
@@ -3467,7 +3477,7 @@
<< cancelEvent->getDescription();
std::unique_ptr<DispatchEntry> cancelDispatchEntry =
createDispatchEntry(inputTarget, std::move(cancelEvent),
- ftl::Flags<InputTarget::Flags>());
+ ftl::Flags<InputTarget::Flags>(), mWindowInfosVsyncId);
// Send these cancel events to the queue before sending the event from the new
// device.
diff --git a/services/inputflinger/dispatcher/trace/AndroidInputEventProtoConverter.cpp b/services/inputflinger/dispatcher/trace/AndroidInputEventProtoConverter.cpp
index a15ad80..a61fa85 100644
--- a/services/inputflinger/dispatcher/trace/AndroidInputEventProtoConverter.cpp
+++ b/services/inputflinger/dispatcher/trace/AndroidInputEventProtoConverter.cpp
@@ -71,4 +71,39 @@
outProto.set_policy_flags(event.policyFlags);
}
+void AndroidInputEventProtoConverter::toProtoWindowDispatchEvent(
+ const InputTracingBackendInterface::WindowDispatchArgs& args,
+ proto::AndroidWindowInputDispatchEvent& outProto) {
+ std::visit([&](auto entry) { outProto.set_event_id(entry.id); }, args.eventEntry);
+ outProto.set_vsync_id(args.vsyncId);
+ outProto.set_window_id(args.windowId);
+ outProto.set_resolved_flags(args.resolvedFlags);
+
+ if (auto* motion = std::get_if<TracedMotionEvent>(&args.eventEntry); motion != nullptr) {
+ for (size_t i = 0; i < motion->pointerProperties.size(); i++) {
+ auto* pointerProto = outProto.add_dispatched_pointer();
+ pointerProto->set_pointer_id(motion->pointerProperties[i].id);
+ const auto rawXY =
+ MotionEvent::calculateTransformedXY(motion->source, args.rawTransform,
+ motion->pointerCoords[i].getXYValue());
+ pointerProto->set_x_in_display(rawXY.x);
+ pointerProto->set_y_in_display(rawXY.y);
+
+ const auto& coords = motion->pointerCoords[i];
+ const auto coordsInWindow =
+ MotionEvent::calculateTransformedCoords(motion->source, args.transform, coords);
+ auto bits = BitSet64(coords.bits);
+ for (int32_t axisIndex = 0; !bits.isEmpty(); axisIndex++) {
+ const uint32_t axis = bits.clearFirstMarkedBit();
+ const float axisValueInWindow = coordsInWindow.values[axisIndex];
+ if (coords.values[axisIndex] != axisValueInWindow) {
+ auto* axisEntry = pointerProto->add_axis_value_in_window();
+ axisEntry->set_axis(axis);
+ axisEntry->set_value(axisValueInWindow);
+ }
+ }
+ }
+ }
+}
+
} // namespace android::inputdispatcher::trace
diff --git a/services/inputflinger/dispatcher/trace/AndroidInputEventProtoConverter.h b/services/inputflinger/dispatcher/trace/AndroidInputEventProtoConverter.h
index fd23238..8a46f15 100644
--- a/services/inputflinger/dispatcher/trace/AndroidInputEventProtoConverter.h
+++ b/services/inputflinger/dispatcher/trace/AndroidInputEventProtoConverter.h
@@ -32,6 +32,8 @@
static void toProtoMotionEvent(const TracedMotionEvent& event,
proto::AndroidMotionEvent& outProto);
static void toProtoKeyEvent(const TracedKeyEvent& event, proto::AndroidKeyEvent& outProto);
+ static void toProtoWindowDispatchEvent(const InputTracingBackendInterface::WindowDispatchArgs&,
+ proto::AndroidWindowInputDispatchEvent& outProto);
};
} // namespace android::inputdispatcher::trace
diff --git a/services/inputflinger/dispatcher/trace/InputTracer.cpp b/services/inputflinger/dispatcher/trace/InputTracer.cpp
index 60f574d..b065729 100644
--- a/services/inputflinger/dispatcher/trace/InputTracer.cpp
+++ b/services/inputflinger/dispatcher/trace/InputTracer.cpp
@@ -19,6 +19,7 @@
#include "InputTracer.h"
#include <android-base/logging.h>
+#include <utils/AndroidThreads.h>
namespace android::inputdispatcher::trace::impl {
@@ -112,37 +113,76 @@
}
void InputTracer::traceEventDispatch(const DispatchEntry& dispatchEntry,
- const EventTrackerInterface* cookie) {}
+ const EventTrackerInterface* cookie) {
+ {
+ std::scoped_lock lock(mLock);
+ const EventEntry& entry = *dispatchEntry.eventEntry;
+
+ TracedEvent traced;
+ if (entry.type == EventEntry::Type::MOTION) {
+ const auto& motion = static_cast<const MotionEntry&>(entry);
+ traced = createTracedEvent(motion);
+ } else if (entry.type == EventEntry::Type::KEY) {
+ const auto& key = static_cast<const KeyEntry&>(entry);
+ traced = createTracedEvent(key);
+ } else {
+ LOG(FATAL) << "Cannot trace EventEntry of type: " << ftl::enum_string(entry.type);
+ }
+
+ if (!cookie) {
+ // This event was not tracked as an inbound event, so trace it now.
+ mTraceQueue.emplace_back(traced);
+ }
+
+ // The vsyncId only has meaning if the event is targeting a window.
+ const int32_t windowId = dispatchEntry.windowId.value_or(0);
+ const int32_t vsyncId = dispatchEntry.windowId.has_value() ? dispatchEntry.vsyncId : 0;
+
+ mDispatchTraceQueue.emplace_back(std::move(traced), dispatchEntry.deliveryTime,
+ dispatchEntry.resolvedFlags, dispatchEntry.targetUid,
+ vsyncId, windowId, dispatchEntry.transform,
+ dispatchEntry.rawTransform);
+ } // release lock
+
+ mThreadWakeCondition.notify_all();
+}
std::optional<InputTracer::EventState>& InputTracer::getState(const EventTrackerInterface& cookie) {
return static_cast<const EventTrackerImpl&>(cookie).mLockedState;
}
void InputTracer::threadLoop() {
+ androidSetThreadName("InputTracer");
+
while (true) {
std::vector<const EventState> eventsToTrace;
+ std::vector<const WindowDispatchArgs> dispatchEventsToTrace;
{
std::unique_lock lock(mLock);
base::ScopedLockAssertion assumeLocked(mLock);
if (mThreadExit) {
return;
}
- if (mTraceQueue.empty()) {
+ if (mTraceQueue.empty() && mDispatchTraceQueue.empty()) {
// Wait indefinitely until the thread is awoken.
mThreadWakeCondition.wait(lock);
}
mTraceQueue.swap(eventsToTrace);
+ mDispatchTraceQueue.swap(dispatchEventsToTrace);
} // release lock
// Trace the events into the backend without holding the lock to reduce the amount of
// work performed in the critical section.
- writeEventsToBackend(eventsToTrace);
+ writeEventsToBackend(eventsToTrace, dispatchEventsToTrace);
eventsToTrace.clear();
+ dispatchEventsToTrace.clear();
}
}
-void InputTracer::writeEventsToBackend(const std::vector<const EventState>& events) {
+void InputTracer::writeEventsToBackend(
+ const std::vector<const EventState>& events,
+ const std::vector<const WindowDispatchArgs>& dispatchEvents) {
for (const auto& event : events) {
if (auto* motion = std::get_if<TracedMotionEvent>(&event.event); motion != nullptr) {
mBackend->traceMotionEvent(*motion);
@@ -150,6 +190,10 @@
mBackend->traceKeyEvent(std::get<TracedKeyEvent>(event.event));
}
}
+
+ for (const auto& dispatchArgs : dispatchEvents) {
+ mBackend->traceWindowDispatch(dispatchArgs);
+ }
}
// --- InputTracer::EventTrackerImpl ---
diff --git a/services/inputflinger/dispatcher/trace/InputTracer.h b/services/inputflinger/dispatcher/trace/InputTracer.h
index 97f3a2b..9fe395d 100644
--- a/services/inputflinger/dispatcher/trace/InputTracer.h
+++ b/services/inputflinger/dispatcher/trace/InputTracer.h
@@ -68,6 +68,8 @@
// dispatch target UIDs.
};
std::vector<const EventState> mTraceQueue GUARDED_BY(mLock);
+ using WindowDispatchArgs = InputTracingBackendInterface::WindowDispatchArgs;
+ std::vector<const WindowDispatchArgs> mDispatchTraceQueue GUARDED_BY(mLock);
// Provides thread-safe access to the state from an event tracker cookie.
std::optional<EventState>& getState(const EventTrackerInterface&) REQUIRES(mLock);
@@ -90,7 +92,8 @@
};
void threadLoop();
- void writeEventsToBackend(const std::vector<const EventState>& events);
+ void writeEventsToBackend(const std::vector<const EventState>& events,
+ const std::vector<const WindowDispatchArgs>& dispatchEvents);
};
} // namespace android::inputdispatcher::trace::impl
diff --git a/services/inputflinger/dispatcher/trace/InputTracingPerfettoBackend.cpp b/services/inputflinger/dispatcher/trace/InputTracingPerfettoBackend.cpp
index db88726..4442ad8 100644
--- a/services/inputflinger/dispatcher/trace/InputTracingPerfettoBackend.cpp
+++ b/services/inputflinger/dispatcher/trace/InputTracingPerfettoBackend.cpp
@@ -81,8 +81,14 @@
});
}
-void PerfettoBackend::traceWindowDispatch(const WindowDispatchArgs&) const {
- // TODO(b/210460522): Implement.
+void PerfettoBackend::traceWindowDispatch(const WindowDispatchArgs& dispatchArgs) const {
+ InputEventDataSource::Trace([&](InputEventDataSource::TraceContext ctx) {
+ auto tracePacket = ctx.NewTracePacket();
+ auto* inputEventProto = tracePacket->set_android_input_event();
+ auto* dispatchEventProto = inputEventProto->set_dispatcher_window_dispatch_event();
+ AndroidInputEventProtoConverter::toProtoWindowDispatchEvent(dispatchArgs,
+ *dispatchEventProto);
+ });
}
} // namespace android::inputdispatcher::trace::impl