SurfaceFlinger: use duration instead of offset

This change is using the duration given to sf/app without
converting them back to the legacy offset. This allows us to get
the expected vsync associated with a wakeup event.

This change also required some refactoring:
 - Move the periodic callback interface out of DispSync and in
   to DispSyncSource
 - Translate legacy offsets to duration in case that duration
   is not specified in the build files
 - Add support to VSD to expose the deadline timestamp of when
   a frame needs to be ready by

Bug: 162888874
Test: SF unit tests
Test: examine systraces

Change-Id: I87a53cc7dea931d3c195eab6842e003ca4516885
diff --git a/services/surfaceflinger/tests/unittests/DispSyncSourceTest.cpp b/services/surfaceflinger/tests/unittests/DispSyncSourceTest.cpp
index afebc40..54f4c7c 100644
--- a/services/surfaceflinger/tests/unittests/DispSyncSourceTest.cpp
+++ b/services/surfaceflinger/tests/unittests/DispSyncSourceTest.cpp
@@ -27,13 +27,99 @@
 
 #include "AsyncCallRecorder.h"
 #include "Scheduler/DispSyncSource.h"
-#include "mock/MockDispSync.h"
+#include "Scheduler/VSyncDispatch.h"
 
 namespace android {
 namespace {
 
 using namespace std::chrono_literals;
-using testing::Return;
+using namespace testing;
+
+class MockVSyncDispatch : public scheduler::VSyncDispatch {
+public:
+    MOCK_METHOD2(registerCallback,
+                 CallbackToken(std::function<void(nsecs_t, nsecs_t, nsecs_t)> const&, std::string));
+    MOCK_METHOD1(unregisterCallback, void(CallbackToken));
+    MOCK_METHOD2(schedule, scheduler::ScheduleResult(CallbackToken, ScheduleTiming));
+    MOCK_METHOD1(cancel, scheduler::CancelResult(CallbackToken token));
+    MOCK_CONST_METHOD1(dump, void(std::string&));
+
+    MockVSyncDispatch() {
+        ON_CALL(*this, registerCallback)
+                .WillByDefault(
+                        [this](std::function<void(nsecs_t, nsecs_t, nsecs_t)> const& callback,
+                               std::string) {
+                            CallbackToken token(mNextToken);
+                            mNextToken++;
+
+                            mCallbacks.emplace(token, CallbackData(callback));
+                            ALOGD("registerCallback: %zu", token.value());
+                            return token;
+                        });
+
+        ON_CALL(*this, unregisterCallback).WillByDefault([this](CallbackToken token) {
+            ALOGD("unregisterCallback: %zu", token.value());
+            mCallbacks.erase(token);
+        });
+
+        ON_CALL(*this, schedule).WillByDefault([this](CallbackToken token, ScheduleTiming timing) {
+            ALOGD("schedule: %zu", token.value());
+            if (mCallbacks.count(token) == 0) {
+                ALOGD("schedule: callback %zu not registered", token.value());
+                return scheduler::ScheduleResult::Error;
+            }
+
+            auto& callback = mCallbacks.at(token);
+            callback.scheduled = true;
+            callback.vsyncTime = timing.earliestVsync;
+            callback.targetWakeupTime =
+                    timing.earliestVsync - timing.workDuration - timing.readyDuration;
+            ALOGD("schedule: callback %zu scheduled", token.value());
+            return scheduler::ScheduleResult::Scheduled;
+        });
+
+        ON_CALL(*this, cancel).WillByDefault([this](CallbackToken token) {
+            ALOGD("cancel: %zu", token.value());
+            if (mCallbacks.count(token) == 0) {
+                ALOGD("cancel: callback %zu is not registered", token.value());
+                return scheduler::CancelResult::Error;
+            }
+
+            auto& callback = mCallbacks.at(token);
+            callback.scheduled = false;
+            ALOGD("cancel: callback %zu cancelled", token.value());
+            return scheduler::CancelResult::Cancelled;
+        });
+    }
+
+    void triggerCallbacks() {
+        ALOGD("triggerCallbacks");
+        for (auto& [token, callback] : mCallbacks) {
+            if (callback.scheduled) {
+                ALOGD("triggerCallbacks: callback %zu", token.value());
+                callback.scheduled = false;
+                callback.func(callback.vsyncTime, callback.targetWakeupTime, callback.readyTime);
+            } else {
+                ALOGD("triggerCallbacks: callback %zu is not scheduled", token.value());
+            }
+        }
+    }
+
+private:
+    struct CallbackData {
+        explicit CallbackData(std::function<void(nsecs_t, nsecs_t, nsecs_t)> func)
+              : func(std::move(func)) {}
+
+        std::function<void(nsecs_t, nsecs_t, nsecs_t)> func;
+        bool scheduled = false;
+        nsecs_t vsyncTime = 0;
+        nsecs_t targetWakeupTime = 0;
+        nsecs_t readyTime = 0;
+    };
+
+    std::unordered_map<CallbackToken, CallbackData> mCallbacks;
+    size_t mNextToken;
+};
 
 class DispSyncSourceTest : public testing::Test, private VSyncSource::Callback {
 protected:
@@ -43,15 +129,19 @@
     void createDispSync();
     void createDispSyncSource();
 
-    void onVSyncEvent(nsecs_t when, nsecs_t expectedVSyncTimestamp) override;
+    void onVSyncEvent(nsecs_t when, nsecs_t expectedVSyncTimestamp,
+                      nsecs_t deadlineTimestamp) override;
 
-    std::unique_ptr<mock::DispSync> mDispSync;
-    std::unique_ptr<DispSyncSource> mDispSyncSource;
+    std::unique_ptr<MockVSyncDispatch> mVSyncDispatch;
+    std::unique_ptr<scheduler::DispSyncSource> mDispSyncSource;
 
-    AsyncCallRecorder<void (*)(nsecs_t)> mVSyncEventCallRecorder;
+    AsyncCallRecorder<void (*)(nsecs_t, nsecs_t, nsecs_t)> mVSyncEventCallRecorder;
 
-    static constexpr std::chrono::nanoseconds mPhaseOffset = 6ms;
+    static constexpr std::chrono::nanoseconds mWorkDuration = 20ms;
+    static constexpr std::chrono::nanoseconds mReadyDuration = 10ms;
     static constexpr int mIterations = 100;
+    const scheduler::VSyncDispatch::CallbackToken mFakeToken{2398};
+    const std::string mName = "DispSyncSourceTest";
 };
 
 DispSyncSourceTest::DispSyncSourceTest() {
@@ -66,20 +156,21 @@
     ALOGD("**** Tearing down after %s.%s\n", test_info->test_case_name(), test_info->name());
 }
 
-void DispSyncSourceTest::onVSyncEvent(nsecs_t when, nsecs_t /*expectedVSyncTimestamp*/) {
+void DispSyncSourceTest::onVSyncEvent(nsecs_t when, nsecs_t expectedVSyncTimestamp,
+                                      nsecs_t deadlineTimestamp) {
     ALOGD("onVSyncEvent: %" PRId64, when);
 
-    mVSyncEventCallRecorder.recordCall(when);
+    mVSyncEventCallRecorder.recordCall(when, expectedVSyncTimestamp, deadlineTimestamp);
 }
 
 void DispSyncSourceTest::createDispSync() {
-    mDispSync = std::make_unique<mock::DispSync>();
+    mVSyncDispatch = std::make_unique<MockVSyncDispatch>();
 }
 
 void DispSyncSourceTest::createDispSyncSource() {
-    createDispSync();
-    mDispSyncSource = std::make_unique<DispSyncSource>(mDispSync.get(), mPhaseOffset.count(), true,
-                                                       "DispSyncSourceTest");
+    mDispSyncSource =
+            std::make_unique<scheduler::DispSyncSource>(*mVSyncDispatch, mWorkDuration,
+                                                        mReadyDuration, true, mName.c_str());
     mDispSyncSource->setCallback(this);
 }
 
@@ -89,57 +180,119 @@
 
 TEST_F(DispSyncSourceTest, createDispSync) {
     createDispSync();
-    EXPECT_TRUE(mDispSync);
+    EXPECT_TRUE(mVSyncDispatch);
 }
 
 TEST_F(DispSyncSourceTest, createDispSyncSource) {
+    createDispSync();
+
+    InSequence seq;
+    EXPECT_CALL(*mVSyncDispatch, registerCallback(_, mName)).WillOnce(Return(mFakeToken));
+    EXPECT_CALL(*mVSyncDispatch, cancel(mFakeToken))
+            .WillOnce(Return(scheduler::CancelResult::Cancelled));
+    EXPECT_CALL(*mVSyncDispatch, unregisterCallback(mFakeToken)).WillOnce(Return());
     createDispSyncSource();
+
     EXPECT_TRUE(mDispSyncSource);
 }
 
 TEST_F(DispSyncSourceTest, noCallbackAfterInit) {
+    createDispSync();
+
+    InSequence seq;
+    EXPECT_CALL(*mVSyncDispatch, registerCallback(_, mName)).Times(1);
+    EXPECT_CALL(*mVSyncDispatch, cancel(_)).Times(1);
+    EXPECT_CALL(*mVSyncDispatch, unregisterCallback(_)).Times(1);
     createDispSyncSource();
+
     EXPECT_TRUE(mDispSyncSource);
 
     // DispSyncSource starts with Vsync disabled
-    mDispSync->triggerCallback();
+    mVSyncDispatch->triggerCallbacks();
     EXPECT_FALSE(mVSyncEventCallRecorder.waitForUnexpectedCall().has_value());
 }
 
 TEST_F(DispSyncSourceTest, waitForCallbacks) {
+    createDispSync();
+
+    InSequence seq;
+    EXPECT_CALL(*mVSyncDispatch, registerCallback(_, mName)).Times(1);
+    EXPECT_CALL(*mVSyncDispatch,
+                schedule(_, Truly([&](auto timings) {
+                             return timings.workDuration == mWorkDuration.count() &&
+                                     timings.readyDuration == mReadyDuration.count();
+                         })))
+            .Times(mIterations + 1);
+    EXPECT_CALL(*mVSyncDispatch, cancel(_)).Times(1);
+    EXPECT_CALL(*mVSyncDispatch, unregisterCallback(_)).Times(1);
     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());
+        mVSyncDispatch->triggerCallbacks();
+        const auto callbackData = mVSyncEventCallRecorder.waitForCall();
+        ASSERT_TRUE(callbackData.has_value());
+        const auto [when, expectedVSyncTimestamp, deadlineTimestamp] = callbackData.value();
+        EXPECT_EQ(when, expectedVSyncTimestamp - mWorkDuration.count() - mReadyDuration.count());
     }
 }
 
-TEST_F(DispSyncSourceTest, waitForCallbacksWithPhaseChange) {
+TEST_F(DispSyncSourceTest, waitForCallbacksWithDurationChange) {
+    createDispSync();
+
+    InSequence seq;
+    EXPECT_CALL(*mVSyncDispatch, registerCallback(_, mName)).Times(1);
+    EXPECT_CALL(*mVSyncDispatch,
+                schedule(_, Truly([&](auto timings) {
+                             return timings.workDuration == mWorkDuration.count() &&
+                                     timings.readyDuration == mReadyDuration.count();
+                         })))
+            .Times(1);
+
     createDispSyncSource();
+
     EXPECT_TRUE(mDispSyncSource);
 
     mDispSyncSource->setVSyncEnabled(true);
-    EXPECT_EQ(mDispSync->getCallbackPhase(), mPhaseOffset.count());
-
+    EXPECT_CALL(*mVSyncDispatch,
+                schedule(_, Truly([&](auto timings) {
+                             return timings.workDuration == mWorkDuration.count() &&
+                                     timings.readyDuration == mReadyDuration.count();
+                         })))
+            .Times(mIterations);
     for (int i = 0; i < mIterations; i++) {
-        mDispSync->triggerCallback();
-        EXPECT_TRUE(mVSyncEventCallRecorder.waitForCall().has_value());
+        mVSyncDispatch->triggerCallbacks();
+        const auto callbackData = mVSyncEventCallRecorder.waitForCall();
+        ASSERT_TRUE(callbackData.has_value());
+        const auto [when, expectedVSyncTimestamp, deadlineTimestamp] = callbackData.value();
+        EXPECT_EQ(when, expectedVSyncTimestamp - mWorkDuration.count() - mReadyDuration.count());
     }
 
-    EXPECT_CALL(*mDispSync, getPeriod()).Times(1).WillOnce(Return(16666666));
-    mDispSyncSource->setPhaseOffset((mPhaseOffset / 2).count());
+    const auto newDuration = mWorkDuration / 2;
+    EXPECT_CALL(*mVSyncDispatch, schedule(_, Truly([&](auto timings) {
+                                              return timings.workDuration == newDuration.count() &&
+                                                      timings.readyDuration == 0;
+                                          })))
+            .Times(1);
+    mDispSyncSource->setDuration(newDuration, 0ns);
 
-    EXPECT_EQ(mDispSync->getCallbackPhase(), (mPhaseOffset / 2).count());
-
+    EXPECT_CALL(*mVSyncDispatch, schedule(_, Truly([&](auto timings) {
+                                              return timings.workDuration == newDuration.count() &&
+                                                      timings.readyDuration == 0;
+                                          })))
+            .Times(mIterations);
     for (int i = 0; i < mIterations; i++) {
-        mDispSync->triggerCallback();
-        EXPECT_TRUE(mVSyncEventCallRecorder.waitForCall().has_value());
+        mVSyncDispatch->triggerCallbacks();
+        const auto callbackData = mVSyncEventCallRecorder.waitForCall();
+        ASSERT_TRUE(callbackData.has_value());
+        const auto [when, expectedVSyncTimestamp, deadlineTimestamp] = callbackData.value();
+        EXPECT_EQ(when, expectedVSyncTimestamp - newDuration.count());
     }
+
+    EXPECT_CALL(*mVSyncDispatch, cancel(_)).Times(1);
+    EXPECT_CALL(*mVSyncDispatch, unregisterCallback(_)).Times(1);
 }
 
 } // namespace