SurfaceFlinger: add explicit eEarlyWakeup start and end

The current handling of eEarlyWakeup is using 2 frames of timeout
in SurfaceFlinger to know when we are no longer in early offset config.
There are few cases where a transaction is dropped or delayed (usually
caused by the offset change itself) which results in switching back
and forth from early offset to non-early offset. This change adds two
new flags, eExplicitEarlyWakeupStart and eExplicitEarlyWakeupEnd that
will be used by WindowManager to indicate when to enter early offset
and when to exit. With these explicit flags, the timings on transaction
no longer matters and we consistently stay at early offset config for the desired
duration.

Bug: 158127834
Test: Quick switch between apps and verify that offset doesn't change
Test: adb shell /data/nativetest64/libsurfaceflinger_unittest/libsurfaceflinger_unittest
Change-Id: Ie10af30a2d8c0f4f21ac7ffed469a74e1bf8dbc1
diff --git a/services/surfaceflinger/Scheduler/VSyncModulator.cpp b/services/surfaceflinger/Scheduler/VSyncModulator.cpp
index 510dc2d..2567c04 100644
--- a/services/surfaceflinger/Scheduler/VSyncModulator.cpp
+++ b/services/surfaceflinger/Scheduler/VSyncModulator.cpp
@@ -31,11 +31,11 @@
 
 namespace android::scheduler {
 
-VSyncModulator::VSyncModulator(Scheduler& scheduler,
+VSyncModulator::VSyncModulator(IPhaseOffsetControl& phaseOffsetControl,
                                Scheduler::ConnectionHandle appConnectionHandle,
                                Scheduler::ConnectionHandle sfConnectionHandle,
                                const OffsetsConfig& config)
-      : mScheduler(scheduler),
+      : mPhaseOffsetControl(phaseOffsetControl),
         mAppConnectionHandle(appConnectionHandle),
         mSfConnectionHandle(sfConnectionHandle),
         mOffsetsConfig(config) {
@@ -51,14 +51,35 @@
 }
 
 void VSyncModulator::setTransactionStart(Scheduler::TransactionStart transactionStart) {
-    if (transactionStart == Scheduler::TransactionStart::EARLY) {
+    switch (transactionStart) {
+        case Scheduler::TransactionStart::EarlyStart:
+            ALOGW_IF(mExplicitEarlyWakeup, "Already in TransactionStart::EarlyStart");
+            mExplicitEarlyWakeup = true;
+            break;
+        case Scheduler::TransactionStart::EarlyEnd:
+            ALOGW_IF(!mExplicitEarlyWakeup, "Not in TransactionStart::EarlyStart");
+            mExplicitEarlyWakeup = false;
+            break;
+        case Scheduler::TransactionStart::Normal:
+        case Scheduler::TransactionStart::Early:
+            // Non explicit don't change the explicit early wakeup state
+            break;
+    }
+
+    if (mTraceDetailedInfo) {
+        ATRACE_INT("mExplicitEarlyWakeup", mExplicitEarlyWakeup);
+    }
+
+    if (!mExplicitEarlyWakeup &&
+        (transactionStart == Scheduler::TransactionStart::Early ||
+         transactionStart == Scheduler::TransactionStart::EarlyEnd)) {
         mRemainingEarlyFrameCount = MIN_EARLY_FRAME_COUNT_TRANSACTION;
         mEarlyTxnStartTime = std::chrono::steady_clock::now();
     }
 
     // An early transaction stays an early transaction.
     if (transactionStart == mTransactionStart ||
-        mTransactionStart == Scheduler::TransactionStart::EARLY) {
+        mTransactionStart == Scheduler::TransactionStart::EarlyEnd) {
         return;
     }
     mTransactionStart = transactionStart;
@@ -67,8 +88,8 @@
 
 void VSyncModulator::onTransactionHandled() {
     mTxnAppliedTime = std::chrono::steady_clock::now();
-    if (mTransactionStart == Scheduler::TransactionStart::NORMAL) return;
-    mTransactionStart = Scheduler::TransactionStart::NORMAL;
+    if (mTransactionStart == Scheduler::TransactionStart::Normal) return;
+    mTransactionStart = Scheduler::TransactionStart::Normal;
     updateOffsets();
 }
 
@@ -91,11 +112,10 @@
 void VSyncModulator::onRefreshed(bool usedRenderEngine) {
     bool updateOffsetsNeeded = false;
 
-    // Apply a 1ms margin to account for potential data races
+    // Apply a margin to account for potential data races
     // This might make us stay in early offsets for one
     // additional frame but it's better to be conservative here.
-    static const constexpr std::chrono::nanoseconds kMargin = 1ms;
-    if ((mEarlyTxnStartTime.load() + kMargin) < mTxnAppliedTime.load()) {
+    if ((mEarlyTxnStartTime.load() + MARGIN_FOR_TX_APPLY) < mTxnAppliedTime.load()) {
         if (mRemainingEarlyFrameCount > 0) {
             mRemainingEarlyFrameCount--;
             updateOffsetsNeeded = true;
@@ -121,8 +141,8 @@
 const VSyncModulator::Offsets& VSyncModulator::getNextOffsets() const {
     // Early offsets are used if we're in the middle of a refresh rate
     // change, or if we recently begin a transaction.
-    if (mTransactionStart == Scheduler::TransactionStart::EARLY || mRemainingEarlyFrameCount > 0 ||
-        mRefreshRateChangePending) {
+    if (mExplicitEarlyWakeup || mTransactionStart == Scheduler::TransactionStart::EarlyEnd ||
+        mRemainingEarlyFrameCount > 0 || mRefreshRateChangePending) {
         return mOffsetsConfig.early;
     } else if (mRemainingRenderEngineUsageCount > 0) {
         return mOffsetsConfig.earlyGl;
@@ -139,8 +159,8 @@
 void VSyncModulator::updateOffsetsLocked() {
     const Offsets& offsets = getNextOffsets();
 
-    mScheduler.setPhaseOffset(mSfConnectionHandle, offsets.sf);
-    mScheduler.setPhaseOffset(mAppConnectionHandle, offsets.app);
+    mPhaseOffsetControl.setPhaseOffset(mSfConnectionHandle, offsets.sf);
+    mPhaseOffsetControl.setPhaseOffset(mAppConnectionHandle, offsets.app);
 
     mOffsets = offsets;