blob: 2941a14ef9ebb9f4ca47464d6bb92947aebaaf49 [file] [log] [blame]
/*
* 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 <android/gui/BnJankListener.h>
#include <binder/IInterface.h>
#include "BackgroundExecutor.h"
#include "Jank/JankTracker.h"
#include <gmock/gmock.h>
#include <gtest/gtest.h>
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<gui::JankData>& jankData),
(override));
};
} // anonymous namespace
class JankTrackerTest : public Test {
public:
JankTrackerTest() {}
void SetUp() override { mListener = sp<StrictMock<MockJankListener>>::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<gui::JankData> getCollectedJankData(int32_t layerId) {
return JankTracker::getCollectedJankDataForTesting(layerId);
}
sp<StrictMock<MockJankListener>> 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<gui::JankData>& 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<gui::JankData>& 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<gui::JankData>& 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