Merge "EGL: refactor and enforce clang-format"
diff --git a/cmds/surfacereplayer/proto/src/trace.proto b/cmds/surfacereplayer/proto/src/trace.proto
index b574098..3ada05c 100644
--- a/cmds/surfacereplayer/proto/src/trace.proto
+++ b/cmds/surfacereplayer/proto/src/trace.proto
@@ -25,8 +25,9 @@
     repeated SurfaceChange surface_change = 1;
     repeated DisplayChange display_change = 2;
 
-    required bool synchronous = 3;
-    required bool animation   = 4;
+    required bool   synchronous = 3;
+    required bool   animation   = 4;
+    optional Origin origin      = 5;
 }
 
 message SurfaceChange {
@@ -208,4 +209,9 @@
 
 message ShadowRadiusChange {
     required float radius = 1;
+}
+
+message Origin {
+    required int32 pid = 1;
+    required int32 uid = 2;
 }
\ No newline at end of file
diff --git a/libs/binder/ndk/include_cpp/android/binder_interface_utils.h b/libs/binder/ndk/include_cpp/android/binder_interface_utils.h
index 33e4586..f44ce0c 100644
--- a/libs/binder/ndk/include_cpp/android/binder_interface_utils.h
+++ b/libs/binder/ndk/include_cpp/android/binder_interface_utils.h
@@ -88,13 +88,21 @@
 
     static void operator delete(void* p) { std::free(p); }
 
+    // Once minSdkVersion is 30, we are guaranteed to be building with the
+    // Android 11 AIDL compiler which supports the SharedRefBase::make API.
+    //
+    // Use 'SharedRefBase::make<T>(...)' to make. SharedRefBase has implicit
+    // ownership. Making this operator private to avoid double-ownership.
+#if !defined(__ANDROID_API__) || __ANDROID_API__ >= 30
+   private:
+#else
+    [[deprecated("Prefer SharedRefBase::make<T>(...) if possible.")]]
+#endif
+    static void* operator new(size_t s) { return std::malloc(s); }
+
    private:
     std::once_flag mFlagThis;
     std::weak_ptr<SharedRefBase> mThis;
-
-    // Use 'SharedRefBase::make<T>(...)' to make. SharedRefBase has implicit
-    // ownership. Making this operator private to avoid double-ownership.
-    static void* operator new(size_t s) { return std::malloc(s); }
 };
 
 /**
diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp
index 7742503..725d3cd 100644
--- a/libs/gui/LayerState.cpp
+++ b/libs/gui/LayerState.cpp
@@ -61,7 +61,7 @@
     output.writeUint32(transform);
     output.writeBool(transformToDisplayInverse);
     output.write(crop);
-    output.write(frame);
+    output.write(orientedDisplaySpaceRect);
     if (buffer) {
         output.writeBool(true);
         output.write(*buffer);
@@ -159,7 +159,7 @@
     transform = input.readUint32();
     transformToDisplayInverse = input.readBool();
     input.read(crop);
-    input.read(frame);
+    input.read(orientedDisplaySpaceRect);
     buffer = new GraphicBuffer();
     if (input.readBool()) {
         input.read(*buffer);
@@ -216,15 +216,13 @@
     return state.read(input);
 }
 
-
-DisplayState::DisplayState() :
-    what(0),
-    layerStack(0),
-    viewport(Rect::EMPTY_RECT),
-    frame(Rect::EMPTY_RECT),
-    width(0),
-    height(0) {
-}
+DisplayState::DisplayState()
+      : what(0),
+        layerStack(0),
+        layerStackSpaceRect(Rect::EMPTY_RECT),
+        orientedDisplaySpaceRect(Rect::EMPTY_RECT),
+        width(0),
+        height(0) {}
 
 status_t DisplayState::write(Parcel& output) const {
     output.writeStrongBinder(token);
@@ -232,8 +230,8 @@
     output.writeUint32(what);
     output.writeUint32(layerStack);
     output.writeUint32(toRotationInt(orientation));
-    output.write(viewport);
-    output.write(frame);
+    output.write(layerStackSpaceRect);
+    output.write(orientedDisplaySpaceRect);
     output.writeUint32(width);
     output.writeUint32(height);
     return NO_ERROR;
@@ -245,8 +243,8 @@
     what = input.readUint32();
     layerStack = input.readUint32();
     orientation = ui::toRotation(input.readUint32());
-    input.read(viewport);
-    input.read(frame);
+    input.read(layerStackSpaceRect);
+    input.read(orientedDisplaySpaceRect);
     width = input.readUint32();
     height = input.readUint32();
     return NO_ERROR;
@@ -264,8 +262,8 @@
     if (other.what & eDisplayProjectionChanged) {
         what |= eDisplayProjectionChanged;
         orientation = other.orientation;
-        viewport = other.viewport;
-        frame = other.frame;
+        layerStackSpaceRect = other.layerStackSpaceRect;
+        orientedDisplaySpaceRect = other.orientedDisplaySpaceRect;
     }
     if (other.what & eDisplaySizeChanged) {
         what |= eDisplaySizeChanged;
@@ -368,7 +366,7 @@
     }
     if (other.what & eFrameChanged) {
         what |= eFrameChanged;
-        frame = other.frame;
+        orientedDisplaySpaceRect = other.orientedDisplaySpaceRect;
     }
     if (other.what & eBufferChanged) {
         what |= eBufferChanged;
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index b51bf1f..62a3c45 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -1137,7 +1137,7 @@
         return *this;
     }
     s->what |= layer_state_t::eFrameChanged;
-    s->frame = frame;
+    s->orientedDisplaySpaceRect = frame;
 
     registerSurfaceControlForCallback(sc);
     return *this;
@@ -1545,8 +1545,8 @@
                                                               const Rect& displayRect) {
     DisplayState& s(getDisplayState(token));
     s.orientation = orientation;
-    s.viewport = layerStackRect;
-    s.frame = displayRect;
+    s.layerStackSpaceRect = layerStackRect;
+    s.orientedDisplaySpaceRect = displayRect;
     s.what |= DisplayState::eDisplayProjectionChanged;
     mForceSynchronous = true; // TODO: do we actually still need this?
 }
diff --git a/libs/gui/include/gui/LayerState.h b/libs/gui/include/gui/LayerState.h
index 6a304ef..187e478 100644
--- a/libs/gui/include/gui/LayerState.h
+++ b/libs/gui/include/gui/LayerState.h
@@ -129,7 +129,7 @@
             transform(0),
             transformToDisplayInverse(false),
             crop(Rect::INVALID_RECT),
-            frame(Rect::INVALID_RECT),
+            orientedDisplaySpaceRect(Rect::INVALID_RECT),
             dataspace(ui::Dataspace::UNKNOWN),
             surfaceDamageRegion(),
             api(-1),
@@ -192,7 +192,7 @@
     uint32_t transform;
     bool transformToDisplayInverse;
     Rect crop;
-    Rect frame;
+    Rect orientedDisplaySpaceRect;
     sp<GraphicBuffer> buffer;
     sp<Fence> acquireFence;
     ui::Dataspace dataspace;
@@ -265,18 +265,18 @@
 
     // These states define how layers are projected onto the physical display.
     //
-    // Layers are first clipped to `viewport'.  They are then translated and
-    // scaled from `viewport' to `frame'.  Finally, they are rotated according
-    // to `orientation', `width', and `height'.
+    // Layers are first clipped to `layerStackSpaceRect'.  They are then translated and
+    // scaled from `layerStackSpaceRect' to `orientedDisplaySpaceRect'.  Finally, they are rotated
+    // according to `orientation', `width', and `height'.
     //
-    // For example, assume viewport is Rect(0, 0, 200, 100), frame is Rect(20,
-    // 10, 420, 210), and the size of the display is WxH.  When orientation is
-    // 0, layers will be scaled by a factor of 2 and translated by (20, 10).
-    // When orientation is 1, layers will be additionally rotated by 90
-    // degrees around the origin clockwise and translated by (W, 0).
+    // For example, assume layerStackSpaceRect is Rect(0, 0, 200, 100), orientedDisplaySpaceRect is
+    // Rect(20, 10, 420, 210), and the size of the display is WxH.  When orientation is 0, layers
+    // will be scaled by a factor of 2 and translated by (20, 10). When orientation is 1, layers
+    // will be additionally rotated by 90 degrees around the origin clockwise and translated by (W,
+    // 0).
     ui::Rotation orientation = ui::ROTATION_0;
-    Rect viewport;
-    Rect frame;
+    Rect layerStackSpaceRect;
+    Rect orientedDisplaySpaceRect;
 
     uint32_t width, height;
 
diff --git a/libs/input/InputTransport.cpp b/libs/input/InputTransport.cpp
index b088ee7..79e15c1 100644
--- a/libs/input/InputTransport.cpp
+++ b/libs/input/InputTransport.cpp
@@ -481,13 +481,13 @@
     }
     if (DEBUG_TRANSPORT_ACTIONS) {
         std::string transformString;
-        transform.dump(transformString, "");
+        transform.dump(transformString, "transform", "        ");
         ALOGD("channel '%s' publisher ~ publishMotionEvent: seq=%u, deviceId=%d, source=0x%x, "
               "displayId=%" PRId32 ", "
               "action=0x%x, actionButton=0x%08x, flags=0x%x, edgeFlags=0x%x, "
               "metaState=0x%x, buttonState=0x%x, classification=%s,"
               "xPrecision=%f, yPrecision=%f, downTime=%" PRId64 ", eventTime=%" PRId64 ", "
-              "pointerCount=%" PRIu32 " transform=%s",
+              "pointerCount=%" PRIu32 " \n%s",
               mChannel->getName().c_str(), seq, deviceId, source, displayId, action, actionButton,
               flags, edgeFlags, metaState, buttonState,
               motionClassificationToString(classification), xPrecision, yPrecision, downTime,
diff --git a/libs/ui/DebugUtils.cpp b/libs/ui/DebugUtils.cpp
index f394635..1f006ce 100644
--- a/libs/ui/DebugUtils.cpp
+++ b/libs/ui/DebugUtils.cpp
@@ -321,10 +321,6 @@
     return std::string("Unknown RenderIntent");
 }
 
-std::string to_string(const android::Rect& rect) {
-    return StringPrintf("(%4d,%4d,%4d,%4d)", rect.left, rect.top, rect.right, rect.bottom);
-}
-
 std::string toString(const android::DeviceProductInfo::ManufactureOrModelDate& date) {
     using ModelYear = android::DeviceProductInfo::ModelYear;
     using ManufactureYear = android::DeviceProductInfo::ManufactureYear;
diff --git a/libs/ui/Rect.cpp b/libs/ui/Rect.cpp
index 13fed3a..a8d6285 100644
--- a/libs/ui/Rect.cpp
+++ b/libs/ui/Rect.cpp
@@ -14,6 +14,7 @@
  * limitations under the License.
  */
 
+#include <android-base/stringprintf.h>
 #include <system/graphics.h>
 #include <ui/Rect.h>
 
@@ -149,4 +150,13 @@
     return result;
 }
 
+std::string to_string(const android::Rect& rect) {
+    return android::base::StringPrintf("Rect(%d, %d, %d, %d)", rect.left, rect.top, rect.right,
+                                       rect.bottom);
+}
+
+void PrintTo(const Rect& rect, ::std::ostream* os) {
+    *os << to_string(rect);
+}
+
 }; // namespace android
diff --git a/libs/ui/Transform.cpp b/libs/ui/Transform.cpp
index 5424a3c..6b1bb40 100644
--- a/libs/ui/Transform.cpp
+++ b/libs/ui/Transform.cpp
@@ -457,7 +457,43 @@
     return m;
 }
 
-void Transform::dump(std::string& out, const char* name) const {
+static std::string rotationToString(const uint32_t rotationFlags) {
+    switch (rotationFlags) {
+        case Transform::ROT_0:
+            return "ROT_0";
+        case Transform::FLIP_H:
+            return "FLIP_H";
+        case Transform::FLIP_V:
+            return "FLIP_V";
+        case Transform::ROT_90:
+            return "ROT_90";
+        case Transform::ROT_180:
+            return "ROT_180";
+        case Transform::ROT_270:
+            return "ROT_270";
+        case Transform::ROT_INVALID:
+        default:
+            return "ROT_INVALID";
+    }
+}
+
+static std::string transformToString(const uint32_t transform) {
+    if (transform == Transform::IDENTITY) {
+        return "IDENTITY";
+    }
+
+    if (transform == Transform::UNKNOWN) {
+        return "UNKNOWN";
+    }
+
+    std::string out;
+    if (transform & Transform::SCALE) out.append("SCALE ");
+    if (transform & Transform::ROTATE) out.append("ROTATE ");
+    if (transform & Transform::TRANSLATE) out.append("TRANSLATE");
+    return out;
+}
+
+void Transform::dump(std::string& out, const char* name, const char* prefix) const {
     using android::base::StringAppendF;
 
     type(); // Ensure the information in mType is up to date
@@ -465,38 +501,29 @@
     const uint32_t type = mType;
     const uint32_t orient = type >> 8;
 
-    StringAppendF(&out, "%s 0x%08x (", name, orient);
+    out += prefix;
+    out += name;
+    out += " ";
 
     if (orient & ROT_INVALID) {
-        out.append("ROT_INVALID ");
-    } else {
-        if (orient & ROT_90) {
-            out.append("ROT_90 ");
-        } else {
-            out.append("ROT_0 ");
-        }
-        if (orient & FLIP_V) out.append("FLIP_V ");
-        if (orient & FLIP_H) out.append("FLIP_H ");
+        StringAppendF(&out, "0x%08x ", orient);
     }
+    out += "(" + rotationToString(orient) + ") ";
 
-    StringAppendF(&out, ") 0x%02x (", type);
-
-    if (!(type & (SCALE | ROTATE | TRANSLATE))) out.append("IDENTITY ");
-    if (type & SCALE) out.append("SCALE ");
-    if (type & ROTATE) out.append("ROTATE ");
-    if (type & TRANSLATE) out.append("TRANSLATE ");
-
-    out.append(")\n");
+    if (type & UNKNOWN) {
+        StringAppendF(&out, "0x%02x ", type);
+    }
+    out += "(" + transformToString(type) + ")\n";
 
     for (size_t i = 0; i < 3; i++) {
-        StringAppendF(&out, "    %.4f  %.4f  %.4f\n", static_cast<double>(mMatrix[0][i]),
+        StringAppendF(&out, "%s    %.4f  %.4f  %.4f\n", prefix, static_cast<double>(mMatrix[0][i]),
                       static_cast<double>(mMatrix[1][i]), static_cast<double>(mMatrix[2][i]));
     }
 }
 
-void Transform::dump(const char* name) const {
+void Transform::dump(const char* name, const char* prefix) const {
     std::string out;
-    dump(out, name);
+    dump(out, name, prefix);
     ALOGD("%s", out.c_str());
 }
 
diff --git a/libs/ui/include/ui/DebugUtils.h b/libs/ui/include/ui/DebugUtils.h
index 4685575..18cd487 100644
--- a/libs/ui/include/ui/DebugUtils.h
+++ b/libs/ui/include/ui/DebugUtils.h
@@ -34,5 +34,4 @@
 std::string decodeColorTransform(android_color_transform colorTransform);
 std::string decodePixelFormat(android::PixelFormat format);
 std::string decodeRenderIntent(android::ui::RenderIntent renderIntent);
-std::string to_string(const android::Rect& rect);
 std::string toString(const android::DeviceProductInfo&);
diff --git a/libs/ui/include/ui/DisplayState.h b/libs/ui/include/ui/DisplayState.h
index 64efc84..70a0d50 100644
--- a/libs/ui/include/ui/DisplayState.h
+++ b/libs/ui/include/ui/DisplayState.h
@@ -32,7 +32,7 @@
 struct DisplayState {
     LayerStack layerStack = NO_LAYER_STACK;
     Rotation orientation = ROTATION_0;
-    Size viewport;
+    Size layerStackSpaceRect;
 };
 
 static_assert(std::is_trivially_copyable_v<DisplayState>);
diff --git a/libs/ui/include/ui/Rect.h b/libs/ui/include/ui/Rect.h
index 2f2229e..6670dc0 100644
--- a/libs/ui/include/ui/Rect.h
+++ b/libs/ui/include/ui/Rect.h
@@ -19,10 +19,10 @@
 
 #include <ostream>
 
+#include <log/log.h>
 #include <utils/Flattenable.h>
 #include <utils/Log.h>
 #include <utils/TypeHelpers.h>
-#include <log/log.h>
 
 #include <ui/FloatRect.h>
 #include <ui/Point.h>
@@ -216,11 +216,10 @@
     }
 };
 
+std::string to_string(const android::Rect& rect);
+
 // Defining PrintTo helps with Google Tests.
-static inline void PrintTo(const Rect& rect, ::std::ostream* os) {
-    *os << "Rect(" << rect.left << ", " << rect.top << ", " << rect.right << ", " << rect.bottom
-        << ")";
-}
+void PrintTo(const Rect& rect, ::std::ostream* os);
 
 ANDROID_BASIC_TYPES_TRAITS(Rect)
 
diff --git a/libs/ui/include/ui/Rotation.h b/libs/ui/include/ui/Rotation.h
index 89008f6..83d431d 100644
--- a/libs/ui/include/ui/Rotation.h
+++ b/libs/ui/include/ui/Rotation.h
@@ -41,6 +41,15 @@
     return toRotation((toRotationInt(lhs) + toRotationInt(rhs)) % N);
 }
 
+constexpr Rotation operator-(Rotation lhs, Rotation rhs) {
+    constexpr auto N = toRotationInt(ROTATION_270) + 1;
+    return toRotation((N + toRotationInt(lhs) - toRotationInt(rhs)) % N);
+}
+
+constexpr Rotation operator-(Rotation rotation) {
+    return ROTATION_0 - rotation;
+}
+
 constexpr const char* toCString(Rotation rotation) {
     switch (rotation) {
         case ROTATION_0:
diff --git a/libs/ui/include/ui/Transform.h b/libs/ui/include/ui/Transform.h
index 2612e82..4c463bf 100644
--- a/libs/ui/include/ui/Transform.h
+++ b/libs/ui/include/ui/Transform.h
@@ -104,8 +104,8 @@
     Transform inverse() const;
 
     // for debugging
-    void dump(std::string& result, const char* name) const;
-    void dump(const char* name) const;
+    void dump(std::string& result, const char* name, const char* prefix = "") const;
+    void dump(const char* name, const char* prefix = "") const;
 
     static RotationFlags toRotationFlags(Rotation);
 
diff --git a/services/inputflinger/Android.bp b/services/inputflinger/Android.bp
index 28cce47..a0de607 100644
--- a/services/inputflinger/Android.bp
+++ b/services/inputflinger/Android.bp
@@ -25,6 +25,9 @@
         "-Wshadow-field-in-constructor-modified",
         "-Wshadow-uncaptured-local",
     ],
+    sanitize: {
+        misc_undefined: ["bounds"],
+    },
 }
 
 /////////////////////////////////////////////////
diff --git a/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp b/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp
index b31980b..f99fffe 100644
--- a/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp
+++ b/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp
@@ -103,7 +103,7 @@
 class FakeInputReceiver {
 public:
     void consumeEvent() {
-        uint32_t consumeSeq;
+        uint32_t consumeSeq = 0;
         InputEvent* event;
 
         std::chrono::time_point start = std::chrono::steady_clock::now();
diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp
index 44f26b0..5d71666 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.cpp
+++ b/services/inputflinger/dispatcher/InputDispatcher.cpp
@@ -4245,7 +4245,7 @@
                                          "ms\n",
                                          windowInfo->ownerPid, windowInfo->ownerUid,
                                          millis(windowInfo->dispatchingTimeout));
-                    windowInfo->transform.dump(dump, INDENT4 "transform=");
+                    windowInfo->transform.dump(dump, "transform", INDENT4);
                 }
             } else {
                 dump += INDENT2 "Windows: <none>\n";
diff --git a/services/inputflinger/dispatcher/InputTarget.cpp b/services/inputflinger/dispatcher/InputTarget.cpp
index f6958d4..d39113b 100644
--- a/services/inputflinger/dispatcher/InputTarget.cpp
+++ b/services/inputflinger/dispatcher/InputTarget.cpp
@@ -74,10 +74,10 @@
 }
 
 std::string InputTarget::getPointerInfoString() const {
-    std::string out;
+    std::string out = "\n";
     if (useDefaultPointerTransform()) {
         const ui::Transform& transform = getDefaultPointerTransform();
-        transform.dump(out, "default");
+        transform.dump(out, "default", "        ");
         return out;
     }
 
@@ -86,9 +86,8 @@
             continue;
         }
 
-        out += "\n";
         const std::string name = "pointerId " + std::to_string(i) + ":";
-        pointerTransforms[i].dump(out, name.c_str());
+        pointerTransforms[i].dump(out, name.c_str(), "        ");
     }
     return out;
 }
diff --git a/services/inputflinger/reader/EventHub.cpp b/services/inputflinger/reader/EventHub.cpp
index cde977f..76b9419 100644
--- a/services/inputflinger/reader/EventHub.cpp
+++ b/services/inputflinger/reader/EventHub.cpp
@@ -187,7 +187,6 @@
 
 EventHub::Device::~Device() {
     close();
-    delete configuration;
 }
 
 void EventHub::Device::close() {
@@ -284,11 +283,14 @@
     if (configurationFile.empty()) {
         ALOGD("No input device configuration file found for device '%s'.", identifier.name.c_str());
     } else {
-        status_t status = PropertyMap::load(String8(configurationFile.c_str()), &configuration);
+        PropertyMap* propertyMap;
+        status_t status = PropertyMap::load(String8(configurationFile.c_str()), &propertyMap);
         if (status) {
             ALOGE("Error loading input device configuration file for device '%s'.  "
                   "Using default configuration.",
                   identifier.name.c_str());
+        } else {
+            configuration = std::unique_ptr<PropertyMap>(propertyMap);
         }
     }
 }
@@ -305,7 +307,7 @@
 }
 
 status_t EventHub::Device::loadKeyMapLocked() {
-    return keyMap.load(identifier, configuration);
+    return keyMap.load(identifier, configuration.get());
 }
 
 bool EventHub::Device::isExternalDeviceLocked() {
@@ -415,8 +417,6 @@
       : mBuiltInKeyboardId(NO_BUILT_IN_KEYBOARD),
         mNextDeviceId(1),
         mControllerNumbers(),
-        mOpeningDevices(0),
-        mClosingDevices(0),
         mNeedToSendFinishedDeviceScan(false),
         mNeedToReopenDevices(false),
         mNeedToScanDevices(true),
@@ -471,8 +471,6 @@
 EventHub::~EventHub(void) {
     closeAllDevicesLocked();
 
-    mClosingDevices.clear();
-
     ::close(mEpollFd);
     ::close(mINotifyFd);
     ::close(mWakeReadPipeFd);
@@ -1487,7 +1485,8 @@
     if (device->classes.test(InputDeviceClass::KEYBOARD)) {
         // Register the keyboard as a built-in keyboard if it is eligible.
         if (!keyMapStatus && mBuiltInKeyboardId == NO_BUILT_IN_KEYBOARD &&
-            isEligibleBuiltInKeyboard(device->identifier, device->configuration, &device->keyMap)) {
+            isEligibleBuiltInKeyboard(device->identifier, device->configuration.get(),
+                                      &device->keyMap)) {
             mBuiltInKeyboardId = device->id;
         }
 
@@ -1711,8 +1710,8 @@
 
 void EventHub::closeAllDevicesLocked() {
     mUnattachedVideoDevices.clear();
-    for (const auto& [id, device] : mDevices) {
-        closeDeviceLocked(*device);
+    while (!mDevices.empty()) {
+        closeDeviceLocked(*(mDevices.begin()->second));
     }
 }
 
@@ -1733,11 +1732,10 @@
     }
 
     releaseControllerNumberLocked(device.controllerNumber);
+    device.controllerNumber = 0;
     device.close();
-
-    // Move device to mClosingDevices
     mClosingDevices.push_back(std::move(mDevices[device.id]));
-    // Erase device from mDevices
+
     mDevices.erase(device.id);
 }
 
diff --git a/services/inputflinger/reader/include/EventHub.h b/services/inputflinger/reader/include/EventHub.h
index 80e80cb..ff12d98 100644
--- a/services/inputflinger/reader/include/EventHub.h
+++ b/services/inputflinger/reader/include/EventHub.h
@@ -417,7 +417,7 @@
         BitArray<INPUT_PROP_MAX> propBitmask;
 
         std::string configurationFile;
-        PropertyMap* configuration;
+        std::unique_ptr<PropertyMap> configuration;
         std::unique_ptr<VirtualKeyMap> virtualKeyMap;
         KeyMap keyMap;
 
diff --git a/services/surfaceflinger/Android.bp b/services/surfaceflinger/Android.bp
index c55e9df..e452187 100644
--- a/services/surfaceflinger/Android.bp
+++ b/services/surfaceflinger/Android.bp
@@ -176,7 +176,7 @@
         "Scheduler/Timer.cpp",
         "Scheduler/VSyncDispatchTimerQueue.cpp",
         "Scheduler/VSyncPredictor.cpp",
-        "Scheduler/VSyncModulator.cpp",
+        "Scheduler/VsyncModulator.cpp",
         "Scheduler/VSyncReactor.cpp",
         "StartPropertySetThread.cpp",
         "SurfaceFlinger.cpp",
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h
index 26299e9..6cc7a53 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h
@@ -163,11 +163,12 @@
     virtual void setCompositionEnabled(bool) = 0;
 
     // Sets the projection state to use
-    virtual void setProjection(const ui::Transform&, uint32_t orientation, const Rect& frame,
-                               const Rect& viewport, const Rect& destinationClip,
+    virtual void setProjection(const ui::Transform&, uint32_t orientation,
+                               const Rect& orientedDisplaySpaceRect,
+                               const Rect& layerStackSpaceRect, const Rect& displaySpaceRect,
                                bool needsFiltering) = 0;
     // Sets the bounds to use
-    virtual void setBounds(const ui::Size&) = 0;
+    virtual void setDisplaySpaceSize(const ui::Size&) = 0;
 
     // Sets the layer stack filtering settings for this output. See
     // belongsInOutput for full details.
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/ProjectionSpace.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/ProjectionSpace.h
new file mode 100644
index 0000000..9d15665
--- /dev/null
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/ProjectionSpace.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <ostream>
+
+#include <android-base/stringprintf.h>
+#include <ui/Rect.h>
+#include <ui/Rotation.h>
+#include <ui/Transform.h>
+
+namespace android {
+namespace compositionengine {
+
+// Geometrical space to which content is projected.
+// For example, this can be the layer space or the physical display space.
+struct ProjectionSpace {
+    ProjectionSpace() = default;
+    ProjectionSpace(ui::Size size, Rect content)
+          : bounds(std::move(size)), content(std::move(content)) {}
+
+    // Bounds of this space. Always starts at (0,0).
+    Rect bounds;
+
+    // Rect onto which content is projected.
+    Rect content;
+};
+
+} // namespace compositionengine
+
+inline std::string to_string(const android::compositionengine::ProjectionSpace& space) {
+    return android::base::StringPrintf("ProjectionSpace(bounds = %s, content = %s)",
+                                       to_string(space.bounds).c_str(),
+                                       to_string(space.content).c_str());
+}
+
+// Defining PrintTo helps with Google Tests.
+inline void PrintTo(const android::compositionengine::ProjectionSpace& space, ::std::ostream* os) {
+    *os << to_string(space);
+}
+
+} // namespace android
\ No newline at end of file
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h
index 0ac2545..57b7a97 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h
@@ -38,10 +38,10 @@
     bool isValid() const override;
     std::optional<DisplayId> getDisplayId() const override;
     void setCompositionEnabled(bool) override;
-    void setProjection(const ui::Transform&, uint32_t orientation, const Rect& frame,
-                       const Rect& viewport, const Rect& destinationClip,
-                       bool needsFiltering) override;
-    void setBounds(const ui::Size&) override;
+    void setProjection(const ui::Transform&, uint32_t orientation,
+                       const Rect& orientedDisplaySpaceRect, const Rect& layerStackSpaceRect,
+                       const Rect& displaySpaceRect, bool needsFiltering) override;
+    void setDisplaySpaceSize(const ui::Size&) override;
     void setLayerStackFilter(uint32_t layerStackId, bool isInternal) override;
 
     void setColorTransform(const compositionengine::CompositionRefreshArgs&) override;
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h
index 7120a48..462d952 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h
@@ -29,6 +29,7 @@
 // TODO(b/129481165): remove the #pragma below and fix conversion issues
 #pragma clang diagnostic pop // ignored "-Wconversion"
 
+#include <compositionengine/ProjectionSpace.h>
 #include <ui/Rect.h>
 #include <ui/Region.h>
 #include <ui/Transform.h>
@@ -50,8 +51,7 @@
     // If true, the current frame on this output uses device composition
     bool usesDeviceComposition{false};
 
-    // If true, the client target should be flipped when performing client
-    // composition
+    // If true, the client target should be flipped when performing client composition
     bool flipClientTarget{false};
 
     // If true, the current frame reused the buffer from a previous client composition
@@ -63,25 +63,26 @@
     // The layer stack to display on this display
     uint32_t layerStackId{~0u};
 
-    // The physical space screen bounds
-    Rect bounds;
+    // The common space for all layers in the layer stack. layerStackSpace.content is the Rect
+    // which gets projected on the display. The content in this space is always in a single
+    // orientation.
+    ProjectionSpace layerStackSpace;
 
-    // The logical to physical transformation to use
+    // Oriented physical display space. It will have the same size as displaySpace oriented to
+    // match the orientation of layerStackSpace. The content in this space is always in a single
+    // orientation.
+    ProjectionSpace orientedDisplaySpace;
+
+    // The space of the physical display. It is as big as the currently active display mode. The
+    // content in this space can be rotated.
+    ProjectionSpace displaySpace;
+
+    // Transformation from layerStackSpace to displaySpace
     ui::Transform transform;
 
-    // The physical orientation of the display, expressed as ui::Transform
-    // orientation flags.
+    // The physical orientation of the display, expressed as ui::Transform orientation flags.
     uint32_t orientation{0};
 
-    // The logical space user visible bounds
-    Rect frame;
-
-    // The logical space user viewport rectangle
-    Rect viewport;
-
-    // The physical space destination clip rectangle
-    Rect destinationClip;
-
     // If true, RenderEngine filtering should be enabled
     bool needsFiltering{false};
 
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h
index c4dff73..375d334 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h
@@ -38,7 +38,7 @@
     MOCK_METHOD1(setCompositionEnabled, void(bool));
     MOCK_METHOD6(setProjection,
                  void(const ui::Transform&, uint32_t, const Rect&, const Rect&, const Rect&, bool));
-    MOCK_METHOD1(setBounds, void(const ui::Size&));
+    MOCK_METHOD1(setDisplaySpaceSize, void(const ui::Size&));
     MOCK_METHOD2(setLayerStackFilter, void(uint32_t, bool));
 
     MOCK_METHOD1(setColorTransform, void(const compositionengine::CompositionRefreshArgs&));
diff --git a/services/surfaceflinger/CompositionEngine/src/DumpHelpers.cpp b/services/surfaceflinger/CompositionEngine/src/DumpHelpers.cpp
index 9598430..9d1bb02 100644
--- a/services/surfaceflinger/CompositionEngine/src/DumpHelpers.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/DumpHelpers.cpp
@@ -77,6 +77,7 @@
 
 void dumpVal(std::string& out, const char* name, const ui::Transform& transform) {
     transform.dump(out, name);
+    out.append(" ");
 }
 
 void dumpVal(std::string& out, const char* name, const ui::Size& size) {
diff --git a/services/surfaceflinger/CompositionEngine/src/Output.cpp b/services/surfaceflinger/CompositionEngine/src/Output.cpp
index 670b969..9e0a43a 100644
--- a/services/surfaceflinger/CompositionEngine/src/Output.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/Output.cpp
@@ -105,24 +105,32 @@
     dirtyEntireOutput();
 }
 
-void Output::setProjection(const ui::Transform& transform, uint32_t orientation, const Rect& frame,
-                           const Rect& viewport, const Rect& destinationClip, bool needsFiltering) {
+void Output::setProjection(const ui::Transform& transform, uint32_t orientation,
+                           const Rect& orientedDisplaySpaceRect, const Rect& layerStackSpaceRect,
+                           const Rect& displaySpaceRect, bool needsFiltering) {
     auto& outputState = editState();
     outputState.transform = transform;
     outputState.orientation = orientation;
-    outputState.destinationClip = destinationClip;
-    outputState.frame = frame;
-    outputState.viewport = viewport;
+    outputState.displaySpace.content = displaySpaceRect;
+    // outputState.displaySpace.bounds should be already set from setDisplaySpaceSize().
+    outputState.orientedDisplaySpace.content = orientedDisplaySpaceRect;
+
+    ui::Size orientedSize = outputState.displaySpace.bounds.getSize();
+    if (orientation == ui::Transform::ROT_90 || orientation == ui::Transform::ROT_270) {
+        std::swap(orientedSize.width, orientedSize.height);
+    }
+    outputState.orientedDisplaySpace.bounds = Rect(orientedSize);
+
+    outputState.layerStackSpace.content = layerStackSpaceRect;
+    outputState.layerStackSpace.bounds = layerStackSpaceRect;
     outputState.needsFiltering = needsFiltering;
 
     dirtyEntireOutput();
 }
 
-// TODO(b/121291683): Rename setSize() once more is moved.
-void Output::setBounds(const ui::Size& size) {
+void Output::setDisplaySpaceSize(const ui::Size& size) {
     mRenderSurface->setDisplaySize(size);
-    // TODO(b/121291683): Rename outputState.size once more is moved.
-    editState().bounds = Rect(mRenderSurface->getSize());
+    editState().displaySpace.bounds = Rect(mRenderSurface->getSize());
 
     dirtyEntireOutput();
 }
@@ -230,7 +238,7 @@
 
 void Output::setRenderSurface(std::unique_ptr<compositionengine::RenderSurface> surface) {
     mRenderSurface = std::move(surface);
-    editState().bounds = Rect(mRenderSurface->getSize());
+    editState().displaySpace.bounds = Rect(mRenderSurface->getSize());
 
     dirtyEntireOutput();
 }
@@ -249,7 +257,7 @@
 
 Region Output::getDirtyRegion(bool repaintEverything) const {
     const auto& outputState = getState();
-    Region dirty(outputState.viewport);
+    Region dirty(outputState.layerStackSpace.content);
     if (!repaintEverything) {
         dirty.andSelf(outputState.dirtyRegion);
     }
@@ -334,7 +342,7 @@
 
     // Compute the resulting coverage for this output, and store it for later
     const ui::Transform& tr = outputState.transform;
-    Region undefinedRegion{outputState.bounds};
+    Region undefinedRegion{outputState.displaySpace.bounds};
     undefinedRegion.subtractSelf(tr.transform(coverage.aboveOpaqueLayers));
 
     outputState.undefinedRegion = undefinedRegion;
@@ -537,7 +545,7 @@
     // TODO(b/121291683): Why does this not use visibleRegion? (see outputSpaceVisibleRegion below)
     const auto& outputState = getState();
     Region drawRegion(outputState.transform.transform(visibleNonTransparentRegion));
-    drawRegion.andSelf(outputState.bounds);
+    drawRegion.andSelf(outputState.displaySpace.bounds);
     if (drawRegion.isEmpty()) {
         return;
     }
@@ -554,8 +562,8 @@
     outputLayerState.visibleRegion = visibleRegion;
     outputLayerState.visibleNonTransparentRegion = visibleNonTransparentRegion;
     outputLayerState.coveredRegion = coveredRegion;
-    outputLayerState.outputSpaceVisibleRegion =
-            outputState.transform.transform(visibleNonShadowRegion.intersect(outputState.viewport));
+    outputLayerState.outputSpaceVisibleRegion = outputState.transform.transform(
+            visibleNonShadowRegion.intersect(outputState.layerStackSpace.content));
     outputLayerState.shadowRegion = shadowRegion;
 }
 
@@ -860,8 +868,8 @@
     ALOGV("hasClientComposition");
 
     renderengine::DisplaySettings clientCompositionDisplay;
-    clientCompositionDisplay.physicalDisplay = outputState.destinationClip;
-    clientCompositionDisplay.clip = outputState.viewport;
+    clientCompositionDisplay.physicalDisplay = outputState.displaySpace.content;
+    clientCompositionDisplay.clip = outputState.layerStackSpace.content;
     clientCompositionDisplay.orientation = outputState.orientation;
     clientCompositionDisplay.outputDataspace = mDisplayColorProfile->hasWideColorGamut()
             ? outputState.dataspace
@@ -945,7 +953,7 @@
     ALOGV("Rendering client layers");
 
     const auto& outputState = getState();
-    const Region viewportRegion(outputState.viewport);
+    const Region viewportRegion(outputState.layerStackSpace.content);
     bool firstLayer = true;
     // Used when a layer clears part of the buffer.
     Region stubRegion;
@@ -981,17 +989,17 @@
                 !layerState.visibleRegion.subtract(layerState.shadowRegion).isEmpty();
 
         if (clientComposition || clearClientComposition) {
-            compositionengine::LayerFE::ClientCompositionTargetSettings targetSettings{
-                    clip,
-                    layer->needsFiltering() || outputState.needsFiltering,
-                    outputState.isSecure,
-                    supportsProtectedContent,
-                    clientComposition ? clearRegion : stubRegion,
-                    outputState.viewport,
-                    outputDataspace,
-                    realContentIsVisible,
-                    !clientComposition, /* clearContent  */
-            };
+            compositionengine::LayerFE::ClientCompositionTargetSettings
+                    targetSettings{.clip = clip,
+                                   .needsFiltering =
+                                           layer->needsFiltering() || outputState.needsFiltering,
+                                   .isSecure = outputState.isSecure,
+                                   .supportsProtectedContent = supportsProtectedContent,
+                                   .clearRegion = clientComposition ? clearRegion : stubRegion,
+                                   .viewport = outputState.layerStackSpace.content,
+                                   .dataspace = outputDataspace,
+                                   .realContentIsVisible = realContentIsVisible,
+                                   .clearContent = !clientComposition};
             std::vector<LayerFE::LayerSettings> results =
                     layerFE.prepareClientCompositionList(targetSettings);
             if (realContentIsVisible && !results.empty()) {
@@ -1088,7 +1096,7 @@
 
 void Output::dirtyEntireOutput() {
     auto& outputState = editState();
-    outputState.dirtyRegion.set(outputState.bounds);
+    outputState.dirtyRegion.set(outputState.displaySpace.bounds);
 }
 
 void Output::chooseCompositionStrategy() {
diff --git a/services/surfaceflinger/CompositionEngine/src/OutputCompositionState.cpp b/services/surfaceflinger/CompositionEngine/src/OutputCompositionState.cpp
index f3b2da1..776fdde 100644
--- a/services/surfaceflinger/CompositionEngine/src/OutputCompositionState.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/OutputCompositionState.cpp
@@ -37,11 +37,12 @@
     dumpVal(out, "transform", transform);
 
     out.append("\n   ");
-
-    dumpVal(out, "bounds", bounds);
-    dumpVal(out, "frame", frame);
-    dumpVal(out, "viewport", viewport);
-    dumpVal(out, "destinationClip", destinationClip);
+    dumpVal(out, "layerStackSpace", to_string(layerStackSpace));
+    out.append("\n   ");
+    dumpVal(out, "orientedDisplaySpace", to_string(orientedDisplaySpace));
+    out.append("\n   ");
+    dumpVal(out, "displaySpace", to_string(displaySpace));
+    out.append("\n   ");
     dumpVal(out, "needsFiltering", needsFiltering);
 
     out.append("\n   ");
diff --git a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
index 1faf775..376b4b3 100644
--- a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
@@ -77,7 +77,7 @@
     FloatRect activeCropFloat =
             reduce(layerState.geomLayerBounds, layerState.transparentRegionHint);
 
-    const Rect& viewport = getOutput().getState().viewport;
+    const Rect& viewport = getOutput().getState().layerStackSpace.content;
     const ui::Transform& layerTransform = layerState.geomLayerTransform;
     const ui::Transform& inverseLayerTransform = layerState.geomInverseLayerTransform;
     // Transform to screen space.
@@ -189,7 +189,7 @@
     Rect activeCrop = layerState.geomCrop;
     if (!activeCrop.isEmpty() && bufferSize.isValid()) {
         activeCrop = layerTransform.transform(activeCrop);
-        if (!activeCrop.intersect(outputState.viewport, &activeCrop)) {
+        if (!activeCrop.intersect(outputState.layerStackSpace.content, &activeCrop)) {
             activeCrop.clear();
         }
         activeCrop = inverseLayerTransform.transform(activeCrop, true);
@@ -215,7 +215,7 @@
     // transformation. We then round upon constructing 'frame'.
     Rect frame{
             layerTransform.transform(reduce(layerState.geomLayerBounds, activeTransparentRegion))};
-    if (!frame.intersect(outputState.viewport, &frame)) {
+    if (!frame.intersect(outputState.layerStackSpace.content, &frame)) {
         frame.clear();
     }
     const ui::Transform displayTransform{outputState.transform};
@@ -568,7 +568,7 @@
     const auto& outputState = getOutput().getState();
 
     Rect frame = layerFEState->cursorFrame;
-    frame.intersect(outputState.viewport, &frame);
+    frame.intersect(outputState.layerStackSpace.content, &frame);
     Rect position = outputState.transform.transform(frame);
 
     if (auto error = hwcLayer->setCursorPosition(position.left, position.top);
diff --git a/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp b/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp
index 378c050..4519a9d 100644
--- a/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp
@@ -908,7 +908,7 @@
 
     mDisplay->editState().isEnabled = true;
     mDisplay->editState().usesClientComposition = false;
-    mDisplay->editState().viewport = Rect(0, 0, 1, 1);
+    mDisplay->editState().layerStackSpace.content = Rect(0, 0, 1, 1);
     mDisplay->editState().dirtyRegion = Region::INVALID_REGION;
 
     CompositionRefreshArgs refreshArgs;
@@ -929,7 +929,7 @@
 
     nonHwcDisplay->editState().isEnabled = true;
     nonHwcDisplay->editState().usesClientComposition = false;
-    nonHwcDisplay->editState().viewport = Rect(0, 0, 1, 1);
+    nonHwcDisplay->editState().layerStackSpace.content = Rect(0, 0, 1, 1);
     nonHwcDisplay->editState().dirtyRegion = Region::INVALID_REGION;
 
     CompositionRefreshArgs refreshArgs;
@@ -950,7 +950,7 @@
 
     nonHwcDisplay->editState().isEnabled = true;
     nonHwcDisplay->editState().usesClientComposition = false;
-    nonHwcDisplay->editState().viewport = Rect(0, 0, 1, 1);
+    nonHwcDisplay->editState().layerStackSpace.content = Rect(0, 0, 1, 1);
     nonHwcDisplay->editState().dirtyRegion = Region(Rect(0, 0, 1, 1));
 
     CompositionRefreshArgs refreshArgs;
@@ -971,7 +971,7 @@
 
     nonHwcDisplay->editState().isEnabled = true;
     nonHwcDisplay->editState().usesClientComposition = false;
-    nonHwcDisplay->editState().viewport = Rect(0, 0, 1, 1);
+    nonHwcDisplay->editState().layerStackSpace.content = Rect(0, 0, 1, 1);
     nonHwcDisplay->editState().dirtyRegion = Region::INVALID_REGION;
 
     CompositionRefreshArgs refreshArgs;
diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp
index 020f93a..df3da85 100644
--- a/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp
@@ -138,7 +138,7 @@
         mLayerFEState.geomBufferSize = Rect{0, 0, 1920, 1080};
         mLayerFEState.geomBufferTransform = TR_IDENT;
 
-        mOutputState.viewport = Rect{0, 0, 1920, 1080};
+        mOutputState.layerStackSpace.content = Rect{0, 0, 1920, 1080};
     }
 
     FloatRect calculateOutputSourceCrop() {
@@ -223,7 +223,7 @@
 }
 
 TEST_F(OutputLayerSourceCropTest, viewportAffectsCrop) {
-    mOutputState.viewport = Rect{0, 0, 960, 540};
+    mOutputState.layerStackSpace.content = Rect{0, 0, 960, 540};
 
     const FloatRect expected{0.f, 0.f, 960.f, 540.f};
     EXPECT_THAT(calculateOutputSourceCrop(), expected);
@@ -245,7 +245,7 @@
         mLayerFEState.geomCrop = Rect{0, 0, 1920, 1080};
         mLayerFEState.geomLayerBounds = FloatRect{0.f, 0.f, 1920.f, 1080.f};
 
-        mOutputState.viewport = Rect{0, 0, 1920, 1080};
+        mOutputState.layerStackSpace.content = Rect{0, 0, 1920, 1080};
         mOutputState.transform = ui::Transform{TR_IDENT};
     }
 
@@ -293,7 +293,7 @@
 }
 
 TEST_F(OutputLayerDisplayFrameTest, viewportAffectsFrame) {
-    mOutputState.viewport = Rect{0, 0, 960, 540};
+    mOutputState.layerStackSpace.content = Rect{0, 0, 960, 540};
     const Rect expected{0, 0, 960, 540};
     EXPECT_THAT(calculateOutputDisplayFrame(), expected);
 }
@@ -988,7 +988,7 @@
 
         mLayerFEState.cursorFrame = kDefaultCursorFrame;
 
-        mOutputState.viewport = kDefaultDisplayViewport;
+        mOutputState.layerStackSpace.content = kDefaultDisplayViewport;
         mOutputState.transform = ui::Transform{kDefaultTransform};
     }
 
diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
index fdaf907..3dd26c0 100644
--- a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
@@ -136,7 +136,7 @@
                 std::unique_ptr<DisplayColorProfile>(mDisplayColorProfile));
         mOutput->setRenderSurfaceForTest(std::unique_ptr<RenderSurface>(mRenderSurface));
 
-        mOutput->editState().bounds = kDefaultDisplaySize;
+        mOutput->editState().displaySpace.bounds = kDefaultDisplaySize;
     }
 
     void injectOutputLayer(InjectedLayer& layer) {
@@ -248,14 +248,14 @@
 
     EXPECT_THAT(mOutput->getState().transform, transform);
     EXPECT_EQ(orientation, mOutput->getState().orientation);
-    EXPECT_EQ(frame, mOutput->getState().frame);
-    EXPECT_EQ(viewport, mOutput->getState().viewport);
-    EXPECT_EQ(destinationClip, mOutput->getState().destinationClip);
+    EXPECT_EQ(frame, mOutput->getState().orientedDisplaySpace.content);
+    EXPECT_EQ(viewport, mOutput->getState().layerStackSpace.content);
+    EXPECT_EQ(destinationClip, mOutput->getState().displaySpace.content);
     EXPECT_EQ(needsFiltering, mOutput->getState().needsFiltering);
 }
 
 /*
- * Output::setBounds()
+ * Output::setDisplaySpaceSize()
  */
 
 TEST_F(OutputTest, setBoundsSetsSizeAndDirtiesEntireOutput) {
@@ -264,9 +264,9 @@
     EXPECT_CALL(*mRenderSurface, setDisplaySize(displaySize)).Times(1);
     EXPECT_CALL(*mRenderSurface, getSize()).WillOnce(ReturnRef(displaySize));
 
-    mOutput->setBounds(displaySize);
+    mOutput->setDisplaySpaceSize(displaySize);
 
-    EXPECT_EQ(Rect(displaySize), mOutput->getState().bounds);
+    EXPECT_EQ(Rect(displaySize), mOutput->getState().displaySpace.bounds);
 
     EXPECT_THAT(mOutput->getState().dirtyRegion, RegionEq(Region(Rect(displaySize))));
 }
@@ -429,7 +429,7 @@
 
     mOutput->setRenderSurface(std::unique_ptr<RenderSurface>(renderSurface));
 
-    EXPECT_EQ(Rect(newDisplaySize), mOutput->getState().bounds);
+    EXPECT_EQ(Rect(newDisplaySize), mOutput->getState().displaySpace.bounds);
 }
 
 /*
@@ -438,7 +438,7 @@
 
 TEST_F(OutputTest, getDirtyRegionWithRepaintEverythingTrue) {
     const Rect viewport{100, 200};
-    mOutput->editState().viewport = viewport;
+    mOutput->editState().layerStackSpace.content = viewport;
     mOutput->editState().dirtyRegion.set(50, 300);
 
     {
@@ -450,7 +450,7 @@
 
 TEST_F(OutputTest, getDirtyRegionWithRepaintEverythingFalse) {
     const Rect viewport{100, 200};
-    mOutput->editState().viewport = viewport;
+    mOutput->editState().layerStackSpace.content = viewport;
     mOutput->editState().dirtyRegion.set(50, 300);
 
     {
@@ -858,7 +858,7 @@
     OutputRebuildLayerStacksTest() {
         mOutput.mState.isEnabled = true;
         mOutput.mState.transform = kIdentityTransform;
-        mOutput.mState.bounds = kOutputBounds;
+        mOutput.mState.displaySpace.bounds = kOutputBounds;
 
         mRefreshArgs.updatingOutputGeometryThisFrame = true;
 
@@ -1065,8 +1065,8 @@
         EXPECT_CALL(mOutput, getOutputLayerOrderedByZByIndex(0u))
                 .WillRepeatedly(Return(&mLayer.outputLayer));
 
-        mOutput.mState.bounds = Rect(0, 0, 200, 300);
-        mOutput.mState.viewport = Rect(0, 0, 200, 300);
+        mOutput.mState.displaySpace.bounds = Rect(0, 0, 200, 300);
+        mOutput.mState.layerStackSpace.content = Rect(0, 0, 200, 300);
         mOutput.mState.transform = ui::Transform(TR_IDENT, 200, 300);
 
         mLayer.layerFEState.isVisible = true;
@@ -1146,7 +1146,7 @@
 }
 
 TEST_F(OutputEnsureOutputLayerIfVisibleTest, takesNotSoEarlyOutifDrawRegionEmpty) {
-    mOutput.mState.bounds = Rect(0, 0, 0, 0);
+    mOutput.mState.displaySpace.bounds = Rect(0, 0, 0, 0);
 
     ensureOutputLayerIfVisible();
 }
@@ -1343,7 +1343,7 @@
     mLayer.layerFEState.contentDirty = true;
     mLayer.layerFEState.geomLayerTransform = ui::Transform(TR_IDENT, 100, 200);
 
-    mOutput.mState.viewport = Rect(0, 0, 300, 200);
+    mOutput.mState.layerStackSpace.content = Rect(0, 0, 300, 200);
     mOutput.mState.transform = ui::Transform(TR_ROT_90, 200, 300);
 
     EXPECT_CALL(mOutput, getOutputLayerCount()).WillOnce(Return(0u));
@@ -1369,7 +1369,7 @@
     mLayer.layerFEState.contentDirty = true;
     mLayer.layerFEState.geomLayerTransform = ui::Transform(TR_IDENT, 100, 200);
 
-    mOutput.mState.viewport = Rect(0, 0, 300, 200);
+    mOutput.mState.layerStackSpace.content = Rect(0, 0, 300, 200);
     mOutput.mState.transform = ui::Transform(TR_ROT_90, 200, 300);
 
     EXPECT_CALL(mOutput, ensureOutputLayer(Eq(0u), Eq(mLayer.layerFE)))
@@ -2783,9 +2783,9 @@
         mOutput.setRenderSurfaceForTest(std::unique_ptr<RenderSurface>(mRenderSurface));
         mOutput.cacheClientCompositionRequests(MAX_CLIENT_COMPOSITION_CACHE_SIZE);
 
-        mOutput.mState.frame = kDefaultOutputFrame;
-        mOutput.mState.viewport = kDefaultOutputViewport;
-        mOutput.mState.destinationClip = kDefaultOutputDestinationClip;
+        mOutput.mState.orientedDisplaySpace.content = kDefaultOutputFrame;
+        mOutput.mState.layerStackSpace.content = kDefaultOutputViewport;
+        mOutput.mState.displaySpace.content = kDefaultOutputDestinationClip;
         mOutput.mState.transform = ui::Transform{kDefaultOutputOrientation};
         mOutput.mState.orientation = kDefaultOutputOrientation;
         mOutput.mState.dataspace = kDefaultOutputDataspace;
@@ -3409,9 +3409,9 @@
 struct GenerateClientCompositionRequestsTest_ThreeLayers
       : public GenerateClientCompositionRequestsTest {
     GenerateClientCompositionRequestsTest_ThreeLayers() {
-        mOutput.mState.frame = kDisplayFrame;
-        mOutput.mState.viewport = kDisplayViewport;
-        mOutput.mState.destinationClip = kDisplayDestinationClip;
+        mOutput.mState.orientedDisplaySpace.content = kDisplayFrame;
+        mOutput.mState.layerStackSpace.content = kDisplayViewport;
+        mOutput.mState.displaySpace.content = kDisplayDestinationClip;
         mOutput.mState.transform = ui::Transform{kDisplayOrientation};
         mOutput.mState.orientation = kDisplayOrientation;
         mOutput.mState.needsFiltering = false;
@@ -3924,9 +3924,9 @@
     const uint32_t kPortraitOrientation = TR_ROT_90;
     constexpr ui::Dataspace kOutputDataspace = ui::Dataspace::DISPLAY_P3;
 
-    mOutput.mState.frame = kPortraitFrame;
-    mOutput.mState.viewport = kPortraitViewport;
-    mOutput.mState.destinationClip = kPortraitDestinationClip;
+    mOutput.mState.orientedDisplaySpace.content = kPortraitFrame;
+    mOutput.mState.layerStackSpace.content = kPortraitViewport;
+    mOutput.mState.displaySpace.content = kPortraitDestinationClip;
     mOutput.mState.transform = ui::Transform{kPortraitOrientation};
     mOutput.mState.orientation = kPortraitOrientation;
     mOutput.mState.needsFiltering = false;
diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp
index a4fc833..016b6ca 100644
--- a/services/surfaceflinger/DisplayDevice.cpp
+++ b/services/surfaceflinger/DisplayDevice.cpp
@@ -29,6 +29,7 @@
 #include <compositionengine/DisplayColorProfileCreationArgs.h>
 #include <compositionengine/DisplayCreationArgs.h>
 #include <compositionengine/DisplaySurface.h>
+#include <compositionengine/ProjectionSpace.h>
 #include <compositionengine/RenderSurface.h>
 #include <compositionengine/RenderSurfaceCreationArgs.h>
 #include <compositionengine/impl/OutputCompositionState.h>
@@ -101,11 +102,11 @@
 }
 
 int DisplayDevice::getWidth() const {
-    return mCompositionDisplay->getState().bounds.getWidth();
+    return mCompositionDisplay->getState().displaySpace.bounds.getWidth();
 }
 
 int DisplayDevice::getHeight() const {
-    return mCompositionDisplay->getState().bounds.getHeight();
+    return mCompositionDisplay->getState().displaySpace.bounds.getHeight();
 }
 
 void DisplayDevice::setDisplayName(const std::string& displayName) {
@@ -155,13 +156,14 @@
 }
 
 void DisplayDevice::setDisplaySize(int width, int height) {
-    mCompositionDisplay->setBounds(ui::Size(width, height));
+    mCompositionDisplay->setDisplaySpaceSize(ui::Size(width, height));
 }
 
-void DisplayDevice::setProjection(ui::Rotation orientation, Rect viewport, Rect frame) {
+void DisplayDevice::setProjection(ui::Rotation orientation, Rect layerStackSpaceRect,
+                                  Rect orientedDisplaySpaceRect) {
     mOrientation = orientation;
 
-    const Rect& displayBounds = getCompositionDisplay()->getState().bounds;
+    const Rect& displayBounds = getCompositionDisplay()->getState().displaySpace.bounds;
     const int displayWidth = displayBounds.width();
     const int displayHeight = displayBounds.height();
 
@@ -171,40 +173,38 @@
         rotation.set(flags, displayWidth, displayHeight);
     }
 
-    if (!frame.isValid()) {
+    if (!orientedDisplaySpaceRect.isValid()) {
         // the destination frame can be invalid if it has never been set,
         // in that case we assume the whole display frame.
-        frame = Rect(displayWidth, displayHeight);
+        orientedDisplaySpaceRect = Rect(displayWidth, displayHeight);
     }
 
-    if (viewport.isEmpty()) {
-        // viewport can be invalid if it has never been set, in that case
+    if (layerStackSpaceRect.isEmpty()) {
+        // layerStackSpaceRect can be invalid if it has never been set, in that case
         // we assume the whole display size.
-        // it's also invalid to have an empty viewport, so we handle that
+        // It's also invalid to have an empty layerStackSpaceRect, so we handle that
         // case in the same way.
-        viewport = Rect(displayWidth, displayHeight);
+        layerStackSpaceRect = Rect(displayWidth, displayHeight);
         if (rotation.getOrientation() & ui::Transform::ROT_90) {
-            // viewport is always specified in the logical orientation
-            // of the display (ie: post-rotation).
-            std::swap(viewport.right, viewport.bottom);
+            std::swap(layerStackSpaceRect.right, layerStackSpaceRect.bottom);
         }
     }
 
     ui::Transform logicalTranslation, physicalTranslation, scale;
-    const float sourceWidth = viewport.width();
-    const float sourceHeight = viewport.height();
-    const float destWidth = frame.width();
-    const float destHeight = frame.height();
+    const float sourceWidth = layerStackSpaceRect.width();
+    const float sourceHeight = layerStackSpaceRect.height();
+    const float destWidth = orientedDisplaySpaceRect.width();
+    const float destHeight = orientedDisplaySpaceRect.height();
     if (sourceWidth != destWidth || sourceHeight != destHeight) {
         const float scaleX = destWidth / sourceWidth;
         const float scaleY = destHeight / sourceHeight;
         scale.set(scaleX, 0, 0, scaleY);
     }
 
-    const float sourceX = viewport.left;
-    const float sourceY = viewport.top;
-    const float destX = frame.left;
-    const float destY = frame.top;
+    const float sourceX = layerStackSpaceRect.left;
+    const float sourceY = layerStackSpaceRect.top;
+    const float destX = orientedDisplaySpaceRect.left;
+    const float destY = orientedDisplaySpaceRect.top;
     logicalTranslation.set(-sourceX, -sourceY);
     physicalTranslation.set(destX, destY);
 
@@ -217,7 +217,7 @@
         }
     }
 
-    // The viewport and frame are both in the logical orientation.
+    // The layerStackSpaceRect and orientedDisplaySpaceRect are both in the logical orientation.
     // Apply the logical translation, scale to physical size, apply the
     // physical translation and finally rotate to the physical orientation.
     ui::Transform globalTransform = rotation * physicalTranslation * scale * logicalTranslation;
@@ -226,12 +226,12 @@
     const bool needsFiltering =
             (!globalTransform.preserveRects() || (type >= ui::Transform::SCALE));
 
-    Rect destinationClip = globalTransform.transform(viewport);
-    if (destinationClip.isEmpty()) {
-        destinationClip = displayBounds;
+    Rect displaySpaceRect = globalTransform.transform(layerStackSpaceRect);
+    if (displaySpaceRect.isEmpty()) {
+        displaySpaceRect = displayBounds;
     }
-    // Make sure the destination clip is contained in the display bounds
-    destinationClip.intersect(displayBounds, &destinationClip);
+    // Make sure the displaySpaceRect is contained in the display bounds
+    displaySpaceRect.intersect(displayBounds, &displaySpaceRect);
 
     uint32_t transformOrientation;
 
@@ -242,8 +242,9 @@
         transformOrientation = ui::Transform::toRotationFlags(orientation);
     }
 
-    getCompositionDisplay()->setProjection(globalTransform, transformOrientation, frame, viewport,
-                                           destinationClip, needsFiltering);
+    getCompositionDisplay()->setProjection(globalTransform, transformOrientation,
+                                           orientedDisplaySpaceRect, layerStackSpaceRect,
+                                           displaySpaceRect, needsFiltering);
 }
 
 ui::Transform::RotationFlags DisplayDevice::getPrimaryDisplayRotationFlags() {
@@ -296,7 +297,7 @@
 }
 
 const Rect& DisplayDevice::getBounds() const {
-    return mCompositionDisplay->getState().bounds;
+    return mCompositionDisplay->getState().displaySpace.bounds;
 }
 
 const Region& DisplayDevice::getUndefinedRegion() const {
@@ -315,12 +316,12 @@
     return mCompositionDisplay->getState().transform;
 }
 
-const Rect& DisplayDevice::getViewport() const {
-    return mCompositionDisplay->getState().viewport;
+const Rect& DisplayDevice::getLayerStackSpaceRect() const {
+    return mCompositionDisplay->getState().layerStackSpace.content;
 }
 
-const Rect& DisplayDevice::getFrame() const {
-    return mCompositionDisplay->getState().frame;
+const Rect& DisplayDevice::getOrientedDisplaySpaceRect() const {
+    return mCompositionDisplay->getState().orientedDisplaySpace.content;
 }
 
 bool DisplayDevice::hasWideColorGamut() const {
diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h
index 1319679..35a8b62 100644
--- a/services/surfaceflinger/DisplayDevice.h
+++ b/services/surfaceflinger/DisplayDevice.h
@@ -99,8 +99,8 @@
     }
 
     const ui::Transform& getTransform() const;
-    const Rect& getViewport() const;
-    const Rect& getFrame() const;
+    const Rect& getLayerStackSpaceRect() const;
+    const Rect& getOrientedDisplaySpaceRect() const;
     bool needsFiltering() const;
     ui::LayerStack getLayerStack() const;
 
@@ -208,8 +208,8 @@
     std::optional<Physical> physical;
     sp<IGraphicBufferProducer> surface;
     ui::LayerStack layerStack = ui::NO_LAYER_STACK;
-    Rect viewport;
-    Rect frame;
+    Rect layerStackSpaceRect;
+    Rect orientedDisplaySpaceRect;
     ui::Rotation orientation = ui::ROTATION_0;
     uint32_t width = 0;
     uint32_t height = 0;
diff --git a/services/surfaceflinger/DisplayRenderArea.cpp b/services/surfaceflinger/DisplayRenderArea.cpp
index d7157b1..9a6b328 100644
--- a/services/surfaceflinger/DisplayRenderArea.cpp
+++ b/services/surfaceflinger/DisplayRenderArea.cpp
@@ -49,7 +49,7 @@
 DisplayRenderArea::DisplayRenderArea(sp<const DisplayDevice> display, const Rect& sourceCrop,
                                      ui::Size reqSize, ui::Dataspace reqDataSpace,
                                      bool useIdentityTransform, bool allowSecureLayers)
-      : RenderArea(reqSize, CaptureFill::OPAQUE, reqDataSpace, display->getViewport(),
+      : RenderArea(reqSize, CaptureFill::OPAQUE, reqDataSpace, display->getLayerStackSpaceRect(),
                    allowSecureLayers, applyDeviceOrientation(useIdentityTransform, *display)),
         mDisplay(std::move(display)),
         mSourceCrop(sourceCrop) {}
@@ -93,7 +93,7 @@
 Rect DisplayRenderArea::getSourceCrop() const {
     // use the projected display viewport by default.
     if (mSourceCrop.isEmpty()) {
-        return mDisplay->getViewport();
+        return mDisplay->getLayerStackSpaceRect();
     }
 
     // Correct for the orientation when the screen capture request contained
@@ -101,8 +101,8 @@
     // it needs to rotate based on the screen orientation to allow the screenshot
     // to be taken in the ROT_0 orientation
     const auto flags = getRotationFlags();
-    int width = mDisplay->getViewport().getWidth();
-    int height = mDisplay->getViewport().getHeight();
+    int width = mDisplay->getLayerStackSpaceRect().getWidth();
+    int height = mDisplay->getLayerStackSpaceRect().getHeight();
     ui::Transform rotation;
     rotation.set(flags, width, height);
     return rotation.transform(mSourceCrop);
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index eb33175..138d08c 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -647,9 +647,9 @@
 }
 
 std::optional<compositionengine::LayerFE::LayerSettings> Layer::prepareShadowClientComposition(
-        const LayerFE::LayerSettings& casterLayerSettings, const Rect& displayViewport,
+        const LayerFE::LayerSettings& casterLayerSettings, const Rect& layerStackRect,
         ui::Dataspace outputDataspace) {
-    renderengine::ShadowSettings shadow = getShadowSettings(displayViewport);
+    renderengine::ShadowSettings shadow = getShadowSettings(layerStackRect);
     if (shadow.length <= 0.f) {
         return {};
     }
@@ -2158,12 +2158,12 @@
             : RoundedCornerState();
 }
 
-renderengine::ShadowSettings Layer::getShadowSettings(const Rect& viewport) const {
+renderengine::ShadowSettings Layer::getShadowSettings(const Rect& layerStackRect) const {
     renderengine::ShadowSettings state = mFlinger->mDrawingState.globalShadowSettings;
 
     // Shift the spot light x-position to the middle of the display and then
     // offset it by casting layer's screen pos.
-    state.lightPos.x = (viewport.width() / 2.f) - mScreenBounds.left;
+    state.lightPos.x = (layerStackRect.width() / 2.f) - mScreenBounds.left;
     state.lightPos.y -= mScreenBounds.top;
 
     state.length = mEffectiveShadowRadius;
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index 8d8ab6d..521659d 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -366,7 +366,7 @@
     virtual bool setMetadata(const LayerMetadata& data);
     bool reparentChildren(const sp<IBinder>& newParentHandle);
     void reparentChildren(const sp<Layer>& newParent);
-    virtual void setChildrenDrawingParent(const sp<Layer>& layer);
+    virtual void setChildrenDrawingParent(const sp<Layer>&);
     virtual bool reparent(const sp<IBinder>& newParentHandle);
     virtual bool detachChildren();
     bool attachChildren();
@@ -535,7 +535,7 @@
     // Write drawing or current state. If writing current state, the caller should hold the
     // external mStateLock. If writing drawing state, this function should be called on the
     // main or tracing thread.
-    void writeToProtoCommonState(LayerProto* layerInfo, LayerVector::StateSet stateSet,
+    void writeToProtoCommonState(LayerProto* layerInfo, LayerVector::StateSet,
                                  uint32_t traceFlags = SurfaceTracing::TRACE_ALL);
 
     virtual Geometry getActiveGeometry(const Layer::State& s) const { return s.active_legacy; }
@@ -585,16 +585,16 @@
     void updateClonedChildren(const sp<Layer>& mirrorRoot,
                               std::map<sp<Layer>, sp<Layer>>& clonedLayersMap);
     void updateClonedRelatives(const std::map<sp<Layer>, sp<Layer>>& clonedLayersMap);
-    void addChildToDrawing(const sp<Layer>& layer);
+    void addChildToDrawing(const sp<Layer>&);
     void updateClonedInputInfo(const std::map<sp<Layer>, sp<Layer>>& clonedLayersMap);
     virtual std::optional<compositionengine::LayerFE::LayerSettings> prepareClientComposition(
             compositionengine::LayerFE::ClientCompositionTargetSettings&);
     virtual std::optional<compositionengine::LayerFE::LayerSettings> prepareShadowClientComposition(
-            const LayerFE::LayerSettings& layerSettings, const Rect& displayViewport,
+            const LayerFE::LayerSettings&, const Rect& layerStackRect,
             ui::Dataspace outputDataspace);
     // Modifies the passed in layer settings to clear the contents. If the blackout flag is set,
     // the settings clears the content with a solid black fill.
-    void prepareClearClientComposition(LayerFE::LayerSettings& layerSettings, bool blackout) const;
+    void prepareClearClientComposition(LayerFE::LayerSettings&, bool blackout) const;
 
 public:
     /*
@@ -756,7 +756,7 @@
     // ignored.
     virtual RoundedCornerState getRoundedCornerState() const;
 
-    renderengine::ShadowSettings getShadowSettings(const Rect& viewport) const;
+    renderengine::ShadowSettings getShadowSettings(const Rect& layerStackRect) const;
 
     /**
      * Traverse this layer and it's hierarchy of children directly. Unlike traverseInZOrder
@@ -766,17 +766,15 @@
      * the scene state, but it's also more efficient than traverseInZOrder and so useful for
      * book-keeping.
      */
-    void traverse(LayerVector::StateSet stateSet, const LayerVector::Visitor& visitor);
-    void traverseInReverseZOrder(LayerVector::StateSet stateSet,
-                                 const LayerVector::Visitor& visitor);
-    void traverseInZOrder(LayerVector::StateSet stateSet, const LayerVector::Visitor& visitor);
+    void traverse(LayerVector::StateSet, const LayerVector::Visitor&);
+    void traverseInReverseZOrder(LayerVector::StateSet, const LayerVector::Visitor&);
+    void traverseInZOrder(LayerVector::StateSet, const LayerVector::Visitor&);
 
     /**
      * Traverse only children in z order, ignoring relative layers that are not children of the
      * parent.
      */
-    void traverseChildrenInZOrder(LayerVector::StateSet stateSet,
-                                  const LayerVector::Visitor& visitor);
+    void traverseChildrenInZOrder(LayerVector::StateSet, const LayerVector::Visitor&);
 
     size_t getChildrenCount() const;
 
@@ -788,7 +786,7 @@
     // the current state, but should not be called anywhere else!
     LayerVector& getCurrentChildren() { return mCurrentChildren; }
 
-    void addChild(const sp<Layer>& layer);
+    void addChild(const sp<Layer>&);
     // Returns index if removed, or negative value otherwise
     // for symmetry with Vector::remove
     ssize_t removeChild(const sp<Layer>& layer);
@@ -802,7 +800,7 @@
     // Copy the current list of children to the drawing state. Called by
     // SurfaceFlinger to complete a transaction.
     void commitChildList();
-    int32_t getZ(LayerVector::StateSet stateSet) const;
+    int32_t getZ(LayerVector::StateSet) const;
     virtual void pushPendingState();
 
     /**
@@ -828,7 +826,7 @@
      */
     Rect getCroppedBufferSize(const Layer::State& s) const;
 
-    bool setFrameRate(FrameRate frameRate);
+    bool setFrameRate(FrameRate);
     virtual FrameRate getFrameRateForLayerTree() const;
     static std::string frameRateCompatibilityString(FrameRateCompatibility compatibility);
 
@@ -870,8 +868,8 @@
      * crop coordinates, transforming them into layer space.
      */
     void setupRoundedCornersCropCoordinates(Rect win, const FloatRect& roundedCornersCrop) const;
-    void setParent(const sp<Layer>& layer);
-    LayerVector makeTraversalList(LayerVector::StateSet stateSet, bool* outSkipRelativeZUsers);
+    void setParent(const sp<Layer>&);
+    LayerVector makeTraversalList(LayerVector::StateSet, bool* outSkipRelativeZUsers);
     void addZOrderRelative(const wp<Layer>& relative);
     void removeZOrderRelative(const wp<Layer>& relative);
 
@@ -970,7 +968,7 @@
 protected:
     compositionengine::OutputLayer* findOutputLayerForDisplay(const DisplayDevice*) const;
 
-    bool usingRelativeZ(LayerVector::StateSet stateSet) const;
+    bool usingRelativeZ(LayerVector::StateSet) const;
 
     bool mPremultipliedAlpha{true};
     const std::string mName;
@@ -1050,15 +1048,14 @@
      * Returns an unsorted vector of all layers that are part of this tree.
      * That includes the current layer and all its descendants.
      */
-    std::vector<Layer*> getLayersInTree(LayerVector::StateSet stateSet);
+    std::vector<Layer*> getLayersInTree(LayerVector::StateSet);
     /**
      * Traverses layers that are part of this tree in the correct z order.
      * layersInTree must be sorted before calling this method.
      */
     void traverseChildrenInZOrderInner(const std::vector<Layer*>& layersInTree,
-                                       LayerVector::StateSet stateSet,
-                                       const LayerVector::Visitor& visitor);
-    LayerVector makeChildrenTraversalList(LayerVector::StateSet stateSet,
+                                       LayerVector::StateSet, const LayerVector::Visitor&);
+    LayerVector makeChildrenTraversalList(LayerVector::StateSet,
                                           const std::vector<Layer*>& layersInTree);
 
     void updateTreeHasFrameRateVote();
diff --git a/services/surfaceflinger/LayerRenderArea.cpp b/services/surfaceflinger/LayerRenderArea.cpp
index 555e61d..e84508f 100644
--- a/services/surfaceflinger/LayerRenderArea.cpp
+++ b/services/surfaceflinger/LayerRenderArea.cpp
@@ -44,8 +44,8 @@
 
 LayerRenderArea::LayerRenderArea(SurfaceFlinger& flinger, sp<Layer> layer, const Rect& crop,
                                  ui::Size reqSize, ui::Dataspace reqDataSpace, bool childrenOnly,
-                                 const Rect& displayViewport, bool allowSecureLayers)
-      : RenderArea(reqSize, CaptureFill::CLEAR, reqDataSpace, displayViewport, allowSecureLayers),
+                                 const Rect& layerStackRect, bool allowSecureLayers)
+      : RenderArea(reqSize, CaptureFill::CLEAR, reqDataSpace, layerStackRect, allowSecureLayers),
         mLayer(std::move(layer)),
         mCrop(crop),
         mFlinger(flinger),
diff --git a/services/surfaceflinger/LayerRenderArea.h b/services/surfaceflinger/LayerRenderArea.h
index 71ff1ce..6a90694 100644
--- a/services/surfaceflinger/LayerRenderArea.h
+++ b/services/surfaceflinger/LayerRenderArea.h
@@ -33,7 +33,7 @@
 class LayerRenderArea : public RenderArea {
 public:
     LayerRenderArea(SurfaceFlinger& flinger, sp<Layer> layer, const Rect& crop, ui::Size reqSize,
-                    ui::Dataspace reqDataSpace, bool childrenOnly, const Rect& displayViewport,
+                    ui::Dataspace reqDataSpace, bool childrenOnly, const Rect& layerStackRect,
                     bool allowSecureLayers);
 
     const ui::Transform& getTransform() const override;
diff --git a/services/surfaceflinger/RenderArea.h b/services/surfaceflinger/RenderArea.h
index b4bddac..c9f7f46 100644
--- a/services/surfaceflinger/RenderArea.h
+++ b/services/surfaceflinger/RenderArea.h
@@ -24,14 +24,14 @@
     static float getCaptureFillValue(CaptureFill captureFill);
 
     RenderArea(ui::Size reqSize, CaptureFill captureFill, ui::Dataspace reqDataSpace,
-               const Rect& displayViewport, bool allowSecureLayers = false,
+               const Rect& layerStackRect, bool allowSecureLayers = false,
                RotationFlags rotation = ui::Transform::ROT_0)
           : mAllowSecureLayers(allowSecureLayers),
             mReqSize(reqSize),
             mReqDataSpace(reqDataSpace),
             mCaptureFill(captureFill),
             mRotationFlags(rotation),
-            mDisplayViewport(displayViewport) {}
+            mLayerStackSpaceRect(layerStackRect) {}
 
     virtual ~RenderArea() = default;
 
@@ -83,7 +83,7 @@
     virtual sp<const DisplayDevice> getDisplayDevice() const = 0;
 
     // Returns the source display viewport.
-    const Rect& getDisplayViewport() const { return mDisplayViewport; }
+    const Rect& getLayerStackSpaceRect() const { return mLayerStackSpaceRect; }
 
 protected:
     const bool mAllowSecureLayers;
@@ -93,7 +93,7 @@
     const ui::Dataspace mReqDataSpace;
     const CaptureFill mCaptureFill;
     const RotationFlags mRotationFlags;
-    const Rect mDisplayViewport;
+    const Rect mLayerStackSpaceRect;
 };
 
 } // namespace android
diff --git a/services/surfaceflinger/Scheduler/PhaseOffsets.h b/services/surfaceflinger/Scheduler/PhaseOffsets.h
index 9ec6d56..0ae9fef 100644
--- a/services/surfaceflinger/Scheduler/PhaseOffsets.h
+++ b/services/surfaceflinger/Scheduler/PhaseOffsets.h
@@ -19,7 +19,7 @@
 #include <unordered_map>
 
 #include "RefreshRateConfigs.h"
-#include "VSyncModulator.h"
+#include "VsyncModulator.h"
 
 namespace android::scheduler {
 
@@ -31,7 +31,7 @@
  */
 class PhaseConfiguration {
 public:
-    using Offsets = VSyncModulator::OffsetsConfig;
+    using Offsets = VsyncModulator::OffsetsConfig;
 
     virtual ~PhaseConfiguration();
 
diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h
index 6a5082a..4e7a9a1 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.h
+++ b/services/surfaceflinger/Scheduler/Scheduler.h
@@ -60,28 +60,13 @@
     ~ISchedulerCallback() = default;
 };
 
-struct IPhaseOffsetControl {
-    virtual void setPhaseOffset(scheduler::ConnectionHandle, nsecs_t phaseOffset) = 0;
-
-protected:
-    ~IPhaseOffsetControl() = default;
-};
-
-class Scheduler : public IPhaseOffsetControl {
+class Scheduler {
 public:
     using RefreshRate = scheduler::RefreshRateConfigs::RefreshRate;
     using ConfigEvent = scheduler::RefreshRateConfigEvent;
 
-    // Indicates whether to start the transaction early, or at vsync time.
-    enum class TransactionStart {
-        Early,      // DEPRECATED. Start the transaction early. Times out on its own
-        EarlyStart, // Start the transaction early and keep this config until EarlyEnd
-        EarlyEnd,   // End the early config started at EarlyStart
-        Normal      // Start the transaction at the normal time
-    };
-
     Scheduler(const scheduler::RefreshRateConfigs&, ISchedulerCallback&);
-    virtual ~Scheduler();
+    ~Scheduler();
 
     DispSync& getPrimaryDispSync();
 
@@ -104,7 +89,7 @@
     void onScreenReleased(ConnectionHandle);
 
     // Modifies phase offset in the event thread.
-    void setPhaseOffset(ConnectionHandle, nsecs_t phaseOffset) override;
+    void setPhaseOffset(ConnectionHandle, nsecs_t phaseOffset);
 
     void getDisplayStatInfo(DisplayStatInfo* stats);
 
diff --git a/services/surfaceflinger/Scheduler/VSyncModulator.cpp b/services/surfaceflinger/Scheduler/VSyncModulator.cpp
deleted file mode 100644
index 2567c04..0000000
--- a/services/surfaceflinger/Scheduler/VSyncModulator.cpp
+++ /dev/null
@@ -1,183 +0,0 @@
-/*
- * Copyright 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-// TODO(b/129481165): remove the #pragma below and fix conversion issues
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wconversion"
-
-#define ATRACE_TAG ATRACE_TAG_GRAPHICS
-
-#include "VSyncModulator.h"
-
-#include <cutils/properties.h>
-#include <utils/Trace.h>
-
-#include <chrono>
-#include <cinttypes>
-#include <mutex>
-
-namespace android::scheduler {
-
-VSyncModulator::VSyncModulator(IPhaseOffsetControl& phaseOffsetControl,
-                               Scheduler::ConnectionHandle appConnectionHandle,
-                               Scheduler::ConnectionHandle sfConnectionHandle,
-                               const OffsetsConfig& config)
-      : mPhaseOffsetControl(phaseOffsetControl),
-        mAppConnectionHandle(appConnectionHandle),
-        mSfConnectionHandle(sfConnectionHandle),
-        mOffsetsConfig(config) {
-    char value[PROPERTY_VALUE_MAX];
-    property_get("debug.sf.vsync_trace_detailed_info", value, "0");
-    mTraceDetailedInfo = atoi(value);
-}
-
-void VSyncModulator::setPhaseOffsets(const OffsetsConfig& config) {
-    std::lock_guard<std::mutex> lock(mMutex);
-    mOffsetsConfig = config;
-    updateOffsetsLocked();
-}
-
-void VSyncModulator::setTransactionStart(Scheduler::TransactionStart transactionStart) {
-    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::EarlyEnd) {
-        return;
-    }
-    mTransactionStart = transactionStart;
-    updateOffsets();
-}
-
-void VSyncModulator::onTransactionHandled() {
-    mTxnAppliedTime = std::chrono::steady_clock::now();
-    if (mTransactionStart == Scheduler::TransactionStart::Normal) return;
-    mTransactionStart = Scheduler::TransactionStart::Normal;
-    updateOffsets();
-}
-
-void VSyncModulator::onRefreshRateChangeInitiated() {
-    if (mRefreshRateChangePending) {
-        return;
-    }
-    mRefreshRateChangePending = true;
-    updateOffsets();
-}
-
-void VSyncModulator::onRefreshRateChangeCompleted() {
-    if (!mRefreshRateChangePending) {
-        return;
-    }
-    mRefreshRateChangePending = false;
-    updateOffsets();
-}
-
-void VSyncModulator::onRefreshed(bool usedRenderEngine) {
-    bool updateOffsetsNeeded = false;
-
-    // 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.
-    if ((mEarlyTxnStartTime.load() + MARGIN_FOR_TX_APPLY) < mTxnAppliedTime.load()) {
-        if (mRemainingEarlyFrameCount > 0) {
-            mRemainingEarlyFrameCount--;
-            updateOffsetsNeeded = true;
-        }
-    }
-    if (usedRenderEngine) {
-        mRemainingRenderEngineUsageCount = MIN_EARLY_GL_FRAME_COUNT_TRANSACTION;
-        updateOffsetsNeeded = true;
-    } else if (mRemainingRenderEngineUsageCount > 0) {
-        mRemainingRenderEngineUsageCount--;
-        updateOffsetsNeeded = true;
-    }
-    if (updateOffsetsNeeded) {
-        updateOffsets();
-    }
-}
-
-VSyncModulator::Offsets VSyncModulator::getOffsets() const {
-    std::lock_guard<std::mutex> lock(mMutex);
-    return mOffsets;
-}
-
-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 (mExplicitEarlyWakeup || mTransactionStart == Scheduler::TransactionStart::EarlyEnd ||
-        mRemainingEarlyFrameCount > 0 || mRefreshRateChangePending) {
-        return mOffsetsConfig.early;
-    } else if (mRemainingRenderEngineUsageCount > 0) {
-        return mOffsetsConfig.earlyGl;
-    } else {
-        return mOffsetsConfig.late;
-    }
-}
-
-void VSyncModulator::updateOffsets() {
-    std::lock_guard<std::mutex> lock(mMutex);
-    updateOffsetsLocked();
-}
-
-void VSyncModulator::updateOffsetsLocked() {
-    const Offsets& offsets = getNextOffsets();
-
-    mPhaseOffsetControl.setPhaseOffset(mSfConnectionHandle, offsets.sf);
-    mPhaseOffsetControl.setPhaseOffset(mAppConnectionHandle, offsets.app);
-
-    mOffsets = offsets;
-
-    if (!mTraceDetailedInfo) {
-        return;
-    }
-
-    const bool isEarly = &offsets == &mOffsetsConfig.early;
-    const bool isEarlyGl = &offsets == &mOffsetsConfig.earlyGl;
-    const bool isLate = &offsets == &mOffsetsConfig.late;
-
-    ATRACE_INT("Vsync-EarlyOffsetsOn", isEarly);
-    ATRACE_INT("Vsync-EarlyGLOffsetsOn", isEarlyGl);
-    ATRACE_INT("Vsync-LateOffsetsOn", isLate);
-}
-
-} // namespace android::scheduler
-
-// TODO(b/129481165): remove the #pragma below and fix conversion issues
-#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/Scheduler/VSyncModulator.h b/services/surfaceflinger/Scheduler/VSyncModulator.h
deleted file mode 100644
index ab678c9..0000000
--- a/services/surfaceflinger/Scheduler/VSyncModulator.h
+++ /dev/null
@@ -1,125 +0,0 @@
-/*
- * Copyright 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include <chrono>
-#include <mutex>
-
-#include "Scheduler.h"
-
-namespace android::scheduler {
-
-/*
- * Modulates the vsync-offsets depending on current SurfaceFlinger state.
- */
-class VSyncModulator {
-private:
-    // Number of frames we'll keep the early phase offsets once they are activated for a
-    // transaction. This acts as a low-pass filter in case the client isn't quick enough in
-    // sending new transactions.
-    static constexpr int MIN_EARLY_FRAME_COUNT_TRANSACTION = 2;
-
-    // Number of frames we'll keep the early gl phase offsets once they are activated.
-    // This acts as a low-pass filter to avoid scenarios where we rapidly
-    // switch in and out of gl composition.
-    static constexpr int MIN_EARLY_GL_FRAME_COUNT_TRANSACTION = 2;
-
-    // Margin used to account for potential data races
-    static const constexpr std::chrono::nanoseconds MARGIN_FOR_TX_APPLY = 1ms;
-
-public:
-    // Wrapper for a collection of surfaceflinger/app offsets for a particular
-    // configuration.
-    struct Offsets {
-        nsecs_t sf;
-        nsecs_t app;
-
-        bool operator==(const Offsets& other) const { return sf == other.sf && app == other.app; }
-
-        bool operator!=(const Offsets& other) const { return !(*this == other); }
-    };
-
-    struct OffsetsConfig {
-        Offsets early;   // For transactions with the eEarlyWakeup flag.
-        Offsets earlyGl; // As above but while compositing with GL.
-        Offsets late;    // Default.
-
-        bool operator==(const OffsetsConfig& other) const {
-            return early == other.early && earlyGl == other.earlyGl && late == other.late;
-        }
-
-        bool operator!=(const OffsetsConfig& other) const { return !(*this == other); }
-    };
-
-    VSyncModulator(IPhaseOffsetControl&, ConnectionHandle appConnectionHandle,
-                   ConnectionHandle sfConnectionHandle, const OffsetsConfig&);
-
-    void setPhaseOffsets(const OffsetsConfig&) EXCLUDES(mMutex);
-
-    // Signals that a transaction has started, and changes offsets accordingly.
-    void setTransactionStart(Scheduler::TransactionStart transactionStart);
-
-    // Signals that a transaction has been completed, so that we can finish
-    // special handling for a transaction.
-    void onTransactionHandled();
-
-    // Called when we send a refresh rate change to hardware composer, so that
-    // we can move into early offsets.
-    void onRefreshRateChangeInitiated();
-
-    // 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 onRefreshRateChangeCompleted();
-
-    // Called when the display is presenting a new frame. usedRenderEngine
-    // should be set to true if RenderEngine was involved with composing the new
-    // frame.
-    void onRefreshed(bool usedRenderEngine);
-
-    // Returns the offsets that we are currently using
-    Offsets getOffsets() const EXCLUDES(mMutex);
-
-private:
-    friend class VSyncModulatorTest;
-    // Returns the next offsets that we should be using
-    const Offsets& getNextOffsets() const REQUIRES(mMutex);
-    // Updates offsets and persists them into the scheduler framework.
-    void updateOffsets() EXCLUDES(mMutex);
-    void updateOffsetsLocked() REQUIRES(mMutex);
-
-    IPhaseOffsetControl& mPhaseOffsetControl;
-    const ConnectionHandle mAppConnectionHandle;
-    const ConnectionHandle mSfConnectionHandle;
-
-    mutable std::mutex mMutex;
-    OffsetsConfig mOffsetsConfig GUARDED_BY(mMutex);
-
-    Offsets mOffsets GUARDED_BY(mMutex){mOffsetsConfig.late};
-
-    std::atomic<Scheduler::TransactionStart> mTransactionStart =
-            Scheduler::TransactionStart::Normal;
-    std::atomic<bool> mRefreshRateChangePending = false;
-    std::atomic<bool> mExplicitEarlyWakeup = false;
-    std::atomic<int> mRemainingEarlyFrameCount = 0;
-    std::atomic<int> mRemainingRenderEngineUsageCount = 0;
-    std::atomic<std::chrono::steady_clock::time_point> mEarlyTxnStartTime = {};
-    std::atomic<std::chrono::steady_clock::time_point> mTxnAppliedTime = {};
-
-    bool mTraceDetailedInfo = false;
-};
-
-} // namespace android::scheduler
diff --git a/services/surfaceflinger/Scheduler/VsyncModulator.cpp b/services/surfaceflinger/Scheduler/VsyncModulator.cpp
new file mode 100644
index 0000000..7a1b7e4
--- /dev/null
+++ b/services/surfaceflinger/Scheduler/VsyncModulator.cpp
@@ -0,0 +1,163 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+
+#undef LOG_TAG
+#define LOG_TAG "VsyncModulator"
+
+#include "VsyncModulator.h"
+
+#include <android-base/properties.h>
+#include <log/log.h>
+#include <utils/Trace.h>
+
+#include <chrono>
+#include <cinttypes>
+#include <mutex>
+
+using namespace std::chrono_literals;
+
+namespace android::scheduler {
+
+const std::chrono::nanoseconds VsyncModulator::MIN_EARLY_TRANSACTION_TIME = 1ms;
+
+VsyncModulator::VsyncModulator(const OffsetsConfig& config, Now now)
+      : mOffsetsConfig(config),
+        mNow(now),
+        mTraceDetailedInfo(base::GetBoolProperty("debug.sf.vsync_trace_detailed_info", false)) {}
+
+VsyncModulator::Offsets VsyncModulator::setPhaseOffsets(const OffsetsConfig& config) {
+    std::lock_guard<std::mutex> lock(mMutex);
+    mOffsetsConfig = config;
+    return updateOffsetsLocked();
+}
+
+VsyncModulator::OffsetsOpt VsyncModulator::setTransactionSchedule(TransactionSchedule schedule) {
+    switch (schedule) {
+        case Schedule::EarlyStart:
+            ALOGW_IF(mExplicitEarlyWakeup, "%s: Duplicate EarlyStart", __FUNCTION__);
+            mExplicitEarlyWakeup = true;
+            break;
+        case Schedule::EarlyEnd:
+            ALOGW_IF(!mExplicitEarlyWakeup, "%s: Unexpected EarlyEnd", __FUNCTION__);
+            mExplicitEarlyWakeup = false;
+            break;
+        case Schedule::Early:
+        case Schedule::Late:
+            // No change to mExplicitEarlyWakeup for non-explicit states.
+            break;
+    }
+
+    if (mTraceDetailedInfo) {
+        ATRACE_INT("mExplicitEarlyWakeup", mExplicitEarlyWakeup);
+    }
+
+    if (!mExplicitEarlyWakeup && (schedule == Schedule::Early || schedule == Schedule::EarlyEnd)) {
+        mEarlyTransactionFrames = MIN_EARLY_TRANSACTION_FRAMES;
+        mEarlyTransactionStartTime = mNow();
+    }
+
+    // An early transaction stays an early transaction.
+    if (schedule == mTransactionSchedule || mTransactionSchedule == Schedule::EarlyEnd) {
+        return std::nullopt;
+    }
+    mTransactionSchedule = schedule;
+    return updateOffsets();
+}
+
+VsyncModulator::OffsetsOpt VsyncModulator::onTransactionCommit() {
+    mLastTransactionCommitTime = mNow();
+    if (mTransactionSchedule == Schedule::Late) return std::nullopt;
+    mTransactionSchedule = Schedule::Late;
+    return updateOffsets();
+}
+
+VsyncModulator::OffsetsOpt VsyncModulator::onRefreshRateChangeInitiated() {
+    if (mRefreshRateChangePending) return std::nullopt;
+    mRefreshRateChangePending = true;
+    return updateOffsets();
+}
+
+VsyncModulator::OffsetsOpt VsyncModulator::onRefreshRateChangeCompleted() {
+    if (!mRefreshRateChangePending) return std::nullopt;
+    mRefreshRateChangePending = false;
+    return updateOffsets();
+}
+
+VsyncModulator::OffsetsOpt VsyncModulator::onDisplayRefresh(bool usedGpuComposition) {
+    bool updateOffsetsNeeded = false;
+
+    if (mEarlyTransactionStartTime.load() + MIN_EARLY_TRANSACTION_TIME <=
+        mLastTransactionCommitTime.load()) {
+        if (mEarlyTransactionFrames > 0) {
+            mEarlyTransactionFrames--;
+            updateOffsetsNeeded = true;
+        }
+    }
+    if (usedGpuComposition) {
+        mEarlyGpuFrames = MIN_EARLY_GPU_FRAMES;
+        updateOffsetsNeeded = true;
+    } else if (mEarlyGpuFrames > 0) {
+        mEarlyGpuFrames--;
+        updateOffsetsNeeded = true;
+    }
+
+    if (!updateOffsetsNeeded) return std::nullopt;
+    return updateOffsets();
+}
+
+VsyncModulator::Offsets VsyncModulator::getOffsets() const {
+    std::lock_guard<std::mutex> lock(mMutex);
+    return mOffsets;
+}
+
+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 (mExplicitEarlyWakeup || mTransactionSchedule == Schedule::EarlyEnd ||
+        mEarlyTransactionFrames > 0 || mRefreshRateChangePending) {
+        return mOffsetsConfig.early;
+    } else if (mEarlyGpuFrames > 0) {
+        return mOffsetsConfig.earlyGpu;
+    } else {
+        return mOffsetsConfig.late;
+    }
+}
+
+VsyncModulator::Offsets VsyncModulator::updateOffsets() {
+    std::lock_guard<std::mutex> lock(mMutex);
+    return updateOffsetsLocked();
+}
+
+VsyncModulator::Offsets VsyncModulator::updateOffsetsLocked() {
+    const Offsets& offsets = getNextOffsets();
+    mOffsets = offsets;
+
+    if (mTraceDetailedInfo) {
+        const bool isEarly = &offsets == &mOffsetsConfig.early;
+        const bool isEarlyGpu = &offsets == &mOffsetsConfig.earlyGpu;
+        const bool isLate = &offsets == &mOffsetsConfig.late;
+
+        ATRACE_INT("Vsync-EarlyOffsetsOn", isEarly);
+        ATRACE_INT("Vsync-EarlyGpuOffsetsOn", isEarlyGpu);
+        ATRACE_INT("Vsync-LateOffsetsOn", isLate);
+    }
+
+    return offsets;
+}
+
+} // namespace android::scheduler
diff --git a/services/surfaceflinger/Scheduler/VsyncModulator.h b/services/surfaceflinger/Scheduler/VsyncModulator.h
new file mode 100644
index 0000000..f920bd2
--- /dev/null
+++ b/services/surfaceflinger/Scheduler/VsyncModulator.h
@@ -0,0 +1,123 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <chrono>
+#include <mutex>
+#include <optional>
+
+#include <android-base/thread_annotations.h>
+#include <utils/Timers.h>
+
+namespace android::scheduler {
+
+// State machine controlled by transaction flags. VsyncModulator switches to early phase offsets
+// when a transaction is flagged EarlyStart or Early, lasting until an EarlyEnd transaction or a
+// fixed number of frames, respectively.
+enum class TransactionSchedule {
+    Late,  // Default.
+    Early, // Deprecated.
+    EarlyStart,
+    EarlyEnd
+};
+
+// Modulates VSYNC phase depending on transaction schedule and refresh rate changes.
+class VsyncModulator {
+public:
+    // Number of frames to keep early offsets after an early transaction or GPU composition.
+    // This acts as a low-pass filter in case subsequent transactions are delayed, or if the
+    // composition strategy alternates on subsequent frames.
+    static constexpr int MIN_EARLY_TRANSACTION_FRAMES = 2;
+    static constexpr int MIN_EARLY_GPU_FRAMES = 2;
+
+    // Duration to delay the MIN_EARLY_TRANSACTION_FRAMES countdown after an early transaction.
+    // This may keep early offsets for an extra frame, but avoids a race with transaction commit.
+    static const std::chrono::nanoseconds MIN_EARLY_TRANSACTION_TIME;
+
+    // Phase offsets for SF and app deadlines from VSYNC.
+    struct Offsets {
+        nsecs_t sf;
+        nsecs_t app;
+
+        bool operator==(const Offsets& other) const { return sf == other.sf && app == other.app; }
+        bool operator!=(const Offsets& other) const { return !(*this == other); }
+    };
+
+    using OffsetsOpt = std::optional<Offsets>;
+
+    struct OffsetsConfig {
+        Offsets early;    // Used for early transactions, and during refresh rate change.
+        Offsets earlyGpu; // Used during GPU composition.
+        Offsets late;     // Default.
+
+        bool operator==(const OffsetsConfig& other) const {
+            return early == other.early && earlyGpu == other.earlyGpu && late == other.late;
+        }
+
+        bool operator!=(const OffsetsConfig& other) const { return !(*this == other); }
+    };
+
+    using Clock = std::chrono::steady_clock;
+    using TimePoint = Clock::time_point;
+    using Now = TimePoint (*)();
+
+    explicit VsyncModulator(const OffsetsConfig&, Now = Clock::now);
+
+    Offsets getOffsets() const EXCLUDES(mMutex);
+
+    [[nodiscard]] Offsets setPhaseOffsets(const OffsetsConfig&) EXCLUDES(mMutex);
+
+    // Changes offsets in response to transaction flags or commit.
+    [[nodiscard]] OffsetsOpt setTransactionSchedule(TransactionSchedule);
+    [[nodiscard]] OffsetsOpt onTransactionCommit();
+
+    // Called when we send a refresh rate change to hardware composer, so that
+    // we can move into early offsets.
+    [[nodiscard]] OffsetsOpt onRefreshRateChangeInitiated();
+
+    // 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.
+    [[nodiscard]] OffsetsOpt onRefreshRateChangeCompleted();
+
+    [[nodiscard]] OffsetsOpt onDisplayRefresh(bool usedGpuComposition);
+
+private:
+    const Offsets& getNextOffsets() const REQUIRES(mMutex);
+    [[nodiscard]] Offsets updateOffsets() EXCLUDES(mMutex);
+    [[nodiscard]] Offsets updateOffsetsLocked() REQUIRES(mMutex);
+
+    mutable std::mutex mMutex;
+    OffsetsConfig mOffsetsConfig GUARDED_BY(mMutex);
+
+    Offsets mOffsets GUARDED_BY(mMutex){mOffsetsConfig.late};
+
+    using Schedule = TransactionSchedule;
+    std::atomic<Schedule> mTransactionSchedule = Schedule::Late;
+    std::atomic<bool> mExplicitEarlyWakeup = false;
+
+    std::atomic<bool> mRefreshRateChangePending = false;
+
+    std::atomic<int> mEarlyTransactionFrames = 0;
+    std::atomic<int> mEarlyGpuFrames = 0;
+    std::atomic<TimePoint> mEarlyTransactionStartTime = TimePoint();
+    std::atomic<TimePoint> mLastTransactionCommitTime = TimePoint();
+
+    const Now mNow;
+    const bool mTraceDetailedInfo;
+};
+
+} // namespace android::scheduler
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index ca9f629..b35c68d 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -862,8 +862,9 @@
     state->layerStack = display->getLayerStack();
     state->orientation = display->getOrientation();
 
-    const Rect viewport = display->getViewport();
-    state->viewport = viewport.isValid() ? viewport.getSize() : display->getSize();
+    const Rect layerStackRect = display->getLayerStackSpaceRect();
+    state->layerStackSpaceRect =
+            layerStackRect.isValid() ? layerStackRect.getSize() : display->getSize();
 
     return NO_ERROR;
 }
@@ -1036,10 +1037,9 @@
         mScheduler->resyncToHardwareVsync(true, refreshRate.getVsyncPeriod());
         // As we called to set period, we will call to onRefreshRateChangeCompleted once
         // DispSync model is locked.
-        mVSyncModulator->onRefreshRateChangeInitiated();
+        modulateVsync(&VsyncModulator::onRefreshRateChangeInitiated);
 
-        mPhaseConfiguration->setRefreshRateFps(refreshRate.getFps());
-        mVSyncModulator->setPhaseOffsets(mPhaseConfiguration->getCurrentOffsets());
+        updatePhaseConfiguration(refreshRate);
         mScheduler->setConfigChangePending(true);
     }
 
@@ -1098,8 +1098,7 @@
     if (refreshRate.getVsyncPeriod() != oldRefreshRate.getVsyncPeriod()) {
         mTimeStats->incrementRefreshRateSwitches();
     }
-    mPhaseConfiguration->setRefreshRateFps(refreshRate.getFps());
-    mVSyncModulator->setPhaseOffsets(mPhaseConfiguration->getCurrentOffsets());
+    updatePhaseConfiguration(refreshRate);
     ATRACE_INT("ActiveConfigFPS", refreshRate.getFps());
 
     if (mUpcomingActiveConfig.event != Scheduler::ConfigEvent::None) {
@@ -1119,9 +1118,9 @@
 
     const auto& refreshRate =
             mRefreshRateConfigs->getRefreshRateFromConfigId(mDesiredActiveConfig.configId);
+
     mScheduler->resyncToHardwareVsync(true, refreshRate.getVsyncPeriod());
-    mPhaseConfiguration->setRefreshRateFps(refreshRate.getFps());
-    mVSyncModulator->setPhaseOffsets(mPhaseConfiguration->getCurrentOffsets());
+    updatePhaseConfiguration(refreshRate);
     mScheduler->setConfigChangePending(false);
 }
 
@@ -1600,7 +1599,7 @@
     bool periodFlushed = false;
     mScheduler->addResyncSample(timestamp, vsyncPeriod, &periodFlushed);
     if (periodFlushed) {
-        mVSyncModulator->onRefreshRateChangeCompleted();
+        modulateVsync(&VsyncModulator::onRefreshRateChangeCompleted);
     }
 }
 
@@ -1790,7 +1789,7 @@
     // We are storing the last 2 present fences. If sf's phase offset is to be
     // woken up before the actual vsync but targeting the next vsync, we need to check
     // fence N-2
-    return mVSyncModulator->getOffsets().sf > 0 ? mPreviousPresentFences[0]
+    return mVsyncModulator->getOffsets().sf > 0 ? mPreviousPresentFences[0]
                                                 : mPreviousPresentFences[1];
 }
 
@@ -1823,7 +1822,7 @@
     mScheduler->getDisplayStatInfo(&stats);
     const nsecs_t presentTime = mScheduler->getDispSyncExpectedPresentTime(now);
     // Inflate the expected present time if we're targetting the next vsync.
-    return mVSyncModulator->getOffsets().sf > 0 ? presentTime : presentTime + stats.vsyncPeriod;
+    return mVsyncModulator->getOffsets().sf > 0 ? presentTime : presentTime + stats.vsyncPeriod;
 }
 
 void SurfaceFlinger::onMessageReceived(int32_t what, nsecs_t expectedVSyncTime) {
@@ -2120,7 +2119,8 @@
     }
 
     // TODO: b/160583065 Enable skip validation when SF caches all client composition layers
-    mVSyncModulator->onRefreshed(mHadClientComposition || mReusedClientComposition);
+    const bool usedGpuComposition = mHadClientComposition || mReusedClientComposition;
+    modulateVsync(&VsyncModulator::onDisplayRefresh, usedGpuComposition);
 
     mLayersWithQueuedFrames.clear();
     if (mVisibleRegionsDirty) {
@@ -2368,7 +2368,7 @@
 }
 
 FloatRect SurfaceFlinger::getLayerClipBoundsForDisplay(const DisplayDevice& displayDevice) const {
-    return displayDevice.getViewport().toFloatRect();
+    return displayDevice.getLayerStackSpaceRect().toFloatRect();
 }
 
 void SurfaceFlinger::computeLayerBounds() {
@@ -2416,7 +2416,7 @@
     // with mStateLock held to guarantee that mCurrentState won't change
     // until the transaction is committed.
 
-    mVSyncModulator->onTransactionHandled();
+    modulateVsync(&VsyncModulator::onTransactionCommit);
     transactionFlags = getTransactionFlags(eTransactionMask);
     handleTransactionLocked(transactionFlags);
 
@@ -2569,7 +2569,8 @@
     }
 
     display->setLayerStack(state.layerStack);
-    display->setProjection(state.orientation, state.viewport, state.frame);
+    display->setProjection(state.orientation, state.layerStackSpaceRect,
+                           state.orientedDisplaySpaceRect);
     display->setDisplayName(state.displayName);
 
     return display;
@@ -2698,10 +2699,10 @@
             display->setLayerStack(currentState.layerStack);
         }
         if ((currentState.orientation != drawingState.orientation) ||
-            (currentState.viewport != drawingState.viewport) ||
-            (currentState.frame != drawingState.frame)) {
-            display->setProjection(currentState.orientation, currentState.viewport,
-                                   currentState.frame);
+            (currentState.layerStackSpaceRect != drawingState.layerStackSpaceRect) ||
+            (currentState.orientedDisplaySpaceRect != drawingState.orientedDisplaySpaceRect)) {
+            display->setProjection(currentState.orientation, currentState.layerStackSpaceRect,
+                                   currentState.orientedDisplaySpaceRect);
         }
         if (currentState.width != drawingState.width ||
             currentState.height != drawingState.height) {
@@ -2977,6 +2978,7 @@
     mRefreshRateStats->setConfigMode(currentConfig);
 
     mPhaseConfiguration = getFactory().createPhaseConfiguration(*mRefreshRateConfigs);
+    mVsyncModulator.emplace(mPhaseConfiguration->getCurrentOffsets());
 
     // start the EventThread
     mScheduler = getFactory().createScheduler(*mRefreshRateConfigs, *this);
@@ -2990,8 +2992,6 @@
                                          });
 
     mEventQueue->setEventConnection(mScheduler->getEventConnection(mSfConnectionHandle));
-    mVSyncModulator.emplace(*mScheduler, mAppConnectionHandle, mSfConnectionHandle,
-                            mPhaseConfiguration->getCurrentOffsets());
 
     mRegionSamplingThread =
             new RegionSamplingThread(*this, *mScheduler,
@@ -3009,8 +3009,17 @@
                                               vsyncPeriod);
 }
 
-void SurfaceFlinger::commitTransaction()
-{
+void SurfaceFlinger::updatePhaseConfiguration(const RefreshRate& refreshRate) {
+    mPhaseConfiguration->setRefreshRateFps(refreshRate.getFps());
+    setPhaseOffsets(mVsyncModulator->setPhaseOffsets(mPhaseConfiguration->getCurrentOffsets()));
+}
+
+void SurfaceFlinger::setPhaseOffsets(const VsyncModulator::Offsets& offsets) {
+    mScheduler->setPhaseOffset(mAppConnectionHandle, offsets.app);
+    mScheduler->setPhaseOffset(mSfConnectionHandle, offsets.sf);
+}
+
+void SurfaceFlinger::commitTransaction() {
     commitTransactionLocked();
     mTransactionPending = false;
     mAnimTransactionPending = false;
@@ -3046,15 +3055,19 @@
     // clear the "changed" flags in current state
     mCurrentState.colorMatrixChanged = false;
 
-    mDrawingState.traverse([&](Layer* layer) {
-        layer->commitChildList();
-
-        // If the layer can be reached when traversing mDrawingState, then the layer is no
-        // longer offscreen. Remove the layer from the offscreenLayer set.
-        if (mOffscreenLayers.count(layer)) {
-            mOffscreenLayers.erase(layer);
-        }
-    });
+    for (const auto& rootLayer : mDrawingState.layersSortedByZ) {
+        rootLayer->commitChildList();
+    }
+    // TODO(b/163019109): See if this traversal is needed at all...
+    if (!mOffscreenLayers.empty()) {
+        mDrawingState.traverse([&](Layer* layer) {
+            // If the layer can be reached when traversing mDrawingState, then the layer is no
+            // longer offscreen. Remove the layer from the offscreenLayer set.
+            if (mOffscreenLayers.count(layer)) {
+                mOffscreenLayers.erase(layer);
+            }
+        });
+    }
 
     commitOffscreenLayers();
     mDrawingState.traverse([&](Layer* layer) { layer->updateMirrorInfo(); });
@@ -3250,16 +3263,13 @@
 }
 
 uint32_t SurfaceFlinger::setTransactionFlags(uint32_t flags) {
-    return setTransactionFlags(flags, Scheduler::TransactionStart::Normal);
+    return setTransactionFlags(flags, TransactionSchedule::Late);
 }
 
-uint32_t SurfaceFlinger::setTransactionFlags(uint32_t flags,
-                                             Scheduler::TransactionStart transactionStart) {
+uint32_t SurfaceFlinger::setTransactionFlags(uint32_t flags, TransactionSchedule schedule) {
     uint32_t old = mTransactionFlags.fetch_or(flags);
-    mVSyncModulator->setTransactionStart(transactionStart);
-    if ((old & flags)==0) { // wake the server up
-        signalTransaction();
-    }
+    modulateVsync(&VsyncModulator::setTransactionSchedule, schedule);
+    if ((old & flags) == 0) signalTransaction();
     return old;
 }
 
@@ -3292,7 +3302,8 @@
                                       mPendingInputWindowCommands, transaction.desiredPresentTime,
                                       transaction.buffer, transaction.postTime,
                                       transaction.privileged, transaction.hasListenerCallbacks,
-                                      transaction.listenerCallbacks, /*isMainThread*/ true);
+                                      transaction.listenerCallbacks, transaction.originPID,
+                                      transaction.originUID, /*isMainThread*/ true);
                 transactionQueue.pop();
                 flushedATransaction = true;
             }
@@ -3372,17 +3383,22 @@
         mExpectedPresentTime = calculateExpectedPresentTime(systemTime());
     }
 
+    IPCThreadState* ipc = IPCThreadState::self();
+    const int originPID = ipc->getCallingPid();
+    const int originUID = ipc->getCallingUid();
+
     if (pendingTransactions || !transactionIsReadyToBeApplied(desiredPresentTime, states)) {
         mTransactionQueues[applyToken].emplace(states, displays, flags, desiredPresentTime,
                                                uncacheBuffer, postTime, privileged,
-                                               hasListenerCallbacks, listenerCallbacks);
+                                               hasListenerCallbacks, listenerCallbacks, originPID,
+                                               originUID);
         setTransactionFlags(eTransactionFlushNeeded);
         return;
     }
 
     applyTransactionState(states, displays, flags, inputWindowCommands, desiredPresentTime,
                           uncacheBuffer, postTime, privileged, hasListenerCallbacks,
-                          listenerCallbacks);
+                          listenerCallbacks, originPID, originUID, /*isMainThread*/ false);
 }
 
 void SurfaceFlinger::applyTransactionState(
@@ -3390,7 +3406,7 @@
         const InputWindowCommands& inputWindowCommands, const int64_t desiredPresentTime,
         const client_cache_t& uncacheBuffer, const int64_t postTime, bool privileged,
         bool hasListenerCallbacks, const std::vector<ListenerCallbacks>& listenerCallbacks,
-        bool isMainThread) {
+        int originPID, int originUID, bool isMainThread) {
     uint32_t transactionFlags = 0;
 
     if (flags & eAnimation) {
@@ -3467,22 +3483,17 @@
         mForceTraversal = true;
     }
 
-    const auto transactionStart = [](uint32_t flags) {
-        if (flags & eEarlyWakeup) {
-            return Scheduler::TransactionStart::Early;
-        }
-        if (flags & eExplicitEarlyWakeupEnd) {
-            return Scheduler::TransactionStart::EarlyEnd;
-        }
-        if (flags & eExplicitEarlyWakeupStart) {
-            return Scheduler::TransactionStart::EarlyStart;
-        }
-        return Scheduler::TransactionStart::Normal;
+    const auto schedule = [](uint32_t flags) {
+        if (flags & eEarlyWakeup) return TransactionSchedule::Early;
+        if (flags & eExplicitEarlyWakeupEnd) return TransactionSchedule::EarlyEnd;
+        if (flags & eExplicitEarlyWakeupStart) return TransactionSchedule::EarlyStart;
+        return TransactionSchedule::Late;
     }(flags);
 
     if (transactionFlags) {
         if (mInterceptor->isEnabled()) {
-            mInterceptor->saveTransaction(states, mCurrentState.displays, displays, flags);
+            mInterceptor->saveTransaction(states, mCurrentState.displays, displays, flags,
+                                          originPID, originUID);
         }
 
         // TODO(b/159125966): Remove eEarlyWakeup completly as no client should use this flag
@@ -3496,7 +3507,7 @@
         }
 
         // this triggers the transaction
-        setTransactionFlags(transactionFlags, transactionStart);
+        setTransactionFlags(transactionFlags, schedule);
 
         if (flags & eAnimation) {
             mAnimTransactionPending = true;
@@ -3534,11 +3545,10 @@
             }
         }
     } else {
-        // even if a transaction is not needed, we need to update VsyncModulator
-        // about explicit early indications
-        if (transactionStart == Scheduler::TransactionStart::EarlyStart ||
-            transactionStart == Scheduler::TransactionStart::EarlyEnd) {
-            mVSyncModulator->setTransactionStart(transactionStart);
+        // Update VsyncModulator state machine even if transaction is not needed.
+        if (schedule == TransactionSchedule::EarlyStart ||
+            schedule == TransactionSchedule::EarlyEnd) {
+            modulateVsync(&VsyncModulator::setTransactionSchedule, schedule);
         }
     }
 }
@@ -3568,12 +3578,12 @@
             state.orientation = s.orientation;
             flags |= eDisplayTransactionNeeded;
         }
-        if (state.frame != s.frame) {
-            state.frame = s.frame;
+        if (state.orientedDisplaySpaceRect != s.orientedDisplaySpaceRect) {
+            state.orientedDisplaySpaceRect = s.orientedDisplaySpaceRect;
             flags |= eDisplayTransactionNeeded;
         }
-        if (state.viewport != s.viewport) {
-            state.viewport = s.viewport;
+        if (state.layerStackSpaceRect != s.layerStackSpaceRect) {
+            state.layerStackSpaceRect = s.layerStackSpaceRect;
             flags |= eDisplayTransactionNeeded;
         }
     }
@@ -3808,7 +3818,7 @@
         if (layer->setCrop(s.crop)) flags |= eTraversalNeeded;
     }
     if (what & layer_state_t::eFrameChanged) {
-        if (layer->setFrame(s.frame)) flags |= eTraversalNeeded;
+        if (layer->setFrame(s.orientedDisplaySpaceRect)) flags |= eTraversalNeeded;
     }
     if (what & layer_state_t::eAcquireFenceChanged) {
         if (layer->setAcquireFence(s.acquireFence)) flags |= eTraversalNeeded;
@@ -4191,8 +4201,8 @@
     d.token = token;
     d.layerStack = 0;
     d.orientation = ui::ROTATION_0;
-    d.frame.makeInvalid();
-    d.viewport.makeInvalid();
+    d.orientedDisplaySpaceRect.makeInvalid();
+    d.layerStackSpaceRect.makeInvalid();
     d.width = 0;
     d.height = 0;
     displays.add(d);
@@ -5476,10 +5486,9 @@
         displayWeak = display;
         layerStack = display->getLayerStack();
 
-        // set the requested width/height to the logical display viewport size
-        // by default
+        // set the requested width/height to the logical display layer stack rect size by default
         if (args.width == 0 || args.height == 0) {
-            reqSize = display->getViewport().getSize();
+            reqSize = display->getLayerStackSpaceRect().getSize();
         }
 
         const ui::ColorMode colorMode = display->getCompositionDisplay()->getState().colorMode;
@@ -5552,7 +5561,7 @@
         layerStack = display->getLayerStack();
         displayWeak = display;
 
-        size = display->getViewport().getSize();
+        size = display->getLayerStackSpaceRect().getSize();
 
         dataspace =
                 pickDataspaceFromColorMode(display->getCompositionDisplay()->getState().colorMode);
@@ -5586,7 +5595,7 @@
     sp<Layer> parent;
     Rect crop(args.sourceCrop);
     std::unordered_set<sp<Layer>, ISurfaceComposer::SpHash<Layer>> excludeLayers;
-    Rect displayViewport;
+    Rect layerStackSpaceRect;
     ui::Dataspace dataspace;
     bool captureSecureLayers;
     {
@@ -5638,7 +5647,7 @@
             return NAME_NOT_FOUND;
         }
 
-        displayViewport = display->getViewport();
+        layerStackSpaceRect = display->getLayerStackSpaceRect();
 
         const ui::ColorMode colorMode = display->getCompositionDisplay()->getState().colorMode;
         dataspace = pickDataspaceFromColorMode(colorMode);
@@ -5657,7 +5666,7 @@
     bool childrenOnly = args.childrenOnly;
     RenderAreaFuture renderAreaFuture = promise::defer([=]() -> std::unique_ptr<RenderArea> {
         return std::make_unique<LayerRenderArea>(*this, parent, crop, reqSize, dataspace,
-                                                 childrenOnly, displayViewport,
+                                                 childrenOnly, layerStackSpaceRect,
                                                  captureSecureLayers);
     });
 
@@ -5778,7 +5787,7 @@
     const auto sourceCrop = renderArea.getSourceCrop();
     const auto transform = renderArea.getTransform();
     const auto rotation = renderArea.getRotationFlags();
-    const auto& displayViewport = renderArea.getDisplayViewport();
+    const auto& layerStackSpaceRect = renderArea.getLayerStackSpaceRect();
 
     renderengine::DisplaySettings clientCompositionDisplay;
     std::vector<compositionengine::LayerFE::LayerSettings> clientCompositionLayers;
@@ -5815,7 +5824,7 @@
                 renderArea.isSecure(),
                 supportProtectedContent,
                 clearRegion,
-                displayViewport,
+                layerStackSpaceRect,
                 clientCompositionDisplay.outputDataspace,
                 true,  /* realContentIsVisible */
                 false, /* clearContent */
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 1acfda9..3c24158 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -58,7 +58,7 @@
 #include "Scheduler/RefreshRateConfigs.h"
 #include "Scheduler/RefreshRateStats.h"
 #include "Scheduler/Scheduler.h"
-#include "Scheduler/VSyncModulator.h"
+#include "Scheduler/VsyncModulator.h"
 #include "SurfaceFlingerFactory.h"
 #include "SurfaceTracing.h"
 #include "TracedOrdinal.h"
@@ -549,8 +549,6 @@
     void signalLayerUpdate();
     void signalRefresh();
 
-    using RefreshRate = scheduler::RefreshRateConfigs::RefreshRate;
-
     struct ActiveConfigInfo {
         HwcConfigIndexType configId;
         Scheduler::ConfigEvent event = Scheduler::ConfigEvent::None;
@@ -604,7 +602,13 @@
     void updateInputWindowInfo();
     void commitInputWindowCommands() REQUIRES(mStateLock);
     void updateCursorAsync();
+
+    using RefreshRate = scheduler::RefreshRateConfigs::RefreshRate;
+    using VsyncModulator = scheduler::VsyncModulator;
+
     void initScheduler(PhysicalDisplayId primaryDisplayId);
+    void updatePhaseConfiguration(const RefreshRate&);
+    void setPhaseOffsets(const VsyncModulator::Offsets&);
 
     /* handlePageFlip - latch a new buffer if available and compute the dirty
      * region. Returns whether a new buffer has been latched, i.e., whether it
@@ -615,6 +619,8 @@
     /* ------------------------------------------------------------------------
      * Transactions
      */
+    using TransactionSchedule = scheduler::TransactionSchedule;
+
     void applyTransactionState(const Vector<ComposerState>& state,
                                const Vector<DisplayState>& displays, uint32_t flags,
                                const InputWindowCommands& inputWindowCommands,
@@ -622,7 +628,8 @@
                                const client_cache_t& uncacheBuffer, const int64_t postTime,
                                bool privileged, bool hasListenerCallbacks,
                                const std::vector<ListenerCallbacks>& listenerCallbacks,
-                               bool isMainThread = false) REQUIRES(mStateLock);
+                               int originPID, int originUID, bool isMainThread = false)
+            REQUIRES(mStateLock);
     // Returns true if at least one transaction was flushed
     bool flushTransactionQueues();
     // Returns true if there is at least one transaction that needs to be flushed
@@ -637,7 +644,7 @@
     // but there is no need to try and wake up immediately to do it. Rather we rely on
     // onFrameAvailable or another layer update to wake us up.
     void setTraversalNeeded();
-    uint32_t setTransactionFlags(uint32_t flags, Scheduler::TransactionStart transactionStart);
+    uint32_t setTransactionFlags(uint32_t flags, TransactionSchedule);
     void commitTransaction() REQUIRES(mStateLock);
     void commitOffscreenLayers();
     bool transactionIsReadyToBeApplied(int64_t desiredPresentTime,
@@ -842,14 +849,13 @@
     void dispatchDisplayHotplugEvent(PhysicalDisplayId displayId, bool connected);
 
     /* ------------------------------------------------------------------------
-     * VSync
+     * VSYNC
      */
     nsecs_t getVsyncPeriodFromHWC() const REQUIRES(mStateLock);
 
     // Sets the refresh rate by switching active configs, if they are available for
     // the desired refresh rate.
-    void changeRefreshRateLocked(const RefreshRate&, Scheduler::ConfigEvent event)
-            REQUIRES(mStateLock);
+    void changeRefreshRateLocked(const RefreshRate&, Scheduler::ConfigEvent) REQUIRES(mStateLock);
 
     bool isDisplayConfigAllowed(HwcConfigIndexType configId) const REQUIRES(mStateLock);
 
@@ -1129,7 +1135,8 @@
                          const Vector<DisplayState>& displayStates, uint32_t transactionFlags,
                          int64_t desiredPresentTime, const client_cache_t& uncacheBuffer,
                          int64_t postTime, bool privileged, bool hasListenerCallbacks,
-                         std::vector<ListenerCallbacks> listenerCallbacks)
+                         std::vector<ListenerCallbacks> listenerCallbacks, int originPID,
+                         int originUID)
               : states(composerStates),
                 displays(displayStates),
                 flags(transactionFlags),
@@ -1138,7 +1145,9 @@
                 postTime(postTime),
                 privileged(privileged),
                 hasListenerCallbacks(hasListenerCallbacks),
-                listenerCallbacks(listenerCallbacks) {}
+                listenerCallbacks(listenerCallbacks),
+                originPID(originPID),
+                originUID(originUID) {}
 
         Vector<ComposerState> states;
         Vector<DisplayState> displays;
@@ -1149,6 +1158,8 @@
         bool privileged;
         bool hasListenerCallbacks;
         std::vector<ListenerCallbacks> listenerCallbacks;
+        int originPID;
+        int originUID;
     };
     std::unordered_map<sp<IBinder>, std::queue<TransactionState>, IListenerHash> mTransactionQueues;
 
@@ -1205,8 +1216,8 @@
     // Stores phase offsets configured per refresh rate.
     std::unique_ptr<scheduler::PhaseConfiguration> mPhaseConfiguration;
 
-    // Optional to defer construction until scheduler connections are created.
-    std::optional<scheduler::VSyncModulator> mVSyncModulator;
+    // Optional to defer construction until PhaseConfiguration is created.
+    std::optional<scheduler::VsyncModulator> mVsyncModulator;
 
     std::unique_ptr<scheduler::RefreshRateConfigs> mRefreshRateConfigs;
     std::unique_ptr<scheduler::RefreshRateStats> mRefreshRateStats;
@@ -1214,6 +1225,14 @@
     std::atomic<nsecs_t> mExpectedPresentTime = 0;
     hal::Vsync mHWCVsyncPendingState = hal::Vsync::DISABLE;
 
+    template <typename... Args,
+              typename Handler = VsyncModulator::OffsetsOpt (VsyncModulator::*)(Args...)>
+    void modulateVsync(Handler handler, Args... args) {
+        if (const auto offsets = (*mVsyncModulator.*handler)(args...)) {
+            setPhaseOffsets(*offsets);
+        }
+    }
+
     /* ------------------------------------------------------------------------
      * Generic Layer Metadata
      */
diff --git a/services/surfaceflinger/SurfaceInterceptor.cpp b/services/surfaceflinger/SurfaceInterceptor.cpp
index 80102bd..c15d0df 100644
--- a/services/surfaceflinger/SurfaceInterceptor.cpp
+++ b/services/surfaceflinger/SurfaceInterceptor.cpp
@@ -143,7 +143,7 @@
     addDisplayLayerStackLocked(transaction, display.sequenceId, display.layerStack);
     addDisplaySizeLocked(transaction, display.sequenceId, display.width, display.height);
     addDisplayProjectionLocked(transaction, display.sequenceId, toRotationInt(display.orientation),
-                               display.viewport, display.frame);
+                               display.layerStackSpaceRect, display.orientedDisplaySpaceRect);
 }
 
 status_t SurfaceInterceptor::writeProtoFileLocked() {
@@ -221,6 +221,13 @@
     protoRect->set_bottom(rect.bottom);
 }
 
+void SurfaceInterceptor::setTransactionOriginLocked(Transaction* transaction, int32_t pid,
+                                                    int32_t uid) {
+    Origin* origin(transaction->mutable_origin());
+    origin->set_pid(pid);
+    origin->set_uid(uid);
+}
+
 void SurfaceInterceptor::addPositionLocked(Transaction* transaction, int32_t layerId,
         float x, float y)
 {
@@ -483,18 +490,20 @@
     }
     if (state.what & DisplayState::eDisplayProjectionChanged) {
         addDisplayProjectionLocked(transaction, sequenceId, toRotationInt(state.orientation),
-                                   state.viewport, state.frame);
+                                   state.layerStackSpaceRect, state.orientedDisplaySpaceRect);
     }
 }
 
-void SurfaceInterceptor::addTransactionLocked(Increment* increment,
-        const Vector<ComposerState>& stateUpdates,
-        const DefaultKeyedVector< wp<IBinder>, DisplayDeviceState>& displays,
-        const Vector<DisplayState>& changedDisplays, uint32_t transactionFlags)
-{
+void SurfaceInterceptor::addTransactionLocked(
+        Increment* increment, const Vector<ComposerState>& stateUpdates,
+        const DefaultKeyedVector<wp<IBinder>, DisplayDeviceState>& displays,
+        const Vector<DisplayState>& changedDisplays, uint32_t transactionFlags, int originPID,
+        int originUID) {
     Transaction* transaction(increment->mutable_transaction());
     transaction->set_synchronous(transactionFlags & BnSurfaceComposer::eSynchronous);
     transaction->set_animation(transactionFlags & BnSurfaceComposer::eAnimation);
+    setTransactionOriginLocked(transaction, originPID, originUID);
+
     for (const auto& compState: stateUpdates) {
         addSurfaceChangesLocked(transaction, compState.state);
     }
@@ -613,17 +622,17 @@
     powerModeUpdate->set_mode(mode);
 }
 
-void SurfaceInterceptor::saveTransaction(const Vector<ComposerState>& stateUpdates,
-        const DefaultKeyedVector< wp<IBinder>, DisplayDeviceState>& displays,
-        const Vector<DisplayState>& changedDisplays, uint32_t flags)
-{
+void SurfaceInterceptor::saveTransaction(
+        const Vector<ComposerState>& stateUpdates,
+        const DefaultKeyedVector<wp<IBinder>, DisplayDeviceState>& displays,
+        const Vector<DisplayState>& changedDisplays, uint32_t flags, int originPID, int originUID) {
     if (!mEnabled || (stateUpdates.size() <= 0 && changedDisplays.size() <= 0)) {
         return;
     }
     ATRACE_CALL();
     std::lock_guard<std::mutex> protoGuard(mTraceMutex);
     addTransactionLocked(createTraceIncrementLocked(), stateUpdates, displays, changedDisplays,
-            flags);
+                         flags, originPID, originUID);
 }
 
 void SurfaceInterceptor::saveSurfaceCreation(const sp<const Layer>& layer) {
diff --git a/services/surfaceflinger/SurfaceInterceptor.h b/services/surfaceflinger/SurfaceInterceptor.h
index 896bdcc..1798b5a 100644
--- a/services/surfaceflinger/SurfaceInterceptor.h
+++ b/services/surfaceflinger/SurfaceInterceptor.h
@@ -62,7 +62,8 @@
     virtual void saveTransaction(
             const Vector<ComposerState>& stateUpdates,
             const DefaultKeyedVector<wp<IBinder>, DisplayDeviceState>& displays,
-            const Vector<DisplayState>& changedDisplays, uint32_t flags) = 0;
+            const Vector<DisplayState>& changedDisplays, uint32_t flags, int originPID,
+            int originUID) = 0;
 
     // Intercept surface data
     virtual void saveSurfaceCreation(const sp<const Layer>& layer) = 0;
@@ -97,7 +98,8 @@
     // Intercept display and surface transactions
     void saveTransaction(const Vector<ComposerState>& stateUpdates,
                          const DefaultKeyedVector<wp<IBinder>, DisplayDeviceState>& displays,
-                         const Vector<DisplayState>& changedDisplays, uint32_t flags) override;
+                         const Vector<DisplayState>& changedDisplays, uint32_t flags, int originPID,
+                         int originUID) override;
 
     // Intercept surface data
     void saveSurfaceCreation(const sp<const Layer>& layer) override;
@@ -160,8 +162,9 @@
             int32_t overrideScalingMode);
     void addSurfaceChangesLocked(Transaction* transaction, const layer_state_t& state);
     void addTransactionLocked(Increment* increment, const Vector<ComposerState>& stateUpdates,
-            const DefaultKeyedVector< wp<IBinder>, DisplayDeviceState>& displays,
-            const Vector<DisplayState>& changedDisplays, uint32_t transactionFlags);
+                              const DefaultKeyedVector<wp<IBinder>, DisplayDeviceState>& displays,
+                              const Vector<DisplayState>& changedDisplays,
+                              uint32_t transactionFlags, int originPID, int originUID);
     void addReparentLocked(Transaction* transaction, int32_t layerId, int32_t parentId);
     void addReparentChildrenLocked(Transaction* transaction, int32_t layerId, int32_t parentId);
     void addDetachChildrenLocked(Transaction* transaction, int32_t layerId, bool detached);
@@ -182,6 +185,8 @@
     void addDisplayChangesLocked(Transaction* transaction,
             const DisplayState& state, int32_t sequenceId);
 
+    // Add transaction origin to trace
+    void setTransactionOriginLocked(Transaction* transaction, int32_t pid, int32_t uid);
 
     bool mEnabled {false};
     std::string mOutputFileName {DEFAULT_FILENAME};
diff --git a/services/surfaceflinger/tests/MultiDisplayLayerBounds_test.cpp b/services/surfaceflinger/tests/MultiDisplayLayerBounds_test.cpp
index 06e8761..db0c56f 100644
--- a/services/surfaceflinger/tests/MultiDisplayLayerBounds_test.cpp
+++ b/services/surfaceflinger/tests/MultiDisplayLayerBounds_test.cpp
@@ -90,7 +90,7 @@
 };
 
 TEST_F(MultiDisplayLayerBoundsTest, RenderLayerInVirtualDisplay) {
-    createDisplay(mMainDisplayState.viewport, 1 /* layerStack */);
+    createDisplay(mMainDisplayState.layerStackSpaceRect, 1 /* layerStack */);
     createColorLayer(1 /* layerStack */);
 
     asTransaction([&](Transaction& t) { t.setPosition(mColorLayer, 10, 10); });
@@ -111,9 +111,9 @@
     // Create a display and set its layer stack to the main display's layer stack so
     // the contents of the main display are mirrored on to the virtual display.
 
-    // Assumption here is that the new mirrored display has the same viewport as the
+    // Assumption here is that the new mirrored display has the same layer stack rect as the
     // primary display that it is mirroring.
-    createDisplay(mMainDisplayState.viewport, 0 /* layerStack */);
+    createDisplay(mMainDisplayState.layerStackSpaceRect, 0 /* layerStack */);
     createColorLayer(0 /* layerStack */);
 
     asTransaction([&](Transaction& t) { t.setPosition(mColorLayer, 10, 10); });
diff --git a/services/surfaceflinger/tests/TransactionTestHarnesses.h b/services/surfaceflinger/tests/TransactionTestHarnesses.h
index f0af363..01badf4 100644
--- a/services/surfaceflinger/tests/TransactionTestHarnesses.h
+++ b/services/surfaceflinger/tests/TransactionTestHarnesses.h
@@ -65,7 +65,7 @@
                 t.setDisplaySurface(vDisplay, producer);
                 t.setDisplayLayerStack(vDisplay, 0);
                 t.setDisplayProjection(vDisplay, displayState.orientation,
-                                       Rect(displayState.viewport), Rect(resolution));
+                                       Rect(displayState.layerStackSpaceRect), Rect(resolution));
                 t.apply();
                 SurfaceComposerClient::Transaction().apply(true);
                 BufferItem item;
diff --git a/services/surfaceflinger/tests/unittests/Android.bp b/services/surfaceflinger/tests/unittests/Android.bp
index c46c914..4a59c19 100644
--- a/services/surfaceflinger/tests/unittests/Android.bp
+++ b/services/surfaceflinger/tests/unittests/Android.bp
@@ -61,7 +61,7 @@
         "StrongTypingTest.cpp",
         "VSyncDispatchTimerQueueTest.cpp",
         "VSyncDispatchRealtimeTest.cpp",
-        "VSyncModulatorTest.cpp",
+        "VsyncModulatorTest.cpp",
         "VSyncPredictorTest.cpp",
         "VSyncReactorTest.cpp",
         "mock/DisplayHardware/MockComposer.cpp",
diff --git a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
index 6086a05..7fade0d 100644
--- a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
+++ b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
@@ -1523,9 +1523,9 @@
                                 mHardwareDisplaySize.height),
                   compositionState.transform);
         EXPECT_EQ(TRANSFORM_FLAGS_ROT_0, compositionState.orientation);
-        EXPECT_EQ(Rect(mHardwareDisplaySize), compositionState.destinationClip);
-        EXPECT_EQ(Rect(mHardwareDisplaySize), compositionState.frame);
-        EXPECT_EQ(Rect(mHardwareDisplaySize), compositionState.viewport);
+        EXPECT_EQ(Rect(mHardwareDisplaySize), compositionState.displaySpace.content);
+        EXPECT_EQ(Rect(mHardwareDisplaySize), compositionState.orientedDisplaySpace.content);
+        EXPECT_EQ(Rect(mHardwareDisplaySize), compositionState.layerStackSpace.content);
         EXPECT_EQ(false, compositionState.needsFiltering);
     }
 
@@ -1535,10 +1535,12 @@
                                 mHardwareDisplaySize.height),
                   compositionState.transform);
         EXPECT_EQ(TRANSFORM_FLAGS_ROT_90, compositionState.orientation);
-        EXPECT_EQ(Rect(mHardwareDisplaySize), compositionState.destinationClip);
-        // For 90, the frame and viewport have the hardware display size width and height swapped
-        EXPECT_EQ(Rect(SwapWH(mHardwareDisplaySize)), compositionState.frame);
-        EXPECT_EQ(Rect(SwapWH(mHardwareDisplaySize)), compositionState.viewport);
+        EXPECT_EQ(Rect(mHardwareDisplaySize), compositionState.displaySpace.content);
+        // For 90, the orientedDisplaySpaceRect and layerStackSpaceRect have the hardware display
+        // size width and height swapped
+        EXPECT_EQ(Rect(SwapWH(mHardwareDisplaySize)),
+                  compositionState.orientedDisplaySpace.content);
+        EXPECT_EQ(Rect(SwapWH(mHardwareDisplaySize)), compositionState.layerStackSpace.content);
         EXPECT_EQ(false, compositionState.needsFiltering);
     }
 
@@ -1548,8 +1550,8 @@
                                 mHardwareDisplaySize.height),
                   compositionState.transform);
         EXPECT_EQ(TRANSFORM_FLAGS_ROT_180, compositionState.orientation);
-        EXPECT_EQ(Rect(mHardwareDisplaySize), compositionState.frame);
-        EXPECT_EQ(Rect(mHardwareDisplaySize), compositionState.viewport);
+        EXPECT_EQ(Rect(mHardwareDisplaySize), compositionState.orientedDisplaySpace.content);
+        EXPECT_EQ(Rect(mHardwareDisplaySize), compositionState.layerStackSpace.content);
         EXPECT_EQ(false, compositionState.needsFiltering);
     }
 
@@ -1559,10 +1561,12 @@
                                 mHardwareDisplaySize.height),
                   compositionState.transform);
         EXPECT_EQ(TRANSFORM_FLAGS_ROT_270, compositionState.orientation);
-        EXPECT_EQ(Rect(mHardwareDisplaySize), compositionState.destinationClip);
-        // For 270, the frame and viewport have the hardware display size width and height swapped
-        EXPECT_EQ(Rect(SwapWH(mHardwareDisplaySize)), compositionState.frame);
-        EXPECT_EQ(Rect(SwapWH(mHardwareDisplaySize)), compositionState.viewport);
+        EXPECT_EQ(Rect(mHardwareDisplaySize), compositionState.displaySpace.content);
+        // For 270, the orientedDisplaySpaceRect and layerStackSpaceRect have the hardware display
+        // size width and height swapped
+        EXPECT_EQ(Rect(SwapWH(mHardwareDisplaySize)),
+                  compositionState.orientedDisplaySpace.content);
+        EXPECT_EQ(Rect(SwapWH(mHardwareDisplaySize)), compositionState.layerStackSpace.content);
         EXPECT_EQ(false, compositionState.needsFiltering);
     }
 
@@ -2484,11 +2488,11 @@
     EXPECT_EQ(newTransform, display.mutableDisplayDevice()->getOrientation());
 }
 
-TEST_F(HandleTransactionLockedTest, processesDisplayViewportChanges) {
+TEST_F(HandleTransactionLockedTest, processesDisplayLayerStackRectChanges) {
     using Case = NonHwcVirtualDisplayCase;
 
-    const Rect oldViewport(0, 0, 0, 0);
-    const Rect newViewport(0, 0, 123, 456);
+    const Rect oldLayerStackRect(0, 0, 0, 0);
+    const Rect newLayerStackRect(0, 0, 123, 456);
 
     // --------------------------------------------------------------------
     // Preconditions
@@ -2497,9 +2501,9 @@
     auto display = Case::Display::makeFakeExistingDisplayInjector(this);
     display.inject();
 
-    // There is a change to the viewport state
-    display.mutableDrawingDisplayState().viewport = oldViewport;
-    display.mutableCurrentDisplayState().viewport = newViewport;
+    // There is a change to the layerStackSpaceRect state
+    display.mutableDrawingDisplayState().layerStackSpaceRect = oldLayerStackRect;
+    display.mutableCurrentDisplayState().layerStackSpaceRect = newLayerStackRect;
 
     // --------------------------------------------------------------------
     // Invocation
@@ -2509,7 +2513,7 @@
     // --------------------------------------------------------------------
     // Postconditions
 
-    EXPECT_EQ(newViewport, display.mutableDisplayDevice()->getViewport());
+    EXPECT_EQ(newLayerStackRect, display.mutableDisplayDevice()->getLayerStackSpaceRect());
 }
 
 TEST_F(HandleTransactionLockedTest, processesDisplayFrameChanges) {
@@ -2525,9 +2529,9 @@
     auto display = Case::Display::makeFakeExistingDisplayInjector(this);
     display.inject();
 
-    // There is a change to the viewport state
-    display.mutableDrawingDisplayState().frame = oldFrame;
-    display.mutableCurrentDisplayState().frame = newFrame;
+    // There is a change to the layerStackSpaceRect state
+    display.mutableDrawingDisplayState().orientedDisplaySpaceRect = oldFrame;
+    display.mutableCurrentDisplayState().orientedDisplaySpaceRect = newFrame;
 
     // --------------------------------------------------------------------
     // Invocation
@@ -2537,7 +2541,7 @@
     // --------------------------------------------------------------------
     // Postconditions
 
-    EXPECT_EQ(newFrame, display.mutableDisplayDevice()->getFrame());
+    EXPECT_EQ(newFrame, display.mutableDisplayDevice()->getOrientedDisplaySpaceRect());
 }
 
 TEST_F(HandleTransactionLockedTest, processesDisplayWidthChanges) {
@@ -2568,7 +2572,7 @@
     EXPECT_CALL(*nativeWindow, perform(NATIVE_WINDOW_API_DISCONNECT)).Times(1);
     display.inject();
 
-    // There is a change to the viewport state
+    // There is a change to the layerStackSpaceRect state
     display.mutableDrawingDisplayState().width = oldWidth;
     display.mutableDrawingDisplayState().height = oldHeight;
     display.mutableCurrentDisplayState().width = newWidth;
@@ -2613,7 +2617,7 @@
     EXPECT_CALL(*nativeWindow, perform(NATIVE_WINDOW_API_DISCONNECT)).Times(1);
     display.inject();
 
-    // There is a change to the viewport state
+    // There is a change to the layerStackSpaceRect state
     display.mutableDrawingDisplayState().width = oldWidth;
     display.mutableDrawingDisplayState().height = oldHeight;
     display.mutableCurrentDisplayState().width = oldWidth;
@@ -2834,8 +2838,8 @@
 TEST_F(DisplayTransactionTest, setDisplayStateLockedDoesNothingIfProjectionDidNotChange) {
     using Case = SimplePrimaryDisplayCase;
     constexpr ui::Rotation initialOrientation = ui::ROTATION_180;
-    const Rect initialFrame = {1, 2, 3, 4};
-    const Rect initialViewport = {5, 6, 7, 8};
+    const Rect initialOrientedDisplayRect = {1, 2, 3, 4};
+    const Rect initialLayerStackRect = {5, 6, 7, 8};
 
     // --------------------------------------------------------------------
     // Preconditions
@@ -2846,16 +2850,16 @@
 
     // The current display state projection state is all set
     display.mutableCurrentDisplayState().orientation = initialOrientation;
-    display.mutableCurrentDisplayState().frame = initialFrame;
-    display.mutableCurrentDisplayState().viewport = initialViewport;
+    display.mutableCurrentDisplayState().orientedDisplaySpaceRect = initialOrientedDisplayRect;
+    display.mutableCurrentDisplayState().layerStackSpaceRect = initialLayerStackRect;
 
     // The incoming request sets the same projection state
     DisplayState state;
     state.what = DisplayState::eDisplayProjectionChanged;
     state.token = display.token();
     state.orientation = initialOrientation;
-    state.frame = initialFrame;
-    state.viewport = initialViewport;
+    state.orientedDisplaySpaceRect = initialOrientedDisplayRect;
+    state.layerStackSpaceRect = initialLayerStackRect;
 
     // --------------------------------------------------------------------
     // Invocation
@@ -2871,8 +2875,9 @@
     // The current display state is unchanged
     EXPECT_EQ(initialOrientation, display.getCurrentDisplayState().orientation);
 
-    EXPECT_EQ(initialFrame, display.getCurrentDisplayState().frame);
-    EXPECT_EQ(initialViewport, display.getCurrentDisplayState().viewport);
+    EXPECT_EQ(initialOrientedDisplayRect,
+              display.getCurrentDisplayState().orientedDisplaySpaceRect);
+    EXPECT_EQ(initialLayerStackRect, display.getCurrentDisplayState().layerStackSpaceRect);
 }
 
 TEST_F(DisplayTransactionTest, setDisplayStateLockedRequestsUpdateIfOrientationChanged) {
@@ -2913,8 +2918,8 @@
 
 TEST_F(DisplayTransactionTest, setDisplayStateLockedRequestsUpdateIfFrameChanged) {
     using Case = SimplePrimaryDisplayCase;
-    const Rect initialFrame = {0, 0, 0, 0};
-    const Rect desiredFrame = {5, 6, 7, 8};
+    const Rect initialOrientedDisplayRect = {0, 0, 0, 0};
+    const Rect desiredOrientedDisplayRect = {5, 6, 7, 8};
 
     // --------------------------------------------------------------------
     // Preconditions
@@ -2923,14 +2928,14 @@
     auto display = Case::Display::makeFakeExistingDisplayInjector(this);
     display.inject();
 
-    // The current display state does not have a frame
-    display.mutableCurrentDisplayState().frame = initialFrame;
+    // The current display state does not have a orientedDisplaySpaceRect
+    display.mutableCurrentDisplayState().orientedDisplaySpaceRect = initialOrientedDisplayRect;
 
-    // The incoming request sets a frame
+    // The incoming request sets a orientedDisplaySpaceRect
     DisplayState state;
     state.what = DisplayState::eDisplayProjectionChanged;
     state.token = display.token();
-    state.frame = desiredFrame;
+    state.orientedDisplaySpaceRect = desiredOrientedDisplayRect;
 
     // --------------------------------------------------------------------
     // Invocation
@@ -2944,13 +2949,14 @@
     EXPECT_EQ(eDisplayTransactionNeeded, flags);
 
     // The current display state has the new value.
-    EXPECT_EQ(desiredFrame, display.getCurrentDisplayState().frame);
+    EXPECT_EQ(desiredOrientedDisplayRect,
+              display.getCurrentDisplayState().orientedDisplaySpaceRect);
 }
 
-TEST_F(DisplayTransactionTest, setDisplayStateLockedRequestsUpdateIfViewportChanged) {
+TEST_F(DisplayTransactionTest, setDisplayStateLockedRequestsUpdateIfLayerStackRectChanged) {
     using Case = SimplePrimaryDisplayCase;
-    const Rect initialViewport = {0, 0, 0, 0};
-    const Rect desiredViewport = {5, 6, 7, 8};
+    const Rect initialLayerStackRect = {0, 0, 0, 0};
+    const Rect desiredLayerStackRect = {5, 6, 7, 8};
 
     // --------------------------------------------------------------------
     // Preconditions
@@ -2959,14 +2965,14 @@
     auto display = Case::Display::makeFakeExistingDisplayInjector(this);
     display.inject();
 
-    // The current display state does not have a viewport
-    display.mutableCurrentDisplayState().viewport = initialViewport;
+    // The current display state does not have a layerStackSpaceRect
+    display.mutableCurrentDisplayState().layerStackSpaceRect = initialLayerStackRect;
 
-    // The incoming request sets a viewport
+    // The incoming request sets a layerStackSpaceRect
     DisplayState state;
     state.what = DisplayState::eDisplayProjectionChanged;
     state.token = display.token();
-    state.viewport = desiredViewport;
+    state.layerStackSpaceRect = desiredLayerStackRect;
 
     // --------------------------------------------------------------------
     // Invocation
@@ -2980,7 +2986,7 @@
     EXPECT_EQ(eDisplayTransactionNeeded, flags);
 
     // The current display state has the new value.
-    EXPECT_EQ(desiredViewport, display.getCurrentDisplayState().viewport);
+    EXPECT_EQ(desiredLayerStackRect, display.getCurrentDisplayState().layerStackSpaceRect);
 }
 
 TEST_F(DisplayTransactionTest, setDisplayStateLockedDoesNothingIfSizeDidNotChange) {
@@ -3142,11 +3148,11 @@
     // The orientation state should be set to zero
     EXPECT_EQ(ui::ROTATION_0, primaryDisplayState.orientation);
 
-    // The frame state should be set to INVALID
-    EXPECT_EQ(Rect::INVALID_RECT, primaryDisplayState.frame);
+    // The orientedDisplaySpaceRect state should be set to INVALID
+    EXPECT_EQ(Rect::INVALID_RECT, primaryDisplayState.orientedDisplaySpaceRect);
 
-    // The viewport state should be set to INVALID
-    EXPECT_EQ(Rect::INVALID_RECT, primaryDisplayState.viewport);
+    // The layerStackSpaceRect state should be set to INVALID
+    EXPECT_EQ(Rect::INVALID_RECT, primaryDisplayState.layerStackSpaceRect);
 
     // The width and height should both be zero
     EXPECT_EQ(0u, primaryDisplayState.width);
@@ -3157,7 +3163,7 @@
     auto displayDevice = primaryDisplay.mutableDisplayDevice();
     EXPECT_EQ(PowerMode::ON, displayDevice->getPowerMode());
 
-    // The display refresh period should be set in the frame tracker.
+    // The display refresh period should be set in the orientedDisplaySpaceRect tracker.
     FrameStats stats;
     mFlinger.getAnimFrameTracker().getStats(&stats);
     EXPECT_EQ(DEFAULT_REFRESH_RATE, stats.refreshPeriodNano);
diff --git a/services/surfaceflinger/tests/unittests/PhaseOffsetsTest.cpp b/services/surfaceflinger/tests/unittests/PhaseOffsetsTest.cpp
index 0b74682..96bb74b 100644
--- a/services/surfaceflinger/tests/unittests/PhaseOffsetsTest.cpp
+++ b/services/surfaceflinger/tests/unittests/PhaseOffsetsTest.cpp
@@ -29,8 +29,7 @@
 
 using namespace testing;
 
-namespace android {
-namespace scheduler {
+namespace android::scheduler {
 
 class TestablePhaseOffsetsAsDurations : public impl::PhaseDurations {
 public:
@@ -53,7 +52,6 @@
     TestablePhaseOffsetsAsDurations mPhaseDurations;
 };
 
-namespace {
 /* ------------------------------------------------------------------------
  * Test cases
  */
@@ -71,9 +69,9 @@
 
     EXPECT_EQ(offsets.early.app, 833'334);
 
-    EXPECT_EQ(offsets.earlyGl.sf, 3'166'667);
+    EXPECT_EQ(offsets.earlyGpu.sf, 3'166'667);
 
-    EXPECT_EQ(offsets.earlyGl.app, 15'500'001);
+    EXPECT_EQ(offsets.earlyGpu.app, 15'500'001);
 }
 
 TEST_F(PhaseDurationTest, getOffsetsForRefreshRate_90Hz) {
@@ -90,9 +88,9 @@
 
     EXPECT_EQ(offsets.early.app, 833'333);
 
-    EXPECT_EQ(offsets.earlyGl.sf, -2'388'889);
+    EXPECT_EQ(offsets.earlyGpu.sf, -2'388'889);
 
-    EXPECT_EQ(offsets.earlyGl.app, 9'944'444);
+    EXPECT_EQ(offsets.earlyGpu.app, 9'944'444);
 }
 
 TEST_F(PhaseDurationTest, getOffsetsForRefreshRate_DefaultOffsets) {
@@ -107,9 +105,9 @@
 
         EXPECT_EQ(offsets.early.app, 1'000'000);
 
-        EXPECT_EQ(offsets.earlyGl.sf, 1'000'000);
+        EXPECT_EQ(offsets.earlyGpu.sf, 1'000'000);
 
-        EXPECT_EQ(offsets.earlyGl.app, 1'000'000);
+        EXPECT_EQ(offsets.earlyGpu.app, 1'000'000);
     };
 
     phaseOffsetsWithDefaultValues.setRefreshRateFps(90.0f);
@@ -136,31 +134,20 @@
 
     EXPECT_EQ(offsets.early.app, 35'527'208);
 
-    EXPECT_EQ(offsets.earlyGl.sf, 54'527'208);
+    EXPECT_EQ(offsets.earlyGpu.sf, 54'527'208);
 
-    EXPECT_EQ(offsets.earlyGl.app, 33'527'208);
+    EXPECT_EQ(offsets.earlyGpu.app, 33'527'208);
 }
 
-} // namespace
+TEST(PhaseOffsetsTest, getOffsetsForRefreshRate_unknownRefreshRate) {
+    struct PhaseOffsets : impl::PhaseOffsets {
+        using impl::PhaseOffsets::PhaseOffsets;
+        static PhaseOffsets get() {
+            return {{60.0f, 90.0f}, 60.0f, 1'000'000, 1'000'000, {}, {}, {}, {}, 10'000'000};
+        }
+    };
 
-class TestablePhaseOffsets : public impl::PhaseOffsets {
-public:
-    TestablePhaseOffsets()
-          : impl::PhaseOffsets({60.0f, 90.0f}, 60.0f, 1'000'000, 1'000'000, {}, {}, {}, {},
-                               10'000'000) {}
-};
-
-class PhaseOffsetsTest : public testing::Test {
-protected:
-    PhaseOffsetsTest() = default;
-    ~PhaseOffsetsTest() = default;
-
-    TestablePhaseOffsets mPhaseOffsets;
-};
-
-namespace {
-TEST_F(PhaseOffsetsTest, getOffsetsForRefreshRate_unknownRefreshRate) {
-    auto offsets = mPhaseOffsets.getOffsetsForRefreshRate(14.7f);
+    auto offsets = PhaseOffsets::get().getOffsetsForRefreshRate(14.7f);
 
     EXPECT_EQ(offsets.late.sf, 1'000'000);
 
@@ -170,14 +157,12 @@
 
     EXPECT_EQ(offsets.early.app, 1'000'000);
 
-    EXPECT_EQ(offsets.earlyGl.sf, 1'000'000);
+    EXPECT_EQ(offsets.earlyGpu.sf, 1'000'000);
 
-    EXPECT_EQ(offsets.earlyGl.app, 1'000'000);
+    EXPECT_EQ(offsets.earlyGpu.app, 1'000'000);
 }
 
-} // namespace
-} // namespace scheduler
-} // namespace android
+} // namespace android::scheduler
 
 // TODO(b/129481165): remove the #pragma below and fix conversion issues
-#pragma clang diagnostic pop // ignored "-Wconversion"
\ No newline at end of file
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
index b349144..df15516 100644
--- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
+++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
@@ -218,6 +218,7 @@
                                              /*powerMode=*/hal::PowerMode::OFF);
         mFlinger->mPhaseConfiguration =
                 mFactory.createPhaseConfiguration(*mFlinger->mRefreshRateConfigs);
+        mFlinger->mVsyncModulator.emplace(mFlinger->mPhaseConfiguration->getCurrentOffsets());
 
         constexpr bool kUseContentDetectionV2 = false;
         mScheduler =
@@ -227,10 +228,6 @@
         mFlinger->mAppConnectionHandle = mScheduler->createConnection(std::move(appEventThread));
         mFlinger->mSfConnectionHandle = mScheduler->createConnection(std::move(sfEventThread));
         resetScheduler(mScheduler);
-
-        mFlinger->mVSyncModulator.emplace(*mScheduler, mFlinger->mAppConnectionHandle,
-                                          mFlinger->mSfConnectionHandle,
-                                          mFlinger->mPhaseConfiguration->getCurrentOffsets());
     }
 
     void resetScheduler(Scheduler* scheduler) { mFlinger->mScheduler.reset(scheduler); }
diff --git a/services/surfaceflinger/tests/unittests/VSyncModulatorTest.cpp b/services/surfaceflinger/tests/unittests/VSyncModulatorTest.cpp
deleted file mode 100644
index af1e84b..0000000
--- a/services/surfaceflinger/tests/unittests/VSyncModulatorTest.cpp
+++ /dev/null
@@ -1,301 +0,0 @@
-/*
- * Copyright 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#undef LOG_TAG
-#define LOG_TAG "LibSurfaceFlingerUnittests"
-#define LOG_NDEBUG 0
-
-#include "Scheduler/VSyncModulator.h"
-
-#include <gmock/gmock.h>
-#include <gtest/gtest.h>
-
-using namespace testing;
-
-namespace android::scheduler {
-
-class MockScheduler final : public IPhaseOffsetControl {
-public:
-    nsecs_t getOffset(ConnectionHandle handle) { return mPhaseOffset[handle]; }
-
-private:
-    void setPhaseOffset(ConnectionHandle handle, nsecs_t phaseOffset) override {
-        mPhaseOffset[handle] = phaseOffset;
-    }
-
-    std::unordered_map<ConnectionHandle, nsecs_t> mPhaseOffset;
-};
-
-class VSyncModulatorTest : public testing::Test {
-protected:
-    static constexpr auto MIN_EARLY_FRAME_COUNT_TRANSACTION =
-            VSyncModulator::MIN_EARLY_FRAME_COUNT_TRANSACTION;
-    // Add a 1ms slack to avoid strange timer race conditions.
-    static constexpr auto MARGIN_FOR_TX_APPLY = VSyncModulator::MARGIN_FOR_TX_APPLY + 1ms;
-
-    // Used to enumerate the different offsets we have
-    enum {
-        SF_LATE,
-        APP_LATE,
-        SF_EARLY,
-        APP_EARLY,
-        SF_EARLY_GL,
-        APP_EARLY_GL,
-    };
-
-    std::unique_ptr<VSyncModulator> mVSyncModulator;
-    MockScheduler mMockScheduler;
-    ConnectionHandle mAppConnection{1};
-    ConnectionHandle mSfConnection{2};
-    VSyncModulator::OffsetsConfig mOffsets = {{SF_EARLY, APP_EARLY},
-                                              {SF_EARLY_GL, APP_EARLY_GL},
-                                              {SF_LATE, APP_LATE}};
-
-    void SetUp() override {
-        mVSyncModulator = std::make_unique<VSyncModulator>(mMockScheduler, mAppConnection,
-                                                           mSfConnection, mOffsets);
-        mVSyncModulator->setPhaseOffsets(mOffsets);
-
-        EXPECT_EQ(APP_LATE, mMockScheduler.getOffset(mAppConnection));
-        EXPECT_EQ(SF_LATE, mMockScheduler.getOffset(mSfConnection));
-    };
-
-    void TearDown() override { mVSyncModulator.reset(); }
-};
-
-TEST_F(VSyncModulatorTest, Normal) {
-    mVSyncModulator->setTransactionStart(Scheduler::TransactionStart::Normal);
-    std::this_thread::sleep_for(MARGIN_FOR_TX_APPLY);
-    mVSyncModulator->onTransactionHandled();
-    EXPECT_EQ(APP_LATE, mMockScheduler.getOffset(mAppConnection));
-    EXPECT_EQ(SF_LATE, mMockScheduler.getOffset(mSfConnection));
-
-    for (int i = 0; i < MIN_EARLY_FRAME_COUNT_TRANSACTION; i++) {
-        mVSyncModulator->onRefreshed(false);
-        EXPECT_EQ(APP_LATE, mMockScheduler.getOffset(mAppConnection));
-        EXPECT_EQ(SF_LATE, mMockScheduler.getOffset(mSfConnection));
-    }
-}
-
-TEST_F(VSyncModulatorTest, EarlyEnd) {
-    mVSyncModulator->setTransactionStart(Scheduler::TransactionStart::EarlyEnd);
-    std::this_thread::sleep_for(MARGIN_FOR_TX_APPLY);
-    mVSyncModulator->onTransactionHandled();
-    EXPECT_EQ(APP_EARLY, mMockScheduler.getOffset(mAppConnection));
-    EXPECT_EQ(SF_EARLY, mMockScheduler.getOffset(mSfConnection));
-
-    for (int i = 0; i < MIN_EARLY_FRAME_COUNT_TRANSACTION - 1; i++) {
-        mVSyncModulator->onRefreshed(false);
-        EXPECT_EQ(APP_EARLY, mMockScheduler.getOffset(mAppConnection));
-        EXPECT_EQ(SF_EARLY, mMockScheduler.getOffset(mSfConnection));
-    }
-
-    mVSyncModulator->onRefreshed(false);
-    EXPECT_EQ(APP_LATE, mMockScheduler.getOffset(mAppConnection));
-    EXPECT_EQ(SF_LATE, mMockScheduler.getOffset(mSfConnection));
-}
-
-TEST_F(VSyncModulatorTest, EarlyStart) {
-    mVSyncModulator->setTransactionStart(Scheduler::TransactionStart::EarlyStart);
-    std::this_thread::sleep_for(MARGIN_FOR_TX_APPLY);
-    mVSyncModulator->onTransactionHandled();
-    EXPECT_EQ(APP_EARLY, mMockScheduler.getOffset(mAppConnection));
-    EXPECT_EQ(SF_EARLY, mMockScheduler.getOffset(mSfConnection));
-
-    for (int i = 0; i < 5 * MIN_EARLY_FRAME_COUNT_TRANSACTION; i++) {
-        mVSyncModulator->onRefreshed(false);
-        EXPECT_EQ(APP_EARLY, mMockScheduler.getOffset(mAppConnection));
-        EXPECT_EQ(SF_EARLY, mMockScheduler.getOffset(mSfConnection));
-    }
-
-    mVSyncModulator->setTransactionStart(Scheduler::TransactionStart::EarlyEnd);
-    std::this_thread::sleep_for(MARGIN_FOR_TX_APPLY);
-    mVSyncModulator->onTransactionHandled();
-    EXPECT_EQ(APP_EARLY, mMockScheduler.getOffset(mAppConnection));
-    EXPECT_EQ(SF_EARLY, mMockScheduler.getOffset(mSfConnection));
-
-    for (int i = 0; i < MIN_EARLY_FRAME_COUNT_TRANSACTION - 1; i++) {
-        mVSyncModulator->onRefreshed(false);
-        EXPECT_EQ(APP_EARLY, mMockScheduler.getOffset(mAppConnection));
-        EXPECT_EQ(SF_EARLY, mMockScheduler.getOffset(mSfConnection));
-    }
-
-    mVSyncModulator->onRefreshed(false);
-    EXPECT_EQ(APP_LATE, mMockScheduler.getOffset(mAppConnection));
-    EXPECT_EQ(SF_LATE, mMockScheduler.getOffset(mSfConnection));
-}
-
-TEST_F(VSyncModulatorTest, EarlyStartWithEarly) {
-    mVSyncModulator->setTransactionStart(Scheduler::TransactionStart::EarlyStart);
-    std::this_thread::sleep_for(MARGIN_FOR_TX_APPLY);
-    mVSyncModulator->onTransactionHandled();
-    EXPECT_EQ(APP_EARLY, mMockScheduler.getOffset(mAppConnection));
-    EXPECT_EQ(SF_EARLY, mMockScheduler.getOffset(mSfConnection));
-
-    for (int i = 0; i < 5 * MIN_EARLY_FRAME_COUNT_TRANSACTION; i++) {
-        mVSyncModulator->onRefreshed(false);
-        EXPECT_EQ(APP_EARLY, mMockScheduler.getOffset(mAppConnection));
-        EXPECT_EQ(SF_EARLY, mMockScheduler.getOffset(mSfConnection));
-    }
-
-    mVSyncModulator->setTransactionStart(Scheduler::TransactionStart::Early);
-    std::this_thread::sleep_for(MARGIN_FOR_TX_APPLY);
-    mVSyncModulator->onTransactionHandled();
-    EXPECT_EQ(APP_EARLY, mMockScheduler.getOffset(mAppConnection));
-    EXPECT_EQ(SF_EARLY, mMockScheduler.getOffset(mSfConnection));
-
-    for (int i = 0; i < 5 * MIN_EARLY_FRAME_COUNT_TRANSACTION; i++) {
-        mVSyncModulator->onRefreshed(false);
-        EXPECT_EQ(APP_EARLY, mMockScheduler.getOffset(mAppConnection));
-        EXPECT_EQ(SF_EARLY, mMockScheduler.getOffset(mSfConnection));
-    }
-
-    mVSyncModulator->setTransactionStart(Scheduler::TransactionStart::EarlyEnd);
-    std::this_thread::sleep_for(MARGIN_FOR_TX_APPLY);
-    mVSyncModulator->onTransactionHandled();
-    EXPECT_EQ(APP_EARLY, mMockScheduler.getOffset(mAppConnection));
-    EXPECT_EQ(SF_EARLY, mMockScheduler.getOffset(mSfConnection));
-
-    for (int i = 0; i < MIN_EARLY_FRAME_COUNT_TRANSACTION - 1; i++) {
-        mVSyncModulator->onRefreshed(false);
-        EXPECT_EQ(APP_EARLY, mMockScheduler.getOffset(mAppConnection));
-        EXPECT_EQ(SF_EARLY, mMockScheduler.getOffset(mSfConnection));
-    }
-
-    mVSyncModulator->onRefreshed(false);
-    EXPECT_EQ(APP_LATE, mMockScheduler.getOffset(mAppConnection));
-    EXPECT_EQ(SF_LATE, mMockScheduler.getOffset(mSfConnection));
-}
-
-TEST_F(VSyncModulatorTest, EarlyStartWithMoreTransactions) {
-    mVSyncModulator->setTransactionStart(Scheduler::TransactionStart::EarlyStart);
-    std::this_thread::sleep_for(MARGIN_FOR_TX_APPLY);
-    mVSyncModulator->onTransactionHandled();
-    EXPECT_EQ(APP_EARLY, mMockScheduler.getOffset(mAppConnection));
-    EXPECT_EQ(SF_EARLY, mMockScheduler.getOffset(mSfConnection));
-
-    for (int i = 0; i < 5 * MIN_EARLY_FRAME_COUNT_TRANSACTION; i++) {
-        mVSyncModulator->setTransactionStart(Scheduler::TransactionStart::Normal);
-        std::this_thread::sleep_for(MARGIN_FOR_TX_APPLY);
-        mVSyncModulator->onRefreshed(false);
-        EXPECT_EQ(APP_EARLY, mMockScheduler.getOffset(mAppConnection));
-        EXPECT_EQ(SF_EARLY, mMockScheduler.getOffset(mSfConnection));
-    }
-
-    mVSyncModulator->setTransactionStart(Scheduler::TransactionStart::EarlyEnd);
-    std::this_thread::sleep_for(MARGIN_FOR_TX_APPLY);
-    mVSyncModulator->onTransactionHandled();
-    EXPECT_EQ(APP_EARLY, mMockScheduler.getOffset(mAppConnection));
-    EXPECT_EQ(SF_EARLY, mMockScheduler.getOffset(mSfConnection));
-
-    for (int i = 0; i < MIN_EARLY_FRAME_COUNT_TRANSACTION - 1; i++) {
-        mVSyncModulator->onRefreshed(false);
-        EXPECT_EQ(APP_EARLY, mMockScheduler.getOffset(mAppConnection));
-        EXPECT_EQ(SF_EARLY, mMockScheduler.getOffset(mSfConnection));
-    }
-
-    mVSyncModulator->onRefreshed(false);
-    EXPECT_EQ(APP_LATE, mMockScheduler.getOffset(mAppConnection));
-    EXPECT_EQ(SF_LATE, mMockScheduler.getOffset(mSfConnection));
-}
-
-TEST_F(VSyncModulatorTest, EarlyStartAfterEarlyEnd) {
-    mVSyncModulator->setTransactionStart(Scheduler::TransactionStart::EarlyEnd);
-    std::this_thread::sleep_for(MARGIN_FOR_TX_APPLY);
-    mVSyncModulator->onTransactionHandled();
-    EXPECT_EQ(APP_EARLY, mMockScheduler.getOffset(mAppConnection));
-    EXPECT_EQ(SF_EARLY, mMockScheduler.getOffset(mSfConnection));
-
-    for (int i = 0; i < MIN_EARLY_FRAME_COUNT_TRANSACTION - 1; i++) {
-        mVSyncModulator->onRefreshed(false);
-        EXPECT_EQ(APP_EARLY, mMockScheduler.getOffset(mAppConnection));
-        EXPECT_EQ(SF_EARLY, mMockScheduler.getOffset(mSfConnection));
-    }
-
-    mVSyncModulator->setTransactionStart(Scheduler::TransactionStart::EarlyStart);
-    std::this_thread::sleep_for(MARGIN_FOR_TX_APPLY);
-    mVSyncModulator->onTransactionHandled();
-    EXPECT_EQ(APP_EARLY, mMockScheduler.getOffset(mAppConnection));
-    EXPECT_EQ(SF_EARLY, mMockScheduler.getOffset(mSfConnection));
-
-    for (int i = 0; i < 5 * MIN_EARLY_FRAME_COUNT_TRANSACTION; i++) {
-        mVSyncModulator->onRefreshed(false);
-        EXPECT_EQ(APP_EARLY, mMockScheduler.getOffset(mAppConnection));
-        EXPECT_EQ(SF_EARLY, mMockScheduler.getOffset(mSfConnection));
-    }
-
-    mVSyncModulator->setTransactionStart(Scheduler::TransactionStart::EarlyEnd);
-    std::this_thread::sleep_for(MARGIN_FOR_TX_APPLY);
-    mVSyncModulator->onTransactionHandled();
-    EXPECT_EQ(APP_EARLY, mMockScheduler.getOffset(mAppConnection));
-    EXPECT_EQ(SF_EARLY, mMockScheduler.getOffset(mSfConnection));
-
-    for (int i = 0; i < MIN_EARLY_FRAME_COUNT_TRANSACTION - 1; i++) {
-        mVSyncModulator->onRefreshed(false);
-        EXPECT_EQ(APP_EARLY, mMockScheduler.getOffset(mAppConnection));
-        EXPECT_EQ(SF_EARLY, mMockScheduler.getOffset(mSfConnection));
-    }
-
-    mVSyncModulator->onRefreshed(false);
-    EXPECT_EQ(APP_LATE, mMockScheduler.getOffset(mAppConnection));
-    EXPECT_EQ(SF_LATE, mMockScheduler.getOffset(mSfConnection));
-}
-
-TEST_F(VSyncModulatorTest, EarlyStartAfterEarlyEndWithMoreTransactions) {
-    mVSyncModulator->setTransactionStart(Scheduler::TransactionStart::EarlyEnd);
-    std::this_thread::sleep_for(MARGIN_FOR_TX_APPLY);
-    mVSyncModulator->onTransactionHandled();
-    EXPECT_EQ(APP_EARLY, mMockScheduler.getOffset(mAppConnection));
-    EXPECT_EQ(SF_EARLY, mMockScheduler.getOffset(mSfConnection));
-
-    for (int i = 0; i < MIN_EARLY_FRAME_COUNT_TRANSACTION - 1; i++) {
-        mVSyncModulator->onRefreshed(false);
-        EXPECT_EQ(APP_EARLY, mMockScheduler.getOffset(mAppConnection));
-        EXPECT_EQ(SF_EARLY, mMockScheduler.getOffset(mSfConnection));
-    }
-
-    mVSyncModulator->setTransactionStart(Scheduler::TransactionStart::EarlyStart);
-    std::this_thread::sleep_for(MARGIN_FOR_TX_APPLY);
-    mVSyncModulator->onTransactionHandled();
-    EXPECT_EQ(APP_EARLY, mMockScheduler.getOffset(mAppConnection));
-    EXPECT_EQ(SF_EARLY, mMockScheduler.getOffset(mSfConnection));
-
-    for (int i = 0; i < 5 * MIN_EARLY_FRAME_COUNT_TRANSACTION; i++) {
-        mVSyncModulator->setTransactionStart(Scheduler::TransactionStart::Normal);
-        std::this_thread::sleep_for(MARGIN_FOR_TX_APPLY);
-        mVSyncModulator->onRefreshed(false);
-        EXPECT_EQ(APP_EARLY, mMockScheduler.getOffset(mAppConnection));
-        EXPECT_EQ(SF_EARLY, mMockScheduler.getOffset(mSfConnection));
-    }
-
-    mVSyncModulator->setTransactionStart(Scheduler::TransactionStart::EarlyEnd);
-    std::this_thread::sleep_for(MARGIN_FOR_TX_APPLY);
-    mVSyncModulator->onTransactionHandled();
-    EXPECT_EQ(APP_EARLY, mMockScheduler.getOffset(mAppConnection));
-    EXPECT_EQ(SF_EARLY, mMockScheduler.getOffset(mSfConnection));
-
-    for (int i = 0; i < MIN_EARLY_FRAME_COUNT_TRANSACTION - 1; i++) {
-        mVSyncModulator->onRefreshed(false);
-        EXPECT_EQ(APP_EARLY, mMockScheduler.getOffset(mAppConnection));
-        EXPECT_EQ(SF_EARLY, mMockScheduler.getOffset(mSfConnection));
-    }
-
-    mVSyncModulator->onRefreshed(false);
-    EXPECT_EQ(APP_LATE, mMockScheduler.getOffset(mAppConnection));
-    EXPECT_EQ(SF_LATE, mMockScheduler.getOffset(mSfConnection));
-}
-
-} // namespace android::scheduler
diff --git a/services/surfaceflinger/tests/unittests/VsyncModulatorTest.cpp b/services/surfaceflinger/tests/unittests/VsyncModulatorTest.cpp
new file mode 100644
index 0000000..d7093c6
--- /dev/null
+++ b/services/surfaceflinger/tests/unittests/VsyncModulatorTest.cpp
@@ -0,0 +1,170 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+#include "Scheduler/VsyncModulator.h"
+
+namespace android::scheduler {
+
+class VsyncModulatorTest : public testing::Test {
+    enum Offsets {
+        SF_LATE,
+        APP_LATE,
+        SF_EARLY,
+        APP_EARLY,
+        SF_EARLY_GPU,
+        APP_EARLY_GPU,
+    };
+
+    static VsyncModulator::TimePoint Now() {
+        static VsyncModulator::TimePoint now;
+        return now += VsyncModulator::MIN_EARLY_TRANSACTION_TIME;
+    }
+
+protected:
+    static constexpr auto MIN_EARLY_TRANSACTION_FRAMES =
+            VsyncModulator::MIN_EARLY_TRANSACTION_FRAMES;
+
+    using Schedule = scheduler::TransactionSchedule;
+
+    const VsyncModulator::Offsets kEarly{SF_EARLY, APP_EARLY};
+    const VsyncModulator::Offsets kEarlyGpu{SF_EARLY_GPU, APP_EARLY_GPU};
+    const VsyncModulator::Offsets kLate{SF_LATE, APP_LATE};
+
+    const VsyncModulator::OffsetsConfig mOffsets = {kEarly, kEarlyGpu, kLate};
+    VsyncModulator mVsyncModulator{mOffsets, Now};
+
+    void SetUp() override { EXPECT_EQ(kLate, mVsyncModulator.setPhaseOffsets(mOffsets)); }
+};
+
+#define CHECK_COMMIT(result, offsets)                         \
+    EXPECT_EQ(result, mVsyncModulator.onTransactionCommit()); \
+    EXPECT_EQ(offsets, mVsyncModulator.getOffsets());
+
+#define CHECK_REFRESH(N, result, offsets)                           \
+    for (int i = 0; i < N; i++) {                                   \
+        EXPECT_EQ(result, mVsyncModulator.onDisplayRefresh(false)); \
+        EXPECT_EQ(offsets, mVsyncModulator.getOffsets());           \
+    }
+
+TEST_F(VsyncModulatorTest, Late) {
+    EXPECT_FALSE(mVsyncModulator.setTransactionSchedule(Schedule::Late));
+
+    CHECK_COMMIT(std::nullopt, kLate);
+    CHECK_REFRESH(MIN_EARLY_TRANSACTION_FRAMES, std::nullopt, kLate);
+}
+
+TEST_F(VsyncModulatorTest, EarlyEnd) {
+    EXPECT_EQ(kEarly, mVsyncModulator.setTransactionSchedule(Schedule::EarlyEnd));
+
+    CHECK_COMMIT(kEarly, kEarly);
+    CHECK_REFRESH(MIN_EARLY_TRANSACTION_FRAMES - 1, kEarly, kEarly);
+    CHECK_REFRESH(1, kLate, kLate);
+}
+
+TEST_F(VsyncModulatorTest, EarlyStart) {
+    EXPECT_EQ(kEarly, mVsyncModulator.setTransactionSchedule(Schedule::EarlyStart));
+
+    CHECK_COMMIT(kEarly, kEarly);
+    CHECK_REFRESH(5 * MIN_EARLY_TRANSACTION_FRAMES, std::nullopt, kEarly);
+
+    EXPECT_EQ(kEarly, mVsyncModulator.setTransactionSchedule(Schedule::EarlyEnd));
+
+    CHECK_COMMIT(kEarly, kEarly);
+    CHECK_REFRESH(MIN_EARLY_TRANSACTION_FRAMES - 1, kEarly, kEarly);
+    CHECK_REFRESH(1, kLate, kLate);
+}
+
+TEST_F(VsyncModulatorTest, EarlyStartWithEarly) {
+    EXPECT_EQ(kEarly, mVsyncModulator.setTransactionSchedule(Schedule::EarlyStart));
+
+    CHECK_COMMIT(kEarly, kEarly);
+    CHECK_REFRESH(5 * MIN_EARLY_TRANSACTION_FRAMES, std::nullopt, kEarly);
+
+    EXPECT_EQ(kEarly, mVsyncModulator.setTransactionSchedule(Schedule::Early));
+
+    CHECK_COMMIT(kEarly, kEarly);
+    CHECK_REFRESH(5 * MIN_EARLY_TRANSACTION_FRAMES, std::nullopt, kEarly);
+
+    EXPECT_EQ(kEarly, mVsyncModulator.setTransactionSchedule(Schedule::EarlyEnd));
+
+    CHECK_COMMIT(kEarly, kEarly);
+    CHECK_REFRESH(MIN_EARLY_TRANSACTION_FRAMES - 1, kEarly, kEarly);
+    CHECK_REFRESH(1, kLate, kLate);
+}
+
+TEST_F(VsyncModulatorTest, EarlyStartWithMoreTransactions) {
+    EXPECT_EQ(kEarly, mVsyncModulator.setTransactionSchedule(Schedule::EarlyStart));
+
+    CHECK_COMMIT(kEarly, kEarly);
+
+    for (int i = 0; i < 5 * MIN_EARLY_TRANSACTION_FRAMES; i++) {
+        EXPECT_FALSE(mVsyncModulator.setTransactionSchedule(Schedule::Late));
+        CHECK_REFRESH(1, std::nullopt, kEarly);
+    }
+
+    EXPECT_EQ(kEarly, mVsyncModulator.setTransactionSchedule(Schedule::EarlyEnd));
+
+    CHECK_COMMIT(kEarly, kEarly);
+    CHECK_REFRESH(MIN_EARLY_TRANSACTION_FRAMES - 1, kEarly, kEarly);
+    CHECK_REFRESH(1, kLate, kLate);
+}
+
+TEST_F(VsyncModulatorTest, EarlyStartAfterEarlyEnd) {
+    EXPECT_EQ(kEarly, mVsyncModulator.setTransactionSchedule(Schedule::EarlyEnd));
+
+    CHECK_COMMIT(kEarly, kEarly);
+    CHECK_REFRESH(MIN_EARLY_TRANSACTION_FRAMES - 1, kEarly, kEarly);
+
+    EXPECT_EQ(kEarly, mVsyncModulator.setTransactionSchedule(Schedule::EarlyStart));
+
+    CHECK_COMMIT(kEarly, kEarly);
+    CHECK_REFRESH(1, kEarly, kEarly);
+    CHECK_REFRESH(5 * MIN_EARLY_TRANSACTION_FRAMES, std::nullopt, kEarly);
+
+    EXPECT_EQ(kEarly, mVsyncModulator.setTransactionSchedule(Schedule::EarlyEnd));
+
+    CHECK_COMMIT(kEarly, kEarly);
+    CHECK_REFRESH(MIN_EARLY_TRANSACTION_FRAMES - 1, kEarly, kEarly);
+    CHECK_REFRESH(1, kLate, kLate);
+}
+
+TEST_F(VsyncModulatorTest, EarlyStartAfterEarlyEndWithMoreTransactions) {
+    EXPECT_EQ(kEarly, mVsyncModulator.setTransactionSchedule(Schedule::EarlyEnd));
+
+    CHECK_COMMIT(kEarly, kEarly);
+    CHECK_REFRESH(MIN_EARLY_TRANSACTION_FRAMES - 1, kEarly, kEarly);
+
+    EXPECT_EQ(kEarly, mVsyncModulator.setTransactionSchedule(Schedule::EarlyStart));
+
+    CHECK_COMMIT(kEarly, kEarly);
+    CHECK_REFRESH(1, kEarly, kEarly);
+
+    for (int i = 0; i < 5 * MIN_EARLY_TRANSACTION_FRAMES; i++) {
+        EXPECT_FALSE(mVsyncModulator.setTransactionSchedule(Schedule::Late));
+        CHECK_REFRESH(1, std::nullopt, kEarly);
+    }
+
+    EXPECT_EQ(kEarly, mVsyncModulator.setTransactionSchedule(Schedule::EarlyEnd));
+
+    CHECK_COMMIT(kEarly, kEarly);
+    CHECK_REFRESH(MIN_EARLY_TRANSACTION_FRAMES - 1, kEarly, kEarly);
+    CHECK_REFRESH(1, kLate, kLate);
+}
+
+} // namespace android::scheduler
diff --git a/services/surfaceflinger/tests/unittests/mock/MockSurfaceInterceptor.h b/services/surfaceflinger/tests/unittests/mock/MockSurfaceInterceptor.h
index 5beee1c..ccb7bb9 100644
--- a/services/surfaceflinger/tests/unittests/mock/MockSurfaceInterceptor.h
+++ b/services/surfaceflinger/tests/unittests/mock/MockSurfaceInterceptor.h
@@ -33,10 +33,10 @@
                       const DefaultKeyedVector<wp<IBinder>, DisplayDeviceState>&));
     MOCK_METHOD0(disable, void());
     MOCK_METHOD0(isEnabled, bool());
-    MOCK_METHOD4(saveTransaction,
+    MOCK_METHOD6(saveTransaction,
                  void(const Vector<ComposerState>&,
                       const DefaultKeyedVector<wp<IBinder>, DisplayDeviceState>&,
-                      const Vector<DisplayState>&, uint32_t));
+                      const Vector<DisplayState>&, uint32_t, int, int));
     MOCK_METHOD1(saveSurfaceCreation, void(const sp<const Layer>&));
     MOCK_METHOD1(saveSurfaceDeletion, void(const sp<const Layer>&));
     MOCK_METHOD4(saveBufferUpdate, void(int32_t, uint32_t, uint32_t, uint64_t));