blob: b065729873fc99bce5a2bc20bedee48bd53b4d10 [file] [log] [blame]
Prabir Pradhandae52792023-12-15 07:36:40 +00001/*
2 * Copyright 2024 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#define LOG_TAG "InputTracer"
18
19#include "InputTracer.h"
20
21#include <android-base/logging.h>
Prabir Pradhanadc59b42023-12-15 05:34:11 +000022#include <utils/AndroidThreads.h>
Prabir Pradhandae52792023-12-15 07:36:40 +000023
24namespace android::inputdispatcher::trace::impl {
25
26namespace {
27
28TracedEvent createTracedEvent(const MotionEntry& e) {
29 return TracedMotionEvent{e.id,
30 e.eventTime,
31 e.policyFlags,
32 e.deviceId,
33 e.source,
34 e.displayId,
35 e.action,
36 e.actionButton,
37 e.flags,
38 e.metaState,
39 e.buttonState,
40 e.classification,
41 e.edgeFlags,
42 e.xPrecision,
43 e.yPrecision,
44 e.xCursorPosition,
45 e.yCursorPosition,
46 e.downTime,
47 e.pointerProperties,
48 e.pointerCoords};
49}
50
51TracedEvent createTracedEvent(const KeyEntry& e) {
52 return TracedKeyEvent{e.id, e.eventTime, e.policyFlags, e.deviceId, e.source,
53 e.displayId, e.action, e.keyCode, e.scanCode, e.metaState,
54 e.downTime, e.flags, e.repeatCount};
55}
56
57} // namespace
58
59// --- InputTracer ---
60
61InputTracer::InputTracer(std::unique_ptr<InputTracingBackendInterface> backend)
62 : mTracerThread(&InputTracer::threadLoop, this), mBackend(std::move(backend)) {}
63
64InputTracer::~InputTracer() {
65 {
66 std::scoped_lock lock(mLock);
67 mThreadExit = true;
68 }
69 mThreadWakeCondition.notify_all();
70 mTracerThread.join();
71}
72
73std::unique_ptr<EventTrackerInterface> InputTracer::traceInboundEvent(const EventEntry& entry) {
74 std::scoped_lock lock(mLock);
75 TracedEvent traced;
76
77 if (entry.type == EventEntry::Type::MOTION) {
78 const auto& motion = static_cast<const MotionEntry&>(entry);
79 traced = createTracedEvent(motion);
80 } else if (entry.type == EventEntry::Type::KEY) {
81 const auto& key = static_cast<const KeyEntry&>(entry);
82 traced = createTracedEvent(key);
83 } else {
84 LOG(FATAL) << "Cannot trace EventEntry of type: " << ftl::enum_string(entry.type);
85 }
86
87 return std::make_unique<EventTrackerImpl>(*this, std::move(traced));
88}
89
90void InputTracer::dispatchToTargetHint(const EventTrackerInterface& cookie,
91 const InputTarget& target) {
92 std::scoped_lock lock(mLock);
93 auto& cookieState = getState(cookie);
94 if (!cookieState) {
95 LOG(FATAL) << "dispatchToTargetHint() should not be called after eventProcessingComplete()";
96 }
97 // TODO(b/210460522): Determine if the event is sensitive based on the target.
98}
99
100void InputTracer::eventProcessingComplete(const EventTrackerInterface& cookie) {
101 {
102 std::scoped_lock lock(mLock);
103 auto& cookieState = getState(cookie);
104 if (!cookieState) {
105 LOG(FATAL) << "Traced event was already logged. "
106 "eventProcessingComplete() was likely called more than once.";
107 }
108 mTraceQueue.emplace_back(std::move(*cookieState));
109 cookieState.reset();
110 } // release lock
111
112 mThreadWakeCondition.notify_all();
113}
114
115void InputTracer::traceEventDispatch(const DispatchEntry& dispatchEntry,
Prabir Pradhanadc59b42023-12-15 05:34:11 +0000116 const EventTrackerInterface* cookie) {
117 {
118 std::scoped_lock lock(mLock);
119 const EventEntry& entry = *dispatchEntry.eventEntry;
120
121 TracedEvent traced;
122 if (entry.type == EventEntry::Type::MOTION) {
123 const auto& motion = static_cast<const MotionEntry&>(entry);
124 traced = createTracedEvent(motion);
125 } else if (entry.type == EventEntry::Type::KEY) {
126 const auto& key = static_cast<const KeyEntry&>(entry);
127 traced = createTracedEvent(key);
128 } else {
129 LOG(FATAL) << "Cannot trace EventEntry of type: " << ftl::enum_string(entry.type);
130 }
131
132 if (!cookie) {
133 // This event was not tracked as an inbound event, so trace it now.
134 mTraceQueue.emplace_back(traced);
135 }
136
137 // The vsyncId only has meaning if the event is targeting a window.
138 const int32_t windowId = dispatchEntry.windowId.value_or(0);
139 const int32_t vsyncId = dispatchEntry.windowId.has_value() ? dispatchEntry.vsyncId : 0;
140
141 mDispatchTraceQueue.emplace_back(std::move(traced), dispatchEntry.deliveryTime,
142 dispatchEntry.resolvedFlags, dispatchEntry.targetUid,
143 vsyncId, windowId, dispatchEntry.transform,
144 dispatchEntry.rawTransform);
145 } // release lock
146
147 mThreadWakeCondition.notify_all();
148}
Prabir Pradhandae52792023-12-15 07:36:40 +0000149
150std::optional<InputTracer::EventState>& InputTracer::getState(const EventTrackerInterface& cookie) {
151 return static_cast<const EventTrackerImpl&>(cookie).mLockedState;
152}
153
154void InputTracer::threadLoop() {
Prabir Pradhanadc59b42023-12-15 05:34:11 +0000155 androidSetThreadName("InputTracer");
156
Prabir Pradhandae52792023-12-15 07:36:40 +0000157 while (true) {
158 std::vector<const EventState> eventsToTrace;
Prabir Pradhanadc59b42023-12-15 05:34:11 +0000159 std::vector<const WindowDispatchArgs> dispatchEventsToTrace;
Prabir Pradhandae52792023-12-15 07:36:40 +0000160 {
161 std::unique_lock lock(mLock);
162 base::ScopedLockAssertion assumeLocked(mLock);
163 if (mThreadExit) {
164 return;
165 }
Prabir Pradhanadc59b42023-12-15 05:34:11 +0000166 if (mTraceQueue.empty() && mDispatchTraceQueue.empty()) {
Prabir Pradhandae52792023-12-15 07:36:40 +0000167 // Wait indefinitely until the thread is awoken.
168 mThreadWakeCondition.wait(lock);
169 }
170
171 mTraceQueue.swap(eventsToTrace);
Prabir Pradhanadc59b42023-12-15 05:34:11 +0000172 mDispatchTraceQueue.swap(dispatchEventsToTrace);
Prabir Pradhandae52792023-12-15 07:36:40 +0000173 } // release lock
174
175 // Trace the events into the backend without holding the lock to reduce the amount of
176 // work performed in the critical section.
Prabir Pradhanadc59b42023-12-15 05:34:11 +0000177 writeEventsToBackend(eventsToTrace, dispatchEventsToTrace);
Prabir Pradhandae52792023-12-15 07:36:40 +0000178 eventsToTrace.clear();
Prabir Pradhanadc59b42023-12-15 05:34:11 +0000179 dispatchEventsToTrace.clear();
Prabir Pradhandae52792023-12-15 07:36:40 +0000180 }
181}
182
Prabir Pradhanadc59b42023-12-15 05:34:11 +0000183void InputTracer::writeEventsToBackend(
184 const std::vector<const EventState>& events,
185 const std::vector<const WindowDispatchArgs>& dispatchEvents) {
Prabir Pradhandae52792023-12-15 07:36:40 +0000186 for (const auto& event : events) {
187 if (auto* motion = std::get_if<TracedMotionEvent>(&event.event); motion != nullptr) {
188 mBackend->traceMotionEvent(*motion);
189 } else {
190 mBackend->traceKeyEvent(std::get<TracedKeyEvent>(event.event));
191 }
192 }
Prabir Pradhanadc59b42023-12-15 05:34:11 +0000193
194 for (const auto& dispatchArgs : dispatchEvents) {
195 mBackend->traceWindowDispatch(dispatchArgs);
196 }
Prabir Pradhandae52792023-12-15 07:36:40 +0000197}
198
199// --- InputTracer::EventTrackerImpl ---
200
201InputTracer::EventTrackerImpl::EventTrackerImpl(InputTracer& tracer, TracedEvent&& event)
202 : mTracer(tracer), mLockedState(event) {}
203
204InputTracer::EventTrackerImpl::~EventTrackerImpl() {
205 {
206 std::scoped_lock lock(mTracer.mLock);
207 if (!mLockedState) {
208 // This event has already been written to the trace as expected.
209 return;
210 }
211 // We're still holding on to the state, which means it hasn't yet been written to the trace.
212 // Write it to the trace now.
213 // TODO(b/210460522): Determine why/where the event is being destroyed before
214 // eventProcessingComplete() is called.
215 mTracer.mTraceQueue.emplace_back(std::move(*mLockedState));
216 mLockedState.reset();
217 } // release lock
218
219 mTracer.mThreadWakeCondition.notify_all();
220}
221
222} // namespace android::inputdispatcher::trace::impl