blob: 1c3293b3d082af31e03cfa07b36ac8b9fc4d2ad3 [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) {
43 switch (linuxBus) {
44 case BUS_USB:
45 return util::INPUT_DEVICE_USAGE_REPORTED__DEVICE_BUS__USB;
46 case BUS_BLUETOOTH:
47 return util::INPUT_DEVICE_USAGE_REPORTED__DEVICE_BUS__BLUETOOTH;
48 default:
49 return util::INPUT_DEVICE_USAGE_REPORTED__DEVICE_BUS__OTHER;
50 }
51}
52
53class : public InputDeviceMetricsLogger {
54 nanoseconds getCurrentTime() override { return nanoseconds(systemTime(SYSTEM_TIME_MONOTONIC)); }
55
56 void logInputDeviceUsageReported(const InputDeviceIdentifier& identifier,
Prabir Pradhanaff13032023-04-07 22:25:03 +000057 const DeviceUsageReport& report) override {
Prabir Pradhan852db892023-04-06 22:16:44 +000058 const int32_t durationMillis =
Prabir Pradhanaff13032023-04-07 22:25:03 +000059 std::chrono::duration_cast<std::chrono::milliseconds>(report.usageDuration).count();
Prabir Pradhan852db892023-04-06 22:16:44 +000060 const static std::vector<int32_t> empty;
61
62 ALOGD_IF(DEBUG, "Usage session reported for device: %s", identifier.name.c_str());
63 ALOGD_IF(DEBUG, " Total duration: %dms", durationMillis);
Prabir Pradhanaff13032023-04-07 22:25:03 +000064 ALOGD_IF(DEBUG, " Source breakdown:");
65
66 std::vector<int32_t> sources;
67 std::vector<int32_t> durationsPerSource;
68 for (auto& [src, dur] : report.sourceBreakdown) {
69 sources.push_back(ftl::to_underlying(src));
70 int32_t durMillis = std::chrono::duration_cast<std::chrono::milliseconds>(dur).count();
71 durationsPerSource.emplace_back(durMillis);
72 ALOGD_IF(DEBUG, " - usageSource: %s\t duration: %dms",
73 ftl::enum_string(src).c_str(), durMillis);
74 }
Prabir Pradhan852db892023-04-06 22:16:44 +000075
Prabir Pradhan44293792023-05-08 19:37:44 +000076 ALOGD_IF(DEBUG, " Uid breakdown:");
77
78 std::vector<int32_t> uids;
79 std::vector<int32_t> durationsPerUid;
80 for (auto& [uid, dur] : report.uidBreakdown) {
Prabir Pradhan8a5c41d2023-06-08 19:13:46 +000081 uids.push_back(uid.val());
Prabir Pradhan44293792023-05-08 19:37:44 +000082 int32_t durMillis = std::chrono::duration_cast<std::chrono::milliseconds>(dur).count();
83 durationsPerUid.push_back(durMillis);
Prabir Pradhan8a5c41d2023-06-08 19:13:46 +000084 ALOGD_IF(DEBUG, " - uid: %s\t duration: %dms", uid.toString().c_str(),
85 durMillis);
Prabir Pradhan44293792023-05-08 19:37:44 +000086 }
Prabir Pradhan852db892023-04-06 22:16:44 +000087 util::stats_write(util::INPUTDEVICE_USAGE_REPORTED, identifier.vendor, identifier.product,
88 identifier.version, linuxBusToInputDeviceBusEnum(identifier.bus),
Prabir Pradhan44293792023-05-08 19:37:44 +000089 durationMillis, sources, durationsPerSource, uids, durationsPerUid);
Prabir Pradhan852db892023-04-06 22:16:44 +000090 }
91} sStatsdLogger;
92
93bool isIgnoredInputDeviceId(int32_t deviceId) {
94 switch (deviceId) {
95 case INVALID_INPUT_DEVICE_ID:
96 case VIRTUAL_KEYBOARD_ID:
97 return true;
98 default:
99 return false;
100 }
101}
102
103} // namespace
104
Prabir Pradhanae10ee62023-05-12 19:44:18 +0000105InputDeviceUsageSource getUsageSourceForKeyArgs(const InputDeviceInfo& info,
106 const NotifyKeyArgs& keyArgs) {
107 if (!isFromSource(keyArgs.source, AINPUT_SOURCE_KEYBOARD)) {
108 return InputDeviceUsageSource::UNKNOWN;
109 }
110
111 if (isFromSource(keyArgs.source, AINPUT_SOURCE_DPAD) &&
112 DPAD_ALL_KEYCODES.count(keyArgs.keyCode) != 0) {
113 return InputDeviceUsageSource::DPAD;
114 }
115
116 if (isFromSource(keyArgs.source, AINPUT_SOURCE_GAMEPAD) &&
117 GAMEPAD_KEYCODES.count(keyArgs.keyCode) != 0) {
118 return InputDeviceUsageSource::GAMEPAD;
119 }
120
121 if (info.getKeyboardType() == AINPUT_KEYBOARD_TYPE_ALPHABETIC) {
122 return InputDeviceUsageSource::KEYBOARD;
123 }
124
125 return InputDeviceUsageSource::BUTTONS;
126}
127
128std::set<InputDeviceUsageSource> getUsageSourcesForMotionArgs(const NotifyMotionArgs& motionArgs) {
129 LOG_ALWAYS_FATAL_IF(motionArgs.pointerCount < 1, "Received motion args without pointers");
130 std::set<InputDeviceUsageSource> sources;
131
132 for (uint32_t i = 0; i < motionArgs.pointerCount; i++) {
133 const auto toolType = motionArgs.pointerProperties[i].toolType;
134 if (isFromSource(motionArgs.source, AINPUT_SOURCE_MOUSE)) {
135 if (toolType == ToolType::MOUSE) {
136 sources.emplace(InputDeviceUsageSource::MOUSE);
137 continue;
138 }
139 if (toolType == ToolType::FINGER) {
140 sources.emplace(InputDeviceUsageSource::TOUCHPAD);
141 continue;
142 }
143 if (isStylusToolType(toolType)) {
144 sources.emplace(InputDeviceUsageSource::STYLUS_INDIRECT);
145 continue;
146 }
147 }
148 if (isFromSource(motionArgs.source, AINPUT_SOURCE_MOUSE_RELATIVE) &&
149 toolType == ToolType::MOUSE) {
150 sources.emplace(InputDeviceUsageSource::MOUSE_CAPTURED);
151 continue;
152 }
153 if (isFromSource(motionArgs.source, AINPUT_SOURCE_TOUCHPAD) &&
154 toolType == ToolType::FINGER) {
155 sources.emplace(InputDeviceUsageSource::TOUCHPAD_CAPTURED);
156 continue;
157 }
158 if (isFromSource(motionArgs.source, AINPUT_SOURCE_BLUETOOTH_STYLUS) &&
159 isStylusToolType(toolType)) {
160 sources.emplace(InputDeviceUsageSource::STYLUS_FUSED);
161 continue;
162 }
163 if (isFromSource(motionArgs.source, AINPUT_SOURCE_STYLUS) && isStylusToolType(toolType)) {
164 sources.emplace(InputDeviceUsageSource::STYLUS_DIRECT);
165 continue;
166 }
167 if (isFromSource(motionArgs.source, AINPUT_SOURCE_TOUCH_NAVIGATION)) {
168 sources.emplace(InputDeviceUsageSource::TOUCH_NAVIGATION);
169 continue;
170 }
171 if (isFromSource(motionArgs.source, AINPUT_SOURCE_JOYSTICK)) {
172 sources.emplace(InputDeviceUsageSource::JOYSTICK);
173 continue;
174 }
175 if (isFromSource(motionArgs.source, AINPUT_SOURCE_ROTARY_ENCODER)) {
176 sources.emplace(InputDeviceUsageSource::ROTARY_ENCODER);
177 continue;
178 }
179 if (isFromSource(motionArgs.source, AINPUT_SOURCE_TRACKBALL)) {
180 sources.emplace(InputDeviceUsageSource::TRACKBALL);
181 continue;
182 }
183 if (isFromSource(motionArgs.source, AINPUT_SOURCE_TOUCHSCREEN)) {
184 sources.emplace(InputDeviceUsageSource::TOUCHSCREEN);
185 continue;
186 }
187 sources.emplace(InputDeviceUsageSource::UNKNOWN);
188 }
189
190 return sources;
191}
192
193// --- InputDeviceMetricsCollector ---
194
Prabir Pradhanaddf8e92023-04-06 00:28:48 +0000195InputDeviceMetricsCollector::InputDeviceMetricsCollector(InputListenerInterface& listener)
Prabir Pradhan852db892023-04-06 22:16:44 +0000196 : InputDeviceMetricsCollector(listener, sStatsdLogger, DEFAULT_USAGE_SESSION_TIMEOUT) {}
197
198InputDeviceMetricsCollector::InputDeviceMetricsCollector(InputListenerInterface& listener,
199 InputDeviceMetricsLogger& logger,
200 nanoseconds usageSessionTimeout)
201 : mNextListener(listener), mLogger(logger), mUsageSessionTimeout(usageSessionTimeout) {}
Prabir Pradhanaddf8e92023-04-06 00:28:48 +0000202
203void InputDeviceMetricsCollector::notifyInputDevicesChanged(
204 const NotifyInputDevicesChangedArgs& args) {
Prabir Pradhanaff13032023-04-07 22:25:03 +0000205 reportCompletedSessions();
Prabir Pradhan852db892023-04-06 22:16:44 +0000206 onInputDevicesChanged(args.inputDeviceInfos);
Prabir Pradhanaddf8e92023-04-06 00:28:48 +0000207 mNextListener.notify(args);
208}
209
210void InputDeviceMetricsCollector::notifyConfigurationChanged(
211 const NotifyConfigurationChangedArgs& args) {
Prabir Pradhanaff13032023-04-07 22:25:03 +0000212 reportCompletedSessions();
Prabir Pradhanaddf8e92023-04-06 00:28:48 +0000213 mNextListener.notify(args);
214}
215
216void InputDeviceMetricsCollector::notifyKey(const NotifyKeyArgs& args) {
Prabir Pradhanaff13032023-04-07 22:25:03 +0000217 reportCompletedSessions();
218 const SourceProvider getSources = [&args](const InputDeviceInfo& info) {
219 return std::set{getUsageSourceForKeyArgs(info, args)};
220 };
221 onInputDeviceUsage(DeviceId{args.deviceId}, nanoseconds(args.eventTime), getSources);
Prabir Pradhan852db892023-04-06 22:16:44 +0000222
Prabir Pradhanaddf8e92023-04-06 00:28:48 +0000223 mNextListener.notify(args);
224}
225
226void InputDeviceMetricsCollector::notifyMotion(const NotifyMotionArgs& args) {
Prabir Pradhanaff13032023-04-07 22:25:03 +0000227 reportCompletedSessions();
228 onInputDeviceUsage(DeviceId{args.deviceId}, nanoseconds(args.eventTime),
229 [&args](const auto&) { return getUsageSourcesForMotionArgs(args); });
Prabir Pradhan852db892023-04-06 22:16:44 +0000230
Prabir Pradhanaddf8e92023-04-06 00:28:48 +0000231 mNextListener.notify(args);
232}
233
234void InputDeviceMetricsCollector::notifySwitch(const NotifySwitchArgs& args) {
Prabir Pradhanaff13032023-04-07 22:25:03 +0000235 reportCompletedSessions();
Prabir Pradhanaddf8e92023-04-06 00:28:48 +0000236 mNextListener.notify(args);
237}
238
239void InputDeviceMetricsCollector::notifySensor(const NotifySensorArgs& args) {
Prabir Pradhanaff13032023-04-07 22:25:03 +0000240 reportCompletedSessions();
Prabir Pradhanaddf8e92023-04-06 00:28:48 +0000241 mNextListener.notify(args);
242}
243
244void InputDeviceMetricsCollector::notifyVibratorState(const NotifyVibratorStateArgs& args) {
Prabir Pradhanaff13032023-04-07 22:25:03 +0000245 reportCompletedSessions();
Prabir Pradhanaddf8e92023-04-06 00:28:48 +0000246 mNextListener.notify(args);
247}
248
249void InputDeviceMetricsCollector::notifyDeviceReset(const NotifyDeviceResetArgs& args) {
Prabir Pradhanaff13032023-04-07 22:25:03 +0000250 reportCompletedSessions();
Prabir Pradhanaddf8e92023-04-06 00:28:48 +0000251 mNextListener.notify(args);
252}
253
254void InputDeviceMetricsCollector::notifyPointerCaptureChanged(
255 const NotifyPointerCaptureChangedArgs& args) {
Prabir Pradhanaff13032023-04-07 22:25:03 +0000256 reportCompletedSessions();
Prabir Pradhanaddf8e92023-04-06 00:28:48 +0000257 mNextListener.notify(args);
258}
259
Prabir Pradhan8ede1d12023-05-08 19:37:44 +0000260void InputDeviceMetricsCollector::notifyDeviceInteraction(int32_t deviceId, nsecs_t timestamp,
Prabir Pradhan8a5c41d2023-06-08 19:13:46 +0000261 const std::set<Uid>& uids) {
262 mInteractionsQueue.push(DeviceId{deviceId}, timestamp, uids);
Prabir Pradhan8ede1d12023-05-08 19:37:44 +0000263}
264
Prabir Pradhanaddf8e92023-04-06 00:28:48 +0000265void InputDeviceMetricsCollector::dump(std::string& dump) {
266 dump += "InputDeviceMetricsCollector:\n";
Prabir Pradhan852db892023-04-06 22:16:44 +0000267
268 dump += " Logged device IDs: " + dumpMapKeys(mLoggedDeviceInfos, &toString) + "\n";
269 dump += " Devices with active usage sessions: " +
270 dumpMapKeys(mActiveUsageSessions, &toString) + "\n";
271}
272
273void InputDeviceMetricsCollector::onInputDevicesChanged(const std::vector<InputDeviceInfo>& infos) {
Prabir Pradhanaff13032023-04-07 22:25:03 +0000274 std::map<DeviceId, InputDeviceInfo> newDeviceInfos;
Prabir Pradhan852db892023-04-06 22:16:44 +0000275
276 for (const InputDeviceInfo& info : infos) {
277 if (isIgnoredInputDeviceId(info.getId())) {
278 continue;
279 }
Prabir Pradhanaff13032023-04-07 22:25:03 +0000280 newDeviceInfos.emplace(info.getId(), info);
Prabir Pradhan852db892023-04-06 22:16:44 +0000281 }
282
Prabir Pradhanaff13032023-04-07 22:25:03 +0000283 for (auto [deviceId, info] : mLoggedDeviceInfos) {
284 if (newDeviceInfos.count(deviceId) != 0) {
Prabir Pradhan852db892023-04-06 22:16:44 +0000285 continue;
286 }
Prabir Pradhanaff13032023-04-07 22:25:03 +0000287 onInputDeviceRemoved(deviceId, info.getIdentifier());
Prabir Pradhan852db892023-04-06 22:16:44 +0000288 }
289
Prabir Pradhanaff13032023-04-07 22:25:03 +0000290 std::swap(newDeviceInfos, mLoggedDeviceInfos);
Prabir Pradhan852db892023-04-06 22:16:44 +0000291}
292
293void InputDeviceMetricsCollector::onInputDeviceRemoved(DeviceId deviceId,
294 const InputDeviceIdentifier& identifier) {
Prabir Pradhan852db892023-04-06 22:16:44 +0000295 auto it = mActiveUsageSessions.find(deviceId);
Prabir Pradhanaff13032023-04-07 22:25:03 +0000296 if (it == mActiveUsageSessions.end()) {
297 return;
Prabir Pradhan852db892023-04-06 22:16:44 +0000298 }
Prabir Pradhanaff13032023-04-07 22:25:03 +0000299 // Report usage for that device if there is an active session.
300 auto& [_, activeSession] = *it;
301 mLogger.logInputDeviceUsageReported(identifier, activeSession.finishSession());
302 mActiveUsageSessions.erase(it);
303
Prabir Pradhan852db892023-04-06 22:16:44 +0000304 // We don't remove this from mLoggedDeviceInfos because it will be updated in
305 // onInputDevicesChanged().
306}
307
Prabir Pradhanaff13032023-04-07 22:25:03 +0000308void InputDeviceMetricsCollector::onInputDeviceUsage(DeviceId deviceId, nanoseconds eventTime,
309 const SourceProvider& getSources) {
310 auto infoIt = mLoggedDeviceInfos.find(deviceId);
311 if (infoIt == mLoggedDeviceInfos.end()) {
Prabir Pradhan852db892023-04-06 22:16:44 +0000312 // Do not track usage for devices that are not logged.
313 return;
314 }
315
Prabir Pradhanaff13032023-04-07 22:25:03 +0000316 auto [sessionIt, _] =
317 mActiveUsageSessions.try_emplace(deviceId, mUsageSessionTimeout, eventTime);
318 for (InputDeviceUsageSource source : getSources(infoIt->second)) {
319 sessionIt->second.recordUsage(eventTime, source);
Prabir Pradhan852db892023-04-06 22:16:44 +0000320 }
321}
322
Prabir Pradhan44293792023-05-08 19:37:44 +0000323void InputDeviceMetricsCollector::onInputDeviceInteraction(const Interaction& interaction) {
324 auto activeSessionIt = mActiveUsageSessions.find(std::get<DeviceId>(interaction));
325 if (activeSessionIt == mActiveUsageSessions.end()) {
326 return;
327 }
Prabir Pradhan852db892023-04-06 22:16:44 +0000328
Prabir Pradhan44293792023-05-08 19:37:44 +0000329 activeSessionIt->second.recordInteraction(interaction);
330}
331
332void InputDeviceMetricsCollector::reportCompletedSessions() {
333 // Process all pending interactions.
334 for (auto interaction = mInteractionsQueue.pop(); interaction;
335 interaction = mInteractionsQueue.pop()) {
336 onInputDeviceInteraction(*interaction);
337 }
338
339 const auto currentTime = mLogger.getCurrentTime();
Prabir Pradhan852db892023-04-06 22:16:44 +0000340 std::vector<DeviceId> completedUsageSessions;
341
Prabir Pradhan44293792023-05-08 19:37:44 +0000342 // Process usages for all active session to determine if any sessions have expired.
Prabir Pradhanaff13032023-04-07 22:25:03 +0000343 for (auto& [deviceId, activeSession] : mActiveUsageSessions) {
344 if (activeSession.checkIfCompletedAt(currentTime)) {
Prabir Pradhan852db892023-04-06 22:16:44 +0000345 completedUsageSessions.emplace_back(deviceId);
346 }
347 }
348
Prabir Pradhan44293792023-05-08 19:37:44 +0000349 // Close out and log all expired usage sessions.
Prabir Pradhan852db892023-04-06 22:16:44 +0000350 for (DeviceId deviceId : completedUsageSessions) {
Prabir Pradhanaff13032023-04-07 22:25:03 +0000351 const auto infoIt = mLoggedDeviceInfos.find(deviceId);
352 LOG_ALWAYS_FATAL_IF(infoIt == mLoggedDeviceInfos.end());
Prabir Pradhan852db892023-04-06 22:16:44 +0000353
Prabir Pradhanaff13032023-04-07 22:25:03 +0000354 auto activeSessionIt = mActiveUsageSessions.find(deviceId);
355 LOG_ALWAYS_FATAL_IF(activeSessionIt == mActiveUsageSessions.end());
356 auto& [_, activeSession] = *activeSessionIt;
357 mLogger.logInputDeviceUsageReported(infoIt->second.getIdentifier(),
358 activeSession.finishSession());
359 mActiveUsageSessions.erase(activeSessionIt);
Prabir Pradhan852db892023-04-06 22:16:44 +0000360 }
Prabir Pradhanaddf8e92023-04-06 00:28:48 +0000361}
362
Prabir Pradhanaff13032023-04-07 22:25:03 +0000363// --- InputDeviceMetricsCollector::ActiveSession ---
364
365InputDeviceMetricsCollector::ActiveSession::ActiveSession(nanoseconds usageSessionTimeout,
366 nanoseconds startTime)
367 : mUsageSessionTimeout(usageSessionTimeout), mDeviceSession({startTime, startTime}) {}
368
369void InputDeviceMetricsCollector::ActiveSession::recordUsage(nanoseconds eventTime,
370 InputDeviceUsageSource source) {
371 // We assume that event times for subsequent events are always monotonically increasing for each
372 // input device.
373 auto [activeSourceIt, inserted] =
374 mActiveSessionsBySource.try_emplace(source, eventTime, eventTime);
375 if (!inserted) {
376 activeSourceIt->second.end = eventTime;
377 }
378 mDeviceSession.end = eventTime;
379}
380
Prabir Pradhan44293792023-05-08 19:37:44 +0000381void InputDeviceMetricsCollector::ActiveSession::recordInteraction(const Interaction& interaction) {
382 const auto sessionExpiryTime = mDeviceSession.end + mUsageSessionTimeout;
383 const auto timestamp = std::get<nanoseconds>(interaction);
384 if (timestamp >= sessionExpiryTime) {
385 // This interaction occurred after the device's current active session is set to expire.
386 // Ignore it.
387 return;
388 }
389
390 for (Uid uid : std::get<std::set<Uid>>(interaction)) {
391 auto [activeUidIt, inserted] = mActiveSessionsByUid.try_emplace(uid, timestamp, timestamp);
392 if (!inserted) {
393 activeUidIt->second.end = timestamp;
394 }
395 }
396}
397
Prabir Pradhanaff13032023-04-07 22:25:03 +0000398bool InputDeviceMetricsCollector::ActiveSession::checkIfCompletedAt(nanoseconds timestamp) {
399 const auto sessionExpiryTime = timestamp - mUsageSessionTimeout;
400 std::vector<InputDeviceUsageSource> completedSourceSessionsForDevice;
401 for (auto& [source, session] : mActiveSessionsBySource) {
402 if (session.end <= sessionExpiryTime) {
403 completedSourceSessionsForDevice.emplace_back(source);
404 }
405 }
406 for (InputDeviceUsageSource source : completedSourceSessionsForDevice) {
407 auto it = mActiveSessionsBySource.find(source);
408 const auto& [_, session] = *it;
409 mSourceUsageBreakdown.emplace_back(source, session.end - session.start);
410 mActiveSessionsBySource.erase(it);
411 }
Prabir Pradhan44293792023-05-08 19:37:44 +0000412
413 std::vector<Uid> completedUidSessionsForDevice;
414 for (auto& [uid, session] : mActiveSessionsByUid) {
415 if (session.end <= sessionExpiryTime) {
416 completedUidSessionsForDevice.emplace_back(uid);
417 }
418 }
419 for (Uid uid : completedUidSessionsForDevice) {
420 auto it = mActiveSessionsByUid.find(uid);
421 const auto& [_, session] = *it;
422 mUidUsageBreakdown.emplace_back(uid, session.end - session.start);
423 mActiveSessionsByUid.erase(it);
424 }
425
426 // This active session has expired if there are no more active source sessions tracked.
Prabir Pradhanaff13032023-04-07 22:25:03 +0000427 return mActiveSessionsBySource.empty();
428}
429
430InputDeviceMetricsLogger::DeviceUsageReport
431InputDeviceMetricsCollector::ActiveSession::finishSession() {
432 const auto deviceUsageDuration = mDeviceSession.end - mDeviceSession.start;
433
434 for (const auto& [source, sourceSession] : mActiveSessionsBySource) {
435 mSourceUsageBreakdown.emplace_back(source, sourceSession.end - sourceSession.start);
436 }
437 mActiveSessionsBySource.clear();
438
Prabir Pradhan44293792023-05-08 19:37:44 +0000439 for (const auto& [uid, uidSession] : mActiveSessionsByUid) {
440 mUidUsageBreakdown.emplace_back(uid, uidSession.end - uidSession.start);
441 }
442 mActiveSessionsByUid.clear();
443
444 return {deviceUsageDuration, mSourceUsageBreakdown, mUidUsageBreakdown};
Prabir Pradhanaff13032023-04-07 22:25:03 +0000445}
446
Prabir Pradhanaddf8e92023-04-06 00:28:48 +0000447} // namespace android