SF: add partial implementation of VSyncReactor
Adds an adaptor for the VSyncDispatch/VSyncTracker system
that will implemente the DispSync interface. Implementation
is only partial, will build out rest in subsequent MPs.
Bug: 140303479
Test: 6 new unit tests (VSyncReactor)
Change-Id: I11441f0f5bac9095d14122f487ab99bbdf44a7e3
diff --git a/services/surfaceflinger/tests/unittests/Android.bp b/services/surfaceflinger/tests/unittests/Android.bp
index 0c4a752..ccfa6c5 100644
--- a/services/surfaceflinger/tests/unittests/Android.bp
+++ b/services/surfaceflinger/tests/unittests/Android.bp
@@ -57,6 +57,7 @@
"VSyncDispatchTimerQueueTest.cpp",
"VSyncDispatchRealtimeTest.cpp",
"VSyncPredictorTest.cpp",
+ "VSyncReactorTest.cpp",
"mock/DisplayHardware/MockComposer.cpp",
"mock/DisplayHardware/MockDisplay.cpp",
"mock/DisplayHardware/MockPowerAdvisor.cpp",
diff --git a/services/surfaceflinger/tests/unittests/VSyncReactorTest.cpp b/services/surfaceflinger/tests/unittests/VSyncReactorTest.cpp
new file mode 100644
index 0000000..b4aebf0
--- /dev/null
+++ b/services/surfaceflinger/tests/unittests/VSyncReactorTest.cpp
@@ -0,0 +1,184 @@
+/*
+ * 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 "Scheduler/VSyncDispatch.h"
+#include "Scheduler/VSyncReactor.h"
+#include "Scheduler/VSyncTracker.h"
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+#include <ui/Fence.h>
+#include <ui/FenceTime.h>
+#include <array>
+
+using namespace testing;
+using namespace std::literals;
+namespace android::scheduler {
+
+class MockVSyncTracker : public VSyncTracker {
+public:
+ MOCK_METHOD1(addVsyncTimestamp, void(nsecs_t));
+ MOCK_CONST_METHOD1(nextAnticipatedVSyncTimeFrom, nsecs_t(nsecs_t));
+};
+
+class VSyncTrackerWrapper : public VSyncTracker {
+public:
+ VSyncTrackerWrapper(std::shared_ptr<VSyncTracker> const& tracker) : mTracker(tracker) {}
+
+ void addVsyncTimestamp(nsecs_t timestamp) final { mTracker->addVsyncTimestamp(timestamp); }
+ nsecs_t nextAnticipatedVSyncTimeFrom(nsecs_t timePoint) const final {
+ return mTracker->nextAnticipatedVSyncTimeFrom(timePoint);
+ }
+
+private:
+ std::shared_ptr<VSyncTracker> const mTracker;
+};
+
+class MockVSyncDispatch : public VSyncDispatch {
+public:
+ MOCK_METHOD2(registerCallback, CallbackToken(std::function<void(nsecs_t)> const&, std::string));
+ MOCK_METHOD1(unregisterCallback, void(CallbackToken));
+ MOCK_METHOD3(schedule, ScheduleResult(CallbackToken, nsecs_t, nsecs_t));
+ MOCK_METHOD1(cancel, CancelResult(CallbackToken token));
+};
+
+class VSyncDispatchWrapper : public VSyncDispatch {
+public:
+ VSyncDispatchWrapper(std::shared_ptr<VSyncDispatch> const& dispatch) : mDispatch(dispatch) {}
+ CallbackToken registerCallback(std::function<void(nsecs_t)> const& callbackFn,
+ std::string callbackName) final {
+ return mDispatch->registerCallback(callbackFn, callbackName);
+ }
+
+ void unregisterCallback(CallbackToken token) final { mDispatch->unregisterCallback(token); }
+
+ ScheduleResult schedule(CallbackToken token, nsecs_t workDuration,
+ nsecs_t earliestVsync) final {
+ return mDispatch->schedule(token, workDuration, earliestVsync);
+ }
+
+ CancelResult cancel(CallbackToken token) final { return mDispatch->cancel(token); }
+
+private:
+ std::shared_ptr<VSyncDispatch> const mDispatch;
+};
+
+std::shared_ptr<FenceTime> generateInvalidFence() {
+ sp<Fence> fence = new Fence();
+ return std::make_shared<FenceTime>(fence);
+}
+
+std::shared_ptr<FenceTime> generatePendingFence() {
+ sp<Fence> fence = new Fence(dup(fileno(tmpfile())));
+ return std::make_shared<FenceTime>(fence);
+}
+
+void signalFenceWithTime(std::shared_ptr<FenceTime> const& fence, nsecs_t time) {
+ FenceTime::Snapshot snap(time);
+ fence->applyTrustedSnapshot(snap);
+}
+
+std::shared_ptr<FenceTime> generateSignalledFenceWithTime(nsecs_t time) {
+ sp<Fence> fence = new Fence(dup(fileno(tmpfile())));
+ std::shared_ptr<FenceTime> ft = std::make_shared<FenceTime>(fence);
+ signalFenceWithTime(ft, time);
+ return ft;
+}
+
+class VSyncReactorTest : public testing::Test {
+protected:
+ VSyncReactorTest()
+ : mMockDispatch(std::make_shared<MockVSyncDispatch>()),
+ mMockTracker(std::make_shared<MockVSyncTracker>()),
+ mReactor(std::make_unique<VSyncDispatchWrapper>(mMockDispatch),
+ std::make_unique<VSyncTrackerWrapper>(mMockTracker), kPendingLimit) {}
+
+ std::shared_ptr<MockVSyncDispatch> mMockDispatch;
+ std::shared_ptr<MockVSyncTracker> mMockTracker;
+ static constexpr size_t kPendingLimit = 3;
+ static constexpr nsecs_t dummyTime = 47;
+ VSyncReactor mReactor;
+};
+
+TEST_F(VSyncReactorTest, addingNullFenceCheck) {
+ EXPECT_FALSE(mReactor.addPresentFence(nullptr));
+}
+
+TEST_F(VSyncReactorTest, addingInvalidFenceSignalsNeedsMoreInfo) {
+ EXPECT_TRUE(mReactor.addPresentFence(generateInvalidFence()));
+}
+
+TEST_F(VSyncReactorTest, addingSignalledFenceAddsToTracker) {
+ EXPECT_CALL(*mMockTracker, addVsyncTimestamp(dummyTime));
+ EXPECT_FALSE(mReactor.addPresentFence(generateSignalledFenceWithTime(dummyTime)));
+}
+
+TEST_F(VSyncReactorTest, addingPendingFenceAddsSignalled) {
+ nsecs_t anotherDummyTime = 2919019201;
+
+ EXPECT_CALL(*mMockTracker, addVsyncTimestamp(_)).Times(0);
+ auto pendingFence = generatePendingFence();
+ EXPECT_FALSE(mReactor.addPresentFence(pendingFence));
+ Mock::VerifyAndClearExpectations(mMockTracker.get());
+
+ signalFenceWithTime(pendingFence, dummyTime);
+
+ EXPECT_CALL(*mMockTracker, addVsyncTimestamp(dummyTime));
+ EXPECT_CALL(*mMockTracker, addVsyncTimestamp(anotherDummyTime));
+ EXPECT_FALSE(mReactor.addPresentFence(generateSignalledFenceWithTime(anotherDummyTime)));
+}
+
+TEST_F(VSyncReactorTest, limitsPendingFences) {
+ std::array<std::shared_ptr<FenceTime>, kPendingLimit * 2> fences;
+ std::array<nsecs_t, fences.size()> fakeTimes;
+ std::generate(fences.begin(), fences.end(), [] { return generatePendingFence(); });
+ std::generate(fakeTimes.begin(), fakeTimes.end(), [i = 10]() mutable {
+ i++;
+ return i * i;
+ });
+
+ for (auto const& fence : fences) {
+ mReactor.addPresentFence(fence);
+ }
+
+ for (auto i = fences.size() - kPendingLimit; i < fences.size(); i++) {
+ EXPECT_CALL(*mMockTracker, addVsyncTimestamp(fakeTimes[i]));
+ }
+
+ for (auto i = 0u; i < fences.size(); i++) {
+ signalFenceWithTime(fences[i], fakeTimes[i]);
+ }
+ mReactor.addPresentFence(generatePendingFence());
+}
+
+TEST_F(VSyncReactorTest, ignoresPresentFencesWhenToldTo) {
+ static constexpr size_t aFewTimes = 8;
+ EXPECT_CALL(*mMockTracker, addVsyncTimestamp(dummyTime)).Times(1);
+
+ mReactor.setIgnorePresentFences(true);
+ for (auto i = 0; i < aFewTimes; i++) {
+ mReactor.addPresentFence(generateSignalledFenceWithTime(dummyTime));
+ }
+
+ mReactor.setIgnorePresentFences(false);
+ EXPECT_FALSE(mReactor.addPresentFence(generateSignalledFenceWithTime(dummyTime)));
+}
+
+} // namespace android::scheduler