SF: VSyncTracker, clear timestamps on beginResync

DispSync would clear its internal model around power events, as the
vsync timings during power mode changes are not accurate for screen-on
vsync prediction. DispSync uses the beginResync signal for this, and the
new system does the same (although once DispSync is deprecated,
begin/endResync should go away too).

Fixes: 146050690
Test: Dogfooding blueline
Test: 2 new unit tests
Change-Id: Ie4b607029516dcea0e5d65afca75a7017bf63e12
diff --git a/services/surfaceflinger/Scheduler/VSyncPredictor.cpp b/services/surfaceflinger/Scheduler/VSyncPredictor.cpp
index 3b99a58..68d58f0 100644
--- a/services/surfaceflinger/Scheduler/VSyncPredictor.cpp
+++ b/services/surfaceflinger/Scheduler/VSyncPredictor.cpp
@@ -38,7 +38,7 @@
         kMinimumSamplesForPrediction(minimumSamplesForPrediction),
         kOutlierTolerancePercent(std::min(outlierTolerancePercent, kMaxPercent)),
         mIdealPeriod(idealPeriod) {
-    mRateMap[mIdealPeriod] = {idealPeriod, 0};
+    resetModel();
 }
 
 inline size_t VSyncPredictor::next(int i) const {
@@ -199,6 +199,10 @@
         mRateMap[mIdealPeriod] = {period, 0};
     }
 
+    clearTimestamps();
+}
+
+void VSyncPredictor::clearTimestamps() {
     if (!timestamps.empty()) {
         mKnownTimestamp = *std::max_element(timestamps.begin(), timestamps.end());
         timestamps.clear();
@@ -223,4 +227,10 @@
     return needsMoreSamples;
 }
 
+void VSyncPredictor::resetModel() {
+    std::lock_guard<std::mutex> lk(mMutex);
+    mRateMap[mIdealPeriod] = {mIdealPeriod, 0};
+    clearTimestamps();
+}
+
 } // namespace android::scheduler
diff --git a/services/surfaceflinger/Scheduler/VSyncPredictor.h b/services/surfaceflinger/Scheduler/VSyncPredictor.h
index 4210b3c..41e5469 100644
--- a/services/surfaceflinger/Scheduler/VSyncPredictor.h
+++ b/services/surfaceflinger/Scheduler/VSyncPredictor.h
@@ -40,6 +40,7 @@
     void addVsyncTimestamp(nsecs_t timestamp) final;
     nsecs_t nextAnticipatedVSyncTimeFrom(nsecs_t timePoint) const final;
     nsecs_t currentPeriod() const final;
+    void resetModel() final;
 
     /*
      * Inform the model that the period is anticipated to change to a new value.
@@ -48,7 +49,7 @@
      *
      * \param [in] period   The new period that should be used.
      */
-    void setPeriod(nsecs_t period);
+    void setPeriod(nsecs_t period) final;
 
     /* Query if the model is in need of more samples to make a prediction at timePoint.
      * \param [in] timePoint    The timePoint to inquire of.
@@ -61,6 +62,7 @@
 private:
     VSyncPredictor(VSyncPredictor const&) = delete;
     VSyncPredictor& operator=(VSyncPredictor const&) = delete;
+    void clearTimestamps() REQUIRES(mMutex);
 
     size_t const kHistorySize;
     size_t const kMinimumSamplesForPrediction;
diff --git a/services/surfaceflinger/Scheduler/VSyncReactor.cpp b/services/surfaceflinger/Scheduler/VSyncReactor.cpp
index a652053..57e05d3 100644
--- a/services/surfaceflinger/Scheduler/VSyncReactor.cpp
+++ b/services/surfaceflinger/Scheduler/VSyncReactor.cpp
@@ -185,7 +185,9 @@
     return mTracker->currentPeriod();
 }
 
-void VSyncReactor::beginResync() {}
+void VSyncReactor::beginResync() {
+    mTracker->resetModel();
+}
 
 void VSyncReactor::endResync() {}
 
diff --git a/services/surfaceflinger/Scheduler/VSyncTracker.h b/services/surfaceflinger/Scheduler/VSyncTracker.h
index 6be63fe..2b27884 100644
--- a/services/surfaceflinger/Scheduler/VSyncTracker.h
+++ b/services/surfaceflinger/Scheduler/VSyncTracker.h
@@ -61,6 +61,9 @@
      */
     virtual void setPeriod(nsecs_t period) = 0;
 
+    /* Inform the tracker that the samples it has are not accurate for prediction. */
+    virtual void resetModel() = 0;
+
 protected:
     VSyncTracker(VSyncTracker const&) = delete;
     VSyncTracker& operator=(VSyncTracker const&) = delete;
diff --git a/services/surfaceflinger/tests/unittests/VSyncDispatchRealtimeTest.cpp b/services/surfaceflinger/tests/unittests/VSyncDispatchRealtimeTest.cpp
index 5846c77..9c3d32e 100644
--- a/services/surfaceflinger/tests/unittests/VSyncDispatchRealtimeTest.cpp
+++ b/services/surfaceflinger/tests/unittests/VSyncDispatchRealtimeTest.cpp
@@ -50,6 +50,7 @@
     nsecs_t currentPeriod() const final { return mPeriod; }
 
     void setPeriod(nsecs_t) final {}
+    void resetModel() final {}
 
 private:
     nsecs_t const mPeriod;
@@ -83,6 +84,7 @@
     }
 
     void setPeriod(nsecs_t) final {}
+    void resetModel() final {}
 
 private:
     std::mutex mutable mMutex;
diff --git a/services/surfaceflinger/tests/unittests/VSyncDispatchTimerQueueTest.cpp b/services/surfaceflinger/tests/unittests/VSyncDispatchTimerQueueTest.cpp
index 5aff429..b23159b 100644
--- a/services/surfaceflinger/tests/unittests/VSyncDispatchTimerQueueTest.cpp
+++ b/services/surfaceflinger/tests/unittests/VSyncDispatchTimerQueueTest.cpp
@@ -41,6 +41,7 @@
     MOCK_CONST_METHOD1(nextAnticipatedVSyncTimeFrom, nsecs_t(nsecs_t));
     MOCK_CONST_METHOD0(currentPeriod, nsecs_t());
     MOCK_METHOD1(setPeriod, void(nsecs_t));
+    MOCK_METHOD0(resetModel, void());
 
     nsecs_t nextVSyncTime(nsecs_t timePoint) const {
         if (timePoint % mPeriod == 0) {
diff --git a/services/surfaceflinger/tests/unittests/VSyncPredictorTest.cpp b/services/surfaceflinger/tests/unittests/VSyncPredictorTest.cpp
index 4cb6a38..afa1481 100644
--- a/services/surfaceflinger/tests/unittests/VSyncPredictorTest.cpp
+++ b/services/surfaceflinger/tests/unittests/VSyncPredictorTest.cpp
@@ -351,4 +351,19 @@
     EXPECT_THAT(prediction, Ge(timePoint));
 }
 
+TEST_F(VSyncPredictorTest, resetsWhenInstructed) {
+    auto const idealPeriod = 10000;
+    auto const realPeriod = 10500;
+    tracker.setPeriod(idealPeriod);
+    for (auto i = 0; i < kMinimumSamplesForPrediction; i++) {
+        tracker.addVsyncTimestamp(i * realPeriod);
+    }
+
+    EXPECT_THAT(std::get<0>(tracker.getVSyncPredictionModel()),
+                IsCloseTo(realPeriod, mMaxRoundingError));
+    tracker.resetModel();
+    EXPECT_THAT(std::get<0>(tracker.getVSyncPredictionModel()),
+                IsCloseTo(idealPeriod, mMaxRoundingError));
+}
+
 } // namespace android::scheduler
diff --git a/services/surfaceflinger/tests/unittests/VSyncReactorTest.cpp b/services/surfaceflinger/tests/unittests/VSyncReactorTest.cpp
index 72f8bb9..d5e0660 100644
--- a/services/surfaceflinger/tests/unittests/VSyncReactorTest.cpp
+++ b/services/surfaceflinger/tests/unittests/VSyncReactorTest.cpp
@@ -39,6 +39,7 @@
     MOCK_CONST_METHOD1(nextAnticipatedVSyncTimeFrom, nsecs_t(nsecs_t));
     MOCK_CONST_METHOD0(currentPeriod, nsecs_t());
     MOCK_METHOD1(setPeriod, void(nsecs_t));
+    MOCK_METHOD0(resetModel, void());
 };
 
 class VSyncTrackerWrapper : public VSyncTracker {
@@ -50,7 +51,8 @@
         return mTracker->nextAnticipatedVSyncTimeFrom(timePoint);
     }
     nsecs_t currentPeriod() const final { return mTracker->currentPeriod(); }
-    void setPeriod(nsecs_t period) { mTracker->setPeriod(period); }
+    void setPeriod(nsecs_t period) final { mTracker->setPeriod(period); }
+    void resetModel() final { mTracker->resetModel(); }
 
 private:
     std::shared_ptr<VSyncTracker> const mTracker;
@@ -515,6 +517,11 @@
     mReactor.addEventListener(mName, negativePhase, &outerCb, lastCallbackTime);
 }
 
+TEST_F(VSyncReactorTest, beginResyncResetsModel) {
+    EXPECT_CALL(*mMockTracker, resetModel());
+    mReactor.beginResync();
+}
+
 using VSyncReactorDeathTest = VSyncReactorTest;
 TEST_F(VSyncReactorDeathTest, invalidRemoval) {
     mReactor.addEventListener(mName, mPhase, &outerCb, lastCallbackTime);