[SurfaceFlinger] fix permanently enabling early offsets.

* Add notion of intended period in DispSync, and use that to detect
whether the simulated period will be changed.
* Propagate that signal to setDesiredActiveConfig, so that we don't fall
into early offsets unnecessarily, which can cause early offsets to
always be enabled.

Bug: 132678707
Test: systrace
Test: swappy test app
Test: scrolling through google news
Change-Id: I18df1b9d949cd534ecbf1c8891b6f88eab8be399
diff --git a/services/surfaceflinger/Scheduler/DispSync.cpp b/services/surfaceflinger/Scheduler/DispSync.cpp
index cd6fa41..f7a30af 100644
--- a/services/surfaceflinger/Scheduler/DispSync.cpp
+++ b/services/surfaceflinger/Scheduler/DispSync.cpp
@@ -115,11 +115,13 @@
     void lockModel() {
         Mutex::Autolock lock(mMutex);
         mModelLocked = true;
+        ATRACE_INT("DispSync:ModelLocked", mModelLocked);
     }
 
     void unlockModel() {
         Mutex::Autolock lock(mMutex);
         mModelLocked = false;
+        ATRACE_INT("DispSync:ModelLocked", mModelLocked);
     }
 
     virtual bool threadLoop() {
@@ -493,7 +495,6 @@
         ALOGE("Couldn't set SCHED_FIFO for DispSyncThread");
     }
 
-    reset();
     beginResync();
 
     if (mTraceDetailedInfo && kEnableZeroPhaseTracer) {
@@ -545,17 +546,15 @@
 void DispSync::beginResync() {
     Mutex::Autolock lock(mMutex);
     ALOGV("[%s] beginResync", mName);
-    mThread->unlockModel();
-    mModelUpdated = false;
-    mNumResyncSamples = 0;
+    resetLocked();
 }
 
-bool DispSync::addResyncSample(nsecs_t timestamp, bool* periodChanged) {
+bool DispSync::addResyncSample(nsecs_t timestamp, bool* periodFlushed) {
     Mutex::Autolock lock(mMutex);
 
     ALOGV("[%s] addResyncSample(%" PRId64 ")", mName, ns2us(timestamp));
 
-    *periodChanged = false;
+    *periodFlushed = false;
     const size_t idx = (mFirstResyncSample + mNumResyncSamples) % MAX_RESYNC_SAMPLES;
     mResyncSamples[idx] = timestamp;
     if (mNumResyncSamples == 0) {
@@ -569,16 +568,20 @@
         const nsecs_t lastTimestamp = mResyncSamples[priorIdx];
 
         const nsecs_t observedVsync = std::abs(timestamp - lastTimestamp);
-        if (std::abs(observedVsync - mPendingPeriod) < std::abs(observedVsync - mPeriod)) {
-            // Observed vsync is closer to the pending period, so reset the
-            // model and flush the pending period.
+        if (std::abs(observedVsync - mPendingPeriod) <= std::abs(observedVsync - mIntendedPeriod)) {
+            // Either the observed vsync is closer to the pending period, (and
+            // thus we detected a period change), or the period change will
+            // no-op. In either case, reset the model and flush the pending
+            // period.
             resetLocked();
+            mIntendedPeriod = mPendingPeriod;
             mPeriod = mPendingPeriod;
             mPendingPeriod = 0;
             if (mTraceDetailedInfo) {
                 ATRACE_INT("DispSync:PendingPeriod", mPendingPeriod);
+                ATRACE_INT("DispSync:IntendedPeriod", mIntendedPeriod);
             }
-            *periodChanged = true;
+            *periodFlushed = true;
         }
     }
     // Always update the reference time with the most recent timestamp.
@@ -609,6 +612,7 @@
     bool modelLocked = mModelUpdated && mError < (kErrorThreshold / 2) && mPendingPeriod == 0;
     ALOGV("[%s] addResyncSample returning %s", mName, modelLocked ? "locked" : "unlocked");
     if (modelLocked) {
+        *periodFlushed = true;
         mThread->lockModel();
     }
     return !modelLocked;
@@ -643,10 +647,17 @@
 
 void DispSync::setPeriod(nsecs_t period) {
     Mutex::Autolock lock(mMutex);
-    if (mTraceDetailedInfo) {
-        ATRACE_INT("DispSync:PendingPeriod", period);
+
+    const bool pendingPeriodShouldChange =
+            period != mIntendedPeriod || (period == mIntendedPeriod && mPendingPeriod != 0);
+
+    if (pendingPeriodShouldChange) {
+        mPendingPeriod = period;
     }
-    mPendingPeriod = period;
+    if (mTraceDetailedInfo) {
+        ATRACE_INT("DispSync:IntendedPeriod", mIntendedPeriod);
+        ATRACE_INT("DispSync:PendingPeriod", mPendingPeriod);
+    }
 }
 
 nsecs_t DispSync::getPeriod() {
@@ -764,6 +775,9 @@
     mPresentSampleOffset = 0;
     mError = 0;
     mZeroErrSamplesCount = 0;
+    if (mTraceDetailedInfo) {
+        ATRACE_INT64("DispSync:Error", mError);
+    }
     for (size_t i = 0; i < NUM_PRESENT_SAMPLES; i++) {
         mPresentFences[i] = FenceTime::NO_FENCE;
     }
diff --git a/services/surfaceflinger/Scheduler/DispSync.h b/services/surfaceflinger/Scheduler/DispSync.h
index 8f8b8e7..3e33c7e 100644
--- a/services/surfaceflinger/Scheduler/DispSync.h
+++ b/services/surfaceflinger/Scheduler/DispSync.h
@@ -49,7 +49,7 @@
     virtual void reset() = 0;
     virtual bool addPresentFence(const std::shared_ptr<FenceTime>&) = 0;
     virtual void beginResync() = 0;
-    virtual bool addResyncSample(nsecs_t timestamp, bool* periodChanged) = 0;
+    virtual bool addResyncSample(nsecs_t timestamp, bool* periodFlushed) = 0;
     virtual void endResync() = 0;
     virtual void setPeriod(nsecs_t period) = 0;
     virtual nsecs_t getPeriod() = 0;
@@ -120,17 +120,19 @@
     // from the hardware vsync events.
     void beginResync() override;
     // Adds a vsync sample to the dispsync model. The timestamp is the time
-    // of the vsync event that fired. periodChanged will return true if the
+    // of the vsync event that fired. periodFlushed will return true if the
     // vsync period was detected to have changed to mPendingPeriod.
     //
     // This method will return true if more vsync samples are needed to lock
     // down the DispSync model, and false otherwise.
-    bool addResyncSample(nsecs_t timestamp, bool* periodChanged) override;
+    // periodFlushed will be set to true if mPendingPeriod is flushed to
+    // mIntendedPeriod, and false otherwise.
+    bool addResyncSample(nsecs_t timestamp, bool* periodFlushed) override;
     void endResync() override;
 
     // The setPeriod method sets the vsync event model's period to a specific
-    // value.  This should be used to prime the model when a display is first
-    // turned on.  It should NOT be used after that.
+    // value. This should be used to prime the model when a display is first
+    // turned on, or when a refresh rate change is requested.
     void setPeriod(nsecs_t period) override;
 
     // The getPeriod method returns the current vsync period.
@@ -205,6 +207,11 @@
     // nanoseconds.
     nsecs_t mPeriod;
 
+    // mIntendedPeriod is the intended period of the modeled vsync events in
+    // nanoseconds. Under ideal conditions this should be similar if not the
+    // same as mPeriod, plus or minus an observed error.
+    nsecs_t mIntendedPeriod = 0;
+
     // mPendingPeriod is the proposed period change in nanoseconds.
     // If mPendingPeriod differs from mPeriod and is nonzero, it will
     // be flushed to mPeriod when we detect that the hardware switched
@@ -236,8 +243,8 @@
     // process to store information about the hardware vsync event times used
     // to compute the model.
     nsecs_t mResyncSamples[MAX_RESYNC_SAMPLES] = {0};
-    size_t mFirstResyncSample;
-    size_t mNumResyncSamples;
+    size_t mFirstResyncSample = 0;
+    size_t mNumResyncSamples = 0;
     int mNumResyncSamplesSincePresent;
 
     // These member variables store information about the present fences used
diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp
index 513436a..e2a348e 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.cpp
+++ b/services/surfaceflinger/Scheduler/Scheduler.cpp
@@ -280,13 +280,13 @@
     }
 }
 
-void Scheduler::addResyncSample(const nsecs_t timestamp, bool* periodChanged) {
+void Scheduler::addResyncSample(const nsecs_t timestamp, bool* periodFlushed) {
     bool needsHwVsync = false;
-    *periodChanged = false;
+    *periodFlushed = false;
     { // Scope for the lock
         std::lock_guard<std::mutex> lock(mHWVsyncLock);
         if (mPrimaryHWVsyncEnabled) {
-            needsHwVsync = mPrimaryDispSync->addResyncSample(timestamp, periodChanged);
+            needsHwVsync = mPrimaryDispSync->addResyncSample(timestamp, periodFlushed);
         }
     }
 
@@ -415,7 +415,7 @@
     ATRACE_INT("ExpiredKernelIdleTimer", 0);
     std::lock_guard<std::mutex> lock(mCallbackLock);
     if (mGetVsyncPeriod) {
-        resyncToHardwareVsync(false, mGetVsyncPeriod());
+        resyncToHardwareVsync(true, mGetVsyncPeriod());
     }
 }
 
diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h
index 96d4bd5..f6cc87b 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.h
+++ b/services/surfaceflinger/Scheduler/Scheduler.h
@@ -135,13 +135,18 @@
 
     void enableHardwareVsync();
     void disableHardwareVsync(bool makeUnavailable);
+    // Resyncs the scheduler to hardware vsync.
+    // If makeAvailable is true, then hardware vsync will be turned on.
+    // Otherwise, if hardware vsync is not already enabled then this method will
+    // no-op.
+    // The period is the vsync period from the current display configuration.
     void resyncToHardwareVsync(bool makeAvailable, nsecs_t period);
     // Creates a callback for resyncing.
     ResyncCallback makeResyncCallback(GetVsyncPeriod&& getVsyncPeriod);
     void setRefreshSkipCount(int count);
-    // Passes a vsync sample to DispSync. periodChange will be true if DipSync
-    // detected that the vsync period changed, and false otherwise.
-    void addResyncSample(const nsecs_t timestamp, bool* periodChanged);
+    // Passes a vsync sample to DispSync. periodFlushed will be true if
+    // DispSync detected that the vsync period changed, and false otherwise.
+    void addResyncSample(const nsecs_t timestamp, bool* periodFlushed);
     void addPresentFence(const std::shared_ptr<FenceTime>& fenceTime);
     void setIgnorePresentFences(bool ignore);
     nsecs_t expectedPresentTime();
diff --git a/services/surfaceflinger/Scheduler/VSyncModulator.h b/services/surfaceflinger/Scheduler/VSyncModulator.h
index 81a7864..21dad12 100644
--- a/services/surfaceflinger/Scheduler/VSyncModulator.h
+++ b/services/surfaceflinger/Scheduler/VSyncModulator.h
@@ -116,7 +116,7 @@
 
     // Called when we detect from vsync signals that the refresh rate changed.
     // This way we can move out of early offsets if no longer necessary.
-    void onRefreshRateChangeDetected() {
+    void onRefreshRateChangeCompleted() {
         if (!mRefreshRateChangePending) {
             return;
         }