SF: enable high refresh rate virtual mode

Add support for SF backdoor to set a multiplier
and divisor on the period for VSYNC-sf and
VSYNC-app from the primary DispSync object.

Bug: 111549030
Test: enable high refresh rate in devOptions and
view with systrace

Change-Id: I4226d5791d8d7ddeae1ad96577713c9c2141ed58
diff --git a/services/surfaceflinger/DispSync.cpp b/services/surfaceflinger/DispSync.cpp
index cdfbba3..b789d04 100644
--- a/services/surfaceflinger/DispSync.cpp
+++ b/services/surfaceflinger/DispSync.cpp
@@ -515,12 +515,26 @@
 
 void DispSync::setPeriod(nsecs_t period) {
     Mutex::Autolock lock(mMutex);
-    mPeriod = period;
+    mPeriodBase = mPeriod = period;
     mPhase = 0;
     mReferenceTime = 0;
     mThread->updateModel(mPeriod, mPhase, mReferenceTime);
 }
 
+void DispSync::scalePeriod(uint32_t multiplier, uint32_t divisor) {
+    Mutex::Autolock lock(mMutex);
+
+    // if only 1 of the properties is updated, we will get to this
+    // point "attempting" to set the scale to 1 when it is already
+    // 1.  Check that special case so that we don't do a useless
+    // update of the model.
+    if ((multiplier == 1) && (divisor == 1) && (mPeriod == mPeriodBase))
+        return;
+
+    mPeriod = mPeriodBase * multiplier / divisor;
+    mThread->updateModel(mPeriod, mPhase, mReferenceTime);
+}
+
 nsecs_t DispSync::getPeriod() {
     // lock mutex as mPeriod changes multiple times in updateModelLocked
     Mutex::Autolock lock(mMutex);
@@ -545,7 +559,7 @@
 
         // Exclude the min and max from the average
         durationSum -= minDuration + maxDuration;
-        mPeriod = durationSum / (mNumResyncSamples - 3);
+        mPeriodBase = mPeriod = durationSum / (mNumResyncSamples - 3);
 
         ALOGV("[%s] mPeriod = %" PRId64, mName, ns2us(mPeriod));
 
diff --git a/services/surfaceflinger/DispSync.h b/services/surfaceflinger/DispSync.h
index 1be131f..183966f 100644
--- a/services/surfaceflinger/DispSync.h
+++ b/services/surfaceflinger/DispSync.h
@@ -48,6 +48,7 @@
     virtual bool addResyncSample(nsecs_t timestamp) = 0;
     virtual void endResync() = 0;
     virtual void setPeriod(nsecs_t period) = 0;
+    virtual void scalePeriod(const uint32_t multiplier, uint32_t divisor) = 0;
     virtual nsecs_t getPeriod() = 0;
     virtual void setRefreshSkipCount(int count) = 0;
     virtual status_t addEventListener(const char* name, nsecs_t phase, Callback* callback) = 0;
@@ -117,6 +118,12 @@
     // turned on.  It should NOT be used after that.
     void setPeriod(nsecs_t period) override;
 
+    // The scalePeriod method applies the multiplier and divisor to
+    // scale the vsync event model's period.   The function is added
+    // for an experimental test mode and should not be used outside
+    // of that purpose.
+    void scalePeriod(const uint32_t multiplier, uint32_t divisor);
+
     // The getPeriod method returns the current vsync period.
     nsecs_t getPeriod() override;
 
@@ -176,6 +183,7 @@
     // mPeriod is the computed period of the modeled vsync events in
     // nanoseconds.
     nsecs_t mPeriod;
+    nsecs_t mPeriodBase;
 
     // mPhase is the phase offset of the modeled vsync events.  It is the
     // number of nanoseconds from time 0 to the first vsync event.
diff --git a/services/surfaceflinger/DisplayHardware/HWC2.h b/services/surfaceflinger/DisplayHardware/HWC2.h
index 900b3d7..e0d6ecc 100644
--- a/services/surfaceflinger/DisplayHardware/HWC2.h
+++ b/services/surfaceflinger/DisplayHardware/HWC2.h
@@ -23,6 +23,7 @@
 #undef HWC2_INCLUDE_STRINGIFICATION
 #undef HWC2_USE_CPP11
 
+#include <cutils/properties.h>
 #include <gui/HdrMetadata.h>
 #include <math/mat4.h>
 #include <ui/GraphicTypes.h>
@@ -160,6 +161,8 @@
             }
             Builder& setVsyncPeriod(int32_t vsyncPeriod) {
                 mConfig->mVsyncPeriod = vsyncPeriod;
+                mConfig->mPeriodMultiplier = 1;
+                mConfig->mPeriodDivisor = 1;
                 return *this;
             }
             Builder& setDpiX(int32_t dpiX) {
@@ -189,7 +192,12 @@
 
         int32_t getWidth() const { return mWidth; }
         int32_t getHeight() const { return mHeight; }
-        nsecs_t getVsyncPeriod() const { return mVsyncPeriod; }
+        nsecs_t getVsyncPeriod() const {
+            return mVsyncPeriod * mPeriodMultiplier / mPeriodDivisor; }
+        void scalePanelFrequency(int32_t multiplier, int32_t divisor) const {
+            mPeriodMultiplier = multiplier;
+            mPeriodDivisor = divisor;
+        }
         float getDpiX() const { return mDpiX; }
         float getDpiY() const { return mDpiY; }
 
@@ -202,6 +210,8 @@
         int32_t mWidth;
         int32_t mHeight;
         nsecs_t mVsyncPeriod;
+        mutable int32_t mPeriodMultiplier;
+        mutable int32_t mPeriodDivisor;
         float mDpiX;
         float mDpiY;
     };
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 31e4444..1c12bd5 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -4855,6 +4855,33 @@
                 reply->writeBool(getBE().mHwc->isUsingVrComposer());
                 return NO_ERROR;
             }
+            case 1029: {
+                // Code 1029 is an experimental feature that allows applications to
+                // simulate a high frequency panel by setting a multiplier and divisor
+                // on the VSYNC-sf clock.  If either the multiplier or divisor are
+                // 0, then the code will set both to 1 to return the VSYNC-sf clock
+                // to it's normal frequency.
+                int multiplier = data.readInt32();
+                int divisor = data.readInt32();
+
+                if ((multiplier == 0) || (divisor == 0)) {
+                    multiplier = 1;
+                    divisor = 1;
+                }
+
+                if ((multiplier == 1) && (divisor == 1)) {
+                    enableHardwareVsync();
+                } else {
+                    disableHardwareVsync(true);
+                }
+                getBE().mHwc->getActiveConfig(DisplayDevice::DISPLAY_PRIMARY)
+                    ->scalePanelFrequency(multiplier, divisor);
+                mPrimaryDispSync->scalePeriod(multiplier, divisor);
+
+                ATRACE_INT("PeriodMultiplier", multiplier);
+                ATRACE_INT("PeriodDivisor", divisor);
+                return NO_ERROR;
+            }
         }
     }
     return err;
diff --git a/services/surfaceflinger/tests/unittests/mock/MockDispSync.h b/services/surfaceflinger/tests/unittests/mock/MockDispSync.h
index 4a466ef..cd8d943 100644
--- a/services/surfaceflinger/tests/unittests/mock/MockDispSync.h
+++ b/services/surfaceflinger/tests/unittests/mock/MockDispSync.h
@@ -35,6 +35,7 @@
     MOCK_METHOD1(addResyncSample, bool(nsecs_t));
     MOCK_METHOD0(endResync, void());
     MOCK_METHOD1(setPeriod, void(nsecs_t));
+    MOCK_METHOD2(scalePeriod, void(uint32_t, uint32_t));
     MOCK_METHOD0(getPeriod, nsecs_t());
     MOCK_METHOD1(setRefreshSkipCount, void(int));
     MOCK_METHOD3(addEventListener, status_t(const char*, nsecs_t, Callback*));