Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 9180f87b authored by Treehugger Robot's avatar Treehugger Robot Committed by Android (Google) Code Review
Browse files

Merge "InputTracer: Separate the threading logic into a wrapper backend" into main

parents c7c3ed1b bb7a0208
Loading
Loading
Loading
Loading
+11 −3
Original line number Diff line number Diff line
@@ -54,6 +54,7 @@
#include "InputDispatcher.h"
#include "trace/InputTracer.h"
#include "trace/InputTracingPerfettoBackend.h"
#include "trace/ThreadedBackend.h"

#define INDENT "  "
#define INDENT2 "    "
@@ -86,6 +87,15 @@ bool isInputTracingEnabled() {
    return input_flags::enable_input_event_tracing() && isUserdebugOrEng;
}

// Create the input tracing backend that writes to perfetto from a single thread.
std::unique_ptr<trace::InputTracingBackendInterface> createInputTracingBackendIfEnabled() {
    if (!isInputTracingEnabled()) {
        return nullptr;
    }
    return std::make_unique<trace::impl::ThreadedBackend<trace::impl::PerfettoBackend>>(
            trace::impl::PerfettoBackend());
}

template <class Entry>
void ensureEventTraced(const Entry& entry) {
    if (!entry.traceTracker) {
@@ -832,9 +842,7 @@ std::pair<bool /*cancelPointers*/, bool /*cancelNonPointers*/> expandCancellatio
// --- InputDispatcher ---

InputDispatcher::InputDispatcher(InputDispatcherPolicyInterface& policy)
      : InputDispatcher(policy,
                        isInputTracingEnabled() ? std::make_unique<trace::impl::PerfettoBackend>()
                                                : nullptr) {}
      : InputDispatcher(policy, createInputTracingBackendIfEnabled()) {}

InputDispatcher::InputDispatcher(InputDispatcherPolicyInterface& policy,
                                 std::unique_ptr<trace::InputTracingBackendInterface> traceBackend)
+57 −118
Original line number Diff line number Diff line
@@ -19,12 +19,17 @@
#include "InputTracer.h"

#include <android-base/logging.h>
#include <utils/AndroidThreads.h>

namespace android::inputdispatcher::trace::impl {

namespace {

// Helper to std::visit with lambdas.
template <typename... V>
struct Visitor : V... {
    using V::operator()...;
};

TracedEvent createTracedEvent(const MotionEntry& e) {
    return TracedMotionEvent{e.id,
                             e.eventTime,
@@ -59,19 +64,9 @@ TracedEvent createTracedEvent(const KeyEntry& e) {
// --- InputTracer ---

InputTracer::InputTracer(std::unique_ptr<InputTracingBackendInterface> backend)
      : mTracerThread(&InputTracer::threadLoop, this), mBackend(std::move(backend)) {}

InputTracer::~InputTracer() {
    {
        std::scoped_lock lock(mLock);
        mThreadExit = true;
    }
    mThreadWakeCondition.notify_all();
    mTracerThread.join();
}
      : mBackend(std::move(backend)) {}

std::unique_ptr<EventTrackerInterface> InputTracer::traceInboundEvent(const EventEntry& entry) {
    std::scoped_lock lock(mLock);
    TracedEvent traced;

    if (entry.type == EventEntry::Type::MOTION) {
@@ -89,7 +84,6 @@ std::unique_ptr<EventTrackerInterface> InputTracer::traceInboundEvent(const Even

void InputTracer::dispatchToTargetHint(const EventTrackerInterface& cookie,
                                       const InputTarget& target) {
    std::scoped_lock lock(mLock);
    auto& cookieState = getState(cookie);
    if (!cookieState) {
        LOG(FATAL) << "dispatchToTargetHint() should not be called after eventProcessingComplete()";
@@ -98,24 +92,20 @@ void InputTracer::dispatchToTargetHint(const EventTrackerInterface& cookie,
}

void InputTracer::eventProcessingComplete(const EventTrackerInterface& cookie) {
    {
        std::scoped_lock lock(mLock);
    auto& cookieState = getState(cookie);
    if (!cookieState) {
        LOG(FATAL) << "Traced event was already logged. "
                      "eventProcessingComplete() was likely called more than once.";
    }
        mTraceQueue.emplace_back(std::move(*cookieState));
        cookieState.reset();
    } // release lock

    mThreadWakeCondition.notify_all();
    std::visit(Visitor{[&](const TracedMotionEvent& e) { mBackend->traceMotionEvent(e); },
                       [&](const TracedKeyEvent& e) { mBackend->traceKeyEvent(e); }},
               cookieState->event);
    cookieState.reset();
}

void InputTracer::traceEventDispatch(const DispatchEntry& dispatchEntry,
                                     const EventTrackerInterface* cookie) {
    {
        std::scoped_lock lock(mLock);
    const EventEntry& entry = *dispatchEntry.eventEntry;

    TracedEvent traced;
@@ -131,82 +121,32 @@ void InputTracer::traceEventDispatch(const DispatchEntry& dispatchEntry,

    if (!cookie) {
        // This event was not tracked as an inbound event, so trace it now.
            mTraceQueue.emplace_back(traced);
        std::visit(Visitor{[&](const TracedMotionEvent& e) { mBackend->traceMotionEvent(e); },
                           [&](const TracedKeyEvent& e) { mBackend->traceKeyEvent(e); }},
                   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();
    mBackend->traceWindowDispatch({std::move(traced), dispatchEntry.deliveryTime,
                                   dispatchEntry.resolvedFlags, dispatchEntry.targetUid, vsyncId,
                                   windowId, dispatchEntry.transform, dispatchEntry.rawTransform,
                                   /*hmac=*/{}});
}

std::optional<InputTracer::EventState>& InputTracer::getState(const EventTrackerInterface& cookie) {
    return static_cast<const EventTrackerImpl&>(cookie).mLockedState;
}

void InputTracer::threadLoop() {
    androidSetThreadName("InputTracer");

    std::vector<const EventState> eventsToTrace;
    std::vector<const WindowDispatchArgs> dispatchEventsToTrace;

    while (true) {
        { // acquire lock
            std::unique_lock lock(mLock);
            base::ScopedLockAssertion assumeLocked(mLock);

            // Wait until we need to process more events or exit.
            mThreadWakeCondition.wait(lock, [&]() REQUIRES(mLock) {
                return mThreadExit || !mTraceQueue.empty() || !mDispatchTraceQueue.empty();
            });
            if (mThreadExit) {
                return;
            }

            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, dispatchEventsToTrace);
        eventsToTrace.clear();
        dispatchEventsToTrace.clear();
    }
}

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);
        } else {
            mBackend->traceKeyEvent(std::get<TracedKeyEvent>(event.event));
        }
    }

    for (const auto& dispatchArgs : dispatchEvents) {
        mBackend->traceWindowDispatch(dispatchArgs);
    }
    return static_cast<const EventTrackerImpl&>(cookie).mState;
}

// --- InputTracer::EventTrackerImpl ---

InputTracer::EventTrackerImpl::EventTrackerImpl(InputTracer& tracer, TracedEvent&& event)
      : mTracer(tracer), mLockedState(event) {}
      : mTracer(tracer), mState(event) {}

InputTracer::EventTrackerImpl::~EventTrackerImpl() {
    {
        std::scoped_lock lock(mTracer.mLock);
        if (!mLockedState) {
    if (!mState) {
        // This event has already been written to the trace as expected.
        return;
    }
@@ -214,11 +154,10 @@ InputTracer::EventTrackerImpl::~EventTrackerImpl() {
    // Write it to the trace now.
    // TODO(b/210460522): Determine why/where the event is being destroyed before
    //   eventProcessingComplete() is called.
        mTracer.mTraceQueue.emplace_back(std::move(*mLockedState));
        mLockedState.reset();
    } // release lock

    mTracer.mThreadWakeCondition.notify_all();
    std::visit(Visitor{[&](const TracedMotionEvent& e) { mTracer.mBackend->traceMotionEvent(e); },
                       [&](const TracedKeyEvent& e) { mTracer.mBackend->traceKeyEvent(e); }},
               mState->event);
    mState.reset();
}

} // namespace android::inputdispatcher::trace::impl
+9 −29
Original line number Diff line number Diff line
@@ -18,14 +18,7 @@

#include "InputTracerInterface.h"

#include <android-base/thread_annotations.h>
#include <gui/WindowInfo.h>

#include <memory>
#include <mutex>
#include <thread>
#include <unordered_set>
#include <vector>

#include "../Entry.h"
#include "InputTracingBackendInterface.h"
@@ -35,17 +28,16 @@ namespace android::inputdispatcher::trace::impl {
/**
 * The tracer implementation for InputDispatcher.
 *
 * InputTracer is thread-safe, so it can be called from any thread. Upon construction, InputTracer
 * will start its own thread that it uses for write events into the tracing backend. That is the
 * one and only thread that will interact with the tracing backend, since the Perfetto backend
 * uses thread-local storage.
 * InputTracer's responsibility is to keep track of events as they are processed by InputDispatcher,
 * and to write the events to the tracing backend when enough information is collected. InputTracer
 * is not thread-safe.
 *
 * See the documentation in InputTracerInterface for the API surface.
 */
class InputTracer : public InputTracerInterface {
public:
    explicit InputTracer(std::unique_ptr<InputTracingBackendInterface>);
    ~InputTracer() override;
    ~InputTracer() = default;
    InputTracer(const InputTracer&) = delete;
    InputTracer& operator=(const InputTracer&) = delete;

@@ -55,10 +47,6 @@ public:
    void traceEventDispatch(const DispatchEntry&, const EventTrackerInterface*) override;

private:
    std::mutex mLock;
    std::thread mTracerThread;
    bool mThreadExit GUARDED_BY(mLock){false};
    std::condition_variable mThreadWakeCondition;
    std::unique_ptr<InputTracingBackendInterface> mBackend;

    // The state of a tracked event.
@@ -67,14 +55,12 @@ private:
        // TODO(b/210460522): Add additional args for tracking event sensitivity and
        //  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);
    // Get the event state associated with a tracking cookie.
    std::optional<EventState>& getState(const EventTrackerInterface&);

    // Implementation of the event tracker cookie.
    // Implementation of the event tracker cookie. The cookie holds the event state directly for
    // convenience to avoid the overhead of tracking the state separately in InputTracer.
    class EventTrackerImpl : public EventTrackerInterface {
    public:
        explicit EventTrackerImpl(InputTracer&, TracedEvent&& entry);
@@ -84,16 +70,10 @@ private:
        InputTracer& mTracer;
        // This event tracker cookie will only hold the state as long as it has not been written
        // to the trace. The state is released when the event is written to the trace.
        mutable std::optional<EventState> mLockedState;
        mutable std::optional<EventState> mState;

        // Only allow InputTracer access to the locked state through getTrackerState() to ensure
        // that the InputTracer lock is held when this is accessed.
        friend std::optional<EventState>& InputTracer::getState(const EventTrackerInterface&);
    };

    void threadLoop();
    void writeEventsToBackend(const std::vector<const EventState>& events,
                              const std::vector<const WindowDispatchArgs>& dispatchEvents);
};

} // namespace android::inputdispatcher::trace::impl
+3 −3
Original line number Diff line number Diff line
@@ -82,10 +82,10 @@ public:
    virtual ~InputTracingBackendInterface() = default;

    /** Trace a KeyEvent. */
    virtual void traceKeyEvent(const TracedKeyEvent&) const = 0;
    virtual void traceKeyEvent(const TracedKeyEvent&) = 0;

    /** Trace a MotionEvent. */
    virtual void traceMotionEvent(const TracedMotionEvent&) const = 0;
    virtual void traceMotionEvent(const TracedMotionEvent&) = 0;

    /** Trace an event being sent to a window. */
    struct WindowDispatchArgs {
@@ -99,7 +99,7 @@ public:
        ui::Transform rawTransform;
        std::array<uint8_t, 32> hmac;
    };
    virtual void traceWindowDispatch(const WindowDispatchArgs&) const = 0;
    virtual void traceWindowDispatch(const WindowDispatchArgs&) = 0;
};

} // namespace android::inputdispatcher::trace
+3 −3
Original line number Diff line number Diff line
@@ -63,7 +63,7 @@ PerfettoBackend::PerfettoBackend() {
    });
}

void PerfettoBackend::traceMotionEvent(const TracedMotionEvent& event) const {
void PerfettoBackend::traceMotionEvent(const TracedMotionEvent& event) {
    InputEventDataSource::Trace([&](InputEventDataSource::TraceContext ctx) {
        auto tracePacket = ctx.NewTracePacket();
        auto* inputEvent = tracePacket->set_android_input_event();
@@ -72,7 +72,7 @@ void PerfettoBackend::traceMotionEvent(const TracedMotionEvent& event) const {
    });
}

void PerfettoBackend::traceKeyEvent(const TracedKeyEvent& event) const {
void PerfettoBackend::traceKeyEvent(const TracedKeyEvent& event) {
    InputEventDataSource::Trace([&](InputEventDataSource::TraceContext ctx) {
        auto tracePacket = ctx.NewTracePacket();
        auto* inputEvent = tracePacket->set_android_input_event();
@@ -81,7 +81,7 @@ void PerfettoBackend::traceKeyEvent(const TracedKeyEvent& event) const {
    });
}

void PerfettoBackend::traceWindowDispatch(const WindowDispatchArgs& dispatchArgs) const {
void PerfettoBackend::traceWindowDispatch(const WindowDispatchArgs& dispatchArgs) {
    InputEventDataSource::Trace([&](InputEventDataSource::TraceContext ctx) {
        auto tracePacket = ctx.NewTracePacket();
        auto* inputEventProto = tracePacket->set_android_input_event();
Loading