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

Commit 50c202aa authored by Ady Abraham's avatar Ady Abraham
Browse files

SurfaceFlinger: add a unit test for DispSyncSource

Add a unit test for DispSyncSource class.

Fixes: 124799942
Test: adb shell /data/nativetest64/libsurfaceflinger_unittest/libsurfaceflinger_unittest --gtest_repeat=20
Change-Id: I76b824f25a9cbc8ba204a702e446fe9ac073be02
parent d3dfeb62
Loading
Loading
Loading
Loading
+4 −1
Original line number Original line Diff line number Diff line
@@ -453,7 +453,10 @@ DispSync::DispSync(const char* name) : mName(name), mRefreshSkipCount(0) {
    mThread = new DispSyncThread(name, mTraceDetailedInfo);
    mThread = new DispSyncThread(name, mTraceDetailedInfo);
}
}


DispSync::~DispSync() {}
DispSync::~DispSync() {
    mThread->stop();
    mThread->requestExitAndWait();
}


void DispSync::init(bool hasSyncFramework, int64_t dispSyncPresentTimeOffset) {
void DispSync::init(bool hasSyncFramework, int64_t dispSyncPresentTimeOffset) {
    mIgnorePresentFences = !hasSyncFramework;
    mIgnorePresentFences = !hasSyncFramework;
+1 −0
Original line number Original line Diff line number Diff line
@@ -37,6 +37,7 @@ cc_test {
        "libsurfaceflinger_unittest_main.cpp",
        "libsurfaceflinger_unittest_main.cpp",
        "AllowedDisplayConfigsTest.cpp",
        "AllowedDisplayConfigsTest.cpp",
        "CompositionTest.cpp",
        "CompositionTest.cpp",
        "DispSyncSourceTest.cpp",
        "DisplayIdentificationTest.cpp",
        "DisplayIdentificationTest.cpp",
        "DisplayTransactionTest.cpp",
        "DisplayTransactionTest.cpp",
        "EventControlThreadTest.cpp",
        "EventControlThreadTest.cpp",
+164 −0
Original line number Original line Diff line number Diff line
/*
 * Copyright 2019 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.
 */

#undef LOG_TAG
#define LOG_TAG "LibSurfaceFlingerUnittests"
#define LOG_NDEBUG 0

#include <inttypes.h>

#include <gmock/gmock.h>
#include <gtest/gtest.h>

#include <log/log.h>

#include "AsyncCallRecorder.h"
#include "Scheduler/DispSyncSource.h"
#include "mock/MockDispSync.h"

namespace android {
namespace {

using namespace std::chrono_literals;
using testing::Return;

class DispSyncSourceTest : public testing::Test, private VSyncSource::Callback {
protected:
    DispSyncSourceTest();
    ~DispSyncSourceTest() override;

    void createDispSync();
    void createDispSyncSource();

    void onVSyncEvent(nsecs_t when) override;

    std::unique_ptr<mock::DispSync> mDispSync;
    std::unique_ptr<DispSyncSource> mDispSyncSource;

    AsyncCallRecorder<void (*)(nsecs_t)> mVSyncEventCallRecorder;

    static constexpr std::chrono::nanoseconds mPhaseOffset = 6ms;
    static constexpr int mIterations = 100;
};

DispSyncSourceTest::DispSyncSourceTest() {
    const ::testing::TestInfo* const test_info =
            ::testing::UnitTest::GetInstance()->current_test_info();
    ALOGD("**** Setting up for %s.%s\n", test_info->test_case_name(), test_info->name());
}

DispSyncSourceTest::~DispSyncSourceTest() {
    const ::testing::TestInfo* const test_info =
            ::testing::UnitTest::GetInstance()->current_test_info();
    ALOGD("**** Tearing down after %s.%s\n", test_info->test_case_name(), test_info->name());
}

void DispSyncSourceTest::onVSyncEvent(nsecs_t when) {
    ALOGD("onVSyncEvent: %" PRId64, when);

    mVSyncEventCallRecorder.recordCall(when);
}

void DispSyncSourceTest::createDispSync() {
    mDispSync = std::make_unique<mock::DispSync>();
}

void DispSyncSourceTest::createDispSyncSource() {
    createDispSync();
    mDispSyncSource = std::make_unique<DispSyncSource>(mDispSync.get(), mPhaseOffset.count(), true,
                                                       "DispSyncSourceTest");
    mDispSyncSource->setCallback(this);
}

/* ------------------------------------------------------------------------
 * Test cases
 */

TEST_F(DispSyncSourceTest, createDispSync) {
    createDispSync();
    EXPECT_TRUE(mDispSync);
}

TEST_F(DispSyncSourceTest, createDispSyncSource) {
    createDispSyncSource();
    EXPECT_TRUE(mDispSyncSource);
}

TEST_F(DispSyncSourceTest, noCallbackAfterInit) {
    createDispSyncSource();
    EXPECT_TRUE(mDispSyncSource);

    // DispSyncSource starts with Vsync disabled
    mDispSync->triggerCallback();
    EXPECT_FALSE(mVSyncEventCallRecorder.waitForUnexpectedCall().has_value());
}

TEST_F(DispSyncSourceTest, waitForCallbacks) {
    createDispSyncSource();
    EXPECT_TRUE(mDispSyncSource);

    mDispSyncSource->setVSyncEnabled(true);
    EXPECT_EQ(mDispSync->getCallbackPhase(), mPhaseOffset.count());

    for (int i = 0; i < mIterations; i++) {
        mDispSync->triggerCallback();
        EXPECT_TRUE(mVSyncEventCallRecorder.waitForCall().has_value());
    }
}

TEST_F(DispSyncSourceTest, waitForCallbacksWithPhaseChange) {
    createDispSyncSource();
    EXPECT_TRUE(mDispSyncSource);

    mDispSyncSource->setVSyncEnabled(true);
    EXPECT_EQ(mDispSync->getCallbackPhase(), mPhaseOffset.count());

    for (int i = 0; i < mIterations; i++) {
        mDispSync->triggerCallback();
        EXPECT_TRUE(mVSyncEventCallRecorder.waitForCall().has_value());
    }

    EXPECT_CALL(*mDispSync, getPeriod()).Times(1).WillOnce(Return(16666666));
    mDispSyncSource->setPhaseOffset((mPhaseOffset / 2).count());

    EXPECT_EQ(mDispSync->getCallbackPhase(), (mPhaseOffset / 2).count());

    for (int i = 0; i < mIterations; i++) {
        mDispSync->triggerCallback();
        EXPECT_TRUE(mVSyncEventCallRecorder.waitForCall().has_value());
    }
}

TEST_F(DispSyncSourceTest, pauseCallbacks) {
    createDispSyncSource();
    EXPECT_TRUE(mDispSyncSource);

    mDispSyncSource->setVSyncEnabled(true);
    EXPECT_EQ(mDispSync->getCallbackPhase(), mPhaseOffset.count());
    mDispSync->triggerCallback();
    EXPECT_TRUE(mVSyncEventCallRecorder.waitForCall().has_value());

    mDispSyncSource->pauseVsyncCallback(true);
    mDispSync->triggerCallback();
    EXPECT_FALSE(mVSyncEventCallRecorder.waitForUnexpectedCall().has_value());

    mDispSyncSource->pauseVsyncCallback(false);
    mDispSync->triggerCallback();
    EXPECT_TRUE(mVSyncEventCallRecorder.waitForUnexpectedCall().has_value());
}

} // namespace
} // namespace android
+35 −0
Original line number Original line Diff line number Diff line
@@ -15,6 +15,7 @@
 */
 */


#include "mock/MockDispSync.h"
#include "mock/MockDispSync.h"
#include <thread>


namespace android {
namespace android {
namespace mock {
namespace mock {
@@ -23,5 +24,39 @@ namespace mock {
DispSync::DispSync() = default;
DispSync::DispSync() = default;
DispSync::~DispSync() = default;
DispSync::~DispSync() = default;


status_t DispSync::addEventListener(const char* /*name*/, nsecs_t phase, Callback* callback,
                                    nsecs_t /*lastCallbackTime*/) {
    if (mCallback.callback != nullptr) {
        return BAD_VALUE;
    }

    mCallback = {callback, phase};
    return NO_ERROR;
}
status_t DispSync::removeEventListener(Callback* callback, nsecs_t* /*outLastCallback*/) {
    if (mCallback.callback != callback) {
        return BAD_VALUE;
    }

    mCallback = {nullptr, 0};
    return NO_ERROR;
}

status_t DispSync::changePhaseOffset(Callback* callback, nsecs_t phase) {
    if (mCallback.callback != callback) {
        return BAD_VALUE;
    }

    mCallback.phase = phase;
    return NO_ERROR;
}

void DispSync::triggerCallback() {
    if (mCallback.callback == nullptr) return;

    mCallback.callback->onDispSyncEvent(
            std::chrono::steady_clock::now().time_since_epoch().count());
}

} // namespace mock
} // namespace mock
} // namespace android
} // namespace android
+16 −3
Original line number Original line Diff line number Diff line
@@ -36,14 +36,27 @@ public:
    MOCK_METHOD1(setPeriod, void(nsecs_t));
    MOCK_METHOD1(setPeriod, void(nsecs_t));
    MOCK_METHOD0(getPeriod, nsecs_t());
    MOCK_METHOD0(getPeriod, nsecs_t());
    MOCK_METHOD1(setRefreshSkipCount, void(int));
    MOCK_METHOD1(setRefreshSkipCount, void(int));
    MOCK_METHOD4(addEventListener, status_t(const char*, nsecs_t, Callback*, nsecs_t));
    MOCK_METHOD2(removeEventListener, status_t(Callback*, nsecs_t*));
    MOCK_METHOD2(changePhaseOffset, status_t(Callback*, nsecs_t));
    MOCK_CONST_METHOD1(computeNextRefresh, nsecs_t(int));
    MOCK_CONST_METHOD1(computeNextRefresh, nsecs_t(int));
    MOCK_METHOD1(setIgnorePresentFences, void(bool));
    MOCK_METHOD1(setIgnorePresentFences, void(bool));
    MOCK_METHOD0(expectedPresentTime, nsecs_t());
    MOCK_METHOD0(expectedPresentTime, nsecs_t());


    MOCK_CONST_METHOD1(dump, void(std::string&));
    MOCK_CONST_METHOD1(dump, void(std::string&));

    status_t addEventListener(const char* name, nsecs_t phase, Callback* callback,
                              nsecs_t lastCallbackTime) override;
    status_t removeEventListener(Callback* callback, nsecs_t* outLastCallback) override;
    status_t changePhaseOffset(Callback* callback, nsecs_t phase) override;

    nsecs_t getCallbackPhase() { return mCallback.phase; }

    void triggerCallback();

private:
    struct CallbackType {
        Callback* callback = nullptr;
        nsecs_t phase;
    };
    CallbackType mCallback;
};
};


} // namespace mock
} // namespace mock