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