Merge "DispSync: mLastCallbackTime is set incorrectly"
diff --git a/data/etc/android.hardware.nfc.ese.xml b/data/etc/android.hardware.nfc.ese.xml
new file mode 100644
index 0000000..6642bb2
--- /dev/null
+++ b/data/etc/android.hardware.nfc.ese.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2019 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<!-- This feature indicates that the device supports eSE-based NFC card
+     emulation -->
+<permissions>
+    <feature name="android.hardware.nfc.ese" />
+</permissions>
diff --git a/data/etc/android.hardware.nfc.uicc.xml b/data/etc/android.hardware.nfc.uicc.xml
new file mode 100644
index 0000000..4f12de4
--- /dev/null
+++ b/data/etc/android.hardware.nfc.uicc.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2019 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<!-- This feature indicates that the device supports uicc-based NFC card
+     emulation -->
+<permissions>
+    <feature name="android.hardware.nfc.uicc" />
+</permissions>
diff --git a/libs/android_runtime_lazy/Android.bp b/libs/android_runtime_lazy/Android.bp
index b200314..9284acb 100644
--- a/libs/android_runtime_lazy/Android.bp
+++ b/libs/android_runtime_lazy/Android.bp
@@ -33,6 +33,7 @@
 cc_library {
     name: "libandroid_runtime_lazy",
     vendor_available: true,
+    double_loadable: true,
 
     cflags: [
         "-Wall",
diff --git a/libs/binder/aidl/android/content/pm/IPackageManagerNative.aidl b/libs/binder/aidl/android/content/pm/IPackageManagerNative.aidl
index ccde12a..b1c577e 100644
--- a/libs/binder/aidl/android/content/pm/IPackageManagerNative.aidl
+++ b/libs/binder/aidl/android/content/pm/IPackageManagerNative.aidl
@@ -59,4 +59,22 @@
      * Unknown packages are mapped to false.
      */
     boolean[] isAudioPlaybackCaptureAllowed(in @utf8InCpp String[] packageNames);
+
+    /*  ApplicationInfo.isSystemApp() == true */
+    const int LOCATION_SYSTEM = 0x1;
+    /*  ApplicationInfo.isVendor() == true */
+    const int LOCATION_VENDOR = 0x2;
+    /*  ApplicationInfo.isProduct() == true */
+    const int LOCATION_PRODUCT = 0x4;
+    /*  ApplicationInfo.isProductServices() == true */
+    const int LOCATION_PRODUCT_SERVICES = 0x8;
+
+    /**
+     * Returns a set of bitflags about package location.
+     * LOCATION_SYSTEM: getApplicationInfo(packageName).isSystemApp()
+     * LOCATION_VENDOR: getApplicationInfo(packageName).isVendor()
+     * LOCATION_PRODUCT: getApplicationInfo(packageName).isProduct()
+     * LOCATION_PRODUCT_SERVICES: getApplicationInfo(packageName).isProductService()
+     */
+    int getLocationFlags(in @utf8InCpp String packageName);
 }
diff --git a/libs/graphicsenv/Android.bp b/libs/graphicsenv/Android.bp
index 0571dcc..56521bf 100644
--- a/libs/graphicsenv/Android.bp
+++ b/libs/graphicsenv/Android.bp
@@ -27,6 +27,7 @@
         "libbase",
         "libbinder",
         "libcutils",
+        "libdl_android",
         "liblog",
         "libutils",
     ],
diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp
index bc63d31..b74d675 100644
--- a/libs/gui/ISurfaceComposer.cpp
+++ b/libs/gui/ISurfaceComposer.cpp
@@ -69,7 +69,8 @@
                                      const sp<IBinder>& applyToken,
                                      const InputWindowCommands& commands,
                                      int64_t desiredPresentTime,
-                                     const cached_buffer_t& uncacheBuffer) {
+                                     const cached_buffer_t& uncacheBuffer,
+                                     const std::vector<ListenerCallbacks>& listenerCallbacks) {
         Parcel data, reply;
         data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
 
@@ -89,6 +90,14 @@
         data.writeInt64(desiredPresentTime);
         data.writeStrongBinder(uncacheBuffer.token);
         data.writeUint64(uncacheBuffer.cacheId);
+
+        if (data.writeVectorSize(listenerCallbacks) == NO_ERROR) {
+            for (const auto& [listener, callbackIds] : listenerCallbacks) {
+                data.writeStrongBinder(IInterface::asBinder(listener));
+                data.writeInt64Vector(callbackIds);
+            }
+        }
+
         remote()->transact(BnSurfaceComposer::SET_TRANSACTION_STATE, data, &reply);
     }
 
@@ -978,8 +987,18 @@
             uncachedBuffer.token = data.readStrongBinder();
             uncachedBuffer.cacheId = data.readUint64();
 
+            std::vector<ListenerCallbacks> listenerCallbacks;
+            int32_t listenersSize = data.readInt32();
+            for (int32_t i = 0; i < listenersSize; i++) {
+                auto listener =
+                        interface_cast<ITransactionCompletedListener>(data.readStrongBinder());
+                std::vector<CallbackId> callbackIds;
+                data.readInt64Vector(&callbackIds);
+                listenerCallbacks.emplace_back(listener, callbackIds);
+            }
+
             setTransactionState(state, displays, stateFlags, applyToken, inputWindowCommands,
-                                desiredPresentTime, uncachedBuffer);
+                                desiredPresentTime, uncachedBuffer, listenerCallbacks);
             return NO_ERROR;
         }
         case BOOT_FINISHED: {
diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp
index f6ca9e8..3077b21 100644
--- a/libs/gui/LayerState.cpp
+++ b/libs/gui/LayerState.cpp
@@ -86,14 +86,7 @@
     memcpy(output.writeInplace(16 * sizeof(float)),
            colorTransform.asArray(), 16 * sizeof(float));
     output.writeFloat(cornerRadius);
-
-    if (output.writeVectorSize(listenerCallbacks) == NO_ERROR) {
-        for (const auto& [listener, callbackIds] : listenerCallbacks) {
-            output.writeStrongBinder(IInterface::asBinder(listener));
-            output.writeInt64Vector(callbackIds);
-        }
-    }
-
+    output.writeBool(hasListenerCallbacks);
     output.writeStrongBinder(cachedBuffer.token);
     output.writeUint64(cachedBuffer.cacheId);
     output.writeParcelable(metadata);
@@ -163,15 +156,7 @@
 
     colorTransform = mat4(static_cast<const float*>(input.readInplace(16 * sizeof(float))));
     cornerRadius = input.readFloat();
-
-    int32_t listenersSize = input.readInt32();
-    for (int32_t i = 0; i < listenersSize; i++) {
-        auto listener = interface_cast<ITransactionCompletedListener>(input.readStrongBinder());
-        std::vector<CallbackId> callbackIds;
-        input.readInt64Vector(&callbackIds);
-        listenerCallbacks.emplace_back(listener, callbackIds);
-    }
-
+    hasListenerCallbacks = input.readBool();
     cachedBuffer.token = input.readStrongBinder();
     cachedBuffer.cacheId = input.readUint64();
     input.readParcelable(&metadata);
@@ -376,9 +361,9 @@
         what |= eColorTransformChanged;
         colorTransform = other.colorTransform;
     }
-    if (other.what & eListenerCallbacksChanged) {
-        what |= eListenerCallbacksChanged;
-        listenerCallbacks = other.listenerCallbacks;
+    if (other.what & eHasListenerCallbacksChanged) {
+        what |= eHasListenerCallbacksChanged;
+        hasListenerCallbacks = other.hasListenerCallbacks;
     }
 
 #ifndef NO_INPUT
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index 39cd62f..c627898 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -381,7 +381,7 @@
     s.state.parentHandleForChild = nullptr;
 
     composerStates.add(s);
-    sf->setTransactionState(composerStates, displayStates, 0, nullptr, {}, -1, {});
+    sf->setTransactionState(composerStates, displayStates, 0, nullptr, {}, -1, {}, {});
 }
 
 void SurfaceComposerClient::doUncacheBufferTransaction(uint64_t cacheId) {
@@ -391,7 +391,7 @@
     uncacheBuffer.token = BufferCache::getInstance().getToken();
     uncacheBuffer.cacheId = cacheId;
 
-    sf->setTransactionState({}, {}, 0, nullptr, {}, -1, uncacheBuffer);
+    sf->setTransactionState({}, {}, 0, nullptr, {}, -1, uncacheBuffer, {});
 }
 
 void SurfaceComposerClient::Transaction::cacheBuffers() {
@@ -406,10 +406,16 @@
             continue;
         }
 
+        // Don't try to cache a null buffer. Sending null buffers is cheap so we shouldn't waste
+        // time trying to cache them.
+        if (!s->buffer) {
+            continue;
+        }
+
         uint64_t cacheId = 0;
         status_t ret = BufferCache::getInstance().getCacheId(s->buffer, &cacheId);
         if (ret == NO_ERROR) {
-            s->what &= ~static_cast<uint32_t>(layer_state_t::eBufferChanged);
+            s->what &= ~static_cast<uint64_t>(layer_state_t::eBufferChanged);
             s->buffer = nullptr;
         } else {
             cacheId = BufferCache::getInstance().cache(s->buffer);
@@ -434,6 +440,8 @@
 
     sp<ISurfaceComposer> sf(ComposerService::getComposerService());
 
+    std::vector<ListenerCallbacks> listenerCallbacks;
+
     // For every listener with registered callbacks
     for (const auto& [listener, callbackInfo] : mListenerCallbacks) {
         auto& [callbackIds, surfaceControls] = callbackInfo;
@@ -441,11 +449,7 @@
             continue;
         }
 
-        // If the listener does not have any SurfaceControls set on this Transaction, send the
-        // callback now
-        if (surfaceControls.empty()) {
-            listener->onTransactionCompleted(ListenerStats::createEmpty(listener, callbackIds));
-        }
+        listenerCallbacks.emplace_back(listener, std::move(callbackIds));
 
         // If the listener has any SurfaceControls set on this Transaction update the surface state
         for (const auto& surfaceControl : surfaceControls) {
@@ -454,8 +458,8 @@
                 ALOGE("failed to get layer state");
                 continue;
             }
-            s->what |= layer_state_t::eListenerCallbacksChanged;
-            s->listenerCallbacks.emplace_back(listener, std::move(callbackIds));
+            s->what |= layer_state_t::eHasListenerCallbacksChanged;
+            s->hasListenerCallbacks = true;
         }
     }
     mListenerCallbacks.clear();
@@ -494,7 +498,8 @@
     sp<IBinder> applyToken = IInterface::asBinder(TransactionCompletedListener::getIInstance());
     sf->setTransactionState(composerStates, displayStates, flags, applyToken, mInputWindowCommands,
                             mDesiredPresentTime,
-                            {} /*uncacheBuffer - only set in doUncacheBufferTransaction*/);
+                            {} /*uncacheBuffer - only set in doUncacheBufferTransaction*/,
+                            listenerCallbacks);
     mInputWindowCommands.clear();
     mStatus = NO_ERROR;
     return NO_ERROR;
diff --git a/libs/gui/include/gui/ISurfaceComposer.h b/libs/gui/include/gui/ISurfaceComposer.h
index 0ef5b39..fe85fdf 100644
--- a/libs/gui/include/gui/ISurfaceComposer.h
+++ b/libs/gui/include/gui/ISurfaceComposer.h
@@ -20,13 +20,10 @@
 #include <stdint.h>
 #include <sys/types.h>
 
-#include <utils/RefBase.h>
-#include <utils/Errors.h>
-#include <utils/Timers.h>
-#include <utils/Vector.h>
-
 #include <binder/IInterface.h>
 
+#include <gui/ITransactionCompletedListener.h>
+
 #include <ui/ConfigStoreTypes.h>
 #include <ui/DisplayedFrameStats.h>
 #include <ui/FrameStats.h>
@@ -34,6 +31,11 @@
 #include <ui/GraphicTypes.h>
 #include <ui/PixelFormat.h>
 
+#include <utils/Errors.h>
+#include <utils/RefBase.h>
+#include <utils/Timers.h>
+#include <utils/Vector.h>
+
 #include <optional>
 #include <vector>
 
@@ -133,7 +135,8 @@
                                      const sp<IBinder>& applyToken,
                                      const InputWindowCommands& inputWindowCommands,
                                      int64_t desiredPresentTime,
-                                     const cached_buffer_t& uncacheBuffer) = 0;
+                                     const cached_buffer_t& uncacheBuffer,
+                                     const std::vector<ListenerCallbacks>& listenerCallbacks) = 0;
 
     /* signal that we're done booting.
      * Requires ACCESS_SURFACE_FLINGER permission
diff --git a/libs/gui/include/gui/LayerState.h b/libs/gui/include/gui/LayerState.h
index 77bf8f1..2256497 100644
--- a/libs/gui/include/gui/LayerState.h
+++ b/libs/gui/include/gui/LayerState.h
@@ -23,7 +23,6 @@
 #include <utils/Errors.h>
 
 #include <gui/IGraphicBufferProducer.h>
-#include <gui/ITransactionCompletedListener.h>
 #include <math/mat4.h>
 
 #ifndef NO_INPUT
@@ -86,7 +85,7 @@
         eApiChanged = 0x04000000,
         eSidebandStreamChanged = 0x08000000,
         eColorTransformChanged = 0x10000000,
-        eListenerCallbacksChanged = 0x20000000,
+        eHasListenerCallbacksChanged = 0x20000000,
         eInputInfoChanged = 0x40000000,
         eCornerRadiusChanged = 0x80000000,
         eFrameChanged = 0x1'00000000,
@@ -120,6 +119,7 @@
             surfaceDamageRegion(),
             api(-1),
             colorTransform(mat4()),
+            hasListenerCallbacks(false),
             bgColorAlpha(0),
             bgColorDataspace(ui::Dataspace::UNKNOWN),
             colorSpaceAgnostic(false) {
@@ -182,7 +182,7 @@
     sp<NativeHandle> sidebandStream;
     mat4 colorTransform;
 
-    std::vector<ListenerCallbacks> listenerCallbacks;
+    bool hasListenerCallbacks;
 #ifndef NO_INPUT
     InputWindowInfo inputInfo;
 #endif
diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp
index 94b669d..0ee9bff 100644
--- a/libs/gui/tests/Surface_test.cpp
+++ b/libs/gui/tests/Surface_test.cpp
@@ -561,7 +561,9 @@
                              const sp<IBinder>& /*applyToken*/,
                              const InputWindowCommands& /*inputWindowCommands*/,
                              int64_t /*desiredPresentTime*/,
-                             const cached_buffer_t& /*cachedBuffer*/) override {}
+                             const cached_buffer_t& /*cachedBuffer*/,
+                             const std::vector<ListenerCallbacks>& /*listenerCallbacks*/) override {
+    }
 
     void bootFinished() override {}
     bool authenticateSurfaceTexture(
diff --git a/libs/renderengine/gl/GLESRenderEngine.cpp b/libs/renderengine/gl/GLESRenderEngine.cpp
index 1980f50..5847402 100644
--- a/libs/renderengine/gl/GLESRenderEngine.cpp
+++ b/libs/renderengine/gl/GLESRenderEngine.cpp
@@ -808,12 +808,14 @@
     return success;
 }
 EGLImageKHR GLESRenderEngine::createFramebufferImageIfNeeded(ANativeWindowBuffer* nativeBuffer,
-                                                             bool isProtected) {
+                                                             bool isProtected,
+                                                             bool useFramebufferCache) {
     sp<GraphicBuffer> graphicBuffer = GraphicBuffer::from(nativeBuffer);
-    uint64_t bufferId = graphicBuffer->getId();
-    for (const auto& image : mFramebufferImageCache) {
-        if (image.first == bufferId) {
-            return image.second;
+    if (useFramebufferCache) {
+        for (const auto& image : mFramebufferImageCache) {
+            if (image.first == graphicBuffer->getId()) {
+                return image.second;
+            }
         }
     }
     EGLint attributes[] = {
@@ -823,13 +825,15 @@
     };
     EGLImageKHR image = eglCreateImageKHR(mEGLDisplay, EGL_NO_CONTEXT, EGL_NATIVE_BUFFER_ANDROID,
                                           nativeBuffer, attributes);
-    if (image != EGL_NO_IMAGE_KHR) {
-        if (mFramebufferImageCache.size() >= mFramebufferImageCacheSize) {
-            EGLImageKHR expired = mFramebufferImageCache.front().second;
-            mFramebufferImageCache.pop_front();
-            eglDestroyImageKHR(mEGLDisplay, expired);
+    if (useFramebufferCache) {
+        if (image != EGL_NO_IMAGE_KHR) {
+            if (mFramebufferImageCache.size() >= mFramebufferImageCacheSize) {
+                EGLImageKHR expired = mFramebufferImageCache.front().second;
+                mFramebufferImageCache.pop_front();
+                eglDestroyImageKHR(mEGLDisplay, expired);
+            }
+            mFramebufferImageCache.push_back({graphicBuffer->getId(), image});
         }
-        mFramebufferImageCache.push_back({bufferId, image});
     }
     return image;
 }
@@ -837,7 +841,8 @@
 status_t GLESRenderEngine::drawLayers(const DisplaySettings& display,
                                       const std::vector<LayerSettings>& layers,
                                       ANativeWindowBuffer* const buffer,
-                                      base::unique_fd&& bufferFence, base::unique_fd* drawFence) {
+                                      const bool useFramebufferCache, base::unique_fd&& bufferFence,
+                                      base::unique_fd* drawFence) {
     ATRACE_CALL();
     if (layers.empty()) {
         ALOGV("Drawing empty layer stack");
@@ -857,7 +862,7 @@
     {
         std::lock_guard<std::mutex> lock(mRenderingMutex);
 
-        BindNativeBufferAsFramebuffer fbo(*this, buffer);
+        BindNativeBufferAsFramebuffer fbo(*this, buffer, useFramebufferCache);
 
         if (fbo.getStatus() != NO_ERROR) {
             ALOGE("Failed to bind framebuffer! Aborting GPU composition for buffer (%p).",
diff --git a/libs/renderengine/gl/GLESRenderEngine.h b/libs/renderengine/gl/GLESRenderEngine.h
index 8c8f308..cbde5f4 100644
--- a/libs/renderengine/gl/GLESRenderEngine.h
+++ b/libs/renderengine/gl/GLESRenderEngine.h
@@ -83,14 +83,16 @@
     bool supportsProtectedContent() const override;
     bool useProtectedContext(bool useProtectedContext) override;
     status_t drawLayers(const DisplaySettings& display, const std::vector<LayerSettings>& layers,
-                        ANativeWindowBuffer* buffer, base::unique_fd&& bufferFence,
-                        base::unique_fd* drawFence) EXCLUDES(mRenderingMutex) override;
+                        ANativeWindowBuffer* buffer, const bool useFramebufferCache,
+                        base::unique_fd&& bufferFence, base::unique_fd* drawFence)
+            EXCLUDES(mRenderingMutex) override;
 
     // internal to RenderEngine
     EGLDisplay getEGLDisplay() const { return mEGLDisplay; }
     EGLConfig getEGLConfig() const { return mEGLConfig; }
     // Creates an output image for rendering to
-    EGLImageKHR createFramebufferImageIfNeeded(ANativeWindowBuffer* nativeBuffer, bool isProtected);
+    EGLImageKHR createFramebufferImageIfNeeded(ANativeWindowBuffer* nativeBuffer, bool isProtected,
+                                               bool useFramebufferCache);
 
     // Test-only methods
     // Returns true iff mImageCache contains an image keyed by bufferId
diff --git a/libs/renderengine/gl/GLFramebuffer.cpp b/libs/renderengine/gl/GLFramebuffer.cpp
index c45598c..dacf8d3 100644
--- a/libs/renderengine/gl/GLFramebuffer.cpp
+++ b/libs/renderengine/gl/GLFramebuffer.cpp
@@ -41,19 +41,25 @@
     glDeleteTextures(1, &mTextureName);
 }
 
-bool GLFramebuffer::setNativeWindowBuffer(ANativeWindowBuffer* nativeBuffer, bool isProtected) {
+bool GLFramebuffer::setNativeWindowBuffer(ANativeWindowBuffer* nativeBuffer, bool isProtected,
+                                          const bool useFramebufferCache) {
     ATRACE_CALL();
     if (mEGLImage != EGL_NO_IMAGE_KHR) {
+        if (!usingFramebufferCache) {
+            eglDestroyImageKHR(mEGLDisplay, mEGLImage);
+        }
         mEGLImage = EGL_NO_IMAGE_KHR;
         mBufferWidth = 0;
         mBufferHeight = 0;
     }
 
     if (nativeBuffer) {
-        mEGLImage = mEngine.createFramebufferImageIfNeeded(nativeBuffer, isProtected);
+        mEGLImage = mEngine.createFramebufferImageIfNeeded(nativeBuffer, isProtected,
+                                                           useFramebufferCache);
         if (mEGLImage == EGL_NO_IMAGE_KHR) {
             return false;
         }
+        usingFramebufferCache = useFramebufferCache;
         mBufferWidth = nativeBuffer->width;
         mBufferHeight = nativeBuffer->height;
     }
diff --git a/libs/renderengine/gl/GLFramebuffer.h b/libs/renderengine/gl/GLFramebuffer.h
index 1289fbf..b7650bb 100644
--- a/libs/renderengine/gl/GLFramebuffer.h
+++ b/libs/renderengine/gl/GLFramebuffer.h
@@ -35,7 +35,8 @@
     explicit GLFramebuffer(GLESRenderEngine& engine);
     ~GLFramebuffer() override;
 
-    bool setNativeWindowBuffer(ANativeWindowBuffer* nativeBuffer, bool isProtected) override;
+    bool setNativeWindowBuffer(ANativeWindowBuffer* nativeBuffer, bool isProtected,
+                               const bool useFramebufferCache) override;
     EGLImageKHR getEGLImage() const { return mEGLImage; }
     uint32_t getTextureName() const { return mTextureName; }
     uint32_t getFramebufferName() const { return mFramebufferName; }
@@ -46,6 +47,7 @@
     GLESRenderEngine& mEngine;
     EGLDisplay mEGLDisplay;
     EGLImageKHR mEGLImage;
+    bool usingFramebufferCache = false;
     uint32_t mTextureName, mFramebufferName;
 
     int32_t mBufferHeight = 0;
diff --git a/libs/renderengine/include/renderengine/Framebuffer.h b/libs/renderengine/include/renderengine/Framebuffer.h
index 66eb9ef..6511127 100644
--- a/libs/renderengine/include/renderengine/Framebuffer.h
+++ b/libs/renderengine/include/renderengine/Framebuffer.h
@@ -27,7 +27,8 @@
 public:
     virtual ~Framebuffer() = default;
 
-    virtual bool setNativeWindowBuffer(ANativeWindowBuffer* nativeBuffer, bool isProtected) = 0;
+    virtual bool setNativeWindowBuffer(ANativeWindowBuffer* nativeBuffer, bool isProtected,
+                                       const bool useFramebufferCache) = 0;
 };
 
 } // namespace renderengine
diff --git a/libs/renderengine/include/renderengine/RenderEngine.h b/libs/renderengine/include/renderengine/RenderEngine.h
index b211551..fa57215 100644
--- a/libs/renderengine/include/renderengine/RenderEngine.h
+++ b/libs/renderengine/include/renderengine/RenderEngine.h
@@ -170,6 +170,9 @@
     // @param layers The layers to draw onto the display, in Z-order.
     // @param buffer The buffer which will be drawn to. This buffer will be
     // ready once drawFence fires.
+    // @param useFramebufferCache True if the framebuffer cache should be used.
+    // If an implementation does not cache output framebuffers, then this
+    // parameter does nothing.
     // @param bufferFence Fence signalling that the buffer is ready to be drawn
     // to.
     // @param drawFence A pointer to a fence, which will fire when the buffer
@@ -180,8 +183,8 @@
     // now, this always returns NO_ERROR.
     virtual status_t drawLayers(const DisplaySettings& display,
                                 const std::vector<LayerSettings>& layers,
-                                ANativeWindowBuffer* buffer, base::unique_fd&& bufferFence,
-                                base::unique_fd* drawFence) = 0;
+                                ANativeWindowBuffer* buffer, const bool useFramebufferCache,
+                                base::unique_fd&& bufferFence, base::unique_fd* drawFence) = 0;
 
 protected:
     // Gets a framebuffer to render to. This framebuffer may or may not be
@@ -195,14 +198,16 @@
 
 class BindNativeBufferAsFramebuffer {
 public:
-    BindNativeBufferAsFramebuffer(RenderEngine& engine, ANativeWindowBuffer* buffer)
+    BindNativeBufferAsFramebuffer(RenderEngine& engine, ANativeWindowBuffer* buffer,
+                                  const bool useFramebufferCache)
           : mEngine(engine), mFramebuffer(mEngine.getFramebufferForDrawing()), mStatus(NO_ERROR) {
-        mStatus = mFramebuffer->setNativeWindowBuffer(buffer, mEngine.isProtected())
+        mStatus = mFramebuffer->setNativeWindowBuffer(buffer, mEngine.isProtected(),
+                                                      useFramebufferCache)
                 ? mEngine.bindFrameBuffer(mFramebuffer)
                 : NO_MEMORY;
     }
     ~BindNativeBufferAsFramebuffer() {
-        mFramebuffer->setNativeWindowBuffer(nullptr, false);
+        mFramebuffer->setNativeWindowBuffer(nullptr, false, /*arbitrary*/ true);
         mEngine.unbindFrameBuffer(mFramebuffer);
     }
     status_t getStatus() const { return mStatus; }
diff --git a/libs/renderengine/include/renderengine/mock/Framebuffer.h b/libs/renderengine/include/renderengine/mock/Framebuffer.h
index 7695885..dfb6a4e 100644
--- a/libs/renderengine/include/renderengine/mock/Framebuffer.h
+++ b/libs/renderengine/include/renderengine/mock/Framebuffer.h
@@ -28,7 +28,7 @@
     Framebuffer();
     ~Framebuffer() override;
 
-    MOCK_METHOD2(setNativeWindowBuffer, bool(ANativeWindowBuffer*, bool));
+    MOCK_METHOD3(setNativeWindowBuffer, bool(ANativeWindowBuffer*, bool, const bool));
 };
 
 } // namespace mock
diff --git a/libs/renderengine/include/renderengine/mock/RenderEngine.h b/libs/renderengine/include/renderengine/mock/RenderEngine.h
index 479c7ac..7393f7a 100644
--- a/libs/renderengine/include/renderengine/mock/RenderEngine.h
+++ b/libs/renderengine/include/renderengine/mock/RenderEngine.h
@@ -77,9 +77,9 @@
     MOCK_CONST_METHOD0(isProtected, bool());
     MOCK_CONST_METHOD0(supportsProtectedContent, bool());
     MOCK_METHOD1(useProtectedContext, bool(bool));
-    MOCK_METHOD5(drawLayers,
+    MOCK_METHOD6(drawLayers,
                  status_t(const DisplaySettings&, const std::vector<LayerSettings>&,
-                          ANativeWindowBuffer*, base::unique_fd&&, base::unique_fd*));
+                          ANativeWindowBuffer*, const bool, base::unique_fd&&, base::unique_fd*));
 };
 
 } // namespace mock
diff --git a/libs/renderengine/tests/RenderEngineTest.cpp b/libs/renderengine/tests/RenderEngineTest.cpp
index 8c93cf4..351ca6b 100644
--- a/libs/renderengine/tests/RenderEngineTest.cpp
+++ b/libs/renderengine/tests/RenderEngineTest.cpp
@@ -118,7 +118,7 @@
     void invokeDraw(renderengine::DisplaySettings settings,
                     std::vector<renderengine::LayerSettings> layers, sp<GraphicBuffer> buffer) {
         base::unique_fd fence;
-        status_t status = sRE->drawLayers(settings, layers, buffer->getNativeBuffer(),
+        status_t status = sRE->drawLayers(settings, layers, buffer->getNativeBuffer(), true,
                                           base::unique_fd(), &fence);
         sCurrentBuffer = buffer;
 
@@ -770,7 +770,7 @@
     BufferSourceVariant<ForceOpaqueBufferVariant>::fillColor(layer, 1.0f, 0.0f, 0.0f, this);
     layers.push_back(layer);
     base::unique_fd fence;
-    status_t status = sRE->drawLayers(settings, layers, nullptr, base::unique_fd(), &fence);
+    status_t status = sRE->drawLayers(settings, layers, nullptr, true, base::unique_fd(), &fence);
 
     ASSERT_EQ(BAD_VALUE, status);
 }
@@ -787,13 +787,33 @@
     layer.alpha = 1.0;
     layers.push_back(layer);
 
-    status_t status = sRE->drawLayers(settings, layers, mBuffer->getNativeBuffer(),
+    status_t status = sRE->drawLayers(settings, layers, mBuffer->getNativeBuffer(), true,
                                       base::unique_fd(), nullptr);
     sCurrentBuffer = mBuffer;
     ASSERT_EQ(NO_ERROR, status);
     expectBufferColor(fullscreenRect(), 255, 0, 0, 255);
 }
 
+TEST_F(RenderEngineTest, drawLayers_doesNotCacheFramebuffer) {
+    renderengine::DisplaySettings settings;
+    settings.physicalDisplay = fullscreenRect();
+    settings.clip = fullscreenRect();
+
+    std::vector<renderengine::LayerSettings> layers;
+    renderengine::LayerSettings layer;
+    layer.geometry.boundaries = fullscreenRect().toFloatRect();
+    BufferSourceVariant<ForceOpaqueBufferVariant>::fillColor(layer, 1.0f, 0.0f, 0.0f, this);
+    layer.alpha = 1.0;
+    layers.push_back(layer);
+
+    status_t status = sRE->drawLayers(settings, layers, mBuffer->getNativeBuffer(), false,
+                                      base::unique_fd(), nullptr);
+    sCurrentBuffer = mBuffer;
+    ASSERT_EQ(NO_ERROR, status);
+    ASSERT_FALSE(sRE->isFramebufferImageCachedForTesting(mBuffer->getId()));
+    expectBufferColor(fullscreenRect(), 255, 0, 0, 255);
+}
+
 TEST_F(RenderEngineTest, drawLayers_fillRedBuffer_colorSource) {
     fillRedBuffer<ColorSourceVariant>();
 }
diff --git a/libs/vr/libbufferhub/Android.bp b/libs/vr/libbufferhub/Android.bp
index fa92830..6d202ae 100644
--- a/libs/vr/libbufferhub/Android.bp
+++ b/libs/vr/libbufferhub/Android.bp
@@ -59,9 +59,6 @@
         "libbufferhub_headers",
         "libnativebase_headers",
     ],
-
-    // TODO(b/117568153): Temporarily opt out using libcrt.
-    no_libcrt: true,
 }
 
 cc_test {
@@ -70,7 +67,4 @@
     shared_libs: sharedLibraries,
     header_libs: headerLibraries,
     name: "buffer_hub-test",
-
-    // TODO(b/117568153): Temporarily opt out using libcrt.
-    no_libcrt: true,
 }
diff --git a/libs/vr/libbufferhubqueue/Android.bp b/libs/vr/libbufferhubqueue/Android.bp
index 20894e3..9f72c05 100644
--- a/libs/vr/libbufferhubqueue/Android.bp
+++ b/libs/vr/libbufferhubqueue/Android.bp
@@ -59,9 +59,6 @@
     static_libs: staticLibraries,
     shared_libs: sharedLibraries,
     header_libs: headerLibraries,
-
-    // TODO(b/117568153): Temporarily opt out using libcrt.
-    no_libcrt: true,
 }
 
 subdirs = ["benchmarks", "tests"]
diff --git a/libs/vr/libdvr/tests/Android.bp b/libs/vr/libdvr/tests/Android.bp
index 357dffe..3260447 100644
--- a/libs/vr/libdvr/tests/Android.bp
+++ b/libs/vr/libdvr/tests/Android.bp
@@ -49,9 +49,6 @@
         "-g",
     ],
     name: "dvr_api-test",
-
-    // TODO(b/117568153): Temporarily opt out using libcrt.
-    no_libcrt: true,
 }
 
 cc_test {
diff --git a/libs/vr/libvrflinger/tests/Android.bp b/libs/vr/libvrflinger/tests/Android.bp
index c884cb3..410e234 100644
--- a/libs/vr/libvrflinger/tests/Android.bp
+++ b/libs/vr/libvrflinger/tests/Android.bp
@@ -33,7 +33,4 @@
         "-Werror",
     ],
     name: "vrflinger_test",
-
-    // TODO(b/117568153): Temporarily opt out using libcrt.
-    no_libcrt: true,
 }
diff --git a/services/surfaceflinger/Android.bp b/services/surfaceflinger/Android.bp
index ac1d492..52c68df 100644
--- a/services/surfaceflinger/Android.bp
+++ b/services/surfaceflinger/Android.bp
@@ -47,7 +47,7 @@
         "libhwbinder",
         "liblayers_proto",
         "liblog",
-	"libnativewindow",
+        "libnativewindow",
         "libpdx_default_transport",
         "libprocessgroup",
         "libprotobuf-cpp-lite",
@@ -56,7 +56,7 @@
         "libui",
         "libinput",
         "libutils",
-        "libSurfaceFlingerProperties",
+        "libSurfaceFlingerProp",
     ],
     static_libs: [
         "libcompositionengine",
@@ -138,8 +138,9 @@
         "LayerVector.cpp",
         "MonitoredProducer.cpp",
         "NativeWindowSurface.cpp",
-        "RenderArea.cpp",
+        "RefreshRateOverlay.cpp",
         "RegionSamplingThread.cpp",
+        "RenderArea.cpp",
         "Scheduler/DispSync.cpp",
         "Scheduler/DispSyncSource.cpp",
         "Scheduler/EventControlThread.cpp",
@@ -221,7 +222,7 @@
     srcs: [":surfaceflinger_binary_sources"],
     shared_libs: [
         "libsurfaceflinger",
-        "libSurfaceFlingerProperties",
+        "libSurfaceFlingerProp",
     ],
 }
 
@@ -232,10 +233,9 @@
 ]
 
 cc_library_shared {
-    name: "libSurfaceFlingerProperties",
+    name: "libSurfaceFlingerProp",
     srcs: [
         "SurfaceFlingerProperties.cpp",
-        "sysprop/*.sysprop",
     ],
     shared_libs: [
         "android.hardware.configstore-utils",
@@ -247,6 +247,10 @@
         "libhwbinder",
         "libui",
         "libutils",
+        "liblog",
+    ],
+    static_libs: [
+        "SurfaceFlingerProperties",
     ],
     export_shared_lib_headers: [
         "android.hardware.graphics.common@1.2",
@@ -254,4 +258,7 @@
         "libhidltransport",
         "libhwbinder",
     ],
+    export_static_lib_headers: [
+        "SurfaceFlingerProperties",
+    ],
 }
diff --git a/services/surfaceflinger/RefreshRateOverlay.cpp b/services/surfaceflinger/RefreshRateOverlay.cpp
new file mode 100644
index 0000000..e70bfe4
--- /dev/null
+++ b/services/surfaceflinger/RefreshRateOverlay.cpp
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "RefreshRateOverlay.h"
+#include "Client.h"
+#include "Layer.h"
+
+namespace android {
+
+using RefreshRateType = scheduler::RefreshRateConfigs::RefreshRateType;
+
+RefreshRateOverlay::RefreshRateOverlay(SurfaceFlinger& flinger)
+      : mFlinger(flinger), mClient(new Client(&mFlinger)) {
+    createLayer();
+}
+
+bool RefreshRateOverlay::createLayer() {
+    const status_t ret =
+            mFlinger.createLayer(String8("RefreshRateOverlay"), mClient, 0, 0,
+                                 PIXEL_FORMAT_RGBA_8888, ISurfaceComposerClient::eFXSurfaceColor,
+                                 LayerMetadata(), &mIBinder, &mGbp, &mLayer);
+    if (ret) {
+        ALOGE("failed to color layer");
+        return false;
+    }
+
+    mLayer = mClient->getLayerUser(mIBinder);
+    mLayer->setCrop_legacy(Rect(0, 0, 200, 100), true);
+    mLayer->setLayer(INT32_MAX - 2);
+
+    return true;
+}
+
+void RefreshRateOverlay::changeRefreshRate(RefreshRateType type) {
+    const half3& color = (type == RefreshRateType::PERFORMANCE) ? GREEN : RED;
+    mLayer->setColor(color);
+    mFlinger.setTransactionFlags(eTransactionMask);
+}
+
+}; // namespace android
diff --git a/services/surfaceflinger/RefreshRateOverlay.h b/services/surfaceflinger/RefreshRateOverlay.h
new file mode 100644
index 0000000..ce29bc3
--- /dev/null
+++ b/services/surfaceflinger/RefreshRateOverlay.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#pragma once
+
+#include "SurfaceFlinger.h"
+
+namespace android {
+
+using RefreshRateType = scheduler::RefreshRateConfigs::RefreshRateType;
+
+class RefreshRateOverlay {
+public:
+    RefreshRateOverlay(SurfaceFlinger& flinger);
+
+    void changeRefreshRate(RefreshRateType type);
+
+private:
+    bool createLayer();
+
+    SurfaceFlinger& mFlinger;
+    sp<Client> mClient;
+    sp<Layer> mLayer;
+    sp<IBinder> mIBinder;
+    sp<IGraphicBufferProducer> mGbp;
+
+    const half3 RED = half3(1.0f, 0.0f, 0.0f);
+    const half3 GREEN = half3(0.0f, 1.0f, 0.0f);
+};
+
+}; // namespace android
diff --git a/services/surfaceflinger/Scheduler/EventThread.cpp b/services/surfaceflinger/Scheduler/EventThread.cpp
index 78bf7c5..a760079 100644
--- a/services/surfaceflinger/Scheduler/EventThread.cpp
+++ b/services/surfaceflinger/Scheduler/EventThread.cpp
@@ -97,7 +97,7 @@
     return event;
 }
 
-DisplayEventReceiver::Event makeConfigChanged(uint32_t displayId, int32_t configId) {
+DisplayEventReceiver::Event makeConfigChanged(PhysicalDisplayId displayId, int32_t configId) {
     DisplayEventReceiver::Event event;
     event.header = {DisplayEventReceiver::DISPLAY_EVENT_CONFIG_CHANGED, displayId, systemTime()};
     event.config.configId = configId;
diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
index 9e95f95..1aa6ade 100644
--- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
+++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
@@ -57,7 +57,7 @@
     }
     ~RefreshRateConfigs() = default;
 
-    const std::unordered_map<RefreshRateType, std::shared_ptr<RefreshRate>>& getRefreshRates() {
+    const std::map<RefreshRateType, std::shared_ptr<RefreshRate>>& getRefreshRates() {
         return mRefreshRates;
     }
     std::shared_ptr<RefreshRate> getRefreshRate(RefreshRateType type) {
@@ -120,7 +120,7 @@
         }
     }
 
-    std::unordered_map<RefreshRateType, std::shared_ptr<RefreshRate>> mRefreshRates;
+    std::map<RefreshRateType, std::shared_ptr<RefreshRate>> mRefreshRates;
 };
 
 } // namespace scheduler
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index a5f025d..c0d7f2d 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -84,6 +84,7 @@
 #include "LayerVector.h"
 #include "MonitoredProducer.h"
 #include "NativeWindowSurface.h"
+#include "RefreshRateOverlay.h"
 #include "StartPropertySetThread.h"
 #include "SurfaceFlinger.h"
 #include "SurfaceInterceptor.h"
@@ -128,8 +129,6 @@
 using ui::Hdr;
 using ui::RenderIntent;
 
-using RefreshRateType = scheduler::RefreshRateConfigs::RefreshRateType;
-
 namespace {
 
 #pragma clang diagnostic push
@@ -281,6 +280,7 @@
         mFactory(factory),
         mTransactionPending(false),
         mAnimTransactionPending(false),
+        mTraversalNeededMainThread(false),
         mLayersRemoved(false),
         mLayersAdded(false),
         mBootTime(systemTime()),
@@ -942,24 +942,18 @@
     return display->getActiveConfig();
 }
 
-void SurfaceFlinger::setDesiredActiveConfig(const sp<IBinder>& displayToken, int mode,
-                                            Scheduler::ConfigEvent event) {
+void SurfaceFlinger::setDesiredActiveConfig(const ActiveConfigInfo& info) {
     ATRACE_CALL();
 
     // Lock is acquired by setRefreshRateTo.
-    const auto display = getDisplayDeviceLocked(displayToken);
+    const auto display = getDisplayDeviceLocked(info.displayToken);
     if (!display) {
-        ALOGE("Attempt to set active config %d for invalid display token %p", mode,
-              displayToken.get());
+        ALOGE("Attempt to set active config %d for invalid display token %p", info.configId,
+              info.displayToken.get());
         return;
     }
     if (display->isVirtual()) {
-        ALOGW("Attempt to set active config %d for virtual display", mode);
-        return;
-    }
-    int currentDisplayPowerMode = display->getPowerMode();
-    if (currentDisplayPowerMode != HWC_POWER_MODE_NORMAL) {
-        // Don't change active config when in AoD.
+        ALOGW("Attempt to set active config %d for virtual display", info.configId);
         return;
     }
 
@@ -967,8 +961,9 @@
     // config twice. However event generation config might have changed so we need to update it
     // accordingly
     std::lock_guard<std::mutex> lock(mActiveConfigLock);
-    const Scheduler::ConfigEvent desiredConfig = mDesiredActiveConfig.event | event;
-    mDesiredActiveConfig = ActiveConfigInfo{mode, displayToken, desiredConfig};
+    const Scheduler::ConfigEvent prevConfig = mDesiredActiveConfig.event;
+    mDesiredActiveConfig = info;
+    mDesiredActiveConfig.event = mDesiredActiveConfig.event | prevConfig;
 
     if (!mDesiredActiveConfigChanged) {
         // This is the first time we set the desired
@@ -979,6 +974,10 @@
     }
     mDesiredActiveConfigChanged = true;
     ATRACE_INT("DesiredActiveConfigChanged", mDesiredActiveConfigChanged);
+
+    if (mRefreshRateOverlay) {
+        mRefreshRateOverlay->changeRefreshRate(mDesiredActiveConfig.type);
+    }
 }
 
 status_t SurfaceFlinger::setActiveConfig(const sp<IBinder>& displayToken, int mode) {
@@ -1041,6 +1040,7 @@
         // on both cases there is nothing left to do
         std::lock_guard<std::mutex> lock(mActiveConfigLock);
         mScheduler->pauseVsyncCallback(mAppConnectionHandle, false);
+        mDesiredActiveConfig.event = Scheduler::ConfigEvent::None;
         mDesiredActiveConfigChanged = false;
         ATRACE_INT("DesiredActiveConfigChanged", mDesiredActiveConfigChanged);
         return false;
@@ -1491,7 +1491,7 @@
     }
 
     mPhaseOffsets->setRefreshRateType(refreshRate);
-    setDesiredActiveConfig(getInternalDisplayTokenLocked(), desiredConfigId, event);
+    setDesiredActiveConfig({refreshRate, desiredConfigId, getInternalDisplayTokenLocked(), event});
 }
 
 void SurfaceFlinger::onHotplugReceived(int32_t sequenceId, hwc2_display_t hwcDisplayId,
@@ -2778,7 +2778,7 @@
      * (perform the transaction for each of them if needed)
      */
 
-    if (transactionFlags & eTraversalNeeded) {
+    if ((transactionFlags & eTraversalNeeded) || mTraversalNeededMainThread) {
         mCurrentState.traverseInZOrder([&](Layer* layer) {
             uint32_t trFlags = layer->getTransactionFlags(eTransactionNeeded);
             if (!trFlags) return;
@@ -2791,6 +2791,7 @@
                 mInputInfoChanged = true;
             }
         });
+        mTraversalNeededMainThread = false;
     }
 
     /*
@@ -3436,7 +3437,8 @@
             }
         }
         renderEngine.drawLayers(clientCompositionDisplay, clientCompositionLayers,
-                                buf->getNativeBuffer(), std::move(fd), readyFence);
+                                buf->getNativeBuffer(), /*useFramebufferCache=*/true, std::move(fd),
+                                readyFence);
         if (expensiveRenderingExpected && displayId) {
             mPowerAdvisor.setExpensiveRenderingExpected(*displayId, false);
         }
@@ -3522,14 +3524,14 @@
 
         while (!transactionQueue.empty()) {
             const auto&
-                    [states, displays, flags, desiredPresentTime, uncacheBuffer, postTime,
-                     privileged] = transactionQueue.front();
+                    [states, displays, flags, desiredPresentTime, uncacheBuffer, listenerCallbacks,
+                     postTime, privileged] = transactionQueue.front();
             if (!transactionIsReadyToBeApplied(desiredPresentTime, states)) {
                 break;
             }
             applyTransactionState(states, displays, flags, mPendingInputWindowCommands,
-                                  desiredPresentTime, uncacheBuffer, postTime, privileged,
-                                  /*isMainThread*/ true);
+                                  desiredPresentTime, uncacheBuffer, listenerCallbacks, postTime,
+                                  privileged, /*isMainThread*/ true);
             transactionQueue.pop();
         }
 
@@ -3587,7 +3589,8 @@
                                          const sp<IBinder>& applyToken,
                                          const InputWindowCommands& inputWindowCommands,
                                          int64_t desiredPresentTime,
-                                         const cached_buffer_t& uncacheBuffer) {
+                                         const cached_buffer_t& uncacheBuffer,
+                                         const std::vector<ListenerCallbacks>& listenerCallbacks) {
     ATRACE_CALL();
 
     const int64_t postTime = systemTime();
@@ -3604,13 +3607,14 @@
     if (mTransactionQueues.find(applyToken) != mTransactionQueues.end() ||
         !transactionIsReadyToBeApplied(desiredPresentTime, states)) {
         mTransactionQueues[applyToken].emplace(states, displays, flags, desiredPresentTime,
-                                               uncacheBuffer, postTime, privileged);
+                                               uncacheBuffer, listenerCallbacks, postTime,
+                                               privileged);
         setTransactionFlags(eTransactionNeeded);
         return;
     }
 
     applyTransactionState(states, displays, flags, inputWindowCommands, desiredPresentTime,
-                          uncacheBuffer, postTime, privileged);
+                          uncacheBuffer, listenerCallbacks, postTime, privileged);
 }
 
 void SurfaceFlinger::applyTransactionState(const Vector<ComposerState>& states,
@@ -3618,6 +3622,7 @@
                                            const InputWindowCommands& inputWindowCommands,
                                            const int64_t desiredPresentTime,
                                            const cached_buffer_t& uncacheBuffer,
+                                           const std::vector<ListenerCallbacks>& listenerCallbacks,
                                            const int64_t postTime, bool privileged,
                                            bool isMainThread) {
     uint32_t transactionFlags = 0;
@@ -3644,7 +3649,15 @@
 
     uint32_t clientStateFlags = 0;
     for (const ComposerState& state : states) {
-        clientStateFlags |= setClientStateLocked(state, desiredPresentTime, postTime, privileged);
+        clientStateFlags |= setClientStateLocked(state, desiredPresentTime, listenerCallbacks,
+                                                 postTime, privileged);
+    }
+
+    // In case the client has sent a Transaction that should receive callbacks but without any
+    // SurfaceControls that should be included in the callback, send the listener and callbackIds
+    // to the callback thread so it can send an empty callback
+    for (const auto& [listener, callbackIds] : listenerCallbacks) {
+        mTransactionCompletedThread.addCallback(listener, callbackIds);
     }
     // If the state doesn't require a traversal and there are callbacks, send them now
     if (!(clientStateFlags & eTraversalNeeded)) {
@@ -3667,6 +3680,13 @@
         transactionFlags = eTransactionNeeded;
     }
 
+    // If we are on the main thread, we are about to preform a traversal. Clear the traversal bit
+    // so we don't have to wake up again next frame to preform an uneeded traversal.
+    if (isMainThread && (transactionFlags & eTraversalNeeded)) {
+        transactionFlags = transactionFlags & (~eTraversalNeeded);
+        mTraversalNeededMainThread = true;
+    }
+
     if (transactionFlags) {
         if (mInterceptor->isEnabled()) {
             mInterceptor->saveTransaction(states, mCurrentState.displays, displays, flags);
@@ -3765,9 +3785,10 @@
     return true;
 }
 
-uint32_t SurfaceFlinger::setClientStateLocked(const ComposerState& composerState,
-                                              int64_t desiredPresentTime, int64_t postTime,
-                                              bool privileged) {
+uint32_t SurfaceFlinger::setClientStateLocked(
+        const ComposerState& composerState, int64_t desiredPresentTime,
+        const std::vector<ListenerCallbacks>& listenerCallbacks, int64_t postTime,
+        bool privileged) {
     const layer_state_t& s = composerState.state;
     sp<Client> client(static_cast<Client*>(composerState.client.get()));
 
@@ -3993,9 +4014,9 @@
         }
     }
     std::vector<sp<CallbackHandle>> callbackHandles;
-    if ((what & layer_state_t::eListenerCallbacksChanged) && (!s.listenerCallbacks.empty())) {
+    if ((what & layer_state_t::eHasListenerCallbacksChanged) && (!listenerCallbacks.empty())) {
         mTransactionCompletedThread.run();
-        for (const auto& [listener, callbackIds] : s.listenerCallbacks) {
+        for (const auto& [listener, callbackIds] : listenerCallbacks) {
             callbackHandles.emplace_back(new CallbackHandle(listener, callbackIds, s.surface));
         }
     }
@@ -4256,7 +4277,7 @@
     d.width = 0;
     d.height = 0;
     displays.add(d);
-    setTransactionState(state, displays, 0, nullptr, mPendingInputWindowCommands, -1, {});
+    setTransactionState(state, displays, 0, nullptr, mPendingInputWindowCommands, -1, {}, {});
 
     setPowerModeInternal(display, HWC_POWER_MODE_NORMAL);
 
@@ -5020,9 +5041,9 @@
         code == IBinder::SYSPROPS_TRANSACTION) {
         return OK;
     }
-    // Numbers from 1000 to 1033 are currently used for backdoors. The code
+    // Numbers from 1000 to 1034 are currently used for backdoors. The code
     // in onTransact verifies that the user is root, and has access to use SF.
-    if (code >= 1000 && code <= 1033) {
+    if (code >= 1000 && code <= 1034) {
         ALOGV("Accessing SurfaceFlinger through backdoor code: %u", code);
         return OK;
     }
@@ -5338,6 +5359,18 @@
                 reply->writeInt32(NO_ERROR);
                 return NO_ERROR;
             }
+            case 1034: {
+                // TODO(b/129297325): expose this via developer menu option
+                n = data.readInt32();
+                if (n && !mRefreshRateOverlay) {
+                    std::lock_guard<std::mutex> lock(mActiveConfigLock);
+                    mRefreshRateOverlay = std::make_unique<RefreshRateOverlay>(*this);
+                    mRefreshRateOverlay->changeRefreshRate(mDesiredActiveConfig.type);
+                } else if (!n) {
+                    mRefreshRateOverlay.reset();
+                }
+                return NO_ERROR;
+            }
         }
     }
     return err;
@@ -5722,7 +5755,7 @@
     base::unique_fd drawFence;
     getRenderEngine().useProtectedContext(false);
     getRenderEngine().drawLayers(clientCompositionDisplay, clientCompositionLayers, buffer,
-                                 std::move(bufferFence), &drawFence);
+                                 /*useFramebufferCache=*/false, std::move(bufferFence), &drawFence);
 
     *outSyncFd = drawFence.release();
 }
@@ -5805,30 +5838,14 @@
         mAllowedConfigs[*displayId] = std::move(allowedConfigs);
     }
 
-    // make sure that the current config is still allowed
-    int currentConfigIndex = getHwComposer().getActiveConfigIndex(*displayId);
-    if (!isConfigAllowed(*displayId, currentConfigIndex)) {
-        for (const auto& [type, config] : mRefreshRateConfigs[*displayId]->getRefreshRates()) {
-            if (config && isConfigAllowed(*displayId, config->configId)) {
-                // TODO: we switch to the first allowed config. In the future
-                // we may want to enhance this logic to pick a similar config
-                // to the current one
-                ALOGV("Old config is not allowed - switching to config %d", config->configId);
-                setDesiredActiveConfig(displayToken, config->configId,
-                                       Scheduler::ConfigEvent::Changed);
-                break;
-            }
-        }
-    }
-
-    // If idle timer and fps detection are disabled and we are in RefreshRateType::DEFAULT,
-    // there is no trigger to move to RefreshRateType::PERFORMANCE, even if it is an allowed.
-    if (!mScheduler->isIdleTimerEnabled() && !mUseSmart90ForVideo) {
-        const auto& performanceRefreshRate =
-                mRefreshRateConfigs[*displayId]->getRefreshRate(RefreshRateType::PERFORMANCE);
-        if (performanceRefreshRate &&
-            isConfigAllowed(*displayId, performanceRefreshRate->configId)) {
-            setRefreshRateTo(RefreshRateType::PERFORMANCE, Scheduler::ConfigEvent::Changed);
+    // Set the highest allowed config by iterating backwards on available refresh rates
+    const auto& refreshRates = mRefreshRateConfigs[*displayId]->getRefreshRates();
+    for (auto iter = refreshRates.crbegin(); iter != refreshRates.crend(); ++iter) {
+        if (iter->second && isConfigAllowed(*displayId, iter->second->configId)) {
+            ALOGV("switching to config %d", iter->second->configId);
+            setDesiredActiveConfig({iter->first, iter->second->configId, displayToken,
+                                    Scheduler::ConfigEvent::Changed});
+            break;
         }
     }
 }
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 26d0cd1..3d8b6b7 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -90,6 +90,8 @@
 
 namespace android {
 
+using RefreshRateType = scheduler::RefreshRateConfigs::RefreshRateType;
+
 // ---------------------------------------------------------------------------
 
 class Client;
@@ -102,6 +104,7 @@
 class IInputFlinger;
 class InjectVSyncSource;
 class Layer;
+class RefreshRateOverlay;
 class Surface;
 class SurfaceFlingerBE;
 class TimeStats;
@@ -366,6 +369,7 @@
     friend class BufferQueueLayer;
     friend class BufferStateLayer;
     friend class MonitoredProducer;
+    friend class RefreshRateOverlay;
     friend class RegionSamplingThread;
     friend class SurfaceTracing;
 
@@ -431,8 +435,8 @@
                              const Vector<DisplayState>& displays, uint32_t flags,
                              const sp<IBinder>& applyToken,
                              const InputWindowCommands& inputWindowCommands,
-                             int64_t desiredPresentTime,
-                             const cached_buffer_t& uncacheBuffer) override;
+                             int64_t desiredPresentTime, const cached_buffer_t& uncacheBuffer,
+                             const std::vector<ListenerCallbacks>& listenerCallbacks) override;
     void bootFinished() override;
     bool authenticateSurfaceTexture(
             const sp<IGraphicBufferProducer>& bufferProducer) const override;
@@ -528,11 +532,30 @@
     void signalLayerUpdate();
     void signalRefresh();
 
+    struct ActiveConfigInfo {
+        RefreshRateType type;
+        int configId;
+        sp<IBinder> displayToken;
+        Scheduler::ConfigEvent event;
+
+        bool operator!=(const ActiveConfigInfo& other) const {
+            if (type != other.type) {
+                return true;
+            }
+            if (configId != other.configId) {
+                return true;
+            }
+            if (displayToken != other.displayToken) {
+                return true;
+            }
+            return (event != other.event);
+        }
+    };
+
     // called on the main thread in response to initializeDisplays()
     void onInitializeDisplays() REQUIRES(mStateLock);
     // Sets the desired active config bit. It obtains the lock, and sets mDesiredActiveConfig.
-    void setDesiredActiveConfig(const sp<IBinder>& displayToken, int mode,
-                                Scheduler::ConfigEvent event) REQUIRES(mStateLock);
+    void setDesiredActiveConfig(const ActiveConfigInfo& info) REQUIRES(mStateLock);
     // Once HWC has returned the present fence, this sets the active config and a new refresh
     // rate in SF. It also triggers HWC vsync.
     void setActiveConfigInternal() REQUIRES(mStateLock);
@@ -579,8 +602,10 @@
                                const Vector<DisplayState>& displays, uint32_t flags,
                                const InputWindowCommands& inputWindowCommands,
                                const int64_t desiredPresentTime,
-                               const cached_buffer_t& uncacheBuffer, const int64_t postTime,
-                               bool privileged, bool isMainThread = false) REQUIRES(mStateLock);
+                               const cached_buffer_t& uncacheBuffer,
+                               const std::vector<ListenerCallbacks>& listenerCallbacks,
+                               const int64_t postTime, bool privileged, bool isMainThread = false)
+            REQUIRES(mStateLock);
     bool flushTransactionQueues();
     uint32_t getTransactionFlags(uint32_t flags);
     uint32_t peekTransactionFlags();
@@ -593,6 +618,7 @@
     bool transactionIsReadyToBeApplied(int64_t desiredPresentTime,
                                        const Vector<ComposerState>& states);
     uint32_t setClientStateLocked(const ComposerState& composerState, int64_t desiredPresentTime,
+                                  const std::vector<ListenerCallbacks>& listenerCallbacks,
                                   int64_t postTime, bool privileged) REQUIRES(mStateLock);
     uint32_t setDisplayStateLocked(const DisplayState& s) REQUIRES(mStateLock);
     uint32_t addInputWindowCommands(const InputWindowCommands& inputWindowCommands)
@@ -815,8 +841,7 @@
 
     // Sets the refresh rate by switching active configs, if they are available for
     // the desired refresh rate.
-    void setRefreshRateTo(scheduler::RefreshRateConfigs::RefreshRateType,
-                          Scheduler::ConfigEvent event) REQUIRES(mStateLock);
+    void setRefreshRateTo(RefreshRateType, Scheduler::ConfigEvent event) REQUIRES(mStateLock);
 
     bool isConfigAllowed(const DisplayId& displayId, int32_t config);
 
@@ -938,6 +963,7 @@
     bool mTransactionPending;
     bool mAnimTransactionPending;
     SortedVector< sp<Layer> > mLayersPendingRemoval;
+    bool mTraversalNeededMainThread;
 
     // guards access to the mDrawing state if tracing is enabled.
     mutable std::mutex mDrawingStateLock;
@@ -1062,12 +1088,14 @@
         TransactionState(const Vector<ComposerState>& composerStates,
                          const Vector<DisplayState>& displayStates, uint32_t transactionFlags,
                          int64_t desiredPresentTime, const cached_buffer_t& uncacheBuffer,
-                         int64_t postTime, bool privileged)
+                         const std::vector<ListenerCallbacks>& listenerCallbacks, int64_t postTime,
+                         bool privileged)
               : states(composerStates),
                 displays(displayStates),
                 flags(transactionFlags),
                 desiredPresentTime(desiredPresentTime),
                 buffer(uncacheBuffer),
+                callback(listenerCallbacks),
                 postTime(postTime),
                 privileged(privileged) {}
 
@@ -1076,6 +1104,7 @@
         uint32_t flags;
         const int64_t desiredPresentTime;
         cached_buffer_t buffer;
+        std::vector<ListenerCallbacks> callback;
         const int64_t postTime;
         bool privileged;
     };
@@ -1134,18 +1163,6 @@
     std::unordered_map<DisplayId, std::unique_ptr<const AllowedDisplayConfigs>> mAllowedConfigs
             GUARDED_BY(mAllowedConfigsLock);
 
-    struct ActiveConfigInfo {
-        int configId;
-        sp<IBinder> displayToken;
-        Scheduler::ConfigEvent event;
-
-        bool operator!=(const ActiveConfigInfo& other) const {
-            if (configId != other.configId) {
-                return true;
-            }
-            return (displayToken != other.displayToken);
-        }
-    };
     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
@@ -1172,6 +1189,8 @@
     sp<SetInputWindowsListener> mSetInputWindowsListener;
     bool mPendingSyncInputWindows GUARDED_BY(mStateLock);
     Hwc2::impl::PowerAdvisor mPowerAdvisor;
+
+    std::unique_ptr<RefreshRateOverlay> mRefreshRateOverlay;
 };
 }; // namespace android
 
diff --git a/services/surfaceflinger/SurfaceFlingerProperties.cpp b/services/surfaceflinger/SurfaceFlingerProperties.cpp
index e130511..09b793a 100644
--- a/services/surfaceflinger/SurfaceFlingerProperties.cpp
+++ b/services/surfaceflinger/SurfaceFlingerProperties.cpp
@@ -1,6 +1,4 @@
 
-#include <sysprop/SurfaceFlingerProperties.sysprop.h>
-
 #include <android/hardware/configstore/1.0/ISurfaceFlingerConfigs.h>
 #include <android/hardware/configstore/1.1/ISurfaceFlingerConfigs.h>
 #include <android/hardware/configstore/1.1/types.h>
diff --git a/services/surfaceflinger/SurfaceFlingerProperties.h b/services/surfaceflinger/SurfaceFlingerProperties.h
index 6f90117..b2fafdd 100644
--- a/services/surfaceflinger/SurfaceFlingerProperties.h
+++ b/services/surfaceflinger/SurfaceFlingerProperties.h
@@ -2,9 +2,9 @@
 #ifndef SURFACEFLINGERPROPERTIES_H_
 #define SURFACEFLINGERPROPERTIES_H_
 
+#include <SurfaceFlingerProperties.sysprop.h>
 #include <android/hardware/configstore/1.1/ISurfaceFlingerConfigs.h>
 #include <android/hardware/graphics/common/1.2/types.h>
-#include <sysprop/SurfaceFlingerProperties.sysprop.h>
 #include <ui/ConfigStoreTypes.h>
 
 #include <cstdint>
diff --git a/services/surfaceflinger/TransactionCompletedThread.cpp b/services/surfaceflinger/TransactionCompletedThread.cpp
index d2b7fe0..6e0c1e2 100644
--- a/services/surfaceflinger/TransactionCompletedThread.cpp
+++ b/services/surfaceflinger/TransactionCompletedThread.cpp
@@ -100,26 +100,48 @@
     addCallbackHandle(handle);
 }
 
-void TransactionCompletedThread::addCallbackHandle(const sp<CallbackHandle>& handle) {
-    const sp<IBinder> listener = IInterface::asBinder(handle->listener);
+void TransactionCompletedThread::addCallback(
+        const sp<ITransactionCompletedListener>& transactionListener,
+        const std::vector<CallbackId>& callbackIds) {
+    std::lock_guard lock(mMutex);
+    addCallbackLocked(transactionListener, callbackIds);
+}
 
+status_t TransactionCompletedThread::addCallbackHandle(const sp<CallbackHandle>& handle) {
+    status_t err = addCallbackLocked(handle->listener, handle->callbackIds);
+    if (err != NO_ERROR) {
+        ALOGE("cannot add callback, err: %d", err);
+        return err;
+    }
+
+    const sp<IBinder> listener = IInterface::asBinder(handle->listener);
+    auto& listenerStats = mListenerStats[listener];
+    auto& transactionStats = listenerStats.transactionStats[handle->callbackIds];
+
+    transactionStats.latchTime = handle->latchTime;
+    transactionStats.surfaceStats.emplace_back(handle->surfaceControl, handle->acquireTime,
+                                               handle->previousReleaseFence);
+    return NO_ERROR;
+}
+
+status_t TransactionCompletedThread::addCallbackLocked(
+        const sp<ITransactionCompletedListener>& transactionListener,
+        const std::vector<CallbackId>& callbackIds) {
+    const sp<IBinder> listener = IInterface::asBinder(transactionListener);
     // If we don't already have a reference to this listener, linkToDeath so we get a notification
     // if it dies.
     if (mListenerStats.count(listener) == 0) {
-        status_t error = listener->linkToDeath(mDeathRecipient);
-        if (error != NO_ERROR) {
-            ALOGE("cannot add callback handle because linkToDeath failed, err: %d", error);
-            return;
+        status_t err = listener->linkToDeath(mDeathRecipient);
+        if (err != NO_ERROR) {
+            ALOGE("cannot add callback because linkToDeath failed, err: %d", err);
+            return err;
         }
     }
 
     auto& listenerStats = mListenerStats[listener];
-    listenerStats.listener = handle->listener;
-
-    auto& transactionStats = listenerStats.transactionStats[handle->callbackIds];
-    transactionStats.latchTime = handle->latchTime;
-    transactionStats.surfaceStats.emplace_back(handle->surfaceControl, handle->acquireTime,
-                                               handle->previousReleaseFence);
+    listenerStats.listener = transactionListener;
+    listenerStats.transactionStats[callbackIds];
+    return NO_ERROR;
 }
 
 void TransactionCompletedThread::addPresentFence(const sp<Fence>& presentFence) {
diff --git a/services/surfaceflinger/TransactionCompletedThread.h b/services/surfaceflinger/TransactionCompletedThread.h
index f49306d..88808fd 100644
--- a/services/surfaceflinger/TransactionCompletedThread.h
+++ b/services/surfaceflinger/TransactionCompletedThread.h
@@ -64,6 +64,11 @@
     // presented this frame.
     void addUnpresentedCallbackHandle(const sp<CallbackHandle>& handle);
 
+    // Adds listener and callbackIds in case there are no SurfaceControls that are supposed
+    // to be included in the callback.
+    void addCallback(const sp<ITransactionCompletedListener>& transactionListener,
+                     const std::vector<CallbackId>& callbackIds);
+
     void addPresentFence(const sp<Fence>& presentFence);
 
     void sendCallbacks();
@@ -71,7 +76,9 @@
 private:
     void threadMain();
 
-    void addCallbackHandle(const sp<CallbackHandle>& handle) REQUIRES(mMutex);
+    status_t addCallbackHandle(const sp<CallbackHandle>& handle) REQUIRES(mMutex);
+    status_t addCallbackLocked(const sp<ITransactionCompletedListener>& transactionListener,
+                               const std::vector<CallbackId>& callbackIds) REQUIRES(mMutex);
 
     class ThreadDeathRecipient : public IBinder::DeathRecipient {
     public:
diff --git a/services/surfaceflinger/sysprop/Android.bp b/services/surfaceflinger/sysprop/Android.bp
new file mode 100644
index 0000000..7721d7d2
--- /dev/null
+++ b/services/surfaceflinger/sysprop/Android.bp
@@ -0,0 +1,6 @@
+sysprop_library {
+    name: "SurfaceFlingerProperties",
+    srcs: ["*.sysprop"],
+    api_packages: ["android.sysprop"],
+    property_owner: "Platform",
+}
diff --git a/services/surfaceflinger/sysprop/api/current.txt b/services/surfaceflinger/sysprop/api/current.txt
new file mode 100644
index 0000000..d802177
--- /dev/null
+++ b/services/surfaceflinger/sysprop/api/current.txt
@@ -0,0 +1 @@
+// Signature format: 2.0
diff --git a/services/surfaceflinger/sysprop/api/removed.txt b/services/surfaceflinger/sysprop/api/removed.txt
new file mode 100644
index 0000000..d802177
--- /dev/null
+++ b/services/surfaceflinger/sysprop/api/removed.txt
@@ -0,0 +1 @@
+// Signature format: 2.0
diff --git a/services/surfaceflinger/sysprop/api/system-current.txt b/services/surfaceflinger/sysprop/api/system-current.txt
new file mode 100644
index 0000000..d802177
--- /dev/null
+++ b/services/surfaceflinger/sysprop/api/system-current.txt
@@ -0,0 +1 @@
+// Signature format: 2.0
diff --git a/services/surfaceflinger/sysprop/api/system-removed.txt b/services/surfaceflinger/sysprop/api/system-removed.txt
new file mode 100644
index 0000000..d802177
--- /dev/null
+++ b/services/surfaceflinger/sysprop/api/system-removed.txt
@@ -0,0 +1 @@
+// Signature format: 2.0
diff --git a/services/surfaceflinger/sysprop/api/test-current.txt b/services/surfaceflinger/sysprop/api/test-current.txt
new file mode 100644
index 0000000..d802177
--- /dev/null
+++ b/services/surfaceflinger/sysprop/api/test-current.txt
@@ -0,0 +1 @@
+// Signature format: 2.0
diff --git a/services/surfaceflinger/sysprop/api/test-removed.txt b/services/surfaceflinger/sysprop/api/test-removed.txt
new file mode 100644
index 0000000..d802177
--- /dev/null
+++ b/services/surfaceflinger/sysprop/api/test-removed.txt
@@ -0,0 +1 @@
+// Signature format: 2.0
diff --git a/services/surfaceflinger/tests/unittests/CompositionTest.cpp b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
index ea2818d..ef3dfef 100644
--- a/services/surfaceflinger/tests/unittests/CompositionTest.cpp
+++ b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
@@ -175,7 +175,6 @@
     renderengine::mock::RenderEngine* mRenderEngine = new renderengine::mock::RenderEngine();
     mock::MessageQueue* mMessageQueue = new mock::MessageQueue();
     mock::DispSync* mPrimaryDispSync = new mock::DispSync();
-    renderengine::mock::Framebuffer* mReFrameBuffer = new renderengine::mock::Framebuffer();
 
     sp<Fence> mClientTargetAcquireFence = Fence::NO_FENCE;
 
@@ -312,8 +311,8 @@
         EXPECT_CALL(*test->mRenderEngine, drawLayers)
                 .WillRepeatedly(
                         [](const renderengine::DisplaySettings& displaySettings,
-                           const std::vector<renderengine::LayerSettings>& /*layerSettings*/,
-                           ANativeWindowBuffer*, base::unique_fd&&, base::unique_fd*) -> status_t {
+                           const std::vector<renderengine::LayerSettings>&, ANativeWindowBuffer*,
+                           const bool, base::unique_fd&&, base::unique_fd*) -> status_t {
                             EXPECT_EQ(DEFAULT_DISPLAY_MAX_LUMINANCE, displaySettings.maxLuminance);
                             EXPECT_EQ(Rect(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT),
                                       displaySettings.physicalDisplay);
@@ -351,8 +350,8 @@
         EXPECT_CALL(*test->mRenderEngine, drawLayers)
                 .WillRepeatedly(
                         [](const renderengine::DisplaySettings& displaySettings,
-                           const std::vector<renderengine::LayerSettings>& /*layerSettings*/,
-                           ANativeWindowBuffer*, base::unique_fd&&, base::unique_fd*) -> status_t {
+                           const std::vector<renderengine::LayerSettings>&, ANativeWindowBuffer*,
+                           const bool, base::unique_fd&&, base::unique_fd*) -> status_t {
                             EXPECT_EQ(DEFAULT_DISPLAY_MAX_LUMINANCE, displaySettings.maxLuminance);
                             EXPECT_EQ(Rect(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT),
                                       displaySettings.physicalDisplay);
@@ -581,7 +580,7 @@
         EXPECT_CALL(*test->mRenderEngine, drawLayers)
                 .WillOnce([](const renderengine::DisplaySettings& displaySettings,
                              const std::vector<renderengine::LayerSettings>& layerSettings,
-                             ANativeWindowBuffer*, base::unique_fd&&,
+                             ANativeWindowBuffer*, const bool, base::unique_fd&&,
                              base::unique_fd*) -> status_t {
                     EXPECT_EQ(DEFAULT_DISPLAY_MAX_LUMINANCE, displaySettings.maxLuminance);
                     EXPECT_EQ(Rect(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT),
@@ -624,7 +623,7 @@
         EXPECT_CALL(*test->mRenderEngine, drawLayers)
                 .WillOnce([](const renderengine::DisplaySettings& displaySettings,
                              const std::vector<renderengine::LayerSettings>& layerSettings,
-                             ANativeWindowBuffer*, base::unique_fd&&,
+                             ANativeWindowBuffer*, const bool, base::unique_fd&&,
                              base::unique_fd*) -> status_t {
                     EXPECT_EQ(DEFAULT_DISPLAY_MAX_LUMINANCE, displaySettings.maxLuminance);
                     EXPECT_EQ(Rect(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT),
@@ -694,7 +693,7 @@
         EXPECT_CALL(*test->mRenderEngine, drawLayers)
                 .WillOnce([](const renderengine::DisplaySettings& displaySettings,
                              const std::vector<renderengine::LayerSettings>& layerSettings,
-                             ANativeWindowBuffer*, base::unique_fd&&,
+                             ANativeWindowBuffer*, const bool, base::unique_fd&&,
                              base::unique_fd*) -> status_t {
                     EXPECT_EQ(DEFAULT_DISPLAY_MAX_LUMINANCE, displaySettings.maxLuminance);
                     EXPECT_EQ(Rect(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT),
diff --git a/services/surfaceflinger/tests/unittests/EventThreadTest.cpp b/services/surfaceflinger/tests/unittests/EventThreadTest.cpp
index 406ec81..249c78f 100644
--- a/services/surfaceflinger/tests/unittests/EventThreadTest.cpp
+++ b/services/surfaceflinger/tests/unittests/EventThreadTest.cpp
@@ -38,6 +38,7 @@
 
 constexpr PhysicalDisplayId INTERNAL_DISPLAY_ID = 111;
 constexpr PhysicalDisplayId EXTERNAL_DISPLAY_ID = 222;
+constexpr PhysicalDisplayId DISPLAY_ID_64BIT = 0xabcd12349876fedcULL;
 
 class MockVSyncSource : public VSyncSource {
 public:
@@ -470,5 +471,10 @@
     expectConfigChangedEventReceivedByConnection(EXTERNAL_DISPLAY_ID, 5);
 }
 
+TEST_F(EventThreadTest, postConfigChangedPrimary64bit) {
+    mThread->onConfigChanged(DISPLAY_ID_64BIT, 7);
+    expectConfigChangedEventReceivedByConnection(DISPLAY_ID_64BIT, 7);
+}
+
 } // namespace
 } // namespace android
diff --git a/services/vr/bufferhubd/Android.bp b/services/vr/bufferhubd/Android.bp
index 4e24a64..afb3004 100644
--- a/services/vr/bufferhubd/Android.bp
+++ b/services/vr/bufferhubd/Android.bp
@@ -44,9 +44,6 @@
     static_libs: [
         "libbufferhub",
     ],
-
-    // TODO(b/117568153): Temporarily opt out using libcrt.
-    no_libcrt: true,
 }
 
 cc_binary {
diff --git a/vulkan/libvulkan/Android.bp b/vulkan/libvulkan/Android.bp
index 206c8eb..71a120a 100644
--- a/vulkan/libvulkan/Android.bp
+++ b/vulkan/libvulkan/Android.bp
@@ -76,6 +76,7 @@
         "libhardware",
         "libsync",
         "libbase",
+        "libdl_android",
         "libhidlbase",
         "libhidltransport",
         "liblog",