xref: /aosp_15_r20/frameworks/native/services/inputflinger/InputDeviceMetricsCollector.h (revision 38e8c45f13ce32b0dcecb25141ffecaf386fa17f)
1*38e8c45fSAndroid Build Coastguard Worker /*
2*38e8c45fSAndroid Build Coastguard Worker  * Copyright 2023 The Android Open Source Project
3*38e8c45fSAndroid Build Coastguard Worker  *
4*38e8c45fSAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*38e8c45fSAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*38e8c45fSAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*38e8c45fSAndroid Build Coastguard Worker  *
8*38e8c45fSAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*38e8c45fSAndroid Build Coastguard Worker  *
10*38e8c45fSAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*38e8c45fSAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*38e8c45fSAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*38e8c45fSAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*38e8c45fSAndroid Build Coastguard Worker  * limitations under the License.
15*38e8c45fSAndroid Build Coastguard Worker  */
16*38e8c45fSAndroid Build Coastguard Worker 
17*38e8c45fSAndroid Build Coastguard Worker #pragma once
18*38e8c45fSAndroid Build Coastguard Worker 
19*38e8c45fSAndroid Build Coastguard Worker #include "InputDeviceMetricsSource.h"
20*38e8c45fSAndroid Build Coastguard Worker #include "InputListener.h"
21*38e8c45fSAndroid Build Coastguard Worker #include "NotifyArgs.h"
22*38e8c45fSAndroid Build Coastguard Worker #include "SyncQueue.h"
23*38e8c45fSAndroid Build Coastguard Worker 
24*38e8c45fSAndroid Build Coastguard Worker #include <android-base/thread_annotations.h>
25*38e8c45fSAndroid Build Coastguard Worker #include <ftl/mixins.h>
26*38e8c45fSAndroid Build Coastguard Worker #include <gui/WindowInfo.h>
27*38e8c45fSAndroid Build Coastguard Worker #include <input/InputDevice.h>
28*38e8c45fSAndroid Build Coastguard Worker #include <chrono>
29*38e8c45fSAndroid Build Coastguard Worker #include <functional>
30*38e8c45fSAndroid Build Coastguard Worker #include <map>
31*38e8c45fSAndroid Build Coastguard Worker #include <mutex>
32*38e8c45fSAndroid Build Coastguard Worker #include <set>
33*38e8c45fSAndroid Build Coastguard Worker #include <vector>
34*38e8c45fSAndroid Build Coastguard Worker 
35*38e8c45fSAndroid Build Coastguard Worker namespace android {
36*38e8c45fSAndroid Build Coastguard Worker 
37*38e8c45fSAndroid Build Coastguard Worker /**
38*38e8c45fSAndroid Build Coastguard Worker  * Logs metrics about registered input devices and their usages.
39*38e8c45fSAndroid Build Coastguard Worker  */
40*38e8c45fSAndroid Build Coastguard Worker class InputDeviceMetricsCollectorInterface : public InputListenerInterface {
41*38e8c45fSAndroid Build Coastguard Worker public:
42*38e8c45fSAndroid Build Coastguard Worker     /**
43*38e8c45fSAndroid Build Coastguard Worker      * Notify the metrics collector that there was an input device interaction with apps.
44*38e8c45fSAndroid Build Coastguard Worker      * Called from the InputDispatcher thread.
45*38e8c45fSAndroid Build Coastguard Worker      */
46*38e8c45fSAndroid Build Coastguard Worker     virtual void notifyDeviceInteraction(int32_t deviceId, nsecs_t timestamp,
47*38e8c45fSAndroid Build Coastguard Worker                                          const std::set<gui::Uid>& uids) = 0;
48*38e8c45fSAndroid Build Coastguard Worker     /**
49*38e8c45fSAndroid Build Coastguard Worker      * Dump the state of the interaction blocker.
50*38e8c45fSAndroid Build Coastguard Worker      * This method may be called on any thread (usually by the input manager on a binder thread).
51*38e8c45fSAndroid Build Coastguard Worker      */
52*38e8c45fSAndroid Build Coastguard Worker     virtual void dump(std::string& dump) = 0;
53*38e8c45fSAndroid Build Coastguard Worker 
54*38e8c45fSAndroid Build Coastguard Worker     /** Called by the heartbeat to ensure that this component has not deadlocked. */
55*38e8c45fSAndroid Build Coastguard Worker     virtual void monitor() = 0;
56*38e8c45fSAndroid Build Coastguard Worker };
57*38e8c45fSAndroid Build Coastguard Worker 
58*38e8c45fSAndroid Build Coastguard Worker /** The logging interface for the metrics collector, injected for testing. */
59*38e8c45fSAndroid Build Coastguard Worker class InputDeviceMetricsLogger {
60*38e8c45fSAndroid Build Coastguard Worker public:
61*38e8c45fSAndroid Build Coastguard Worker     virtual std::chrono::nanoseconds getCurrentTime() = 0;
62*38e8c45fSAndroid Build Coastguard Worker 
63*38e8c45fSAndroid Build Coastguard Worker     // Describes the breakdown of an input device usage session by its usage sources.
64*38e8c45fSAndroid Build Coastguard Worker     // An input device can have more than one usage source. For example, some game controllers have
65*38e8c45fSAndroid Build Coastguard Worker     // buttons, joysticks, and touchpads. We track usage by these sources to get a better picture of
66*38e8c45fSAndroid Build Coastguard Worker     // the device usage. The source breakdown of a 10 minute usage session could look like this:
67*38e8c45fSAndroid Build Coastguard Worker     //   { {GAMEPAD, <9 mins>}, {TOUCHPAD, <2 mins>}, {TOUCHPAD, <3 mins>} }
68*38e8c45fSAndroid Build Coastguard Worker     // This would indicate that the GAMEPAD source was used first, and that source usage session
69*38e8c45fSAndroid Build Coastguard Worker     // lasted for 9 mins. During that time, the TOUCHPAD was used for 2 mins, until its source
70*38e8c45fSAndroid Build Coastguard Worker     // usage session expired. The TOUCHPAD was then used again later for another 3 mins.
71*38e8c45fSAndroid Build Coastguard Worker     using SourceUsageBreakdown =
72*38e8c45fSAndroid Build Coastguard Worker             std::vector<std::pair<InputDeviceUsageSource, std::chrono::nanoseconds /*duration*/>>;
73*38e8c45fSAndroid Build Coastguard Worker 
74*38e8c45fSAndroid Build Coastguard Worker     // Describes the breakdown of an input device usage session by the UIDs that it interacted with.
75*38e8c45fSAndroid Build Coastguard Worker     using UidUsageBreakdown =
76*38e8c45fSAndroid Build Coastguard Worker             std::vector<std::pair<gui::Uid, std::chrono::nanoseconds /*duration*/>>;
77*38e8c45fSAndroid Build Coastguard Worker 
78*38e8c45fSAndroid Build Coastguard Worker     struct DeviceUsageReport {
79*38e8c45fSAndroid Build Coastguard Worker         std::chrono::nanoseconds usageDuration;
80*38e8c45fSAndroid Build Coastguard Worker         SourceUsageBreakdown sourceBreakdown;
81*38e8c45fSAndroid Build Coastguard Worker         UidUsageBreakdown uidBreakdown;
82*38e8c45fSAndroid Build Coastguard Worker     };
83*38e8c45fSAndroid Build Coastguard Worker 
84*38e8c45fSAndroid Build Coastguard Worker     // A subset of information from the InputDeviceInfo class that is used for metrics collection,
85*38e8c45fSAndroid Build Coastguard Worker     // used to avoid copying and storing all of the fields and strings in InputDeviceInfo.
86*38e8c45fSAndroid Build Coastguard Worker     struct MetricsDeviceInfo {
87*38e8c45fSAndroid Build Coastguard Worker         int32_t deviceId;
88*38e8c45fSAndroid Build Coastguard Worker         int32_t vendor;
89*38e8c45fSAndroid Build Coastguard Worker         int32_t product;
90*38e8c45fSAndroid Build Coastguard Worker         int32_t version;
91*38e8c45fSAndroid Build Coastguard Worker         int32_t bus;
92*38e8c45fSAndroid Build Coastguard Worker         bool isUsiStylus;
93*38e8c45fSAndroid Build Coastguard Worker         int32_t keyboardType;
94*38e8c45fSAndroid Build Coastguard Worker     };
95*38e8c45fSAndroid Build Coastguard Worker     virtual void logInputDeviceUsageReported(const MetricsDeviceInfo&,
96*38e8c45fSAndroid Build Coastguard Worker                                              const DeviceUsageReport&) = 0;
97*38e8c45fSAndroid Build Coastguard Worker     virtual ~InputDeviceMetricsLogger() = default;
98*38e8c45fSAndroid Build Coastguard Worker };
99*38e8c45fSAndroid Build Coastguard Worker 
100*38e8c45fSAndroid Build Coastguard Worker class InputDeviceMetricsCollector : public InputDeviceMetricsCollectorInterface {
101*38e8c45fSAndroid Build Coastguard Worker public:
102*38e8c45fSAndroid Build Coastguard Worker     explicit InputDeviceMetricsCollector(InputListenerInterface& listener);
103*38e8c45fSAndroid Build Coastguard Worker     ~InputDeviceMetricsCollector() override = default;
104*38e8c45fSAndroid Build Coastguard Worker 
105*38e8c45fSAndroid Build Coastguard Worker     // Test constructor
106*38e8c45fSAndroid Build Coastguard Worker     InputDeviceMetricsCollector(InputListenerInterface& listener, InputDeviceMetricsLogger& logger,
107*38e8c45fSAndroid Build Coastguard Worker                                 std::chrono::nanoseconds usageSessionTimeout);
108*38e8c45fSAndroid Build Coastguard Worker 
109*38e8c45fSAndroid Build Coastguard Worker     void notifyInputDevicesChanged(const NotifyInputDevicesChangedArgs& args) override;
110*38e8c45fSAndroid Build Coastguard Worker     void notifyKey(const NotifyKeyArgs& args) override;
111*38e8c45fSAndroid Build Coastguard Worker     void notifyMotion(const NotifyMotionArgs& args) override;
112*38e8c45fSAndroid Build Coastguard Worker     void notifySwitch(const NotifySwitchArgs& args) override;
113*38e8c45fSAndroid Build Coastguard Worker     void notifySensor(const NotifySensorArgs& args) override;
114*38e8c45fSAndroid Build Coastguard Worker     void notifyVibratorState(const NotifyVibratorStateArgs& args) override;
115*38e8c45fSAndroid Build Coastguard Worker     void notifyDeviceReset(const NotifyDeviceResetArgs& args) override;
116*38e8c45fSAndroid Build Coastguard Worker     void notifyPointerCaptureChanged(const NotifyPointerCaptureChangedArgs& args) override;
117*38e8c45fSAndroid Build Coastguard Worker 
118*38e8c45fSAndroid Build Coastguard Worker     void notifyDeviceInteraction(int32_t deviceId, nsecs_t timestamp,
119*38e8c45fSAndroid Build Coastguard Worker                                  const std::set<gui::Uid>& uids) override;
120*38e8c45fSAndroid Build Coastguard Worker     void dump(std::string& dump) override;
121*38e8c45fSAndroid Build Coastguard Worker     void monitor() override;
122*38e8c45fSAndroid Build Coastguard Worker 
123*38e8c45fSAndroid Build Coastguard Worker private:
124*38e8c45fSAndroid Build Coastguard Worker     std::mutex mLock;
125*38e8c45fSAndroid Build Coastguard Worker     InputListenerInterface& mNextListener;
126*38e8c45fSAndroid Build Coastguard Worker     InputDeviceMetricsLogger& mLogger GUARDED_BY(mLock);
127*38e8c45fSAndroid Build Coastguard Worker     const std::chrono::nanoseconds mUsageSessionTimeout;
128*38e8c45fSAndroid Build Coastguard Worker 
129*38e8c45fSAndroid Build Coastguard Worker     // Type-safe wrapper for input device id.
130*38e8c45fSAndroid Build Coastguard Worker     struct DeviceId : ftl::Constructible<DeviceId, std::int32_t>,
131*38e8c45fSAndroid Build Coastguard Worker                       ftl::Equatable<DeviceId>,
132*38e8c45fSAndroid Build Coastguard Worker                       ftl::Orderable<DeviceId> {
133*38e8c45fSAndroid Build Coastguard Worker         using Constructible::Constructible;
134*38e8c45fSAndroid Build Coastguard Worker     };
toString(const DeviceId & id)135*38e8c45fSAndroid Build Coastguard Worker     static inline std::string toString(const DeviceId& id) {
136*38e8c45fSAndroid Build Coastguard Worker         return std::to_string(ftl::to_underlying(id));
137*38e8c45fSAndroid Build Coastguard Worker     }
138*38e8c45fSAndroid Build Coastguard Worker 
139*38e8c45fSAndroid Build Coastguard Worker     using Uid = gui::Uid;
140*38e8c45fSAndroid Build Coastguard Worker     using MetricsDeviceInfo = InputDeviceMetricsLogger::MetricsDeviceInfo;
141*38e8c45fSAndroid Build Coastguard Worker 
142*38e8c45fSAndroid Build Coastguard Worker     std::map<DeviceId, MetricsDeviceInfo> mLoggedDeviceInfos GUARDED_BY(mLock);
143*38e8c45fSAndroid Build Coastguard Worker 
144*38e8c45fSAndroid Build Coastguard Worker     using Interaction = std::tuple<DeviceId, std::chrono::nanoseconds, std::set<Uid>>;
145*38e8c45fSAndroid Build Coastguard Worker     SyncQueue<Interaction> mInteractionsQueue GUARDED_BY(mLock);
146*38e8c45fSAndroid Build Coastguard Worker 
147*38e8c45fSAndroid Build Coastguard Worker     class ActiveSession {
148*38e8c45fSAndroid Build Coastguard Worker     public:
149*38e8c45fSAndroid Build Coastguard Worker         explicit ActiveSession(std::chrono::nanoseconds usageSessionTimeout,
150*38e8c45fSAndroid Build Coastguard Worker                                std::chrono::nanoseconds startTime);
151*38e8c45fSAndroid Build Coastguard Worker         void recordUsage(std::chrono::nanoseconds eventTime, InputDeviceUsageSource source);
152*38e8c45fSAndroid Build Coastguard Worker         void recordInteraction(const Interaction&);
153*38e8c45fSAndroid Build Coastguard Worker         bool checkIfCompletedAt(std::chrono::nanoseconds timestamp);
154*38e8c45fSAndroid Build Coastguard Worker         InputDeviceMetricsLogger::DeviceUsageReport finishSession();
155*38e8c45fSAndroid Build Coastguard Worker 
156*38e8c45fSAndroid Build Coastguard Worker     private:
157*38e8c45fSAndroid Build Coastguard Worker         struct UsageSession {
158*38e8c45fSAndroid Build Coastguard Worker             std::chrono::nanoseconds start{};
159*38e8c45fSAndroid Build Coastguard Worker             std::chrono::nanoseconds end{};
160*38e8c45fSAndroid Build Coastguard Worker         };
161*38e8c45fSAndroid Build Coastguard Worker 
162*38e8c45fSAndroid Build Coastguard Worker         const std::chrono::nanoseconds mUsageSessionTimeout;
163*38e8c45fSAndroid Build Coastguard Worker         UsageSession mDeviceSession{};
164*38e8c45fSAndroid Build Coastguard Worker 
165*38e8c45fSAndroid Build Coastguard Worker         std::map<InputDeviceUsageSource, UsageSession> mActiveSessionsBySource{};
166*38e8c45fSAndroid Build Coastguard Worker         InputDeviceMetricsLogger::SourceUsageBreakdown mSourceUsageBreakdown{};
167*38e8c45fSAndroid Build Coastguard Worker 
168*38e8c45fSAndroid Build Coastguard Worker         std::map<Uid, UsageSession> mActiveSessionsByUid{};
169*38e8c45fSAndroid Build Coastguard Worker         InputDeviceMetricsLogger::UidUsageBreakdown mUidUsageBreakdown{};
170*38e8c45fSAndroid Build Coastguard Worker     };
171*38e8c45fSAndroid Build Coastguard Worker 
172*38e8c45fSAndroid Build Coastguard Worker     // The input devices that currently have active usage sessions.
173*38e8c45fSAndroid Build Coastguard Worker     std::map<DeviceId, ActiveSession> mActiveUsageSessions GUARDED_BY(mLock);
174*38e8c45fSAndroid Build Coastguard Worker 
175*38e8c45fSAndroid Build Coastguard Worker     void onInputDevicesChanged(const std::vector<InputDeviceInfo>& infos) REQUIRES(mLock);
176*38e8c45fSAndroid Build Coastguard Worker     void onInputDeviceRemoved(DeviceId deviceId, const MetricsDeviceInfo& info) REQUIRES(mLock);
177*38e8c45fSAndroid Build Coastguard Worker     using SourceProvider =
178*38e8c45fSAndroid Build Coastguard Worker             std::function<std::set<InputDeviceUsageSource>(const MetricsDeviceInfo&)>;
179*38e8c45fSAndroid Build Coastguard Worker     void onInputDeviceUsage(DeviceId deviceId, std::chrono::nanoseconds eventTime,
180*38e8c45fSAndroid Build Coastguard Worker                             const SourceProvider& getSources) REQUIRES(mLock);
181*38e8c45fSAndroid Build Coastguard Worker     void onInputDeviceInteraction(const Interaction&) REQUIRES(mLock);
182*38e8c45fSAndroid Build Coastguard Worker     void reportCompletedSessions() REQUIRES(mLock);
183*38e8c45fSAndroid Build Coastguard Worker };
184*38e8c45fSAndroid Build Coastguard Worker 
185*38e8c45fSAndroid Build Coastguard Worker } // namespace android
186