Merge "Include Rect.h explictly" into rvc-dev
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index 2307fbf..605c2e8 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -430,6 +430,19 @@
 }
 
 status_t SurfaceComposerClient::Transaction::writeToParcel(Parcel* parcel) const {
+    // If we write the Transaction to a parcel, we want to ensure the Buffers are cached
+    // before crossing the IPC boundary. Otherwise the receiving party will cache the buffers
+    // but is unlikely to use them again as they are owned by the other process.
+    // You may be asking yourself, is this const cast safe? Const cast is safe up
+    // until the point where you try and write to an object that was originally const at which
+    // point we enter undefined behavior. In this case we are safe though, because there are
+    // two possibilities:
+    //    1. The SurfaceComposerClient::Transaction was originally non-const. Safe.
+    //    2. It was originall const! In this case not only was it useless, but it by definition
+    //       contains no composer states and so cacheBuffers will not perform any writes.
+
+    const_cast<SurfaceComposerClient::Transaction*>(this)->cacheBuffers();
+
     parcel->writeUint32(mForceSynchronous);
     parcel->writeUint32(mTransactionNestCount);
     parcel->writeBool(mAnimation);
@@ -507,7 +520,7 @@
 
     mInputWindowCommands.merge(other.mInputWindowCommands);
 
-    mContainsBuffer = other.mContainsBuffer;
+    mContainsBuffer |= other.mContainsBuffer;
     mEarlyWakeup = mEarlyWakeup || other.mEarlyWakeup;
     other.clear();
     return *this;
@@ -547,6 +560,11 @@
         layer_state_t* s = getLayerState(handle);
         if (!(s->what & layer_state_t::eBufferChanged)) {
             continue;
+        } else if (s->what & layer_state_t::eCachedBufferChanged) {
+            // If eBufferChanged and eCachedBufferChanged are both trued then that means
+            // we already cached the buffer in a previous call to cacheBuffers, perhaps
+            // from writeToParcel on a Transaction that was merged in to this one.
+            continue;
         }
 
         // Don't try to cache a null buffer. Sending null buffers is cheap so we shouldn't waste
diff --git a/libs/renderengine/gl/GLESRenderEngine.cpp b/libs/renderengine/gl/GLESRenderEngine.cpp
index d56a82f..36a54a7 100644
--- a/libs/renderengine/gl/GLESRenderEngine.cpp
+++ b/libs/renderengine/gl/GLESRenderEngine.cpp
@@ -793,35 +793,66 @@
     // top rectangle and the bottom rectangle, and turn off blending for the middle rectangle.
     FloatRect bounds = layer.geometry.roundedCornersCrop;
 
-    // Firstly, we need to convert the coordination from layer native coordination space to
-    // device coordination space.
-    // TODO(143929254): Verify that this transformation is correct
-    const auto transformMatrix = display.globalTransform * layer.geometry.positionTransform;
-    const vec4 leftTopCoordinate(bounds.left, bounds.top, 1.0, 1.0);
-    const vec4 rightBottomCoordinate(bounds.right, bounds.bottom, 1.0, 1.0);
-    const vec4 leftTopCoordinateInBuffer = transformMatrix * leftTopCoordinate;
-    const vec4 rightBottomCoordinateInBuffer = transformMatrix * rightBottomCoordinate;
-    bounds = FloatRect(leftTopCoordinateInBuffer[0], leftTopCoordinateInBuffer[1],
-                       rightBottomCoordinateInBuffer[0], rightBottomCoordinateInBuffer[1]);
-
-    // Secondly, if the display is rotated, we need to undo the rotation on coordination and
-    // align the (left, top) and (right, bottom) coordination with the device coordination
-    // space.
+    // Explicitly compute the transform from the clip rectangle to the physical
+    // display. Normally, this is done in glViewport but we explicitly compute
+    // it here so that we can get the scissor bounds correct.
+    const Rect& source = display.clip;
+    const Rect& destination = display.physicalDisplay;
+    // Here we compute the following transform:
+    // 1. Translate the top left corner of the source clip to (0, 0)
+    // 2. Rotate the clip rectangle about the origin in accordance with the
+    // orientation flag
+    // 3. Translate the top left corner back to the origin.
+    // 4. Scale the clip rectangle to the destination rectangle dimensions
+    // 5. Translate the top left corner to the destination rectangle's top left
+    // corner.
+    const mat4 translateSource = mat4::translate(vec4(-source.left, -source.top, 0, 1));
+    mat4 rotation;
+    int displacementX = 0;
+    int displacementY = 0;
+    float destinationWidth = static_cast<float>(destination.getWidth());
+    float destinationHeight = static_cast<float>(destination.getHeight());
+    float sourceWidth = static_cast<float>(source.getWidth());
+    float sourceHeight = static_cast<float>(source.getHeight());
+    const float rot90InRadians = 2.0f * static_cast<float>(M_PI) / 4.0f;
     switch (display.orientation) {
         case ui::Transform::ROT_90:
-            std::swap(bounds.left, bounds.right);
+            rotation = mat4::rotate(rot90InRadians, vec3(0, 0, 1));
+            displacementX = source.getHeight();
+            std::swap(sourceHeight, sourceWidth);
             break;
         case ui::Transform::ROT_180:
-            std::swap(bounds.left, bounds.right);
-            std::swap(bounds.top, bounds.bottom);
+            rotation = mat4::rotate(rot90InRadians * 2.0f, vec3(0, 0, 1));
+            displacementY = source.getHeight();
+            displacementX = source.getWidth();
             break;
         case ui::Transform::ROT_270:
-            std::swap(bounds.top, bounds.bottom);
+            rotation = mat4::rotate(rot90InRadians * 3.0f, vec3(0, 0, 1));
+            displacementY = source.getWidth();
+            std::swap(sourceHeight, sourceWidth);
             break;
         default:
             break;
     }
 
+    const mat4 intermediateTranslation = mat4::translate(vec4(displacementX, displacementY, 0, 1));
+    const mat4 scale = mat4::scale(
+            vec4(destinationWidth / sourceWidth, destinationHeight / sourceHeight, 1, 1));
+    const mat4 translateDestination =
+            mat4::translate(vec4(destination.left, destination.top, 0, 1));
+    const mat4 globalTransform =
+            translateDestination * scale * intermediateTranslation * rotation * translateSource;
+
+    const mat4 transformMatrix = globalTransform * layer.geometry.positionTransform;
+    const vec4 leftTopCoordinate(bounds.left, bounds.top, 1.0, 1.0);
+    const vec4 rightBottomCoordinate(bounds.right, bounds.bottom, 1.0, 1.0);
+    const vec4 leftTopCoordinateInBuffer = transformMatrix * leftTopCoordinate;
+    const vec4 rightBottomCoordinateInBuffer = transformMatrix * rightBottomCoordinate;
+    bounds = FloatRect(std::min(leftTopCoordinateInBuffer[0], rightBottomCoordinateInBuffer[0]),
+                       std::min(leftTopCoordinateInBuffer[1], rightBottomCoordinateInBuffer[1]),
+                       std::max(leftTopCoordinateInBuffer[0], rightBottomCoordinateInBuffer[0]),
+                       std::max(leftTopCoordinateInBuffer[1], rightBottomCoordinateInBuffer[1]));
+
     // Finally, we cut the layer into 3 parts, with top and bottom parts having rounded corners
     // and the middle part without rounded corners.
     const int32_t radius = ceil(layer.geometry.roundedCornersRadius);
diff --git a/libs/renderengine/include/renderengine/DisplaySettings.h b/libs/renderengine/include/renderengine/DisplaySettings.h
index c0766ab..ca16d2c 100644
--- a/libs/renderengine/include/renderengine/DisplaySettings.h
+++ b/libs/renderengine/include/renderengine/DisplaySettings.h
@@ -40,16 +40,6 @@
     // z=1.
     Rect clip = Rect::INVALID_RECT;
 
-    // Global transform to apply to all layers.
-    // The global transform is assumed to automatically apply when projecting
-    // the clip rectangle onto the physical display; however, this should be
-    // explicitly provided to perform CPU-side optimizations such as computing
-    // scissor rectangles for rounded corners which require transformation to
-    // the phsical display space.
-    //
-    // This transform is also assumed to include the orientation flag below.
-    mat4 globalTransform = mat4();
-
     // Maximum luminance pulled from the display's HDR capabilities.
     float maxLuminance = 1.0f;
 
@@ -62,9 +52,7 @@
     mat4 colorTransform = mat4();
 
     // Region that will be cleared to (0, 0, 0, 1) prior to rendering.
-    // RenderEngine will transform the clearRegion passed in here, by
-    // globalTransform, so that it will be in the same coordinate space as the
-    // rendered layers.
+    // This is specified in layer-stack space.
     Region clearRegion = Region::INVALID_REGION;
 
     // An additional orientation flag to be applied after clipping the output.
@@ -76,8 +64,7 @@
 
 static inline bool operator==(const DisplaySettings& lhs, const DisplaySettings& rhs) {
     return lhs.physicalDisplay == rhs.physicalDisplay && lhs.clip == rhs.clip &&
-            lhs.globalTransform == rhs.globalTransform && lhs.maxLuminance == rhs.maxLuminance &&
-            lhs.outputDataspace == rhs.outputDataspace &&
+            lhs.maxLuminance == rhs.maxLuminance && lhs.outputDataspace == rhs.outputDataspace &&
             lhs.colorTransform == rhs.colorTransform &&
             lhs.clearRegion.hasSameRects(rhs.clearRegion) && lhs.orientation == rhs.orientation;
 }
@@ -89,7 +76,6 @@
     PrintTo(settings.physicalDisplay, os);
     *os << "\n    .clip = ";
     PrintTo(settings.clip, os);
-    *os << "\n    .globalTransform = " << settings.globalTransform;
     *os << "\n    .maxLuminance = " << settings.maxLuminance;
     *os << "\n    .outputDataspace = ";
     PrintTo(settings.outputDataspace, os);
diff --git a/libs/renderengine/tests/RenderEngineTest.cpp b/libs/renderengine/tests/RenderEngineTest.cpp
index ce9131d..f5bf014 100644
--- a/libs/renderengine/tests/RenderEngineTest.cpp
+++ b/libs/renderengine/tests/RenderEngineTest.cpp
@@ -924,7 +924,6 @@
     settings.physicalDisplay = fullscreenRect();
     // Here logical space is 4x4
     settings.clip = Rect(4, 4);
-    settings.globalTransform = mat4::scale(vec4(2, 4, 0, 1));
     settings.clearRegion = Region(Rect(2, 4));
     std::vector<const renderengine::LayerSettings*> layers;
     // dummy layer, without bounds should not render anything
diff --git a/libs/ui/Gralloc4.cpp b/libs/ui/Gralloc4.cpp
index d8e4059..f799ce4 100644
--- a/libs/ui/Gralloc4.cpp
+++ b/libs/ui/Gralloc4.cpp
@@ -203,7 +203,7 @@
     std::vector<ui::PlaneLayout> planeLayouts;
     status_t err = getPlaneLayouts(bufferHandle, &planeLayouts);
 
-    if (err != NO_ERROR && !planeLayouts.empty()) {
+    if (err == NO_ERROR && !planeLayouts.empty()) {
         if (outBytesPerPixel) {
             int32_t bitsPerPixel = planeLayouts.front().sampleIncrementInBits;
             for (const auto& planeLayout : planeLayouts) {
diff --git a/services/surfaceflinger/CompositionEngine/src/Display.cpp b/services/surfaceflinger/CompositionEngine/src/Display.cpp
index c345405..308ec5a 100644
--- a/services/surfaceflinger/CompositionEngine/src/Display.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/Display.cpp
@@ -268,12 +268,9 @@
 }
 
 bool Display::getSkipColorTransform() const {
-    if (!mId) {
-        return false;
-    }
-
-    auto& hwc = getCompositionEngine().getHwComposer();
-    return hwc.hasDisplayCapability(*mId, HWC2::DisplayCapability::SkipClientColorTransform);
+    const auto& hwc = getCompositionEngine().getHwComposer();
+    return mId ? hwc.hasDisplayCapability(*mId, HWC2::DisplayCapability::SkipClientColorTransform)
+               : hwc.hasCapability(HWC2::Capability::SkipClientColorTransform);
 }
 
 bool Display::anyLayersRequireClientComposition() const {
diff --git a/services/surfaceflinger/CompositionEngine/src/Output.cpp b/services/surfaceflinger/CompositionEngine/src/Output.cpp
index 248933e..34d0cb2 100644
--- a/services/surfaceflinger/CompositionEngine/src/Output.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/Output.cpp
@@ -829,7 +829,6 @@
     renderengine::DisplaySettings clientCompositionDisplay;
     clientCompositionDisplay.physicalDisplay = outputState.destinationClip;
     clientCompositionDisplay.clip = outputState.sourceClip;
-    clientCompositionDisplay.globalTransform = outputState.transform.asMatrix4();
     clientCompositionDisplay.orientation = outputState.orientation;
     clientCompositionDisplay.outputDataspace = mDisplayColorProfile->hasWideColorGamut()
             ? outputState.dataspace
diff --git a/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp b/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp
index 88f2686..f73a6f7 100644
--- a/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp
@@ -681,15 +681,17 @@
 
 using DisplayGetSkipColorTransformTest = DisplayWithLayersTestCommon;
 
-TEST_F(DisplayGetSkipColorTransformTest, doesNothingIfNonHwcDisplay) {
+TEST_F(DisplayGetSkipColorTransformTest, checksCapabilityIfNonHwcDisplay) {
+    EXPECT_CALL(mHwComposer, hasCapability(HWC2::Capability::SkipClientColorTransform))
+            .WillOnce(Return(true));
     auto args = getDisplayCreationArgsForNonHWCVirtualDisplay();
     auto nonHwcDisplay{impl::createDisplay(mCompositionEngine, args)};
-    EXPECT_FALSE(nonHwcDisplay->getSkipColorTransform());
+    EXPECT_TRUE(nonHwcDisplay->getSkipColorTransform());
 }
 
-TEST_F(DisplayGetSkipColorTransformTest, checksHwcCapability) {
+TEST_F(DisplayGetSkipColorTransformTest, checksDisplayCapability) {
     EXPECT_CALL(mHwComposer,
-                hasDisplayCapability(std::make_optional(DEFAULT_DISPLAY_ID),
+                hasDisplayCapability(DEFAULT_DISPLAY_ID,
                                      HWC2::DisplayCapability::SkipClientColorTransform))
             .WillOnce(Return(true));
     EXPECT_TRUE(mDisplay->getSkipColorTransform());
diff --git a/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h b/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h
index 88f6649..52bd6a1 100644
--- a/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h
+++ b/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h
@@ -40,8 +40,7 @@
     MOCK_CONST_METHOD3(getDisplayIdentificationData,
                        bool(hwc2_display_t, uint8_t*, DisplayIdentificationData*));
     MOCK_CONST_METHOD1(hasCapability, bool(HWC2::Capability));
-    MOCK_CONST_METHOD2(hasDisplayCapability,
-                       bool(const std::optional<DisplayId>&, HWC2::DisplayCapability));
+    MOCK_CONST_METHOD2(hasDisplayCapability, bool(DisplayId, HWC2::DisplayCapability));
 
     MOCK_METHOD3(allocateVirtualDisplay,
                  std::optional<DisplayId>(uint32_t, uint32_t, ui::PixelFormat*));
diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
index 63bb459..1c9cd9c 100644
--- a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
@@ -3100,9 +3100,8 @@
             .andIfUsesHdr(true)
             .andIfSkipColorTransform(false)
             .thenExpectDisplaySettingsUsed({kDefaultOutputDestinationClip, kDefaultOutputSourceClip,
-                                            mat4(), kDefaultMaxLuminance, kDefaultOutputDataspace,
-                                            mat4(), Region::INVALID_REGION,
-                                            kDefaultOutputOrientation})
+                                            kDefaultMaxLuminance, kDefaultOutputDataspace, mat4(),
+                                            Region::INVALID_REGION, kDefaultOutputOrientation})
             .execute()
             .expectAFenceWasReturned();
 }
@@ -3112,9 +3111,8 @@
             .andIfUsesHdr(false)
             .andIfSkipColorTransform(false)
             .thenExpectDisplaySettingsUsed({kDefaultOutputDestinationClip, kDefaultOutputSourceClip,
-                                            mat4(), kDefaultMaxLuminance, kDefaultOutputDataspace,
-                                            mat4(), Region::INVALID_REGION,
-                                            kDefaultOutputOrientation})
+                                            kDefaultMaxLuminance, kDefaultOutputDataspace, mat4(),
+                                            Region::INVALID_REGION, kDefaultOutputOrientation})
             .execute()
             .expectAFenceWasReturned();
 }
@@ -3124,7 +3122,7 @@
             .andIfUsesHdr(true)
             .andIfSkipColorTransform(false)
             .thenExpectDisplaySettingsUsed({kDefaultOutputDestinationClip, kDefaultOutputSourceClip,
-                                            mat4(), kDefaultMaxLuminance, kDefaultOutputDataspace,
+                                            kDefaultMaxLuminance, kDefaultOutputDataspace,
                                             kDefaultColorTransformMat, Region::INVALID_REGION,
                                             kDefaultOutputOrientation})
             .execute()
@@ -3136,7 +3134,7 @@
             .andIfUsesHdr(false)
             .andIfSkipColorTransform(false)
             .thenExpectDisplaySettingsUsed({kDefaultOutputDestinationClip, kDefaultOutputSourceClip,
-                                            mat4(), kDefaultMaxLuminance, kDefaultOutputDataspace,
+                                            kDefaultMaxLuminance, kDefaultOutputDataspace,
                                             kDefaultColorTransformMat, Region::INVALID_REGION,
                                             kDefaultOutputOrientation})
             .execute()
@@ -3149,9 +3147,8 @@
             .andIfUsesHdr(true)
             .andIfSkipColorTransform(true)
             .thenExpectDisplaySettingsUsed({kDefaultOutputDestinationClip, kDefaultOutputSourceClip,
-                                            mat4(), kDefaultMaxLuminance, kDefaultOutputDataspace,
-                                            mat4(), Region::INVALID_REGION,
-                                            kDefaultOutputOrientation})
+                                            kDefaultMaxLuminance, kDefaultOutputDataspace, mat4(),
+                                            Region::INVALID_REGION, kDefaultOutputOrientation})
             .execute()
             .expectAFenceWasReturned();
 }
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
index 560299a..f30d662 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
@@ -190,17 +190,10 @@
     return mCapabilities.count(capability) > 0;
 }
 
-bool HWComposer::hasDisplayCapability(const std::optional<DisplayId>& displayId,
+bool HWComposer::hasDisplayCapability(DisplayId displayId,
                                       HWC2::DisplayCapability capability) const {
-    if (!displayId) {
-        // Checkout global capabilities for displays without a corresponding HWC display.
-        if (capability == HWC2::DisplayCapability::SkipClientColorTransform) {
-            return hasCapability(HWC2::Capability::SkipClientColorTransform);
-        }
-        return false;
-    }
-    RETURN_IF_INVALID_DISPLAY(*displayId, false);
-    return mDisplayData.at(*displayId).hwcDisplay->getCapabilities().count(capability) > 0;
+    RETURN_IF_INVALID_DISPLAY(displayId, false);
+    return mDisplayData.at(displayId).hwcDisplay->getCapabilities().count(capability) > 0;
 }
 
 std::optional<DisplayIdentificationInfo> HWComposer::onHotplug(hwc2_display_t hwcDisplayId,
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.h b/services/surfaceflinger/DisplayHardware/HWComposer.h
index 3cb40b1..e18419a 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.h
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.h
@@ -70,7 +70,7 @@
                                               DisplayIdentificationData* outData) const = 0;
 
     virtual bool hasCapability(HWC2::Capability capability) const = 0;
-    virtual bool hasDisplayCapability(const std::optional<DisplayId>& displayId,
+    virtual bool hasDisplayCapability(DisplayId displayId,
                                       HWC2::DisplayCapability capability) const = 0;
 
     // Attempts to allocate a virtual display and returns its ID if created on the HWC device.
@@ -234,7 +234,7 @@
                                       DisplayIdentificationData* outData) const override;
 
     bool hasCapability(HWC2::Capability capability) const override;
-    bool hasDisplayCapability(const std::optional<DisplayId>& displayId,
+    bool hasDisplayCapability(DisplayId displayId,
                               HWC2::DisplayCapability capability) const override;
 
     // Attempts to allocate a virtual display and returns its ID if created on the HWC device.
diff --git a/services/surfaceflinger/Scheduler/EventThread.cpp b/services/surfaceflinger/Scheduler/EventThread.cpp
index 0d6a92e..8347650 100644
--- a/services/surfaceflinger/Scheduler/EventThread.cpp
+++ b/services/surfaceflinger/Scheduler/EventThread.cpp
@@ -429,7 +429,13 @@
                     ALOGW("Faking VSYNC due to driver stall for thread %s", mThreadName);
                     std::string debugInfo = "VsyncSource debug info:\n";
                     mVSyncSource->dump(debugInfo);
-                    ALOGW("%s", debugInfo.c_str());
+                    // Log the debug info line-by-line to avoid logcat overflow
+                    auto pos = debugInfo.find('\n');
+                    while (pos != std::string::npos) {
+                        ALOGW("%s", debugInfo.substr(0, pos).c_str());
+                        debugInfo = debugInfo.substr(pos + 1);
+                        pos = debugInfo.find('\n');
+                    }
                 }
 
                 LOG_FATAL_IF(!mVSyncState);
diff --git a/services/surfaceflinger/Scheduler/TimeKeeper.h b/services/surfaceflinger/Scheduler/TimeKeeper.h
index 38f0708..da2195c 100644
--- a/services/surfaceflinger/Scheduler/TimeKeeper.h
+++ b/services/surfaceflinger/Scheduler/TimeKeeper.h
@@ -53,6 +53,8 @@
      */
     virtual void alarmCancel() = 0;
 
+    virtual void dump(std::string& result) const = 0;
+
 protected:
     TimeKeeper(TimeKeeper const&) = delete;
     TimeKeeper& operator=(TimeKeeper const&) = delete;
diff --git a/services/surfaceflinger/Scheduler/Timer.cpp b/services/surfaceflinger/Scheduler/Timer.cpp
index 8f81c2c..7c5058e 100644
--- a/services/surfaceflinger/Scheduler/Timer.cpp
+++ b/services/surfaceflinger/Scheduler/Timer.cpp
@@ -17,6 +17,7 @@
 #undef LOG_TAG
 #define LOG_TAG "SchedulerTimer"
 #define ATRACE_TAG ATRACE_TAG_GRAPHICS
+#include <android-base/stringprintf.h>
 #include <log/log.h>
 #include <sys/epoll.h>
 #include <sys/timerfd.h>
@@ -29,28 +30,53 @@
 #include "Timer.h"
 
 namespace android::scheduler {
+using base::StringAppendF;
 
 static constexpr size_t kReadPipe = 0;
 static constexpr size_t kWritePipe = 1;
 
-Timer::Timer()
-      : mTimerFd(timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC | TFD_NONBLOCK)),
-        mEpollFd(epoll_create1(EPOLL_CLOEXEC)) {
-    if (pipe2(mPipes.data(), O_CLOEXEC | O_NONBLOCK)) {
-        ALOGE("could not create TimerDispatch mPipes");
-    };
-
-    mDispatchThread = std::thread(std::bind(&Timer::dispatch, this));
+Timer::Timer() {
+    reset();
+    mDispatchThread = std::thread([this]() { threadMain(); });
 }
 
 Timer::~Timer() {
     endDispatch();
     mDispatchThread.join();
+    cleanup();
+}
 
-    close(mPipes[kWritePipe]);
-    close(mPipes[kReadPipe]);
-    close(mEpollFd);
-    close(mTimerFd);
+void Timer::reset() {
+    cleanup();
+    mTimerFd = timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC | TFD_NONBLOCK);
+    mEpollFd = epoll_create1(EPOLL_CLOEXEC);
+    if (pipe2(mPipes.data(), O_CLOEXEC | O_NONBLOCK)) {
+        ALOGE("could not create TimerDispatch mPipes");
+        return;
+    };
+    setDebugState(DebugState::Reset);
+}
+
+void Timer::cleanup() {
+    if (mTimerFd != -1) {
+        close(mTimerFd);
+        mTimerFd = -1;
+    }
+
+    if (mEpollFd != -1) {
+        close(mEpollFd);
+        mEpollFd = -1;
+    }
+
+    if (mPipes[kReadPipe] != -1) {
+        close(mPipes[kReadPipe]);
+        mPipes[kReadPipe] = -1;
+    }
+
+    if (mPipes[kWritePipe] != -1) {
+        close(mPipes[kWritePipe]);
+        mPipes[kWritePipe] = -1;
+    }
 }
 
 void Timer::endDispatch() {
@@ -99,7 +125,14 @@
     }
 }
 
-void Timer::dispatch() {
+void Timer::threadMain() {
+    while (dispatch()) {
+        reset();
+    }
+}
+
+bool Timer::dispatch() {
+    setDebugState(DebugState::Running);
     struct sched_param param = {0};
     param.sched_priority = 2;
     if (pthread_setschedparam(pthread_self(), SCHED_FIFO, &param) != 0) {
@@ -116,7 +149,7 @@
     timerEvent.data.u32 = DispatchType::TIMER;
     if (epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mTimerFd, &timerEvent) == -1) {
         ALOGE("Error adding timer fd to epoll dispatch loop");
-        return;
+        return true;
     }
 
     epoll_event terminateEvent;
@@ -124,18 +157,20 @@
     terminateEvent.data.u32 = DispatchType::TERMINATE;
     if (epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mPipes[kReadPipe], &terminateEvent) == -1) {
         ALOGE("Error adding control fd to dispatch loop");
-        return;
+        return true;
     }
 
     uint64_t iteration = 0;
     char const traceNamePrefix[] = "TimerIteration #";
     static constexpr size_t maxlen = arrayLen(traceNamePrefix) + max64print;
     std::array<char, maxlen> str_buffer;
-    auto timing = true;
-    while (timing) {
+
+    while (true) {
+        setDebugState(DebugState::Waiting);
         epoll_event events[DispatchType::MAX_DISPATCH_TYPE];
         int nfds = epoll_wait(mEpollFd, events, DispatchType::MAX_DISPATCH_TYPE, -1);
 
+        setDebugState(DebugState::Running);
         if (ATRACE_ENABLED()) {
             snprintf(str_buffer.data(), str_buffer.size(), "%s%" PRIu64, traceNamePrefix,
                      iteration++);
@@ -144,29 +179,62 @@
 
         if (nfds == -1) {
             if (errno != EINTR) {
-                timing = false;
-                continue;
+                ALOGE("Error waiting on epoll: %s", strerror(errno));
+                return true;
             }
         }
 
         for (auto i = 0; i < nfds; i++) {
             if (events[i].data.u32 == DispatchType::TIMER) {
                 static uint64_t mIgnored = 0;
+                setDebugState(DebugState::Reading);
                 read(mTimerFd, &mIgnored, sizeof(mIgnored));
+                setDebugState(DebugState::Running);
                 std::function<void()> cb;
                 {
                     std::lock_guard<decltype(mMutex)> lk(mMutex);
                     cb = mCallback;
                 }
                 if (cb) {
+                    setDebugState(DebugState::InCallback);
                     cb();
+                    setDebugState(DebugState::Running);
                 }
             }
             if (events[i].data.u32 == DispatchType::TERMINATE) {
-                timing = false;
+                ALOGE("Terminated");
+                setDebugState(DebugState::Running);
+                return false;
             }
         }
     }
 }
 
+void Timer::setDebugState(DebugState state) {
+    std::lock_guard lk(mMutex);
+    mDebugState = state;
+}
+
+const char* Timer::strDebugState(DebugState state) const {
+    switch (state) {
+        case DebugState::Reset:
+            return "Reset";
+        case DebugState::Running:
+            return "Running";
+        case DebugState::Waiting:
+            return "Waiting";
+        case DebugState::Reading:
+            return "Reading";
+        case DebugState::InCallback:
+            return "InCallback";
+        case DebugState::Terminated:
+            return "Terminated";
+    }
+}
+
+void Timer::dump(std::string& result) const {
+    std::lock_guard lk(mMutex);
+    StringAppendF(&result, "\t\tDebugState: %s\n", strDebugState(mDebugState));
+}
+
 } // namespace android::scheduler
diff --git a/services/surfaceflinger/Scheduler/Timer.h b/services/surfaceflinger/Scheduler/Timer.h
index 0ae82c8..a8e2d5a 100644
--- a/services/surfaceflinger/Scheduler/Timer.h
+++ b/services/surfaceflinger/Scheduler/Timer.h
@@ -34,18 +34,27 @@
     //     Most users will want to serialize thes calls so as to be aware of the timer state.
     void alarmIn(std::function<void()> const& cb, nsecs_t fireIn) final;
     void alarmCancel() final;
+    void dump(std::string& result) const final;
 
 private:
-    int const mTimerFd;
-    int const mEpollFd;
-    std::array<int, 2> mPipes;
+    enum class DebugState { Reset, Running, Waiting, Reading, InCallback, Terminated };
+    void reset();
+    void cleanup();
+    void setDebugState(DebugState state) EXCLUDES(mMutex);
+    const char* strDebugState(DebugState state) const;
+
+    int mTimerFd = -1;
+    int mEpollFd = -1;
+    std::array<int, 2> mPipes = {-1, -1};
 
     std::thread mDispatchThread;
-    void dispatch();
+    void threadMain();
+    bool dispatch();
     void endDispatch();
 
-    std::mutex mMutex;
+    mutable std::mutex mMutex;
     std::function<void()> mCallback GUARDED_BY(mMutex);
+    DebugState mDebugState GUARDED_BY(mMutex);
 };
 
 } // namespace android::scheduler
diff --git a/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.cpp b/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.cpp
index 460d4a5..cd15617 100644
--- a/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.cpp
+++ b/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.cpp
@@ -168,6 +168,7 @@
     mIntendedWakeupTime = targetTime;
     mTimeKeeper->alarmIn(std::bind(&VSyncDispatchTimerQueue::timerCallback, this),
                          targetTime - now);
+    mLastTimerSchedule = mTimeKeeper->now();
 }
 
 void VSyncDispatchTimerQueue::rearmTimer(nsecs_t now) {
@@ -226,6 +227,7 @@
     std::vector<Invocation> invocations;
     {
         std::lock_guard<decltype(mMutex)> lk(mMutex);
+        mLastTimerCallback = mTimeKeeper->now();
         for (auto it = mCallbacks.begin(); it != mCallbacks.end(); it++) {
             auto& callback = it->second;
             auto const wakeupTime = callback->wakeupTime();
@@ -322,10 +324,15 @@
 
 void VSyncDispatchTimerQueue::dump(std::string& result) const {
     std::lock_guard<decltype(mMutex)> lk(mMutex);
+    StringAppendF(&result, "\tTimer:\n");
+    mTimeKeeper->dump(result);
     StringAppendF(&result, "\tmTimerSlack: %.2fms mMinVsyncDistance: %.2fms\n", mTimerSlack / 1e6f,
                   mMinVsyncDistance / 1e6f);
     StringAppendF(&result, "\tmIntendedWakeupTime: %.2fms from now\n",
-                  (mIntendedWakeupTime - systemTime()) / 1e6f);
+                  (mIntendedWakeupTime - mTimeKeeper->now()) / 1e6f);
+    StringAppendF(&result, "\tmLastTimerCallback: %.2fms ago mLastTimerSchedule: %.2fms ago\n",
+                  (mTimeKeeper->now() - mLastTimerCallback) / 1e6f,
+                  (mTimeKeeper->now() - mLastTimerSchedule) / 1e6f);
     StringAppendF(&result, "\tCallbacks:\n");
     for (const auto& [token, entry] : mCallbacks) {
         entry->dump(result);
diff --git a/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.h b/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.h
index 390e0c4..26a8ec0 100644
--- a/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.h
+++ b/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.h
@@ -152,6 +152,10 @@
         std::array<char, maxlen> str_buffer;
         void note(std::string_view name, nsecs_t in, nsecs_t vs);
     } mTraceBuffer GUARDED_BY(mMutex);
+
+    // For debugging purposes
+    nsecs_t mLastTimerCallback GUARDED_BY(mMutex) = kInvalidTime;
+    nsecs_t mLastTimerSchedule GUARDED_BY(mMutex) = kInvalidTime;
 };
 
 } // namespace android::scheduler
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index aa0005d..2979322 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -1217,7 +1217,7 @@
               displayToken.get());
         return NAME_NOT_FOUND;
     }
-    *outSupport = getHwComposer().hasDisplayCapability(displayId,
+    *outSupport = getHwComposer().hasDisplayCapability(*displayId,
                                                        HWC2::DisplayCapability::AutoLowLatencyMode);
     return NO_ERROR;
 }
@@ -1488,7 +1488,7 @@
         return NAME_NOT_FOUND;
     }
     *outSupport =
-            getHwComposer().hasDisplayCapability(displayId, HWC2::DisplayCapability::Brightness);
+            getHwComposer().hasDisplayCapability(*displayId, HWC2::DisplayCapability::Brightness);
     return NO_ERROR;
 }
 
@@ -4404,6 +4404,7 @@
                   mDebugDisplayConfigSetByBackdoor ? "yes" : "no");
 
     mScheduler->dump(mAppConnectionHandle, result);
+    mScheduler->getPrimaryDispSync().dump(result);
 }
 
 void SurfaceFlinger::dumpStaticScreenStats(std::string& result) const {
@@ -5755,7 +5756,6 @@
     // buffer bounds.
     clientCompositionDisplay.physicalDisplay = Rect(reqWidth, reqHeight);
     clientCompositionDisplay.clip = sourceCrop;
-    clientCompositionDisplay.globalTransform = mat4();
     clientCompositionDisplay.orientation = rotation;
 
     clientCompositionDisplay.outputDataspace = renderArea.getReqDataSpace();
diff --git a/services/surfaceflinger/SurfaceTracing.cpp b/services/surfaceflinger/SurfaceTracing.cpp
index 0b1251e..f0b895d 100644
--- a/services/surfaceflinger/SurfaceTracing.cpp
+++ b/services/surfaceflinger/SurfaceTracing.cpp
@@ -36,22 +36,21 @@
       : mFlinger(flinger), mSfLock(flinger.mDrawingStateLock) {}
 
 void SurfaceTracing::mainLoop() {
-    addFirstEntry();
-    bool enabled = true;
+    bool enabled = addFirstEntry();
     while (enabled) {
         LayersTraceProto entry = traceWhenNotified();
         enabled = addTraceToBuffer(entry);
     }
 }
 
-void SurfaceTracing::addFirstEntry() {
+bool SurfaceTracing::addFirstEntry() {
     const auto displayDevice = mFlinger.getDefaultDisplayDevice();
     LayersTraceProto entry;
     {
         std::scoped_lock lock(mSfLock);
         entry = traceLayersLocked("tracing.enable", displayDevice);
     }
-    addTraceToBuffer(entry);
+    return addTraceToBuffer(entry);
 }
 
 LayersTraceProto SurfaceTracing::traceWhenNotified() {
diff --git a/services/surfaceflinger/SurfaceTracing.h b/services/surfaceflinger/SurfaceTracing.h
index a00e5d6..e90fc4d 100644
--- a/services/surfaceflinger/SurfaceTracing.h
+++ b/services/surfaceflinger/SurfaceTracing.h
@@ -90,7 +90,7 @@
     };
 
     void mainLoop();
-    void addFirstEntry();
+    bool addFirstEntry();
     LayersTraceProto traceWhenNotified();
     LayersTraceProto traceLayersLocked(const char* where,
                                        const sp<const DisplayDevice>& displayDevice)
diff --git a/services/surfaceflinger/tests/unittests/VSyncDispatchTimerQueueTest.cpp b/services/surfaceflinger/tests/unittests/VSyncDispatchTimerQueueTest.cpp
index 3543361..1899bed 100644
--- a/services/surfaceflinger/tests/unittests/VSyncDispatchTimerQueueTest.cpp
+++ b/services/surfaceflinger/tests/unittests/VSyncDispatchTimerQueueTest.cpp
@@ -71,6 +71,7 @@
     MOCK_CONST_METHOD0(now, nsecs_t());
     MOCK_METHOD2(alarmIn, void(std::function<void()> const&, nsecs_t time));
     MOCK_METHOD0(alarmCancel, void());
+    MOCK_CONST_METHOD1(dump, void(std::string&));
 
     void alarmInDefaultBehavior(std::function<void()> const& callback, nsecs_t time) {
         mCallback = callback;
@@ -188,6 +189,7 @@
             }
             void alarmCancel() final { mControllableClock.alarmCancel(); }
             nsecs_t now() const final { return mControllableClock.now(); }
+            void dump(std::string&) const final {}
 
         private:
             TimeKeeper& mControllableClock;