Merge "Process focus events first"
diff --git a/libs/binder/Parcel.cpp b/libs/binder/Parcel.cpp
index 9e135ac..f07f82a 100644
--- a/libs/binder/Parcel.cpp
+++ b/libs/binder/Parcel.cpp
@@ -2836,8 +2836,6 @@
         }
 
     } else {
-        desired = std::max(desired, (size_t)128);
-
         // This is the first data.  Easy!
         uint8_t* data = (uint8_t*)malloc(desired);
         if (!data) {
diff --git a/libs/binder/TEST_MAPPING b/libs/binder/TEST_MAPPING
index 0442b8b..9aa7651 100644
--- a/libs/binder/TEST_MAPPING
+++ b/libs/binder/TEST_MAPPING
@@ -7,9 +7,6 @@
       "name": "binderVendorDoubleLoadTest"
     },
     {
-      "name": "binderAllocationLimits"
-    },
-    {
       "name": "binderDriverInterfaceTest"
     },
     {
diff --git a/libs/binder/tests/Android.bp b/libs/binder/tests/Android.bp
index 2680e84..c0da2cd 100644
--- a/libs/binder/tests/Android.bp
+++ b/libs/binder/tests/Android.bp
@@ -169,18 +169,3 @@
     test_suites: ["device-tests"],
     require_root: true,
 }
-
-cc_test {
-    name: "binderAllocationLimits",
-    defaults: ["binder_test_defaults"],
-    srcs: ["binderAllocationLimits.cpp"],
-    shared_libs: [
-        "libbinder",
-        "liblog",
-        "libutils",
-        "libutilscallstack",
-        "libbase",
-    ],
-    test_suites: ["device-tests"],
-    require_root: true,
-}
diff --git a/libs/binder/tests/binderAllocationLimits.cpp b/libs/binder/tests/binderAllocationLimits.cpp
deleted file mode 100644
index e1f5ed5..0000000
--- a/libs/binder/tests/binderAllocationLimits.cpp
+++ /dev/null
@@ -1,186 +0,0 @@
-/*
- * 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.
- */
-
-#include <android-base/logging.h>
-#include <binder/Parcel.h>
-#include <binder/IServiceManager.h>
-#include <gtest/gtest.h>
-#include <utils/CallStack.h>
-
-#include <malloc.h>
-#include <functional>
-#include <vector>
-
-struct DestructionAction {
-    DestructionAction(std::function<void()> f) : mF(std::move(f)) {}
-    ~DestructionAction() { mF(); };
-private:
-    std::function<void()> mF;
-};
-
-// Group of hooks
-struct MallocHooks {
-    decltype(__malloc_hook) malloc_hook;
-    decltype(__realloc_hook) realloc_hook;
-
-    static MallocHooks save() {
-        return {
-            .malloc_hook = __malloc_hook,
-            .realloc_hook = __realloc_hook,
-        };
-    }
-
-    void overwrite() const {
-        __malloc_hook = malloc_hook;
-        __realloc_hook = realloc_hook;
-    }
-};
-
-static const MallocHooks orig_malloc_hooks = MallocHooks::save();
-
-// When malloc is hit, executes lambda.
-namespace LambdaHooks {
-    using AllocationHook = std::function<void(size_t)>;
-    static std::vector<AllocationHook> lambdas = {};
-
-    static void* lambda_realloc_hook(void* ptr, size_t bytes, const void* arg);
-    static void* lambda_malloc_hook(size_t bytes, const void* arg);
-
-    static const MallocHooks lambda_malloc_hooks = {
-        .malloc_hook = lambda_malloc_hook,
-        .realloc_hook = lambda_realloc_hook,
-    };
-
-    static void* lambda_malloc_hook(size_t bytes, const void* arg) {
-        {
-            orig_malloc_hooks.overwrite();
-            lambdas.at(lambdas.size() - 1)(bytes);
-            lambda_malloc_hooks.overwrite();
-        }
-        return orig_malloc_hooks.malloc_hook(bytes, arg);
-    }
-
-    static void* lambda_realloc_hook(void* ptr, size_t bytes, const void* arg) {
-        {
-            orig_malloc_hooks.overwrite();
-            lambdas.at(lambdas.size() - 1)(bytes);
-            lambda_malloc_hooks.overwrite();
-        }
-        return orig_malloc_hooks.realloc_hook(ptr, bytes, arg);
-    }
-
-}
-
-// Action to execute when malloc is hit. Supports nesting. Malloc is not
-// restricted when the allocation hook is being processed.
-__attribute__((warn_unused_result))
-DestructionAction OnMalloc(LambdaHooks::AllocationHook f) {
-    MallocHooks before = MallocHooks::save();
-    LambdaHooks::lambdas.emplace_back(std::move(f));
-    LambdaHooks::lambda_malloc_hooks.overwrite();
-    return DestructionAction([before]() {
-        before.overwrite();
-        LambdaHooks::lambdas.pop_back();
-    });
-}
-
-// exported symbol, to force compiler not to optimize away pointers we set here
-const void* imaginary_use;
-
-TEST(TestTheTest, OnMalloc) {
-    size_t mallocs = 0;
-    {
-        const auto on_malloc = OnMalloc([&](size_t bytes) {
-            mallocs++;
-            EXPECT_EQ(bytes, 40);
-        });
-
-        imaginary_use = new int[10];
-    }
-    EXPECT_EQ(mallocs, 1);
-}
-
-
-__attribute__((warn_unused_result))
-DestructionAction ScopeDisallowMalloc() {
-    return OnMalloc([&](size_t bytes) {
-        ADD_FAILURE() << "Unexpected allocation: " << bytes;
-        using android::CallStack;
-        std::cout << CallStack::stackToString("UNEXPECTED ALLOCATION", CallStack::getCurrent(4 /*ignoreDepth*/).get())
-                  << std::endl;
-    });
-}
-
-using android::IBinder;
-using android::Parcel;
-using android::String16;
-using android::defaultServiceManager;
-using android::sp;
-using android::IServiceManager;
-
-static sp<IBinder> GetRemoteBinder() {
-    // This gets binder representing the service manager
-    // the current IServiceManager API doesn't expose the binder, and
-    // I want to avoid adding usages of the AIDL generated interface it
-    // is using underneath, so to avoid people copying it.
-    sp<IBinder> binder = defaultServiceManager()->checkService(String16("manager"));
-    EXPECT_NE(nullptr, binder);
-    return binder;
-}
-
-TEST(BinderAllocation, ParcelOnStack) {
-    const auto m = ScopeDisallowMalloc();
-    Parcel p;
-    imaginary_use = p.data();
-}
-
-TEST(BinderAllocation, GetServiceManager) {
-    defaultServiceManager(); // first call may alloc
-    const auto m = ScopeDisallowMalloc();
-    defaultServiceManager();
-}
-
-// note, ping does not include interface descriptor
-TEST(BinderAllocation, PingTransaction) {
-    sp<IBinder> a_binder = GetRemoteBinder();
-    const auto m = ScopeDisallowMalloc();
-    a_binder->pingBinder();
-}
-
-TEST(BinderAllocation, SmallTransaction) {
-    String16 empty_descriptor = String16("");
-    sp<IServiceManager> manager = defaultServiceManager();
-
-    size_t mallocs = 0;
-    const auto on_malloc = OnMalloc([&](size_t bytes) {
-        mallocs++;
-        // Parcel should allocate a small amount by default
-        EXPECT_EQ(bytes, 128);
-    });
-    manager->checkService(empty_descriptor);
-
-    EXPECT_EQ(mallocs, 1);
-}
-
-int main(int argc, char** argv) {
-    if (getenv("LIBC_HOOKS_ENABLE") == nullptr) {
-        CHECK(0 == setenv("LIBC_HOOKS_ENABLE", "1", true /*overwrite*/));
-        execv(argv[0], argv);
-        return 1;
-    }
-    ::testing::InitGoogleTest(&argc, argv);
-    return RUN_ALL_TESTS();
-}
diff --git a/libs/gralloc/types/include/gralloctypes/Gralloc4.h b/libs/gralloc/types/include/gralloctypes/Gralloc4.h
index 8d12754..1a7c2c9 100644
--- a/libs/gralloc/types/include/gralloctypes/Gralloc4.h
+++ b/libs/gralloc/types/include/gralloctypes/Gralloc4.h
@@ -431,6 +431,12 @@
          static_cast<int64_t>(
                  aidl::android::hardware::graphics::common::PlaneLayoutComponentType::A)};
 
+static const aidl::android::hardware::graphics::common::ExtendableType
+        PlaneLayoutComponentType_RAW =
+                {GRALLOC4_STANDARD_PLANE_LAYOUT_COMPONENT_TYPE,
+                 static_cast<int64_t>(
+                         aidl::android::hardware::graphics::common::PlaneLayoutComponentType::RAW)};
+
 /*---------------------------------------------------------------------------------------------*/
 
 /**
diff --git a/libs/renderengine/RenderEngine.cpp b/libs/renderengine/RenderEngine.cpp
index f0eb34b..596f15c 100644
--- a/libs/renderengine/RenderEngine.cpp
+++ b/libs/renderengine/RenderEngine.cpp
@@ -25,7 +25,7 @@
 namespace android {
 namespace renderengine {
 
-std::unique_ptr<impl::RenderEngine> RenderEngine::create(const RenderEngineCreationArgs& args) {
+std::unique_ptr<RenderEngine> RenderEngine::create(const RenderEngineCreationArgs& args) {
     RenderEngineType renderEngineType = args.renderEngineType;
 
     // Keep the ability to override by PROPERTIES:
@@ -41,7 +41,9 @@
     switch (renderEngineType) {
         case RenderEngineType::THREADED:
             ALOGD("Threaded RenderEngine with GLES Backend");
-            return renderengine::threaded::RenderEngineThreaded::create(args);
+            return renderengine::threaded::RenderEngineThreaded::create([&args]() {
+                return android::renderengine::gl::GLESRenderEngine::create(args);
+            });
         case RenderEngineType::GLES:
         default:
             ALOGD("RenderEngine with GLES Backend");
diff --git a/libs/renderengine/include/renderengine/RenderEngine.h b/libs/renderengine/include/renderengine/RenderEngine.h
index 45e19ee..b137023 100644
--- a/libs/renderengine/include/renderengine/RenderEngine.h
+++ b/libs/renderengine/include/renderengine/RenderEngine.h
@@ -76,7 +76,7 @@
         THREADED = 2,
     };
 
-    static std::unique_ptr<impl::RenderEngine> create(const RenderEngineCreationArgs& args);
+    static std::unique_ptr<RenderEngine> create(const RenderEngineCreationArgs& args);
 
     virtual ~RenderEngine() = 0;
 
diff --git a/libs/renderengine/tests/RenderEngineThreadedTest.cpp b/libs/renderengine/tests/RenderEngineThreadedTest.cpp
index 117af0f..69a0e19 100644
--- a/libs/renderengine/tests/RenderEngineThreadedTest.cpp
+++ b/libs/renderengine/tests/RenderEngineThreadedTest.cpp
@@ -28,56 +28,44 @@
 using testing::Return;
 
 struct RenderEngineThreadedTest : public ::testing::Test {
-    RenderEngineThreadedTest() {
-        sThreadedRE->setRenderEngine(std::unique_ptr<renderengine::RenderEngine>(mRenderEngine));
-    }
-
     ~RenderEngineThreadedTest() {}
 
-    static void SetUpTestSuite() {
-        sThreadedRE = renderengine::threaded::RenderEngineThreaded::create(
-                renderengine::RenderEngineCreationArgs::Builder()
-                        .setRenderEngineType(renderengine::RenderEngine::RenderEngineType::THREADED)
-                        .build());
+    void SetUp() override {
+        mThreadedRE = renderengine::threaded::RenderEngineThreaded::create(
+                [this]() { return std::unique_ptr<renderengine::RenderEngine>(mRenderEngine); });
     }
 
-    static void TearDownTestSuite() { sThreadedRE = nullptr; }
-
-    // To avoid creating RE on every instantiation of the test, it is kept as a static variable.
-    static std::unique_ptr<renderengine::threaded::RenderEngineThreaded> sThreadedRE;
+    std::unique_ptr<renderengine::threaded::RenderEngineThreaded> mThreadedRE;
     renderengine::mock::RenderEngine* mRenderEngine = new renderengine::mock::RenderEngine();
 };
 
-std::unique_ptr<renderengine::threaded::RenderEngineThreaded>
-        RenderEngineThreadedTest::sThreadedRE = nullptr;
-
 TEST_F(RenderEngineThreadedTest, dump) {
     std::string testString = "XYZ";
     EXPECT_CALL(*mRenderEngine, dump(_));
-    sThreadedRE->dump(testString);
+    mThreadedRE->dump(testString);
 }
 
 TEST_F(RenderEngineThreadedTest, primeCache) {
     EXPECT_CALL(*mRenderEngine, primeCache());
-    sThreadedRE->primeCache();
+    mThreadedRE->primeCache();
 }
 
 TEST_F(RenderEngineThreadedTest, genTextures) {
     uint32_t texName;
     EXPECT_CALL(*mRenderEngine, genTextures(1, &texName));
-    sThreadedRE->genTextures(1, &texName);
+    mThreadedRE->genTextures(1, &texName);
 }
 
 TEST_F(RenderEngineThreadedTest, deleteTextures) {
     uint32_t texName;
     EXPECT_CALL(*mRenderEngine, deleteTextures(1, &texName));
-    sThreadedRE->deleteTextures(1, &texName);
+    mThreadedRE->deleteTextures(1, &texName);
 }
 
 TEST_F(RenderEngineThreadedTest, bindExternalBuffer_nullptrBuffer) {
     EXPECT_CALL(*mRenderEngine, bindExternalTextureBuffer(0, Eq(nullptr), Eq(nullptr)))
             .WillOnce(Return(BAD_VALUE));
-    status_t result = sThreadedRE->bindExternalTextureBuffer(0, nullptr, nullptr);
+    status_t result = mThreadedRE->bindExternalTextureBuffer(0, nullptr, nullptr);
     ASSERT_EQ(BAD_VALUE, result);
 }
 
@@ -85,119 +73,119 @@
     sp<GraphicBuffer> buf = new GraphicBuffer();
     EXPECT_CALL(*mRenderEngine, bindExternalTextureBuffer(0, buf, Eq(nullptr)))
             .WillOnce(Return(NO_ERROR));
-    status_t result = sThreadedRE->bindExternalTextureBuffer(0, buf, nullptr);
+    status_t result = mThreadedRE->bindExternalTextureBuffer(0, buf, nullptr);
     ASSERT_EQ(NO_ERROR, result);
 }
 
 TEST_F(RenderEngineThreadedTest, cacheExternalTextureBuffer_nullptr) {
     EXPECT_CALL(*mRenderEngine, cacheExternalTextureBuffer(Eq(nullptr)));
-    sThreadedRE->cacheExternalTextureBuffer(nullptr);
+    mThreadedRE->cacheExternalTextureBuffer(nullptr);
 }
 
 TEST_F(RenderEngineThreadedTest, cacheExternalTextureBuffer_withBuffer) {
     sp<GraphicBuffer> buf = new GraphicBuffer();
     EXPECT_CALL(*mRenderEngine, cacheExternalTextureBuffer(buf));
-    sThreadedRE->cacheExternalTextureBuffer(buf);
+    mThreadedRE->cacheExternalTextureBuffer(buf);
 }
 
 TEST_F(RenderEngineThreadedTest, unbindExternalTextureBuffer) {
     EXPECT_CALL(*mRenderEngine, unbindExternalTextureBuffer(0x0));
-    sThreadedRE->unbindExternalTextureBuffer(0x0);
+    mThreadedRE->unbindExternalTextureBuffer(0x0);
 }
 
 TEST_F(RenderEngineThreadedTest, bindFrameBuffer_returnsBadValue) {
     std::unique_ptr<renderengine::Framebuffer> framebuffer;
     EXPECT_CALL(*mRenderEngine, bindFrameBuffer(framebuffer.get())).WillOnce(Return(BAD_VALUE));
-    status_t result = sThreadedRE->bindFrameBuffer(framebuffer.get());
+    status_t result = mThreadedRE->bindFrameBuffer(framebuffer.get());
     ASSERT_EQ(BAD_VALUE, result);
 }
 
 TEST_F(RenderEngineThreadedTest, bindFrameBuffer_returnsNoError) {
     std::unique_ptr<renderengine::Framebuffer> framebuffer;
     EXPECT_CALL(*mRenderEngine, bindFrameBuffer(framebuffer.get())).WillOnce(Return(NO_ERROR));
-    status_t result = sThreadedRE->bindFrameBuffer(framebuffer.get());
+    status_t result = mThreadedRE->bindFrameBuffer(framebuffer.get());
     ASSERT_EQ(NO_ERROR, result);
 }
 
 TEST_F(RenderEngineThreadedTest, unbindFrameBuffer) {
     std::unique_ptr<renderengine::Framebuffer> framebuffer;
     EXPECT_CALL(*mRenderEngine, unbindFrameBuffer(framebuffer.get()));
-    sThreadedRE->unbindFrameBuffer(framebuffer.get());
+    mThreadedRE->unbindFrameBuffer(framebuffer.get());
 }
 
 TEST_F(RenderEngineThreadedTest, getMaxTextureSize_returns20) {
     size_t size = 20;
     EXPECT_CALL(*mRenderEngine, getMaxTextureSize()).WillOnce(Return(size));
-    size_t result = sThreadedRE->getMaxTextureSize();
+    size_t result = mThreadedRE->getMaxTextureSize();
     ASSERT_EQ(size, result);
 }
 
 TEST_F(RenderEngineThreadedTest, getMaxTextureSize_returns0) {
     size_t size = 0;
     EXPECT_CALL(*mRenderEngine, getMaxTextureSize()).WillOnce(Return(size));
-    size_t result = sThreadedRE->getMaxTextureSize();
+    size_t result = mThreadedRE->getMaxTextureSize();
     ASSERT_EQ(size, result);
 }
 
 TEST_F(RenderEngineThreadedTest, getMaxViewportDims_returns20) {
     size_t dims = 20;
     EXPECT_CALL(*mRenderEngine, getMaxViewportDims()).WillOnce(Return(dims));
-    size_t result = sThreadedRE->getMaxViewportDims();
+    size_t result = mThreadedRE->getMaxViewportDims();
     ASSERT_EQ(dims, result);
 }
 
 TEST_F(RenderEngineThreadedTest, getMaxViewportDims_returns0) {
     size_t dims = 0;
     EXPECT_CALL(*mRenderEngine, getMaxViewportDims()).WillOnce(Return(dims));
-    size_t result = sThreadedRE->getMaxViewportDims();
+    size_t result = mThreadedRE->getMaxViewportDims();
     ASSERT_EQ(dims, result);
 }
 
 TEST_F(RenderEngineThreadedTest, isProtected_returnsFalse) {
     EXPECT_CALL(*mRenderEngine, isProtected()).WillOnce(Return(false));
-    status_t result = sThreadedRE->isProtected();
+    status_t result = mThreadedRE->isProtected();
     ASSERT_EQ(false, result);
 }
 
 TEST_F(RenderEngineThreadedTest, isProtected_returnsTrue) {
     EXPECT_CALL(*mRenderEngine, isProtected()).WillOnce(Return(true));
-    size_t result = sThreadedRE->isProtected();
+    size_t result = mThreadedRE->isProtected();
     ASSERT_EQ(true, result);
 }
 
 TEST_F(RenderEngineThreadedTest, supportsProtectedContent_returnsFalse) {
     EXPECT_CALL(*mRenderEngine, supportsProtectedContent()).WillOnce(Return(false));
-    status_t result = sThreadedRE->supportsProtectedContent();
+    status_t result = mThreadedRE->supportsProtectedContent();
     ASSERT_EQ(false, result);
 }
 
 TEST_F(RenderEngineThreadedTest, supportsProtectedContent_returnsTrue) {
     EXPECT_CALL(*mRenderEngine, supportsProtectedContent()).WillOnce(Return(true));
-    status_t result = sThreadedRE->supportsProtectedContent();
+    status_t result = mThreadedRE->supportsProtectedContent();
     ASSERT_EQ(true, result);
 }
 
 TEST_F(RenderEngineThreadedTest, useProtectedContext_returnsFalse) {
     EXPECT_CALL(*mRenderEngine, useProtectedContext(false)).WillOnce(Return(false));
-    status_t result = sThreadedRE->useProtectedContext(false);
+    status_t result = mThreadedRE->useProtectedContext(false);
     ASSERT_EQ(false, result);
 }
 
 TEST_F(RenderEngineThreadedTest, useProtectedContext_returnsTrue) {
     EXPECT_CALL(*mRenderEngine, useProtectedContext(false)).WillOnce(Return(true));
-    status_t result = sThreadedRE->useProtectedContext(false);
+    status_t result = mThreadedRE->useProtectedContext(false);
     ASSERT_EQ(true, result);
 }
 
 TEST_F(RenderEngineThreadedTest, cleanupPostRender_returnsFalse) {
     EXPECT_CALL(*mRenderEngine, cleanupPostRender()).WillOnce(Return(false));
-    status_t result = sThreadedRE->cleanupPostRender();
+    status_t result = mThreadedRE->cleanupPostRender();
     ASSERT_EQ(false, result);
 }
 
 TEST_F(RenderEngineThreadedTest, cleanupPostRender_returnsTrue) {
     EXPECT_CALL(*mRenderEngine, cleanupPostRender()).WillOnce(Return(true));
-    status_t result = sThreadedRE->cleanupPostRender();
+    status_t result = mThreadedRE->cleanupPostRender();
     ASSERT_EQ(true, result);
 }
 
@@ -214,7 +202,7 @@
                          const sp<GraphicBuffer>&, const bool, base::unique_fd&&,
                          base::unique_fd*) -> status_t { return NO_ERROR; });
 
-    status_t result = sThreadedRE->drawLayers(settings, layers, buffer, false,
+    status_t result = mThreadedRE->drawLayers(settings, layers, buffer, false,
                                               std::move(bufferFence), &drawFence);
     ASSERT_EQ(NO_ERROR, result);
 }
diff --git a/libs/renderengine/threaded/RenderEngineThreaded.cpp b/libs/renderengine/threaded/RenderEngineThreaded.cpp
index a883ad3..ad61718 100644
--- a/libs/renderengine/threaded/RenderEngineThreaded.cpp
+++ b/libs/renderengine/threaded/RenderEngineThreaded.cpp
@@ -23,6 +23,7 @@
 #include <future>
 
 #include <android-base/stringprintf.h>
+#include <private/gui/SyncFeatures.h>
 #include <utils/Trace.h>
 
 #include "gl/GLESRenderEngine.h"
@@ -33,36 +34,15 @@
 namespace renderengine {
 namespace threaded {
 
-std::unique_ptr<RenderEngineThreaded> RenderEngineThreaded::create(
-        const RenderEngineCreationArgs& args) {
-    return std::make_unique<RenderEngineThreaded>(args);
+std::unique_ptr<RenderEngineThreaded> RenderEngineThreaded::create(CreateInstanceFactory factory) {
+    return std::make_unique<RenderEngineThreaded>(std::move(factory));
 }
 
-void RenderEngineThreaded::setRenderEngine(
-        std::unique_ptr<renderengine::RenderEngine> renderEngine) {
-    ATRACE_CALL();
-    // In order to ensure this is a thread safe call, it also needs to be put on a stack.
-    std::promise<void> resultPromise;
-    std::future<void> resultFuture = resultPromise.get_future();
-    {
-        std::lock_guard lock(mThreadMutex);
-        mFunctionCalls.push(
-                [this, &resultPromise, &renderEngine](renderengine::RenderEngine& /*instance*/) {
-                    ATRACE_NAME("REThreaded::setRenderEngine");
-                    mRenderEngine = std::move(renderEngine);
-                    resultPromise.set_value();
-                });
-    }
-    mCondition.notify_one();
-    resultFuture.wait();
-}
-
-RenderEngineThreaded::RenderEngineThreaded(const RenderEngineCreationArgs& args)
-      : renderengine::impl::RenderEngine(args) {
+RenderEngineThreaded::RenderEngineThreaded(CreateInstanceFactory factory) {
     ATRACE_CALL();
 
     std::lock_guard lockThread(mThreadMutex);
-    mThread = std::thread(&RenderEngineThreaded::threadMain, this, args);
+    mThread = std::thread(&RenderEngineThreaded::threadMain, this, factory);
 }
 
 RenderEngineThreaded::~RenderEngineThreaded() {
@@ -78,8 +58,7 @@
 }
 
 // NO_THREAD_SAFETY_ANALYSIS is because std::unique_lock presently lacks thread safety annotations.
-void RenderEngineThreaded::threadMain(const RenderEngineCreationArgs& args)
-        NO_THREAD_SAFETY_ANALYSIS {
+void RenderEngineThreaded::threadMain(CreateInstanceFactory factory) NO_THREAD_SAFETY_ANALYSIS {
     ATRACE_CALL();
 
     struct sched_param param = {0};
@@ -88,7 +67,7 @@
         ALOGE("Couldn't set SCHED_FIFO");
     }
 
-    mRenderEngine = renderengine::gl::GLESRenderEngine::create(args);
+    mRenderEngine = factory();
 
     std::unique_lock<std::mutex> lock(mThreadMutex);
     pthread_setname_np(pthread_self(), mThreadName);
@@ -137,6 +116,36 @@
     result.assign(resultFuture.get());
 }
 
+bool RenderEngineThreaded::useNativeFenceSync() const {
+    std::promise<bool> resultPromise;
+    std::future<bool> resultFuture = resultPromise.get_future();
+    {
+        std::lock_guard lock(mThreadMutex);
+        mFunctionCalls.push([&resultPromise](renderengine::RenderEngine& /*instance*/) {
+            ATRACE_NAME("REThreaded::useNativeFenceSync");
+            bool returnValue = SyncFeatures::getInstance().useNativeFenceSync();
+            resultPromise.set_value(returnValue);
+        });
+    }
+    mCondition.notify_one();
+    return resultFuture.get();
+}
+
+bool RenderEngineThreaded::useWaitSync() const {
+    std::promise<bool> resultPromise;
+    std::future<bool> resultFuture = resultPromise.get_future();
+    {
+        std::lock_guard lock(mThreadMutex);
+        mFunctionCalls.push([&resultPromise](renderengine::RenderEngine& /*instance*/) {
+            ATRACE_NAME("REThreaded::useWaitSync");
+            bool returnValue = SyncFeatures::getInstance().useWaitSync();
+            resultPromise.set_value(returnValue);
+        });
+    }
+    mCondition.notify_one();
+    return resultFuture.get();
+}
+
 void RenderEngineThreaded::genTextures(size_t count, uint32_t* names) {
     std::promise<void> resultPromise;
     std::future<void> resultFuture = resultPromise.get_future();
diff --git a/libs/renderengine/threaded/RenderEngineThreaded.h b/libs/renderengine/threaded/RenderEngineThreaded.h
index 8e4431e..ec18e1f 100644
--- a/libs/renderengine/threaded/RenderEngineThreaded.h
+++ b/libs/renderengine/threaded/RenderEngineThreaded.h
@@ -28,21 +28,25 @@
 namespace renderengine {
 namespace threaded {
 
+using CreateInstanceFactory = std::function<std::unique_ptr<renderengine::RenderEngine>()>;
+
 /**
  * This class extends a basic RenderEngine class. It contains a thread. Each time a function of
  * this class is called, we create a lambda function that is put on a queue. The main thread then
  * executes the functions in order.
  */
-class RenderEngineThreaded : public impl::RenderEngine {
+class RenderEngineThreaded : public RenderEngine {
 public:
-    static std::unique_ptr<RenderEngineThreaded> create(const RenderEngineCreationArgs& args);
+    static std::unique_ptr<RenderEngineThreaded> create(CreateInstanceFactory factory);
 
-    RenderEngineThreaded(const RenderEngineCreationArgs& args);
+    RenderEngineThreaded(CreateInstanceFactory factory);
     ~RenderEngineThreaded() override;
     void primeCache() const override;
 
     void dump(std::string& result) override;
 
+    bool useNativeFenceSync() const override;
+    bool useWaitSync() const override;
     void genTextures(size_t count, uint32_t* names) override;
     void deleteTextures(size_t count, uint32_t const* names) override;
     void bindExternalTextureImage(uint32_t texName, const Image& image) override;
@@ -64,13 +68,12 @@
                         const std::vector<const LayerSettings*>& layers,
                         const sp<GraphicBuffer>& buffer, const bool useFramebufferCache,
                         base::unique_fd&& bufferFence, base::unique_fd* drawFence) override;
-    void setRenderEngine(std::unique_ptr<renderengine::RenderEngine>);
 
 protected:
     Framebuffer* getFramebufferForDrawing() override;
 
 private:
-    void threadMain(const RenderEngineCreationArgs& args);
+    void threadMain(CreateInstanceFactory factory);
 
     /* ------------------------------------------------------------------------
      * Threading
diff --git a/services/surfaceflinger/BufferLayerConsumer.cpp b/services/surfaceflinger/BufferLayerConsumer.cpp
index 648d129..8722952 100644
--- a/services/surfaceflinger/BufferLayerConsumer.cpp
+++ b/services/surfaceflinger/BufferLayerConsumer.cpp
@@ -452,6 +452,13 @@
 }
 
 void BufferLayerConsumer::onDisconnect() {
+    Mutex::Autolock lock(mMutex);
+
+    if (mAbandoned) {
+        // Nothing to do if we're already abandoned.
+        return;
+    }
+
     mLayer->onDisconnect();
 }
 
@@ -486,6 +493,13 @@
 
 void BufferLayerConsumer::addAndGetFrameTimestamps(const NewFrameEventsEntry* newTimestamps,
                                                    FrameEventHistoryDelta* outDelta) {
+    Mutex::Autolock lock(mMutex);
+
+    if (mAbandoned) {
+        // Nothing to do if we're already abandoned.
+        return;
+    }
+
     mLayer->addAndGetFrameTimestamps(newTimestamps, outDelta);
 }
 
diff --git a/services/surfaceflinger/BufferLayerConsumer.h b/services/surfaceflinger/BufferLayerConsumer.h
index c71a1d9..5e3044f 100644
--- a/services/surfaceflinger/BufferLayerConsumer.h
+++ b/services/surfaceflinger/BufferLayerConsumer.h
@@ -331,8 +331,8 @@
     // construction time.
     const uint32_t mTexName;
 
-    // The layer for this BufferLayerConsumer
-    Layer* mLayer;
+    // The layer for this BufferLayerConsumer. Always check mAbandoned before accessing.
+    Layer* mLayer GUARDED_BY(mMutex);
 
     wp<ContentsChangedListener> mContentsChangedListener;
 
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/RenderSurface.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/RenderSurface.h
index 5ce2fdc..f680460 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/RenderSurface.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/RenderSurface.h
@@ -63,6 +63,12 @@
     // Sets the dataspace used for rendering the surface
     virtual void setBufferDataspace(ui::Dataspace) = 0;
 
+    // Sets the pixel format used for rendering the surface.
+    // Changing the pixel format of the buffer will result in buffer
+    // reallocation as well as some reconfiguration of the graphics context,
+    // which are both expensive operations.
+    virtual void setBufferPixelFormat(ui::PixelFormat) = 0;
+
     // Configures the protected rendering on the surface
     virtual void setProtected(bool useProtected) = 0;
 
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h
index 9ca7d2f..7a4f738 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h
@@ -70,11 +70,13 @@
     using ChangedTypes = android::HWComposer::DeviceRequestedChanges::ChangedTypes;
     using DisplayRequests = android::HWComposer::DeviceRequestedChanges::DisplayRequests;
     using LayerRequests = android::HWComposer::DeviceRequestedChanges::LayerRequests;
+    using ClientTargetProperty = android::HWComposer::DeviceRequestedChanges::ClientTargetProperty;
     virtual bool anyLayersRequireClientComposition() const;
     virtual bool allLayersRequireClientComposition() const;
     virtual void applyChangedTypesToLayers(const ChangedTypes&);
     virtual void applyDisplayRequests(const DisplayRequests&);
     virtual void applyLayerRequestsToLayers(const LayerRequests&);
+    virtual void applyClientTargetRequests(const ClientTargetProperty&);
 
     // Internal
     virtual void setConfiguration(const compositionengine::DisplayCreationArgs&);
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/RenderSurface.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/RenderSurface.h
index 692d78d..5127a6f 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/RenderSurface.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/RenderSurface.h
@@ -49,6 +49,7 @@
 
     const sp<Fence>& getClientTargetAcquireFence() const override;
     void setBufferDataspace(ui::Dataspace) override;
+    void setBufferPixelFormat(ui::PixelFormat) override;
     void setDisplaySize(const ui::Size&) override;
     void setProtected(bool useProtected) override;
     status_t beginFrame(bool mustRecompose) override;
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/RenderSurface.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/RenderSurface.h
index ed4d492..a0cae6f 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/RenderSurface.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/RenderSurface.h
@@ -36,6 +36,7 @@
     MOCK_METHOD1(setDisplaySize, void(const ui::Size&));
     MOCK_METHOD1(setProtected, void(bool));
     MOCK_METHOD1(setBufferDataspace, void(ui::Dataspace));
+    MOCK_METHOD1(setBufferPixelFormat, void(ui::PixelFormat));
     MOCK_METHOD1(beginFrame, status_t(bool mustRecompose));
     MOCK_METHOD2(prepareFrame, void(bool, bool));
     MOCK_METHOD1(dequeueBuffer, sp<GraphicBuffer>(base::unique_fd*));
diff --git a/services/surfaceflinger/CompositionEngine/src/Display.cpp b/services/surfaceflinger/CompositionEngine/src/Display.cpp
index ab26939..d201104 100644
--- a/services/surfaceflinger/CompositionEngine/src/Display.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/Display.cpp
@@ -259,6 +259,7 @@
         applyChangedTypesToLayers(changes->changedTypes);
         applyDisplayRequests(changes->displayRequests);
         applyLayerRequestsToLayers(changes->layerRequests);
+        applyClientTargetRequests(changes->clientTargetProperty);
     }
 
     // Determine what type of composition we are doing from the final state
@@ -326,6 +327,16 @@
     }
 }
 
+void Display::applyClientTargetRequests(const ClientTargetProperty& clientTargetProperty) {
+    if (clientTargetProperty.dataspace == ui::Dataspace::UNKNOWN) {
+        return;
+    }
+    auto outputState = editState();
+    outputState.dataspace = clientTargetProperty.dataspace;
+    getRenderSurface()->setBufferDataspace(clientTargetProperty.dataspace);
+    getRenderSurface()->setBufferPixelFormat(clientTargetProperty.pixelFormat);
+}
+
 compositionengine::Output::FrameFences Display::presentAndGetFrameFences() {
     auto result = impl::Output::presentAndGetFrameFences();
 
diff --git a/services/surfaceflinger/CompositionEngine/src/RenderSurface.cpp b/services/surfaceflinger/CompositionEngine/src/RenderSurface.cpp
index 4084653..2773fd3 100644
--- a/services/surfaceflinger/CompositionEngine/src/RenderSurface.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/RenderSurface.cpp
@@ -104,6 +104,10 @@
                                          static_cast<android_dataspace>(dataspace));
 }
 
+void RenderSurface::setBufferPixelFormat(ui::PixelFormat pixelFormat) {
+    native_window_set_buffers_format(mNativeWindow.get(), static_cast<int32_t>(pixelFormat));
+}
+
 void RenderSurface::setProtected(bool useProtected) {
     uint64_t usageFlags = GRALLOC_USAGE_HW_RENDER;
     if (useProtected) {
diff --git a/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp b/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp
index 62977a4..09f37fb 100644
--- a/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp
@@ -654,6 +654,7 @@
             {{nullptr, hal::Composition::CLIENT}},
             hal::DisplayRequest::FLIP_CLIENT_TARGET,
             {{nullptr, hal::LayerRequest::CLEAR_CLIENT_TARGET}},
+            {hal::PixelFormat::RGBA_8888, hal::Dataspace::UNKNOWN},
     };
 
     // Since two calls are made to anyLayersRequireClientComposition with different return
diff --git a/services/surfaceflinger/DisplayHardware/ComposerHal.cpp b/services/surfaceflinger/DisplayHardware/ComposerHal.cpp
index 97eeea2..dbdffec 100644
--- a/services/surfaceflinger/DisplayHardware/ComposerHal.cpp
+++ b/services/surfaceflinger/DisplayHardware/ComposerHal.cpp
@@ -1354,6 +1354,12 @@
     return error;
 }
 
+Error Composer::getClientTargetProperty(
+        Display display, IComposerClient::ClientTargetProperty* outClientTargetProperty) {
+    mReader.takeClientTargetProperty(display, outClientTargetProperty);
+    return Error::NONE;
+}
+
 CommandReader::~CommandReader()
 {
     resetData();
@@ -1662,10 +1668,22 @@
     *state = data.presentOrValidateState;
 }
 
+void CommandReader::takeClientTargetProperty(
+        Display display, IComposerClient::ClientTargetProperty* outClientTargetProperty) {
+    auto found = mReturnData.find(display);
+
+    // If not found, return the default values.
+    if (found == mReturnData.end()) {
+        outClientTargetProperty->pixelFormat = PixelFormat::RGBA_8888;
+        outClientTargetProperty->dataspace = Dataspace::UNKNOWN;
+    }
+
+    ReturnData& data = found->second;
+    *outClientTargetProperty = data.clientTargetProperty;
+}
+
 } // namespace impl
-
 } // namespace Hwc2
-
 } // namespace android
 
 // TODO(b/129481165): remove the #pragma below and fix conversion issues
diff --git a/services/surfaceflinger/DisplayHardware/ComposerHal.h b/services/surfaceflinger/DisplayHardware/ComposerHal.h
index aa43f09..00ef782 100644
--- a/services/surfaceflinger/DisplayHardware/ComposerHal.h
+++ b/services/surfaceflinger/DisplayHardware/ComposerHal.h
@@ -240,6 +240,8 @@
                                                 const std::vector<uint8_t>& value) = 0;
     virtual V2_4::Error getLayerGenericMetadataKeys(
             std::vector<IComposerClient::LayerGenericMetadataKey>* outKeys) = 0;
+    virtual Error getClientTargetProperty(
+            Display display, IComposerClient::ClientTargetProperty* outClientTargetProperty) = 0;
 };
 
 namespace impl {
@@ -282,6 +284,10 @@
     // Get what stage succeeded during PresentOrValidate: Present or Validate
     void takePresentOrValidateStage(Display display, uint32_t * state);
 
+    // Get the client target properties requested by hardware composer.
+    void takeClientTargetProperty(Display display,
+                                  IComposerClient::ClientTargetProperty* outClientTargetProperty);
+
 private:
     void resetData();
 
@@ -479,6 +485,9 @@
                                         bool mandatory, const std::vector<uint8_t>& value) override;
     V2_4::Error getLayerGenericMetadataKeys(
             std::vector<IComposerClient::LayerGenericMetadataKey>* outKeys) override;
+    Error getClientTargetProperty(
+            Display display,
+            IComposerClient::ClientTargetProperty* outClientTargetProperty) override;
 
 private:
 #if defined(USE_VR_COMPOSER) && USE_VR_COMPOSER
diff --git a/services/surfaceflinger/DisplayHardware/HWC2.cpp b/services/surfaceflinger/DisplayHardware/HWC2.cpp
index fb82033..af76b81 100644
--- a/services/surfaceflinger/DisplayHardware/HWC2.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWC2.cpp
@@ -668,6 +668,11 @@
     return static_cast<Error>(intError);
 }
 
+Error Display::getClientTargetProperty(ClientTargetProperty* outClientTargetProperty) {
+    const auto error = mComposer.getClientTargetProperty(mId, outClientTargetProperty);
+    return static_cast<Error>(error);
+}
+
 // For use by Device
 
 void Display::setConnected(bool connected) {
diff --git a/services/surfaceflinger/DisplayHardware/HWC2.h b/services/surfaceflinger/DisplayHardware/HWC2.h
index f4c7fdd..6819ff4 100644
--- a/services/surfaceflinger/DisplayHardware/HWC2.h
+++ b/services/surfaceflinger/DisplayHardware/HWC2.h
@@ -234,6 +234,8 @@
     [[clang::warn_unused_result]] virtual hal::Error getSupportedContentTypes(
             std::vector<hal::ContentType>*) const = 0;
     [[clang::warn_unused_result]] virtual hal::Error setContentType(hal::ContentType) = 0;
+    [[clang::warn_unused_result]] virtual hal::Error getClientTargetProperty(
+            hal::ClientTargetProperty* outClientTargetProperty) = 0;
 };
 
 namespace impl {
@@ -305,6 +307,8 @@
     hal::Error getSupportedContentTypes(
             std::vector<hal::ContentType>* outSupportedContentTypes) const override;
     hal::Error setContentType(hal::ContentType) override;
+    hal::Error getClientTargetProperty(hal::ClientTargetProperty* outClientTargetProperty) override;
+
     // Other Display methods
     hal::HWDisplayId getId() const override { return mId; }
     bool isConnected() const override { return mIsConnected; }
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
index 038cec4..7a2f0f3 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
@@ -541,9 +541,12 @@
     error = hwcDisplay->getRequests(&displayRequests, &layerRequests);
     RETURN_IF_HWC_ERROR_FOR("getRequests", error, displayId, BAD_INDEX);
 
-    outChanges->emplace(DeviceRequestedChanges{std::move(changedTypes), std::move(displayRequests),
-                                               std::move(layerRequests)});
+    DeviceRequestedChanges::ClientTargetProperty clientTargetProperty;
+    error = hwcDisplay->getClientTargetProperty(&clientTargetProperty);
 
+    outChanges->emplace(DeviceRequestedChanges{std::move(changedTypes), std::move(displayRequests),
+                                               std::move(layerRequests),
+                                               std::move(clientTargetProperty)});
     error = hwcDisplay->acceptChanges();
     RETURN_IF_HWC_ERROR_FOR("acceptChanges", error, displayId, BAD_INDEX);
 
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.h b/services/surfaceflinger/DisplayHardware/HWComposer.h
index b7e9f3a..c355ebd 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.h
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.h
@@ -66,6 +66,18 @@
 
 class HWComposer {
 public:
+    struct DeviceRequestedChanges {
+        using ChangedTypes = std::unordered_map<HWC2::Layer*, hal::Composition>;
+        using ClientTargetProperty = hal::ClientTargetProperty;
+        using DisplayRequests = hal::DisplayRequest;
+        using LayerRequests = std::unordered_map<HWC2::Layer*, hal::LayerRequest>;
+
+        ChangedTypes changedTypes;
+        DisplayRequests displayRequests;
+        LayerRequests layerRequests;
+        ClientTargetProperty clientTargetProperty;
+    };
+
     virtual ~HWComposer();
 
     virtual void setConfiguration(HWC2::ComposerCallback* callback, int32_t sequenceId) = 0;
@@ -88,16 +100,6 @@
     // Destroy a previously created layer
     virtual void destroyLayer(DisplayId displayId, HWC2::Layer* layer) = 0;
 
-    struct DeviceRequestedChanges {
-        using ChangedTypes = std::unordered_map<HWC2::Layer*, hal::Composition>;
-        using DisplayRequests = hal::DisplayRequest;
-        using LayerRequests = std::unordered_map<HWC2::Layer*, hal::LayerRequest>;
-
-        ChangedTypes changedTypes;
-        DisplayRequests displayRequests;
-        LayerRequests layerRequests;
-    };
-
     // Gets any required composition change requests from the HWC device.
     //
     // Note that frameUsesClientComposition must be set correctly based on
diff --git a/services/surfaceflinger/DisplayHardware/Hal.h b/services/surfaceflinger/DisplayHardware/Hal.h
index 66ee425..bb2888e 100644
--- a/services/surfaceflinger/DisplayHardware/Hal.h
+++ b/services/surfaceflinger/DisplayHardware/Hal.h
@@ -53,6 +53,7 @@
 using Connection = IComposerCallback::Connection;
 using ContentType = IComposerClient::ContentType;
 using Capability = IComposer::Capability;
+using ClientTargetProperty = IComposerClient::ClientTargetProperty;
 using DisplayCapability = IComposerClient::DisplayCapability;
 using DisplayRequest = IComposerClient::DisplayRequest;
 using DisplayType = IComposerClient::DisplayType;
diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
index 4a4f9c8..e181c12 100644
--- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
+++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
@@ -128,15 +128,24 @@
         }
     }
 
+    const bool hasExplicitVoteLayers =
+            explicitDefaultVoteLayers > 0 || explicitExactOrMultipleVoteLayers > 0;
+
     // Consider the touch event if there are no Explicit* layers. Otherwise wait until after we've
     // selected a refresh rate to see if we should apply touch boost.
-    if (touchActive && explicitDefaultVoteLayers == 0 && explicitExactOrMultipleVoteLayers == 0) {
+    if (touchActive && !hasExplicitVoteLayers) {
         ALOGV("TouchBoost - choose %s", getMaxRefreshRateByPolicyLocked().getName().c_str());
         if (touchConsidered) *touchConsidered = true;
         return getMaxRefreshRateByPolicyLocked();
     }
 
-    if (!touchActive && idle) {
+    // If the primary range consists of a single refresh rate then we can only
+    // move out the of range if layers explicitly request a different refresh
+    // rate.
+    const Policy* policy = getCurrentPolicyLocked();
+    const bool primaryRangeIsSingleRate = policy->primaryRange.min == policy->primaryRange.max;
+
+    if (!touchActive && idle && !(primaryRangeIsSingleRate && hasExplicitVoteLayers)) {
         return getMinRefreshRateByPolicyLocked();
     }
 
@@ -150,8 +159,6 @@
         return getMinRefreshRateByPolicyLocked();
     }
 
-    const Policy* policy = getCurrentPolicyLocked();
-
     // Find the best refresh rate based on score
     std::vector<std::pair<const RefreshRate*, float>> scores;
     scores.reserve(mAppRequestRefreshRates.size());
@@ -171,7 +178,8 @@
         for (auto i = 0u; i < scores.size(); i++) {
             bool inPrimaryRange =
                     scores[i].first->inPolicy(policy->primaryRange.min, policy->primaryRange.max);
-            if (!inPrimaryRange && layer.vote != LayerVoteType::ExplicitDefault &&
+            if ((primaryRangeIsSingleRate || !inPrimaryRange) &&
+                layer.vote != LayerVoteType::ExplicitDefault &&
                 layer.vote != LayerVoteType::ExplicitExactOrMultiple) {
                 // Only layers with explicit frame rate settings are allowed to score refresh rates
                 // outside the primary range.
@@ -263,11 +271,23 @@
             ? getBestRefreshRate(scores.rbegin(), scores.rend())
             : getBestRefreshRate(scores.begin(), scores.end());
 
+    if (primaryRangeIsSingleRate) {
+        // If we never scored any layers, then choose the rate from the primary
+        // range instead of picking a random score from the app range.
+        if (std::all_of(scores.begin(), scores.end(),
+                        [](std::pair<const RefreshRate*, float> p) { return p.second == 0; })) {
+            return getMaxRefreshRateByPolicyLocked();
+        } else {
+            return *bestRefreshRate;
+        }
+    }
+
     // Consider the touch event if there are no ExplicitDefault layers. ExplicitDefault are mostly
     // interactive (as opposed to ExplicitExactOrMultiple) and therefore if those posted an explicit
     // vote we should not change it if we get a touch event. Only apply touch boost if it will
     // actually increase the refresh rate over the normal selection.
     const RefreshRate& touchRefreshRate = getMaxRefreshRateByPolicyLocked();
+
     if (touchActive && explicitDefaultVoteLayers == 0 &&
         bestRefreshRate->fps < touchRefreshRate.fps) {
         if (touchConsidered) *touchConsidered = true;
diff --git a/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp b/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp
index 692f71f..c919e93 100644
--- a/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp
+++ b/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp
@@ -1205,6 +1205,121 @@
     }
 }
 
+TEST_F(RefreshRateConfigsTest,
+       getBestRefreshRate_withDisplayManagerRequestingSingleRate_ignoresTouchFlag) {
+    auto refreshRateConfigs =
+            std::make_unique<RefreshRateConfigs>(m60_90Device,
+                                                 /*currentConfigId=*/HWC_CONFIG_ID_90);
+
+    ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy(
+                      {HWC_CONFIG_ID_90, {90.f, 90.f}, {60.f, 90.f}}),
+              0);
+
+    auto layers = std::vector<LayerRequirement>{LayerRequirement{.weight = 1.0f}};
+    auto& lr = layers[0];
+
+    bool touchConsidered = false;
+    lr.vote = LayerVoteType::ExplicitExactOrMultiple;
+    lr.desiredRefreshRate = 60.0f;
+    lr.name = "60Hz ExplicitExactOrMultiple";
+    EXPECT_EQ(mExpected60Config,
+              refreshRateConfigs->getBestRefreshRate(layers, /*touchActive*/ true, /*idle*/ false,
+                                                     &touchConsidered));
+    EXPECT_EQ(false, touchConsidered);
+
+    lr.vote = LayerVoteType::ExplicitDefault;
+    lr.desiredRefreshRate = 60.0f;
+    lr.name = "60Hz ExplicitDefault";
+    EXPECT_EQ(mExpected60Config,
+              refreshRateConfigs->getBestRefreshRate(layers, /*touchActive*/ true, /*idle*/ false,
+                                                     &touchConsidered));
+    EXPECT_EQ(false, touchConsidered);
+}
+
+TEST_F(RefreshRateConfigsTest,
+       getBestRefreshRate_withDisplayManagerRequestingSingleRate_ignoresIdleFlag) {
+    auto refreshRateConfigs =
+            std::make_unique<RefreshRateConfigs>(m60_90Device,
+                                                 /*currentConfigId=*/HWC_CONFIG_ID_60);
+
+    ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy(
+                      {HWC_CONFIG_ID_60, {60.f, 60.f}, {60.f, 90.f}}),
+              0);
+
+    auto layers = std::vector<LayerRequirement>{LayerRequirement{.weight = 1.0f}};
+    auto& lr = layers[0];
+
+    bool touchConsidered = false;
+    lr.vote = LayerVoteType::ExplicitExactOrMultiple;
+    lr.desiredRefreshRate = 90.0f;
+    lr.name = "90Hz ExplicitExactOrMultiple";
+    EXPECT_EQ(mExpected90Config,
+              refreshRateConfigs->getBestRefreshRate(layers, /*touchActive*/ false, /*idle*/ true,
+                                                     &touchConsidered));
+
+    lr.vote = LayerVoteType::ExplicitDefault;
+    lr.desiredRefreshRate = 90.0f;
+    lr.name = "90Hz ExplicitDefault";
+    EXPECT_EQ(mExpected90Config,
+              refreshRateConfigs->getBestRefreshRate(layers, /*touchActive*/ false, /*idle*/ true,
+                                                     &touchConsidered));
+}
+
+TEST_F(RefreshRateConfigsTest,
+       getBestRefreshRate_withDisplayManagerRequestingSingleRate_onlySwitchesRatesForExplicitLayers) {
+    auto refreshRateConfigs =
+            std::make_unique<RefreshRateConfigs>(m60_90Device,
+                                                 /*currentConfigId=*/HWC_CONFIG_ID_90);
+
+    ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy(
+                      {HWC_CONFIG_ID_90, {90.f, 90.f}, {60.f, 90.f}}),
+              0);
+
+    bool touchConsidered = false;
+    EXPECT_EQ(mExpected90Config,
+              refreshRateConfigs->getBestRefreshRate({}, /*touchActive*/ false, /*idle*/ false,
+                                                     &touchConsidered));
+    EXPECT_EQ(false, touchConsidered);
+
+    auto layers = std::vector<LayerRequirement>{LayerRequirement{.weight = 1.0f}};
+    auto& lr = layers[0];
+
+    lr.vote = LayerVoteType::ExplicitExactOrMultiple;
+    lr.desiredRefreshRate = 60.0f;
+    lr.name = "60Hz ExplicitExactOrMultiple";
+    EXPECT_EQ(mExpected60Config,
+              refreshRateConfigs->getBestRefreshRate(layers, /*touchActive*/ false, /*idle*/ false,
+                                                     &touchConsidered));
+
+    lr.vote = LayerVoteType::ExplicitDefault;
+    lr.desiredRefreshRate = 60.0f;
+    lr.name = "60Hz ExplicitDefault";
+    EXPECT_EQ(mExpected60Config,
+              refreshRateConfigs->getBestRefreshRate(layers, /*touchActive*/ false, /*idle*/ false,
+                                                     &touchConsidered));
+
+    lr.vote = LayerVoteType::Heuristic;
+    lr.desiredRefreshRate = 60.0f;
+    lr.name = "60Hz Heuristic";
+    EXPECT_EQ(mExpected90Config,
+              refreshRateConfigs->getBestRefreshRate(layers, /*touchActive*/ false, /*idle*/ false,
+                                                     &touchConsidered));
+
+    lr.vote = LayerVoteType::Max;
+    lr.desiredRefreshRate = 60.0f;
+    lr.name = "60Hz Max";
+    EXPECT_EQ(mExpected90Config,
+              refreshRateConfigs->getBestRefreshRate(layers, /*touchActive*/ false, /*idle*/ false,
+                                                     &touchConsidered));
+
+    lr.vote = LayerVoteType::Min;
+    lr.desiredRefreshRate = 60.0f;
+    lr.name = "60Hz Min";
+    EXPECT_EQ(mExpected90Config,
+              refreshRateConfigs->getBestRefreshRate(layers, /*touchActive*/ false, /*idle*/ false,
+                                                     &touchConsidered));
+}
+
 TEST_F(RefreshRateConfigsTest, groupSwitching) {
     auto refreshRateConfigs =
             std::make_unique<RefreshRateConfigs>(m60_90DeviceWithDifferentGroups,
@@ -1234,7 +1349,7 @@
 
 TEST_F(RefreshRateConfigsTest, primaryVsAppRequestPolicy) {
     auto refreshRateConfigs =
-            std::make_unique<RefreshRateConfigs>(m60_90Device,
+            std::make_unique<RefreshRateConfigs>(m30_60_90Device,
                                                  /*currentConfigId=*/HWC_CONFIG_ID_60);
 
     auto layers = std::vector<LayerRequirement>{LayerRequirement{.weight = 1.0f}};
@@ -1253,7 +1368,7 @@
     };
 
     ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy(
-                      {HWC_CONFIG_ID_60, {60.f, 60.f}, {60.f, 90.f}}),
+                      {HWC_CONFIG_ID_60, {30.f, 60.f}, {30.f, 90.f}}),
               0);
     bool touchConsidered;
     EXPECT_EQ(HWC_CONFIG_ID_60,
@@ -1262,7 +1377,7 @@
                                            &touchConsidered)
                       .getConfigId());
     EXPECT_EQ(HWC_CONFIG_ID_60, getFrameRate(LayerVoteType::NoVote, 90.f));
-    EXPECT_EQ(HWC_CONFIG_ID_60, getFrameRate(LayerVoteType::Min, 90.f));
+    EXPECT_EQ(HWC_CONFIG_ID_30, getFrameRate(LayerVoteType::Min, 90.f));
     EXPECT_EQ(HWC_CONFIG_ID_60, getFrameRate(LayerVoteType::Max, 90.f));
     EXPECT_EQ(HWC_CONFIG_ID_60, getFrameRate(LayerVoteType::Heuristic, 90.f));
     EXPECT_EQ(HWC_CONFIG_ID_90, getFrameRate(LayerVoteType::ExplicitDefault, 90.f));
diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h
index 2a31078..c2c5072 100644
--- a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h
+++ b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h
@@ -140,6 +140,7 @@
                              const std::vector<uint8_t>&));
     MOCK_METHOD1(getLayerGenericMetadataKeys,
                  V2_4::Error(std::vector<IComposerClient::LayerGenericMetadataKey>*));
+    MOCK_METHOD2(getClientTargetProperty, Error(Display, IComposerClient::ClientTargetProperty*));
 };
 
 } // namespace mock
diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockDisplay.h b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockDisplay.h
index dade9fc..fe99e77 100644
--- a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockDisplay.h
+++ b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockDisplay.h
@@ -93,6 +93,7 @@
     MOCK_METHOD1(setAutoLowLatencyMode, hal::Error(bool on));
     MOCK_CONST_METHOD1(getSupportedContentTypes, hal::Error(std::vector<hal::ContentType>*));
     MOCK_METHOD1(setContentType, hal::Error(hal::ContentType));
+    MOCK_METHOD1(getClientTargetProperty, hal::Error(hal::ClientTargetProperty*));
     MOCK_CONST_METHOD1(getConnectionType, hal::Error(android::DisplayConnectionType*));
     MOCK_CONST_METHOD0(isVsyncPeriodSwitchSupported, bool());
 };