blob: 2319d51441e29ffb5eb372ac7779ba764ae06880 [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 Pradhana3863092023-05-31 14:43:53 +000034constexpr nanoseconds DEFAULT_USAGE_SESSION_TIMEOUT = std::chrono::minutes(2);
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
42int32_t linuxBusToInputDeviceBusEnum(int32_t linuxBus) {
Harry Cuttsa34de522023-06-06 15:52:54 +000043 // When adding cases to this switch, also add them to the copy of this method in
44 // TouchpadInputMapper.cpp.
45 // TODO(b/286394420): deduplicate this method with the one in TouchpadInputMapper.cpp.
Prabir Pradhan852db892023-04-06 22:16:44 +000046 switch (linuxBus) {
47 case BUS_USB:
48 return util::INPUT_DEVICE_USAGE_REPORTED__DEVICE_BUS__USB;
49 case BUS_BLUETOOTH:
50 return util::INPUT_DEVICE_USAGE_REPORTED__DEVICE_BUS__BLUETOOTH;
51 default:
52 return util::INPUT_DEVICE_USAGE_REPORTED__DEVICE_BUS__OTHER;
53 }
54}
55
56class : public InputDeviceMetricsLogger {
57 nanoseconds getCurrentTime() override { return nanoseconds(systemTime(SYSTEM_TIME_MONOTONIC)); }
58
59 void logInputDeviceUsageReported(const InputDeviceIdentifier& identifier,
Prabir Pradhanaff13032023-04-07 22:25:03 +000060 const DeviceUsageReport& report) override {
Prabir Pradhan852db892023-04-06 22:16:44 +000061 const int32_t durationMillis =
Prabir Pradhanaff13032023-04-07 22:25:03 +000062 std::chrono::duration_cast<std::chrono::milliseconds>(report.usageDuration).count();
Prabir Pradhan852db892023-04-06 22:16:44 +000063 const static std::vector<int32_t> empty;
64
65 ALOGD_IF(DEBUG, "Usage session reported for device: %s", identifier.name.c_str());
66 ALOGD_IF(DEBUG, " Total duration: %dms", durationMillis);
Prabir Pradhanaff13032023-04-07 22:25:03 +000067 ALOGD_IF(DEBUG, " Source breakdown:");
68
69 std::vector<int32_t> sources;
70 std::vector<int32_t> durationsPerSource;
71 for (auto& [src, dur] : report.sourceBreakdown) {
72 sources.push_back(ftl::to_underlying(src));
73 int32_t durMillis = std::chrono::duration_cast<std::chrono::milliseconds>(dur).count();
74 durationsPerSource.emplace_back(durMillis);
75 ALOGD_IF(DEBUG, " - usageSource: %s\t duration: %dms",
76 ftl::enum_string(src).c_str(), durMillis);
77 }
Prabir Pradhan852db892023-04-06 22:16:44 +000078
Prabir Pradhan44293792023-05-08 19:37:44 +000079 ALOGD_IF(DEBUG, " Uid breakdown:");
80
81 std::vector<int32_t> uids;
82 std::vector<int32_t> durationsPerUid;
83 for (auto& [uid, dur] : report.uidBreakdown) {
84 uids.push_back(uid);
85 int32_t durMillis = std::chrono::duration_cast<std::chrono::milliseconds>(dur).count();
86 durationsPerUid.push_back(durMillis);
87 ALOGD_IF(DEBUG, " - uid: %d\t duration: %dms", uid, durMillis);
88 }
Prabir Pradhan852db892023-04-06 22:16:44 +000089 util::stats_write(util::INPUTDEVICE_USAGE_REPORTED, identifier.vendor, identifier.product,
90 identifier.version, linuxBusToInputDeviceBusEnum(identifier.bus),
Prabir Pradhan44293792023-05-08 19:37:44 +000091 durationMillis, sources, durationsPerSource, uids, durationsPerUid);
Prabir Pradhan852db892023-04-06 22:16:44 +000092 }
93} sStatsdLogger;
94
95bool isIgnoredInputDeviceId(int32_t deviceId) {
96 switch (deviceId) {
97 case INVALID_INPUT_DEVICE_ID:
98 case VIRTUAL_KEYBOARD_ID:
99 return true;
100 default:
101 return false;
102 }
103}
104
105} // namespace
106
Prabir Pradhanae10ee62023-05-12 19:44:18 +0000107InputDeviceUsageSource getUsageSourceForKeyArgs(const InputDeviceInfo& info,
108 const NotifyKeyArgs& keyArgs) {
109 if (!isFromSource(keyArgs.source, AINPUT_SOURCE_KEYBOARD)) {
110 return InputDeviceUsageSource::UNKNOWN;
111 }
112
113 if (isFromSource(keyArgs.source, AINPUT_SOURCE_DPAD) &&
114 DPAD_ALL_KEYCODES.count(keyArgs.keyCode) != 0) {
115 return InputDeviceUsageSource::DPAD;
116 }
117
118 if (isFromSource(keyArgs.source, AINPUT_SOURCE_GAMEPAD) &&
119 GAMEPAD_KEYCODES.count(keyArgs.keyCode) != 0) {
120 return InputDeviceUsageSource::GAMEPAD;
121 }
122
123 if (info.getKeyboardType() == AINPUT_KEYBOARD_TYPE_ALPHABETIC) {
124 return InputDeviceUsageSource::KEYBOARD;
125 }
126
127 return InputDeviceUsageSource::BUTTONS;
128}
129
130std::set<InputDeviceUsageSource> getUsageSourcesForMotionArgs(const NotifyMotionArgs& motionArgs) {
131 LOG_ALWAYS_FATAL_IF(motionArgs.pointerCount < 1, "Received motion args without pointers");
132 std::set<InputDeviceUsageSource> sources;
133
134 for (uint32_t i = 0; i < motionArgs.pointerCount; i++) {
135 const auto toolType = motionArgs.pointerProperties[i].toolType;
136 if (isFromSource(motionArgs.source, AINPUT_SOURCE_MOUSE)) {
137 if (toolType == ToolType::MOUSE) {
138 sources.emplace(InputDeviceUsageSource::MOUSE);
139 continue;
140 }
141 if (toolType == ToolType::FINGER) {
142 sources.emplace(InputDeviceUsageSource::TOUCHPAD);
143 continue;
144 }
145 if (isStylusToolType(toolType)) {
146 sources.emplace(InputDeviceUsageSource::STYLUS_INDIRECT);
147 continue;
148 }
149 }
150 if (isFromSource(motionArgs.source, AINPUT_SOURCE_MOUSE_RELATIVE) &&
151 toolType == ToolType::MOUSE) {
152 sources.emplace(InputDeviceUsageSource::MOUSE_CAPTURED);
153 continue;
154 }
155 if (isFromSource(motionArgs.source, AINPUT_SOURCE_TOUCHPAD) &&
156 toolType == ToolType::FINGER) {
157 sources.emplace(InputDeviceUsageSource::TOUCHPAD_CAPTURED);
158 continue;
159 }
160 if (isFromSource(motionArgs.source, AINPUT_SOURCE_BLUETOOTH_STYLUS) &&
161 isStylusToolType(toolType)) {
162 sources.emplace(InputDeviceUsageSource::STYLUS_FUSED);
163 continue;
164 }
165 if (isFromSource(motionArgs.source, AINPUT_SOURCE_STYLUS) && isStylusToolType(toolType)) {
166 sources.emplace(InputDeviceUsageSource::STYLUS_DIRECT);
167 continue;
168 }
169 if (isFromSource(motionArgs.source, AINPUT_SOURCE_TOUCH_NAVIGATION)) {
170 sources.emplace(InputDeviceUsageSource::TOUCH_NAVIGATION);
171 continue;
172 }
173 if (isFromSource(motionArgs.source, AINPUT_SOURCE_JOYSTICK)) {
174 sources.emplace(InputDeviceUsageSource::JOYSTICK);
175 continue;
176 }
177 if (isFromSource(motionArgs.source, AINPUT_SOURCE_ROTARY_ENCODER)) {
178 sources.emplace(InputDeviceUsageSource::ROTARY_ENCODER);
179 continue;
180 }
181 if (isFromSource(motionArgs.source, AINPUT_SOURCE_TRACKBALL)) {
182 sources.emplace(InputDeviceUsageSource::TRACKBALL);
183 continue;
184 }
185 if (isFromSource(motionArgs.source, AINPUT_SOURCE_TOUCHSCREEN)) {
186 sources.emplace(InputDeviceUsageSource::TOUCHSCREEN);
187 continue;
188 }
189 sources.emplace(InputDeviceUsageSource::UNKNOWN);
190 }
191
192 return sources;
193}
194
195// --- InputDeviceMetricsCollector ---
196
Prabir Pradhanaddf8e92023-04-06 00:28:48 +0000197InputDeviceMetricsCollector::InputDeviceMetricsCollector(InputListenerInterface& listener)
Prabir Pradhan852db892023-04-06 22:16:44 +0000198 : InputDeviceMetricsCollector(listener, sStatsdLogger, DEFAULT_USAGE_SESSION_TIMEOUT) {}
199
200InputDeviceMetricsCollector::InputDeviceMetricsCollector(InputListenerInterface& listener,
201 InputDeviceMetricsLogger& logger,
202 nanoseconds usageSessionTimeout)
203 : mNextListener(listener), mLogger(logger), mUsageSessionTimeout(usageSessionTimeout) {}
Prabir Pradhanaddf8e92023-04-06 00:28:48 +0000204
205void InputDeviceMetricsCollector::notifyInputDevicesChanged(
206 const NotifyInputDevicesChangedArgs& args) {
Prabir Pradhanaff13032023-04-07 22:25:03 +0000207 reportCompletedSessions();
Prabir Pradhan852db892023-04-06 22:16:44 +0000208 onInputDevicesChanged(args.inputDeviceInfos);
Prabir Pradhanaddf8e92023-04-06 00:28:48 +0000209 mNextListener.notify(args);
210}
211
212void InputDeviceMetricsCollector::notifyConfigurationChanged(
213 const NotifyConfigurationChangedArgs& args) {
Prabir Pradhanaff13032023-04-07 22:25:03 +0000214 reportCompletedSessions();
Prabir Pradhanaddf8e92023-04-06 00:28:48 +0000215 mNextListener.notify(args);
216}
217
218void InputDeviceMetricsCollector::notifyKey(const NotifyKeyArgs& args) {
Prabir Pradhanaff13032023-04-07 22:25:03 +0000219 reportCompletedSessions();
220 const SourceProvider getSources = [&args](const InputDeviceInfo& info) {
221 return std::set{getUsageSourceForKeyArgs(info, args)};
222 };
223 onInputDeviceUsage(DeviceId{args.deviceId}, nanoseconds(args.eventTime), getSources);
Prabir Pradhan852db892023-04-06 22:16:44 +0000224
Prabir Pradhanaddf8e92023-04-06 00:28:48 +0000225 mNextListener.notify(args);
226}
227
228void InputDeviceMetricsCollector::notifyMotion(const NotifyMotionArgs& args) {
Prabir Pradhanaff13032023-04-07 22:25:03 +0000229 reportCompletedSessions();
230 onInputDeviceUsage(DeviceId{args.deviceId}, nanoseconds(args.eventTime),
231 [&args](const auto&) { return getUsageSourcesForMotionArgs(args); });
Prabir Pradhan852db892023-04-06 22:16:44 +0000232
Prabir Pradhanaddf8e92023-04-06 00:28:48 +0000233 mNextListener.notify(args);
234}
235
236void InputDeviceMetricsCollector::notifySwitch(const NotifySwitchArgs& args) {
Prabir Pradhanaff13032023-04-07 22:25:03 +0000237 reportCompletedSessions();
Prabir Pradhanaddf8e92023-04-06 00:28:48 +0000238 mNextListener.notify(args);
239}
240
241void InputDeviceMetricsCollector::notifySensor(const NotifySensorArgs& args) {
Prabir Pradhanaff13032023-04-07 22:25:03 +0000242 reportCompletedSessions();
Prabir Pradhanaddf8e92023-04-06 00:28:48 +0000243 mNextListener.notify(args);
244}
245
246void InputDeviceMetricsCollector::notifyVibratorState(const NotifyVibratorStateArgs& args) {
Prabir Pradhanaff13032023-04-07 22:25:03 +0000247 reportCompletedSessions();
Prabir Pradhanaddf8e92023-04-06 00:28:48 +0000248 mNextListener.notify(args);
249}
250
251void InputDeviceMetricsCollector::notifyDeviceReset(const NotifyDeviceResetArgs& args) {
Prabir Pradhanaff13032023-04-07 22:25:03 +0000252 reportCompletedSessions();
Prabir Pradhanaddf8e92023-04-06 00:28:48 +0000253 mNextListener.notify(args);
254}
255
256void InputDeviceMetricsCollector::notifyPointerCaptureChanged(
257 const NotifyPointerCaptureChangedArgs& args) {
Prabir Pradhanaff13032023-04-07 22:25:03 +0000258 reportCompletedSessions();
Prabir Pradhanaddf8e92023-04-06 00:28:48 +0000259 mNextListener.notify(args);
260}
261
Prabir Pradhan8ede1d12023-05-08 19:37:44 +0000262void InputDeviceMetricsCollector::notifyDeviceInteraction(int32_t deviceId, nsecs_t timestamp,
263 const std::set<int32_t>& uids) {
Prabir Pradhan44293792023-05-08 19:37:44 +0000264 std::set<Uid> typeSafeUids;
265 for (auto uid : uids) {
266 typeSafeUids.emplace(uid);
267 }
268 mInteractionsQueue.push(DeviceId{deviceId}, timestamp, typeSafeUids);
Prabir Pradhan8ede1d12023-05-08 19:37:44 +0000269}
270
Prabir Pradhanaddf8e92023-04-06 00:28:48 +0000271void InputDeviceMetricsCollector::dump(std::string& dump) {
272 dump += "InputDeviceMetricsCollector:\n";
Prabir Pradhan852db892023-04-06 22:16:44 +0000273
274 dump += " Logged device IDs: " + dumpMapKeys(mLoggedDeviceInfos, &toString) + "\n";
275 dump += " Devices with active usage sessions: " +
276 dumpMapKeys(mActiveUsageSessions, &toString) + "\n";
277}
278
279void InputDeviceMetricsCollector::onInputDevicesChanged(const std::vector<InputDeviceInfo>& infos) {
Prabir Pradhanaff13032023-04-07 22:25:03 +0000280 std::map<DeviceId, InputDeviceInfo> newDeviceInfos;
Prabir Pradhan852db892023-04-06 22:16:44 +0000281
282 for (const InputDeviceInfo& info : infos) {
283 if (isIgnoredInputDeviceId(info.getId())) {
284 continue;
285 }
Prabir Pradhanaff13032023-04-07 22:25:03 +0000286 newDeviceInfos.emplace(info.getId(), info);
Prabir Pradhan852db892023-04-06 22:16:44 +0000287 }
288
Prabir Pradhanaff13032023-04-07 22:25:03 +0000289 for (auto [deviceId, info] : mLoggedDeviceInfos) {
290 if (newDeviceInfos.count(deviceId) != 0) {
Prabir Pradhan852db892023-04-06 22:16:44 +0000291 continue;
292 }
Prabir Pradhanaff13032023-04-07 22:25:03 +0000293 onInputDeviceRemoved(deviceId, info.getIdentifier());
Prabir Pradhan852db892023-04-06 22:16:44 +0000294 }
295
Prabir Pradhanaff13032023-04-07 22:25:03 +0000296 std::swap(newDeviceInfos, mLoggedDeviceInfos);
Prabir Pradhan852db892023-04-06 22:16:44 +0000297}
298
299void InputDeviceMetricsCollector::onInputDeviceRemoved(DeviceId deviceId,
300 const InputDeviceIdentifier& identifier) {
Prabir Pradhan852db892023-04-06 22:16:44 +0000301 auto it = mActiveUsageSessions.find(deviceId);
Prabir Pradhanaff13032023-04-07 22:25:03 +0000302 if (it == mActiveUsageSessions.end()) {
303 return;
Prabir Pradhan852db892023-04-06 22:16:44 +0000304 }
Prabir Pradhanaff13032023-04-07 22:25:03 +0000305 // Report usage for that device if there is an active session.
306 auto& [_, activeSession] = *it;
307 mLogger.logInputDeviceUsageReported(identifier, activeSession.finishSession());
308 mActiveUsageSessions.erase(it);
309
Prabir Pradhan852db892023-04-06 22:16:44 +0000310 // We don't remove this from mLoggedDeviceInfos because it will be updated in
311 // onInputDevicesChanged().
312}
313
Prabir Pradhanaff13032023-04-07 22:25:03 +0000314void InputDeviceMetricsCollector::onInputDeviceUsage(DeviceId deviceId, nanoseconds eventTime,
315 const SourceProvider& getSources) {
316 auto infoIt = mLoggedDeviceInfos.find(deviceId);
317 if (infoIt == mLoggedDeviceInfos.end()) {
Prabir Pradhan852db892023-04-06 22:16:44 +0000318 // Do not track usage for devices that are not logged.
319 return;
320 }
321
Prabir Pradhanaff13032023-04-07 22:25:03 +0000322 auto [sessionIt, _] =
323 mActiveUsageSessions.try_emplace(deviceId, mUsageSessionTimeout, eventTime);
324 for (InputDeviceUsageSource source : getSources(infoIt->second)) {
325 sessionIt->second.recordUsage(eventTime, source);
Prabir Pradhan852db892023-04-06 22:16:44 +0000326 }
327}
328
Prabir Pradhan44293792023-05-08 19:37:44 +0000329void InputDeviceMetricsCollector::onInputDeviceInteraction(const Interaction& interaction) {
330 auto activeSessionIt = mActiveUsageSessions.find(std::get<DeviceId>(interaction));
331 if (activeSessionIt == mActiveUsageSessions.end()) {
332 return;
333 }
Prabir Pradhan852db892023-04-06 22:16:44 +0000334
Prabir Pradhan44293792023-05-08 19:37:44 +0000335 activeSessionIt->second.recordInteraction(interaction);
336}
337
338void InputDeviceMetricsCollector::reportCompletedSessions() {
339 // Process all pending interactions.
340 for (auto interaction = mInteractionsQueue.pop(); interaction;
341 interaction = mInteractionsQueue.pop()) {
342 onInputDeviceInteraction(*interaction);
343 }
344
345 const auto currentTime = mLogger.getCurrentTime();
Prabir Pradhan852db892023-04-06 22:16:44 +0000346 std::vector<DeviceId> completedUsageSessions;
347
Prabir Pradhan44293792023-05-08 19:37:44 +0000348 // Process usages for all active session to determine if any sessions have expired.
Prabir Pradhanaff13032023-04-07 22:25:03 +0000349 for (auto& [deviceId, activeSession] : mActiveUsageSessions) {
350 if (activeSession.checkIfCompletedAt(currentTime)) {
Prabir Pradhan852db892023-04-06 22:16:44 +0000351 completedUsageSessions.emplace_back(deviceId);
352 }
353 }
354
Prabir Pradhan44293792023-05-08 19:37:44 +0000355 // Close out and log all expired usage sessions.
Prabir Pradhan852db892023-04-06 22:16:44 +0000356 for (DeviceId deviceId : completedUsageSessions) {
Prabir Pradhanaff13032023-04-07 22:25:03 +0000357 const auto infoIt = mLoggedDeviceInfos.find(deviceId);
358 LOG_ALWAYS_FATAL_IF(infoIt == mLoggedDeviceInfos.end());
Prabir Pradhan852db892023-04-06 22:16:44 +0000359
Prabir Pradhanaff13032023-04-07 22:25:03 +0000360 auto activeSessionIt = mActiveUsageSessions.find(deviceId);
361 LOG_ALWAYS_FATAL_IF(activeSessionIt == mActiveUsageSessions.end());
362 auto& [_, activeSession] = *activeSessionIt;
363 mLogger.logInputDeviceUsageReported(infoIt->second.getIdentifier(),
364 activeSession.finishSession());
365 mActiveUsageSessions.erase(activeSessionIt);
Prabir Pradhan852db892023-04-06 22:16:44 +0000366 }
Prabir Pradhanaddf8e92023-04-06 00:28:48 +0000367}
368
Prabir Pradhanaff13032023-04-07 22:25:03 +0000369// --- InputDeviceMetricsCollector::ActiveSession ---
370
371InputDeviceMetricsCollector::ActiveSession::ActiveSession(nanoseconds usageSessionTimeout,
372 nanoseconds startTime)
373 : mUsageSessionTimeout(usageSessionTimeout), mDeviceSession({startTime, startTime}) {}
374
375void InputDeviceMetricsCollector::ActiveSession::recordUsage(nanoseconds eventTime,
376 InputDeviceUsageSource source) {
377 // We assume that event times for subsequent events are always monotonically increasing for each
378 // input device.
379 auto [activeSourceIt, inserted] =
380 mActiveSessionsBySource.try_emplace(source, eventTime, eventTime);
381 if (!inserted) {
382 activeSourceIt->second.end = eventTime;
383 }
384 mDeviceSession.end = eventTime;
385}
386
Prabir Pradhan44293792023-05-08 19:37:44 +0000387void InputDeviceMetricsCollector::ActiveSession::recordInteraction(const Interaction& interaction) {
388 const auto sessionExpiryTime = mDeviceSession.end + mUsageSessionTimeout;
389 const auto timestamp = std::get<nanoseconds>(interaction);
390 if (timestamp >= sessionExpiryTime) {
391 // This interaction occurred after the device's current active session is set to expire.
392 // Ignore it.
393 return;
394 }
395
396 for (Uid uid : std::get<std::set<Uid>>(interaction)) {
397 auto [activeUidIt, inserted] = mActiveSessionsByUid.try_emplace(uid, timestamp, timestamp);
398 if (!inserted) {
399 activeUidIt->second.end = timestamp;
400 }
401 }
402}
403
Prabir Pradhanaff13032023-04-07 22:25:03 +0000404bool InputDeviceMetricsCollector::ActiveSession::checkIfCompletedAt(nanoseconds timestamp) {
405 const auto sessionExpiryTime = timestamp - mUsageSessionTimeout;
406 std::vector<InputDeviceUsageSource> completedSourceSessionsForDevice;
407 for (auto& [source, session] : mActiveSessionsBySource) {
408 if (session.end <= sessionExpiryTime) {
409 completedSourceSessionsForDevice.emplace_back(source);
410 }
411 }
412 for (InputDeviceUsageSource source : completedSourceSessionsForDevice) {
413 auto it = mActiveSessionsBySource.find(source);
414 const auto& [_, session] = *it;
415 mSourceUsageBreakdown.emplace_back(source, session.end - session.start);
416 mActiveSessionsBySource.erase(it);
417 }
Prabir Pradhan44293792023-05-08 19:37:44 +0000418
419 std::vector<Uid> completedUidSessionsForDevice;
420 for (auto& [uid, session] : mActiveSessionsByUid) {
421 if (session.end <= sessionExpiryTime) {
422 completedUidSessionsForDevice.emplace_back(uid);
423 }
424 }
425 for (Uid uid : completedUidSessionsForDevice) {
426 auto it = mActiveSessionsByUid.find(uid);
427 const auto& [_, session] = *it;
428 mUidUsageBreakdown.emplace_back(uid, session.end - session.start);
429 mActiveSessionsByUid.erase(it);
430 }
431
432 // This active session has expired if there are no more active source sessions tracked.
Prabir Pradhanaff13032023-04-07 22:25:03 +0000433 return mActiveSessionsBySource.empty();
434}
435
436InputDeviceMetricsLogger::DeviceUsageReport
437InputDeviceMetricsCollector::ActiveSession::finishSession() {
438 const auto deviceUsageDuration = mDeviceSession.end - mDeviceSession.start;
439
440 for (const auto& [source, sourceSession] : mActiveSessionsBySource) {
441 mSourceUsageBreakdown.emplace_back(source, sourceSession.end - sourceSession.start);
442 }
443 mActiveSessionsBySource.clear();
444
Prabir Pradhan44293792023-05-08 19:37:44 +0000445 for (const auto& [uid, uidSession] : mActiveSessionsByUid) {
446 mUidUsageBreakdown.emplace_back(uid, uidSession.end - uidSession.start);
447 }
448 mActiveSessionsByUid.clear();
449
450 return {deviceUsageDuration, mSourceUsageBreakdown, mUidUsageBreakdown};
Prabir Pradhanaff13032023-04-07 22:25:03 +0000451}
452
Prabir Pradhanaddf8e92023-04-06 00:28:48 +0000453} // namespace android