Merge "Add locks to InputDispatcher_test" into rvc-dev
diff --git a/data/etc/android.hardware.camera.concurrent.xml b/data/etc/android.hardware.camera.concurrent.xml
new file mode 100644
index 0000000..2cbb263
--- /dev/null
+++ b/data/etc/android.hardware.camera.concurrent.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 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.
+-->
+
+<!-- This is the set of features required for a camera2 device that supports concurrent operation
+     of front and back cameras -->
+<permissions>
+    <feature name="android.hardware.camera.front" />
+    <feature name="android.hardware.camera.concurrent" />
+</permissions>
diff --git a/data/etc/android.hardware.sensor.hinge_angle.xml b/data/etc/android.hardware.sensor.hinge_angle.xml
new file mode 100644
index 0000000..d744305
--- /dev/null
+++ b/data/etc/android.hardware.sensor.hinge_angle.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 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.
+-->
+
+<!-- Feature for devices with a hinge angle sensor. -->
+<permissions>
+    <feature name="android.hardware.sensor.hinge_angle" />
+</permissions>
\ No newline at end of file
diff --git a/headers/Android.bp b/headers/Android.bp
index 82bc8a1..5337235 100644
--- a/headers/Android.bp
+++ b/headers/Android.bp
@@ -17,4 +17,5 @@
         "libutils_headers",
         "libstagefright_foundation_headers",
     ],
+    min_sdk_version: "29",
 }
diff --git a/libs/nativedisplay/include/android/choreographer.h b/include/android/choreographer.h
similarity index 88%
rename from libs/nativedisplay/include/android/choreographer.h
rename to include/android/choreographer.h
index 5fd3de9..c1c4a72 100644
--- a/libs/nativedisplay/include/android/choreographer.h
+++ b/include/android/choreographer.h
@@ -75,14 +75,16 @@
  * Deprecated: Use AChoreographer_postFrameCallback64 instead.
  */
 void AChoreographer_postFrameCallback(AChoreographer* choreographer,
-        AChoreographer_frameCallback callback, void* data) __INTRODUCED_IN(24) __DEPRECATED_IN(29);
+                                      AChoreographer_frameCallback callback, void* data)
+        __INTRODUCED_IN(24) __DEPRECATED_IN(29);
 
 /**
  * Deprecated: Use AChoreographer_postFrameCallbackDelayed64 instead.
  */
 void AChoreographer_postFrameCallbackDelayed(AChoreographer* choreographer,
-                AChoreographer_frameCallback callback, void* data,
-                long delayMillis) __INTRODUCED_IN(24) __DEPRECATED_IN(29);
+                                             AChoreographer_frameCallback callback, void* data,
+                                             long delayMillis) __INTRODUCED_IN(24)
+        __DEPRECATED_IN(29);
 
 #endif /* __ANDROID_API__ >= 24 */
 
@@ -95,7 +97,8 @@
  * Available since API level 29.
  */
 void AChoreographer_postFrameCallback64(AChoreographer* choreographer,
-                AChoreographer_frameCallback64 callback, void* data) __INTRODUCED_IN(29);
+                                        AChoreographer_frameCallback64 callback, void* data)
+        __INTRODUCED_IN(29);
 
 /**
  * Post a callback to be run on the frame following the specified delay.  The
@@ -105,7 +108,8 @@
  * Available since API level 29.
  */
 void AChoreographer_postFrameCallbackDelayed64(AChoreographer* choreographer,
-                AChoreographer_frameCallback64 callback, void* data, uint32_t delayMillis) __INTRODUCED_IN(29);
+                                               AChoreographer_frameCallback64 callback, void* data,
+                                               uint32_t delayMillis) __INTRODUCED_IN(29);
 
 #endif /* __ANDROID_API__ >= 29 */
 
diff --git a/include/input/InputWindow.h b/include/input/InputWindow.h
index 856c54d..c5e56fd 100644
--- a/include/input/InputWindow.h
+++ b/include/input/InputWindow.h
@@ -108,6 +108,7 @@
         TYPE_ACCESSIBILITY_OVERLAY = FIRST_SYSTEM_WINDOW + 32,
         TYPE_DOCK_DIVIDER = FIRST_SYSTEM_WINDOW + 34,
         TYPE_NOTIFICATION_SHADE = FIRST_SYSTEM_WINDOW + 40,
+        TYPE_TRUSTED_APPLICATION_OVERLAY = FIRST_SYSTEM_WINDOW + 42,
         LAST_SYSTEM_WINDOW = 2999,
     };
 
diff --git a/libs/arect/Android.bp b/libs/arect/Android.bp
index 2518b14..f66673f 100644
--- a/libs/arect/Android.bp
+++ b/libs/arect/Android.bp
@@ -35,4 +35,5 @@
             enabled: true,
         },
     },
+    min_sdk_version: "29",
 }
diff --git a/libs/binder/Android.bp b/libs/binder/Android.bp
index 7298282..db4aba8 100644
--- a/libs/binder/Android.bp
+++ b/libs/binder/Android.bp
@@ -28,6 +28,7 @@
         "libcutils_headers",
         "libutils_headers",
     ],
+    min_sdk_version: "29",
 }
 
 // These interfaces are android-specific implementation unrelated to binder
@@ -152,6 +153,7 @@
     sanitize: {
         misc_undefined: ["integer"],
     },
+    min_sdk_version: "29",
 }
 
 // AIDL interface between libbinder and framework.jar
diff --git a/libs/binder/tests/Android.bp b/libs/binder/tests/Android.bp
index 69fdd7c..c0da2cd 100644
--- a/libs/binder/tests/Android.bp
+++ b/libs/binder/tests/Android.bp
@@ -27,7 +27,9 @@
     defaults: ["binder_test_defaults"],
     srcs: ["binderDriverInterfaceTest.cpp"],
     compile_multilib: "32",
+    multilib: { lib32: { suffix: "" } },
     cflags: ["-DBINDER_IPC_32BIT=1"],
+    test_suites: ["vts"],
 }
 
 cc_test {
@@ -52,7 +54,10 @@
         "libutils",
     ],
     compile_multilib: "32",
+    multilib: { lib32: { suffix: "" } },
     cflags: ["-DBINDER_IPC_32BIT=1"],
+    test_suites: ["vts"],
+    require_root: true,
 }
 
 cc_test {
diff --git a/libs/binder/tests/binderAbiHelper.h b/libs/binder/tests/binderAbiHelper.h
new file mode 100644
index 0000000..369b55d
--- /dev/null
+++ b/libs/binder/tests/binderAbiHelper.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 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 <stdlib.h>
+#include <iostream>
+
+#ifdef BINDER_IPC_32BIT
+static constexpr bool kBuild32Abi = true;
+#else
+static constexpr bool kBuild32Abi = false;
+#endif
+
+// TODO: remove when CONFIG_ANDROID_BINDER_IPC_32BIT is no longer supported
+static inline bool ReadKernelConfigIs32BitAbi() {
+    // failure case implies we run with standard ABI
+    return 0 == system("zcat /proc/config.gz | grep -E \"^CONFIG_ANDROID_BINDER_IPC_32BIT=y$\"");
+}
+
+static inline void ExitIfWrongAbi() {
+    bool runtime32Abi = ReadKernelConfigIs32BitAbi();
+
+    if (kBuild32Abi != runtime32Abi) {
+        std::cout << "[==========] Running 1 test from 1 test suite." << std::endl;
+        std::cout << "[----------] Global test environment set-up." << std::endl;
+        std::cout << "[----------] 1 tests from BinderLibTest" << std::endl;
+        std::cout << "[ RUN      ] BinderTest.AbortForWrongAbi" << std::endl;
+        std::cout << "[ INFO     ] test build abi 32: " << kBuild32Abi << " runtime abi 32: " << runtime32Abi << " so, skipping tests " << std::endl;
+        std::cout << "[       OK ] BinderTest.AbortForWrongAbi (0 ms) " << std::endl;
+        std::cout << "[----------] 1 tests from BinderTest (0 ms total)" << std::endl;
+        std::cout << "" << std::endl;
+        std::cout << "[----------] Global test environment tear-down" << std::endl;
+        std::cout << "[==========] 1 test from 1 test suite ran. (0 ms total)" << std::endl;
+        std::cout << "[  PASSED  ] 1 tests." << std::endl;
+        exit(0);
+    }
+}
+
diff --git a/libs/binder/tests/binderDriverInterfaceTest.cpp b/libs/binder/tests/binderDriverInterfaceTest.cpp
index f3ed6a6..8cc3054 100644
--- a/libs/binder/tests/binderDriverInterfaceTest.cpp
+++ b/libs/binder/tests/binderDriverInterfaceTest.cpp
@@ -25,6 +25,8 @@
 #include <sys/mman.h>
 #include <poll.h>
 
+#include "binderAbiHelper.h"
+
 #define BINDER_DEV_NAME "/dev/binder"
 
 testing::Environment* binder_env;
@@ -361,6 +363,7 @@
 }
 
 int main(int argc, char **argv) {
+    ExitIfWrongAbi();
     ::testing::InitGoogleTest(&argc, argv);
 
     binder_env = AddGlobalTestEnvironment(new BinderDriverInterfaceTestEnv());
diff --git a/libs/binder/tests/binderLibTest.cpp b/libs/binder/tests/binderLibTest.cpp
index e343df7..40de2db 100644
--- a/libs/binder/tests/binderLibTest.cpp
+++ b/libs/binder/tests/binderLibTest.cpp
@@ -32,6 +32,8 @@
 #include <sys/epoll.h>
 #include <sys/prctl.h>
 
+#include "binderAbiHelper.h"
+
 #define ARRAY_SIZE(array) (sizeof array / sizeof array[0])
 
 using namespace android;
@@ -1451,6 +1453,8 @@
 }
 
 int main(int argc, char **argv) {
+    ExitIfWrongAbi();
+
     if (argc == 4 && !strcmp(argv[1], "--servername")) {
         binderservername = argv[2];
     } else {
diff --git a/libs/binderthreadstate/Android.bp b/libs/binderthreadstate/Android.bp
index 5eb509c..88752ee 100644
--- a/libs/binderthreadstate/Android.bp
+++ b/libs/binderthreadstate/Android.bp
@@ -22,7 +22,7 @@
 
     shared_libs: [
         "libbinder",
-        "libhidlbase",  // libhwbinder is in here
+        "libhidlbase", // libhwbinder is in here
     ],
 
     export_include_dirs: ["include"],
@@ -31,6 +31,7 @@
         "-Wall",
         "-Werror",
     ],
+    min_sdk_version: "29",
 }
 
 hidl_package_root {
diff --git a/libs/gui/Android.bp b/libs/gui/Android.bp
index 7f57f5d..7976ecb 100644
--- a/libs/gui/Android.bp
+++ b/libs/gui/Android.bp
@@ -27,6 +27,7 @@
         "android.hardware.graphics.bufferqueue@1.0",
         "android.hardware.graphics.bufferqueue@2.0",
     ],
+    min_sdk_version: "29",
 }
 
 cc_library_shared {
diff --git a/libs/gui/DisplayEventDispatcher.cpp b/libs/gui/DisplayEventDispatcher.cpp
index 15f966d..b33bc9e 100644
--- a/libs/gui/DisplayEventDispatcher.cpp
+++ b/libs/gui/DisplayEventDispatcher.cpp
@@ -36,10 +36,7 @@
 DisplayEventDispatcher::DisplayEventDispatcher(const sp<Looper>& looper,
                                                ISurfaceComposer::VsyncSource vsyncSource,
                                                ISurfaceComposer::ConfigChanged configChanged)
-      : mLooper(looper),
-        mReceiver(vsyncSource, configChanged),
-        mWaitingForVsync(false),
-        mConfigChangeFlag(configChanged) {
+      : mLooper(looper), mReceiver(vsyncSource, configChanged), mWaitingForVsync(false) {
     ALOGV("dispatcher %p ~ Initializing display event dispatcher.", this);
 }
 
@@ -92,16 +89,12 @@
     return OK;
 }
 
-void DisplayEventDispatcher::toggleConfigEvents(ISurfaceComposer::ConfigChanged configChangeFlag) {
-    if (mConfigChangeFlag == configChangeFlag) {
-        return;
-    }
-    status_t status = mReceiver.toggleConfigEvents(configChangeFlag);
+void DisplayEventDispatcher::requestLatestConfig() {
+    status_t status = mReceiver.requestLatestConfig();
     if (status) {
         ALOGW("Failed enable config events, status=%d", status);
         return;
     }
-    mConfigChangeFlag = configChangeFlag;
 }
 
 int DisplayEventDispatcher::getFd() const {
diff --git a/libs/gui/DisplayEventReceiver.cpp b/libs/gui/DisplayEventReceiver.cpp
index fd6aaf8..1fed509 100644
--- a/libs/gui/DisplayEventReceiver.cpp
+++ b/libs/gui/DisplayEventReceiver.cpp
@@ -79,10 +79,9 @@
     return NO_INIT;
 }
 
-status_t DisplayEventReceiver::toggleConfigEvents(
-        ISurfaceComposer::ConfigChanged configChangeFlag) {
+status_t DisplayEventReceiver::requestLatestConfig() {
     if (mEventConnection != nullptr) {
-        mEventConnection->toggleConfigEvents(configChangeFlag);
+        mEventConnection->requestLatestConfig();
         return NO_ERROR;
     }
     return NO_INIT;
diff --git a/libs/gui/IDisplayEventConnection.cpp b/libs/gui/IDisplayEventConnection.cpp
index dda5acf..aa74bfd 100644
--- a/libs/gui/IDisplayEventConnection.cpp
+++ b/libs/gui/IDisplayEventConnection.cpp
@@ -26,8 +26,8 @@
     STEAL_RECEIVE_CHANNEL = IBinder::FIRST_CALL_TRANSACTION,
     SET_VSYNC_RATE,
     REQUEST_NEXT_VSYNC,
-    TOGGLE_CONFIG_EVENTS,
-    LAST = TOGGLE_CONFIG_EVENTS,
+    REQUEST_LATEST_CONFIG,
+    LAST = REQUEST_LATEST_CONFIG,
 };
 
 } // Anonymous namespace
@@ -55,10 +55,9 @@
                 Tag::REQUEST_NEXT_VSYNC);
     }
 
-    void toggleConfigEvents(ISurfaceComposer::ConfigChanged configChangeFlag) override {
-        callRemoteAsync<decltype(
-                &IDisplayEventConnection::toggleConfigEvents)>(Tag::TOGGLE_CONFIG_EVENTS,
-                                                               configChangeFlag);
+    void requestLatestConfig() override {
+        callRemoteAsync<decltype(&IDisplayEventConnection::requestLatestConfig)>(
+                Tag::REQUEST_LATEST_CONFIG);
     }
 };
 
@@ -81,8 +80,8 @@
             return callLocal(data, reply, &IDisplayEventConnection::setVsyncRate);
         case Tag::REQUEST_NEXT_VSYNC:
             return callLocalAsync(data, reply, &IDisplayEventConnection::requestNextVsync);
-        case Tag::TOGGLE_CONFIG_EVENTS:
-            return callLocalAsync(data, reply, &IDisplayEventConnection::toggleConfigEvents);
+        case Tag::REQUEST_LATEST_CONFIG:
+            return callLocalAsync(data, reply, &IDisplayEventConnection::requestLatestConfig);
     }
 }
 
diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp
index f7158d0..e43446a 100644
--- a/libs/gui/LayerState.cpp
+++ b/libs/gui/LayerState.cpp
@@ -116,6 +116,7 @@
     output.writeInt32(frameRateSelectionPriority);
     output.writeFloat(frameRate);
     output.writeByte(frameRateCompatibility);
+    output.writeUint32(fixedTransformHint);
     return NO_ERROR;
 }
 
@@ -198,6 +199,7 @@
     frameRateSelectionPriority = input.readInt32();
     frameRate = input.readFloat();
     frameRateCompatibility = input.readByte();
+    fixedTransformHint = static_cast<ui::Transform::RotationFlags>(input.readUint32());
     return NO_ERROR;
 }
 
@@ -433,6 +435,10 @@
         frameRate = other.frameRate;
         frameRateCompatibility = other.frameRateCompatibility;
     }
+    if (other.what & eFixedTransformHintChanged) {
+        what |= eFixedTransformHintChanged;
+        fixedTransformHint = other.fixedTransformHint;
+    }
     if ((other.what & what) != other.what) {
         ALOGE("Unmerged SurfaceComposer Transaction properties. LayerState::merge needs updating? "
               "other.what=0x%" PRIu64 " what=0x%" PRIu64,
diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp
index f911e70..2bf8ff7 100644
--- a/libs/gui/Surface.cpp
+++ b/libs/gui/Surface.cpp
@@ -57,7 +57,8 @@
     return op == NATIVE_WINDOW_SET_CANCEL_INTERCEPTOR ||
             op == NATIVE_WINDOW_SET_DEQUEUE_INTERCEPTOR ||
             op == NATIVE_WINDOW_SET_PERFORM_INTERCEPTOR ||
-            op == NATIVE_WINDOW_SET_QUEUE_INTERCEPTOR;
+            op == NATIVE_WINDOW_SET_QUEUE_INTERCEPTOR ||
+            op == NATIVE_WINDOW_SET_QUERY_INTERCEPTOR;
 }
 
 } // namespace
@@ -501,6 +502,19 @@
 
 int Surface::hook_query(const ANativeWindow* window, int what, int* value) {
     const Surface* c = getSelf(window);
+    {
+        std::shared_lock<std::shared_mutex> lock(c->mInterceptorMutex);
+        if (c->mQueryInterceptor != nullptr) {
+            auto interceptor = c->mQueryInterceptor;
+            auto data = c->mQueryInterceptorData;
+            return interceptor(window, Surface::queryInternal, data, what, value);
+        }
+    }
+    return c->query(what, value);
+}
+
+int Surface::queryInternal(const ANativeWindow* window, int what, int* value) {
+    const Surface* c = getSelf(window);
     return c->query(what, value);
 }
 
@@ -1177,6 +1191,9 @@
     case NATIVE_WINDOW_SET_QUEUE_INTERCEPTOR:
         res = dispatchAddQueueInterceptor(args);
         break;
+    case NATIVE_WINDOW_SET_QUERY_INTERCEPTOR:
+        res = dispatchAddQueryInterceptor(args);
+        break;
     case NATIVE_WINDOW_ALLOCATE_BUFFERS:
         allocateBuffers();
         res = NO_ERROR;
@@ -1457,6 +1474,15 @@
     return NO_ERROR;
 }
 
+int Surface::dispatchAddQueryInterceptor(va_list args) {
+    ANativeWindow_queryInterceptor interceptor = va_arg(args, ANativeWindow_queryInterceptor);
+    void* data = va_arg(args, void*);
+    std::lock_guard<std::shared_mutex> lock(mInterceptorMutex);
+    mQueryInterceptor = interceptor;
+    mQueryInterceptorData = data;
+    return NO_ERROR;
+}
+
 int Surface::dispatchGetLastQueuedBuffer(va_list args) {
     AHardwareBuffer** buffer = va_arg(args, AHardwareBuffer**);
     int* fence = va_arg(args, int*);
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index a52f298..5922f3a 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -1437,6 +1437,22 @@
     return *this;
 }
 
+SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setFixedTransformHint(
+        const sp<SurfaceControl>& sc, int32_t fixedTransformHint) {
+    layer_state_t* s = getLayerState(sc);
+    if (!s) {
+        mStatus = BAD_INDEX;
+        return *this;
+    }
+
+    const ui::Transform::RotationFlags transform = fixedTransformHint == -1
+            ? ui::Transform::ROT_INVALID
+            : ui::Transform::toRotationFlags(static_cast<ui::Rotation>(fixedTransformHint));
+    s->what |= layer_state_t::eFixedTransformHintChanged;
+    s->fixedTransformHint = transform;
+    return *this;
+}
+
 // ---------------------------------------------------------------------------
 
 DisplayState& SurfaceComposerClient::Transaction::getDisplayState(const sp<IBinder>& token) {
diff --git a/libs/gui/include/gui/DisplayEventDispatcher.h b/libs/gui/include/gui/DisplayEventDispatcher.h
index fcdf6bf..f210c34 100644
--- a/libs/gui/include/gui/DisplayEventDispatcher.h
+++ b/libs/gui/include/gui/DisplayEventDispatcher.h
@@ -31,7 +31,7 @@
     status_t initialize();
     void dispose();
     status_t scheduleVsync();
-    void toggleConfigEvents(ISurfaceComposer::ConfigChanged configChangeFlag);
+    void requestLatestConfig();
     int getFd() const;
     virtual int handleEvent(int receiveFd, int events, void* data);
 
@@ -42,7 +42,6 @@
     sp<Looper> mLooper;
     DisplayEventReceiver mReceiver;
     bool mWaitingForVsync;
-    ISurfaceComposer::ConfigChanged mConfigChangeFlag;
 
     virtual void dispatchVsync(nsecs_t timestamp, PhysicalDisplayId displayId, uint32_t count) = 0;
     virtual void dispatchHotplug(nsecs_t timestamp, PhysicalDisplayId displayId,
diff --git a/libs/gui/include/gui/DisplayEventReceiver.h b/libs/gui/include/gui/DisplayEventReceiver.h
index d9a0253..8d49184 100644
--- a/libs/gui/include/gui/DisplayEventReceiver.h
+++ b/libs/gui/include/gui/DisplayEventReceiver.h
@@ -147,9 +147,10 @@
     status_t requestNextVsync();
 
     /*
-     * toggleConfigEvents() toggles delivery of config change events.
+     * requestLatestConfig() force-requests the current config for the primary
+     * display.
      */
-    status_t toggleConfigEvents(ISurfaceComposer::ConfigChanged configChangeFlag);
+    status_t requestLatestConfig();
 
 private:
     sp<IDisplayEventConnection> mEventConnection;
diff --git a/libs/gui/include/gui/IDisplayEventConnection.h b/libs/gui/include/gui/IDisplayEventConnection.h
index 8b35ef6..674aafd 100644
--- a/libs/gui/include/gui/IDisplayEventConnection.h
+++ b/libs/gui/include/gui/IDisplayEventConnection.h
@@ -53,11 +53,9 @@
     virtual void requestNextVsync() = 0; // Asynchronous
 
     /*
-     * togglesConfigEvents() configures whether or not display config changes
-     * should be propagated.
+     * requestLatestConfig() requests the config for the primary display.
      */
-    virtual void toggleConfigEvents(
-            ISurfaceComposer::ConfigChanged configChangeFlag) = 0; // Asynchronous
+    virtual void requestLatestConfig() = 0; // Asynchronous
 };
 
 class BnDisplayEventConnection : public SafeBnInterface<IDisplayEventConnection> {
diff --git a/libs/gui/include/gui/LayerState.h b/libs/gui/include/gui/LayerState.h
index 2b2f773..e60f677 100644
--- a/libs/gui/include/gui/LayerState.h
+++ b/libs/gui/include/gui/LayerState.h
@@ -35,6 +35,7 @@
 #include <ui/Rect.h>
 #include <ui/Region.h>
 #include <ui/Rotation.h>
+#include <ui/Transform.h>
 #include <utils/Errors.h>
 
 namespace android {
@@ -103,6 +104,7 @@
         eFrameRateChanged = 0x40'00000000,
         eBackgroundBlurRadiusChanged = 0x80'00000000,
         eProducerDisconnect = 0x100'00000000,
+        eFixedTransformHintChanged = 0x200'00000000,
     };
 
     layer_state_t()
@@ -136,7 +138,8 @@
             shadowRadius(0.0f),
             frameRateSelectionPriority(-1),
             frameRate(0.0f),
-            frameRateCompatibility(ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT) {
+            frameRateCompatibility(ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT),
+            fixedTransformHint(ui::Transform::ROT_INVALID) {
         matrix.dsdx = matrix.dtdy = 1.0f;
         matrix.dsdy = matrix.dtdx = 0.0f;
         hdrMetadata.validTypes = 0;
@@ -225,6 +228,15 @@
     // Layer frame rate and compatibility. See ANativeWindow_setFrameRate().
     float frameRate;
     int8_t frameRateCompatibility;
+
+    // Set by window manager indicating the layer and all its children are
+    // in a different orientation than the display. The hint suggests that
+    // the graphic producers should receive a transform hint as if the
+    // display was in this orientation. When the display changes to match
+    // the layer orientation, the graphic producer may not need to allocate
+    // a buffer of a different size. -1 means the transform hint is not set,
+    // otherwise the value will be a valid ui::Rotation.
+    ui::Transform::RotationFlags fixedTransformHint;
 };
 
 struct ComposerState {
diff --git a/libs/gui/include/gui/Surface.h b/libs/gui/include/gui/Surface.h
index 917c0d4..49c83da 100644
--- a/libs/gui/include/gui/Surface.h
+++ b/libs/gui/include/gui/Surface.h
@@ -209,6 +209,7 @@
                                      int* fenceFd);
     static int performInternal(ANativeWindow* window, int operation, va_list args);
     static int queueBufferInternal(ANativeWindow* window, ANativeWindowBuffer* buffer, int fenceFd);
+    static int queryInternal(const ANativeWindow* window, int what, int* value);
 
     static int hook_cancelBuffer_DEPRECATED(ANativeWindow* window,
             ANativeWindowBuffer* buffer);
@@ -261,6 +262,7 @@
     int dispatchAddDequeueInterceptor(va_list args);
     int dispatchAddPerformInterceptor(va_list args);
     int dispatchAddQueueInterceptor(va_list args);
+    int dispatchAddQueryInterceptor(va_list args);
     int dispatchGetLastQueuedBuffer(va_list args);
     bool transformToDisplayInverse();
 
@@ -468,7 +470,7 @@
     mutable Mutex mMutex;
 
     // mInterceptorMutex is the mutex guarding interceptors.
-    std::shared_mutex mInterceptorMutex;
+    mutable std::shared_mutex mInterceptorMutex;
 
     ANativeWindow_cancelBufferInterceptor mCancelInterceptor = nullptr;
     void* mCancelInterceptorData = nullptr;
@@ -478,6 +480,8 @@
     void* mPerformInterceptorData = nullptr;
     ANativeWindow_queueBufferInterceptor mQueueInterceptor = nullptr;
     void* mQueueInterceptorData = nullptr;
+    ANativeWindow_queryInterceptor mQueryInterceptor = nullptr;
+    void* mQueryInterceptorData = nullptr;
 
     // must be used from the lock/unlock thread
     sp<GraphicBuffer>           mLockedBuffer;
diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h
index 531aed7..e981a39 100644
--- a/libs/gui/include/gui/SurfaceComposerClient.h
+++ b/libs/gui/include/gui/SurfaceComposerClient.h
@@ -519,6 +519,14 @@
         Transaction& setFrameRate(const sp<SurfaceControl>& sc, float frameRate,
                                   int8_t compatibility);
 
+        // Set by window manager indicating the layer and all its children are
+        // in a different orientation than the display. The hint suggests that
+        // the graphic producers should receive a transform hint as if the
+        // display was in this orientation. When the display changes to match
+        // the layer orientation, the graphic producer may not need to allocate
+        // a buffer of a different size.
+        Transaction& setFixedTransformHint(const sp<SurfaceControl>& sc, int32_t transformHint);
+
         status_t setDisplaySurface(const sp<IBinder>& token,
                 const sp<IGraphicBufferProducer>& bufferProducer);
 
diff --git a/libs/gui/sysprop/Android.bp b/libs/gui/sysprop/Android.bp
index e7f7c1f..64b1eac 100644
--- a/libs/gui/sysprop/Android.bp
+++ b/libs/gui/sysprop/Android.bp
@@ -4,4 +4,7 @@
     api_packages: ["android.sysprop"],
     property_owner: "Platform",
     vendor_available: true,
+    cpp: {
+        min_sdk_version: "29",
+    },
 }
diff --git a/libs/input/InputWindow.cpp b/libs/input/InputWindow.cpp
index b27b050..85a2015 100644
--- a/libs/input/InputWindow.cpp
+++ b/libs/input/InputWindow.cpp
@@ -42,6 +42,7 @@
             && y >= frameTop && y < frameBottom;
 }
 
+// TODO(b/155781676): Remove and replace call points with trustedOverlay when that is ready.
 bool InputWindowInfo::isTrustedOverlay() const {
     return layoutParamsType == TYPE_INPUT_METHOD || layoutParamsType == TYPE_INPUT_METHOD_DIALOG ||
             layoutParamsType == TYPE_MAGNIFICATION_OVERLAY || layoutParamsType == TYPE_STATUS_BAR ||
@@ -51,7 +52,8 @@
             layoutParamsType == TYPE_SECURE_SYSTEM_OVERLAY ||
             layoutParamsType == TYPE_DOCK_DIVIDER ||
             layoutParamsType == TYPE_ACCESSIBILITY_OVERLAY ||
-            layoutParamsType == TYPE_INPUT_CONSUMER;
+            layoutParamsType == TYPE_INPUT_CONSUMER ||
+            layoutParamsType == TYPE_TRUSTED_APPLICATION_OVERLAY;
 }
 
 bool InputWindowInfo::supportsSplitTouch() const {
diff --git a/libs/nativebase/Android.bp b/libs/nativebase/Android.bp
index 7375a2b..9e7e4a2 100644
--- a/libs/nativebase/Android.bp
+++ b/libs/nativebase/Android.bp
@@ -25,5 +25,6 @@
         windows: {
             enabled: true,
         },
-    }
+    },
+    min_sdk_version: "29",
 }
diff --git a/libs/nativedisplay/AChoreographer.cpp b/libs/nativedisplay/AChoreographer.cpp
index 0ff33ac..e458b2e 100644
--- a/libs/nativedisplay/AChoreographer.cpp
+++ b/libs/nativedisplay/AChoreographer.cpp
@@ -17,24 +17,63 @@
 #define LOG_TAG "Choreographer"
 //#define LOG_NDEBUG 0
 
-#include <apex/choreographer.h>
+#include <android-base/thread_annotations.h>
 #include <gui/DisplayEventDispatcher.h>
 #include <gui/ISurfaceComposer.h>
 #include <gui/SurfaceComposerClient.h>
+#include <nativehelper/JNIHelp.h>
+#include <private/android/choreographer.h>
 #include <utils/Looper.h>
-#include <utils/Mutex.h>
 #include <utils/Timers.h>
 
 #include <cinttypes>
+#include <mutex>
 #include <optional>
 #include <queue>
 #include <thread>
 
-namespace android {
+namespace {
+struct {
+    // Global JVM that is provided by zygote
+    JavaVM* jvm = nullptr;
+    struct {
+        jclass clazz;
+        jmethodID getInstance;
+        jmethodID registerNativeChoreographerForRefreshRateCallbacks;
+        jmethodID unregisterNativeChoreographerForRefreshRateCallbacks;
+    } displayManagerGlobal;
+} gJni;
 
-static inline const char* toString(bool value) {
+// Gets the JNIEnv* for this thread, and performs one-off initialization if we
+// have never retrieved a JNIEnv* pointer before.
+JNIEnv* getJniEnv() {
+    if (gJni.jvm == nullptr) {
+        ALOGW("AChoreographer: No JVM provided!");
+        return nullptr;
+    }
+
+    JNIEnv* env = nullptr;
+    if (gJni.jvm->GetEnv((void**)&env, JNI_VERSION_1_4) != JNI_OK) {
+        ALOGD("Attaching thread to JVM for AChoreographer");
+        JavaVMAttachArgs args = {JNI_VERSION_1_4, "AChoreographer_env", NULL};
+        jint attachResult = gJni.jvm->AttachCurrentThreadAsDaemon(&env, (void*)&args);
+        if (attachResult != JNI_OK) {
+            ALOGE("Unable to attach thread. Error: %d", attachResult);
+            return nullptr;
+        }
+    }
+    if (env == nullptr) {
+        ALOGW("AChoreographer: No JNI env available!");
+    }
+    return env;
+}
+
+inline const char* toString(bool value) {
     return value ? "true" : "false";
 }
+} // namespace
+
+namespace android {
 
 struct FrameCallback {
     AChoreographer_frameCallback callback;
@@ -52,24 +91,43 @@
 struct RefreshRateCallback {
     AChoreographer_refreshRateCallback callback;
     void* data;
+    bool firstCallbackFired = false;
 };
 
+class Choreographer;
+
+struct {
+    std::mutex lock;
+    std::vector<Choreographer*> ptrs GUARDED_BY(lock);
+    bool registeredToDisplayManager GUARDED_BY(lock) = false;
+
+    std::atomic<nsecs_t> mLastKnownVsync = -1;
+} gChoreographers;
+
 class Choreographer : public DisplayEventDispatcher, public MessageHandler {
 public:
-    explicit Choreographer(const sp<Looper>& looper);
+    explicit Choreographer(const sp<Looper>& looper) EXCLUDES(gChoreographers.lock);
     void postFrameCallbackDelayed(AChoreographer_frameCallback cb,
                                   AChoreographer_frameCallback64 cb64, void* data, nsecs_t delay);
-    void registerRefreshRateCallback(AChoreographer_refreshRateCallback cb, void* data);
+    void registerRefreshRateCallback(AChoreographer_refreshRateCallback cb, void* data)
+            EXCLUDES(gChoreographers.lock);
     void unregisterRefreshRateCallback(AChoreographer_refreshRateCallback cb, void* data);
+    // Drains the queue of pending vsync periods and dispatches refresh rate
+    // updates to callbacks.
+    // The assumption is that this method is only called on a single
+    // processing thread, either by looper or by AChoreographer_handleEvents
+    void handleRefreshRateUpdates();
+    void scheduleLatestConfigRequest();
 
     enum {
         MSG_SCHEDULE_CALLBACKS = 0,
-        MSG_SCHEDULE_VSYNC = 1
+        MSG_SCHEDULE_VSYNC = 1,
+        MSG_HANDLE_REFRESH_RATE_UPDATES = 2,
     };
     virtual void handleMessage(const Message& message) override;
 
     static Choreographer* getForThread();
-    virtual ~Choreographer() = default;
+    virtual ~Choreographer() override EXCLUDES(gChoreographers.lock);
 
 private:
     Choreographer(const Choreographer&) = delete;
@@ -81,21 +139,17 @@
 
     void scheduleCallbacks();
 
+    std::mutex mLock;
     // Protected by mLock
     std::priority_queue<FrameCallback> mFrameCallbacks;
-
-    // Protected by mLock
     std::vector<RefreshRateCallback> mRefreshRateCallbacks;
-    nsecs_t mVsyncPeriod = 0;
 
-    mutable Mutex mLock;
+    nsecs_t mLatestVsyncPeriod = -1;
 
     const sp<Looper> mLooper;
     const std::thread::id mThreadId;
-    const std::optional<PhysicalDisplayId> mInternalDisplayId;
 };
 
-
 static thread_local Choreographer* gChoreographer;
 Choreographer* Choreographer::getForThread() {
     if (gChoreographer == nullptr) {
@@ -115,17 +169,47 @@
 }
 
 Choreographer::Choreographer(const sp<Looper>& looper)
-      : DisplayEventDispatcher(looper),
+      : DisplayEventDispatcher(looper, ISurfaceComposer::VsyncSource::eVsyncSourceApp,
+                               ISurfaceComposer::ConfigChanged::eConfigChangedDispatch),
         mLooper(looper),
-        mThreadId(std::this_thread::get_id()),
-        mInternalDisplayId(SurfaceComposerClient::getInternalDisplayId()) {}
+        mThreadId(std::this_thread::get_id()) {
+    std::lock_guard<std::mutex> _l(gChoreographers.lock);
+    gChoreographers.ptrs.push_back(this);
+}
+
+Choreographer::~Choreographer() {
+    std::lock_guard<std::mutex> _l(gChoreographers.lock);
+    gChoreographers.ptrs.erase(std::remove_if(gChoreographers.ptrs.begin(),
+                                              gChoreographers.ptrs.end(),
+                                              [=](Choreographer* c) { return c == this; }),
+                               gChoreographers.ptrs.end());
+    // Only poke DisplayManagerGlobal to unregister if we previously registered
+    // callbacks.
+    if (gChoreographers.ptrs.empty() && gChoreographers.registeredToDisplayManager) {
+        JNIEnv* env = getJniEnv();
+        if (env == nullptr) {
+            ALOGW("JNI environment is unavailable, skipping choreographer cleanup");
+            return;
+        }
+        jobject dmg = env->CallStaticObjectMethod(gJni.displayManagerGlobal.clazz,
+                                                  gJni.displayManagerGlobal.getInstance);
+        if (dmg == nullptr) {
+            ALOGW("DMS is not initialized yet, skipping choreographer cleanup");
+        } else {
+            env->CallVoidMethod(dmg,
+                                gJni.displayManagerGlobal
+                                        .unregisterNativeChoreographerForRefreshRateCallbacks);
+            env->DeleteLocalRef(dmg);
+        }
+    }
+}
 
 void Choreographer::postFrameCallbackDelayed(
         AChoreographer_frameCallback cb, AChoreographer_frameCallback64 cb64, void* data, nsecs_t delay) {
     nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
     FrameCallback callback{cb, cb64, data, now + delay};
     {
-        AutoMutex _l{mLock};
+        std::lock_guard<std::mutex> _l{mLock};
         mFrameCallbacks.push(callback);
     }
     if (callback.dueTime <= now) {
@@ -150,37 +234,68 @@
 }
 
 void Choreographer::registerRefreshRateCallback(AChoreographer_refreshRateCallback cb, void* data) {
+    std::lock_guard<std::mutex> _l{mLock};
+    for (const auto& callback : mRefreshRateCallbacks) {
+        // Don't re-add callbacks.
+        if (cb == callback.callback && data == callback.data) {
+            return;
+        }
+    }
+    mRefreshRateCallbacks.emplace_back(
+            RefreshRateCallback{.callback = cb, .data = data, .firstCallbackFired = false});
+    bool needsRegistration = false;
     {
-        AutoMutex _l{mLock};
-        for (const auto& callback : mRefreshRateCallbacks) {
-            // Don't re-add callbacks.
-            if (cb == callback.callback && data == callback.data) {
-                return;
+        std::lock_guard<std::mutex> _l2(gChoreographers.lock);
+        needsRegistration = !gChoreographers.registeredToDisplayManager;
+    }
+    if (needsRegistration) {
+        JNIEnv* env = getJniEnv();
+        if (env == nullptr) {
+            ALOGW("JNI environment is unavailable, skipping registration");
+            return;
+        }
+        jobject dmg = env->CallStaticObjectMethod(gJni.displayManagerGlobal.clazz,
+                                                  gJni.displayManagerGlobal.getInstance);
+        if (dmg == nullptr) {
+            ALOGW("DMS is not initialized yet: skipping registration");
+            return;
+        } else {
+            env->CallVoidMethod(dmg,
+                                gJni.displayManagerGlobal
+                                        .registerNativeChoreographerForRefreshRateCallbacks,
+                                reinterpret_cast<int64_t>(this));
+            env->DeleteLocalRef(dmg);
+            {
+                std::lock_guard<std::mutex> _l2(gChoreographers.lock);
+                gChoreographers.registeredToDisplayManager = true;
             }
         }
-        mRefreshRateCallbacks.emplace_back(RefreshRateCallback{cb, data});
-        toggleConfigEvents(ISurfaceComposer::ConfigChanged::eConfigChangedDispatch);
+    } else {
+        scheduleLatestConfigRequest();
     }
 }
 
 void Choreographer::unregisterRefreshRateCallback(AChoreographer_refreshRateCallback cb,
                                                   void* data) {
-    {
-        AutoMutex _l{mLock};
-        mRefreshRateCallbacks.erase(std::remove_if(mRefreshRateCallbacks.begin(),
-                                                   mRefreshRateCallbacks.end(),
-                                                   [&](const RefreshRateCallback& callback) {
-                                                       return cb == callback.callback &&
-                                                               data == callback.data;
-                                                   }),
-                                    mRefreshRateCallbacks.end());
-        if (mRefreshRateCallbacks.empty()) {
-            toggleConfigEvents(ISurfaceComposer::ConfigChanged::eConfigChangedSuppress);
-            // If callbacks are empty then clear out the most recently seen
-            // vsync period so that when another callback is registered then the
-            // up-to-date refresh rate can be communicated to the app again.
-            mVsyncPeriod = 0;
-        }
+    std::lock_guard<std::mutex> _l{mLock};
+    mRefreshRateCallbacks.erase(std::remove_if(mRefreshRateCallbacks.begin(),
+                                               mRefreshRateCallbacks.end(),
+                                               [&](const RefreshRateCallback& callback) {
+                                                   return cb == callback.callback &&
+                                                           data == callback.data;
+                                               }),
+                                mRefreshRateCallbacks.end());
+}
+
+void Choreographer::scheduleLatestConfigRequest() {
+    if (mLooper != nullptr) {
+        Message m{MSG_HANDLE_REFRESH_RATE_UPDATES};
+        mLooper->sendMessage(this, m);
+    } else {
+        // If the looper thread is detached from Choreographer, then refresh rate
+        // changes will be handled in AChoreographer_handlePendingEvents, so we
+        // need to redispatch a config from SF
+        requestLatestConfig();
     }
 }
 
@@ -188,7 +303,7 @@
     const nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
     nsecs_t dueTime;
     {
-        AutoMutex _{mLock};
+        std::lock_guard<std::mutex> _l{mLock};
         // If there are no pending callbacks then don't schedule a vsync
         if (mFrameCallbacks.empty()) {
             return;
@@ -203,13 +318,35 @@
     }
 }
 
+void Choreographer::handleRefreshRateUpdates() {
+    std::vector<RefreshRateCallback> callbacks{};
+    const nsecs_t pendingPeriod = gChoreographers.mLastKnownVsync.load();
+    const nsecs_t lastPeriod = mLatestVsyncPeriod;
+    if (pendingPeriod > 0) {
+        mLatestVsyncPeriod = pendingPeriod;
+    }
+    {
+        std::lock_guard<std::mutex> _l{mLock};
+        for (auto& cb : mRefreshRateCallbacks) {
+            callbacks.push_back(cb);
+            cb.firstCallbackFired = true;
+        }
+    }
+
+    for (auto& cb : callbacks) {
+        if (!cb.firstCallbackFired || (pendingPeriod > 0 && pendingPeriod != lastPeriod)) {
+            cb.callback(pendingPeriod, cb.data);
+        }
+    }
+}
+
 // TODO(b/74619554): The PhysicalDisplayId is ignored because SF only emits VSYNC events for the
 // internal display and DisplayEventReceiver::requestNextVsync only allows requesting VSYNC for
 // the internal display implicitly.
 void Choreographer::dispatchVsync(nsecs_t timestamp, PhysicalDisplayId, uint32_t) {
     std::vector<FrameCallback> callbacks{};
     {
-        AutoMutex _l{mLock};
+        std::lock_guard<std::mutex> _l{mLock};
         nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
         while (!mFrameCallbacks.empty() && mFrameCallbacks.top().dueTime < now) {
             callbacks.push_back(mFrameCallbacks.top());
@@ -236,20 +373,29 @@
 // display, so as such Choreographer does not support the notion of multiple
 // displays. When multi-display choreographer is properly supported, then
 // PhysicalDisplayId should no longer be ignored.
-void Choreographer::dispatchConfigChanged(nsecs_t, PhysicalDisplayId, int32_t,
+void Choreographer::dispatchConfigChanged(nsecs_t, PhysicalDisplayId displayId, int32_t configId,
                                           nsecs_t vsyncPeriod) {
+    ALOGV("choreographer %p ~ received config change event "
+          "(displayId=%" ANDROID_PHYSICAL_DISPLAY_ID_FORMAT ", configId=%d).",
+          this, displayId, configId);
+
+    const nsecs_t lastPeriod = mLatestVsyncPeriod;
+    std::vector<RefreshRateCallback> callbacks{};
     {
-        AutoMutex _l{mLock};
-        for (const auto& cb : mRefreshRateCallbacks) {
-            // Only perform the callback when the old refresh rate is different
-            // from the new refresh rate, so that we don't dispatch the callback
-            // on every single configuration change.
-            if (mVsyncPeriod != vsyncPeriod) {
-                cb.callback(vsyncPeriod, cb.data);
-            }
+        std::lock_guard<std::mutex> _l{mLock};
+        for (auto& cb : mRefreshRateCallbacks) {
+            callbacks.push_back(cb);
+            cb.firstCallbackFired = true;
         }
-        mVsyncPeriod = vsyncPeriod;
     }
+
+    for (auto& cb : callbacks) {
+        if (!cb.firstCallbackFired || (vsyncPeriod > 0 && vsyncPeriod != lastPeriod)) {
+            cb.callback(vsyncPeriod, cb.data);
+        }
+    }
+
+    mLatestVsyncPeriod = vsyncPeriod;
 }
 
 void Choreographer::handleMessage(const Message& message) {
@@ -260,19 +406,80 @@
     case MSG_SCHEDULE_VSYNC:
         scheduleVsync();
         break;
+    case MSG_HANDLE_REFRESH_RATE_UPDATES:
+        handleRefreshRateUpdates();
+        break;
     }
 }
 
-}
-
-/* Glue for the NDK interface */
-
+} // namespace android
 using namespace android;
 
 static inline Choreographer* AChoreographer_to_Choreographer(AChoreographer* choreographer) {
     return reinterpret_cast<Choreographer*>(choreographer);
 }
 
+// Glue for private C api
+namespace android {
+void AChoreographer_signalRefreshRateCallbacks(nsecs_t vsyncPeriod) EXCLUDES(gChoreographers.lock) {
+    std::lock_guard<std::mutex> _l(gChoreographers.lock);
+    gChoreographers.mLastKnownVsync.store(vsyncPeriod);
+    for (auto c : gChoreographers.ptrs) {
+        c->scheduleLatestConfigRequest();
+    }
+}
+
+void AChoreographer_initJVM(JNIEnv* env) {
+    env->GetJavaVM(&gJni.jvm);
+    // Now we need to find the java classes.
+    jclass dmgClass = env->FindClass("android/hardware/display/DisplayManagerGlobal");
+    gJni.displayManagerGlobal.clazz = static_cast<jclass>(env->NewGlobalRef(dmgClass));
+    gJni.displayManagerGlobal.getInstance =
+            env->GetStaticMethodID(dmgClass, "getInstance",
+                                   "()Landroid/hardware/display/DisplayManagerGlobal;");
+    gJni.displayManagerGlobal.registerNativeChoreographerForRefreshRateCallbacks =
+            env->GetMethodID(dmgClass, "registerNativeChoreographerForRefreshRateCallbacks", "()V");
+    gJni.displayManagerGlobal.unregisterNativeChoreographerForRefreshRateCallbacks =
+            env->GetMethodID(dmgClass, "unregisterNativeChoreographerForRefreshRateCallbacks",
+                             "()V");
+}
+
+AChoreographer* AChoreographer_routeGetInstance() {
+    return AChoreographer_getInstance();
+}
+void AChoreographer_routePostFrameCallback(AChoreographer* choreographer,
+                                           AChoreographer_frameCallback callback, void* data) {
+    return AChoreographer_postFrameCallback(choreographer, callback, data);
+}
+void AChoreographer_routePostFrameCallbackDelayed(AChoreographer* choreographer,
+                                                  AChoreographer_frameCallback callback, void* data,
+                                                  long delayMillis) {
+    return AChoreographer_postFrameCallbackDelayed(choreographer, callback, data, delayMillis);
+}
+void AChoreographer_routePostFrameCallback64(AChoreographer* choreographer,
+                                             AChoreographer_frameCallback64 callback, void* data) {
+    return AChoreographer_postFrameCallback64(choreographer, callback, data);
+}
+void AChoreographer_routePostFrameCallbackDelayed64(AChoreographer* choreographer,
+                                                    AChoreographer_frameCallback64 callback,
+                                                    void* data, uint32_t delayMillis) {
+    return AChoreographer_postFrameCallbackDelayed64(choreographer, callback, data, delayMillis);
+}
+void AChoreographer_routeRegisterRefreshRateCallback(AChoreographer* choreographer,
+                                                     AChoreographer_refreshRateCallback callback,
+                                                     void* data) {
+    return AChoreographer_registerRefreshRateCallback(choreographer, callback, data);
+}
+void AChoreographer_routeUnregisterRefreshRateCallback(AChoreographer* choreographer,
+                                                       AChoreographer_refreshRateCallback callback,
+                                                       void* data) {
+    return AChoreographer_unregisterRefreshRateCallback(choreographer, callback, data);
+}
+
+} // namespace android
+
+/* Glue for the NDK interface */
+
 static inline const Choreographer* AChoreographer_to_Choreographer(
         const AChoreographer* choreographer) {
     return reinterpret_cast<const Choreographer*>(choreographer);
@@ -343,5 +550,6 @@
     // Pass dummy fd and events args to handleEvent, since the underlying
     // DisplayEventDispatcher doesn't need them outside of validating that a
     // Looper instance didn't break, but these args circumvent those checks.
-    AChoreographer_to_Choreographer(choreographer)->handleEvent(-1, Looper::EVENT_INPUT, data);
+    Choreographer* impl = AChoreographer_to_Choreographer(choreographer);
+    impl->handleEvent(-1, Looper::EVENT_INPUT, data);
 }
diff --git a/libs/nativedisplay/Android.bp b/libs/nativedisplay/Android.bp
index c956578..f56b3a2 100644
--- a/libs/nativedisplay/Android.bp
+++ b/libs/nativedisplay/Android.bp
@@ -12,23 +12,16 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-ndk_headers {
-    name: "libnativedisplay_ndk_headers",
-    from: "include/android",
-    to: "android",
-    srcs: ["include/android/*.h"],
-    license: "NOTICE",
-}
-
 cc_library_headers {
     name: "libnativedisplay_headers",
-    export_include_dirs: ["include"],
+    export_include_dirs: ["include",],
 }
 
-cc_library {
+cc_library_shared {
     name: "libnativedisplay",
     export_include_dirs: [
         "include",
+        "include-private",
     ],
 
     clang: true,
@@ -63,6 +56,10 @@
         "libnativehelper",
     ],
 
+    export_shared_lib_headers: [
+        "libnativehelper",
+    ],
+
     header_libs: [
         "libnativedisplay_headers",
     ],
diff --git a/libs/nativedisplay/include-private/private/android/choreographer.h b/libs/nativedisplay/include-private/private/android/choreographer.h
new file mode 100644
index 0000000..2164930
--- /dev/null
+++ b/libs/nativedisplay/include-private/private/android/choreographer.h
@@ -0,0 +1,55 @@
+/*
+ * 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 <apex/choreographer.h>
+#include <inttypes.h>
+#include <nativehelper/JNIHelp.h>
+
+namespace android {
+
+// Registers the global JVM for AChoreographer
+void AChoreographer_initJVM(JNIEnv* env);
+
+// Signals all AChoregorapher* instances that a new vsync period is available
+// for consumption by callbacks.
+void AChoreographer_signalRefreshRateCallbacks(int64_t vsyncPeriod);
+
+// Trampoline functions allowing libandroid.so to define the NDK symbols without including
+// the entirety of libnativedisplay as a whole static lib. As libnativedisplay
+// maintains global state, libnativedisplay can never be directly statically
+// linked so that global state won't be duplicated. This way libandroid.so can
+// reroute the NDK methods into the implementations defined by libnativedisplay
+AChoreographer* AChoreographer_routeGetInstance();
+void AChoreographer_routePostFrameCallback(AChoreographer* choreographer,
+                                           AChoreographer_frameCallback callback, void* data);
+void AChoreographer_routePostFrameCallbackDelayed(AChoreographer* choreographer,
+                                                  AChoreographer_frameCallback callback, void* data,
+                                                  long delayMillis);
+void AChoreographer_routePostFrameCallback64(AChoreographer* choreographer,
+                                             AChoreographer_frameCallback64 callback, void* data);
+void AChoreographer_routePostFrameCallbackDelayed64(AChoreographer* choreographer,
+                                                    AChoreographer_frameCallback64 callback,
+                                                    void* data, uint32_t delayMillis);
+void AChoreographer_routeRegisterRefreshRateCallback(AChoreographer* choreographer,
+                                                     AChoreographer_refreshRateCallback callback,
+                                                     void* data);
+void AChoreographer_routeUnregisterRefreshRateCallback(AChoreographer* choreographer,
+                                                       AChoreographer_refreshRateCallback callback,
+                                                       void* data);
+
+} // namespace android
diff --git a/libs/nativedisplay/include/surfacetexture/surface_texture_platform.h b/libs/nativedisplay/include/surfacetexture/surface_texture_platform.h
index 6a94a77..e2d036b 100644
--- a/libs/nativedisplay/include/surfacetexture/surface_texture_platform.h
+++ b/libs/nativedisplay/include/surfacetexture/surface_texture_platform.h
@@ -19,7 +19,7 @@
 
 #include <EGL/egl.h>
 #include <EGL/eglext.h>
-
+#include <nativehelper/JNIHelp.h>
 #include <system/graphics.h>
 
 // This file provides a facade API on top of SurfaceTexture, which avoids using
@@ -30,6 +30,20 @@
 
 namespace android {
 
+// Trampoline functions allowing libandroid.so to define the NDK symbols without including
+// the entirety of libnativedisplay as a whole static lib. As libnativedisplay
+// maintains global state, libnativedisplay can never be directly statically
+// linked so that global state won't be duplicated. This way libandroid.so can
+// reroute the NDK methods into the implementations defined by libnativedisplay
+ANativeWindow* ASurfaceTexture_routeAcquireANativeWindow(ASurfaceTexture* st);
+int ASurfaceTexture_routeAttachToGLContext(ASurfaceTexture* st, uint32_t texName);
+int ASurfaceTexture_routeDetachFromGLContext(ASurfaceTexture* st);
+void ASurfaceTexture_routeRelease(ASurfaceTexture* st);
+int ASurfaceTexture_routeUpdateTexImage(ASurfaceTexture* st);
+void ASurfaceTexture_routeGetTransformMatrix(ASurfaceTexture* st, float mtx[16]);
+int64_t ASurfaceTexture_routeGetTimestamp(ASurfaceTexture* st);
+ASurfaceTexture* ASurfaceTexture_routeFromSurfaceTexture(JNIEnv* env, jobject surfacetexture);
+
 /**
  * ASurfaceTexture_getCurrentTextureTarget returns the texture target of the
  * current texture.
diff --git a/libs/nativedisplay/libnativedisplay.map.txt b/libs/nativedisplay/libnativedisplay.map.txt
index 483fb25..fc59431 100644
--- a/libs/nativedisplay/libnativedisplay.map.txt
+++ b/libs/nativedisplay/libnativedisplay.map.txt
@@ -20,6 +20,15 @@
 LIBNATIVEDISPLAY_PLATFORM {
   global:
     extern "C++" {
+      android::AChoreographer_initJVM*;
+      android::AChoreographer_routeGetInstance*;
+      android::AChoreographer_routePostFrameCallback*;
+      android::AChoreographer_routePostFrameCallbackDelayed*;
+      android::AChoreographer_routePostFrameCallback64*;
+      android::AChoreographer_routePostFrameCallbackDelayed64*;
+      android::AChoreographer_routeRegisterRefreshRateCallback*;
+      android::AChoreographer_routeUnregisterRefreshRateCallback*;
+      android::AChoreographer_signalRefreshRateCallbacks*;
       android::ADisplay_acquirePhysicalDisplays*;
       android::ADisplay_release*;
       android::ADisplay_getMaxSupportedFps*;
@@ -36,6 +45,14 @@
       android::ASurfaceTexture_takeConsumerOwnership*;
       android::ASurfaceTexture_releaseConsumerOwnership*;
       android::ASurfaceTexture_dequeueBuffer*;
+      android::ASurfaceTexture_routeAcquireANativeWindow*;
+      android::ASurfaceTexture_routeAttachToGLContext*;
+      android::ASurfaceTexture_routeDetachFromGLContext*;
+      android::ASurfaceTexture_routeGetTimestamp*;
+      android::ASurfaceTexture_routeGetTransformMatrix*;
+      android::ASurfaceTexture_routeUpdateTexImage*;
+      android::ASurfaceTexture_routeFromSurfaceTexture*;
+      android::ASurfaceTexture_routeRelease*;
       android::SurfaceTexture*;
     };
     ASurfaceTexture_acquireANativeWindow;
diff --git a/libs/nativedisplay/surfacetexture/surface_texture.cpp b/libs/nativedisplay/surfacetexture/surface_texture.cpp
index 1670fbb..d1bcd8d 100644
--- a/libs/nativedisplay/surfacetexture/surface_texture.cpp
+++ b/libs/nativedisplay/surfacetexture/surface_texture.cpp
@@ -149,6 +149,37 @@
 
 // The following functions are private/unstable API.
 namespace android {
+ANativeWindow* ASurfaceTexture_routeAcquireANativeWindow(ASurfaceTexture* st) {
+    return ASurfaceTexture_acquireANativeWindow(st);
+}
+
+int ASurfaceTexture_routeAttachToGLContext(ASurfaceTexture* st, uint32_t texName) {
+    return ASurfaceTexture_attachToGLContext(st, texName);
+}
+
+void ASurfaceTexture_routeRelease(ASurfaceTexture* st) {
+    return ASurfaceTexture_release(st);
+}
+
+int ASurfaceTexture_routeDetachFromGLContext(ASurfaceTexture* st) {
+    return ASurfaceTexture_detachFromGLContext(st);
+}
+
+int ASurfaceTexture_routeUpdateTexImage(ASurfaceTexture* st) {
+    return ASurfaceTexture_updateTexImage(st);
+}
+
+void ASurfaceTexture_routeGetTransformMatrix(ASurfaceTexture* st, float mtx[16]) {
+    return ASurfaceTexture_getTransformMatrix(st, mtx);
+}
+
+int64_t ASurfaceTexture_routeGetTimestamp(ASurfaceTexture* st) {
+    return ASurfaceTexture_getTimestamp(st);
+}
+
+ASurfaceTexture* ASurfaceTexture_routeFromSurfaceTexture(JNIEnv* env, jobject surfacetexture) {
+    return ASurfaceTexture_fromSurfaceTexture(env, surfacetexture);
+}
 
 unsigned int ASurfaceTexture_getCurrentTextureTarget(ASurfaceTexture* st) {
     return st->consumer->getCurrentTextureTarget();
diff --git a/libs/nativewindow/Android.bp b/libs/nativewindow/Android.bp
index 5baec2f..ee006aa 100644
--- a/libs/nativewindow/Android.bp
+++ b/libs/nativewindow/Android.bp
@@ -25,6 +25,7 @@
     name: "libnativewindow_headers",
     export_include_dirs: ["include"],
     vendor_available: true,
+    min_sdk_version: "29",
 }
 
 ndk_library {
diff --git a/libs/nativewindow/include/system/window.h b/libs/nativewindow/include/system/window.h
index 869ca9e..b78fc5d 100644
--- a/libs/nativewindow/include/system/window.h
+++ b/libs/nativewindow/include/system/window.h
@@ -254,6 +254,7 @@
     NATIVE_WINDOW_SET_QUEUE_INTERCEPTOR           = 44,    /* private */
     NATIVE_WINDOW_ALLOCATE_BUFFERS                = 45,    /* private */
     NATIVE_WINDOW_GET_LAST_QUEUED_BUFFER          = 46,    /* private */
+    NATIVE_WINDOW_SET_QUERY_INTERCEPTOR           = 47,    /* private */
     // clang-format on
 };
 
@@ -1062,4 +1063,38 @@
     return value;
 }
 
+/**
+ * Prototype of the function that an ANativeWindow implementation would call
+ * when ANativeWindow_query is called.
+ */
+typedef int (*ANativeWindow_queryFn)(const ANativeWindow* window, int what, int* value);
+
+/**
+ * Prototype of the function that intercepts an invocation of
+ * ANativeWindow_queryFn, along with a data pointer that's passed by the
+ * caller who set the interceptor, as well as arguments that would be
+ * passed to ANativeWindow_queryFn if it were to be called.
+ */
+typedef int (*ANativeWindow_queryInterceptor)(const ANativeWindow* window,
+                                                ANativeWindow_queryFn perform, void* data,
+                                                int what, int* value);
+
+/**
+ * Registers an interceptor for ANativeWindow_query. Instead of calling
+ * the underlying query function, instead the provided interceptor is
+ * called, which may optionally call the underlying query function. An
+ * optional data pointer is also provided to side-channel additional arguments.
+ *
+ * Note that usage of this should only be used for specialized use-cases by
+ * either the system partition or to Mainline modules. This should never be
+ * exposed to NDK or LL-NDK.
+ *
+ * Returns NO_ERROR on success, -errno if registration failed.
+ */
+static inline int ANativeWindow_setQueryInterceptor(ANativeWindow* window,
+                                            ANativeWindow_queryInterceptor interceptor,
+                                            void* data) {
+    return window->perform(window, NATIVE_WINDOW_SET_QUERY_INTERCEPTOR, interceptor, data);
+}
+
 __END_DECLS
diff --git a/libs/ui/Android.bp b/libs/ui/Android.bp
index 458ee67..1ee8c71 100644
--- a/libs/ui/Android.bp
+++ b/libs/ui/Android.bp
@@ -133,6 +133,7 @@
         "libhardware_headers",
         "libui_headers",
     ],
+    min_sdk_version: "29",
 }
 
 cc_library_headers {
@@ -151,6 +152,7 @@
     export_header_lib_headers: [
         "libnativewindow_headers",
     ],
+    min_sdk_version: "29",
 }
 
 // defaults to enable VALIDATE_REGIONS traces
diff --git a/libs/vr/libpdx/Android.bp b/libs/vr/libpdx/Android.bp
index 23a4224..24ba830 100644
--- a/libs/vr/libpdx/Android.bp
+++ b/libs/vr/libpdx/Android.bp
@@ -2,6 +2,7 @@
     name: "libpdx_headers",
     export_include_dirs: ["private"],
     vendor_available: true,
+    min_sdk_version: "29",
 }
 
 cc_library_static {
diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp
index 155021d..1dbcf98 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.cpp
+++ b/services/inputflinger/dispatcher/InputDispatcher.cpp
@@ -2748,7 +2748,10 @@
             // Monitor channels are never explicitly unregistered.
             // We do it automatically when the remote endpoint is closed so don't warn
             // about them.
-            notify = !connection->monitor;
+            const bool stillHaveWindowHandle =
+                    d->getWindowHandleLocked(connection->inputChannel->getConnectionToken()) !=
+                    nullptr;
+            notify = !connection->monitor && stillHaveWindowHandle;
             if (notify) {
                 ALOGW("channel '%s' ~ Consumer closed input channel or an error occurred.  "
                       "events=0x%x",
diff --git a/services/surfaceflinger/BufferLayer.cpp b/services/surfaceflinger/BufferLayer.cpp
index 5b28384..8ecdd95 100644
--- a/services/surfaceflinger/BufferLayer.cpp
+++ b/services/surfaceflinger/BufferLayer.cpp
@@ -843,6 +843,13 @@
     mDrawingState.inputInfo = tmpInputInfo;
 }
 
+void BufferLayer::setTransformHint(ui::Transform::RotationFlags displayTransformHint) const {
+    mTransformHint = getFixedTransformHint();
+    if (mTransformHint == ui::Transform::ROT_INVALID) {
+        mTransformHint = displayTransformHint;
+    }
+}
+
 } // namespace android
 
 #if defined(__gl_h_)
diff --git a/services/surfaceflinger/BufferLayer.h b/services/surfaceflinger/BufferLayer.h
index 56bab1b..cfccc8a 100644
--- a/services/surfaceflinger/BufferLayer.h
+++ b/services/surfaceflinger/BufferLayer.h
@@ -117,6 +117,10 @@
 
     sp<GraphicBuffer> getBuffer() const override;
 
+    ui::Transform::RotationFlags getTransformHint() const override { return mTransformHint; }
+
+    void setTransformHint(ui::Transform::RotationFlags displayTransformHint) const override;
+
     // -----------------------------------------------------------------------
 
     // -----------------------------------------------------------------------
@@ -205,6 +209,10 @@
 
     virtual uint64_t getHeadFrameNumber(nsecs_t expectedPresentTime) const;
 
+    // Transform hint provided to the producer. This must be accessed holding
+    /// the mStateLock.
+    mutable ui::Transform::RotationFlags mTransformHint = ui::Transform::ROT_0;
+
 private:
     // Returns true if this layer requires filtering
     bool needsFiltering(const sp<const DisplayDevice>& displayDevice) const override;
diff --git a/services/surfaceflinger/BufferQueueLayer.cpp b/services/surfaceflinger/BufferQueueLayer.cpp
index f4e630e..5d80768 100644
--- a/services/surfaceflinger/BufferQueueLayer.cpp
+++ b/services/surfaceflinger/BufferQueueLayer.cpp
@@ -58,8 +58,9 @@
     }
 }
 
-void BufferQueueLayer::setTransformHint(uint32_t orientation) const {
-    mConsumer->setTransformHint(orientation);
+void BufferQueueLayer::setTransformHint(ui::Transform::RotationFlags displayTransformHint) const {
+    BufferLayer::setTransformHint(displayTransformHint);
+    mConsumer->setTransformHint(mTransformHint);
 }
 
 std::vector<OccupancyTracker::Segment> BufferQueueLayer::getOccupancyHistory(bool forceFlush) {
@@ -493,10 +494,6 @@
     if (!mFlinger->isLayerTripleBufferingDisabled()) {
         mProducer->setMaxDequeuedBufferCount(2);
     }
-
-    if (const auto display = mFlinger->getDefaultDisplayDeviceLocked()) {
-        updateTransformHint(display);
-    }
 }
 
 status_t BufferQueueLayer::setDefaultBufferProperties(uint32_t w, uint32_t h, PixelFormat format) {
diff --git a/services/surfaceflinger/BufferQueueLayer.h b/services/surfaceflinger/BufferQueueLayer.h
index 16b4b6e..9bcb63a 100644
--- a/services/surfaceflinger/BufferQueueLayer.h
+++ b/services/surfaceflinger/BufferQueueLayer.h
@@ -43,7 +43,7 @@
 
     void onLayerDisplayed(const sp<Fence>& releaseFence) override;
 
-    void setTransformHint(uint32_t orientation) const override;
+    void setTransformHint(ui::Transform::RotationFlags displayTransformHint) const override;
 
     std::vector<OccupancyTracker::Segment> getOccupancyHistory(bool forceFlush) override;
 
diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp
index a121ce0..a1ed6d7 100644
--- a/services/surfaceflinger/BufferStateLayer.cpp
+++ b/services/surfaceflinger/BufferStateLayer.cpp
@@ -51,9 +51,6 @@
       : BufferLayer(args), mHwcSlotGenerator(new HwcSlotGenerator()) {
     mOverrideScalingMode = NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW;
     mCurrentState.dataspace = ui::Dataspace::V0_SRGB;
-    if (const auto display = args.displayDevice) {
-        updateTransformHint(display);
-    }
 }
 
 BufferStateLayer::~BufferStateLayer() {
@@ -108,10 +105,6 @@
     }
 }
 
-void BufferStateLayer::setTransformHint(uint32_t orientation) const {
-    mTransformHint = orientation;
-}
-
 void BufferStateLayer::releasePendingBuffer(nsecs_t dequeueReadyTime) {
     for (const auto& handle : mDrawingState.callbackHandles) {
         handle->transformHint = mTransformHint;
diff --git a/services/surfaceflinger/BufferStateLayer.h b/services/surfaceflinger/BufferStateLayer.h
index 5873a73..00fa7f7 100644
--- a/services/surfaceflinger/BufferStateLayer.h
+++ b/services/surfaceflinger/BufferStateLayer.h
@@ -42,7 +42,6 @@
     const char* getType() const override { return "BufferStateLayer"; }
 
     void onLayerDisplayed(const sp<Fence>& releaseFence) override;
-    void setTransformHint(uint32_t orientation) const override;
     void releasePendingBuffer(nsecs_t dequeueReadyTime) override;
 
     void finalizeFrameEventHistory(const std::shared_ptr<FenceTime>& glDoneFence,
@@ -68,7 +67,6 @@
     }
     Rect getCrop(const Layer::State& s) const;
 
-    uint32_t getTransformHint() const { return mTransformHint; }
     bool setTransform(uint32_t transform) override;
     bool setTransformToDisplayInverse(bool transformToDisplayInverse) override;
     bool setCrop(const Rect& crop) override;
@@ -164,8 +162,6 @@
     bool mReleasePreviousBuffer = false;
     nsecs_t mCallbackHandleAcquireTime = -1;
 
-    mutable uint32_t mTransformHint = 0;
-
     // TODO(marissaw): support sticky transform for LEGACY camera mode
 
     class HwcSlotGenerator : public ClientCache::ErasedRecipient {
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 752407a..25929ed1 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -117,6 +117,7 @@
     mCurrentState.metadata = args.metadata;
     mCurrentState.shadowRadius = 0.f;
     mCurrentState.treeHasFrameRateVote = false;
+    mCurrentState.fixedTransformHint = ui::Transform::ROT_INVALID;
 
     // drawing state & current state are identical
     mDrawingState = mCurrentState;
@@ -1333,6 +1334,18 @@
     return true;
 }
 
+bool Layer::setFixedTransformHint(ui::Transform::RotationFlags fixedTransformHint) {
+    if (mCurrentState.fixedTransformHint == fixedTransformHint) {
+        return false;
+    }
+
+    mCurrentState.sequence++;
+    mCurrentState.fixedTransformHint = fixedTransformHint;
+    mCurrentState.modified = true;
+    setTransactionFlags(eTransactionNeeded);
+    return true;
+}
+
 void Layer::updateTreeHasFrameRateVote() {
     const auto traverseTree = [&](const LayerVector::Visitor& visitor) {
         auto parent = getParent();
@@ -1460,19 +1473,19 @@
 }
 
 void Layer::updateTransformHint(const sp<const DisplayDevice>& display) const {
-    uint32_t orientation = 0;
+    ui::Transform::RotationFlags transformHint = ui::Transform::ROT_0;
     // Disable setting transform hint if the debug flag is set.
     if (!mFlinger->mDebugDisableTransformHint) {
         // The transform hint is used to improve performance, but we can
         // only have a single transform hint, it cannot
         // apply to all displays.
         const ui::Transform& planeTransform = display->getTransform();
-        orientation = planeTransform.getOrientation();
-        if (orientation & ui::Transform::ROT_INVALID) {
-            orientation = 0;
+        transformHint = static_cast<ui::Transform::RotationFlags>(planeTransform.getOrientation());
+        if (transformHint & ui::Transform::ROT_INVALID) {
+            transformHint = ui::Transform::ROT_0;
         }
     }
-    setTransformHint(orientation);
+    setTransformHint(transformHint);
 }
 
 // ----------------------------------------------------------------------------
@@ -2076,6 +2089,16 @@
     return parentAlpha * getDrawingState().color.a;
 }
 
+ui::Transform::RotationFlags Layer::getFixedTransformHint() const {
+    ui::Transform::RotationFlags fixedTransformHint = mCurrentState.fixedTransformHint;
+    if (fixedTransformHint != ui::Transform::ROT_INVALID) {
+        return fixedTransformHint;
+    }
+    const auto& p = mCurrentParent.promote();
+    if (!p) return fixedTransformHint;
+    return p->getFixedTransformHint();
+}
+
 half4 Layer::getColor() const {
     const half4 color(getDrawingState().color);
     return half4(color.r, color.g, color.b, getAlpha());
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index b630333..224ea19 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -262,6 +262,15 @@
 
         // Indicates whether parents / children of this layer had set FrameRate
         bool treeHasFrameRateVote;
+
+        // Set by window manager indicating the layer and all its children are
+        // in a different orientation than the display. The hint suggests that
+        // the graphic producers should receive a transform hint as if the
+        // display was in this orientation. When the display changes to match
+        // the layer orientation, the graphic producer may not need to allocate
+        // a buffer of a different size. ui::Transform::ROT_INVALID means the
+        // a fixed transform hint is not set.
+        ui::Transform::RotationFlags fixedTransformHint;
     };
 
     explicit Layer(const LayerCreationArgs& args);
@@ -388,6 +397,7 @@
     virtual bool setColorSpaceAgnostic(const bool agnostic);
     bool setShadowRadius(float shadowRadius);
     virtual bool setFrameRateSelectionPriority(int32_t priority);
+    virtual bool setFixedTransformHint(ui::Transform::RotationFlags fixedTransformHint);
     //  If the variable is not set on the layer, it traverses up the tree to inherit the frame
     //  rate priority from its parent.
     virtual int32_t getFrameRateSelectionPriority() const;
@@ -611,7 +621,7 @@
     bool getClearClientTarget(const sp<const DisplayDevice>& display) const;
 
     virtual bool shouldPresentNow(nsecs_t /*expectedPresentTime*/) const { return false; }
-    virtual void setTransformHint(uint32_t /*orientation*/) const { }
+    virtual void setTransformHint(ui::Transform::RotationFlags /*transformHint*/) const {}
 
     /*
      * called after composition.
@@ -689,6 +699,8 @@
 
     virtual sp<GraphicBuffer> getBuffer() const { return nullptr; }
 
+    virtual ui::Transform::RotationFlags getTransformHint() const { return ui::Transform::ROT_0; }
+
     /*
      * Returns if a frame is ready
      */
@@ -733,6 +745,12 @@
     int32_t getBackgroundBlurRadius() const;
     bool drawShadows() const { return mEffectiveShadowRadius > 0.f; };
 
+    // Returns the transform hint set by Window Manager on the layer or one of its parents.
+    // This traverses the current state because the data is needed when creating
+    // the layer(off drawing thread) and the hint should be available before the producer
+    // is ready to acquire a buffer.
+    ui::Transform::RotationFlags getFixedTransformHint() const;
+
     // Returns how rounded corners should be drawn for this layer.
     // This will traverse the hierarchy until it reaches its root, finding topmost rounded
     // corner definition and converting it into current layer's coordinates.
diff --git a/services/surfaceflinger/RefreshRateOverlay.cpp b/services/surfaceflinger/RefreshRateOverlay.cpp
index 2e7fbc1..f602412 100644
--- a/services/surfaceflinger/RefreshRateOverlay.cpp
+++ b/services/surfaceflinger/RefreshRateOverlay.cpp
@@ -200,26 +200,22 @@
     }
 }
 
-void RefreshRateOverlay::changeRefreshRate(const RefreshRate& refreshRate) {
-    const auto display = mFlinger.getDefaultDisplayDeviceLocked();
-    if (!display) {
-        return;
-    }
-
-    const int32_t left = display->getWidth() / 32;
-    const int32_t top = display->getHeight() / 32;
-    const int32_t right = left + display->getWidth() / 8;
-    const int32_t buttom = top + display->getHeight() / 32;
-
-    auto buffer = mBufferCache[refreshRate.getFps()];
-    mLayer->setBuffer(buffer, Fence::NO_FENCE, 0, 0, {});
-
-    mLayer->setFrame(Rect(left, top, right, buttom));
+void RefreshRateOverlay::setViewport(ui::Size viewport) {
+    Rect frame(viewport.width >> 3, viewport.height >> 5);
+    frame.offsetBy(viewport.width >> 5, viewport.height >> 4);
+    mLayer->setFrame(frame);
 
     mFlinger.mTransactionFlags.fetch_or(eTransactionMask);
 }
 
-}; // namespace android
+void RefreshRateOverlay::changeRefreshRate(const RefreshRate& refreshRate) {
+    auto buffer = mBufferCache[refreshRate.getFps()];
+    mLayer->setBuffer(buffer, Fence::NO_FENCE, 0, 0, {});
+
+    mFlinger.mTransactionFlags.fetch_or(eTransactionMask);
+}
+
+} // namespace android
 
 // TODO(b/129481165): remove the #pragma below and fix conversion issues
 #pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/RefreshRateOverlay.h b/services/surfaceflinger/RefreshRateOverlay.h
index 6d34df2..35c8020 100644
--- a/services/surfaceflinger/RefreshRateOverlay.h
+++ b/services/surfaceflinger/RefreshRateOverlay.h
@@ -13,19 +13,35 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
 #pragma once
 
-#include "SurfaceFlinger.h"
+#include <unordered_map>
+
+#include <math/vec4.h>
+#include <ui/Rect.h>
+#include <ui/Size.h>
+#include <utils/StrongPointer.h>
+
+#include "Scheduler/RefreshRateConfigs.h"
 
 namespace android {
 
+class Client;
+class GraphicBuffer;
+class IBinder;
+class IGraphicBufferProducer;
+class Layer;
+class SurfaceFlinger;
+
 using RefreshRate = scheduler::RefreshRateConfigs::RefreshRate;
 
 class RefreshRateOverlay {
 public:
-    RefreshRateOverlay(SurfaceFlinger& flinger);
+    explicit RefreshRateOverlay(SurfaceFlinger&);
 
-    void changeRefreshRate(const RefreshRate& refreshRate);
+    void setViewport(ui::Size);
+    void changeRefreshRate(const RefreshRate&);
 
 private:
     class SevenSegmentDrawer {
@@ -56,7 +72,7 @@
     void primeCache();
 
     SurfaceFlinger& mFlinger;
-    sp<Client> mClient;
+    const sp<Client> mClient;
     sp<Layer> mLayer;
     sp<IBinder> mIBinder;
     sp<IGraphicBufferProducer> mGbp;
@@ -68,4 +84,4 @@
     const half3 HIGH_FPS_COLOR = half3(0.0f, 1.0f, 0.0f);
 };
 
-}; // namespace android
+} // namespace android
diff --git a/services/surfaceflinger/Scheduler/EventThread.cpp b/services/surfaceflinger/Scheduler/EventThread.cpp
index 5dedb6a..cee36a1 100644
--- a/services/surfaceflinger/Scheduler/EventThread.cpp
+++ b/services/surfaceflinger/Scheduler/EventThread.cpp
@@ -152,16 +152,9 @@
     mEventThread->requestNextVsync(this);
 }
 
-void EventThreadConnection::toggleConfigEvents(ISurfaceComposer::ConfigChanged configChangeFlag) {
-    ATRACE_NAME("enableConfigEvents");
-    mConfigChanged = configChangeFlag;
-
-    // In principle it's possible for rapidly toggling config events to drop an
-    // event here, but it's unlikely in practice.
-    if (configChangeFlag == ISurfaceComposer::eConfigChangedDispatch) {
-        mForcedConfigChangeDispatch = true;
-        mEventThread->requestLatestConfig();
-    }
+void EventThreadConnection::requestLatestConfig() {
+    ATRACE_NAME("requestLatestConfig");
+    mEventThread->requestLatestConfig(this);
 }
 
 status_t EventThreadConnection::postEvent(const DisplayEventReceiver::Event& event) {
@@ -276,8 +269,12 @@
     }
 }
 
-void EventThread::requestLatestConfig() {
+void EventThread::requestLatestConfig(const sp<EventThreadConnection>& connection) {
     std::lock_guard<std::mutex> lock(mMutex);
+    if (connection->mForcedConfigChangeDispatch) {
+        return;
+    }
+    connection->mForcedConfigChangeDispatch = true;
     auto pendingConfigChange =
             std::find_if(std::begin(mPendingEvents), std::end(mPendingEvents),
                          [&](const DisplayEventReceiver::Event& event) {
@@ -384,6 +381,10 @@
                 vsyncRequested |= connection->vsyncRequest != VSyncRequest::None;
 
                 if (event && shouldConsumeEvent(*event, connection)) {
+                    if (event->header.type == DisplayEventReceiver::DISPLAY_EVENT_CONFIG_CHANGED &&
+                        connection->mForcedConfigChangeDispatch) {
+                        connection->mForcedConfigChangeDispatch = false;
+                    }
                     consumers.push_back(connection);
                 }
 
@@ -459,8 +460,8 @@
             return true;
 
         case DisplayEventReceiver::DISPLAY_EVENT_CONFIG_CHANGED: {
-            const bool forcedDispatch = connection->mForcedConfigChangeDispatch.exchange(false);
-            return forcedDispatch ||
+            const bool oneTimeDispatch = connection->mForcedConfigChangeDispatch;
+            return oneTimeDispatch ||
                     connection->mConfigChanged == ISurfaceComposer::eConfigChangedDispatch;
         }
 
diff --git a/services/surfaceflinger/Scheduler/EventThread.h b/services/surfaceflinger/Scheduler/EventThread.h
index 9e7086e..64acbd7 100644
--- a/services/surfaceflinger/Scheduler/EventThread.h
+++ b/services/surfaceflinger/Scheduler/EventThread.h
@@ -81,19 +81,19 @@
     status_t stealReceiveChannel(gui::BitTube* outChannel) override;
     status_t setVsyncRate(uint32_t rate) override;
     void requestNextVsync() override; // asynchronous
-    void toggleConfigEvents(ISurfaceComposer::ConfigChanged configChangeFlag) override;
+    void requestLatestConfig() override; // asynchronous
 
     // Called in response to requestNextVsync.
     const ResyncCallback resyncCallback;
 
     VSyncRequest vsyncRequest = VSyncRequest::None;
-    std::atomic<ISurfaceComposer::ConfigChanged> mConfigChanged =
+    ISurfaceComposer::ConfigChanged mConfigChanged =
             ISurfaceComposer::ConfigChanged::eConfigChangedSuppress;
     // Store whether we need to force dispatching a config change separately -
     // if mConfigChanged ever changes before the config change is dispatched
     // then we still need to propagate an initial config to the app if we
     // haven't already.
-    std::atomic<bool> mForcedConfigChangeDispatch = false;
+    bool mForcedConfigChangeDispatch = false;
 
 private:
     virtual void onFirstRef();
@@ -129,11 +129,10 @@
     virtual void setVsyncRate(uint32_t rate, const sp<EventThreadConnection>& connection) = 0;
     // Requests the next vsync. If resetIdleTimer is set to true, it resets the idle timer.
     virtual void requestNextVsync(const sp<EventThreadConnection>& connection) = 0;
-
     // Dispatches the most recent configuration
     // Usage of this method assumes that only the primary internal display
     // supports multiple display configurations.
-    virtual void requestLatestConfig() = 0;
+    virtual void requestLatestConfig(const sp<EventThreadConnection>& connection) = 0;
 
     // Retrieves the number of event connections tracked by this EventThread.
     virtual size_t getEventThreadConnectionCount() = 0;
@@ -154,7 +153,7 @@
     status_t registerDisplayEventConnection(const sp<EventThreadConnection>& connection) override;
     void setVsyncRate(uint32_t rate, const sp<EventThreadConnection>& connection) override;
     void requestNextVsync(const sp<EventThreadConnection>& connection) override;
-    void requestLatestConfig() override;
+    void requestLatestConfig(const sp<EventThreadConnection>& connection) override;
 
     // called before the screen is turned off from main thread
     void onScreenReleased() override;
diff --git a/services/surfaceflinger/Scheduler/LayerInfoV2.cpp b/services/surfaceflinger/Scheduler/LayerInfoV2.cpp
index bf1fb88..b7d0bdd 100644
--- a/services/surfaceflinger/Scheduler/LayerInfoV2.cpp
+++ b/services/surfaceflinger/Scheduler/LayerInfoV2.cpp
@@ -111,23 +111,46 @@
 
     // Calculate the refresh rate by finding the average delta between frames
     nsecs_t totalPresentTimeDeltas = 0;
+    nsecs_t totalQueueTimeDeltas = 0;
+    auto missingPresentTime = false;
     for (auto it = mFrameTimes.begin(); it != mFrameTimes.end() - 1; ++it) {
-        // If there are no presentation timestamp provided we can't calculate the refresh rate
+        totalQueueTimeDeltas +=
+                std::max(((it + 1)->queueTime - it->queueTime), mHighRefreshRatePeriod);
+
         if (it->presetTime == 0 || (it + 1)->presetTime == 0) {
-            return std::nullopt;
+            missingPresentTime = true;
+            continue;
         }
 
         totalPresentTimeDeltas +=
                 std::max(((it + 1)->presetTime - it->presetTime), mHighRefreshRatePeriod);
     }
+
+    // If there are no presentation timestamps provided we can't calculate the refresh rate
+    if (missingPresentTime && mLastReportedRefreshRate == 0) {
+        return std::nullopt;
+    }
+
+    // Calculate the average frame time based on presentation timestamps. If those
+    // doesn't exist, we look at the time the buffer was queued only. We can do that only if
+    // we calculated a refresh rate based on presentation timestamps in the past. The reason
+    // we look at the queue time is to handle cases where hwui attaches presentation timestamps
+    // when implementing render ahead for specific refresh rates. When hwui no longer provides
+    // presentation timestamps we look at the queue time to see if the current refresh rate still
+    // matches the content.
     const float averageFrameTime =
-            static_cast<float>(totalPresentTimeDeltas) / (mFrameTimes.size() - 1);
+            static_cast<float>(missingPresentTime ? totalQueueTimeDeltas : totalPresentTimeDeltas) /
+            (mFrameTimes.size() - 1);
 
     // Now once we calculated the refresh rate we need to make sure that all the frames we captured
     // are evenly distributed and we don't calculate the average across some burst of frames.
     for (auto it = mFrameTimes.begin(); it != mFrameTimes.end() - 1; ++it) {
-        const nsecs_t presentTimeDeltas =
-                std::max(((it + 1)->presetTime - it->presetTime), mHighRefreshRatePeriod);
+        const auto presentTimeDeltas = [&] {
+            const auto delta = missingPresentTime ? (it + 1)->queueTime - it->queueTime
+                                                  : (it + 1)->presetTime - it->presetTime;
+            return std::max(delta, mHighRefreshRatePeriod);
+        }();
+
         if (std::abs(presentTimeDeltas - averageFrameTime) > 2 * averageFrameTime) {
             return std::nullopt;
         }
diff --git a/services/surfaceflinger/Scheduler/LayerInfoV2.h b/services/surfaceflinger/Scheduler/LayerInfoV2.h
index ad91f18..e36b7f7 100644
--- a/services/surfaceflinger/Scheduler/LayerInfoV2.h
+++ b/services/surfaceflinger/Scheduler/LayerInfoV2.h
@@ -88,6 +88,7 @@
         // buffer as Max as we don't know anything about this layer or Min as this layer is
         // posting infrequent updates.
         mFrameTimeValidSince = std::chrono::steady_clock::now();
+        mLastReportedRefreshRate = 0.0f;
     }
 
 private:
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 87e73a0..3b66fa9 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -189,7 +189,7 @@
 using ConditionalLock = ConditionalLockGuard<Mutex>;
 
 // TODO(b/141333600): Consolidate with HWC2::Display::Config::Builder::getDefaultDensity.
-constexpr float FALLBACK_DENSITY = ACONFIGURATION_DENSITY_TV / 160.f;
+constexpr float FALLBACK_DENSITY = ACONFIGURATION_DENSITY_TV;
 
 float getDensityFromProperty(const char* property, bool required) {
     char value[PROPERTY_VALUE_MAX];
@@ -198,7 +198,7 @@
         ALOGE("%s must be defined as a build property", property);
         return FALLBACK_DENSITY;
     }
-    return density / 160.f;
+    return density;
 }
 
 // Currently we only support V0_SRGB and DISPLAY_P3 as composition preference.
@@ -582,14 +582,13 @@
     LOG_EVENT_LONG(LOGTAG_SF_STOP_BOOTANIM,
                    ns2ms(systemTime(SYSTEM_TIME_MONOTONIC)));
 
-    static_cast<void>(schedule([this]() NO_THREAD_SAFETY_ANALYSIS {
+    static_cast<void>(schedule([this] {
         readPersistentProperties();
         mPowerAdvisor.onBootFinished();
         mBootStage = BootStage::FINISHED;
 
         if (property_get_bool("sf.debug.show_refresh_rate_overlay", false)) {
-            mRefreshRateOverlay = std::make_unique<RefreshRateOverlay>(*this);
-            mRefreshRateOverlay->changeRefreshRate(mRefreshRateConfigs->getCurrentRefreshRate());
+            enableRefreshRateOverlay(true);
         }
     }));
 }
@@ -830,6 +829,7 @@
                 ? mInternalDisplayDensity
                 : FALLBACK_DENSITY;
     }
+    info->density /= ACONFIGURATION_DENSITY_MEDIUM;
 
     info->secure = display->isSecure();
     info->deviceProductInfo = getDeviceProductInfoLocked(*display);
@@ -934,9 +934,8 @@
     }
 
     if (isPrimary) {
-        std::lock_guard<std::mutex> lock(mActiveConfigLock);
-        if (mDesiredActiveConfigChanged) {
-            return mDesiredActiveConfig.configId.value();
+        if (const auto config = getDesiredActiveConfig()) {
+            return config->configId.value();
         }
     }
 
@@ -1063,14 +1062,7 @@
     ATRACE_CALL();
     ALOGV("performSetActiveConfig");
     // Store the local variable to release the lock.
-    const auto desiredActiveConfig = [&]() -> std::optional<ActiveConfigInfo> {
-        std::lock_guard<std::mutex> lock(mActiveConfigLock);
-        if (mDesiredActiveConfigChanged) {
-            return mDesiredActiveConfig;
-        }
-        return std::nullopt;
-    }();
-
+    const auto desiredActiveConfig = getDesiredActiveConfig();
     if (!desiredActiveConfig) {
         // No desired active config pending to be applied
         return;
@@ -1605,7 +1597,7 @@
 }
 
 void SurfaceFlinger::onHotplugReceived(int32_t sequenceId, hal::HWDisplayId hwcDisplayId,
-                                       hal::Connection connection) {
+                                       hal::Connection connection) NO_THREAD_SAFETY_ANALYSIS {
     ALOGV("%s(%d, %" PRIu64 ", %s)", __FUNCTION__, sequenceId, hwcDisplayId,
           connection == hal::Connection::CONNECTED ? "connected" : "disconnected");
 
@@ -1927,8 +1919,11 @@
                 ATRACE_NAME("Jank detected");
                 ALOGD("Detected janky event. Missed frames: %d", mMissedFrameJankCount);
                 const int32_t jankyDurationMillis = jankDuration / (1000 * 1000);
-                android::util::stats_write(android::util::DISPLAY_JANK_REPORTED,
-                                           jankyDurationMillis, mMissedFrameJankCount);
+                {
+                    ATRACE_NAME("Pushing to statsd");
+                    android::util::stats_write(android::util::DISPLAY_JANK_REPORTED,
+                                               jankyDurationMillis, mMissedFrameJankCount);
+                }
             }
 
             // We either reported a jank event or we missed the trace
@@ -2679,9 +2674,14 @@
         if (currentState.width != drawingState.width ||
             currentState.height != drawingState.height) {
             display->setDisplaySize(currentState.width, currentState.height);
+
             if (display->isPrimary()) {
                 mScheduler->onPrimaryDisplayAreaChanged(currentState.width * currentState.height);
             }
+
+            if (mRefreshRateOverlay) {
+                mRefreshRateOverlay->setViewport(display->getSize());
+            }
         }
     }
 }
@@ -2765,7 +2765,7 @@
         processDisplayHotplugEventsLocked();
     }
 
-    if (transactionFlags & (eDisplayLayerStackChanged|eDisplayTransactionNeeded)) {
+    if (transactionFlags & (eTransformHintUpdateNeeded | eDisplayTransactionNeeded)) {
         // The transform hint might have changed for some layers
         // (either because a display has changed, or because a layer
         // as changed).
@@ -2833,7 +2833,6 @@
         });
     }
 
-
     /*
      * Perform our own transaction if needed
      */
@@ -3138,7 +3137,8 @@
 status_t SurfaceFlinger::addClientLayer(const sp<Client>& client, const sp<IBinder>& handle,
                                         const sp<IGraphicBufferProducer>& gbc, const sp<Layer>& lbc,
                                         const sp<IBinder>& parentHandle,
-                                        const sp<Layer>& parentLayer, bool addToCurrentState) {
+                                        const sp<Layer>& parentLayer, bool addToCurrentState,
+                                        uint32_t* outTransformHint) {
     // add this layer to the current state list
     {
         Mutex::Autolock _l(mStateLock);
@@ -3179,6 +3179,14 @@
                                 mGraphicBufferProducerList.size(),
                                 mMaxGraphicBufferProducerListSize, mNumLayers.load());
         }
+
+        if (const auto display = getDefaultDisplayDeviceLocked()) {
+            lbc->updateTransformHint(display);
+        }
+        if (outTransformHint) {
+            *outTransformHint = lbc->getTransformHint();
+        }
+
         mLayersAdded = true;
     }
 
@@ -3680,7 +3688,7 @@
             mCurrentState.layersSortedByZ.add(layer);
             // we need traversal (state changed)
             // AND transaction (list changed)
-            flags |= eTransactionNeeded|eTraversalNeeded|eDisplayLayerStackChanged;
+            flags |= eTransactionNeeded | eTraversalNeeded | eTransformHintUpdateNeeded;
         }
     }
     if (what & layer_state_t::eDeferTransaction_legacy) {
@@ -3777,6 +3785,11 @@
             flags |= eTraversalNeeded;
         }
     }
+    if (what & layer_state_t::eFixedTransformHintChanged) {
+        if (layer->setFixedTransformHint(s.fixedTransformHint)) {
+            flags |= eTraversalNeeded | eTransformHintUpdateNeeded;
+        }
+    }
     // This has to happen after we reparent children because when we reparent to null we remove
     // child layers from current state and remove its relative z. If the children are reparented in
     // the same transaction, then we have to make sure we reparent the children first so we do not
@@ -3864,7 +3877,8 @@
         mirrorLayer->mClonedChild = mirrorFrom->createClone();
     }
 
-    return addClientLayer(client, *outHandle, nullptr, mirrorLayer, nullptr, nullptr, false);
+    return addClientLayer(client, *outHandle, nullptr, mirrorLayer, nullptr, nullptr, false,
+                          nullptr /* outTransformHint */);
 }
 
 status_t SurfaceFlinger::createLayer(const String8& name, const sp<Client>& client, uint32_t w,
@@ -3909,7 +3923,7 @@
             break;
         case ISurfaceComposerClient::eFXSurfaceBufferState:
             result = createBufferStateLayer(client, std::move(uniqueName), w, h, flags,
-                                            std::move(metadata), handle, outTransformHint, &layer);
+                                            std::move(metadata), handle, &layer);
             break;
         case ISurfaceComposerClient::eFXSurfaceEffect:
             // check if buffer size is set for color layer.
@@ -3947,7 +3961,7 @@
 
     bool addToCurrentState = callingThreadHasUnscopedSurfaceFlingerAccess();
     result = addClientLayer(client, *handle, *gbp, layer, parentHandle, parentLayer,
-                            addToCurrentState);
+                            addToCurrentState, outTransformHint);
     if (result != NO_ERROR) {
         return result;
     }
@@ -4024,14 +4038,11 @@
 status_t SurfaceFlinger::createBufferStateLayer(const sp<Client>& client, std::string name,
                                                 uint32_t w, uint32_t h, uint32_t flags,
                                                 LayerMetadata metadata, sp<IBinder>* handle,
-                                                uint32_t* outTransformHint, sp<Layer>* outLayer) {
+                                                sp<Layer>* outLayer) {
     LayerCreationArgs args(this, client, std::move(name), w, h, flags, std::move(metadata));
     args.displayDevice = getDefaultDisplayDevice();
     args.textureName = getNewTexture();
     sp<BufferStateLayer> layer = getFactory().createBufferStateLayer(args);
-    if (outTransformHint) {
-        *outTransformHint = layer->getTransformHint();
-    }
     *handle = layer->getHandle();
     *outLayer = layer;
 
@@ -5229,15 +5240,15 @@
                 return NO_ERROR;
             }
             case 1034: {
-                n = data.readInt32();
-                if (n == 1 && !mRefreshRateOverlay) {
-                    mRefreshRateOverlay = std::make_unique<RefreshRateOverlay>(*this);
-                    auto& current = mRefreshRateConfigs->getCurrentRefreshRate();
-                    mRefreshRateOverlay->changeRefreshRate(current);
-                } else if (n == 0) {
-                    mRefreshRateOverlay.reset();
-                } else {
-                    reply->writeBool(mRefreshRateOverlay != nullptr);
+                switch (n = data.readInt32()) {
+                    case 0:
+                    case 1:
+                        enableRefreshRateOverlay(static_cast<bool>(n));
+                        break;
+                    default: {
+                        Mutex::Autolock lock(mStateLock);
+                        reply->writeBool(mRefreshRateOverlay != nullptr);
+                    }
                 }
                 return NO_ERROR;
             }
@@ -5285,29 +5296,26 @@
 void SurfaceFlinger::kernelTimerChanged(bool expired) {
     static bool updateOverlay =
             property_get_bool("debug.sf.kernel_idle_timer_update_overlay", true);
-    if (!updateOverlay || !mRefreshRateOverlay) return;
+    if (!updateOverlay) return;
+    if (Mutex::Autolock lock(mStateLock); !mRefreshRateOverlay) return;
 
     // Update the overlay on the main thread to avoid race conditions with
     // mRefreshRateConfigs->getCurrentRefreshRate()
-    static_cast<void>(schedule([=]() NO_THREAD_SAFETY_ANALYSIS {
-        if (mRefreshRateOverlay) {
+    static_cast<void>(schedule([=] {
+        const auto desiredActiveConfig = getDesiredActiveConfig();
+        const auto& current = desiredActiveConfig
+                ? mRefreshRateConfigs->getRefreshRateFromConfigId(desiredActiveConfig->configId)
+                : mRefreshRateConfigs->getCurrentRefreshRate();
+        const auto& min = mRefreshRateConfigs->getMinRefreshRate();
+
+        if (current != min) {
             const auto kernelTimerEnabled = property_get_bool(KERNEL_IDLE_TIMER_PROP, false);
             const bool timerExpired = kernelTimerEnabled && expired;
-            const auto& current = [this]() -> const RefreshRate& {
-                std::lock_guard<std::mutex> lock(mActiveConfigLock);
-                if (mDesiredActiveConfigChanged) {
-                    return mRefreshRateConfigs->getRefreshRateFromConfigId(
-                            mDesiredActiveConfig.configId);
-                }
 
-                return mRefreshRateConfigs->getCurrentRefreshRate();
-            }();
-            const auto& min = mRefreshRateConfigs->getMinRefreshRate();
-
-            if (current != min) {
+            if (Mutex::Autolock lock(mStateLock); mRefreshRateOverlay) {
                 mRefreshRateOverlay->changeRefreshRate(timerExpired ? min : current);
-                mEventQueue->invalidate();
             }
+            mEventQueue->invalidate();
         }
     }));
 }
@@ -6224,6 +6232,29 @@
     }));
 }
 
+void SurfaceFlinger::enableRefreshRateOverlay(bool enable) {
+    static_cast<void>(schedule([=] {
+        std::unique_ptr<RefreshRateOverlay> overlay;
+        if (enable) {
+            overlay = std::make_unique<RefreshRateOverlay>(*this);
+        }
+
+        {
+            Mutex::Autolock lock(mStateLock);
+
+            // Destroy the layer of the current overlay, if any, outside the lock.
+            mRefreshRateOverlay.swap(overlay);
+            if (!mRefreshRateOverlay) return;
+
+            if (const auto display = getDefaultDisplayDeviceLocked()) {
+                mRefreshRateOverlay->setViewport(display->getSize());
+            }
+
+            mRefreshRateOverlay->changeRefreshRate(mRefreshRateConfigs->getCurrentRefreshRate());
+        }
+    }));
+}
+
 } // namespace android
 
 #if defined(__gl_h_)
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index f3984ed..509de0f 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -117,7 +117,7 @@
     eTransactionNeeded = 0x01,
     eTraversalNeeded = 0x02,
     eDisplayTransactionNeeded = 0x04,
-    eDisplayLayerStackChanged = 0x08,
+    eTransformHintUpdateNeeded = 0x08,
     eTransactionFlushNeeded = 0x10,
     eTransactionMask = 0x1f,
 };
@@ -675,8 +675,7 @@
 
     status_t createBufferStateLayer(const sp<Client>& client, std::string name, uint32_t w,
                                     uint32_t h, uint32_t flags, LayerMetadata metadata,
-                                    sp<IBinder>* outHandle, uint32_t* outTransformHint,
-                                    sp<Layer>* outLayer);
+                                    sp<IBinder>* outHandle, sp<Layer>* outLayer);
 
     status_t createEffectLayer(const sp<Client>& client, std::string name, uint32_t w, uint32_t h,
                                uint32_t flags, LayerMetadata metadata, sp<IBinder>* outHandle,
@@ -701,7 +700,7 @@
     status_t addClientLayer(const sp<Client>& client, const sp<IBinder>& handle,
                             const sp<IGraphicBufferProducer>& gbc, const sp<Layer>& lbc,
                             const sp<IBinder>& parentHandle, const sp<Layer>& parentLayer,
-                            bool addToCurrentState);
+                            bool addToCurrentState, uint32_t* outTransformHint);
 
     // Traverse through all the layers and compute and cache its bounds.
     void computeLayerBounds();
@@ -829,13 +828,13 @@
             const DisplayDeviceState& state,
             const sp<compositionengine::DisplaySurface>& displaySurface,
             const sp<IGraphicBufferProducer>& producer);
-    void processDisplayChangesLocked();
+    void processDisplayChangesLocked() REQUIRES(mStateLock);
     void processDisplayAdded(const wp<IBinder>& displayToken, const DisplayDeviceState& state);
     void processDisplayRemoved(const wp<IBinder>& displayToken);
     void processDisplayChanged(const wp<IBinder>& displayToken,
                                const DisplayDeviceState& currentState,
-                               const DisplayDeviceState& drawingState);
-    void processDisplayHotplugEventsLocked();
+                               const DisplayDeviceState& drawingState) REQUIRES(mStateLock);
+    void processDisplayHotplugEventsLocked() REQUIRES(mStateLock);
 
     void dispatchDisplayHotplugEvent(PhysicalDisplayId displayId, bool connected);
 
@@ -1216,6 +1215,12 @@
      * Misc
      */
 
+    std::optional<ActiveConfigInfo> getDesiredActiveConfig() EXCLUDES(mActiveConfigLock) {
+        std::lock_guard<std::mutex> lock(mActiveConfigLock);
+        if (mDesiredActiveConfigChanged) return mDesiredActiveConfig;
+        return std::nullopt;
+    }
+
     std::mutex mActiveConfigLock;
     // This bit is set once we start setting the config. We read from this bit during the
     // process. If at the end, this bit is different than mDesiredActiveConfig, we restart
@@ -1258,7 +1263,8 @@
     // This should only be accessed on the main thread.
     nsecs_t mFrameStartTime = 0;
 
-    std::unique_ptr<RefreshRateOverlay> mRefreshRateOverlay;
+    void enableRefreshRateOverlay(bool enable);
+    std::unique_ptr<RefreshRateOverlay> mRefreshRateOverlay GUARDED_BY(mStateLock);
 
     // Flag used to set override allowed display configs from backdoor
     bool mDebugDisplayConfigSetByBackdoor = false;
diff --git a/services/surfaceflinger/tests/unittests/mock/MockEventThread.h b/services/surfaceflinger/tests/unittests/mock/MockEventThread.h
index 50eb390..054aaf8 100644
--- a/services/surfaceflinger/tests/unittests/mock/MockEventThread.h
+++ b/services/surfaceflinger/tests/unittests/mock/MockEventThread.h
@@ -40,7 +40,7 @@
                  status_t(const sp<android::EventThreadConnection> &));
     MOCK_METHOD2(setVsyncRate, void(uint32_t, const sp<android::EventThreadConnection> &));
     MOCK_METHOD1(requestNextVsync, void(const sp<android::EventThreadConnection> &));
-    MOCK_METHOD0(requestLatestConfig, void());
+    MOCK_METHOD1(requestLatestConfig, void(const sp<android::EventThreadConnection> &));
     MOCK_METHOD1(pauseVsyncCallback, void(bool));
     MOCK_METHOD0(getEventThreadConnectionCount, size_t());
 };
diff --git a/vulkan/libvulkan/driver.cpp b/vulkan/libvulkan/driver.cpp
index a5f0c9f..7bcb2c1 100644
--- a/vulkan/libvulkan/driver.cpp
+++ b/vulkan/libvulkan/driver.cpp
@@ -252,18 +252,6 @@
     result = LoadUpdatedDriver(&module);
     if (result == -ENOENT) {
         result = LoadBuiltinDriver(&module);
-        if (result != 0) {
-            // -ENOENT means the sphal namespace doesn't exist, not that there
-            // is a problem with the driver.
-            ALOGW_IF(
-                result != -ENOENT,
-                "Failed to load Vulkan driver into sphal namespace. This "
-                "usually means the driver has forbidden library dependencies."
-                "Please fix, this will soon stop working.");
-            result =
-                hw_get_module(HWVULKAN_HARDWARE_MODULE_ID,
-                              reinterpret_cast<const hw_module_t**>(&module));
-        }
     }
     if (result != 0) {
         android::GraphicsEnv::getInstance().setDriverLoaded(