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