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