/* * Copyright 2024 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. */ #include #include #include "BackgroundExecutor.h" #include "Jank/JankTracker.h" #include #include namespace android { namespace { using namespace testing; class MockJankListener : public gui::BnJankListener { public: MockJankListener() = default; ~MockJankListener() override = default; MOCK_METHOD(binder::Status, onJankData, (const std::vector& jankData), (override)); }; } // anonymous namespace class JankTrackerTest : public Test { public: JankTrackerTest() {} void SetUp() override { mListener = sp>::make(); } void addJankListener(int32_t layerId) { JankTracker::addJankListener(layerId, IInterface::asBinder(mListener)); } void removeJankListener(int32_t layerId, int64_t after) { JankTracker::removeJankListener(layerId, IInterface::asBinder(mListener), after); } void addJankData(int32_t layerId, int jankType) { gui::JankData data; data.frameVsyncId = mVsyncId++; data.jankType = jankType; data.frameIntervalNs = 8333333; JankTracker::onJankData(layerId, data); } void flushBackgroundThread() { BackgroundExecutor::getLowPriorityInstance().flushQueue(); } size_t listenerCount() { return JankTracker::sListenerCount; } std::vector getCollectedJankData(int32_t layerId) { return JankTracker::getCollectedJankDataForTesting(layerId); } sp> mListener = nullptr; int64_t mVsyncId = 1000; }; TEST_F(JankTrackerTest, jankDataIsTrackedAndPropagated) { ASSERT_EQ(listenerCount(), 0u); EXPECT_CALL(*mListener.get(), onJankData(SizeIs(3))) .WillOnce([](const std::vector& jankData) { EXPECT_EQ(jankData[0].frameVsyncId, 1000); EXPECT_EQ(jankData[0].jankType, 1); EXPECT_EQ(jankData[0].frameIntervalNs, 8333333); EXPECT_EQ(jankData[1].frameVsyncId, 1001); EXPECT_EQ(jankData[1].jankType, 2); EXPECT_EQ(jankData[1].frameIntervalNs, 8333333); EXPECT_EQ(jankData[2].frameVsyncId, 1002); EXPECT_EQ(jankData[2].jankType, 3); EXPECT_EQ(jankData[2].frameIntervalNs, 8333333); return binder::Status::ok(); }); EXPECT_CALL(*mListener.get(), onJankData(SizeIs(2))) .WillOnce([](const std::vector& jankData) { EXPECT_EQ(jankData[0].frameVsyncId, 1003); EXPECT_EQ(jankData[0].jankType, 4); EXPECT_EQ(jankData[0].frameIntervalNs, 8333333); EXPECT_EQ(jankData[1].frameVsyncId, 1004); EXPECT_EQ(jankData[1].jankType, 5); EXPECT_EQ(jankData[1].frameIntervalNs, 8333333); return binder::Status::ok(); }); addJankListener(123); addJankData(123, 1); addJankData(123, 2); addJankData(123, 3); JankTracker::flushJankData(123); addJankData(123, 4); removeJankListener(123, mVsyncId); addJankData(123, 5); JankTracker::flushJankData(123); addJankData(123, 6); JankTracker::flushJankData(123); removeJankListener(123, 0); flushBackgroundThread(); } TEST_F(JankTrackerTest, jankDataIsAutomaticallyFlushedInBatches) { ASSERT_EQ(listenerCount(), 0u); // needs to be larger than kJankDataBatchSize in JankTracker.cpp. constexpr size_t kNumberOfJankDataToSend = 234; size_t jankDataReceived = 0; size_t numBatchesReceived = 0; EXPECT_CALL(*mListener.get(), onJankData(_)) .WillRepeatedly([&](const std::vector& jankData) { jankDataReceived += jankData.size(); numBatchesReceived++; return binder::Status::ok(); }); addJankListener(123); for (size_t i = 0; i < kNumberOfJankDataToSend; i++) { addJankData(123, 0); } flushBackgroundThread(); // Check that we got some data, without explicitly flushing. EXPECT_GT(jankDataReceived, 0u); EXPECT_GT(numBatchesReceived, 0u); EXPECT_LT(numBatchesReceived, jankDataReceived); // batches should be > size 1. removeJankListener(123, 0); JankTracker::flushJankData(123); flushBackgroundThread(); EXPECT_EQ(jankDataReceived, kNumberOfJankDataToSend); } TEST_F(JankTrackerTest, jankListenerIsRemovedWhenReturningNullError) { ASSERT_EQ(listenerCount(), 0u); EXPECT_CALL(*mListener.get(), onJankData(SizeIs(3))) .WillOnce(Return(binder::Status::fromExceptionCode(binder::Status::EX_NULL_POINTER))); addJankListener(123); addJankData(123, 1); addJankData(123, 2); addJankData(123, 3); JankTracker::flushJankData(123); addJankData(123, 4); addJankData(123, 5); JankTracker::flushJankData(123); flushBackgroundThread(); EXPECT_EQ(listenerCount(), 0u); } TEST_F(JankTrackerTest, jankDataIsDroppedIfNobodyIsListening) { ASSERT_EQ(listenerCount(), 0u); addJankData(123, 1); addJankData(123, 2); addJankData(123, 3); flushBackgroundThread(); EXPECT_EQ(getCollectedJankData(123).size(), 0u); } TEST_F(JankTrackerTest, listenerCountTracksRegistrations) { ASSERT_EQ(listenerCount(), 0u); addJankListener(123); addJankListener(456); flushBackgroundThread(); EXPECT_EQ(listenerCount(), 2u); removeJankListener(123, 0); JankTracker::flushJankData(123); removeJankListener(456, 0); JankTracker::flushJankData(456); flushBackgroundThread(); EXPECT_EQ(listenerCount(), 0u); } TEST_F(JankTrackerTest, listenerCountIsAccurateOnDuplicateRegistration) { ASSERT_EQ(listenerCount(), 0u); addJankListener(123); addJankListener(123); flushBackgroundThread(); EXPECT_EQ(listenerCount(), 1u); removeJankListener(123, 0); JankTracker::flushJankData(123); flushBackgroundThread(); EXPECT_EQ(listenerCount(), 0u); } } // namespace android