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

Commit 4c6ec526 authored by Treehugger Robot's avatar Treehugger Robot Committed by Gerrit Code Review
Browse files

Merge "Fully delete duplicate entries inside LatencyTracker"

parents 6c90d86a f9cb2a7f
Loading
Loading
Loading
Loading
+7 −0
Original line number Diff line number Diff line
@@ -3899,6 +3899,13 @@ void InputDispatcher::notifyMotion(const NotifyMotionArgs* args) {
                                              args->downTime, args->pointerCount,
                                              args->pointerProperties, args->pointerCoords, 0, 0);

        if (args->id != android::os::IInputConstants::INVALID_INPUT_EVENT_ID &&
            IdGenerator::getSource(args->id) == IdGenerator::Source::INPUT_READER &&
            !mInputFilterEnabled) {
            const bool isDown = args->action == AMOTION_EVENT_ACTION_DOWN;
            mLatencyTracker.trackListener(args->id, isDown, args->eventTime, args->readTime);
        }

        needWake = enqueueInboundEventLocked(std::move(newEntry));
        mLock.unlock();
    } // release lock
+10 −19
Original line number Diff line number Diff line
@@ -50,13 +50,12 @@ static bool isMatureEvent(nsecs_t eventTime, nsecs_t now) {
 * key-value pair. Equivalent to the imaginary std api std::multimap::erase(key, value).
 */
template <typename K, typename V>
static void eraseByKeyAndValue(std::multimap<K, V>& map, K key, V value) {
    auto iterpair = map.equal_range(key);

    for (auto it = iterpair.first; it != iterpair.second; ++it) {
static void eraseByValue(std::multimap<K, V>& map, const V& value) {
    for (auto it = map.begin(); it != map.end();) {
        if (it->second == value) {
            map.erase(it);
            break;
            it = map.erase(it);
        } else {
            it++;
        }
    }
}
@@ -76,9 +75,7 @@ void LatencyTracker::trackListener(int32_t inputEventId, bool isDown, nsecs_t ev
        // confuse us by reporting the rest of the timeline for one of them. This should happen
        // rarely, so we won't lose much data
        mTimelines.erase(it);
        // In case we have another input event with a different id and at the same eventTime,
        // only erase this specific inputEventId.
        eraseByKeyAndValue(mEventTimes, eventTime, inputEventId);
        eraseByValue(mEventTimes, inputEventId);
        return;
    }
    mTimelines.emplace(inputEventId, InputEventTimeline(isDown, eventTime, readTime));
@@ -90,7 +87,8 @@ void LatencyTracker::trackFinishedEvent(int32_t inputEventId, const sp<IBinder>&
                                        nsecs_t finishTime) {
    const auto it = mTimelines.find(inputEventId);
    if (it == mTimelines.end()) {
        // It's possible that an app sends a bad (or late)'Finish' signal, since it's free to do
        // This could happen if we erased this event when duplicate events were detected. It's
        // also possible that an app sent a bad (or late) 'Finish' signal, since it's free to do
        // anything in its process. Just drop the report and move on.
        return;
    }
@@ -120,7 +118,8 @@ void LatencyTracker::trackGraphicsLatency(
        std::array<nsecs_t, GraphicsTimeline::SIZE> graphicsTimeline) {
    const auto it = mTimelines.find(inputEventId);
    if (it == mTimelines.end()) {
        // It's possible that an app sends a bad (or late) 'Timeline' signal, since it's free to do
        // This could happen if we erased this event when duplicate events were detected. It's
        // also possible that an app sent a bad (or late) 'Timeline' signal, since it's free to do
        // anything in its process. Just drop the report and move on.
        return;
    }
@@ -166,14 +165,6 @@ void LatencyTracker::reportAndPruneMatureRecords(nsecs_t newEventTime) {
    }
}

void LatencyTracker::reportNow() {
    for (const auto& [inputEventId, timeline] : mTimelines) {
        mTimelineProcessor->processTimeline(timeline);
    }
    mTimelines.clear();
    mEventTimes.clear();
}

std::string LatencyTracker::dump(const char* prefix) {
    return StringPrintf("%sLatencyTracker:\n", prefix) +
            StringPrintf("%s  mTimelines.size() = %zu\n", prefix, mTimelines.size()) +
+6 −8
Original line number Diff line number Diff line
@@ -43,6 +43,12 @@ public:
    LatencyTracker(InputEventTimelineProcessor* processor);
    /**
     * Start keeping track of an event identified by inputEventId. This must be called first.
     * If duplicate events are encountered (events that have the same eventId), none of them will be
     * tracked. This is because there is not enough information to correctly track them. The api's
     * 'trackFinishedEvent' and 'trackGraphicsLatency' only contain the inputEventId, and not the
     * eventTime. Even if eventTime was provided, there would still be a possibility of having
     * duplicate events that happen to have the same eventTime and inputEventId. Therefore, we
     * must drop all duplicate data.
     */
    void trackListener(int32_t inputEventId, bool isDown, nsecs_t eventTime, nsecs_t readTime);
    void trackFinishedEvent(int32_t inputEventId, const sp<IBinder>& connectionToken,
@@ -50,14 +56,6 @@ public:
    void trackGraphicsLatency(int32_t inputEventId, const sp<IBinder>& connectionToken,
                              std::array<nsecs_t, GraphicsTimeline::SIZE> timeline);

    /**
     * Report all collected events immediately, even if some of them are currently incomplete
     * and may receive 'trackFinishedEvent' or 'trackGraphicsLatency' calls in the future.
     * This is useful for tests. Otherwise, tests would have to inject additional "future" events,
     * which is not convenient.
     */
    void reportNow();

    std::string dump(const char* prefix);

private:
+45 −2
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@

#include "../dispatcher/LatencyTracker.h"

#include <android-base/properties.h>
#include <binder/Binder.h>
#include <gtest/gtest.h>
#include <inttypes.h>
@@ -23,11 +24,16 @@

#define TAG "LatencyTracker_test"

using android::base::HwTimeoutMultiplier;
using android::inputdispatcher::InputEventTimeline;
using android::inputdispatcher::LatencyTracker;

namespace android::inputdispatcher {

const std::chrono::duration ANR_TIMEOUT = std::chrono::milliseconds(
        android::os::IInputConstants::UNMULTIPLIED_DEFAULT_DISPATCHING_TIMEOUT_MILLIS *
        HwTimeoutMultiplier());

InputEventTimeline getTestTimeline() {
    InputEventTimeline t(
            /*isDown*/ true,
@@ -57,6 +63,8 @@ protected:
    }
    void TearDown() override {}

    void triggerEventReporting(nsecs_t lastEventTime);

    void assertReceivedTimeline(const InputEventTimeline& timeline);
    /**
     * Timelines can be received in any order (order is not guaranteed). So if we are expecting more
@@ -72,8 +80,17 @@ private:
    std::deque<InputEventTimeline> mReceivedTimelines;
};

/**
 * Send an event that would trigger the reporting of all of the events that are at least as old as
 * the provided 'lastEventTime'.
 */
void LatencyTrackerTest::triggerEventReporting(nsecs_t lastEventTime) {
    const nsecs_t triggerEventTime =
            lastEventTime + std::chrono::nanoseconds(ANR_TIMEOUT).count() + 1;
    mTracker->trackListener(1 /*inputEventId*/, true /*isDown*/, triggerEventTime, 3 /*readTime*/);
}

void LatencyTrackerTest::assertReceivedTimeline(const InputEventTimeline& timeline) {
    mTracker->reportNow();
    ASSERT_FALSE(mReceivedTimelines.empty());
    const InputEventTimeline& t = mReceivedTimelines.front();
    ASSERT_EQ(timeline, t);
@@ -88,7 +105,6 @@ void LatencyTrackerTest::assertReceivedTimeline(const InputEventTimeline& timeli
 * equal element in B, and for every element in B there is an equal element in A.
 */
void LatencyTrackerTest::assertReceivedTimelines(const std::vector<InputEventTimeline>& timelines) {
    mTracker->reportNow();
    ASSERT_EQ(timelines.size(), mReceivedTimelines.size());
    for (const InputEventTimeline& expectedTimeline : timelines) {
        bool found = false;
@@ -121,6 +137,7 @@ void LatencyTrackerTest::assertReceivedTimelines(const std::vector<InputEventTim
 */
TEST_F(LatencyTrackerTest, TrackListener_DoesNotTriggerReporting) {
    mTracker->trackListener(1 /*inputEventId*/, false /*isDown*/, 2 /*eventTime*/, 3 /*readTime*/);
    triggerEventReporting(2 /*eventTime*/);
    assertReceivedTimeline(InputEventTimeline{false, 2, 3});
}

@@ -130,6 +147,7 @@ TEST_F(LatencyTrackerTest, TrackListener_DoesNotTriggerReporting) {
TEST_F(LatencyTrackerTest, TrackFinishedEvent_DoesNotTriggerReporting) {
    mTracker->trackFinishedEvent(1 /*inputEventId*/, connection1, 2 /*deliveryTime*/,
                                 3 /*consumeTime*/, 4 /*finishTime*/);
    triggerEventReporting(4 /*eventTime*/);
    assertReceivedTimelines({});
}

@@ -141,6 +159,7 @@ TEST_F(LatencyTrackerTest, TrackGraphicsLatency_DoesNotTriggerReporting) {
    graphicsTimeline[GraphicsTimeline::GPU_COMPLETED_TIME] = 2;
    graphicsTimeline[GraphicsTimeline::PRESENT_TIME] = 3;
    mTracker->trackGraphicsLatency(1 /*inputEventId*/, connection2, graphicsTimeline);
    triggerEventReporting(3 /*eventTime*/);
    assertReceivedTimelines({});
}

@@ -155,9 +174,30 @@ TEST_F(LatencyTrackerTest, TrackAllParameters_ReportsFullTimeline) {
                                 expectedCT.consumeTime, expectedCT.finishTime);
    mTracker->trackGraphicsLatency(inputEventId, connectionToken, expectedCT.graphicsTimeline);

    triggerEventReporting(expected.eventTime);
    assertReceivedTimeline(expected);
}

/**
 * Send 2 events with the same inputEventId, but different eventTime's. Ensure that no crash occurs,
 * and that the tracker drops such events completely.
 */
TEST_F(LatencyTrackerTest, WhenDuplicateEventsAreReported_DoesNotCrash) {
    constexpr nsecs_t inputEventId = 1;
    constexpr nsecs_t readTime = 3; // does not matter for this test
    constexpr bool isDown = true;   // does not matter for this test

    // In the following 2 calls to trackListener, the inputEventId's are the same, but event times
    // are different.
    mTracker->trackListener(inputEventId, isDown, 1 /*eventTime*/, readTime);
    mTracker->trackListener(inputEventId, isDown, 2 /*eventTime*/, readTime);

    triggerEventReporting(2 /*eventTime*/);
    // Since we sent duplicate input events, the tracker should just delete all of them, because it
    // does not have enough information to properly track them.
    assertReceivedTimelines({});
}

TEST_F(LatencyTrackerTest, MultipleEvents_AreReportedConsistently) {
    constexpr int32_t inputEventId1 = 1;
    InputEventTimeline timeline1(
@@ -204,6 +244,7 @@ TEST_F(LatencyTrackerTest, MultipleEvents_AreReportedConsistently) {
    mTracker->trackGraphicsLatency(inputEventId2, connection2,
                                   connectionTimeline2.graphicsTimeline);
    // Now both events should be completed
    triggerEventReporting(timeline2.eventTime);
    assertReceivedTimelines({timeline1, timeline2});
}

@@ -228,6 +269,7 @@ TEST_F(LatencyTrackerTest, IncompleteEvents_AreHandledConsistently) {
    mTracker->trackGraphicsLatency(1 /*inputEventId*/, token, expectedCT.graphicsTimeline);

    expectedTimelines[0].connectionTimelines.emplace(token, std::move(expectedCT));
    triggerEventReporting(timeline.eventTime);
    assertReceivedTimelines(expectedTimelines);
}

@@ -246,6 +288,7 @@ TEST_F(LatencyTrackerTest, EventsAreTracked_WhenTrackListenerIsCalledFirst) {
    mTracker->trackGraphicsLatency(inputEventId, connection1, expectedCT.graphicsTimeline);

    mTracker->trackListener(inputEventId, expected.isDown, expected.eventTime, expected.readTime);
    triggerEventReporting(expected.eventTime);
    assertReceivedTimeline(
            InputEventTimeline{expected.isDown, expected.eventTime, expected.readTime});
}
+45 −0
Original line number Diff line number Diff line
// Copyright (C) 2021 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package {
    // See: http://go/android-license-faq
    // A large-scale-change added 'default_applicable_licenses' to import
    // all of the 'license_kinds' from "frameworks_native_license"
    // to get the below license kinds:
    //   SPDX-license-identifier-Apache-2.0
    default_applicable_licenses: ["frameworks_native_license"],
}


cc_fuzz {
    name: "inputflinger_latencytracker_fuzzer",
    defaults: [
        "inputflinger_defaults",
    ],
    include_dirs: [
        "frameworks/native/services/inputflinger",
    ],
    shared_libs: [
        "libbase",
        "libbinder",
        "liblog",
        "libui",
        "libutils",
        "libinput",
        "libinputflinger",
    ],
    srcs: [
        "LatencyTrackerFuzzer.cpp",
    ],
}
Loading