• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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