blob: 4f618851623408a3cf0f0333a06dfb95ddddc3ed [file] [log] [blame]
Prabir Pradhanbb7a0202024-02-10 02:09:01 +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 "ThreadedBackend.h"
20
21#include "InputTracingPerfettoBackend.h"
22
23#include <android-base/logging.h>
Prabir Pradhanbb7a0202024-02-10 02:09:01 +000024
25namespace android::inputdispatcher::trace::impl {
26
27namespace {
28
29// Helper to std::visit with lambdas.
30template <typename... V>
31struct Visitor : V... {
32 using V::operator()...;
33};
34
35} // namespace
36
37// --- ThreadedBackend ---
38
39template <typename Backend>
40ThreadedBackend<Backend>::ThreadedBackend(Backend&& innerBackend)
Prabir Pradhan1cdb2fa2024-03-19 17:21:45 +000041 : mBackend(std::move(innerBackend)),
42 mTracerThread(
Prabir Pradhan47827682024-02-23 19:31:43 +000043 "InputTracer", [this]() { threadLoop(); },
Siarhei Vishniakouf53fa6b2024-09-19 17:42:42 -070044 [this]() { mThreadWakeCondition.notify_all(); }, /*isInCriticalPath=*/false) {}
Prabir Pradhanbb7a0202024-02-10 02:09:01 +000045
46template <typename Backend>
47ThreadedBackend<Backend>::~ThreadedBackend() {
48 {
49 std::scoped_lock lock(mLock);
50 mThreadExit = true;
51 }
52 mThreadWakeCondition.notify_all();
Prabir Pradhanbb7a0202024-02-10 02:09:01 +000053}
54
55template <typename Backend>
Prabir Pradhan8c3b1432024-02-09 23:34:16 +000056void ThreadedBackend<Backend>::traceMotionEvent(const TracedMotionEvent& event,
Prabir Pradhanc7edaaa2024-03-15 15:31:02 +000057 const TracedEventMetadata& metadata) {
Prabir Pradhanbb7a0202024-02-10 02:09:01 +000058 std::scoped_lock lock(mLock);
Prabir Pradhanc7edaaa2024-03-15 15:31:02 +000059 mQueue.emplace_back(event, metadata);
Prabir Pradhan6c0de2b2024-04-11 16:59:22 +000060 setIdleStatus(false);
Prabir Pradhanbb7a0202024-02-10 02:09:01 +000061 mThreadWakeCondition.notify_all();
62}
63
64template <typename Backend>
Prabir Pradhan8c3b1432024-02-09 23:34:16 +000065void ThreadedBackend<Backend>::traceKeyEvent(const TracedKeyEvent& event,
Prabir Pradhanc7edaaa2024-03-15 15:31:02 +000066 const TracedEventMetadata& metadata) {
Prabir Pradhanbb7a0202024-02-10 02:09:01 +000067 std::scoped_lock lock(mLock);
Prabir Pradhanc7edaaa2024-03-15 15:31:02 +000068 mQueue.emplace_back(event, metadata);
Prabir Pradhan6c0de2b2024-04-11 16:59:22 +000069 setIdleStatus(false);
Prabir Pradhanbb7a0202024-02-10 02:09:01 +000070 mThreadWakeCondition.notify_all();
71}
72
73template <typename Backend>
Prabir Pradhan8c3b1432024-02-09 23:34:16 +000074void ThreadedBackend<Backend>::traceWindowDispatch(const WindowDispatchArgs& dispatchArgs,
Prabir Pradhanc7edaaa2024-03-15 15:31:02 +000075 const TracedEventMetadata& metadata) {
Prabir Pradhanbb7a0202024-02-10 02:09:01 +000076 std::scoped_lock lock(mLock);
Prabir Pradhanc7edaaa2024-03-15 15:31:02 +000077 mQueue.emplace_back(dispatchArgs, metadata);
Prabir Pradhan6c0de2b2024-04-11 16:59:22 +000078 setIdleStatus(false);
Prabir Pradhanbb7a0202024-02-10 02:09:01 +000079 mThreadWakeCondition.notify_all();
80}
81
82template <typename Backend>
83void ThreadedBackend<Backend>::threadLoop() {
Prabir Pradhan47827682024-02-23 19:31:43 +000084 std::vector<TraceEntry> entries;
Prabir Pradhanbb7a0202024-02-10 02:09:01 +000085
Prabir Pradhan47827682024-02-23 19:31:43 +000086 { // acquire lock
87 std::unique_lock lock(mLock);
88 base::ScopedLockAssertion assumeLocked(mLock);
Prabir Pradhanbb7a0202024-02-10 02:09:01 +000089
Prabir Pradhan6c0de2b2024-04-11 16:59:22 +000090 if (mQueue.empty()) {
91 setIdleStatus(true);
92 }
Prabir Pradhan9a9897d2024-03-21 21:52:57 +000093
Prabir Pradhan47827682024-02-23 19:31:43 +000094 // Wait until we need to process more events or exit.
95 mThreadWakeCondition.wait(lock,
96 [&]() REQUIRES(mLock) { return mThreadExit || !mQueue.empty(); });
97 if (mThreadExit) {
Prabir Pradhan9a9897d2024-03-21 21:52:57 +000098 setIdleStatus(true);
Prabir Pradhan47827682024-02-23 19:31:43 +000099 return;
Prabir Pradhanbb7a0202024-02-10 02:09:01 +0000100 }
Prabir Pradhan47827682024-02-23 19:31:43 +0000101
102 mQueue.swap(entries);
103 } // release lock
104
105 // Trace the events into the backend without holding the lock to reduce the amount of
106 // work performed in the critical section.
Prabir Pradhan8c3b1432024-02-09 23:34:16 +0000107 for (const auto& [entry, traceArgs] : entries) {
108 std::visit(Visitor{[&](const TracedMotionEvent& e) {
109 mBackend.traceMotionEvent(e, traceArgs);
110 },
111 [&](const TracedKeyEvent& e) { mBackend.traceKeyEvent(e, traceArgs); },
Prabir Pradhan47827682024-02-23 19:31:43 +0000112 [&](const WindowDispatchArgs& args) {
Prabir Pradhan8c3b1432024-02-09 23:34:16 +0000113 mBackend.traceWindowDispatch(args, traceArgs);
Prabir Pradhan47827682024-02-23 19:31:43 +0000114 }},
115 entry);
Prabir Pradhanbb7a0202024-02-10 02:09:01 +0000116 }
Prabir Pradhan47827682024-02-23 19:31:43 +0000117 entries.clear();
Prabir Pradhanbb7a0202024-02-10 02:09:01 +0000118}
119
Prabir Pradhan9a9897d2024-03-21 21:52:57 +0000120template <typename Backend>
121std::function<void()> ThreadedBackend<Backend>::getIdleWaiterForTesting() {
122 std::scoped_lock lock(mLock);
123 if (!mIdleWaiter) {
124 mIdleWaiter = std::make_shared<IdleWaiter>();
125 }
126
127 // Return a lambda that holds a strong reference to the idle waiter, whose lifetime can extend
128 // beyond this threaded backend object.
129 return [idleWaiter = mIdleWaiter]() {
130 std::unique_lock idleLock(idleWaiter->idleLock);
131 base::ScopedLockAssertion assumeLocked(idleWaiter->idleLock);
132 idleWaiter->threadIdleCondition.wait(idleLock, [&]() REQUIRES(idleWaiter->idleLock) {
133 return idleWaiter->isIdle;
134 });
135 };
136}
137
138template <typename Backend>
139void ThreadedBackend<Backend>::setIdleStatus(bool isIdle) {
140 if (!mIdleWaiter) {
141 return;
142 }
143 std::scoped_lock idleLock(mIdleWaiter->idleLock);
144 mIdleWaiter->isIdle = isIdle;
145 if (isIdle) {
146 mIdleWaiter->threadIdleCondition.notify_all();
147 }
148}
149
Prabir Pradhanbb7a0202024-02-10 02:09:01 +0000150// Explicit template instantiation for the PerfettoBackend.
151template class ThreadedBackend<PerfettoBackend>;
152
153} // namespace android::inputdispatcher::trace::impl