Merge "[RoundedCorners] Avoid using invalid crop." into qt-dev
diff --git a/libs/gui/BufferQueueConsumer.cpp b/libs/gui/BufferQueueConsumer.cpp
index 776c6e6..e226136 100644
--- a/libs/gui/BufferQueueConsumer.cpp
+++ b/libs/gui/BufferQueueConsumer.cpp
@@ -190,6 +190,7 @@
                         desiredPresent - expectedPresent,
                         systemTime(CLOCK_MONOTONIC),
                         front->mFrameNumber, maxFrameNumber);
+                ATRACE_NAME("PRESENT_LATER");
                 return PRESENT_LATER;
             }
 
diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp
index b586bf3..a3165dd 100644
--- a/libs/gui/ISurfaceComposer.cpp
+++ b/libs/gui/ISurfaceComposer.cpp
@@ -109,7 +109,7 @@
     }
 
     virtual status_t captureScreen(const sp<IBinder>& display, sp<GraphicBuffer>* outBuffer,
-                                   const ui::Dataspace reqDataspace,
+                                   bool& outCapturedSecureLayers, const ui::Dataspace reqDataspace,
                                    const ui::PixelFormat reqPixelFormat, Rect sourceCrop,
                                    uint32_t reqWidth, uint32_t reqHeight, bool useIdentityTransform,
                                    ISurfaceComposer::Rotation rotation, bool captureSecureLayers) {
@@ -137,20 +137,27 @@
 
         *outBuffer = new GraphicBuffer();
         reply.read(**outBuffer);
+        outCapturedSecureLayers = reply.readBool();
 
         return result;
     }
 
-    virtual status_t captureLayers(const sp<IBinder>& layerHandleBinder,
-                                   sp<GraphicBuffer>* outBuffer, const ui::Dataspace reqDataspace,
-                                   const ui::PixelFormat reqPixelFormat, const Rect& sourceCrop,
-                                   float frameScale, bool childrenOnly) {
+    virtual status_t captureLayers(
+            const sp<IBinder>& layerHandleBinder, sp<GraphicBuffer>* outBuffer,
+            const ui::Dataspace reqDataspace, const ui::PixelFormat reqPixelFormat,
+            const Rect& sourceCrop,
+            const std::unordered_set<sp<IBinder>, SpHash<IBinder>>& excludeLayers, float frameScale,
+            bool childrenOnly) {
         Parcel data, reply;
         data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
         data.writeStrongBinder(layerHandleBinder);
         data.writeInt32(static_cast<int32_t>(reqDataspace));
         data.writeInt32(static_cast<int32_t>(reqPixelFormat));
         data.write(sourceCrop);
+        data.writeInt32(excludeLayers.size());
+        for (auto el : excludeLayers) {
+            data.writeStrongBinder(el);
+        }
         data.writeFloat(frameScale);
         data.writeBool(childrenOnly);
         status_t result = remote()->transact(BnSurfaceComposer::CAPTURE_LAYERS, data, &reply);
@@ -1021,12 +1028,17 @@
             int32_t rotation = data.readInt32();
             bool captureSecureLayers = static_cast<bool>(data.readInt32());
 
-            status_t res = captureScreen(display, &outBuffer, reqDataspace, reqPixelFormat,
-                                         sourceCrop, reqWidth, reqHeight, useIdentityTransform,
-                                         static_cast<ISurfaceComposer::Rotation>(rotation), captureSecureLayers);
+            bool capturedSecureLayers = false;
+            status_t res = captureScreen(display, &outBuffer, capturedSecureLayers, reqDataspace,
+                                         reqPixelFormat, sourceCrop, reqWidth, reqHeight,
+                                         useIdentityTransform,
+                                         static_cast<ISurfaceComposer::Rotation>(rotation),
+                                         captureSecureLayers);
+
             reply->writeInt32(res);
             if (res == NO_ERROR) {
                 reply->write(*outBuffer);
+                reply->writeBool(capturedSecureLayers);
             }
             return NO_ERROR;
         }
@@ -1038,11 +1050,20 @@
             sp<GraphicBuffer> outBuffer;
             Rect sourceCrop(Rect::EMPTY_RECT);
             data.read(sourceCrop);
+
+            std::unordered_set<sp<IBinder>, SpHash<IBinder>> excludeHandles;
+            int numExcludeHandles = data.readInt32();
+            excludeHandles.reserve(numExcludeHandles);
+            for (int i = 0; i < numExcludeHandles; i++) {
+                excludeHandles.emplace(data.readStrongBinder());
+            }
+
             float frameScale = data.readFloat();
             bool childrenOnly = data.readBool();
 
-            status_t res = captureLayers(layerHandleBinder, &outBuffer, reqDataspace,
-                                         reqPixelFormat, sourceCrop, frameScale, childrenOnly);
+            status_t res =
+                    captureLayers(layerHandleBinder, &outBuffer, reqDataspace, reqPixelFormat,
+                                  sourceCrop, excludeHandles, frameScale, childrenOnly);
             reply->writeInt32(res);
             if (res == NO_ERROR) {
                 reply->write(*outBuffer);
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index 83cf40c..611da89 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -1542,13 +1542,15 @@
 status_t ScreenshotClient::capture(const sp<IBinder>& display, const ui::Dataspace reqDataSpace,
                                    const ui::PixelFormat reqPixelFormat, Rect sourceCrop,
                                    uint32_t reqWidth, uint32_t reqHeight, bool useIdentityTransform,
-                                   uint32_t rotation, bool captureSecureLayers, sp<GraphicBuffer>* outBuffer) {
+                                   uint32_t rotation, bool captureSecureLayers,
+                                   sp<GraphicBuffer>* outBuffer, bool& outCapturedSecureLayers) {
     sp<ISurfaceComposer> s(ComposerService::getComposerService());
     if (s == nullptr) return NO_INIT;
-    status_t ret = s->captureScreen(display, outBuffer, reqDataSpace, reqPixelFormat, sourceCrop,
-            reqWidth, reqHeight, useIdentityTransform,
-            static_cast<ISurfaceComposer::Rotation>(rotation),
-            captureSecureLayers);
+    status_t ret =
+            s->captureScreen(display, outBuffer, outCapturedSecureLayers, reqDataSpace,
+                             reqPixelFormat, sourceCrop, reqWidth, reqHeight, useIdentityTransform,
+                             static_cast<ISurfaceComposer::Rotation>(rotation),
+                             captureSecureLayers);
     if (ret != NO_ERROR) {
         return ret;
     }
@@ -1559,8 +1561,9 @@
                                    const ui::PixelFormat reqPixelFormat, Rect sourceCrop,
                                    uint32_t reqWidth, uint32_t reqHeight, bool useIdentityTransform,
                                    uint32_t rotation, sp<GraphicBuffer>* outBuffer) {
-    return capture(display, reqDataSpace, reqPixelFormat, sourceCrop, reqWidth,
-            reqHeight, useIdentityTransform, rotation, false, outBuffer);
+    bool ignored;
+    return capture(display, reqDataSpace, reqPixelFormat, sourceCrop, reqWidth, reqHeight,
+                   useIdentityTransform, rotation, false, outBuffer, ignored);
 }
 
 status_t ScreenshotClient::captureLayers(const sp<IBinder>& layerHandle,
@@ -1570,18 +1573,20 @@
     sp<ISurfaceComposer> s(ComposerService::getComposerService());
     if (s == nullptr) return NO_INIT;
     status_t ret = s->captureLayers(layerHandle, outBuffer, reqDataSpace, reqPixelFormat,
-                                    sourceCrop, frameScale, false /* childrenOnly */);
+                                    sourceCrop, {}, frameScale, false /* childrenOnly */);
     return ret;
 }
 
-status_t ScreenshotClient::captureChildLayers(const sp<IBinder>& layerHandle,
-                                              const ui::Dataspace reqDataSpace,
-                                              const ui::PixelFormat reqPixelFormat, Rect sourceCrop,
-                                              float frameScale, sp<GraphicBuffer>* outBuffer) {
+status_t ScreenshotClient::captureChildLayers(
+        const sp<IBinder>& layerHandle, const ui::Dataspace reqDataSpace,
+        const ui::PixelFormat reqPixelFormat, Rect sourceCrop,
+        const std::unordered_set<sp<IBinder>, ISurfaceComposer::SpHash<IBinder>>& excludeHandles,
+        float frameScale, sp<GraphicBuffer>* outBuffer) {
     sp<ISurfaceComposer> s(ComposerService::getComposerService());
     if (s == nullptr) return NO_INIT;
-    status_t ret = s->captureLayers(layerHandle, outBuffer, reqDataSpace, reqPixelFormat,
-                                    sourceCrop, frameScale, true /* childrenOnly */);
+    status_t ret =
+            s->captureLayers(layerHandle, outBuffer, reqDataSpace, reqPixelFormat, sourceCrop,
+                             excludeHandles, frameScale, true /* childrenOnly */);
     return ret;
 }
 // ----------------------------------------------------------------------------
diff --git a/libs/gui/bufferqueue/2.0/types.cpp b/libs/gui/bufferqueue/2.0/types.cpp
index a110517..cbd6cad 100644
--- a/libs/gui/bufferqueue/2.0/types.cpp
+++ b/libs/gui/bufferqueue/2.0/types.cpp
@@ -289,6 +289,7 @@
         return false;
     }
     *to = GraphicBuffer::fromAHardwareBuffer(hwBuffer);
+    AHardwareBuffer_release(hwBuffer);
     return true;
 }
 
diff --git a/libs/gui/bufferqueue/OWNERS b/libs/gui/bufferqueue/OWNERS
new file mode 100644
index 0000000..cbe9317
--- /dev/null
+++ b/libs/gui/bufferqueue/OWNERS
@@ -0,0 +1,5 @@
+chz@google.com
+lajos@google.com
+pawin@google.com
+taklee@google.com
+wonsik@google.com
diff --git a/libs/gui/include/gui/ISurfaceComposer.h b/libs/gui/include/gui/ISurfaceComposer.h
index fe85fdf..415b2d5 100644
--- a/libs/gui/include/gui/ISurfaceComposer.h
+++ b/libs/gui/include/gui/ISurfaceComposer.h
@@ -20,6 +20,7 @@
 #include <stdint.h>
 #include <sys/types.h>
 
+#include <binder/IBinder.h>
 #include <binder/IInterface.h>
 
 #include <gui/ITransactionCompletedListener.h>
@@ -37,6 +38,7 @@
 #include <utils/Vector.h>
 
 #include <optional>
+#include <unordered_set>
 #include <vector>
 
 namespace android {
@@ -210,7 +212,7 @@
      * it) around its center.
      */
     virtual status_t captureScreen(const sp<IBinder>& display, sp<GraphicBuffer>* outBuffer,
-                                   const ui::Dataspace reqDataspace,
+                                   bool& outCapturedSecureLayers, const ui::Dataspace reqDataspace,
                                    const ui::PixelFormat reqPixelFormat, Rect sourceCrop,
                                    uint32_t reqWidth, uint32_t reqHeight, bool useIdentityTransform,
                                    Rotation rotation = eRotateNone,
@@ -239,10 +241,17 @@
     virtual status_t captureScreen(const sp<IBinder>& display, sp<GraphicBuffer>* outBuffer,
                                    Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight,
                                    bool useIdentityTransform, Rotation rotation = eRotateNone) {
-        return captureScreen(display, outBuffer, ui::Dataspace::V0_SRGB, ui::PixelFormat::RGBA_8888,
-                             sourceCrop, reqWidth, reqHeight, useIdentityTransform, rotation);
+        bool outIgnored;
+        return captureScreen(display, outBuffer, outIgnored, ui::Dataspace::V0_SRGB,
+                             ui::PixelFormat::RGBA_8888, sourceCrop, reqWidth, reqHeight,
+                             useIdentityTransform, rotation);
     }
 
+    template <class AA>
+    struct SpHash {
+        size_t operator()(const sp<AA>& k) const { return std::hash<AA*>()(k.get()); }
+    };
+
     /**
      * Capture a subtree of the layer hierarchy, potentially ignoring the root node.
      *
@@ -250,10 +259,12 @@
      * of the buffer. The caller should pick the data space and pixel format
      * that it can consume.
      */
-    virtual status_t captureLayers(const sp<IBinder>& layerHandleBinder,
-                                   sp<GraphicBuffer>* outBuffer, const ui::Dataspace reqDataspace,
-                                   const ui::PixelFormat reqPixelFormat, const Rect& sourceCrop,
-                                   float frameScale = 1.0, bool childrenOnly = false) = 0;
+    virtual status_t captureLayers(
+            const sp<IBinder>& layerHandleBinder, sp<GraphicBuffer>* outBuffer,
+            const ui::Dataspace reqDataspace, const ui::PixelFormat reqPixelFormat,
+            const Rect& sourceCrop,
+            const std::unordered_set<sp<IBinder>, SpHash<IBinder>>& excludeHandles,
+            float frameScale = 1.0, bool childrenOnly = false) = 0;
 
     /**
      * Capture a subtree of the layer hierarchy into an sRGB buffer with RGBA_8888 pixel format,
@@ -263,7 +274,7 @@
                            const Rect& sourceCrop, float frameScale = 1.0,
                            bool childrenOnly = false) {
         return captureLayers(layerHandleBinder, outBuffer, ui::Dataspace::V0_SRGB,
-                             ui::PixelFormat::RGBA_8888, sourceCrop, frameScale, childrenOnly);
+                             ui::PixelFormat::RGBA_8888, sourceCrop, {}, frameScale, childrenOnly);
     }
 
     /* Clears the frame statistics for animations.
diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h
index 593a5e7..9d34468 100644
--- a/libs/gui/include/gui/SurfaceComposerClient.h
+++ b/libs/gui/include/gui/SurfaceComposerClient.h
@@ -37,6 +37,7 @@
 #include <ui/PixelFormat.h>
 
 #include <gui/CpuConsumer.h>
+#include <gui/ISurfaceComposer.h>
 #include <gui/ITransactionCompletedListener.h>
 #include <gui/LayerState.h>
 #include <gui/SurfaceControl.h>
@@ -508,7 +509,8 @@
     static status_t capture(const sp<IBinder>& display, const ui::Dataspace reqDataSpace,
                             const ui::PixelFormat reqPixelFormat, Rect sourceCrop,
                             uint32_t reqWidth, uint32_t reqHeight, bool useIdentityTransform,
-                            uint32_t rotation, bool captureSecureLayers, sp<GraphicBuffer>* outBuffer);
+                            uint32_t rotation, bool captureSecureLayers,
+                            sp<GraphicBuffer>* outBuffer, bool& outCapturedSecureLayers);
     static status_t capture(const sp<IBinder>& display, const ui::Dataspace reqDataSpace,
                             const ui::PixelFormat reqPixelFormat, Rect sourceCrop,
                             uint32_t reqWidth, uint32_t reqHeight, bool useIdentityTransform,
@@ -516,10 +518,12 @@
     static status_t captureLayers(const sp<IBinder>& layerHandle, const ui::Dataspace reqDataSpace,
                                   const ui::PixelFormat reqPixelFormat, Rect sourceCrop,
                                   float frameScale, sp<GraphicBuffer>* outBuffer);
-    static status_t captureChildLayers(const sp<IBinder>& layerHandle,
-                                       const ui::Dataspace reqDataSpace,
-                                       const ui::PixelFormat reqPixelFormat, Rect sourceCrop,
-                                       float frameScale, sp<GraphicBuffer>* outBuffer);
+    static status_t captureChildLayers(
+            const sp<IBinder>& layerHandle, const ui::Dataspace reqDataSpace,
+            const ui::PixelFormat reqPixelFormat, Rect sourceCrop,
+            const std::unordered_set<sp<IBinder>, ISurfaceComposer::SpHash<IBinder>>&
+                    excludeHandles,
+            float frameScale, sp<GraphicBuffer>* outBuffer);
 };
 
 // ---------------------------------------------------------------------------
diff --git a/libs/gui/include/gui/SurfaceControl.h b/libs/gui/include/gui/SurfaceControl.h
index 55efcbf..23bfc02 100644
--- a/libs/gui/include/gui/SurfaceControl.h
+++ b/libs/gui/include/gui/SurfaceControl.h
@@ -84,6 +84,9 @@
     
     explicit SurfaceControl(const sp<SurfaceControl>& other);
 
+    SurfaceControl(const sp<SurfaceComposerClient>& client, const sp<IBinder>& handle,
+                   const sp<IGraphicBufferProducer>& gbp, bool owned);
+
 private:
     // can't be copied
     SurfaceControl& operator = (SurfaceControl& rhs);
@@ -92,12 +95,6 @@
     friend class SurfaceComposerClient;
     friend class Surface;
 
-    SurfaceControl(
-            const sp<SurfaceComposerClient>& client,
-            const sp<IBinder>& handle,
-            const sp<IGraphicBufferProducer>& gbp,
-            bool owned);
-
     ~SurfaceControl();
 
     sp<Surface> generateSurfaceLocked() const;
diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp
index 0ee9bff..d5bdd74 100644
--- a/libs/gui/tests/Surface_test.cpp
+++ b/libs/gui/tests/Surface_test.cpp
@@ -126,7 +126,7 @@
 }
 
 // This test probably doesn't belong here.
-TEST_F(SurfaceTest, ScreenshotsOfProtectedBuffersSucceed) {
+TEST_F(SurfaceTest, ScreenshotsOfProtectedBuffersDontSucceed) {
     sp<ANativeWindow> anw(mSurface);
 
     // Verify the screenshot works with no protected buffers.
@@ -136,8 +136,9 @@
     ASSERT_FALSE(display == nullptr);
 
     sp<GraphicBuffer> outBuffer;
+    bool ignored;
     ASSERT_EQ(NO_ERROR,
-              sf->captureScreen(display, &outBuffer, ui::Dataspace::V0_SRGB,
+              sf->captureScreen(display, &outBuffer, ignored, ui::Dataspace::V0_SRGB,
                                 ui::PixelFormat::RGBA_8888, Rect(), 64, 64, false));
 
     ASSERT_EQ(NO_ERROR, native_window_api_connect(anw.get(),
@@ -169,7 +170,7 @@
         ASSERT_EQ(NO_ERROR, anw->queueBuffer(anw.get(), buf, -1));
     }
     ASSERT_EQ(NO_ERROR,
-              sf->captureScreen(display, &outBuffer, ui::Dataspace::V0_SRGB,
+              sf->captureScreen(display, &outBuffer, ignored, ui::Dataspace::V0_SRGB,
                                 ui::PixelFormat::RGBA_8888, Rect(), 64, 64, false));
 }
 
@@ -615,6 +616,7 @@
     status_t setActiveColorMode(const sp<IBinder>& /*display*/,
         ColorMode /*colorMode*/) override { return NO_ERROR; }
     status_t captureScreen(const sp<IBinder>& /*display*/, sp<GraphicBuffer>* /*outBuffer*/,
+                           bool& /* outCapturedSecureLayers */,
                            const ui::Dataspace /*reqDataspace*/,
                            const ui::PixelFormat /*reqPixelFormat*/, Rect /*sourceCrop*/,
                            uint32_t /*reqWidth*/, uint32_t /*reqHeight*/,
@@ -622,12 +624,13 @@
                            bool /*captureSecureLayers*/) override {
         return NO_ERROR;
     }
-    virtual status_t captureLayers(const sp<IBinder>& /*parentHandle*/,
-                                   sp<GraphicBuffer>* /*outBuffer*/,
-                                   const ui::Dataspace /*reqDataspace*/,
-                                   const ui::PixelFormat /*reqPixelFormat*/,
-                                   const Rect& /*sourceCrop*/, float /*frameScale*/,
-                                   bool /*childrenOnly*/) override {
+    virtual status_t captureLayers(
+            const sp<IBinder>& /*parentHandle*/, sp<GraphicBuffer>* /*outBuffer*/,
+            const ui::Dataspace /*reqDataspace*/, const ui::PixelFormat /*reqPixelFormat*/,
+            const Rect& /*sourceCrop*/,
+            const std::unordered_set<sp<IBinder>,
+                                     ISurfaceComposer::SpHash<IBinder>>& /*excludeHandles*/,
+            float /*frameScale*/, bool /*childrenOnly*/) override {
         return NO_ERROR;
     }
     status_t clearAnimationFrameStats() override { return NO_ERROR; }
diff --git a/opengl/tools/glgen/specs/egl/EGL15.spec b/opengl/tools/glgen/specs/egl/EGL15.spec
index e0aad30..5c48a15 100644
--- a/opengl/tools/glgen/specs/egl/EGL15.spec
+++ b/opengl/tools/glgen/specs/egl/EGL15.spec
@@ -1,7 +1,8 @@
 EGLSync eglCreateSync ( EGLDisplay dpy, EGLenum type, const EGLAttrib *attrib_list )
+// eglGetSyncAttrib pulled in with eglCreateSync stubs
+// EGLBoolean eglGetSyncAttrib ( EGLDisplay dpy, EGLSync sync, EGLint attribute, EGLAttrib *value )
 EGLBoolean eglDestroySync ( EGLDisplay dpy, EGLSync sync )
 EGLint eglClientWaitSync ( EGLDisplay dpy, EGLSync sync, EGLint flags, EGLTime timeout )
-EGLBoolean eglGetSyncAttrib ( EGLDisplay dpy, EGLSync sync, EGLint attribute, EGLAttrib *value )
 // NOTE: native_display isn't actually an EGLAttrib. Using EGLAttrib
 // so that the generate creates mostly correct code (do not want a buffer)
 // have to manually change cast to (void *) in generated code that calls
diff --git a/opengl/tools/glgen/stubs/egl/EGL15cHeader.cpp b/opengl/tools/glgen/stubs/egl/EGL15cHeader.cpp
index 1c53c9e..8bb0c6a 100644
--- a/opengl/tools/glgen/stubs/egl/EGL15cHeader.cpp
+++ b/opengl/tools/glgen/stubs/egl/EGL15cHeader.cpp
@@ -25,6 +25,7 @@
 #include <utils/misc.h>
 
 #include <assert.h>
+#include <vector>
 #include <EGL/egl.h>
 
 #include <ui/ANativeObjectBase.h>
@@ -206,4 +207,22 @@
     return _env->NewObject(cls, con, reinterpret_cast<jlong>(handle));
 }
 
+struct WrappedEGLAttribs {
+private:
+    std::vector<EGLAttrib> backing; // only for 32-bit
+public:
+    EGLAttrib *attribs;
+    WrappedEGLAttribs(): attribs(nullptr) { };
+    void init(jlong *array, jint size) {
+        if (sizeof(EGLAttrib) != sizeof(jlong)) {
+            for (jint i = 0; i < size; ++i) {
+                backing.push_back(array[i]);
+            }
+            attribs = backing.data();
+        } else {
+            attribs = (EGLAttrib*)array;
+        }
+    }
+};
+
 // --------------------------------------------------------------------------
diff --git a/opengl/tools/glgen/stubs/egl/eglCreateImage.cpp b/opengl/tools/glgen/stubs/egl/eglCreateImage.cpp
new file mode 100644
index 0000000..f93815c
--- /dev/null
+++ b/opengl/tools/glgen/stubs/egl/eglCreateImage.cpp
@@ -0,0 +1,50 @@
+/* EGLImage eglCreateImage ( EGLDisplay dpy, EGLContext context, EGLenum target, EGLClientBuffer buffer, const EGLAttrib *attrib_list ) */
+static jobject
+android_eglCreateImage
+  (JNIEnv *_env, jobject _this, jobject dpy, jobject context, jint target, jlong buffer, jlongArray attrib_list_ref, jint offset) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
+    EGLImage _returnValue = (EGLImage) 0;
+    EGLDisplay dpy_native = (EGLDisplay) fromEGLHandle(_env, egldisplayGetHandleID, dpy);
+    EGLContext context_native = (EGLContext) fromEGLHandle(_env, eglcontextGetHandleID, context);
+    jlong *attrib_list_base = (jlong *) 0;
+    jint _remaining;
+    WrappedEGLAttribs attrib_list;
+
+    if (!attrib_list_ref) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "attrib_list == null";
+        goto exit;
+    }
+    if (offset < 0) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "offset < 0";
+        goto exit;
+    }
+    _remaining = _env->GetArrayLength(attrib_list_ref) - offset;
+    attrib_list_base = (jlong *)
+        _env->GetLongArrayElements(attrib_list_ref, (jboolean *)0);
+    attrib_list.init(attrib_list_base + offset, _remaining);
+
+    _returnValue = eglCreateImage(
+        (EGLDisplay)dpy_native,
+        (EGLContext)context_native,
+        (EGLenum)target,
+        (EGLClientBuffer)buffer,
+        attrib_list.attribs
+    );
+
+exit:
+    if (attrib_list_base) {
+        _env->ReleaseLongArrayElements(attrib_list_ref, (jlong*)attrib_list_base,
+            JNI_ABORT);
+    }
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
+        return nullptr;
+    }
+    return toEGLHandle(_env, eglimageClass, eglimageConstructor, _returnValue);
+}
diff --git a/opengl/tools/glgen/stubs/egl/eglCreateImage.java b/opengl/tools/glgen/stubs/egl/eglCreateImage.java
new file mode 100644
index 0000000..06a04bb
--- /dev/null
+++ b/opengl/tools/glgen/stubs/egl/eglCreateImage.java
@@ -0,0 +1,11 @@
+    // C function EGLImage eglCreateImage ( EGLDisplay dpy, EGLContext context, EGLenum target, EGLClientBuffer buffer, const EGLAttrib *attrib_list )
+
+    public static native EGLImage eglCreateImage(
+        EGLDisplay dpy,
+        EGLContext context,
+        int target,
+        long buffer,
+        long[] attrib_list,
+        int offset
+    );
+
diff --git a/opengl/tools/glgen/stubs/egl/eglCreateImage.nativeReg b/opengl/tools/glgen/stubs/egl/eglCreateImage.nativeReg
new file mode 100644
index 0000000..da5687d
--- /dev/null
+++ b/opengl/tools/glgen/stubs/egl/eglCreateImage.nativeReg
@@ -0,0 +1 @@
+{"eglCreateImage", "(Landroid/opengl/EGLDisplay;Landroid/opengl/EGLContext;IJ[JI)Landroid/opengl/EGLImage;", (void *) android_eglCreateImage },
diff --git a/opengl/tools/glgen/stubs/egl/eglCreatePlatformWindowSurface.cpp b/opengl/tools/glgen/stubs/egl/eglCreatePlatformWindowSurface.cpp
new file mode 100644
index 0000000..48dbd35
--- /dev/null
+++ b/opengl/tools/glgen/stubs/egl/eglCreatePlatformWindowSurface.cpp
@@ -0,0 +1,68 @@
+/* EGLSurface eglCreatePlatformWindowSurface ( EGLDisplay dpy, EGLConfig config, void *native_window, const EGLAttrib *attrib_list ) */
+static jobject
+android_eglCreatePlatformWindowSurface
+  (JNIEnv *_env, jobject _this, jobject dpy, jobject config, jobject native_window_buf, jlongArray attrib_list_ref, jint offset) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
+    jarray _array = (jarray) 0;
+    jint _bufferOffset = (jint) 0;
+    EGLSurface _returnValue = (EGLSurface) 0;
+    EGLDisplay dpy_native = (EGLDisplay) fromEGLHandle(_env, egldisplayGetHandleID, dpy);
+    EGLConfig config_native = (EGLConfig) fromEGLHandle(_env, eglconfigGetHandleID, config);
+    jint _native_windowRemaining;
+    void *native_window = (void *) 0;
+    jlong *attrib_list_base = (jlong *) 0;
+    jint _attrib_listRemaining;
+    WrappedEGLAttribs attrib_list;
+
+    if (!native_window_buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "native_window == null";
+        goto exit;
+    }
+    native_window = (void *)getPointer(_env, native_window_buf, (jarray*)&_array, &_native_windowRemaining, &_bufferOffset);
+    if (!attrib_list_ref) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "attrib_list == null";
+        goto exit;
+    }
+    if (offset < 0) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "offset < 0";
+        goto exit;
+    }
+    _attrib_listRemaining = _env->GetArrayLength(attrib_list_ref) - offset;
+    attrib_list_base = (jlong *)
+        _env->GetLongArrayElements(attrib_list_ref, (jboolean *)0);
+    attrib_list.init(attrib_list_base + offset, _attrib_listRemaining);
+
+    if (native_window == NULL) {
+        char * _native_windowBase = (char *)_env->GetPrimitiveArrayCritical(_array, (jboolean *) 0);
+        native_window = (void *) (_native_windowBase + _bufferOffset);
+    }
+    _returnValue = eglCreatePlatformWindowSurface(
+        (EGLDisplay)dpy_native,
+        (EGLConfig)config_native,
+        (void *)native_window,
+        attrib_list.attribs
+    );
+
+exit:
+    if (attrib_list_base) {
+        _env->ReleaseLongArrayElements(attrib_list_ref, (jlong*)attrib_list_base,
+            JNI_ABORT);
+    }
+    if (_array) {
+        releasePointer(_env, _array, native_window, _exception ? JNI_FALSE : JNI_TRUE);
+    }
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
+        return nullptr;
+    }
+    return toEGLHandle(_env, eglsurfaceClass, eglsurfaceConstructor, _returnValue);
+}
+
diff --git a/opengl/tools/glgen/stubs/egl/eglCreatePlatformWindowSurface.java b/opengl/tools/glgen/stubs/egl/eglCreatePlatformWindowSurface.java
new file mode 100644
index 0000000..dda37f8
--- /dev/null
+++ b/opengl/tools/glgen/stubs/egl/eglCreatePlatformWindowSurface.java
@@ -0,0 +1,10 @@
+    // C function EGLSurface eglCreatePlatformWindowSurface ( EGLDisplay dpy, EGLConfig config, void *native_window, const EGLAttrib *attrib_list )
+
+    public static native EGLSurface eglCreatePlatformWindowSurface(
+        EGLDisplay dpy,
+        EGLConfig config,
+        java.nio.Buffer native_window,
+        long[] attrib_list,
+        int offset
+    );
+
diff --git a/opengl/tools/glgen/stubs/egl/eglCreatePlatformWindowSurface.nativeReg b/opengl/tools/glgen/stubs/egl/eglCreatePlatformWindowSurface.nativeReg
new file mode 100644
index 0000000..ce464e8
--- /dev/null
+++ b/opengl/tools/glgen/stubs/egl/eglCreatePlatformWindowSurface.nativeReg
@@ -0,0 +1 @@
+{"eglCreatePlatformWindowSurface", "(Landroid/opengl/EGLDisplay;Landroid/opengl/EGLConfig;Ljava/nio/Buffer;[JI)Landroid/opengl/EGLSurface;", (void *) android_eglCreatePlatformWindowSurface },
diff --git a/opengl/tools/glgen/stubs/egl/eglCreateSync.cpp b/opengl/tools/glgen/stubs/egl/eglCreateSync.cpp
new file mode 100644
index 0000000..c53afea
--- /dev/null
+++ b/opengl/tools/glgen/stubs/egl/eglCreateSync.cpp
@@ -0,0 +1,101 @@
+/* EGLSync eglCreateSync ( EGLDisplay dpy, EGLenum type, const EGLAttrib *attrib_list ) */
+static jobject
+android_eglCreateSync
+  (JNIEnv *_env, jobject _this, jobject dpy, jint type, jlongArray attrib_list_ref, jint offset) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
+    EGLSync _returnValue = (EGLSync) 0;
+    EGLDisplay dpy_native = (EGLDisplay) fromEGLHandle(_env, egldisplayGetHandleID, dpy);
+    jlong *attrib_list_base = (jlong *) 0;
+    jint _remaining;
+    WrappedEGLAttribs attrib_list;
+
+    if (!attrib_list_ref) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "attrib_list == null";
+        goto exit;
+    }
+    if (offset < 0) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "offset < 0";
+        goto exit;
+    }
+    _remaining = _env->GetArrayLength(attrib_list_ref) - offset;
+    attrib_list_base = (jlong *)
+        _env->GetLongArrayElements(attrib_list_ref, (jboolean *)0);
+    attrib_list.init(attrib_list_base + offset, _remaining);
+
+    _returnValue = eglCreateSync(
+        (EGLDisplay)dpy_native,
+        (EGLenum)type,
+        attrib_list.attribs
+    );
+
+exit:
+    if (attrib_list_base) {
+        _env->ReleaseLongArrayElements(attrib_list_ref, (jlong*)attrib_list_base,
+            JNI_ABORT);
+    }
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
+        return nullptr;
+    }
+    return toEGLHandle(_env, eglsyncClass, eglsyncConstructor, _returnValue);
+}
+
+/* EGLBoolean eglGetSyncAttrib ( EGLDisplay dpy, EGLSync sync, EGLint attribute, EGLAttrib *value ) */
+static jboolean
+android_eglGetSyncAttrib
+  (JNIEnv *_env, jobject _this, jobject dpy, jobject sync, jint attribute, jlongArray value_ref, jint offset) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
+    EGLBoolean _returnValue = (EGLBoolean) 0;
+    EGLDisplay dpy_native = (EGLDisplay) fromEGLHandle(_env, egldisplayGetHandleID, dpy);
+    EGLSync sync_native = (EGLSync) fromEGLHandle(_env, eglsyncGetHandleID, sync);
+    jlong *value_base = (jlong *) 0;
+    jint _remaining;
+    EGLAttrib value;
+
+    if (!value_ref) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "value == null";
+        goto exit;
+    }
+    if (offset < 0) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "offset < 0";
+        goto exit;
+    }
+    _remaining = _env->GetArrayLength(value_ref) - offset;
+    value_base = (jlong *)
+        _env->GetLongArrayElements(value_ref, (jboolean *)0);
+
+    _returnValue = eglGetSyncAttrib(
+        (EGLDisplay)dpy_native,
+        (EGLSync)sync_native,
+        (EGLint)attribute,
+        &value
+    );
+
+    if (value_base && _returnValue == EGL_TRUE) {
+        *(value_base + offset) = (jlong) value;
+    }
+
+exit:
+    if (value_base) {
+        _env->ReleaseLongArrayElements(value_ref, (jlong*)value_base,
+            _exception ? JNI_ABORT: 0);
+    }
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
+        return JNI_FALSE;
+    }
+    return (jboolean)_returnValue;
+}
+
diff --git a/opengl/tools/glgen/stubs/egl/eglCreateSync.java b/opengl/tools/glgen/stubs/egl/eglCreateSync.java
new file mode 100644
index 0000000..db8f728
--- /dev/null
+++ b/opengl/tools/glgen/stubs/egl/eglCreateSync.java
@@ -0,0 +1,22 @@
+    // C function EGLSync eglCreateSync ( EGLDisplay dpy, EGLenum type, const EGLAttrib *attrib_list )
+
+    public static native EGLSync eglCreateSync(
+        EGLDisplay dpy,
+        int type,
+        long[] attrib_list,
+        int offset
+    );
+
+    /**
+    * C function EGLBoolean eglGetSyncAttrib ( EGLDisplay dpy, EGLSync sync, EGLint attribute,
+    *                                          EGLAttrib *value )
+    */
+
+    public static native boolean eglGetSyncAttrib(
+            EGLDisplay dpy,
+            EGLSync sync,
+            int attribute,
+            long[] value,
+            int offset
+    );
+
diff --git a/opengl/tools/glgen/stubs/egl/eglCreateSync.nativeReg b/opengl/tools/glgen/stubs/egl/eglCreateSync.nativeReg
new file mode 100644
index 0000000..c99e7fe
--- /dev/null
+++ b/opengl/tools/glgen/stubs/egl/eglCreateSync.nativeReg
@@ -0,0 +1,2 @@
+{"eglCreateSync", "(Landroid/opengl/EGLDisplay;I[JI)Landroid/opengl/EGLSync;", (void *) android_eglCreateSync },
+{"eglGetSyncAttrib", "(Landroid/opengl/EGLDisplay;Landroid/opengl/EGLSync;I[JI)Z", (void *) android_eglGetSyncAttrib },
diff --git a/opengl/tools/glgen/stubs/egl/eglGetPlatformDisplay.cpp b/opengl/tools/glgen/stubs/egl/eglGetPlatformDisplay.cpp
index 3a6176f..6acb32a 100644
--- a/opengl/tools/glgen/stubs/egl/eglGetPlatformDisplay.cpp
+++ b/opengl/tools/glgen/stubs/egl/eglGetPlatformDisplay.cpp
@@ -6,9 +6,9 @@
     const char * _exceptionType = NULL;
     const char * _exceptionMessage = NULL;
     EGLDisplay _returnValue = (EGLDisplay) 0;
-    EGLAttrib *attrib_list_base = (EGLAttrib *) 0;
+    jlong *attrib_list_base = (jlong *) 0;
     jint _remaining;
-    EGLAttrib *attrib_list = (EGLAttrib *) 0;
+    WrappedEGLAttribs attrib_list;
 
     if (!attrib_list_ref) {
         _exception = 1;
@@ -23,14 +23,14 @@
         goto exit;
     }
     _remaining = _env->GetArrayLength(attrib_list_ref) - offset;
-    attrib_list_base = (EGLAttrib *)
+    attrib_list_base = (jlong *)
         _env->GetLongArrayElements(attrib_list_ref, (jboolean *)0);
-    attrib_list = attrib_list_base + offset;
+    attrib_list.init(attrib_list_base + offset, _remaining);
 
     _returnValue = eglGetPlatformDisplay(
         (EGLenum)platform,
         (void *)native_display,
-        (EGLAttrib *)attrib_list
+        attrib_list.attribs
     );
 
 exit:
diff --git a/services/inputflinger/EventHub.cpp b/services/inputflinger/EventHub.cpp
index 0544ec1..ce56272 100644
--- a/services/inputflinger/EventHub.cpp
+++ b/services/inputflinger/EventHub.cpp
@@ -115,8 +115,15 @@
  * The system property ro.input.video_enabled can be used to control whether
  * EventHub scans and opens V4L devices. As V4L does not support multiple
  * clients, EventHub effectively blocks access to these devices when it opens
- * them. This property enables other clients to read these devices for testing
- * and development.
+ * them.
+ *
+ * Setting this to "false" would prevent any video devices from being discovered and
+ * associated with input devices.
+ *
+ * This property can be used as follows:
+ * 1. To turn off features that are dependent on video device presence.
+ * 2. During testing and development, to allow other clients to read video devices
+ * directly from /dev.
  */
 static bool isV4lScanningEnabled() {
   return property_get_bool("ro.input.video_enabled", true /* default_value */);
diff --git a/services/surfaceflinger/AllowedDisplayConfigs.h b/services/surfaceflinger/AllowedDisplayConfigs.h
deleted file mode 100644
index 7ca62ea..0000000
--- a/services/surfaceflinger/AllowedDisplayConfigs.h
+++ /dev/null
@@ -1,68 +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.
- */
-
-#pragma once
-
-#include <log/log.h>
-#include <vector>
-
-/*
- * Used to represent the Display Configurations allowed to be set by SurfaceFlinger
- */
-class AllowedDisplayConfigs {
-private:
-    // Defining ConstructorTag as private to prevent instantiating this class from outside
-    // while still allowing it to be constructed by std::make_unique
-    struct ConstructorTag {};
-
-public:
-    AllowedDisplayConfigs(ConstructorTag) {}
-
-    class Builder {
-    public:
-        Builder()
-              : mAllowedDisplayConfigs(std::make_unique<AllowedDisplayConfigs>(ConstructorTag{})) {}
-
-        std::unique_ptr<const AllowedDisplayConfigs> build() {
-            return std::move(mAllowedDisplayConfigs);
-        }
-
-        // add a config to the allowed config set
-        Builder& addConfig(int32_t config) {
-            mAllowedDisplayConfigs->addConfig(config);
-            return *this;
-        }
-
-    private:
-        std::unique_ptr<AllowedDisplayConfigs> mAllowedDisplayConfigs;
-    };
-
-    bool isConfigAllowed(int32_t config) const {
-        return (std::find(mConfigs.begin(), mConfigs.end(), config) != mConfigs.end());
-    }
-
-    void getAllowedConfigs(std::vector<int32_t>* outConfigs) const {
-        if (outConfigs) {
-            *outConfigs = mConfigs;
-        }
-    }
-
-private:
-    // add a config to the allowed config set
-    void addConfig(int32_t config) { mConfigs.push_back(config); }
-
-    std::vector<int32_t> mConfigs;
-};
diff --git a/services/surfaceflinger/Android.bp b/services/surfaceflinger/Android.bp
index 52c68df..9080d29 100644
--- a/services/surfaceflinger/Android.bp
+++ b/services/surfaceflinger/Android.bp
@@ -147,6 +147,7 @@
         "Scheduler/EventThread.cpp",
         "Scheduler/IdleTimer.cpp",
         "Scheduler/LayerHistory.cpp",
+        "Scheduler/LayerInfo.cpp",
         "Scheduler/MessageQueue.cpp",
         "Scheduler/Scheduler.cpp",
         "Scheduler/SchedulerUtils.cpp",
diff --git a/services/surfaceflinger/BufferLayer.cpp b/services/surfaceflinger/BufferLayer.cpp
index 1b2b180..a08ae8c 100644
--- a/services/surfaceflinger/BufferLayer.cpp
+++ b/services/surfaceflinger/BufferLayer.cpp
@@ -413,6 +413,7 @@
     // If the head buffer's acquire fence hasn't signaled yet, return and
     // try again later
     if (!fenceHasSignaled()) {
+        ATRACE_NAME("!fenceHasSignaled()");
         mFlinger->signalLayerUpdate();
         return false;
     }
diff --git a/services/surfaceflinger/BufferQueueLayer.cpp b/services/surfaceflinger/BufferQueueLayer.cpp
index b623991..ff5f271 100644
--- a/services/surfaceflinger/BufferQueueLayer.cpp
+++ b/services/surfaceflinger/BufferQueueLayer.cpp
@@ -398,8 +398,8 @@
     // Add this buffer from our internal queue tracker
     { // Autolock scope
         if (mFlinger->mUseSmart90ForVideo) {
-            // Report mApi ID for each layer.
-            mFlinger->mScheduler->addNativeWindowApi(item.mApi);
+            const nsecs_t presentTime = item.mIsAutoTimestamp ? 0 : item.mTimestamp;
+            mFlinger->mScheduler->addLayerPresentTime(mSchedulerLayerHandle, presentTime);
         }
 
         Mutex::Autolock lock(mQueueItemLock);
diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp
index 64dfdc3..2cbb917 100644
--- a/services/surfaceflinger/BufferStateLayer.cpp
+++ b/services/surfaceflinger/BufferStateLayer.cpp
@@ -209,7 +209,8 @@
     return true;
 }
 
-bool BufferStateLayer::setBuffer(const sp<GraphicBuffer>& buffer) {
+bool BufferStateLayer::setBuffer(const sp<GraphicBuffer>& buffer, nsecs_t postTime,
+                                 nsecs_t desiredPresentTime) {
     if (mCurrentState.buffer) {
         mReleasePreviousBuffer = true;
     }
@@ -217,6 +218,15 @@
     mCurrentState.buffer = buffer;
     mCurrentState.modified = true;
     setTransactionFlags(eTransactionNeeded);
+
+    mFlinger->mTimeStats->setPostTime(getSequence(), getFrameNumber(), getName().c_str(), postTime);
+    mDesiredPresentTime = desiredPresentTime;
+
+    if (mFlinger->mUseSmart90ForVideo) {
+        const nsecs_t presentTime = (mDesiredPresentTime == -1) ? 0 : mDesiredPresentTime;
+        mFlinger->mScheduler->addLayerPresentTime(mSchedulerLayerHandle, presentTime);
+    }
+
     return true;
 }
 
@@ -348,14 +358,6 @@
     return parentBounds;
 }
 
-void BufferStateLayer::setPostTime(nsecs_t postTime) {
-    mFlinger->mTimeStats->setPostTime(getSequence(), getFrameNumber(), getName().c_str(), postTime);
-}
-
-void BufferStateLayer::setDesiredPresentTime(nsecs_t desiredPresentTime) {
-    mDesiredPresentTime = desiredPresentTime;
-}
-
 // -----------------------------------------------------------------------
 
 // -----------------------------------------------------------------------
diff --git a/services/surfaceflinger/BufferStateLayer.h b/services/surfaceflinger/BufferStateLayer.h
index 668830a..864a15d 100644
--- a/services/surfaceflinger/BufferStateLayer.h
+++ b/services/surfaceflinger/BufferStateLayer.h
@@ -63,7 +63,8 @@
     bool setTransformToDisplayInverse(bool transformToDisplayInverse) override;
     bool setCrop(const Rect& crop) override;
     bool setFrame(const Rect& frame) override;
-    bool setBuffer(const sp<GraphicBuffer>& buffer) override;
+    bool setBuffer(const sp<GraphicBuffer>& buffer, nsecs_t postTime,
+                   nsecs_t desiredPresentTime) override;
     bool setAcquireFence(const sp<Fence>& fence) override;
     bool setDataspace(ui::Dataspace dataspace) override;
     bool setHdrMetadata(const HdrMetadata& hdrMetadata) override;
@@ -90,8 +91,6 @@
     Rect getBufferSize(const State& s) const override;
     FloatRect computeSourceBounds(const FloatRect& parentBounds) const override;
 
-    void setPostTime(nsecs_t postTime) override;
-    void setDesiredPresentTime(nsecs_t desiredPresentTime) override;
     // -----------------------------------------------------------------------
 
     // -----------------------------------------------------------------------
diff --git a/services/surfaceflinger/Client.cpp b/services/surfaceflinger/Client.cpp
index e54b460..508be13 100644
--- a/services/surfaceflinger/Client.cpp
+++ b/services/surfaceflinger/Client.cpp
@@ -76,18 +76,9 @@
                                uint32_t flags, const sp<IBinder>& parentHandle,
                                LayerMetadata metadata, sp<IBinder>* handle,
                                sp<IGraphicBufferProducer>* gbp) {
-    sp<Layer> parent = nullptr;
-    if (parentHandle != nullptr) {
-        auto layerHandle = reinterpret_cast<Layer::Handle*>(parentHandle.get());
-        parent = layerHandle->owner.promote();
-        if (parent == nullptr) {
-            return NAME_NOT_FOUND;
-        }
-    }
-
     // We rely on createLayer to check permissions.
     return mFlinger->createLayer(name, this, w, h, format, flags, std::move(metadata), handle, gbp,
-                                 &parent);
+                                 parentHandle);
 }
 
 status_t Client::createWithSurfaceParent(const String8& name, uint32_t w, uint32_t h,
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index b358437..0211df9 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -70,7 +70,10 @@
 std::atomic<int32_t> Layer::sSequence{1};
 
 Layer::Layer(const LayerCreationArgs& args)
-      : mFlinger(args.flinger), mName(args.name), mClientRef(args.client) {
+      : mFlinger(args.flinger),
+        mName(args.name),
+        mClientRef(args.client),
+        mWindowType(args.metadata.getInt32(METADATA_WINDOW_TYPE, 0)) {
     mCurrentCrop.makeInvalid();
 
     uint32_t layerFlags = 0;
@@ -115,6 +118,8 @@
     mFrameEventHistory.initializeCompositorTiming(compositorTiming);
     mFrameTracker.setDisplayRefreshPeriod(compositorTiming.interval);
 
+    mSchedulerLayerHandle = mFlinger->mScheduler->registerLayer(mName.c_str(), mWindowType);
+
     mFlinger->onLayerCreated();
 }
 
@@ -125,7 +130,6 @@
     }
 
     mFrameTracker.logAndResetStats(mName);
-
     mFlinger->onLayerDestroyed();
 }
 
@@ -1298,6 +1302,7 @@
     result.append("-----------------------------\n");
     result.append(" Layer name\n");
     result.append("           Z | ");
+    result.append(" Window Type | ");
     result.append(" Comp Type | ");
     result.append(" Transform | ");
     result.append("  Disp Frame (LTRB) | ");
@@ -1334,6 +1339,7 @@
     } else {
         StringAppendF(&result, "  %10d | ", layerState.z);
     }
+    StringAppendF(&result, "  %10d | ", mWindowType);
     StringAppendF(&result, "%10s | ", toString(getCompositionType(displayDevice)).c_str());
     StringAppendF(&result, "%10s | ",
                   toString(getCompositionLayer() ? compositionState.bufferTransform
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index 8348ce1..f4545e0 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -311,7 +311,10 @@
     virtual bool setTransformToDisplayInverse(bool /*transformToDisplayInverse*/) { return false; };
     virtual bool setCrop(const Rect& /*crop*/) { return false; };
     virtual bool setFrame(const Rect& /*frame*/) { return false; };
-    virtual bool setBuffer(const sp<GraphicBuffer>& /*buffer*/) { return false; };
+    virtual bool setBuffer(const sp<GraphicBuffer>& /*buffer*/, nsecs_t /*postTime*/,
+                           nsecs_t /*desiredPresentTime*/) {
+        return false;
+    }
     virtual bool setAcquireFence(const sp<Fence>& /*fence*/) { return false; };
     virtual bool setDataspace(ui::Dataspace /*dataspace*/) { return false; };
     virtual bool setHdrMetadata(const HdrMetadata& /*hdrMetadata*/) { return false; };
@@ -450,9 +453,6 @@
     }
     virtual Rect getCrop(const Layer::State& s) const { return s.crop_legacy; }
 
-    virtual void setPostTime(nsecs_t /*postTime*/) {}
-    virtual void setDesiredPresentTime(nsecs_t /*desiredPresentTime*/) {}
-
 protected:
     virtual bool prepareClientLayer(const RenderArea& renderArea, const Region& clip,
                                     bool useIdentityTransform, Region& clearRegion,
@@ -885,6 +885,12 @@
     // Can only be accessed with the SF state lock held.
     bool mChildrenChanged{false};
 
+    // Window types from WindowManager.LayoutParams
+    const int mWindowType;
+
+    // This is populated if the layer is registered with Scheduler for tracking purposes.
+    std::unique_ptr<scheduler::LayerHistory::LayerHandle> mSchedulerLayerHandle;
+
 private:
     /**
      * Returns an unsorted vector of all layers that are part of this tree.
diff --git a/services/surfaceflinger/RefreshRateOverlay.cpp b/services/surfaceflinger/RefreshRateOverlay.cpp
index e70bfe4..240c84e 100644
--- a/services/surfaceflinger/RefreshRateOverlay.cpp
+++ b/services/surfaceflinger/RefreshRateOverlay.cpp
@@ -31,9 +31,9 @@
     const status_t ret =
             mFlinger.createLayer(String8("RefreshRateOverlay"), mClient, 0, 0,
                                  PIXEL_FORMAT_RGBA_8888, ISurfaceComposerClient::eFXSurfaceColor,
-                                 LayerMetadata(), &mIBinder, &mGbp, &mLayer);
+                                 LayerMetadata(), &mIBinder, &mGbp, nullptr);
     if (ret) {
-        ALOGE("failed to color layer");
+        ALOGE("failed to create color layer");
         return false;
     }
 
diff --git a/services/surfaceflinger/RegionSamplingThread.cpp b/services/surfaceflinger/RegionSamplingThread.cpp
index 35f11fc..252ff0d 100644
--- a/services/surfaceflinger/RegionSamplingThread.cpp
+++ b/services/surfaceflinger/RegionSamplingThread.cpp
@@ -392,7 +392,8 @@
     //
     // To avoid this, we drop the mutex while we call into SF.
     mMutex.unlock();
-    mFlinger.captureScreenCommon(renderArea, traverseLayers, buffer, false);
+    bool ignored;
+    mFlinger.captureScreenCommon(renderArea, traverseLayers, buffer, false, ignored);
     mMutex.lock();
 
     std::vector<Descriptor> activeDescriptors;
diff --git a/services/surfaceflinger/Scheduler/LayerHistory.cpp b/services/surfaceflinger/Scheduler/LayerHistory.cpp
index d5ccbe1..8e36ae9 100644
--- a/services/surfaceflinger/Scheduler/LayerHistory.cpp
+++ b/services/surfaceflinger/Scheduler/LayerHistory.cpp
@@ -14,14 +14,18 @@
  * limitations under the License.
  */
 
+#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+
 #include "LayerHistory.h"
 
 #include <cinttypes>
 #include <cstdint>
+#include <limits>
 #include <numeric>
 #include <string>
 #include <unordered_map>
 
+#include <cutils/properties.h>
 #include <utils/Log.h>
 #include <utils/Timers.h>
 #include <utils/Trace.h>
@@ -29,28 +33,114 @@
 #include "SchedulerUtils.h"
 
 namespace android {
+namespace scheduler {
 
-LayerHistory::LayerHistory() {}
+std::atomic<int64_t> LayerHistory::sNextId = 0;
+
+LayerHistory::LayerHistory() {
+    char value[PROPERTY_VALUE_MAX];
+    property_get("debug.sf.layer_history_trace", value, "0");
+    mTraceEnabled = bool(atoi(value));
+}
 
 LayerHistory::~LayerHistory() = default;
 
-void LayerHistory::insert(const std::string layerName, nsecs_t presentTime) {
-    mElements[mCounter].insert(std::make_pair(layerName, presentTime));
+std::unique_ptr<LayerHistory::LayerHandle> LayerHistory::createLayer(const std::string name,
+                                                                     float maxRefreshRate) {
+    const int64_t id = sNextId++;
+
+    std::lock_guard lock(mLock);
+    mInactiveLayerInfos.emplace(id, std::make_shared<LayerInfo>(name, maxRefreshRate));
+    return std::make_unique<LayerHistory::LayerHandle>(*this, id);
 }
 
-void LayerHistory::incrementCounter() {
-    mCounter++;
-    mCounter = mCounter % scheduler::ARRAY_SIZE;
-    // Clear all the previous data from the history. This is a ring buffer, so we are
-    // reusing memory.
-    mElements[mCounter].clear();
+void LayerHistory::destroyLayer(const int64_t id) {
+    std::lock_guard lock(mLock);
+    auto it = mActiveLayerInfos.find(id);
+    if (it != mActiveLayerInfos.end()) {
+        mActiveLayerInfos.erase(it);
+    }
+
+    it = mInactiveLayerInfos.find(id);
+    if (it != mInactiveLayerInfos.end()) {
+        mInactiveLayerInfos.erase(it);
+    }
 }
 
-const std::unordered_map<std::string, nsecs_t>& LayerHistory::get(size_t index) const {
-    // For the purposes of the layer history, the index = 0 always needs to start at the
-    // current counter, and then decrement to access the layers in correct historical order.
-    return mElements.at((scheduler::ARRAY_SIZE + (mCounter - (index % scheduler::ARRAY_SIZE))) %
-                        scheduler::ARRAY_SIZE);
+void LayerHistory::insert(const std::unique_ptr<LayerHandle>& layerHandle, nsecs_t presentTime) {
+    std::shared_ptr<LayerInfo> layerInfo;
+    {
+        std::lock_guard lock(mLock);
+        auto layerInfoIterator = mInactiveLayerInfos.find(layerHandle->mId);
+        if (layerInfoIterator != mInactiveLayerInfos.end()) {
+            layerInfo = layerInfoIterator->second;
+            mInactiveLayerInfos.erase(layerInfoIterator);
+            mActiveLayerInfos.insert({layerHandle->mId, layerInfo});
+        } else {
+            layerInfoIterator = mActiveLayerInfos.find(layerHandle->mId);
+            if (layerInfoIterator != mActiveLayerInfos.end()) {
+                layerInfo = layerInfoIterator->second;
+            } else {
+                ALOGW("Inserting information about layer that is not registered: %" PRId64,
+                      layerHandle->mId);
+                return;
+            }
+        }
+    }
+    layerInfo->setLastPresentTime(presentTime);
 }
 
+float LayerHistory::getDesiredRefreshRate() {
+    float newRefreshRate = 0.f;
+    std::lock_guard lock(mLock);
+
+    removeIrrelevantLayers();
+
+    // Iterate through all layers that have been recently updated, and find the max refresh rate.
+    for (const auto& [layerId, layerInfo] : mActiveLayerInfos) {
+        const float layerRefreshRate = layerInfo->getDesiredRefreshRate();
+        if (mTraceEnabled) {
+            // Store the refresh rate in traces for easy debugging.
+            std::string layerName = "LFPS " + layerInfo->getName();
+            ATRACE_INT(layerName.c_str(), std::round(layerRefreshRate));
+            ALOGD("%s: %f", layerName.c_str(), std::round(layerRefreshRate));
+        }
+        if (layerInfo->isRecentlyActive() && layerRefreshRate > newRefreshRate) {
+            newRefreshRate = layerRefreshRate;
+        }
+    }
+    if (mTraceEnabled) {
+        ALOGD("LayerHistory DesiredRefreshRate: %.2f", newRefreshRate);
+    }
+
+    return newRefreshRate;
+}
+
+void LayerHistory::removeIrrelevantLayers() {
+    const int64_t obsoleteEpsilon = systemTime() - scheduler::OBSOLETE_TIME_EPSILON_NS.count();
+    // Iterator pointing to first element in map
+    auto it = mActiveLayerInfos.begin();
+    while (it != mActiveLayerInfos.end()) {
+        // If last updated was before the obsolete time, remove it.
+        if (it->second->getLastUpdatedTime() < obsoleteEpsilon) {
+            // erase() function returns the iterator of the next
+            // to last deleted element.
+            if (mTraceEnabled) {
+                ALOGD("Layer %s obsolete", it->second->getName().c_str());
+                // Make sure to update systrace to indicate that the layer was erased.
+                std::string layerName = "LFPS " + it->second->getName();
+                ATRACE_INT(layerName.c_str(), 0);
+            }
+            auto id = it->first;
+            auto layerInfo = it->second;
+            layerInfo->clearHistory();
+            mInactiveLayerInfos.insert({id, layerInfo});
+            it = mActiveLayerInfos.erase(it);
+        } else {
+            ++it;
+        }
+    }
+}
+
+} // namespace scheduler
 } // namespace android
\ No newline at end of file
diff --git a/services/surfaceflinger/Scheduler/LayerHistory.h b/services/surfaceflinger/Scheduler/LayerHistory.h
index c6fab07..39061e7 100644
--- a/services/surfaceflinger/Scheduler/LayerHistory.h
+++ b/services/surfaceflinger/Scheduler/LayerHistory.h
@@ -25,40 +25,60 @@
 
 #include <utils/Timers.h>
 
+#include "LayerInfo.h"
 #include "SchedulerUtils.h"
 
 namespace android {
+namespace scheduler {
 
 /*
- * This class represents a circular buffer in which we keep layer history for
- * the past ARRAY_SIZE frames. Each time, a signal for new frame comes, the counter
- * gets incremented and includes all the layers that are requested to draw in that
- * frame.
- *
- * Once the buffer reaches the end of the array, it starts overriding the elements
- * at the beginning of the array.
+ * This class represents information about layers that are considered current. We keep an
+ * unordered map between layer name and LayerInfo.
  */
 class LayerHistory {
 public:
+    // Handle for each layer we keep track of.
+    class LayerHandle {
+    public:
+        LayerHandle(LayerHistory& lh, int64_t id) : mId(id), mLayerHistory(lh) {}
+        ~LayerHandle() { mLayerHistory.destroyLayer(mId); }
+
+        const int64_t mId;
+
+    private:
+        LayerHistory& mLayerHistory;
+    };
+
     LayerHistory();
     ~LayerHistory();
 
-    // Method for inserting layers and their requested present time into the ring buffer.
-    // The elements are going to be inserted into an unordered_map at the position 'now'.
-    void insert(const std::string layerName, nsecs_t presentTime);
-    // Method for incrementing the current slot in the ring buffer. It also clears the
-    // unordered_map, if it was created previously.
-    void incrementCounter();
-    // Returns unordered_map at the given at index. The index is decremented from 'now'. For
-    // example, 0 is now, 1 is previous frame.
-    const std::unordered_map<std::string, nsecs_t>& get(size_t index) const;
-    // Returns the total size of the ring buffer. The value is always the same regardless
-    // of how many slots we filled in.
-    static constexpr size_t getSize() { return scheduler::ARRAY_SIZE; }
+    // When the layer is first created, register it.
+    std::unique_ptr<LayerHandle> createLayer(const std::string name, float maxRefreshRate);
+
+    // Method for inserting layers and their requested present time into the unordered map.
+    void insert(const std::unique_ptr<LayerHandle>& layerHandle, nsecs_t presentTime);
+    // Returns the desired refresh rate, which is a max refresh rate of all the current
+    // layers. See go/content-fps-detection-in-scheduler for more information.
+    float getDesiredRefreshRate();
+
+    // Removes the handle and the object from the map.
+    void destroyLayer(const int64_t id);
 
 private:
-    size_t mCounter = 0;
-    std::array<std::unordered_map<std::string, nsecs_t>, scheduler::ARRAY_SIZE> mElements;
+    // Removes the layers that have been idle for a given amount of time from mLayerInfos.
+    void removeIrrelevantLayers() REQUIRES(mLock);
+
+    // Information about currently active layers.
+    std::mutex mLock;
+    std::unordered_map<int64_t, std::shared_ptr<LayerInfo>> mActiveLayerInfos GUARDED_BY(mLock);
+    std::unordered_map<int64_t, std::shared_ptr<LayerInfo>> mInactiveLayerInfos GUARDED_BY(mLock);
+
+    // Each layer has it's own ID. This variable keeps track of the count.
+    static std::atomic<int64_t> sNextId;
+
+    // Flag whether to log layer FPS in systrace
+    bool mTraceEnabled = false;
 };
 
+} // namespace scheduler
 } // namespace android
\ No newline at end of file
diff --git a/services/surfaceflinger/Scheduler/LayerInfo.cpp b/services/surfaceflinger/Scheduler/LayerInfo.cpp
new file mode 100644
index 0000000..95d7d31
--- /dev/null
+++ b/services/surfaceflinger/Scheduler/LayerInfo.cpp
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "LayerInfo.h"
+
+#include <cinttypes>
+#include <cstdint>
+#include <numeric>
+#include <string>
+
+namespace android {
+namespace scheduler {
+
+LayerInfo::LayerInfo(const std::string name, float maxRefreshRate)
+      : mName(name),
+        mMinRefreshDuration(1e9f / maxRefreshRate),
+        mRefreshRateHistory(mMinRefreshDuration) {}
+
+LayerInfo::~LayerInfo() = default;
+
+void LayerInfo::setLastPresentTime(nsecs_t lastPresentTime) {
+    std::lock_guard lock(mLock);
+
+    // Buffers can come with a present time far in the future. That keeps them relevant.
+    mLastUpdatedTime = std::max(lastPresentTime, systemTime());
+    mPresentTimeHistory.insertPresentTime(mLastUpdatedTime);
+
+    const nsecs_t timeDiff = lastPresentTime - mLastPresentTime;
+    mLastPresentTime = lastPresentTime;
+    // Ignore time diff that are too high - those are stale values
+    if (timeDiff > TIME_EPSILON_NS.count()) return;
+    const nsecs_t refreshDuration = (timeDiff > 0) ? timeDiff : mMinRefreshDuration;
+    mRefreshRateHistory.insertRefreshRate(refreshDuration);
+}
+
+} // namespace scheduler
+} // namespace android
diff --git a/services/surfaceflinger/Scheduler/LayerInfo.h b/services/surfaceflinger/Scheduler/LayerInfo.h
new file mode 100644
index 0000000..1970a47
--- /dev/null
+++ b/services/surfaceflinger/Scheduler/LayerInfo.h
@@ -0,0 +1,156 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <cinttypes>
+#include <cstdint>
+#include <deque>
+#include <mutex>
+#include <numeric>
+#include <string>
+
+#include <log/log.h>
+
+#include <utils/Mutex.h>
+#include <utils/Timers.h>
+
+#include "SchedulerUtils.h"
+
+namespace android {
+namespace scheduler {
+
+/*
+ * This class represents information about individial layers.
+ */
+class LayerInfo {
+    /**
+     * Struct that keeps the information about the refresh rate for last
+     * HISTORY_SIZE frames. This is used to better determine the refresh rate
+     * for individual layers.
+     */
+    class RefreshRateHistory {
+    public:
+        explicit RefreshRateHistory(nsecs_t minRefreshDuration)
+              : mMinRefreshDuration(minRefreshDuration) {}
+        void insertRefreshRate(nsecs_t refreshRate) {
+            mElements.push_back(refreshRate);
+            if (mElements.size() > HISTORY_SIZE) {
+                mElements.pop_front();
+            }
+        }
+
+        float getRefreshRateAvg() const {
+            nsecs_t refreshDuration = mMinRefreshDuration;
+            if (mElements.size() == HISTORY_SIZE) {
+                refreshDuration = scheduler::calculate_mean(mElements);
+            }
+
+            return 1e9f / refreshDuration;
+        }
+        void clearHistory() { mElements.clear(); }
+
+    private:
+        std::deque<nsecs_t> mElements;
+        static constexpr size_t HISTORY_SIZE = 30;
+        const nsecs_t mMinRefreshDuration;
+    };
+
+    /**
+     * Struct that keeps the information about the present time for last
+     * HISTORY_SIZE frames. This is used to better determine whether the given layer
+     * is still relevant and it's refresh rate should be considered.
+     */
+    class PresentTimeHistory {
+    public:
+        void insertPresentTime(nsecs_t presentTime) {
+            mElements.push_back(presentTime);
+            if (mElements.size() > HISTORY_SIZE) {
+                mElements.pop_front();
+            }
+        }
+
+        // Checks whether the present time that was inserted HISTORY_SIZE ago is within a
+        // certain threshold: TIME_EPSILON_NS.
+        bool isRelevant() const {
+            const int64_t obsoleteEpsilon = systemTime() - scheduler::TIME_EPSILON_NS.count();
+            // The layer had to publish at least HISTORY_SIZE of updates, and the first
+            // update should not be older than TIME_EPSILON_NS nanoseconds.
+            if (mElements.size() == HISTORY_SIZE &&
+                mElements.at(HISTORY_SIZE - 1) > obsoleteEpsilon) {
+                return true;
+            }
+            return false;
+        }
+
+        void clearHistory() { mElements.clear(); }
+
+    private:
+        std::deque<nsecs_t> mElements;
+        static constexpr size_t HISTORY_SIZE = 10;
+    };
+
+public:
+    LayerInfo(const std::string name, float maxRefreshRate);
+    ~LayerInfo();
+
+    LayerInfo(const LayerInfo&) = delete;
+    LayerInfo& operator=(const LayerInfo&) = delete;
+
+    // Records the last requested oresent time. It also stores information about when
+    // the layer was last updated. If the present time is farther in the future than the
+    // updated time, the updated time is the present time.
+    void setLastPresentTime(nsecs_t lastPresentTime);
+
+    // Checks the present time history to see whether the layer is relevant.
+    bool isRecentlyActive() const {
+        std::lock_guard lock(mLock);
+        return mPresentTimeHistory.isRelevant();
+    }
+
+    // Calculate the average refresh rate.
+    float getDesiredRefreshRate() const {
+        std::lock_guard lock(mLock);
+        return mRefreshRateHistory.getRefreshRateAvg();
+    }
+
+    // Return the last updated time. If the present time is farther in the future than the
+    // updated time, the updated time is the present time.
+    nsecs_t getLastUpdatedTime() {
+        std::lock_guard lock(mLock);
+        return mLastUpdatedTime;
+    }
+
+    std::string getName() const { return mName; }
+
+    void clearHistory() {
+        std::lock_guard lock(mLock);
+        mRefreshRateHistory.clearHistory();
+        mPresentTimeHistory.clearHistory();
+    }
+
+private:
+    const std::string mName;
+    const nsecs_t mMinRefreshDuration;
+    mutable std::mutex mLock;
+    nsecs_t mLastUpdatedTime GUARDED_BY(mLock) = 0;
+    nsecs_t mLastPresentTime GUARDED_BY(mLock) = 0;
+    RefreshRateHistory mRefreshRateHistory GUARDED_BY(mLock);
+    PresentTimeHistory mPresentTimeHistory GUARDED_BY(mLock);
+};
+
+} // namespace scheduler
+} // namespace android
\ No newline at end of file
diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
index 1aa6ade..eb9ae35 100644
--- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
+++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
@@ -51,16 +51,10 @@
 
     // TODO(b/122916473): Get this information from configs prepared by vendors, instead of
     // baking them in.
-    explicit RefreshRateConfigs(
-            const std::vector<std::shared_ptr<const HWC2::Display::Config>>& configs) {
-        init(configs);
-    }
-    ~RefreshRateConfigs() = default;
-
-    const std::map<RefreshRateType, std::shared_ptr<RefreshRate>>& getRefreshRates() {
+    const std::map<RefreshRateType, std::shared_ptr<RefreshRate>>& getRefreshRates() const {
         return mRefreshRates;
     }
-    std::shared_ptr<RefreshRate> getRefreshRate(RefreshRateType type) {
+    std::shared_ptr<RefreshRate> getRefreshRate(RefreshRateType type) const {
         const auto& refreshRate = mRefreshRates.find(type);
         if (refreshRate != mRefreshRates.end()) {
             return refreshRate->second;
@@ -68,8 +62,9 @@
         return nullptr;
     }
 
-private:
-    void init(const std::vector<std::shared_ptr<const HWC2::Display::Config>>& configs) {
+    void populate(const std::vector<std::shared_ptr<const HWC2::Display::Config>>& configs) {
+        mRefreshRates.clear();
+
         // This is the rate that HWC encapsulates right now when the device is in DOZE mode.
         mRefreshRates.emplace(RefreshRateType::POWER_SAVING,
                               std::make_shared<RefreshRate>(
@@ -120,6 +115,7 @@
         }
     }
 
+private:
     std::map<RefreshRateType, std::shared_ptr<RefreshRate>> mRefreshRates;
 };
 
diff --git a/services/surfaceflinger/Scheduler/RefreshRateStats.h b/services/surfaceflinger/Scheduler/RefreshRateStats.h
index ff63faf..7e7c630 100644
--- a/services/surfaceflinger/Scheduler/RefreshRateStats.h
+++ b/services/surfaceflinger/Scheduler/RefreshRateStats.h
@@ -41,12 +41,8 @@
     static constexpr int64_t MS_PER_DAY = 24 * MS_PER_HOUR;
 
 public:
-    explicit RefreshRateStats(const std::shared_ptr<RefreshRateConfigs>& refreshRateConfigs,
-                              const std::shared_ptr<TimeStats>& timeStats)
-          : mRefreshRateConfigs(refreshRateConfigs),
-            mTimeStats(timeStats),
-            mPreviousRecordedTime(systemTime()) {}
-    ~RefreshRateStats() = default;
+    RefreshRateStats(const RefreshRateConfigs& refreshRateConfigs, TimeStats& timeStats)
+          : mRefreshRateConfigs(refreshRateConfigs), mTimeStats(timeStats) {}
 
     // Sets power mode. We only collect the information when the power mode is not
     // HWC_POWER_MODE_NORMAL. When power mode is HWC_POWER_MODE_NORMAL, we collect the stats based
@@ -83,7 +79,7 @@
         flushTime();
 
         std::unordered_map<std::string, int64_t> totalTime;
-        for (auto [type, config] : mRefreshRateConfigs->getRefreshRates()) {
+        for (const auto& [type, config] : mRefreshRateConfigs.getRefreshRates()) {
             int64_t totalTimeForConfig = 0;
             if (!config) {
                 continue;
@@ -98,11 +94,11 @@
 
     // Traverses through the map of config modes and returns how long they've been running in easy
     // to read format.
-    std::string doDump() {
+    std::string doDump() const {
         std::ostringstream stream;
         stream << "+  Refresh rate: running time in seconds\n";
-        for (auto stats : getTotalTimes()) {
-            stream << stats.first.c_str() << ": " << getDateFormatFromMs(stats.second) << "\n";
+        for (const auto& [name, time] : const_cast<RefreshRateStats*>(this)->getTotalTimes()) {
+            stream << name << ": " << getDateFormatFromMs(time) << '\n';
         }
         return stream.str();
     }
@@ -126,12 +122,12 @@
         mPreviousRecordedTime = currentTime;
 
         mConfigModesTotalTime[mode] += timeElapsedMs;
-        for (const auto& [type, config] : mRefreshRateConfigs->getRefreshRates()) {
+        for (const auto& [type, config] : mRefreshRateConfigs.getRefreshRates()) {
             if (!config) {
                 continue;
             }
             if (config->configId == mode) {
-                mTimeStats->recordRefreshRate(config->fps, timeElapsed);
+                mTimeStats.recordRefreshRate(config->fps, timeElapsed);
             }
         }
     }
@@ -148,17 +144,17 @@
     }
 
     // Keeps information about refresh rate configs that device has.
-    std::shared_ptr<RefreshRateConfigs> mRefreshRateConfigs;
+    const RefreshRateConfigs& mRefreshRateConfigs;
 
     // Aggregate refresh rate statistics for telemetry.
-    std::shared_ptr<TimeStats> mTimeStats;
+    TimeStats& mTimeStats;
 
     int64_t mCurrentConfigMode = SCREEN_OFF_CONFIG_ID;
     int32_t mCurrentPowerMode = HWC_POWER_MODE_OFF;
 
     std::unordered_map<int /* power mode */, int64_t /* duration in ms */> mConfigModesTotalTime;
 
-    nsecs_t mPreviousRecordedTime;
+    nsecs_t mPreviousRecordedTime = systemTime();
 };
 
 } // namespace scheduler
diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp
index 0063c8a..b1c39ef 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.cpp
+++ b/services/surfaceflinger/Scheduler/Scheduler.cpp
@@ -28,6 +28,7 @@
 #include <android/hardware/configstore/1.1/ISurfaceFlingerConfigs.h>
 #include <configstore/Utils.h>
 #include <cutils/properties.h>
+#include <input/InputWindow.h>
 #include <system/window.h>
 #include <ui/DisplayStatInfo.h>
 #include <utils/Timers.h>
@@ -39,6 +40,7 @@
 #include "EventThread.h"
 #include "IdleTimer.h"
 #include "InjectVSyncSource.h"
+#include "LayerInfo.h"
 #include "SchedulerUtils.h"
 #include "SurfaceFlingerProperties.h"
 
@@ -55,11 +57,13 @@
 
 std::atomic<int64_t> Scheduler::sNextId = 0;
 
-Scheduler::Scheduler(impl::EventControlThread::SetVSyncEnabledFunction function)
+Scheduler::Scheduler(impl::EventControlThread::SetVSyncEnabledFunction function,
+                     const scheduler::RefreshRateConfigs& refreshRateConfig)
       : mHasSyncFramework(running_without_sync_framework(true)),
         mDispSyncPresentTimeOffset(present_time_offset_from_vsync_ns(0)),
         mPrimaryHWVsyncEnabled(false),
-        mHWVsyncAvailable(false) {
+        mHWVsyncAvailable(false),
+        mRefreshRateConfigs(refreshRateConfig) {
     // Note: We create a local temporary with the real DispSync implementation
     // type temporarily so we can initialize it with the configured values,
     // before storing it for more generic use using the interface type.
@@ -297,32 +301,34 @@
     mPrimaryDispSync->dump(result);
 }
 
-void Scheduler::addNativeWindowApi(int apiId) {
-    std::lock_guard<std::mutex> lock(mWindowApiHistoryLock);
-    mWindowApiHistory[mApiHistoryCounter] = apiId;
-    mApiHistoryCounter++;
-    mApiHistoryCounter = mApiHistoryCounter % scheduler::ARRAY_SIZE;
+std::unique_ptr<scheduler::LayerHistory::LayerHandle> Scheduler::registerLayer(
+        std::string const& name, int windowType) {
+    RefreshRateType refreshRateType = (windowType == InputWindowInfo::TYPE_WALLPAPER)
+            ? RefreshRateType::DEFAULT
+            : RefreshRateType::PERFORMANCE;
+
+    const auto refreshRate = mRefreshRateConfigs.getRefreshRate(refreshRateType);
+    const uint32_t fps = (refreshRate) ? refreshRate->fps : 0;
+    return mLayerHistory.createLayer(name, fps);
+}
+
+void Scheduler::addLayerPresentTime(
+        const std::unique_ptr<scheduler::LayerHistory::LayerHandle>& layerHandle,
+        nsecs_t presentTime) {
+    mLayerHistory.insert(layerHandle, presentTime);
 }
 
 void Scheduler::withPrimaryDispSync(std::function<void(DispSync&)> const& fn) {
     fn(*mPrimaryDispSync);
 }
 
-void Scheduler::updateFpsBasedOnNativeWindowApi() {
-    int mode;
-    {
-        std::lock_guard<std::mutex> lock(mWindowApiHistoryLock);
-        mode = scheduler::calculate_mode(mWindowApiHistory);
-    }
-    ATRACE_INT("NativeWindowApiMode", mode);
-
-    if (mode == NATIVE_WINDOW_API_MEDIA) {
-        // TODO(b/127365162): These callback names are not accurate anymore. Update.
-        mediaChangeRefreshRate(MediaFeatureState::MEDIA_PLAYING);
-        ATRACE_INT("DetectedVideo", 1);
+void Scheduler::updateFpsBasedOnContent() {
+    uint32_t refreshRate = std::round(mLayerHistory.getDesiredRefreshRate());
+    ATRACE_INT("ContentFPS", refreshRate);
+    if (refreshRate > 0) {
+        contentChangeRefreshRate(ContentFeatureState::CONTENT_DETECTION_ON, refreshRate);
     } else {
-        mediaChangeRefreshRate(MediaFeatureState::MEDIA_OFF);
-        ATRACE_INT("DetectedVideo", 0);
+        contentChangeRefreshRate(ContentFeatureState::CONTENT_DETECTION_OFF, 0);
     }
 }
 
@@ -365,39 +371,70 @@
     return stream.str();
 }
 
-void Scheduler::mediaChangeRefreshRate(MediaFeatureState mediaFeatureState) {
-    // Default playback for media is DEFAULT when media is on.
-    RefreshRateType refreshRateType = RefreshRateType::DEFAULT;
-    ConfigEvent configEvent = ConfigEvent::None;
-
+void Scheduler::contentChangeRefreshRate(ContentFeatureState contentFeatureState,
+                                         uint32_t refreshRate) {
+    RefreshRateType newRefreshRateType;
     {
         std::lock_guard<std::mutex> lock(mFeatureStateLock);
-        mCurrentMediaFeatureState = mediaFeatureState;
-        // Only switch to PERFORMANCE if idle timer was reset, when turning
-        // media off. If the timer is IDLE, stay at DEFAULT.
-        if (mediaFeatureState == MediaFeatureState::MEDIA_OFF &&
-            mCurrentIdleTimerState == IdleTimerState::RESET) {
-            refreshRateType = RefreshRateType::PERFORMANCE;
-        }
+        mCurrentContentFeatureState = contentFeatureState;
+        mContentRefreshRate = refreshRate;
+        newRefreshRateType = calculateRefreshRateType();
     }
-    changeRefreshRate(refreshRateType, configEvent);
+    changeRefreshRate(newRefreshRateType, ConfigEvent::Changed);
 }
 
 void Scheduler::timerChangeRefreshRate(IdleTimerState idleTimerState) {
-    RefreshRateType refreshRateType = RefreshRateType::DEFAULT;
-    ConfigEvent configEvent = ConfigEvent::None;
-
+    RefreshRateType newRefreshRateType;
     {
         std::lock_guard<std::mutex> lock(mFeatureStateLock);
         mCurrentIdleTimerState = idleTimerState;
-        // Only switch to PERFOMANCE if the idle timer was reset, and media is
-        // not playing. Otherwise, stay at DEFAULT.
-        if (idleTimerState == IdleTimerState::RESET &&
-            mCurrentMediaFeatureState == MediaFeatureState::MEDIA_OFF) {
-            refreshRateType = RefreshRateType::PERFORMANCE;
+        newRefreshRateType = calculateRefreshRateType();
+    }
+    changeRefreshRate(newRefreshRateType, ConfigEvent::None);
+}
+
+Scheduler::RefreshRateType Scheduler::calculateRefreshRateType() {
+    // First check if timer has expired as it means there is no new content on the screen
+    if (mCurrentIdleTimerState == IdleTimerState::EXPIRED) {
+        return RefreshRateType::DEFAULT;
+    }
+
+    // If content detection is off we choose performance as we don't know the content fps
+    if (mCurrentContentFeatureState == ContentFeatureState::CONTENT_DETECTION_OFF) {
+        return RefreshRateType::PERFORMANCE;
+    }
+
+    // Content detection is on, find the appropriate refresh rate
+    // Start with the smallest refresh rate which is within a margin of the content
+    RefreshRateType currRefreshRateType = RefreshRateType::PERFORMANCE;
+    constexpr float MARGIN = 0.05f;
+    auto iter = mRefreshRateConfigs.getRefreshRates().cbegin();
+    while (iter != mRefreshRateConfigs.getRefreshRates().cend()) {
+        if (iter->second->fps >= mContentRefreshRate * (1 - MARGIN)) {
+            currRefreshRateType = iter->first;
+            break;
+        }
+        ++iter;
+    }
+
+    // Some content aligns better on higher refresh rate. For example for 45fps we should choose
+    // 90Hz config. However we should still prefer a lower refresh rate if the content doesn't
+    // align well with both
+    float ratio = mRefreshRateConfigs.getRefreshRate(currRefreshRateType)->fps /
+            float(mContentRefreshRate);
+    if (std::abs(std::round(ratio) - ratio) > MARGIN) {
+        while (iter != mRefreshRateConfigs.getRefreshRates().cend()) {
+            ratio = iter->second->fps / float(mContentRefreshRate);
+
+            if (std::abs(std::round(ratio) - ratio) <= MARGIN) {
+                currRefreshRateType = iter->first;
+                break;
+            }
+            ++iter;
         }
     }
-    changeRefreshRate(refreshRateType, configEvent);
+
+    return currRefreshRateType;
 }
 
 void Scheduler::changeRefreshRate(RefreshRateType refreshRateType, ConfigEvent configEvent) {
diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h
index 73896d5..1318fbb 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.h
+++ b/services/surfaceflinger/Scheduler/Scheduler.h
@@ -90,7 +90,8 @@
         std::atomic<nsecs_t> lastResyncTime = 0;
     };
 
-    explicit Scheduler(impl::EventControlThread::SetVSyncEnabledFunction function);
+    explicit Scheduler(impl::EventControlThread::SetVSyncEnabledFunction function,
+                       const scheduler::RefreshRateConfigs& refreshRateConfig);
 
     virtual ~Scheduler();
 
@@ -145,16 +146,22 @@
     void addPresentFence(const std::shared_ptr<FenceTime>& fenceTime);
     void setIgnorePresentFences(bool ignore);
     nsecs_t expectedPresentTime();
-    // apiId indicates the API (NATIVE_WINDOW_API_xxx) that queues the buffer.
-    // TODO(b/123956502): Remove this call with V1 go/content-fps-detection-in-scheduler.
-    void addNativeWindowApi(int apiId);
-    // Updates FPS based on the most occured request for Native Window API.
-    void updateFpsBasedOnNativeWindowApi();
+    // Registers the layer in the scheduler, and returns the handle for future references.
+    std::unique_ptr<scheduler::LayerHistory::LayerHandle> registerLayer(std::string const& name,
+                                                                        int windowType);
+
+    // Stores present time for a layer.
+    void addLayerPresentTime(
+            const std::unique_ptr<scheduler::LayerHistory::LayerHandle>& layerHandle,
+            nsecs_t presentTime);
+    // Updates FPS based on the most content presented.
+    void updateFpsBasedOnContent();
     // Callback that gets invoked when Scheduler wants to change the refresh rate.
     void setChangeRefreshRateCallback(const ChangeRefreshRateCallback& changeRefreshRateCallback);
 
     // Returns whether idle timer is enabled or not
     bool isIdleTimerEnabled() { return mSetIdleTimerMs > 0; }
+
     // Returns relevant information about Scheduler for dumpsys purposes.
     std::string doDump();
 
@@ -171,7 +178,7 @@
 
     // In order to make sure that the features don't override themselves, we need a state machine
     // to keep track which feature requested the config change.
-    enum class MediaFeatureState { MEDIA_PLAYING, MEDIA_OFF };
+    enum class ContentFeatureState { CONTENT_DETECTION_ON, CONTENT_DETECTION_OFF };
     enum class IdleTimerState { EXPIRED, RESET };
 
     // Creates a connection on the given EventThread and forwards the given callbacks.
@@ -188,12 +195,17 @@
     // Sets vsync period.
     void setVsyncPeriod(const nsecs_t period);
     // Media feature's function to change the refresh rate.
-    void mediaChangeRefreshRate(MediaFeatureState mediaFeatureState);
+    void contentChangeRefreshRate(ContentFeatureState contentFeatureState, uint32_t refreshRate);
     // Idle timer feature's function to change the refresh rate.
     void timerChangeRefreshRate(IdleTimerState idleTimerState);
+    // Calculate the new refresh rate type
+    RefreshRateType calculateRefreshRateType() REQUIRES(mFeatureStateLock);
     // Acquires a lock and calls the ChangeRefreshRateCallback() with given parameters.
     void changeRefreshRate(RefreshRateType refreshRateType, ConfigEvent configEvent);
 
+    // Helper function to calculate error frames
+    float getErrorFrames(float contentFps, float configFps);
+
     // If fences from sync Framework are supported.
     const bool mHasSyncFramework;
 
@@ -226,13 +238,8 @@
     std::array<int64_t, scheduler::ARRAY_SIZE> mTimeDifferences{};
     size_t mCounter = 0;
 
-    // The following few fields follow native window api bits that come with buffers. If there are
-    // more buffers with NATIVE_WINDOW_API_MEDIA we render at 60Hz, otherwise we render at 90Hz.
-    // There is not dependency on timestamp for V0.
-    // TODO(b/123956502): Remove this when more robust logic for content fps detection is developed.
-    std::mutex mWindowApiHistoryLock;
-    std::array<int, scheduler::ARRAY_SIZE> mWindowApiHistory GUARDED_BY(mWindowApiHistoryLock);
-    int64_t mApiHistoryCounter = 0;
+    // Historical information about individual layers. Used for predicting the refresh rate.
+    scheduler::LayerHistory mLayerHistory;
 
     // Timer that records time between requests for next vsync. If the time is higher than a given
     // interval, a callback is fired. Set this variable to >0 to use this feature.
@@ -245,9 +252,12 @@
     // In order to make sure that the features don't override themselves, we need a state machine
     // to keep track which feature requested the config change.
     std::mutex mFeatureStateLock;
-    MediaFeatureState mCurrentMediaFeatureState GUARDED_BY(mFeatureStateLock) =
-            MediaFeatureState::MEDIA_OFF;
+    ContentFeatureState mCurrentContentFeatureState GUARDED_BY(mFeatureStateLock) =
+            ContentFeatureState::CONTENT_DETECTION_OFF;
     IdleTimerState mCurrentIdleTimerState GUARDED_BY(mFeatureStateLock) = IdleTimerState::RESET;
+    uint32_t mContentRefreshRate;
+
+    const scheduler::RefreshRateConfigs& mRefreshRateConfigs;
 };
 
 } // namespace android
diff --git a/services/surfaceflinger/Scheduler/SchedulerUtils.h b/services/surfaceflinger/Scheduler/SchedulerUtils.h
index 9e6e8c7..a935cac 100644
--- a/services/surfaceflinger/Scheduler/SchedulerUtils.h
+++ b/services/surfaceflinger/Scheduler/SchedulerUtils.h
@@ -16,6 +16,7 @@
 
 #pragma once
 
+#include <chrono>
 #include <cinttypes>
 #include <numeric>
 #include <unordered_map>
@@ -23,6 +24,8 @@
 
 namespace android {
 namespace scheduler {
+using namespace std::chrono_literals;
+
 // This number is used to set the size of the arrays in scheduler that hold information
 // about layers.
 static constexpr size_t ARRAY_SIZE = 30;
@@ -32,12 +35,20 @@
 // still like to keep track of time when the device is in this config.
 static constexpr int SCREEN_OFF_CONFIG_ID = -1;
 
+// This number is used when we try to determine how long does a given layer stay relevant.
+// Currently it is set to 100ms, because that would indicate 10Hz rendering.
+static constexpr std::chrono::nanoseconds TIME_EPSILON_NS = 100ms;
+
+// This number is used when we try to determine how long do we keep layer information around
+// before we remove it. Currently it is set to 100ms.
+static constexpr std::chrono::nanoseconds OBSOLETE_TIME_EPSILON_NS = 100ms;
+
 // Calculates the statistical mean (average) in the data structure (array, vector). The
 // function does not modify the contents of the array.
 template <typename T>
 auto calculate_mean(const T& v) {
     using V = typename T::value_type;
-    V sum = std::accumulate(v.begin(), v.end(), 0);
+    V sum = std::accumulate(v.begin(), v.end(), static_cast<V>(0));
     return sum / static_cast<V>(v.size());
 }
 
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 33455b9..bd3f156 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -558,14 +558,10 @@
         mBootStage = BootStage::FINISHED;
 
         // set the refresh rate according to the policy
-        const auto displayId = getInternalDisplayIdLocked();
-        LOG_ALWAYS_FATAL_IF(!displayId);
-
         const auto& performanceRefreshRate =
-                mRefreshRateConfigs[*displayId]->getRefreshRate(RefreshRateType::PERFORMANCE);
+                mRefreshRateConfigs.getRefreshRate(RefreshRateType::PERFORMANCE);
 
-        if (performanceRefreshRate &&
-            isConfigAllowed(*displayId, performanceRefreshRate->configId)) {
+        if (performanceRefreshRate && isDisplayConfigAllowed(performanceRefreshRate->configId)) {
             setRefreshRateTo(RefreshRateType::PERFORMANCE, Scheduler::ConfigEvent::None);
         } else {
             setRefreshRateTo(RefreshRateType::DEFAULT, Scheduler::ConfigEvent::None);
@@ -609,7 +605,8 @@
     Mutex::Autolock _l(mStateLock);
     // start the EventThread
     mScheduler =
-            getFactory().createScheduler([this](bool enabled) { setPrimaryVsyncEnabled(enabled); });
+            getFactory().createScheduler([this](bool enabled) { setPrimaryVsyncEnabled(enabled); },
+                                         mRefreshRateConfigs);
     auto resyncCallback =
             mScheduler->makeResyncCallback(std::bind(&SurfaceFlinger::getVsyncPeriod, this));
 
@@ -706,12 +703,9 @@
                     setRefreshRateTo(type, event);
                 });
     }
-    mRefreshRateConfigs[*display->getId()] = std::make_shared<scheduler::RefreshRateConfigs>(
-            getHwComposer().getConfigs(*display->getId()));
-    mRefreshRateStats =
-            std::make_unique<scheduler::RefreshRateStats>(mRefreshRateConfigs[*display->getId()],
-                                                          mTimeStats);
-    mRefreshRateStats->setConfigMode(getHwComposer().getActiveConfigIndex(*display->getId()));
+
+    mRefreshRateConfigs.populate(getHwComposer().getConfigs(*display->getId()));
+    mRefreshRateStats.setConfigMode(getHwComposer().getActiveConfigIndex(*display->getId()));
 
     ALOGV("Done initializing");
 }
@@ -786,12 +780,14 @@
     return NO_ERROR;
 }
 
-status_t SurfaceFlinger::getDisplayConfigsLocked(const sp<IBinder>& displayToken,
-                                                 Vector<DisplayInfo>* configs) {
+status_t SurfaceFlinger::getDisplayConfigs(const sp<IBinder>& displayToken,
+                                           Vector<DisplayInfo>* configs) {
     if (!displayToken || !configs) {
         return BAD_VALUE;
     }
 
+    Mutex::Autolock lock(mStateLock);
+
     const auto displayId = getPhysicalDisplayIdLocked(displayToken);
     if (!displayId) {
         return NAME_NOT_FOUND;
@@ -917,18 +913,6 @@
 void SurfaceFlinger::setDesiredActiveConfig(const ActiveConfigInfo& info) {
     ATRACE_CALL();
 
-    // Lock is acquired by setRefreshRateTo.
-    const auto display = getDisplayDeviceLocked(info.displayToken);
-    if (!display) {
-        ALOGE("Attempt to set active config %d for invalid display token %p", info.configId,
-              info.displayToken.get());
-        return;
-    }
-    if (display->isVirtual()) {
-        ALOGW("Attempt to set active config %d for virtual display", info.configId);
-        return;
-    }
-
     // 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
@@ -964,23 +948,28 @@
 void SurfaceFlinger::setActiveConfigInternal() {
     ATRACE_CALL();
 
-    std::lock_guard<std::mutex> lock(mActiveConfigLock);
-    mRefreshRateStats->setConfigMode(mUpcomingActiveConfig.configId);
+    const auto display = getDefaultDisplayDeviceLocked();
+    if (!display) {
+        return;
+    }
 
-    const auto display = getDisplayDeviceLocked(mUpcomingActiveConfig.displayToken);
+    std::lock_guard<std::mutex> lock(mActiveConfigLock);
+    mRefreshRateStats.setConfigMode(mUpcomingActiveConfig.configId);
+
     display->setActiveConfig(mUpcomingActiveConfig.configId);
 
     mScheduler->resyncToHardwareVsync(true, getVsyncPeriod());
     const auto [early, gl, late] = mPhaseOffsets->getCurrentOffsets();
     mVsyncModulator.setPhaseOffsets(early, gl, late);
     ATRACE_INT("ActiveConfigMode", mUpcomingActiveConfig.configId);
+
     if (mUpcomingActiveConfig.event != Scheduler::ConfigEvent::None) {
         mScheduler->onConfigChanged(mAppConnectionHandle, display->getId()->value,
                                     mUpcomingActiveConfig.configId);
     }
 }
 
-bool SurfaceFlinger::performSetActiveConfig() NO_THREAD_SAFETY_ANALYSIS {
+bool SurfaceFlinger::performSetActiveConfig() {
     ATRACE_CALL();
     if (mCheckPendingFence) {
         if (mPreviousPresentFence != Fence::NO_FENCE &&
@@ -1006,7 +995,7 @@
         desiredActiveConfig = mDesiredActiveConfig;
     }
 
-    const auto display = getDisplayDevice(desiredActiveConfig.displayToken);
+    const auto display = getDefaultDisplayDeviceLocked();
     if (!display || display->getActiveConfig() == desiredActiveConfig.configId) {
         // display is not valid or we are already in the requested mode
         // on both cases there is nothing left to do
@@ -1021,7 +1010,7 @@
     // Desired active config was set, it is different than the config currently in use, however
     // allowed configs might have change by the time we process the refresh.
     // Make sure the desired config is still allowed
-    if (!isConfigAllowed(*display->getId(), desiredActiveConfig.configId)) {
+    if (!isDisplayConfigAllowed(desiredActiveConfig.configId)) {
         std::lock_guard<std::mutex> lock(mActiveConfigLock);
         mDesiredActiveConfig.configId = display->getActiveConfig();
         return false;
@@ -1422,29 +1411,19 @@
     *compositorTiming = getBE().mCompositorTiming;
 }
 
-bool SurfaceFlinger::isConfigAllowed(const DisplayId& displayId, int32_t config) {
-    std::lock_guard lock(mAllowedConfigsLock);
-
-    // if allowed configs are not set yet for this display, every config is considered allowed
-    if (mAllowedConfigs.find(displayId) == mAllowedConfigs.end()) {
-        return true;
-    }
-
-    return mAllowedConfigs[displayId]->isConfigAllowed(config);
+bool SurfaceFlinger::isDisplayConfigAllowed(int32_t configId) {
+    return mAllowedDisplayConfigs.empty() || mAllowedDisplayConfigs.count(configId);
 }
 
 void SurfaceFlinger::setRefreshRateTo(RefreshRateType refreshRate, Scheduler::ConfigEvent event) {
-    if (mBootStage != BootStage::FINISHED) {
+    const auto display = getDefaultDisplayDeviceLocked();
+    if (!display || mBootStage != BootStage::FINISHED) {
         return;
     }
     ATRACE_CALL();
 
     // Don't do any updating if the current fps is the same as the new one.
-    const auto displayId = getInternalDisplayIdLocked();
-    LOG_ALWAYS_FATAL_IF(!displayId);
-    const auto displayToken = getInternalDisplayTokenLocked();
-
-    const auto& refreshRateConfig = mRefreshRateConfigs[*displayId]->getRefreshRate(refreshRate);
+    const auto& refreshRateConfig = mRefreshRateConfigs.getRefreshRate(refreshRate);
     if (!refreshRateConfig) {
         ALOGV("Skipping refresh rate change request for unsupported rate.");
         return;
@@ -1452,19 +1431,18 @@
 
     const int desiredConfigId = refreshRateConfig->configId;
 
-    if (!isConfigAllowed(*displayId, desiredConfigId)) {
+    if (!isDisplayConfigAllowed(desiredConfigId)) {
         ALOGV("Skipping config %d as it is not part of allowed configs", desiredConfigId);
         return;
     }
 
     mPhaseOffsets->setRefreshRateType(refreshRate);
 
-    const auto display = getDisplayDeviceLocked(displayToken);
     if (desiredConfigId == display->getActiveConfig()) {
         return;
     }
 
-    setDesiredActiveConfig({refreshRate, desiredConfigId, getInternalDisplayTokenLocked(), event});
+    setDesiredActiveConfig({refreshRate, desiredConfigId, event});
 }
 
 void SurfaceFlinger::onHotplugReceived(int32_t sequenceId, hwc2_display_t hwcDisplayId,
@@ -1604,7 +1582,7 @@
     setTransactionFlags(eDisplayTransactionNeeded);
 }
 
-void SurfaceFlinger::onMessageReceived(int32_t what) {
+void SurfaceFlinger::onMessageReceived(int32_t what) NO_THREAD_SAFETY_ANALYSIS {
     ATRACE_CALL();
     switch (what) {
         case MessageQueue::INVALIDATE: {
@@ -1631,7 +1609,7 @@
             if (mUseSmart90ForVideo) {
                 // This call is made each time SF wakes up and creates a new frame. It is part
                 // of video detection feature.
-                mScheduler->updateFpsBasedOnNativeWindowApi();
+                mScheduler->updateFpsBasedOnContent();
             }
 
             if (performSetActiveConfig()) {
@@ -1822,11 +1800,6 @@
                 layer->forceClientComposition(displayDevice);
             }
 
-            // TODO(b/111562338) remove when composer 2.3 is shipped.
-            if (layer->hasColorTransform()) {
-                layer->forceClientComposition(displayDevice);
-            }
-
             if (layer->getRoundedCornerState().radius > 0.0f) {
                 layer->forceClientComposition(displayDevice);
             }
@@ -2488,9 +2461,6 @@
                 state.displayName = info->name;
                 mCurrentState.displays.add(mPhysicalDisplayTokens[info->id], state);
                 mInterceptor->saveDisplayCreation(state);
-                // TODO(b/123715322): Removes the per-display state that was added to the scheduler.
-                mRefreshRateConfigs[info->id] = std::make_shared<scheduler::RefreshRateConfigs>(
-                        getHwComposer().getConfigs(info->id));
             }
         } else {
             ALOGV("Removing display %s", to_string(info->id).c_str());
@@ -2502,7 +2472,6 @@
                 mCurrentState.displays.removeItemsAt(index);
             }
             mPhysicalDisplayTokens.erase(info->id);
-            mRefreshRateConfigs.erase(info->id);
         }
 
         processDisplayChangesLocked();
@@ -3148,6 +3117,7 @@
 
 bool SurfaceFlinger::handlePageFlip()
 {
+    ATRACE_CALL();
     ALOGV("handlePageFlip");
 
     nsecs_t latchTime = systemTime();
@@ -3173,6 +3143,7 @@
             if (layer->shouldPresentNow(expectedPresentTime)) {
                 mLayersWithQueuedFrames.push_back(layer);
             } else {
+                ATRACE_NAME("!layer->shouldPresentNow()");
                 layer->useEmptyDamage();
             }
         } else {
@@ -3407,9 +3378,8 @@
         renderEngine.drawLayers(clientCompositionDisplay, clientCompositionLayers,
                                 buf->getNativeBuffer(), /*useFramebufferCache=*/true, std::move(fd),
                                 readyFence);
-        if (expensiveRenderingExpected && displayId) {
-            mPowerAdvisor.setExpensiveRenderingExpected(*displayId, false);
-        }
+    } else if (displayId) {
+        mPowerAdvisor.setExpensiveRenderingExpected(*displayId, false);
     }
     return true;
 }
@@ -3423,12 +3393,20 @@
         const sp<IBinder>& handle,
         const sp<IGraphicBufferProducer>& gbc,
         const sp<Layer>& lbc,
-        const sp<Layer>& parent,
+        const sp<IBinder>& parentHandle,
         bool addToCurrentState)
 {
     // add this layer to the current state list
     {
         Mutex::Autolock _l(mStateLock);
+        sp<Layer> parent;
+        if (parentHandle != nullptr) {
+            parent = fromHandle(parentHandle);
+            if (parent == nullptr) {
+                return NAME_NOT_FOUND;
+            }
+        }
+
         if (mNumLayers >= MAX_LAYERS) {
             ALOGE("AddClientLayer failed, mNumLayers (%zu) >= MAX_LAYERS (%zu)", mNumLayers,
                   MAX_LAYERS);
@@ -4013,10 +3991,8 @@
         buffer = s.buffer;
     }
     if (buffer) {
-        if (layer->setBuffer(buffer)) {
+        if (layer->setBuffer(buffer, postTime, desiredPresentTime)) {
             flags |= eTraversalNeeded;
-            layer->setPostTime(postTime);
-            layer->setDesiredPresentTime(desiredPresentTime);
         }
     }
     if (layer->setTransactionCompletedListeners(callbackHandles)) flags |= eTraversalNeeded;
@@ -4039,10 +4015,10 @@
     return flags;
 }
 
-status_t SurfaceFlinger::createLayer(const String8& name, const sp<Client>& client, uint32_t w,
-                                     uint32_t h, PixelFormat format, uint32_t flags,
-                                     LayerMetadata metadata, sp<IBinder>* handle,
-                                     sp<IGraphicBufferProducer>* gbp, sp<Layer>* parent) {
+status_t SurfaceFlinger::createLayer(
+        const String8& name, const sp<Client>& client, uint32_t w, uint32_t h, PixelFormat format,
+        uint32_t flags, LayerMetadata metadata, sp<IBinder>* handle,
+        sp<IGraphicBufferProducer>* gbp, const sp<IBinder>& parentHandle) {
     if (int32_t(w|h) < 0) {
         ALOGE("createLayer() failed, w or h is negative (w=%d, h=%d)",
                 int(w), int(h));
@@ -4062,7 +4038,7 @@
     if (metadata.has(METADATA_WINDOW_TYPE)) {
         int32_t windowType = metadata.getInt32(METADATA_WINDOW_TYPE, 0);
         if (windowType == 441731) {
-            metadata.setInt32(METADATA_WINDOW_TYPE, 2024); // TYPE_NAVIGATION_BAR_PANEL
+            metadata.setInt32(METADATA_WINDOW_TYPE, InputWindowInfo::TYPE_NAVIGATION_BAR_PANEL);
             primaryDisplayOnly = true;
         }
     }
@@ -4107,12 +4083,14 @@
         return result;
     }
 
+    mLayersByLocalBinderToken.emplace((*handle)->localBinder(), layer);
+
     if (primaryDisplayOnly) {
         layer->setPrimaryDisplayOnly();
     }
 
     bool addToCurrentState = callingThreadHasUnscopedSurfaceFlingerAccess();
-    result = addClientLayer(client, *handle, *gbp, layer, *parent,
+    result = addClientLayer(client, *handle, *gbp, layer, parentHandle,
             addToCurrentState);
     if (result != NO_ERROR) {
         return result;
@@ -4230,6 +4208,16 @@
         mCurrentState.layersSortedByZ.remove(layer);
     }
     markLayerPendingRemovalLocked(layer);
+
+    auto it = mLayersByLocalBinderToken.begin();
+    while (it != mLayersByLocalBinderToken.end()) {
+        if (it->second == layer) {
+            it = mLayersByLocalBinderToken.erase(it);
+        } else {
+            it++;
+        }
+    }
+
     layer.clear();
 }
 
@@ -4351,10 +4339,7 @@
 
     if (display->isPrimary()) {
         mTimeStats->setPowerMode(mode);
-        if (mRefreshRateStats) {
-            // Update refresh rate stats.
-            mRefreshRateStats->setPowerMode(mode);
-        }
+        mRefreshRateStats.setPowerMode(mode);
     }
 
     ALOGD("Finished setting power mode %d on display %s", mode, to_string(*displayId).c_str());
@@ -4882,7 +4867,7 @@
     result.append("\nScheduler state:\n");
     result.append(mScheduler->doDump() + "\n");
     StringAppendF(&result, "+  Smart video mode: %s\n\n", mUseSmart90ForVideo ? "on" : "off");
-    result.append(mRefreshRateStats->doDump() + "\n");
+    result.append(mRefreshRateStats.doDump() + "\n");
 }
 
 const Vector<sp<Layer>>& SurfaceFlinger::getLayerSortedByZForHwcDisplay(DisplayId displayId) {
@@ -5374,7 +5359,8 @@
 };
 
 status_t SurfaceFlinger::captureScreen(const sp<IBinder>& displayToken,
-                                       sp<GraphicBuffer>* outBuffer, const Dataspace reqDataspace,
+                                       sp<GraphicBuffer>* outBuffer, bool& outCapturedSecureLayers,
+                                       const Dataspace reqDataspace,
                                        const ui::PixelFormat reqPixelFormat, Rect sourceCrop,
                                        uint32_t reqWidth, uint32_t reqHeight,
                                        bool useIdentityTransform,
@@ -5407,13 +5393,14 @@
     auto traverseLayers = std::bind(&SurfaceFlinger::traverseLayersInDisplay, this, display,
                                     std::placeholders::_1);
     return captureScreenCommon(renderArea, traverseLayers, outBuffer, reqPixelFormat,
-                               useIdentityTransform);
+                               useIdentityTransform, outCapturedSecureLayers);
 }
 
-status_t SurfaceFlinger::captureLayers(const sp<IBinder>& layerHandleBinder,
-                                       sp<GraphicBuffer>* outBuffer, const Dataspace reqDataspace,
-                                       const ui::PixelFormat reqPixelFormat, const Rect& sourceCrop,
-                                       float frameScale, bool childrenOnly) {
+status_t SurfaceFlinger::captureLayers(
+        const sp<IBinder>& layerHandleBinder, sp<GraphicBuffer>* outBuffer,
+        const Dataspace reqDataspace, const ui::PixelFormat reqPixelFormat, const Rect& sourceCrop,
+        const std::unordered_set<sp<IBinder>, ISurfaceComposer::SpHash<IBinder>>& excludeHandles,
+        float frameScale, bool childrenOnly) {
     ATRACE_CALL();
 
     class LayerRenderArea : public RenderArea {
@@ -5498,34 +5485,50 @@
         const bool mChildrenOnly;
     };
 
-    auto layerHandle = reinterpret_cast<Layer::Handle*>(layerHandleBinder.get());
-    auto parent = layerHandle->owner.promote();
-
-    if (parent == nullptr || parent->isRemovedFromCurrentState()) {
-        ALOGE("captureLayers called with a removed parent");
-        return NAME_NOT_FOUND;
-    }
-
-    const int uid = IPCThreadState::self()->getCallingUid();
-    const bool forSystem = uid == AID_GRAPHICS || uid == AID_SYSTEM;
-    if (!forSystem && parent->getCurrentState().flags & layer_state_t::eLayerSecure) {
-        ALOGW("Attempting to capture secure layer: PERMISSION_DENIED");
-        return PERMISSION_DENIED;
-    }
-
+    int reqWidth = 0;
+    int reqHeight = 0;
+    sp<Layer> parent;
     Rect crop(sourceCrop);
-    if (sourceCrop.width() <= 0) {
-        crop.left = 0;
-        crop.right = parent->getBufferSize(parent->getCurrentState()).getWidth();
-    }
+    std::unordered_set<sp<Layer>, ISurfaceComposer::SpHash<Layer>> excludeLayers;
 
-    if (sourceCrop.height() <= 0) {
-        crop.top = 0;
-        crop.bottom = parent->getBufferSize(parent->getCurrentState()).getHeight();
-    }
+    {
+        Mutex::Autolock _l(mStateLock);
 
-    int32_t reqWidth = crop.width() * frameScale;
-    int32_t reqHeight = crop.height() * frameScale;
+        parent = fromHandle(layerHandleBinder);
+        if (parent == nullptr || parent->isRemovedFromCurrentState()) {
+            ALOGE("captureLayers called with an invalid or removed parent");
+            return NAME_NOT_FOUND;
+        }
+
+        const int uid = IPCThreadState::self()->getCallingUid();
+        const bool forSystem = uid == AID_GRAPHICS || uid == AID_SYSTEM;
+        if (!forSystem && parent->getCurrentState().flags & layer_state_t::eLayerSecure) {
+            ALOGW("Attempting to capture secure layer: PERMISSION_DENIED");
+            return PERMISSION_DENIED;
+        }
+
+        if (sourceCrop.width() <= 0) {
+            crop.left = 0;
+            crop.right = parent->getBufferSize(parent->getCurrentState()).getWidth();
+        }
+
+        if (sourceCrop.height() <= 0) {
+            crop.top = 0;
+            crop.bottom = parent->getBufferSize(parent->getCurrentState()).getHeight();
+        }
+        reqWidth = crop.width() * frameScale;
+        reqHeight = crop.height() * frameScale;
+
+        for (const auto& handle : excludeHandles) {
+            sp<Layer> excludeLayer = fromHandle(handle);
+            if (excludeLayer != nullptr) {
+                excludeLayers.emplace(excludeLayer);
+            } else {
+                ALOGW("Invalid layer handle passed as excludeLayer to captureLayers");
+                return NAME_NOT_FOUND;
+            }
+        }
+    } // mStateLock
 
     // really small crop or frameScale
     if (reqWidth <= 0) {
@@ -5536,25 +5539,38 @@
     }
 
     LayerRenderArea renderArea(this, parent, crop, reqWidth, reqHeight, reqDataspace, childrenOnly);
-
-    auto traverseLayers = [parent, childrenOnly](const LayerVector::Visitor& visitor) {
+    auto traverseLayers = [parent, childrenOnly,
+                           &excludeLayers](const LayerVector::Visitor& visitor) {
         parent->traverseChildrenInZOrder(LayerVector::StateSet::Drawing, [&](Layer* layer) {
             if (!layer->isVisible()) {
                 return;
             } else if (childrenOnly && layer == parent.get()) {
                 return;
             }
+
+            sp<Layer> p = layer;
+            while (p != nullptr) {
+                if (excludeLayers.count(p) != 0) {
+                    return;
+                }
+                p = p->getParent();
+            }
+
             visitor(layer);
         });
     };
-    return captureScreenCommon(renderArea, traverseLayers, outBuffer, reqPixelFormat, false);
+
+    bool outCapturedSecureLayers = false;
+    return captureScreenCommon(renderArea, traverseLayers, outBuffer, reqPixelFormat, false,
+                               outCapturedSecureLayers);
 }
 
 status_t SurfaceFlinger::captureScreenCommon(RenderArea& renderArea,
                                              TraverseLayersFunction traverseLayers,
                                              sp<GraphicBuffer>* outBuffer,
                                              const ui::PixelFormat reqPixelFormat,
-                                             bool useIdentityTransform) {
+                                             bool useIdentityTransform,
+                                             bool& outCapturedSecureLayers) {
     ATRACE_CALL();
 
     // TODO(b/116112787) Make buffer usage a parameter.
@@ -5565,13 +5581,15 @@
                                              static_cast<android_pixel_format>(reqPixelFormat), 1,
                                              usage, "screenshot");
 
-    return captureScreenCommon(renderArea, traverseLayers, *outBuffer, useIdentityTransform);
+    return captureScreenCommon(renderArea, traverseLayers, *outBuffer, useIdentityTransform,
+                               outCapturedSecureLayers);
 }
 
 status_t SurfaceFlinger::captureScreenCommon(RenderArea& renderArea,
                                              TraverseLayersFunction traverseLayers,
                                              const sp<GraphicBuffer>& buffer,
-                                             bool useIdentityTransform) {
+                                             bool useIdentityTransform,
+                                             bool& outCapturedSecureLayers) {
     // This mutex protects syncFd and captureResult for communication of the return values from the
     // main thread back to this Binder thread
     std::mutex captureMutex;
@@ -5600,7 +5618,8 @@
             Mutex::Autolock _l(mStateLock);
             renderArea.render([&] {
                 result = captureScreenImplLocked(renderArea, traverseLayers, buffer.get(),
-                                                 useIdentityTransform, forSystem, &fd);
+                                                 useIdentityTransform, forSystem, &fd,
+                                                 outCapturedSecureLayers);
             });
         }
 
@@ -5740,21 +5759,19 @@
 status_t SurfaceFlinger::captureScreenImplLocked(const RenderArea& renderArea,
                                                  TraverseLayersFunction traverseLayers,
                                                  ANativeWindowBuffer* buffer,
-                                                 bool useIdentityTransform,
-                                                 bool forSystem,
-                                                 int* outSyncFd) {
+                                                 bool useIdentityTransform, bool forSystem,
+                                                 int* outSyncFd, bool& outCapturedSecureLayers) {
     ATRACE_CALL();
 
-    bool secureLayerIsVisible = false;
-
     traverseLayers([&](Layer* layer) {
-        secureLayerIsVisible = secureLayerIsVisible || (layer->isVisible() && layer->isSecure());
+        outCapturedSecureLayers =
+                outCapturedSecureLayers || (layer->isVisible() && layer->isSecure());
     });
 
     // We allow the system server to take screenshots of secure layers for
     // use in situations like the Screen-rotation animation and place
     // the impetus on WindowManager to not persist them.
-    if (secureLayerIsVisible && !forSystem) {
+    if (outCapturedSecureLayers && !forSystem) {
         ALOGW("FB is protected: PERMISSION_DENIED");
         return PERMISSION_DENIED;
     }
@@ -5800,95 +5817,66 @@
     }
 }
 
-void SurfaceFlinger::setAllowedDisplayConfigsInternal(
-        const android::sp<android::IBinder>& displayToken,
-        std::unique_ptr<const AllowedDisplayConfigs>&& allowedConfigs) {
-    const auto displayId = getPhysicalDisplayIdLocked(displayToken);
-    if (!displayId) {
-        ALOGE("setAllowedDisplayConfigsInternal: getPhysicalDisplayId failed");
+void SurfaceFlinger::setAllowedDisplayConfigsInternal(const sp<DisplayDevice>& display,
+                                                      const std::vector<int32_t>& allowedConfigs) {
+    if (!display->isPrimary()) {
         return;
     }
 
     ALOGV("Updating allowed configs");
-    {
-        std::lock_guard lock(mAllowedConfigsLock);
-        mAllowedConfigs[*displayId] = std::move(allowedConfigs);
-    }
+    mAllowedDisplayConfigs = DisplayConfigs(allowedConfigs.begin(), allowedConfigs.end());
 
     // Set the highest allowed config by iterating backwards on available refresh rates
-    const auto& refreshRates = mRefreshRateConfigs[*displayId]->getRefreshRates();
+    const auto& refreshRates = mRefreshRateConfigs.getRefreshRates();
     for (auto iter = refreshRates.crbegin(); iter != refreshRates.crend(); ++iter) {
-        if (iter->second && isConfigAllowed(*displayId, iter->second->configId)) {
+        if (iter->second && isDisplayConfigAllowed(iter->second->configId)) {
             ALOGV("switching to config %d", iter->second->configId);
-            setDesiredActiveConfig({iter->first, iter->second->configId, displayToken,
-                                    Scheduler::ConfigEvent::Changed});
+            setDesiredActiveConfig(
+                    {iter->first, iter->second->configId, Scheduler::ConfigEvent::Changed});
             break;
         }
     }
 }
 
-status_t SurfaceFlinger::setAllowedDisplayConfigs(const android::sp<android::IBinder>& displayToken,
+status_t SurfaceFlinger::setAllowedDisplayConfigs(const sp<IBinder>& displayToken,
                                                   const std::vector<int32_t>& allowedConfigs) {
     ATRACE_CALL();
 
-    if (!displayToken) {
-        ALOGE("setAllowedDisplayConfigs: displayToken is null");
+    if (!displayToken || allowedConfigs.empty()) {
         return BAD_VALUE;
     }
 
-    if (!allowedConfigs.size()) {
-        ALOGE("setAllowedDisplayConfigs: empty config set provided");
-        return BAD_VALUE;
-    }
-
-    {
-        ConditionalLock lock(mStateLock, std::this_thread::get_id() != mMainThreadId);
-        const auto displayId = getPhysicalDisplayIdLocked(displayToken);
-        if (!displayId) {
-            ALOGE("setAllowedDisplayConfigs: display not found");
-            return NAME_NOT_FOUND;
-        }
-    }
-
-    auto allowedDisplayConfigsBuilder = AllowedDisplayConfigs::Builder();
-    for (int config : allowedConfigs) {
-        ALOGV("setAllowedDisplayConfigs: Adding config to the allowed configs = %d", config);
-        allowedDisplayConfigsBuilder.addConfig(config);
-    }
-    auto allowedDisplayConfigs = allowedDisplayConfigsBuilder.build();
     postMessageSync(new LambdaMessage([&]() NO_THREAD_SAFETY_ANALYSIS {
-        setAllowedDisplayConfigsInternal(displayToken, std::move(allowedDisplayConfigs));
+        const auto display = getDisplayDeviceLocked(displayToken);
+        if (!display) {
+            ALOGE("Attempt to set allowed display configs for invalid display token %p",
+                  displayToken.get());
+        } else if (display->isVirtual()) {
+            ALOGW("Attempt to set allowed display configs for virtual display");
+        } else {
+            setAllowedDisplayConfigsInternal(display, allowedConfigs);
+        }
     }));
+
     return NO_ERROR;
 }
 
-status_t SurfaceFlinger::getAllowedDisplayConfigs(const android::sp<android::IBinder>& displayToken,
+status_t SurfaceFlinger::getAllowedDisplayConfigs(const sp<IBinder>& displayToken,
                                                   std::vector<int32_t>* outAllowedConfigs) {
     ATRACE_CALL();
 
-    if (!displayToken) {
-        ALOGE("getAllowedDisplayConfigs: displayToken is null");
+    if (!displayToken || !outAllowedConfigs) {
         return BAD_VALUE;
     }
 
-    if (!outAllowedConfigs) {
-        ALOGE("getAllowedDisplayConfigs: outAllowedConfigs is null");
-        return BAD_VALUE;
-    }
+    Mutex::Autolock lock(mStateLock);
 
-    ConditionalLock stateLock(mStateLock, std::this_thread::get_id() != mMainThreadId);
-    const auto displayId = getPhysicalDisplayIdLocked(displayToken);
-    if (!displayId) {
-        ALOGE("getAllowedDisplayConfigs: display not found");
+    if (displayToken != getInternalDisplayTokenLocked()) {
+        ALOGE("%s is only supported for the internal display", __FUNCTION__);
         return NAME_NOT_FOUND;
     }
 
-    std::lock_guard allowedConfigLock(mAllowedConfigsLock);
-    auto allowedConfigIterator = mAllowedConfigs.find(displayId.value());
-    if (allowedConfigIterator != mAllowedConfigs.end()) {
-        allowedConfigIterator->second->getAllowedConfigs(outAllowedConfigs);
-    }
-
+    outAllowedConfigs->assign(mAllowedDisplayConfigs.begin(), mAllowedDisplayConfigs.end());
     return NO_ERROR;
 }
 
@@ -5896,6 +5884,18 @@
     mFlinger->setInputWindowsFinished();
 }
 
+sp<Layer> SurfaceFlinger::fromHandle(const sp<IBinder>& handle) {
+    BBinder *b = handle->localBinder();
+    if (b == nullptr) {
+        return nullptr;
+    }
+    auto it = mLayersByLocalBinderToken.find(b);
+    if (it != mLayersByLocalBinderToken.end()) {
+        return it->second.promote();
+    }
+    return nullptr;
+}
+
 } // namespace android
 
 #if defined(__gl_h_)
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 5cd0f21..d8108c5 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -46,7 +46,6 @@
 #include <utils/Trace.h>
 #include <utils/threads.h>
 
-#include "AllowedDisplayConfigs.h"
 #include "DisplayDevice.h"
 #include "DisplayHardware/HWC2.h"
 #include "DisplayHardware/PowerAdvisor.h"
@@ -74,6 +73,7 @@
 #include <thread>
 #include <type_traits>
 #include <unordered_map>
+#include <unordered_set>
 #include <utility>
 
 using namespace android::surfaceflinger;
@@ -313,6 +313,8 @@
         return mTransactionCompletedThread;
     }
 
+    sp<Layer> fromHandle(const sp<IBinder>& handle) REQUIRES(mStateLock);
+
 private:
     friend class BufferLayer;
     friend class BufferQueueLayer;
@@ -395,21 +397,20 @@
     sp<IDisplayEventConnection> createDisplayEventConnection(
             ISurfaceComposer::VsyncSource vsyncSource = eVsyncSourceApp) override;
     status_t captureScreen(const sp<IBinder>& displayToken, sp<GraphicBuffer>* outBuffer,
-                           const ui::Dataspace reqDataspace, const ui::PixelFormat reqPixelFormat,
-                           Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight,
-                           bool useIdentityTransform, ISurfaceComposer::Rotation rotation,
-                           bool captureSecureLayers) override;
-    status_t captureLayers(const sp<IBinder>& parentHandle, sp<GraphicBuffer>* outBuffer,
-                           const ui::Dataspace reqDataspace, const ui::PixelFormat reqPixelFormat,
-                           const Rect& sourceCrop, float frameScale, bool childrenOnly) override;
+            bool& outCapturedSecureLayers, const ui::Dataspace reqDataspace,
+            const ui::PixelFormat reqPixelFormat, Rect sourceCrop,
+            uint32_t reqWidth, uint32_t reqHeight,
+            bool useIdentityTransform, ISurfaceComposer::Rotation rotation, bool captureSecureLayers) override;
+    status_t captureLayers(
+            const sp<IBinder>& parentHandle, sp<GraphicBuffer>* outBuffer,
+            const ui::Dataspace reqDataspace, const ui::PixelFormat reqPixelFormat,
+            const Rect& sourceCrop,
+            const std::unordered_set<sp<IBinder>, ISurfaceComposer::SpHash<IBinder>>& exclude,
+            float frameScale, bool childrenOnly) override;
+
     status_t getDisplayStats(const sp<IBinder>& displayToken, DisplayStatInfo* stats) override;
     status_t getDisplayConfigs(const sp<IBinder>& displayToken,
-                               Vector<DisplayInfo>* configs) override {
-        Mutex::Autolock _l(mStateLock);
-        return getDisplayConfigsLocked(displayToken, configs);
-    }
-    status_t getDisplayConfigsLocked(const sp<IBinder>& displayToken, Vector<DisplayInfo>* configs)
-            REQUIRES(mStateLock);
+                               Vector<DisplayInfo>* configs) override;
     int getActiveConfig(const sp<IBinder>& displayToken) override;
     status_t getDisplayColorModes(const sp<IBinder>& displayToken,
                                   Vector<ui::ColorMode>* configs) override;
@@ -488,20 +489,10 @@
     struct ActiveConfigInfo {
         RefreshRateType type;
         int configId;
-        sp<IBinder> displayToken;
         Scheduler::ConfigEvent event;
 
         bool operator!=(const ActiveConfigInfo& other) const {
-            if (type != other.type) {
-                return true;
-            }
-            if (configId != other.configId) {
-                return true;
-            }
-            if (displayToken != other.displayToken) {
-                return true;
-            }
-            return (event != other.event);
+            return type != other.type || configId != other.configId || event != other.event;
         }
     };
 
@@ -516,14 +507,14 @@
     // desired config was set, HWC needs to update the panel on the next refresh, and when
     // we receive the fence back, we know that the process was complete. It returns whether
     // we need to wait for the next invalidate
-    bool performSetActiveConfig();
+    bool performSetActiveConfig() REQUIRES(mStateLock);
     // called on the main thread in response to setPowerMode()
     void setPowerModeInternal(const sp<DisplayDevice>& display, int mode) REQUIRES(mStateLock);
 
     // called on the main thread in response to setAllowedDisplayConfigs()
-    void setAllowedDisplayConfigsInternal(
-            const sp<IBinder>& displayToken,
-            std::unique_ptr<const AllowedDisplayConfigs>&& allowedConfigs) REQUIRES(mStateLock);
+    void setAllowedDisplayConfigsInternal(const sp<DisplayDevice>& display,
+                                          const std::vector<int32_t>& allowedConfigs)
+            REQUIRES(mStateLock);
 
     // Returns whether the transaction actually modified any state
     bool handleMessageTransaction();
@@ -584,9 +575,10 @@
     /* ------------------------------------------------------------------------
      * Layer management
      */
-    status_t createLayer(const String8& name, const sp<Client>& client, uint32_t w, uint32_t h,
-                         PixelFormat format, uint32_t flags, LayerMetadata metadata,
-                         sp<IBinder>* handle, sp<IGraphicBufferProducer>* gbp, sp<Layer>* parent);
+    status_t createLayer(
+            const String8& name, const sp<Client>& client, uint32_t w, uint32_t h,
+            PixelFormat format, uint32_t flags, LayerMetadata metadata,
+            sp<IBinder>* handle, sp<IGraphicBufferProducer>* gbp, const sp<IBinder>& parentHandle);
 
     status_t createBufferQueueLayer(const sp<Client>& client, const String8& name, uint32_t w,
                                     uint32_t h, uint32_t flags, LayerMetadata metadata,
@@ -618,7 +610,7 @@
             const sp<IBinder>& handle,
             const sp<IGraphicBufferProducer>& gbc,
             const sp<Layer>& lbc,
-            const sp<Layer>& parent,
+            const sp<IBinder>& parentHandle,
             bool addToCurrentState);
 
     // Traverse through all the layers and compute and cache its bounds.
@@ -637,13 +629,14 @@
                                 int* outSyncFd);
     status_t captureScreenCommon(RenderArea& renderArea, TraverseLayersFunction traverseLayers,
                                  sp<GraphicBuffer>* outBuffer, const ui::PixelFormat reqPixelFormat,
-                                 bool useIdentityTransform);
+                                 bool useIdentityTransform, bool& outCapturedSecureLayers);
     status_t captureScreenCommon(RenderArea& renderArea, TraverseLayersFunction traverseLayers,
-                                 const sp<GraphicBuffer>& buffer, bool useIdentityTransform);
+                                 const sp<GraphicBuffer>& buffer, bool useIdentityTransform,
+                                 bool& outCapturedSecureLayers);
     status_t captureScreenImplLocked(const RenderArea& renderArea,
                                      TraverseLayersFunction traverseLayers,
                                      ANativeWindowBuffer* buffer, bool useIdentityTransform,
-                                     bool forSystem, int* outSyncFd);
+                                     bool forSystem, int* outSyncFd, bool& outCapturedSecureLayers);
     void traverseLayersInDisplay(const sp<const DisplayDevice>& display,
                                  const LayerVector::Visitor& visitor);
 
@@ -802,7 +795,7 @@
     // the desired refresh rate.
     void setRefreshRateTo(RefreshRateType, Scheduler::ConfigEvent event) REQUIRES(mStateLock);
 
-    bool isConfigAllowed(const DisplayId& displayId, int32_t config);
+    bool isDisplayConfigAllowed(int32_t configId) REQUIRES(mStateLock);
 
     /*
      * Display identification
@@ -991,6 +984,9 @@
     std::map<wp<IBinder>, sp<DisplayDevice>> mDisplays;
     std::unordered_map<DisplayId, sp<IBinder>> mPhysicalDisplayTokens;
 
+    // protected by mStateLock
+    std::unordered_map<BBinder*, wp<Layer>> mLayersByLocalBinderToken;
+
     // don't use a lock for these, we don't care
     int mDebugRegion = 0;
     bool mDebugDisableHWC = false;
@@ -1108,14 +1104,13 @@
     std::unique_ptr<Scheduler> mScheduler;
     sp<Scheduler::ConnectionHandle> mAppConnectionHandle;
     sp<Scheduler::ConnectionHandle> mSfConnectionHandle;
-    std::unique_ptr<scheduler::RefreshRateStats> mRefreshRateStats;
 
-    std::unordered_map<DisplayId, std::shared_ptr<scheduler::RefreshRateConfigs>>
-            mRefreshRateConfigs;
+    scheduler::RefreshRateConfigs mRefreshRateConfigs;
+    scheduler::RefreshRateStats mRefreshRateStats{mRefreshRateConfigs, *mTimeStats};
 
-    std::mutex mAllowedConfigsLock;
-    std::unordered_map<DisplayId, std::unique_ptr<const AllowedDisplayConfigs>> mAllowedConfigs
-            GUARDED_BY(mAllowedConfigsLock);
+    // All configs are allowed if the set is empty.
+    using DisplayConfigs = std::set<int32_t>;
+    DisplayConfigs mAllowedDisplayConfigs GUARDED_BY(mStateLock);
 
     std::mutex mActiveConfigLock;
     // This bit is set once we start setting the config. We read from this bit during the
diff --git a/services/surfaceflinger/SurfaceFlingerFactory.cpp b/services/surfaceflinger/SurfaceFlingerFactory.cpp
index 26d2c21..e425b2a 100644
--- a/services/surfaceflinger/SurfaceFlingerFactory.cpp
+++ b/services/surfaceflinger/SurfaceFlingerFactory.cpp
@@ -73,8 +73,10 @@
             return std::make_unique<scheduler::impl::PhaseOffsets>();
         }
 
-        std::unique_ptr<Scheduler> createScheduler(std::function<void(bool)> callback) override {
-            return std::make_unique<Scheduler>(callback);
+        std::unique_ptr<Scheduler> createScheduler(
+                std::function<void(bool)> callback,
+                const scheduler::RefreshRateConfigs& refreshRateConfig) override {
+            return std::make_unique<Scheduler>(callback, refreshRateConfig);
         }
 
         std::unique_ptr<SurfaceInterceptor> createSurfaceInterceptor(
diff --git a/services/surfaceflinger/SurfaceFlingerFactory.h b/services/surfaceflinger/SurfaceFlingerFactory.h
index fc1d0f8..c2bc808 100644
--- a/services/surfaceflinger/SurfaceFlingerFactory.h
+++ b/services/surfaceflinger/SurfaceFlingerFactory.h
@@ -71,7 +71,9 @@
     virtual std::unique_ptr<HWComposer> createHWComposer(const std::string& serviceName) = 0;
     virtual std::unique_ptr<MessageQueue> createMessageQueue() = 0;
     virtual std::unique_ptr<scheduler::PhaseOffsets> createPhaseOffsets() = 0;
-    virtual std::unique_ptr<Scheduler> createScheduler(std::function<void(bool)> callback) = 0;
+    virtual std::unique_ptr<Scheduler> createScheduler(
+            std::function<void(bool)> callback,
+            const scheduler::RefreshRateConfigs& refreshRateConfig) = 0;
     virtual std::unique_ptr<SurfaceInterceptor> createSurfaceInterceptor(SurfaceFlinger*) = 0;
 
     virtual sp<StartPropertySetThread> createStartPropertySetThread(
diff --git a/services/surfaceflinger/tests/Android.bp b/services/surfaceflinger/tests/Android.bp
index f121a95..d3c87bf 100644
--- a/services/surfaceflinger/tests/Android.bp
+++ b/services/surfaceflinger/tests/Android.bp
@@ -19,6 +19,7 @@
     srcs: [
         "BufferGenerator.cpp",
         "Credentials_test.cpp",
+        "InvalidHandles_test.cpp",
         "Stress_test.cpp",
         "SurfaceInterceptor_test.cpp",
         "Transaction_test.cpp",
diff --git a/services/surfaceflinger/tests/InvalidHandles_test.cpp b/services/surfaceflinger/tests/InvalidHandles_test.cpp
new file mode 100644
index 0000000..42d1f5a
--- /dev/null
+++ b/services/surfaceflinger/tests/InvalidHandles_test.cpp
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <binder/Binder.h>
+
+#include <gtest/gtest.h>
+
+#include <gui/ISurfaceComposer.h>
+#include <gui/SurfaceComposerClient.h>
+#include <private/gui/ComposerService.h>
+#include <ui/Rect.h>
+
+namespace android {
+namespace {
+
+class NotALayer : public BBinder {};
+
+/**
+ * For all of these tests we make a SurfaceControl with an invalid layer handle
+ * and verify we aren't able to trick SurfaceFlinger.
+ */
+class InvalidHandleTest : public ::testing::Test {
+protected:
+    sp<SurfaceComposerClient> mScc;
+    sp<SurfaceControl> mNotSc;
+    void SetUp() override {
+        mScc = new SurfaceComposerClient;
+        ASSERT_EQ(NO_ERROR, mScc->initCheck());
+        mNotSc = makeNotSurfaceControl();
+    }
+
+    sp<SurfaceControl> makeNotSurfaceControl() {
+        return new SurfaceControl(mScc, new NotALayer(), nullptr, true);
+    }
+};
+
+TEST_F(InvalidHandleTest, createSurfaceInvalidHandle) {
+    auto notSc = makeNotSurfaceControl();
+    ASSERT_EQ(nullptr,
+              mScc->createSurface(String8("lolcats"), 19, 47, PIXEL_FORMAT_RGBA_8888, 0,
+                                  notSc.get())
+                      .get());
+}
+
+TEST_F(InvalidHandleTest, captureLayersInvalidHandle) {
+    sp<ISurfaceComposer> sf(ComposerService::getComposerService());
+    sp<GraphicBuffer> outBuffer;
+
+    ASSERT_EQ(NAME_NOT_FOUND,
+              sf->captureLayers(mNotSc->getHandle(), &outBuffer, Rect::EMPTY_RECT, 1.0f));
+}
+
+} // namespace
+} // namespace android
diff --git a/services/surfaceflinger/tests/SurfaceFlinger_test.filter b/services/surfaceflinger/tests/SurfaceFlinger_test.filter
index be862c9..a8d09ea 100644
--- a/services/surfaceflinger/tests/SurfaceFlinger_test.filter
+++ b/services/surfaceflinger/tests/SurfaceFlinger_test.filter
@@ -1,5 +1,5 @@
 {
         "presubmit": {
-            "filter": "CredentialsTest.*:SurfaceFlingerStress.*:SurfaceInterceptorTest.*:LayerTransactionTest.*:LayerTypeTransactionTest.*:LayerUpdateTest.*:GeometryLatchingTest.*:CropLatchingTest.*:ChildLayerTest.*:ScreenCaptureTest.*:ScreenCaptureChildOnlyTest.*:DereferenceSurfaceControlTest.*:BoundlessLayerTest.*:MultiDisplayLayerBoundsTest.*"
+            "filter": "CredentialsTest.*:SurfaceFlingerStress.*:SurfaceInterceptorTest.*:LayerTransactionTest.*:LayerTypeTransactionTest.*:LayerUpdateTest.*:GeometryLatchingTest.*:CropLatchingTest.*:ChildLayerTest.*:ScreenCaptureTest.*:ScreenCaptureChildOnlyTest.*:DereferenceSurfaceControlTest.*:BoundlessLayerTest.*:MultiDisplayLayerBoundsTest.*:InvalidHandleTest.*"
         }
 }
diff --git a/services/surfaceflinger/tests/Transaction_test.cpp b/services/surfaceflinger/tests/Transaction_test.cpp
index d62afa5..d03c25d 100644
--- a/services/surfaceflinger/tests/Transaction_test.cpp
+++ b/services/surfaceflinger/tests/Transaction_test.cpp
@@ -231,6 +231,20 @@
         *sc = std::make_unique<ScreenCapture>(outBuffer);
     }
 
+    static void captureChildLayersExcluding(
+            std::unique_ptr<ScreenCapture>* sc, sp<IBinder>& parentHandle,
+            std::unordered_set<sp<IBinder>, ISurfaceComposer::SpHash<IBinder>> excludeLayers) {
+        sp<ISurfaceComposer> sf(ComposerService::getComposerService());
+        SurfaceComposerClient::Transaction().apply(true);
+
+        sp<GraphicBuffer> outBuffer;
+        ASSERT_EQ(NO_ERROR,
+                  sf->captureLayers(parentHandle, &outBuffer, ui::Dataspace::V0_SRGB,
+                                    ui::PixelFormat::RGBA_8888, Rect::EMPTY_RECT, excludeLayers,
+                                    1.0f, true));
+        *sc = std::make_unique<ScreenCapture>(outBuffer);
+    }
+
     void expectColor(const Rect& rect, const Color& color, uint8_t tolerance = 0) {
         ASSERT_EQ(HAL_PIXEL_FORMAT_RGBA_8888, mOutBuffer->getPixelFormat());
         expectBufferColor(mOutBuffer, mPixels, rect, color, tolerance);
@@ -1255,11 +1269,12 @@
 
     // Here we pass captureSecureLayers = true and since we are AID_SYSTEM we should be able
     // to receive them...we are expected to take care with the results.
+    bool outCapturedSecureLayers;
     ASSERT_EQ(NO_ERROR,
-              composer->captureScreen(mDisplay, &outBuffer,
-                      ui::Dataspace::V0_SRGB, ui::PixelFormat::RGBA_8888,
-                      Rect(), 0, 0, false,
-                      ISurfaceComposer::eRotateNone, true));
+              composer->captureScreen(mDisplay, &outBuffer, outCapturedSecureLayers,
+                                      ui::Dataspace::V0_SRGB, ui::PixelFormat::RGBA_8888, Rect(), 0,
+                                      0, false, ISurfaceComposer::eRotateNone, true));
+    ASSERT_EQ(true, outCapturedSecureLayers);
     ScreenCapture sc(outBuffer);
     sc.expectColor(Rect(0, 0, 32, 32), Color::RED);
 }
@@ -5238,6 +5253,57 @@
     mCapture->expectChildColor(0, 0);
 }
 
+TEST_F(ScreenCaptureTest, CaptureLayerExclude) {
+    auto fgHandle = mFGSurfaceControl->getHandle();
+
+    sp<SurfaceControl> child = createSurface(mClient, "Child surface", 10, 10,
+                                             PIXEL_FORMAT_RGBA_8888, 0, mFGSurfaceControl.get());
+    fillSurfaceRGBA8(child, 200, 200, 200);
+    sp<SurfaceControl> child2 = createSurface(mClient, "Child surface", 10, 10,
+                                              PIXEL_FORMAT_RGBA_8888, 0, mFGSurfaceControl.get());
+    fillSurfaceRGBA8(child2, 200, 0, 200);
+
+    SurfaceComposerClient::Transaction()
+            .show(child)
+            .show(child2)
+            .setLayer(child, 1)
+            .setLayer(child2, 2)
+            .apply(true);
+
+    // Child2 would be visible but its excluded, so we should see child1 color instead.
+    ScreenCapture::captureChildLayersExcluding(&mCapture, fgHandle, {child2->getHandle()});
+    mCapture->checkPixel(10, 10, 0, 0, 0);
+    mCapture->checkPixel(0, 0, 200, 200, 200);
+}
+
+// Like the last test but verifies that children are also exclude.
+TEST_F(ScreenCaptureTest, CaptureLayerExcludeTree) {
+    auto fgHandle = mFGSurfaceControl->getHandle();
+
+    sp<SurfaceControl> child = createSurface(mClient, "Child surface", 10, 10,
+                                             PIXEL_FORMAT_RGBA_8888, 0, mFGSurfaceControl.get());
+    fillSurfaceRGBA8(child, 200, 200, 200);
+    sp<SurfaceControl> child2 = createSurface(mClient, "Child surface", 10, 10,
+                                              PIXEL_FORMAT_RGBA_8888, 0, mFGSurfaceControl.get());
+    fillSurfaceRGBA8(child2, 200, 0, 200);
+    sp<SurfaceControl> child3 = createSurface(mClient, "Child surface", 10, 10,
+                                              PIXEL_FORMAT_RGBA_8888, 0, child2.get());
+    fillSurfaceRGBA8(child2, 200, 0, 200);
+
+    SurfaceComposerClient::Transaction()
+            .show(child)
+            .show(child2)
+            .show(child3)
+            .setLayer(child, 1)
+            .setLayer(child2, 2)
+            .apply(true);
+
+    // Child2 would be visible but its excluded, so we should see child1 color instead.
+    ScreenCapture::captureChildLayersExcluding(&mCapture, fgHandle, {child2->getHandle()});
+    mCapture->checkPixel(10, 10, 0, 0, 0);
+    mCapture->checkPixel(0, 0, 200, 200, 200);
+}
+
 TEST_F(ScreenCaptureTest, CaptureTransparent) {
     sp<SurfaceControl> child = createSurface(mClient, "Child surface", 10, 10,
                                              PIXEL_FORMAT_RGBA_8888, 0, mFGSurfaceControl.get());
diff --git a/services/surfaceflinger/tests/unittests/AllowedDisplayConfigsTest.cpp b/services/surfaceflinger/tests/unittests/AllowedDisplayConfigsTest.cpp
deleted file mode 100644
index 4274254..0000000
--- a/services/surfaceflinger/tests/unittests/AllowedDisplayConfigsTest.cpp
+++ /dev/null
@@ -1,96 +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.
- */
-
-#undef LOG_TAG
-#define LOG_TAG "LibSurfaceFlingerUnittests"
-#define LOG_NDEBUG 0
-
-#include <memory>
-#include <vector>
-
-#include <gtest/gtest.h>
-
-#include <log/log.h>
-
-#include "AllowedDisplayConfigs.h"
-
-namespace android {
-namespace {
-
-class AllowedDisplayConfigsTest : public testing::Test {
-protected:
-    AllowedDisplayConfigsTest();
-    ~AllowedDisplayConfigsTest() override;
-
-    void buildAllowedConfigs();
-
-    const std::vector<int32_t> expectedConfigs = {0, 2, 7, 129};
-    constexpr static int32_t notAllowedConfig = 5;
-    std::unique_ptr<const AllowedDisplayConfigs> mAllowedConfigs;
-};
-
-AllowedDisplayConfigsTest::AllowedDisplayConfigsTest() {
-    const ::testing::TestInfo* const test_info =
-            ::testing::UnitTest::GetInstance()->current_test_info();
-    ALOGD("**** Setting up for %s.%s\n", test_info->test_case_name(), test_info->name());
-}
-
-AllowedDisplayConfigsTest::~AllowedDisplayConfigsTest() {
-    const ::testing::TestInfo* const test_info =
-            ::testing::UnitTest::GetInstance()->current_test_info();
-    ALOGD("**** Tearing down after %s.%s\n", test_info->test_case_name(), test_info->name());
-}
-
-void AllowedDisplayConfigsTest::buildAllowedConfigs() {
-    AllowedDisplayConfigs::Builder builder;
-    for (int config : expectedConfigs) {
-        builder.addConfig(config);
-    }
-    mAllowedConfigs = builder.build();
-}
-
-/* ------------------------------------------------------------------------
- * Test cases
- */
-
-TEST_F(AllowedDisplayConfigsTest, checkConfigs) {
-    buildAllowedConfigs();
-
-    // Check that all expected configs are allowed
-    for (int config : expectedConfigs) {
-        EXPECT_TRUE(mAllowedConfigs->isConfigAllowed(config));
-    }
-
-    // Check that all the allowed configs are expected
-    std::vector<int32_t> allowedConfigVector;
-    mAllowedConfigs->getAllowedConfigs(&allowedConfigVector);
-    EXPECT_EQ(allowedConfigVector, expectedConfigs);
-
-    // Check that notAllowedConfig is indeed not allowed
-    EXPECT_TRUE(std::find(expectedConfigs.begin(), expectedConfigs.end(), notAllowedConfig) ==
-                expectedConfigs.end());
-    EXPECT_FALSE(mAllowedConfigs->isConfigAllowed(notAllowedConfig));
-}
-
-TEST_F(AllowedDisplayConfigsTest, getAllowedConfigsNullptr) {
-    buildAllowedConfigs();
-
-    // No other expectations rather than no crash
-    mAllowedConfigs->getAllowedConfigs(nullptr);
-}
-
-} // namespace
-} // namespace android
diff --git a/services/surfaceflinger/tests/unittests/Android.bp b/services/surfaceflinger/tests/unittests/Android.bp
index d4eac88..85e9ce5 100644
--- a/services/surfaceflinger/tests/unittests/Android.bp
+++ b/services/surfaceflinger/tests/unittests/Android.bp
@@ -35,7 +35,6 @@
     srcs: [
         ":libsurfaceflinger_sources",
         "libsurfaceflinger_unittest_main.cpp",
-        "AllowedDisplayConfigsTest.cpp",
         "CompositionTest.cpp",
         "DispSyncSourceTest.cpp",
         "DisplayIdentificationTest.cpp",
diff --git a/services/surfaceflinger/tests/unittests/CompositionTest.cpp b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
index ef3dfef..bebfa6c 100644
--- a/services/surfaceflinger/tests/unittests/CompositionTest.cpp
+++ b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
@@ -125,7 +125,7 @@
     }
 
     void setupScheduler() {
-        mScheduler = new TestableScheduler();
+        mScheduler = new TestableScheduler(mFlinger.mutableRefreshRateConfigs());
         mScheduler->mutableEventControlThread().reset(mEventControlThread);
         mScheduler->mutablePrimaryDispSync().reset(mPrimaryDispSync);
         EXPECT_CALL(*mEventThread.get(), registerDisplayEventConnection(_));
diff --git a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
index 9bf29a2..d83f1bd 100644
--- a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
+++ b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
@@ -179,7 +179,7 @@
 }
 
 void DisplayTransactionTest::setupScheduler() {
-    mScheduler = new TestableScheduler();
+    mScheduler = new TestableScheduler(mFlinger.mutableRefreshRateConfigs());
     mScheduler->mutableEventControlThread().reset(mEventControlThread);
     mScheduler->mutablePrimaryDispSync().reset(mPrimaryDispSync);
     EXPECT_CALL(*mEventThread, registerDisplayEventConnection(_));
diff --git a/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp b/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp
index 3fb1a6e..e51121f 100644
--- a/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp
+++ b/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp
@@ -7,6 +7,7 @@
 #include <log/log.h>
 
 #include <mutex>
+#include <thread>
 
 #include "Scheduler/LayerHistory.h"
 
@@ -14,6 +15,7 @@
 using testing::Return;
 
 namespace android {
+namespace scheduler {
 
 class LayerHistoryTest : public testing::Test {
 public:
@@ -22,6 +24,8 @@
 
 protected:
     std::unique_ptr<LayerHistory> mLayerHistory;
+
+    static constexpr float MAX_REFRESH_RATE = 90.f;
 };
 
 LayerHistoryTest::LayerHistoryTest() {
@@ -30,145 +34,79 @@
 LayerHistoryTest::~LayerHistoryTest() {}
 
 namespace {
-TEST_F(LayerHistoryTest, simpleInsertAndGet) {
-    mLayerHistory->insert("TestLayer", 0);
+TEST_F(LayerHistoryTest, oneLayer) {
+    std::unique_ptr<LayerHistory::LayerHandle> testLayer =
+            mLayerHistory->createLayer("TestLayer", MAX_REFRESH_RATE);
 
-    const std::unordered_map<std::string, nsecs_t>& testMap = mLayerHistory->get(0);
-    EXPECT_EQ(1, testMap.size());
-    auto element = testMap.find("TestLayer");
-    EXPECT_EQ("TestLayer", element->first);
-    EXPECT_EQ(0, element->second);
+    mLayerHistory->insert(testLayer, 0);
+    EXPECT_FLOAT_EQ(0.f, mLayerHistory->getDesiredRefreshRate());
 
-    // Testing accessing object at an empty container will return an empty map.
-    const std::unordered_map<std::string, nsecs_t>& emptyMap = mLayerHistory->get(1);
-    EXPECT_EQ(0, emptyMap.size());
+    mLayerHistory->insert(testLayer, 0);
+    mLayerHistory->insert(testLayer, 0);
+    mLayerHistory->insert(testLayer, 0);
+    // This is still 0, because the layer is not considered recently active if it
+    // has been present in less than 10 frames.
+    EXPECT_FLOAT_EQ(0.f, mLayerHistory->getDesiredRefreshRate());
+    mLayerHistory->insert(testLayer, 0);
+    mLayerHistory->insert(testLayer, 0);
+    mLayerHistory->insert(testLayer, 0);
+    mLayerHistory->insert(testLayer, 0);
+    mLayerHistory->insert(testLayer, 0);
+    mLayerHistory->insert(testLayer, 0);
+    // This should be MAX_REFRESH_RATE as we have more than 10 samples
+    EXPECT_FLOAT_EQ(MAX_REFRESH_RATE, mLayerHistory->getDesiredRefreshRate());
 }
 
-TEST_F(LayerHistoryTest, multipleInserts) {
-    mLayerHistory->insert("TestLayer0", 0);
-    mLayerHistory->insert("TestLayer1", 1);
-    mLayerHistory->insert("TestLayer2", 2);
-    mLayerHistory->insert("TestLayer3", 3);
+TEST_F(LayerHistoryTest, explicitTimestamp) {
+    std::unique_ptr<LayerHistory::LayerHandle> test30FpsLayer =
+            mLayerHistory->createLayer("30FpsLayer", MAX_REFRESH_RATE);
 
-    const std::unordered_map<std::string, nsecs_t>& testMap = mLayerHistory->get(0);
-    // Because the counter was not incremented, all elements were inserted into the first
-    // container.
-    EXPECT_EQ(4, testMap.size());
-    auto element = testMap.find("TestLayer0");
-    EXPECT_EQ("TestLayer0", element->first);
-    EXPECT_EQ(0, element->second);
-
-    element = testMap.find("TestLayer1");
-    EXPECT_EQ("TestLayer1", element->first);
-    EXPECT_EQ(1, element->second);
-
-    element = testMap.find("TestLayer2");
-    EXPECT_EQ("TestLayer2", element->first);
-    EXPECT_EQ(2, element->second);
-
-    element = testMap.find("TestLayer3");
-    EXPECT_EQ("TestLayer3", element->first);
-    EXPECT_EQ(3, element->second);
-
-    // Testing accessing object at an empty container will return an empty map.
-    const std::unordered_map<std::string, nsecs_t>& emptyMap = mLayerHistory->get(1);
-    EXPECT_EQ(0, emptyMap.size());
-}
-
-TEST_F(LayerHistoryTest, incrementingCounter) {
-    mLayerHistory->insert("TestLayer0", 0);
-    mLayerHistory->incrementCounter();
-    mLayerHistory->insert("TestLayer1", 1);
-    mLayerHistory->insert("TestLayer2", 2);
-    mLayerHistory->incrementCounter();
-    mLayerHistory->insert("TestLayer3", 3);
-
-    // Because the counter was incremented, the elements were inserted into different
-    // containers.
-    // We expect the get method to access the slot at the current counter of the index
-    // is 0.
-    const std::unordered_map<std::string, nsecs_t>& testMap1 = mLayerHistory->get(0);
-    EXPECT_EQ(1, testMap1.size());
-    auto element = testMap1.find("TestLayer3");
-    EXPECT_EQ("TestLayer3", element->first);
-    EXPECT_EQ(3, element->second);
-
-    const std::unordered_map<std::string, nsecs_t>& testMap2 = mLayerHistory->get(1);
-    EXPECT_EQ(2, testMap2.size());
-    element = testMap2.find("TestLayer1");
-    EXPECT_EQ("TestLayer1", element->first);
-    EXPECT_EQ(1, element->second);
-    element = testMap2.find("TestLayer2");
-    EXPECT_EQ("TestLayer2", element->first);
-    EXPECT_EQ(2, element->second);
-
-    const std::unordered_map<std::string, nsecs_t>& testMap3 = mLayerHistory->get(2);
-    EXPECT_EQ(1, testMap3.size());
-    element = testMap3.find("TestLayer0");
-    EXPECT_EQ("TestLayer0", element->first);
-    EXPECT_EQ(0, element->second);
-
-    // Testing accessing object at an empty container will return an empty map.
-    const std::unordered_map<std::string, nsecs_t>& emptyMap = mLayerHistory->get(3);
-    EXPECT_EQ(0, emptyMap.size());
-}
-
-TEST_F(LayerHistoryTest, clearTheMap) {
-    mLayerHistory->insert("TestLayer0", 0);
-
-    const std::unordered_map<std::string, nsecs_t>& testMap1 = mLayerHistory->get(0);
-    EXPECT_EQ(1, testMap1.size());
-    auto element = testMap1.find("TestLayer0");
-    EXPECT_EQ("TestLayer0", element->first);
-    EXPECT_EQ(0, element->second);
-
-    mLayerHistory->incrementCounter();
-    // The array currently contains 30 elements.
-    for (int i = 1; i < 30; ++i) {
-        mLayerHistory->insert("TestLayer0", i);
-        mLayerHistory->incrementCounter();
-    }
-    // Expect the map to be cleared.
-    const std::unordered_map<std::string, nsecs_t>& testMap2 = mLayerHistory->get(0);
-    EXPECT_EQ(0, testMap2.size());
-
-    mLayerHistory->insert("TestLayer30", 30);
-    const std::unordered_map<std::string, nsecs_t>& testMap3 = mLayerHistory->get(0);
-    element = testMap3.find("TestLayer30");
-    EXPECT_EQ("TestLayer30", element->first);
-    EXPECT_EQ(30, element->second);
-    // The original element in this location does not exist anymore.
-    element = testMap3.find("TestLayer0");
-    EXPECT_EQ(testMap3.end(), element);
-}
-
-TEST_F(LayerHistoryTest, testingGet) {
-    // The array currently contains 30 elements.
-    for (int i = 0; i < 30; ++i) {
-        const auto name = "TestLayer" + std::to_string(i);
-        mLayerHistory->insert(name, i);
-        mLayerHistory->incrementCounter();
+    nsecs_t startTime = systemTime();
+    for (int i = 0; i < 31; i++) {
+        mLayerHistory->insert(test30FpsLayer, startTime + (i * 33333333));
     }
 
-    // The counter should be set to 0, and the map at 0 should be cleared.
-    const std::unordered_map<std::string, nsecs_t>& testMap1 = mLayerHistory->get(0);
-    EXPECT_EQ(0, testMap1.size());
+    EXPECT_FLOAT_EQ(30.f, mLayerHistory->getDesiredRefreshRate());
+}
 
-    // This should return (ARRAY_SIZE + (counter - 3)) % ARRAY_SIZE
-    const std::unordered_map<std::string, nsecs_t>& testMap2 = mLayerHistory->get(3);
-    EXPECT_EQ(1, testMap2.size());
-    auto element = testMap2.find("TestLayer27");
-    EXPECT_EQ("TestLayer27", element->first);
-    EXPECT_EQ(27, element->second);
+TEST_F(LayerHistoryTest, multipleLayers) {
+    std::unique_ptr<LayerHistory::LayerHandle> testLayer =
+            mLayerHistory->createLayer("TestLayer", MAX_REFRESH_RATE);
+    std::unique_ptr<LayerHistory::LayerHandle> test30FpsLayer =
+            mLayerHistory->createLayer("30FpsLayer", MAX_REFRESH_RATE);
+    std::unique_ptr<LayerHistory::LayerHandle> testLayer2 =
+            mLayerHistory->createLayer("TestLayer2", MAX_REFRESH_RATE);
 
-    // If the user gives an out of bound index, we should mod it with ARRAY_SIZE first,
-    // so requesting element 40 would be the same as requesting element 10.
-    const std::unordered_map<std::string, nsecs_t>& testMap3 = mLayerHistory->get(40);
-    EXPECT_EQ(1, testMap3.size());
-    element = testMap3.find("TestLayer20");
-    EXPECT_EQ("TestLayer20", element->first);
-    EXPECT_EQ(20, element->second);
+    nsecs_t startTime = systemTime();
+    for (int i = 0; i < 10; i++) {
+        mLayerHistory->insert(testLayer, 0);
+    }
+    EXPECT_FLOAT_EQ(MAX_REFRESH_RATE, mLayerHistory->getDesiredRefreshRate());
+
+    startTime = systemTime();
+    for (int i = 0; i < 10; i++) {
+        mLayerHistory->insert(test30FpsLayer, startTime + (i * 33333333));
+    }
+    EXPECT_FLOAT_EQ(MAX_REFRESH_RATE, mLayerHistory->getDesiredRefreshRate());
+
+    for (int i = 10; i < 30; i++) {
+        mLayerHistory->insert(test30FpsLayer, startTime + (i * 33333333));
+    }
+    EXPECT_FLOAT_EQ(MAX_REFRESH_RATE, mLayerHistory->getDesiredRefreshRate());
+
+    // This frame is only around for 9 occurrences, so it doesn't throw
+    // anything off.
+    for (int i = 0; i < 9; i++) {
+        mLayerHistory->insert(testLayer2, 0);
+    }
+    EXPECT_FLOAT_EQ(MAX_REFRESH_RATE, mLayerHistory->getDesiredRefreshRate());
+    // After 100 ms frames become obsolete.
+    std::this_thread::sleep_for(std::chrono::milliseconds(500));
+    // Insert the 31st frame.
+    mLayerHistory->insert(test30FpsLayer, startTime + (30 * 33333333));
+    EXPECT_FLOAT_EQ(30.f, mLayerHistory->getDesiredRefreshRate());
 }
 
 } // namespace
+} // namespace scheduler
 } // namespace android
\ No newline at end of file
diff --git a/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp b/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp
index b218ad6..8b37c22 100644
--- a/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp
+++ b/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp
@@ -49,6 +49,8 @@
         ASSERT_EQ(left.name, right.name);
         ASSERT_EQ(left.fps, right.fps);
     }
+
+    RefreshRateConfigs mConfigs;
 };
 
 RefreshRateConfigsTest::RefreshRateConfigsTest() {
@@ -69,10 +71,10 @@
  */
 TEST_F(RefreshRateConfigsTest, zeroDeviceConfigs_storesPowerSavingConfig) {
     std::vector<std::shared_ptr<const HWC2::Display::Config>> displayConfigs;
-    RefreshRateConfigs configs(displayConfigs);
+    mConfigs.populate(displayConfigs);
 
     // We always store a configuration for screen off.
-    const auto& rates = configs.getRefreshRates();
+    const auto& rates = mConfigs.getRefreshRates();
     ASSERT_EQ(1, rates.size());
     const auto& powerSavingRate = rates.find(RefreshRateType::POWER_SAVING);
     ASSERT_NE(rates.end(), powerSavingRate);
@@ -82,13 +84,13 @@
     RefreshRate expectedConfig = RefreshRate{SCREEN_OFF_CONFIG_ID, "ScreenOff", 0};
     assertRatesEqual(expectedConfig, *powerSavingRate->second);
 
-    ASSERT_TRUE(configs.getRefreshRate(RefreshRateType::POWER_SAVING));
-    assertRatesEqual(expectedConfig, *configs.getRefreshRate(RefreshRateType::POWER_SAVING));
-    ASSERT_FALSE(configs.getRefreshRate(RefreshRateType::PERFORMANCE));
-    ASSERT_FALSE(configs.getRefreshRate(RefreshRateType::DEFAULT));
+    ASSERT_TRUE(mConfigs.getRefreshRate(RefreshRateType::POWER_SAVING));
+    assertRatesEqual(expectedConfig, *mConfigs.getRefreshRate(RefreshRateType::POWER_SAVING));
+    ASSERT_FALSE(mConfigs.getRefreshRate(RefreshRateType::PERFORMANCE));
+    ASSERT_FALSE(mConfigs.getRefreshRate(RefreshRateType::DEFAULT));
 
     // Sanity check that getRefreshRate() does not modify the underlying configs.
-    ASSERT_EQ(1, configs.getRefreshRates().size());
+    ASSERT_EQ(1, mConfigs.getRefreshRates().size());
 }
 
 TEST_F(RefreshRateConfigsTest, oneDeviceConfig_storesDefaultConfig) {
@@ -97,9 +99,9 @@
     auto config60 = HWC2::Display::Config::Builder(*display, CONFIG_ID_60);
     config60.setVsyncPeriod(VSYNC_60);
     displayConfigs.push_back(config60.build());
-    RefreshRateConfigs configs(displayConfigs);
+    mConfigs.populate(displayConfigs);
 
-    const auto& rates = configs.getRefreshRates();
+    const auto& rates = mConfigs.getRefreshRates();
     ASSERT_EQ(2, rates.size());
     const auto& powerSavingRate = rates.find(RefreshRateType::POWER_SAVING);
     const auto& defaultRate = rates.find(RefreshRateType::DEFAULT);
@@ -112,15 +114,15 @@
     RefreshRate expectedDefaultConfig = RefreshRate{CONFIG_ID_60, "60fps", 60};
     assertRatesEqual(expectedDefaultConfig, *defaultRate->second);
 
-    ASSERT_TRUE(configs.getRefreshRate(RefreshRateType::POWER_SAVING));
+    ASSERT_TRUE(mConfigs.getRefreshRate(RefreshRateType::POWER_SAVING));
     assertRatesEqual(expectedPowerSavingConfig,
-                     *configs.getRefreshRate(RefreshRateType::POWER_SAVING));
-    ASSERT_TRUE(configs.getRefreshRate(RefreshRateType::DEFAULT));
-    assertRatesEqual(expectedDefaultConfig, *configs.getRefreshRate(RefreshRateType::DEFAULT));
-    ASSERT_FALSE(configs.getRefreshRate(RefreshRateType::PERFORMANCE));
+                     *mConfigs.getRefreshRate(RefreshRateType::POWER_SAVING));
+    ASSERT_TRUE(mConfigs.getRefreshRate(RefreshRateType::DEFAULT));
+    assertRatesEqual(expectedDefaultConfig, *mConfigs.getRefreshRate(RefreshRateType::DEFAULT));
+    ASSERT_FALSE(mConfigs.getRefreshRate(RefreshRateType::PERFORMANCE));
 
     // Sanity check that getRefreshRate() does not modify the underlying configs.
-    ASSERT_EQ(2, configs.getRefreshRates().size());
+    ASSERT_EQ(2, mConfigs.getRefreshRates().size());
 }
 
 TEST_F(RefreshRateConfigsTest, twoDeviceConfigs_storesPerformanceConfig) {
@@ -132,9 +134,9 @@
     auto config90 = HWC2::Display::Config::Builder(*display, CONFIG_ID_90);
     config90.setVsyncPeriod(VSYNC_90);
     displayConfigs.push_back(config90.build());
-    RefreshRateConfigs configs(displayConfigs);
+    mConfigs.populate(displayConfigs);
 
-    const auto& rates = configs.getRefreshRates();
+    const auto& rates = mConfigs.getRefreshRates();
     ASSERT_EQ(3, rates.size());
     const auto& powerSavingRate = rates.find(RefreshRateType::POWER_SAVING);
     const auto& defaultRate = rates.find(RefreshRateType::DEFAULT);
@@ -150,14 +152,14 @@
     RefreshRate expectedPerformanceConfig = RefreshRate{CONFIG_ID_90, "90fps", 90};
     assertRatesEqual(expectedPerformanceConfig, *performanceRate->second);
 
-    ASSERT_TRUE(configs.getRefreshRate(RefreshRateType::POWER_SAVING));
+    ASSERT_TRUE(mConfigs.getRefreshRate(RefreshRateType::POWER_SAVING));
     assertRatesEqual(expectedPowerSavingConfig,
-                     *configs.getRefreshRate(RefreshRateType::POWER_SAVING));
-    ASSERT_TRUE(configs.getRefreshRate(RefreshRateType::DEFAULT));
-    assertRatesEqual(expectedDefaultConfig, *configs.getRefreshRate(RefreshRateType::DEFAULT));
-    ASSERT_TRUE(configs.getRefreshRate(RefreshRateType::PERFORMANCE));
+                     *mConfigs.getRefreshRate(RefreshRateType::POWER_SAVING));
+    ASSERT_TRUE(mConfigs.getRefreshRate(RefreshRateType::DEFAULT));
+    assertRatesEqual(expectedDefaultConfig, *mConfigs.getRefreshRate(RefreshRateType::DEFAULT));
+    ASSERT_TRUE(mConfigs.getRefreshRate(RefreshRateType::PERFORMANCE));
     assertRatesEqual(expectedPerformanceConfig,
-                     *configs.getRefreshRate(RefreshRateType::PERFORMANCE));
+                     *mConfigs.getRefreshRate(RefreshRateType::PERFORMANCE));
 }
 } // namespace
 } // namespace scheduler
diff --git a/services/surfaceflinger/tests/unittests/RefreshRateStatsTest.cpp b/services/surfaceflinger/tests/unittests/RefreshRateStatsTest.cpp
index 10f5af8..411ec61 100644
--- a/services/surfaceflinger/tests/unittests/RefreshRateStatsTest.cpp
+++ b/services/surfaceflinger/tests/unittests/RefreshRateStatsTest.cpp
@@ -42,11 +42,9 @@
     RefreshRateStatsTest();
     ~RefreshRateStatsTest();
 
-    void init(std::vector<std::shared_ptr<const HWC2::Display::Config>> configs);
-
-    std::unique_ptr<RefreshRateStats> mRefreshRateStats;
-    std::shared_ptr<android::mock::TimeStats> mTimeStats;
-    std::shared_ptr<RefreshRateConfigs> mRefreshRateConfigs;
+    mock::TimeStats mTimeStats;
+    RefreshRateConfigs mRefreshRateConfigs;
+    RefreshRateStats mRefreshRateStats{mRefreshRateConfigs, mTimeStats};
 };
 
 RefreshRateStatsTest::RefreshRateStatsTest() {
@@ -61,22 +59,16 @@
     ALOGD("**** Tearing down after %s.%s\n", test_info->test_case_name(), test_info->name());
 }
 
-void RefreshRateStatsTest::init(std::vector<std::shared_ptr<const HWC2::Display::Config>> configs) {
-    mTimeStats = std::make_shared<android::mock::TimeStats>();
-    mRefreshRateConfigs = std::make_shared<RefreshRateConfigs>(configs);
-    mRefreshRateStats = std::make_unique<RefreshRateStats>(mRefreshRateConfigs, mTimeStats);
-}
-
 namespace {
 /* ------------------------------------------------------------------------
  * Test cases
  */
 TEST_F(RefreshRateStatsTest, canCreateAndDestroyTest) {
     std::vector<std::shared_ptr<const HWC2::Display::Config>> configs;
-    init(configs);
+    mRefreshRateConfigs.populate(configs);
 
     // There is one default config, so the refresh rates should have one item.
-    EXPECT_EQ(1, mRefreshRateStats->getTotalTimes().size());
+    EXPECT_EQ(1, mRefreshRateStats.getTotalTimes().size());
 }
 
 TEST_F(RefreshRateStatsTest, oneConfigTest) {
@@ -87,12 +79,12 @@
     std::vector<std::shared_ptr<const HWC2::Display::Config>> configs;
     configs.push_back(config.build());
 
-    init(configs);
+    mRefreshRateConfigs.populate(configs);
 
-    EXPECT_CALL(*mTimeStats, recordRefreshRate(0, _)).Times(AtLeast(1));
-    EXPECT_CALL(*mTimeStats, recordRefreshRate(90, _)).Times(AtLeast(1));
+    EXPECT_CALL(mTimeStats, recordRefreshRate(0, _)).Times(AtLeast(1));
+    EXPECT_CALL(mTimeStats, recordRefreshRate(90, _)).Times(AtLeast(1));
 
-    std::unordered_map<std::string, int64_t> times = mRefreshRateStats->getTotalTimes();
+    std::unordered_map<std::string, int64_t> times = mRefreshRateStats.getTotalTimes();
     EXPECT_EQ(2, times.size());
     EXPECT_NE(0u, times.count("ScreenOff"));
     EXPECT_EQ(1u, times.count("90fps"));
@@ -105,29 +97,29 @@
 
     // Screen is off by default.
     std::this_thread::sleep_for(std::chrono::milliseconds(2));
-    times = mRefreshRateStats->getTotalTimes();
+    times = mRefreshRateStats.getTotalTimes();
     EXPECT_LT(screenOff, times["ScreenOff"]);
     EXPECT_EQ(0, times["90fps"]);
 
-    mRefreshRateStats->setConfigMode(CONFIG_ID_90);
-    mRefreshRateStats->setPowerMode(HWC_POWER_MODE_NORMAL);
-    screenOff = mRefreshRateStats->getTotalTimes()["ScreenOff"];
+    mRefreshRateStats.setConfigMode(CONFIG_ID_90);
+    mRefreshRateStats.setPowerMode(HWC_POWER_MODE_NORMAL);
+    screenOff = mRefreshRateStats.getTotalTimes()["ScreenOff"];
     std::this_thread::sleep_for(std::chrono::milliseconds(2));
-    times = mRefreshRateStats->getTotalTimes();
+    times = mRefreshRateStats.getTotalTimes();
     EXPECT_EQ(screenOff, times["ScreenOff"]);
     EXPECT_LT(ninety, times["90fps"]);
 
-    mRefreshRateStats->setPowerMode(HWC_POWER_MODE_DOZE);
-    ninety = mRefreshRateStats->getTotalTimes()["90fps"];
+    mRefreshRateStats.setPowerMode(HWC_POWER_MODE_DOZE);
+    ninety = mRefreshRateStats.getTotalTimes()["90fps"];
     std::this_thread::sleep_for(std::chrono::milliseconds(2));
-    times = mRefreshRateStats->getTotalTimes();
+    times = mRefreshRateStats.getTotalTimes();
     EXPECT_LT(screenOff, times["ScreenOff"]);
     EXPECT_EQ(ninety, times["90fps"]);
 
-    mRefreshRateStats->setConfigMode(CONFIG_ID_90);
-    screenOff = mRefreshRateStats->getTotalTimes()["ScreenOff"];
+    mRefreshRateStats.setConfigMode(CONFIG_ID_90);
+    screenOff = mRefreshRateStats.getTotalTimes()["ScreenOff"];
     std::this_thread::sleep_for(std::chrono::milliseconds(2));
-    times = mRefreshRateStats->getTotalTimes();
+    times = mRefreshRateStats.getTotalTimes();
     // Because the power mode is not HWC_POWER_MODE_NORMAL, switching the config
     // does not update refresh rates that come from the config.
     EXPECT_LT(screenOff, times["ScreenOff"]);
@@ -146,13 +138,13 @@
     config60.setVsyncPeriod(VSYNC_60);
     configs.push_back(config60.build());
 
-    init(configs);
+    mRefreshRateConfigs.populate(configs);
 
-    EXPECT_CALL(*mTimeStats, recordRefreshRate(0, _)).Times(AtLeast(1));
-    EXPECT_CALL(*mTimeStats, recordRefreshRate(60, _)).Times(AtLeast(1));
-    EXPECT_CALL(*mTimeStats, recordRefreshRate(90, _)).Times(AtLeast(1));
+    EXPECT_CALL(mTimeStats, recordRefreshRate(0, _)).Times(AtLeast(1));
+    EXPECT_CALL(mTimeStats, recordRefreshRate(60, _)).Times(AtLeast(1));
+    EXPECT_CALL(mTimeStats, recordRefreshRate(90, _)).Times(AtLeast(1));
 
-    std::unordered_map<std::string, int64_t> times = mRefreshRateStats->getTotalTimes();
+    std::unordered_map<std::string, int64_t> times = mRefreshRateStats.getTotalTimes();
     EXPECT_EQ(3, times.size());
     EXPECT_NE(0u, times.count("ScreenOff"));
     EXPECT_EQ(1u, times.count("60fps"));
@@ -168,60 +160,60 @@
 
     // Screen is off by default.
     std::this_thread::sleep_for(std::chrono::milliseconds(2));
-    times = mRefreshRateStats->getTotalTimes();
+    times = mRefreshRateStats.getTotalTimes();
     EXPECT_LT(screenOff, times["ScreenOff"]);
     EXPECT_EQ(sixty, times["60fps"]);
     EXPECT_EQ(ninety, times["90fps"]);
 
-    mRefreshRateStats->setConfigMode(CONFIG_ID_90);
-    mRefreshRateStats->setPowerMode(HWC_POWER_MODE_NORMAL);
-    screenOff = mRefreshRateStats->getTotalTimes()["ScreenOff"];
+    mRefreshRateStats.setConfigMode(CONFIG_ID_90);
+    mRefreshRateStats.setPowerMode(HWC_POWER_MODE_NORMAL);
+    screenOff = mRefreshRateStats.getTotalTimes()["ScreenOff"];
     std::this_thread::sleep_for(std::chrono::milliseconds(2));
-    times = mRefreshRateStats->getTotalTimes();
+    times = mRefreshRateStats.getTotalTimes();
     EXPECT_EQ(screenOff, times["ScreenOff"]);
     EXPECT_EQ(sixty, times["60fps"]);
     EXPECT_LT(ninety, times["90fps"]);
 
     // When power mode is normal, time for configs updates.
-    mRefreshRateStats->setConfigMode(CONFIG_ID_60);
-    ninety = mRefreshRateStats->getTotalTimes()["90fps"];
+    mRefreshRateStats.setConfigMode(CONFIG_ID_60);
+    ninety = mRefreshRateStats.getTotalTimes()["90fps"];
     std::this_thread::sleep_for(std::chrono::milliseconds(2));
-    times = mRefreshRateStats->getTotalTimes();
+    times = mRefreshRateStats.getTotalTimes();
     EXPECT_EQ(screenOff, times["ScreenOff"]);
     EXPECT_EQ(ninety, times["90fps"]);
     EXPECT_LT(sixty, times["60fps"]);
 
-    mRefreshRateStats->setConfigMode(CONFIG_ID_90);
-    sixty = mRefreshRateStats->getTotalTimes()["60fps"];
+    mRefreshRateStats.setConfigMode(CONFIG_ID_90);
+    sixty = mRefreshRateStats.getTotalTimes()["60fps"];
     std::this_thread::sleep_for(std::chrono::milliseconds(2));
-    times = mRefreshRateStats->getTotalTimes();
+    times = mRefreshRateStats.getTotalTimes();
     EXPECT_EQ(screenOff, times["ScreenOff"]);
     EXPECT_LT(ninety, times["90fps"]);
     EXPECT_EQ(sixty, times["60fps"]);
 
-    mRefreshRateStats->setConfigMode(CONFIG_ID_60);
-    ninety = mRefreshRateStats->getTotalTimes()["90fps"];
+    mRefreshRateStats.setConfigMode(CONFIG_ID_60);
+    ninety = mRefreshRateStats.getTotalTimes()["90fps"];
     std::this_thread::sleep_for(std::chrono::milliseconds(2));
-    times = mRefreshRateStats->getTotalTimes();
+    times = mRefreshRateStats.getTotalTimes();
     EXPECT_EQ(screenOff, times["ScreenOff"]);
     EXPECT_EQ(ninety, times["90fps"]);
     EXPECT_LT(sixty, times["60fps"]);
 
     // Because the power mode is not HWC_POWER_MODE_NORMAL, switching the config
     // does not update refresh rates that come from the config.
-    mRefreshRateStats->setPowerMode(HWC_POWER_MODE_DOZE);
-    mRefreshRateStats->setConfigMode(CONFIG_ID_90);
-    sixty = mRefreshRateStats->getTotalTimes()["60fps"];
+    mRefreshRateStats.setPowerMode(HWC_POWER_MODE_DOZE);
+    mRefreshRateStats.setConfigMode(CONFIG_ID_90);
+    sixty = mRefreshRateStats.getTotalTimes()["60fps"];
     std::this_thread::sleep_for(std::chrono::milliseconds(2));
-    times = mRefreshRateStats->getTotalTimes();
+    times = mRefreshRateStats.getTotalTimes();
     EXPECT_LT(screenOff, times["ScreenOff"]);
     EXPECT_EQ(ninety, times["90fps"]);
     EXPECT_EQ(sixty, times["60fps"]);
 
-    mRefreshRateStats->setConfigMode(CONFIG_ID_60);
-    screenOff = mRefreshRateStats->getTotalTimes()["ScreenOff"];
+    mRefreshRateStats.setConfigMode(CONFIG_ID_60);
+    screenOff = mRefreshRateStats.getTotalTimes()["ScreenOff"];
     std::this_thread::sleep_for(std::chrono::milliseconds(2));
-    times = mRefreshRateStats->getTotalTimes();
+    times = mRefreshRateStats.getTotalTimes();
     EXPECT_LT(screenOff, times["ScreenOff"]);
     EXPECT_EQ(ninety, times["90fps"]);
     EXPECT_EQ(sixty, times["60fps"]);
diff --git a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
index ec76538..b960bdf 100644
--- a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
+++ b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
@@ -33,14 +33,17 @@
         MOCK_METHOD0(requestNextVsync, void());
     };
 
+    scheduler::RefreshRateConfigs mRefreshRateConfigs;
+
     /**
      * This mock Scheduler class uses implementation of mock::EventThread but keeps everything else
      * the same.
      */
     class MockScheduler : public android::Scheduler {
     public:
-        MockScheduler(std::unique_ptr<EventThread> eventThread)
-              : Scheduler([](bool) {}), mEventThread(std::move(eventThread)) {}
+        MockScheduler(const scheduler::RefreshRateConfigs& refreshRateConfigs,
+                      std::unique_ptr<EventThread> eventThread)
+              : Scheduler([](bool) {}, refreshRateConfigs), mEventThread(std::move(eventThread)) {}
 
         std::unique_ptr<EventThread> makeEventThread(
                 const char* /* connectionName */, DispSync* /* dispSync */,
@@ -71,7 +74,7 @@
 
     std::unique_ptr<mock::EventThread> eventThread = std::make_unique<mock::EventThread>();
     mEventThread = eventThread.get();
-    mScheduler = std::make_unique<MockScheduler>(std::move(eventThread));
+    mScheduler = std::make_unique<MockScheduler>(mRefreshRateConfigs, std::move(eventThread));
     EXPECT_CALL(*mEventThread, registerDisplayEventConnection(_)).WillOnce(Return(0));
 
     mEventThreadConnection = new MockEventThreadConnection(mEventThread);
diff --git a/services/surfaceflinger/tests/unittests/TestableScheduler.h b/services/surfaceflinger/tests/unittests/TestableScheduler.h
index dcbf973..1c397d8 100644
--- a/services/surfaceflinger/tests/unittests/TestableScheduler.h
+++ b/services/surfaceflinger/tests/unittests/TestableScheduler.h
@@ -19,13 +19,15 @@
 #include <gmock/gmock.h>
 
 #include "Scheduler/EventThread.h"
+#include "Scheduler/RefreshRateConfigs.h"
 #include "Scheduler/Scheduler.h"
 
 namespace android {
 
 class TestableScheduler : public Scheduler {
 public:
-    TestableScheduler() : Scheduler([](bool) {}) {}
+    TestableScheduler(const scheduler::RefreshRateConfigs& refreshRateConfig)
+          : Scheduler([](bool) {}, refreshRateConfig) {}
 
     // Creates EventThreadConnection with the given eventThread. Creates Scheduler::Connection
     // and adds it to the list of connectins. Returns the ConnectionHandle for the
diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
index 81235ba..df14e7e 100644
--- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
+++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
@@ -86,7 +86,8 @@
         return std::make_unique<scheduler::FakePhaseOffsets>();
     }
 
-    std::unique_ptr<Scheduler> createScheduler(std::function<void(bool)>) override {
+    std::unique_ptr<Scheduler> createScheduler(std::function<void(bool)>,
+                                               const scheduler::RefreshRateConfigs&) override {
         // TODO: Use test-fixture controlled factory
         return nullptr;
     }
@@ -276,12 +277,13 @@
 
     auto onMessageReceived(int32_t what) { return mFlinger->onMessageReceived(what); }
 
-    auto captureScreenImplLocked(const RenderArea& renderArea,
-                                 SurfaceFlinger::TraverseLayersFunction traverseLayers,
-                                 ANativeWindowBuffer* buffer, bool useIdentityTransform,
-                                 bool forSystem, int* outSyncFd) {
+    auto captureScreenImplLocked(
+            const RenderArea& renderArea, SurfaceFlinger::TraverseLayersFunction traverseLayers,
+            ANativeWindowBuffer* buffer, bool useIdentityTransform, bool forSystem, int* outSyncFd) {
+        bool ignored;
         return mFlinger->captureScreenImplLocked(renderArea, traverseLayers, buffer,
-                                                 useIdentityTransform, forSystem, outSyncFd);
+                                                 useIdentityTransform, forSystem, outSyncFd,
+                                                 ignored);
     }
 
     auto traverseLayersInDisplay(const sp<const DisplayDevice>& display,
@@ -339,6 +341,7 @@
     auto& mutableScheduler() { return mFlinger->mScheduler; }
     auto& mutableAppConnectionHandle() { return mFlinger->mAppConnectionHandle; }
     auto& mutableSfConnectionHandle() { return mFlinger->mSfConnectionHandle; }
+    auto& mutableRefreshRateConfigs() { return mFlinger->mRefreshRateConfigs; }
 
     ~TestableSurfaceFlinger() {
         // All these pointer and container clears help ensure that GMock does
diff --git a/services/vr/virtual_touchpad/Android.bp b/services/vr/virtual_touchpad/Android.bp
index 0263481..131a306 100644
--- a/services/vr/virtual_touchpad/Android.bp
+++ b/services/vr/virtual_touchpad/Android.bp
@@ -62,7 +62,7 @@
 service_src = [
     "main.cpp",
     "VirtualTouchpadService.cpp",
-    "aidl/android/dvr/VirtualTouchpadService.aidl",
+    "aidl/android/dvr/IVirtualTouchpadService.aidl",
 ]
 
 service_static_libs = [
@@ -99,7 +99,7 @@
 client_src = [
     "VirtualTouchpadClient.cpp",
     "DvrVirtualTouchpadClient.cpp",
-    "aidl/android/dvr/VirtualTouchpadService.aidl",
+    "aidl/android/dvr/IVirtualTouchpadService.aidl",
 ]
 
 client_shared_libs = [
diff --git a/services/vr/virtual_touchpad/aidl/android/dvr/VirtualTouchpadService.aidl b/services/vr/virtual_touchpad/aidl/android/dvr/IVirtualTouchpadService.aidl
similarity index 97%
rename from services/vr/virtual_touchpad/aidl/android/dvr/VirtualTouchpadService.aidl
rename to services/vr/virtual_touchpad/aidl/android/dvr/IVirtualTouchpadService.aidl
index 256203c..89aa44a 100644
--- a/services/vr/virtual_touchpad/aidl/android/dvr/VirtualTouchpadService.aidl
+++ b/services/vr/virtual_touchpad/aidl/android/dvr/IVirtualTouchpadService.aidl
@@ -1,7 +1,7 @@
 package android.dvr;
 
 /** @hide */
-interface VirtualTouchpadService
+interface IVirtualTouchpadService
 {
   const String SERVICE_NAME = "virtual_touchpad";