blob: 56a3fb44b4e55dcd74fea4bddc2e749319121198 [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 Pradhan7adabad2023-06-28 16:16:27 +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
Prabir Pradhan047695b2023-06-30 01:48:45 +000042constexpr size_t INTERACTIONS_QUEUE_CAPACITY = 500;
43
Prabir Pradhan67d09ca2023-09-08 20:28:55 +000044int32_t linuxBusToInputDeviceBusEnum(int32_t linuxBus, bool isUsiStylus) {
45 if (isUsiStylus) {
46 // This is a stylus connected over the Universal Stylus Initiative (USI) protocol.
47 // For metrics purposes, we treat this protocol as a separate bus.
48 return util::INPUT_DEVICE_USAGE_REPORTED__DEVICE_BUS__USI;
49 }
50
Harry Cuttsa34de522023-06-06 15:52:54 +000051 // When adding cases to this switch, also add them to the copy of this method in
52 // TouchpadInputMapper.cpp.
53 // TODO(b/286394420): deduplicate this method with the one in TouchpadInputMapper.cpp.
Prabir Pradhan852db892023-04-06 22:16:44 +000054 switch (linuxBus) {
55 case BUS_USB:
56 return util::INPUT_DEVICE_USAGE_REPORTED__DEVICE_BUS__USB;
57 case BUS_BLUETOOTH:
58 return util::INPUT_DEVICE_USAGE_REPORTED__DEVICE_BUS__BLUETOOTH;
59 default:
60 return util::INPUT_DEVICE_USAGE_REPORTED__DEVICE_BUS__OTHER;
61 }
62}
63
64class : public InputDeviceMetricsLogger {
65 nanoseconds getCurrentTime() override { return nanoseconds(systemTime(SYSTEM_TIME_MONOTONIC)); }
66
Prabir Pradhan67d09ca2023-09-08 20:28:55 +000067 void logInputDeviceUsageReported(const InputDeviceInfo& info,
Prabir Pradhanaff13032023-04-07 22:25:03 +000068 const DeviceUsageReport& report) override {
Prabir Pradhan852db892023-04-06 22:16:44 +000069 const int32_t durationMillis =
Prabir Pradhanaff13032023-04-07 22:25:03 +000070 std::chrono::duration_cast<std::chrono::milliseconds>(report.usageDuration).count();
Prabir Pradhan852db892023-04-06 22:16:44 +000071 const static std::vector<int32_t> empty;
Prabir Pradhan67d09ca2023-09-08 20:28:55 +000072 const auto& identifier = info.getIdentifier();
Prabir Pradhan852db892023-04-06 22:16:44 +000073
74 ALOGD_IF(DEBUG, "Usage session reported for device: %s", identifier.name.c_str());
75 ALOGD_IF(DEBUG, " Total duration: %dms", durationMillis);
Prabir Pradhanaff13032023-04-07 22:25:03 +000076 ALOGD_IF(DEBUG, " Source breakdown:");
77
78 std::vector<int32_t> sources;
79 std::vector<int32_t> durationsPerSource;
80 for (auto& [src, dur] : report.sourceBreakdown) {
81 sources.push_back(ftl::to_underlying(src));
82 int32_t durMillis = std::chrono::duration_cast<std::chrono::milliseconds>(dur).count();
83 durationsPerSource.emplace_back(durMillis);
84 ALOGD_IF(DEBUG, " - usageSource: %s\t duration: %dms",
85 ftl::enum_string(src).c_str(), durMillis);
86 }
Prabir Pradhan852db892023-04-06 22:16:44 +000087
Prabir Pradhan44293792023-05-08 19:37:44 +000088 ALOGD_IF(DEBUG, " Uid breakdown:");
89
90 std::vector<int32_t> uids;
91 std::vector<int32_t> durationsPerUid;
92 for (auto& [uid, dur] : report.uidBreakdown) {
Prabir Pradhan8a5c41d2023-06-08 19:13:46 +000093 uids.push_back(uid.val());
Prabir Pradhan44293792023-05-08 19:37:44 +000094 int32_t durMillis = std::chrono::duration_cast<std::chrono::milliseconds>(dur).count();
95 durationsPerUid.push_back(durMillis);
Prabir Pradhan8a5c41d2023-06-08 19:13:46 +000096 ALOGD_IF(DEBUG, " - uid: %s\t duration: %dms", uid.toString().c_str(),
97 durMillis);
Prabir Pradhan44293792023-05-08 19:37:44 +000098 }
Prabir Pradhan852db892023-04-06 22:16:44 +000099 util::stats_write(util::INPUTDEVICE_USAGE_REPORTED, identifier.vendor, identifier.product,
Prabir Pradhan67d09ca2023-09-08 20:28:55 +0000100 identifier.version,
101 linuxBusToInputDeviceBusEnum(identifier.bus,
102 info.getUsiVersion().has_value()),
Prabir Pradhan44293792023-05-08 19:37:44 +0000103 durationMillis, sources, durationsPerSource, uids, durationsPerUid);
Prabir Pradhan852db892023-04-06 22:16:44 +0000104 }
105} sStatsdLogger;
106
107bool isIgnoredInputDeviceId(int32_t deviceId) {
108 switch (deviceId) {
109 case INVALID_INPUT_DEVICE_ID:
110 case VIRTUAL_KEYBOARD_ID:
111 return true;
112 default:
113 return false;
114 }
115}
116
117} // namespace
118
Prabir Pradhanae10ee62023-05-12 19:44:18 +0000119InputDeviceUsageSource getUsageSourceForKeyArgs(const InputDeviceInfo& info,
120 const NotifyKeyArgs& keyArgs) {
121 if (!isFromSource(keyArgs.source, AINPUT_SOURCE_KEYBOARD)) {
122 return InputDeviceUsageSource::UNKNOWN;
123 }
124
125 if (isFromSource(keyArgs.source, AINPUT_SOURCE_DPAD) &&
126 DPAD_ALL_KEYCODES.count(keyArgs.keyCode) != 0) {
127 return InputDeviceUsageSource::DPAD;
128 }
129
130 if (isFromSource(keyArgs.source, AINPUT_SOURCE_GAMEPAD) &&
131 GAMEPAD_KEYCODES.count(keyArgs.keyCode) != 0) {
132 return InputDeviceUsageSource::GAMEPAD;
133 }
134
135 if (info.getKeyboardType() == AINPUT_KEYBOARD_TYPE_ALPHABETIC) {
136 return InputDeviceUsageSource::KEYBOARD;
137 }
138
139 return InputDeviceUsageSource::BUTTONS;
140}
141
142std::set<InputDeviceUsageSource> getUsageSourcesForMotionArgs(const NotifyMotionArgs& motionArgs) {
Siarhei Vishniakou3218fc02023-06-15 20:41:02 -0700143 LOG_ALWAYS_FATAL_IF(motionArgs.getPointerCount() < 1, "Received motion args without pointers");
Prabir Pradhanae10ee62023-05-12 19:44:18 +0000144 std::set<InputDeviceUsageSource> sources;
145
Siarhei Vishniakou3218fc02023-06-15 20:41:02 -0700146 for (uint32_t i = 0; i < motionArgs.getPointerCount(); i++) {
Prabir Pradhanae10ee62023-05-12 19:44:18 +0000147 const auto toolType = motionArgs.pointerProperties[i].toolType;
148 if (isFromSource(motionArgs.source, AINPUT_SOURCE_MOUSE)) {
149 if (toolType == ToolType::MOUSE) {
150 sources.emplace(InputDeviceUsageSource::MOUSE);
151 continue;
152 }
153 if (toolType == ToolType::FINGER) {
154 sources.emplace(InputDeviceUsageSource::TOUCHPAD);
155 continue;
156 }
157 if (isStylusToolType(toolType)) {
158 sources.emplace(InputDeviceUsageSource::STYLUS_INDIRECT);
159 continue;
160 }
161 }
162 if (isFromSource(motionArgs.source, AINPUT_SOURCE_MOUSE_RELATIVE) &&
163 toolType == ToolType::MOUSE) {
164 sources.emplace(InputDeviceUsageSource::MOUSE_CAPTURED);
165 continue;
166 }
167 if (isFromSource(motionArgs.source, AINPUT_SOURCE_TOUCHPAD) &&
168 toolType == ToolType::FINGER) {
169 sources.emplace(InputDeviceUsageSource::TOUCHPAD_CAPTURED);
170 continue;
171 }
172 if (isFromSource(motionArgs.source, AINPUT_SOURCE_BLUETOOTH_STYLUS) &&
173 isStylusToolType(toolType)) {
174 sources.emplace(InputDeviceUsageSource::STYLUS_FUSED);
175 continue;
176 }
177 if (isFromSource(motionArgs.source, AINPUT_SOURCE_STYLUS) && isStylusToolType(toolType)) {
178 sources.emplace(InputDeviceUsageSource::STYLUS_DIRECT);
179 continue;
180 }
181 if (isFromSource(motionArgs.source, AINPUT_SOURCE_TOUCH_NAVIGATION)) {
182 sources.emplace(InputDeviceUsageSource::TOUCH_NAVIGATION);
183 continue;
184 }
185 if (isFromSource(motionArgs.source, AINPUT_SOURCE_JOYSTICK)) {
186 sources.emplace(InputDeviceUsageSource::JOYSTICK);
187 continue;
188 }
189 if (isFromSource(motionArgs.source, AINPUT_SOURCE_ROTARY_ENCODER)) {
190 sources.emplace(InputDeviceUsageSource::ROTARY_ENCODER);
191 continue;
192 }
193 if (isFromSource(motionArgs.source, AINPUT_SOURCE_TRACKBALL)) {
194 sources.emplace(InputDeviceUsageSource::TRACKBALL);
195 continue;
196 }
197 if (isFromSource(motionArgs.source, AINPUT_SOURCE_TOUCHSCREEN)) {
198 sources.emplace(InputDeviceUsageSource::TOUCHSCREEN);
199 continue;
200 }
201 sources.emplace(InputDeviceUsageSource::UNKNOWN);
202 }
203
204 return sources;
205}
206
207// --- InputDeviceMetricsCollector ---
208
Prabir Pradhanaddf8e92023-04-06 00:28:48 +0000209InputDeviceMetricsCollector::InputDeviceMetricsCollector(InputListenerInterface& listener)
Prabir Pradhan852db892023-04-06 22:16:44 +0000210 : InputDeviceMetricsCollector(listener, sStatsdLogger, DEFAULT_USAGE_SESSION_TIMEOUT) {}
211
212InputDeviceMetricsCollector::InputDeviceMetricsCollector(InputListenerInterface& listener,
213 InputDeviceMetricsLogger& logger,
214 nanoseconds usageSessionTimeout)
Prabir Pradhan047695b2023-06-30 01:48:45 +0000215 : mNextListener(listener),
216 mLogger(logger),
217 mUsageSessionTimeout(usageSessionTimeout),
218 mInteractionsQueue(INTERACTIONS_QUEUE_CAPACITY) {}
Prabir Pradhanaddf8e92023-04-06 00:28:48 +0000219
220void InputDeviceMetricsCollector::notifyInputDevicesChanged(
221 const NotifyInputDevicesChangedArgs& args) {
Prabir Pradhanaff13032023-04-07 22:25:03 +0000222 reportCompletedSessions();
Prabir Pradhan852db892023-04-06 22:16:44 +0000223 onInputDevicesChanged(args.inputDeviceInfos);
Prabir Pradhanaddf8e92023-04-06 00:28:48 +0000224 mNextListener.notify(args);
225}
226
227void InputDeviceMetricsCollector::notifyConfigurationChanged(
228 const NotifyConfigurationChangedArgs& args) {
Prabir Pradhanaff13032023-04-07 22:25:03 +0000229 reportCompletedSessions();
Prabir Pradhanaddf8e92023-04-06 00:28:48 +0000230 mNextListener.notify(args);
231}
232
233void InputDeviceMetricsCollector::notifyKey(const NotifyKeyArgs& args) {
Prabir Pradhanaff13032023-04-07 22:25:03 +0000234 reportCompletedSessions();
235 const SourceProvider getSources = [&args](const InputDeviceInfo& info) {
236 return std::set{getUsageSourceForKeyArgs(info, args)};
237 };
238 onInputDeviceUsage(DeviceId{args.deviceId}, nanoseconds(args.eventTime), getSources);
Prabir Pradhan852db892023-04-06 22:16:44 +0000239
Prabir Pradhanaddf8e92023-04-06 00:28:48 +0000240 mNextListener.notify(args);
241}
242
243void InputDeviceMetricsCollector::notifyMotion(const NotifyMotionArgs& args) {
Prabir Pradhanaff13032023-04-07 22:25:03 +0000244 reportCompletedSessions();
245 onInputDeviceUsage(DeviceId{args.deviceId}, nanoseconds(args.eventTime),
246 [&args](const auto&) { return getUsageSourcesForMotionArgs(args); });
Prabir Pradhan852db892023-04-06 22:16:44 +0000247
Prabir Pradhanaddf8e92023-04-06 00:28:48 +0000248 mNextListener.notify(args);
249}
250
251void InputDeviceMetricsCollector::notifySwitch(const NotifySwitchArgs& 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::notifySensor(const NotifySensorArgs& args) {
Prabir Pradhanaff13032023-04-07 22:25:03 +0000257 reportCompletedSessions();
Prabir Pradhanaddf8e92023-04-06 00:28:48 +0000258 mNextListener.notify(args);
259}
260
261void InputDeviceMetricsCollector::notifyVibratorState(const NotifyVibratorStateArgs& args) {
Prabir Pradhanaff13032023-04-07 22:25:03 +0000262 reportCompletedSessions();
Prabir Pradhanaddf8e92023-04-06 00:28:48 +0000263 mNextListener.notify(args);
264}
265
266void InputDeviceMetricsCollector::notifyDeviceReset(const NotifyDeviceResetArgs& args) {
Prabir Pradhanaff13032023-04-07 22:25:03 +0000267 reportCompletedSessions();
Prabir Pradhanaddf8e92023-04-06 00:28:48 +0000268 mNextListener.notify(args);
269}
270
271void InputDeviceMetricsCollector::notifyPointerCaptureChanged(
272 const NotifyPointerCaptureChangedArgs& args) {
Prabir Pradhanaff13032023-04-07 22:25:03 +0000273 reportCompletedSessions();
Prabir Pradhanaddf8e92023-04-06 00:28:48 +0000274 mNextListener.notify(args);
275}
276
Prabir Pradhan8ede1d12023-05-08 19:37:44 +0000277void InputDeviceMetricsCollector::notifyDeviceInteraction(int32_t deviceId, nsecs_t timestamp,
Prabir Pradhan8a5c41d2023-06-08 19:13:46 +0000278 const std::set<Uid>& uids) {
Prabir Pradhan047695b2023-06-30 01:48:45 +0000279 if (isIgnoredInputDeviceId(deviceId)) {
280 return;
281 }
Prabir Pradhan8a5c41d2023-06-08 19:13:46 +0000282 mInteractionsQueue.push(DeviceId{deviceId}, timestamp, uids);
Prabir Pradhan8ede1d12023-05-08 19:37:44 +0000283}
284
Prabir Pradhanaddf8e92023-04-06 00:28:48 +0000285void InputDeviceMetricsCollector::dump(std::string& dump) {
286 dump += "InputDeviceMetricsCollector:\n";
Prabir Pradhan852db892023-04-06 22:16:44 +0000287
288 dump += " Logged device IDs: " + dumpMapKeys(mLoggedDeviceInfos, &toString) + "\n";
289 dump += " Devices with active usage sessions: " +
290 dumpMapKeys(mActiveUsageSessions, &toString) + "\n";
291}
292
293void InputDeviceMetricsCollector::onInputDevicesChanged(const std::vector<InputDeviceInfo>& infos) {
Prabir Pradhanaff13032023-04-07 22:25:03 +0000294 std::map<DeviceId, InputDeviceInfo> newDeviceInfos;
Prabir Pradhan852db892023-04-06 22:16:44 +0000295
296 for (const InputDeviceInfo& info : infos) {
297 if (isIgnoredInputDeviceId(info.getId())) {
298 continue;
299 }
Prabir Pradhanaff13032023-04-07 22:25:03 +0000300 newDeviceInfos.emplace(info.getId(), info);
Prabir Pradhan852db892023-04-06 22:16:44 +0000301 }
302
Prabir Pradhanaff13032023-04-07 22:25:03 +0000303 for (auto [deviceId, info] : mLoggedDeviceInfos) {
304 if (newDeviceInfos.count(deviceId) != 0) {
Prabir Pradhan852db892023-04-06 22:16:44 +0000305 continue;
306 }
Prabir Pradhan67d09ca2023-09-08 20:28:55 +0000307 onInputDeviceRemoved(deviceId, info);
Prabir Pradhan852db892023-04-06 22:16:44 +0000308 }
309
Prabir Pradhanaff13032023-04-07 22:25:03 +0000310 std::swap(newDeviceInfos, mLoggedDeviceInfos);
Prabir Pradhan852db892023-04-06 22:16:44 +0000311}
312
313void InputDeviceMetricsCollector::onInputDeviceRemoved(DeviceId deviceId,
Prabir Pradhan67d09ca2023-09-08 20:28:55 +0000314 const InputDeviceInfo& info) {
Prabir Pradhan852db892023-04-06 22:16:44 +0000315 auto it = mActiveUsageSessions.find(deviceId);
Prabir Pradhanaff13032023-04-07 22:25:03 +0000316 if (it == mActiveUsageSessions.end()) {
317 return;
Prabir Pradhan852db892023-04-06 22:16:44 +0000318 }
Prabir Pradhanaff13032023-04-07 22:25:03 +0000319 // Report usage for that device if there is an active session.
320 auto& [_, activeSession] = *it;
Prabir Pradhan67d09ca2023-09-08 20:28:55 +0000321 mLogger.logInputDeviceUsageReported(info, activeSession.finishSession());
Prabir Pradhanaff13032023-04-07 22:25:03 +0000322 mActiveUsageSessions.erase(it);
323
Prabir Pradhan852db892023-04-06 22:16:44 +0000324 // We don't remove this from mLoggedDeviceInfos because it will be updated in
325 // onInputDevicesChanged().
326}
327
Prabir Pradhanaff13032023-04-07 22:25:03 +0000328void InputDeviceMetricsCollector::onInputDeviceUsage(DeviceId deviceId, nanoseconds eventTime,
329 const SourceProvider& getSources) {
330 auto infoIt = mLoggedDeviceInfos.find(deviceId);
331 if (infoIt == mLoggedDeviceInfos.end()) {
Prabir Pradhan852db892023-04-06 22:16:44 +0000332 // Do not track usage for devices that are not logged.
333 return;
334 }
335
Prabir Pradhanaff13032023-04-07 22:25:03 +0000336 auto [sessionIt, _] =
337 mActiveUsageSessions.try_emplace(deviceId, mUsageSessionTimeout, eventTime);
338 for (InputDeviceUsageSource source : getSources(infoIt->second)) {
339 sessionIt->second.recordUsage(eventTime, source);
Prabir Pradhan852db892023-04-06 22:16:44 +0000340 }
341}
342
Prabir Pradhan44293792023-05-08 19:37:44 +0000343void InputDeviceMetricsCollector::onInputDeviceInteraction(const Interaction& interaction) {
344 auto activeSessionIt = mActiveUsageSessions.find(std::get<DeviceId>(interaction));
345 if (activeSessionIt == mActiveUsageSessions.end()) {
346 return;
347 }
Prabir Pradhan852db892023-04-06 22:16:44 +0000348
Prabir Pradhan44293792023-05-08 19:37:44 +0000349 activeSessionIt->second.recordInteraction(interaction);
350}
351
352void InputDeviceMetricsCollector::reportCompletedSessions() {
353 // Process all pending interactions.
354 for (auto interaction = mInteractionsQueue.pop(); interaction;
355 interaction = mInteractionsQueue.pop()) {
356 onInputDeviceInteraction(*interaction);
357 }
358
359 const auto currentTime = mLogger.getCurrentTime();
Prabir Pradhan852db892023-04-06 22:16:44 +0000360 std::vector<DeviceId> completedUsageSessions;
361
Prabir Pradhan44293792023-05-08 19:37:44 +0000362 // Process usages for all active session to determine if any sessions have expired.
Prabir Pradhanaff13032023-04-07 22:25:03 +0000363 for (auto& [deviceId, activeSession] : mActiveUsageSessions) {
364 if (activeSession.checkIfCompletedAt(currentTime)) {
Prabir Pradhan852db892023-04-06 22:16:44 +0000365 completedUsageSessions.emplace_back(deviceId);
366 }
367 }
368
Prabir Pradhan44293792023-05-08 19:37:44 +0000369 // Close out and log all expired usage sessions.
Prabir Pradhan852db892023-04-06 22:16:44 +0000370 for (DeviceId deviceId : completedUsageSessions) {
Prabir Pradhanaff13032023-04-07 22:25:03 +0000371 const auto infoIt = mLoggedDeviceInfos.find(deviceId);
372 LOG_ALWAYS_FATAL_IF(infoIt == mLoggedDeviceInfos.end());
Prabir Pradhan852db892023-04-06 22:16:44 +0000373
Prabir Pradhanaff13032023-04-07 22:25:03 +0000374 auto activeSessionIt = mActiveUsageSessions.find(deviceId);
375 LOG_ALWAYS_FATAL_IF(activeSessionIt == mActiveUsageSessions.end());
376 auto& [_, activeSession] = *activeSessionIt;
Prabir Pradhan67d09ca2023-09-08 20:28:55 +0000377 mLogger.logInputDeviceUsageReported(infoIt->second, activeSession.finishSession());
Prabir Pradhanaff13032023-04-07 22:25:03 +0000378 mActiveUsageSessions.erase(activeSessionIt);
Prabir Pradhan852db892023-04-06 22:16:44 +0000379 }
Prabir Pradhanaddf8e92023-04-06 00:28:48 +0000380}
381
Prabir Pradhanaff13032023-04-07 22:25:03 +0000382// --- InputDeviceMetricsCollector::ActiveSession ---
383
384InputDeviceMetricsCollector::ActiveSession::ActiveSession(nanoseconds usageSessionTimeout,
385 nanoseconds startTime)
386 : mUsageSessionTimeout(usageSessionTimeout), mDeviceSession({startTime, startTime}) {}
387
388void InputDeviceMetricsCollector::ActiveSession::recordUsage(nanoseconds eventTime,
389 InputDeviceUsageSource source) {
390 // We assume that event times for subsequent events are always monotonically increasing for each
391 // input device.
392 auto [activeSourceIt, inserted] =
393 mActiveSessionsBySource.try_emplace(source, eventTime, eventTime);
394 if (!inserted) {
395 activeSourceIt->second.end = eventTime;
396 }
397 mDeviceSession.end = eventTime;
398}
399
Prabir Pradhan44293792023-05-08 19:37:44 +0000400void InputDeviceMetricsCollector::ActiveSession::recordInteraction(const Interaction& interaction) {
401 const auto sessionExpiryTime = mDeviceSession.end + mUsageSessionTimeout;
402 const auto timestamp = std::get<nanoseconds>(interaction);
403 if (timestamp >= sessionExpiryTime) {
404 // This interaction occurred after the device's current active session is set to expire.
405 // Ignore it.
406 return;
407 }
408
409 for (Uid uid : std::get<std::set<Uid>>(interaction)) {
410 auto [activeUidIt, inserted] = mActiveSessionsByUid.try_emplace(uid, timestamp, timestamp);
411 if (!inserted) {
412 activeUidIt->second.end = timestamp;
413 }
414 }
415}
416
Prabir Pradhanaff13032023-04-07 22:25:03 +0000417bool InputDeviceMetricsCollector::ActiveSession::checkIfCompletedAt(nanoseconds timestamp) {
418 const auto sessionExpiryTime = timestamp - mUsageSessionTimeout;
419 std::vector<InputDeviceUsageSource> completedSourceSessionsForDevice;
420 for (auto& [source, session] : mActiveSessionsBySource) {
421 if (session.end <= sessionExpiryTime) {
422 completedSourceSessionsForDevice.emplace_back(source);
423 }
424 }
425 for (InputDeviceUsageSource source : completedSourceSessionsForDevice) {
426 auto it = mActiveSessionsBySource.find(source);
427 const auto& [_, session] = *it;
428 mSourceUsageBreakdown.emplace_back(source, session.end - session.start);
429 mActiveSessionsBySource.erase(it);
430 }
Prabir Pradhan44293792023-05-08 19:37:44 +0000431
432 std::vector<Uid> completedUidSessionsForDevice;
433 for (auto& [uid, session] : mActiveSessionsByUid) {
434 if (session.end <= sessionExpiryTime) {
435 completedUidSessionsForDevice.emplace_back(uid);
436 }
437 }
438 for (Uid uid : completedUidSessionsForDevice) {
439 auto it = mActiveSessionsByUid.find(uid);
440 const auto& [_, session] = *it;
441 mUidUsageBreakdown.emplace_back(uid, session.end - session.start);
442 mActiveSessionsByUid.erase(it);
443 }
444
445 // This active session has expired if there are no more active source sessions tracked.
Prabir Pradhanaff13032023-04-07 22:25:03 +0000446 return mActiveSessionsBySource.empty();
447}
448
449InputDeviceMetricsLogger::DeviceUsageReport
450InputDeviceMetricsCollector::ActiveSession::finishSession() {
451 const auto deviceUsageDuration = mDeviceSession.end - mDeviceSession.start;
452
453 for (const auto& [source, sourceSession] : mActiveSessionsBySource) {
454 mSourceUsageBreakdown.emplace_back(source, sourceSession.end - sourceSession.start);
455 }
456 mActiveSessionsBySource.clear();
457
Prabir Pradhan44293792023-05-08 19:37:44 +0000458 for (const auto& [uid, uidSession] : mActiveSessionsByUid) {
459 mUidUsageBreakdown.emplace_back(uid, uidSession.end - uidSession.start);
460 }
461 mActiveSessionsByUid.clear();
462
463 return {deviceUsageDuration, mSourceUsageBreakdown, mUidUsageBreakdown};
Prabir Pradhanaff13032023-04-07 22:25:03 +0000464}
465
Prabir Pradhanaddf8e92023-04-06 00:28:48 +0000466} // namespace android