InputTracer: Trace an event being dispatched to a window

Bug: 210460522
Test: manual with perfetto
Change-Id: Ie161726da294bc5c660d5062af85c9cd621c1b4c
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