Merge "SurfaceFlinger: fix deferred transactions for buffers with timestamps" into qt-dev
diff --git a/include/audiomanager/AudioManager.h b/include/audiomanager/AudioManager.h
index 009dc52..639df7a 100644
--- a/include/audiomanager/AudioManager.h
+++ b/include/audiomanager/AudioManager.h
@@ -20,7 +20,6 @@
 namespace android {
 
 // must be kept in sync with definitions in AudioPlaybackConfiguration.java
-
 #define PLAYER_PIID_INVALID -1
 
 typedef enum {
@@ -40,6 +39,15 @@
     PLAYER_STATE_STOPPED  = 4,
 } player_state_t;
 
+// must be kept in sync with definitions in AudioManager.java
+#define RECORD_RIID_INVALID -1
+
+typedef enum {
+    RECORDER_STATE_UNKNOWN  = -1,
+    RECORDER_STATE_STARTED  = 0,
+    RECORDER_STATE_STOPPED  = 1,
+} recorder_state_t;
+
 }; // namespace android
 
 #endif // ANDROID_AUDIOMANAGER_H
diff --git a/include/audiomanager/IAudioManager.h b/include/audiomanager/IAudioManager.h
index d279bbd..d0642c6 100644
--- a/include/audiomanager/IAudioManager.h
+++ b/include/audiomanager/IAudioManager.h
@@ -36,6 +36,8 @@
         PLAYER_ATTRIBUTES                     = IBinder::FIRST_CALL_TRANSACTION + 1,
         PLAYER_EVENT                          = IBinder::FIRST_CALL_TRANSACTION + 2,
         RELEASE_PLAYER                        = IBinder::FIRST_CALL_TRANSACTION + 3,
+        TRACK_RECORDER                        = IBinder::FIRST_CALL_TRANSACTION + 4,
+        RECORDER_EVENT                        = IBinder::FIRST_CALL_TRANSACTION + 5,
     };
 
     DECLARE_META_INTERFACE(AudioManager)
@@ -48,6 +50,8 @@
                 audio_content_type_t content)= 0;
     /*oneway*/ virtual status_t playerEvent(audio_unique_id_t piid, player_state_t event) = 0;
     /*oneway*/ virtual status_t releasePlayer(audio_unique_id_t piid) = 0;
+    virtual audio_unique_id_t trackRecorder(const sp<IBinder>& recorder) = 0;
+    /*oneway*/ virtual status_t recorderEvent(audio_unique_id_t riid, recorder_state_t event) = 0;
 };
 
 // ----------------------------------------------------------------------------
diff --git a/libs/binder/IAppOpsCallback.cpp b/libs/binder/IAppOpsCallback.cpp
index 2f4dbee..aba4967 100644
--- a/libs/binder/IAppOpsCallback.cpp
+++ b/libs/binder/IAppOpsCallback.cpp
@@ -57,7 +57,8 @@
         case OP_CHANGED_TRANSACTION: {
             CHECK_INTERFACE(IAppOpsCallback, data, reply);
             int32_t op = data.readInt32();
-            String16 packageName = data.readString16();
+            String16 packageName;
+            (void)data.readString16(&packageName);
             opChanged(op, packageName);
             reply->writeNoException();
             return NO_ERROR;
diff --git a/libs/dumputils/dump_utils.cpp b/libs/dumputils/dump_utils.cpp
index 53ca7ea..26c2a0d 100644
--- a/libs/dumputils/dump_utils.cpp
+++ b/libs/dumputils/dump_utils.cpp
@@ -54,8 +54,10 @@
         "android.hardware.media.c2@1.0::IComponentStore",
         "android.hardware.media.omx@1.0::IOmx",
         "android.hardware.media.omx@1.0::IOmxStore",
+        "android.hardware.power@1.3::IPower",
         "android.hardware.power.stats@1.0::IPowerStats",
         "android.hardware.sensors@1.0::ISensors",
+        "android.hardware.thermal@2.0::IThermal",
         "android.hardware.vr@1.0::IVr",
         NULL,
 };
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/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/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index 2083a2b..437cdd7 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -1149,8 +1149,12 @@
 
     int x = dst.left;
     int y = dst.top;
-    float xScale = dst.getWidth() / static_cast<float>(source.getWidth());
-    float yScale = dst.getHeight() / static_cast<float>(source.getHeight());
+
+    float sourceWidth = source.getWidth();
+    float sourceHeight = source.getHeight();
+
+    float xScale = sourceWidth < 0 ? 1.0f : dst.getWidth() / sourceWidth;
+    float yScale = sourceHeight < 0 ? 1.0f : dst.getHeight() / sourceHeight;
     float matrix[4] = {1, 0, 0, 1};
 
     switch (transform) {
diff --git a/libs/renderengine/gl/GLESRenderEngine.cpp b/libs/renderengine/gl/GLESRenderEngine.cpp
index faf6d2a..efe4bdf 100644
--- a/libs/renderengine/gl/GLESRenderEngine.cpp
+++ b/libs/renderengine/gl/GLESRenderEngine.cpp
@@ -540,16 +540,14 @@
         return false;
     }
 
-    EGLint attribs[] = {EGL_SYNC_NATIVE_FENCE_FD_ANDROID, fenceFd, EGL_NONE};
+    // release the fd and transfer the ownership to EGLSync
+    EGLint attribs[] = {EGL_SYNC_NATIVE_FENCE_FD_ANDROID, fenceFd.release(), EGL_NONE};
     EGLSyncKHR sync = eglCreateSyncKHR(mEGLDisplay, EGL_SYNC_NATIVE_FENCE_ANDROID, attribs);
     if (sync == EGL_NO_SYNC_KHR) {
         ALOGE("failed to create EGL native fence sync: %#x", eglGetError());
         return false;
     }
 
-    // fenceFd is now owned by EGLSync
-    (void)fenceFd.release();
-
     // XXX: The spec draft is inconsistent as to whether this should return an
     // EGLint or void.  Ignore the return value for now, as it's not strictly
     // needed.
@@ -1313,7 +1311,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/renderengine/gl/ProgramCache.cpp b/libs/renderengine/gl/ProgramCache.cpp
index cd1182c..086a324 100644
--- a/libs/renderengine/gl/ProgramCache.cpp
+++ b/libs/renderengine/gl/ProgramCache.cpp
@@ -575,7 +575,9 @@
             float applyCornerRadius(vec2 cropCoords)
             {
                 vec2 position = cropCoords - cropCenter;
-                vec2 dist = abs(position) + vec2(cornerRadius) - cropCenter;
+                // Increase precision here so that a large corner radius doesn't
+                // cause floating point error
+                highp vec2 dist = abs(position) + vec2(cornerRadius) - cropCenter;
                 float plane = length(max(dist, vec2(0.0)));
                 return 1.0 - clamp(plane - cornerRadius, 0.0, 1.0);
             }
diff --git a/libs/ui/Android.bp b/libs/ui/Android.bp
index 755418e..0407d88 100644
--- a/libs/ui/Android.bp
+++ b/libs/ui/Android.bp
@@ -82,6 +82,9 @@
         "frameworks/native/include",
     ],
 
+    // Uncomment the following line to enable VALIDATE_REGIONS traces
+    //defaults: ["libui-validate-regions-defaults"],
+
     shared_libs: [
         "android.frameworks.bufferhub@1.0",
         "android.hardware.graphics.allocator@2.0",
@@ -98,7 +101,6 @@
         "libhwbinder",
         "libsync",
         "libutils",
-        "libutilscallstack",
         "liblog",
     ],
 
@@ -175,6 +177,13 @@
     ],
 }
 
+// defaults to enable VALIDATE_REGIONS traces
+cc_defaults {
+    name: "libui-validate-regions-defaults",
+    shared_libs: ["libutilscallstack"],
+    cflags: ["-DVALIDATE_REGIONS"],
+}
+
 subdirs = [
     "tests",
     "tools",
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/Region.cpp b/libs/ui/Region.cpp
index 224dc2c..55e3b99 100644
--- a/libs/ui/Region.cpp
+++ b/libs/ui/Region.cpp
@@ -22,7 +22,6 @@
 #include <android-base/stringprintf.h>
 
 #include <utils/Log.h>
-#include <utils/CallStack.h>
 
 #include <ui/Rect.h>
 #include <ui/Region.h>
@@ -31,10 +30,18 @@
 #include <private/ui/RegionHelper.h>
 
 // ----------------------------------------------------------------------------
-#define VALIDATE_REGIONS        (false)
+
+// ### VALIDATE_REGIONS ###
+// To enable VALIDATE_REGIONS traces, use the "libui-validate-regions-defaults"
+// in Android.bp. Do not #define VALIDATE_REGIONS here as it requires extra libs.
+
 #define VALIDATE_WITH_CORECG    (false)
 // ----------------------------------------------------------------------------
 
+#if defined(VALIDATE_REGIONS)
+#include <utils/CallStack.h>
+#endif
+
 #if VALIDATE_WITH_CORECG
 #include <core/SkRegion.h>
 #endif
@@ -67,7 +74,7 @@
 Region::Region(const Region& rhs)
     : mStorage(rhs.mStorage)
 {
-#if VALIDATE_REGIONS
+#if defined(VALIDATE_REGIONS)
     validate(rhs, "rhs copy-ctor");
 #endif
 }
@@ -203,7 +210,7 @@
             outputRegion.mStorage, direction_LTR);
     outputRegion.mStorage.add(r.getBounds()); // to make region valid, mStorage must end with bounds
 
-#if VALIDATE_REGIONS
+#if defined(VALIDATE_REGIONS)
     validate(outputRegion, "T-Junction free region");
 #endif
 
@@ -212,7 +219,7 @@
 
 Region& Region::operator = (const Region& rhs)
 {
-#if VALIDATE_REGIONS
+#if defined(VALIDATE_REGIONS)
     validate(*this, "this->operator=");
     validate(rhs, "rhs.operator=");
 #endif
@@ -599,10 +606,12 @@
         result = false;
         ALOGE_IF(!silent, "%s: mStorage size is 2, which is never valid", name);
     }
+#if defined(VALIDATE_REGIONS)
     if (result == false && !silent) {
         reg.dump(name);
         CallStack stack(LOG_TAG);
     }
+#endif
     return result;
 }
 
@@ -610,7 +619,7 @@
         const Region& lhs,
         const Region& rhs, int dx, int dy)
 {
-#if VALIDATE_REGIONS
+#if defined(VALIDATE_REGIONS)
     validate(lhs, "boolean_operation (before): lhs");
     validate(rhs, "boolean_operation (before): rhs");
     validate(dst, "boolean_operation (before): dst");
@@ -630,7 +639,7 @@
         operation(r);
     }
 
-#if VALIDATE_REGIONS
+#if defined(VALIDATE_REGIONS)
     validate(lhs, "boolean_operation: lhs");
     validate(rhs, "boolean_operation: rhs");
     validate(dst, "boolean_operation: dst");
@@ -728,7 +737,7 @@
         return;
     }
 
-#if VALIDATE_WITH_CORECG || VALIDATE_REGIONS
+#if VALIDATE_WITH_CORECG || defined(VALIDATE_REGIONS)
     boolean_operation(op, dst, lhs, Region(rhs), dx, dy);
 #else
     size_t lhs_count;
@@ -760,7 +769,7 @@
 void Region::translate(Region& reg, int dx, int dy)
 {
     if ((dx || dy) && !reg.isEmpty()) {
-#if VALIDATE_REGIONS
+#if defined(VALIDATE_REGIONS)
         validate(reg, "translate (before)");
 #endif
         size_t count = reg.mStorage.size();
@@ -770,7 +779,7 @@
             rects++;
             count--;
         }
-#if VALIDATE_REGIONS
+#if defined(VALIDATE_REGIONS)
         validate(reg, "translate (after)");
 #endif
     }
@@ -789,7 +798,7 @@
 }
 
 status_t Region::flatten(void* buffer, size_t size) const {
-#if VALIDATE_REGIONS
+#if defined(VALIDATE_REGIONS)
     validate(*this, "Region::flatten");
 #endif
     if (size < getFlattenedSize()) {
@@ -836,7 +845,7 @@
         result.mStorage.push_back(rect);
     }
 
-#if VALIDATE_REGIONS
+#if defined(VALIDATE_REGIONS)
     validate(result, "Region::unflatten");
 #endif
 
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 10dd8cb..95c41bc 100644
--- a/opengl/libs/EGL/Loader.cpp
+++ b/opengl/libs/EGL/Loader.cpp
@@ -69,41 +69,6 @@
     return loader;
 }
 
-/* This function is called to check whether we run inside the emulator,
- * and if this is the case whether GLES GPU emulation is supported.
- *
- * Returned values are:
- *  -1   -> not running inside the emulator
- *   0   -> running inside the emulator, but GPU emulation not supported
- *   1   -> running inside the emulator, GPU emulation is supported
- *          through the "emulation" host-side OpenGL ES implementation.
- *   2   -> running inside the emulator, GPU emulation is supported
- *          through a guest-side vendor driver's OpenGL ES implementation.
- */
-static int
-checkGlesEmulationStatus(void)
-{
-    /* We're going to check for the following kernel parameters:
-     *
-     *    qemu=1                      -> tells us that we run inside the emulator
-     *    android.qemu.gles=<number>  -> tells us the GLES GPU emulation status
-     *
-     * Note that we will return <number> if we find it. This let us support
-     * more additionnal emulation modes in the future.
-     */
-    char  prop[PROPERTY_VALUE_MAX];
-    int   result = -1;
-
-    /* First, check for qemu=1 */
-    property_get("ro.kernel.qemu",prop,"0");
-    if (atoi(prop) != 1)
-        return -1;
-
-    /* We are in the emulator, get GPU status value */
-    property_get("qemu.gles",prop,"0");
-    return atoi(prop);
-}
-
 static void* do_dlopen(const char* path, int mode) {
     ATRACE_CALL();
     return dlopen(path, mode);
@@ -208,6 +173,11 @@
     }
 }
 
+static const char* HAL_SUBNAME_KEY_PROPERTIES[2] = {
+    "ro.hardware.egl",
+    "ro.board.platform",
+};
+
 void* Loader::open(egl_connection_t* cnx)
 {
     ATRACE_CALL();
@@ -229,12 +199,30 @@
         hnd = attempt_to_load_updated_driver(cnx);
     }
     if (!hnd) {
-        // Thirdly, try to load emulation driver.
-        hnd = attempt_to_load_emulation_driver(cnx);
+        // 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.
+        // i.e.:
+        //      libGLES_${prop}.so, or:
+        //      libEGL_${prop}.so, libGLESv1_CM_${prop}.so, libGLESv2_${prop}.so
+        char prop[PROPERTY_VALUE_MAX + 1];
+        for (auto key : HAL_SUBNAME_KEY_PROPERTIES) {
+            if (property_get(key, prop, nullptr) <= 0) {
+                continue;
+            }
+            hnd = attempt_to_load_system_driver(cnx, prop);
+            if (hnd) {
+                break;
+            }
+        }
     }
+
     if (!hnd) {
-        // Finally, load system driver.
-        hnd = attempt_to_load_system_driver(cnx);
+        // Can't find graphics driver by appending system properties, now search for the exact name
+        // without any suffix of the GLES userspace driver in both locations.
+        // i.e.:
+        //      libGLES.so, or:
+        //      libEGL.so, libGLESv1_CM.so, libGLESv2.so
+        hnd = attempt_to_load_system_driver(cnx, nullptr);
     }
 
     if (!hnd) {
@@ -242,7 +230,9 @@
                                                             false, systemTime() - openTime);
     }
 
-    LOG_ALWAYS_FATAL_IF(!hnd, "couldn't find an OpenGL ES implementation");
+    LOG_ALWAYS_FATAL_IF(!hnd,
+                        "couldn't find an OpenGL ES implementation, make sure you set %s or %s",
+                        HAL_SUBNAME_KEY_PROPERTIES[0], HAL_SUBNAME_KEY_PROPERTIES[1]);
 
     cnx->libEgl   = load_wrapper(EGL_WRAPPER_DIR "/libEGL.so");
     cnx->libGles2 = load_wrapper(EGL_WRAPPER_DIR "/libGLESv2.so");
@@ -350,71 +340,11 @@
     }
 }
 
-static void* load_emulation_driver(const char* kind) {
-    const int emulationStatus = checkGlesEmulationStatus();
-
-    // Invalid emulation status, abort.
-    if (emulationStatus < 0 || emulationStatus > 2) {
-        return nullptr;
-    }
-
-    std::string absolutePath;
-    switch (emulationStatus) {
-        case 0:
-#if defined(__LP64__)
-            absolutePath = "/vendor/lib64/egl/libGLES_android.so";
-#else
-            absolutePath = "/vendor/lib/egl/libGLES_android.so";
-#endif
-            break;
-        case 1:
-            // Use host-side OpenGL through the "emulation" library
-#if defined(__LP64__)
-            absolutePath = std::string("/vendor/lib64/egl/lib") + kind + "_emulation.so";
-#else
-            absolutePath = std::string("/vendor/lib/egl/lib") + kind + "_emulation.so";
-#endif
-            break;
-        case 2:
-            // Use guest side swiftshader library
-#if defined(__LP64__)
-            absolutePath = std::string("/vendor/lib64/egl/lib") + kind + "_swiftshader.so";
-#else
-            absolutePath = std::string("/vendor/lib/egl/lib") + kind + "_swiftshader.so";
-#endif
-            break;
-      default:
-            // Not in emulator, or use other guest-side implementation
-            break;
-    }
-    if (absolutePath.empty()) {
-        // this happens often, we don't want to log an error
-        return nullptr;
-    }
-    const char* const driver_absolute_path = absolutePath.c_str();
-
-    // Try to load drivers from the 'sphal' namespace, if it exist. Fall back to
-    // the original routine when the namespace does not exist.
-    // See /system/core/rootdir/etc/ld.config.txt for the configuration of the
-    // sphal namespace.
-    void* dso = do_android_load_sphal_library(driver_absolute_path,
-                                              RTLD_NOW | RTLD_LOCAL);
-    if (dso == nullptr) {
-        const char* err = dlerror();
-        ALOGE("load_driver(%s): %s", driver_absolute_path, err ? err : "unknown");
-        return nullptr;
-    }
-    ALOGD("loaded %s", driver_absolute_path);
-    return dso;
-}
-
-static void* load_system_driver(const char* kind) {
+static void* load_system_driver(const char* kind, const char* suffix) {
     ATRACE_CALL();
     class MatchFile {
     public:
-        static std::string find(const char* kind) {
-            std::string result;
-            std::string pattern = std::string("lib") + kind;
+        static std::string find(const char* libraryName) {
             const char* const searchPaths[] = {
 #if defined(__LP64__)
                     "/vendor/lib64/egl",
@@ -425,74 +355,23 @@
 #endif
             };
 
-            // first, we search for the exact name of the GLES userspace
-            // driver in both locations.
-            // i.e.:
-            //      libGLES.so, or:
-            //      libEGL.so, libGLESv1_CM.so, libGLESv2.so
-
-            for (size_t i=0 ; i<NELEM(searchPaths) ; i++) {
-                if (find(result, pattern, searchPaths[i], true)) {
-                    return result;
-                }
-            }
-
-            // for compatibility with the old "egl.cfg" naming convention
-            // we look for files that match:
-            //      libGLES_*.so, or:
-            //      libEGL_*.so, libGLESv1_CM_*.so, libGLESv2_*.so
-
-            pattern.append("_");
-            for (size_t i=0 ; i<NELEM(searchPaths) ; i++) {
-                if (find(result, pattern, searchPaths[i], false)) {
-                    return result;
-                }
-            }
-
-            // we didn't find the driver. gah.
-            result.clear();
-            return result;
-        }
-
-    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";
+            for (auto dir : searchPaths) {
+                std::string absolutePath = dir + std::string("/") + libraryName + ".so";
                 if (!access(absolutePath.c_str(), R_OK)) {
-                    result = absolutePath;
-                    return true;
+                    return absolutePath;
                 }
-                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;
+            // Driver not found. gah.
+            return std::string();
         }
     };
 
-
-    std::string absolutePath = MatchFile::find(kind);
+    std::string libraryName = std::string("lib") + kind;
+    if (suffix) {
+        libraryName += std::string("_") + suffix;
+    }
+    std::string absolutePath = MatchFile::find(libraryName.c_str());
     if (absolutePath.empty()) {
         // this happens often, we don't want to log an error
         return nullptr;
@@ -574,7 +453,20 @@
         cnx->angleBackend = angleBackendDefault;
         if (!cnx->vendorEGL && (cnx->angleBackend == EGL_PLATFORM_ANGLE_TYPE_OPENGLES_ANGLE)) {
             // Find and load vendor libEGL for ANGLE's GL back-end to use.
-            cnx->vendorEGL = load_system_driver("EGL");
+            char prop[PROPERTY_VALUE_MAX + 1];
+            for (auto key : HAL_SUBNAME_KEY_PROPERTIES) {
+                if (property_get(key, prop, nullptr) <= 0) {
+                    continue;
+                }
+                void* dso = load_system_driver("EGL", prop);
+                if (dso) {
+                    cnx->vendorEGL = dso;
+                    break;
+                }
+            }
+            if (!cnx->vendorEGL) {
+                cnx->vendorEGL = load_system_driver("EGL", nullptr);
+            }
         }
     } else {
         ALOGV("Loaded native %s library for '%s' (instead of ANGLE)", kind,
@@ -586,11 +478,6 @@
     return so;
 }
 
-static const char* HAL_SUBNAME_KEY_PROPERTIES[2] = {
-    "ro.hardware.egl",
-    "ro.board.platform",
-};
-
 static void* load_updated_driver(const char* kind, android_namespace_t* ns) {
     ATRACE_CALL();
     const android_dlextinfo dlextinfo = {
@@ -600,12 +487,13 @@
     void* so = nullptr;
     char prop[PROPERTY_VALUE_MAX + 1];
     for (auto key : HAL_SUBNAME_KEY_PROPERTIES) {
-        if (property_get(key, prop, nullptr) > 0) {
-            std::string name = std::string("lib") + kind + "_" + prop + ".so";
-            so = do_android_dlopen_ext(name.c_str(), RTLD_LOCAL | RTLD_NOW, &dlextinfo);
-            if (so) {
-                return so;
-            }
+        if (property_get(key, prop, nullptr) <= 0) {
+            continue;
+        }
+        std::string name = std::string("lib") + kind + "_" + prop + ".so";
+        so = do_android_dlopen_ext(name.c_str(), RTLD_LOCAL | RTLD_NOW, &dlextinfo);
+        if (so) {
+            return so;
         }
     }
     return nullptr;
@@ -674,52 +562,26 @@
 #endif
 }
 
-Loader::driver_t* Loader::attempt_to_load_emulation_driver(egl_connection_t* cnx) {
+Loader::driver_t* Loader::attempt_to_load_system_driver(egl_connection_t* cnx, const char* suffix) {
     ATRACE_CALL();
     android::GraphicsEnv::getInstance().setDriverToLoad(android::GraphicsEnv::Driver::GL);
     driver_t* hnd = nullptr;
-    void* dso = load_emulation_driver("GLES");
+    void* dso = load_system_driver("GLES", suffix);
     if (dso) {
         initialize_api(dso, cnx, EGL | GLESv1_CM | GLESv2);
         hnd = new driver_t(dso);
         return hnd;
     }
-    dso = load_emulation_driver("EGL");
+    dso = load_system_driver("EGL", suffix);
     if (dso) {
         initialize_api(dso, cnx, EGL);
         hnd = new driver_t(dso);
 
-        dso = load_emulation_driver("GLESv1_CM");
+        dso = load_system_driver("GLESv1_CM", suffix);
         initialize_api(dso, cnx, GLESv1_CM);
         hnd->set(dso, GLESv1_CM);
 
-        dso = load_emulation_driver("GLESv2");
-        initialize_api(dso, cnx, GLESv2);
-        hnd->set(dso, GLESv2);
-    }
-    return hnd;
-}
-
-Loader::driver_t* Loader::attempt_to_load_system_driver(egl_connection_t* cnx) {
-    ATRACE_CALL();
-    android::GraphicsEnv::getInstance().setDriverToLoad(android::GraphicsEnv::Driver::GL);
-    driver_t* hnd = nullptr;
-    void* dso = load_system_driver("GLES");
-    if (dso) {
-        initialize_api(dso, cnx, EGL | GLESv1_CM | GLESv2);
-        hnd = new driver_t(dso);
-        return hnd;
-    }
-    dso = load_system_driver("EGL");
-    if (dso) {
-        initialize_api(dso, cnx, EGL);
-        hnd = new driver_t(dso);
-
-        dso = load_system_driver("GLESv1_CM");
-        initialize_api(dso, cnx, GLESv1_CM);
-        hnd->set(dso, GLESv1_CM);
-
-        dso = load_system_driver("GLESv2");
+        dso = load_system_driver("GLESv2", suffix);
         initialize_api(dso, cnx, GLESv2);
         hnd->set(dso, GLESv2);
     }
diff --git a/opengl/libs/EGL/Loader.h b/opengl/libs/EGL/Loader.h
index c0f1b75..f6b67ab 100644
--- a/opengl/libs/EGL/Loader.h
+++ b/opengl/libs/EGL/Loader.h
@@ -57,8 +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_emulation_driver(egl_connection_t* cnx);
-    driver_t* attempt_to_load_system_driver(egl_connection_t* cnx);
+    driver_t* attempt_to_load_system_driver(egl_connection_t* cnx, const char* suffix);
     void initialize_api(void* dso, egl_connection_t* cnx, uint32_t mask);
 
     static __attribute__((noinline))
diff --git a/services/audiomanager/IAudioManager.cpp b/services/audiomanager/IAudioManager.cpp
index b9b0706..f5d4826 100644
--- a/services/audiomanager/IAudioManager.cpp
+++ b/services/audiomanager/IAudioManager.cpp
@@ -98,6 +98,30 @@
         data.writeInt32((int32_t) piid);
         return remote()->transact(RELEASE_PLAYER, data, &reply, IBinder::FLAG_ONEWAY);
     }
+
+    virtual audio_unique_id_t trackRecorder(const sp<IBinder>& recorder) {
+        Parcel data, reply;
+        data.writeInterfaceToken(IAudioManager::getInterfaceDescriptor());
+        data.writeStrongBinder(recorder);
+        // get new RIId in reply
+        const status_t res = remote()->transact(TRACK_RECORDER, data, &reply, 0);
+        if (res != OK || reply.readExceptionCode() != 0) {
+            ALOGE("trackRecorder() failed, riid is %d", RECORD_RIID_INVALID);
+            return RECORD_RIID_INVALID;
+        } else {
+            const audio_unique_id_t riid = (audio_unique_id_t) reply.readInt32();
+            ALOGV("trackRecorder() returned riid %d", riid);
+            return riid;
+        }
+    }
+
+    virtual status_t recorderEvent(audio_unique_id_t riid, recorder_state_t event) {
+        Parcel data, reply;
+        data.writeInterfaceToken(IAudioManager::getInterfaceDescriptor());
+        data.writeInt32((int32_t) riid);
+        data.writeInt32((int32_t) event);
+        return remote()->transact(RECORDER_EVENT, data, &reply, IBinder::FLAG_ONEWAY);
+    }
 };
 
 IMPLEMENT_META_INTERFACE(AudioManager, "android.media.IAudioService");
diff --git a/services/inputflinger/InputClassifier.cpp b/services/inputflinger/InputClassifier.cpp
index b4db338..4a6efa6 100644
--- a/services/inputflinger/InputClassifier.cpp
+++ b/services/inputflinger/InputClassifier.cpp
@@ -507,19 +507,53 @@
 
 // --- MotionClassifier ---
 
-MotionClassifier::MotionClassifier(
-        sp<android::hardware::input::classifier::V1_0::IInputClassifier> service) :
-        mEvents(MAX_EVENTS), mService(service) {
+MotionClassifier::MotionClassifier(sp<android::hardware::hidl_death_recipient> deathRecipient) :
+        mDeathRecipient(deathRecipient), mEvents(MAX_EVENTS) {
     mHalThread = std::thread(&MotionClassifier::callInputClassifierHal, this);
 #if defined(__linux__)
     // Set the thread name for debugging
     pthread_setname_np(mHalThread.native_handle(), "InputClassifier");
 #endif
+}
+
+/**
+ * This function may block for some time to initialize the HAL, so it should only be called
+ * from the "InputClassifier HAL" thread.
+ */
+bool MotionClassifier::init() {
+    ensureHalThread(__func__);
+    sp<android::hardware::input::classifier::V1_0::IInputClassifier> service =
+            classifier::V1_0::IInputClassifier::getService();
+    if (!service) {
+        // Not really an error, maybe the device does not have this HAL,
+        // but somehow the feature flag is flipped
+        ALOGI("Could not obtain InputClassifier HAL");
+        return false;
+    }
+
+    sp<android::hardware::hidl_death_recipient> recipient = mDeathRecipient.promote();
+    if (recipient != nullptr) {
+        const bool linked = service->linkToDeath(recipient, 0 /* cookie */).withDefault(false);
+        if (!linked) {
+            ALOGE("Could not link MotionClassifier to the HAL death");
+            return false;
+        }
+    }
+
     // Under normal operation, we do not need to reset the HAL here. But in the case where system
     // crashed, but HAL didn't, we may be connecting to an existing HAL process that might already
     // have received events in the past. That means, that HAL could be in an inconsistent state
     // once it receives events from the newly created MotionClassifier.
     mEvents.push(ClassifierEvent::createHalResetEvent());
+
+    {
+        std::scoped_lock lock(mLock);
+        if (mService) {
+            ALOGE("MotionClassifier::%s should only be called once", __func__);
+        }
+        mService = service;
+    }
+    return true;
 }
 
 MotionClassifier::~MotionClassifier() {
@@ -530,7 +564,7 @@
 void MotionClassifier::ensureHalThread(const char* function) {
     if (DEBUG) {
         if (std::this_thread::get_id() != mHalThread.get_id()) {
-            ALOGE("Function %s should only be called from InputClassifier thread", function);
+            LOG_FATAL("Function %s should only be called from InputClassifier thread", function);
         }
     }
 }
@@ -547,6 +581,21 @@
  */
 void MotionClassifier::callInputClassifierHal() {
     ensureHalThread(__func__);
+    const bool initialized = init();
+    if (!initialized) {
+        // MotionClassifier no longer useful.
+        // Deliver death notification from a separate thread
+        // because ~MotionClassifier may be invoked, which calls mHalThread.join()
+        std::thread([deathRecipient = mDeathRecipient](){
+                sp<android::hardware::hidl_death_recipient> recipient = deathRecipient.promote();
+                if (recipient != nullptr) {
+                    recipient->serviceDied(0 /*cookie*/, nullptr);
+                }
+        }).detach();
+        return;
+    }
+    // From this point on, mService is guaranteed to be non-null.
+
     while (true) {
         ClassifierEvent event = mEvents.pop();
         bool halResponseOk = true;
@@ -666,10 +715,19 @@
     enqueueEvent(std::make_unique<NotifyDeviceResetArgs>(args));
 }
 
+const char* MotionClassifier::getServiceStatus() REQUIRES(mLock) {
+    if (!mService) {
+        return "null";
+    }
+    if (mService->ping().isOk()) {
+        return "running";
+    }
+    return "not responding";
+}
+
 void MotionClassifier::dump(std::string& dump) {
     std::scoped_lock lock(mLock);
-    std::string serviceStatus = mService->ping().isOk() ? "running" : " not responding";
-    dump += StringPrintf(INDENT2 "mService status: %s\n", serviceStatus.c_str());
+    dump += StringPrintf(INDENT2 "mService status: %s\n", getServiceStatus());
     dump += StringPrintf(INDENT2 "mEvents: %zu element(s) (max=%zu)\n",
             mEvents.size(), MAX_EVENTS);
     dump += INDENT2 "mClassifications, mLastDownTimes:\n";
@@ -700,28 +758,14 @@
 }
 
 void InputClassifier::onFirstRef() {
-    std::scoped_lock lock(mLock);
     if (!deepPressEnabled()) {
-        // If feature is not enabled, the InputClassifier will just be in passthrough
-        // mode, and will forward all events to the next InputListener, unmodified
+        // If feature is not enabled, MotionClassifier should stay null to avoid unnecessary work.
+        // When MotionClassifier is null, InputClassifier will forward all events
+        // to the next InputListener, unmodified.
         return;
     }
-
-    sp<android::hardware::input::classifier::V1_0::IInputClassifier> service =
-            classifier::V1_0::IInputClassifier::getService();
-    if (!service) {
-        // Not really an error, maybe the device does not have this HAL,
-        // but somehow the feature flag is flipped
-        ALOGI("Could not obtain InputClassifier HAL");
-        return;
-    }
-    const bool linked = service->linkToDeath(this, 0 /* cookie */).withDefault(false);
-    if (!linked) {
-        ALOGE("Could not link android::InputClassifier to the HAL death");
-        return;
-    }
-
-    mMotionClassifier = std::make_unique<MotionClassifier>(service);
+    std::scoped_lock lock(mLock);
+    mMotionClassifier = std::make_unique<MotionClassifier>(this);
 }
 
 void InputClassifier::notifyConfigurationChanged(const NotifyConfigurationChangedArgs* args) {
@@ -786,4 +830,4 @@
     dump += "\n";
 }
 
-} // namespace android
\ No newline at end of file
+} // namespace android
diff --git a/services/inputflinger/InputClassifier.h b/services/inputflinger/InputClassifier.h
index 0b1483f..47e20db 100644
--- a/services/inputflinger/InputClassifier.h
+++ b/services/inputflinger/InputClassifier.h
@@ -114,15 +114,22 @@
 class MotionClassifier final : public MotionClassifierInterface {
 public:
     /**
-     * The provided pointer to the service cannot be null.
+     * The deathRecipient will be subscribed to the HAL death. If the death recipient
+     * owns MotionClassifier and receives HAL death, it should delete its copy of it.
+     * The callback serviceDied will also be sent if the MotionClassifier itself fails
+     * to initialize. If the MotionClassifier fails to initialize, it is not useful, and
+     * should be deleted.
+     * If no death recipient is supplied, then the registration step will be skipped, so there will
+     * be no listeners registered for the HAL death. This is useful for testing
+     * MotionClassifier in isolation.
      */
-    MotionClassifier(sp<android::hardware::input::classifier::V1_0::IInputClassifier> service);
+    explicit MotionClassifier(sp<android::hardware::hidl_death_recipient> deathRecipient = nullptr);
     ~MotionClassifier();
+
     /**
      * Classifies events asynchronously; that is, it doesn't block events on a classification,
-     * but instead sends them over to the classifier HAL
-     * and after a classification is determined,
-     * it then marks the next event it sees in the stream with it.
+     * but instead sends them over to the classifier HAL and after a classification is
+     * determined, it then marks the next event it sees in the stream with it.
      *
      * Therefore, it is acceptable to have the classifications be delayed by 1-2 events
      * in a particular gesture.
@@ -134,6 +141,16 @@
     virtual void dump(std::string& dump) override;
 
 private:
+    /**
+     * Initialize MotionClassifier.
+     * Return true if initializaion is successful.
+     */
+    bool init();
+    /**
+     * Entity that will be notified of the HAL death (most likely InputClassifier).
+     */
+    wp<android::hardware::hidl_death_recipient> mDeathRecipient;
+
     // The events that need to be sent to the HAL.
     BlockingQueue<ClassifierEvent> mEvents;
     /**
@@ -148,7 +165,7 @@
     std::thread mHalThread;
     /**
      * Print an error message if the caller is not on the InputClassifier thread.
-     * Caller must supply the name of the calling function as __function__
+     * Caller must supply the name of the calling function as __func__
      */
     void ensureHalThread(const char* function);
     /**
@@ -156,9 +173,14 @@
      */
     void callInputClassifierHal();
     /**
-     * Access to the InputClassifier HAL. Can always be safely dereferenced.
+     * Access to the InputClassifier HAL. May be null if init() hasn't completed yet.
+     * When init() successfully completes, mService is guaranteed to remain non-null and to not
+     * change its value until MotionClassifier is destroyed.
+     * This variable is *not* guarded by mLock in the InputClassifier thread, because
+     * that thread knows exactly when this variable is initialized.
+     * When accessed in any other thread, mService is checked for nullness with a lock.
      */
-    const sp<android::hardware::input::classifier::V1_0::IInputClassifier> mService;
+    sp<android::hardware::input::classifier::V1_0::IInputClassifier> mService;
     std::mutex mLock;
     /**
      * Per-device input classifications. Should only be accessed using the
@@ -195,6 +217,10 @@
      * Useful for tests to ensure proper cleanup.
      */
     void requestExit();
+    /**
+     * Return string status of mService
+     */
+    const char* getServiceStatus() REQUIRES(mLock);
 };
 
 
diff --git a/services/inputflinger/tests/InputClassifier_test.cpp b/services/inputflinger/tests/InputClassifier_test.cpp
index 1651057..7cc17a2 100644
--- a/services/inputflinger/tests/InputClassifier_test.cpp
+++ b/services/inputflinger/tests/InputClassifier_test.cpp
@@ -136,11 +136,7 @@
     std::unique_ptr<MotionClassifierInterface> mMotionClassifier;
 
     virtual void SetUp() override {
-        sp<android::hardware::input::classifier::V1_0::IInputClassifier> service =
-                classifier::V1_0::IInputClassifier::getService();
-        if (service) {
-            mMotionClassifier = std::make_unique<MotionClassifier>(service);
-        }
+        mMotionClassifier = std::make_unique<MotionClassifier>();
     }
 };
 
@@ -165,9 +161,7 @@
 
     // We are not checking the return value, because we can't be making assumptions
     // about the HAL operation, since it will be highly hardware-dependent
-    if (mMotionClassifier) {
-        ASSERT_NO_FATAL_FAILURE(mMotionClassifier->classify(motionArgs));
-    }
+    ASSERT_NO_FATAL_FAILURE(mMotionClassifier->classify(motionArgs));
 }
 
 /**
@@ -183,9 +177,7 @@
 
     // We are not checking the return value, because we can't be making assumptions
     // about the HAL operation, since it will be highly hardware-dependent
-    if (mMotionClassifier) {
-        ASSERT_NO_FATAL_FAILURE(mMotionClassifier->classify(motionArgs));
-    }
+    ASSERT_NO_FATAL_FAILURE(mMotionClassifier->classify(motionArgs));
 }
 
 /**
@@ -206,18 +198,14 @@
 
     // We are not checking the return value, because we can't be making assumptions
     // about the HAL operation, since it will be highly hardware-dependent
-    if (mMotionClassifier) {
-        ASSERT_NO_FATAL_FAILURE(mMotionClassifier->classify(motionArgs));
-    }
+    ASSERT_NO_FATAL_FAILURE(mMotionClassifier->classify(motionArgs));
 }
 
 /**
  * Make sure MotionClassifier does not crash when it is reset.
  */
 TEST_F(MotionClassifierTest, Reset_DoesNotCrash) {
-    if (mMotionClassifier) {
-        ASSERT_NO_FATAL_FAILURE(mMotionClassifier->reset());
-    }
+    ASSERT_NO_FATAL_FAILURE(mMotionClassifier->reset());
 }
 
 /**
@@ -225,9 +213,7 @@
  */
 TEST_F(MotionClassifierTest, DeviceReset_DoesNotCrash) {
     NotifyDeviceResetArgs args(1/*sequenceNum*/, 2/*eventTime*/, 3/*deviceId*/);
-    if (mMotionClassifier) {
-        ASSERT_NO_FATAL_FAILURE(mMotionClassifier->reset(args));
-    }
+    ASSERT_NO_FATAL_FAILURE(mMotionClassifier->reset(args));
 }
 
 } // namespace android
diff --git a/services/sensorservice/SensorDevice.cpp b/services/sensorservice/SensorDevice.cpp
index 6570704..659329e 100644
--- a/services/sensorservice/SensorDevice.cpp
+++ b/services/sensorservice/SensorDevice.cpp
@@ -767,6 +767,10 @@
                     checkReturn(mSensors->activate(sensor_handle, 1 /* enabled */)));
             ALOGE_IF(err, "Error activating sensor %d (%s)", sensor_handle, strerror(-err));
         }
+
+        if (err == NO_ERROR) {
+            info.isActive = true;
+        }
     }
 }
 
@@ -774,7 +778,7 @@
     if (mSensors == nullptr) return;
     Mutex::Autolock _l(mLock);
     for (size_t i = 0; i< mActivationCount.size(); ++i) {
-        const Info& info = mActivationCount.valueAt(i);
+        Info& info = mActivationCount.editValueAt(i);
         // Check if this sensor has been activated previously and disable it.
         if (info.batchParams.size() > 0) {
            const int sensor_handle = mActivationCount.keyAt(i);
@@ -788,6 +792,8 @@
                mDisabledClients.add(info.batchParams.keyAt(j));
                ALOGI("added %p to mDisabledClients", info.batchParams.keyAt(j));
            }
+
+           info.isActive = false;
         }
     }
 }
diff --git a/services/sensorservice/SensorService.cpp b/services/sensorservice/SensorService.cpp
index cbdd473..0269990 100644
--- a/services/sensorservice/SensorService.cpp
+++ b/services/sensorservice/SensorService.cpp
@@ -1381,15 +1381,6 @@
             ALOGD_IF(DEBUG_CONNECTIONS, "... and it was the last connection");
             mActiveSensors.removeItemsAt(i, 1);
             mActiveVirtualSensors.erase(handle);
-
-            // If this is the last connection, then mark the RecentEventLogger as stale. This is
-            // critical for on-change events since the previous event is sent to a client if the
-            // sensor is already active. If two clients request the sensor at the same time, one
-            // of the clients would receive a stale event.
-            auto logger = mRecentEvent.find(handle);
-            if (logger != mRecentEvent.end()) {
-                logger->second->setLastEventStale();
-            }
             delete rec;
             size--;
         } else {
@@ -1444,6 +1435,20 @@
         if (sensor->isVirtual()) {
             mActiveVirtualSensors.emplace(handle);
         }
+
+        // There was no SensorRecord for this sensor which means it was previously disabled. Mark
+        // the recent event as stale to ensure that the previous event is not sent to a client. This
+        // ensures on-change events that were generated during a previous sensor activation are not
+        // erroneously sent to newly connected clients, especially if a second client registers for
+        // an on-change sensor before the first client receives the updated event. Once an updated
+        // event is received, the recent events will be marked as current, and any new clients will
+        // immediately receive the most recent event.
+        if (sensor->getSensor().getReportingMode() == AREPORTING_MODE_ON_CHANGE) {
+            auto logger = mRecentEvent.find(handle);
+            if (logger != mRecentEvent.end()) {
+                logger->second->setLastEventStale();
+            }
+        }
     } else {
         if (rec->addConnection(connection)) {
             // this sensor is already activated, but we are adding a connection that uses it.
diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp
index 30848d6..a740afb 100644
--- a/services/surfaceflinger/BufferStateLayer.cpp
+++ b/services/surfaceflinger/BufferStateLayer.cpp
@@ -433,7 +433,7 @@
 }
 
 Region BufferStateLayer::getDrawingSurfaceDamage() const {
-    return Region::INVALID_REGION;
+    return getDrawingState().surfaceDamageRegion;
 }
 
 const HdrMetadata& BufferStateLayer::getDrawingHdrMetadata() const {
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/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 1d54cb2..2ca5c02 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -977,10 +977,9 @@
 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
-            repaintEverythingForHWC();
+            mEventQueue->invalidateForHWC();
             return true;
         }
 
@@ -1031,7 +1030,7 @@
 
     // we need to submit an empty frame to HWC to start the process
     mCheckPendingFence = true;
-
+    mEventQueue->invalidateForHWC();
     return false;
 }
 
@@ -1447,10 +1446,6 @@
         return;
     }
 
-    if (desiredConfigId == display->getActiveConfig()) {
-        return;
-    }
-
     setDesiredActiveConfig({refreshRate, desiredConfigId, event});
 }
 
@@ -1591,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));
@@ -1986,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;
@@ -2079,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() {
@@ -2936,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();
     }
@@ -2949,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;
@@ -2977,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();
@@ -3499,7 +3542,12 @@
             flushedATransaction = true;
         }
 
-        it = (transactionQueue.empty()) ? mTransactionQueues.erase(it) : std::next(it, 1);
+        if (transactionQueue.empty()) {
+            it = mTransactionQueues.erase(it);
+            mTransactionCV.broadcast();
+        } else {
+            std::next(it, 1);
+        }
     }
     return flushedATransaction;
 }
@@ -3572,7 +3620,22 @@
     }
 
     // If its TransactionQueue already has a pending TransactionState or if it is pending
-    if (mTransactionQueues.find(applyToken) != mTransactionQueues.end() ||
+    auto itr = mTransactionQueues.find(applyToken);
+    // if this is an animation frame, wait until prior animation frame has
+    // been applied by SF
+    if (flags & eAnimation) {
+        while (itr != mTransactionQueues.end()) {
+            status_t err = mTransactionCV.waitRelative(mStateLock, s2ns(5));
+            if (CC_UNLIKELY(err != NO_ERROR)) {
+                ALOGW_IF(err == TIMED_OUT,
+                         "setTransactionState timed out "
+                         "waiting for animation frame to apply");
+                break;
+            }
+            itr = mTransactionQueues.find(applyToken);
+        }
+    }
+    if (itr != mTransactionQueues.end() ||
         !transactionIsReadyToBeApplied(desiredPresentTime, states)) {
         mTransactionQueues[applyToken].emplace(states, displays, flags, desiredPresentTime,
                                                uncacheBuffer, listenerCallbacks, postTime,
@@ -4885,6 +4948,9 @@
     result.append(mScheduler->doDump() + "\n");
     StringAppendF(&result, "+  Smart video mode: %s\n\n", mUseSmart90ForVideo ? "on" : "off");
     result.append(mRefreshRateStats.doDump() + "\n");
+
+    result.append(mTimeStats->miniDump());
+    result.append("\n");
 }
 
 const Vector<sp<Layer>>& SurfaceFlinger::getLayerSortedByZForHwcDisplay(DisplayId displayId) {
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/TimeStats/TimeStats.cpp b/services/surfaceflinger/TimeStats/TimeStats.cpp
index 740099e..c97a19b 100644
--- a/services/surfaceflinger/TimeStats/TimeStats.cpp
+++ b/services/surfaceflinger/TimeStats/TimeStats.cpp
@@ -67,6 +67,16 @@
     }
 }
 
+std::string TimeStats::miniDump() {
+    ATRACE_CALL();
+
+    std::string result = "TimeStats miniDump:\n";
+    std::lock_guard<std::mutex> lock(mMutex);
+    android::base::StringAppendF(&result, "Number of tracked layers is %zu\n",
+                                 mTimeStatsTracker.size());
+    return result;
+}
+
 void TimeStats::incrementTotalFrames() {
     if (!mEnabled.load()) return;
 
@@ -252,7 +262,8 @@
           postTime);
 
     std::lock_guard<std::mutex> lock(mMutex);
-    if (!mTimeStatsTracker.count(layerID) && layerNameIsValid(layerName)) {
+    if (!mTimeStatsTracker.count(layerID) && mTimeStatsTracker.size() < MAX_NUM_LAYER_RECORDS &&
+        layerNameIsValid(layerName)) {
         mTimeStatsTracker[layerID].layerName = layerName;
     }
     if (!mTimeStatsTracker.count(layerID)) return;
diff --git a/services/surfaceflinger/TimeStats/TimeStats.h b/services/surfaceflinger/TimeStats/TimeStats.h
index d8c0786..4e040a3 100644
--- a/services/surfaceflinger/TimeStats/TimeStats.h
+++ b/services/surfaceflinger/TimeStats/TimeStats.h
@@ -41,6 +41,7 @@
 
     virtual void parseArgs(bool asProto, const Vector<String16>& args, std::string& result) = 0;
     virtual bool isEnabled() = 0;
+    virtual std::string miniDump();
 
     virtual void incrementTotalFrames() = 0;
     virtual void incrementMissedFrames() = 0;
@@ -112,6 +113,7 @@
 
     void parseArgs(bool asProto, const Vector<String16>& args, std::string& result) override;
     bool isEnabled() override;
+    std::string miniDump() override;
 
     void incrementTotalFrames() override;
     void incrementMissedFrames() override;
@@ -137,8 +139,6 @@
     void recordRefreshRate(uint32_t fps, nsecs_t duration) override;
     void setPresentFenceGlobal(const std::shared_ptr<FenceTime>& presentFence) override;
 
-    // TODO(zzyiwei): Bound the timeStatsTracker with weighted LRU
-    // static const size_t MAX_NUM_LAYER_RECORDS = 200;
     static const size_t MAX_NUM_TIME_RECORDS = 64;
 
 private:
@@ -159,6 +159,8 @@
     std::unordered_map<int32_t, LayerRecord> mTimeStatsTracker;
     PowerTime mPowerTime;
     GlobalRecord mGlobalRecord;
+
+    static const size_t MAX_NUM_LAYER_RECORDS = 200;
 };
 
 } // namespace impl
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 {}
 };
diff --git a/services/surfaceflinger/tests/unittests/mock/MockTimeStats.h b/services/surfaceflinger/tests/unittests/mock/MockTimeStats.h
index 08fdb9d..b1634a8 100644
--- a/services/surfaceflinger/tests/unittests/mock/MockTimeStats.h
+++ b/services/surfaceflinger/tests/unittests/mock/MockTimeStats.h
@@ -30,6 +30,7 @@
 
     MOCK_METHOD3(parseArgs, void(bool, const Vector<String16>&, std::string&));
     MOCK_METHOD0(isEnabled, bool());
+    MOCK_METHOD0(miniDump, std::string());
     MOCK_METHOD0(incrementTotalFrames, void());
     MOCK_METHOD0(incrementMissedFrames, void());
     MOCK_METHOD0(incrementClientCompositionFrames, void());