|  | #undef LOG_TAG | 
|  | #define LOG_TAG "SchedulerUnittests" | 
|  |  | 
|  | #include <gmock/gmock.h> | 
|  | #include <gtest/gtest.h> | 
|  |  | 
|  | #include <log/log.h> | 
|  |  | 
|  | #include <mutex> | 
|  |  | 
|  | #include "Scheduler/EventControlThread.h" | 
|  | #include "Scheduler/EventThread.h" | 
|  | #include "Scheduler/Scheduler.h" | 
|  | #include "mock/MockEventThread.h" | 
|  |  | 
|  | using testing::_; | 
|  | using testing::Return; | 
|  |  | 
|  | namespace android { | 
|  |  | 
|  | constexpr PhysicalDisplayId PHYSICAL_DISPLAY_ID = 999; | 
|  |  | 
|  | class SchedulerTest : public testing::Test { | 
|  | protected: | 
|  | class MockEventThreadConnection : public android::EventThreadConnection { | 
|  | public: | 
|  | explicit MockEventThreadConnection(EventThread* eventThread) | 
|  | : EventThreadConnection(eventThread, ResyncCallback(), | 
|  | ISurfaceComposer::eConfigChangedSuppress) {} | 
|  | ~MockEventThreadConnection() = default; | 
|  |  | 
|  | MOCK_METHOD1(stealReceiveChannel, status_t(gui::BitTube* outChannel)); | 
|  | MOCK_METHOD1(setVsyncRate, status_t(uint32_t count)); | 
|  | MOCK_METHOD0(requestNextVsync, void()); | 
|  | }; | 
|  |  | 
|  | scheduler::RefreshRateConfigs mRefreshRateConfigs; | 
|  |  | 
|  | /** | 
|  | * This mock Scheduler class uses implementation of mock::EventThread but keeps everything else | 
|  | * the same. | 
|  | */ | 
|  | class MockScheduler : public android::Scheduler { | 
|  | public: | 
|  | MockScheduler(const scheduler::RefreshRateConfigs& refreshRateConfigs, | 
|  | std::unique_ptr<EventThread> eventThread) | 
|  | : Scheduler([](bool) {}, refreshRateConfigs), mEventThread(std::move(eventThread)) {} | 
|  |  | 
|  | std::unique_ptr<EventThread> makeEventThread( | 
|  | const char* /* connectionName */, DispSync* /* dispSync */, | 
|  | nsecs_t /* phaseOffsetNs */, nsecs_t /* offsetThresholdForNextVsync */, | 
|  | impl::EventThread::InterceptVSyncsCallback /* interceptCallback */) override { | 
|  | return std::move(mEventThread); | 
|  | } | 
|  |  | 
|  | MockScheduler() = default; | 
|  | ~MockScheduler() override = default; | 
|  |  | 
|  | std::unique_ptr<EventThread> mEventThread; | 
|  | }; | 
|  |  | 
|  | SchedulerTest(); | 
|  | ~SchedulerTest() override; | 
|  |  | 
|  | sp<Scheduler::ConnectionHandle> mConnectionHandle; | 
|  | mock::EventThread* mEventThread; | 
|  | std::unique_ptr<MockScheduler> mScheduler; | 
|  | sp<MockEventThreadConnection> mEventThreadConnection; | 
|  | }; | 
|  |  | 
|  | SchedulerTest::SchedulerTest() { | 
|  | 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()); | 
|  |  | 
|  | std::unique_ptr<mock::EventThread> eventThread = std::make_unique<mock::EventThread>(); | 
|  | mEventThread = eventThread.get(); | 
|  | mScheduler = std::make_unique<MockScheduler>(mRefreshRateConfigs, std::move(eventThread)); | 
|  | EXPECT_CALL(*mEventThread, registerDisplayEventConnection(_)).WillOnce(Return(0)); | 
|  |  | 
|  | mEventThreadConnection = new MockEventThreadConnection(mEventThread); | 
|  |  | 
|  | // createConnection call to scheduler makes a createEventConnection call to EventThread. Make | 
|  | // sure that call gets executed and returns an EventThread::Connection object. | 
|  | EXPECT_CALL(*mEventThread, createEventConnection(_, _)) | 
|  | .WillRepeatedly(Return(mEventThreadConnection)); | 
|  |  | 
|  | mConnectionHandle = mScheduler->createConnection("appConnection", 16, 16, ResyncCallback(), | 
|  | impl::EventThread::InterceptVSyncsCallback()); | 
|  | EXPECT_TRUE(mConnectionHandle != nullptr); | 
|  | } | 
|  |  | 
|  | SchedulerTest::~SchedulerTest() { | 
|  | 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()); | 
|  | } | 
|  |  | 
|  | namespace { | 
|  | /* ------------------------------------------------------------------------ | 
|  | * Test cases | 
|  | */ | 
|  |  | 
|  | TEST_F(SchedulerTest, testNullPtr) { | 
|  | // Passing a null pointer for ConnectionHandle is a valid argument. The code doesn't throw any | 
|  | // exceptions, just gracefully continues. | 
|  | sp<IDisplayEventConnection> returnedValue; | 
|  | ASSERT_NO_FATAL_FAILURE( | 
|  | returnedValue = | 
|  | mScheduler->createDisplayEventConnection(nullptr, ResyncCallback(), | 
|  | ISurfaceComposer:: | 
|  | eConfigChangedSuppress)); | 
|  | EXPECT_TRUE(returnedValue == nullptr); | 
|  | EXPECT_TRUE(mScheduler->getEventThread(nullptr) == nullptr); | 
|  | EXPECT_TRUE(mScheduler->getEventConnection(nullptr) == nullptr); | 
|  | ASSERT_NO_FATAL_FAILURE(mScheduler->hotplugReceived(nullptr, PHYSICAL_DISPLAY_ID, false)); | 
|  | ASSERT_NO_FATAL_FAILURE(mScheduler->onScreenAcquired(nullptr)); | 
|  | ASSERT_NO_FATAL_FAILURE(mScheduler->onScreenReleased(nullptr)); | 
|  | std::string testString; | 
|  | ASSERT_NO_FATAL_FAILURE(mScheduler->dump(nullptr, testString)); | 
|  | EXPECT_TRUE(testString == ""); | 
|  | ASSERT_NO_FATAL_FAILURE(mScheduler->setPhaseOffset(nullptr, 10)); | 
|  | } | 
|  |  | 
|  | TEST_F(SchedulerTest, invalidConnectionHandle) { | 
|  | // Passing an invalid ConnectionHandle is a valid argument. The code doesn't throw any | 
|  | // exceptions, just gracefully continues. | 
|  | sp<Scheduler::ConnectionHandle> connectionHandle = new Scheduler::ConnectionHandle(20); | 
|  |  | 
|  | sp<IDisplayEventConnection> returnedValue; | 
|  | ASSERT_NO_FATAL_FAILURE( | 
|  | returnedValue = | 
|  | mScheduler->createDisplayEventConnection(connectionHandle, ResyncCallback(), | 
|  | ISurfaceComposer:: | 
|  | eConfigChangedSuppress)); | 
|  | EXPECT_TRUE(returnedValue == nullptr); | 
|  | EXPECT_TRUE(mScheduler->getEventThread(connectionHandle) == nullptr); | 
|  | EXPECT_TRUE(mScheduler->getEventConnection(connectionHandle) == nullptr); | 
|  |  | 
|  | // The EXPECT_CALLS make sure we don't call the functions on the subsequent event threads. | 
|  | EXPECT_CALL(*mEventThread, onHotplugReceived(_, _)).Times(0); | 
|  | ASSERT_NO_FATAL_FAILURE( | 
|  | mScheduler->hotplugReceived(connectionHandle, PHYSICAL_DISPLAY_ID, false)); | 
|  |  | 
|  | EXPECT_CALL(*mEventThread, onScreenAcquired()).Times(0); | 
|  | ASSERT_NO_FATAL_FAILURE(mScheduler->onScreenAcquired(connectionHandle)); | 
|  |  | 
|  | EXPECT_CALL(*mEventThread, onScreenReleased()).Times(0); | 
|  | ASSERT_NO_FATAL_FAILURE(mScheduler->onScreenReleased(connectionHandle)); | 
|  |  | 
|  | std::string testString; | 
|  | EXPECT_CALL(*mEventThread, dump(_)).Times(0); | 
|  | ASSERT_NO_FATAL_FAILURE(mScheduler->dump(connectionHandle, testString)); | 
|  | EXPECT_TRUE(testString == ""); | 
|  |  | 
|  | EXPECT_CALL(*mEventThread, setPhaseOffset(_)).Times(0); | 
|  | ASSERT_NO_FATAL_FAILURE(mScheduler->setPhaseOffset(connectionHandle, 10)); | 
|  | } | 
|  |  | 
|  | TEST_F(SchedulerTest, validConnectionHandle) { | 
|  | sp<IDisplayEventConnection> returnedValue; | 
|  | ASSERT_NO_FATAL_FAILURE( | 
|  | returnedValue = | 
|  | mScheduler->createDisplayEventConnection(mConnectionHandle, ResyncCallback(), | 
|  | ISurfaceComposer:: | 
|  | eConfigChangedSuppress)); | 
|  | EXPECT_TRUE(returnedValue != nullptr); | 
|  | ASSERT_EQ(returnedValue, mEventThreadConnection); | 
|  |  | 
|  | EXPECT_TRUE(mScheduler->getEventThread(mConnectionHandle) != nullptr); | 
|  | EXPECT_TRUE(mScheduler->getEventConnection(mConnectionHandle) != nullptr); | 
|  |  | 
|  | EXPECT_CALL(*mEventThread, onHotplugReceived(PHYSICAL_DISPLAY_ID, false)).Times(1); | 
|  | ASSERT_NO_FATAL_FAILURE( | 
|  | mScheduler->hotplugReceived(mConnectionHandle, PHYSICAL_DISPLAY_ID, false)); | 
|  |  | 
|  | EXPECT_CALL(*mEventThread, onScreenAcquired()).Times(1); | 
|  | ASSERT_NO_FATAL_FAILURE(mScheduler->onScreenAcquired(mConnectionHandle)); | 
|  |  | 
|  | EXPECT_CALL(*mEventThread, onScreenReleased()).Times(1); | 
|  | ASSERT_NO_FATAL_FAILURE(mScheduler->onScreenReleased(mConnectionHandle)); | 
|  |  | 
|  | std::string testString("dump"); | 
|  | EXPECT_CALL(*mEventThread, dump(testString)).Times(1); | 
|  | ASSERT_NO_FATAL_FAILURE(mScheduler->dump(mConnectionHandle, testString)); | 
|  | EXPECT_TRUE(testString != ""); | 
|  |  | 
|  | EXPECT_CALL(*mEventThread, setPhaseOffset(10)).Times(1); | 
|  | ASSERT_NO_FATAL_FAILURE(mScheduler->setPhaseOffset(mConnectionHandle, 10)); | 
|  | } | 
|  | } // namespace | 
|  | } // namespace android |