1 /*
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 "InputTracingPerfettoBackend.h"
20
21 #include "AndroidInputEventProtoConverter.h"
22
23 #include <android-base/logging.h>
24 #include <binder/IServiceManager.h>
25 #include <perfetto/trace/android/android_input_event.pbzero.h>
26 #include <perfetto/trace/android/winscope_extensions.pbzero.h>
27 #include <perfetto/trace/android/winscope_extensions_impl.pbzero.h>
28 #include <private/android_filesystem_config.h>
29 #include <utils/String16.h>
30
31 namespace android::inputdispatcher::trace::impl {
32
33 namespace {
34
35 constexpr auto INPUT_EVENT_TRACE_DATA_SOURCE_NAME = "android.input.inputevent";
36
isPermanentlyAllowed(gui::Uid uid)37 bool isPermanentlyAllowed(gui::Uid uid) {
38 switch (uid.val()) {
39 case AID_SYSTEM:
40 case AID_SHELL:
41 case AID_ROOT:
42 return true;
43 default:
44 return false;
45 }
46 }
47
getPackageManager()48 sp<content::pm::IPackageManagerNative> getPackageManager() {
49 sp<IServiceManager> serviceManager = defaultServiceManager();
50 if (!serviceManager) {
51 LOG(ERROR) << __func__ << ": unable to access native ServiceManager";
52 return nullptr;
53 }
54
55 sp<IBinder> binder = serviceManager->waitForService(String16("package_native"));
56 auto packageManager = interface_cast<content::pm::IPackageManagerNative>(binder);
57 if (!packageManager) {
58 LOG(ERROR) << ": unable to access native PackageManager";
59 return nullptr;
60 }
61 return packageManager;
62 }
63
getPackageUid(const sp<content::pm::IPackageManagerNative> & pm,const std::string & package)64 gui::Uid getPackageUid(const sp<content::pm::IPackageManagerNative>& pm,
65 const std::string& package) {
66 int32_t outUid = -1;
67 if (auto status = pm->getPackageUid(package, /*flags=*/0, AID_SYSTEM, &outUid);
68 !status.isOk()) {
69 LOG(INFO) << "Failed to get package UID from native package manager for package '"
70 << package << "': " << status;
71 return gui::Uid::INVALID;
72 }
73 return gui::Uid{static_cast<uid_t>(outUid)};
74 }
75
76 } // namespace
77
78 // --- PerfettoBackend::InputEventDataSource ---
79
InputEventDataSource()80 PerfettoBackend::InputEventDataSource::InputEventDataSource() : mInstanceId(sNextInstanceId++) {}
81
OnSetup(const InputEventDataSource::SetupArgs & args)82 void PerfettoBackend::InputEventDataSource::OnSetup(const InputEventDataSource::SetupArgs& args) {
83 LOG(INFO) << "Setting up perfetto trace for: " << INPUT_EVENT_TRACE_DATA_SOURCE_NAME
84 << ", instanceId: " << mInstanceId;
85 const auto rawConfig = args.config->android_input_event_config_raw();
86 auto protoConfig = perfetto::protos::pbzero::AndroidInputEventConfig::Decoder{rawConfig};
87
88 mConfig = AndroidInputEventProtoConverter::parseConfig(protoConfig);
89 }
90
OnStart(const InputEventDataSource::StartArgs &)91 void PerfettoBackend::InputEventDataSource::OnStart(const InputEventDataSource::StartArgs&) {
92 LOG(INFO) << "Starting perfetto trace for: " << INPUT_EVENT_TRACE_DATA_SOURCE_NAME
93 << ", instanceId: " << mInstanceId;
94 }
95
OnStop(const InputEventDataSource::StopArgs &)96 void PerfettoBackend::InputEventDataSource::OnStop(const InputEventDataSource::StopArgs&) {
97 LOG(INFO) << "Stopping perfetto trace for: " << INPUT_EVENT_TRACE_DATA_SOURCE_NAME
98 << ", instanceId: " << mInstanceId;
99 InputEventDataSource::Trace([&](InputEventDataSource::TraceContext ctx) { ctx.Flush(); });
100 }
101
initializeUidMap()102 void PerfettoBackend::InputEventDataSource::initializeUidMap() {
103 if (mUidMap.has_value()) {
104 return;
105 }
106
107 mUidMap = {{}};
108 auto packageManager = PerfettoBackend::sPackageManagerProvider();
109 if (!packageManager) {
110 LOG(ERROR) << "Failed to initialize UID map: Could not get native package manager";
111 return;
112 }
113
114 for (const auto& rule : mConfig.rules) {
115 for (const auto& package : rule.matchAllPackages) {
116 mUidMap->emplace(package, getPackageUid(packageManager, package));
117 }
118 for (const auto& package : rule.matchAnyPackages) {
119 mUidMap->emplace(package, getPackageUid(packageManager, package));
120 }
121 }
122 }
123
shouldIgnoreTracedInputEvent(const EventType & type) const124 bool PerfettoBackend::InputEventDataSource::shouldIgnoreTracedInputEvent(
125 const EventType& type) const {
126 if (!getFlags().test(TraceFlag::TRACE_DISPATCHER_INPUT_EVENTS)) {
127 // Ignore all input events.
128 return true;
129 }
130 if (!getFlags().test(TraceFlag::TRACE_DISPATCHER_WINDOW_DISPATCH) &&
131 type != EventType::INBOUND) {
132 // When window dispatch tracing is disabled, ignore any events that are not inbound events.
133 return true;
134 }
135 return false;
136 }
137
resolveTraceLevel(const TracedEventMetadata & metadata) const138 TraceLevel PerfettoBackend::InputEventDataSource::resolveTraceLevel(
139 const TracedEventMetadata& metadata) const {
140 // Check for matches with the rules in the order that they are defined.
141 for (const auto& rule : mConfig.rules) {
142 if (ruleMatches(rule, metadata)) {
143 return rule.level;
144 }
145 }
146 // The event is not traced if it matched zero rules.
147 return TraceLevel::TRACE_LEVEL_NONE;
148 }
149
ruleMatches(const TraceRule & rule,const TracedEventMetadata & metadata) const150 bool PerfettoBackend::InputEventDataSource::ruleMatches(const TraceRule& rule,
151 const TracedEventMetadata& metadata) const {
152 // By default, a rule will match all events. Return early if the rule does not match.
153
154 // Match the event if it is directed to a secure window.
155 if (rule.matchSecure.has_value() && *rule.matchSecure != metadata.isSecure) {
156 return false;
157 }
158
159 // Match the event if it was processed while there was an active InputMethod connection.
160 if (rule.matchImeConnectionActive.has_value() &&
161 *rule.matchImeConnectionActive != metadata.isImeConnectionActive) {
162 return false;
163 }
164
165 // Match the event if all of its target packages are explicitly allowed in the "match all" list.
166 if (!rule.matchAllPackages.empty() &&
167 !std::all_of(metadata.targets.begin(), metadata.targets.end(), [&](const auto& uid) {
168 return isPermanentlyAllowed(uid) ||
169 std::any_of(rule.matchAllPackages.begin(), rule.matchAllPackages.end(),
170 [&](const auto& pkg) { return uid == mUidMap->at(pkg); });
171 })) {
172 return false;
173 }
174
175 // Match the event if any of its target packages are allowed in the "match any" list.
176 if (!rule.matchAnyPackages.empty() &&
177 !std::any_of(metadata.targets.begin(), metadata.targets.end(), [&](const auto& uid) {
178 return std::any_of(rule.matchAnyPackages.begin(), rule.matchAnyPackages.end(),
179 [&](const auto& pkg) { return uid == mUidMap->at(pkg); });
180 })) {
181 return false;
182 }
183
184 // The event matches all matchers specified in the rule.
185 return true;
186 }
187
188 // --- PerfettoBackend ---
189
190 bool PerfettoBackend::sUseInProcessBackendForTest{false};
191
192 std::function<sp<content::pm::IPackageManagerNative>()> PerfettoBackend::sPackageManagerProvider{
193 &getPackageManager};
194
195 std::once_flag PerfettoBackend::sDataSourceRegistrationFlag{};
196
197 std::atomic<int32_t> PerfettoBackend::sNextInstanceId{1};
198
PerfettoBackend()199 PerfettoBackend::PerfettoBackend() {
200 // Use a once-flag to ensure that the data source is only registered once per boot, since
201 // we never unregister the InputEventDataSource.
202 std::call_once(sDataSourceRegistrationFlag, []() {
203 perfetto::TracingInitArgs args;
204 args.backends = sUseInProcessBackendForTest ? perfetto::kInProcessBackend
205 : perfetto::kSystemBackend;
206 perfetto::Tracing::Initialize(args);
207
208 // Register our custom data source for input event tracing.
209 perfetto::DataSourceDescriptor dsd;
210 dsd.set_name(INPUT_EVENT_TRACE_DATA_SOURCE_NAME);
211 InputEventDataSource::Register(dsd);
212 LOG(INFO) << "InputTracer initialized for data source: "
213 << INPUT_EVENT_TRACE_DATA_SOURCE_NAME;
214 });
215 }
216
traceMotionEvent(const TracedMotionEvent & event,const TracedEventMetadata & metadata)217 void PerfettoBackend::traceMotionEvent(const TracedMotionEvent& event,
218 const TracedEventMetadata& metadata) {
219 InputEventDataSource::Trace([&](InputEventDataSource::TraceContext ctx) {
220 auto dataSource = ctx.GetDataSourceLocked();
221 if (!dataSource.valid()) {
222 return;
223 }
224 dataSource->initializeUidMap();
225 if (dataSource->shouldIgnoreTracedInputEvent(event.eventType)) {
226 return;
227 }
228 const TraceLevel traceLevel = dataSource->resolveTraceLevel(metadata);
229 if (traceLevel == TraceLevel::TRACE_LEVEL_NONE) {
230 return;
231 }
232 const bool isRedacted = traceLevel == TraceLevel::TRACE_LEVEL_REDACTED;
233 auto tracePacket = ctx.NewTracePacket();
234 tracePacket->set_timestamp(metadata.processingTimestamp);
235 tracePacket->set_timestamp_clock_id(perfetto::protos::pbzero::BUILTIN_CLOCK_MONOTONIC);
236 auto* winscopeExtensions = static_cast<perfetto::protos::pbzero::WinscopeExtensionsImpl*>(
237 tracePacket->set_winscope_extensions());
238 auto* inputEvent = winscopeExtensions->set_android_input_event();
239 auto* dispatchMotion = isRedacted ? inputEvent->set_dispatcher_motion_event_redacted()
240 : inputEvent->set_dispatcher_motion_event();
241 AndroidInputEventProtoConverter::toProtoMotionEvent(event, *dispatchMotion, isRedacted);
242 });
243 }
244
traceKeyEvent(const TracedKeyEvent & event,const TracedEventMetadata & metadata)245 void PerfettoBackend::traceKeyEvent(const TracedKeyEvent& event,
246 const TracedEventMetadata& metadata) {
247 InputEventDataSource::Trace([&](InputEventDataSource::TraceContext ctx) {
248 auto dataSource = ctx.GetDataSourceLocked();
249 if (!dataSource.valid()) {
250 return;
251 }
252 dataSource->initializeUidMap();
253 if (dataSource->shouldIgnoreTracedInputEvent(event.eventType)) {
254 return;
255 }
256 const TraceLevel traceLevel = dataSource->resolveTraceLevel(metadata);
257 if (traceLevel == TraceLevel::TRACE_LEVEL_NONE) {
258 return;
259 }
260 const bool isRedacted = traceLevel == TraceLevel::TRACE_LEVEL_REDACTED;
261 auto tracePacket = ctx.NewTracePacket();
262 tracePacket->set_timestamp(metadata.processingTimestamp);
263 tracePacket->set_timestamp_clock_id(perfetto::protos::pbzero::BUILTIN_CLOCK_MONOTONIC);
264 auto* winscopeExtensions = static_cast<perfetto::protos::pbzero::WinscopeExtensionsImpl*>(
265 tracePacket->set_winscope_extensions());
266 auto* inputEvent = winscopeExtensions->set_android_input_event();
267 auto* dispatchKey = isRedacted ? inputEvent->set_dispatcher_key_event_redacted()
268 : inputEvent->set_dispatcher_key_event();
269 AndroidInputEventProtoConverter::toProtoKeyEvent(event, *dispatchKey, isRedacted);
270 });
271 }
272
traceWindowDispatch(const WindowDispatchArgs & dispatchArgs,const TracedEventMetadata & metadata)273 void PerfettoBackend::traceWindowDispatch(const WindowDispatchArgs& dispatchArgs,
274 const TracedEventMetadata& metadata) {
275 InputEventDataSource::Trace([&](InputEventDataSource::TraceContext ctx) {
276 auto dataSource = ctx.GetDataSourceLocked();
277 if (!dataSource.valid()) {
278 return;
279 }
280 dataSource->initializeUidMap();
281 if (!dataSource->getFlags().test(TraceFlag::TRACE_DISPATCHER_WINDOW_DISPATCH)) {
282 return;
283 }
284 const TraceLevel traceLevel = dataSource->resolveTraceLevel(metadata);
285 if (traceLevel == TraceLevel::TRACE_LEVEL_NONE) {
286 return;
287 }
288 const bool isRedacted = traceLevel == TraceLevel::TRACE_LEVEL_REDACTED;
289 auto tracePacket = ctx.NewTracePacket();
290 tracePacket->set_timestamp(dispatchArgs.deliveryTime);
291 tracePacket->set_timestamp_clock_id(perfetto::protos::pbzero::BUILTIN_CLOCK_MONOTONIC);
292 auto* winscopeExtensions = static_cast<perfetto::protos::pbzero::WinscopeExtensionsImpl*>(
293 tracePacket->set_winscope_extensions());
294 auto* inputEvent = winscopeExtensions->set_android_input_event();
295 auto* dispatchEvent = isRedacted
296 ? inputEvent->set_dispatcher_window_dispatch_event_redacted()
297 : inputEvent->set_dispatcher_window_dispatch_event();
298 AndroidInputEventProtoConverter::toProtoWindowDispatchEvent(dispatchArgs, *dispatchEvent,
299 isRedacted);
300 });
301 }
302
303 } // namespace android::inputdispatcher::trace::impl
304