blob: 279932794e3d191f9b883685e085ab65b651f61a [file] [log] [blame]
Prabir Pradhanaddf8e92023-04-06 00:28:48 +00001/*
2 * Copyright 2023 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 "InputDeviceMetricsCollector"
18#include "InputDeviceMetricsCollector.h"
19
Prabir Pradhanae10ee62023-05-12 19:44:18 +000020#include "KeyCodeClassifications.h"
21
Prabir Pradhan852db892023-04-06 22:16:44 +000022#include <android-base/stringprintf.h>
23#include <input/PrintTools.h>
24#include <linux/input.h>
Prabir Pradhan852db892023-04-06 22:16:44 +000025
Prabir Pradhanaddf8e92023-04-06 00:28:48 +000026namespace android {
27
Prabir Pradhan852db892023-04-06 22:16:44 +000028using android::base::StringPrintf;
29using std::chrono::nanoseconds;
Prabir Pradhan44293792023-05-08 19:37:44 +000030using std::chrono_literals::operator""ns;
Prabir Pradhan852db892023-04-06 22:16:44 +000031
32namespace {
33
Prabir Pradhan97814e82023-06-26 18:20:39 +000034constexpr nanoseconds DEFAULT_USAGE_SESSION_TIMEOUT = std::chrono::seconds(5);
Prabir Pradhan852db892023-04-06 22:16:44 +000035
36/**
37 * Log debug messages about metrics events logged to statsd.
38 * Enable this via "adb shell setprop log.tag.InputDeviceMetricsCollector DEBUG" (requires restart)
39 */
40const bool DEBUG = __android_log_is_loggable(ANDROID_LOG_DEBUG, LOG_TAG, ANDROID_LOG_INFO);
41
Prabir Pradhan047695b2023-06-30 01:48:45 +000042constexpr size_t INTERACTIONS_QUEUE_CAPACITY = 500;
43
Prabir Pradhan852db892023-04-06 22:16:44 +000044int32_t linuxBusToInputDeviceBusEnum(int32_t linuxBus) {
Harry Cuttsa34de522023-06-06 15:52:54 +000045 // When adding cases to this switch, also add them to the copy of this method in
46 // TouchpadInputMapper.cpp.
47 // TODO(b/286394420): deduplicate this method with the one in TouchpadInputMapper.cpp.
Prabir Pradhan852db892023-04-06 22:16:44 +000048 switch (linuxBus) {
49 case BUS_USB:
50 return util::INPUT_DEVICE_USAGE_REPORTED__DEVICE_BUS__USB;
51 case BUS_BLUETOOTH:
52 return util::INPUT_DEVICE_USAGE_REPORTED__DEVICE_BUS__BLUETOOTH;
53 default:
54 return util::INPUT_DEVICE_USAGE_REPORTED__DEVICE_BUS__OTHER;
55 }
56}
57
58class : public InputDeviceMetricsLogger {
59 nanoseconds getCurrentTime() override { return nanoseconds(systemTime(SYSTEM_TIME_MONOTONIC)); }
60
61 void logInputDeviceUsageReported(const InputDeviceIdentifier& identifier,
Prabir Pradhanaff13032023-04-07 22:25:03 +000062 const DeviceUsageReport& report) override {
Prabir Pradhan852db892023-04-06 22:16:44 +000063 const int32_t durationMillis =
Prabir Pradhanaff13032023-04-07 22:25:03 +000064 std::chrono::duration_cast<std::chrono::milliseconds>(report.usageDuration).count();
Prabir Pradhan852db892023-04-06 22:16:44 +000065 const static std::vector<int32_t> empty;
66
67 ALOGD_IF(DEBUG, "Usage session reported for device: %s", identifier.name.c_str());
68 ALOGD_IF(DEBUG, " Total duration: %dms", durationMillis);
Prabir Pradhanaff13032023-04-07 22:25:03 +000069 ALOGD_IF(DEBUG, " Source breakdown:");
70
71 std::vector<int32_t> sources;
72 std::vector<int32_t> durationsPerSource;
73 for (auto& [src, dur] : report.sourceBreakdown) {
74 sources.push_back(ftl::to_underlying(src));
75 int32_t durMillis = std::chrono::duration_cast<std::chrono::milliseconds>(dur).count();
76 durationsPerSource.emplace_back(durMillis);
77 ALOGD_IF(DEBUG, " - usageSource: %s\t duration: %dms",
78 ftl::enum_string(src).c_str(), durMillis);
79 }
Prabir Pradhan852db892023-04-06 22:16:44 +000080
Prabir Pradhan44293792023-05-08 19:37:44 +000081 ALOGD_IF(DEBUG, " Uid breakdown:");
82
83 std::vector<int32_t> uids;
84 std::vector<int32_t> durationsPerUid;
85 for (auto& [uid, dur] : report.uidBreakdown) {
Prabir Pradhan8a5c41d2023-06-08 19:13:46 +000086 uids.push_back(uid.val());
Prabir Pradhan44293792023-05-08 19:37:44 +000087 int32_t durMillis = std::chrono::duration_cast<std::chrono::milliseconds>(dur).count();
88 durationsPerUid.push_back(durMillis);
Prabir Pradhan8a5c41d2023-06-08 19:13:46 +000089 ALOGD_IF(DEBUG, " - uid: %s\t duration: %dms", uid.toString().c_str(),
90 durMillis);
Prabir Pradhan44293792023-05-08 19:37:44 +000091 }
Prabir Pradhan852db892023-04-06 22:16:44 +000092 util::stats_write(util::INPUTDEVICE_USAGE_REPORTED, identifier.vendor, identifier.product,
93 identifier.version, linuxBusToInputDeviceBusEnum(identifier.bus),
Prabir Pradhan44293792023-05-08 19:37:44 +000094 durationMillis, sources, durationsPerSource, uids, durationsPerUid);
Prabir Pradhan852db892023-04-06 22:16:44 +000095 }
96} sStatsdLogger;
97
98bool isIgnoredInputDeviceId(int32_t deviceId) {
99 switch (deviceId) {
100 case INVALID_INPUT_DEVICE_ID:
101 case VIRTUAL_KEYBOARD_ID:
102 return true;
103 default:
104 return false;
105 }
106}
107
108} // namespace
109
Prabir Pradhanae10ee62023-05-12 19:44:18 +0000110InputDeviceUsageSource getUsageSourceForKeyArgs(const InputDeviceInfo& info,
111 const NotifyKeyArgs& keyArgs) {
112 if (!isFromSource(keyArgs.source, AINPUT_SOURCE_KEYBOARD)) {
113 return InputDeviceUsageSource::UNKNOWN;
114 }
115
116 if (isFromSource(keyArgs.source, AINPUT_SOURCE_DPAD) &&
117 DPAD_ALL_KEYCODES.count(keyArgs.keyCode) != 0) {
118 return InputDeviceUsageSource::DPAD;
119 }
120
121 if (isFromSource(keyArgs.source, AINPUT_SOURCE_GAMEPAD) &&
122 GAMEPAD_KEYCODES.count(keyArgs.keyCode) != 0) {
123 return InputDeviceUsageSource::GAMEPAD;
124 }
125
126 if (info.getKeyboardType() == AINPUT_KEYBOARD_TYPE_ALPHABETIC) {
127 return InputDeviceUsageSource::KEYBOARD;
128 }
129
130 return InputDeviceUsageSource::BUTTONS;
131}
132
133std::set<InputDeviceUsageSource> getUsageSourcesForMotionArgs(const NotifyMotionArgs& motionArgs) {
Siarhei Vishniakou3218fc02023-06-15 20:41:02 -0700134 LOG_ALWAYS_FATAL_IF(motionArgs.getPointerCount() < 1, "Received motion args without pointers");
Prabir Pradhanae10ee62023-05-12 19:44:18 +0000135 std::set<InputDeviceUsageSource> sources;
136
Siarhei Vishniakou3218fc02023-06-15 20:41:02 -0700137 for (uint32_t i = 0; i < motionArgs.getPointerCount(); i++) {
Prabir Pradhanae10ee62023-05-12 19:44:18 +0000138 const auto toolType = motionArgs.pointerProperties[i].toolType;
139 if (isFromSource(motionArgs.source, AINPUT_SOURCE_MOUSE)) {
140 if (toolType == ToolType::MOUSE) {
141 sources.emplace(InputDeviceUsageSource::MOUSE);
142 continue;
143 }
144 if (toolType == ToolType::FINGER) {
145 sources.emplace(InputDeviceUsageSource::TOUCHPAD);
146 continue;
147 }
148 if (isStylusToolType(toolType)) {
149 sources.emplace(InputDeviceUsageSource::STYLUS_INDIRECT);
150 continue;
151 }
152 }
153 if (isFromSource(motionArgs.source, AINPUT_SOURCE_MOUSE_RELATIVE) &&
154 toolType == ToolType::MOUSE) {
155 sources.emplace(InputDeviceUsageSource::MOUSE_CAPTURED);
156 continue;
157 }
158 if (isFromSource(motionArgs.source, AINPUT_SOURCE_TOUCHPAD) &&
159 toolType == ToolType::FINGER) {
160 sources.emplace(InputDeviceUsageSource::TOUCHPAD_CAPTURED);
161 continue;
162 }
163 if (isFromSource(motionArgs.source, AINPUT_SOURCE_BLUETOOTH_STYLUS) &&
164 isStylusToolType(toolType)) {
165 sources.emplace(InputDeviceUsageSource::STYLUS_FUSED);
166 continue;
167 }
168 if (isFromSource(motionArgs.source, AINPUT_SOURCE_STYLUS) && isStylusToolType(toolType)) {
169 sources.emplace(InputDeviceUsageSource::STYLUS_DIRECT);
170 continue;
171 }
172 if (isFromSource(motionArgs.source, AINPUT_SOURCE_TOUCH_NAVIGATION)) {
173 sources.emplace(InputDeviceUsageSource::TOUCH_NAVIGATION);
174 continue;
175 }
176 if (isFromSource(motionArgs.source, AINPUT_SOURCE_JOYSTICK)) {
177 sources.emplace(InputDeviceUsageSource::JOYSTICK);
178 continue;
179 }
180 if (isFromSource(motionArgs.source, AINPUT_SOURCE_ROTARY_ENCODER)) {
181 sources.emplace(InputDeviceUsageSource::ROTARY_ENCODER);
182 continue;
183 }
184 if (isFromSource(motionArgs.source, AINPUT_SOURCE_TRACKBALL)) {
185 sources.emplace(InputDeviceUsageSource::TRACKBALL);
186 continue;
187 }
188 if (isFromSource(motionArgs.source, AINPUT_SOURCE_TOUCHSCREEN)) {
189 sources.emplace(InputDeviceUsageSource::TOUCHSCREEN);
190 continue;
191 }
192 sources.emplace(InputDeviceUsageSource::UNKNOWN);
193 }
194
195 return sources;
196}
197
198// --- InputDeviceMetricsCollector ---
199
Prabir Pradhanaddf8e92023-04-06 00:28:48 +0000200InputDeviceMetricsCollector::InputDeviceMetricsCollector(InputListenerInterface& listener)
Prabir Pradhan852db892023-04-06 22:16:44 +0000201 : InputDeviceMetricsCollector(listener, sStatsdLogger, DEFAULT_USAGE_SESSION_TIMEOUT) {}
202
203InputDeviceMetricsCollector::InputDeviceMetricsCollector(InputListenerInterface& listener,
204 InputDeviceMetricsLogger& logger,
205 nanoseconds usageSessionTimeout)
Prabir Pradhan047695b2023-06-30 01:48:45 +0000206 : mNextListener(listener),
207 mLogger(logger),
208 mUsageSessionTimeout(usageSessionTimeout),
209 mInteractionsQueue(INTERACTIONS_QUEUE_CAPACITY) {}
Prabir Pradhanaddf8e92023-04-06 00:28:48 +0000210
211void InputDeviceMetricsCollector::notifyInputDevicesChanged(
212 const NotifyInputDevicesChangedArgs& args) {
Prabir Pradhanaff13032023-04-07 22:25:03 +0000213 reportCompletedSessions();
Prabir Pradhan852db892023-04-06 22:16:44 +0000214 onInputDevicesChanged(args.inputDeviceInfos);
Prabir Pradhanaddf8e92023-04-06 00:28:48 +0000215 mNextListener.notify(args);
216}
217
218void InputDeviceMetricsCollector::notifyConfigurationChanged(
219 const NotifyConfigurationChangedArgs& args) {
Prabir Pradhanaff13032023-04-07 22:25:03 +0000220 reportCompletedSessions();
Prabir Pradhanaddf8e92023-04-06 00:28:48 +0000221 mNextListener.notify(args);
222}
223
224void InputDeviceMetricsCollector::notifyKey(const NotifyKeyArgs& args) {
Prabir Pradhanaff13032023-04-07 22:25:03 +0000225 reportCompletedSessions();
226 const SourceProvider getSources = [&args](const InputDeviceInfo& info) {
227 return std::set{getUsageSourceForKeyArgs(info, args)};
228 };
229 onInputDeviceUsage(DeviceId{args.deviceId}, nanoseconds(args.eventTime), getSources);
Prabir Pradhan852db892023-04-06 22:16:44 +0000230
Prabir Pradhanaddf8e92023-04-06 00:28:48 +0000231 mNextListener.notify(args);
232}
233
234void InputDeviceMetricsCollector::notifyMotion(const NotifyMotionArgs& args) {
Prabir Pradhanaff13032023-04-07 22:25:03 +0000235 reportCompletedSessions();
236 onInputDeviceUsage(DeviceId{args.deviceId}, nanoseconds(args.eventTime),
237 [&args](const auto&) { return getUsageSourcesForMotionArgs(args); });
Prabir Pradhan852db892023-04-06 22:16:44 +0000238
Prabir Pradhanaddf8e92023-04-06 00:28:48 +0000239 mNextListener.notify(args);
240}
241
242void InputDeviceMetricsCollector::notifySwitch(const NotifySwitchArgs& args) {
Prabir Pradhanaff13032023-04-07 22:25:03 +0000243 reportCompletedSessions();
Prabir Pradhanaddf8e92023-04-06 00:28:48 +0000244 mNextListener.notify(args);
245}
246
247void InputDeviceMetricsCollector::notifySensor(const NotifySensorArgs& args) {
Prabir Pradhanaff13032023-04-07 22:25:03 +0000248 reportCompletedSessions();
Prabir Pradhanaddf8e92023-04-06 00:28:48 +0000249 mNextListener.notify(args);
250}
251
252void InputDeviceMetricsCollector::notifyVibratorState(const NotifyVibratorStateArgs& args) {
Prabir Pradhanaff13032023-04-07 22:25:03 +0000253 reportCompletedSessions();
Prabir Pradhanaddf8e92023-04-06 00:28:48 +0000254 mNextListener.notify(args);
255}
256
257void InputDeviceMetricsCollector::notifyDeviceReset(const NotifyDeviceResetArgs& args) {
Prabir Pradhanaff13032023-04-07 22:25:03 +0000258 reportCompletedSessions();
Prabir Pradhanaddf8e92023-04-06 00:28:48 +0000259 mNextListener.notify(args);
260}
261
262void InputDeviceMetricsCollector::notifyPointerCaptureChanged(
263 const NotifyPointerCaptureChangedArgs& args) {
Prabir Pradhanaff13032023-04-07 22:25:03 +0000264 reportCompletedSessions();
Prabir Pradhanaddf8e92023-04-06 00:28:48 +0000265 mNextListener.notify(args);
266}
267
Prabir Pradhan8ede1d12023-05-08 19:37:44 +0000268void InputDeviceMetricsCollector::notifyDeviceInteraction(int32_t deviceId, nsecs_t timestamp,
Prabir Pradhan8a5c41d2023-06-08 19:13:46 +0000269 const std::set<Uid>& uids) {
Prabir Pradhan047695b2023-06-30 01:48:45 +0000270 if (isIgnoredInputDeviceId(deviceId)) {
271 return;
272 }
Prabir Pradhan8a5c41d2023-06-08 19:13:46 +0000273 mInteractionsQueue.push(DeviceId{deviceId}, timestamp, uids);
Prabir Pradhan8ede1d12023-05-08 19:37:44 +0000274}
275
Prabir Pradhanaddf8e92023-04-06 00:28:48 +0000276void InputDeviceMetricsCollector::dump(std::string& dump) {
277 dump += "InputDeviceMetricsCollector:\n";
Prabir Pradhan852db892023-04-06 22:16:44 +0000278
279 dump += " Logged device IDs: " + dumpMapKeys(mLoggedDeviceInfos, &toString) + "\n";
280 dump += " Devices with active usage sessions: " +
281 dumpMapKeys(mActiveUsageSessions, &toString) + "\n";
282}
283
284void InputDeviceMetricsCollector::onInputDevicesChanged(const std::vector<InputDeviceInfo>& infos) {
Prabir Pradhanaff13032023-04-07 22:25:03 +0000285 std::map<DeviceId, InputDeviceInfo> newDeviceInfos;
Prabir Pradhan852db892023-04-06 22:16:44 +0000286
287 for (const InputDeviceInfo& info : infos) {
288 if (isIgnoredInputDeviceId(info.getId())) {
289 continue;
290 }
Prabir Pradhanaff13032023-04-07 22:25:03 +0000291 newDeviceInfos.emplace(info.getId(), info);
Prabir Pradhan852db892023-04-06 22:16:44 +0000292 }
293
Prabir Pradhanaff13032023-04-07 22:25:03 +0000294 for (auto [deviceId, info] : mLoggedDeviceInfos) {
295 if (newDeviceInfos.count(deviceId) != 0) {
Prabir Pradhan852db892023-04-06 22:16:44 +0000296 continue;
297 }
Prabir Pradhanaff13032023-04-07 22:25:03 +0000298 onInputDeviceRemoved(deviceId, info.getIdentifier());
Prabir Pradhan852db892023-04-06 22:16:44 +0000299 }
300
Prabir Pradhanaff13032023-04-07 22:25:03 +0000301 std::swap(newDeviceInfos, mLoggedDeviceInfos);
Prabir Pradhan852db892023-04-06 22:16:44 +0000302}
303
304void InputDeviceMetricsCollector::onInputDeviceRemoved(DeviceId deviceId,
305 const InputDeviceIdentifier& identifier) {
Prabir Pradhan852db892023-04-06 22:16:44 +0000306 auto it = mActiveUsageSessions.find(deviceId);
Prabir Pradhanaff13032023-04-07 22:25:03 +0000307 if (it == mActiveUsageSessions.end()) {
308 return;
Prabir Pradhan852db892023-04-06 22:16:44 +0000309 }
Prabir Pradhanaff13032023-04-07 22:25:03 +0000310 // Report usage for that device if there is an active session.
311 auto& [_, activeSession] = *it;
312 mLogger.logInputDeviceUsageReported(identifier, activeSession.finishSession());
313 mActiveUsageSessions.erase(it);
314
Prabir Pradhan852db892023-04-06 22:16:44 +0000315 // We don't remove this from mLoggedDeviceInfos because it will be updated in
316 // onInputDevicesChanged().
317}
318
Prabir Pradhanaff13032023-04-07 22:25:03 +0000319void InputDeviceMetricsCollector::onInputDeviceUsage(DeviceId deviceId, nanoseconds eventTime,
320 const SourceProvider& getSources) {
321 auto infoIt = mLoggedDeviceInfos.find(deviceId);
322 if (infoIt == mLoggedDeviceInfos.end()) {
Prabir Pradhan852db892023-04-06 22:16:44 +0000323 // Do not track usage for devices that are not logged.
324 return;
325 }
326
Prabir Pradhanaff13032023-04-07 22:25:03 +0000327 auto [sessionIt, _] =
328 mActiveUsageSessions.try_emplace(deviceId, mUsageSessionTimeout, eventTime);
329 for (InputDeviceUsageSource source : getSources(infoIt->second)) {
330 sessionIt->second.recordUsage(eventTime, source);
Prabir Pradhan852db892023-04-06 22:16:44 +0000331 }
332}
333
Prabir Pradhan44293792023-05-08 19:37:44 +0000334void InputDeviceMetricsCollector::onInputDeviceInteraction(const Interaction& interaction) {
335 auto activeSessionIt = mActiveUsageSessions.find(std::get<DeviceId>(interaction));
336 if (activeSessionIt == mActiveUsageSessions.end()) {
337 return;
338 }
Prabir Pradhan852db892023-04-06 22:16:44 +0000339
Prabir Pradhan44293792023-05-08 19:37:44 +0000340 activeSessionIt->second.recordInteraction(interaction);
341}
342
343void InputDeviceMetricsCollector::reportCompletedSessions() {
344 // Process all pending interactions.
345 for (auto interaction = mInteractionsQueue.pop(); interaction;
346 interaction = mInteractionsQueue.pop()) {
347 onInputDeviceInteraction(*interaction);
348 }
349
350 const auto currentTime = mLogger.getCurrentTime();
Prabir Pradhan852db892023-04-06 22:16:44 +0000351 std::vector<DeviceId> completedUsageSessions;
352
Prabir Pradhan44293792023-05-08 19:37:44 +0000353 // Process usages for all active session to determine if any sessions have expired.
Prabir Pradhanaff13032023-04-07 22:25:03 +0000354 for (auto& [deviceId, activeSession] : mActiveUsageSessions) {
355 if (activeSession.checkIfCompletedAt(currentTime)) {
Prabir Pradhan852db892023-04-06 22:16:44 +0000356 completedUsageSessions.emplace_back(deviceId);
357 }
358 }
359
Prabir Pradhan44293792023-05-08 19:37:44 +0000360 // Close out and log all expired usage sessions.
Prabir Pradhan852db892023-04-06 22:16:44 +0000361 for (DeviceId deviceId : completedUsageSessions) {
Prabir Pradhanaff13032023-04-07 22:25:03 +0000362 const auto infoIt = mLoggedDeviceInfos.find(deviceId);
363 LOG_ALWAYS_FATAL_IF(infoIt == mLoggedDeviceInfos.end());
Prabir Pradhan852db892023-04-06 22:16:44 +0000364
Prabir Pradhanaff13032023-04-07 22:25:03 +0000365 auto activeSessionIt = mActiveUsageSessions.find(deviceId);
366 LOG_ALWAYS_FATAL_IF(activeSessionIt == mActiveUsageSessions.end());
367 auto& [_, activeSession] = *activeSessionIt;
368 mLogger.logInputDeviceUsageReported(infoIt->second.getIdentifier(),
369 activeSession.finishSession());
370 mActiveUsageSessions.erase(activeSessionIt);
Prabir Pradhan852db892023-04-06 22:16:44 +0000371 }
Prabir Pradhanaddf8e92023-04-06 00:28:48 +0000372}
373
Prabir Pradhanaff13032023-04-07 22:25:03 +0000374// --- InputDeviceMetricsCollector::ActiveSession ---
375
376InputDeviceMetricsCollector::ActiveSession::ActiveSession(nanoseconds usageSessionTimeout,
377 nanoseconds startTime)
378 : mUsageSessionTimeout(usageSessionTimeout), mDeviceSession({startTime, startTime}) {}
379
380void InputDeviceMetricsCollector::ActiveSession::recordUsage(nanoseconds eventTime,
381 InputDeviceUsageSource source) {
382 // We assume that event times for subsequent events are always monotonically increasing for each
383 // input device.
384 auto [activeSourceIt, inserted] =
385 mActiveSessionsBySource.try_emplace(source, eventTime, eventTime);
386 if (!inserted) {
387 activeSourceIt->second.end = eventTime;
388 }
389 mDeviceSession.end = eventTime;
390}
391
Prabir Pradhan44293792023-05-08 19:37:44 +0000392void InputDeviceMetricsCollector::ActiveSession::recordInteraction(const Interaction& interaction) {
393 const auto sessionExpiryTime = mDeviceSession.end + mUsageSessionTimeout;
394 const auto timestamp = std::get<nanoseconds>(interaction);
395 if (timestamp >= sessionExpiryTime) {
396 // This interaction occurred after the device's current active session is set to expire.
397 // Ignore it.
398 return;
399 }
400
401 for (Uid uid : std::get<std::set<Uid>>(interaction)) {
402 auto [activeUidIt, inserted] = mActiveSessionsByUid.try_emplace(uid, timestamp, timestamp);
403 if (!inserted) {
404 activeUidIt->second.end = timestamp;
405 }
406 }
407}
408
Prabir Pradhanaff13032023-04-07 22:25:03 +0000409bool InputDeviceMetricsCollector::ActiveSession::checkIfCompletedAt(nanoseconds timestamp) {
410 const auto sessionExpiryTime = timestamp - mUsageSessionTimeout;
411 std::vector<InputDeviceUsageSource> completedSourceSessionsForDevice;
412 for (auto& [source, session] : mActiveSessionsBySource) {
413 if (session.end <= sessionExpiryTime) {
414 completedSourceSessionsForDevice.emplace_back(source);
415 }
416 }
417 for (InputDeviceUsageSource source : completedSourceSessionsForDevice) {
418 auto it = mActiveSessionsBySource.find(source);
419 const auto& [_, session] = *it;
420 mSourceUsageBreakdown.emplace_back(source, session.end - session.start);
421 mActiveSessionsBySource.erase(it);
422 }
Prabir Pradhan44293792023-05-08 19:37:44 +0000423
424 std::vector<Uid> completedUidSessionsForDevice;
425 for (auto& [uid, session] : mActiveSessionsByUid) {
426 if (session.end <= sessionExpiryTime) {
427 completedUidSessionsForDevice.emplace_back(uid);
428 }
429 }
430 for (Uid uid : completedUidSessionsForDevice) {
431 auto it = mActiveSessionsByUid.find(uid);
432 const auto& [_, session] = *it;
433 mUidUsageBreakdown.emplace_back(uid, session.end - session.start);
434 mActiveSessionsByUid.erase(it);
435 }
436
437 // This active session has expired if there are no more active source sessions tracked.
Prabir Pradhanaff13032023-04-07 22:25:03 +0000438 return mActiveSessionsBySource.empty();
439}
440
441InputDeviceMetricsLogger::DeviceUsageReport
442InputDeviceMetricsCollector::ActiveSession::finishSession() {
443 const auto deviceUsageDuration = mDeviceSession.end - mDeviceSession.start;
444
445 for (const auto& [source, sourceSession] : mActiveSessionsBySource) {
446 mSourceUsageBreakdown.emplace_back(source, sourceSession.end - sourceSession.start);
447 }
448 mActiveSessionsBySource.clear();
449
Prabir Pradhan44293792023-05-08 19:37:44 +0000450 for (const auto& [uid, uidSession] : mActiveSessionsByUid) {
451 mUidUsageBreakdown.emplace_back(uid, uidSession.end - uidSession.start);
452 }
453 mActiveSessionsByUid.clear();
454
455 return {deviceUsageDuration, mSourceUsageBreakdown, mUidUsageBreakdown};
Prabir Pradhanaff13032023-04-07 22:25:03 +0000456}
457
Prabir Pradhanaddf8e92023-04-06 00:28:48 +0000458} // namespace android