[SurfaceFlinger] Add vsync offset information to systrace.

* Trace offset values in DispSyncSource
* Trace offset type in VSyncModulator
* Refactor how offsets are stored so that refresh rate type can be
encoded in VSyncModulator
* Add locking to catch a potential race condition when updating offsets,
as phase offsets can be accessed or updated on multiple threads.

Bug: 133325345
Test: verified that correct offsets are reported in systrace
Change-Id: I38d43b722cd54728a2e4de3df7dd472aceb1de15
diff --git a/services/surfaceflinger/Scheduler/DispSyncSource.cpp b/services/surfaceflinger/Scheduler/DispSyncSource.cpp
index 265b8aa..026b557 100644
--- a/services/surfaceflinger/Scheduler/DispSyncSource.cpp
+++ b/services/surfaceflinger/Scheduler/DispSyncSource.cpp
@@ -34,6 +34,8 @@
         mTraceVsync(traceVsync),
         mVsyncOnLabel(base::StringPrintf("VsyncOn-%s", name)),
         mVsyncEventLabel(base::StringPrintf("VSYNC-%s", name)),
+        mVsyncOffsetLabel(base::StringPrintf("VsyncOffset-%s", name)),
+        mVsyncNegativeOffsetLabel(base::StringPrintf("VsyncNegativeOffset-%s", name)),
         mDispSync(dispSync),
         mPhaseOffset(phaseOffset),
         mOffsetThresholdForNextVsync(offsetThresholdForNextVsync) {}
@@ -41,6 +43,7 @@
 void DispSyncSource::setVSyncEnabled(bool enable) {
     std::lock_guard lock(mVsyncMutex);
     if (enable) {
+        tracePhaseOffset();
         status_t err = mDispSync->addEventListener(mName, mPhaseOffset,
                                                    static_cast<DispSync::Callback*>(this),
                                                    mLastCallbackTime);
@@ -76,6 +79,7 @@
     const int numPeriods = phaseOffset / period;
     phaseOffset -= numPeriods * period;
     mPhaseOffset = phaseOffset;
+    tracePhaseOffset();
 
     // If we're not enabled, we don't need to mess with the listeners
     if (!mEnabled) {
@@ -94,11 +98,11 @@
     {
         std::lock_guard lock(mCallbackMutex);
         callback = mCallback;
+    }
 
-        if (mTraceVsync) {
-            mValue = (mValue + 1) % 2;
-            ATRACE_INT(mVsyncEventLabel.c_str(), mValue);
-        }
+    if (mTraceVsync) {
+        mValue = (mValue + 1) % 2;
+        ATRACE_INT(mVsyncEventLabel.c_str(), mValue);
     }
 
     if (callback != nullptr) {
@@ -106,4 +110,14 @@
     }
 }
 
-} // namespace android
\ No newline at end of file
+void DispSyncSource::tracePhaseOffset() {
+    if (mPhaseOffset > 0) {
+        ATRACE_INT(mVsyncOffsetLabel.c_str(), mPhaseOffset);
+        ATRACE_INT(mVsyncNegativeOffsetLabel.c_str(), 0);
+    } else {
+        ATRACE_INT(mVsyncOffsetLabel.c_str(), 0);
+        ATRACE_INT(mVsyncNegativeOffsetLabel.c_str(), -mPhaseOffset);
+    }
+}
+
+} // namespace android
diff --git a/services/surfaceflinger/Scheduler/DispSyncSource.h b/services/surfaceflinger/Scheduler/DispSyncSource.h
index b6785c5..50560a5 100644
--- a/services/surfaceflinger/Scheduler/DispSyncSource.h
+++ b/services/surfaceflinger/Scheduler/DispSyncSource.h
@@ -39,12 +39,16 @@
     // The following method is the implementation of the DispSync::Callback.
     virtual void onDispSyncEvent(nsecs_t when);
 
+    void tracePhaseOffset() REQUIRES(mVsyncMutex);
+
     const char* const mName;
     int mValue = 0;
 
     const bool mTraceVsync;
     const std::string mVsyncOnLabel;
     const std::string mVsyncEventLabel;
+    const std::string mVsyncOffsetLabel;
+    const std::string mVsyncNegativeOffsetLabel;
     nsecs_t mLastCallbackTime GUARDED_BY(mVsyncMutex) = 0;
 
     DispSync* mDispSync;
@@ -58,4 +62,4 @@
     bool mEnabled GUARDED_BY(mVsyncMutex) = false;
 };
 
-} // namespace android
\ No newline at end of file
+} // namespace android
diff --git a/services/surfaceflinger/Scheduler/PhaseOffsets.cpp b/services/surfaceflinger/Scheduler/PhaseOffsets.cpp
index 276bce1..8a2604f 100644
--- a/services/surfaceflinger/Scheduler/PhaseOffsets.cpp
+++ b/services/surfaceflinger/Scheduler/PhaseOffsets.cpp
@@ -25,6 +25,7 @@
 
 namespace scheduler {
 
+using RefreshRateType = RefreshRateConfigs::RefreshRateType;
 PhaseOffsets::~PhaseOffsets() = default;
 
 namespace impl {
@@ -72,25 +73,32 @@
     property_get("debug.sf.phase_offset_threshold_for_next_vsync_ns", value, "-1");
     const int phaseOffsetThresholdForNextVsyncNs = atoi(value);
 
-    mDefaultRefreshRateOffsets.early = {earlySfOffsetNs != -1 ? earlySfOffsetNs
-                                                              : sfVsyncPhaseOffsetNs,
-                                        earlyAppOffsetNs != -1 ? earlyAppOffsetNs
-                                                               : vsyncPhaseOffsetNs};
-    mDefaultRefreshRateOffsets.earlyGl = {earlyGlSfOffsetNs != -1 ? earlyGlSfOffsetNs
-                                                                  : sfVsyncPhaseOffsetNs,
-                                          earlyGlAppOffsetNs != -1 ? earlyGlAppOffsetNs
-                                                                   : vsyncPhaseOffsetNs};
-    mDefaultRefreshRateOffsets.late = {sfVsyncPhaseOffsetNs, vsyncPhaseOffsetNs};
+    Offsets defaultOffsets;
+    Offsets highFpsOffsets;
+    defaultOffsets.early = {RefreshRateType::DEFAULT,
+                            earlySfOffsetNs != -1 ? earlySfOffsetNs : sfVsyncPhaseOffsetNs,
+                            earlyAppOffsetNs != -1 ? earlyAppOffsetNs : vsyncPhaseOffsetNs};
+    defaultOffsets.earlyGl = {RefreshRateType::DEFAULT,
+                              earlyGlSfOffsetNs != -1 ? earlyGlSfOffsetNs : sfVsyncPhaseOffsetNs,
+                              earlyGlAppOffsetNs != -1 ? earlyGlAppOffsetNs : vsyncPhaseOffsetNs};
+    defaultOffsets.late = {RefreshRateType::DEFAULT, sfVsyncPhaseOffsetNs, vsyncPhaseOffsetNs};
 
-    mHighRefreshRateOffsets.early = {highFpsEarlySfOffsetNs != -1 ? highFpsEarlySfOffsetNs
-                                                                  : highFpsLateSfOffsetNs,
-                                     highFpsEarlyAppOffsetNs != -1 ? highFpsEarlyAppOffsetNs
-                                                                   : highFpsLateAppOffsetNs};
-    mHighRefreshRateOffsets.earlyGl = {highFpsEarlyGlSfOffsetNs != -1 ? highFpsEarlyGlSfOffsetNs
-                                                                      : highFpsLateSfOffsetNs,
-                                       highFpsEarlyGlAppOffsetNs != -1 ? highFpsEarlyGlAppOffsetNs
-                                                                       : highFpsLateAppOffsetNs};
-    mHighRefreshRateOffsets.late = {highFpsLateSfOffsetNs, highFpsLateAppOffsetNs};
+    highFpsOffsets.early = {RefreshRateType::PERFORMANCE,
+                            highFpsEarlySfOffsetNs != -1 ? highFpsEarlySfOffsetNs
+                                                         : highFpsLateSfOffsetNs,
+                            highFpsEarlyAppOffsetNs != -1 ? highFpsEarlyAppOffsetNs
+                                                          : highFpsLateAppOffsetNs};
+    highFpsOffsets.earlyGl = {RefreshRateType::PERFORMANCE,
+                              highFpsEarlyGlSfOffsetNs != -1 ? highFpsEarlyGlSfOffsetNs
+                                                             : highFpsLateSfOffsetNs,
+                              highFpsEarlyGlAppOffsetNs != -1 ? highFpsEarlyGlAppOffsetNs
+                                                              : highFpsLateAppOffsetNs};
+    highFpsOffsets.late = {RefreshRateType::PERFORMANCE, highFpsLateSfOffsetNs,
+                           highFpsLateAppOffsetNs};
+
+    mOffsets.insert({RefreshRateType::POWER_SAVING, defaultOffsets});
+    mOffsets.insert({RefreshRateType::DEFAULT, defaultOffsets});
+    mOffsets.insert({RefreshRateType::PERFORMANCE, highFpsOffsets});
 
     mOffsetThresholdForNextVsync = phaseOffsetThresholdForNextVsyncNs != -1
             ? phaseOffsetThresholdForNextVsyncNs
@@ -99,12 +107,7 @@
 
 PhaseOffsets::Offsets PhaseOffsets::getOffsetsForRefreshRate(
         android::scheduler::RefreshRateConfigs::RefreshRateType refreshRateType) const {
-    switch (refreshRateType) {
-        case RefreshRateConfigs::RefreshRateType::PERFORMANCE:
-            return mHighRefreshRateOffsets;
-        default:
-            return mDefaultRefreshRateOffsets;
-    }
+    return mOffsets.at(refreshRateType);
 }
 
 void PhaseOffsets::dump(std::string& result) const {
diff --git a/services/surfaceflinger/Scheduler/PhaseOffsets.h b/services/surfaceflinger/Scheduler/PhaseOffsets.h
index dc71e6e..2b5c2f1 100644
--- a/services/surfaceflinger/Scheduler/PhaseOffsets.h
+++ b/services/surfaceflinger/Scheduler/PhaseOffsets.h
@@ -17,6 +17,7 @@
 #pragma once
 
 #include <cinttypes>
+#include <unordered_map>
 
 #include "RefreshRateConfigs.h"
 #include "VSyncModulator.h"
@@ -79,14 +80,10 @@
     void dump(std::string& result) const override;
 
 private:
-    Offsets getDefaultRefreshRateOffsets() { return mDefaultRefreshRateOffsets; }
-    Offsets getHighRefreshRateOffsets() { return mHighRefreshRateOffsets; }
-
     std::atomic<RefreshRateConfigs::RefreshRateType> mRefreshRateType =
             RefreshRateConfigs::RefreshRateType::DEFAULT;
 
-    Offsets mDefaultRefreshRateOffsets;
-    Offsets mHighRefreshRateOffsets;
+    std::unordered_map<RefreshRateConfigs::RefreshRateType, Offsets> mOffsets;
     nsecs_t mOffsetThresholdForNextVsync;
 };
 } // namespace impl
diff --git a/services/surfaceflinger/Scheduler/VSyncModulator.cpp b/services/surfaceflinger/Scheduler/VSyncModulator.cpp
index af8f445..381308a 100644
--- a/services/surfaceflinger/Scheduler/VSyncModulator.cpp
+++ b/services/surfaceflinger/Scheduler/VSyncModulator.cpp
@@ -14,28 +14,36 @@
  * limitations under the License.
  */
 
+#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+
 #include "VSyncModulator.h"
 
+#include <cutils/properties.h>
+#include <utils/Trace.h>
+
 #include <cinttypes>
 #include <mutex>
 
 namespace android {
 
+using RefreshRateType = scheduler::RefreshRateConfigs::RefreshRateType;
+VSyncModulator::VSyncModulator() {
+    char value[PROPERTY_VALUE_MAX];
+    property_get("debug.sf.vsync_trace_detailed_info", value, "0");
+    mTraceDetailedInfo = atoi(value);
+    // Populate the offset map with some default offsets.
+    const Offsets defaultOffsets = {RefreshRateType::DEFAULT, 0, 0};
+    setPhaseOffsets(defaultOffsets, defaultOffsets, defaultOffsets, 0);
+}
+
 void VSyncModulator::setPhaseOffsets(Offsets early, Offsets earlyGl, Offsets late,
                                      nsecs_t thresholdForNextVsync) {
-    mEarlyOffsets = early;
-    mEarlyGlOffsets = earlyGl;
-    mLateOffsets = late;
+    std::lock_guard<std::mutex> lock(mMutex);
+    mOffsetMap.insert_or_assign(OffsetType::Early, early);
+    mOffsetMap.insert_or_assign(OffsetType::EarlyGl, earlyGl);
+    mOffsetMap.insert_or_assign(OffsetType::Late, late);
     mThresholdForNextVsync = thresholdForNextVsync;
-
-    if (mSfConnectionHandle && late.sf != mOffsets.load().sf) {
-        mScheduler->setPhaseOffset(mSfConnectionHandle, late.sf);
-    }
-
-    if (mAppConnectionHandle && late.app != mOffsets.load().app) {
-        mScheduler->setPhaseOffset(mAppConnectionHandle, late.app);
-    }
-    mOffsets = late;
+    updateOffsetsLocked();
 }
 
 void VSyncModulator::setTransactionStart(Scheduler::TransactionStart transactionStart) {
@@ -93,21 +101,35 @@
 }
 
 VSyncModulator::Offsets VSyncModulator::getOffsets() {
+    std::lock_guard<std::mutex> lock(mMutex);
+    return mOffsetMap.at(mOffsetType);
+}
+
+VSyncModulator::Offsets VSyncModulator::getNextOffsets() {
+    return mOffsetMap.at(getNextOffsetType());
+}
+
+VSyncModulator::OffsetType VSyncModulator::getNextOffsetType() {
     // 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) {
-        return mEarlyOffsets;
+        return OffsetType::Early;
     } else if (mRemainingRenderEngineUsageCount > 0) {
-        return mEarlyGlOffsets;
+        return OffsetType::EarlyGl;
     } else {
-        return mLateOffsets;
+        return OffsetType::Late;
     }
 }
 
 void VSyncModulator::updateOffsets() {
-    const Offsets desired = getOffsets();
-    const Offsets current = mOffsets;
+    std::lock_guard<std::mutex> lock(mMutex);
+    updateOffsetsLocked();
+}
+
+void VSyncModulator::updateOffsetsLocked() {
+    const Offsets desired = getNextOffsets();
+    const Offsets current = mOffsetMap.at(mOffsetType);
 
     bool changed = false;
     if (desired.sf != current.sf) {
@@ -128,8 +150,29 @@
     }
 
     if (changed) {
-        mOffsets = desired;
+        updateOffsetType();
     }
 }
 
+void VSyncModulator::updateOffsetType() {
+    mOffsetType = getNextOffsetType();
+    if (!mTraceDetailedInfo) {
+        return;
+    }
+    OffsetType type = mOffsetType;
+    Offsets offsets = mOffsetMap.at(type);
+    ATRACE_INT("Vsync-EarlyOffsetsOn",
+               offsets.fpsMode == RefreshRateType::DEFAULT && type == OffsetType::Early);
+    ATRACE_INT("Vsync-EarlyGLOffsetsOn",
+               offsets.fpsMode == RefreshRateType::DEFAULT && type == OffsetType::EarlyGl);
+    ATRACE_INT("Vsync-LateOffsetsOn",
+               offsets.fpsMode == RefreshRateType::DEFAULT && type == OffsetType::Late);
+    ATRACE_INT("Vsync-HighFpsEarlyOffsetsOn",
+               offsets.fpsMode == RefreshRateType::PERFORMANCE && type == OffsetType::Early);
+    ATRACE_INT("Vsync-HighFpsEarlyGLOffsetsOn",
+               offsets.fpsMode == RefreshRateType::PERFORMANCE && type == OffsetType::EarlyGl);
+    ATRACE_INT("Vsync-HighFpsLateOffsetsOn",
+               offsets.fpsMode == RefreshRateType::PERFORMANCE && type == OffsetType::Late);
+}
+
 } // namespace android
diff --git a/services/surfaceflinger/Scheduler/VSyncModulator.h b/services/surfaceflinger/Scheduler/VSyncModulator.h
index 677862e..c6374be 100644
--- a/services/surfaceflinger/Scheduler/VSyncModulator.h
+++ b/services/surfaceflinger/Scheduler/VSyncModulator.h
@@ -39,13 +39,22 @@
     const int MIN_EARLY_GL_FRAME_COUNT_TRANSACTION = 2;
 
 public:
+    VSyncModulator();
+
     // Wrapper for a collection of surfaceflinger/app offsets for a particular
     // configuration .
     struct Offsets {
+        scheduler::RefreshRateConfigs::RefreshRateType fpsMode;
         nsecs_t sf;
         nsecs_t app;
     };
 
+    enum class OffsetType {
+        Early,
+        EarlyGl,
+        Late,
+    };
+
     // Sets the phase offsets
     //
     // sfEarly: The phase offset when waking up SF early, which happens when marking a transaction
@@ -57,13 +66,7 @@
     // appEarlyGl: Like sfEarlyGl, but for the app-vsync.
     // appLate: The regular app vsync phase offset.
     void setPhaseOffsets(Offsets early, Offsets earlyGl, Offsets late,
-                         nsecs_t thresholdForNextVsync);
-
-    // Returns the configured early offsets.
-    Offsets getEarlyOffsets() const { return mEarlyOffsets; }
-
-    // Returns the configured early gl offsets.
-    Offsets getEarlyGlOffsets() const { return mEarlyGlOffsets; }
+                         nsecs_t thresholdForNextVsync) EXCLUDES(mMutex);
 
     // Sets handles to the SF and app event threads.
     void setEventThreads(EventThread* sfEventThread, EventThread* appEventThread) {
@@ -100,15 +103,22 @@
     // frame.
     void onRefreshed(bool usedRenderEngine);
 
-    // Returns the offsets that should be used.
-    Offsets getOffsets();
+    // Returns the offsets that we are currently using
+    Offsets getOffsets() EXCLUDES(mMutex);
 
 private:
-    void updateOffsets();
+    // Returns the next offsets that we should be using
+    Offsets getNextOffsets() REQUIRES(mMutex);
+    // Returns the next offset type that we should use.
+    OffsetType getNextOffsetType();
+    // Updates offsets and persists them into the scheduler framework.
+    void updateOffsets() EXCLUDES(mMutex);
+    void updateOffsetsLocked() REQUIRES(mMutex);
+    // Updates the internal offset type.
+    void updateOffsetType() REQUIRES(mMutex);
 
-    Offsets mLateOffsets;
-    Offsets mEarlyOffsets;
-    Offsets mEarlyGlOffsets;
+    mutable std::mutex mMutex;
+    std::unordered_map<OffsetType, Offsets> mOffsetMap GUARDED_BY(mMutex);
     nsecs_t mThresholdForNextVsync;
 
     EventThread* mSfEventThread = nullptr;
@@ -118,13 +128,15 @@
     Scheduler::ConnectionHandle* mAppConnectionHandle = nullptr;
     Scheduler::ConnectionHandle* mSfConnectionHandle = nullptr;
 
-    std::atomic<Offsets> mOffsets;
+    OffsetType mOffsetType GUARDED_BY(mMutex) = OffsetType::Late;
 
     std::atomic<Scheduler::TransactionStart> mTransactionStart =
             Scheduler::TransactionStart::NORMAL;
     std::atomic<bool> mRefreshRateChangePending = false;
     std::atomic<int> mRemainingEarlyFrameCount = 0;
     std::atomic<int> mRemainingRenderEngineUsageCount = 0;
+
+    bool mTraceDetailedInfo = false;
 };
 
 } // namespace android
diff --git a/services/surfaceflinger/tests/unittests/FakePhaseOffsets.h b/services/surfaceflinger/tests/unittests/FakePhaseOffsets.h
index 96121bb..1d75011 100644
--- a/services/surfaceflinger/tests/unittests/FakePhaseOffsets.h
+++ b/services/surfaceflinger/tests/unittests/FakePhaseOffsets.h
@@ -23,6 +23,8 @@
 namespace android {
 namespace scheduler {
 
+using RefreshRateType = RefreshRateConfigs::RefreshRateType;
+
 class FakePhaseOffsets : public android::scheduler::PhaseOffsets {
     nsecs_t FAKE_PHASE_OFFSET_NS = 0;
 
@@ -34,20 +36,20 @@
     nsecs_t getCurrentSfOffset() override { return FAKE_PHASE_OFFSET_NS; }
 
     PhaseOffsets::Offsets getOffsetsForRefreshRate(
-            RefreshRateConfigs::RefreshRateType /*refreshRateType*/) const override {
+            RefreshRateType /*refreshRateType*/) const override {
         return getCurrentOffsets();
     }
 
     // Returns early, early GL, and late offsets for Apps and SF.
     PhaseOffsets::Offsets getCurrentOffsets() const override {
-        return Offsets{{FAKE_PHASE_OFFSET_NS, FAKE_PHASE_OFFSET_NS},
-                       {FAKE_PHASE_OFFSET_NS, FAKE_PHASE_OFFSET_NS},
-                       {FAKE_PHASE_OFFSET_NS, FAKE_PHASE_OFFSET_NS}};
+        return Offsets{{RefreshRateType::DEFAULT, FAKE_PHASE_OFFSET_NS, FAKE_PHASE_OFFSET_NS},
+                       {RefreshRateType::DEFAULT, FAKE_PHASE_OFFSET_NS, FAKE_PHASE_OFFSET_NS},
+                       {RefreshRateType::DEFAULT, FAKE_PHASE_OFFSET_NS, FAKE_PHASE_OFFSET_NS}};
     }
 
     // This function should be called when the device is switching between different
     // refresh rates, to properly update the offsets.
-    void setRefreshRateType(RefreshRateConfigs::RefreshRateType /*refreshRateType*/) override {}
+    void setRefreshRateType(RefreshRateType /*refreshRateType*/) override {}
 
     nsecs_t getOffsetThresholdForNextVsync() const override { return FAKE_PHASE_OFFSET_NS; }
 
@@ -56,4 +58,4 @@
 };
 
 } // namespace scheduler
-} // namespace android
\ No newline at end of file
+} // namespace android