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

Commit 74382015 authored by Prabir Pradhan's avatar Prabir Pradhan Committed by Android (Google) Code Review
Browse files

Merge changes I2ab660ed,I308c12e2,I8c50a597,I14f77d61 into main

* changes:
  InputDispatcher_test: Verify all traced events match exactly
  InputDispatcher_test: Consume all moves to prevent events from batching
  InputDispatcher: Create new EventEntries for events with zero-ed coords
  InputDispatcher: Improve pointer transform mapping in InputTarget
parents 77add0b0 65a071a7
Loading
Loading
Loading
Loading
+9 −1
Original line number Diff line number Diff line
@@ -181,6 +181,7 @@ static constexpr size_t MAX_POINTERS = 16;
 */
struct AInputEvent {
    virtual ~AInputEvent() {}
    bool operator==(const AInputEvent&) const = default;
};

/*
@@ -545,6 +546,8 @@ public:

    static int32_t nextId();

    bool operator==(const InputEvent&) const = default;

protected:
    void initialize(int32_t id, DeviceId deviceId, uint32_t source, int32_t displayId,
                    std::array<uint8_t, 32> hmac);
@@ -598,6 +601,8 @@ public:

    static const char* actionToString(int32_t action);

    bool operator==(const KeyEvent&) const = default;

protected:
    int32_t mAction;
    int32_t mFlags;
@@ -917,6 +922,9 @@ public:
    // The rounding precision for transformed motion events.
    static constexpr float ROUNDING_PRECISION = 0.001f;

    bool operator==(const MotionEvent&) const;
    inline bool operator!=(const MotionEvent& o) const { return !(*this == o); };

protected:
    int32_t mAction;
    int32_t mActionButton;
+27 −0
Original line number Diff line number Diff line
@@ -1007,6 +1007,33 @@ PointerCoords MotionEvent::calculateTransformedCoords(uint32_t source,
    return out;
}

bool MotionEvent::operator==(const android::MotionEvent& o) const {
    // We use NaN values to represent invalid cursor positions. Since NaN values are not equal
    // to themselves according to IEEE 754, we cannot use the default equality operator to compare
    // MotionEvents. Therefore we define a custom equality operator with special handling for NaNs.
    // clang-format off
    return InputEvent::operator==(static_cast<const InputEvent&>(o)) &&
            mAction == o.mAction &&
            mActionButton == o.mActionButton &&
            mFlags == o.mFlags &&
            mEdgeFlags == o.mEdgeFlags &&
            mMetaState == o.mMetaState &&
            mButtonState == o.mButtonState &&
            mClassification == o.mClassification &&
            mTransform == o.mTransform &&
            mXPrecision == o.mXPrecision &&
            mYPrecision == o.mYPrecision &&
            ((std::isnan(mRawXCursorPosition) && std::isnan(o.mRawXCursorPosition)) ||
                mRawXCursorPosition == o.mRawXCursorPosition) &&
            ((std::isnan(mRawYCursorPosition) && std::isnan(o.mRawYCursorPosition)) ||
                mRawYCursorPosition == o.mRawYCursorPosition) &&
            mRawTransform == o.mRawTransform && mDownTime == o.mDownTime &&
            mPointerProperties == o.mPointerProperties &&
            mSampleEventTimes == o.mSampleEventTimes &&
            mSamplePointerCoords == o.mSamplePointerCoords;
    // clang-format on
}

std::ostream& operator<<(std::ostream& out, const MotionEvent& event) {
    out << "MotionEvent { action=" << MotionEvent::actionToString(event.getAction());
    if (event.getActionButton() != 0) {
+49 −56
Original line number Diff line number Diff line
@@ -365,17 +365,20 @@ size_t firstMarkedBit(T set) {
    return i;
}

std::unique_ptr<DispatchEntry> createDispatchEntry(const InputTarget& inputTarget,
std::unique_ptr<DispatchEntry> createDispatchEntry(const IdGenerator& idGenerator,
                                                   const InputTarget& inputTarget,
                                                   std::shared_ptr<const EventEntry> eventEntry,
                                                   ftl::Flags<InputTarget::Flags> inputTargetFlags,
                                                   int64_t vsyncId) {
    const bool zeroCoords = inputTargetFlags.test(InputTarget::Flags::ZERO_COORDS);
    const sp<WindowInfoHandle> win = inputTarget.windowHandle;
    const std::optional<int32_t> windowId =
            win ? std::make_optional(win->getInfo()->id) : std::nullopt;
    // Assume the only targets that are not associated with a window are global monitors, and use
    // the system UID for global monitors for tracing purposes.
    const gui::Uid uid = win ? win->getInfo()->ownerUid : gui::Uid(AID_SYSTEM);
    if (inputTarget.useDefaultPointerTransform()) {

    if (inputTarget.useDefaultPointerTransform() && !zeroCoords) {
        const ui::Transform& transform = inputTarget.getDefaultPointerTransform();
        return std::make_unique<DispatchEntry>(eventEntry, inputTargetFlags, transform,
                                               inputTarget.displayTransform,
@@ -386,33 +389,39 @@ std::unique_ptr<DispatchEntry> createDispatchEntry(const InputTarget& inputTarge
    ALOG_ASSERT(eventEntry->type == EventEntry::Type::MOTION);
    const MotionEntry& motionEntry = static_cast<const MotionEntry&>(*eventEntry);

    std::vector<PointerCoords> pointerCoords;
    pointerCoords.resize(motionEntry.getPointerCount());
    std::vector<PointerCoords> pointerCoords{motionEntry.getPointerCount()};

    // Use the first pointer information to normalize all other pointers. This could be any pointer
    // as long as all other pointers are normalized to the same value and the final DispatchEntry
    // uses the transform for the normalized pointer.
    const ui::Transform& firstPointerTransform =
            inputTarget.pointerTransforms[firstMarkedBit(inputTarget.pointerIds)];
    ui::Transform inverseFirstTransform = firstPointerTransform.inverse();
    const ui::Transform* transform = &kIdentityTransform;
    const ui::Transform* displayTransform = &kIdentityTransform;
    if (zeroCoords) {
        std::for_each(pointerCoords.begin(), pointerCoords.end(), [](auto& pc) { pc.clear(); });
    } else {
        // Use the first pointer information to normalize all other pointers. This could be any
        // pointer as long as all other pointers are normalized to the same value and the final
        // DispatchEntry uses the transform for the normalized pointer.
        transform =
                &inputTarget.getTransformForPointer(firstMarkedBit(inputTarget.getPointerIds()));
        const ui::Transform inverseTransform = transform->inverse();
        displayTransform = &inputTarget.displayTransform;

        // Iterate through all pointers in the event to normalize against the first.
    for (uint32_t pointerIndex = 0; pointerIndex < motionEntry.getPointerCount(); pointerIndex++) {
        const PointerProperties& pointerProperties = motionEntry.pointerProperties[pointerIndex];
        uint32_t pointerId = uint32_t(pointerProperties.id);
        const ui::Transform& currTransform = inputTarget.pointerTransforms[pointerId];
        for (size_t i = 0; i < motionEntry.getPointerCount(); i++) {
            PointerCoords& newCoords = pointerCoords[i];
            const auto pointerId = motionEntry.pointerProperties[i].id;
            const ui::Transform& currTransform = inputTarget.getTransformForPointer(pointerId);

        pointerCoords[pointerIndex].copyFrom(motionEntry.pointerCoords[pointerIndex]);
            newCoords.copyFrom(motionEntry.pointerCoords[i]);
            // First, apply the current pointer's transform to update the coordinates into
            // window space.
        pointerCoords[pointerIndex].transform(currTransform);
            newCoords.transform(currTransform);
            // Next, apply the inverse transform of the normalized coordinates so the
            // current coordinates are transformed into the normalized coordinate space.
        pointerCoords[pointerIndex].transform(inverseFirstTransform);
            newCoords.transform(inverseTransform);
        }
    }

    std::unique_ptr<MotionEntry> combinedMotionEntry =
            std::make_unique<MotionEntry>(motionEntry.id, motionEntry.injectionState,
            std::make_unique<MotionEntry>(idGenerator.nextId(), motionEntry.injectionState,
                                          motionEntry.eventTime, motionEntry.deviceId,
                                          motionEntry.source, motionEntry.displayId,
                                          motionEntry.policyFlags, motionEntry.action,
@@ -426,7 +435,7 @@ std::unique_ptr<DispatchEntry> createDispatchEntry(const InputTarget& inputTarge

    std::unique_ptr<DispatchEntry> dispatchEntry =
            std::make_unique<DispatchEntry>(std::move(combinedMotionEntry), inputTargetFlags,
                                            firstPointerTransform, inputTarget.displayTransform,
                                            *transform, *displayTransform,
                                            inputTarget.globalScaleFactor, uid, vsyncId, windowId);
    return dispatchEntry;
}
@@ -1630,14 +1639,12 @@ void InputDispatcher::dispatchFocusLocked(nsecs_t currentTime,
    if (connection == nullptr) {
        return; // Connection has gone away
    }
    InputTarget target;
    target.connection = connection;
    entry->dispatchInProgress = true;
    std::string message = std::string("Focus ") + (entry->hasFocus ? "entering " : "leaving ") +
            connection->getInputChannelName();
    std::string reason = std::string("reason=").append(entry->reason);
    android_log_event_list(LOGTAG_INPUT_FOCUS) << message << reason << LOG_ID_EVENTS;
    dispatchEventLocked(currentTime, entry, {target});
    dispatchEventLocked(currentTime, entry, {{connection}});
}

void InputDispatcher::dispatchPointerCaptureChangedLocked(
@@ -1703,10 +1710,8 @@ void InputDispatcher::dispatchPointerCaptureChangedLocked(
        }
        return;
    }
    InputTarget target;
    target.connection = connection;
    entry->dispatchInProgress = true;
    dispatchEventLocked(currentTime, entry, {target});
    dispatchEventLocked(currentTime, entry, {{connection}});

    dropReason = DropReason::NOT_DROPPED;
}
@@ -1739,9 +1744,7 @@ std::vector<InputTarget> InputDispatcher::getInputTargetsFromWindowHandlesLocked
        if (connection == nullptr) {
            continue; // Connection has gone away
        }
        InputTarget target;
        target.connection = connection;
        inputTargets.push_back(target);
        inputTargets.emplace_back(connection);
    }
    return inputTargets;
}
@@ -2022,10 +2025,8 @@ void InputDispatcher::dispatchDragLocked(nsecs_t currentTime,
    if (connection == nullptr) {
        return; // Connection has gone away
    }
    InputTarget target;
    target.connection = connection;
    entry->dispatchInProgress = true;
    dispatchEventLocked(currentTime, entry, {target});
    dispatchEventLocked(currentTime, entry, {{connection}});
}

void InputDispatcher::logOutboundMotionDetails(const char* prefix, const MotionEntry& entry) {
@@ -2868,8 +2869,7 @@ std::optional<InputTarget> InputDispatcher::createInputTargetLocked(
        ALOGW("Not creating InputTarget for %s, no input channel", windowHandle->getName().c_str());
        return {};
    }
    InputTarget inputTarget;
    inputTarget.connection = connection;
    InputTarget inputTarget{connection};
    inputTarget.windowHandle = windowHandle;
    inputTarget.dispatchMode = dispatchMode;
    inputTarget.flags = targetFlags;
@@ -2982,8 +2982,7 @@ void InputDispatcher::addGlobalMonitoringTargetsLocked(std::vector<InputTarget>&
    if (monitorsIt == mGlobalMonitorsByDisplay.end()) return;

    for (const Monitor& monitor : selectResponsiveMonitorsLocked(monitorsIt->second)) {
        InputTarget target;
        target.connection = monitor.connection;
        InputTarget target{monitor.connection};
        // target.firstDownTimeInTarget is not set for global monitors. It is only required in split
        // touch and global monitoring works as intended even without setting firstDownTimeInTarget
        if (const auto& it = mDisplayInfos.find(displayId); it != mDisplayInfos.end()) {
@@ -3275,7 +3274,7 @@ void InputDispatcher::prepareDispatchCycleLocked(nsecs_t currentTime,
        ALOGD("channel '%s' ~ prepareDispatchCycle - flags=%s, "
              "globalScaleFactor=%f, pointerIds=%s %s",
              connection->getInputChannelName().c_str(), inputTarget.flags.string().c_str(),
              inputTarget.globalScaleFactor, bitsetToString(inputTarget.pointerIds).c_str(),
              inputTarget.globalScaleFactor, bitsetToString(inputTarget.getPointerIds()).c_str(),
              inputTarget.getPointerInfoString().c_str());
    }

@@ -3297,7 +3296,7 @@ void InputDispatcher::prepareDispatchCycleLocked(nsecs_t currentTime,
                            ftl::enum_string(eventEntry->type).c_str());

        const MotionEntry& originalMotionEntry = static_cast<const MotionEntry&>(*eventEntry);
        if (inputTarget.pointerIds.count() != originalMotionEntry.getPointerCount()) {
        if (inputTarget.getPointerIds().count() != originalMotionEntry.getPointerCount()) {
            if (!inputTarget.firstDownTimeInTarget.has_value()) {
                logDispatchStateLocked();
                LOG(FATAL) << "Splitting motion events requires a down time to be set for the "
@@ -3306,7 +3305,7 @@ void InputDispatcher::prepareDispatchCycleLocked(nsecs_t currentTime,
                           << originalMotionEntry.getDescription();
            }
            std::unique_ptr<MotionEntry> splitMotionEntry =
                    splitMotionEvent(originalMotionEntry, inputTarget.pointerIds,
                    splitMotionEvent(originalMotionEntry, inputTarget.getPointerIds(),
                                     inputTarget.firstDownTimeInTarget.value());
            if (!splitMotionEntry) {
                return; // split event was dropped
@@ -3364,7 +3363,8 @@ void InputDispatcher::enqueueDispatchEntryLocked(const std::shared_ptr<Connectio
    // This is a new event.
    // Enqueue a new dispatch entry onto the outbound queue for this connection.
    std::unique_ptr<DispatchEntry> dispatchEntry =
            createDispatchEntry(inputTarget, eventEntry, inputTarget.flags, mWindowInfosVsyncId);
            createDispatchEntry(mIdGenerator, inputTarget, eventEntry, inputTarget.flags,
                                mWindowInfosVsyncId);

    // Use the eventEntry from dispatchEntry since the entry may have changed and can now be a
    // different EventEntry than what was passed in.
@@ -3485,7 +3485,7 @@ void InputDispatcher::enqueueDispatchEntryLocked(const std::shared_ptr<Connectio
                          << connection->getInputChannelName() << " with event "
                          << cancelEvent->getDescription();
                std::unique_ptr<DispatchEntry> cancelDispatchEntry =
                        createDispatchEntry(inputTarget, std::move(cancelEvent),
                        createDispatchEntry(mIdGenerator, inputTarget, std::move(cancelEvent),
                                            ftl::Flags<InputTarget::Flags>(), mWindowInfosVsyncId);

                // Send these cancel events to the queue before sending the event from the new
@@ -3664,12 +3664,6 @@ status_t InputDispatcher::publishMotionEvent(Connection& connection,
            }
            usingCoords = scaledCoords;
        }
    } else if (dispatchEntry.targetFlags.test(InputTarget::Flags::ZERO_COORDS)) {
        // We don't want the dispatch target to know the coordinates
        for (uint32_t i = 0; i < motionEntry.getPointerCount(); i++) {
            scaledCoords[i].clear();
        }
        usingCoords = scaledCoords;
    }

    std::array<uint8_t, 32> hmac = getSignature(motionEntry, dispatchEntry);
@@ -4109,7 +4103,7 @@ void InputDispatcher::synthesizeCancelationEventsForConnectionLocked(

    const bool wasEmpty = connection->outboundQueue.empty();
    // The target to use if we don't find a window associated with the channel.
    const InputTarget fallbackTarget{.connection = connection};
    const InputTarget fallbackTarget{connection};
    const auto& token = connection->getToken();

    for (size_t i = 0; i < cancelationEvents.size(); i++) {
@@ -4227,8 +4221,7 @@ void InputDispatcher::synthesizePointerDownEventsForConnectionLocked(
                                                 targetFlags, pointerIds, motionEntry.downTime,
                                                 targets);
                } else {
                    targets.emplace_back(
                            InputTarget{.connection = connection, .flags = targetFlags});
                    targets.emplace_back(connection, targetFlags);
                    const auto it = mDisplayInfos.find(motionEntry.displayId);
                    if (it != mDisplayInfos.end()) {
                        targets.back().displayTransform = it->second.transform;
+45 −17
Original line number Diff line number Diff line
@@ -26,6 +26,15 @@ using android::base::StringPrintf;

namespace android::inputdispatcher {

namespace {

const static ui::Transform kIdentityTransform{};

}

InputTarget::InputTarget(const std::shared_ptr<Connection>& connection, ftl::Flags<Flags> flags)
      : connection(connection), flags(flags) {}

void InputTarget::addPointers(std::bitset<MAX_POINTER_ID + 1> newPointerIds,
                              const ui::Transform& transform) {
    // The pointerIds can be empty, but still a valid InputTarget. This can happen when there is no
@@ -36,31 +45,46 @@ void InputTarget::addPointers(std::bitset<MAX_POINTER_ID + 1> newPointerIds,
    }

    // Ensure that the new set of pointers doesn't overlap with the current set of pointers.
    if ((pointerIds & newPointerIds).any()) {
    if ((getPointerIds() & newPointerIds).any()) {
        LOG(FATAL) << __func__ << " - overlap with incoming pointers "
                   << bitsetToString(newPointerIds) << " in " << *this;
    }

    pointerIds |= newPointerIds;
    for (size_t i = 0; i < newPointerIds.size(); i++) {
        if (!newPointerIds.test(i)) {
            continue;
    for (auto& [existingTransform, existingPointers] : mPointerTransforms) {
        if (transform == existingTransform) {
            existingPointers |= newPointerIds;
            return;
        }
        pointerTransforms[i] = transform;
    }
    mPointerTransforms.emplace_back(transform, newPointerIds);
}

void InputTarget::setDefaultPointerTransform(const ui::Transform& transform) {
    pointerIds.reset();
    pointerTransforms[0] = transform;
    mPointerTransforms = {{transform, {}}};
}

bool InputTarget::useDefaultPointerTransform() const {
    return pointerIds.none();
    return mPointerTransforms.size() <= 1;
}

const ui::Transform& InputTarget::getDefaultPointerTransform() const {
    return pointerTransforms[0];
    if (!useDefaultPointerTransform()) {
        LOG(FATAL) << __func__ << ": Not using default pointer transform";
    }
    return mPointerTransforms.size() == 1 ? mPointerTransforms[0].first : kIdentityTransform;
}

const ui::Transform& InputTarget::getTransformForPointer(int32_t pointerId) const {
    for (const auto& [transform, ids] : mPointerTransforms) {
        if (ids.test(pointerId)) {
            return transform;
        }
    }

    LOG(FATAL) << __func__
               << ": Cannot get transform: The following Pointer ID does not exist in target: "
               << pointerId;
    return kIdentityTransform;
}

std::string InputTarget::getPointerInfoString() const {
@@ -71,15 +95,19 @@ std::string InputTarget::getPointerInfoString() const {
        return out;
    }

    for (uint32_t i = 0; i < pointerIds.size(); i++) {
        if (!pointerIds.test(i)) {
            continue;
    for (const auto& [transform, ids] : mPointerTransforms) {
        const std::string name = "pointerIds " + bitsetToString(ids) + ":";
        transform.dump(out, name.c_str(), "        ");
    }
    return out;
}

        const std::string name = "pointerId " + std::to_string(i) + ":";
        pointerTransforms[i].dump(out, name.c_str(), "        ");
std::bitset<MAX_POINTER_ID + 1> InputTarget::getPointerIds() const {
    PointerIds allIds;
    for (const auto& [_, ids] : mPointerTransforms) {
        allIds |= ids;
    }
    return out;
    return allIds;
}

std::ostream& operator<<(std::ostream& out, const InputTarget& target) {
+20 −7
Original line number Diff line number Diff line
@@ -33,7 +33,8 @@ namespace android::inputdispatcher {
 * be added to input event coordinates to compensate for the absolute position of the
 * window area.
 */
struct InputTarget {
class InputTarget {
public:
    using Flags = InputTargetFlags;

    enum class DispatchMode {
@@ -80,20 +81,17 @@ struct InputTarget {
    // Current display transform. Used for compatibility for raw coordinates.
    ui::Transform displayTransform;

    // The subset of pointer ids to include in motion events dispatched to this input target
    // if FLAG_SPLIT is set.
    std::bitset<MAX_POINTER_ID + 1> pointerIds;
    // Event time for the first motion event (ACTION_DOWN) dispatched to this input target if
    // FLAG_SPLIT is set.
    std::optional<nsecs_t> firstDownTimeInTarget;
    // The data is stored by the pointerId. Use the bit position of pointerIds to look up
    // Transform per pointerId.
    ui::Transform pointerTransforms[MAX_POINTERS];

    // The window that this input target is being dispatched to. It is possible for this to be
    // null for cases like global monitors.
    sp<gui::WindowInfoHandle> windowHandle;

    InputTarget() = default;
    InputTarget(const std::shared_ptr<Connection>&, ftl::Flags<Flags> = {});

    void addPointers(std::bitset<MAX_POINTER_ID + 1> pointerIds, const ui::Transform& transform);
    void setDefaultPointerTransform(const ui::Transform& transform);

@@ -111,7 +109,22 @@ struct InputTarget {
     */
    const ui::Transform& getDefaultPointerTransform() const;

    const ui::Transform& getTransformForPointer(int32_t pointerId) const;

    std::bitset<MAX_POINTER_ID + 1> getPointerIds() const;

    std::string getPointerInfoString() const;

private:
    template <typename K, typename V>
    using ArrayMap = std::vector<std::pair<K, V>>;
    using PointerIds = std::bitset<MAX_POINTER_ID + 1>;
    // The mapping of pointer IDs to the transform that should be used for that collection of IDs.
    // Each of the pointer IDs are mutually disjoint, and their union makes up pointer IDs to
    // include in the motion events dispatched to this target. We use an ArrayMap to store this to
    // avoid having to define hash or comparison functions for ui::Transform, which would be needed
    // to use std::unordered_map or std::map respectively.
    ArrayMap<ui::Transform, PointerIds> mPointerTransforms;
};

std::ostream& operator<<(std::ostream& out, const InputTarget& target);
Loading