diff options
author | 2023-06-21 16:19:07 +0000 | |
---|---|---|
committer | 2023-06-21 16:19:07 +0000 | |
commit | c16c3d24b72c5ad015cf76208b9ee14fcaf075c6 (patch) | |
tree | bf52a58553032bd38cca4580eb52d03b65dc748c | |
parent | 8bea9dbe5363014b04e3c9fae7a01a457d335893 (diff) | |
parent | a34de5209546e74a5ad6e4c348016d70271a6492 (diff) |
Merge "TouchpadInputMapper: report usage metrics" into udc-qpr-dev
4 files changed, 157 insertions, 1 deletions
diff --git a/services/inputflinger/InputDeviceMetricsCollector.cpp b/services/inputflinger/InputDeviceMetricsCollector.cpp index 55b1df13cb..2319d51441 100644 --- a/services/inputflinger/InputDeviceMetricsCollector.cpp +++ b/services/inputflinger/InputDeviceMetricsCollector.cpp @@ -40,6 +40,9 @@ constexpr nanoseconds DEFAULT_USAGE_SESSION_TIMEOUT = std::chrono::minutes(2); const bool DEBUG = __android_log_is_loggable(ANDROID_LOG_DEBUG, LOG_TAG, ANDROID_LOG_INFO); int32_t linuxBusToInputDeviceBusEnum(int32_t linuxBus) { + // When adding cases to this switch, also add them to the copy of this method in + // TouchpadInputMapper.cpp. + // TODO(b/286394420): deduplicate this method with the one in TouchpadInputMapper.cpp. switch (linuxBus) { case BUS_USB: return util::INPUT_DEVICE_USAGE_REPORTED__DEVICE_BUS__USB; diff --git a/services/inputflinger/reader/Android.bp b/services/inputflinger/reader/Android.bp index b0edb5746c..ccb8773ed0 100644 --- a/services/inputflinger/reader/Android.bp +++ b/services/inputflinger/reader/Android.bp @@ -98,12 +98,14 @@ cc_defaults { android: { shared_libs: [ "libinput", + "libstatspull", ], }, host: { static_libs: [ "libinput", "libbinder", + "libstatspull", ], }, }, diff --git a/services/inputflinger/reader/mapper/TouchpadInputMapper.cpp b/services/inputflinger/reader/mapper/TouchpadInputMapper.cpp index c72425a90b..ca4dd1e806 100644 --- a/services/inputflinger/reader/mapper/TouchpadInputMapper.cpp +++ b/services/inputflinger/reader/mapper/TouchpadInputMapper.cpp @@ -16,8 +16,11 @@ #include "../Macros.h" +#include <algorithm> #include <chrono> +#include <iterator> #include <limits> +#include <map> #include <optional> #include <android-base/stringprintf.h> @@ -26,6 +29,8 @@ #include <input/PrintTools.h> #include <linux/input-event-codes.h> #include <log/log_main.h> +#include <stats_pull_atom_callback.h> +#include <statslog.h> #include "TouchCursorInputMapperCommon.h" #include "TouchpadInputMapper.h" #include "ui/Rotation.h" @@ -169,6 +174,106 @@ void gestureInterpreterCallback(void* clientData, const Gesture* gesture) { mapper->consumeGesture(gesture); } +int32_t linuxBusToInputDeviceBusEnum(int32_t linuxBus) { + // When adding cases to this switch, also add them to the copy of this method in + // InputDeviceMetricsCollector.cpp. + // TODO(b/286394420): deduplicate this method with the one in InputDeviceMetricsCollector.cpp. + switch (linuxBus) { + case BUS_USB: + return util::INPUT_DEVICE_USAGE_REPORTED__DEVICE_BUS__USB; + case BUS_BLUETOOTH: + return util::INPUT_DEVICE_USAGE_REPORTED__DEVICE_BUS__BLUETOOTH; + default: + return util::INPUT_DEVICE_USAGE_REPORTED__DEVICE_BUS__OTHER; + } +} + +class MetricsAccumulator { +public: + static MetricsAccumulator& getInstance() { + static MetricsAccumulator sAccumulator; + return sAccumulator; + } + + void recordFinger(const TouchpadInputMapper::MetricsIdentifier& id) { mCounters[id].fingers++; } + + void recordPalm(const TouchpadInputMapper::MetricsIdentifier& id) { mCounters[id].palms++; } + + // Checks whether a Gesture struct is for the end of a gesture that we log metrics for, and + // records it if so. + void processGesture(const TouchpadInputMapper::MetricsIdentifier& id, const Gesture& gesture) { + switch (gesture.type) { + case kGestureTypeFling: + if (gesture.details.fling.fling_state == GESTURES_FLING_START) { + // Indicates the end of a two-finger scroll gesture. + mCounters[id].twoFingerSwipeGestures++; + } + break; + case kGestureTypeSwipeLift: + mCounters[id].threeFingerSwipeGestures++; + break; + case kGestureTypeFourFingerSwipeLift: + mCounters[id].fourFingerSwipeGestures++; + break; + case kGestureTypePinch: + if (gesture.details.pinch.zoom_state == GESTURES_ZOOM_END) { + mCounters[id].pinchGestures++; + } + break; + default: + // We're not interested in any other gestures. + break; + } + } + +private: + MetricsAccumulator() { + AStatsManager_setPullAtomCallback(android::util::TOUCHPAD_USAGE, /*metadata=*/nullptr, + MetricsAccumulator::pullAtomCallback, /*cookie=*/nullptr); + } + + ~MetricsAccumulator() { AStatsManager_clearPullAtomCallback(android::util::TOUCHPAD_USAGE); } + + static AStatsManager_PullAtomCallbackReturn pullAtomCallback(int32_t atomTag, + AStatsEventList* outEventList, + void* cookie) { + LOG_ALWAYS_FATAL_IF(atomTag != android::util::TOUCHPAD_USAGE); + MetricsAccumulator& accumulator = MetricsAccumulator::getInstance(); + accumulator.produceAtoms(outEventList); + accumulator.resetCounters(); + return AStatsManager_PULL_SUCCESS; + } + + void produceAtoms(AStatsEventList* outEventList) const { + for (auto& [id, counters] : mCounters) { + auto [busId, vendorId, productId, versionId] = id; + addAStatsEvent(outEventList, android::util::TOUCHPAD_USAGE, vendorId, productId, + versionId, linuxBusToInputDeviceBusEnum(busId), counters.fingers, + counters.palms, counters.twoFingerSwipeGestures, + counters.threeFingerSwipeGestures, counters.fourFingerSwipeGestures, + counters.pinchGestures); + } + } + + void resetCounters() { mCounters.clear(); } + + // Stores the counters for a specific touchpad model. Fields have the same meanings as those of + // the TouchpadUsage atom; see that definition for detailed documentation. + struct Counters { + int32_t fingers = 0; + int32_t palms = 0; + + int32_t twoFingerSwipeGestures = 0; + int32_t threeFingerSwipeGestures = 0; + int32_t fourFingerSwipeGestures = 0; + int32_t pinchGestures = 0; + }; + + // Metrics are aggregated by device model and version, so if two devices of the same model and + // version are connected at once, they will have the same counters. + std::map<TouchpadInputMapper::MetricsIdentifier, Counters> mCounters; +}; + } // namespace TouchpadInputMapper::TouchpadInputMapper(InputDeviceContext& deviceContext, @@ -178,7 +283,8 @@ TouchpadInputMapper::TouchpadInputMapper(InputDeviceContext& deviceContext, mPointerController(getContext()->getPointerController(getDeviceId())), mStateConverter(deviceContext, mMotionAccumulator), mGestureConverter(*getContext(), deviceContext, getDeviceId()), - mCapturedEventConverter(*getContext(), deviceContext, mMotionAccumulator, getDeviceId()) { + mCapturedEventConverter(*getContext(), deviceContext, mMotionAccumulator, getDeviceId()), + mMetricsId(metricsIdFromInputDeviceIdentifier(deviceContext.getDeviceIdentifier())) { RawAbsoluteAxisInfo slotAxisInfo; deviceContext.getAbsoluteAxisInfo(ABS_MT_SLOT, &slotAxisInfo); if (!slotAxisInfo.valid || slotAxisInfo.maxValue <= 0) { @@ -331,12 +437,39 @@ std::list<NotifyArgs> TouchpadInputMapper::process(const RawEvent* rawEvent) { } std::optional<SelfContainedHardwareState> state = mStateConverter.processRawEvent(rawEvent); if (state) { + updatePalmDetectionMetrics(); return sendHardwareState(rawEvent->when, rawEvent->readTime, *state); } else { return {}; } } +void TouchpadInputMapper::updatePalmDetectionMetrics() { + std::set<int32_t> currentTrackingIds; + for (size_t i = 0; i < mMotionAccumulator.getSlotCount(); i++) { + const MultiTouchMotionAccumulator::Slot& slot = mMotionAccumulator.getSlot(i); + if (!slot.isInUse()) { + continue; + } + currentTrackingIds.insert(slot.getTrackingId()); + if (slot.getToolType() == ToolType::PALM) { + mPalmTrackingIds.insert(slot.getTrackingId()); + } + } + std::vector<int32_t> liftedTouches; + std::set_difference(mLastFrameTrackingIds.begin(), mLastFrameTrackingIds.end(), + currentTrackingIds.begin(), currentTrackingIds.end(), + std::inserter(liftedTouches, liftedTouches.begin())); + for (int32_t trackingId : liftedTouches) { + if (mPalmTrackingIds.erase(trackingId) > 0) { + MetricsAccumulator::getInstance().recordPalm(mMetricsId); + } else { + MetricsAccumulator::getInstance().recordFinger(mMetricsId); + } + } + mLastFrameTrackingIds = currentTrackingIds; +} + std::list<NotifyArgs> TouchpadInputMapper::sendHardwareState(nsecs_t when, nsecs_t readTime, SelfContainedHardwareState schs) { ALOGD_IF(DEBUG_TOUCHPAD_GESTURES, "New hardware state: %s", schs.state.String().c_str()); @@ -363,8 +496,10 @@ void TouchpadInputMapper::consumeGesture(const Gesture* gesture) { std::list<NotifyArgs> TouchpadInputMapper::processGestures(nsecs_t when, nsecs_t readTime) { std::list<NotifyArgs> out = {}; + MetricsAccumulator& metricsAccumulator = MetricsAccumulator::getInstance(); for (Gesture& gesture : mGesturesToProcess) { out += mGestureConverter.handleGesture(when, readTime, gesture); + metricsAccumulator.processGesture(mMetricsId, gesture); } mGesturesToProcess.clear(); return out; diff --git a/services/inputflinger/reader/mapper/TouchpadInputMapper.h b/services/inputflinger/reader/mapper/TouchpadInputMapper.h index 23d0fd3cf3..73ca5afa04 100644 --- a/services/inputflinger/reader/mapper/TouchpadInputMapper.h +++ b/services/inputflinger/reader/mapper/TouchpadInputMapper.h @@ -18,6 +18,7 @@ #include <list> #include <memory> +#include <set> #include <vector> #include <PointerControllerInterface.h> @@ -58,10 +59,16 @@ public: void consumeGesture(const Gesture* gesture); + // A subset of InputDeviceIdentifier used for logging metrics, to avoid storing a copy of the + // strings in that bigger struct. + using MetricsIdentifier = std::tuple<uint16_t /*busId*/, uint16_t /*vendorId*/, + uint16_t /*productId*/, uint16_t /*version*/>; + private: void resetGestureInterpreter(nsecs_t when); explicit TouchpadInputMapper(InputDeviceContext& deviceContext, const InputReaderConfiguration& readerConfig); + void updatePalmDetectionMetrics(); [[nodiscard]] std::list<NotifyArgs> sendHardwareState(nsecs_t when, nsecs_t readTime, SelfContainedHardwareState schs); [[nodiscard]] std::list<NotifyArgs> processGestures(nsecs_t when, nsecs_t readTime); @@ -86,6 +93,15 @@ private: bool mProcessing = false; bool mResettingInterpreter = false; std::vector<Gesture> mGesturesToProcess; + + static MetricsIdentifier metricsIdFromInputDeviceIdentifier(const InputDeviceIdentifier& id) { + return std::make_tuple(id.bus, id.vendor, id.product, id.version); + } + const MetricsIdentifier mMetricsId; + // Tracking IDs for touches on the pad in the last evdev frame. + std::set<int32_t> mLastFrameTrackingIds; + // Tracking IDs for touches that have at some point been reported as palms by the touchpad. + std::set<int32_t> mPalmTrackingIds; }; } // namespace android |