blob: 60f574d6c9845fee06a6907fdb3572bd3dba6392 [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>
22
23namespace android::inputdispatcher::trace::impl {
24
25namespace {
26
27TracedEvent createTracedEvent(const MotionEntry& e) {
28 return TracedMotionEvent{e.id,
29 e.eventTime,
30 e.policyFlags,
31 e.deviceId,
32 e.source,
33 e.displayId,
34 e.action,
35 e.actionButton,
36 e.flags,
37 e.metaState,
38 e.buttonState,
39 e.classification,
40 e.edgeFlags,
41 e.xPrecision,
42 e.yPrecision,
43 e.xCursorPosition,
44 e.yCursorPosition,
45 e.downTime,
46 e.pointerProperties,
47 e.pointerCoords};
48}
49
50TracedEvent createTracedEvent(const KeyEntry& e) {
51 return TracedKeyEvent{e.id, e.eventTime, e.policyFlags, e.deviceId, e.source,
52 e.displayId, e.action, e.keyCode, e.scanCode, e.metaState,
53 e.downTime, e.flags, e.repeatCount};
54}
55
56} // namespace
57
58// --- InputTracer ---
59
60InputTracer::InputTracer(std::unique_ptr<InputTracingBackendInterface> backend)
61 : mTracerThread(&InputTracer::threadLoop, this), mBackend(std::move(backend)) {}
62
63InputTracer::~InputTracer() {
64 {
65 std::scoped_lock lock(mLock);
66 mThreadExit = true;
67 }
68 mThreadWakeCondition.notify_all();
69 mTracerThread.join();
70}
71
72std::unique_ptr<EventTrackerInterface> InputTracer::traceInboundEvent(const EventEntry& entry) {
73 std::scoped_lock lock(mLock);
74 TracedEvent traced;
75
76 if (entry.type == EventEntry::Type::MOTION) {
77 const auto& motion = static_cast<const MotionEntry&>(entry);
78 traced = createTracedEvent(motion);
79 } else if (entry.type == EventEntry::Type::KEY) {
80 const auto& key = static_cast<const KeyEntry&>(entry);
81 traced = createTracedEvent(key);
82 } else {
83 LOG(FATAL) << "Cannot trace EventEntry of type: " << ftl::enum_string(entry.type);
84 }
85
86 return std::make_unique<EventTrackerImpl>(*this, std::move(traced));
87}
88
89void InputTracer::dispatchToTargetHint(const EventTrackerInterface& cookie,
90 const InputTarget& target) {
91 std::scoped_lock lock(mLock);
92 auto& cookieState = getState(cookie);
93 if (!cookieState) {
94 LOG(FATAL) << "dispatchToTargetHint() should not be called after eventProcessingComplete()";
95 }
96 // TODO(b/210460522): Determine if the event is sensitive based on the target.
97}
98
99void InputTracer::eventProcessingComplete(const EventTrackerInterface& cookie) {
100 {
101 std::scoped_lock lock(mLock);
102 auto& cookieState = getState(cookie);
103 if (!cookieState) {
104 LOG(FATAL) << "Traced event was already logged. "
105 "eventProcessingComplete() was likely called more than once.";
106 }
107 mTraceQueue.emplace_back(std::move(*cookieState));
108 cookieState.reset();
109 } // release lock
110
111 mThreadWakeCondition.notify_all();
112}
113
114void InputTracer::traceEventDispatch(const DispatchEntry& dispatchEntry,
115 const EventTrackerInterface* cookie) {}
116
117std::optional<InputTracer::EventState>& InputTracer::getState(const EventTrackerInterface& cookie) {
118 return static_cast<const EventTrackerImpl&>(cookie).mLockedState;
119}
120
121void InputTracer::threadLoop() {
122 while (true) {
123 std::vector<const EventState> eventsToTrace;
124 {
125 std::unique_lock lock(mLock);
126 base::ScopedLockAssertion assumeLocked(mLock);
127 if (mThreadExit) {
128 return;
129 }
130 if (mTraceQueue.empty()) {
131 // Wait indefinitely until the thread is awoken.
132 mThreadWakeCondition.wait(lock);
133 }
134
135 mTraceQueue.swap(eventsToTrace);
136 } // release lock
137
138 // Trace the events into the backend without holding the lock to reduce the amount of
139 // work performed in the critical section.
140 writeEventsToBackend(eventsToTrace);
141 eventsToTrace.clear();
142 }
143}
144
145void InputTracer::writeEventsToBackend(const std::vector<const EventState>& events) {
146 for (const auto& event : events) {
147 if (auto* motion = std::get_if<TracedMotionEvent>(&event.event); motion != nullptr) {
148 mBackend->traceMotionEvent(*motion);
149 } else {
150 mBackend->traceKeyEvent(std::get<TracedKeyEvent>(event.event));
151 }
152 }
153}
154
155// --- InputTracer::EventTrackerImpl ---
156
157InputTracer::EventTrackerImpl::EventTrackerImpl(InputTracer& tracer, TracedEvent&& event)
158 : mTracer(tracer), mLockedState(event) {}
159
160InputTracer::EventTrackerImpl::~EventTrackerImpl() {
161 {
162 std::scoped_lock lock(mTracer.mLock);
163 if (!mLockedState) {
164 // This event has already been written to the trace as expected.
165 return;
166 }
167 // We're still holding on to the state, which means it hasn't yet been written to the trace.
168 // Write it to the trace now.
169 // TODO(b/210460522): Determine why/where the event is being destroyed before
170 // eventProcessingComplete() is called.
171 mTracer.mTraceQueue.emplace_back(std::move(*mLockedState));
172 mLockedState.reset();
173 } // release lock
174
175 mTracer.mThreadWakeCondition.notify_all();
176}
177
178} // namespace android::inputdispatcher::trace::impl