Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit c16c3d24 authored by Harry Cutts's avatar Harry Cutts Committed by Android (Google) Code Review
Browse files

Merge "TouchpadInputMapper: report usage metrics" into udc-qpr-dev

parents 8bea9dbe a34de520
Loading
Loading
Loading
Loading
+3 −0
Original line number Original line Diff line number Diff line
@@ -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);
const bool DEBUG = __android_log_is_loggable(ANDROID_LOG_DEBUG, LOG_TAG, ANDROID_LOG_INFO);


int32_t linuxBusToInputDeviceBusEnum(int32_t linuxBus) {
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) {
    switch (linuxBus) {
        case BUS_USB:
        case BUS_USB:
            return util::INPUT_DEVICE_USAGE_REPORTED__DEVICE_BUS__USB;
            return util::INPUT_DEVICE_USAGE_REPORTED__DEVICE_BUS__USB;
+2 −0
Original line number Original line Diff line number Diff line
@@ -98,12 +98,14 @@ cc_defaults {
        android: {
        android: {
            shared_libs: [
            shared_libs: [
                "libinput",
                "libinput",
                "libstatspull",
            ],
            ],
        },
        },
        host: {
        host: {
            static_libs: [
            static_libs: [
                "libinput",
                "libinput",
                "libbinder",
                "libbinder",
                "libstatspull",
            ],
            ],
        },
        },
    },
    },
+136 −1
Original line number Original line Diff line number Diff line
@@ -16,8 +16,11 @@


#include "../Macros.h"
#include "../Macros.h"


#include <algorithm>
#include <chrono>
#include <chrono>
#include <iterator>
#include <limits>
#include <limits>
#include <map>
#include <optional>
#include <optional>


#include <android-base/stringprintf.h>
#include <android-base/stringprintf.h>
@@ -26,6 +29,8 @@
#include <input/PrintTools.h>
#include <input/PrintTools.h>
#include <linux/input-event-codes.h>
#include <linux/input-event-codes.h>
#include <log/log_main.h>
#include <log/log_main.h>
#include <stats_pull_atom_callback.h>
#include <statslog.h>
#include "TouchCursorInputMapperCommon.h"
#include "TouchCursorInputMapperCommon.h"
#include "TouchpadInputMapper.h"
#include "TouchpadInputMapper.h"
#include "ui/Rotation.h"
#include "ui/Rotation.h"
@@ -169,6 +174,106 @@ void gestureInterpreterCallback(void* clientData, const Gesture* gesture) {
    mapper->consumeGesture(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
} // namespace


TouchpadInputMapper::TouchpadInputMapper(InputDeviceContext& deviceContext,
TouchpadInputMapper::TouchpadInputMapper(InputDeviceContext& deviceContext,
@@ -178,7 +283,8 @@ TouchpadInputMapper::TouchpadInputMapper(InputDeviceContext& deviceContext,
        mPointerController(getContext()->getPointerController(getDeviceId())),
        mPointerController(getContext()->getPointerController(getDeviceId())),
        mStateConverter(deviceContext, mMotionAccumulator),
        mStateConverter(deviceContext, mMotionAccumulator),
        mGestureConverter(*getContext(), deviceContext, getDeviceId()),
        mGestureConverter(*getContext(), deviceContext, getDeviceId()),
        mCapturedEventConverter(*getContext(), deviceContext, mMotionAccumulator, getDeviceId()) {
        mCapturedEventConverter(*getContext(), deviceContext, mMotionAccumulator, getDeviceId()),
        mMetricsId(metricsIdFromInputDeviceIdentifier(deviceContext.getDeviceIdentifier())) {
    RawAbsoluteAxisInfo slotAxisInfo;
    RawAbsoluteAxisInfo slotAxisInfo;
    deviceContext.getAbsoluteAxisInfo(ABS_MT_SLOT, &slotAxisInfo);
    deviceContext.getAbsoluteAxisInfo(ABS_MT_SLOT, &slotAxisInfo);
    if (!slotAxisInfo.valid || slotAxisInfo.maxValue <= 0) {
    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);
    std::optional<SelfContainedHardwareState> state = mStateConverter.processRawEvent(rawEvent);
    if (state) {
    if (state) {
        updatePalmDetectionMetrics();
        return sendHardwareState(rawEvent->when, rawEvent->readTime, *state);
        return sendHardwareState(rawEvent->when, rawEvent->readTime, *state);
    } else {
    } else {
        return {};
        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,
std::list<NotifyArgs> TouchpadInputMapper::sendHardwareState(nsecs_t when, nsecs_t readTime,
                                                             SelfContainedHardwareState schs) {
                                                             SelfContainedHardwareState schs) {
    ALOGD_IF(DEBUG_TOUCHPAD_GESTURES, "New hardware state: %s", schs.state.String().c_str());
    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> TouchpadInputMapper::processGestures(nsecs_t when, nsecs_t readTime) {
    std::list<NotifyArgs> out = {};
    std::list<NotifyArgs> out = {};
    MetricsAccumulator& metricsAccumulator = MetricsAccumulator::getInstance();
    for (Gesture& gesture : mGesturesToProcess) {
    for (Gesture& gesture : mGesturesToProcess) {
        out += mGestureConverter.handleGesture(when, readTime, gesture);
        out += mGestureConverter.handleGesture(when, readTime, gesture);
        metricsAccumulator.processGesture(mMetricsId, gesture);
    }
    }
    mGesturesToProcess.clear();
    mGesturesToProcess.clear();
    return out;
    return out;
+16 −0
Original line number Original line Diff line number Diff line
@@ -18,6 +18,7 @@


#include <list>
#include <list>
#include <memory>
#include <memory>
#include <set>
#include <vector>
#include <vector>


#include <PointerControllerInterface.h>
#include <PointerControllerInterface.h>
@@ -58,10 +59,16 @@ public:


    void consumeGesture(const Gesture* gesture);
    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:
private:
    void resetGestureInterpreter(nsecs_t when);
    void resetGestureInterpreter(nsecs_t when);
    explicit TouchpadInputMapper(InputDeviceContext& deviceContext,
    explicit TouchpadInputMapper(InputDeviceContext& deviceContext,
                                 const InputReaderConfiguration& readerConfig);
                                 const InputReaderConfiguration& readerConfig);
    void updatePalmDetectionMetrics();
    [[nodiscard]] std::list<NotifyArgs> sendHardwareState(nsecs_t when, nsecs_t readTime,
    [[nodiscard]] std::list<NotifyArgs> sendHardwareState(nsecs_t when, nsecs_t readTime,
                                                          SelfContainedHardwareState schs);
                                                          SelfContainedHardwareState schs);
    [[nodiscard]] std::list<NotifyArgs> processGestures(nsecs_t when, nsecs_t readTime);
    [[nodiscard]] std::list<NotifyArgs> processGestures(nsecs_t when, nsecs_t readTime);
@@ -86,6 +93,15 @@ private:
    bool mProcessing = false;
    bool mProcessing = false;
    bool mResettingInterpreter = false;
    bool mResettingInterpreter = false;
    std::vector<Gesture> mGesturesToProcess;
    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
} // namespace android