Merge "Add mInputFilterEnabled to dump" into qt-dev
diff --git a/cmds/atrace/atrace.cpp b/cmds/atrace/atrace.cpp
index 5836f11..7ac0eb7 100644
--- a/cmds/atrace/atrace.cpp
+++ b/cmds/atrace/atrace.cpp
@@ -62,7 +62,7 @@
 
 using std::string;
 
-#define MAX_SYS_FILES 10
+#define MAX_SYS_FILES 11
 
 const char* k_traceTagsProperty = "debug.atrace.tags.enableflags";
 const char* k_userInitiatedTraceProperty = "debug.atrace.user_initiated";
@@ -133,7 +133,11 @@
         { OPT,      "events/sched/sched_blocked_reason/enable" },
         { OPT,      "events/sched/sched_cpu_hotplug/enable" },
         { OPT,      "events/sched/sched_pi_setprio/enable" },
+        { OPT,      "events/sched/sched_process_exit/enable" },
         { OPT,      "events/cgroup/enable" },
+        { OPT,      "events/oom/oom_score_adj_update/enable" },
+        { OPT,      "events/task/task_rename/enable" },
+        { OPT,      "events/task/task_newtask/enable" },
     } },
     { "irq",        "IRQ Events",   0, {
         { REQ,      "events/irq/enable" },
@@ -231,10 +235,6 @@
         { OPT,      "events/kmem/rss_stat/enable" },
         { OPT,      "events/kmem/ion_heap_grow/enable" },
         { OPT,      "events/kmem/ion_heap_shrink/enable" },
-        { OPT,      "events/oom/oom_score_adj_update/enable" },
-        { OPT,      "events/sched/sched_process_exit/enable" },
-        { OPT,      "events/task/task_rename/enable" },
-        { OPT,      "events/task/task_newtask/enable" },
     } },
 };
 
diff --git a/cmds/atrace/atrace.rc b/cmds/atrace/atrace.rc
index 7c58a85..032d072 100644
--- a/cmds/atrace/atrace.rc
+++ b/cmds/atrace/atrace.rc
@@ -33,6 +33,8 @@
     chmod 0666 /sys/kernel/tracing/events/sched/sched_cpu_hotplug/enable
     chmod 0666 /sys/kernel/debug/tracing/events/sched/sched_pi_setprio/enable
     chmod 0666 /sys/kernel/tracing/events/sched/sched_pi_setprio/enable
+    chmod 0666 /sys/kernel/debug/tracing/events/sched/sched_process_exit/enable
+    chmod 0666 /sys/kernel/tracing/events/sched/sched_process_exit/enable
     chmod 0666 /sys/kernel/debug/tracing/events/sched/sched_waking/enable
     chmod 0666 /sys/kernel/tracing/events/sched/sched_waking/enable
     chmod 0666 /sys/kernel/debug/tracing/events/cgroup/enable
diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp
index 2cc1b32..671c788 100644
--- a/cmds/dumpstate/dumpstate.cpp
+++ b/cmds/dumpstate/dumpstate.cpp
@@ -2697,7 +2697,15 @@
             MYLOGI(
                 "Did not receive user consent yet."
                 " Will not copy the bugreport artifacts to caller.\n");
-            // TODO(b/111441001): cancel outstanding requests
+            const String16 incidentcompanion("incidentcompanion");
+            sp<android::IBinder> ics(defaultServiceManager()->getService(incidentcompanion));
+            if (ics != nullptr) {
+                MYLOGD("Canceling user consent request via incidentcompanion service\n");
+                android::interface_cast<android::os::IIncidentCompanion>(ics)->cancelAuthorization(
+                        consent_callback_.get());
+            } else {
+                MYLOGD("Unable to cancel user consent; incidentcompanion service unavailable\n");
+            }
         }
     }
 
diff --git a/headers/media_plugin/media/drm/DrmAPI.h b/headers/media_plugin/media/drm/DrmAPI.h
index 59bd292..17b9993 100644
--- a/headers/media_plugin/media/drm/DrmAPI.h
+++ b/headers/media_plugin/media/drm/DrmAPI.h
@@ -115,7 +115,8 @@
             kKeyStatusType_Expired,
             kKeyStatusType_OutputNotAllowed,
             kKeyStatusType_StatusPending,
-            kKeyStatusType_InternalError
+            kKeyStatusType_InternalError,
+            kKeyStatusType_UsableInFuture
         };
 
         // Used by sendKeysChange to report the usability status of each
diff --git a/libs/binder/aidl/android/content/pm/IPackageManagerNative.aidl b/libs/binder/aidl/android/content/pm/IPackageManagerNative.aidl
index 70ed80d..90980b8 100644
--- a/libs/binder/aidl/android/content/pm/IPackageManagerNative.aidl
+++ b/libs/binder/aidl/android/content/pm/IPackageManagerNative.aidl
@@ -74,4 +74,11 @@
      * LOCATION_PRODUCT: getApplicationInfo(packageName).isProduct()
      */
     int getLocationFlags(in @utf8InCpp String packageName);
+
+    /**
+     * Returns the target SDK version for the given package.
+     * Unknown packages will cause the call to fail. The caller must check the
+     * returned Status before using the result of this function.
+     */
+    int getTargetSdkVersionForPackage(in String packageName);
 }
diff --git a/libs/graphicsenv/GpuStatsInfo.cpp b/libs/graphicsenv/GpuStatsInfo.cpp
index 0fa0d9e..f89b4c1 100644
--- a/libs/graphicsenv/GpuStatsInfo.cpp
+++ b/libs/graphicsenv/GpuStatsInfo.cpp
@@ -34,6 +34,9 @@
     if ((status = parcel->writeInt32(glLoadingFailureCount)) != OK) return status;
     if ((status = parcel->writeInt32(vkLoadingCount)) != OK) return status;
     if ((status = parcel->writeInt32(vkLoadingFailureCount)) != OK) return status;
+    if ((status = parcel->writeInt32(vulkanVersion)) != OK) return status;
+    if ((status = parcel->writeInt32(cpuVulkanVersion)) != OK) return status;
+    if ((status = parcel->writeInt32(glesVersion)) != OK) return status;
     return OK;
 }
 
@@ -47,6 +50,9 @@
     if ((status = parcel->readInt32(&glLoadingFailureCount)) != OK) return status;
     if ((status = parcel->readInt32(&vkLoadingCount)) != OK) return status;
     if ((status = parcel->readInt32(&vkLoadingFailureCount)) != OK) return status;
+    if ((status = parcel->readInt32(&vulkanVersion)) != OK) return status;
+    if ((status = parcel->readInt32(&cpuVulkanVersion)) != OK) return status;
+    if ((status = parcel->readInt32(&glesVersion)) != OK) return status;
     return OK;
 }
 
@@ -60,6 +66,9 @@
     StringAppendF(&result, "glLoadingFailureCount = %d\n", glLoadingFailureCount);
     StringAppendF(&result, "vkLoadingCount = %d\n", vkLoadingCount);
     StringAppendF(&result, "vkLoadingFailureCount = %d\n", vkLoadingFailureCount);
+    StringAppendF(&result, "vulkanVersion = %d\n", vulkanVersion);
+    StringAppendF(&result, "cpuVulkanVersion = %d\n", cpuVulkanVersion);
+    StringAppendF(&result, "glesVersion = %d\n", glesVersion);
     return result;
 }
 
diff --git a/libs/graphicsenv/GraphicsEnv.cpp b/libs/graphicsenv/GraphicsEnv.cpp
index 13c0d87..8728f03 100644
--- a/libs/graphicsenv/GraphicsEnv.cpp
+++ b/libs/graphicsenv/GraphicsEnv.cpp
@@ -162,7 +162,8 @@
 
 void GraphicsEnv::setGpuStats(const std::string& driverPackageName,
                               const std::string& driverVersionName, uint64_t driverVersionCode,
-                              int64_t driverBuildTime, const std::string& appPackageName) {
+                              int64_t driverBuildTime, const std::string& appPackageName,
+                              const int vulkanVersion) {
     ATRACE_CALL();
 
     std::lock_guard<std::mutex> lock(mStatsLock);
@@ -171,15 +172,17 @@
           "\tdriverVersionName[%s]\n"
           "\tdriverVersionCode[%" PRIu64 "]\n"
           "\tdriverBuildTime[%" PRId64 "]\n"
-          "\tappPackageName[%s]\n",
+          "\tappPackageName[%s]\n"
+          "\tvulkanVersion[%d]\n",
           driverPackageName.c_str(), driverVersionName.c_str(), driverVersionCode, driverBuildTime,
-          appPackageName.c_str());
+          appPackageName.c_str(), vulkanVersion);
 
     mGpuStats.driverPackageName = driverPackageName;
     mGpuStats.driverVersionName = driverVersionName;
     mGpuStats.driverVersionCode = driverVersionCode;
     mGpuStats.driverBuildTime = driverBuildTime;
     mGpuStats.appPackageName = appPackageName;
+    mGpuStats.vulkanVersion = vulkanVersion;
 }
 
 void GraphicsEnv::setDriverToLoad(GraphicsEnv::Driver driver) {
@@ -270,19 +273,20 @@
           "\tdriverVersionCode[%" PRIu64 "]\n"
           "\tdriverBuildTime[%" PRId64 "]\n"
           "\tappPackageName[%s]\n"
+          "\tvulkanVersion[%d]\n"
           "\tdriver[%d]\n"
           "\tisDriverLoaded[%d]\n"
           "\tdriverLoadingTime[%" PRId64 "]",
           mGpuStats.driverPackageName.c_str(), mGpuStats.driverVersionName.c_str(),
           mGpuStats.driverVersionCode, mGpuStats.driverBuildTime, mGpuStats.appPackageName.c_str(),
-          static_cast<int32_t>(driver), isDriverLoaded, driverLoadingTime);
+          mGpuStats.vulkanVersion, static_cast<int32_t>(driver), isDriverLoaded, driverLoadingTime);
 
     const sp<IGpuService> gpuService = getGpuService();
     if (gpuService) {
         gpuService->setGpuStats(mGpuStats.driverPackageName, mGpuStats.driverVersionName,
                                 mGpuStats.driverVersionCode, mGpuStats.driverBuildTime,
-                                mGpuStats.appPackageName, driver, isDriverLoaded,
-                                driverLoadingTime);
+                                mGpuStats.appPackageName, mGpuStats.vulkanVersion, driver,
+                                isDriverLoaded, driverLoadingTime);
     }
 }
 
diff --git a/libs/graphicsenv/IGpuService.cpp b/libs/graphicsenv/IGpuService.cpp
index 1dc1c0e..100dca5 100644
--- a/libs/graphicsenv/IGpuService.cpp
+++ b/libs/graphicsenv/IGpuService.cpp
@@ -30,8 +30,8 @@
     virtual void setGpuStats(const std::string& driverPackageName,
                              const std::string& driverVersionName, uint64_t driverVersionCode,
                              int64_t driverBuildTime, const std::string& appPackageName,
-                             GraphicsEnv::Driver driver, bool isDriverLoaded,
-                             int64_t driverLoadingTime) {
+                             const int32_t vulkanVersion, GraphicsEnv::Driver driver,
+                             bool isDriverLoaded, int64_t driverLoadingTime) {
         Parcel data, reply;
         data.writeInterfaceToken(IGpuService::getInterfaceDescriptor());
 
@@ -40,6 +40,7 @@
         data.writeUint64(driverVersionCode);
         data.writeInt64(driverBuildTime);
         data.writeUtf8AsUtf16(appPackageName);
+        data.writeInt32(vulkanVersion);
         data.writeInt32(static_cast<int32_t>(driver));
         data.writeBool(isDriverLoaded);
         data.writeInt64(driverLoadingTime);
@@ -118,6 +119,9 @@
             std::string appPackageName;
             if ((status = data.readUtf8FromUtf16(&appPackageName)) != OK) return status;
 
+            int32_t vulkanVersion;
+            if ((status = data.readInt32(&vulkanVersion)) != OK) return status;
+
             int32_t driver;
             if ((status = data.readInt32(&driver)) != OK) return status;
 
@@ -128,8 +132,8 @@
             if ((status = data.readInt64(&driverLoadingTime)) != OK) return status;
 
             setGpuStats(driverPackageName, driverVersionName, driverVersionCode, driverBuildTime,
-                        appPackageName, static_cast<GraphicsEnv::Driver>(driver), isDriverLoaded,
-                        driverLoadingTime);
+                        appPackageName, vulkanVersion, static_cast<GraphicsEnv::Driver>(driver),
+                        isDriverLoaded, driverLoadingTime);
 
             return OK;
         }
diff --git a/libs/graphicsenv/include/graphicsenv/GpuStatsInfo.h b/libs/graphicsenv/include/graphicsenv/GpuStatsInfo.h
index a92ca70..98ab02b 100644
--- a/libs/graphicsenv/include/graphicsenv/GpuStatsInfo.h
+++ b/libs/graphicsenv/include/graphicsenv/GpuStatsInfo.h
@@ -44,6 +44,9 @@
     int32_t glLoadingFailureCount = 0;
     int32_t vkLoadingCount = 0;
     int32_t vkLoadingFailureCount = 0;
+    int32_t vulkanVersion = 0;
+    int32_t cpuVulkanVersion = 0;
+    int32_t glesVersion = 0;
 };
 
 /*
diff --git a/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h b/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h
index cb4239f..b10cab7 100644
--- a/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h
+++ b/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h
@@ -50,6 +50,7 @@
         uint64_t driverVersionCode;
         int64_t driverBuildTime;
         std::string appPackageName;
+        int32_t vulkanVersion;
         Driver glDriverToLoad;
         Driver glDriverFallback;
         Driver vkDriverToLoad;
@@ -61,6 +62,7 @@
                 driverVersionCode(0),
                 driverBuildTime(0),
                 appPackageName(""),
+                vulkanVersion(0),
                 glDriverToLoad(Driver::NONE),
                 glDriverFallback(Driver::NONE),
                 vkDriverToLoad(Driver::NONE),
@@ -84,7 +86,7 @@
     android_namespace_t* getDriverNamespace();
     void setGpuStats(const std::string& driverPackageName, const std::string& driverVersionName,
                      uint64_t versionCode, int64_t driverBuildTime,
-                     const std::string& appPackageName);
+                     const std::string& appPackageName, const int32_t vulkanVersion);
     void setDriverToLoad(Driver driver);
     void setDriverLoaded(Api api, bool isDriverLoaded, int64_t driverLoadingTime);
     void clearDriverLoadingInfo(Api api);
diff --git a/libs/graphicsenv/include/graphicsenv/IGpuService.h b/libs/graphicsenv/include/graphicsenv/IGpuService.h
index ac022b5..5bf0269 100644
--- a/libs/graphicsenv/include/graphicsenv/IGpuService.h
+++ b/libs/graphicsenv/include/graphicsenv/IGpuService.h
@@ -37,8 +37,8 @@
     virtual void setGpuStats(const std::string& driverPackageName,
                              const std::string& driverVersionName, uint64_t driverVersionCode,
                              int64_t driverBuildTime, const std::string& appPackageName,
-                             GraphicsEnv::Driver driver, bool isDriverLoaded,
-                             int64_t driverLoadingTime) = 0;
+                             const int32_t vulkanVersion, GraphicsEnv::Driver driver,
+                             bool isDriverLoaded, int64_t driverLoadingTime) = 0;
 
     // get GPU global stats from GpuStats module.
     virtual status_t getGpuStatsGlobalInfo(std::vector<GpuStatsGlobalInfo>* outStats) const = 0;
diff --git a/libs/gui/Android.bp b/libs/gui/Android.bp
index fcbfba9..34575f5 100644
--- a/libs/gui/Android.bp
+++ b/libs/gui/Android.bp
@@ -25,49 +25,19 @@
     },
     double_loadable: true,
 
-    clang: true,
-    cflags: [
-        "-Wall",
-        "-Werror",
-    ],
-    cppflags: [
-        "-Wextra",
-        "-DDEBUG_ONLY_CODE=0",
-    ],
-
-    product_variables: {
-        eng: {
-            cppflags: [
-                "-UDEBUG_ONLY_CODE",
-                "-DDEBUG_ONLY_CODE=1",
-            ],
-        },
-    },
+    defaults: ["libgui_bufferqueue-defaults"],
 
     srcs: [
         "BitTube.cpp",
         "BufferHubConsumer.cpp",
         "BufferHubProducer.cpp",
-        "BufferItem.cpp",
         "BufferItemConsumer.cpp",
-        "BufferQueue.cpp",
-        "BufferQueueConsumer.cpp",
-        "BufferQueueCore.cpp",
-        "BufferQueueProducer.cpp",
-        "BufferQueueThreadState.cpp",
-        "BufferSlot.cpp",
         "ConsumerBase.cpp",
         "CpuConsumer.cpp",
         "DisplayEventReceiver.cpp",
-        "FrameTimestamps.cpp",
         "GLConsumer.cpp",
         "GuiConfig.cpp",
-        "HdrMetadata.cpp",
         "IDisplayEventConnection.cpp",
-        "IConsumerListener.cpp",
-        "IGraphicBufferConsumer.cpp",
-        "IGraphicBufferProducer.cpp",
-        "IProducerListener.cpp",
         "IRegionSamplingListener.cpp",
         "ISurfaceComposer.cpp",
         "ISurfaceComposerClient.cpp",
@@ -75,50 +45,20 @@
         "LayerDebugInfo.cpp",
         "LayerMetadata.cpp",
         "LayerState.cpp",
-        "OccupancyTracker.cpp",
         "StreamSplitter.cpp",
         "Surface.cpp",
         "SurfaceControl.cpp",
         "SurfaceComposerClient.cpp",
         "SyncFeatures.cpp",
         "view/Surface.cpp",
-        "bufferqueue/1.0/B2HProducerListener.cpp",
-        "bufferqueue/1.0/Conversion.cpp",
-        "bufferqueue/1.0/H2BGraphicBufferProducer.cpp",
-        "bufferqueue/1.0/H2BProducerListener.cpp",
-        "bufferqueue/1.0/WProducerListener.cpp",
-        "bufferqueue/2.0/B2HGraphicBufferProducer.cpp",
-        "bufferqueue/2.0/B2HProducerListener.cpp",
-        "bufferqueue/2.0/H2BGraphicBufferProducer.cpp",
-        "bufferqueue/2.0/H2BProducerListener.cpp",
-        "bufferqueue/2.0/types.cpp",
     ],
 
     shared_libs: [
         "android.frameworks.bufferhub@1.0",
-        "android.hardware.graphics.bufferqueue@1.0",
-        "android.hardware.graphics.bufferqueue@2.0",
-        "android.hardware.graphics.common@1.1",
-        "android.hardware.graphics.common@1.2",
-        "android.hidl.token@1.0-utils",
-        "libbase",
-        "libbinder",
         "libbufferhub",
         "libbufferhubqueue", // TODO(b/70046255): Remove this once BufferHub is integrated into libgui.
-        "libcutils",
-        "libEGL",
-        "libGLESv2",
-        "libhidlbase",
-        "libhidltransport",
-        "libhwbinder",
         "libinput",
-        "liblog",
-        "libnativewindow",
         "libpdx_default_transport",
-        "libsync",
-        "libui",
-        "libutils",
-        "libvndksupport",
     ],
 
     // bufferhub is not used when building libgui for vendors
@@ -144,9 +84,100 @@
 
     header_libs: [
         "libdvr_headers",
+        "libpdx_headers",
+    ],
+}
+
+// Used by media codec services exclusively as a static lib for
+// core bufferqueue support only.
+cc_library_static {
+    name: "libgui_bufferqueue_static",
+    vendor_available: true,
+
+    cflags: [
+        "-DNO_BUFFERHUB",
+    ],
+
+    defaults: ["libgui_bufferqueue-defaults"],
+}
+
+// Common build config shared by libgui and libgui_bufferqueue_static.
+cc_defaults {
+    name: "libgui_bufferqueue-defaults",
+
+    clang: true,
+    cflags: [
+        "-Wall",
+        "-Werror",
+    ],
+
+    cppflags: [
+        "-Wextra",
+        "-DDEBUG_ONLY_CODE=0",
+    ],
+
+    product_variables: {
+        eng: {
+            cppflags: [
+                "-UDEBUG_ONLY_CODE",
+                "-DDEBUG_ONLY_CODE=1",
+            ],
+        },
+    },
+
+    srcs: [
+        "BufferItem.cpp",
+        "BufferQueue.cpp",
+        "BufferQueueConsumer.cpp",
+        "BufferQueueCore.cpp",
+        "BufferQueueProducer.cpp",
+        "BufferQueueThreadState.cpp",
+        "BufferSlot.cpp",
+        "FrameTimestamps.cpp",
+        "GLConsumerUtils.cpp",
+        "HdrMetadata.cpp",
+        "IConsumerListener.cpp",
+        "IGraphicBufferConsumer.cpp",
+        "IGraphicBufferProducer.cpp",
+        "IProducerListener.cpp",
+        "OccupancyTracker.cpp",
+        "bufferqueue/1.0/B2HProducerListener.cpp",
+        "bufferqueue/1.0/Conversion.cpp",
+        "bufferqueue/1.0/H2BGraphicBufferProducer.cpp",
+        "bufferqueue/1.0/H2BProducerListener.cpp",
+        "bufferqueue/1.0/WProducerListener.cpp",
+        "bufferqueue/2.0/B2HGraphicBufferProducer.cpp",
+        "bufferqueue/2.0/B2HProducerListener.cpp",
+        "bufferqueue/2.0/H2BGraphicBufferProducer.cpp",
+        "bufferqueue/2.0/H2BProducerListener.cpp",
+        "bufferqueue/2.0/types.cpp",
+    ],
+
+    shared_libs: [
+        "android.hardware.graphics.bufferqueue@1.0",
+        "android.hardware.graphics.bufferqueue@2.0",
+        "android.hardware.graphics.common@1.1",
+        "android.hardware.graphics.common@1.2",
+        "android.hidl.token@1.0-utils",
+        "libbase",
+        "libbinder",
+        "libcutils",
+        "libEGL",
+        "libGLESv2",
+        "libhidlbase",
+        "libhidltransport",
+        "libhwbinder",
+        "liblog",
+        "libnativewindow",
+        "libsync",
+        "libui",
+        "libutils",
+        "libvndksupport",
+    ],
+
+    header_libs: [
         "libgui_headers",
         "libnativebase_headers",
-        "libpdx_headers",
     ],
 
     export_shared_lib_headers: [
diff --git a/libs/gui/BufferQueue.cpp b/libs/gui/BufferQueue.cpp
index d87228f..5fb3f0b 100644
--- a/libs/gui/BufferQueue.cpp
+++ b/libs/gui/BufferQueue.cpp
@@ -59,13 +59,6 @@
     }
 }
 
-void BufferQueue::ProxyConsumerListener::onBufferAllocated(const BufferItem& item) {
-    sp<ConsumerListener> listener(mConsumerListener.promote());
-    if (listener != nullptr) {
-        listener->onBufferAllocated(item);
-    }
-}
-
 void BufferQueue::ProxyConsumerListener::onBuffersReleased() {
     sp<ConsumerListener> listener(mConsumerListener.promote());
     if (listener != nullptr) {
diff --git a/libs/gui/BufferQueueConsumer.cpp b/libs/gui/BufferQueueConsumer.cpp
index e226136..528bfb1 100644
--- a/libs/gui/BufferQueueConsumer.cpp
+++ b/libs/gui/BufferQueueConsumer.cpp
@@ -94,8 +94,6 @@
         // Skip this if we're in shared buffer mode and the queue is empty,
         // since in that case we'll just return the shared buffer.
         if (expectedPresent != 0 && !mCore->mQueue.empty()) {
-            const int MAX_REASONABLE_NSEC = 1000000000ULL; // 1 second
-
             // The 'expectedPresent' argument indicates when the buffer is expected
             // to be presented on-screen. If the buffer's desired present time is
             // earlier (less) than expectedPresent -- meaning it will be displayed
diff --git a/libs/gui/BufferQueueProducer.cpp b/libs/gui/BufferQueueProducer.cpp
index c94c6b3..3928bb9 100644
--- a/libs/gui/BufferQueueProducer.cpp
+++ b/libs/gui/BufferQueueProducer.cpp
@@ -539,13 +539,6 @@
                 return NO_INIT;
             }
 
-            if (mCore->mConsumerListener != nullptr) {
-                BufferItem item;
-                item.mGraphicBuffer = graphicBuffer;
-                item.mSlot = *outSlot;
-                mCore->mConsumerListener->onBufferAllocated(item);
-            }
-
             VALIDATE_CONSISTENCY();
         } // Autolock scope
     }
@@ -975,9 +968,6 @@
         item.mGraphicBuffer.clear();
     }
 
-    // Don't send the slot number through the callback since the consumer shouldn't need it
-    item.mSlot = BufferItem::INVALID_BUFFER_SLOT;
-
     // Call back without the main BufferQueue lock held, but with the callback
     // lock held so we can ensure that callbacks occur in order
 
@@ -1433,13 +1423,6 @@
                 BQ_LOGV("allocateBuffers: allocated a new buffer in slot %d",
                         *slot);
 
-                if (mCore->mConsumerListener != nullptr) {
-                    BufferItem item;
-                    item.mGraphicBuffer = buffers[i];
-                    item.mSlot = *slot;
-                    mCore->mConsumerListener->onBufferAllocated(item);
-                }
-
                 // Make sure the erase is done after all uses of the slot
                 // iterator since it will be invalid after this point.
                 mCore->mFreeSlots.erase(slot);
diff --git a/libs/gui/ConsumerBase.cpp b/libs/gui/ConsumerBase.cpp
index 1e94cc1..abd9921 100644
--- a/libs/gui/ConsumerBase.cpp
+++ b/libs/gui/ConsumerBase.cpp
@@ -131,8 +131,6 @@
     }
 }
 
-void ConsumerBase::onBufferAllocated(const BufferItem& /*item*/) {}
-
 void ConsumerBase::onBuffersReleased() {
     Mutex::Autolock lock(mMutex);
 
diff --git a/libs/gui/GLConsumer.cpp b/libs/gui/GLConsumer.cpp
index faf02f3..8d66154 100644
--- a/libs/gui/GLConsumer.cpp
+++ b/libs/gui/GLConsumer.cpp
@@ -745,104 +745,6 @@
         mCurrentTransform, mFilteringEnabled);
 }
 
-void GLConsumer::computeTransformMatrix(float outTransform[16],
-        const sp<GraphicBuffer>& buf, const Rect& cropRect, uint32_t transform,
-        bool filtering) {
-    // Transform matrices
-    static const mat4 mtxFlipH(
-        -1, 0, 0, 0,
-        0, 1, 0, 0,
-        0, 0, 1, 0,
-        1, 0, 0, 1
-    );
-    static const mat4 mtxFlipV(
-        1, 0, 0, 0,
-        0, -1, 0, 0,
-        0, 0, 1, 0,
-        0, 1, 0, 1
-    );
-    static const mat4 mtxRot90(
-        0, 1, 0, 0,
-        -1, 0, 0, 0,
-        0, 0, 1, 0,
-        1, 0, 0, 1
-    );
-
-    mat4 xform;
-    if (transform & NATIVE_WINDOW_TRANSFORM_FLIP_H) {
-        xform *= mtxFlipH;
-    }
-    if (transform & NATIVE_WINDOW_TRANSFORM_FLIP_V) {
-        xform *= mtxFlipV;
-    }
-    if (transform & NATIVE_WINDOW_TRANSFORM_ROT_90) {
-        xform *= mtxRot90;
-    }
-
-    if (!cropRect.isEmpty()) {
-        float tx = 0.0f, ty = 0.0f, sx = 1.0f, sy = 1.0f;
-        float bufferWidth = buf->getWidth();
-        float bufferHeight = buf->getHeight();
-        float shrinkAmount = 0.0f;
-        if (filtering) {
-            // In order to prevent bilinear sampling beyond the edge of the
-            // crop rectangle we may need to shrink it by 2 texels in each
-            // dimension.  Normally this would just need to take 1/2 a texel
-            // off each end, but because the chroma channels of YUV420 images
-            // are subsampled we may need to shrink the crop region by a whole
-            // texel on each side.
-            switch (buf->getPixelFormat()) {
-                case PIXEL_FORMAT_RGBA_8888:
-                case PIXEL_FORMAT_RGBX_8888:
-                case PIXEL_FORMAT_RGBA_FP16:
-                case PIXEL_FORMAT_RGBA_1010102:
-                case PIXEL_FORMAT_RGB_888:
-                case PIXEL_FORMAT_RGB_565:
-                case PIXEL_FORMAT_BGRA_8888:
-                    // We know there's no subsampling of any channels, so we
-                    // only need to shrink by a half a pixel.
-                    shrinkAmount = 0.5;
-                    break;
-
-                default:
-                    // If we don't recognize the format, we must assume the
-                    // worst case (that we care about), which is YUV420.
-                    shrinkAmount = 1.0;
-                    break;
-            }
-        }
-
-        // Only shrink the dimensions that are not the size of the buffer.
-        if (cropRect.width() < bufferWidth) {
-            tx = (float(cropRect.left) + shrinkAmount) / bufferWidth;
-            sx = (float(cropRect.width()) - (2.0f * shrinkAmount)) /
-                    bufferWidth;
-        }
-        if (cropRect.height() < bufferHeight) {
-            ty = (float(bufferHeight - cropRect.bottom) + shrinkAmount) /
-                    bufferHeight;
-            sy = (float(cropRect.height()) - (2.0f * shrinkAmount)) /
-                    bufferHeight;
-        }
-
-        mat4 crop(
-            sx, 0, 0, 0,
-            0, sy, 0, 0,
-            0, 0, 1, 0,
-            tx, ty, 0, 1
-        );
-        xform = crop * xform;
-    }
-
-    // GLConsumer uses the GL convention where (0, 0) is the bottom-left
-    // corner and (1, 1) is the top-right corner.  Add an additional vertical
-    // flip after all other transforms to map from GL convention to buffer
-    // queue memory layout, where (0, 0) is the top-left corner.
-    xform = mtxFlipV * xform;
-
-    memcpy(outTransform, xform.asArray(), sizeof(xform));
-}
-
 Rect GLConsumer::scaleDownCrop(const Rect& crop, uint32_t bufferWidth, uint32_t bufferHeight) {
     Rect outCrop = crop;
 
diff --git a/libs/gui/GLConsumerUtils.cpp b/libs/gui/GLConsumerUtils.cpp
new file mode 100644
index 0000000..7a06c3d
--- /dev/null
+++ b/libs/gui/GLConsumerUtils.cpp
@@ -0,0 +1,125 @@
+/*
+ * Copyright (C) 2010 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.
+ */
+
+#define LOG_TAG "GLConsumerUtils"
+//#define LOG_NDEBUG 0
+
+#include <gui/GLConsumer.h>
+#include <math/mat4.h>
+#include <system/window.h>
+#include <utils/Log.h>
+
+namespace android {
+
+void GLConsumer::computeTransformMatrix(float outTransform[16],
+        const sp<GraphicBuffer>& buf, const Rect& cropRect, uint32_t transform,
+        bool filtering) {
+    // Transform matrices
+    static const mat4 mtxFlipH(
+        -1, 0, 0, 0,
+        0, 1, 0, 0,
+        0, 0, 1, 0,
+        1, 0, 0, 1
+    );
+    static const mat4 mtxFlipV(
+        1, 0, 0, 0,
+        0, -1, 0, 0,
+        0, 0, 1, 0,
+        0, 1, 0, 1
+    );
+    static const mat4 mtxRot90(
+        0, 1, 0, 0,
+        -1, 0, 0, 0,
+        0, 0, 1, 0,
+        1, 0, 0, 1
+    );
+
+    mat4 xform;
+    if (transform & NATIVE_WINDOW_TRANSFORM_FLIP_H) {
+        xform *= mtxFlipH;
+    }
+    if (transform & NATIVE_WINDOW_TRANSFORM_FLIP_V) {
+        xform *= mtxFlipV;
+    }
+    if (transform & NATIVE_WINDOW_TRANSFORM_ROT_90) {
+        xform *= mtxRot90;
+    }
+
+    if (!cropRect.isEmpty()) {
+        float tx = 0.0f, ty = 0.0f, sx = 1.0f, sy = 1.0f;
+        float bufferWidth = buf->getWidth();
+        float bufferHeight = buf->getHeight();
+        float shrinkAmount = 0.0f;
+        if (filtering) {
+            // In order to prevent bilinear sampling beyond the edge of the
+            // crop rectangle we may need to shrink it by 2 texels in each
+            // dimension.  Normally this would just need to take 1/2 a texel
+            // off each end, but because the chroma channels of YUV420 images
+            // are subsampled we may need to shrink the crop region by a whole
+            // texel on each side.
+            switch (buf->getPixelFormat()) {
+                case PIXEL_FORMAT_RGBA_8888:
+                case PIXEL_FORMAT_RGBX_8888:
+                case PIXEL_FORMAT_RGBA_FP16:
+                case PIXEL_FORMAT_RGBA_1010102:
+                case PIXEL_FORMAT_RGB_888:
+                case PIXEL_FORMAT_RGB_565:
+                case PIXEL_FORMAT_BGRA_8888:
+                    // We know there's no subsampling of any channels, so we
+                    // only need to shrink by a half a pixel.
+                    shrinkAmount = 0.5;
+                    break;
+
+                default:
+                    // If we don't recognize the format, we must assume the
+                    // worst case (that we care about), which is YUV420.
+                    shrinkAmount = 1.0;
+                    break;
+            }
+        }
+
+        // Only shrink the dimensions that are not the size of the buffer.
+        if (cropRect.width() < bufferWidth) {
+            tx = (float(cropRect.left) + shrinkAmount) / bufferWidth;
+            sx = (float(cropRect.width()) - (2.0f * shrinkAmount)) /
+                    bufferWidth;
+        }
+        if (cropRect.height() < bufferHeight) {
+            ty = (float(bufferHeight - cropRect.bottom) + shrinkAmount) /
+                    bufferHeight;
+            sy = (float(cropRect.height()) - (2.0f * shrinkAmount)) /
+                    bufferHeight;
+        }
+
+        mat4 crop(
+            sx, 0, 0, 0,
+            0, sy, 0, 0,
+            0, 0, 1, 0,
+            tx, ty, 0, 1
+        );
+        xform = crop * xform;
+    }
+
+    // GLConsumer uses the GL convention where (0, 0) is the bottom-left
+    // corner and (1, 1) is the top-right corner.  Add an additional vertical
+    // flip after all other transforms to map from GL convention to buffer
+    // queue memory layout, where (0, 0) is the top-left corner.
+    xform = mtxFlipV * xform;
+
+    memcpy(outTransform, xform.asArray(), sizeof(xform));
+}
+
+}; // namespace android
diff --git a/libs/gui/IConsumerListener.cpp b/libs/gui/IConsumerListener.cpp
index ea9045c..85ac304 100644
--- a/libs/gui/IConsumerListener.cpp
+++ b/libs/gui/IConsumerListener.cpp
@@ -28,8 +28,7 @@
     ON_FRAME_REPLACED,
     ON_BUFFERS_RELEASED,
     ON_SIDEBAND_STREAM_CHANGED,
-    ON_BUFFER_ALLOCATED,
-    LAST = ON_BUFFER_ALLOCATED,
+    LAST = ON_SIDEBAND_STREAM_CHANGED,
 };
 
 } // Anonymous namespace
@@ -55,11 +54,6 @@
                                                                        item);
     }
 
-    void onBufferAllocated(const BufferItem& item) override {
-        callRemoteAsync<decltype(&IConsumerListener::onBufferAllocated)>(Tag::ON_BUFFER_ALLOCATED,
-                                                                         item);
-    }
-
     void onBuffersReleased() override {
         callRemoteAsync<decltype(&IConsumerListener::onBuffersReleased)>(Tag::ON_BUFFERS_RELEASED);
     }
@@ -95,8 +89,6 @@
             return callLocalAsync(data, reply, &IConsumerListener::onFrameAvailable);
         case Tag::ON_FRAME_REPLACED:
             return callLocalAsync(data, reply, &IConsumerListener::onFrameReplaced);
-        case Tag::ON_BUFFER_ALLOCATED:
-            return callLocalAsync(data, reply, &IConsumerListener::onBufferAllocated);
         case Tag::ON_BUFFERS_RELEASED:
             return callLocalAsync(data, reply, &IConsumerListener::onBuffersReleased);
         case Tag::ON_SIDEBAND_STREAM_CHANGED:
diff --git a/libs/gui/bufferqueue/1.0/H2BGraphicBufferProducer.cpp b/libs/gui/bufferqueue/1.0/H2BGraphicBufferProducer.cpp
index e64ba9b..cee1b81 100644
--- a/libs/gui/bufferqueue/1.0/H2BGraphicBufferProducer.cpp
+++ b/libs/gui/bufferqueue/1.0/H2BGraphicBufferProducer.cpp
@@ -1061,7 +1061,7 @@
 
 status_t H2BGraphicBufferProducer::attachBuffer(
         int* outSlot, const sp<GraphicBuffer>& buffer) {
-    AnwBuffer tBuffer;
+    AnwBuffer tBuffer{};
     wrapAs(&tBuffer, *buffer);
     status_t fnStatus;
     status_t transStatus = toStatusT(mBase->attachBuffer(tBuffer,
@@ -1076,7 +1076,7 @@
         int slot,
         const QueueBufferInput& input,
         QueueBufferOutput* output) {
-    HGraphicBufferProducer::QueueBufferInput tInput;
+    HGraphicBufferProducer::QueueBufferInput tInput{};
     native_handle_t* nh;
     if (!wrapAs(&tInput, &nh, input)) {
         ALOGE("H2BGraphicBufferProducer::queueBuffer - "
diff --git a/libs/gui/bufferqueue/2.0/B2HGraphicBufferProducer.cpp b/libs/gui/bufferqueue/2.0/B2HGraphicBufferProducer.cpp
index e039593..e891ec5 100644
--- a/libs/gui/bufferqueue/2.0/B2HGraphicBufferProducer.cpp
+++ b/libs/gui/bufferqueue/2.0/B2HGraphicBufferProducer.cpp
@@ -15,7 +15,7 @@
  */
 
 //#define LOG_NDEBUG 0
-#define LOG_TAG "H2BGraphicBufferProducer@2.0"
+#define LOG_TAG "B2HGraphicBufferProducer@2.0"
 
 #include <android-base/logging.h>
 
@@ -30,13 +30,38 @@
 #include <vndk/hardware_buffer.h>
 
 namespace android {
-
 namespace hardware {
 namespace graphics {
 namespace bufferqueue {
 namespace V2_0 {
 namespace utils {
 
+namespace /* unnamed */ {
+
+using BQueueBufferInput = ::android::
+        IGraphicBufferProducer::QueueBufferInput;
+using HQueueBufferInput = ::android::hardware::graphics::bufferqueue::V2_0::
+        IGraphicBufferProducer::QueueBufferInput;
+using BQueueBufferOutput = ::android::
+        IGraphicBufferProducer::QueueBufferOutput;
+using HQueueBufferOutput = ::android::hardware::graphics::bufferqueue::V2_0::
+        IGraphicBufferProducer::QueueBufferOutput;
+
+using ::android::hardware::graphics::bufferqueue::V2_0::utils::b2h;
+using ::android::hardware::graphics::bufferqueue::V2_0::utils::h2b;
+
+bool b2h(BQueueBufferOutput const& from, HQueueBufferOutput* to) {
+    to->width = from.width;
+    to->height = from.height;
+    to->transformHint = static_cast<int32_t>(from.transformHint);
+    to->numPendingBuffers = from.numPendingBuffers;
+    to->nextFrameNumber = from.nextFrameNumber;
+    to->bufferReplaced = from.bufferReplaced;
+    return true;
+}
+
+} // unnamed namespace
+
 // B2HGraphicBufferProducer
 // ========================
 
@@ -161,11 +186,7 @@
         int32_t slot,
         QueueBufferInput const& hInput,
         queueBuffer_cb _hidl_cb) {
-    using HOutput = QueueBufferOutput;
-    using BInput = BGraphicBufferProducer::QueueBufferInput;
-    using BOutput = BGraphicBufferProducer::QueueBufferOutput;
-
-    BInput bInput{
+    BQueueBufferInput bInput{
             hInput.timestamp,
             hInput.isAutoTimestamp,
             static_cast<android_dataspace>(hInput.dataSpace),
@@ -178,35 +199,32 @@
 
     // Convert crop.
     if (!h2b(hInput.crop, &bInput.crop)) {
-        _hidl_cb(HStatus::UNKNOWN_ERROR, HOutput{});
+        _hidl_cb(HStatus::UNKNOWN_ERROR, QueueBufferOutput{});
         return {};
     }
 
     // Convert surfaceDamage.
     if (!h2b(hInput.surfaceDamage, &bInput.surfaceDamage)) {
-        _hidl_cb(HStatus::UNKNOWN_ERROR, HOutput{});
+        _hidl_cb(HStatus::UNKNOWN_ERROR, QueueBufferOutput{});
         return {};
     }
 
     // Convert fence.
     if (!h2b(hInput.fence, &bInput.fence)) {
-        _hidl_cb(HStatus::UNKNOWN_ERROR, HOutput{});
+        _hidl_cb(HStatus::UNKNOWN_ERROR, QueueBufferOutput{});
         return {};
     }
 
-    BOutput bOutput{};
+    BQueueBufferOutput bOutput{};
     HStatus hStatus{};
-    bool converted = b2h(
-            mBase->queueBuffer(static_cast<int>(slot), bInput, &bOutput),
-            &hStatus);
+    QueueBufferOutput hOutput{};
+    bool converted =
+            b2h(
+                mBase->queueBuffer(static_cast<int>(slot), bInput, &bOutput),
+                &hStatus) &&
+            b2h(bOutput, &hOutput);
 
-    _hidl_cb(converted ? hStatus : HStatus::UNKNOWN_ERROR,
-             HOutput{bOutput.width,
-                     bOutput.height,
-                     static_cast<int32_t>(bOutput.transformHint),
-                     bOutput.numPendingBuffers,
-                     bOutput.nextFrameNumber,
-                     bOutput.bufferReplaced});
+    _hidl_cb(converted ? hStatus : HStatus::UNKNOWN_ERROR, hOutput);
     return {};
 }
 
@@ -236,33 +254,23 @@
         HConnectionType hConnectionType,
         bool producerControlledByApp,
         connect_cb _hidl_cb) {
-    using BOutput = BGraphicBufferProducer::QueueBufferOutput;
-    using HOutput = HGraphicBufferProducer::QueueBufferOutput;
     sp<BProducerListener> bListener = new H2BProducerListener(hListener);
-    if (!bListener) {
-        _hidl_cb(HStatus::UNKNOWN_ERROR, HOutput{});
+    int bConnectionType{};
+    if (!bListener || !h2b(hConnectionType, &bConnectionType)) {
+        _hidl_cb(HStatus::UNKNOWN_ERROR, QueueBufferOutput{});
         return {};
     }
-    int bConnectionType;
-    if (!h2b(hConnectionType, &bConnectionType)) {
-        _hidl_cb(HStatus::UNKNOWN_ERROR, HOutput{});
-        return {};
-    }
-    BOutput bOutput{};
+    BQueueBufferOutput bOutput{};
     HStatus hStatus{};
-    bool converted = b2h(
-            mBase->connect(bListener,
-                           bConnectionType,
-                           producerControlledByApp,
-                           &bOutput),
-            &hStatus);
-    _hidl_cb(converted ? hStatus : HStatus::UNKNOWN_ERROR,
-             HOutput{bOutput.width,
-                     bOutput.height,
-                     static_cast<int32_t>(bOutput.transformHint),
-                     bOutput.numPendingBuffers,
-                     bOutput.nextFrameNumber,
-                     bOutput.bufferReplaced});
+    QueueBufferOutput hOutput{};
+    bool converted =
+            b2h(mBase->connect(bListener,
+                               bConnectionType,
+                               producerControlledByApp,
+                               &bOutput),
+                &hStatus) &&
+            b2h(bOutput, &hOutput);
+    _hidl_cb(converted ? hStatus : HStatus::UNKNOWN_ERROR, hOutput);
     return {};
 }
 
diff --git a/libs/gui/bufferqueue/2.0/H2BGraphicBufferProducer.cpp b/libs/gui/bufferqueue/2.0/H2BGraphicBufferProducer.cpp
index 1023ef1..2f5b73c 100644
--- a/libs/gui/bufferqueue/2.0/H2BGraphicBufferProducer.cpp
+++ b/libs/gui/bufferqueue/2.0/H2BGraphicBufferProducer.cpp
@@ -29,13 +29,54 @@
 #include <vndk/hardware_buffer.h>
 
 namespace android {
-
 namespace hardware {
 namespace graphics {
 namespace bufferqueue {
 namespace V2_0 {
 namespace utils {
 
+namespace /* unnamed */ {
+
+using BQueueBufferInput = ::android::
+        IGraphicBufferProducer::QueueBufferInput;
+using HQueueBufferInput = ::android::hardware::graphics::bufferqueue::V2_0::
+        IGraphicBufferProducer::QueueBufferInput;
+using BQueueBufferOutput = ::android::
+        IGraphicBufferProducer::QueueBufferOutput;
+using HQueueBufferOutput = ::android::hardware::graphics::bufferqueue::V2_0::
+        IGraphicBufferProducer::QueueBufferOutput;
+
+using ::android::hardware::graphics::bufferqueue::V2_0::utils::b2h;
+using ::android::hardware::graphics::bufferqueue::V2_0::utils::h2b;
+
+bool b2h(BQueueBufferInput const& from, HQueueBufferInput* to,
+         HFenceWrapper* hFenceWrapper) {
+    to->timestamp = from.timestamp;
+    to->isAutoTimestamp = static_cast<bool>(from.isAutoTimestamp);
+    to->dataSpace = static_cast<int32_t>(from.dataSpace);
+    to->transform = static_cast<int32_t>(from.transform);
+    to->stickyTransform = static_cast<int32_t>(from.stickyTransform);
+    if (!b2h(from.crop, &to->crop) ||
+            !b2h(from.surfaceDamage, &to->surfaceDamage) ||
+            !b2h(from.fence, hFenceWrapper)) {
+        return false;
+    }
+    to->fence = hFenceWrapper->getHandle();
+    return true;
+}
+
+bool h2b(HQueueBufferOutput const& from, BQueueBufferOutput* to) {
+    to->width = from.width;
+    to->height = from.height;
+    to->transformHint = static_cast<uint32_t>(from.transformHint);
+    to->numPendingBuffers = from.numPendingBuffers;
+    to->nextFrameNumber = from.nextFrameNumber;
+    to->bufferReplaced = from.bufferReplaced;
+    return true;
+}
+
+} // unnamed namespace
+
 // H2BGraphicBufferProducer
 // ========================
 
@@ -209,47 +250,13 @@
         int slot,
         QueueBufferInput const& input,
         QueueBufferOutput* output) {
-    HRect hCrop{};
-    (void)b2h(input.crop, &hCrop);
-
-    using HInput = HGraphicBufferProducer::QueueBufferInput;
-    HInput hInput{
-            input.timestamp,
-            static_cast<bool>(input.isAutoTimestamp),
-            static_cast<int32_t>(input.dataSpace),
-            {}, // crop
-            static_cast<int32_t>(input.transform),
-            static_cast<int32_t>(input.stickyTransform),
-            {}, // fence
-            {}  // surfaceDamage
-            };
-
-    // Convert crop.
-    if (!b2h(input.crop, &hInput.crop)) {
-        LOG(ERROR) << "queueBuffer: corrupted input crop rectangle.";
-        return UNKNOWN_ERROR;
-    }
-
-    // Convert surfaceDamage.
-    size_t numRects;
-    Rect const* rectArray = input.surfaceDamage.getArray(&numRects);
-    hInput.surfaceDamage.resize(numRects);
-    for (size_t i = 0; i < numRects; ++i) {
-        if (!b2h(rectArray[i], &hInput.surfaceDamage[i])) {
-            LOG(ERROR) << "queueBuffer: corrupted input surface damage.";
-            return UNKNOWN_ERROR;
-        }
-    }
-
-    // Convert fence.
+    HQueueBufferInput hInput{};
     HFenceWrapper hFenceWrapper;
-    if (!b2h(input.fence, &hFenceWrapper)) {
-        LOG(ERROR) << "queueBuffer: corrupted input fence.";
+    if (!b2h(input, &hInput, &hFenceWrapper)) {
+        LOG(ERROR) << "queueBuffer: corrupted input.";
         return UNKNOWN_ERROR;
     }
-    hInput.fence = hFenceWrapper.getHandle();
 
-    using HOutput = HGraphicBufferProducer::QueueBufferOutput;
     bool converted{};
     status_t bStatus{};
     Return<void> transResult = mBase->queueBuffer(
@@ -257,15 +264,8 @@
             hInput,
             [&converted, &bStatus, output](
                     HStatus hStatus,
-                    HOutput const& hOutput) {
-                converted = h2b(hStatus, &bStatus);
-                output->width = hOutput.width;
-                output->height = hOutput.height;
-                output->transformHint =
-                        static_cast<uint32_t>(hOutput.transformHint);
-                output->numPendingBuffers = hOutput.numPendingBuffers;
-                output->nextFrameNumber = hOutput.nextFrameNumber;
-                output->bufferReplaced = hOutput.bufferReplaced;
+                    HQueueBufferOutput const& hOutput) {
+                converted = h2b(hStatus, &bStatus) && h2b(hOutput, output);
             });
 
     if (!transResult.isOk()) {
@@ -332,7 +332,6 @@
         }
     }
 
-    using HOutput = HGraphicBufferProducer::QueueBufferOutput;
     bool converted{};
     status_t bStatus{};
     Return<void> transResult = mBase->connect(
@@ -341,15 +340,8 @@
             producerControlledByApp,
             [&converted, &bStatus, output](
                     HStatus hStatus,
-                    HOutput hOutput) {
-                converted = h2b(hStatus, &bStatus);
-                output->width = hOutput.width;
-                output->height = hOutput.height;
-                output->transformHint =
-                        static_cast<uint32_t>(hOutput.transformHint);
-                output->numPendingBuffers = hOutput.numPendingBuffers;
-                output->nextFrameNumber = hOutput.nextFrameNumber;
-                output->bufferReplaced = hOutput.bufferReplaced;
+                    HQueueBufferOutput const& hOutput) {
+                converted = h2b(hStatus, &bStatus) && h2b(hOutput, output);
             });
     if (!transResult.isOk()) {
         LOG(ERROR) << "connect: transaction failed.";
diff --git a/libs/gui/include/gui/BufferQueue.h b/libs/gui/include/gui/BufferQueue.h
index 721427b..da95274 100644
--- a/libs/gui/include/gui/BufferQueue.h
+++ b/libs/gui/include/gui/BufferQueue.h
@@ -61,7 +61,6 @@
         void onDisconnect() override;
         void onFrameAvailable(const BufferItem& item) override;
         void onFrameReplaced(const BufferItem& item) override;
-        void onBufferAllocated(const BufferItem& item) override;
         void onBuffersReleased() override;
         void onSidebandStreamChanged() override;
         void addAndGetFrameTimestamps(
diff --git a/libs/gui/include/gui/BufferQueueConsumer.h b/libs/gui/include/gui/BufferQueueConsumer.h
index aa13c0c..7db69ec 100644
--- a/libs/gui/include/gui/BufferQueueConsumer.h
+++ b/libs/gui/include/gui/BufferQueueConsumer.h
@@ -171,6 +171,9 @@
 
     // End functions required for backwards compatibility
 
+    // Value used to determine if present time is valid.
+    constexpr static int MAX_REASONABLE_NSEC = 1'000'000'000ULL; // 1 second
+
 private:
     sp<BufferQueueCore> mCore;
 
diff --git a/libs/gui/include/gui/ConsumerBase.h b/libs/gui/include/gui/ConsumerBase.h
index 7c26482..366ced3 100644
--- a/libs/gui/include/gui/ConsumerBase.h
+++ b/libs/gui/include/gui/ConsumerBase.h
@@ -141,7 +141,6 @@
     // classes if they want the notification.
     virtual void onFrameAvailable(const BufferItem& item) override;
     virtual void onFrameReplaced(const BufferItem& item) override;
-    virtual void onBufferAllocated(const BufferItem& item) override;
     virtual void onBuffersReleased() override;
     virtual void onSidebandStreamChanged() override;
 
diff --git a/libs/gui/include/gui/IConsumerListener.h b/libs/gui/include/gui/IConsumerListener.h
index 03fefbe..c082882 100644
--- a/libs/gui/include/gui/IConsumerListener.h
+++ b/libs/gui/include/gui/IConsumerListener.h
@@ -61,13 +61,6 @@
     // This is called without any lock held and can be called concurrently by multiple threads.
     virtual void onFrameReplaced(const BufferItem& /* item */) {} /* Asynchronous */
 
-    // onBufferAllocated is called to notify the buffer consumer that the BufferQueue has allocated
-    // a GraphicBuffer for a particular slot. Only the GraphicBuffer pointer and the slot ID will
-    // be populated.
-    //
-    // This is called without any lock held and can be called concurrently by multiple threads.
-    virtual void onBufferAllocated(const BufferItem& /* item */) {} /* Asynchronous */
-
     // onBuffersReleased is called to notify the buffer consumer that the BufferQueue has released
     // its references to one or more GraphicBuffers contained in its slots. The buffer consumer
     // should then call BufferQueue::getReleasedBuffers to retrieve the list of buffers.
diff --git a/libs/gui/include/gui/bufferqueue/1.0/WGraphicBufferProducer.h b/libs/gui/include/gui/bufferqueue/1.0/WGraphicBufferProducer.h
index 0e57f20..029dcc0 100644
--- a/libs/gui/include/gui/bufferqueue/1.0/WGraphicBufferProducer.h
+++ b/libs/gui/include/gui/bufferqueue/1.0/WGraphicBufferProducer.h
@@ -68,7 +68,7 @@
     Return<void> requestBuffer(int32_t slot, HGraphicBufferProducer::requestBuffer_cb _hidl_cb) override {
         sp<GraphicBuffer> buf;
         status_t status = mBase->requestBuffer(slot, &buf);
-        AnwBuffer anwBuffer;
+        AnwBuffer anwBuffer{};
         if (buf != nullptr) {
             ::android::conversion::wrapAs(&anwBuffer, *buf);
         }
@@ -89,15 +89,15 @@
             uint32_t width, uint32_t height,
             ::android::hardware::graphics::common::V1_0::PixelFormat format, uint32_t usage,
             bool getFrameTimestamps, HGraphicBufferProducer::dequeueBuffer_cb _hidl_cb) override {
-        int slot;
+        int slot{};
         sp<Fence> fence;
         ::android::FrameEventHistoryDelta outTimestamps;
         status_t status = mBase->dequeueBuffer(
             &slot, &fence, width, height,
             static_cast<::android::PixelFormat>(format), usage, nullptr,
             getFrameTimestamps ? &outTimestamps : nullptr);
-        hidl_handle tFence;
-        HGraphicBufferProducer::FrameEventHistoryDelta tOutTimestamps;
+        hidl_handle tFence{};
+        HGraphicBufferProducer::FrameEventHistoryDelta tOutTimestamps{};
 
         native_handle_t* nh = nullptr;
         if ((fence == nullptr) || !::android::conversion::wrapAs(&tFence, &nh, *fence)) {
@@ -144,8 +144,8 @@
         sp<GraphicBuffer> outBuffer;
         sp<Fence> outFence;
         status_t status = mBase->detachNextBuffer(&outBuffer, &outFence);
-        AnwBuffer tBuffer;
-        hidl_handle tFence;
+        AnwBuffer tBuffer{};
+        hidl_handle tFence{};
 
         if (outBuffer == nullptr) {
             LOG(ERROR) << "TWGraphicBufferProducer::detachNextBuffer - "
@@ -185,7 +185,7 @@
     Return<void> queueBuffer(
             int32_t slot, const HGraphicBufferProducer::QueueBufferInput& input,
             HGraphicBufferProducer::queueBuffer_cb _hidl_cb) override {
-        HGraphicBufferProducer::QueueBufferOutput tOutput;
+        HGraphicBufferProducer::QueueBufferOutput tOutput{};
         BGraphicBufferProducer::QueueBufferInput lInput(
                 0, false, HAL_DATASPACE_UNKNOWN,
                 ::android::Rect(0, 0, 1, 1),
@@ -246,7 +246,7 @@
                 producerControlledByApp,
                 &lOutput);
 
-        HGraphicBufferProducer::QueueBufferOutput tOutput;
+        HGraphicBufferProducer::QueueBufferOutput tOutput{};
         std::vector<std::vector<native_handle_t*> > nhAA;
         if (!::android::conversion::wrapAs(&tOutput, &nhAA, lOutput)) {
             LOG(ERROR) << "TWGraphicBufferProducer::connect - "
@@ -320,11 +320,11 @@
         status_t status = mBase->getLastQueuedBuffer(
                 &lOutBuffer, &lOutFence, lOutTransformMatrix);
 
-        AnwBuffer tOutBuffer;
+        AnwBuffer tOutBuffer{};
         if (lOutBuffer != nullptr) {
             ::android::conversion::wrapAs(&tOutBuffer, *lOutBuffer);
         }
-        hidl_handle tOutFence;
+        hidl_handle tOutFence{};
         native_handle_t* nh = nullptr;
         if ((lOutFence == nullptr) || !::android::conversion::wrapAs(&tOutFence, &nh, *lOutFence)) {
             LOG(ERROR) << "TWGraphicBufferProducer::getLastQueuedBuffer - "
@@ -346,7 +346,7 @@
         ::android::FrameEventHistoryDelta lDelta;
         mBase->getFrameTimestamps(&lDelta);
 
-        HGraphicBufferProducer::FrameEventHistoryDelta tDelta;
+        HGraphicBufferProducer::FrameEventHistoryDelta tDelta{};
         std::vector<std::vector<native_handle_t*> > nhAA;
         if (!::android::conversion::wrapAs(&tDelta, &nhAA, lDelta)) {
             LOG(ERROR) << "TWGraphicBufferProducer::getFrameTimestamps - "
@@ -365,7 +365,7 @@
     }
 
     Return<void> getUniqueId(HGraphicBufferProducer::getUniqueId_cb _hidl_cb) override {
-        uint64_t outId;
+        uint64_t outId{};
         status_t status = mBase->getUniqueId(&outId);
         _hidl_cb(static_cast<int32_t>(status), outId);
         return Void();
diff --git a/libs/renderengine/gl/GLESRenderEngine.cpp b/libs/renderengine/gl/GLESRenderEngine.cpp
index 48cb620..46a8e9e 100644
--- a/libs/renderengine/gl/GLESRenderEngine.cpp
+++ b/libs/renderengine/gl/GLESRenderEngine.cpp
@@ -271,13 +271,6 @@
     extensions.initWithGLStrings(glGetString(GL_VENDOR), glGetString(GL_RENDERER),
                                  glGetString(GL_VERSION), glGetString(GL_EXTENSIONS));
 
-    // In order to have protected contents in GPU composition, the OpenGL ES extension
-    // GL_EXT_protected_textures must be supported. If it's not supported, reset
-    // protected context to EGL_NO_CONTEXT to indicate that protected contents is not supported.
-    if (!extensions.hasProtectedTexture()) {
-        protectedContext = EGL_NO_CONTEXT;
-    }
-
     EGLSurface protectedDummy = EGL_NO_SURFACE;
     if (protectedContext != EGL_NO_CONTEXT && !extensions.hasSurfacelessContext()) {
         protectedDummy =
@@ -616,10 +609,6 @@
     const GLenum target = GL_TEXTURE_EXTERNAL_OES;
 
     glBindTexture(target, texName);
-    if (supportsProtectedContent()) {
-        glTexParameteri(target, GL_TEXTURE_PROTECTED_EXT,
-                        glImage.isProtected() ? GL_TRUE : GL_FALSE);
-    }
     if (glImage.getEGLImage() != EGL_NO_IMAGE_KHR) {
         glEGLImageTargetTexture2DOES(target, static_cast<GLeglImageOES>(glImage.getEGLImage()));
     }
@@ -799,10 +788,6 @@
 
     // Bind the texture and turn our EGLImage into a texture
     glBindTexture(GL_TEXTURE_2D, textureName);
-    if (supportsProtectedContent()) {
-        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_PROTECTED_EXT,
-                        mInProtectedContext ? GL_TRUE : GL_FALSE);
-    }
     glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, (GLeglImageOES)eglImage);
 
     // Bind the Framebuffer to render into
@@ -1311,7 +1296,9 @@
     StringAppendF(&result, "GLES: %s, %s, %s\n", extensions.getVendor(), extensions.getRenderer(),
                   extensions.getVersion());
     StringAppendF(&result, "%s\n", extensions.getExtensions());
-    StringAppendF(&result, "RenderEngine is in protected context : %d\n", mInProtectedContext);
+    StringAppendF(&result, "RenderEngine supports protected context: %d\n",
+                  supportsProtectedContent());
+    StringAppendF(&result, "RenderEngine is in protected context: %d\n", mInProtectedContext);
     StringAppendF(&result, "RenderEngine program cache size for unprotected context: %zu\n",
                   cache.getSize(mEGLContext));
     StringAppendF(&result, "RenderEngine program cache size for protected context: %zu\n",
diff --git a/libs/sensor/Sensor.cpp b/libs/sensor/Sensor.cpp
index d9a986e..139987e 100644
--- a/libs/sensor/Sensor.cpp
+++ b/libs/sensor/Sensor.cpp
@@ -22,6 +22,13 @@
 #include <binder/IPermissionController.h>
 #include <binder/IServiceManager.h>
 
+/*
+ * The permission to use for activity recognition sensors (like step counter).
+ * See sensor types for more details on what sensors should require this
+ * permission.
+ */
+#define SENSOR_PERMISSION_ACTIVITY_RECOGNITION "android.permission.ACTIVITY_RECOGNITION"
+
 // ----------------------------------------------------------------------------
 namespace android {
 // ----------------------------------------------------------------------------
@@ -116,7 +123,7 @@
         mStringType = SENSOR_STRING_TYPE_HEART_RATE;
         mRequiredPermission = SENSOR_PERMISSION_BODY_SENSORS;
         AppOpsManager appOps;
-        mRequiredAppOp = appOps.permissionToOpCode(String16(SENSOR_PERMISSION_BODY_SENSORS));
+        mRequiredAppOp = appOps.permissionToOpCode(String16(mRequiredPermission));
         mFlags |= SENSOR_FLAG_ON_CHANGE_MODE;
         } break;
     case SENSOR_TYPE_LIGHT:
@@ -165,14 +172,22 @@
             mFlags |= SENSOR_FLAG_WAKE_UP;
         }
         break;
-    case SENSOR_TYPE_STEP_COUNTER:
+    case SENSOR_TYPE_STEP_COUNTER: {
         mStringType = SENSOR_STRING_TYPE_STEP_COUNTER;
+        mRequiredPermission = SENSOR_PERMISSION_ACTIVITY_RECOGNITION;
+        AppOpsManager appOps;
+        mRequiredAppOp =
+                appOps.permissionToOpCode(String16(mRequiredPermission));
         mFlags |= SENSOR_FLAG_ON_CHANGE_MODE;
-        break;
-    case SENSOR_TYPE_STEP_DETECTOR:
+        } break;
+    case SENSOR_TYPE_STEP_DETECTOR: {
         mStringType = SENSOR_STRING_TYPE_STEP_DETECTOR;
+        mRequiredPermission = SENSOR_PERMISSION_ACTIVITY_RECOGNITION;
+        AppOpsManager appOps;
+        mRequiredAppOp =
+                appOps.permissionToOpCode(String16(mRequiredPermission));
         mFlags |= SENSOR_FLAG_SPECIAL_REPORTING_MODE;
-        break;
+        } break;
     case SENSOR_TYPE_TEMPERATURE:
         mStringType = SENSOR_STRING_TYPE_TEMPERATURE;
         mFlags |= SENSOR_FLAG_ON_CHANGE_MODE;
diff --git a/libs/ui/GraphicBufferAllocator.cpp b/libs/ui/GraphicBufferAllocator.cpp
index 5a67dc4..0861a1f 100644
--- a/libs/ui/GraphicBufferAllocator.cpp
+++ b/libs/ui/GraphicBufferAllocator.cpp
@@ -60,6 +60,15 @@
 
 GraphicBufferAllocator::~GraphicBufferAllocator() {}
 
+size_t GraphicBufferAllocator::getTotalSize() const {
+    Mutex::Autolock _l(sLock);
+    size_t total = 0;
+    for (size_t i = 0; i < sAllocList.size(); ++i) {
+        total += sAllocList.valueAt(i).size;
+    }
+    return total;
+}
+
 void GraphicBufferAllocator::dump(std::string& result) const {
     Mutex::Autolock _l(sLock);
     KeyedVector<buffer_handle_t, alloc_rec_t>& list(sAllocList);
diff --git a/libs/ui/include/ui/GraphicBufferAllocator.h b/libs/ui/include/ui/GraphicBufferAllocator.h
index 3a547b6..25d4512 100644
--- a/libs/ui/include/ui/GraphicBufferAllocator.h
+++ b/libs/ui/include/ui/GraphicBufferAllocator.h
@@ -49,6 +49,8 @@
 
     status_t free(buffer_handle_t handle);
 
+    size_t getTotalSize() const;
+
     void dump(std::string& res) const;
     static void dumpToSystemLog();
 
diff --git a/opengl/libs/EGL/Loader.cpp b/opengl/libs/EGL/Loader.cpp
index 95c41bc..d5c46c6 100644
--- a/opengl/libs/EGL/Loader.cpp
+++ b/opengl/libs/EGL/Loader.cpp
@@ -173,8 +173,10 @@
     }
 }
 
+static const char* DRIVER_SUFFIX_PROPERTY = "ro.hardware.egl";
+
 static const char* HAL_SUBNAME_KEY_PROPERTIES[2] = {
-    "ro.hardware.egl",
+    DRIVER_SUFFIX_PROPERTY,
     "ro.board.platform",
 };
 
@@ -198,6 +200,8 @@
         // Secondly, try to load from driver apk.
         hnd = attempt_to_load_updated_driver(cnx);
     }
+
+    bool failToLoadFromDriverSuffixProperty = false;
     if (!hnd) {
         // Finally, try to load system driver, start by searching for the library name appended by
         // the system properties of the GLES userspace driver in both locations.
@@ -209,9 +213,11 @@
             if (property_get(key, prop, nullptr) <= 0) {
                 continue;
             }
-            hnd = attempt_to_load_system_driver(cnx, prop);
+            hnd = attempt_to_load_system_driver(cnx, prop, true);
             if (hnd) {
                 break;
+            } else if (strcmp(key, DRIVER_SUFFIX_PROPERTY) == 0) {
+                failToLoadFromDriverSuffixProperty = true;
             }
         }
     }
@@ -222,7 +228,11 @@
         // i.e.:
         //      libGLES.so, or:
         //      libEGL.so, libGLESv1_CM.so, libGLESv2.so
-        hnd = attempt_to_load_system_driver(cnx, nullptr);
+        hnd = attempt_to_load_system_driver(cnx, nullptr, true);
+    }
+
+    if (!hnd && !failToLoadFromDriverSuffixProperty) {
+        hnd = attempt_to_load_system_driver(cnx, nullptr, false);
     }
 
     if (!hnd) {
@@ -340,11 +350,11 @@
     }
 }
 
-static void* load_system_driver(const char* kind, const char* suffix) {
+static void* load_system_driver(const char* kind, const char* suffix, const bool exact) {
     ATRACE_CALL();
     class MatchFile {
     public:
-        static std::string find(const char* libraryName) {
+        static std::string find(const char* libraryName, const bool exact) {
             const char* const searchPaths[] = {
 #if defined(__LP64__)
                     "/vendor/lib64/egl",
@@ -356,8 +366,8 @@
             };
 
             for (auto dir : searchPaths) {
-                std::string absolutePath = dir + std::string("/") + libraryName + ".so";
-                if (!access(absolutePath.c_str(), R_OK)) {
+                std::string absolutePath;
+                if (find(absolutePath, libraryName, dir, exact)) {
                     return absolutePath;
                 }
             }
@@ -365,13 +375,53 @@
             // Driver not found. gah.
             return std::string();
         }
+    private:
+        static bool find(std::string& result,
+                const std::string& pattern, const char* const search, bool exact) {
+            if (exact) {
+                std::string absolutePath = std::string(search) + "/" + pattern + ".so";
+                if (!access(absolutePath.c_str(), R_OK)) {
+                    result = absolutePath;
+                    return true;
+                }
+                return false;
+            }
+
+            DIR* d = opendir(search);
+            if (d != nullptr) {
+                struct dirent* e;
+                while ((e = readdir(d)) != nullptr) {
+                    if (e->d_type == DT_DIR) {
+                        continue;
+                    }
+                    if (!strcmp(e->d_name, "libGLES_android.so")) {
+                        // always skip the software renderer
+                        continue;
+                    }
+                    if (strstr(e->d_name, pattern.c_str()) == e->d_name) {
+                        if (!strcmp(e->d_name + strlen(e->d_name) - 3, ".so")) {
+                            result = std::string(search) + "/" + e->d_name;
+                            closedir(d);
+                            return true;
+                        }
+                    }
+                }
+                closedir(d);
+            }
+            return false;
+        }
     };
 
     std::string libraryName = std::string("lib") + kind;
     if (suffix) {
         libraryName += std::string("_") + suffix;
+    } else if (!exact) {
+        // Deprecated: we look for files that match
+        //      libGLES_*.so, or:
+        //      libEGL_*.so, libGLESv1_CM_*.so, libGLESv2_*.so
+        libraryName += std::string("_");
     }
-    std::string absolutePath = MatchFile::find(libraryName.c_str());
+    std::string absolutePath = MatchFile::find(libraryName.c_str(), exact);
     if (absolutePath.empty()) {
         // this happens often, we don't want to log an error
         return nullptr;
@@ -458,14 +508,14 @@
                 if (property_get(key, prop, nullptr) <= 0) {
                     continue;
                 }
-                void* dso = load_system_driver("EGL", prop);
+                void* dso = load_system_driver("EGL", prop, true);
                 if (dso) {
                     cnx->vendorEGL = dso;
                     break;
                 }
             }
             if (!cnx->vendorEGL) {
-                cnx->vendorEGL = load_system_driver("EGL", nullptr);
+                cnx->vendorEGL = load_system_driver("EGL", nullptr, true);
             }
         }
     } else {
@@ -562,26 +612,27 @@
 #endif
 }
 
-Loader::driver_t* Loader::attempt_to_load_system_driver(egl_connection_t* cnx, const char* suffix) {
+Loader::driver_t* Loader::attempt_to_load_system_driver(egl_connection_t* cnx, const char* suffix,
+                                                        const bool exact) {
     ATRACE_CALL();
     android::GraphicsEnv::getInstance().setDriverToLoad(android::GraphicsEnv::Driver::GL);
     driver_t* hnd = nullptr;
-    void* dso = load_system_driver("GLES", suffix);
+    void* dso = load_system_driver("GLES", suffix, exact);
     if (dso) {
         initialize_api(dso, cnx, EGL | GLESv1_CM | GLESv2);
         hnd = new driver_t(dso);
         return hnd;
     }
-    dso = load_system_driver("EGL", suffix);
+    dso = load_system_driver("EGL", suffix, exact);
     if (dso) {
         initialize_api(dso, cnx, EGL);
         hnd = new driver_t(dso);
 
-        dso = load_system_driver("GLESv1_CM", suffix);
+        dso = load_system_driver("GLESv1_CM", suffix, exact);
         initialize_api(dso, cnx, GLESv1_CM);
         hnd->set(dso, GLESv1_CM);
 
-        dso = load_system_driver("GLESv2", suffix);
+        dso = load_system_driver("GLESv2", suffix, exact);
         initialize_api(dso, cnx, GLESv2);
         hnd->set(dso, GLESv2);
     }
diff --git a/opengl/libs/EGL/Loader.h b/opengl/libs/EGL/Loader.h
index f6b67ab..0292d02 100644
--- a/opengl/libs/EGL/Loader.h
+++ b/opengl/libs/EGL/Loader.h
@@ -57,7 +57,7 @@
     Loader();
     driver_t* attempt_to_load_angle(egl_connection_t* cnx);
     driver_t* attempt_to_load_updated_driver(egl_connection_t* cnx);
-    driver_t* attempt_to_load_system_driver(egl_connection_t* cnx, const char* suffix);
+    driver_t* attempt_to_load_system_driver(egl_connection_t* cnx, const char* suffix, const bool exact);
     void initialize_api(void* dso, egl_connection_t* cnx, uint32_t mask);
 
     static __attribute__((noinline))
diff --git a/services/gpuservice/GpuService.cpp b/services/gpuservice/GpuService.cpp
index 59fa1c0..b42884e 100644
--- a/services/gpuservice/GpuService.cpp
+++ b/services/gpuservice/GpuService.cpp
@@ -51,12 +51,12 @@
 void GpuService::setGpuStats(const std::string& driverPackageName,
                              const std::string& driverVersionName, uint64_t driverVersionCode,
                              int64_t driverBuildTime, const std::string& appPackageName,
-                             GraphicsEnv::Driver driver, bool isDriverLoaded,
-                             int64_t driverLoadingTime) {
+                             const int32_t vulkanVersion, GraphicsEnv::Driver driver,
+                             bool isDriverLoaded, int64_t driverLoadingTime) {
     ATRACE_CALL();
 
     mGpuStats->insert(driverPackageName, driverVersionName, driverVersionCode, driverBuildTime,
-                      appPackageName, driver, isDriverLoaded, driverLoadingTime);
+                      appPackageName, vulkanVersion, driver, isDriverLoaded, driverLoadingTime);
 }
 
 status_t GpuService::getGpuStatsGlobalInfo(std::vector<GpuStatsGlobalInfo>* outStats) const {
diff --git a/services/gpuservice/GpuService.h b/services/gpuservice/GpuService.h
index 7a9b2d4..3e02b4a 100644
--- a/services/gpuservice/GpuService.h
+++ b/services/gpuservice/GpuService.h
@@ -45,8 +45,9 @@
      */
     void setGpuStats(const std::string& driverPackageName, const std::string& driverVersionName,
                      uint64_t driverVersionCode, int64_t driverBuildTime,
-                     const std::string& appPackageName, GraphicsEnv::Driver driver,
-                     bool isDriverLoaded, int64_t driverLoadingTime) override;
+                     const std::string& appPackageName, const int32_t vulkanVersion,
+                     GraphicsEnv::Driver driver, bool isDriverLoaded,
+                     int64_t driverLoadingTime) override;
     status_t getGpuStatsGlobalInfo(std::vector<GpuStatsGlobalInfo>* outStats) const override;
     status_t getGpuStatsAppInfo(std::vector<GpuStatsAppInfo>* outStats) const override;
 
diff --git a/services/gpuservice/gpustats/GpuStats.cpp b/services/gpuservice/gpustats/GpuStats.cpp
index 6185305..5174c86 100644
--- a/services/gpuservice/gpustats/GpuStats.cpp
+++ b/services/gpuservice/gpustats/GpuStats.cpp
@@ -19,11 +19,12 @@
 
 #include "GpuStats.h"
 
-#include <unordered_set>
-
+#include <cutils/properties.h>
 #include <log/log.h>
 #include <utils/Trace.h>
 
+#include <unordered_set>
+
 namespace android {
 
 static bool addLoadingCount(GraphicsEnv::Driver driver, bool isDriverLoaded,
@@ -68,8 +69,8 @@
 
 void GpuStats::insert(const std::string& driverPackageName, const std::string& driverVersionName,
                       uint64_t driverVersionCode, int64_t driverBuildTime,
-                      const std::string& appPackageName, GraphicsEnv::Driver driver,
-                      bool isDriverLoaded, int64_t driverLoadingTime) {
+                      const std::string& appPackageName, const int32_t vulkanVersion,
+                      GraphicsEnv::Driver driver, bool isDriverLoaded, int64_t driverLoadingTime) {
     ATRACE_CALL();
 
     std::lock_guard<std::mutex> lock(mLock);
@@ -79,11 +80,13 @@
           "\tdriverVersionCode[%" PRIu64 "]\n"
           "\tdriverBuildTime[%" PRId64 "]\n"
           "\tappPackageName[%s]\n"
+          "\tvulkanVersion[%d]\n"
           "\tdriver[%d]\n"
           "\tisDriverLoaded[%d]\n"
           "\tdriverLoadingTime[%" PRId64 "]",
           driverPackageName.c_str(), driverVersionName.c_str(), driverVersionCode, driverBuildTime,
-          appPackageName.c_str(), static_cast<int32_t>(driver), isDriverLoaded, driverLoadingTime);
+          appPackageName.c_str(), vulkanVersion, static_cast<int32_t>(driver), isDriverLoaded,
+          driverLoadingTime);
 
     if (!mGlobalStats.count(driverVersionCode)) {
         GpuStatsGlobalInfo globalInfo;
@@ -94,6 +97,7 @@
         globalInfo.driverVersionName = driverVersionName;
         globalInfo.driverVersionCode = driverVersionCode;
         globalInfo.driverBuildTime = driverBuildTime;
+        globalInfo.vulkanVersion = vulkanVersion;
         mGlobalStats.insert({driverVersionCode, globalInfo});
     } else if (!addLoadingCount(driver, isDriverLoaded, &mGlobalStats[driverVersionCode])) {
         return;
@@ -117,6 +121,16 @@
     addLoadingTime(driver, driverLoadingTime, &mAppStats[appStatsKey]);
 }
 
+void GpuStats::interceptSystemDriverStatsLocked() {
+    // Append cpuVulkanVersion and glesVersion to system driver stats
+    if (!mGlobalStats.count(0) || mGlobalStats[0].glesVersion) {
+        return;
+    }
+
+    mGlobalStats[0].cpuVulkanVersion = property_get_int32("ro.cpuvulkan.version", 0);
+    mGlobalStats[0].glesVersion = property_get_int32("ro.opengles.version", 0);
+}
+
 void GpuStats::dump(const Vector<String16>& args, std::string* result) {
     ATRACE_CALL();
 
@@ -173,6 +187,8 @@
 }
 
 void GpuStats::dumpGlobalLocked(std::string* result) {
+    interceptSystemDriverStatsLocked();
+
     for (const auto& ele : mGlobalStats) {
         result->append(ele.second.toString());
         result->append("\n");
@@ -193,6 +209,8 @@
     outStats->clear();
     outStats->reserve(mGlobalStats.size());
 
+    interceptSystemDriverStatsLocked();
+
     for (const auto& ele : mGlobalStats) {
         outStats->emplace_back(ele.second);
     }
diff --git a/services/gpuservice/gpustats/GpuStats.h b/services/gpuservice/gpustats/GpuStats.h
index d942154..49699ee 100644
--- a/services/gpuservice/gpustats/GpuStats.h
+++ b/services/gpuservice/gpustats/GpuStats.h
@@ -35,8 +35,8 @@
     // Insert new gpu stats into global stats and app stats.
     void insert(const std::string& driverPackageName, const std::string& driverVersionName,
                 uint64_t driverVersionCode, int64_t driverBuildTime,
-                const std::string& appPackageName, GraphicsEnv::Driver driver, bool isDriverLoaded,
-                int64_t driverLoadingTime);
+                const std::string& appPackageName, const int32_t vulkanVersion,
+                GraphicsEnv::Driver driver, bool isDriverLoaded, int64_t driverLoadingTime);
     // dumpsys interface
     void dump(const Vector<String16>& args, std::string* result);
     // Pull gpu global stats
@@ -52,6 +52,8 @@
     void dumpGlobalLocked(std::string* result);
     // Dump app stats
     void dumpAppLocked(std::string* result);
+    // Append cpuVulkanVersion and glesVersion to system driver stats
+    void interceptSystemDriverStatsLocked();
 
     // Below limits the memory usage of GpuStats to be less than 10KB. This is
     // the preferred number for statsd while maintaining nice data quality.
diff --git a/services/sensorservice/SensorEventConnection.cpp b/services/sensorservice/SensorEventConnection.cpp
index c4cfdc6..0e40940 100644
--- a/services/sensorservice/SensorEventConnection.cpp
+++ b/services/sensorservice/SensorEventConnection.cpp
@@ -285,8 +285,9 @@
                         scratch[count++] = buffer[i];
                     }
                 } else {
-                    // Regular sensor event, just copy it to the scratch buffer.
-                    if (hasSensorAccess()) {
+                    // Regular sensor event, just copy it to the scratch buffer after checking
+                    // the AppOp.
+                    if (hasSensorAccess() && noteOpIfRequired(buffer[i])) {
                         scratch[count++] = buffer[i];
                     }
                 }
@@ -386,6 +387,16 @@
     return mHasSensorAccess && !mService->mSensorPrivacyPolicy->isSensorPrivacyEnabled();
 }
 
+bool SensorService::SensorEventConnection::noteOpIfRequired(const sensors_event_t& event) {
+    bool success = true;
+    const auto iter = mHandleToAppOp.find(event.sensor);
+    if (iter != mHandleToAppOp.end()) {
+        int32_t appOpMode = mService->sAppOpsManager.noteOp((*iter).second, mUid, mOpPackageName);
+        success = (appOpMode == AppOpsManager::MODE_ALLOWED);
+    }
+    return success;
+}
+
 void SensorService::SensorEventConnection::reAllocateCacheLocked(sensors_event_t const* scratch,
                                                                  int count) {
     sensors_event_t *eventCache_new;
diff --git a/services/sensorservice/SensorEventConnection.h b/services/sensorservice/SensorEventConnection.h
index 7077880..fd881cb 100644
--- a/services/sensorservice/SensorEventConnection.h
+++ b/services/sensorservice/SensorEventConnection.h
@@ -19,6 +19,7 @@
 
 #include <stdint.h>
 #include <sys/types.h>
+#include <unordered_map>
 
 #include <utils/Vector.h>
 #include <utils/SortedVector.h>
@@ -134,6 +135,9 @@
     // privacy not being enabled.
     bool hasSensorAccess();
 
+    // Call noteOp for the sensor if the sensor requires a permission
+    bool noteOpIfRequired(const sensors_event_t& event);
+
     sp<SensorService> const mService;
     sp<BitTube> mChannel;
     uid_t mUid;
@@ -181,6 +185,10 @@
     mutable Mutex mDestroyLock;
     bool mDestroyed;
     bool mHasSensorAccess;
+
+    // Store a mapping of sensor handles to required AppOp for a sensor. This map only contains a
+    // valid mapping for sensors that require a permission in order to reduce the lookup time.
+    std::unordered_map<int32_t, int32_t> mHandleToAppOp;
 };
 
 } // namepsace android
diff --git a/services/sensorservice/SensorService.cpp b/services/sensorservice/SensorService.cpp
index 0269990..639ce78 100644
--- a/services/sensorservice/SensorService.cpp
+++ b/services/sensorservice/SensorService.cpp
@@ -13,8 +13,8 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+#include <android/content/pm/IPackageManagerNative.h>
 #include <binder/ActivityManager.h>
-#include <binder/AppOpsManager.h>
 #include <binder/BinderService.h>
 #include <binder/IServiceManager.h>
 #include <binder/PermissionCache.h>
@@ -75,6 +75,9 @@
 const char* SensorService::WAKE_LOCK_NAME = "SensorService_wakelock";
 uint8_t SensorService::sHmacGlobalKey[128] = {};
 bool SensorService::sHmacGlobalKeyIsValid = false;
+std::map<String16, int> SensorService::sPackageTargetVersion;
+Mutex SensorService::sPackageTargetVersionLock;
+AppOpsManager SensorService::sAppOpsManager;
 
 #define SENSOR_SERVICE_DIR "/data/system/sensor_service"
 #define SENSOR_SERVICE_HMAC_KEY_FILE  SENSOR_SERVICE_DIR "/hmac_key"
@@ -1394,6 +1397,14 @@
         checkWakeLockStateLocked();
     }
 
+    {
+        Mutex::Autolock packageLock(sPackageTargetVersionLock);
+        auto iter = sPackageTargetVersion.find(c->mOpPackageName);
+        if (iter != sPackageTargetVersion.end()) {
+            sPackageTargetVersion.erase(iter);
+        }
+    }
+
     SensorDevice& dev(SensorDevice::getInstance());
     dev.notifyConnectionDestroyed(c);
 }
@@ -1539,6 +1550,10 @@
     if (err == NO_ERROR) {
         connection->updateLooperRegistration(mLooper);
 
+        if (sensor->getSensor().getRequiredPermission().size() > 0) {
+            connection->mHandleToAppOp[handle] = sensor->getSensor().getRequiredAppOp();
+        }
+
         mLastNSensorRegistrations.editItemAt(mNextSensorRegIndex) =
                 SensorRegistrationInfo(handle, connection->getPackageName(),
                                        samplingPeriodNs, maxBatchReportLatencyNs, true);
@@ -1663,13 +1678,50 @@
 
 bool SensorService::canAccessSensor(const Sensor& sensor, const char* operation,
         const String16& opPackageName) {
-    const String8& requiredPermission = sensor.getRequiredPermission();
-
-    if (requiredPermission.length() <= 0) {
+    // Check if a permission is required for this sensor
+    if (sensor.getRequiredPermission().length() <= 0) {
         return true;
     }
 
+    const int32_t opCode = sensor.getRequiredAppOp();
+    const int32_t appOpMode = sAppOpsManager.checkOp(opCode,
+            IPCThreadState::self()->getCallingUid(), opPackageName);
+
+    // Ensure that the AppOp is allowed
+    //
+    // This check is also required to ensure that the user hasn't revoked the necessary permissions
+    // to access the Step Detector and Step Counter when the application targets pre-Q. Without this
+    // check, if the user revokes the pre-Q install-time GMS Core AR permission, the app would
+    // still be able to receive Step Counter and Step Detector events.
+    bool canAccess = false;
+    if (opCode >= 0 && appOpMode == AppOpsManager::MODE_ALLOWED) {
+        if (hasPermissionForSensor(sensor)) {
+            canAccess = true;
+        } else if (sensor.getType() == SENSOR_TYPE_STEP_COUNTER ||
+                   sensor.getType() == SENSOR_TYPE_STEP_DETECTOR) {
+            int targetSdkVersion = getTargetSdkVersion(opPackageName);
+            // Allow access to the sensor if the application targets pre-Q, which is before the
+            // requirement to hold the AR permission to access Step Counter and Step Detector events
+            // was introduced.
+            if (targetSdkVersion > 0 && targetSdkVersion <= __ANDROID_API_P__) {
+                canAccess = true;
+            }
+        }
+    }
+
+    if (canAccess) {
+        sAppOpsManager.noteOp(opCode, IPCThreadState::self()->getCallingUid(), opPackageName);
+    } else {
+        ALOGE("%s a sensor (%s) without holding its required permission: %s",
+                operation, sensor.getName().string(), sensor.getRequiredPermission().string());
+    }
+
+    return canAccess;
+}
+
+bool SensorService::hasPermissionForSensor(const Sensor& sensor) {
     bool hasPermission = false;
+    const String8& requiredPermission = sensor.getRequiredPermission();
 
     // Runtime permissions can't use the cache as they may change.
     if (sensor.isRequiredPermissionRuntime()) {
@@ -1678,25 +1730,31 @@
     } else {
         hasPermission = PermissionCache::checkCallingPermission(String16(requiredPermission));
     }
+    return hasPermission;
+}
 
-    if (!hasPermission) {
-        ALOGE("%s a sensor (%s) without holding its required permission: %s",
-                operation, sensor.getName().string(), sensor.getRequiredPermission().string());
-        return false;
-    }
-
-    const int32_t opCode = sensor.getRequiredAppOp();
-    if (opCode >= 0) {
-        AppOpsManager appOps;
-        if (appOps.noteOp(opCode, IPCThreadState::self()->getCallingUid(), opPackageName)
-                        != AppOpsManager::MODE_ALLOWED) {
-            ALOGE("%s a sensor (%s) without enabled required app op: %d",
-                    operation, sensor.getName().string(), opCode);
-            return false;
+int SensorService::getTargetSdkVersion(const String16& opPackageName) {
+    Mutex::Autolock packageLock(sPackageTargetVersionLock);
+    int targetSdkVersion = -1;
+    auto entry = sPackageTargetVersion.find(opPackageName);
+    if (entry != sPackageTargetVersion.end()) {
+        targetSdkVersion = entry->second;
+    } else {
+        sp<IBinder> binder = defaultServiceManager()->getService(String16("package_native"));
+        if (binder != nullptr) {
+            sp<content::pm::IPackageManagerNative> packageManager =
+                    interface_cast<content::pm::IPackageManagerNative>(binder);
+            if (packageManager != nullptr) {
+                binder::Status status = packageManager->getTargetSdkVersionForPackage(
+                        opPackageName, &targetSdkVersion);
+                if (!status.isOk()) {
+                    targetSdkVersion = -1;
+                }
+            }
         }
+        sPackageTargetVersion[opPackageName] = targetSdkVersion;
     }
-
-    return true;
+    return targetSdkVersion;
 }
 
 void SensorService::checkWakeLockState() {
diff --git a/services/sensorservice/SensorService.h b/services/sensorservice/SensorService.h
index 5076967..e6ec96d 100644
--- a/services/sensorservice/SensorService.h
+++ b/services/sensorservice/SensorService.h
@@ -20,6 +20,7 @@
 #include "SensorList.h"
 #include "RecentEventLogger.h"
 
+#include <binder/AppOpsManager.h>
 #include <binder/BinderService.h>
 #include <binder/IUidObserver.h>
 #include <cutils/compiler.h>
@@ -243,6 +244,8 @@
             sensors_event_t const* buffer, const int count);
     static bool canAccessSensor(const Sensor& sensor, const char* operation,
             const String16& opPackageName);
+    static bool hasPermissionForSensor(const Sensor& sensor);
+    static int getTargetSdkVersion(const String16& opPackageName);
     // SensorService acquires a partial wakelock for delivering events from wake up sensors. This
     // method checks whether all the events from these wake up sensors have been delivered to the
     // corresponding applications, if yes the wakelock is released.
@@ -343,6 +346,10 @@
 
     sp<UidPolicy> mUidPolicy;
     sp<SensorPrivacyPolicy> mSensorPrivacyPolicy;
+
+    static AppOpsManager sAppOpsManager;
+    static std::map<String16, int> sPackageTargetVersion;
+    static Mutex sPackageTargetVersionLock;
 };
 
 } // namespace android
diff --git a/services/surfaceflinger/BufferLayer.cpp b/services/surfaceflinger/BufferLayer.cpp
index 4ea587d..06caf1e 100644
--- a/services/surfaceflinger/BufferLayer.cpp
+++ b/services/surfaceflinger/BufferLayer.cpp
@@ -534,11 +534,13 @@
 
 // transaction
 void BufferLayer::notifyAvailableFrames() {
-    auto headFrameNumber = getHeadFrameNumber();
-    bool headFenceSignaled = fenceHasSignaled();
+    const auto headFrameNumber = getHeadFrameNumber();
+    const bool headFenceSignaled = fenceHasSignaled();
+    const bool presentTimeIsCurrent = framePresentTimeIsCurrent();
     Mutex::Autolock lock(mLocalSyncPointMutex);
     for (auto& point : mLocalSyncPoints) {
-        if (headFrameNumber >= point->getFrameNumber() && headFenceSignaled) {
+        if (headFrameNumber >= point->getFrameNumber() && headFenceSignaled &&
+            presentTimeIsCurrent) {
             point->setFrameAvailable();
         }
     }
diff --git a/services/surfaceflinger/BufferLayer.h b/services/surfaceflinger/BufferLayer.h
index dc103cb..b679380 100644
--- a/services/surfaceflinger/BufferLayer.h
+++ b/services/surfaceflinger/BufferLayer.h
@@ -114,6 +114,7 @@
     // -----------------------------------------------------------------------
 private:
     virtual bool fenceHasSignaled() const = 0;
+    virtual bool framePresentTimeIsCurrent() const = 0;
 
     virtual nsecs_t getDesiredPresentTime() = 0;
     virtual std::shared_ptr<FenceTime> getCurrentFenceTime() const = 0;
diff --git a/services/surfaceflinger/BufferLayerConsumer.cpp b/services/surfaceflinger/BufferLayerConsumer.cpp
index fc98dc8..6709fb4 100644
--- a/services/surfaceflinger/BufferLayerConsumer.cpp
+++ b/services/surfaceflinger/BufferLayerConsumer.cpp
@@ -478,20 +478,15 @@
     }
 }
 
-void BufferLayerConsumer::onBufferAllocated(const BufferItem& item) {
-    if (item.mGraphicBuffer != nullptr) {
-        std::shared_ptr<Image> image = std::make_shared<Image>(item.mGraphicBuffer, mRE);
-        std::shared_ptr<Image> oldImage;
-        {
-            std::lock_guard<std::mutex> lock(mImagesMutex);
-            oldImage = mImages[item.mSlot];
-            if (oldImage == nullptr || oldImage->graphicBuffer() == nullptr ||
-                oldImage->graphicBuffer()->getId() != item.mGraphicBuffer->getId()) {
-                mImages[item.mSlot] = std::make_shared<Image>(item.mGraphicBuffer, mRE);
-            }
-            image = mImages[item.mSlot];
+void BufferLayerConsumer::onBufferAvailable(const BufferItem& item) {
+    if (item.mGraphicBuffer != nullptr && item.mSlot != BufferQueue::INVALID_BUFFER_SLOT) {
+        std::lock_guard<std::mutex> lock(mImagesMutex);
+        const std::shared_ptr<Image>& oldImage = mImages[item.mSlot];
+        if (oldImage == nullptr || oldImage->graphicBuffer() == nullptr ||
+            oldImage->graphicBuffer()->getId() != item.mGraphicBuffer->getId()) {
+            mImages[item.mSlot] = std::make_shared<Image>(item.mGraphicBuffer, mRE);
+            mRE.cacheExternalTextureBuffer(item.mGraphicBuffer);
         }
-        mRE.cacheExternalTextureBuffer(image->graphicBuffer());
     }
 }
 
@@ -533,5 +528,4 @@
         mRE.unbindExternalTextureBuffer(mGraphicBuffer->getId());
     }
 }
-
 }; // namespace android
diff --git a/services/surfaceflinger/BufferLayerConsumer.h b/services/surfaceflinger/BufferLayerConsumer.h
index 0f0655d..e3f6100 100644
--- a/services/surfaceflinger/BufferLayerConsumer.h
+++ b/services/surfaceflinger/BufferLayerConsumer.h
@@ -176,6 +176,7 @@
     // setConsumerUsageBits overrides the ConsumerBase method to OR
     // DEFAULT_USAGE_FLAGS to usage.
     status_t setConsumerUsageBits(uint64_t usage);
+    void onBufferAvailable(const BufferItem& item) EXCLUDES(mImagesMutex);
 
 protected:
     // abandonLocked overrides the ConsumerBase method to clear
@@ -241,7 +242,6 @@
 
     // IConsumerListener interface
     void onDisconnect() override;
-    void onBufferAllocated(const BufferItem& item) override EXCLUDES(mImagesMutex);
     void onSidebandStreamChanged() override;
     void addAndGetFrameTimestamps(const NewFrameEventsEntry* newTimestamps,
                                   FrameEventHistoryDelta* outDelta) override;
diff --git a/services/surfaceflinger/BufferQueueLayer.cpp b/services/surfaceflinger/BufferQueueLayer.cpp
index ff5f271..3d51ec3 100644
--- a/services/surfaceflinger/BufferQueueLayer.cpp
+++ b/services/surfaceflinger/BufferQueueLayer.cpp
@@ -14,11 +14,15 @@
  * limitations under the License.
  */
 
+#undef LOG_TAG
+#define LOG_TAG "BufferQueueLayer"
+#define ATRACE_TAG ATRACE_TAG_GRAPHICS
 #include <compositionengine/Display.h>
 #include <compositionengine/Layer.h>
 #include <compositionengine/OutputLayer.h>
 #include <compositionengine/impl/LayerCompositionState.h>
 #include <compositionengine/impl/OutputLayerCompositionState.h>
+#include <gui/BufferQueueConsumer.h>
 #include <system/window.h>
 
 #include "BufferQueueLayer.h"
@@ -133,6 +137,15 @@
     return mQueueItems[0].mFenceTime->getSignalTime() != Fence::SIGNAL_TIME_PENDING;
 }
 
+bool BufferQueueLayer::framePresentTimeIsCurrent() const {
+    if (!hasFrameUpdate() || isRemovedFromCurrentState()) {
+        return true;
+    }
+
+    Mutex::Autolock lock(mQueueItemLock);
+    return mQueueItems[0].mTimestamp <= mFlinger->mScheduler->expectedPresentTime();
+}
+
 nsecs_t BufferQueueLayer::getDesiredPresentTime() {
     return mConsumer->getTimestamp();
 }
@@ -185,7 +198,37 @@
 
 uint64_t BufferQueueLayer::getFrameNumber() const {
     Mutex::Autolock lock(mQueueItemLock);
-    return mQueueItems[0].mFrameNumber;
+    uint64_t frameNumber = mQueueItems[0].mFrameNumber;
+
+    // The head of the queue will be dropped if there are signaled and timely frames behind it
+    nsecs_t expectedPresentTime = mFlinger->mScheduler->expectedPresentTime();
+
+    if (isRemovedFromCurrentState()) {
+        expectedPresentTime = 0;
+    }
+
+    for (int i = 1; i < mQueueItems.size(); i++) {
+        const bool fenceSignaled =
+                mQueueItems[i].mFenceTime->getSignalTime() != Fence::SIGNAL_TIME_PENDING;
+        if (!fenceSignaled) {
+            break;
+        }
+
+        // We don't drop frames without explicit timestamps
+        if (mQueueItems[i].mIsAutoTimestamp) {
+            break;
+        }
+
+        const nsecs_t desiredPresent = mQueueItems[i].mTimestamp;
+        if (desiredPresent < expectedPresentTime - BufferQueueConsumer::MAX_REASONABLE_NSEC ||
+            desiredPresent > expectedPresentTime) {
+            break;
+        }
+
+        frameNumber = mQueueItems[i].mFrameNumber;
+    }
+
+    return frameNumber;
 }
 
 bool BufferQueueLayer::getAutoRefresh() const {
@@ -395,6 +438,7 @@
 }
 
 void BufferQueueLayer::onFrameAvailable(const BufferItem& item) {
+    ATRACE_CALL();
     // Add this buffer from our internal queue tracker
     { // Autolock scope
         if (mFlinger->mUseSmart90ForVideo) {
@@ -435,9 +479,11 @@
     } else {
         mFlinger->signalLayerUpdate();
     }
+    mConsumer->onBufferAvailable(item);
 }
 
 void BufferQueueLayer::onFrameReplaced(const BufferItem& item) {
+    ATRACE_CALL();
     { // Autolock scope
         Mutex::Autolock lock(mQueueItemLock);
 
@@ -459,6 +505,7 @@
         mLastFrameNumberReceived = item.mFrameNumber;
         mQueueItemCondition.broadcast();
     }
+    mConsumer->onBufferAvailable(item);
 }
 
 void BufferQueueLayer::onSidebandStreamChanged() {
diff --git a/services/surfaceflinger/BufferQueueLayer.h b/services/surfaceflinger/BufferQueueLayer.h
index a2aad17..7def33a 100644
--- a/services/surfaceflinger/BufferQueueLayer.h
+++ b/services/surfaceflinger/BufferQueueLayer.h
@@ -61,6 +61,7 @@
     // -----------------------------------------------------------------------
 public:
     bool fenceHasSignaled() const override;
+    bool framePresentTimeIsCurrent() const override;
 
 private:
     nsecs_t getDesiredPresentTime() override;
diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp
index 6ef4518..a740afb 100644
--- a/services/surfaceflinger/BufferStateLayer.cpp
+++ b/services/surfaceflinger/BufferStateLayer.cpp
@@ -374,6 +374,14 @@
     return getDrawingState().acquireFence->getStatus() == Fence::Status::Signaled;
 }
 
+bool BufferStateLayer::framePresentTimeIsCurrent() const {
+    if (!hasFrameUpdate() || isRemovedFromCurrentState()) {
+        return true;
+    }
+
+    return mDesiredPresentTime <= mFlinger->mScheduler->expectedPresentTime();
+}
+
 nsecs_t BufferStateLayer::getDesiredPresentTime() {
     return mDesiredPresentTime;
 }
diff --git a/services/surfaceflinger/BufferStateLayer.h b/services/surfaceflinger/BufferStateLayer.h
index 13186dd..4e2bc45 100644
--- a/services/surfaceflinger/BufferStateLayer.h
+++ b/services/surfaceflinger/BufferStateLayer.h
@@ -101,6 +101,7 @@
     // Interface implementation for BufferLayer
     // -----------------------------------------------------------------------
     bool fenceHasSignaled() const override;
+    bool framePresentTimeIsCurrent() const override;
 
 private:
     nsecs_t getDesiredPresentTime() override;
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/RenderSurface.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/RenderSurface.h
index e69b99f..e21128c 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/RenderSurface.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/RenderSurface.h
@@ -50,6 +50,9 @@
     // Returns the bounds of the surface
     virtual const ui::Size& getSize() const = 0;
 
+    // Returns whether the surface is protected.
+    virtual bool isProtected() const = 0;
+
     // Gets the latest fence to pass to the HWC to signal that the surface
     // buffer is done rendering
     virtual const sp<Fence>& getClientTargetAcquireFence() const = 0;
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/RenderSurface.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/RenderSurface.h
index 3c79084..0f57315 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/RenderSurface.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/RenderSurface.h
@@ -45,6 +45,7 @@
     bool isValid() const override;
     void initialize() override;
     const ui::Size& getSize() const override;
+    bool isProtected() const override { return mProtected; }
 
     const sp<Fence>& getClientTargetAcquireFence() const override;
     void setBufferDataspace(ui::Dataspace) override;
@@ -78,6 +79,7 @@
     sp<GraphicBuffer> mGraphicBuffer;
     const sp<DisplaySurface> mDisplaySurface;
     ui::Size mSize;
+    bool mProtected{false};
     std::uint32_t mPageFlipCount{0};
 };
 
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/RenderSurface.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/RenderSurface.h
index 1562f58..ca2299a 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/RenderSurface.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/RenderSurface.h
@@ -31,6 +31,7 @@
     MOCK_CONST_METHOD0(isValid, bool());
     MOCK_METHOD0(initialize, void());
     MOCK_CONST_METHOD0(getSize, const ui::Size&());
+    MOCK_CONST_METHOD0(isProtected, bool());
     MOCK_CONST_METHOD0(getClientTargetAcquireFence, const sp<Fence>&());
     MOCK_METHOD1(setDisplaySize, void(const ui::Size&));
     MOCK_METHOD1(setProtected, void(bool));
diff --git a/services/surfaceflinger/CompositionEngine/src/Output.cpp b/services/surfaceflinger/CompositionEngine/src/Output.cpp
index 2893031..01b5781 100644
--- a/services/surfaceflinger/CompositionEngine/src/Output.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/Output.cpp
@@ -89,14 +89,14 @@
 }
 
 void Output::setColorTransform(const mat4& transform) {
+    if (mState.colorTransformMat == transform) {
+        return;
+    }
+
     const bool isIdentity = (transform == mat4());
     const auto newColorTransform =
             isIdentity ? HAL_COLOR_TRANSFORM_IDENTITY : HAL_COLOR_TRANSFORM_ARBITRARY_MATRIX;
 
-    if (mState.colorTransform == newColorTransform) {
-        return;
-    }
-
     mState.colorTransform = newColorTransform;
     mState.colorTransformMat = transform;
 
diff --git a/services/surfaceflinger/CompositionEngine/src/RenderSurface.cpp b/services/surfaceflinger/CompositionEngine/src/RenderSurface.cpp
index b5a6678..3fcd9d1 100644
--- a/services/surfaceflinger/CompositionEngine/src/RenderSurface.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/RenderSurface.cpp
@@ -101,6 +101,9 @@
     }
     const int status = native_window_set_usage(mNativeWindow.get(), usageFlags);
     ALOGE_IF(status != NO_ERROR, "Unable to set BQ usage bits for protected content: %d", status);
+    if (status == NO_ERROR) {
+        mProtected = useProtected;
+    }
 }
 
 status_t RenderSurface::beginFrame(bool mustRecompose) {
diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
index a84af3a..fee0c11 100644
--- a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
@@ -172,16 +172,29 @@
     mOutput.setColorTransform(identity);
 
     EXPECT_EQ(HAL_COLOR_TRANSFORM_IDENTITY, mOutput.getState().colorTransform);
+    EXPECT_EQ(identity, mOutput.getState().colorTransformMat);
 
     // Since identity is the default, the dirty region should be unchanged (empty)
     EXPECT_THAT(mOutput.getState().dirtyRegion, RegionEq(Region()));
 
     // Non-identity matrix sets a non-identity state value
-    const mat4 nonIdentity = mat4() * 2;
+    const mat4 nonIdentityHalf = mat4() * 0.5;
 
-    mOutput.setColorTransform(nonIdentity);
+    mOutput.setColorTransform(nonIdentityHalf);
 
     EXPECT_EQ(HAL_COLOR_TRANSFORM_ARBITRARY_MATRIX, mOutput.getState().colorTransform);
+    EXPECT_EQ(nonIdentityHalf, mOutput.getState().colorTransformMat);
+
+    // Since this is a state change, the entire output should now be dirty.
+    EXPECT_THAT(mOutput.getState().dirtyRegion, RegionEq(Region(kDefaultDisplaySize)));
+
+    // Non-identity matrix sets a non-identity state value
+    const mat4 nonIdentityQuarter = mat4() * 0.25;
+
+    mOutput.setColorTransform(nonIdentityQuarter);
+
+    EXPECT_EQ(HAL_COLOR_TRANSFORM_ARBITRARY_MATRIX, mOutput.getState().colorTransform);
+    EXPECT_EQ(nonIdentityQuarter, mOutput.getState().colorTransformMat);
 
     // Since this is a state change, the entire output should now be dirty.
     EXPECT_THAT(mOutput.getState().dirtyRegion, RegionEq(Region(kDefaultDisplaySize)));
diff --git a/services/surfaceflinger/CompositionEngine/tests/RenderSurfaceTest.cpp b/services/surfaceflinger/CompositionEngine/tests/RenderSurfaceTest.cpp
index 9960478..f75a4dc 100644
--- a/services/surfaceflinger/CompositionEngine/tests/RenderSurfaceTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/RenderSurfaceTest.cpp
@@ -143,16 +143,40 @@
  */
 
 TEST_F(RenderSurfaceTest, setProtectedTrueEnablesProtection) {
+    EXPECT_FALSE(mSurface.isProtected());
     EXPECT_CALL(*mNativeWindow, setUsage(GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_PROTECTED))
             .WillOnce(Return(NO_ERROR));
 
     mSurface.setProtected(true);
+    EXPECT_TRUE(mSurface.isProtected());
 }
 
 TEST_F(RenderSurfaceTest, setProtectedFalseDisablesProtection) {
+    EXPECT_FALSE(mSurface.isProtected());
     EXPECT_CALL(*mNativeWindow, setUsage(GRALLOC_USAGE_HW_RENDER)).WillOnce(Return(NO_ERROR));
 
     mSurface.setProtected(false);
+    EXPECT_FALSE(mSurface.isProtected());
+}
+
+TEST_F(RenderSurfaceTest, setProtectedEnableAndDisable) {
+    EXPECT_FALSE(mSurface.isProtected());
+    EXPECT_CALL(*mNativeWindow, setUsage(GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_PROTECTED))
+            .WillOnce(Return(NO_ERROR));
+    EXPECT_CALL(*mNativeWindow, setUsage(GRALLOC_USAGE_HW_RENDER)).WillOnce(Return(NO_ERROR));
+
+    mSurface.setProtected(true);
+    EXPECT_TRUE(mSurface.isProtected());
+    mSurface.setProtected(false);
+    EXPECT_FALSE(mSurface.isProtected());
+}
+
+TEST_F(RenderSurfaceTest, setProtectedEnableWithError) {
+    EXPECT_FALSE(mSurface.isProtected());
+    EXPECT_CALL(*mNativeWindow, setUsage(GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_PROTECTED))
+            .WillOnce(Return(INVALID_OPERATION));
+    mSurface.setProtected(true);
+    EXPECT_FALSE(mSurface.isProtected());
 }
 
 /* ------------------------------------------------------------------------
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 46ca0b6..cbe8b29 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -130,7 +130,7 @@
     }
 
     mFrameTracker.logAndResetStats(mName);
-    mFlinger->onLayerDestroyed();
+    mFlinger->onLayerDestroyed(this);
 }
 
 // ---------------------------------------------------------------------------
diff --git a/services/surfaceflinger/RefreshRateOverlay.cpp b/services/surfaceflinger/RefreshRateOverlay.cpp
index fcde8da..1e5c25f 100644
--- a/services/surfaceflinger/RefreshRateOverlay.cpp
+++ b/services/surfaceflinger/RefreshRateOverlay.cpp
@@ -38,7 +38,7 @@
     }
 
     mLayer = mClient->getLayerUser(mIBinder);
-    mLayer->setCrop_legacy(Rect(0, 0, 200, 100), true);
+    mLayer->setCrop_legacy(Rect(50, 70, 200, 100), true);
     mLayer->setLayer(INT32_MAX - 2);
 
     return true;
diff --git a/services/surfaceflinger/RegionSamplingThread.cpp b/services/surfaceflinger/RegionSamplingThread.cpp
index 252ff0d..0d14267 100644
--- a/services/surfaceflinger/RegionSamplingThread.cpp
+++ b/services/surfaceflinger/RegionSamplingThread.cpp
@@ -377,10 +377,15 @@
         mFlinger.traverseLayersInDisplay(device, filterVisitor);
     };
 
-    const uint32_t usage = GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_HW_RENDER;
-    sp<GraphicBuffer> buffer =
-            new GraphicBuffer(sampledArea.getWidth(), sampledArea.getHeight(),
-                              PIXEL_FORMAT_RGBA_8888, 1, usage, "RegionSamplingThread");
+    sp<GraphicBuffer> buffer = nullptr;
+    if (mCachedBuffer && mCachedBuffer->getWidth() == sampledArea.getWidth() &&
+        mCachedBuffer->getHeight() == sampledArea.getHeight()) {
+        buffer = mCachedBuffer;
+    } else {
+        const uint32_t usage = GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_HW_RENDER;
+        buffer = new GraphicBuffer(sampledArea.getWidth(), sampledArea.getHeight(),
+                                   PIXEL_FORMAT_RGBA_8888, 1, usage, "RegionSamplingThread");
+    }
 
     // When calling into SF, we post a message into the SF message queue (so the
     // screen capture runs on the main thread). This message blocks until the
@@ -415,6 +420,12 @@
     for (size_t d = 0; d < activeDescriptors.size(); ++d) {
         activeDescriptors[d].listener->onSampleCollected(lumas[d]);
     }
+
+    // Extend the lifetime of mCachedBuffer from the previous frame to here to ensure that:
+    // 1) The region sampling thread is the last owner of the buffer, and the freeing of the buffer
+    // happens in this thread, as opposed to the main thread.
+    // 2) The listener(s) receive their notifications prior to freeing the buffer.
+    mCachedBuffer = buffer;
     ATRACE_INT(lumaSamplingStepTag, static_cast<int>(samplingStep::noWorkNeeded));
 }
 
diff --git a/services/surfaceflinger/RegionSamplingThread.h b/services/surfaceflinger/RegionSamplingThread.h
index 9796429..72b2042 100644
--- a/services/surfaceflinger/RegionSamplingThread.h
+++ b/services/surfaceflinger/RegionSamplingThread.h
@@ -24,13 +24,13 @@
 
 #include <android-base/thread_annotations.h>
 #include <binder/IBinder.h>
+#include <ui/GraphicBuffer.h>
 #include <ui/Rect.h>
 #include <utils/StrongPointer.h>
 #include "Scheduler/IdleTimer.h"
 
 namespace android {
 
-class GraphicBuffer;
 class IRegionSamplingListener;
 class Layer;
 class Scheduler;
@@ -121,6 +121,8 @@
     std::unordered_map<wp<IBinder>, Descriptor, WpHash> mDescriptors GUARDED_BY(mMutex);
     std::chrono::nanoseconds lastSampleTime GUARDED_BY(mMutex);
     bool mDiscardedFrames GUARDED_BY(mMutex) = false;
+
+    sp<GraphicBuffer> mCachedBuffer GUARDED_BY(mMutex) = nullptr;
 };
 
 } // namespace android
diff --git a/services/surfaceflinger/Scheduler/DispSync.cpp b/services/surfaceflinger/Scheduler/DispSync.cpp
index 871f556..abf7b71 100644
--- a/services/surfaceflinger/Scheduler/DispSync.cpp
+++ b/services/surfaceflinger/Scheduler/DispSync.cpp
@@ -210,17 +210,14 @@
             const nsecs_t baseTime = now - mReferenceTime;
             const nsecs_t numPeriodsSinceReference = baseTime / mPeriod;
             const nsecs_t predictedReference = mReferenceTime + numPeriodsSinceReference * mPeriod;
-            listener.mLastEventTime = predictedReference + mPhase + listener.mPhase;
-            // If we're very close in time to the predicted last event time,
-            // and we're not very close to the next predicted last event time
-            // then we need to back up the last event time so that we can
-            // attempt to fire an event immediately.
-            //
-            // Otherwise, keep the last event time that we predicted so that
-            // we don't wake up early.
-            if (isShorterThanPeriod(now - listener.mLastEventTime) &&
-                !isShorterThanPeriod(listener.mLastEventTime + mPeriod - now)) {
-                listener.mLastEventTime -= mPeriod;
+            const nsecs_t phaseCorrection = mPhase + listener.mPhase;
+            const nsecs_t predictedLastEventTime = predictedReference + phaseCorrection;
+            if (predictedLastEventTime >= now) {
+                // Make sure that the last event time does not exceed the current time.
+                // If it would, then back the last event time by a period.
+                listener.mLastEventTime = predictedLastEventTime - mPeriod;
+            } else {
+                listener.mLastEventTime = predictedLastEventTime;
             }
         } else {
             listener.mLastEventTime = now + mPhase - mWakeupLatency;
@@ -316,7 +313,7 @@
 
     // Sanity check that the duration is close enough in length to a period without
     // falling into double-rate vsyncs.
-    bool isShorterThanPeriod(nsecs_t duration) {
+    bool isCloseToPeriod(nsecs_t duration) {
         // Ratio of 3/5 is arbitrary, but it must be greater than 1/2.
         return duration < (3 * mPeriod) / 5;
     }
@@ -332,7 +329,7 @@
             nsecs_t t = computeListenerNextEventTimeLocked(eventListener, onePeriodAgo);
 
             if (t < now) {
-                if (isShorterThanPeriod(now - eventListener.mLastCallbackTime)) {
+                if (isCloseToPeriod(now - eventListener.mLastCallbackTime)) {
                     eventListener.mLastEventTime = t;
                     ALOGV("[%s] [%s] Skipping event due to model error", mName,
                           eventListener.mName);
@@ -392,7 +389,7 @@
 
         // Check that it's been slightly more than half a period since the last
         // event so that we don't accidentally fall into double-rate vsyncs
-        if (isShorterThanPeriod(t - listener.mLastEventTime)) {
+        if (isCloseToPeriod(t - listener.mLastEventTime)) {
             t += mPeriod;
             ALOGV("[%s] Modifying t -> %" PRId64, mName, ns2us(t));
         }
diff --git a/services/surfaceflinger/Scheduler/PhaseOffsets.cpp b/services/surfaceflinger/Scheduler/PhaseOffsets.cpp
index 16f6729..276bce1 100644
--- a/services/surfaceflinger/Scheduler/PhaseOffsets.cpp
+++ b/services/surfaceflinger/Scheduler/PhaseOffsets.cpp
@@ -65,6 +65,13 @@
     property_get("debug.sf.high_fps_late_sf_phase_offset_ns", value, "1000000");
     const int highFpsLateSfOffsetNs = atoi(value);
 
+    // Below defines the threshold when an offset is considered to be negative, i.e. targeting
+    // for the N+2 vsync instead of N+1. This means that:
+    // For offset < threshold, SF wake up (vsync_duration - offset) before HW vsync.
+    // For offset >= threshold, SF wake up (2 * vsync_duration - offset) before HW vsync.
+    property_get("debug.sf.phase_offset_threshold_for_next_vsync_ns", value, "-1");
+    const int phaseOffsetThresholdForNextVsyncNs = atoi(value);
+
     mDefaultRefreshRateOffsets.early = {earlySfOffsetNs != -1 ? earlySfOffsetNs
                                                               : sfVsyncPhaseOffsetNs,
                                         earlyAppOffsetNs != -1 ? earlyAppOffsetNs
@@ -84,6 +91,10 @@
                                        highFpsEarlyGlAppOffsetNs != -1 ? highFpsEarlyGlAppOffsetNs
                                                                        : highFpsLateAppOffsetNs};
     mHighRefreshRateOffsets.late = {highFpsLateSfOffsetNs, highFpsLateAppOffsetNs};
+
+    mOffsetThresholdForNextVsync = phaseOffsetThresholdForNextVsyncNs != -1
+            ? phaseOffsetThresholdForNextVsyncNs
+            : std::numeric_limits<nsecs_t>::max();
 }
 
 PhaseOffsets::Offsets PhaseOffsets::getOffsetsForRefreshRate(
diff --git a/services/surfaceflinger/Scheduler/PhaseOffsets.h b/services/surfaceflinger/Scheduler/PhaseOffsets.h
index 08747a5..dc71e6e 100644
--- a/services/surfaceflinger/Scheduler/PhaseOffsets.h
+++ b/services/surfaceflinger/Scheduler/PhaseOffsets.h
@@ -46,6 +46,7 @@
             RefreshRateConfigs::RefreshRateType refreshRateType) const = 0;
     virtual Offsets getCurrentOffsets() const = 0;
     virtual void setRefreshRateType(RefreshRateConfigs::RefreshRateType refreshRateType) = 0;
+    virtual nsecs_t getOffsetThresholdForNextVsync() const = 0;
     virtual void dump(std::string& result) const = 0;
 };
 
@@ -72,6 +73,8 @@
         mRefreshRateType = refreshRateType;
     }
 
+    nsecs_t getOffsetThresholdForNextVsync() const override { return mOffsetThresholdForNextVsync; }
+
     // Returns current offsets in human friendly format.
     void dump(std::string& result) const override;
 
@@ -84,6 +87,7 @@
 
     Offsets mDefaultRefreshRateOffsets;
     Offsets mHighRefreshRateOffsets;
+    nsecs_t mOffsetThresholdForNextVsync;
 };
 } // namespace impl
 
diff --git a/services/surfaceflinger/Scheduler/VSyncModulator.h b/services/surfaceflinger/Scheduler/VSyncModulator.h
index 1a0de08..81a7864 100644
--- a/services/surfaceflinger/Scheduler/VSyncModulator.h
+++ b/services/surfaceflinger/Scheduler/VSyncModulator.h
@@ -139,6 +139,19 @@
         }
     }
 
+    Offsets getOffsets() {
+        // Early offsets are used if we're in the middle of a refresh rate
+        // change, or if we recently begin a transaction.
+        if (mTransactionStart == Scheduler::TransactionStart::EARLY ||
+            mRemainingEarlyFrameCount > 0 || mRefreshRateChangePending) {
+            return mEarlyOffsets;
+        } else if (mLastFrameUsedRenderEngine) {
+            return mEarlyGlOffsets;
+        } else {
+            return mLateOffsets;
+        }
+    }
+
 private:
     void updateOffsets() {
         const Offsets desired = getOffsets();
@@ -167,19 +180,6 @@
         }
     }
 
-    Offsets getOffsets() {
-        // Early offsets are used if we're in the middle of a refresh rate
-        // change, or if we recently begin a transaction.
-        if (mTransactionStart == Scheduler::TransactionStart::EARLY ||
-            mRemainingEarlyFrameCount > 0 || mRefreshRateChangePending) {
-            return mEarlyOffsets;
-        } else if (mLastFrameUsedRenderEngine) {
-            return mEarlyGlOffsets;
-        } else {
-            return mLateOffsets;
-        }
-    }
-
     Offsets mLateOffsets;
     Offsets mEarlyOffsets;
     Offsets mEarlyGlOffsets;
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index d5a38e9..f8745f7 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -977,8 +977,7 @@
 bool SurfaceFlinger::performSetActiveConfig() {
     ATRACE_CALL();
     if (mCheckPendingFence) {
-        if (mPreviousPresentFence != Fence::NO_FENCE &&
-            (mPreviousPresentFence->getStatus() == Fence::Status::Unsignaled)) {
+        if (previousFrameMissed()) {
             // fence has not signaled yet. wait for the next invalidate
             mEventQueue->invalidateForHWC();
             return true;
@@ -1587,12 +1586,23 @@
     setTransactionFlags(eDisplayTransactionNeeded);
 }
 
+bool SurfaceFlinger::previousFrameMissed() NO_THREAD_SAFETY_ANALYSIS {
+    // We are storing the last 2 present fences. If sf's phase offset is to be
+    // woken up before the actual vsync but targeting the next vsync, we need to check
+    // fence N-2
+    const sp<Fence>& fence =
+            mVsyncModulator.getOffsets().sf < mPhaseOffsets->getOffsetThresholdForNextVsync()
+            ? mPreviousPresentFences[0]
+            : mPreviousPresentFences[1];
+
+    return fence != Fence::NO_FENCE && (fence->getStatus() == Fence::Status::Unsignaled);
+}
+
 void SurfaceFlinger::onMessageReceived(int32_t what) NO_THREAD_SAFETY_ANALYSIS {
     ATRACE_CALL();
     switch (what) {
         case MessageQueue::INVALIDATE: {
-            bool frameMissed = mPreviousPresentFence != Fence::NO_FENCE &&
-                    (mPreviousPresentFence->getStatus() == Fence::Status::Unsignaled);
+            bool frameMissed = previousFrameMissed();
             bool hwcFrameMissed = mHadDeviceComposition && frameMissed;
             bool gpuFrameMissed = mHadClientComposition && frameMissed;
             ATRACE_INT("FrameMissed", static_cast<int>(frameMissed));
@@ -1622,7 +1632,7 @@
             }
 
             // For now, only propagate backpressure when missing a hwc frame.
-            if (hwcFrameMissed) {
+            if (hwcFrameMissed && !gpuFrameMissed) {
                 if (mPropagateBackpressure) {
                     signalLayerUpdate();
                     break;
@@ -1982,9 +1992,11 @@
     }
 
     getBE().mDisplayTimeline.updateSignalTimes();
-    mPreviousPresentFence = displayDevice ? getHwComposer().getPresentFence(*displayDevice->getId())
-                                          : Fence::NO_FENCE;
-    auto presentFenceTime = std::make_shared<FenceTime>(mPreviousPresentFence);
+    mPreviousPresentFences[1] = mPreviousPresentFences[0];
+    mPreviousPresentFences[0] = displayDevice
+            ? getHwComposer().getPresentFence(*displayDevice->getId())
+            : Fence::NO_FENCE;
+    auto presentFenceTime = std::make_shared<FenceTime>(mPreviousPresentFences[0]);
     getBE().mDisplayTimeline.push(presentFenceTime);
 
     DisplayStatInfo stats;
@@ -2075,12 +2087,18 @@
         }
     }
 
-    mTransactionCompletedThread.addPresentFence(mPreviousPresentFence);
+    mTransactionCompletedThread.addPresentFence(mPreviousPresentFences[0]);
     mTransactionCompletedThread.sendCallbacks();
 
     if (mLumaSampling && mRegionSamplingThread) {
         mRegionSamplingThread->notifyNewContent();
     }
+
+    // Even though ATRACE_INT64 already checks if tracing is enabled, it doesn't prevent the
+    // side-effect of getTotalSize(), so we check that again here
+    if (ATRACE_ENABLED()) {
+        ATRACE_INT64("Total Buffer Size", GraphicBufferAllocator::get().getTotalSize());
+    }
 }
 
 void SurfaceFlinger::computeLayerBounds() {
@@ -2932,6 +2950,13 @@
             if (l->isRemovedFromCurrentState()) {
                 latchAndReleaseBuffer(l);
             }
+
+            // If the layer has been removed and has no parent, then it will not be reachable
+            // when traversing layers on screen. Add the layer to the offscreenLayers set to
+            // ensure we can copy its current to drawing state.
+            if (!l->getParent()) {
+                mOffscreenLayers.emplace(l.get());
+            }
         }
         mLayersPendingRemoval.clear();
     }
@@ -2945,7 +2970,17 @@
         // clear the "changed" flags in current state
         mCurrentState.colorMatrixChanged = false;
 
-        mDrawingState.traverseInZOrder([](Layer* layer) { layer->commitChildList(); });
+        mDrawingState.traverseInZOrder([&](Layer* layer) {
+            layer->commitChildList();
+
+            // If the layer can be reached when traversing mDrawingState, then the layer is no
+            // longer offscreen. Remove the layer from the offscreenLayer set.
+            if (mOffscreenLayers.count(layer)) {
+                mOffscreenLayers.erase(layer);
+            }
+        });
+
+        commitOffscreenLayers();
     });
 
     mTransactionPending = false;
@@ -2973,6 +3008,18 @@
     }
 }
 
+void SurfaceFlinger::commitOffscreenLayers() {
+    for (Layer* offscreenLayer : mOffscreenLayers) {
+        offscreenLayer->traverseInZOrder(LayerVector::StateSet::Drawing, [](Layer* layer) {
+            uint32_t trFlags = layer->getTransactionFlags(eTransactionNeeded);
+            if (!trFlags) return;
+
+            layer->doTransaction(0);
+            layer->commitChildList();
+        });
+    }
+}
+
 void SurfaceFlinger::computeVisibleRegions(const sp<const DisplayDevice>& displayDevice,
                                            Region& outDirtyRegion, Region& outOpaqueRegion) {
     ATRACE_CALL();
@@ -3254,8 +3301,11 @@
                     break;
                 }
             }
-            if (needsProtected != renderEngine.isProtected() &&
-                renderEngine.useProtectedContext(needsProtected)) {
+            if (needsProtected != renderEngine.isProtected()) {
+                renderEngine.useProtectedContext(needsProtected);
+            }
+            if (needsProtected != display->getRenderSurface()->isProtected() &&
+                needsProtected == renderEngine.isProtected()) {
                 display->getRenderSurface()->setProtected(needsProtected);
             }
         }
@@ -3473,33 +3523,41 @@
 }
 
 bool SurfaceFlinger::flushTransactionQueues() {
-    Mutex::Autolock _l(mStateLock);
+    // to prevent onHandleDestroyed from being called while the lock is held,
+    // we must keep a copy of the transactions (specifically the composer
+    // states) around outside the scope of the lock
+    std::vector<const TransactionState> transactions;
     bool flushedATransaction = false;
+    {
+        Mutex::Autolock _l(mStateLock);
 
-    auto it = mTransactionQueues.begin();
-    while (it != mTransactionQueues.end()) {
-        auto& [applyToken, transactionQueue] = *it;
+        auto it = mTransactionQueues.begin();
+        while (it != mTransactionQueues.end()) {
+            auto& [applyToken, transactionQueue] = *it;
 
-        while (!transactionQueue.empty()) {
-            const auto&
-                    [states, displays, flags, desiredPresentTime, uncacheBuffer, listenerCallbacks,
-                     postTime, privileged] = transactionQueue.front();
-            if (!transactionIsReadyToBeApplied(desiredPresentTime, states)) {
-                setTransactionFlags(eTransactionFlushNeeded);
-                break;
+            while (!transactionQueue.empty()) {
+                const auto& transaction = transactionQueue.front();
+                if (!transactionIsReadyToBeApplied(transaction.desiredPresentTime,
+                                                   transaction.states)) {
+                    setTransactionFlags(eTransactionFlushNeeded);
+                    break;
+                }
+                transactions.push_back(transaction);
+                applyTransactionState(transaction.states, transaction.displays, transaction.flags,
+                                      mPendingInputWindowCommands, transaction.desiredPresentTime,
+                                      transaction.buffer, transaction.callback,
+                                      transaction.postTime, transaction.privileged,
+                                      /*isMainThread*/ true);
+                transactionQueue.pop();
+                flushedATransaction = true;
             }
-            applyTransactionState(states, displays, flags, mPendingInputWindowCommands,
-                                  desiredPresentTime, uncacheBuffer, listenerCallbacks, postTime,
-                                  privileged, /*isMainThread*/ true);
-            transactionQueue.pop();
-            flushedATransaction = true;
-        }
 
-        if (transactionQueue.empty()) {
-            it = mTransactionQueues.erase(it);
-            mTransactionCV.broadcast();
-        } else {
-            std::next(it, 1);
+            if (transactionQueue.empty()) {
+                it = mTransactionQueues.erase(it);
+                mTransactionCV.broadcast();
+            } else {
+                std::next(it, 1);
+            }
         }
     }
     return flushedATransaction;
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 72e2ff9..5871774 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -308,7 +308,10 @@
         const sp<IGraphicBufferProducer>& bufferProducer) const;
 
     inline void onLayerCreated() { mNumLayers++; }
-    inline void onLayerDestroyed() { mNumLayers--; }
+    inline void onLayerDestroyed(Layer* layer) {
+        mNumLayers--;
+        mOffscreenLayers.erase(layer);
+    }
 
     TransactionCompletedThread& getTransactionCompletedThread() {
         return mTransactionCompletedThread;
@@ -563,6 +566,7 @@
     uint32_t setTransactionFlags(uint32_t flags, Scheduler::TransactionStart transactionStart);
     void latchAndReleaseBuffer(const sp<Layer>& layer);
     void commitTransaction() REQUIRES(mStateLock);
+    void commitOffscreenLayers();
     bool containsAnyInvalidClientState(const Vector<ComposerState>& states);
     bool transactionIsReadyToBeApplied(int64_t desiredPresentTime,
                                        const Vector<ComposerState>& states);
@@ -824,6 +828,8 @@
         return hwcDisplayId ? getHwComposer().toPhysicalDisplayId(*hwcDisplayId) : std::nullopt;
     }
 
+    bool previousFrameMissed();
+
     /*
      * Debugging & dumpsys
      */
@@ -956,7 +962,7 @@
     std::vector<sp<Layer>> mLayersWithQueuedFrames;
     // Tracks layers that need to update a display's dirty region.
     std::vector<sp<Layer>> mLayersPendingRefresh;
-    sp<Fence> mPreviousPresentFence = Fence::NO_FENCE;
+    std::array<sp<Fence>, 2> mPreviousPresentFences = {Fence::NO_FENCE, Fence::NO_FENCE};
     // True if in the previous frame at least one layer was composed via the GPU.
     bool mHadClientComposition = false;
     // True if in the previous frame at least one layer was composed via HW Composer.
@@ -1150,6 +1156,12 @@
 
     // Flag used to set override allowed display configs from backdoor
     bool mDebugDisplayConfigSetByBackdoor = false;
+
+    // A set of layers that have no parent so they are not drawn on screen.
+    // Should only be accessed by the main thread.
+    // The Layer pointer is removed from the set when the destructor is called so there shouldn't
+    // be any issues with a raw pointer referencing an invalid object.
+    std::unordered_set<Layer*> mOffscreenLayers;
 };
 
 } // namespace android
diff --git a/services/surfaceflinger/tests/unittests/FakePhaseOffsets.h b/services/surfaceflinger/tests/unittests/FakePhaseOffsets.h
index cfa8337..96121bb 100644
--- a/services/surfaceflinger/tests/unittests/FakePhaseOffsets.h
+++ b/services/surfaceflinger/tests/unittests/FakePhaseOffsets.h
@@ -49,6 +49,8 @@
     // refresh rates, to properly update the offsets.
     void setRefreshRateType(RefreshRateConfigs::RefreshRateType /*refreshRateType*/) override {}
 
+    nsecs_t getOffsetThresholdForNextVsync() const override { return FAKE_PHASE_OFFSET_NS; }
+
     // Returns current offsets in human friendly format.
     void dump(std::string& /*result*/) const override {}
 };