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

Commit 27f04355 authored by Treehugger Robot's avatar Treehugger Robot Committed by Automerger Merge Worker
Browse files

Merge "Fully delete duplicate entries inside LatencyTracker" am: 4c6ec526

Original change: https://android-review.googlesource.com/c/platform/frameworks/native/+/1885231

Change-Id: I75c58e572fbcde97664a652c3dc7d6b77a145b15
parents 90fd96ff 4c6ec526
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