Merge "dumpstate: add fingerprint HAL dump" into rvc-dev
diff --git a/data/etc/android.hardware.device_unique_attestation.xml b/data/etc/android.hardware.device_unique_attestation.xml
new file mode 100644
index 0000000..309be7a
--- /dev/null
+++ b/data/etc/android.hardware.device_unique_attestation.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2020 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<!-- Feature for devices with Keymaster that support unique attestation. -->
+<permissions>
+    <feature name="android.hardware.device_unique_attestation" />
+</permissions>
diff --git a/include/ui/FatVector.h b/include/ui/FatVector.h
deleted file mode 120000
index c2047c0..0000000
--- a/include/ui/FatVector.h
+++ /dev/null
@@ -1 +0,0 @@
-../../libs/ui/include/ui/FatVector.h
\ No newline at end of file
diff --git a/libs/binder/AppOpsManager.cpp b/libs/binder/AppOpsManager.cpp
index aeca12b..43b0da3 100644
--- a/libs/binder/AppOpsManager.cpp
+++ b/libs/binder/AppOpsManager.cpp
@@ -30,24 +30,10 @@
 
 namespace android {
 
-namespace {
-
-#if defined(__BRILLO__)
-// Because Brillo has no application model, security policy is managed
-// statically (at build time) with SELinux controls.
-// As a consequence, it also never runs the AppOpsManager service.
-const int APP_OPS_MANAGER_UNAVAILABLE_MODE = AppOpsManager::MODE_ALLOWED;
-#else
-const int APP_OPS_MANAGER_UNAVAILABLE_MODE = AppOpsManager::MODE_IGNORED;
-#endif  // defined(__BRILLO__)
-
-}  // namespace
-
-static String16 _appops("appops");
-static pthread_mutex_t gClientIdMutex = PTHREAD_MUTEX_INITIALIZER;
-static sp<IBinder> gClientId;
-
 static const sp<IBinder>& getClientId() {
+    static pthread_mutex_t gClientIdMutex = PTHREAD_MUTEX_INITIALIZER;
+    static sp<IBinder> gClientId;
+
     pthread_mutex_lock(&gClientIdMutex);
     if (gClientId == nullptr) {
         gClientId = new BBinder();
@@ -56,22 +42,13 @@
     return gClientId;
 }
 
-thread_local uint64_t notedAppOpsInThisBinderTransaction[2];
-thread_local int32_t uidOfThisBinderTransaction = -1;
-
-// Whether an appop should be collected: 0 == not initialized, 1 == don't note, 2 == note
-uint8_t appOpsToNote[AppOpsManager::_NUM_OP] = {0};
-
 AppOpsManager::AppOpsManager()
 {
 }
 
-#if defined(__BRILLO__)
-// There is no AppOpsService on Brillo
-sp<IAppOpsService> AppOpsManager::getService() { return NULL; }
-#else
 sp<IAppOpsService> AppOpsManager::getService()
 {
+    static String16 _appops("appops");
 
     std::lock_guard<Mutex> scoped_lock(mLock);
     int64_t startTime = 0;
@@ -96,14 +73,13 @@
     }
     return service;
 }
-#endif  // defined(__BRILLO__)
 
 int32_t AppOpsManager::checkOp(int32_t op, int32_t uid, const String16& callingPackage)
 {
     sp<IAppOpsService> service = getService();
     return service != nullptr
             ? service->checkOperation(op, uid, callingPackage)
-            : APP_OPS_MANAGER_UNAVAILABLE_MODE;
+            : AppOpsManager::MODE_IGNORED;
 }
 
 int32_t AppOpsManager::checkAudioOpNoThrow(int32_t op, int32_t usage, int32_t uid,
@@ -111,7 +87,7 @@
     sp<IAppOpsService> service = getService();
     return service != nullptr
            ? service->checkAudioOperation(op, usage, uid, callingPackage)
-           : APP_OPS_MANAGER_UNAVAILABLE_MODE;
+           : AppOpsManager::MODE_IGNORED;
 }
 
 int32_t AppOpsManager::noteOp(int32_t op, int32_t uid, const String16& callingPackage) {
@@ -125,7 +101,7 @@
     int32_t mode = service != nullptr
             ? service->noteOperation(op, uid, callingPackage, featureId, shouldCollectNotes(op),
                     message)
-            : APP_OPS_MANAGER_UNAVAILABLE_MODE;
+            : AppOpsManager::MODE_IGNORED;
 
     return mode;
 }
@@ -143,7 +119,7 @@
     int32_t mode = service != nullptr
             ? service->startOperation(getClientId(), op, uid, callingPackage,
                     featureId, startIfModeDefault, shouldCollectNotes(op), message)
-            : APP_OPS_MANAGER_UNAVAILABLE_MODE;
+            : AppOpsManager::MODE_IGNORED;
 
     return mode;
 }
@@ -192,6 +168,9 @@
 
 // check it the appops needs to be collected and cache result
 bool AppOpsManager::shouldCollectNotes(int32_t opcode) {
+    // Whether an appop should be collected: 0 == not initialized, 1 == don't note, 2 == note
+    static uint8_t appOpsToNote[AppOpsManager::_NUM_OP] = {0};
+
     if (appOpsToNote[opcode] == 0) {
         if (getService()->shouldCollectNotes(opcode)) {
             appOpsToNote[opcode] = 2;
diff --git a/libs/gui/BufferHubConsumer.cpp b/libs/gui/BufferHubConsumer.cpp
index 0ddb87e..b5cdeb2 100644
--- a/libs/gui/BufferHubConsumer.cpp
+++ b/libs/gui/BufferHubConsumer.cpp
@@ -147,16 +147,6 @@
     return INVALID_OPERATION;
 }
 
-status_t BufferHubConsumer::setFrameRate(float /*frameRate*/) {
-    ALOGE("BufferHubConsumer::setFrameRate: not implemented.");
-    return INVALID_OPERATION;
-}
-
-status_t BufferHubConsumer::getFrameRate(float* /*frameRate*/) const {
-    ALOGE("BufferHubConsumer::getFrameRate: not implemented.");
-    return INVALID_OPERATION;
-}
-
 status_t BufferHubConsumer::dumpState(const String8& /*prefix*/, String8* /*outResult*/) const {
     ALOGE("BufferHubConsumer::dumpState: not implemented.");
     return INVALID_OPERATION;
diff --git a/libs/gui/BufferQueueConsumer.cpp b/libs/gui/BufferQueueConsumer.cpp
index 4435265..da6143c 100644
--- a/libs/gui/BufferQueueConsumer.cpp
+++ b/libs/gui/BufferQueueConsumer.cpp
@@ -783,18 +783,6 @@
     return NO_ERROR;
 }
 
-status_t BufferQueueConsumer::setFrameRate(float frameRate) {
-    std::lock_guard<std::mutex> lock(mCore->mMutex);
-    mCore->mFrameRate = frameRate;
-    return NO_ERROR;
-}
-
-status_t BufferQueueConsumer::getFrameRate(float* frameRate) const {
-    std::lock_guard<std::mutex> lock(mCore->mMutex);
-    *frameRate = mCore->mFrameRate;
-    return NO_ERROR;
-}
-
 status_t BufferQueueConsumer::dumpState(const String8& prefix, String8* outResult) const {
     struct passwd* pwd = getpwnam("shell");
     uid_t shellUid = pwd ? pwd->pw_uid : 0;
diff --git a/libs/gui/BufferQueueCore.cpp b/libs/gui/BufferQueueCore.cpp
index 9e5d681..a1803d8 100644
--- a/libs/gui/BufferQueueCore.cpp
+++ b/libs/gui/BufferQueueCore.cpp
@@ -130,8 +130,7 @@
         mLastQueuedSlot(INVALID_BUFFER_SLOT),
         mUniqueId(getUniqueId()),
         mAutoPrerotation(false),
-        mTransformHintInUse(0),
-        mFrameRate(0) {
+        mTransformHintInUse(0) {
     int numStartingBuffers = getMaxBufferCountLocked();
     for (int s = 0; s < numStartingBuffers; s++) {
         mFreeSlots.insert(s);
diff --git a/libs/gui/BufferQueueProducer.cpp b/libs/gui/BufferQueueProducer.cpp
index 9e86838..3f4c5da 100644
--- a/libs/gui/BufferQueueProducer.cpp
+++ b/libs/gui/BufferQueueProducer.cpp
@@ -1676,14 +1676,4 @@
     return NO_ERROR;
 }
 
-status_t BufferQueueProducer::setFrameRate(float frameRate) {
-    ATRACE_CALL();
-    BQ_LOGV("setFrameRate: %.0f", frameRate);
-
-    std::lock_guard<std::mutex> lock(mCore->mMutex);
-
-    mCore->mFrameRate = frameRate;
-    return NO_ERROR;
-}
-
 } // namespace android
diff --git a/libs/gui/ConsumerBase.cpp b/libs/gui/ConsumerBase.cpp
index 515f45c..9f91d9d 100644
--- a/libs/gui/ConsumerBase.cpp
+++ b/libs/gui/ConsumerBase.cpp
@@ -363,24 +363,6 @@
     return OK;
 }
 
-status_t ConsumerBase::setFrameRate(float frameRate) {
-    Mutex::Autolock _l(mMutex);
-    if (mAbandoned) {
-        CB_LOGE("setFrameRate: ConsumerBase is abandoned!");
-        return NO_INIT;
-    }
-    return mConsumer->setFrameRate(frameRate);
-}
-
-status_t ConsumerBase::getFrameRate(float* frameRate) {
-    Mutex::Autolock _l(mMutex);
-    if (mAbandoned) {
-        CB_LOGE("getFrameRate: ConsumerBase is abandoned!");
-        return NO_INIT;
-    }
-    return mConsumer->getFrameRate(frameRate);
-}
-
 void ConsumerBase::dumpState(String8& result) const {
     dumpState(result, "");
 }
diff --git a/libs/gui/IGraphicBufferConsumer.cpp b/libs/gui/IGraphicBufferConsumer.cpp
index 2521a7c..c705d39 100644
--- a/libs/gui/IGraphicBufferConsumer.cpp
+++ b/libs/gui/IGraphicBufferConsumer.cpp
@@ -51,8 +51,6 @@
     GET_SIDEBAND_STREAM,
     GET_OCCUPANCY_HISTORY,
     DISCARD_FREE_BUFFERS,
-    SET_FRAME_RATE,
-    GET_FRAME_RATE,
     DUMP_STATE,
     LAST = DUMP_STATE,
 };
@@ -165,16 +163,6 @@
                 Tag::DISCARD_FREE_BUFFERS);
     }
 
-    status_t setFrameRate(float frameRate) override {
-        using Signature = decltype(&IGraphicBufferConsumer::setFrameRate);
-        return callRemote<Signature>(Tag::SET_FRAME_RATE, frameRate);
-    }
-
-    status_t getFrameRate(float* frameRate) const override {
-        using Signature = decltype(&IGraphicBufferConsumer::getFrameRate);
-        return callRemote<Signature>(Tag::GET_FRAME_RATE, frameRate);
-    }
-
     status_t dumpState(const String8& prefix, String8* outResult) const override {
         using Signature = status_t (IGraphicBufferConsumer::*)(const String8&, String8*) const;
         return callRemote<Signature>(Tag::DUMP_STATE, prefix, outResult);
@@ -232,10 +220,6 @@
             return callLocal(data, reply, &IGraphicBufferConsumer::getOccupancyHistory);
         case Tag::DISCARD_FREE_BUFFERS:
             return callLocal(data, reply, &IGraphicBufferConsumer::discardFreeBuffers);
-        case Tag::SET_FRAME_RATE:
-            return callLocal(data, reply, &IGraphicBufferConsumer::setFrameRate);
-        case Tag::GET_FRAME_RATE:
-            return callLocal(data, reply, &IGraphicBufferConsumer::getFrameRate);
         case Tag::DUMP_STATE: {
             using Signature = status_t (IGraphicBufferConsumer::*)(const String8&, String8*) const;
             return callLocal<Signature>(data, reply, &IGraphicBufferConsumer::dumpState);
diff --git a/libs/gui/IGraphicBufferProducer.cpp b/libs/gui/IGraphicBufferProducer.cpp
index 7b5596e..ad00939 100644
--- a/libs/gui/IGraphicBufferProducer.cpp
+++ b/libs/gui/IGraphicBufferProducer.cpp
@@ -74,7 +74,6 @@
     GET_CONSUMER_USAGE,
     SET_LEGACY_BUFFER_DROP,
     SET_AUTO_PREROTATION,
-    SET_FRAME_RATE,
 };
 
 class BpGraphicBufferProducer : public BpInterface<IGraphicBufferProducer>
@@ -560,14 +559,6 @@
         }
         return result;
     }
-
-    virtual status_t setFrameRate(float frameRate) {
-        Parcel data, reply;
-        data.writeInterfaceToken(IGraphicBufferProducer::getInterfaceDescriptor());
-        data.writeFloat(frameRate);
-        status_t result = remote()->transact(SET_FRAME_RATE, data, &reply, IBinder::FLAG_ONEWAY);
-        return result;
-    }
 };
 
 // Out-of-line virtual method definition to trigger vtable emission in this
@@ -700,8 +691,6 @@
     status_t setAutoPrerotation(bool autoPrerotation) override {
         return mBase->setAutoPrerotation(autoPrerotation);
     }
-
-    status_t setFrameRate(float frameRate) override { return mBase->setFrameRate(frameRate); }
 };
 
 IMPLEMENT_HYBRID_META_INTERFACE(GraphicBufferProducer,
@@ -721,12 +710,6 @@
     return INVALID_OPERATION;
 }
 
-status_t IGraphicBufferProducer::setFrameRate(float frameRate) {
-    // No-op for IGBP other than BufferQueue.
-    (void)frameRate;
-    return INVALID_OPERATION;
-}
-
 status_t IGraphicBufferProducer::exportToParcel(Parcel* parcel) {
     status_t res = OK;
     res = parcel->writeUint32(USE_BUFFER_QUEUE);
@@ -1096,13 +1079,6 @@
             reply->writeInt32(result);
             return NO_ERROR;
         }
-        case SET_FRAME_RATE: {
-            CHECK_INTERFACE(IGraphicBuffer, data, reply);
-            float frameRate = data.readFloat();
-            status_t result = setFrameRate(frameRate);
-            reply->writeInt32(result);
-            return NO_ERROR;
-        }
     }
     return BBinder::onTransact(code, data, reply, flags);
 }
diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp
index ce41eab..04c21a9 100644
--- a/libs/gui/ISurfaceComposer.cpp
+++ b/libs/gui/ISurfaceComposer.cpp
@@ -1281,6 +1281,9 @@
 
             std::unordered_set<sp<IBinder>, SpHash<IBinder>> excludeHandles;
             int numExcludeHandles = data.readInt32();
+            if (numExcludeHandles >= static_cast<int>(MAX_LAYERS)) {
+                return BAD_VALUE;
+            }
             excludeHandles.reserve(numExcludeHandles);
             for (int i = 0; i < numExcludeHandles; i++) {
                 excludeHandles.emplace(data.readStrongBinder());
diff --git a/libs/gui/include/gui/BufferHubConsumer.h b/libs/gui/include/gui/BufferHubConsumer.h
index d756203..d380770 100644
--- a/libs/gui/include/gui/BufferHubConsumer.h
+++ b/libs/gui/include/gui/BufferHubConsumer.h
@@ -93,12 +93,6 @@
     // See |IGraphicBufferConsumer::discardFreeBuffers|
     status_t discardFreeBuffers() override;
 
-    // See |IGraphicBufferConsumer::setFrameRate|
-    status_t setFrameRate(float frameRate) override;
-
-    // See |IGraphicBufferConsumer::getFrameRate|
-    status_t getFrameRate(float* frameRate) const override;
-
     // See |IGraphicBufferConsumer::dumpState|
     status_t dumpState(const String8& prefix, String8* outResult) const override;
 
diff --git a/libs/gui/include/gui/BufferQueueConsumer.h b/libs/gui/include/gui/BufferQueueConsumer.h
index e9f0449..7db69ec 100644
--- a/libs/gui/include/gui/BufferQueueConsumer.h
+++ b/libs/gui/include/gui/BufferQueueConsumer.h
@@ -149,12 +149,6 @@
     // See IGraphicBufferConsumer::discardFreeBuffers
     virtual status_t discardFreeBuffers() override;
 
-    // See IGraphicBufferConsumer::setFrameRate.
-    virtual status_t setFrameRate(float frameRate) override;
-
-    // See IGraphicBufferConsumer::getFrameRate.
-    virtual status_t getFrameRate(float* frameRate) const override;
-
     // dump our state in a String
     status_t dumpState(const String8& prefix, String8* outResult) const override;
 
diff --git a/libs/gui/include/gui/BufferQueueCore.h b/libs/gui/include/gui/BufferQueueCore.h
index 05c2074..557c28b 100644
--- a/libs/gui/include/gui/BufferQueueCore.h
+++ b/libs/gui/include/gui/BufferQueueCore.h
@@ -354,9 +354,6 @@
     // mTransformHintInUse is to cache the mTransformHint used by the producer.
     uint32_t mTransformHintInUse;
 
-    // The frame rate the app intends to run at.
-    float mFrameRate;
-
 }; // class BufferQueueCore
 
 } // namespace android
diff --git a/libs/gui/include/gui/BufferQueueProducer.h b/libs/gui/include/gui/BufferQueueProducer.h
index cbace5b..a7f7d1d 100644
--- a/libs/gui/include/gui/BufferQueueProducer.h
+++ b/libs/gui/include/gui/BufferQueueProducer.h
@@ -198,9 +198,6 @@
     // See IGraphicBufferProducer::setAutoPrerotation
     virtual status_t setAutoPrerotation(bool autoPrerotation);
 
-    // See IGraphicBufferProducer::setFrameRate
-    virtual status_t setFrameRate(float frameRate) override;
-
 private:
     // This is required by the IBinder::DeathRecipient interface
     virtual void binderDied(const wp<IBinder>& who);
diff --git a/libs/gui/include/gui/ConsumerBase.h b/libs/gui/include/gui/ConsumerBase.h
index cfed9aa..8ff0cd0 100644
--- a/libs/gui/include/gui/ConsumerBase.h
+++ b/libs/gui/include/gui/ConsumerBase.h
@@ -111,12 +111,6 @@
     // See IGraphicBufferConsumer::discardFreeBuffers
     status_t discardFreeBuffers();
 
-    // See IGraphicBufferConsumer::setFrameRate
-    status_t setFrameRate(float frameRate);
-
-    // See IGraphicBufferConsumer::getFrameRate
-    status_t getFrameRate(float* frameRate);
-
 private:
     ConsumerBase(const ConsumerBase&);
     void operator=(const ConsumerBase&);
diff --git a/libs/gui/include/gui/IGraphicBufferConsumer.h b/libs/gui/include/gui/IGraphicBufferConsumer.h
index 56fe949..0b92e7d 100644
--- a/libs/gui/include/gui/IGraphicBufferConsumer.h
+++ b/libs/gui/include/gui/IGraphicBufferConsumer.h
@@ -275,16 +275,6 @@
     // call to free up any of its locally cached buffers.
     virtual status_t discardFreeBuffers() = 0;
 
-    // Set the frame rate the producer will run at.
-    //
-    // Return of a value other than NO_ERROR means an unknown error has occurred.
-    virtual status_t setFrameRate(float frameRate) = 0;
-
-    // Get the frame rate the producer will run at.
-    //
-    // Return of a value other than NO_ERROR means an unknown error has occurred.
-    virtual status_t getFrameRate(float* frameRate) const = 0;
-
     // dump state into a string
     virtual status_t dumpState(const String8& prefix, String8* outResult) const = 0;
 
diff --git a/libs/gui/include/gui/IGraphicBufferProducer.h b/libs/gui/include/gui/IGraphicBufferProducer.h
index 87989da..d7f3492 100644
--- a/libs/gui/include/gui/IGraphicBufferProducer.h
+++ b/libs/gui/include/gui/IGraphicBufferProducer.h
@@ -639,9 +639,6 @@
     // the width and height used for dequeueBuffer will be additionally swapped.
     virtual status_t setAutoPrerotation(bool autoPrerotation);
 
-    // Sets the apps intended frame rate.
-    virtual status_t setFrameRate(float frameRate);
-
 #ifndef NO_BINDER
     // Static method exports any IGraphicBufferProducer object to a parcel. It
     // handles null producer as well.
diff --git a/libs/gui/include/gui/ISurfaceComposer.h b/libs/gui/include/gui/ISurfaceComposer.h
index 0659f0d..09487ea 100644
--- a/libs/gui/include/gui/ISurfaceComposer.h
+++ b/libs/gui/include/gui/ISurfaceComposer.h
@@ -76,6 +76,8 @@
 public:
     DECLARE_META_INTERFACE(SurfaceComposer)
 
+    static constexpr size_t MAX_LAYERS = 4096;
+
     // flags for setTransactionState()
     enum {
         eSynchronous = 0x01,
diff --git a/libs/gui/include/gui/Surface.h b/libs/gui/include/gui/Surface.h
index ad7cbfe..917c0d4 100644
--- a/libs/gui/include/gui/Surface.h
+++ b/libs/gui/include/gui/Surface.h
@@ -178,7 +178,6 @@
     status_t getUniqueId(uint64_t* outId) const;
     status_t getConsumerUsage(uint64_t* outUsage) const;
 
-    // See IGraphicBufferProducer::setFrameRate
     status_t setFrameRate(float frameRate, int8_t compatibility);
 
 protected:
diff --git a/libs/gui/include/gui/mock/GraphicBufferConsumer.h b/libs/gui/include/gui/mock/GraphicBufferConsumer.h
index e940cf3..98f24c2 100644
--- a/libs/gui/include/gui/mock/GraphicBufferConsumer.h
+++ b/libs/gui/include/gui/mock/GraphicBufferConsumer.h
@@ -49,8 +49,6 @@
     MOCK_CONST_METHOD1(getSidebandStream, status_t(sp<NativeHandle>*));
     MOCK_METHOD2(getOccupancyHistory, status_t(bool, std::vector<OccupancyTracker::Segment>*));
     MOCK_METHOD0(discardFreeBuffers, status_t());
-    MOCK_METHOD1(setFrameRate, status_t(float));
-    MOCK_CONST_METHOD1(getFrameRate, status_t(float*));
     MOCK_CONST_METHOD2(dumpState, status_t(const String8&, String8*));
 };
 
diff --git a/libs/nativedisplay/AChoreographer.cpp b/libs/nativedisplay/AChoreographer.cpp
index 0f7e2fb..0ff33ac 100644
--- a/libs/nativedisplay/AChoreographer.cpp
+++ b/libs/nativedisplay/AChoreographer.cpp
@@ -185,9 +185,18 @@
 }
 
 void Choreographer::scheduleCallbacks() {
-    AutoMutex _{mLock};
-    nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
-    if (mFrameCallbacks.top().dueTime <= now) {
+    const nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t dueTime;
+    {
+        AutoMutex _{mLock};
+        // If there are no pending callbacks then don't schedule a vsync
+        if (mFrameCallbacks.empty()) {
+            return;
+        }
+        dueTime = mFrameCallbacks.top().dueTime;
+    }
+
+    if (dueTime <= now) {
         ALOGV("choreographer %p ~ scheduling vsync", this);
         scheduleVsync();
         return;
diff --git a/libs/renderengine/gl/GLESRenderEngine.cpp b/libs/renderengine/gl/GLESRenderEngine.cpp
index 416ebfe..0d4305b 100644
--- a/libs/renderengine/gl/GLESRenderEngine.cpp
+++ b/libs/renderengine/gl/GLESRenderEngine.cpp
@@ -381,15 +381,6 @@
         LOG_ALWAYS_FATAL_IF(!success, "can't make default context current");
     }
 
-    const uint16_t protTexData[] = {0};
-    glGenTextures(1, &mProtectedTexName);
-    glBindTexture(GL_TEXTURE_2D, mProtectedTexName);
-    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
-    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
-    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
-    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
-    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 1, 1, 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, protTexData);
-
     // mColorBlindnessCorrection = M;
 
     if (mUseColorManagement) {
diff --git a/libs/renderengine/gl/GLESRenderEngine.h b/libs/renderengine/gl/GLESRenderEngine.h
index 4cd0b3d..32dbad1 100644
--- a/libs/renderengine/gl/GLESRenderEngine.h
+++ b/libs/renderengine/gl/GLESRenderEngine.h
@@ -178,7 +178,6 @@
     EGLSurface mDummySurface;
     EGLContext mProtectedEGLContext;
     EGLSurface mProtectedDummySurface;
-    GLuint mProtectedTexName;
     GLint mMaxViewportDims[2];
     GLint mMaxTextureSize;
     GLuint mVpWidth;
diff --git a/libs/ui/Region.cpp b/libs/ui/Region.cpp
index cd2a448..bf487c4 100644
--- a/libs/ui/Region.cpp
+++ b/libs/ui/Region.cpp
@@ -67,20 +67,19 @@
 // ----------------------------------------------------------------------------
 
 Region::Region() {
-    mStorage.push_back(Rect(0, 0));
+    mStorage.add(Rect(0,0));
 }
 
 Region::Region(const Region& rhs)
+    : mStorage(rhs.mStorage)
 {
-    mStorage.clear();
-    mStorage.insert(mStorage.begin(), rhs.mStorage.begin(), rhs.mStorage.end());
 #if defined(VALIDATE_REGIONS)
     validate(rhs, "rhs copy-ctor");
 #endif
 }
 
 Region::Region(const Rect& rhs) {
-    mStorage.push_back(rhs);
+    mStorage.add(rhs);
 }
 
 Region::~Region()
@@ -101,8 +100,8 @@
  * final, correctly ordered region buffer. Each rectangle will be compared with the span directly
  * above it, and subdivided to resolve any remaining T-junctions.
  */
-static void reverseRectsResolvingJunctions(const Rect* begin, const Rect* end, FatVector<Rect>& dst,
-                                           int spanDirection) {
+static void reverseRectsResolvingJunctions(const Rect* begin, const Rect* end,
+        Vector<Rect>& dst, int spanDirection) {
     dst.clear();
 
     const Rect* current = end - 1;
@@ -110,7 +109,7 @@
 
     // add first span immediately
     do {
-        dst.push_back(*current);
+        dst.add(*current);
         current--;
     } while (current->top == lastTop && current >= begin);
 
@@ -148,12 +147,12 @@
                 if (prev.right <= left) break;
 
                 if (prev.right > left && prev.right < right) {
-                    dst.push_back(Rect(prev.right, top, right, bottom));
+                    dst.add(Rect(prev.right, top, right, bottom));
                     right = prev.right;
                 }
 
                 if (prev.left > left && prev.left < right) {
-                    dst.push_back(Rect(prev.left, top, right, bottom));
+                    dst.add(Rect(prev.left, top, right, bottom));
                     right = prev.left;
                 }
 
@@ -167,12 +166,12 @@
                 if (prev.left >= right) break;
 
                 if (prev.left > left && prev.left < right) {
-                    dst.push_back(Rect(left, top, prev.left, bottom));
+                    dst.add(Rect(left, top, prev.left, bottom));
                     left = prev.left;
                 }
 
                 if (prev.right > left && prev.right < right) {
-                    dst.push_back(Rect(left, top, prev.right, bottom));
+                    dst.add(Rect(left, top, prev.right, bottom));
                     left = prev.right;
                 }
                 // if an entry in the previous span is too far left, nothing further right in the
@@ -184,7 +183,7 @@
         }
 
         if (left < right) {
-            dst.push_back(Rect(left, top, right, bottom));
+            dst.add(Rect(left, top, right, bottom));
         }
 
         current--;
@@ -202,14 +201,13 @@
     if (r.isEmpty()) return r;
     if (r.isRect()) return r;
 
-    FatVector<Rect> reversed;
+    Vector<Rect> reversed;
     reverseRectsResolvingJunctions(r.begin(), r.end(), reversed, direction_RTL);
 
     Region outputRegion;
-    reverseRectsResolvingJunctions(reversed.data(), reversed.data() + reversed.size(),
-                                   outputRegion.mStorage, direction_LTR);
-    outputRegion.mStorage.push_back(
-            r.getBounds()); // to make region valid, mStorage must end with bounds
+    reverseRectsResolvingJunctions(reversed.begin(), reversed.end(),
+            outputRegion.mStorage, direction_LTR);
+    outputRegion.mStorage.add(r.getBounds()); // to make region valid, mStorage must end with bounds
 
 #if defined(VALIDATE_REGIONS)
     validate(outputRegion, "T-Junction free region");
@@ -224,8 +222,7 @@
     validate(*this, "this->operator=");
     validate(rhs, "rhs.operator=");
 #endif
-    mStorage.clear();
-    mStorage.insert(mStorage.begin(), rhs.mStorage.begin(), rhs.mStorage.end());
+    mStorage = rhs.mStorage;
     return *this;
 }
 
@@ -234,7 +231,7 @@
     if (mStorage.size() >= 2) {
         const Rect bounds(getBounds());
         mStorage.clear();
-        mStorage.push_back(bounds);
+        mStorage.add(bounds);
     }
     return *this;
 }
@@ -258,25 +255,25 @@
 void Region::clear()
 {
     mStorage.clear();
-    mStorage.push_back(Rect(0, 0));
+    mStorage.add(Rect(0,0));
 }
 
 void Region::set(const Rect& r)
 {
     mStorage.clear();
-    mStorage.push_back(r);
+    mStorage.add(r);
 }
 
 void Region::set(int32_t w, int32_t h)
 {
     mStorage.clear();
-    mStorage.push_back(Rect(w, h));
+    mStorage.add(Rect(w, h));
 }
 
 void Region::set(uint32_t w, uint32_t h)
 {
     mStorage.clear();
-    mStorage.push_back(Rect(w, h));
+    mStorage.add(Rect(w, h));
 }
 
 bool Region::isTriviallyEqual(const Region& region) const {
@@ -302,7 +299,8 @@
 void Region::addRectUnchecked(int l, int t, int r, int b)
 {
     Rect rect(l,t,r,b);
-    mStorage.insert(mStorage.end() - 1, rect);
+    size_t where = mStorage.size() - 1;
+    mStorage.insertAt(rect, where, 1);
 }
 
 // ----------------------------------------------------------------------------
@@ -352,7 +350,7 @@
 
 Region& Region::scaleSelf(float sx, float sy) {
     size_t count = mStorage.size();
-    Rect* rects = mStorage.data();
+    Rect* rects = mStorage.editArray();
     while (count) {
         rects->left = static_cast<int32_t>(static_cast<float>(rects->left) * sx + 0.5f);
         rects->right = static_cast<int32_t>(static_cast<float>(rects->right) * sx + 0.5f);
@@ -457,10 +455,10 @@
 class Region::rasterizer : public region_operator<Rect>::region_rasterizer
 {
     Rect bounds;
-    FatVector<Rect>& storage;
+    Vector<Rect>& storage;
     Rect* head;
     Rect* tail;
-    FatVector<Rect> span;
+    Vector<Rect> span;
     Rect* cur;
 public:
     explicit rasterizer(Region& reg)
@@ -487,8 +485,8 @@
         flushSpan();
     }
     if (storage.size()) {
-        bounds.top = storage.front().top;
-        bounds.bottom = storage.back().bottom;
+        bounds.top = storage.itemAt(0).top;
+        bounds.bottom = storage.top().bottom;
         if (storage.size() == 1) {
             storage.clear();
         }
@@ -496,7 +494,7 @@
         bounds.left  = 0;
         bounds.right = 0;
     }
-    storage.push_back(bounds);
+    storage.add(bounds);
 }
 
 void Region::rasterizer::operator()(const Rect& rect)
@@ -511,15 +509,15 @@
             return;
         }
     }
-    span.push_back(rect);
-    cur = span.data() + (span.size() - 1);
+    span.add(rect);
+    cur = span.editArray() + (span.size() - 1);
 }
 
 void Region::rasterizer::flushSpan()
 {
     bool merge = false;
     if (tail-head == ssize_t(span.size())) {
-        Rect const* p = span.data();
+        Rect const* p = span.editArray();
         Rect const* q = head;
         if (p->top == q->bottom) {
             merge = true;
@@ -534,17 +532,17 @@
         }
     }
     if (merge) {
-        const int bottom = span.front().bottom;
+        const int bottom = span[0].bottom;
         Rect* r = head;
         while (r != tail) {
             r->bottom = bottom;
             r++;
         }
     } else {
-        bounds.left = min(span.front().left, bounds.left);
-        bounds.right = max(span.back().right, bounds.right);
-        storage.insert(storage.end(), span.begin(), span.end());
-        tail = storage.data() + storage.size();
+        bounds.left = min(span.itemAt(0).left, bounds.left);
+        bounds.right = max(span.top().right, bounds.right);
+        storage.appendVector(span);
+        tail = storage.editArray() + storage.size();
         head = tail - span.size();
     }
     span.clear();
@@ -552,7 +550,7 @@
 
 bool Region::validate(const Region& reg, const char* name, bool silent)
 {
-    if (reg.mStorage.empty()) {
+    if (reg.mStorage.isEmpty()) {
         ALOGE_IF(!silent, "%s: mStorage is empty, which is never valid", name);
         // return immediately as the code below assumes mStorage is non-empty
         return false;
@@ -691,8 +689,9 @@
     }
     sk_dst.op(sk_lhs, sk_rhs, sk_op);
 
-    if (sk_dst.empty() && dst.empty()) return;
-
+    if (sk_dst.isEmpty() && dst.isEmpty())
+        return;
+    
     bool same = true;
     Region::const_iterator head = dst.begin();
     Region::const_iterator const tail = dst.end();
@@ -787,7 +786,7 @@
         validate(reg, "translate (before)");
 #endif
         size_t count = reg.mStorage.size();
-        Rect* rects = reg.mStorage.data();
+        Rect* rects = reg.mStorage.editArray();
         while (count) {
             rects->offsetBy(dx, dy);
             rects++;
@@ -867,25 +866,24 @@
         ALOGE("Region::unflatten() failed, invalid region");
         return BAD_VALUE;
     }
-    mStorage.clear();
-    mStorage.insert(mStorage.begin(), result.mStorage.begin(), result.mStorage.end());
+    mStorage = result.mStorage;
     return NO_ERROR;
 }
 
 // ----------------------------------------------------------------------------
 
 Region::const_iterator Region::begin() const {
-    return mStorage.data();
+    return mStorage.array();
 }
 
 Region::const_iterator Region::end() const {
     // Workaround for b/77643177
     // mStorage should never be empty, but somehow it is and it's causing
     // an abort in ubsan
-    if (mStorage.empty()) return mStorage.data();
+    if (mStorage.isEmpty()) return mStorage.array();
 
     size_t numRects = isRect() ? 1 : mStorage.size() - 1;
-    return mStorage.data() + numRects;
+    return mStorage.array() + numRects;
 }
 
 Rect const* Region::getArray(size_t* count) const {
diff --git a/libs/ui/include/ui/FatVector.h b/libs/ui/include/ui/FatVector.h
deleted file mode 100644
index 25fe3a0..0000000
--- a/libs/ui/include/ui/FatVector.h
+++ /dev/null
@@ -1,93 +0,0 @@
-/*
- * Copyright 2019, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ANDROID_REGION_FAT_VECTOR_H
-#define ANDROID_REGION_FAT_VECTOR_H
-
-#include <stddef.h>
-#include <stdlib.h>
-#include <utils/Log.h>
-#include <type_traits>
-
-#include <vector>
-
-namespace android {
-
-template <typename T, size_t SIZE = 4>
-class InlineStdAllocator {
-public:
-    struct Allocation {
-    private:
-        Allocation(const Allocation&) = delete;
-        void operator=(const Allocation&) = delete;
-
-    public:
-        Allocation() {}
-        // char array instead of T array, so memory is uninitialized, with no destructors run
-        char array[sizeof(T) * SIZE];
-        bool inUse = false;
-    };
-
-    typedef T value_type; // needed to implement std::allocator
-    typedef T* pointer;   // needed to implement std::allocator
-
-    explicit InlineStdAllocator(Allocation& allocation) : mAllocation(allocation) {}
-    InlineStdAllocator(const InlineStdAllocator& other) : mAllocation(other.mAllocation) {}
-    ~InlineStdAllocator() {}
-
-    T* allocate(size_t num, const void* = 0) {
-        if (!mAllocation.inUse && num <= SIZE) {
-            mAllocation.inUse = true;
-            return static_cast<T*>(static_cast<void*>(mAllocation.array));
-        } else {
-            return static_cast<T*>(static_cast<void*>(malloc(num * sizeof(T))));
-        }
-    }
-
-    void deallocate(pointer p, size_t) {
-        if (p == static_cast<T*>(static_cast<void*>(mAllocation.array))) {
-            mAllocation.inUse = false;
-        } else {
-            // 'free' instead of delete here - destruction handled separately
-            free(p);
-        }
-    }
-    Allocation& mAllocation;
-};
-
-/**
- * std::vector with SIZE elements preallocated into an internal buffer.
- *
- * Useful for avoiding the cost of malloc in cases where only SIZE or
- * fewer elements are needed in the common case.
- */
-template <typename T, size_t SIZE = 4>
-class FatVector : public std::vector<T, InlineStdAllocator<T, SIZE>> {
-public:
-    FatVector()
-          : std::vector<T, InlineStdAllocator<T, SIZE>>(InlineStdAllocator<T, SIZE>(mAllocation)) {
-        this->reserve(SIZE);
-    }
-
-    explicit FatVector(size_t capacity) : FatVector() { this->resize(capacity); }
-
-private:
-    typename InlineStdAllocator<T, SIZE>::Allocation mAllocation;
-};
-
-} // namespace android
-
-#endif // ANDROID_REGION_FAT_VECTOR_H
diff --git a/libs/ui/include/ui/Region.h b/libs/ui/include/ui/Region.h
index 6bb7b8d..2db3b10 100644
--- a/libs/ui/include/ui/Region.h
+++ b/libs/ui/include/ui/Region.h
@@ -21,13 +21,13 @@
 #include <sys/types.h>
 #include <ostream>
 
+#include <utils/Vector.h>
+
 #include <ui/Rect.h>
 #include <utils/Flattenable.h>
 
 #include <android-base/macros.h>
 
-#include "FatVector.h"
-
 #include <string>
 
 namespace android {
@@ -180,7 +180,7 @@
     // with an extra Rect as the last element which is set to the
     // bounds of the region. However, if the region is
     // a simple Rect then mStorage contains only that rect.
-    FatVector<Rect> mStorage;
+    Vector<Rect> mStorage;
 };
 
 
@@ -235,3 +235,4 @@
 }; // namespace android
 
 #endif // ANDROID_UI_REGION_H
+
diff --git a/libs/ui/include_vndk/ui/FatVector.h b/libs/ui/include_vndk/ui/FatVector.h
deleted file mode 120000
index bf30166..0000000
--- a/libs/ui/include_vndk/ui/FatVector.h
+++ /dev/null
@@ -1 +0,0 @@
-../../include/ui/FatVector.h
\ No newline at end of file
diff --git a/services/inputflinger/BlockingQueue.h b/services/inputflinger/BlockingQueue.h
index db9f26e..b612ca7 100644
--- a/services/inputflinger/BlockingQueue.h
+++ b/services/inputflinger/BlockingQueue.h
@@ -45,10 +45,7 @@
     T pop() {
         std::unique_lock lock(mLock);
         android::base::ScopedLockAssertion assumeLock(mLock);
-        mHasElements.wait(lock, [this]{
-                android::base::ScopedLockAssertion assumeLock(mLock);
-                return !this->mQueue.empty();
-        });
+        mHasElements.wait(lock, [this]() REQUIRES(mLock) { return !this->mQueue.empty(); });
         T t = std::move(mQueue.front());
         mQueue.erase(mQueue.begin());
         return t;
diff --git a/services/inputflinger/InputClassifier.cpp b/services/inputflinger/InputClassifier.cpp
index ae9a348..e5e83d7 100644
--- a/services/inputflinger/InputClassifier.cpp
+++ b/services/inputflinger/InputClassifier.cpp
@@ -250,7 +250,7 @@
             case ClassifierEventType::DEVICE_RESET: {
                 const int32_t deviceId = *(event.getDeviceId());
                 halResponseOk = mService->resetDevice(deviceId).isOk();
-                setClassification(deviceId, MotionClassification::NONE);
+                clearDeviceState(deviceId);
                 break;
             }
             case ClassifierEventType::HAL_RESET: {
@@ -321,6 +321,12 @@
     mClassifications[deviceId] = MotionClassification::NONE;
 }
 
+void MotionClassifier::clearDeviceState(int32_t deviceId) {
+    std::scoped_lock lock(mLock);
+    mClassifications.erase(deviceId);
+    mLastDownTimes.erase(deviceId);
+}
+
 MotionClassification MotionClassifier::classify(const NotifyMotionArgs& args) {
     if ((args.action & AMOTION_EVENT_ACTION_MASK) == AMOTION_EVENT_ACTION_DOWN) {
         updateLastDownTime(args.deviceId, args.downTime);
@@ -455,6 +461,7 @@
 void InputClassifier::dump(std::string& dump) {
     std::scoped_lock lock(mLock);
     dump += "Input Classifier State:\n";
+    dump += StringPrintf(INDENT1 "Deep press: %s\n", deepPressEnabled() ? "enabled" : "disabled");
 
     dump += INDENT1 "Motion Classifier:\n";
     if (mMotionClassifier) {
diff --git a/services/inputflinger/InputClassifier.h b/services/inputflinger/InputClassifier.h
index 47e20db..9692352 100644
--- a/services/inputflinger/InputClassifier.h
+++ b/services/inputflinger/InputClassifier.h
@@ -212,6 +212,8 @@
 
     void updateLastDownTime(int32_t deviceId, nsecs_t downTime);
 
+    void clearDeviceState(int32_t deviceId);
+
     /**
      * Exit the InputClassifier HAL thread.
      * Useful for tests to ensure proper cleanup.
diff --git a/services/surfaceflinger/BufferQueueLayer.cpp b/services/surfaceflinger/BufferQueueLayer.cpp
index f5a99ca..18f7f44 100644
--- a/services/surfaceflinger/BufferQueueLayer.cpp
+++ b/services/surfaceflinger/BufferQueueLayer.cpp
@@ -564,8 +564,6 @@
     mBufferInfo.mApi = mConsumer->getCurrentApi();
     mBufferInfo.mPixelFormat = mFormat;
     mBufferInfo.mTransformToDisplayInverse = mConsumer->getTransformToDisplayInverse();
-    float latchedFrameRate;
-    mConsumer->getFrameRate(&latchedFrameRate);
 }
 
 sp<Layer> BufferQueueLayer::createClone() {
diff --git a/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp b/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp
index 550ec61..06e0cbb 100644
--- a/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp
+++ b/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp
@@ -124,24 +124,20 @@
     static std::unique_ptr<HalWrapper> connect() {
         // Power HAL 1.3 is not guaranteed to be available, thus we need to query
         // Power HAL 1.0 first and try to cast it to Power HAL 1.3.
-        // Power HAL 1.0 is always available, thus if we fail to query it, it means
-        // Power HAL is not available temporarily and we should retry later. However,
-        // if Power HAL 1.0 is available and we can't cast it to Power HAL 1.3,
-        // it means Power HAL 1.3 is not available at all, so we should stop trying.
         sp<V1_3::IPower> powerHal = nullptr;
-        if (sHasPowerHal_1_3) {
-            sp<V1_0::IPower> powerHal_1_0 = V1_0::IPower::getService();
-            if (powerHal_1_0 != nullptr) {
-                // Try to cast to Power HAL 1.3
-                powerHal = V1_3::IPower::castFrom(powerHal_1_0);
-                if (powerHal == nullptr) {
-                    ALOGW("No Power HAL 1.3 service in system");
-                    sHasPowerHal_1_3 = false;
-                } else {
-                    ALOGI("Loaded Power HAL 1.3 service");
-                }
+        sp<V1_0::IPower> powerHal_1_0 = V1_0::IPower::getService();
+        if (powerHal_1_0 != nullptr) {
+            // Try to cast to Power HAL 1.3
+            powerHal = V1_3::IPower::castFrom(powerHal_1_0);
+            if (powerHal == nullptr) {
+                ALOGW("No Power HAL 1.3 service in system, disabling PowerAdvisor");
+            } else {
+                ALOGI("Loaded Power HAL 1.3 service");
             }
+        } else {
+            ALOGW("No Power HAL found, disabling PowerAdvisor");
         }
+
         if (powerHal == nullptr) {
             return nullptr;
         }
@@ -162,12 +158,9 @@
     }
 
 private:
-    static bool sHasPowerHal_1_3;
     const sp<V1_3::IPower> mPowerHal = nullptr;
 };
 
-bool HidlPowerHalWrapper::sHasPowerHal_1_3 = true;
-
 class AidlPowerHalWrapper : public PowerAdvisor::HalWrapper {
 public:
     AidlPowerHalWrapper(sp<IPower> powerHal) : mPowerHal(std::move(powerHal)) {
@@ -226,7 +219,13 @@
 
 PowerAdvisor::HalWrapper* PowerAdvisor::getPowerHal() {
     static std::unique_ptr<HalWrapper> sHalWrapper = nullptr;
+    static bool sHasHal = true;
 
+    if (!sHasHal) {
+        return nullptr;
+    }
+
+    // If we used to have a HAL, but it stopped responding, attempt to reconnect
     if (mReconnectPowerHal) {
         sHalWrapper = nullptr;
         mReconnectPowerHal = false;
@@ -244,6 +243,12 @@
         sHalWrapper = HidlPowerHalWrapper::connect();
     }
 
+    // If we make it to this point and still don't have a HAL, it's unlikely we
+    // will, so stop trying
+    if (sHalWrapper == nullptr) {
+        sHasHal = false;
+    }
+
     return sHalWrapper.get();
 }
 
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 766871e..64cfb3d 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -719,9 +719,14 @@
 Hwc2::IComposerClient::Composition Layer::getCompositionType(
         const sp<const DisplayDevice>& display) const {
     const auto outputLayer = findOutputLayerForDisplay(display);
-    LOG_FATAL_IF(!outputLayer);
-    return outputLayer->getState().hwc ? (*outputLayer->getState().hwc).hwcCompositionType
-                                       : Hwc2::IComposerClient::Composition::CLIENT;
+    if (outputLayer == nullptr) {
+        return Hwc2::IComposerClient::Composition::INVALID;
+    }
+    if (outputLayer->getState().hwc) {
+        return (*outputLayer->getState().hwc).hwcCompositionType;
+    } else {
+        return Hwc2::IComposerClient::Composition::CLIENT;
+    }
 }
 
 bool Layer::getClearClientTarget(const sp<const DisplayDevice>& display) const {
@@ -2052,13 +2057,20 @@
     setTransactionFlags(eTransactionNeeded);
 }
 
-LayerProto* Layer::writeToProto(LayersProto& layersProto, uint32_t traceFlags) const {
+LayerProto* Layer::writeToProto(LayersProto& layersProto, uint32_t traceFlags,
+                                const sp<const DisplayDevice>& device) const {
     LayerProto* layerProto = layersProto.add_layers();
     writeToProtoDrawingState(layerProto, traceFlags);
     writeToProtoCommonState(layerProto, LayerVector::StateSet::Drawing, traceFlags);
 
+    // Only populate for the primary display.
+    if (device) {
+        const Hwc2::IComposerClient::Composition compositionType = getCompositionType(device);
+        layerProto->set_hwc_composition_type(static_cast<HwcCompositionType>(compositionType));
+    }
+
     for (const sp<Layer>& layer : mDrawingChildren) {
-        layer->writeToProto(layersProto, traceFlags);
+        layer->writeToProto(layersProto, traceFlags, device);
     }
 
     return layerProto;
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index 5d2144a..20d7232 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -506,7 +506,8 @@
     bool isRemovedFromCurrentState() const;
 
     LayerProto* writeToProto(LayersProto& layersProto,
-                             uint32_t traceFlags = SurfaceTracing::TRACE_ALL) const;
+                             uint32_t traceFlags = SurfaceTracing::TRACE_ALL,
+                             const sp<const DisplayDevice>& device = nullptr) const;
 
     // Write states that are modified by the main thread. This includes drawing
     // state as well as buffer data. This should be called in the main or tracing
diff --git a/services/surfaceflinger/MonitoredProducer.cpp b/services/surfaceflinger/MonitoredProducer.cpp
index 40a63d7..5009e10 100644
--- a/services/surfaceflinger/MonitoredProducer.cpp
+++ b/services/surfaceflinger/MonitoredProducer.cpp
@@ -162,10 +162,6 @@
     return mProducer->setAutoPrerotation(autoPrerotation);
 }
 
-status_t MonitoredProducer::setFrameRate(float frameRate) {
-    return mProducer->setFrameRate(frameRate);
-}
-
 IBinder* MonitoredProducer::onAsBinder() {
     return this;
 }
diff --git a/services/surfaceflinger/MonitoredProducer.h b/services/surfaceflinger/MonitoredProducer.h
index 4bda831..788919b 100644
--- a/services/surfaceflinger/MonitoredProducer.h
+++ b/services/surfaceflinger/MonitoredProducer.h
@@ -71,7 +71,6 @@
     virtual status_t getUniqueId(uint64_t* outId) const override;
     virtual status_t getConsumerUsage(uint64_t* outUsage) const override;
     virtual status_t setAutoPrerotation(bool autoPrerotation) override;
-    virtual status_t setFrameRate(float frameRate) override;
 
     // The Layer which created this producer, and on which queued Buffer's will be displayed.
     sp<Layer> getLayer() const;
diff --git a/services/surfaceflinger/RefreshRateOverlay.cpp b/services/surfaceflinger/RefreshRateOverlay.cpp
index 682679c..c675971 100644
--- a/services/surfaceflinger/RefreshRateOverlay.cpp
+++ b/services/surfaceflinger/RefreshRateOverlay.cpp
@@ -168,9 +168,9 @@
 }
 
 void RefreshRateOverlay::primeCache() {
-    auto allRefreshRates = mFlinger.mRefreshRateConfigs->getAllRefreshRates();
+    auto& allRefreshRates = mFlinger.mRefreshRateConfigs->getAllRefreshRates();
     if (allRefreshRates.size() == 1) {
-        auto fps = allRefreshRates.begin()->second.fps;
+        auto fps = allRefreshRates.begin()->second->fps;
         half4 color = {LOW_FPS_COLOR, ALPHA};
         mBufferCache.emplace(fps, SevenSegmentDrawer::drawNumber(fps, color));
         return;
@@ -178,8 +178,8 @@
 
     std::vector<uint32_t> supportedFps;
     supportedFps.reserve(allRefreshRates.size());
-    for (auto [ignored, refreshRate] : allRefreshRates) {
-        supportedFps.push_back(refreshRate.fps);
+    for (auto& [ignored, refreshRate] : allRefreshRates) {
+        supportedFps.push_back(refreshRate->fps);
     }
 
     std::sort(supportedFps.begin(), supportedFps.end());
diff --git a/services/surfaceflinger/Scheduler/LayerInfoV2.cpp b/services/surfaceflinger/Scheduler/LayerInfoV2.cpp
index b755798..b4365bf 100644
--- a/services/surfaceflinger/Scheduler/LayerInfoV2.cpp
+++ b/services/surfaceflinger/Scheduler/LayerInfoV2.cpp
@@ -82,14 +82,14 @@
         }
     }
 
-    const auto numFrames = std::distance(it, mFrameTimes.end()) - 1;
-    if (numFrames <= 0) {
+    const auto numFrames = std::distance(it, mFrameTimes.end());
+    if (numFrames < FREQUENT_LAYER_WINDOW_SIZE) {
         return false;
     }
 
     // Layer is considered frequent if the average frame rate is higher than the threshold
     const auto totalTime = mFrameTimes.back().queueTime - it->queueTime;
-    return (1e9f * numFrames) / totalTime >= MIN_FPS_FOR_FREQUENT_LAYER;
+    return (1e9f * (numFrames - 1)) / totalTime >= MIN_FPS_FOR_FREQUENT_LAYER;
 }
 
 bool LayerInfoV2::hasEnoughDataForHeuristic() const {
diff --git a/services/surfaceflinger/Scheduler/PhaseOffsets.cpp b/services/surfaceflinger/Scheduler/PhaseOffsets.cpp
index 63d9c4b..c04447d 100644
--- a/services/surfaceflinger/Scheduler/PhaseOffsets.cpp
+++ b/services/surfaceflinger/Scheduler/PhaseOffsets.cpp
@@ -71,10 +71,10 @@
     std::unordered_map<float, Offsets> offsets;
 
     for (const auto& [ignored, refreshRate] : refreshRateConfigs.getAllRefreshRates()) {
-        if (refreshRate.fps > 65.0f) {
-            offsets.emplace(refreshRate.fps, getHighFpsOffsets(refreshRate.vsyncPeriod));
+        if (refreshRate->fps > 65.0f) {
+            offsets.emplace(refreshRate->fps, getHighFpsOffsets(refreshRate->vsyncPeriod));
         } else {
-            offsets.emplace(refreshRate.fps, getDefaultOffsets(refreshRate.vsyncPeriod));
+            offsets.emplace(refreshRate->fps, getDefaultOffsets(refreshRate->vsyncPeriod));
         }
     }
     return offsets;
@@ -238,7 +238,7 @@
     refreshRates.reserve(allRefreshRates.size());
 
     for (const auto& [ignored, refreshRate] : allRefreshRates) {
-        refreshRates.emplace_back(refreshRate.fps);
+        refreshRates.emplace_back(refreshRate->fps);
     }
 
     return refreshRates;
diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
index 1765d2d..9edbaee 100644
--- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
+++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
@@ -235,13 +235,13 @@
             ? getBestRefreshRate(scores.rbegin(), scores.rend())
             : getBestRefreshRate(scores.begin(), scores.end());
 
-    return bestRefreshRate == nullptr ? *mCurrentRefreshRate : *bestRefreshRate;
+    return *bestRefreshRate;
 }
 
 template <typename Iter>
 const RefreshRate* RefreshRateConfigs::getBestRefreshRate(Iter begin, Iter end) const {
-    const RefreshRate* bestRefreshRate = nullptr;
-    float max = 0;
+    const RefreshRate* bestRefreshRate = begin->first;
+    float max = begin->second;
     for (auto i = begin; i != end; ++i) {
         const auto [refreshRate, score] = *i;
         ALOGV("%s scores %.2f", refreshRate->name.c_str(), score);
@@ -286,12 +286,12 @@
                   mCurrentRefreshRate) != mAvailableRefreshRates.end()) {
         return *mCurrentRefreshRate;
     }
-    return mRefreshRates.at(mDefaultConfig);
+    return *mRefreshRates.at(mDefaultConfig);
 }
 
 void RefreshRateConfigs::setCurrentConfigId(HwcConfigIndexType configId) {
     std::lock_guard lock(mLock);
-    mCurrentRefreshRate = &mRefreshRates.at(configId);
+    mCurrentRefreshRate = mRefreshRates.at(configId).get();
 }
 
 RefreshRateConfigs::RefreshRateConfigs(const std::vector<InputConfig>& configs,
@@ -326,7 +326,7 @@
     if (mRefreshRates.count(defaultConfigId) == 0) {
         return BAD_VALUE;
     }
-    const RefreshRate& refreshRate = mRefreshRates.at(defaultConfigId);
+    const RefreshRate& refreshRate = *mRefreshRates.at(defaultConfigId);
     if (!refreshRate.inPolicy(minRefreshRate, maxRefreshRate)) {
         return BAD_VALUE;
     }
@@ -361,10 +361,10 @@
     outRefreshRates->clear();
     outRefreshRates->reserve(mRefreshRates.size());
     for (const auto& [type, refreshRate] : mRefreshRates) {
-        if (shouldAddRefreshRate(refreshRate)) {
+        if (shouldAddRefreshRate(*refreshRate)) {
             ALOGV("getSortedRefreshRateList: config %d added to list policy",
-                  refreshRate.configId.value());
-            outRefreshRates->push_back(&refreshRate);
+                  refreshRate->configId.value());
+            outRefreshRates->push_back(refreshRate.get());
         }
     }
 
@@ -376,7 +376,7 @@
 
 void RefreshRateConfigs::constructAvailableRefreshRates() {
     // Filter configs based on current policy and sort based on vsync period
-    HwcConfigGroupType group = mRefreshRates.at(mDefaultConfig).configGroup;
+    HwcConfigGroupType group = mRefreshRates.at(mDefaultConfig)->configGroup;
     ALOGV("constructAvailableRefreshRates: default %d group %d min %.2f max %.2f",
           mDefaultConfig.value(), group.value(), mMinRefreshRateFps, mMaxRefreshRateFps);
     getSortedRefreshRateList(
@@ -403,16 +403,15 @@
     LOG_ALWAYS_FATAL_IF(configs.empty());
     LOG_ALWAYS_FATAL_IF(currentHwcConfig.value() >= configs.size());
 
-    auto buildRefreshRate = [&](InputConfig config) -> RefreshRate {
-        const float fps = 1e9f / config.vsyncPeriod;
-        return RefreshRate(config.configId, config.vsyncPeriod, config.configGroup,
-                           base::StringPrintf("%2.ffps", fps), fps);
-    };
-
     for (const auto& config : configs) {
-        mRefreshRates.emplace(config.configId, buildRefreshRate(config));
+        const float fps = 1e9f / config.vsyncPeriod;
+        mRefreshRates.emplace(config.configId,
+                              std::make_unique<RefreshRate>(config.configId, config.vsyncPeriod,
+                                                            config.configGroup,
+                                                            base::StringPrintf("%2.ffps", fps),
+                                                            fps));
         if (config.configId == currentHwcConfig) {
-            mCurrentRefreshRate = &mRefreshRates.at(config.configId);
+            mCurrentRefreshRate = mRefreshRates.at(config.configId).get();
         }
     }
 
diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
index c8aec86..9cd5959 100644
--- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
+++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
@@ -59,6 +59,8 @@
                 configGroup(configGroup),
                 name(std::move(name)),
                 fps(fps) {}
+
+        RefreshRate(const RefreshRate&) = delete;
         // This config ID corresponds to the position of the config in the vector that is stored
         // on the device.
         const HwcConfigIndexType configId;
@@ -85,7 +87,8 @@
         bool operator==(const RefreshRate& other) const { return !(*this != other); }
     };
 
-    using AllRefreshRatesMapType = std::unordered_map<HwcConfigIndexType, const RefreshRate>;
+    using AllRefreshRatesMapType =
+            std::unordered_map<HwcConfigIndexType, std::unique_ptr<const RefreshRate>>;
 
     // Sets the current policy to choose refresh rates. Returns NO_ERROR if the requested policy is
     // valid, or a negative error value otherwise. policyChanged, if non-null, will be set to true
@@ -163,7 +166,7 @@
     // Returns the refresh rate that corresponds to a HwcConfigIndexType. This won't change at
     // runtime.
     const RefreshRate& getRefreshRateFromConfigId(HwcConfigIndexType configId) const {
-        return mRefreshRates.at(configId);
+        return *mRefreshRates.at(configId);
     };
 
     // Stores the current configId the device operates at
diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp
index 5444239..96fa061 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.cpp
+++ b/services/surfaceflinger/Scheduler/Scheduler.cpp
@@ -463,7 +463,7 @@
             return;
         }
         mFeatures.configId = newConfigId;
-        auto newRefreshRate = mRefreshRateConfigs.getRefreshRateFromConfigId(newConfigId);
+        auto& newRefreshRate = mRefreshRateConfigs.getRefreshRateFromConfigId(newConfigId);
         mSchedulerCallback.changeRefreshRate(newRefreshRate, ConfigEvent::Changed);
     }
 }
@@ -515,7 +515,7 @@
 
     // TODO(145561154): cleanup the kernel idle timer implementation and the refresh rate
     // magic number
-    const auto refreshRate = mRefreshRateConfigs.getCurrentRefreshRate();
+    const auto& refreshRate = mRefreshRateConfigs.getCurrentRefreshRate();
     constexpr float FPS_THRESHOLD_FOR_KERNEL_TIMER = 65.0f;
     if (state == TimerState::Reset && refreshRate.fps > FPS_THRESHOLD_FOR_KERNEL_TIMER) {
         // If we're not in performance mode then the kernel timer shouldn't do
diff --git a/services/surfaceflinger/Scheduler/VSyncReactor.cpp b/services/surfaceflinger/Scheduler/VSyncReactor.cpp
index 949ba4c..8987dcd 100644
--- a/services/surfaceflinger/Scheduler/VSyncReactor.cpp
+++ b/services/surfaceflinger/Scheduler/VSyncReactor.cpp
@@ -19,8 +19,10 @@
 #define LOG_TAG "VSyncReactor"
 //#define LOG_NDEBUG 0
 #include "VSyncReactor.h"
+#include <cutils/properties.h>
 #include <log/log.h>
 #include <utils/Trace.h>
+#include "../TracedOrdinal.h"
 #include "TimeKeeper.h"
 #include "VSyncDispatch.h"
 #include "VSyncTracker.h"
@@ -32,12 +34,35 @@
     return systemTime(SYSTEM_TIME_MONOTONIC);
 }
 
+class PredictedVsyncTracer {
+public:
+    PredictedVsyncTracer(VSyncDispatch& dispatch)
+          : mRegistration(dispatch,
+                          std::bind(&PredictedVsyncTracer::callback, this, std::placeholders::_1,
+                                    std::placeholders::_2),
+                          "PredictedVsyncTracer") {
+        mRegistration.schedule(0, 0);
+    }
+
+private:
+    TracedOrdinal<bool> mParity = {"VSYNC-predicted", 0};
+    VSyncCallbackRegistration mRegistration;
+
+    void callback(nsecs_t /*vsyncTime*/, nsecs_t /*targetWakeupTim*/) {
+        mParity = !mParity;
+        mRegistration.schedule(0, 0);
+    }
+};
+
 VSyncReactor::VSyncReactor(std::unique_ptr<Clock> clock, std::unique_ptr<VSyncDispatch> dispatch,
                            std::unique_ptr<VSyncTracker> tracker, size_t pendingFenceLimit)
       : mClock(std::move(clock)),
         mTracker(std::move(tracker)),
         mDispatch(std::move(dispatch)),
-        mPendingLimit(pendingFenceLimit) {}
+        mPendingLimit(pendingFenceLimit),
+        mPredictedVsyncTracer(property_get_bool("debug.sf.show_predicted_vsync", false)
+                                      ? std::make_unique<PredictedVsyncTracer>(*mDispatch)
+                                      : nullptr) {}
 
 VSyncReactor::~VSyncReactor() = default;
 
@@ -287,7 +312,7 @@
     auto it = mCallbacks.find(callback);
     if (it == mCallbacks.end()) {
         // TODO (b/146557561): resolve lastCallbackTime semantics in DispSync i/f.
-        static auto constexpr maxListeners = 3;
+        static auto constexpr maxListeners = 4;
         if (mCallbacks.size() >= maxListeners) {
             ALOGE("callback %s not added, exceeded callback limit of %i (currently %zu)", name,
                   maxListeners, mCallbacks.size());
diff --git a/services/surfaceflinger/Scheduler/VSyncReactor.h b/services/surfaceflinger/Scheduler/VSyncReactor.h
index aa8a38d..7d8a8e3 100644
--- a/services/surfaceflinger/Scheduler/VSyncReactor.h
+++ b/services/surfaceflinger/Scheduler/VSyncReactor.h
@@ -30,6 +30,7 @@
 class VSyncDispatch;
 class VSyncTracker;
 class CallbackRepeater;
+class PredictedVsyncTracer;
 
 // TODO (b/145217110): consider renaming.
 class VSyncReactor : public android::DispSync {
@@ -86,6 +87,8 @@
 
     std::unordered_map<DispSync::Callback*, std::unique_ptr<CallbackRepeater>> mCallbacks
             GUARDED_BY(mMutex);
+
+    const std::unique_ptr<PredictedVsyncTracer> mPredictedVsyncTracer;
 };
 
 class SystemClock : public Clock {
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 1d00624..e764d24 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -367,7 +367,7 @@
     property_get("ro.sf.blurs_are_expensive", value, "0");
     mBlursAreExpensive = atoi(value);
 
-    const size_t defaultListSize = MAX_LAYERS;
+    const size_t defaultListSize = ISurfaceComposer::MAX_LAYERS;
     auto listSize = property_get_int32("debug.sf.max_igbp_list_size", int32_t(defaultListSize));
     mMaxGraphicBufferProducerListSize = (listSize > 0) ? size_t(listSize) : defaultListSize;
 
@@ -903,18 +903,27 @@
 
 void SurfaceFlinger::setDesiredActiveConfig(const ActiveConfigInfo& info) {
     ATRACE_CALL();
-    auto refreshRate = mRefreshRateConfigs->getRefreshRateFromConfigId(info.configId);
+    auto& refreshRate = mRefreshRateConfigs->getRefreshRateFromConfigId(info.configId);
     ALOGV("setDesiredActiveConfig(%s)", refreshRate.name.c_str());
 
-    // Don't check against the current mode yet. Worst case we set the desired
-    // 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 prevConfig = mDesiredActiveConfig.event;
-    mDesiredActiveConfig = info;
-    mDesiredActiveConfig.event = mDesiredActiveConfig.event | prevConfig;
+    if (mDesiredActiveConfigChanged) {
+        // If a config change is pending, just cache the latest request in
+        // mDesiredActiveConfig
+        const Scheduler::ConfigEvent prevConfig = mDesiredActiveConfig.event;
+        mDesiredActiveConfig = info;
+        mDesiredActiveConfig.event = mDesiredActiveConfig.event | prevConfig;
+    } else {
+        // Check is we are already at the desired config
+        const auto display = getDefaultDisplayDeviceLocked();
+        if (!display || display->getActiveConfig() == refreshRate.configId) {
+            return;
+        }
 
-    if (!mDesiredActiveConfigChanged) {
+        // Initiate a config change.
+        mDesiredActiveConfigChanged = true;
+        mDesiredActiveConfig = info;
+
         // This will trigger HWC refresh without resetting the idle timer.
         repaintEverythingForHWC();
         // Start receiving vsync samples now, so that we can detect a period
@@ -927,7 +936,6 @@
         mPhaseConfiguration->setRefreshRateFps(refreshRate.fps);
         mVSyncModulator->setPhaseOffsets(mPhaseConfiguration->getCurrentOffsets());
     }
-    mDesiredActiveConfigChanged = true;
 
     if (mRefreshRateOverlay) {
         mRefreshRateOverlay->changeRefreshRate(refreshRate);
@@ -976,7 +984,7 @@
     mRefreshRateStats->setConfigMode(mUpcomingActiveConfig.configId);
     display->setActiveConfig(mUpcomingActiveConfig.configId);
 
-    auto refreshRate =
+    auto& refreshRate =
             mRefreshRateConfigs->getRefreshRateFromConfigId(mUpcomingActiveConfig.configId);
     mPhaseConfiguration->setRefreshRateFps(refreshRate.fps);
     mVSyncModulator->setPhaseOffsets(mPhaseConfiguration->getCurrentOffsets());
@@ -996,7 +1004,7 @@
     mDesiredActiveConfig.event = Scheduler::ConfigEvent::None;
     mDesiredActiveConfigChanged = false;
 
-    auto const refreshRate =
+    const auto& refreshRate =
             mRefreshRateConfigs->getRefreshRateFromConfigId(mDesiredActiveConfig.configId);
     mScheduler->resyncToHardwareVsync(true, refreshRate.vsyncPeriod);
     mPhaseConfiguration->setRefreshRateFps(refreshRate.fps);
@@ -1029,7 +1037,7 @@
         desiredActiveConfig = mDesiredActiveConfig;
     }
 
-    auto refreshRate =
+    auto& refreshRate =
             mRefreshRateConfigs->getRefreshRateFromConfigId(desiredActiveConfig.configId);
     ALOGV("performSetActiveConfig changing active config to %d(%s)", refreshRate.configId.value(),
           refreshRate.name.c_str());
@@ -1066,7 +1074,9 @@
                                                            mUpcomingActiveConfig.configId.value(),
                                                            constraints, &outTimeline);
     if (status != NO_ERROR) {
-        LOG_ALWAYS_FATAL("setActiveConfigWithConstraints failed: %d", status);
+        // setActiveConfigWithConstraints may fail if a hotplug event is just about
+        // to be sent. We just log the error in this case.
+        ALOGW("setActiveConfigWithConstraints failed: %d", status);
         return false;
     }
 
@@ -3058,9 +3068,9 @@
             parent = parentLayer;
         }
 
-        if (mNumLayers >= MAX_LAYERS) {
+        if (mNumLayers >= ISurfaceComposer::MAX_LAYERS) {
             ALOGE("AddClientLayer failed, mNumLayers (%zu) >= MAX_LAYERS (%zu)", mNumLayers.load(),
-                  MAX_LAYERS);
+                  ISurfaceComposer::MAX_LAYERS);
             return NO_MEMORY;
         }
 
@@ -4450,13 +4460,20 @@
 }
 
 LayersProto SurfaceFlinger::dumpDrawingStateProto(uint32_t traceFlags) const {
+    Mutex::Autolock _l(mStateLock);
+    const auto device = getDefaultDisplayDeviceLocked();
     LayersProto layersProto;
     for (const sp<Layer>& layer : mDrawingState.layersSortedByZ) {
-        layer->writeToProto(layersProto, traceFlags);
+        layer->writeToProto(layersProto, traceFlags, device);
     }
+
     return layersProto;
 }
 
+void SurfaceFlinger::dumpHwc(std::string& result) const {
+    getHwComposer().dump(result);
+}
+
 void SurfaceFlinger::dumpOffscreenLayersProto(LayersProto& layersProto, uint32_t traceFlags) const {
     // Add a fake invisible root layer to the proto output and parent all the offscreen layers to
     // it.
@@ -4471,7 +4488,8 @@
         rootProto->add_children(offscreenLayer->sequence);
 
         // Add layer
-        LayerProto* layerProto = offscreenLayer->writeToProto(layersProto, traceFlags);
+        LayerProto* layerProto =
+                offscreenLayer->writeToProto(layersProto, traceFlags, nullptr /*device*/);
         layerProto->set_parent(offscreenRootLayerId);
     }
 }
@@ -5120,7 +5138,7 @@
                 n = data.readInt32();
                 if (n == 1 && !mRefreshRateOverlay) {
                     mRefreshRateOverlay = std::make_unique<RefreshRateOverlay>(*this);
-                    auto current = mRefreshRateConfigs->getCurrentRefreshRate();
+                    auto& current = mRefreshRateConfigs->getCurrentRefreshRate();
                     mRefreshRateOverlay->changeRefreshRate(current);
                 } else if (n == 0) {
                     mRefreshRateOverlay.reset();
@@ -5169,7 +5187,7 @@
         if (mRefreshRateOverlay) {
             const auto kernelTimerEnabled = property_get_bool(KERNEL_IDLE_TIMER_PROP, false);
             const bool timerExpired = kernelTimerEnabled && expired;
-            const auto& current = [this]() {
+            const auto& current = [this]() -> const RefreshRate& {
                 std::lock_guard<std::mutex> lock(mActiveConfigLock);
                 if (mDesiredActiveConfigChanged) {
                     return mRefreshRateConfigs->getRefreshRateFromConfigId(
@@ -5849,7 +5867,7 @@
                                 display->getActiveConfig(), vsyncPeriod);
 
     auto configId = mScheduler->getPreferredConfigId();
-    auto preferredRefreshRate = configId
+    auto& preferredRefreshRate = configId
             ? mRefreshRateConfigs->getRefreshRateFromConfigId(*configId)
             // NOTE: Choose the default config ID, if Scheduler doesn't have one in mind.
             : mRefreshRateConfigs->getRefreshRateFromConfigId(defaultConfig);
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 477d7a5..e7f9930 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -351,7 +351,6 @@
     // every half hour.
     enum { LOG_FRAME_STATS_PERIOD =  30*60*60 };
 
-    static const size_t MAX_LAYERS = 4096;
     static const int MAX_TRACING_MEMORY = 100 * 1024 * 1024; // 100MB
 
 protected:
@@ -921,6 +920,8 @@
     LayersProto dumpDrawingStateProto(uint32_t traceFlags = SurfaceTracing::TRACE_ALL) const;
     void dumpOffscreenLayersProto(LayersProto& layersProto,
                                   uint32_t traceFlags = SurfaceTracing::TRACE_ALL) const;
+    // Dumps state from HW Composer
+    void dumpHwc(std::string& result) const;
     LayersProto dumpProtoFromMainThread(uint32_t traceFlags = SurfaceTracing::TRACE_ALL)
             EXCLUDES(mStateLock);
     void dumpOffscreenLayers(std::string& result) EXCLUDES(mStateLock);
@@ -974,7 +975,7 @@
 
     // Can't be unordered_set because wp<> isn't hashable
     std::set<wp<IBinder>> mGraphicBufferProducerList;
-    size_t mMaxGraphicBufferProducerListSize = MAX_LAYERS;
+    size_t mMaxGraphicBufferProducerListSize = ISurfaceComposer::MAX_LAYERS;
 
     // protected by mStateLock (but we could use another lock)
     bool mLayersRemoved = false;
diff --git a/services/surfaceflinger/SurfaceTracing.cpp b/services/surfaceflinger/SurfaceTracing.cpp
index eb5c7de..c5556ec 100644
--- a/services/surfaceflinger/SurfaceTracing.cpp
+++ b/services/surfaceflinger/SurfaceTracing.cpp
@@ -170,6 +170,12 @@
     mFlinger.dumpOffscreenLayersProto(layers);
     entry.mutable_layers()->Swap(&layers);
 
+    if (mTraceFlags & SurfaceTracing::TRACE_HWC) {
+        std::string hwcDump;
+        mFlinger.dumpHwc(hwcDump);
+        entry.set_hwc_blob(hwcDump);
+    }
+
     return entry;
 }
 
diff --git a/services/surfaceflinger/SurfaceTracing.h b/services/surfaceflinger/SurfaceTracing.h
index 18524f0..3c24881 100644
--- a/services/surfaceflinger/SurfaceTracing.h
+++ b/services/surfaceflinger/SurfaceTracing.h
@@ -56,6 +56,7 @@
         TRACE_CRITICAL = 1 << 0,
         TRACE_INPUT = 1 << 1,
         TRACE_EXTRA = 1 << 2,
+        TRACE_HWC = 1 << 3,
         TRACE_ALL = 0xffffffff
     };
     void setTraceFlags(uint32_t flags);
diff --git a/services/surfaceflinger/layerproto/layers.proto b/services/surfaceflinger/layerproto/layers.proto
index 8afe503..7f1f542 100644
--- a/services/surfaceflinger/layerproto/layers.proto
+++ b/services/surfaceflinger/layerproto/layers.proto
@@ -9,6 +9,23 @@
   repeated LayerProto layers = 1;
 }
 
+// Must match definition in the IComposerClient HAL
+enum HwcCompositionType {
+    // Invalid composition type
+    INVALID = 0;
+    // Layer was composited by the client into the client target buffer
+    CLIENT = 1;
+    // Layer was composited by the device through hardware overlays
+    DEVICE = 2;
+    // Layer was composited by the device using a color
+    SOLID_COLOR = 3;
+    // Similar to DEVICE, but the layer position may have been asynchronously set
+    // through setCursorPosition
+    CURSOR = 4;
+    // Layer was composited by the device via a sideband stream.
+    SIDEBAND = 5;
+}
+
 // Information about each layer.
 message LayerProto {
   // unique id per layer.
@@ -73,7 +90,7 @@
   int32 window_type = 33 [deprecated=true];
   int32 app_id = 34 [deprecated=true];
   // The layer's composition type
-  int32 hwc_composition_type = 35;
+  HwcCompositionType hwc_composition_type = 35;
   // If it's a buffer layer, indicate if the content is protected
   bool is_protected = 36;
   // Current frame number being rendered.
@@ -190,4 +207,4 @@
 message ColorTransformProto {
   // This will be a 4x4 matrix of float values
   repeated float val = 1;
-}
\ No newline at end of file
+}
diff --git a/services/surfaceflinger/layerproto/layerstrace.proto b/services/surfaceflinger/layerproto/layerstrace.proto
index bee17d2..ac33a0e 100644
--- a/services/surfaceflinger/layerproto/layerstrace.proto
+++ b/services/surfaceflinger/layerproto/layerstrace.proto
@@ -48,4 +48,7 @@
     optional string where = 2;
 
     optional LayersProto layers = 3;
+
+    // Blob for the current HWC information for all layers, reported by dumpsys.
+    optional string hwc_blob = 4;
 }
diff --git a/services/surfaceflinger/tests/unittests/LayerHistoryTestV2.cpp b/services/surfaceflinger/tests/unittests/LayerHistoryTestV2.cpp
index 959c256..37da76b 100644
--- a/services/surfaceflinger/tests/unittests/LayerHistoryTestV2.cpp
+++ b/services/surfaceflinger/tests/unittests/LayerHistoryTestV2.cpp
@@ -36,6 +36,7 @@
 protected:
     static constexpr auto PRESENT_TIME_HISTORY_SIZE = LayerInfoV2::HISTORY_SIZE;
     static constexpr auto MAX_FREQUENT_LAYER_PERIOD_NS = LayerInfoV2::MAX_FREQUENT_LAYER_PERIOD_NS;
+    static constexpr auto FREQUENT_LAYER_WINDOW_SIZE = LayerInfoV2::FREQUENT_LAYER_WINDOW_SIZE;
 
     static constexpr float LO_FPS = 30.f;
     static constexpr auto LO_FPS_PERIOD = static_cast<nsecs_t>(1e9f / LO_FPS);
@@ -451,5 +452,61 @@
     EXPECT_EQ(0, frequentLayerCount(time));
 }
 
+TEST_F(LayerHistoryTestV2, inactiveLayers) {
+    auto layer = createLayer();
+
+    EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(true));
+    EXPECT_CALL(*layer, getFrameRate()).WillRepeatedly(Return(Layer::FrameRate()));
+
+    nsecs_t time = systemTime();
+
+    // the very first updates makes the layer frequent
+    for (int i = 0; i < FREQUENT_LAYER_WINDOW_SIZE - 1; i++) {
+        history().record(layer.get(), time, time);
+        time += MAX_FREQUENT_LAYER_PERIOD_NS.count();
+
+        EXPECT_EQ(1, layerCount());
+        ASSERT_EQ(1, history().summarize(time).size());
+        EXPECT_EQ(LayerHistory::LayerVoteType::Max, history().summarize(time)[0].vote);
+        EXPECT_EQ(1, activeLayerCount());
+        EXPECT_EQ(1, frequentLayerCount(time));
+    }
+
+    // the next update with the MAX_FREQUENT_LAYER_PERIOD_NS will get us to infrequent
+    history().record(layer.get(), time, time);
+    time += MAX_FREQUENT_LAYER_PERIOD_NS.count();
+
+    EXPECT_EQ(1, layerCount());
+    ASSERT_EQ(1, history().summarize(time).size());
+    EXPECT_EQ(LayerHistory::LayerVoteType::Min, history().summarize(time)[0].vote);
+    EXPECT_EQ(1, activeLayerCount());
+    EXPECT_EQ(0, frequentLayerCount(time));
+
+    // advance the time for the previous frame to be inactive
+    time += MAX_ACTIVE_LAYER_PERIOD_NS.count();
+
+    // Now event if we post a quick few frame we should stay infrequent
+    for (int i = 0; i < FREQUENT_LAYER_WINDOW_SIZE - 1; i++) {
+        history().record(layer.get(), time, time);
+        time += HI_FPS_PERIOD;
+
+        EXPECT_EQ(1, layerCount());
+        ASSERT_EQ(1, history().summarize(time).size());
+        EXPECT_EQ(LayerHistory::LayerVoteType::Min, history().summarize(time)[0].vote);
+        EXPECT_EQ(1, activeLayerCount());
+        EXPECT_EQ(0, frequentLayerCount(time));
+    }
+
+    // More quick frames will get us to frequent again
+    history().record(layer.get(), time, time);
+    time += HI_FPS_PERIOD;
+
+    EXPECT_EQ(1, layerCount());
+    ASSERT_EQ(1, history().summarize(time).size());
+    EXPECT_EQ(LayerHistory::LayerVoteType::Max, history().summarize(time)[0].vote);
+    EXPECT_EQ(1, activeLayerCount());
+    EXPECT_EQ(1, frequentLayerCount(time));
+}
+
 } // namespace
 } // namespace android::scheduler
diff --git a/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp b/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp
index e7e7f66..4a179b6 100644
--- a/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp
+++ b/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp
@@ -93,8 +93,8 @@
     auto refreshRateConfigs =
             std::make_unique<RefreshRateConfigs>(configs, /*currentConfigId=*/HWC_CONFIG_ID_60);
 
-    const auto minRate = refreshRateConfigs->getMinRefreshRate();
-    const auto performanceRate = refreshRateConfigs->getMaxRefreshRate();
+    const auto& minRate = refreshRateConfigs->getMinRefreshRate();
+    const auto& performanceRate = refreshRateConfigs->getMaxRefreshRate();
 
     RefreshRate expectedDefaultConfig = {HWC_CONFIG_ID_60, VSYNC_60, HWC_GROUP_ID_0, "60fps", 60};
     ASSERT_EQ(expectedDefaultConfig, minRate);
@@ -102,8 +102,8 @@
                                              90};
     ASSERT_EQ(expectedPerformanceConfig, performanceRate);
 
-    const auto minRateByPolicy = refreshRateConfigs->getMinRefreshRateByPolicy();
-    const auto performanceRateByPolicy = refreshRateConfigs->getMaxRefreshRateByPolicy();
+    const auto& minRateByPolicy = refreshRateConfigs->getMinRefreshRateByPolicy();
+    const auto& performanceRateByPolicy = refreshRateConfigs->getMaxRefreshRateByPolicy();
     ASSERT_EQ(minRateByPolicy, minRate);
     ASSERT_EQ(performanceRateByPolicy, performanceRate);
 }
@@ -115,10 +115,10 @@
     auto refreshRateConfigs =
             std::make_unique<RefreshRateConfigs>(configs, /*currentConfigId=*/HWC_CONFIG_ID_60);
 
-    const auto minRate = refreshRateConfigs->getMinRefreshRateByPolicy();
-    const auto performanceRate = refreshRateConfigs->getMaxRefreshRate();
-    const auto minRate60 = refreshRateConfigs->getMinRefreshRateByPolicy();
-    const auto performanceRate60 = refreshRateConfigs->getMaxRefreshRateByPolicy();
+    const auto& minRate = refreshRateConfigs->getMinRefreshRateByPolicy();
+    const auto& performanceRate = refreshRateConfigs->getMaxRefreshRate();
+    const auto& minRate60 = refreshRateConfigs->getMinRefreshRateByPolicy();
+    const auto& performanceRate60 = refreshRateConfigs->getMaxRefreshRateByPolicy();
 
     RefreshRate expectedDefaultConfig = {HWC_CONFIG_ID_60, VSYNC_60, HWC_GROUP_ID_0, "60fps", 60};
     ASSERT_EQ(expectedDefaultConfig, minRate);
@@ -128,8 +128,8 @@
     ASSERT_GE(refreshRateConfigs->setPolicy(HWC_CONFIG_ID_90, 60, 90, nullptr), 0);
     refreshRateConfigs->setCurrentConfigId(HWC_CONFIG_ID_90);
 
-    const auto minRate90 = refreshRateConfigs->getMinRefreshRateByPolicy();
-    const auto performanceRate90 = refreshRateConfigs->getMaxRefreshRateByPolicy();
+    const auto& minRate90 = refreshRateConfigs->getMinRefreshRateByPolicy();
+    const auto& performanceRate90 = refreshRateConfigs->getMaxRefreshRateByPolicy();
 
     RefreshRate expectedPerformanceConfig = {HWC_CONFIG_ID_90, VSYNC_90, HWC_GROUP_ID_1, "90fps",
                                              90};
@@ -145,8 +145,8 @@
     auto refreshRateConfigs =
             std::make_unique<RefreshRateConfigs>(configs, /*currentConfigId=*/HWC_CONFIG_ID_60);
 
-    auto minRate = refreshRateConfigs->getMinRefreshRateByPolicy();
-    auto performanceRate = refreshRateConfigs->getMaxRefreshRateByPolicy();
+    auto& minRate = refreshRateConfigs->getMinRefreshRateByPolicy();
+    auto& performanceRate = refreshRateConfigs->getMaxRefreshRateByPolicy();
 
     RefreshRate expectedDefaultConfig = {HWC_CONFIG_ID_60, VSYNC_60, HWC_GROUP_ID_0, "60fps", 60};
     ASSERT_EQ(expectedDefaultConfig, minRate);
@@ -156,8 +156,8 @@
 
     ASSERT_GE(refreshRateConfigs->setPolicy(HWC_CONFIG_ID_60, 60, 60, nullptr), 0);
 
-    auto minRate60 = refreshRateConfigs->getMinRefreshRateByPolicy();
-    auto performanceRate60 = refreshRateConfigs->getMaxRefreshRateByPolicy();
+    auto& minRate60 = refreshRateConfigs->getMinRefreshRateByPolicy();
+    auto& performanceRate60 = refreshRateConfigs->getMaxRefreshRateByPolicy();
     ASSERT_EQ(expectedDefaultConfig, minRate60);
     ASSERT_EQ(expectedDefaultConfig, performanceRate60);
 }
@@ -169,19 +169,19 @@
     auto refreshRateConfigs =
             std::make_unique<RefreshRateConfigs>(configs, /*currentConfigId=*/HWC_CONFIG_ID_60);
     {
-        auto current = refreshRateConfigs->getCurrentRefreshRate();
+        auto& current = refreshRateConfigs->getCurrentRefreshRate();
         EXPECT_EQ(current.configId, HWC_CONFIG_ID_60);
     }
 
     refreshRateConfigs->setCurrentConfigId(HWC_CONFIG_ID_90);
     {
-        auto current = refreshRateConfigs->getCurrentRefreshRate();
+        auto& current = refreshRateConfigs->getCurrentRefreshRate();
         EXPECT_EQ(current.configId, HWC_CONFIG_ID_90);
     }
 
     ASSERT_GE(refreshRateConfigs->setPolicy(HWC_CONFIG_ID_90, 90, 90, nullptr), 0);
     {
-        auto current = refreshRateConfigs->getCurrentRefreshRate();
+        auto& current = refreshRateConfigs->getCurrentRefreshRate();
         EXPECT_EQ(current.configId, HWC_CONFIG_ID_90);
     }
 }