Merge "sf: reuse luma sampling buffer when available" into qt-dev
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/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/gui/Android.bp b/libs/gui/Android.bp
index fcbfba9..f435d98 100644
--- a/libs/gui/Android.bp
+++ b/libs/gui/Android.bp
@@ -61,6 +61,7 @@
         "DisplayEventReceiver.cpp",
         "FrameTimestamps.cpp",
         "GLConsumer.cpp",
+        "GLConsumerUtils.cpp",
         "GuiConfig.cpp",
         "HdrMetadata.cpp",
         "IDisplayEventConnection.cpp",
@@ -170,4 +171,107 @@
     ],
 }
 
+// Used by media codec services exclusively as a static lib for
+// core bufferqueuesupport only.
+cc_library_static {
+    name: "libgui_bufferqueue_static",
+    vendor_available: true,
+
+    clang: true,
+    cflags: [
+        "-Wall",
+        "-Werror",
+        "-DNO_BUFFERHUB",
+    ],
+
+    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",
+    ],
+
+    export_shared_lib_headers: [
+        "libbinder",
+        "libEGL",
+        "libnativewindow",
+        "libui",
+        "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",
+    ],
+
+    export_header_lib_headers: [
+        "libgui_headers",
+    ],
+
+    export_include_dirs: [
+        "include",
+    ],
+}
+
 subdirs = ["tests"]
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/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/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/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/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/BufferQueueLayer.cpp b/services/surfaceflinger/BufferQueueLayer.cpp
index ff5f271..5d729f5 100644
--- a/services/surfaceflinger/BufferQueueLayer.cpp
+++ b/services/surfaceflinger/BufferQueueLayer.cpp
@@ -19,6 +19,7 @@
 #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 +134,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 +195,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 {
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/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/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/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/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 304ff4b..fc0d5fc 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -2093,6 +2093,12 @@
     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() {
@@ -2944,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();
     }
@@ -2957,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;
@@ -2985,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();
@@ -3485,33 +3520,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 fc89f53..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);
@@ -1152,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